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 ;
2022-04-12 17:15:50 -04:00
Dvar : : Var ServerList : : UIServerSelected ;
Dvar : : Var ServerList : : UIServerSelectedMap ;
Dvar : : Var ServerList : : NETServerQueryLimit ;
Dvar : : Var ServerList : : NETServerFrames ;
2022-10-15 16:31:16 -04:00
bool ServerList : : UseMasterServer = true ;
2022-05-03 01:17:31 -04:00
2017-01-16 11:42:50 -05:00
std : : vector < ServerList : : ServerInfo > * ServerList : : GetList ( )
{
if ( ServerList : : IsOnlineList ( ) )
{
return & ServerList : : OnlineList ;
}
2022-06-25 12:21:12 -04:00
if ( ServerList : : IsOfflineList ( ) )
2017-01-16 11:42:50 -05:00
{
return & ServerList : : OfflineList ;
}
2022-06-25 12:21:12 -04:00
if ( ServerList : : IsFavouriteList ( ) )
2017-01-16 11:42:50 -05:00
{
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 ( )
{
2022-10-15 16:31:16 -04:00
return ( 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 :
{
2022-08-15 05:56:00 -04:00
return ( server - > password ? " :icon_locked: " : " " ) ;
2017-06-14 06:06:04 -04:00
}
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
2022-08-14 15:39:53 -04:00
case Column : : AimAssist :
{
2022-08-15 05:56:00 -04:00
return ( ( server - > aimassist = = 1 ) ? " :headshot: " : " " ) ;
2022-08-14 15:39:53 -04:00
}
case Column : : VoiceChat :
{
2022-08-15 05:56:00 -04:00
return ( ( server - > voice = = 1 ) ? " :voice_on: " : " " ) ;
2022-08-14 15:39:53 -04: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 )
{
2022-04-12 17:15:50 -04:00
ServerList : : UIServerSelected . set ( true ) ;
ServerList : : UIServerSelectedMap . set ( info - > mapname ) ;
2017-01-16 11:42:50 -05:00
Dvar : : Var ( " ui_serverSelectedGametype " ) . set ( info - > gametype ) ;
}
else
{
2022-04-12 17:15:50 -04:00
ServerList : : UIServerSelected . set ( false ) ;
2017-01-16 11:42:50 -05:00
}
}
2022-08-24 10:38:14 -04:00
void ServerList : : UpdateVisibleList ( [[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game : : uiInfo_s * info )
2017-01-16 11:42:50 -05:00
{
auto list = ServerList : : GetList ( ) ;
if ( ! list ) return ;
std : : vector < ServerList : : ServerInfo > tempList ( * list ) ;
if ( tempList . empty ( ) )
{
2022-08-24 10:38:14 -04:00
ServerList : : Refresh ( UIScript : : Token ( ) , info ) ;
2017-01-16 11:42:50 -05:00
}
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
}
}
}
2022-08-24 10:38:14 -04:00
void ServerList : : RefreshVisibleList ( [[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game : : uiInfo_s * info )
2022-05-07 09:23:26 -04:00
{
2022-08-24 10:38:14 -04:00
ServerList : : RefreshVisibleListInternal ( UIScript : : Token ( ) , info ) ;
2022-05-07 09:23:26 -04:00
}
2022-08-24 10:38:14 -04:00
void ServerList : : RefreshVisibleListInternal ( [[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game : : uiInfo_s * info , bool refresh )
2017-01-16 11:42:50 -05:00
{
Dvar : : Var ( " ui_serverSelected " ) . set ( false ) ;
ServerList : : VisibleList . clear ( ) ;
auto list = ServerList : : GetList ( ) ;
if ( ! list ) return ;
2022-05-07 09:23:26 -04:00
if ( refresh )
{
2022-08-24 10:38:14 -04:00
ServerList : : Refresh ( UIScript : : Token ( ) , info ) ;
2022-05-07 09:23:26 -04:00
return ;
}
2022-08-24 10:38:14 -04:00
auto ui_browserShowFull = Dvar : : Var ( " ui_browserShowFull " ) . get < bool > ( ) ;
auto ui_browserShowEmpty = Dvar : : Var ( " ui_browserShowEmpty " ) . get < bool > ( ) ;
auto ui_browserShowHardcore = Dvar : : Var ( " ui_browserKillcam " ) . get < int > ( ) ;
auto ui_browserShowPassword = Dvar : : Var ( " ui_browserShowPassword " ) . get < int > ( ) ;
auto ui_browserMod = Dvar : : Var ( " ui_browserMod " ) . get < int > ( ) ;
auto ui_joinGametype = Dvar : : Var ( " ui_joinGametype " ) . get < int > ( ) ;
2017-01-16 11:42:50 -05:00
for ( unsigned int i = 0 ; i < list - > size ( ) ; + + i )
{
2022-08-24 10:38:14 -04:00
auto * serverInfo = & ( * list ) [ i ] ;
2017-01-16 11:42:50 -05:00
// Filter full servers
2022-08-24 10:38:14 -04:00
if ( ! ui_browserShowFull & & serverInfo - > clients > = serverInfo - > maxClients ) continue ;
2017-01-16 11:42:50 -05:00
// Filter empty servers
2022-08-24 10:38:14 -04:00
if ( ! ui_browserShowEmpty & & serverInfo - > clients < = 0 ) continue ;
2017-01-16 11:42:50 -05:00
// Filter hardcore servers
2022-08-24 10:38:14 -04:00
if ( ( ui_browserShowHardcore = = 0 & & serverInfo - > hardcore ) | | ( ui_browserShowHardcore = = 1 & & ! serverInfo - > hardcore ) ) continue ;
2017-01-16 11:42:50 -05:00
// Filter servers with password
2022-08-24 10:38:14 -04:00
if ( ( ui_browserShowPassword = = 0 & & serverInfo - > password ) | | ( ui_browserShowPassword = = 1 & & ! serverInfo - > password ) ) continue ;
2017-01-16 11:42:50 -05:00
// Don't show modded servers
2022-08-24 10:38:14 -04:00
if ( ( ui_browserMod = = 0 & & serverInfo - > mod . size ( ) ) | | ( ui_browserMod = = 1 & & ! serverInfo - > mod . size ( ) ) ) continue ;
2017-01-16 11:42:50 -05:00
// Filter by gametype
2022-08-24 10:38:14 -04:00
if ( ui_joinGametype > 0 & & ( ui_joinGametype - 1 ) < * Game : : gameTypeCount & & Game : : gameTypes [ ( ui_joinGametype - 1 ) ] . gameType ! = serverInfo - > gametype ) continue ;
2017-01-16 11:42:50 -05:00
ServerList : : VisibleList . push_back ( i ) ;
}
ServerList : : SortList ( ) ;
}
2022-08-24 10:38:14 -04:00
void ServerList : : Refresh ( [[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game : : uiInfo_s * info )
2017-01-16 11:42:50 -05:00
{
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 ( ) )
{
2022-05-03 01:17:31 -04:00
const auto masterPort = Dvar : : Var ( " masterPort " ) . get < int > ( ) ;
const auto masterServerName = Dvar : : Var ( " masterServerName " ) . get < const char * > ( ) ;
2017-01-16 11:42:50 -05:00
2022-05-03 12:35:53 -04:00
// Check if our dvars can properly convert to a address
2022-05-03 01:17:31 -04:00
Game : : netadr_t masterServerAddr ;
2022-05-03 12:35:53 -04:00
if ( ! ServerList : : GetMasterServer ( masterServerName , masterPort , masterServerAddr ) )
2022-05-03 01:17:31 -04:00
{
2022-06-12 17:07:53 -04:00
Logger : : Print ( " Could not resolve address for {}:{} " , masterServerName , masterPort ) ;
2022-05-03 12:35:53 -04:00
Toast : : Show ( " cardicon_headshot " , " ^1Error " , Utils : : String : : VA ( " Could not resolve address for %s:%u " , masterServerName , masterPort ) , 5000 ) ;
2022-10-15 16:31:16 -04:00
UseMasterServer = false ;
2022-05-03 12:35:53 -04:00
return ;
}
2017-01-16 11:42:50 -05:00
2022-05-03 12:35:53 -04:00
Toast : : Show ( " cardicon_headshot " , " Server Browser " , " Fetching servers... " , 3000 ) ;
2017-01-16 11:42:50 -05:00
2022-10-15 16:31:16 -04:00
UseMasterServer = true ;
2017-01-16 11:42:50 -05:00
2022-05-03 12:35:53 -04:00
ServerList : : RefreshContainer . awatingList = true ;
ServerList : : RefreshContainer . awaitTime = Game : : Sys_Milliseconds ( ) ;
ServerList : : RefreshContainer . host = Network : : Address ( Utils : : String : : VA ( " %s:%u " , masterServerName , masterPort ) ) ;
Logger : : Print ( " Sending serverlist request to master \n " ) ;
Network : : SendCommand ( ServerList : : RefreshContainer . host , " getservers " , Utils : : String : : VA ( " IW4 %i full empty " , PROTOCOL ) ) ;
2017-01-16 11:42:50 -05:00
}
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
{
std : : vector < std : : string > servers ;
2022-08-19 12:35:36 -04:00
const auto parseData = Utils : : IO : : ReadFile ( FavouriteFile ) ;
if ( ! parseData . empty ( ) )
2017-01-16 11:42:50 -05:00
{
2022-10-16 11:17:42 -04:00
nlohmann : : json object ;
try
{
object = nlohmann : : json : : parse ( parseData ) ;
}
catch ( const nlohmann : : json : : parse_error & ex )
{
Logger : : PrintError ( Game : : CON_CHANNEL_ERROR , " Json Parse Error: {} \n " , ex . what ( ) ) ;
return ;
}
2017-01-16 11:42:50 -05:00
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 ;
}
2022-08-19 12:35:36 -04:00
const nlohmann : : json : : array_t storedServers = object ;
for ( const auto & storedServer : storedServers )
2017-01-16 11:42:50 -05:00
{
2022-08-19 12:35:36 -04:00
if ( ! storedServer . is_string ( ) ) continue ;
if ( storedServer . get < std : : string > ( ) = = server )
2017-01-16 11:42:50 -05:00
{
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 ;
}
2022-08-19 12:35:36 -04:00
servers . push_back ( storedServer . get < std : : string > ( ) ) ;
2017-01-16 11:42:50 -05:00
}
}
servers . push_back ( server ) ;
2022-08-19 12:35:36 -04:00
const auto data = nlohmann : : json ( servers ) ;
Utils : : IO : : WriteFile ( FavouriteFile , 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 ;
2022-08-19 12:35:36 -04:00
const auto parseData = Utils : : IO : : ReadFile ( FavouriteFile ) ;
if ( ! parseData . empty ( ) )
2017-01-18 17:35:33 -05:00
{
2022-10-16 11:17:42 -04:00
nlohmann : : json object ;
try
{
object = nlohmann : : json : : parse ( parseData ) ;
}
catch ( const nlohmann : : json : : parse_error & ex )
{
Logger : : PrintError ( Game : : CON_CHANNEL_ERROR , " Json Parse Error: {} \n " , ex . what ( ) ) ;
return ;
}
2017-01-18 17:35:33 -05:00
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 ;
}
2022-08-19 12:35:36 -04:00
const nlohmann : : json : : array_t arr = object ;
2022-07-29 15:54:18 -04:00
for ( auto & storedServer : arr )
2017-01-18 17:35:33 -05:00
{
2022-07-29 15:54:18 -04:00
if ( storedServer . is_string ( ) & & storedServer . get < std : : string > ( ) ! = server )
2017-01-18 17:35:33 -05:00
{
2022-07-29 15:54:18 -04:00
servers . push_back ( storedServer . get < std : : string > ( ) ) ;
2017-01-18 17:35:33 -05:00
}
}
}
2022-08-19 12:35:36 -04:00
const auto data = nlohmann : : json ( servers ) ;
Utils : : IO : : WriteFile ( FavouriteFile , data . dump ( ) ) ;
2017-01-18 17:35:33 -05:00
auto list = ServerList : : GetList ( ) ;
if ( list ) list - > clear ( ) ;
2022-08-24 10:38:14 -04:00
ServerList : : RefreshVisibleListInternal ( UIScript : : Token ( ) , nullptr ) ;
2017-01-18 17:35:33 -05:00
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 ( )
{
2022-08-19 12:35:36 -04:00
if ( ! ServerList : : IsFavouriteList ( ) )
2017-01-16 11:42:50 -05:00
{
2022-08-19 12:35:36 -04:00
return ;
}
2017-01-16 11:42:50 -05:00
2022-08-19 12:35:36 -04:00
auto list = ServerList : : GetList ( ) ;
if ( list ) list - > clear ( ) ;
2017-01-16 11:42:50 -05:00
2022-08-19 12:35:36 -04:00
const auto parseData = Utils : : IO : : ReadFile ( FavouriteFile ) ;
if ( parseData . empty ( ) )
{
return ;
}
2017-01-16 11:42:50 -05:00
2022-10-16 11:17:42 -04:00
nlohmann : : json object ;
try
{
object = nlohmann : : json : : parse ( parseData ) ;
}
catch ( const nlohmann : : json : : parse_error & ex )
{
Logger : : PrintError ( Game : : CON_CHANNEL_ERROR , " Json Parse Error: {} \n " , ex . what ( ) ) ;
return ;
}
2022-08-19 12:35:36 -04:00
if ( ! object . is_array ( ) )
{
Logger : : Print ( " Favourites storage file is invalid! \n " ) ;
Game : : ShowMessageBox ( " Favourites storage file is invalid! " , " Error " ) ;
return ;
}
2017-01-16 11:42:50 -05:00
2022-08-19 12:35:36 -04:00
const nlohmann : : json : : array_t servers = object ;
for ( const auto & server : servers )
{
if ( ! server . is_string ( ) ) continue ;
ServerList : : InsertRequest ( server . get < std : : string > ( ) ) ;
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 ;
}
}
2022-06-04 04:56:14 -04:00
void ServerList : : Insert ( const Network : : Address & address , const Utils : : InfoString & info )
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
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 ) ;
2022-08-14 15:39:53 -04:00
server . aimassist = ( atoi ( info . get ( " aimAssist " ) . data ( ) ) ! = 0 ) ;
server . voice = ( atoi ( info . get ( " voiceChat " ) . data ( ) ) ! = 0 ) ;
2017-01-16 11:42:50 -05:00
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 ) ;
2022-08-24 10:38:14 -04:00
ServerList : : RefreshVisibleListInternal ( UIScript : : Token ( ) , nullptr ) ;
2017-01-16 11:42:50 -05:00
}
}
}
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
2022-05-03 05:10:48 -04:00
if ( ! ServerList : : IsServerListOpen ( ) ) 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 ;
2022-04-12 17:15:50 -04:00
const auto interval = static_cast < int > ( 1000.0f / ServerList : : NETServerFrames . get < int > ( ) ) ;
if ( ! frameLimit . elapsed ( std : : chrono : : milliseconds ( interval ) ) )
return ;
2017-07-12 04:12:51 -04:00
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 )
{
2022-05-03 02:34:57 -04:00
// Stop counting if we are out of the server browser menu
2022-05-03 05:10:48 -04:00
if ( ! ServerList : : IsServerListOpen ( ) )
2022-05-03 02:34:57 -04:00
{
ServerList : : RefreshContainer . awatingList = false ;
}
// Check if we haven't got a response within 5 seconds
2017-01-16 11:42:50 -05:00
if ( Game : : Sys_Milliseconds ( ) - ServerList : : RefreshContainer . awaitTime > 5000 )
{
ServerList : : RefreshContainer . awatingList = false ;
2022-06-12 17:07:53 -04:00
Logger : : Print ( " We haven't received a response from the master within {} seconds! \n " , ( Game : : Sys_Milliseconds ( ) - ServerList : : RefreshContainer . awaitTime ) / 1000 ) ;
2022-05-03 02:34:57 -04:00
Toast : : Show ( " cardicon_headshot " , " ^1Error " , " Failed to reach master server, using node servers instead. " , 5000 ) ;
2022-10-15 16:31:16 -04:00
UseMasterServer = false ;
2022-05-03 02:34:57 -04:00
Node : : Synchronize ( ) ;
2017-01-16 11:42:50 -05:00
}
}
2022-04-12 17:15:50 -04:00
auto requestLimit = ServerList : : NETServerQueryLimit . get < int > ( ) ;
2017-07-12 04:12:51 -04:00
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 ) ;
2022-08-24 10:38:14 -04:00
ServerList : : RefreshVisibleListInternal ( UIScript : : Token ( ) , nullptr , true ) ;
2017-01-16 11:42:50 -05:00
}
void ServerList : : UpdateGameType ( )
{
Dvar : : Var joinGametype ( " ui_joinGametype " ) ;
int gametype = joinGametype . get < int > ( ) ;
if ( + + gametype > * Game : : gameTypeCount )
{
gametype = 0 ;
}
joinGametype . set ( gametype ) ;
2022-08-24 10:38:14 -04:00
ServerList : : RefreshVisibleListInternal ( UIScript : : Token ( ) , nullptr ) ;
2017-01-16 11:42:50 -05:00
}
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
}
}
}
2022-05-03 03:01:54 -04:00
bool ServerList : : GetMasterServer ( const char * ip , int port , Game : : netadr_t & address )
2022-05-03 01:17:31 -04:00
{
2022-05-03 03:01:54 -04:00
return Game : : NET_StringToAdr ( Utils : : String : : VA ( " %s:%u " , ip , port ) , & address ) ;
2022-05-03 02:34:57 -04:00
}
bool ServerList : : IsServerListOpen ( )
{
2022-05-03 05:10:48 -04:00
auto * menu = Game : : Menus_FindByName ( Game : : uiContext , " pc_join_unranked " ) ;
2022-05-03 02:34:57 -04:00
if ( ! menu )
return false ;
return Game : : Menu_IsVisible ( Game : : uiContext , menu ) ;
2022-05-03 01:17:31 -04: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 ( ) ;
2022-05-27 06:19:28 -04:00
Scheduler : : Once ( [ ]
2017-01-16 11:42:50 -05:00
{
2022-04-12 17:15:50 -04:00
ServerList : : UIServerSelected = Dvar : : Register < bool > ( " ui_serverSelected " , false ,
2022-07-02 13:52:57 -04:00
Game : : DVAR_NONE , " Whether a server has been selected in the serverlist " ) ;
2022-04-12 17:15:50 -04:00
ServerList : : UIServerSelectedMap = Dvar : : Register < const char * > ( " ui_serverSelectedMap " , " mp_afghan " ,
2022-07-02 13:52:57 -04:00
Game : : DVAR_NONE , " Map of the selected server " ) ;
2017-07-12 04:12:51 -04:00
2022-04-12 17:15:50 -04:00
ServerList : : NETServerQueryLimit = Dvar : : Register < int > ( " net_serverQueryLimit " , 1 ,
2022-07-02 13:52:57 -04:00
1 , 10 , Dedicated : : IsEnabled ( ) ? Game : : DVAR_NONE : Game : : DVAR_ARCHIVE , " Amount of server queries per frame " ) ;
2022-04-12 17:15:50 -04:00
ServerList : : NETServerFrames = Dvar : : Register < int > ( " net_serverFrames " , 30 ,
2022-07-02 13:52:57 -04:00
1 , 60 , Dedicated : : IsEnabled ( ) ? Game : : DVAR_NONE : Game : : DVAR_ARCHIVE , " Amount of server query frames per second " ) ;
2022-05-27 06:19:28 -04:00
} , Scheduler : : Pipeline : : MAIN ) ;
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
2022-08-19 19:10:35 -04:00
Network : : OnClientPacket ( " getServersResponse " , [ ] ( const Network : : Address & address , [[maybe_unused]] 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
}
2022-06-12 17:07:53 -04:00
Logger : : Print ( " Parsed {} servers from master \n " , ServerList : : RefreshContainer . servers . size ( ) - count ) ;
2017-01-16 11:42:50 -05:00
} ) ;
// Set default masterServerName + port and save it
2022-05-03 05:10:48 -04:00
Utils : : Hook : : Set < const char * > ( 0x60AD92 , " master.xlabs.dev " ) ;
2022-07-02 13:52:57 -04:00
Utils : : Hook : : Set < BYTE > ( 0x60AD90 , Game : : DVAR_NONE ) ; // masterServerName
Utils : : Hook : : Set < BYTE > ( 0x60ADC6 , Game : : DVAR_NONE ) ; // masterPort
2017-01-16 11:42:50 -05:00
// 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 ) ;
2022-04-12 17:15:50 -04:00
2022-08-24 10:38:14 -04:00
UIScript : : Add ( " JoinServer " , [ ] ( [[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game : : uiInfo_s * info )
2017-01-16 11:42:50 -05:00
{
2022-08-24 10:38:14 -04:00
auto * serverInfo = ServerList : : GetServer ( ServerList : : CurrentServer ) ;
if ( serverInfo )
2017-01-16 11:42:50 -05:00
{
2022-08-24 10:38:14 -04:00
Party : : Connect ( serverInfo - > addr ) ;
2017-01-16 11:42:50 -05:00
}
} ) ;
2022-04-12 17:15:50 -04:00
2022-08-24 10:38:14 -04:00
UIScript : : Add ( " ServerSort " , [ ] ( [[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game : : uiInfo_s * info )
2017-01-16 11:42:50 -05:00
{
2022-08-24 10:38:14 -04:00
auto key = token . get < int > ( ) ;
2017-01-16 11:42:50 -05:00
if ( ServerList : : SortKey = = key )
{
ServerList : : SortAsc = ! ServerList : : SortAsc ;
}
else
{
ServerList : : SortKey = key ;
ServerList : : SortAsc = true ;
}
2022-06-12 17:07:53 -04:00
Logger : : Print ( " Sorting server list by token: {} \n " , ServerList : : SortKey ) ;
2017-01-16 11:42:50 -05:00
ServerList : : SortList ( ) ;
} ) ;
2022-04-12 17:15:50 -04:00
2022-08-24 10:38:14 -04:00
UIScript : : Add ( " CreateListFavorite " , [ ] ( [[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game : : uiInfo_s * info )
2017-01-16 11:42:50 -05:00
{
2022-08-24 10:38:14 -04:00
auto * serverInfo = ServerList : : GetCurrentServer ( ) ;
2017-01-16 11:42:50 -05:00
if ( info )
{
2022-08-24 10:38:14 -04:00
ServerList : : StoreFavourite ( serverInfo - > addr . getString ( ) ) ;
2017-01-16 11:42:50 -05:00
}
} ) ;
2022-04-12 17:15:50 -04:00
2022-08-24 10:38:14 -04:00
UIScript : : Add ( " CreateFavorite " , [ ] ( [[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game : : uiInfo_s * info )
2017-01-16 11:42:50 -05:00
{
ServerList : : StoreFavourite ( Dvar : : Var ( " ui_favoriteAddress " ) . get < std : : string > ( ) ) ;
} ) ;
2022-04-12 17:15:50 -04:00
2022-08-24 10:38:14 -04:00
UIScript : : Add ( " CreateCurrentServerFavorite " , [ ] ( [[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game : : uiInfo_s * info )
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 ) ;
}
}
} ) ;
2022-04-12 17:15:50 -04:00
2022-08-24 10:38:14 -04:00
UIScript : : Add ( " DeleteFavorite " , [ ] ( [[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game : : uiInfo_s * info )
2017-01-18 17:35:33 -05:00
{
2022-08-24 10:38:14 -04:00
auto * serverInfo = ServerList : : GetCurrentServer ( ) ;
if ( serverInfo )
2017-01-18 17:35:33 -05:00
{
2022-08-24 10:38:14 -04:00
ServerList : : RemoveFavourite ( serverInfo - > addr . getString ( ) ) ;
}
2017-01-18 17:35:33 -05:00
} ) ;
2017-01-16 11:42:50 -05:00
2022-04-12 17:15:50 -04:00
# ifdef _DEBUG
2017-01-28 07:31:43 -05:00
Command : : Add ( " playerCount " , [ ] ( Command : : Params * )
{
2022-04-12 17:15:50 -04:00
auto count = 0 ;
for ( const auto & server : ServerList : : OnlineList )
2017-01-28 07:31:43 -05:00
{
count + = server . clients ;
}
2022-06-22 04:58:51 -04:00
Logger : : Debug ( " There are {} players playing " , count ) ;
2017-01-28 07:31:43 -05:00
} ) ;
2022-04-12 17:15:50 -04:00
# endif
2017-01-16 11:42:50 -05:00
// Add required ownerDraws
UIScript : : AddOwnerDraw ( 220 , ServerList : : UpdateSource ) ;
UIScript : : AddOwnerDraw ( 253 , ServerList : : UpdateGameType ) ;
// Add frame callback
2022-05-06 19:15:58 -04:00
Scheduler : : Loop ( ServerList : : Frame , Scheduler : : Pipeline : : CLIENT ) ;
2017-01-16 11:42:50 -05:00
}
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
}
}