[crossfire] Map Protocol Question

Andreas Kirschbaum kirschbaum at myrealbox.com
Wed Jul 6 05:09:40 CDT 2005


Mark Wedel wrote:
>
     
      Alex Schultz wrote:
     
     >
     
      > Hi,
     
     >
     
      >
     
     >
     
      > I'm currently making a bot framework with a GUI display similar to a
     
     >
     
      > normal client in python. I have managed to impliment handling for
     
     >
     
      > the map protocol in a way that works quite well except for a few
     
     >
     
      > obscure bugs, one of which I'm wondering if anybody has any idea
     
     >
     
      > about.
     
     >
     
      >
     
     >
     
      > I've noticed that often while teleporting in the GTK client, that
     
     >
     
      > sometimes some seemly random tiles are blank for a very brief moment
     
     >
     
      > and then display after the others. In the bot that I'm making, for
     
     >
     
      > some reason this same thing happens except those tiles stay blank. I
     
     >
     
      > haven't been able to determine the pattern to which tiles are blank,
     
     >
     
      > but I'm wondering if anybody has any idea about possible cause of
     
     >
     
      > that.
     
     >
     
     
     >
     
      I'm not sure why the tiles would stay blank on your client - that bit
     
     >
     
      seems odd.
     
     >
     
     
     >
     
      I've not investigated the problem at all, because as said, it does
     
     >
     
      correct itself pretty quickly.
     
     >
     
     
     >
     
      My thought is something like this: The server logic is to only send
     
     >
     
      those spaces that change. When you change maps, there are cases where
     
     >
     
      some spaces may be the same (or perhaps some faulty logic on the
     
     >
     
      server part). So those aren't send on the first map command. On the
     
     >
     
      next one, the server sees that some data it has sent isn't correct,
     
     >
     
      and sends the updated data correcting the problem. But since there is
     
     >
     
      roughly 1/8th a second between those two commands, you see the missing
     
     >
     
      spaces briefly.
     
     >
     
     
     >
     
      I seem to notice the most when leaving some of the shops in scorn. But
     
     >
     
      the map draw logic has gotten very complicated with various changes
     
     >
     
      and I really need to redo it at some point.
     
     
If I read the protocol description correctly, it is supposed that a
newmap command tells the client that "the map has changed, please forget
all fog of war information". But currently the server does it wrong:

The server sends this command (after the player has changed the map) but
does not clear its internal map state. The result is that client and
server disagree about the map contents: the client assumes an empty map
(thus showing blank faces). But the server still assumes the
surroundings of the previous map, therefore *not* re-sending these (in
the servers' view) unchanged tiles, resulting in the problem (tiles
staying blank) the bot has.

The currently existing "real" clients circumvent this bug by just
sending a mapredraw command after they receive a newmap command. (For
the x11 client see x11/xutil.c, function reset_map().) Thus, the problem
gets corrected shortly afterwards (and explains the shortly visible
blank tiles).

The attached patch is how I tried to fix it quite a while ago. (Note
that I did not check if it is currently still working.) I did stop
working on that fix because I think there is more to it:

You cannot fix the clients as well by just not sending the mapredraw
command because that would break new clients connecting to old servers
(i.e. not fixed servers). One solution I thought of was to increase the
server version and make the client not send the mapredraw command only
if it detects a fixed server.
-------------- next part --------------
Index: socket/request.c
===================================================================
RCS file: /cvsroot/crossfire/crossfire/socket/request.c,v
retrieving revision 1.69
diff -c -5 -r1.69 request.c
*** socket/request.c	6 May 2005 21:10:27 -0000	1.69
--- socket/request.c	6 Jul 2005 10:05:23 -0000
***************
*** 82,91 ****
--- 82,93 ----
  #include <sys/time.h>
  #endif
  
  #include "sounds.h"
  
+ static void map_clearcell(struct MapCell *cell, int face0, int face1, int face2, int count);
+ 
  /**
   * This table translates the attack numbers as used within the
   * program to the value we use when sending STATS command to the
   * client.  If a value is -1, then we don't send that to the
   * client.
***************
*** 651,672 ****
  
  /** client wants the map resent */
  
  void MapRedrawCmd(char *buff, int len, player *pl)
  {
      /* Okay, this is MAJOR UGLY. but the only way I know how to
       * clear the "cache"
       */
!     memset(&pl->socket.lastmap, 0, sizeof(struct Map));
      draw_client_map(pl->ob);
  }
  
  /** Newmap command */
  void MapNewmapCmd( player *pl)
  {
!     if( pl->socket.newmapcmd == 1)
          Write_String_To_Socket( &pl->socket, "newmap", 6);
  }
  
  
  
  /**
--- 653,688 ----
  
  /** client wants the map resent */
  
  void MapRedrawCmd(char *buff, int len, player *pl)
  {
+     int x, y;
+ 
      /* Okay, this is MAJOR UGLY. but the only way I know how to
       * clear the "cache"
       */
!     for(y=0; y<pl->socket.mapy; y++) {
! 	for(x=0; x<pl->socket.mapx; x++) {
! 	    map_clearcell(&pl->socket.lastmap.cells[x][y],0,0,0,-2);
! 	}
!     }
      draw_client_map(pl->ob);
  }
  
  /** Newmap command */
  void MapNewmapCmd( player *pl)
  {
!     int x, y;
! 
!     if( pl->socket.newmapcmd == 1) {
          Write_String_To_Socket( &pl->socket, "newmap", 6);
+ 	for(y=0; y<pl->socket.mapy; y++) {
+ 	    for(x=0; x<pl->socket.mapx; x++) {
+ 		map_clearcell(&pl->socket.lastmap.cells[x][y],0,0,0,-1);
+ 	    }
+ 	}
+     }
  }
  
  
  
  /**
***************
*** 1078,1087 ****
--- 1094,1104 ----
  {
      cell->count=count;
      cell->faces[0] = face0;
      cell->faces[1] = face1;
      cell->faces[2] = face2;
+     /* XXX: does not reset cell->faces[3] and cell->smooth[] */
  }
  
  #define MAX_HEAD_POS	31
  #define MAX_LAYERS	3
  
    
    


More information about the crossfire mailing list