[PLUGIN] Savior

On project settings, you can edit Savior settings.

Set the supported base classes that can be respawned from scope.
There’s a filter there for both Actor classes and Components that can be respawned…

And on Slot class, you can define a filter of classes that can be saved to that Slot.

Both filters are set to AActor and UActorComponent base classes, by default.
You can pick only the base classes that matters to your design.


Anyway, I will check the code and see if mistakes there are made.

Inside RespawnActorFromData, we can change this section:

	bool GUID = false;
	for (TActorIterator<AActor>Actor(World); Actor; ++Actor) {
		if ((*Actor)->HasAnyFlags(RF_ClassDefaultObject|RF_BeginDestroyed)) {continue;}
		if (Reflector::MakeActorID(*Actor,true).ToString()==Data.FullName) {GUID=true; break;}
		if (IsMatchingSGUID(Data.GUID,*Actor)) {GUID=true; break;}
	} if (GUID) {return;}
	
	UObject* OTR = nullptr;
	for (TObjectIterator<UObject>OBJ; OBJ; ++OBJ) {
		if (Reflector::MakeObjectID(*OBJ).ToString()==Data.OuterName) {OTR=(*OBJ); break;}
	}

To this, reducing overhead. But that may cause bug with Child Actor Components:

	bool GUID = false; UObject* OTR = nullptr;
	for (TActorIterator<AActor>Actor(World); Actor; ++Actor) {
		if ((*Actor)->HasAnyFlags(RF_ClassDefaultObject|RF_BeginDestroyed)) {continue;}
		if (Reflector::MakeObjectID(*Actor).ToString()==Data.OuterName) {OTR=(*Actor); continue;}
		if (Reflector::MakeActorID(*Actor,true).ToString()==Data.FullName) {GUID=true;}
		if (IsMatchingSGUID(Data.GUID,*Actor)) {GUID=true;}
	} if (GUID) {return;}

Please try latest update and see if you still face the same issue.

Thanks for the update. Just got my covid booster so I will probably get around to it tomorrow.

This fixed it! Back in the single millisecond range. If I see any strange behavior with Child Actor Components I will let you know. Thanks for the help!

1 Like

Hi Bruno. After several updates of the savior, I returned to work and noticed that after loading some of the actors not loaded. Previously, everything worked. And so I tried to do some work on the errors thinking it was my fault. And I found that when saving, I have all the actors and each has a unique SGUID, this is also confirmed in the save file.
And during loading, I lose about half of the actors and components, there is no log of loading the missing actors and components in the loading logs.
For loading, I use node Load Game World [+ Callback], also in Scope the actors loaded by parent are specified. What could be the problem?

@CHERI1230 are you saving new files or are you trying to load old save files?

Please email me the save file so I can take a look.

No ,I am creating a new save game. I sent you a message with save slot.

It’s the change a few posts above that caused you issues.
I will investigate a way to merge it without causing errors for either case.

There were a few issues on the plugin due to last changes which I am rolling back for Unreal 4.26 and 4.27.

There was a bug caused by invalid ObjectIDs when creating Outer paths, causing records to overwrite each other in some cases. So I fixed that and submitted v3.9.2 for review.

Apparently some folks cannot read code that is not Microsoft standard.
I have a custom auto format script that I created for ultrawide screens I use, but that seems to cause issues for some people…

They don’t know how to auto format a source file, so I switched back my LLVM script to use Microsoft standard style again, to give them an easier time when they try to modify the plugin.

I’d like to recommend making this change to your MakeActorGUID logic:

Heres our use case:
So I’ve put the MakeActorGUID in PostInitProperties so I can abstract the GUID generation and exposed the GuidGenerationMode as a property so derived blueprints can change it. The issue we are having is that when the CDO runs this, the default value is StaticNameToGUID so it generates a GUID as expected. However, when any blueprints that are derived from this class that have a setting other than StaticNameToGUID (i.e. ResolvedNameToGUID), your MakeActorGUID function first checks the CDO for a valid SGUID and sees that one was already generated (from StaticNameToGUID) and simply returns it, when actuality I want it to generate a new one based on the ResolvedNameToGUID method.

image

@Get_Gooder I cannot look into this at the moment; but I will keep noted and investigate when I have the time. Thanks!

No worries! Also, for whatever reason, any time I attempt to make any changes to Savior3.cpp it fails to compile with the following error:

Savior3.cpp(5387): [C4506] no definition for inline function ‘const FString Reflector::SanitizeObjectPath(const FString &)’

Any ideas why this is happening or how to fix it?

delete “inline” from declaration at the end of Reflector.h;
and delete precompiled, PCH, intermediate files before compile.

Hi, I have just purchased this plugin, I have followed the first steps (Sguid) but It seems it doesn’t work… on my game mode.

  • I have created a Game mode (My_GameMode)
  • I have added the SGUID, save tag enabled, instance editable in My_GameMode (enum is Stati Name to GUID);
  • MyGamemode has the interface (Seriazible and Procedural); interface event works;
  • I have add a simple variable in my Game Mode (an integer - MyTest);
  • I have added the tag save game to such variable (MyTest - Savegame)
  • I have enabled log deep from slot1 (where slot one is a savior file system)
  • When I save, I can see the variable is saved;
  • When I load the variable is not loaded.

This is the game save log:

SaviorLog: {S}:: SAVED DATA for My_GameMode :: {“Test”:0}

This is the game load Log:

SaviorLog: {S}:: UNPACKED DATA for GameInstance_59 :: {}

Also:

I did the same steps in the player blueprint (third person character) and thing there works: one thing I have noticed is that in log the player bp is named ThirdPersonCharacter_My_00000303000002B9000002A200000248.
On the other hand my game instance is labelled as

SaviorLog: {S}:: UNPACKED DATA for GameInstance_59 :: {}

I guess I am doing something wrong in the sguid of the Game mode not reporting the right SGUID. But what??

I am getting a bit crazy here: what am I missing?

Could you help me?

Thanks


After reading post n. 612 I have changed in my construction script of Game Mode the node and switch to Make once Sguid which seems to work.
May I ask why?

In the Editor every time you click Play… the editor creates a new instance of your GameInstance. The “Make Once” node does not care about the IDs of existing objects of the same class, so its generated Guid is a constant in the Editor just like at runtime.

Think I may have found a bug. The first time I call the [SAVIOR] Load Game World (Async) node, the On Success/On Failure delegates never fire. However, all subsequent calls work as expected. This may be the case for other Load async nodes (haven’t tested), but it doesn’t seem to be a problem for the Save async nodes.

Usually these errors with async delegates on Editor is that a PIE session was interrupted in the middle of an async work so the plugin did not have a chance to reset the static “thread safety state” internal enum that it uses…

It’s static, so it stays there until an Editor reboot.

This is 100% reproducible in our project even from a fresh reboot of the editor. Are you suggesting that we are doing something wrong? If so, what might cause this (calling 2 async Savior nodes at the same time, ect.)?