diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..9706353 --- /dev/null +++ b/build.sh @@ -0,0 +1,10 @@ + +SRC_DIR="src" +LOVE_DIR="../../love" +BUILD_DIR="build" + +cp -r $SRC_DIR/ $BUILD_DIR/ +cd $BUILD_DIR/ +zip -9 -r vision.love + +cat ../../love/love.exe vision.love > vision.exe \ No newline at end of file diff --git a/src/metaserver.lua b/src/metaserver.lua index 71040c9..94aa93a 100644 --- a/src/metaserver.lua +++ b/src/metaserver.lua @@ -1,20 +1,86 @@ +local SERVERTIMEOUT = 30 +local CLIENTTIMEOUT = 1 + local shared = assert( require 'shared' ) local socket = assert( require 'socket' ) +local packet = assert( shared.packet ) 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 servers = {} +local clients = {} -local serverInfo = {} -local serverIPs = {} -local clientIPs = {} +local handlers = setmetatable({ -local function Parse( packet, ip, port ) - + serverInfo = function( svInfo, ip, port ) + if ip ~= tostring( svInfo.ip ) then return print("Server IP mismatch:", ip, svInfo.ip) end + local t = socket.gettime() + if not servers[ip] then servers[ip] = { ip = ip, port = port, info = svInfo } end + servers[ip].time = t + packet.advertised{ time = t } + + local p = packet.get() + for i = 1, 10 do udp:sendto( p, ip, port ) end + end, + + default = function( s, ip, port ) + print( ip, port, "Malformed message: ", s ) + end, + + metaServer = function() + + end, + + clientInfo = function( clientInfo, ip, port ) + if ip ~= tostring( clientInfo.ip ) then + return print( ip, port, "Client IP mismatch:", clientInfo.ip ) + end + + if clients[ip] then print( ip, port, "Client request timeout." ) end + + local t = socket.gettime() + clients[ip].time = t + + for i, server in ipairs( servers ) do + packet.serverInfo( server.info ) + end + + local p = packet.get() + for i = 1, 10 do udp:sendto( p, ip, port ) end + end + }, + + { + __index = function(t) return t.default end + }) + +local function read(msg, ip, port) + if not msg then return end + local msgs, types = packet.deserialise( msg ) + if types[1] ~= "metaServer" then + print( ip, port, "Dropped packet, no padding." ) + return read( udp:receivefrom() ) + end + for i = 1, #msgs do + handlers[ types[i] ]( msgs[i], ip, port ) + end + return read( udp:receivefrom() ) +end + +local function prune( t ) + print( "Pruning", socket.gettime() ) + for ip, server in pairs(servers) do + if server.time < t - SERVERTIMEOUT then + servers[ip] = nil + end + end end print( "Starting Metaserver", socket.gettime() ) -repeat - -until socket.sleep( 2.0 - (socket.gettime() % 2.0) ) \ No newline at end of file +repeat + read( udp:receivefrom() ) + prune( socket.gettime() ) + io.flush() +until socket.sleep( 2.0 ) \ No newline at end of file diff --git a/src/server.lua b/src/server.lua index c79c455..6913ba7 100644 --- a/src/server.lua +++ b/src/server.lua @@ -14,7 +14,7 @@ local svInfo = { version = 13, local server = { tick = 0 } -local msIP, msPort +local msIP, msPort = "127.0.0.0", 8 local clients = {} @@ -35,7 +35,10 @@ function server.StartLocalClient() end function server.Advertise() - udp:sendto( packet.get( packet.serverInfo( svInfo ) ) , msIP, msPort ) + print( socket.gettime(), "Advertise." ) + packet.metaServer{ padding = "" } + packet.serverInfo( svInfo ) + udp:sendto( packet.get() , msIP, msPort ) end --Incoming packet. @@ -61,10 +64,14 @@ function server.Start() server.SetIP( socket.dns.toip(socket.dns.gethostname()), 51312 ) assert( udp:setsockname( tostring( svInfo.ip ), svInfo.port )) server.StartLocalClient() + print( socket.gettime(), "Start." ) repeat server.Parse( udp:receivefrom() ) server.Advance() - until socket.sleep( 0.1 - (socket.gettime() % 0.1) ) + if server.tick % 20 == 0 then + server.Advertise() + end + until socket.sleep( 0.1 ) end function server.Advance() diff --git a/src/shared/packet.lua b/src/shared/packet.lua index b58c528..67f6d4e 100644 --- a/src/shared/packet.lua +++ b/src/shared/packet.lua @@ -8,9 +8,10 @@ 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 ) ) + 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 ) + assert( t.size < 500, t.name ) setmetatable( t, mt ) --print( "Packet:", t.name, "Members:", #t + 1, "Size:", t.size, "Alignment:", ffi.alignof( t.ct ) ) @@ -29,9 +30,15 @@ newStruct{ } newStruct{ - name = "requestServers", + name = "clientInfo", + netname = 22, + "char username[31]", +} + +newStruct{ + name = "metaServer", netname = 123, - "char padding[999]" + "char padding[300]" --Just a bunch of padding to mitigate amplification. } newStruct{ @@ -84,6 +91,12 @@ newStruct{ "char command", } +newStruct{ + name = "advertised", + netname = 144, + "uint32_t time", +} + local readBuffer = buffer.new( 1024 ) function packet.deserialise( str ) readBuffer:set( str ) @@ -117,7 +130,7 @@ end local writeBuffer = buffer.new( 1024 ) function packet.add( struct, data ) - local str = ffi.new( struct.ct, data ) + local str = ffi.new( struct.ct, data or 0 ) str.netname = assert( struct.netname ) writeBuffer:putcdata( str, struct.size ) return writeBuffer @@ -129,7 +142,7 @@ end mt.__call = packet.add -local testing = true +local testing = testing --TESTS-- if testing then