Complete.Org: Mailing Lists: Archives: freeciv-dev: May 2003:
[Freeciv-Dev] (PR#4242) Clean up the goto route network protocol and rou
Home

[Freeciv-Dev] (PR#4242) Clean up the goto route network protocol and rou

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients:;
Subject: [Freeciv-Dev] (PR#4242) Clean up the goto route network protocol and route execution
From: "Raimar Falke" <rf13@xxxxxxxxxxxxxxxxx>
Date: Thu, 15 May 2003 13:00:45 -0700
Reply-to: rt@xxxxxxxxxxxxxx


The attached patch:
 - cleans up the network protocol (struct packet_goto_route)
 - rewrites goto_route_execute
 - minor cleanups (destroy_unit_goto_route, move of struct goto_route
 to unit.h, maybe_cancel_patrol_due_to_enemy)

Notes:
 - since I'm not sure what should be returned in case of waiting I
 just added another constant: GR_WAIT. It doesn't seems that any
 caller checks the result of goto_route_execute strictly.
 - the savegame load support of older savegames is fishy. It may
 work. It may not. It works with a new savegame.
 - a lot of the cruft of the old protocol was about handling
 unlimited routes by splitting these into chunks. I removed this and
 set a limit (MAX_LEN_ROUTE). MAX_LEN_ROUTE is 1200 steps. This is ~5
 times the number to go around the largest world (255x255).
 - a unit which is waiting is blinking with a "G" at the client. This
 may be irritating.
 - the old code creates a patrol route by reversing the path to the
 "reverse point". This doesn't work with waiting (trireme). If this is
 done properly it can happen that the way back to the starting point
 is different from the way to the "reverse point".
 - only the human player ever uses punit->pgr. No other code sets it.
 - in total the patch removes some lines :-)
 11 files changed, 323 insertions(+), 358 deletions(-)

It works with my test cases. But this is rather large change so I'm
sure that there are errors.

        Raimar

-- 
 email: rf13@xxxxxxxxxxxxxxxxx
 "We've all heard that a million monkeys banging on a million typewriters
  will eventually reproduce the entire works of Shakespeare.
  Now, thanks to the Internet, we know this is not true."

Index: client/goto.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/goto.c,v
retrieving revision 1.49
diff -u -u -r1.49 goto.c
--- client/goto.c       2003/05/15 12:38:11     1.49
+++ client/goto.c       2003/05/15 19:57:02
@@ -406,13 +406,52 @@
 }
 
 /********************************************************************** 
-  FIXME: the packet interface need to be changed to support danger
-  paths.
+  Convert the path structure used by the path finding to the route
+  structure which is used for the network interface. If the path waits
+  the output will be shorter.
 ***********************************************************************/
+static void compact_path(struct packet_goto_route *dest,
+                        const struct pf_path *src)
+{
+  int i, j = 0;
+
+  assert(src->length < MAX_LEN_ROUTE);
+
+  pf_print_path(LOG_DEBUG, src);
+
+  for (i = 0; i < src->length; i++) {
+    struct pf_position *a = &src->positions[i];
+    struct pf_position *next =
+       (i == src->length - 1) ? NULL : &src->positions[i + 1];
+
+    dest->path[j].x = a->x;
+    dest->path[j].y = a->y;
+
+    if (i == src->length - 1 || is_valid_dir(a->dir_to_next_pos)) {
+      dest->path[j].wait = FALSE;
+    } else {
+      assert(next && (a->x == next->x && a->y == next->y));
+      dest->path[j].wait = TRUE;
+      i++;
+    }
+    j++;
+  }
+  dest->length = j;
+
+  for (i = 0; i < dest->length; i++) {
+    freelog(LOG_DEBUG, "[%d/%d] (%d,%d) wait=%d", i, dest->length,
+           dest->path[i].x, dest->path[i].y, dest->path[i].wait);
+  }
+}
+
+/********************************************************************** 
+  NOTE: there is no easy way to revert (go back on it) a path if the
+  original path waits at some points.
+***********************************************************************/
 void send_patrol_route(struct unit *punit)
 {
   struct packet_goto_route p;
-  int i, j = 0;
+  int from, to, i;
   struct pf_path *path = NULL;
 
   assert(is_active);
@@ -422,38 +461,24 @@
     path = pft_concat(path, goto_map.parts[i].path);
   }
 
+  compact_path(&p,path);
+
   p.unit_id = punit->id;
 
-  /* we skip the start position */
-  /* FIXME: but for unknown reason the server discards the last position */
-  p.length = 2 * (path->length - 1) + 1;
-  p.first_index = 0;
-  p.last_index = p.length - 1;
-  p.pos = fc_malloc(p.length * sizeof(struct map_position));
-  j = 0;
-  for (i = 1; i < path->length; i++) {
-    p.pos[j].x = path->positions[i].x;
-    p.pos[j].y = path->positions[i].y;
-    freelog(PACKET_LOG_LEVEL, "  packet[%d] = (%d,%d)", j, p.pos[j].x,
-            p.pos[j].y);
-    j++;
-  }
-  for (i = path->length - 2; i >= 0; i--) {
-    p.pos[j].x = path->positions[i].x;
-    p.pos[j].y = path->positions[i].y;
-    freelog(PACKET_LOG_LEVEL, "  packet[%d] = (%d,%d)", j, p.pos[j].x,
-            p.pos[j].y);
-    j++;
+  assert(p.length * 2 < MAX_LEN_ROUTE);
+
+  to = p.length;
+  for (from = p.length - 2; from >= 0; from--) {
+    p.path[to] = p.path[from];
+    to++;
+    p.length++;
   }
   send_packet_goto_route(&aconnection, &p, ROUTE_PATROL);
-  free(p.pos);
-  p.pos = NULL;
   pf_destroy_path(path);
 }
 
 /********************************************************************** 
-  FIXME: the packet interface need to be changed to support danger
-  paths.
+...
 ***********************************************************************/
 void send_goto_route(struct unit *punit)
 {
@@ -468,23 +493,11 @@
     path = pft_concat(path, goto_map.parts[i].path);
   }
 
+  compact_path(&p,path);
+
   p.unit_id = punit->id;
 
-  /* we skip the start position */
-  /* FIXME: but for unknown reason the server discards the last position */
-  p.length = path->length - 1 + 1;
-  p.first_index = 0;
-  p.last_index = p.length - 1;
-  p.pos = fc_malloc(p.length * sizeof(struct map_position));
-  for (i = 0; i < path->length - 1; i++) {
-    p.pos[i].x = path->positions[i + 1].x;
-    p.pos[i].y = path->positions[i + 1].y;
-    freelog(PACKET_LOG_LEVEL, "  packet[%d] = (%d,%d)", i, p.pos[i].x,
-            p.pos[i].y);
-  }
   send_packet_goto_route(&aconnection, &p, ROUTE_GOTO);
-  free(p.pos);
-  p.pos = NULL;
   pf_destroy_path(path);
 }
 
