[PLUGIN] Savior

Cool, looking forward to it! Also we periodically get crashes when saving our game. Here is the stack trace:

FName::ToString(FString &) UnrealNames.cpp:2218
FName::ToString() UnrealNames.cpp:2209
FNameAsStringProxyArchive::operator<<(FName &) Archive.cpp:615
FStructuredArchiveSlot::operator<<(FName &) StructuredArchive.cpp:500
TProperty_WithEqualityAndSerializer<FName,FProperty>::SerializeItem(FStructuredArchiveSlot,void *,const void *) UnrealType.h:1192
FMapProperty::SerializeItem(FStructuredArchiveSlot,void *,const void *) PropertyMap.cpp:491
FPropertyTag::SerializeTaggedProperty(FStructuredArchiveSlot,FProperty *,unsigned char *,unsigned char *) PropertyTag.cpp:241
UStruct::SerializeVersionedTaggedProperties(FStructuredArchiveSlot,unsigned char *,UStruct *,unsigned char *,const UObject *) Class.cpp:1586
UStruct::SerializeTaggedProperties(FStructuredArchiveSlot,unsigned char *,UStruct *,unsigned char *,const UObject *) Class.cpp:1285
UScriptStruct::SerializeItem(FStructuredArchiveSlot,void *,const void *) Class.cpp:2775
FStructProperty::SerializeItem(FStructuredArchiveSlot,void *,const void *) PropertyStruct.cpp:152
FMapProperty::SerializeItem(FStructuredArchiveSlot,void *,const void *) PropertyMap.cpp:472
FPropertyTag::SerializeTaggedProperty(FStructuredArchiveSlot,FProperty *,unsigned char *,unsigned char *) PropertyTag.cpp:241
UStruct::SerializeVersionedTaggedProperties(FStructuredArchiveSlot,unsigned char *,UStruct *,unsigned char *,const UObject *) Class.cpp:1586
UStruct::SerializeTaggedProperties(FStructuredArchiveSlot,unsigned char *,UStruct *,unsigned char *,const UObject *) Class.cpp:1285
UObject::SerializeScriptProperties(FStructuredArchiveSlot) Obj.cpp:1467
UObject::Serialize(FStructuredArchiveRecord) Obj.cpp:1383
UObject::Serialize(FArchive &) Obj.cpp:1272
UGameplayStatics::SaveGameToMemory(USaveGame *,TArray<unsigned char,TSizedDefaultAllocator<32> > &) GameplayStatics.cpp:2093
UGameplayStatics::SaveGameToSlot(USaveGame *,const FString &,const int) GameplayStatics.cpp:2143
USavior3::WriteSlotToFile(const int,ESaviorResult &) Savior3.cpp:219
OnFinishSerializeGameWorld(USavior3 *,ESaviorResult) Savior3.h:1419
[Inlined] Invoke(void (*const &)(USavior3 *, ESaviorResult),USavior3 *const &,const ESaviorResult &) Invoke.h:51
[Inlined] UE4Tuple_Private::TTupleBase<TIntegerSequence<unsigned int,0,1>,USavior3 *,enum ESaviorResult>::ApplyAfter(void (*const &)(USavior3 *, ESaviorResult)) Tuple.h:306
TBaseStaticDelegateInstance<void __cdecl(void),FDefaultDelegateUserPolicy,USavior3 *,enum ESaviorResult>::ExecuteIfSafe() DelegateInstancesImpl.h:729
[Inlined] TDelegate<void __cdecl(void),FDefaultDelegateUserPolicy>::ExecuteIfBound() DelegateSignatureImpl.inl:599
[Inlined] FSimpleDelegateGraphTask::DoTask(Type,const TRefCountPtr<FGraphEvent> &) TaskGraphInterfaces.h:1215
TGraphTask<FSimpleDelegateGraphTask>::ExecuteTask(TArray<FBaseGraphTask *,TSizedDefaultAllocator<32> > &,Type) TaskGraphInterfaces.h:886
[Inlined] FBaseGraphTask::Execute(TArray<FBaseGraphTask *,TSizedDefaultAllocator<32> > &,Type) TaskGraphInterfaces.h:524
FNamedTaskThread::ProcessTasksNamedThread(int,bool) TaskGraph.cpp:710
FNamedTaskThread::ProcessTasksUntilQuit(int) TaskGraph.cpp:601
[Inlined] FTaskGraphImplementation::ProcessThreadUntilRequestReturn(Type) TaskGraph.cpp:1480
FTaskGraphImplementation::WaitUntilTasksComplete(const TArray<TRefCountPtr<FGraphEvent>,TInlineAllocator<4,TSizedDefaultAllocator<32> > > &,Type) TaskGraph.cpp:1531
FTickTaskSequencer::ReleaseTickGroup(ETickingGroup,bool) TickTaskManager.cpp:563
FTickTaskManager::RunTickGroup(ETickingGroup,bool) TickTaskManager.cpp:1584
UWorld::RunTickGroup(ETickingGroup,bool) LevelTick.cpp:784
UWorld::Tick(ELevelTick,float) LevelTick.cpp:1522
UEditorEngine::Tick(float,bool) EditorEngine.cpp:1732
UUnrealEdEngine::Tick(float,bool) UnrealEdEngine.cpp:423
FEngineLoop::Tick() LaunchEngineLoop.cpp:4916
[Inlined] EngineTick() Launch.cpp:62
GuardedMain(const wchar_t *) Launch.cpp:180
LaunchWindowsStartup(HINSTANCE__ *,HINSTANCE__ *,char *,int,const wchar_t *) LaunchWindows.cpp:262
WinMain(HINSTANCE__ *,HINSTANCE__ *,char *,int) LaunchWindows.cpp:320
[Inlined] invoke_main() 0x00007ff700347e8a
__scrt_common_main_seh() 0x00007ff700347e69
<unknown> 0x00007ffddc957034
<unknown> 0x00007ffdddea2651

