Post Reply 
 
Thread Rating:
  • 0 Votes - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
jsMUD - the NodeJS MUD Engine
10-21-2010, 04:37 AM (This post was last modified: 12-19-2010 12:59 AM by krem.)
Post: #1
jsMUD - the NodeJS MUD Engine
I've been playing around with many different aspects of NodeJS (when time permits) and found that it would make a good basis for my next attempt at a mud engine (PikeMUD is discontinued due to too many technical hurdles).

Right now I'm still playing with Proof-Of-Concept items and changing how I develop. JavaScript isn't your classical inheritance language. It's a prototype-like language with a ton of flexibility (it's not a pure Prototype language).

Because of that, I'm attempting to change my thinking on how objects are created and extended. An object in JavaScript is a 'soft-object'. It doesn't have a formal definition or interface to be based on like in the classical class-based languages. It does have a prototype-chain, but the prototype chain doesn't allow for good data scoping (i.e. hiding data from derived versions).

The way I'm implementing my 'inheritance' is prototype-based. This is how it works. My base object (Entity) is a factory object. You call 'create' to create an new base object that you can either use or extend. Here's the code to create a base Entity object.
Code:
//ObjectManager is responsible for creating every type of registered object
var object_mgr = require("./ObjectManager");

//Tell the ObjectManager to create an Entity object
var obj = object_mgr.create();
obj is its own instance with its own functions and private data. You can call methods on it, add additional methods on it, assign member variables, etc.

Behind the scenes, this is what ObjectManager.create() does:
Code:
exports.create = function()
{
    ///<summary>
    ///Creates a base object with standard properties and methods
    ///</summary>
    ///<returns>object</returns>
    var obj = entityFactory.create("Entity", {});

    gObjects[obj.__objectID] = obj;

    return obj;
}
2 things happen here:
1) We use a factory to create the base object. By using factories, I can actually expand this engine to have different type of objects by simply adding additional factories. The {} parameter defines a private-scope data storage area for the entity to use. You'll see what I mean in a bit.
2) We add a reference to this newly create object to an internal collection. This is used for persistence of all game objects.

So what is this about private scope? Does JavaScript support private scope? Yes it does, just not in a clear way. Here is what the create method in the entity factory does:
Code:
exports.create = function(typeName, instanceData)
{
    ///<summary>
    ///Creates a base object with standard properties and methods.
    ///</summary>
    ///<returns>object</returns>
    if(!instanceData)
        throw new Error("No storage object supplied for instance");

    //Define the standard properties and methods available
    //to all objects
    instanceData.objectID = ++gNextObjectID;
    instanceData.createdDate = new Date();
    instanceData.typeName = typeName ? typeName : "GameObject";

    var props =
    {
        constructor :
        {
            value: function() { events.EventEmitter.call(this); }
            , enumerable : false
        }

        , typeName :
        {
            value : instanceData.typeName
            , enumerable : true
            , configurable : false
            , writable : false
        }

        , __objectID :
        {
            value : instanceData.objectID
            , writable : false
            , enumerable : false
            , configurable : false
        }

        , ObjectAge :
        {
            get : function() { return new Date() - instanceData.createdDate; }
        }

        //Methods
        , toString :
        {
            value : function() { return "[object " + instanceData.typeName + "]"; }
            , configurable : true
            , enumerable : true
            , writable : true
        }
    };

    var obj = Object.create(new events.EventEmitter(), props);

    return obj;
}
A review of the code shows some interesting things.

First, we assign a unique Object ID to this object. How do we do that without making the gNewObjectID global? Each of these files I've showed you are their own file. In NodeJS, if you define a variable (using var) in a file, it has the equivalent scope as a module level variable. Anything within that file can access the variable, but nothing outside of the file can.

You will also notice that I'm assigning properties to the instanceData object. This parameter is how I achieve private scope. In JavaScript, if you define a function inside another function, the inner function has access to all variables in the container function. In this case, the toString() method has access to instanceData. However, instanceData is not accessible to any methods added to the object outside of the create() function. Unfortunately, there is no way of doing protected scope in JavaScript... yet. There are some interesting ways around that, but I haven't implement those here.

Finally, we utilize a standard ECMAScript function called Object.create. This allows us to do not only create an object based on another object (this instance being the NodeJS EventEmitter object), put also define read-only properties, hidden properties, as well as functions to extend that object.

Let's revisit the Object Manager's create method. Let's say we want to add persistence to our object. We can modify our code to look like this:
Code:
exports.create = function()
{
    ///<summary>
    ///Creates a base object with standard properties and methods
    ///</summary>
    ///<returns>object</returns>
    var instance_data = {};
    var obj = entityFactory.create("Entity", instance_data);

    gObjects[obj.__objectID] = obj;

    //Add some system methods
    var props =
    {
        persist :
        {
            value : function() { persistGameObject(obj, instance_data); }
            , enumerable : false
            , configurable : false
            , writable : false
        }
    }
    Object.defineProperties(obj, props);

    return obj;
}
The same concept of private-scoping in JavaScript is also being applied here. I'm able to add a persist method that has access to the actual object and its instance data without actually having to make instance_data publicly available.


This is the model that I'm using to build the game library. The second part has to do with component-based architecture. There are great articles and examples on this (see http://www.bit-101.com/blog/?p=2408).

As I continue with my development, I will let you know any cool things I'm using. I want to use CouchDB, but the style of persistence I'm using will not work well with JSON in general. The persisted version of the instance data is pseudo-JSON, but contains custom formats for 'Game Object' objects.
Find all posts by this user
Quote this message in a reply
12-19-2010, 01:11 AM
Post: #2
RE: jsMUD - the NodeJS MUD Engine
So I'm still working on concepts for my NodeJS MUD engine. I'm just going through some different design principals. Do I make the MUD engine like LPC and very extensible by allowing the creators to compile code in-game? Do I go the C-based MUD driver route and make additions to the game confined to server side changes? Both have pros and cons.

