20080618

Justification for doX Processing Target Strings

One of the rules of coding that I try to abide by, both at work and at home, is always to have a reason for doing something some way. Whether it be choosing to use if/elsif vs. switch statements or whether to make something a member of some class, I try to have a reason for every choice that I encounter. Sometimes I get distracted or something, and make what I later feel to be a bad choice. When correcting it, again, I require myself to have a justification. Here is one such time.

In the sequence of events involved with commands it actually seems to handwave about the final step. Ultimately a method is invoked on the character object that is performing a command that actually has the implementation of the action that takes place. For instance, if you type, "say hi", at some point character.doSay("hi") is called. There's one such so-called doX method for each applicable command. Certain commands take targets. For instance, when you type, "get bag", something needs to interpret "bag" as an identifier in the game world and associate it with a real Dealie instance, which is then manipulated by doGet. In this example, "bag" is what I refer to as a "target string."

Originally, the GetCommand class would do a minimal amount of processing on the arguments to the command, then pass on basically the raw target string to doGet, which would lookup the target string in the current room, find the dealie, and mess with it.

At some point, I got the crazy idea that the doX methods Really Should take the final objects themselves. For example, whereas the signature for doGet was something like doGet(targetString) before, it then became doGet(targetDealie). The reason I came up with was that...er..."it just seems right," or some nonsense like that. OK, so I don't think I had a really solid reason for it.

So I did a bunch of work to push out most of the target string to target object code into the Command classes. In a way, this wasn't so bad, because this code was kind of old and it got a well-deserved polishing. Then I came to my senses when I realized a few reasons why it shouldn't be that way.

Firstly, it violated one of Scott Meyers' rules about good design: make interfaces easy to use correctly and hard to use incorrectly. Before, a caller passed in simply a string, and it was thoroughly validated within the doX method. Afterwards, the caller could pass in anything they really wanted, and its validity needed to be thoroughly validated within. A lot of the checks that are done in the process of resolving the target string are kind of implicit, and making them explicit was not only tedious, but also prone to becoming outdated with the arrival of new features, and probably duplicate code for something the caller does to perform the mapping himself.

For example, in the "get" example above, the target string is looked for only on the ground of the room the character is standing in. After my silly change, the caller can pass in an object that is already in the character's inventory, which is a clearly invalid case. The root cause of this class of problems is that the real logic of the functionality is now spread between two different functions--one that does the target string lookup, and one that does the processing on the target; but these pieces of logic are closely tied together, and so should really live close together.

Secondly, the previous way represented the behavior of a character better. A command like, "get 3.bag" means something like, "get the third thing identified as a bag nearby [in this room]." Then code within the Mob class is responsible for finding the real object--i.e. looking for it with his eyes--and picking it up. The newer way detached these steps from the Mob class and put them in the Command classes instead, which have no similar analog in the MUD world.

Finally, the newer way violates the Law of Demeter worse than the older way did. I have a lot of places in my code where I disobey the Law of Demeter, but reducing those occurrences is widely considered a good thing to do. Basically, the Law of Demeter says that objects shouldn't really try to access objects that aren't direct "neighbors" in some sense. Specifically, the code in the Command classes would do things like query the character for what room they're in and call functions on that to look up dealies or mobs in that room. This kind of interaction between the Command classes and things that really don't concern them (rooms, dealies, etc.) leads to tight coupling, which eventually becomes hard to break.

But I wasn't able to remove this entirely. There is a reason to support these kinds of calls receiving target objects directly. Here's an example. A certain nipic is programmed to whisper some words to anyone who whispers something to them. More specifically, when this nipic receives any WhisperEvento, he needs to whisper some string to evento.source, which is generally an instance of Mob. With the old way, the rough code to do this would look like so:

def receiveEvento(evento)
    if evento.source != manager().mob
        if evento.kind_of?(WhisperEvento)
            manager().mob().doWhisper(mapTargetToTargetString(evento.source), "Don't whisper at me!")
        end 
    end 
end # function receive evento

