[PLUGIN] Savior

Sorry to trouble you again, but I’m running into another issue. I have a UObject stored on my custom GameInstance class, and I would like to be able to save/load the state of the UObject. Is this something that is possible with the systems in place? When I inspect the .sav file, I can see the UObject with the correct SGUID, but it is empty when I attempt to load it.

There are several ways the plugin provides to do that.
If the object is instantiated, and has the sguid property (and the variable holding the object is marked ‘Save Game’),
If the object class is a child of ‘Auto Respawn’ class and/or is in the auto respawn list, that object will be managed by the plugin… respawned then loaded from save file.
If that is not working for you, there could be a conflict between your object’s lifetime and saving/loading.

Anyway, you can as well save and load by hand any hierarchy of instances of objects.
Here’s a manual example, I use “Save Game Instance” node from somewhere, and the Game Instance class has the “Serializable” interface implemented:

When the instance of Game Instance object is loaded, it fires from its own interface a call to “On Loaded” event, from where it loads from Slot subsequent objects it owns;
When saving I use “Save Object Hierarchy” just for the sake of example (every children of that object instance owned by the Game Instance will be saved to disk):

There are several projects manually saving/loading hierarchy of items similar to this simple example above.

So I set everything up based on the example you shared, but the OnSaved/OnLoaded events are never being triggered. I even tried setting this up in a clean project to make sure nothing else was interfering with it, but I got the same results. Any ideas as to what would cause this?

I will look in source code to see if something is wrong, I still didn’t have the time to sit down and see try the issue with Data Assets, so I hope the check both issue this week.

@thatdevjeremy I was looking in code and, for that “Save Game Instance” node, the events “On Prepare to Load” and “On Prepare to Save” on the game instance should work on example I gave there. Just replace the events from screenshot above.

Ok, seems to be progress there. When I hit the “Load Object” node, it is entering the “Failed” state. When checking the output log, the only notice I have is the following:

Looking at the save data, the SGUIDs for all of my objects match what I’m expecting to see. I feel like I must be missing something obvious at this point…

If you email me screenshots of what you’re doing will be easier for me to help.
A sample level (zipped project) that I can edit and send you back is even better.

Hey [USER=“434”]BrUnO XaVIeR[/USER] I’m using ue 4.25.4 and savior 3.1.0.
I tried to save array of UObjects and after adding my base USaveableObject that has SGUID it passed my unit tests.

Problem is that after restarting project tests failed. I checked and saw that every time a restart project, classes added to Instance Scope and Respawn Scope in project settings are changed to None. It seems that Engine classes stay but classes from my project or plugin are changed to None after restarting the project.

I was able to reproduce it using a fresh version of Your demo project from the Marketplace page.

Is there something I do wrong that I was unable to find in this thread, or is it seems to be some problem with plugin/ or my configuration? I didn’t test it on a different computer.

Detailed info:
[SPOILER]
Reproduction steps:

  1. Open freshly downloaded demo project using ue4.25.4 with savior 3.1.0 installed in the engine
  2. Create new C++ class based on UObject named MyObject and place it in default source localization.
  3. Go to Project Settings -> Savior 3 Settings
  4. Add MyObject to Instance Scope Array
  5. Add MyObject to Respawn Scope Array
  6. Close Project
  7. Open Project

What Happened?
New values in both arrays are now None

What Should Happen?
Both arrays should keep their values being MyObject

Config file seems to be saved correctly:
“\Savior_3.0.0_Demo_UE4.25\UE4_25\Saved\Config\Windows\Game.ini”



[/Script/Savior3.Savior3Settings]
<Part omitted>
InstanceScope=(Class'"/Script/Savior3.AutoInstanced"',Class'"/Script/SAVIOR2_Demo.MyObject"')
RespawnScope=(Class'"/Script/Engine.ActorComponent"',Class'"/Script/Engine.Actor"',Class'"/Script/SAVIOR2_Demo.MyObject"')

[/SPOILER]

That will happen because the filter is a ‘TSet<TSubclassOf<UObject>>’ property.

You have two options to solve this:
1: Create a Blueprint class from your C++ UObject class and use it.
2: Make your UObject class a child of UAutoInstanced class.

This default base class is a UObject that already implements Serializable interface for you:



class *UAutoInstanced *: public *UObject*, public *ISAVIOR_Serializable*
{
    //
}




UCLASS()
class MYGAME_API UMyBaseObject : public UAutoInstanced {
    GENERATED_BODY()

public:
    UMyBaseObject()
    {
        //...
    }

};


Do **not **add Auto Instanced classes to Respawn Scope.
That is redundant configuration, the plugin will ignore you, because it only respawns Actors or Components (into the World). UObjects go into *Instance Scope *because they will be recreated regardless of having active UWorld. In other hand if you add AActor or UActorComponent classes into Instance Scope you’re probably going to hard crash the engine.
I know there should be better filters for this, but some project architectures forbid me from enforcing strict filters there.

