robathome

AutoMiner - Central startup

Oct 25th, 2025 (edited)
634
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.89 KB | None | 0 0
  1. -- central_startup.lua (updated)
  2. -- Advanced computer with Ender modem + two 3x3 Advanced Monitors.
  3. -- LEFT monitor: widened columns table. RIGHT monitor: larger font with focused turtle details.
  4. -- Adds miner-specific commands: mine_vector, return_service, dump, refuel, abort/resume/stop.
  5.  
  6. -- ====== CONFIG ======
  7. local PROTOCOL = "minesys:v1"
  8. local MON_LEFT = "left" -- side name of LEFT monitor (3x3 merged)
  9. local MON_RIGHT = "right" -- side name of RIGHT monitor (3x3 merged)
  10. local HOME_POS = {x=-924,y=99,z=-1093}
  11. -- =====================
  12.  
  13. -- Peripherals
  14. local modem = peripheral.find("modem", function(_,p) return p.isWireless() end)
  15. assert(modem, "No wireless/Ender modem")
  16. rednet.open(peripheral.getName(modem))
  17.  
  18. local monL = peripheral.wrap(MON_LEFT); assert(monL and peripheral.getType(MON_LEFT)=="monitor","LEFT monitor not found")
  19. local monR = peripheral.wrap(MON_RIGHT); assert(monR and peripheral.getType(MON_RIGHT)=="monitor","RIGHT monitor not found")
  20. monL.setTextScale(0.5) -- keep dense table on the left
  21. monR.setTextScale(1.0) -- larger text on the right (more readable)
  22.  
  23. -- State
  24. local function now() return os.epoch("utc") end
  25. -- turtles[key] = {id,label,pos={x,y,z},fuel,facing,status,inv={freeSlots,freePct,fuelAvail},tSeen,job}
  26. local turtles = {}
  27. local focusKey = nil
  28.  
  29. local function count(tbl) local n=0 for _ in pairs(tbl) do n=n+1 end return n end
  30. 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
  31.  
  32. -- Ingest miner heartbeat/status
  33. local function upsertStatus(m)
  34. local key = m.label or m.id; if not key then return end
  35. local t = turtles[key] or {}
  36. t.id = m.id or t.id
  37. t.label = m.label or t.label or ("t"..tostring(m.id or ""))
  38. t.pos = m.pos or t.pos
  39. t.fuel = m.fuel or t.fuel
  40. t.facing = m.facing or t.facing
  41. t.status = m.status or t.status or "?"
  42. if m.extra and m.extra.inv then
  43. t.inv = t.inv or {}
  44. t.inv.freeSlots = m.extra.inv.freeSlots
  45. t.inv.freePct = m.extra.inv.freePct
  46. end
  47. if m.extra and m.extra.inv and m.extra.inv.fuelAvail then
  48. t.inv = t.inv or {}; t.inv.fuelAvail = m.extra.inv.fuelAvail
  49. end
  50. t.tSeen = now()
  51. turtles[key] = t
  52. if not focusKey then focusKey = key end
  53. end
  54.  
  55. -- Task classifier
  56. local function classifyTask(t)
  57. local s = (t.status or ""):lower()
  58. if s:find("err") or s:find("stop") then return "STOPPED", colors.red, nil end
  59. if t.job and t.job.kind=="move" and t.job.total and t.job.done then
  60. local pct = math.max(0, math.min(100, math.floor((1 - (t.job.done/t.job.total))*100+0.5)))
  61. return "MOVING", colors.orange, pct
  62. end
  63. if t.job and t.job.kind=="work" and t.job.total and t.job.done then
  64. local pct = math.max(0, math.min(100, math.floor((1 - (t.job.done/t.job.total))*100+0.5)))
  65. return "ACTIVE", colors.yellow, pct
  66. end
  67. if t.pos and dist2D(t.pos, HOME_POS)<=2 and (s=="waiting" or s=="idle" or s=="") then
  68. return "HOME", colors.lime, nil
  69. end
  70. return "HOME", colors.lime, nil
  71. end
  72.  
  73. -- LEFT monitor: widened columns
  74. -- Columns: >Lbl | X | Y | Z | Task(%) | Fuel(cur/inv) | Inv%Filled
  75. local function drawLeft()
  76. local m=monL
  77. m.setBackgroundColor(colors.black); m.clear()
  78. m.setTextColor(colors.white)
  79. m.setCursorPos(1,1); m.write(("Turtles: %d"):format(count(turtles)))
  80. m.setCursorPos(1,2); m.write("Label X Y Z Task(%) Fuel Inv%")
  81.  
  82. local y=3
  83. local h
  84. do local _,hh=m.getSize(); h=hh end
  85. for _,t in pairs(turtles) do
  86. if y>h then break end
  87. local lbl=(t.label or "?"):sub(1,8)
  88. local xs=(t.pos and t.pos.x) and string.format("%5d", t.pos.x) or " ?"
  89. local ys=(t.pos and t.pos.y) and string.format("%5d", t.pos.y) or " ?"
  90. local zs=(t.pos and t.pos.z) and string.format("%5d", t.pos.z) or " ?"
  91. local task,col,pct = classifyTask(t)
  92. local fuelCur = t.fuel and tostring(t.fuel) or "?"
  93. local fuelInv = t.inv and t.inv.fuelAvail and tostring(t.inv.fuelAvail) or "?"
  94. local invFilled = t.inv and t.inv.freePct and (100 - math.floor(t.inv.freePct+0.5)) or nil
  95. local invTxt = invFilled and string.format("%3d", invFilled) or " --"
  96.  
  97. m.setTextColor(colors.white)
  98. m.setCursorPos(1,y); m.write(string.format(">%-8s", lbl))
  99. m.setCursorPos(11,y); m.write(xs)
  100. m.setCursorPos(17,y); m.write(ys)
  101. m.setCursorPos(23,y); m.write(zs)
  102.  
  103. m.setCursorPos(29,y); m.setTextColor(col)
  104. m.write(string.format("%-8s", task))
  105. if pct then m.write(string.format("(%3d)", pct)) else m.write(" ") end
  106. m.setTextColor(colors.white)
  107.  
  108. m.setCursorPos(44,y); m.write(string.format("%-6s/%-6s", fuelCur, fuelInv))
  109. m.setCursorPos(58,y); m.write(invTxt)
  110.  
  111. -- focus marker
  112. if focusKey == (t.label or t.id) then
  113. m.setCursorPos(1,y); m.setTextColor(colors.cyan); m.write(">")
  114. m.setTextColor(colors.white)
  115. end
  116. y=y+1
  117. end
  118. end
  119.  
  120. -- RIGHT monitor: larger font details
  121. local function drawRight()
  122. local m=monR
  123. m.setBackgroundColor(colors.black); m.clear()
  124. m.setTextColor(colors.white)
  125. local t = focusKey and turtles[focusKey]
  126. if not t then m.setCursorPos(1,1); m.write("No focus"); return end
  127.  
  128. local task,col,pct = classifyTask(t)
  129. local invFilled = t.inv and t.inv.freePct and (100 - math.floor(t.inv.freePct+0.5)) or nil
  130.  
  131. m.setCursorPos(1,1); m.write("Focus:"); m.setTextColor(colors.cyan)
  132. m.write(" "..(t.label or ("#"..tostring(t.id)))); m.setTextColor(colors.white)
  133.  
  134. m.setCursorPos(1,3); m.write("Pos: ")
  135. m.write(t.pos and string.format("(%d,%d,%d)", t.pos.x,t.pos.y,t.pos.z) or "(?, ?, ?)")
  136.  
  137. m.setCursorPos(1,4); m.write("Facing: "..(t.facing or "?"))
  138. m.setCursorPos(1,5); m.write("Fuel: "..(t.fuel and tostring(t.fuel) or "?"))
  139. m.setCursorPos(1,6); m.write("FuelInv: "..(t.inv and t.inv.fuelAvail and tostring(t.inv.fuelAvail) or "?"))
  140. m.setCursorPos(1,7); m.write("Inv fill: "..(invFilled and (invFilled.."%") or "?"))
  141.  
  142. m.setCursorPos(1,9); m.setTextColor(col)
  143. m.write("Task: "..task..(pct and (" ("..pct.."%)") or "")); m.setTextColor(colors.white)
  144.  
  145. if t.status then m.setCursorPos(1,11); m.write("Status: "..t.status) end
  146. if t.job then
  147. m.setCursorPos(1,12); m.write("Job: "..(t.job.kind or "?"))
  148. if t.job.total then m.setCursorPos(1,13); m.write(("Steps: %d/%d"):format(t.job.done or 0, t.job.total)) end
  149. if t.job.note then m.setCursorPos(1,14); m.write("Note: "..t.job.note) end
  150. end
  151.  
  152. m.setCursorPos(1,16); m.setTextColor(colors.lightGray)
  153. m.write("help | focus <lab> | mv | svc | dump | refuel | abort/resume/stop")
  154. m.setTextColor(colors.white)
  155. end
  156.  
  157. -- ---- Send commands / job tracking ----
  158. local function findKey(lblOrId)
  159. for k,t in pairs(turtles) do
  160. if t.label==lblOrId or tostring(t.id)==tostring(lblOrId) then return k end
  161. end
  162. end
  163.  
  164. local function sendCmd(target, tbl, onAck)
  165. tbl.op="cmd"; tbl.ref=math.random(1,1e9)
  166. local tgtID=nil
  167. for _,t in pairs(turtles) do
  168. if t.label==target or tostring(t.id)==tostring(target) then tgtID=t.id break end
  169. end
  170. if not tgtID then return false,"unknown target" end
  171. rednet.send(tgtID, tbl, PROTOCOL)
  172. local tm=os.startTimer(3)
  173. while true do
  174. local ev,a,b,c = os.pullEvent()
  175. if ev=="rednet_message" then
  176. local sid,msg,proto=a,b,c
  177. if proto==PROTOCOL and type(msg)=="table" and msg.op=="ack" and msg.ref==tbl.ref then
  178. if onAck then onAck(msg) end
  179. return msg.ok, msg.err
  180. end
  181. elseif ev=="timer" and a==tm then
  182. return false,"ack timeout"
  183. end
  184. end
  185. end
  186.  
  187. -- Miner-oriented helpers
  188. local function mv(lbl, axis, len, haltAir, haltDirt)
  189. len = tonumber(len) or 0
  190. local ha = (haltAir == "1") or (haltAir == true)
  191. local hd = (haltDirt== "1") or (haltDirt== true)
  192. return sendCmd(lbl, {act="mine_vector", axis=axis, len=len, stopOnAir=ha, stopOnDirt=hd}, function()
  193. local k=findKey(lbl); if not k then return end
  194. local t=turtles[k]; t.job = {kind="work", total=math.abs(len), done=0, note=("axis "..axis)}
  195. end)
  196. end
  197.  
  198. local function service(lbl) return sendCmd(lbl, {act="return_service"}) end
  199. local function doDump(lbl) return sendCmd(lbl, {act="dump"}) end
  200. local function doRefuel(lbl) return sendCmd(lbl, {act="refuel"}) end
  201. local function doAbort(lbl) return sendCmd(lbl, {act="abort"}) end
  202. local function doResume(lbl) return sendCmd(lbl, {act="resume"}) end
  203. local function doStop(lbl) return sendCmd(lbl, {act="stop"}) end
  204. local function setFacingTag(lbl,dir) return sendCmd(lbl, {act="set_facing_tag", dir=dir}) end
  205.  
  206. -- Progress bump on movement (coarse). Any position delta advances current job by 1.
  207. local function onMinerStatusForProgress(k, prevPos)
  208. local t=turtles[k]; if not t then return end
  209. if not prevPos or not t.pos then return end
  210. if prevPos.x~=t.pos.x or prevPos.y~=t.pos.y or prevPos.z~=t.pos.z then
  211. if t.job then
  212. t.job.done = math.min((t.job.done or 0)+1, t.job.total or (t.job.done or 0))
  213. if t.job.total and t.job.done >= t.job.total then t.job=nil end
  214. end
  215. end
  216. end
  217.  
  218. -- Net + UI
  219. local function netUi()
  220. while true do
  221. local id,msg,proto = rednet.receive(PROTOCOL, 0.2)
  222. if id and proto==PROTOCOL and type(msg)=="table" and msg.op=="status" then
  223. local key = msg.label or msg.id
  224. local prevPos = key and turtles[key] and turtles[key].pos
  225. upsertStatus(msg)
  226. onMinerStatusForProgress(key, prevPos)
  227. end
  228. drawLeft(); drawRight()
  229. end
  230. end
  231.  
  232. -- REPL
  233. local function help()
  234. print("help")
  235. print("list")
  236. print("focus <label|id>")
  237. print("mv <label> <axis:x|y|z> <len> [haltAir 0/1] [haltDirt 0/1]")
  238. print("svc <label> -- return_service (dump+refuel handled on miner)")
  239. print("dump <label> -- force dump")
  240. print("refuel <label> -- force refuel")
  241. print("abort <label> | resume <label> | stop <label>")
  242. print("tagface <label> <N|E|S|W>")
  243. end
  244.  
  245. local function repl()
  246. term.clear(); term.setCursorPos(1,1); help()
  247. while true do
  248. io.write("> ")
  249. local line = read()
  250. local a,b,c,d,e,f = line:match("^(%S+)%s*(%S*)%s*(%S*)%s*(%S*)%s*(%S*)%s*(%S*)")
  251. if a=="help" then help()
  252. elseif a=="list" then
  253. for _,t in pairs(turtles) do
  254. print((t.label or "?"), t.id or "?", t.pos and (t.pos.x..","..t.pos.y..","..t.pos.z) or "?, ?, ?")
  255. end
  256. elseif a=="focus" then
  257. local k=findKey(b); if k then focusKey=k else print("unknown") end
  258. elseif a=="mv" then
  259. if b=="" or c=="" or d=="" then print("usage: mv <label> <axis:x|y|z> <len> [haltAir 0/1] [haltDirt 0/1]") else
  260. print(mv(b,c,d,e,f))
  261. end
  262. elseif a=="svc" then print(service(b))
  263. elseif a=="dump" then print(doDump(b))
  264. elseif a=="refuel" then print(doRefuel(b))
  265. elseif a=="abort" then print(doAbort(b))
  266. elseif a=="resume" then print(doResume(b))
  267. elseif a=="stop" then print(doStop(b))
  268. elseif a=="tagface" then print(setFacingTag(b,c))
  269. else print("unknown") end
  270. end
  271. end
  272.  
  273. parallel.waitForAny(netUi, repl)
  274.  
Advertisement
Add Comment
Please, Sign In to add comment