mirror of
https://github.com/Yuyi-Oak/BlueArchiveToolkit.git
synced 2026-09-18 08:54:55 +08:00
补齐解析模块维护冻结规则,并同步 CURRENT_STATUS、CURRENT_GAPS、PROJECT_PLAN、RPC 参考、部署指南、用户指南和官方资源运行说明。 文档同时反映 bat-api 资源 bootstrap/分发边界、官方同步解析缓存、TextUnit 队列、双目录发布和 patch 入口的当前状态。 验证:未运行新命令;本轮已按要求停止重复构建/测试。
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# 稳定工程基线指南
|
||||
|
||||
- **更新时间**:2026-07-20
|
||||
- **更新时间**:2026-07-26
|
||||
- **目标**:让工作区处于可继续开发核心功能的可信状态。
|
||||
|
||||
---
|
||||
@@ -90,10 +90,11 @@ git check-ignore -v Cargo.lock CLAUDE.md AGENTS.md CONTRIBUTING.md
|
||||
|
||||
CAS V1 和 Rust 官方同步闭环完成后,下一阶段优先推进:
|
||||
|
||||
1. 收敛 Go 产品入口:当前 `cmd/bat` 仅是试验骨架,不能视为完成。
|
||||
2. 按 `docs/guides/official-full-pull-smoke.md` 执行真实官方网络全量下载 smoke,并保留隔离目录报告。
|
||||
3. 官方同步结果接入 CAS + ResourceRepository。
|
||||
4. AssetBundle UnityFS 引擎级解析。
|
||||
1. 继续联调 Go `bat-api` 与 Rust daemon 的资源分发路径;Go 同步 CLI 不再作为产品目标。
|
||||
2. 按 `docs/guides/official-full-pull-smoke.md` 在隔离目录执行真实官方网络全量下载 smoke,并保留运行报告。
|
||||
3. 将 `crowdin-textunit-queue.json` 接入真实 Crowdin worker、翻译记忆和 Patch 构建。
|
||||
4. 扩展 ResourceRepository 查询面:翻译任务状态、CAS 诊断入口和更丰富 TextUnit 查询。
|
||||
5. 继续完善 AssetBundle 复杂对象解析、复杂对象重打包和 Patch 发布流程统一;通用 Binary/JSON/Text Patch 基础与 UnityFS TextAsset patch 发布前置链路已可用。
|
||||
|
||||
优先阅读:
|
||||
|
||||
|
||||
+152
-7
@@ -5,8 +5,9 @@
|
||||
BlueArchive Toolkit 的部署文档分为当前可用模式和目标模式:
|
||||
|
||||
1. **本地开发模式**:代码在本地,连接本地或远程数据库。
|
||||
2. **官方资源同步生产任务**:当前可用,运行 Rust `bat --watch`。
|
||||
3. **完整单机/分布式部署**:尚未提供。API Server、数据库迁移和 Web 未实现前,不把它作为可执行部署方案。
|
||||
2. **官方资源同步生产任务**:当前可用,运行 Rust `bat --watch` 或 RPC/daemon 模式。
|
||||
3. **bat-api 资源 bootstrap / 分发服务**:当前可用,和 Rust `bat` 在同一服务器/容器环境运行,经 `bat.sock` RPC 获取当前 `resource_root`。
|
||||
4. **完整单机/分布式部署**:尚未提供。完整游戏业务 API、数据库迁移和 Web 未实现前,不把它作为可执行部署方案。
|
||||
|
||||
---
|
||||
|
||||
@@ -100,7 +101,7 @@ REDIS_PORT=6379
|
||||
|
||||
## 模式 3:官方资源同步生产任务
|
||||
|
||||
当前可部署的生产任务是 Rust 官方资源同步 binary。API Server 和 Web 尚未实现,不能按完整服务端产品部署。
|
||||
当前可部署的生产同步任务是 Rust 官方资源同步 binary。`bat-api` 资源 bootstrap / 分发服务见模式 4;完整游戏业务 API 和 Web 尚未实现,不能按完整服务端产品部署。
|
||||
|
||||
### 构建 release binary
|
||||
|
||||
@@ -198,14 +199,14 @@ sudo -u bat /opt/bluearchive-toolkit/bin/bat \
|
||||
--no-progress
|
||||
```
|
||||
|
||||
### 推荐模式:systemd 托管 `--watch`
|
||||
### 推荐模式:纯同步时 systemd 托管 `--watch`
|
||||
|
||||
生产推荐让 systemd 直接托管前台 `--watch` 进程,而不是在 systemd 里再启动 `--daemon`。原因:
|
||||
只需要远程长期同步资源、暂不部署 `bat-api` 时,推荐让 systemd 直接托管前台 `--watch` 进程,而不是在 systemd 里再启动 `--daemon`。原因:
|
||||
|
||||
- systemd 能直接追踪主进程、退出码、重启次数和 stop 信号。
|
||||
- 日志进入 journald,用 `journalctl` 管理,不依赖 `bat-daemon.log`。
|
||||
- Rust 内部已经负责 1 小时间隔、北京时间固定强制刷新和失败快速重试,systemd 不需要 timer。
|
||||
- `bat --daemon` 的 Unix socket RPC 适合没有进程管理器的 shell/container 场景;systemd 场景下用 `systemctl`、`journalctl`、`bat verify/doctor` 运维即可。
|
||||
- `bat --daemon` 的 Unix socket RPC 适合 shell/container 场景,也适合给同环境运行的 `bat-api` 提供 release 发现;纯同步 systemd 场景下用 `systemctl`、`journalctl`、`bat verify/doctor` 运维即可。
|
||||
|
||||
安装 unit 和可选环境文件:
|
||||
|
||||
@@ -256,6 +257,8 @@ sudo -u bat /opt/bluearchive-toolkit/bin/bat stop --state-dir /var/lib/bluearchi
|
||||
|
||||
不要同时运行 systemd `--watch` 和 standalone `--daemon` 指向同一个 `--output`。二者都会被资源锁和 live daemon 互斥保护,但生产运维上应保持单一 owner。
|
||||
|
||||
如果同一台服务器还要运行 `bat-api`,必须让 Rust `bat` 以能提供 `bat.sock` 的 RPC 形态运行,并让 `bat-api` 通过该 socket 获取当前 `resource_root`。这种部署见模式 4;不要把 `BAT_API_RESOURCE_ROOT` 当作生产主配置。
|
||||
|
||||
### 日志和状态路径
|
||||
|
||||
systemd 模式:
|
||||
@@ -351,7 +354,149 @@ sudo -u bat tar -C /var/lib/bluearchive-toolkit/official \
|
||||
|
||||
---
|
||||
|
||||
## 模式 4:完整生产环境部署
|
||||
## 模式 4:bat-api 资源 bootstrap / 分发服务
|
||||
|
||||
适用场景:真实 Rust `bat` 长期运行在远程服务器,并且同一服务器/容器环境内运行 Go `bat-api`,给客户端、补丁器或上层工具提供启动前资源入口和 CDN path 只读分发。
|
||||
|
||||
核心约束:
|
||||
|
||||
1. `bat-api` 与 Rust `bat` 同环境部署,至少要能访问同一个 Unix socket 和同一个已发布资源文件系统。
|
||||
2. 当前资源目录由 `bat.sock` RPC 返回的 `resource_root` 决定;生产不要在 `bat-api` 配置里写死 `BAT_API_RESOURCE_ROOT`。
|
||||
3. `BAT_API_RESOURCE_ROOT` 只用于本地 fixture、临时只读诊断或 RPC 不可用时的应急验证。
|
||||
4. `bat.sock` 只在服务器本机使用,不通过公网暴露;对外只发布 HTTP `bat-api`,生产建议放在反向代理和 TLS 后面。
|
||||
5. 本地开发环境不需要、也不应全量运行 `bat`;使用 Go 单测、fixture release 或远程服务器联调。
|
||||
|
||||
### 构建和安装 bat-api
|
||||
|
||||
```bash
|
||||
make build-go-api
|
||||
|
||||
VERSION="$(git rev-parse --short HEAD)"
|
||||
sudo install -d -o root -g root -m 0755 \
|
||||
/opt/bluearchive-toolkit/releases/"${VERSION}" \
|
||||
/opt/bluearchive-toolkit/bin
|
||||
sudo install -o root -g root -m 0755 \
|
||||
bin/bat-api \
|
||||
/opt/bluearchive-toolkit/releases/"${VERSION}"/bat-api
|
||||
sudo ln -sfn \
|
||||
/opt/bluearchive-toolkit/releases/"${VERSION}"/bat-api \
|
||||
/opt/bluearchive-toolkit/bin/bat-api
|
||||
/opt/bluearchive-toolkit/bin/bat-api --help
|
||||
```
|
||||
|
||||
如果 Rust `bat` 和 Go `bat-api` 使用同一个 release 目录发布,也可以把二者放在同一个 `<version-or-git-sha>` 目录下,分别通过 `/opt/bluearchive-toolkit/bin/bat` 和 `/opt/bluearchive-toolkit/bin/bat-api` 暴露稳定 symlink。
|
||||
|
||||
### bat 侧前置条件
|
||||
|
||||
`bat-api` 依赖 live RPC,而不是直接读取 daemon 状态文件。部署 `bat-api` 前,远程服务器上应已有 socket 形态的 Rust `bat`:
|
||||
|
||||
```bash
|
||||
sudo -u bat /opt/bluearchive-toolkit/bin/bat \
|
||||
--auto-discover \
|
||||
--output /var/lib/bluearchive-toolkit/official \
|
||||
--localized-output /var/lib/bluearchive-toolkit/localized \
|
||||
--state-dir /var/lib/bluearchive-toolkit/daemon-state \
|
||||
--daemon
|
||||
|
||||
sudo -u bat /opt/bluearchive-toolkit/bin/bat status \
|
||||
--state-dir /var/lib/bluearchive-toolkit/daemon-state
|
||||
```
|
||||
|
||||
确认 socket 存在:
|
||||
|
||||
```bash
|
||||
sudo -u bat test -S /var/lib/bluearchive-toolkit/daemon-state/bat.sock
|
||||
```
|
||||
|
||||
不要同时再运行一个 `--watch` service 指向 `/var/lib/bluearchive-toolkit/official`。如果当前服务器已经部署了 `bluearchive-toolkit-official-sync.service` 的纯同步 `--watch` 模式,需要先切换为 socket/RPC 形态,再启用 `bat-api`。
|
||||
|
||||
### 安装 bat-api systemd unit
|
||||
|
||||
```bash
|
||||
sudo install -o root -g root -m 0644 \
|
||||
deployments/systemd/bluearchive-toolkit-bat-api.service \
|
||||
/etc/systemd/system/bluearchive-toolkit-bat-api.service
|
||||
sudo install -o root -g root -m 0644 \
|
||||
deployments/systemd/bat-api.env.example \
|
||||
/etc/bluearchive-toolkit/bat-api.env
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now bluearchive-toolkit-bat-api.service
|
||||
```
|
||||
|
||||
默认配置只监听本机:
|
||||
|
||||
```env
|
||||
BAT_API_LISTEN=127.0.0.1:18080
|
||||
BAT_API_PUBLIC_BASE_URL=http://127.0.0.1:18080
|
||||
BAT_API_SOCKET=/var/lib/bluearchive-toolkit/daemon-state/bat.sock
|
||||
BAT_API_REFRESH_INTERVAL=1m
|
||||
BAT_API_ACCESS_LOG=true
|
||||
BAT_API_RATE_LIMIT_RPS=30
|
||||
BAT_API_RATE_LIMIT_BURST=120
|
||||
```
|
||||
|
||||
生产反向代理公开后,把 `BAT_API_PUBLIC_BASE_URL` 改成客户端实际访问的 HTTPS 根,例如:
|
||||
|
||||
```env
|
||||
BAT_API_PUBLIC_BASE_URL=https://assets.example.com
|
||||
```
|
||||
|
||||
面对玩家分发时还应通过 secret manager 或 systemd credential 注入:
|
||||
|
||||
```env
|
||||
BAT_API_AUTH_TOKEN=<secret>
|
||||
BAT_API_AUTH_QUERY_PARAM=bat_token
|
||||
BAT_API_AUTH_EXEMPT_PATHS=/healthz,/readyz
|
||||
BAT_API_MAX_RESOURCE_LIMIT=1000
|
||||
```
|
||||
|
||||
反代必须强制 HTTPS,并在转发到 `bat-api` 前清洗客户端提交的 `X-Forwarded-For` / `X-Real-IP`。只有确认反代会覆盖这些 header 时,才设置:
|
||||
|
||||
```env
|
||||
BAT_API_TRUST_PROXY_HEADERS=true
|
||||
```
|
||||
|
||||
否则保持默认 `false`,`bat-api` 会按 TCP peer IP 做限流和日志归因。应用层访问日志只记录 path,不记录 query string,避免 query token 进入日志。动态 JSON 响应使用 `Cache-Control: no-store`;CDN 字节路径仍使用长期 immutable 缓存。
|
||||
|
||||
不要在生产 env 里设置 `BAT_API_RESOURCE_ROOT`。`bat-api` 会按 `BAT_API_REFRESH_INTERVAL` 周期通过 RPC 重新读取 `catalog.status` / `resource.manifest`,从而跟随 Rust `bat` 切换 `current -> versions/<id>`。
|
||||
|
||||
### 健康检查
|
||||
|
||||
```bash
|
||||
systemctl status bluearchive-toolkit-bat-api.service
|
||||
journalctl -u bluearchive-toolkit-bat-api.service -f
|
||||
curl -fsS http://127.0.0.1:18080/healthz
|
||||
curl -fsS http://127.0.0.1:18080/readyz
|
||||
curl -fsS http://127.0.0.1:18080/v1/bootstrap
|
||||
curl -fsS http://127.0.0.1:18080/v1/launcher/bootstrap
|
||||
curl -fsS http://127.0.0.1:18080/api-launcher-jp.yo-star.com/api/launcher/game/config
|
||||
curl -fsS http://127.0.0.1:18080/openapi.yaml
|
||||
curl -fsS http://127.0.0.1:18080/admin/
|
||||
```
|
||||
|
||||
`/healthz` 是 liveness,固定返回服务存活状态,并包含最近一次 RPC refresh 的开始时间、成功时间、耗时、warning 和错误摘要。`/readyz` 是 readiness,当前没有可分发 release 时返回 `503`。`rpc_available=true` 且 `ready=true` 表示 `bat-api` 已经通过 RPC 发现可分发 release;`ready=false` 时,先检查 `bat.sock`、Rust `bat status`、`resource_root` 是否存在,以及 `official-download-manifest.json` 中的文件是否仍在磁盘上。
|
||||
|
||||
`/v1/launcher/bootstrap` 和 `/api-launcher-jp.yo-star.com/api/launcher/...` 只用于 launcher 资源 metadata / GameMainConfig 引导兼容。它们从 Rust `bat` 的已发布 snapshot/RPC 派生响应,显式标记不是完整 package update manifest;生产排障时应确认这些响应中的 `scope=resource_bootstrap_only`、`resource_bootstrap_url`、server-info URL 和 client-patch base 是否指向当前 `BAT_API_PUBLIC_BASE_URL`。
|
||||
|
||||
### 本地开发限制
|
||||
|
||||
开发机不能本地全量运行 `bat` 时,不需要伪造生产资源目录。Go 侧改动用单测和 fixture 验证:
|
||||
|
||||
```bash
|
||||
make test-go-api
|
||||
make build-go-api
|
||||
BAT_API_SKIP_ENV_FILE=1 go run ./cmd/bat-api \
|
||||
--listen 127.0.0.1:18080 \
|
||||
--public-base-url http://127.0.0.1:18080 \
|
||||
--resource-root internal/api/testdata/release \
|
||||
--refresh-interval 0
|
||||
```
|
||||
|
||||
这条本地命令只验证 HTTP 形态、server-info 改写、CDN path、Range/缓存语义和管理接口;真实全量 release 联调应在远程长期运行的 `bat` 环境里执行。
|
||||
|
||||
---
|
||||
|
||||
## 模式 5:完整生产环境部署
|
||||
|
||||
当前不可用。API Server、数据库迁移、Web 管理后台和发布编排尚未实现;不要按完整服务端产品部署本仓库。
|
||||
|
||||
|
||||
+125
-1
@@ -117,6 +117,10 @@ git push origin feature/your-feature-name
|
||||
|
||||
禁止使用 demo、临时实现、硬编码路径或只为当前测试通过的伪实现。确实未完成的能力应写入当前缺口文档,而不是用 `TODO` 或 `FIXME` 隐藏。
|
||||
|
||||
### 解析模块冻结
|
||||
|
||||
UnityFS / AssetBundle / Addressables / TypeTree 解析当前处于维护冻结。冻结期不得新增解析类型、扩大解析覆盖、开放新的写入型解析 RPC/CLI,或用合成 fixture 宣称新增能力。允许变更仅限编译、测试、clippy、真实运行回归、诊断和文档一致性修复。细则见 `docs/reports/PARSER_FREEZE.md`。
|
||||
|
||||
### Go
|
||||
- 遵循 [Effective Go](https://golang.org/doc/effective_go)
|
||||
- 使用 `gofmt` 格式化
|
||||
@@ -149,17 +153,31 @@ go vet ./internal/api/... ./internal/backendrpc/... ./cmd/bat-api/...
|
||||
Go 边界与进度以 `docs/reports/GO_STATUS.md` 为准:
|
||||
|
||||
- **同步/运维命令行** = Rust `bat`(近乎全自动)
|
||||
- **资源分发服务** = `cmd/bat-api`(`make build-go-api`)
|
||||
- **资源 bootstrap/分发服务** = `cmd/bat-api`(`make build-go-api`)
|
||||
- **默认 Go 门禁** = `make test-go-api`(无 FFI)
|
||||
- 试验 CLI 产物为 `bin/bat-go`(`make build-go-cli`),**禁止**与 Rust `bat` 重名
|
||||
- 修改 FFI 时再跑 `make test-go-ffi`
|
||||
|
||||
开发环境不能本地全量运行 Rust `bat` 时,`bat-api` 不需要真实生产资源目录。用 fixture 或 mock RPC 验证服务面;生产联调再连接远程服务器上同环境运行的 `bat.sock`:
|
||||
|
||||
```bash
|
||||
make test-go-api
|
||||
BAT_API_SKIP_ENV_FILE=1 go run ./cmd/bat-api \
|
||||
--listen 127.0.0.1:18080 \
|
||||
--public-base-url http://127.0.0.1:18080 \
|
||||
--resource-root internal/api/testdata/release \
|
||||
--refresh-interval 0
|
||||
```
|
||||
|
||||
生产默认路径仍是 `--socket` / `BAT_API_SOCKET`,资源根由 Rust `bat` RPC 返回;`--resource-root` 只用于上述 fixture 或应急只读诊断。
|
||||
|
||||
### 常用聚焦命令
|
||||
|
||||
```bash
|
||||
cargo test -p bat-core -- --nocapture
|
||||
cargo test -p bat-adapters -- --nocapture
|
||||
cargo test -p bat-ffi -- --nocapture
|
||||
cargo test -p bat-patch -- --nocapture
|
||||
cargo test -p bat-infrastructure -- --nocapture
|
||||
cargo test -p bat-infrastructure --bin bat -- --nocapture
|
||||
cargo clippy -p bat-core -p bat-adapters -p bat-infrastructure --all-targets -- -D warnings
|
||||
@@ -195,6 +213,112 @@ cargo run -p bat-infrastructure --bin bat -- \
|
||||
|
||||
开发环境真实官方资源下载默认写入 `./bat-resources`;汉化产物默认写入独立的 `./bat-localized`。如果要覆盖,官方原版资源使用 `--output` / `BAT_OUTPUT`,汉化产物使用 `--localized-output` / `BAT_LOCALIZED_OUTPUT`。两者都必须使用 `/tmp` 或其他隔离目录,不要写入现有资源目录,也不要把汉化输出覆盖到官方原版资源目录。
|
||||
|
||||
官方 release 拉取并校验完成后会在当前 release 根目录维护
|
||||
`official-resource-changes.json`、`crowdin-translation-handoff.json`、
|
||||
`official-parse-cache.json` 和 `official-textunit-index.json`,随后从
|
||||
Added/Modified 资源、parse cache 与 TextUnit 明细索引派生
|
||||
`official-textunit-tasks.json` 和 `crowdin-textunit-queue.json`。本地已有旧完整
|
||||
版本时,新版本发布后会先按 manifest destination 对比旧/新 release,只把新增和
|
||||
内容变更的资源写入解析与 Crowdin handoff;删除资源只记录差异,不进入翻译队列。
|
||||
up-to-date 轮询发现本地文件、解析缓存、TextUnit 明细索引和 TextUnit 队列未变时不会重复解析。
|
||||
Crowdin 队列当前只落本地文件,不发网络请求。
|
||||
|
||||
需要把已校验官方 release 导入 CAS + `ResourceRepository` 时,显式启用:
|
||||
|
||||
```bash
|
||||
cargo run -p bat-infrastructure --bin bat -- \
|
||||
--auto-discover \
|
||||
--import-repository \
|
||||
--import-cas-root /tmp/bat-test.cas \
|
||||
--import-resource-db /tmp/bat-test-resources.sqlite
|
||||
```
|
||||
|
||||
对应 `.env` / 环境变量键为 `BAT_IMPORT_REPOSITORY`、
|
||||
`BAT_IMPORT_CAS_ROOT` 和 `BAT_IMPORT_RESOURCE_DB`。只读查询命令:
|
||||
|
||||
```bash
|
||||
cargo run -p bat-infrastructure --bin bat -- parse-status
|
||||
cargo run -p bat-infrastructure --bin bat -- parse-text-units --limit 50
|
||||
cargo run -p bat-infrastructure --bin bat -- parse-errors --limit 50
|
||||
cargo run -p bat-infrastructure --bin bat -- localized-status
|
||||
cargo run -p bat-infrastructure --bin bat -- resource-index --limit 50
|
||||
```
|
||||
|
||||
`parse-status` 会额外显示 TextUnit 明细索引和队列摘要;`parse-text-units` /
|
||||
`parse-errors` 可按 destination、archive entry、path id、class id、field path
|
||||
和 format 分页查询当前官方 release 的 TextUnit 明细与解析错误;
|
||||
`resource-index` 返回的资源 JSON 包含 release、平台、bundle path、TextAsset 和 TextUnit metadata;
|
||||
`localized-status` 只有在 `localized-version-state.json`、`current` symlink 和
|
||||
`localized-patch-manifest.json` 都匹配当前官方 release 时才返回 `localized`。
|
||||
|
||||
文件级写入命令只处理显式输入/输出文件,不切换官方或汉化 release:
|
||||
|
||||
```bash
|
||||
cargo run -p bat-infrastructure --bin bat -- patch-apply \
|
||||
--patch-kind text \
|
||||
--source-file /tmp/bat-source.txt \
|
||||
--patch-file /tmp/bat-source.text-patch.json \
|
||||
--target-file /tmp/bat-target.txt
|
||||
|
||||
cargo run -p bat-infrastructure --bin bat -- unityfs-patch-text-asset \
|
||||
--bundle-file /tmp/source.bundle \
|
||||
--serialized-file CAB-Example \
|
||||
--object-path-id 1 \
|
||||
--replacement-file /tmp/replacement.bytes \
|
||||
--target-file /tmp/target.bundle
|
||||
|
||||
cargo run -p bat-infrastructure --bin bat -- unityfs-patch-string-field \
|
||||
--bundle-file /tmp/source.bundle \
|
||||
--serialized-file CAB-Example \
|
||||
--object-path-id 1 \
|
||||
--string-field-path message \
|
||||
--replacement-text "老师" \
|
||||
--target-file /tmp/target.bundle
|
||||
|
||||
cargo run -p bat-infrastructure --bin bat -- unityfs-patch-field \
|
||||
--bundle-file /tmp/source.bundle \
|
||||
--serialized-file CAB-Example \
|
||||
--object-path-id 1 \
|
||||
--field-path scores[1] \
|
||||
--expected-json '{"kind":"signed","value":20}' \
|
||||
--replacement-json '{"kind":"signed","value":42}' \
|
||||
--target-file /tmp/target.bundle
|
||||
|
||||
cargo run -p bat-infrastructure --bin bat -- unityfs-patch-field \
|
||||
--bundle-file /tmp/source.bundle \
|
||||
--serialized-file CAB-Example \
|
||||
--object-path-id 1 \
|
||||
--field-path difficulty \
|
||||
--expected-json '{"kind":"enum","value":{"type_name":"ScenarioDifficulty","storage_type":"int","value":2}}' \
|
||||
--replacement-json '{"kind":"enum","value":{"type_name":"ScenarioDifficulty","storage_type":"int","value":3}}' \
|
||||
--target-file /tmp/target.bundle
|
||||
|
||||
cargo run -p bat-infrastructure --bin bat -- unityfs-patch-field \
|
||||
--bundle-file /tmp/source.bundle \
|
||||
--serialized-file CAB-Example \
|
||||
--object-path-id 1 \
|
||||
--field-path target_layers \
|
||||
--expected-json '{"kind":"bit_field","value":{"type_name":"LayerMask","storage_type":"UInt32","bits":5}}' \
|
||||
--replacement-json '{"kind":"bit_field","value":{"type_name":"LayerMask","storage_type":"UInt32","bits":9}}' \
|
||||
--target-file /tmp/target.bundle
|
||||
|
||||
cargo run -p bat-infrastructure --bin bat -- unityfs-patch-field \
|
||||
--bundle-file /tmp/source.bundle \
|
||||
--serialized-file CAB-Example \
|
||||
--object-path-id 1 \
|
||||
--field-path messages \
|
||||
--replacement-json '{"kind":"array","value":[{"kind":"string","value":"你好"},{"kind":"string","value":"老师"}]}' \
|
||||
--target-file /tmp/target.bundle
|
||||
|
||||
cargo run -p bat-infrastructure --bin bat -- unityfs-patch-field \
|
||||
--bundle-file /tmp/source.bundle \
|
||||
--serialized-file CAB-Example \
|
||||
--object-path-id 1 \
|
||||
--field-path texts \
|
||||
--replacement-json '{"kind":"map","value":[{"kind":"object","value":[{"name":"first","value":{"kind":"string","value":"jp"}},{"name":"second","value":{"kind":"string","value":"你好"}}]}]}' \
|
||||
--target-file /tmp/target.bundle
|
||||
```
|
||||
|
||||
生产或 CI 环境不得依赖安装官方启动器。需要启动器信息时,只能分析启动器资源、官方 manifest 或公开更新数据,并将解析结果固化为可验证流程。
|
||||
|
||||
### 基准测试
|
||||
|
||||
@@ -97,9 +97,9 @@ Linux 生产运行时链路只走官方日服 HTTP 资源,不安装、不启
|
||||
2. 请求官方 `server-info`。
|
||||
3. 生成 Windows + Android 的官方资源 discovery 端点。
|
||||
4. 拉取 seed catalog,生成完整官方 pull plan。
|
||||
5. dry-run 只输出 URL;非 dry-run 下载全部官方 URL 到 staging,验收完成后原子发布到 `current`。
|
||||
5. dry-run 只输出 URL;非 dry-run 下载全部官方 URL 到 staging,验收完成后原子发布到 `current`,并在 release 中写入 `official-launcher-bootstrap.json`。
|
||||
|
||||
`--auto-discover` 会下载官方 metadata,并按官方 manifest 临时获取 `resources.assets` 解析 `GameMainConfig`;旧 ZIP manifest 才会下载临时 game zip。该流程不会安装官方启动器,也不会执行官方启动器进程。`--launcher-bootstrap` 只是旧命名兼容别名,新流程不要再推荐使用。
|
||||
`--auto-discover` 会下载官方 metadata,记录 launcher API 返回的 game config、CDN config、remote manifest 文件列表和选中的 `resources.assets` 来源,并按官方 manifest 临时获取 `resources.assets` 解析 `GameMainConfig`;旧 ZIP manifest 才会下载临时 game zip。该流程不会安装官方启动器,也不会执行官方启动器进程。`--launcher-bootstrap` 只是旧命名兼容别名,新流程不要再推荐使用。
|
||||
|
||||
## 2. 可选 metadata 审计
|
||||
|
||||
@@ -198,11 +198,13 @@ cargo run -p bat-infrastructure --example official_pull_plan -- \
|
||||
- 官方 seed `.hash` 校验失败会让本轮失败,并清理对应本地 manifest 条目;下一轮会继续把这类文件视为需要 repair,而不是把失败产物当作健康缓存复用。
|
||||
- curl 默认自动检测本地代理环境;也可以用 `--proxy <URL>` 显式指定代理,或用 `--no-proxy` 强制直连。代理决策会进入 progress log、daemon log 和 `doctor` 诊断输出。
|
||||
- curl 失败会按类型分类:403/404/普通 4xx 不重试,5xx、429、DNS、连接、超时、中断和网络类错误按尝试次数重试。
|
||||
- 官方维护或大版本发布窗口可能出现启动器/server-info 已经给出新版本和新 `AddressablesCatalogUrlRoot`,但 client-patch CDN 的 seed marker 或必需 seed catalog 尚未开放的状态。此时单次运行会输出 `update_status=waiting_for_official_resources`、`waiting_for_official_resources=true` 和 `unavailable_endpoints`;不会进入 staging、不会写入 `failed_versions`、不会切换 `current`。watch/daemon 会把状态置为 `waiting`,按 `--error-retry` / `BAT_ERROR_RETRY_SECONDS`(默认 60 秒)继续探测。
|
||||
- 单个 URL 最终失败后会写入 `official-download-quarantine.json`,progress log、daemon status 和 `bat-events.jsonl` 会记录失败类型、HTTP 状态、是否可重试、尝试次数和 quarantine 状态。
|
||||
- quarantine 项会跳过本轮发布并让同步失败,避免把不完整 staging 发布到 `current`;下一轮 repair/refresh 成功后会清理对应 quarantine 条目。
|
||||
- 失败或中断后的 staging 不会无条件丢弃:如果 version-state 记录的失败版本和本轮远端元数据匹配,且 staging 目录仍安全存在,下一轮会复用该 staging;已通过 manifest 校验的文件会跳过,缺失、损坏、无 manifest 或官方 seed `.hash` 需要刷新的 URL 会重新下载。
|
||||
- 旧 launcher 包或 `resources.assets` 下载路径使用官方 launcher CDN 配置,primary CDN 失败后会切换官方 backup CDN;资源 patch host 当前只使用 server-info 返回的官方 client-patch host,不猜测非官方镜像。
|
||||
- 远端和本地都一致:单次模式输出 `update_status=up_to_date`,watch 模式默认静默并等待下次检查。
|
||||
- 远端 metadata 已更新但资源端尚未开放:单次模式输出 `update_status=waiting_for_official_resources`,watch/daemon 模式保留现有资源并短间隔重试。
|
||||
- 有远端变化或本地 repair:生成 pull plan,下载完整官方资源到 staging,成功后更新 snapshot 并原子发布到 `current`。
|
||||
- 非 dry-run 会维护 `<output>/official-version-state.json`:开始下载后写入 `in_progress_version`,发布成功后写入 `current_completed_version` 和 `previous_available_version`,失败或中断后写入 `failed_versions`。同一 app version、bundle version 和 Addressables root 的失败只保留最新一条;同一版本开始重新拉取或后续发布成功时会清理对应失败记录。重新拉取同一失败版本时会复用安全存在的失败 staging,不会因为 `publish_id` 变化从空目录重新开始。
|
||||
- `--dry-run`:只报告本次是否会下载,不写 snapshot;如果 cache miss,也不会写入新的 bootstrap cache。
|
||||
@@ -210,15 +212,22 @@ cargo run -p bat-infrastructure --example official_pull_plan -- \
|
||||
- 真实更新会输出 `downloaded_count`、`resumed_count`、`skipped_count`、`transferred_bytes`、`official_seed_hash_verified_count`。
|
||||
- 校验报告分层输出 `official_seed_hash_verified_count`、`local_manifest_verified_count`、`addressables_marker_checked_count`、`unverified_marker_count`。
|
||||
- 下载阶段复用同一套本地清单、ZIP 结构校验和 `.part` 续传逻辑;没有清单或校验不匹配的文件会重新下载。
|
||||
- 校验和发布完成后会刷新 `<output>/current/official-parse-cache.json`。解析缓存从 `official-download-manifest.json` 的全部条目出发,处理直接 UnityFS bundle 和 zip 内 UnityFS 条目;catalog、hash、媒体等非 UnityFS 文件记录为不支持,不视为同步失败。本地 URL、相对路径、size 和 BLAKE3 未变化时复用缓存并跳过重复解析。
|
||||
- 非 dry-run 且启用 `--auto-discover` 时,成功发布的 release 会包含 `official-launcher-bootstrap.json`;up-to-date 轮询发现当前 release 缺少该文件时会补写。官方 launcher/server-info 已更新但 client-patch 资源尚未开放时,不切换 `current`,只在输出根写入 `official-launcher-bootstrap.pending.json` 作为维护期证据。
|
||||
- 校验和发布完成后会先对比上一完整 release 与当前 release 的 `official-download-manifest.json`,写出 `<output>/current/official-resource-changes.json` 和 `<output>/current/crowdin-translation-handoff.json`。同一 destination 只有 size 或 BLAKE3 改变才算 modified;仅 URL/CDN 根变化但内容一致不会触发解析/翻译候选。新增+变更资源进入解析和 Crowdin 翻译 handoff,删除资源只进入差异记录;当前不会直接调用 Crowdin API。
|
||||
- 随后会刷新 `<output>/current/official-parse-cache.json`。解析缓存从 `official-download-manifest.json` 的全部条目出发,处理直接 UnityFS bundle 和 zip 内 UnityFS 条目;catalog、hash、媒体等非 UnityFS 文件记录为不支持,不视为同步失败。新 release 会刷新解析缓存;远端和本地都 up-to-date 且已有有效解析缓存时只读取摘要,不重复解析。
|
||||
- 需要将已校验官方 release 导入 CAS + SQLite ResourceRepository 时,使用 `--import-repository` 或 `.env` 中 `BAT_IMPORT_REPOSITORY=1`;默认 CAS 为 `<output>/.cas`,默认索引为 `<output>/resources.sqlite`,可用 `--import-cas-root` / `BAT_IMPORT_CAS_ROOT` 和 `--import-resource-db` / `BAT_IMPORT_RESOURCE_DB` 覆盖。`resource.index` RPC 可查询现有索引,索引不存在时返回 `available=false`,不会创建空库。
|
||||
- 官方同步报告中的 `localized_release_status=not_localized` 表示原版资源已发布、汉化资源未发布,这是当前官方同步阶段的正常完成状态;后续 Patch 发布完成后才应切换为 `localized`,表示原版和汉化两套资源都已发布。
|
||||
|
||||
资源同步状态文件默认分布如下:
|
||||
|
||||
- `<output>/current/official-sync-snapshot.json`:上一次成功同步的 v2 snapshot,包含 app version、connection group、bundle version、addressables root、endpoint URL、官方 seed `.hash` 内容、Addressables `catalog_*.hash` marker、launcher metadata 摘要和 `GameMainConfig` 摘要。
|
||||
- `<output>/official-bootstrap-cache.json`:`--auto-discover` 的 `GameMainConfig` 解析缓存。launcher metadata 未变时复用缓存;metadata 变化时才通过官方 HTTP 按 manifest 下载必要 `resources.assets` 或旧版 game zip 到临时目录解析。
|
||||
- `<output>/current/official-sync-snapshot.json`:上一次成功同步的 v2 snapshot,包含 app version、connection group、bundle version、addressables root、endpoint URL、官方 seed `.hash` 内容、Addressables `catalog_*.hash` marker、launcher metadata 摘要和 `GameMainConfig` 摘要;launcher metadata 额外包含 remote manifest 文件列表 digest,用于发现同文件数但内容变化的 launcher manifest。
|
||||
- `<output>/current/official-launcher-bootstrap.json`:随已发布 release versioned 保存的官方 launcher bootstrap 产物,包含 launcher metadata、launcher CDN config、remote manifest 文件列表、选中的 `resources.assets` 来源、`GameMainConfig` 摘要和当前资源上下文。
|
||||
- `<output>/official-launcher-bootstrap.pending.json`:官方 launcher/server-info 已前进但 client-patch seed marker 或必需 seed catalog 尚未开放时写入的待处理 bootstrap 证据;它不代表资源已发布,也不会改变 `current`。
|
||||
- `<output>/official-bootstrap-cache.json`:`--auto-discover` 的 `GameMainConfig` 解析缓存。launcher metadata 与 remote manifest 文件列表 digest 都未变时复用缓存;任一变化时才通过官方 HTTP 按 manifest 下载必要 `resources.assets` 或旧版 game zip 到临时目录解析。
|
||||
- `<output>/official-version-state.json`:资源发布根目录的持久版本状态,包含当前已完成版本、正在拉取版本、上一个可用版本和失败版本。
|
||||
- `<output>/current/official-download-manifest.json`:本地下载强校验清单,记录 URL、相对路径、size 和 BLAKE3。
|
||||
- `<output>/current/official-resource-changes.json`:当前 release 相对上一完整 release 的资源差异,记录新增、变更、删除以及解析/翻译候选计数。
|
||||
- `<output>/current/crowdin-translation-handoff.json`:为后续 Crowdin worker 预留的本地队列,只包含新增+变更资源;它不是 Crowdin API 调用结果。
|
||||
- `<output>/current/official-parse-cache.json`:官方资源发布后的派生解析缓存,记录 bundle/zip 条目解析摘要和缓存复用情况;它不是汉化产物。
|
||||
- `<output>/current/official-download-quarantine.json` 或当前 staging 下同名文件:下载最终失败的 URL 诊断记录,包含失败类型、HTTP 状态、是否可重试、尝试次数和最后错误。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user