Custom Actor empty after Unreal reboot

Hello,
I’m currently stuck for some days and I can’t figure it out by myself.

I am working on a project who create ready to use actors based on a XML description. This XML describe the geometry of the actor. Based on it I can create dynamically the USceneComponent tree of my actor. It works well, the generated actor is well constructed and rendered. I can add it to my world and use it correctly.
The problems are:

  1. I can’t save a level with an actor inside. I got this error : Can't save C:/.../MyProject/Content/Main.umap: Graph is linked to external private object StaticMeshComponent /Game/MyAssetFolder/A_MyActor.Default__A_MyActor_C:SM_Base (InstanceComponents) where SM_Base is the name of my StaticMeshComponent.
    In the log I have a lot of warnings from the LogSavePackage module who list all the Referencers but this is not very understandable because the names don’t matches every time to something I know.
  2. I can save my actor on my content browser but after a reboot of Unreal all the Component tree just disapear.

I think the boths problems are only one but I didn’t found anything who could help me to solve this.

I use a sub object to generate the Component tree because there is already a lot of mess in my actor.
For reference some extracts of the objects :

MyActor.h

UCLASS(BlueprintType, Blueprintable)
class MYPLUGIN_API AMyActor : public AActor {
  
  GENERATED_BODY()
  
public:

  AMyActor();

  void BeginPlay();
  void EndPlay(const EEndPlayReason::Type EndPlayReason);
  void Tick(float DeltaTime);

  UXMLDescription* XMLDescription; // Custom object who contain XML already parsed to properties
  FActorGeometryTree GeometryTree;

// Method called during BP creation to set the Component tree
  void SetXMLDescription(UXMLDescription* ActorXMLDescription);

};

MyActor.cpp

AMyActor::AMyActor() {

  PrimaryActorTick.bCanEverTick = true;
  this->SetRootComponent(CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent")));
}

void AMyActor::SetXMLDescription(UXMLDescription* ActorXMLDescription) {

  this->GDTFDescription = FixtureGDTFDescription;
  
  // Construction of the Geometries tree
  this->GeometryTree = FActorGeometryTree(ActorXMLDescription, this);

<...> // Other stuff but not related with this problem
}

FActorGeometryTree.h

/**
* Manage the Scene components tree of our Actor
*/
class FActorGeometryTree {

private:

  AMyActor* ParentActor;
  UXMLDescription* XMLDescription;

public:

  // Equals to "SM_"
  static constexpr const TCHAR* PREFIX_STATIC_MESH = TEXT("SM_");

  FActorGeometryTree() {};

/**
    * Map to simplify access to Components at Runtime
    */
  	TMap<FName, USceneComponent*> Components;

  /**
   * Creates the object, all the SceneComponent tree and attach them to the Actor
  */
  FActorGeometryTree(UXMLDescription* XMLDescription, AActor* Actor);

private:

  /**
   * Creates a branch of the tree (the given geometry and all his childrens)
 * RECURSIVE METHOD
  */
  USceneComponent* CreateTreeBranch(USceneComponent* Parent, UXMLDescription* Geometry);

  /**
   * Creates a StaticMeshComponent and attach it to the parent.
  */
  bool CreateStaticMeshComponentChild(USceneComponent* Parent, UXMLDescription* Geometry);

  /**
   * Creates a USceneComponent and attach it to the parent.
  */
  USceneComponent* CreateAndAttachSceneComponent(USceneComponent* Parent, FName Name);
};

FActorGeometryTree.cpp

/**
* Creates the object, all the SceneComponent tree and attach them to the Actor
*/
FActorGeometryTree::FActorGeometryTree(UXMLDescription* XMLDescription, AActor* Actor) {

  this->ParentActor = Actor;
  this->XMLDescription = XMLDescription;

// We create the tree recursively
  USceneComponent* TreeBranch = this->CreateTreeBranch(this->ParentActor->GetRootComponent(), XMLDescription);
  TreeBranch->AttachToComponent(this->ParentActor->GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform);
}

/**
* Creates a branch of the tree (the given geometry and all his childrens)
* RECURSIVE METHOD
*/
USceneComponent* CreateTreeBranch(USceneComponent* Parent, UXMLDescription* Geometry); {

  // Creation of the container component
  USceneComponent* CurrentComponent = this->CreateAndAttachSceneComponent(Parent, Geometry->Name);
  this->Components.Add(Geometry->Name, CurrentComponent); // Registering of the component in the Map

  CurrentComponent->SetRelativeLocationAndRotation(Geometry->Position, Geometry->Rotation);
  
  // Creation of the sub geometries
  for (UXMLDescription* ChildGeometry : Geometry->Childrens) {
  	USceneComponent* ChildComponent = this->CreateTreeBranch(CurrentComponent, ChildGeometry);
  	this->Components.Add(ChildGeometry->Name, ChildComponent);
  }

  // Creation of StaticMesh
  if (Geometry->Type == EGeometryType::Mesh) { // If this geometry describe a mesh we create the StaticMeshComponent 
  	CreateStaticMeshComponentChild(CurrentComponent, Geometry);
  }
  return CurrentComponent;
}


/**
* Creates a StaticMeshComponent and attach it to the parent.
*/
void FActorGeometryTree::CreateStaticMeshComponentChild(USceneComponent* Parent, UXMLDescription* Geometry) {

  UStaticMesh* StaticMesh = nullptr;

<...> // We load the good mesh. Not related to this problem.

  // We create the UStaticMeshComponent and attach it to his parent
  FName Name = FName(FActorGeometryTree::PREFIX_STATIC_MESH + Geometry->Name.ToString());

  UStaticMeshComponent* Component = NewObject<UStaticMeshComponent>(this->ParentActor, UStaticMeshComponent::StaticClass(), Name);
  Component->AttachToComponent(Parent, FAttachmentTransformRules::KeepRelativeTransform);
  this->ParentActor->AddInstanceComponent(Component);
  Component->SetStaticMesh(StaticMesh);

  // Step 5: We save it here for future use
  this->ParentActor->Components.Add(Name, Component);
}

/**
* Creates a USceneComponent and attach it to the parent.
*/
USceneComponent* FActorGeometryTree::CreateAndAttachSceneComponent(USceneComponent* Parent, FName Name) {

  USceneComponent* NewComponent = NewObject<USceneComponent>(this->ParentActor, USceneComponent::StaticClass(), Name);
  if (Parent != nullptr) NewComponent->AttachToComponent(Parent, FAttachmentTransformRules::KeepRelativeTransform);
  this->ParentActor->AddInstanceComponent(NewComponent);
  return NewComponent;
}

I don’t have any idea of where my probem could be. Everything related to component is public so I don’t really understand the Unreal error.

I suspect this might have to do with how Blueprints work and how they are compiled into skeleton class and generated class.
Look into KismetEditorUtilities.h there are lots of interesting functions for your use case I believe.

From a quick glance through KismetEditorUtilities, I think you could use one of two approaches :

  • Either automate tasks like a normal user does in editor : create package, create blueprint, add components to the blueprint (function AddComponentsToBlueprint), compile, save

  • Build your actor with instanced components like you are doing at this time, then use function CreateBlueprintFromActor to automagically generate a proper blueprint from it