From a626fcdd951436f606321824b88992e273149a2c Mon Sep 17 00:00:00 2001 From: masterdraco Date: Sun, 27 Sep 2026 13:31:22 +0200 Subject: [PATCH] =?UTF-8?q?fix(bygninger):=20pallespawnere=20viger=20for?= =?UTF-8?q?=20afl=C3=A6sningen=20n=C3=A5r=20begge=20vil=20have=20samme=20m?= =?UTF-8?q?ark=C3=B8r=20og=20afl=C3=A6sningen=20st=C3=A5r=20t=C3=A6ttere?= =?UTF-8?q?=20=E2=80=94=20f=C3=A5restaldens=20foderindkast=20fik=20'Sheep?= =?UTF-8?q?=20Milk'=20som=20m=C3=A5l;=20g=C3=A6lder=20alle=20bygningstyper?= =?UTF-8?q?,=20rigtige=20l=C3=A6ssetriggere=20beholder=20forrang=20(v1.36.?= =?UTF-8?q?5.0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FS25_ADSmartPickup/adBuildings.lua | 51 ++++++++++++++++++++++++++++-- FS25_ADSmartPickup/modDesc.xml | 2 +- tests/test_adBuildings.lua | 14 ++++++++ 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/FS25_ADSmartPickup/adBuildings.lua b/FS25_ADSmartPickup/adBuildings.lua index 97cec0f..e91e18d 100644 --- a/FS25_ADSmartPickup/adBuildings.lua +++ b/FS25_ADSmartPickup/adBuildings.lua @@ -119,7 +119,10 @@ local function collectNodes(placeable, loadStations, unloadStations) for _, place in ipairs(spawner.spawnPlaces or {}) do if place.startNode ~= nil then table.insert(nodes, place.startNode) end end - if #nodes > 0 then table.insert(loadGroups, nodes) end + if #nodes > 0 then + nodes.isSpawner = true + table.insert(loadGroups, nodes) + end end -- stald uden aflæsningsnoder i stationen (hønsehus: kun foder-triggeren) -> søg i staldens foderdata if #unloadNodes == 0 and placeable.getHusbandryFillLevel ~= nil then @@ -140,7 +143,10 @@ local function collectNodes(placeable, loadStations, unloadStations) for _, place in ipairs(palletSpawner.spawnPlaces or {}) do if place.startNode ~= nil then table.insert(nodes, place.startNode) end end - if #nodes > 0 then table.insert(loadGroups, nodes) end + if #nodes > 0 then + nodes.isSpawner = true + table.insert(loadGroups, nodes) + end end end if placeable.spec_objectStorage ~= nil and placeable.rootNode ~= nil then @@ -219,6 +225,44 @@ end -- Aflæsningsmarkør: nærmeste ikke-Wait-markør ≤ MAX_MARKER_DISTANCE til aflæsningsnoderne — men ikke -- bygningens egne LÆSSEmarkører, når der findes en anden (Sugarbeet Crusher: pickup står tættere på -- aflæsningstriggeren end drop). Kun én fælles markør (AIO Load / Unload) bruges til begge. +-- Alle ikke-Wait-markører ≤ MAX_MARKER_DISTANCE til nodes, nærmeste først: {{id, name, distance}}. +local function markerCandidates(adEnv, nodes) + local positions, found = {}, {} + for _, node in ipairs(nodes) do + local x, z = getNodePosition(node) + if x ~= nil then table.insert(positions, {x = x, z = z}) end + end + for _, marker in pairs(adEnv.ADGraphManager:getMapMarkers()) do + local wayPoint = not ADSupplyPlanner.isWaitMarker(marker) and adEnv.ADGraphManager:getWayPointById(marker.id) or nil + if wayPoint ~= nil then + local nearest = nil + for _, position in ipairs(positions) do + local distance = math.sqrt((wayPoint.x - position.x) ^ 2 + (wayPoint.z - position.z) ^ 2) + if nearest == nil or distance < nearest then nearest = distance end + end + if nearest ~= nil and nearest < ADBuildings.MAX_MARKER_DISTANCE then + table.insert(found, {id = marker.id, name = tostring(marker.name), distance = nearest}) + end + end + end + table.sort(found, function(a, b) return a.distance < b.distance end) + return found +end + +-- Læssemarkør for én læssegruppe. En pallespawner (upræcist startpunkt) viger for aflæsningen, når begge vil +-- have samme markør og aflæsningen står tættere — så tager den sin næstnærmeste. Rigtige læssetriggere beholder +-- markøren (Sugarbeet Crusher: pickup står tættere på aflæsningstriggeren end drop). Gælder alle bygningstyper. +-- (in-game 27/9 fårestald: spawner 9 m fra "Sheep Food", foderindkast 5 m -> Goat Food fik "Sheep Milk") +function ADBuildings.pickLoadMarker(candidates, unloadBest, yieldsToUnload) + for _, candidate in ipairs(candidates or {}) do + local isUnloads = yieldsToUnload and unloadBest ~= nil and candidate.id == unloadBest.id and unloadBest.distance < candidate.distance + if not isUnloads then + return {id = candidate.id, name = candidate.name, distance = math.floor(candidate.distance + 0.5)} + end + end + return nil +end + -- Diagnose (én gang pr. stald pr. session): hvilke markører ligger nærmest læsse- og aflæsningspunkterne. -- (in-game 27/9: Goat Food fik "Sheep Milk"-markørerne som mål og Goat Milk Pickup "Sheep Food" som kilde) local diagnosed = {} @@ -371,8 +415,9 @@ local function build(adEnv, farmId) local marker = siloLoadMarker(adEnv, farmId, placeable, loadStations) if marker ~= nil then table.insert(loadMarkers, marker) end else + local unloadBest = markerCandidates(adEnv, unloadNodes)[1] for _, nodes in ipairs(loadGroups) do - local marker = nearestMarker(adEnv, nodes) + local marker = ADBuildings.pickLoadMarker(markerCandidates(adEnv, nodes), unloadBest, nodes.isSpawner == true) if marker ~= nil and not seen[marker.id] then seen[marker.id] = true table.insert(loadMarkers, marker) diff --git a/FS25_ADSmartPickup/modDesc.xml b/FS25_ADSmartPickup/modDesc.xml index 3561806..c39fb04 100644 --- a/FS25_ADSmartPickup/modDesc.xml +++ b/FS25_ADSmartPickup/modDesc.xml @@ -1,7 +1,7 @@ masterdraco - 1.36.4.0 + 1.36.5.0 <en>AD Smart Pickup</en> diff --git a/tests/test_adBuildings.lua b/tests/test_adBuildings.lua index 3c104df..4ca6fac 100644 --- a/tests/test_adBuildings.lua +++ b/tests/test_adBuildings.lua @@ -234,5 +234,19 @@ do check("B-SHED aflæsning = nærmeste (Unload)", byShed.shedX.unloadMarker and byShed.shedX.unloadMarker.id, 71) end + +-- pickLoadMarker: en pallespawner viger for aflæsningen, når begge vil have samme markør og aflæsningen står +-- tættere (in-game 27/9 fårestald: spawner 9 m fra "Sheep Food", foderindkast 5 m -> Goat Food fik "Sheep Milk") +do + local food, milk = {id = 1, name = "Sheep Food 1", distance = 9}, {id = 2, name = "Sheep Milk 1", distance = 13} + local unloadBest = {id = 1, name = "Sheep Food 1", distance = 5} + check("PL spawner viger for tættere aflæsning", ADBuildings.pickLoadMarker({food, milk}, unloadBest, true).name, "Sheep Milk 1") + check("PL rigtig læssetrigger beholder markøren (Sugarbeet Crusher)", ADBuildings.pickLoadMarker({food, milk}, unloadBest, false).name, "Sheep Food 1") + check("PL spawner tættest selv -> beholder", ADBuildings.pickLoadMarker({food, milk}, {id = 1, name = "Sheep Food 1", distance = 12}, true).name, "Sheep Food 1") + check("PL ingen konflikt", ADBuildings.pickLoadMarker({milk}, unloadBest, true).name, "Sheep Milk 1") + check("PL eneste kandidat er aflæsningens -> ingen læssemarkør", ADBuildings.pickLoadMarker({food}, unloadBest, true), nil) + check("PL ingen kandidater", ADBuildings.pickLoadMarker({}, unloadBest, true), nil) +end + print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL")) os.exit(failures == 0 and 0 or 1)