MudDesigner: Configurable stand-alone Server Client

The Mud Designer's Runtime server code has become a pretty solid component. Gone is the old infinite loop and tightly coupling the server all over within the engine runtime. Now the runtime runs completely independent of the server. The server, and the way it will handle processing commands sent from the user, has been abstracted away from the actual player code. This allows the engine runtime to run as a singleplayer game if needed, or move across platforms without worrying if its going on a mobile device with out a server or not.

As a result of this, the actual server client application needed to be revised. The client application (a Win32 Console app) was originally responsible for the following workflow

  • Create Server instance
  • Configure the server properties
  • Create a game instance
  • Configure the game
  • Start the server
    • Provide the server the game
    • Provide the server the player class to use
    • Provide the server all of the dependencies the game and player might need.
  • Listen to game world changes and render them.

This resulted in none of the code being easily shareable across projects. If I wanted to spin up a server in the Design Editor, I'd have to either copy/paste the code or re-write it. Luckily that isn't the case any longer. The actually MudDesigner.Windows.Server.exe server application only needs the following two lines of code:

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

The application defers all of the server instancing, configuration, game setup and starting of the server to the bootstrap class. The class inherits from ServerBootstrap which is an abstract class. Developers may inherit from the ServerBootstrap so that they can configure the server application startup and dependency model on their own, or use the default bootstrap that ships with the engine.

Bootstrap methods

The ServerBootstrap class has the following abstract methods that children classes must implement.

protected abstract void Run();
protected abstract void ConfigureServices();
protected abstract IServerConfiguration CreateServerConfiguration();
protected abstract IServer CreateServer();
protected abstract IGame CreateGame();
protected abstract void RegisterAllowedSecurityRoles(IEnumerable<ISecurityRole> roles);

Run

This method is responsible for handling the actual game loop. When this method exits, the server application shuts down.

ConfigureServices

This is where any dependency injection requirements can be setup. The Runtime has been built with the assumption that an IoC container of some kind will be used, so objects ask for all of their dependencies to be passed through their constructor. You may opt out of using DI by implementing your own bootstrap class.

CreateServerConfiguration

The Runtime now includes an IServerConfiguration interface that is passed in to the IServer.Start() method invocation. The Start() method uses the IServerConfiguration instance to configure itself. The CreateServerConfiguration method is responsible for creating an instance of a class implementing the IServerConfiguration interface, and returning it. The DefaultServerBootstrap that ships with the engine resolves this through the IoC container.

CreateServer

This method must create an instance of a class implementing the IServer interface and return it. The DefaultServerBootstrap that ships with the engine resolves this through the IoC container.

CreateGame

This method must create an instance of a class implementing the IGame interface and return it. The DefaultServerBootstrap that ships with the engine resolves this through the IoC container.

RegisterAllowdSecurityRoles

The method will be given a collection of ISecurityRole objects. These are all of the roles available for assigning to players. This method allows you to set up how the roles will be fetched when needed. The DefaultServerBootstrap that ships with the engine registers the collection of roles with the IoC container. The roles will be resolved through DI when ever the Runtime engine asks for them.

Conclusion of Bootstrap

The ServerBootstrap class will hopefully help make the code used for the creation, setup and running of the game and its server reusable across multiple applications. I will now be able to use the same bootstrap in the stand-alone server, the Designer toolkit and on a web server.

Notes on Dependency Injection

The MudDesigner.Windows.Server.exe server application uses dependency injection to provide the engine runtime with everything it needs. The engine runtime itself does not make use of dependency injection. If you want to use the engine, with a custom toolchain, you can do so, without being forced to use DI.

Localization Support for ValidatableBase

Localization Support

The included Validation Attributes now all support localization, allowing your failure messages to be presented to the user in the native language for global applications. In order to provide this in a cross-platform manor (iOS, Android and Windows), localization support must be handled with a couple levels of indirection.

Without localization, you would manually specify the FailureMessage like this:

[ValidateObjectHasValue(
    FailureMessage = "Email address must not be blank.",
    ValidationMessageType = typeof(ValidationErrorMessage))]
public string Email
{
    get
    {
        return this.email;
    }

    set
    {
        this.email = value;
        this.OnPropertyChanged("Email");
    }
}

Localization is done by specifying a localization key on your validation rules and omitting the FailureMessage property assignment like the following.

[ValidateObjectHasValue(
    LocalizationKey = "User-Email-Validation-Failure-Cannot-be-blank",
    ValidationMessageType = typeof(ValidationErrorMessage))]
