Archive for the ‘Castle’ Category

XNA Game Development: Coding For Multiplatform Multiplayer 2

Thursday, March 12th, 2009

It occurs to me that I wasn’t thinking straight when I wrote the previous entry regarding my reluctance to use .Net 3.5 SP1 in ‘Encounters’ for hybrid networking.

In a clearer state of mind, it occurs to me that because only the Windows version of the game is going to use the WCF networking implementation, that only the Windows version of the game will require the 3.5 SP1 version of the framework as a result.

The Xbox 360 appears to use a version of the Compact Framework 3.5, however it’s worth noting that 3.5 is a binary compatible set of additional assemblies that run in the .Net 2.0 environment.

What this effectively means is that I can use functionality in 3.5 SP1 (specifically the ability to serailize objects that aren’t marked as DataContracts or Seralizable) for the Windows version of the networking stack without contaminating the code of the game and preventing it from running on a 360.

Even better, it means I don’t need to mark-up my data model with any kind of attributes to support network play on Windows and I shouldn’t need to use a dubious set of byte array wrappers for data that can be typesafe, effectively letting me maintain a “purer” game model.

I’ll move my development environment to 3.5 SP1 and test this theory later, but I suspect I can simplify the networking stack on windows without the need for any messy hacks because of SP1.

Sometimes sleeping on a problem really is the answer; I was about to do something pretty stupid.

XNA Game Development: Coding For Multiplatform Multiplayer

Thursday, March 12th, 2009

I’ve jumped right in to the deep end with my game project (which is going under the working title of “Encounters” – I needed to call the solution something!) and one of the core design goals of the project is the multiplayer focus of the game.

I’m a huge fan of Id SoftwareJohn Carmack is probably my favourite “celebrity computer programmer”.  He’s incredible smart and consistent and has made some of both the most influential and my own favourite games.

Standing on the shoulders of giants – The “Quake” model

I’ve always thought the “Quake model” of single player and multiplayer game development to be a good one.  For those that don’t know, one of the simple design tenants of the Quake engine is that everything is a multiplayer game.  When you play the campaign in the original Quake what the game actually does is start a local game server which you then connect to.  Due to the proliferation of the Quake engine and other engines that have been inspired by it’s design this became quite a common way to build first person shooters with multiplayer support from the offset.  It reduced the implementation of multiplayer to simply having a second player connect to the active session.

Standing on the shoulders of giants, I’ve decided that this is the model I wish to follow for Encounters, especially seeing as the primary work-in-progress game design desires 4-player coop as the main campaign (with NPC assistants if you play with fewer humans).  Because of the way supporting multiplayer from the offset effectively means that all the games “thinking” is done in the server component (collision detection, cheat prevention, state management..) I decide that it’d be the best place to start the implementation.

Prototyping

So far so good, I spent an hour or two last night designing a simple state managing game server and retrofitting it to my previous prototype (an arena with a player-controlled unit moving around it) and moving all the logic and validation to the server side.

At this point the “game server” was a singleton class that the game accessed though a fake “proxy” class (left empty for eventual network implementation) and it worked pretty well.  The collision detection worked on the “server side” when the server was running in the same application domain and as a proof of concept everything was quite sound. I’m still left facing a few issues surrounding the frequency of syncing with the server and client side prediction, but they’re all relatively well solved problems in gaming (and there’s certainly some prior art to take inspiration from in XNA tutorials around the web).

Building a network stack

Once the proof of concept was working I started looking into the networking support provided by XNA and hit the mother of all roadblocks.  Because I’m targeting both the 360 and Windows, networking becomes significantly more complicated.  See, Microsoft offer no direct network access on the 360, via XNA, or even to their licensed partners (internet hearsay claims).  They provide Xbox Live APIs as part of the XNA framework however, which seemed like a decent solution until I realised that these networking APIs function only on a 360 as part of Xbox live.

Not so multiplatform really

