[PLUGIN] Savior

I will edit the source this next weekend to make it trigger interfaces, so you don’t have to forcefully use Load Game World.

Oh, that’s nice.
I just added OnPrepareToSave() to SaveActor() and it seems to trigger. (it seems to trigger too many times and not the right way to do it and I’ll let you take a look ^^ )

Will you also implement the auto component recreation? That will be super if possible. Yeah, I can probably do but doing it myself would not be easy to deal with name clashes and such. I had a few issues with it already and that’s the reason why I wanted to use your asset. Yeah, there is SGUID to help but I’m not very comfortable with it yet.

Many thanks for the support.

Yes, I will try to make it work.
Will let you know if I get it done. Changes requires lots of testing, they might break something to somebody else…

Sure, sometimes it’s inevitable in SW business. ^^
But I’m sure it’s good for everyone down the road.
We can do this privately until we make sure it works if you want.

@ChrisK

I have modified the “Load Actors of Class” function to do what you need.
This node will respawn actors from records (when the GUID of the Actor doesn’t exist yet in the World) and will also respawn Actor Components that are missing and have implemented in the Component Class the Procedural Interface before loading hierarchy data:


You could use already existing nodes (or c++ functions) to do the same, but I know might be confusing to deal with the concurrency of multiple threads the plugin might be running…

So in this function RespawnActorsHierarchyFromData(…) I put everything together to run from within the main Game Thread, so you ca invoke it from anywhere if needed.
To save, you can use any existing Save function from the plugin, you have to make sure the Components have SGUID property and implement the Procedural Interface.

Also make sure that on your project settings, the plugin has authority to respawn components and the classes are listed in allowed Scope (or a parent class such as the base class ActorComponent).


I will run some tests tomorrow, if it’s all fine I submit an update to the Marketplace next Monday.

Hi,
Cool! It’s really awesome.
Right now, I need to save/load a single actor. I hope it also includes a support for a single actor (vs. actors of Class) to make it symmetric.

Cheers!

I would create a blueprint / subclass just for that singleton actor, at least for now.

The reason why I injected the code into that function is because it is not used by the main multi-threaded Load World pipeline, so the risk of affecting somebody else’s project is diminished.

1 Like

Hi!

I couldn’t find a place to submit bugs for the plugin anywhere so I’ll do it here:

When saving with the Save Game World (Async) node, when using the Save Slot Meta option, the “play time” variable of the save slot doesn’t get saved to disk, while at least the chapter, progress, and save date variables do.

Using Savior 3.

Thanks, I will add this to my notes and test it later. :+1:

Hi Bruno, love what you do man,

However recently I have had few crashes with the savior when attempting to “save game world”, crashes and logs didn’t give me much clue but after doing quite a bit of testing I realized it may have to do with a structure containing another structure, can’t find much info on this topic on the forum (huge apologies if I am blind), would I be correct to assume this can cause crashes?

If so anyways around it? Or would I have avoid using them?

I can’t know without a crash log file.

If you have a crash while using the plugin, email me the logs so I see why it happened.

@SirJackson from the logs you sent me… There’s these problems:

(not plugin, but causes crash because of this)

