Advertisement
Elkemental

Untitled

Jun 13th, 2023 (edited)
12
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.13 KB | None | 0 0
  1. --[[
  2. Turtle Control OS
  3. Originally created by ottomated, modified by PrintedScript
  4. https://github.com/PrintedScript/turtle-control
  5. ]]
  6. -- Settings
  7. local websocketServer = "https://83de-2601-cd-c000-2ae0-00-816.ngrok-free.app"
  8.  
  9.  
  10. -- BEGIN JSON LIBRARY --
  11. local type = type
  12. local next = next
  13. local error = error
  14. local tonumber = tonumber
  15. local tostring = tostring
  16. local utf8_char = string.char
  17. local table_concat = table.concat
  18. local table_sort = table.sort
  19. local string_char = string.char
  20. local string_byte = string.byte
  21. local string_find = string.find
  22. local string_match = string.match
  23. local string_gsub = string.gsub
  24. local string_sub = string.sub
  25. local string_format = string.format
  26. local setmetatable = setmetatable
  27. local getmetatable = getmetatable
  28. local huge = math.huge
  29. local tiny = -huge
  30.  
  31. local json = {}
  32. json.object = {}
  33.  
  34. function math_type(number)
  35. if math.floor(number) == number then
  36. return "integer"
  37. else
  38. return "float"
  39. end
  40. end
  41. -- json.encode --
  42. local statusVisited
  43. local statusBuilder
  44.  
  45. local encode_map = {}
  46.  
  47. local encode_escape_map = {
  48. [ "\"" ] = "\\\"",
  49. [ "\\" ] = "\\\\",
  50. [ "/" ] = "\\/",
  51. [ "\b" ] = "\\b",
  52. [ "\f" ] = "\\f",
  53. [ "\n" ] = "\\n",
  54. [ "\r" ] = "\\r",
  55. [ "\t" ] = "\\t",
  56. }
  57.  
  58. local decode_escape_set = {}
  59. local decode_escape_map = {}
  60. for k, v in next, encode_escape_map do
  61. decode_escape_map[v] = k
  62. decode_escape_set[string_byte(v, 2)] = true
  63. end
  64.  
  65. for i = 0, 31 do
  66. local c = string_char(i)
  67. if not encode_escape_map[c] then
  68. encode_escape_map[c] = string_format("\\u%04x", i)
  69. end
  70. end
  71.  
  72. local function encode(v)
  73. local res = encode_map[type(v)](v)
  74. statusBuilder[#statusBuilder+1] = res
  75. end
  76.  
  77. encode_map["nil"] = function ()
  78. return "null"
  79. end
  80.  
  81. local function encode_string(v)
  82. return string_gsub(v, '[\0-\31\\"]', encode_escape_map)
  83. end
  84.  
  85. function encode_map.string(v)
  86. statusBuilder[#statusBuilder+1] = '"'
  87. statusBuilder[#statusBuilder+1] = encode_string(v)
  88. return '"'
  89. end
  90.  
  91. local function convertreal(v)
  92. local g = string_format('%.16g', v)
  93. if tonumber(g) == v then
  94. return g
  95. end
  96. return string_format('%.17g', v)
  97. end
  98.  
  99. if string_match(tostring(1/2), "%p") == "," then
  100. local _convertreal = convertreal
  101. function convertreal(v)
  102. return string_gsub(_convertreal(v), ',', '.')
  103. end
  104. end
  105.  
  106. function encode_map.number(v)
  107. if v ~= v or v <= tiny or v >= huge then
  108. error("unexpected number value '" .. tostring(v) .. "'")
  109. end
  110. return convertreal(v)
  111. end
  112.  
  113. function encode_map.boolean(v)
  114. if v then
  115. return "true"
  116. else
  117. return "false"
  118. end
  119. end
  120.  
  121. function encode_map.table(t)
  122. local first_val = next(t)
  123. if first_val == nil then
  124. if getmetatable(t) == json.object then
  125. return "{}"
  126. else
  127. return "[]"
  128. end
  129. end
  130. if statusVisited[t] then
  131. error("circular reference")
  132. end
  133. statusVisited[t] = true
  134. if type(first_val) == 'string' then
  135. local key = {}
  136. for k in next, t do
  137. if type(k) ~= "string" then
  138. error("invalid table: mixed or invalid key types")
  139. end
  140. key[#key+1] = k
  141. end
  142. table_sort(key)
  143. local k = key[1]
  144. statusBuilder[#statusBuilder+1] = '{"'
  145. statusBuilder[#statusBuilder+1] = encode_string(k)
  146. statusBuilder[#statusBuilder+1] = '":'
  147. encode(t[k])
  148. for i = 2, #key do
  149. local k = key[i]
  150. statusBuilder[#statusBuilder+1] = ',"'
  151. statusBuilder[#statusBuilder+1] = encode_string(k)
  152. statusBuilder[#statusBuilder+1] = '":'
  153. encode(t[k])
  154. end
  155. statusVisited[t] = nil
  156. return "}"
  157. else
  158. local max = 0
  159. for k in next, t do
  160. if math_type(k) ~= "integer" or k <= 0 then
  161. error("invalid table: mixed or invalid key types")
  162. end
  163. if max < k then
  164. max = k
  165. end
  166. end
  167. statusBuilder[#statusBuilder+1] = "["
  168. encode(t[1])
  169. for i = 2, max do
  170. statusBuilder[#statusBuilder+1] = ","
  171. encode(t[i])
  172. end
  173. statusVisited[t] = nil
  174. return "]"
  175. end
  176. end
  177.  
  178. local function encode_unexpected(v)
  179. if v == json.null then
  180. return "null"
  181. else
  182. error("unexpected type '"..type(v).."'")
  183. end
  184. end
  185. encode_map[ "function" ] = encode_unexpected
  186. encode_map[ "userdata" ] = encode_unexpected
  187. encode_map[ "thread" ] = encode_unexpected
  188.  
  189. function json.encode(v)
  190. statusVisited = {}
  191. statusBuilder = {}
  192. encode(v)
  193. return table_concat(statusBuilder)
  194. end
  195.  
  196. json._encode_map = encode_map
  197. json._encode_string = encode_string
  198.  
  199. -- json.decode --
  200.  
  201. local statusBuf
  202. local statusPos
  203. local statusTop
  204. local statusAry = {}
  205. local statusRef = {}
  206.  
  207. local function find_line()
  208. local line = 1
  209. local pos = 1
  210. while true do
  211. local f, _, nl1, nl2 = string_find(statusBuf, '([\n\r])([\n\r]?)', pos)
  212. if not f then
  213. return line, statusPos - pos + 1
  214. end
  215. local newpos = f + ((nl1 == nl2 or nl2 == '') and 1 or 2)
  216. if newpos > statusPos then
  217. return line, statusPos - pos + 1
  218. end
  219. pos = newpos
  220. line = line + 1
  221. end
  222. end
  223.  
  224. local function decode_error(msg)
  225. error(string_format("ERROR: %s at line %d col %d", msg, find_line()))
  226. end
  227.  
  228. local function get_word()
  229. return string_match(statusBuf, "^[^ \t\r\n%]},]*", statusPos)
  230. end
  231.  
  232. local function next_byte()
  233. local pos = string_find(statusBuf, "[^ \t\r\n]", statusPos)
  234. if pos then
  235. statusPos = pos
  236. return string_byte(statusBuf, pos)
  237. end
  238. return -1
  239. end
  240.  
  241. local function consume_byte(c)
  242. local _, pos = string_find(statusBuf, c, statusPos)
  243. if pos then
  244. statusPos = pos + 1
  245. return true
  246. end
  247. end
  248.  
  249. local function expect_byte(c)
  250. local _, pos = string_find(statusBuf, c, statusPos)
  251. if not pos then
  252. decode_error(string_format("expected '%s'", string_sub(c, #c)))
  253. end
  254. statusPos = pos
  255. end
  256.  
  257. local function decode_unicode_surrogate(s1, s2)
  258. return utf8_char(0x10000 + (tonumber(s1, 16) - 0xd800) * 0x400 + (tonumber(s2, 16) - 0xdc00))
  259. end
  260.  
  261. local function decode_unicode_escape(s)
  262. return utf8_char(tonumber(s, 16))
  263. end
  264.  
  265. local function decode_string()
  266. local has_unicode_escape = false
  267. local has_escape = false
  268. local i = statusPos + 1
  269. while true do
  270. i = string_find(statusBuf, '["\\\0-\31]', i)
  271. if not i then
  272. decode_error "expected closing quote for string"
  273. end
  274. local x = string_byte(statusBuf, i)
  275. if x < 32 then
  276. statusPos = i
  277. decode_error "control character in string"
  278. end
  279. if x == 34 --[[ '"' ]] then
  280. local s = string_sub(statusBuf, statusPos + 1, i - 1)
  281. if has_unicode_escape then
  282. s = string_gsub(string_gsub(s
  283. , "\\u([dD][89aAbB]%x%x)\\u([dD][c-fC-F]%x%x)", decode_unicode_surrogate)
  284. , "\\u(%x%x%x%x)", decode_unicode_escape)
  285. end
  286. if has_escape then
  287. s = string_gsub(s, "\\.", decode_escape_map)
  288. end
  289. statusPos = i + 1
  290. return s
  291. end
  292. --assert(x == 92 --[[ "\\" ]])
  293. local nx = string_byte(statusBuf, i+1)
  294. if nx == 117 --[[ "u" ]] then
  295. if not string_match(statusBuf, "^%x%x%x%x", i+2) then
  296. statusPos = i
  297. decode_error "invalid unicode escape in string"
  298. end
  299. has_unicode_escape = true
  300. i = i + 6
  301. else
  302. if not decode_escape_set[nx] then
  303. statusPos = i
  304. decode_error("invalid escape char '" .. (nx and string_char(nx) or "<eol>") .. "' in string")
  305. end
  306. has_escape = true
  307. i = i + 2
  308. end
  309. end
  310. end
  311.  
  312. local function decode_number()
  313. local num, c = string_match(statusBuf, '^([0-9]+%.?[0-9]*)([eE]?)', statusPos)
  314. if not num or string_byte(num, -1) == 0x2E --[[ "." ]] then
  315. decode_error("invalid number '" .. get_word() .. "'")
  316. end
  317. if c ~= '' then
  318. num = string_match(statusBuf, '^([^eE]*[eE][-+]?[0-9]+)[ \t\r\n%]},]', statusPos)
  319. if not num then
  320. decode_error("invalid number '" .. get_word() .. "'")
  321. end
  322. end
  323. statusPos = statusPos + #num
  324. return tonumber(num)
  325. end
  326.  
  327. local function decode_number_zero()
  328. local num, c = string_match(statusBuf, '^(.%.?[0-9]*)([eE]?)', statusPos)
  329. if not num or string_byte(num, -1) == 0x2E --[[ "." ]] or string_match(statusBuf, '^.[0-9]+', statusPos) then
  330. decode_error("invalid number '" .. get_word() .. "'")
  331. end
  332. if c ~= '' then
  333. num = string_match(statusBuf, '^([^eE]*[eE][-+]?[0-9]+)[ \t\r\n%]},]', statusPos)
  334. if not num then
  335. decode_error("invalid number '" .. get_word() .. "'")
  336. end
  337. end
  338. statusPos = statusPos + #num
  339. return tonumber(num)
  340. end
  341.  
  342. local function decode_number_negative()
  343. statusPos = statusPos + 1
  344. local c = string_byte(statusBuf, statusPos)
  345. if c then
  346. if c == 0x30 then
  347. return -decode_number_zero()
  348. elseif c > 0x30 and c < 0x3A then
  349. return -decode_number()
  350. end
  351. end
  352. decode_error("invalid number '" .. get_word() .. "'")
  353. end
  354.  
  355. local function decode_true()
  356. if string_sub(statusBuf, statusPos, statusPos+3) ~= "true" then
  357. decode_error("invalid literal '" .. get_word() .. "'")
  358. end
  359. statusPos = statusPos + 4
  360. return true
  361. end
  362.  
  363. local function decode_false()
  364. if string_sub(statusBuf, statusPos, statusPos+4) ~= "false" then
  365. decode_error("invalid literal '" .. get_word() .. "'")
  366. end
  367. statusPos = statusPos + 5
  368. return false
  369. end
  370.  
  371. local function decode_null()
  372. if string_sub(statusBuf, statusPos, statusPos+3) ~= "null" then
  373. decode_error("invalid literal '" .. get_word() .. "'")
  374. end
  375. statusPos = statusPos + 4
  376. return json.null
  377. end
  378.  
  379. local function decode_array()
  380. statusPos = statusPos + 1
  381. local res = {}
  382. if consume_byte "^[ \t\r\n]*%]" then
  383. return res
  384. end
  385. statusTop = statusTop + 1
  386. statusAry[statusTop] = true
  387. statusRef[statusTop] = res
  388. return res
  389. end
  390.  
  391. local function decode_object()
  392. statusPos = statusPos + 1
  393. local res = {}
  394. if consume_byte "^[ \t\r\n]*}" then
  395. return setmetatable(res, json.object)
  396. end
  397. statusTop = statusTop + 1
  398. statusAry[statusTop] = false
  399. statusRef[statusTop] = res
  400. return res
  401. end
  402.  
  403. local decode_uncompleted_map = {
  404. [ string_byte '"' ] = decode_string,
  405. [ string_byte "0" ] = decode_number_zero,
  406. [ string_byte "1" ] = decode_number,
  407. [ string_byte "2" ] = decode_number,
  408. [ string_byte "3" ] = decode_number,
  409. [ string_byte "4" ] = decode_number,
  410. [ string_byte "5" ] = decode_number,
  411. [ string_byte "6" ] = decode_number,
  412. [ string_byte "7" ] = decode_number,
  413. [ string_byte "8" ] = decode_number,
  414. [ string_byte "9" ] = decode_number,
  415. [ string_byte "-" ] = decode_number_negative,
  416. [ string_byte "t" ] = decode_true,
  417. [ string_byte "f" ] = decode_false,
  418. [ string_byte "n" ] = decode_null,
  419. [ string_byte "[" ] = decode_array,
  420. [ string_byte "{" ] = decode_object,
  421. }
  422. local function unexpected_character()
  423. decode_error("unexpected character '" .. string_sub(statusBuf, statusPos, statusPos) .. "'")
  424. end
  425. local function unexpected_eol()
  426. decode_error("unexpected character '<eol>'")
  427. end
  428.  
  429. local decode_map = {}
  430. for i = 0, 255 do
  431. decode_map[i] = decode_uncompleted_map[i] or unexpected_character
  432. end
  433. decode_map[-1] = unexpected_eol
  434.  
  435. local function decode()
  436. return decode_map[next_byte()]()
  437. end
  438.  
  439. local function decode_item()
  440. local top = statusTop
  441. local ref = statusRef[top]
  442. if statusAry[top] then
  443. ref[#ref+1] = decode()
  444. else
  445. expect_byte '^[ \t\r\n]*"'
  446. local key = decode_string()
  447. expect_byte '^[ \t\r\n]*:'
  448. statusPos = statusPos + 1
  449. ref[key] = decode()
  450. end
  451. if top == statusTop then
  452. repeat
  453. local chr = next_byte(); statusPos = statusPos + 1
  454. if chr == 44 --[[ "," ]] then
  455. return
  456. end
  457. if statusAry[statusTop] then
  458. if chr ~= 93 --[[ "]" ]] then decode_error "expected ']' or ','" end
  459. else
  460. if chr ~= 125 --[[ "}" ]] then decode_error "expected '}' or ','" end
  461. end
  462. statusTop = statusTop - 1
  463. until statusTop == 0
  464. end
  465. end
  466.  
  467. function json.decode(str)
  468. if type(str) ~= "string" then
  469. error("expected argument of type string, got " .. type(str))
  470. end
  471. statusBuf = str
  472. statusPos = 1
  473. statusTop = 0
  474. local res = decode()
  475. while statusTop > 0 do
  476. decode_item()
  477. end
  478. if string_find(statusBuf, "[^ \t\r\n]", statusPos) then
  479. decode_error "trailing garbage"
  480. end
  481. return res
  482. end
  483.  
  484. -- Generate a lightuserdata
  485. json.null = 12897345879
  486.  
  487. -- I stole this from you :)
  488. function getItemIndex(itemName)
  489. for slot = 1, 16, 1 do
  490. local item = turtle.getItemDetail(slot)
  491. if(item ~= nil) then
  492. if(item["name"] == itemName) then
  493. return slot
  494. end
  495. end
  496. end
  497. end
  498.  
  499. -- BEGIN MAIN CODE --
  500.  
  501. -- check if we are running on a disk
  502. if fs.exists("/disk/startup") then
  503. if not fs.exists("/startup") then
  504. fs.copy("/disk/startup", "/startup")
  505. shell.run("reboot")
  506. end
  507. end
  508.  
  509. function undergoMitosis()
  510. turtle.select(getItemIndex("computercraft:peripheral"))
  511. if not turtle.place() then
  512. return nil
  513. end
  514. turtle.select(getItemIndex("computercraft:disk_expanded"))
  515. turtle.drop()
  516. if not turtle.up() then
  517. return nil
  518. end
  519. turtle.select(getItemIndex("computercraft:turtle_expanded"))
  520. if not turtle.place() then
  521. return nil
  522. end
  523. turtle.select(1)
  524. turtle.drop(math.floor(turtle.getItemCount() / 2))
  525. os.sleep(1)
  526. peripheral.call("front", "turnOn")
  527. local cloneId = peripheral.call("front", "getID")
  528. if not turtle.down() then
  529. return nil
  530. end
  531. if not turtle.suck() then
  532. return nil
  533. end
  534. if not turtle.dig() then
  535. return nil
  536. end
  537. return cloneId
  538. end
  539.  
  540. function GetGPSLocation()
  541. local X, Y, Z = gps.locate(5)
  542. if X == nil then
  543. return nil,nil,nil
  544. end
  545. return X, Y, Z
  546. end
  547.  
  548. function mineTunnel(obj, ws)
  549. local file
  550. local blocks = {}
  551. for i=1,obj.length,1 do
  552. if obj.direction == 'forward' then
  553. turtle.dig()
  554. local success = turtle.forward()
  555. if not success then
  556. return res
  557. end
  558. ws.send(json.encode({move="f", nonce=obj.nonce}))
  559. blocks[i] = {}
  560. blocks[i][1] = select(2,turtle.inspectDown())
  561. blocks[i][2] = select(2,turtle.inspectUp())
  562. turtle.turnLeft()
  563. ws.send(json.encode({move="l", nonce=obj.nonce}))
  564. blocks[i][3] = select(2,turtle.inspect())
  565. turtle.turnRight()
  566. ws.send(json.encode({move="r", nonce=obj.nonce}))
  567. turtle.turnRight()
  568. ws.send(json.encode({move="r", nonce=obj.nonce}))
  569. blocks[i][4] = select(2,turtle.inspect())
  570. turtle.turnLeft()
  571. ws.send(json.encode({move="l", blocks=blocks[i], nonce=obj.nonce}))
  572. else
  573. if obj.direction == 'up' then
  574. turtle.digUp()
  575. local success = turtle.up()
  576. if not success then
  577. return res
  578. end
  579. ws.send(json.encode({move="u", nonce=obj.nonce}))
  580. else
  581. turtle.digDown()
  582. local success = turtle.down()
  583. if not success then
  584. return res
  585. end
  586. ws.send(json.encode({move="d", nonce=obj.nonce}))
  587. end
  588.  
  589. blocks[i] = {}
  590. blocks[i][1] = select(2,turtle.inspect())
  591. turtle.turnLeft()
  592. ws.send(json.encode({move="l", nonce=obj.nonce}))
  593.  
  594. blocks[i][2] = select(2,turtle.inspect())
  595. turtle.turnLeft()
  596. ws.send(json.encode({move="l", nonce=obj.nonce}))
  597.  
  598. blocks[i][3] = select(2,turtle.inspect())
  599. turtle.turnLeft()
  600. ws.send(json.encode({move="l", nonce=obj.nonce}))
  601.  
  602. blocks[i][4] = select(2,turtle.inspect())
  603. ws.send(json.encode({blocks=blocks[i], nonce=obj.nonce}))
  604. end
  605. end
  606. return blocks
  607. end
  608. local X,Y,Z = 0,0,0
  609. function websocketLoop()
  610.  
  611. local ws, err = http.websocket(websocketServer)
  612.  
  613. if err then
  614. print(err)
  615. elseif ws then
  616. while true do
  617. term.clear()
  618. term.setCursorPos(1,1)
  619. print("Turtle Control OS, originally created by Ottomated. Modified by PrintedScript")
  620. print("View the project on github! https://github.com/PrintedScript/turtle-control")
  621. local message = ws.receive()
  622. if message == nil then
  623. break
  624. end
  625. local obj = json.decode(message)
  626. if obj.type == 'eval' then
  627. local func = loadstring(obj['function'])
  628. local result = func()
  629. ws.send(json.encode({data=result, nonce=obj.nonce}))
  630. elseif obj.type == 'mitosis' then
  631. local status, res = pcall(undergoMitosis)
  632. if not status then
  633. ws.send(json.encode({data="null", nonce=obj.nonce}))
  634. elseif res == nil then
  635. ws.send(json.encode({data="null", nonce=obj.nonce}))
  636. else
  637. ws.send(json.encode({data=res, nonce=obj.nonce}))
  638. end
  639. elseif obj.type == 'mine' then
  640. local status, res = pcall(mineTunnel, obj, ws)
  641. ws.send(json.encode({data="end", nonce=obj.nonce}))
  642. elseif obj.type == 'location' then
  643. X,Y,Z = GetGPSLocation()
  644. if X == nil then
  645. ws.send(json.encode({data="null", nonce=obj.nonce}))
  646. else
  647. ws.send(json.encode({data={X,Y,Z}, nonce=obj.nonce}))
  648. end
  649. end
  650. end
  651. end
  652. if ws then
  653. ws.close()
  654. end
  655. end
  656.  
  657. while true do
  658. local status, res = pcall(websocketLoop)
  659. term.clear()
  660. term.setCursorPos(1,1)
  661. if res == 'Terminated' then
  662. print("Turtle Control OS terminated")
  663. break
  664. end
  665. print("Sleeping for 5 seconds before attempting reconnection - Turtle Control OS - https://github.com/PrintedScript/turtle-control")
  666. os.sleep(5)
  667. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement