Packaging with Nativize Blueprints enabled causes assert on loading blueprint class about multiple components with the same name

I have an actor in C++ that creates a number of components in it’s constructor, like so:

UCLASS(HideCategories = ("Replication", "Actor Tick", "Actor", "Input"))
class PERSISTENCE_API AMyClass : public AActor
{
	GENERATED_BODY()

public:
	AMyClass ();

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "MyClass")
		UBoxComponent* TriggerVolume = nullptr;

    ...
};

AMyClass::AMyClass()
{
	PrimaryActorTick.bCanEverTick = false;

    ...

	TriggerVolume = CreateDefaultSubobject<UBoxComponent>(TEXT("TriggerVolume"));
	TriggerVolume->SetBoxExtent(FVector(50.f, 50.f, 10.f));
	TriggerVolume->SetCollisionObjectType(ECC_WorldStatic);
	TriggerVolume->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
	TriggerVolume->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Overlap);
	TriggerVolume->SetCollisionResponseToChannel(ECC_PlayerCharacter, ECollisionResponse::ECR_Ignore);
	TriggerVolume->SetCollisionResponseToChannel(ECC_Camera, ECollisionResponse::ECR_Ignore);
	TriggerVolume->SetCanEverAffectNavigation(false);
	TriggerVolume->SetupAttachment(DefaultSceneRoot);
}

I then have a number of blueprints based on this actor, which mostly just tweak settings, meshes etc. on the existing components, to create the specific instances of this class.

When packaging with nativize assets, the game asserts when running the package. The assert hit is here:

UObjectGlobals.cpp line 3714

UE_LOG(LogClass, Fatal, TEXT("Default subobject %s %s already exists for %s."), *OverrideClass->GetName(), *SubobjectFName.ToString(), *Outer->GetFullName());

.
[2017.03.15-18.04.56:622][547]LogHAL:Error: appError called: Assertion failed: Assertion failed: [File:F:\work\projects\unreal\415\Engine\Source\Runtime\CoreUObject\Private\UObject\UObjectGlobals.cpp] [Line: 3714] Default subobject BoxComponent TriggerVolume already exists for BP_MyBlueprintClass_C /Game/Objects/BP_MyBlueprintClass.Default__BP_MyBlueprintClass_C.

Looking at the code generated by the nativizer for this blueprint, I can indeed see that there are duplicate components being created with the same name, as both my C++ game code, and the nativized blueprint generated code, are trying to create the component. The constructor generated by the nativizer contains this snippet:

