fix: rute-tjek begge veje før Wait-omdirigering; hjem ved halv-tomt mål (v1.7.2.0)
In-game 2026-09-22 21:37: Fastrac omdirigeret til 'Cow Wait' uden vejnet dertil -> AutoDrive 'cannot reach' + StopAndDisableADTask (AD slukket i stalden). Nu: ADGraphManager:getPathTo + pathFromTo (rene opslag) skal ende i hhv. Wait-punkt og mål, ellers næste punkt; intet nåeligt = som i dag + advarsel. 700.000 l-vogn i 300.000 l-stald kunne aldrig opfylde 'hele resten passer': ADSupplyPlanner.canUnloadRest = fri >= min(rest, 50 % af kapacitet).
This commit is contained in:
@@ -401,7 +401,7 @@ local function getLoadCapacity(adEnv, driver)
|
||||
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);
|
||||
-- Fri plads + kapacitet for varen i køretøjets aflæsningsmål (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()
|
||||
@@ -418,7 +418,7 @@ function ADSmartPickup.getTargetFreeCapacity(adEnv, driver, fillType)
|
||||
if level == nil then
|
||||
return nil
|
||||
end
|
||||
return capacity - level
|
||||
return capacity - level, capacity
|
||||
end
|
||||
|
||||
-- Behovsstyret: den ingrediens aflæsningsmålet mangler mest, som også findes i en silo.
|
||||
|
||||
@@ -132,20 +132,39 @@ function ADSupplyPlanner.isWaitMarker(marker)
|
||||
end
|
||||
|
||||
-- candidates: {{marker, x, z}}; claims: {[marker.id] = køretøj}. Nærmeste punkt der er
|
||||
-- ledigt eller allerede reserveret af dette køretøj. nil hvis alle er optaget.
|
||||
function ADSupplyPlanner.pickNearestFreeWaitPoint(candidates, claims, x, z, vehicle)
|
||||
local best, bestDistance = nil, nil
|
||||
-- ledigt (eller allerede reserveret af dette køretøj) og som isReachable(candidate)
|
||||
-- godkender (valgfri; AutoDrive slukker sig selv, hvis den sendes mod et punkt uden rute).
|
||||
-- nil hvis intet punkt duer. Nåelighed tjekkes kun for de punkter der er i spil, nærmeste først.
|
||||
function ADSupplyPlanner.pickNearestFreeWaitPoint(candidates, claims, x, z, vehicle, isReachable)
|
||||
local free = {}
|
||||
for _, candidate in ipairs(candidates) do
|
||||
local owner = claims[candidate.marker.id]
|
||||
if owner == nil or owner == vehicle then
|
||||
local dx, dz = candidate.x - x, candidate.z - z
|
||||
local distance = dx * dx + dz * dz
|
||||
if bestDistance == nil or distance < bestDistance then
|
||||
best, bestDistance = candidate, distance
|
||||
end
|
||||
table.insert(free, {candidate = candidate, distance = dx * dx + dz * dz})
|
||||
end
|
||||
end
|
||||
return best
|
||||
table.sort(free, function(a, b) return a.distance < b.distance end)
|
||||
for _, entry in ipairs(free) do
|
||||
if isReachable == nil or isReachable(entry.candidate) then
|
||||
return entry.candidate
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Så stor en andel af målets kapacitet skal være fri, før en rest der er større end
|
||||
-- det, kan afleveres (en 700.000 l-vogn kan aldrig tømme HELE resten i en 300.000 l-stald).
|
||||
ADSupplyPlanner.WAIT_RETURN_FREE_FRACTION = 0.5
|
||||
|
||||
-- Kan den ventende køre hjem? Ja når hele resten passer, eller når målet er mindst
|
||||
-- WAIT_RETURN_FREE_FRACTION tomt. capacity nil = kun hele resten tæller.
|
||||
function ADSupplyPlanner.canUnloadRest(freeSpace, rest, capacity)
|
||||
local needed = rest
|
||||
if capacity ~= nil and capacity > 0 then
|
||||
needed = math.min(rest, capacity * ADSupplyPlanner.WAIT_RETURN_FREE_FRACTION)
|
||||
end
|
||||
return freeSpace >= needed
|
||||
end
|
||||
|
||||
-- needs: {{fillType, level, capacity[, litersPerMinute]}, ...}. Returnerer NY liste,
|
||||
|
||||
@@ -60,6 +60,23 @@ local function getVehiclePosition(vehicle)
|
||||
return x, z
|
||||
end
|
||||
|
||||
-- Ender ruten i målet? (AutoDrive returnerer tom/afkortet liste når der ingen vej er.)
|
||||
local function pathReaches(path, wayPointId)
|
||||
return path ~= nil and #path > 0 and path[#path].id == wayPointId
|
||||
end
|
||||
|
||||
-- Findes der vejnet fra køretøjet til Wait-punktet OG fra Wait-punktet hjem til målet?
|
||||
-- Sendes AutoDrive mod et punkt uden rute, viser den "cannot reach" og slukker sig selv.
|
||||
-- getPathTo/pathFromTo er rene opslag uden bivirkninger.
|
||||
local function hasRouteBothWays(adEnv, vehicle, waitWayPointId, homeWayPointId)
|
||||
local graph = adEnv.ADGraphManager
|
||||
if graph.getPathTo == nil or graph.pathFromTo == nil then
|
||||
return true
|
||||
end
|
||||
return pathReaches(graph:getPathTo(vehicle, waitWayPointId), waitWayPointId)
|
||||
and pathReaches(graph:pathFromTo(waitWayPointId, homeWayPointId), homeWayPointId)
|
||||
end
|
||||
|
||||
local function redirect(task, destinationID)
|
||||
task.destinationID = destinationID
|
||||
task.state = ADUnloadWait.STATE_DRIVING
|
||||
@@ -90,11 +107,14 @@ local function startWaiting(adEnv, task)
|
||||
end
|
||||
|
||||
local x, z = getVehiclePosition(vehicle)
|
||||
local candidate = x ~= nil and ADSupplyPlanner.pickNearestFreeWaitPoint(getWaitCandidates(adEnv), claims, x, z, vehicle) or nil
|
||||
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
|
||||
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 (markør i en mappe med 'Wait' i navnet), så AutoDrive venter ved målet", tostring(vehicle:getName()), rest)
|
||||
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)
|
||||
end
|
||||
return
|
||||
end
|
||||
@@ -118,8 +138,8 @@ local function updateWaiting(adEnv, task, wait)
|
||||
release(vehicle)
|
||||
return
|
||||
end
|
||||
local free = ADSmartPickup.getTargetFreeCapacity(adEnv, vehicle, fillType)
|
||||
if free == nil or free < rest then
|
||||
local free, capacity = ADSmartPickup.getTargetFreeCapacity(adEnv, vehicle, fillType)
|
||||
if free == nil or not ADSupplyPlanner.canUnloadRest(free, rest, capacity) then
|
||||
return
|
||||
end
|
||||
local home = wait.homeDestinationID
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<modDesc descVersion="107">
|
||||
<author>masterdraco</author>
|
||||
<version>1.7.1.0</version>
|
||||
<version>1.7.2.0</version>
|
||||
<title>
|
||||
<en>AD Smart Pickup</en>
|
||||
</title>
|
||||
|
||||
Reference in New Issue
Block a user