aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.Client/Durango/Network/DQRNetworkManager.h
blob: 5f7b8d90875ca763b94b953d627233d868263622 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
#pragma once

#include "DQRNetworkPlayer.h"
#include "..\Minecraft.World\C4JThread.h"
#include <collection.h>

class IDQRNetworkManagerListener;
class PartyController;

class DQRNetworkManager;
class ChatIntegrationLayer;

namespace MXS = Microsoft::Xbox::Services;
namespace MXSM = Microsoft::Xbox::Services::Multiplayer;
namespace MXSS = Microsoft::Xbox::Services::Social;
namespace WXM = Windows::Xbox::Multiplayer;
namespace WXN = Windows::Xbox::Networking;
namespace WXNRs = Windows::Xbox::Networking::RealtimeSession;
namespace WFC = Windows::Foundation::Collections;

#define MATCH_SESSION_TEMPLATE_NAME    L"PeerToHostTemplate"
#define MAX_PLAYERS_IN_TEMPLATE		   8

using namespace std;

ref class DQRNetworkManagerEventHandlers sealed
{
internal:
	DQRNetworkManagerEventHandlers(DQRNetworkManager *pDQRNet);
public:
	void Setup(WXNRs::Session^ session);
	void Pulldown(WXNRs::Session^ session);

    void DataReceivedHandler(Platform::Object^ session, WXNRs::DataReceivedEventArgs^ args);
    void SessionAddressDataChangedHandler(Platform::Object^ session, WXNRs::SessionAddressDataChangedEventArgs^ args);
    void SessionStatusUpdateHandler(Platform::Object^ session, WXNRs::SessionStatusUpdateEventArgs^ args);
    void AddedSessionAddressHandler(Platform::Object^ session, WXNRs::AddedSessionAddressEventArgs^ args);
    void RemovedSessionAddressHandler(Platform::Object^ session, WXNRs::RemovedSessionAddressEventArgs^ args);
    void GlobalSessionDataChangedHandler(Platform::Object^ session, WXNRs::GlobalSessionDataChangedEventArgs^ args);

private:
    Windows::Foundation::EventRegistrationToken	m_dataReceivedToken;
    Windows::Foundation::EventRegistrationToken	m_sessionStatusToken;
    Windows::Foundation::EventRegistrationToken	m_sessionAddressToken;
    Windows::Foundation::EventRegistrationToken	m_addedSessionToken;
    Windows::Foundation::EventRegistrationToken	m_removedSessionToken;
    Windows::Foundation::EventRegistrationToken	m_globalDataToken;

	DQRNetworkManager *m_pDQRNet;
};

typedef enum
{
	DQR_INTERNAL_ASSIGN_SMALL_IDS,
	DQR_INTERNAL_UNASSIGN_SMALL_ID,
	DQR_INTERNAL_PLAYER_TABLE,
	DQR_INTERNAL_ADD_PLAYER_FAILED,
};

class DQRConnectionInfo
{
public:
	typedef enum
	{
		ConnectionState_HeaderByte0,
		ConnectionState_HeaderByte1,
		ConnectionState_ReadBytes
	} eDQRConnectionState;

	typedef enum
	{
		ConnectionState_InternalHeaderByte,
		ConnectionState_InternalAssignSmallIdMask,
		ConnectionState_InternalAssignSmallId0,
		ConnectionState_InternalAssignSmallId1,
		ConnectionState_InternalAssignSmallId2,
		ConnectionState_InternalAssignSmallId3,
		ConnectionState_InternalRoomSyncData,
		ConnectionState_InternalAddPlayerFailedData,
	} eDQRInternalDataState;

	DQRConnectionInfo();
	void		  Reset();

	eDQRConnectionState		m_state;
	eDQRInternalDataState	m_internalDataState;

