运行时在 Pak 中访问非资源文件

可以把一些非 UE 资源文件(比如 txt,视频)等文件打包到 Pak 中,在游戏运行中访问,可以使用我上面写的 HotPatcher 工具来打包,这里写一下在运行时访问的方法。

首先将文件打包到 Pak:

这里我是将文件 AAAAA.json 打包到了 Pak 中,其挂载路径为../../../PROJECT_NAME/AAAAA.json.

在游戏中访问一定要使用挂载路径,可以使用 FPaths::ProjectDir 在打包后获取到的是相对路径,在 PIE 下是项目的相对路径。

使用方法:

其中的 PeojectDirFPaths::ProjectDirLoadFileToString则是 IFileManager::LoadFileToString 的封装。

运行结果:

如果想要访问打包出的项目文件和挂载的 Pak 中的文件,可以使用下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void UPakVisitorHelper::VisitorProjectDir()
{
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();

FFillArrayDirectoryVisitor Visitor;
PlatformFile.IterateDirectory(*FPaths::ProjectDir(), Visitor);

UE_LOG(LogTemp,Log,TEXT("Found Files:"));
for (const auto& File : Visitor.Files)
{
UE_LOG(LogTemp, Log, TEXT("%s"), *File);
}
UE_LOG(LogTemp, Log, TEXT("Found Directorys:"));
for (const auto& Dir : Visitor.Directories)
{
UE_LOG(LogTemp, Log, TEXT("%s"), *Dir);
}
}

IPlatformFile::IterateDirectory这个函数有两个原型:

1
2
virtual bool IterateDirectory(const TCHAR * Directory, FDirectoryVisitor Visitor);
virtual bool IterateDirectory(const TCHAR * Directory,FDirectoryVisitorFunc Visitor);

可以传入一个继承自 FDirectoryVisitor 的对象,或者传入一个下列签名的函数对象:

1
typedef TFunctionRef < bool(const TCHAR *, bool)> FDirectoryVisitorFunc

支持传入一个 Lambda 也是可以的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
TArray<FString> Files;
TArray<FString> Dirs;

IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
auto FallArrayDirVisitor = [&Files,&Dirs](const TCHAR* InItem,bool bInDir)->bool
{
if (bInDir)
{
Dirs.AddUnique(InItem);
}
else
{
Files.AddUnique(InItem);
}
return true;
};
PlatformFile.IterateDirectory(*InRelativePath, FallArrayDirVisitor);

执行结果:

AssetRegistry.bin/*.uproject等文件都是在打包的时候打包进 pak 里的,AAAAA.json则是上面手动打到 Patch 的 Pak 里的。