public string Email
{
    get
    {
        return this.email;
    }

    set
    {
        this.email = value;
        this.OnPropertyChanged("Email");
    }
}

When validation is performed, and the Email property is null, a localized failure message will be assigned to the FailureMessage property.

In order to facilitate this, the validation rules fetch an implementation of IValidationLocalizationService from a new Factory, the ValidationLocalizationFactory. The API ships with a Windows App Store supported localization service in the Universal App Shared project.

The factory must provide this service to the validation rules. In order to do that, you must initialize the factory. This is demonstrated in the sample projects as well, in the App.Xaml.cs file.

public App()
{
    this.InitializeComponent();
    this.Suspending += this.OnSuspending;

    ValidationLocalizationFactory.Initialize<ValidationLocalizationService>();
}

The factory is initialized with our Windows App Store version of the localization service included in the sample project. The validation rules will use this service any time that it needs to fetch a localized string.

Another feature of the localization support are fallback messages. While you are developing the application, you often don't have all of the localization done. You can assign a value to both FailureMessage and LocalizationKey. The validation rule will try to fetch a localized string and if none exist, continue to use the specified FailureMessage. If it finds a localized string, it replaces the fallback value with the localized string for you.

The following demonstrates this:

[ValidateObjectHasValue(
    FailureMessage = "Email address can not be blank.", /* fallback if localization does not exist for the key yet */
    LocalizationKey = "User-Email-Validation-Failure-Cannot-be-blank",
    ValidationMessageType = typeof(ValidationErrorMessage))]
public string Email
{
    get
    {
        return this.email;
    }

    set
    {
        this.email = value;
        this.OnPropertyChanged("Email");
    }
}

You can create a custom implementation of IValidationLocalizationService for iOS and Android apps as well. Just initialize the ValidationLocalizationFactory with the Service type for each platform. This allows you to use localized text across all platforms that your app can run on, without making any changes to your models or building custom validation rules per-platform.

Check out the latest build over on the GitHub Repository.

Good-bye OnPropertyChanged. Hello BindableProperty

One of the most annoying things with XAML binding in WPF and Windows App Store apps is the need to raise a property changed notification to the user interface. Typically, you would abstract the actual property changed notification in to a base class like this:

public class BindableBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void SetProperty<T>(ref T oldValue, T newValue, [CallerMemberName] string property = "")
    {
        if (object.Equals(oldValue, newValue))
        {
            return;
        }

        oldValue = newValue;
        this.OnPropertyChanged(property);
    }

    protected virtual void OnPropertyChanged(string property)
    {
        var eventHandler = this.PropertyChanged;
        if (eventHandler != null)
        {
            eventHandler(this, new PropertyChangedEventArgs(property));
        }
    }
}

This at least prevents you from having to implement INotifyPropertyChanged on every one of your models. The issue however is that you still need to raise the event. In order to do so, you would invoke the base class' OnPropertyChanged method.

public class User : BindableBase
{
    private string firstName;

    private string lastName;

    public string FirstName
    {
        get
        {
            return this.firstName;
        }
        set
        {
            this.SetProperty(ref this.firstName, value);
        }
    }

    public string LastName
    {
        get
        {
            return this.lastName;
        }

        set
        {
            this.SetProperty(ref this.lastName, value);
        }
    }
}

The boiler plate code here gets really monotonous when you have a project with more than a handful of models. Luckily, Roslyn now has Initializer support for Auto-Properties..

With Auto-Property Initializers, we can build a wrapper around the actual property and bind to the value our wrapper holds. To demonstrate, we will create a simple wrapper. There will be a generic and a non-generic flavor. The non-generic provides a static method for constructing a generic wrapper. We will call this wrapper BindableProperty.

Generic Property Wrapper

public class BindableProperty<T> : BindableBase
{
    private T value;

    public BindableProperty(T value, [CallerMemberName] string propertyName = "")
    {
        this.value = value;
        this.Name = propertyName;
    }

    public BindableProperty([CallerMemberName] string propertyName = "")
    {
        this.value = default(T);
        this.Name = propertyName;
    }

    public T Value
    {
        get
        {
            return this.value;
        }

        set
        {
            this.SetProperty(ref this.value, value);
        }
    }

    public string Name { get; private set; }

    public static BindableProperty<T> Prepare(T value, [CallerMemberName] string propertyName = "")
    {
        return new BindableProperty<T>(value, propertyName);
    }

    public static BindableProperty<T> Prepare([CallerMemberName] string propertyName = "")
    {
        return new BindableProperty<T>(default(T), propertyName);
    }
}