That looks like you write to file while other node is still writing to the same file.
This is why I put the “thread safety” checks in there, to make sure multiple nodes won’t try to async write to the same file at the same time.

Hi Bruno. Starting from version 3.9.2, the Load Game World [+Callbacks] node does not make Finished Load Callback and On Secusses while the world is loaded, all my actors are loaded successfully and there are no errors or warnings in the plugin logs. Began Load Callback work fine.

Can you send me a log file showing when that happens?

And screenshot of where you’re calling the node from.

Thanks

Took me quite some time to figure out why, but everything was broken on Unreal 5.P2.
Respawning actors was broken, properties were “dead” with no record, actors were not recording location, etc…

Well, turns out Unreal 5.P2 is very different, “Float” properties of Blueprints are no longer floats, they are double precision now and I had to add support for this new property type and now it’s finally working:

Property->IsA<FDoubleProperty>() ?  // add to save..

Now values are restoring and auto respawn is working again on UE5.



2 Likes

Hi,

I’m having a hard time to get this working for my project.

What I want to achive:
I only want to save the Game-Mode, which is my Pawn, Controller, Instance and Gamemode.

The pawn spawns in Level 1, collects some items in his inventory, which is a Component of the PawnActor. The component has a variable inventory, which is marked as SaveGame.

When finished, the player moves to the next level via OpenLevel by entering an area. This is where I want savior to save the states. (Before calling open level ofc)

When the player then spawns in the next level, savior should reload the states.

What I have tried so far:

  • The PawnActor, GamemodeBP, ControllerBP have a SGUID var of type GUID, SaveGame checked
  • The SGUID is generated in constructor of them - Resolve Name to GUID
  • On Keypress I call SaveGameMode(Async)
  • On KeyPress I call LoadGameMode(Async) with Ignore Main Pawn Transform checked

My SaveSlot is setup this way:


The logs show, that child components of the PawnActor, e.g. the equipment component are ignored:

SaviorLog: {S}:: Serialized Actor :: /AT_DevGameMode_C PersistentLevel.AT_DevGameMode_0000027E000002BB0000026A00000202
SaviorLog: {S}:: SAVED DATA for PersistentLevel_AT_DevGameMode_0000027E000002BB0000026A00000202 :: {"bCanBeDamaged":false}
SaviorLog: {S}:: Serialized Actor :: /ATFullGameStateBP_C PersistentLevel.ATFullGameStateBP
SaviorLog: {S}:: SAVED DATA for PersistentLevel_ATFullGameStateBP :: {"bCanBeDamaged":false}
SaviorLog: {S}:: Serialized Actor :: /P0_ATOD_FullPlayerController_BP_C PersistentLevel.ATOD_FullPlayerController_BP_000002C10000025700000231000001FA
SaviorLog: {S}:: SAVED DATA for PersistentLevel_ATOD_FullPlayerController_BP_000002C10000025700000231000001FA :: {"bCanBeDamaged":false}
SaviorLog: {S}:: Serialized Actor :: /P0_Barbarian_C PersistentLevel.Barbarian_000002580000028F00000228000001FC
SaviorLog: {S}:: SAVED DATA for PersistentLevel_Barbarian_000002580000028F00000228000001FC :: {"Test":"wwwww","InventorySave":[],"CharacterName":"Base Player","bCanBeDamaged":true}