So I’ve started thinking around the problem.  I do a lot of work with WCF in my day-job writing distributed systems so my obvious inclination was to provide a WCF client-server architecture for the Windows targeted version of the game.  This adds an additional set of issues.  For a start it looks as though the WCF assemblies (System.ServiceModel) are probably not available on the 360.  You’d think that’s not much of a problem if you’re going to use the Live APIs, but then you realise that if you’re using a version of .Net 3.5 prior to the first service pack, you need to annotate any classes you want to transfer via WCF with the DataContract attribute.  Which is in the System.ServiceModel namespace.

I’m not sure (as I currently don’t have a subscription to deploy my test code onto my 360) what version of the framework the 360 is running, but I’d hazard a guess that it’s pre SP1.  I’m going to have to further research this problem, because if you can use SP1 on the 360 (which supports serialization without any attributes on the classes) then we’re home free.

Multiplatform networking code using Inversion of Control

In the interim I’ve devised a cunning solution (or perhaps workaround, I’m not sure).  See, all of these issues lead me to need two entirely separate network stacks for my game.  One that supported the Windows, and the other that supported Xbox live, without contaminating my data model with mark-up that’s useable in only one or the other of the stacks.

Castle Windsor to the rescue.

This is purely speculative as I haven’t attempted to implement the 360 network stack yet, but I intend to use the Castle Windsor IoC (inversion of control) container to load a separate network stack at runtime, depending on the platform.

My idea is that the game knows about two interfaces IGameServer and IGameServerConnection.  I then create two entirely separate assemblies, one with the networking code for the PC, the other with the Live networking code.  The PC version contains a class called WcfGameServer which implements IGameServer (I’ve already written this code), and a class called WcfGameServerConnection which implementes IGameServerConnection (and acts as a hand crafted WCF proxy).  The 360 implementation will feature XBL counterparts to these classes.

As far as the game is concerned, it’ll use the Windsor container to load an instance of IGameServer, call the StartListening(); method, then use Windsor to load an instance of IGameServerConnection() and call JoinGame() on that connection.  This way, the specific networking implementation is entirely removed from the game and hidden behind these two simple interfaces.

I’ve currently got a good way through implementing the WCF version of this model though I’ve hit a few snags on the way.  Because I’m deliberately developing in a pre-SP1 environment for the sake of this exercise, WCF doesn’t like serializing the game model to send over the wire.  As a result I’ve had to produce an inelegant hack to work around my desire to keep the System.ServiceModel assembly reference clear of my game model.

Trying to keep it light

I’ve marked up my model with Serializable attributes (.NET 1.1, that’ll be fine) and inside my WCF implementation of IGameServerConnection I’m marshalling all my data into byte[]’s before sending it over the wire.  This isn’t ideal as it requires the WCF implementation to manually deserialize the byte[]’s into their correct data types in the service implementation and the client library, but it does work.  Unfortunately at the moment these byte arrays are being stored as XML before being sent over the wire (as is the default WCF way) so I’m going to need to force WCF to binary serialize all it’s data rather than bloat my packets (and as a result, the game latency).  I’m using Net.Tcp so it’s pretty lightweight as far as protocols go but I suspect I’ll need to do some additional fine tuning to make the WCF implementation viable.

Either way, I’ve got a good feeling about the model, subtle hacks aside, and I think this is quite a good way to target both platforms with minimal impact to your game code.

So this is day 3 of development (I’m sure I’m going to loose count pretty quickly).

[Footnote]

It occurs to me that I got a few fundamental things wrong when this post was originally written regarding the requirements for .Net 3.5 SP1.  These mistakes almost complicated the design of the networking stack.  Read more in my follow up here.

Using C#, Inversion of Control and WCF to produce a generic host for use in distributed systems.

Thursday, February 21st, 2008

.Net 3.0 & 3.5 provides a number of techniques for you to author your own distributed architectures and I’m going to attempt to explain a technique that “worked for me”, allowing me to write a reliable, testable, service based application using the Windows Communication Foundation (WCF).

The goal of this little project is to create a multipurpose standalone server application that can host any code you wish, using WCF to provide other applications access to the code.  The server application should have no idea what it’s hosting, nor be concerned with it.  New services should be installable in to the service host by configuration tweaks alone.  This will result in a low impact standard method to expose API’s and web services to either external or internal applications using just configuration settings.

 

Pre-Requirements