Non-generic static class for coonstruction

public static class BindableProperty
{
    public static BindableProperty<T> Prepare<T>([CallerMemberName] string propertyName = "")
    {
        return new BindableProperty<T>(default(T), propertyName);
    }
}

You can see the BindableProperty object still has a private backing field and a property setter that handles the property changed event. The difference however is that this is the only place this code needs to ever exist now.

With our new BindableProperty object, let's re-write our User.

public class User
{
    public BindableProperty<string> FirstName { get; set; } = BindableProperty.Prepare<string>();

    public BindableProperty<string> LastName { get; set; } = BindableProperty.Prepare<string>();
}

We now have properties in our model that can be data-bound to and push change notifications back to the UI. We could even provide an initial value for the properties if we wanted to.

public class User
{
    public BindableProperty<string> FirstName { get; set; } = BindableProperty.Prepare<string>(string.Empty);

    public BindableProperty<string> LastName { get; set; } = BindableProperty.Prepare<string>("Stevenson");
}

Now we can create a view model real-quick for our view.

public class NewUserViewModel : ICommand
{
    public User NewUser { get; set; } = new User();

    public event EventHandler CanExecuteChanged;

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public async void Execute(object parameter)
    {
        if (string.IsNullOrEmpty(this.NewUser.FirstName.Value) ||
            string.IsNullOrEmpty(this.NewUser.LastName.Value))
        {
            var dlg = new MessageDialog("User information is invalid");
            await dlg.ShowAsync();
        }
    }
}

In order to execute properly, the FirstName and LastName properties need to have their Value property checked. If the Value property is null, we show a dialog. Having to check the Value property is an extra step that you wouldn't normally need to take, but one extra 'dot' is a lot less than having to write all the OnPropertyChanged boiler plate code.

Now for our view, we just wire up a quick simple user entry form. The TextBoxes are bound to the Value property in each of the User's BindableProperty properties.

<StackPanel>
    <StackPanel Orientation="Horizontal">
        <TextBlock Text="First name" />
        <TextBox Text="{Binding Path=NewUser.FirstName.Value}" />
    </StackPanel>
    <StackPanel Orientation="Horizontal">
        <TextBlock Text="Last name" />
        <TextBox Text="{Binding Path=NewUser.LastName.Valuey}" />
    </StackPanel>

    <Button Command="{Binding }"
            Content="Create." />
</StackPanel>

This is going to make your models a lot cleaner and speed up the amount of time it takes to create property changed based objects.

Building an Exception Factory

If you write a lot of code that takes dependencies in a method or constructor, you'll find that you write a lot of null checking like this:

public DefaultGame(ILoggingService loggingService, IWorldService worldService)
{
    if (loggingService == null)
    {
        throw new ArgumentNullException("loggingService", "Logging Service must not be null!");
    }
    else if (worldService == null)
    {
        throw new ArgumentNullException("worldService", "World Service must not be null!");
    }

    this.loggingService = loggingService;
    this.worldService = worldService;
}

Depending on the number of dependencies, this tends to bloat methods with more safety checks than actual code. I wanted to resolve this, and did so with a factory.

The factory needed to satisfy a few things.

  • Instance exceptions
  • Support stashing custom data in to the exceptions
  • Only throw if a given condition was met
  • Allow a callback if the conditions are not met (meaning no exception will be thrown)

Turns out this was pretty easy to implement. The end product, in its simplest form looks like this:

public DefaultGame(ILoggingService loggingService, IWorldService worldService)
{
    ExceptionFactory
        .ThrowExceptionIf< ArgumentNullException>(loggingService == null);
    ExceptionFactory
        .ThrowExceptionIf< ArgumentNullException>(worldService == null);

    this.loggingService = loggingService;
    this.worldService = worldService;
}

You can also invoke a callback, and provide a custom message.

public DefaultGame(ILoggingService loggingService, IWorldService worldService)
{
    ExceptionFactory
        .ThrowExceptionIf< ArgumentNullException>(loggingService == null, "Logging Service must not be null!")
        .ElseDo(() => this.loggingService = loggingService);

    ExceptionFactory
        .ThrowExceptionIf< ArgumentNullException>(worldService == null, "World Service must not be null!")
        .ElseDo(() => this.worldService = worldService);
}

If you need to do something more complex with your conditional check, you use a Func< bool>

ExceptionFactory
    .ThrowExceptionIf< Exception>(
        () =>
        {
            this.Worlds = worldService.GetAllWorlds();
            return this.Worlds.Any();
        },
        "An empty world can not be used!"));

