Original Post
In my game, it is possible for game objects to acquire references to other game objects. Seeing as it would be useful for them to store said references (instead of re-querying for whatever object they wanted each time they wanted it), I wrote a simple pointer management system to ensure that pointers would be consistent across saves. The way it works is this:
There is a structure which, internally, stores a pointer to the object holding the pointer, a pointer to the object being pointed at, and a string so that the pointer can be easily accessed. These pointer structures are arranged in some broader structure which groups pointers together based on the ID of the holder object.
When a holder object is flagged for deletion, its pointer set is wiped out. Pointers cannot be manually deleted at any other time.
When an object is flagged for deletion, all pointers pointing to it are set to null.
When the game is saved, the IDs of the holder and target pointers are written out. When the game is loaded, the IDs -- which are consistent across a save and load -- are used to rebuild the pointer table.
Pointer tables are local to a level because IDs within a given level are guaranteed to be unique; additionally, pointers to things in other levels is, frankly, something I don't want because it could lead to weird behavior.
For the most part this has worked out fine so far. However, I've recently decided I want a set of game objects that exist externally to any level for various reasons (which are left as an exercise to future generations who might be reading this). I want to allow objects in a given level to point to these extra-level objects, (but not vice versa). I'm encountering a few problems:
1. The pointer null-ing code would work fine on the extra-level objects, in the sense that if a level-object had a pointer to an extra-level object that got flagged for deletion, if the player was in that level, the pointer would get null'd...
2. ... however, the pointer nulling code only runs for the level the player is currently, meaning something in another level with a pointer to an extra-level object flagged for deletion would not have its pointer correctly nulled.
3. Running the pointer nulling code for non-active levels is impractical for two reasons: First, it strikes me as inefficient. Second and more importantly, not every level is loaded into memory at the same time. If an object in a non-loaded level has a pointer to an extra-level object flagged for deletion, its pointers aren't even going to be in memory to get nulled out.
4. Furthermore, if an extra-level object is deleted, its ID will be freed and re-assigned. If a level containing a level-object that had previously stored a pointer to the now-deleted object is then loaded into memory, the loading code will assign the pointer to the WRONG object, since the ID will match, breaking the IDs remaining consistent across saves and loads which had worked out fine when pointers were strictly level-local.
5. In the current system, it should be noted that extra-level objects could safely point to other extra-level objects without these issues afflicting them.
So, a few possible solutions, none of which I like:
1. IDs are unique, but released for re-assignment when their associated object is deleted. This works fine for level-objects. As mentioned in problem 4, it causes problems with extra-level objects. An incorrect way to address this problem would be to never re-use IDs. A better solution would be to not re-use IDs for extra-level objects until it is determined that doing so would be safe; however I am not sure how to go about that.
I think something that might be viable is this: Flag a released ID as being unusable upon its release. When saving the game, test all
2. In terms of the other problems, I have considered having objects store pointers to the pointers that point at them, but this sounds needlessly obtuse, and still doesn't address the issue of nullifying pointers that aren't in memory.
3. Seeing as non-existent-but-potentially-existent can't really be nulled, one possible solution would be to store a list of target IDs in the extra-level object structure. When an extra-level object got flagged for deletion, it would add its ID to this list, so that, on accessing it, whatever object was accessing it would have its pointer figure out that it should null itself.
4. Implement a proper garbage collector of some sort for extra-level objects and just keep objects around until nothing pointed at them, which would probably address all of my issues, but would be inconsistent with how things are handled elsewhere and might be overkill. I'm looking more at this, though, really. Garbage collection would probably occur when saving the game, and probably wouldn't be a huge deal since it wouldn't really be necessary to garbage collect regular level objects.
There is a structure which, internally, stores a pointer to the object holding the pointer, a pointer to the object being pointed at, and a string so that the pointer can be easily accessed. These pointer structures are arranged in some broader structure which groups pointers together based on the ID of the holder object.
When a holder object is flagged for deletion, its pointer set is wiped out. Pointers cannot be manually deleted at any other time.
When an object is flagged for deletion, all pointers pointing to it are set to null.
When the game is saved, the IDs of the holder and target pointers are written out. When the game is loaded, the IDs -- which are consistent across a save and load -- are used to rebuild the pointer table.
Pointer tables are local to a level because IDs within a given level are guaranteed to be unique; additionally, pointers to things in other levels is, frankly, something I don't want because it could lead to weird behavior.
For the most part this has worked out fine so far. However, I've recently decided I want a set of game objects that exist externally to any level for various reasons (which are left as an exercise to future generations who might be reading this). I want to allow objects in a given level to point to these extra-level objects, (but not vice versa). I'm encountering a few problems:
1. The pointer null-ing code would work fine on the extra-level objects, in the sense that if a level-object had a pointer to an extra-level object that got flagged for deletion, if the player was in that level, the pointer would get null'd...
2. ... however, the pointer nulling code only runs for the level the player is currently, meaning something in another level with a pointer to an extra-level object flagged for deletion would not have its pointer correctly nulled.
3. Running the pointer nulling code for non-active levels is impractical for two reasons: First, it strikes me as inefficient. Second and more importantly, not every level is loaded into memory at the same time. If an object in a non-loaded level has a pointer to an extra-level object flagged for deletion, its pointers aren't even going to be in memory to get nulled out.
4. Furthermore, if an extra-level object is deleted, its ID will be freed and re-assigned. If a level containing a level-object that had previously stored a pointer to the now-deleted object is then loaded into memory, the loading code will assign the pointer to the WRONG object, since the ID will match, breaking the IDs remaining consistent across saves and loads which had worked out fine when pointers were strictly level-local.
5. In the current system, it should be noted that extra-level objects could safely point to other extra-level objects without these issues afflicting them.
So, a few possible solutions, none of which I like:
1. IDs are unique, but released for re-assignment when their associated object is deleted. This works fine for level-objects. As mentioned in problem 4, it causes problems with extra-level objects. An incorrect way to address this problem would be to never re-use IDs. A better solution would be to not re-use IDs for extra-level objects until it is determined that doing so would be safe; however I am not sure how to go about that.
I think something that might be viable is this: Flag a released ID as being unusable upon its release. When saving the game, test all
2. In terms of the other problems, I have considered having objects store pointers to the pointers that point at them, but this sounds needlessly obtuse, and still doesn't address the issue of nullifying pointers that aren't in memory.
3. Seeing as non-existent-but-potentially-existent can't really be nulled, one possible solution would be to store a list of target IDs in the extra-level object structure. When an extra-level object got flagged for deletion, it would add its ID to this list, so that, on accessing it, whatever object was accessing it would have its pointer figure out that it should null itself.
4. Implement a proper garbage collector of some sort for extra-level objects and just keep objects around until nothing pointed at them, which would probably address all of my issues, but would be inconsistent with how things are handled elsewhere and might be overkill. I'm looking more at this, though, really. Garbage collection would probably occur when saving the game, and probably wouldn't be a huge deal since it wouldn't really be necessary to garbage collect regular level objects.