Initialize object based off blueprint in editor

I’m trying to write an inventory/item system where a UItem holds item data like the name and the mesh, and then a AWorldItem has a reference to a UItem blueprint, a StaticMeshComponent, and modifies itself accordingly based off whichever UItem it is supposed to represent.

So I’ve got a blueprint class based off UItem called Item_Box and I have a blueprint class based off AWorldItem called WA_Box. I set up WA_Box to hold a reference to the Item_Box blueprint, and now I want to make it so that the StaticMeshComponent in AWorldItem has it’s static mesh set to the mesh property in the Item_Box.

I thought this was straightforward, however the following code crashes the editor as soon as it compiles:

AWorldItem::AWorldItem()
{
	PrimaryActorTick.bCanEverTick = true;

    meshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ItemMesh"));
    RootComponent = meshComponent;

    const UItem* const test = itemClass->GetDefaultObject<UItem>();
    meshComponent->SetStaticMesh(test->GetMesh());
}

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

What I’m confused about, is that changing the code so that the mesh setting happens in BeginPlay(), as illustrated in the following code, works just fine. But I want the mesh to be changed before the game even starts, so I can see it in the editor. I’m not sure how to do that.

 AWorldItem::AWorldItem()
 {
     PrimaryActorTick.bCanEverTick = true;
 
     meshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ItemMesh"));
     RootComponent = meshComponent;
 }
 
 void AWorldItem::BeginPlay()
 {
     Super::BeginPlay();

     const UItem* const test = itemClass->GetDefaultObject<UItem>();
     meshComponent->SetStaticMesh(test->GetMesh());
 }

I am not getting any sort of crash log from the editor. It says I don’t have the debug symbols. In order to start the project back up without crashing, I have to remove the GetDefaultObject() line and build the solution from Visual Studio. What am I doing wrong?

What you want to do is to make your item class property as editable in the editor and then you should derive OnConstruct function and change the mesh in it.

What is going to happen is the actor will trigger construction script every time the item class property changed and then your mesh changing code will automatically run.

Maybe something like this:

UCLASS(Blueprintable)
class AWorldItem : public AActor
{
	...

	void SetItemClass( TSbclassOf<UItem> InItemClass )
	{
		ItemClass = InItemClass;
		UStaticMesh* StaticMesh = ItemClass ? ItemClass->GetDefaultObject<UItem>()->GetMesh() : nullptr ;
		meshComponent->SetStaticMesh( StaticMesh );
	}

	virtual void OnConstruct( const FTransform& Transform ) override
	{
		Super::OnConstruct( Transform );
		SetItemClass( ItemClass );
	}

protected:

	UPROPERTY(EditAnywhere, Category="Item")
	TSubclassOf<UItem> ItemClass;

        ...
};

This works great, thanks! Let me just note that the function is named OnConstruction() in the current engine version.

I have some questions though… What’s the deal with the constructor, like what is the difference between that and OnConstruction()? You setup the components in the constructor, so I assumed you would set every other Actor default in there. Also, why the ‘Blueprintable’ key on the UCLASS()? I don’t have that and mine works just fine, and I’m able to make a blueprint of it.

Ah yes, sorry, it is OnConstruction.

There are many points in which we can initialize an object, the class constructor is usually where we want to create various sub-default object or specifying values of native properties. There is also PostInitProperties where we can initialize some properties after cdo has been copied, and then we have PostLoad where we can change the value of some properties after the object has been loaded.

OnConstruction is special to an Actor (Object does not have it), along with PostInitializeComponents. The safest and easiest way to initialize an actor after one of its properties has been changed in the editor is to add it in OnConstruction, although not all properties will trigger the construction script (e.g Transform will not be trigger construction script for non blueprint actor), you can also reconstruct the actor manually ( I believe it is RerunConstructionScript, sorry my current laptop doesn’t have UE4)

As for the Blueprintable, that’s not necessary, most class modifiers are derived from its parent, including Blueprintable, it’s just a habit of mine so that by just looking at the class modifiers I know that it can be made into blueprint, and for some cases where I don’t want user to use this class as parent class for a blueprint then i just add Non in front of it.

This is very useful information. Thank you!