mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2024-12-14 04:00:30 +00:00
Fix computer IDs greater than 65535 crashing Rednet (#900)
This commit is contained in:
parent
eb61c5c5d7
commit
297426419b
@ -61,6 +61,8 @@
|
|||||||
(table space)
|
(table space)
|
||||||
(index no-space))
|
(index no-space))
|
||||||
|
|
||||||
|
(allow-clarifying-parens true)
|
||||||
|
|
||||||
;; colours imports from colors, and we don't handle that right now.
|
;; colours imports from colors, and we don't handle that right now.
|
||||||
;; keys is entirely dynamic, so we skip it.
|
;; keys is entirely dynamic, so we skip it.
|
||||||
(dynamic-modules colours keys _G)
|
(dynamic-modules colours keys _G)
|
||||||
|
@ -25,10 +25,18 @@ CHANNEL_BROADCAST = 65535
|
|||||||
--- The channel used by the Rednet API to repeat messages.
|
--- The channel used by the Rednet API to repeat messages.
|
||||||
CHANNEL_REPEAT = 65533
|
CHANNEL_REPEAT = 65533
|
||||||
|
|
||||||
|
--- The number of channels rednet reserves for computer IDs. Computers with IDs
|
||||||
|
-- greater or equal to this limit wrap around to 0.
|
||||||
|
MAX_ID_CHANNELS = 65500
|
||||||
|
|
||||||
local tReceivedMessages = {}
|
local tReceivedMessages = {}
|
||||||
local tReceivedMessageTimeouts = {}
|
local tReceivedMessageTimeouts = {}
|
||||||
local tHostnames = {}
|
local tHostnames = {}
|
||||||
|
|
||||||
|
local function id_as_channel(id)
|
||||||
|
return (id or os.getComputerID()) % MAX_ID_CHANNELS
|
||||||
|
end
|
||||||
|
|
||||||
--[[- Opens a modem with the given @{peripheral} name, allowing it to send and
|
--[[- Opens a modem with the given @{peripheral} name, allowing it to send and
|
||||||
receive messages over rednet.
|
receive messages over rednet.
|
||||||
|
|
||||||
@ -47,7 +55,7 @@ function open(modem)
|
|||||||
if peripheral.getType(modem) ~= "modem" then
|
if peripheral.getType(modem) ~= "modem" then
|
||||||
error("No such modem: " .. modem, 2)
|
error("No such modem: " .. modem, 2)
|
||||||
end
|
end
|
||||||
peripheral.call(modem, "open", os.getComputerID())
|
peripheral.call(modem, "open", id_as_channel())
|
||||||
peripheral.call(modem, "open", CHANNEL_BROADCAST)
|
peripheral.call(modem, "open", CHANNEL_BROADCAST)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -64,7 +72,7 @@ function close(modem)
|
|||||||
if peripheral.getType(modem) ~= "modem" then
|
if peripheral.getType(modem) ~= "modem" then
|
||||||
error("No such modem: " .. modem, 2)
|
error("No such modem: " .. modem, 2)
|
||||||
end
|
end
|
||||||
peripheral.call(modem, "close", os.getComputerID())
|
peripheral.call(modem, "close", id_as_channel())
|
||||||
peripheral.call(modem, "close", CHANNEL_BROADCAST)
|
peripheral.call(modem, "close", CHANNEL_BROADCAST)
|
||||||
else
|
else
|
||||||
-- Close all modems
|
-- Close all modems
|
||||||
@ -87,7 +95,7 @@ function isOpen(modem)
|
|||||||
if modem then
|
if modem then
|
||||||
-- Check if a specific modem is open
|
-- Check if a specific modem is open
|
||||||
if peripheral.getType(modem) == "modem" then
|
if peripheral.getType(modem) == "modem" then
|
||||||
return peripheral.call(modem, "isOpen", os.getComputerID()) and peripheral.call(modem, "isOpen", CHANNEL_BROADCAST)
|
return peripheral.call(modem, "isOpen", id_as_channel()) and peripheral.call(modem, "isOpen", CHANNEL_BROADCAST)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- Check if any modem is open
|
-- Check if any modem is open
|
||||||
@ -134,10 +142,11 @@ function send(nRecipient, message, sProtocol)
|
|||||||
tReceivedMessageTimeouts[os.startTimer(30)] = nMessageID
|
tReceivedMessageTimeouts[os.startTimer(30)] = nMessageID
|
||||||
|
|
||||||
-- Create the message
|
-- Create the message
|
||||||
local nReplyChannel = os.getComputerID()
|
local nReplyChannel = id_as_channel()
|
||||||
local tMessage = {
|
local tMessage = {
|
||||||
nMessageID = nMessageID,
|
nMessageID = nMessageID,
|
||||||
nRecipient = nRecipient,
|
nRecipient = nRecipient,
|
||||||
|
nSender = os.getComputerID(),
|
||||||
message = message,
|
message = message,
|
||||||
sProtocol = sProtocol,
|
sProtocol = sProtocol,
|
||||||
}
|
}
|
||||||
@ -145,10 +154,14 @@ function send(nRecipient, message, sProtocol)
|
|||||||
local sent = false
|
local sent = false
|
||||||
if nRecipient == os.getComputerID() then
|
if nRecipient == os.getComputerID() then
|
||||||
-- Loopback to ourselves
|
-- Loopback to ourselves
|
||||||
os.queueEvent("rednet_message", nReplyChannel, message, sProtocol)
|
os.queueEvent("rednet_message", os.getComputerID(), message, sProtocol)
|
||||||
sent = true
|
sent = true
|
||||||
else
|
else
|
||||||
-- Send on all open modems, to the target and to repeaters
|
-- Send on all open modems, to the target and to repeaters
|
||||||
|
if nRecipient ~= CHANNEL_BROADCAST then
|
||||||
|
nRecipient = id_as_channel(nRecipient)
|
||||||
|
end
|
||||||
|
|
||||||
for _, sModem in ipairs(peripheral.getNames()) do
|
for _, sModem in ipairs(peripheral.getNames()) do
|
||||||
if isOpen(sModem) then
|
if isOpen(sModem) then
|
||||||
peripheral.call(sModem, "transmit", nRecipient, nReplyChannel, tMessage)
|
peripheral.call(sModem, "transmit", nRecipient, nReplyChannel, tMessage)
|
||||||
@ -390,13 +403,14 @@ function run()
|
|||||||
if sEvent == "modem_message" then
|
if sEvent == "modem_message" then
|
||||||
-- Got a modem message, process it and add it to the rednet event queue
|
-- Got a modem message, process it and add it to the rednet event queue
|
||||||
local sModem, nChannel, nReplyChannel, tMessage = p1, p2, p3, p4
|
local sModem, nChannel, nReplyChannel, tMessage = p1, p2, p3, p4
|
||||||
if isOpen(sModem) and (nChannel == os.getComputerID() or nChannel == CHANNEL_BROADCAST) then
|
if isOpen(sModem) and (nChannel == id_as_channel() or nChannel == CHANNEL_BROADCAST) then
|
||||||
if type(tMessage) == "table" and type(tMessage.nMessageID) == "number"
|
if type(tMessage) == "table" and type(tMessage.nMessageID) == "number"
|
||||||
and tMessage.nMessageID == tMessage.nMessageID and not tReceivedMessages[tMessage.nMessageID]
|
and tMessage.nMessageID == tMessage.nMessageID and not tReceivedMessages[tMessage.nMessageID]
|
||||||
|
and ((tMessage.nRecipient and tMessage.nRecipient == os.getComputerID()) or nChannel == CHANNEL_BROADCAST)
|
||||||
then
|
then
|
||||||
tReceivedMessages[tMessage.nMessageID] = true
|
tReceivedMessages[tMessage.nMessageID] = true
|
||||||
tReceivedMessageTimeouts[os.startTimer(30)] = tMessage.nMessageID
|
tReceivedMessageTimeouts[os.startTimer(30)] = tMessage.nMessageID
|
||||||
os.queueEvent("rednet_message", nReplyChannel, tMessage.message, tMessage.sProtocol)
|
os.queueEvent("rednet_message", tMessage.nSender or nReplyChannel, tMessage.message, tMessage.sProtocol)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -14,6 +14,10 @@ else
|
|||||||
print(#tModems .. " modems found.")
|
print(#tModems .. " modems found.")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function idAsChannel(id)
|
||||||
|
return (id or os.getComputerID()) % rednet.MAX_ID_CHANNELS
|
||||||
|
end
|
||||||
|
|
||||||
local function open(nChannel)
|
local function open(nChannel)
|
||||||
for n = 1, #tModems do
|
for n = 1, #tModems do
|
||||||
local sModem = tModems[n]
|
local sModem = tModems[n]
|
||||||
@ -53,7 +57,7 @@ local ok, error = pcall(function()
|
|||||||
for n = 1, #tModems do
|
for n = 1, #tModems do
|
||||||
local sOtherModem = tModems[n]
|
local sOtherModem = tModems[n]
|
||||||
peripheral.call(sOtherModem, "transmit", rednet.CHANNEL_REPEAT, nReplyChannel, tMessage)
|
peripheral.call(sOtherModem, "transmit", rednet.CHANNEL_REPEAT, nReplyChannel, tMessage)
|
||||||
peripheral.call(sOtherModem, "transmit", tMessage.nRecipient, nReplyChannel, tMessage)
|
peripheral.call(sOtherModem, "transmit", idAsChannel(tMessage.nRecipient), nReplyChannel, tMessage)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Log the event
|
-- Log the event
|
||||||
|
@ -84,7 +84,7 @@ describe("The rednet library", function()
|
|||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe("on a fake computers", function()
|
describe("on fake computers", function()
|
||||||
local fake_computer = require "support.fake_computer"
|
local fake_computer = require "support.fake_computer"
|
||||||
|
|
||||||
local function computer_with_rednet(id, fn, options)
|
local function computer_with_rednet(id, fn, options)
|
||||||
@ -168,5 +168,24 @@ describe("The rednet library", function()
|
|||||||
|
|
||||||
fake_computer.run_all({ computer_1, computer_2, computer_3 }, { computer_1, computer_3 })
|
fake_computer.run_all({ computer_1, computer_2, computer_3 }, { computer_1, computer_3 })
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it("repeats messages between computers with massive ids", function()
|
||||||
|
local id_1, id_3 = 24283947, 93428798
|
||||||
|
local computer_1, modem_1 = computer_with_rednet(id_1, function(rednet, _ENV)
|
||||||
|
rednet.send(id_3, "Hello")
|
||||||
|
local id, message = rednet.receive()
|
||||||
|
expect { id, message }:same { id_3, "World" }
|
||||||
|
end, { open = true })
|
||||||
|
local computer_2, modem_2 = computer_with_rednet(2, nil, { open = true, rep = true })
|
||||||
|
local computer_3, modem_3 = computer_with_rednet(id_3, function(rednet)
|
||||||
|
rednet.send(id_1, "World")
|
||||||
|
local id, message = rednet.receive()
|
||||||
|
expect { id, message }:same { id_1, "Hello" }
|
||||||
|
end, { open = true })
|
||||||
|
fake_computer.add_modem_edge(modem_1, modem_2)
|
||||||
|
fake_computer.add_modem_edge(modem_2, modem_3)
|
||||||
|
|
||||||
|
fake_computer.run_all({ computer_1, computer_2, computer_3 }, { computer_1, computer_3 })
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
@ -70,15 +70,22 @@ local function make_computer(id, fn)
|
|||||||
return { env = env, peripherals = peripherals, queue_event = queue_event, step = step, co = co }
|
return { env = env, peripherals = peripherals, queue_event = queue_event, step = step, co = co }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function parse_channel(c)
|
||||||
|
if c < 0 or c > 65535 then error("Expected number in range 0-65535", 3) end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
--- Add a modem to a computer on a particular side
|
--- Add a modem to a computer on a particular side
|
||||||
local function add_modem(owner, side)
|
local function add_modem(owner, side)
|
||||||
local open, adjacent = {}, {}
|
local open, adjacent = {}, {}
|
||||||
local peripheral = setmetatable({
|
local peripheral = setmetatable({
|
||||||
open = function(channel) open[channel] = true end,
|
open = function(channel) open[parse_channel(channel)] = true end,
|
||||||
close = function(channel) open[channel] = false end,
|
close = function(channel) open[parse_channel(channel)] = false end,
|
||||||
closeAll = function(channel) open = {} end,
|
closeAll = function(channel) open = {} end,
|
||||||
isOpen = function(channel) return open[channel] == true end,
|
isOpen = function(channel) return open[parse_channel(channel)] == true end,
|
||||||
transmit = function(channel, reply_channel, payload)
|
transmit = function(channel, reply_channel, payload)
|
||||||
|
channel, reply_channel = parse_channel(channel), parse_channel(reply_channel)
|
||||||
|
|
||||||
for _, adjacent in pairs(adjacent) do
|
for _, adjacent in pairs(adjacent) do
|
||||||
if adjacent.open[channel] then
|
if adjacent.open[channel] then
|
||||||
adjacent.owner.queue_event("modem_message", adjacent.side, channel, reply_channel, payload, 123)
|
adjacent.owner.queue_event("modem_message", adjacent.side, channel, reply_channel, payload, 123)
|
||||||
|
Loading…
Reference in New Issue
Block a user