[PLUGIN] Savior

Which engine version did that happen?
What class is the entry object that happened, the class before entering plugin code.

Unreal 4.26.2
Savior 3.5.0

It looks like it is crashing trying to get the World.

Forgot debug symbols on new pc…

Full report:

Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0x0000000000000028

UE4Editor_CoreUObject!UObjectBaseUtility::GetTypedOuter() [D:\Build++UE4\Sync\Engine\Source\Runtime\CoreUObject\Private\UObject\UObjectBaseUtility.cpp:276]
UE4Editor_Savior3!USavior3::MakeActorGUID() [D:\Build++Portal\Sync\LocalBuilds\PluginTemp\HostProject\Plugins\Savior\Source\Savior3\Private\Savior3.cpp:2437]
UE4Editor_Savior3!USavior3::execMakeActorGUID() [D:\Build++Portal\Sync\LocalBuilds\PluginTemp\HostProject\Plugins\Savior\Intermediate\Build\Win64\UE4Editor\Inc\Savior3\Savior3.gen.cpp:771]
UE4Editor_CoreUObject!UObject::execCallMathFunction() [D:\Build++UE4\Sync\Engine\Source\Runtime\CoreUObject\Private\UObject\ScriptCore.cpp:930]
UE4Editor_CoreUObject!UObject::execLet() [D:\Build++UE4\Sync\Engine\Source\Runtime\CoreUObject\Private\UObject\ScriptCore.cpp:2655]
UE4Editor_CoreUObject!ProcessLocalScriptFunction() [D:\Build++UE4\Sync\Engine\Source\Runtime\CoreUObject\Private\UObject\ScriptCore.cpp:1067]
UE4Editor_CoreUObject!UObject::ProcessInternal() [D:\Build++UE4\Sync\Engine\Source\Runtime\CoreUObject\Private\UObject\ScriptCore.cpp:1155]
UE4Editor_CoreUObject!UFunction::Invoke() [D:\Build++UE4\Sync\Engine\Source\Runtime\CoreUObject\Private\UObject\Class.cpp:5588]
UE4Editor_CoreUObject!UObject::ProcessEvent() [D:\Build++UE4\Sync\Engine\Source\Runtime\CoreUObject\Private\UObject\ScriptCore.cpp:1992]
UE4Editor_Engine!AActor::ProcessEvent() [D:\Build++UE4\Sync\Engine\Source\Runtime\Engine\Private\Actor.cpp:864]
UE4Editor_Engine!AActor::ProcessUserConstructionScript() [D:\Build++UE4\Sync\Engine\Source\Runtime\Engine\Private\ActorConstruction.cpp:889]
UE4Editor_Engine!AActor::ExecuteConstruction() [D:\Build++UE4\Sync\Engine\Source\Runtime\Engine\Private\ActorConstruction.cpp:805]
UE4Editor_Engine!AActor::RerunConstructionScripts() [D:\Build++UE4\Sync\Engine\Source\Runtime\Engine\Private\ActorConstruction.cpp:523]
UE4Editor_Engine!ULevel::IncrementalUpdateComponents() [D:\Build++UE4\Sync\Engine\Source\Runtime\Engine\Private\Level.cpp:1135]
UE4Editor_Engine!UWorld::UpdateWorldComponents() [D:\Build++UE4\Sync\Engine\Source\Runtime\Engine\Private\World.cpp:1970]
UE4Editor_UnrealEd!UEditorEngine::Map_Load() [D:\Build++UE4\Sync\Engine\Source\Editor\UnrealEd\Private\EditorServer.cpp:2771]
UE4Editor_UnrealEd!UEditorEngine::HandleMapCommand() [D:\Build++UE4\Sync\Engine\Source\Editor\UnrealEd\Private\EditorServer.cpp:6204]
UE4Editor_UnrealEd!UEditorEngine::Exec() [D:\Build++UE4\Sync\Engine\Source\Editor\UnrealEd\Private\EditorServer.cpp:5705]
UE4Editor_UnrealEd!UUnrealEdEngine::Exec() [D:\Build++UE4\Sync\Engine\Source\Editor\UnrealEd\Private\UnrealEdSrv.cpp:697]
UE4Editor_UnrealEd!FEditorFileUtils::LoadMap() [D:\Build++UE4\Sync\Engine\Source\Editor\UnrealEd\Private\FileHelpers.cpp:2554]
UE4Editor_UnrealEd!FEditorFileUtils::LoadDefaultMapAtStartup() [D:\Build++UE4\Sync\Engine\Source\Editor\UnrealEd\Private\FileHelpers.cpp:4043]
UE4Editor_UnrealEd!FUnrealEdMisc::OnInit() [D:\Build++UE4\Sync\Engine\Source\Editor\UnrealEd\Private\UnrealEdMisc.cpp:359]
UE4Editor_UnrealEd!EditorInit() [D:\Build++UE4\Sync\Engine\Source\Editor\UnrealEd\Private\UnrealEdGlobals.cpp:115]
UE4Editor!GuardedMain() [D:\Build++UE4\Sync\Engine\Source\Runtime\Launch\Private\Launch.cpp:149]
UE4Editor!GuardedMainWrapper() [D:\Build++UE4\Sync\Engine\Source\Runtime\Launch\Private\Windows\LaunchWindows.cpp:137]
UE4Editor!WinMain() [D:\Build++UE4\Sync\Engine\Source\Runtime\Launch\Private\Windows\LaunchWindows.cpp:268]
UE4Editor!__scrt_common_main_seh() [d:\agent_work\5\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288]
kernel32
ntdll

