From: Olav Bakke Svendsen Date: Tue, 26 Nov 2024 23:39:56 +0000 (+0100) Subject: Uploaded working catalyst farm code X-Git-Tag: catalyst~1 X-Git-Url: http://git.olavbs.no/?a=commitdiff_plain;h=772b86ed386c4daf4e1b1a8c46804cdd1226dd02;p=cc.git Uploaded working catalyst farm code --- diff --git a/catalyst/auto.lua b/catalyst/auto.lua new file mode 100644 index 0000000..11ba2d8 --- /dev/null +++ b/catalyst/auto.lua @@ -0,0 +1,9 @@ +local args = {...} +if args[1] == "on" or args[1] == "true" then + os.queueEvent("auto", true) +elseif args[1] == "off" or args[1] == "false" then + os.queueEvent("auto", false) +else + print "usage: auto on | off" +end + diff --git a/catalyst/carriage-controller.lua b/catalyst/carriage-controller.lua new file mode 100644 index 0000000..5a85fb2 --- /dev/null +++ b/catalyst/carriage-controller.lua @@ -0,0 +1,290 @@ +-- /bin/carriage.lua +-- Configuration file at /etc/carriage.lua +-- Operates drilling carriage. Starts drilling on "drill" event. +-- Enable/disable automatic redrilling with "auto" bool event. +-- Transfers items and restocks deployers after drilling. + + +-- options + +local verbose +do + local args = {...} + for i = 1, #args do + if args[i] == "-v" or args[i] == "--verbose" then + verbose = true + end + end +end + + +-- imports + +dofile "/lib/import.lua" + +global_import "/lib/control.lua" { "forever", "simultaneously" } + +local inv = import "/lib/inventory.lua" + { "free" + , "find" + , "move_all" + } + +local log = dofile "/lib/log.lua" +-- log.on_insert = log.queue_event("log") +log.debug = function(self, str) self:insert("debug", str) end +log.on_insert = function(t) + if not verbose and t.status == "debug" then return end + local color = (t.status == "debug" and colors.gray) + or (t.status == "warn" and colors.yellow) + or (t.status == "err" and colors.red) + or colors.white + term.setTextColor(colors.gray) + write(os.date("%a %T ", t.epoch)) + term.setTextColor(color) + print(t.entry) +end + + +-- configuration + +local config_path = "/etc/carriage-controller.lua" +local config = {} +do + local ok, config_file = pcall(dofile, config_path) + if not ok then return "couldn't load config" end +-- local config_file = log:pwarn("Couldn't load \""..config_path.."\"", dofile, config_path) +-- if err then log.warn("Couldn't load \""..config_path.."\": "..err) end + config_file = config_file or {} + for k,v in pairs(config_file) do config[k] = v end + + if not config.deployers then + log:ok("auto-detecting deployers") + config.deployers = {} + for _,p in ipairs(peripheral.getNames()) do + if string.match(p, "^create:deployer") then + table.insert(config.deployers, p) + end + end + local f = #config.deployers > 0 and log.ok or log.err + f(log, "found "..tostring(#config.deployers).." deployers") + end + if not config.deployers or #config.deployers <= 0 then return end + + for k, v in pairs(config.contacts) do + local addr, side = table.unpack(config.contacts[k]) + config.contacts[k].getInput = addr == "internal" + and function() return rs.getInput(side) end + or function() return peripheral.call(addr, "getInput", side) end + end +end + + +-- signals + +local signal = {} +signal.carriage_ready = function() os.queueEvent("carriage", "ready") end +signal.carriage_busy = function() os.queueEvent("carriage", "busy") end +signal.carriage_parked = function() os.queueEvent("carriage", "parked") end +signal.drill = function() os.queueEvent("drill") end +signal.auto = function(bool) os.queueEvent("auto", bool) end + + +-- wait_until functions: yields until some condition is met + +local wait_until = {} + +wait_until.carriage_event = function(status) + return function() + local ev + repeat + _, ev = os.pullEvent("carriage") + until ev == status + end +end + +wait_until.carriage_ready = wait_until.carriage_event("ready") + +wait_until.carriage_busy = wait_until.carriage_event("busy") + +wait_until.carriage_parked = wait_until.carriage_event("parked") + +wait_until.drilling_started = function() os.pullEvent("drill") end + +wait_until.auto = function(bool) + local auto + repeat + _, auto = os.pullEvent("auto") + until auto == bool +end + +wait_until.carriage_should_return = function() + while not config.contacts.away.getInput() do os.sleep(0) end +end + +wait_until.carriage_has_returned = function() + while not config.contacts.home.getInput() do os.sleep(0) end +end + +wait_until.deployers_available = function() + local available = function() + for _,d in ipairs(config.deployers) do + if not peripheral.wrap(d) then return false end + end + return true + end + while not available() do os.sleep(); print("waiting for deployers") end +end + +wait_until.carriage_inventory_available = function() + while not peripheral.wrap(config.carriage_inventory) do os.sleep() end +end + +wait_until.output_below_threshold = function() + while inv.free(config.output_inventory) >= config.output_threshold do + os.sleep() + end +end + + +-- gearshift +local gearshift = {} +gearshift.forward = nil +gearshift.back = nil + +do + local addr, side = table.unpack(config.gearshift) + local set + if addr == "internal" then + set = function(bool) return function() rs.setOutput(side, bool) end end + else + set = function(bool) return function() peripheral.call(addr, "setOutput", side, bool) end end + end + gearshift.forward = set(true) + gearshift.back = set(false) +end + + +-- inventory management + +local restock_deployers +local transfer_items + +restock_deployers = function() +-- wait_until.deployers_available() + for _, d in pairs(config.deployers) do +-- local deployer = peripheral.wrap(d) + local empty = { name = "minecraft:redstone", count = 0, maxCount = 64 } + local item = peripheral.call(d, "getItemDetail", 1) or empty + if item.name ~= "minecraft:redstone" then + log:err(d.." holding "..item.name) + end + local found_all, index = inv.find(config.redstone_inventory, { ["minecraft:redstone"] = item.maxCount - item.count }) + if not found_all then + log:warn("low on redstone") + end + if not index["minecraft:redstone"] then + log:warn("out of redstone") + else + for slot, amount in pairs(index["minecraft:redstone"].slots) do + peripheral.call(config.redstone_inventory, "pushItems", d, slot, amount) + end + end + end +end + +transfer_items = function() +-- wait_until.carriage_inventory_available() +-- wait_until.output_below_threshold() + local moved = inv.move_all(config.carriage_inventory, config.output_inventory) + log:ok("transferred "..tostring(moved).." items") +end + + +-- routines + +local drill +local ready_carriage +local toggle_auto +local print_log +local initialize + +drill = forever(function() + wait_until.carriage_ready() + log:debug("carriage ready") + wait_until.drilling_started() + log:debug("drilling started") + signal.carriage_busy() + gearshift.forward() + wait_until.carriage_should_return() + log:debug("carriage returning") + gearshift.back() + wait_until.carriage_has_returned() + log:debug("carriage parked") + signal.carriage_parked() +end) + +ready_carriage = forever(function() + wait_until.carriage_parked() +-- wait_until.deployers_available() + log:debug("restocking deployers") + restock_deployers() +-- wait_until.output_below_threshold() +-- wait_until.carriage_inventory_available() + log:debug("transferring items") + transfer_items() + signal.carriage_ready() +end) + +toggle_auto = forever(function() + wait_until.auto(true) + log:ok("auto enabled") + simultaneously + { function() wait_until.auto(false) end + , forever(function() + wait_until.carriage_ready() + log:debug("auto drilling on ready") + signal.drill() + end) + , function() + if config.start_immediately then + log:debug("auto drilling immediately") + signal.drill() + end + forever(coroutine.yield)() + end + } + log:ok("auto disabled") +end) + +-- print_log = forever(function() +-- local _, epoch, status, entry = os.pullEvent("log") +-- print(status, entry) +-- end) + +initialize = function() + if not config.contacts.home.getInput() then + log:warn("carriage not found") + log:ok("(tip: \"park home\" forces it home)") + end + wait_until.carriage_has_returned() +-- wait_until.deployers_available() +-- wait_until.carriage_inventory_available() + log:ok("carriage parked") + signal.carriage_parked() + wait_until.carriage_ready() + if config.auto then signal.auto(true) end + forever(coroutine.yield)() +end + + +-- main + +simultaneously + { drill + , ready_carriage + , toggle_auto +-- , print_log + , initialize + , function() os.pullEventRaw("terminate") end + } diff --git a/catalyst/config.lua b/catalyst/config.lua new file mode 100644 index 0000000..ee523e8 --- /dev/null +++ b/catalyst/config.lua @@ -0,0 +1,44 @@ +-- catalyst controller config + +return + + -- enable automatic redrilling by default + { auto = true + + -- whether to start drilling when auto is enabled + , start_immediately = true + + -- redstone contacts + , gearshift = { "redstoneIntegrator_3", "front" } + + -- redstone contacts + , contacts = + { home = { "redstoneIntegrator_3", "top" } + , away = { "redstoneIntegrator_5", "top" } + } + + -- list of deployer addresses + -- (automatically detects deployers when nil) + , deployers = + { "create:deployer_4" + , "create:deployer_5" + , "create:deployer_6" + , "create:deployer_7" + } + + -- carriage's inventory address + -- (must be defined) + , carriage_inventory = "minecraft:barrel_6" + + -- stationary inventory addresses + -- (must be defined) + , redstone_inventory = "functionalstorage:birch_1_2" + , output_inventory = "functionalstorage:birch_1_3" + + -- pause automatic drilling unless output + -- inventory has space for this many items + , output_threshold = 1000 -- math.huge + + } + + diff --git a/catalyst/drill.lua b/catalyst/drill.lua new file mode 100644 index 0000000..3954131 --- /dev/null +++ b/catalyst/drill.lua @@ -0,0 +1 @@ +os.queueEvent("drill") diff --git a/catalyst/package b/catalyst/package new file mode 100644 index 0000000..520fdf2 --- /dev/null +++ b/catalyst/package @@ -0,0 +1,10 @@ +cc catalyst/carriage-controller.lua:/bin/carriage-controller.lua:o +cc catalyst/startup.lua:/bin/carriage-controller-startup.lua:o +cc catalyst/drill.lua:/bin/drill.lua:o +cc catalyst/auto.lua:/bin/auto.lua:o +cc catalyst/park.lua:/bin/park.lua:o +cc catalyst/config.lua:/etc/carriage-controller.lua +cc lib/import.lua:/lib/import.lua:o +cc lib/control.lua:/lib/control.lua:o +cc lib/inventory.lua:/lib/inventory.lua:o +cc lib/log.lua:/lib/log.lua:o diff --git a/catalyst/park.lua b/catalyst/park.lua new file mode 100644 index 0000000..448c1b9 --- /dev/null +++ b/catalyst/park.lua @@ -0,0 +1,19 @@ +local args = {...} + +local config = dofile "/etc/carriage-controller.lua" + +local addr, side = table.unpack(config.gearshift) +local set +if addr == "internal" then + set = function(bool) rs.setOutput(side, bool) end +else + set = function(bool) peripheral.call(addr, "setOutput", side, bool) end +end + +if args[1] == "home" or args[1] == "false" then + set(false) +elseif args[1] == "away" or args[1] == "true" then + set(true) +else + print "usage: park home | away" +end diff --git a/catalyst/startup.lua b/catalyst/startup.lua new file mode 100644 index 0000000..48e158d --- /dev/null +++ b/catalyst/startup.lua @@ -0,0 +1,11 @@ +shell.run("bg carriage-controller -v") +term.clear() +term.setCursorPos(1,1) +term.setTextColor(colors.yellow) +print("Catalyst farm") +term.setTextColor(colors.white) +print("Config at /etc/carriage-controller.lua") +print("Commands:") +print(" drill") +print(" auto on | off") +print(" park home | away") diff --git a/lib/inventory.lua b/lib/inventory.lua index bf8996c..41d8442 100644 --- a/lib/inventory.lua +++ b/lib/inventory.lua @@ -103,6 +103,14 @@ t.move = function(source_address, destination_address, item_amounts) return not err or table.unpack({ false, "Could not move: "..err }) end +t.move_all = function(src, dst) + local moved = 0 + for slot = 1, peripheral.call(src, "size") do + moved = moved + peripheral.call(src, "pushItems", dst, slot) + end + return moved +end + t.count = function(address, item_names) local slots = peripheral.call(address, "list") local count = 0 @@ -114,4 +122,74 @@ t.count = function(address, item_names) return count end +t.free = function(address) + local inventory = peripheral.wrap(address) +-- local items = inventory.list() + local free = 0 + for slot = 1, inventory.size() do + local limit = inventory.getItemLimit(slot) + local item = inventory.getItemDetail(slot) + local amount = item and item.count or 0 + free = free + limit - amount + end + return free +end + + +-- index :: inventory name -> index +-- index :: name -> m (name, index) +-- move :: (inv, { slot = amt }) +-- index :: inv -> (inv, { item = { total = amount, slots = { slot = amount } } }) +-- find :: {inv} -> item -> amount -> { inv = { total = amount, slots = { slot = amount } } } + +-- by_item :: ... -> { item = { total = amount, inventories = { total = amount, slots = { slot = amount } } } } +-- by_inventory :: ... -> { inventory = { item = { total = amount, slots = { slot = amount } } } } + +-- internal inventories are indexed once. the index is stored in the inventory object and modified as the contents are operated on. +-- normal inventories do not keep track of their index, and is re-indexed every time index() is called + +local inventory_index = {} +-- { ["item_name"] = { total = amt, slots = { slot = amt } } } +do + local mt = {} + mt.__index = function() return { total = 0, slots = {} } end + mt.__call = function() + end + setmetatable(inventory_index, mt) +end + +local do_index = function(inventory) + if inventory.internal then + return inventory.index + end + if not inventory.current_index then + -- do the indexing + end + return inventory.index +end + +local do_move = function(from, to, what) + local from_index + if not from.indexed then + end +end + +local inventory = {} +inventory.wrap = function(inventory_addr, block_reader_addr) + local inv = + { addr = inventory_addr + , block_reader_addr = block_reader_addr or false + , internal = false + , current_index = false + , index = function(self) end + , move = function(self, ...) end + } + return inv +end +inventory.wrap_internal = function(...) + local inv = inventory.wrap(...) + inv.internal = true + return inv +end + return t