Let's say that you have a whole bunch of assets of the same type, that you want to be able to treat as data. I'll use Niagara effects, because my game has a lot of distinct Niagara effects which all get treated the same way: load one, put it in position, tell it to play.
Problem: how do you find and load the right effect?
The simple solution is to make a ProjectSettings subclass for your project, add a TArray<TSoftObjectPtr<UNiagaraSystem>>
property to it, and update that array every time you make a new asset. This works, I used to use it, but it's annoying. Wouldn't it be nicer if you could automatically discover all appropriate assets, say in some subdirectory of your project, and load them at runtime? (newsflash: you can)
This C++ code, which you can stick into a subsystem for ease of access, will search everything in the "Niagara" subdirectory of your project's Contents directory for all Niagara effects, then add them to a TMap<FString, UNiagaraSystem*> for later use. Note that it assumes that all of your Niagara systems are named like NS_Foo
// Load VFX by finding all Niagara systems in the registry
// that are in the "Niagara" subdirectory.
IAssetRegistry& registry = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry").GetRegistry();
FARFilter filter;
filter.ClassPaths.Add(UNiagaraSystem::StaticClass()->GetClassPathName());
filter.PackagePaths.Add(TEXT("/Game/Niagara"));
filter.bRecursiveClasses = true;
filter.bRecursivePaths = true;
TArray<FAssetData> assetData;
registry.GetAssets(filter, assetData);
for (const auto datum : assetData) {
// Object path strings look like "/Game/Niagara/HitEffects/NS_SpiralFlame.NS_SpiralFlame"
// We only care about the "SpiralFlame" part, so strip off everything before ".NS_".
const auto path = datum.GetObjectPathString();
FString left, right;
if (!path.Split(".NS_", &left, &right)) {
UE_LOG(LogTemp, Error, TEXT("Couldn't extract VFX name from %s! Expected to find `.NS_` in there somewhere."), *path);
}
else {
loadedVFXMap.Add(right, streamer.LoadSynchronous(static_cast<TSoftObjectPtr<UNiagaraSystem>>(datum.ToSoftObjectPath())));
}
}
NOTE: you also need to tell Unreal to include the entire directory when it packages your game. Go to your Project Settings and search for "Additional Asset Directories to Cook". Make sure that the same directory you're searching in your C++ code is represented here. Otherwise this code will break when you package your build.
There's obviously plenty of changes / improvements that could be made here; this post is mostly to say "hey, the Asset Registry Module exists, and it's handy."