The new configurable Mud Engine Server Adapter

Back in May I posted about how you could configure the mud server for use with the Mud Engine. Since then, I have built out an implementation of the Adapter pattern. With that, I wanted to demonstrate how you would startup the server with the engine, and configure it.

Previously in the Mud Engine

In the last iteration of my configuration setup, you had to implement the abstract ServerBootstrap class, and then build out an implementation of IServerConfiguration. The bootstrap implementation looked something like this.

public class DefaultServerBootstrap : ServerBootstrap
{
    protected override void Run()
    {
        this.Server.GetCurrentGame()
            .NotificationCenter
            .Subscribe<ServerMessage>((msg, sub) => 
                Console.Write(msg.Content));

         while (this.Server.Status != ServerStatus.Stopped)
        {
            Thread.Sleep(100);
        }
    }

    protected override void RegisterAssemblies()
    {
        base.RegisterAssemblies();
    }

    protected override void ConfigureServices()
    {
    }

    protected override IServerConfiguration CreateServerConfiguration()
    {
        return new ServerConfiguration();
    }

    protected override IServer CreateServer()
    {
        var server = new Server();
        server.PlayerConnected += this.ExecuteInitialCommand;
        return server;
    }

    protected override IGame CreateGame()
    {
        return new DefaultGame();
    }

    protected override IInputCommand InitialConnectionCommand()
    {
        returnnew PlayerLoginCommand();
    }

    protected override void RegisterAllowedSecurityRoles(IEnumerable<ISecurityRole> roles)
    {
    }
}

Then in the application startup, you had to setup the bootstrap.

public static void Main(string[] args)
{
    var bootstrap = new DefaultServerBootstrap();    
    Task bootstrapTask = bootstrap.Initialize();
    bootstrapTask.Wait();
}

This was the minimum that had to be done in order to start the game with a server. There were several issues with this approach, one of which is violating SRP. The bootstrap does a lot of different things that aren't even related to the server. It defines the initial command, creates a player, and creates the game. None of which are specific to the server. These actions can be applicable in a single-player game as well.

The other thing that the bootstrap does is configures any services, and register security roles with the services. Gross. The server startup should be free of IoC dependency injection setup goo. So I set out to fix that with the new Mud Engine Adapters.

Setting up a server with adapters

Now that the server has been migrated over to use the adapter architecture, it's much more straight-forward to get a server running. Previously, the server owned the game. Now, the game owns the server - it just doesn't know it.

To start up the game, and give it a server, we do this.

static void Main(string[] args)
{        
    var serverConfig = new ServerConfiguration();
    IServer server = new WindowsServer(new TestPlayerFactory(), new ConnectionFactory(), serverConfig);

    var gameConfig = new GameConfiguration();
    gameConfig.UseAdapter(server);  

    var game = new MudGame();
    game.Configure(gameConfig);

    Task gameStartTask = game.StartAsync();
    gameStartTask.Wait();
}

In the code above, we create a serverconfiguration. Then we create a WindowsServer instance, giving it a couple of factories and our config. Next we we create a GameConfiguration and register our WindowsServer with the game config. When we call game.Configure(gameConfig), the game will consume the WindowsServer adapter and automatically configure the server using the ServerConfiguration.

Lastly, we start the game calling game.StartAsync(). This initialize and run all of the registered adapters that the game has. In our case, it initializes and runs the WindowsServer. At this point, the WindowsServer is running and can accept incoming client connections.

There is some flexability when it comes to configuring adapters. Each adapter can either skip configuration all-together, or opt into configuration by requiring a configuration class. This can be any class that implements the IConfiguration interface. Taking this approach allows each adapter to have their own config that can be tailored to what they want to expose. In the case of Server Configuration, there is quiet a bit we can do with it. For instance:

var serverConfig = new ServerConfiguration();
serverConfig.OnServerStartup = (context) => 
    Console.WriteLine($"Server running on port {context.Server.RunningPort}");

That code registers a callback that will be invoked when the server is starting. In this example, we just lookup the port the server is running on and write it out to the console. You can do more then just that however.

