From a6662d6da13510d36364a1ad242b7f18b2c4300c Mon Sep 17 00:00:00 2001 From: masterdraco Date: Wed, 30 Sep 2026 22:54:28 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20diagnose=20n=C3=A5r=20AD=20st=C3=A5r=20?= =?UTF-8?q?ved=20LOAD-m=C3=A5l=20uden=20at=20fylde?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + FS25_ADSmartPickup/adLoadDiag.lua | 119 +++++++++++++++++++++++++++ FS25_ADSmartPickup/adSmartPickup.lua | 3 + FS25_ADSmartPickup/modDesc.xml | 3 +- 4 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 FS25_ADSmartPickup/adLoadDiag.lua diff --git a/CHANGELOG.md b/CHANGELOG.md index 34e86e8..4a3f64e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ står i [docs/BRUGERMANUAL.md](docs/BRUGERMANUAL.md) (dansk) og [docs/USER_MANUA ## 1.62 — Kæder slås selv til +- **1.62.5** Diagnose: står AutoDrive 30 s ved et LOAD-mål uden at fylde, skriver loggen én linje med markør, vare og for hver vogn den nærmeste AD-læssetrigger (afstand, har varen, står vognen i triggerens boks). Ingen indgreb. - **1.62.4** Rettet: påfyldning af et langt sæt fik AutoDrive til at oprette ekstra markører med stationens navn (fx "Buying Station Multifruit"). Det gør AutoDrives `getMarkerAtStation`, når ingen markør passer til togets længde. Moden kalder den ikke længere; markøren findes ved stationens læssetriggere eller ved bygningen. - **1.62.3** Rettet: påfyldning ved købestation valgte en anden stations markør for lange sæt. AutoDrive vil have markøren togets længde + 3–13 m forbi triggeren, så Puma + Kinze 4900 ventede på frø ved "Market Price Liquid Fill Station" i stedet for "Buying Station Multifruit". Nu vælges den nærmeste markør ved stationens egne læssetriggere; P-, Connect- og Wait-markører springes over. Loggen skriver, hvor et tomt redskab fyldes. - **1.62.2** Kæderne læser fabrikkernes udgange (Sælg / Fordel / Behold). **Fordel:** spillet leverer selv til gårdens fabrikker, så kæden opretter intet flow, og fanen Kæder viser *fordeles af spillet*. **Behold** (spawn eller lager): et flow henter varen ved fabrikken som hidtil. **Sælg på en mellemvare** betyder, at næste led i kæden intet får, så kæden sætter den til Behold og henter den. diff --git a/FS25_ADSmartPickup/adLoadDiag.lua b/FS25_ADSmartPickup/adLoadDiag.lua new file mode 100644 index 0000000..6cf5fc1 --- /dev/null +++ b/FS25_ADSmartPickup/adLoadDiag.lua @@ -0,0 +1,119 @@ +-- AD Load Diag +-- Diagnose når AutoDrive står ved et LOAD-mål uden at fylde (in-game 30/9: Fendt + MEGA-sprøjte ved "Market Price +-- Liquid Fill Station"). AutoDrive fylder kun, når en fyldenhed står i triggerens boks (trigger.fillableObjects) og +-- triggeren har varen. Efter REPORT_MS ved målet uden fremgang skrives én linje: markør, vare, og for hver vogn den +-- nærmeste AD-læssetrigger (afstand, har varen?, står vognen i boksen?). Ingen indgreb — kun log. + +ADLoadDiag = {} +ADLoadDiag.LOG_PREFIX = "ADSmartPickup: pålæsning: " +ADLoadDiag.REPORT_MS = 30000 + +-- ---- ren logik ---- + +-- state (pr. opgave), dt, reached (ved målet), level (liter på vognene) -> true når der skal rapporteres (én gang pr. +-- ankomst). Fremgang eller kørsel nulstiller. +function ADLoadDiag.tick(state, dt, reached, level) + if not reached then + state.ms, state.reported, state.level = 0, false, nil + return false + end + if state.level == nil or level > state.level then + state.level, state.ms = level, 0 + return false + end + state.ms = (state.ms or 0) + (dt or 0) + if state.reported or state.ms < ADLoadDiag.REPORT_MS then return false end + state.reported = true + return true +end + +-- ---- spil ---- + +local function fillTypeName(fillType) + return g_fillTypeManager ~= nil and fillType ~= nil and g_fillTypeManager:getFillTypeNameByIndex(fillType) or tostring(fillType) +end + +local function inBox(trigger, trailer) + for key, entry in pairs(trigger.fillableObjects or {}) do + if key == trailer or (type(entry) == "table" and entry.object == trailer) then return true end + end + return false +end + +local function describeTrailer(adEnv, trailer, fillType) + local node = trailer.components ~= nil and trailer.components[1] ~= nil and trailer.components[1].node or trailer.rootNode + if node == nil then return nil end + local tx, _, tz = getWorldTranslation(node) + local nearest, nearestOk = nil, nil + for _, trigger in pairs(adEnv.ADTriggerManager.getLoadTriggers() or {}) do + local x, _, z = adEnv.ADTriggerManager.getTriggerPos(trigger) + if x ~= nil and (x ~= 0 or z ~= 0) then + local d = math.sqrt((x - tx) ^ 2 + (z - tz) ^ 2) + local ok = adEnv.ADTriggerManager.triggerSupportsFillType(trigger, fillType) + if nearest == nil or d < nearest.d then nearest = {d = d, ok = ok, trigger = trigger} end + if ok and (nearestOk == nil or d < nearestOk.d) then nearestOk = {d = d, trigger = trigger} end + end + end + local name = trailer.getName ~= nil and trailer:getName() or "?" + local parts = {} + if nearest ~= nil then + table.insert(parts, string.format("nærmeste AD-trigger %.1f m (%s varen, %s)", nearest.d, nearest.ok and "har" or "UDEN", + inBox(nearest.trigger, trailer) and "vognen i boksen" or "vognen IKKE i boksen")) + end + if nearestOk ~= nil and (nearest == nil or nearestOk.trigger ~= nearest.trigger) then + table.insert(parts, string.format("nærmeste med varen %.1f m (%s)", nearestOk.d, + inBox(nearestOk.trigger, trailer) and "i boksen" or "ikke i boksen")) + end + if nearestOk == nil then table.insert(parts, "INGEN AD-læssetrigger med varen") end + return string.format("'%s': %s", tostring(name), table.concat(parts, ", ")) +end + +local function report(adEnv, task) + local vehicle = task.vehicle + local fillType = vehicle.ad.stateModule.getFillType ~= nil and vehicle.ad.stateModule:getFillType() or nil + local marker = task.destinationID ~= nil and adEnv.ADGraphManager:getMapMarkerByWayPointId(task.destinationID) or nil + local lines = {} + for _, trailer in ipairs(task.trailers or {}) do + if trailer.getFillUnits ~= nil and #trailer:getFillUnits() > 0 then + local ok, line = pcall(describeTrailer, adEnv, trailer, fillType) + if ok and line ~= nil then table.insert(lines, line) end + end + end + local maxDistance = adEnv.AutoDrive.getMaxTriggerDistance ~= nil and adEnv.AutoDrive.getMaxTriggerDistance(vehicle) or nil + Logging.warning(ADLoadDiag.LOG_PREFIX .. "'%s' står ved '%s' uden at fylde %s i %d s (AD-triggerafstand %s m): %s", + tostring(ADRuns.vehicleLabel(vehicle)), tostring(marker ~= nil and marker.name or task.destinationID), fillTypeName(fillType), + math.floor(ADLoadDiag.REPORT_MS / 1000), tostring(maxDistance), #lines > 0 and table.concat(lines, "; ") or "ingen vogne med fyldenheder") +end + +local states = setmetatable({}, {__mode = "k"}) + +function ADLoadDiag.after(adEnv, task, dt) + local vehicle = task.vehicle + if vehicle == nil or vehicle.ad == nil or vehicle.ad.drivePathModule == nil then return end + local state = states[task] + if state == nil then + state = {} + states[task] = state + end + local reached = vehicle.ad.drivePathModule:isTargetReached() and not vehicle.ad.trailerModule:isActiveAtTrigger() + local level = adEnv.AutoDrive.getAllFillLevels(task.trailers) or 0 + if ADLoadDiag.tick(state, dt, reached, level) then report(adEnv, task) end +end + +local isInstalled = false + +function ADLoadDiag.install(adEnv) + local task = adEnv ~= nil and adEnv.LoadAtDestinationTask or nil + if isInstalled or task == nil or task.update == nil or adEnv.ADTriggerManager == nil then return end + isInstalled = true + local original = task.update + task.update = function(self, dt) + local result = original(self, dt) + local ok, err = pcall(ADLoadDiag.after, adEnv, self, dt) + if not ok and not self.spuDiagFailed then + self.spuDiagFailed = true + Logging.warning(ADLoadDiag.LOG_PREFIX .. "diagnose fejlede: %s", tostring(err)) + end + return result + end +end diff --git a/FS25_ADSmartPickup/adSmartPickup.lua b/FS25_ADSmartPickup/adSmartPickup.lua index 72868ed..0480a7b 100644 --- a/FS25_ADSmartPickup/adSmartPickup.lua +++ b/FS25_ADSmartPickup/adSmartPickup.lua @@ -1152,6 +1152,9 @@ local function installHook(adEnv) if ADHitchCreep ~= nil and ADHitchCreep.install ~= nil then ADHitchCreep.install(adEnv) end + if ADLoadDiag ~= nil and ADLoadDiag.install ~= nil then + ADLoadDiag.install(adEnv) + end Logging.info(ADSmartPickup.LOG_PREFIX .. "aktiv (mindst fyldte silo med varen; flere valgte varer = behovsstyret forsyning; Wait-punkter for rest-læs; udkørsel til silo/salg)") end diff --git a/FS25_ADSmartPickup/modDesc.xml b/FS25_ADSmartPickup/modDesc.xml index a83fc3e..d97bfe9 100644 --- a/FS25_ADSmartPickup/modDesc.xml +++ b/FS25_ADSmartPickup/modDesc.xml @@ -1,7 +1,7 @@ masterdraco - 1.62.4.0 + 1.62.5.0 <en>AD Smart Pickup</en> @@ -32,6 +32,7 @@ +