My second guess was to just manually save and load the pawn only, which kinda worked but not really as I needed:

I would be happy with this result but this only works if I set the Slot Asset to “Simple” - which is OK for me, because I have no idea what the difference is (except respawning, which I don’t seem to need). In complex mode the SaveHierarchy just executed it’s failed pin, no errors in the logs.

The main problem with this solution for me is, that the pawn’s transform is also saved. Adding the !Tran tag didn’t make a any difference. For my scenario this means that the character is instantly teleported to the level exit.

So to recap:
Try #1 does not save my inventory component, but I can avoid teleporting of my character with the checkbox.

Try #2 does save my inventory component in simple slot bot teleports my character.

I hope that problem is not that the inventory component has no SGUID - this component is a C++ plugin, which I don’t want to change, in order to avoid conflicts when updates are incoming for that plugin. Technically I could do it, if there is no other way, but I’d rather avoid it.

Thanks for your time!

P.S.

this is the log of the Save Actor Hierarchy when Save Slot Asset is set to Complex:

SaviorLog: {S}:: Serialized Actor :: /P0_Barbarian_C PersistentLevel.Barbarian_000002580000028F00000228000001FC
SaviorLog: {S}:: SAVED DATA for PersistentLevel_Barbarian_000002580000028F00000228000001FC :: {"Test":"wwwww","InventorySave":[],"CharacterName":"Base Player","bCanBeDamaged":true}

This is the log Output when set to simple mode:

