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 Design - The Agile Way

One of the issues the Mud Designer has suffered with over the years is lack of direction. I have a grand vision, but don't have any kind of proper design documentation wrote up or flow charts created to indicate the apps flow. Without a lot of the lower level stuff defined, I find myself hitting barriers because of gaps in the engine I missed. I end up fixing or adding things to bridge the gap, which in turn break other items in the engine and before I know it, I've someone managed to modify a massive chunk of the engine in one check-in.

If it's one thing I've learned from my day job, is that improper planning can ruin a product. We spend a lot of time planning and making sure things are crystal clear before progressing and it makes a huge difference. In our previous Sprint, I improperly planned it and we failed to finish it. This really made me think about the Mud Engine too. I haven't ever properly planned out what the finished product is, nor what features it should fully support. That's going to change.

I created a VisualStudio online project tonight for the Mud Designer. It gives me access to a full TFS project, with Agile planning tools, user story and work item support and source control support all in one. The plus side is I have a one stop shop for the project and it's work items. I'll even be able to attach Tasks, User Stories and Bug items to my check-ins. The fact that it supports Git is a plus, however I just stuck with the standard TFS source control since that's what I use on a daily basis at work.

The downside to this is that VisualStudio online does not support open source projects. So the source code will no longer be hosted on Codeplex. I will provide the source code as a download on codeplex, so I can stay within the Codeplex policies, but the actual source code repository will be moved to a closed server.

Most of the users who downloaded the product, did not download the source so I don't think this will be a big deal. The source will still be available, just at a higher scope. Each individual check-in will not be made readily available to the public.

So moving forward, I've started writing user stories and got on board the agile bandwagon for Mud. I have a lot of ideas that I have always wanted to do, but never got them wrote down. Without seeing the cool concepts and ideas every day, motivation tends to suffer. This should go a long way towards addressing that. I'm also anxious to start tackling it in verticle slices and shipping a product again. I enjoyed the feedback and communication I received from users when I was actively pushing new versions out. I'm hoping to get some of that interaction back.

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)