Hi, I wanted to make a subsystem to handle creation and updating of common save profile data.
Such as time played, storing a thumbnail, basic info on what state the player was in, like city name etc.
I have 2 types of data stored.
USaveGameGlobalBase and USaveGameProfileBase.
Both are meant to be inheritable classes that you can make blueprint types of.
You would make a child of GlobalBase and add custom values for your game such as volume settings.
And same with ProfileBase such as Money, InventoryItems etc, you have on that particular save.
Now that I explained the base of how its supposed to be used.
Here is the problem.
I can load a global object which contains the profiles.
I can load a profile object which contains a test variable named “Money”.
I can print this test value after I load it and it’s all good.
I load a different level using the Open Level node.
I attempt to get a reference to the currently loaded profile and I get a crash.
(The line that crashes is litterally just a getter of a private variable stored in the subsystem)
I have no idea what goes wrong here.
Ps. The event happens when I press the testbutton I made in a widget, to fetch the Money variable from the save profile. And its not even reaching the print before it crashes.
You can have a look at the source code here:
I have attempted to convert the internal pointer to a TSharedPtr with no different result.
I’m out of ideas here. Any clues?
After further experimenting I have a gut feeling that the object pointers in question seem to be invalid after another level is loaded. This seems like a bug to me as a UGameInstanceSubsystem should persist through the level switch and preserve the objects from Garbage Collection.
Anyways, I noticed that I’m also randomly getting another callstack result that I thought I would post.
Callstack Text 2
Not going to claim I’m good at c++ with unreal yet.
But from what I can tell, I would call this a bug with subsystems.
I tried to store a reference to both the objects that I’m storing in my subsystem from before, in my GameInstance Blueprint as well. And now the data can be accessed from the subsystem without issues!
So for some reason, after a level gets changed, I claim that garbage collection misstakenly delete objects that are only stored in the subsystem. I will have to do some more research before I report this to figure out if this is in reguards to any type of object or just blueprint objects etc.
Can confirm that this works for me as well.
I had a similar issue, which only showed up on built packages.
And the problem was that object properties were not marked as UPROPERTY, and therefore the garbage collector got rid of them after a while even when they are derived from UObject.
In your case the in SaveGamesSubsystem.h :
So adding UPROPERTY() should do the trick. I assume that the subsystems are neither a container class nor a class referenced to a root set itself, so they do not keep a reference list of used UObjects in subsystems, so the explicit UPROPERTY marking is necessary? I’m not sure about this.
From the documentation UObject
One practical implication here is that
you typically need to maintain a
UPROPERTY reference to any Object you
wish to keep alive, or store a pointer
to it in a TArray or other Unreal
Engine container class. Actors and
their Components are frequently an
exception to this, since the Actors
are usually referenced by an Object
that links back to the root set, such
as the Level to which they belong, and
the Actor’s Components are referenced
by the Actor itself.