From ddaf61c52c661f191217f76e039cda03d84a1f8e Mon Sep 17 00:00:00 2001 From: wan-may Date: Sun, 26 Oct 2025 22:12:53 -0300 Subject: [PATCH] starting over --- src/client/assets/glsl/crepuscular | 21 -- src/client/client/assets/client-icon.png | Bin 25019 -> 0 bytes src/client/config.lua | 68 ------- src/client/connecting.lua | 90 --------- src/client/crepuscular.lua | 23 --- src/client/game.lua | 91 --------- src/client/main.lua | 7 +- src/client/renderer/main.lua | 47 ----- src/client/scene.lua | 47 ----- src/client/strings.lua | 3 - src/client/test/browser.lua | 39 ---- src/client/udp.lua | 82 -------- src/client/ui/browser.lua | 247 ----------------------- src/client/ui/button.lua | 58 ------ src/client/ui/fonts.lua | 9 - src/client/ui/mainmenu.lua | 54 ----- src/client/ui/menu.lua | 153 -------------- src/client/ui/options.lua | 84 -------- src/client/ui/textinput.lua | 119 ----------- src/main.lua | 1 + src/server/client.lua | 23 --- src/server/conf.lua | 51 ----- src/server/main.lua | 212 ------------------- src/shared/getip.lua | 3 - src/shared/hash.lua | 11 - src/shared/ipstring.lua | 23 --- src/shared/metaserver.lua | 3 - src/shared/packet.lua | 216 -------------------- src/shared/print.lua | 15 -- src/shared/roles.lua | 9 - src/shared/shared.lua | 48 ----- 31 files changed, 4 insertions(+), 1853 deletions(-) delete mode 100644 src/client/assets/glsl/crepuscular delete mode 100644 src/client/client/assets/client-icon.png delete mode 100644 src/client/config.lua delete mode 100644 src/client/connecting.lua delete mode 100644 src/client/crepuscular.lua delete mode 100644 src/client/game.lua delete mode 100644 src/client/renderer/main.lua delete mode 100644 src/client/scene.lua delete mode 100644 src/client/strings.lua delete mode 100644 src/client/test/browser.lua delete mode 100644 src/client/udp.lua delete mode 100644 src/client/ui/browser.lua delete mode 100644 src/client/ui/button.lua delete mode 100644 src/client/ui/fonts.lua delete mode 100644 src/client/ui/mainmenu.lua delete mode 100644 src/client/ui/menu.lua delete mode 100644 src/client/ui/options.lua delete mode 100644 src/client/ui/textinput.lua create mode 100644 src/main.lua delete mode 100644 src/server/client.lua delete mode 100644 src/server/conf.lua delete mode 100644 src/server/main.lua delete mode 100644 src/shared/getip.lua delete mode 100644 src/shared/hash.lua delete mode 100644 src/shared/ipstring.lua delete mode 100644 src/shared/metaserver.lua delete mode 100644 src/shared/packet.lua delete mode 100644 src/shared/print.lua delete mode 100644 src/shared/roles.lua delete mode 100644 src/shared/shared.lua 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 0329af96abe4fd232268576059acee1250de77cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25019 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�$El`g@tSwGwnn0nE40x$%B03JnTt|ZMWeK?-AbN=!peNucyMr_ zCKCAs>df?;cqDCwPlP(n!nGNzehOTzT+`7F&^H?!--*X1e6hre75_F(yUcbPb|UKJ16uG_fu)VUD8;QL zp`;)BpLxIzz5ijN|7bsuU&1%%L0TR|_xOA?x_e~giXIx`Fq!QX9*jRNa z*bJbc+Zo|7XM?3Y27%@pWNhep$YqNmYBUPxpvGxR7C>Z_tbHGM>fttv)m+J1YHwVJ zQ~g;`jEvwwQzJJu#MDJ@Y{sw>pw#d4y==!f+e5Ko~6BC3qzj zxd;}AKs?ZOi#9J;%MNmmUIdj$FB#wLL)^p{?{4$y;jkC){*qE%naqxX{?n6_qvPW< z!C;+YO&bD@(cYd|Bzl26QSbtt#}XSw(9Ldj$C{sx6QHm(d%1RqmEn50D>ZMs1*fZe z6t~VI5!nUSIx@t_j(?#6k`dOsMP%#No$8a4l1?3$o!#Fci9E7UXbz&?d?Z&y^r68&&mZYYpS-sJ)i$lf4?gnCgV>F znO;8@jjn{Y%Dj_ual`g{(RLy(lm{!a3d5bf-l~Elrg`MoI{2StzAX0+*;bb6bCvh~ z8zuf;Uw^XbQ_?Y}MpYKiGxTX}bnYEgnU^~}jq*Li=2%1+9T;OvuY!4a5&Q4J1>*C^9hHr1%OZtd=}JB~mvA++2%%neb#qQ`7!rvKCum zyuIB>CZiaA+c<}vRM7}LhO4l{6};%an~{C2bu<9Z6YY^4f2Ar@0UZS7YHX zhITu!h4;bmR`%kvf|}MLOMi~xaTmA~tV&hxE(*@(79n;@afN7%&+E3VZYf3-d6b;k ziVE4ORC^{9LPqRSDX&UF%qJ5!iM04wGl;PW6Um#y1kXVfNaCarOXNkIdl730O4@Dm z5y*#(K*-xJN#!@b5-dH zSR*-@?nC-CiIRv`$y(w8QTb~Nod3hb7vol&G%r3*|*C5q52dBqrrVgiHBFO&cv-k*dWgHHW%=UK8+)2ddwX1`vaC4QY?A9 zfO9uKsD{(800>g4zc2DhIj5e%0)WRkwaGALr}9HECoUbQs}0YbmZCd*r~0Yp5#FGi3QPfK7Gqv_qfB8Egk0MJh1&{R zIg?Cwqq!T`jF5w>F*qE{7tUt0geMR8_nwMIK2n?l3m{7ovn;zNt_J4U!qcWon(eH> z6bII?mr{Y4rph`f+St`8ahF>zgEya%}dG2E7Az19-`Kxs*nrJ}wp zvVZ~jV#{=8P-61~{NbvU_jYy?zSA0~XV@hrQPuO=Y=3=2O(8F1u{f)>vbW@h_e4*) zu48pBkwEf*0o^t#v{5=)Dw*A}G{r7e6rV9{x55gLg z%RKr-0X9l51F%~K*=^F(@HS1gytkIHb{rKT#+6RbVO;vi3QB%`BHZ6jr8-fT+TisP zHtbQVj~-Pi&altT5)idX$ql8QKvSG++&QA&fLFLC)QsR09|I`w)yjO40IGn=#rYqR W|F&OPD~g{00000 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