-- 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?). Kun når en trigger med varen er inden for -- NEAR_M (holder ved Wait-punkter logges ikke). Ingen indgreb — kun log. ADLoadDiag = {} ADLoadDiag.LOG_PREFIX = "ADSmartPickup: pålæsning: " ADLoadDiag.REPORT_MS = 30000 ADLoadDiag.NEAR_M = 20 -- m: trigger med varen herinden for = køretøjet står ved stationen (ellers Wait/mark: ingen log) -- ---- 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 -- distances = afstande fra vognene til nærmeste AD-trigger med varen -> står ved stationen? function ADLoadDiag.atStation(distances) for _, d in ipairs(distances or {}) do if d <= ADLoadDiag.NEAR_M then return true end end return false 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, ", ")), nearestOk ~= nil and nearestOk.d or nil 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, distances = {}, {} for _, trailer in ipairs(task.trailers or {}) do if trailer.getFillUnits ~= nil and #trailer:getFillUnits() > 0 then local ok, line, distance = pcall(describeTrailer, adEnv, trailer, fillType) if ok and line ~= nil then table.insert(lines, line) end if ok and distance ~= nil then table.insert(distances, distance) end end end -- holder ved Wait/mark (ingen trigger med varen tæt på): det er ikke en fejlet pålæsning if not ADLoadDiag.atStation(distances) then return 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