mirror of
https://github.com/Yuyi-Oak/BlueArchiveToolkit.git
synced 2026-09-18 11:34:59 +08:00
feat(assetbundle): 完善官方资源解析与双目录发布
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
# AssetBundle 与资源解析路线图
|
||||
|
||||
- **更新时间**:2026-07-25
|
||||
- **适用范围**:Rust 解析引擎、官方同步后的解析缓存、CAS/ResourceRepository 接入、后续文本提取和 Patch 发布。
|
||||
- **权威关联**:`PROJECT_PLAN.md` Milestone 3/4/5/8,`docs/reports/CURRENT_GAPS.md` G-005/G-007/G-011/G-011D。
|
||||
|
||||
---
|
||||
|
||||
## 1. 目标边界
|
||||
|
||||
解析系统的目标不是把下载流程写成一次性脚本,而是建立可长期维护的资源理解层:
|
||||
|
||||
1. 官方资源同步负责拉取、校验和发布原版资源。
|
||||
2. 解析器只读取已发布或 staging 中已校验的资源,不修改原始文件。
|
||||
3. 解析结果写入派生缓存、CAS 索引或后续文本提取索引。
|
||||
4. 汉化产物只能由 Patch/发布阶段写入 `localized-output`,不能写回官方资源目录。
|
||||
5. 解析器必须与 CLI、daemon、Go API、Patch 业务流程解耦。
|
||||
|
||||
当前官方同步完成后会维护 `official-parse-cache.json`。它是官方 release 的派生索引,不是汉化产物;本地 URL、相对路径、size 和 BLAKE3 未变化时应复用旧解析结果并跳过重复解析。
|
||||
|
||||
---
|
||||
|
||||
## 2. 分层模型
|
||||
|
||||
解析能力按从外到内分层:
|
||||
|
||||
| 层级 | 输入 | 输出 | 当前状态 |
|
||||
| --- | --- | --- | --- |
|
||||
| 官方 seed manifest | `TableCatalog.bytes`、`BundlePackingInfo.bytes`、`MediaCatalog.bytes` | 完整下载 URL、相对路径、hash 校验边界 | 已用于下载计划,仍需沉淀更多结构化字段 |
|
||||
| Addressables catalog | `catalog_*.zip` 内 JSON/bin catalog、`catalog_*.hash` | asset path、provider、dependencies、size、CRC、bundle name | JSON/compact 当前样本已覆盖,仍需更多真实结构变体 |
|
||||
| UnityFS container | `.bundle`、zip 内 bundle | header、block、directory、解压文件、基础摘要 | 已支持基础解包、LZ4/LZMA、边界校验 |
|
||||
| Serialized file | UnityFS directory 文件 | header、type table、TypeTree node、object table、TextAsset bytes | 已支持基础表结构和 TextAsset bytes |
|
||||
| Unity 对象字段 | TextAsset、MonoBehaviour、ScriptableObject | 可翻译文本单元、上下文、资源定位 | TextAsset bytes 已有入口,字段级反序列化未完成 |
|
||||
| Patch 发布前解析 | 已翻译文本、中间格式、原版资源 | 可验证 patch manifest、汉化 release 目录 | 未完成 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 当前已落地能力
|
||||
|
||||
`crates/bat-assetbundle` 已经承担解析核心:
|
||||
|
||||
1. `UnityFsParser` 解析 UnityFS header、block info、directory。
|
||||
2. 支持 LZ4/LZMA block info 和数据 block 解压。
|
||||
3. 支持 block info at end 和官方样本中出现的 block data alignment。
|
||||
4. 能从 UnityFS directory 提取文件 bytes。
|
||||
5. `serialized` 模块能读取 Unity serialized file header、type table、TypeTree node 元数据、object table。
|
||||
6. 能提取 TextAsset 的 name 和原始 bytes。
|
||||
7. `ResourceImportService` 能把 AssetBundle 摘要、TextAsset/Table/Media 分类写入导入报告。
|
||||
8. 官方同步后 `OfficialParseCacheService` 能从 `official-download-manifest.json` 遍历所有资源,解析直接 bundle 和 zip 内条目,非候选资源记录为 unsupported。
|
||||
|
||||
当前还不能宣称完整:
|
||||
|
||||
1. MonoBehaviour/ScriptableObject 的 TypeTree 字段级反序列化未完成。
|
||||
2. Unity managed reference、PPtr、array/map、string alignment 等复杂字段未完整覆盖。
|
||||
3. Addressables bin/compact catalog 结构变体仍需真实样本驱动补齐。
|
||||
4. 解析结果尚未自动进入用户级 CAS + ResourceRepository 查询流程。
|
||||
5. 不能重写 AssetBundle,也不能生成可发布汉化 patch。
|
||||
|
||||
---
|
||||
|
||||
## 4. 补全顺序
|
||||
|
||||
### P0:解析缓存和样本闭环
|
||||
|
||||
目标:让官方同步后的解析结果可复用、可诊断、可回归。
|
||||
|
||||
交付:
|
||||
|
||||
1. `official-parse-cache.json` 记录 manifest entry、zip entry、解析状态、Unity 版本、文件数、TextAsset 数、错误摘要和缓存复用状态。
|
||||
2. 解析直接 `.bundle` / `.unity3d` 和 zip 内全部文件条目,不能只假设 `FullPatch_*.zip`。
|
||||
3. 非候选资源记录为 unsupported,不影响官方同步发布。
|
||||
4. 缺失、损坏或无法解析的 bundle 记录 failed,但不回滚已经完成校验的官方原版 release。
|
||||
5. 用合成 fixture、隔离真实样本和回归 fixture 覆盖缓存复用、zip 内条目、非候选资源、解析失败。
|
||||
|
||||
验收:
|
||||
|
||||
1. 第二次运行同一 release 时能看到解析缓存复用计数。
|
||||
2. 修改任意 manifest entry 的 size/BLAKE3 后,只重新解析对应资源。
|
||||
3. 解析缓存不会写入 `localized-output`。
|
||||
|
||||
### P1:Addressables catalog 完整化
|
||||
|
||||
目标:把“能列出资源”推进到“能稳定定位 bundle、依赖、校验字段和资源类型”。
|
||||
|
||||
交付:
|
||||
|
||||
1. 覆盖 JSON catalog、compact JSON、可能的二进制 catalog 入口。
|
||||
2. 解析 provider id、internal id、primary key、dependency key、resource type、bundle name、hash、size、CRC。
|
||||
3. 明确 `catalog_*.hash` 只作为 Addressables remote catalog marker,不套用 seed `.hash` 的 xxHash32 规则。
|
||||
4. 将 Windows/Android catalog 样本拆成可复现 fixture,不把大文件纳入 Git。
|
||||
5. 对未知结构返回明确错误或保真 raw metadata,不静默丢字段。
|
||||
|
||||
验收:
|
||||
|
||||
1. 当前目标版本 Windows/Android catalog 样本集合解析通过。
|
||||
2. 解析结果能反查 bundle 文件和依赖链。
|
||||
3. size/CRC/hash 字段能参与本地文件验证或至少进入诊断报告。
|
||||
|
||||
### P2:Unity Serialized 字段级解析
|
||||
|
||||
目标:把 Unity object table 推进到可提取文本字段。
|
||||
|
||||
交付:
|
||||
|
||||
1. TypeTree schema 内部表示稳定化:node path、type、name、size、flags、array 信息。
|
||||
2. 实现基础字段 reader:bool、integer、float、string、bytes、array、map、PPtr、managed reference 占位。
|
||||
3. 支持 TextAsset script/name 的结构化读取,而不只保留 raw bytes。
|
||||
4. 支持 MonoBehaviour 和 ScriptableObject 的 TypeTree 字段遍历。
|
||||
5. 对缺 TypeTree 或 stripped 类型返回可诊断错误,保留 raw object bytes 作为后备。
|
||||
|
||||
验收:
|
||||
|
||||
1. 合成 fixture 覆盖标量、数组、嵌套结构、string alignment。
|
||||
2. 隔离真实样本能输出稳定 JSON field tree。
|
||||
3. 解析错误包含 file path、object path id、class id、字段路径和偏移。
|
||||
|
||||
### P3:文本提取中间层
|
||||
|
||||
目标:为日语汉化提供稳定、可回写定位的文本单元。
|
||||
|
||||
交付:
|
||||
|
||||
1. 定义 `TextUnit`:source text、resource path、archive entry、object path id、field path、语言、版本、上下文。
|
||||
2. TextAsset 支持 JSON/CSV/TSV/plain text 的可配置探测。
|
||||
3. MonoBehaviour/ScriptableObject 按字段路径和类型策略提取字符串。
|
||||
4. 保留重复文本和上下文,不在解析阶段做会丢定位的合并。
|
||||
5. 导出 JSONL 作为第一稳定格式,CSV/XLIFF 可后置。
|
||||
|
||||
验收:
|
||||
|
||||
1. 提取不会修改官方资源。
|
||||
2. 每条文本能追溯回原 bundle、serialized file、path id 和字段路径。
|
||||
3. 同一文本在不同上下文中保持可区分。
|
||||
|
||||
### P4:CAS/Repository 用户级接入
|
||||
|
||||
目标:让解析结果进入可查询资源库,而不是只停留在文件系统缓存。
|
||||
|
||||
交付:
|
||||
|
||||
1. 官方同步完成后可配置触发导入 CAS + ResourceRepository。
|
||||
2. ResourceRepository 保存版本、平台、资源类型、bundle path、TextAsset 名称、TextUnit 索引摘要。
|
||||
3. 支持 CLI/RPC 查询资源、bundle、TextAsset、解析错误和缓存状态。
|
||||
4. schema 迁移版本化,旧库可重复升级。
|
||||
|
||||
验收:
|
||||
|
||||
1. 可以按版本、路径、类型、hash、TextAsset 名称查询。
|
||||
2. 解析缓存和 repository 数据能从同一 manifest fingerprint 追溯。
|
||||
3. CAS 对象跨版本复用,不重复存储相同文件。
|
||||
|
||||
### P5:Patch 发布前置解析
|
||||
|
||||
目标:让解析结果成为可生成汉化 patch 的输入。
|
||||
|
||||
交付:
|
||||
|
||||
1. 定义 patch manifest:目标官方版本、输入 TextUnit 版本、输出文件、hash、回滚信息。
|
||||
2. 支持 TextAsset raw bytes 替换的最小 patch 路径。
|
||||
3. MonoBehaviour/ScriptableObject 字段替换必须依赖 P2 字段级解析结果。
|
||||
4. Patch 产物写入 `localized-output/.staging/<id>`,校验通过后发布到 `localized-output/versions/<id>` 并切换 `current`。
|
||||
5. 成功后发布状态从 `not_localized` 切到 `localized`。
|
||||
|
||||
验收:
|
||||
|
||||
1. Patch 失败不影响 `bat-resources/current`。
|
||||
2. 汉化 release 保留官方相对目录结构。
|
||||
3. `localized` 状态能证明原版和汉化两套资源都已发布。
|
||||
|
||||
---
|
||||
|
||||
## 5. 解析器接口原则
|
||||
|
||||
1. 解析器输入只接受 bytes、逻辑路径和可选上下文,不直接访问下载器状态。
|
||||
2. 解析器输出必须可序列化,供 CLI/RPC/API、缓存和测试 golden 使用。
|
||||
3. 错误必须带位置:URL 或路径、archive entry、UnityFS directory、object path id、field path、offset。
|
||||
4. 未识别结构优先保留 raw metadata,不做低保真猜测。
|
||||
5. 解析器不写 `bat-resources` 和 `bat-localized`,写文件由上层缓存、导入或 Patch 发布流程负责。
|
||||
|
||||
---
|
||||
|
||||
## 6. Fixture 策略
|
||||
|
||||
1. 合成 fixture 放入代码仓库,覆盖边界和回归。
|
||||
2. 真实小样本可放入仓库前必须确认体积、许可和可复现性。
|
||||
3. 大型真实官方资源只允许放在 `/tmp`、隔离测试目录或用户显式提供的远端测试目录,不纳入 Git。
|
||||
4. 每个新增 fixture 必须说明覆盖的真实风险:字段变体、压缩模式、越界、hash mismatch、zip 内路径、TypeTree 结构等。
|
||||
|
||||
---
|
||||
|
||||
## 7. 近期关闭路径
|
||||
|
||||
优先顺序:
|
||||
|
||||
1. 完成 Addressables Windows/Android 当前版本 catalog 样本集合,关闭 G-007 当前阶段。
|
||||
2. 完成 TypeTree 字段 reader 和 MonoBehaviour/ScriptableObject 遍历,推进 G-005。
|
||||
3. 将 `official-parse-cache.json` 摘要接入 CAS/ResourceRepository 用户级导入,推进 G-011。
|
||||
4. 定义 TextUnit JSONL 和最小 TextAsset 提取命令,衔接 Milestone 5。
|
||||
5. 在 Patch 引擎落地后实现 `localized` 发布状态切换,关闭 G-011D 的核心发布缺口。
|
||||
@@ -6,6 +6,12 @@
|
||||
|
||||
这个后端只处理 **日服官方资源**,只接受官方 `.jp/.com` 域名下的资源链路。
|
||||
|
||||
**Release 布局、URL→磁盘映射、seed 模板与 bat-api 分发 path 的冻结契约**见:
|
||||
|
||||
- `docs/architecture/resource-release-layout.md`
|
||||
|
||||
---
|
||||
|
||||
明确排除:
|
||||
|
||||
- `bluearchive.cafe`
|
||||
@@ -207,8 +213,10 @@
|
||||
10. 下载先写入 `<output>/.staging/<id>`;若已有 active release,会先 seed staging 以复用已验证文件;若 version-state 中存在同一版本的失败 staging,则优先复用该 staging 并跳过 active seed,避免旧 active 覆盖已下载的新文件。
|
||||
11. 下载、manifest、本地 BLAKE3、ZIP 和官方 `.hash` 校验完成后写入新的 snapshot。
|
||||
12. 将 staging rename 为 `<output>/versions/<id>`,再原子替换 `<output>/current` symlink 指向该 versioned 目录。
|
||||
13. 发布完成后刷新 active release 下的 `official-parse-cache.json`;未变化文件按 manifest 的 URL、相对路径、size 和 BLAKE3 复用旧解析结果。
|
||||
14. 官方同步报告默认给出 `localized_release_status=not_localized`,表示原版资源已发布、汉化资源未发布;后续 Patch 发布阶段完成后才切换为 `localized`,表示原版和汉化两套资源都已发布。
|
||||
|
||||
该入口不安装、不执行官方启动器,也不读取生产外的本地客户端目录。Rust 正式 binary `bat` 支持单次运行、`--watch` 常驻模式、`--daemon` 后台模式,以及 `status`、`stop`、`restart`、`reload`、`logs`、`refresh`、`verify`、`repair`、`doctor`、`clean-stable` 管理命令。`--daemon` 会在后台状态目录下创建 `bat.sock`,使用 Unix socket JSON-RPC 作为 live control plane;`bat.pid`、`bat-status.json` 和 `bat-daemon.log` 是快照、诊断和兼容 fallback;`bat-events.jsonl` 是带轮转的结构化 JSONL 事件日志;`bat-control.lock` 串行化控制命令,并在 stale/corrupt 时由下一次控制命令或 `clean-stable` 恢复。`bat-status.json` 和 `status` 子命令包含最后成功时间、下次检查时间、最后错误摘要、当前阶段和当前下载 URL 进度。PID、status、log 和控制锁文件创建时使用私有权限,读取和写入时不跟随 symlink。`status`、`stop`、`logs`、`reload`、默认形态的 `refresh` 和默认形态的 `repair` 优先走 RPC;`reload` 会唤醒或排队 watch 循环重新自动发现并强制刷新,默认 `repair` 会通过 `resource.repair` 入队本地 manifest 审计+修复任务,`restart` 才负责重启进程或替换启动参数;显式 `--proxy` / `--no-proxy` 会作为启动参数保存并在后台重启时复用。后台 daemon 管理某个资源目录时,前台 `run/watch/refresh/repair` 不允许直接写入同一目录;默认形态 `refresh` 会通过 RPC 触发后台刷新,默认形态 `repair` 会通过 RPC 入队任务。正常情况下默认每 1 小时执行一次检查;每天北京时间(UTC+8)`03:00`、`16:00`、`18:00` 会中断普通 sleep 并强制执行一次自动刷新,该轮注入 `force=true`。远端和本地一致时静默等待下次检查,不一致时自动下载或 repair。下载、发现或校验失败时不等待完整正常周期,默认 60 秒后重试;如果固定时间强制刷新失败,会保留 pending force 并按失败重试周期继续重试,可用 `--error-retry` 或 `--error-retry-seconds` 调整。默认资源输出目录是 `./bat-resources`,默认后台状态目录是 `/tmp/bat-pid`,二者通过 `--output` 和 `--state-dir` 分别配置。单次运行仍保留为核心幂等路径,systemd service、容器或 Go 进程可以只负责守护该常驻进程;cron/systemd timer 调单次模式只是可选集成方式。项目是否热更新、热重载或重启进程,由上层业务集成决定。
|
||||
该入口不安装、不执行官方启动器,也不读取生产外的本地客户端目录。Rust 正式 binary `bat` 支持单次运行、`--watch` 常驻模式、`--daemon` 后台模式,以及 `status`、`stop`、`restart`、`reload`、`logs`、`refresh`、`verify`、`repair`、`doctor`、`clean-stable` 管理命令。`--daemon` 会在后台状态目录下创建 `bat.sock`,使用 Unix socket JSON-RPC 作为 live control plane;`bat.pid`、`bat-status.json` 和 `bat-daemon.log` 是快照、诊断和兼容 fallback;`bat-events.jsonl` 是带轮转的结构化 JSONL 事件日志;`bat-control.lock` 串行化控制命令,并在 stale/corrupt 时由下一次控制命令或 `clean-stable` 恢复。`bat-status.json` 和 `status` 子命令包含最后成功时间、下次检查时间、最后错误摘要、当前阶段和当前下载 URL 进度。PID、status、log 和控制锁文件创建时使用私有权限,读取和写入时不跟随 symlink。`status`、`stop`、`logs`、`reload`、默认形态的 `refresh` 和默认形态的 `repair` 优先走 RPC;`reload` 会唤醒或排队 watch 循环重新自动发现并强制刷新,默认 `repair` 会通过 `resource.repair` 入队本地 manifest 审计+修复任务,`restart` 才负责重启进程或替换启动参数;显式 `--proxy` / `--no-proxy` 会作为启动参数保存并在后台重启时复用。后台 daemon 管理某个资源目录时,前台 `run/watch/refresh/repair` 不允许直接写入同一目录;默认形态 `refresh` 会通过 RPC 触发后台刷新,默认形态 `repair` 会通过 RPC 入队任务。正常情况下默认每 1 小时执行一次检查;每天北京时间(UTC+8)`03:00`、`16:00`、`18:00` 会中断普通 sleep 并强制执行一次自动刷新,该轮注入 `force=true`。远端和本地一致时静默等待下次检查,不一致时自动下载或 repair。下载、发现或校验失败时不等待完整正常周期,默认 60 秒后重试;如果固定时间强制刷新失败,会保留 pending force 并按失败重试周期继续重试,可用 `--error-retry` 或 `--error-retry-seconds` 调整。默认官方原版资源输出目录是 `./bat-resources`,默认汉化产物目录是 `./bat-localized`,默认后台状态目录是 `/tmp/bat-pid`,三者分别通过 `--output`、`--localized-output` 和 `--state-dir` 配置;官方目录和汉化目录不能相同或互相嵌套。单次运行仍保留为核心幂等路径,systemd service、容器或 Go 进程可以只负责守护该常驻进程;cron/systemd timer 调单次模式只是可选集成方式。项目是否热更新、热重载或重启进程,由上层业务集成决定。
|
||||
|
||||
对应实现主要在:
|
||||
|
||||
@@ -304,14 +312,22 @@ JSON-RPC 2.0 服务,是面向上层服务(Go 层)的**主要跨语言边
|
||||
|
||||
### 7.2 Go 层职责边界
|
||||
|
||||
- Go 层负责:BlueArchive 客户端请求处理、HTTP API、鉴权、内容分发,
|
||||
以及通过 `internal/backendrpc` 作为 RPC client 调用本机 daemon
|
||||
(连接 `bat.sock`,每行一个 JSON-RPC 请求/响应)。当前 Go 产品入口
|
||||
尚未完成,`cmd/bat` 仍是试验骨架。
|
||||
- Rust daemon 负责:官方资源自动拉取与校验、catalog 更新检查、
|
||||
- Go 层负责:资源内容分发(`cmd/bat-api`)、HTTP API 进程配置、以及通过
|
||||
`internal/backendrpc` 作为 RPC client 调用本机 daemon(连接 `bat.sock`,
|
||||
每行一个 JSON-RPC 请求/响应)。`cmd/bat` 仍是试验骨架,不是产品级用户 CLI。
|
||||
- **`bat-api`(资源分发,issue #19)**:
|
||||
- 只读提供 Rust `bat` 已发布 release 中的资源字节(官方 CDN host/path 形态)。
|
||||
- 版本/清单发现优先走 RPC:先 `daemon.status`,再 `daemon.doctor`,再
|
||||
`catalog.status` / `resource.manifest`(可用 `--socket` 指定 socket 文件)。
|
||||
- 支持 `.env` / 环境变量配置监听端口、public base URL、RPC socket,并预留
|
||||
database/redis 键供后续 API 持久化;**不**负责资源自动拉取。
|
||||
- 可选改写 server-info 中的 `AddressablesCatalogUrlRoot` 指向自身;不伪装
|
||||
完整游戏业务 API,launcher 全链非本服务关闭条件。
|
||||
- Rust `bat` / daemon 负责:官方资源自动发现与拉取、校验、catalog 更新检查、
|
||||
版本状态与发布、任务队列/日志/错误/进度管理等长期状态型工作。
|
||||
- Go 层**不**直接嵌入 Rust FFI,不直接读写 daemon 的状态文件与资源
|
||||
目录内部结构;跨语言交互只经 RPC 契约。
|
||||
- Go 层**不**直接嵌入 Rust FFI,不直接读写 daemon 的状态文件;跨语言控制面
|
||||
只经 RPC 契约。文件字节从 RPC 给出的 `resource_root`(或显式
|
||||
`--resource-root`)读取,与 daemon 同机或共享文件系统部署。
|
||||
|
||||
### 7.3 FFI 的定位(降级说明)
|
||||
|
||||
|
||||
@@ -0,0 +1,311 @@
|
||||
# 官方资源 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`)
|
||||
|
||||
---
|
||||
|
||||
## 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)
|
||||
|
||||
```text
|
||||
<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`。
|
||||
|
||||
```text
|
||||
https://{host}/{path...} → <resource_root>/{host}/{path...}
|
||||
```
|
||||
|
||||
规则:
|
||||
|
||||
1. 仅 `https://`
|
||||
2. host 必须是官方 JP 资源 host(见下节)
|
||||
3. path 分段不得为 `.` / `..`
|
||||
4. **禁止** query / fragment(否则直接拒绝,避免同路径覆盖)
|
||||
5. 分段经 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)
|
||||
|
||||
```text
|
||||
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` 形如:
|
||||
|
||||
```text
|
||||
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 端点模板
|
||||
|
||||
共享(非平台):
|
||||
|
||||
```text
|
||||
{CLIENT_PATCH}/{token}/TableBundles/TableCatalog.bytes
|
||||
{CLIENT_PATCH}/{token}/TableBundles/TableCatalog.hash
|
||||
```
|
||||
|
||||
每平台:
|
||||
|
||||
```text
|
||||
{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 改写后客户端拼接:
|
||||
|
||||
```text
|
||||
{rewritten_root}/TableBundles/TableCatalog.bytes
|
||||
≡ {public-base}/prod-clientpatch.../{token}/TableBundles/TableCatalog.bytes
|
||||
```
|
||||
|
||||
与磁盘映射一致。
|
||||
|
||||
---
|
||||
|
||||
## 8. RPC 与分发发现顺序
|
||||
|
||||
`bat-api`(及任何 Go 服务层)发现当前 release:
|
||||
|
||||
1. `daemon.status`
|
||||
2. `daemon.doctor`
|
||||
3. `catalog.status`(`version.resource_root`、`addressables_root`、app/bundle)
|
||||
4. `resource.manifest` 分页(url / destination / bytes / blake3)
|
||||
5. 在 `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)
|
||||
|
||||
连接信息到位后只读执行:
|
||||
|
||||
1. `readlink current` → version id
|
||||
2. 顶层是否仅有官方 host 目录 + manifest/snapshot
|
||||
3. manifest 条目数 vs 磁盘抽样 size
|
||||
4. RPC 四步(status → doctor → catalog.status → manifest 首页)
|
||||
5. 将结论写入 `docs/reports/resource-server-survey-YYYYMMDD.md`(无凭据)
|
||||
|
||||
所需:
|
||||
|
||||
```text
|
||||
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. 变更纪律
|
||||
|
||||
1. 改 URL 模板或落盘规则 → **必须**同步本文 + 相关单测。
|
||||
2. 改 inventory 启发式 → 说明覆盖的真实风险并补 fixture。
|
||||
3. 真机实勘若发现与本文冲突 → **以真机为准** 修代码与本文,禁止静默分叉。
|
||||
Reference in New Issue
Block a user