Start laying down network protocol.
This commit is contained in:
parent
ab6502db61
commit
a720ebf173
|
@ -1,3 +1,2 @@
|
||||||
logs/
|
logs/
|
||||||
build/
|
build/
|
||||||
lib/lua
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
#pragma language glsl3
|
||||||
|
varying float hue;
|
||||||
|
uniform float time;
|
||||||
|
|
||||||
|
#ifdef VERTEX
|
||||||
|
uniform mat4 proj;
|
||||||
|
uniform mat4 view;
|
||||||
|
uniform sampler2D canvas;
|
||||||
|
|
||||||
|
vec4 position(mat4 transform_projection, vec4 vertex_position)
|
||||||
|
{
|
||||||
|
return vertex_position;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef PIXEL
|
||||||
|
|
||||||
|
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords)
|
||||||
|
{
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -1,6 +1,6 @@
|
||||||
return {
|
return {
|
||||||
name = "Player Name",
|
name = "Player Name",
|
||||||
pronoun = "they",
|
pronoun = "they/them/their",
|
||||||
colour = {0.8, 0.4, 0.4, 0.7},
|
colour = {0.8, 0.4, 0.4, 0.7},
|
||||||
gamma = 0.5,
|
gamma = 0.5,
|
||||||
keybinds = {
|
keybinds = {
|
||||||
|
@ -12,4 +12,6 @@ return {
|
||||||
love = "q",
|
love = "q",
|
||||||
hate = "e",
|
hate = "e",
|
||||||
}
|
}
|
||||||
|
serverIP = "192.168.2.15",
|
||||||
|
serverPort = 51312,
|
||||||
}
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
local scene = assert( require 'client.scene' )
|
||||||
|
local lg = assert( love.graphics )
|
||||||
|
local server = assert( require 'client.udp' )
|
||||||
|
local connecting = {}
|
||||||
|
|
||||||
|
local time, ip, port = 0
|
||||||
|
|
||||||
|
function connecting.draw()
|
||||||
|
lg.print( "Connecting to server:\t"..time, 0, 0, 0 )
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function connecting.update(dt)
|
||||||
|
time = time + dt
|
||||||
|
|
||||||
|
if time > 5 then
|
||||||
|
return scene.loadScene( scene.game )
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function connecting:onLoad( params )
|
||||||
|
local ip, port = assert( params, "No IP address specified!" ).ip, params.port
|
||||||
|
return server.connect( ip, port )
|
||||||
|
end
|
||||||
|
|
||||||
|
scene.connecting = connecting
|
||||||
|
return connecting
|
|
@ -0,0 +1,23 @@
|
||||||
|
local crepuscular = {}
|
||||||
|
local lg = assert( love.graphics )
|
||||||
|
local shader = assert( lg.newShader( 'client/assets/glsl/crepuscular' ))
|
||||||
|
local scene = assert( require( 'client.scene' ) )
|
||||||
|
local rectanglePosition = { }
|
||||||
|
|
||||||
|
function crepuscular.draw()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function crepuscular.onLoad()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function crepuscular.resize()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function crepuscular.update()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return crepuscular
|
|
@ -1,8 +1,8 @@
|
||||||
local lg = assert( love.graphics )
|
local lg = assert( love.graphics )
|
||||||
local scene = assert( require 'client.scene' )
|
local scene = assert( require 'client.scene' )
|
||||||
local socket = assert( require 'socket' )
|
|
||||||
local shared = assert( require 'shared' )
|
local shared = assert( require 'shared' )
|
||||||
local udp = socket.udp()
|
local server = assert( require 'client.udp' )
|
||||||
|
local crepuscular = assert( require 'client.crepuscular' )
|
||||||
|
|
||||||
local game = {}
|
local game = {}
|
||||||
local t = 0
|
local t = 0
|
||||||
|
@ -15,17 +15,19 @@ function game.draw()
|
||||||
lg.print( serverTick, 0, 25 )
|
lg.print( serverTick, 0, 25 )
|
||||||
end
|
end
|
||||||
|
|
||||||
function game.onPacket( data, msg )
|
function game.onPacket( data )
|
||||||
if data then serverTick = data end
|
if not data then return end
|
||||||
|
serverTick = data
|
||||||
|
return game.onPacket( server.receive() ) --Recurse to get all waiting packets.
|
||||||
end
|
end
|
||||||
|
|
||||||
function game.update( dt )
|
function game.update( dt )
|
||||||
t = dt + t
|
t = dt + t
|
||||||
game.onPacket( udp:receive() )
|
game.onPacket( server.receive() )
|
||||||
if t > 0.1 then
|
if t > 0.1 then
|
||||||
t = 0
|
t = 0
|
||||||
tick = tick + 1
|
tick = tick + 1
|
||||||
udp:send( tostring(tick) )
|
assert( server.send( tostring(tick) ) )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -35,14 +37,11 @@ function game.newGame( )
|
||||||
end
|
end
|
||||||
|
|
||||||
function game.disconnect( )
|
function game.disconnect( )
|
||||||
return scene.mainmenu()
|
return scene.mainmenu( server.disconnect() )
|
||||||
end
|
end
|
||||||
|
|
||||||
function game.onLoad( params )
|
function game.onLoad( params )
|
||||||
params = params or {}
|
|
||||||
local serverIP, serverPort = params.serverIP or "192.168.2.15", params.serverPort or 51312
|
|
||||||
udp:settimeout( 0 )
|
|
||||||
udp:setpeername( serverIP, serverPort )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function game.keypressed( key, code, isRepeat )
|
function game.keypressed( key, code, isRepeat )
|
||||||
|
|
|
@ -30,6 +30,18 @@ local function newScene( scenes, name, t )
|
||||||
rawset( scenes, name, t )
|
rawset( scenes, name, t )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function scene.overlayScene( scen, params )
|
||||||
|
print( "Adding Scene:", scen.name )
|
||||||
|
for k, v in pairs( callbacks ) do
|
||||||
|
local old = love[k]
|
||||||
|
local new = scen[k]
|
||||||
|
if new then
|
||||||
|
love[k] = function( ... ) return new( ... ) and old( ... ) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
scen:onLoad( params )
|
||||||
|
end
|
||||||
|
|
||||||
return setmetatable( scene,
|
return setmetatable( scene,
|
||||||
{__call = scene.loadScene,
|
{__call = scene.loadScene,
|
||||||
__newindex = newScene
|
__newindex = newScene
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
local socket = assert( require 'socket' )
|
||||||
|
|
||||||
|
local udp = {}
|
||||||
|
|
||||||
|
local cxn = assert( socket.udp() )
|
||||||
|
cxn:settimeout( 0 )
|
||||||
|
|
||||||
|
function udp.receive()
|
||||||
|
return cxn:receive()
|
||||||
|
end
|
||||||
|
|
||||||
|
function udp.connect( ip, port )
|
||||||
|
assert( cxn:setpeername( ip, port ) )
|
||||||
|
end
|
||||||
|
|
||||||
|
function udp.disconnect( )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function udp.send( s )
|
||||||
|
return cxn:send( s )
|
||||||
|
end
|
||||||
|
|
||||||
|
return udp
|
|
@ -4,11 +4,38 @@ local textInput = assert( require 'client.ui.textinput' )
|
||||||
local button = assert( require 'client.ui.button' )
|
local button = assert( require 'client.ui.button' )
|
||||||
local browser = {}
|
local browser = {}
|
||||||
|
|
||||||
|
local serverList = {
|
||||||
|
selected = false,
|
||||||
|
x = 25,
|
||||||
|
y = 160,
|
||||||
|
h = 24,
|
||||||
|
{ name = "test", ip = "192.168.2.150", port = 51312, players = 1, capacity = 64, map = "testMap" },
|
||||||
|
{ name = "best", ip = "142.154.3.212", port = 21345, players = 2, capacity = 64, map = "nestMap" },
|
||||||
|
{ name = "aest", ip = "123.45.67.89", port = 21253, players = 3, capacity = 32, map = "aestMap" },
|
||||||
|
}
|
||||||
|
|
||||||
|
function serverList.draw()
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function serverList.select()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function serverList.up()
|
||||||
|
serverList.selected = ( serverList.selected or 0 ) - 1
|
||||||
|
end
|
||||||
|
|
||||||
|
function serverList.down()
|
||||||
|
serverList.selected = ( serverList.selected or 0 ) + 1
|
||||||
|
end
|
||||||
|
|
||||||
local ti = textInput.new{
|
local ti = textInput.new{
|
||||||
width = 300,
|
width = 300,
|
||||||
length = 20,
|
length = 20,
|
||||||
x = 15,
|
x = 15,
|
||||||
y = 165
|
y = 175
|
||||||
}
|
}
|
||||||
|
|
||||||
function browser.draw()
|
function browser.draw()
|
||||||
|
@ -31,6 +58,7 @@ end
|
||||||
|
|
||||||
function browser.joinIPString( s )
|
function browser.joinIPString( s )
|
||||||
--Parse IP address and port from string. If it's valid, join the server.
|
--Parse IP address and port from string. If it's valid, join the server.
|
||||||
|
print( "browser: Attempting to join server", s )
|
||||||
if not s then return end
|
if not s then return end
|
||||||
ti:clear()
|
ti:clear()
|
||||||
local valid, ip, port
|
local valid, ip, port
|
||||||
|
@ -39,6 +67,7 @@ function browser.joinIPString( s )
|
||||||
end
|
end
|
||||||
|
|
||||||
function browser.joinIP( ip, port )
|
function browser.joinIP( ip, port )
|
||||||
|
print( "Joining server:", ip, port )
|
||||||
return scene.game{ serverIP = ip, serverPort = port }
|
return scene.game{ serverIP = ip, serverPort = port }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
local lg = assert( love.graphics )
|
local lg = assert( love.graphics )
|
||||||
local love = assert( love )
|
local love = assert( love )
|
||||||
local scene = assert( require 'client.scene' )
|
local scene = assert( require 'client.scene' )
|
||||||
local strings = assert( require 'client.assets.strings' )
|
local strings = strings or assert( require 'client.assets.strings.english' )
|
||||||
local button = assert( require 'client.ui.button' )
|
local button = assert( require 'client.ui.button' )
|
||||||
local menu = assert( require 'client.ui.menu' )
|
local menu = assert( require 'client.ui.menu' )
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ return menu.new(
|
||||||
x = 15, w = lg.getWidth(), y = 115, h = 72,
|
x = 15, w = lg.getWidth(), y = 115, h = 72,
|
||||||
text = strings.newgame_button,
|
text = strings.newgame_button,
|
||||||
color = { 0.6, 0.6, 0.6, 0.9 },
|
color = { 0.6, 0.6, 0.6, 0.9 },
|
||||||
callback = function() return scene.game() end },
|
callback = function() return scene.connecting() end },
|
||||||
|
|
||||||
button{
|
button{
|
||||||
text = strings.join_button,
|
text = strings.join_button,
|
||||||
|
@ -47,5 +47,5 @@ return menu.new(
|
||||||
{ 0, 1, 0, 1, 0.4, 0.05, 0.05, 0.1 },
|
{ 0, 1, 0, 1, 0.4, 0.05, 0.05, 0.1 },
|
||||||
},
|
},
|
||||||
|
|
||||||
lg.newFont( "client/assets/Montserrat-Bold.ttf", 48 )
|
lg.newFont( "client/assets/fonts/Montserrat-Bold.ttf", 48 )
|
||||||
)
|
)
|
|
@ -1,7 +1,7 @@
|
||||||
local lg = assert( love.graphics )
|
local lg = assert( love.graphics )
|
||||||
local love = assert( love )
|
local love = assert( love )
|
||||||
local scene = assert( require 'client.scene' )
|
local scene = assert( require 'client.scene' )
|
||||||
local strings = assert( require 'client.assets.strings' )
|
local strings = strings or assert( require 'client.assets.strings.english' )
|
||||||
local button = assert( require 'client.ui.button' )
|
local button = assert( require 'client.ui.button' )
|
||||||
local menu = assert( require 'client.ui.menu' )
|
local menu = assert( require 'client.ui.menu' )
|
||||||
|
|
||||||
|
@ -58,5 +58,5 @@ return menu.new(
|
||||||
{ 0, 1, 0, 1, 0, 0, 0, 0.01 },
|
{ 0, 1, 0, 1, 0, 0, 0, 0.01 },
|
||||||
},
|
},
|
||||||
|
|
||||||
lg.newFont( "client/assets/Montserrat-Bold.ttf", 18 )
|
lg.newFont( "client/assets/fonts/Montserrat-Bold.ttf", 18 )
|
||||||
)
|
)
|
|
@ -4,12 +4,13 @@ local love = assert( love )
|
||||||
|
|
||||||
function love.load()
|
function love.load()
|
||||||
love.window.setIcon( assert( love.image.newImageData( "client/assets/client-icon.png" ) ) )
|
love.window.setIcon( assert( love.image.newImageData( "client/assets/client-icon.png" ) ) )
|
||||||
love.graphics.setNewFont( "client/assets/Montserrat-Bold.ttf", 48 )
|
love.graphics.setNewFont( "client/assets/fonts/Montserrat-Bold.ttf", 48 )
|
||||||
local scenes = assert( require 'client.scene' )
|
local scenes = assert( require 'client.scene' )
|
||||||
|
|
||||||
assert( require 'client.ui.options' )
|
assert( require 'client.ui.options' )
|
||||||
assert( require 'client.ui.browser' )
|
assert( require 'client.ui.browser' )
|
||||||
assert( require 'client.game' )
|
assert( require 'client.game' )
|
||||||
assert( require 'client.ui.mainmenu' )
|
assert( require 'client.ui.mainmenu' )
|
||||||
|
assert( require 'client.connecting' )
|
||||||
scenes.loadScene( scenes.mainmenu )
|
scenes.loadScene( scenes.mainmenu )
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
local shared = assert( require 'shared' )
|
||||||
|
local socket = assert( require 'socket' )
|
||||||
|
local udp = assert( socket.udp() )
|
||||||
|
|
||||||
|
--Servers broadcast their information here.
|
||||||
|
--The metaserver builds a list of available servers. ( available meaning, "broadcasted in last ten heartbeats" )
|
||||||
|
--Clients ask the metaserver for this list ( maybe with some filter? )
|
||||||
|
|
||||||
|
local serverInfo = {}
|
||||||
|
local serverIPs = {}
|
||||||
|
local clientIPs = {}
|
||||||
|
|
||||||
|
local function Parse( packet, ip, port )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
print( "Starting Metaserver", socket.gettime() )
|
||||||
|
repeat
|
||||||
|
|
||||||
|
until socket.sleep( 2.0 - (socket.gettime() % 2.0) )
|
|
@ -1,18 +1,24 @@
|
||||||
package.path = package.path .. "."
|
|
||||||
local shared = assert( require 'shared' )
|
local shared = assert( require 'shared' )
|
||||||
|
local packet = shared.packet
|
||||||
local socket = assert( require 'socket' )
|
local socket = assert( require 'socket' )
|
||||||
local udp = socket.udp()
|
local udp
|
||||||
local io = assert( io )
|
local io = assert( io )
|
||||||
local server = {
|
|
||||||
tick = 0,
|
local svInfo = { version = 13,
|
||||||
portNumber = 51312,
|
players = 0,
|
||||||
logFile = assert( io.open( "../logs/dajjal"..os.time()..".txt", "a" )),
|
capacity = 255,
|
||||||
serverName = "dajjal-server",
|
ip = shared.ip.fromString( socket.dns.toip(socket.dns.gethostname()) ),
|
||||||
}
|
port = 51312,
|
||||||
|
svname = "New Server",
|
||||||
|
map = "Test Map"}
|
||||||
|
|
||||||
|
local server = { tick = 0 }
|
||||||
|
|
||||||
|
local msIP, msPort
|
||||||
|
|
||||||
local clients = {}
|
local clients = {}
|
||||||
|
|
||||||
do
|
--[[do
|
||||||
local _print = print
|
local _print = print
|
||||||
function server.Print(...)
|
function server.Print(...)
|
||||||
_print( ... )
|
_print( ... )
|
||||||
|
@ -20,7 +26,7 @@ do
|
||||||
server.logFile:flush()
|
server.logFile:flush()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local print = server.Print
|
local print = server.Print]]
|
||||||
|
|
||||||
|
|
||||||
--Developer convenience function: start the local client program.
|
--Developer convenience function: start the local client program.
|
||||||
|
@ -28,20 +34,32 @@ function server.StartLocalClient()
|
||||||
os.execute( "start vision.bat" )
|
os.execute( "start vision.bat" )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function server.Advertise()
|
||||||
|
udp:sendto( packet.get( packet.serverInfo( svInfo ) ) , msIP, msPort )
|
||||||
|
end
|
||||||
|
|
||||||
--Incoming packet.
|
--Incoming packet.
|
||||||
function server.Parse( packet, ip, port )
|
function server.Parse( msg, ip, port )
|
||||||
if not packet then return end
|
if not msg then return end
|
||||||
if not clients[ip] then
|
if not clients[ip] then
|
||||||
clients[ip] = { ip = ip, port = port }
|
clients[ip] = { ip = ip, port = port }
|
||||||
end
|
end
|
||||||
clients[ip].tick = packet
|
|
||||||
return server.Parse( udp:receivefrom() ) -- Process any packets we missed.
|
local msgs = packet.deserialise( msg )
|
||||||
|
print( "in: ", ip, port, msg, server.tick )
|
||||||
|
return server.Parse( udp:receivefrom() ) -- Process other packets.
|
||||||
|
end
|
||||||
|
|
||||||
|
function server.SetIP( ipString, port )
|
||||||
|
svInfo.ip = shared.ip.fromString( ipString )
|
||||||
|
svInfo.port = port
|
||||||
end
|
end
|
||||||
|
|
||||||
function server.Start()
|
function server.Start()
|
||||||
|
udp = assert( socket.udp() )
|
||||||
udp:settimeout(0)
|
udp:settimeout(0)
|
||||||
udp:setsockname('*', server.portNumber)
|
server.SetIP( socket.dns.toip(socket.dns.gethostname()), 51312 )
|
||||||
print( "Starting Server" )
|
assert( udp:setsockname( tostring( svInfo.ip ), svInfo.port ))
|
||||||
server.StartLocalClient()
|
server.StartLocalClient()
|
||||||
repeat
|
repeat
|
||||||
server.Parse( udp:receivefrom() )
|
server.Parse( udp:receivefrom() )
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
local client = {}
|
||||||
|
|
||||||
|
function client.connect( ip, port )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function client.challenge( )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function client.acceptConnection( )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function client.disconnect( )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return
|
|
@ -1,5 +1,8 @@
|
||||||
local shared = {}
|
local shared = {}
|
||||||
|
|
||||||
|
shared.ip = assert( require 'shared.ipstring' )
|
||||||
|
shared.packet = assert( require 'shared.packet' )
|
||||||
|
|
||||||
|
|
||||||
--World state.
|
--World state.
|
||||||
local world = {}
|
local world = {}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
local ffi = assert( require 'ffi' )
|
||||||
|
local ipString = {}
|
||||||
|
local string = assert( string )
|
||||||
|
ffi.cdef[[
|
||||||
|
typedef struct {
|
||||||
|
uint8_t a;
|
||||||
|
uint8_t b;
|
||||||
|
uint8_t c;
|
||||||
|
uint8_t d;
|
||||||
|
} ipAddress;
|
||||||
|
]]
|
||||||
|
|
||||||
|
local ipAddress = ffi.typeof( ffi.new( "ipAddress" ) )
|
||||||
|
ffi.metatype( ipAddress, { __tostring = function( ip ) return ip.a.."."..ip.b.."."..ip.c.."."..ip.d end } )
|
||||||
|
|
||||||
|
function ipString.new( t )
|
||||||
|
local ip = ffi.new( ipAddress )
|
||||||
|
ip.a, ip.b, ip.c, ip.d = t[1], t[2], t[3], t[4]
|
||||||
|
return ip
|
||||||
|
end
|
||||||
|
|
||||||
|
function ipString.fromString( s )
|
||||||
|
local t = {}
|
||||||
|
for octet in s:gmatch( '%d+' ) do
|
||||||
|
table.insert( t, tonumber( octet ) )
|
||||||
|
end
|
||||||
|
return ipString.new( t )
|
||||||
|
end
|
||||||
|
|
||||||
|
return ipString
|
|
@ -0,0 +1,178 @@
|
||||||
|
local ffi = assert( require 'ffi' )
|
||||||
|
local buffer = assert( require( "string.buffer" ) )
|
||||||
|
local ipString = assert( require 'shared.ipstring' )
|
||||||
|
local packet = {}
|
||||||
|
local mt = { __index = { new = function( self ) return ffi.new( self.ct ) end } }
|
||||||
|
|
||||||
|
local function newStruct( t )
|
||||||
|
assert( not( packet[ t.name ] or packet[ t.netname ] ))
|
||||||
|
packet[ t.name ] = t
|
||||||
|
packet[ t.netname ] = t
|
||||||
|
ffi.cdef( ("typedef struct {uint8_t netname;\n%s;\n} %s;"):format( table.concat( t, ";\n" ) , t.name ) )
|
||||||
|
t.ct = ffi.typeof( ffi.new( t.name ) )
|
||||||
|
t.size = ffi.sizeof( t.ct )
|
||||||
|
setmetatable( t, mt )
|
||||||
|
|
||||||
|
--print( "Packet:", t.name, "Members:", #t + 1, "Size:", t.size, "Alignment:", ffi.alignof( t.ct ) )
|
||||||
|
end
|
||||||
|
|
||||||
|
newStruct{
|
||||||
|
name = "serverInfo",
|
||||||
|
netname = 42,
|
||||||
|
"uint8_t players",
|
||||||
|
"uint8_t capacity",
|
||||||
|
"ipAddress ip",
|
||||||
|
"uint16_t version",
|
||||||
|
"uint16_t port",
|
||||||
|
"char svname[32]",
|
||||||
|
"char map[32]",
|
||||||
|
}
|
||||||
|
|
||||||
|
newStruct{
|
||||||
|
name = "requestServers",
|
||||||
|
netname = 123,
|
||||||
|
"char padding[999]"
|
||||||
|
}
|
||||||
|
|
||||||
|
newStruct{
|
||||||
|
name = "heartbeat",
|
||||||
|
netname = 69,
|
||||||
|
"uint16_t protocol",
|
||||||
|
"uint32_t tick",
|
||||||
|
"uint32_t hash",
|
||||||
|
}
|
||||||
|
|
||||||
|
newStruct{
|
||||||
|
name = "insect",
|
||||||
|
netname = 81,
|
||||||
|
"uint8_t id",
|
||||||
|
"bool dead",
|
||||||
|
"int8_t hp",
|
||||||
|
"int8_t vx",
|
||||||
|
"int8_t vy",
|
||||||
|
"uint8_t folio",
|
||||||
|
"uint32_t x",
|
||||||
|
"uint32_t y",
|
||||||
|
}
|
||||||
|
|
||||||
|
newStruct{
|
||||||
|
name = "soleil",
|
||||||
|
netname = 27,
|
||||||
|
"uint16_t azimuth",
|
||||||
|
"uint16_t altitude",
|
||||||
|
"int8_t vazi",
|
||||||
|
"int8_t valt",
|
||||||
|
}
|
||||||
|
|
||||||
|
newStruct{
|
||||||
|
name = "playerChange",
|
||||||
|
netname = 72,
|
||||||
|
"uint8_t id",
|
||||||
|
"uint8_t role",
|
||||||
|
"char username[31]",
|
||||||
|
}
|
||||||
|
|
||||||
|
newStruct{
|
||||||
|
name = "chatMessage",
|
||||||
|
netname = 54,
|
||||||
|
"char cmsg[127]",
|
||||||
|
}
|
||||||
|
|
||||||
|
newStruct{
|
||||||
|
name = "command",
|
||||||
|
netname = 32,
|
||||||
|
"char command",
|
||||||
|
}
|
||||||
|
|
||||||
|
local readBuffer = buffer.new( 1024 )
|
||||||
|
function packet.deserialise( str )
|
||||||
|
readBuffer:set( str )
|
||||||
|
local data = {}
|
||||||
|
local types = {}
|
||||||
|
local n = 0
|
||||||
|
while #readBuffer ~= 0 do
|
||||||
|
local netname = readBuffer:ref()[0] --Read a byte to determine the packet type.
|
||||||
|
local t = packet[ netname ]
|
||||||
|
if not t then
|
||||||
|
error( "Malformed packet. Unknown header:\n"..readBuffer:get() )
|
||||||
|
end
|
||||||
|
if #readBuffer < t.size then
|
||||||
|
error( "Malformed packet. Packet too small:\n"..readBuffer:get() )
|
||||||
|
end --Malformed packets might cause an overread.
|
||||||
|
|
||||||
|
--Allocate new struct and copy into it.
|
||||||
|
n = n + 1
|
||||||
|
data[n] = ffi.new( t.ct )
|
||||||
|
types[n] = t.name
|
||||||
|
ffi.copy( data[n], readBuffer:ref(), t.size )
|
||||||
|
readBuffer:skip( t.size )
|
||||||
|
end
|
||||||
|
|
||||||
|
return data, types
|
||||||
|
end
|
||||||
|
|
||||||
|
function packet.getString( member )
|
||||||
|
return ffi.string( member, ffi.sizeof( member ) )
|
||||||
|
end
|
||||||
|
|
||||||
|
local writeBuffer = buffer.new( 1024 )
|
||||||
|
function packet.add( struct, data )
|
||||||
|
local str = ffi.new( struct.ct, data )
|
||||||
|
str.netname = assert( struct.netname )
|
||||||
|
writeBuffer:putcdata( str, struct.size )
|
||||||
|
return writeBuffer
|
||||||
|
end
|
||||||
|
|
||||||
|
function packet.get()
|
||||||
|
return writeBuffer:get()
|
||||||
|
end
|
||||||
|
|
||||||
|
mt.__call = packet.add
|
||||||
|
|
||||||
|
local testing = true
|
||||||
|
--TESTS--
|
||||||
|
if testing then
|
||||||
|
|
||||||
|
packet.serverInfo{
|
||||||
|
players = 0,
|
||||||
|
capacity = 255,
|
||||||
|
map = "abcdefghijklmnopqrstuvwxyz1234567890",
|
||||||
|
svname = "😘😘😘😘😘😘😘kissyfaceserver",
|
||||||
|
version = 25,
|
||||||
|
port = 51312,
|
||||||
|
ip = ipString.new{ 132, 213, 45, 21 }
|
||||||
|
}
|
||||||
|
|
||||||
|
packet.heartbeat{
|
||||||
|
tick = 49,
|
||||||
|
hash = 33753745832876,
|
||||||
|
protocol = 25
|
||||||
|
}
|
||||||
|
|
||||||
|
packet.insect{
|
||||||
|
id = 5,
|
||||||
|
dead = true,
|
||||||
|
hp = -3,
|
||||||
|
vx = -5,
|
||||||
|
vy = 47,
|
||||||
|
x = 59183,
|
||||||
|
y = 21412
|
||||||
|
}
|
||||||
|
|
||||||
|
local d, t = packet.deserialise( packet.get() )
|
||||||
|
assert( #writeBuffer == 0, "Test failed. Write buffer not empty!" )
|
||||||
|
for i = 1, #d do
|
||||||
|
print( "", t[i], d[i] )
|
||||||
|
if t[i] == 'serverInfo' then
|
||||||
|
print( "", "", packet.getString( d[i].map ), packet.getString( d[i].svname ) )
|
||||||
|
end
|
||||||
|
if t[i] == 'insect' then print( d[i].vx ) end
|
||||||
|
end
|
||||||
|
|
||||||
|
packet[42]{}
|
||||||
|
|
||||||
|
assert( not( pcall( packet.deserialise, "grgrsgs" ) ), "Test failed. Failed to reject malformed packet." )
|
||||||
|
end
|
||||||
|
--END TESTS--
|
||||||
|
|
||||||
|
return packet
|
Loading…
Reference in New Issue