Pak 与 IoStore

自动关联目录:Pak 与 IoStore

Pak 是 UE 的资源容器:把成百上千个散文件打包成一个大文件,减少 IO 次数、便于分发、便于加密与更新。UE5 引入了 IoStore(.utoc + .ucas)作为新一代容器。

一句话定位:Pak 解决"文件太多",IoStore 解决"IO 太随机";而挂载顺序决定谁覆盖谁,这是热更新的全部原理。

Pak 结构

MyGame-Windows.pak
├── Index(文件表:路径 → 偏移/大小/压缩方式/Hash)
├── 加密的 Index(可选)
└── Data(所有资产的内容,按块压缩)
特性说明
只读运行时不写入
可挂载多个后挂载的优先
可加密/签名见下文
可压缩省体积,代价是解压时间
命名决定优先级带 _P(patch)后缀的优先级更高

常用命令:

UnrealPak.exe MyGame.pak -List                 # 列出内容
UnrealPak.exe MyGame.pak -Extract ExtractDir   # 解包
UnrealPak.exe Out.pak -Create=response.txt     # 打包(response 文件描述内容)

挂载顺序

多个 pak 里如果有同名资产,优先级高的那个生效。优先级由 pak 文件名和挂载顺序共同决定。

(低)  MyGame-Windows.pak          主包
   ↑
        MyGame-Windows_P.pak       补丁包(_P 后缀,优先级更高)
   ↑
(高)  运行时动态挂载的 pak
FPakPlatformFile* PakPlatform = (FPakPlatformFile*)FPlatformFileManager::Get().FindPlatformFile(TEXT("PakFile"));
PakPlatform->Mount(TEXT("D:/Patch/MyPatch.pak"), PakOrder, TEXT("D:/Patch/"));

PakOrder 越大优先级越高。热更新的本质就是:发一个优先级更高的 pak,里面放新版本的资产。

IoStore

PakIoStore
文件.pak.utoc(索引)+ .ucas(内容)
设计目标减少文件数减少随机 IO,优化加载
索引方式文件路径按 chunk 组织的容器,读取更连续
UE5 默认否是(可关闭)
补丁覆盖式 pak支持 Patch 容器层
[/Script/Engine.Engine]
bUseIoStore=True
bUseZenStore=False

IoStore 的收益在移动端最明显——移动设备的随机 IO 代价极高,容器化后加载时间能明显下降。

代价是工具链更复杂:解包要同时处理 .utoc 和 .ucas,热更新的容器合并逻辑也比单纯覆盖 pak 麻烦。

签名与加密

机制作用代价
Index 加密隐藏文件表,无法直接 -List需配置密钥
内容加密资产内容加密,无法直接解包运行时解密开销
签名验证 pak 未被篡改启动校验时间
主索引签名防止伪造整个包—
[/Script/UnrealEd.ProjectPackagingSettings]
bEncryptIniFiles=True
bEncryptPakIndex=True
bEncryptPakFiles=False            # 全包加密,开销大,按需
bEnablePakSigning=True

密钥在 DefaultCrypto.ini(不要提交到公开仓库)。

加密只能提高门槛,不能防住决心逆向的人——见 Security。判断是否值得加密的标准是:被解包的商业损失 vs 运行时的解密开销与兼容性风险。

压缩

维度不压缩压缩
包体大小(通常 40–60%)
加载快(直接读)慢(要解压)
内存无额外解压缓冲
适用主机/PC、磁盘空间不敏感移动端、下载体积敏感
[/Script/UnrealEd.ProjectPackagingSettings]
bCompressPaks=True

移动端推荐做法:包体压缩(省下载),但对启动时必需的资源单独放不压缩的 chunk,避免开局慢。

分块与按需下载

方案说明
ChunkDownloader 插件UE 官方的按需下载,读 BuildManifest-*.json
自定义下载自己管理 pak 下载 + Mount
平台机制Android App Bundle / iOS On-Demand Resources

流程:

1. 启动时读本地版本清单
2. 比对服务器清单,算出缺失/过期的 chunk
3. 下载 pak 到本地持久目录
4. 校验(大小 + 哈希)
5. Mount,通知游戏可用

下载一定要校验:下载中断会产生截断的 pak,挂载后表现为各种诡异的资源错误。

与热更新的关系

热更新的完整链路见 热更新与补丁。这里只需记住三条:

  1. 新 pak 的优先级必须高于旧 pak(文件名 _P 后缀或更大的 PakOrder)
  2. pak 一旦挂载,同名资产就被覆盖,原 pak 里的旧版本不再生效
  3. 删除 pak 等于回滚——但已加载进内存的资产不会立刻变

排查

现象查什么
更新后资源没变pak 挂载顺序、PakOrder、文件名后缀
pak 挂载失败路径、签名校验、文件完整性
解包看不到内容是否开了 index 加密
加载变慢(UE5 升级后)IoStore 配置、压缩设置
包里缺资产回到 Cook 阶段的引用链
// 打印当前挂载的 pak 列表
TArray<FString> MountedPaks;
FCoreDelegates::OnMountPak.IsBound();
// 或用 -logpaks 启动参数

常见坑

坑说明
补丁 pak 优先级没设高更新不生效
pak 放在会被系统清理的目录移动端常见,更新后丢失
下载后没校验就挂载截断的 pak 导致随机资源错误
加密密钥泄露在仓库等于没加密
全包加密导致加载变慢只加密 index 通常够用
移动端开了压缩导致开局慢关键资源应放不压缩 chunk
混用 pak 与 IoStore 配置不一致部分资产读不到
热更新后没重启就期望生效已加载资源需重新加载或重启