//----------------------------------------------------------------------------- // // Xbox Matchmaking Definitions for Title: Jedi Academy [0x4C41000B] // Generated by MatchSim // //----------------------------------------------------------------------------- #pragma once #include #include #include //----------------------------------------------------------------------------- // Constants //----------------------------------------------------------------------------- // // Attribute IDs ID num Data Type // ------ ---------------------------- const DWORD XATTRIB_GAME_TYPE = 0x0001 | X_ATTRIBUTE_DATATYPE_INTEGER; const DWORD XATTRIB_CURRENT_MAP = 0x0002 | X_ATTRIBUTE_DATATYPE_INTEGER; const DWORD XATTRIB_SESSION_NAME = 0x0003 | X_ATTRIBUTE_DATATYPE_STRING; const DWORD XATTRIB_FRIENDLY_FIRE = 0x0004 | X_ATTRIBUTE_DATATYPE_INTEGER; const DWORD XATTRIB_JEDI_MASTERY = 0x0005 | X_ATTRIBUTE_DATATYPE_INTEGER; const DWORD XATTRIB_TOTAL_PLAYERS = 0x0007 | X_ATTRIBUTE_DATATYPE_INTEGER; const DWORD XATTRIB_SABER_ONLY = 0x0008 | X_ATTRIBUTE_DATATYPE_INTEGER; const DWORD XATTRIB_DEDICATED = 0x0009 | X_ATTRIBUTE_DATATYPE_INTEGER; // // Attribute Maximum Lengths // (for strings, this doesn't include the terminating NULL) // const DWORD XATTRIB_SESSION_NAME_MAX_LEN = 16; // SessionName attribute // Specify X_MATCH_NULL_INTEGER for optional integer query arguments const ULONGLONG X_MATCH_NULL_INTEGER = 0x7FFFFFFFFFFFFFFFui64; // Maximum number of sessions returned by OptiMatch query const DWORD MAX_OPTI_MATCH_RESULTS = 25; // Maximum number of sessions returned by JoinSessionByID query const DWORD MAX_JOIN_SESSION_BY_ID_RESULTS = 1; // Number of QoS probes const DWORD NUM_QOS_PROBES = 8; // Maximum bandwidth to consume for QoS probes const DWORD QOS_BITS_PER_SEC = 16000; //----------------------------------------------------------------------------- // Types //----------------------------------------------------------------------------- // Helper class for getting/setting blob attributes class CBlob { public: CBlob() : m_wLength( 0 ), m_pvData( NULL ) {} CBlob( WORD wLength, const PVOID pvData ) : m_wLength( wLength), m_pvData( pvData) {} CBlob( const CBlob & b ) { *this = b; } CBlob & operator=( const CBlob & b ) { m_wLength = b.Length; m_pvData = b.Data; return *this; } BOOL operator==( const CBlob & b ) const { return m_wLength == b.Length && memcmp( m_pvData, b.Data, b.Length ) == 0; } BOOL IsNull() { return m_pvData == NULL; } __declspec( property( put = SetData, get=GetData ) ) const PVOID Data; const PVOID GetData() const { return m_pvData; } VOID SetData( const PVOID pvData ) { m_pvData = pvData; } __declspec( property( put = SetLength, get=GetLength ) ) WORD Length; WORD GetLength() const { return m_wLength; } VOID SetLength( WORD wLength ) { m_wLength = wLength; } private: WORD m_wLength; PVOID m_pvData; }; // A null blob is defined as having a NULL pointer #define NULL_BLOB CBlob( 0, NULL ) // Macro for declaring "blob literals" (much like the _T() macro does for strings) #define B( length, ptr ) CBlob( length, (const PVOID) ptr ) class CSession { public: CSession(); ~CSession(); HRESULT Create(); HRESULT Update(); HRESULT Delete(); HRESULT Process(); VOID Reset(); DWORD PublicFilled; DWORD PublicOpen; DWORD PrivateFilled; DWORD PrivateOpen; XNKEY KeyExchangeKey; XNKID SessionID; BOOL IsUpdating() const { return m_State == STATE_UPDATING; } BOOL IsDeleting() const { return m_State == STATE_DELETING; } BOOL IsCreating() const { return m_State == STATE_CREATING; } BOOL Exists() const { return m_State == STATE_ACTIVE || IsUpdating(); } // Attribute Accessors BOOL IsListening() const { return m_bListening; } __declspec( property( put = SetQosResponse, get = GetQosResponse ) ) CBlob QosResponse; CBlob GetQosResponse(); VOID SetQosResponse( CBlob Value ); VOID Listen( BOOL bEnable = TRUE, DWORD dwBitsPerSec = 0 ); static const DWORD NO_WAIT = 1; __declspec( property( put = SetGameType, get=GetGameType ) ) ULONGLONG GameType; ULONGLONG GetGameType(); VOID SetGameType( ULONGLONG Value ); __declspec( property( put = SetCurrentMap, get=GetCurrentMap ) ) ULONGLONG CurrentMap; ULONGLONG GetCurrentMap(); VOID SetCurrentMap( ULONGLONG Value ); __declspec( property( put = SetSessionName, get=GetSessionName ) ) const WCHAR * SessionName; const WCHAR * GetSessionName(); VOID SetSessionName( const WCHAR * Value ); __declspec( property( put = SetFriendlyFire, get=GetFriendlyFire ) ) ULONGLONG FriendlyFire; ULONGLONG GetFriendlyFire(); VOID SetFriendlyFire( ULONGLONG Value ); __declspec( property( put = SetJediMastery, get=GetJediMastery ) ) ULONGLONG JediMastery; ULONGLONG GetJediMastery(); VOID SetJediMastery( ULONGLONG Value ); __declspec( property( put = SetTotalPlayers, get=GetTotalPlayers ) ) ULONGLONG TotalPlayers; ULONGLONG GetTotalPlayers(); VOID SetTotalPlayers( ULONGLONG Value ); __declspec( property( put = SetSaberOnly, get=GetSaberOnly ) ) ULONGLONG SaberOnly; ULONGLONG GetSaberOnly(); VOID SetSaberOnly( ULONGLONG Value ); __declspec( property( put = SetDedicated, get=GetDedicated ) ) ULONGLONG Dedicated; ULONGLONG GetDedicated(); VOID SetDedicated( ULONGLONG Value ); private: // The m_Attributes array is accessed using predefined constants: enum { GAME_TYPE_INDEX, CURRENT_MAP_INDEX, SESSION_NAME_INDEX, FRIENDLY_FIRE_INDEX, JEDI_MASTERY_INDEX, TOTAL_PLAYERS_INDEX, SABER_ONLY_INDEX, DEDICATED_INDEX, NUM_ATTRIBUTES }; XONLINE_ATTRIBUTE m_Attributes[NUM_ATTRIBUTES]; // Storage for the SessionName string attribute WCHAR m_strSessionName[XATTRIB_SESSION_NAME_MAX_LEN+1]; // Qos listening struct QosQEntry { XNKID SessionID; // Session to unregister DWORD dwStartTick; // Time entry was added struct QosQEntry *pNext; // Next item in the queue }; class CSessionQosQ { public: CSessionQosQ(); VOID Add( XNKID & SessionID, DWORD dwStartTick ); VOID Remove( XNKID &SessionID ); VOID Dequeue(); const QosQEntry *Head() const { return m_pHead; } const QosQEntry *Tail() const { return m_pTail; } private: QosQEntry *m_pHead; QosQEntry *m_pTail; }; CSessionQosQ m_SessionQosQ; BOOL m_bListening; // Listening for Qos probes CBlob m_QosResponse; VOID PurgeSessionQ( BOOL fRemoveAll = FALSE ); VOID PurgeSessionQHead(); HRESULT ProcessStateCreateSession(); HRESULT ProcessStateUpdateSession(); HRESULT ProcessStateDeleteSession(); HRESULT ProcessStateActiveSession(); VOID Close(); VOID SetupAttributes(); XONLINETASK_HANDLE m_hSessionTask; enum STATE { STATE_IDLE, STATE_CREATING, STATE_UPDATING, STATE_DELETING, STATE_ACTIVE }; STATE m_State; BOOL m_bKeyRegistered; BOOL m_bUpdate; }; // // COptiMatchResult represents a single return result from the // OptiMatch query // #pragma pack(push, 1) class COptiMatchResult { public: // The query return attributes must come first, and in the order // returned by the query ULONGLONG GameType; ULONGLONG CurrentMap; WCHAR SessionName[XATTRIB_SESSION_NAME_MAX_LEN+1]; ULONGLONG FriendlyFire; ULONGLONG JediMastery; ULONGLONG SaberOnly; ULONGLONG Dedicated; XNKID SessionID; XNKEY KeyExchangeKey; XNADDR HostAddress; DWORD PublicOpen; DWORD PrivateOpen; DWORD PublicFilled; DWORD PrivateFilled; XNQOSINFO* pQosInfo; }; #pragma pack(pop) // Collection of results for the OptiMatch query class COptiMatchQueryResults { public: COptiMatchQueryResults() { m_dwSize = 0; } DWORD Size() { return m_dwSize; } COptiMatchResult &operator[]( DWORD i ) { return v[i]; } private: void Clear() { m_dwSize = 0; } void Remove( DWORD i ) { assert( i < m_dwSize ); if( i < m_dwSize ) { m_dwSize--; memcpy( &v[i], &v[i+1], sizeof( v[0] ) * ( m_dwSize - i ) ); } } void SetSize( DWORD dwSize ) { m_dwSize = dwSize; } friend class COptiMatchQuery; COptiMatchResult v[MAX_OPTI_MATCH_RESULTS]; DWORD m_dwSize; }; // // Query object for OptiMatch query (id 0x1) // class COptiMatchQuery { public: COptiMatchQuery(); ~COptiMatchQuery(); COptiMatchQueryResults Results; HRESULT Process(); void Cancel(); void Clear(); BOOL Done() const { return m_State == STATE_DONE; } BOOL Succeeded() const { return SUCCEEDED( m_hrQuery ); } HRESULT Query( ULONGLONG GameType, // Optional: X_MATCH_NULL_INTEGER to omit ULONGLONG CurrentMap, // Optional: X_MATCH_NULL_INTEGER to omit ULONGLONG MinimumPlayers, ULONGLONG MaximumPlayers, ULONGLONG FriendlyFire, // Optional: X_MATCH_NULL_INTEGER to omit ULONGLONG JediMastery, // Optional: X_MATCH_NULL_INTEGER to omit ULONGLONG SaberOnly, // Optional: X_MATCH_NULL_INTEGER to omit ULONGLONG Dedicated // Optional: X_MATCH_NULL_INTEGER to omit ); BOOL IsRunning() const { return m_State == STATE_RUNNING || m_State == STATE_PROBING_CONNECTIVITY; } BOOL IsProbing() const { return m_State == STATE_PROBING_BANDWIDTH; } HRESULT Probe(); private: // Quality of Service const XNADDR *m_rgpXnAddr[ MAX_OPTI_MATCH_RESULTS ]; const XNKID *m_rgpXnKid [ MAX_OPTI_MATCH_RESULTS ]; const XNKEY *m_rgpXnKey [ MAX_OPTI_MATCH_RESULTS ]; XNQOS *m_pXnQos; enum STATE { STATE_IDLE, STATE_RUNNING, STATE_PROBING_CONNECTIVITY, STATE_PROBING_BANDWIDTH, STATE_DONE }; STATE m_State; HRESULT m_hrQuery; XONLINETASK_HANDLE m_hSearchTask; }; // // CJoinSessionByIDResult represents a single return result from the // JoinSessionByID query // #pragma pack(push, 1) class CJoinSessionByIDResult { public: XNKID SessionID; XNKEY KeyExchangeKey; XNADDR HostAddress; DWORD PublicOpen; DWORD PrivateOpen; DWORD PublicFilled; DWORD PrivateFilled; XNQOSINFO* pQosInfo; }; #pragma pack(pop) // Collection of results for the JoinSessionByID query class CJoinSessionByIDQueryResults { public: CJoinSessionByIDQueryResults() { m_dwSize = 0; } DWORD Size() { return m_dwSize; } CJoinSessionByIDResult &operator[]( DWORD i ) { return v[i]; } private: void Clear() { m_dwSize = 0; } void Remove( DWORD i ) { assert( i < m_dwSize ); if( i < m_dwSize ) { m_dwSize--; memcpy( &v[i], &v[i+1], sizeof( v[0] ) * ( m_dwSize - i ) ); } } void SetSize( DWORD dwSize ) { m_dwSize = dwSize; } friend class CJoinSessionByIDQuery; CJoinSessionByIDResult v[MAX_JOIN_SESSION_BY_ID_RESULTS]; DWORD m_dwSize; }; // // Query object for JoinSessionByID query (id 0x2) // class CJoinSessionByIDQuery { public: CJoinSessionByIDQuery(); ~CJoinSessionByIDQuery(); CJoinSessionByIDQueryResults Results; HRESULT Process(); void Cancel(); void Clear(); BOOL Done() const { return m_State == STATE_DONE; } BOOL Succeeded() const { return SUCCEEDED( m_hrQuery ); } HRESULT Query( ULONGLONG SessionID ); BOOL IsRunning() const { return m_State == STATE_RUNNING || m_State == STATE_PROBING_CONNECTIVITY; } BOOL IsProbing() const { return m_State == STATE_PROBING_BANDWIDTH; } HRESULT Probe(); private: // Quality of Service const XNADDR *m_rgpXnAddr[ MAX_JOIN_SESSION_BY_ID_RESULTS ]; const XNKID *m_rgpXnKid [ MAX_JOIN_SESSION_BY_ID_RESULTS ]; const XNKEY *m_rgpXnKey [ MAX_JOIN_SESSION_BY_ID_RESULTS ]; XNQOS *m_pXnQos; enum STATE { STATE_IDLE, STATE_RUNNING, STATE_PROBING_CONNECTIVITY, STATE_PROBING_BANDWIDTH, STATE_DONE }; STATE m_State; HRESULT m_hrQuery; XONLINETASK_HANDLE m_hSearchTask; };