Complete.Org: Mailing Lists: Archives: freeciv-dev: July 2004:
[Freeciv-Dev] (PR#9456) Improvements' lists in savegames
Home

[Freeciv-Dev] (PR#9456) Improvements' lists in savegames

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [Freeciv-Dev] (PR#9456) Improvements' lists in savegames
From: "Mateusz Stefek" <mstefek@xxxxxxxxx>
Date: Wed, 21 Jul 2004 00:17:00 -0700
Reply-to: rt@xxxxxxxxxxx

<URL: http://rt.freeciv.org/Ticket/Display.html?id=9456 >

With this patch savegames(city.improvements and destroyed_wonders)  
don't depend on improvement order in ruleset.
I changed my mind and implemented it with secfile_insert_str_vec().
I hope it's acceptable that secfile_insert_str_vec() implementation is  
a little tricky, this is really harmless.

--
mateusz


Tylko w freeciv: h
Tylko w freeciv/server: k.gz
diff -ur -Xdiff_ignore freeorig/server/savegame.c freeciv/server/savegame.c
--- freeorig/server/savegame.c  2004-07-19 09:34:46.000000000 +0200
+++ freeciv/server/savegame.c   2004-07-20 15:42:09.000000000 +0200
@@ -176,7 +176,7 @@
 #define SAVEFILE_OPTIONS "startoptions spacerace2 rulesets" \
 " diplchance_percent worklists2 map_editor known32fix turn " \
 "attributes watchtower rulesetdir client_worklists orders " \
-"startunits turn_last_built"
+"startunits turn_last_built improvement_order"
 
 static const char hex_chars[] = "0123456789abcdef";
 static const char terrain_chars[] = "adfghjm prstu";
@@ -732,6 +732,36 @@
   return old_impr_types[id];
 }
 
+/*****************************************************************
+  Insert improvement into old-style bitvector
+  Improvement lists in cities and destroyed_wonders are saved
+  that way. New bitvectors does not depend on ruleset order.
+  However, we want to create savegames which can be read by 
+  1.14.x and earlier servers.
+*****************************************************************/
+static void add_improvement_into_old_bitvector(char* bitvector,
+                                               Impr_Type_id id)
+{
+  int old_id;
+  old_id = old_impr_type_id(id);
+  if (old_id < 0 || old_id >= ARRAY_SIZE(old_impr_types)) {
+    return;
+  }
+  bitvector[old_id] = '1';
+}
+
+/*************************************************************
+  Fill old-style improvement bitvector with '0' s
+*************************************************************/
+static void init_old_improvement_bitvector(char* bitvector)
+{
+  int i;
+  for (i = 0; i < ARRAY_SIZE(old_impr_types); i++) {
+    bitvector[i] = '0';
+  }
+  bitvector[ARRAY_SIZE(old_impr_types)] = '\0';
+}
+
 /***************************************************************
 Load the worklist elements specified by path, given the arguments
 plrno and wlinx, into the worklist pointed to by pwl.
@@ -1060,7 +1090,9 @@
 ...
 ***************************************************************/
 static void player_load(struct player *plr, int plrno,
-                       struct section_file *file)
+                       struct section_file *file,
+                       char** improvement_order,
+                       int improvement_order_size)
 {
   int i, j, x, y, ncities, c_s;
   const char *p;
@@ -1340,7 +1372,7 @@
     int nat_y = secfile_lookup_int(file, "player%d.c%d.y", plrno, i);
     int map_x, map_y;
     const char* name;
-    int id;
+    int id, k;
 
     native_to_map_pos(&map_x, &map_y, nat_x, nat_y);
     pcity = create_city_virtual(plr, map_x, map_y,
@@ -1524,18 +1556,35 @@
       }
     }
 
-    p=secfile_lookup_str(file, "player%d.c%d.improvements", plrno, i);
-
     /* Initialise list of improvements with City- and Building-wide
        equiv_ranges */
     improvement_status_init(pcity->improvements,
                            ARRAY_SIZE(pcity->improvements));
 
-    impr_type_iterate(x) {
-      if (*p != '\0' && *p++=='1') {
-        city_add_improvement(pcity,x);
+    p = secfile_lookup_str_default(file, NULL, "player%d.c%d.improvements_new",
+                                   plrno, i);
+    if (!p) {
+      /* old savegames */
+      p = secfile_lookup_str(file, "player%d.c%d.improvements", plrno, i);
+      for (k = 0; *p; k++, p++) {
+        if (*p == '1') {
+         name = old_impr_type_name(k);
+         id = find_improvement_by_name_orig(name);
+         if (id != -1) {
+           city_add_improvement(pcity, id);
+         }
+       }
       }
-    } impr_type_iterate_end;
+    } else {
+      for (k = 0; *p && k < improvement_order_size; k++, p++) {
+        if (*p == '1') {
+         id = find_improvement_by_name_orig(improvement_order[k]);
+         if (id != -1) {
+           city_add_improvement(pcity, id);
+         }
+       }
+      }
+    }
 
     init_worklist(&pcity->worklist);
     if (has_capability("worklists2", savefile_options)) {
@@ -2116,11 +2165,25 @@
                          "player%d.c%d.currently_building_name", plrno, i);
     }
 
+    /* 1.14 servers depend on improvement order in ruleset. Here we
+     * are trying to simulate 1.14.1 default order
+     */
+    init_old_improvement_bitvector(buf);
+    impr_type_iterate(id) {
+      if (pcity->improvements[id] != I_NONE) {
+        add_improvement_into_old_bitvector(buf, id);
+      }
+    } impr_type_iterate_end;
+    secfile_insert_str(file, buf, "player%d.c%d.improvements", plrno, i);
+
+    /* Save improvement list as bitvector. Note that improvement order
+     * is saved in savefile.improvement_order.
+     */
     impr_type_iterate(id) {
       buf[id] = (pcity->improvements[id] != I_NONE) ? '1' : '0';
     } impr_type_iterate_end;
     buf[game.num_impr_types] = '\0';
-    secfile_insert_str(file, buf, "player%d.c%d.improvements", plrno, i);
+    secfile_insert_str(file, buf, "player%d.c%d.improvements_new", plrno, i);  
  
 
     worklist_save(file, "player%d.c%d", plrno, i, &pcity->worklist);
 
@@ -2333,16 +2396,23 @@
 ***************************************************************/
 void game_load(struct section_file *file)
 {
-  int i;
+  int i, k, id;
   enum server_states tmp_server_state;
   char *savefile_options;
   const char *string;
+  char** improvement_order = NULL;
+  int improvement_order_size = 0;
+  const char* name;
 
   game.version = secfile_lookup_int_default(file, 0, "game.version");
   tmp_server_state = (enum server_states)
     secfile_lookup_int_default(file, RUN_GAME_STATE, "game.server_state");
 
   savefile_options = secfile_lookup_str(file, "savefile.options");
+  if (has_capability("improvement_order", savefile_options)) {
+    improvement_order = secfile_lookup_str_vec(file, &improvement_order_size,
+                                               "savefile.improvement_order");
+  }
 
   /* we require at least version 1.9.0 */
   if (10900 > game.version) {
@@ -2677,23 +2747,39 @@
 
   if (!game.is_new_game) {
     /* destroyed wonders: */
-    string = secfile_lookup_str_default(file, "", "game.destroyed_wonders");
-    impr_type_iterate(i) {
-      if (string[i] == '\0') {
-       goto out;
+    string = secfile_lookup_str_default(file, NULL,
+                                        "game.destroyed_wonders_new");
+    if (!string) {
+      /* old savegames */
+      string = secfile_lookup_str_default(file, "",
+                                          "game.destroyed_wonders");
+      for (k = 0; *string; k++, string++) {
+        if (*string == '1') {
+         name = old_impr_type_name(k);
+         id = find_improvement_by_name_orig(name);
+         if (id != -1) {
+           game.global_wonders[id] = -1;
+         }
+       }
       }
-      if (string[i] == '1') {
-       game.global_wonders[i] = -1; /* destroyed! */
+    } else {
+      for (k = 0; *string && k < improvement_order_size; k++, string++) {
+        if (*string == '1') {
+         id = find_improvement_by_name_orig(improvement_order[k]);
+         if (id != -1) {
+            game.global_wonders[id] = -1;
+         }
+       }
       }
-    } impr_type_iterate_end;
-  out:
+    }
 
     /* This is done after continents are assigned, but before effects 
      * are added. */
     allot_island_improvs();
 
     for(i=0; i<game.nplayers; i++) {
-      player_load(&game.players[i], i, file); 
+      player_load(&game.players[i], i, file, improvement_order,
+                  improvement_order_size); 
     }
 
     cities_iterate(pcity) {
@@ -2831,7 +2917,19 @@
     }
   }
   secfile_insert_str(file, options, "savefile.options");
-
+  /* Save improvement order in savegame, so we are not dependent on
+   * ruleset order.
+   * If the game isn't started improvements aren't loaded
+   * so we can not save the order.
+   */
+  if (game.num_impr_types > 0) {
+    const char* buf[game.num_impr_types];
+    impr_type_iterate(id) {
+      buf[id] = get_improvement_name_orig(id);
+    } impr_type_iterate_end;
+    secfile_insert_str_vec(file, buf, game.num_impr_types,
+                           "savefile.improvement_order");
+  }
   secfile_insert_int(file, game.gold, "game.gold");
   secfile_insert_int(file, game.tech, "game.tech");
   secfile_insert_int(file, game.skill_level, "game.skill_level");
@@ -2952,17 +3050,31 @@
 
   secfile_insert_bool(file, game.save_options.save_players, 
"game.save_players");
   if (game.save_options.save_players) {
-    /* destroyed wonders: */
-    impr_type_iterate(i) {
-      if (is_wonder(i) && game.global_wonders[i]!=0
-         && !find_city_by_id(game.global_wonders[i])) {
-       temp[i] = '1';
+    /* 1.14 servers depend on improvement order in ruleset. Here we
+     * are trying to simulate 1.14.1 default order
+     */
+    init_old_improvement_bitvector(temp);
+    impr_type_iterate(id) {
+      if (is_wonder(id) && game.global_wonders[id]!=0
+         && !find_city_by_id(game.global_wonders[id])) {
+        add_improvement_into_old_bitvector(temp, id);
+      } 
+    } impr_type_iterate_end;
+    secfile_insert_str(file, temp, "game.destroyed_wonders");
+    
+    /* Save destroyed wonders as bitvector. Note that improvement order
+     * is saved in savefile.improvement_order
+     */
+    impr_type_iterate(id) {
+      if (is_wonder(id) && game.global_wonders[id]!=0
+         && !find_city_by_id(game.global_wonders[id])) {
+       temp[id] = '1';
       } else {
-       temp[i] = '0';
+        temp[id] = '0';
       }
     } impr_type_iterate_end;
     temp[game.num_impr_types] = '\0';
-    secfile_insert_str(file, temp, "game.destroyed_wonders");
+    secfile_insert_str(file, temp, "game.destroyed_wonders_new");
 
     calc_unit_ordering();
 
diff -ur -Xdiff_ignore freeorig/utility/registry.c freeciv/utility/registry.c
--- freeorig/utility/registry.c 2004-06-26 01:43:01.000000000 +0200
+++ freeciv/utility/registry.c  2004-07-21 08:54:53.000000000 +0200
@@ -174,13 +174,16 @@
 #define SPECVEC_TAG astring
 #include "specvec.h"
 
-/* An 'entry' is a single value, either a string or integer;
- * Whether string or int is determined by whether svalue is NULL.
+/* An 'entry' is a string, integer or string vector;
+ * Whether it is string or int or string vector is determined by whether
+ * svalue/vec_values is NULL.
  */
 struct entry {
   char *name;                  /* name, not including section prefix */
   int  ivalue;                 /* value if integer */
   char *svalue;                        /* value if string (in sbuffer) */
+  char **vec_values;           /* string vector values */
+  int dim;                     /* vector's size */
   int  used;                   /* number of times entry looked up */
   char *comment;                /* comment, may be NULL */
 };
@@ -634,6 +637,7 @@
 
   struct genlist_link *ent_iter, *save_iter, *col_iter;
   struct entry *pentry, *col_pentry;
+  int i;
 
   if (!fs)
     return FALSE;
@@ -745,11 +749,19 @@
        if(!pentry) break;
       }
       if(!pentry) break;
-
-      if(pentry->svalue)
+      
+      if (pentry->vec_values) {
+        fz_fprintf(fs, "%s=\"%s\"", pentry->name,
+                  moutstr(pentry->vec_values[0]));
+       for (i = 1; i < pentry->dim; i++) {
+         fz_fprintf(fs, ", \"%s\"", moutstr(pentry->vec_values[i]));
+       }
+      } else if (pentry->svalue) {
        fz_fprintf(fs, "%s=\"%s\"", pentry->name, moutstr(pentry->svalue));
-      else
+      } else {
        fz_fprintf(fs, "%s=%d", pentry->name, pentry->ivalue);
+      }
+      
       if (pentry->comment) {
        fz_fprintf(fs, "  # %s\n", pentry->comment);
       } else {
@@ -852,6 +864,8 @@
 
   pentry->ivalue=val;
   pentry->svalue = NULL;
+  pentry->vec_values = NULL;
+  pentry->dim = 0;
   pentry->comment = NULL;
 }
 
@@ -874,6 +888,8 @@
 
   pentry->ivalue = val;
   pentry->svalue = NULL;
+  pentry->vec_values = NULL;
+  pentry->dim = 0;
   pentry->comment = sbuf_strdup(my_section_file->sb, comment);
 }
 
@@ -901,6 +917,8 @@
 
   pentry->ivalue = val ? 1 : 0;
   pentry->svalue = NULL;
+  pentry->vec_values = NULL;
+  pentry->dim = 0;
   pentry->comment = NULL;
 }
 
@@ -920,6 +938,8 @@
 
   pentry = section_file_insert_internal(my_section_file, buf);
   pentry->svalue = sbuf_strdup(my_section_file->sb, sval);
+  pentry->vec_values = NULL;
+  pentry->dim = 0;
   pentry->comment = NULL;
 }
 
@@ -940,10 +960,46 @@
 
   pentry = section_file_insert_internal(my_section_file, buf);
   pentry->svalue = sbuf_strdup(my_section_file->sb, sval);
+  pentry->vec_values = NULL;
+  pentry->dim = 0;
   pentry->comment = sbuf_strdup(my_section_file->sb, comment);
 }
 
 /**************************************************************************
+  Insert string vector into section_file. It will be writen out as:
+  name = "value1", "value2", "value3"
+  This function is little tricky, because values inserted here can't
+  be recovered by secfile_lookup_str_vec. Luckily we never use section_file
+  for both reading and writing.
+**************************************************************************/
+void secfile_insert_str_vec(struct section_file *my_section_file,
+                           const char **values, int dim,
+                           const char *path, ...)
+{
+  struct entry *pentry;
+  char buf[MAX_LEN_BUFFER];
+  int i;
+  va_list ap;
+
+  va_start(ap, path);
+  my_vsnprintf(buf, sizeof(buf), path, ap);
+  va_end(ap);
+
+  assert(dim > 0);
+  
+  pentry = section_file_insert_internal(my_section_file, buf);
+  pentry->dim = dim;
+  pentry->vec_values = sbuf_malloc(my_section_file->sb,
+                                   sizeof(char*) * dim);
+  for (i = 0; i < dim; i++) {
+    pentry->vec_values[i] = sbuf_strdup(my_section_file->sb, values[i]);
+  }
+                                
+  pentry->svalue = NULL;
+  pentry->comment = NULL;
+}
+
+/**************************************************************************
 ...
 **************************************************************************/
 int secfile_lookup_int(struct section_file *my_section_file, 
diff -ur -Xdiff_ignore freeorig/utility/registry.h freeciv/utility/registry.h
--- freeorig/utility/registry.h 2004-04-16 19:08:27.000000000 +0200
+++ freeciv/utility/registry.h  2004-07-17 11:40:29.000000000 +0200
@@ -60,7 +60,10 @@
                                char *sval, const char *const comment,
                                const char *path, ...)
                                 fc__attribute((format (printf, 4, 5)));
-
+void secfile_insert_str_vec(struct section_file *my_section_file, 
+                           const char **values, int dim,
+                           const char *path, ...)
+                            fc__attribute((format (printf, 4, 5)));
 bool section_file_lookup(struct section_file *my_section_file, 
                        const char *path, ...)
                         fc__attribute((format (printf, 2, 3)));



[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#9456) Improvements' lists in savegames, Mateusz Stefek <=