In order to make progress, I'm thinking that I will go with the locked-down model of the C-based MUD drivers. Given the nature of JavaScript, I can see a way of adding the in-game scripting functionality in the future.
Find all posts by this user
Quote this message in a reply
12-31-2010, 12:41 AM
Post: #3
RE: jsMUD - the NodeJS MUD Engine
I found this site by searching google for creating a mud in NodeJS. I come from LPC/LDMud and am interested in helping with this. If you'd like some help, please PM me.

Thanks.
Find all posts by this user
Quote this message in a reply
12-31-2010, 12:55 AM
Post: #4
RE: jsMUD - the NodeJS MUD Engine
(12-31-2010 12:41 AM)mmccaskill Wrote:  I found this site by searching google for creating a mud in NodeJS. I come from LPC/LDMud and am interested in helping with this. If you'd like some help, please PM me.

Thanks.
I would love to discuss this with anyone interested. Coming from an LPC/LPMUD background is both a blessing and a curse because you want to maintain the same functionality that an LPC/LPMUD developer has, but without proper sandboxing, I don't know how possible that is yet.
Find all posts by this user
Quote this message in a reply
12-31-2010, 12:57 AM
Post: #5
RE: jsMUD - the NodeJS MUD Engine
(12-31-2010 12:55 AM)krem Wrote:  I would love to discuss this with anyone interested. Coming from an LPC/LPMUD background is both a blessing and a curse because you want to maintain the same functionality that an LPC/LPMUD developer has, but without proper sandboxing, I don't know how possible that is yet.

Well I'm just starting to learn NodeJS so my initial contributions will be small but maybe we can figure out how to make it work.
Find all posts by this user
Quote this message in a reply
01-01-2011, 02:56 AM
Post: #6
RE: jsMUD - the NodeJS MUD Engine
(12-31-2010 12:57 AM)mmccaskill Wrote:  
(12-31-2010 12:55 AM)krem Wrote:  I would love to discuss this with anyone interested. Coming from an LPC/LPMUD background is both a blessing and a curse because you want to maintain the same functionality that an LPC/LPMUD developer has, but without proper sandboxing, I don't know how possible that is yet.

Well I'm just starting to learn NodeJS so my initial contributions will be small but maybe we can figure out how to make it work.
I'm simply in the design and Proof-of-concept mode. Actual game development is still a bits away.

For the benefit of the community, though, I thing we should post all comments and thoughts to the forums. Hopefully some more people might be able to offer help/insight as well.
Find all posts by this user
Quote this message in a reply
01-02-2011, 11:41 PM
Post: #7
RE: jsMUD - the NodeJS MUD Engine
Cool. I'll keep learning NodeJS. In the meantime, feel free to bounce ideas.
Find all posts by this user
Quote this message in a reply
01-07-2011, 10:27 AM
Post: #8
RE: jsMUD - the NodeJS MUD Engine
The thing about NodeJS is that it's mostly event driven. That means the normal sequential processing that you are use to in typical MUDs doesn't apply here. You have to change your approach to the engine design.

Let's take the simple process of reading a file. With the normal LPC model, it would be something like this:
Code:
void create()
{
    ReadConfig("/secure/config/master.cfg");
    
    //Continue loading based on config settings
}

void ReadConfig(string configFile)
{
    string data = read_file(configFile);
    string[] lines = split(data, "\n");
    int i = 0;
    
    for(i = 0; i < sizeof(lines); i++)
    {
        //Line parsing code
    }
}

However, NodeJS and event-based structure is more like this:
Code:
void create()
{
    ReadConfig("/secure/config/master.cfg", function(err, data)
        {
            if(err) throw err;

            //Continue loading based on config settings
        });
}

void ProcessData(data)
{
    string[] lines = split(data, "\n");
    int i = 0;
    
    for(i = 0; i < sizeof(lines); i++)
    {
        //Line parsing code
    }
}

void ReadConfig(configFile, callback)
{
    fs.readFile(configFile, function(err, data)
        {
            //If an error has not occured, process the data
            if(!err)
                ProcessData(data);

            //Call the callback if one is specified
            if(callback)
                callback(err, data);
        });
}

See how the NodeJS code isn't as straight forward. Now file reading isn't the best example as there are synchronous versions of it, but then you lose some of the benefits of NodeJS by doing that.

Just something to keep in mind when trying to design a MUD engine with NodeJS
Find all posts by this user
Quote this message in a reply
01-07-2011, 09:48 PM
Post: #9
RE: jsMUD - the NodeJS MUD Engine
Yeah I can see how that would change the design.
Find all posts by this user
Quote this message in a reply
03-22-2011, 11:06 PM
Post: #10
RE: jsMUD - the NodeJS MUD Engine
Just an update. I've been playing around with different ideas. I am going to be publishing an article for JsMag in my series 'Game Development using Node.js' with Part 1 being about Node.js and Socket.IO for real-time, bi-directional communications.

I'm trying to determine how I can (or even if I should) make a game engine that would be MUD compatible (all text) and also isometric game compatible. Do I drop the text-based version at the risk of losing some of the richness that MUDs always provided to attract a broader audience (the casual visual gamer)?

Either way, I am moving forward in my efforts. Right now I'm putting together Part 2 of the series which will focus on user management and a component-based entity library. If there is time and space in the article, I may add object serialization.
Find all posts by this user
Quote this message in a reply
Post Reply 


Forum Jump:


User(s) browsing this thread: 1 Guest(s)