forked from Not/srb2k-leaderboard
ghosts alpha
This commit is contained in:
249
transmission.lua
Normal file
249
transmission.lua
Normal file
@ -0,0 +1,249 @@
|
||||
local MSG = "<<~"
|
||||
local CHN = "~>>"
|
||||
|
||||
local PACKET_MAX_SIZE = 200
|
||||
local MAX_TICS = TICRATE * 2
|
||||
|
||||
local function encode(data)
|
||||
data = string.gsub(data, "\n", "\\n")
|
||||
data = string.gsub(data, "\t", "\\t")
|
||||
return data
|
||||
end
|
||||
|
||||
local function decode(data)
|
||||
data = string.gsub(data, "\\n", "\n")
|
||||
data = string.gsub(data, "\\t", "\t")
|
||||
return data
|
||||
end
|
||||
|
||||
local transmitters = {}
|
||||
|
||||
local function Transmitter(channel, opts)
|
||||
assert(channel, "Transmitter: channel is required")
|
||||
opts = $ or {}
|
||||
|
||||
return {
|
||||
packets = {},
|
||||
|
||||
push = function(this, packet)
|
||||
table.insert(this.packets, MSG..channel..CHN..packet)
|
||||
end,
|
||||
|
||||
pop = function(this)
|
||||
return table.remove(this.packets)
|
||||
end,
|
||||
|
||||
sendPacket = function(this)
|
||||
local sender = consoleplayer or server
|
||||
COM_BufInsertText(sender, "say \""..this:pop().."\"")
|
||||
return not #this.packets
|
||||
end,
|
||||
|
||||
writeHeader = function(this)
|
||||
this:push(#this.packets)
|
||||
end,
|
||||
|
||||
close = function(this)
|
||||
for i, tr in ipairs(transmitters) do
|
||||
if tr == this then
|
||||
table.remove(transmitters, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if opts.free then
|
||||
opts.free(this, opts.handle)
|
||||
end
|
||||
end,
|
||||
|
||||
enqueue = function(this)
|
||||
table.insert(transmitters, this)
|
||||
end,
|
||||
|
||||
transmit = function(this, data)
|
||||
assert(data, "Transmitter: nil data")
|
||||
|
||||
data = encode(data)
|
||||
|
||||
if opts.stream then
|
||||
assert(
|
||||
#data < PACKET_MAX_SIZE,
|
||||
"Transmitter: data packet too large for stream"
|
||||
)
|
||||
|
||||
this:push(data)
|
||||
this:enqueue()
|
||||
return
|
||||
end
|
||||
|
||||
local sub
|
||||
for i = 1, #data, PACKET_MAX_SIZE do
|
||||
sub = data:sub(i, min(#data, i + PACKET_MAX_SIZE-1))
|
||||
this:push(sub)
|
||||
end
|
||||
|
||||
this:writeHeader()
|
||||
this:enqueue()
|
||||
end
|
||||
}
|
||||
end
|
||||
rawset(_G, "lb_transmitter", Transmitter)
|
||||
|
||||
addHook("ThinkFrame", function()
|
||||
if not #transmitters then return end
|
||||
|
||||
local index = (leveltime % #transmitters) + 1
|
||||
local transmitter = transmitters[index]
|
||||
|
||||
if transmitter:sendPacket() then
|
||||
transmitter:close()
|
||||
end
|
||||
end)
|
||||
|
||||
local Channels = {
|
||||
channel = {},
|
||||
|
||||
add = function(this, ch, reciever)
|
||||
this.channel[ch] = $ or {}
|
||||
table.insert(this.channel[ch], reciever)
|
||||
end,
|
||||
|
||||
chan = function(this, ch)
|
||||
local c = this.channel[ch]
|
||||
local i = c and #c + 1 or 0
|
||||
return function()
|
||||
if i > 1 then
|
||||
i = i - 1
|
||||
return i, c[i]
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
remove = function(this, ch, index)
|
||||
table.remove(this.channel[ch], index)
|
||||
end,
|
||||
|
||||
recieve = function(this)
|
||||
return function(packet, ch)
|
||||
for i, reciever in this:chan(ch) do
|
||||
if reciever:push(packet) then
|
||||
reciever:close()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
addHook("ThinkFrame", function()
|
||||
for _, ch in pairs(Channels.channel) do
|
||||
for _, rec in pairs(ch) do
|
||||
if rec:tick() then
|
||||
rec:close()
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local function Reciever(channel, callback, opts)
|
||||
assert(callback, "Reciever: callback is required")
|
||||
opts = $ or {}
|
||||
|
||||
local ticker, pusher
|
||||
local MAX_TICS = MAX_TICS
|
||||
if opts.stream then
|
||||
ticker = function(this) end
|
||||
|
||||
pusher = function(this, packet)
|
||||
callback(decode(packet), opts.handle)
|
||||
end
|
||||
else
|
||||
ticker = function(this)
|
||||
this.tics = $ + 1
|
||||
return this.tics > MAX_TICS
|
||||
end
|
||||
|
||||
pusher = function(this, packet)
|
||||
if not this.len then
|
||||
this:recieveHeader(packet)
|
||||
return
|
||||
end
|
||||
|
||||
table.insert(this.packets, packet)
|
||||
|
||||
if opts.progress then
|
||||
opts.progress(#this.packets, this.len, opts.handle)
|
||||
end
|
||||
|
||||
if #this.packets >= this.len then
|
||||
this:finish()
|
||||
return true
|
||||
end
|
||||
|
||||
this.tics = 0
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
len,
|
||||
packets = {},
|
||||
tics = 0,
|
||||
tick = ticker,
|
||||
|
||||
close = function(this)
|
||||
for i, rec in Channels:chan(channel) do
|
||||
if rec == this then
|
||||
Channels:remove(channel, i)
|
||||
if opts.free then
|
||||
opts.free(this, opts.handle)
|
||||
end
|
||||
return
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
push = pusher,
|
||||
|
||||
recieveHeader = function(this, header)
|
||||
local len = tonumber(header)
|
||||
assert(len ~= nil,
|
||||
"Reciever: invalid header '"..(header or "nil").."'")
|
||||
this.len = len
|
||||
end,
|
||||
|
||||
listen = function(this)
|
||||
Channels:add(channel, this)
|
||||
end,
|
||||
|
||||
pop = function(this)
|
||||
return table.remove(this.packets)
|
||||
end,
|
||||
|
||||
finish = function(this)
|
||||
local data = ""
|
||||
|
||||
local s = this:pop()
|
||||
while s do
|
||||
data = $..s
|
||||
s = this:pop()
|
||||
end
|
||||
|
||||
callback(decode(data), opts.handle)
|
||||
end
|
||||
}
|
||||
end
|
||||
rawset(_G, "lb_reciever", Reciever)
|
||||
|
||||
local function scan(sym, msg, fn)
|
||||
if msg:find(sym) == 1 then
|
||||
msg = msg:sub(#sym+1)
|
||||
local chi = msg:find(CHN)
|
||||
local ch = msg:sub(1, chi-1)
|
||||
msg = msg:sub(chi+#CHN)
|
||||
fn(msg, ch)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
addHook("PlayerMsg", function(source, type, target, msg)
|
||||
return scan(MSG, msg, Channels:recieve())
|
||||
end)
|
Reference in New Issue
Block a user