diff --git a/FS25_ADSmartPickup/adBuildings.lua b/FS25_ADSmartPickup/adBuildings.lua index 4832954..4f506f3 100644 --- a/FS25_ADSmartPickup/adBuildings.lua +++ b/FS25_ADSmartPickup/adBuildings.lua @@ -8,6 +8,8 @@ ADBuildings = {} ADBuildings.LOG_PREFIX = "ADSmartPickup: " ADBuildings.MAX_MARKER_DISTANCE = 40 +-- en separat drop-markør (≠ bygningens læssemarkør) må højst stå så langt fra aflæsningstriggeren +ADBuildings.MAX_DROP_DISTANCE = 25 ADBuildings.CACHE_MS = 1000 local cache = {list = nil, farmId = nil, time = -math.huge} @@ -175,6 +177,50 @@ local function nearestMarker(adEnv, nodes) return {id = best.id, name = tostring(best.name), distance = math.floor(bestDistance + 0.5)} end +-- Aflæsningsmarkør: nærmeste ikke-Wait-markør ≤ MAX_MARKER_DISTANCE til aflæsningsnoderne — men ikke +-- bygningens egne LÆSSEmarkører, når der findes en anden (Sugarbeet Crusher: pickup står tættere på +-- aflæsningstriggeren end drop). Kun én fælles markør (AIO Load / Unload) bruges til begge. +local function unloadMarkerFor(adEnv, nodes, loadMarkers, allowSkipLoad) + if #nodes == 0 then + return nil + end + local isLoad = {} + for _, marker in ipairs(loadMarkers or {}) do isLoad[marker.id] = true end + local positions = {} + for _, node in ipairs(nodes) do + local x, z = getNodePosition(node) + if x ~= nil then table.insert(positions, {x = x, z = z}) end + end + local best, bestOther = nil, nil + for _, marker in pairs(adEnv.ADGraphManager:getMapMarkers()) do + if not ADSupplyPlanner.isWaitMarker(marker) then + local wayPoint = adEnv.ADGraphManager:getWayPointById(marker.id) + if wayPoint ~= nil then + for _, position in ipairs(positions) do + local dx, dz = wayPoint.x - position.x, wayPoint.z - position.z + local distance = math.sqrt(dx * dx + dz * dz) + if distance < ADBuildings.MAX_MARKER_DISTANCE then + if best == nil or distance < best.distance then best = {marker = marker, distance = distance} end + if not isLoad[marker.id] and (bestOther == nil or distance < bestOther.distance) then + bestOther = {marker = marker, distance = distance} + end + end + end + end + end + end + -- siloer: altid nærmeste (en fælles markør må ikke erstattes af nabosiloens); ellers kun en "anden" + -- markør der står tæt på aflæsningen + local chosen = best + if allowSkipLoad and bestOther ~= nil and bestOther.distance <= ADBuildings.MAX_DROP_DISTANCE then + chosen = bestOther + end + if chosen == nil then + return nil + end + return {id = chosen.marker.id, name = tostring(chosen.marker.name), distance = math.floor(chosen.distance + 0.5)} +end + -- Silo: den markør hvis STRENGE opslag (trigger bag næsen) rammer siloens læssestation. local function siloLoadMarker(adEnv, farmId, placeable, loadStations) local own = {} @@ -241,7 +287,7 @@ local function build(adEnv, farmId) end table.sort(loadMarkers, function(a, b) return ADBuildings.naturalLess(a.name, b.name) end) end - local unloadMarker = nearestMarker(adEnv, unloadNodes) + local unloadMarker = unloadMarkerFor(adEnv, unloadNodes, loadMarkers, kind ~= "silo") -- silo der kun kan FYLDES (fx drive-on-bunker der fodrer en biogas-fermentor): aflæsning, -- ingen læssestation -> et forsyningsmål, aldrig en kilde local isFillOnlySilo = kind == "silo" and loadMarkers[1] == nil and #loadGroups == 0 and unloadMarker ~= nil diff --git a/FS25_ADSmartPickup/modDesc.xml b/FS25_ADSmartPickup/modDesc.xml index 7777843..d2cd772 100644 --- a/FS25_ADSmartPickup/modDesc.xml +++ b/FS25_ADSmartPickup/modDesc.xml @@ -1,7 +1,7 @@ masterdraco - 1.18.4.0 + 1.18.5.0 <en>AD Smart Pickup</en> diff --git a/docs/BRUGERMANUAL.md b/docs/BRUGERMANUAL.md index 0cd0af7..d737fbb 100644 --- a/docs/BRUGERMANUAL.md +++ b/docs/BRUGERMANUAL.md @@ -1,6 +1,6 @@ # AD Smart Pickup — brugermanual -Version 1.18.4 · Farming Simulator 25 · tillæg til AutoDrive +Version 1.18.5 · Farming Simulator 25 · tillæg til AutoDrive *English version: [USER_MANUAL.md](USER_MANUAL.md)* @@ -92,6 +92,9 @@ Markøren skal højst være **40 m** fra bygningens trigger. *Cow 1 Slurry*. Moden viser dem alle ud for stalden. - **Objektlagre (palleskure):** sæt markøren, så vognens autoload-zone dækker lagerets udleveringsområde, præcis som når du læsser manuelt. +- **Separat drop og pickup:** har en fabrik både en pickup- og en drop-markør, bruges drop til + aflæsning, også når pickup står tættere på aflæsningstriggeren. Drop-markøren må højst stå 25 m + fra triggeren. Siloer bruger altid deres egen nærmeste markør. - **Markørnavne:** navnene er frie. Moden viser bygningens eget navn i menuen og markørens navn i parentes. diff --git a/docs/USER_MANUAL.md b/docs/USER_MANUAL.md index d59a17f..eea0509 100644 --- a/docs/USER_MANUAL.md +++ b/docs/USER_MANUAL.md @@ -1,6 +1,6 @@ # AD Smart Pickup — user manual -Version 1.18.4 · Farming Simulator 25 · add-on for AutoDrive +Version 1.18.5 · Farming Simulator 25 · add-on for AutoDrive *Dansk version: [BRUGERMANUAL.md](BRUGERMANUAL.md)* @@ -94,6 +94,9 @@ The marker must be at most **40 m** from the building's trigger. *Cow 1 Slurry*. The mod shows all of them next to the barn. - **Object storages (pallet sheds):** place the marker so the trailer's autoload zone covers the storage's output area, just like when you load by hand. +- **Separate drop and pickup:** if a factory has both a pickup and a drop marker, drop is used for + unloading, even when pickup is closer to the unloading trigger. The drop marker must be within + 25 m of the trigger. Silos always use their own nearest marker. - **Marker names:** names are free. The menu shows the building's own name and the marker's name. ### Wait points diff --git a/tests/test_adBuildings.lua b/tests/test_adBuildings.lua index cb3ad07..b142fb8 100644 --- a/tests/test_adBuildings.lua +++ b/tests/test_adBuildings.lua @@ -162,5 +162,29 @@ do check("B-SEP læssemarkør", bySep.sep1 and bySep.sep1.loadMarker and bySep.sep1.loadMarker.id, 41) end +-- B-DROP: fabrik med pickup-markør TÆT på aflæsningstriggeren og en separat drop-markør længere væk +-- (Sugarbeet Crusher): aflæsningsmarkøren skal være drop, ikke bygningens egen læssemarkør +do + local crusher = placeable("crusher1", "Sugarbeet Crusher", 8000, 0, {spec_productionPoint = {productionPoint = {productions = {}, storage = {}}}}) + table.insert(loadStations, {owningPlaceable = crusher, loadTriggers = {{triggerNode = {x = 8000, z = 5}}}}) + table.insert(unloadStations, {owningPlaceable = crusher, unloadTriggers = {{exactFillRootNode = {x = 8003, z = 2}}}}) + addMarker(51, "Sugar Beet Cut Pickup", "Fabrication", 8000, 8) -- 3 m fra læs, ~6 m fra aflæsning + addMarker(52, "Sugar Beet Cut Beet Drop", "Fabrication", 8012, 2) -- 9 m fra aflæsning + ADBuildings.invalidate() + local byC = {} + for _, b in ipairs(ADBuildings.list(adEnv, 1)) do byC[b.id] = b end + check("B-DROP læssemarkør = pickup", byC.crusher1.loadMarker.id, 51) + check("B-DROP aflæsningsmarkør = drop (ikke pickup)", byC.crusher1.unloadMarker.id, 52) + -- kun én fælles markør (AIO Load / Unload): bruges til begge + local aio = placeable("aio1", "AIO", 9000, 0, {spec_productionPoint = {productionPoint = {productions = {}, storage = {}}}}) + table.insert(loadStations, {owningPlaceable = aio, loadTriggers = {{triggerNode = {x = 9000, z = 5}}}}) + table.insert(unloadStations, {owningPlaceable = aio, unloadTriggers = {{exactFillRootNode = {x = 9002, z = 5}}}}) + addMarker(53, "AIO Load / Unload", "Fabrication", 9000, 9) + ADBuildings.invalidate() + for _, b in ipairs(ADBuildings.list(adEnv, 1)) do byC[b.id] = b end + check("B-DROP fælles markør bruges til aflæsning", byC.aio1.unloadMarker.id, 53) + check("B-DROP silo beholder sin egen markør (ikke nabosiloens)", byC.silo1.unloadMarker.id, 6) +end + print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL")) os.exit(failures == 0 and 0 or 1)