local lg = assert( love.graphics ) 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 menu = assert( require 'client.ui.menu' ) local strings = assert( require 'client.strings' ) local fonts = assert( require 'client.ui.fonts' ) local metaserver = assert ( require 'client.udp' ) local utf8 = assert( require 'utf8' ) local browser = { latest = 0, } local test = assert( require 'client.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 ) 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() 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, heartbeat = serverList.clear, 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. 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 ) print( "Joining server:", ip, port ) return scene.loadScene( scene.connecting, { ip = ip, port = port } ) 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