2022-02-27 07:53:44 -05:00
# include <STDInclude.hpp>
2017-01-16 11:42:50 -05:00
namespace Components
{
bool ServerList : : SortAsc = true ;
int ServerList : : SortKey = ServerList : : Column : : Ping ;
unsigned int ServerList : : CurrentServer = 0 ;
ServerList : : Container ServerList : : RefreshContainer ;
std : : vector < ServerList : : ServerInfo > ServerList : : OnlineList ;
std : : vector < ServerList : : ServerInfo > ServerList : : OfflineList ;
std : : vector < ServerList : : ServerInfo > ServerList : : FavouriteList ;
std : : vector < unsigned int > ServerList : : VisibleList ;
std : : vector < ServerList : : ServerInfo > * ServerList : : GetList ( )
{
if ( ServerList : : IsOnlineList ( ) )
{
return & ServerList : : OnlineList ;
}
else if ( ServerList : : IsOfflineList ( ) )
{
return & ServerList : : OfflineList ;
}
else if ( ServerList : : IsFavouriteList ( ) )
{
return & ServerList : : FavouriteList ;
}
return nullptr ;
}
bool ServerList : : IsFavouriteList ( )
{
return ( Dvar : : Var ( " ui_netSource " ) . get < int > ( ) = = 2 ) ;
}
bool ServerList : : IsOfflineList ( )
{
return ( Dvar : : Var ( " ui_netSource " ) . get < int > ( ) = = 0 ) ;
}
bool ServerList : : IsOnlineList ( )
{
2017-02-25 09:32:15 -05:00
return ( Monitor : : IsEnabled ( ) | | Dvar : : Var ( " ui_netSource " ) . get < int > ( ) = = 1 ) ;
2017-01-16 11:42:50 -05:00
}
unsigned int ServerList : : GetServerCount ( )
{
return ServerList : : VisibleList . size ( ) ;
}
const char * ServerList : : GetServerText ( unsigned int index , int column )
{
ServerList : : ServerInfo * info = ServerList : : GetServer ( index ) ;
if ( info )
{
2017-01-21 16:14:23 -05:00
return ServerList : : GetServerInfoText ( info , column ) ;
2017-01-16 11:42:50 -05:00
}
return " " ;
}
2017-06-05 10:24:57 -04:00
const char * ServerList : : GetServerInfoText ( ServerList : : ServerInfo * server , int column , bool sorting )
2017-01-16 11:42:50 -05:00
{
if ( ! server ) return " " ;
switch ( column )
{
2017-06-14 06:06:04 -04:00
case Column : : Password :
{
return ( server - > password ? " X " : " " ) ;
}
2017-01-16 11:42:50 -05:00
2017-06-14 06:06:04 -04:00
case Column : : Matchtype :
{
return ( ( server - > matchType = = 1 ) ? " P " : " M " ) ;
}
2017-01-16 11:42:50 -05:00
2017-06-14 06:06:04 -04:00
case Column : : Hostname :
{
return server - > hostname . data ( ) ;
}
2017-01-16 11:42:50 -05:00
2017-06-14 06:06:04 -04:00
case Column : : Mapname :
{
if ( server - > svRunning )
2017-01-16 11:42:50 -05:00
{
2017-06-14 06:06:04 -04:00
if ( ! sorting & & ! Maps : : CheckMapInstalled ( server - > mapname . data ( ) ) )
2017-01-16 11:42:50 -05:00
{
2017-06-14 06:06:04 -04:00
return Utils : : String : : VA ( " ^1%s " , Game : : UI_LocalizeMapName ( server - > mapname . data ( ) ) ) ;
2017-01-16 11:42:50 -05:00
}
2017-06-14 06:06:04 -04:00
return Game : : UI_LocalizeMapName ( server - > mapname . data ( ) ) ;
2017-01-16 11:42:50 -05:00
}
2017-06-14 06:06:04 -04:00
else
2017-01-16 11:42:50 -05:00
{
2017-06-14 06:06:04 -04:00
return Utils : : String : : VA ( " ^3%s " , Game : : UI_LocalizeMapName ( server - > mapname . data ( ) ) ) ;
2017-01-16 11:42:50 -05:00
}
2017-06-14 06:06:04 -04:00
}
case Column : : Players :
{
return Utils : : String : : VA ( " %i/%i (%i) " , server - > clients , server - > maxClients , server - > bots ) ;
}
case Column : : Gametype :
{
return Game : : UI_LocalizeGameType ( server - > gametype . data ( ) ) ;
}
2017-01-16 11:42:50 -05:00
2017-06-14 06:06:04 -04:00
case Column : : Mod :
{
if ( server - > mod ! = " " )
2017-01-16 11:42:50 -05:00
{
2017-06-14 06:06:04 -04:00
return ( server - > mod . data ( ) + 5 ) ;
2017-01-16 11:42:50 -05:00
}
2017-06-14 06:06:04 -04:00
return " " ;
}
2017-01-16 11:42:50 -05:00
2017-06-14 06:06:04 -04:00
case Column : : Ping :
{
if ( server - > ping < 75 ) // Below this is a good ping
{
return Utils : : String : : VA ( " ^2%i " , server - > ping ) ;
2017-01-16 11:42:50 -05:00
}
2017-06-14 06:06:04 -04:00
else if ( server - > ping < 150 ) // Below this is a medium ping
2017-01-16 11:42:50 -05:00
{
2017-06-14 06:06:04 -04:00
return Utils : : String : : VA ( " ^3%i " , server - > ping ) ;
2017-01-16 11:42:50 -05:00
}
2017-06-14 06:06:04 -04:00
else
2017-01-20 16:41:03 -05:00
{
2017-06-14 06:06:04 -04:00
return Utils : : String : : VA ( " ^1%i " , server - > ping ) ;
}
}
default :
{
break ;
} ;
2017-01-16 11:42:50 -05:00
}
return " " ;
}
void ServerList : : SelectServer ( unsigned int index )
{
ServerList : : CurrentServer = index ;
ServerList : : ServerInfo * info = ServerList : : GetCurrentServer ( ) ;
if ( info )
{
Dvar : : Var ( " ui_serverSelected " ) . set ( true ) ;
Dvar : : Var ( " ui_serverSelectedMap " ) . set ( info - > mapname ) ;
Dvar : : Var ( " ui_serverSelectedGametype " ) . set ( info - > gametype ) ;
}
else
{
Dvar : : Var ( " ui_serverSelected " ) . set ( false ) ;
}
}
void ServerList : : UpdateVisibleList ( UIScript : : Token )
{
auto list = ServerList : : GetList ( ) ;
if ( ! list ) return ;
std : : vector < ServerList : : ServerInfo > tempList ( * list ) ;
if ( tempList . empty ( ) )
{
ServerList : : Refresh ( UIScript : : Token ( ) ) ;
}
else
{
list - > clear ( ) ;
2017-02-28 13:58:03 -05:00
std : : lock_guard < std : : recursive_mutex > _ ( ServerList : : RefreshContainer . mutex ) ;
2017-01-16 11:42:50 -05:00
ServerList : : RefreshContainer . sendCount = 0 ;
ServerList : : RefreshContainer . sentCount = 0 ;
2017-05-30 14:31:00 -04:00
for ( auto & server : tempList )
2017-01-16 11:42:50 -05:00
{
2017-02-28 13:58:03 -05:00
ServerList : : InsertRequest ( server . addr ) ;
2017-01-16 11:42:50 -05:00
}
}
}
void ServerList : : RefreshVisibleList ( UIScript : : Token )
{
Dvar : : Var ( " ui_serverSelected " ) . set ( false ) ;
ServerList : : VisibleList . clear ( ) ;
auto list = ServerList : : GetList ( ) ;
if ( ! list ) return ;
// Refresh entirely, if there is no entry in the list
if ( list - > empty ( ) )
{
ServerList : : Refresh ( UIScript : : Token ( ) ) ;
return ;
}
bool ui_browserShowFull = Dvar : : Var ( " ui_browserShowFull " ) . get < bool > ( ) ;
bool ui_browserShowEmpty = Dvar : : Var ( " ui_browserShowEmpty " ) . get < bool > ( ) ;
int ui_browserShowHardcore = Dvar : : Var ( " ui_browserKillcam " ) . get < int > ( ) ;
int ui_browserShowPassword = Dvar : : Var ( " ui_browserShowPassword " ) . get < int > ( ) ;
int ui_browserMod = Dvar : : Var ( " ui_browserMod " ) . get < int > ( ) ;
int ui_joinGametype = Dvar : : Var ( " ui_joinGametype " ) . get < int > ( ) ;
for ( unsigned int i = 0 ; i < list - > size ( ) ; + + i )
{
ServerList : : ServerInfo * info = & ( * list ) [ i ] ;
// Filter full servers
if ( ! ui_browserShowFull & & info - > clients > = info - > maxClients ) continue ;
// Filter empty servers
if ( ! ui_browserShowEmpty & & info - > clients < = 0 ) continue ;
// Filter hardcore servers
if ( ( ui_browserShowHardcore = = 0 & & info - > hardcore ) | | ( ui_browserShowHardcore = = 1 & & ! info - > hardcore ) ) continue ;
// Filter servers with password
if ( ( ui_browserShowPassword = = 0 & & info - > password ) | | ( ui_browserShowPassword = = 1 & & ! info - > password ) ) continue ;
// Don't show modded servers
if ( ( ui_browserMod = = 0 & & info - > mod . size ( ) ) | | ( ui_browserMod = = 1 & & ! info - > mod . size ( ) ) ) continue ;
// Filter by gametype
2017-06-14 06:06:04 -04:00
if ( ui_joinGametype > 0 & & ( ui_joinGametype - 1 ) < * Game : : gameTypeCount & & Game : : gameTypes [ ( ui_joinGametype - 1 ) ] . gameType ! = info - > gametype ) continue ;
2017-01-16 11:42:50 -05:00
ServerList : : VisibleList . push_back ( i ) ;
}
ServerList : : SortList ( ) ;
}
void ServerList : : Refresh ( UIScript : : Token )
{
Dvar : : Var ( " ui_serverSelected " ) . set ( false ) ;
2017-03-10 20:11:32 -05:00
//Localization::Set("MPUI_SERVERQUERIED", "Sent requests: 0/0");
2017-01-16 11:42:50 -05:00
// ServerList::OnlineList.clear();
// ServerList::OfflineList.clear();
// ServerList::FavouriteList.clear();
auto list = ServerList : : GetList ( ) ;
if ( list ) list - > clear ( ) ;
ServerList : : VisibleList . clear ( ) ;
2017-05-30 14:31:00 -04:00
{
std : : lock_guard < std : : recursive_mutex > _ ( ServerList : : RefreshContainer . mutex ) ;
ServerList : : RefreshContainer . servers . clear ( ) ;
ServerList : : RefreshContainer . sendCount = 0 ;
ServerList : : RefreshContainer . sentCount = 0 ;
}
2017-01-16 11:42:50 -05:00
if ( ServerList : : IsOfflineList ( ) )
{
Discovery : : Perform ( ) ;
}
else if ( ServerList : : IsOnlineList ( ) )
{
# ifdef USE_LEGACY_SERVER_LIST
ServerList : : RefreshContainer . awatingList = true ;
ServerList : : RefreshContainer . awaitTime = Game : : Sys_Milliseconds ( ) ;
int masterPort = Dvar : : Var ( " masterPort " ) . get < int > ( ) ;
const char * masterServerName = Dvar : : Var ( " masterServerName " ) . get < const char * > ( ) ;
ServerList : : RefreshContainer . host = Network : : Address ( Utils : : String : : VA ( " %s:%u " , masterServerName , masterPort ) ) ;
Logger : : Print ( " Sending serverlist request to master: %s:%u \n " , masterServerName , masterPort ) ;
Network : : SendCommand ( ServerList : : RefreshContainer . host , " getservers " , Utils : : String : : VA ( " IW4 %i full empty " , PROTOCOL ) ) ;
//Network::SendCommand(ServerList::RefreshContainer.Host, "getservers", "0 full empty");
# else
2018-10-09 04:53:15 -04:00
Node : : Synchronize ( ) ;
2017-01-16 11:42:50 -05:00
# endif
}
else if ( ServerList : : IsFavouriteList ( ) )
{
ServerList : : LoadFavourties ( ) ;
}
}
2018-12-17 08:29:18 -05:00
void ServerList : : StoreFavourite ( const std : : string & server )
2017-01-16 11:42:50 -05:00
{
//json11::Json::parse()
std : : vector < std : : string > servers ;
if ( Utils : : IO : : FileExists ( " players/favourites.json " ) )
{
std : : string data = Utils : : IO : : ReadFile ( " players/favourites.json " ) ;
json11 : : Json object = json11 : : Json : : parse ( data , data ) ;
if ( ! object . is_array ( ) )
{
Logger : : Print ( " Favourites storage file is invalid! \n " ) ;
2017-02-06 15:09:41 -05:00
Game : : ShowMessageBox ( " Favourites storage file is invalid! " , " Error " ) ;
2017-01-16 11:42:50 -05:00
return ;
}
auto storedServers = object . array_items ( ) ;
for ( unsigned int i = 0 ; i < storedServers . size ( ) ; + + i )
{
if ( ! storedServers [ i ] . is_string ( ) ) continue ;
if ( storedServers [ i ] . string_value ( ) = = server )
{
2017-02-06 15:09:41 -05:00
Game : : ShowMessageBox ( " Server already marked as favourite. " , " Error " ) ;
2017-01-16 11:42:50 -05:00
return ;
}
servers . push_back ( storedServers [ i ] . string_value ( ) ) ;
}
}
servers . push_back ( server ) ;
json11 : : Json data = json11 : : Json ( servers ) ;
Utils : : IO : : WriteFile ( " players/favourites.json " , data . dump ( ) ) ;
2017-02-06 15:09:41 -05:00
Game : : ShowMessageBox ( " Server added to favourites. " , " Success " ) ;
2017-01-16 11:42:50 -05:00
}
2018-12-17 08:29:18 -05:00
void ServerList : : RemoveFavourite ( const std : : string & server )
2017-01-18 17:35:33 -05:00
{
std : : vector < std : : string > servers ;
if ( Utils : : IO : : FileExists ( " players/favourites.json " ) )
{
std : : string data = Utils : : IO : : ReadFile ( " players/favourites.json " ) ;
json11 : : Json object = json11 : : Json : : parse ( data , data ) ;
if ( ! object . is_array ( ) )
{
Logger : : Print ( " Favourites storage file is invalid! \n " ) ;
2017-02-06 15:09:41 -05:00
Game : : ShowMessageBox ( " Favourites storage file is invalid! " , " Error " ) ;
2017-01-18 17:35:33 -05:00
return ;
}
for ( auto & storedServer : object . array_items ( ) )
{
if ( storedServer . is_string ( ) & & storedServer . string_value ( ) ! = server )
{
servers . push_back ( storedServer . string_value ( ) ) ;
}
}
}
json11 : : Json data = json11 : : Json ( servers ) ;
Utils : : IO : : WriteFile ( " players/favourites.json " , data . dump ( ) ) ;
auto list = ServerList : : GetList ( ) ;
if ( list ) list - > clear ( ) ;
ServerList : : RefreshVisibleList ( UIScript : : Token ( ) ) ;
2017-02-06 15:09:41 -05:00
Game : : ShowMessageBox ( " Server removed from favourites. " , " Success " ) ;
2017-01-18 17:35:33 -05:00
}
2017-01-16 11:42:50 -05:00
void ServerList : : LoadFavourties ( )
{
if ( ServerList : : IsFavouriteList ( ) & & Utils : : IO : : FileExists ( " players/favourites.json " ) )
{
auto list = ServerList : : GetList ( ) ;
if ( list ) list - > clear ( ) ;
std : : string data = Utils : : IO : : ReadFile ( " players/favourites.json " ) ;
json11 : : Json object = json11 : : Json : : parse ( data , data ) ;
if ( ! object . is_array ( ) )
{
Logger : : Print ( " Favourites storage file is invalid! \n " ) ;
2017-02-06 15:09:41 -05:00
Game : : ShowMessageBox ( " Favourites storage file is invalid! " , " Error " ) ;
2017-01-16 11:42:50 -05:00
return ;
}
auto servers = object . array_items ( ) ;
for ( unsigned int i = 0 ; i < servers . size ( ) ; + + i )
{
2017-06-14 06:06:04 -04:00
if ( ! servers [ i ] . is_string ( ) ) continue ;
2017-02-28 13:58:03 -05:00
ServerList : : InsertRequest ( servers [ i ] . string_value ( ) ) ;
2017-01-16 11:42:50 -05:00
}
}
}
2017-02-28 13:58:03 -05:00
void ServerList : : InsertRequest ( Network : : Address address )
2017-01-16 11:42:50 -05:00
{
2017-02-28 13:58:03 -05:00
std : : lock_guard < std : : recursive_mutex > _ ( ServerList : : RefreshContainer . mutex ) ;
2017-01-16 11:42:50 -05:00
ServerList : : Container : : ServerContainer container ;
container . sent = false ;
container . target = address ;
bool alreadyInserted = false ;
for ( auto & server : ServerList : : RefreshContainer . servers )
{
if ( server . target = = container . target )
{
alreadyInserted = true ;
break ;
}
}
if ( ! alreadyInserted )
{
ServerList : : RefreshContainer . servers . push_back ( container ) ;
auto list = ServerList : : GetList ( ) ;
if ( list )
{
2017-05-30 14:31:00 -04:00
for ( auto & server : * list )
2017-01-16 11:42:50 -05:00
{
if ( server . addr = = container . target )
{
- - ServerList : : RefreshContainer . sendCount ;
- - ServerList : : RefreshContainer . sentCount ;
break ;
}
}
}
+ + ServerList : : RefreshContainer . sendCount ;
}
}
void ServerList : : Insert ( Network : : Address address , Utils : : InfoString info )
{
2017-02-28 13:58:03 -05:00
std : : lock_guard < std : : recursive_mutex > _ ( ServerList : : RefreshContainer . mutex ) ;
2017-01-16 11:42:50 -05:00
for ( auto i = ServerList : : RefreshContainer . servers . begin ( ) ; i ! = ServerList : : RefreshContainer . servers . end ( ) ; )
{
// Our desired server
if ( i - > target = = address & & i - > sent )
{
// 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 ;
}
ServerInfo server ;
server . hostname = info . get ( " hostname " ) ;
server . mapname = info . get ( " mapname " ) ;
server . gametype = info . get ( " gametype " ) ;
server . shortversion = info . get ( " shortversion " ) ;
server . mod = info . get ( " fs_game " ) ;
server . matchType = atoi ( info . get ( " matchtype " ) . data ( ) ) ;
server . clients = atoi ( info . get ( " clients " ) . data ( ) ) ;
2017-06-12 15:01:56 -04:00
server . bots = atoi ( info . get ( " bots " ) . data ( ) ) ;
2017-01-16 11:42:50 -05:00
server . securityLevel = atoi ( info . get ( " securityLevel " ) . data ( ) ) ;
server . maxClients = atoi ( info . get ( " sv_maxclients " ) . data ( ) ) ;
server . password = ( atoi ( info . get ( " isPrivate " ) . data ( ) ) ! = 0 ) ;
server . hardcore = ( atoi ( info . get ( " hc " ) . data ( ) ) ! = 0 ) ;
server . svRunning = ( atoi ( info . get ( " sv_running " ) . data ( ) ) ! = 0 ) ;
server . ping = ( Game : : Sys_Milliseconds ( ) - i - > sendTime ) ;
server . addr = address ;
2021-09-07 08:51:36 -04:00
server . hostname = TextRenderer : : StripMaterialTextIcons ( server . hostname ) ;
server . mapname = TextRenderer : : StripMaterialTextIcons ( server . mapname ) ;
server . gametype = TextRenderer : : StripMaterialTextIcons ( server . gametype ) ;
server . mod = TextRenderer : : StripMaterialTextIcons ( server . mod ) ;
2021-08-21 06:35:32 -04:00
2017-01-16 11:42:50 -05:00
// Remove server from queue
i = ServerList : : RefreshContainer . servers . erase ( i ) ;
2021-08-20 12:42:47 -04:00
// Servers with more than 18 players or less than 0 players are faking for sure
// So lets ignore those
if ( server . clients > 18 | | server . maxClients > 18 | | server . clients < 0 | | server . maxClients < 0 )
return ;
2017-01-16 11:42:50 -05:00
// Check if already inserted and remove
auto list = ServerList : : GetList ( ) ;
if ( ! list ) return ;
unsigned int k = 0 ;
for ( auto j = list - > begin ( ) ; j ! = list - > end ( ) ; + + k )
{
if ( j - > addr = = address )
{
j = list - > erase ( j ) ;
}
else
{
+ + j ;
}
}
// Also remove from visible list
for ( auto j = ServerList : : VisibleList . begin ( ) ; j ! = ServerList : : VisibleList . end ( ) ; )
{
if ( * j = = k )
{
j = ServerList : : VisibleList . erase ( j ) ;
}
else
{
+ + j ;
}
}
if ( info . get ( " gamename " ) = = " IW4 "
2017-06-14 06:06:04 -04:00
& & server . matchType
2017-02-15 04:15:35 -05:00
# if !defined(DEBUG) && defined(VERSION_FILTER)
2017-02-15 08:11:36 -05:00
& & ServerList : : CompareVersion ( server . shortversion , SHORTVERSION )
2017-01-16 11:42:50 -05:00
# endif
)
{
auto lList = ServerList : : GetList ( ) ;
if ( lList )
{
lList - > push_back ( server ) ;
ServerList : : RefreshVisibleList ( UIScript : : Token ( ) ) ;
}
}
break ;
}
else
{
+ + i ;
}
}
}
2018-12-17 08:29:18 -05:00
bool ServerList : : CompareVersion ( const std : : string & version1 , const std : : string & version2 )
2017-02-15 08:11:36 -05:00
{
2022-02-26 18:02:04 -05:00
auto subVersions1 = Utils : : String : : Split ( version1 , ' . ' ) ;
auto subVersions2 = Utils : : String : : Split ( version2 , ' . ' ) ;
2017-02-15 08:11:36 -05:00
while ( subVersions1 . size ( ) > = 3 ) subVersions1 . pop_back ( ) ;
while ( subVersions2 . size ( ) > = 3 ) subVersions2 . pop_back ( ) ;
if ( subVersions1 . size ( ) ! = subVersions2 . size ( ) ) return false ;
2017-06-14 06:06:04 -04:00
for ( unsigned int i = 0 ; i < subVersions1 . size ( ) ; + + i )
2017-02-15 08:11:36 -05:00
{
2017-06-14 06:06:04 -04:00
if ( atoi ( subVersions1 [ i ] . data ( ) ) ! = atoi ( subVersions2 [ i ] . data ( ) ) )
2017-02-15 08:11:36 -05:00
{
return false ;
}
}
return true ;
}
2017-01-16 11:42:50 -05:00
ServerList : : ServerInfo * ServerList : : GetCurrentServer ( )
{
return ServerList : : GetServer ( ServerList : : CurrentServer ) ;
}
void ServerList : : SortList ( )
{
2017-06-05 10:12:15 -04:00
// Only sort when the serverlist is open
Game : : menuDef_t * menu = Game : : Menus_FindByName ( Game : : uiContext , " pc_join_unranked " ) ;
2017-06-14 06:06:04 -04:00
if ( ! menu | | ! Game : : Menu_IsVisible ( Game : : uiContext , menu ) ) return ;
2017-01-16 11:42:50 -05:00
2017-07-12 07:39:45 -04:00
std : : stable_sort ( ServerList : : VisibleList . begin ( ) , ServerList : : VisibleList . end ( ) , [ ] ( const unsigned int & server1 , const unsigned int & server2 ) - > bool
2017-06-05 10:12:15 -04:00
{
2017-01-16 11:42:50 -05:00
ServerInfo * info1 = nullptr ;
ServerInfo * info2 = nullptr ;
auto list = ServerList : : GetList ( ) ;
2017-06-08 11:55:18 -04:00
if ( ! list ) return false ;
2017-01-16 11:42:50 -05:00
if ( list - > size ( ) > server1 ) info1 = & ( * list ) [ server1 ] ;
if ( list - > size ( ) > server2 ) info2 = & ( * list ) [ server2 ] ;
2017-06-08 11:55:18 -04:00
if ( ! info1 ) return false ;
if ( ! info2 ) return false ;
2017-01-16 11:42:50 -05:00
// Numerical comparisons
if ( ServerList : : SortKey = = ServerList : : Column : : Ping )
{
2017-06-08 11:55:18 -04:00
return info1 - > ping < info2 - > ping ;
2017-01-16 11:42:50 -05:00
}
else if ( ServerList : : SortKey = = ServerList : : Column : : Players )
{
2017-06-08 11:55:18 -04:00
return info1 - > clients < info2 - > clients ;
2017-01-16 11:42:50 -05:00
}
2021-09-07 06:49:02 -04:00
std : : string text1 = Utils : : String : : ToLower ( TextRenderer : : StripColors ( ServerList : : GetServerInfoText ( info1 , ServerList : : SortKey , true ) ) ) ;
std : : string text2 = Utils : : String : : ToLower ( TextRenderer : : StripColors ( ServerList : : GetServerInfoText ( info2 , ServerList : : SortKey , true ) ) ) ;
2017-01-16 11:42:50 -05:00
// ASCII-based comparison
2017-06-08 11:55:18 -04:00
return text1 . compare ( text2 ) < 0 ;
2017-01-16 11:42:50 -05:00
} ) ;
2017-06-08 11:55:18 -04:00
if ( ! ServerList : : SortAsc ) std : : reverse ( ServerList : : VisibleList . begin ( ) , ServerList : : VisibleList . end ( ) ) ;
2017-01-16 11:42:50 -05:00
}
ServerList : : ServerInfo * ServerList : : GetServer ( unsigned int index )
{
if ( ServerList : : VisibleList . size ( ) > index )
{
auto list = ServerList : : GetList ( ) ;
if ( ! list ) return nullptr ;
if ( list - > size ( ) > ServerList : : VisibleList [ index ] )
{
return & ( * list ) [ ServerList : : VisibleList [ index ] ] ;
}
}
return nullptr ;
}
void ServerList : : Frame ( )
{
2017-07-12 04:12:51 -04:00
static Utils : : Time : : Interval frameLimit ;
int interval = static_cast < int > ( 1000.0f / Dvar : : Var ( " net_serverFrames " ) . get < int > ( ) ) ;
if ( ! frameLimit . elapsed ( std : : chrono : : milliseconds ( interval ) ) ) return ;
frameLimit . update ( ) ;
2017-05-30 14:31:00 -04:00
std : : lock_guard < std : : recursive_mutex > _ ( ServerList : : RefreshContainer . mutex ) ;
2017-01-16 11:42:50 -05:00
if ( ServerList : : RefreshContainer . awatingList )
{
// Check if we haven't got a response within 10 seconds
if ( Game : : Sys_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 : : Sys_Milliseconds ( ) - ServerList : : RefreshContainer . awaitTime ) / 1000 ) ;
}
}
2017-07-12 04:12:51 -04:00
int requestLimit = Dvar : : Var ( " net_serverQueryLimit " ) . get < int > ( ) ;
for ( unsigned int i = 0 ; i < ServerList : : RefreshContainer . servers . size ( ) & & requestLimit > 0 ; + + i )
2017-01-16 11:42:50 -05:00
{
ServerList : : Container : : ServerContainer * server = & ServerList : : RefreshContainer . servers [ i ] ;
if ( server - > sent ) continue ;
// Found server we can send a request to
server - > sent = true ;
2017-07-12 04:12:51 -04:00
requestLimit - - ;
2017-01-16 11:42:50 -05:00
server - > sendTime = Game : : Sys_Milliseconds ( ) ;
2017-01-19 12:14:30 -05:00
server - > challenge = Utils : : Cryptography : : Rand : : GenerateChallenge ( ) ;
2017-01-16 11:42:50 -05:00
+ + ServerList : : RefreshContainer . sentCount ;
Network : : SendCommand ( server - > target , " getinfo " , server - > challenge ) ;
// Display in the menu, like in COD4
2017-02-26 09:27:02 -05:00
//Localization::Set("MPUI_SERVERQUERIED", Utils::String::VA("Sent requests: %d/%d", ServerList::RefreshContainer.sentCount, ServerList::RefreshContainer.sendCount));
2017-01-16 11:42:50 -05:00
}
2017-02-26 09:27:02 -05:00
ServerList : : UpdateVisibleInfo ( ) ;
2017-01-16 11:42:50 -05:00
}
void ServerList : : UpdateSource ( )
{
Dvar : : Var netSource ( " ui_netSource " ) ;
int source = netSource . get < int > ( ) ;
2018-05-09 06:04:20 -04:00
if ( + + source > netSource . get < Game : : dvar_t * > ( ) - > domain . integer . max )
2017-01-16 11:42:50 -05:00
{
source = 0 ;
}
netSource . set ( source ) ;
ServerList : : RefreshVisibleList ( UIScript : : Token ( ) ) ;
}
void ServerList : : UpdateGameType ( )
{
Dvar : : Var joinGametype ( " ui_joinGametype " ) ;
int gametype = joinGametype . get < int > ( ) ;
if ( + + gametype > * Game : : gameTypeCount )
{
gametype = 0 ;
}
joinGametype . set ( gametype ) ;
ServerList : : RefreshVisibleList ( UIScript : : Token ( ) ) ;
}
2017-02-26 09:27:02 -05:00
void ServerList : : UpdateVisibleInfo ( )
{
static int servers = 0 ;
static int players = 0 ;
2017-06-25 16:07:16 -04:00
static int bots = 0 ;
2017-02-26 09:27:02 -05:00
auto list = ServerList : : GetList ( ) ;
if ( list )
{
int newSevers = list - > size ( ) ;
int newPlayers = 0 ;
2017-06-25 16:07:16 -04:00
int newBots = 0 ;
2017-02-26 09:27:02 -05:00
for ( unsigned int i = 0 ; i < list - > size ( ) ; + + i )
{
newPlayers + = list - > at ( i ) . clients ;
2017-06-25 16:07:16 -04:00
newBots + = list - > at ( i ) . bots ;
2017-02-26 09:27:02 -05:00
}
2017-06-25 16:07:16 -04:00
if ( newSevers ! = servers | | newPlayers ! = players | | newBots ! = bots )
2017-02-26 09:27:02 -05:00
{
servers = newSevers ;
players = newPlayers ;
2017-06-25 16:07:16 -04:00
bots = newBots ;
2017-02-26 09:27:02 -05:00
2017-06-25 16:07:16 -04:00
Localization : : Set ( " MPUI_SERVERQUERIED " , Utils : : String : : VA ( " Servers: %i \n Players: %i (%i) " , servers , players , bots ) ) ;
2017-02-26 09:27:02 -05:00
}
}
}
2017-01-16 11:42:50 -05:00
ServerList : : ServerList ( )
{
ServerList : : OnlineList . clear ( ) ;
2017-02-26 09:27:02 -05:00
ServerList : : OfflineList . clear ( ) ;
ServerList : : FavouriteList . clear ( ) ;
2017-01-16 11:42:50 -05:00
ServerList : : VisibleList . clear ( ) ;
2017-06-14 06:06:04 -04:00
Dvar : : OnInit ( [ ] ( )
2017-01-16 11:42:50 -05:00
{
2022-03-08 07:20:28 -05:00
Dvar : : Register < bool > ( " ui_serverSelected " , false , Game : : dvar_flag : : DVAR_NONE , " Whether a server has been selected in the serverlist " ) ;
Dvar : : Register < const char * > ( " ui_serverSelectedMap " , " mp_afghan " , Game : : dvar_flag : : DVAR_NONE , " Map of the selected server " ) ;
2017-07-12 04:12:51 -04:00
2022-03-08 07:44:05 -05:00
Dvar : : Register < int > ( " net_serverQueryLimit " , 1 , 1 , 10 , Dedicated : : IsEnabled ( ) ? Game : : dvar_flag : : DVAR_NONE : Game : : dvar_flag : : DVAR_ARCHIVE , " Amount of server queries per frame " ) ;
Dvar : : Register < int > ( " net_serverFrames " , 30 , 1 , 60 , Dedicated : : IsEnabled ( ) ? Game : : dvar_flag : : DVAR_NONE : Game : : dvar_flag : : DVAR_ARCHIVE , " Amount of server query frames per second " ) ;
2017-01-16 11:42:50 -05:00
} ) ;
2017-03-24 13:28:03 -04:00
// Fix ui_netsource dvar
Utils : : Hook : : Nop ( 0x4CDEEC , 5 ) ; // Don't reset the netsource when gametypes aren't loaded
2022-03-08 07:20:28 -05:00
Dvar : : Register < int > ( " ui_netSource " , 1 , 0 , 2 , Game : : DVAR_ARCHIVE , reinterpret_cast < const char * > ( 0x6D9F08 ) ) ;
2017-03-24 13:28:03 -04:00
2017-02-26 09:27:02 -05:00
//Localization::Set("MPUI_SERVERQUERIED", "Sent requests: 0/0");
2017-06-25 16:07:16 -04:00
Localization : : Set ( " MPUI_SERVERQUERIED " , " Servers: 0 \n Players: 0 (0) " ) ;
2017-01-16 11:42:50 -05:00
2018-12-17 08:29:18 -05:00
Network : : Handle ( " getServersResponse " , [ ] ( Network : : Address address , const std : : string & data )
2017-01-16 11:42:50 -05:00
{
if ( ServerList : : RefreshContainer . host ! = address ) return ; // Only parse from host we sent to
ServerList : : RefreshContainer . awatingList = false ;
2017-02-28 13:58:03 -05:00
std : : lock_guard < std : : recursive_mutex > _ ( ServerList : : RefreshContainer . mutex ) ;
2017-01-16 11:42:50 -05:00
int offset = 0 ;
int count = ServerList : : RefreshContainer . servers . size ( ) ;
ServerList : : MasterEntry * entry = nullptr ;
// Find first entry
2017-06-14 06:06:04 -04:00
do
2017-01-16 11:42:50 -05:00
{
entry = reinterpret_cast < ServerList : : MasterEntry * > ( const_cast < char * > ( data . data ( ) ) + offset + + ) ;
2017-06-14 06:06:04 -04:00
} while ( ! entry - > HasSeparator ( ) & & ! entry - > IsEndToken ( ) ) ;
2017-01-16 11:42:50 -05:00
for ( int i = 0 ; ! entry [ i ] . IsEndToken ( ) & & entry [ i ] . HasSeparator ( ) ; + + i )
{
Network : : Address serverAddr = address ;
serverAddr . setIP ( entry [ i ] . ip ) ;
serverAddr . setPort ( ntohs ( entry [ i ] . port ) ) ;
serverAddr . setType ( Game : : NA_IP ) ;
2017-02-28 13:58:03 -05:00
ServerList : : InsertRequest ( serverAddr ) ;
2017-01-16 11:42:50 -05:00
}
Logger : : Print ( " Parsed %d servers from master \n " , ServerList : : RefreshContainer . servers . size ( ) - count ) ;
} ) ;
// Set default masterServerName + port and save it
# ifdef USE_LEGACY_SERVER_LIST
2017-03-24 15:31:59 -04:00
Utils : : Hook : : Set < char * > ( 0x60AD92 , " 127.0.0.1 " ) ;
2022-03-08 07:20:28 -05:00
Utils : : Hook : : Set < BYTE > ( 0x60AD90 , Game : : dvar_flag : : DVAR_ARCHIVE ) ; // masterServerName
Utils : : Hook : : Set < BYTE > ( 0x60ADC6 , Game : : dvar_flag : : DVAR_ARCHIVE ) ; // masterPort
2017-01-16 11:42:50 -05:00
# endif
// Add server list feeder
UIFeeder : : Add ( 2.0f , ServerList : : GetServerCount , ServerList : : GetServerText , ServerList : : SelectServer ) ;
// Add required UIScripts
UIScript : : Add ( " UpdateFilter " , ServerList : : RefreshVisibleList ) ;
UIScript : : Add ( " RefreshFilter " , ServerList : : UpdateVisibleList ) ;
UIScript : : Add ( " RefreshServers " , ServerList : : Refresh ) ;
2017-06-14 06:06:04 -04:00
UIScript : : Add ( " JoinServer " , [ ] ( UIScript : : Token )
2017-01-16 11:42:50 -05:00
{
ServerList : : ServerInfo * info = ServerList : : GetServer ( ServerList : : CurrentServer ) ;
if ( info )
{
Party : : Connect ( info - > addr ) ;
}
} ) ;
2017-06-14 06:06:04 -04:00
UIScript : : Add ( " ServerSort " , [ ] ( UIScript : : Token token )
2017-01-16 11:42:50 -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 ) ;
ServerList : : SortList ( ) ;
} ) ;
2017-06-14 06:06:04 -04:00
UIScript : : Add ( " CreateListFavorite " , [ ] ( UIScript : : Token )
2017-01-16 11:42:50 -05:00
{
ServerList : : ServerInfo * info = ServerList : : GetCurrentServer ( ) ;
if ( info )
{
ServerList : : StoreFavourite ( info - > addr . getString ( ) ) ;
}
} ) ;
2017-06-14 06:06:04 -04:00
UIScript : : Add ( " CreateFavorite " , [ ] ( UIScript : : Token )
2017-01-16 11:42:50 -05:00
{
ServerList : : StoreFavourite ( Dvar : : Var ( " ui_favoriteAddress " ) . get < std : : string > ( ) ) ;
} ) ;
2017-06-14 06:06:04 -04:00
UIScript : : Add ( " CreateCurrentServerFavorite " , [ ] ( UIScript : : Token )
2017-01-16 11:42:50 -05:00
{
2017-01-18 17:35:33 -05:00
if ( Game : : CL_IsCgameInitialized ( ) )
2017-01-16 11:42:50 -05:00
{
std : : string addressText = Network : : Address ( * Game : : connectedHost ) . getString ( ) ;
if ( addressText ! = " 0.0.0.0:0 " & & addressText ! = " loopback " )
{
ServerList : : StoreFavourite ( addressText ) ;
}
}
} ) ;
2017-06-14 06:06:04 -04:00
UIScript : : Add ( " DeleteFavorite " , [ ] ( UIScript : : Token )
2017-01-18 17:35:33 -05:00
{
ServerList : : ServerInfo * info = ServerList : : GetCurrentServer ( ) ;
if ( info )
{
ServerList : : RemoveFavourite ( info - > addr . getString ( ) ) ;
} ;
} ) ;
2017-01-16 11:42:50 -05:00
2017-01-28 07:31:43 -05:00
Command : : Add ( " playerCount " , [ ] ( Command : : Params * )
{
int count = 0 ;
2017-06-14 06:06:04 -04:00
for ( auto server : ServerList : : OnlineList )
2017-01-28 07:31:43 -05:00
{
count + = server . clients ;
}
Logger : : Print ( " There are %d players playing. \n " , count ) ;
} ) ;
2017-01-16 11:42:50 -05:00
// Add required ownerDraws
UIScript : : AddOwnerDraw ( 220 , ServerList : : UpdateSource ) ;
UIScript : : AddOwnerDraw ( 253 , ServerList : : UpdateGameType ) ;
// Add frame callback
2017-05-31 09:45:12 -04:00
Scheduler : : OnFrame ( ServerList : : Frame ) ;
2017-01-16 11:42:50 -05:00
// This is placed here in case the anticheat has been disabled!
2017-06-23 04:04:43 -04:00
# if !defined(DISABLE_ANTICHEAT) && defined(PROCTECT_PROCESS)
2017-06-01 04:25:13 -04:00
Scheduler : : OnFrame ( AntiCheat : : ReadIntegrityCheck , true ) ;
2017-01-16 11:42:50 -05:00
# endif
}
ServerList : : ~ ServerList ( )
{
2022-03-15 20:44:59 -04:00
std : : lock_guard < std : : recursive_mutex > _ ( ServerList : : RefreshContainer . mutex ) ;
ServerList : : RefreshContainer . awatingList = false ;
ServerList : : RefreshContainer . servers . clear ( ) ;
2017-01-16 11:42:50 -05:00
}
}