diff --git a/src/client/assets/glsl/crepuscular b/src/client/assets/glsl/crepuscular deleted file mode 100644 index 48d9a6a..0000000 --- a/src/client/assets/glsl/crepuscular +++ /dev/null @@ -1,21 +0,0 @@ -#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 \ No newline at end of file diff --git a/src/client/client/assets/client-icon.png b/src/client/client/assets/client-icon.png deleted file mode 100644 index 0329af9..0000000 Binary files a/src/client/client/assets/client-icon.png and /dev/null differ diff --git a/src/client/config.lua b/src/client/config.lua deleted file mode 100644 index 96825c1..0000000 --- a/src/client/config.lua +++ /dev/null @@ -1,68 +0,0 @@ -local config -local lfs = assert( love ).filesystem -local cfg = lfs.newFile "cfg.lua" - -local mt = { __tostring = function( t ) - local arr = { "tblOption{\n ",} - for k, v in pairs( t ) do - arr[#arr + 1] = k - arr[#arr + 1] = " = " - arr[#arr + 1] = tostring( v ) - arr[#arr + 1] = ",\n " - end - arr[#arr + 1] = "}" - return table.concat( arr ) -end } -local function tblOption(t) - return setmetatable( t, mt ) -end - -local defaultConfig = { - plName = "Player Name", - plPronoun = tblOption{ - subject = "they", - object = "them", - possessive = "their", - }, - plColour = tblOption{ 0.5, 0.6, 0.7, 0.5 }, - gamma = 0.5, - keybinds = tblOption{ - Forward = "w", - Back = "s", - Left = "a", - Right = "d", - Chat = "t", - Love = "q", - Hate = "e", - }, - serverIP = "192.168.2.15", - serverPort = 51312, - logFile = "log.txt", -} - -local function readConfigFile() - local ok, cfgTbl, err = pcall( lfs.load, 'cfg.lua' ) - if ok and cfgTbl then - local ok, err = pcall( cfgTbl ) - if err then print( "Failed to load settings file: ", err ) end - return - end - return defaultConfig -end - -local function dumpConfigFile() - print( "Saving Settings." ) - assert( cfg:open 'w' ) - cfg:write( "return {\n " ) - for k, v in pairs( config ) do - cfg:write( k ) - cfg:write( " = " ) - cfg:write( tostring( v ) ) - cfg:write( ",\n" ) - end - cfg:write( "}" ) -end - -config = readConfigFile() - -return config \ No newline at end of file diff --git a/src/client/connecting.lua b/src/client/connecting.lua deleted file mode 100644 index 642030e..0000000 --- a/src/client/connecting.lua +++ /dev/null @@ -1,90 +0,0 @@ -local scene = assert( require 'scene' ) -local lg = assert( love.graphics ) -local server = assert( require 'udp' ) -local button = assert( require 'ui.button' ) -local strings = assert( require 'strings' ) -local connecting = {} - -local time, ip, port, attempts, svInfo = 0, 0, 0, 1 - -local cancelButton = button{ - x = lg.getWidth() / 4, - y = lg.getHeight() / 2, - w = lg.getWidth() / 2, - h = 100, - text = lg.newText( lg.getFont(), strings.cancel_button ), -} - -function connecting.mousemoved( x, y ) - cancelButton.selected = cancelButton:contains( x, y ) -end - -function connecting.mousepressed( x, y ) - if cancelButton:contains( x, y ) then return scene.browser() end -end - -function connecting.keypressed( x, y ) - return scene.browser() -end - -function connecting.draw() - lg.setColor( 1,1,1,1 ) - lg.printf( ("ADDRESS: %s"):format( ip ), lg.getWidth() / 4, 15, lg.getWidth() - 30, "left" ) - lg.printf( ("ATTEMPTS: %d"):format( attempts ), lg.getWidth() / 4, 20 + lg.getFont():getHeight(), lg.getWidth() - 30, "left" ) - cancelButton:draw() - return false -end - -function connecting.svChimo( msg ) - return server.answerChallenge( msg.nonce ) -end - -function connecting.connected( msg ) - server.setToken( msg.token ) - return scene.game() -end - -function connecting.keypressed(key, code, isrepeat) - if code == "escape" then return scene.browser() end -end - -function connecting.read( msg ) - if not msg then return false end - local msgs, types = server.deserialise( msg ) - for i = 1, #msgs do - ( connecting[ types[i] ] or print )( msgs[i], ip, port ) - end - return connecting.read( server.receive() ) -end - -function connecting.update(dt) - time = time + dt - - if time > 2 then - time = 0 - attempts = attempts + 1 - server.connect( ip, port ) - --return scene.loadScene( scene.game ) - end - - return connecting.read( server.receive() ) -end - -function connecting:onLoad( params ) - lg.setCanvas() - time = 0 - attempts = 1 - params = params or { ip = "8.8.8.8", port = 8 } - ip, port = params.ip, params.port - if server.isValid( ip, port ) then - server.setInfo( params.svInfo ) - return server.connect( ip, port ) - end -end - -function connecting.exit() - -end - -scene.connecting = connecting -return connecting \ No newline at end of file diff --git a/src/client/crepuscular.lua b/src/client/crepuscular.lua deleted file mode 100644 index 6be36ee..0000000 --- a/src/client/crepuscular.lua +++ /dev/null @@ -1,23 +0,0 @@ -local crepuscular = {} -local lg = assert( love.graphics ) -local shader = assert( lg.newShader( 'assets/glsl/crepuscular' )) -local scene = assert( require( 'scene' ) ) -local rectanglePosition = { } - -function crepuscular.draw() - -end - -function crepuscular.onLoad() - -end - -function crepuscular.resize() - -end - -function crepuscular.update() - -end - -return crepuscular \ No newline at end of file diff --git a/src/client/game.lua b/src/client/game.lua deleted file mode 100644 index bc2a2bd..0000000 --- a/src/client/game.lua +++ /dev/null @@ -1,91 +0,0 @@ -local lg = assert( love.graphics ) -local scene = assert( require 'scene' ) -local shared = assert( require 'shared.shared' ) -local server = assert( require 'udp' ) -local packet = shared.packet -local crepuscular = assert( require 'crepuscular' ) - -local game = {} -local handlers = setmetatable( {}, {__index = function() return print end } ) -local t = 0 -local tick = 0 -local serverTick = 0 - -function handlers.connected( data ) - serverTick = math.max( data.tick, serverTick ) - tick = math.max( serverTick, tick ) -end - -function handlers.insect( data ) - -end - -function handlers.soleil( data ) - -end - -function handlers.playerChange( data ) - -end - -function handlers.svInfo( data ) - if server.svInfo.map ~= data.map then end - return server.setInfo( data ) -end - -function handlers.chatMessage( msg ) - print( msg.cmsg ) -end - -function game.draw() - lg.setColor( 1, 1, 1, 1 ) - lg.print( "Client Tick: "..tick, 0, 0 ) - lg.print( "Server Tick: "..serverTick, 0, 25 ) - lg.print( "Current Map: "..packet.getString(server.svInfo.map), 0, 50 ) - lg.print( "Server Name: "..packet.getString(server.svInfo.svname), 0, 75 ) - lg.print( "# Connected: "..server.svInfo.players, 0, 100 ) -end - -function game.onPacket( msg ) - if not msg or (#msg < 1) then return end - local msgs, types = packet.deserialise( msg ) - if not msgs then - print( "malformed packet:", types ) - return game.onPacket( server.receive() ) - end - for i = 1, #msgs do - --Handler returns something if msg should be discarded. - if handlers[ types[i] ]( msgs[i] ) then break end - end - return game.onPacket( server.receive() ) -end - -function game.update( dt ) - t = dt + t - game.onPacket( server.receive() ) - if t > 0.1 then - t = 0 - tick = tick + 1 - server.newPacket( tick ) - assert( server.send() ) - end -end - -function game.newGame( ) - game.curWorld = shared.NewWorld() --Last world state received from server. - game.preWorld = shared.NewWorld() --Current world state predicted by this client. -end - -function game.disconnect( ) - return scene.mainmenu( server.disconnect( tick ) ) -end - -function game.onLoad( params ) -end - -function game.keypressed( key, code, isRepeat ) - if code == "escape" then return game.disconnect() end -end - -scene.game = game -return game \ No newline at end of file diff --git a/src/client/main.lua b/src/client/main.lua index 31206f0..b4b07b6 100644 --- a/src/client/main.lua +++ b/src/client/main.lua @@ -1,18 +1,17 @@ -package.cpath = "..\\?.dll;..\\clib\\?.dll;"..package.cpath -package.path = "..\\?.lua;..\\lualib\\?.lua;"..package.path local shared = assert( require 'shared.shared' ) local love = assert( love ) function love.load() + package.path = "./client/?.lua"..package.path print( "Client Started." ) assert( require 'config' ) --Crash if running luajit 2.1 and coconut missing --[[loadstring( love.data.decode( "string", "base64","G0xKAgrbAQAACgALABY2AAAAOQABADkAAgAnAgMAJwMEADYEAAA5BAEEOQQFBCcGBgA2BwAAOQcHBzkHCAcnCQkAQgcCAEEEAQBBAAICBgAKAFgAAoArAAEAWAEBgCsAAgBMAAIALWQ4MmY3M2RkNjQ1MDcxNDZiNTkwNTMwYjg0NDcwMWZlMmJmYjdjZTkeY2xpZW50L2Fzc2V0cy9jb2NvbnV0LnBuZxFuZXdJbWFnZURhdGEKaW1hZ2UJc2hhMQloYXNoCGhleAtzdHJpbmcLZW5jb2RlCWRhdGEJbG92ZV0BAAUABQAONgAAADMCAQBCAAICDgAAAFgBB4A2AAIANAIAADUDAwA2BAAAPQQEA0IAAwJCAAECMgAAgEwAAgALX19jYWxsAQAAEXNldG1ldGF0YWJsZQAKcGNhbGwA" ))()]] - love.window.setIcon( assert( love.image.newImageData( "assets/client-icon.png" ) ) ) - love.graphics.setNewFont( "assets/fonts/Montserrat-Bold.ttf", 48 ) + love.window.setIcon( assert( love.image.newImageData( "client/assets/client-icon.png" ) ) ) + love.graphics.setNewFont( "client/assets/fonts/Montserrat-Bold.ttf", 48 ) local scenes = assert( require 'scene' ) assert( require 'ui.options' ) diff --git a/src/client/renderer/main.lua b/src/client/renderer/main.lua deleted file mode 100644 index 20a74e9..0000000 --- a/src/client/renderer/main.lua +++ /dev/null @@ -1,47 +0,0 @@ -local love = assert( love ) -local lg = love.graphics -local time = 0 -local text = "" - ---Set up the canvas. -assert( lg.getCanvasFormats( false ).stencil8, "Error: 8-bit stencil buffers not supported on this system." ) -local stencil = love.graphics.newCanvas( - lg.getWidth(), - lg.getHeight(), - { - type = "2d", - format = "stencil8", - readable = false, - msaa = 0, - dpiscale = 1, - mipmaps = "none", - }) - -local canvas = love.graphics.newCanvas( - lg.getWidth(), - lg.getHeight(), - { - type = "2d", - format = "rgba8", - readable = true, - msaa = 0, - dpiscale = 1, - mipmaps = "none", - }) - -function love.update(dt) - time = time + dt -end - -function love.draw() - lg.setCanvas{{canvas}, depthstencil = {stencil}} - lg.clear() - lg.setColor( 1,1,1,0.3 ) - lg.rectangle( "fill", time * 15.0 , 0, 400, 400 ) - lg.setCanvas() - lg.draw( canvas ) -end - -function love.textinput(t) - text = text..t -end \ No newline at end of file diff --git a/src/client/scene.lua b/src/client/scene.lua deleted file mode 100644 index b013f68..0000000 --- a/src/client/scene.lua +++ /dev/null @@ -1,47 +0,0 @@ -local scene = {} -local love = assert( love ) - -local callbacks = { - draw = true, - mousepressed = true, - mousemoved = true, - keypressed = true, - update = true, - resize = true, - wheelmoved = true, -} - -local mt = {} - -function scene.loadScene( scen, params ) - print( "Loading Scene:", scen.name ) - for k, v in pairs( callbacks ) do - if not scen[k] then print( "Warning: scene missing callback.", scen.name, k ) end - love[k] = scen[k] or love[k] - end - scen:onLoad( params ) -end - -local function newScene( scenes, name, t ) - t.name = t.name or name - print( "Adding Scene:", t.name ) - setmetatable( t, { __call = function() return scene.loadScene( t ) end } ) - rawset( scenes, name, t ) -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, - {__call = scene.loadScene, - __newindex = newScene - } ) \ No newline at end of file diff --git a/src/client/strings.lua b/src/client/strings.lua deleted file mode 100644 index 423a930..0000000 --- a/src/client/strings.lua +++ /dev/null @@ -1,3 +0,0 @@ ---TODO: check config option for current language, dynamically change it? -local utf8 = assert( require 'utf8' ) -return require 'client.assets.strings.english' \ No newline at end of file diff --git a/src/client/test/browser.lua b/src/client/test/browser.lua deleted file mode 100644 index 368af81..0000000 --- a/src/client/test/browser.lua +++ /dev/null @@ -1,39 +0,0 @@ -local packet = assert( require 'shared.packet' ) -local ipString = assert( require 'shared.ipstring' ) -local utf8 = assert( require 'utf8' ) -local r = math.random -local rand = function() return r( 1, 255 ) end -local rs = function() - local t = {} - for i = 1, r( 0, 64 ) do t[i] = rand() end - return string.char( unpack( t ) ) -end -local rutf8 = function() - local t = {} - for i = 1, r( 1, 16 ) do t[i] = r( 0x40, 0x70 ) end - - local s = utf8.char( unpack( t ) ) - return s -end -local randserver = function() - local str = rutf8 - return packet.serverInfo{ - players = rand(), - capacity = rand(), - ip = ipString.new{ rand(), rand(), rand(), rand() }, - port = r( 1, 65535 ), - version = 25, - svname = str(), - map = str(), - } -end - -return { - - --Simulate getting server info from the metaserver. - getTestServers = function() - packet.get() - for i = 1, r( 1, 125 ) do randserver() end - return packet.deserialise( packet.get() ) - end -} \ No newline at end of file diff --git a/src/client/udp.lua b/src/client/udp.lua deleted file mode 100644 index 90a60a8..0000000 --- a/src/client/udp.lua +++ /dev/null @@ -1,82 +0,0 @@ -local socket = assert( require 'socket' ) -local ms = assert( require 'shared.metaserver' ) -local config = assert( require 'config' ) - -local udp = { svInfo = {}, token = false, } -local packet = assert( require 'shared.packet' ) -local hash = assert( require 'shared.hash' ) - -local cxn = assert( socket.udp() ) -local mscxn = assert( socket.udp() ) -cxn:settimeout( 0 ) -mscxn:settimeout( 0 ) -assert(mscxn:setpeername( ms.ip, ms.port )) - -function udp.receive() - return cxn:receive() -end - -udp.deserialise = packet.deserialise - -function udp.receiveMeta() - return mscxn:receive() -end - -function udp.requestServerList() - print( "Requesting server list." ) - packet.get() - packet.metaServer() - packet.clientInfo() - return mscxn:send( packet.get() ) -end - -function udp.newPacket( tick ) - if udp.token then packet.connected{ token = udp.token, tick = tick or 0 } end -end - -function udp.setToken( token ) - print( "Setting server token:", token ) - udp.token = token -end - -function udp.setInfo( svInfo ) - udp.svInfo = svInfo -end - -function udp.answerChallenge( svNonce ) - local clNonce = hash.rand() - packet.get() - packet.clChimo{ nonce = clNonce, hash = hash.hash( clNonce, svNonce ) } - print( "Received authentication nonce. Reply:", clNonce, svNonce ) - return udp.send() -end - -function udp.isValid( ip, port ) - local s, e = socket.udp() - if s then s, e = s:setpeername( ip, port ) end - if s then return true - else return nil, e end --temporary socket, gc it, we just want the error -end - -function udp.connect( ip, port ) - assert( cxn:setpeername( ip, port ) ) - print( "Connection request to:", ip, port ) - return udp.send( packet.clientInfo{ username = config.plName }) -end - -function udp.disconnect( tick ) - for i = 1, 10 do - udp.newPacket( tick ) - packet.disconnect() - udp.send() - end - udp.setToken() - cxn = assert( socket.udp() ) - cxn:settimeout( 0 ) -end - -function udp.send() - return cxn:send( packet.get() ) -end - -return udp \ No newline at end of file diff --git a/src/client/ui/browser.lua b/src/client/ui/browser.lua deleted file mode 100644 index 2cd8178..0000000 --- a/src/client/ui/browser.lua +++ /dev/null @@ -1,247 +0,0 @@ -local lg = assert( love.graphics ) -local scene = assert( require 'scene' ) -local textInput = assert( require 'ui.textinput' ) -local button = assert( require 'ui.button' ) -local packet = assert( require 'shared.packet' ) -local menu = assert( require 'ui.menu' ) -local strings = assert( require 'strings' ) -local fonts = assert( require 'ui.fonts' ) -local metaserver = assert ( require 'udp' ) -local utf8 = assert( require 'utf8' ) - -local browser = { latest = 0, } - -local test = assert( require 'test.browser' ) - -local font = fonts.font -local cw = fonts.font:getWidth( "w" ) - -local function joinServerCallback( button ) - if button.ip and button.port then - return browser.joinIP( button.ip, button.port, button.serverInfo ) - end -end - -local function tryAdd( text, d, x ) - local s = packet.getString( d ) - return pcall( text.add, text, s, x ) or text:add( strings.utf8_error, x ) -end - -local function serverInfoToText( server ) - local cw = fonts.font:getWidth( "w" ) - local text = lg.newText( fonts.font ) - tryAdd( text, server.svname, 0 ) - tryAdd( text, server.map, cw * 16 ) - text:add( tostring( server.ip ), cw * 32 ) - text:add( server.port, cw * ( 32 + 12 ) ) - text:add( server.players, cw * ( 32 + 12 + 6 ) ) - text:add( server.capacity, cw * ( 32 + 12 + 9 ) ) - return text -end - - - -local serverList = menu.new{ - name = "serverList", - buttons = {}, - fg = lg.newMesh{ - { 0.5, 0, 0.5, 0, 0, 0, 0, 0 }, - { 1, 0, 1, 0, 1, 1, 1, 0.5 }, - { 1, 1, 1, 1, 1, 1, 1, 0.5 }, - { 0.5, 1, 0.5, 1, 0, 0, 0, 0 }, - }, - bg = lg.newMesh{ - { 0, 0, 0, 0, 0.4, 0.05, 0.0, 0.9 }, - { 1, 0, 1, 0, 0.8, 0.3, 0.1, 0.8 }, - { 1, 1, 1, 1, 0.7, 0.4, 0.1, 0.8 }, - { 0, 1, 0, 1, 0.4, 0.05, 0.05, 0.9 }, - }, - - font = fonts.font, - subScene = true } -serverList.selected = false -serverList.x = 25 -serverList.y = 0 -serverList.h = 36 -serverList.ips = {} -local serverButtons = serverList.buttons -local color = { 1, 0.6, 0.6, 0.1 } -local ti = textInput.new{ - width = lg.getWidth(), - length = 20, - x = cw, - y = 35, - h = 55, - str = strings.ip_button, - font = fonts.midFont, -} -function ti:callback() return self:enterText( browser.joinIPString ) end -local headerButtons = { - - button{ - callback = function() serverList.clear() return serverList.requestServers() end, - text = lg.newText( fonts.midFont, strings.refresh_button ) , - color = color, - x = cw * 32, - y = 75, - w = 1400, - h = 36 - }, - - button{ - callback = function() return scene.mainmenu() end, - text = lg.newText( fonts.midFont, strings.mainmenu_button ) , - color = color, - x = cw, - y = 75, - w = 1400, - }, - - ti, - - button{ x = cw * 53, color = color, y = 135, text = lg.newText( font, strings.svinfo_capacity ) }, - button{ x = cw * 50, color = color, y = 135, text = lg.newText( font, strings.svinfo_players ) }, - button{ x = cw * 44, color = color, y = 135, text = lg.newText( font, strings.svinfo_port ) }, - button{ x = cw * 32, color = color, y = 135, text = lg.newText( font, strings.svinfo_ip ) }, - button{ x = cw * 16, color = color, y = 135, text = lg.newText( font, strings.svinfo_map ) }, - button{ x = cw , color = color, y = 135, text = lg.newText( font, strings.svinfo_name ) }, - -} - -for j, headerButton in ipairs( headerButtons ) do - serverButtons[j] = headerButton -end - -function serverList.requestServers() - return metaserver.requestServerList() -end - -function serverList.clear( ) - for i = #headerButtons + 1, #serverButtons do serverButtons[i] = nil end - for ip in pairs( serverList.ips ) do serverList.ips[ip] = nil end -end - -function serverList.add( serverInfo ) - local y = 27 * ( #serverButtons - #headerButtons ) + 180 - local ip = tostring( serverInfo.ip ) - serverButtons[ #serverButtons + 1] = button{ - space = 0, - x = cw, - w = lg.getWidth(), - y = y, - h = 24, - color = { 0.3 + 0.1 * (#serverButtons % 2), 0.3 + 0.1 * (#serverButtons % 2), 0.8, 0.3 }, - callback = joinServerCallback, - serverInfo = serverInfo, - ip = ip, - port = serverInfo.port, - text = serverInfoToText( serverInfo ), - active = ( y < lg.getHeight() )} - serverList.ips[ ip ] = true - return serverList:paint() -end - -local metaServerHandlers = setmetatable( - { - default = function() end, - serverInfo = serverList.add, - }, - {__index = function( t ) return t.default end }) - -function serverList.scroll( up ) - local minY = 170 - local maxY = lg.getHeight() + 40 - if #serverButtons > #headerButtons then - if up and serverButtons[ #headerButtons + 1 ].y > minY then return end - if ( not up ) and serverButtons[ #serverButtons ].y < maxY then return end - - up = ( 27 / 3 ) * ( up and 1 or -1 ) - for i = #headerButtons + 1, #serverButtons do - local sb = serverButtons[i] - sb.y = sb.y + up - sb.active = ( sb.y > minY ) and ( sb.y < maxY ) - end - end - return serverList:paint() -end - -browser.selected = false - -function browser.draw() - lg.setColor( 1, 1, 1, 1 ) - serverList.draw() -end - -function browser.update( dt ) - local p = metaserver.receiveMeta() - if not p then return end - print( "Receiving server list:", p ) - local msgs, types = packet.deserialise( p ) - for i = 1, #msgs do metaServerHandlers[types[i]]( msgs[i] ) end -end - -function browser.onLoad( ) - serverList:onLoad() - lg.setColor( 1, 1, 1, 1 ) -end - -function browser.mousemoved( x, y, dx, dy, istouch ) - return serverList.mousemoved( x, y, dx, dy, istouch ) -end - -function browser.wheelmoved( x, y ) - if y == 0 then return end - return serverList.scroll( ( y > 0 ) ) -end - -function browser.resize( x, y ) - serverList.resize( x, y ) - - for i, button in ipairs( serverButtons ) do - button.w = x - end - return serverList:paint() -end - -function browser.mousepressed(x, y, button, istouch, pressed) - return serverList.mousepressed( x, y, button, istouch, pressed ) -end - -function browser.joinIPString( s ) - --Parse IP address and port from string. If it's valid, join the server. - --TODO: there should be two fields, one for IP, one for port. - --Parsing the entered address for the port is possible but more error-prone. - print( "browser: entered IP and port", s ) - if not s then return end - ti:clear() - local ip, port = s:match '(%d+%.%d+%.%d+%.%d+)', s:match ':(%d+)' - print( "browser:", "ip:", ip, port ) - - if ip and port then return browser.joinIP( ip, port ) end -end - -function browser.joinIP( ip, port, svInfo ) - print( "Joining server:", ip, port ) - return scene.loadScene( scene.connecting, { ip = ip, port = port, svInfo = svInfo } ) -end - -function browser.keypressed( key, code, isRepeat ) - - local y = serverList.getSelectedButton() - - if code == "escape" then return scene.mainmenu() end - - if y and code == "down" and y.y > lg.getHeight() - 100 then - for i = 1, 3 do serverList.scroll( false ) end - end - - if y and code == "up" and y.y > 180 and y.y < 250 then - for i = 1, 3 do serverList.scroll( true ) end - end - - return serverList.keypressed( key, code, isRepeat ) - -end - -scene.browser = browser -return browser \ No newline at end of file diff --git a/src/client/ui/button.lua b/src/client/ui/button.lua deleted file mode 100644 index 00528d9..0000000 --- a/src/client/ui/button.lua +++ /dev/null @@ -1,58 +0,0 @@ - -local lg = assert( love.graphics ) -local button = { - h = 60, - y = 0, - x = 0, - w = 100, - space = 15, -} -local mt = { __index = button } - -function button:new( t ) - t = t or {} - - if t.y then button.y = t.y end - if t.h then button.h = t.h end - if t.w then button.w = t.w end - if t.x then button.x = t.x end - if t.space then button.space = t.space end - - t.x = t.x or button.x - t.y = t.y or button.y - t.w = t.w or button.w - t.h = t.h or button.h - t.text = t.text or lg.newText( lg.getFont(), "button" ) - t.color = t.color or { 0.5, 0.5, 0.5, 0.5 } - t.callback = t.callback or function() print( "Clicked button:", t.text ) end - t.selected = t.selected or false - if t.active == nil then t.active = true end - - button.y = button.y + t.h + button.space - - return setmetatable( t, mt ) -end - -function button:contains( x, y ) - local mx, my, Mx, My = self.x, self.y, self.x + self.w, self.y + self.h - return self.active and (x < Mx and x > mx and y > my and y < My) -end - -function button:draw( ) - if not self.active then return end - lg.setColor( self.color ) - lg.rectangle( "fill", self.x, self.y, self.w, self.h, 10) - - - if self.selected then - lg.setColor( 1, 1, 1, 0.8 ) - lg.rectangle( "fill", self.x + 3, self.y + 3, self.w - 6, self.h - 6, 10 ) - end - - lg.setColor( 0, 0, 0, 0.8 ) - lg.draw( self.text, self.x + 15, self.y + self.h / 2 - self.text:getHeight() / 2 ) - lg.setColor( 0, 0, 0, 0.2 ) - lg.draw( self.text, self.x + 12, self.y + self.h / 2 - self.text:getHeight() / 2 )-- + self.h / 2 ) -end - -return setmetatable( button, { __call = button.new } ) \ No newline at end of file diff --git a/src/client/ui/fonts.lua b/src/client/ui/fonts.lua deleted file mode 100644 index 6ccdf5a..0000000 --- a/src/client/ui/fonts.lua +++ /dev/null @@ -1,9 +0,0 @@ ---References to font objects. -local lgnf = love.graphics.newFont - - -return { - font = lgnf( "assets/fonts/Montserrat-Bold.ttf", 14 ), - midFont = lgnf( "assets/fonts/Montserrat-Bold.ttf", 24 ), - headerFont = lgnf( "assets/fonts/Montserrat-Bold.ttf", 48 ) -} \ No newline at end of file diff --git a/src/client/ui/mainmenu.lua b/src/client/ui/mainmenu.lua deleted file mode 100644 index b4b2c66..0000000 --- a/src/client/ui/mainmenu.lua +++ /dev/null @@ -1,54 +0,0 @@ -local lg = assert( love.graphics ) -local love = assert( love ) -local scene = assert( require 'scene' ) -local strings = strings or assert( require 'strings' ) -local button = assert( require 'ui.button' ) -local menu = assert( require 'ui.menu' ) -local font = assert( require 'ui.fonts').headerFont - -return menu.new{ - name = "mainmenu", - - buttons = { - - button{ - x = 15, w = lg.getWidth(), y = 115, h = 72, space = 15, - text = lg.newText( font, strings.newgame_button ), - color = { 0.6, 0.6, 0.6, 0.9 }, - callback = function() return scene.connecting{ip = "127.0.0.0", port = 8} end }, - - button{ - text = lg.newText( font, strings.join_button ), - color = { 0.6, 0.6, 0.6, 0.9 }, - callback = function() return scene.browser() end }, - - button{ - text = lg.newText( font, strings.option_button ), - color = { 0.6, 0.6, 0.6, 0.9 }, - callback = function() return scene.options() end }, - - button{ - text = lg.newText( font, strings.quit_button ), - color = { 0.6, 0.6, 0.6, 0.9 }, - callback = love.event.quit }, - - }, - - fg = lg.newMesh{ - { 0, 0, 0, 0, 0.4, 0.1, 0.05, 0.0 }, - { 1, 0, 1, 0, 0.8, 0.3, 0.1, 0.8 }, - { 1, 1, 1, 1, 0.7, 0.4, 0.1, 0.8 }, - { 0, 1, 0, 1, 0.4, 0.1, 0.03, 0.0 }, - }, - - bg = lg.newMesh{ - { 0, 0, 0, 0, 1, 1, 1, 0.01 }, - { 1, 0, 1, 0, 1, 1, 1, 0.1 }, - { 1, 1, 1, 1, 0, 0, 0, 0.1 }, - { 0, 1, 0, 1, 0, 0, 0, 0.01 }, - }, - - font = font, - - wheelmoved = function( x, y ) return ( y ~= 0 ) and love.keypressed( nil, (y > 0) and "up" or "down" ) end -} \ No newline at end of file diff --git a/src/client/ui/menu.lua b/src/client/ui/menu.lua deleted file mode 100644 index a93c404..0000000 --- a/src/client/ui/menu.lua +++ /dev/null @@ -1,153 +0,0 @@ -local love = assert( love ) -local lg = assert( love.graphics ) -local scene = assert( require 'scene' ) -local menu = {} - ---Static variables. -local selectedButtonIdx -local canvas -local wWidth, wHeight -local currentMenu - -function menu.getSelectedButton() - return selectedButtonIdx and currentMenu.buttons[selectedButtonIdx] -end - -function menu.selectButton( idx ) - local but = currentMenu.buttons[selectedButtonIdx] - if but then but.selected = false end - selectedButtonIdx = idx - but = currentMenu.buttons[idx] - if but then but.selected = true end -end - -function menu.clear() - return lg.clear( canvas ) -end - -function menu.new( t ) - if t.subScene then setmetatable( t, t ) - else - scene[t.name] = t - end - getmetatable( t ).__index = menu - return t -end - -function menu:onLoad() - print( 'Loading Menu:', self.name ) - currentMenu = self - if self.font then lg.setFont( self.font ) end - return menu.resize( lg.getDimensions() ) -end - -function menu.update( dt ) end - -function menu.resize( w, h ) - wWidth, wHeight = w, h - canvas = lg.newCanvas() - return currentMenu:paint() -end - -function menu.draw() - lg.setCanvas() - lg.setColor( 1,1,1,1 ) - lg.draw( canvas ) -end - -function menu.mousemoved( x, y, dx, dy, istouch ) - if not currentMenu then return end - local buttons = currentMenu.buttons - - local selectedButton = buttons[selectedButtonIdx or 0] - for id, menuButton in ipairs( buttons ) do - if menuButton:contains( x, y ) then - if selectedButton then selectedButton.selected = false end - menuButton.selected = true - selectedButtonIdx = id - if menuButton ~= selectedButton then - return currentMenu:paint() - else return end - end - end - - --deselect button - if selectedButton then - selectedButtonIdx = nil - selectedButton.selected = false - return currentMenu:paint() - end -end - - -function menu.mousepressed( x, y, button, istouch, presses ) - - if not selectedButtonIdx and currentMenu then return end - local uiButton = currentMenu.buttons[selectedButtonIdx] - if uiButton:contains( x, y ) then - selectedButtonIdx = nil - uiButton.selected = false - return uiButton:callback() - end - return currentMenu:paint() -end - -function menu.keypressed( key, code, isrepeat ) - - assert( currentMenu ) - - if code == "escape" then - return love.event.quit() - end - - local buttons = currentMenu.buttons - - if code == "return" and selectedButtonIdx then - local button = buttons[selectedButtonIdx] - selectedButtonIdx = nil - button.selected = false - currentMenu:paint() - return button:callback() - end - - if #buttons > 0 and (code == "down" or code == "tab" or code == "up") then - repeat - local sbi = (selectedButtonIdx or 1) - if buttons[sbi] then buttons[sbi].selected = false end - - --Increment / decrement - - sbi = sbi + ((code == "up") and -1 or 1) - if #buttons < 1 then selectedButtonIdx = false; return end - if sbi > #buttons then sbi = 1 end - if sbi < 1 then sbi = #buttons end - - selectedButtonIdx = sbi - buttons[selectedButtonIdx].selected = true - until buttons[selectedButtonIdx].active --Skip deactivated buttons. - print( "Selected button: ", selectedButtonIdx ) - end - - - return currentMenu:paint() -end - -function menu:paint() - lg.setCanvas( canvas ) - - --bg - lg.setColor( 1, 1, 1, 1 ) - if self.bg then lg.draw( self.bg, 0, 0, 0, wWidth, wHeight ) end - - --buttons - for i = #self.buttons, 1, -1 do self.buttons[i]:draw( ) end - - --gradient - lg.setColor( 1, 1, 1, 1 ) - - if self.fg then lg.draw( self.fg, 0, 0, 0, wWidth, wHeight ) end - lg.setCanvas() -end - - -return menu \ No newline at end of file diff --git a/src/client/ui/options.lua b/src/client/ui/options.lua deleted file mode 100644 index 062a222..0000000 --- a/src/client/ui/options.lua +++ /dev/null @@ -1,84 +0,0 @@ -local lg = assert( love.graphics ) -local love = assert( love ) -local scene = assert( require 'scene' ) -local strings = strings or assert( require 'strings' ) -local button = assert( require 'ui.button' ) -local menu = assert( require 'ui.menu' ) -local config = assert( require 'config' ) -local font = assert( require 'ui.fonts' ).midFont - -local function editSelectedOption( button ) - -end - -local optionsMenu = menu.new{ - name = "options", - - buttons = { - - button{ - x = 0.5 * lg.getWidth(), w = 0.45 * lg.getWidth(), h = lg.getHeight(), y = 55, - text = lg.newText( font, "" ), - color = { 0.4, 0.1, 0.1, 0.1 } - }, - - button{ - x = 15, y = 115, w = 800, h = 30, space = 8, - text = lg.newText( font, strings.mainmenu_button ), - color = { 0.6, 0.6, 0.6, 0.8 }, - callback = function() return scene.mainmenu() end }, - - button{ - option = 'plName', - text = lg.newText( font, strings.option_name ), - color = { 0.6, 0.6, 0.6, 0.8 }, - callback = editSelectedOption }, - - button{ - option = 'plPronoun', - text = lg.newText( font, strings.option_pron ), - color = { 0.6, 0.6, 0.6, 0.8 }, - callback = editSelectedOption }, - - button{ - option = 'plColour', - text = lg.newText( font, strings.option_tint ), - color = { 0.6, 0.6, 0.6, 0.8 }, - callback = editSelectedOption }, - - - button{ - option = 'keybinds', - text = lg.newText( font, strings.option_keybinds ), - color = { 0.6, 0.6, 0.6, 0.8 }, - callback = editSelectedOption, - } - }, - - fg = lg.newMesh{ - { 0, 0, 0, 0, 0.4, 0.1, 0.05, 0.0 }, - { 1, 0, 1, 0, 0.8, 0.3, 0.1, 0.8 }, - { 1, 1, 1, 1, 0.7, 0.4, 0.1, 0.8 }, - { 0, 1, 0, 1, 0.4, 0.1, 0.03, 0.0 }, - }, - - bg = lg.newMesh{ - { 0, 0, 0, 0, 1, 1, 1, 0.01 }, - { 1, 0, 1, 0, 1, 1, 1, 0.1 }, - { 1, 1, 1, 1, 0, 0, 0, 0.1 }, - { 0, 1, 0, 1, 0, 0, 0, 0.01 }, - } - -} - -do - local op = optionsMenu.paint - function optionsMenu:paint() - local selected = self.getSelectedButton() - local optionName = selected and selected.option - self.buttons[1].text:set( optionName and tostring( config[optionName] ) or "") - return op( self ) - end -end - -return optionsMenu \ No newline at end of file diff --git a/src/client/ui/textinput.lua b/src/client/ui/textinput.lua deleted file mode 100644 index 1a76099..0000000 --- a/src/client/ui/textinput.lua +++ /dev/null @@ -1,119 +0,0 @@ -local love = assert( love ) -local lk = assert( love.keyboard ) -local lg = assert( love.graphics ) - -local utf8 = assert( require 'utf8' ) -local string = assert( string ) -local button = assert( require 'client.ui.button' ) - -local _lt -local _lkp -local _lmm -local _lmp -local _callback - - -local textInput = { } -local __mt = { __index = textInput } - -local font = lg.getFont() - --- There is only one active text input widget at a time. --- It takes exclusive control of key input. -local activeWidget - -textInput.width = 200 -textInput.length = 20 -textInput.x = 0 -textInput.y = 0 - -function textInput.new( t ) - t = t or {} - t.str = t.str or "" - t.text = lg.newText( t.font or font, t.str ) - return setmetatable( t, __mt ) -end - -function textInput.keypressed(key, code, isRepeat) - if activeWidget and textInput[code] then textInput[code]() end - if _lkp then return _lkp() end -end - -function textInput:clear() - self.str = "" - self.text:set( self.str ) -end - -function textInput:contains(x, y) - local mx, my, Mx, My = self.x, self.y, self.x + self.width, self.y + font:getHeight() - return (x < Mx and x > mx and y > my and y < My) -end - -function textInput:draw() - local w = self.text:getWidth() - local h = (self.font or font):getHeight() - lg.setColor( 1, 1, 1, 0.5 ) - if w > 1 then lg.rectangle( "fill", self.x, self.y, math.max( w, 30 ), h, 15, 15 ) end - if self.selected then lg.rectangle( "fill", self.x, self.y, self.width, h, 15, 15 ) end - lg.rectangle( "line", self.x - 3, self.y - 3, self.width + 6, h + 6, 15, 15 ) - lg.setColor( 0, 0, 0, 1 ) - lg.draw( self.text, self.x or 0, self.y or 0) -end - -function textInput:getText() - return self.str -end - -function textInput.textInput( s ) - activeWidget.str = activeWidget.str..s - activeWidget.text:set( activeWidget.str ) - if _lkp then return _lkp() end -end - -function textInput.backspace( ) - local str = activeWidget.str - local byteoffset = utf8.offset(str, -1) - if byteoffset then str = string.sub(str, 1, byteoffset - 1) - else return end - activeWidget.str = str - activeWidget.text:set( activeWidget.str ) -end - -function textInput:enterText( callback ) - _lt = love.textinput - _lkp = love.keypressed - _lmm = love.mousemoved - _lmp = love.mousepressed - _callback = assert( callback ) - love.textinput = textInput.textInput - love.keypressed = textInput.keypressed - love.mousepressed = nil - love.mousemoved = nil - self.oldStr = self.str - self.str = "" - self.text:set( self.str ) - activeWidget = self -end - -local function disable() - activeWidget = nil - love.textinput = _lt - love.keypressed = _lkp - love.mousemoved = _lmm - love.mousepressed = _lmp -end - -function textInput.escape() - activeWidget.str = activeWidget.oldStr or "" - activeWidget.text:set( activeWidget.str ) - disable() - return _callback() -end - -textInput["return"] = function() --unusual decl because return is a keyword - local str = activeWidget.str - disable() - return _callback( str ) -end - -return textInput \ No newline at end of file diff --git a/src/main.lua b/src/main.lua new file mode 100644 index 0000000..423181a --- /dev/null +++ b/src/main.lua @@ -0,0 +1 @@ +if love then require( "client.main" ) else require( "server.main" ) end \ No newline at end of file diff --git a/src/server/client.lua b/src/server/client.lua deleted file mode 100644 index ede7514..0000000 --- a/src/server/client.lua +++ /dev/null @@ -1,23 +0,0 @@ -local clients = {} -local client = {} -client.__index = client - -function client.new() - local c = setmetatable( {}, client ) - clients[ c.id ] = c - return c -end - -function client:disconnect() - clients[self.id] = nil -end - -function client:assignRole( role ) - self.role = role -end - -function client.connect( ip, port ) - -end - -return client \ No newline at end of file diff --git a/src/server/conf.lua b/src/server/conf.lua deleted file mode 100644 index c69eda2..0000000 --- a/src/server/conf.lua +++ /dev/null @@ -1,51 +0,0 @@ -function love.conf(t) - t.identity = "vision-server" -- The name of the save directory (string) - t.appendidentity = false -- Search files in source directory before save directory (boolean) - t.version = "11.4" -- The Lร–VE version this game was made for (string) - t.console = true -- Attach a console (boolean, Windows only) - t.accelerometerjoystick = true -- Enable the accelerometer on iOS and Android by exposing it as a Joystick (boolean) - t.externalstorage = false -- True to save files (and read from the save directory) in external storage on Android (boolean) - t.gammacorrect = false -- Enable gamma-correct rendering, when supported by the system (boolean) - - t.audio.mic = false -- Request and use microphone capabilities in Android (boolean) - t.audio.mixwithsystem = true -- Keep background music playing when opening LOVE (boolean, iOS and Android only) - - t.window.title = "vision-server" -- The window title (string) - t.window.icon = false -- Filepath to an image to use as the window's icon (string) - t.window.width = 800 -- The window width (number) - t.window.height = 600 -- The window height (number) - t.window.borderless = false -- Remove all border visuals from the window (boolean) - t.window.resizable = true -- Let the window be user-resizable (boolean) - t.window.minwidth = 400 -- Minimum window width if the window is resizable (number) - t.window.minheight = 400 -- Minimum window height if the window is resizable (number) - t.window.fullscreen = false -- Enable fullscreen (boolean) - t.window.fullscreentype = "desktop" -- Choose between "desktop" fullscreen or "exclusive" fullscreen mode (string) - t.window.vsync = 1 -- Vertical sync mode (number) - t.window.msaa = 3 -- The number of samples to use with multi-sampled antialiasing (number) - t.window.depth = nil -- The number of bits per sample in the depth buffer - t.window.stencil = nil -- The number of bits per sample in the stencil buffer - t.window.display = 1 -- Index of the monitor to show the window in (number) - t.window.highdpi = false -- Enable high-dpi mode for the window on a Retina display (boolean) - t.window.usedpiscale = true -- Enable automatic DPI scaling when highdpi is set to true as well (boolean) - t.window.x = nil -- The x-coordinate of the window's position in the specified display (number) - t.window.y = nil -- The y-coordinate of the window's position in the specified display (number) - - t.modules.audio = true -- Enable the audio module (boolean) - t.modules.data = true -- Enable the data module (boolean) - t.modules.event = true -- Enable the event module (boolean) - t.modules.font = true -- Enable the font module (boolean) - t.modules.graphics = true -- Enable the graphics module (boolean) - t.modules.image = true -- Enable the image module (boolean) - t.modules.joystick = false -- Enable the joystick module (boolean) - t.modules.keyboard = true -- Enable the keyboard module (boolean) - t.modules.math = true -- Enable the math module (boolean) - t.modules.mouse = true -- Enable the mouse module (boolean) - t.modules.physics = true -- Enable the physics module (boolean) - t.modules.sound = true -- Enable the sound module (boolean) - t.modules.system = true -- Enable the system module (boolean) - t.modules.thread = true -- Enable the thread module (boolean) - t.modules.timer = true -- Enable the timer module (boolean), Disabling it will result 0 delta time in love.update - t.modules.touch = false -- Enable the touch module (boolean) - t.modules.video = false -- Enable the video module (boolean) - t.modules.window = false -- Enable the window module (boolean) -end \ No newline at end of file diff --git a/src/server/main.lua b/src/server/main.lua deleted file mode 100644 index 4f3f4be..0000000 --- a/src/server/main.lua +++ /dev/null @@ -1,212 +0,0 @@ -package.cpath = "..\\?.dll;..\\clib\\?.dll;"..package.cpath -package.path = "..\\?.lua;..\\lualib\\?.lua;"..package.path -local shared = assert( require 'shared.shared' ) -local packet = shared.packet -local socket = assert( require 'socket' ) -local mscxn = assert( socket.udp() ) -mscxn:settimeout( 0 ) -assert( mscxn:setpeername( shared.metaserver.ip, shared.metaserver.port ), "Could not connect to metaserver!" ) -local udp -local io = assert( io ) - -local CLIENTTIMEOUT = 10 - -local svInfo = packet.serverInfo{ version = 13, - players = 0, - capacity = 255, - ip = shared.ip.fromString( socket.dns.toip(socket.dns.gethostname()) ), - port = 51312, - svname = "New Server", - map = "Test Map" -} - -local clients = {} -local connecting = {} -local server = { tick = 0, time = 0, currentClient = false } - -local handlers = setmetatable({ - - --This is the start of a packet from a connected client. - connected = function( msg, ip, port ) - local client = clients[msg.token] - if not client or - (client.ip ~= ip) or - (client.port ~= port) - then - print( "Invalid token from IP:", msg.token, ip, port ) - return true - end - - if client.tick > msg.tick then - print( "Old packet received:", msg.tick, ip ) - return true - end - - client.tick = msg.tick - client.time = server.time - server.currentClient = client - end, - - --A client wants to disconnect. - disconnect = function( msg, ip, port ) - --This is the authenticated client whose packets are being processed. - local client = server.currentClient - if client and client.ip == ip and client.port == port then - print( "Client disconnecting:", client.id) - clients[ client.id ] = nil - server.currentClient = false - return true - end - end, - - --Client responds to handshake challenge. - clChimo = function( clChimo, ip, port ) - - print( "Received handshake response." ) - - --No active challenge, don't send anything. - local key = ip..":"..port - if not connecting[ key ] then - print( "Old connection attempt from:", key ) - return true - end - - --Compute session token. - local remoteHash = clChimo.hash - local clNonce = clChimo.nonce - local svNonce = connecting[key].nonce - local token = shared.hash.hash( clNonce, svNonce ) - if token ~= remoteHash then - print( "Hashes differ:", shared.hash.hex( clNonce ), shared.hash.hex( svNonce ) ) - return true - end - - --Hash collision. - while clients[token] do token = token + 1 end - - --Successful handshake. - print( "Client connected:", token, port, ip ) - clients[ token ] = connecting[ key ] - clients[ token ].id = token - clients[ token ].time = socket.gettime() - packet.connected{ token = token, tick = server.tick } - return udp:sendto( packet.get(), ip, port ) - end, - - --Metaserver replying with real IP address. - advertised = function( ack, ip, port ) - if ip ~= shared.metaserver.ip then return print( "Advertisement acked from rogue address:", ip, port ) end - if udp:getsockname() then - --assert( udp:getsockname() == tostring( ack.ip ), print( tostring( ack.ip ), udp:getsockname()) or "IP mismatch!" ) - return print( "Advertised. Address already set." ) - end - print( "Advertised. Setting address:", ack.ip, ack.port ) - server.SetIP( tostring( ack.ip ), ack.port ) - end, - - --New client seeks to connect. Challenge immediately. - clientInfo = function( clientInfo, ip, port ) - local key = ip..":"..port - connecting[key] = connecting[key] or { ip = ip, port = port, tick = 0 } - local client = connecting[key] - local nonce = shared.hash.rand() - client.nonce = nonce - print( "Received connection request from:", ip, port ) - print( "Sending authentication nonce:", nonce ) - packet.svChimo{ nonce = nonce } - return udp:sendto( packet.get(), ip, port ) - end, - - - }, {__index = function() return print end }) - -function server.Advertise() - print( "Advertise." ) - packet.get() - packet.metaServer() - packet.serverInfo( svInfo ) - mscxn:send( packet.get() ) -end - -function server.serverInfo( serverInfo ) - print( packet.getString( serverInfo.svname ) ) -end - -function server.metaServer( ms ) - server.advertising = true -end - ---Incoming packet. -function server.Parse( msg, ip, port ) - if (not msg) or (#msg < 1) then return end - local msgs, types = packet.deserialise( msg ) - if msgs then - for i = 1, #msgs do - if handlers[ types[i] ]( msgs[i], ip, port ) then break end - end - server.currentClient = false - else print( types ) - end - return server.Parse( udp:receivefrom() ) -- Process other packets. -end - -function server.SetIP( ipString, port ) - svInfo.ip = shared.ip.fromString( ipString ) - svInfo.port = port - local ok, err = udp:setsockname( ipString, port ) - if ok then - print( "Server IP:", udp:getsockname() ) - return true - --Find another port. - elseif port < 65536 then - print( "Could not use port:", ipString, port, err ) - return server.SetIP( ipString, port + 1 ) - else - print( "Could not use IP:", ipString, err ) - return error( "Connection failed." ) - end -end - - -function server.Start() - udp = assert( socket.udp() ) - udp:settimeout(0) -end - -function server.Advance() - server.tick = server.tick + 1 - for id, client in pairs( clients ) do - packet.get() - packet.connected{ token = id, tick = server.tick } - udp:sendto( packet.get(), client.ip, client.port ) - - if server.time - client.time > CLIENTTIMEOUT then - print( "dropping client:", id ) - clients[id] = nil - end - end -end - -function server.NewGame() - server.tick = 0 -end - -function server.Quit() - -end - -server.Start() -function love.update( dt ) - server.time = server.time + dt - server.Parse( udp:receivefrom() ) - if server.time > 0.1 then - if (server.tick % 50) == 0 then - server.Advertise() - server.Parse( mscxn:receive(), shared.metaserver.ip, shared.metaserver.port ) - end - server.time = 0 - server.Advance() - end -end - -function love.draw() end \ No newline at end of file diff --git a/src/shared/getip.lua b/src/shared/getip.lua deleted file mode 100644 index 664bf2e..0000000 --- a/src/shared/getip.lua +++ /dev/null @@ -1,3 +0,0 @@ -local dns = assert( require 'socket' ).dns ---Get your own local IP address via DNS. -return dns.toip( dns.gethostname() ) \ No newline at end of file diff --git a/src/shared/hash.lua b/src/shared/hash.lua deleted file mode 100644 index a827bc0..0000000 --- a/src/shared/hash.lua +++ /dev/null @@ -1,11 +0,0 @@ -local math = math -local bit = assert( require 'bit' ) -local max = 65536 -math.randomseed( 4 ) ---hash of a pair of 32-bit numbers -return { - hash = bit.bxor, - hex = bit.tohex, - rand = function() - return math.random( 1, max ) - end, } \ No newline at end of file diff --git a/src/shared/ipstring.lua b/src/shared/ipstring.lua deleted file mode 100644 index 96654cb..0000000 --- a/src/shared/ipstring.lua +++ /dev/null @@ -1,23 +0,0 @@ ---CData structure that can hold the longest string representation of an IPv6 address ---we do this because LuaSocket expects a Lua string, and because we can't guarantee v4-only addresses -local ffi = assert( require 'ffi' ) -local ipString = {} -local string = assert( string ) -ffi.cdef[[ - typedef struct { - char ip[40]; - } ipAddress; -]] - -local ipAddress = ffi.typeof( ffi.new( "ipAddress" ) ) -ffi.metatype( ipAddress, { __tostring = function( ip ) return ffi.string( ip.ip, ffi.sizeof( ip.ip ) ) end } ) - -function ipString.new( t ) - local ip = ffi.new( ipAddress ) - ip.ip = t - return ip -end - -ipString.fromString = ipString.new - -return ipString \ No newline at end of file diff --git a/src/shared/metaserver.lua b/src/shared/metaserver.lua deleted file mode 100644 index 3dd3299..0000000 --- a/src/shared/metaserver.lua +++ /dev/null @@ -1,3 +0,0 @@ -local ms = { ip = '192.168.2.15', port = 42069 } -print( "Metaserver public address:", ms.ip, ms.port ) -return ms \ No newline at end of file diff --git a/src/shared/packet.lua b/src/shared/packet.lua deleted file mode 100644 index 1ab2e49..0000000 --- a/src/shared/packet.lua +++ /dev/null @@ -1,216 +0,0 @@ -local ffi = assert( require 'ffi' ) -local buffer = assert( require( "string.buffer" ) ) -local ipString = assert( require 'shared.ipstring' ) -local roles = assert( require 'shared.roles' ) -local packet = {} -local mt = { __index = { new = function( self ) return ffi.new( self.ct ) end } } - -local headerByte = 0x41 --Ensure printable characters at start of packets. - -local function newStruct( t ) - assert( not( packet[ t.name ] )) - packet[ t.name ] = t - t.netname = headerByte - packet[ headerByte ] = t - headerByte = headerByte + 1 - 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 ) ) -end - -newStruct{ - name = "serverInfo", - "uint8_t players", - "uint8_t capacity", - "ipAddress ip", - "uint16_t version", - "uint16_t port", - "char svname[32]", - "char map[32]", -} - -newStruct{ - name = "clientInfo", - "char username[31]", -} - -newStruct{ - name = "svChimo", - "uint32_t nonce", -} - -newStruct{ - name = "clChimo", - "uint32_t nonce", - "uint32_t hash", -} - -newStruct{ - name = "connected", - "uint32_t token", - "uint32_t tick", -} - -newStruct{ - name = "metaServer", - "char padding[300]" --Just a bunch of padding to mitigate amplification. -} - -newStruct{ - name = "insect", - "uint8_t id", - "bool dead", - "int16_t z", - "int8_t hp", - "int8_t vx", - "int8_t vy", - "int8_t vz", - "int32_t x", - "int32_t y", -} - -newStruct{ - name = "soleil", - "uint16_t azimuth", - "uint16_t altitude", - "int8_t vazi", - "int8_t valt", -} - -newStruct{ - name = "playerInfo", - "uint8_t id", - "role_t role", - "char username[31]", -} - -newStruct{ - name = "chatMessage", - "uint8_t id", - "char cmsg[127]", -} - -newStruct{ - name = "command", - "char command", -} - -newStruct{ - name = "advertised", - "uint32_t time", - "ipAddress ip", - "uint16_t port", -} - -newStruct{ - name = "disconnect", - "char reason", -} - -newStruct{ - name = "debugLatency", - "uint32_t lastTick", -} - -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 - return nil, "Malformed packet. Unknown header:\n"..readBuffer:get() - end - if #readBuffer < t.size then - return nil, "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 - ---Slow! -function packet.luaString( member ) - local s = packet.getString( member ) - return s:sub( 1, ( s:find( "\0" ) or s:len() ) - 1 ) -end - -local writeBuffer = buffer.new( 1024 ) -function packet.add( struct, data ) - local str = ffi.new( struct.ct, data or 0 ) - str.netname = assert( struct.netname ) - writeBuffer:putcdata( str, struct.size ) - return str -end - -function packet.get() - return writeBuffer:get() -end - -mt.__call = packet.add - -local testing = testing ---TESTS-- -if testing then - - packet.serverInfo{ - players = 0, - capacity = 255, - map = "abcdefghijklmnopqrstuvwxyz1234567890", - svname = "๐Ÿ˜˜๐Ÿ˜˜๐Ÿ˜˜๐Ÿ˜˜๐Ÿ˜˜๐Ÿ˜˜๐Ÿ˜˜kissyfaceserver", - version = 25, - port = 51312, - ip = ipString.new '132.145.25.62' - } - - 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 \ No newline at end of file diff --git a/src/shared/print.lua b/src/shared/print.lua deleted file mode 100644 index 327f0dc..0000000 --- a/src/shared/print.lua +++ /dev/null @@ -1,15 +0,0 @@ -local _print = print -local lfs = assert( love.filesystem ) -local log = assert( lfs.newFile( ("log_%04d.txt"):format( os.time() % 1000 ))) -assert( log:open 'a', "Could not open log file!" ) -return function( ... ) - - log:write( os.date("!%M%S") ) - for i, v in ipairs{...} do - log:write("\t") - log:write(tostring(v)) - end - log:write("\n") - - return _print( ... ) -end \ No newline at end of file diff --git a/src/shared/roles.lua b/src/shared/roles.lua deleted file mode 100644 index 41f595f..0000000 --- a/src/shared/roles.lua +++ /dev/null @@ -1,9 +0,0 @@ -local ffi = require 'ffi' -ffi.cdef[[ -typedef enum { - roleSpectator = 0, - roleSoleil = 1, - roleInsect = 2, - } role_t; -]] -return ffi.typeof( ffi.new 'role_t' ) \ No newline at end of file diff --git a/src/shared/shared.lua b/src/shared/shared.lua deleted file mode 100644 index 6eec1c1..0000000 --- a/src/shared/shared.lua +++ /dev/null @@ -1,48 +0,0 @@ -print( "Loading Shared." ) -local shared = {} - ---[[do - local rq = require - require = function( ... ) - print( "Require:", ... ) - return rq( ... ) - end -end]] -shared.hash = assert( require 'shared.hash' ) -shared.ip = assert( require 'shared.ipstring' ) -shared.packet = assert( require 'shared.packet' ) -shared.print = assert( require 'shared.print' ) -shared.metaserver = assert( require 'shared.metaserver' ) -shared.myip = assert( require 'shared.getip' ) - ---Turn on logging? -print = shared.print -print( "My IP: ", shared.myip ) - ---World state. -local world = {} -function world:Advance() - -end - -function world:Reset() - -end - -function world:Load( map ) - -end - -function world:AddPlayer( playerID, x, y, stage ) - -end - -function world:RemovePlayer( playerID ) - -end - -function shared.NewWorld() - return setmetatable( {}, {__index = world } ) -end - -return shared \ No newline at end of file