12 KiB
官方资源 Release 布局与资源侧契约
- 更新时间:2026-07-24
- 用途:冻结日服官方资源在本地发布根上的布局、URL 映射、seed 规则,以及
bat-api分发 path 的 1:1 对应关系。 - 范围:资源发现 / 清单 / 落盘 / 只读分发(不是完整游戏业务 API)。
- 权威代码:
- URL / 平台 / seed:
adapters/src/official/yostar_jp.rs - inventory 抽取:
adapters/src/official/inventory.rs - 落盘与 manifest:
infrastructure/src/official_download.rs(destination_for_url) - 发布布局:
infrastructure/src/official_update.rs - 分发:
cmd/bat-api+internal/api(见docs/reports/GO_STATUS.md)
- URL / 平台 / seed:
1. 产品边界(资源侧)
| 角色 | 组件 | 职责 |
|---|---|---|
| 同步 / 运维(近乎全自动) | Rust bat |
auto-discover、拉取、校验、发布、watch/daemon、RPC 后端 |
| 资源只读分发 | Go bat-api |
按官方 CDN path 提供已发布字节;经 bat.sock 发现版本 |
| 试验 CLI | Go cmd/bat → bin/bat-go |
非产品;禁止与 Rust bat 重名 |
禁止:把已安装客户端目录或 /home/wanye/D/BlueArchive 当作生产输入;真实全量样本优先服务器 release 或 /tmp 隔离目录。
2. 发布根布局(L1)
<output>/ # 官方原版资源发布根(--output / BAT_OUTPUT)
current -> versions/<id> # 原子 symlink,生产读侧
versions/<id>/ # 已发布 versioned release(= resource_root)
official-download-manifest.json
official-parse-cache.json # 校验后派生解析缓存,不是汉化产物
official-sync-snapshot.json # 常在 active root / current 下
prod-clientpatch.bluearchiveyostar.com/
<root_token>/
TableBundles/
TableCatalog.bytes
TableCatalog.hash
<table files...> # e.g. ExcelDB.db, Excel.zip
Windows_PatchPack/
BundlePackingInfo.bytes
BundlePackingInfo.hash
catalog_StandaloneWindows64.zip
catalog_StandaloneWindows64.hash
FullPatch_NNN.zip
Android_PatchPack/
BundlePackingInfo.bytes
BundlePackingInfo.hash
catalog_Android.zip
catalog_Android.hash
FullPatch_NNN.zip
MediaResources-Windows/
Catalog/MediaCatalog.bytes
Catalog/MediaCatalog.hash
GameData/...
Prologue/...
MediaResources/ # Android
Catalog/MediaCatalog.bytes
Catalog/MediaCatalog.hash
...
yostar-serverinfo.bluearchiveyostar.com/ # 若曾下载 server-info
<name>.json
.staging/<id>/ # 未发布写侧(失败可复用)
official-version-state.json # 发布根级版本状态
official-bootstrap-cache.json # auto-discover 缓存
<localized-output>/ # 汉化产物发布根(--localized-output / BAT_LOCALIZED_OUTPUT)
current -> versions/<id> # 已汉化后才切换;未汉化状态不发布
versions/<id>/ # 与官方相对路径一致的汉化资源
localized-version-state.json # 预留:后续 Patch 发布阶段维护,官方同步阶段不写入
官方资源发布和汉化发布是两个独立状态:
not_localized:官方原版资源已经完成下载、校验和发布,汉化资源尚未发布;这是官方同步完成后的默认状态。localized:同一官方版本的原版资源和汉化资源都已发布,生产侧可以同时提供两套资源。
2.1 读侧 vs 写侧
| 阶段 | 根目录 |
|---|---|
| 下载写入 | <output>/.staging/<id> |
| 发布完成 | rename 到 versions/<id>,再切换 current |
| 生产读取 / bat-api | current 解析后的 versioned 目录,或 RPC 给出的 version.resource_root |
3. URL → 磁盘映射(核心不变量)
实现:OfficialResourcePullService::destination_for_url。
https://{host}/{path...} → <resource_root>/{host}/{path...}
规则:
- 仅
https:// - host 必须是官方 JP 资源 host(见下节)
- path 分段不得为
./.. - 禁止 query / fragment(否则直接拒绝,避免同路径覆盖)
- 分段经 sanitize 后 join;结果必须在
resource_root内
3.1 官方 host
| Host | 用途 |
|---|---|
prod-clientpatch.bluearchiveyostar.com |
Addressables / Table / Media / PatchPack 内容 |
yostar-serverinfo.bluearchiveyostar.com |
server-info JSON |
(launcher 包 CDN 属于启动器链,不是默认资源 release 主体。)
3.2 bat-api 对外 path(1:1)
GET {public-base-url}/prod-clientpatch.bluearchiveyostar.com/<root_token>/...
≡ 磁盘 <resource_root>/prod-clientpatch.bluearchiveyostar.com/<root_token>/...
默认仅服务 download manifest 索引内且 Present + size 匹配 的文件。
4. official-download-manifest.json
| 字段 | 类型 | 说明 |
|---|---|---|
version |
u32 | 当前为 1 |
entries |
map URL → entry | 按完整官方 URL 为键(有序 BTreeMap) |
每条 entry:
| 字段 | 说明 |
|---|---|
url |
官方 https URL |
destination |
相对 resource_root 的路径(host/path...) |
bytes |
文件大小 |
blake3 |
本地 BLAKE3 hex |
权威清单:拉取闭环写入的 manifest;bat-api / RPC resource.manifest 以此为应有集合,再以磁盘校验 Present。
5. 发现与 seed URL 规则(L2)
常量根:
- server-info:
https://yostar-serverinfo.bluearchiveyostar.com - client-patch:
https://prod-clientpatch.bluearchiveyostar.com
AddressablesCatalogUrlRoot 形如:
https://prod-clientpatch.bluearchiveyostar.com/<root_token>
默认平台:Windows + Android。
5.1 平台目录名
| 平台 | Patch 目录 | Media 目录 | Addressables catalog zip |
|---|---|---|---|
| Windows | Windows_PatchPack |
MediaResources-Windows |
catalog_StandaloneWindows64.zip |
| Android | Android_PatchPack |
MediaResources |
catalog_Android.zip |
5.2 Seed 端点模板
共享(非平台):
{CLIENT_PATCH}/{token}/TableBundles/TableCatalog.bytes
{CLIENT_PATCH}/{token}/TableBundles/TableCatalog.hash
每平台:
{CLIENT_PATCH}/{token}/{PatchDir}/BundlePackingInfo.bytes
{CLIENT_PATCH}/{token}/{PatchDir}/BundlePackingInfo.hash
{CLIENT_PATCH}/{token}/{PatchDir}/{catalog_zip}
{CLIENT_PATCH}/{token}/{PatchDir}/{catalog_base}.hash
{CLIENT_PATCH}/{token}/{MediaDir}/Catalog/MediaCatalog.bytes
{CLIENT_PATCH}/{token}/{MediaDir}/Catalog/MediaCatalog.hash
5.3 Content URL 模板
| 类型 | 模板 |
|---|---|
| Table 文件 | {CLIENT_PATCH}/{token}/TableBundles/{Name} |
| Patch pack | {CLIENT_PATCH}/{token}/{PatchDir}/{FullPatch_NNN.zip} |
| Media 文件 | {CLIENT_PATCH}/{token}/{MediaDir}/{relative_path} |
relative_path 示例:GameData/Audio/VOC_JP/JP_Airi.zip、Prologue/Scenario/Event/10000_Title_Sound.ogg。
5.4 校验分层
| 对象 | 算法 / 规则 |
|---|---|
seed .bytes + .hash |
官方 .hash 为 xxHash32(seed=0) 的十进制文本;强校验 |
| 一般已下载文件 | 本地 manifest size + BLAKE3 |
.zip |
另加 ZIP central/local 结构校验 |
catalog_*.hash |
Addressables/SBP Hash128 文本标记,不是 seed 的 xxHash32 规则 |
6. Inventory 抽取规则(L3,当前实现)
实现:adapters/src/official/inventory.rs(可打印串启发式,非完整 schema 反序列化)。
| Catalog | 抽取逻辑 | 风险 |
|---|---|---|
BundlePackingInfo.bytes |
可打印串中扩展名为 zip 且匹配 FullPatch_NNN.zip(总长 17,中间 3 位数字) |
漏抽非 FullPatch 包名(当前有意只 FullPatch) |
TableCatalog.bytes |
可打印串中 .db/.zip 文件名;出现次数 ≥ 2 才收录 |
依赖「双份列表」启发式;形态变化会漏/多 |
MediaCatalog.bytes |
可打印串中相对路径,扩展名 zip/mp4/png/jpg/jpeg/ogg/wav | 路径须 is_plausible_relative_path |
R2 待真机核对:用服务器全量 seed 字节跑抽取,与 manifest 中 content URL 集合 diff;有未解释差异再改 inventory + fixture。
仓库内已有:adapters/tests/fixtures、infrastructure/tests/fixtures/official_regression;不能替代全量 release 实勘。
7. 客户端资源请求假设(R3,服务 bat-api)
| 面 | 假设(当前工程) | bat-api 行为 |
|---|---|---|
| client-patch 内容 | GET 官方 path;无业务鉴权头(资源 CDN) | GET/HEAD /prod-clientpatch.../... 原样字节 |
| server-info | GET JSON;字段 PascalCase(ConnectionGroups 等) |
可选加载并只改 AddressablesCatalogUrlRoot 指向 {public-base}/prod-clientpatch.../{token} |
seed .hash |
纯文本十进制(可含空白) | 原样分发 |
| Range / 断点 | 官方客户端下载器用 Range;bat 用 curl .part |
本轮 bat-api 可不实现 Range;记入后续 |
| 业务 ApiUrl/Gateway | 游戏协议 | 不改写、不仿造 |
Addressables 改写后客户端拼接:
{rewritten_root}/TableBundles/TableCatalog.bytes
≡ {public-base}/prod-clientpatch.../{token}/TableBundles/TableCatalog.bytes
与磁盘映射一致。
8. RPC 与分发发现顺序
bat-api(及任何 Go 服务层)发现当前 release:
daemon.statusdaemon.doctorcatalog.status(version.resource_root、addressables_root、app/bundle)resource.manifest分页(url / destination / bytes / blake3)- 在
resource_root上 Lstat 校验 Present / size
不读 bat-status.json / bat-tasks.json 作为常规路径。
配置:--socket / BAT_API_SOCKET;应急 --resource-root。见 cmd/bat-api/.env.example。
9. issue #2 / #3 样本索引(R4/R5 预置)
在服务器 release 上优先采集到 /tmp 隔离目录(不入库大文件):
| 用途 | 建议路径模式 |
|---|---|
| Addressables(#2) | {PatchDir}/catalog_*.zip 解压后的 JSON/bin + 旁路 .hash |
| UnityFS(#3) | FullPatch_*.zip 内抽样 .bundle,或已解包 bundle |
| seed 加固(R2) | 各平台 TableCatalog / BundlePackingInfo / MediaCatalog 的 .bytes+.hash |
字段目标(#2,已有 m_Crc 部分):继续扩大 hash/size/CRC/依赖等可校验字段覆盖。
结构目标(#3):header / block / directory / metadata / object table 引擎级解析。
10. 服务器实勘清单(R1,等 SSH)
连接信息到位后只读执行:
readlink current→ version id- 顶层是否仅有官方 host 目录 + manifest/snapshot
- manifest 条目数 vs 磁盘抽样 size
- RPC 四步(status → doctor → catalog.status → manifest 首页)
- 将结论写入
docs/reports/resource-server-survey-YYYYMMDD.md(无凭据)
所需:
SSH: user@host -p PORT
资源目录: .../official
bat.sock 或 state-dir: ...
11. 相关文档
docs/reports/GO_STATUS.md— Go 边界与进度docs/architecture/official-resource-backend.md— 拉取后端总览docs/reference/rpc-backend-api.md— RPC 契约docs/guides/official-resource-test-pull.md— 用户向运行说明docs/reports/CURRENT_GAPS.md— G-009 / #2 / #3
12. 变更纪律
- 改 URL 模板或落盘规则 → 必须同步本文 + 相关单测。
- 改 inventory 启发式 → 说明覆盖的真实风险并补 fixture。
- 真机实勘若发现与本文冲突 → 以真机为准 修代码与本文,禁止静默分叉。