1998Q4/
<!-- MHonArc v2.4.4 -->
<!--X-Subject: [MUD&#45;Dev] example custom protocol and its uses -->
<!--X-From-R13: Quevf Uenl <ptNnzv&#45;pt.UenlEntr.Sqzbagba.OP.QO> -->
<!--X-Date: Fri, 18 Dec 1998 23:26:02 &#45;0800 -->
<!--X-Message-Id: 199812190526.WAA10999@ami&#45;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>
[&nbsp;<a href="../">Other Periods</a>
&nbsp;|&nbsp;<a href="../../">Other mailing lists</a>
&nbsp;|&nbsp;<a href="/search.php3">Search</a>
&nbsp;]
<br clear=all><hr>
<!--X-Body-Begin-->
<!--X-User-Header-->
<!--X-User-Header-End-->
<!--X-TopPNI-->

Date:&nbsp;
[&nbsp;<a href="msg01016.html">Previous</a>
&nbsp;|&nbsp;<a href="msg01018.html">Next</a>
&nbsp;]
&nbsp;&nbsp;&nbsp;&nbsp;
Thread:&nbsp;
[&nbsp;<a href="msg01022.html">Previous</a>
&nbsp;|&nbsp;<a href="msg01015.html">Next</a>
&nbsp;]
&nbsp;&nbsp;&nbsp;&nbsp;
Index:&nbsp;
[&nbsp;<A HREF="author.html#01017">Author</A>
&nbsp;|&nbsp;<A HREF="#01017">Date</A>
&nbsp;|&nbsp;<A HREF="thread.html#01017">Thread</A>
&nbsp;]

<!--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 &lt;<A HREF="mailto:cg#ami-cg,GraySage.Edmonton.AB.CA">cg#ami-cg,GraySage.Edmonton.AB.CA</A>&gt;</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>
[&nbsp;<a href="../">Other Periods</a>
&nbsp;|&nbsp;<a href="../../">Other mailing lists</a>
&nbsp;|&nbsp;<a href="/search.php3">Search</a>
&nbsp;]
</center>
<hr>
</body>
</html>