Engine Crashing When Adding Reference To Blueprint Class To Data Asset

I’m working on an inventory system that uses a Data Table populated by Data Assets in order to handle item management. The ItemData asset can hold a reference to a weapon component that will be given to the player, however currently the engine will crash if I ever populate this field in the data asset, returning the following error:

Typed element was requested for '/Game/FirstPerson/Data/ItemDatas/ItemData_Generic.ItemData_Generic:BP_WeaponRifle_C_1' before the registry was available! This usually means that NewObject was used instead of CreateDefaultSubobject during CDO construction.

The weapon object I’m using is a blueprint created from the weapon component class and assigned to the Item Data in the editor, so I’m struggling to take much from the error message since I don’t create the object in code at all. Below are some screenshots of the relevant classes.



How did you initialize WeaponData?

Can you show us CPP of the Weapon Component?

WeaponData is another DataAsset that I set in editor, do I need to also initialise it in the CPP somewhere?

The Weapon Component CPP is mostly the default one from the FPS template:

UTP_WeaponComponent::UTP_WeaponComponent()
{
	// Default offset from the character location for projectiles to spawn
	MuzzleOffset = FVector(100.0f, 0.0f, 10.0f);
}

void UTP_WeaponComponent::Reload()
{
	if (WeaponData != nullptr)
	{
		WeaponData->OnReload();
	}
}

void UTP_WeaponComponent::Fire()
{
	if (Character == nullptr || Character->GetController() == nullptr || WeaponData == nullptr)
	{
		return;
	}

	if (WeaponData->GetCurrentAmmo() == 0)
	{
		Reload();
		return;
	}

	float time = UGameplayStatics::GetRealTimeSeconds(GetWorld());
	if (time - WeaponData->GetLastFireTime() > WeaponData->GetFireRate())
	{
		// Try and fire a projectile
		if (WeaponData->UseProjectile && WeaponData->ProjectileClass != nullptr)
		{
			UWorld* const World = GetWorld();
			if (World != nullptr)
			{
				APlayerController* PlayerController = Cast<APlayerController>(Character->GetController());
				const FRotator SpawnRotation = PlayerController->PlayerCameraManager->GetCameraRotation();
				// MuzzleOffset is in camera space, so transform it to world space before offsetting from the character location to find the final muzzle position
				const FVector SpawnLocation = GetOwner()->GetActorLocation() + SpawnRotation.RotateVector(MuzzleOffset);

				//Set Spawn Collision Handling Override
				FActorSpawnParameters ActorSpawnParams;
				ActorSpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButDontSpawnIfColliding;

				// Spawn the projectile at the muzzle
				World->SpawnActor<AFPS_ProjectProjectile>(WeaponData->ProjectileClass, SpawnLocation, SpawnRotation, ActorSpawnParams);
			}
		}
		else
		{
			//TODO: implement hitscan here
		}

		WeaponData->AdjustAmmo(-1);
		WeaponData->SetLastFireTime(time);
		// Try and play the sound if specified
		if (WeaponData->FireSound != nullptr)
		{
			//TODO: add back in later - just too annoying to work with now
			//UGameplayStatics::PlaySoundAtLocation(this, FireSound, Character->GetActorLocation());
		}

		// Try and play a firing animation if specified
		if (WeaponData->FireAnimation != nullptr)
		{
			// Get the animation object for the arms mesh
			UAnimInstance* AnimInstance = Character->GetMesh1P()->GetAnimInstance();
			if (AnimInstance != nullptr)
			{
				AnimInstance->Montage_Play(WeaponData->FireAnimation, 1.f);
			}
		}
	}
}

int UTP_WeaponComponent::GetMaxAmmo()
{
	return WeaponData->GetMaxAmmo();
}

int UTP_WeaponComponent::GetCurrentAmmo()
{
	return WeaponData->GetCurrentAmmo();
}

void UTP_WeaponComponent::AttachWeapon(AFPS_ProjectCharacter* TargetCharacter)
{
	Character = TargetCharacter;

	// Check that the character is valid, and has no rifle yet
	if (Character == nullptr || Character->GetHasRifle())
	{
		return;
	}

	// Attach the weapon to the First Person Character
	FAttachmentTransformRules AttachmentRules(EAttachmentRule::SnapToTarget, true);
	AttachToComponent(Character->GetMesh1P(), AttachmentRules, FName(TEXT("GripPoint")));
	
	// switch bHasRifle so the animation blueprint can switch to another animation set
	Character->SetHasRifle(true);

	// Set up action bindings
	if (APlayerController* PlayerController = Cast<APlayerController>(Character->GetController()))
	{
		if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
		{
			// Set the priority of the mapping to 1, so that it overrides the Jump action with the Fire action when using touch input
			Subsystem->AddMappingContext(FireMappingContext, 1);
		}

		if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerController->InputComponent))
		{
			// Fire
			EnhancedInputComponent->BindAction(FireAction, ETriggerEvent::Triggered, this, &UTP_WeaponComponent::Fire);
			EnhancedInputComponent->BindAction(ReloadAction, ETriggerEvent::Triggered, this, &UTP_WeaponComponent::Reload);
		}
	}
}

void UTP_WeaponComponent::BeginPlay()
{
	if (WeaponData)
	{
		WeaponData->Init();
	}
}

void UTP_WeaponComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	if (Character == nullptr)
	{
		return;
	}

	if (APlayerController* PlayerController = Cast<APlayerController>(Character->GetController()))
	{
		if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
		{
			Subsystem->RemoveMappingContext(FireMappingContext);
		}
	}
}

For me it’s hard to figure out what is going on. I hope you initialized the component in your character properly.

Something like this in the constructor of your character.

WeaponComponent = CreateDefaultSubobject<UTP_WeaponComponent>(FName("UTP Weapon Component"));

My character doesn’t start with the weapon component as a part of them, it’s added during runtime from the inventory. The crash only happens as a result of the weapon component object being set in the ItemData DataAsset in the editor.