Computercraft-Turtle-Quarry.../quarry-repeater.lua

220 lines
7.6 KiB
Lua

https://pastebin.com/raw/Te359WA2
--Version 1.0.3
--This program will act as a repeater between a turtle and a receiver computer
--important options are doAcceptPing and arbitraryNumber
--expected message format: {message, id, distance, fingerprint}
--added modifications similar to receiver program
--Config
local doDebug = false --...
local arbitraryNumber = 100 --How many messages to keep between deletions
local saveFile = "QuarryRepeaterSave"
local expectedFingerprints = {quarry = true, quarryReceiver = true}
local acceptLegacy = true --This will auto-format old messages that come along
local doAcceptPing = true --Accept pings. Can be turned off for tight quarters
local pingFingerprint = "ping"
local pingSide = "top"
--Init
local sentMessages = {} --Table of received message ids
local counter = 0
local tempCounter = 0 --How many messages since last delete
local recentID = 1 --Most recent message ID received, used for restore in delete
local channels = {} --List of channels to open listen on
local modem --The wireless modem
local modemSide --Will not necessarily be set
--Function Declarations--
local function debug(...) if doDebug then return print(...) end end --Debug print
local function newID()
return math.random(1,2000000000) --1 through 2 billion; close enough
end
local function save()
debug("Saving File")
local file = fs.open(saveFile, "w")
file.writeLine(textutils.serialize(channels):gsub("[\n\r]","")) --All the channels
file.writeLine(counter) --Total number of messages received
file.writeLine(modemSide) --The side the modem is on, helps for old MC
return file.close()
end
local function addID(id)
sentMessages[id] = true
tempCounter = tempCounter + 1
counter = counter + 1
recentID = id
save()
end
local function openChannels()
for a,b in pairs(channels) do
debug("Checking channel ",b)
if not modem.isOpen(b) then
debug("Opening channel ",b)
modem.open(b)
end
end
end
local function testPeripheral(periph, periphFunc)
if type(periph) ~= "table" then return false end
if type(periph[periphFunc]) ~= "function" then return false end
if periph[periphFunc]() == nil then --Expects string because the function could access nil
return false
end
return true
end
local function initModem() --Sets up modem, returns true if modem exists
if not testPeripheral(modem, "isWireless") then
if peripheral.getType(modemSide or "") == "modem" then
modem = peripheral.wrap(modemSide)
if not modem.isWireless() then --Apparently this is a thing
modem = nil
return false
end
return true
end
if peripheral.find then
modem = peripheral.find("modem", function(side, obj) return obj.isWireless() end)
end
return modem and true or false
end
return true
end
local function addChannel(num, doPrint) --Tries to add channel number. Checks if channel not already added. Speaks if doPrint set to true.
num = tonumber(num)
for a, b in pairs(channels) do
if b == num then
if doPrint then
print("Channel "..num.." already added.")
end
return false
end
end
if num >= 1 and num <= 65535 then
table.insert(channels, num)
if doPrint then
print("Channel "..num.." added.")
end
end
end
--Actual Program Part Starts Here--
if fs.exists(saveFile) then
local file = fs.open(saveFile,"r")
channels = textutils.unserialize(file.readLine()) or (print("Channels could not be read") and {})
counter = tonumber(file.readLine()) or (print("Counter could not be read") and 0)
modemSide = file.readLine() or (print("Modem Side not read") and "")
print("Done reading save file")
file.close()
end
while not initModem() do
print("No modem is connected, please attach one")
if not peripheral.find then
print("What side was that on?")
modemSide = read()
else
os.pullEvent("peripheral")
end
end
openChannels()
sleep(2) --Give users a second to read this stuff.
local continue = true
while continue do
print("\nHit 'q' to quit, 'r' to remove channels, 'p' to ping or any other key to add channels")
local event, key, receivedFreq, replyFreq, received, dist = os.pullEvent()
term.clear()
term.setCursorPos(1,1)
if event == "modem_message" then
print("Modem Message Received")
debug("Received on channel "..receivedFreq.."\nReply channel is "..replyFreq.."\nDistance is "..dist)
if acceptLegacy and type(received) ~= "table" then
debug("Unformatted message, formatting for quarry")
received = { message = received, id = newID(), distance = 0, fingerprint = "quarry"}
end
debug("Message Properties")
for a, b in pairs(received) do
debug(a," ",b)
end
if expectedFingerprints[received.fingerprint] and not sentMessages[received.id] then --A regular expected message
if received.distance then
received.distance = received.distance + dist --Add on to repeater how far message had to go
else
received.distance = dist
end
debug("Adding return channel "..replyFreq.." to channels")
addChannel(replyFreq,false)
debug("Sending Return Message")
modem.transmit(receivedFreq, replyFreq, received) --Send back exactly what we got
addID(received.id)
elseif doAcceptPing and received.fingerprint == pingFingerprint then --We got a ping!
debug("We got a ping!")
redstone.setOutput(pingSide, true) --Just a toggle should be fine
sleep(1)
redstone.setOutput(pingSide, false)
end
if tempCounter > arbitraryNumber then --Purge messages to save memory
debug("Purging messages")
sleep(0.05) --Wait a tick for no good reason
sentMessages = {} --Completely reset table
sentMessages[recentID] = true --Reset last message (not sure if really needed. Oh well.)
tempCounter = 0
end
print("Messages Received: "..counter)
elseif event == "char" then
if key == "q" then --Quitting
print("Quitting")
continue = false
elseif key == "p" then --Ping other channels
for a,b in pairs(channels) do --Ping all open channels
debug("Pinging channel ",b)
modem.transmit(b,b,{message = "I am ping! Wrar!", fingerprint = "ping"})
sleep(1)
end
elseif key == "r" then --Removing Channels
print("Enter a comma separated list of channels to remove")
local str = "" --Concatenate all the channels into one, maybe restructure this for sorting?
for i=1,#channels do
str = str..tostring(channels[i])..", "
end
print("Channels: ",str:sub(1,-2)) --Sub for removing comma and space
local input = io.read()
local toRemove = {} --We have to use this table because user list will not be in reverse numerical order. Because modifying while iterating is bad...
for num in input:gmatch("%d+") do
for a, b in pairs(channels) do
if b == tonumber(num) then
debug("Removing ",b)
table.insert(toRemove, a, 1) --This way it will remove indexes from the back of the table
modem.close(b)
break --No use checking the rest of the table for this number
end
end
end
for i=1, #toRemove do
table.remove(channels, toRemove[i])
end
else --Adding Channels
print("What channels would you like to open. Enter a comma-separated list.\nAdd only sending channels. Receiving ones will be added automatically.\n")
local input = io.read()
for num in input:gmatch("%d+") do
addChannel(num,true)
end
sleep(2)
end
save()
openChannels() --This will only open channels if they aren't open
end
end
for i=1, #channels do
modem.close(channels[i])
end