--Note, this won't work unless you set up port forwarding! local SERVERTIMEOUT = 30 local CLIENTTIMEOUT = 1 local shared = assert( require '../shared.shared' ) local socket = assert( require 'socket' ) local packet = assert( shared.packet ) local udp = assert( socket.udp() ) local msip = assert( require 'getip' ) udp:settimeout(0) local localIP = socket.dns.toip(socket.dns.gethostname()) print( "Metaserver local IP:", localIP ) assert( udp:setsockname( localIP, shared.metaserver.port )) --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 tick = 0 local handlers = setmetatable({ serverInfo = function( svInfo, ip, port ) print( "Server:", ip, port ) local t = socket.gettime() if not servers[ip..port] then servers[ip..port] = { ip = ip, port = port, info = svInfo } --NAT punch: the server doesn't know its own external IP --so it contacts a third party (the metaserver) to discover it. --This external IP gets advertised to prospective clients. svInfo.ip = shared.ip.fromString( ip ) svInfo.port = port end servers[ip..port].time = t packet.advertised{ time = t, ip = svInfo.ip, port = svInfo.port } return udp:sendto( packet.get(), ip, port ) 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]] print( "Server List:", ip, port ) clients[ip] = clients[ip] or {} local t = socket.gettime() clients[ip].time = t packet.heartbeat{ tick = tick } for svIP, server in pairs( servers ) do print( "", svIP, packet.getString( server.info.svname )) packet.serverInfo( server.info ) end return udp:sendto( packet.get(), ip, port ) 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 ) for ip, server in pairs(servers) do if server.time < t - SERVERTIMEOUT then print( "Pruning server IP:", ip ) servers[ip] = nil end end end print( "Starting Metaserver", os.time(), udp:getsockname() ) function love.update() read( udp:receivefrom() ) prune( socket.gettime() ) io.flush() tick = tick + 1 end