static void Main(string[] args)
{        
    var serverConfig = new ServerConfiguration();
    serverConfig.OnServerStartup = (context) =>
    {
        context.ListeningSocket.BeginAccept(
            new AsyncCallback(Program.HandleClientConnection), context.ListeningSocket);
        context.SetServerState(ServerStatus.Running);
        context.IsHandled = true;
    };

    IServer server = new WindowsServer(new TestPlayerFactory(), new ConnectionFactory(), serverConfig);

    var gameConfig = new GameConfiguration();
    gameConfig.UseAdapter(server);

    var game = new MudGame();
    game.Configure(gameConfig);

    Task gameStartTask = game.StartAsync();
    gameStartTask.Wait();
}

private static void HandleClientConnection(IAsyncResult result)
{
    Socket server = (Socket)result.AsyncState;
    Socket clientConnection = server.EndAccept(result);

    // Fetch the next incoming connection.
    server.BeginAccept(new AsyncCallback(HandleClientConnection), server);

    // Create player character here.
}

In this example, we used both the WindowsServer and it's Socket to completely replace the way incoming connections are handled. We're not replacing how client communication between the server and client are handled (that is planned) but allowing users to define custom server behavior without reimplementing IServer. At the end of the OnServerStartup callback, we set IsHandled to true, which tells the server to stop using its internal startup and rely on the custom logic being defined.

There are more things you can do, such as intercepting the shutdown of the server, client connections, disconnects and more.

Sharing information across adapters

The server publishes out messages that you can intercept and react to as well. An example is this:

static void Main(string[] args)
{
    SetupMessageBrokering();

    var serverConfig = new ServerConfiguration();
    IServer server = new WindowsServer(new TestPlayerFactory(), new ConnectionFactory(), serverConfig);

    var gameConfig = new GameConfiguration();
    gameConfig.UseAdapter(server);

    var game = new MudGame();
    game.Configure(gameConfig);

    Task gameStartTask = game.StartAsync();
    gameStartTask.Wait();
}

static void SetupMessageBrokering()
{
    MessageBrokerFactory.Instance.Subscribe<InfoMessage>(
        (msg, subscription) => Console.WriteLine(msg.Content));

    MessageBrokerFactory.Instance.Subscribe<GameMessage>(
        (msg, subscription) => Console.WriteLine(msg.Content));

    MessageBrokerFactory.Instance.Subscribe<PlayerCreatedMessage>(
        (msg, sub) => Console.WriteLine("Player connected."));

    MessageBrokerFactory.Instance.Subscribe<PlayerDeletionMessage>(
        (msg, sub) =>
        {
            Console.WriteLine("Player disconnected.");
        });
}

The first thing we do is subscribe, via the MessageBroker, to a series of messages that can be published by other objects. In this scenario, the WindowsServer will publish messages that are InfoMessage, PlayerCreatedMessage and PlayerDeletionMessage. The MudGame will publish GameMessage notifications. This looks like this when the server is running and has accepted several connections, and had a few disconnects.

The flexability given now with adapters and their custom configurators will make it easy to get up and running, and still provide you with a lot of flexability when you want to do more advanced things.

As always you can replace the IServer or IServerConfiguration implementations with your own all together. Since IServer inherits from IAdapter your custom implementation can plug straight into the game using the game.UseAdapter(customServer) call.

Handling what is missing

The original implementation shown at the start of this post had some other things being done. It handled the setup of security and commanding. That responsibility will be moved to additional adapters, which will run independent of the server and game. They can subscribe to messages sent from the server and react to them, launching the initial login command and handling security without knowing that the server even exists.

var gameConfig = new GameConfiguration();
gameConfig.UseAdapter(new WindowsServer());
gameConfig.UseAdapter(new CommandManager());
gameConfig.UseAdapter(new SecurityBroker());
gameConfig.UseAdapter(new WorldManager());

var game = new MudGame();
game.Configure(gameConfig);

Task gameStartTask = game.StartAsync();

Each one of the adapters shown above have not been written yet; they are coming. When they are ready, they will share the same level of flexability as the server, using configuration objects that you can intercept and interact with.

There is a lot of other new stuff happening in the engine that won't fit into this post, like a new home on GitHub (more on that in a different post), character APIs and real usage documentation.

More coming soon!

