SHOW:
|
|
- or go back to the newest paste.
| 1 | ---------------------------------------------------------------------- | |
| 2 | -- Module API -- | |
| 3 | ---------------------------------------------------------------------- | |
| 4 | - | |
| 4 | + | |
| 5 | - | -- Version 0.1a |
| 5 | + | -- Version 0.1(481): 1.481-compatible |
| 6 | - | |
| 6 | + | |
| 7 | -- Module is an API that allows to interact with master and perform next functions: | |
| 8 | -- Communication to the master. | |
| 9 | -- Navigation to the said point. | |
| 10 | -- Request tasks and execute functions using a response table. | |
| 11 | -- Usage: | |
| 12 | -- 1) Set up a task table using the module.addTasks(taskTable) function | |
| 13 | -- taskTable is a table with tasks as keys (tasks are recived from Master) | |
| 14 | -- and functions as values. Function should accept a response as an argument, | |
| 15 | -- so master can pass some additional data to module. | |
| 16 | -- Those functions are executed when module recieved an associated task after module has navigated to | |
| 17 | -- the position sent in response (if any) | |
| 18 | -- 2) Set the type of your module using the setType (newType) function | |
| 19 | -- Type is used by Master to determine what can this module do. | |
| 20 | -- 3) Run the module.init () function | |
| 21 | -- 4) Run the module.operate() function to start | |
| 22 | -- 5) If you move the module in your tasks, please use module.move(direction) or module.moveEx (f) to move it | |
| 23 | -- and use turn(side) or turnTo(f) to turn it, because those functions are keep tracking the module's position | |
| 24 | -- or you can find its new position by yourself and use module.setPosition (x,y,z,f) to set it | |
| 25 | ||
| 26 | ||
| 27 | --[[ | |
| 28 | ********************************************************************************************* | |
| 29 | * Navigation Part * | |
| 30 | ********************************************************************************************* | |
| 31 | ]]-- | |
| 32 | ||
| 33 | -- Location is a global table containing all the coordinates and facing direction of the turtle | |
| 34 | -- And here is the function to set the position of the turtle and another one to get it. | |
| 35 | location = {x = 0, y = 0, z = 0, f = 0}
| |
| 36 | ||
| 37 | function setPosition (x, y, z, f) | |
| 38 | location.x = x | |
| 39 | location.y = y | |
| 40 | location.z = z | |
| 41 | location.f = f | |
| 42 | end | |
| 43 | ||
| 44 | function getPosition () | |
| 45 | return { x = location.x,
| |
| 46 | y = location.y, | |
| 47 | z = location.z, | |
| 48 | f = location.f, } -- return a copy of the location table. | |
| 49 | end | |
| 50 | ||
| 51 | -- And a small function to print the position. For debug purposes | |
| 52 | function printPosition () | |
| 53 | print ("Currrent turtle position:")
| |
| 54 | print (" x = "..location.x)
| |
| 55 | print (" y = "..location.y)
| |
| 56 | print (" z = "..location.z)
| |
| 57 | print (" f = "..location.f)
| |
| 58 | end | |
| 59 | ||
| 60 | -- A turning function | |
| 61 | function turn (direction) | |
| 62 | if direction == "left" then | |
| 63 | turtle.turnLeft() | |
| 64 | location.f = location.f - 1 | |
| 65 | elseif direction == "right" then | |
| 66 | turtle.turnRight() | |
| 67 | location.f = location.f + 1 | |
| 68 | elseif direction == "around" then | |
| 69 | turtle.turnLeft() | |
| 70 | turtle.turnLeft() | |
| 71 | location.f = location.f - 2 | |
| 72 | else | |
| 73 | print ("No such direction: "..direction)
| |
| 74 | return false | |
| 75 | end | |
| 76 | location.f = (location.f + 4) % 4 -- This is used to handle the f < 0 and f > 3 situations | |
| 77 | return true | |
| 78 | end | |
| 79 | ||
| 80 | -- This one is used to turn the turtle to specified f direction. | |
| 81 | -- A little bit of pony magic is used to calculate how should it turn | |
| 82 | function turnTo (face) | |
| 83 | local diff = face - location.f | |
| 84 | if math.abs(diff) == 2 then --this is true if the difference between f and face is 2 or -2, so it should turn around | |
| 85 | return turn ("around")
| |
| 86 | elseif math.fmod(diff + 4, 4) == 1 then --this is true if the difference between f and face is 1 | |
| 87 | return turn ("right") --f = 0 and face = 3 is also satisfies the condition (-3 + 4 == 1)
| |
| 88 | elseif math.fmod(diff - 4, 4) == -1 then --this is true if the difference between f and face is -1 | |
| 89 | return turn ("left") --f = 3 and face = 1 is also satisfies the condition ( 3 - 4 == 1)
| |
| 90 | end | |
| 91 | return false --returned if turtle is already faced the specified direction | |
| 92 | end | |
| 93 | ||
| 94 | -- This function is used to return actual x and z shifts | |
| 95 | -- These shifts are the numbers which you should add to the coordinates when turtle moves forward. | |
| 96 | -- I use a table to decode it since it is more compact and easier to read than lots of conditions | |
| 97 | local tShifts = {
| |
| 98 | [0] = { 1, 0},
| |
| 99 | [1] = { 0, 1},
| |
| 100 | [2] = {-1, 0},
| |
| 101 | [3] = { 0, -1},
| |
| 102 | } | |
| 103 | function fDirection () | |
| 104 | return unpack (tShifts[location.f]) | |
| 105 | end | |
| 106 | ||
| 107 | -- This function is used to update the turtle location when it has moved | |
| 108 | function updateLocation (direction) | |
| 109 | if direction == "up" then | |
| 110 | location.y = location.y + 1 | |
| 111 | elseif direction == "down" then | |
| 112 | location.y = location.y - 1 | |
| 113 | elseif direction == "forward" then | |
| 114 | local xShift, zShift = fDirection () | |
| 115 | location.x = location.x + xShift | |
| 116 | location.z = location.z + zShift | |
| 117 | elseif direction == "back" then | |
| 118 | local xShift, yShift = fDirection () | |
| 119 | location.x = location.x - xShift | |
| 120 | location.z = location.z - zShift | |
| 121 | end | |
| 122 | end | |
| 123 | ||
| 124 | -- This function helps us with our EnderChests if there is something that obstructs placement | |
| 125 | -- It checks what's going on on top of it, and if there is a turtle, it waits before digging. | |
| 126 | function forcePlaceUp () | |
| 127 | - | while not turtle.placeUp() do |
| 127 | + | while not turtle.placeUp() do |
| 128 | - | if turtle.detectUp() then |
| 128 | + | if turtle.detectUp() then |
| 129 | - | if peripheral.isPresent ("top") and peripheral.getType ("top") == "turtle" then
|
| 129 | + | if peripheral.isPresent ("top") and peripheral.getType ("top") == "turtle" then
|
| 130 | - | print "Other turtle detected. Waiting..." |
| 130 | + | print "Other turtle detected. Waiting..." |
| 131 | - | while peripheral.isPresent ("top") do
|
| 131 | + | while peripheral.isPresent ("top") do
|
| 132 | - | sleep (5) |
| 132 | + | sleep (5) |
| 133 | - | end |
| 133 | + | end |
| 134 | - | end |
| 134 | + | end |
| 135 | - | turtle.digUp() |
| 135 | + | turtle.digUp() |
| 136 | - | elseif turtle.attackUp() then |
| 136 | + | elseif turtle.attackUp() then |
| 137 | - | print "Attacking obstructing entity" |
| 137 | + | print "Attacking obstructing entity" |
| 138 | - | end |
| 138 | + | |
| 139 | - | end |
| 139 | + | |
| 140 | end | |
| 141 | -- This function tries to refuel the turtle to make it have an <amount> of fuel | |
| 142 | -- It assumes that turtle has a refuel ender chest in slot 1 | |
| 143 | function refuel (amount) | |
| 144 | if turtle.getFuelLevel () > amount then | |
| 145 | return true | |
| 146 | else | |
| 147 | turtle.select (1) | |
| 148 | forcePlaceUp () | |
| 149 | turtle.suckUp () | |
| 150 | while turtle.refuel (1) do | |
| 151 | if turtle.getFuelLevel() >= amount then | |
| 152 | turtle.dropUp () | |
| 153 | turtle.digUp () | |
| 154 | return true | |
| 155 | end | |
| 156 | if turtle.getItemCount (1) == 0 then | |
| 157 | turtle.suckUp () | |
| 158 | end | |
| 159 | end | |
| 160 | end | |
| 161 | - | turtle.dropUp () |
| 161 | + | turtle.dropUp () |
| 162 | turtle.digUp () | |
| 163 | return false | |
| 164 | end | |
| 165 | ||
| 166 | -- This function checks if there are required amount of fuel, | |
| 167 | -- and if there's not, it tries to refuel it, | |
| 168 | -- if it fails, it hangs until refueling sucseeds | |
| 169 | function checkFuel (amount) | |
| 170 | if turtle.getFuelLevel () > amount then | |
| 171 | return true | |
| 172 | else | |
| 173 | if not refuel (amount) then | |
| 174 | print "No fuel found! Please, add more fuel!" | |
| 175 | while not refuel (amount) do | |
| 176 | sleep (2) | |
| 177 | end | |
| 178 | end | |
| 179 | return true | |
| 180 | end | |
| 181 | end | |
| 182 | ||
| 183 | -- This function used to empty the turtle's inventory into the ender chest in the second slot | |
| 184 | -- Warning! Required a good sorting system able to empty the chest as quickly as possible! | |
| 185 | -- It will hang if chest is full, but it's not recommended | |
| 186 | function dumpStuff () | |
| 187 | turtle.select (2) | |
| 188 | forcePlaceUp () | |
| 189 | for i = 3,16 do | |
| 190 | while turtle.getItemCount (i) > 0 do | |
| 191 | turtle.select (i) | |
| 192 | turtle.dropUp () | |
| 193 | end | |
| 194 | end | |
| 195 | turtle.select (2) | |
| 196 | turtle.digUp () | |
| 197 | turtle.select (1) | |
| 198 | end | |
| 199 | ||
| 200 | function checkSpace () | |
| 201 | if turtle.getItemCount (16) > 0 then | |
| 202 | dumpStuff () | |
| 203 | end | |
| 204 | end | |
| 205 | ||
| 206 | -- Advanced movement function. | |
| 207 | -- Again, I use a set of tables with all the movements and other "directional" turtle actions | |
| 208 | -- The fuction detects if there is a turtle in the direction it wants to move, and if there is one, it waits while it moves away. | |
| 209 | -- If it waits too long (60 seconds), however, it just eats that turtle | |
| 210 | tMove = {
| |
| 211 | forward = turtle.forward, | |
| 212 | up = turtle.up, | |
| 213 | down = turtle.down | |
| 214 | } | |
| 215 | tDetect = {
| |
| 216 | forward = turtle.detect, | |
| 217 | up = turtle.detectUp, | |
| 218 | down = turtle.detectDown | |
| 219 | } | |
| 220 | tDig = {
| |
| 221 | forward = turtle.dig, | |
| 222 | up = turtle.digUp, | |
| 223 | down = turtle.digDown | |
| 224 | } | |
| 225 | tAttack = {
| |
| 226 | forward = turtle.attack, | |
| 227 | up = turtle.attackUp, | |
| 228 | down = turtle.attackDown | |
| 229 | } | |
| 230 | tIsTurtle = {
| |
| 231 | forward = function () | |
| 232 | if peripheral.isPresent ("front") and peripheral.getType ("front") == "turtle" then
| |
| 233 | return true | |
| 234 | end | |
| 235 | return false | |
| 236 | end, | |
| 237 | up = function () | |
| 238 | if peripheral.isPresent ("top") and peripheral.getType ("top") == "turtle" then
| |
| 239 | return true | |
| 240 | end | |
| 241 | return false | |
| 242 | end, | |
| 243 | down = function () | |
| 244 | if peripheral.isPresent ("bottom") and peripheral.getType ("bottom") == "turtle" then
| |
| 245 | return true | |
| 246 | end | |
| 247 | return false | |
| 248 | end | |
| 249 | } | |
| 250 | function move (direction) | |
| 251 | if not checkFuel (1) then | |
| 252 | return false | |
| 253 | end | |
| 254 | while not tMove[direction]() do | |
| 255 | if tDetect[direction]() then | |
| 256 | if tIsTurtle[direction]() then | |
| 257 | print "Other turtle detected. Waiting..." | |
| 258 | while tIsTurtle[direction]() do | |
| 259 | sleep (5) | |
| 260 | end | |
| 261 | else | |
| 262 | if tDig[direction]() then | |
| 263 | checkSpace () | |
| 264 | else | |
| 265 | print "Can't pass the obstruction!" | |
| 266 | return false | |
| 267 | end | |
| 268 | end | |
| 269 | elseif tAttack[direction]() then | |
| 270 | checkSpace () | |
| 271 | end | |
| 272 | end | |
| 273 | updateLocation (direction) | |
| 274 | return true | |
| 275 | end | |
| 276 | ||
| 277 | -- This one is used to move turtle to specified f direction OR up/down <count times> | |
| 278 | function moveEx (direction, count) | |
| 279 | if type(direction) == "number" then | |
| 280 | turnTo (direction) | |
| 281 | for i = 1, count do | |
| 282 | move ("forward")
| |
| 283 | end | |
| 284 | else | |
| 285 | for i = 1, count do | |
| 286 | move (direction) | |
| 287 | end | |
| 288 | end | |
| 289 | end | |
| 290 | ||
| 291 | -- A height function. For convinience | |
| 292 | function height (value) | |
| 293 | local diff = value - location.y | |
| 294 | refuel(math.abs(diff)) | |
| 295 | if diff > 0 then | |
| 296 | moveEx ("up", diff)
| |
| 297 | elseif diff < 0 then | |
| 298 | moveEx ("down", -diff)
| |
| 299 | end | |
| 300 | end | |
| 301 | ||
| 302 | -- Small goto function. It moves turtle in one axis. | |
| 303 | -- Example: module.gotoOne ("x", 10) moves the turtle to x = 10
| |
| 304 | function gotoOne (coordinate, value) | |
| 305 | if coordinate == "y" then | |
| 306 | height (value) | |
| 307 | elseif coordinate == "x" then | |
| 308 | local diff = value - location.x | |
| 309 | refuel(math.abs(diff)) | |
| 310 | if diff > 0 then | |
| 311 | moveEx (0, diff) | |
| 312 | elseif diff < 0 then | |
| 313 | moveEx (2, -diff) | |
| 314 | end | |
| 315 | elseif coordinate == "z" then | |
| 316 | local diff = value - location.z | |
| 317 | refuel(math.abs(diff)) | |
| 318 | if diff > 0 then | |
| 319 | moveEx (1, diff) | |
| 320 | elseif diff < 0 then | |
| 321 | moveEx (3, -diff) | |
| 322 | end | |
| 323 | end | |
| 324 | end | |
| 325 | ||
| 326 | -- Let's organize our movement a bit to avoid movement deadlocks. Thanks to Doyle3694 for the idea | |
| 327 | -- It is 2D navigation, so height is not taken into account. It will allow turtles to relocate themselves to their mining positions | |
| 328 | -- without stucking. | |
| 329 | -- I'll divide all the 2D area to four zones. In each zone turtle can move only in two directions. | |
| 330 | -- Zones are determinated by the pair of coordinates. Turtles will move clockwise relative to the point with that coordinates | |
| 331 | -- height is the heighat at which all navigation is done | |
| 332 | -- There is a function to set the zones | |
| 333 | local naviZones = {x = 0, z = 0, height = 0}
| |
| 334 | function setZones (x, z, height) | |
| 335 | naviZones.x = x | |
| 336 | naviZones.z = z | |
| 337 | naviZones.height = height | |
| 338 | end | |
| 339 | ||
| 340 | -- There is a table used to determine to which directions turtle is allowed to move. | |
| 341 | -- Direction "first" is the direction turtle will move first ^_^ This one can't lead out of the zone. | |
| 342 | -- Direction "second" is leading to the next zone. | |
| 343 | -- Directions are the tables of coordinate and direction (+1 - positive, -1 - negative) | |
| 344 | local tZones = {
| |
| 345 | z1 = {first = {"x", 1}, second = {"z", 1}},
| |
| 346 | z2 = {first = {"z", 1}, second = {"x", -1}},
| |
| 347 | z3 = {first = {"x", -1}, second = {"z", -1}},
| |
| 348 | z4 = {first = {"z", -1}, second = {"x", 1}}
| |
| 349 | } | |
| 350 | ||
| 351 | -- Here is a function to determine in which zone turtle is | |
| 352 | function currentZone () | |
| 353 | if location.x > naviZones.x then | |
| 354 | if location.z > naviZones.z then | |
| 355 | return "z2" | |
| 356 | else | |
| 357 | return "z1" | |
| 358 | end | |
| 359 | else | |
| 360 | if location.z > naviZones.z then | |
| 361 | return "z3" | |
| 362 | else | |
| 363 | return "z4" | |
| 364 | end | |
| 365 | end | |
| 366 | end | |
| 367 | ||
| 368 | -- And there is one used to navigate turtle, taking into account zones. | |
| 369 | -- All the navigation is done at zones.height and then turtle changes it's height | |
| 370 | function navigateTo (destination) | |
| 371 | -- go to zones.height only if we need to move | |
| 372 | if destination.x ~= location.x or destination.z ~= location.z then | |
| 373 | height (naviZones.height) | |
| 374 | end | |
| 375 | while location.x ~= destination.x or location.z ~= destination.z do -- navigate between zones until we are in the place | |
| 376 | - | local zone = currentZone () |
| 376 | + | local zone = currentZone () |
| 377 | -- Let's unpack all the coordinates | |
| 378 | local coordinateFirst, directionFirst = unpack (tZones[zone].first) | |
| 379 | local coordinateSecond, directionSecond = unpack (tZones[zone].second) | |
| 380 | -- And check some things | |
| 381 | -- if we are allowed to move at both directions - just do it! | |
| 382 | if (destination[coordinateFirst]-location[coordinateFirst]) * directionFirst >= 0 | |
| 383 | and (destination[coordinateSecond]-location[coordinateSecond]) * directionSecond >= 0 then | |
| 384 | -- BTW, we just check there that coordinate difference and destination has the same sign | |
| 385 | -- Otherwise turtle that is already went to "second" coordinate won't be able to change it's "first" coordinate | |
| 386 | -- Then just use gotoOne to go to the desired location | |
| 387 | gotoOne (coordinateFirst, destination[coordinateFirst]) | |
| 388 | gotoOne (coordinateSecond, destination[coordinateSecond]) | |
| 389 | else | |
| 390 | -- If we are not allowed to move by any of those coordinates in current zone | |
| 391 | -- Just head up to the second zone | |
| 392 | local nextPosition = naviZones[coordinateSecond] | |
| 393 | -- We need to do that for actually leave z1 and z4 since they are one block bigger | |
| 394 | if zone == "z4" or zone == "z1" then | |
| 395 | nextPosition = nextPosition + 1 | |
| 396 | end | |
| 397 | -- go to the next zone! | |
| 398 | gotoOne (coordinateSecond, nextPosition) | |
| 399 | end | |
| 400 | end | |
| 401 | - | -- if y is set - move to y. |
| 401 | + | -- if y is set - move to y. |
| 402 | - | if destination.y ~= nil then |
| 402 | + | if destination.y ~= nil then |
| 403 | - | height(destination.y) |
| 403 | + | height(destination.y) |
| 404 | - | end |
| 404 | + | |
| 405 | -- same for f | |
| 406 | - | if destination.f ~= nil then |
| 406 | + | if destination.f ~= nil then |
| 407 | - | turnTo(destination.f) |
| 407 | + | turnTo(destination.f) |
| 408 | - | end |
| 408 | + | |
| 409 | end | |
| 410 | ||
| 411 | --[[ | |
| 412 | ********************************************************************************************* | |
| 413 | * Communication Part * | |
| 414 | ********************************************************************************************* | |
| 415 | ]]-- | |
| 416 | -- There are some variables used for communication | |
| 417 | -- ID is the turtle's unique identifier | |
| 418 | -- Master is the ID of the master | |
| 419 | -- Channel is the channel used to send messages to Master | |
| 420 | -- Master should respond on channel+1 | |
| 421 | -- Type is the type of the module. Used by Master to determine what it can do | |
| 422 | local ID = 0 | |
| 423 | local Master = 0 | |
| 424 | - | local channel = 100 |
| 424 | + | |
| 425 | function setType (newType) | |
| 426 | Type = newType | |
| 427 | - | Type = newType |
| 427 | + | |
| 428 | ||
| 429 | -- The first function is used to parse a message received on modem | |
| 430 | - | -- Wee need a modem to communicate. |
| 430 | + | |
| 431 | - | local modem = peripheral.wrap ("right")
|
| 431 | + | |
| 432 | -- 1) Protocol - must be equal to "KuuNet" | |
| 433 | -- 2) ID - that must be equal to turtle's ID | |
| 434 | -- 3) Master - that must be equal to Master variable. | |
| 435 | -- Some other fiels | |
| 436 | function isValid (message) | |
| 437 | if message ~= nil then | |
| 438 | if message.Protocol ~= "KuuNet" then | |
| 439 | return false | |
| 440 | end | |
| 441 | - | if message ~= nil then |
| 441 | + | if message.ID ~= ID then |
| 442 | - | if message.Protocol ~= "KuuNet" then |
| 442 | + | return false |
| 443 | - | return false |
| 443 | + | |
| 444 | - | end |
| 444 | + | if message.Master ~= Master then |
| 445 | - | if message.ID ~= ID then |
| 445 | + | return false |
| 446 | - | return false |
| 446 | + | |
| 447 | - | end |
| 447 | + | |
| 448 | - | if message.Master ~= Master then |
| 448 | + | |
| 449 | - | return false |
| 449 | + | return false |
| 450 | - | end |
| 450 | + | |
| 451 | - | return true |
| 451 | + | |
| 452 | - | else |
| 452 | + | |
| 453 | - | return false |
| 453 | + | |
| 454 | - | end |
| 454 | + | |
| 455 | -- It returns response as message or nil | |
| 456 | function request (message, timeout) | |
| 457 | -- open a channel to listen for response | |
| 458 | rednet.open ("right")
| |
| 459 | local request = {
| |
| 460 | Protocol = "KuuNet", | |
| 461 | - | -- open a channel to listen for response |
| 461 | + | ID = ID, |
| 462 | - | modem.open (channel+1) |
| 462 | + | Type = Type, |
| 463 | - | local request = {
|
| 463 | + | Master = Master, |
| 464 | - | Protocol = "KuuNet", |
| 464 | + | Request = message |
| 465 | - | ID = ID, |
| 465 | + | } |
| 466 | - | Type = Type, |
| 466 | + | rednet.broadcast (textutils.serialize(request)) |
| 467 | - | Master = Master, |
| 467 | + | local response = nil |
| 468 | - | Request = message |
| 468 | + | parallel.waitForAny ( |
| 469 | - | } |
| 469 | + | function () |
| 470 | - | modem.transmit (channel, channel+1, textutils.serialize(request)) |
| 470 | + | sleep (timeout) |
| 471 | - | local response = nil |
| 471 | + | end, |
| 472 | - | parallel.waitForAny ( |
| 472 | + | function () |
| 473 | - | function () |
| 473 | + | while true do |
| 474 | - | sleep (timeout) |
| 474 | + | local event, sndID, text_msg, senderDistance = os.pullEvent("rednet_message")
|
| 475 | - | end, |
| 475 | + | local msg = textutils.unserialize (text_msg) |
| 476 | - | function () |
| 476 | + | if isValid(msg) then |
| 477 | - | while true do |
| 477 | + | response = msg |
| 478 | - | local event, modemSide, sndChan, rplyChan, text_msg, senderDistance = os.pullEvent("modem_message")
|
| 478 | + | break |
| 479 | - | local msg = textutils.unserialize (text_msg) |
| 479 | + | end |
| 480 | - | if isValid(msg) then |
| 480 | + | end |
| 481 | - | response = msg |
| 481 | + | |
| 482 | - | break |
| 482 | + | ) |
| 483 | - | end |
| 483 | + | rednet.close ("right")
|
| 484 | - | end |
| 484 | + | return response |
| 485 | - | end |
| 485 | + | |
| 486 | - | ) |
| 486 | + | |
| 487 | - | modem.close (channel+1) |
| 487 | + | |
| 488 | - | return response |
| 488 | + | |
| 489 | * Operation part * | |
| 490 | ********************************************************************************************* | |
| 491 | ]]-- | |
| 492 | -- Fallback location is the point where module goes if it can't get a task from Master | |
| 493 | local fallbackLocation = {}
| |
| 494 | ||
| 495 | -- We need to read all the data we need to move around - turtle's position and navigation zones | |
| 496 | -- "initdata" is the file created by Master and containing all the data that's similar for each module placed by that Master | |
| 497 | function init () | |
| 498 | local file = fs.open ("/disk/initdata", "r")
| |
| 499 | local communicationData = textutils.unserialize (file.readLine ()) | |
| 500 | Master = communicationData.MasterID | |
| 501 | -- set module's location | |
| 502 | location = textutils.unserialize (file.readLine ()) | |
| 503 | -- set navigation data | |
| 504 | naviZones = textutils.unserialize (file.readLine ()) | |
| 505 | - | channel = communicationData.channel |
| 505 | + | |
| 506 | -- set fallbackLocation to the point where we are, but at navigation height. | |
| 507 | - | location = textutils.unserialize (file.readLine ()) |
| 507 | + | |
| 508 | ||
| 509 | - | naviZones = textutils.unserialize (file.readLine ()) |
| 509 | + | |
| 510 | - | |
| 510 | + | local response = request ("Master", 5)
|
| 511 | ID = response.NewID | |
| 512 | ||
| 513 | - | |
| 513 | + | -- move forward to be ready to go down. Because of the placement rules, master should place modules on some block, so the block under the module won't be empty. |
| 514 | move("forward")
| |
| 515 | - | local response = request ("Master", 5)
|
| 515 | + | |
| 516 | - | ID = response.NewID |
| 516 | + | |
| 517 | -- Here is the task table. It is the table, that contains all the task module can get form Master and associated functions | |
| 518 | - | -- move forward to be ready to go down. Because of the placement rules, master should place modules on some block, so the block under the module won't be empty. |
| 518 | + | |
| 519 | - | move("forward")
|
| 519 | + | |
| 520 | -- 1) Requesting a task from master | |
| 521 | -- 2) Moving to the location specified in response (if present) | |
| 522 | -- 3) Executing the associated function | |
| 523 | -- There is always a default task "return" which returns module to Master. | |
| 524 | -- response from Master is always passed to the function, so, if it contains additional data, you can use it | |
| 525 | -- Return is a task to return. Master should pass a xet of coordinates as well as "f" direction to make module face the Master. | |
| 526 | tTasks = {
| |
| 527 | Return = function (response) | |
| 528 | move ("forward")
| |
| 529 | request ("Returned", 3)
| |
| 530 | sleep (30) | |
| 531 | end | |
| 532 | - | Return = function (response) |
| 532 | + | |
| 533 | - | move ("forward")
|
| 533 | + | |
| 534 | - | request ("Returned", 3)
|
| 534 | + | |
| 535 | - | sleep (30) |
| 535 | + | |
| 536 | - | end |
| 536 | + | for key, value in pairs (taskTable) do |
| 537 | tTasks[key] = value | |
| 538 | end | |
| 539 | end | |
| 540 | ||
| 541 | - | for key, value in pairs (taskTable) do |
| 541 | + | |
| 542 | - | tTasks[key] = value |
| 542 | + | |
| 543 | - | end |
| 543 | + | tTasks [task] = nil |
| 544 | end | |
| 545 | ||
| 546 | -- And a main operation function | |
| 547 | function operate () | |
| 548 | - | tTasks [task] = nil |
| 548 | + | while true do |
| 549 | local task | |
| 550 | -- failedRequests indicates how many times Master didn't answered to request | |
| 551 | local failedRequests = 0 | |
| 552 | while task == nil do | |
| 553 | - | while true do |
| 553 | + | task = request ("Task", 5)
|
| 554 | - | local task |
| 554 | + | |
| 555 | failedRequests = failedRequests + 1 | |
| 556 | -- if there are 5 requests failed, then change position to the point of last communication | |
| 557 | - | while task == nil do |
| 557 | + | |
| 558 | - | task = request ("Task", 5)
|
| 558 | + | |
| 559 | navigateTo (fallbackLocation) | |
| 560 | end | |
| 561 | else | |
| 562 | lastCommunication = getPosition() | |
| 563 | end | |
| 564 | end | |
| 565 | if task.x ~= nil and task.z ~= nil then | |
| 566 | navigateTo (task) | |
| 567 | end | |
| 568 | tTasks [task.Task](task) -- Task. tttTask. Tasktask. taskataskatask. HerpDerp. | |
| 569 | - | end |
| 569 | + | |
| 570 | - | if task.x ~= nil and task.z ~= nil then |
| 570 | + |