feat(stald): æg/uld-paller fra staldens egne pallespawnere (hønsehus) som udkørselskilde; brændstoftanke er ikke lager-kilder (v1.18.8.0)

This commit is contained in:
2026-09-24 19:24:36 +02:00
parent 6d25478783
commit b3d49c4857
7 changed files with 129 additions and 11 deletions
+30 -1
View File
@@ -104,6 +104,19 @@ local function collectNodes(placeable, loadStations, unloadStations)
end
if #nodes > 0 then table.insert(loadGroups, nodes) end
end
-- stald med egne pallespawnere (hønsehus: æg, fårestald: uld) — én læssegruppe pr. spawner
local husbandryPallets = placeable.spec_husbandryPallets
local seenSpawners = {}
for _, palletSpawner in pairs(husbandryPallets ~= nil and husbandryPallets.fillTypeIndexToPalletSpawner or {}) do
if not seenSpawners[palletSpawner] then
seenSpawners[palletSpawner] = true
local nodes = {}
for _, place in ipairs(palletSpawner.spawnPlaces or {}) do
if place.startNode ~= nil then table.insert(nodes, place.startNode) end
end
if #nodes > 0 then table.insert(loadGroups, nodes) end
end
end
if placeable.spec_objectStorage ~= nil and placeable.rootNode ~= nil then
table.insert(loadGroups, {placeable.rootNode})
table.insert(unloadNodes, placeable.rootNode)
@@ -249,9 +262,25 @@ local function isSellPlaceable(placeable, unloadStations)
return false
end
-- Brændstof er ikke en vare der køres rundt (gårdens tankanlæg har en læssestation til diesel).
local FUEL_FILL_TYPES = {DIESEL = true, DEF = true, ELECTRICCHARGE = true, METHANE = true}
local function isFuelOnly(station)
local supported = station.supportedFillTypes
if supported == nil or next(supported) == nil or g_fillTypeManager == nil then
return false
end
for fillType, isSupported in pairs(supported) do
if isSupported and not FUEL_FILL_TYPES[tostring(g_fillTypeManager:getFillTypeNameByIndex(fillType))] then
return false
end
end
return true
end
local function hasOwnLoadingStation(placeable, loadStations)
for _, station in pairs(loadStations) do
if station.owningPlaceable == placeable then return true end
if station.owningPlaceable == placeable and not isFuelOnly(station) then return true end
end
return false
end
+46 -5
View File
@@ -11,6 +11,17 @@ ADSources.MAX_DISTANCE = 40
-- Paller der står inden for denne afstand af fabrikkens pallespawner tæller som fabrikkens output.
ADSources.PALLET_RADIUS = 25
-- Staldens egne pallespawnere (hønsehus: æg, fårestald: uld): {[fillType] = spawner}.
local function getHusbandryPalletSpawners(placeable)
local spec = placeable ~= nil and placeable.spec_husbandryPallets or nil
return spec ~= nil and spec.fillTypeIndexToPalletSpawner or nil
end
local function firstSpawnerNode(spawner)
return spawner ~= nil and spawner.spawnPlaces ~= nil and spawner.spawnPlaces[1] ~= nil and spawner.spawnPlaces[1].startNode or nil
end
local function distance2(ax, az, bx, bz)
local dx, dz = ax - bx, az - bz
return dx * dx + dz * dz
@@ -63,7 +74,10 @@ end
-- Palle eller bulk ved DENNE kilde: silo = bulk; objektlager = palle; fabrik = bulk hvis
-- markørens læssestation udleverer varen, ellers palle hvis varen er en palletype.
function ADSources.isPalletAt(source, fillType)
if source.kind == "silo" or source.kind == "husbandry" then
if source.kind == "husbandry" then
local spawners = getHusbandryPalletSpawners(source.placeable)
return spawners ~= nil and spawners[fillType] ~= nil
elseif source.kind == "silo" then
return false
elseif source.kind == "objectStorage" then
return true
@@ -76,11 +90,14 @@ function ADSources.isPalletAt(source, fillType)
return ADSources.isPalletFillType(fillType)
end
-- Placeable'ns "nærmeste punkt" for kildegenkendelse: pallespawnerens første plads (fabrik)
-- eller rodnoden.
-- Placeable'ns "nærmeste punkt" for kildegenkendelse: pallespawnerens første plads (fabrik,
-- stald med paller) eller rodnoden.
local function getPlaceableAnchor(placeable)
local productionPoint = getProductionPoint(placeable)
local spawner = productionPoint ~= nil and productionPoint.palletSpawner or nil
if spawner == nil then
for _, husbandrySpawner in pairs(getHusbandryPalletSpawners(placeable) or {}) do spawner = husbandrySpawner break end
end
local place = spawner ~= nil and spawner.spawnPlaces ~= nil and spawner.spawnPlaces[1] or nil
local node = place ~= nil and place.startNode or placeable.rootNode
local x, z = getNodePosition(node)
@@ -158,6 +175,11 @@ function ADSources.identify(adEnv, wayPointId, farmId)
end
end
end
-- stald med egne pallespawnere (hønsehus: æg) — markøren står ved spawneren, ingen læssestation
local palletBarn = findPlaceableNear(wayPoint, farmId, function(placeable) return placeable.getHusbandryFillLevel ~= nil and getHusbandryPalletSpawners(placeable) ~= nil end)
if palletBarn ~= nil then
return {kind = "husbandry", placeable = palletBarn, station = nil, wayPointId = wayPointId, name = getPlaceableName(palletBarn, markerName)}
end
-- Rene pallefabrikker (halmvarer, bageri ...) har ingen læssestation: find dem på afstand
-- til pallespawneren; dernæst objektlagre.
local factory = findPlaceableNear(wayPoint, farmId, isProductionPoint)
@@ -221,10 +243,10 @@ end
-- Liter af varen på paller der står ved fabrikkens spawner (pallespawneren tømmer lageret
-- ud på jorden løbende, så det er dér varen fysisk er).
local function getPalletsNearSpawner(placeable, fillType, farmId)
local function getPalletsNearSpawner(placeable, fillType, farmId, spawnerNode)
local productionPoint = getProductionPoint(placeable)
local spawner = productionPoint ~= nil and productionPoint.palletSpawner or nil
local node = spawner ~= nil and spawner.spawnPlaces ~= nil and spawner.spawnPlaces[1] ~= nil and spawner.spawnPlaces[1].startNode or placeable.rootNode
local node = spawnerNode or (spawner ~= nil and spawner.spawnPlaces ~= nil and spawner.spawnPlaces[1] ~= nil and spawner.spawnPlaces[1].startNode) or placeable.rootNode
local sx, sz = getNodePosition(node)
if sx == nil then
return 0
@@ -369,8 +391,27 @@ local function getNearestTriggerFillTypes(adEnv, source)
return #list > 0 and list or nil
end
local function getHusbandryPalletProducts(source, farmId)
local products = {}
local spec = source.placeable.spec_husbandryPallets
for fillType, spawner in pairs(getHusbandryPalletSpawners(source.placeable) or {}) do
local liters, count = getPalletsNearSpawner(source.placeable, fillType, farmId, firstSpawnerNode(spawner))
local capacity = spec ~= nil and spec.capacities ~= nil and spec.capacities[fillType] or 0
local product = newProduct(fillType, liters, liters, math.max(capacity or 0, liters), true)
product.palletLiters, product.palletCount = liters, count
table.insert(products, product)
end
table.sort(products, function(a, b) return a.fillType < b.fillType end)
return products
end
local function getHusbandryProducts(adEnv, source)
local placeable, station = source.placeable, source.station
local farmId = g_currentMission ~= nil and g_currentMission.getFarmId ~= nil and g_currentMission:getFarmId() or 1
if station == nil then
-- kilde via staldens pallespawner (hønsehus: æg): kun pallevarerne
return getHusbandryPalletProducts(source, farmId)
end
local fillTypes = getNearestTriggerFillTypes(adEnv, source) or {}
if #fillTypes == 0 then
for fillType, supported in pairs(station ~= nil and station.supportedFillTypes or {}) do
+1 -1
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<modDesc descVersion="107">
<author>masterdraco</author>
<version>1.18.7.0</version>
<version>1.18.8.0</version>
<title>
<en>AD Smart Pickup</en>
</title>
+2 -2
View File
@@ -1,6 +1,6 @@
# AD Smart Pickup — brugermanual
Version 1.18.7 · Farming Simulator 25 · tillæg til AutoDrive
Version 1.18.8 · Farming Simulator 25 · tillæg til AutoDrive
*English version: [USER_MANUAL.md](USER_MANUAL.md)*
@@ -285,7 +285,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, inklusive tilknyttede udvidelsestanke som Milk Tank Extension |
| **Stald** | Mælk, gylle og gødning fra staldens læssepunkter, inklusive tilknyttede udvidelsestanke som Milk Tank Extension. Æg og uld hentes som paller ved staldens pallespawner, fx i hønsehuset. Sæt en markør ved spawneren |
| **Objektlager** | Paller og baller. De tages ud én ad gangen |
| **Lager** | Andre bygninger med en læssestation, fx Pumps & Hoses' separatorhal med digestat. Varerne læses fra læssestationen |
+2 -2
View File
@@ -1,6 +1,6 @@
# AD Smart Pickup — user manual
Version 1.18.7 · Farming Simulator 25 · add-on for AutoDrive
Version 1.18.8 · Farming Simulator 25 · add-on for AutoDrive
*Dansk version: [BRUGERMANUAL.md](BRUGERMANUAL.md)*
@@ -288,7 +288,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, including attached extension tanks such as Milk Tank Extension |
| **Barn** | Milk, slurry and manure from the barn's loading points, including attached extension tanks such as Milk Tank Extension. Eggs and wool are collected as pallets at the barn's pallet spawner, such as the chicken coop's. Place a marker at the spawner |
| **Object storage** | Pallets and bales. They are taken out one at a time |
| **Storage** | Other buildings with a loading station, such as the Pumps & Hoses separator hall with digestate. The goods are read from the loading station |
+27
View File
@@ -186,5 +186,32 @@ do
check("B-DROP silo beholder sin egen markør (ikke nabosiloens)", byC.silo1.unloadMarker.id, 6)
end
-- B-COOP: hønsehus — foder aflæsses i den ene ende, æg-paller spawnes i den anden (ingen læssestation)
do
local coop = placeable("coop1", "Chicken Coop", 10000, 0, {getHusbandryFillLevel = function() return 0 end,
spec_husbandryPallets = {fillTypeIndexToPalletSpawner = {[99] = {spawnPlaces = {{startNode = {x = 10030, z = 0}}}}}}})
table.insert(unloadStations, {owningPlaceable = coop, unloadTriggers = {{exactFillRootNode = {x = 9970, z = 0}}}})
addMarker(61, "Chicken Food", "Chicken", 9965, 0)
addMarker(62, "Egg Pickup", "Chicken", 10035, 0)
ADBuildings.invalidate()
local byCoop = {}
for _, b in ipairs(ADBuildings.list(adEnv, 1)) do byCoop[b.id] = b end
check("B-COOP læssemarkør ved æggene", byCoop.coop1.loadMarker and byCoop.coop1.loadMarker.id, 62)
check("B-COOP aflæsningsmarkør ved foderet", byCoop.coop1.unloadMarker and byCoop.coop1.unloadMarker.id, 61)
end
-- B-FUEL: brændstoftank (læssestation kun med DIESEL) er ikke et lager/en kilde
do
local fmBefore = g_fillTypeManager
g_fillTypeManager = {getFillTypeNameByIndex = function(_, index) return index == 900 and "DIESEL" or "X" end}
local tank = placeable("fuel1", "Small Petrol Tank", 11000, 0, {})
table.insert(loadStations, {owningPlaceable = tank, supportedFillTypes = {[900] = true}, loadTriggers = {{triggerNode = {x = 11000, z = 3}}}})
ADBuildings.invalidate()
local byFuel = {}
for _, b in ipairs(ADBuildings.list(adEnv, 1)) do byFuel[b.id] = b end
check("B-FUEL brændstoftank udeladt", byFuel.fuel1, nil)
g_fillTypeManager = fmBefore
end
print(failures == 0 and "\nALLE TESTS OK" or ("\n" .. failures .. " FEJL"))
os.exit(failures == 0 and 0 or 1)
+21
View File
@@ -389,6 +389,27 @@ local sepProducts = sepSource and ADSources.getProducts(adEnv, sepSource, 1) or
check("S14d digestat fra stationen", sepProducts[1] and sepProducts[1].fillType, DIGESTATE)
check("S14d mængde", sepProducts[1] and sepProducts[1].level, 42000)
-- S14e: hønsehus — æg kommer som PALLER fra staldens egen pallespawner (spec_husbandryPallets), ingen
-- læssestation ved æggene: markøren ved spawneren er en staldkilde, æggene er pallevarer
local EGGS = 31
DESC[EGGS] = {index = EGGS, name = "EGG", title = "Æg", isPallet = true}
local coopSpawner = {spawnPlaces = {{startNode = {x = 8000, z = 0}}}}
local coop = {rootNode = {x = 8040, z = 0}, ownerFarmId = 1, getOwnerFarmId = function() return 1 end, getName = function() return "Chicken Coop" end,
getHusbandryFillLevel = function() return 0 end,
spec_husbandryPallets = {fillTypeIndexToPalletSpawner = {[EGGS] = coopSpawner}, activeFillTypes = {EGGS}, fillLevels = {[EGGS] = 0}, capacities = {[EGGS] = 5000}}}
table.insert(g_currentMission.placeableSystem.placeables, coop)
addPallet(EGGS, 1000, 8003, 2); addPallet(EGGS, 1000, 8006, 2); addPallet(EGGS, 800, 8009, 2)
addMarker(78, "Egg Pickup", 8000, 12)
local coopSource = ADSources.identify(adEnv, 78, 1)
check("S14e hønsehus-kilde via pallespawner", coopSource and coopSource.kind, "husbandry")
local coopProducts = coopSource and ADSources.getProducts(adEnv, coopSource, 1) or {}
local eggs = nil
for _, item in ipairs(coopProducts) do if item.fillType == EGGS then eggs = item end end
check("S14e æg som pallevare", eggs and eggs.isPallet, true)
check("S14e æg på paller ved spawneren", eggs and eggs.available, 2800)
check("S14e tre paller", eggs and eggs.palletCount, 3)
check("S14e isPalletAt æg", coopSource and ADSources.isPalletAt(coopSource, EGGS), true)
-- S15: forklaring af en markør til advarslen (hvad opslaget ser)
check("S15 forklaring stald", ADSources.explainMarker(adEnv, 10, 1), "læssestation ved markøren hører til 'Kostald' (stald)")
check("S15 forklaring ingen station", ADSources.explainMarker(adEnv, 4, 1), "ingen læssestation ved markøren, og ingen fabrik/objektlager inden for 40 m")