Initial commit.
This commit is contained in:
716
codemp/xbox/XBLive_Friends.cpp
Normal file
716
codemp/xbox/XBLive_Friends.cpp
Normal file
@@ -0,0 +1,716 @@
|
||||
// XBLIVE_FRIENDS.CPP
|
||||
//
|
||||
// wrapper to the Xbox online friends API
|
||||
//
|
||||
|
||||
#include "..\xbox\XBLive.h"
|
||||
#include "..\xbox\XBoxCommon.h"
|
||||
#include "..\xbox\XBVoice.h"
|
||||
#include "..\game\q_shared.h"
|
||||
#include "..\qcommon\qcommon.h"
|
||||
#include "..\cgame\cg_local.h"
|
||||
#include "../ui/ui_shared.h"
|
||||
#include "../qcommon/stringed_ingame.h"
|
||||
#include "../qcommon/xb_settings.h"
|
||||
|
||||
extern int RE_RegisterShaderNoMip( const char *name );
|
||||
|
||||
//DEFINES
|
||||
|
||||
#define OPEN_SLOTS_JOIN_THRESHOLD 1 // the number of public slots needed to be open to make a player joinable (TCR recommends 3)
|
||||
#define JOINABLE_CHECK_RATE 400 // 400 ticks (8ish seconds) between checks
|
||||
#define FRIEND_DISPLAY_LIMIT 10 // only display a maximum of 10 friends at a time
|
||||
#define MAX_TITLE_LENGTH 16 // allow 16 wide characters for a title's name
|
||||
#define GAME_TITLE "Jedi Knight: Jedi Academy"
|
||||
|
||||
//VARIABLES
|
||||
|
||||
XONLINE_FRIEND friendsList[MAX_FRIENDS]; // Our copy of the user's friends list
|
||||
XONLINETASK_HANDLE friendsGeneralTask;
|
||||
XONLINETASK_HANDLE enumerationTask;
|
||||
bool friendsInitialized = false;
|
||||
bool generatingFriends = false; // flag stating that we are currently enumerating the friends list
|
||||
BYTE friendChosen = 0; // the friend selcted for action
|
||||
int numFriends = 0; // number of friends found while enumerating list
|
||||
DWORD current_state = 0; // flags depicting current state as perceived by friends
|
||||
|
||||
//PROTOTYPES
|
||||
void XBL_F_GetTitleString(const DWORD titleID, char* titleString);
|
||||
HRESULT XBL_F_Invite(void);
|
||||
void XBL_F_JoinFriendUninvited( XONLINE_FRIEND* friendPlaying);
|
||||
|
||||
// ******************************************************
|
||||
// INITIALIZING FUNCTIONS
|
||||
// *******************************************************
|
||||
|
||||
// Initialize the friends functionality
|
||||
//
|
||||
void XBL_F_Init()
|
||||
{
|
||||
if( friendsInitialized )
|
||||
return;
|
||||
|
||||
// We have no friends (yet)
|
||||
numFriends = 0;
|
||||
|
||||
// system startup
|
||||
//
|
||||
HRESULT result = XOnlineFriendsStartup( NULL, &friendsGeneralTask );
|
||||
if( result != S_OK )
|
||||
{
|
||||
Com_Printf("XBLive_F - Error %d in startup\n", result);
|
||||
friendsGeneralTask = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// Default state after logging in
|
||||
XBL_F_SetState(XONLINE_FRIENDSTATE_FLAG_ONLINE, !Settings.appearOffline);
|
||||
XBL_F_SetState(XONLINE_FRIENDSTATE_FLAG_PLAYING, false);
|
||||
XBL_F_SetState(XONLINE_FRIENDSTATE_FLAG_VOICE, g_Voice.IsVoiceAllowed());
|
||||
XBL_F_SetState(XONLINE_FRIENDSTATE_FLAG_JOINABLE, false);
|
||||
|
||||
friendsInitialized = true;
|
||||
}
|
||||
|
||||
// generate the list of friends
|
||||
//
|
||||
void XBL_F_GenerateFriendsList()
|
||||
{
|
||||
if(!logged_on || generatingFriends)
|
||||
return;
|
||||
|
||||
// generate the list of records
|
||||
//
|
||||
HRESULT result = XOnlineFriendsEnumerate( IN_GetMainController(), NULL, &enumerationTask );
|
||||
if( result != S_OK )
|
||||
{
|
||||
Com_Printf("XBLive_F - Error %d using XOnlineFriendsEnumerate\n", result);
|
||||
enumerationTask = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset friends count, set flag to retrieve friends during tick
|
||||
numFriends = 0;
|
||||
generatingFriends = true;
|
||||
}
|
||||
|
||||
// ******************************************************
|
||||
// CLEANUP FUNCTIONS
|
||||
// *******************************************************
|
||||
|
||||
// stop generating the friends list
|
||||
//
|
||||
void XBL_F_ReleaseFriendsList()
|
||||
{
|
||||
if( !generatingFriends )
|
||||
return;
|
||||
|
||||
// wait for enumeration to complete
|
||||
//
|
||||
if(enumerationTask)
|
||||
{
|
||||
HRESULT result = XOnlineFriendsEnumerateFinish( enumerationTask );
|
||||
if( IS_ERROR(result) )
|
||||
{
|
||||
Com_Printf("XBLive_F - Error %d using XOnlineFriendsEnumerateFinish\n", result);
|
||||
}
|
||||
|
||||
// finish any related tasks
|
||||
//
|
||||
do
|
||||
{
|
||||
result = XOnlineTaskContinue( enumerationTask );
|
||||
if( IS_ERROR(result) )
|
||||
{
|
||||
Com_Printf("XBLive_F - Error %d enumerating friends list\n", result);
|
||||
}
|
||||
}
|
||||
while( result != XONLINETASK_S_SUCCESS );
|
||||
|
||||
XOnlineTaskClose(enumerationTask);
|
||||
enumerationTask = NULL;
|
||||
}
|
||||
|
||||
// List isn't valid anymore, so no friends, and tell tick to stop generating
|
||||
generatingFriends = false;
|
||||
numFriends = 0;
|
||||
}
|
||||
|
||||
// shutdown and cleanup friends functionality
|
||||
//
|
||||
void XBL_F_Cleanup()
|
||||
{
|
||||
HRESULT result;
|
||||
|
||||
XBL_F_ReleaseFriendsList();
|
||||
|
||||
// finish off incomplete tasks
|
||||
//
|
||||
if(friendsGeneralTask)
|
||||
{
|
||||
do
|
||||
{
|
||||
result = XOnlineTaskContinue( friendsGeneralTask );
|
||||
if( IS_ERROR(result) )
|
||||
{
|
||||
Com_Printf("XBLive_F - Error %d finishing off friends general tasks\n", result);
|
||||
XOnlineTaskClose(friendsGeneralTask);
|
||||
friendsGeneralTask = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while( result != XONLINETASK_S_RUNNING_IDLE );
|
||||
XOnlineTaskClose(friendsGeneralTask);
|
||||
friendsGeneralTask = NULL;
|
||||
}
|
||||
friendsInitialized = false;
|
||||
}
|
||||
|
||||
// ******************************************************
|
||||
// FUNCTIONS THE MENU SYSTEM USES TO COMMUNICATE TO FRIENDS
|
||||
// *******************************************************
|
||||
|
||||
//Return the number of friends found while enumerating list
|
||||
int XBL_F_GetNumFriends(void)
|
||||
{
|
||||
return numFriends;
|
||||
}
|
||||
|
||||
// Set the higlighted friend for use when friend is selected
|
||||
void XBL_F_SetChosenFriendIndex(const int index)
|
||||
{
|
||||
// Sanity check - this does get called before we're done enumerating some times!
|
||||
assert( (index >= 0 && index < numFriends) || !numFriends );
|
||||
|
||||
// SOF2 had checks for less than zero - probably forgot to do a
|
||||
// Menu_SetFeederSelection before opening the menu.
|
||||
friendChosen = index;
|
||||
|
||||
// The UI calls this when the selection in the listbox moves. Set the status lines:
|
||||
Cvar_Set( "fl_voiceLine", XBL_F_GetVoiceString( index ) );
|
||||
Cvar_Set( "fl_statusLine", XBL_F_GetStatusString( index ) );
|
||||
Cvar_Set( "fl_statusLine2", XBL_F_GetStatusString2( index ) );
|
||||
}
|
||||
|
||||
XONLINE_FRIEND *XBL_F_GetChosenFriend( void )
|
||||
{
|
||||
if( friendChosen >= 0 && friendChosen < numFriends )
|
||||
return &friendsList[friendChosen];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Handle a players attempt to join a friends game from an invite when they are potentially using another title
|
||||
//
|
||||
HRESULT XBL_F_JoinGameFromInvite()
|
||||
{
|
||||
HRESULT result;
|
||||
|
||||
result = XOnlineFriendsAnswerGameInvite( IN_GetMainController(), &friendsList[friendChosen], XONLINE_GAMEINVITE_YES); // writes invite to HD if needed
|
||||
if( result != S_OK )
|
||||
{
|
||||
assert(!"faliure to accept invite");
|
||||
// report error
|
||||
}
|
||||
|
||||
// figure out if you're playing the same game as your friend
|
||||
//
|
||||
BOOL playingSameGame = XOnlineTitleIdIsSameTitle( friendsList[friendChosen].dwTitleID );
|
||||
|
||||
// if you are
|
||||
//
|
||||
if( playingSameGame )
|
||||
{
|
||||
XBL_MM_ConnectViaSessionID( &friendsList[friendChosen].sessionID, true );
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// else if its a different game return the code to show popup
|
||||
//
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Handle a players attempt to join a friends game when they are potentially using another title
|
||||
HRESULT XBL_F_JoinGame()
|
||||
{
|
||||
// Figure out if you're playing the same game as your friend
|
||||
BOOL playingSameGame = XOnlineTitleIdIsSameTitle( friendsList[friendChosen].dwTitleID );
|
||||
|
||||
// If you are
|
||||
if( playingSameGame )
|
||||
{
|
||||
XBL_MM_ConnectViaSessionID( &friendsList[friendChosen].sessionID, false );
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// It's a different game, write out the info:
|
||||
HRESULT result = XOnlineFriendsJoinGame( IN_GetMainController(), &friendsList[friendChosen] );
|
||||
assert( result == S_OK );
|
||||
|
||||
// Show insert disk popup
|
||||
return -1;
|
||||
}
|
||||
|
||||
// This handle all possbile actions that the user can perform on a selected friend
|
||||
//
|
||||
HRESULT XBL_F_PerformMenuAction(friendChoices_t action)
|
||||
{
|
||||
HRESULT result = S_OK;
|
||||
|
||||
switch(action)
|
||||
{
|
||||
case UI_F_FRIENDREQUESTED:
|
||||
result = XOnlineFriendsRequest(IN_GetMainController(), friendsList[friendChosen].xuid);
|
||||
break;
|
||||
|
||||
case UI_F_FRIENDACCEPTED:
|
||||
result = XOnlineFriendsAnswerRequest(IN_GetMainController(), &friendsList[friendChosen], XONLINE_REQUEST_YES);
|
||||
break;
|
||||
|
||||
case UI_F_FRIENDREMOVE:
|
||||
result = XOnlineFriendsRemove(IN_GetMainController(), &friendsList[friendChosen]);
|
||||
break;
|
||||
|
||||
case UI_F_FRIENDDECLINE:
|
||||
result = XOnlineFriendsAnswerRequest(IN_GetMainController(), &friendsList[friendChosen], XONLINE_REQUEST_NO);
|
||||
break;
|
||||
|
||||
case UI_F_FRIENDBLOCK:
|
||||
result = XOnlineFriendsAnswerRequest(IN_GetMainController(), &friendsList[friendChosen], XONLINE_REQUEST_BLOCK);
|
||||
break;
|
||||
|
||||
case UI_F_FRIENDCANCEL:
|
||||
result = XOnlineFriendsRemove(IN_GetMainController(), &friendsList[friendChosen]);
|
||||
break;
|
||||
|
||||
case UI_F_GAMEREQUESTED:
|
||||
result = XBL_F_Invite();
|
||||
break;
|
||||
|
||||
case UI_F_GAMEACCEPTED:
|
||||
result = XBL_F_JoinGameFromInvite();
|
||||
break;
|
||||
|
||||
case UI_F_GAMEDECLINE:
|
||||
result = XOnlineFriendsAnswerGameInvite(IN_GetMainController(), &friendsList[friendChosen], XONLINE_GAMEINVITE_NO);
|
||||
break;
|
||||
|
||||
case UI_F_GAMEFRIENDREMOVED:
|
||||
result = XOnlineFriendsAnswerGameInvite(IN_GetMainController(), &friendsList[friendChosen], XONLINE_GAMEINVITE_REMOVE);
|
||||
break;
|
||||
|
||||
case UI_F_GAMECANCEL:
|
||||
result = XOnlineFriendsRevokeGameInvite(IN_GetMainController(), *Net_GetXNKID(), 1, &friendsList[friendChosen]);
|
||||
break;
|
||||
|
||||
case UI_F_JOINSESSION:
|
||||
result = XBL_F_JoinGame();
|
||||
break;
|
||||
|
||||
case UI_F_TOGGLEONLINE:
|
||||
if(current_state & XONLINE_FRIENDSTATE_FLAG_ONLINE)
|
||||
XBL_F_SetState(XONLINE_FRIENDSTATE_FLAG_ONLINE, false);
|
||||
else
|
||||
XBL_F_SetState(XONLINE_FRIENDSTATE_FLAG_ONLINE, true);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Returns the gamertag of the given friend - used by UI listbox renderer
|
||||
const char *XBL_F_GetFriendName( const int index )
|
||||
{
|
||||
// Invalid index?
|
||||
if( index < 0 || index >= numFriends )
|
||||
return "";
|
||||
|
||||
return friendsList[index].szGamertag;
|
||||
}
|
||||
|
||||
// Returns the voice icon to use in the friends list for the given friend
|
||||
int XBL_F_GetVoiceIcon( const int index )
|
||||
{
|
||||
// Invalid index?
|
||||
if( index < 0 || index >= numFriends )
|
||||
return -1;
|
||||
|
||||
// Friend has no voice?
|
||||
if( !(friendsList[index].dwFriendState & XONLINE_FRIENDSTATE_FLAG_VOICE) )
|
||||
return -1;
|
||||
|
||||
// They have voice. Just check if they're muted.
|
||||
if( g_Voice.IsMuted( friendsList[index].xuid ) )
|
||||
return RE_RegisterShaderNoMip( "gfx/mp/voice_mute_icon" );
|
||||
else
|
||||
return RE_RegisterShaderNoMip( "gfx/mp/voice_on_icon" );
|
||||
}
|
||||
|
||||
// Returns the full voice info status line for the given friend
|
||||
const char *XBL_F_GetVoiceString( const int index )
|
||||
{
|
||||
// Invalid index?
|
||||
if( index < 0 || index >= numFriends )
|
||||
return "";
|
||||
|
||||
// Never display voice info for an offline friend
|
||||
if( !(friendsList[index].dwFriendState & XONLINE_FRIENDSTATE_FLAG_ONLINE) )
|
||||
return "";
|
||||
|
||||
// Friend has no voice?
|
||||
if( !(friendsList[index].dwFriendState & XONLINE_FRIENDSTATE_FLAG_VOICE) )
|
||||
return va( "%s %s", SE_GetString( "MENUS_VOICE" ), SE_GetString( "MENUS_OFF" ) );
|
||||
|
||||
// OK. Friend has voice. Just check if they're muted.
|
||||
if( g_Voice.IsMuted( friendsList[index].xuid ) )
|
||||
return va( "%s %s", SE_GetString( "MENUS_VOICE" ), SE_GetString( "MENUS_MUTED" ) );
|
||||
else
|
||||
return va( "%s %s", SE_GetString( "MENUS_VOICE" ), SE_GetString( "MENUS_ON" ) );
|
||||
}
|
||||
|
||||
// Returns the status icon to use in the friends list for the given friend
|
||||
int XBL_F_GetStatusIcon( const int index )
|
||||
{
|
||||
// Invalid index?
|
||||
if( index < 0 || index >= numFriends )
|
||||
return -1;
|
||||
|
||||
// We'll be using this a lot...
|
||||
const XONLINE_FRIEND *curFriend = &friendsList[index];
|
||||
|
||||
// In order of importance
|
||||
|
||||
// Player has received a request to a game
|
||||
if( curFriend->dwFriendState & XONLINE_FRIENDSTATE_FLAG_RECEIVEDINVITE )
|
||||
return RE_RegisterShaderNoMip( "gfx/mp/game_received_icon" );
|
||||
|
||||
// Player has received a request to be a friend
|
||||
if( curFriend->dwFriendState & XONLINE_FRIENDSTATE_FLAG_RECEIVEDREQUEST )
|
||||
return RE_RegisterShaderNoMip( "gfx/mp/friend_received_icon" );
|
||||
|
||||
// Player has sent invite to game
|
||||
if( (curFriend->dwFriendState & XONLINE_FRIENDSTATE_FLAG_SENTINVITE) &&
|
||||
!(curFriend->dwFriendState & XONLINE_FRIENDSTATE_FLAG_INVITEACCEPTED) &&
|
||||
!(curFriend->dwFriendState & XONLINE_FRIENDSTATE_FLAG_INVITEREJECTED) )
|
||||
return RE_RegisterShaderNoMip( "gfx/mp/game_sent_icon" );
|
||||
|
||||
// Player has sent friend request
|
||||
if( curFriend->dwFriendState & XONLINE_FRIENDSTATE_FLAG_SENTREQUEST )
|
||||
return RE_RegisterShaderNoMip( "gfx/mp/friend_sent_icon" );
|
||||
|
||||
// Friend is online, or online and playing
|
||||
if( (curFriend->dwFriendState & XONLINE_FRIENDSTATE_FLAG_PLAYING) ||
|
||||
(curFriend->dwFriendState & XONLINE_FRIENDSTATE_FLAG_ONLINE) )
|
||||
return RE_RegisterShaderNoMip( "gfx/mp/online_icon" );
|
||||
|
||||
// Friend is offline
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Returns the online/offline status line for the given friend
|
||||
const char *XBL_F_GetStatusString( const int index )
|
||||
{
|
||||
// Invalid index?
|
||||
if( index < 0 || index >= numFriends )
|
||||
return "";
|
||||
|
||||
// Some things we'lll be reusing a bit:
|
||||
const XONLINE_FRIEND *curFriend = &friendsList[index];
|
||||
char titleString[MAX_TITLENAME_LEN+1];
|
||||
XBL_F_GetTitleString( curFriend->dwTitleID, titleString );
|
||||
|
||||
// In order of importance
|
||||
|
||||
// Friend is currently playing some game
|
||||
if( curFriend->dwFriendState & XONLINE_FRIENDSTATE_FLAG_PLAYING )
|
||||
return va( SE_GetString( "MENUS_PLAYING" ), titleString );
|
||||
|
||||
// Friend is online - not in a session
|
||||
if( curFriend->dwFriendState & XONLINE_FRIENDSTATE_FLAG_ONLINE )
|
||||
return va( SE_GetString( "MENUS_AVAILABLE_IN" ), titleString );
|
||||
|
||||
// Friend is offline
|
||||
return SE_GetString( "MENUS_OFFLINE" );
|
||||
}
|
||||
|
||||
// Returns the special case status info for the given friend
|
||||
const char *XBL_F_GetStatusString2( const int index )
|
||||
{
|
||||
// Invalid index?
|
||||
if( index < 0 || index >= numFriends )
|
||||
return "";
|
||||
|
||||
// Some things we'lll be reusing a bit:
|
||||
const XONLINE_FRIEND *curFriend = &friendsList[index];
|
||||
char titleString[MAX_TITLENAME_LEN+1];
|
||||
XBL_F_GetTitleString( curFriend->dwTitleID, titleString );
|
||||
|
||||
// In order of importance
|
||||
|
||||
// Player has received a game invite fom the indicated friend
|
||||
if( curFriend->dwFriendState & XONLINE_FRIENDSTATE_FLAG_RECEIVEDINVITE )
|
||||
return va( SE_GetString( "MENUS_WANTS_TO_PLAY" ), titleString ); // Cleared ui_gameInvite (now xbl_hudGame)
|
||||
|
||||
// Player has received a request to be a friend
|
||||
if( curFriend->dwFriendState & XONLINE_FRIENDSTATE_FLAG_RECEIVEDREQUEST )
|
||||
return SE_GetString( "MENUS_WANTS_TO_BE_FRIEND" ); // Cleared ui_friendInvite
|
||||
|
||||
// Player has sent invite to game
|
||||
if( (curFriend->dwFriendState & XONLINE_FRIENDSTATE_FLAG_SENTINVITE) &&
|
||||
!(curFriend->dwFriendState & XONLINE_FRIENDSTATE_FLAG_INVITEACCEPTED) &&
|
||||
!(curFriend->dwFriendState & XONLINE_FRIENDSTATE_FLAG_INVITEREJECTED) )
|
||||
return SE_GetString( "MENUS_INVITED_TO_PLAY" );
|
||||
|
||||
// Player has sent friend request
|
||||
if( curFriend->dwFriendState & XONLINE_FRIENDSTATE_FLAG_SENTREQUEST )
|
||||
return SE_GetString( "MENUS_YOU_ASKED_TO_BE_FRIEND" );
|
||||
|
||||
// No special state:
|
||||
return "";
|
||||
}
|
||||
|
||||
// Determines the friend status of a given user. Used by the player list
|
||||
// code to set the state of each user, which is then used to determine icons.
|
||||
FriendState XBL_F_GetFriendStatus( const XUID *xuid )
|
||||
{
|
||||
XONLINE_FRIEND *curFriend = NULL;
|
||||
for( int i = 0; i < numFriends; i++ )
|
||||
{
|
||||
if( XOnlineAreUsersIdentical( &friendsList[i].xuid, xuid ) )
|
||||
{
|
||||
curFriend = &friendsList[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !curFriend )
|
||||
return FRIEND_NO;
|
||||
|
||||
if( curFriend->dwFriendState & XONLINE_FRIENDSTATE_FLAG_SENTREQUEST )
|
||||
{
|
||||
return FRIEND_RQST;
|
||||
}
|
||||
|
||||
if( curFriend->dwFriendState & XONLINE_FRIENDSTATE_FLAG_RECEIVEDREQUEST )
|
||||
{
|
||||
return FRIEND_RQST_RCV;
|
||||
}
|
||||
|
||||
return FRIEND_YES;
|
||||
}
|
||||
|
||||
// Send a friend invitation to this user.
|
||||
void XBL_F_AddFriend( const XUID *pXuid )
|
||||
{
|
||||
// Send the request to the servers - VVFIXME - handle errors here?
|
||||
HRESULT hr = XOnlineFriendsRequest( IN_GetMainController(), *pXuid );
|
||||
}
|
||||
|
||||
// Cancel a friend invitation we may have sent to this user, and/or
|
||||
// remove them from our friend list.
|
||||
void XBL_F_RemoveFriend( const XUID *pXuid )
|
||||
{
|
||||
XONLINE_FRIEND *curFriend = NULL;
|
||||
for( int i = 0; i < numFriends; i++ )
|
||||
{
|
||||
if( XOnlineAreUsersIdentical( &friendsList[i].xuid, pXuid ) )
|
||||
{
|
||||
curFriend = &friendsList[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we found them in our list
|
||||
if( !curFriend )
|
||||
return;
|
||||
|
||||
// OK. Remove them from the list
|
||||
XOnlineFriendsRemove( IN_GetMainController(), curFriend );
|
||||
}
|
||||
|
||||
// ******************************************************
|
||||
// SUPPORT FUNCTIONS FOR MANAGING FRIENDS
|
||||
// *******************************************************
|
||||
|
||||
// ******************************************************
|
||||
// PUBLIC ** PUBLIC ** PUBLIC ** PUBLIC ** PUBLIC ** PUBLIC
|
||||
// *******************************************************
|
||||
// functionality to be run every game tick
|
||||
//
|
||||
void XBL_F_Tick()
|
||||
{
|
||||
if( !friendsInitialized )
|
||||
return;
|
||||
|
||||
HRESULT result;
|
||||
|
||||
// Check if we are in a session with enough open public slots to make us joinable
|
||||
XBL_F_CheckJoinableStatus( false );
|
||||
|
||||
// Process the general task, required during gameplay to handle invitations
|
||||
if( friendsGeneralTask )
|
||||
{
|
||||
result = XOnlineTaskContinue( friendsGeneralTask );
|
||||
if( IS_ERROR(result) )
|
||||
{
|
||||
Com_Printf("XBLive_F - Error %d running friends general tasks\n", result);
|
||||
XOnlineTaskClose(friendsGeneralTask);
|
||||
friendsGeneralTask = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// If the UI is currently displaying the friends list we must continue to update it
|
||||
if( generatingFriends && enumerationTask )
|
||||
{
|
||||
// Keep enumerating
|
||||
result = XOnlineTaskContinue( enumerationTask );
|
||||
if( IS_ERROR(result) )
|
||||
{
|
||||
Com_Printf("XBLive_F - Error %d enumerating friends list\n", result);
|
||||
}
|
||||
|
||||
// Do we have all the results?
|
||||
if( result == XONLINETASK_S_RESULTS_AVAIL )
|
||||
{
|
||||
// Copy the list into our buffer
|
||||
numFriends = XOnlineFriendsGetLatest(IN_GetMainController(), MAX_FRIENDS, &friendsList[0] );
|
||||
|
||||
// Also update the strings about the currently selected friend:
|
||||
if( friendChosen >= 0 && friendChosen < numFriends )
|
||||
{
|
||||
Cvar_Set( "fl_voiceLine", XBL_F_GetVoiceString( friendChosen ) );
|
||||
Cvar_Set( "fl_statusLine", XBL_F_GetStatusString( friendChosen ) );
|
||||
Cvar_Set( "fl_statusLine2", XBL_F_GetStatusString2( friendChosen ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Change our state - set or remove a notification flag
|
||||
void XBL_F_SetState( DWORD flag, bool set_flag )
|
||||
{
|
||||
if( set_flag )
|
||||
current_state |= flag;
|
||||
else
|
||||
current_state &= ~flag;
|
||||
|
||||
HRESULT hr = XOnlineNotificationSetState(IN_GetMainController(), current_state, *Net_GetXNKID(), 0, NULL );
|
||||
assert( hr == S_OK );
|
||||
|
||||
// VVFIXME - Move this shite into the calling code
|
||||
//jsw//Hack for the menus
|
||||
if(flag == XONLINE_FRIENDSTATE_FLAG_ONLINE)
|
||||
{
|
||||
if(set_flag)
|
||||
Cvar_Set( "ui_xblivefriendonline", SE_GetString("XBL_ONLINE") );
|
||||
else
|
||||
Cvar_Set( "ui_xblivefriendonline", SE_GetString("XBL_OFFLINE") );
|
||||
}
|
||||
}
|
||||
|
||||
// Just a way to get our own state information (things that are in our friend state)
|
||||
bool XBL_F_GetState( DWORD flag )
|
||||
{
|
||||
return current_state & flag;
|
||||
}
|
||||
|
||||
// Invite a friend to join the current game
|
||||
HRESULT XBL_F_Invite(void)
|
||||
{
|
||||
return XOnlineFriendsGameInvite( IN_GetMainController(), *Net_GetXNKID(), 1, &friendsList[friendChosen] );
|
||||
}
|
||||
|
||||
// we need to change our client friend states to show that we're not in a session
|
||||
//
|
||||
void XBL_F_OnClientLeaveSession()
|
||||
{
|
||||
XBL_F_SetState( XONLINE_FRIENDSTATE_FLAG_JOINABLE, false );
|
||||
XBL_F_SetState( XONLINE_FRIENDSTATE_FLAG_PLAYING, false );
|
||||
}
|
||||
|
||||
bool XBL_F_FriendNotice( void )
|
||||
{
|
||||
return (logged_on && XOnlineGetNotification( IN_GetMainController(), XONLINE_NOTIFICATION_FRIEND_REQUEST ));
|
||||
}
|
||||
|
||||
bool XBL_F_GameNotice( void )
|
||||
{
|
||||
return (logged_on && XOnlineGetNotification( IN_GetMainController(), XONLINE_NOTIFICATION_GAME_INVITE ));
|
||||
}
|
||||
|
||||
// Get friend details based on gamertag
|
||||
//
|
||||
XONLINE_FRIEND* XBL_F_GetFriendFromName( char* name )
|
||||
{
|
||||
for( int i = 0; i < numFriends; i++ )
|
||||
{
|
||||
if( !strcmp( friendsList[i].szGamertag, name ) )
|
||||
{
|
||||
return &friendsList[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// ******************************************************
|
||||
// PRIVATE ** PRIVATE ** PRIVATE ** PRIVATE ** PRIVATE ** PRIVATE
|
||||
// *******************************************************
|
||||
|
||||
//Get the title string of game being played
|
||||
void XBL_F_GetTitleString(const DWORD titleID, char* titleString)
|
||||
{
|
||||
// Is their title ID valid?
|
||||
if( !titleID )
|
||||
{
|
||||
strcpy( titleString, "" );
|
||||
return;
|
||||
}
|
||||
|
||||
WCHAR playingWstr[MAX_TITLENAME_LEN+1];
|
||||
int attempt = 0;
|
||||
|
||||
// MS suggests polling to get the string:
|
||||
do
|
||||
{
|
||||
attempt++;
|
||||
XOnlineFriendsGetTitleName( titleID, XC_LANGUAGE_ENGLISH, MAX_TITLE_LENGTH, playingWstr );
|
||||
} while( playingWstr[0] == 0 && attempt < 10000 );
|
||||
|
||||
// If we got something, use it, else just print the title ID
|
||||
if( attempt < 10000 )
|
||||
wcharToChar( titleString, playingWstr );
|
||||
else
|
||||
sprintf( titleString, "%d", titleID );
|
||||
}
|
||||
|
||||
// periodically update your joinability status (your session has X+ public slots open)
|
||||
//
|
||||
void XBL_F_CheckJoinableStatus( bool force )
|
||||
{
|
||||
// if not currently in a session, leave
|
||||
//
|
||||
if( !(current_state & XONLINE_FRIENDSTATE_FLAG_PLAYING) )
|
||||
return;
|
||||
|
||||
static int pass = 0;
|
||||
|
||||
// if its time to check...
|
||||
//
|
||||
if( ++pass > JOINABLE_CHECK_RATE || force )
|
||||
{
|
||||
// Just count how many clients we have valid info for, and compare to maxclients!
|
||||
// Need a special case for dedicated host though:
|
||||
extern cvar_t *sv_maxclients;
|
||||
int numClients = 0;
|
||||
int maxClients = com_dedicated->integer ? sv_maxclients->integer : cgs.maxclients;
|
||||
for( int i = 0; i < maxClients; ++i )
|
||||
if( xbOnlineInfo.xbPlayerList[i].isActive )
|
||||
numClients++;
|
||||
|
||||
// Set our joinable state based on the number of empty slots.
|
||||
XBL_F_SetState( XONLINE_FRIENDSTATE_FLAG_JOINABLE, numClients < maxClients );
|
||||
|
||||
pass = 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user