Implement auto-smelting functionality with furnace management and item handling

This commit is contained in:
MayaTheShy
2026-03-15 22:27:12 -04:00
parent d8a08528b9
commit 1a80b7d0d4

View File

@@ -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")