Getting an Asset Reference

Hey all,

By assigning a variable’s UPROPERTY as EditAnywhere, we can open that variable to be the Editor so that it can reference a particular asset in your Content folder.

But what if I wanted to skip that? Instead of opening it up to the editor so that I can code it in later, I call the variable reference within the code, the same as it would have been called by the editor?

I’ve looked around and seen that a soft object (or class?) reference might be a way to do it. But it also mentioned that this can cause spikes in the FPS when loading it. Is that really how assets are set by the editor?

For reference, the variable type is a data table. I want to call it every time a component is created to pull its profile settings with an ID (the Row Name).

I appreciate your help!

2 Likes

Are you perhaps looking for an FObjectFinder?

static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshRef(TEXT("/Engine/VREditor/TransformGizmo/SM_Sequencer_Node"));
UStaticMesh* StaticMesh = MeshRef.Object;
check(StaticMesh != nullptr);
2 Likes

Yes!

That worked great in getting the object.

Thank you again for your help

1 Like

For best practices, C++ land shouldn’t be hard referencing assets/blueprints at all. Specially not in constructors.

Assets should only be loaded by UE via UPROPERTY() references that should be set by the user in a blueprint extending the C++ classes you want to use them in. And for soft loading assets, the soft object path should still be set via UPROPERTY() and not in code. When we do that then assets lifetime and reference practices are followed correctly.

If you circumvent UE’s asset loading system then you are:

  • Adding a big delay before the first frame of the game can be shown since it needs to load all of these before the engine even finishes initializing.
  • Adding all the objects to a permanent object pool that disregards GC and never gets garbage collected.
  • Making the game crash when those objects try to reference anything outside of that disregard pool like when they try to load their own assets later on.
1 Like

Ah, I see. Thank you.

The system I’m trying to create is one where I store information (Such as DataTables holding Item Data) in some custom project settings. Item objects then pull the info from there, using FObjectFinder (although the ref paths are now saved in a Config file).

Faced with best practices in memory management, would a system like this be worth pursuing? Should I have the Item Info DataTable as a variable in the Item Object?

What is currently in my Item Object Constructor:

	FString MasterItemListRef;
	bool MatchFound = false;

	//Get Config File and reference to DataTable
	FString File = FPaths::GeneratedConfigDir().Append("Game.ini");
	GConfig->GetString(TEXT("/Script/MIS.MISGlobalSettings"), TEXT("MasterItemList"), MasterItemListRef, GGameIni);
	
	//Get DataTable Object
	static ConstructorHelpers::FObjectFinder<UDataTable> ItemRef(*MasterItemListRef);
	UDataTable* MasterItemList = ItemRef.Object;
	
	//Is DT valid?
	if (MasterItemList)
	{

		//Querry Row Name to see if ItemID matches
		for (FName QuerriedID : MasterItemList->GetRowNames())
		{
			if (ItemID == QuerriedID)
			{
				BaseItemProperties = *MasterItemList->FindRow<FMISItemInfo>(ItemID, "");
				MatchFound = true;
				break;
			}
		}
	}

	//Is Item Properties valid?
	if (!MatchFound)
	{
		UE_LOG(LogTemp, Error, TEXT("Error: %s is not a valid ItemID"), *this->GetFName().ToString());
	}

If the data table needs to be loaded all the time anyway, then you can as well use the object finder and just keep it in memory. Specially if it isn’t too big.

Since you have the asset paths in your configs, the other option would be to stream it in yourself during your game’s loading. That would allow you to unload it also when you don’t need it anymore.

1 Like