Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- central_startup.lua (updated)
- -- Advanced computer with Ender modem + two 3x3 Advanced Monitors.
- -- LEFT monitor: widened columns table. RIGHT monitor: larger font with focused turtle details.
- -- Adds miner-specific commands: mine_vector, return_service, dump, refuel, abort/resume/stop.
- -- ====== CONFIG ======
- local PROTOCOL = "minesys:v1"
- local MON_LEFT = "left" -- side name of LEFT monitor (3x3 merged)
- local MON_RIGHT = "right" -- side name of RIGHT monitor (3x3 merged)
- local HOME_POS = {x=-924,y=99,z=-1093}
- -- =====================
- -- Peripherals
- local modem = peripheral.find("modem", function(_,p) return p.isWireless() end)
- assert(modem, "No wireless/Ender modem")
- rednet.open(peripheral.getName(modem))
- local monL = peripheral.wrap(MON_LEFT); assert(monL and peripheral.getType(MON_LEFT)=="monitor","LEFT monitor not found")
- local monR = peripheral.wrap(MON_RIGHT); assert(monR and peripheral.getType(MON_RIGHT)=="monitor","RIGHT monitor not found")
- monL.setTextScale(0.5) -- keep dense table on the left
- monR.setTextScale(1.0) -- larger text on the right (more readable)
- -- State
- local function now() return os.epoch("utc") end
- -- turtles[key] = {id,label,pos={x,y,z},fuel,facing,status,inv={freeSlots,freePct,fuelAvail},tSeen,job}
- local turtles = {}
- local focusKey = nil
- local function count(tbl) local n=0 for _ in pairs(tbl) do n=n+1 end return n end
- local function dist2D(a,b) local dx=a.x-b.x local dz=a.z-b.z return math.sqrt(dx*dx+dz*dz) end
- -- Ingest miner heartbeat/status
- local function upsertStatus(m)
- local key = m.label or m.id; if not key then return end
- local t = turtles[key] or {}
- t.id = m.id or t.id
- t.label = m.label or t.label or ("t"..tostring(m.id or ""))
- t.pos = m.pos or t.pos
- t.fuel = m.fuel or t.fuel
- t.facing = m.facing or t.facing
- t.status = m.status or t.status or "?"
- if m.extra and m.extra.inv then
- t.inv = t.inv or {}
- t.inv.freeSlots = m.extra.inv.freeSlots
- t.inv.freePct = m.extra.inv.freePct
- end
- if m.extra and m.extra.inv and m.extra.inv.fuelAvail then
- t.inv = t.inv or {}; t.inv.fuelAvail = m.extra.inv.fuelAvail
- end
- t.tSeen = now()
- turtles[key] = t
- if not focusKey then focusKey = key end
- end
- -- Task classifier
- local function classifyTask(t)
- local s = (t.status or ""):lower()
- if s:find("err") or s:find("stop") then return "STOPPED", colors.red, nil end
- if t.job and t.job.kind=="move" and t.job.total and t.job.done then
- local pct = math.max(0, math.min(100, math.floor((1 - (t.job.done/t.job.total))*100+0.5)))
- return "MOVING", colors.orange, pct
- end
- if t.job and t.job.kind=="work" and t.job.total and t.job.done then
- local pct = math.max(0, math.min(100, math.floor((1 - (t.job.done/t.job.total))*100+0.5)))
- return "ACTIVE", colors.yellow, pct
- end
- if t.pos and dist2D(t.pos, HOME_POS)<=2 and (s=="waiting" or s=="idle" or s=="") then
- return "HOME", colors.lime, nil
- end
- return "HOME", colors.lime, nil
- end
- -- LEFT monitor: widened columns
- -- Columns: >Lbl | X | Y | Z | Task(%) | Fuel(cur/inv) | Inv%Filled
- local function drawLeft()
- local m=monL
- m.setBackgroundColor(colors.black); m.clear()
- m.setTextColor(colors.white)
- m.setCursorPos(1,1); m.write(("Turtles: %d"):format(count(turtles)))
- m.setCursorPos(1,2); m.write("Label X Y Z Task(%) Fuel Inv%")
- local y=3
- local h
- do local _,hh=m.getSize(); h=hh end
- for _,t in pairs(turtles) do
- if y>h then break end
- local lbl=(t.label or "?"):sub(1,8)
- local xs=(t.pos and t.pos.x) and string.format("%5d", t.pos.x) or " ?"
- local ys=(t.pos and t.pos.y) and string.format("%5d", t.pos.y) or " ?"
- local zs=(t.pos and t.pos.z) and string.format("%5d", t.pos.z) or " ?"
- local task,col,pct = classifyTask(t)
- local fuelCur = t.fuel and tostring(t.fuel) or "?"
- local fuelInv = t.inv and t.inv.fuelAvail and tostring(t.inv.fuelAvail) or "?"
- local invFilled = t.inv and t.inv.freePct and (100 - math.floor(t.inv.freePct+0.5)) or nil
- local invTxt = invFilled and string.format("%3d", invFilled) or " --"
- m.setTextColor(colors.white)
- m.setCursorPos(1,y); m.write(string.format(">%-8s", lbl))
- m.setCursorPos(11,y); m.write(xs)
- m.setCursorPos(17,y); m.write(ys)
- m.setCursorPos(23,y); m.write(zs)
- m.setCursorPos(29,y); m.setTextColor(col)
- m.write(string.format("%-8s", task))
- if pct then m.write(string.format("(%3d)", pct)) else m.write(" ") end
- m.setTextColor(colors.white)
- m.setCursorPos(44,y); m.write(string.format("%-6s/%-6s", fuelCur, fuelInv))
- m.setCursorPos(58,y); m.write(invTxt)
- -- focus marker
- if focusKey == (t.label or t.id) then
- m.setCursorPos(1,y); m.setTextColor(colors.cyan); m.write(">")
- m.setTextColor(colors.white)
- end
- y=y+1
- end
- end
- -- RIGHT monitor: larger font details
- local function drawRight()
- local m=monR
- m.setBackgroundColor(colors.black); m.clear()
- m.setTextColor(colors.white)
- local t = focusKey and turtles[focusKey]
- if not t then m.setCursorPos(1,1); m.write("No focus"); return end
- local task,col,pct = classifyTask(t)
- local invFilled = t.inv and t.inv.freePct and (100 - math.floor(t.inv.freePct+0.5)) or nil
- m.setCursorPos(1,1); m.write("Focus:"); m.setTextColor(colors.cyan)
- m.write(" "..(t.label or ("#"..tostring(t.id)))); m.setTextColor(colors.white)
- m.setCursorPos(1,3); m.write("Pos: ")
- m.write(t.pos and string.format("(%d,%d,%d)", t.pos.x,t.pos.y,t.pos.z) or "(?, ?, ?)")
- m.setCursorPos(1,4); m.write("Facing: "..(t.facing or "?"))
- m.setCursorPos(1,5); m.write("Fuel: "..(t.fuel and tostring(t.fuel) or "?"))
- m.setCursorPos(1,6); m.write("FuelInv: "..(t.inv and t.inv.fuelAvail and tostring(t.inv.fuelAvail) or "?"))
- m.setCursorPos(1,7); m.write("Inv fill: "..(invFilled and (invFilled.."%") or "?"))
- m.setCursorPos(1,9); m.setTextColor(col)
- m.write("Task: "..task..(pct and (" ("..pct.."%)") or "")); m.setTextColor(colors.white)
- if t.status then m.setCursorPos(1,11); m.write("Status: "..t.status) end
- if t.job then
- m.setCursorPos(1,12); m.write("Job: "..(t.job.kind or "?"))
- if t.job.total then m.setCursorPos(1,13); m.write(("Steps: %d/%d"):format(t.job.done or 0, t.job.total)) end
- if t.job.note then m.setCursorPos(1,14); m.write("Note: "..t.job.note) end
- end
- m.setCursorPos(1,16); m.setTextColor(colors.lightGray)
- m.write("help | focus <lab> | mv | svc | dump | refuel | abort/resume/stop")
- m.setTextColor(colors.white)
- end
- -- ---- Send commands / job tracking ----
- local function findKey(lblOrId)
- for k,t in pairs(turtles) do
- if t.label==lblOrId or tostring(t.id)==tostring(lblOrId) then return k end
- end
- end
- local function sendCmd(target, tbl, onAck)
- tbl.op="cmd"; tbl.ref=math.random(1,1e9)
- local tgtID=nil
- for _,t in pairs(turtles) do
- if t.label==target or tostring(t.id)==tostring(target) then tgtID=t.id break end
- end
- if not tgtID then return false,"unknown target" end
- rednet.send(tgtID, tbl, PROTOCOL)
- local tm=os.startTimer(3)
- while true do
- local ev,a,b,c = os.pullEvent()
- if ev=="rednet_message" then
- local sid,msg,proto=a,b,c
- if proto==PROTOCOL and type(msg)=="table" and msg.op=="ack" and msg.ref==tbl.ref then
- if onAck then onAck(msg) end
- return msg.ok, msg.err
- end
- elseif ev=="timer" and a==tm then
- return false,"ack timeout"
- end
- end
- end
- -- Miner-oriented helpers
- local function mv(lbl, axis, len, haltAir, haltDirt)
- len = tonumber(len) or 0
- local ha = (haltAir == "1") or (haltAir == true)
- local hd = (haltDirt== "1") or (haltDirt== true)
- return sendCmd(lbl, {act="mine_vector", axis=axis, len=len, stopOnAir=ha, stopOnDirt=hd}, function()
- local k=findKey(lbl); if not k then return end
- local t=turtles[k]; t.job = {kind="work", total=math.abs(len), done=0, note=("axis "..axis)}
- end)
- end
- local function service(lbl) return sendCmd(lbl, {act="return_service"}) end
- local function doDump(lbl) return sendCmd(lbl, {act="dump"}) end
- local function doRefuel(lbl) return sendCmd(lbl, {act="refuel"}) end
- local function doAbort(lbl) return sendCmd(lbl, {act="abort"}) end
- local function doResume(lbl) return sendCmd(lbl, {act="resume"}) end
- local function doStop(lbl) return sendCmd(lbl, {act="stop"}) end
- local function setFacingTag(lbl,dir) return sendCmd(lbl, {act="set_facing_tag", dir=dir}) end
- -- Progress bump on movement (coarse). Any position delta advances current job by 1.
- local function onMinerStatusForProgress(k, prevPos)
- local t=turtles[k]; if not t then return end
- if not prevPos or not t.pos then return end
- if prevPos.x~=t.pos.x or prevPos.y~=t.pos.y or prevPos.z~=t.pos.z then
- if t.job then
- t.job.done = math.min((t.job.done or 0)+1, t.job.total or (t.job.done or 0))
- if t.job.total and t.job.done >= t.job.total then t.job=nil end
- end
- end
- end
- -- Net + UI
- local function netUi()
- while true do
- local id,msg,proto = rednet.receive(PROTOCOL, 0.2)
- if id and proto==PROTOCOL and type(msg)=="table" and msg.op=="status" then
- local key = msg.label or msg.id
- local prevPos = key and turtles[key] and turtles[key].pos
- upsertStatus(msg)
- onMinerStatusForProgress(key, prevPos)
- end
- drawLeft(); drawRight()
- end
- end
- -- REPL
- local function help()
- print("help")
- print("list")
- print("focus <label|id>")
- print("mv <label> <axis:x|y|z> <len> [haltAir 0/1] [haltDirt 0/1]")
- print("svc <label> -- return_service (dump+refuel handled on miner)")
- print("dump <label> -- force dump")
- print("refuel <label> -- force refuel")
- print("abort <label> | resume <label> | stop <label>")
- print("tagface <label> <N|E|S|W>")
- end
- local function repl()
- term.clear(); term.setCursorPos(1,1); help()
- while true do
- io.write("> ")
- local line = read()
- local a,b,c,d,e,f = line:match("^(%S+)%s*(%S*)%s*(%S*)%s*(%S*)%s*(%S*)%s*(%S*)")
- if a=="help" then help()
- elseif a=="list" then
- for _,t in pairs(turtles) do
- print((t.label or "?"), t.id or "?", t.pos and (t.pos.x..","..t.pos.y..","..t.pos.z) or "?, ?, ?")
- end
- elseif a=="focus" then
- local k=findKey(b); if k then focusKey=k else print("unknown") end
- elseif a=="mv" then
- if b=="" or c=="" or d=="" then print("usage: mv <label> <axis:x|y|z> <len> [haltAir 0/1] [haltDirt 0/1]") else
- print(mv(b,c,d,e,f))
- end
- elseif a=="svc" then print(service(b))
- elseif a=="dump" then print(doDump(b))
- elseif a=="refuel" then print(doRefuel(b))
- elseif a=="abort" then print(doAbort(b))
- elseif a=="resume" then print(doResume(b))
- elseif a=="stop" then print(doStop(b))
- elseif a=="tagface" then print(setFacingTag(b,c))
- else print("unknown") end
- end
- end
- parallel.waitForAny(netUi, repl)
Advertisement
Add Comment
Please, Sign In to add comment