220 lines
7.6 KiB
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
|