NewObject from InitializeComponent breaks everything?

I have a class that derives from USceneComponent. In its constructor, I’ve been creating a sub-component (a USphereComponent) via CreateDefaultSubObject. Recently, I wanted to make this shape be either a USphereComponent or UCapsuleComponent.

I moved the creation code from the constructor to an overridden InitializeComponent, and changed it to use NewObject, RegisterComponent, and AttachToComponent. This works, but I can’t save the object anymore! I get an error that the “Graph is linked to external private object.”

What is the correct way to make a sub-component outside of the constructor? Not at runtime, as I still want to adjust parameters in the editor.

Header

#pragma once

#include "CoreMinimal.h"
#include "Components/SceneComponent.h"
#include "MySceneComponent.generated.h"


UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent), Blueprintable, BlueprintType )
class YOUR_API UMySceneComponent : public USceneComponent
{
	GENERATED_BODY()

public:	

	UMySceneComponent(const FObjectInitializer &objectInitializer);

protected:
	// Called when the game starts
	virtual void BeginPlay() override;

public:	

	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
	
	UFUNCTION()
	virtual void InitializeComponent() override;
};

cpp

#include "MySceneComponent.h"
#include "Components/SphereComponent.h"

UMySceneComponent::UMySceneComponent(const FObjectInitializer& objectInitializer) : Super(objectInitializer)
{
	PrimaryComponentTick.bCanEverTick = true;
	bWantsInitializeComponent = true;
}

void UMySceneComponent::BeginPlay()
{
	Super::BeginPlay();	
}

void UMySceneComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
}

void UMySceneComponent::InitializeComponent()
{
	Super::InitializeComponent();

	USphereComponent* SC = NewObject<USphereComponent>(this, USphereComponent::StaticClass());

// extra code to make it visible for tests
	SC->SetSphereRadius(500);
	SC->SetHiddenInGame(false, false);
// end extra code
	SC->SetupAttachment(this);
	SC->RegisterComponent();
}
1 Like

Huh, that is almost exactly what I had. And is now exactly. And when I recreated my blueprint with the component… it worked. Then I went back and re-added an intermediate step I’d done, and re-broke it.

If I use your code and add this function, it won’t let me save a level that contains the blueprint because of the aforementioned “Graph is linked…” error:

void UMySceneComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
	Super::PostEditChangeProperty(PropertyChangedEvent);

	// SC is a private UPROPERTY, initially created in InitializeComponent
	if(SC)
	{
		SC->DestroyComponent();
		SC = nullptr;
	}

	SC = NewObject<USphereComponent>(this, USphereComponent::StaticClass());

	// set some aspects based on properties...

	SC->SetupAttachment(this);
	SC->RegisterComponent();
}

Try:
File > Refresh All Nodes

Tried your code and not getting any errors. The sphere shows up post property change. Tried saving in a level as a bp component, then added an actor with a child actor component set to the class creating the sphere. All saves.

1 Like

Argh, no luck. If the “SC” variable is a UPROPERTY, i get that error. If it’s not a UPROPERTY, I don’t get an error (but I also don’t see the created component anymore). Creating it with NewObject in PostEditChangeProperty just seems to not work.

You cannot mark a private property with the macro UPROPERTY.

Perhaps PostInitProperties would work better in your case?

1 Like

That is a great read, and sheds a lot of light on what I’m seeing. I am indeed making a blueprint-spawned component, and it does look like PostEditChangeProperty is marking the object for deletion. I moved the sub-component creation into OnComponentCreated, and the problem is resolved! Thanks!!

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.