It also supports providing a custom exception factory method for use. Since some exceptions have additional parameters in the constructor, this can be really useful.

ExceptionFactory
    .ThrowExceptionIf< ArgumentNullException>(
        worldService == null,
        () => new ArgumentNullException("worldService", "World Service must not be null!"));

We can also pass custom data in to the exception if we want.

ExceptionFactory
    .ThrowExceptionIf< ArgumentNullException>(
        worldService == null,
        () => new ArgumentNullException("worldService", "World Service must not be null!"),
        new KeyValuePair< string, string>("Member", "DefaultGame"),
        new KeyValuePair< string, string>("MemberType", "Constructor"));

So how does the insides work? Let's take a look

The Factory

There are a total of four factory methods.

  • ThrowExceptionIf< TException>(Func< bool> predicate, string message = null, params KeyValuePair< string, string>[] data);
  • ThrowExceptionIf< TException>(Func< bool> predicate, Func< TException> exception, params KeyValuePair< string, string>[] data)
  • ThrowExceptionIf< TException>(bool condition, string message = null, params KeyValuePair< string, string>[] data)
  • ThrowExceptionIf< TException>(bool condition, Func< TException> exception, params KeyValuePair< string, string>[] data)

and one last method for adding data to the exception

AddExceptionData(Exception exception, params KeyValuePair< string, string>[] data)

Since we can build this in an overloaded fashion, we will just build the most complex method out, then let the rest of them piggy back on top of it.

public static ExceptionFactoryResult ThrowExceptionIf< TException>(bool condition, Func< TException> exception, params KeyValuePair< string, string>[] data) where TException : Exception, new()
{
    if (condition)
    {
        return new ExceptionFactoryResult();
    }

    TException exceptionToThrow = exception();
    AddExceptionData(exceptionToThrow, data);

    throw exceptionToThrow;
}

This method is really straight forward, it requires a bool value to indicate if this exception must be instanced and thrown or not. If the condition is false, then we go ahead and invoke the Func< TException> delegate. This returns the exception that we are to throw.

Next we take the optional exception data parameter and pass it to an AddExceptionData method. That method will iterate over the param data and add it to the exception. We then finally throw the exception. Really straight forward.

The AddExceptionData method looks like this:

public static void AddExceptionData(Exception exception, params KeyValuePair< string, string>[] data)
{
    foreach (var exceptionData in data)
    {
        exception.Data.Add(exceptionData.Key, exceptionData.Value);
    }
}

Now we can build out our overloads. The second most complex one is really easy to write. We just pass a delegate in that instances a new exception using the Activator class.

public static ExceptionFactoryResult ThrowExceptionIf< TException>(bool condition, string message = null, params KeyValuePair< string, string>[] data) where TException : Exception, new()
{
    return ThrowExceptionIf< TException>(
        condition,
        () => (TException)Activator.CreateInstance(typeof(TException), message),
        data);
}

Next, we will provide support for delegate predicates.

public static ExceptionFactoryResult ThrowExceptionIf< TException>(Func< bool> predicate, Func< TException> exception, params KeyValuePair< string, string>[] data) where TException : Exception, new()
{
    return ThrowExceptionIf< TException>(predicate(), exception, character, data);
}

public static ExceptionFactoryResult ThrowExceptionIf< TException>(Func< bool> predicate, string message = null, params KeyValuePair< string, string>[] data) where TException : Exception, new()
{
    return ThrowExceptionIf< TException>(predicate(), message, character, data);
}

The last thing we need to do is support the method callbacks. This is done using the ExceptionFactoryResult class that all of our factory methods return. This class has nothing more than a simple method that takes an Action and invokes it.

public class ExceptionFactoryResult
{
    public void ElseDo(Action callback)
    {
        callback();
    }
}

That's all there is to it!

ValidatableBase 2.0

A couple of weeks ago I released verison 2.0 of ValidatableBase on GitHub. The newest build provides Data Annotation styled attribute validation for Universal Windows applications, iOS, Android and any other platform that .NET Portable Class Libraries can run on.

Release features

  • New Data Annotation styled attribute validation system has been added. The attributes implement IValidationRule and provide a simple means of writing custom validation rules if needed.
  • Registration of properties is no longer needed.
  • The library is now in a Portable Class Library, usable across all platforms that PCL's can run on.
    • As a side-effect of this, the validation messages collection is no longer directly exposed. The underlying implementation is Dictionary< string, IEnumerable< IValidationMessage>> which requires conversion if you need to bind to the validation results. The example app includes an extension method that can be used to perform the conversion, for view models that want to expose validation to the view.
  • ValidatableBase now has a ValidationChanged event that you can subscribe to. Any time validation is changed, either by adding/removing messages or running validation, your view models can be notified.

