Stevemine26

turtle_server

Jul 7th, 2025
76
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 13.14 KB | None | 0 0
  1. -- turtle_server with local and remote command input
  2.  
  3. -- Auto-detect and open wireless modem
  4. local opened = false
  5. for _, side in ipairs({"left", "right", "top", "bottom", "back"}) do
  6.     if peripheral.getType(side) == "modem" and peripheral.call(side, "isWireless") then
  7.         rednet.open(side)
  8.         print("Opened modem on " .. side)
  9.         opened = true
  10.         break
  11.     end
  12. end
  13.  
  14. if not opened then
  15.     print("No wireless modem found.")
  16. end
  17.  
  18. local password = "test"  -- set to "" to disable
  19. local secured = password ~= ""
  20. local authenticatedClients = {} -- stores senderIDs who passed auth
  21. local selected_slot = turtle.getSelectedSlot()
  22. local commandLog = {} -- logs movement for return_home
  23. local remoteNames = {}  -- senderID -> name
  24. local localName = "turtle"
  25. local awaitingInput = false
  26.  
  27. -- Position tracking
  28. local position = { x = 0, y = 0, z = 0 }
  29. local facing = 0 -- 0 = north, 1 = east, 2 = south, 3 = west
  30. local home = { x = 0, y = 0, z = 0, facing = 0 }
  31.  
  32. -- Direction vectors
  33. local directions = {
  34.     [0] = { x = 0, z = -1 }, -- North
  35.     [1] = { x = 1, z = 0 },  -- East
  36.     [2] = { x = 0, z = 1 },  -- South
  37.     [3] = { x = -1, z = 0 }  -- West
  38. }
  39.  
  40. print("Turtle is online and listening...")
  41. if secured then print("password is: " .. password) end
  42.  
  43. -- Helper functions
  44. local function repeatAction(amount, action, direction)
  45.     amount = tonumber(amount) or 1
  46.     for i = 1, amount do
  47.         local success, result = pcall(action)
  48.         if success and result then
  49.             if direction == "forward" then
  50.                 table.insert(commandLog, "back")
  51.             elseif direction == "back" then
  52.                 table.insert(commandLog, "forward")
  53.             elseif direction == "up" then
  54.                 table.insert(commandLog, "down")
  55.             elseif direction == "down" then
  56.                 table.insert(commandLog, "up")
  57.             elseif direction == "right" then
  58.                 table.insert(commandLog, "left")
  59.             elseif direction == "left" then
  60.                 table.insert(commandLog, "right")
  61.             end
  62.         elseif not result then
  63.             return false, "Blocked: " .. direction
  64.         elseif not success then
  65.             return false, "Error: " .. tostring(result)
  66.         end
  67.     end
  68.     return true
  69. end
  70.  
  71.  
  72.  
  73. local function randomObjectFromTable(t)
  74.     return t[math.random(1, #t)]
  75. end
  76.  
  77. -- [NEW] Core command handler (shared by both local and remote input)
  78. local function handleCommand(input, senderID)
  79.     local args = {}
  80.     for word in string.gmatch(input, "%S+") do
  81.         table.insert(args, word)
  82.     end
  83.  
  84.     local command = args[1]
  85.     local success, err, replyMessage
  86.  
  87.     if command == "forward" then
  88.         success, err = repeatAction(args[2], turtle.forward, "forward")
  89.         replyMessage = success and "Moved forward" or ("Error moving forward: " .. tostring(err))
  90.  
  91.     elseif command == "back" then
  92.         success, err = repeatAction(args[2], turtle.back, "back")
  93.         replyMessage = success and "Moved back" or ("Error moving back: " .. tostring(err))
  94.  
  95.     elseif command == "left" then
  96.         success, err = repeatAction(args[2], turtle.turnLeft, "left")
  97.         replyMessage = success and "Turned left" or ("Error turning left: " .. tostring(err))
  98.  
  99.     elseif command == "right" then
  100.         success, err = repeatAction(args[2], turtle.turnRight, "right")
  101.         replyMessage = success and "Turned right" or ("Error turning right: " .. tostring(err))
  102.  
  103.     elseif command == "180" then
  104.         local maybe = {true, false}
  105.         if randomObjectFromTable(maybe) then
  106.             success, err = repeatAction(2, turtle.turnLeft, "left")
  107.             replyMessage = success and "Turned 180 degress left" or ("Error turning 180 degress left: " .. tostring(err))
  108.         else
  109.             success, err = repeatAction(2, turtle.turnRight, "right")
  110.             replyMessage = success and "Turned 180 degress right" or ("Error turning 180 degress right: " .. tostring(err))
  111.         end
  112.  
  113.     elseif command == "up" then
  114.         success, err = repeatAction(args[2], turtle.up, "up")
  115.         replyMessage = success and "Moved up" or ("Error moving up: " .. tostring(err))
  116.  
  117.     elseif command == "down" then
  118.         success, err = repeatAction(args[2], turtle.down, "down")
  119.         replyMessage = success and "Moved down" or ("Error moving down: " .. tostring(err))
  120.  
  121.     elseif command == "dig" then
  122.         local right = turtle.getEquippedRight()
  123.         if right and right.name ~= "minecraft:diamond_pickaxe" then
  124.             local selected_slot = turtle.getSelectedSlot()
  125.             turtle.select(16)
  126.             turtle.equipRight()
  127.             turtle.select(selected_slot)
  128.         end
  129.         local dir = args[2] or "forward"
  130.         if dir == "up" then
  131.             success, err = pcall(turtle.digUp)
  132.             replyMessage = success and "Dug up" or ("Error digging up: " .. tostring(err))
  133.         elseif dir == "down" then
  134.             success, err = pcall(turtle.digDown)
  135.             replyMessage = success and "Dug down" or ("Error digging down: " .. tostring(err))
  136.         else
  137.             success, err = pcall(turtle.dig)
  138.             replyMessage = success and "Dug forward" or ("Error digging forward: " .. tostring(err))
  139.         end
  140.  
  141.     elseif command == "attack" then
  142.         local right = turtle.getEquippedRight()
  143.         if right and right.name ~= "minecraft:diamond_sword" then
  144.             local selected_slot = turtle.getSelectedSlot()
  145.             turtle.select(16)
  146.             turtle.equipRight()
  147.             turtle.select(selected_slot)
  148.         end
  149.         local dir = args[2] or "forward"
  150.         if dir == "up" then
  151.             success, err = pcall(turtle.attackUp)
  152.             replyMessage = success and "Attacked up" or ("Error attacking up: " .. tostring(err))
  153.         elseif dir == "down" then
  154.             success, err = pcall(turtle.attackDown)
  155.             replyMessage = success and "Attacked down" or ("Error attacking down: " .. tostring(err))
  156.         else
  157.             success, err = pcall(turtle.attack)
  158.             replyMessage = success and "Attacked forward" or ("Error attacking forward: " .. tostring(err))
  159.         end
  160.  
  161.     elseif command == "place" then
  162.         local dir = args[2] or "forward"
  163.         if dir == "up" then
  164.             success, err = pcall(turtle.placeUp)
  165.             replyMessage = success and "Placed up" or ("Error placing up: " .. tostring(err))
  166.         elseif dir == "down" then
  167.             success, err = pcall(turtle.placeDown)
  168.             replyMessage = success and "Placed down" or ("Error placing down: " .. tostring(err))
  169.         else
  170.             success, err = pcall(turtle.place)
  171.             replyMessage = success and "Placed forward" or ("Error placing forward: " .. tostring(err))
  172.         end
  173.  
  174.     elseif (command == "select" or command == "slot") and args[2] then
  175.         if args[2] == "help" then
  176.             replyMessage = "Use select/slot <1-15>"
  177.         else
  178.             local slot = tonumber(args[2])
  179.             if slot and slot >= 1 and slot <= 15 then
  180.                 selected_slot = slot
  181.                 turtle.select(selected_slot)
  182.                 replyMessage = "Selected slot " .. slot
  183.             else
  184.                 replyMessage = "Invalid slot number."
  185.             end
  186.         end
  187.  
  188.     elseif command == "name" and args[2] then
  189.         local newName = table.concat(args, " ", 2)
  190.  
  191.         if senderID then
  192.             remoteNames[senderID] = newName
  193.             replyMessage = "Name set to '" .. newName .. "'"
  194.         else
  195.             localName = newName
  196.             replyMessage = "Local name set to '" .. newName .. "'"
  197.         end
  198.  
  199.     elseif command == "whoami" then
  200.         if senderID then
  201.             local name = remoteNames[senderID]
  202.             if name then
  203.                 replyMessage = "You are named '" .. name .. "'"
  204.             else
  205.                 replyMessage = "You are senderID #" .. tostring(senderID)
  206.             end
  207.         else
  208.             replyMessage = "You are named '" .. localName .. "'"
  209.         end
  210.  
  211.     elseif command == "print" and args[2] then
  212.         local message = table.concat(args, " ", 2)
  213.         replyMessage = message
  214.  
  215.     elseif command == "set_home" then
  216.         commandLog = {}
  217.         replyMessage = "Set home."
  218.  
  219.     elseif command == "return_home" or command == "home" then
  220.         for i = #commandLog, 1, -1 do
  221.             local reverseCmd = commandLog[i]
  222.             handleCommand(reverseCmd, nil) -- simulate local call
  223.         end
  224.         commandLog = {} -- optional: clear log after returning
  225.         replyMessage = "Returned home."
  226.  
  227.     elseif command == "dump" then
  228.         local selected_slot = turtle.getSelectedSlot()
  229.         local dir = args[2] or "down"
  230.         local dropped = 0
  231.  
  232.         for slot = 1, 15 do -- skip slot 16
  233.             turtle.select(slot)
  234.             local item = turtle.getItemDetail()
  235.             if item then
  236.                 local success
  237.                 if dir == "up" then
  238.                     success = turtle.dropUp()
  239.                 elseif dir == "forward" then
  240.                     success = turtle.drop()
  241.                 else
  242.                     success = turtle.dropDown()
  243.                 end
  244.                if success then
  245.                     dropped = dropped + 1
  246.                 end
  247.             end
  248.         end
  249.         turtle.select(selected_slot)
  250.  
  251.         turtle.select(selected_slot or 1)
  252.         replyMessage = "Dropped " .. dropped .. " item stacks to the " .. dir
  253.  
  254.     elseif command == "exit" or command == off then
  255.         replyMessage = "Shutting down on command."
  256.         if senderID then rednet.send(senderID, replyMessage) end
  257.         print(replyMessage)
  258.         os.shutdown() -- Immediate exit
  259.  
  260.     else
  261.         replyMessage = "Unknown command."
  262.     end
  263.  
  264.     if senderID and replyMessage then
  265.         rednet.send(senderID, replyMessage)
  266.     elseif not senderID then
  267.         print("< " .. replyMessage)
  268.         if awaitingInput then
  269.             local x, y = term.getCursorPos()
  270.             local w, h = term.getSize()
  271.             term.setCursorPos(1, y)
  272.             term.clearLine()
  273.             term.write(localName .. "> ")
  274.         end
  275.     end
  276. end
  277.  
  278. -- [NEW] Thread 1: Remote command listener
  279. local function listenRednet()
  280.     while true do
  281.         local senderID, message = rednet.receive()
  282.  
  283.         if type(message) == "string" then
  284.             local displayName = remoteNames[senderID] or tostring(senderID)
  285.             if remoteNames[senderID] then
  286.                 print("Remote message from " .. displayName .. " (" .. senderID .. "): " .. message)
  287.                 if awaitingInput then
  288.                     local x, y = term.getCursorPos()
  289.                     local w, h = term.getSize()
  290.                     term.setCursorPos(1, y)
  291.                     term.clearLine()
  292.                     term.write(localName .. "> ")
  293.                 end
  294.             else
  295.                 print("Remote message from " .. displayName .. ": " .. message)
  296.                 if awaitingInput then
  297.                     local x, y = term.getCursorPos()
  298.                     local w, h = term.getSize()
  299.                     term.setCursorPos(1, y)
  300.                     term.clearLine()
  301.                     term.write(localName .. "> ")
  302.                 end
  303.             end
  304.  
  305.             if secured and not authenticatedClients[senderID] then
  306.                 -- Require authentication first
  307.                 local args = {}
  308.                 for word in string.gmatch(message, "%S+") do
  309.                     table.insert(args, word)
  310.                 end
  311.  
  312.                 if args[1] == "auth" and args[2] == password then
  313.                     authenticatedClients[senderID] = true
  314.                     rednet.send(senderID, "Authentication successful.")
  315.                     print("Client " .. senderID .. " authenticated.")
  316.                     if awaitingInput then
  317.                         local x, y = term.getCursorPos()
  318.                         local w, h = term.getSize()
  319.                         term.setCursorPos(1, y)
  320.                         term.clearLine()
  321.                         term.write(localName .. "> ")
  322.                     end
  323.                 else
  324.                     rednet.send(senderID, "Please authenticate with: auth <password>")
  325.                     print("Blocked command from unauthenticated client " .. senderID)
  326.                     if awaitingInput then
  327.                         local x, y = term.getCursorPos()
  328.                         local w, h = term.getSize()
  329.                         term.setCursorPos(1, y)
  330.                         term.clearLine()
  331.                         term.write(localName .. "> ")
  332.                     end
  333.                 end
  334.             else
  335.                 -- Already authenticated
  336.                 handleCommand(message, senderID)
  337.             end
  338.         end
  339.     end
  340. end
  341.  
  342. -- [NEW] Thread 2: Local command listener
  343. local function listenKeyboard()
  344.     while true do
  345.         term.write(localName .. "> ")
  346.         awaitingInput = true
  347.         local input = read()
  348.         awaitingInput = false
  349.         handleCommand(input, nil)
  350.     end
  351. end
  352.  
  353. -- [NEW] Run both listeners simultaneously
  354. parallel.waitForAny(listenRednet, listenKeyboard)
  355.  
Tags: Cc
Advertisement
Add Comment
Please, Sign In to add comment