Index: common/capstr.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/capstr.c,v
retrieving revision 1.134
diff -u -u -r1.134 capstr.c
--- common/capstr.c     2003/05/08 03:06:58     1.134
+++ common/capstr.c     2003/05/15 19:57:02
@@ -78,7 +78,7 @@
                    "city_struct_minor_cleanup obsolete_last class_legend " \
                    "+impr_req +waste +fastfocus +continent +small_dipl " \
                    "+no_nation_selected +diplomacy +no_extra_tiles" \
-                   "+diplomacy2 +citizens_style"
+                   "+diplomacy2 +citizens_style +pgr"
 /* "+1.14.0" is protocol for 1.14.0 release.
  *
  * "conn_info" is sending the conn_id field. To preserve compatability
@@ -126,6 +126,8 @@
  *
  * "citizens_style": is support for loading of ruleset-specified
  * multi style citizens icons.
+ *
+ * "pgr": new goto route protocol. Adds the wait bit.
  */
 
 void init_our_capability(void)
Index: common/map.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/map.h,v
retrieving revision 1.146
diff -u -u -r1.146 map.h
--- common/map.h        2003/05/15 12:38:11     1.146
+++ common/map.h        2003/05/15 19:57:03
@@ -36,17 +36,6 @@
   int x,y;
 };
 
-struct goto_route {
-  int first_index; /* first valid tile pos */
-  int last_index; /* point to the first non_legal pos. Note that the pos
-                  is always alloced in the pos array (for coding reasons) */
-  int length; /* length of pos array (use this as modulus when iterating)
-                Note that this is always at least 1 greater than the number
-                of valid positions, to make comparing first_index with
-                last_index during wrapped iteration easier. */
-  struct map_position *pos;
-};
-
 struct tile {
   enum tile_terrain_type terrain;
   enum tile_special_type special;
Index: common/packets.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/packets.c,v
retrieving revision 1.247
diff -u -u -r1.247 packets.c
--- common/packets.c    2003/05/08 03:06:58     1.247
+++ common/packets.c    2003/05/15 19:57:04
@@ -2943,83 +2943,37 @@
   RECEIVE_PACKET_END(packet);
 }
 
