feat(flows): stoppet flow tømmer vognen før den parkeres — først ved flowets mål, rest til nærmeste silo/egen fabrik der tager varen, så på plads og hjem (v1.51.4.0)
This commit is contained in:
@@ -134,6 +134,7 @@ end
|
|||||||
local function isBusyVehicle(vehicle, id)
|
local function isBusyVehicle(vehicle, id)
|
||||||
return ADFieldJobs.state.assignments[id] ~= nil or isAdActive(vehicle) or ADCpBridge.isWorking(vehicle)
|
return ADFieldJobs.state.assignments[id] ~= nil or isAdActive(vehicle) or ADCpBridge.isWorking(vehicle)
|
||||||
or (ADFieldSilos ~= nil and ADFieldSilos.isLoaned(vehicle)) or (ADPool ~= nil and ADPool.isReturning(vehicle))
|
or (ADFieldSilos ~= nil and ADFieldSilos.isLoaned(vehicle)) or (ADPool ~= nil and ADPool.isReturning(vehicle))
|
||||||
|
or (ADFlowWagons ~= nil and ADFlowWagons.isEmptying(vehicle))
|
||||||
end
|
end
|
||||||
|
|
||||||
ADFieldWork.isBusyVehicle = isBusyVehicle
|
ADFieldWork.isBusyVehicle = isBusyVehicle
|
||||||
|
|||||||
@@ -89,6 +89,24 @@ function ADFlowWagons.missingBuildings(run, exists, seen)
|
|||||||
return missing
|
return missing
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Tøm vognen før den parkeres (flowet stoppet): flowets mål -> silo/egen fabrik -> hjem.
|
||||||
|
-- stage: "start" | "target" | "dump"; s = {cargo, hasTarget, adActive, elapsedMs}
|
||||||
|
-- -> "home" | "target" | "dump" | "wait" | "giveUp"
|
||||||
|
ADFlowWagons.EMPTY_MIN_LITERS = 100
|
||||||
|
ADFlowWagons.EMPTY_TIMEOUT_MS = 600000
|
||||||
|
function ADFlowWagons.emptyStep(stage, s)
|
||||||
|
local cargo = s.cargo or 0
|
||||||
|
if stage == "start" then
|
||||||
|
if cargo < ADFlowWagons.EMPTY_MIN_LITERS then return "home" end
|
||||||
|
return s.hasTarget and "target" or "dump"
|
||||||
|
end
|
||||||
|
if (s.elapsedMs or 0) >= ADFlowWagons.EMPTY_TIMEOUT_MS then return "giveUp" end
|
||||||
|
if s.adActive then return "wait" end
|
||||||
|
if cargo < ADFlowWagons.EMPTY_MIN_LITERS then return "home" end
|
||||||
|
if stage == "target" then return "dump" end
|
||||||
|
return "giveUp"
|
||||||
|
end
|
||||||
|
|
||||||
-- ---- spil ----
|
-- ---- spil ----
|
||||||
|
|
||||||
local waiting = setmetatable({}, {__mode = "k"}) -- traktor -> runId (venter på sin vogn)
|
local waiting = setmetatable({}, {__mode = "k"}) -- traktor -> runId (venter på sin vogn)
|
||||||
@@ -178,6 +196,7 @@ function ADFlowWagons.isPoolBusy(vehicle, tractorId)
|
|||||||
or (ADFieldSilos ~= nil and ADFieldSilos.isLoaned(vehicle))
|
or (ADFieldSilos ~= nil and ADFieldSilos.isLoaned(vehicle))
|
||||||
or (ADPool ~= nil and ADPool.isReturning(vehicle))
|
or (ADPool ~= nil and ADPool.isReturning(vehicle))
|
||||||
or (ADCpBridge ~= nil and ADCpBridge.isWorking(vehicle))
|
or (ADCpBridge ~= nil and ADCpBridge.isWorking(vehicle))
|
||||||
|
or (ADFlowWagons.isEmptying ~= nil and ADFlowWagons.isEmptying(vehicle))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Før en flow-traktor startes: hent sin vogn / vent på den. -> håndteret, resultat (som startVehicle)
|
-- Før en flow-traktor startes: hent sin vogn / vent på den. -> håndteret, resultat (som startVehicle)
|
||||||
@@ -239,20 +258,119 @@ function ADFlowWagons.beforeStart(adEnv, run, vehicle)
|
|||||||
return true, {vehicle = vehicle, ok = true, reason = "fetchingWagon"}
|
return true, {vehicle = vehicle, ok = true, reason = "fetchingWagon"}
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Stop/slet/bygning væk: vognen på plads, traktoren hjem.
|
-- Stop/slet/bygning væk: vognen tømmes (flowets mål, ellers silo/egen fabrik), sættes på plads, traktoren hjem.
|
||||||
|
local emptying = setmetatable({}, {__mode = "k"}) -- traktor -> {stage, since, fillType, runName}
|
||||||
|
local nowMs = 0
|
||||||
|
|
||||||
|
local function cargoOf(adEnv, vehicle)
|
||||||
|
local level, fillType = 0, nil
|
||||||
|
local ok, units = pcall(adEnv.AutoDrive.getAllDischargeableUnits, vehicle)
|
||||||
|
for _, unit in ipairs(ok and units or {}) do
|
||||||
|
local object, index = unit.object, unit.fillUnitIndex
|
||||||
|
if object ~= nil and object.getFillUnitFillLevel ~= nil then
|
||||||
|
local unitLevel = object:getFillUnitFillLevel(index) or 0
|
||||||
|
if unitLevel > 0 then
|
||||||
|
level = level + unitLevel
|
||||||
|
fillType = fillType or object:getFillUnitFillType(index)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return level, fillType
|
||||||
|
end
|
||||||
|
|
||||||
|
local function goHome(adEnv, vehicle)
|
||||||
|
emptying[vehicle] = nil
|
||||||
|
local okHome, pooled = pcall(ADHitch.returnHome, adEnv, vehicle)
|
||||||
|
if not (okHome and pooled) then
|
||||||
|
local park = ADFieldWork.parkMarkerId(adEnv, vehicle)
|
||||||
|
if park ~= nil then pcall(ADFieldWork.startAd, adEnv, vehicle, adEnv.AutoDrive.MODE_DRIVETO, park, nil) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function fillName(fillType)
|
||||||
|
local desc = fillType ~= nil and g_fillTypeManager ~= nil and g_fillTypeManager:getFillTypeByIndex(fillType) or nil
|
||||||
|
return desc ~= nil and (desc.title or desc.name) or tostring(fillType)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function startDump(adEnv, vehicle, state)
|
||||||
|
local cargo, fillType = cargoOf(adEnv, vehicle)
|
||||||
|
local isReachable = function(markerId)
|
||||||
|
return ADUnloadWait == nil or ADUnloadWait.hasRouteTo == nil or ADUnloadWait.hasRouteTo(adEnv, vehicle, markerId)
|
||||||
|
end
|
||||||
|
local ok, marker, why = pcall(ADLoadSwap.findDumpMarker, adEnv, vehicle, fillType, cargo, nil, isReachable, nil, nil, true)
|
||||||
|
if not ok or marker == nil then
|
||||||
|
Logging.warning(ADFlowWagons.LOG_PREFIX .. "'%s' har stadig %d l %s — intet sted at aflæsse (%s); parkeres med last",
|
||||||
|
tostring(ADRuns.vehicleLabel(vehicle)), math.floor(cargo), fillName(fillType), tostring(ok and why or marker))
|
||||||
|
goHome(adEnv, vehicle)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
state.stage, state.since = "dump", nowMs
|
||||||
|
ADFieldWork.startAd(adEnv, vehicle, adEnv.AutoDrive.MODE_DELIVERTO, marker.id, nil, fillType)
|
||||||
|
Logging.info(ADFlowWagons.LOG_PREFIX .. "'%s' aflæsser resten (%d l %s) ved %s før parkering",
|
||||||
|
tostring(ADRuns.vehicleLabel(vehicle)), math.floor(cargo), fillName(fillType), tostring(marker.name))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Én traktor hjem (fra et stoppet/slettet flow): tøm først, så parkering.
|
||||||
|
function ADFlowWagons.homeVehicle(adEnv, vehicle, runName)
|
||||||
|
waiting[vehicle] = nil
|
||||||
|
if fetching[vehicle] ~= nil then
|
||||||
|
fetching[vehicle] = nil
|
||||||
|
ADHitch.cancel(vehicle)
|
||||||
|
end
|
||||||
|
local module = vehicle.ad ~= nil and vehicle.ad.stateModule or nil
|
||||||
|
local target = module ~= nil and module.getSecondMarker ~= nil and module:getSecondMarker() or nil
|
||||||
|
local cargo, fillType = cargoOf(adEnv, vehicle)
|
||||||
|
local action = ADFlowWagons.emptyStep("start", {cargo = cargo, hasTarget = target ~= nil})
|
||||||
|
if action == "home" then return goHome(adEnv, vehicle) end
|
||||||
|
local state = {stage = action, since = nowMs, runName = runName}
|
||||||
|
emptying[vehicle] = state
|
||||||
|
if action == "target" then
|
||||||
|
ADFieldWork.startAd(adEnv, vehicle, adEnv.AutoDrive.MODE_DELIVERTO, target.id, nil, fillType)
|
||||||
|
Logging.info(ADFlowWagons.LOG_PREFIX .. "'%s' afleverer sit læs (%d l %s) ved %s før parkering",
|
||||||
|
tostring(ADRuns.vehicleLabel(vehicle)), math.floor(cargo), fillName(fillType), tostring(target.name))
|
||||||
|
else
|
||||||
|
startDump(adEnv, vehicle, state)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ADFlowWagons.isEmptying(vehicle)
|
||||||
|
return emptying[vehicle] ~= nil
|
||||||
|
end
|
||||||
|
|
||||||
function ADFlowWagons.sendHome(adEnv, run)
|
function ADFlowWagons.sendHome(adEnv, run)
|
||||||
for _, vehicleId in ipairs(run.vehicleIds or {}) do
|
for _, vehicleId in ipairs(run.vehicleIds or {}) do
|
||||||
local vehicle = ADRunsController.findVehicleById(adEnv, vehicleId)
|
local vehicle = ADRunsController.findVehicleById(adEnv, vehicleId)
|
||||||
if vehicle ~= nil then
|
if vehicle ~= nil then
|
||||||
waiting[vehicle] = nil
|
local ok, err = pcall(ADFlowWagons.homeVehicle, adEnv, vehicle, run.name)
|
||||||
if fetching[vehicle] ~= nil then
|
if not ok then
|
||||||
fetching[vehicle] = nil
|
Logging.warning(ADFlowWagons.LOG_PREFIX .. "hjem fejlede: %s", tostring(err))
|
||||||
ADHitch.cancel(vehicle)
|
goHome(adEnv, vehicle)
|
||||||
end
|
end
|
||||||
local okHome, pooled = pcall(ADHitch.returnHome, adEnv, vehicle)
|
end
|
||||||
if not (okHome and pooled) then
|
end
|
||||||
local park = ADFieldWork.parkMarkerId(adEnv, vehicle)
|
end
|
||||||
if park ~= nil then pcall(ADFieldWork.startAd, adEnv, vehicle, adEnv.AutoDrive.MODE_DRIVETO, park, nil) end
|
|
||||||
|
local function tickEmptying(adEnv)
|
||||||
|
local list = {}
|
||||||
|
for vehicle, state in pairs(emptying) do table.insert(list, {vehicle = vehicle, state = state}) end
|
||||||
|
for _, item in ipairs(list) do
|
||||||
|
local vehicle, state = item.vehicle, item.state
|
||||||
|
local module = vehicle.ad ~= nil and vehicle.ad.stateModule or nil
|
||||||
|
local cargo, fillType = cargoOf(adEnv, vehicle)
|
||||||
|
local controlled = vehicle.getIsControlled ~= nil and vehicle:getIsControlled()
|
||||||
|
if controlled then
|
||||||
|
emptying[vehicle] = nil -- spilleren har overtaget
|
||||||
|
else
|
||||||
|
local action = ADFlowWagons.emptyStep(state.stage, {cargo = cargo, adActive = module ~= nil and module:isActive(),
|
||||||
|
elapsedMs = nowMs - state.since})
|
||||||
|
if action == "home" then
|
||||||
|
goHome(adEnv, vehicle)
|
||||||
|
elseif action == "dump" then
|
||||||
|
startDump(adEnv, vehicle, state)
|
||||||
|
elseif action == "giveUp" then
|
||||||
|
Logging.warning(ADFlowWagons.LOG_PREFIX .. "'%s' kunne ikke tømme vognen (%d l %s tilbage) — parkeres med last",
|
||||||
|
tostring(ADRuns.vehicleLabel(vehicle)), math.floor(cargo), fillName(fillType))
|
||||||
|
goHome(adEnv, vehicle)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -329,17 +447,26 @@ local function cleanupAfterLoad(adEnv)
|
|||||||
local controlled = vehicle ~= nil and vehicle.getIsControlled ~= nil and vehicle:getIsControlled()
|
local controlled = vehicle ~= nil and vehicle.getIsControlled ~= nil and vehicle:getIsControlled()
|
||||||
if module ~= nil and not module:isActive() and not controlled and #ADHitch.poolParkIds(adEnv, vehicle) > 0
|
if module ~= nil and not module:isActive() and not controlled and #ADHitch.poolParkIds(adEnv, vehicle) > 0
|
||||||
and not ADFlowWagons.isPoolBusy(vehicle, vehicleId) then
|
and not ADFlowWagons.isPoolBusy(vehicle, vehicleId) then
|
||||||
Logging.info(ADFlowWagons.LOG_PREFIX .. "flow '%s' er stoppet: '%s' sætter sin vogn på plads", tostring(run.name),
|
Logging.info(ADFlowWagons.LOG_PREFIX .. "flow '%s' er stoppet: '%s' tømmer og sætter sin vogn på plads", tostring(run.name),
|
||||||
tostring(ADRuns.vehicleLabel(vehicle)))
|
tostring(ADRuns.vehicleLabel(vehicle)))
|
||||||
pcall(ADHitch.returnHome, adEnv, vehicle)
|
pcall(ADFlowWagons.homeVehicle, adEnv, vehicle, run.name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local emptyTimer = 0
|
||||||
|
|
||||||
function ADFlowWagons.tick(adEnv, dt)
|
function ADFlowWagons.tick(adEnv, dt)
|
||||||
if adEnv == nil or ADRunsController.store == nil then return end
|
if adEnv == nil or ADRunsController.store == nil then return end
|
||||||
|
nowMs = nowMs + dt
|
||||||
|
emptyTimer = emptyTimer + dt
|
||||||
|
if emptyTimer >= 2000 then
|
||||||
|
emptyTimer = 0
|
||||||
|
local okEmpty, errEmpty = pcall(tickEmptying, adEnv)
|
||||||
|
if not okEmpty then Logging.warning(ADFlowWagons.LOG_PREFIX .. "tømning: %s", tostring(errEmpty)) end
|
||||||
|
end
|
||||||
if not cleanedUp then
|
if not cleanedUp then
|
||||||
sinceLoad = sinceLoad + dt
|
sinceLoad = sinceLoad + dt
|
||||||
if sinceLoad >= ADFlowWagons.AFTER_LOAD_MS then
|
if sinceLoad >= ADFlowWagons.AFTER_LOAD_MS then
|
||||||
|
|||||||
@@ -1203,9 +1203,14 @@ function ADRunsController.stopAllAndPark(adEnv)
|
|||||||
if ADFieldSilos ~= nil and ADFieldSilos.stopAll ~= nil then pcall(ADFieldSilos.stopAll, adEnv) end
|
if ADFieldSilos ~= nil and ADFieldSilos.stopAll ~= nil then pcall(ADFieldSilos.stopAll, adEnv) end
|
||||||
if ADFieldJobs ~= nil and ADFieldJobs.setPaused ~= nil then ADFieldJobs.setPaused(true) end
|
if ADFieldJobs ~= nil and ADFieldJobs.setPaused ~= nil then ADFieldJobs.setPaused(true) end
|
||||||
for _, vehicle in ipairs(toPark) do
|
for _, vehicle in ipairs(toPark) do
|
||||||
-- flow-vogn/puljeredskab bag traktoren: sæt det af på sin plads og kør hjem
|
-- flow-traktor: tøm vognen, sæt den af på sin plads og kør hjem (ADFlowWagons klarer hele turen)
|
||||||
local okHome, pooled = false, false
|
local okHome, pooled = false, false
|
||||||
if ADHitch ~= nil then okHome, pooled = pcall(ADHitch.returnHome, adEnv, vehicle) end
|
if ADFlowWagons ~= nil and ADRunsController.getRunForVehicle(vehicle) ~= nil then
|
||||||
|
okHome = pcall(ADFlowWagons.homeVehicle, adEnv, vehicle)
|
||||||
|
pooled = okHome
|
||||||
|
elseif ADHitch ~= nil then
|
||||||
|
okHome, pooled = pcall(ADHitch.returnHome, adEnv, vehicle)
|
||||||
|
end
|
||||||
local park = not (okHome and pooled) and ADFieldWork ~= nil and ADFieldWork.parkMarkerId ~= nil and ADFieldWork.parkMarkerId(adEnv, vehicle) or nil
|
local park = not (okHome and pooled) and ADFieldWork ~= nil and ADFieldWork.parkMarkerId ~= nil and ADFieldWork.parkMarkerId(adEnv, vehicle) or nil
|
||||||
if okHome and pooled then
|
if okHome and pooled then
|
||||||
summary.parked = summary.parked + 1
|
summary.parked = summary.parked + 1
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||||
<modDesc descVersion="107">
|
<modDesc descVersion="107">
|
||||||
<author>masterdraco</author>
|
<author>masterdraco</author>
|
||||||
<version>1.51.3.0</version>
|
<version>1.51.4.0</version>
|
||||||
<title>
|
<title>
|
||||||
<en>AD Smart Pickup</en>
|
<en>AD Smart Pickup</en>
|
||||||
</title>
|
</title>
|
||||||
|
|||||||
@@ -66,5 +66,15 @@ check("gæt: andet flow", W.guessWagon("Goat Food", 2, cands, {}), "g1")
|
|||||||
check("gæt: intet passer", W.guessWagon("Pig Food", 1, cands, {}), nil)
|
check("gæt: intet passer", W.guessWagon("Pig Food", 1, cands, {}), nil)
|
||||||
check("gæt: store/små bogstaver", W.guessWagon("cow food", 2, cands, {}), "v2")
|
check("gæt: store/små bogstaver", W.guessWagon("cow food", 2, cands, {}), "v2")
|
||||||
check("gæt: 'Cow Food 1' matcher ikke 'Cow Food 10'", W.guessWagon("Cow Food", 1, {{id = "x", parkName = "P Cow Food vogn 10"}, {id = "y", parkName = "P Cow Food vogn 1"}}, {}), "y")
|
check("gæt: 'Cow Food 1' matcher ikke 'Cow Food 10'", W.guessWagon("Cow Food", 1, {{id = "x", parkName = "P Cow Food vogn 10"}, {id = "y", parkName = "P Cow Food vogn 1"}}, {}), "y")
|
||||||
|
-- tøm vognen før den parkeres (flow stoppet): mål -> silo/fabrik -> hjem
|
||||||
|
check("tøm: tom vogn -> hjem", W.emptyStep("start", {cargo = 0}), "home")
|
||||||
|
check("tøm: last -> flowets mål", W.emptyStep("start", {cargo = 5000, hasTarget = true}), "target")
|
||||||
|
check("tøm: last uden mål -> silo", W.emptyStep("start", {cargo = 5000, hasTarget = false}), "dump")
|
||||||
|
check("tøm: kører stadig -> vent", W.emptyStep("target", {cargo = 5000, adActive = true}), "wait")
|
||||||
|
check("tøm: mål fuldt, rest -> silo", W.emptyStep("target", {cargo = 2000}), "dump")
|
||||||
|
check("tøm: målet tog det hele -> hjem", W.emptyStep("target", {cargo = 0}), "home")
|
||||||
|
check("tøm: silo tog det -> hjem", W.emptyStep("dump", {cargo = 0}), "home")
|
||||||
|
check("tøm: silo kunne ikke -> giv op, hjem", W.emptyStep("dump", {cargo = 2000}), "giveUp")
|
||||||
|
check("tøm: for længe -> giv op", W.emptyStep("target", {cargo = 5000, adActive = true, elapsedMs = W.EMPTY_TIMEOUT_MS}), "giveUp")
|
||||||
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
|
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
|
||||||
os.exit(failures == 0 and 0 or 1)
|
os.exit(failures == 0 and 0 or 1)
|
||||||
|
|||||||
Reference in New Issue
Block a user