Download

How to get class of asset file without loading it fully?

Hi, I’m working on loading assets at runtime from .pak files. This is working great using object libraries or FStreamableManager.
However, I would like to get the class of an asset before loading it, to filter classes early.

This is the code I use to get FStringAssetReference of all assets within a path:


// This is a asset name in editor: 'Shape_NarrowCapsule1'
// This is the asset reference when we right click the asset and 'copy reference' : StaticMesh'/Game/Test/Hallo/Shape_NarrowCapsule1.Shape_NarrowCapsule1'
// But another possible asset reference is: '/Game/Test/Hallo/Shape_NarrowCapsule1.Shape_NarrowCapsule1'

   TArray<FString> Filenames;
   // This function looks within platform file chain, thus it will look through mounted .pak files in FPakPlatformFiles.
   // The path in this case must be a full path or a relative path for the file system.
   // Something like: FPaths::GameContentDir() or FPaths::ConvertRelativePathToFull(FPaths::GameContentDir())
   FPackageName::FindPackagesInDirectory(Filenames, path);

   // At this point we have full file names with file extensions, already filtered to contain only .uasset and .umap.

   // Iterate over all files and convert the filename to an asset reference, so it looks like
    // '/Game/Test/Hallo/Shape_NarrowCapsule1.Shape_NarrowCapsule1'
   for (TArray<FString>::TConstIterator FileItem(Filenames); FileItem; ++FileItem)
   {
       assetReferences.Add(FPackageName::FilenameToLongPackageName(*FileItem) + TEXT(".") + FPaths::GetBaseFilename(*FileItem));
   }

But what needs to be done to get the class of the assets. I can load them without issue, but I first want to check what assets are e.g. Materials (UMateralInterface) and load only those.
Stuff known to the game cause it was packaged with the game, is known by the AssetRegistry and can be queried using it, returning FAssetData. FAssetData can be queried to get the class.
But the assets loaded at runtime from the .pak file are not known to the AssetRegistry and that will not work. I had a look into the AssetRegistry how it aquires the FAssetData but I had no luck doing so. It must be some serialization process.

Anyone any Idea?

I’ve not worked with loading pak files directly so not certain, but the asset registry has methods where you can give it paths to scan for assets. I don’t believe there is any special link between packaging and the asset registry; it’s just that by default, it will only scan the game’s content directory.

Check out the IAssetRegistry interface.

IAssetRegistry::AddPath should be the way to go, but did not work on my end. .pak file was mounted to content directory.

I was thinking more of ScanPathsSynchronous, have you tried calling that?

Awsome, that did it, thanks.


        // Try to make the AssetRegistry aware of the of the mounted files
        FAssetRegistryModule& assetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
        IAssetRegistry& assetRegistry = assetRegistryModule.Get();
        FString contentRelativeDir(TEXT("/Game/Test/Hallo"); // mountpoint: ../../../PROJECTNAME/Content/Test/Hallo/
        assetRegistry.AddPath(contentRelativeDir); // Should not be needed for the next function, but just do it.
        assetRegistry.ScanPathsSynchronous({ contentRelativeDir });

#if 1  && !UE_BUILD_SHIPPING //Enable to check if the assets of the .pak file are registered in the assetregistry
        UObjectLibrary* library = UObjectLibrary::CreateLibrary(UObject::StaticClass(), false, false);
        library->LoadAssetDataFromPath(*contentRelativeDir); // Will query the AssetRegistry
        TArray<FAssetData> assetData;
        library->GetAssetDataList(assetData);
        for (FAssetData& data : assetData)
        {
            CM_LOG(Warning, "MountedCheck AssetDataFound, Class: %s, Name: %s", *data.GetClass()->GetName(), *data.GetFullName() );
        }
#endif