	int						m_currentChannel;
	bool					m_internalFlag;
	int						m_bytesRemaining;
	int						m_roomSyncDataBytesRead;
	int						m_roomSyncDataBytesToRead;
	unsigned char *			m_pucRoomSyncData;
	int						m_addFailedPlayerDataBytesRead;
	int						m_addFailedPlayerDataBytesToRead;
	unsigned char *			m_pucAddFailedPlayerData;
	unsigned char			m_smallId[4];
	bool					m_channelActive[4];
	unsigned char			m_smallIdReadMask;
	unsigned char			*m_pucsmallIdReadMaskResolved;
	bool					m_initialPacketReceived;
};


class DQRNetworkManager
{
	friend class PartyController;
	friend ref class DQRNetworkManagerEventHandlers;
	friend class DQRNetworkPlayer;
	friend class ChatIntegrationLayer;
public:
	static const int JOIN_PACKET_RESEND_DELAY_MS = 200;
	static const int JOIN_PACKET_RESEND_TIMEOUT_MS = 20000;
	static const int JOIN_RESERVATION_WAIT_TIME = 30000;
	static const int JOIN_CREATE_SESSION_MAX_ATTEMPTS = 5;

	static const int PRIMARY_PLAYER_LEAVING_PARTY_WAIT_MS = 20000;		// Time between primary player leaving and when we should respond to it, to allow time for us to receive a new party for them to be going to if they are just changing party rather than leaving altogether

	class SessionInfo
	{
	public:
		SessionInfo(wstring& sessionName, wstring& serviceConfig, wstring& sessionTemplate);
		SessionInfo();
		bool m_detailsValid;
		wstring m_sessionName;
		wstring m_serviceConfig;
		wstring m_sessionTemplate;
	};

	static const int MAX_LOCAL_PLAYER_COUNT = 4;
	static const int MAX_ONLINE_PLAYER_COUNT = 8;
	static const int MAX_ONLINE_PLAYER_NAME_LENGTH = 21;

	// This class stores everything about a player that must be synchronised between machines. 
	class PlayerSyncData
	{
	public:
		wchar_t						*m_XUID;								// XUID / XboxUserIds are passed round as decimal strings on Xbox 1
		uint32_t					m_sessionAddress;						// XRNS session address for this player, ie can identify which machine this player is on
		uint8_t						m_smallId;								// Assigned by DQRNetworkManager, to attach a permanent id to this player (until we have to wrap round), to match a similar concept in qnet
		uint8_t						m_channel;								// Local index / communication channel within session address, of player on this machine
		wchar_t						m_name[MAX_ONLINE_PLAYER_NAME_LENGTH];
	};

	class RoomSyncData
	{
	public:
		int				playerCount;
		PlayerSyncData	players[MAX_ONLINE_PLAYER_COUNT];
	};

	class HostGamertagResolveDetails
	{
	public:;
		DQRNetworkPlayer*	m_pPlayer;
		wstring				m_name;
		unsigned int		m_sessionAddress;
		int					m_channel;
		bool				m_sync;
	};

	DQRNetworkManager(IDQRNetworkManagerListener *listener);
	void Initialise();
	void EnableDebugXBLContext(MXS::XboxLiveContext^ XBLContext);

	void CreateAndJoinSession(int userMask, unsigned char *customSessionData, unsigned int customSessionDataSize, bool offline);
	void JoinSession(int playerMask);
	void JoinSessionFromInviteInfo(int playerMask);
	bool AddUsersToSession(int playerMask, MXSM::MultiplayerSessionReference^ sessionRef );
	void UpdateCustomSessionData();

	bool AddLocalPlayerByUserIndex(int userIndex);
	bool RemoveLocalPlayerByUserIndex(int userIndex);

	bool IsHost();
	bool IsInSession();

	// Player retrieval
	int					GetPlayerCount();
	int					GetOnlinePlayerCount();
	DQRNetworkPlayer	*GetPlayerByIndex(int idx);
	DQRNetworkPlayer	*GetPlayerBySmallId(int idx);
	DQRNetworkPlayer	*GetPlayerByXuid(PlayerUID xuid);
	wstring				GetDisplayNameByGamertag(wstring gamertag);
	DQRNetworkPlayer	*GetLocalPlayerByUserIndex(int idx);
	DQRNetworkPlayer	*GetHostPlayer();
	int					GetSessionIndex(DQRNetworkPlayer *player);
	void				Tick();
	void				Tick_XRNS();
	void				Tick_VoiceChat();
	void				Tick_Party();
	void				Tick_CustomSessionData();
	void				Tick_AddAndRemoveLocalPlayers();
	void				Tick_ResolveGamertags();
	void				Tick_PartyProcess();
	void				Tick_StateMachine();
	void				Tick_CheckInviteParty();

