sys_session_callbacks.cpp (16339B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. 25 26 =========================================================================== 27 */ 28 #pragma hdrstop 29 #include "../idlib/precompiled.h" 30 #include "../framework/Common_local.h" 31 #include "sys_session_local.h" 32 33 // The more the idLobby class needs to call back into this class, the more likely we're doing something wrong, and there is a better way. 34 35 /* 36 ======================== 37 idSessionLocalCallbacks::BecomingHost 38 This is called when 39 ======================== 40 */ 41 bool idSessionLocalCallbacks::BecomingHost( idLobby & lobby ) { 42 if ( lobby.lobbyType == idLobby::TYPE_GAME ) { 43 if ( sessionLocal->GetActivePlatformLobby() != &lobby ) { 44 idLib::Printf( "BecomingHost: Must be past the party lobby to become host of a game lobby.\n" ); 45 return false; 46 } 47 if ( sessionLocal->localState == idSessionLocal::STATE_INGAME || sessionLocal->localState == idSessionLocal::STATE_LOADING ) { 48 // If we are in a game, go back to the lobby before becoming the new host of a game lobby 49 sessionLocal->SetState( idSessionLocal::STATE_GAME_LOBBY_PEER ); 50 51 // session mgr housekeeping that would usually be done through the standard EndMatch path 52 sessionLocal->EndMatchForMigration(); 53 } 54 } 55 56 return true; 57 } 58 59 /* 60 ======================== 61 idSessionLocalCallbacks::BecameHost 62 ======================== 63 */ 64 void idSessionLocalCallbacks::BecameHost( idLobby & lobby ) { 65 // If we were in the lobby when we switched to host, then set the right state 66 if ( lobby.lobbyType == idLobby::TYPE_PARTY && sessionLocal->localState == idSessionLocal::STATE_PARTY_LOBBY_PEER ) { 67 sessionLocal->SetState( idSessionLocal::STATE_PARTY_LOBBY_HOST ); 68 } else if ( lobby.lobbyType == idLobby::TYPE_GAME && sessionLocal->localState == idSessionLocal::STATE_GAME_LOBBY_PEER ) { 69 sessionLocal->SetState( idSessionLocal::STATE_GAME_LOBBY_HOST ); 70 } 71 } 72 73 /* 74 ======================== 75 idSessionLocalCallbacks::BecomingPeer 76 ======================== 77 */ 78 bool idSessionLocalCallbacks::BecomingPeer( idLobby & lobby ) { 79 if ( lobby.lobbyType == idLobby::TYPE_GAME ) { 80 if ( sessionLocal->localState == idSessionLocal::STATE_INGAME || sessionLocal->localState == idSessionLocal::STATE_LOADING ) { 81 // Go to the party lobby while we try to connect to the new host 82 // This isn't totally necessary but we want to end the current game now and go to some screen. 83 // When the connection goes through or fails will send the session mgr to the appropriate state (game lobby or main menu) 84 85 // What happens if we got the game migration before the party migration? 86 sessionLocal->SetState( sessionLocal->GetPartyLobby().IsHost() ? idSessionLocal::STATE_PARTY_LOBBY_HOST : idSessionLocal::STATE_PARTY_LOBBY_PEER ); 87 88 // session mgr housekeeping that would usually be done through the standard EndMatch path 89 sessionLocal->EndMatchForMigration(); 90 91 return true; // return true tells the session that we want him to tell us when the connects/fails 92 } 93 } 94 return false; 95 } 96 97 /* 98 ======================== 99 idSessionLocalCallbacks::BecamePeer 100 ======================== 101 */ 102 void idSessionLocalCallbacks::BecamePeer( idLobby & lobby ) { 103 if ( lobby.lobbyType == idLobby::TYPE_GAME ) { 104 sessionLocal->SetState( idSessionLocal::STATE_GAME_LOBBY_PEER ); 105 } 106 } 107 108 /* 109 ======================== 110 idSessionLocalCallbacks::FailedGameMigration 111 ======================== 112 */ 113 void idSessionLocalCallbacks::FailedGameMigration( idLobby & lobby ) { 114 // We failed to complete a game migration this could happen for a couple reasons: 115 // -The network invites failed / failed to join migrated session 116 // -There was nobody to invite 117 lobby.ResetAllMigrationState(); 118 if ( lobby.lobbyType == idLobby::TYPE_GAME ) { // this check is a redundant since we should only get this CB from the game session 119 120 sessionLocal->SetState( idSessionLocal::STATE_GAME_LOBBY_HOST ); 121 122 // Make sure the sessions are joinable again 123 sessionLocal->EndSessions(); 124 } 125 } 126 127 /* 128 ======================== 129 idSessionLocalCallbacks::MigrationEnded 130 ======================== 131 */ 132 void idSessionLocalCallbacks::MigrationEnded( idLobby & lobby ) { 133 if ( lobby.migrationInfo.persistUntilGameEndsData.wasMigratedGame ) { 134 #if 1 135 if ( lobby.lobbyType == idLobby::TYPE_GAME || ( lobby.lobbyType == idLobby::TYPE_PARTY && session->GetState() <= idSession::PARTY_LOBBY ) ) { 136 common->Dialog().ClearDialog( GDM_MIGRATING ); 137 common->Dialog().ClearDialog( GDM_MIGRATING_WAITING ); 138 common->Dialog().ClearDialog( GDM_MIGRATING_RELAUNCHING ); 139 140 if ( lobby.GetNumLobbyUsers() <= 1 ) { 141 if ( MatchTypeHasStats( lobby.parms.matchFlags ) ) { 142 common->Dialog().AddDialog( GDM_MIGRATING_FAILED_DISBANDED_STATS, DIALOG_ACCEPT, NULL, NULL, false, "", 0, true ); // Game has disbanded 143 } else { 144 common->Dialog().AddDialog( GDM_MIGRATING_FAILED_DISBANDED, DIALOG_ACCEPT, NULL, NULL, false, "", 0, true ); // Game has disbanded 145 } 146 } else { 147 //common->Dialog().AddDialog( GDM_MIGRATING_FAILED_CONNECTION, DIALOG_ACCEPT, NULL, NULL, false, "", 0, true ); // Lost connection to game 148 if ( lobby.lobbyType == idLobby::TYPE_GAME && MatchTypeHasStats( lobby.parms.matchFlags ) ) { 149 // This means we came from a public match, so tell them they didn't lose stats 150 common->Dialog().AddDialog( GDM_HOST_CONNECTION_LOST_STATS, DIALOG_ACCEPT, NULL, NULL, false, "", 0, true ); // The connection to the host has been lost. This game will not count towards your ranking. 151 } else { 152 // This means we came from a private match, just say host quit 153 common->Dialog().AddDialog( GDM_HOST_CONNECTION_LOST, DIALOG_ACCEPT, NULL, NULL, false, "", 0, true ); // The connection to the host has been lost. 154 } 155 } 156 157 lobby.ResetAllMigrationState(); 158 159 // Make sure the sessions are joinable again 160 sessionLocal->EndSessions(); 161 } 162 #else 163 // If we get here, we migrated from a game 164 if ( lobby.GetNumLobbyUsers() <= 1 && lobby.lobbyType == idLobby::TYPE_GAME ) { 165 if ( !MatchTypeIsJoinInProgress( lobby.parms.matchFlags ) ) { 166 // Handles 'soft' failed game migration where we migrated from a game and are now alone 167 gameDialogMessages_t errorDlg = GDM_INVALID; 168 lobby.migrationInfo.persistUntilGameEndsData.hasGameData = false; // never restart the game if we are by ourselves 169 if ( lobby.migrationInfo.invites.Num() > 0 ) { 170 // outstanding invites: migration failed 171 errorDlg = ( MatchTypeHasStats( lobby.migrateMsgFlags ) && ( sessionLocal->GetFlushedStats() == false ) ) ? GDM_MIGRATING_FAILED_CONNECTION_STATS : GDM_MIGRATING_FAILED_CONNECTION; 172 } else { 173 // there was no one to invite 174 errorDlg = ( MatchTypeHasStats( lobby.migrateMsgFlags ) && ( sessionLocal->GetFlushedStats() == false ) ) ? GDM_MIGRATING_FAILED_DISBANDED_STATS : GDM_MIGRATING_FAILED_DISBANDED; 175 } 176 if ( errorDlg != GDM_INVALID ) { 177 common->Dialog().AddDialog( errorDlg, DIALOG_ACCEPT, NULL, NULL, false ); 178 } 179 common->Dialog().ClearDialog( GDM_MIGRATING ); 180 common->Dialog().ClearDialog( GDM_MIGRATING_WAITING ); 181 common->Dialog().ClearDialog( GDM_MIGRATING_RELAUNCHING ); 182 183 FailedGameMigration( lobby ); 184 } 185 } else if ( lobby.lobbyType == idLobby::TYPE_PARTY ) { 186 if ( session->GetState() <= idSession::PARTY_LOBBY ) { 187 // We got dropped the party lobby, let them know what happened 188 common->Dialog().ClearDialog( GDM_MIGRATING ); 189 common->Dialog().ClearDialog( GDM_MIGRATING_WAITING ); 190 common->Dialog().ClearDialog( GDM_MIGRATING_RELAUNCHING ); 191 192 if ( lobby.GetNumLobbyUsers() <= 1 ) { 193 common->Dialog().AddDialog( GDM_MIGRATING_FAILED_DISBANDED, DIALOG_ACCEPT, NULL, NULL, false, "", 0, true ); // Game has disbanded 194 } else { 195 //common->Dialog().AddDialog( GDM_MIGRATING_FAILED_CONNECTION, DIALOG_ACCEPT, NULL, NULL, false, "", 0, true ); // Lost connection to game 196 common->Dialog().AddDialog( GDM_HOST_CONNECTION_LOST_STATS, DIALOG_ACCEPT, NULL, NULL, false, "", 0, true ); 197 } 198 199 lobby.ResetAllMigrationState(); 200 201 // Make sure the sessions are joinable again 202 sessionLocal->EndSessions(); 203 } 204 } 205 #endif 206 } else if ( lobby.GetNumLobbyUsers() <= 1 && session->GetState() == idSession::PARTY_LOBBY ) { 207 // If they didn't come from a game, and are by themselves, just show the lobby disband msg 208 common->Dialog().AddDialog( GDM_LOBBY_DISBANDED, DIALOG_ACCEPT, NULL, NULL, false, "", 0, true ); // The lobby you were previously in has disbanded 209 210 // Make sure the sessions are joinable again 211 sessionLocal->EndSessions(); 212 } 213 } 214 215 /* 216 ======================== 217 idSessionLocalCallbacks::GoodbyeFromHost 218 ======================== 219 */ 220 void idSessionLocalCallbacks::GoodbyeFromHost( idLobby & lobby, int peerNum, const lobbyAddress_t & remoteAddress, int msgType ) { 221 sessionLocal->GoodbyeFromHost( lobby, peerNum, remoteAddress, msgType ); 222 } 223 224 /* 225 ======================== 226 idSessionLocalCallbacks::AnyPeerHasAddress 227 ======================== 228 */ 229 bool idSessionLocalCallbacks::AnyPeerHasAddress( const lobbyAddress_t & remoteAddress ) const { 230 return sessionLocal->GetPartyLobby().FindAnyPeer( remoteAddress ) || sessionLocal->GetGameLobby().FindAnyPeer( remoteAddress ); 231 } 232 233 /* 234 ======================== 235 idSessionLocalCallbacks::RecvLeaderboardStats 236 ======================== 237 */ 238 void idSessionLocalCallbacks::RecvLeaderboardStats( idBitMsg & msg ) { 239 // Steam and PS3 just write them as they come per player, they don't need to flush 240 sessionLocal->RecvLeaderboardStatsForPlayer( msg ); 241 } 242 243 /* 244 ======================== 245 idSessionLocalCallbacks::ReceivedFullSnap 246 ======================== 247 */ 248 void idSessionLocalCallbacks::ReceivedFullSnap() { 249 // If we received a full snap, then we can transition into the INGAME state 250 sessionLocal->numFullSnapsReceived++; 251 252 if ( sessionLocal->numFullSnapsReceived < 2 ) { 253 return; 254 } 255 256 if ( sessionLocal->localState != idSessionLocal::STATE_INGAME ) { 257 sessionLocal->GetActingGameStateLobby().QueueReliableMessage( sessionLocal->GetActingGameStateLobby().host, idLobby::RELIABLE_IN_GAME ); // Let host know we are in game now 258 sessionLocal->SetState( idSessionLocal::STATE_INGAME ); 259 } 260 } 261 262 /* 263 ======================== 264 idSessionLocalCallbacks::LeaveGameLobby 265 ======================== 266 */ 267 void idSessionLocalCallbacks::LeaveGameLobby() { 268 269 // Make sure we're in the game lobby 270 if ( session->GetState() != idSession::GAME_LOBBY ) { 271 return; 272 } 273 274 // If we're the host of the party, only we are allowed to make this call 275 if ( sessionLocal->GetPartyLobby().IsHost() ) { 276 return; 277 } 278 279 sessionLocal->GetGameLobby().Shutdown(); 280 sessionLocal->SetState( idSessionLocal::STATE_PARTY_LOBBY_PEER ); 281 } 282 283 /* 284 ======================== 285 idSessionLocalCallbacks::PrePickNewHost 286 This is called when we have determined that we need to pick a new host. 287 Call PickNewHostInternal to continue on with the host picking process. 288 ======================== 289 */ 290 void idSessionLocalCallbacks::PrePickNewHost( idLobby & lobby, bool forceMe, bool inviteOldHost ) { 291 sessionLocal->PrePickNewHost( lobby, forceMe, inviteOldHost ); 292 } 293 294 /* 295 ======================== 296 idSessionLocalCallbacks::PreMigrateInvite 297 This is called just before we get invited to a migrated session 298 If we return false, the invite will be ignored 299 ======================== 300 */ 301 bool idSessionLocalCallbacks::PreMigrateInvite( idLobby & lobby ) { 302 return sessionLocal->PreMigrateInvite( lobby ); 303 } 304 305 /* 306 ======================== 307 idSessionLocalCallbacks::ConnectAndMoveToLobby 308 ======================== 309 */ 310 void idSessionLocalCallbacks::ConnectAndMoveToLobby( idLobby::lobbyType_t destLobbyType, const lobbyConnectInfo_t & connectInfo, bool waitForPartyOk ) { 311 312 // See if we are already in the game lobby 313 idLobby * lobby = sessionLocal->GetLobbyFromType( destLobbyType ); 314 315 if ( lobby == NULL ) { 316 idLib::Printf( "RELIABLE_CONNECT_AND_MOVE_TO_LOBBY: Invalid lobby type.\n" ); 317 return; 318 } 319 320 if ( lobby->lobbyBackend != NULL && lobby->lobbyBackend->IsOwnerOfConnectInfo( connectInfo ) ) { 321 idLib::Printf( "RELIABLE_CONNECT_AND_MOVE_TO_LOBBY: Already in lobby.\n" ); 322 return; 323 } 324 325 // See if we are in a game, or loading into a game. If so, ignore invites from our party host 326 if ( destLobbyType == idLobby::TYPE_GAME || destLobbyType == idLobby::TYPE_GAME_STATE ) { 327 if ( GetState() == idSession::INGAME || GetState() == idSession::LOADING ) { 328 idLib::Printf( "RELIABLE_CONNECT_AND_MOVE_TO_LOBBY: In a different game, ignoring.\n" ); 329 return; 330 } 331 } 332 333 // End current game lobby 334 lobby->Shutdown(); 335 336 // waitForPartyOk will be true if the party host wants us to wait for his ok to stay in the lobby 337 lobby->waitForPartyOk = waitForPartyOk; 338 339 // Connect to new game lobby 340 sessionLocal->ConnectAndMoveToLobby( *lobby, connectInfo, true ); // Consider this an invite if party host told us to connect 341 } 342 343 /* 344 ======================== 345 idSessionLocalCallbacks::HandleServerQueryRequest 346 ======================== 347 */ 348 void idSessionLocalCallbacks::HandleServerQueryRequest( lobbyAddress_t & remoteAddr, idBitMsg & msg, int msgType ) { 349 sessionLocal->HandleServerQueryRequest( remoteAddr, msg, msgType ); 350 } 351 352 /* 353 ======================== 354 idSessionLocalCallbacks::HandleServerQueryAck 355 ======================== 356 */ 357 void idSessionLocalCallbacks::HandleServerQueryAck( lobbyAddress_t & remoteAddr, idBitMsg & msg ) { 358 sessionLocal->HandleServerQueryAck( remoteAddr, msg ); 359 } 360 361 extern idCVar net_headlessServer; 362 363 /* 364 ======================== 365 idSessionLocalCallbacks::HandlePeerMatchParamUpdate 366 ======================== 367 */ 368 void idSessionLocalCallbacks::HandlePeerMatchParamUpdate( int peer, int msg ) { 369 if ( net_headlessServer.GetBool() ) { 370 sessionLocal->storedPeer = peer; 371 sessionLocal->storedMsgType = msg; 372 } 373 } 374 375 /* 376 ======================== 377 idSessionLocalCallbacks::CreateLobbyBackend 378 ======================== 379 */ 380 idLobbyBackend * idSessionLocalCallbacks::CreateLobbyBackend( const idMatchParameters & p, float skillLevel, idLobbyBackend::lobbyBackendType_t lobbyType ) { 381 return sessionLocal->CreateLobbyBackend( p, skillLevel, lobbyType ); 382 } 383 384 /* 385 ======================== 386 idSessionLocalCallbacks::FindLobbyBackend 387 ======================== 388 */ 389 idLobbyBackend * idSessionLocalCallbacks::FindLobbyBackend( const idMatchParameters & p, int numPartyUsers, float skillLevel, idLobbyBackend::lobbyBackendType_t lobbyType ) { 390 return sessionLocal->FindLobbyBackend( p, numPartyUsers, skillLevel, lobbyType ); 391 } 392 393 /* 394 ======================== 395 idSessionLocalCallbacks::JoinFromConnectInfo 396 ======================== 397 */ 398 idLobbyBackend * idSessionLocalCallbacks::JoinFromConnectInfo( const lobbyConnectInfo_t & connectInfo , idLobbyBackend::lobbyBackendType_t lobbyType ) { 399 return sessionLocal->JoinFromConnectInfo( connectInfo, lobbyType ); 400 } 401 402 /* 403 ======================== 404 idSessionLocalCallbacks::DestroyLobbyBackend 405 ======================== 406 */ 407 void idSessionLocalCallbacks::DestroyLobbyBackend( idLobbyBackend * lobbyBackend ) { 408 sessionLocal->DestroyLobbyBackend( lobbyBackend ); 409 }