<URL: http://bugs.freeciv.org/Ticket/Display.html?id=39472 >

A closer look at the backtrace reveals a rather severe bug in packhand.c.

   /* update continents */
   if (ptile->continent != packet->continent && ptile->continent != 0
       && packet->continent > 0) {
     /* We're renumbering continents, somebody did a transform.
      * But we don't care about renumbering oceans since
      * num_oceans is not kept at the client. */
     map.num_continents = 0;
   }

   ptile->continent = packet->continent;

   if (ptile->continent > map.num_continents) {
     map.num_continents = ptile->continent;
     allot_island_improvs();
   }

The num_continents reset to 0 is triggered when a land tile changes 
continent (this only happens when continents are merged or split via 
land<->ocean transformation).  This then triggers num_continents to be 
set below which triggers a recheck of the island improvements.  But the 
setting of num_continents is incorrect as there is no guarantee that 
THIS tile is the highest numbered continent.  Thus for a while 
map.num_continents is wrong and the bug will be triggered.  In the 
savegame of course there were a huge number of continents so the bug is 
likely triggered most of the time when two of them are unified via ocean 
transformation.

trunk code doesn't have the allot_island_improvs call but the 
num_continents bug appears to still be there.  allot_island_improvs is a 
bit problematic here because it appears when a continent renumbering 
happens it will be called once for EACH tile on the renumbered 
continent.  For 2.0 this needn't be changed of course but hopefully 
trunk does have a better system.

The short explanation is that we can never decrease map.num_continents 
without iterating over the entire map to find the correct value for it, 
which the code does not do.  The safest way to handle this is just to 
always increase it.

The attached patches should fix it for 2.0 and trunk.  This probably 
replaces the previous patch I sent.  One variant or another should 
probably apply to S2_1 and S2_2 also.

-jason

Index: client/packhand.c
===================================================================
--- client/packhand.c	(revision 14840)
+++ client/packhand.c	(working copy)
@@ -1967,6 +1967,7 @@
   enum known_type old_known = ptile->known;
   bool tile_changed = FALSE;
   bool known_changed = FALSE;
+  bool renumbered = FALSE;
 
   if (ptile->terrain != packet->type) { /*terrain*/
     tile_changed = TRUE;
@@ -2030,13 +2031,17 @@
     /* We're renumbering continents, somebody did a transform.
      * But we don't care about renumbering oceans since 
      * num_oceans is not kept at the client. */
-    map.num_continents = 0;
+    renumbered = TRUE;
   }
 
   ptile->continent = packet->continent;
 
   if (ptile->continent > map.num_continents) {
     map.num_continents = ptile->continent;
+    renumbered = TRUE;
+  }
+
+  if (renumbered) {
     allot_island_improvs();
   }
 
Index: client/packhand.c
===================================================================
--- client/packhand.c	(revision 14840)
+++ client/packhand.c	(working copy)
@@ -2370,21 +2370,9 @@
     unit_list_unlink_all(ptile->units);
   }
 
-  /* update continents */
-  if (ptile->continent != packet->continent && ptile->continent != 0
-      && packet->continent > 0) {
-    /* We're renumbering continents, somebody did a transform.
-     * But we don't care about renumbering oceans since 
-     * num_oceans is not kept at the client. */
-    map.num_continents = 0;
-  }
-
   ptile->continent = packet->continent;
+  map.num_continents = MAX(ptile->continent, map.num_continents);
 
-  if (ptile->continent > map.num_continents) {
-    map.num_continents = ptile->continent;
-  }
-
   if (known_changed || tile_changed) {
     /* 
      * A tile can only change if it was known before and is still
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to