[2021.12.01-10.33.25:430][  0]LogProperty: Error: FStructProperty::Serialize Loading: Property 'StructProperty /Game/Blueprints/PlayerCharacterBP.PlayerCharacterBP_C:OrderList.OrderList_Value'. Unknown structure.
[2021.12.01-10.33.25:430][  0]LogProperty: Error: FStructProperty::Serialize Loading: Property 'StructProperty /Game/Blueprints/PlayerCharacterBP.PlayerCharacterBP_C:CompletedOrders.CompletedOrders_Value'. Unknown structure.
[2021.12.01-10.33.25:451][  0]LogProperty: Error: FStructProperty::Serialize Loading: Property 'StructProperty /Game/Blueprints/PlayerCharacterBP.PlayerCharacterBP_C:GetItemCountCompletedOrder:CallFunc_Map_Find_Value'. Unknown structure.
[2021.12.01-10.33.25:460][  0]LogProperty: Error: FStructProperty::Serialize Loading: Property 'StructProperty /Game/Blueprints/PlayerCharacterBP.PlayerCharacterBP_C:NewCompletedOrder:K2Node_MakeStruct_ST_Orders'. Unknown structure.
[2021.12.01-10.33.25:460][  0]LogProperty: Error: FStructProperty::Serialize Loading: Property 'StructProperty /Game/Blueprints/PlayerCharacterBP.PlayerCharacterBP_C:GetCompletedOrder:Order'. Unknown structure.
[2021.12.01-10.33.25:460][  0]LogProperty: Error: FStructProperty::Serialize Loading: Property 'StructProperty /Game/Blueprints/PlayerCharacterBP.PlayerCharacterBP_C:GetCompletedOrder:CallFunc_Map_Find_Value'. Unknown structure.
[2021.12.01-10.33.25:460][  0]LogProperty: Error: FStructProperty::Serialize Loading: Property 'StructProperty /Game/Blueprints/PlayerCharacterBP.PlayerCharacterBP_C:Delivered:CallFunc_GetCompletedOrder_Order'. Unknown structure.
[2021.12.01-10.33.25:464][  0]LogProperty: Error: FStructProperty::Serialize Loading: Property 'StructProperty /Game/Blueprints/PlayerCharacterBP.PlayerCharacterBP_C:OrderTotal:CallFunc_GetOrder_Order'. Unknown structure.
[2021.12.01-10.33.25:465][  0]LogProperty: Error: FStructProperty::Serialize Loading: Property 'StructProperty /Game/Blueprints/PlayerCharacterBP.PlayerCharacterBP_C:NewOrder:K2Node_MakeStruct_ST_Orders'. Unknown structure.
[2021.12.01-10.33.25:465][  0]LogProperty: Error: FStructProperty::Serialize Loading: Property 'StructProperty /Game/Blueprints/PlayerCharacterBP.PlayerCharacterBP_C:GetOrder:Order'. Unknown structure.
[2021.12.01-10.33.25:465][  0]LogProperty: Error: FStructProperty::Serialize Loading: Property 'StructProperty /Game/Blueprints/PlayerCharacterBP.PlayerCharacterBP_C:GetOrder:CallFunc_Map_Find_Value'. Unknown structure.
[2021.12.01-10.33.26:466][  0]LogProperty: Error: FStructProperty::Serialize Loading: Property 'StructProperty /Game/UI/OS/OS.OS_C:PopulateOrders:CallFunc_Map_Find_Value'. Unknown structure.
[2021.12.01-10.33.26:467][  0]LogProperty: Error: FStructProperty::Serialize Loading: Property 'StructProperty /Game/UI/OS/OS.OS_C:PopulateOrders:CallFunc_Map_Find_Value_1'. Unknown structure.

(and from plugin, but this is crash avoidance)

[2021.12.01-10.34.21:060][822]SaviorLog: Warning: {S}:: Unreal Engine explicitly disallows serializing ASCII Object References (when members of User-Defined Structs) so this Struct Member will NOT be saved:  StaticMesh_20_447B30F14ACE56347B03448D6E79F6FD
[2021.12.01-10.34.21:060][822]SaviorLog: Warning: {S}:: Unreal Engine explicitly disallows serializing ASCII Object References (when members of User-Defined Structs) so this Struct Member will NOT be saved:  Picture_42_EA8EEBEC40B15677CDEB33A6E451A56B
[2021.12.01-10.34.21:060][822]SaviorLog: Warning: {S}:: Unreal Engine explicitly disallows serializing ASCII Object References (when members of User-Defined Structs) so this Struct Member will NOT be saved:  StaticMesh_20_447B30F14ACE56347B03448D6E79F6FD
[2021.12.01-10.34.21:060][822]SaviorLog: Warning: {S}:: Unreal Engine explicitly disallows serializing ASCII Object References (when members of User-Defined Structs) so this Struct Member will NOT be saved:  Picture_42_EA8EEBEC40B15677CDEB33A6E451A56B
[2021.12.01-10.34.21:060][822]SaviorLog: Warning: {S}:: Unreal Engine explicitly disallows serializing ASCII Object References (when members of User-Defined Structs) so this Struct Member will NOT be saved:  StaticMesh_20_447B30F14ACE56347B03448D6E79F6FD
[2021.12.01-10.34.21:060][822]SaviorLog: Warning: {S}:: Unreal Engine explicitly disallows serializing ASCII Object References (when members of User-Defined Structs) so this Struct Member will NOT be saved:  Picture_42_EA8EEBEC40B15677CDEB33A6E451A56B
[2021.12.01-10.34.21:060][822]SaviorLog: Warning: {S}:: Unreal Engine explicitly disallows serializing ASCII Object References (when members of User-Defined Structs) so this Struct Member will NOT be saved:  StaticMesh_20_447B30F14ACE56347B03448D6E79F6FD
[2021.12.01-10.34.21:060][822]SaviorLog: Warning: {S}:: Unreal Engine explicitly disallows serializing ASCII Object References (when members of User-Defined Structs) so this Struct Member will NOT be saved:  Picture_42_EA8EEBEC40B15677CDEB33A6E451A56B
[2021.12.01-10.34.21:060][822]SaviorLog: Warning: {S}:: Unreal Engine explicitly disallows serializing ASCII Object References (when members of User-Defined Structs) so this Struct Member will NOT be saved:  StaticMesh_20_447B30F14ACE56347B03448D6E79F6FD
[2021.12.01-10.34.21:060][822]SaviorLog: Warning: {S}:: Unreal Engine explicitly disallows serializing ASCII Object References (when members of User-Defined Structs) so this Struct Member will NOT be saved:  Picture_42_EA8EEBEC40B15677CDEB33A6E451A56B

