From dfa5a7eb8081d66484cd0f7dafaa8036cef1c2fe Mon Sep 17 00:00:00 2001 From: SamuXarick <43006711+SamuXarick@users.noreply.github.com> Date: Sat, 15 Feb 2025 15:18:46 +0000 Subject: [PATCH 1/4] Fix #13519, e4c511d: Select chosen AI/GS version, not the highest compatible version --- src/script/script_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/script/script_gui.cpp b/src/script/script_gui.cpp index d2ef7819a9..0202d1285a 100644 --- a/src/script/script_gui.cpp +++ b/src/script/script_gui.cpp @@ -172,7 +172,7 @@ struct ScriptListWindow : public Window { } else { ScriptInfoList::const_iterator it = this->info_list->cbegin(); std::advance(it, this->selected); - GetConfig(this->slot)->Change(it->second->GetName(), it->second->GetVersion()); + GetConfig(this->slot)->Change(it->second->GetName(), it->second->GetVersion(), this->show_all); } if (_game_mode == GM_EDITOR) { if (this->slot == OWNER_DEITY) { From 6ee9712d497894769894941b21a6e5680357bec0 Mon Sep 17 00:00:00 2001 From: SamuXarick <43006711+SamuXarick@users.noreply.github.com> Date: Mon, 17 Feb 2025 22:03:18 +0000 Subject: [PATCH 2/4] Change: [Script] Save exact version selected in savegames --- src/saveload/ai_sl.cpp | 73 +++++++++++++++++++++++------------- src/saveload/game_sl.cpp | 42 +++++++++++++-------- src/saveload/saveload.h | 2 + src/script/script_config.cpp | 7 ++++ src/script/script_config.hpp | 6 +++ 5 files changed, 89 insertions(+), 41 deletions(-) diff --git a/src/saveload/ai_sl.cpp b/src/saveload/ai_sl.cpp index 29f759361c..3a0d74a04e 100644 --- a/src/saveload/ai_sl.cpp +++ b/src/saveload/ai_sl.cpp @@ -27,18 +27,21 @@ static std::string _ai_saveload_name; static int _ai_saveload_version; static std::string _ai_saveload_settings; static bool _ai_saveload_is_random; +static bool _ai_saveload_force_exact_match; static const SaveLoad _ai_company_desc[] = { SLEG_SSTR("name", _ai_saveload_name, SLE_STR), SLEG_SSTR("settings", _ai_saveload_settings, SLE_STR), SLEG_CONDVAR("version", _ai_saveload_version, SLE_UINT32, SLV_108, SL_MAX_VERSION), SLEG_CONDVAR("is_random", _ai_saveload_is_random, SLE_BOOL, SLV_136, SLV_AI_LOCAL_CONFIG), + SLEG_CONDVAR("force_exact_match", _ai_saveload_force_exact_match, SLE_BOOL, SLV_SCRIPT_FORCE_EXACT_MATCH, SL_MAX_VERSION), }; static const SaveLoad _ai_running_desc[] = { SLEG_CONDSSTR("running_name", _ai_saveload_name, SLE_STR, SLV_AI_LOCAL_CONFIG, SL_MAX_VERSION), SLEG_CONDSSTR("running_settings", _ai_saveload_settings, SLE_STR, SLV_AI_LOCAL_CONFIG, SL_MAX_VERSION), SLEG_CONDVAR("running_version", _ai_saveload_version, SLE_UINT32, SLV_AI_LOCAL_CONFIG, SL_MAX_VERSION), + SLEG_CONDVAR("running_force_exact_match", _ai_saveload_force_exact_match, SLE_BOOL, SLV_SCRIPT_FORCE_EXACT_MATCH, SL_MAX_VERSION), }; static void SaveReal_AIPL(int arg) @@ -56,6 +59,7 @@ static void SaveReal_AIPL(int arg) } _ai_saveload_settings = config->SettingsToString(); + _ai_saveload_force_exact_match = config->GetForceExactMatch(); SlObject(nullptr, _ai_company_desc); @@ -66,10 +70,10 @@ static void SaveReal_AIPL(int arg) _ai_saveload_name = config->GetName(); _ai_saveload_version = config->GetVersion(); _ai_saveload_settings = config->SettingsToString(); + _ai_saveload_force_exact_match = config->GetForceExactMatch(); SlObject(nullptr, _ai_running_desc); AI::Save(index); - } struct AIPLChunkHandler : ChunkHandler { @@ -90,6 +94,7 @@ struct AIPLChunkHandler : ChunkHandler { _ai_saveload_is_random = false; _ai_saveload_version = -1; + _ai_saveload_force_exact_match = false; SlObject(nullptr, slt); if (_game_mode == GM_MENU || (_networking && !_network_server)) { @@ -105,19 +110,27 @@ struct AIPLChunkHandler : ChunkHandler { /* A random AI. */ config->Change(std::nullopt, -1, false); } else { - config->Change(_ai_saveload_name, _ai_saveload_version, false); + if (_ai_saveload_force_exact_match) config->Change(_ai_saveload_name, _ai_saveload_version, true); if (!config->HasScript()) { - /* No version of the AI available. Try to configure the - * latest version of the AI instead. */ - config->Change(_ai_saveload_name, -1, false); + /* Exact version of the AI is not available. Try to + * configure the highest compatible version. */ + config->Change(_ai_saveload_name, _ai_saveload_version, false); if (!config->HasScript()) { - if (_ai_saveload_name.compare("%_dummy") != 0) { - Debug(script, 0, "The savegame has an AI by the name '{}', version {} which is no longer available.", _ai_saveload_name, _ai_saveload_version); - Debug(script, 0, "Configuration switched to Random AI."); + /* No version of the AI available. Try to configure the + * latest version of the AI instead. */ + config->Change(_ai_saveload_name, -1, false); + if (!config->HasScript()) { + if (_ai_saveload_name.compare("%_dummy") != 0) { + Debug(script, 0, "The savegame has an AI by the name '{}', {}version {} which is no longer available.", _ai_saveload_name, _ai_saveload_force_exact_match ? "forcing " : "", _ai_saveload_version); + Debug(script, 0, "Configuration switched to Random AI."); + } + } else { + Debug(script, 0, "The savegame has an AI by the name '{}', {}version {} which is no longer available.", _ai_saveload_name, _ai_saveload_force_exact_match ? "forcing " : "", _ai_saveload_version); + Debug(script, 0, "The latest version of that AI has been configured instead."); } - } else { - Debug(script, 0, "The savegame has an AI by the name '{}', version {} which is no longer available.", _ai_saveload_name, _ai_saveload_version); - Debug(script, 0, "The latest version of that AI has been configured instead"); + } else if (_ai_saveload_force_exact_match) { + Debug(script, 0, "The savegame has an AI by the name '{}', forcing version {} which is no longer available.", _ai_saveload_name, _ai_saveload_version); + Debug(script, 0, "The highest compatible version of that AI has been configured instead."); } } } @@ -130,26 +143,34 @@ struct AIPLChunkHandler : ChunkHandler { Company::Get(index)->ai_config = std::make_unique(); config = Company::Get(index)->ai_config.get(); - config->Change(_ai_saveload_name, _ai_saveload_version, false); + if (_ai_saveload_force_exact_match) config->Change(_ai_saveload_name, _ai_saveload_version, true); if (!config->HasScript()) { - /* No version of the AI available that can load the data. Try to load the - * latest version of the AI instead. */ - config->Change(_ai_saveload_name, -1, false); + /* Exact version of the AI is not available. Try to load the highest + * compatible version of the AI instead that can load the data. */ + config->Change(_ai_saveload_name, _ai_saveload_version, false); if (!config->HasScript()) { - if (_ai_saveload_name.compare("%_dummy") != 0) { - Debug(script, 0, "The savegame has an AI by the name '{}', version {} which is no longer available.", _ai_saveload_name, _ai_saveload_version); - Debug(script, 0, "A random other AI will be loaded in its place."); + /* No version of the AI available that can load the data. Try to load the + * latest version of the AI instead. */ + config->Change(_ai_saveload_name, -1, false); + if (!config->HasScript()) { + if (_ai_saveload_name.compare("%_dummy") != 0) { + Debug(script, 0, "The savegame has an AI by the name '{}', {}version {} which is no longer available.", _ai_saveload_name, _ai_saveload_force_exact_match ? "forcing " : "", _ai_saveload_version); + Debug(script, 0, "A random other AI will be loaded in its place."); + } else { + Debug(script, 0, "The savegame had no AIs available at the time of saving."); + Debug(script, 0, "A random available AI will be loaded now."); + } } else { - Debug(script, 0, "The savegame had no AIs available at the time of saving."); - Debug(script, 0, "A random available AI will be loaded now."); + Debug(script, 0, "The savegame has an AI by the name '{}', {}version {} which is no longer available.", _ai_saveload_name, _ai_saveload_force_exact_match ? "forcing " : "", _ai_saveload_version); + Debug(script, 0, "The latest version of that AI has been loaded instead, but it'll not get the savegame data as it's incompatible."); } - } else { - Debug(script, 0, "The savegame has an AI by the name '{}', version {} which is no longer available.", _ai_saveload_name, _ai_saveload_version); - Debug(script, 0, "The latest version of that AI has been loaded instead, but it'll not get the savegame data as it's incompatible."); + /* Make sure the AI doesn't get the saveload data, as it was not the + * writer of the saveload data in the first place */ + _ai_saveload_version = -1; + } else if (_ai_saveload_force_exact_match) { + Debug(script, 0, "The savegame has an AI by the name '{}', forcing version {} which is no longer available.", _ai_saveload_name, _ai_saveload_version); + Debug(script, 0, "The highest compatible version of that AI has been loaded instead."); } - /* Make sure the AI doesn't get the saveload data, as it was not the - * writer of the saveload data in the first place */ - _ai_saveload_version = -1; } config->StringToSettings(_ai_saveload_settings); config->SetToLoadData(AIInstance::Load(_ai_saveload_version)); diff --git a/src/saveload/game_sl.cpp b/src/saveload/game_sl.cpp index d6a35ffa20..63514e80df 100644 --- a/src/saveload/game_sl.cpp +++ b/src/saveload/game_sl.cpp @@ -25,11 +25,13 @@ static std::string _game_saveload_name; static int _game_saveload_version; static std::string _game_saveload_settings; +static bool _game_saveload_force_exact_match; static const SaveLoad _game_script_desc[] = { SLEG_SSTR("name", _game_saveload_name, SLE_STR), SLEG_SSTR("settings", _game_saveload_settings, SLE_STR), SLEG_VAR("version", _game_saveload_version, SLE_UINT32), + SLEG_CONDVAR("force_exact_match", _game_saveload_force_exact_match, SLE_BOOL, SLV_SCRIPT_FORCE_EXACT_MATCH, SL_MAX_VERSION), }; static void SaveReal_GSDT(int) @@ -46,6 +48,7 @@ static void SaveReal_GSDT(int) } _game_saveload_settings = config->SettingsToString(); + _game_saveload_force_exact_match = config->GetForceExactMatch(); SlObject(nullptr, _game_script_desc); Game::Save(); @@ -64,6 +67,7 @@ struct GSDTChunkHandler : ChunkHandler { if (SlIterateArray() == -1) return; _game_saveload_version = -1; + _game_saveload_force_exact_match = false; SlObject(nullptr, slt); if (_game_mode == GM_MENU || (_networking && !_network_server)) { @@ -74,26 +78,34 @@ struct GSDTChunkHandler : ChunkHandler { GameConfig *config = GameConfig::GetConfig(GameConfig::SSS_FORCE_GAME); if (!_game_saveload_name.empty()) { - config->Change(_game_saveload_name, _game_saveload_version, false); + if (_game_saveload_force_exact_match) config->Change(_game_saveload_name, _game_saveload_version, true); if (!config->HasScript()) { - /* No version of the GameScript available that can load the data. Try to load the - * latest version of the GameScript instead. */ - config->Change(_game_saveload_name, -1, false); + /* Exact version of the GameScript is not available. Try to load the highest + * compatible version of the AI instead that can load the data. */ + config->Change(_game_saveload_name, _game_saveload_version, false); if (!config->HasScript()) { - if (_game_saveload_name.compare("%_dummy") != 0) { - Debug(script, 0, "The savegame has an GameScript by the name '{}', version {} which is no longer available.", _game_saveload_name, _game_saveload_version); - Debug(script, 0, "This game will continue to run without GameScript."); + /* No version of the GameScript available that can load the data. Try to load the + * latest version of the GameScript instead. */ + config->Change(_game_saveload_name, -1, false); + if (!config->HasScript()) { + if (_game_saveload_name.compare("%_dummy") != 0) { + Debug(script, 0, "The savegame has a GameScript by the name '{}', {}version {} which is no longer available.", _game_saveload_name, _game_saveload_force_exact_match ? "forcing " : "", _game_saveload_version); + Debug(script, 0, "This game will continue to run without GameScript."); + } else { + Debug(script, 0, "The savegame had no GameScript available at the time of saving."); + Debug(script, 0, "This game will continue to run without GameScript."); + } } else { - Debug(script, 0, "The savegame had no GameScript available at the time of saving."); - Debug(script, 0, "This game will continue to run without GameScript."); + Debug(script, 0, "The savegame has a GameScript by the name '{}', {}version {} which is no longer available.", _game_saveload_name, _game_saveload_force_exact_match ? "forcing " : "", _game_saveload_version); + Debug(script, 0, "The latest version of that GameScript has been loaded instead, but it'll not get the savegame data as it's incompatible."); } - } else { - Debug(script, 0, "The savegame has an GameScript by the name '{}', version {} which is no longer available.", _game_saveload_name, _game_saveload_version); - Debug(script, 0, "The latest version of that GameScript has been loaded instead, but it'll not get the savegame data as it's incompatible."); + /* Make sure the GameScript doesn't get the saveload data, as it was not the + * writer of the saveload data in the first place */ + _game_saveload_version = -1; + } else if (_game_saveload_force_exact_match) { + Debug(script, 0, "The savegame has a GameScript by the name '{}', forcing version {} which is no longer available.", _game_saveload_name, _game_saveload_version); + Debug(script, 0, "The highest compatible version of that GameScript has been loaded instead."); } - /* Make sure the GameScript doesn't get the saveload data, as it was not the - * writer of the saveload data in the first place */ - _game_saveload_version = -1; } } diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index ec78153db1..f543e10411 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -403,6 +403,8 @@ enum SaveLoadVersion : uint16_t { SLV_FIX_SCC_ENCODED_NEGATIVE, ///< 353 PR#14049 Fix encoding of negative parameters. SLV_ORDERS_OWNED_BY_ORDERLIST, ///< 354 PR#13948 Orders stored in OrderList, pool removed. + SLV_SCRIPT_FORCE_EXACT_MATCH, ///< 355 PR#13565 Store script force exact match in savegames. + SL_MAX_VERSION, ///< Highest possible saveload version }; diff --git a/src/script/script_config.cpp b/src/script/script_config.cpp index a599a7e30a..856d223ea4 100644 --- a/src/script/script_config.cpp +++ b/src/script/script_config.cpp @@ -29,6 +29,7 @@ void ScriptConfig::Change(std::optional name, int version, boo this->info = nullptr; } this->version = (info == nullptr) ? -1 : info->GetVersion(); + this->force_exact_match = (info == nullptr) ? false : force_exact_match; this->config_list.reset(); this->to_load_data.reset(); @@ -40,6 +41,7 @@ ScriptConfig::ScriptConfig(const ScriptConfig &config) this->name = config.name; this->info = config.info; this->version = config.version; + this->force_exact_match = config.force_exact_match; this->to_load_data.reset(); for (const auto &item : config.settings) { @@ -140,6 +142,11 @@ int ScriptConfig::GetVersion() const return this->version; } +bool ScriptConfig::GetForceExactMatch() const +{ + return this->force_exact_match; +} + void ScriptConfig::StringToSettings(std::string_view value) { std::string_view to_process = value; diff --git a/src/script/script_config.hpp b/src/script/script_config.hpp index 76da137bcf..1059985c04 100644 --- a/src/script/script_config.hpp +++ b/src/script/script_config.hpp @@ -150,6 +150,11 @@ public: */ int GetVersion() const; + /** + * Whether the config is forcing the exact version of the Script? + */ + bool GetForceExactMatch() const; + /** * Convert a string which is stored in the config file or savegames to * custom settings of this Script. @@ -176,6 +181,7 @@ public: protected: std::string name; ///< Name of the Script int version; ///< Version of the Script + bool force_exact_match; ///< Force exact match for the version class ScriptInfo *info; ///< ScriptInfo object for related to this Script version SettingValueList settings; ///< List with all setting=>value pairs that are configure for this Script std::unique_ptr config_list; ///< List with all settings defined by this Script From ae7903e71f6ad5edca74a15eb9b8ba1b3e17281c Mon Sep 17 00:00:00 2001 From: SamuXarick <43006711+SamuXarick@users.noreply.github.com> Date: Sat, 15 Feb 2025 15:21:30 +0000 Subject: [PATCH 3/4] Add: Show version selected in the AI/GS slots as well --- src/ai/ai_gui.cpp | 7 +++++-- src/game/game_gui.cpp | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp index d839e58850..5323251363 100644 --- a/src/ai/ai_gui.cpp +++ b/src/ai/ai_gui.cpp @@ -169,8 +169,11 @@ struct AIConfigWindow : public Window { std::string GetSlotText(CompanyID cid) const { if ((_game_mode != GM_NORMAL && cid == 0) || (_game_mode == GM_NORMAL && Company::IsValidHumanID(cid))) return GetString(STR_AI_CONFIG_HUMAN_PLAYER); - if (const AIInfo *info = AIConfig::GetConfig(cid)->GetInfo(); info != nullptr) return info->GetName(); - return GetString(STR_AI_CONFIG_RANDOM_AI); + const AIConfig *config = AIConfig::GetConfig(cid); + const AIInfo *info = config->GetInfo(); + if (info == nullptr) return GetString(STR_AI_CONFIG_RANDOM_AI); + if (config->GetForceExactMatch()) return GetString(STR_AI_CONFIG_NAME_VERSION, info->GetName(), info->GetVersion()); + return info->GetName(); } /** diff --git a/src/game/game_gui.cpp b/src/game/game_gui.cpp index 207a4c7daf..8604a08dbc 100644 --- a/src/game/game_gui.cpp +++ b/src/game/game_gui.cpp @@ -167,8 +167,11 @@ struct GSConfigWindow : public Window { */ std::string GetText() const { - if (const GameInfo *info = GameConfig::GetConfig()->GetInfo(); info != nullptr) return info->GetName(); - return GetString(STR_AI_CONFIG_NONE); + const GameConfig *config = GameConfig::GetConfig(); + const GameInfo *info = config->GetInfo(); + if (info == nullptr) return GetString(STR_AI_CONFIG_NONE); + if (config->GetForceExactMatch()) return GetString(STR_AI_CONFIG_NAME_VERSION, info->GetName(), info->GetVersion()); + return info->GetName(); } void DrawWidget(const Rect &r, WidgetID widget) const override From e3db611fde8341190050351fc326caefda937824 Mon Sep 17 00:00:00 2001 From: SamuXarick <43006711+SamuXarick@users.noreply.github.com> Date: Mon, 17 Feb 2025 22:04:47 +0000 Subject: [PATCH 4/4] Change: [Script] Append version in config file when forcing exact version --- src/ai/ai_core.cpp | 8 +++---- src/game/game_core.cpp | 6 +++--- src/settings.cpp | 47 +++++++++++++++++++++++++++++++----------- 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/src/ai/ai_core.cpp b/src/ai/ai_core.cpp index 0283b38f66..ae2e104bf6 100644 --- a/src/ai/ai_core.cpp +++ b/src/ai/ai_core.cpp @@ -203,21 +203,21 @@ for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) { if (_settings_game.script_config.ai[c] != nullptr && _settings_game.script_config.ai[c]->HasScript()) { if (!_settings_game.script_config.ai[c]->ResetInfo(true)) { - Debug(script, 0, "After a reload, the AI by the name '{}' was no longer found, and removed from the list.", _settings_game.script_config.ai[c]->GetName()); + Debug(script, 0, "After a reload, the AI by the name '{}' with version {} was no longer found, and removed from the list.", _settings_game.script_config.ai[c]->GetName(), _settings_game.script_config.ai[c]->GetVersion()); _settings_game.script_config.ai[c]->Change(std::nullopt); } } if (_settings_newgame.script_config.ai[c] != nullptr && _settings_newgame.script_config.ai[c]->HasScript()) { - if (!_settings_newgame.script_config.ai[c]->ResetInfo(false)) { - Debug(script, 0, "After a reload, the AI by the name '{}' was no longer found, and removed from the list.", _settings_newgame.script_config.ai[c]->GetName()); + if (!_settings_newgame.script_config.ai[c]->ResetInfo(_settings_newgame.script_config.ai[c]->GetForceExactMatch())) { + Debug(script, 0, "After a reload, the AI by the name '{}' with version {} was no longer found, and removed from the list.", _settings_newgame.script_config.ai[c]->GetName(), _settings_game.script_config.ai[c]->GetVersion()); _settings_newgame.script_config.ai[c]->Change(std::nullopt); } } if (Company::IsValidAiID(c) && Company::Get(c)->ai_config != nullptr) { AIConfig *config = Company::Get(c)->ai_config.get(); - if (!config->ResetInfo(true)) { + if (!config->ResetInfo(_settings_newgame.script_config.ai[c]->GetForceExactMatch())) { /* The code belonging to an already running AI was deleted. We can only do * one thing here to keep everything sane and that is kill the AI. After * killing the offending AI we start a random other one in it's place, just diff --git a/src/game/game_core.cpp b/src/game/game_core.cpp index 14ebcd9ab9..0054945b1e 100644 --- a/src/game/game_core.cpp +++ b/src/game/game_core.cpp @@ -159,7 +159,7 @@ * the GameConfig. If not, remove the Game from the list. */ if (_settings_game.script_config.game != nullptr && _settings_game.script_config.game->HasScript()) { if (!_settings_game.script_config.game->ResetInfo(true)) { - Debug(script, 0, "After a reload, the GameScript by the name '{}' was no longer found, and removed from the list.", _settings_game.script_config.game->GetName()); + Debug(script, 0, "After a reload, the GameScript by the name '{}' with version {} was no longer found, and removed from the list.", _settings_game.script_config.game->GetName(), _settings_newgame.script_config.game->GetVersion()); _settings_game.script_config.game->Change(std::nullopt); if (Game::instance != nullptr) Game::ResetInstance(); } else if (Game::instance != nullptr) { @@ -167,8 +167,8 @@ } } if (_settings_newgame.script_config.game != nullptr && _settings_newgame.script_config.game->HasScript()) { - if (!_settings_newgame.script_config.game->ResetInfo(false)) { - Debug(script, 0, "After a reload, the GameScript by the name '{}' was no longer found, and removed from the list.", _settings_newgame.script_config.game->GetName()); + if (!_settings_newgame.script_config.game->ResetInfo(_settings_newgame.script_config.game->GetForceExactMatch())) { + Debug(script, 0, "After a reload, the GameScript by the name '{}' with version {} was no longer found, and removed from the list.", _settings_newgame.script_config.game->GetName(), _settings_newgame.script_config.game->GetVersion()); _settings_newgame.script_config.game->Change(std::nullopt); } } diff --git a/src/settings.cpp b/src/settings.cpp index 9efb21a057..ed6f2923cf 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -948,6 +948,21 @@ static void ValidateSettings() } } +static std::pair TryReadScriptNameWithVersion(std::string_view item_name) +{ + StringConsumer consumer{item_name}; + auto name = consumer.ReadUntilChar('.', StringConsumer::SKIP_ONE_SEPARATOR); + + if (consumer.AnyBytesLeft()) { + auto version = consumer.TryReadIntegerBase(10); + if (version.has_value()) { + return { name, *version }; + } + } + + return { name, -1 }; +} + static void AILoadConfig(const IniFile &ini, std::string_view grpname) { const IniGroup *group = ini.GetGroup(grpname); @@ -966,9 +981,14 @@ static void AILoadConfig(const IniFile &ini, std::string_view grpname) config->Change(item.name); if (!config->HasScript()) { - if (item.name != "none") { - Debug(script, 0, "The AI by the name '{}' was no longer found, and removed from the list.", item.name); - continue; + auto [name, version] = TryReadScriptNameWithVersion(item.name); + config->Change(name, version, version != -1); + + if (!config->HasScript()) { + if (name != "none") { + Debug(script, 0, "The AI by the name '{}' was no longer found, and removed from the list.", name); + continue; + } } } if (item.value.has_value()) config->StringToSettings(*item.value); @@ -993,9 +1013,14 @@ static void GameLoadConfig(const IniFile &ini, std::string_view grpname) config->Change(item.name); if (!config->HasScript()) { - if (item.name != "none") { - Debug(script, 0, "The GameScript by the name '{}' was no longer found, and removed from the list.", item.name); - return; + auto [name, version] = TryReadScriptNameWithVersion(item.name); + config->Change(name, version, version != -1); + + if (!config->HasScript()) { + if (name != "none") { + Debug(script, 0, "The GameScript by the name '{}' was no longer found, and removed from the list.", name); + return; + } } } if (item.value.has_value()) config->StringToSettings(*item.value); @@ -1184,13 +1209,12 @@ static void AISaveConfig(IniFile &ini, std::string_view grpname) for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) { AIConfig *config = AIConfig::GetConfig(c, AIConfig::SSS_FORCE_NEWGAME); - std::string name; + std::string name = "none"; std::string value = config->SettingsToString(); if (config->HasScript()) { name = config->GetName(); - } else { - name = "none"; + if (config->GetForceExactMatch()) name = fmt::format("{}.{}", name, config->GetVersion()); } group.CreateItem(name).SetValue(value); @@ -1203,13 +1227,12 @@ static void GameSaveConfig(IniFile &ini, std::string_view grpname) group.Clear(); GameConfig *config = GameConfig::GetConfig(AIConfig::SSS_FORCE_NEWGAME); - std::string name; + std::string name = "none"; std::string value = config->SettingsToString(); if (config->HasScript()) { name = config->GetName(); - } else { - name = "none"; + if (config->GetForceExactMatch()) name = fmt::format("{}.{}", name, config->GetVersion()); } group.CreateItem(name).SetValue(value);