ABP_MyBlueprintClass_C__pf1991454251::ABP_MyBlueprintClass_C__pf1991454251(const FObjectInitializer& ObjectInitializer) : Super() 
{ 
       if(HasAnyFlags(RF_ClassDefaultObject) && (ABP_MyBlueprintClass_C__pf1991454251::StaticClass() == GetClass())) 
       { 
       ABP_MyBlueprintClass_C__pf1991454251::__CustomDynamicClassInitialization(CastChecked<UDynamicClass>(GetClass())); 
   } 

   auto __Local__8 = CreateDefaultSubobject<UBoxComponent>(TEXT("TriggerVolume")); 
   auto& __Local__9 = (*(AccessPrivateProperty<FVector >((__Local__8), UBoxComponent::__PPO__BoxExtent() ))); 
   __Local__9 = FVector(20.000000, 50.000000, 10.000000); 

i.e. both constructors are creating the TriggerVolume component.

There are a number of other components in the class that are declared and constructed in exactly the same way, which the nativizer correctly deduces and accesses in its generated constructor like so:

auto __Local__15 = CastChecked<UBoxComponent>(GetDefaultSubobjectByName(TEXT("CollisionVolume"))); 

I can’t see any difference between the components that work and the component that doesn’t, so I can’t see anything to change on the game side to try remedy the issue.

Note that the only package I’ve checked for this is a PS4 development build (everything seems fine in a shipping build, where the assert is defined out, though I guess in this case perhaps there just are duplicates of this component but everything manages to work okay regardless).

Thanks for reading this far!

Hello ,

I’m having issues reproducing this locally but from looking at the issue you’re having, could you try checking to see if the component pointer is null prior to CreateDefaultSubobject? I’m curious to see if that would resolve the particular issue you’re seeing in the meantime.

Hi Matthew,

Thanks for the reply! By component pointer, do you mean the reference in the parent class? If so, no this is not null at this point; it looks to have been set up correctly as per the parent class constructor.

However, looking at this again now in the debugger I have noticed something different about the problem component that I suspect could be causing this issue…

The problem component is added to an array of component pointers on one of the other components on the actor, in the parent class’s C++ constructor, like so:

FaultyMachinery->TriggerVolumes.Add(TriggerVolume);

where FaultyMachinery is a custom ActorComponent on the same actor, created earlier in the constructor, and TriggerVolumes is a UPROPERTY on this component declared like so:

UPROPERTY(BlueprintReadWrite, Category = "Trigger")
	TArray<UPrimitiveComponent*> TriggerVolumes;

I’m noticing now that the constructor in the code generated by the nativizer has also tried to reproduce this behaviour by adding its newly created components to the same array like so:

auto __Local__7 = CastChecked<UFaultyMachineryComponent>(GetDefaultSubobjectByName(TEXT("FaultyMachinery")));
__Local__7->TriggerVolumes = TArray<UPrimitiveComponent*> ();
__Local__7->TriggerVolumes.Reserve(2);

__Local__7->TriggerVolumes.Add(__Local__8);

so perhaps it’s having these multiple references to this component that’s causing the issue?

Hope that helps!
Thanks,

I meant checking to see if it is null in the constructor, which at that time it should be, seeing as you’re declaring it as such:

UBoxComponent* TriggerVolume = nullptr;

What I meant to accomplish by doing this check is to have the CreateDefaultSubobject function only be called if TriggerVolume is equal to nullptr. This way it should avoid making multiple even if the constructor is being duplicated. I’m also wondering if the same would work in this case, with the TriggerVolumes array.

In my game-code constructor, TriggerVolume is null before the call to CreateDefaultSubobject, yes, as expected.

In the constructor of the subclass, generated by the nativizer, TriggerVolume is not null, also as expected, because the parent class constructor (in my game-code) has already run. The game then asserts when the nativized subclass constructor tries to create another component named TriggerVolume.

Hope that clears things up. Thanks!

Exactly what I mean. Add a check in the constructor to only call CreateDefaultSubobject if TriggerVolume is null. This way when the nativizer’s version is called, the CreateDefaultSubobject will not be run, as it is not null.

Sorry, I’m not sure I follow.

In my class, the null check isn’t necessary, because TriggerVolume is always null at this point.

In the derived class, I can’t add a null check, because this code is generated by the nativizer whenever the game is packaged, and so not modifiable.

Apologies if I’m misunderstanding!

As the constructor for the TriggerVolume is being inherited from the code class, it should be inheriting anything else in the constructor as well, such as the null check, although I’m not completely familiar with everything the nativizer does so it may not take that into account.

Yes, but the parent class constructor will always run first, before the nativizer generated constructor, so there’s no benefit to adding a null check in the parent class.

As I explained. If the nativizer is basing its constructor off the parent’s constructor, since it is being inherited, if this null check is made in the parent’s constructor, it will also be made in the nativizer generated constructor. If this check is also made in the nativizer generated constructor, the issue will not occur as it will be checking for null.

Edit: Even if you don’t think it will work, please try it and see if it works. See if the If check for checking for nullptr is being added to the nativizer’s constructor when you put it in the parent’s one. If it isn’t, that’s fine, we can move onto something else. There’s no reason to keep this exchange going without just trying it.

ah, sorry, I understand now. I will try this and get back to you.

I’m afraid this didn’t make any difference.

I wrapped the CreateDefaultSubobject call in the parent class with if (TriggerVolume == nullptr), but the nativizer generated exactly the same constructor as before, and the same assert was hit on loading the game.

Hello ,

Are you still experiencing this issue?

In the end we had to give up on using the nativize blueprints functionality and instead go back to moving expensive bits of blueprint to code manually.

Last I checked the issue was still occurring, but when I get a moment I’ll try enable the setting again, build a package and see if it’s still happening. I think we’ve moved from 4.15 to 4.16 since I first made this post, so perhaps things have changed.

Hi Matthew,

I’m afraid that I’m unable to give you an answer at the moment, as our project currently fails to compile when using Nativize Blueprints; i.e. the nativizer generates code that does not compile. I’ve been able to work around similar issues in the past by tweaking blueprint logic, but right now I can’t see any way to trick the nativizer into generating the correct code in these cases. If I get chance, I’ll make a separate post / bug report for these compile errors.

Thanks,