Engine: register static objects missing from a restored save's pool - #3091
craigharman wants to merge 2 commits into
Conversation
Restoring a save replaces the managed pool with the saved one, which only lists the audio clips, characters, dialogs, GUIs and GUI controls that existed when the save was made. Any added to the game in a later build are left out of the pool, and the first script that stores a pointer to one (for example, passes it as a function argument) fails with "Pointer cast failure: the object being pointed to is not in the managed object pool". After reading the pool, register any of these static objects it lacks.
…pool Restoring a 0.9.1 save in 0.9.3 crashed in the cabaret with "Pointer cast failure" because clips added in 0.9.2 weren't in the restored managed pool. After reading the pool, register any audio clips, characters, dialogs, GUIs and GUI controls it lacks. Submitted upstream as adventuregamestudio#3091.
|
Interesting, this problem means that the support for restoring old saves in a game with more objects (added in 3.6.2) was not complete. Perhaps, not many people tried this system yet. I see that in your commit you register the objects right in the ReadManagedPool(). I'd rather move this code to DoAfterRestore(), which is run after all save data was loaded. This function already is registering "missing" audiochannels, and re-exports gui controls, as you can see here: Lines 645 to 650 in 0badfb5 |
Move the registration out of ReadManagedPool into DoAfterRestore, next to export_missing_audiochans(), so it runs once all save data is loaded. Drop the GUI control loop: DoAfterRestore already re-exports GUI controls.
|
Thanks, that makes sense. I've moved the registration into I kept the new About the |
Restoring a save replaces the managed object pool with the one stored in the save. That pool only contains the audio clips, characters, dialogs, GUIs and GUI controls that existed when the save was made. If the developer adds any of these in a later build, those objects are missing from the pool once an old save is restored.
Using them directly still works, e.g.
aNewMusic.Play(). The first script that stores a pointer to one fails, because storing a pointer looks the address up in the pool:Passing one as a function argument counts as storing, so an ordinary helper is enough to trigger it:
Our players hit this after an update that appended five music clips. Saves from the previous build crashed as soon as a room passed one of the new clips to a helper. We saw the same thing with a GUI added in a later update, when it was passed through a
GUI*parameter.Fix
After
ReadManagedPoolrestores the pool, register any audio clip, character, dialog, GUI or GUI control that the pool doesn't already contain. Objects that are already there keep their saved handles. Missing ones get new handles, which is safe because no saved data can refer to them. Characters are included because a game can accept a save with a different character count throughvalidate_restored_save. Inventory items, audio channels, hotspots, objects and regions are left alone. The engine registers a fixed maximum number of each, so they're always in the pool.This adds a small helper,
ccRegisterManagedObjectIfMissing(), todynobj_manager.To reproduce
AudioClip*parameter.