-- rnc2.lua (CC:T API version – no module/table tricks)
local BASE_PORT = 39000
local MODEMS = { peripheral.find("modem") }
if #MODEMS == 0 then
error("rnc2: no modems found")
end
-- open base port
for _, m in ipairs(MODEMS) do
m.open(BASE_PORT)
end
local function shortHash(s)
local h = 0
for i = 1, #s do
h = (h + s:byte(i)) % 1000
end
return h
end
local function progPort(prog)
return BASE_PORT + shortHash(prog)
end
local function openProg(prog)
local p = progPort(prog)
for _, m in ipairs(MODEMS) do
if not m.isOpen(p) then m.open(p) end
end
return p
end
-- ✅ these are the PUBLIC ones CC will expose as rnc2.getId(...)
function getId(prog)
return ("%s@%d"):format(prog, os.getComputerID())
end
function getPort(prog)
return progPort(prog)
end
function send(prog, target, body)
local port = openProg(prog)
local pkt = {
prog = prog,
from = getId(prog),
to = target or "*",
t = os.epoch("utc"),
body = body
}
local data = textutils.serialize(pkt)
for _, m in ipairs(MODEMS) do
m.transmit(port, port, data)
end
end
function broadcast(prog, body)
return send(prog, "*", body)
end
function recv(prog, timeout)
local port = openProg(prog)
local timerId
if timeout and timeout > 0 then
timerId = os.startTimer(timeout)
end
while true do
local ev, p1, p2, p3, p4 = os.pullEvent()
if ev == "modem_message" and p2 == port then
local ok, pkt = pcall(textutils.unserialize, p4)
if ok and type(pkt) == "table" then
local me = getId(prog)
if (not pkt.to) or pkt.to == "*" or pkt.to == me then
return pkt
end
end
elseif ev == "timer" and p1 == timerId then
return nil
end
end
end
function autoPong(prog, pkt)
if pkt.body and pkt.body.type == "ping" then
send(prog, pkt.from, { type = "pong" })
return true
end
return false
end