Crossfire Mailing List Archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Client/server protocol



The client server discussion seems to have pretty much died.  Since it needs
to be done, I thought I would start working on the protcol.  This is mostly
Carl Edman's protocol, with some clarifications and implementation thoughts
tossed in.  Some of the thoughts were gleaned from the old mail log.

The orignal proposal will have > prepended to the lines.  Clarifcations
will also be in this area.  The document has also be re-organized
to some extent.

==============================================================================
>GENERALITIES
>============
>
>A bi-directional 8-bit wide clean error-free channel of some form
>exists between the client and the server.  Absolutely all communication
>between them occurs on this channel and a client can receive everything
>it needs to run through it.  Typically this channel will be a TCP/IP
>connection, but it may very well in some situations be a high speed
>modem connection or a UN*X pipe or some completely different network
>protocol.
>
>In practice the up channel (from client to server) and the down channel
>(from server to client) function as two independent uni-directional
>chutes.  If one side has something to tell to the other it just drops a
>packet into its send channel and forgets about it.  Confirmations are
>not given or expected.  The sender just assumes that the receiver will
>handle the packet or it will complain in another packet.  At the same
>time the two chutes may be communicating about two entirely different
>subjects.
>
>Each packet consists out of one line of text terminated by a newline
>(0x0a) character.  Line lengths of up to 4096 characters (including the
>terminating newline) are guaranteed to work.  The receiver may
>correctly interpret longer packets, silently drop them or send an error
>message (see below) depending on what makes sense for the receiver.
>All characters are case sensitive.
>
>Every packet begins with a word terminated either by a space (0x20) or
>the end of the packet.  The interpretation of the rest of the line
>depends on the initial word.
>

I see no real problems in this area of the protocol.  However, see
notes on startup (below) about extensions.

==============================================================================
STARTUP
=======
>C->S:LOGIN <client-version> <name> <password>
>Typically this will be the first command sent by the client.  If it is
>sent during a session, the effect is the same as if the session had
>been terminated and a new connection had been established with this
>command.  <client-version> is a string created by the client at compile
>time.  The server is not encouraged to treat different clients
>differently.  This string is just there to be able to gather statistics
>(and to correlate with ERROR packets).  <name> and <password> are
>self-explanatory.

(both): PROTOCOL (revision)
This is the protocol that both the client and server understands.  In
this way, new commands can be added without requiring all clients to
be upgraded (the server recognizes it is an old client, and avoids the
new commands).  The server is required to be backward compatible with
all revisions, so a client can never be outdated (exceptions may be made
for very old and no longer needed commands).
  The client is not required to understand more than its current revision.
If it is a newer revision than the server, than an error will result from
the server.
  In general, changes to the protocol should not happen very often, but
this gives a mechanism for making changes and not requiring every
client to upgrade.

C->S:  There should be some mechanism for the client getting all the
data it needs now instead of making REQUEST commands later.  On a slow
link, you may very wall want a slow startup time in exchange for minimal
data transfer once the game begins (ie, you don't want to enter a room, and
have the game freeze for a few ticks and the image of the monster is
transmitted).  Likewise, on fast links, you may very wall to transmit the
data as you need to.

C->S: STACKING (depth)
This is how many images the client plans to display per space.  If
using fonts or bitmaps, then any value beyond 1 does not have any meaning.
For pixmaps, this can have meaning up to a reasonably high number.  However,
how it is handled becomes a little more difficult.  If a stacking of 2 is
requested, I should only see 2 objects (perhaps floor + top object).  If
three objects, should I see both floors (DOUBLE_FLOOR_PATCH) + top object?
one floor + the 2 top objects?  The details of this needs to be worked out.
  The server is not required to do anything with this request.  IT is just
that, a request that will hopefully cut down on the amount of unnecessary
data transmitted.

==============================================================================
>VALID COMMANDS FROM THE SERVER TO THE CLIENT
>============================================
>MAP <locx1> <locy1> <image1> <locx2> <locy2> <image2> ...
>Using one of these commands the server may tell the client that it sees
>the map at a series of location given by coordinate pairs.  The name
>refers to the image to use for the particular map location.  If the
>client doesn't know that particular name, it asks the server for it
>(see REQUEST/TRANSMIT).

