--[[ tutel client __ .,-;-;-,. /'_\ _/_/_/_|_\_\) / '-<_><_><_><_>=/\ `/_/====/_/-'\_\ "" "" "" ]] --[[ network variables ]] local HOST_CHANNEL local TURTLE_CHANNEL local MSG_HEADER = 0x747574656C local modem = peripheral.find("modem") or error("No modems found", 0) modem.open(0) -- general port used for scanning --[[ logging ]] local logTypes = { ["general"] = { ["BG"] = colours.green, ["FG"] = colours.white }, ["info"] = { ["BG"] = colours.blue, ["FG"] = colours.white }, ["warning"] = { ["BG"] = colours.orange, ["FG"] = colours.black, ["AffectContent"] = true }, ["error"] = { ["BG"] = colours.red, ["FG"] = colours.black, ["AffectContent"] = true } } local log = {} for typeName, format in pairs(logTypes) do log[typeName] = function(fmt, ...) local prevColourBg = term.getBackgroundColour() local prevColourFg = term.getTextColour() term.setBackgroundColour(format["BG"]) term.setTextColour(format["FG"]) io.write(("[%s @ line %d]"):format(typeName, debug.getinfo(2, "l").currentline)) if format["AffectContent"] then io.write(" ", string.format(fmt, ...), "\n") term.setBackgroundColour(prevColourBg) term.setTextColour(prevColourFg) else term.setBackgroundColour(prevColourBg) term.setTextColour(prevColourFg) io.write(" ", string.format(fmt, ...), "\n") end end end --[[ helper networking functions ]] function sendToHost(name, msgData) local message = { ["header"] = MSG_HEADER, ["name"] = name, ["data"] = msgData or {}, ["id"] = os.getComputerID() } modem.transmit(HOST_CHANNEL, TURTLE_CHANNEL or 0, message) end --[[ command handling ]] local commands = {} function declareCommandHandler(name, handler, requiredKeys) commands[name] = { ["keys"] = requiredKeys or {}, ["handler"] = handler } end -- scan function handleScan(keys) -- to-do: check and maybe inform if turtle is already linked to another host HOST_CHANNEL = keys.hostChannel log.info("received scan, host channel assigned to %d, replying...", keys.hostChannel) local x, y, z = gps.locate() sendToHost("SCAN", { ["positionX"] = x, ["positionY"] = y, ["positionZ"] = z, ["fuel"] = turtle.getFuelLevel() }) -- HOST_CHANNEL = keys.hostChannel -- REPLY_CHANNEL = keys.replyChannel -- log.info("Received scan, HOST_CHANNEL: %d - REPLY_CHANNEL: %d", HOST_CHANNEL, REPLY_CHANNEL) end declareCommandHandler("SCAN", handleScan, { ["hostChannel"] = "number" }) -- register function handleRegister(keys) log.info("received register for id:", keys.id) if (keys.id ~= os.getComputerID()) then return end -- message was not meant for this computer TURTLE_CHANNEL = keys.turtleChannel log.info("received register, host assigned channel: %d", keys.turtleChannel) modem.open(keys.turtleChannel) modem.close(0) end declareCommandHandler("REGISTER", handleRegister, { ["id"] = "number", ["turtleChannel"] = "number" }) -- status function handleStatus(keys) end declareCommandHandler("STATUS", handleStatus) -- goto function handleGoTo(keys) end declareCommandHandler("GOTO", handleGoTo, { ["destX"] = "number", ["destY"] = "number", ["destZ"] = "number" }) -- mine area function handleMineArea(keys) end declareCommandHandler("MINE-AREA", handleGoTo, { ["startX"] = "number", ["startY"] = "number", ["destX"] = "number", ["destZ"] = "number" }) -- abort function handleAbort() end declareCommandHandler("ABORT", handleAbort) --[[ event handling ]] local eventListeners = {} local function registerEventListener(name, listener) if not eventListeners[name] then eventListeners[name] = {} end table.insert(eventListeners[name], listener) end local function dispatchEvents(event, ...) local eventTbl = eventListeners[event] if not eventTbl then return end for i = 1, #eventTbl, 1 do eventTbl[i](...) end end local function handleMessages(side, channel, replyChannel, message, dist) if TURTLE_CHANNEL and channel ~= TURTLE_CHANNEL then return end -- msg validation if type(message) ~= "table" then return end if not message.header or message.header ~= MSG_HEADER then return end if not message.data then message.data = {} end -- cmd validation if not message.name then log.warning("received nameless command?") return end if not commands[message.name] then log.error("unhandled command (%s)", message.name) return end local cmd = commands[message.name] for i, v in pairs(cmd.keys) do if type(message.data[i]) ~= v and v ~= "optional" then log.error("command %s requires key %s of type %s (was %s)", message.name, i, v, type(message[i])) return end end -- cmd execution local success, err = pcall(cmd.handler, message.data, message.id) if not success then log.error("error occurred while executing command %s: %s", message.name, err) return end log.info("processed command (%s)", message.name) end registerEventListener("modem_message", handleMessages) --[[ event polling ]] function pollEvents() local eventData = { os.pullEvent() } local eventName = eventData[1] table.remove(eventData, 1) dispatchEvents(eventName, table.unpack(eventData)) end --[[ main loop ]] log.info("init") while true do pollEvents() end