-- Inventory Manager: Auto-sort barrel, order & dispense via networked dropper -- Main computer (networked). Computer 1 sits next to dropper_0 and runs dropperController.lua. local DROPPER_NAME = "minecraft:dropper_9" local BARREL_NAME = "minecraft:barrel_0" local MODEM_SIDE = nil -- auto-detected local CONTROLLER_ID = 1 -- computer ID of the dropper controller local POLL_INTERVAL = 2 -- seconds between barrel checks local PROTOCOL = "inventory" ------------------------------------------------- -- Networking ------------------------------------------------- -- Find and open the modem local function setupModem() for _, side in ipairs({"top","bottom","left","right","front","back"}) do if peripheral.getType(side) == "modem" then rednet.open(side) MODEM_SIDE = side return true end end -- Also check for wired modems wrapped as peripherals for _, name in ipairs(peripheral.getNames()) do if peripheral.getType(name) == "modem" then rednet.open(name) MODEM_SIDE = name return true end end return false end ------------------------------------------------- -- Inventory helpers ------------------------------------------------- -- Get all chest peripheral names on the network local function getChests() local chests = {} for _, name in ipairs(peripheral.getNames()) do if peripheral.getType(name) == "minecraft:chest" then table.insert(chests, name) end end return chests end -- Scan a single inventory: returns { [itemName] = { total=N, slots={ [slot]={name,count} } } } local function scanInventory(deviceName) local inv = peripheral.wrap(deviceName) if not inv then return {} end local result = {} for slot, item in pairs(inv.list()) do if not result[item.name] then result[item.name] = { total = 0, slots = {} } end result[item.name].total = result[item.name].total + item.count result[item.name].slots[slot] = { name = item.name, count = item.count } end return result end -- Build a full catalogue: itemName -> { {chest=name, total=N}, ... } local function buildCatalogue() local catalogue = {} -- itemName -> list of {chest, total} for _, chest in ipairs(getChests()) do local contents = scanInventory(chest) for itemName, info in pairs(contents) do if not catalogue[itemName] then catalogue[itemName] = {} end table.insert(catalogue[itemName], { chest = chest, total = info.total }) end end return catalogue end ------------------------------------------------- -- Barrel auto-sort ------------------------------------------------- -- Move all items from the barrel into matching chests (or first chest with space) local function sortBarrel() local barrel = peripheral.wrap(BARREL_NAME) if not barrel then return end local contents = barrel.list() if not contents or not next(contents) then return end local catalogue = buildCatalogue() local chests = getChests() for slot, item in pairs(contents) do local moved = 0 -- Try chests that already hold this item first if catalogue[item.name] then for _, entry in ipairs(catalogue[item.name]) do local n = barrel.pushItems(entry.chest, slot) if n and n > 0 then moved = moved + n print(string.format("[SORT] %s x%d -> %s", item.name, n, entry.chest)) end if moved >= item.count then break end end end -- If some remain, push to any chest with space 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 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 print(string.format("[WARN] Could not sort %d remaining %s", item.count - moved, item.name)) end end end ------------------------------------------------- -- Order & dispense ------------------------------------------------- -- Send redstone trigger to computer 1 via rednet local function triggerDropper() rednet.send(CONTROLLER_ID, "dispense", PROTOCOL) print("[NET] Sent dispense signal to computer " .. CONTROLLER_ID) end -- Order items: move from chest(s) to dropper, then trigger dispense local function orderItem(itemName, amount) local catalogue = buildCatalogue() if not catalogue[itemName] then print("[ERR] Item not found: " .. itemName) return false end local dropper = peripheral.wrap(DROPPER_NAME) if not dropper then print("[ERR] Dropper not found: " .. DROPPER_NAME) return false end local remaining = amount for _, entry in ipairs(catalogue[itemName]) do local chest = peripheral.wrap(entry.chest) if chest then -- Find slots in this chest with the target item for slot, slotItem in pairs(chest.list()) do if slotItem.name == itemName then local toMove = math.min(remaining, slotItem.count) local moved = chest.pushItems(DROPPER_NAME, slot, toMove) if moved and moved > 0 then remaining = remaining - moved print(string.format("[ORDER] %s x%d from %s -> dropper", itemName, moved, entry.chest)) end if remaining <= 0 then break end end end end if remaining <= 0 then break end end if remaining > 0 then print(string.format("[WARN] Only moved %d/%d of %s", amount - remaining, amount, itemName)) end -- Trigger computer 1 to fire the dropper triggerDropper() return true end ------------------------------------------------- -- Display ------------------------------------------------- local function showCatalogue() local catalogue = buildCatalogue() print("") print("=== Item Catalogue ===") print("") local index = 1 local items = {} for itemName, sources in pairs(catalogue) do local total = 0 for _, s in ipairs(sources) do total = total + s.total end -- Strip "minecraft:" prefix for cleaner display local short = itemName:gsub("^minecraft:", "") print(string.format(" %2d. %-30s x%d", index, short, total)) items[index] = itemName index = index + 1 end print("") return items end ------------------------------------------------- -- Main loop ------------------------------------------------- local function main() print("=================================") print(" Inventory Manager v2") print("=================================") print("") -- Setup networking if not setupModem() then print("[WARN] No modem found. Dispense signals won't work.") else print("[OK] Modem opened on: " .. tostring(MODEM_SIDE)) end -- Check dropper if peripheral.wrap(DROPPER_NAME) then print("[OK] Dropper found: " .. DROPPER_NAME) else print("[WARN] Dropper not found: " .. DROPPER_NAME) end -- Check barrel if peripheral.wrap(BARREL_NAME) then print("[OK] Barrel found: " .. BARREL_NAME) else print("[WARN] Barrel not found: " .. BARREL_NAME) end print("") -- Run barrel watcher and command prompt in parallel parallel.waitForAny( -- Task 1: Watch barrel for new items function() while true do sortBarrel() sleep(POLL_INTERVAL) end end, -- Task 2: Interactive command prompt function() while true do local items = showCatalogue() print("Commands:") print(" order [amount] - Dispense an item") print(" scan - Refresh catalogue") print(" quit - Exit") print("") write("> ") local input = read() local parts = {} for word in input:gmatch("%S+") do table.insert(parts, word) end local cmd = parts[1] if cmd == "order" or cmd == "o" then local idx = tonumber(parts[2]) local amt = tonumber(parts[3]) or 1 if idx and items[idx] then orderItem(items[idx], amt) else print("[ERR] Invalid item number.") end elseif cmd == "scan" or cmd == "s" then print("Rescanning...") elseif cmd == "quit" or cmd == "q" then print("Shutting down.") return else print("[ERR] Unknown command: " .. tostring(cmd)) end print("") end end ) end main()