	bool				ShouldMessageForFullSession();
	void				FlagInvitedToFullSession();
	void				UnflagInvitedToFullSession();
	// Externally exposed state. All internal states are mapped to one of these broader states.
	typedef enum
	{
		DNM_STATE_INITIALISING,
		DNM_STATE_INITIALISE_FAILED,
		DNM_STATE_IDLE,

		DNM_STATE_HOSTING,
		DNM_STATE_JOINING,

		DNM_STATE_STARTING,
		DNM_STATE_PLAYING,		

		DNM_STATE_LEAVING,
		DNM_STATE_ENDING,
	} eDQRNetworkManagerState;

	eDQRNetworkManagerState												GetState();

	class SessionSearchResult
	{
	public:
		SessionSearchResult() { m_extData = NULL; }
		~SessionSearchResult() { free(m_extData); }
		wstring			m_partyId;
		wstring			m_sessionName;

		// These names/xuids reflect the server controlled list of who is actually in the game
		wstring			m_playerNames[MAX_ONLINE_PLAYER_COUNT];
		PlayerUID		m_playerXuids[MAX_ONLINE_PLAYER_COUNT];
		int				m_playerCount;

		// This count & set of xuids reflects the session document list of who is in the game
		wstring			m_sessionXuids[MAX_ONLINE_PLAYER_COUNT];
		int				m_usedSlotCount;

		void			*m_extData;
	};

protected:
	// NOTE: If anything changes in here, then the mapping from internal -> external state needs to be updated (m_INTtoEXTStateMappings, defined in the cpp file)
	typedef enum
	{
		DNM_INT_STATE_INITIALISING,
		DNM_INT_STATE_INITIALISE_FAILED,
		DNM_INT_STATE_IDLE,
		DNM_INT_STATE_HOSTING,
		DNM_INT_STATE_HOSTING_WAITING_TO_PLAY,
		DNM_INT_STATE_HOSTING_FAILED,
		DNM_INT_STATE_JOINING,
		DNM_INT_STATE_JOINING_WAITING_FOR_RESERVATIONS,
		DNM_INT_STATE_JOINING_GET_SDA,
		DNM_INT_STATE_JOINING_WAITING_FOR_SDA,
		DNM_INT_STATE_JOINING_CREATE_SESSION,
		DNM_INT_STATE_JOINING_WAITING_FOR_ACTIVE_SESSION,
		DNM_INT_STATE_JOINING_SENDING_UNRELIABLE,
		DNM_INT_STATE_JOINING_FAILED_TIDY_UP,
		DNM_INT_STATE_JOINING_FAILED,
		DNM_INT_STATE_STARTING,
		DNM_INT_STATE_PLAYING,
		DNM_INT_STATE_LEAVING,
		DNM_INT_STATE_LEAVING_FAILED,
		DNM_INT_STATE_ENDING,
		DNM_INT_STATE_COUNT
	} eDQRNetworkManagerInternalState;

	typedef enum
	{
		DNM_ADD_PLAYER_STATE_IDLE,
		DNM_ADD_PLAYER_STATE_PROCESSING,
		DNM_ADD_PLAYER_STATE_COMPLETE_SUCCESS,
		DNM_ADD_PLAYER_STATE_COMPLETE_FAIL,
		DNM_ADD_PLAYER_STATE_COMPLETE_FAIL_FULL,
	} eDQRAddLocalPlayerState;