Introducing adapters in Mud Engine

I've had a pretty configurable startup sequence with the Mud Engine for a bit now, but I wasn't really happy with it. The issue that I had was that you still performed to much initialization logic in a boot strap class, or in the server app startup (not the server implementation themselves).

I wanted to make the whole configuration piece of the engine more extensible, and easier to plug into. The engine already uses a custom message brokering pipeline to publish messages to subscribers, and so I wanted to harness that a bit with the configuration.

Adapters

There is a new interface in the engine called IAdapter. It provides a series of methods for letting adapters subscribe to messages published from within the engine, along with publishing their own. It's an IInitializableComponent, so it can be initialized and deleted. This allows for adapters to perform cleanup, such as unsubscribing from the message broker, when they are being deleted.

The IAdapter includes a Name property so that the adapter can have a name; most importantly though is the Start(IGame) method. This method allows your adapters to spin off their own background tasks and do what ever they want while the game continues to run.

The engine currently has a WorldManager adapter, which initializes all of the worlds it is given and starts the world clocks/weather climate clocks etc. The engine server is being modified as well allowing it to become an adapter that starts up and runs when the game starts.

How it works

So how do adapters fit in to the workflow of the engine? Adapters are registered with a modified IGameConfiguration interface. This interface is then given to an IGame when you call Configure() on the game instance. The default IGame implementation (MudGame) pulls all of the adapters out of the configuration class and initializes them when IGame.Initialize() is invoked. It then starts each one of the adapters when the IGame.StartAsync() method is invoked. When IGame.StartAsync() is invoked, an internal game loop is created and the game will forever run. Because of this, adapters must not perform any long running or blocking tasks. If you have to perform a long running operation, such as running a server, spin it up on a worker thread and do the work there.

Example Game setup

I wrote a quick unit test to demonstrate how you can setup a game using adapters.

private async Task TestGameStartup()
{
    // Mocks & Adapters
    IWorldFactory worldFactory = Mock.Of<IWorldFactory>();
    IAdapter server = Mock.Of<AdapterBase>();
    IAdapter worldManager = new WorldManager(worldFactory);

    // Create our game configuration
    IGameConfiguration configuration = new GameConfiguration { Name = "Sample Mud Game", };
    configuration.UseAdapter(server);
    configuration.UseAdapter(worldManager);

    // Setup and run the game.
    IGame game = new MudGame();
    await game.Configure(configuration);
    await game.StartAsync();
}

The above code creates a fake world factory, as an IWorldFactory implementation is required by the WorldManager adapter. I also create a fake server by mocking an adapter base class that the engine provides.

Once my adapters are setup, I create a new GameConfiguration and pass the adapters in to the config using the UseAdapter method. There is also a generic version of this method (UseAdapter<T>).

Lastly, we create a new MudGame, configure the game using our new GameConfiguration instance and then we start the game. Note that game.Initialize() did not get called here. That is because the MudGame class checks if it has been initialized upon starting and initializes itself and all its adapters if that has not happened yet.

At this point, the awaited StartAsync method will not end until something within the engine signals it needs to end, or something calls game.Stop(). It creates an internal game loop and runs.

There is another approach that can be used for those that want a custom game loop.

game.BeginStart(runningGame =>
    {
        Task.Run(() =>
        {
            while (runningGame.IsRunning)
            {
                // Thread.Sleep(1) is not available on Portable Libraries.
                Task.Delay(1).Wait();
            }
        });
    });

This will instead start the game and invoke your callback. This lets you run the game loop in a Task for things like an editor, and not block and UI threads. Your editor or client can still stop the game by invoking game.Stop(). As long as your while loop checks for IsRunning, you're game loop will safely be shut down.

There's a lot of additional new stuff that I couldn't fit in to this post, so I'll work on making more frequent posts with the change that have taken place over the last couple of months.

For now, EOF.

Mud Designer's first real sprint

Now that I have Mud Designer moved over to Visual Studio Online (VSO) I can start really making use of the Agile platform that VSO is built on top of. Going forward, the project will adopt the Agile methodology, with developing taking place during sprints.

The first sprint started today with three User Stories being brought in to the sprint.

  • Text File Data Storage Service
  • Character Security Permissions
  • Command Security

