4

I want to do this: Create and package original game. Then I want to create additional PAK files with new meshes/sounds/animations and blueprints based on blueprint in the original game. Original game should not know anything about additional meshes/animations/etc. So I need to create a smart system with AssetRegistry in the original game that scans all PAK files, load/mount them and with AssetRegistry scan those PAK files for all assets.

What I did to achieve my goal: I create and package successfully original game for the target platform (windows standalone). Then in the project, I create additional content and cook them for the target platform. I use UnrealPak.exe to create PAK files for additional content. I am able to load/mount PAK file in the original game by placing PAK file in Paks folder and they load/mount at startup of the game (this sentence is based on the LOG file from the original game, I don't know how to check if it is true or not). I am able to load/mount PAK file even with code by using FCoreDelegates::OnMountPak.Execute (this sentence is also based on the LOG file from the original game). So loading/mounting PAK files should work well. But now where is the biggest issue. I want to use AssetRegistry to scan for all assets in all PAK files. I tried everything I came up with. I tried ScanPathsSynchronous method, GetAllAssets method. Only what happens is it loads assets from ORIGINAL GAME PAK FILE. It seems that AssetRegistry doesn't know anything about other PAK files. I tried to tell AssetRegistry where are those files with AddPath method and still doesn't work.

So my example code what I tried is here:

         FString path1 = FPaths::ConvertRelativePathToFull(FString("../../../TestPaks/Content/Paks/test.pak"));
     FString path2 = FPaths::ConvertRelativePathToFull(FString("../../../TestPaks/Content/Paks/testmaterial.pak"));        

     bool check1 = false;
     bool check2 = false;
     if (FCoreDelegates::OnMountPak.IsBound())
     {
         check1 = FCoreDelegates::OnMountPak.Execute(path1, 0, nullptr); //Number should be 0-4; specifies search order
         check2 = FCoreDelegates::OnMountPak.Execute(path2, 0, nullptr); //Number should be 0-4; specifies search order
     }

     UE_LOG(LogTemp, Warning, TEXT("%s"), *path1);
     UE_LOG(LogTemp, Warning, TEXT("%s"), *path2);

     FString NewString1 = check1 ? "true" : "false";
     FString NewString2 = check2 ? "true" : "false";
     UE_LOG(LogTemp, Warning, TEXT("check 1 = %s"), *NewString1);
     UE_LOG(LogTemp, Warning, TEXT("check 2 = %s"), *NewString2);

     FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(FName("AssetRegistry"));
     IAssetRegistry& assetRegistry = AssetRegistryModule.Get();

     TArray<FString> ContentPaths;
     TArray<FAssetData> data;
     //assetRegistry.AddPath(path1);
     FString contentRelativeDir = TEXT("/Game/Paks");
     assetRegistry.AddPath(contentRelativeDir);
     assetRegistry.ScanPathsSynchronous({ contentRelativeDir });
     //assetRegistry.SearchAllAssets(true);
     assetRegistry.GetAllAssets(data, false);

     assetRegistry.GetAllCachedPaths(ContentPaths);
     for (FString& data : ContentPaths)
     {
         UE_LOG(LogTemp, Warning, TEXT("GetAllCachedPaths: %s"), *data);
     }

     FString NewString = FString::FromInt(data.Num());
     UE_LOG(LogTemp, Warning, TEXT("%s"), *NewString);

     for (int32 i = 0; i < data.Num(); i++)
     {
         FString s = data[i].AssetName.ToString();
         FString ss = data[i].AssetClass.ToString();
         UE_LOG(LogTemp, Warning, TEXT("%s | %s"), *s, *ss);
     }

I tried a lot of versions of paths and nothing is working. I am in this mess around 2 weeks and I don't have any much more tips on what to do and what will work. So how should this work properly??? I looked in forums here and StackOverflow and there are some solutions, but they don't work anymore.

Roman Skydan
  • 3,620
  • 2
  • 15
  • 37
Keri Enviro
  • 41
  • 1
  • 3
  • Hey, have you figured out what was the deal with `AssetRegistry`? It would be good to see a definite answer. P.S. And if Giap Tran's answer is indeed correct, mark it as an answer, please. – login_not_failed Jul 25 '19 at 13:14

1 Answers1

4

I have loaded asset from .pak file but I use FStreamableManager instead of AssetRegistry. I will describe what I do...

1) Mount .pak file: I just need to put additional .pak file to WindowNoEditor/[Project_Name]/Content/Paks/ folder (assumed that you package for window), game engine will auto mount that .pak file.

2) Load/Get asset from that .pak file:

FPakPlatformFile *PakPlatformFile;
FString PlatformFileName = FPlatformFileManager::Get().GetPlatformFile().GetName();
if (PlatformFileName.Equals(FString(TEXT("PakFile"))))
{
  PakPlatformFile = static_cast<FPakPlatformFile*>(&FPlatformFileManager::Get().GetPlatformFile());
}
else
{
  PakPlatformFile = new FPakPlatformFile;
    if (!PakPlatformFile->Initialize(&FPlatformFileManager::Get().GetPlatformFile(), TEXT("")))
    {
        UE_LOG(LogTemp, Error, TEXT("FPakPlatformFile failed to initialize"));
        return;
    }
    FPlatformFileManager::Get().SetPlatformFile(*PakPlatformFile);
}
TArray<FString> ArrAllMountedPakFile;
PakPlatformFile->GetMountedPakFilenames(ArrAllMountedPakFile);
for (int32 i = 0; i < ArrAllMountedPakFile.Num(); i++)
{
   FString PakFileName = ArrAllMountedPakFile[i];
   FString PakFilePathFull = FPaths::ConvertRelativePathToFull(PakFileName);
   FPakFile PakFile(PakPlatformFile, *PakFilePathFull, false);
   TArray<FString> FileList;
   FString MountPoint = PakFile.GetMountPoint();
   PakFile.FindFilesAtPath(FileList, *MountPoint, true, false, true);
   for (int32 i = 0; i < FileList.Num(); i++)
   {
       FString AssetName = FileList[i];
       FString AssetShortName = FPackageName::GetShortName(AssetName);
       FString FileName, FileExt;
       AssetShortName.Split(TEXT("."), &FileName, &FileExt);
       FString NewAssetName = TEXT("/Game/<path_to_asset>/") + FileName + TEXT(".") + FileName;

       FSoftObjectPath StrNewAssetRef = NewAssetName;
       FStreamableManager AssetLoader;
       UObject* NewLoadedObject = AssetLoader.LoadSynchronous(StrNewAssetRef);
       if (NewLoadedObject)
       {
           // do something, cast to compatible type.
       }
   }
}

Hope that to help you. Cheer !

Giap Tran
  • 41
  • 3