SaviorLog: {S}:: (Minimal) Serialized Actor :: Barbarian_C_0
SaviorLog: {S}:: SAVED MINIMAL DATA for Barbarian_C_0 :: {"Test":"wwwww","InventorySave":[],"CharacterName":"Base Player","bCanBeDamaged":true}
SaviorLog: {S}:: (Minimal) Serialized Component :: CollisionCylinder
SaviorLog: {S}:: SAVED MINIMAL DATA for CollisionCylinder :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: Arrow
SaviorLog: {S}:: SAVED MINIMAL DATA for Arrow :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: CharMoveComp
SaviorLog: {S}:: SAVED MINIMAL DATA for CharMoveComp :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: CharacterMesh0
SaviorLog: {S}:: SAVED MINIMAL DATA for CharacterMesh0 :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: Actions Manager
SaviorLog: {S}:: SAVED MINIMAL DATA for Actions Manager :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: Locomotion Component
SaviorLog: {S}:: SAVED MINIMAL DATA for Locomotion Component :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: Statistic Component
SaviorLog: {S}:: SAVED MINIMAL DATA for Statistic Component :: {"DefaultAttributeSet":{"Attributes":[{"attributeType":{"tagName":"RPG.Attribute.Strength"},"value":12},{"attributeType":{"tagName":"RPG.Attribute.Constitution"},"value":5},{"attributeType":{"tagName":"RPG.Attribute.Endurance"},"value":10}],"Statistics":[{"statType":{"tagName":"RPG.Statistic.Stam
ina"},"maxValue":0,"currentValue":100,"hasRegeneration":true,"bStartFromZero":false,"regenValue":0,"regenDelay":0.5},{"statType":{"tagName":"RPG.Statistic.Mana"},"maxValue":100,"currentValue":100,"hasRegeneration":true,"bStartFromZero":false,"regenValue":0.20000000298023224,"regenDelay":0}],"Parameters":[{"attributeType":{"tagName":"RPG.Parameters.CritChance
"},"value":10}]},"LevelingType":"EAssignPerksManually","CharacterLevel":1,"CurrentExps":0,"ExpToNextLevel":3954,"AttributeSet":{"Attributes":[{"attributeType":{"tagName":"RPG.Attribute.Strength"},"value":12},{"attributeType":{"tagName":"RPG.Attribute.Constitution"},"value":55},{"attributeType":{"tagName":"RPG.Attribute.Endurance"},"value":10}],"Statistics":[
{"statType":{"tagName":"RPG.Statistic.Stamina"},"maxValue":67.836433410644531,"currentValue":67.836433410644531,"hasRegeneration":true,"bStartFromZero":false,"regenValue":19.762310028076172,"regenDelay":0.5},{"statType":{"tagName":"RPG.Statistic.Mana"},"maxValue":100,"currentValue":100,"hasRegeneration":true,"bStartFromZero":false,"regenValue":0.200000002980
23224,"regenDelay":0},{"statType":{"tagName":"RPG.Statistic.Health"},"maxValue":329.40066528320312,"currentValue":329.40066528320312,"hasRegeneration":true,"bStartFromZero":false,"regenValue":0,"regenDelay":0}],"Parameters":[{"attributeType":{"tagName":"RPG.Parameters.CritChance"},"value":10},{"attributeType":{"tagName":"RPG.Parameters.MeleeDamage"},"value":
116.92443084716797},{"attributeType":{"tagName":"RPG.Parameters.RangedDamage"},"value":2000}]},"Perks":0,"baseAttributeSet":{"Attributes":[{"attributeType":{"tagName":"RPG.Attribute.Strength"},"value":12},{"attributeType":{"tagName":"RPG.Attribute.Constitution"},"value":5},{"attributeType":{"tagName":"RPG.Attribute.Endurance"},"value":10}],"Statistics":[{"st
atType":{"tagName":"RPG.Statistic.Stamina"},"maxValue":0,"currentValue":100,"hasRegeneration":true,"bStartFromZero":false,"regenValue":0,"regenDelay":0.5},{"statType":{"tagName":"RPG.Statistic.Mana"},"maxValue":100,"currentValue":100,"hasRegeneration":true,"bStartFromZero":false,"regenValue":0.20000000298023224,"regenDelay":0}],"Parameters":[{"attributeType"
:{"tagName":"RPG.Parameters.CritChance"},"value":10}]}}
SaviorLog: {S}:: (Minimal) Serialized Component :: Collisions Manager
SaviorLog: {S}:: SAVED MINIMAL DATA for Collisions Manager :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: Equipment Component
SaviorLog: {S}:: SAVED MINIMAL DATA for Equipment Component :: {"Inventory":[{"itemInfo":{"thumbNail":"Texture2D'/MP_Icons/Novart_icons_pack/Weapons/T_weapon__7_.T_weapon__7_'","name":"Axe R","description":"","itemType":"MeleeWeapon","maxInventoryStack":1,"itemWeight":5,"worldMesh":"StaticMesh'/Game/Assets/Items/Weapons/Sword_01/SM_Sword_01a.SM_Sword_01a'","
bDroppable":true,"bUpgradable":false,"requiredItemsToUpgrade":[{"itemClass":"None","count":1}],"nextLevelClass":"None","upgradeCurrencyCost":0,"currencyValue":5,"itemSlot":{"tagName":"ItemSlot.MeleeWeapon"}},"count":1,"bIsEquipped":true,"dropChancePercentage":0,"itemClass":"BlueprintGeneratedClass'/Game/Blueprints/Items/BP_Axe_R_01a1.BP_Axe_R_01a1_C'","itemG
uid":"5CE86AC045A6C7A06810A8B265D104EF"},{"itemInfo":{"thumbNail":"Texture2D'/MP_Icons/Novart_icons_pack/Weapons/T_weapon__7_.T_weapon__7_'","name":"Axe L","description":"","itemType":"MeleeWeapon","maxInventoryStack":1,"itemWeight":5,"worldMesh":"StaticMesh'/Game/Assets/Items/Weapons/Axe_01/SM_Axe_01a.SM_Axe_01a'","bDroppable":true,"bUpgradable":false,"requ
iredItemsToUpgrade":[{"itemClass":"None","count":1}],"nextLevelClass":"None","upgradeCurrencyCost":0,"currencyValue":5,"itemSlot":{"tagName":"ItemSlot.LeftHandWeapon"}},"count":1,"bIsEquipped":true,"dropChancePercentage":0,"itemClass":"BlueprintGeneratedClass'/Game/Blueprints/Items/BP_Axe_L_01a.BP_Axe_L_01a_C'","itemGuid":"15950E2745E859DC29BB639D1350415E"},
{"itemInfo":{"thumbNail":"Texture2D'/Game/Assets/UI/Icons/high-shot.high-shot'","name":"BUPBow","description":"","itemType":"RangedWeapon","maxInventoryStack":1,"itemWeight":5,"worldMesh":"None","bDroppable":true,"bUpgradable":false,"requiredItemsToUpgrade":[],"nextLevelClass":"None","upgradeCurrencyCost":0,"currencyValue":5,"itemSlot":{"tagName":"ItemSlot.R
angedWeapon"}},"count":1,"bIsEquipped":true,"dropChancePercentage":0,"itemClass":"BlueprintGeneratedClass'/Game/Blueprints/Items/BUPBowBP.BUPBowBP_C'","itemGuid":"81363BD5423D57230FBC549D95492E8F"},{"itemInfo":{"thumbNail":"Texture2D'/Game/Assets/UI/Icons/quiver__1_.quiver__1_'","name":"Arrow","description":"","itemType":"Armor","maxInventoryStack":30,"itemW
eight":0.10000000149011612,"worldMesh":"None","bDroppable":true,"bUpgradable":false,"requiredItemsToUpgrade":[],"nextLevelClass":"None","upgradeCurrencyCost":0,"currencyValue":5,"itemSlot":{"tagName":"ItemSlot.Ammo"}},"count":5,"bIsEquipped":true,"dropChancePercentage":0,"itemClass":"BlueprintGeneratedClass'/Game/Blueprints/Items/BUPArrowBP.BUPArrowBP_C'","i
temGuid":"B702F5A2428728BF91BB9485A33E07E3"},{"itemInfo":{"thumbNail":"Texture2D'/Game/Blueprints/Items/Cards/card_test_full.card_test_full'","name":"Card of Life","description":"+10 to Constitution","itemType":"Armor","maxInventoryStack":10,"itemWeight":0.0099999997764825821,"worldMesh":"StaticMesh'/Game/Blueprints/Items/Cards/SM_Card.SM_Card'","bDroppable"
:true,"bUpgradable":false,"requiredItemsToUpgrade":[],"nextLevelClass":"None","upgradeCurrencyCost":0,"currencyValue":5,"itemSlot":{"tagName":"ItemSlot.Card"}},"count":1,"bIsEquipped":true,"dropChancePercentage":0,"itemClass":"BlueprintGeneratedClass'/Game/Blueprints/Items/Cards/BP_Card_of_Life.BP_Card_of_Life_C'","itemGuid":"1FF161C74B26E1C804D5138B3A866A5E
"}]}
SaviorLog: {S}:: (Minimal) Serialized Component :: Perception Stimuli Component
SaviorLog: {S}:: SAVED MINIMAL DATA for Perception Stimuli Component :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: Damage Handler Component
SaviorLog: {S}:: SAVED MINIMAL DATA for Damage Handler Component :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: Ragdoll Component
SaviorLog: {S}:: SAVED MINIMAL DATA for Ragdoll Component :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: Audio Component
SaviorLog: {S}:: SAVED MINIMAL DATA for Audio Component :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: ATSTargetPoint
SaviorLog: {S}:: SAVED MINIMAL DATA for ATSTargetPoint :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: TargetedWidget
SaviorLog: {S}:: SAVED MINIMAL DATA for TargetedWidget :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: HealthWidget
SaviorLog: {S}:: SAVED MINIMAL DATA for HealthWidget :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: AT_EffectsManagerComponentBP
SaviorLog: {S}:: SAVED MINIMAL DATA for AT_EffectsManagerComponentBP :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: Textwidget
SaviorLog: {S}:: SAVED MINIMAL DATA for Textwidget :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: BUPDefenseStance
SaviorLog: {S}:: SAVED MINIMAL DATA for BUPDefenseStance :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: AC_OcclusionTrace
SaviorLog: {S}:: SAVED MINIMAL DATA for AC_OcclusionTrace :: {"TestVar":"TESTVARCHILDCOMP000444"}
SaviorLog: {S}:: (Minimal) Serialized Component :: BUPInteraction
SaviorLog: {S}:: SAVED MINIMAL DATA for BUPInteraction :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: SpringArm
SaviorLog: {S}:: SAVED MINIMAL DATA for SpringArm :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: Camera
SaviorLog: {S}:: SAVED MINIMAL DATA for Camera :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: StaticMeshComponent_0
SaviorLog: {S}:: SAVED MINIMAL DATA for StaticMeshComponent_0 :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: DrawFrustumComponent_0
SaviorLog: {S}:: SAVED MINIMAL DATA for DrawFrustumComponent_0 :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: PlayLight1
SaviorLog: {S}:: SAVED MINIMAL DATA for PlayLight1 :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: BUPDialogueComponentBP
SaviorLog: {S}:: SAVED MINIMAL DATA for BUPDialogueComponentBP :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: BUPShooting
SaviorLog: {S}:: SAVED MINIMAL DATA for BUPShooting :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: BUPRider
SaviorLog: {S}:: SAVED MINIMAL DATA for BUPRider :: {"bIsRiding":false}
SaviorLog: {S}:: (Minimal) Serialized Component :: BUPExecutor
SaviorLog: {S}:: SAVED MINIMAL DATA for BUPExecutor :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: CASAnimSlave
SaviorLog: {S}:: SAVED MINIMAL DATA for CASAnimSlave :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: CASSnapper
SaviorLog: {S}:: SAVED MINIMAL DATA for CASSnapper :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: BUPAbilitySystem
SaviorLog: {S}:: SAVED MINIMAL DATA for BUPAbilitySystem :: {"currentlyActiveAbilities":{},"currentlyAvailableAbilities":{"currentlyAvailableAbilities_KEY":["Curse","Bless","Summon","Whirlwind"],"currentlyAvailableAbilities_VALUE":[{"name":"Curse","description":"None","icon":"None","ability":"BlueprintGeneratedClass'/Game/Blueprints/Abilities/Ability_Curse.A
bility_Curse_C'"},{"name":"Bless","description":"None","icon":"None","ability":"BlueprintGeneratedClass'/Game/Blueprints/Abilities/Ability_Bless.Ability_Bless_C'"},{"name":"Summon","description":"Summon","icon":"None","ability":"BlueprintGeneratedClass'/Game/Blueprints/Abilities/Ability_Summon.Ability_Summon_C'"},{"name":"Whirlwind","description":"None","ico
n":"None","ability":"BlueprintGeneratedClass'/Game/Blueprints/Abilities/Ability_Whirlwind.Ability_Whirlwind_C'"}]}}
SaviorLog: {S}:: (Minimal) Serialized Component :: CCMLookAtPoint
SaviorLog: {S}:: SAVED MINIMAL DATA for CCMLookAtPoint :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: CCMCameraSpline
SaviorLog: {S}:: SAVED MINIMAL DATA for CCMCameraSpline :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: MapView
SaviorLog: {S}:: SAVED MINIMAL DATA for MapView :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: MapIcon
SaviorLog: {S}:: SAVED MINIMAL DATA for MapIcon :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: MapRevealer
SaviorLog: {S}:: SAVED MINIMAL DATA for MapRevealer :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: PawnInputComponent0
SaviorLog: {S}:: SAVED MINIMAL DATA for PawnInputComponent0 :: {}
SaviorLog: {S}:: (Minimal) Serialized Actor :: BUPBowBP_C_0
SaviorLog: {S}:: SAVED MINIMAL DATA for BUPBowBP_C_0 :: {"UnsheathedAttributeModifier":{"Guid":{"A":51601403,"B":1316489961,"C":443985080,"D":-940245054},"ModType":"EAdditive"},"DefenseStateModifier":{"Guid":{"A":1823674901,"B":1109407741,"C":-2142997075,"D":814394638},"ModType":"EAdditive"},"AttributeModifier":{"Guid":{"A":-1854714081,"B":1320459042,"C":-16
21926468,"D":-823793837},"ModType":"EAdditive","Parameters":[{"attributeType":{"tagName":"RPG.Parameters.RangedDamage"},"value":2000}]},"bCanBeDamaged":true}
SaviorLog: {S}:: (Minimal) Serialized Component :: Handle
SaviorLog: {S}:: SAVED MINIMAL DATA for Handle :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: Mesh
SaviorLog: {S}:: SAVED MINIMAL DATA for Mesh :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: Collisions Manager
SaviorLog: {S}:: SAVED MINIMAL DATA for Collisions Manager :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: ShotingComponent
SaviorLog: {S}:: SAVED MINIMAL DATA for ShotingComponent :: {}
SaviorLog: {S}:: (Minimal) Serialized Actor :: BP_Axe_L_01a_C_0
SaviorLog: {S}:: SAVED MINIMAL DATA for BP_Axe_L_01a_C_0 :: {"UnsheathedAttributeModifier":{"Guid":{"A":-179392850,"B":1095522667,"C":-2002932334,"D":1049560032},"ModType":"EAdditive"},"DefenseStateModifier":{"Guid":{"A":1349599112,"B":1278525548,"C":1481006984,"D":-1171865308},"ModType":"EAdditive"},"AttributeModifier":{"Guid":{"A":-1462720808,"B":115672854
5,"C":1677688736,"D":-357245380},"ModType":"EAdditive","Parameters":[{"attributeType":{"tagName":"RPG.Parameters.MeleeDamage"},"value":25}]},"bCanBeDamaged":true}
SaviorLog: {S}:: (Minimal) Serialized Component :: Handle
SaviorLog: {S}:: SAVED MINIMAL DATA for Handle :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: Mesh
SaviorLog: {S}:: SAVED MINIMAL DATA for Mesh :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: Collisions Manager
SaviorLog: {S}:: SAVED MINIMAL DATA for Collisions Manager :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: ParticleSystemComponent_0
SaviorLog: {S}:: SAVED MINIMAL DATA for ParticleSystemComponent_0 :: {}
SaviorLog: {S}:: (Minimal) Serialized Actor :: BP_Axe_R_01a1_C_0
SaviorLog: {S}:: SAVED MINIMAL DATA for BP_Axe_R_01a1_C_0 :: {"UnsheathedAttributeModifier":{"Guid":{"A":-384885240,"B":1233225979,"C":-961177428,"D":-367403799},"ModType":"EAdditive"},"DefenseStateModifier":{"Guid":{"A":-496132618,"B":1303341625,"C":-1137749322,"D":1243534040},"ModType":"EAdditive"},"AttributeModifier":{"Guid":{"A":327080158,"B":1174564414,
"C":-1057434190,"D":-1686794105},"ModType":"EAdditive","Parameters":[{"attributeType":{"tagName":"RPG.Parameters.MeleeDamage"},"value":25}]},"bCanBeDamaged":true}
SaviorLog: {S}:: (Minimal) Serialized Component :: Handle
SaviorLog: {S}:: SAVED MINIMAL DATA for Handle :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: Mesh
SaviorLog: {S}:: SAVED MINIMAL DATA for Mesh :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: Collisions Manager
SaviorLog: {S}:: SAVED MINIMAL DATA for Collisions Manager :: {}
SaviorLog: {S}:: (Minimal) Serialized Component :: ParticleSystemComponent_0
SaviorLog: {S}:: SAVED MINIMAL DATA for ParticleSystemComponent_0 :: {}

Why is there this big of a difference?

New Slot Instance → Save Actor(s) → Write Slot to File, will save any of your child actors to the save file.

“Save Game Mode” will only target members of Game Mode group and you can’t append other actors to it since the node will lock the save progress until the file is written.

Use “Save Actor” nodes instead, since your instances are not members of Game Mode in any way.

How can I prevent the transform of my pawn to be saved or rather then restored? I don’t want him to be teleported.

So what I can do is to just the 2 components I actually need to be saved. Do I need to add an SGUI property to the components?

Hi Bruno,

Would you consider or find it useful to change within the USavior3::SaveActorMaterials and USavior3::LoadActorMaterials functions possibility from simply SkeletalMeshComponent and StaticMeshComponent class to just the MeshComponent class?

In our specific case this has two added benefits;

  • Changing from both these 2 former classes to the latter one would make the method more simple, since both Mesh Component class types already inherit from the same MeshComponent base class type. This allows for less clutter since this would bring the amount of duped for-loops back from two to one.
  • However, the most important one for us; we are using a combination of Static Mesh Components, Procedural Mesh Components, and FDynamicMesh3 Components within our application. The last two are not supported by the current Saving and Loading methods.

Please let us know if this is something you would consider adding to the plugin on your part as it may be useful to other people as well.

If this is not considered as a feasible enough addon for you to add to the plugin, please let us know. I would be more than happy to make changes to the plugin on our end. However, we’re trying to not modify plugins as much as possible as this would add a large overhead for us in each plugin revision, especially since we are using quite a lot of different plugins.

From:

    TArray<USkeletalMeshComponent *> Skins;
	TArray<UStaticMeshComponent *> Meshes;

	Actor->GetComponents<UStaticMeshComponent>(Meshes);
	Actor->GetComponents<USkeletalMeshComponent>(Skins);
for (auto CMP : Meshes)
{
	const auto Mesh = CastChecked<UStaticMeshComponent>(CMP);
	TArray<UMaterialInterface *> Mats = Mesh->GetMaterials();

	for (auto Mat : Mats)
	{
		if (!Mat->IsValidLowLevel())
		{
			continue;
		}
		if (!Mat->IsA(UMaterialInstanceDynamic::StaticClass()))
		{
			continue;
		}

		FMaterialRecord MatInfo = CaptureMaterialSnapshot(CastChecked<UMaterialInstanceDynamic>(Mat));
		const FName MatID = *FString::Printf(TEXT("%s.%s"), *ActorID.ToString(), *Mat->GetName());
		ActorRecord.Materials.Add(MatID, MatInfo);
	}
}

for (auto CMP : Skins)
{
	const auto Mesh = CastChecked<USkeletalMeshComponent>(CMP);
	TArray<UMaterialInterface *> Mats = Mesh->GetMaterials();

	for (auto Mat : Mats)
	{
		if (!Mat->IsValidLowLevel())
		{
			continue;
		}
		if (!Mat->IsA(UMaterialInstanceDynamic::StaticClass()))
		{
			continue;
		}

		FMaterialRecord MatInfo = CaptureMaterialSnapshot(CastChecked<UMaterialInstanceDynamic>(Mat));
		const FName MatID = *FString::Printf(TEXT("%s.%s"), *ActorID.ToString(), *Mat->GetName());
		ActorRecord.Materials.Add(MatID, MatInfo);
	}
}

To:

TArray<UMeshComponent*> Meshes;

Actor->GetComponents<UMeshComponent>(Meshes);

for (auto CMP : Meshes)
	{
		const auto Mesh = CastChecked<UMeshComponent>(CMP);
		TArray<UMaterialInterface *> Mats = Mesh->GetMaterials();

		for (auto Mat : Mats)
		{
			if (!Mat->IsValidLowLevel())
			{
				continue;
			}
			if (!Mat->IsA(UMaterialInstanceDynamic::StaticClass()))
			{
				continue;
			}

			FMaterialRecord MatInfo = CaptureMaterialSnapshot(CastChecked<UMaterialInstanceDynamic>(Mat));
			const FName MatID = *FString::Printf(TEXT("%s.%s"), *ActorID.ToString(), *Mat->GetName());
			ActorRecord.Materials.Add(MatID, MatInfo);
		}
	}

Have you already tested that?

Sometimes I make changes, it break the plugin for somebody else’s project, I would have to make sure it’s working for everyone’s 3D models setup.

No, not yet unfortunately, in theory it should work. But good point, better not change it yet without proper testing in case it may break other peoples projects. I think i may have time to test the proposed changes extensively next week. :slight_smile:

I have completed the process of porting the plugin to Unreal 5.0.
I have tested in-editor functionality and packaged builds both on Debug and Shipping modes, and all plugin’s subsystems are working correctly.

I’ve updated the demo project to Unreal 5 and you can download a copy of this demo here:


With all tests succeeding, I have moved forward and submitted v4.0 for Unreal 5 to the Unreal Marketplace and we are now waiting for review.


Here’s screenshots of the sample project running on Unreal 5 (shipping).
(the quality of lighting at 4K makes Unreal 4 look like grandma’s tech)

1 Like

The plugin for Unreal 5 is already released on Marketplace.

1 Like

Hi Bruno, I’m using the savior on my project. I would like to know how to load the saved state from my blueprints when loading a new map.
I set them up, when loading world from a save file (loading game) everything works just fine, but when I teleport to another level all blueprints are on the original state and not on the saved state. How to “load” the saved state of the blueprints when opening a level?

You just have to invoke one of load game nodes from level begin play, if you are manually switching between levels.

If you are saving all levels to same slot, then you are overwriting data from previous level.

I created a save for every world, I’m saving the player variables on the game instance.

How do I load the game world and then the game instance with the player variables?

I tried creating a save slot only for game instance and others to the levels, then I tried to load game world and then the game instance of a different slot but it didn’t work.

My player can go to another level and go back, so if he goes back it needs the current player variables (items, skills) but the world state of when he left that level (door opened, items that he got don’t appear again, enemies killed).

I tried using the node “Load Actor: (Slot Data)”, but I don’t know from where to get the data node from.

Did you download the demo project and read the docs ?

First set your slots to run as “Synchronous Task” and stop using the “Async” nodes if you feel lost. Use default non async nodes first, it’s easier for non programmers.

When you execute “Load Game World”, if the level is not the current, the plugin will first open the level before loading data from Slot. See demo project for reference.

The properties you want to save are only saved if they are marked with “Save Game” checkbox on advanced section of the property, and your instance has a valid “SGUID” Guid property in place. Again, see demo project for reference.