perf(kæde): priser slås kun op for kandidatmarker, fanen genbruger resultater under 30 s og kæden måles af profileren

This commit is contained in:
2026-09-30 14:27:08 +02:00
parent 9e34a16dfa
commit 83394aabfd
4 changed files with 41 additions and 18 deletions
+7 -1
View File
@@ -275,7 +275,7 @@ local function plan(data, state)
if not data.fieldsIncomplete then if not data.fieldsIncomplete then
shortages = ADCropPlan.shortages(chain.fieldDemand, data.stock, data.fields, data.yields) shortages = ADCropPlan.shortages(chain.fieldDemand, data.stock, data.fields, data.yields)
state.dismissed = ADChain.pruneDismissed(state.dismissed, shortages) state.dismissed = ADChain.pruneDismissed(state.dismissed, shortages)
actions = ADCropPlan.choose(shortages, data.fields, used, data.yields, data.prices, ADChain.dismissedFruits(state.dismissed)) actions = ADCropPlan.choose(shortages, data.fields, used, data.yields, data.priceOf or data.prices, ADChain.dismissedFruits(state.dismissed))
end end
-- de ægte opskrifter (ikke kopien): en pauset rod er stadig tændt og må ikke "tændes" og overtages af kæden -- de ægte opskrifter (ikke kopien): en pauset rod er stadig tændt og må ikke "tændes" og overtages af kæden
local prod = ADChainActions.productions(data.recipes, chain.needRecipes, protected) local prod = ADChainActions.productions(data.recipes, chain.needRecipes, protected)
@@ -326,6 +326,12 @@ function ADChain.evaluate(adEnv, act)
return ADChain.last return ADChain.last
end end
-- Alder (ms, spillets ur) af det sidste resultat; math.huge når der intet er. Fanen genbruger et friskt resultat.
function ADChain.lastAge()
if ADChain.last == nil then return math.huge end
return ADChain.now - (ADChain.last.at or 0)
end
function ADChain.tick(adEnv, dt) function ADChain.tick(adEnv, dt)
if adEnv == nil then return end if adEnv == nil then return end
ADChain.now = ADChain.now + (dt or 0) ADChain.now = ADChain.now + (dt or 0)
+27 -5
View File
@@ -141,6 +141,27 @@ local function readPlaceables(data, farmId, byChain, nameOf)
table.sort(data.recipes, function(a, b) return a.key < b.key end) table.sort(data.recipes, function(a, b) return a.key < b.key end)
end end
-- Markedspris for en afgrøde, først når kæden spørger (kun kandidatmarkernes afgrøder, kun ved mangel);
-- hver afgrøde slås højst op én gang pr. læsning. Fejl -> 0 (logget én gang).
local function priceResolver(data)
local cache = {}
return function(fruitName)
if cache[fruitName] ~= nil then return cache[fruitName] end
local index = data.fruitFillIndex[fruitName]
local price = 0
if index ~= nil then
local ok, quote = pcall(ADSources.getMarketQuote, index)
if ok then
price = quote ~= nil and quote.price or 0
else
ADChainData.warnOnce("price:" .. tostring(fruitName), "pris for %s kunne ikke læses: %s", tostring(fruitName), tostring(quote))
end
end
cache[fruitName] = price
return price
end
end
local function readCrops(data, nameOf) local function readCrops(data, nameOf)
local fruits = g_fruitTypeManager ~= nil and g_fruitTypeManager.fruitTypes or {} local fruits = g_fruitTypeManager ~= nil and g_fruitTypeManager.fruitTypes or {}
for _, fruit in ipairs(fruits) do for _, fruit in ipairs(fruits) do
@@ -151,8 +172,7 @@ local function readCrops(data, nameOf)
if fruit.fillType.index ~= nil then nameOf(fruit.fillType.index) end if fruit.fillType.index ~= nil then nameOf(fruit.fillType.index) end
data.crops[fillName] = fruit.name data.crops[fillName] = fruit.name
data.yields[fruit.name] = (tonumber(fruit.literPerSqm) or 0) * 10000 data.yields[fruit.name] = (tonumber(fruit.literPerSqm) or 0) * 10000
local quote = fruit.fillType.index ~= nil and ADSources.getMarketQuote(fruit.fillType.index) or nil data.fruitFillIndex[fruit.name] = fruit.fillType.index
data.prices[fruit.name] = quote ~= nil and quote.price or 0
end) end)
if not ok then failed(data, "fruit:" .. tostring(fruit.name), "afgrøde %s kunne ikke læses: %s", tostring(fruit.name), tostring(err)) end if not ok then failed(data, "fruit:" .. tostring(fruit.name), "afgrøde %s kunne ikke læses: %s", tostring(fruit.name), tostring(err)) end
end end
@@ -169,7 +189,8 @@ local function readStock(data, adEnv, farmId, nameOf)
if not ok then failed(data, "stock", "lager kunne ikke læses: %s", tostring(err)) end if not ok then failed(data, "stock", "lager kunne ikke læses: %s", tostring(err)) end
end end
-- Afgrøder gården selv bruger: input i en tændt produktion eller foder/halm i en stald. -- Afgrøder gården selv bruger: input i en tændt produktion eller foder/halm i en stald (kun staldenes forbrug
-- læses: feedOnly springer fabrikkernes rater over — dem dækker opskrifterne allerede).
local function readUsedFruits(data, adEnv, farmId, nameOf) local function readUsedFruits(data, adEnv, farmId, nameOf)
for _, recipe in ipairs(data.recipes) do for _, recipe in ipairs(data.recipes) do
if recipe.enabled then if recipe.enabled then
@@ -179,7 +200,7 @@ local function readUsedFruits(data, adEnv, farmId, nameOf)
end end
end end
local ok, err = pcall(function() local ok, err = pcall(function()
for index, rate in pairs(ADSources.getFarmRates(adEnv, farmId) or {}) do for index, rate in pairs(ADSources.getFarmRates(adEnv, farmId, true) or {}) do
local fruit = data.crops[nameOf(index) or ""] local fruit = data.crops[nameOf(index) or ""]
if fruit ~= nil and (rate.consumption or 0) > 0 then data.usedFruits[fruit] = true end if fruit ~= nil and (rate.consumption or 0) > 0 then data.usedFruits[fruit] = true end
end end
@@ -216,9 +237,10 @@ end
-- data.partial = true når noget ikke kunne læses i dette kald; data.fieldsIncomplete = true mens markscanningen -- data.partial = true når noget ikke kunne læses i dette kald; data.fieldsIncomplete = true mens markscanningen
-- ikke har nået alle marker. -- ikke har nået alle marker.
function ADChainData.collect(adEnv, farmId, byChain) function ADChainData.collect(adEnv, farmId, byChain)
local data = {recipes = {}, husbandry = {}, crops = {}, stock = {}, fields = {}, yields = {}, prices = {}, local data = {recipes = {}, husbandry = {}, crops = {}, stock = {}, fields = {}, yields = {}, fruitFillIndex = {},
usedFruits = {}, points = {}, fillTitles = {}, fillIndex = {}} usedFruits = {}, points = {}, fillTitles = {}, fillIndex = {}}
local nameOf = nameResolver(data) local nameOf = nameResolver(data)
data.priceOf = priceResolver(data)
readPlaceables(data, farmId, byChain, nameOf) readPlaceables(data, farmId, byChain, nameOf)
readCrops(data, nameOf) readCrops(data, nameOf)
readStock(data, adEnv, farmId, nameOf) readStock(data, adEnv, farmId, nameOf)
+2
View File
@@ -110,6 +110,8 @@ function ADProfiler.install()
{ADSources, "getFarmInventory", "gårdens lagre"}, {ADSources, "getFarmInventory", "gårdens lagre"},
{ADWaitPool, "hasRouteTo", "rutetjek"}, {ADWaitPool, "hasRouteTo", "rutetjek"},
{ADWaitPool, "hasRouteBothWays", "rutetjek frem+tilbage"}, {ADWaitPool, "hasRouteBothWays", "rutetjek frem+tilbage"},
{ADChain, "evaluate", "kæde"},
{ADChainData, "collect", "kæde: læs gården"},
} }
for _, target in ipairs(targets) do for _, target in ipairs(targets) do
ADProfiler.wrap(target[1], target[2], target[3]) ADProfiler.wrap(target[1], target[2], target[3])
+5 -12
View File
@@ -1,22 +1,15 @@
-- Smart Pickup — fanen Kæder -- Smart Pickup — fanen Kæder
-- Produktionskæderne som træ: rod (produktion spilleren har tændt) -> varer -> råvarer, med kilde, behov pr. -- Produktionskæderne som træ: rod (produktion spilleren har tændt) -> varer -> råvarer, med kilde, behov pr.
-- måned og flowstatus; afgrødeforslag kan godkendes/afvises og en rod sættes på pause. Rækkerne bygges af -- måned og flowstatus; afgrødeforslag kan godkendes/afvises og en rod sættes på pause. Rækkerne bygges af
-- ADChainView (testet); her kun kloning, farve og klik. Evaluering højst hvert CHAIN_EVALUATE_MS (visning, handler ikke). -- ADChainView (testet); her kun kloning, farve og klik. Et resultat yngre end CHAIN_MAX_AGE_MS (fra kædens eget
-- tick eller en tidligere visning) genbruges; ellers evalueres (visning, handler ikke). Klik evaluerer altid.
SmartPickupFrame.CHAIN_EVALUATE_MS = 5000 SmartPickupFrame.CHAIN_MAX_AGE_MS = 30000
-- Spillets ur i ms; uden g_time evalueres ved hver opbygning (der kun sker hvert CHAIN_REBUILD_TICKS s).
local function nowMs()
return type(g_time) == "number" and g_time or nil
end
function SmartPickupFrame:chainLast(adEnv, force) function SmartPickupFrame:chainLast(adEnv, force)
local now = nowMs() local age = ADChain.lastAge ~= nil and ADChain.lastAge() or math.huge
local due = force or ADChain.last == nil or now == nil or self.chainEvaluatedAt == nil if force or ADChain.last == nil or age >= SmartPickupFrame.CHAIN_MAX_AGE_MS then
or now - self.chainEvaluatedAt >= SmartPickupFrame.CHAIN_EVALUATE_MS
if due then
ADChain.evaluate(adEnv) ADChain.evaluate(adEnv)
self.chainEvaluatedAt = now
end end
return ADChain.last return ADChain.last
end end