Project

General

Profile

Bug #834 ยป 0021-Drop-dev-save-compat.patch

Marko Lindqvist, 09/07/2024 02:36 AM

View differences:

configure.ac
[ METAINFODIR=${withval} ], [ METAINFODIR="\$(prefix)/share/metainfo" ])
AC_SUBST([METAINFODIR])
dnl try to support this development version's previous save games formats
AC_ARG_ENABLE([dev-save-compat],
AS_HELP_STRING([--enable-dev-save-compat=yes/no],
[enable development version save game compatibility]),
[case "${enableval}" in
yes) dev_save_compat=1 ;;
no) dev_save_compat=0 ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-dev-save-compat]) ;;
esac],
[dev_save_compat=$IS_DEVEL_VERSION])
AS_IF([test $dev_save_compat != 0],
[AC_DEFINE([FREECIV_DEV_SAVE_COMPAT], [1],
[Development version save game compatibility])
AC_DEFINE([FREECIV_DEV_SAVE_COMPAT_3_2], [1],
[Development version save game compatibility - 3.2 development])])
AC_ARG_ENABLE([patient-connect],
AS_HELP_STRING([--enable-patient-connect=yes/no],
[enable client to be very patient in connecting spawned server]),
server/savegame/savecompat.c
static void compat_post_load_030100(struct loaddata *loading,
enum sgf_version format_class);
#ifdef FREECIV_DEV_SAVE_COMPAT
static void compat_load_dev(struct loaddata *loading);
static void compat_post_load_dev(struct loaddata *loading);
#endif /* FREECIV_DEV_SAVE_COMPAT */
typedef void (*load_version_func_t) (struct loaddata *loading, enum sgf_version format_class);
struct compatibility {
......
compat[i].load(loading, format_class);
}
}
#ifdef FREECIV_DEV_SAVE_COMPAT
if (loading->version == compat[compat_current].version) {
compat_load_dev(loading);
}
#endif /* FREECIV_DEV_SAVE_COMPAT */
}
/************************************************************************//**
......
compat[i].post_load(loading, format_class);
}
}
#ifdef FREECIV_DEV_SAVE_COMPAT
if (loading->version == compat[compat_current].version) {
compat_post_load_dev(loading);
}
#endif /* FREECIV_DEV_SAVE_COMPAT */
}
/************************************************************************//**
......
}
}
/************************************************************************//**
Translate savegame secfile data from earlier development version format
to current one.
****************************************************************************/
#ifdef FREECIV_DEV_SAVE_COMPAT
static void compat_load_dev(struct loaddata *loading)
{
int game_version;
/* Check status and return if not OK (sg_success FALSE). */
sg_check_ret();
log_debug("Upgrading data between development revisions");
if (!secfile_lookup_int(loading->file, &game_version, "scenario.game_version")) {
game_version = 2060000;
}
#ifdef FREECIV_DEV_SAVE_COMPAT_3_2
if (game_version < 3019100) {
/* Before version number bump to 3.1.91 */
int i;
int count;
/* Older savegames had a bug that got_tech_multi was not saved.
* Insert the entry to such savegames */
/* May be unsaved (e.g. scenario case). */
count = secfile_lookup_int_default(loading->file, 0, "research.count");
for (i = 0; i < count; i++) {
if (secfile_entry_lookup(loading->file,
"research.r%d.got_tech_multi", i) == NULL) {
/* Default to FALSE */
secfile_insert_bool(loading->file, FALSE,
"research.r%d.got_tech_multi", i);
}
}
} /* Version < 3.1.91 */
if (game_version < 3019200) {
/* Before version number bump to 3.1.92, August 2022 */
int set_count;
bool gamestart_valid = FALSE;
bool al_set_already = FALSE;
bool wrap_set_already = FALSE;
const char *level;
bool count_changed = FALSE;
bool topo_defined = FALSE;
char wrap[100];
char wrap_gs[100];
if (secfile_lookup_int(loading->file, &set_count, "settings.set_count")) {
int i;
gamestart_valid
= secfile_lookup_bool_default(loading->file, FALSE,
"settings.gamestart_valid");
for (i = 0; i < set_count; i++) {
const char *old_name
= secfile_lookup_str(loading->file, "settings.set%d.name", i);
const char *name;
if (!old_name) {
continue;
}
name = setcompat_S3_2_name_from_S3_1(old_name);
if (fc_strcasecmp(old_name, name)) {
/* Setting's name changed */
secfile_replace_str(loading->file, name, "settings.set%d.name", i);
}
if (!fc_strcasecmp("compresstype", name)) {
const char *val = secfile_lookup_str(loading->file,
"settings.set%d.value", i);
if (!fc_strcasecmp(val, "BZIP2")) {
#ifdef FREECIV_HAVE_LIBZSTD
secfile_replace_str(loading->file, "ZSTD",
"settings.set%d.value", i);
#elif FREECIV_HAVE_LIBLZMA
secfile_replace_str(loading->file, "XZ",
"settings.set%d.value", i);
#elif FREECIV_HAVE_LIBZ
secfile_replace_str(loading->file, "LIBZ",
"settings.set%d.value", i);
#else
secfile_replace_str(loading->file, "PLAIN",
"settings.set%d.value", i);
#endif
}
if (gamestart_valid) {
val = secfile_lookup_str(loading->file,
"settings.set%d.gamestart", i);
if (!fc_strcasecmp(val, "BZIP2")) {
#ifdef FREECIV_HAVE_LIBZSTD
secfile_replace_str(loading->file, "ZSTD",
"settings.set%d.gamestart", i);
#elif FREECIV_HAVE_LIBLZMA
secfile_replace_str(loading->file, "XZ",
"settings.set%d.gamestart", i);
#elif FREECIV_HAVE_LIBZ
secfile_replace_str(loading->file, "LIBZ",
"settings.set%d.gamestart", i);
#else
secfile_replace_str(loading->file, "PLAIN",
"settings.set%d.gamestart", i);
#endif
}
}
} else if (!fc_strcasecmp("ailevel", name)) {
al_set_already = TRUE;
} else if (!fc_strcasecmp("topology", name)) {
struct setting *pset = setting_by_name(name);
struct sf_cb_data info = { pset, TRUE };
int val;
if (secfile_lookup_enum_data(loading->file, &val, TRUE,
setting_bitwise_secfile_str, &info,
"settings.set%d.value", i)) {
bool topo_changed = TRUE;
if (val & TF_OLD_WRAPX) {
if (val & TF_OLD_WRAPY) {
fc_strlcpy(wrap, "WrapX|WrapY", sizeof(wrap));
} else {
fc_strlcpy(wrap, "WrapX", sizeof(wrap));
}
} else if (val & TF_OLD_WRAPY) {
fc_strlcpy(wrap, "WrapY", sizeof(wrap));
} else {
fc_strlcpy(wrap, "", sizeof(wrap));
topo_changed = FALSE;
}
if (topo_changed) {
char buf[100];
if (val & TF_ISO) {
if (val & TF_HEX) {
setting_bitwise_set(pset, "ISO|HEX", NULL, NULL, 0);
} else {
setting_bitwise_set(pset, "ISO", NULL, NULL, 0);
}
} else if (val & TF_HEX) {
setting_bitwise_set(pset, "HEX", NULL, NULL, 0);
} else {
setting_bitwise_set(pset, "", NULL, NULL, 0);
}
setting_value_name(pset, FALSE, buf, sizeof(buf));
secfile_replace_str(loading->file, buf,
"settings.set%d.value", i);
}
if (gamestart_valid) {
if (secfile_lookup_enum_data(loading->file, &val, TRUE,
setting_bitwise_secfile_str, &info,
"settings.set%d.gamestart", i)) {
topo_changed = TRUE;
if (val & TF_OLD_WRAPX) {
if (val & TF_OLD_WRAPY) {
fc_strlcpy(wrap_gs, "WrapX|WrapY", sizeof(wrap));
} else {
fc_strlcpy(wrap_gs, "WrapX", sizeof(wrap));
}
} else if (val & TF_OLD_WRAPY) {
fc_strlcpy(wrap_gs, "WrapY", sizeof(wrap));
} else {
fc_strlcpy(wrap_gs, "", sizeof(wrap));
topo_changed = FALSE;
}
if (topo_changed) {
char buf[100];
if (val & TF_ISO) {
if (val & TF_HEX) {
setting_bitwise_set(pset, "ISO|HEX", NULL, NULL, 0);
} else {
setting_bitwise_set(pset, "ISO", NULL, NULL, 0);
}
} else if (val & TF_HEX) {
setting_bitwise_set(pset, "HEX", NULL, NULL, 0);
} else {
setting_bitwise_set(pset, "", NULL, NULL, 0);
}
setting_value_name(pset, FALSE, buf, sizeof(buf));
secfile_replace_str(loading->file, buf,
"settings.set%d.gamestart", i);
}
}
}
topo_defined = TRUE;
}
} else if (!fc_strcasecmp("wrap", name)) {
wrap_set_already = TRUE;
}
}
}
if (!al_set_already) {
level = secfile_lookup_str_default(loading->file, NULL, "game.level");
if (level == NULL) {
/* Assume that this was a new format savegame after all,
* setting just has not been explicitly saved for containing default value. */
al_set_already = TRUE;
}
}
if (!al_set_already) {
/* Turn old AI level field to a setting. */
enum ai_level lvl;
if (level != NULL && !fc_strcasecmp("Handicapped", level)) {
/* Up to freeciv-3.1 Restricted AI level was known as Handicapped */
lvl = AI_LEVEL_RESTRICTED;
} else {
lvl = ai_level_by_name(level, fc_strcasecmp);
}
if (!ai_level_is_valid(lvl)) {
log_sg("Invalid AI level \"%s\". "
"Changed to \"%s\".", level,
ai_level_name(GAME_HARDCODED_DEFAULT_SKILL_LEVEL));
lvl = GAME_HARDCODED_DEFAULT_SKILL_LEVEL;
}
secfile_insert_str(loading->file, "ailevel", "settings.set%d.name", set_count);
secfile_insert_enum(loading->file, lvl, ai_level, "settings.set%d.value", set_count);
if (gamestart_valid) {
secfile_insert_enum(loading->file, lvl, ai_level, "settings.set%d.gamestart",
set_count);
}
set_count++;
count_changed = TRUE;
}
if (!wrap_set_already && topo_defined) {
secfile_insert_str(loading->file, "wrap", "settings.set%d.name", set_count);
secfile_insert_str(loading->file, wrap, "settings.set%d.value", set_count);
if (gamestart_valid) {
secfile_insert_str(loading->file, wrap_gs, "settings.set%d.value", set_count);
}
set_count++;
count_changed = TRUE;
}
if (count_changed) {
secfile_replace_int(loading->file, set_count, "settings.set_count");
}
{
int action_count;
action_count = secfile_lookup_int_default(loading->file, 0,
"savefile.action_size");
if (action_count > 0) {
const char **modname;
const char **savemod;
int j;
const char *dur_name = "Disband Unit Recover";
modname = secfile_lookup_str_vec(loading->file, &loading->action.size,
"savefile.action_vector");
savemod = fc_calloc(action_count, sizeof(*savemod));
for (j = 0; j < action_count; j++) {
if (!fc_strcasecmp("Recycle Unit", modname[j])) {
savemod[j] = dur_name;
} else {
savemod[j] = modname[j];
}
}
secfile_replace_str_vec(loading->file, savemod, action_count,
"savefile.action_vector");
free(savemod);
}
}
player_slots_iterate(pslot) {
int plrno = player_slot_index(pslot);
int wonder_city = secfile_lookup_int_default(loading->file, -1,
"player%d.adv.wonder_city",
plrno);
if (wonder_city < 0) {
/* No wonder_city saved with the new name. Check for the old name */
wonder_city = secfile_lookup_int_default(loading->file, -1,
"player%d.wonder_city",
plrno);
if (wonder_city >= 0) {
secfile_replace_int(loading->file, wonder_city,
"player%d.adv.wonder_city", plrno);
}
}
} player_slots_iterate_end;
} /* Version < 3.1.92 */
if (game_version < 3019300) {
/* Before version number bump to 3.1.93 */
/* Older savegames unnecessarily saved diplstate type order.
* Silence "unused entry" warnings about those. */
{
int dscount = secfile_lookup_int_default(loading->file, 0,
"savefile.diplstate_type_size");
int i;
for (i = 0; i < dscount; i++) {
(void) secfile_entry_lookup(loading->file,
"savefile.diplstate_type_vector,%d", i);
}
}
(void) secfile_entry_lookup(loading->file, "game.hardcoded_counters");
/* Add wl_max_length and orders_max_length entries for players */
{
player_slots_iterate(pslot) {
int plrno = player_slot_index(pslot);
int ncities, nunits;
int cnro, unro;
size_t wlist_max_length = 0;
size_t olist_max_length = 0;
if (secfile_section_lookup(loading->file, "player%d", plrno) == NULL) {
continue;
}
ncities = secfile_lookup_int_default(loading->file, 0,
"player%d.ncities", plrno);
for (cnro = 0; cnro < ncities; cnro++) {
int wl_length = secfile_lookup_int_default(loading->file, 0,
"player%d.c%d.wl_length",
plrno, cnro);
wlist_max_length = MAX(wlist_max_length, wl_length);
if (secfile_entry_lookup(loading->file,
"player%d.c%d.acquire_t",
plrno, cnro) == NULL) {
if (secfile_lookup_int_default(loading->file, plrno,
"player%d.c%d.original",
plrno, cnro) != plrno) {
secfile_insert_int(loading->file, CACQ_CONQUEST,
"player%d.c%d.acquire_t",
plrno, cnro);
} else {
secfile_insert_int(loading->file, CACQ_FOUNDED,
"player%d.c%d.acquire_t",
plrno, cnro);
}
}
if (secfile_entry_lookup(loading->file,
"player%d.c%d.wlcb",
plrno, cnro) == NULL) {
secfile_insert_int(loading->file, WLCB_SMART,
"player%d.c%d.wlcb",
plrno, cnro);
}
}
secfile_insert_int(loading->file, wlist_max_length,
"player%d.wl_max_length", plrno);
nunits = secfile_lookup_int_default(loading->file, 0,
"player%d.nunits", plrno);
for (unro = 0; unro < nunits; unro++) {
int ol_length
= secfile_lookup_int_default(loading->file, 0,
"player%d.u%d.orders_length",
plrno, unro);
olist_max_length = MAX(olist_max_length, ol_length);
}
secfile_insert_int(loading->file, olist_max_length,
"player%d.orders_max_length", plrno);
secfile_insert_int(loading->file, MAX_TRADE_ROUTES_OLD,
"player%d.routes_max_length", plrno);
} player_slots_iterate_end;
}
/* Replace got_tech[_multi] bools on free_bulbs integers. */
{
int count = secfile_lookup_int_default(loading->file, 0, "research.count");
for (int i = 0; i < count; i++) {
bool got_tech = FALSE;
int bulbs = 0;
bool got_tech_multi
= secfile_lookup_bool_default(loading->file, FALSE,
"research.r%d.got_tech_multi", i);
if (secfile_lookup_bool(loading->file, &got_tech,
"research.r%d.got_tech", i)
&& secfile_lookup_int(loading->file, &bulbs,
"research.r%d.bulbs", i)) {
secfile_insert_int(loading->file,
got_tech || got_tech_multi ? bulbs : 0,
"research.r%d.free_bulbs", i);
}
}
}
/* Convert 'alltemperate' and 'singlepole' into 'northlatitude' and
* 'southlatitude' server settings */
{
int i;
int set_count = secfile_lookup_int_default(loading->file, 0,
"settings.set_count");
int alltemperate_idx = -1, singlepole_idx = -1;
for (i = 0; i < set_count; i++) {
const char *name
= secfile_lookup_str(loading->file, "settings.set%d.name", i);
if (!name) {
continue;
}
if (!fc_strcasecmp("northlatitude", name)
|| !fc_strcasecmp("southlatitude", name)) {
/* this savegame is recent enough to already have latitude
* settings ~> no change necessary */
alltemperate_idx = singlepole_idx = -1;
break;
}
if (!fc_strcasecmp("alltemperate", name)) {
alltemperate_idx = i;
} else if (!fc_strcasecmp("singlepole", name)) {
singlepole_idx = i;
}
}
if (alltemperate_idx >= 0 || singlepole_idx >= 0) {
int north_latitude, south_latitude;
int north_idx, south_idx;
bool alltemperate, singlepole;
if (alltemperate_idx < 0
|| !secfile_lookup_bool(loading->file, &alltemperate,
"settings.set%d.value",
alltemperate_idx)) {
/* infer what would've been the ruleset default */
alltemperate = (wld.map.north_latitude == wld.map.south_latitude);
}
if (singlepole_idx < 0
|| !secfile_lookup_bool(loading->file, &singlepole,
"settings.set%d.value",
singlepole_idx)) {
/* infer what would've been the ruleset default */
singlepole = (wld.map.south_latitude >= 0);
}
/* Note: hard-coding 1000-based latitudes here; if MAX_LATITUDE ever
* changes, that'll have to be handled in later migrations anyway */
north_latitude = alltemperate ? 500 : 1000;
south_latitude = alltemperate ? 500 : (singlepole ? 0 : -1000);
/* Replace alltemperate with northlatitude, and singlepole with
* southlatitude. If only one of the two was given, add the other
* at the end. */
north_idx = (alltemperate_idx < 0) ? set_count : alltemperate_idx;
south_idx = (singlepole_idx < 0) ? set_count : singlepole_idx;
secfile_replace_str(loading->file, "northlatitude",
"settings.set%d.name", north_idx);
secfile_replace_int(loading->file, north_latitude,
"settings.set%d.value", north_idx);
secfile_replace_str(loading->file, "southlatitude",
"settings.set%d.name", south_idx);
secfile_replace_int(loading->file, south_latitude,
"settings.set%d.value", south_idx);
if (secfile_lookup_bool_default(loading->file, FALSE,
"settings.gamestart_valid")) {
if (alltemperate_idx < 0
|| !secfile_lookup_bool(loading->file, &alltemperate,
"settings.set%d.gamestart",
alltemperate_idx)) {
alltemperate =
(wld.map.north_latitude == wld.map.south_latitude);
}
if (singlepole_idx < 0
|| !secfile_lookup_bool(loading->file, &singlepole,
"settings.set%d.gamestart",
singlepole_idx)) {
singlepole = (wld.map.south_latitude >= 0);
}
north_latitude = alltemperate ? 500 : 1000;
south_latitude = alltemperate ? 500 : (singlepole ? 0 : -1000);
secfile_replace_int(loading->file, north_latitude,
"settings.set%d.gamestart", north_idx);
secfile_replace_int(loading->file, south_latitude,
"settings.set%d.gamestart", south_idx);
}
if (alltemperate_idx < 0 || singlepole_idx < 0) {
/* only one was given and replaced ~> we added one new entry */
set_count++;
secfile_replace_int(loading->file, set_count,
"settings.set_count");
}
}
}
{
int action_count;
action_count = secfile_lookup_int_default(loading->file, 0,
"savefile.action_size");
if (action_count > 0) {
const char **modname;
const char **savemod;
int j;
const char *dur_name = "Transport Deboard";
modname = secfile_lookup_str_vec(loading->file, &loading->action.size,
"savefile.action_vector");
savemod = fc_calloc(action_count, sizeof(*savemod));
for (j = 0; j < action_count; j++) {
if (!fc_strcasecmp("Transport Alight", modname[j])) {
savemod[j] = dur_name;
} else {
savemod[j] = modname[j];
}
}
secfile_replace_str_vec(loading->file, savemod, action_count,
"savefile.action_vector");
free(savemod);
}
}
{
const char *str = secfile_lookup_str_default(loading->file, NULL,
"savefile.orig_version");
if (str == NULL) {
/* Make sure CURRENTLY running version does not
* end as orig_version when we resave. */
secfile_insert_str(loading->file, "old savegame3, or older",
"savefile.orig_version");
}
}
} /* Version < 3.1.93 */
if (game_version < 3019400) {
/* Before version number bump to 3.1.94, January 2024 */
{
int action_count;
action_count = secfile_lookup_int_default(loading->file, 0,
"savefile.action_size");
if (action_count > 0) {
const char **modname;
const char **savemod;
int j;
const char *clean_name = "Clean";
modname = secfile_lookup_str_vec(loading->file, &loading->action.size,
"savefile.action_vector");
savemod = fc_calloc(action_count, sizeof(*savemod));
for (j = 0; j < action_count; j++) {
if (!fc_strcasecmp("Clean Pollution", modname[j])
|| !fc_strcasecmp("Clean Fallout", modname[j])) {
savemod[j] = clean_name;
} else {
savemod[j] = modname[j];
}
}
secfile_replace_str_vec(loading->file, savemod, action_count,
"savefile.action_vector");
free(savemod);
}
}
{
int activities_count;
activities_count = secfile_lookup_int_default(loading->file, 0,
"savefile.activities_size");
if (activities_count > 0) {
const char **modname;
const char **savemod;
int j;
const char *clean_name = "Clean";
modname = secfile_lookup_str_vec(loading->file, &loading->activities.size,
"savefile.activities_vector");
savemod = fc_calloc(activities_count, sizeof(*savemod));
for (j = 0; j < activities_count; j++) {
if (!fc_strcasecmp("Pollution", modname[j])
|| !fc_strcasecmp("Fallout", modname[j])) {
savemod[j] = clean_name;
} else {
savemod[j] = modname[j];
}
}
secfile_replace_str_vec(loading->file, savemod, activities_count,
"savefile.activities_vector");
free(savemod);
}
}
/* Server setting migration. */
{
int set_count;
if (secfile_lookup_int(loading->file, &set_count, "settings.set_count")) {
bool gamestart_valid = FALSE;
gamestart_valid
= secfile_lookup_bool_default(loading->file, FALSE,
"settings.gamestart_valid");
if (!gamestart_valid) {
int i;
/* Older savegames saved gamestart values even when they were not valid.
* Silence warnings caused by them. */
for (i = 0; i < set_count; i++) {
(void) secfile_entry_lookup(loading->file, "settings.set%d.gamestart", i);
(void) secfile_entry_lookup(loading->file, "settings.set%d.gamesetdef", i);
}
}
}
}
{
player_slots_iterate(pslot) {
int plrno = player_slot_index(pslot);
bool first_city;
if (secfile_section_lookup(loading->file, "player%d", plrno) == NULL) {
continue;
}
first_city = secfile_lookup_bool_default(loading->file, FALSE,
"player%d.got_first_city",
plrno);
if (first_city) {
const char **flag_names = fc_calloc(PLRF_COUNT, sizeof(char *));
int flagcount = 0;
const char **flags_sg;
size_t nval;
int i;
flag_names[flagcount++] = plr_flag_id_name(PLRF_FIRST_CITY);
flags_sg = secfile_lookup_str_vec(loading->file, &nval,
"player%d.flags", plrno);
for (i = 0; i < nval; i++) {
enum plr_flag_id fid = plr_flag_id_by_name(flags_sg[i],
fc_strcasecmp);
flag_names[flagcount++] = plr_flag_id_name(fid);
}
secfile_replace_str_vec(loading->file, flag_names, flagcount,
"player%d.flags", plrno);
free(flag_names);
}
} player_slots_iterate_end;
}
} /* Version < 3.1.94 */
if (game_version < 3019500) {
/* Before version number bump to 3.1.95 */
} /* Version < 3.1.95 */
#endif /* FREECIV_DEV_SAVE_COMPAT_3_2 */
}
/************************************************************************//**
Update loaded game data from earlier development version to something
usable by current Freeciv.
****************************************************************************/
static void compat_post_load_dev(struct loaddata *loading)
{
int game_version;
/* Check status and return if not OK (sg_success FALSE). */
sg_check_ret();
if (!secfile_lookup_int(loading->file, &game_version, "scenario.game_version")) {
game_version = 2060000;
}
#ifdef FREECIV_DEV_SAVE_COMPAT_3_2
if (game_version < 3019100) {
/* Before version number bump to 3.1.91 */
} /* Version < 3.1.91 */
#endif /* FREECIV_DEV_SAVE_COMPAT_3_2 */
}
#endif /* FREECIV_DEV_SAVE_COMPAT */
/************************************************************************//**
Convert old ai level value to ai_level
****************************************************************************/
    (1-1/1)