	typedef enum
	{
		DNM_REMOVE_PLAYER_STATE_IDLE,
		DNM_REMOVE_PLAYER_STATE_PROCESSING,
		DNM_REMOVE_PLAYER_STATE_COMPLETE_SUCCESS,
		DNM_REMOVE_PLAYER_STATE_COMPLETE_FAIL,
	} eDQRRemoveLocalPlayerState;

	class StateChangeInfo
	{
	public:
		eDQRNetworkManagerState m_oldState;
		eDQRNetworkManagerState m_newState;
		StateChangeInfo(eDQRNetworkManagerState oldState, eDQRNetworkManagerState newState) : m_oldState(oldState), m_newState(newState) {}
	};

	typedef enum
	{
		// Incoming messages
		RTS_MESSAGE_DATA_RECEIVED,
		RTS_MESSAGE_DATA_RECEIVED_CHAT,
		RTS_MESSAGE_ADDED_SESSION_ADDRESS,
		RTS_MESSAGE_REMOVED_SESSION_ADDRESS,
		RTS_MESSAGE_STATUS_ACTIVE,
		RTS_MESSAGE_STATUS_TERMINATED,

		// Outgoing messages
		RTS_MESSAGE_START_CLIENT,
		RTS_MESSAGE_START_HOST,
		RTS_MESSAGE_TERMINATE,
		RTS_MESSAGE_SEND_DATA,
	} eRTSMessageType;

	typedef enum
	{
		RTS_MESSAGE_FLAG_BROADCAST_MODE = 1,
		RTS_MESSAGE_FLAG_RELIABLE = 2,
		RTS_MESSAGE_FLAG_SEQUENTIAL = 4,
		RTS_MESSAGE_FLAG_COALESCE = 8,
		RTS_MESSAGE_FLAG_GAME_CHANNEL = 16,
	} eRTSFlags;

	class RTS_Message
	{
	public:
		eRTSMessageType m_eType;
		unsigned int	m_sessionAddress;
		unsigned char	*m_pucData;
		unsigned int	m_dataSize;
		unsigned int	m_flags;
	};

	std::queue<StateChangeInfo>											m_stateChangeQueue;
	CRITICAL_SECTION													m_csStateChangeQueue;
	CRITICAL_SECTION													m_csSendBytes;
	CRITICAL_SECTION													m_csPartyViewVector;
	std::queue<RTS_Message>												m_RTSMessageQueueIncoming;
	CRITICAL_SECTION													m_csRTSMessageQueueIncoming;
	std::queue<RTS_Message>												m_RTSMessageQueueOutgoing;
	CRITICAL_SECTION													m_csRTSMessageQueueOutgoing;
private:
	void																SetState(DQRNetworkManager::eDQRNetworkManagerInternalState state);
	static const eDQRNetworkManagerState								m_INTtoEXTStateMappings[DNM_INT_STATE_COUNT];
	eDQRNetworkManagerInternalState										m_state;
	eDQRNetworkManagerState												m_stateExternal;
	__int64																m_lastUnreliableSendTime;
	__int64																m_firstUnreliableSendTime;
	__int64																m_startedWaitingForReservationsTime;
	unsigned char														*m_customSessionData;
	unsigned int														m_customSessionDataSize;
	int																	m_customDataDirtyUpdateTicks;
	std::shared_ptr<ChatIntegrationLayer>								m_chat;

	eDQRAddLocalPlayerState												m_addLocalPlayerState;
	DQRNetworkPlayer													*m_addLocalPlayerSuccessPlayer;
	int																	m_addLocalPlayerSuccessIndex;
	int																	m_addLocalPlayerFailedIndex;

	eDQRRemoveLocalPlayerState											m_removeLocalPlayerState;
	int																	m_removeLocalPlayerIndex;

	Windows::Xbox::System::User^										m_primaryUser;
	MXS::XboxLiveContext^												m_primaryUserXboxLiveContext;
	WXN::SecureDeviceAssociationTemplate^								m_associationTemplate;

	CRITICAL_SECTION													m_csRoomSyncData;
	RoomSyncData														m_roomSyncData;
	DQRNetworkPlayer													*m_players[MAX_ONLINE_PLAYER_COUNT];	

