From 793f792f8b7c53176ad7ba3bdc6a17cf955ab695 Mon Sep 17 00:00:00 2001 From: masterdraco Date: Tue, 29 Sep 2026 15:20:48 +0200 Subject: [PATCH] =?UTF-8?q?fix(forsyning):=20mindst=20fyldte=20kilde=20f?= =?UTF-8?q?=C3=B8rst=20kun=20blandt=20kilder=20med=20>=3D=2025=20%=20af=20?= =?UTF-8?q?et=20l=C3=A6s=20(ellers=20fyldeste)=20=E2=80=94=20foder-traktor?= =?UTF-8?q?er=20hentede=202-10k=20l=20i=20en=20g=C3=A6ringssilo=20der=20fy?= =?UTF-8?q?ldes=20l=C3=B8bende;=20knappen=20viser=20Start=20for=20et=20flo?= =?UTF-8?q?w=20der=20aldrig=20kom=20i=20gang,=20selv=20med=20vogn=20p?= =?UTF-8?q?=C3=A5=20(v1.57.0.0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FS25_ADSmartPickup/adFlowWagons.lua | 5 ++++- FS25_ADSmartPickup/adSmartPickup.lua | 20 ++++++++++++++------ FS25_ADSmartPickup/adSupplyPlanner.lua | 21 +++++++++++++++++++-- FS25_ADSmartPickup/modDesc.xml | 2 +- tests/test_adSmartPickup.lua | 7 ++++--- tests/test_adSupplyPlanner.lua | 11 +++++++++++ 6 files changed, 53 insertions(+), 13 deletions(-) diff --git a/FS25_ADSmartPickup/adFlowWagons.lua b/FS25_ADSmartPickup/adFlowWagons.lua index 98fa470..79f41a1 100644 --- a/FS25_ADSmartPickup/adFlowWagons.lua +++ b/FS25_ADSmartPickup/adFlowWagons.lua @@ -193,7 +193,10 @@ end function ADFlowWagons.hasActivity(run, vehiclesById) for _, vehicleId in ipairs(run.vehicleIds or {}) do local vehicle = vehiclesById ~= nil and vehiclesById[vehicleId] or nil - if vehicle ~= nil and (waiting[vehicle] ~= nil or fetching[vehicle] ~= nil or #ADHitch.rearImplementsOf(vehicle) > 0) then + -- vogn bagpå tæller kun i et flow der er startet: et flow der aldrig kom i gang (fx 'ingen vogn', og spilleren + -- har selv koblet på) skal vise Start, ikke Stop (in-game 29/9: Milk Store) + local holdsWagon = vehicle ~= nil and ADRunsController.runningRuns[run.id] == true and #ADHitch.rearImplementsOf(vehicle) > 0 + if vehicle ~= nil and (waiting[vehicle] ~= nil or fetching[vehicle] ~= nil or holdsWagon) then return true end end diff --git a/FS25_ADSmartPickup/adSmartPickup.lua b/FS25_ADSmartPickup/adSmartPickup.lua index 2ebfeb7..48915b7 100644 --- a/FS25_ADSmartPickup/adSmartPickup.lua +++ b/FS25_ADSmartPickup/adSmartPickup.lua @@ -372,18 +372,26 @@ end -- Bedste kilde der har varen: mindst fyldte først for lagervarer, fyldeste først for -- varer hvis tanke løber fulde (ADSupplyPlanner). Siloer med varen i EGET lager går -- altid forud for dem der kun kan låne fra naboer. Returnerer et valg eller nil. -local function findBestSource(markerStations, fillTypes, farmId) +local getLoadCapacity -- defineret længere nede (læs-kapacitet til kildevalget) + +local function findBestSource(markerStations, fillTypes, farmId, loadCapacity) local prefersFullest = ADSupplyPlanner.prefersFullestSource(getFillTypeNames(fillTypes)) + local ample = ADSupplyPlanner.ampleLevel(loadCapacity) local best = {[true] = {}, [false] = {}} for _, entry in ipairs(markerStations) do local level, isOwn = getStationFillLevel(entry.station, fillTypes, farmId) if level >= ADSmartPickup.MIN_USEFUL_LITERS and not isProtectedProductionInput(entry.station, fillTypes) - and ADSupplyPlanner.isBetterSource(level, best[isOwn].level, prefersFullest) then + and ADSupplyPlanner.isBetterSource(level, best[isOwn].level, prefersFullest, ample) then best[isOwn] = {level = level, marker = entry.marker, station = entry.station, isOwn = isOwn} end end - local choice = best[true].marker ~= nil and best[true] or best[false] + -- eget lager går forud — men ikke en næsten tom egen tank frem for et rigeligt nabolager + local own, other = best[true], best[false] + local choice = own + if own.marker == nil or (not prefersFullest and other.marker ~= nil and own.level < ample and other.level >= ample) then + choice = other + end if choice.marker == nil then return nil end @@ -412,7 +420,7 @@ function ADSmartPickup.findLeastFilledPickup(adEnv, driver) return nil end local groupMarkers = adEnv.ADGraphManager:getMapMarkersInGroup(firstMarker.group) - return findBestSource(collectMarkerStations(adEnv, groupMarkers, farmId, nil), fillTypes, farmId) + return findBestSource(collectMarkerStations(adEnv, groupMarkers, farmId, nil), fillTypes, farmId, getLoadCapacity(adEnv, driver)) end -- Lagrene bag aflæsningsstationen; produktionspunkter uden targetStorages læses direkte. @@ -719,7 +727,7 @@ function ADSmartPickup.getTargetNeedsRanked(station, fillTypes, farmId, pending) end -- Vognens samlede kapacitet (liter); nil hvis AutoDrive ikke kan opgøre den. -local function getLoadCapacity(adEnv, driver) +getLoadCapacity = function(adEnv, driver) if adEnv.AutoDrive.getAllUnits == nil or adEnv.AutoDrive.getAllFillLevels == nil then return nil end @@ -787,7 +795,7 @@ function ADSmartPickup.findSupplyPickup(adEnv, driver, ingredients, targetWayPoi -- bedste foder først: lavere foder kun når truget er nødlidende (ADSupplyPlanner.isFoodAllowed) local bestFood = ADSupplyPlanner.bestFoodPriority ~= nil and ADSupplyPlanner.bestFoodPriority(ranked) or nil for _, need in ipairs(ranked) do - local choice = (ADSupplyPlanner.isFoodAllowed == nil or ADSupplyPlanner.isFoodAllowed(need, bestFood)) and findBestSource(markerStations, {need.fillType}, farmId) or nil + local choice = (ADSupplyPlanner.isFoodAllowed == nil or ADSupplyPlanner.isFoodAllowed(need, bestFood)) and findBestSource(markerStations, {need.fillType}, farmId, loadCapacity) or nil if choice ~= nil then return { markerIndex = choice.markerIndex, diff --git a/FS25_ADSmartPickup/adSupplyPlanner.lua b/FS25_ADSmartPickup/adSupplyPlanner.lua index 570c590..111f5fe 100644 --- a/FS25_ADSmartPickup/adSupplyPlanner.lua +++ b/FS25_ADSmartPickup/adSupplyPlanner.lua @@ -29,15 +29,32 @@ function ADSupplyPlanner.prefersFullestSource(fillTypeNames) return true end +-- "Rigelig" kilde: kan levere mindst MIN_LOAD_SHARE af et læs (mindst MIN_AMPLE_LITERS). +ADSupplyPlanner.MIN_LOAD_SHARE = 0.25 +ADSupplyPlanner.MIN_AMPLE_LITERS = 5000 + +function ADSupplyPlanner.ampleLevel(loadCapacity) + return math.max(ADSupplyPlanner.MIN_AMPLE_LITERS, (loadCapacity or 0) * ADSupplyPlanner.MIN_LOAD_SHARE) +end + -- Er en kilde med dette niveau bedre end den hidtil bedste (nil = ingen endnu)? -function ADSupplyPlanner.isBetterSource(level, bestLevel, prefersFullest) +-- Lagervarer: mindst fyldte først, men kun blandt rigelige kilder — en næsten tom tank der fyldes løbende +-- (gæringssilo) ville ellers altid vinde og give et par tusind liter pr. tur (in-game 29/9). Ingen rigelige: +-- den fyldeste. ample = nil: gammel regel. +function ADSupplyPlanner.isBetterSource(level, bestLevel, prefersFullest, ample) if bestLevel == nil then return true end if prefersFullest then return level > bestLevel end - return level < bestLevel + if ample == nil then + return level < bestLevel + end + local isAmple, bestIsAmple = level >= ample, bestLevel >= ample + if isAmple ~= bestIsAmple then return isAmple end + if isAmple then return level < bestLevel end + return level > bestLevel end function ADSupplyPlanner.copyList(list) diff --git a/FS25_ADSmartPickup/modDesc.xml b/FS25_ADSmartPickup/modDesc.xml index d4cd4ba..1baeac4 100644 --- a/FS25_ADSmartPickup/modDesc.xml +++ b/FS25_ADSmartPickup/modDesc.xml @@ -1,7 +1,7 @@ masterdraco - 1.56.5.0 + 1.57.0.0 <en>AD Smart Pickup</en> diff --git a/tests/test_adSmartPickup.lua b/tests/test_adSmartPickup.lua index 9ed925a..3832fc6 100644 --- a/tests/test_adSmartPickup.lua +++ b/tests/test_adSmartPickup.lua @@ -206,9 +206,10 @@ check("markør uden nær silo ignoreres", manager:getNextPickup(makeDriver(marke -- 4: flere valgte varer lægges sammen resetWorld() -addMarker(1, "Silo 1", "Siloer", 0, 0); table.insert(stations, makeStation(101, 0, 15, {[SUGARBEET] = 100, [WHEAT] = 5000})) -addMarker(2, "Silo 2", "Siloer", 500, 0); table.insert(stations, makeStation(102, 500, 15, {[SUGARBEET] = 3000})) -check("flere varetyper summeres", manager:getNextPickup(makeDriver(markers[1], {SUGARBEET, WHEAT}), false), 2) +-- summeret er silo 1 rigelig (6000 >= 5000) og vinder; uden summering var den 3000 og taber til silo 2's 4000 +addMarker(1, "Silo 1", "Siloer", 0, 0); table.insert(stations, makeStation(101, 0, 15, {[SUGARBEET] = 3000, [WHEAT] = 3000})) +addMarker(2, "Silo 2", "Siloer", 500, 0); table.insert(stations, makeStation(102, 500, 15, {[SUGARBEET] = 4000})) +check("flere varetyper summeres", manager:getNextPickup(makeDriver(markers[1], {SUGARBEET, WHEAT}), false), 1) -- 4b: klynge med delt lager — eget indhold slår nabo-sum, også når nabo-summen er mindre resetWorld() diff --git a/tests/test_adSupplyPlanner.lua b/tests/test_adSupplyPlanner.lua index 710857c..3121bba 100644 --- a/tests/test_adSupplyPlanner.lua +++ b/tests/test_adSupplyPlanner.lua @@ -251,5 +251,16 @@ check("CF vare uden for run'et -> nil", ADSupplyPlanner.cargoFor(HAY, 5000, {SIL check("CF tom vogn -> nil", ADSupplyPlanner.cargoFor(SILAGE, 0, {SILAGE}), nil) check("CF ukendt vare -> nil", ADSupplyPlanner.cargoFor(nil, 5000, {SILAGE}), nil) +-- kilde med nok til et rigtigt læs: mindst fyldte først kun blandt kilder med >= 25 % af et læs; ellers fyldeste +-- (in-game 29/9: 4 foder-traktorer hentede 2-10k l i en gæringssilo der løbende fyldes, og kørte "tomme") +local SP = ADSupplyPlanner +check("kilde-grænse: 25 % af læsset", SP.ampleLevel(1000000), 250000) +check("kilde-grænse: ukendt læs -> kun minimum", SP.ampleLevel(nil), SP.MIN_AMPLE_LITERS) +check("kilde-grænse: lille vogn -> mindst minimum", SP.ampleLevel(10000), SP.MIN_AMPLE_LITERS) +check("vælg: næsten tom taber til rigelig", SP.isBetterSource(10000, 12000000, false, 250000), false) +check("vælg: blandt rigelige mindst fyldte", SP.isBetterSource(300000, 12000000, false, 250000), true) +check("vælg: ingen rigelige -> fyldeste", SP.isBetterSource(9000, 2000, false, 250000), true) +check("vælg: løber-fuld-varer uændret (fyldeste)", SP.isBetterSource(12000000, 300000, true, 250000), true) +check("vælg: første kandidat", SP.isBetterSource(10, nil, false, 250000), true) print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL")) os.exit(failures == 0 and 0 or 1)