From 0d1e82983a10f661d4acc7a42a5fc8dbb53ab211 Mon Sep 17 00:00:00 2001 From: masterdraco Date: Wed, 23 Sep 2026 15:02:32 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20autoload-bil=20l=C3=B8sner=20stropperne?= =?UTF-8?q?=2025=20m=20f=C3=B8r=20afl=C3=A6sningsm=C3=A5let=20(ladet=20pas?= =?UTF-8?q?serer=20triggeren=20f=C3=B8r=20mark=C3=B8ren)=20(v1.12.11.0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FS25_ADSmartPickup/adOutbound.lua | 53 +++++++++++++++++++++++++++++++ FS25_ADSmartPickup/modDesc.xml | 2 +- tests/test_adOutbound.lua | 33 +++++++++++++++++++ 3 files changed, 87 insertions(+), 1 deletion(-) diff --git a/FS25_ADSmartPickup/adOutbound.lua b/FS25_ADSmartPickup/adOutbound.lua index a38defb..084fb3c 100644 --- a/FS25_ADSmartPickup/adOutbound.lua +++ b/FS25_ADSmartPickup/adOutbound.lua @@ -25,6 +25,10 @@ ADOutbound.NOTIFICATION_MS = 8000 -- spawnet, forkert farm, ...): kilden udelukkes for varen i EMPTY_SOURCE_TTL_MS og turen afsluttes. ADOutbound.EMPTY_SOURCE_MS = 30000 ADOutbound.EMPTY_SOURCE_TTL_MS = 300000 +-- Autoload-bil på vej til aflæsning: stropperne løsnes så mange meter FØR markøren. Markøren står +-- hvor næsen stopper, og en lastbils lad har passeret salgstriggeren dér; AutoDrive løsner selv +-- først ved markøren ("AL unload = center"), hvilket er for sent for en lastbil. +ADOutbound.UNSTRAP_BEFORE_M = 25 -- køretøj -> {run, trip, sources, queue, visited, current, lastFill, noProgressMs, spawn, done} local trips = setmetatable({}, {__mode = "k"}) @@ -570,6 +574,43 @@ function ADOutbound.beforeLoadUpdate(adEnv, task, dt) return false end +local function distanceToWayPoint(adEnv, vehicle, wayPointId) + local wayPoint = adEnv.ADGraphManager:getWayPointById(wayPointId) + if wayPoint == nil or vehicle.rootNode == nil then + return nil + end + local x, _, z = getWorldTranslation(vehicle.rootNode) + local dx, dz = wayPoint.x - x, wayPoint.z - z + return math.sqrt(dx * dx + dz * dz) +end + +-- Aflæsningskørsel (UnloadAtDestinationTask.update): autoload-bil med tur -> stropper af +-- UNSTRAP_BEFORE_M før målet, én gang pr. tur. Ændrer aldrig opgaven (returnerer altid false). +function ADOutbound.beforeUnloadUpdate(adEnv, task, dt) + local vehicle = task.vehicle + local state = trips[vehicle] + if state == nil or state.unstrapped or task.destinationID ~= state.trip.targetWayPointId then + return false + end + local _, hasAutoload = getVehicleCapacity(adEnv, vehicle) + if not hasAutoload then + state.unstrapped = true + return false + end + local distance = distanceToWayPoint(adEnv, vehicle, task.destinationID) + if distance == nil or distance > ADOutbound.UNSTRAP_BEFORE_M then + return false + end + state.unstrapped = true + for _, unit in ipairs(task.trailers or {}) do + if unit.setAllTensionBeltsActive ~= nil then + 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)) + return false +end + -- true = opsamlingsrunden fortsætter til næste kilde (original finished springes over). function ADOutbound.beforeLoadFinished(adEnv, task) local vehicle = task.vehicle @@ -661,4 +702,16 @@ function ADOutbound.install(adEnv) return originalFinished(self) end end + + local unloadTask = adEnv.UnloadAtDestinationTask + if unloadTask ~= nil and unloadTask.update ~= nil then + local originalUnloadUpdate = unloadTask.update + unloadTask.update = function(self, dt) + local okUnload, err = pcall(ADOutbound.beforeUnloadUpdate, adEnv, self, dt) + if not okUnload then + Logging.warning(ADOutbound.LOG_PREFIX .. "fejl ved strop-løsning, AutoDrive fortsætter selv: %s", tostring(err)) + end + return originalUnloadUpdate(self, dt) + end + end end diff --git a/FS25_ADSmartPickup/modDesc.xml b/FS25_ADSmartPickup/modDesc.xml index 335318f..a83d7c2 100644 --- a/FS25_ADSmartPickup/modDesc.xml +++ b/FS25_ADSmartPickup/modDesc.xml @@ -1,7 +1,7 @@ masterdraco - 1.12.10.0 + 1.12.11.0 <en>AD Smart Pickup</en> diff --git a/tests/test_adOutbound.lua b/tests/test_adOutbound.lua index cb1a72a..bb8251f 100644 --- a/tests/test_adOutbound.lua +++ b/tests/test_adOutbound.lua @@ -72,6 +72,7 @@ local adEnv = { AutoDriveMessageEvent = {sendMessageOrNotification = function(vehicle, kind, text, duration, ...) table.insert(notifications, {vehicle = vehicle, kind = kind, text = string.format(text, ...)}) end}, ADMessagesManager = {messageTypes = {INFO = 1, WARN = 2, ERROR = 3}}, LoadAtDestinationTask = {STATE_DRIVING = 2, update = function() end, finished = function(self) self.finishedCalls = (self.finishedCalls or 0) + 1 end}, + UnloadAtDestinationTask = {STATE_DRIVING = 2, update = function() end}, } local function newVehicle(name, x, z, capacity, ual) @@ -438,6 +439,35 @@ check("O20 kapacitet ukendt for pallebil", input20.capacity, nil) check("O20 har autoload", input20.hasAutoload, true) check("O20 turen planlægges alligevel", ADOutboundPlanner.plan(input20) ~= nil, true) +-- O21: autoload-bil på vej til aflæsning: stropperne løsnes UNSTRAP_BEFORE_M før målet (ladet passerer +-- triggeren før markøren), kun én gang pr. tur, og aldrig for tipvogne +local v21 = newVehicle("Dragon3", 0, 0, 1, true) +v21.carriable = {} +v21.trailers[1].setAllTensionBeltsActive = function(self, active) self.beltsActive = active end +runs[v21] = outboundRun(22, {3}, {{fillType = "STRAW_BASKET", policy = "sell"}}) +sources[3].stored[BASKET] = 3 +quotes["selling station"][BASKET] = {percent = 95, price = 1} +ADOutbound.choosePickup(adEnv, v21) +check("O21 tur mod salgssted", v21.ad.stateModule.secondMarkerId, 10) +local unloadTask21 = {vehicle = v21, destinationID = 10, trailers = v21.trailers} +v21.rootNode = {x = 200 - 40, z = 0} -- 40 m fra markør 10 (x=200) +ADOutbound.beforeUnloadUpdate(adEnv, unloadTask21, 16) +check("O21 40 m: stropper stadig på", v21.trailers[1].beltsActive, nil) +v21.rootNode = {x = 200 - 20, z = 0} +ADOutbound.beforeUnloadUpdate(adEnv, unloadTask21, 16) +check("O21 20 m: stropper løsnet", v21.trailers[1].beltsActive, false) +v21.trailers[1].beltsActive = nil +ADOutbound.beforeUnloadUpdate(adEnv, unloadTask21, 16) +check("O21 kun én gang", v21.trailers[1].beltsActive, nil) +local v21b = newVehicle("Tip", 0, 0, 20000) +v21b.trailers[1].setAllTensionBeltsActive = function(self, active) self.beltsActive = active end +runs[v21b] = outboundRun(23, {1}, {{fillType = "SUGAR", policy = "sell"}}) +quotes["selling station"][SUGAR].percent = 92 +ADOutbound.choosePickup(adEnv, v21b) +v21b.rootNode = {x = 195, z = 0} +ADOutbound.beforeUnloadUpdate(adEnv, {vehicle = v21b, destinationID = 10, trailers = v21b.trailers}, 16) +check("O21 tipvogn: ingen stropper", v21b.trailers[1].beltsActive, nil) + -- O10: install wrapper: fejl i hook stopper ikke AD local calls = {} adEnv.LoadAtDestinationTask.update = function(self, dt) calls.update = (calls.update or 0) + 1 end @@ -448,6 +478,9 @@ adEnv.LoadAtDestinationTask.update(newTask(vX, 1), 16) check("O10 original update kaldt", calls.update, 1) adEnv.LoadAtDestinationTask.finished(newTask(vX, 1)) check("O10 original finished kaldt", calls.finished, 1) +adEnv.UnloadAtDestinationTask.update = function(self, dt) calls.unload = (calls.unload or 0) + 1 end +ADOutbound.install(adEnv) +check("O10 unload-wrap ikke installeret dobbelt", adEnv.UnloadAtDestinationTask.update ~= nil, true) print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL")) os.exit(failures == 0 and 0 or 1)