Validation Rule examples

ValidatableBase supports a very flexible attribute based validation system that can be used on any of your models, regardless of platform.

To demonstrate, let's create a very basic model with zero validation.

namespace SampleUniversalApp.Models
{
    using System.ComponentModel;
    using System.Linq;
    using System.Reflection;
    using Sullinger.ValidatableBase.Models;
    using Sullinger.ValidatableBase.Models.ValidationRules;

    public class User : INotifyPropertyChanged
    {
        private string email = string.Empty;

        private string password = string.Empty;

        public event PropertyChangedEventHandler PropertyChanged;

        public string Email
        {
            get
            {
                return this.email;
            }

            set
            {
                this.email = value;
                this.OnPropertyChanged("Email");
            }
        }

        public string Password
        {
            get
            {
                return this.password;
            }

            set
            {
                this.password = value;
                this.OnPropertyChanged("Password");
            }
        }

        protected virtual void OnPropertyChanged(string propertyName = "")
        {
            var handler = this.PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

This model is really straight-forward and shouldn't need any explaining. It implements INotifyPropertyChanged and has two properties.

Validation

Now that we have a model, we want to validate it. We will perform validation on both the Email and the Password properties. We want to make sure neither of them are blank.

The first thing we have to do is inherit from a concrete Type implementing IValidatable. The ValidatableBase API ships with a base class called ValidatableBase (surprise, surprise) that you can use.

Update your class definition to look like the following:

public class User : ValidatableBase, INotifyPropertyChanged

Since the ValidatableBase API is cross-platform and lives within a Portable Class Library, the ValidatableBase class does not implement INotifyPropertyChanged. If you are targeting a platform that supports this (such as WPF) then you can build a secondary base-class on top of ValidatableBase, or build your own implementation of IValidatable.

The ValidatableBase API performs validation mostly through attributes. To make sure neither property is left blank, we will decorate each property with a ValidateObjectHasValue attribute.

    [ValidateObjectHasValue(
        FailureMessage = "E-Mail can not be left blank.", 
        ValidationMessageType = typeof(ValidationErrorMessage))]
    public string Email
    {
        get
        {
            return this.email;
        }

        set
        {
            this.email = value;
            this.OnPropertyChanged("Email");
        }
    }

    [ValidateObjectHasValue(
        FailureMessage = "Password can not be left blank.",
        ValidationMessageType = typeof(ValidationErrorMessage))]
    public string Password
    {
        get
        {
            return this.password;
        }

        set
        {
            this.password = value;
            this.OnPropertyChanged("Password");
        }
    }

Performing the validation

The next step is to obviously perform the validation. To do that, we will create a view model that implements ICommand, exposing an Execute method.

public class MainPageViewModel : ICommand, INotifyPropertyChanged
{
    public MainPageViewModel()
    {
        this.AppUser = new User();
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public event EventHandler CanExecuteChanged;
    public User AppUser { get; private set; }

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public void Execute(object parameter)
    {
        // Perform validation on the user's built in validation.
        this.AppUser.ValidateAll();

        // Do stuff.
        return;
    }

We have now validated our model. You can check if the model has any validation messages (indicating failure) by using the HasValidationMessages< IValidationMessage>() method.

if (this.AppUser.HasValidationMessages< ValidationErrorMessage>())
{
    // Failed, so abort.
    return;
}

Adding additional validation rules.

Since the models validation is performed by the attributes, we can come back at a later date and add or replace validation on the properties without having to re-write a large amount of logic code. To demonstrate, we will replace the Password properties validation. Instead of checking if the property is empty, we will check if the password entered meets a required password range of 6 to 20 characters.

    [ValidateStringIsGreaterThan(GreaterThanValue = 6, 
        FailureMessage = "Password must be greater than 6 characters.", 
        ValidationMessageType = typeof(ValidationErrorMessage))]
    [ValidateStringIsLessThan(LessThanValue = 20, 
        FailureMessage = "Password must be less than 20 characters.", 
        ValidationMessageType = typeof(ValidationErrorMessage))]
    public string Password
    {
        get
        {
            return this.password;
        }

        set
        {
            this.password = value;
            this.OnPropertyChanged("Password");
        }
    }

Now when we run the this.AppUser.ValidateAll() method, the property will ensure it has a password between the range of 6 characters and 20. If not, a ValidationErrorMessage is created.