Are you using MakeActorGUID() from C++ constructor or is it a Blueprint’s construct script?

I have both I think.

BTW, I just realized it doesn’t work on either computer.

This should stop the crash from happening within MakeActorGUID()
function:

UWorld* Outermost = nullptr;

if ( !Instance->HasAnyFlags(RF_ClassDefaultObject) )
{
	Outermost = Instance->GetTypedOuter<UWorld>();
}

That above replaces first line of the function.
I sent a a fix to Epic, but they take a while to review updates.

You’re awesome, thanks!!

Hey, I’ve got a weird crash using the OpenLevel blueprint nodes.
Using OpenLevel (by name) works fine.
Using OpenLevel (by reference) in a level blueprint works fine.
But OpenLevel (by reference) called from an Actor crashes in StaticLoadGameWorld(UWorld* InWorld) on the SECOND call. So yeah, super weird.

I put together a mwe with the three examples. Open “Map_Ref_WithActor_A” and press 1
twice should cause the crash unless the problem is somewhere on my end.

SaviorCrashTest.7z (274.1 KB)

EDIT: Might not even be worth looking into, converting the reference to name and calling OpenLevel (by name) was easy enough.

Looks like the plugin published but the problem persists.
I was able to delay the crash by changing my engine.ini to open in a map with only some meshes in it, but the crash still happens seconds after the editor opens.

Now the error is:

Unhandled Exception: EXCEPTION_ACCESS_VIOLATION reading address 0x0000000000000008

0x00007ffc4d6e985f UE4Editor-Savior3.dll!USavior3::MakeActorGUID() [D:\build++Portal\Sync\LocalBuilds\PluginTemp\HostProject\Plugins\Savior\Source\Savior3\Private\Savior3.cpp:2454]
0x00007ffc4d720522 UE4Editor-Savior3.dll!USavior3::execMakeActorGUID() [D:\build++Portal\Sync\LocalBuilds\PluginTemp\HostProject\Plugins\Savior\Intermediate\Build\Win64\UE4Editor\Inc\Savior3\Savior3.gen.cpp:801]

You have to make sure the object you call MakeActorGUID(…) function is valid in your C++ code.

If the Actor is null it’s going to crash.

I added a check to all of my C++ classes that call MakeActorGUID with no luck. Not sure what happened between 4.25 and 4.26 or when I updated Savior… but something doesn’t like it.

There’s something in your code somewhere calling the function with a nullptr actor.

I would comment out all calls to it until I figure out where it is happening.
The SGUID value can be generated manually, so I would do that while the bad code isn’t found.

I will submit another update which returns an invalid SGUID if the target Actor is nullptr;
but you still should search your blueprints to find where you are calling “Make SGUID” without any actor attached to the “Instance” pin.

Thanks, that update got me back in the editor.

I think it was actually a BP causing the problem. Before the update I started deleting BPs and was able to get back in when I deleted some UI.

When I got the update, I saw the savior log the invalid actor function call. I have a ui widget that receives a screen capture from an actor, and when I stopped calling makeGUID in that actors constructors, the log went away.

Thank you again for your help, I will keep an eye out for that log in the future. I think the problem is solved now on my end, I hope this added info about the BP helps.

1 Like

Hi,

