feat: fabriksstyret forsyning — målets tændte produktioner styrer ingredienslisten (v1.6.0.0)
Er aflæsningsmålet et produktionspunkt, erstattes ingredienslisten af inputs fra ønskede produktioner (tændte, eller auto-slukkede af kortet med status MISSING_INPUTS — Dakotas ExtendedProductionPoint), begrænset til det vognen kan bære. Brugerens multi-valg er kun tændknappen og gendannes ved stop som hidtil. Prioritet: tid til tom = lager / (Σ amount × cyclesPerMinute); varer med kendt forbrug scorer i ]1,2] og går altid forud for relativ tomhed [0,1]. Loggen viser forbrug og minutter; fabrik uden ønskede produktioner logges én gang. API-navne verificeret mod EasyDevControls + Dakota16x ExtendedProductionPoint.
This commit is contained in:
@@ -250,21 +250,81 @@ function ADSmartPickup.findLeastFilledPickup(adEnv, driver)
|
||||
return findBestSource(collectMarkerStations(adEnv, groupMarkers, farmId, nil), fillTypes, farmId)
|
||||
end
|
||||
|
||||
local function getProductionPoint(station)
|
||||
local placeable = station.owningPlaceable
|
||||
if placeable ~= nil and placeable.spec_productionPoint ~= nil then
|
||||
return placeable.spec_productionPoint.productionPoint
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Lagrene bag aflæsningsstationen; produktionspunkter uden targetStorages læses direkte.
|
||||
local function getTargetStorages(station)
|
||||
if station.targetStorages ~= nil and next(station.targetStorages) ~= nil then
|
||||
return station.targetStorages
|
||||
end
|
||||
local placeable = station.owningPlaceable
|
||||
local productionPoint = placeable ~= nil and placeable.spec_productionPoint ~= nil and placeable.spec_productionPoint.productionPoint or nil
|
||||
local productionPoint = getProductionPoint(station)
|
||||
if productionPoint ~= nil and productionPoint.storage ~= nil then
|
||||
return {productionPoint.storage}
|
||||
end
|
||||
return {}
|
||||
end
|
||||
|
||||
-- Niveau + kapacitet pr. ingrediens i aflæsningsmålets lager.
|
||||
local function getTargetNeeds(station, ingredients, farmId)
|
||||
local function isProductionEnabled(productionPoint, production)
|
||||
if productionPoint.getIsProductionEnabled ~= nil then
|
||||
return productionPoint:getIsProductionEnabled(production.id) == true
|
||||
end
|
||||
for _, active in ipairs(productionPoint.activeProductions or {}) do
|
||||
if active == production then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Fabriksstyret: {[fillType] = liter/min} som målets ønskede produktioner bruger,
|
||||
-- begrænset til det vognen kan bære. Tom tabel = intet produktionspunkt/intet ønsket.
|
||||
local function getProductionDemand(adEnv, station, driver)
|
||||
local productionPoint = getProductionPoint(station)
|
||||
if productionPoint == nil or productionPoint.productions == nil then
|
||||
return {}
|
||||
end
|
||||
local canCarry = {}
|
||||
for _, fillType in ipairs(adEnv.AutoDrive.getSupportedFillTypesOfAllUnitsAlphabetically(driver) or {}) do
|
||||
canCarry[fillType] = true
|
||||
end
|
||||
local missingInputs = ProductionPoint ~= nil and ProductionPoint.PROD_STATUS ~= nil and ProductionPoint.PROD_STATUS.MISSING_INPUTS or nil
|
||||
local function isWanted(production)
|
||||
return ADSupplyPlanner.isProductionWanted(isProductionEnabled(productionPoint, production), production.status, missingInputs)
|
||||
end
|
||||
return ADSupplyPlanner.collectProductionDemand(productionPoint.productions, isWanted, canCarry)
|
||||
end
|
||||
|
||||
-- Fabrikkens inputs som sorteret liste (stabil rækkefølge -> stabil log/rangering).
|
||||
local function getDemandFillTypes(demand)
|
||||
local fillTypes = {}
|
||||
for fillType in pairs(demand) do
|
||||
table.insert(fillTypes, fillType)
|
||||
end
|
||||
table.sort(fillTypes)
|
||||
return fillTypes
|
||||
end
|
||||
|
||||
-- Fabrik som mål uden ønskede produktioner: sig det én gang, så en stille
|
||||
-- tilbagefald til brugerens valg ikke ligner en fejl i moden.
|
||||
local factoryFallbackLogged = setmetatable({}, {__mode = "k"})
|
||||
local function logFactoryFallbackOnce(driver, station)
|
||||
local placeable = station.owningPlaceable
|
||||
local name = placeable ~= nil and placeable.getName ~= nil and placeable:getName() or "fabrik"
|
||||
local message = string.format("'%s': %s har ingen ønskede produktioner (tændte eller auto-slukkede pga. mangel) med varer vognen kan bære; bruger dit varevalg", tostring(driver:getName()), tostring(name))
|
||||
if factoryFallbackLogged[driver] ~= message then
|
||||
factoryFallbackLogged[driver] = message
|
||||
Logging.info(ADSmartPickup.LOG_PREFIX .. "%s", message)
|
||||
end
|
||||
end
|
||||
|
||||
-- Niveau + kapacitet pr. ingrediens i aflæsningsmålets lager; demand giver forbrug/min.
|
||||
local function getTargetNeeds(station, ingredients, farmId, demand)
|
||||
local needs = {}
|
||||
local storages = getTargetStorages(station)
|
||||
for _, fillType in ipairs(ingredients) do
|
||||
@@ -278,7 +338,7 @@ local function getTargetNeeds(station, ingredients, farmId)
|
||||
-- ukendt lagertype: brug stationens egen opgørelse af fri plads
|
||||
level, freeSpace = 0, station:getFreeCapacity(fillType, farmId) or 0
|
||||
end
|
||||
table.insert(needs, {fillType = fillType, level = level, capacity = level + freeSpace})
|
||||
table.insert(needs, {fillType = fillType, level = level, capacity = level + freeSpace, litersPerMinute = demand[fillType]})
|
||||
end
|
||||
end
|
||||
return needs
|
||||
@@ -297,9 +357,19 @@ function ADSmartPickup.findSupplyPickup(adEnv, driver, ingredients)
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Er målet en fabrik med ønskede produktioner, følger listen fabrikken —
|
||||
-- brugerens multi-valg er kun tændknappen (og gendannes ved stop).
|
||||
local demand = getProductionDemand(adEnv, target, driver)
|
||||
if next(demand) ~= nil then
|
||||
ingredients = getDemandFillTypes(demand)
|
||||
factoryFallbackLogged[driver] = nil
|
||||
elseif getProductionPoint(target) ~= nil then
|
||||
logFactoryFallbackOnce(driver, target)
|
||||
end
|
||||
|
||||
local allMarkers = adEnv.ADGraphManager:getMapMarkers()
|
||||
local markerStations = collectMarkerStations(adEnv, allMarkers, farmId, target.owningPlaceable)
|
||||
for _, need in ipairs(ADSupplyPlanner.rankNeeds(getTargetNeeds(target, ingredients, farmId))) do
|
||||
for _, need in ipairs(ADSupplyPlanner.rankNeeds(getTargetNeeds(target, ingredients, farmId, demand))) do
|
||||
local choice = findBestSource(markerStations, {need.fillType}, farmId)
|
||||
if choice ~= nil then
|
||||
return {
|
||||
@@ -351,7 +421,11 @@ local function describeChoice(choice)
|
||||
return string.format("%.0f l, %s", choice.level, source)
|
||||
end
|
||||
local fillTypeName = g_fillTypeManager ~= nil and g_fillTypeManager:getFillTypeNameByIndex(choice.fillType) or tostring(choice.fillType)
|
||||
return string.format("%s: kilde %.0f l, %s, målet har %.0f/%.0f l", tostring(fillTypeName), choice.level, source, choice.need.level, choice.need.capacity)
|
||||
local urgency = ""
|
||||
if choice.need.minutesToEmpty ~= nil then
|
||||
urgency = string.format(", fabrikken bruger %.0f l/min = %.0f min til tom", choice.need.litersPerMinute, choice.need.minutesToEmpty)
|
||||
end
|
||||
return string.format("%s: kilde %.0f l, %s, målet har %.0f/%.0f l%s", tostring(fillTypeName), choice.level, source, choice.need.level, choice.need.capacity, urgency)
|
||||
end
|
||||
|
||||
local function logChoiceOnce(driver, choice)
|
||||
|
||||
Reference in New Issue
Block a user