2017-01-19 16:23:59 -05:00
# include "STDInclude.hpp"
namespace Components
{
Party : : JoinContainer Party : : Container ;
std : : map < uint64_t , Network : : Address > Party : : LobbyMap ;
SteamID Party : : GenerateLobbyId ( )
{
SteamID id ;
2017-02-18 03:42:55 -05:00
id . accountID = Game : : Sys_Milliseconds ( ) ;
id . universe = 1 ;
id . accountType = 8 ;
id . accountInstance = 0x40000 ;
2017-01-19 16:23:59 -05:00
return id ;
}
Network : : Address Party : : Target ( )
{
return Party : : Container . target ;
}
void Party : : Connect ( Network : : Address target )
{
2018-10-09 04:53:15 -04:00
Node : : Add ( target ) ;
2017-01-19 16:23:59 -05:00
Party : : Container . valid = true ;
Party : : Container . awaitingPlaylist = false ;
Party : : Container . joinTime = Game : : Sys_Milliseconds ( ) ;
Party : : Container . target = target ;
Party : : Container . challenge = Utils : : Cryptography : : Rand : : GenerateChallenge ( ) ;
Network : : SendCommand ( Party : : Container . target , " getinfo " , Party : : Container . challenge ) ;
Command : : Execute ( " openmenu popup_reconnectingtoparty " ) ;
}
2018-12-17 08:29:18 -05:00
const char * Party : : GetLobbyInfo ( SteamID lobby , const std : : string & key )
2017-01-19 16:23:59 -05:00
{
2017-02-18 03:42:55 -05:00
if ( Party : : LobbyMap . find ( lobby . bits ) ! = Party : : LobbyMap . end ( ) )
2017-01-19 16:23:59 -05:00
{
2017-02-18 03:42:55 -05:00
Network : : Address address = Party : : LobbyMap [ lobby . bits ] ;
2017-01-19 16:23:59 -05:00
if ( key = = " addr " )
{
return Utils : : String : : VA ( " %d " , address . getIP ( ) . full ) ;
}
2017-06-14 06:06:04 -04:00
else if ( key = = " port " )
2017-01-19 16:23:59 -05:00
{
return Utils : : String : : VA ( " %d " , address . getPort ( ) ) ;
}
}
return " 212 " ;
}
void Party : : RemoveLobby ( SteamID lobby )
{
2017-02-18 03:42:55 -05:00
if ( Party : : LobbyMap . find ( lobby . bits ) ! = Party : : LobbyMap . end ( ) )
2017-01-19 16:23:59 -05:00
{
2017-02-18 03:42:55 -05:00
Party : : LobbyMap . erase ( Party : : LobbyMap . find ( lobby . bits ) ) ;
2017-01-19 16:23:59 -05:00
}
}
2018-12-17 08:29:18 -05:00
void Party : : ConnectError ( const std : : string & message )
2017-01-19 16:23:59 -05:00
{
Localization : : ClearTemp ( ) ;
Command : : Execute ( " closemenu popup_reconnectingtoparty " ) ;
Dvar : : Var ( " partyend_reason " ) . set ( message ) ;
Command : : Execute ( " openmenu menu_xboxlive_partyended " ) ;
}
std : : string Party : : GetMotd ( )
{
return Party : : Container . motd ;
}
Game : : dvar_t * Party : : RegisterMinPlayers ( const char * name , int /*value*/ , int /*min*/ , int max , Game : : dvar_flag flag , const char * description )
{
return Dvar : : Register < int > ( name , 1 , 1 , max , Game : : dvar_flag : : DVAR_FLAG_WRITEPROTECTED | flag , description ) . get < Game : : dvar_t * > ( ) ;
}
bool Party : : PlaylistAwaiting ( )
{
return Party : : Container . awaitingPlaylist ;
}
void Party : : PlaylistContinue ( )
{
Dvar : : Var ( " xblive_privateserver " ) . set ( false ) ;
// Ensure we can join
* Game : : g_lobbyCreateInProgress = false ;
Party : : Container . awaitingPlaylist = false ;
SteamID id = Party : : GenerateLobbyId ( ) ;
// Temporary workaround
// TODO: Patch the 127.0.0.1 -> loopback mapping in the party code
if ( Party : : Container . target . isLoopback ( ) )
{
if ( * Game : : numIP )
{
Party : : Container . target . setIP ( * Game : : localIP ) ;
Party : : Container . target . setType ( Game : : netadrtype_t : : NA_IP ) ;
Logger : : Print ( " Trying to connect to party with loopback address, using a local ip instead: %s \n " , Party : : Container . target . getCString ( ) ) ;
}
else
{
Logger : : Print ( " Trying to connect to party with loopback address, but no local ip was found. \n " ) ;
}
}
2017-02-18 03:42:55 -05:00
Party : : LobbyMap [ id . bits ] = Party : : Container . target ;
2017-01-19 16:23:59 -05:00
Game : : Steam_JoinLobby ( id , 0 ) ;
}
2018-12-17 08:29:18 -05:00
void Party : : PlaylistError ( const std : : string & error )
2017-01-19 16:23:59 -05:00
{
Party : : Container . valid = false ;
Party : : Container . awaitingPlaylist = false ;
Party : : ConnectError ( error ) ;
}
DWORD Party : : UIDvarIntStub ( char * dvar )
{
2017-03-01 13:56:36 -05:00
if ( ! _stricmp ( dvar , " onlinegame " ) & & ! Stats : : IsMaxLevel ( ) )
2017-01-19 16:23:59 -05:00
{
return 0x649E660 ;
}
return Utils : : Hook : : Call < DWORD ( char * ) > ( 0x4D5390 ) ( dvar ) ;
}
2017-07-12 13:36:18 -04:00
bool Party : : IsInLobby ( )
{
return ( ! Dvar : : Var ( " sv_running " ) . get < bool > ( ) & & Dvar : : Var ( " party_enable " ) . get < bool > ( ) & & Dvar : : Var ( " party_host " ) . get < bool > ( ) ) ;
}
bool Party : : IsInUserMapLobby ( )
{
return ( Party : : IsInLobby ( ) & & Maps : : IsUserMap ( Dvar : : Var ( " ui_mapname " ) . get < const char * > ( ) ) ) ;
}
2017-01-19 16:23:59 -05:00
Party : : Party ( )
{
static Game : : dvar_t * partyEnable = Dvar : : Register < bool > ( " party_enable " , Dedicated : : IsEnabled ( ) , Game : : dvar_flag : : DVAR_FLAG_NONE , " Enable party system " ) . get < Game : : dvar_t * > ( ) ;
Dvar : : Register < bool > ( " xblive_privatematch " , true , Game : : dvar_flag : : DVAR_FLAG_WRITEPROTECTED , " " ) . get < Game : : dvar_t * > ( ) ;
// various changes to SV_DirectConnect-y stuff to allow non-party joinees
Utils : : Hook : : Set < WORD > ( 0x460D96 , 0x90E9 ) ;
Utils : : Hook : : Set < BYTE > ( 0x460F0A , 0xEB ) ;
Utils : : Hook : : Set < BYTE > ( 0x401CA4 , 0xEB ) ;
Utils : : Hook : : Set < BYTE > ( 0x401C15 , 0xEB ) ;
// disable configstring checksum matching (it's unreliable at most)
Utils : : Hook : : Set < BYTE > ( 0x4A75A7 , 0xEB ) ; // SV_SpawnServer
Utils : : Hook : : Set < BYTE > ( 0x5AC2CF , 0xEB ) ; // CL_ParseGamestate
Utils : : Hook : : Set < BYTE > ( 0x5AC2C3 , 0xEB ) ; // CL_ParseGamestate
2017-06-22 04:35:45 -04:00
// AnonymousAddRequest
2017-01-19 16:23:59 -05:00
Utils : : Hook : : Set < BYTE > ( 0x5B5E18 , 0xEB ) ;
Utils : : Hook : : Set < BYTE > ( 0x5B5E64 , 0xEB ) ;
Utils : : Hook : : Nop ( 0x5B5E5C , 2 ) ;
// HandleClientHandshake
Utils : : Hook : : Set < BYTE > ( 0x5B6EA5 , 0xEB ) ;
Utils : : Hook : : Set < BYTE > ( 0x5B6EF3 , 0xEB ) ;
Utils : : Hook : : Nop ( 0x5B6EEB , 2 ) ;
// Allow local connections
Utils : : Hook : : Set < BYTE > ( 0x4D43DA , 0xEB ) ;
// LobbyID mismatch
Utils : : Hook : : Nop ( 0x4E50D6 , 2 ) ;
Utils : : Hook : : Set < BYTE > ( 0x4E50DA , 0xEB ) ;
// causes 'does current Steam lobby match' calls in Steam_JoinLobby to be ignored
Utils : : Hook : : Set < BYTE > ( 0x49D007 , 0xEB ) ;
// functions checking party heartbeat timeouts, cause random issues
Utils : : Hook : : Nop ( 0x4E532D , 5 ) ;
// Steam_JoinLobby call causes migration
Utils : : Hook : : Nop ( 0x5AF851 , 5 ) ;
Utils : : Hook : : Set < BYTE > ( 0x5AF85B , 0xEB ) ;
// Allow xpartygo in public lobbies
Utils : : Hook : : Set < BYTE > ( 0x5A969E , 0xEB ) ;
Utils : : Hook : : Nop ( 0x5A96BE , 2 ) ;
// Always open lobby menu when connecting
// It's not possible to entirely patch it via code
//Utils::Hook::Set<BYTE>(0x5B1698, 0xEB);
//Utils::Hook::Nop(0x5029F2, 6);
//Utils::Hook::SetString(0x70573C, "menu_xboxlive_lobby");
// Disallow selecting team in private match
//Utils::Hook::Nop(0x5B2BD8, 6);
// Force teams, even if not private match
Utils : : Hook : : Set < BYTE > ( 0x487BB2 , 0xEB ) ;
// Force xblive_privatematch 0 and rename it
//Utils::Hook::Set<BYTE>(0x420A6A, 4);
Utils : : Hook : : Set < BYTE > ( 0x420A6C , 0 ) ;
Utils : : Hook : : Set < char * > ( 0x420A6E , " xblive_privateserver " ) ;
// Remove migration shutdown, it causes crashes and will be destroyed when erroring anyways
Utils : : Hook : : Nop ( 0x5A8E1C , 12 ) ;
Utils : : Hook : : Nop ( 0x5A8E33 , 11 ) ;
// Enable XP Bar
Utils : : Hook ( 0x62A2A7 , Party : : UIDvarIntStub , HOOK_CALL ) . install ( ) - > quick ( ) ;
// Set NAT to open
Utils : : Hook : : Set < int > ( 0x79D898 , 1 ) ;
// Disable host migration
Utils : : Hook : : Set < BYTE > ( 0x5B58B2 , 0xEB ) ;
Utils : : Hook : : Set < BYTE > ( 0x4D6171 , 0 ) ;
2017-02-01 22:20:53 -05:00
Utils : : Hook : : Nop ( 0x4077A1 , 5 ) ; // PartyMigrate_Frame
2017-01-19 16:23:59 -05:00
2017-06-22 04:35:45 -04:00
// Patch playlist stuff for non-party behavior
2017-01-19 16:23:59 -05:00
Utils : : Hook : : Set < Game : : dvar_t * * > ( 0x4A4093 , & partyEnable ) ;
Utils : : Hook : : Set < Game : : dvar_t * * > ( 0x4573F1 , & partyEnable ) ;
Utils : : Hook : : Set < Game : : dvar_t * * > ( 0x5B1A0C , & partyEnable ) ;
// Invert corresponding jumps
Utils : : Hook : : Xor < BYTE > ( 0x4A409B , 1 ) ;
Utils : : Hook : : Xor < BYTE > ( 0x4573FA , 1 ) ;
Utils : : Hook : : Xor < BYTE > ( 0x5B1A17 , 1 ) ;
// Fix xstartlobby
//Utils::Hook::Set<BYTE>(0x5B71CD, 0xEB);
// Patch party_minplayers to 1 and protect it
//Utils::Hook(0x4D5D51, Party::RegisterMinPlayers, HOOK_CALL).install()->quick();
// Set ui_maxclients to sv_maxclients
Utils : : Hook : : Set < char * > ( 0x42618F , " sv_maxclients " ) ;
Utils : : Hook : : Set < char * > ( 0x4D3756 , " sv_maxclients " ) ;
Utils : : Hook : : Set < char * > ( 0x5E3772 , " sv_maxclients " ) ;
// Unlatch maxclient dvars
Utils : : Hook : : Xor < BYTE > ( 0x426187 , Game : : dvar_flag : : DVAR_FLAG_LATCHED ) ;
Utils : : Hook : : Xor < BYTE > ( 0x4D374E , Game : : dvar_flag : : DVAR_FLAG_LATCHED ) ;
Utils : : Hook : : Xor < BYTE > ( 0x5E376A , Game : : dvar_flag : : DVAR_FLAG_LATCHED ) ;
Utils : : Hook : : Xor < DWORD > ( 0x4261A1 , Game : : dvar_flag : : DVAR_FLAG_LATCHED ) ;
Utils : : Hook : : Xor < DWORD > ( 0x4D376D , Game : : dvar_flag : : DVAR_FLAG_LATCHED ) ;
Utils : : Hook : : Xor < DWORD > ( 0x5E3789 , Game : : dvar_flag : : DVAR_FLAG_LATCHED ) ;
// Patch Live_PlayerHasLoopbackAddr
//Utils::Hook::Set<DWORD>(0x418F30, 0x90C3C033);
2017-06-14 06:06:04 -04:00
Command : : Add ( " connect " , [ ] ( Command : : Params * params )
2017-01-19 16:23:59 -05:00
{
if ( params - > length ( ) < 2 )
{
return ;
}
2017-06-14 06:06:04 -04:00
if ( Game : : CL_IsCgameInitialized ( ) )
2017-05-29 14:43:03 -04:00
{
Command : : Execute ( " disconnect " , false ) ;
Command : : Execute ( Utils : : String : : VA ( " %s " , params - > join ( 0 ) . data ( ) ) , false ) ;
}
else
{
Party : : Connect ( Network : : Address ( params - > get ( 1 ) ) ) ;
}
2017-01-19 16:23:59 -05:00
} ) ;
2017-06-14 06:06:04 -04:00
Command : : Add ( " reconnect " , [ ] ( Command : : Params * )
2017-01-19 16:23:59 -05:00
{
Party : : Connect ( Party : : Container . target ) ;
} ) ;
2017-06-14 06:06:04 -04:00
Scheduler : : OnFrame ( [ ] ( )
2017-01-19 16:23:59 -05:00
{
if ( Party : : Container . valid )
{
2017-04-07 15:37:01 -04:00
if ( ( Game : : Sys_Milliseconds ( ) - Party : : Container . joinTime ) > 10'000 )
2017-01-19 16:23:59 -05:00
{
Party : : Container . valid = false ;
Party : : ConnectError ( " Server connection timed out. " ) ;
}
}
if ( Party : : Container . awaitingPlaylist )
{
2017-04-07 15:37:01 -04:00
if ( ( Game : : Sys_Milliseconds ( ) - Party : : Container . requestTime ) > 5'000 )
2017-01-19 16:23:59 -05:00
{
Party : : Container . awaitingPlaylist = false ;
Party : : ConnectError ( " Playlist request timed out. " ) ;
}
}
2017-06-01 04:25:13 -04:00
} , true ) ;
2017-01-19 16:23:59 -05:00
// Basic info handler
2018-12-17 08:29:18 -05:00
Network : : Handle ( " getInfo " , [ ] ( Network : : Address address , const std : : string & data )
2017-01-19 16:23:59 -05:00
{
2017-06-12 15:01:56 -04:00
int botCount = 0 ;
2017-01-19 16:23:59 -05:00
int clientCount = 0 ;
int maxclientCount = * Game : : svs_numclients ;
if ( maxclientCount )
{
for ( int i = 0 ; i < maxclientCount ; + + i )
{
if ( Game : : svs_clients [ i ] . state > = 3 )
{
2017-06-12 15:01:56 -04:00
if ( Game : : svs_clients [ i ] . isBot ) + + botCount ;
else + + clientCount ;
2017-01-19 16:23:59 -05:00
}
}
}
else
{
2017-02-24 18:52:11 -05:00
maxclientCount = Dvar : : Var ( " party_maxplayers " ) . get < int > ( ) ;
//maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame);
2017-01-19 16:23:59 -05:00
clientCount = Game : : PartyHost_CountMembers ( reinterpret_cast < Game : : PartyData_s * > ( 0x1081C00 ) ) ;
}
Utils : : InfoString info ;
info . set ( " challenge " , Utils : : ParseChallenge ( data ) ) ;
info . set ( " gamename " , " IW4 " ) ;
info . set ( " hostname " , Dvar : : Var ( " sv_hostname " ) . get < const char * > ( ) ) ;
info . set ( " gametype " , Dvar : : Var ( " g_gametype " ) . get < const char * > ( ) ) ;
info . set ( " fs_game " , Dvar : : Var ( " fs_game " ) . get < const char * > ( ) ) ;
2017-02-18 03:42:55 -05:00
info . set ( " xuid " , Utils : : String : : VA ( " %llX " , Steam : : SteamUser ( ) - > GetSteamID ( ) . bits ) ) ;
2017-01-19 16:23:59 -05:00
info . set ( " clients " , Utils : : String : : VA ( " %i " , clientCount ) ) ;
2017-06-12 15:01:56 -04:00
info . set ( " bots " , Utils : : String : : VA ( " %i " , botCount ) ) ;
2017-01-19 16:23:59 -05:00
info . set ( " sv_maxclients " , Utils : : String : : VA ( " %i " , maxclientCount ) ) ;
info . set ( " protocol " , Utils : : String : : VA ( " %i " , PROTOCOL ) ) ;
info . set ( " shortversion " , SHORTVERSION ) ;
info . set ( " checksum " , Utils : : String : : VA ( " %d " , Game : : Sys_Milliseconds ( ) ) ) ;
info . set ( " mapname " , Dvar : : Var ( " mapname " ) . get < const char * > ( ) ) ;
info . set ( " isPrivate " , ( Dvar : : Var ( " g_password " ) . get < std : : string > ( ) . size ( ) ? " 1 " : " 0 " ) ) ;
info . set ( " hc " , ( Dvar : : Var ( " g_hardcore " ) . get < bool > ( ) ? " 1 " : " 0 " ) ) ;
info . set ( " securityLevel " , Utils : : String : : VA ( " %i " , Dvar : : Var ( " sv_securityLevel " ) . get < int > ( ) ) ) ;
info . set ( " sv_running " , ( Dvar : : Var ( " sv_running " ) . get < bool > ( ) ? " 1 " : " 0 " ) ) ;
2017-07-12 13:36:18 -04:00
// Ensure mapname is set
if ( info . get ( " mapname " ) . empty ( ) | | Party : : IsInLobby ( ) )
{
info . set ( " mapname " , Dvar : : Var ( " ui_mapname " ) . get < const char * > ( ) ) ;
}
2017-04-06 16:22:47 -04:00
if ( Maps : : GetUserMap ( ) - > isValid ( ) )
{
info . set ( " usermaphash " , Utils : : String : : VA ( " %i " , Maps : : GetUserMap ( ) - > getHash ( ) ) ) ;
}
2017-07-12 13:36:18 -04:00
else if ( Party : : IsInUserMapLobby ( ) )
2017-01-19 16:23:59 -05:00
{
2017-07-12 13:36:18 -04:00
info . set ( " usermaphash " , Utils : : String : : VA ( " %i " , Maps : : GetUsermapHash ( info . get ( " mapname " ) ) ) ) ;
2017-01-19 16:23:59 -05:00
}
2017-07-12 13:36:18 -04:00
if ( Dedicated : : IsEnabled ( ) )
2017-01-19 16:23:59 -05:00
{
2017-07-12 13:36:18 -04:00
info . set ( " sv_motd " , Dvar : : Var ( " sv_motd " ) . get < std : : string > ( ) ) ;
2017-01-19 16:23:59 -05:00
}
// Set matchtype
// 0 - No match, connecting not possible
// 1 - Party, use Steam_JoinLobby to connect
// 2 - Match, use CL_ConnectFromParty to connect
if ( Dvar : : Var ( " party_enable " ) . get < bool > ( ) & & Dvar : : Var ( " party_host " ) . get < bool > ( ) ) // Party hosting
{
info . set ( " matchtype " , " 1 " ) ;
}
else if ( Dvar : : Var ( " sv_running " ) . get < bool > ( ) ) // Match hosting
{
info . set ( " matchtype " , " 2 " ) ;
}
else
{
info . set ( " matchtype " , " 0 " ) ;
}
2017-06-15 12:52:29 -04:00
info . set ( " wwwDownload " , ( Dvar : : Var ( " sv_wwwDownload " ) . get < bool > ( ) ? " 1 " : " 0 " ) ) ;
info . set ( " wwwUrl " , Dvar : : Var ( " sv_wwwBaseUrl " ) . get < std : : string > ( ) ) ;
2017-01-19 16:23:59 -05:00
Network : : SendCommand ( address , " infoResponse " , " \\ " + info . build ( ) ) ;
} ) ;
2018-12-17 08:29:18 -05:00
Network : : Handle ( " infoResponse " , [ ] ( Network : : Address address , const std : : string & data )
2017-01-19 16:23:59 -05:00
{
Utils : : InfoString info ( data ) ;
// Handle connection
if ( Party : : Container . valid )
{
if ( Party : : Container . target = = address )
{
// Invalidate handler for future packets
Party : : Container . valid = false ;
Party : : Container . info = info ;
Party : : Container . matchType = atoi ( info . get ( " matchtype " ) . data ( ) ) ;
uint32_t securityLevel = static_cast < uint32_t > ( atoi ( info . get ( " securityLevel " ) . data ( ) ) ) ;
2017-04-06 16:22:47 -04:00
bool isUsermap = ! info . get ( " usermaphash " ) . empty ( ) ;
unsigned int usermapHash = atoi ( info . get ( " usermaphash " ) . data ( ) ) ;
2017-01-19 16:23:59 -05:00
std : : string mod = Dvar : : Var ( " fs_game " ) . get < std : : string > ( ) ;
2017-06-15 12:52:29 -04:00
// set fast server stuff here so its updated when we go to download stuff
if ( info . get ( " wwwDownload " ) = = " 1 " s )
{
Dvar : : Var ( " sv_wwwDownload " ) . set ( true ) ;
Dvar : : Var ( " sv_wwwBaseUrl " ) . set ( info . get ( " wwwUrl " ) ) ;
}
else
{
Dvar : : Var ( " sv_wwwDownload " ) . set ( false ) ;
Dvar : : Var ( " sv_wwwBaseUrl " ) . set ( " " ) ;
}
2017-01-19 16:23:59 -05:00
if ( info . get ( " challenge " ) ! = Party : : Container . challenge )
{
Party : : ConnectError ( " Invalid join response: Challenge mismatch. " ) ;
}
else if ( securityLevel > Auth : : GetSecurityLevel ( ) )
{
//Party::ConnectError(Utils::VA("Your security level (%d) is lower than the server's (%d)", Auth::GetSecurityLevel(), securityLevel));
Command : : Execute ( " closemenu popup_reconnectingtoparty " ) ;
Auth : : IncreaseSecurityLevel ( securityLevel , " reconnect " ) ;
}
else if ( ! Party : : Container . matchType )
{
Party : : ConnectError ( " Server is not hosting a match. " ) ;
}
2017-06-14 06:06:04 -04:00
else if ( Party : : Container . matchType > 2 | | Party : : Container . matchType < 0 )
2017-01-19 16:23:59 -05:00
{
Party : : ConnectError ( " Invalid join response: Unknown matchtype " ) ;
}
2017-04-06 16:22:47 -04:00
else if ( Party : : Container . info . get ( " mapname " ) . empty ( ) | | Party : : Container . info . get ( " gametype " ) . empty ( ) )
{
Party : : ConnectError ( " Invalid map or gametype. " ) ;
}
2017-06-19 15:39:48 -04:00
else if ( Party : : Container . info . get ( " isPrivate " ) = = " 1 " s & & ! Dvar : : Var ( " password " ) . get < std : : string > ( ) . length ( ) )
{
Party : : ConnectError ( " A password is required to join this server! Set it at the bottom of the serverlist. " ) ;
}
2017-06-14 06:06:04 -04:00
else if ( isUsermap & & usermapHash ! = Maps : : GetUsermapHash ( info . get ( " mapname " ) ) )
2017-04-06 16:22:47 -04:00
{
Command : : Execute ( " closemenu popup_reconnectingtoparty " ) ;
2017-06-19 15:39:48 -04:00
Download : : InitiateMapDownload ( info . get ( " mapname " ) , info . get ( " isPrivate " ) = = " 1 " ) ;
2017-04-06 16:22:47 -04:00
}
2017-06-14 06:06:04 -04:00
else if ( ! info . get ( " fs_game " ) . empty ( ) & & Utils : : String : : ToLower ( mod ) ! = Utils : : String : : ToLower ( info . get ( " fs_game " ) ) )
2017-01-19 16:23:59 -05:00
{
Command : : Execute ( " closemenu popup_reconnectingtoparty " ) ;
2017-06-19 15:39:48 -04:00
Download : : InitiateClientDownload ( info . get ( " fs_game " ) , info . get ( " isPrivate " ) = = " 1 " s ) ;
2017-01-19 16:23:59 -05:00
}
else if ( ! Dvar : : Var ( " fs_game " ) . get < std : : string > ( ) . empty ( ) & & info . get ( " fs_game " ) . empty ( ) )
{
Dvar : : Var ( " fs_game " ) . set ( " " ) ;
if ( Dvar : : Var ( " cl_modVidRestart " ) . get < bool > ( ) )
{
Command : : Execute ( " vid_restart " , false ) ;
}
Command : : Execute ( " reconnect " , false ) ;
}
else
{
2017-04-06 16:22:47 -04:00
if ( ! Maps : : CheckMapInstalled ( Party : : Container . info . get ( " mapname " ) . data ( ) , true ) ) return ;
2017-01-19 16:23:59 -05:00
Party : : Container . motd = info . get ( " sv_motd " ) ;
if ( Party : : Container . matchType = = 1 ) // Party
{
// Send playlist request
Party : : Container . requestTime = Game : : Sys_Milliseconds ( ) ;
Party : : Container . awaitingPlaylist = true ;
2017-06-21 23:17:13 -04:00
Network : : SendCommand ( Party : : Container . target , " getplaylist " , Dvar : : Var ( " password " ) . get < std : : string > ( ) ) ;
2017-01-19 16:23:59 -05:00
// This is not a safe method
// TODO: Fix actual error!
if ( Game : : CL_IsCgameInitialized ( ) )
{
Command : : Execute ( " disconnect " , true ) ;
}
}
else if ( Party : : Container . matchType = = 2 ) // Match
{
if ( atoi ( Party : : Container . info . get ( " clients " ) . data ( ) ) > = atoi ( Party : : Container . info . get ( " sv_maxclients " ) . data ( ) ) )
{
Party : : ConnectError ( " @EXE_SERVERISFULL " ) ;
}
else
{
Dvar : : Var ( " xblive_privateserver " ) . set ( true ) ;
Game : : Menus_CloseAll ( Game : : uiContext ) ;
Game : : _XSESSION_INFO hostInfo ;
Game : : CL_ConnectFromParty ( 0 , & hostInfo , * Party : : Container . target . get ( ) , 0 , 0 , Party : : Container . info . get ( " mapname " ) . data ( ) , Party : : Container . info . get ( " gametype " ) . data ( ) ) ;
}
}
}
}
}
ServerList : : Insert ( address , info ) ;
2017-02-12 16:55:45 -05:00
Friends : : UpdateServer ( address , info . get ( " hostname " ) , info . get ( " mapname " ) ) ;
2017-01-19 16:23:59 -05:00
} ) ;
}
Party : : ~ Party ( )
{
Party : : LobbyMap . clear ( ) ;
}
}