Text File Data Storage Service

Once this is completed, I will have the first of many data storage services created. The intent is to create a simple data store to use while I build the rest of the engine. I have other Stories for creating SQL and Cloud based services, but those are more complex. While the engine is being developed, I want to just use a simple local data store.

Character Security Permissions

This story contains the meat of the engines security framework. When completed, Permissions can be created and assigned to Roles. There will be a framework constructed for objects that need specific security permissions, to register for them.

Command Security

Pigging backing on top of the Character Security Permissions story, this will allow Commands to register for permissions they require. The engine will ensure that users have the required permissions within their roles before letting them execute the command.

Wrapping up

Since I am the only developer, each sprint is scheduled for 4 weeks, so it will be a bit before this sprint is completed. If the user stories are finished early, I will pull more stories in and continue working until the end of the sprint.

As each story is completed, I plan on writing a post on what work was done and what the features are. I would also like to do a code analysis and report the quality of the code for each story.

Mud Designer Architecture

I had a bit of free time tonight, so I thought I would put together a quick post on how the overall engine architecture now looks. The following is a diagram showing the engine's major layers.

As shown in the diagram, the application is broken up in to three major layers, not including the apps.

Engine

The Engine layer being the base layer that everything is built on top of and relies on. The engine has a Core project, that is a portable class library. This project contains all of the Types that can be shared across all platforms, including Windows 7, Windows 8, Windows 8 Metro, Windows Phone 8, iOS, Android, Linux and OS X.

The Desktop application project holds the Types that can be shared across desktop applications, with the goal being Windows 7, Windows 8 desktop, Linux and OS X.

The Networking.Portable will eventually be renamed to Default.Mobile, and that will contain Types specific to mobile devices like Windows 8 metro, Windows Phone 8, iOS and Android.

The bulk of the code will be usable across all platforms, which was the biggest challenge. Since I don't have Xamarin licenses, I can't do any testing to see if the code runs as expected on iOS & Android. I should be able to start running tests in OS X over the next month.

Windows Desktop App

This layer is composed of several projects that ultimately make up the Windows Desktop version of the editing tools & server. The actual app will reference an Infrastructure project, which will contain support Types and region definitions. A region is a part of the user interface that can hold a module and ultimately provide support for 3rd party plugins. An example of a region would be that of a menu region, content region or a toolbox region. Regions provide an easy way for 3rd party developers to create modules that plug in to the editor, in the area that they feel it needs to be installed to, with ease.

A modules project is actually another layer by itself, that sits as part of the overall app. There can be an unlimited number of module projects, each providing the actual Views and view models that the app will use. It provides support for 3rd party modules that can be plugged in to the editor at run-time. Modules are used by the editor to provide tools to the end-user for creating their game. Modules are not referenced by anything, allowing them to be freely added and removed without needing to rebuild the toolkit. The modules themselves only reference the infrastructure and shared windows library.

Both the Infrastructure and Modules projects reference a Windows Shared Library project. This project will contain code that can be shared across multiple Windows Desktop apps. Such as the Server, the Editor and a future Web-App. This will contain things such as support classes, Factories and any Facade's that can be shared.

Shared Windows Library

The Shared Windows Library will contain the code needed to set up all of the dependency's, determine what repositories and services are needed and expose them through an interface to the apps. Mostly via Factories.

Windows store Apps

This layer provides the code-base for the Windows metro styled apps. These will require their own views and view models, but should be able to share the same factories and repositories.

Repository

The Repository layer is used to bridge the gap between the App and the data storage medium. There will be two different ways to retrieve objects within the app.

  1. Create a new instance using a Factory in the the Windows Shared Library
  2. Fetch existing objects using a Repository.

The Repository will let the app restore, save and delete objects without the app needing to know what the storage medium is. You can easily replace the default storage mediums with something custom if you want, such as some kind of cloud hosting. The overall framework won't really need to know. There is some set-up that must be done to facilitate this, but that is pretty straight forward and will be saved for another post.

Since the data store is often times platform specific, Repositories provide the app and engine a cross-platform solution to accessing data. They don't need to know what platform they are running on, or where the data is stored. You can also intermix data stores, such as saving player data locally in encrypted files and hosting your world data in the cloud. The repositories take care of putting it all back together.

