fix: æg-markør genkendes som hønsehus når det er nærmere end en løs læssestation (Pickup 1+2 blev Pigsty); palletildeling måler til hele spawn-området (alle rækker, start-slut) (v1.28.2.0)

This commit is contained in:
2026-09-26 11:52:22 +02:00
parent cb68c81a3f
commit 725ad7b459
4 changed files with 116 additions and 33 deletions
+1 -1
View File
@@ -257,7 +257,7 @@ function ADSmartPickup.getLoadStationNearWayPointId(adEnv, wayPointId, farmId, m
end
end
end
return best
return best, best ~= nil and bestDistance or nil
end
-- Siloens EGET indhold. Udvidelses-siloer (isExtension) deler lager med naboer
+74 -29
View File
@@ -24,10 +24,6 @@ local function getHusbandryPalletSpawners(placeable)
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
@@ -130,7 +126,8 @@ local function findPlaceableNear(wayPoint, farmId, predicate)
end
end
end
return best
-- (afstand i meter som 2. værdi)
return best, best ~= nil and math.sqrt(bestDistance) or nil
end
local function isObjectStorage(placeable)
@@ -177,9 +174,15 @@ function ADSources.identifyUncached(adEnv, wayPointId, farmId)
end
-- Det strenge opslag (trigger bag næsen) passer til silorækker; en mælketank eller fabrik ligger
-- ofte ved siden af markøren. Løst opslag inden for 40 m — men aldrig for siloer.
-- stald med egne pallespawnere (hønsehus: æg) — markøren står ved spawneren, ingen læssestation
local palletBarn, palletBarnDistance = findPlaceableNear(wayPoint, farmId, function(placeable) return placeable.getHusbandryFillLevel ~= nil and getHusbandryPalletSpawners(placeable) ~= nil end)
if placeable == nil and ADSmartPickup.getLoadStationNearWayPointId ~= nil then
local loose = ADSmartPickup.getLoadStationNearWayPointId(adEnv, wayPointId, farmId, ADSources.MAX_DISTANCE)
local loose, looseDistance = ADSmartPickup.getLoadStationNearWayPointId(adEnv, wayPointId, farmId, ADSources.MAX_DISTANCE)
local loosePlaceable = loose ~= nil and loose.owningPlaceable or nil
-- et nærmere hønsehus vinder over en fjernere læssestation (gyllestation 23 m fra "Æg Pickup 1")
if palletBarn ~= nil and looseDistance ~= nil and palletBarnDistance ~= nil and palletBarnDistance < looseDistance then
loosePlaceable = nil
end
if loosePlaceable ~= nil and loosePlaceable.spec_silo == nil then
if getProductionPoint(loosePlaceable) ~= nil then
return {kind = "factory", placeable = loosePlaceable, station = loose, wayPointId = wayPointId, name = getPlaceableName(loosePlaceable, markerName)}
@@ -188,8 +191,6 @@ function ADSources.identifyUncached(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
@@ -254,55 +255,99 @@ local function getPalletContent(vehicle)
return nil, 0
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).
-- Alle andre pallespawnere der kan lave varen (stalde med spawner for fillType, fabrikkers
-- pallespawner): {{x, z}, ...}. Står bygningerne tættere end PALLET_RADIUS (hønsehuse på række),
-- tilhører en palle den nærmeste spawner — ellers tæller et tomt hus naboernes paller med.
-- Spawnerens område som segmenter {ax, az, bx, bz}: hver spawnPlace fra start til slut (startNode/endNode,
-- eller PlacementUtil-felterne startX/startZ + dirX/dirZ*width). Et hønsehus har to rækker; måles kun
-- til første række, ligger den anden række tættere på naboens start end husets egen.
local function spawnerSegments(spawner)
local segments = {}
for _, place in ipairs(spawner ~= nil and spawner.spawnPlaces or {}) do
local ax, az = getNodePosition(place.startNode)
local bx, bz = getNodePosition(place.endNode)
if ax == nil and place.startX ~= nil and place.startZ ~= nil then
ax, az = place.startX, place.startZ
if place.dirX ~= nil and place.dirZ ~= nil and place.width ~= nil then
bx, bz = ax + place.dirX * place.width, az + place.dirZ * place.width
end
end
if ax ~= nil then table.insert(segments, {ax, az, bx or ax, bz or az}) end
end
return segments
end
-- Kvadreret afstand fra (x, z) til nærmeste punkt på et af segmenterne.
local function segmentsDistance2(segments, x, z)
local best = math.huge
for _, s in ipairs(segments) do
local ax, az, bx, bz = s[1], s[2], s[3], s[4]
local dx, dz = bx - ax, bz - az
local len2 = dx * dx + dz * dz
local t = len2 > 0 and math.max(0, math.min(1, ((x - ax) * dx + (z - az) * dz) / len2)) or 0
local d = distance2(x, z, ax + dx * t, az + dz * t)
if d < best then best = d end
end
return best
end
-- Alle pallespawnere der kan lave varen (stalde med spawner for fillType, fabrikkers pallespawner) som
-- {placeable, segments}. Står bygningerne tættere end PALLET_RADIUS (hønsehuse på række), tilhører en
-- palle den spawner hvis område er nærmest — ellers tæller et tomt hus naboernes paller med.
local function findRivalSpawners(fillType)
local rivals = {}
local placeables = g_currentMission ~= nil and g_currentMission.placeableSystem ~= nil and g_currentMission.placeableSystem.placeables or {}
for _, placeable in pairs(placeables) do
local husbandrySpawners = getHusbandryPalletSpawners(placeable)
local productionPoint = getProductionPoint(placeable)
local node = firstSpawnerNode(husbandrySpawners ~= nil and husbandrySpawners[fillType] or nil)
or firstSpawnerNode(productionPoint ~= nil and productionPoint.palletSpawner or nil)
local x, z = getNodePosition(node)
if x ~= nil then table.insert(rivals, {x = x, z = z}) end
local spawner = husbandrySpawners ~= nil and husbandrySpawners[fillType] or (productionPoint ~= nil and productionPoint.palletSpawner or nil)
local segments = spawnerSegments(spawner)
if #segments > 0 then table.insert(rivals, {placeable = placeable, segments = segments}) end
end
return rivals
end
local function isNearestSpawner(rivals, sx, sz, x, z)
local own = distance2(sx, sz, x, z)
local function isNearestSpawner(rivals, placeable, own, x, z)
for _, rival in ipairs(rivals) do
if distance2(rival.x, rival.z, x, z) < own then return false end
if rival.placeable ~= placeable and segmentsDistance2(rival.segments, x, z) < own then return false end
end
return true
end
local function getPalletsNearSpawner(placeable, fillType, farmId, spawnerNode)
ADSources.lastPalletNote = {}
-- Liter af varen på paller ved spawneren (pallespawneren tømmer lageret ud på jorden løbende, så
-- det er dér varen fysisk er). spawner = staldens spawner for varen; nil = fabrikkens pallespawner.
local function getPalletsNearSpawner(placeable, fillType, farmId, spawner)
local productionPoint = getProductionPoint(placeable)
local spawner = productionPoint ~= nil and productionPoint.palletSpawner or nil
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
local segments = spawnerSegments(spawner or (productionPoint ~= nil and productionPoint.palletSpawner or nil))
if #segments == 0 then
local rx, rz = getNodePosition(placeable.rootNode)
if rx == nil then return 0, 0 end
segments = {{rx, rz, rx, rz}}
end
local rivals = cacheGet("palletSpawners", fillType, 10000, function() return findRivalSpawners(fillType) end)
local vehicles = g_currentMission ~= nil and g_currentMission.vehicleSystem ~= nil and g_currentMission.vehicleSystem.vehicles or {}
local total, count = 0, 0
local total, count, lost = 0, 0, 0
local radius2 = ADSources.PALLET_RADIUS * ADSources.PALLET_RADIUS
for _, vehicle in pairs(vehicles) do
if isPalletVehicle(vehicle) and (vehicle.getOwnerFarmId == nil or vehicle:getOwnerFarmId() == farmId) then
local palletFillType, level = getPalletContent(vehicle)
local x, z = getNodePosition(vehicle.rootNode)
if palletFillType == fillType and x ~= nil and distance2(sx, sz, x, z) <= radius2 and isNearestSpawner(rivals, sx, sz, x, z) then
local own = (palletFillType == fillType and x ~= nil) and segmentsDistance2(segments, x, z) or math.huge
if own <= radius2 then
if isNearestSpawner(rivals, placeable, own, x, z) then
total = total + level
count = count + 1
else
lost = lost + 1
end
end
end
end
-- diagnose: paller inden for rækkevidde, men alle tildelt en nabo (højst én gang pr. minut pr. bygning)
local now = g_currentMission ~= nil and g_currentMission.time or nil
if count == 0 and lost > 0 and now ~= nil and (ADSources.lastPalletNote[placeable] or -math.huge) + 60000 < now then
ADSources.lastPalletNote[placeable] = now
Logging.info(ADSources.LOG_PREFIX .. "%s: %d paller inden for %d m tilhører nabo-spawnere (0 egne)", getPlaceableName(placeable, "?"), lost, ADSources.PALLET_RADIUS)
end
return total, count
end
@@ -434,7 +479,7 @@ 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 liters, count = getPalletsNearSpawner(source.placeable, fillType, farmId, 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
+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.28.1.0</version>
<version>1.28.2.0</version>
<title>
<en>AD Smart Pickup</en>
</title>
+38
View File
@@ -438,6 +438,31 @@ check("S14f tomt hus 0 paller", eggsAt(emptyCoop).palletCount, 0)
table.remove(g_currentMission.placeableSystem.placeables)
table.remove(g_currentMission.placeableSystem.placeables)
-- S14g: spawnerens område er ALLE rækker fra start til slut — ikke kun første rækkes start. Hus A's
-- række 2 slutter tæt på hus B's start; en palle for enden af A's række 2 er stadig A's.
local rowA = {spawnPlaces = {{startNode = {x = 9000, z = 0}, endNode = {x = 9008, z = 0}}, {startNode = {x = 9000, z = 3}, endNode = {x = 9008, z = 3}}}}
local rowB = {spawnPlaces = {{startNode = {x = 9014, z = 3}, endNode = {x = 9022, z = 3}}}}
local function rowCoop(spawner, x)
return {rootNode = {x = x, z = -10}, ownerFarmId = 1, getOwnerFarmId = function() return 1 end, getName = function() return "Chicken Coop" end,
getHusbandryFillLevel = function() return 0 end,
spec_husbandryPallets = {fillTypeIndexToPalletSpawner = {[EGGS] = spawner}, activeFillTypes = {EGGS}, fillLevels = {[EGGS] = 0}, capacities = {[EGGS] = 5000}}}
end
local coopA, coopB = rowCoop(rowA, 9004), rowCoop(rowB, 9018)
table.insert(g_currentMission.placeableSystem.placeables, coopA)
table.insert(g_currentMission.placeableSystem.placeables, coopB)
addPallet(EGGS, 1000, 9008, 3) -- enden af A's række 2: 6 m til B's start, 8 m til A's første start
check("S14g palle for enden af egen række 2 er husets egen", eggsAt(coopA).available, 1000)
check("S14g naboen får den ikke", eggsAt(coopB).available, 0)
-- PlacementUtil-form (startX/startZ + dirX/dirZ*width) i stedet for noder
local placeC = {spawnPlaces = {{startX = 9000, startZ = 50, dirX = 1, dirZ = 0, width = 8}}}
local coopC = rowCoop(placeC, 9004)
table.insert(g_currentMission.placeableSystem.placeables, coopC)
addPallet(EGGS, 700, 9007, 51)
check("S14g PlacementUtil-plads tæller", eggsAt(coopC).available, 700)
table.remove(g_currentMission.placeableSystem.placeables)
table.remove(g_currentMission.placeableSystem.placeables)
table.remove(g_currentMission.placeableSystem.placeables)
-- 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")
@@ -457,6 +482,19 @@ looseAt[13] = siloStation
check("S16 silo aldrig via løst opslag", ADSources.identify(adEnv, 13, 1), nil)
check("S16 forklaring nævner den løse station", ADSources.explainMarker(adEnv, 13, 1):find("silo", 1, true) ~= nil, true)
-- S16b: "Æg Pickup 1" står 12 m fra hønsehusets palleområde og 23 m fra svinestaldens gyllestation;
-- det nærmeste vinder (in-game 26/9: Pickup 1+2 blev genkendt som Pigsty og æggene aldrig hentet)
local looseDistance = {}
ADSmartPickup.getLoadStationNearWayPointId = function(_, id, farmId, maxDistance) return looseAt[id], looseDistance[id] end
local pigStation = {owningPlaceable = cowBarn}
addMarker(14, "Æg Pickup 1", 8000, 12)
looseAt[14], looseDistance[14] = pigStation, 23
local eggSource = ADSources.identify(adEnv, 14, 1)
check("S16b hønsehuset vinder over fjernere gyllestation", eggSource and eggSource.placeable, coop)
addMarker(15, "Slurry ved hønsehus", 8000, 30)
looseAt[15], looseDistance[15] = pigStation, 5
check("S16b nærmere gyllestation vinder stadig", ADSources.identify(adEnv, 15, 1).placeable, cowBarn)
-- S17: stald med ÉN station og TO læssepunkter (mælk i den ene ende, gylle i den anden): hver markør
-- giver kun de varer dens nærmeste læssepunkt udleverer (in-game 24/9, LargerAnimalBarns cowBarnBig)
local SLURRY = 13