Implement auto-smelting functionality with furnace management and item handling
This commit is contained in:
@@ -6,6 +6,98 @@ local BARREL_NAME = "minecraft:barrel_0"
|
||||
local POLL_INTERVAL = 2 -- seconds between barrel checks
|
||||
local MONITOR_SIDE = "left"
|
||||
local SCAN_INTERVAL = 3 -- seconds between background scans
|
||||
local SMELT_INTERVAL = 3 -- seconds between furnace checks
|
||||
local SMELT_RESERVE = 64 -- keep at least 1 stack of each raw material
|
||||
|
||||
-------------------------------------------------
|
||||
-- Furnace types to manage
|
||||
-------------------------------------------------
|
||||
|
||||
local FURNACE_TYPES = {
|
||||
"minecraft:furnace",
|
||||
"minecraft:smoker",
|
||||
"minecraft:blast_furnace",
|
||||
}
|
||||
|
||||
-- Furnace slots: 1 = input, 2 = fuel, 3 = output (standard Minecraft)
|
||||
local SLOT_INPUT = 1
|
||||
local SLOT_FUEL = 2
|
||||
local SLOT_OUTPUT = 3
|
||||
|
||||
-------------------------------------------------
|
||||
-- Smeltable items: input -> output
|
||||
-- Items in chests matching a key here get auto-smelted.
|
||||
-- Add/remove entries to control what gets cooked.
|
||||
-------------------------------------------------
|
||||
|
||||
local SMELTABLE = {
|
||||
-- Ores
|
||||
["minecraft:raw_iron"] = "minecraft:iron_ingot",
|
||||
["minecraft:raw_gold"] = "minecraft:gold_ingot",
|
||||
["minecraft:raw_copper"] = "minecraft:copper_ingot",
|
||||
["minecraft:iron_ore"] = "minecraft:iron_ingot",
|
||||
["minecraft:gold_ore"] = "minecraft:gold_ingot",
|
||||
["minecraft:copper_ore"] = "minecraft:copper_ingot",
|
||||
["minecraft:deepslate_iron_ore"] = "minecraft:iron_ingot",
|
||||
["minecraft:deepslate_gold_ore"] = "minecraft:gold_ingot",
|
||||
["minecraft:deepslate_copper_ore"] = "minecraft:copper_ingot",
|
||||
["minecraft:ancient_debris"] = "minecraft:netherite_scrap",
|
||||
-- Sand / stone
|
||||
["minecraft:sand"] = "minecraft:glass",
|
||||
["minecraft:red_sand"] = "minecraft:glass",
|
||||
["minecraft:cobblestone"] = "minecraft:stone",
|
||||
["minecraft:stone"] = "minecraft:smooth_stone",
|
||||
["minecraft:clay_ball"] = "minecraft:brick",
|
||||
["minecraft:netherrack"] = "minecraft:nether_brick",
|
||||
["minecraft:sandstone"] = "minecraft:smooth_sandstone",
|
||||
-- Food
|
||||
["minecraft:beef"] = "minecraft:cooked_beef",
|
||||
["minecraft:porkchop"] = "minecraft:cooked_porkchop",
|
||||
["minecraft:chicken"] = "minecraft:cooked_chicken",
|
||||
["minecraft:mutton"] = "minecraft:cooked_mutton",
|
||||
["minecraft:rabbit"] = "minecraft:cooked_rabbit",
|
||||
["minecraft:cod"] = "minecraft:cooked_cod",
|
||||
["minecraft:salmon"] = "minecraft:cooked_salmon",
|
||||
["minecraft:potato"] = "minecraft:baked_potato",
|
||||
["minecraft:kelp"] = "minecraft:dried_kelp",
|
||||
-- Misc
|
||||
["minecraft:wet_sponge"] = "minecraft:sponge",
|
||||
["minecraft:cactus"] = "minecraft:green_dye",
|
||||
["minecraft:sea_pickle"] = "minecraft:lime_dye",
|
||||
["minecraft:log"] = "minecraft:charcoal",
|
||||
["minecraft:oak_log"] = "minecraft:charcoal",
|
||||
["minecraft:spruce_log"] = "minecraft:charcoal",
|
||||
["minecraft:birch_log"] = "minecraft:charcoal",
|
||||
["minecraft:jungle_log"] = "minecraft:charcoal",
|
||||
["minecraft:acacia_log"] = "minecraft:charcoal",
|
||||
["minecraft:dark_oak_log"] = "minecraft:charcoal",
|
||||
["minecraft:mangrove_log"] = "minecraft:charcoal",
|
||||
["minecraft:cherry_log"] = "minecraft:charcoal",
|
||||
}
|
||||
|
||||
-- Fuel items, ordered by preference (best first)
|
||||
-- burn_time = how many items one fuel smelts
|
||||
local FUEL_LIST = {
|
||||
{ name = "minecraft:coal", burn_time = 8 },
|
||||
{ name = "minecraft:charcoal", burn_time = 8 },
|
||||
{ name = "minecraft:coal_block", burn_time = 80 },
|
||||
{ name = "minecraft:blaze_rod", burn_time = 12 },
|
||||
{ name = "minecraft:dried_kelp_block", burn_time = 20 },
|
||||
{ name = "minecraft:lava_bucket", burn_time = 100 },
|
||||
{ name = "minecraft:oak_planks", burn_time = 1.5 },
|
||||
{ name = "minecraft:spruce_planks",burn_time = 1.5 },
|
||||
{ name = "minecraft:birch_planks", burn_time = 1.5 },
|
||||
{ name = "minecraft:jungle_planks",burn_time = 1.5 },
|
||||
{ name = "minecraft:acacia_planks",burn_time = 1.5 },
|
||||
{ name = "minecraft:dark_oak_planks",burn_time = 1.5 },
|
||||
{ name = "minecraft:mangrove_planks",burn_time = 1.5 },
|
||||
{ name = "minecraft:cherry_planks",burn_time = 1.5 },
|
||||
{ name = "minecraft:stick", burn_time = 0.5 },
|
||||
}
|
||||
|
||||
-- Build a set for quick lookup
|
||||
local FUEL_SET = {}
|
||||
for _, f in ipairs(FUEL_LIST) do FUEL_SET[f.name] = true end
|
||||
|
||||
-------------------------------------------------
|
||||
-- Cached data (updated by background scanner)
|
||||
@@ -32,6 +124,7 @@ local activity = {
|
||||
sorting = false, -- barrel sort in progress
|
||||
dispensing = false, -- order in progress
|
||||
scanning = false, -- background scan in progress
|
||||
smelting = false, -- auto-smelt in progress
|
||||
}
|
||||
|
||||
-------------------------------------------------
|
||||
@@ -48,6 +141,18 @@ local function getChests()
|
||||
return chests
|
||||
end
|
||||
|
||||
local function getFurnaces()
|
||||
local furnaces = {}
|
||||
for _, ftype in ipairs(FURNACE_TYPES) do
|
||||
for _, name in ipairs(peripheral.getNames()) do
|
||||
if peripheral.getType(name) == ftype then
|
||||
table.insert(furnaces, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
return furnaces
|
||||
end
|
||||
|
||||
local function scanInventory(deviceName)
|
||||
local inv = peripheral.wrap(deviceName)
|
||||
if not inv then return {} end
|
||||
@@ -120,6 +225,17 @@ local function refreshCache()
|
||||
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
|
||||
|
||||
activity.scanning = false
|
||||
end
|
||||
|
||||
@@ -274,11 +390,15 @@ local function drawDashboard()
|
||||
table.insert(statusParts, string.format(" Chests: %d", cache.chestCount))
|
||||
table.insert(statusParts, cache.dropperOk and "Dropper: OK" or "Dropper: --")
|
||||
table.insert(statusParts, cache.barrelOk and "Barrel: OK" or "Barrel: --")
|
||||
if cache.furnaceCount and cache.furnaceCount > 0 then
|
||||
table.insert(statusParts, string.format("Furnaces: %d", cache.furnaceCount))
|
||||
end
|
||||
|
||||
-- Activity indicators
|
||||
local actParts = {}
|
||||
if activity.sorting then table.insert(actParts, "SORTING") end
|
||||
if activity.dispensing then table.insert(actParts, "DISPENSING") end
|
||||
if activity.smelting then table.insert(actParts, "SMELTING") end
|
||||
if activity.scanning then table.insert(actParts, "SCANNING") end
|
||||
|
||||
monWrite(2, 2, table.concat(statusParts, " | "), colors.white, colors.gray)
|
||||
@@ -528,6 +648,8 @@ local function drawDashboard()
|
||||
local bottomMsg = " Tap item to order "
|
||||
if activity.dispensing then
|
||||
bottomMsg = " DISPENSING... "
|
||||
elseif activity.smelting then
|
||||
bottomMsg = " SMELTING... "
|
||||
elseif activity.sorting then
|
||||
bottomMsg = " SORTING BARREL... "
|
||||
end
|
||||
@@ -592,6 +714,122 @@ local function sortBarrel()
|
||||
needsRedraw = true
|
||||
end
|
||||
|
||||
-------------------------------------------------
|
||||
-- Auto-smelt
|
||||
-------------------------------------------------
|
||||
|
||||
local function autoSmelt()
|
||||
local furnaces = getFurnaces()
|
||||
if #furnaces == 0 then return end
|
||||
|
||||
local chests = getChests()
|
||||
local catalogue = cache.catalogue
|
||||
local didWork = false
|
||||
|
||||
for _, fname in ipairs(furnaces) do
|
||||
local furnace = peripheral.wrap(fname)
|
||||
if furnace then
|
||||
local contents = furnace.list()
|
||||
|
||||
-- 1) Pull finished output (slot 3) back to chests
|
||||
if contents[SLOT_OUTPUT] then
|
||||
for _, chest in ipairs(chests) do
|
||||
local n = furnace.pushItems(chest, SLOT_OUTPUT)
|
||||
if n and n > 0 then
|
||||
print(string.format("[SMELT] Output %s x%d -> %s",
|
||||
contents[SLOT_OUTPUT].name, n, chest))
|
||||
didWork = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Re-read after output pull
|
||||
contents = furnace.list()
|
||||
|
||||
-- 2) Refuel if fuel slot is empty or low
|
||||
local fuelItem = contents[SLOT_FUEL]
|
||||
local needFuel = not fuelItem or fuelItem.count < 8
|
||||
|
||||
if needFuel then
|
||||
for _, fuel in ipairs(FUEL_LIST) do
|
||||
if catalogue[fuel.name] then
|
||||
for _, source in ipairs(catalogue[fuel.name]) do
|
||||
local chest = peripheral.wrap(source.chest)
|
||||
if chest then
|
||||
for slot, slotItem in pairs(chest.list()) do
|
||||
if slotItem.name == fuel.name then
|
||||
local toMove = math.min(16, slotItem.count)
|
||||
local n = chest.pushItems(fname, slot, toMove, SLOT_FUEL)
|
||||
if n and n > 0 then
|
||||
print(string.format("[SMELT] Fuel %s x%d -> %s",
|
||||
fuel.name, n, fname))
|
||||
didWork = true
|
||||
needFuel = false
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if not needFuel then break end
|
||||
end
|
||||
end
|
||||
if not needFuel then break end
|
||||
end
|
||||
end
|
||||
|
||||
-- 3) Load smeltable items into empty input slot
|
||||
local inputItem = contents[SLOT_INPUT]
|
||||
if not inputItem then
|
||||
-- Find something smeltable in chests
|
||||
for itemName, _ in pairs(SMELTABLE) do
|
||||
if catalogue[itemName] then
|
||||
-- Count total of this item across all chests
|
||||
local totalInStorage = 0
|
||||
for _, src in ipairs(catalogue[itemName]) do
|
||||
totalInStorage = totalInStorage + src.total
|
||||
end
|
||||
|
||||
-- Only smelt the excess beyond SMELT_RESERVE
|
||||
local available = totalInStorage - SMELT_RESERVE
|
||||
if available <= 0 then
|
||||
-- Skip: need to keep reserve
|
||||
else
|
||||
local loaded = false
|
||||
local remaining = math.min(available, 64)
|
||||
for _, source in ipairs(catalogue[itemName]) do
|
||||
local chest = peripheral.wrap(source.chest)
|
||||
if chest then
|
||||
for slot, slotItem in pairs(chest.list()) do
|
||||
if slotItem.name == itemName then
|
||||
local toMove = math.min(slotItem.count, remaining)
|
||||
local n = chest.pushItems(fname, slot, toMove, SLOT_INPUT)
|
||||
if n and n > 0 then
|
||||
print(string.format("[SMELT] Input %s x%d -> %s (reserve %d)",
|
||||
itemName, n, fname, math.max(0, totalInStorage - n)))
|
||||
didWork = true
|
||||
remaining = remaining - n
|
||||
if remaining <= 0 then
|
||||
loaded = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if loaded then break end
|
||||
end
|
||||
if loaded or remaining < math.min(available, 64) then break end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return didWork
|
||||
end
|
||||
|
||||
-------------------------------------------------
|
||||
-- Order
|
||||
-------------------------------------------------
|
||||
@@ -801,7 +1039,24 @@ local function main()
|
||||
end
|
||||
end,
|
||||
|
||||
-- Task 3: Dashboard redraw (event-driven, checks every 0.1s)
|
||||
-- Task 3: Auto-smelt
|
||||
function()
|
||||
while true do
|
||||
activity.smelting = true
|
||||
needsRedraw = true
|
||||
local ok, didWork = pcall(autoSmelt)
|
||||
activity.smelting = false
|
||||
needsRedraw = true
|
||||
-- If work was done, scan sooner to update cache
|
||||
if ok and didWork then
|
||||
pcall(refreshCache)
|
||||
needsRedraw = true
|
||||
end
|
||||
sleep(SMELT_INTERVAL)
|
||||
end
|
||||
end,
|
||||
|
||||
-- Task 4: Dashboard redraw (event-driven, checks every 0.1s)
|
||||
function()
|
||||
needsRedraw = true
|
||||
while true do
|
||||
@@ -821,7 +1076,7 @@ local function main()
|
||||
end
|
||||
end,
|
||||
|
||||
-- Task 4: Touch event listener
|
||||
-- Task 5: Touch event listener
|
||||
function()
|
||||
while true do
|
||||
local event, side, x, y = os.pullEvent("monitor_touch")
|
||||
|
||||
Reference in New Issue
Block a user