OnLoadedSavedGameWithDLCExisting
Tracking Issue: #808
When loading a save the game makes a distinction between "existing" and "new" mods/DLCs. The list of the "existing" mods is stored inside the save and is used as "source of truth" during the loading process.
First, the game checks if any of the "existing" mods are currently not active. If such exist, the player gets the "missing mods" popup.
Then, the game checks whether any of the currently active mods are not listed as "existing". Such
mods are considered "new" and the OnLoadedSavedGame
hook is called on their DLCInfos.
Finally, the "new" mods are marked as "existing" to prevent the previous step from occurring again the next time the same campaign is loaded and to facilitate the popup, should any of them be removed.
The above process misses an important aspect - what happens if the mod is "existing" but wants to make
state changes before the save is loaded? An example use case would be adjusting existing campaigns due to
updates in the mod code. OnLoadedSavedGameWithDLCExisting
fills that gap - it is called on the "existing"
mods every time a save is loaded.
Important note 1: OnLoadedSavedGameWithDLCExisting
is exclusive with OnLoadedSavedGame
. If the mod was just
added (it is "new") then only OnLoadedSavedGame
will be called. On subsequent loads of saves from that
campaign (the mod is now "existing") only OnLoadedSavedGameWithDLCExisting
will be called.
Important note 2: this (and the base game OnLoadedSavedGame) is called before the ruleset of the save is initialized. This is great as any state changes done here will be picked up automatically (no need to refresh anything anywhere), however it imposes several limitations:
- You cannot use
SubmitGameStateContext
/SubmitGameState
. UseXComGameStateHistory::AddGameStateToHistory
instead - Event listener templates should be assumed as not registered
- In fact, due to (1), only
ELD_Immediate
listeners (that are registered on state objects) will be triggered. Therefore, you are advised to not trigger any events at all.
If the above is too limiting for your use case, consider using OnLoadedSavedGameToStrategy
/OnLoadedSavedGameToTactical
,
which are called after the relevant listener templates are registered and most of the presentation has loaded.
Important note 3: in case the save is loaded mid-tactical, some strategy state objects will be missing from the history. This is intended behaviour and you must account for it when using this hook. You can read more about it here: https://robojumper.github.io/too-real/history/#archived
Important note 4: the list of "existing" mods is not cleared when the mod is removed (in order to facilitate the popup).
This means that add -> save -> remove -> load -> save -> add -> load will trigger OnLoadedSavedGameWithDLCExisting
as the mod will be considered "existing". However, any state objects which are instances of class(es) added by the mod
will be gone as they will fail to deserialize when the save is loaded without the mod active. The only exception to
this is the "Remove Missing Mods" mod which removes the missing mods from the list of the "existing" ones. In that case,
the mod will be considered "new" (again).
While any mod can potentially manipulate that list, the "Remove Missing Mods" mod is currently the only known way of removing entries from said list
Important note 5: the decision to consider a mod either "new" or "existing" is made using its DLCName
.
See ModDependencyCheck
for an explanation.