How to load assets from a pak file at runtime?

Now I have a pak file, which contains some .uasset files. I want to load the .uasset files at runtime but the code doesn’t work right. The code is as below:

    IPlatformFile &PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
    FPakPlatformFile *PakPlatfromFile = new FPakPlatformFile;
    PakPlatfromFile->Initialize(&PlatformFile, TEXT(""));
    FPakFile PakFile(PakFileName, false);
    UE_LOG(LogDynamicStaticMeshActor, Log, TEXT("Init - IsPakFileValid:%d"), PakFile.IsValid());
    FString MountPoint(FPaths::EngineDir());
    int32 PakOrder = 0;
    if (!PakPlatfromFile->Mount(PakFileName, PakOrder, *MountPoint)) {
        UE_LOG(LogDynamicStaticMeshActor, Fatal, TEXT("Mount error"));
    }

    UObjectLibrary *ObjectLibrary = ConstructObject<UObjectLibrary>(UObjectLibrary::StaticClass());
    ObjectLibrary->UseWeakReferences(true);
    ObjectLibrary->AddToRoot();
    UE_LOG(LogDynamicStaticMeshActor, Log, TEXT("Before load asset"));
    ObjectLibrary->LoadAssetDataFromPath(MountPoint);
    if (ObjectLibrary->IsLibraryFullyLoaded()) {
        UE_LOG(LogDynamicStaticMeshActor, Log, TEXT("Fully loaded"));
        ObjectLibrary->LoadAssetsFromAssetData();
    }

    TArray<FAssetData> AssetDataList;
    int32 count = ObjectLibrary->GetAssetDataCount();
    UE_LOG(LogDynamicStaticMeshActor, Log, TEXT("count:%d"), count);

It seems the mount step is successful, but when it runs to ObjectLibrary->LoadAssetDataFromPath(MountPoint), it is not fully loaded belong to the log, and ObjectLibrary->GetAssetDataCount() returns zero.

Also I’ve tried other ways:

void ADynamicStaticMeshActor::Init(const TCHAR* PakFileName) {
    IPlatformFile &PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
    FPakPlatformFile PakPlatfromFile;
    PakPlatfromFile.Initialize(&PlatformFile, TEXT(""));
    FPakFile PakFile(PakFileName, false);
    UE_LOG(LogDynamicStaticMeshActor, Log, TEXT("Init - IsPakFileValid:%d"), PakFile.IsValid());
    FString MountPoint(TEXT("/Engine/Content/DLC/"));
    int32 PakOrder = 0;
    if (!PakPlatfromFile.Mount(PakFileName, PakOrder, *MountPoint)) {
        UE_LOG(LogDynamicStaticMeshActor, Fatal, TEXT("Mount error"));
    }

    TArray<FString> AssetFileNames;
    PakFile.FindFilesAtPath(AssetFileNames, *MountPoint);

    for (const FString &AssetName : AssetFileNames) {
        UE_LOG(LogDynamicStaticMeshActor, Log, TEXT("AssetName:%s"), *AssetName);
    }

    FString MaterialFilePath = MountPoint + TEXT("BR_DongChenMingHan_6.uasset");
    FString MaterialFileContent;
    FFileHelper::LoadFileToString(MaterialFileContent, *MaterialFilePath);
    UE_LOG(LogDynamicStaticMeshActor, Log, TEXT("Path:%s Content:%s"), *MaterialFilePath, *MaterialFileContent);

    UStaticMeshComponent *StaticMeshComponent = NewObject<UStaticMeshComponent>(this, TEXT("staticMeshCom"));
    FStreamableManager StreamableManager;
    FString AssetName(MaterialFilePath);
    FStringAssetReference AssetRef(AssetName);
    Cast<UMaterial>(StaticLoadObject(UMaterial::StaticClass(), nullptr, *AssetName));
    UObject *Object = StreamableManager.SynchronousLoad(AssetRef);
    UMaterial *Material = Cast<UMaterial>(Object);
}

it could not load the assset file BR_DongChenMingHan_6.uasset to string. So I’m not sure whether the mount step is successful? And when loading the asset using StaticLoadObject, It logs “can’t find object” and I am really confused about this log for the file path seems correct.
The related log is as below:

LogDynamicStaticMeshActor: Init - IsPakFileValid:1
LogDynamicStaticMeshActor: Path:/Engine/Content/DLC/BR_DongChenMingHan_6.uasset Content:
LogLinker:Warning: Can't find file '/Engine/Content/DLC/BR_DongChenMingHan_6'
LogLinker:Warning: Can't find file '/Engine/Content/DLC/BR_DongChenMingHan_6'
LogUObjectGlobals:Warning: Failed to find object 'Material /Engine/Content/DLC/BR_DongChenMingHan_6.uasset'
LogDynamicStaticMeshActor: Before load Object
LogLinker:Warning: Can't find file '/Engine/Content/DLC/BR_DongChenMingHan_6'
LogUObjectGlobals:Warning: Failed to find object 'Object /Engine/Content/DLC/BR_DongChenMingHan_6.uasset'
LogStreamableManager: Failed attempt to load /Engine/Content/DLC/BR_DongChenMingHan_6.uasset

It’s very kind of u if anyone teach me the right resolution, for I’ve spent several days on this problem.

I don’t understand why you use LoadFileToString. Why do you want to load a uasset into a string ? Maybe this is because I don’t use FStreamableManager but I would build this way :

FString MaterialFilePath = MountPoint + TEXT("BR_DongChenMingHan_6.BR_DongChenMingHan_6"); // the reference to the object in the engine, not the path of the file
UMaterial *Material = Cast<UMaterial>(StaticLoadObject(UMaterial::StaticClass(), NULL, *MaterialFilePath));