-enum packet_goto_route_type {
-  GR_FIRST_MORE, GR_FIRST_LAST, GR_MORE, GR_LAST
-};
-#define GOTO_CHUNK 20
 /**************************************************************************
-Chop the route up and send the pieces one by one.
+...
 **************************************************************************/
 int send_packet_goto_route(struct connection *pc,
                           const struct packet_goto_route *packet,
                           enum goto_route_type type)
 {
-  int i;
-  int num_poses = packet->last_index > packet->first_index ?
-    packet->last_index - packet->first_index :
-    packet->length - packet->first_index + packet->last_index;
-  int num_chunks = (num_poses + GOTO_CHUNK - 1) / GOTO_CHUNK;
-  int this_chunk = 1;
-
-  i = packet->first_index;
-  assert(num_chunks > 0);
-  while (i != packet->last_index) {
-    unsigned char buffer[MAX_LEN_PACKET];
-    struct data_out dout;
-    int chunk_pos;
-
-    dio_output_init(&dout, buffer, sizeof(buffer));
-    dio_put_uint16(&dout, 0);
-
-    switch (type) {
-    case ROUTE_GOTO:
-      dio_put_uint8(&dout, PACKET_GOTO_ROUTE);
-      break;
-    case ROUTE_PATROL:
-      dio_put_uint8(&dout, PACKET_PATROL_ROUTE);
-      break;
-    default:
-      die("unknown type %d", type);
-    }
+  enum packet_type packet_type;
 
-    chunk_pos = 0;
-    if (this_chunk == 1) {
-      if (num_chunks == 1)
-       dio_put_uint8(&dout, GR_FIRST_LAST);
-      else
-       dio_put_uint8(&dout, GR_FIRST_MORE);
-    } else {
-      if (this_chunk == num_chunks)
-       dio_put_uint8(&dout, GR_LAST);
-      else
-       dio_put_uint8(&dout, GR_MORE);
-    }
+  if (type == ROUTE_GOTO) {
+    packet_type = PACKET_GOTO_ROUTE;
+  } else if (type == ROUTE_PATROL) {
+    packet_type = PACKET_PATROL_ROUTE;
+  } else {
+    assert(0);
+  }
 
-    while (i != packet->last_index && chunk_pos < GOTO_CHUNK) {
-      dio_put_uint8(&dout, packet->pos[i].x);
-      dio_put_uint8(&dout, packet->pos[i].y);
-      i++; i%=packet->length;
-      chunk_pos++;
-    }
-    /* if we finished fill the last chunk with NOPs */
-    for (; chunk_pos < GOTO_CHUNK; chunk_pos++) {
-      dio_put_uint8(&dout, map.xsize);
-      dio_put_uint8(&dout, map.ysize);
-    }
+  {
+    SEND_PACKET_START(packet_type);
+    int i;
 
     dio_put_uint16(&dout, packet->unit_id);
-
-    {
-      size_t size = dio_output_used(&dout);
+    dio_put_uint16(&dout, packet->length);
 
-      dio_output_rewind(&dout);
-      dio_put_uint16(&dout, size);
-      send_packet_data(pc, buffer, size);
+    for (i = 0; i < packet->length; i++) {
+      dio_put_uint8(&dout, packet->path[i].x);
+      dio_put_uint8(&dout, packet->path[i].y);
+      dio_put_bool8(&dout, packet->path[i].wait);
     }
-    this_chunk++;
+    SEND_PACKET_END;
   }
-
-  return 0;
 }
 
 /**************************************************************************
@@ -3028,86 +2982,23 @@
 **************************************************************************/
 struct packet_goto_route *receive_packet_goto_route(struct connection *pc)
 {
-  struct data_in din;
-  int i, num_valid = 0;
-  enum packet_goto_route_type type;
-  struct map_position pos[GOTO_CHUNK];
-  struct map_position *pos2;
-  struct packet_goto_route *packet;
-  int length, unit_id;
-
-  dio_input_init(&din, pc->buffer->data, pc->buffer->ndata);
-  dio_get_uint16(&din, NULL);
-  dio_get_uint8(&din, NULL);
-
-  dio_get_uint8(&din, (int *)&type);
-  for (i = 0; i < GOTO_CHUNK; i++) {
-    dio_get_uint8(&din, &pos[i].x);
-    dio_get_uint8(&din, &pos[i].y);
-    if (pos[i].x != map.xsize) num_valid++;
-  }
-  dio_get_uint16(&din, &unit_id);
+  RECEIVE_PACKET_START(packet_goto_route, packet);
+  int i;
 
-  check_packet(&din, pc);
-  remove_packet_from_buffer(pc->buffer);
+  dio_get_uint16(&din, &packet->unit_id);
+  dio_get_uint16(&din, &packet->length);
 
-  /* sanity check */
-  if (!pc->route)
-    pc->route_length = 0;
-
-  switch (type) {
-  case GR_FIRST_MORE:
-    free(pc->route);
-    pc->route = fc_malloc(GOTO_CHUNK * sizeof(struct map_position));
-    pc->route_length = GOTO_CHUNK;
-    for (i = 0; i < GOTO_CHUNK; i++) {
-      pc->route[i].x = pos[i].x;
-      pc->route[i].y = pos[i].y;
-    }
-    return NULL;
-  case GR_LAST:
-    packet = fc_malloc(sizeof(struct packet_goto_route));
-    packet->unit_id = unit_id;
-    length = pc->route_length+num_valid+1;
-    if (!pc->route)
-      freelog(LOG_ERROR, "Got a GR_LAST packet with NULL without previous 
route");
-    packet->pos = fc_malloc(length * sizeof(struct map_position));
-    packet->length = length;
-    packet->first_index = 0;
-    packet->last_index = length-1;
-    for (i = 0; i < pc->route_length; i++)
-      packet->pos[i] = pc->route[i];
-    for (i = 0; i < num_valid; i++)
-      packet->pos[i+pc->route_length] = pos[i];
-    free(pc->route);
-    pc->route = NULL;
-    return packet;
-  case GR_FIRST_LAST:
-    packet = fc_malloc(sizeof(struct packet_goto_route));
-    packet->unit_id = unit_id;
-    packet->pos = fc_malloc((num_valid+1) * sizeof(struct map_position));
-    packet->length = num_valid + 1;
-    packet->first_index = 0;
-    packet->last_index = num_valid;
-    for (i = 0; i < num_valid; i++)
-      packet->pos[i] = pos[i];
-    return packet;
-  case GR_MORE:
-    pos2 = fc_malloc((GOTO_CHUNK+pc->route_length) * sizeof(struct 
map_position));
-    if (!pc->route)
-      freelog(LOG_ERROR, "Got a GR_MORE packet with NULL without previous 
route");
-    for (i = 0; i < pc->route_length; i++)
-      pos2[i] = pc->route[i];
-    for (i = 0; i < GOTO_CHUNK; i++)
-      pos2[i+pc->route_length] = pos[i];
-    free(pc->route);
-    pc->route = pos2;
-    pc->route_length += GOTO_CHUNK;
-    return NULL;
-  default:
-    freelog(LOG_ERROR, "invalid type in receive_packet_goto_route()");
-    return NULL;
+  if (packet->length > MAX_LEN_ROUTE) {
+    packet->length = MAX_LEN_ROUTE;
   }
+
+  for (i = 0; i < packet->length; i++) {
+    dio_get_uint8(&din, &packet->path[i].x);
+    dio_get_uint8(&din, &packet->path[i].y);
+    dio_get_bool8(&din, &packet->path[i].wait);
+  }
+
+  RECEIVE_PACKET_END(packet);
 }
 
 /**************************************************************************
Index: common/packets.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/packets.h,v
retrieving revision 1.146
diff -u -u -r1.146 packets.h
--- common/packets.h    2003/05/08 03:06:58     1.146
+++ common/packets.h    2003/05/15 19:57:05
@@ -25,6 +25,7 @@
 #define MAX_LEN_MSG             1536
 #define MAX_ATTRIBUTE_BLOCK     (256*1024)     /* largest attribute block */
 #define ATTRIBUTE_CHUNK_SIZE    (1024*2)  /* attribute chunk size to use */
+#define MAX_LEN_ROUTE          (1200)    /* MAX_LEN_PACKET/3 - header */
 
 /* Note that MAX_LEN_USERNAME cannot be expanded, because it
    is used for the name in the first packet sent by the client,
@@ -899,13 +900,14 @@
   char improvements[B_LAST+1];
 };
 
-struct packet_goto_route
-{
-  int length;
-  int first_index;
-  int last_index;
-  struct map_position *pos;
+struct packet_goto_route {
   int unit_id;
+  int length;
+  struct {
+    int x, y;
+    /* will only leave this position with full move points */
+    bool wait;
+  } path[MAX_LEN_ROUTE];
 };
 
 struct packet_attribute_chunk
Index: common/unit.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/unit.c,v
retrieving revision 1.174
diff -u -u -r1.174 unit.c
--- common/unit.c       2003/05/13 11:16:52     1.174
+++ common/unit.c       2003/05/15 19:57:05
@@ -1468,10 +1468,15 @@
 **************************************************************************/
 void destroy_unit_virtual(struct unit *punit)
 {
+  destroy_unit_goto_route(punit);
+  free(punit);
+}
+
+void destroy_unit_goto_route(struct unit *punit)
+{
   if (punit->pgr) {
-    free(punit->pgr->pos);
+    free(punit->pgr->path);
     free(punit->pgr);
     punit->pgr = NULL;
   }
-  free(punit);
 }
Index: common/unit.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/unit.h,v
retrieving revision 1.97
diff -u -u -r1.97 unit.h
--- common/unit.h       2003/05/05 12:41:39     1.97
+++ common/unit.h       2003/05/15 19:57:06
@@ -18,7 +18,6 @@
 
 struct player;
 struct city;
-struct goto_route;
 struct tile;
 
 #define BARBARIAN_LIFE    5
@@ -95,6 +94,18 @@
                                   sewer but city has no sewer */
 };
 
+struct goto_position {
+  int x, y;
+  /* will only leave this position with full move points */
+  bool wait;
+};
+
+struct goto_route {
+  int current_index;
+  int length;
+  struct goto_position *path;
+};
+
 struct unit_ai {
   bool control; /* 0: not automated    1: automated */
   enum ai_unit_task ai_role;
@@ -267,5 +278,6 @@
 struct unit *create_unit_virtual(struct player *pplayer, struct city *pcity,
                                  Unit_Type_id type, bool make_veteran);
 void destroy_unit_virtual(struct unit *punit);
+void destroy_unit_goto_route(struct unit *punit);
 
 #endif  /* FC__UNIT_H */
Index: server/gotohand.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/gotohand.h,v
retrieving revision 1.27
diff -u -u -r1.27 gotohand.h
--- server/gotohand.h   2003/02/20 09:45:22     1.27
+++ server/gotohand.h   2003/05/15 19:57:07
@@ -25,7 +25,8 @@
   GR_ARRIVED,            /* arrived to the destination */
   GR_OUT_OF_MOVEPOINTS,  /* either no moves left or plane refueling */ 
   GR_FOUGHT,             /* was stopped due to fighting, has moves */
-  GR_FAILED              /* failed for some other reason, has moves */
+  GR_FAILED,             /* failed for some other reason, has moves */
+  GR_WAIT                /* is waiting a turn for recharge of moves */
 };
 
 bool is_dist_finite(int dist);
Index: server/savegame.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/savegame.c,v
retrieving revision 1.117
diff -u -u -r1.117 savegame.c
--- server/savegame.c   2003/05/15 12:26:53     1.117
+++ server/savegame.c   2003/05/15 19:57:09
@@ -1025,21 +1025,26 @@
 
     /* load the goto route */
     {
-      int len = secfile_lookup_int_default(file, 0, 
"player%d.u%d.goto_length", plrno, i);
+      int len = secfile_lookup_int_default(file, 0,
+                                          "player%d.u%d.goto_length",
+                                          plrno, i);
       if (len > 0) {
        char *goto_buf, *goto_buf_ptr;
        struct goto_route *pgr = fc_malloc(sizeof(struct goto_route));
-       pgr->pos = fc_malloc((len+1) * sizeof(struct map_position));
-       pgr->first_index = 0;
-       pgr->length = len+1;
-       pgr->last_index = len;
+
+       pgr->length = len;
+       pgr->current_index = secfile_lookup_int_default(file, 0,
+                                                       
"player%d.u%d.goto_index",
+                                                       plrno, i);
+       pgr->path = fc_malloc(len * sizeof(struct goto_position));
        punit->pgr = pgr;
 
        /* get x coords */
-       goto_buf = secfile_lookup_str(file, "player%d.u%d.goto_route_x", plrno, 
i);
+       goto_buf =
+           secfile_lookup_str(file, "player%d.u%d.goto_route_x", plrno, i);
        goto_buf_ptr = goto_buf;
        for (j = 0; j < len; j++) {
-         if (sscanf(goto_buf_ptr, "%d", &pgr->pos[j].x) == 0) {
+         if (sscanf(goto_buf_ptr, "%d", &pgr->path[j].x) == 0) {
            die("not an int");
          }
          while (*goto_buf_ptr != ',') {
@@ -1050,11 +1055,13 @@
          }
          goto_buf_ptr++;
        }
+
        /* get y coords */
-       goto_buf = secfile_lookup_str(file, "player%d.u%d.goto_route_y", plrno, 
i);
+       goto_buf =
+           secfile_lookup_str(file, "player%d.u%d.goto_route_y", plrno, i);
        goto_buf_ptr = goto_buf;
        for (j = 0; j < len; j++) {
-         if (sscanf(goto_buf_ptr, "%d", &pgr->pos[j].y) == 0) {
+         if (sscanf(goto_buf_ptr, "%d", &pgr->path[j].y) == 0) {
            die("not an int");
          }
          while (*goto_buf_ptr != ',') {
@@ -1065,14 +1072,45 @@
          }
          goto_buf_ptr++;
        }
+
+       /* get wait */
+       goto_buf =
+           secfile_lookup_str_default(file, "",
+                                      "player%d.u%d.goto_route_wait", plrno,
+                                      i);
+       if (strlen(goto_buf) > 0) {
+         /* Older savegames don't have this field */
+         goto_buf_ptr = goto_buf;
+         for (j = 0; j < len; j++) {
+           int tmp;
+
+           if (sscanf(goto_buf_ptr, "%d", &tmp) == 0) {
+             die("not an int");
+           }
+           pgr->path[j].wait = tmp;
+           while (*goto_buf_ptr != ',') {
+             goto_buf_ptr++;
+             if (*goto_buf_ptr == '\0') {
+               die("byebye");
+             }
+           }
+           goto_buf_ptr++;
+         }
+       }
       } else {
        /* mark unused strings as read to avoid warnings */
        (void) secfile_lookup_str_default(file, "",
+                                         "player%d.u%d.goto_route_index",
+                                         plrno, i);
+       (void) secfile_lookup_str_default(file, "",
                                          "player%d.u%d.goto_route_x", plrno,
                                          i);
        (void) secfile_lookup_str_default(file, "",
                                          "player%d.u%d.goto_route_y", plrno,
                                          i);
+       (void) secfile_lookup_str_default(file, "",
+                                         "player%d.u%d.goto_route_wait",
+                                         plrno, i);
        punit->pgr = NULL;
       }
     }
@@ -1428,42 +1466,49 @@
     secfile_insert_bool(file, punit->paradropped, "player%d.u%d.paradropped", 
plrno, i);
     secfile_insert_int(file, punit->transported_by,
                       "player%d.u%d.transported_by", plrno, i);
-    if (punit->pgr && punit->pgr->first_index != punit->pgr->last_index) {
+    if (punit->pgr) {
       struct goto_route *pgr = punit->pgr;
-      int index = pgr->first_index;
-      int len = 0;
-      while (pgr && index != pgr->last_index) {
-       len++;
-       index = (index + 1) % pgr->length;
-      }
-      assert(len > 0);
-      secfile_insert_int(file, len, "player%d.u%d.goto_length", plrno, i);
+
+      secfile_insert_int(file, pgr->length, "player%d.u%d.goto_length",
+                        plrno, i);
+      secfile_insert_int(file, pgr->current_index, "player%d.u%d.goto_index",
+                        plrno, i);
       /* assumption about the chars per map position */
       assert(MAP_MAX_HEIGHT < 1000 && MAP_MAX_WIDTH < 1000);
       {
-       char *goto_buf = fc_malloc(4 * len + 1);
+       char *goto_buf = fc_malloc(4 * pgr->length + 1);
        char *goto_buf_ptr = goto_buf;
-       index = pgr->first_index;
-       while (index != pgr->last_index) {
-         goto_buf_ptr += sprintf(goto_buf_ptr, "%d,", pgr->pos[index].x);
-         index = (index + 1) % pgr->length;
+       int j;
+
+       for (j = 0; j < pgr->length; j++) {
+         goto_buf_ptr += sprintf(goto_buf_ptr, "%d,", pgr->path[j].x);
+       }
+       *goto_buf_ptr = '\0';
+       secfile_insert_str(file, goto_buf, "player%d.u%d.goto_route_x",
+                          plrno, i);
+
+       goto_buf_ptr = goto_buf;
+       for (j = 0; j < pgr->length; j++) {
+         goto_buf_ptr += sprintf(goto_buf_ptr, "%d,", pgr->path[j].y);
        }
        *goto_buf_ptr = '\0';
-       secfile_insert_str(file, goto_buf, "player%d.u%d.goto_route_x", plrno, 
i);
+       secfile_insert_str(file, goto_buf, "player%d.u%d.goto_route_y",
+                          plrno, i);
 
        goto_buf_ptr = goto_buf;
-       index = pgr->first_index;
-       while (index != pgr->last_index) {
-         goto_buf_ptr += sprintf(goto_buf_ptr, "%d,", pgr->pos[index].y);
-         index = (index + 1) % pgr->length;
+       for (j = 0; j < pgr->length; j++) {
+         goto_buf_ptr += sprintf(goto_buf_ptr, "%d,", pgr->path[j].wait);
        }
        *goto_buf_ptr = '\0';
-       secfile_insert_str(file, goto_buf, "player%d.u%d.goto_route_y", plrno, 
i);
+       secfile_insert_str(file, goto_buf, "player%d.u%d.goto_route_wait",
+                          plrno, i);
       }
     } else {
       secfile_insert_int(file, 0, "player%d.u%d.goto_length", plrno, i);
+      secfile_insert_int(file, 0, "player%d.u%d.goto_index", plrno, i);
       secfile_insert_str(file, "", "player%d.u%d.goto_route_x", plrno, i);
       secfile_insert_str(file, "", "player%d.u%d.goto_route_y", plrno, i);
+      secfile_insert_str(file, "", "player%d.u%d.goto_route_wait", plrno, i);
     }
   }
   unit_list_iterate_end;
Index: server/unithand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unithand.c,v
retrieving revision 1.259
diff -u -u -r1.259 unithand.c
--- server/unithand.c   2003/05/06 08:13:21     1.259
+++ server/unithand.c   2003/05/15 19:57:09
@@ -1286,11 +1286,7 @@
     enum unit_activity old_activity = punit->activity;
     enum tile_special_type old_target = punit->activity_target;
     set_unit_activity(punit, new_activity);
-    if (punit->pgr) {
-      free(punit->pgr->pos);
-      free(punit->pgr);
-      punit->pgr = NULL;
-    }
+    destroy_unit_goto_route(punit);
     send_unit_info(NULL, punit);
     handle_unit_activity_dependencies(punit, old_activity, old_target);
   }
@@ -1310,11 +1306,7 @@
     enum tile_special_type old_target = punit->activity_target;
     set_unit_activity_targeted(punit, new_activity, new_target);
 
-    if (punit->pgr) {
-      free(punit->pgr->pos);
-      free(punit->pgr);
-      punit->pgr = NULL;
-    }
+    destroy_unit_goto_route(punit);
 
     send_unit_info_to_onlookers(NULL, punit, punit->x, punit->y, FALSE);
 
@@ -1390,63 +1382,37 @@
   (void) do_paradrop(punit, req->x, req->y);
 }
 
-
-
 /**************************************************************************
-Sanity checks on the goto route.
-**************************************************************************/
-static bool check_route(struct player *pplayer, struct packet_goto_route 
*packet)
-{
-  struct unit *punit = player_find_unit_by_id(pplayer, packet->unit_id);
-
-  if (!punit) {
-    return FALSE;
-  }
-
-  if (packet->first_index != 0) {
-    freelog(LOG_ERROR, "Bad route packet, first_index is %d!",
-           packet->first_index);
-    return FALSE;
-  }
-  if (packet->last_index != packet->length - 1) {
-    freelog(LOG_ERROR, "bad route, li: %d != l-1: %d",
-           packet->last_index, packet->length - 1);
-    return FALSE;
-  }
-
-  return TRUE;
-}
-
-/**************************************************************************
-Receives goto route packages.
+...
 **************************************************************************/
-static void handle_route(struct player *pplayer, struct packet_goto_route 
*packet)
+static void handle_route(struct player *pplayer,
+                        struct packet_goto_route *packet)
 {
-  struct goto_route *pgr = NULL;
   struct unit *punit = player_find_unit_by_id(pplayer, packet->unit_id);
+  struct goto_route *pgr = fc_malloc(sizeof(struct goto_route));
+  int i;
 
-  pgr = fc_malloc(sizeof(struct goto_route));
+  assert(same_pos(packet->path[0].x, packet->path[0].y, punit->x, punit->y));
 
-  pgr->pos = packet->pos; /* here goes the malloced packet->pos */
-  pgr->first_index = 0;
   pgr->length = packet->length;
-  pgr->last_index = packet->length-1; /* index magic... */
+  pgr->path = fc_malloc(pgr->length * sizeof(struct goto_position));
+  pgr->current_index = 0;
 
-  punit->pgr = pgr;
+  freelog(LOG_DEBUG, "unit-id=%d, length=%d", packet->unit_id, pgr->length);
 
-#ifdef DEBUG
-  {
-    int i = pgr->first_index;
-    freelog(LOG_DEBUG, "first:%d, last:%d, length:%d",
-          pgr->first_index, pgr->last_index, pgr->length);
-    for (; i < pgr->last_index;i++)
-      freelog(LOG_DEBUG, "%d,%d", pgr->pos[i].x, pgr->pos[i].y);
+  for (i = 0; i < pgr->length; i++) {
+    pgr->path[i].x = packet->path[i].x;
+    pgr->path[i].y = packet->path[i].y;
+    pgr->path[i].wait = packet->path[i].wait;
+    freelog(LOG_DEBUG, "  [%d] = (%d,%d) wait=%d", i,
+           pgr->path[i].x, pgr->path[i].y, pgr->path[i].wait);
   }
-#endif
 
+  punit->pgr = pgr;
+
   if (punit->activity == ACTIVITY_GOTO) {
-    punit->goto_dest_x = pgr->pos[pgr->last_index-1].x;
-    punit->goto_dest_y = pgr->pos[pgr->last_index-1].y;
+    punit->goto_dest_x = pgr->path[pgr->length - 1].x;
+    punit->goto_dest_y = pgr->path[pgr->length - 1].y;
     send_unit_info(pplayer, punit);
   }
 
@@ -1457,13 +1423,20 @@
 /**************************************************************************
 Receives goto route packages.
 **************************************************************************/
-void handle_goto_route(struct player *pplayer, struct packet_goto_route 
*packet)
+void handle_goto_route(struct player *pplayer,
+                      struct packet_goto_route *packet)
 {
   struct unit *punit = player_find_unit_by_id(pplayer, packet->unit_id);
 
-  if (!check_route(pplayer, packet))
+  if (!punit) {
     return;
+  }
 
+  if (packet->length < 2 || !same_pos(punit->x, punit->y, packet->path[0].x,
+                                     packet->path[0].y)) {
+    return;
+  }
+
   handle_unit_activity_request(punit, ACTIVITY_GOTO);
   handle_route(pplayer, packet);
 }
@@ -1471,13 +1444,17 @@
 /**************************************************************************
 Receives patrol route packages.
 **************************************************************************/
-void handle_patrol_route(struct player *pplayer, struct packet_goto_route 
*packet)
+void handle_patrol_route(struct player *pplayer,
+                        struct packet_goto_route *packet)
 {
   struct unit *punit = player_find_unit_by_id(pplayer, packet->unit_id);
+
+  if (!punit) {
+    return;
+  }
 
-  if (!check_route(pplayer, packet)) {
-    free(packet->pos);
-    packet->pos = NULL;
+  if (packet->length < 2 || !same_pos(punit->x, punit->y, packet->path[0].x,
+                                     packet->path[0].y)) {
     return;
   }
 
Index: server/unittools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unittools.c,v
retrieving revision 1.223
diff -u -u -r1.223 unittools.c
--- server/unittools.c  2003/05/10 18:11:25     1.223
+++ server/unittools.c  2003/05/15 19:57:11
@@ -54,6 +54,7 @@
 
 #include "unittools.h"
 
+#define GOTO_EXECUTE_LOG_LEVEL         LOG_DEBUG
 
 static void unit_restore_hitpoints(struct player *pplayer, struct unit *punit);
 static void unit_restore_movepoints(struct player *pplayer, struct unit 
*punit);
@@ -2681,8 +2682,7 @@
      We do not wakeup units further away than 3 squares... */
   square_iterate(punit->x, punit->y, 3, x, y) {
     unit_list_iterate(map_get_tile(x, y)->units, ppatrol) {
-      if (punit != ppatrol
-         && ppatrol->activity == ACTIVITY_PATROL) {
+      if (punit != ppatrol) {
        (void) maybe_cancel_patrol_due_to_enemy(ppatrol);
       }
     } unit_list_iterate_end;
@@ -2957,6 +2957,10 @@
   bool cancel = FALSE;
   int range;
 
+  if (punit->activity != ACTIVITY_PATROL) {
+    return FALSE;
+  }
+
   if (map_has_special(punit->x, punit->y, S_FORTRESS)
       && unit_profits_of_watchtower(punit))
     range = get_watchtower_vision(punit);
@@ -2982,95 +2986,119 @@
 }
 
 /**************************************************************************
-Moves a unit according to its pgr (goto or patrol order). If two consequetive
-positions in the route is not adjacent it is assumed to be a goto. The unit
-is put on idle if a move fails.
-If the activity is ACTIVITY_PATROL the map positions are put back in the
-route (at the end).  To avoid infinite loops on railroad we stop for this
-turn when the unit is back where it started, eben if it have moves left.
-
-If a patrolling unit came across an enemy we could make the patrolling unit
-autoattack or just stop and wait for the owner to attack. It is also
-debateable if units on goto should stop when they encountered an enemy
-unit. Currently the unit continues if it can, or if it is blocked it stops.
+Moves a unit according to its pgr (goto or patrol order). The unit is
+put on idle if a move fails.
+
+To avoid infinite loops on railroad we stop for this turn when the
+unit is back where it started, even if it have moves left.
+
+If a patrolling unit came across an enemy we could make the patrolling
+unit autoattack or just stop and wait for the owner to attack. It is
+also debateable if units on goto should stop when they encountered an
+enemy unit. Currently the unit continues if it can, or if it is
+blocked it stops.
 **************************************************************************/
 enum goto_result goto_route_execute(struct unit *punit)
 {
   struct goto_route *pgr = punit->pgr;
-  int index, x, y;
-  bool res, last_tile;
-  int patrol_stop_index = pgr->last_index;
   int unitid = punit->id;
   struct player *pplayer = unit_owner(punit);
 
   assert(pgr != NULL);
   while (TRUE) {
-    freelog(LOG_DEBUG, "running a round\n");
+    bool moved, last_step;
+    int old_x = pgr->path[pgr->current_index].x;
+    int old_y = pgr->path[pgr->current_index].y;
+    int x = pgr->path[pgr->current_index + 1].x;
+    int y = pgr->path[pgr->current_index + 1].y;
+    bool wait = pgr->path[pgr->current_index].wait;
+
+    assert(same_pos(old_x, old_y, punit->x, punit->y));
+
+    assert(pgr->current_index >= 0 && pgr->length >= 2
+          && pgr->current_index < pgr->length);
+
+    freelog(GOTO_EXECUTE_LOG_LEVEL,
+           "moves_left=%d pos=(%i,%i) -> (%i,%i) wait=%d",
+           punit->moves_left, punit->x, punit->y, x, y, wait);
 
-    index = pgr->first_index;
-    if (index == pgr->last_index) {
-      free(punit->pgr);
-      punit->pgr = NULL;
-      if (punit->activity == ACTIVITY_GOTO) 
-       /* the activity could already be SENTRY (if boarded a ship) 
-          -- leave it as it is then */
-       handle_unit_activity_request(punit, ACTIVITY_IDLE);
-      return GR_ARRIVED;
-    }
-    x = pgr->pos[index].x; y = pgr->pos[index].y;
-    freelog(LOG_DEBUG, "%i,%i -> %i,%i\n", punit->x, punit->y, x, y);
-
     if (punit->moves_left == 0) {
+      freelog(GOTO_EXECUTE_LOG_LEVEL, "  no move points");
       return GR_OUT_OF_MOVEPOINTS;
     }
 
-    if (punit->activity == ACTIVITY_PATROL
-       && maybe_cancel_patrol_due_to_enemy(punit)) {
+    if (maybe_cancel_patrol_due_to_enemy(punit)) {
       return GR_FAILED;
     }
 
+    if (wait && punit->moves_left <unit_move_rate(punit)) {
+      freelog(GOTO_EXECUTE_LOG_LEVEL, "  waiting");
+      return GR_WAIT;
+    }
+
     /* Move unit */
-    last_tile = (((index + 1) % pgr->length) == (pgr->last_index));
-    freelog(LOG_DEBUG, "handling\n");
-    res = handle_unit_move_request(punit, x, y, FALSE, !last_tile);
+    last_step = (pgr->current_index == pgr->length - 2);
+    moved = handle_unit_move_request(punit, x, y, FALSE, !last_step);
 
     if (!player_find_unit_by_id(pplayer, unitid)) {
+      freelog(GOTO_EXECUTE_LOG_LEVEL, "  died");
       return GR_DIED;
     }
 
-    if (same_pos(punit->x, punit->y, x, y)) {
-      /* We succeeded in moving one step forward */
-      pgr->first_index = (pgr->first_index + 1) % pgr->length;
-      if (punit->activity == ACTIVITY_PATROL) {
-       /* When patroling we go in little circles; 
-        * done by reinserting points */
-       pgr->pos[pgr->last_index].x = x;
-       pgr->pos[pgr->last_index].y = y;
-       pgr->last_index = (pgr->last_index + 1) % pgr->length;
-
-       if (patrol_stop_index == pgr->first_index) {
-         freelog(LOG_DEBUG, "stopping because we ran a round\n");
-         return GR_ARRIVED;    /* don't patrol more than one round */
-       }
+    freelog(GOTO_EXECUTE_LOG_LEVEL, "  moved=%d same_pos=%d moves_left=%d",
+           moved, same_pos(x, y, punit->x, punit->y), punit->moves_left);
+
+    if (!moved) {
+      if (punit->moves_left > 0) {
+       freelog(GOTO_EXECUTE_LOG_LEVEL, "can't move -> idle");
+       handle_unit_activity_request(punit, ACTIVITY_IDLE);
+       return GR_FAILED;
+      } else {
+       assert(punit->moves_left == 0);
+       freelog(GOTO_EXECUTE_LOG_LEVEL,
+               "not enough movepoints; unit lost in dice roll");
+       return GR_OUT_OF_MOVEPOINTS;
+      }
+    } else {                   /* moved */
+      if (!same_pos(x, y, punit->x, punit->y)) {
+       /*
+        * unit is alive, moved alright, didn't arrive, has moves_left
+        * --- what else can it be 
+        */
+       freelog(GOTO_EXECUTE_LOG_LEVEL, "attacked and won");
+       return GR_FOUGHT;
+      } else {
+       /* We succeeded in moving one step forward. */
+
+       pgr->current_index++;
+
        if (maybe_cancel_patrol_due_to_enemy(punit)) {
          return GR_FAILED;
        }
-      }
-    }
 
-    if (res && !same_pos(x, y, punit->x, punit->y)) {
-      /*
-       * unit is alive, moved alright, didn't arrive, has moves_left
-       * --- what else can it be 
-       */
-      return GR_FOUGHT;
-    }
-
-    if (!res && punit->moves_left > 0) {
-      freelog(LOG_DEBUG, "move idling\n");
-      handle_unit_activity_request(punit, ACTIVITY_IDLE);
-      return GR_FAILED;
-    }
+       if (pgr->current_index == pgr->length - 1) {
+         if (punit->activity == ACTIVITY_GOTO) {
+           /* the activity could already be SENTRY (if boarded a ship) 
+              -- leave it as it is then */
+           handle_unit_activity_request(punit, ACTIVITY_IDLE);
+           return GR_ARRIVED;
+         } else if (punit->activity == ACTIVITY_PATROL) {
+           assert(same_pos(pgr->path[pgr->current_index].x,
+                           pgr->path[pgr->current_index].y,
+                           pgr->path[0].x, pgr->path[0].y));
+           pgr->current_index = 0;
+
+           /* 
+            * We return here because we may otherwise be in a
+            * railroad loop.
+            */
+           return GR_ARRIVED;
+         } else {
+           assert(0);
+         }
+       }
+      } /* same_pos */
+    } /* moved */
   } /* end while*/
 }
 

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#4242) Clean up the goto route network protocol and route execution, Raimar Falke <=