Note that all (locx,locy) pairs are map relative, not center relative (in
other words, the locx,locy values are the same as the (server) ob->x and
ob->y values.

>
>UNMAP <locx1> <locy1> <locx2> <locy2> ...
>This command tells the client that a certain series locations isn't any
>longer in the LOS of the player.  The client may respond to this by
>erasing the squares in question, shading them to indicate to the user
>that they aren't any longer directly visible or just by doing nothing.
>
>ITEM <number> <locx> <locy> <image> <text>
>Tells the client that the player seen an item with the tag <number> at
>the location <locx>,<locy>.  <image> indicates the name of the image
>file to use for the item and <text> is the full name of the item.  In
>addition, <locx> may also be the string "IN".  In that case <locy> is
>the tag number of the item within which the item at hand is located or
><locy> is the string "VOID" which means that the item has disappeared.
>
>VIEW <number>
>After this command the client considers the item with the tag <number>
>to be the viewpoint item and will always try to center the map around
>it.  This is typically the item which is the player object.


By followups, <number> is a unique number of each item.  A bunch of
orcs may have numbers 500,501,505, 508, etc.

<image> should probably be the archetype name.  In this way, the client
will know about the animations, as well as the item name.  However, 
image names in objects can be modified (ie, have a key look like a horn).
Also, some objects could have their animations disabled.

Also, it seems to me that sending the monsters along with all they are
carrying is something not immediately needed.  In general, I could
care less what an orc is carrying, and would probably prefer for it
to be inserted into the map when I kill him.  But even then, I only 
care about the number items up to my STACKING depth.

I also want to be able to use a local archetypes file if possible.  Not
the full information contained in the archetype file is necessary, but
things like name and animations would be.  But what this allows me to
do is adjust things like animations.  I may not want sea and grass
animated, or things like the fire in fireballs, simply because I have
a slow X-server, and these slow things down too much.  By having a local
archetypes file, these can be adjusted fairly easily to my tastes.

I believe in some followup, both MAP and ITEM commands and (light_value)
as part of their description (if/when light sources get added).  These
are not needed right now - the PROTOCOL revision can add this in later,
and still have things work.

Examples of how the above works (taken from another mail message
by Carl):

Server->Client: VIEW 123
(states that object 123 is the center object of the map, and calculates
LOS accordingly).

S->C: MAP 40 40 floor 41 40 wall 42 40 wall ...
(sets what objects are where.  IT is not clear in the present
protocol about sending two different images with the same coordinate
via the map command.  I would think that this means that there are those
two images there, and not that an overwrite should occur)

S->C: ITEM 123 44 44 1 Carlsimage Carl
           ^    ^  ^ ^  ^          ^
Itemtag ---|    |  | |  |          |
X coordinate ---|  | |  |          |
Y coordinate ------| |  |          |
Quantity ------------|  |          |
Name of image ----------|          |
Name of item ----------------------|

(this is the player item.  The view command centers the map
around this object).

S->C: ITEM 433 IN 123 1 helmetimage X ray Helmet (worn)
Tells the client that this item is in the player item.  It can
keep track of this in the inventory window.  Note that the (worn)
is just part of the name.  If the client recognizes this and then does
something special, that is its perogative.

More item commands like the above would happen as the players inventory
is sent.  Now that you could having something like:
S->C: ITEM 600 IN 123 1 luggage The Luggage
S->C: ITEM 605 IN 600 5 gems Gems

The first states that the player is carrying the luggage, and the second
is stating that he has 5 gems in the luggage.

C->S: MOVE 123 44 45
A request by the client to move the player (object 123) south (from
44 to 45).  Remember, that the maps make 0,0 as the upper left corner,
not lower left as in standard geometry.

The server then process this command.  If the player can make this
move (no wall), and when sufficient time has passed (slowdown factor),
it sends:

S->C: ITEM 123 44 45
Telling the client that object 123 is now at 44,45.  IT does not
need to send full data, since this object never left LOS.

However, this does require that the server keep track of an object in
LOS or if it leaves it.  This because a bit of an implementation problem -
you don't want to keep track of whether each object is in LOS for
each player - this would chew up a lot of memory and would probably
hard code some maximum number of players (if you use an int, you only
have 32 bits for LOS for players).

As I see it, an array of some sort will need to be kept in the
player structure, with this array containing what objects/images were
last drawn around the player.  Then each tick, you go through and see
what is around the player, and see if any new objects have appeared,
and send ITEM/MAP commands for them.  A linked list could be used to keep
track of the items it has sent descriptions for.

Another method would be to keep track of this information when the
object changes/moves.  Perhaps have a few fields of linked list of
objects in the players - one for 'changed' and one for entered field
of view.  Then, when the object moves/does whatever, it checks to see
if it is in any players field of view, and if so, puts itself on
one of those lists (changed or entered field of view).  Then, this
data is processed, and it woudl be decided if it is sent down the
line or not (determined via stacking).  However, this would require
all ITEM commands need to be sent, or you once again need to keep track
someplace what items have been sent down the line (and also need to
somehow keep track of what was sent down the line but is no longer
visible.

 IF anyone has good ideas on how to handle this area, I would
be interested.

Back to the player moving (S->C: ITEM 123 44 45):

When the client recieves this, it should scroll the map up one.
It now sends a map command to fill the new bottom row up:
S->C: MAP 40 50 wall 41 50 wall 42 50 wall ...

S->C: UNMAP 40 40 41 40 ...
removes the row that scrolled off.  I personally don't think this
is necessary - if a row scrolls off the edge of the display, it should
be taken as an implicit unmap.


LOS is updated (IMHO, this should be done before the MAP command),
and new object that appear are sent:
S->C: ITEM 642 45 50 1 orcimage Orc chieftain

Orc wants to attack player, so it moves towards him:
S->C: ITEM 642 45 49
S->C: ITEM 642 45 48
S->C: ITEM 642 45 47

 Since the item tag number is unique, each item command effectively
removes the previous location.

Problem: This requires that for each ITEM command received by the client,
the client needs to search through all the old ITEM objects it has stored
to see if an item of that tag exists someplace else.

The player decides to drop his helmet (has not moved any spaces):
C->S: MOVE 433 44 45

This is a request by the client to drop the helmet.  Effectively, it is a
move out of inventory and onto the map.

S->C: ITEM 433 44 45
Server process the command.  Note that the client has to search through
all the items it knows about and find the one with tag 433 and remove it.

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
More SERVER->CLIENT commands:
>TEXT ...
>This commands instructs the client to display the remainder of the line
>(after the space character terminating the TEXT command) verbatim in
>some sort of text area.  The client may word wrap the text.
>
>PLAY <sound>
>Instructs the client to play the sound with the specified name.  If the
>client doesn't know the sound by that name it requests it from the
>server (see REQUEST/TRANSMIT).

At startup, their should also be a mechanism for the client to state
it doesn't have sound, and thus, PLAY commands should not be sent
(probably a minor bandwidth savings)

>STAT <stat> <current> [<maximum>]
>This tells the client that the value of the player statistic called
><stat> is <current>.  If given <maximum> indicates the maximum value of
>that stat.  The client could simply print out this message in the text
>area, but it is encouraged to recognize at least a few commonly used
>stats like hp or sp or food and make up some cute graphical
>representation for them which the player sees at all times.
>
>REQUEST <name> <type>
>Ask the client to send the the binary file called <name> of type <type>
>using the TRANSMIT command.

It is unclear why the server would ever make a request.  And in fact,
this could be considered a security problem (server requests some file
it has no business knowing about (ie, /etc/passwd).  I suppose that
an option in the client to ignore REQUEST's would solve this
potential problem.
>
>TRANSMIT <name> <type> <length>
>This command is followed by binary data of the length <length> bytes
>which describes the binary object of name <name> of type <type>
>(typically either IMG or SND).  All other command interpretation is
>suspended while the binary data streams in.  After the binary data has
>been received normal command interpretation resumes immediately.
>
>
>ERROR <...>
>This command is used to indicate that a real error has occured.  The
>remainder of the line is some free form text describing that error.
>What the client does with that message is up to it.  This command is
>only used to indicate actual program errors which point to
>bugs/incompatibilities between it and the server such as malformed
>packets and the like.  Player errors (like trying to take something
>which isn't there) are handled by normal TEXT messages.
>
>QUERY <...>
>Ask the user a question with the text <...>.  Some clients may want to
>pop up a requestor for this.  Others may not.  The answer is taken from
>the next REPLY packet sent by the client.
>
This is a really a convenience command.  It is not needed, and usage
of the TEXT and SAY command (see below) could also be used.

==============================================================================
VALID COMMANDS FROM THE CLIENT TO THE SERVER
============================================
>LOGIN <client-version> <name> <password>
>Typically this will be the first command sent by the client.  If it is  
>sent during a session, the effect is the same as if the session had
>been terminated and a new connection had been established with this
>command.  <client-version> is a string created by the client at compile
>time.  The server is not encouraged to treat different clients
>differently.  This string is just there to be able to gather statistics
>(and to correlate with ERROR packets).  <name> and <password> are
>self-explanatory.
>
>REQUEST
>TRANSMIT
>ERROR
>These three commands are valid in this direction as well with the same
>syntax and semantics.
>
>MOVE <number> <locx> <locy>
>This is probably the most frequently used command.  In it the client
>asks the server to move the item with tag <number> to be moved to
>location <locx>, <locy>.  As with ITEM (see above) <locx> can also be
>the string "IN" in which case <locy> is the tag of an item into which
>the item at hand should be moved.  A player would use this command to
>pick up items, to drop them, to throw them, to steal them and most
>importantly to move himself around the map (with <number> == the tag
>number which the client was told by the VIEW command).  Clients may
>want to take single steps or can ask to run as far as possible in one
>direction by giving huge values for <locx> or <locy>.
>
>APPLY <number>
>The player tries to apply the item with tag <number>.
>
>INVOKE <spell> <locx> <locy>
>The player actually casts the spell with name <spell> at <locx>,<locy>
>(as with MOVE, <locx> can be "IN" and <locy> an item tag number to cast
>a spell at an item).
>
>SAY <...>
>The player says whatever the free-form text which follows on the line
>is.  Other players would see this by means of some TEXT message.
>
>REPLY [YES|NO]
>The response to the most recent QUERY command.
>
>
COMMAND (command):  This is a simple extension.  Various servers may
add commands that do not warrant extending the protocol.  Right
now, there are many commands that really do not need individual
protocl requests (who, help, etc).  An option in the client can
exist to pass the command directly to the server.  If the
server does not understand the command, it can send the error
back as TEXT message.

Various thoughts are welcome.  I am really worried about finding a good
way to implement the MAP and ITEM commands in an efficient manner.

Mark Wedel
master@rahul.net