Also I don’t understand why this line don’t return any log :

UE_LOG(LogDynamicStaticMeshActor, Log, TEXT("AssetName:%s"), *AssetName);

Are you sure that you have uasset files into your pak file ?

I mistakenly thought the mount is just like the shell command mount, which maps the files under a path. But I still don’t understand what “the reference to the object in the engine” exactly means, would u mind give me some documents? After all, it still logs can’t find file ‘/Engine/Content/DLC/BR_DongChenMingHan_6’ even though I change the path to MountPoint + TEXT(“BR_DongChenMingHan_6.BR_DongChenMingHan_6”)

that UE_LOG(LogDynamicStaticMeshActor, Log, TEXT(“AssetName:%s”), *AssetName) doesn’t log may be because that PakFile.setMountPoint is not called. And I am quite sure the pak file contains BR_DongChenMingHan_6.uasset for I’ve extracted it to a folder using UnrealPak.exe

The reference to the object is what you get in the editor when you right click on an asset and pick “copy reference”. You can see that even if this is a path, the extension is not ‘.uasset’. It looks like ‘/Game/Content/DLC/BR_DongChenMingHan_6.BR_DongChenMingHan_6’ and Game/ is replaced by /Engine when the asset is mounted. So yes the mount kind of maps the files under a path but not exactly I guess.

Anyway you already have a problem before if the *AssetName is not logged during your loop. I don’t see any difference between your code and mine so if you are absolutely sure that you have your asset into your pak file I don’t know what your problem is.

Thank you for your reply and now I can load assets under the game folder at runtime, but still cannot load assets from a pak file. I’m absolutely sure that the pak file contains the assets. Or would u mind show me the right code, for I’ve spent tens of hours on this problem but still have no answer.

这个问题,我也在研究,好像PAK文件mount后,必须要注册,见引擎源文件的UObjectBase::AddObject接口,加我的QQ:1346362278

No, sorry, I can’t. I don’t have the legal right to do this.

When I put the *.pak file on default folder “./Content\Paks” and application init for the first time it load the asset and I can use it.
But if I drag and drop another *.pak file to the same folder during runtime, the application don’t load the content to memory. Even if I code an explicit method to do it.

It’s possible to replicate the behaviour of loading a *.pak file content at init() method during runtime ?

Regards,
Nelson

我是在异步加载资源的时候遇到问题,FStreamableManager 的RequestAsyncLoad方法,日志输出LogLinker:Warning: The file ‘…/…/…/LoadTest/Content/Content/ArchVis/Textures/T_Wood_S.uasset’ contains unrecognizable data, check that it is of the expected type.
是不是我pak文件生成有问题,你的pak文件是怎么生成的,我用的ProjectLauncher来做的基于一个release的dlc

我现在也在做从pak文件中加载*.uasset,可以mount到指定的目录,但是最后加载*.uasset失败,大家能给点建议吗?

Hi~

I have just solved this problem.

The key is the asset’s path.

Remeber,When you are using the StaticLoadObject method.

You path should be Path1/Path2/Pathxx/AssetName.AssetName

Instead of AssetName.uasset or AssetName.umap…

try to change the path and let me know if you solve this problem

Here is my code,and it worked correctly!!

1 Like

Guys please help!

我也是这个问题!!!!!!

Copy&Paste

    void AAssetLoad::LoadPakFile()
	{
		IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
		FPakPlatformFile* PakPlatformFile = new FPakPlatformFile(); 
		PakPlatformFile->Initialize(&PlatformFile, TEXT(""));
		FPlatformFileManager::Get().SetPlatformFile(*PakPlatformFile);

		const FString PakFilename = FPaths::GameContentDir() + TEXT("Data/OutPak1.pak");
		FPakFile PakFile(*PakFilename, false);
		
		const FString MountPoint(FPaths::EngineContentDir());
		PakFile.SetMountPoint(*MountPoint);

		if (PakPlatformFile->Mount(*PakFilename, 0, *MountPoint))
		{
			UE_LOG(LogClass, Log, TEXT("Mount Success"));
			TArray<FString> FileList;

			PakFile.FindFilesAtPath(FileList, *PakFile.GetMountPoint(), true, false, true);
			FStreamableManager StreamableManager;
			
			// Static load object
			FString AssetName = FileList[0];
			FString AssetShortName = FPackageName::GetShortName(AssetName);
			FString LeftStr;
			FString RightStr;
			AssetShortName.Split(TEXT("."), &LeftStr, &RightStr);
			AssetName = TEXT("/Engine/") + LeftStr + TEXT(".") + LeftStr;
			FStringAssetReference Reference = AssetName;

			UObject* LoadObject = StreamableManager.SynchronousLoad(Reference);
			if (LoadObject != nullptr)
			{
				UE_LOG(LogClass, Log, TEXT("Object load Success..."));
			}
			else
			{
				UE_LOG(LogClass, Error, TEXT("Can't load asset..."));
			}
		}
		else
		{
			UE_LOG(LogClass, Error, TEXT("Mount failed"));
		}
	}

Its been some month since I did that stuff. If I remember right this code did not work for me directly either. You also must make sure you mountpoint and stuff is correct. He sets the mountpoint manually. Try to omit that. The mountpoint is in the pakfile and should get read automatically. Try debug the code and see where it goes wrong.

Another thing: This is very basic code just to get you started. The code creates a new FPakPlatformfFile every time. That is ■■■■■■■■. You only need one. I made a singleton class that creates that file uppon creation and caches it.

I wanted to provide the Plugin I made via Marketplace, but as I’m again working on other stuff I haven’t got to test it toroughly.

Print “Can’t load asset…”