Throughout this example I’ll be presuming that the reader has a strong grasp of .Net. C#, and Microsoft technologies.  I’ll also touch on nUnit testing and the Castle projects IOC container Windsor, so exposure to either or both of those products would be advantageous.  That said, for the most part, this should just be compile, configure and go.

Castle Windsor: http://www.castleproject.org/castle/download.html
NUnit: http://www.nunit.org/index.php?p=download (or mbUnit if you wish…)
and obviously Visual Studio 2005/2008.

 

Sample Architecture

The following is a pattern that I’ve found to work very successfully:

  • /ServiceApplication
    • /ConsoleHost
    • /SystemService
    • /ServiceContracts
    • /ServiceImplementations
    • /Test_SystemService
    • /Test_ServiceImplementations
    • /CommunicationManager
    • /Installation
  • /ClientApplication
    • /Model
    • /DataManager

We’ll take a look at the client application later, but first a rough outline of the projects that the ServiceApplication consists of.

ConsoleHost is designed to be an exceptionally thin wrapper to provide a console view on the service, it’s concerned only with user interaction and should use CommunicationManager for all of the legwork.

SystemService is an equally thin wrapper around CommunicationManager providing an installable service wrap for your application.

ServiceContracts is an assembly that should contain ONLY the WCF service contracts (C# interfaces) that you intend to make accessible remotely.  You should expect to share this compiled assembly with any client implementations, so ensure this is dependency free (which really shouldn’t be a problem so long as you ensure that you only store interfaces in this assembly).

ServiceImplementations should consist of the ServiceApplication specific implementations of the interfaces defined within ServiceContracts.

Test_SystemService is designed to store unit tests that make use of WCF to connect to the running ServiceApplication, and Test_ServiceImplementations should contain unit tests designed to test the ServiceImplementations directly.  Having these two similar test projects allows you to troubleshoot connection related errors during development independently of code logic related errors.

The CommunicationManager does the brunt of the work, constructing WCF endpoints and maintaining them throughout their lifecycle.  This assembly takes care of the opening and closing of listening services.  It’s constructed of a few key components I’ll detail later.

Installation is reserved for an Installer of your choice, preferably one that can deploy and install Windows Services (WiX or old fashioned MSI projects, I’m looking at you).

I’m not going to go into great detail regarding the SystemService (it’s a standard windows service which calls the same methods the console host will), nor the unit tests or installer.  I’m also not going to try and explain the intricate details of the configuration of WCF, there’s a wealth of resources available online on this topic.  I will however supply some example configuration- enough to make the code functional.

 

Service Functionality

Define Your Service Contracts

The simplest way to start this project is to define an interface in C# which should describe a few basic operations that you wish to make available as a service (the WCF Service Contract).  I’ve distilled this down into an example I’m calling IExampleContract, the contents of which are:

using System.ServiceModel;

namespace DEJW.ServiceContracts
{
    [ServiceContract(Namespace = "http://namespace/", Name = "Example Service")]
    public interface IExampleContract
    {
        /// <summary>
        /// Returns the uniqueIdentifier supplied back to the calling application.
        /// </summary>
        /// <param name=”uniqueIdentifier”></param>
        /// <returns></returns>
        [OperationContract]
        [FaultContract(typeof(ExceptionDetail))]
        string Handshake(string uniqueIdentifier);
    }
}

 

Define the ServiceImplementation tests

For the sake of following good “XP” practice, the next step should be constructing a simple unit test for the methods you wish to define, and then author the implementation top down.  For the above simple “Handshake” method, the following nUnit test should suffice:

[Test]
public void HandshakeWithSimpleString()
{
    string testString = “Hello World!”;

    ExampleContractImpl impl = new ExampleContractImpl();
    string response = impl.Handshake(testString);

    Assert.AreEqual(testString, response);
}

Write the ServiceImplementations to fulfil the tests

With my (failing, no code!) unit test in place, I’ll now write the code to pass the test.  The implementation should go into a ServiceImplementations project (because when you hand your ServiceContracts over to the consuming application, you’d not want to pass over the service implementation to go with it…).

using DEJW.CommunicationManager;
using DEJW.ServiceContracts;

namespace DEJW.ServiceImplementations
{
    public class ExampleContractImpl: IExampleContract, IPlugableService
    {
        #region IExampleContract Members

        public string Handshake(string uniqueIdentifier)
        {
            return uniqueIdentifier;
        }

        #endregion
    }
}

You may have noticed that the implementation features a rogue little interface called IPlugableService that doesn’t appear to need implementing.  This is a concession to the Castle IOC framework and I’ll elaborate on its use in the section on CommunicationManager.


Communication Manager

The CommunicationManager assembly consists of a few key components. 

  • HostManager, responsible for opening and closing WCF endpoints as per the configuration in app.config.
  • IOCFactory, a wrapper for the Windsor containers that helps quickly load a concrete implementation from a configuration value and assembly name.
  • IPlugableService interface, an empty interface used that must be implemented by our service implementations in order for the Windsor container to identify them.
  • IPlugableServiceFactory, an configuration parsing library that inspects configuration and instantiates instances of all the IPlugableServices’ defined in app.config.

I’m not going to go into great detail regarding HostManager, most of the code was adapted from various Microsoft WCF samples with a few generic collections tacked on and a couple of wrapping methods.  There’s nothing high-tech here, it just works.

Usage is very simple:

_hostManager = new HostManager();
_hostManager.AddServiceContracts(PlugableServiceFactory.RetrieveCollectionOfPlugableServices());
_hostManager.StartListening();

As long as your configuration settings are correct, magic happens here.

The key method there is PlugableServiceFactory.RetrieveCollectionOfPlugableServices().  This method loads and traverses the Castle Windsor configuration, and then loads by name every instances of IPlugableService it finds in the config file.  HostManager then uses a typeof on each of these loaded IPlugableService to create a instance of their concrete type, ignoring IPlugableService entirely.  IPlugableService is an interface in place simply so we can tell Windsor what to do.  HostManager then configures the concrete classes as WCF ServiceHosts using the configuration specified.

Configuration Settings

Ensure the following is included in your app.config file:

<configSections>
  <section name=”castle” type=”Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor” />
</configSections>

<castle>
  <components>
    <component  id=”service1″
                service=”DEJW.CommunicationManager.IPlugableService, DEJW.CommunicationManager”
                type=”DEJW.ServiceImplementations.ExampleContractImpl, DEJW.ServiceImplementations” />

    <component  id=”service2″
                service=”DEJW.CommunicationManager.IPlugableService, DEJW.CommunicationManager”
                type=”DEJW.ServiceImplementations.ExampleContractTwoImpl, DEJW.ServiceImplementations” />
  </components>
</castle>

If you look carefully you’ll see why IPlugableService is important; the Windsor components will attempt to instantiate your components as instances of that empty interface.  The type attribute points to “NameSpace.ConcreteClass, assembly” allowing the Windsor container to find your service implementations.

Next you need to add the relevant WCF configuration, it’s quite lengthy if you’re explicit, but descriptive.

<system.serviceModel>
   <bindings>
     <netTcpBinding>
       <binding name=”IExampleContractBinding”
        transferMode=”Buffered”
        transactionProtocol=”OleTransactions”
        hostNameComparisonMode=”StrongWildcard”
        closeTimeout=”00:01:00″
        openTimeout=”00:01:00″
        receiveTimeout=”00:10:00″
        sendTimeout=”00:10:00″
        transactionFlow=”false”
        maxBufferPoolSize=”50000000″
        maxBufferSize=”268435455″
        maxReceivedMessageSize=”268435455″
        maxConnections=”10000″
                >
         <readerQuotas
           maxDepth=”50000000″
           maxStringContentLength=”50000000″
           maxArrayLength=”50000000″
           maxBytesPerRead=”50000000″
           maxNameTableCharCount=”50000000″
         />
         <reliableSession ordered=”false”
           inactivityTimeout=”00:10:00″
           enabled=”false”
         />
         <security mode=”None”>
           <transport clientCredentialType=”Windows” />
           <message clientCredentialType=”Windows”/>
         </security>
       </binding>

     </netTcpBinding>

   </bindings>

   <behaviors>
     <serviceBehaviors>

       <behavior name=”IExampleContractBehaviour”>
         <serviceMetadata httpGetEnabled=”true” />
         <dataContractSerializer maxItemsInObjectGraph=”100000″/>
         <serviceThrottling maxConcurrentCalls=”100″ maxConcurrentSessions=”100″ />
       </behavior>

     </serviceBehaviors>
   </behaviors>

   <services>
     <service name=”DEJW.ServiceImplementations.ExampleContractImpl” behaviorConfiguration=”IExampleContractBehaviour”>

       <endpoint name=”IExampleContractEndpoint”
                 address=”query”
                 binding=”netTcpBinding”
                 bindingConfiguration=”IExampleContractBinding”
                 contract=”DEJW.ServiceContracts.IExampleContract” />

       <endpoint name=”IExampleContractMetaData”
                 address=”mex”
                 binding=”mexHttpBinding”
                 contract=”IMetadataExchange” />

       <host>
         <baseAddresses>
           <add baseAddress=”net.tcp://localhost:8000/DistributedServer” />
           <add baseAddress=”http://localhost:8001/DistributedServer” />
         </baseAddresses>
       </host>
     </service>

     <service name=”DEJW.ServiceImplementations.ExampleContractTwoImpl” behaviorConfiguration=”IExampleContractBehaviour”>

       <endpoint name=”IExampleContractTwoEndpoint”
                 address=”query”
                 binding=”netTcpBinding”
                 bindingConfiguration=”IExampleContractBinding”
                 contract=”DEJW.ServiceContracts.IExampleContractTwo” />

       <endpoint name=”IExampleContractTwoMetaData”
                 address=”mex”
                 binding=”mexHttpBinding”
                 contract=”IMetadataExchange” />

       <host>
         <baseAddresses>
           <add baseAddress=”net.tcp://localhost:8002/DistributedServer” />
           <add baseAddress=”http://localhost:8003/DistributedServer” />
         </baseAddresses>
       </host>
     </service>
   </services>
</system.serviceModel>

Obviously your mileage may vary with the above configuration (a lot of those values are values I’ve used in my day job for development purposes, but you’ll want to tighten down lots of those values and, I suspect, enable security for any production system).

Control Application

The control application that goes with this code is practically nonexistent (one of the stated goals) just stick the aforementioned usage example in the main method, followed by some kind of message and a ReadLine() to stop the application exiting.  Something akin to:

_hostManager = new HostManager();
_hostManager.AddServiceContracts(PlugableServiceFactory.RetrieveCollectionOfPlugableServices());
_hostManager.StartListening();

Console.WriteLine(”Press any key to exit”);
Console.ReadLine();

For the windows service implementation create a static instance of HostManager and override protected override void OnStart(string[] args), in this method call the StartListening() method on HostManager, and override OnStop to call the StopListening() method for a clean shutdown.

Maintainability

The key benefit to this approach to service hosting is how trivial it makes expanding your services.  In order to add extra functionality to an existing service you need to modify the service contract and service implementation, recompile those two projects and let the HostManager do the rest.  If you wish to host an entirely new service, create a new service contract and implementation, and remember to add a configuration section to app.config, and again, let HostManager take care of the details.

 

Source code

The source code provided here is NOT a compiling project.  Instead I’ve provided the CommunicationManager project (if you’ve read the above details you’ll realise that’s all you really need), the example ServiceContracts and example ServiceImplementations, alongside the example unit test and an example App.config.

If you wish to use this code, remember you’ll need a copy of the Windsor components, you’ll need NUnit if you want to run the unit test and you’ll need to write your own console / service wrapper.

Some of the code in here was inspired by writing a more specific service for my employer that made me wonder if I could abstract the service host portion of the code into a more general purpose application.  Apparently it was possible!  I’ve not reused any code however I’d imagine the similarities are striking, so whilst not “production tested”, the methods and techniques used should be relatively bug free.  No warranty etc etc, but I hope somebody finds this useful.  It’s definitely the approach I intend to take to authoring services from this point forwards.

 Download GenericWCFServer.zip

Now Playing: Zimmers Hole – When You Were Shouting At The Devil… We Were In League With Satan