Thanks! Derivating my UObject from UAutoInstanced worked like charm.
Thanks for Your hard work, great plugin, and fast support!
Have a nice day!

@dzarafata Glad to help :slight_smile:
[HR][/HR]
@thatdevjeremy I got your sample zipped project; I did a quick edit of things that were missing, and took a few screenshots that I later will try to illustrate what is missing.

However, I do understand what you are trying to do.
So instead of forcing you to implement workarounds, I have included into the “Save Game Instance” node the ability to invoke the “On Loaded/Saved” interface events, this will make your setup easier to achieve.

So, I will send Epic Games an update, once you have the update in hands I send back to you the edited project with a few comment blobs and the screenshots with some info on what you were missing. With the extended node the interface call will be executed the way you expect:

[USER=“434”]BrUnO XaVIeR[/USER]
I’m using ue 4.25.4 and Savior 3.1.0

I have a problem with respawning Actor. Below You can see the code of my Unit Test, the code of the Actor I’m respawning, and the changes I made to save the slot.
If I understand correctly, the Actor variable should be set to reference a newly respawned actor after loading the game.

After Destroying Actor, but before loading the game Actor reference is set to None.
After loading the game new actor with the same SGUID and name ending with C_1 is spawned on the map but the Actor reference in the test is set to the old value (ending with C_0, marked for destroying)
The actor is respawned on the level and SaveGame variables are properly restored.

Should the Actor reference point to a new respawned actor after loading the game or is it something I have to do manually?

BP_TestSavableActorBPOnly is direct child of AActor. SGUID is marked SaveGame

@dzarafata “Create SGUID Once” does not care about “C_1”, “C_0”, “C_2”, etc…

If distinction of these instances are important for your case, you should replace “Create SGUID” node, use new node “Make SGUID” with ‘Mode’ set to “Resolved Name to GUID”;

“Resolved Name to GUID” mode will create a fixed SGUID value that will be unique for each instance ending “C_xx”.

[USER=“434”]BrUnO XaVIeR[/USER] Hey, the problem is that the reference is invalid (IsValid return false).

On screenshots You can see that the actor is respawned but the Actor variable is not valid

ActorsList.png

If I understand correctly, after loading the game Actor variable should become valid reference to respawned actor, is that correct?

PS: Is that new node available in the newest Savior 3 version for ue4.25?

That will depend on a few factors:

  • “Actor” property is checked as ‘Save Game’.
  • The instance respawned successfully.
  • The “Actor” property is loaded AFTER instance was respawned.

Some projects cannot control third factor, so what some do is uncheck ‘Save Game’ on the “Actor” property and from the new instance’s “On Finished Respawn” event the spawned actor assign itself to the external property.

There’s a bit of a discussion about this here:
https://forums.unrealengine.com/unreal-engine/marketplace/1467088-plugin-savior-3?p=1842395#post1842395

[USER=“434”]BrUnO XaVIeR[/USER] Hi, now after setting actor data in OnFinishRespawn.
TestedActor is still invalid during assertion.

I unchecked SaveGame from TestedActor variable.

while debugging, the order of execution is:

  1. Load Game
  2. Set Tested Actor which set TestedActor variable as a correct reference to newly respawned actor
  3. Load Game again (perhaps due to the async nature of it),** in this step TestedActor value is changed again to reference destroyed actor and is invalid**
  4. Assertion that fails

Do I have also to add some delay before calling SetTestedActor? That would be super nasty.
Coupling actors that need to respawn and both ways with its users seems bad enough already…

Here is example project using Savior 3.1.0 with unit test showing the problem if it can help You help me. SaviorProblemExample.zip (105 KB)

In your graph you are ignoring the fact that Actor spawning is an expensive operation and they don’t spawn immediately.

Spawn will never be completed on the same frame it began, so your assertion will always fail.

The loading process can also be finished while respawned Actors are still being allocated by the engine.

[USER=“434”]BrUnO XaVIeR[/USER]
a) I thought that OnSuccess will fire after loading and respawning all actors. Does it mean that it can fire before that?

b) I posted the order of the execution I get while debugging this code step using breakpoints. Please read it carefully and You will see that in this case assertion fired **after **calling SetTestedActor.

c) Adding a 3 seconds delay before assertion didn’t help (which is obvious if You look at the execution order in my last post)

Is the property the only reference to the Actor?
Is it actually respawning after you unchecked ‘Save Game’ on the property?

I can’t try the test project right now (I am away from PC)

TestedActor is the only variable keeping reference to this actor and it has SaveGame unchecked

TestedActor has only one field, which is a reference to AutomationTestActor that spawned it, so it can tell him that he respawned.
This field has SaveGame checked.

TestedActor respawns correctly. can be located on level and calls SetTestedActor.
There is print in SetTestedActor that prints validity of new value and it’s always true
(For some reason sometimes BP debugger seems to ignore breakpoint inside SetTestedActor function, but the print is always printing the value)