	IDQRNetworkManagerListener											*m_listener;
	PartyController														*m_partyController;
	DQRNetworkManagerEventHandlers^										m_eventHandlers;
	WXNRs::Session^														m_XRNS_Session;
	unsigned int														m_XRNS_LocalAddress;
	unsigned int														m_XRNS_OldestAddress;
	MXSM::MultiplayerSession^											m_multiplayerSession;
	WXN::SecureDeviceAssociation^										m_sda;
	Platform::String^													m_secureDeviceAddressBase64;
	unsigned char														m_currentSmallId;
	unsigned char														m_hostSmallId;
	bool																m_isHosting;
	bool																m_isInSession;
	bool																m_isOfflineGame;
public:
	int																	m_currentUserMask;
private:
	int																	m_joinSessionUserMask;
	Platform::Array<Platform::String^>^									m_joinSessionXUIDs;
	int																	m_joinSmallIdMask;

	Platform::Array<BYTE>^												m_remoteSocketAddress;
	Platform::Array<BYTE>^												m_localSocketAddress;
	int																	m_joinCreateSessionAttempts;

	C4JThread															*m_CreateSessionThread;
	C4JThread															*m_LeaveRoomThread;		
	C4JThread															*m_TidyUpJoinThread;
	C4JThread															*m_UpdateCustomSessionDataThread;
	C4JThread															*m_RTS_DoWorkThread;
	C4JThread															*m_CheckPartyInviteThread;

	bool																m_notifyForFullParty;

	unordered_map<unsigned int,DQRConnectionInfo *>						m_sessionAddressToConnectionInfoMapHost;	// For host - there may be more than one remote session attached to this listening session
	unsigned int														m_sessionAddressFromSmallId[256];			// For host - for mapping back from small Id, to session address
	unsigned char														m_channelFromSmallId[256];					// For host and client, for mapping back from small Id, to channel
	DQRConnectionInfo													m_connectionInfoClient;						// For client
	unsigned int														m_hostSessionAddress;						// For client

	CRITICAL_SECTION													m_csHostGamertagResolveResults;
	queue<HostGamertagResolveDetails *>									m_hostGamertagResolveResults;

	void																AddPlayerFailed(Platform::String ^xuid);
	Platform::String^													RemoveBracesFromGuidString(__in Platform::String^ guid );
	void																HandleSessionChange( MXSM::MultiplayerSession^ session );
	MXSM::MultiplayerSession^											WriteSessionHelper(  MXS::XboxLiveContext^ xboxLiveContext,
																							MXSM::MultiplayerSession^ multiplayerSession,
																							MXSM::MultiplayerSessionWriteMode writeMode,
																							HRESULT& hr);
	MXSM::MultiplayerSessionMember^										GetUserMemberInSession( Windows::Xbox::System::User^ user, MXSM::MultiplayerSession^ session);
	bool																IsPlayerInSession( Platform::String^ xboxUserId, MXSM::MultiplayerSession^ session, int *smallId );

	WXM::MultiplayerSessionReference^									ConvertToWindowsXboxMultiplayerSessionReference( MXSM::MultiplayerSessionReference^ sessionRef);
	MXSM::MultiplayerSessionReference^									ConvertToMicrosoftXboxServicesMultiplayerSessionReference( WXM::MultiplayerSessionReference^ sessionRef );

	void																BytesReceived(int smallId, BYTE *bytes, int byteCount);
	void																BytesReceivedInternal(DQRConnectionInfo *connectionInfo, unsigned int sessionAddress, BYTE *bytes, int byteCount);
	void																SendBytes(int smallId, BYTE *bytes, int byteCount);
	int																	GetQueueSizeBytes();
	int																	GetQueueSizeMessages();
	void																SendBytesRaw(int smallId, BYTE *bytes, int byteCount, bool reliableAndSequential);
	void																SendBytesChat(unsigned int address, BYTE *bytes, int byteCount, bool reliable, bool sequential, bool broadcast);
	
