From 65dd202e1b61487ec1c74d92759f766b373b3410 Mon Sep 17 00:00:00 2001 From: masterdraco Date: Thu, 24 Sep 2026 03:14:28 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20k=C3=B8ret=C3=B8jer=20navngives=20efter?= =?UTF-8?q?=20deres=20flow=20(AD-f=C3=B8rernavn=20'Milk=20Collect=201'),?= =?UTF-8?q?=20bruges=20i=20log=20og=20menu;=20modelnavn=20tilbage=20ved=20?= =?UTF-8?q?udmeldelse=20(v1.17.0.0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FS25_ADSmartPickup/adLoadSwap.lua | 4 +- FS25_ADSmartPickup/adOutbound.lua | 32 +++++----- FS25_ADSmartPickup/adRuns.lua | 40 ++++++++++++ FS25_ADSmartPickup/adRunsController.lua | 68 +++++++++++++++++---- FS25_ADSmartPickup/adSmartPickup.lua | 13 ++-- FS25_ADSmartPickup/adUnloadWait.lua | 12 ++-- FS25_ADSmartPickup/gui/SmartPickupFrame.lua | 2 +- FS25_ADSmartPickup/modDesc.xml | 2 +- docs/BRUGERMANUAL.md | 9 ++- docs/USER_MANUAL.md | 9 ++- tests/test_adRuns.lua | 15 +++++ tests/test_adRunsController.lua | 17 ++++++ 12 files changed, 176 insertions(+), 47 deletions(-) diff --git a/FS25_ADSmartPickup/adLoadSwap.lua b/FS25_ADSmartPickup/adLoadSwap.lua index 4a58ab9..09c1142 100644 --- a/FS25_ADSmartPickup/adLoadSwap.lua +++ b/FS25_ADSmartPickup/adLoadSwap.lua @@ -121,7 +121,7 @@ function ADLoadSwap.tryFromWait(adEnv, task, wait, dt, redirect, release, isReac if marker == nil then if not warnedNoSilo[vehicle] then warnedNoSilo[vehicle] = true - Logging.warning(ADLoadSwap.LOG_PREFIX .. "'%s' venter med %.0f l %s (%s) — %s; den bliver ved Wait-punktet", tostring(vehicle:getName()), wait.rest, tostring(restName), missing ~= nil and ("målet mangler " .. tostring(missingName)) or "målet tager ikke varen", tostring(why)) + Logging.warning(ADLoadSwap.LOG_PREFIX .. "'%s' venter med %.0f l %s (%s) — %s; den bliver ved Wait-punktet", tostring(ADRuns.vehicleLabel(vehicle)), wait.rest, tostring(restName), missing ~= nil and ("målet mangler " .. tostring(missingName)) or "målet tager ikke varen", tostring(why)) end return false end @@ -129,7 +129,7 @@ function ADLoadSwap.tryFromWait(adEnv, task, wait, dt, redirect, release, isReac release(vehicle) redirect(task, marker.id) local why = missing ~= nil and ("målet mangler " .. tostring(missingName)) or "målet tager ikke varen" - Logging.info(ADLoadSwap.LOG_PREFIX .. "'%s' bytter læs: %.0f l %s tilbage i %s (markør %s), %s", tostring(vehicle:getName()), wait.rest, tostring(restName), tostring(marker.name), tostring(marker.markerIndex or marker.id), why) + Logging.info(ADLoadSwap.LOG_PREFIX .. "'%s' bytter læs: %.0f l %s tilbage i %s (markør %s), %s", tostring(ADRuns.vehicleLabel(vehicle)), wait.rest, tostring(restName), tostring(marker.name), tostring(marker.markerIndex or marker.id), why) return true end diff --git a/FS25_ADSmartPickup/adOutbound.lua b/FS25_ADSmartPickup/adOutbound.lua index 758127d..c402fa1 100644 --- a/FS25_ADSmartPickup/adOutbound.lua +++ b/FS25_ADSmartPickup/adOutbound.lua @@ -245,7 +245,7 @@ function ADOutbound.buildPlanInput(adEnv, run, vehicle) if warned[vehicle] == nil or warned[vehicle][key] ~= text then warned[vehicle] = warned[vehicle] or {} warned[vehicle][key] = text - Logging.info(ADOutbound.LOG_PREFIX .. "'%s': %s", tostring(vehicle:getName()), text) + Logging.info(ADOutbound.LOG_PREFIX .. "'%s': %s", tostring(ADRuns.vehicleLabel(vehicle)), text) end end -- gårdens eget behov (fabrikker/stalde) sælges ikke; kilderne selv tæller ikke som forbrugere @@ -254,7 +254,7 @@ function ADOutbound.buildPlanInput(adEnv, run, vehicle) product.reserve, product.reservedFor = demand.liters, demand.consumers end if quote == nil and unreachableName ~= nil then - warnOnce(adEnv, vehicle, "sell:" .. product.name, string.format("'%s' kan ikke nå salgssted '%s' for %s – tjek vejnettet", tostring(vehicle:getName()), unreachableName, product.name)) + warnOnce(adEnv, vehicle, "sell:" .. product.name, string.format("'%s' kan ikke nå salgssted '%s' for %s – tjek vejnettet", tostring(ADRuns.vehicleLabel(vehicle)), unreachableName, product.name)) else clearWarning(vehicle, "sell:" .. product.name) end @@ -352,7 +352,7 @@ local function applyTrip(adEnv, vehicle, run, trip, sourcesById) local sourceNames = {} for _, id in ipairs(trip.sourceIds) do table.insert(sourceNames, sourcesById[id] ~= nil and sourcesById[id].name or tostring(id)) end local why = trip.kind == "sell" and string.format("salg, %d %% af top", trip.percent or 0) or "lager" - Logging.info(ADOutbound.LOG_PREFIX .. "'%s' udkørsel: %s fra %s → %s (%s)", tostring(vehicle:getName()), table.concat(names, "+"), table.concat(sourceNames, ", "), tostring(trip.targetName), why) + Logging.info(ADOutbound.LOG_PREFIX .. "'%s' udkørsel: %s fra %s → %s (%s)", tostring(ADRuns.vehicleLabel(vehicle)), table.concat(names, "+"), table.concat(sourceNames, ", "), tostring(trip.targetName), why) end -- Lagermål i en tæt silorække: AutoDrive tipper ved den FØRSTE aflæsningstrigger inden for sin @@ -378,7 +378,7 @@ local function warnDenseSilosOnce(adEnv, vehicle, trip) local dx, dz = wayPoint ~= nil and (wayPoint.x - target.x) or math.huge, wayPoint ~= nil and (wayPoint.z - target.z) or math.huge if dx * dx + dz * dz <= distance * distance and ADSmartPickup.getUnloadStationAtWayPointId(adEnv, marker.id, farmId) ~= nil then warnedTriggerDistance[trip.targetWayPointId] = true - Logging.warning(ADOutbound.LOG_PREFIX .. "'%s': målet %s har en anden aflæsningsmarkør (%s) inden for AutoDrives 'Max trigger distance' (%d m) — AutoDrive kan tippe ved nabosiloen; sæt AD-indstillingen til 10 m", tostring(vehicle:getName()), tostring(trip.targetName), tostring(marker.name), distance) + Logging.warning(ADOutbound.LOG_PREFIX .. "'%s': målet %s har en anden aflæsningsmarkør (%s) inden for AutoDrives 'Max trigger distance' (%d m) — AutoDrive kan tippe ved nabosiloen; sæt AD-indstillingen til 10 m", tostring(ADRuns.vehicleLabel(vehicle)), tostring(trip.targetName), tostring(marker.name), distance) return end end @@ -409,11 +409,11 @@ local function startHold(adEnv, vehicle, run, reasons, sourcesById) if marker == nil then return nil end - warnOnce(adEnv, vehicle, "noWait", string.format("'%s' har intet ledigt Wait-punkt med vejnet (run '%s'); holder ved kilden %s", tostring(vehicle:getName()), tostring(run.name), tostring(marker.name))) + warnOnce(adEnv, vehicle, "noWait", string.format("'%s' har intet ledigt Wait-punkt med vejnet (run '%s'); holder ved kilden %s", tostring(ADRuns.vehicleLabel(vehicle)), tostring(run.name), tostring(marker.name))) end local previous = holds[vehicle] holds[vehicle] = {markerId = marker.id, markerName = tostring(marker.name), reasons = reasons, timerMs = 0} - local message = string.format("'%s' holder ved %s: %s", tostring(vehicle:getName()), tostring(marker.name), table.concat(reasons, "; ")) + local message = string.format("'%s' holder ved %s: %s", tostring(ADRuns.vehicleLabel(vehicle)), tostring(marker.name), table.concat(reasons, "; ")) if previous == nil or previous.lastLogged ~= message then Logging.info(ADOutbound.LOG_PREFIX .. "%s", message) end @@ -447,7 +447,7 @@ function ADOutbound.choosePickup(adEnv, vehicle) runStatus.reasons = reasons for _, reason in ipairs(reasons) do if string.find(reason, ": ingen silo med plads", 1, true) then - warnOnce(adEnv, vehicle, "store:" .. reason, string.format("'%s' finder ingen silo med plads (%s)", tostring(vehicle:getName()), reason)) + warnOnce(adEnv, vehicle, "store:" .. reason, string.format("'%s' finder ingen silo med plads (%s)", tostring(ADRuns.vehicleLabel(vehicle)), reason)) end end if trip == nil then @@ -461,7 +461,7 @@ function ADOutbound.choosePickup(adEnv, vehicle) if trip.kind == "sell" then for _, product in ipairs(input.products) do if product.fillType == trip.fillTypes[1] and product.quote ~= nil then - Logging.info(ADOutbound.LOG_PREFIX .. "'%s' pris %s: %.0f kr/1000 l ved %s, årets top %.0f -> %d %% (kræver %d)", tostring(vehicle:getName()), product.name, (product.quote.price or 0) * 1000, tostring(product.quote.stationName), (product.quote.top or 0) * 1000, product.quote.percent or 0, run.sellAtPercent or 90) + Logging.info(ADOutbound.LOG_PREFIX .. "'%s' pris %s: %.0f kr/1000 l ved %s, årets top %.0f -> %d %% (kræver %d)", tostring(ADRuns.vehicleLabel(vehicle)), product.name, (product.quote.price or 0) * 1000, tostring(product.quote.stationName), (product.quote.top or 0) * 1000, product.quote.percent or 0, run.sellAtPercent or 90) end end end @@ -511,7 +511,7 @@ local function updateHold(adEnv, task, hold, dt) releaseHold(vehicle) ADWaitPool.redirect(task, targetId) task.activatedUALLoading = false - Logging.info(ADOutbound.LOG_PREFIX .. "'%s' kører fra Wait: der er noget at hente igen", tostring(vehicle:getName())) + Logging.info(ADOutbound.LOG_PREFIX .. "'%s' kører fra Wait: der er noget at hente igen", tostring(ADRuns.vehicleLabel(vehicle))) end return true end @@ -568,7 +568,7 @@ local function updateSpawn(adEnv, state, task, source, dt) if stored < spawn.pending.stored and (loaded > spawn.pending.loaded or level > spawn.pending.level) then spawn.pending = nil elseif spawn.pending.ms > ADOutbound.SPAWN_STALL_MS then - warnOnce(adEnv, vehicle, "spawn", string.format("'%s': objektlageret %s spawner ikke %s (30 s uden fremdrift); kører med det der er", tostring(vehicle:getName()), tostring(source.name), fillTypeName(fillType))) + warnOnce(adEnv, vehicle, "spawn", string.format("'%s': objektlageret %s spawner ikke %s (30 s uden fremdrift); kører med det der er", tostring(ADRuns.vehicleLabel(vehicle)), tostring(source.name), fillTypeName(fillType))) state.done = true return else @@ -594,7 +594,7 @@ local function updateSpawn(adEnv, state, task, source, dt) if ADSources.spawnOne(source, index) then spawn.pending = {stored = ADSources.countStored(source, fillType), loaded = countLoaded(task.trailers), level = adEnv.AutoDrive.getAllFillLevels(task.trailers) or 0, ms = 0} else - warnOnce(adEnv, vehicle, "spawn", string.format("'%s': kunne ikke tage %s ud af %s; kører med det der er", tostring(vehicle:getName()), fillTypeName(fillType), tostring(source.name))) + warnOnce(adEnv, vehicle, "spawn", string.format("'%s': kunne ikke tage %s ud af %s; kører med det der er", tostring(ADRuns.vehicleLabel(vehicle)), fillTypeName(fillType), tostring(source.name))) state.done = true end end @@ -669,13 +669,13 @@ function ADOutbound.beforeLoadUpdate(adEnv, task, dt) emptyUntil[tostring(state.current) .. ":" .. tostring(fillType)] = expires end local okDiag, diagnosis = pcall(describeLoadFailure, adEnv, vehicle, task, state, source) - Logging.warning(ADOutbound.LOG_PREFIX .. "'%s': intet at læsse ved %s efter %d s; kilden springes over i %d min (%s)", tostring(vehicle:getName()), tostring(source ~= nil and source.name or state.current), math.floor(ADOutbound.EMPTY_SOURCE_MS / 1000), math.floor(ADOutbound.EMPTY_SOURCE_TTL_MS / 60000), okDiag and diagnosis or tostring(diagnosis)) + Logging.warning(ADOutbound.LOG_PREFIX .. "'%s': intet at læsse ved %s efter %d s; kilden springes over i %d min (%s)", tostring(ADRuns.vehicleLabel(vehicle)), tostring(source ~= nil and source.name or state.current), math.floor(ADOutbound.EMPTY_SOURCE_MS / 1000), math.floor(ADOutbound.EMPTY_SOURCE_TTL_MS / 60000), okDiag and diagnosis or tostring(diagnosis)) state.noProgressMs, state.completed = 0, true task:finished() return true end if state.noProgressMs > ADOutbound.NO_PROGRESS_MS and level > 0 and not spawnPending then - Logging.info(ADOutbound.LOG_PREFIX .. "'%s': ingen mere last ved %s; kører med %.0f l", tostring(vehicle:getName()), tostring(source ~= nil and source.name or state.current), level) + Logging.info(ADOutbound.LOG_PREFIX .. "'%s': ingen mere last ved %s; kører med %.0f l", tostring(ADRuns.vehicleLabel(vehicle)), tostring(source ~= nil and source.name or state.current), level) state.noProgressMs, state.completed = 0, true task:finished() return true @@ -716,7 +716,7 @@ function ADOutbound.beforeUnloadUpdate(adEnv, task, dt) pcall(unit.setAllTensionBeltsActive, unit, false, false) end end - Logging.info(ADOutbound.LOG_PREFIX .. "'%s': stropper løsnet %.0f m før %s", tostring(vehicle:getName()), distance, tostring(state.trip.targetName)) + Logging.info(ADOutbound.LOG_PREFIX .. "'%s': stropper løsnet %.0f m før %s", tostring(ADRuns.vehicleLabel(vehicle)), distance, tostring(state.trip.targetName)) return false end @@ -741,7 +741,7 @@ function ADOutbound.strapAfterLoading(adEnv, task) end state.unstrapped = false if strapped > 0 then - Logging.info(ADOutbound.LOG_PREFIX .. "'%s': stropper spændt efter pålæsning", tostring(vehicle:getName())) + Logging.info(ADOutbound.LOG_PREFIX .. "'%s': stropper spændt efter pålæsning", tostring(ADRuns.vehicleLabel(vehicle))) end end @@ -759,7 +759,7 @@ function ADOutbound.beforeLoadFinished(adEnv, task) end for _, wayPointId in ipairs(state.queue) do if not state.visited[wayPointId] and state.sources[wayPointId] ~= nil then - Logging.info(ADOutbound.LOG_PREFIX .. "'%s' runde: %.0f l på vognen, videre til %s", tostring(vehicle:getName()), level or 0, tostring(state.sources[wayPointId].name)) + Logging.info(ADOutbound.LOG_PREFIX .. "'%s' runde: %.0f l på vognen, videre til %s", tostring(ADRuns.vehicleLabel(vehicle)), level or 0, tostring(state.sources[wayPointId].name)) goToSource(adEnv, state, task, wayPointId) return true end diff --git a/FS25_ADSmartPickup/adRuns.lua b/FS25_ADSmartPickup/adRuns.lua index d21c68b..3310505 100644 --- a/FS25_ADSmartPickup/adRuns.lua +++ b/FS25_ADSmartPickup/adRuns.lua @@ -410,3 +410,43 @@ function ADRuns.fromRecords(records) end return store end + +-- ---- køretøjsnavne ---- + +-- Navn pr. køretøj efter det forløb det kører: "Milk Collect 1", "Milk Collect 2" … i medlemsrækkefølge; +-- er køretøjet alene i forløbet, bare forløbets navn. {[vehicleId] = navn}. +function ADRuns.vehicleNames(store) + local names = {} + for _, run in ipairs(store ~= nil and store.runs or {}) do + local count = #(run.vehicleIds or {}) + for index, vehicleId in ipairs(run.vehicleIds or {}) do + names[vehicleId] = count > 1 and string.format("%s %d", tostring(run.name), index) or tostring(run.name) + end + end + return names +end + +-- true når navnet er et forløbsnavn vi selv har sat ("Navn" eller "Navn 3"). +function ADRuns.isRunVehicleName(store, name) + if name == nil then return false end + for _, run in ipairs(store ~= nil and store.runs or {}) do + local runName = tostring(run.name) + if name == runName then return true end + local prefix, number = string.match(name, "^(.-) (%d+)$") + if prefix == runName and number ~= nil then return true end + end + return false +end + +-- Navnet i log og menu: AutoDrives førernavn (sat efter forløbet), ellers køretøjets modelnavn. +function ADRuns.vehicleLabel(vehicle) + local stateModule = vehicle ~= nil and vehicle.ad ~= nil and vehicle.ad.stateModule or nil + if stateModule ~= nil and stateModule.getName ~= nil then + local ok, name = pcall(stateModule.getName, stateModule) + if ok and name ~= nil and name ~= "" then return tostring(name) end + end + if vehicle ~= nil and vehicle.getName ~= nil then + return tostring(vehicle:getName()) + end + return "?" +end diff --git a/FS25_ADSmartPickup/adRunsController.lua b/FS25_ADSmartPickup/adRunsController.lua index 88599cb..9ad9d86 100644 --- a/FS25_ADSmartPickup/adRunsController.lua +++ b/FS25_ADSmartPickup/adRunsController.lua @@ -136,6 +136,45 @@ function ADRunsController.unassignVehicle(vehicle) end end +-- ---- køretøjsnavne ---- + +ADRunsController.NAME_INTERVAL_MS = 2000 +local nameTimerMs = 0 +local namedByUs = {} + +-- Sætter AutoDrives førernavn efter forløbet ("Milk Collect 1"). Et køretøj der ikke længere er i et +-- forløb, får modelnavnet tilbage — men kun hvis navnet er et vi selv har sat (brugerens egne navne røres ikke). +function ADRunsController.applyVehicleNames(adEnv) + local store = ADRunsController.store + local names = ADRuns.vehicleNames(store) + for _, vehicle in ipairs(ADRunsController.getFarmVehicles(adEnv)) do + local stateModule = vehicle.ad ~= nil and vehicle.ad.stateModule or nil + if stateModule ~= nil and stateModule.setName ~= nil then + local id = ADRunsController.getVehicleId(vehicle) + local wanted = id ~= nil and names[id] or nil + local current = stateModule.getName ~= nil and stateModule:getName() or stateModule.driverName + if wanted ~= nil then + if current ~= wanted then + stateModule:setName(wanted) + if stateModule.raiseDirtyFlag ~= nil then stateModule:raiseDirtyFlag() end + end + namedByUs[vehicle] = wanted + elseif (namedByUs[vehicle] ~= nil and current == namedByUs[vehicle]) or ADRuns.isRunVehicleName(store, current) then + stateModule:setName(tostring(vehicle:getName())) + if stateModule.raiseDirtyFlag ~= nil then stateModule:raiseDirtyFlag() end + namedByUs[vehicle] = nil + end + end + end +end + +function ADRunsController.applyVehicleNamesThrottled(adEnv, dt) + nameTimerMs = nameTimerMs + (dt or 0) + if nameTimerMs < ADRunsController.NAME_INTERVAL_MS then return end + nameTimerMs = 0 + ADRunsController.applyVehicleNames(adEnv) +end + -- ---- varer ---- function ADRunsController.getCarriableFillTypes(adEnv, vehicle) @@ -270,12 +309,17 @@ end -- Fire traktorer kan hedde det samme; løbenummeret er pladsen i farmens AD-køretøjsliste. function ADRunsController.getVehicleLabel(adEnv, vehicle) + local label, model = tostring(ADRuns.vehicleLabel(vehicle)), tostring(vehicle:getName()) + -- førernavn efter forløbet: "Milk Collect 1 (Virtus 135 RVshift)"; ellers modelnavn + løbenummer + if label ~= model then + return string.format("%s (%s)", label, model) + end for index, candidate in ipairs(ADRunsController.getFarmVehicles(adEnv)) do if candidate == vehicle then - return string.format("%s (#%d)", tostring(vehicle:getName()), index) + return string.format("%s (#%d)", model, index) end end - return tostring(vehicle:getName()) + return model end -- ---- bygninger (flow-tavlen): bygnings-id'er -> markører ---- @@ -428,7 +472,7 @@ function ADRunsController.getFlowRow(adEnv, run) local vehiclesById = getFarmVehiclesById(adEnv) for _, vehicleId in ipairs(run.vehicleIds) do local vehicle = vehiclesById[vehicleId] - table.insert(row.vehicleNames, vehicle ~= nil and tostring(vehicle:getName()) or "?") + table.insert(row.vehicleNames, vehicle ~= nil and tostring(ADRuns.vehicleLabel(vehicle)) or "?") end local status = ADRunsController.getRunStatus(adEnv, run) row.running, row.total, row.isRunning = status.running, status.total, status.isRunning @@ -484,7 +528,7 @@ local function hasAutoload(adEnv, vehicle) autoloadDiagnosed[vehicle] = true local parts = {} for _, unit in ipairs(trailers or {}) do table.insert(parts, describeAutoloadUnit(unit)) end - Logging.info(ADRunsController.LOG_PREFIX .. "'%s': ingen autoload fundet på enhederne: %s", tostring(vehicle:getName()), #parts > 0 and table.concat(parts, "; ") or "(ingen enheder)") + Logging.info(ADRunsController.LOG_PREFIX .. "'%s': ingen autoload fundet på enhederne: %s", tostring(ADRuns.vehicleLabel(vehicle)), #parts > 0 and table.concat(parts, "; ") or "(ingen enheder)") end return false end @@ -719,10 +763,10 @@ function ADRunsController.findWrongCargoDump(adEnv, run, vehicle, targetId) local marker, why = ADLoadSwap.findDumpMarker(adEnv, vehicle, fillType, liters, targetId, isReachable) local fillTypeName = g_fillTypeManager ~= nil and g_fillTypeManager:getFillTypeNameByIndex(fillType) or tostring(fillType) if marker == nil then - Logging.warning(ADRunsController.LOG_PREFIX .. "run '%s': '%s' har %.0f l %s på vognen, som målet ikke tager — %s; AutoDrive starter som normalt", tostring(run.name), tostring(vehicle:getName()), liters, tostring(fillTypeName), tostring(why)) + Logging.warning(ADRunsController.LOG_PREFIX .. "run '%s': '%s' har %.0f l %s på vognen, som målet ikke tager — %s; AutoDrive starter som normalt", tostring(run.name), tostring(ADRuns.vehicleLabel(vehicle)), liters, tostring(fillTypeName), tostring(why)) return nil end - Logging.info(ADRunsController.LOG_PREFIX .. "run '%s': '%s' læsser først %.0f l %s af i %s (markør %s) — målet tager ikke varen", tostring(run.name), tostring(vehicle:getName()), liters, tostring(fillTypeName), tostring(marker.name), tostring(marker.markerIndex or marker.id)) + Logging.info(ADRunsController.LOG_PREFIX .. "run '%s': '%s' læsser først %.0f l %s af i %s (markør %s) — målet tager ikke varen", tostring(run.name), tostring(ADRuns.vehicleLabel(vehicle)), liters, tostring(fillTypeName), tostring(marker.name), tostring(marker.markerIndex or marker.id)) return {marker = marker, fillType = fillType, liters = liters} end @@ -793,7 +837,7 @@ ADRunsController.AL_UNLOAD_CENTER = 1 local function ensureAutoloadUnload(adEnv, vehicle) if getSettingValue(adEnv, vehicle, "ALUnload") == 0 then setSetting(adEnv, vehicle, "ALUnload", ADRunsController.AL_UNLOAD_CENTER) - Logging.info(ADRunsController.LOG_PREFIX .. "'%s': AutoDrives 'AL unload' var fra — sat til 'center' (stropper løsnes i triggeren)", tostring(vehicle:getName())) + Logging.info(ADRunsController.LOG_PREFIX .. "'%s': AutoDrives 'AL unload' var fra — sat til 'center' (stropper løsnes i triggeren)", tostring(ADRuns.vehicleLabel(vehicle))) end end @@ -914,7 +958,7 @@ function ADRunsController.startRun(adEnv, runId) local validation = ADRunsController.validateVehicle(adEnv, run, vehicle) local result = {vehicle = vehicle, ok = validation.ok, reason = validation.reason, missingBuilding = validation.missingBuilding} if not validation.ok then - Logging.info(ADRunsController.LOG_PREFIX .. "run '%s': '%s' sprunget over (%s)", tostring(run.name), tostring(vehicle:getName()), tostring(validation.reason)) + Logging.info(ADRunsController.LOG_PREFIX .. "run '%s': '%s' sprunget over (%s)", tostring(run.name), tostring(ADRuns.vehicleLabel(vehicle)), tostring(validation.reason)) end if validation.ok then local ingredients = ADRunsController.getRunIngredients(adEnv, run, vehicle) @@ -922,10 +966,10 @@ function ADRunsController.startRun(adEnv, runId) if ok then started = started + 1 local target = run.kind == "outbound" and ("kilde " .. tostring(run.sourceWayPointIds[1])) or ("markør " .. tostring(run.targetWayPointId)) - Logging.info(ADRunsController.LOG_PREFIX .. "run '%s': '%s' startet mod %s", tostring(run.name), tostring(vehicle:getName()), target) + Logging.info(ADRunsController.LOG_PREFIX .. "run '%s': '%s' startet mod %s", tostring(run.name), tostring(ADRuns.vehicleLabel(vehicle)), target) else result.ok, result.reason = false, "error" - Logging.warning(ADRunsController.LOG_PREFIX .. "run '%s': kunne ikke starte '%s': %s", tostring(run.name), tostring(vehicle:getName()), tostring(err)) + Logging.warning(ADRunsController.LOG_PREFIX .. "run '%s': kunne ikke starte '%s': %s", tostring(run.name), tostring(ADRuns.vehicleLabel(vehicle)), tostring(err)) end end table.insert(results, result) @@ -944,7 +988,7 @@ function ADRunsController.stopIfRunning(vehicle, reason) return false end stopVehicle(vehicle) - Logging.info(ADRunsController.LOG_PREFIX .. "'%s' stoppet (%s)", tostring(vehicle:getName()), tostring(reason)) + Logging.info(ADRunsController.LOG_PREFIX .. "'%s' stoppet (%s)", tostring(ADRuns.vehicleLabel(vehicle)), tostring(reason)) return true end @@ -960,7 +1004,7 @@ function ADRunsController.stopRun(adEnv, runId) if vehicle ~= nil and isVehicleActive(vehicle) then stopVehicle(vehicle) stopped = stopped + 1 - Logging.info(ADRunsController.LOG_PREFIX .. "run '%s': '%s' stoppet", tostring(run.name), tostring(vehicle:getName())) + Logging.info(ADRunsController.LOG_PREFIX .. "run '%s': '%s' stoppet", tostring(run.name), tostring(ADRuns.vehicleLabel(vehicle))) end end ADRunsController.runningRuns[runId] = nil diff --git a/FS25_ADSmartPickup/adSmartPickup.lua b/FS25_ADSmartPickup/adSmartPickup.lua index aa70b13..0924019 100644 --- a/FS25_ADSmartPickup/adSmartPickup.lua +++ b/FS25_ADSmartPickup/adSmartPickup.lua @@ -379,7 +379,7 @@ local factoryFallbackLogged = setmetatable({}, {__mode = "k"}) local function logFactoryFallbackOnce(driver, station) local placeable = station.owningPlaceable local name = placeable ~= nil and placeable.getName ~= nil and placeable:getName() or "fabrik" - local message = string.format("'%s': %s har ingen ønskede produktioner (tændte eller auto-slukkede pga. mangel) med varer vognen kan bære; bruger dit varevalg", tostring(driver:getName()), tostring(name)) + local message = string.format("'%s': %s har ingen ønskede produktioner (tændte eller auto-slukkede pga. mangel) med varer vognen kan bære; bruger dit varevalg", tostring(ADRuns.vehicleLabel(driver)), tostring(name)) if factoryFallbackLogged[driver] ~= message then factoryFallbackLogged[driver] = message Logging.info(ADSmartPickup.LOG_PREFIX .. "%s", message) @@ -723,7 +723,7 @@ local function chooseRunTarget(adEnv, driver) stateModule:setSecondMarkerByWayPointId(targetId) local marker = adEnv.ADGraphManager.getMapMarkerByWayPointId ~= nil and adEnv.ADGraphManager:getMapMarkerByWayPointId(targetId) or nil local why = #ADRunsController.getRunTargets(run) > 1 and "mangler mest af run'ets mål" or "run'ets mål" - Logging.info(ADSmartPickup.LOG_PREFIX .. "'%s' kører til %s (%s)", tostring(driver:getName()), marker ~= nil and tostring(marker.name) or tostring(targetId), why) + Logging.info(ADSmartPickup.LOG_PREFIX .. "'%s' kører til %s (%s)", tostring(ADRuns.vehicleLabel(driver)), marker ~= nil and tostring(marker.name) or tostring(targetId), why) end -- Samlet valg: behovsstyret med ingrediensliste, ellers mappe-logik. nil = AutoDrives original. @@ -781,7 +781,7 @@ local function describeChoice(choice) end local function logChoiceOnce(driver, choice) - local message = string.format("'%s' -> %s (%s)", tostring(driver:getName()), tostring(choice.markerName), describeChoice(choice)) + local message = string.format("'%s' -> %s (%s)", tostring(ADRuns.vehicleLabel(driver)), tostring(choice.markerName), describeChoice(choice)) if lastLogged[driver] ~= message then lastLogged[driver] = message Logging.info(ADSmartPickup.LOG_PREFIX .. "%s", message) @@ -856,7 +856,7 @@ local function installLoadWaitHook(adEnv) end local cargoName = g_fillTypeManager ~= nil and g_fillTypeManager:getFillTypeNameByIndex(fillType) or tostring(fillType) local wantedName = g_fillTypeManager ~= nil and g_fillTypeManager:getFillTypeNameByIndex(pickup.fillType) or tostring(pickup.fillType) - Logging.info(ADSmartPickup.LOG_PREFIX .. "'%s' har %.0f l %s på vognen og skulle hente %s — leverer først det den har", tostring(loadTask.vehicle:getName()), liters, tostring(cargoName), tostring(wantedName)) + Logging.info(ADSmartPickup.LOG_PREFIX .. "'%s' har %.0f l %s på vognen og skulle hente %s — leverer først det den har", tostring(ADRuns.vehicleLabel(loadTask.vehicle)), liters, tostring(cargoName), tostring(wantedName)) return true end @@ -874,7 +874,7 @@ local function installLoadWaitHook(adEnv) if shouldWait then local stalledOk, isStalled = pcall(hasLoadingStalled, self, dt) if not stalledOk or isStalled then - Logging.warning(ADSmartPickup.LOG_PREFIX .. "'%s' læsser ikke ved markøren; slipper grebet så AutoDrive kører videre", tostring(self.vehicle:getName())) + Logging.warning(ADSmartPickup.LOG_PREFIX .. "'%s' læsser ikke ved markøren; slipper grebet så AutoDrive kører videre", tostring(ADRuns.vehicleLabel(self.vehicle))) activePickups[self.vehicle] = nil shouldWait = false end @@ -1052,6 +1052,9 @@ function ADSmartPickup:update(dt) if ADOutbound ~= nil and ADOutbound.releaseInactive ~= nil then pcall(ADOutbound.releaseInactive) end + if ADRunsController ~= nil and ADRunsController.applyVehicleNamesThrottled ~= nil then + pcall(ADRunsController.applyVehicleNamesThrottled, getAutoDriveEnv(), dt) + end local ok, err = pcall(restoreStoppedVehicles) if not ok then Logging.warning(ADSmartPickup.LOG_PREFIX .. "kunne ikke gendanne varevalg: %s", tostring(err)) diff --git a/FS25_ADSmartPickup/adUnloadWait.lua b/FS25_ADSmartPickup/adUnloadWait.lua index edf262b..7a49c4d 100644 --- a/FS25_ADSmartPickup/adUnloadWait.lua +++ b/FS25_ADSmartPickup/adUnloadWait.lua @@ -142,7 +142,7 @@ local function startWaiting(adEnv, task) -- ("til den er tømt") og spærrer for de næste. Regn vognen som tom og kør videre. local smallFree = ADSmartPickup.getTargetFreeCapacity(adEnv, vehicle, fillType) if rest > 0 and (smallFree == nil or smallFree < rest) and task.finished ~= nil then - Logging.info(ADUnloadWait.LOG_PREFIX .. "'%s': %.0f l %s rest kan ikke komme af — regnes som tom, kører videre", tostring(vehicle:getName()), rest, g_fillTypeManager ~= nil and tostring(g_fillTypeManager:getFillTypeNameByIndex(fillType)) or tostring(fillType)) + Logging.info(ADUnloadWait.LOG_PREFIX .. "'%s': %.0f l %s rest kan ikke komme af — regnes som tom, kører videre", tostring(ADRuns.vehicleLabel(vehicle)), rest, g_fillTypeManager ~= nil and tostring(g_fillTypeManager:getFillTypeNameByIndex(fillType)) or tostring(fillType)) task:finished() end return @@ -166,7 +166,7 @@ local function startWaiting(adEnv, task) if not warnedNoWaitPoint[vehicle] then warnedNoWaitPoint[vehicle] = true local poolText = pool ~= nil and pool ~= "" and (" i puljen '" .. pool .. "'") or "" - Logging.warning(ADUnloadWait.LOG_PREFIX .. "'%s' har %.0f l rest, og målet er fuldt — intet ledigt Wait-punkt%s med vejnet til OG fra målet (markør i en mappe med 'Wait' i navnet), så AutoDrive venter ved målet", tostring(vehicle:getName()), rest, poolText) + Logging.warning(ADUnloadWait.LOG_PREFIX .. "'%s' har %.0f l rest, og målet er fuldt — intet ledigt Wait-punkt%s med vejnet til OG fra målet (markør i en mappe med 'Wait' i navnet), så AutoDrive venter ved målet", tostring(ADRuns.vehicleLabel(vehicle)), rest, poolText) end return end @@ -177,7 +177,7 @@ local function startWaiting(adEnv, task) -- portioner, når målet forbruger løbende. Derfor peger AD's mål på Wait-punktet imens. redirectForUnload(task, candidate.marker.id) local fillTypeName = g_fillTypeManager ~= nil and g_fillTypeManager:getFillTypeNameByIndex(fillType) or tostring(fillType) - Logging.info(ADUnloadWait.LOG_PREFIX .. "'%s' venter ved %s (markør %s): %.0f l %s rest, målet har kun %.0f l fri", tostring(vehicle:getName()), tostring(candidate.marker.name), tostring(candidate.marker.markerIndex or candidate.marker.id), rest, tostring(fillTypeName), free) + Logging.info(ADUnloadWait.LOG_PREFIX .. "'%s' venter ved %s (markør %s): %.0f l %s rest, målet har kun %.0f l fri", tostring(ADRuns.vehicleLabel(vehicle)), tostring(candidate.marker.name), tostring(candidate.marker.markerIndex or candidate.marker.id), rest, tostring(fillTypeName), free) end -- Ventende køretøj: er der nu plads til hele resten, køres tilbage til målet. @@ -216,7 +216,7 @@ local function updateWaiting(adEnv, task, wait, dt) release(vehicle) restoreTarget(vehicle) redirect(task, home) - Logging.info(ADUnloadWait.LOG_PREFIX .. "'%s' kører tilbage fra %s og læsser %.0f l af (målet har %.0f l fri)", tostring(vehicle:getName()), tostring(wait.waitMarker.name), rest, free) + Logging.info(ADUnloadWait.LOG_PREFIX .. "'%s' kører tilbage fra %s og læsser %.0f l af (målet har %.0f l fri)", tostring(ADRuns.vehicleLabel(vehicle)), tostring(wait.waitMarker.name), rest, free) end -- Diagnose (midlertidig): mens en traktor holder ved sit mål med last, logges hvert 15. s hvad @@ -255,7 +255,7 @@ local function debugAtTarget(adEnv, task, dt) local fillTypeName = g_fillTypeManager ~= nil and g_fillTypeManager:getFillTypeNameByIndex(fillType) or tostring(fillType) local distance = adEnv.AutoDrive.getDistanceToUnloadPosition ~= nil and adEnv.AutoDrive.getDistanceToUnloadPosition(vehicle) or -1 local secondMarker = vehicle.ad.stateModule.getSecondMarker ~= nil and vehicle.ad.stateModule:getSecondMarker() or nil - Logging.info(ADUnloadWait.LOG_PREFIX .. "DEBUG '%s': targetReached=%s taskDest=%s adMål=%s; %.0f l %s på vognen; målet fri=%s/kap=%s; AD isUnloading=%s isLoading=%s afstandTilAflæsning=%.1f; venter=%s; %s", tostring(vehicle:getName()), tostring(targetReached), tostring(task.destinationID), tostring(secondMarker ~= nil and secondMarker.id or nil), rest, tostring(fillTypeName), tostring(free), tostring(capacity), tostring(trailerModule ~= nil and trailerModule.isUnloading), tostring(trailerModule ~= nil and trailerModule.isLoading), tonumber(distance) or -1, tostring(waits[vehicle] ~= nil), table.concat(states, " | ")) + Logging.info(ADUnloadWait.LOG_PREFIX .. "DEBUG '%s': targetReached=%s taskDest=%s adMål=%s; %.0f l %s på vognen; målet fri=%s/kap=%s; AD isUnloading=%s isLoading=%s afstandTilAflæsning=%.1f; venter=%s; %s", tostring(ADRuns.vehicleLabel(vehicle)), tostring(targetReached), tostring(task.destinationID), tostring(secondMarker ~= nil and secondMarker.id or nil), rest, tostring(fillTypeName), tostring(free), tostring(capacity), tostring(trailerModule ~= nil and trailerModule.isUnloading), tostring(trailerModule ~= nil and trailerModule.isLoading), tonumber(distance) or -1, tostring(waits[vehicle] ~= nil), table.concat(states, " | ")) end function ADUnloadWait.beforeUpdate(adEnv, task, dt) @@ -299,7 +299,7 @@ function ADUnloadWait.adoptOrphans(adEnv) pendingTargetRestore[vehicle] = homeId waits[vehicle] = {task = task, homeDestinationID = homeId, waitMarker = marker, fillType = fillType, rest = rest} local fillTypeName = g_fillTypeManager ~= nil and g_fillTypeManager:getFillTypeNameByIndex(fillType) or tostring(fillType) - Logging.info(ADUnloadWait.LOG_PREFIX .. "'%s' genoptager ventning ved %s efter genindlæsning: %.0f l %s rest, hjem = markør %s", tostring(vehicle:getName()), tostring(marker.name), rest, tostring(fillTypeName), tostring(homeId)) + Logging.info(ADUnloadWait.LOG_PREFIX .. "'%s' genoptager ventning ved %s efter genindlæsning: %.0f l %s rest, hjem = markør %s", tostring(ADRuns.vehicleLabel(vehicle)), tostring(marker.name), rest, tostring(fillTypeName), tostring(homeId)) end end end diff --git a/FS25_ADSmartPickup/gui/SmartPickupFrame.lua b/FS25_ADSmartPickup/gui/SmartPickupFrame.lua index 84d009c..c48fb69 100644 --- a/FS25_ADSmartPickup/gui/SmartPickupFrame.lua +++ b/FS25_ADSmartPickup/gui/SmartPickupFrame.lua @@ -741,7 +741,7 @@ function SmartPickupFrame:onClickStartStop() if result.reason == "noMarker" and result.missingBuilding ~= nil then reasonText = string.format(reasonText, tostring(result.missingBuilding)) end - table.insert(reasons, string.format("%s: %s", tostring(result.vehicle:getName()), reasonText)) + table.insert(reasons, string.format("%s: %s", tostring(ADRuns.vehicleLabel(result.vehicle)), reasonText)) end end frame.statusOverride = string.format(frame.i18n:getText("spu_status_started"), started, skipped) diff --git a/FS25_ADSmartPickup/modDesc.xml b/FS25_ADSmartPickup/modDesc.xml index 2493b17..1b0c818 100644 --- a/FS25_ADSmartPickup/modDesc.xml +++ b/FS25_ADSmartPickup/modDesc.xml @@ -1,7 +1,7 @@ masterdraco - 1.16.3.0 + 1.17.0.0 <en>AD Smart Pickup</en> diff --git a/docs/BRUGERMANUAL.md b/docs/BRUGERMANUAL.md index 32b997c..dc06acd 100644 --- a/docs/BRUGERMANUAL.md +++ b/docs/BRUGERMANUAL.md @@ -1,6 +1,6 @@ # AD Smart Pickup — brugermanual -Version 1.16.1 · Farming Simulator 25 · tillæg til AutoDrive +Version 1.17.0 · Farming Simulator 25 · tillæg til AutoDrive *English version: [USER_MANUAL.md](USER_MANUAL.md)* @@ -267,7 +267,7 @@ Under **Fra** kan du vælge: |---|---| | **Fabrik** | Fabrikkens outputs, både bulk og paller fra pallespawneren | | **Silo** | Siloens indhold | -| **Stald** | Mælk, gylle og gødning fra staldens læssepunkter | +| **Stald** | Mælk, gylle og gødning fra staldens læssepunkter, inklusive tilknyttede udvidelsestanke som Milk Tank Extension | | **Objektlager** | Paller og baller. De tages ud én ad gangen | ### Politik pr. vare @@ -357,6 +357,11 @@ Nederst i flowet står gårdens køretøjer med kapacitet. Sæt **Ja** ud for de - **Køretøjer, der ikke kan bruges, er låst** og viser grunden. Grundene er beskrevet i tabellen. - Et køretøj kan kun være med i ét flow. Flyttes det, står der *flyttet fra 'andet flow'*. - Fjerner du en kørende traktor fra et flow, stoppes den. +- **Navne:** traktorerne får automatisk AutoDrive-førernavn efter deres flow, fx *Milk Collect 1* og + *Milk Collect 2*. Er traktoren alene i flowet, hedder den bare som flowet. Navnet bruges i + AutoDrive, i menuen og i loggen, og modelnavnet står i parentes i menuen. Tages traktoren ud af + flowet, får den sit modelnavn igen. Navne, du selv har givet i AutoDrive, røres kun, mens + traktoren er med i et flow. | Grund | Betydning | |---|---| diff --git a/docs/USER_MANUAL.md b/docs/USER_MANUAL.md index c771c58..897dab9 100644 --- a/docs/USER_MANUAL.md +++ b/docs/USER_MANUAL.md @@ -1,6 +1,6 @@ # AD Smart Pickup — user manual -Version 1.16.1 · Farming Simulator 25 · add-on for AutoDrive +Version 1.17.0 · Farming Simulator 25 · add-on for AutoDrive *Dansk version: [BRUGERMANUAL.md](BRUGERMANUAL.md)* @@ -270,7 +270,7 @@ Under **From** you can pick: |---|---| | **Factory** | The factory's outputs, both bulk and pallets from the pallet spawner | | **Silo** | The silo's contents | -| **Barn** | Milk, slurry and manure from the barn's loading points | +| **Barn** | Milk, slurry and manure from the barn's loading points, including attached extension tanks such as Milk Tank Extension | | **Object storage** | Pallets and bales. They are taken out one at a time | ### Policy per good @@ -361,6 +361,11 @@ ones that should drive. - **Vehicles that cannot be used are locked** and show the reason. The reasons are in the table. - A vehicle can only be in one flow. If it is moved, it shows *moved from 'other flow'*. - If you remove a running tractor from a flow, it is stopped. +- **Names:** tractors automatically get an AutoDrive driver name after their flow, such as + *Milk Collect 1* and *Milk Collect 2*. A tractor that is alone in its flow gets the flow's name. + The name is used in AutoDrive, in the menu and in the log, and the menu shows the model name in + brackets. When a tractor leaves its flow, it gets its model name back. Names you set yourself in + AutoDrive are only changed while the tractor is in a flow. | Reason | Meaning | |---|---| diff --git a/tests/test_adRuns.lua b/tests/test_adRuns.lua index a1f0756..b7652ee 100644 --- a/tests/test_adRuns.lua +++ b/tests/test_adRuns.lua @@ -292,5 +292,20 @@ do check("Rv3 xml læs kilder", table.concat(ADRuns.getRun(back, flow.id).sourceBuildingIds, ","), "barn1,barn2") end +-- RN: køretøjsnavne efter forløbet — "Navn 1", "Navn 2" … i medlemsrækkefølge; ét køretøj = bare navnet +do + local store, runA = ADRuns.createRun(ADRuns.newStore(), "Milk Collect", "outbound") + store = ADRuns.assignVehicle(store, runA.id, "v1") + store = ADRuns.assignVehicle(store, runA.id, "v2") + local runB + store, runB = ADRuns.createRun(store, "Milk Salg", "outbound") + store = ADRuns.assignVehicle(store, runB.id, "v3") + local names = ADRuns.vehicleNames(store) + check("RN to i samme forløb: 1", names.v1, "Milk Collect 1") + check("RN to i samme forløb: 2", names.v2, "Milk Collect 2") + check("RN alene i forløb = navnet", names.v3, "Milk Salg") + check("RN ukendt køretøj", names.v9, nil) +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_adRunsController.lua b/tests/test_adRunsController.lua index 6f6cf19..7b4fb48 100644 --- a/tests/test_adRunsController.lua +++ b/tests/test_adRunsController.lua @@ -702,5 +702,22 @@ check("CF5 forsyning til", table.concat(rowIn.toNames, ","), "Kostald 1,Sukkerfa check("CF5 forsyning auto-varer", rowIn.productAuto, true) ADBuildings = nil; ADSources = nil; ADOutbound = nil +-- RC-navne: køretøjer får AD-førernavn efter forløbet; ude af forløb -> modelnavnet igen +do + local named = makeVehicle("vehicleNamed", "Virtus 135", {MILK or 1}, 20000, 0, 0) + named.ad.stateModule.driverName = "Virtus 135" + named.ad.stateModule.setName = function(self, n) self.driverName = n end + named.ad.stateModule.getName = function(self) return self.driverName end + local run = ADRunsController.createRun("Mælk ind", "outbound") + ADRunsController.assignVehicle(run.id, named) + ADRunsController.applyVehicleNames(adEnv) + check("RC-navne sat efter forløb", named.ad.stateModule.driverName, "Mælk ind") + check("RC-navne label bruger førernavn", ADRuns.vehicleLabel(named), "Mælk ind") + ADRunsController.store = ADRuns.unassignVehicle(ADRunsController.store, "vehicleNamed") + ADRunsController.applyVehicleNames(adEnv) + check("RC-navne ude af forløb -> modelnavn", named.ad.stateModule.driverName, "Virtus 135") + check("RC-navne label uden AD-navn", ADRuns.vehicleLabel({getName = function() return "Fendt" end}), "Fendt") +end + print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL")) os.exit(failures == 0 and 0 or 1)