feat: run-traktorer får ingredienser og Wait-pulje fra deres run

This commit is contained in:
2026-09-22 22:39:31 +02:00
parent 264a07c697
commit aa040d95ef
4 changed files with 88 additions and 9 deletions
+20 -3
View File
@@ -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
+13 -4
View File
@@ -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
+3
View File
@@ -12,6 +12,9 @@
<multiplayer supported="true"/>
<extraSourceFiles>
<sourceFile filename="adSupplyPlanner.lua"/>
<sourceFile filename="adRuns.lua"/>
<sourceFile filename="adRunsStorage.lua"/>
<sourceFile filename="adRunsController.lua"/>
<sourceFile filename="adUnloadWait.lua"/>
<sourceFile filename="adSmartPickup.lua"/>
</extraSourceFiles>
+52 -2
View File
@@ -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])