robathome icon

AutoMiner - Central startup

robathome | PRO | 10/26/25 02:57:37 AM UTC (Edited) | 0 ⭐ | 546 👁️ | Never ⏰ | []
text |

10.89 KB

|

None

|

0 👍

/

0 👎

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

Comments