the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
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, ¤t->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, ¤t->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}