Wednesday, June 22, 2011

Foray into Photon - Part 14 - Migrating to Operation and Event Handlers

So before we get into creating and sending the Login operation we are going to modify our GameStates to have a dictionary of OperationHandlers and EventHandlers. But first we need a set of objects to base our handlers off of. I began by opening Unity3d and creating a new folder called _Handlers. Inside that folder I created a folder called Operations and another one called Events. In Operations I created a new class called IOperationHandler and it looks like this:


using System.Collections;
using AegisBornCommon;


public abstract class IOperationHandler
{
    public delegate void BeforeMessageRecieved();
    public BeforeMessageRecieved beforeMessageRecieved;


    public delegate void AfterMessageRecieved();
    public AfterMessageRecieved afterMessageRecieved;


    public void HandleMessage(Game gameLogic, OperationCode operationCode, int returnCode, Hashtable returnValues)
    {
        if (beforeMessageRecieved != null)
        {
            beforeMessageRecieved();
        }
        OnHandleMessage(gameLogic, operationCode, returnCode, returnValues);
        if (afterMessageRecieved != null)
        {
            afterMessageRecieved();
        }
    }


    public abstract void OnHandleMessage(Game gameLogic, OperationCode operationCode, int returnCode, Hashtable returnValues);
}


If you notice, this class is exactly like our IMessageHandler from the SmartFoxProject. The only difference is the HandleMessage and OnHandleMessage where we pass along the game, the op code, the return code and the table of values.


Then we need to wire in the handlers to the IGameState:


    Dictionary OperationHandlers { get; }

This means we need to change our Disconnected and WaitingForConnect to include the following:

    public Dictionary OperationHandlers
    {
        get { throw new NotImplementedException(); }
    }

So we will get an error if Disconnected or WaitingForConnect tries to load our handlers. Next we need Connected to be modified. Here we will create a real dictionary and set it up:

    private readonly Dictionary _handlers;
    public Dictionary OperationHandlers
    {
        get { return _handlers; }
    }

    public Connected()
    {
        _handlers = new Dictionary();
        // Add handlers here
        var keyHandler = new ExchangeKeysHandler();
        _handlers.Add(OperationCode.ExchangeKeysForEncryption, keyHandler);
    }

So here we have created our handler dictionary and added a new class that we haven't created yet called ExchangeKeysHandler. The last thing we are going to do before we create this new class is make the modifications to look through our list of handlers and attempt to find one to handle this method:

    public void OnOperationReturn(Game gameLogic, OperationCode operationCode, int returnCode, Hashtable returnValues)
    {
        IOperationHandler handler;

        if (_handlers.TryGetValue(operationCode, out handler))
        {
            handler.HandleMessage(gameLogic, operationCode, returnCode, returnValues);
        }
        else
        {
            gameLogic.OnUnexpectedPhotonReturn(returnCode, operationCode, returnValues);
        }
    }

This code does like it does in the SmartFox code, it attempts to find a handler and if one isn't found, we get an unexpected return which prints a message in our debug stating that we couldn't handle it.

So now we need to build our ExchangeKeysHandler class which we will create in the Operations folder under _Handlers:

using System.Collections;
using AegisBornCommon;

public class ExchangeKeysHandler : IOperationHandler
{
    public override void OnHandleMessage(Game gameLogic, OperationCode operationCode, int returnCode, Hashtable returnValues)
    {
        gameLogic.Peer.DeriveSharedKey((byte[])returnValues[(byte)ParameterCode.ServerKey]);
        gameLogic.NotifyKeysExchanged();
    }
}

This contains the code that was originally in the switch statement with the exception of the handled boolean to tell us we handled it.

Now we can handle messages in any of our IGameStates by creating a new class of type IOperationHandler and adding it to our list of handlers in our game state. Again, if you are interested, this is already checked into the github repository, which has now been split between the smartfox and photon versions. Links are in the right hand column.

No comments: