general / message_doc

Edit on Github

the message() client protocol

message is a new efun in MudOS designed to make communication efuns more generic and to provide a standard way of talking to clients intelligently.

Here is the manual page for message:

===================================================================== void message (mixed class, string message, mixed targets, mixed exclude);

message calls receive_message(mixed class, string message) in all message recipients (derived from the target list) excluding those in the exclude list. This basically tells the object the message.

Message is a string containing the message to be sent

Class is the type of message (used for clients and such). An example would be ‘combat’, ‘shout’, ‘emergency’ etc.

target is a list of objects to be sent the message. This can be either a single object string or object pointer, or may be an array of either. If a target is non living all objects in it’s environment will receive the message.

Exclude is a list of objects that should not receive the message. This can either be a one or an array of object pointers. ======================================================================

Probably the most important element of this function is the “class”. If used properly, you could use this field to implement a very simple version of earmuffs, or to communicate intelligently with a custom client. The class defines the type of message that the string contains. Initial simple implementations would have the classes “shout”, “say”, “write”, “tell_object” (which would be generated by simul_efuns of the same name that replace the more traditional efuns).

Given this, let’s say that you wanted to implment a quick and easy earmuff ability. (the ability to mask shouts) In your user (player) object, you would have the function receive_message. Here’s the simplest implementation possible:

void receive_message (string msg, mixed class) { receive(msg); }

This simply takes all messages generated by the message efun and displays them to the user. However, you could imagine a simple earmuffs implementation on top of this:

string *muffle = ({});

int muffle_class (string arg) { muffle += ({arg}); }

void receive_message (string msg, string class) { if (member_array(class,string) == -1) receive(msg); }

Now you can see, that if a particular class is muffled (say, “shout” for example), the text never gets displayed, but in other cases it does.

However, not all uses of the shout() efun are really shouts, in the traditional mud sense. For example, let’s say that the admin of the mud wants to send a message to all users telling them that the system is going to be shut down in 5 minutes. To do this, they might use echo, which in turn uses the shout() efun. So all users who had “shout” muffled would miss this important message. This means that a broader number of classes is really needed to make message() truly useful. For the example given, let’s say we make a new “broadcast” class. This message class would be used for important announcements that everyone should hear. Perhaps a restriction could even be made so that muffle prohibited blocking this class.

Let’s look at another example. What if you’re tired of all of the millions of emotes (soul commands) that clutter your screen? Wouldn’t it be nice to just muffle those? Well, obviously a new “emote” class is needed that all soul functions use. Now you might be thinking to yourself “hey… I don’t want to have to use this really complex message() efun every time I write a soul command. write() and say() are very simple, and I like using those.” Well, I couldn’t agree with you more. To combat that problem, I make a simul_efun for each type of commonly used message class. Like emote for example. I made a new simul_efun called emote() that in fact made writing soul commands easier, and used message() with the “emote” class. I won’t show you the code for the emote simul_efun, but here’s the basic idea:

varargs int emote (object emoter, string self_message, string other_message, mixed emotee, string target_message, string modifier);

emoter - the object doing the emoting self_message - the message displayed to the emoter other_message - the message displayed to the whole room emotee - the target of the emote (i.e. kick huthar) target_message - the message displayed to the emotee string modifier - any extra modifier to tack on to the end of the emote string. (i.e. adverbs: smiles happily, cheerfully, etc.) - only really complex soul commands need this (if they want to be able to control multiple modifiers to a single soul command)

At this point, some might be thinking, “ok… so you can do very powerful selective muffling, big deal. this seems like a lot of work for nothing.” Good point. Muffling was just a simple neat thing you could do with message now. Most of the real advantages from message will come a bit down the line when someone gets around to writing a smart client program. Here’s how that will work.

Basically the idea is to separate all of the messages sent to a user by the content. So you have a “combat” class, and a “stat” class, and a “room_description” class, and a “help” class as some examples. Before I get started, let’s write a new version of receive_message().

int has_smart_client;

void receive_message (string msg, string class) { if (member_array(class,muffle) == -1) { if (has_smart_client) receive (class + “ : “ + msg); else receive (msg); } }

Ok. Let’s look at what this does. If the user object has defined has_smart_client to be > 0, then it prepends all messages with the class name as well. So if you were to write a smart client that parsed messages like that, you could make it redirect room descriptions into one window, conversation into another, combat into yet another area, etc. You could make a status line that always kept your current room name (since it got passed as class “room_name” when you enetered the room). You could make the heart_beat, pass a class “status” message which gives a constant readout of your hit points in your status line. All of this would be transparent to the end user. It would just work.

In addition, you could do a simply graphical client using the same technique. The BSX graphical mud / client could easily be implemented on top of MudOS using message(). Or you could pass around small bitmaps rather than the polygon-based line drawings of BSX. The possibilities are pretty wide open.

There is at least one major flaw with this argument so far. Since everyone has to implement this message protocol themselves, and since nobody has written a smart client to take advantage of the protocol, then when a client comes out, what’s to guarantee that your mudlib will even work with it? Well, that’s actually most of the point to this document. I’d like to outline a simple protocol that I hope everyone will adopt, so that when a client finally comes out, it will work with all mudlibs that adhere to this protocol.

The protocol:

all messages sent to the smart client are in the form

“class:msg_length:msg”

msg_len is the length of the msg string. This is put in so that the client can always know when it has received the entire message, and when one starts and ends.

The following list of classes should be used and a client should be able to parse and use any messages using these classes.

say use of the “say” command or its equivalent shout use of the “shout” command or its equivalent tell use of the “tell” command or its equivalent emote a soul command or emote broadcast a broadcast message to everyone on the mud combat generic combat messages combatself combat messages generated by the user’s own attack combat_other combat messages generated by others combat_ all other specific combat messages roomdescription a long description of a room or location room_name a short name for a room or location inventory what you’re carrying item_description a long description of the item status generic status messages status_hp current hit points status_sp current spell points status_sobriety current state of drunkeness status_ all other specific status messages score generic score messages scoreexp experience points score_money the amount of coins or other money developer a broadcast message to all wizards/developers class_fighter a message to all fighters class_mage a message to all mages class_thief a message to all thieves class_priest a message to all priests class_ a message to the class specified racehuman a message to all humans race_elf a message to all elves race_dwarf a message to all dwarves race_ a message to the race specified

_ optional classes to implement _ bitmap a generic bitmap message bitmap* a specific type of bitmap drawing a generic drawing message drawing* a specific type of drawing