Asset Registry

The Asset Registry is an editor subsystem which gathers information about unloaded assets asynchronously as the editor loads. This information is stored in memory so the editor can create lists of assets without loading them. The information is authoritative and is kept up to date automatically as assets are changed in memory or files are changed on disk. The Content Browser is the primary consumer for this system, but it may be used anywhere in editor code.


How to use Asset Registry?

Asset registry is fully accessible by the programmer. Because the Registry tracks anything that happens inside Content Browser, it is a very powerful tool to use. Downside is that it is rather data-filled and you need to take some extra steps to get your pointers referencing the object / class you desire.  So now let’s go ahead and create a C++ class based on Actor. Inside BeginPlay() we create our AssetRegistry() object. We also need to include some things for this to work.

#include "AssetRegistryModule.h"
#include "ARFilter.h"// For filtering
#include "ModuleManager.h"

In BeginPlay.

// We create the AssetRegistry object.
FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");

After that we create a Array that holds our FAssetData. Then we Filter out assets we want to search. All the filtering options can be seen here.

TArray<FAssetData> AssetData;
// Force Registry to scan folders so they are 100% loaded.
TArray<FString> PathsToScan;
PathsToScan.Add(TEXT("/Game/Textures/");
// Creating filter
FARFilter Filter;
// We filter Path we want to search. In this case Textures.
Filter.PackagePaths.Add("/Game/Textures");
// Fill our TArray with the data found!
AssetRegistryModule.Get().GetAssets(Filter, AssetData);

Now you have all the assets from you texture folder inside your array. We can loop it now. We Cast just to make sure we get only UTextures.

for (auto asset : AssetData)
{
UTexture2D* Mytexture = Cast<UTexture2D>(asset.GetAsset());
//FString name = asset.GetAsset.GetFullName;
if (Mytexture)
UE_LOG(LogTemp, Warning, TEXT("%s"), *Mytexture->GetName());
}

That’s all you need to do to get basic stuff from Content Browser. Next, we will get Blueprint class using AssetRegistry.

TArray<FAssetData> AssetDataBlueprints;
// Force path scan
TArray<FString> PathsToScan;
PathsToScan.Add(TEXT("/Game/Blueprints/");
Filter.Clear(); // Clear previous filter
Filter.PackagePaths.Add("/Game/Blueprints");
AssetRegistryModule.Get().GetAssets(Filter, AssetDataBlueprints);
// We are testing that did we get anything.
for (auto asset : AssetDataBlueprints)
{		
auto Obj = asset.GetAsset();
if (Obj)
UE_LOG(LogTemp, Warning, TEXT("%s"), *Obj->GetName());
}

Great! So the only problem is, how do we get reference to our Blueprint?  We go another loop and inside loop we get the path to our class and use FStringClassReference to load directly from the path. We use AActor in this case. If you know specific class you are trying to get, you can use that of course. FPackageName comes with lot of handy global functions. You should check out the other functions too!

for (FAssetData asset : AssetDataBlueprints)
{
// Get the the class this blueprint generates (this is stored as a full path)
if (auto GeneratedClassPathPtr = asset.TagsAndValues.Find(TEXT("GeneratedClass")))
{
const FString ClassObjectPath = FPackageName::ExportTextPathToObjectPath(*GeneratedClassPathPtr);
TSubclassOf<AActor> FoundClass = FStringClassReference(ClassObjectPath).TryLoadClass<AActor>();
if (FoundClass)
{
UE_LOG(LogTemp, Warning, TEXT("Conversion success!"));
}
}
}

Another way to do the same thing.

for (FAssetData asset : AssetDataBlueprints)
{			
const FString ClassObjectPath = FPackageName::ExportTextPathToObjectPath(asset.GetExportTextName()) + "_C"; // Classes needs the _C at the end!
UE_LOG(LogTemp, Warning, TEXT("%s"), *ClassObjectPath);
TSubclassOf<AActor> FoundClass = FStringClassReference(ClassObjectPath).TryLoadClass<AActor>();
if (FoundClass)
{
UE_LOG(LogTemp, Warning, TEXT("Conversion success!"));
}	
}

That’s it! You can filter out the folders and get blueprint classes and any other stuff from the Content Browser!


Tags and Value

So now we know the basics of how to get stuff using AssetRegistry. This is all well and good, but there is however one very powerful system build inside engine when dealing with FAssets that we are going to go through. That is ability to search your classes using the Tags. You can tag any class and filter out the results using that tag. Why it is so great? Think about the situation where you have build a massive game. Game has like 1000 different potions. You want to get reference to all potions that can heal player. How would you do it? You definitely do not want to load all the potion classes and go through them and check if they are healing potion and then destroy them. That would take huge amount of memory and calculation time. Instead you would want to go through all the classes without ever loading them to memory and check out if they are tagged as ”HealingPotion”. Then you would only need to load those and save that calculation time and memory.

So how does the tagging works? Go to edit any class you desire and inside class create variable with UPROPERTY(AssetRegistrySearchable). You can use this variable inside your game or just create it for the sake of making it searchable. We create FString variable called HealingPotion.

UPROPERTY(AssetRegistrySearchable)
FString HealthPotion;

Go ahead and do that to any number of classes you have created.

Then go inside the class where we created previous AssetRegistry stuff. We are still going to search the blueprint classes, but we change the filter a little bit. So full code.

FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
TArray<FAssetData> AssetData;
FARFilter Filter;
Filter.PackagePaths.Add("/Game/Blueprints");
// Filter all the stuff that has HealthPotion tag!
Filter.TagsAndValues.Add("HealthPotion");
AssetRegistryModule.Get().GetAssets(Filter, AssetData);
for (auto asset : AssetData)
{
UE_LOG(LogTemp, Warning, TEXT("Health Potion Tagged classes are %s"), *asset.GetFullName());
}

That’s it! Now you successfully received all your tagged classes.

Of course, you don’t necessary need to filter the results right away. You can check them while looping assets. In this case we use Contains method that returns bool. There are lot of different methods inside TagsAndValues. You can check them out.

for (auto asset : AssetData)
{
bool FoundAsset= asset.TagsAndValues.Contains("HealthPotion");
if (FoundAsset == true)
UE_LOG(LogTemp, Warning, TEXT("I have the potion! %s"), *asset.GetFullName());
}

If your variable has some value you can get that. ”SomeInt” and ”SomeFloat” are the variable names given inside class.

  for (auto asset : AssetData)
{
int32 IntFromRegistry = asset.GetTagValueRef<int32>("SomeInt");
float FloatFromRegistry = asset.GetTagValueRef<float>("SomeFloat");
}

So go ahead and experience with different functions. Be sure to check documents for every possible function.


Delegates

AssetRegistry comes with delegates you can use if you like. They are mostly used for intern usage, but they are be utilized. If you dont know what delegates are, check out the delegates page. Delegates you can use are.

/** Register/Unregister a callback for when assets are added to the registry */
virtual FAssetAddedEvent& OnAssetAdded() = 0;
/** Register/Unregister a callback for when assets are removed from the registry */
virtual FAssetRemovedEvent& OnAssetRemoved() = 0;
/** Register/Unregister a callback for when assets are renamed in the registry */
virtual FAssetRenamedEvent& OnAssetRenamed() = 0;
/** Register/Unregister a callback for when the asset registry is done loading files */
virtual FFilesLoadedEvent& OnFilesLoaded() = 0;
/** Register/Unregister a callback to update the progress of the background file load */
virtual FFileLoadProgressUpdatedEvent& OnFileLoadProgressUpdated() = 0;
/** Returns true if the asset registry is currently loading files and does not yet know about all assets */
virtual bool IsLoadingAssets() = 0;

They are binded through the IAssetRegistry that can be accessed directly from our already created AssetRegistryModule. Get() method returns the IAssetRegistry so you dont need to create it seperately. Just write them in one line. Example.

AssetRegistryModule.Get().OnFilesLoaded().BindUObject(this, &MyClass::MyFunction );

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *