From ff71fb4f43b817a0a646c60a50afd46f1dcae3f2 Mon Sep 17 00:00:00 2001 From: masterdraco Date: Thu, 24 Sep 2026 19:47:54 +0200 Subject: [PATCH] =?UTF-8?q?fix(stald):=20foder-trigger=20s=C3=B8ges=20i=20?= =?UTF-8?q?spec=5FhusbandryFood=20(feedingTrough=20findes=20ikke=20i=20FS2?= =?UTF-8?q?5)=20n=C3=A5r=20stationen=20er=20uden=20noder=20=E2=80=94=20h?= =?UTF-8?q?=C3=B8nsehus;=20diagnose-log=20af=20feltnavne=20(v1.19.4.0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FS25_ADSmartPickup/adBuildings.lua | 30 +++++++++++++++++++++----- FS25_ADSmartPickup/adSmartPickup.lua | 21 ++++++++++-------- FS25_ADSmartPickup/adSupplyPlanner.lua | 27 +++++++++++++++++++++++ FS25_ADSmartPickup/modDesc.xml | 2 +- docs/BRUGERMANUAL.md | 2 +- docs/USER_MANUAL.md | 2 +- tests/test_adBuildings.lua | 11 +++++++++- tests/test_adSmartPickup.lua | 2 +- 8 files changed, 78 insertions(+), 19 deletions(-) diff --git a/FS25_ADSmartPickup/adBuildings.lua b/FS25_ADSmartPickup/adBuildings.lua index 3484f94..6cb903d 100644 --- a/FS25_ADSmartPickup/adBuildings.lua +++ b/FS25_ADSmartPickup/adBuildings.lua @@ -72,6 +72,22 @@ local function getKind(placeable) return nil end +local logHusbandryFoodOnce +ADBuildings.findTriggerNodes = function(root, maxDepth) return ADSupplyPlanner.findTriggerNodes(root, maxDepth) end + +-- Diagnose én gang pr. stald: hvilke felter foderdataene har, når ingen trigger-node blev fundet. +local loggedFood = setmetatable({}, {__mode = "k"}) +logHusbandryFoodOnce = function(placeable) + if loggedFood[placeable] then return end + loggedFood[placeable] = true + local keys = {} + for key, value in pairs(placeable.spec_husbandryFood or {}) do table.insert(keys, tostring(key) .. ":" .. type(value)) end + table.sort(keys) + if Logging ~= nil and Logging.info ~= nil then + Logging.info(ADBuildings.LOG_PREFIX .. "stald '%s' har ingen aflæsnings-trigger; spec_husbandryFood-felter: %s", getName(placeable, "?"), table.concat(keys, ", ")) + end +end + -- Trigger-noder pr. bygning: læsse (loadTriggers.triggerNode, pallespawner, objektlager) og -- aflæsning (unloadTriggers exactFillRootNode/triggerNode/aiNode). -- loadGroups: én gruppe noder pr. læssepunkt (mælketank, gyllebeholder ...), så hvert punkt får sin @@ -104,11 +120,15 @@ local function collectNodes(placeable, loadStations, unloadStations) end if #nodes > 0 then table.insert(loadGroups, nodes) end end - -- staldens foderkrybbe (hønsehus: kun krybben, ingen trigger i aflæsningsstationen) - local food = placeable.spec_husbandryFood - local trough = food ~= nil and food.feedingTrough or nil - local troughNode = trough ~= nil and (trough.exactFillRootNode or trough.triggerNode) or nil - if troughNode ~= nil then table.insert(unloadNodes, troughNode) 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 + for _, node in ipairs(ADSupplyPlanner.findTriggerNodes(placeable.spec_husbandryFood)) do + table.insert(unloadNodes, node) + end + if #unloadNodes == 0 then + logHusbandryFoodOnce(placeable) + end + end -- stald med egne pallespawnere (hønsehus: æg, fårestald: uld) — én læssegruppe pr. spawner local husbandryPallets = placeable.spec_husbandryPallets local seenSpawners = {} diff --git a/FS25_ADSmartPickup/adSmartPickup.lua b/FS25_ADSmartPickup/adSmartPickup.lua index 3e44926..18519f9 100644 --- a/FS25_ADSmartPickup/adSmartPickup.lua +++ b/FS25_ADSmartPickup/adSmartPickup.lua @@ -167,9 +167,10 @@ local function getLoadStationAtMarker(adEnv, wayPoint, farmId) return getClosestStation(adEnv, g_currentMission.storageSystem:getLoadingStations(), "loadTriggers", LOAD_TRIGGER_NODE_FIELDS, wayPoint, farmId) end --- Staldes foderkrybbe (spec_husbandryFood.feedingTrough, samme tippe-trigger som AutoDrive bruger) står --- ikke altid i aflæsningsstationens unloadTriggers — hønsehuset har KUN krybben. Opslaget får derfor en --- proxy pr. krybbe der peger på staldens station (eller en minimal station). Caches i UNLOAD_CACHE_MS. +-- En stalds foder-trigger står ikke altid i aflæsningsstationens unloadTriggers (hønsehuset har kun +-- foder-triggeren under spec_husbandryFood; feltstien varierer). Står stationen uden trigger-noder, søges +-- foderdataene, og opslaget får en proxy med de fundne noder, der peger på staldens station (eller en +-- minimal station). Caches i UNLOAD_CACHE_MS. ADSmartPickup.UNLOAD_CACHE_MS = 1000 local unloadCache = {list = nil, time = -math.huge} @@ -191,16 +192,18 @@ local function getUnloadCandidates() end local placeables = g_currentMission.placeableSystem ~= nil and g_currentMission.placeableSystem.placeables or {} for _, placeable in pairs(placeables) do - local food = placeable.spec_husbandryFood - local trough = food ~= nil and food.feedingTrough or nil - local node = trough ~= nil and (trough.exactFillRootNode or trough.triggerNode) or nil - if node ~= nil then - local station = byPlaceable[placeable] or { + local ownStation = byPlaceable[placeable] + local ownHasNodes = ownStation ~= nil and ownStation.unloadTriggers ~= nil and #ADSupplyPlanner.findTriggerNodes(ownStation.unloadTriggers, 1) > 0 + local foodNodes = (placeable.getHusbandryFillLevel ~= nil and not ownHasNodes) and ADSupplyPlanner.findTriggerNodes(placeable.spec_husbandryFood) or {} + if #foodNodes > 0 then + local triggers = {} + for _, foodNode in ipairs(foodNodes) do table.insert(triggers, {exactFillRootNode = foodNode}) end + local station = ownStation or { owningPlaceable = placeable, -- spillets adgangstjek kalder getOwnerFarmId på stationen getOwnerFarmId = function() return placeable.getOwnerFarmId ~= nil and placeable:getOwnerFarmId() or placeable.ownerFarmId end, } - table.insert(list, setmetatable({unloadTriggers = {{exactFillRootNode = node}}}, {__index = station})) + table.insert(list, setmetatable({unloadTriggers = triggers}, {__index = station})) end end unloadCache.list, unloadCache.time = list, now or -math.huge diff --git a/FS25_ADSmartPickup/adSupplyPlanner.lua b/FS25_ADSmartPickup/adSupplyPlanner.lua index d303486..5bbedfb 100644 --- a/FS25_ADSmartPickup/adSupplyPlanner.lua +++ b/FS25_ADSmartPickup/adSupplyPlanner.lua @@ -296,3 +296,30 @@ function ADSupplyPlanner.resolveIngredients(state, selected) end return nil end + + +-- Trigger-noder (exactFillRootNode/triggerNode) i indlejrede tabeller, fx en stalds foderdata hvor feltstien +-- varierer mellem FS-versioner og mods (hønsehuset har kun foder-triggeren, ikke i aflæsningsstationen). +-- Højst maxDepth niveauer (standard 3); løkker og placeable-referencer følges ikke. +local SKIP_KEYS = {owningPlaceable = true, placeable = true, owner = true, parent = true, vehicle = true, target = true, mission = true} + +function ADSupplyPlanner.findTriggerNodes(root, maxDepth) + local nodes, seen = {}, {} + local function visit(value, depth) + if type(value) ~= "table" or seen[value] or depth > (maxDepth or 3) then + return + end + seen[value] = true + for _, field in ipairs({"exactFillRootNode", "triggerNode"}) do + local node = rawget(value, field) + if node ~= nil and type(node) ~= "boolean" then table.insert(nodes, node) end + end + for key, child in pairs(value) do + if type(child) == "table" and not SKIP_KEYS[key] then + visit(child, depth + 1) + end + end + end + visit(root, 0) + return nodes +end diff --git a/FS25_ADSmartPickup/modDesc.xml b/FS25_ADSmartPickup/modDesc.xml index 4300286..dd77440 100644 --- a/FS25_ADSmartPickup/modDesc.xml +++ b/FS25_ADSmartPickup/modDesc.xml @@ -1,7 +1,7 @@ masterdraco - 1.19.3.0 + 1.19.4.0 <en>AD Smart Pickup</en> diff --git a/docs/BRUGERMANUAL.md b/docs/BRUGERMANUAL.md index d438ed0..b00d208 100644 --- a/docs/BRUGERMANUAL.md +++ b/docs/BRUGERMANUAL.md @@ -1,6 +1,6 @@ # AD Smart Pickup — brugermanual -Version 1.19.3 · Farming Simulator 25 · tillæg til AutoDrive +Version 1.19.4 · Farming Simulator 25 · tillæg til AutoDrive *English version: [USER_MANUAL.md](USER_MANUAL.md)* diff --git a/docs/USER_MANUAL.md b/docs/USER_MANUAL.md index c0eea3c..b76b6e0 100644 --- a/docs/USER_MANUAL.md +++ b/docs/USER_MANUAL.md @@ -1,6 +1,6 @@ # AD Smart Pickup — user manual -Version 1.19.3 · Farming Simulator 25 · add-on for AutoDrive +Version 1.19.4 · Farming Simulator 25 · add-on for AutoDrive *Dansk version: [BRUGERMANUAL.md](BRUGERMANUAL.md)* diff --git a/tests/test_adBuildings.lua b/tests/test_adBuildings.lua index 396b12f..314edcb 100644 --- a/tests/test_adBuildings.lua +++ b/tests/test_adBuildings.lua @@ -189,7 +189,7 @@ end -- B-COOP: hønsehus — foder aflæsses i den ene ende, æg-paller spawnes i den anden (ingen læssestation) do local coop = placeable("coop1", "Chicken Coop", 10000, 0, {getHusbandryFillLevel = function() return 0 end, - spec_husbandryFood = {feedingTrough = {exactFillRootNode = {x = 9970, z = 0}}}, + spec_husbandryFood = {triggers = {{someTrigger = {exactFillRootNode = {x = 9970, z = 0}}}}}, -- ukendt feltsti: søges spec_husbandryPallets = {fillTypeIndexToPalletSpawner = {[99] = {spawnPlaces = {{startNode = {x = 10030, z = 0}}}}}}}) table.insert(unloadStations, {owningPlaceable = coop, unloadTriggers = {}}) -- som chickenBarnBig: tom station addMarker(61, "Chicken Food", "Chicken", 9965, 0) @@ -214,5 +214,14 @@ do g_fillTypeManager = fmBefore end +-- B-SCAN: søgning efter trigger-noder i indlejrede tabeller (dybde ≤ 3, ingen løkker) +do + local loop = {} + loop.self = loop + local nodes = ADBuildings.findTriggerNodes({a = {b = {exactFillRootNode = "n1"}}, c = {triggerNode = "n2"}, d = loop, e = {f = {g = {h = {exactFillRootNode = "for-dybt"}}}}}) + table.sort(nodes) + check("B-SCAN finder n1 og n2, ikke for dybt", table.concat(nodes, ","), "n1,n2") +end + print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL")) os.exit(failures == 0 and 0 or 1) diff --git a/tests/test_adSmartPickup.lua b/tests/test_adSmartPickup.lua index 5677889..1702bdb 100644 --- a/tests/test_adSmartPickup.lua +++ b/tests/test_adSmartPickup.lua @@ -1263,7 +1263,7 @@ ADOutbound = nil -- unloadTriggers; stationsopslaget ved markøren skal alligevel finde hønsehuset do local coop = {getHusbandryFillLevel = function() return 0 end, getName = function() return "Chicken Coop" end, - spec_husbandryFood = {feedingTrough = {exactFillRootNode = 9901}}} + spec_husbandryFood = {unloadTrigger = {exactFillRootNode = 9901}}} nodePositions[9901] = {x = 20000, z = 3} local coopStation = {owningPlaceable = coop, unloadTriggers = {}} table.insert(unloadStations, coopStation)