From ba37c6ecc04a1da3c348d6a0408faab5838df9d4 Mon Sep 17 00:00:00 2001 From: Pavel Solodovnikov Date: Thu, 11 Jan 2024 23:52:01 +0300 Subject: [PATCH] game.cpp: Fix loading commander droids without `psGroup` When a commander transitions from an offworld mission, it will currently lose its group (actually, this is kind of a bug, too), i.e. its `psGroup` is `nullptr`. If a player attempts to save the game right after this transition and then loads the savegame again, the game will crash. `loadSaveDroid()` function will try to allocate a new group for these "orphaned" returning commanders. But this new group ID is not in sync with other group IDs that may already be present in the currently-processed "droid.json" file and thus may clash with other groups, leading to various memory-related bugs. For example, this may happen when there is a commander back at the players' base with some commander group assigned. There is a non-zero probability that the commander which returns from an offworld mission, will try to allocate the same group ID as the commander back at the base. Signed-off-by: Pavel Solodovnikov --- src/game.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/game.cpp b/src/game.cpp index 44b1f05c147..d2623af42e7 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -5552,10 +5552,16 @@ static bool loadSaveDroid(const char *pFileName, PerPlayerDroidLists& ppsCurrent // Sort list so transports are loaded first, since they must be loaded before the droids they contain. std::vector> sortedList; bool missionList = fName.compare("mdroid"); + // This will be set to the largest group ID found throughout the droid file + 1. + // + // This helps to allocate non-conflicting group IDs for commanders which + // happen to lose their group, e.g. when transitioning from an offworld mission. + int nextFreeGroupID = 0; for (size_t i = 0; i < list.size(); ++i) { ini.beginGroup(list[i]); DROID_TYPE droidType = (DROID_TYPE)ini.value("droidType").toInt(); + int aigroup = ini.value("aigroup", -1).toInt(); int priority = 0; switch (droidType) { @@ -5571,6 +5577,10 @@ static bool loadSaveDroid(const char *pFileName, PerPlayerDroidLists& ppsCurrent { ++priority; } + if (aigroup >= 0) + { + nextFreeGroupID = std::max(nextFreeGroupID, aigroup) + 1; + } default: break; } @@ -5701,7 +5711,7 @@ static bool loadSaveDroid(const char *pFileName, PerPlayerDroidLists& ppsCurrent { if (isTransporter(psDroid) || psDroid->droidType == DROID_COMMAND) { - DROID_GROUP *psGroup = grpCreate(); + DROID_GROUP *psGroup = grpCreate(nextFreeGroupID++); psGroup->add(psDroid); } else