So you have a bad Struct Blueprint somewhere, corrupted for whatever reason, that you use as a Key to a Map property.

And you are trying to save raw object pointers within Structs that’s not supported (use Soft Object References within Structs instead).

Thank you very much for your email and reply here, clarified a lot for me Bruno

1 Like

@ChrisK just one more thing…
In your particular case, you might want to comment out the line 290 on Reflector.cpp:

//if (Reflector::MakeComponentID(*OBJ,true).ToString()==Data.FullName) {GUID=true; break;}

I have seen some project need this line in, others need it out.

Hi, Bruno, thanks for the heads up. I’ll give it a try and let you know how it goes.
Have a good weekend.

Just a tiny update on the situation in case anyone else has to deal with this, I am sure this is an UE4 problem more than anything, but I fixed the corrupted struct and used soft object references in the struct, still was having crashes when saving the game, even after deleting the save files.

I managed to understand where the issue was after quite a few hours of testing, when I used the “Remove” node on my map to remove an element from the map then pressing save, the game crashed, even if I gave it some time before saving. Instead, I stopped using maps and resorted to array of structs and all started working fine, no more crashes!

Using “Clear” on the map didn’t cause crashes, but “Remove” did.

This only happened to maps that had a key of string, name (and other primitive types) and value of structs.

Hope this helps someone, sometime

2 Likes

Hi, Bruno, I tried the new version over the weekend and I have loads of issues.
First of all, here are my setup.

  1. I added SGUID to the component with SaveGame.
  2. I set the Component Scope and Actor Scope to the base classes to my actor and component.
  3. I instantiated Slot with Complex type and called SaveActorHierarchy.
  4. I verified that it saved all the components and SGUID looked all fine.
  5. Problem 1: My component(dynamic) is derived from StaticMeshComponent and it doesn’t seem like to save any info regarding the StaticMesh.

Now I’m trying to load the actor.

  1. I call LoadActorsOfClass and I traced to see what it’s doing.

  2. Problem 2: In LoadComponent, it cannot find the ComponentID from SlotData and it just returns with Failed result.

  3. Problem 3: LoadComponent gets called on the same component multiple times (about 3 I think)

  4. Problem 4: LoadComponent fails to find ID, however, it spawns the Actor anyway. It spawns multiple times and I get several duplicated actors after loading.

  5. Problem 5:
    I think there is a problem when storing the slot or loading the slot.
    When I looked at the loaded SlotData.Complex array, the size is about 500 and it seems many duplicated info. I could not tell exactly but at least when I looked at the array name, the component name is repeated many times (about 5 times). Perhaps it’s because you are storing each component piece-by-piece.

Thanks for your support.

Update 1: About Problem 2, I changed FullPath argument to false to see if helps but it didn’t. I cannot use FullPath because the actor has to load from a different map anyway.

Update 2: I tried to change the Compression type to Minimal to see what happens. It saved components are not even on the list from the loaded Actor. I just see one component, SpringArm, of which I didn’t even want to save.

Update 3: About Update 2, I found a bug. In LoadActorHierarchy, around line 1013, Components = Actor->GetComponents(); needs be moved to below “for (auto Sub : Attached) …”. Components can be overwritten by it. It was causing why I only had one Component loaded. I’m still seeing nothing because StaticMesh is not being saved/loaded. BTW, Why isn’t OnBeginRespawn callback function called back on the component? I’ve added the interface and added the implementation.

Update 4: About Problem 2, my component class name has underscore. The ComponentID generated from MakeComponentID shows only the front part of the class name. Could this be why it cannot find the component from SlotData?
The component name is BxPart_CoaxGun, but CoaxGun is chopped off because it matched “_C” split.

Update 5: About Problem 3, I verified that LoadActor is getting called multiple times ( 5 times to be exact). And I think the reason is because SaveActorHierarchy saves the same actor 5 times. I tried to look at the .sav file and I see it repeated 5 times.

How is an actor child of Mesh Component?

I will have to make more tests, if you can share the blueprint class you use so I can take a look inside, would be great.

Opps, sorry, it’s a typo. It is a component. I’ll update it.

My BP isn’t anything special but it’s my actor with the dynamic components.
As I mentioned earlier, I’m trying to build a vehicle with parts dynamically. The component just has StaticMesh with some properties and they are layered with many levels of hierarchy. That’s pretty much it.

One thing to note is that, the component uses Scale information. I guess I need to use Complex type but then I need to load the actor from different maps. I’m not sure which is the right approach. Should use Minimal but add Scale info? or use Complex but use non-FullPath?

Oh, I forgot one thing. Some components have an attached Actor, a Camera Actor. Could this be a reason why it saves the Vehicle Actor multiple times?

Did you try it without adding SGuid to the component class?
_C should not be cut if there’s no SGuid on the components.


Then the ID would be MyActor_GUID__ComponentID, no Component Guid, but + C_1, C_2 on the component ending.