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.