I’ve been struggling with saving dynamically spawned actor components for a few days, and I’m hoping someone here might have dealt with this problem.
I’ve posted this on AnswerHub (here), but I figured it would be a better place to discuss on the forums.
I’m aiming to save and load an actor who has dynamic actor components added at runtime.
I haven’t been able to find examples of saving and loading dynamic components.
The actor is saving in my implementation, and it seems to properly save and load static components (eg. it’s static mesh is set properly on load),
but I’m having trouble with dynamic components added at runtime - they are not populated on load.
I’m using the SaveGame object method of saving and loading (UGameplayStatics::{Load/Save}GameFromSlot), and the actor is being serialized like this:
FActorRecord record;
record.Name = Actor->GetFName();
record.Class = Actor->GetClass();
record.AttachSocketName = Actor->GetAttachParentSocketName();
record.Transform = Actor->GetTransform();
FMemoryWriter MemoryWriter(record.ActorData, false);
FH2SaveGameArchive Ar(MemoryWriter, false);
Actor->Serialize(Ar);
After this, I loop through all the components, serialize them, and store them on the Actor record.
The records look like this:
USTRUCT()
struct FComponentRecord
{
GENERATED_BODY()
public:
UPROPERTY(SaveGame)
FName Name;
UPROPERTY(SaveGame)
UClass* Class;
UPROPERTY(SaveGame)
FTransform RelativeTransform;
UPROPERTY(SaveGame)
TArray<uint8> ComponentData;
};
USTRUCT()
struct FActorRecord
{
GENERATED_BODY()
public:
UPROPERTY(SaveGame)
FName Name;
UPROPERTY(SaveGame)
USceneComponent* AttachParent;
UPROPERTY(SaveGame)
FName AttachSocketName;
UPROPERTY(SaveGame)
UClass* Class;
UPROPERTY(SaveGame)
FTransform Transform;
UPROPERTY(SaveGame)
FVector_NetQuantize100 LinearVelocity;
UPROPERTY(SaveGame)
FVector_NetQuantize100 AngularVelocity;
UPROPERTY(SaveGame)
TArray<uint8> ActorData;
UPROPERTY(SaveGame)
TArray<FComponentRecord> Components;
};
The save portion SEEMS to work fine.
On Load, I do a similar chore as above with the actor (except with a MemoryReader instead of a MemoryWriter).
I then loop through the component records stored along with it, find the related component or spawn a new one if it doesn’t exist, and then deserialize the component (using the UObject::Serialize(Ar) method).
Some of the components work fine on reload, but the dynamically spawned ones end up in an infinite loop in Class.cpp::SerializeTaggedProperties.
EDIT: and eventually crashes specifically on this line of FName::InitInternal called by FNameAsStringProxyArchive::operator<<
check(TCString<TCharType>::Strlen(InName)<=NAME_SIZE);
Has anyone dealt with dynamic components while reloading? How did you handle them?
Thanks in advance!