CC-navigation/netNav/remoteControl.lua

303 lines
7.8 KiB
Lua

local tArgs = {...}
-- CONSTANTS
local REDNET_PROTOCOL = "NET_NAV:CONTROL"
-- VARIABLES
local mapName
local listWidth, listHeight
local buttonInstance
local turtleList
local selectedTurtle
local setSelectedTurtle
local turtleData
local guiOffset
local mainTerm
-- CHECK MAP NAME
mapName = tArgs[1]
if type(mapName) ~= "string" then
printError("mapName must be string")
return
end
-- LOAD BUTTON_HANDLER API
if not buttonHandler then
if not os.loadAPI("buttonHandler") then
error("could not load buttonHandler API")
end
end
-- OPEN REDNET
for _, side in ipairs(redstone.getSides()) do
if peripheral.getType(side) == "modem" then
rednet.open(side)
end
end
if not rednet.isOpen() then
printError("Could not open rednet")
return
end
-- DEFINE REDNET METHODS
local function newPacket(senderID, request, arguments)
return {
mapName,
senderID,
request,
arguments,
}
end
local function sendPacket(packet)
if packet[2] == -1 then
rednet.broadcast(packet, REDNET_PROTOCOL)
else
rednet.send(packet[2], packet, REDNET_PROTOCOL)
end
end
local function sendPingPacket(sendTo)
sendPacket(newPacket(sendTo, "PING"))
end
local function sendExplorePacket(sendTo)
sendPacket(newPacket(sendTo, "EXPLORE", {}))
end
local function sendReturnPacket(sendTo)
sendPacket(newPacket(sendTo, "RETURN", {}))
end
local function sendFollowPacket(sendTo, position)
sendPacket(newPacket(sendTo, "FOLLOW", position))
end
local function sendIdlePacket(sendTo)
sendPacket(newPacket(sendTo, "IDLE", {}))
end
-- SET UP GUI
local function createListValue(turtleID, status)
local value = turtleID..string.rep(" ", math.max(0, 4 - #tostring(turtleID)))
value = value..string.rep(" ", math.max(0, 8 - #status))..status
return value
end
do
term.setBackgroundColour(colours.cyan)
term.setTextColour(colours.white)
term.clear()
local width, height = term.getSize()
guiOffset = math.ceil((width - 26)/2)
local win = window.create(term.current(), guiOffset + 1, 1, 26, height, true)
win.setBackgroundColour(colours.grey)
win.clear()
mainTerm = term.redirect(win)
end
buttonInstance = buttonHandler.new(term.current())
local width, height = term.getSize()
paintutils.drawLine(13, 1, 13, height, colours.cyan)
paintutils.drawLine(14, height - 5, width, height - 5, colours.cyan)
paintutils.drawLine(14, 6, width, 6, colours.cyan)
-- SET UP TURTLE LIST SECTION
local function turtleListHandler(value)
if value then
local turtleID = tonumber(value:match("^%d+"))
local data = turtleData[turtleID] or {}
setSelectedTurtle(turtleID, unpack(data))
end
end
turtleData = {}
turtleList = buttonInstance:AddList("turtle", {}, turtleListHandler, 1, 1, 12, height - 1)
local function allPing()
buttonInstance:Flash("ALL_PING")
turtleData = {}
turtleList:SetValues({})
sendPingPacket(-1)
end
buttonInstance:Add("ALL_PING", allPing, 1, height, 12, 1, " Refresh ", colours.red)
-- SET UP INDIVIDUAL TURTLE CONTROL SECTION
term.setCursorPos(14, 1)
term.setBackgroundColour(colours.red)
term.setTextColour(colours.white)
term.write(" Control: nil")
local function selectedExplore()
if selectedTurtle then
buttonInstance:Flash("EXPLORE")
sendExplorePacket(selectedTurtle)
end
end
buttonInstance:Add("EXPLORE", selectedExplore, 14, 2, 13, 1, " Explore ", colours.grey)
local function selectedReturn()
if selectedTurtle then
buttonInstance:Flash("RETURN")
sendReturnPacket(selectedTurtle)
end
end
buttonInstance:Add("RETURN", selectedReturn, 14, 3, 13, 1, " Return ", colours.lightGrey)
local function selectedFollow()
if selectedTurtle then
buttonInstance:Flash("FOLLOW")
local x, y, z = gps.locate()
if x then
local position = {math.floor(x), math.floor(y), math.floor(z)}
sendFollowPacket(selectedTurtle, position)
end
end
end
buttonInstance:Add("FOLLOW", selectedFollow, 14, 4, 13, 1, " Follow ", colours.grey)
local function selectedStop()
if selectedTurtle then
buttonInstance:Flash("STOP")
sendIdlePacket(selectedTurtle)
end
end
buttonInstance:Add("STOP", selectedStop, 14, 5, 13, 1, " Stop ", colours.lightGrey)
-- SET UP TURTLE INFO SECTION
setSelectedTurtle = function(turtleID, xPos, yPos, zPos)
if turtleID then
selectedTurtle = turtleID
end
term.setCursorPos(14, 1)
term.setBackgroundColour(colours.red)
term.setTextColour(colours.white)
term.write(" Control:"..string.rep(" ", math.max(0, 4 - #tostring(turtleID)))..tostring(turtleID))
term.setBackgroundColour(colours.grey)
term.setTextColour(colours.white)
term.setCursorPos(14, 7)
term.write("ID:"..string.rep(" ", 10 - #tostring(turtleID))..tostring(turtleID))
term.setCursorPos(14, 9)
term.write("X Pos:"..string.rep(" ", 7 - #tostring(xPos))..tostring(xPos))
term.setCursorPos(14, 10)
term.write("Y Pos:"..string.rep(" ", 7 - #tostring(yPos))..tostring(yPos))
term.setCursorPos(14, 11)
term.write("Z Pos:"..string.rep(" ", 7 - #tostring(zPos))..tostring(zPos))
end
setSelectedTurtle()
local function selectedPing()
if selectedTurtle then
buttonInstance:Flash("PING")
sendPingPacket(selectedTurtle)
end
end
buttonInstance:Add("PING", selectedPing, 14, height - 6, 13, 1, " Refresh ", colours.red)
-- SET UP CONTROL ALL SECTION
term.setCursorPos(14, height - 4)
term.setBackgroundColour(colours.red)
term.setTextColour(colours.white)
term.write(" Control All ")
local function allExplore()
buttonInstance:Flash("ALL_EXPLORE")
sendExplorePacket(-1)
end
buttonInstance:Add("ALL_EXPLORE", allExplore, 14, height - 3, 13, 1, " Explore ", colours.grey)
local function allReturn()
buttonInstance:Flash("ALL_RETURN")
sendReturnPacket(-1)
end
buttonInstance:Add("ALL_RETURN", allReturn, 14, height - 2, 13, 1, " Return ", colours.lightGrey)
local function allFollow()
buttonInstance:Flash("ALL_FOLLOW")
local x, y, z = gps.locate()
if x then
local position = {math.floor(x), math.floor(y), math.floor(z)}
sendFollowPacket(-1, position)
end
end
buttonInstance:Add("ALL_FOLLOW", allFollow, 14, height - 1, 13, 1, " Follow ", colours.grey)
local function allStop()
buttonInstance:Flash("ALL_STOP")
sendIdlePacket(-1)
end
buttonInstance:Add("ALL_STOP", allStop, 14, height, 13, 1, " Stop ", colours.lightGrey)
-- DEFINE INPUT ROUTINE
local function input()
buttonInstance:Draw()
while true do
local event = {os.pullEvent()}
if event[1] == "mouse_click" then
buttonInstance:HandleClick(event[3] - guiOffset, event[4])
elseif event[1] == "key" then
if event[2] == keys.backspace then
break
elseif event[2] == keys.up then
turtleList:SetOffset(turtleList:GetOffset() - 1)
elseif event[2] == keys.down then
turtleList:SetOffset(turtleList:GetOffset() + 1)
end
end
end
end
-- DEFINE LISTEN ROUTINE
local function listen()
sendPingPacket(-1)
while true do
local senderID, message = rednet.receive(REDNET_PROTOCOL)
if type(message) == "table" and message[1] == mapName then
local sentTo = message[2]
if sentTo == os.computerID() or sentTo == -1 then
if message[3] == "PONG" then
-- update turtleList
local values = turtleList:GetValues()
local found = false
for index, data in ipairs(values) do
local id = tonumber(data:match("^%d+"))
if id == senderID then
data = createListValue(senderID, message[5])
table.remove(values, index)
table.insert(values, index, data)
turtleList:SetValues(values)
found = true
break
end
end
if not found then
local data = createListValue(senderID, message[5])
table.insert(values, data)
turtleList:SetValues(values)
end
turtleData[senderID] = message[4]
if senderID == selectedTurtle then
setSelectedTurtle(senderID, unpack(message[4]))
-- update selectedTurtle info
end
end
end
end
end
end
parallel.waitForAny(input, listen)
term.redirect(mainTerm)
term.setBackgroundColour(colours.black)
term.setTextColour(colours.white)
term.clear()
term.setCursorPos(1, 1)