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.

Mud Designer Code Analysis: Sealed Attributes

I had mentioned a couple of times that I would be refactoring the current engine re-write using the NDepend statically analysis tool. I performed an initial analysis last night and reviewed the report and started to dig in. Some of the issues that I ran in to were really simple to fix. Let's start with those first.

Avoid unsealed attributes

Microsoft's MSDN states that for performance reasons, you should avoid unsealed attributes whenever possible. Considering that the engine's built-in validation mechanics are built off of attributes, I want to make sure and grab any performance increase that I can get.

I started out with an existing Fixture model that I created during development. The model is really simple and includes three properties, each being validated in some manor.

public class ValidatableFixture : ValidatableBase
{
    private const string PasswordConfirmationDelegateName = "ConfirmPasswordsMatch";

    public ValidatableFixture()
    {
        this.Name = string.Empty;
        this.Password = string.Empty;
        this.PasswordConfirmation = string.Empty;
    }


    [ValidateValueIsNotNullOrEmpty(ValidationMessageType = typeof(MessageFixture), FailureMessage = "Name must be set.")]
    public string Name { get; set; }


    [ValidateValueIsNotNullOrEmpty(ValidationMessageType = typeof(MessageFixture), FailureMessage = "Password must be set.")]
    [ValidateStringIsGreaterThan(GreaterThanValue = 4, ValidationMessageType = typeof(MessageFixture), FailureMessage = "Password must be greater than 4 characters.")]
    public string Password { get; set; }


    [ValidateWithCustomHandler(DelegateName = PasswordConfirmationDelegateName, ValidationMessageType = typeof(MessageFixture), FailureMessage = "Passwords do not match.")]
    public string PasswordConfirmation { get; set; }


    [ValidationCustomHandlerDelegate(DelegateName = PasswordConfirmationDelegateName)]
    public IMessage PasswordConfirmationValidation(IMessage message, PropertyInfo property)
    {
        return this.PasswordConfirmation.Equals(this.Password) ?
            null :
            message;
    }
}

This fixture contains four total validation rules that will be invoked during the test. The most expensive of the four would be the ValidateWithCustomHandler attribute. Unlike the rest of the validation system, the ValidateWithCustomHandler attribute does not cache the MethodInfo object it fetches via reflection. At the moment, the engine just caches the attributes themselves and their associated properties for re-use across multiple instances. Caching of method delegates will make its way in to the system at some point in the future.

To get started, I wrote a simple unit test that creates 1,000 instances of the ValidatableFixture class and invokes ValidateAll(). The unit test ran through all 1,000 instances, invoking Validate() on each attribute, which caused the attribute validation to take place. In theory, there shouldn't be a huge penalty here due to the caching I am doing. Once the first ValidatableFixture is instanced, the rest of them use the PropertyInfo and ValidationAttribute cache that the first one generated. There won't be any deep walking of the attribute heirarchy.

// Arrange
var fixtures = new List< ValidatableFixture>();
var watch = new Stopwatch();
for (int index = 0; index < 1000; index++)
{
    var model = new ValidatableFixture();
    model.Name = "TestName";
    model.Password = "pass";
    model.PasswordConfirmation = "pass";
    fixtures.Add(model);
}

// Act
watch.Start();
foreach(ValidatableFixture fixture in fixtures)
{
    fixture.ValidateAll();
}

watch.Stop();
Debug.WriteLine(watch.Elapsed.TotalMilliseconds);

I ran the test 5 times and ended with an average of 41.3199ms.

Finally, I went through and sealed all of the validation classes and re-ran the test. To my surprise, the results ended up be slower than leaving them unsealed, with an average time of 43.3881ms.

I found this to be really interesting, as sealing the class should technically make it faster.

I did some research online and discovered there is actually a debate over whether you should or should not seal your classes. I'm in the camp that they should be sealed unless there is an explicit need to override them. In the case of the validation attributes, they should remain sealed, even at the cost of a bit of performance. The idea behind the validation rules is that developers should write their own implementation of IValidationRule rather than inheriting from an existing one and trying to change one step out of many within the classes validaiton process. It opens up the possibility of unexpected results happening behind the scenes during the validation process.

Mud Designer Alpha 3 Analysis with NDepend

I was finally able to get the Mud Designer in to a usable state over the weekend. It has an improved Telnet server that is completely decoupled from the IGame interface. The only coupling the server has with the engine at the moment is a reference to IPlayer, which I might be able to get rid of at some point down the road.

I thought this would be a good time to run some code analysis on the project and see where it stands. Unfortuantely, the report didn't bring the good news I was hoping to see. Let's take a look at the report.

The project contains 1,270 lines of code (compared to Alpha 2 which had 3,852) along with 89 Types (compared to 152). The Alpha 2 release contained 8 critical rule violations and 828 standard violations. Looking at the numbers for Alpha 3, they're roughly cut in half. I was hoping for the number to be lower, but it's early enough in the re-write that I can address this and lower these numbers. The goal of the re-write is to produce a more reliable code-base that provides greater flexibility and is easier to maintain. Proper patterning, architecture, design and code quality is critical for this. NDepend does an excellent job of identifying the areas that I need to address, and allows me to research and apply code designer philosophies.

One of the things that has greatly improved with the current code base is the Cyclomatic Complexity of the source. The overall average is about the same, but the maximum is down from 74 paths to 23.

Over the course of this week as I address some of these code violations, I will post a blog entry for the rule(s) I am currently working on addressing. The problematic source will be posted along with the end result of the refactor to satisfy the NDepend analyzer