diff --git a/FS25_ADSmartPickup/adLoadSwap.lua b/FS25_ADSmartPickup/adLoadSwap.lua index 09c1142..f545ada 100644 --- a/FS25_ADSmartPickup/adLoadSwap.lua +++ b/FS25_ADSmartPickup/adLoadSwap.lua @@ -54,7 +54,23 @@ end -- Nærmeste silo med plads til resten og vejnet fra traktoren; siloer der allerede har varen -- foretrækkes. Returnerer marker — eller nil + en forklaring (til loggen). -- excludedPlaceables (valgfri): {[placeable] = true} der aldrig må vælges (fx udkørslens kilder). -function ADLoadSwap.findDumpMarker(adEnv, vehicle, fillType, rest, homeWayPointId, isReachable, excludedPlaceables) +-- Rækkefølge for aflæsnings-siloer: markører et forløb HENTER fra (avoidMarkers = {[id] = true}) sidst — +-- ellers læsser en lagertur af dér hvor en salgstur skal læsse (samme tank-række); dernæst siloer der +-- allerede har varen, så nærmeste. Returnerer en ny sorteret liste. +function ADLoadSwap.rankDumpCandidates(candidates, avoidMarkers) + local ranked = {} + for _, candidate in ipairs(candidates or {}) do table.insert(ranked, candidate) end + local function avoided(candidate) return avoidMarkers ~= nil and avoidMarkers[candidate.marker.id] == true end + table.sort(ranked, function(a, b) + if avoided(a) ~= avoided(b) then return not avoided(a) end + if a.hasFillType ~= b.hasFillType then return a.hasFillType end + if a.distance ~= b.distance then return a.distance < b.distance end + return a.marker.id < b.marker.id + end) + return ranked +end + +function ADLoadSwap.findDumpMarker(adEnv, vehicle, fillType, rest, homeWayPointId, isReachable, excludedPlaceables, avoidMarkers) if vehicle.rootNode == nil then return nil, "køretøjet har ingen position" end @@ -82,12 +98,7 @@ function ADLoadSwap.findDumpMarker(adEnv, vehicle, fillType, rest, homeWayPointI end end end - table.sort(candidates, function(a, b) - if a.hasFillType ~= b.hasFillType then - return a.hasFillType - end - return a.distance < b.distance - end) + candidates = ADLoadSwap.rankDumpCandidates(candidates, avoidMarkers) for _, candidate in ipairs(candidates) do if isReachable(candidate.marker.id) then return candidate.marker diff --git a/FS25_ADSmartPickup/adOutbound.lua b/FS25_ADSmartPickup/adOutbound.lua index a97a3ed..fbcb043 100644 --- a/FS25_ADSmartPickup/adOutbound.lua +++ b/FS25_ADSmartPickup/adOutbound.lua @@ -200,7 +200,8 @@ local function findStoreMarker(adEnv, vehicle, product, capacity, sources, liter end end local liters = math.max(1, math.min(available, capacity or available)) - local marker = ADLoadSwap.findDumpMarker(adEnv, vehicle, product.fillType, liters, nil, isReachable, ADSources.getSourcePlaceables(sources)) + local avoid = ADRunsController ~= nil and ADRunsController.getPickupMarkers ~= nil and ADRunsController.getPickupMarkers() or nil + local marker = ADLoadSwap.findDumpMarker(adEnv, vehicle, product.fillType, liters, nil, isReachable, ADSources.getSourcePlaceables(sources), avoid) if marker == nil then return nil end diff --git a/FS25_ADSmartPickup/adRunsController.lua b/FS25_ADSmartPickup/adRunsController.lua index 9ad9d86..bf99e82 100644 --- a/FS25_ADSmartPickup/adRunsController.lua +++ b/FS25_ADSmartPickup/adRunsController.lua @@ -136,6 +136,17 @@ function ADRunsController.unassignVehicle(vehicle) end end +-- Markører udkørsels-forløb HENTER fra: {[wayPointId] = true}. Lagerture læsser helst ikke af dér. +function ADRunsController.getPickupMarkers() + local result = {} + for _, run in ipairs(ADRunsController.store ~= nil and ADRunsController.store.runs or {}) do + if run.kind == "outbound" then + for _, wayPointId in ipairs(run.sourceWayPointIds or {}) do result[wayPointId] = true end + end + end + return result +end + -- ---- køretøjsnavne ---- ADRunsController.NAME_INTERVAL_MS = 2000 diff --git a/FS25_ADSmartPickup/modDesc.xml b/FS25_ADSmartPickup/modDesc.xml index 97b6f28..40977f7 100644 --- a/FS25_ADSmartPickup/modDesc.xml +++ b/FS25_ADSmartPickup/modDesc.xml @@ -1,7 +1,7 @@ masterdraco - 1.17.4.0 + 1.17.5.0 <en>AD Smart Pickup</en> diff --git a/docs/BRUGERMANUAL.md b/docs/BRUGERMANUAL.md index 6f31cfa..7f4befb 100644 --- a/docs/BRUGERMANUAL.md +++ b/docs/BRUGERMANUAL.md @@ -1,6 +1,6 @@ # AD Smart Pickup — brugermanual -Version 1.17.4 · Farming Simulator 25 · tillæg til AutoDrive +Version 1.17.5 · Farming Simulator 25 · tillæg til AutoDrive *English version: [USER_MANUAL.md](USER_MANUAL.md)* @@ -304,7 +304,9 @@ Før hver pålæsning, og hvert femte sekund mens traktoren holder, vurderer mod til salg **uanset mængde**. Det sikrer, at du får pengene, når prisen topper. Den højeste pris-% går først. 2. **Lager.** Findes en Lager-vare med et fuldt læs, eller en kilde over tærsklen, køres den til den - nærmeste silo med plads til hele læsset. Den mest fyldte kilde går først. + nærmeste silo med plads til hele læsset. Den mest fyldte kilde går først. Markører, som et andet + udkørselsflow henter fra, bruges kun som aflæsningssted, hvis intet andet passer. Så læsser en + lagertur ikke af, hvor en salgstur skal læsse. 3. **Ingen tur.** Traktoren holder ved et Wait-punkt og prøver igen. Status viser hvorfor, fx `holder ved Wait 3: SUGAR 78 % af top (kræver 90), lager 41 %`. diff --git a/docs/USER_MANUAL.md b/docs/USER_MANUAL.md index 7ab2347..412376b 100644 --- a/docs/USER_MANUAL.md +++ b/docs/USER_MANUAL.md @@ -1,6 +1,6 @@ # AD Smart Pickup — user manual -Version 1.17.4 · Farming Simulator 25 · add-on for AutoDrive +Version 1.17.5 · Farming Simulator 25 · add-on for AutoDrive *Dansk version: [BRUGERMANUAL.md](BRUGERMANUAL.md)* @@ -308,7 +308,9 @@ Before each loading, and every five seconds while the tractor waits, the mod che drives to sell **regardless of amount**. This makes sure you get the money when the price peaks. The highest price share goes first. 2. **Store.** If a Store good has a full load, or a source is above its threshold, it is taken to the - nearest silo with room for the whole load. The fullest source goes first. + nearest silo with room for the whole load. The fullest source goes first. Markers another delivery + flow loads from are only used for unloading when nothing else fits. That way a storage trip does + not unload where a sale trip needs to load. 3. **No trip.** The tractor parks at a Wait point and tries again. The status says why, such as `holding at Wait 3: SUGAR 78 % of top (needs 90), storage 41 %`. diff --git a/tests/test_adLoadSwap.lua b/tests/test_adLoadSwap.lua new file mode 100644 index 0000000..30833a6 --- /dev/null +++ b/tests/test_adLoadSwap.lua @@ -0,0 +1,31 @@ +-- Kør: luajit tests/test_adLoadSwap.lua (fra repo-roden) +-- Ren rangering af aflæsnings-siloer (lagermål for udkørsel og læs-bytte). + +dofile("FS25_ADSmartPickup/adLoadSwap.lua") +local L = ADLoadSwap + +local failures = 0 +local function check(name, actual, expected) + if actual == expected then + print("OK " .. name) + else + failures = failures + 1 + print(string.format("FAIL %s: forventede %s, fik %s", name, tostring(expected), tostring(actual))) + end +end + +-- LS1: markører et andet forløb HENTER fra (fx "Milk Storage Load") vælges sidst; ellers har-varen, så afstand +local candidates = { + {marker = {id = 1, name = "Milk Storage Load"}, hasFillType = true, distance = 100}, + {marker = {id = 2, name = "Milk Storage unload"}, hasFillType = true, distance = 400}, + {marker = {id = 3, name = "Silo tom"}, hasFillType = false, distance = 10}, +} +local ranked = L.rankDumpCandidates(candidates, {[1] = true}) +check("LS1 afhentningsmarkør undgås", ranked[1].marker.id, 2) +check("LS1 derefter tom silo før afhentning", ranked[2].marker.id, 3) +check("LS1 afhentning sidst (stadig mulig)", ranked[3].marker.id, 1) +local plain = L.rankDumpCandidates(candidates, nil) +check("LS1 uden undgå-liste: har varen + nærmest", plain[1].marker.id, 1) + +print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL")) +os.exit(failures == 0 and 0 or 1) diff --git a/tests/test_adRunsController.lua b/tests/test_adRunsController.lua index 7b4fb48..da20080 100644 --- a/tests/test_adRunsController.lua +++ b/tests/test_adRunsController.lua @@ -719,5 +719,16 @@ do check("RC-navne label uden AD-navn", ADRuns.vehicleLabel({getName = function() return "Fendt" end}), "Fendt") end +-- PM: afhentningsmarkører fra udkørsels-forløb (lagerture undgår dem som aflæsningssted) +do + local sale = ADRunsController.createRun("Salg-test", "outbound") + ADRunsController.updateRun(sale.id, {sourceWayPointIds = {4711, 4712}}) + local supply = ADRunsController.createRun("Forsyning-test", "supply") + ADRunsController.updateRun(supply.id, {sourceWayPointIds = {9999}}) + local pickups = ADRunsController.getPickupMarkers() + check("PM udkørsels-kilde med", pickups[4711], true) + check("PM forsyning tæller ikke", pickups[9999], nil) +end + print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL")) os.exit(failures == 0 and 0 or 1)