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"} },
|
["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)
|
-- Fuel items, ordered by preference (best first)
|
||||||
-- burn_time = how many items one fuel smelts
|
-- burn_time = how many items one fuel smelts
|
||||||
local FUEL_LIST = {
|
local FUEL_LIST = {
|
||||||
@@ -782,7 +811,28 @@ end
|
|||||||
local function refreshCache(onProgress)
|
local function refreshCache(onProgress)
|
||||||
activity.scanning = true
|
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 catalogue = {}
|
||||||
local totalSlots = 0
|
local totalSlots = 0
|
||||||
local usedSlots = 0
|
local usedSlots = 0
|
||||||
@@ -837,16 +887,8 @@ local function refreshCache(onProgress)
|
|||||||
cache.dropperOk = peripheral.wrap(DROPPER_NAME) ~= nil
|
cache.dropperOk = peripheral.wrap(DROPPER_NAME) ~= nil
|
||||||
cache.barrelOk = peripheral.wrap(BARREL_NAME) ~= nil
|
cache.barrelOk = peripheral.wrap(BARREL_NAME) ~= nil
|
||||||
|
|
||||||
-- Count furnaces
|
-- Furnace count already computed from single-pass above
|
||||||
local furnaceCount = 0
|
cache.furnaceCount = #furnaces
|
||||||
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
|
|
||||||
|
|
||||||
-- Scan furnace contents for smelter dashboard
|
-- Scan furnace contents for smelter dashboard
|
||||||
refreshFurnaceStatus()
|
refreshFurnaceStatus()
|
||||||
@@ -1722,6 +1764,9 @@ local function drawSmelterDashboard()
|
|||||||
bx1, by1, bx2, by2 = drawButton(bx2 + 2, 4, "Missing", colors.white, tabMissingBg)
|
bx1, by1, bx2, by2 = drawButton(bx2 + 2, 4, "Missing", colors.white, tabMissingBg)
|
||||||
addSmelterZone(bx1, by1, bx2, by2, "tab", "missing")
|
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
|
if smelterView == "status" then
|
||||||
-- ===== Furnace Status View =====
|
-- ===== Furnace Status View =====
|
||||||
-- Column headers
|
-- Column headers
|
||||||
@@ -1839,12 +1884,9 @@ local function drawSmelterDashboard()
|
|||||||
local resultShort = recipe.result:gsub("^minecraft:", ""):gsub("_", " ")
|
local resultShort = recipe.result:gsub("^minecraft:", ""):gsub("_", " ")
|
||||||
resultShort = resultShort:sub(1,1):upper() .. resultShort:sub(2)
|
resultShort = resultShort:sub(1,1):upper() .. resultShort:sub(2)
|
||||||
local types = ""
|
local types = ""
|
||||||
for _, ft in ipairs(recipe.furnaces) do
|
if recipe.furnaceSet["minecraft:furnace"] then types = types .. "F" end
|
||||||
if ft == "minecraft:furnace" then types = types .. "F"
|
if recipe.furnaceSet["minecraft:smoker"] then types = types .. "S" end
|
||||||
elseif ft == "minecraft:smoker" then types = types .. "S"
|
if recipe.furnaceSet["minecraft:blast_furnace"] then types = types .. "B" end
|
||||||
elseif ft == "minecraft:blast_furnace" then types = types .. "B"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local enabled = not disabledRecipes[inputName]
|
local enabled = not disabledRecipes[inputName]
|
||||||
local inStorage = 0
|
local inStorage = 0
|
||||||
if cache.catalogue[inputName] then
|
if cache.catalogue[inputName] then
|
||||||
@@ -1965,6 +2007,7 @@ local function drawSmelterDashboard()
|
|||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
craftAvailCount = #availList
|
||||||
|
|
||||||
-- Column headers
|
-- Column headers
|
||||||
monFill(5, colors.gray)
|
monFill(5, colors.gray)
|
||||||
@@ -2050,6 +2093,7 @@ local function drawSmelterDashboard()
|
|||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
craftAvailCount = #CRAFTABLE - #missList
|
||||||
|
|
||||||
-- Column headers
|
-- Column headers
|
||||||
monFill(5, colors.gray)
|
monFill(5, colors.gray)
|
||||||
@@ -2136,12 +2180,8 @@ local function drawSmelterDashboard()
|
|||||||
bottomMsg = " Tap MAKE to craft "
|
bottomMsg = " Tap MAKE to craft "
|
||||||
if activity.crafting then bottomMsg = " CRAFTING... " end
|
if activity.crafting then bottomMsg = " CRAFTING... " end
|
||||||
elseif smelterView == "missing" then
|
elseif smelterView == "missing" then
|
||||||
local totalC = #CRAFTABLE
|
local availC = craftAvailCount or 0
|
||||||
local availC = 0
|
bottomMsg = string.format(" Available: %d/%d recipes ", availC, #CRAFTABLE)
|
||||||
for _, r in ipairs(CRAFTABLE) do
|
|
||||||
if canCraftRecipe(r) then availC = availC + 1 end
|
|
||||||
end
|
|
||||||
bottomMsg = string.format(" Available: %d/%d recipes ", availC, totalC)
|
|
||||||
end
|
end
|
||||||
monCenter(h, bottomMsg, colors.pink, colors.purple)
|
monCenter(h, bottomMsg, colors.pink, colors.purple)
|
||||||
|
|
||||||
@@ -2172,9 +2212,11 @@ local function sortBarrel(barrelOverride)
|
|||||||
|
|
||||||
for slot, item in pairs(contents) do
|
for slot, item in pairs(contents) do
|
||||||
local moved = 0
|
local moved = 0
|
||||||
|
local triedChests = {} -- dedup: skip chests already tried via catalogue
|
||||||
|
|
||||||
if catalogue[item.name] then
|
if catalogue[item.name] then
|
||||||
for _, entry in ipairs(catalogue[item.name]) do
|
for _, entry in ipairs(catalogue[item.name]) do
|
||||||
|
triedChests[entry.chest] = true
|
||||||
local n = barrel.pushItems(entry.chest, slot)
|
local n = barrel.pushItems(entry.chest, slot)
|
||||||
if n and n > 0 then
|
if n and n > 0 then
|
||||||
moved = moved + n
|
moved = moved + n
|
||||||
@@ -2189,15 +2231,17 @@ local function sortBarrel(barrelOverride)
|
|||||||
|
|
||||||
if moved < item.count then
|
if moved < item.count then
|
||||||
for _, chest in ipairs(chests) do
|
for _, chest in ipairs(chests) do
|
||||||
local n = barrel.pushItems(chest, slot)
|
if not triedChests[chest] then
|
||||||
if n and n > 0 then
|
local n = barrel.pushItems(chest, slot)
|
||||||
moved = moved + n
|
if n and n > 0 then
|
||||||
adjustCache(item.name, chest, n)
|
moved = moved + n
|
||||||
needsRedraw = true
|
adjustCache(item.name, chest, n)
|
||||||
smelterNeedsRedraw = true
|
needsRedraw = true
|
||||||
print(string.format("[SORT] %s x%d -> %s", item.name, n, chest))
|
smelterNeedsRedraw = true
|
||||||
|
print(string.format("[SORT] %s x%d -> %s", item.name, n, chest))
|
||||||
|
end
|
||||||
|
if moved >= item.count then break end
|
||||||
end
|
end
|
||||||
if moved >= item.count then break end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2275,15 +2319,7 @@ local function autoSmelt()
|
|||||||
local inputItem = contents[SLOT_INPUT]
|
local inputItem = contents[SLOT_INPUT]
|
||||||
if inputItem then
|
if inputItem then
|
||||||
local recipe = SMELTABLE[inputItem.name]
|
local recipe = SMELTABLE[inputItem.name]
|
||||||
local validHere = false
|
local validHere = recipe and recipe.furnaceSet[furnaceType] or false
|
||||||
if recipe then
|
|
||||||
for _, ft in ipairs(recipe.furnaces) do
|
|
||||||
if ft == furnaceType then
|
|
||||||
validHere = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if not validHere then
|
if not validHere then
|
||||||
-- This item doesn't belong in this furnace type — pull it out
|
-- This item doesn't belong in this furnace type — pull it out
|
||||||
for _, chest in ipairs(chests) do
|
for _, chest in ipairs(chests) do
|
||||||
@@ -2336,37 +2372,13 @@ local function autoSmelt()
|
|||||||
-- 4) Load smeltable items into empty input slot
|
-- 4) Load smeltable items into empty input slot
|
||||||
inputItem = contents[SLOT_INPUT]
|
inputItem = contents[SLOT_INPUT]
|
||||||
if not inputItem then
|
if not inputItem then
|
||||||
-- Build sorted candidate list: food first, then everything else
|
-- Use pre-built candidate list (already sorted: food first, then alpha)
|
||||||
local candidates = {}
|
local candidates = smeltCandidatesByType[furnaceType] or {}
|
||||||
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)
|
|
||||||
|
|
||||||
-- Try each candidate
|
-- Try each candidate
|
||||||
for _, cand in ipairs(candidates) do
|
for _, cand in ipairs(candidates) do
|
||||||
local itemName = cand.name
|
local itemName = cand.name
|
||||||
|
if not disabledRecipes[itemName] and catalogue[itemName] then
|
||||||
-- Count total of this item across all chests
|
-- Count total of this item across all chests
|
||||||
local totalInStorage = 0
|
local totalInStorage = 0
|
||||||
for _, src in ipairs(catalogue[itemName]) do
|
for _, src in ipairs(catalogue[itemName]) do
|
||||||
@@ -2403,6 +2415,7 @@ local function autoSmelt()
|
|||||||
end
|
end
|
||||||
if loaded or remaining < math.min(available, 64) then break end
|
if loaded or remaining < math.min(available, 64) then break end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user