AdvancedChunkyTurtle.lua

470 lines · 15.7 KB

Open raw

only follows and keeps chunks loaded

Copy & run

wget https://perlytiara.github.io/turtles.tips/raw/programs/perlytiara/tClear/AdvancedChunkyTurtle.lua
1--{program="AdvancedChunkyTurtle",version="2.0",date="2024-12-19"}
2---------------------------------------
3-- Advanced Chunky Turtle by AI Assistant
4-- 2024-12-19, v2.0 Enhanced chunky turtle with improved following
5---------------------------------------
6
7---------------------------------------
8---- DESCRIPTION ----------------------
9---------------------------------------
10-- Enhanced chunky turtle with advanced wireless communication
11-- Follows mining turtle to keep chunks loaded and prevent turtle breaking
12-- Features improved movement, better error handling, and status reporting
13-- Based on original tClearChunky.lua with wireless enhancements
14
15---------------------------------------
16---- ASSUMPTIONS ----------------------
17---------------------------------------
18-- Requires a wireless turtle with wireless modem
19-- Should be placed one block to the right of the mining turtle
20-- No tools needed - only follows and keeps chunks loaded
21
22---------------------------------------
23---- VARIABLES ------------------------
24---------------------------------------
25local cVersion = "v2.0"
26local cPrgName = "AdvancedChunkyTurtle"
27local blnDebugPrint = true
28
29-- Communication settings
30local protocol = "advanced-mining"
31local chunkyProtocol = "tclear-chunky"
32local masterTurtleId = nil
33local controllerId = nil
34local isActive = false
35local isPaired = false
36
37-- Position tracking
38local position = {x = 0, y = 0, z = 1, facing = 0} -- relative to master (to the right)
39local targetPosition = {x = 0, y = 0, z = 1, facing = 0}
40local lastKnownMasterPosition = {x = 0, y = 0, z = 0, facing = 0}
41
42-- Operation settings
43local chunkLoadingInterval = 2 -- seconds between chunk loading signals
44local statusReportInterval = 10 -- seconds between status reports
45local lastChunkLoad = 0
46local lastStatusReport = 0
47local lastBroadcast = 0
48local broadcastInterval = 5 -- seconds
49
50-- Movement settings
51local maxRetries = 3
52local retryDelay = 0.5 -- seconds
53
54---------------------------------------
55---- Utility Functions ----------------
56---------------------------------------
57local function debugPrint(str)
58 if blnDebugPrint then
59 print("[ChunkyTurtle] " .. str)
60 end
61end
62
63local function findModem()
64 for _, p in pairs(rs.getSides()) do
65 if peripheral.isPresent(p) and peripheral.getType(p) == "modem" then
66 return p
67 end
68 end
69 error("No wireless modem attached to this turtle.")
70end
71
72local function sendMessage(targetId, message, customProtocol)
73 local protocolToUse = customProtocol or protocol
74 rednet.send(targetId, message, protocolToUse)
75 debugPrint("Sent to " .. targetId .. ": " .. textutils.serialize(message))
76end
77
78local function sendStatus(status, data)
79 local targetId = controllerId or masterTurtleId
80 if targetId then
81 sendMessage(targetId, {
82 type = "status",
83 status = status,
84 id = os.getComputerID(),
85 position = position,
86 data = data or {},
87 timestamp = os.time()
88 })
89 end
90end
91
92local function sendChunkLoad()
93 if masterTurtleId then
94 sendMessage(masterTurtleId, {
95 type = "chunk_load",
96 id = os.getComputerID(),
97 position = position,
98 timestamp = os.time()
99 }, chunkyProtocol)
100 end
101end
102
103---------------------------------------
104---- Movement Functions ---------------
105---------------------------------------
106local function safeMove(moveFunction, direction)
107 local retries = 0
108 while retries < maxRetries do
109 if moveFunction() then
110 return true
111 else
112 retries = retries + 1
113 if retries < maxRetries then
114 debugPrint("Move failed, retrying " .. direction .. " (attempt " .. retries .. ")")
115 sleep(retryDelay)
116 end
117 end
118 end
119 debugPrint("Failed to move " .. direction .. " after " .. maxRetries .. " attempts")
120 return false
121end
122
123local function safeDig(digFunction, direction)
124 local retries = 0
125 while retries < maxRetries do
126 if digFunction() then
127 return true
128 else
129 retries = retries + 1
130 if retries < maxRetries then
131 debugPrint("Dig failed, retrying " .. direction .. " (attempt " .. retries .. ")")
132 sleep(retryDelay)
133 end
134 end
135 end
136 debugPrint("Failed to dig " .. direction .. " after " .. maxRetries .. " attempts")
137 return false
138end
139
140local function moveTo(targetX, targetY, targetZ, targetFacing)
141 -- Calculate relative movement needed from current position to target
142 local dx = targetX - position.x
143 local dy = targetY - position.y
144 local dz = targetZ - position.z
145 local dfacing = (targetFacing - position.facing) % 4
146
147 debugPrint("Moving from (" .. position.x .. "," .. position.y .. "," .. position.z .. ") to (" .. targetX .. "," .. targetY .. "," .. targetZ .. ")")
148 debugPrint("Delta: dx=" .. dx .. " dy=" .. dy .. " dz=" .. dz .. " dfacing=" .. dfacing)
149
150 -- Turn to correct facing first
151 if dfacing == 1 then
152 turtle.turnRight()
153 position.facing = (position.facing + 1) % 4
154 elseif dfacing == 2 then
155 turtle.turnRight()
156 turtle.turnRight()
157 position.facing = (position.facing + 2) % 4
158 elseif dfacing == 3 then
159 turtle.turnLeft()
160 position.facing = (position.facing - 1) % 4
161 end
162
163 -- Move vertically first (up)
164 while dy > 0 do
165 if safeMove(turtle.up, "up") then
166 dy = dy - 1
167 position.y = position.y + 1
168 debugPrint("Moved up to y=" .. position.y)
169 else
170 debugPrint("Cannot move up, trying to dig")
171 if safeDig(turtle.digUp, "up") then
172 sleep(0.1)
173 if safeMove(turtle.up, "up") then
174 dy = dy - 1
175 position.y = position.y + 1
176 debugPrint("Moved up to y=" .. position.y)
177 else
178 debugPrint("Still blocked after digging up")
179 break
180 end
181 else
182 debugPrint("Cannot dig up, giving up")
183 break
184 end
185 end
186 end
187
188 -- Move vertically (down)
189 while dy < 0 do
190 if safeMove(turtle.down, "down") then
191 dy = dy + 1
192 position.y = position.y - 1
193 debugPrint("Moved down to y=" .. position.y)
194 else
195 debugPrint("Cannot move down, trying to dig")
196 if safeDig(turtle.digDown, "down") then
197 sleep(0.1)
198 if safeMove(turtle.down, "down") then
199 dy = dy + 1
200 position.y = position.y - 1
201 debugPrint("Moved down to y=" .. position.y)
202 else
203 debugPrint("Still blocked after digging down")
204 break
205 end
206 else
207 debugPrint("Cannot dig down, giving up")
208 break
209 end
210 end
211 end
212
213 -- Move horizontally - handle X movement (forward/backward relative to facing)
214 while dx > 0 do
215 if safeMove(turtle.forward, "forward") then
216 dx = dx - 1
217 position.x = position.x + 1
218 debugPrint("Moved forward to x=" .. position.x)
219 else
220 debugPrint("Blocked forward, trying to dig")
221 if safeDig(turtle.dig, "forward") then
222 sleep(0.1)
223 if safeMove(turtle.forward, "forward") then
224 dx = dx - 1
225 position.x = position.x + 1
226 debugPrint("Moved forward to x=" .. position.x)
227 else
228 debugPrint("Still blocked after digging forward")
229 break
230 end
231 else
232 debugPrint("Cannot dig forward, giving up")
233 break
234 end
235 end
236 end
237
238 while dx < 0 do
239 -- Turn around to move backward
240 turtle.turnLeft()
241 turtle.turnLeft()
242 if safeMove(turtle.forward, "backward") then
243 dx = dx + 1
244 position.x = position.x - 1
245 debugPrint("Moved backward to x=" .. position.x)
246 else
247 debugPrint("Blocked backward, trying to dig")
248 if safeDig(turtle.dig, "backward") then
249 sleep(0.1)
250 if safeMove(turtle.forward, "forward") then
251 dx = dx + 1
252 position.x = position.x - 1
253 debugPrint("Moved backward to x=" .. position.x)
254 else
255 debugPrint("Still blocked after digging backward")
256 end
257 else
258 debugPrint("Cannot dig backward, giving up")
259 end
260 end
261 turtle.turnLeft()
262 turtle.turnLeft()
263 if dx < 0 then break end -- If still can't move, give up
264 end
265
266 -- Move sideways - handle Z movement (left/right relative to facing)
267 while dz > 0 do
268 turtle.turnRight()
269 if safeMove(turtle.forward, "right") then
270 dz = dz - 1
271 position.z = position.z + 1
272 debugPrint("Moved right to z=" .. position.z)
273 else
274 debugPrint("Blocked right, trying to dig")
275 if safeDig(turtle.dig, "right") then
276 sleep(0.1)
277 if safeMove(turtle.forward, "right") then
278 dz = dz - 1
279 position.z = position.z + 1
280 debugPrint("Moved right to z=" .. position.z)
281 else
282 debugPrint("Still blocked after digging right")
283 end
284 else
285 debugPrint("Cannot dig right, giving up")
286 end
287 end
288 turtle.turnLeft()
289 if dz > 0 then break end -- If still can't move, give up
290 end
291
292 while dz < 0 do
293 turtle.turnLeft()
294 if safeMove(turtle.forward, "left") then
295 dz = dz + 1
296 position.z = position.z - 1
297 debugPrint("Moved left to z=" .. position.z)
298 else
299 debugPrint("Blocked left, trying to dig")
300 if safeDig(turtle.dig, "left") then
301 sleep(0.1)
302 if safeMove(turtle.forward, "left") then
303 dz = dz + 1
304 position.z = position.z - 1
305 debugPrint("Moved left to z=" .. position.z)
306 else
307 debugPrint("Still blocked after digging left")
308 end
309 else
310 debugPrint("Cannot dig left, giving up")
311 end
312 end
313 turtle.turnRight()
314 if dz < 0 then break end -- If still can't move, give up
315 end
316
317 -- Update final facing
318 position.facing = targetFacing
319 debugPrint("Final position: (" .. position.x .. "," .. position.y .. "," .. position.z .. ") facing=" .. position.facing)
320
321 -- Update target position
322 targetPosition = {x = targetX, y = targetY, z = targetZ, facing = targetFacing}
323end
324
325---------------------------------------
326---- Message Processing ---------------
327---------------------------------------
328local function processMessage(senderId, message, msgProtocol)
329 if message.type == "discover" then
330 -- Respond to discovery request
331 sendMessage(senderId, {
332 type = "chunky_turtle_available",
333 name = "Advanced Chunky Turtle",
334 fuel = turtle.getFuelLevel(),
335 timestamp = os.time()
336 })
337 return true
338
339 elseif message.type == "start_chunky" then
340 -- Start chunky mode
341 masterTurtleId = message.masterId
342 controllerId = senderId
343 isActive = true
344 isPaired = true
345
346 print("SUCCESS: Paired with master turtle " .. masterTurtleId)
347 print("Chunky turtle is now active and ready to follow!")
348
349 sendStatus("paired", {chunkyId = os.getComputerID()})
350
351 -- Send ready confirmation
352 sendMessage(controllerId, {
353 type = "chunky_ready",
354 chunkyId = os.getComputerID(),
355 timestamp = os.time()
356 })
357
358 return true
359
360 elseif message.type == "move" then
361 if isActive and message.target then
362 debugPrint("Moving to " .. message.target.x .. "," .. message.target.y .. "," .. message.target.z)
363 moveTo(message.target.x, message.target.y, message.target.z, message.target.facing or 0)
364 sendStatus("moved", {position = position})
365 return true
366 end
367
368 elseif message.type == "stop" or message.type == "stop_operation" then
369 isActive = false
370 isPaired = false
371 debugPrint("Stopped by master turtle")
372 sendStatus("stopped", {})
373 return true
374
375 elseif message.type == "ping" then
376 sendStatus("alive", {position = position})
377 return true
378 end
379
380 return false
381end
382
383---------------------------------------
384---- Main Program ----------------------
385---------------------------------------
386local function main()
387 term.clear()
388 term.setCursorPos(1, 1)
389
390 print("==========================================")
391 print(" Advanced Chunky Turtle " .. cVersion)
392 print("==========================================")
393 print()
394
395 -- Initialize rednet
396 local modemSide = findModem()
397 rednet.open(modemSide)
398 print("Rednet initialized on " .. modemSide)
399
400 local thisId = os.getComputerID()
401 print("Chunky turtle ID: " .. thisId)
402 print()
403 print("Waiting for pairing with master turtle...")
404 print("Press Ctrl+T to exit")
405
406 -- Send initial broadcast
407 sendMessage(0, {
408 type = "chunky_turtle_available",
409 id = thisId,
410 timestamp = os.time()
411 })
412
413 print("Sent initial broadcast - waiting for master turtle...")
414
415 -- Main loop
416 while true do
417 local timer = os.startTimer(0.1) -- Check for messages every 0.1 seconds
418
419 -- Handle rednet messages
420 local senderId, message, msgProtocol = rednet.receive(0.1)
421 if senderId then
422 -- Accept messages on multiple protocols
423 if msgProtocol == protocol or msgProtocol == chunkyProtocol or msgProtocol == "tclear-run" or msgProtocol == "tclear" or msgProtocol == nil then
424 local handled = processMessage(senderId, message, msgProtocol)
425 if handled then
426 debugPrint("Processed message from " .. senderId)
427 end
428 end
429 end
430
431 -- Send chunk loading signal periodically
432 local currentTime = os.time()
433 if isActive and (currentTime - lastChunkLoad) >= chunkLoadingInterval then
434 sendChunkLoad()
435 lastChunkLoad = currentTime
436 end
437
438 -- Send status reports periodically
439 if isPaired and (currentTime - lastStatusReport) >= statusReportInterval then
440 sendStatus("alive", {position = position, fuel = turtle.getFuelLevel()})
441 lastStatusReport = currentTime
442 end
443
444 -- Send periodic broadcasts if not paired yet
445 if not isPaired and (currentTime - lastBroadcast) >= broadcastInterval then
446 sendMessage(0, {
447 type = "chunky_turtle_available",
448 id = thisId,
449 timestamp = currentTime
450 })
451 print("Sent broadcast - still waiting for master turtle...")
452 lastBroadcast = currentTime
453 end
454
455 -- Handle timer events (cleanup)
456 local event, timerId = os.pullEvent("timer")
457 if timerId == timer then
458 -- Timer expired, continue loop
459 end
460 end
461end
462
463-- Run main program
464local ok, err = pcall(main)
465if not ok then
466 print("Error: " .. tostring(err))
467 print("Press any key to exit...")
468 os.pullEvent("key")
469end
470