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

Client/server part x



[ This has been dissucced to death, but still one more try ;) ]

The goals for client/server (some from Mark, some added by me):

1) To make it a low bandwidth protocol. 
   - Probably means binary and UDP in the future, but ASCII and
     TCP/IP is good starting point. Just remember to keep code 
     so it's easy to change.
   - Allow client to tell server what information it can't use, 
     so that server doesn't send them (e.g. sound/stacking)

2) To keep a smart client, but assumed unsecure client.
   - Think client as a player, if player needs to know something
     tell it client, otherwise not send it to client.
   - All pickup modes/inventory handling done by client side,
     server only handle client's requests (apply chest, drop
     sword). All done with item's tag.

3) To keep things relatively simple in coding standards.
   - Avoid bugs 
   - Get something to done.

4) To make more secure interface.
   - Opening windows on X-screens is far from secure

5) To make server simpler and more efficient
   - Allows more players
   - Easier to degug and make more stable.

I agree with Cameron Blackwood in most ideas. I don't think its 
useful to have a global coordinate system. The first thing is that 
player doesn't need to the global coordinates so don't send
them. It also forces client have idea of map, which is a bad thing.
The current world map is one try to compile small maps to world map
and player is interesting about the world, not maps. Also when player 
changes a map, both server and client must clear all old buffers
and totally start again (If player has played large map then it
might be large number of commands 'ITEM ob IN VOID'. Remember that 
player knows only object's face if object isn't below the player.

Another basic thing is a difference between objects (ITEM) and
backgrounds (MAP). Some old version of crossfire did have that
difference and I don't like get it back. It's easily abused from 
client's side. The simplest abuse is the draw a big red cross over 
every item which name is wall, a very efficient way to implement 
'detect secret doors' spell ;). Other thing is that most floor 
objects can't use MAP command since it doesn't contain object 
names and most floors names are wanted to be kept. MAP commands 
can't even cached since UNMAP is needed when player moves or players 
LOS changes. So it's complicated and no any advantage is achieved.

The previous two points are what I would like change in proposed protocol.
And those main principals not actually nothing to do with implementation
with individual commands.

Although Mark said that he won't make any significant changes without
very good reason, I can still try to present my points. (If they are
good, it's another question :). So lets move to the implementation 
part. 

Initialisation is the motly good. Some command is needed to tell if 
client(server) can support sounds. Also if you want to support fonts 
it should have I_IMAGE command containing bitmap number. Client wastes 
too much time just converting string to numbers, so why server can't 
use the numbers. The numbers could be indexes to font, pixmap arrays 
or animation arrays (expained later). Image name might also include 
some checksum for each image (or image group), so client can notice if 
some bitmaps have changed in the server side.

Basic map updates from server client:

S->C: MAP <image1.1.1> <image1.2.1>,<image2.1>,<image3.1>.... 120 times

where 
 <image.1.1.1> is the top left corner in current vision and 
 <image.1.1.2> is below of it.
 <image.2.1>  the second item of that row and so on.

The full update. Update the whole clients vision. This is needed 
when player moves totally different environment (e.g. enters shop).
This is much shorter because coordinates aren't needed like previous
version.

S->C: REMAP <locx1> <locy1> <image1> <image2>, <locx2> <locy2> <image2>...

<locx> <locy> is relative location to player (or top left corner of 
              players view). 

The partical update. Send only the changes to last view. Note that
this can be used even if map changes. (If player is middle of
forest and sees only trees then players view doesn't change 
even map changes). 

[ minor optimation follows:                                       ]
[ <square> could be used instead of <locx> <locy>, so that        ]
[ <square> = <locy> * VIEW_SIZE + <locx> (VIEW_SIZE currently 11) ]

Forget the whole UNMAP command, it really hasn't any use, just sending
black face makes same thing and it simpler for server side. Also client
shouldn't care if square is outside of map or just blocked square, it 
looks just the same.

S->C: ITEM <length_flags> <tag> <locx> <locy> <arch_name> <flags> <weight> 
	   <name>

This is basically good, but details have to be changed :). The face is 
missing and it can't be taken from archetype (you have key which face can 
be shovel and so on). And I don't really see client side archetype file 
useful, since archetypes aren't used in maps (objects are) and player sees 
only maps and objects. The only thing what is unique to archetype is 
animation. It's very good idea let client decide if it wants to see 
'decoration' animations (like grass or sea), but all important animations 
are needed to be done by server (gates, spikes, monster turning). One 
solution is use <anim_name> instead of <arch_name>. <anim_name> would be 
name of animation used in that object. Animation struct contains series 
of faces and animation speed. Much simpler than whole archetype and can 
support also colors.

