Building an app targeting desktops & mobile

The Mud Designer is currently being developed to support a wide range of operating systems.

  1. Desktops
    1. Windows 7
    2. Windows 8
    3. Windows 8.1
    4. OS X
  2. Mobile
    1. WinRT 8
    2. WinRT 8.1
    3. Windows Phone 8
    4. Windows Phone 8.1
    5. iOS
    6. Android

To facility this, the engine at the lowest level will be wrote using Portable Class Libraries (PCL) so that I can target all of the operating systems with the same low-level codebase. The engine itself will be developed fairly abstractly, implementing a series of patterns that will help facilitate this requirement, with the bulk of the components hidden behind interfaces.

At the moment the engine is broken up in to 4 layers. From the highest layer to the lowest layer, the following provides an idea of what the overall acrchitectural layout looks like.

  1. App
  2. Engine
  3. Data Access
  4. Services

Each layer is broken down further, to facilitate the level of abstraction needed to provide cross-platform support.

App

The App layer looks like this

  1. Universal App
    1. Windows Phone
    2. WindowsRT
    3. Shared
    4. Presentation
  2. Windows
    1. Desktop
    2. Modules
    3. Infrastructure

As you can see, the mobile apps will be wrote within the Universal App layer while the Windows Desktop apps will be wrote under the Windows layer. Each will be able to target a version of the engine (and it's repositories and services) that is designed specifically for that platform.

I really want to avoid using #if WinRT #elif Win7 #endif kind of macros through-out the engine, as that makes maintaining it difficult and doesn't provide the level of support I want to provide for 3rd party developers. Since the engine will fully support engine and editor plugins, it needs to be modular and flexible enough to allow other developers to target a specific device or platform if they want, without having to rely on macro's.

For instance, the core project contains an IGame interface that exposes the following contract.

/// < summary>
/// Gets or Sets the current World for the game. Contains all of the Realms, Zones and Rooms.
/// < /summary>
ICollection< IWorld> Worlds { get; set; }

Since Universal Apps don't support ObservableCollections in the same manor that WPF Desktop apps do, I can implement the IGame in a Desktop library like this.

/// < summary>
/// Gets or Sets the current World for the game. Contains all of the Realms, Zones and Rooms.
/// < /summary>
public ObservableCollection< IWorld> Worlds { get; set; }

This still satisfies the interface's contract, yet provides support for WPF XAML's binding engine. Ideally, I will be able to build an abstract implementation of IGame in the Core engine, and then have the individual platforms inherit and override/implement the specific components that apply to them.

While the solution is still being organized and structured, this is the initial look of how the over-all application suite will be set up.

Messaging in Mud Designer

One of the things that bugged me with the previous version of the Mud Designer was how I had essentially hard-coded the encoding of the text directly in to the flow of transfering the data back and forth between the user and the server. The old version of the engine would send content directly to the user like this:

player.SendMessage("What is your username, adventurer? ", false);

and the SendMessage looked like:

public override void SendMessage(string message, bool newLine = true)
{
    // When printing properties that don't have values, they'll
    // be null.
    if (message == null)
        return;

    if (newLine && !lastMessageHadNewLine)
        message = message.Insert(0, System.Environment.NewLine);

    if (newLine)
    {
        message += System.Environment.NewLine;
        lastMessageHadNewLine = true;
    }
    else
        this.lastMessageHadNewLine = false;

    // Make sure we are still connected
    try
    {
        if (IsConnected)
            Connection.Send(new ASCIIEncoding().GetBytes(message));
    }
    catch (Exception ex)
    {
        // No connection was made, so make sure we clean up
        if (!IsConnected)
            Disconnect();
    }
}

So, as you can see the formatting of the content sent to the player was pretty static. If you wanted to change how the text was formatted, you had to modify this one method. If you wanted to have multiple types of formatting it was almost impossible because you would not know what the content of the message was once it was within the SendMessage method. You only know that there is text that must be sent. This was changed in the re-write. Now, all messages are wrapped within an IMessage object. The object must have a property called Message which contains the actual message and a method called FormatMessage(). The interface looks like this:

public interface IMessage
{
    /// < summary>
    /// Gets or sets the message.
    /// < /summary>
    string Message { get; set; }

    /// < summary>
    /// Formats the message.
    /// < /summary>
    /// < returns>Returns a formatted message.</returns>
    string FormatMessage();
}

Why is this a good thing? Now you can customize how you want your message to be sent to the player. For instance, I have an IState object that handles the users login. The state renders both a welcome message to the user along with a prompt to enter the users name. I can now format both messages differently, by creating two different IMessage objects. One for showing information and one for asking for input.

this.connectedPlayer.Send(new InformationalMessage("Invalid username/password specified."));
this.currentState = CurrentState.FetchUserName;
this.connectedPlayer.Send(new InputMessage("Please enter your user name"));

The above code outputs the following to the players console:

Invalid username/password specified.
Please enter your user name >:

The first IMessage type is implemented with out any formatting. It just takes the message and appends a new line to the end of it.

public class InformationalMessage : IMessage
{
    public InformationalMessage(string message)
    {
        this.Message = message;
    }

    /// < summary>
    /// Gets or sets the message.
    /// < /summary>
    public string Message { get; set; }

    /// < summary>
    /// Formats the message.
    /// < /summary>
    public string FormatMessage()
    {
        return this.Message += Environment.NewLine;
    }
}

The second one, InputMessage formats the message by appending a >: to the end of the message. This indicates that the user must enter a command in order to continue.

public class InputMessage : IMessage
{
    /// < summary>
    /// Initializes a new instance of the <see data-preserve-html-node="true" cref="InputMessage"/> class.
    /// < /summary>
    /// < param name="message">The message.</param>
    public InputMessage(string message)
    {
        this.Message = message;
    }

    /// < summary>
    /// Gets or sets the message.
    /// < /summary>
    public string Message { get; set; }


    /// < summary>
    /// Formats the message.
    /// < /summary>
    public string FormatMessage()
    {
        return string.Format("{0}>: ", this.Message);
    }
}

By requiring all of the methods within the engine that pass messages around, to be supplied with an IMessage implementation, the engine can display data differently to the user based off of what the context of that data is. This should make presenting content more flexible in the engine going forward.

Mud Designer Alpha 3 Progress

I have spent the last couple of weeks working on the Mud Designer, revising the code-base some. We had done a pretty good job of writing the engine source for Alpha 2, so in order to do some of my revisions to the source I just had to replace a handful of files rather than a full re-write like we had to do in Alpha 2. While I did re-write a couple of files, the majority of the revisions were made to existing code, allowing me to re-use the bulk of what we wrote.

There are several things within the engine that I wanted to improve on and make changes to. The changes will break any projects using the Alpha 2 engine, but I have always been upfront in regards to the lack of forwards compatibility between versions while in the Alpha stage. Let's take a look at whats changing shall we?

Good bye Codeplex / Hello GitHub

The source control is moving from Codeplex to GitHub. The decision was made due to the engine targetting multiple platforms. It made more sense to host the entire project on GitHub since it will run on OS X, Windows and hopefully mobile devices. Codeplex is typically Windows only software, so the repository location needed to be changed.

Async & Task Parallelism

The engine needed to be revised to make use of the whole new Task Parallelism Library (TPL) Microsoft made available in .NET 4.5. We could not make much use of it originally because of our need to support Windows XP. Unfortunetly when Alpha 3 is released, Windows XP support will be dropped. As of now, Windows 7 holds the majority of the marketshare, and that is what I am going to target.

In order to implement TPL and async stuff, the networking code needed to be revised. Essentially, the server has been re-wrote from the ground up, using TPL instead of System Threads. There probably won't be a big performance increase, but the rest of the engine moving forward will be using TPL so I wanted to ensure that the Server was using the same framework feature set.

R.I.P. IDirector

In Alpha 2, the IDirector interface was used to help abstract away some of the functionality of various things from objects. For instance, the Server had it's player data handling abstracted out and placed into a ServerDirector. The director handled the player connection from the time of connection to the time of disconnect. At the time it made sense to do it this way, but it proved to be a little more difficult to maintain.

In Alpha 3, the player management will be handled by the Server and the Player jointly. The Player Type will implement a new IConnectionState interface that will provide a contract to Player objects for disconnecting and connecting. The Player objects will be responsible for cleaning up their own individual socket connections. Once they are completed, the server will handle the player drop and handle server level clean up. This removes the need for a 3rd object sitting in the middle. Since the Player object has always had a Connection property with a typeof(Socket), it makes sense to have the Player object manage its own disconnect.

This also helps simplify the event wiring that I could not get implemented into Alpha 2. It really did not make sense to have a object fire an event, that traveled to another object. Take the following code for example.

public MyPlayerObject()
{
    this.DisconnectEvent += Player_DisconnectEvent;
}

public void Player_DisconnectEvent()
{
    // My Code here...
    this.Director.Disconnect(this);
}

If a user is making a custom Player object that inherits from BasePlayer and they want to run specific code during a disconnect, they still have to make sure and invoke the server director's Disconnect() method. I wanted to revise this some so that in the future all that they have to write is their specific code and they don't have to pass the Player object off to the director. This will help prevent some issues that can come from this. For instance, what if the Player object cleaned up something that the Server Director still needed to use? Or what if the Server Director cleaned up something that the developer's Player object needed to use? This will prevent that issue form occuring. Another thing with events in C# is that they hardly ever call base and to require a event to always invoke a method in another object that is not base is never really done. Events should technically be added using the += operator, allowing the base event to fire first and the developer event to fire second. While I could have invoked the Server Director method in the base event, I would still run into the issue of the child object trying to access things within the Player object that the Server Director had cleaned up and disconnected.

Essentially in Alpha 2 the Server object worked only as a transfer of authority. The player would connect to the server and the server would just pass the Player object off to the ServerDirector object to manage. In Alpha 3, the Server will maintain control of the Player objects and allow the players to manage themselves for the most part.

States & Commands

I liked the set up put in place for player state management in Alpha 2 but revisions were still needed. In Alpha 2, the flow of control went something like this:

  1. Director renders current state to terminal.
  2. Director Requests the users next command from the current state.
  3. Current state asks the Player object to receive input from the client connection.
  4. Current state attempts to find a Command object that can handle the players input.
  5. Current state instances / invokes the Command object.
  6. Command object performs its action.
  7. Command object changes the Player objects state to a new State.
  8. Loop back at 1.

That is a lot of steps and makes it a real pain to debug and add new functionality. I want to revise this workflow a little bit.

States will no longer be responsible for fetching the next command. The network data is already received within the Player object, so it makes more sense to have the Player object determine the command as well. The current State object uses something along the following lines:

public ICommand GetCommand()
{
    var input = this.Player.ReceiveInput();

    // Determine what command the input correlates to.
}

At the moment, the Player object receives the network input but does nothing with it. Other objects around it take the data and manipulate it. It should be the Player object's responsibility to manage it's own data. When a user enters data, the Player object should parse it and determine what needs to be done. Once it determines what must be done, it can pass the action off to something else at that point. Which is where the Command object will take over.

States will continue to be used, but primarily just to render content to the clients terminal. A Player object will be responsible for switching it's state, but any object can tell the Player object to change it's State from what ever it currently is, to another. Which is essentially how it is set up mostly at the moment.

Data Persistance / Storage

Another major change will be on how the engine stores the current state of the game for saving. Currently, the engine stores everything by serializing the objects out to JSon text files. All of the objects are saved using the FileIO object, which implements the ISavable and ILoadable interfaces. The issue with Alpha 2 was that we never abstracted the save calls. So if a developer wanted to use a MySQL database for storing their data instead of files on the local disk, they would have to trudge through all of the scripts and source files and replace the FileIO calls.

This time around, things are going to be a bit different. I have added a DataContextFactory object that is responsible for fetching all of the Data Context's that can be used for storage. A developer can implement a new storage facility by implementing IDataContext and it will become exposed to the engine automatically. Through out the engine and scripts, the save methods will invoke IDataContext.Save. This allows developers to swap out the actual storage type, such as XML, database or a server someplace, without having to change any of the engine or existing script source code.

In order to achieve this, a lot of the engine save and load code had to be revised. It will work out better in the end, with my ultimate goal being to ship both the original JSon flat-file serialization mode along with a SQLite storage mode for Alpha 3 to help demonstrate how to build custom storage options for your games.

Editor

There are a lot of revisions going on with the engine; due to the changes, the editor has essentially become broken. I was never happy with the editor in the first place and always wanted to do something more dynamic, something that provides better support for custom developer scripted objects. So the Editor is the one piece that will be trashed and re-wrote. I haven't decided how I am going to re-write it yet, but I do know that I am not going to use Windows Forms. I am currently debating between either a WPF app or a web-based app that runs on a local server.

Another thing that I have yet to decide on, is if the Alpha 3 will be held up by the editor re-write or if I will ship Alpha 3 with no editor. Alpha 2 shipped with an editor, but it was still fairly gimped. The engine supported 10x what the editor was actually able to do. When Alpha 2 shipped, there was support for Mobs, items, stats, races, classes and mob appearance customizations. None of which was exposed to the editor due to time constraints. Looking back on it, it kind of sucked to ship something that did not make use of 1/2 of the tech that you had built.

Conclusion

Alpha 3 will be a large improvement over Alpha 2, and will allow the engine development to continue moving forward in a solid direction. Alpha 2 was a huge improvement over the first alpha, and the 3rd version takes Alpha 2 and improves on it even more. I am really looking forward to the next release and getting the engine prepared for the first official Beta. At which point, the engine will be considered feature complete and will just require tweaking, feature improvements and scripted content (for developer references) to be created.

(EOF)