-- -- configure.lua -- -- Interactive configurator for a facility device. Pick the role, then pick each -- peripheral from a menu of what's actually attached - so you never hand-type a -- peripheral name - and it writes /config.lua. -- -- configure -- -- Run it on the device you're setting up, after the wired/ender modems are -- attached and activated. Re-run any time to reconfigure. -- local CONFIG_PATH = "/config.lua" local PROGRAM = { coordinator = "coordinator", sim_chamber = "chamber_rtu", me_network = "me_rtu", data_center = "dc_rtu", } -- ── tiny UI helpers ───────────────────────────────────────────────────────── local canColor = term.isColour() local function color(c) if canColor then term.setTextColor(c) end end local function header(t) term.clear(); term.setCursorPos(1, 1) color(colors.yellow); print("== " .. t .. " =="); color(colors.white); print("") end local function yesno(prompt, default_yes) color(colors.white) write(prompt .. (default_yes and " (Y/n): " or " (y/N): ")) local s = read():lower() if s == "" then return default_yes == true end return s == "y" or s == "yes" end local function askText(prompt, default) write(prompt) if default then color(colors.gray); write(" [" .. default .. "]"); color(colors.white) end write(": ") local s = read() if s == "" then return default end return s end local function askNumber(prompt, default) while true do write(prompt) if default ~= nil then color(colors.gray); write(" [" .. default .. "]"); color(colors.white) end write(": ") local s = read() if s == "" and default ~= nil then return default end local n = tonumber(s) if n then return math.floor(n) end color(colors.red); print(" please enter a number"); color(colors.white) end end -- numbered menu over {label=, value=}; returns the chosen value local function menu(title, options) while true do header(title) for i, o in ipairs(options) do print(" " .. i .. ") " .. o.label) end print("") color(colors.gray); write("choose 1-" .. #options .. ": "); color(colors.white) local n = tonumber(read()) if n and options[n] then return options[n].value end end end -- short "what's inside" hint for an inventory peripheral, to tell barrels apart local function invHint(name) local p = peripheral.wrap(name) if not (p and p.list) then return "" end local ok, list = pcall(p.list) if not ok or not list then return "" end local total, first = 0, nil for _, item in pairs(list) do total = total + item.count if not first then local d = p.getItemDetail and select(2, pcall(p.getItemDetail, next(list))) first = (type(d) == "table" and d.displayName) or item.name end end if total == 0 then return " (empty)" end return " (" .. (first or "?") .. " x" .. total .. ")" end -- Pick a peripheral of the given type. Detected ones + manual entry + optional -- "none". `annotate(name)` adds a per-entry hint. Returns a name or nil. local function pickPeripheral(title, ptype, allowNone, annotate) local opts = {} for _, n in ipairs(peripheral.getNames()) do if peripheral.getType(n) == ptype then local label = n if annotate then label = label .. " " .. annotate(n) end opts[#opts + 1] = { label = label, value = n } end end opts[#opts + 1] = { label = "(type a name manually)", value = "__manual__" } if allowNone then opts[#opts + 1] = { label = "(none / skip)", value = false } end local choice = menu(title .. " [type: " .. ptype .. "]", opts) if choice == "__manual__" then local n = askText(" peripheral name") return (n ~= "" and n) or (allowNone and nil) end if choice == false then return nil end return choice end local function modemHint(n) local ok, wireless = pcall(peripheral.call, n, "isWireless") return (ok and wireless) and "(wireless/ender)" or "(wired)" end -- ── the wizard ────────────────────────────────────────────────────────────── local role = menu("Facility configurator - device role", { { label = "Coordinator (control computer + monitors)", value = "coordinator" }, { label = "Sim-chamber RTU", value = "sim_chamber" }, { label = "ME-network RTU", value = "me_network" }, { label = "Data-center RTU", value = "data_center" }, }) local cfg = { unit_type = role } header("Common settings - " .. role) cfg.unit_id = askNumber("Unit id (unique across the whole facility)") print("") color(colors.gray); print("Pick the ENDER (wireless) modem used for the rednet link:"); color(colors.white) cfg.modem = pickPeripheral("Rednet modem", "modem", false, modemHint) if role == "sim_chamber" then header("Sim-chamber settings") cfg.chamber_type = askText("Chamber peripheral type", "hostilenetworks:sim_chamber") cfg.barrel_side = askText("Barrel side/name (models + matrices)", "back") cfg.catalyst_low = askNumber("Low-catalyst threshold", 8) elseif role == "me_network" then header("ME-network settings") print("Leave blank/none to auto-detect the ME Bridge.") cfg.me_bridge = pickPeripheral("ME Bridge", "meBridge", true) elseif role == "data_center" then header("Data-center ports (from dc_probe: 0=input, 1=models, 2=output)") local PT = "hostilenetworks:data_center_io_port" cfg.dc_input_port = pickPeripheral("INPUT port", PT, false, invHint) cfg.dc_model_port = pickPeripheral("MODELS port", PT, false, invHint) cfg.dc_output_port = pickPeripheral("OUTPUT port (optional)", PT, true, invHint) header("Data-center barrels (the hint shows contents to tell them apart)") cfg.dc_model_source = pickPeripheral("MODELS barrel", "minecraft:barrel", true, invHint) cfg.dc_input_source = pickPeripheral("PREDICTIONS barrel", "minecraft:barrel", true, invHint) cfg.dc_output_sink = pickPeripheral("OUTPUT barrel (optional)", "minecraft:barrel", true, invHint) elseif role == "coordinator" then header("Coordinator monitors") cfg.chambers_monitor = pickPeripheral("Chambers monitor (optional)", "monitor", true) cfg.me_monitor = pickPeripheral("ME monitor (optional)", "monitor", true) local dc_monitors = {} while yesno("Add a data-center monitor?", next(dc_monitors) == nil) do local uid = askNumber(" data-center unit_id") local mon = pickPeripheral(" monitor for DC #" .. uid, "monitor", false) if mon then dc_monitors[uid] = mon end end if next(dc_monitors) then cfg.dc_monitors = dc_monitors end end -- ── review + write ────────────────────────────────────────────────────────── header("Review /config.lua") print(textutils.serialize(cfg)) print("") if fs.exists(CONFIG_PATH) and not yesno(CONFIG_PATH .. " exists - overwrite?") then print("Cancelled, nothing written.") return end if not fs.exists(CONFIG_PATH) and not yesno("Write " .. CONFIG_PATH .. "?", true) then print("Cancelled, nothing written.") return end local f = fs.open(CONFIG_PATH, "w") f.write("-- generated by configure.lua\nreturn " .. textutils.serialize(cfg) .. "\n") f.close() color(colors.green); print("Wrote " .. CONFIG_PATH); color(colors.white) print("") local prog = PROGRAM[role] print("Run this device with: " .. prog) print("Auto-run on load: put shell.run(\"" .. prog .. "\") in startup.lua")