Yes paks should be in Content/Paks if you want them to be mounted automatically.
It is also possible to mount them manually, in which case you can specify any path on disk. However it will require C++ to discover them on disk (iterate folders) and mount them.
Regarding iterating pak assets, well I doubt there is a builtin way to do that as you are not really supposed to do it. All mounted paks are kind-of merged into a shared virtual filesystem where everything ends up in /Game/xxx
.
Asset registry module is completely independent from file system module so you cannot just ask it to “find assets in pak”.
However there are ways you can organize your stuff to work around this.
For example, if each pak is a theme, you could organize your assets (in editor) such that each theme has its own specific folder, eg:
- /Content/ClassicTheme/… —> ClassicTheme.pak
- /Content/SpaceTheme/… —> SpaceTheme.pak
- /Content/CastleTheme/… —> CastleTheme.pak
Then you can easily use asset registry to iterate assets by path, like this :
auto AssetRegistry = IAssetRegistry::Get();
TArray<FAssetData> Results;
AssetRegistry->GetAssetsByPath("/Game/SpaceTheme", Results, /*recursive*/true);
for (const auto& Data : Results)
{
// Print in canonical format: " AssetClass'/Path/To/Package.Object' "
UE_LOG(LogTemp, Log, TEXT("%s'%s.%s'")
, *Data.AssetClassPath.ToString()
, *Data.PackageName.ToString()
, *Data.AssetName.ToString()
);
}
Alternatively you can use a lower level approach, directly through the Pak system, though it is more complex.
Just like the asset manager has no concept of pak files, the pak system has no concept of assets either, it’s just files. You have to glue the two together yourself. When iterating filesystem (virtual) files, convert paths into asset paths that you can feed into AssetManager, or use as soft object paths for loading, depending on your needs.
Something like this :
auto PPF = (FPakPlatformFile*)FPlatformFileManager::Get().FindPlatformFile(TEXT("PakFile"));
/* get / iterate mounted pak files */
TArray<FString> PakNames;
PPF->GetMountedPakFilenames(PakNames);
for (const FString& PakName : PakNames)
{
UE_LOG(LogTemp, Log, TEXT("Pak: %s"), *PakName);
}
/* iterate files within a given pak file */
TArray<FString> Files;
PPF->GetPrunedFilenamesInPakFile(PakNames[0], Files);
for (const FString& File : Files)
{
// File format: "../../../MyProject/Content/SomeBlueprint.uasset"
UE_LOG(LogTemp, Log, TEXT("File: %s"), *File);
// Convert to an asset path: "/Game/SomeBlueprint"
FString AssetPath = FPackageName::FilenameToLongPackageName(File);
UE_LOG(LogTemp, Log, TEXT("Asset: %s"), *AssetPath);
// Retrieve corresponding AssetData from AssetManager
auto Assets = AssetRegistry->GetAssetsByPackageName(*AssetPath);
// Result is an array, though in most cases there should be only one
for (FAssetData* Data : Assets)
{
UE_LOG(LogTemp, Log, TEXT("%s'%s.%s'")
, *Data.AssetClassPath.ToString()
, *Data.PackageName.ToString()
, *Data.AssetName.ToString()
);
}
}