does this plugin only allow saving to predefined slots or can we write to save files and load from those?
If yes, would you be able to point me in a direction on how to set that up please?
The demo project only shows a slot based approach.
Thanks!

You can create 1 single Slot preset and at runtime change its “Slot File Name” to whatever *.sav file name you want (exclude file extension). The slot will save to the named file.

1 Like

Thanks a lot!
Saving to individual *.sav files works well now.
Could you elaborate on how to properly load those?

There’s no change, the slot will load data from the Slot File Name when loading.
The nodes used are the same, Load World, etc.

1 Like

Thanks man!
That was too obvious and I totally missed that :slight_smile:

Great plugin - everything works as expected. Good job!

1 Like

Hey Bruno, hello hello from Brazil! :slight_smile:

I gotta say that Savior is impressive technology-wise, congratulations and thanks for taking the time to bring it to life!

A few questions for you:

  1. Should I assign SGUID to the UObjects I want to save as well? Pretty much, my Inventory System is a simple UObject.
  2. I have both an InventoryObject and an InventoryComponent (for when I want to attach the Inventory to Actors). That said, the way I instantiate the InventoryObject at the InventoryComponent is through the BeginPlay and I feel it is overriding anything that’s loaded from the disk. By chance, do you have any ideas about better behavior when it comes to that?
  3. How to assign dynamic SGUIDS to Components generated/attached in run-time? I mean, I know I can create the property and “Generate” a value - but what if I have two of the same components in a given Actor?

Now, if I may, here are a couple of suggestions as a sincere comrade customer.

  1. Would you mind going through some of the Load/Save Actor Hierarchy in your docs? I just discovered them by reading buried posts here and had to unselect “Context Sensitive” in order for them to show up. If it was mentioned earlier, I probably should have saved 1-2 hours of work.
  2. I guess you could improve your docs regarding SGUID a little bit. I mean, it was clear enough to me – except that I didn’t know I had to “Generate” a GUID at Components, and as I asked above, I still don’t know whether it’s required for UObjects to have SGUIDS as well.
  3. As my last suggestion: after reading this thread here, it’s clear to me that people don’t like to read. They asked you 1293719237 times the same thing - specially when it comes to SGUIDs - and it hurts me seeing you answering the same thing over and over again. That said, have you ever considered creating a 5-10 min video, introducing the initial setup and the basics of Savior? I’m really sure people will be happier and you would save yourself a lot of time. :smiley:

Anyways, that’s it!

Once again, thank you for this amazing plug-in and can’t wait to have your answers in hand!

Um abraço! :beers:

1 Like

Your UObjects should have SGUID and you should add the base class to Object Scope list to make them visible to the plug-in’s reflection system.

By default Object Scope list, on slots, is empty:

https://d3kjluh73b9h9o.cloudfront.net/uploads/default/original/3X/e/3/e3c17a99b63a9c3287b96c304c117f391d9e20f4.png


I would set SGUID to component as “Resolved Name to GUID” from Make SGUID" node…

Or maybe generating a value manually from C++ constructor if the inventory is really complex, as “Static Name to GUID” then add +1 to D piece of the Guid struct for each subsequent instance of same inventory component child of same Actor.

(the source code of MakeSGUID() function is in your package, so you could see how it works then create your own if needed).

I think I could add another mode in Make SGUID node to do that, this situation is currently not covered by the function.


The best solution would be me adding a nee mode to “Make SGUID” node to cover this.
Currently, if you want to do what I imagine, best workaround would be having a C++ base class of your Inventory Component and resolve IDs in class constructor.

If you do everything from Construction Script of parent Actor, you might end up impacting your runtime performance.


I will add this to To-Do list.

Your generated UObjects should be created having target Actor as “outer”, if the Actor is not the anchor of the generated UObject it might not be considered part of the hierarchy. So “Save Hierarchy” could give unpredictable results if the Inventory Object doesn’t respect that.


I just cannot afford to sit and make videos, because they will never cover every use case, all projects are different.
(and working a job also get in the way)

I like to answer targeted questions because questions can go surgically to the issue.
A video, I wouldn’t know where to begin because there are hundreds of projects using this plug-in, each their own way.

I could end up just confusing people instead of helping them to find the solution that better fit their particular project.

To sum it up: I have seen people do things with this plug-in that not even I understand, I can only give hints on what the plug-in is going to do behind it’s code and to get where you intend to go.
It’s a very broad range of customization that can be achieved. So it’s difficult for me to say “-look, this is how you use it.”