server-phone.lua
236 lines · 6.4 KB
PHONE SERVER--
Copy & run
wget https://perlytiara.github.io/turtles.tips/raw/programs/perlytiara/BigBaemingGamers/server/server-phone.lua
| 1 | --PHONE SERVER-- |
| 2 | |
| 3 | local SERVER_PORT = 420 |
| 4 | local CLIENT_PORT = 0 |
| 5 | local SLOT_COUNT = 16 |
| 6 | |
| 7 | |
| 8 | local segmentation = 5 |
| 9 | if (#arg == 1) then |
| 10 | segmentation = tonumber(arg[1]) |
| 11 | elseif (#arg == 0) then |
| 12 | print(string.format("No segmentation size selected, defaulting to %d", segmentation)) |
| 13 | else |
| 14 | print('Too many args given...') |
| 15 | exit(1) |
| 16 | end |
| 17 | |
| 18 | |
| 19 | local modem = peripheral.wrap("left") |
| 20 | modem.open(SERVER_PORT) |
| 21 | |
| 22 | local target = vector.new() |
| 23 | local size = vector.new() |
| 24 | local finish = vector.new() |
| 25 | |
| 26 | -- I STOLE -- |
| 27 | function split (inputstr, sep) |
| 28 | if sep == nil then |
| 29 | sep = "%s" |
| 30 | end |
| 31 | local t={} |
| 32 | for str in string.gmatch(inputstr, "([^"..sep.."]+)") do |
| 33 | table.insert(t, str) |
| 34 | end |
| 35 | return t |
| 36 | end |
| 37 | |
| 38 | function parseParams(data) |
| 39 | coords = {} |
| 40 | params = split(data, " ") |
| 41 | |
| 42 | coords[1] = vector.new(params[1], params[2], params[3]) |
| 43 | coords[2] = vector.new(params[4], params[5], params[6]) |
| 44 | |
| 45 | return (coords) |
| 46 | end |
| 47 | |
| 48 | function getItemIndex(itemName) |
| 49 | for slot = 1, SLOT_COUNT, 1 do |
| 50 | local item = turtle.getItemDetail(slot) |
| 51 | if(item ~= nil) then |
| 52 | if(item["name"] == itemName) then |
| 53 | return slot |
| 54 | end |
| 55 | end |
| 56 | end |
| 57 | end |
| 58 | |
| 59 | -- Try multiple candidate item ids; returns first slot found or nil |
| 60 | function getFirstItemIndex(candidates) |
| 61 | for i = 1, #candidates, 1 do |
| 62 | local idx = getItemIndex(candidates[i]) |
| 63 | if idx ~= nil then return idx end |
| 64 | end |
| 65 | return nil |
| 66 | end |
| 67 | |
| 68 | function checkFuel() |
| 69 | turtle.select(1) |
| 70 | |
| 71 | if(turtle.getFuelLevel() < 50) then |
| 72 | print("Attempting Refuel...") |
| 73 | for slot = 1, SLOT_COUNT, 1 do |
| 74 | turtle.select(slot) |
| 75 | if(turtle.refuel(1)) then |
| 76 | return true |
| 77 | end |
| 78 | end |
| 79 | return false |
| 80 | else |
| 81 | return true |
| 82 | end |
| 83 | end |
| 84 | |
| 85 | function deployFuelChest() |
| 86 | if (not checkFuel()) then |
| 87 | print("SERVER NEEDS FUEL...") |
| 88 | exit(1) |
| 89 | end |
| 90 | local chestIdx = getItemIndex("enderstorage:ender_storage") |
| 91 | if chestIdx == nil then |
| 92 | print("WARN: No EnderStorage found for fuel chest; skipping fuel chest deploy.") |
| 93 | return |
| 94 | end |
| 95 | turtle.select(chestIdx) |
| 96 | turtle.up() |
| 97 | turtle.place() |
| 98 | turtle.down() |
| 99 | end |
| 100 | |
| 101 | |
| 102 | function deploy(startCoords, quarySize, endCoords, options) |
| 103 | --Place turtle from inventory |
| 104 | local turtleCandidates = { |
| 105 | "computercraft:turtle_advanced", |
| 106 | "computercraft:turtle_expanded", |
| 107 | "computercraft:turtle_normal", |
| 108 | } |
| 109 | local turtleSlot = getFirstItemIndex(turtleCandidates) |
| 110 | if turtleSlot == nil then |
| 111 | print("ERROR: No turtle item found in inventory. Place advanced/normal turtle in inventory.") |
| 112 | os.exit(1) |
| 113 | end |
| 114 | turtle.select(turtleSlot) |
| 115 | while(turtle.detect()) do |
| 116 | os.sleep(0.3) |
| 117 | end |
| 118 | |
| 119 | --Place and turn on turtle |
| 120 | turtle.place() |
| 121 | peripheral.call("front", "turnOn") |
| 122 | |
| 123 | |
| 124 | --Wait for client to send ping |
| 125 | event, side, senderChannel, replyChannel, msg, distance = os.pullEvent("modem_message") |
| 126 | if(msg ~= "CLIENT_DEPLOYED") then |
| 127 | print("No client deploy message, exitting...") |
| 128 | os.exit() |
| 129 | end |
| 130 | |
| 131 | |
| 132 | if(options["withStorage"]) then |
| 133 | --Set up ender chest |
| 134 | if (not checkFuel()) then |
| 135 | print("SERVER NEEDS FUEL...") |
| 136 | exit(1) |
| 137 | end |
| 138 | local chestIdx = getItemIndex("enderstorage:ender_storage") |
| 139 | if chestIdx ~= nil then |
| 140 | turtle.select(chestIdx) |
| 141 | turtle.up() |
| 142 | turtle.place() |
| 143 | turtle.down() |
| 144 | else |
| 145 | print("WARN: withStorage requested but no EnderStorage in inventory; continuing without storage for this bot.") |
| 146 | end |
| 147 | end |
| 148 | |
| 149 | deployFuelChest() |
| 150 | local storageBit = options["withStorage"] and 1 or 0 |
| 151 | |
| 152 | -- Client is deployed |
| 153 | modem.transmit(CLIENT_PORT, |
| 154 | SERVER_PORT, |
| 155 | string.format("%d %d %d %d %d %d %d %d %d %d", |
| 156 | startCoords.x, startCoords.y, startCoords.z, |
| 157 | quarySize.x, quarySize.y, quarySize.z, |
| 158 | endCoords.x, endCoords.y, endCoords.z, |
| 159 | storageBit |
| 160 | )) |
| 161 | end |
| 162 | |
| 163 | |
| 164 | |
| 165 | -- Return array of arbitrary size for each bot placement |
| 166 | function getPositioningTable(x, z, segmaentationSize) |
| 167 | local xRemainder = x % segmaentationSize |
| 168 | local zRemainder = z % segmaentationSize |
| 169 | |
| 170 | local xMain = x - xRemainder |
| 171 | local zMain = z - zRemainder |
| 172 | |
| 173 | xRemainder = (xRemainder == 0 and segmaentationSize or xRemainder) |
| 174 | zRemainder = (zRemainder == 0 and segmaentationSize or zRemainder) |
| 175 | |
| 176 | local positions = {} |
| 177 | |
| 178 | for zi = 0, z - 1 , segmaentationSize do |
| 179 | for xi = 0, x - 1, segmaentationSize do |
| 180 | |
| 181 | local dims = {xi, zi, segmaentationSize, segmaentationSize} |
| 182 | if(xi >= x - segmaentationSize and xi <= x - 1 ) then |
| 183 | dims = {xi, zi, xRemainder, segmaentationSize} |
| 184 | end |
| 185 | |
| 186 | if(zi >= z - segmaentationSize and zi <= z - 1 ) then |
| 187 | dims = {xi, zi, segmaentationSize, zRemainder} |
| 188 | end |
| 189 | |
| 190 | table.insert(positions, dims) |
| 191 | end |
| 192 | end |
| 193 | |
| 194 | return table.pack(positions, xRemainder, zRemainder) |
| 195 | end |
| 196 | |
| 197 | while (true) do |
| 198 | -- Wait for phone |
| 199 | print("Waiting for target signal...") |
| 200 | event, side, senderChannel, replyChannel, msg, distance = os.pullEvent("modem_message") |
| 201 | |
| 202 | -- Parse out coordinates and options |
| 203 | local args = split(msg, " ") |
| 204 | local withStorageBit = args[#args] |
| 205 | local withStorage = (withStorageBit == "1") |
| 206 | data = parseParams(msg) |
| 207 | options = {} |
| 208 | options["withStorage"] = withStorage |
| 209 | |
| 210 | target = data[1] |
| 211 | size = data[2] |
| 212 | |
| 213 | finish = vector.new(gps.locate()) |
| 214 | finish.y = finish.y + 1 |
| 215 | print(string.format( "RECEIVED QUARY REQUEST AT: %d %d %d", target.x, target.y, target.z)) |
| 216 | |
| 217 | tab, xDf, zDf = table.unpack(getPositioningTable(size.x, size.z, segmentation)) |
| 218 | |
| 219 | print(string.format("Deploying %d bots...", #tab)) |
| 220 | for i = 1, #tab, 1 do |
| 221 | xOffset, zOffset, width, height = table.unpack(tab[i]) |
| 222 | local offsetTarget = vector.new(target.x + xOffset, target.y, target.z + zOffset) |
| 223 | local sclaedSize = vector.new(width, size.y, height) |
| 224 | |
| 225 | deploy(offsetTarget, sclaedSize, finish, options) |
| 226 | os.sleep(1) |
| 227 | print(string.format( "Deploying to; %d %d %d %d %d", target.x + xOffset, target.y, target.z + zOffset, sclaedSize.x, sclaedSize.z)) |
| 228 | end |
| 229 | |
| 230 | -- All bots deployed, wait for last bot finished signal |
| 231 | event, side, senderChannel, replyChannel, msg, distance = os.pullEvent("modem_message") |
| 232 | turtle.digUp() |
| 233 | |
| 234 | end |
| 235 | |
| 236 |