As you can see here, in order to whisper to someone whom the nipic already has unambiugously identified, the code is performing a reverse mapping, from unambiguous source object to more ambiguous target string. If you imagine that the source's short description is "a towering man wearing glasses," that target string might look like "4."man big giant glasses"", which includes all of its keywords in an attempt to make it as precise as possible.

Compare that with the actual final solution that I implemented:

:
manager().mob().doWhisper_Direct(evento.source, "Don't whisper at me!")
:

The only problem is the inability to restrict who can call the doX_Direct methods. They're not just a performance optimization, but also help with correctness in certain situations, where validity checking has already taken place.

20080601

Very Controlling

Snooping is a feature that most MUDs have, including mine. I haven't talked much about it yet because it felt fairly fragile to me for a while. This morning I fixed up several problems with it, and now it feels somewhat more solid. It's time to talk about snooping and controlling.

In case you don't know, snooping is a mechanism by which one character can see everything that another character is doing or play as a Nipic as though it were alive. Due to the sensitive nature of spying on characters, it's a command typically reserved for very few immortals on the MUD, and even then is employed judiciously. Snooping and controlling Nipics, however, is a privilege given to lower level immortals, so that they can take control of Nipics strategically in roleplay situations. You can imagine a quest where a Nipic controlled by a real player is interacting with characters. Having been there personally in the past, it can be pretty cool.

Basic support for snooping (and controlling--I'll just refer to it as snooping henceforth) was one of the earlier things I implemented, because I had a gut feeling that it would prompt architectural changes to the guts of the MUD. My gut was right; several layered pieces had to be inserted to make it all work.

Let's consider the case of another character, since it's somewhat simpler. When you snoop a character, you want just one thing: that all the text that is shown to that target character is also shown to you. Each "living" entity in the game is attached to a manager that handles inserting it into the world, removing it, and keeping track of what mode of interaction with the world it's currently in (the InteractionMode).

When a character sees some text, the writeString method of ConnectionManager is called. This in turn sends the text over the network socket, which then shows in the client's telnet session. The simple thing to do is to hook or shim this call so that it also sends the text to the snooper's manager (actually, to another interaction mode, but we'll get to that shortly). This is basically what I did. MobManager keeps track of a list of "output filters." Whenever writeString is called, it invokes a method on each OutputFilter that is subscribed to receive text from this manager. As long as you're connected to the MUD, you have one output filter that sends text back across the network to you. When you get snooped, a second output filter is added, that also sends the text to someone else. As a relatively minor detail, this is done for both input and output, so the snooper actually sees the exact commands that someone else types in.

I hinted that something is different about snooping Nipics. The obvious thing is that you not only get to see what they're seeing, but you also get to control them. Let's dig into this a little more. In a regular situation, when you type a command, it gets translated into an Invocation of some Command object and is ultimately excuted by calling the callCommand method of Command. Here's the code behind one such command:

def callCommand(invocation, intermode, args)
    if args.empty?()
        intermode.mob().seeText('What do you want to say?')
    else
        intermode.mob().doSay(args)
    end
end # function call command

The intermode parameter here is always the interaction mode that produced the command, so even if you're snooping a Nipic, it would be your (the human's) interaction mode, not the Nipic's. But the mob() call... hmm... If we redirected that call to point to the target Nipic instead of ourselves as it normally does, then commands we type will affect the target Nipic instead. Turns out this is exactly what I did, and it works just as it's expected.

So I just mentioned overriding the mob method of the interaction mode. Since when you start snooping someone, you can't do anything yourself until you're done, this is a prime candidate for having an interaction mode. Indeed, when you snoop someone you enter the ControlInteractionMode, which shims the mob call and inserts the input and output filters into the target mob. When you type exit you leave the interaction mode and remove the filters.

My motto is, "there's always gotchas," and this is no exception. With the introduction of eventos, Nipics don't actually print out text at all for any eventos. Why would they need to? They don't care what the display text for an evento is; the relevant data for the evento is encoded in the object, and they fetch and act on that directly. This poses a problem for snooping: if the Nipic doesn't display text, then that text won't get forwarded to the snooper.

I fixed this much in the same way as the filters. Since the manager already receives and processes eventos--in this case, the NipicManager--it can now keep track of a list of evento listeners that should receive notifications of events. For characters, this listener just sends the text to the network. For Nipics, this listener currently does very little, but is the connection point for mobprogs. When a snooper enters the ControlInteractionMode, when it sets up the input filters, it also adds the same evento filter that characters get into the target Nipic's manager. The only thing this does is cause events to display text to the Nipic, like characters see. Then--cleverly, I feel--the output filter correctly forwards the text to the snooper.

What's left to do? Well, if you snoop a Nipic and use the "ooc" command, which sends an out-of-character message to all characters on the MUD, the MUD currently crashes, because the doOOC method is only implemented on Character, not Nipic. This makes sense, because Nipics have no out-of-character presence. Something in the ControlInteractionMode will probably need to ensure that you can't issue commands to Nipics that aren't valid.

20080527

Commands

This post is going to document in prose how the command and interpreting system currently works. This was one of the early parts of the MUD I wrote, since it's a little hard to interact with the game without it being able to understand what you're trying to say. Along the way, I might even notice some bugs or shortcomings that ought to be fixed.

The easiest way to do this thoroughly is to follow a command from the beginning to the end of its lifetime. Let's start.

A human being types in a command into this telnet client. Let's say it's the "say" command. He types, "say hi".

There's a NetworkConnection instance looping through every line (newline-delimited) that comes in and passing it off to a ConnectionManager instance. The ConnectionManager ties a network connection to an entity in the game. In a way, it's the "brain" of a character, which controls it in the game world. Likewise, a NipicManager performs the same function for a Nipic in the game. You could imagine that the logic behind mobprogs would live in the NipicManager.

The manager passes that line of text to something called an InteractionMode. Since there are various ways that a player interacts with the world, the interaction mode encapsulates the interpretation of commands and displaying of output in those modes. For instance, most of the time, for example, when a character is moving around the world, the player is in the MainInteractionMode; but when he starts to edit his character's description, he's in the TextDocumentInteractionMode. Currently there's also a LoginInteractionMode and a CreationInteractionMode.

The interaction mode employs an Interpreter to parse the line of text received from the client into a Command object that contains information about the command and its arguments. Actually, the interaction mode receives an Invocation object that contains the Command object in question and its arguments. The Command is ignorant of the arguments being passed to it at runtime. Now that I think about it, I'm not really sure why Invocations need to exist. Instances of Command objects should be roughly equivalent to Invocations.

Anyway, the interaction mode in this case receives an Invocation object that contains a SayCommand and the argument, "hi". Now comes the fun stuff. The invocation is not immediately executed, but rather is placed in a queue of invocations. Invocations are picked off of the front of the queue on a periodic basis and executed.

The period is determined by the main loop of the MUD. Every manager, when connected to a valid network connection, signs up to be a PulseListener, which just means it implements the pulse() method. Every so often--to give you a frame of reference, SecondsPerPulse = 0.1--the main loop of the MUD calls pulse on all subscribed PulseListeners. The manager uses this call to ask the interaction mode to manage its queue.

The interaction mode does some processing and decides whether or not to execute an invocation. The reason all of this queue nonsense exists is simply because different commands have different amounts of "lag" associated with them. For instance, by default, every command has a delay of 1 pulse, but some commands deserve a larger delay. As a classic example, if you flee from battle, typically there is a delay of a couple seconds before you can continue running. In terms of what I just told you, for the next 20 times its pulse method was called, it would count down the time before the next invocation could be picked off the queue and executed. Note that the delay from a command comes into effect after the invocation is executed.

Once the invocation is finally executed, that's the end of the command's lifetime.

It's worth pointing out a couple other neat features of the interaction mode. The first is called a "fast" command. Certain commands, e.g. OOC (out-of-character) ones, should be exempt from lag that is preventing further commands in the queue from executing. The interaction mode's queue management takes into account fast commands, which are currently marked by having a delay of 0. Even if lag is halting the queue, fast commands are immediately executed. For now, the "emote" command is a fast command, because I believe that even if you're lagged, you should be allowed to type in-character text about what's going on with your character; it's a roleplay tool.

Another neat feature is called "flushing," which is something every good queue should have. Say you type in a series of commands with a long delay, but something happens in the middle--for instance, you get attacked--that causes you to want to cancel all those long commands you have queued. The interpreter, which is called immediately whenever a line of text comes in, immediately calls a method to flush the queue of the interaction mode, so the rest of those commands are short-circuited. Of course, it doesn't get you out of the lag from the last command. And since it doesn't hold the queue empty, you can immediately start filling it with a new series of commands that will start executing as soon as the lag clears.

In the previous description, I mentioned that the interpreter calls a method on the interaction mode to flush the queue. I just noticed that this design could probably be better. By leveraging fast commands, I could eliminate the need for the interpreter to have any knowledge of interaction modes. Less knowledge is better, as a general rule. I've made a note to investigate changing that design.

In terms of future work, there are two big work items: implementing the "!" command, which executes the last-typed command; and implementing aliases that are full-featured and help players equalize differences in typing speed. I'll be sure to post on both of these when I put them in.

20080523

How to Load Nothing

I ran into a problem with loading the other day that I felt was a shortcoming of the design. I found a situation where I needed to load from the data file the fact that a particular property of something is empty or nil. Really, this can happen whenever a property is optional.

In this particular case, the optional property was the short description of a character. Although Nipics tend to have short descriptions all the time, since there's no other real way to refer to them--having no name, and all--characters are usually referenced by their name in lieu of a short description.

None of that really matters. What matters is there was an optional property, and a shortcoming of the way loading was designed made me have to go through contortions in other places to support it. I decided, finally, to fix the design, because contortions don't scale well.

As you may recall from previous posts, there is some intermediate state during which an object is being loaded from the data file. During this time, the object is semi-initialized, and the process of loading keeps track of what parts have been initialized and which parts have not yet. Usually, those parts can't yet be initialized because they're waiting on some data on which they are dependent.

The problem with the design--and any CS people reading this will immediately agree--is that the unloaded state of a property of some object was represented by the nil value. What this effectively meant is that the nil value itself could never be loaded from a data file; every piece of data needed to be some real, concrete object, be it an empty string or some other kind of placeholder.

The way I fixed this is by instead using some arbitrary value to represent the not-yet-loaded state. As an implementation detail, I decided to use a Symbol, probably because it's very unlikely that I'll ever have a symbol being loaded from a data file. Consequently, I updated every single place where I made the assumption (implicitly, sometimes!) that nil represents a not-loaded value, and replaced the check or value or whatever with this symbol.

This was really quite painful, due mainly to the parenthetical above: there were many implicit assumptions, and most of them were hard to nail down. Aside from now supporting optional properties very easily, the upside of this change is that now there's no way for me to make that kind of assumption implicitly anymore. If I'm expecting or handling a not-loaded state, it jumps out into my face. In a way, it's a step towards making wrong code look obviously wrong. Perhaps more importantly, it's purged this automatic link in my brain between nil and not-loaded.

20080516

Eventos - a little taste of what may be to come

Aside from fixing tons of bugs with various things, I've been working slowly on Eventos, which are events, as you might have guessed. I won't say much about them now because the design is still somewhat in flux. It's basically an observer pattern that will replace each character writing text to other characters' terminals, in favor of sending messages to them. This will hopefully be the infrastructure that ultimately enables mobprogs, oprogs, rprogs, and whatever other kinds of progs you can think of.

A sample:

<type commands for a list> say hi
You say, 'hi'

<type commands for a list>
a man says, 'What do you mean, "hi"???'

<type commands for a list> say wut
You say, 'wut'

<type commands for a list>
a man says, 'What do you mean, "wut"???'

Yes, this gets old real fast. But it demonstrates something. Assuming the man standing in the room isn't parsing the text, "You say, '[text]'"1, he must be getting the text being said some other way. Indeed, he's receiving a SayEvento with the saidText property properly set to the contents of the message.

For fun, here's the old code...

@room.bagMobsInRoom.msgToAllExcept(self, "\\\\r\\\\n#{self.shortDescription} says, '#{text}'", "You say, '#{text}'")

...and the new code.

@room.speakEvento(SayEvento.new(self, text))

More on this later, when it's completed.

1 I would sooner stab myself in the eye than design a feature like that.

20080415

Hard Loading Made for Easy Saving

I complained for a while about the difficulty I had in coming up with a satisfactory solution to loading various types of objects from XML area files. The problems of having recursive, semi-cyclic structure to the files posed quite a challenge. I eventually solved it by describing an object's persisted state in terms of a list of "properties" that are tied to actual members on instances of classes.

It was nice (really nice) to see my design validated at some level today, when I was able to write only the obvious code I had floating around in my brain and get saving working. Simply put, the saving process uses the same properties that were used in loading to extract data from the corresponding members of classes and put them automatically into named elements in the XML file. Again: the same mechanism I used to establish a relationship between XML elements in the area file and data members could be used both for reading and writing. Yes, I'm patting myself on the back for getting this right (at least right enough).

Gotchas for Bags

There are never no gotchas, but luckily the gotchas were easy to solve this time. The structure of a Bag (i.e. container of things--dealies, mobs, etc.) in XML is a single element containing multiple elements, one for each thing in the bag, each with the name item, but differentiated by an attribute called order. Therefore, the "name" of each property of a bag in XML is actually an xpath like item[@order='1']. The naive method of creating a new element with the "name" of the property and filling it with the contents of the item won't work, because it's not really a name.

To get around this, we make two passes. In the first pass, the bag creates empty elements with the correct element name and order attribute. In the second pass, we look for each property's (i.e. item's) element in the XML, which is identified by a unique xpath query, and--rather than creating a new element for the item--reuse the existing one and fill it with the item's serialized representation.

Probably worth illustrating. Here's the first pass. The bag has one item inside, a food dealie. It creates an empty element that has the order set correctly. You can imagine if it had two items within, the next one would have a different order. The bag has a single property, that can be described roughly as: the element identified by item[@order='0'] is tied to the element with index 0 in this container1.

<inventory kind='dealie_bag'>
  <b><item kind='food_dealie' order='0'/></b>
</inventory>

In the second pass, we examine each property of the bag. As I mentioned above, there's just one property, identified by a specific XPath. We search within the inventory element for that sub-element, find it (bolded above), and proceed to fill it with the item's own data:

<inventory kind='dealie_bag'>
  <item kind='food_dealie' order='0'>
    <short_description>the cover for a barn</short_description>
    <long_description>The spare roof of a barn is here.</long_description>
    <proto_lid area_name='main' local_id='10'/>
    <nourishment>10</nourishment>
    <keywords>
      <keyword order='0'>roof</keyword>
      <keyword order='1'>cover</keyword>
      <keyword order='2'>barn</keyword>
    </keywords>
  </item>
</inventory>

Gotchas for Container Dealies

Container Dealies, which are items that can contain other items, have the special characteristic of having their "short description" and "long description" methods overridden to indicate that the item is a container.

<type commands for a list> look
Room: The second room

The spare roof of a barn is here.
<b><C></b> How many hands have been carried in this bag?

a man is here.

<type commands for a list> 

As you can see above, the container has a marker in front telling that it's a container. Usually, the property for the short_description in XML is tied to the ContainerDealie.shortDescription() method. This yields an XML representation that includes the container marker, which means when it's loaded, the marker is loaded as being part of the unadorned description, and you end up with a duplicate container tag. The fix is to tie the short description XML property at write-time to the object's unadorned short/long description attribute instead, which is saved off when the object is loaded originally.

As it turns out, both of these special cases fit in elegantly to the current design, so I don't consider them all that special. I'm fairly confident that this same method is flexible enough to be used to save anything to XML. I'm kicking around the idea of having a totally persistent world, where things don't respawn on reboot, necessarily. There's a lot of issues to work out there, though. Thoughts?


1 Actually, I use procs, not indices (indices are so passe), to identify each item within the container. In a loop through the bag's items, each iteration has a variable that references the current item. At that point, I can create a proc that forever references that item and pass it into the property to save off. I like to think it's a pretty cool trick.

20080412

Multiple Inheritance is Evil, Even in Ruby

So yeah, I took a break for a while. According to Fallenearth's blog page, about 10 months. Wow. What happened in there? School, work, moving, lots of good video games, etc.. But the most influential thing in there that stopped me from coding was multiple inheritance. I'll get to that shortly.

Recently, Leia started playing a Korean MMO, and when I'm around someone who's doing something roughly like mudding, it makes me want to mud, too. And then I slap myself and remind myself that I'm creating one now, not playing one (I just don't have time for the latter). So that ultimately got me motivated to defeat multiple inheritance.

(as an aside, the blog editing page is unusable in IE8 Beta1. I'll have to file some bugs on that...)

When we last left our hero (me, 10 months ago), he (I) was struggling with an inheritance problem. As you may have gathered from previous posts, my still-unnamed mud is heavily object oriented, like everything else written with Ruby, I suppose. The concrete classes in the mud (Dealie, Mob, and company) mixin modules whenever possible, in a weak attempt at formalizing their interface to their callers.

As a concrete example, every dealie on the mud has a set of keywords that identify it in the mud world. These are typically specified in the XML area file, like so:

<dealie_prototype order="1" kind="food_proto">
    <lid area_name='main' local_id='10'/>
    <b><keywords>
        <keyword order="0">barn</keyword>
        <keyword order="1">cover</keyword>
        <keyword order="2">roof</keyword>
    </keywords></b>
    <short_description>the cover for a barn</short_description>
    <long_description>The spare roof of a barn is here.</long_description>
    <nourishment>10</nourishment>
</dealie_prototype>

Therafter, a player can refer to that item in their inventory, on the ground, and so on by using any substring of "barn", "cover", or "roof". By the way, we could theoretically extrapolate the right set of keywords by eliminating articles and such from the short description, but this gives more control to area authors, and that's generally a good thing.

Many very different things have the property of being identified by keywords in the mud world (Mob is another good example), so it makes sense to extract the common code for enabling this keyword identification into a separate module that all interested classes can mixin to get the functionality for free. In my mud, this class is called--stupidly, because I couldn't think of a better name--Keyworded.

The Keyworded module implements several things to enable this. It adds a data structure filled with the actual keywords (stupidly called ThingKeywords) as a member of the object. It provides some methods for matching an instance of the object against a keyword. Since this module has state (the list of keywords, basically), there needs to be a way to initialize the state. One way to do this is to define the initialize method in the Keyworded mixin. Callers who call super(keywords) at the top of their initialize method will pass on the keywords to the Keyworded initialize method. Great!

Not so fast! Callers often inherit from other modules and classes, and doing this means that all modules and classes in the method chain for initialize will get this spurious keywords parameter. Clearly, this won't work. I thought, "how would C++ handle this?" because I recently read Scott Meyers' Effective C++, for which I believe there cannot exist enough praise. Given that C++ is a language that fully supports multiple inheritance, surely it's solved this problem, right?

Indeed, it has. In C++, you don't call a single super method that does everything (pardon the pun), but instead the inheriting class calls the base class/interface constructors in a caller-specified way and order. Oh, if only Ruby supported some kind of syntax for targeting a specific class or module's method when calling it. I'm actually lameting; I don't think it has such a thing. Does it? Anybody?

Needless to say, the solution I ended up implementing is essentially trying to mimic the above. Each module that requires initialization, instead of defining initialize, defines the instance method Modulename_initialize (and Modulename_initialize_copy). Callers, like in C++, explicitly call the module "constructors" in whatever order they want, and with whatever parameters they want. Everybody goes home more or less happy, since as far as workarounds/hacks go, this one isn't so bad in that it follows another tried-and-tested language's pattern.

Having solved this, I went on to fix much more pressing things, like a load of bugs I found along the way, ranging from the minor syntax errors on code that just hadn't been covered yet, to corner cases in loading containers that contain other containers that contain the first one.