Myros27

DefragBot

May 18th, 2025 (edited)
220
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 24.98 KB | None | 0 0
  1. --[[
  2.     DefragBot v0.4 - Merged Version (Fixes + Mult command)
  3.     Combines movement library and bot logic into a single file.
  4.     Provides chat commands to test movement functions.
  5.     Fixes:
  6.     - Peripheral name for End Automata to "endAutomata".
  7.     - Nil concatenation error during initialization log message.
  8.     - Better handling of automata peripheral not being found.
  9.     - Refined argument parsing for the 'cmd' subcommand.
  10.     New Features:
  11.     - Added 'mult' command for sequential basic movements (e.g., @defrag mult lffr).
  12. ]]
  13.  
  14. --#region Configuration (Bot Specific)
  15. local CHAT_BOX_PERIPHERAL_NAME = "chatBox"
  16. local COMMAND_PREFIX = "@defrag"
  17. local CHAT_BOT_NAME = "DefragBot"
  18. local CHAT_BOT_BRACKETS = "[]"
  19. local CHAT_BOT_BRACKET_COLOR = "&3" -- Cyan
  20. --#endregion
  21.  
  22. --#region Movement Library Code (Integrated)
  23.  
  24. --##region Movement Library Configuration and State
  25. local AUTOMATA_PERIPHERAL_NAME = "endAutomata"
  26. local POSITION_FILE = "turtle_pos.json"
  27. local REFUEL_SLOT = 16
  28. local FUEL_ITEM_NAME_PART = "coal"
  29.  
  30. local automata = nil
  31. local current_pos = { x = nil, y = nil, z = nil }
  32. local current_dir = nil
  33.  
  34. local DIR_VECTORS = {
  35.     [0] = {x = 0, y = 0, z = 1},  [1] = {x = 1, y = 0, z = 0},
  36.     [2] = {x = 0, y = 0, z = -1}, [3] = {x = -1, y = 0, z = 0}
  37. }
  38. local DIR_NAMES = {
  39.     [0] = "North (+Z)", [1] = "East (+X)",
  40.     [2] = "South (-Z)", [3] = "West (-X)"
  41. }
  42. --##endregion
  43.  
  44. --##region Movement Library Helper Functions (Internal)
  45. local function moveLog(message) print("[MoveLib] " .. message) end
  46.  
  47. local function savePosition()
  48.     if current_pos.x == nil or current_dir == nil then moveLog("Cannot save position, state is unknown."); return end
  49.     local data = { x = current_pos.x, y = current_pos.y, z = current_pos.z, dir = current_dir }
  50.     local file, err = fs.open(POSITION_FILE, "w")
  51.     if file then
  52.         file.write(textutils.serialiseJSON(data)); file.close()
  53.         moveLog("Position saved: X:" .. data.x .. " Y:" .. data.y .. " Z:" .. data.z .. " Dir:" .. (DIR_NAMES[current_dir] or "Unknown"))
  54.     else moveLog("Error saving position: " .. (err or "unknown")) end
  55. end
  56.  
  57. local function loadPosition()
  58.     if fs.exists(POSITION_FILE) then
  59.         local file, err = fs.open(POSITION_FILE, "r")
  60.         if file then
  61.             local sData = file.readAll(); file.close()
  62.             local success, data = pcall(textutils.unserialiseJSON, sData)
  63.             if success and data and data.x ~= nil and data.y ~= nil and data.z ~= nil and data.dir ~= nil then
  64.                 current_pos.x = data.x; current_pos.y = data.y; current_pos.z = data.z; current_dir = data.dir
  65.                 moveLog("Position loaded: X:" .. current_pos.x .. " Y:" .. current_pos.y .. " Z:" .. current_pos.z .. " Dir:" .. (DIR_NAMES[current_dir] or "Unknown"))
  66.                 return true
  67.             else moveLog("Failed to parse position file or data invalid: " .. tostring(data)) end
  68.         else moveLog("Error opening position file: " .. (err or "unknown")) end
  69.     else moveLog("Position file not found.") end
  70.     return false
  71. end
  72.  
  73. local function dirNameToNumber(name)
  74.     name = string.lower(name or ""); if name == "n" or name == "north" then return 0
  75.     elseif name == "e" or name == "east" then return 1 elseif name == "s" or name == "south" then return 2
  76.     elseif name == "w" or name == "west" then return 3 end
  77.     moveLog("Warning: Invalid direction name '" .. (name or "nil") .. "'. Defaulting to North."); return 0
  78. end
  79. --##endregion
  80.  
  81. --##region Movement Library Core Movement and Action Functions
  82. local function turnLeft()
  83.     if current_dir == nil then moveLog("Cannot turn: direction unknown."); return false end
  84.     if turtle.turnLeft() then
  85.         current_dir = (current_dir - 1 + 4) % 4
  86.         moveLog("Turned Left. New Dir: " .. (DIR_NAMES[current_dir] or "Unknown")); savePosition(); return true
  87.     else moveLog("Failed to turn left."); return false end
  88. end
  89.  
  90. local function turnRight()
  91.     if current_dir == nil then moveLog("Cannot turn: direction unknown."); return false end
  92.     if turtle.turnRight() then
  93.         current_dir = (current_dir + 1) % 4
  94.         moveLog("Turned Right. New Dir: " .. (DIR_NAMES[current_dir] or "Unknown")); savePosition(); return true
  95.     else moveLog("Failed to turn right."); return false end
  96. end
  97.  
  98. local function turnAround()
  99.     if current_dir == nil then moveLog("Cannot turn around: direction unknown."); return false end
  100.     moveLog("Turning around..."); if turnRight() and turnRight() then
  101.         moveLog("Turned Around. New Dir: " .. (DIR_NAMES[current_dir] or "Unknown")); return true
  102.     else moveLog("Failed to turn around completely."); return false end
  103. end
  104.  
  105. local function forward()
  106.     if current_pos.x == nil then moveLog("Cannot move: position unknown."); return false end
  107.     if turtle.forward() then
  108.         local vec = DIR_VECTORS[current_dir]
  109.         current_pos.x = current_pos.x + vec.x; current_pos.y = current_pos.y + vec.y
  110.         current_pos.z = current_pos.z + vec.z
  111.         moveLog("Moved Forward. New Pos: X:" .. current_pos.x .. " Y:" .. current_pos.y .. " Z:" .. current_pos.z); savePosition(); return true
  112.     else moveLog("Failed to move forward (blocked)."); return false end
  113. end
  114.  
  115. local function back()
  116.     if current_pos.x == nil then moveLog("Cannot move: position unknown."); return false end
  117.     if turtle.back() then
  118.         local vec = DIR_VECTORS[current_dir]
  119.         current_pos.x = current_pos.x - vec.x; current_pos.y = current_pos.y - vec.y
  120.         current_pos.z = current_pos.z - vec.z
  121.         moveLog("Moved Back. New Pos: X:" .. current_pos.x .. " Y:" .. current_pos.y .. " Z:" .. current_pos.z); savePosition(); return true
  122.     else moveLog("Failed to move back (blocked)."); return false end
  123. end
  124.  
  125. local function up()
  126.     if current_pos.y == nil then moveLog("Cannot move up: Y position unknown."); return false end
  127.     if turtle.up() then
  128.         current_pos.y = current_pos.y + 1
  129.         moveLog("Moved Up. New Pos: X:" .. current_pos.x .. " Y:" .. current_pos.y .. " Z:" .. current_pos.z); savePosition(); return true
  130.     else moveLog("Failed to move up (blocked or no fuel)."); return false end
  131. end
  132.  
  133. local function down()
  134.     if current_pos.y == nil then moveLog("Cannot move down: Y position unknown."); return false end
  135.     if turtle.down() then
  136.         current_pos.y = current_pos.y - 1
  137.         moveLog("Moved Down. New Pos: X:" .. current_pos.x .. " Y:" .. current_pos.y .. " Z:" .. current_pos.z); savePosition(); return true
  138.     else moveLog("Failed to move down (blocked)."); return false end
  139. end
  140.  
  141. local function home()
  142.     if not automata then automata = peripheral.find(AUTOMATA_PERIPHERAL_NAME)
  143.         if not automata then moveLog("Error: End Automata ('"..AUTOMATA_PERIPHERAL_NAME.."') not found."); return false end
  144.     end
  145.     moveLog("Attempting to warp to 'home'...")
  146.     local success, result = pcall(function() return automata.warpToPoint("home") end)
  147.     if success and result then
  148.         moveLog("Warped to home successfully.")
  149.         current_pos.x = 0; current_pos.y = 0; current_pos.z = 0; current_dir = 0
  150.         moveLog("Position reset to home (0,0,0,N)."); savePosition(); return true
  151.     else moveLog("Failed to warp to home: " .. tostring(result or "pcall error or peripheral method failed")); return false end
  152. end
  153.  
  154. local function refuel()
  155.     moveLog("Starting refuel process..."); local initialFuel = turtle.getFuelLevel()
  156.     moveLog("Initial fuel level: " .. initialFuel); turtle.select(REFUEL_SLOT)
  157.     local fuelInSlot = turtle.getItemCount(REFUEL_SLOT)
  158.     if fuelInSlot > 0 then moveLog("Fuel in slot " .. REFUEL_SLOT .. ": " .. fuelInSlot) end
  159.     local suckedCount = 0; local maxStackSize
  160.     local currentSpace = turtle.getItemSpace(REFUEL_SLOT)
  161.     if currentSpace == 0 and fuelInSlot > 0 then maxStackSize = 64 - fuelInSlot
  162.     elseif currentSpace == 0 and fuelInSlot == 0 then maxStackSize = 64
  163.     else maxStackSize = currentSpace end
  164.     moveLog("Sucking fuel. Slot " .. REFUEL_SLOT .. ". Space: " .. maxStackSize)
  165.     while turtle.getItemSpace(REFUEL_SLOT) > 0 do
  166.         local itemDetail = turtle.getItemDetail(REFUEL_SLOT)
  167.         if itemDetail and not string.find(string.lower(itemDetail.name), FUEL_ITEM_NAME_PART) then
  168.             moveLog("Item in slot " .. REFUEL_SLOT .. " (" .. itemDetail.name .. ") not fuel. Stop."); break
  169.         end
  170.         if turtle.suck() then
  171.             suckedCount = suckedCount + 1; -- moveLog("Sucked 1. Total: " .. suckedCount) -- Reduce log spam
  172.             if turtle.getItemCount(REFUEL_SLOT) >= 64 then moveLog("Slot " .. REFUEL_SLOT .. " full."); break end
  173.         else moveLog("Failed to suck/chest empty. Sucked: " .. suckedCount); break end
  174.         sleep(0.1)
  175.     end
  176.     if suckedCount > 0 then moveLog("Total sucked: " .. suckedCount) end
  177.     turtle.select(REFUEL_SLOT)
  178.     if turtle.getItemCount(REFUEL_SLOT) > 0 then
  179.         moveLog("Refueling from slot " .. REFUEL_SLOT .. "...")
  180.         if turtle.refuel(0) then moveLog("Successfully refueled.")
  181.         else moveLog("Refuel command failed/no fuel items in slot " .. REFUEL_SLOT .. ".") end
  182.     else moveLog("No fuel items in slot " .. REFUEL_SLOT .. " to refuel.") end
  183.     moveLog("Refuel finished. Fuel: " .. turtle.getFuelLevel())
  184.     return turtle.getFuelLevel() == "unlimited" or turtle.getFuelLevel() > initialFuel
  185. end
  186.  
  187. local function setPos(x, y, z, dir_name_or_num)
  188.     if type(x)~="number" or type(y)~="number" or type(z)~="number" then moveLog("Err: setPos xyz num."); return false end
  189.     current_pos.x = x; current_pos.y = y; current_pos.z = z
  190.     if type(dir_name_or_num) == "number" then current_dir = dir_name_or_num % 4
  191.     else current_dir = dirNameToNumber(dir_name_or_num) end
  192.     moveLog("Pos set: X:"..x.." Y:"..y.." Z:"..z.." Dir:"..(DIR_NAMES[current_dir] or "Unk")); savePosition(); return true
  193. end
  194. --##endregion
  195.  
  196. --##region Movement Library Advanced Movement (Pathfinding)
  197. local function turnToDir(target_dir_num)
  198.     if current_dir == nil then moveLog("Cannot turnToDir: dir unknown."); return false end
  199.     if current_dir == target_dir_num then return true end
  200.     moveLog("Turning to target dir: " .. (DIR_NAMES[target_dir_num] or "Unk"))
  201.     local diff = (target_dir_num - current_dir + 4) % 4
  202.     if diff == 1 then return turnRight() elseif diff == 2 then return turnAround()
  203.     elseif diff == 3 then return turnLeft() end; return false
  204. end
  205.  
  206. local function moveTo(targetX, targetY, targetZ, targetDir_name_or_num)
  207.     if current_pos.x == nil then moveLog("Cannot moveTo: current pos unknown."); return false end
  208.     moveLog(string.format("MoveTo: Target X:%s Y:%s Z:%s Dir:%s", tostring(targetX),tostring(targetY),tostring(targetZ),tostring(targetDir_name_or_num)))
  209.     local target_dir_num
  210.     if type(targetDir_name_or_num)=="number" then target_dir_num=targetDir_name_or_num%4 else target_dir_num=dirNameToNumber(targetDir_name_or_num) end
  211.     local attempts=0; local max_total_attempts=100; local max_stuck_attempts_per_axis=3
  212.     while (current_pos.x~=targetX or current_pos.y~=targetY or current_pos.z~=targetZ) and attempts<max_total_attempts do
  213.         attempts=attempts+1; local moved_this_cycle=false; local current_axis_stuck_attempts=0
  214.         -- Y movement
  215.         if current_pos.y < targetY then
  216.             if up() then moved_this_cycle=true else
  217.                 current_axis_stuck_attempts=current_axis_stuck_attempts+1
  218.                 moveLog("moveTo: Blocked UP ("..current_axis_stuck_attempts..")")
  219.                 if (current_pos.x~=targetX or current_pos.z~=targetZ) and current_axis_stuck_attempts<max_stuck_attempts_per_axis then -- try other axes
  220.                 elseif current_axis_stuck_attempts<max_stuck_attempts_per_axis then if turnToDir(math.random(0,3)) and forward() then moved_this_cycle=true end
  221.                 else moveLog("moveTo: Stuck Y (up). Abort Y."); targetY=current_pos.y end
  222.             end
  223.         elseif current_pos.y > targetY then
  224.             if down() then moved_this_cycle=true else
  225.                 current_axis_stuck_attempts=current_axis_stuck_attempts+1
  226.                 moveLog("moveTo: Blocked DOWN ("..current_axis_stuck_attempts..")")
  227.                 if (current_pos.x~=targetX or current_pos.z~=targetZ) and current_axis_stuck_attempts<max_stuck_attempts_per_axis then
  228.                 elseif current_axis_stuck_attempts<max_stuck_attempts_per_axis then if turnToDir(math.random(0,3)) and forward() then moved_this_cycle=true end
  229.                 else moveLog("moveTo: Stuck Y (down). Abort Y."); targetY=current_pos.y end
  230.             end
  231.         end
  232.         if moved_this_cycle then goto continue_main_loop end; current_axis_stuck_attempts=0
  233.  
  234.         -- X movement
  235.         if current_pos.x < targetX then
  236.             if turnToDir(1) and forward() then moved_this_cycle=true else
  237.                 current_axis_stuck_attempts=current_axis_stuck_attempts+1; moveLog("moveTo: Blocked EAST ("..current_axis_stuck_attempts..")")
  238.                 if current_pos.z~=targetZ and current_axis_stuck_attempts<max_stuck_attempts_per_axis then
  239.                 elseif current_axis_stuck_attempts<max_stuck_attempts_per_axis then if turnToDir((math.random(0,1)*2)) and forward() then moved_this_cycle=true end
  240.                 else moveLog("moveTo: Stuck X (east). Abort X."); targetX=current_pos.x end
  241.             end
  242.         elseif current_pos.x > targetX then
  243.             if turnToDir(3) and forward() then moved_this_cycle=true else
  244.                 current_axis_stuck_attempts=current_axis_stuck_attempts+1; moveLog("moveTo: Blocked WEST ("..current_axis_stuck_attempts..")")
  245.                 if current_pos.z~=targetZ and current_axis_stuck_attempts<max_stuck_attempts_per_axis then
  246.                 elseif current_axis_stuck_attempts<max_stuck_attempts_per_axis then if turnToDir((math.random(0,1)*2)) and forward() then moved_this_cycle=true end
  247.                 else moveLog("moveTo: Stuck X (west). Abort X."); targetX=current_pos.x end
  248.             end
  249.         end
  250.         if moved_this_cycle then goto continue_main_loop end; current_axis_stuck_attempts=0
  251.  
  252.         -- Z movement
  253.         if current_pos.z < targetZ then
  254.             if turnToDir(0) and forward() then moved_this_cycle=true else
  255.                 current_axis_stuck_attempts=current_axis_stuck_attempts+1; moveLog("moveTo: Blocked NORTH ("..current_axis_stuck_attempts..")")
  256.                 if current_pos.x~=targetX and current_axis_stuck_attempts<max_stuck_attempts_per_axis then
  257.                 elseif current_axis_stuck_attempts<max_stuck_attempts_per_axis then if turnToDir((math.random(0,1)*2)+1) and forward() then moved_this_cycle=true end
  258.                 else moveLog("moveTo: Stuck Z (north). Abort Z."); targetZ=current_pos.z end
  259.             end
  260.         elseif current_pos.z > targetZ then
  261.             if turnToDir(2) and forward() then moved_this_cycle=true else
  262.                 current_axis_stuck_attempts=current_axis_stuck_attempts+1; moveLog("moveTo: Blocked SOUTH ("..current_axis_stuck_attempts..")")
  263.                 if current_pos.x~=targetX and current_axis_stuck_attempts<max_stuck_attempts_per_axis then
  264.                 elseif current_axis_stuck_attempts<max_stuck_attempts_per_axis then if turnToDir((math.random(0,1)*2)+1) and forward() then moved_this_cycle=true end
  265.                 else moveLog("moveTo: Stuck Z (south). Abort Z."); targetZ=current_pos.z end
  266.             end
  267.         end
  268.         if moved_this_cycle then goto continue_main_loop end
  269.  
  270.         if not moved_this_cycle then moveLog("moveTo: No move this cycle. Attempts: "..attempts); if current_axis_stuck_attempts>=max_stuck_attempts_per_axis then break end end
  271.         ::continue_main_loop::
  272.         sleep(0.05)
  273.     end
  274.     if attempts>=max_total_attempts then moveLog("moveTo: Max total attempts.") end
  275.     if not turnToDir(target_dir_num) then moveLog("moveTo: Failed final turn.") end
  276.     local success=current_pos.x==targetX and current_pos.y==targetY and current_pos.z==targetZ and current_dir==target_dir_num
  277.     if success then moveLog("moveTo: Success.") else moveLog(string.format("moveTo: Finished. Pos X:%s Y:%s Z:%s Dir:%s.",tostring(current_pos.x),tostring(current_pos.y),tostring(current_pos.z),(DIR_NAMES[current_dir]or"Unk"))) end
  278.     return success
  279. end
  280. --##endregion
  281.  
  282. --##region Movement Library Initialization
  283. local function initMoveLibrary()
  284.     moveLog("Initializing Integrated Move Library...")
  285.     automata = peripheral.find(AUTOMATA_PERIPHERAL_NAME)
  286.     if not automata then moveLog("CRIT WARN: End Automata ('"..AUTOMATA_PERIPHERAL_NAME.."') missing. Home warp fail.") end
  287.     if not loadPosition() then
  288.         moveLog("Pos unknown/load fail. Warp home & set default.")
  289.         if home() then moveLog("Init at home success.")
  290.         else moveLog("CRIT: Fail init at home. Pos unknown."); current_pos.x=nil;current_pos.y=nil;current_pos.z=nil;current_dir=nil end
  291.     end
  292.     moveLog("MoveLib Init. Pos: X:"..tostring(current_pos.x).." Y:"..tostring(current_pos.y).." Z:"..tostring(current_pos.z).." Dir:"..(current_dir and DIR_NAMES[current_dir]or"Unk"))
  293. end
  294.  
  295. local function getPosition() return current_pos end
  296. local function getDirection() return current_dir end
  297. local function getDirectionName() return current_dir and DIR_NAMES[current_dir] or "Unknown" end
  298.  
  299. local ml = {
  300.     l=turnLeft,turnLeft=turnLeft,r=turnRight,turnRight=turnRight,f=forward,forward=forward,b=back,back=back,
  301.     a=turnAround,turnAround=turnAround,u=up,up=up,d=down,down=down,h=home,home=home,
  302.     refuel=refuel,setPos=setPos,m=moveTo,moveTo=moveTo,
  303.     getPosition=getPosition,getDirection=getDirection,getDirectionName=getDirectionName,
  304.     init=initMoveLibrary
  305. }
  306. initMoveLibrary()
  307. --##endregion End of Movement Library Code
  308. --#endregion End of Integrated Movement Library
  309.  
  310. --#region DefragBot Peripherals and Helpers
  311. local chatBox = peripheral.find(CHAT_BOX_PERIPHERAL_NAME)
  312. local function botLog(message) print("["..CHAT_BOT_NAME.."-Debug] "..message) end
  313. local function sendFormattedChat(messageComponents, recipientUsername)
  314.     if not chatBox then local pt="";for _,c in ipairs(messageComponents)do pt=pt..(c.text or"")end;print("["..CHAT_BOT_NAME.."-NoChat] "..pt);return end
  315.     local jm=textutils.serialiseJSON(messageComponents)
  316.     if recipientUsername then chatBox.sendFormattedMessageToPlayer(jm,recipientUsername,CHAT_BOT_NAME,CHAT_BOT_BRACKETS,CHAT_BOT_BRACKET_COLOR)
  317.     else chatBox.sendFormattedMessage(jm,CHAT_BOT_NAME,CHAT_BOT_BRACKETS,CHAT_BOT_BRACKET_COLOR) end; sleep(0.2)
  318. end
  319. local function announce(mc) sendFormattedChat(mc) end
  320. local COLORS={GOLD="gold",AQUA="aqua",GRAY="gray",RED="red",GREEN="green",YELLOW="yellow",WHITE="white"}
  321. --#endregion
  322.  
  323. --#region DefragBot Command Handlers
  324. local commandHandlers = {}
  325. commandHandlers.help = function(username, _)
  326.     announce({{text="--- DefragBot Commands ("..COMMAND_PREFIX..") ---",color=COLORS.GOLD,bold=true}})
  327.     announce({{text=COMMAND_PREFIX.." help",color=COLORS.AQUA},{text=" - Shows this help.",color=COLORS.GRAY}})
  328.     announce({{text=COMMAND_PREFIX.." cmd <ml.func_call_string>",color=COLORS.AQUA},{text=" - Executes a movement function.",color=COLORS.GRAY}})
  329.     announce({{text="  Ex: "..COMMAND_PREFIX.." cmd ml.f()",color=COLORS.GRAY}})
  330.     announce({{text="  Ex: "..COMMAND_PREFIX.." cmd ml.moveTo(10,0,0,'N')",color=COLORS.GRAY}})
  331.     announce({{text=COMMAND_PREFIX.." mult <sequence>",color=COLORS.AQUA},{text=" - Executes sequence of l,r,f,b,u,d,a.",color=COLORS.GRAY}})
  332.     announce({{text="  Ex: "..COMMAND_PREFIX.." mult lffr",color=COLORS.GRAY}})
  333.     announce({{text=COMMAND_PREFIX.." pos",color=COLORS.AQUA},{text=" - Current position and direction.",color=COLORS.GRAY}})
  334.     announce({{text=COMMAND_PREFIX.." fuel",color=COLORS.AQUA},{text=" - Current fuel level.",color=COLORS.GRAY}})
  335. end
  336.  
  337. commandHandlers.cmd = function(username, args)
  338.     if #args == 0 then announce({{text="Usage: "..COMMAND_PREFIX.." cmd <ml.function_call_string>",color=COLORS.YELLOW}});return end
  339.     -- Correctly join all parts after "cmd" to form the command string
  340.     local cmdStringParts = {}
  341.     for i = 1, #args do -- Start from the first element of args
  342.         table.insert(cmdStringParts, args[i])
  343.     end
  344.     local cmdString = table.concat(cmdStringParts, " ")
  345.  
  346.     botLog("User "..username.." trying to execute: "..cmdString)
  347.     local func,err=load("return "..cmdString,"user_cmd","t",{ml=ml})
  348.     if not func then announce({{text="Err parsing: ",color=COLORS.RED},{text=tostring(err),color=COLORS.YELLOW}});botLog("Parse err: "..tostring(err));return end
  349.     local s,r=pcall(func)
  350.     if s then announce({{text="Cmd exec. Result: ",color=COLORS.GREEN},{text=tostring(r),color=COLORS.WHITE}});botLog("Cmd result: "..tostring(r))
  351.     else announce({{text="Err exec: ",color=COLORS.RED},{text=tostring(r),color=COLORS.YELLOW}});botLog("Exec err: "..tostring(r)) end
  352. end
  353.  
  354. commandHandlers.mult = function(username, args)
  355.     if #args ~= 1 or type(args[1]) ~= "string" then
  356.         announce({{text="Usage: "..COMMAND_PREFIX.." mult <sequence_string>",color=COLORS.YELLOW}});
  357.         announce({{text="Sequence can contain l,r,f,b,u,d,a. Example: lffr",color=COLORS.GRAY}}); return
  358.     end
  359.     local sequence = string.lower(args[1])
  360.     botLog("User "..username.." requested multi-sequence: "..sequence)
  361.     announce({{text="Executing sequence: ",color=COLORS.AQUA},{text=sequence,color=COLORS.WHITE}})
  362.  
  363.     local success = true
  364.     for i = 1, #sequence do
  365.         local moveChar = string.sub(sequence, i, i)
  366.         local moveFunc = nil
  367.         if moveChar == "l" then moveFunc = ml.l
  368.         elseif moveChar == "r" then moveFunc = ml.r
  369.         elseif moveChar == "f" then moveFunc = ml.f
  370.         elseif moveChar == "b" then moveFunc = ml.b
  371.         elseif moveChar == "u" then moveFunc = ml.u
  372.         elseif moveChar == "d" then moveFunc = ml.d
  373.         elseif moveChar == "a" then moveFunc = ml.a
  374.         end
  375.  
  376.         if moveFunc then
  377.             announce({{text="Executing: ",color=COLORS.GRAY},{text=moveChar,color=COLORS.YELLOW}})
  378.             if not moveFunc() then
  379.                 announce({{text="Move '",color=COLORS.RED},{text=moveChar,color=COLORS.YELLOW},{text="' failed. Stopping sequence.",color=COLORS.RED}})
  380.                 success = false
  381.                 break
  382.             end
  383.             sleep(0.2) -- Small delay between multi-moves
  384.         else
  385.             announce({{text="Unknown move character '",color=COLORS.RED},{text=moveChar,color=COLORS.YELLOW},{text="' in sequence. Stopping.",color=COLORS.RED}})
  386.             success = false
  387.             break
  388.         end
  389.     end
  390.     if success then announce({{text="Sequence finished.",color=COLORS.GREEN}}) end
  391. end
  392.  
  393. commandHandlers.pos = function(username, _)
  394.     local pD=ml.getPosition(); local dNS=ml.getDirectionName()
  395.     if pD and pD.x~=nil then announce({{text="Pos: ",color=COLORS.AQUA},{text="X:"..tostring(pD.x).." Y:"..tostring(pD.y).." Z:"..tostring(pD.z),color=COLORS.WHITE},{text=" Facing: "..dNS,color=COLORS.WHITE}})
  396.     else announce({{text="Position is unknown.",color=COLORS.YELLOW}}) end
  397. end
  398.  
  399. commandHandlers.fuel = function(username, _)
  400.     local l, lim = turtle.getFuelLevel(), turtle.getFuelLimit()
  401.     announce({{text="Fuel: ",color=COLORS.AQUA},{text=tostring(l)..(lim>0 and (" / "..tostring(lim))or""),color=COLORS.WHITE}})
  402. end
  403. --#endregion
  404.  
  405. --#region DefragBot Main Loop
  406. local function run()
  407.     term.clear();term.setCursorPos(1,1); botLog("DefragBot initializing...")
  408.     if not chatBox then botLog("WARN: ChatBox missing!");print("WARN: ChatBox missing!") end
  409.     botLog(CHAT_BOT_NAME.." online. MoveLib init.")
  410.     print(CHAT_BOT_NAME.." online. '"..COMMAND_PREFIX.." help' or '@all'.")
  411.     if chatBox then announce({{text=CHAT_BOT_NAME.." online, defrag duties (test)!",color=COLORS.GREEN}}) end
  412.  
  413.     while true do
  414.         local eventData={os.pullEvent()}
  415.         local eventType=eventData[1]
  416.         if eventType=="chat" then
  417.             local eU,eM=eventData[2],eventData[3]
  418.             if eM then
  419.                 if string.lower(eM)=="@all" then
  420.                     botLog("@all from "..eU); announce({{text="Use '",color=COLORS.GREEN},{text=COMMAND_PREFIX.." help",color=COLORS.AQUA},{text="' for my move test cmds.",color=COLORS.GREEN}})
  421.                 elseif string.sub(eM,1,#COMMAND_PREFIX)==COMMAND_PREFIX then
  422.                     botLog("Chat cmd from "..eU..": "..eM)
  423.                     local parts={};for part in string.gmatch(eM,"[^%s]+")do table.insert(parts,part)end
  424.                     local cmdName="";if parts[2]then cmdName=string.lower(parts[2])end
  425.                     -- Corrected argument collection for all commands
  426.                     local cmdArgs = {}
  427.                     for i = 3, #parts do table.insert(cmdArgs, parts[i]) end
  428.  
  429.                     if commandHandlers[cmdName] then commandHandlers[cmdName](eU,cmdArgs)
  430.                     elseif cmdName~="" then announce({{text="Unk DefragBot cmd: '",color=COLORS.RED},{text=cmdName,color=COLORS.YELLOW},{text="'.",color=COLORS.RED}}) end
  431.                 end
  432.             end
  433.         elseif eventType=="terminate" then
  434.             botLog("Terminate. Shutdown.");if chatBox then announce({{text=CHAT_BOT_NAME.." shut down.",color=COLORS.YELLOW}})end;return
  435.         end
  436.     end
  437. end
  438. run()
  439. --#endregion
Add Comment
Please, Sign In to add comment