diff --git a/src/client/assets/strings/english.lua b/src/client/assets/strings/english.lua index dc6ef64..ae0f0b0 100644 --- a/src/client/assets/strings/english.lua +++ b/src/client/assets/strings/english.lua @@ -8,4 +8,13 @@ return setmetatable({ ["option_pron"] = "Player Pronouns", ["option_tint"] = "Player Colour", ["option_keybinds"] = "Edit Keybindings", + ["utf8_error"] = "??? what is this", + ["server_browser"] = "Server Browser", + ["ip_button"] = "Enter IP:", + ["svinfo_name"] = "Server Name", + ["svinfo_map"] = "Current Map", + ["svinfo_players"] = "In", + ["svinfo_capacity"] = "Max", + ["svinfo_ip"] = "IP", + ["svinfo_port"] = "Port", }, {__index = function( t, k ) return k end } ) \ No newline at end of file diff --git a/src/client/assets/strings/strings.lua b/src/client/assets/strings/strings.lua new file mode 100644 index 0000000..423a930 --- /dev/null +++ b/src/client/assets/strings/strings.lua @@ -0,0 +1,3 @@ +--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/connecting.lua b/src/client/connecting.lua index b58a741..e7b2ceb 100644 --- a/src/client/connecting.lua +++ b/src/client/connecting.lua @@ -3,13 +3,18 @@ local lg = assert( love.graphics ) local server = assert( require 'client.udp' ) local connecting = {} -local time, ip, port = 0 +local time, ip, port function connecting.draw() + lg.setColor( 1,1,1,1 ) lg.print( ("CONNECTING:\nTIME: %1.1fs\nADDRESS: %s:%d"):format(time, ip, port), 0, 0, 0 ) return false end +function connecting.keypressed(key, code, isrepeat) + if code == "escape" then return scene.browser() end +end + function connecting.update(dt) time = time + dt @@ -20,6 +25,8 @@ function connecting.update(dt) end function connecting:onLoad( params ) + lg.setCanvas() + time = 0 print( "connecting:", params, self.ip, self.port ) for k, v in pairs( self ) do print( k,v ) end params = params or { ip = "8.8.8.8", port = 8 } diff --git a/src/client/test/browser.lua b/src/client/test/browser.lua new file mode 100644 index 0000000..0dd317b --- /dev/null +++ b/src/client/test/browser.lua @@ -0,0 +1,39 @@ +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( 0, 64 ) do t[i] = r( 30, 1234 ) 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, 128 ) do randserver() end + return packet.deserialise( packet.get() ) + end +} \ No newline at end of file diff --git a/src/client/ui/browser.lua b/src/client/ui/browser.lua index 3a93df6..6787398 100644 --- a/src/client/ui/browser.lua +++ b/src/client/ui/browser.lua @@ -3,112 +3,84 @@ local scene = assert( require 'client.scene' ) local textInput = assert( require 'client.ui.textinput' ) local button = assert( require 'client.ui.button' ) local packet = assert( require 'shared.packet' ) -local ipString = assert( require 'shared.ipstring' ) local menu = assert( require 'client.ui.menu' ) +local strings = assert( require 'client.assets.strings.strings' ) +local utf8 = assert( require 'utf8' ) +local gs = function( d ) + local s = packet.getString( d ) + local valid, trip = utf8.len( s ) + return valid and s or --Regurgitate name. + ( trip > 1 ) and s:sub( 1, trip - 1 ) or --Attempt truncation to initial valid utf8 sequence. + strings.utf8_error --Return fallback string indicating garbled mess. +end local browser = {} -local font = lg.newFont( "client/assets/fonts/Montserrat-Bold.ttf", 20 ) +local test = assert( require 'client.test.browser' ) + +local font = lg.newFont( "client/assets/fonts/Montserrat-Bold.ttf", 12 ) +local headerFont = lg.newFont( "client/assets/fonts/Montserrat-Bold.ttf", 36 ) +local midFont = lg.newFont( "client/assets/fonts/Montserrat-Bold.ttf", 24 ) -local function populateTestServers() - packet.get() - packet.serverInfo{ - players = 24, - capacity = 255, - ip = ipString.new{ 123, 456, 789, 101 }, - port = 51312, - version = 25, - svname = "test server", - map = "testMap_01", - } - packet.serverInfo{ - players = 8, - capacity = 255, - ip = ipString.new{ 123, 456, 789, 101 }, - port = 51312, - version = 25, - svname = "test server", - map = "testMap_02", - } - packet.serverInfo{ - players = 14, - capacity = 64, - ip = ipString.new{ 150, 645, 151, 67 }, - port = 51312, - version = 25, - svname = "test server", - map = "testMap_03", - } - packet.serverInfo{ - players = 24, - capacity = 255, - ip = ipString.new{ 123, 456, 789, 101 }, - port = 51312, - version = 25, - svname = "test server", - map = "testMap_01", - } - return packet.deserialise( packet.get() ) -end local function joinServerCallback( button ) - if button.ip and button.port then return browser.joinIP( button.ip, button.port ) end + if button.ip and button.port then + return browser.joinIP( button.ip, button.port ) + end end -local serverButtons = populateTestServers() -for i, server in ipairs( serverButtons ) do - serverButtons[i] = button{ - ip = tostring( server.ip ), - port = server.port, - text = tostring( server.ip ), - callback = joinServerCallback} -end -local serverList = menu.new( "serverList", - serverButtons, - nil, - nil, - nil, - true ) -serverList.servers = populateTestServers() -serverList.offsets = { - 15, - 50, - 150, - 100, - 100, - 50, - 50 +local serverButtons = test.getTestServers() +do + local cw = font:getWidth( "w" ) + + + local headerText = lg.newText( font ) + headerText:add( strings.svinfo_name, 0 ) + headerText:add( strings.svinfo_map, cw * 16 ) + headerText:add( strings.svinfo_ip, cw * 32 ) + headerText:add( strings.svinfo_port, cw * ( 32 + 12 ) ) + headerText:add( strings.svinfo_players, cw * ( 32 + 12 + 6 ) ) + headerText:add( strings.svinfo_capacity, cw * ( 32 + 12 + 9 ) ) + local headerButton = button{ + space = 15, y = 135, text = headerText } + for i, server in ipairs( serverButtons ) do + local text = lg.newText( font ) + text:add( gs( server.svname ), 0 ) + text:add( gs( 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 ) ) + + serverButtons[i] = button{ space = 0, + ip = tostring( server.ip ), + port = server.port, + text = text, + callback = joinServerCallback, + color = { 0.3 + 0.1 * (i % 2), 0.3 + 0.1 * (i % 2), 0.8, 0.5 }} + end + + table.insert( serverButtons, 1, headerButton ) + +end +local serverList = menu.new{ + name = "serverList", + buttons = serverButtons, + fg = nil, + bg = lg.newMesh{ + { 0, 0, 0, 0, 0.4, 0.05, 0.0, 0.1 }, + { 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.1 }, + }, + + font = font, + subScene = true } serverList.selected = false serverList.x = 25 -serverList.y = 220 +serverList.y = 0 serverList.h = 36 ---[[function serverList.draw() - local gs = packet.getString - local x, y, h = serverList.x, serverList.y, serverList.h - local oldFont = lg.getFont() - lg.setFont( font ) - for i, svInfo in ipairs( serverList.servers ) do - lg.setColor( 0.7, 0.7, 0.7, 0.7 ) - lg.rectangle( "fill", x, y, 800, h, 5, 5 ) - - x = x + 15 - y = y + 9 - lg.setColor( 0, 0, 0, 0.7 ) - lg.print( svInfo.version, x, y ) - lg.print( gs( svInfo.svname ), 50 + x, y ) - lg.print( tostring( svInfo.ip ), 200 + x, y ) - lg.print( svInfo.port, 300 + x, y ) - lg.print( svInfo.players, 400 + x, y ) - lg.print( svInfo.capacity, 450 + x, y ) - lg.print( gs( svInfo.map ), 500 + x, y ) - y = y - 12 - x = x - 15 - y = y + h + 5 - end - lg.setFont( oldFont ) -end]] - function serverList.select() end @@ -124,17 +96,21 @@ end local ti = textInput.new{ width = 300, length = 20, - x = 15, - y = 175 + x = 150, + y = 75, + str = "8.8.8.8:1234" } browser.selected = false function browser.draw() - lg.setColor( 1, 1, 1, 1 ) - lg.print( "Server Browser", 15, 115 ) - ti:draw() serverList.draw() + lg.setColor( 1, 1, 1, 1 ) + lg.setFont( headerFont ) + lg.print( strings.server_browser, 15, 15 ) + lg.setFont( midFont ) + lg.print( strings.ip_button, 15, 85 ) + ti:draw() end function browser.update( dt ) @@ -146,6 +122,14 @@ function browser.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.resize( x, y ) + return serverList.resize( x, y ) +end + function browser.mousepressed(x, y, button, istouch, pressed) if ti:contains( x, y ) then return ti:enterText( browser.joinIPString ) end return serverList.mousepressed( x, y, button, istouch, pressed ) @@ -170,6 +154,7 @@ end function browser.keypressed( key, code, isRepeat ) if code == "escape" then return scene.mainmenu() end if code == "return" then return ti:enterText( browser.joinIPString ) end + return serverList.keypressed( key, code, isRepeat ) end scene.browser = browser diff --git a/src/client/ui/button.lua b/src/client/ui/button.lua index d7b4f5b..5b0ddf9 100644 --- a/src/client/ui/button.lua +++ b/src/client/ui/button.lua @@ -16,12 +16,13 @@ function button:new( t ) 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 "" + 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 @@ -47,9 +48,9 @@ function button:draw( ) end lg.setColor( 0, 0, 0, 0.8 ) - lg.print( self.text, self.x + 15, self.y + 6) + lg.draw( self.text, self.x + 15, self.y + 6) lg.setColor( 0, 0, 0, 0.2 ) - lg.print( self.text, self.x + 18, self.y + 8) + lg.draw( self.text, self.x + 18, self.y + 8) end return setmetatable( button, { __call = button.new } ) \ No newline at end of file diff --git a/src/client/ui/mainmenu.lua b/src/client/ui/mainmenu.lua index 62e793b..ac40751 100644 --- a/src/client/ui/mainmenu.lua +++ b/src/client/ui/mainmenu.lua @@ -5,47 +5,49 @@ local strings = strings or assert( require 'client.assets.strings.english' ) local button = assert( require 'client.ui.button' ) local menu = assert( require 'client.ui.menu' ) -return menu.new( - "mainmenu", +local font = lg.newFont( "client/assets/fonts/Montserrat-Bold.ttf", 48 ) + +return menu.new{ + name = "mainmenu", + + buttons = { - { - button{ - x = 15, w = lg.getWidth(), y = 115, h = 72, - text = strings.newgame_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 = strings.join_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 = strings.option_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 = strings.quit_button, + text = lg.newText( font, strings.quit_button ), color = { 0.6, 0.6, 0.6, 0.9 }, callback = love.event.quit }, }, - lg.newMesh{ + 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 }, }, - lg.newMesh{ + bg = lg.newMesh{ { 0, 0, 0, 0, 0.4, 0.05, 0.0, 0.1 }, { 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.1 }, }, - - lg.newFont( "client/assets/fonts/Montserrat-Bold.ttf", 48 ) - ) \ No newline at end of file + + font = lg.newFont( "client/assets/fonts/Montserrat-Bold.ttf", 48 ) +} \ No newline at end of file diff --git a/src/client/ui/menu.lua b/src/client/ui/menu.lua index 01c29fd..1aa68a7 100644 --- a/src/client/ui/menu.lua +++ b/src/client/ui/menu.lua @@ -10,11 +10,14 @@ local canvas local wWidth, wHeight local currentMenu -function menu.new( name, buttons, fg, bg, font, subScene ) - local t = { buttons = buttons, fg = fg, bg = bg, font = font or lg.getFont() } - if subScene then setmetatable( t, t ) +function menu.getSelectedButton() + return currentMenu.buttons[selectedButtonIdx] +end + +function menu.new( t ) + if t.subScene then setmetatable( t, t ) else - scene[name] = t + scene[t.name] = t print( 'scene', scene ) end getmetatable( t ).__index = menu diff --git a/src/client/ui/options.lua b/src/client/ui/options.lua index 2f83b31..091fcfd 100644 --- a/src/client/ui/options.lua +++ b/src/client/ui/options.lua @@ -5,45 +5,47 @@ local strings = strings or assert( require 'client.assets.strings.english' ) local button = assert( require 'client.ui.button' ) local menu = assert( require 'client.ui.menu' ) -return menu.new( - "options", +local font = lg.newFont( "client/assets/fonts/Montserrat-Bold.ttf", 18 ) - { +return menu.new{ + name = "options", + + buttons = { button{ - x = 15, y = 115, w = 800, h = 30, - text = strings.mainmenu_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 = 'name', - text = strings.option_name, + text = lg.newText( font, strings.option_name ), color = { 0.6, 0.6, 0.6, 0.8 }, callback = menu.textOption }, button{ option = 'pronoun', - text = strings.option_pron, + text = lg.newText( font, strings.option_pron ), color = { 0.6, 0.6, 0.6, 0.8 }, callback = menu.textOption }, button{ option = 'colour', - text = strings.option_tint, + text = lg.newText( font, strings.option_tint ), color = { 0.6, 0.6, 0.6, 0.8 }, callback = menu.colourOption }, button{ option = 'keybinds', - text = strings.option_keybinds, + text = lg.newText( font, strings.option_keybinds ), color = { 0.6, 0.6, 0.6, 0.8 }, callback = menu.editKeybinds, } }, - lg.newMesh{ + 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 }, @@ -51,12 +53,11 @@ return menu.new( }, - lg.newMesh{ + 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 }, - }, + } - lg.newFont( "client/assets/fonts/Montserrat-Bold.ttf", 18 ) -) \ No newline at end of file +} \ No newline at end of file diff --git a/src/client/ui/textinput.lua b/src/client/ui/textinput.lua index 6d25ea2..c3bf71a 100644 --- a/src/client/ui/textinput.lua +++ b/src/client/ui/textinput.lua @@ -28,8 +28,8 @@ textInput.y = 0 function textInput.new( t ) t = t or {} - t.text = lg.newText( font, "") - t.str = "" + t.str = t.str or "" + t.text = lg.newText( font, t.str ) return setmetatable( t, __mt ) end diff --git a/src/shared/packet.lua b/src/shared/packet.lua index 408a7aa..76f25af 100644 --- a/src/shared/packet.lua +++ b/src/shared/packet.lua @@ -127,6 +127,12 @@ 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 )