Friday, 3 May 2013

Backgammon with SignalR – Part Three – Client Side SignalR

This is the last of a three part series of posts on BackgammonR – an online Backgammon game built with SignalR. If you haven’t read it already, please see Part 1 – Game Engine and Part 2 – Server Side SignalR

The first bit of JavaScript to note is not actually something you write, rather what SignalR generates in order for it to allow for the messages to be passed between client and server and vice versa. It’s at /signalr/hubs/ and if you view it you’ll can see how the methods defined on the server-side hub are exposed to the client.

The script I have written though lives in /public/site/backgammon.js and whilst it consists of a number of methods it can be considered in three main sections.

Data Binding

Before getting into the client-side SignalR code it’s worth flagging up the other libraries I’ve used here. Jquery of course. But also knockout, which provides a nice separation between the intricacies of the UI and the details of the client-side model manipulated in code. It provides a means of automatically data-binding updates to the model – so for example when a new player is added the list displaying those users will be automatically refreshed.

This is all managed in the set of functions under the “Data Binding” comment. A client-side view model is set-up and maintained via helper methods to store details of what is displayed via the browser – i.e. the list of players, games and details of the selected game the user might be playing.

Persistent Connection

Beneath the “Persistent Connection” lies the SignalR related code, primarily in the initPersistentConnection() method. The first thing that occurs is a reference is stored to the SignalR hub:

    var hub = $.connection.gameNotificationHub;

You’ll see here the name of the hub is the same as that defined for the class on the server. The next lines of code define the client-side methods that are called from the server. Going back to the method described in the previous post form when a player joins, there were two client side notifications made – one to the caller and one to all users of the site. These two functions are wired up as below:

        hub.client.joined = function (player, connectionId) {
            addPlayer(player);
            if ($.connection.hub.id != connectionId) {
                notify(player.Name + " has joined.", "message", true);
            }
        };

        hub.client.callerJoined = function (name) {            
            viewModel.name(name);
        };

callerJoined is the one that is sent to just the caller – all we do here is update the view model to set the name and have knockout bind it to the UI. joined is a notification to all players, to update the list of players held on the view model. It also uses the connectionId that’s exposed client as well as server side to display a notification message to all players other than the caller.

The final lines of code in this function are held within the callback of the $.connection.hub.start().done() method. This is where some initialisation calls to the hub are made, and jquery is used to link up various events with the UI. For example against each available player in the list is a link to challenge them; when clicked the name of the player is pulled from the DOM and a SignalR call to the hub’s Challenge method is made.

            $(document).on("click", "#player-list a.challenge", function () {
                var challengedPlayer = $(this).prevAll("span.player-name").text();
                hub.server.challenge(challengedPlayer);
                return false;
            });

Game Canvas

The functions under the comment “Game canvas” are all involved with the drawing of the game board and counters. I decided to use HTML canvas for this as although it would likely have been feasible with pure CSS – and in fact would probably have been better should I want to introduce drag-drop of the pieces rather than the rather clunky form interface I have at the moment – it was again something I was keen to play around with.

Apart from the one function to draw the counters which was one of those write once and hope you don’t have to come back to it events, it’s mostly fairly straightforward. The idea is to get a reference to the canvas and then to the 2D context within it. Once that’s obtained the drawImage method is used to draw the board and the counters in the right places.

And that’s that... so far anyway. There’s still a bit to do – in particularly the end game and making the whole thing look a bit nicer. But that’s mostly details… as far as the SignalR parts are concerned that’s all in place and can say it’s been a fun little side project to work on.

Play the game

View the code

Backgammon with SignalR – Part Two – Server Side SignalR

This is the second of a three part series of posts on BackgammonR – an online Backgammon game built with SignalR. If you haven’t read it already, please see Part 1 – Game Engine.

SignalR actually provides two abstractions above the base technologies for maintaining persistent connections between browser and server. One is fairly low-level, called PersistentConnection that I didn’t look into. The other is Hubs.

I have a single SignalR hub called GameNotificationHub which inherits from Microsoft.AspNet.SignalR.Hub and thus obtains its base functionality. Within that class you can create public methods, which – once SignalR has worked its magic – become end-points that can be called from the client-side JavaScript.

They all return void though – which initially seems counter-intuitive and not what you would do were you wiring up an end-point for an AJAX request for example. However the point is of course that with this type of application we may need to push responses to this method call not just to the caller, but also to groups of other users connected to the application as well.

This is done via the Clients property – which has various dynamic fields such as Caller, All, Others, Group to allow you to send messages to just the appropriate sets of users. Strung on the end of that are further dynamic methods that will resolve to client-side code that is “called” from the server. Parameters can be passed to these messages – which can be simple strings or more complex types that will be accessible as JSON on the client.

For example the code sample that follows illustrates the Join method on the hub. It’s called when an authenticated user first access the game. There’s a check to ensure that the user hasn’t already joined, and if not, they are added to the list of players. Two notifications to the client are made – one to the caller to trigger the update of their screen, and one to all users to flash a message that a new player has joined.

        public void Join(string name)
        {
            if (!Manager.Instance.Players.Any(x => x.Name == name))
            {
                var user = new Player 
                { 
                    Name = name, 
                    ConnectionId = Context.ConnectionId,
                    Status = ConnectionStatus.ReadyToPlay 
                };
                Manager.Instance.Players.Add(user);

                Clients.All.joined(user, Context.ConnectionId);
                Clients.Caller.callerJoined(name);                
            }
        }

Other methods on the hub allow users to leave, challenge others to games, accept or reject those challenges and to take turns in the game.