Repositories are also used for data caching. If one object asks a repository to fetch a collection of every Room in the game, the repository will cache the data fetched from the storage service. The next object that asks for a one or many rooms, will be provided an instance that was previously cached. This saves trips to the data storage, which is often times expensive from a performance stand-point to do.

Note that a Desktop and a Portable Repository project is shown only to demonstrate that you could have a repository per platform if needed. Since different platforms might require different caching techniques. When the engine ships, the goal is to only ship a Repository layer that is not broken down in to Desktop and Portable. I want that to take place at the Service layer and allow the engine and all apps to share the same Repositories.

Services

While the Repostories are meant to let objects access data without knowing where it is stored, the Services layer must communicate directly with the stored data. This layer is what performs the communication with any storage servers, deserialization of xml files, encryption and data transformation. An object can be transformed to fit in to a specific data structure for saving, and then transformed back in to the object it came from when loaded later.

Finally

This set up has provided the engine with a nice level of abstraction and layering. All of the core components in each layer are hidden behind interfaces, so 3rd party developers may customize or replace pieces within each layer as needed.

This post only showed the Windows Apps. Adding other platforms would only require a new project for each platform, such as OS X, with views, view models and any platform specific support. Once the overall product is finished, adding support for other platforms should be a relatively simple endeavor.

In a future post, I will break each layer down - once a bit more of the framework is completed - and review them in a bit more detail. More and likely one post per layer.

Mud Designer's world clock

Tonight I was able to finally get a world clock built in to the Mud Designer engine. The world clock is pretty flexible, allowing users to specify how many real-world hours pass before 1 in-game day is completed. The engine then does a break down and broadcasts updates every in-game minute.

Time of day states

If you set your in-game to real-world hour ratio to 4:24, then the update event will get called every 10 seconds. This means that 1 in-game minute will pass every 10 seconds. If the ratio is to low, the engine will switch over and broadcast updates every in-game hour instead, to prevent stress on the server.

The engine uses an ITimeOfDayState implementation to determine what the current time of day is. It holds a collection of these objects and transitions between the different times of day as needed. The ITimeOfDayState objects have a StartTime property that tells the engine when it needs to transition to the state. This allows users to create their own time of days, such as Evening and LateNight, and let the engine handle moving between the states.

Building a time of day state is really simple. You can just inherit from it's parent class like this:

public class AfternoonState : TimeOfDayState
{
    public AfternoonState()
    {
        this.StateStartTime = new TimeOfDay();
        this.StateStartTime.Hour = 12;
    }

    public override string Name { get { return "Afternoon"; } }

    public override TimeOfDay StateStartTime { get; set; }

You can of course choose to implement a state from ITimeOfDayState, but by inheriting from the abstract TimeOfDayState class, the time of day engine clock will be managed for you, along with the in-game to real-world time conversions.

The engine's IWorld implementation is notified every in-game minute that goes by (or hour if the frequency is to low). When the world is notified, it updates itself accordingly, and checks to see if the state needs to be changed. If so, it transitions the states and posts it's own event that notifies registered objects that a state change took place. This allows developers to publish messages to the users when the time of day changes.

The Engine Timer

Since the engine is being built with full cross-platform support via Portable Class Libraries, I ran in to an issue with the .NET built-in thread-safe Timer class missing. After doing some searching around, it seems that Microsoft did include it in their Portable Class Library profile, but Xamarin has not. Since I am targeting iOS and Android as well, I loose out on the classes Microsoft includes in their latest profiles, until Xamarin updates their profiles.

In order to work around this, I built a custom Timer for the engine, called EngineTimer. It's pretty simple to use and looks like this.

var worldClock = new EngineTimer<IWorld data-preserve-html-node="true">((stateData, clock) => DoSomething(), this);
worldClock.Start(startDelay: 0, interval: 5000);

The EngineTimer is what the Mud Designer will use through-out to handle it's internal state. The Worlds will use one for updating the time of day, Zones will use one for updating their weather conditions, the game class will use one for auto-saving and there will be more usage through-out the engine with it.