AdvancedMiningController.lua
417 lines · 13.8 KB
{program="AdvancedMiningController",version="2.0",date="2024-12-19"}
Copy & run
wget https://perlytiara.github.io/turtles.tips/raw/programs/perlytiara/tClear/AdvancedMiningController.lua
| 1 | --{program="AdvancedMiningController",version="2.0",date="2024-12-19"} |
| 2 | --------------------------------------- |
| 3 | -- Advanced Mining Controller by AI Assistant |
| 4 | -- 2024-12-19, v2.0 Advanced wireless mining system |
| 5 | --------------------------------------- |
| 6 | |
| 7 | --------------------------------------- |
| 8 | ---- DESCRIPTION ---------------------- |
| 9 | --------------------------------------- |
| 10 | -- Master controller for advanced wireless mining operations |
| 11 | -- Controls mining turtle and chunky turtle from a computer |
| 12 | -- Features automatic pairing, real-time monitoring, and advanced coordination |
| 13 | -- Supports single and multi-turtle operations with chunky pairing |
| 14 | |
| 15 | --------------------------------------- |
| 16 | ---- ASSUMPTIONS ---------------------- |
| 17 | --------------------------------------- |
| 18 | -- Requires a computer with wireless modem |
| 19 | -- Mining turtle placed at left corner of mining area |
| 20 | -- Chunky turtle placed one block to the right of mining turtle |
| 21 | -- Both turtles have wireless modems and required programs |
| 22 | |
| 23 | --------------------------------------- |
| 24 | ---- VARIABLES ------------------------ |
| 25 | --------------------------------------- |
| 26 | local cVersion = "v2.0" |
| 27 | local cPrgName = "AdvancedMiningController" |
| 28 | local blnDebugPrint = true |
| 29 | |
| 30 | -- Communication settings |
| 31 | local protocol = "advanced-mining" |
| 32 | local discoveryTimeout = 5 |
| 33 | local responseTimeout = 3 |
| 34 | |
| 35 | -- Turtle management |
| 36 | local miningTurtleId = nil |
| 37 | local chunkyTurtleId = nil |
| 38 | local isOperationActive = false |
| 39 | local operationStatus = "idle" |
| 40 | |
| 41 | -- Operation parameters |
| 42 | local operationParams = { |
| 43 | depth = 0, |
| 44 | width = 0, |
| 45 | height = 0, |
| 46 | options = {} |
| 47 | } |
| 48 | |
| 49 | --------------------------------------- |
| 50 | ---- Utility Functions ---------------- |
| 51 | --------------------------------------- |
| 52 | local function debugPrint(str) |
| 53 | if blnDebugPrint then |
| 54 | print("[Controller] " .. str) |
| 55 | end |
| 56 | end |
| 57 | |
| 58 | local function findModem() |
| 59 | for _, p in pairs(rs.getSides()) do |
| 60 | if peripheral.isPresent(p) and peripheral.getType(p) == "modem" then |
| 61 | return p |
| 62 | end |
| 63 | end |
| 64 | error("No modem attached to this computer.") |
| 65 | end |
| 66 | |
| 67 | local function sendMessage(targetId, message, customProtocol) |
| 68 | local protocolToUse = customProtocol or protocol |
| 69 | rednet.send(targetId, message, protocolToUse) |
| 70 | debugPrint("Sent to " .. targetId .. ": " .. textutils.serialize(message)) |
| 71 | end |
| 72 | |
| 73 | local function broadcastMessage(message, customProtocol) |
| 74 | local protocolToUse = customProtocol or protocol |
| 75 | rednet.broadcast(message, protocolToUse) |
| 76 | debugPrint("Broadcasted: " .. textutils.serialize(message)) |
| 77 | end |
| 78 | |
| 79 | local function waitForResponse(targetId, expectedType, timeout) |
| 80 | timeout = timeout or responseTimeout |
| 81 | local startTime = os.time() |
| 82 | |
| 83 | while (os.time() - startTime) < timeout do |
| 84 | local senderId, message, msgProtocol = rednet.receive(0.1) |
| 85 | if senderId == targetId and msgProtocol == protocol then |
| 86 | if message.type == expectedType then |
| 87 | return message |
| 88 | end |
| 89 | end |
| 90 | end |
| 91 | return nil |
| 92 | end |
| 93 | |
| 94 | --------------------------------------- |
| 95 | ---- Discovery Functions -------------- |
| 96 | --------------------------------------- |
| 97 | local function discoverTurtles() |
| 98 | print("Discovering available turtles...") |
| 99 | |
| 100 | -- Send discovery broadcast |
| 101 | broadcastMessage({ |
| 102 | type = "discover", |
| 103 | controllerId = os.getComputerID(), |
| 104 | timestamp = os.time() |
| 105 | }) |
| 106 | |
| 107 | local discoveredTurtles = {} |
| 108 | local discoveredChunkies = {} |
| 109 | local startTime = os.time() |
| 110 | |
| 111 | -- Collect responses |
| 112 | while (os.time() - startTime) < discoveryTimeout do |
| 113 | local senderId, message, msgProtocol = rednet.receive(0.1) |
| 114 | if senderId and msgProtocol == protocol then |
| 115 | if message.type == "mining_turtle_available" then |
| 116 | table.insert(discoveredTurtles, { |
| 117 | id = senderId, |
| 118 | name = message.name or "Mining Turtle", |
| 119 | fuel = message.fuel or 0, |
| 120 | inventory = message.inventory or 0 |
| 121 | }) |
| 122 | print("Found mining turtle: " .. senderId .. " (Fuel: " .. (message.fuel or 0) .. ")") |
| 123 | elseif message.type == "chunky_turtle_available" then |
| 124 | table.insert(discoveredChunkies, { |
| 125 | id = senderId, |
| 126 | name = message.name or "Chunky Turtle", |
| 127 | fuel = message.fuel or 0 |
| 128 | }) |
| 129 | print("Found chunky turtle: " .. senderId .. " (Fuel: " .. (message.fuel or 0) .. ")") |
| 130 | end |
| 131 | end |
| 132 | end |
| 133 | |
| 134 | return discoveredTurtles, discoveredChunkies |
| 135 | end |
| 136 | |
| 137 | local function selectTurtles(discoveredTurtles, discoveredChunkies) |
| 138 | print("\n=== Turtle Selection ===") |
| 139 | |
| 140 | -- Select mining turtle |
| 141 | if #discoveredTurtles == 0 then |
| 142 | error("No mining turtles found! Make sure mining turtle is running AdvancedMiningTurtle.lua") |
| 143 | end |
| 144 | |
| 145 | if #discoveredTurtles == 1 then |
| 146 | miningTurtleId = discoveredTurtles[1].id |
| 147 | print("Auto-selected mining turtle: " .. miningTurtleId) |
| 148 | else |
| 149 | print("Multiple mining turtles found:") |
| 150 | for i, turtle in ipairs(discoveredTurtles) do |
| 151 | print(i .. ". ID: " .. turtle.id .. " - Fuel: " .. turtle.fuel .. " - Inventory: " .. turtle.inventory .. "%") |
| 152 | end |
| 153 | print("Select mining turtle (1-" .. #discoveredTurtles .. "):") |
| 154 | local choice = tonumber(read()) |
| 155 | if choice and choice >= 1 and choice <= #discoveredTurtles then |
| 156 | miningTurtleId = discoveredTurtles[choice].id |
| 157 | else |
| 158 | error("Invalid selection") |
| 159 | end |
| 160 | end |
| 161 | |
| 162 | -- Select chunky turtle |
| 163 | if #discoveredChunkies == 0 then |
| 164 | print("No chunky turtles found. Operation will continue without chunky pairing.") |
| 165 | chunkyTurtleId = nil |
| 166 | elseif #discoveredChunkies == 1 then |
| 167 | chunkyTurtleId = discoveredChunkies[1].id |
| 168 | print("Auto-selected chunky turtle: " .. chunkyTurtleId) |
| 169 | else |
| 170 | print("Multiple chunky turtles found:") |
| 171 | for i, chunky in ipairs(discoveredChunkies) do |
| 172 | print(i .. ". ID: " .. chunky.id .. " - Fuel: " .. chunky.fuel) |
| 173 | end |
| 174 | print("Select chunky turtle (1-" .. #discoveredChunkies .. ", or 0 to skip):") |
| 175 | local choice = tonumber(read()) |
| 176 | if choice and choice >= 1 and choice <= #discoveredChunkies then |
| 177 | chunkyTurtleId = discoveredChunkies[choice].id |
| 178 | elseif choice == 0 then |
| 179 | chunkyTurtleId = nil |
| 180 | print("Skipping chunky turtle pairing") |
| 181 | else |
| 182 | error("Invalid selection") |
| 183 | end |
| 184 | end |
| 185 | end |
| 186 | |
| 187 | --------------------------------------- |
| 188 | ---- Operation Functions -------------- |
| 189 | --------------------------------------- |
| 190 | local function getOperationParameters() |
| 191 | print("\n=== Operation Parameters ===") |
| 192 | |
| 193 | print("Enter mining depth (forward distance, >= 1):") |
| 194 | operationParams.depth = tonumber(read()) |
| 195 | if not operationParams.depth or operationParams.depth < 1 then |
| 196 | error("Invalid depth. Must be >= 1") |
| 197 | end |
| 198 | |
| 199 | print("Enter mining width (side distance, cannot be -1, 0, or 1):") |
| 200 | operationParams.width = tonumber(read()) |
| 201 | if not operationParams.width or operationParams.width == -1 or operationParams.width == 0 or operationParams.width == 1 then |
| 202 | error("Invalid width. Cannot be -1, 0, or 1") |
| 203 | end |
| 204 | |
| 205 | print("Enter mining height (up/down distance, cannot be 0):") |
| 206 | operationParams.height = tonumber(read()) |
| 207 | if not operationParams.height or operationParams.height == 0 then |
| 208 | error("Invalid height. Cannot be 0") |
| 209 | end |
| 210 | |
| 211 | print("Enter options (space-separated, or press Enter for none):") |
| 212 | print("Available options: layerbylayer, startwithin, stripmine") |
| 213 | local optionsInput = read() |
| 214 | operationParams.options = {} |
| 215 | if optionsInput and optionsInput ~= "" then |
| 216 | for option in string.gmatch(optionsInput, "%S+") do |
| 217 | table.insert(operationParams.options, string.lower(option)) |
| 218 | end |
| 219 | end |
| 220 | end |
| 221 | |
| 222 | local function startOperation() |
| 223 | print("\n=== Starting Operation ===") |
| 224 | |
| 225 | -- Build command string |
| 226 | local command = tostring(operationParams.depth) .. " " .. |
| 227 | tostring(operationParams.width) .. " " .. |
| 228 | tostring(operationParams.height) |
| 229 | |
| 230 | if #operationParams.options > 0 then |
| 231 | command = command .. " " .. table.concat(operationParams.options, " ") |
| 232 | end |
| 233 | |
| 234 | print("Command: " .. command) |
| 235 | |
| 236 | -- Start chunky turtle first if available |
| 237 | if chunkyTurtleId then |
| 238 | print("Starting chunky turtle...") |
| 239 | sendMessage(chunkyTurtleId, { |
| 240 | type = "start_chunky", |
| 241 | masterId = miningTurtleId, |
| 242 | timestamp = os.time() |
| 243 | }) |
| 244 | |
| 245 | -- Wait for chunky turtle to be ready |
| 246 | local response = waitForResponse(chunkyTurtleId, "chunky_ready", 5) |
| 247 | if response then |
| 248 | print("Chunky turtle ready!") |
| 249 | else |
| 250 | print("Warning: Chunky turtle did not respond, continuing anyway...") |
| 251 | end |
| 252 | end |
| 253 | |
| 254 | -- Start mining turtle |
| 255 | print("Starting mining turtle...") |
| 256 | sendMessage(miningTurtleId, { |
| 257 | type = "start_mining", |
| 258 | command = command, |
| 259 | chunkyId = chunkyTurtleId, |
| 260 | timestamp = os.time() |
| 261 | }) |
| 262 | |
| 263 | -- Wait for mining turtle to start |
| 264 | local response = waitForResponse(miningTurtleId, "mining_started", 5) |
| 265 | if response then |
| 266 | print("Mining operation started!") |
| 267 | isOperationActive = true |
| 268 | operationStatus = "running" |
| 269 | else |
| 270 | error("Mining turtle failed to start operation") |
| 271 | end |
| 272 | end |
| 273 | |
| 274 | --------------------------------------- |
| 275 | ---- Monitoring Functions ------------- |
| 276 | --------------------------------------- |
| 277 | local function monitorOperation() |
| 278 | print("\n=== Operation Monitoring ===") |
| 279 | print("Press 's' for status, 'p' to pause, 'r' to resume, 'q' to quit monitoring") |
| 280 | |
| 281 | while isOperationActive do |
| 282 | local event, key = os.pullEvent("key") |
| 283 | |
| 284 | if key == keys.s then |
| 285 | -- Request status update |
| 286 | sendMessage(miningTurtleId, { |
| 287 | type = "status_request", |
| 288 | timestamp = os.time() |
| 289 | }) |
| 290 | |
| 291 | local statusResponse = waitForResponse(miningTurtleId, "status_update", 2) |
| 292 | if statusResponse then |
| 293 | print("=== Status Update ===") |
| 294 | print("Position: " .. (statusResponse.position or "unknown")) |
| 295 | print("Progress: " .. (statusResponse.progress or "unknown")) |
| 296 | print("Fuel: " .. (statusResponse.fuel or "unknown")) |
| 297 | print("Inventory: " .. (statusResponse.inventory or "unknown")) |
| 298 | if statusResponse.chunkyStatus then |
| 299 | print("Chunky Status: " .. statusResponse.chunkyStatus) |
| 300 | end |
| 301 | else |
| 302 | print("No status response received") |
| 303 | end |
| 304 | |
| 305 | elseif key == keys.p then |
| 306 | -- Pause operation |
| 307 | sendMessage(miningTurtleId, { |
| 308 | type = "pause_operation", |
| 309 | timestamp = os.time() |
| 310 | }) |
| 311 | print("Pause command sent") |
| 312 | |
| 313 | elseif key == keys.r then |
| 314 | -- Resume operation |
| 315 | sendMessage(miningTurtleId, { |
| 316 | type = "resume_operation", |
| 317 | timestamp = os.time() |
| 318 | }) |
| 319 | print("Resume command sent") |
| 320 | |
| 321 | elseif key == keys.q then |
| 322 | -- Quit monitoring (but don't stop operation) |
| 323 | print("Stopping monitoring. Operation continues...") |
| 324 | break |
| 325 | end |
| 326 | end |
| 327 | end |
| 328 | |
| 329 | local function stopOperation() |
| 330 | print("\n=== Stopping Operation ===") |
| 331 | |
| 332 | if isOperationActive then |
| 333 | -- Stop mining turtle |
| 334 | sendMessage(miningTurtleId, { |
| 335 | type = "stop_operation", |
| 336 | timestamp = os.time() |
| 337 | }) |
| 338 | |
| 339 | -- Stop chunky turtle if active |
| 340 | if chunkyTurtleId then |
| 341 | sendMessage(chunkyTurtleId, { |
| 342 | type = "stop_operation", |
| 343 | timestamp = os.time() |
| 344 | }) |
| 345 | end |
| 346 | |
| 347 | isOperationActive = false |
| 348 | operationStatus = "stopped" |
| 349 | print("Stop commands sent to all turtles") |
| 350 | end |
| 351 | end |
| 352 | |
| 353 | --------------------------------------- |
| 354 | ---- Main Program ---------------------- |
| 355 | --------------------------------------- |
| 356 | local function main() |
| 357 | term.clear() |
| 358 | term.setCursorPos(1, 1) |
| 359 | |
| 360 | print("==========================================") |
| 361 | print(" Advanced Mining Controller " .. cVersion) |
| 362 | print("==========================================") |
| 363 | print() |
| 364 | |
| 365 | -- Initialize rednet |
| 366 | local modemSide = findModem() |
| 367 | rednet.open(modemSide) |
| 368 | print("Rednet initialized on " .. modemSide) |
| 369 | |
| 370 | -- Discover turtles |
| 371 | local discoveredTurtles, discoveredChunkies = discoverTurtles() |
| 372 | |
| 373 | if #discoveredTurtles == 0 then |
| 374 | error("No mining turtles found! Make sure at least one mining turtle is running AdvancedMiningTurtle.lua") |
| 375 | end |
| 376 | |
| 377 | -- Select turtles |
| 378 | selectTurtles(discoveredTurtles, discoveredChunkies) |
| 379 | |
| 380 | -- Get operation parameters |
| 381 | getOperationParameters() |
| 382 | |
| 383 | -- Confirm operation |
| 384 | print("\n=== Operation Summary ===") |
| 385 | print("Mining Turtle: " .. miningTurtleId) |
| 386 | print("Chunky Turtle: " .. (chunkyTurtleId or "None")) |
| 387 | print("Parameters: " .. operationParams.depth .. " x " .. operationParams.width .. " x " .. operationParams.height) |
| 388 | if #operationParams.options > 0 then |
| 389 | print("Options: " .. table.concat(operationParams.options, ", ")) |
| 390 | end |
| 391 | print() |
| 392 | print("Start operation? (y/n):") |
| 393 | local confirm = read() |
| 394 | |
| 395 | if string.lower(confirm) == "y" or string.lower(confirm) == "yes" then |
| 396 | startOperation() |
| 397 | |
| 398 | -- Monitor operation |
| 399 | monitorOperation() |
| 400 | |
| 401 | -- Final stop |
| 402 | stopOperation() |
| 403 | else |
| 404 | print("Operation cancelled") |
| 405 | end |
| 406 | |
| 407 | print("\nAdvanced Mining Controller finished.") |
| 408 | end |
| 409 | |
| 410 | -- Run main program |
| 411 | local ok, err = pcall(main) |
| 412 | if not ok then |
| 413 | print("Error: " .. tostring(err)) |
| 414 | print("Press any key to exit...") |
| 415 | os.pullEvent("key") |
| 416 | end |
| 417 |