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 -- 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". -- vogntog bagved. Siloer tættere end dette regnes som "markørens silo".
ADSmartPickup.MAX_MARKER_TO_TRIGGER_DISTANCE = 40 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). -- Under dette niveau regnes siloen som tom (undgår ture efter støv-rester).
ADSmartPickup.MIN_USEFUL_LITERS = 1 ADSmartPickup.MIN_USEFUL_LITERS = 1
ADSmartPickup.LOG_PREFIX = "ADSmartPickup: " ADSmartPickup.LOG_PREFIX = "ADSmartPickup: "
@@ -68,41 +71,67 @@ local function getWantedFillTypes(driver)
return wanted return wanted
end end
local function getDistanceToTriggers(triggers, nodeFields, x, z) -- Ankomstretning ved markøren (enhedsvektor) ud fra forrige waypoint, ellers nil.
local closest = math.huge 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 _, trigger in pairs(triggers or {}) do
for _, field in ipairs(nodeFields) do for _, field in ipairs(nodeFields) do
local node = trigger[field] local node = trigger[field]
if node ~= nil and entityExists(node) then if node ~= nil and entityExists(node) then
local tx, _, tz = getWorldTranslation(node) 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 end
end end
return closest return closest, closestBehind
end end
local function getClosestStation(candidateStations, triggersField, nodeFields, wayPoint, farmId) -- Markørens station: nærmeste trigger bag næsen; findes ingen (eller er
local bestStation = nil -- retningen ukendt), nærmeste trigger overhovedet.
local bestDistance = ADSmartPickup.MAX_MARKER_TO_TRIGGER_DISTANCE 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 for _, station in pairs(candidateStations) do
if g_currentMission.accessHandler:canFarmAccess(farmId, station) then if g_currentMission.accessHandler:canFarmAccess(farmId, station) then
local distance = getDistanceToTriggers(station[triggersField], nodeFields, wayPoint.x, wayPoint.z) local closest, closestBehind = getDistancesToTriggers(station[triggersField], nodeFields, wayPoint, direction)
if distance < bestDistance then if closest < best.any.distance then
bestDistance = distance best.any = {distance = closest, station = station}
bestStation = station end
if closestBehind < best.behind.distance then
best.behind = {distance = closestBehind, station = station}
end end
end end
end end
return bestStation return best.behind.station or best.any.station
end end
local function getLoadStationAtMarker(wayPoint, farmId) local function getLoadStationAtMarker(adEnv, wayPoint, farmId)
return getClosestStation(g_currentMission.storageSystem:getLoadingStations(), "loadTriggers", LOAD_TRIGGER_NODE_FIELDS, wayPoint, farmId) return getClosestStation(adEnv, g_currentMission.storageSystem:getLoadingStations(), "loadTriggers", LOAD_TRIGGER_NODE_FIELDS, wayPoint, farmId)
end end
local function getUnloadStationAtMarker(wayPoint, farmId) local function getUnloadStationAtMarker(adEnv, wayPoint, farmId)
return getClosestStation(g_currentMission.storageSystem:getUnloadingStations(), "unloadTriggers", UNLOAD_TRIGGER_NODE_FIELDS, wayPoint, farmId) return getClosestStation(adEnv, g_currentMission.storageSystem:getUnloadingStations(), "unloadTriggers", UNLOAD_TRIGGER_NODE_FIELDS, wayPoint, farmId)
end end
-- Siloens EGET indhold. Udvidelses-siloer (isExtension) deler lager med naboer -- Siloens EGET indhold. Udvidelses-siloer (isExtension) deler lager med naboer
@@ -143,7 +172,7 @@ local function collectMarkerStations(adEnv, candidateMarkers, farmId, excludedPl
local markerStations = {} local markerStations = {}
for _, marker in pairs(candidateMarkers) do for _, marker in pairs(candidateMarkers) do
local wayPoint = adEnv.ADGraphManager:getWayPointById(marker.id) 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 local isExcluded = station ~= nil and excludedPlaceable ~= nil and station.owningPlaceable == excludedPlaceable
if station ~= nil and not isExcluded then if station ~= nil and not isExcluded then
table.insert(markerStations, {marker = marker, station = station}) table.insert(markerStations, {marker = marker, station = station})
@@ -235,7 +264,7 @@ function ADSmartPickup.findSupplyPickup(adEnv, driver, ingredients)
return nil return nil
end end
local targetWayPoint = adEnv.ADGraphManager:getWayPointById(secondMarker.id) 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 if target == nil then
return nil return nil
end end
+1 -1
View File
@@ -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.2.0.0</version> <version>1.3.0.0</version>
<title> <title>
<en>AD Smart Pickup</en> <en>AD Smart Pickup</en>
</title> </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`). - 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. - 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. - 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 - **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 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 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 ---- -- ---- AutoDrive-mocks ----
local markers, wayPoints = {}, {} local markers, wayPoints = {}, {}
local function addMarker(index, name, group, x, z) -- fromX/fromZ: forrige waypoint på ruten ind til markøren (giver ankomstretningen)
wayPoints[index] = {x = x, z = z} 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}) table.insert(markers, {id = index, markerIndex = index, name = name, group = group})
end end
@@ -306,6 +311,23 @@ manager:getNextPickup(loader, false)
FS25_AutoDrive.LoadAtDestinationTask.update(task, 16) FS25_AutoDrive.LoadAtDestinationTask.update(task, 16)
check("L5 AutoDrives eget valg -> rotation uberørt", task.seenRotate, RT_ONLYPICKUP) 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 -- L7: AD stopper -> grebet ryddes, næste opgave venter ikke på en gammel silo
resetWorld() resetWorld()
addMarker(1, "Silo 1", "Andet", 0, 0); table.insert(stations, makeStation(101, 0, 15, {[HAY] = 5000})) addMarker(1, "Silo 1", "Andet", 0, 0); table.insert(stations, makeStation(101, 0, 15, {[HAY] = 5000}))