[ side note: Original protocol sends sea as a MAP command so how    ]
[ image sea.111 can be animated through archetype sea. These hasn't ]
[ any connection.                                                   ]

I would use ITEM command only thing which are players inventory or below 
the player. In that case <locx> and <locy> wouldn't be needed. They could 
be replaced with one <loc> which tells where object is. Value could be 
either tag or (-1?) telling that object is below the player.

Also I would move '(worn) (magic) (cursed)' flags from name to flags 
section, but it's a minor thing. Also I would add nrof so client knows 
number of items without having to parse name. Useful something like 
paying unpaid objects (client decide what coins are are used to pay an 
item and server only needs to check this coin-list for payment). Also 
allows client client make same simple checks (player tries to drop 100 
coins if he has only 10).

so my item would look something like 

S->C: ITEM <tag> <loc> <anim_name> <flags> <weight> <nrof> <name>

I dropped <length_flags> since there aren't really any advantages
to use it. Server should remember what was send before and savings
are very minimal. Things like <loc> is big help for client to locate
object (no need search through all objects). If name haven't changed
then empty string "" could be send. Same for anim_name and flags.

C->S: MOVE <tag> <nrof> <loc>

Move commands needs nrof, so 10 arrows can be dropped. <loc> is 
same as in previous case. <from> could be added to make it 
easier to locate objects.

QUERY/REPLY commands need an unique identifiers if they are being
supported (server can send multiple queries). Only thing where
this might be useful is begin of game "roll again (y/n/1-6?)". But 
like already said this is not really needed.

Player can only move not walk or run like currently. For me it don't 
make sense if we want to reduce server load and have smart client 
still client tells server absolute coordinates and server has to 
route player (The requested position might be the other side of a map).
The more simpler method would have just basic commands 

C->S: GO <dir1> <dir2>
C->S: RUN <dir1> ... 

and client calculates needed directions. And FIRE command should 
contain object to be fired, I don't think that keeping range names for
server side is good idea. The delays (if added) should be for
using items or applying them, not just changing range type. Most
spells need direction (and some parameters) not a coordinates.

Also EXAMINE command is totally missing. It's better support this
directly since is used quite often.

C->S: EXAMINE <tag>


The main reason why I suggest to cache only images and not objects
is because it can be done very efficiently server side and doesn't 
require over complicated server and client code. The proposed
protocol is so complicated 'object cache' that there aren't even 
any efficient solutions to implement it _server_ side, and server's 
CPU time is much more interesting thing that clients. On MAP/REMAP 
could implemented easily to server side (see below). And MAP/REMAP 
commands could be used even in UDP implemantation, send MAP 
periodically and other times just REMAP commands.

for (i = -5 .. 5)
    for (j = -5 .. 5)
  	new_view [i+5][j+5] = map[pl->x + i][pl->y + j].face;
	if (new_view [i+5][j+5] != old_view [i+5][j+5])
            changes++;

if (changes > some_value)
    Send (MAP);
else
    Send (REMAP);
swap(oldview, newview);

Congratulations if you did managed to read to this far. If you
don't agree with me thats fine. The main point is that smart 
client don't mean same as overcomplicated one. If someone 
wants to code the proposed protocol's server part and gets
it even working sometime soon it's great, but I feel that 
it's partly wasted effort.

 -Tero