feat: Wait-punkter for rest-læs + læs der passer foretrækkes (v1.7.0.0)

Rest-læs ved fuldt mål: AutoDrive ventede ved aflæsningspunktet 'til tømt' og
spærrede køen. Nu omdirigeres den aktuelle UnloadAtDestinationTask (destinationID +
drivePathModule:setPathTo) til nærmeste ledige markør med 'Wait' i navnet / mappen
Wait (fælles pulje, reservationer pr. køretøj); tilbage når målet har plads til
hele resten. Ventende ser rotateTargets=RT_NONE så 'rotér aflæsning' ikke kører
videre fra Wait-punktet. Ingen ledige punkter = som i dag + én advarsel.

Rangering: varer hvor et fuldt læs (AutoDrive.getAllFillLevels-kapacitet) passer i
målet går forud; passer intet, mest trængende. Nyt modul adUnloadWait.lua;
ADSmartPickup.getTargetFreeCapacity delt hjælper.
This commit is contained in:
2026-09-22 21:12:55 +02:00
parent 2ff0b641b0
commit 39fccefa40
7 changed files with 469 additions and 22 deletions
+67 -18
View File
@@ -357,31 +357,70 @@ local function isFillTypeAccepted(station, husbandry, fillType)
return station.getIsFillTypeSupported == nil or station:getIsFillTypeSupported(fillType)
end
-- Niveau + kapacitet for én vare i aflæsningsmålet; nil hvis målet ikke tager varen.
local function getTargetLevelAndCapacity(station, fillType, farmId)
local husbandry = getHusbandry(station)
if not isFillTypeAccepted(station, husbandry, fillType) then
return nil
end
if husbandry ~= nil then
local level = husbandry:getHusbandryFillLevel(fillType) or 0
return level, husbandry:getHusbandryCapacity(fillType) or level
end
local level, freeSpace = 0, 0
for _, storage in pairs(getTargetStorages(station)) do
level = level + (storage:getFillLevel(fillType) or 0)
freeSpace = freeSpace + (storage:getFreeCapacity(fillType) or 0)
end
if level + freeSpace <= 0 and station.getFreeCapacity ~= nil then
-- ukendt lagertype: brug stationens egen opgørelse af fri plads
level, freeSpace = 0, station:getFreeCapacity(fillType, farmId) or 0
end
return level, level + freeSpace
end
-- Niveau + kapacitet pr. ingrediens i aflæsningsmålets lager; demand giver forbrug/min.
local function getTargetNeeds(station, ingredients, farmId, demand)
local needs = {}
local storages = getTargetStorages(station)
local husbandry = getHusbandry(station)
for _, fillType in ipairs(ingredients) do
if husbandry ~= nil and isFillTypeAccepted(station, husbandry, fillType) then
local level = husbandry:getHusbandryFillLevel(fillType) or 0
table.insert(needs, {fillType = fillType, level = level, capacity = husbandry:getHusbandryCapacity(fillType) or level, litersPerMinute = demand[fillType]})
elseif isFillTypeAccepted(station, husbandry, fillType) then
local level, freeSpace = 0, 0
for _, storage in pairs(storages) do
level = level + (storage:getFillLevel(fillType) or 0)
freeSpace = freeSpace + (storage:getFreeCapacity(fillType) or 0)
end
if level + freeSpace <= 0 and station.getFreeCapacity ~= nil then
-- ukendt lagertype: brug stationens egen opgørelse af fri plads
level, freeSpace = 0, station:getFreeCapacity(fillType, farmId) or 0
end
table.insert(needs, {fillType = fillType, level = level, capacity = level + freeSpace, litersPerMinute = demand[fillType]})
local level, capacity = getTargetLevelAndCapacity(station, fillType, farmId)
if level ~= nil then
table.insert(needs, {fillType = fillType, level = level, capacity = capacity, litersPerMinute = demand[fillType]})
end
end
return needs
end
-- Vognens samlede kapacitet (liter); nil hvis AutoDrive ikke kan opgøre den.
local function getLoadCapacity(adEnv, driver)
if adEnv.AutoDrive.getAllUnits == nil or adEnv.AutoDrive.getAllFillLevels == nil then
return nil
end
local trailers = adEnv.AutoDrive.getAllUnits(driver)
local _, capacity = adEnv.AutoDrive.getAllFillLevels(trailers)
return capacity ~= nil and capacity > 0 and capacity or nil
end
-- Fri plads til varen i køretøjets aflæsningsmål (bruges af Wait-punkt-logikken);
-- nil hvis målet ikke kendes eller ikke tager varen.
function ADSmartPickup.getTargetFreeCapacity(adEnv, driver, fillType)
local secondMarker = driver.ad.stateModule:getSecondMarker()
local farmId = getFarmId(driver)
if secondMarker == nil or farmId == nil then
return nil
end
local targetWayPoint = adEnv.ADGraphManager:getWayPointById(secondMarker.id)
local target = targetWayPoint ~= nil and getUnloadStationAtMarker(adEnv, targetWayPoint, farmId) or nil
if target == nil then
return nil
end
local level, capacity = getTargetLevelAndCapacity(target, fillType, farmId)
if level == nil then
return nil
end
return capacity - level
end
-- Behovsstyret: den ingrediens aflæsningsmålet mangler mest, som også findes i en silo.
function ADSmartPickup.findSupplyPickup(adEnv, driver, ingredients)
local secondMarker = driver.ad.stateModule:getSecondMarker()
@@ -407,7 +446,8 @@ function ADSmartPickup.findSupplyPickup(adEnv, driver, ingredients)
local allMarkers = adEnv.ADGraphManager:getMapMarkers()
local markerStations = collectMarkerStations(adEnv, allMarkers, farmId, target.owningPlaceable)
for _, need in ipairs(ADSupplyPlanner.rankNeeds(getTargetNeeds(target, ingredients, farmId, demand))) do
local loadCapacity = getLoadCapacity(adEnv, driver)
for _, need in ipairs(ADSupplyPlanner.rankNeeds(getTargetNeeds(target, ingredients, farmId, demand), loadCapacity)) do
local choice = findBestSource(markerStations, {need.fillType}, farmId)
if choice ~= nil then
return {
@@ -463,6 +503,9 @@ local function describeChoice(choice)
if choice.need.minutesToEmpty ~= nil then
urgency = string.format(", fabrikken bruger %.0f l/min = %.0f min til tom", choice.need.litersPerMinute, choice.need.minutesToEmpty)
end
if choice.need.fits == false then
urgency = urgency .. ", et fuldt læs passer IKKE (rest ventes ved Wait-punkt)"
end
return string.format("%s: kilde %.0f l, %s, målet har %.0f/%.0f l%s", tostring(fillTypeName), choice.level, source, choice.need.level, choice.need.capacity, urgency)
end
@@ -571,8 +614,11 @@ local function installHook(adEnv)
end
installLoadWaitHook(adEnv)
if ADUnloadWait ~= nil then
ADUnloadWait.install(adEnv)
end
Logging.info(ADSmartPickup.LOG_PREFIX .. "aktiv (mindst fyldte silo med varen; flere valgte varer = behovsstyret forsyning)")
Logging.info(ADSmartPickup.LOG_PREFIX .. "aktiv (mindst fyldte silo med varen; flere valgte varer = behovsstyret forsyning; Wait-punkter for rest-læs)")
end
-- Når AutoDrive stopper, får køretøjet hele ingredienslisten tilbage i varevalget
@@ -608,6 +654,9 @@ function ADSmartPickup:update(dt)
return
end
if ADUnloadWait ~= nil then
pcall(ADUnloadWait.releaseInactive)
end
local ok, err = pcall(restoreStoppedVehicles)
if not ok then
Logging.warning(ADSmartPickup.LOG_PREFIX .. "kunne ikke gendanne varevalg: %s", tostring(err))