the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at main 1769 lines 57 kB view raw
1#include "stdafx.h" 2#include "..\..\..\Minecraft.World\Socket.h" 3#include "..\..\..\Minecraft.World\StringHelpers.h" 4#include "PlatformNetworkManagerXbox.h" 5#include "NetworkPlayerXbox.h" 6#include "..\..\Common\Network\GameNetworkManager.h" 7 8CPlatformNetworkManagerXbox *g_pPlatformNetworkManager; 9 10VOID CPlatformNetworkManagerXbox::NotifyStateChanged( 11 __in QNET_STATE OldState, 12 __in QNET_STATE NewState, 13 __in HRESULT hrInfo 14 ) 15{ 16 static const char * c_apszStateNames[] = 17 { 18 "QNET_STATE_IDLE", 19 "QNET_STATE_SESSION_HOSTING", 20 "QNET_STATE_SESSION_JOINING", 21 "QNET_STATE_GAME_LOBBY", 22 "QNET_STATE_SESSION_REGISTERING", 23 "QNET_STATE_SESSION_STARTING", 24 "QNET_STATE_GAME_PLAY", 25 "QNET_STATE_SESSION_ENDING", 26 "QNET_STATE_SESSION_LEAVING", 27 "QNET_STATE_SESSION_DELETING", 28 }; 29 30 app.DebugPrintf( "State: %s ==> %s, result 0x%08x.\n", 31 c_apszStateNames[ OldState ], 32 c_apszStateNames[ NewState ], 33 hrInfo ); 34 if( NewState == QNET_STATE_SESSION_HOSTING ) 35 { 36 m_bLeavingGame = false; 37 m_bLeaveGameOnTick = false; 38 m_bHostChanged = false; 39 g_NetworkManager.StateChange_AnyToHosting(); 40 } 41 else if( NewState == QNET_STATE_SESSION_JOINING ) 42 { 43 m_bLeavingGame = false; 44 m_bLeaveGameOnTick = false; 45 m_bHostChanged = false; 46 g_NetworkManager.StateChange_AnyToJoining(); 47 } 48 else if( NewState == QNET_STATE_IDLE && OldState == QNET_STATE_SESSION_JOINING ) 49 { 50 // 4J-PB - now and then we get ERROR_DEVICE_REMOVED when qnet says 51 // " Couldn't join, removed from session!" or 52 //[qnet]: Received data change notification from partially connected player! 53 //[qnet]: Couldn't join, removed from session! 54 // instead of a QNET_E_SESSION_FULL as should be reported 55 56 eJoinFailedReason reason; 57 switch( hrInfo ) 58 { 59 case QNET_E_INSUFFICIENT_PRIVILEGES: 60 reason = JOIN_FAILED_INSUFFICIENT_PRIVILEGES; 61 break; 62 case QNET_E_SESSION_FULL: 63 reason = JOIN_FAILED_SERVER_FULL; 64 break; 65 default: 66 reason = JOIN_FAILED_NONSPECIFIC; 67 break; 68 } 69 g_NetworkManager.StateChange_JoiningToIdle(reason); 70 } 71 else if( NewState == QNET_STATE_IDLE && OldState == QNET_STATE_SESSION_HOSTING ) 72 { 73 m_bLeavingGame = true; 74 } 75 else if( NewState == QNET_STATE_SESSION_STARTING ) 76 { 77 m_lastPlayerEventTimeStart = app.getAppTime(); 78 79 g_NetworkManager.StateChange_AnyToStarting(); 80 } 81 // Fix for #93148 - TCR 001: BAS Game Stability: Title will crash for the multiplayer client if host of the game will exit during the clients loading to created world. 82 // 4J Stu - If the client joins just as the host is exiting, then they can skip to leaving without passing through ending 83 else if( NewState == QNET_STATE_SESSION_ENDING || (NewState == QNET_STATE_SESSION_LEAVING && OldState == QNET_STATE_GAME_PLAY) ) 84 { 85 g_NetworkManager.StateChange_AnyToEnding( OldState == QNET_STATE_GAME_PLAY ); 86 87 if( m_pIQNet->IsHost() ) 88 { 89 m_bLeavingGame = true; 90 } 91 } 92 93 if( NewState == QNET_STATE_IDLE ) 94 { 95 g_NetworkManager.StateChange_AnyToIdle(); 96 } 97} 98 99 100VOID CPlatformNetworkManagerXbox::NotifyPlayerJoined( 101 __in IQNetPlayer * pQNetPlayer 102 ) 103{ 104 const char * pszDescription; 105 106 // 4J Stu - We create a fake socket for every where that we need an INBOUND queue of game data. Outbound 107 // is all handled by QNet so we don't need that. Therefore each client player has one, and the host has one 108 // for each client player. 109 bool createFakeSocket = false; 110 bool localPlayer = false; 111 112 NetworkPlayerXbox *networkPlayer = (NetworkPlayerXbox *)addNetworkPlayer(pQNetPlayer); 113 114 if( pQNetPlayer->IsLocal() ) 115 { 116 localPlayer = true; 117 if( pQNetPlayer->IsHost() ) 118 { 119 pszDescription = "local host"; 120 // 4J Stu - No socket for the localhost as it uses a special loopback queue 121 122 m_machineQNetPrimaryPlayers.push_back( pQNetPlayer ); 123 } 124 else 125 { 126 pszDescription = "local"; 127 128 // We need an inbound queue on all local players to receive data from the host 129 createFakeSocket = true; 130 } 131 } 132 else 133 { 134 if( pQNetPlayer->IsHost() ) 135 { 136 pszDescription = "remote host"; 137 } 138 else 139 { 140 pszDescription = "remote"; 141 142 // If we are the host, then create a fake socket for every remote player 143 if( m_pIQNet->IsHost() ) 144 { 145 createFakeSocket = true; 146 } 147 } 148 149 if( m_pIQNet->IsHost() && !m_bHostChanged ) 150 { 151 // Do we already have a primary player for this system? 152 bool systemHasPrimaryPlayer = false; 153 for(AUTO_VAR(it, m_machineQNetPrimaryPlayers.begin()); it < m_machineQNetPrimaryPlayers.end(); ++it) 154 { 155 IQNetPlayer *pQNetPrimaryPlayer = *it; 156 if( pQNetPlayer->IsSameSystem(pQNetPrimaryPlayer) ) 157 { 158 systemHasPrimaryPlayer = true; 159 break; 160 } 161 } 162 if( !systemHasPrimaryPlayer ) 163 m_machineQNetPrimaryPlayers.push_back( pQNetPlayer ); 164 } 165 } 166 g_NetworkManager.PlayerJoining( networkPlayer ); 167 168 if( createFakeSocket == true && !m_bHostChanged ) 169 { 170 g_NetworkManager.CreateSocket( networkPlayer, localPlayer ); 171 } 172 173 app.DebugPrintf( "Player 0x%p \"%ls\" joined; %s; voice %i; camera %i.\n", 174 pQNetPlayer, 175 pQNetPlayer->GetGamertag(), 176 pszDescription, 177 (int) pQNetPlayer->HasVoice(), 178 (int) pQNetPlayer->HasCamera() ); 179 180 181 if( m_pIQNet->IsHost() ) 182 { 183 // 4J-PB - only the host should do this 184 g_NetworkManager.UpdateAndSetGameSessionData(); 185 SystemFlagAddPlayer( networkPlayer ); 186 } 187 188 for( int idx = 0; idx < XUSER_MAX_COUNT; ++idx) 189 { 190 if(playerChangedCallback[idx] != NULL) 191 playerChangedCallback[idx]( playerChangedCallbackParam[idx], networkPlayer, false ); 192 } 193 194 if(m_pIQNet->GetState() == QNET_STATE_GAME_PLAY) 195 { 196 int localPlayerCount = 0; 197 for(unsigned int idx = 0; idx < XUSER_MAX_COUNT; ++idx) 198 { 199 if( m_pIQNet->GetLocalPlayerByUserIndex(idx) != NULL ) ++localPlayerCount; 200 } 201 202 float appTime = app.getAppTime(); 203 204 // Only record stats for the primary player here 205 m_lastPlayerEventTimeStart = appTime; 206 } 207} 208 209 210VOID CPlatformNetworkManagerXbox::NotifyPlayerLeaving( 211 __in IQNetPlayer * pQNetPlayer 212 ) 213{ 214 //__debugbreak(); 215 216 app.DebugPrintf( "Player 0x%p \"%ls\" leaving.\n", 217 pQNetPlayer, 218 pQNetPlayer->GetGamertag() ); 219 220 INetworkPlayer *networkPlayer = getNetworkPlayer(pQNetPlayer); 221 222 // Get our wrapper object associated with this player. 223 Socket *socket = networkPlayer->GetSocket(); 224 if( socket != NULL ) 225 { 226 // If we are in game then remove this player from the game as well. 227 // We may get here either from the player requesting to exit the game, 228 // in which case we they will already have left the game server, or from a disconnection 229 // where we then have to remove them from the game server 230 if( m_pIQNet->IsHost() && !m_bHostChanged ) 231 { 232 g_NetworkManager.CloseConnection(networkPlayer); 233 } 234 235 // Free the wrapper object memory. 236 // TODO 4J Stu - We may still be using this at the point that the player leaves the session. 237 // We need this as long as the game server still needs to communicate with the player 238 //delete socket; 239 240 networkPlayer->SetSocket( NULL ); 241 } 242 243 if( m_pIQNet->IsHost() && !m_bHostChanged ) 244 { 245 if( isSystemPrimaryPlayer(pQNetPlayer) ) 246 { 247 IQNetPlayer *pNewQNetPrimaryPlayer = NULL; 248 for(unsigned int i = 0; i < m_pIQNet->GetPlayerCount(); ++i ) 249 { 250 IQNetPlayer *pQNetPlayer2 = m_pIQNet->GetPlayerByIndex( i ); 251 252 if( pQNetPlayer2 != pQNetPlayer && pQNetPlayer2->IsSameSystem( pQNetPlayer ) ) 253 { 254 pNewQNetPrimaryPlayer = pQNetPlayer2; 255 break; 256 } 257 } 258 AUTO_VAR(it, find( m_machineQNetPrimaryPlayers.begin(), m_machineQNetPrimaryPlayers.end(), pQNetPlayer)); 259 if( it != m_machineQNetPrimaryPlayers.end() ) 260 { 261 m_machineQNetPrimaryPlayers.erase( it ); 262 } 263 264 if( pNewQNetPrimaryPlayer != NULL ) 265 m_machineQNetPrimaryPlayers.push_back( pNewQNetPrimaryPlayer ); 266 } 267 268 g_NetworkManager.UpdateAndSetGameSessionData( networkPlayer ); 269 SystemFlagRemovePlayer( networkPlayer ); 270 271 } 272 273 g_NetworkManager.PlayerLeaving( networkPlayer ); 274 275 for( int idx = 0; idx < XUSER_MAX_COUNT; ++idx) 276 { 277 if(playerChangedCallback[idx] != NULL) 278 playerChangedCallback[idx]( playerChangedCallbackParam[idx], networkPlayer, true ); 279 } 280 281 if(m_pIQNet->GetState() == QNET_STATE_GAME_PLAY) 282 { 283 int localPlayerCount = 0; 284 for(unsigned int idx = 0; idx < XUSER_MAX_COUNT; ++idx) 285 { 286 if( m_pIQNet->GetLocalPlayerByUserIndex(idx) != NULL ) ++localPlayerCount; 287 } 288 289 float appTime = app.getAppTime(); 290 m_lastPlayerEventTimeStart = appTime; 291 } 292 293 removeNetworkPlayer(pQNetPlayer); 294} 295 296 297VOID CPlatformNetworkManagerXbox::NotifyNewHost( 298 __in IQNetPlayer * pQNetPlayer 299 ) 300{ 301 app.DebugPrintf( "Player 0x%p \"%ls\" (local %i) is new host.\n", 302 pQNetPlayer, 303 pQNetPlayer->GetGamertag(), 304 (int) pQNetPlayer->IsLocal() ); 305 306 m_bHostChanged = true; 307 308 if( m_pIQNet->IsHost() && !IsLeavingGame() ) 309 { 310 m_pGameNetworkManager->HostChanged(); 311 } 312} 313 314 315VOID CPlatformNetworkManagerXbox::NotifyDataReceived( 316 __in IQNetPlayer * pQNetPlayerFrom, 317 __in DWORD dwNumPlayersTo, 318 __in_ecount(dwNumPlayersTo) IQNetPlayer ** apQNetPlayersTo, 319 __in_bcount(dwDataSize) const BYTE * pbData, 320 __in DWORD dwDataSize 321 ) 322{ 323 if(m_pIQNet->GetState() == QNET_STATE_SESSION_ENDING) 324 return; 325 326 DWORD dwPlayer; 327 328 // Loop through all the local players that were targeted and print info 329 // regarding this message. 330 /* 331 for( dwPlayer = 0; dwPlayer < dwNumPlayersTo; dwPlayer++ ) 332 { 333 app.DebugPrintf( "Received %u bytes of data from \"%ls\" to \"%ls\"\n", 334 dwDataSize, 335 pPlayerFrom->GetGamertag(), 336 apPlayersTo[ dwPlayer ]->GetGamertag()); 337 338 } 339 */ 340 341 // Loop through all the players and push this data into their read queue 342 for( dwPlayer = 0; dwPlayer < dwNumPlayersTo; dwPlayer++ ) 343 { 344 if( apQNetPlayersTo[dwPlayer]->IsHost() ) 345 { 346 // If we are the host we care who this came from 347 //app.DebugPrintf( "Pushing data into host read queue for user \"%ls\"\n", pPlayerFrom->GetGamertag()); 348 // Push this data into the read queue for the player that sent it 349 INetworkPlayer *pPlayerFrom = getNetworkPlayer(pQNetPlayerFrom); 350 Socket *socket = pPlayerFrom->GetSocket(); 351 352 if(socket != NULL) 353 socket->pushDataToQueue(pbData, dwDataSize, false); 354 } 355 else 356 { 357 // If we are not the host the message must have come from the host, so we care more about who it is addressed to 358 INetworkPlayer *pPlayerTo = getNetworkPlayer(apQNetPlayersTo[dwPlayer]); 359 Socket *socket = pPlayerTo->GetSocket(); 360 //app.DebugPrintf( "Pushing data into read queue for user \"%ls\"\n", apPlayersTo[dwPlayer]->GetGamertag()); 361 if(socket != NULL) 362 socket->pushDataToQueue(pbData, dwDataSize); 363 } 364 } 365} 366 367 368VOID CPlatformNetworkManagerXbox::NotifyWriteStats( 369 __in IQNetPlayer * pQNetPlayer 370 ) 371{ 372 app.DebugPrintf( "QNet: NotifyWriteStats\n" ); 373 374 g_NetworkManager.WriteStats( getNetworkPlayer( pQNetPlayer ) ); 375} 376 377 378VOID CPlatformNetworkManagerXbox::NotifyReadinessChanged( 379 __in IQNetPlayer * pQNetPlayer, 380 __in BOOL bReady 381 ) 382{ 383 app.DebugPrintf( "Player 0x%p readiness is now %i.\n", pQNetPlayer, (int) bReady ); 384} 385 386 387VOID CPlatformNetworkManagerXbox::NotifyCommSettingsChanged( 388 __in IQNetPlayer * pQNetPlayer 389 ) 390{ 391} 392 393 394VOID CPlatformNetworkManagerXbox::NotifyGameSearchComplete( 395 __in IQNetGameSearch * pGameSearch, 396 __in HRESULT hrComplete, 397 __in DWORD dwNumResults 398 ) 399{ 400 // Not currently used 401} 402 403 404VOID CPlatformNetworkManagerXbox::NotifyGameInvite( 405 __in DWORD dwUserIndex, 406 __in const INVITE_INFO * pInviteInfo 407 ) 408{ 409 g_NetworkManager.GameInviteReceived( dwUserIndex, pInviteInfo ); 410} 411 412 413VOID CPlatformNetworkManagerXbox::NotifyContextChanged( 414 __in const XUSER_CONTEXT * pContext 415 ) 416{ 417 app.DebugPrintf( "Context 0x%p changed.\n", pContext ); 418} 419 420 421VOID CPlatformNetworkManagerXbox::NotifyPropertyChanged( 422 __in const XUSER_PROPERTY * pProperty 423 ) 424{ 425 app.DebugPrintf( "Property 0x%p changed.\n", pProperty ); 426} 427 428bool CPlatformNetworkManagerXbox::Initialise(CGameNetworkManager *pGameNetworkManager, int flagIndexSize) 429{ 430 m_pGameNetworkManager = pGameNetworkManager; 431 m_flagIndexSize = flagIndexSize; 432 g_pPlatformNetworkManager = this; 433 for( int i = 0; i < XUSER_MAX_COUNT; i++ ) 434 { 435 playerChangedCallback[ i ] = NULL; 436 } 437 438 HRESULT hr; 439 int iResult; 440 DWORD dwResult; 441 442 // Start up XNet with default settings. 443 iResult = XNetStartup( NULL ); 444 if( iResult != 0 ) 445 { 446 app.DebugPrintf( "Starting up XNet failed (err = %i)!\n", iResult ); 447 return false; 448 } 449 450 // Start up XOnline. 451 dwResult = XOnlineStartup(); 452 if( dwResult != ERROR_SUCCESS ) 453 { 454 app.DebugPrintf( "Starting up XOnline failed (err = %u)!\n", dwResult ); 455 XNetCleanup(); 456 return false; 457 } 458 459 // Create the QNet object. 460 hr = QNetCreateUsingXAudio2( QNET_SESSIONTYPE_LIVE_STANDARD, this, NULL, g_pXAudio2, &m_pIQNet ); 461 if( FAILED( hr ) ) 462 { 463 app.DebugPrintf( "Creating QNet object failed (err = 0x%08x)!\n", hr ); 464 XOnlineCleanup(); 465 XNetCleanup(); 466 return false; 467 } 468 469 BOOL enableNotify = FALSE; 470 m_pIQNet->SetOpt( QNET_OPTION_NOTIFY_LISTENER, &enableNotify, sizeof BOOL ); 471 472 BOOL enableJip = FALSE; 473 m_pIQNet->SetOpt( QNET_OPTION_JOIN_IN_PROGRESS_ALLOWED, &enableJip, sizeof BOOL ); 474 BOOL enableInv = FALSE; 475 m_pIQNet->SetOpt( QNET_OPTION_INVITES_ALLOWED, &enableInv, sizeof BOOL ); 476 BOOL enablePres = FALSE; 477 m_pIQNet->SetOpt( QNET_OPTION_PRESENCE_JOIN_MODE, &enablePres, sizeof BOOL ); 478 479 // We DO NOT want QNet to handle XN_SYS_SIGNINCHANGED but so far everything else should be fine 480 // We DO WANT QNet to handle XN_LIVE_INVITE_ACCEPTED at a minimum 481 // Receive all types that QNet needs, and filter out the specific ones we don't want later 482 m_notificationListener = XNotifyCreateListener(XNOTIFY_SYSTEM | XNOTIFY_FRIENDS | XNOTIFY_LIVE); 483 484 m_bLeavingGame = false; 485 m_bLeaveGameOnTick = false; 486 m_bHostChanged = false; 487 488 m_bSearchResultsReady = false; 489 m_bSearchPending = false; 490 491 m_bIsOfflineGame = false; 492 m_pSearchParam = NULL; 493 m_SessionsUpdatedCallback = NULL; 494 495 for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) 496 { 497 m_searchResultsCount[i] = 0; 498 m_lastSearchStartTime[i] = 0; 499 500 // The results that will be filled in with the current search 501 m_pSearchResults[i] = NULL; 502 m_pQoSResult[i] = NULL; 503 m_pCurrentSearchResults[i] = NULL; 504 m_pCurrentQoSResult[i] = NULL; 505 m_currentSearchResultsCount[i] = 0; 506 } 507 508 // Success! 509 return true; 510} 511 512void CPlatformNetworkManagerXbox::Terminate() 513{ 514} 515 516int CPlatformNetworkManagerXbox::GetJoiningReadyPercentage() 517{ 518 return 100; 519} 520 521int CPlatformNetworkManagerXbox::CorrectErrorIDS(int IDS) 522{ 523 return IDS; 524} 525 526bool CPlatformNetworkManagerXbox::isSystemPrimaryPlayer(IQNetPlayer *pQNetPlayer) 527{ 528 bool playerIsSystemPrimary = false; 529 for(AUTO_VAR(it, m_machineQNetPrimaryPlayers.begin()); it < m_machineQNetPrimaryPlayers.end(); ++it) 530 { 531 IQNetPlayer *pQNetPrimaryPlayer = *it; 532 if( pQNetPrimaryPlayer == pQNetPlayer ) 533 { 534 playerIsSystemPrimary = true; 535 break; 536 } 537 } 538 return playerIsSystemPrimary; 539} 540 541// We call this twice a frame, either side of the render call so is a good place to "tick" things 542void CPlatformNetworkManagerXbox::DoWork() 543{ 544 DWORD dwNotifyId; 545 ULONG_PTR ulpNotifyParam; 546 547 while( XNotifyGetNext( 548 m_notificationListener, 549 0, // Any notification 550 &dwNotifyId, 551 &ulpNotifyParam) 552 ) 553 { 554 555 switch(dwNotifyId) 556 { 557 558 case XN_SYS_SIGNINCHANGED: 559 app.DebugPrintf("Signinchanged - %d\n", ulpNotifyParam); 560 break; 561 case XN_LIVE_INVITE_ACCEPTED: 562 // ignore these - we're catching them from the game listener, so we can get the one from the dashboard 563 break; 564 default: 565 m_pIQNet->Notify(dwNotifyId,ulpNotifyParam); 566 break; 567 } 568 569 } 570 571 TickSearch(); 572 573 if( m_bLeaveGameOnTick ) 574 { 575 m_pIQNet->LeaveGame(m_migrateHostOnLeave); 576 m_bLeaveGameOnTick = false; 577 } 578 579 m_pIQNet->DoWork(); 580} 581 582int CPlatformNetworkManagerXbox::GetPlayerCount() 583{ 584 return m_pIQNet->GetPlayerCount(); 585} 586 587bool CPlatformNetworkManagerXbox::ShouldMessageForFullSession() 588{ 589 return false; 590} 591 592int CPlatformNetworkManagerXbox::GetOnlinePlayerCount() 593{ 594 DWORD playerCount = GetPlayerCount(); 595 DWORD onlinePlayerCount = 0; 596 597 for(DWORD i = 0; i < playerCount; ++i) 598 { 599 IQNetPlayer *pQNetPlayer = m_pIQNet->GetPlayerByIndex(i); 600 if(!pQNetPlayer->IsLocal())++onlinePlayerCount; 601 } 602 return onlinePlayerCount; 603} 604 605int CPlatformNetworkManagerXbox::GetLocalPlayerMask(int playerIndex) 606{ 607 switch(playerIndex) 608 { 609 case 0: 610 return QNET_USER_MASK_USER0; 611 case 1: 612 return QNET_USER_MASK_USER1; 613 case 2: 614 return QNET_USER_MASK_USER2; 615 case 3: 616 return QNET_USER_MASK_USER3; 617 default: 618 return 0; 619 } 620} 621 622bool CPlatformNetworkManagerXbox::AddLocalPlayerByUserIndex( int userIndex ) 623{ 624 return ( m_pIQNet->AddLocalPlayerByUserIndex(userIndex) == S_OK ); 625} 626 627bool CPlatformNetworkManagerXbox::RemoveLocalPlayerByUserIndex( int userIndex ) 628{ 629 IQNetPlayer *pQNetPlayer = m_pIQNet->GetLocalPlayerByUserIndex(userIndex); 630 INetworkPlayer *pNetworkPlayer = getNetworkPlayer(pQNetPlayer); 631 632 if(pNetworkPlayer != NULL) 633 { 634 Socket *socket = pNetworkPlayer->GetSocket(); 635 636 if( socket != NULL ) 637 { 638 // We can't remove the player from qnet until we have stopped using it to communicate 639 C4JThread* thread = new C4JThread(&CPlatformNetworkManagerXbox::RemovePlayerOnSocketClosedThreadProc, pNetworkPlayer, "RemovePlayerOnSocketClosed"); 640 thread->SetProcessor( CPU_CORE_REMOVE_PLAYER ); 641 thread->Run(); 642 } 643 else 644 { 645 // Safe to remove the player straight away 646 return ( m_pIQNet->RemoveLocalPlayerByUserIndex(userIndex) == S_OK ); 647 } 648 } 649 return true; 650} 651 652bool CPlatformNetworkManagerXbox::IsInStatsEnabledSession() 653{ 654 655 DWORD dataSize = sizeof(QNET_LIVE_STATS_MODE); 656 QNET_LIVE_STATS_MODE statsMode; 657 m_pIQNet->GetOpt(QNET_OPTION_LIVE_STATS_MODE, &statsMode , &dataSize ); 658 659 // Use QNET_LIVE_STATS_MODE_AUTO if there is another way to check if stats are enabled or not 660 bool statsEnabled = statsMode == QNET_LIVE_STATS_MODE_ENABLED; 661 return m_pIQNet->GetState() != QNET_STATE_IDLE && statsEnabled; 662} 663 664bool CPlatformNetworkManagerXbox::SessionHasSpace(unsigned int spaceRequired /*= 1*/) 665{ 666 // This function is used while a session is running, so all players trying to join 667 // should use public slots, 668 DWORD publicSlots = 0; 669 DWORD filledPublicSlots = 0; 670 DWORD privateSlots = 0; 671 DWORD filledPrivateSlots = 0; 672 673 DWORD dataSize = sizeof(DWORD); 674 m_pIQNet->GetOpt(QNET_OPTION_TOTAL_PUBLIC_SLOTS, &publicSlots, &dataSize ); 675 m_pIQNet->GetOpt(QNET_OPTION_FILLED_PUBLIC_SLOTS, &filledPublicSlots, &dataSize ); 676 m_pIQNet->GetOpt(QNET_OPTION_TOTAL_PRIVATE_SLOTS, &privateSlots, &dataSize ); 677 m_pIQNet->GetOpt(QNET_OPTION_FILLED_PRIVATE_SLOTS, &filledPrivateSlots, &dataSize ); 678 679 DWORD spaceLeft = (publicSlots - filledPublicSlots) + (privateSlots - filledPrivateSlots); 680 681 return spaceLeft >= spaceRequired; 682} 683 684void CPlatformNetworkManagerXbox::SendInviteGUI(int quadrant) 685{ 686} 687 688bool CPlatformNetworkManagerXbox::IsAddingPlayer() 689{ 690 return false; 691} 692 693bool CPlatformNetworkManagerXbox::LeaveGame(bool bMigrateHost) 694{ 695 if( m_bLeavingGame ) return true; 696 697 m_bLeavingGame = true; 698 699 // If we are a client, wait for all client connections to close 700 // TODO Possibly need to do multiple objects depending on how split screen online works 701 IQNetPlayer *pQNetPlayer = m_pIQNet->GetLocalPlayerByUserIndex(g_NetworkManager.GetPrimaryPad()); 702 INetworkPlayer *pNetworkPlayer = getNetworkPlayer(pQNetPlayer); 703 704 if(pNetworkPlayer != NULL) 705 { 706 Socket *socket = pNetworkPlayer->GetSocket(); 707 708 if( socket != NULL ) 709 { 710 //printf("Waiting for socket closed event\n"); 711 DWORD result = socket->m_socketClosedEvent->WaitForSignal(INFINITE); 712 713 // The session might be gone once the socket releases 714 if( IsInSession() ) 715 { 716 //printf("Socket closed event has fired\n"); 717 // 4J Stu - Clear our reference to this socket 718 pQNetPlayer = m_pIQNet->GetLocalPlayerByUserIndex(g_NetworkManager.GetPrimaryPad()); 719 pNetworkPlayer = getNetworkPlayer(pQNetPlayer); 720 if(pNetworkPlayer) pNetworkPlayer->SetSocket( NULL ); 721 } 722 delete socket; 723 } 724 else 725 { 726 //printf("Socket is already NULL\n"); 727 } 728 } 729 730 // If we are the host wait for the game server to end 731 if(m_pIQNet->IsHost() && g_NetworkManager.ServerStoppedValid()) 732 { 733 m_pIQNet->EndGame(); 734 g_NetworkManager.ServerStoppedWait(); 735 g_NetworkManager.ServerStoppedDestroy(); 736 } 737 738 return _LeaveGame(bMigrateHost, true); 739} 740 741bool CPlatformNetworkManagerXbox::_LeaveGame(bool bMigrateHost, bool bLeaveRoom) 742{ 743 // 4J Stu - Fix for #10490 - TCR 001 BAS Game Stability: When a party of four players leave a world to join another world without saving the title will crash. 744 // Changed this to make it threadsafe 745 m_bLeaveGameOnTick = true; 746 m_migrateHostOnLeave = bMigrateHost; 747 748 return true; 749} 750 751void CPlatformNetworkManagerXbox::HostGame(int localUsersMask, bool bOnlineGame, bool bIsPrivate, unsigned char publicSlots /*= MINECRAFT_NET_MAX_PLAYERS*/, unsigned char privateSlots /*= 0*/) 752{ 753// #ifdef _XBOX 754 // 4J Stu - We probably did this earlier as well, but just to be sure! 755 SetLocalGame( !bOnlineGame ); 756 SetPrivateGame( bIsPrivate ); 757 SystemFlagReset(); 758 759 // Make sure that the Primary Pad is in by default 760 localUsersMask |= GetLocalPlayerMask( g_NetworkManager.GetPrimaryPad() ); 761 762 _HostGame( localUsersMask, publicSlots, privateSlots ); 763//#endif 764} 765 766void CPlatformNetworkManagerXbox::_HostGame(int usersMask, unsigned char publicSlots /*= MINECRAFT_NET_MAX_PLAYERS*/, unsigned char privateSlots /*= 0*/) 767{ 768 HRESULT hr; 769 // Create a session using the standard game type, in multiplayer game mode, 770 // The constants used to specify game mode, context ID and context value are 771 // defined in the title's .spa.h file, generated using the XLAST tool. 772 // TODO 4J Stu - Game mode should be CONTEXT_GAME_MODE_MULTIPLAYER? 773 XUSER_CONTEXT aXUserContexts[] = { { X_CONTEXT_GAME_TYPE, X_CONTEXT_GAME_TYPE_STANDARD }, 774 { X_CONTEXT_GAME_MODE, CONTEXT_GAME_MODE_GAMEMODE } }; 775 776 777 // We need at least one other slot otherwise it's not multiplayer, is it! 778 if(publicSlots==1 && privateSlots==0) 779 privateSlots = 1; 780 781 //printf("Hosting game with %d public slots and %d private slots\n", publicSlots, privateSlots); 782 783 BOOL enableJip = FALSE; 784 m_pIQNet->SetOpt( QNET_OPTION_JOIN_IN_PROGRESS_ALLOWED, &enableJip, sizeof BOOL ); 785 BOOL enableInv = FALSE; 786 m_pIQNet->SetOpt( QNET_OPTION_INVITES_ALLOWED, &enableInv, sizeof BOOL ); 787 BOOL enablePres = FALSE; 788 m_pIQNet->SetOpt( QNET_OPTION_PRESENCE_JOIN_MODE, &enablePres, sizeof BOOL ); 789 790 // Start hosting a new game 791 // Use only the contexts defined above, and no properties. 792 hr = m_pIQNet->HostGame( 793 g_NetworkManager.GetLockedProfile(), // dwUserIndex 794 usersMask, // dwUserMask 795 publicSlots, // dwPublicSlots 796 privateSlots, // dwPrivateSlots 797 0, // cProperties 798 NULL, // pProperties 799 ARRAYSIZE( aXUserContexts ), // cContexts 800 aXUserContexts ); // pContexts 801 802 m_hostGameSessionData.netVersion = MINECRAFT_NET_VERSION; 803 m_hostGameSessionData.isJoinable = !IsPrivateGame(); 804 805 char* hostName = new char[XUSER_NAME_SIZE]; 806 hostName = g_NetworkManager.GetOnlineName( g_NetworkManager.GetPrimaryPad() ); 807 memcpy(m_hostGameSessionData.hostName,hostName,XUSER_NAME_SIZE); 808 809 hr = m_pIQNet->SetOpt( 810 QNET_OPTION_QOS_DATA_BUFFER, 811 &m_hostGameSessionData, 812 sizeof(GameSessionData) 813 ); 814} 815 816bool CPlatformNetworkManagerXbox::_StartGame() 817{ 818 // Set the options that now allow players to join this game 819 BOOL enableJip = TRUE; // Must always be true othewise nobody can join the game while in the PLAY state 820 m_pIQNet->SetOpt( QNET_OPTION_JOIN_IN_PROGRESS_ALLOWED, &enableJip, sizeof BOOL ); 821 BOOL enableInv = !IsLocalGame(); 822 m_pIQNet->SetOpt( QNET_OPTION_INVITES_ALLOWED, &enableInv, sizeof BOOL ); 823 BOOL enablePres = !IsPrivateGame() && !IsLocalGame(); 824 m_pIQNet->SetOpt( QNET_OPTION_PRESENCE_JOIN_MODE, &enablePres, sizeof BOOL ); 825 826 return ( m_pIQNet->StartGame() == S_OK ); 827} 828 829int CPlatformNetworkManagerXbox::JoinGame(FriendSessionInfo *searchResult, int localUsersMask, int primaryUserIndex) 830{ 831 // Being a bit over-cautious here, but the xbox code pre-refactoring took a copy of XSESSION_SEARCHRESULT (although not in static memory) 832 // so seems safest to replicate this kind of thing here rather than risk data being pointed to by the searchResult being altered whilst 833 // JoinGameFromSearchResult is running. 834 static XSESSION_SEARCHRESULT searchResultCopy; 835 searchResultCopy = searchResult->searchResult; 836 HRESULT hr = m_pIQNet->JoinGameFromSearchResult( 837 primaryUserIndex, // dwUserIndex 838 localUsersMask, // dwUserMask 839 &searchResultCopy ); // pSearchResult 840 841 842 if( FAILED( hr ) ) 843 { 844 app.DebugPrintf( "Failed joining game (err = 0x%08x)!\n", hr ); 845 } 846 847 switch( hr ) 848 { 849 case S_OK: 850 return CGameNetworkManager::JOINGAME_SUCCESS; 851 case QNET_E_SESSION_FULL: 852 return CGameNetworkManager::JOINGAME_FAIL_SERVER_FULL; 853 default: 854 return CGameNetworkManager::JOINGAME_FAIL_GENERAL; 855 } 856} 857 858bool CPlatformNetworkManagerXbox::SetLocalGame(bool isLocal) 859{ 860 if( m_pIQNet->GetState() == QNET_STATE_IDLE ) 861 { 862 QNET_SESSIONTYPE sessionType = isLocal ? QNET_SESSIONTYPE_LOCAL : QNET_SESSIONTYPE_LIVE_STANDARD; 863 m_pIQNet->SetOpt(QNET_OPTION_TYPE_SESSIONTYPE, &sessionType , sizeof QNET_SESSIONTYPE); 864 865 // The default value for this is QNET_LIVE_STATS_MODE_AUTO, but that decides based on the players 866 // in when the game starts. As we may want a non-live player to join the game we cannot have stats enabled 867 // when we create the sessions. As a result of this, the NotifyWriteStats callback will not be called for 868 // LIVE players that are connected to LIVE so we write their stats data on a state change. 869 QNET_LIVE_STATS_MODE statsMode = isLocal ? QNET_LIVE_STATS_MODE_DISABLED : QNET_LIVE_STATS_MODE_ENABLED; 870 m_pIQNet->SetOpt(QNET_OPTION_LIVE_STATS_MODE, &statsMode , sizeof QNET_LIVE_STATS_MODE); 871 872 // Also has a default of QNET_LIVE_PRESENCE_MODE_AUTO as above, although the effects are less of an issue 873 QNET_LIVE_PRESENCE_MODE presenceMode = isLocal ? QNET_LIVE_PRESENCE_MODE_NOT_ADVERTISED : QNET_LIVE_PRESENCE_MODE_ADVERTISED; 874 m_pIQNet->SetOpt(QNET_OPTION_LIVE_PRESENCE_MODE, &presenceMode , sizeof QNET_LIVE_PRESENCE_MODE); 875 876 m_bIsOfflineGame = isLocal; 877 app.DebugPrintf("Setting as local game: %s\n", isLocal ? "yes" : "no" ); 878 } 879 else 880 { 881 app.DebugPrintf("Tried to change QNet Session type while not in idle state\n"); 882 } 883 return true; 884} 885 886void CPlatformNetworkManagerXbox::SetPrivateGame(bool isPrivate) 887{ 888 app.DebugPrintf("Setting as private game: %s\n", isPrivate ? "yes" : "no" ); 889 m_bIsPrivateGame = isPrivate; 890} 891 892void CPlatformNetworkManagerXbox::RegisterPlayerChangedCallback(int iPad, void (*callback)(void *callbackParam, INetworkPlayer *pPlayer, bool leaving), void *callbackParam) 893{ 894 playerChangedCallback[iPad] = callback; 895 playerChangedCallbackParam[iPad] = callbackParam; 896} 897 898void CPlatformNetworkManagerXbox::UnRegisterPlayerChangedCallback(int iPad, void (*callback)(void *callbackParam, INetworkPlayer *pPlayer, bool leaving), void *callbackParam) 899{ 900 if(playerChangedCallbackParam[iPad] == callbackParam) 901 { 902 playerChangedCallback[iPad] = NULL; 903 playerChangedCallbackParam[iPad] = NULL; 904 } 905} 906 907void CPlatformNetworkManagerXbox::HandleSignInChange() 908{ 909 return; 910} 911 912bool CPlatformNetworkManagerXbox::_RunNetworkGame() 913{ 914 // We delay actually starting the session so that we know the game server is running by the time the clients try to join 915 // This does result in a host advantage 916 HRESULT hr = m_pIQNet->StartGame(); 917 if(FAILED(hr)) return false; 918 919 // Set the options that now allow players to join this game 920 BOOL enableJip = TRUE; // Must always be true othewise nobody can join the game while in the PLAY state 921 m_pIQNet->SetOpt( QNET_OPTION_JOIN_IN_PROGRESS_ALLOWED, &enableJip, sizeof BOOL ); 922 BOOL enableInv = !IsLocalGame(); 923 m_pIQNet->SetOpt( QNET_OPTION_INVITES_ALLOWED, &enableInv, sizeof BOOL ); 924 BOOL enablePres = !IsPrivateGame() && !IsLocalGame(); 925 m_pIQNet->SetOpt( QNET_OPTION_PRESENCE_JOIN_MODE, &enablePres, sizeof BOOL ); 926 927 return true; 928} 929 930void CPlatformNetworkManagerXbox::UpdateAndSetGameSessionData(INetworkPlayer *pNetworkPlayerLeaving /*= NULL*/) 931{ 932 DWORD playerCount = m_pIQNet->GetPlayerCount(); 933 934 if( this->m_bLeavingGame ) 935 return; 936 937 if( GetHostPlayer() == NULL ) 938 return; 939 940 for(unsigned int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; ++i) 941 { 942 if( i < playerCount ) 943 { 944 INetworkPlayer *pNetworkPlayer = GetPlayerByIndex(i); 945 946 // We can call this from NotifyPlayerLeaving but at that point the player is still considered in the session 947 if( pNetworkPlayer != pNetworkPlayerLeaving ) 948 { 949 m_hostGameSessionData.players[i] = ((NetworkPlayerXbox *)pNetworkPlayer)->GetUID(); 950 951 char *temp; 952 temp = (char *)wstringtofilename( pNetworkPlayer->GetOnlineName() ); 953 memcpy(m_hostGameSessionData.szPlayers[i],temp,XUSER_NAME_SIZE); 954 } 955 else 956 { 957 m_hostGameSessionData.players[i] = NULL; 958 memset(m_hostGameSessionData.szPlayers[i],0,XUSER_NAME_SIZE); 959 } 960 } 961 else 962 { 963 m_hostGameSessionData.players[i] = NULL; 964 memset(m_hostGameSessionData.szPlayers[i],0,XUSER_NAME_SIZE); 965 } 966 } 967 968 m_hostGameSessionData.hostPlayerUID = ((NetworkPlayerXbox *)GetHostPlayer())->GetQNetPlayer()->GetXuid(); 969 m_hostGameSessionData.m_uiGameHostSettings = app.GetGameHostOption(eGameHostOption_All); 970 971 HRESULT hr = S_OK; 972 hr = m_pIQNet->SetOpt( 973 QNET_OPTION_QOS_DATA_BUFFER, 974 &m_hostGameSessionData, 975 sizeof(GameSessionData) 976 ); 977} 978 979int CPlatformNetworkManagerXbox::RemovePlayerOnSocketClosedThreadProc( void* lpParam ) 980{ 981 INetworkPlayer *pNetworkPlayer = (INetworkPlayer *)lpParam; 982 983 Socket *socket = pNetworkPlayer->GetSocket(); 984 985 if( socket != NULL ) 986 { 987 //printf("Waiting for socket closed event\n"); 988 socket->m_socketClosedEvent->WaitForSignal(INFINITE); 989 990 //printf("Socket closed event has fired\n"); 991 // 4J Stu - Clear our reference to this socket 992 pNetworkPlayer->SetSocket( NULL ); 993 delete socket; 994 } 995 996 return g_pPlatformNetworkManager->RemoveLocalPlayer( pNetworkPlayer ); 997} 998 999bool CPlatformNetworkManagerXbox::RemoveLocalPlayer( INetworkPlayer *pNetworkPlayer ) 1000{ 1001 if( pNetworkPlayer->IsLocal() ) 1002 { 1003 return ( m_pIQNet->RemoveLocalPlayerByUserIndex( pNetworkPlayer->GetUserIndex() ) == S_OK ); 1004 } 1005 1006 return true; 1007} 1008 1009CPlatformNetworkManagerXbox::PlayerFlags::PlayerFlags(INetworkPlayer *pNetworkPlayer, unsigned int count) 1010{ 1011 // 4J Stu - Don't assert, just make it a multiple of 8! This count is calculated from a load of separate values, 1012 // and makes tweaking world/render sizes a pain if we hit an assert here 1013 count = (count + 8 - 1) & ~(8 - 1); 1014 //assert( ( count % 8 ) == 0 ); 1015 this->m_pNetworkPlayer = pNetworkPlayer; 1016 this->flags = new unsigned char [ count / 8 ]; 1017 memset( this->flags, 0, count / 8 ); 1018 this->count = count; 1019} 1020CPlatformNetworkManagerXbox::PlayerFlags::~PlayerFlags() 1021{ 1022 delete [] flags; 1023} 1024 1025// Add a player to the per system flag storage - if we've already got a player from that system, copy its flags over 1026void CPlatformNetworkManagerXbox::SystemFlagAddPlayer(INetworkPlayer *pNetworkPlayer) 1027{ 1028 PlayerFlags *newPlayerFlags = new PlayerFlags( pNetworkPlayer, m_flagIndexSize); 1029 // If any of our existing players are on the same system, then copy over flags from that one 1030 for( unsigned int i = 0; i < m_playerFlags.size(); i++ ) 1031 { 1032 if( pNetworkPlayer->IsSameSystem(m_playerFlags[i]->m_pNetworkPlayer) ) 1033 { 1034 memcpy( newPlayerFlags->flags, m_playerFlags[i]->flags, m_playerFlags[i]->count / 8 ); 1035 break; 1036 } 1037 } 1038 m_playerFlags.push_back(newPlayerFlags); 1039} 1040 1041// Remove a player from the per system flag storage - just maintains the m_playerFlags vector without any gaps in it 1042void CPlatformNetworkManagerXbox::SystemFlagRemovePlayer(INetworkPlayer *pNetworkPlayer) 1043{ 1044 for( unsigned int i = 0; i < m_playerFlags.size(); i++ ) 1045 { 1046 if( m_playerFlags[i]->m_pNetworkPlayer == pNetworkPlayer ) 1047 { 1048 delete m_playerFlags[i]; 1049 m_playerFlags[i] = m_playerFlags.back(); 1050 m_playerFlags.pop_back(); 1051 return; 1052 } 1053 } 1054} 1055 1056void CPlatformNetworkManagerXbox::SystemFlagReset() 1057{ 1058 for( unsigned int i = 0; i < m_playerFlags.size(); i++ ) 1059 { 1060 delete m_playerFlags[i]; 1061 } 1062 m_playerFlags.clear(); 1063} 1064 1065// Set a per system flag - this is done by setting the flag on every player that shares that system 1066void CPlatformNetworkManagerXbox::SystemFlagSet(INetworkPlayer *pNetworkPlayer, int index) 1067{ 1068 if( ( index < 0 ) || ( index >= m_flagIndexSize ) ) return; 1069 if( pNetworkPlayer == NULL ) return; 1070 1071 for( unsigned int i = 0; i < m_playerFlags.size(); i++ ) 1072 { 1073 if( pNetworkPlayer->IsSameSystem(m_playerFlags[i]->m_pNetworkPlayer) ) 1074 { 1075 m_playerFlags[i]->flags[ index / 8 ] |= ( 128 >> ( index % 8 ) ); 1076 } 1077 } 1078} 1079 1080// Get value of a per system flag - can be read from the flags of the passed in player as anything else sent to that 1081// system should also have been duplicated here 1082bool CPlatformNetworkManagerXbox::SystemFlagGet(INetworkPlayer *pNetworkPlayer, int index) 1083{ 1084 if( ( index < 0 ) || ( index >= m_flagIndexSize ) ) return false; 1085 if( pNetworkPlayer == NULL ) 1086 { 1087 return false; 1088 } 1089 1090 for( unsigned int i = 0; i < m_playerFlags.size(); i++ ) 1091 { 1092 if( m_playerFlags[i]->m_pNetworkPlayer == pNetworkPlayer ) 1093 { 1094 return ( ( m_playerFlags[i]->flags[ index / 8 ] & ( 128 >> ( index % 8 ) ) ) != 0 ); 1095 } 1096 } 1097 return false; 1098} 1099 1100wstring CPlatformNetworkManagerXbox::GatherStats() 1101{ 1102 return L"Queue messages: " + _toString(((NetworkPlayerXbox *)GetHostPlayer())->GetQNetPlayer()->GetSendQueueSize( NULL, QNET_GETSENDQUEUESIZE_MESSAGES ) ) 1103 + L" Queue bytes: " + _toString( ((NetworkPlayerXbox *)GetHostPlayer())->GetQNetPlayer()->GetSendQueueSize( NULL, QNET_GETSENDQUEUESIZE_BYTES ) ); 1104} 1105 1106wstring CPlatformNetworkManagerXbox::GatherRTTStats() 1107{ 1108 wstring stats(L"Rtt: "); 1109 1110 wchar_t stat[32]; 1111 1112 for(unsigned int i = 0; i < GetPlayerCount(); ++i) 1113 { 1114 IQNetPlayer *pQNetPlayer = ((NetworkPlayerXbox *)GetPlayerByIndex( i ))->GetQNetPlayer(); 1115 1116 if(!pQNetPlayer->IsLocal()) 1117 { 1118 ZeroMemory(stat,sizeof(WCHAR)*32); 1119 swprintf(stat, 32, L"%d: %d/", i, pQNetPlayer->GetCurrentRtt() ); 1120 stats.append(stat); 1121 } 1122 } 1123 return stats; 1124} 1125 1126void CPlatformNetworkManagerXbox::TickSearch() 1127{ 1128 if( m_bSearchPending ) 1129 { 1130 if( m_bSearchResultsReady ) 1131 { 1132 m_currentSearchResultsCount[m_lastSearchPad] = m_searchResultsCount[m_lastSearchPad]; 1133 1134 // Store the current search results so that we don't delete them too early 1135 if( m_pCurrentSearchResults[m_lastSearchPad] != NULL ) 1136 { 1137 delete m_pCurrentSearchResults[m_lastSearchPad]; 1138 m_pCurrentSearchResults[m_lastSearchPad] = NULL; 1139 } 1140 m_pCurrentSearchResults[m_lastSearchPad] = m_pSearchResults[m_lastSearchPad]; 1141 m_pSearchResults[m_lastSearchPad] = NULL; 1142 1143 if( m_pCurrentQoSResult[m_lastSearchPad] != NULL ) 1144 { 1145 XNetQosRelease(m_pCurrentQoSResult[m_lastSearchPad]); 1146 m_pCurrentQoSResult[m_lastSearchPad] = NULL; 1147 } 1148 m_pCurrentQoSResult[m_lastSearchPad] = m_pQoSResult[m_lastSearchPad]; 1149 m_pQoSResult[m_lastSearchPad] = NULL; 1150 1151 if( m_SessionsUpdatedCallback != NULL ) m_SessionsUpdatedCallback(m_pSearchParam); 1152 m_bSearchResultsReady = false; 1153 m_bSearchPending = false; 1154 } 1155 } 1156 else 1157 { 1158 // Don't start searches unless we have registered a callback 1159 if( m_SessionsUpdatedCallback != NULL && (m_lastSearchStartTime[g_NetworkManager.GetPrimaryPad()] + MINECRAFT_XSESSION_SEARCH_DELAY_MILLISECONDS) < GetTickCount() ) 1160 { 1161 SearchForGames(); 1162 } 1163 } 1164} 1165 1166void CPlatformNetworkManagerXbox::SearchForGames() 1167{ 1168 // Don't start a new search until we have finished the last one 1169 if(m_bSearchPending) return; 1170 1171 m_lastSearchPad = g_NetworkManager.GetPrimaryPad(); 1172 1173 m_lastSearchStartTime[m_lastSearchPad] = GetTickCount(); 1174 m_bSearchPending = true; 1175 m_bSearchResultsReady = false; 1176 1177 for(AUTO_VAR(it, friendsSessions[m_lastSearchPad].begin()); it < friendsSessions[m_lastSearchPad].end(); ++it) 1178 { 1179 delete (*it); 1180 } 1181 friendsSessions[m_lastSearchPad].clear(); 1182 1183 if( m_pSearchResults[m_lastSearchPad] != NULL ) 1184 { 1185 delete m_pSearchResults[m_lastSearchPad]; 1186 m_pSearchResults[m_lastSearchPad] = NULL; 1187 } 1188 if( m_pQoSResult[m_lastSearchPad] != NULL ) 1189 { 1190 XNetQosRelease(m_pQoSResult[m_lastSearchPad]); 1191 m_pQoSResult[m_lastSearchPad] = NULL; 1192 } 1193 1194 bool bMultiplayerAllowed = g_NetworkManager.IsSignedInLive( g_NetworkManager.GetPrimaryPad() ) && g_NetworkManager.AllowedToPlayMultiplayer( g_NetworkManager.GetPrimaryPad() ); 1195 1196 if( bMultiplayerAllowed ) 1197 { 1198 // PARTY 1199 XPARTY_USER_LIST partyUserList; 1200 HRESULT partyResult = XPartyGetUserList( &partyUserList ); 1201 if((partyResult != XPARTY_E_NOT_IN_PARTY) && (partyUserList.dwUserCount>1)) 1202 { 1203 for(unsigned int i = 0; i<partyUserList.dwUserCount; i++) 1204 { 1205 if( 1206 ( (partyUserList.Users[i].dwFlags & XPARTY_USER_ISLOCAL ) != XPARTY_USER_ISLOCAL ) && 1207 ( (partyUserList.Users[i].dwFlags & XPARTY_USER_ISINGAMESESSION) == XPARTY_USER_ISINGAMESESSION ) && 1208 partyUserList.Users[i].dwTitleId == TITLEID_MINECRAFT 1209 ) 1210 { 1211 bool sessionAlreadyAdded = false; 1212 for(AUTO_VAR(it, friendsSessions[m_lastSearchPad].begin()); it < friendsSessions[m_lastSearchPad].end(); ++it) 1213 { 1214 FriendSessionInfo *current = *it; 1215 if( memcmp( &partyUserList.Users[i].SessionInfo.sessionID, &current->sessionId, sizeof(SessionID) ) == 0 ) 1216 { 1217 //printf("We already have this session from another player.\n"); 1218 sessionAlreadyAdded = true; 1219 break; 1220 } 1221 } 1222 1223 if(!sessionAlreadyAdded) 1224 { 1225 FriendSessionInfo *sessionInfo = new FriendSessionInfo(); 1226 sessionInfo->sessionId = partyUserList.Users[i].SessionInfo.sessionID; 1227 sessionInfo->hasPartyMember = true; 1228 friendsSessions[m_lastSearchPad].push_back(sessionInfo); 1229 } 1230 } 1231 } 1232 } 1233 1234 // FRIENDS 1235 1236 DWORD bufferSize = 0; 1237 HANDLE hFriendsEnumerator; 1238 DWORD hr = XFriendsCreateEnumerator( 1239 g_NetworkManager.GetPrimaryPad(), 1240 0, 1241 MAX_FRIENDS, 1242 &bufferSize, 1243 &hFriendsEnumerator 1244 ); 1245 1246 char *buffer = new char[bufferSize]; 1247 DWORD itemsReturned; 1248 DWORD result = XEnumerate( 1249 hFriendsEnumerator, 1250 buffer, 1251 bufferSize, 1252 &itemsReturned, 1253 NULL 1254 ); 1255 1256 DWORD flagPlayingOnline = XONLINE_FRIENDSTATE_FLAG_ONLINE; // | XONLINE_FRIENDSTATE_FLAG_PLAYING; 1257 1258 XONLINE_FRIEND *friends = (XONLINE_FRIEND *)buffer; 1259 for(unsigned int i = 0; i<itemsReturned; i++) 1260 { 1261 //printf("%s\n",friends[i].szGamertag); 1262 if( (friends[i].dwFriendState & flagPlayingOnline) == flagPlayingOnline && 1263 ( (friends[i].dwFriendState & XONLINE_FRIENDSTATE_FLAG_JOINABLE) == XONLINE_FRIENDSTATE_FLAG_JOINABLE || 1264 (friends[i].dwFriendState & XONLINE_FRIENDSTATE_FLAG_JOINABLE_FRIENDS_ONLY) == XONLINE_FRIENDSTATE_FLAG_JOINABLE_FRIENDS_ONLY) 1265 && ( friends[i].dwFriendState & ( XONLINE_FRIENDSTATE_FLAG_SENTREQUEST | XONLINE_FRIENDSTATE_FLAG_RECEIVEDREQUEST ) ) == 0 1266 && friends[i].dwTitleID == TITLEID_MINECRAFT) 1267 { 1268 //printf("Valid game to join\n"); 1269 1270 bool sessionAlreadyAdded = false; 1271 for(AUTO_VAR(it, friendsSessions[m_lastSearchPad].begin()); it < friendsSessions[m_lastSearchPad].end(); ++it) 1272 { 1273 FriendSessionInfo *current = *it; 1274 if( memcmp( &friends[i].sessionID, &current->sessionId, sizeof(SessionID) ) == 0 ) 1275 { 1276 //printf("We already have this session from another player.\n"); 1277 sessionAlreadyAdded = true; 1278 break; 1279 } 1280 } 1281 1282 if(!sessionAlreadyAdded) 1283 { 1284 FriendSessionInfo *sessionInfo = new FriendSessionInfo(); 1285 sessionInfo->sessionId = friends[i].sessionID; 1286 friendsSessions[m_lastSearchPad].push_back(sessionInfo); 1287 //g_NetworkManager.SearchForGameById(friends[i].sessionID,&SearchForGameCallback, m_hObj); 1288 //++m_searches; 1289 } 1290 } 1291 } 1292 delete [] buffer; 1293 } 1294 1295 if( friendsSessions[m_lastSearchPad].empty() ) 1296 { 1297 SetSearchResultsReady(); 1298 return; 1299 } 1300 1301 DWORD sessionIDCount = min( XSESSION_SEARCH_MAX_IDS, friendsSessions[m_lastSearchPad].size() ); 1302 SessionID *sessionIDList = new SessionID[sessionIDCount]; 1303 1304 for(DWORD i = 0; i < sessionIDCount; ++i) 1305 { 1306 sessionIDList[i] = friendsSessions[m_lastSearchPad].at(i)->sessionId; 1307 } 1308 1309 DWORD dwStatus = ERROR_SUCCESS; 1310 DWORD cbResults = 0; 1311 // In this first call, explicitly pass in a null pointer and a buffer size 1312 // of 0. This forces the function to set cbResults to the correct buffer 1313 // size. 1314 1315 dwStatus = XSessionSearchByIds( 1316 sessionIDCount, 1317 sessionIDList, 1318 g_NetworkManager.GetPrimaryPad(), 1319 &cbResults, // Pass in the address of the size variable 1320 NULL, 1321 NULL // This example uses the synchronous model 1322 ); 1323 1324 XOVERLAPPED *pOverlapped = new XOVERLAPPED(); 1325 ZeroMemory(pOverlapped, sizeof(XOVERLAPPED)); 1326 1327 // If the function returns ERROR_INSUFFICIENT_BUFFER cbResults has been 1328 // changed to reflect the size buffer that will be necessary for this call. Use 1329 // the new size to allocate a buffer of the appropriate size. 1330 if (ERROR_INSUFFICIENT_BUFFER == dwStatus && cbResults > 0) 1331 { 1332 // Allocate this on the main thread rather in the search thread which might run out of memory 1333 m_pSearchResults[m_lastSearchPad] = (XSESSION_SEARCHRESULT_HEADER *) new BYTE[cbResults]; 1334 1335 if (!m_pSearchResults[m_lastSearchPad]) 1336 { 1337 dwStatus = ERROR_OUTOFMEMORY; 1338 // Handle this "out of title memory" case and abort the read. 1339 } 1340 1341 ZeroMemory(m_pSearchResults[m_lastSearchPad], cbResults); 1342 1343 // Next, call the function again with the exact same parameters, except 1344 // this time use the modified buffer size and a pointer to a buffer that 1345 // matches it. 1346 dwStatus = XSessionSearchByIds( 1347 sessionIDCount, 1348 sessionIDList, 1349 g_NetworkManager.GetPrimaryPad(), 1350 &cbResults, // Pass in the address of the size variable 1351 m_pSearchResults[m_lastSearchPad], 1352 pOverlapped 1353 ); 1354 } 1355 1356 // Test the result of either the first call (if it failed with 1357 // something other than ERROR_INSUFFICIENT_BUFFER) or the subsequent call. 1358 // If the function does not succeed after allocating a buffer of the appropriate size 1359 // succeed, something else is wrong. 1360 if (ERROR_IO_PENDING != dwStatus)//ERROR_SUCCESS != dwStatus) 1361 { 1362 // Handle other errors. 1363 app.DebugPrintf("An error occured while enumerating sessions\n"); 1364 SetSearchResultsReady(); 1365 1366 delete [] sessionIDList; 1367 } 1368 else if ( cbResults > 0 ) 1369 { 1370 SearchForGamesData *threadData = new SearchForGamesData(); 1371 threadData->sessionIDCount = sessionIDCount; 1372 threadData->searchBuffer = m_pSearchResults[m_lastSearchPad]; 1373 threadData->ppQos = &m_pQoSResult[m_lastSearchPad]; 1374 threadData->pOverlapped = pOverlapped; 1375 threadData->sessionIDList = sessionIDList; 1376 1377 m_SearchingThread = new C4JThread(&CPlatformNetworkManagerXbox::SearchForGamesThreadProc, threadData, "SearchForGames"); 1378 m_SearchingThread->SetProcessor( 2 ); 1379 m_SearchingThread->Run(); 1380 } 1381 else 1382 { 1383 SetSearchResultsReady(); 1384 } 1385} 1386 1387int CPlatformNetworkManagerXbox::SearchForGamesThreadProc( void* lpParameter ) 1388{ 1389 SearchForGamesData *threadData = (SearchForGamesData *)lpParameter; 1390 1391 DWORD sessionIDCount = threadData->sessionIDCount; 1392 1393 XOVERLAPPED *pOverlapped = threadData->pOverlapped; 1394 1395 DWORD dwStatus = ERROR_SUCCESS; 1396 DWORD cbResults = sessionIDCount; 1397 XSESSION_SEARCHRESULT_HEADER *pSearchResults = (XSESSION_SEARCHRESULT_HEADER *)threadData->searchBuffer; 1398 1399 while( !XHasOverlappedIoCompleted(pOverlapped) ) 1400 { 1401 Sleep(100); 1402 } 1403 delete pOverlapped; 1404 delete [] threadData->sessionIDList; 1405 1406 if( pSearchResults->dwSearchResults == 0 ) 1407 { 1408 g_pPlatformNetworkManager->SetSearchResultsReady(); 1409 return 0; 1410 } 1411 1412 // TODO 4J Stu - Is there a nicer way to allocate less here? 1413 const XNADDR *QoSxnaddr[XSESSION_SEARCH_MAX_IDS];// = new XNADDR*[sessionIDCount]; 1414 const SessionID *QoSxnkid[XSESSION_SEARCH_MAX_IDS];// = new XNKID*[sessionIDCount]; // Note SessionID is just typedef'd to be a XNKID on xbox 1415 const XNKEY *QoSxnkey[XSESSION_SEARCH_MAX_IDS];// = new XNKEY*[sessionIDCount]; 1416 1417 1418 for(DWORD i = 0; i < pSearchResults->dwSearchResults; ++i) 1419 { 1420 QoSxnaddr[i] = &pSearchResults->pResults[i].info.hostAddress; 1421 QoSxnkid[i] = &pSearchResults->pResults[i].info.sessionID; 1422 QoSxnkey[i] = &pSearchResults->pResults[i].info.keyExchangeKey; 1423 } 1424 // Create an event object that is autoreset with an initial state of "not signaled". 1425 // Pass this event handle to the QoSLookup to receive notification of each QoS lookup. 1426 HANDLE QoSLookupHandle = CreateEvent(NULL, false, false, NULL); 1427 1428 *threadData->ppQos = new XNQOS(); 1429 1430 INT iRet = XNetQosLookup( 1431 pSearchResults->dwSearchResults, // Number of remote Xbox 360 consoles to probe 1432 QoSxnaddr, // Array of pointers to XNADDR structures 1433 QoSxnkid, // Array of pointers to XNKID structures that contain session IDs for the remote Xbox 360 consoles 1434 QoSxnkey, // Array of pointers to XNKEY structures that contain key-exchange keys for the remote Xbox 360 consoles 1435 0, // Number of security gateways to probe 1436 NULL, // Pointer to an array of IN_ADDR structures that contain the IP addresses of the security gateways 1437 NULL, // Pointer to an array of service IDs for the security gateway 1438 8, // Number of desired probe replies to receive 1439 0, // Maximum upstream bandwidth that the outgoing QoS probe packets can consume 1440 0, // Flags 1441 QoSLookupHandle, // Event handle 1442 threadData->ppQos ); // Pointer to a pointer to an XNQOS structure that receives the results from the QoS probes 1443 1444 if( 0 != iRet ) 1445 { 1446 app.DebugPrintf( "XNetQosLookup failed with error 0x%08x", iRet); 1447 g_pPlatformNetworkManager->SetSearchResultsReady(); 1448 } 1449 else 1450 { 1451 1452 //m_bQoSTesting = TRUE; 1453 1454 // Wait for results to all complete. cxnqosPending will eventually hit zero. 1455 // Pause thread waiting for QosLookup events to be triggered. 1456 while ( (*threadData->ppQos)->cxnqosPending != 0 ) 1457 { 1458 // 4J Stu - We could wait for INFINITE if we weren't watching for the kill flag 1459 WaitForSingleObject(QoSLookupHandle, 100); 1460 } 1461 1462 // Close handle 1463 CloseHandle( QoSLookupHandle ); 1464 1465 g_pPlatformNetworkManager->SetSearchResultsReady(pSearchResults->dwSearchResults); 1466 } 1467 1468 return 0; 1469} 1470 1471void CPlatformNetworkManagerXbox::SetSearchResultsReady(int resultCount ) 1472{ 1473 m_bSearchResultsReady = true; 1474 m_searchResultsCount[m_lastSearchPad] = resultCount; 1475} 1476 1477vector<FriendSessionInfo *> *CPlatformNetworkManagerXbox::GetSessionList(int iPad, int localPlayers, bool partyOnly) 1478{ 1479 vector<FriendSessionInfo *> *filteredList = new vector<FriendSessionInfo *>();; 1480 1481 const XSESSION_SEARCHRESULT *pSearchResult; 1482 const XNQOSINFO * pxnqi; 1483 1484 if( m_currentSearchResultsCount[iPad] > 0 ) 1485 { 1486 // Loop through all the results. 1487 for( DWORD dwResult = 0; dwResult < m_currentSearchResultsCount[iPad]; dwResult++ ) 1488 { 1489 pSearchResult = &m_pCurrentSearchResults[iPad]->pResults[dwResult]; 1490 1491 // No room for us, so ignore it 1492 // 4J Stu - pSearchResult should never be NULL, but just in case... 1493 if(pSearchResult == NULL || pSearchResult->dwOpenPublicSlots < localPlayers) continue; 1494 1495 bool foundSession = false; 1496 FriendSessionInfo *sessionInfo = NULL; 1497 AUTO_VAR(itFriendSession, friendsSessions[iPad].begin()); 1498 for(itFriendSession = friendsSessions[iPad].begin(); itFriendSession < friendsSessions[iPad].end(); ++itFriendSession) 1499 { 1500 sessionInfo = *itFriendSession; 1501 if(memcmp( &pSearchResult->info.sessionID, &sessionInfo->sessionId, sizeof(SessionID) ) == 0 && (!partyOnly || (partyOnly && sessionInfo->hasPartyMember) ) ) 1502 { 1503 sessionInfo->searchResult = *pSearchResult; 1504 sessionInfo->displayLabel = new wchar_t[100]; 1505 ZeroMemory( sessionInfo->displayLabel, 100 * sizeof(wchar_t) ); 1506 foundSession = true; 1507 break; 1508 } 1509 } 1510 1511 // We received a search result for a session no longer in our list of friends sessions 1512 if(!foundSession) continue; 1513 1514 // Print some info about this result. 1515 app.DebugPrintf( "Search result %u:\n", dwResult ); 1516 //app.DebugPrintf( " public slots open = %u, filled = %u\n", pSearchResult->dwOpenPublicSlots, pSearchResult->dwFilledPublicSlots ); 1517 //app.DebugPrintf( " private slots open = %u, filled = %u\n", pSearchResult->dwOpenPrivateSlots, pSearchResult->dwFilledPrivateSlots ); 1518 1519 // See if this result was contacted successfully via QoS probes. 1520 pxnqi = &m_pCurrentQoSResult[iPad]->axnqosinfo[dwResult]; 1521 if( pxnqi->bFlags & XNET_XNQOSINFO_TARGET_CONTACTED ) 1522 { 1523 // Print the round trip time and the rough estimation of 1524 // bandwidth. 1525 //app.DebugPrintf( " RTT min = %u, med = %u\n", pxnqi->wRttMinInMsecs, pxnqi->wRttMedInMsecs ); 1526 //app.DebugPrintf( " bps up = %u, down = %u\n", pxnqi->dwUpBitsPerSec, pxnqi->dwDnBitsPerSec ); 1527 1528 if(pxnqi->cbData > 0) 1529 { 1530 sessionInfo->data = *(GameSessionData *)pxnqi->pbData; 1531 1532 wstring gamerName = convStringToWstring(sessionInfo->data.hostName); 1533#ifndef _CONTENT_PACKAGE 1534 if(app.DebugSettingsOn() && (app.GetGameSettingsDebugMask()&(1L<<eDebugSetting_DebugLeaderboards))) 1535 { 1536 swprintf(sessionInfo->displayLabel,app.GetString(IDS_GAME_HOST_NAME),L"WWWWWWWWWWWWWWWW"); 1537 } 1538 else 1539#endif 1540 { 1541 swprintf(sessionInfo->displayLabel,app.GetString(IDS_GAME_HOST_NAME),gamerName.c_str() ); 1542 } 1543 } 1544 else 1545 { 1546 swprintf(sessionInfo->displayLabel,app.GetString(IDS_GAME_HOST_NAME_UNKNOWN)); 1547 } 1548 sessionInfo->displayLabelLength = wcslen( sessionInfo->displayLabel ); 1549 1550 // If this host wasn't disabled use this one. 1551 if( !( pxnqi->bFlags & XNET_XNQOSINFO_TARGET_DISABLED ) && 1552 sessionInfo->data.netVersion == MINECRAFT_NET_VERSION && 1553 sessionInfo->data.isJoinable) 1554 { 1555 //printf("This game is valid\n"); 1556 //if( foundSession ) friendsSessions.erase(itFriendSession); 1557 FriendSessionInfo *newInfo = new FriendSessionInfo(); 1558 newInfo->data = sessionInfo->data; 1559 newInfo->displayLabel = new wchar_t[100]; 1560 memcpy(newInfo->displayLabel, sessionInfo->displayLabel, 100 * sizeof(wchar_t) ); 1561 newInfo->displayLabelLength = sessionInfo->displayLabelLength; 1562 newInfo->hasPartyMember = sessionInfo->hasPartyMember; 1563 newInfo->searchResult = sessionInfo->searchResult; 1564 newInfo->sessionId = sessionInfo->sessionId; 1565 filteredList->push_back(newInfo); 1566 } 1567 #ifndef _CONTENT_PACKAGE 1568 if( sessionInfo->data.netVersion != MINECRAFT_NET_VERSION ) 1569 { 1570 wprintf(L"%ls version of %d does not match our version of %d\n", sessionInfo->displayLabel, sessionInfo->data.netVersion, MINECRAFT_NET_VERSION); 1571 } 1572 #endif 1573 } 1574 } 1575 } 1576 1577 return filteredList; 1578} 1579 1580// This runs through the search results for a session matching sessionId, then returns the full details in foundSessionInfo 1581bool CPlatformNetworkManagerXbox::GetGameSessionInfo(int iPad, SessionID sessionId, FriendSessionInfo *foundSessionInfo) 1582{ 1583 HRESULT hr = E_FAIL; 1584 1585 const XSESSION_SEARCHRESULT *pSearchResult; 1586 const XNQOSINFO * pxnqi; 1587 1588 if( m_currentSearchResultsCount[iPad] > 0 ) 1589 { 1590 // Loop through all the results. 1591 for( DWORD dwResult = 0; dwResult < m_currentSearchResultsCount[iPad]; dwResult++ ) 1592 { 1593 pSearchResult = &m_pCurrentSearchResults[iPad]->pResults[dwResult]; 1594 1595 if(memcmp( &pSearchResult->info.sessionID, &sessionId, sizeof(SessionID) ) != 0) continue; 1596 1597 bool foundSession = false; 1598 FriendSessionInfo *sessionInfo = NULL; 1599 AUTO_VAR(itFriendSession, friendsSessions[iPad].begin()); 1600 for(itFriendSession = friendsSessions[iPad].begin(); itFriendSession < friendsSessions[iPad].end(); ++itFriendSession) 1601 { 1602 sessionInfo = *itFriendSession; 1603 if(memcmp( &pSearchResult->info.sessionID, &sessionInfo->sessionId, sizeof(SessionID) ) == 0) 1604 { 1605 sessionInfo->searchResult = *pSearchResult; 1606 sessionInfo->displayLabel = new wchar_t[100]; 1607 ZeroMemory( sessionInfo->displayLabel, 100 * sizeof(wchar_t) ); 1608 foundSession = true; 1609 break; 1610 } 1611 } 1612 1613 // We received a search result for a session no longer in our list of friends sessions 1614 if(!foundSession) break; 1615 1616 // See if this result was contacted successfully via QoS probes. 1617 pxnqi = &m_pCurrentQoSResult[iPad]->axnqosinfo[dwResult]; 1618 if( pxnqi->bFlags & XNET_XNQOSINFO_TARGET_CONTACTED ) 1619 { 1620 1621 if(pxnqi->cbData > 0) 1622 { 1623 sessionInfo->data = *(GameSessionData *)pxnqi->pbData; 1624 1625 wstring gamerName = convStringToWstring(sessionInfo->data.hostName); 1626 swprintf(sessionInfo->displayLabel,app.GetString(IDS_GAME_HOST_NAME),L"MWWWWWWWWWWWWWWM");// gamerName.c_str() ); 1627 } 1628 else 1629 { 1630 swprintf(sessionInfo->displayLabel,app.GetString(IDS_GAME_HOST_NAME_UNKNOWN)); 1631 } 1632 sessionInfo->displayLabelLength = wcslen( sessionInfo->displayLabel ); 1633 1634 // If this host wasn't disabled use this one. 1635 if( !( pxnqi->bFlags & XNET_XNQOSINFO_TARGET_DISABLED ) && 1636 sessionInfo->data.netVersion == MINECRAFT_NET_VERSION && 1637 sessionInfo->data.isJoinable) 1638 { 1639 foundSessionInfo->data = sessionInfo->data; 1640 if(foundSessionInfo->displayLabel != NULL) delete [] foundSessionInfo->displayLabel; 1641 foundSessionInfo->displayLabel = new wchar_t[100]; 1642 memcpy(foundSessionInfo->displayLabel, sessionInfo->displayLabel, 100 * sizeof(wchar_t) ); 1643 foundSessionInfo->displayLabelLength = sessionInfo->displayLabelLength; 1644 foundSessionInfo->hasPartyMember = sessionInfo->hasPartyMember; 1645 foundSessionInfo->searchResult = sessionInfo->searchResult; 1646 foundSessionInfo->sessionId = sessionInfo->sessionId; 1647 1648 hr = S_OK; 1649 } 1650 } 1651 } 1652 } 1653 1654 return ( hr == S_OK ); 1655} 1656 1657void CPlatformNetworkManagerXbox::SetSessionsUpdatedCallback( void (*SessionsUpdatedCallback)(LPVOID pParam), LPVOID pSearchParam ) 1658{ 1659 m_SessionsUpdatedCallback = SessionsUpdatedCallback; m_pSearchParam = pSearchParam; 1660} 1661 1662void CPlatformNetworkManagerXbox::GetFullFriendSessionInfo( FriendSessionInfo *foundSession, void (* FriendSessionUpdatedFn)(bool success, void *pParam), void *pParam ) 1663{ 1664 FriendSessionUpdatedFn(true, pParam); 1665} 1666 1667void CPlatformNetworkManagerXbox::ForceFriendsSessionRefresh() 1668{ 1669 app.DebugPrintf("Resetting friends session search data\n"); 1670 for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) 1671 { 1672 m_searchResultsCount[i] = 0; 1673 m_lastSearchStartTime[i] = 0; 1674 delete m_pSearchResults[i]; 1675 m_pSearchResults[i] = NULL; 1676 } 1677} 1678 1679INetworkPlayer *CPlatformNetworkManagerXbox::addNetworkPlayer(IQNetPlayer *pQNetPlayer) 1680{ 1681 NetworkPlayerXbox *pNetworkPlayer = new NetworkPlayerXbox(pQNetPlayer); 1682 pQNetPlayer->SetCustomDataValue((ULONG_PTR)pNetworkPlayer); 1683 currentNetworkPlayers.push_back( pNetworkPlayer ); 1684 return pNetworkPlayer; 1685} 1686 1687void CPlatformNetworkManagerXbox::removeNetworkPlayer(IQNetPlayer *pQNetPlayer) 1688{ 1689 INetworkPlayer *pNetworkPlayer = getNetworkPlayer(pQNetPlayer); 1690 for( AUTO_VAR(it, currentNetworkPlayers.begin()); it != currentNetworkPlayers.end(); it++ ) 1691 { 1692 if( *it == pNetworkPlayer ) 1693 { 1694 currentNetworkPlayers.erase(it); 1695 return; 1696 } 1697 } 1698} 1699 1700INetworkPlayer *CPlatformNetworkManagerXbox::getNetworkPlayer(IQNetPlayer *pQNetPlayer) 1701{ 1702 return pQNetPlayer ? (INetworkPlayer *)(pQNetPlayer->GetCustomDataValue()) : NULL; 1703} 1704 1705 1706INetworkPlayer *CPlatformNetworkManagerXbox::GetLocalPlayerByUserIndex(int userIndex ) 1707{ 1708 return getNetworkPlayer(m_pIQNet->GetLocalPlayerByUserIndex(userIndex)); 1709} 1710 1711INetworkPlayer *CPlatformNetworkManagerXbox::GetPlayerByIndex(int playerIndex) 1712{ 1713 return getNetworkPlayer(m_pIQNet->GetPlayerByIndex(playerIndex)); 1714} 1715 1716INetworkPlayer * CPlatformNetworkManagerXbox::GetPlayerByXuid(PlayerUID xuid) 1717{ 1718 return getNetworkPlayer( m_pIQNet->GetPlayerByXuid(xuid)) ; 1719} 1720 1721INetworkPlayer * CPlatformNetworkManagerXbox::GetPlayerBySmallId(unsigned char smallId) 1722{ 1723 return getNetworkPlayer(m_pIQNet->GetPlayerBySmallId(smallId)); 1724} 1725 1726INetworkPlayer *CPlatformNetworkManagerXbox::GetHostPlayer() 1727{ 1728 return getNetworkPlayer(m_pIQNet->GetHostPlayer()); 1729} 1730 1731bool CPlatformNetworkManagerXbox::IsHost() 1732{ 1733 return m_pIQNet->IsHost() && !m_bHostChanged; 1734} 1735 1736bool CPlatformNetworkManagerXbox::JoinGameFromInviteInfo( int userIndex, int userMask, const INVITE_INFO *pInviteInfo) 1737{ 1738 return ( m_pIQNet->JoinGameFromInviteInfo( userIndex, userMask, pInviteInfo ) == S_OK); 1739} 1740 1741void CPlatformNetworkManagerXbox::SetSessionTexturePackParentId( int id ) 1742{ 1743 m_hostGameSessionData.texturePackParentId = id; 1744} 1745 1746void CPlatformNetworkManagerXbox::SetSessionSubTexturePackId( int id ) 1747{ 1748 m_hostGameSessionData.subTexturePackId = id; 1749} 1750 1751void CPlatformNetworkManagerXbox::Notify(int ID, ULONG_PTR Param) 1752{ 1753 m_pIQNet->Notify( ID, Param ); 1754} 1755 1756bool CPlatformNetworkManagerXbox::IsInSession() 1757{ 1758 return m_pIQNet->GetState() != QNET_STATE_IDLE; 1759} 1760 1761bool CPlatformNetworkManagerXbox::IsInGameplay() 1762{ 1763 return m_pIQNet->GetState() == QNET_STATE_GAME_PLAY; 1764} 1765 1766bool CPlatformNetworkManagerXbox::IsReadyToPlayOrIdle() 1767{ 1768 return true; 1769}