[PLUGIN] Savior

Why can’t I save the camera transform even I add interface to controller?

The “camera boom” will overwrite the values saved for camera position.
The same principle applies, if the plugin doesn’t record this thing, you can create a property in character or controller and once the save was loaded you can re-apply the saved value.

Submitted v2.9.0 update with major fix for “auto destroy” mechanism and the “Procedural” interface events that were not firing properly due to previous changes to the SGuid usage (check past posts above).
I take save file incompatibility very seriously and I try my best to never break old save data, but this time I cannot achieve that unfortunately…

WARNING!!

So, if you have live project and don’t want to risk compatibility issues in old save files, I recommend you make a backup before you try v2.9.0.
I do not plan to push any serious updates anymore this year, exactly to keep save files compatibility as solid as possible across engine versions.

Hi Bruno!
I can’t get your procedural actors to work, but a actor without procedural interface etc spawned at runtime works as expected.
I see in the above post that you have submitted a fix for procedural interface etc, has it been approved by epic yet? I can’t see a pending update in the epic client.

My tests:
A: I applied what you wrote in the procedural tutorial on my base class BP_Character. I create a child actor named NPC_Grunt1 from BP_Character. I spawn NPC_Grunt1 from a spawner blueprint on begin play. I make NPC_Grunt1 run after me, then i save and exit. When I load back he doesn’t stand where I left him, but stands on the spawner again.
Both BP_Character and NPC_Grunt1 are added to the Savior II asset I load and save to.

B: If I DON’T implement the SAVIOR_Procedural interface, and DON’T assign a SGUID to the base class, NPC_Grunt1 works as expected and stays where I left him.

Since the only difference between A and B is that A has procedural actor stuff setup while B don’t, I think that there is an issue with your procedural actors implementation.

Hello!
Not approved yet, I am still waiting on Epic to review the update and publish 2.9.0.
They take a few days, plugin updates are a bit complicated to process…

Yes, at the moment the procedural interface is broken.
The fix in 2.9.0 is a rework to make it do its jobs correctly.

Right now the plugin acts like: "-Oh this is going to crash the game, I won’t do this, skipping…"

Once the update is released please let me know if everything back to normal or you see another anoomaly.

I got a notification that the update was processed.
Should be available on Launcher now :slight_smile:

Great I got the update!
But now instead of getting to the position I left them at, the game crashes as soon as I load. It’s on a fresh save too.

Happened when procedural actor implemented fully like in docs. I pulled enemies, saved the game, then loaded the game, crash happens.
As soon as a SGUID id is assigned and I try to load the file, it crashes. I even disconnected the “Load Actor” node, so I think the error happens due to the SGUID.

I sent an attachment .zip with the crash logs

I will try to:

  • Update UE4.24 to latest version
  • Reinstall plugin

Those logs don’t give me any insight on when the crash happens.
There’s only a ton of warnings about missing blueprints and these:



LogScript: Warning: Script Msg: Attempted to access index 1 from array 'HitFlashDynMats' of length 1 in '/Game/Blueprints/BP_Character.BP_Character_C'!


The plugin have its own log category, there should be something pointing to it in Saved/Logs folder.

Updating the engine version fixed it somewhat, but if I load a few times it eventually crashes. Like 20% risk of crash. Here’s a screencapture of my logs folder, any of these the one? In the CombatGame_2 log file I found some mentions of “Savior”, attached it

The logs you sent me are from March 31 :slight_smile:

I found out how to avoid the crash. A related issue now. I can’t seem to keep references to procedural actors after loading the game… Like in the attached image I simply try to spawn an enemy if my reference is invalid… And it’s always invalid, despite me seeing that the “invalid” enemies standing where I left them. What should I do in these cases? Can I never keep a reference to procedural actors?

Image explanation:

  1. Is where spawners are. They spawned enemies and saved reference to them, I saved and loaded the game, they lost their reference and spawned new enemies.
  2. Is the enemies that the spawners should’ve had a reference to.

Hey Bruno! Love the plugin, I’ve been using it for a while now and it’s been overall fantastic.

I’m running into issues with saving/loading class references (purple pin type), and I was wondering if there’s something I’m missing.

I’m trying to simply save a variable of type class, and here are the results of some tests:

  • Class reference variable cannot be loaded
  • Class reference variable stored inside an array cannot be loaded.
  • Class reference variable stored inside a junk single-member struct cannot be loaded.
  • Class reference variable stored inside a junk single-member struct, stored inside a junk array (even with an array length of one) CAN be loaded

This seems very weird? Why would a struct wrapping the class reference fail, whereas an array wrapping the struct wrapping the reference will succeed to save/load correctly?

What’s more, I ran a simple test by grabbing All Actors of class type character and then for-each grabbed each of their class types, added that to a big “class reference” array, and attempted to save/load that.

Of the 81 Actor class references, my logs pointed out that about 50% of them saved as “nullptr::nullptr”, and the other half saved as “/Script/Engine.Default__BlueprintGeneratedClass::BP_Demo-Character” (exact same on load aswell) - but the editor array showed 81 entries of “None”.

Am I missing some setup in project settings or on the save slot file itself? Would really appreciate your input :).

@Fr0hst Class pointers need to be stored as soft references if you want to save them.
I did this because there is a very large amount classes in Unreal, iteration them all on every save could be too slow, although I have a @Todo to add them back someday when I find an algorithm fast enough to record raw class pointers.

How about object pointers for procedural actors? Is doing a get all actors of class + compare SGUID the way to go?

@Manspear your references are lost in arrays because the procedural spawned instances are not the same you had on save. Their internal object ID to the engine are different.
Instead of keeping an array of Actors your spawner should hold an array of GUIDs, then re-assign GUIDs that have been lost once loading was done.

@**BrUnO XaVIeR **That solved it, thanks for the help!
Now I think it would be nice with a “get object with guid” function to get the object reference, but I guess this is impossible because the object ID of the engine changes every time… In these cases is my only option to do “get all actors of class” → “compare GUID” → “if match save reference” ?

It’s not impossible, I will add to ToDo list.
But you should go on with your solution because I have no idea when that function will be included in plugin!

I don’t like my solution, so could I add that function to your plugin? I could send you my solution and you could release an update. Or is it super advanced deep level stuff that would take 20+ hours to implement?

I have no idea how complex it is, will know when I write it down…

If you know how to patch source code in Visual Studio and generate/replace DLLs you can totally do it yourself, the plugin is distributed with c++ sources included.

@**BrUnO XaVIeR **haven’t yet learned how to generate/replace DLLs,
but I made the “get object with guid” function in blueprint, it was pretty simple here’s how:

  1. In the game instance, create a map/dictionary with GUID as key, and UObject as value.
  2. Create a function library with AddGUIDObject and GetObjectWithGUID functions
  3. In a dynamic object: OnFinishRespawn -> Call AddGUIDObject where it adds itself and its GUID to the dictionary
  4. Wherever: after all objects got loaded: GetObjectWithGUID(GUID)

This was really easy. You could probably add the Dictionary to your “Savior Singleton” (if you have one). Automatically do the OnFinishRespawn -> Call AddGUIDObject in the C++ OnFinishRespawn function. Add the GetObjectWithGUID to your function library.

Neat thing is that the Dictionary doesn’t need to be saved in the savegame since it’ll be refreshed every time a load happens.