From fca26f5b4d75a4c39a567707f21180b1c77257dd Mon Sep 17 00:00:00 2001 From: masterdraco Date: Sun, 27 Sep 2026 10:50:48 +0200 Subject: [PATCH] =?UTF-8?q?fix(marksilo):=20review=20=E2=80=94=20flerv?= =?UTF-8?q?=C3=A6rdi-valg=20som=20MultiTextOption,=20lagerreservation=20p?= =?UTF-8?q?=C3=A5=20tv=C3=A6rs=20af=20runder,=20vagt=20kun=20f=C3=B8r=20st?= =?UTF-8?q?art,=20rutetjek=20+=20straks-fejl=20pauses,=20rotation=20fra=20?= =?UTF-8?q?p=C3=A5=20l=C3=A5nte=20vogne,=20kr=C3=A6ver=20parkering,=20flow?= =?UTF-8?q?-siloer=20udelades,=20slettede=20vogne=20og=20sm=C3=A5=20rester?= =?UTF-8?q?=20h=C3=A5ndteres?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FS25_ADSmartPickup/adFieldSiloPlanner.lua | 5 + FS25_ADSmartPickup/adFieldSilos.lua | 103 +++++++++++++----- FS25_ADSmartPickup/adFieldWork.lua | 1 + FS25_ADSmartPickup/adRunsController.lua | 1 + .../gui/SmartPickupFieldSiloTab.lua | 18 ++- .../gui/SmartPickupOutboundTab.lua | 3 + tests/test_adFieldSiloPlanner.lua | 9 ++ tests/test_adFieldSilos.lua | 73 +++++++++++-- 8 files changed, 176 insertions(+), 37 deletions(-) diff --git a/FS25_ADSmartPickup/adFieldSiloPlanner.lua b/FS25_ADSmartPickup/adFieldSiloPlanner.lua index 67c950e..4cc5b74 100644 --- a/FS25_ADSmartPickup/adFieldSiloPlanner.lua +++ b/FS25_ADSmartPickup/adFieldSiloPlanner.lua @@ -61,6 +61,11 @@ function ADFieldSiloPlanner.plan(input) for _, loan in ipairs(input.loans or {}) do local k = key(loan.siloId, loan.fillType) onWay[k] = (onWay[k] or 0) + (loan.liters or 0) + -- læs på vej til et lager optager pladsen, til de er aflæsset (også i senere runder) + if loan.storeId ~= nil then + local reserveKey = loan.storeId .. ":" .. tostring(loan.fillType) + reserved[reserveKey] = (reserved[reserveKey] or 0) + (loan.liters or 0) + end end local status, tasks = {}, {} for _, silo in ipairs(input.silos or {}) do diff --git a/FS25_ADSmartPickup/adFieldSilos.lua b/FS25_ADSmartPickup/adFieldSilos.lua index 11fb6cd..f37b693 100644 --- a/FS25_ADSmartPickup/adFieldSilos.lua +++ b/FS25_ADSmartPickup/adFieldSilos.lua @@ -9,6 +9,8 @@ ADFieldSilos.PLAN_INTERVAL_MS = 60000 ADFieldSilos.CHECK_INTERVAL_MS = 2000 ADFieldSilos.STUCK_MS = 120000 ADFieldSilos.PAUSE_MS = 600000 +ADFieldSilos.FAIL_MS = 30000 -- AD slukket inden for 30 s uden fremdrift = turen kunne ikke køres +ADFieldSilos.CARGO_MIN_LITERS = 100 -- rest under dette tæller ikke som last ADFieldSilos.MOVING_SPEED = 0.00028 -- m/ms, samme grænse som AutoDrive ADFieldSilos.FILE_NAME = "ADSmartPickup_fieldsilos.xml" ADFieldSilos.ROOT = "ADSmartPickupFieldSilos" @@ -22,13 +24,18 @@ local planTimerMs, checkTimerMs, nowMs = ADFieldSilos.PLAN_INTERVAL_MS, 0, 0 -- ---- ren frigivelsesregel ---- --- vehicleState = {adActive, controlled, fill, moving} +-- vehicleState = {adActive, controlled, fill, moving}. Fremdrift = kører, eller fyldningen ændrer sig (læsser +-- eller aflæsser). Vagten gælder kun før turen er kommet i gang — kø ved siloen/lageret er normalt. function ADFieldSilos.releaseReason(loan, vehicleState, now) if vehicleState.controlled then return "player" end - if not vehicleState.adActive then return "done" end - if vehicleState.moving then return nil end - if (vehicleState.fill or 0) > (loan.lastFill or 0) then return nil end - if now - (loan.lastProgressMs or loan.startedMs or 0) > ADFieldSilos.STUCK_MS then return "stuck" end + local progressing = vehicleState.moving or (vehicleState.fill or 0) ~= (loan.lastFill or 0) + local hasProgressed = loan.hasProgressed or progressing + local age = now - (loan.startedMs or 0) + if not vehicleState.adActive then + return (not hasProgressed and age < ADFieldSilos.FAIL_MS) and "failed" or "done" + end + if hasProgressed then return nil end + if age > ADFieldSilos.STUCK_MS then return "stuck" end return nil end @@ -91,6 +98,18 @@ local function firstMarker(building, role) return markers[1] ~= nil and markers[1].id or nil end +-- Bygninger der er kilde, mål eller lager i et flow: dem tømmer marksilo-flowet ikke (de hører til den drift). +local function runBuildingIds() + local ids = {} + local store = ADRunsController ~= nil and ADRunsController.store or nil + for _, run in ipairs(store ~= nil and store.runs or {}) do + for _, list in ipairs({run.sourceBuildingIds or {}, run.targetBuildingIds or {}, run.storeBuildingIds or {}}) do + for _, id in ipairs(list) do ids[id] = true end + end + end + return ids +end + -- Gårdlagre fra opsætningen + marksiloer (alle markers marksiloer, uden dubletter og uden gårdlagre). function ADFieldSilos.collectBuildings(adEnv) local fid = farmId() @@ -103,7 +122,7 @@ function ADFieldSilos.collectBuildings(adEnv) x = x, z = z, free = siloFree(building.placeable)}) end end - local silos, seen = {}, {} + local silos, seen = {}, runBuildingIds() for _, info in ipairs(ADFields.list()) do for _, building in ipairs(ADFields.fieldSilos(adEnv, fid, info)) do if not seen[building.id] and not ADFieldSiloConfig.hasStore(ADFieldSilos.config, building.id) then @@ -126,7 +145,7 @@ local function trailerInfo(adEnv, vehicle) for fillType in pairs(object.getFillUnitSupportedFillTypes ~= nil and object:getFillUnitSupportedFillTypes(index) or {}) do carries[fillType] = true end - if (object:getFillUnitFillLevel(index) or 0) > 0 then cargo = object:getFillUnitFillType(index) end + if (object:getFillUnitFillLevel(index) or 0) >= ADFieldSilos.CARGO_MIN_LITERS then cargo = object:getFillUnitFillType(index) end end end return capacity, carries, cargo @@ -140,7 +159,9 @@ end function ADFieldSilos.collectVehicles(adEnv) local vehicles, byId = {}, {} for _, rig in ipairs(ADFieldWork.getRigs(adEnv)) do - if rig.role == "unloader" and rig.enabled and not rig.busy and not rig.controlled then + -- uden AD-parkeringspunkt bliver vognen holdende på lagerets markør og spærrer for de næste + local canPark = ADFieldWork.parkMarkerId == nil or ADFieldWork.parkMarkerId(adEnv, rig.vehicle) ~= nil + if rig.role == "unloader" and rig.enabled and not rig.busy and not rig.controlled and canPark then local capacity, carries, cargo = trailerInfo(adEnv, rig.vehicle) table.insert(vehicles, {id = rig.id, x = rig.x, z = rig.z, capacity = capacity, carries = carries, cargo = cargo}) byId[rig.id] = rig.vehicle @@ -166,10 +187,14 @@ local function dispatchOne(adEnv, order, vehicle, silosById, storesById) module.loopCounter = 1 if module.setLoopsDone ~= nil then module:setLoopsDone(0) end ADFieldWork.enableParkAtJobFinished(vehicle) + -- rotation fra: ellers kan modens egne pickup-hooks sende vognen til en anden silo i mappen + if ADRunsController ~= nil and ADRunsController.setSetting ~= nil then + ADRunsController.setSetting(adEnv, vehicle, "rotateTargets", adEnv.AutoDrive.RT_NONE) + end module:raiseDirtyFlag() ADFieldWork.startAd(adEnv, vehicle, adEnv.AutoDrive.MODE_PICKUPANDDELIVER, order.siloMarkerId, order.storeMarkerId, order.fillType) local silo, store = silosById[order.siloId], storesById[order.storeId] - loans[vehicle] = {siloId = order.siloId, siloName = silo ~= nil and silo.name or order.siloId, fillType = order.fillType, + loans[vehicle] = {siloId = order.siloId, storeId = order.storeId, siloName = silo ~= nil and silo.name or order.siloId, fillType = order.fillType, liters = order.liters, startedMs = nowMs, lastProgressMs = nowMs, lastFill = fillLevel(adEnv, vehicle)} Logging.info(ADFieldSilos.LOG_PREFIX .. "'%s' henter %d l %s i %s -> %s", tostring(ADRuns.vehicleLabel(vehicle)), math.floor(order.liters), fillTypeName(order.fillType), tostring(silo ~= nil and silo.name or order.siloId), @@ -180,12 +205,13 @@ local function release(adEnv, vehicle, reason) local loan = loans[vehicle] loans[vehicle] = nil if loan == nil then return end - if reason == "stuck" then + if reason == "stuck" or reason == "failed" then local k = ADFieldSiloPlanner.key(loan.siloId, loan.fillType) paused[k] = nowMs + ADFieldSilos.PAUSE_MS pcall(vehicle.stopAutoDrive, vehicle) - Logging.warning(ADFieldSilos.LOG_PREFIX .. "'%s' kom ikke i gang ved %s (%s) på 2 min — stoppet; siloen springes over i 10 min", - tostring(ADRuns.vehicleLabel(vehicle)), tostring(loan.siloName), fillTypeName(loan.fillType)) + local why = reason == "stuck" and "kom ikke i gang på 2 min — stoppet" or "AutoDrive stoppede turen med det samme (rute/læssested?)" + Logging.warning(ADFieldSilos.LOG_PREFIX .. "'%s' ved %s (%s): %s; siloen springes over i 10 min", + tostring(ADRuns.vehicleLabel(vehicle)), tostring(loan.siloName), fillTypeName(loan.fillType), why) elseif reason == "stopped" then pcall(vehicle.stopAutoDrive, vehicle) end @@ -202,18 +228,28 @@ local function checkLoans(adEnv) local list = {} for vehicle in pairs(loans) do table.insert(list, vehicle) end for _, vehicle in ipairs(list) do - local loan = loans[vehicle] - local stateModule = vehicle.ad ~= nil and vehicle.ad.stateModule or nil - local fill = fillLevel(adEnv, vehicle) - local vehicleState = { - adActive = stateModule ~= nil and stateModule:isActive(), - controlled = vehicle.getIsControlled ~= nil and vehicle:getIsControlled() or false, - fill = fill, moving = (vehicle.lastSpeedReal or 0) >= ADFieldSilos.MOVING_SPEED, - } - if vehicleState.moving or fill > (loan.lastFill or 0) then loan.lastProgressMs = nowMs end - loan.lastFill = math.max(loan.lastFill or 0, fill) - local reason = ADFieldSilos.releaseReason(loan, vehicleState, nowMs) - if reason ~= nil then release(adEnv, vehicle, reason) end + if vehicle.isDeleted then + loans[vehicle] = nil -- solgt/slettet mens den var lånt + else + local ok, err = pcall(function() + local loan = loans[vehicle] + local stateModule = vehicle.ad ~= nil and vehicle.ad.stateModule or nil + local fill = fillLevel(adEnv, vehicle) + local vehicleState = { + adActive = stateModule ~= nil and stateModule:isActive(), + controlled = vehicle.getIsControlled ~= nil and vehicle:getIsControlled() or false, + fill = fill, moving = (vehicle.lastSpeedReal or 0) >= ADFieldSilos.MOVING_SPEED, + } + local reason = ADFieldSilos.releaseReason(loan, vehicleState, nowMs) + if vehicleState.moving or fill ~= (loan.lastFill or 0) then loan.hasProgressed = true end + loan.lastFill = fill + if reason ~= nil then release(adEnv, vehicle, reason) end + end) + if not ok then + loans[vehicle] = nil + Logging.warning(ADFieldSilos.LOG_PREFIX .. "lån opgivet (fejl): %s", tostring(err)) + end + end end end @@ -227,10 +263,24 @@ end local function loanList() local list = {} - for _, loan in pairs(loans) do table.insert(list, {siloId = loan.siloId, fillType = loan.fillType, liters = loan.liters}) end + for _, loan in pairs(loans) do table.insert(list, {siloId = loan.siloId, storeId = loan.storeId, fillType = loan.fillType, liters = loan.liters}) end return list end +-- Rute fra vognen til siloen og videre til lageret (samme opslag som Wait-punkterne); én advarsel pr. kombination. +local warnedRoute = {} +local function hasRoutes(adEnv, vehicle, order) + if ADUnloadWait == nil or ADUnloadWait.hasRouteTo == nil then return true end + local ok = ADUnloadWait.hasRouteTo(adEnv, vehicle, order.siloMarkerId) and ADUnloadWait.hasRouteTo(adEnv, vehicle, order.storeMarkerId) + local warnKey = tostring(order.vehicleId) .. ">" .. tostring(order.siloMarkerId) + if not ok and not warnedRoute[warnKey] then + warnedRoute[warnKey] = true + Logging.warning(ADFieldSilos.LOG_PREFIX .. "ingen AutoDrive-rute for '%s' til marksilo-markør %s eller gårdlager-markør %s", + tostring(ADRuns.vehicleLabel(vehicle)), tostring(order.siloMarkerId), tostring(order.storeMarkerId)) + end + return ok +end + function ADFieldSilos.planNow(adEnv) local cfg = ADFieldSilos.config local silos, stores = ADFieldSilos.collectBuildings(adEnv) @@ -244,6 +294,9 @@ function ADFieldSilos.planNow(adEnv) for _, store in ipairs(stores) do storesById[store.id] = store end for _, order in ipairs(plan.dispatch) do local vehicle = vehiclesById[order.vehicleId] + if vehicle ~= nil and not hasRoutes(adEnv, vehicle, order) then + vehicle = nil + end if vehicle ~= nil then local ok, err = pcall(dispatchOne, adEnv, order, vehicle, silosById, storesById) if not ok then diff --git a/FS25_ADSmartPickup/adFieldWork.lua b/FS25_ADSmartPickup/adFieldWork.lua index 60dc928..f345590 100644 --- a/FS25_ADSmartPickup/adFieldWork.lua +++ b/FS25_ADSmartPickup/adFieldWork.lua @@ -99,6 +99,7 @@ local function parkMarkerId(adEnv, vehicle) local marker = adEnv.ADGraphManager:getMapMarkerById(index) return marker ~= nil and marker.id or nil end +ADFieldWork.parkMarkerId = parkMarkerId local function restLoad(adEnv, vehicle) local ok, level = pcall(function() diff --git a/FS25_ADSmartPickup/adRunsController.lua b/FS25_ADSmartPickup/adRunsController.lua index 9ef8897..521095b 100644 --- a/FS25_ADSmartPickup/adRunsController.lua +++ b/FS25_ADSmartPickup/adRunsController.lua @@ -911,6 +911,7 @@ local function setSetting(adEnv, vehicle, settingName, value) end end end +ADRunsController.setSetting = setSetting -- Nærmeste markør med en læssestation: kun en gyldig start — moden vælger den reelle kilde pr. tur. local function findNearestLoadMarker(adEnv, vehicle, farmId) diff --git a/FS25_ADSmartPickup/gui/SmartPickupFieldSiloTab.lua b/FS25_ADSmartPickup/gui/SmartPickupFieldSiloTab.lua index 841bcdb..5b3a336 100644 --- a/FS25_ADSmartPickup/gui/SmartPickupFieldSiloTab.lua +++ b/FS25_ADSmartPickup/gui/SmartPickupFieldSiloTab.lua @@ -21,14 +21,24 @@ local function indexOf(list, value) return 1 end +-- Valg med flere værdier: productPrefab (MultiTextOption). ingredientPrefab er en BinaryOption med kun to sider. +function SmartPickupFrame:addFieldSiloChoiceRow(kind, title, texts, state) + local element = self:addRow(self.productPrefab, {kind = kind}) + local option = element:getDescendantByName("option") + option:setTexts(texts) + option:setState(state, false) + element:getDescendantByName("title"):setText(title) + local tooltip = option:getDescendantByName("ignore") + if tooltip ~= nil then tooltip:setText("") end + return option +end + function SmartPickupFrame:fillFieldSiloRows(adEnv) local i18n, cfg = self.i18n, ADFieldSilos.config local onOff = {i18n:getText("ui_no"), i18n:getText("ui_yes")} self:addToggleRow("fsEnabled", i18n:getText("spu_fs_enabled"), onOff, cfg.enabled) - local maxOption = self:addToggleRow("fsMaxVehicles", i18n:getText("spu_fs_maxVehicles"), numberTexts(1, ADFieldSiloConfig.MAX_VEHICLES), false) - maxOption:setState(cfg.maxVehicles, false) - local minOption = self:addToggleRow("fsMinLiters", i18n:getText("spu_fs_minLiters"), literTexts(), false) - minOption:setState(indexOf(ADFieldSiloConfig.MIN_LITERS_CHOICES, cfg.minLiters), false) + self:addFieldSiloChoiceRow("fsMaxVehicles", i18n:getText("spu_fs_maxVehicles"), numberTexts(1, ADFieldSiloConfig.MAX_VEHICLES), cfg.maxVehicles) + self:addFieldSiloChoiceRow("fsMinLiters", i18n:getText("spu_fs_minLiters"), literTexts(), indexOf(ADFieldSiloConfig.MIN_LITERS_CHOICES, cfg.minLiters)) local plan = ADFieldSilos.lastPlan local waiting = 0 diff --git a/FS25_ADSmartPickup/gui/SmartPickupOutboundTab.lua b/FS25_ADSmartPickup/gui/SmartPickupOutboundTab.lua index 42daef5..3cd1679 100644 --- a/FS25_ADSmartPickup/gui/SmartPickupOutboundTab.lua +++ b/FS25_ADSmartPickup/gui/SmartPickupOutboundTab.lua @@ -119,6 +119,9 @@ function SmartPickupFrame:onClickProduct(state, element) if clicked ~= nil and clicked.kind == "storageBuilding" then return self:safe(function(frame) frame:onClickStorageBuilding(state) end) end + if clicked ~= nil and SmartPickupFrame.FIELDSILO_ROW_KINDS ~= nil and SmartPickupFrame.FIELDSILO_ROW_KINDS[clicked.kind] then + return self:onClickFieldSiloRow(state, clicked) + end if clicked ~= nil and SmartPickupFrame.FIELD_ROW_KINDS ~= nil and SmartPickupFrame.FIELD_ROW_KINDS[clicked.kind] then return self:onClickFieldRow(state, clicked) end diff --git a/tests/test_adFieldSiloPlanner.lua b/tests/test_adFieldSiloPlanner.lua index 5122809..9440ba6 100644 --- a/tests/test_adFieldSiloPlanner.lua +++ b/tests/test_adFieldSiloPlanner.lua @@ -75,5 +75,14 @@ local input = base({silos = {silo("A", 500, {[WHEAT] = 90000})}, vehicles = {veh P.plan(input) check("input.stores urørt", input.stores[1].free[WHEAT], 1000000) + +-- I1: lån på vej til et lager reserverer pladsen på tværs af planlægningsrunder +r = P.plan(base({stores = {store("s", 400, {[WHEAT] = 30000})}, silos = {silo("A", 500, {[WHEAT] = 90000})}, + loans = {{siloId = "A", fillType = WHEAT, liters = 30000, storeId = "s"}}, vehicles = {vehicle("v1", 400, 50000)}})) +check("I1 lager fyldt af lån på vej -> ingen ny vogn dertil", #r.dispatch, 0) +r = P.plan(base({stores = {store("s", 400, {[WHEAT] = 30000}), store("t", 900, {[WHEAT] = 500000})}, silos = {silo("A", 500, {[WHEAT] = 90000})}, + loans = {{siloId = "A", fillType = WHEAT, liters = 30000, storeId = "s"}}, vehicles = {vehicle("v1", 400, 50000)}})) +check("I1 næste vogn til det andet lager", r.dispatch[1] ~= nil and r.dispatch[1].storeId, "t") + print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL")) os.exit(failures == 0 and 0 or 1) diff --git a/tests/test_adFieldSilos.lua b/tests/test_adFieldSilos.lua index b81b144..33fd0e2 100644 --- a/tests/test_adFieldSilos.lua +++ b/tests/test_adFieldSilos.lua @@ -12,13 +12,20 @@ local function check(name, actual, expected) end local loan = {startedMs = 0, lastProgressMs = 0, lastFill = 0} check("kører, tidligt -> behold", S.releaseReason(loan, {adActive = true, controlled = false, fill = 0, moving = true}, 5000), nil) -check("AD slukket -> done", S.releaseReason(loan, {adActive = false, controlled = false, fill = 0}, 5000), "done") +check("AD slukket efter 40 s -> done", S.releaseReason(loan, {adActive = false, controlled = false, fill = 0}, 40000), "done") check("spiller i vognen -> player", S.releaseReason(loan, {adActive = true, controlled = true, fill = 0}, 5000), "player") check("står stille uden fyld i 120 s -> stuck", S.releaseReason(loan, {adActive = true, controlled = false, fill = 0, moving = false}, 120001), "stuck") check("kører stadig efter 120 s -> behold", S.releaseReason(loan, {adActive = true, controlled = false, fill = 0, moving = true}, 120001), nil) local loading = {startedMs = 0, lastProgressMs = 110000, lastFill = 0} check("fyldning steg for nylig -> behold", S.releaseReason(loading, {adActive = true, controlled = false, fill = 20000, moving = false}, 125000), nil) +-- I2/I3: vagten gælder kun før turen er kommet i gang; AD der slukker straks uden fremdrift = fejl +local going = {startedMs = 0, lastFill = 30000, hasProgressed = true} +check("I2 i gang, står i kø 500 s -> behold", S.releaseReason(going, {adActive = true, controlled = false, fill = 30000, moving = false}, 500000), nil) +check("I2 aflæsning (fyld falder) er fremdrift", S.releaseReason({startedMs = 0, lastFill = 30000}, {adActive = true, controlled = false, fill = 20000, moving = false}, 500000), nil) +check("I3 AD slukket efter 10 s uden fremdrift -> failed", S.releaseReason({startedMs = 0, lastFill = 0}, {adActive = false, controlled = false, fill = 0}, 10000), "failed") +check("I3 AD slukket efter 10 s med fremdrift -> done", S.releaseReason({startedMs = 0, lastFill = 0, hasProgressed = true}, {adActive = false, controlled = false, fill = 0}, 10000), "done") + -- Røgtest af spil-laget med mocks: planNow låner nærmeste tømmevogn, isLoaned = optaget, -- frakobling (setConfig enabled=false) stopper AD og frigiver (Review Focus). do @@ -34,7 +41,9 @@ do ADBuildings = {list = function() return {fieldSilo, farm} end, getMarkers = function(b, role) return {{id = b.id .. "-" .. role}} end} ADFields = {list = function() return {{id = 1}} end, fieldSilos = function() return {fieldSilo, farm} end} - local started = {} + local started, settingsSet, noPark, noRoute, residue = {}, {}, {}, {}, 0 + ADRunsController = {store = {runs = {}}, setSetting = function(_, v, name, value) settingsSet[v] = settingsSet[v] or {}; settingsSet[v][name] = value end} + ADUnloadWait = {hasRouteTo = function(_, _, id) return not noRoute[id] end} local function makeVehicle(name, x) local module = {active = false} function module:setMode() end @@ -48,18 +57,23 @@ do stopAutoDrive = function(self) self.ad.stateModule.active = false; self.stopped = true end} end local near, far = makeVehicle("Nær", 900), makeVehicle("Fjern", 5000) - local adEnv = {AutoDrive = {MODE_PICKUPANDDELIVER = 2, + local adEnv = {AutoDrive = {MODE_PICKUPANDDELIVER = 2, RT_NONE = 0, getAllDischargeableUnits = function() return {{fillUnitIndex = 1, object = { getFillUnitCapacity = function() return 40000 end, getFillUnitSupportedFillTypes = function() return {[WHEAT] = true} end, - getFillUnitFillLevel = function() return 0 end, getFillUnitFillType = function() return WHEAT end}}} end, + getFillUnitFillLevel = function() return residue end, getFillUnitFillType = function() return WHEAT end}}} end, getAllUnits = function() return {} end, getAllFillLevels = function() return 0 end}} ADFieldWork = { - getRigs = function() return { - {id = "n", vehicle = near, role = "unloader", enabled = true, busy = S.isLoaned(near), controlled = false, x = 900, z = 0}, - {id = "f", vehicle = far, role = "unloader", enabled = true, busy = S.isLoaned(far), controlled = false, x = 5000, z = 0}, - {id = "h", vehicle = far, role = "harvester", enabled = true, busy = false, controlled = false, x = 1000, z = 0}} end, + getRigs = function() + local rigs = {} + -- som spillets vehicleSystem: slettede køretøjer er ikke med + if not near.isDeleted then table.insert(rigs, {id = "n", vehicle = near, role = "unloader", enabled = true, busy = S.isLoaned(near), controlled = false, x = 900, z = 0}) end + if not far.isDeleted then table.insert(rigs, {id = "f", vehicle = far, role = "unloader", enabled = true, busy = S.isLoaned(far), controlled = false, x = 5000, z = 0}) end + table.insert(rigs, {id = "h", vehicle = far, role = "harvester", enabled = true, busy = false, controlled = false, x = 1000, z = 0}) + return rigs + end, enableParkAtJobFinished = function() end, + parkMarkerId = function(_, v) if noPark[v] then return nil end return 777 end, startAd = function(_, v, _, first, second, fillType) v.ad.stateModule.active = true; table.insert(started, {v = v, first = first, second = second, fillType = fillType}) end, } S.setConfig(ADFieldSiloConfig.with(ADFieldSiloConfig.toggleStore(ADFieldSiloConfig.new(), "farm"), {enabled = true, maxVehicles = 1})) @@ -72,9 +86,52 @@ do check("RØG gårdlager er ikke marksilo", #plan.status, 1) check("RØG vognen er lånt", S.isLoaned(near), true) check("RØG x nået -> ingen flere", #S.planNow(adEnv).dispatch, 0) + check("I4 rotation slået fra på lånt vogn", settingsSet[near] ~= nil and settingsSet[near].rotateTargets, 0) S.setConfig(ADFieldSiloConfig.with(S.config, {enabled = false})) check("RØG frakobling stopper AD", near.stopped, true) check("RØG frakobling frigiver", S.isLoaned(near), false) + + -- I5: vogn uden parkeringspunkt lånes ikke (ville blive holdende på lagerets markør) + started = {} + noPark[near] = true + near.stopped = nil + S.setConfig(ADFieldSiloConfig.with(S.config, {enabled = true})) + S.planNow(adEnv) + check("I5 uden parkering -> fjern vogn med parkering", started[1] ~= nil and started[1].v.name, "Fjern") + S.setConfig(ADFieldSiloConfig.with(S.config, {enabled = false})) + noPark[near] = nil + + -- I3: ingen rute til siloen -> ingen afsendelse + started = {} + noRoute["fs-load"] = true + S.setConfig(ADFieldSiloConfig.with(S.config, {enabled = true})) + S.planNow(adEnv) + check("I3 ingen rute -> ingen afsendelse", #started, 0) + noRoute["fs-load"] = nil + S.setConfig(ADFieldSiloConfig.with(S.config, {enabled = false})) + + -- I6: silo der er kilde/mål i et flow er ikke marksilo + ADRunsController.store.runs = {{kind = "supply", sourceBuildingIds = {}, targetBuildingIds = {"fs"}, storeBuildingIds = {}}} + local silos = S.collectBuildings(adEnv) + check("I6 silo i et flow tømmes ikke", #silos, 0) + ADRunsController.store.runs = {} + + -- M5: rest under 100 l tæller ikke som last + residue = 50 + local vehicles = S.collectVehicles(adEnv) + check("M5 rest på 50 l er ikke last", vehicles[1].cargo, nil) + residue = 0 + + -- M4: slettet lånt vogn fjernes uden at vælte tick + S.setConfig(ADFieldSiloConfig.with(S.config, {enabled = true})) + started = {} + S.planNow(adEnv) + local loaned = started[1] ~= nil and started[1].v or nil + if loaned ~= nil then loaned.isDeleted = true end + local okTick = pcall(S.tick, adEnv, 2000) + check("M4 tick tåler slettet vogn", okTick, true) + check("M4 slettet vogn frigivet", loaned ~= nil and S.isLoaned(loaned), false) + S.setConfig(ADFieldSiloConfig.with(S.config, {enabled = false})) end print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))