Complete.Org: Mailing Lists: Archives: freeciv-dev: June 2004:
[Freeciv-Dev] (PR#9123) Save unit types by names
Home

[Freeciv-Dev] (PR#9123) Save unit types by names

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [Freeciv-Dev] (PR#9123) Save unit types by names
From: "Mateusz Stefek" <mstefek@xxxxxxxxx>
Date: Sun, 27 Jun 2004 01:05:12 -0700
Reply-to: rt@xxxxxxxxxxx

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

After adding worker unit Diplomats from old savegames became nukes!!
And generally all units are read wrong.

To avoid such problems in the future I wrote a patch which saves unit  
types by name. Old field "type" is still supported for backward  
compatibility.

Same thing is needed for the following:
-City improvements
-Worklists
-research & techs

I'll try to implement this
--
mateusz
diff -ur -Xdiff_ignore freeorig/common/unittype.c freeciv/common/unittype.c
--- freeorig/common/unittype.c  2004-05-11 08:26:52.000000000 +0200
+++ freeciv/common/unittype.c   2004-06-26 16:55:16.000000000 +0200
@@ -239,6 +239,13 @@
 /**************************************************************************
 ...
 **************************************************************************/
+const char *unit_name_orig(Unit_Type_id id)
+{
+  return (unit_types[id].name_orig);
+}
+/**************************************************************************
+...
+**************************************************************************/
 const char *get_unit_name(Unit_Type_id id)
 {
   struct unit_type *ptype;
@@ -363,6 +370,20 @@
 }
 
 /**************************************************************************
+Does a linear search of unit_types[].name_orig
+Returns U_LAST if none match.
+**************************************************************************/
+Unit_Type_id find_unit_type_by_name_orig(const char *s)
+{
+  unit_type_iterate(i) {
+    if (strcmp(unit_types[i].name_orig, s)==0)
+      return i;
+  } unit_type_iterate_end;
+
+  return U_LAST;
+}
+
+/**************************************************************************
   Convert unit_move_type names to enum; case insensitive;
   returns 0 if can't match.
 **************************************************************************/
diff -ur -Xdiff_ignore freeorig/common/unittype.h freeciv/common/unittype.h
--- freeorig/common/unittype.h  2004-04-15 17:14:06.000000000 +0200
+++ freeciv/common/unittype.h   2004-06-26 16:55:53.000000000 +0200
@@ -238,6 +238,7 @@
 int unit_pop_value(Unit_Type_id id);
 
 const char *unit_name(Unit_Type_id id);
+const char *unit_name_orig(Unit_Type_id id);
 const char *unit_class_name(Unit_Class_id id);
 
 const char *get_unit_name(Unit_Type_id id);
@@ -253,6 +254,7 @@
                       const Unit_Type_id from, const Unit_Type_id to);
 
 Unit_Type_id find_unit_type_by_name(const char *s);
+Unit_Type_id find_unit_type_by_name_orig(const char *s);
 
 enum unit_move_type unit_move_type_from_str(const char *s);
 Unit_Class_id unit_class_from_str(const char *s);
diff -ur -Xdiff_ignore freeorig/server/savegame.c freeciv/server/savegame.c
--- freeorig/server/savegame.c  2004-06-26 15:08:32.000000000 +0200
+++ freeciv/server/savegame.c   2004-06-26 17:38:52.000000000 +0200
@@ -181,6 +181,8 @@
 static const char hex_chars[] = "0123456789abcdef";
 static const char terrain_chars[] = "adfghjm prstu";
 
+static void load_player_units(struct player *plr, int plrno,
+                       struct section_file *file);
 /***************************************************************
 This returns an ascii hex value of the given half-byte of the binary
 integer. See ascii_hex2bin().
@@ -676,10 +678,9 @@
 static void player_load(struct player *plr, int plrno,
                        struct section_file *file)
 {
-  int i, j, x, y, nunits, ncities, c_s;
+  int i, j, x, y, ncities, c_s;
   const char *p;
   char *savefile_options = secfile_lookup_str(file, "savefile.options");
-  enum unit_activity activity;
   struct ai_data *ai;
 
   server_player_init(plr, TRUE);
@@ -1130,19 +1131,183 @@
     city_list_insert_back(&plr->cities, pcity);
   }
 
+  load_player_units(plr, plrno, file);
+
+  if (section_file_lookup(file, "player%d.attribute_v2_block_length", plrno)) {
+    int raw_length1, raw_length2, part_nr, parts;
+    size_t quoted_length;
+    char *quoted;
+
+    raw_length1 =
+       secfile_lookup_int(file, "player%d.attribute_v2_block_length", plrno);
+    if (plr->attribute_block.data) {
+      free(plr->attribute_block.data);
+      plr->attribute_block.data = NULL;
+    }
+    plr->attribute_block.data = fc_malloc(raw_length1);
+    plr->attribute_block.length = raw_length1;
+
+    quoted_length = secfile_lookup_int
+       (file, "player%d.attribute_v2_block_length_quoted", plrno);
+    quoted = fc_malloc(quoted_length + 1);
+    quoted[0] = 0;
+
+    parts =
+       secfile_lookup_int(file, "player%d.attribute_v2_block_parts", plrno);
+
+    for (part_nr = 0; part_nr < parts; part_nr++) {
+      char *current = secfile_lookup_str(file,
+                                        
"player%d.attribute_v2_block_data.part%d",
+                                        plrno, part_nr);
+      if (!current)
+       break;
+      freelog(LOG_DEBUG, "quoted_length=%lu quoted=%lu current=%lu",
+             (unsigned long) quoted_length,
+             (unsigned long) strlen(quoted),
+             (unsigned long) strlen(current));
+      assert(strlen(quoted) + strlen(current) <= quoted_length);
+      strcat(quoted, current);
+    }
+    if (quoted_length != strlen(quoted)) {
+      freelog(LOG_NORMAL, "quoted_length=%lu quoted=%lu",
+             (unsigned long) quoted_length,
+             (unsigned long) strlen(quoted));
+      assert(0);
+    }
+
+    raw_length2 =
+       unquote_block(quoted,
+                     plr->attribute_block.data,
+                     plr->attribute_block.length);
+    assert(raw_length1 == raw_length2);
+    free(quoted);
+  }
+}
+
+/* old (1.14.1) unit order in default/civ2/history ruleset */
+const char* old_default_unit_types[] = {
+  "Settlers",  "Engineers",    "Warriors",     "Phalanx",
+  "Archers",   "Legion",       "Pikeman",      "Musketeers",
+  "Fanatics",  "Partisan",     "Alpine Troops","Riflemen",
+  "Marines",   "Paratroopers", "Mech. Inf.",   "Horsemen",
+  "Chariot",   "Elephants",    "Crusaders",    "Knights",
+  "Dragoons",  "Cavalary",     "Armor",        "Catapult",
+  "Cannon",    "Artillery",    "Howitzer",     "Fighter",
+  "Bomber",    "Helicopter",   "Stealth Fighter", "Stealth Bomber",
+  "Trireme",   "Caravel",      "Galleon",      "Frigate",
+  "Ironclad",  "Destroyer",    "Cruiser",      "AEGIS Cruiser",
+  "Battleship",        "Submarine",    "Carrier",      "Transport",
+  "Cruise Missile", "Nuclear", "Diplomat",     "Spy",
+  "Caravan",   "Freight",      "Explorer",     "Barbarian Leader",
+  "AWACS"
+};
+
+/* old (1.14.1) unit order in civ1 ruleset */
+const char* old_civ1_unit_types[] = {
+  "Settlers",  "Engineers",    "Militia",      "Phalanx",
+  "Archers",   "Legion",       "Pikeman",      "Musketeers",
+  "Fanatics",  "Partisan",     "Alpine Troops","Riflemen",
+  "Marines",   "Paratroopers", "Mech. Inf.",   "Cavalary",
+  "Chariot",   "Elephants",    "Crusaders",    "Knights",
+  "Dragoons",  "Civ2-Cavalary","Armor",        "Catapult",
+  "Cannon",    "Civ2-Artillery","Artillery",   "Fighter",
+  "Bomber",    "Helicopter",   "Stealth Fighter", "Stealth Bomber",
+  "Trireme",   "Sail",         "Galleon",      "Frigate",
+  "Ironclad",  "Destroyer",    "Cruiser",      "AEGIS Cruiser",
+  "Battleship",        "Submarine",    "Carrier",      "Transport",
+  "Cruise Missile", "Nuclear", "Diplomat",     "Spy",
+  "Caravan",   "Freight",      "Explorer",     "Barbarian Leader",
+};
+
+/***************************************************************
+  Nowadays unit types are saved by name, but old servers
+  need unit_type id. This function tries to find correct id 
+  for unit type. It is used when unit is saved.
+***************************************************************/
+static int old_type_id(struct unit* punit)
+{
+  const char** T;
+  int k, i;
+  if (strcmp(game.rulesetdir, "civ1") == 0) {
+    T = old_civ1_unit_types;
+    k = ARRAY_SIZE(old_civ1_unit_types);
+  } else {
+    T = old_default_unit_types;
+    k = ARRAY_SIZE(old_default_unit_types);
+  }
+  for (i = 0; i < k; i++) {
+    if (strcmp(unit_name_orig(punit->type), T[i]) == 0) {
+      return i;
+    }
+  }
+  /* It's a new unit. Savegame cannot be backward compatible so we can
+   * return anything */
+  return punit->type;
+}
+
+/***************************************************************
+ ...
+***************************************************************/
+static void load_player_units(struct player *plr, int plrno,
+                       struct section_file *file)
+{
+  int nunits, i, j;
+  enum unit_activity activity;
+  char *savefile_options = secfile_lookup_str(file, "savefile.options");
+
   unit_list_init(&plr->units);
   nunits=secfile_lookup_int(file, "player%d.nunits", plrno);
   if (!plr->is_alive && nunits > 0) {
     nunits = 0; /* Some old savegames may be buggy. */
   }
-
-  for(i=0; i<nunits; i++) { /* read the units */
+  
+  for(i = 0; i < nunits; i++) {
     struct unit *punit;
     struct city *pcity;
     int nat_x, nat_y;
-
+    const char* type_name;
+    Unit_Type_id type;
+    
+    type_name = secfile_lookup_str_default(file, NULL, 
+                                           "player%d.u%d.type_by_name",
+                                          plrno, i);
+    if (!type_name) {
+      /* before 1.15.0 unit types used to be saved by id */
+      int t = secfile_lookup_int(file, "player%d.u%d.type",
+                             plrno, i);
+      if (t < 0) {
+        freelog(LOG_ERROR, _("Wrong player%d.u%d.type value (%d)"),
+               plrno, i, t);
+       exit(EXIT_FAILURE);
+      }
+      /* There was the same order in rulesets but different names.
+       * Warriors in civ1 are called Milita */
+      if (strcmp(game.rulesetdir, "civ1") == 0) {
+        if (t >= ARRAY_SIZE(old_civ1_unit_types)) {
+          freelog(LOG_ERROR, _("Wrong player%d.u%d.type value (%d)"),
+                 plrno, i, t);
+         exit(EXIT_FAILURE);
+       }
+       type_name = old_civ1_unit_types[t];
+      } else {
+        if (t >= ARRAY_SIZE(old_default_unit_types)) {
+         freelog(LOG_ERROR, _("Wrong player%d.u%d.type value (%d)"),
+                 plrno, i, t);
+         exit(EXIT_FAILURE);
+       }
+       type_name = old_default_unit_types[t];
+      }
+    }
+    
+    type = find_unit_type_by_name_orig(type_name);
+    if (type == U_LAST) {
+      freelog(LOG_ERROR, _("Unknown unit type '%s' in player%d section"),
+              type_name, plrno);
+              exit(EXIT_FAILURE);
+    }
+    
     punit = create_unit_virtual(plr, NULL, 
-                  secfile_lookup_int(file, "player%d.u%d.type", plrno, i),
+                  type,
                   secfile_lookup_int(file, "player%d.u%d.veteran", plrno, i));
     punit->id=secfile_lookup_int(file, "player%d.u%d.id", plrno, i);
     alloc_id(punit->id);
@@ -1282,56 +1447,6 @@
 
     unit_list_insert(&map_get_tile(punit->x, punit->y)->units, punit);
   }
-
-  if (section_file_lookup(file, "player%d.attribute_v2_block_length", plrno)) {
-    int raw_length1, raw_length2, part_nr, parts;
-    size_t quoted_length;
-    char *quoted;
-
-    raw_length1 =
-       secfile_lookup_int(file, "player%d.attribute_v2_block_length", plrno);
-    if (plr->attribute_block.data) {
-      free(plr->attribute_block.data);
-      plr->attribute_block.data = NULL;
-    }
-    plr->attribute_block.data = fc_malloc(raw_length1);
-    plr->attribute_block.length = raw_length1;
-
-    quoted_length = secfile_lookup_int
-       (file, "player%d.attribute_v2_block_length_quoted", plrno);
-    quoted = fc_malloc(quoted_length + 1);
-    quoted[0] = 0;
-
-    parts =
-       secfile_lookup_int(file, "player%d.attribute_v2_block_parts", plrno);
-
-    for (part_nr = 0; part_nr < parts; part_nr++) {
-      char *current = secfile_lookup_str(file,
-                                        
"player%d.attribute_v2_block_data.part%d",
-                                        plrno, part_nr);
-      if (!current)
-       break;
-      freelog(LOG_DEBUG, "quoted_length=%lu quoted=%lu current=%lu",
-             (unsigned long) quoted_length,
-             (unsigned long) strlen(quoted),
-             (unsigned long) strlen(current));
-      assert(strlen(quoted) + strlen(current) <= quoted_length);
-      strcat(quoted, current);
-    }
-    if (quoted_length != strlen(quoted)) {
-      freelog(LOG_NORMAL, "quoted_length=%lu quoted=%lu",
-             (unsigned long) quoted_length,
-             (unsigned long) strlen(quoted));
-      assert(0);
-    }
-
-    raw_length2 =
-       unquote_block(quoted,
-                     plr->attribute_block.data,
-                     plr->attribute_block.length);
-    assert(raw_length1 == raw_length2);
-    free(quoted);
-  }
 }
 
 /********************************************************************** 
@@ -1680,8 +1795,12 @@
     secfile_insert_int(file, punit->hp, "player%d.u%d.hp", plrno, i);
     secfile_insert_int(file, punit->homecity, "player%d.u%d.homecity",
                                plrno, i);
-    secfile_insert_int(file, punit->type, "player%d.u%d.type",
+    /* .type is actually kept only for backward compatibility */
+    secfile_insert_int(file, old_type_id(punit), "player%d.u%d.type",
                                plrno, i);
+    secfile_insert_str(file, unit_name_orig(punit->type),
+                       "player%d.u%d.type_by_name",
+                      plrno, i);
     secfile_insert_int(file, punit->activity, "player%d.u%d.activity",
                                plrno, i);
     secfile_insert_int(file, punit->activity_count, 
@@ -1978,7 +2097,6 @@
   }
 }
 
-
 /***************************************************************
  Assign values to ord_city and ord_map for each unit, so the
  values can be saved.
Tylko w freeciv/server: testtest
Tylko w freeciv/server: testtest.gz
Tylko w freeciv/server: testtesttest

[Prev in Thread] Current Thread [Next in Thread]