2015-12-28 20:52:31 -05:00
# include "..\..\STDInclude.hpp"
2015-12-27 22:02:30 -05:00
namespace Components
{
2016-01-02 09:19:34 -05:00
bool ServerList : : SortAsc = true ;
int ServerList : : SortKey = ServerList : : Column : : Ping ;
2015-12-28 08:08:46 -05:00
unsigned int ServerList : : CurrentServer = 0 ;
2015-12-27 22:02:30 -05:00
ServerList : : Container ServerList : : RefreshContainer ;
std : : vector < ServerList : : ServerInfo > ServerList : : OnlineList ;
2016-01-02 09:19:34 -05:00
std : : vector < int > ServerList : : VisibleList ;
2015-12-27 22:02:30 -05:00
int ServerList : : GetServerCount ( )
{
2016-01-02 09:19:34 -05:00
return ( int ) ServerList : : VisibleList . size ( ) ;
2015-12-27 22:02:30 -05:00
}
const char * ServerList : : GetServerText ( int index , int column )
{
2016-01-02 09:19:34 -05:00
return ServerList : : GetServerText ( ServerList : : GetServer ( index ) , column ) ;
}
2015-12-27 22:02:30 -05:00
2016-01-02 09:19:34 -05:00
const char * ServerList : : GetServerText ( ServerList : : ServerInfo * server , int column )
{
if ( ! server ) return " " ;
2015-12-27 22:02:30 -05:00
switch ( column )
{
case Column : : Password :
{
2016-01-02 09:19:34 -05:00
return ( server - > Password ? " X " : " " ) ;
2015-12-27 22:02:30 -05:00
}
case Column : : Hostname :
{
2016-01-02 09:19:34 -05:00
return server - > Hostname . data ( ) ;
2015-12-27 22:02:30 -05:00
}
case Column : : Mapname :
{
2016-01-02 09:19:34 -05:00
return Game : : UI_LocalizeMapName ( server - > Mapname . data ( ) ) ;
2015-12-27 22:02:30 -05:00
}
case Column : : Players :
{
2016-01-02 09:19:34 -05:00
return Utils : : VA ( " %i (%i) " , server - > Clients , server - > MaxClients ) ;
2015-12-27 22:02:30 -05:00
}
case Column : : Gametype :
{
2016-01-02 09:19:34 -05:00
if ( server - > Mod ! = " " )
2015-12-27 22:02:30 -05:00
{
2016-01-02 09:19:34 -05:00
return ( server - > Mod . data ( ) + 5 ) ;
2015-12-27 22:02:30 -05:00
}
2016-01-02 09:19:34 -05:00
return Game : : UI_LocalizeGameType ( server - > Gametype . data ( ) ) ;
2015-12-27 22:02:30 -05:00
}
case Column : : Ping :
{
2016-01-02 09:19:34 -05:00
return Utils : : VA ( " %i " , server - > Ping ) ;
2015-12-27 22:02:30 -05:00
}
}
return " " ;
}
void ServerList : : SelectServer ( int index )
{
2015-12-28 08:08:46 -05:00
ServerList : : CurrentServer = ( unsigned int ) index ;
2015-12-27 22:02:30 -05:00
}
void ServerList : : Refresh ( )
{
ServerList : : OnlineList . clear ( ) ;
2016-01-02 09:19:34 -05:00
ServerList : : VisibleList . clear ( ) ;
2015-12-27 22:02:30 -05:00
ServerList : : RefreshContainer . Mutex . lock ( ) ;
ServerList : : RefreshContainer . Servers . clear ( ) ;
ServerList : : RefreshContainer . Mutex . unlock ( ) ;
2015-12-28 09:46:08 -05:00
ServerList : : RefreshContainer . SendCount = 0 ;
ServerList : : RefreshContainer . SentCount = 0 ;
2015-12-28 11:52:13 -05:00
ServerList : : RefreshContainer . AwatingList = true ;
ServerList : : RefreshContainer . AwaitTime = Game : : Com_Milliseconds ( ) ;
2015-12-27 22:02:30 -05:00
int masterPort = Dvar : : Var ( " masterPort " ) . Get < int > ( ) ;
const char * masterServerName = Dvar : : Var ( " masterServerName " ) . Get < const char * > ( ) ;
ServerList : : RefreshContainer . Host = Network : : Address ( Utils : : VA ( " %s:%u " , masterServerName , masterPort ) ) ;
2015-12-28 11:52:13 -05:00
Logger : : Print ( " Sending serverlist request to master: %s:%u \n " , masterServerName , masterPort ) ;
2015-12-29 18:13:12 -05:00
Network : : Send ( ServerList : : RefreshContainer . Host , Utils : : VA ( " getservers IW4 %i full empty " , PROTOCOL ) ) ;
2015-12-28 12:12:36 -05:00
//Network::Send(ServerList::RefreshContainer.Host, "getservers 0 full empty\n");
2015-12-27 22:02:30 -05:00
}
void ServerList : : Insert ( Network : : Address address , Utils : : InfoString info )
{
ServerList : : RefreshContainer . Mutex . lock ( ) ;
for ( auto i = ServerList : : RefreshContainer . Servers . begin ( ) ; i ! = ServerList : : RefreshContainer . Servers . end ( ) ; i + + )
{
// Our desired server
2015-12-28 09:46:08 -05:00
if ( i - > Target = = address & & i - > Sent )
2015-12-27 22:02:30 -05:00
{
// Challenge did not match
if ( i - > Challenge ! = info . Get ( " challenge " ) )
{
// Shall we remove the server from the queue?
// Better not, it might send a second response with the correct challenge.
// This might happen when users refresh twice (or more often) in a short period of time
break ;
}
2016-01-01 11:36:47 -05:00
// Remove server from queue
ServerList : : RefreshContainer . Servers . erase ( i ) ;
2015-12-27 22:02:30 -05:00
ServerInfo server ;
server . Hostname = info . Get ( " hostname " ) ;
server . Mapname = info . Get ( " mapname " ) ;
server . Gametype = info . Get ( " gametype " ) ;
2016-01-01 11:36:47 -05:00
server . Shortversion = info . Get ( " shortversion " ) ;
2015-12-27 22:02:30 -05:00
server . Mod = info . Get ( " fs_game " ) ;
server . MatchType = atoi ( info . Get ( " matchtype " ) . data ( ) ) ;
server . Clients = atoi ( info . Get ( " clients " ) . data ( ) ) ;
server . MaxClients = atoi ( info . Get ( " sv_maxclients " ) . data ( ) ) ;
server . Password = 0 ; // No info yet
server . Ping = ( Game : : Com_Milliseconds ( ) - i - > SendTime ) ;
2015-12-28 08:08:46 -05:00
server . Addr = address ;
2015-12-27 22:02:30 -05:00
2015-12-28 09:46:08 -05:00
// Check if already inserted and remove
2016-01-02 09:19:34 -05:00
int k = 0 ;
for ( auto j = ServerList : : OnlineList . begin ( ) ; j ! = ServerList : : OnlineList . end ( ) ; j + + , k + + )
2015-12-28 09:46:08 -05:00
{
if ( j - > Addr = = address )
{
ServerList : : OnlineList . erase ( j ) ;
break ;
}
}
2016-01-02 09:19:34 -05:00
// Also remove from visible list
for ( auto j = ServerList : : VisibleList . begin ( ) ; j ! = ServerList : : VisibleList . end ( ) ; j + + )
{
if ( * j = = k )
{
ServerList : : VisibleList . erase ( j ) ;
}
}
2016-01-01 11:36:47 -05:00
if ( info . Get ( " gamename " ) = = " IW4 " & & server . MatchType & & server . Shortversion = = VERSION_STR )
2015-12-29 18:13:12 -05:00
{
2016-01-02 09:19:34 -05:00
int index = ServerList : : OnlineList . size ( ) ;
2015-12-29 18:13:12 -05:00
ServerList : : OnlineList . push_back ( server ) ;
2016-01-02 09:19:34 -05:00
ServerList : : VisibleList . push_back ( index ) ;
2016-01-02 09:23:04 -05:00
ServerList : : SortList ( ) ;
2015-12-29 18:13:12 -05:00
}
2015-12-27 22:02:30 -05:00
break ;
}
}
2015-12-28 09:46:08 -05:00
ServerList : : RefreshContainer . Mutex . unlock ( ) ;
}
2016-01-02 09:23:04 -05:00
void ServerList : : SortList ( )
2016-01-02 09:19:34 -05:00
{
qsort ( ServerList : : VisibleList . data ( ) , ServerList : : VisibleList . size ( ) , sizeof ( int ) , [ ] ( const void * first , const void * second )
{
int server1 = * ( int * ) first ;
int server2 = * ( int * ) second ;
ServerInfo * info1 = nullptr ;
ServerInfo * info2 = nullptr ;
if ( ServerList : : OnlineList . size ( ) > ( unsigned int ) server1 ) info1 = & ServerList : : OnlineList [ server1 ] ;
if ( ServerList : : OnlineList . size ( ) > ( unsigned int ) server2 ) info2 = & ServerList : : OnlineList [ server2 ] ;
if ( ! info1 ) return 1 ;
if ( ! info2 ) return - 1 ;
// Numerical comparisons
2016-01-02 09:23:04 -05:00
if ( ServerList : : SortKey = = ServerList : : Column : : Ping )
2016-01-02 09:19:34 -05:00
{
return ( ( info1 - > Ping - info2 - > Ping ) * ( ServerList : : SortAsc ? 1 : - 1 ) ) ;
}
2016-01-02 09:23:04 -05:00
else if ( ServerList : : SortKey = = ServerList : : Column : : Players )
2016-01-02 09:19:34 -05:00
{
return ( ( info1 - > Clients - info2 - > Clients ) * ( ServerList : : SortAsc ? 1 : - 1 ) ) ;
}
2016-01-02 09:23:04 -05:00
std : : string text1 = Colors : : Strip ( ServerList : : GetServerText ( info1 , ServerList : : SortKey ) ) ;
std : : string text2 = Colors : : Strip ( ServerList : : GetServerText ( info2 , ServerList : : SortKey ) ) ;
2016-01-02 09:19:34 -05:00
// ASCII-based comparison
return ( text1 . compare ( text2 ) * ( ServerList : : SortAsc ? 1 : - 1 ) ) ;
} ) ;
}
ServerList : : ServerInfo * ServerList : : GetServer ( int index )
{
if ( ServerList : : VisibleList . size ( ) > ( unsigned int ) index )
{
if ( ServerList : : OnlineList . size ( ) > ( unsigned int ) ServerList : : VisibleList [ index ] )
{
return & ServerList : : OnlineList [ ServerList : : VisibleList [ index ] ] ;
}
}
return nullptr ;
}
2015-12-28 09:46:08 -05:00
void ServerList : : Frame ( )
{
ServerList : : RefreshContainer . Mutex . lock ( ) ;
2015-12-28 11:52:13 -05:00
if ( ServerList : : RefreshContainer . AwatingList )
{
// Check if we haven't got a response within 10 seconds
if ( Game : : Com_Milliseconds ( ) - ServerList : : RefreshContainer . AwaitTime > 5000 )
{
ServerList : : RefreshContainer . AwatingList = false ;
Logger : : Print ( " We haven't received a response from the master within %d seconds! \n " , ( Game : : Com_Milliseconds ( ) - ServerList : : RefreshContainer . AwaitTime ) / 1000 ) ;
}
}
2015-12-28 09:46:08 -05:00
// Send requests to 10 servers each frame
int SendServers = 10 ;
for ( unsigned int i = 0 ; i < ServerList : : RefreshContainer . Servers . size ( ) ; i + + )
{
ServerList : : Container : : ServerContainer * server = & ServerList : : RefreshContainer . Servers [ i ] ;
if ( server - > Sent ) continue ;
// Found server we can send a request to
server - > Sent = true ;
SendServers - - ;
server - > SendTime = Game : : Com_Milliseconds ( ) ;
server - > Challenge = Utils : : VA ( " %d " , server - > SendTime ) ;
ServerList : : RefreshContainer . SentCount + + ;
Network : : Send ( server - > Target , Utils : : VA ( " getinfo %s \n " , server - > Challenge . data ( ) ) ) ;
// Display in the menu, like in COD4
//Logger::Print("Sent %d/%d\n", ServerList::RefreshContainer.SentCount, ServerList::RefreshContainer.SendCount);
2016-01-03 13:28:47 -05:00
Localization : : Set ( " MPUI_SERVERQUERIED " , Utils : : VA ( " Queried: %d/%d " , ServerList : : RefreshContainer . SentCount , ServerList : : RefreshContainer . SendCount ) ) ;
2015-12-28 09:46:08 -05:00
if ( SendServers < = 0 ) break ;
}
2015-12-27 22:02:30 -05:00
ServerList : : RefreshContainer . Mutex . unlock ( ) ;
}
ServerList : : ServerList ( )
{
ServerList : : OnlineList . clear ( ) ;
2016-01-02 09:19:34 -05:00
ServerList : : VisibleList . clear ( ) ;
2015-12-27 22:02:30 -05:00
2016-01-03 13:28:47 -05:00
Localization : : Set ( " MPUI_SERVERQUERIED " , " Queried: 0/0 " ) ;
2015-12-27 22:02:30 -05:00
Network : : Handle ( " getServersResponse " , [ ] ( Network : : Address address , std : : string data )
{
if ( ServerList : : RefreshContainer . Host ! = address ) return ; // Only parse from host we sent to
2015-12-28 11:52:13 -05:00
ServerList : : RefreshContainer . AwatingList = false ;
2015-12-27 22:02:30 -05:00
ServerList : : RefreshContainer . Mutex . lock ( ) ;
2015-12-28 09:46:08 -05:00
int offset = 0 ;
2015-12-28 11:52:13 -05:00
int count = ServerList : : RefreshContainer . Servers . size ( ) ;
2015-12-28 09:46:08 -05:00
ServerList : : MasterEntry * entry = nullptr ;
// Find first entry
do
{
entry = ( ServerList : : MasterEntry * ) ( data . data ( ) + offset + + ) ;
}
while ( ! entry - > HasSeparator ( ) & & ! entry - > IsEndToken ( ) ) ;
2015-12-27 22:02:30 -05:00
2015-12-28 08:53:20 -05:00
for ( int i = 0 ; ! entry [ i ] . IsEndToken ( ) & & entry [ i ] . HasSeparator ( ) ; i + + )
2015-12-27 22:02:30 -05:00
{
2015-12-28 08:53:20 -05:00
Network : : Address serverAddr = address ;
serverAddr . SetIP ( entry [ i ] . IP ) ;
2016-01-03 14:13:49 -05:00
serverAddr . SetPort ( ntohs ( entry [ i ] . Port ) ) ;
2015-12-28 08:53:20 -05:00
serverAddr . Get ( ) - > type = Game : : NA_IP ;
2015-12-27 22:02:30 -05:00
2015-12-28 08:53:20 -05:00
ServerList : : Container : : ServerContainer container ;
2015-12-28 09:46:08 -05:00
container . Sent = false ;
2015-12-28 08:53:20 -05:00
container . Target = serverAddr ;
2015-12-27 22:02:30 -05:00
2015-12-28 09:46:08 -05:00
bool alreadyInserted = false ;
for ( auto & server : ServerList : : RefreshContainer . Servers )
{
if ( server . Target = = container . Target )
{
alreadyInserted = true ;
break ;
}
}
2015-12-27 22:02:30 -05:00
2015-12-28 09:46:08 -05:00
if ( ! alreadyInserted )
{
ServerList : : RefreshContainer . Servers . push_back ( container ) ;
ServerList : : RefreshContainer . SendCount + + ;
}
2015-12-27 22:02:30 -05:00
}
2015-12-28 11:52:13 -05:00
Logger : : Print ( " Parsed %d servers from master \n " , ServerList : : RefreshContainer . Servers . size ( ) - count ) ;
2015-12-28 08:53:20 -05:00
2015-12-27 22:02:30 -05:00
ServerList : : RefreshContainer . Mutex . unlock ( ) ;
} ) ;
2015-12-28 08:08:46 -05:00
// Set default masterServerName + port and save it
2016-01-02 09:19:34 -05:00
Utils : : Hook : : Set < char * > ( 0x60AD92 , " localhost " ) ;
2015-12-28 08:08:46 -05:00
Utils : : Hook : : Set < BYTE > ( 0x60AD90 , Game : : dvar_flag : : DVAR_FLAG_SAVED ) ; // masterServerName
Utils : : Hook : : Set < BYTE > ( 0x60ADC6 , Game : : dvar_flag : : DVAR_FLAG_SAVED ) ; // masterPort
// Add server list feeder
UIFeeder : : Add ( 2.0f , ServerList : : GetServerCount , ServerList : : GetServerText , ServerList : : SelectServer ) ;
// Add required UIScripts
UIScript : : Add ( " RefreshServers " , ServerList : : Refresh ) ;
UIScript : : Add ( " JoinServer " , [ ] ( )
2015-12-27 22:02:30 -05:00
{
2016-01-02 09:19:34 -05:00
if ( ServerList : : GetServer ( ServerList : : CurrentServer ) )
2015-12-28 08:08:46 -05:00
{
2016-01-02 09:19:34 -05:00
Party : : Connect ( ServerList : : GetServer ( ServerList : : CurrentServer ) - > Addr ) ;
2015-12-28 08:08:46 -05:00
}
} ) ;
UIScript : : Add ( " ServerSort " , [ ] ( UIScript : : Token token )
{
2016-01-02 09:19:34 -05:00
int key = token . Get < int > ( ) ;
if ( ServerList : : SortKey = = key )
{
ServerList : : SortAsc = ! ServerList : : SortAsc ;
}
else
{
ServerList : : SortKey = key ;
ServerList : : SortAsc = true ;
}
Logger : : Print ( " Sorting server list by token: %d \n " , ServerList : : SortKey ) ;
2016-01-02 09:23:04 -05:00
ServerList : : SortList ( ) ;
2015-12-27 22:02:30 -05:00
} ) ;
2015-12-28 09:46:08 -05:00
// Add frame callback
Renderer : : OnFrame ( ServerList : : Frame ) ;
2015-12-27 22:02:30 -05:00
}
ServerList : : ~ ServerList ( )
{
ServerList : : OnlineList . clear ( ) ;
2016-01-02 09:19:34 -05:00
ServerList : : VisibleList . clear ( ) ;
2015-12-27 22:02:30 -05:00
}
}