<!-- MHonArc v2.4.4 --> <!--X-Subject: [MUD-Dev] example custom protocol and its uses --> <!--X-From-R13: Quevf Uenl <ptNnzv-pt.UenlEntr.Sqzbagba.OP.QO> --> <!--X-Date: Fri, 18 Dec 1998 23:26:02 -0800 --> <!--X-Message-Id: 199812190526.WAA10999@ami-cg.GraySage.Edmonton.AB.CA --> <!--X-Content-Type: text/plain --> <!--X-Head-End--> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"> <html> <head> <title>MUD-Dev message, [MUD-Dev] example custom protocol and its uses</title> <!-- meta name="robots" content="noindex,nofollow" --> <link rev="made" href="mailto:cg#ami-cg,GraySage.Edmonton.AB.CA"> </head> <body background="/backgrounds/paperback.gif" bgcolor="#ffffff" text="#000000" link="#0000FF" alink="#FF0000" vlink="#006000"> <font size="+4" color="#804040"> <strong><em>MUD-Dev<br>mailing list archive</em></strong> </font> <br> [ <a href="../">Other Periods</a> | <a href="../../">Other mailing lists</a> | <a href="/search.php3">Search</a> ] <br clear=all><hr> <!--X-Body-Begin--> <!--X-User-Header--> <!--X-User-Header-End--> <!--X-TopPNI--> Date: [ <a href="msg01016.html">Previous</a> | <a href="msg01018.html">Next</a> ] Thread: [ <a href="msg01022.html">Previous</a> | <a href="msg01015.html">Next</a> ] Index: [ <A HREF="author.html#01017">Author</A> | <A HREF="#01017">Date</A> | <A HREF="thread.html#01017">Thread</A> ] <!--X-TopPNI-End--> <!--X-MsgBody--> <!--X-Subject-Header-Begin--> <H1>[MUD-Dev] example custom protocol and its uses</H1> <HR> <!--X-Subject-Header-End--> <!--X-Head-of-Message--> <UL> <LI><em>To</em>: <A HREF="mailto:mud-dev#kanga,nu">mud-dev#kanga,nu</A></LI> <LI><em>Subject</em>: [MUD-Dev] example custom protocol and its uses</LI> <LI><em>From</em>: Chris Gray <<A HREF="mailto:cg#ami-cg,GraySage.Edmonton.AB.CA">cg#ami-cg,GraySage.Edmonton.AB.CA</A>></LI> <LI><em>Date</em>: Fri, 18 Dec 1998 22:26:49 -0700</LI> <LI><em>Reply-To</em>: <A HREF="mailto:mud-dev#kanga,nu">mud-dev#kanga,nu</A></LI> </UL> <!--X-Head-of-Message-End--> <!--X-Head-Body-Sep-Begin--> <HR> <!--X-Head-Body-Sep-End--> <!--X-Body-of-Message--> <PRE> Warning: Long. Skip to the last paragraph for my point. Only if you don't agree with me, or want to learn more about an actual implementation of some of this stuff, do you need to read the stuff inbetween. The protocol I use between my server and a custom client (not yet written except on the old Amiga version) is a fully binary one. Text messages from the server to the client are just one type of message, are are input commands from client to server. The client maintains two windows: one a graphics window and one a text window. The graphics window can be disabled by the user. The text window is used for normal text input/output. Input happens in the bottom line, and input history manipulation is available. Output happens in the rest of the window, and there are scrollbars, etc. for output history. The text window is also used by the built-in editor, which can be used to edit text strings and MUD-language procedures. When an edit session is active, the user can toggle between it and the normal text I/O. An external editor can also be used at the user's option. One of the other key types of messages is the 'effects' message. More on that later. Here are some of the messages from server to client: set prompt get a password delete a cached MUD-language proc definition (someone else changed it) effects (more later) edit the passed string edit the passed MUD-language proc get a string via a pop-up requester flush the indicated cached symbol (the definition is now invalid) define a new client-cached effect query the status of a given file on the client (the answer triggers an asynchronous event on the server) supply an updated player name (for logging purposes) Here are some from client to server (direct reply needed) request connection (sort-of - its more complicated) create new character lookup a symbol (when the client is parsing MUD-language code) read a MUD-language proc header supply a new MUD-language proc body to the server request the server run the supplied proc Here are some client to server message not requiring a direct reply log a message supply a user input command line supply a user typed raw keypress (function key, keypad, etc.) mouse-click inside a defined "region" mouse-click of a defined "button" ask permission to flush a cached effect resize the text window reply to server with entered password toggle graphics on/off toggle sound on/off toggle voice on/off toggle music on/off request editing of the given MUD-language proc (server will send a textual "pretty-print" of the proc) editing of a string is done editing of a MUD-language proc is done run of a long-running effect is done answer to a query-file request So, for example when a client is parsing a MUD-language procedure that the user has entered, it will send symbol lookup requests, waiting for replies from the server. It will cache the results, until it exits or is told to flush one by the server (the server doesn't keep track of which client has which symbol cached - it just tells all of them to invalidate it when needed). If the result is a MUD-language proc, the client will request the header of that proc, so that it can check calls to it. When the entire proc parses correctly, the client will turn it into a byte-stream and send it to the server, asking the server to add it to the world. The server will return the new unique ID for the new procedure. (I'm omitted some details here, like ref-count updates) Effects: An "effect" is a little routine, written in a language with no real definition, which is very simple, having only sequential execution, subroutines, and 'if's based on the existence of files on the client. The statements in an effect routine are things like commands to draw a line, start the playing of a sound, start some music, move the drawing pen, display a background image, display a sprite, add an icon, add a clickable "button" to the display, add a clickable "region", define an effects subroutine, etc. Only certain kinds make sense inside subroutines. Effects are all stored in the client as subroutines, identified by a unique ID. The server is aware of which effects each client has cached, so that they need only be sent once per session. The client does not cache them between sessions. I use these effects to draw rough drawings of areas if the client has no image of the area. I also use them for controls like the buttons, and for sound stuff. All of this is triggered by "builtin" functions in the server, which are native-code routines callable from the MUD-language. I think its time for some examples: This is a MUD-language subroutine which is called when trying to draw a view of something that might need simple door representations. The use of this could be inside an effects conditional that checks for a full background image on the client to use instead of the drawing. define t_graphics proc public HorizontalDoor()void: if not KnowsEffect(nil, HORIZONTAL_DOOR_ID) then DefineEffect(nil, HORIZONTAL_DOOR_ID); GRMove(nil, 0.0, -0.01); GRDraw(nil, 0.0, 0.021); GRMove(nil, 0.0, -0.01); GRDraw(nil, 0.03125, 0.0); GRMove(nil, 0.0, -0.01); GRDraw(nil, 0.0, 0.021); EndEffect(); fi; CallEffect(nil, HORIZONTAL_DOOR_ID); corp; HORIZONTAL_DOOR_ID is the unique ID for this effect subroutine, and is created by a unique-id generator. Basically, if the active client ('nil') does not have a cached copy of this effect subroutine, the code defines that effect routine and sends it to the client. In any case, the effect routine is "called", resulting in a rough horizontal door being draw at the current drawing position with the active pen. All of this would be sent to the client inside an 'effects' request, which are only flushed to the client when the current effect doesn't fit in the buffer, or the input request (e.g. 'walk north') that triggered this activity is completed. The effect routine is thus only sent over once per client session, but might be used many times. A fixed drawing for an area that used the door routine could in itself be a routine cached in the client, so that, in order to draw the picture, only a few bytes need to be sent from server to client to trigger that effects routine. The top level of an area drawing MUD-language procedure might look like this: define tp_streets STREETS_ID NextEffectId()$ define tp_streets proc drawStreets()void: if not KnowsEffect(nil, STREETS_ID) then DefineEffect(nil, STREETS_ID); GSetImage(nil, "Town/streets"); IfFound(nil); ShowCurrentImage(); Else(nil); GSetPen(nil, C_DARK_GREY); GAMove(nil, 0.0, 0.0); GRectangle(nil, 0.4995, 1.0, true); ... for much more Fi(nil); EndEffect(); fi; CallEffect(nil, STREETS_ID); corp; So, whenever we want to display the "town" area to the player, this MUD-language routine is called (actually I attach it to all of the room-objects in that area). The first time in a session, the whole thing (and any effects subroutines it uses, such as the door ones) must be sent over. After than, just a few bytes are needed to call it up. So, even if the client has the required image ("Town/streets"), it ends up with all the effects cached anyway. Something else quite handy that can be done is to have MUD-language procedures that examine the current location in order to automatically produce a drawing of the room. None of these are at all fancy, and currently they are all just bunches of polygons, ovals, etc. However, with a good set of textures on the client, much more should be possible, including 3D views. Note that none of this is even remotely real-time! So far, all of this effects traffic is fairly static. Consider this pair of routines however: define tp_streets BIRDS_SING_ID NextSoundEffectId()$ define tp_streets proc birdsSingOnce(thing client)void: if SOn(client) then SPlaySound(client, "birds2", 1, BIRDS_SING_ID); IfFound(client); Else(client); FailText(client, "Some birds sing."); Fi(client); else SPrint(client, "Some birds sing.\n"); fi; corp; define tp_streets proc parkBirds()status: if Random(5) = 0 then ForEachAgent(Here(), birdsSingOnce); birdsSingOnce(Me()); fi; continue corp; The second one is called whenever a character enters one of the locations in the town park. One out of five times it triggers a call that is done for each agent (PC or NPC) at that location. If the agent is a PC, who is running the custom client, and who has sound enabled, then an effect request is sent to that client to play a sound sample of birds singing. If sound is off, or the sample is not available on the client, a string is emitted into the normal text window. Whenever a time-consuming effect like playing a sound sample is sent, a unique-id is included with it. When the effect completes, the client sends back to the server a message indicating that completion. Thus, scenario code in the server can play sequences of sounds, change sound volumes, etc. I use a repeat count of '0' to indicate that a sound sample should be repeated until cancelled. That is handy for things like a gurgling fountain. The cancellation is an effects message sent by code when, e.g., the character walks away from the fountain. Another class of effects can put mouse-clickable buttons up in the graphics window. I tend to use the left half of the window for current location views, and the right half for control buttons. Other possibilities include areas for inventory display/control, equipment usage control, etc. Then, when the user clicks on such a button, the client sends that button's ID to the server, which triggers a call to MUD_language code with that ID. Thus clicking on the 'N' button is the same as typing 'move north', and is much easier for folks not got at typing. I have whole hierarchies of buttons that can be called up for the on-line building facility, making that facility accessible to those not-so-good with keyboards. Another class of effects is a mouse-clickable region. These are invisible in the graphics window, but clicking in them sends a message containing the region ID and the click position to the server. I use these to allow clicking relative to the character cursor to mean a movement request. I also use them to implement an editor for character icons, all without having icon-editing hard-code in either the client or the server. Discussions in mud-dev and devmud have talked about other things that can be done, such as popping up other windows, triggering calls to dynamically loaded code or Java code, etc. My point in all of this is that using a special protocol like this can allow you to do a great deal of interesting things, all without having to update the client or the server. I used a binary protocol, both because it is more efficient, and because I found it easier. By having the server (and any MUD-language code running on it) kept informed of some user client settings, it can tailor output to those settings. Thus, the MUD can handle text-only telnet clients freely mixed in with custom-client users. My choice was to always send text output to all clients, since that forced me to pay attention to it and get it right. Actually, the graphics aspect of my system grew over time - it started out with just text, so the text facilities were there from the beginning, and so got used a lot. Oh yes, by using a fairly concise protocol, the data volume is kept quite low. This system is actually usable over a 1200 baud modem. A typical internet connection is overkill (except for the latencies). -- Don't design inefficiency in - it'll happen in the implementation. - me Chris Gray cg#ami-cg,GraySage.Edmonton.AB.CA </PRE> <!--X-Body-of-Message-End--> <!--X-MsgBody-End--> <!--X-Follow-Ups--> <HR> <!--X-Follow-Ups-End--> <!--X-References--> <!--X-References-End--> <!--X-BotPNI--> <UL> <LI>Prev by Date: <STRONG><A HREF="msg01016.html">[MUD-Dev] Re: DIS: Client-Server vs Peer-to-Peer</A></STRONG> </LI> <LI>Next by Date: <STRONG><A HREF="msg01018.html">[MUD-Dev] Re: DIS: Client-Server vs Peer-to-Peer</A></STRONG> </LI> <LI>Prev by thread: <STRONG><A HREF="msg01022.html">[MUD-Dev] client stuff...</A></STRONG> </LI> <LI>Next by thread: <STRONG><A HREF="msg01015.html">[MUD-Dev] Re: Response (Was Re: MUD Design doc (long))</A></STRONG> </LI> <LI>Index(es): <UL> <LI><A HREF="index.html#01017"><STRONG>Date</STRONG></A></LI> <LI><A HREF="thread.html#01017"><STRONG>Thread</STRONG></A></LI> </UL> </LI> </UL> <!--X-BotPNI-End--> <!--X-User-Footer--> <!--X-User-Footer-End--> <ul><li>Thread context: <BLOCKQUOTE><UL> <LI><STRONG>[MUD-Dev] Re: [DevMUD] Re: Database module</STRONG>, <EM>(continued)</EM> <ul compact> <ul compact> <LI><strong><A NAME="01041" HREF="msg01041.html">[MUD-Dev] Re: [DevMUD] Re: Database module</A></strong>, T. Alexander Popiel <a href="mailto:popiel#snugharbor,com">popiel#snugharbor,com</a>, Tue 22 Dec 1998, 16:32 GMT </LI> </ul> <LI><strong><A NAME="01044" HREF="msg01044.html">[MUD-Dev] Re: [DevMUD] Re: Database module</A></strong>, Felix A. Croes <a href="mailto:felix#dworkin,nl">felix#dworkin,nl</a>, Tue 22 Dec 1998, 21:42 GMT </LI> </ul> </LI> <LI><strong><A NAME="01024" HREF="msg01024.html">[MUD-Dev] Developing a MUD for the first time?</A></strong>, Alex Oren <a href="mailto:alexo#bigfoot,com">alexo#bigfoot,com</a>, Mon 21 Dec 1998, 07:13 GMT <LI><strong><A NAME="01022" HREF="msg01022.html">[MUD-Dev] client stuff...</A></strong>, Andrew Wilson <a href="mailto:andrew#aaaaaaaa,demon.co.uk">andrew#aaaaaaaa,demon.co.uk</a>, Sat 19 Dec 1998, 20:04 GMT <LI><strong><A NAME="01017" HREF="msg01017.html">[MUD-Dev] example custom protocol and its uses</A></strong>, Chris Gray <a href="mailto:cg#ami-cg,GraySage.Edmonton.AB.CA">cg#ami-cg,GraySage.Edmonton.AB.CA</a>, Sat 19 Dec 1998, 07:26 GMT <LI><strong><A NAME="01015" HREF="msg01015.html">[MUD-Dev] Re: Response (Was Re: MUD Design doc (long))</A></strong>, Chris Gray <a href="mailto:cg#ami-cg,GraySage.Edmonton.AB.CA">cg#ami-cg,GraySage.Edmonton.AB.CA</a>, Sat 19 Dec 1998, 04:51 GMT <UL> <LI><strong><A NAME="01035" HREF="msg01035.html">[MUD-Dev] Re: Response (Was Re: MUD Design doc (long))</A></strong>, J C Lawrence <a href="mailto:claw#under,engr.sgi.com">claw#under,engr.sgi.com</a>, Mon 21 Dec 1998, 23:55 GMT </LI> </UL> </LI> <LI><strong><A NAME="01012" HREF="msg01012.html">[MUD-Dev] Re: Re[2]:[MUD-Dev] Re: MUD Design doc (long)</A></strong>, Caliban Tiresias Darklock <a href="mailto:caliban#darklock,com">caliban#darklock,com</a>, Sat 19 Dec 1998, 01:26 GMT <UL> <LI><strong><A NAME="01034" HREF="msg01034.html">[MUD-Dev] Re: Re[2]:[MUD-Dev] Re: MUD Design doc (long)</A></strong>, J C Lawrence <a href="mailto:claw#under,engr.sgi.com">claw#under,engr.sgi.com</a>, Mon 21 Dec 1998, 23:49 GMT </LI> </UL> </LI> </UL></BLOCKQUOTE> </ul> <hr> <center> [ <a href="../">Other Periods</a> | <a href="../../">Other mailing lists</a> | <a href="/search.php3">Search</a> ] </center> <hr> </body> </html>