[C++] Custom component set to null by FObjectInitializer after editor reload

I have stumbled across a problem that I can’t seem to fix regarding components. I am using C++ on Unreal 4.8.3, and creating blueprints from these classes to be able to mess around with variables without recompiling. Although I have a solid programming background, I am new to the Unreal API and so I am not sure if it is a problem with my component or something unrelated. I’ll try and walk through the steps that cause the issue, because it is happening consistently. Please note that there is other code in the project, but I have tried to isolate the project just to the code listed here. I think I have stripped it enough that no other code should be affecting the issue, but feel free to throw queries at me if there is anything suspect.

First, I create new blueprint based of my class. The component is there and working fine, which can be seen in the details panel.


At this point, I compile and save the blueprint, just to be sure, then hit every save button under the sun to make sure it is all saved (save all, level save, etc.). I set the default pawn to this new blueprint, rebuild the entire project, and PIE. After all this, the component is still alive.

Now I close the editor, and rerun the editor (this whole time I have been hooked up to the VS debugger, I close the editor using the X in the corner, then rerun by running the local VS debugger once more). Once I have fired the editor back up, the component dies (see the details panel, also disregard the change in class name, I did this a second time to make sure the class name had never been used but the results were identical).


Now, the reason I think I may be doing something wrong with the script component is that the camera boom and top down camera components both survive just fine, and they are set in exactly the same way as the script component. By setting a data breakpoint on the pointer (8 bytes), the pointer is set back to null in the FObjectInitializer destructor. The stack trace is as follows.


Along with the code and locals of the top of the call stack (note that ScriptComponent is null in both Obj and DefaultData, yet TopDownCameraComponent and CameraBoom are both fine).


Here is all of the C++ code. I have stripped out everything bar the constructor and the properties in question (I don’t mean for the sake of shortening the code, this is all of the code that is being compiled relating to this actor and component, everything else is commented out).

PlayerCharacter.h

UCLASS(Blueprintable)
class APlayerCharacter : public ACharacter
{
	GENERATED_BODY()

public:
	APlayerCharacter(const FObjectInitializer& ObjectInitializer);

private:
	UPROPERTY(VisibleAnywhere, Category=Camera)
	class UCameraComponent* TopDownCameraComponent;
	UPROPERTY(VisibleAnywhere, Category=Camera)
	class USpringArmComponent* CameraBoom;
	UPROPERTY(VisibleAnywhere, Category=Script)
	class UScriptComponent* ScriptComponent;
};

PlayerCharacter.cpp

APlayerCharacter::APlayerCharacter(const FObjectInitializer& ObjectInitializer):
	Super(ObjectInitializer)
{
	PrimaryActorTick.bCanEverTick = true;
	bReplicates = true;
	bReplicateMovement = false;

	bUseControllerRotationPitch = false;
	bUseControllerRotationYaw = true;
	bUseControllerRotationRoll = false;

	GetCharacterMovement()->GravityScale = 0.f;

	// This component survives the reload
	CameraBoom = ObjectInitializer.CreateDefaultSubobject<USpringArmComponent>(this, TEXT("CameraBoom"));
	CameraBoom->AttachTo(RootComponent);
	CameraBoom->bAbsoluteRotation = true; // Don't want arm to rotate when character does
	CameraBoom->TargetArmLength = 1200.f;
	CameraBoom->RelativeRotation = FRotator(-60.f, 0.f, 0.f);
	CameraBoom->bDoCollisionTest = false; // Don't want to pull camera in when it collides with level

	// This component survives the reload
	TopDownCameraComponent = ObjectInitializer.CreateDefaultSubobject<UCameraComponent>(this, TEXT("TopDownCamera"));
	TopDownCameraComponent->AttachTo(CameraBoom, USpringArmComponent::SocketName);
	TopDownCameraComponent->bUsePawnControlRotation = false; // Camera does not rotate relative to arm

	// This component DOES NOT survive the reload
	// This is a UActorComponent, not a USceneComponent
	// Changing to USceneComponent and attaching changes nothing; it still dies
	ScriptComponent = ObjectInitializer.CreateDefaultSubobject<UScriptComponent>(this, TEXT("Scripts"));
}

ScriptComponent.h

UCLASS(ClassGroup=Script)
class PROJECTARPG_API UScriptComponent : public UActorComponent
{
	GENERATED_BODY()

public:	
	UScriptComponent(const FObjectInitializer& ObjectInitializer);

};

ScriptComponent.cpp

UScriptComponent::UScriptComponent(const FObjectInitializer& ObjectInitializer):
	Super(ObjectInitializer)
{
    // This was left in by accident, but there are no replicated properties
	bReplicates = true;
}

A lot of people had similar issues to this in the past, here’s one related post:

If you’ve tried recreating the blueprint from scratch and that hasn’t helped, then I think you are most likely looking at an engine bug and will need to upgrade. I haven’t experienced this issue again myself recently, and the engine code snippet you posted is different from the current version, so I suspect this issue has been fixed since 4.8.

Hello,

There is a bug in our system (UE-18284) that sounds similar to the issue you are experiencing. I’d like you to perform a quick test. Instead of using VisibleAnywhere on your Script Component, try using EditAnywhere, and see if you get the same results.

Indeed it was a 4.8 issue. I guess the lesson to learn is to keep things up to date.

Hi,

It was a bug in 4.8 which seems to have been fixed now (the steps I listed above no longer cause the component to die).

I had tried using EditAnywhere since I had seen it mentioned while googling around, but I wouldn’t let me compile a component pointer flagged with EditAnywhere (it basically told me to use the various read-only flags). But since I upgraded to 4.10 to make sure it wasn’t an engine bug as suggested by kamrann, it allowed me to compile with EditAnywhere so I can’t give the exact compile error message (not that it is relevant now that I have upgraded).