A few #XBLIG #XNA devs have gotten in touch with me over twitter about how I managed to do the "Invite Friend" functionality in Spectrangle360. Although there is an MSDN article on the subject and the XNA gamestatemanagement example shows how this is done I still think a real world example might come in useful for some people.
So I have decided I would explain how I managed to get it to work in Spectrangle360.
Current Structure
Before I dive into the actual code I want to explain a bit about the structure of Spectrangle360 so that the code actually makes sense. Spectrangle360 was developed with the FSM (finite state machine) pattern as a basis, this meant that each of the areas/classes of the game could be split up to handle their own state.
public interface IState
{
void Enter( IStateContext context);
void Update( IStateContext context, GameTime time);
void Draw( IStateContext context, SpriteBatch spriteBatch);
void Exit( IStateContext context);
}
public interface IStateContext
{
IState State { get; }
void Update(GameTime time);
void Draw( SpriteBatch spriteBatch);
void ChangeState(IState state);
}
So when Spectrangle360 first starts up the game enters into a "GameS
creenManager" state which inherits from "IState", this "GameScreenManager" state is the main state of the game which is always running unless the game throws any exceptions. From this state other states are entered eg when the Demo is playing, the game is playing or the game is being played via Xbox live and this state "TwoPlayerLobby" is the class that handles all the work when a players is in the lobby trying to create or join a two player game.
The Code
The first piece of code is the code which I used to basically set up some variables and to hook the "InviteAccepted" event :-
public void Hook(SpectrangleManager manager, GameScreenManager gm, bool hook)
{
_mgr = null;
_mgr = manager;
_gsm = null;
_gsm = gm;
_context = gm;
if (!hook)
{
NetworkSession.InviteAccepted += NetworkSession_InviteAccepted;
}
}
This hook code is called from the "MainScreen" state via its enter method like this, "_TPL" is an instance of the "TwoPlayerLobby" class :-
public void Enter(IStateContext context)
{
...
((GameScreenManager)context)._TPL.Hook(((GameScreenManager)context).Manager, (GameScreenManager)context, ((GameScreenManager)context).AcceptHook);
...
}
Having an instance of the "TwoPlayerLobby" class means that the game is always ready to accept invites when the player is in the "TwoPlayerLobby" state.
The code used once a game invite has been accepted is this :-
public void NetworkSession_InviteAccepted(object sender, InviteAcceptedEventArgs e)
{
Game1.HSC.SearchNetworkOff = true;
Game1.HSC.Enabled = false;
_gsm.GameSearch.Disable = true;
{
// stops a different gamer controller joining a game in progress
if (e.Gamer.PlayerIndex != Game1.Global.Controller())
{
_gsm.ChangeState(new NetworkErrorMessage("You cannot join game in progress with a different gamer. Please return to the title screen if you wish to swap profiles."));
return;
}
// Quit the current session
if (_mgr.Session != null)
{
try
{
_mgr.Session.Dispose();
_mgr.Session = null;
}
catch
{
return;
}
}
// We can now create a new instance of the SpectrangleManager game and then create the player instances to be used later.
_gsm.Manager = new SpectrangleManager( Game1.Global.Content, (GameScreenManager)_gsm);
_mgr = _gsm.Manager;
_mgr.Players[0] = new Player(_mgr, PlayerIndex.One, "1", PlayerSide.WHITE, false);
_mgr.Players[1] = new Player(_mgr, PlayerIndex.Two, "2", PlayerSide.BLACK, false);
try
{
// Join the new session
_mgr.Session = NetworkSession.JoinInvited(1);
}
catch
{
_gsm.ChangeState(new NetworkErrorMessage("Unable to join game in progress."));
return;
}
// hook the normal network session events
HookSessionEvents();
// We can change the state to wait for the host to start as we have now accepted the friend invite
_gsm.ChangeState(new WaitForHostToStart(2, false, _mgr,_mgr.Session));
}
}
And there you have it, this code allows friend invites to be accepted and once the invite is accepted the "GameScreenManager" main state is changed to "WaitForHostToStart" state. Yes I know this could have been done much cleaner but I just wanted to get this to work the easiest way I could at the time. If I ever develop another multiplayer game with Xbox Live friend invites I would probably look at this whole code again to see if I could improve it.
Anyway hope it helps some one.
Jase