feat(lager): lagerture kan aflæsse i gårdens egne fabrikker der bruger varen som input (gylle -> biogasanlæg) (v1.17.6.0)

This commit is contained in:
2026-09-24 04:41:51 +02:00
parent 73e886ee26
commit b603bd7765
8 changed files with 57 additions and 13 deletions
+30 -3
View File
@@ -42,6 +42,33 @@ local function isSilo(station, homeStation)
and placeable.spec_productionPoint == nil and (homeStation == nil or placeable ~= homeStation.owningPlaceable) and placeable.spec_productionPoint == nil and (homeStation == nil or placeable ~= homeStation.owningPlaceable)
end end
local function usesAsInput(placeable, fillType)
local productionPoint = placeable.spec_productionPoint ~= nil and placeable.spec_productionPoint.productionPoint or nil
for _, production in ipairs(productionPoint ~= nil and productionPoint.productions or {}) do
for _, input in ipairs(production.inputs or {}) do
if input.type == fillType then return true end
end
end
return false
end
-- Lagermål: rene siloer; med allowFactories også gårdens EGNE fabrikker der bruger varen som input
-- (fx et biogasanlæg med gyllesilo). Stalde, fremmede anlæg og hjemmet (målet selv) aldrig.
function ADLoadSwap.isStoreTarget(station, fillType, homeStation, allowFactories)
if isSilo(station, homeStation) then
return true
end
local placeable = station.owningPlaceable
if not allowFactories or placeable == nil or placeable.spec_productionPoint == nil or placeable.getHusbandryFillLevel ~= nil then
return false
end
if homeStation ~= nil and placeable == homeStation.owningPlaceable then
return false
end
local owned = ADPrices ~= nil and ADPrices.isOwnedByPlayer ~= nil and ADPrices.isOwnedByPlayer(placeable)
return owned and usesAsInput(placeable, fillType)
end
local function acceptsRest(station, fillType, rest, farmId) local function acceptsRest(station, fillType, rest, farmId)
if station.getIsFillTypeSupported ~= nil and not station:getIsFillTypeSupported(fillType) then if station.getIsFillTypeSupported ~= nil and not station:getIsFillTypeSupported(fillType) then
return false return false
@@ -70,7 +97,7 @@ function ADLoadSwap.rankDumpCandidates(candidates, avoidMarkers)
return ranked return ranked
end end
function ADLoadSwap.findDumpMarker(adEnv, vehicle, fillType, rest, homeWayPointId, isReachable, excludedPlaceables, avoidMarkers) function ADLoadSwap.findDumpMarker(adEnv, vehicle, fillType, rest, homeWayPointId, isReachable, excludedPlaceables, avoidMarkers, allowFactories)
if vehicle.rootNode == nil then if vehicle.rootNode == nil then
return nil, "køretøjet har ingen position" return nil, "køretøjet har ingen position"
end end
@@ -82,7 +109,7 @@ function ADLoadSwap.findDumpMarker(adEnv, vehicle, fillType, rest, homeWayPointI
for _, marker in pairs(adEnv.ADGraphManager:getMapMarkers()) do for _, marker in pairs(adEnv.ADGraphManager:getMapMarkers()) do
local station = ADSmartPickup.getUnloadStationAtWayPointId(adEnv, marker.id, farmId) local station = ADSmartPickup.getUnloadStationAtWayPointId(adEnv, marker.id, farmId)
local isExcluded = excludedPlaceables ~= nil and excludedPlaceables[station ~= nil and station.owningPlaceable or false] == true local isExcluded = excludedPlaceables ~= nil and excludedPlaceables[station ~= nil and station.owningPlaceable or false] == true
if station ~= nil and isSilo(station, homeStation) and not isExcluded then if station ~= nil and ADLoadSwap.isStoreTarget(station, fillType, homeStation, allowFactories) and not isExcluded then
silos = silos + 1 silos = silos + 1
if acceptsRest(station, fillType, rest, farmId) then if acceptsRest(station, fillType, rest, farmId) then
withSpace = withSpace + 1 withSpace = withSpace + 1
@@ -105,7 +132,7 @@ function ADLoadSwap.findDumpMarker(adEnv, vehicle, fillType, rest, homeWayPointI
end end
end end
if silos == 0 then if silos == 0 then
return nil, "ingen silo med aflæsningsmarkør fundet (siloen skal have en AD-markør ved aflæsningstriggeren)" return nil, allowFactories and "ingen silo eller egen fabrik der bruger varen, med aflæsningsmarkør (sæt en AD-markør ved aflæsningstriggeren)" or "ingen silo med aflæsningsmarkør fundet (siloen skal have en AD-markør ved aflæsningstriggeren)"
elseif withSpace == 0 then elseif withSpace == 0 then
return nil, string.format("%d silo(er) fundet, men ingen tager varen med plads til %.0f l", silos, rest) return nil, string.format("%d silo(er) fundet, men ingen tager varen med plads til %.0f l", silos, rest)
end end
+3 -3
View File
@@ -201,7 +201,7 @@ local function findStoreMarker(adEnv, vehicle, product, capacity, sources, liter
end end
local liters = math.max(1, math.min(available, capacity or available)) local liters = math.max(1, math.min(available, capacity or available))
local avoid = ADRunsController ~= nil and ADRunsController.getPickupMarkers ~= nil and ADRunsController.getPickupMarkers() or nil local avoid = ADRunsController ~= nil and ADRunsController.getPickupMarkers ~= nil and ADRunsController.getPickupMarkers() or nil
local marker = ADLoadSwap.findDumpMarker(adEnv, vehicle, product.fillType, liters, nil, isReachable, ADSources.getSourcePlaceables(sources), avoid) local marker = ADLoadSwap.findDumpMarker(adEnv, vehicle, product.fillType, liters, nil, isReachable, ADSources.getSourcePlaceables(sources), avoid, true)
if marker == nil then if marker == nil then
return nil return nil
end end
@@ -479,8 +479,8 @@ function ADOutbound.choosePickup(adEnv, vehicle)
local runStatus = getStatus(run) local runStatus = getStatus(run)
runStatus.reasons = reasons runStatus.reasons = reasons
for _, reason in ipairs(reasons) do for _, reason in ipairs(reasons) do
if string.find(reason, ": ingen silo med plads", 1, true) then if string.find(reason, ": intet lager med plads", 1, true) then
warnOnce(adEnv, vehicle, "store:" .. reason, string.format("'%s' finder ingen silo med plads (%s)", tostring(ADRuns.vehicleLabel(vehicle)), reason)) warnOnce(adEnv, vehicle, "store:" .. reason, string.format("'%s' finder intet lager med plads (%s)", tostring(ADRuns.vehicleLabel(vehicle)), reason))
end end
end end
if trip == nil then if trip == nil then
+1 -1
View File
@@ -99,7 +99,7 @@ local function reasonFor(product, e, input)
return product.name .. ": intet nåeligt salgssted" return product.name .. ": intet nåeligt salgssted"
end end
if wantsStore(product.policy) and product.store == nil and (e.fullLoad or e.storageHigh) and not e.priceOk then if wantsStore(product.policy) and product.store == nil and (e.fullLoad or e.storageHigh) and not e.priceOk then
return product.name .. ": ingen silo med plads" return product.name .. ": intet lager med plads (silo eller egen fabrik der bruger varen)"
end end
local parts = {} local parts = {}
if wantsSell(product.policy) and e.percent ~= nil then if wantsSell(product.policy) and e.percent ~= nil then
+1 -1
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?> <?xml version="1.0" encoding="utf-8" standalone="no"?>
<modDesc descVersion="107"> <modDesc descVersion="107">
<author>masterdraco</author> <author>masterdraco</author>
<version>1.17.5.0</version> <version>1.17.6.0</version>
<title> <title>
<en>AD Smart Pickup</en> <en>AD Smart Pickup</en>
</title> </title>
+2 -2
View File
@@ -1,6 +1,6 @@
# AD Smart Pickup — brugermanual # AD Smart Pickup — brugermanual
Version 1.17.5 · Farming Simulator 25 · tillæg til AutoDrive Version 1.17.6 · Farming Simulator 25 · tillæg til AutoDrive
*English version: [USER_MANUAL.md](USER_MANUAL.md)* *English version: [USER_MANUAL.md](USER_MANUAL.md)*
@@ -282,7 +282,7 @@ Hver vare, kilderne har, står med sin mængde og nuværende pris. Vælg en poli
| Politik | Betydning | | Politik | Betydning |
|---|---| |---|---|
| **Fra** | Varen røres ikke | | **Fra** | Varen røres ikke |
| **Lager** | Køres til en silo eller et palleskur, når der er et fuldt læs, eller kilden er ved at være fuld | | **Lager** | Køres til en silo, et palleskur eller en af gårdens egne fabrikker, der bruger varen, fx gylle til et biogasanlæg. Det sker, når der er et fuldt læs, eller kilden er ved at være fuld |
| **Salg** | Sælges, når prisen er tæt nok på årets top | | **Salg** | Sælges, når prisen er tæt nok på årets top |
| **Salg, ellers lager** | Sælges ved god pris. Ellers køres den til lager, når kilden er ved at være fuld | | **Salg, ellers lager** | Sælges ved god pris. Ellers køres den til lager, når kilden er ved at være fuld |
+2 -2
View File
@@ -1,6 +1,6 @@
# AD Smart Pickup — user manual # AD Smart Pickup — user manual
Version 1.17.5 · Farming Simulator 25 · add-on for AutoDrive Version 1.17.6 · Farming Simulator 25 · add-on for AutoDrive
*Dansk version: [BRUGERMANUAL.md](BRUGERMANUAL.md)* *Dansk version: [BRUGERMANUAL.md](BRUGERMANUAL.md)*
@@ -286,7 +286,7 @@ Every good in the sources is listed with its amount and current price. Pick a po
| Policy | Meaning | | Policy | Meaning |
|---|---| |---|---|
| **Off** | The good is left alone | | **Off** | The good is left alone |
| **Store** | Taken to a silo or pallet shed when there is a full load, or the source is nearly full | | **Store** | Taken to a silo, a pallet shed or one of the farm's own factories that uses the good, such as slurry for a biogas plant. This happens when there is a full load, or the source is nearly full |
| **Sell** | Sold when the price is close enough to the yearly top | | **Sell** | Sold when the price is close enough to the yearly top |
| **Sell, else store** | Sold at a good price. Otherwise taken to storage when the source is nearly full | | **Sell, else store** | Sold at a good price. Otherwise taken to storage when the source is nearly full |
+17
View File
@@ -1,6 +1,7 @@
-- Kør: luajit tests/test_adLoadSwap.lua (fra repo-roden) -- Kør: luajit tests/test_adLoadSwap.lua (fra repo-roden)
-- Ren rangering af aflæsnings-siloer (lagermål for udkørsel og læs-bytte). -- Ren rangering af aflæsnings-siloer (lagermål for udkørsel og læs-bytte).
dofile("FS25_ADSmartPickup/adPrices.lua")
dofile("FS25_ADSmartPickup/adLoadSwap.lua") dofile("FS25_ADSmartPickup/adLoadSwap.lua")
local L = ADLoadSwap local L = ADLoadSwap
@@ -27,5 +28,21 @@ check("LS1 afhentning sidst (stadig mulig)", ranked[3].marker.id, 1)
local plain = L.rankDumpCandidates(candidates, nil) local plain = L.rankDumpCandidates(candidates, nil)
check("LS1 uden undgå-liste: har varen + nærmest", plain[1].marker.id, 1) check("LS1 uden undgå-liste: har varen + nærmest", plain[1].marker.id, 1)
-- LS2: lagermål — rene siloer altid; egne fabrikker der bruger varen som input kun når tilladt (udkørsel)
local SLURRY, MILK = 20, 21
g_currentMission = {getFarmId = function() return 1 end}
local biogas = {spec_productionPoint = {productionPoint = {productions = {{inputs = {{type = SLURRY, amount = 1}}}}}}, getOwnerFarmId = function() return 1 end}
local foreignBiogas = {spec_productionPoint = {productionPoint = {productions = {{inputs = {{type = SLURRY, amount = 1}}}}}}, getOwnerFarmId = function() return 0 end}
local silo = {spec_silo = {}}
local barn = {spec_silo = {}, getHusbandryFillLevel = function() return 0 end}
check("LS2 silo", L.isStoreTarget({owningPlaceable = silo}, SLURRY, nil, false), true)
check("LS2 stald aldrig", L.isStoreTarget({owningPlaceable = barn}, SLURRY, nil, true), false)
check("LS2 biogas kun når fabrikker tilladt", L.isStoreTarget({owningPlaceable = biogas}, SLURRY, nil, false), false)
check("LS2 biogas tager gylle", L.isStoreTarget({owningPlaceable = biogas}, SLURRY, nil, true), true)
check("LS2 biogas tager ikke mælk", L.isStoreTarget({owningPlaceable = biogas}, MILK, nil, true), false)
check("LS2 fremmed anlæg aldrig", L.isStoreTarget({owningPlaceable = foreignBiogas}, SLURRY, nil, true), false)
check("LS2 hjemmet selv aldrig", L.isStoreTarget({owningPlaceable = biogas}, SLURRY, {owningPlaceable = biogas}, true), false)
g_currentMission = nil
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL")) print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
os.exit(failures == 0 and 0 or 1) os.exit(failures == 0 and 0 or 1)
+1 -1
View File
@@ -69,7 +69,7 @@ check("P6 begrundelse", reasons6[1], "SUGAR: intet nåeligt salgssted")
-- P7: ingen silo med plads ved lagerbehov -- P7: ingen silo med plads ved lagerbehov
local trip7, reasons7 = P.plan(input({product("FORAGE", FORAGE, "store", {{wayPointId = 2, available = 3000000, level = 3000000, capacity = 3500000}}, nil, nil)})) local trip7, reasons7 = P.plan(input({product("FORAGE", FORAGE, "store", {{wayPointId = 2, available = 3000000, level = 3000000, capacity = 3500000}}, nil, nil)}))
check("P7 ingen tur", trip7, nil) check("P7 ingen tur", trip7, nil)
check("P7 begrundelse", reasons7[1], "FORAGE: ingen silo med plads") check("P7 begrundelse", reasons7[1], "FORAGE: intet lager med plads (silo eller egen fabrik der bruger varen)")
-- P8: runde, bulk: samme vare fra flere kilder, mest først -- P8: runde, bulk: samme vare fra flere kilder, mest først
local trip8 = P.plan(input({product("SUGAR", SUGAR, "sell", {{wayPointId = 1, available = 3000, level = 3000, capacity = 180000}, {wayPointId = 3, available = 9000, level = 9000, capacity = 180000}}, quoteS, nil)}, {collectRound = true, capacity = 10000})) local trip8 = P.plan(input({product("SUGAR", SUGAR, "sell", {{wayPointId = 1, available = 3000, level = 3000, capacity = 180000}, {wayPointId = 3, available = 9000, level = 9000, capacity = 180000}}, quoteS, nil)}, {collectRound = true, capacity = 10000}))