feat(lager): lagerture undgår markører andre udkørsels-forløb henter fra (Milk Store læsser af ved 'unload', ikke ved 'Load') (v1.17.5.0)

This commit is contained in:
2026-09-24 04:07:51 +02:00
parent c0f523700e
commit 73e886ee26
8 changed files with 82 additions and 13 deletions
+18 -7
View File
@@ -54,7 +54,23 @@ end
-- Nærmeste silo med plads til resten og vejnet fra traktoren; siloer der allerede har varen
-- foretrækkes. Returnerer marker — eller nil + en forklaring (til loggen).
-- excludedPlaceables (valgfri): {[placeable] = true} der aldrig må vælges (fx udkørslens kilder).
function ADLoadSwap.findDumpMarker(adEnv, vehicle, fillType, rest, homeWayPointId, isReachable, excludedPlaceables)
-- Rækkefølge for aflæsnings-siloer: markører et forløb HENTER fra (avoidMarkers = {[id] = true}) sidst —
-- ellers læsser en lagertur af dér hvor en salgstur skal læsse (samme tank-række); dernæst siloer der
-- allerede har varen, så nærmeste. Returnerer en ny sorteret liste.
function ADLoadSwap.rankDumpCandidates(candidates, avoidMarkers)
local ranked = {}
for _, candidate in ipairs(candidates or {}) do table.insert(ranked, candidate) end
local function avoided(candidate) return avoidMarkers ~= nil and avoidMarkers[candidate.marker.id] == true end
table.sort(ranked, function(a, b)
if avoided(a) ~= avoided(b) then return not avoided(a) end
if a.hasFillType ~= b.hasFillType then return a.hasFillType end
if a.distance ~= b.distance then return a.distance < b.distance end
return a.marker.id < b.marker.id
end)
return ranked
end
function ADLoadSwap.findDumpMarker(adEnv, vehicle, fillType, rest, homeWayPointId, isReachable, excludedPlaceables, avoidMarkers)
if vehicle.rootNode == nil then
return nil, "køretøjet har ingen position"
end
@@ -82,12 +98,7 @@ function ADLoadSwap.findDumpMarker(adEnv, vehicle, fillType, rest, homeWayPointI
end
end
end
table.sort(candidates, function(a, b)
if a.hasFillType ~= b.hasFillType then
return a.hasFillType
end
return a.distance < b.distance
end)
candidates = ADLoadSwap.rankDumpCandidates(candidates, avoidMarkers)
for _, candidate in ipairs(candidates) do
if isReachable(candidate.marker.id) then
return candidate.marker
+2 -1
View File
@@ -200,7 +200,8 @@ local function findStoreMarker(adEnv, vehicle, product, capacity, sources, liter
end
end
local liters = math.max(1, math.min(available, capacity or available))
local marker = ADLoadSwap.findDumpMarker(adEnv, vehicle, product.fillType, liters, nil, isReachable, ADSources.getSourcePlaceables(sources))
local avoid = ADRunsController ~= nil and ADRunsController.getPickupMarkers ~= nil and ADRunsController.getPickupMarkers() or nil
local marker = ADLoadSwap.findDumpMarker(adEnv, vehicle, product.fillType, liters, nil, isReachable, ADSources.getSourcePlaceables(sources), avoid)
if marker == nil then
return nil
end
+11
View File
@@ -136,6 +136,17 @@ function ADRunsController.unassignVehicle(vehicle)
end
end
-- Markører udkørsels-forløb HENTER fra: {[wayPointId] = true}. Lagerture læsser helst ikke af dér.
function ADRunsController.getPickupMarkers()
local result = {}
for _, run in ipairs(ADRunsController.store ~= nil and ADRunsController.store.runs or {}) do
if run.kind == "outbound" then
for _, wayPointId in ipairs(run.sourceWayPointIds or {}) do result[wayPointId] = true end
end
end
return result
end
-- ---- køretøjsnavne ----
ADRunsController.NAME_INTERVAL_MS = 2000
+1 -1
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<modDesc descVersion="107">
<author>masterdraco</author>
<version>1.17.4.0</version>
<version>1.17.5.0</version>
<title>
<en>AD Smart Pickup</en>
</title>
+4 -2
View File
@@ -1,6 +1,6 @@
# AD Smart Pickup — brugermanual
Version 1.17.4 · Farming Simulator 25 · tillæg til AutoDrive
Version 1.17.5 · Farming Simulator 25 · tillæg til AutoDrive
*English version: [USER_MANUAL.md](USER_MANUAL.md)*
@@ -304,7 +304,9 @@ Før hver pålæsning, og hvert femte sekund mens traktoren holder, vurderer mod
til salg **uanset mængde**. Det sikrer, at du får pengene, når prisen topper. Den højeste pris-%
går først.
2. **Lager.** Findes en Lager-vare med et fuldt læs, eller en kilde over tærsklen, køres den til den
nærmeste silo med plads til hele læsset. Den mest fyldte kilde går først.
nærmeste silo med plads til hele læsset. Den mest fyldte kilde går først. Markører, som et andet
udkørselsflow henter fra, bruges kun som aflæsningssted, hvis intet andet passer. Så læsser en
lagertur ikke af, hvor en salgstur skal læsse.
3. **Ingen tur.** Traktoren holder ved et Wait-punkt og prøver igen. Status viser hvorfor, fx
`holder ved Wait 3: SUGAR 78 % af top (kræver 90), lager 41 %`.
+4 -2
View File
@@ -1,6 +1,6 @@
# AD Smart Pickup — user manual
Version 1.17.4 · Farming Simulator 25 · add-on for AutoDrive
Version 1.17.5 · Farming Simulator 25 · add-on for AutoDrive
*Dansk version: [BRUGERMANUAL.md](BRUGERMANUAL.md)*
@@ -308,7 +308,9 @@ Before each loading, and every five seconds while the tractor waits, the mod che
drives to sell **regardless of amount**. This makes sure you get the money when the price peaks.
The highest price share goes first.
2. **Store.** If a Store good has a full load, or a source is above its threshold, it is taken to the
nearest silo with room for the whole load. The fullest source goes first.
nearest silo with room for the whole load. The fullest source goes first. Markers another delivery
flow loads from are only used for unloading when nothing else fits. That way a storage trip does
not unload where a sale trip needs to load.
3. **No trip.** The tractor parks at a Wait point and tries again. The status says why, such as
`holding at Wait 3: SUGAR 78 % of top (needs 90), storage 41 %`.
+31
View File
@@ -0,0 +1,31 @@
-- Kør: luajit tests/test_adLoadSwap.lua (fra repo-roden)
-- Ren rangering af aflæsnings-siloer (lagermål for udkørsel og læs-bytte).
dofile("FS25_ADSmartPickup/adLoadSwap.lua")
local L = ADLoadSwap
local failures = 0
local function check(name, actual, expected)
if actual == expected then
print("OK " .. name)
else
failures = failures + 1
print(string.format("FAIL %s: forventede %s, fik %s", name, tostring(expected), tostring(actual)))
end
end
-- LS1: markører et andet forløb HENTER fra (fx "Milk Storage Load") vælges sidst; ellers har-varen, så afstand
local candidates = {
{marker = {id = 1, name = "Milk Storage Load"}, hasFillType = true, distance = 100},
{marker = {id = 2, name = "Milk Storage unload"}, hasFillType = true, distance = 400},
{marker = {id = 3, name = "Silo tom"}, hasFillType = false, distance = 10},
}
local ranked = L.rankDumpCandidates(candidates, {[1] = true})
check("LS1 afhentningsmarkør undgås", ranked[1].marker.id, 2)
check("LS1 derefter tom silo før afhentning", ranked[2].marker.id, 3)
check("LS1 afhentning sidst (stadig mulig)", ranked[3].marker.id, 1)
local plain = L.rankDumpCandidates(candidates, nil)
check("LS1 uden undgå-liste: har varen + nærmest", plain[1].marker.id, 1)
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
os.exit(failures == 0 and 0 or 1)
+11
View File
@@ -719,5 +719,16 @@ do
check("RC-navne label uden AD-navn", ADRuns.vehicleLabel({getName = function() return "Fendt" end}), "Fendt")
end
-- PM: afhentningsmarkører fra udkørsels-forløb (lagerture undgår dem som aflæsningssted)
do
local sale = ADRunsController.createRun("Salg-test", "outbound")
ADRunsController.updateRun(sale.id, {sourceWayPointIds = {4711, 4712}})
local supply = ADRunsController.createRun("Forsyning-test", "supply")
ADRunsController.updateRun(supply.id, {sourceWayPointIds = {9999}})
local pickups = ADRunsController.getPickupMarkers()
check("PM udkørsels-kilde med", pickups[4711], true)
check("PM forsyning tæller ikke", pickups[9999], nil)
end
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
os.exit(failures == 0 and 0 or 1)