	bool																AddRoomSyncPlayer(DQRNetworkPlayer *pPlayer, unsigned int sessionAddress, int channel);
	void																RemoveRoomSyncPlayersWithSessionAddress(unsigned int sessionAddress);
	void																RemoveRoomSyncPlayer(DQRNetworkPlayer *pPlayer);
	void																UpdateRoomSyncPlayers(RoomSyncData *pNewSyncData);
	void																SendRoomSyncInfo();
	void																SendAddPlayerFailed(Platform::String^ xuid);
	void																SendSmallId(bool reliableAndSequential, int playerMask);
	void																SendUnassignSmallId(int playerIndex);
	int																	GetSessionIndexForSmallId(unsigned char smallId);
	int																	GetSessionIndexAndSmallIdForHost(unsigned char *smallId);

	static void															LogComment( Platform::String^ strText );	
	static void															LogCommentFormat( LPCWSTR strMsg, ... );
	static void															LogCommentWithError( Platform::String^ strTest, HRESULT hr );

	static Platform::String^											GetErrorString( HRESULT hr );
	static Platform::String^											FormatString( LPCWSTR strMsg, ... );
	static Platform::String^											ConvertHResultToErrorName( HRESULT hr );

	Platform::String^													GetNextSmallIdAsJsonString();
	static int															_HostGameThreadProc( void* lpParameter );
	int																	HostGameThreadProc();
	static int															_LeaveRoomThreadProc( void* lpParameter );
	int																	LeaveRoomThreadProc();
	static int															_TidyUpJoinThreadProc( void* lpParameter );
	int																	TidyUpJoinThreadProc();
	static int															_UpdateCustomSessionDataThreadProc( void* lpParameter );
	int																	UpdateCustomSessionDataThreadProc();
	static int															_CheckInviteThreadProc(void *lpParameter);
	int																	CheckInviteThreadProc();
	static int															_RTSDoWorkThread(void* lpParameter);
	int																	RTSDoWorkThread();

	CRITICAL_SECTION													m_csVecChatPlayers;
	vector<int>															m_vecChatPlayersJoined;
public:
	void																HandleNewPartyFoundForPlayer();
	void																HandlePlayerRemovedFromParty(int playerMask);

	void																ChatPlayerJoined(int idx);
	bool																IsReadyToPlayOrIdle();
	void																StartGame();
	void																LeaveRoom();
	void																TidyUpFailedJoin();

	static void															SetInviteReceivedFlag();
	static void															SetPartyProcessJoinParty();
	static void															SetPartyProcessJoinSession(int bootUserIndex, Platform::String^ bootSessionName, Platform::String^ bootServiceConfig, Platform::String^ bootSessionTemplate);

	void																SendInviteGUI(int quadrant);
	bool																IsAddingPlayer();

	bool																FriendPartyManagerIsBusy();
	int																	FriendPartyManagerGetCount();
	bool																FriendPartyManagerSearch();
	void																FriendPartyManagerGetSessionInfo(int idx, SessionSearchResult *searchResult);
	WFC::IVectorView<WXM::UserPartyAssociation^>^						FilterPartiesByPermission(MXS::XboxLiveContext ^context, WFC::IVectorView<WXM::UserPartyAssociation^>^ partyResults);

	bool																JoinPartyFromSearchResult(SessionSearchResult *searchResult, int playerMask);
	void																CancelJoinPartyFromSearchResult();
	void																RequestDisplayName(DQRNetworkPlayer *player);
	void																SetDisplayName(PlayerUID xuid, wstring displayName);

private:
	__int64																m_playersLeftPartyTime;
	int																	m_playersLeftParty;

	bool																GetBestPartyUserIndex();
	C4JThread															*m_GetFriendPartyThread;
	static int															_GetFriendsThreadProc( void* lpParameter );
	int																	GetFriendsThreadProc();
	bool																IsSessionFriendsOfFriends(MXSM::MultiplayerSession^ session);
	bool																GetGameSessionData(MXSM::MultiplayerSession^ session, void *gameSessionData);

public:
	static Platform::Collections::Vector<Platform::String^>^			GetFriends(); 

private:
	SessionSearchResult													*m_sessionSearchResults;
	int																	m_sessionResultCount;
	bool																m_cancelJoinFromSearchResult;

