fix: markørens silo er den bag traktorens næse, ikke nærmeste trigger (v1.3.0.0)

I tætte silo-rækker står markøren ved NÆSTE silos rist (næsen stopper dér, vognen
holder et vogntog bagved). Nærmeste-trigger-koblingen ramte derfor nabosiloen og
forskød alle 40 markører én silo: roer i silo 2 blev til '1 Silo Storage'.
Koblingen bruger nu ankomstretningen fra forrige waypoint og vælger nærmeste
trigger bag næsen (højst 2 m foran); ellers nærmeste trigger som før.
Verificeret mod savegame: 40 markører -> 40 forskellige siloer, TMR Unload -> TMR.
This commit is contained in:
2026-09-21 16:00:53 +02:00
parent bcc245863e
commit e414c99b58
4 changed files with 76 additions and 21 deletions
+47 -18
View File
@@ -13,6 +13,9 @@ ADSmartPickup = {}
-- Markøren er dér hvor trækkerens næse stopper; læssetriggeren ligger et
-- vogntog bagved. Siloer tættere end dette regnes som "markørens silo".
ADSmartPickup.MAX_MARKER_TO_TRIGGER_DISTANCE = 40
-- I tætte silo-rækker ligger nabosiloens trigger FORAN næsen og er ofte nærmere
-- end markørens egen. Triggere mere end dette foran næsen hører til naboen.
ADSmartPickup.MAX_TRIGGER_AHEAD_OF_MARKER = 2
-- Under dette niveau regnes siloen som tom (undgår ture efter støv-rester).
ADSmartPickup.MIN_USEFUL_LITERS = 1
ADSmartPickup.LOG_PREFIX = "ADSmartPickup: "
@@ -68,41 +71,67 @@ local function getWantedFillTypes(driver)
return wanted
end
local function getDistanceToTriggers(triggers, nodeFields, x, z)
local closest = math.huge
-- Ankomstretning ved markøren (enhedsvektor) ud fra forrige waypoint, ellers nil.
local function getArrivalDirection(adEnv, wayPoint)
local previousId = wayPoint.incoming ~= nil and wayPoint.incoming[1] or nil
local previous = previousId ~= nil and adEnv.ADGraphManager:getWayPointById(previousId) or nil
if previous == nil then
return nil
end
local dx, dz = wayPoint.x - previous.x, wayPoint.z - previous.z
local length = math.sqrt(dx * dx + dz * dz)
if length < 0.01 then
return nil
end
return {x = dx / length, z = dz / length}
end
-- Nærmeste trigger-afstand for en station, samlet og blandt triggere BAG næsen.
local function getDistancesToTriggers(triggers, nodeFields, wayPoint, direction)
local closest, closestBehind = math.huge, math.huge
for _, trigger in pairs(triggers or {}) do
for _, field in ipairs(nodeFields) do
local node = trigger[field]
if node ~= nil and entityExists(node) then
local tx, _, tz = getWorldTranslation(node)
closest = math.min(closest, MathUtil.vector2Length(x - tx, z - tz))
local distance = MathUtil.vector2Length(wayPoint.x - tx, wayPoint.z - tz)
closest = math.min(closest, distance)
-- > 0: triggeren ligger bag næsen set i køreretningen
local behind = direction ~= nil and ((wayPoint.x - tx) * direction.x + (wayPoint.z - tz) * direction.z) or nil
if behind ~= nil and behind >= -ADSmartPickup.MAX_TRIGGER_AHEAD_OF_MARKER then
closestBehind = math.min(closestBehind, distance)
end
end
end
end
return closest
return closest, closestBehind
end
local function getClosestStation(candidateStations, triggersField, nodeFields, wayPoint, farmId)
local bestStation = nil
local bestDistance = ADSmartPickup.MAX_MARKER_TO_TRIGGER_DISTANCE
-- Markørens station: nærmeste trigger bag næsen; findes ingen (eller er
-- retningen ukendt), nærmeste trigger overhovedet.
local function getClosestStation(adEnv, candidateStations, triggersField, nodeFields, wayPoint, farmId)
local direction = getArrivalDirection(adEnv, wayPoint)
local best = {any = {distance = ADSmartPickup.MAX_MARKER_TO_TRIGGER_DISTANCE}, behind = {distance = ADSmartPickup.MAX_MARKER_TO_TRIGGER_DISTANCE}}
for _, station in pairs(candidateStations) do
if g_currentMission.accessHandler:canFarmAccess(farmId, station) then
local distance = getDistanceToTriggers(station[triggersField], nodeFields, wayPoint.x, wayPoint.z)
if distance < bestDistance then
bestDistance = distance
bestStation = station
local closest, closestBehind = getDistancesToTriggers(station[triggersField], nodeFields, wayPoint, direction)
if closest < best.any.distance then
best.any = {distance = closest, station = station}
end
if closestBehind < best.behind.distance then
best.behind = {distance = closestBehind, station = station}
end
end
end
return bestStation
return best.behind.station or best.any.station
end
local function getLoadStationAtMarker(wayPoint, farmId)
return getClosestStation(g_currentMission.storageSystem:getLoadingStations(), "loadTriggers", LOAD_TRIGGER_NODE_FIELDS, wayPoint, farmId)
local function getLoadStationAtMarker(adEnv, wayPoint, farmId)
return getClosestStation(adEnv, g_currentMission.storageSystem:getLoadingStations(), "loadTriggers", LOAD_TRIGGER_NODE_FIELDS, wayPoint, farmId)
end
local function getUnloadStationAtMarker(wayPoint, farmId)
return getClosestStation(g_currentMission.storageSystem:getUnloadingStations(), "unloadTriggers", UNLOAD_TRIGGER_NODE_FIELDS, wayPoint, farmId)
local function getUnloadStationAtMarker(adEnv, wayPoint, farmId)
return getClosestStation(adEnv, g_currentMission.storageSystem:getUnloadingStations(), "unloadTriggers", UNLOAD_TRIGGER_NODE_FIELDS, wayPoint, farmId)
end
-- Siloens EGET indhold. Udvidelses-siloer (isExtension) deler lager med naboer
@@ -143,7 +172,7 @@ local function collectMarkerStations(adEnv, candidateMarkers, farmId, excludedPl
local markerStations = {}
for _, marker in pairs(candidateMarkers) do
local wayPoint = adEnv.ADGraphManager:getWayPointById(marker.id)
local station = wayPoint ~= nil and getLoadStationAtMarker(wayPoint, farmId) or nil
local station = wayPoint ~= nil and getLoadStationAtMarker(adEnv, wayPoint, farmId) or nil
local isExcluded = station ~= nil and excludedPlaceable ~= nil and station.owningPlaceable == excludedPlaceable
if station ~= nil and not isExcluded then
table.insert(markerStations, {marker = marker, station = station})
@@ -235,7 +264,7 @@ function ADSmartPickup.findSupplyPickup(adEnv, driver, ingredients)
return nil
end
local targetWayPoint = adEnv.ADGraphManager:getWayPointById(secondMarker.id)
local target = targetWayPoint ~= nil and getUnloadStationAtMarker(targetWayPoint, farmId) or nil
local target = targetWayPoint ~= nil and getUnloadStationAtMarker(adEnv, targetWayPoint, farmId) or nil
if target == nil then
return nil
end
+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.2.0.0</version>
<version>1.3.0.0</version>
<title>
<en>AD Smart Pickup</en>
</title>
+4
View File
@@ -30,6 +30,10 @@ Slå fra ved at vælge en anden enkelt vare.
- Siloens eget lager rangeres før nabo-lån (udvidelses-siloer deler lager inden for `storageRadius`).
- Intet fund, intet behov eller fejl i et spil-API → AutoDrives originale rotation. Valg logges som `ADSmartPickup:` i log.txt.
- Kræver i AutoDrive: "Brug mapper" + "Rotér mål: pålæsning" på køretøjet.
- **Markør ↔ silo (v1.3):** markøren er dér hvor trækkerens næse stopper; vognen holder et vogntog
bagved. Markørens silo er derfor nærmeste trigger **bag næsen** set i ankomstretningen (forrige
waypoint), højst 2 m foran. I tætte rækker (15 m mellem siloerne) er nabosiloens trigger ellers
nærmere end markørens egen. Ingen trigger bag næsen/ukendt retning → nærmeste trigger som før.
- **Står og læsser (v1.2):** med rotation + mapper afslutter AutoDrive normalt pålæsningen i det øjeblik
markøren nås (læsning skal være startet på vej ind, ellers kører den tom videre). Når moden har valgt
siloen, ser AutoDrive under `LoadAtDestinationTask.update` rotationen som slået fra for netop det
+24 -2
View File
@@ -61,8 +61,13 @@ g_currentMission = {
-- ---- AutoDrive-mocks ----
local markers, wayPoints = {}, {}
local function addMarker(index, name, group, x, z)
wayPoints[index] = {x = x, z = z}
-- fromX/fromZ: forrige waypoint på ruten ind til markøren (giver ankomstretningen)
local function addMarker(index, name, group, x, z, fromX, fromZ)
wayPoints[index] = {x = x, z = z, incoming = {}}
if fromX ~= nil then
wayPoints[1000 + index] = {x = fromX, z = fromZ, incoming = {}}
wayPoints[index].incoming = {1000 + index}
end
table.insert(markers, {id = index, markerIndex = index, name = name, group = group})
end
@@ -306,6 +311,23 @@ manager:getNextPickup(loader, false)
FS25_AutoDrive.LoadAtDestinationTask.update(task, 16)
check("L5 AutoDrives eget valg -> rotation uberørt", task.seenRotate, RT_ONLYPICKUP)
-- G1: tæt silo-række, kørsel mod -x. Næsen stopper ved markøren, vognen holder et
-- vogntog BAGVED -> markørens silo er den bag næsen, ikke den (nærmere) foran.
resetWorld()
addMarker(1, "1 Silo", "Siloer", 1243, 0, 1260, 0)
addMarker(2, "2 Silo", "Siloer", 1228, 0, 1243, 0)
table.insert(stations, makeStation(101, 1255, 1, {[HAY] = 9000}, false, {[HAY] = 9000})) -- bag markør 1
table.insert(stations, makeStation(102, 1239, 1, {[SUGARBEET] = 5000}, false, {[SUGARBEET] = 5000})) -- foran markør 1, bag markør 2
table.insert(stations, makeStation(103, 1224, 1, {}, false, {})) -- foran markør 2
check("G1 roer ligger i siloen bag markør 2", manager:getNextPickup(makeDriver(markers[1], {SUGARBEET}), false), 2)
check("G1 hø ligger i siloen bag markør 1", manager:getNextPickup(makeDriver(markers[1], {HAY}), false), 1)
-- G2: ingen trigger bag næsen (eller ukendt retning) -> nærmeste trigger som før
resetWorld()
addMarker(1, "Ensom silo", "Siloer", 100, 0, 120, 0)
table.insert(stations, makeStation(101, 95, 1, {[HAY] = 9000}))
check("G2 kun trigger foran -> nærmeste bruges", manager:getNextPickup(makeDriver(markers[1], {HAY}), false), 1)
-- L7: AD stopper -> grebet ryddes, næste opgave venter ikke på en gammel silo
resetWorld()
addMarker(1, "Silo 1", "Andet", 0, 0); table.insert(stations, makeStation(101, 0, 15, {[HAY] = 5000}))