4.5 版本,原神启动器开始灰度测试全新的 Chunk 下载模式
该下载模式可以解决长期困扰玩家的 “安装/更新游戏需要预留两倍安装/更新包空间” 的问题,4.5版本游戏本体+单语音包已经达到 84G 的大小,传统下载模式需要用户预留接近 170G 的硬盘空间
开启 Chunk 下载模式
新下载模式疑似已在 4.6 版本全量启用
新下载模式正处于灰度测试中,启动器会请求以下 API 判断是否开启
https://abtest-api-data.mihoyo.com/data_abtest_api/config/experiment/list
使用 Fiddler 等工具将其中一个请求返回的 downloadMode
字段由 file
修改为 chunk
即可强行启用新下载模式
{
...
"data": [
{
...
"configs": {
"downloadMode": "chunk"
},
...
}
]
}
开启 Chunk 下载模式后的启动器:
获取 Manifest
启动器使用以下 API 获取游戏包体信息
国服 main 分支(已停止更新)
https://api-takumi.mihoyo.com/downloader/sophon_chunk/api/getBuild?branch=main&package_id=s8m3Yf3j6G&password=QlYzM79uF6va&plat_app=cxgf44wie1a8
国服 predownload 分支(已停止更新)
https://api-takumi.mihoyo.com/downloader/sophon_chunk/api/getBuild?branch=predownload&package_id=s8m3Yf3j6G&password=izObT6iTHAqq&plat_app=cxgf44wie1a8
国服 main 分支(HYP)
https://api-takumi.mihoyo.com/downloader/sophon_chunk/api/getBuild?branch=main&package_id=8xfMve0uwQ&password=CW8GbLNU8f&plat_app=ddxf5qt290cg
国服 predownload 分支(HYP)
https://api-takumi.mihoyo.com/downloader/sophon_chunk/api/getBuild?branch=predownload&package_id=8xfMve0uwQ&password=EPq5oNru9q&plat_app=ddxf5qt290cg
此 API 返回数据中包含了 tag(游戏版本)和游戏包及语音包的 manifest 信息
4.5.0 版本游戏本体 manifest 信息示例:
{
"category_id": "10017",
"category_name": "游戏资源-外网",
"manifest": {
"id": "manifest_233f3acd5276c84e_890ab337d4ec8edf6c98c4dcf702b8bf",
"checksum": "890ab337d4ec8edf6c98c4dcf702b8bf",
"compressed_size": "4736513",
"uncompressed_size": "9818860"
},
"chunk_download": {
"encryption": 0,
"password": "",
"compression": 1,
"url_prefix": "https://autopatchcn.yuanshen.com/client_app/sophon/chunks/cxgf44wie1a8/62nfHL6ocpNF",
"url_suffix": ""
},
"manifest_download": {
"encryption": 0,
"password": "",
"compression": 1,
"url_prefix": "https://autopatchcn.yuanshen.com/client_app/sophon/manifests/cxgf44wie1a8/62nfHL6ocpNF",
"url_suffix": ""
},
"matching_field": "game",
"stats": {
"compressed_size": "75506162967",
"uncompressed_size": "76752839912",
"file_count": "16115",
"chunk_count": "74156"
},
"deduplicated_stats": {
"compressed_size": "75443433225",
"uncompressed_size": "76650339773",
"file_count": "16115",
"chunk_count": "74077"
}
}
使用 manifest_download.url_prefix
与 manifest.id
进行拼接即可获取 manifest 数据
此 API 返回的download
信息中包含暂未使用的encryption
与password
字段,这意味着后续版本中 manifest 与 chunk 文件可能会被加密,或者也可能是仅用于测试服的加密
解析 Manifest
manifest 是一个使用 zstd 算法压缩的 protobuf 数据包,其中包含了文件基础信息以及文件的分块信息,由 Blackbox Protobuf 工具解析后得到以下结构
{
"1": {
"type": "message",
"message_typedef": {
"1": {
"type": "string",
"example_value_ignored": "pkg_version"
},
"2": {
"type": "message",
"message_typedef": {
"1": {
"type": "string",
"example_value_ignored": "6ed042e749b0c6b1_84c069f03b872025728b592e7448e031"
},
"2": {
"type": "string",
"example_value_ignored": "84c069f03b872025728b592e7448e031"
},
"3": {
"type": "int",
"example_value_ignored": 2621003
},
"4": {
"type": "int",
"example_value_ignored": 50321
},
"5": {
"type": "int",
"example_value_ignored": 232573
},
"6": {
"type": "int",
"example_value_ignored": -5162654371156066304
}
},
"seen_repeated": true
},
"3": {
"type": "int",
"example_value_ignored": 64
},
"4": {
"type": "int",
"example_value_ignored": 2853576
},
"5": {
"type": "string",
"example_value_ignored": "069a8b21002eee2aaa2c5a9ecc64615e"
}
},
"seen_repeated": true
}
}
根据以上文件结构编写 proto 文件对 manifest 进行反序列化以获得可读数据
proto 文件示例:
Chunk 字段6 的作用暂不清楚,记为 Unknown
syntax = "proto3";
package manifest;
message Chunk {
string Id = 1;
string Checksum = 2;
int32 Offset = 3;
int32 CompressedSize = 4;
int32 UncompressedSize = 5;
int32 Unknown = 6;
}
message File {
string Path = 1;
repeated Chunk Chunks = 2;
bool IsFolder = 3;
int32 Size = 4;
string Checksum = 5;
}
message Manifest {
repeated File Files = 1;
}
反序列化结果示例(File HoYoKProtect.sys):
{
"Path": "HoYoKProtect.sys",
"Chunks": [
{
"Id": "d9b860120f8ccdb8_5599af11843b5088088aa9d40e75a8b2",
"Checksum": "5599af11843b5088088aa9d40e75a8b2",
"CompressedSize": 1115436,
"UncompressedSize": 1247585,
"Unknown": 346030080,
"Offset": 0
},
{
"Id": "e3328979a868c6e8_7c5efd948e2a5bed89cf195b20f74282",
"Checksum": "7c5efd948e2a5bed89cf195b20f74282",
"Offset": 1247585,
"CompressedSize": 1177009,
"UncompressedSize": 1188402,
"Unknown": 1256456192
},
{
"Id": "4da30f28403f5f1c_470a3eb15ace803c3d934f3e2245f779",
"Checksum": "470a3eb15ace803c3d934f3e2245f779",
"Offset": 2435987,
"CompressedSize": 755378,
"UncompressedSize": 770792,
"Unknown": 742391808
},
{
"Id": "d2ee63fcff6f7529_02a72d7f9b17024d19d1527bbae1bda8",
"Checksum": "02a72d7f9b17024d19d1527bbae1bda8",
"Offset": 3206779,
"CompressedSize": 422551,
"UncompressedSize": 491973,
"Unknown": -1927368755
}
],
"Size": 3698752,
"Checksum": "3336116e64580ac8b7def9e584be87eb",
"IsFolder": false
}
Chunk.Id
为 压缩后数据的xxhash64
拼接 未压缩数据的md5
,manifest.id
也为类似的格式
下载与合成文件
使用 chunk_download.url_prefix
与 Chunk.Id
进行拼接即可获取 chunk 数据
将文件的所有 chunk 使用 zstd 算法进行解压后根据 Offset 进行拼接即可合成完整的文件数据
在下载文件时,下载器会将 chunk 数据下载至 游戏安装目录/chunk
chunk 下载完成后会在 游戏安装目录/staging
中根据 Offset 信息进行拼接,staging
的目录结构与游戏文件目录结构一致
当某文件的所有 chunk 都合并完成并校验通过后就会被从 staging
目录中移至游戏安装目录下
参考
[Document] 原神启动器的 Chunk 下载模式分析 · Issue #725 · Scighost/Starward (github.com)
4.8预下载更新了嘛 manifest里的md5和下载的文件对应不上
文章里提到的这个 API 是旧启动器使用的,随着旧启动器的弃用已经停止更新数据了,可以使用 https://hyp-api.mihoyo.com/hyp/hyp-connect/api/getGameBranches?launcher_id=jGHBHlcOq1 这个 API 获取新启动器的 Chunk 配置
例如当前 predownload 分支的地址是:https://api-takumi.mihoyo.com/downloader/sophon_chunk/api/getBuild?branch=predownload&package_id=8xfMve0uwQ&password=EPq5oNru9q
类似于Steam的下载原理?
是的,我没详细分析过 Steam 的下载过程,不过大致看了下应该是类似的原理,下载 Chunk 然后拼接成游戏文件
谢谢指路,学习了