	map<wstring, wstring>												m_displayNames; // Player display names by gamertag



	typedef enum
	{
		DNM_PARTY_PROCESS_NONE,
		DNM_PARTY_PROCESS_JOIN_PARTY,
		DNM_PARTY_PROCESS_JOIN_SPECIFIED
	} ePartyProcessType;
	static int															m_bootUserIndex;
	static ePartyProcessType											m_partyProcess;
	static wstring														m_bootSessionName;
	static wstring														m_bootServiceConfig;
	static wstring														m_bootSessionTemplate;
	static bool															m_inviteReceived;

	static DQRNetworkManager											*s_pDQRManager;

	static void															GetProfileCallback(LPVOID pParam, Microsoft::Xbox::Services::Social::XboxUserProfile^ profile);

	// Forced signout
	bool m_handleForcedSignOut;

	void CheckForcedSignOut();
	void HandleForcedSignOut();

	unsigned int														m_RTS_Stat_totalBytes;
	unsigned int														m_RTS_Stat_totalSends;

	void																UpdateRTSStats();

	// Incoming messages - to be called from the main thread, to get incoming messages from the RTS work thread
	void																ProcessRTSMessagesIncoming();
	void																Process_RTS_MESSAGE_DATA_RECEIVED(RTS_Message &message);
	void																Process_RTS_MESSAGE_DATA_RECEIVED_CHAT(RTS_Message &message);
	void																Process_RTS_MESSAGE_ADDED_SESSION_ADDRESS(RTS_Message &message);
	void																Process_RTS_MESSAGE_REMOVED_SESSION_ADDRESS(RTS_Message &message);
	void																Process_RTS_MESSAGE_STATUS_ACTIVE(RTS_Message &message);
	void																Process_RTS_MESSAGE_STATUS_TERMINATED(RTS_Message &message);

	// Outgoing messages - to be called from the RTS work thread, to process requests from the main thread
	
	void																ProcessRTSMessagesOutgoing();
	void																Process_RTS_MESSAGE_START_CLIENT(RTS_Message &message);
	void																Process_RTS_MESSAGE_START_HOST(RTS_Message &message);
	void																Process_RTS_MESSAGE_TERMINATE(RTS_Message &message);
	void																Process_RTS_MESSAGE_SEND_DATA(RTS_Message &message);

	// These methods are called from the main thread, to put an outgoing message onto the queue to be processed by these previous methods
	void																RTS_StartCient();
	void																RTS_StartHost();
	void																RTS_Terminate();
	void																RTS_SendData(unsigned char *pucData, unsigned int dataSize, unsigned int sessionAddress, bool reliable, bool sequential, bool coalesce, bool includeMode, bool gameChannel );

};

// Class defining interface to be implemented for class that handles callbacks
class IDQRNetworkManagerListener
{
public:
	virtual void HandleDataReceived(DQRNetworkPlayer *playerFrom, DQRNetworkPlayer *playerTo, unsigned char *data, unsigned int dataSize) = 0;
	virtual void HandlePlayerJoined(DQRNetworkPlayer *player) = 0;
	virtual void HandlePlayerLeaving(DQRNetworkPlayer *player) = 0;
	virtual void HandleStateChange(DQRNetworkManager::eDQRNetworkManagerState oldState, DQRNetworkManager::eDQRNetworkManagerState newState) = 0;
//	virtual void HandleResyncPlayerRequest(DQRNetworkPlayer **aPlayers) = 0;
	virtual void HandleAddLocalPlayerFailed(int idx, bool serverFull) = 0;
	virtual void HandleDisconnect(bool bLostRoomOnly) = 0;
	virtual void HandleInviteReceived(int playerIndex, DQRNetworkManager::SessionInfo *pInviteInfo) = 0;
	virtual bool IsSessionJoinable() = 0;
};