Optimize smelting process by pre-building furnace compatibility sets and using sorted candidate lists for improved efficiency
This commit is contained in:
@@ -195,6 +195,35 @@ local SMELTABLE = {
|
||||
["farmersdelight:minced_beef"] = { result = "farmersdelight:beef_patty", furnaces = {"minecraft:furnace", "minecraft:smoker"} },
|
||||
}
|
||||
|
||||
-- Pre-build furnace compatibility sets for O(1) lookup
|
||||
for _, recipe in pairs(SMELTABLE) do
|
||||
recipe.furnaceSet = {}
|
||||
for _, ft in ipairs(recipe.furnaces) do
|
||||
recipe.furnaceSet[ft] = true
|
||||
end
|
||||
end
|
||||
|
||||
-- Pre-built smelt candidate lists per furnace type (sorted: food first, then alpha)
|
||||
-- Avoids rebuilding & re-sorting in autoSmelt on every cycle.
|
||||
local smeltCandidatesByType = {}
|
||||
do
|
||||
for _, ftype in ipairs(FURNACE_TYPES) do
|
||||
smeltCandidatesByType[ftype] = {}
|
||||
end
|
||||
for itemName, recipe in pairs(SMELTABLE) do
|
||||
local isFood = recipe.furnaceSet["minecraft:smoker"] or false
|
||||
for ft, _ in pairs(recipe.furnaceSet) do
|
||||
table.insert(smeltCandidatesByType[ft], { name = itemName, recipe = recipe, food = isFood })
|
||||
end
|
||||
end
|
||||
for _, list in pairs(smeltCandidatesByType) do
|
||||
table.sort(list, function(a, b)
|
||||
if a.food ~= b.food then return a.food end
|
||||
return a.name < b.name
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
-- Fuel items, ordered by preference (best first)
|
||||
-- burn_time = how many items one fuel smelts
|
||||
local FUEL_LIST = {
|
||||
@@ -782,7 +811,28 @@ end
|
||||
local function refreshCache(onProgress)
|
||||
activity.scanning = true
|
||||
|
||||
local chests = getChests()
|
||||
-- Single pass over peripherals: classify into chests and furnaces
|
||||
local chests = {}
|
||||
local furnaces = {}
|
||||
local furnaceTypeSet = {}
|
||||
for _, ft in ipairs(FURNACE_TYPES) do furnaceTypeSet[ft] = true end
|
||||
|
||||
for _, name in ipairs(peripheral.getNames()) do
|
||||
local ptype = peripheral.getType(name)
|
||||
if ptype == "minecraft:chest" then
|
||||
table.insert(chests, name)
|
||||
elseif furnaceTypeSet[ptype] then
|
||||
table.insert(furnaces, name)
|
||||
end
|
||||
end
|
||||
|
||||
-- Update peripheral caches so getChests()/getFurnaces() stay fresh
|
||||
local now = os.clock()
|
||||
cachedChests = chests
|
||||
cachedChestsTime = now
|
||||
cachedFurnaces = furnaces
|
||||
cachedFurnacesTime = now
|
||||
|
||||
local catalogue = {}
|
||||
local totalSlots = 0
|
||||
local usedSlots = 0
|
||||
@@ -837,16 +887,8 @@ local function refreshCache(onProgress)
|
||||
cache.dropperOk = peripheral.wrap(DROPPER_NAME) ~= nil
|
||||
cache.barrelOk = peripheral.wrap(BARREL_NAME) ~= nil
|
||||
|
||||
-- Count furnaces
|
||||
local furnaceCount = 0
|
||||
for _, ftype in ipairs(FURNACE_TYPES) do
|
||||
for _, name in ipairs(peripheral.getNames()) do
|
||||
if peripheral.getType(name) == ftype then
|
||||
furnaceCount = furnaceCount + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
cache.furnaceCount = furnaceCount
|
||||
-- Furnace count already computed from single-pass above
|
||||
cache.furnaceCount = #furnaces
|
||||
|
||||
-- Scan furnace contents for smelter dashboard
|
||||
refreshFurnaceStatus()
|
||||
@@ -1722,6 +1764,9 @@ local function drawSmelterDashboard()
|
||||
bx1, by1, bx2, by2 = drawButton(bx2 + 2, 4, "Missing", colors.white, tabMissingBg)
|
||||
addSmelterZone(bx1, by1, bx2, by2, "tab", "missing")
|
||||
|
||||
-- Hoisted counter: reused by bottom accent bar to avoid re-scanning recipes
|
||||
local craftAvailCount = nil
|
||||
|
||||
if smelterView == "status" then
|
||||
-- ===== Furnace Status View =====
|
||||
-- Column headers
|
||||
@@ -1839,12 +1884,9 @@ local function drawSmelterDashboard()
|
||||
local resultShort = recipe.result:gsub("^minecraft:", ""):gsub("_", " ")
|
||||
resultShort = resultShort:sub(1,1):upper() .. resultShort:sub(2)
|
||||
local types = ""
|
||||
for _, ft in ipairs(recipe.furnaces) do
|
||||
if ft == "minecraft:furnace" then types = types .. "F"
|
||||
elseif ft == "minecraft:smoker" then types = types .. "S"
|
||||
elseif ft == "minecraft:blast_furnace" then types = types .. "B"
|
||||
end
|
||||
end
|
||||
if recipe.furnaceSet["minecraft:furnace"] then types = types .. "F" end
|
||||
if recipe.furnaceSet["minecraft:smoker"] then types = types .. "S" end
|
||||
if recipe.furnaceSet["minecraft:blast_furnace"] then types = types .. "B" end
|
||||
local enabled = not disabledRecipes[inputName]
|
||||
local inStorage = 0
|
||||
if cache.catalogue[inputName] then
|
||||
@@ -1965,6 +2007,7 @@ local function drawSmelterDashboard()
|
||||
})
|
||||
end
|
||||
end
|
||||
craftAvailCount = #availList
|
||||
|
||||
-- Column headers
|
||||
monFill(5, colors.gray)
|
||||
@@ -2050,6 +2093,7 @@ local function drawSmelterDashboard()
|
||||
})
|
||||
end
|
||||
end
|
||||
craftAvailCount = #CRAFTABLE - #missList
|
||||
|
||||
-- Column headers
|
||||
monFill(5, colors.gray)
|
||||
@@ -2136,12 +2180,8 @@ local function drawSmelterDashboard()
|
||||
bottomMsg = " Tap MAKE to craft "
|
||||
if activity.crafting then bottomMsg = " CRAFTING... " end
|
||||
elseif smelterView == "missing" then
|
||||
local totalC = #CRAFTABLE
|
||||
local availC = 0
|
||||
for _, r in ipairs(CRAFTABLE) do
|
||||
if canCraftRecipe(r) then availC = availC + 1 end
|
||||
end
|
||||
bottomMsg = string.format(" Available: %d/%d recipes ", availC, totalC)
|
||||
local availC = craftAvailCount or 0
|
||||
bottomMsg = string.format(" Available: %d/%d recipes ", availC, #CRAFTABLE)
|
||||
end
|
||||
monCenter(h, bottomMsg, colors.pink, colors.purple)
|
||||
|
||||
@@ -2172,9 +2212,11 @@ local function sortBarrel(barrelOverride)
|
||||
|
||||
for slot, item in pairs(contents) do
|
||||
local moved = 0
|
||||
local triedChests = {} -- dedup: skip chests already tried via catalogue
|
||||
|
||||
if catalogue[item.name] then
|
||||
for _, entry in ipairs(catalogue[item.name]) do
|
||||
triedChests[entry.chest] = true
|
||||
local n = barrel.pushItems(entry.chest, slot)
|
||||
if n and n > 0 then
|
||||
moved = moved + n
|
||||
@@ -2189,15 +2231,17 @@ local function sortBarrel(barrelOverride)
|
||||
|
||||
if moved < item.count then
|
||||
for _, chest in ipairs(chests) do
|
||||
local n = barrel.pushItems(chest, slot)
|
||||
if n and n > 0 then
|
||||
moved = moved + n
|
||||
adjustCache(item.name, chest, n)
|
||||
needsRedraw = true
|
||||
smelterNeedsRedraw = true
|
||||
print(string.format("[SORT] %s x%d -> %s", item.name, n, chest))
|
||||
if not triedChests[chest] then
|
||||
local n = barrel.pushItems(chest, slot)
|
||||
if n and n > 0 then
|
||||
moved = moved + n
|
||||
adjustCache(item.name, chest, n)
|
||||
needsRedraw = true
|
||||
smelterNeedsRedraw = true
|
||||
print(string.format("[SORT] %s x%d -> %s", item.name, n, chest))
|
||||
end
|
||||
if moved >= item.count then break end
|
||||
end
|
||||
if moved >= item.count then break end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2275,15 +2319,7 @@ local function autoSmelt()
|
||||
local inputItem = contents[SLOT_INPUT]
|
||||
if inputItem then
|
||||
local recipe = SMELTABLE[inputItem.name]
|
||||
local validHere = false
|
||||
if recipe then
|
||||
for _, ft in ipairs(recipe.furnaces) do
|
||||
if ft == furnaceType then
|
||||
validHere = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
local validHere = recipe and recipe.furnaceSet[furnaceType] or false
|
||||
if not validHere then
|
||||
-- This item doesn't belong in this furnace type — pull it out
|
||||
for _, chest in ipairs(chests) do
|
||||
@@ -2336,37 +2372,13 @@ local function autoSmelt()
|
||||
-- 4) Load smeltable items into empty input slot
|
||||
inputItem = contents[SLOT_INPUT]
|
||||
if not inputItem then
|
||||
-- Build sorted candidate list: food first, then everything else
|
||||
local candidates = {}
|
||||
for itemName, recipe in pairs(SMELTABLE) do
|
||||
-- Check if this furnace type is compatible
|
||||
local compatible = false
|
||||
for _, ft in ipairs(recipe.furnaces) do
|
||||
if ft == furnaceType then
|
||||
compatible = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if compatible and not disabledRecipes[itemName] and catalogue[itemName] then
|
||||
local isFood = false
|
||||
for _, ft in ipairs(recipe.furnaces) do
|
||||
if ft == "minecraft:smoker" then
|
||||
isFood = true
|
||||
break
|
||||
end
|
||||
end
|
||||
table.insert(candidates, { name = itemName, recipe = recipe, food = isFood })
|
||||
end
|
||||
end
|
||||
-- Sort: food first
|
||||
table.sort(candidates, function(a, b)
|
||||
if a.food ~= b.food then return a.food end
|
||||
return a.name < b.name
|
||||
end)
|
||||
-- Use pre-built candidate list (already sorted: food first, then alpha)
|
||||
local candidates = smeltCandidatesByType[furnaceType] or {}
|
||||
|
||||
-- Try each candidate
|
||||
for _, cand in ipairs(candidates) do
|
||||
local itemName = cand.name
|
||||
if not disabledRecipes[itemName] and catalogue[itemName] then
|
||||
-- Count total of this item across all chests
|
||||
local totalInStorage = 0
|
||||
for _, src in ipairs(catalogue[itemName]) do
|
||||
@@ -2403,6 +2415,7 @@ local function autoSmelt()
|
||||
end
|
||||
if loaded or remaining < math.min(available, 64) then break end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user