The groups feature was particularly useful here. Within SignalR you can create groups as you see fit and assign users to them, and so push messages to just particular groups of them. The classic example of this is the rooms in a chat site. I used a group for each game, identifying it by the game Id, and thus only pushing updates to those users playing or viewing a game. For example in the Move method parameters are passed identifying the game and the move requested. Checks are made to ensure it’s the calling user’s turn and that the move they want to make is valid according to the rules of the game. If that’s all OK, the internal state of the game is updated and the whole Game object passed as a notification to the group associated with that game.

        public void Move(Guid gameId, int[] from, int[] to)
        {
            var game = GetGame(gameId);
            if (game != null)
            {
                if ((game.CurrentPlayer == 1 && game.Black.ConnectionId == Context.ConnectionId) ||
                    (game.CurrentPlayer == 2 && game.White.ConnectionId == Context.ConnectionId))
                {
                    if (game.Move(from, to))
                    {
                        // Notify all clients in group of move
                        Clients.Group(game.Id.ToString()).moved(game);
                    }
                    else
                    {
                        Clients.Caller.displayError("Invalid move.");
                    }
                }
                else
                {
                    Clients.Caller.displayError("Not your turn.");
                }
            }
            else
            {
                Clients.Caller.displayError("Game not found.");
            }
        }

Click for Part 2 – SignalR on the client

Play the game

View the code

Backgammon with SignalR – Part One – Game Engine

There’s no doubt who the cool kid on the block is when it comes to the “one ASP.Net” stack – SignalR, a library created to simplify the process of creating responsive applications that push AND receive notifications from the server. It provides a wrapper around a range of technologies that can provide persistent or semi-persistent connections, choosing the best available when the full chain from browser to server is taken into account.

Wanting to look into this technology with a project that’s at least semi-real, I was inspired by an article in a recent edition of the digital magazine Dot Net Curry where the author created a game of noughts and crosses (or tick-tac-toe). Chess was going to be beyond me for sure, but I figured a game of Backgammon might be feasible to get running. Hence BackgammonR – for some reason all apps using the technology need to end with a capital R.

The application I’ve built so far so far is running here on Azure. And code should anyone want to look into it further is here on Github. Worth flagging from the outset that you certainly won’t play the best game of Backgammon of your life on the app... at least yet. But it’s definitely proved its worth in allowing me to get to grips with the technology.

I’ll explain the code a bit more in this and two further blog posts.

The Game Engine

I won’t actually mention SignalR further in this post though; instead will go through some of the features of the game engine itself.

The application is based on ASP.Net MVC 4 and consists of a single project, plus a project for some unit tests. The game engine I’ve set up in the Models directory and it consists of three key classes.

Manager is a class set up using a singleton pattern to maintain an application wide, static instance of a single object. It contains two lists – one of players and one of the games. As you’ll see there’s no backing store such as a database to persist this information which would be needed were this anywhere near a real application. Currently if the application restarts or the app pool recycles all the running games would be lost. But it’s a nice, quick and easy way to get some form of application state running.

    public class Manager
    {
        private static readonly Manager _instance = new Manager();

        private Manager()
        {
            Players = new List<Player>();
            Games = new List<Game>();
        }

        public static Manager Instance
        {
            get
            {
                return _instance;
            }
        }
        
        public List<Player> Players { get; set; }

        public List<Game> Games { get; set; }
    }

Player is a very simple POCO that holds properties of the player name, connection status and connection Id that’s used by SignalR to recognise each connection.

Game is where the core of the game engine logic is coded. It contains properties that describe a single instance of a game, for example which player is black and white, whose turn it is and with the state of the board and dice.

The last dice roll is modelled as a simple integer array with 2 elements – one for each die. And similarly the board – this is a two-dimensional integer array with one dimension containing an element for each player and the other dimension holding the number of counters for each point. I actually have 26 points – 24 for each of the points, with the first and last position used for the bar and pieces that have been beared off respectively.

As well as these properties are various public methods such as RollDice and Move, along with private ones for validating the moves are valid and updating the state of the board.

Unit Tests

The bulk – in fact currently all – of the unit tests have been written to design and test the Game class, as this is where the bulk of the back-end logic resides. When I’m working with unit tests I like to ensure I cover all classes and methods that are a) have some complexity to provide value for the tests b) not too hard to test in terms of tricky dependencies. I find that provides the most return on investment in testing effort.

This class falls squarely into that category – it has no dependencies so there is no need for mocking and it offered a nice way to work in a TDD fashion as I worked through the various rules for what makes a move valid or not. Here’s an example test:

        [TestMethod]
        public void Game_MoveMatchesDiceButToOccupiedPoint_IsInvalid()
        {
            // Arrange
            var player1 = new Player { Name = "Player 1", };
            var player2 = new Player { Name = "Player 2", };
            var game = new Game(player1, player2);
            game.Dice[0] = 2;
            game.Dice[1] = 5;

            // Act  
            var result = game.Move(new int[] { 1, 1 }, new int[] { 3, 6 });

            // Assert
            Assert.IsFalse(result);
            Assert.AreEqual(1, game.CurrentPlayer);
        }

Authentication

To authenticate users again I’ve used something very simple just to get this working and move onto more interesting aspects of the project. The application uses Forms Authentication via a simple custom membership provider called AppMembershipProvider that merely checks that the name of the player is unique.

        public override bool ValidateUser(string username, string password)
        {
            // All we care about for now is that user name is unique
            return !Manager.Instance.Players.Any(x => x.Name == username);
        }

The HomeController has methods for handling this flow before redirecting authenticated users to the Game method where the backgammon functionality lives.

Worth flagging an issue I ran into here – as did the author of this stack overflow post – which is that initially I looked to set up Forms Authentication from within the SignalR hub. This caused issues as the connection that SignalR recognised for each user was lost between the unauthenticated and authenticated states. So best to keep it separate.

Play the game

View the code