diff --git a/FS25_ADSmartPickup/adSmartPickup.lua b/FS25_ADSmartPickup/adSmartPickup.lua
index 4c5ed7c..dcd6c80 100644
--- a/FS25_ADSmartPickup/adSmartPickup.lua
+++ b/FS25_ADSmartPickup/adSmartPickup.lua
@@ -489,10 +489,23 @@ local function applySupplyChoice(driver, ingredients, choice)
supplyState[driver] = {ingredients = ingredients, narrowedTo = choice.fillType}
end
--- Samlet valg: behovsstyret når flere varer er valgt, ellers mappe-logik. nil = AutoDrives original.
+-- Ingredienslisten for køretøjet: run'ets liste når det er i et run (ingen tændknap
+-- nødvendig), ellers AD's multi-valg (>1 vare). nil = ingen behovsstyring.
+function ADSmartPickup.getIngredientsFor(adEnv, driver)
+ local run = ADRunsController ~= nil and ADRunsController.getRunForVehicle(driver) or nil
+ if run ~= nil then
+ local ingredients = ADRunsController.getRunIngredients(adEnv, run, driver)
+ if #ingredients > 0 then
+ return ingredients
+ end
+ return nil
+ end
+ return ADSupplyPlanner.resolveIngredients(supplyState[driver], driver.ad.stateModule:getSelectedFillTypes())
+end
+
+-- Samlet valg: behovsstyret med ingrediensliste, ellers mappe-logik. nil = AutoDrives original.
function ADSmartPickup.choosePickup(adEnv, driver)
- local selected = driver.ad.stateModule:getSelectedFillTypes()
- local ingredients = ADSupplyPlanner.resolveIngredients(supplyState[driver], selected)
+ local ingredients = ADSmartPickup.getIngredientsFor(adEnv, driver)
if ingredients == nil then
supplyState[driver] = nil
return ADSmartPickup.findLeastFilledPickup(adEnv, driver)
@@ -664,6 +677,10 @@ function ADSmartPickup:update(dt)
if adEnv ~= nil and g_currentMission ~= nil and g_currentMission.storageSystem ~= nil then
installHook(adEnv)
isHooked = true
+ if ADRunsController ~= nil then
+ pcall(ADRunsController.load, adEnv)
+ pcall(ADRunsController.installSaveHook)
+ end
end
return
end
diff --git a/FS25_ADSmartPickup/adUnloadWait.lua b/FS25_ADSmartPickup/adUnloadWait.lua
index 99aa28c..abb7b0f 100644
--- a/FS25_ADSmartPickup/adUnloadWait.lua
+++ b/FS25_ADSmartPickup/adUnloadWait.lua
@@ -39,10 +39,12 @@ local function getRestLoad(adEnv, vehicle)
return bestFillType, bestLevel
end
-local function getWaitCandidates(adEnv)
+-- poolGroup: run'ets Wait-mappe; tom/nil = alle Wait-mapper.
+local function getWaitCandidates(adEnv, poolGroup)
local candidates = {}
for _, marker in pairs(adEnv.ADGraphManager:getMapMarkers()) do
- if ADSupplyPlanner.isWaitMarker(marker) then
+ local isInPool = poolGroup == nil or poolGroup == "" or marker.group == poolGroup
+ if isInPool and ADSupplyPlanner.isWaitMarker(marker) then
local wayPoint = adEnv.ADGraphManager:getWayPointById(marker.id)
if wayPoint ~= nil then
table.insert(candidates, {marker = marker, x = wayPoint.x, z = wayPoint.z})
@@ -52,6 +54,11 @@ local function getWaitCandidates(adEnv)
return candidates
end
+local function getWaitPoolGroup(vehicle)
+ local run = ADRunsController ~= nil and ADRunsController.getRunForVehicle(vehicle) or nil
+ return run ~= nil and run.waitPoolGroup or nil
+end
+
local function getVehiclePosition(vehicle)
if vehicle.rootNode == nil then
return nil
@@ -110,11 +117,13 @@ local function startWaiting(adEnv, task)
local isReachable = function(candidate)
return hasRouteBothWays(adEnv, vehicle, candidate.marker.id, task.destinationID)
end
- local candidate = x ~= nil and ADSupplyPlanner.pickNearestFreeWaitPoint(getWaitCandidates(adEnv), claims, x, z, vehicle, isReachable) or nil
+ local pool = getWaitPoolGroup(vehicle)
+ local candidate = x ~= nil and ADSupplyPlanner.pickNearestFreeWaitPoint(getWaitCandidates(adEnv, pool), claims, x, z, vehicle, isReachable) or nil
if candidate == nil then
if not warnedNoWaitPoint[vehicle] then
warnedNoWaitPoint[vehicle] = true
- Logging.warning(ADUnloadWait.LOG_PREFIX .. "'%s' har %.0f l rest, og målet er fuldt — intet ledigt Wait-punkt med vejnet til OG fra målet (markør i en mappe med 'Wait' i navnet), så AutoDrive venter ved målet", tostring(vehicle:getName()), rest)
+ local poolText = pool ~= nil and pool ~= "" and (" i puljen '" .. pool .. "'") or ""
+ Logging.warning(ADUnloadWait.LOG_PREFIX .. "'%s' har %.0f l rest, og målet er fuldt — intet ledigt Wait-punkt%s med vejnet til OG fra målet (markør i en mappe med 'Wait' i navnet), så AutoDrive venter ved målet", tostring(vehicle:getName()), rest, poolText)
end
return
end
diff --git a/FS25_ADSmartPickup/modDesc.xml b/FS25_ADSmartPickup/modDesc.xml
index 0183d76..e23508f 100644
--- a/FS25_ADSmartPickup/modDesc.xml
+++ b/FS25_ADSmartPickup/modDesc.xml
@@ -12,6 +12,9 @@
+
+
+
diff --git a/tests/test_adSmartPickup.lua b/tests/test_adSmartPickup.lua
index 9a34fe9..6c4f67d 100644
--- a/tests/test_adSmartPickup.lua
+++ b/tests/test_adSmartPickup.lua
@@ -5,7 +5,10 @@ local SUGARBEET, WHEAT = 10, 11
local HAY, GRASS, SILAGE = 20, 21, 22
local MILK = 30
local FILL_TYPE_NAMES = {[SUGARBEET] = "SUGARBEET", [WHEAT] = "WHEAT", [HAY] = "DRYGRASS_WINDROW", [GRASS] = "GRASS_WINDROW", [SILAGE] = "SILAGE", [MILK] = "MILK"}
-g_fillTypeManager = {getFillTypeNameByIndex = function(_, index) return FILL_TYPE_NAMES[index] end}
+g_fillTypeManager = {
+ getFillTypeNameByIndex = function(_, index) return FILL_TYPE_NAMES[index] end,
+ getFillTypeIndexByName = function(_, name) for index, candidate in pairs(FILL_TYPE_NAMES) do if candidate == name then return index end end return nil end,
+}
local logLines = {}
-- ---- FS25-mocks ----
@@ -60,6 +63,7 @@ g_currentMission = {
getUnloadingStations = function() return unloadStations end,
},
accessHandler = {canFarmAccess = function() return true end},
+ getFarmId = function() return 1 end,
}
-- ---- AutoDrive-mocks ----
@@ -80,6 +84,7 @@ local function resetWorld()
end
local RT_NONE, RT_ONLYPICKUP = 1, 2
+local testVehicles = {}
FS25_AutoDrive = {
AutoDrive = {
RT_NONE = RT_NONE,
@@ -87,6 +92,8 @@ FS25_AutoDrive = {
getAllFillLevels = function(trailers) return trailers.level, trailers.capacity or 0, false, 0 end,
getAllUnits = function(vehicle) return vehicle.trailers or {level = 0} end,
getAllDischargeableUnits = function(vehicle) return vehicle.units or {} end,
+ getSupportedFillTypesOfAllUnitsAlphabetically = function(vehicle) return vehicle.carriable or {} end,
+ getAllVehicles = function() return testVehicles end,
},
-- opgaven noterer hvad AutoDrive "ser" af indstillinger mens den opdaterer
LoadAtDestinationTask = {update = function(self)
@@ -154,6 +161,8 @@ local function makeSupplyDriver(firstMarker, secondMarker, fillTypes)
end
dofile("FS25_ADSmartPickup/adSupplyPlanner.lua")
+dofile("FS25_ADSmartPickup/adRuns.lua")
+dofile("FS25_ADSmartPickup/adRunsController.lua")
dofile("FS25_ADSmartPickup/adUnloadWait.lua")
dofile("FS25_ADSmartPickup/adSmartPickup.lua")
listener:update(16) -- installerer hook'en
@@ -307,7 +316,6 @@ check("S10 lager læses fra produktionspunktet", manager:getNextPickup(feeder, f
ProductionPoint = {PROD_STATUS = {INACTIVE = 0, RUNNING = 1, MISSING_INPUTS = 2, NO_OUTPUT_SPACE = 3}}
local WATER = 40
FILL_TYPE_NAMES[WATER] = "WATER"
-FS25_AutoDrive.AutoDrive.getSupportedFillTypesOfAllUnitsAlphabetically = function(vehicle) return vehicle.carriable end
-- Fabrik med TMR-opskrift: sluger ensilage, nipper til hø. Vand kan vognen ikke bære.
local function buildFactoryWorld(tmrEnabled, tmrStatus)
@@ -699,6 +707,48 @@ listener:update(16)
FS25_AutoDrive.LoadAtDestinationTask.update(stopperTask, 16)
check("L7 greb ryddet når AD stopper", stopperTask.seenRotate, RT_ONLYPICKUP)
+-- ==== I: run-integration — ingredienser fra run i stedet for multi-valg; Wait-pulje pr. run ====
+-- I1: traktor i et run med ÉN valgt vare i AD får alligevel behovsstyring (run'ets liste)
+local runDriver = buildCowWorld()
+runDriver.uniqueId = "vehicleRun"
+runDriver.ad.stateModule.selectedFillTypes = {STRAW}
+runDriver.ad.stateModule.fillType = STRAW
+testVehicles = {runDriver}
+ADRunsController.store = ADRuns.newStore()
+local feedRun = ADRunsController.createRun("Cow Feed")
+ADRunsController.updateRun(feedRun.id, {targetWayPointId = 30, ingredientMode = "manual", ingredients = {"FORAGE", "STRAW"}})
+ADRunsController.assignVehicle(feedRun.id, runDriver)
+check("I1 run-liste styrer: halm mangler -> halmladen", manager:getNextPickup(runDriver, false), 21)
+cowLevels[STRAW] = 99500
+check("I1 run-liste styrer: TMR når halm er fuld", manager:getNextPickup(runDriver, false), 20)
+check("I1 getIngredientsFor = run'ets liste", table.concat(ADSmartPickup.getIngredientsFor(FS25_AutoDrive, runDriver), ","), TMR .. "," .. STRAW)
+
+-- I2: samme traktor uden run -> som før (én vare = mappe-logik i mappen "Lader")
+ADRunsController.store = ADRuns.newStore()
+runDriver.ad.stateModule.selectedFillTypes = {STRAW}
+cowLevels[STRAW] = 0
+check("I2 uden run: mappe-logik", manager:getNextPickup(runDriver, false), 21)
+check("I2 uden run og én vare: ingen ingrediensliste", ADSmartPickup.getIngredientsFor(FS25_AutoDrive, runDriver), nil)
+
+-- I3: run med tom auto-liste (intet mål) -> falder tilbage til AD's valg
+local emptyRun = ADRunsController.createRun("Tomt")
+ADRunsController.assignVehicle(emptyRun.id, runDriver)
+check("I3 tom run-liste -> som uden run", manager:getNextPickup(runDriver, false), 21)
+
+-- I4: Wait-kandidater begrænses til run'ets pulje
+buildWaitWorld()
+addMarker(42, "Pig Wait 1", "Pig Wait", 5050, 0) -- nærmere end Cow Wait, men forkert pulje
+local vp, tp = makeUnloadingVehicle("Fastrac Pulje", 511, 5000, 35000)
+vp.uniqueId = "vehiclePool"
+testVehicles = {vp}
+ADRunsController.store = ADRuns.newStore()
+local poolRun = ADRunsController.createRun("Cow Feed")
+ADRunsController.updateRun(poolRun.id, {targetWayPointId = 30, waitPoolGroup = "Cow Wait"})
+ADRunsController.assignVehicle(poolRun.id, vp)
+UnloadTask.update(tp, 16)
+check("I4 kun run'ets pulje", tp.destinationID, 40)
+ADRunsController.store = ADRuns.newStore()
+
-- ==== E: eksponerede opslag (bruges af runs-controller og læs-bytte) ====
local eDriver = buildCowWorld()
check("E1 aflæsningsstation ved waypoint", ADSmartPickup.getUnloadStationAtWayPointId(FS25_AutoDrive, 30, 1), unloadStations[1])