mirror of
https://github.com/Yuyi-Oak/BlueArchiveToolkit.git
synced 2026-07-22 06:35:16 +08:00
1904 lines
44 KiB
Markdown
1904 lines
44 KiB
Markdown
# BlueArchive Toolkit 架构审查报告
|
||
|
||
**审查日期**:2026-06-27
|
||
**审查阶段**:Architecture Refactoring Sprint
|
||
**审查目标**:评估当前架构是否适合十年以上长期维护
|
||
|
||
---
|
||
|
||
## 执行摘要
|
||
|
||
经过对整个项目的全面分析,我发现当前架构存在**多个严重的架构缺陷**,这些问题如果不立即解决,将在未来 1-3 年内导致项目陷入技术债务泥潭,需要大规模重构。
|
||
|
||
**核心问题**:当前架构**过度关注技术实现细节**,而**严重忽视了业务领域建模**和**与 Blue Archive 客户端的集成方式**。
|
||
|
||
**关键发现**:
|
||
- ❌ **缺少游戏客户端集成层设计**(Critical)
|
||
- ❌ **缺少 Unity 版本适配抽象层**(Critical)
|
||
- ❌ **缺少 Manifest 格式适配层**(High)
|
||
- ❌ **模块职责边界不清晰**(High)
|
||
- ❌ **工作流自动化设计缺失**(High)
|
||
- ⚠️ **过早的技术选型固化**(Medium)
|
||
|
||
---
|
||
|
||
## 第一部分:项目现状分析
|
||
|
||
### 1.1 已完成工作
|
||
|
||
✅ **基础设施**
|
||
- Monorepo 目录结构
|
||
- Rust workspace (4 个 crates)
|
||
- Go module 初始化
|
||
- Docker 配置(支持远程数据库)
|
||
- Makefile 构建系统
|
||
- 基础文档
|
||
|
||
✅ **部分实现的模块**
|
||
- CAS 存储接口定义
|
||
- Hash 计算模块
|
||
- Storage trait 实现
|
||
- AssetBundle、Patch、FFI 框架搭建
|
||
|
||
### 1.2 关键缺失
|
||
|
||
❌ **业务领域模型**
|
||
- 没有 Game Client 抽象
|
||
- 没有 Version 概念
|
||
- 没有 Asset 生命周期管理
|
||
- 没有 Translation Workflow 设计
|
||
|
||
❌ **集成方式设计**
|
||
- 如何注入客户端?
|
||
- 如何更新客户端资源?
|
||
- 如何处理官方更新?
|
||
|
||
❌ **可扩展性设计**
|
||
- Unity 版本升级如何处理?
|
||
- Manifest 格式变化如何适配?
|
||
- 新的资源类型如何扩展?
|
||
|
||
---
|
||
|
||
## 第二部分:架构问题深度分析
|
||
|
||
### 问题 1:缺少游戏客户端集成层设计 ⚠️ **CRITICAL**
|
||
|
||
#### 当前状况
|
||
整个项目**没有明确定义如何与 Blue Archive 客户端集成**。
|
||
|
||
#### 问题描述
|
||
- 文档中只提到"资源同步"、"AssetBundle 解析"、"Patch 生成"
|
||
- **但没有说明这些功能最终如何作用于游戏客户端**
|
||
- 没有定义"客户端"的抽象概念
|
||
|
||
#### 为什么这是 Critical?
|
||
这是整个项目的**核心业务逻辑**!如果不先设计清楚这一层,后续所有模块都可能需要推倒重来。
|
||
|
||
#### 未来后果
|
||
- **1 年内**:发现现有设计无法适配实际客户端需求,需要大量重构
|
||
- **3 年内**:积累大量临时方案和 workaround,代码质量急剧下降
|
||
- **5 年内**:维护成本过高,项目陷入停滞
|
||
|
||
---
|
||
|
||
### 问题 2:缺少 Unity 版本适配抽象层 ⚠️ **CRITICAL**
|
||
|
||
#### 当前状况
|
||
AssetBundle 解析器直接依赖特定的 Unity 版本实现。
|
||
|
||
#### 问题描述
|
||
```rust
|
||
// 当前设计(crates/bat-assetbundle/)
|
||
pub trait AssetParser {
|
||
fn parse(&self, bundle: &AssetBundle) -> Result<Vec<Asset>>;
|
||
}
|
||
```
|
||
|
||
这个设计假设 AssetBundle 格式是稳定的,但实际上:
|
||
- Unity 不同版本的 AssetBundle 格式**完全不同**
|
||
- 官方随时可能升级 Unity 版本
|
||
- 需要同时支持多个 Unity 版本
|
||
|
||
#### 正确设计应该是
|
||
```rust
|
||
// 需要的设计
|
||
pub trait UnityVersionAdapter {
|
||
fn version(&self) -> UnityVersion;
|
||
fn can_handle(&self, bundle: &RawBundle) -> bool;
|
||
fn parse(&self, bundle: &RawBundle) -> Result<GenericAssetBundle>;
|
||
}
|
||
|
||
pub struct AssetBundleParser {
|
||
adapters: Vec<Box<dyn UnityVersionAdapter>>,
|
||
}
|
||
```
|
||
|
||
#### 为什么这是 Critical?
|
||
官方升级 Unity 版本是**必然会发生**的事情,如果现在不设计好,到时候整个 AssetBundle 模块都要重写。
|
||
|
||
---
|
||
|
||
|
||
### 问题 3:缺少 Manifest 格式适配层 ⚠️ **HIGH**
|
||
|
||
#### 当前状况
|
||
架构文档中提到"Manifest Parser",但没有设计适配层。
|
||
|
||
#### 问题描述
|
||
- Blue Archive 的 Manifest 格式可能随时变化
|
||
- 不同区域(日服、国际服)的 Manifest 格式可能不同
|
||
- 需要支持旧版本的 Manifest 以便回溯历史
|
||
|
||
#### 正确设计
|
||
```rust
|
||
pub trait ManifestAdapter {
|
||
fn format_version(&self) -> &str;
|
||
fn can_parse(&self, raw_data: &[u8]) -> bool;
|
||
fn parse(&self, raw_data: &[u8]) -> Result<GenericManifest>;
|
||
}
|
||
|
||
pub struct ManifestParser {
|
||
adapters: HashMap<String, Box<dyn ManifestAdapter>>,
|
||
}
|
||
```
|
||
|
||
#### 未来后果
|
||
- **1 年内**:官方修改 Manifest 格式,整个同步系统瘫痪
|
||
- **3 年内**:为了支持多个版本,代码中充斥着 if-else 判断
|
||
|
||
---
|
||
|
||
### 问题 4:模块职责边界不清晰 ⚠️ **HIGH**
|
||
|
||
#### 当前问题
|
||
|
||
**CAS 存储引擎职责过重**
|
||
```rust
|
||
// 当前设计混合了多个职责
|
||
pub trait Storage {
|
||
async fn put(&self, data: &[u8]) -> Result<Hash>; // 存储
|
||
async fn get(&self, hash: &Hash) -> Result<Vec<u8>>; // 读取
|
||
async fn stats(&self) -> Result<StorageStats>; // 统计
|
||
}
|
||
|
||
// 引用计数独立管理
|
||
pub struct RefCounter {
|
||
// 使用独立的 SQLite
|
||
}
|
||
```
|
||
|
||
**问题**:
|
||
1. Storage 和 RefCounter 是两个独立的组件,但它们的数据必须保持一致
|
||
2. 如果 put() 成功但 incr() 失败,会导致数据不一致
|
||
3. 没有事务保证
|
||
|
||
**正确设计**:
|
||
```rust
|
||
pub trait CasRepository {
|
||
// 统一的仓储接口,内部保证事务一致性
|
||
async fn store(&self, data: &[u8]) -> Result<ObjectId>;
|
||
async fn get(&self, id: &ObjectId) -> Result<Vec<u8>>;
|
||
async fn add_reference(&self, id: &ObjectId) -> Result<()>;
|
||
async fn remove_reference(&self, id: &ObjectId) -> Result<bool>; // 返回是否应该删除
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 问题 5:工作流自动化设计缺失 ⚠️ **HIGH**
|
||
|
||
#### 当前状况
|
||
项目规划了各个技术模块,但**没有设计完整的业务工作流**。
|
||
|
||
#### 缺失的工作流
|
||
|
||
**官方更新后的自动化流程**:
|
||
1. 版本检测 → 如何实现?
|
||
2. Manifest 获取 → 从哪里获取?
|
||
3. 资源同步 → 如何判断哪些需要下载?
|
||
4. 自动解析 → 如何识别文本资源?
|
||
5. 自动识别新增文本 → 如何 diff?
|
||
6. 自动翻译 → 如何调度?
|
||
7. 人工审核 → 工作流如何设计?
|
||
8. Patch 生成 → 如何保证一致性?
|
||
9. 自动发布 → 发布到哪里?
|
||
|
||
**当前架构中这些都是空白!**
|
||
|
||
#### 正确设计需要
|
||
```
|
||
workflow/
|
||
├── version_detector/ # 版本检测服务
|
||
├── sync_coordinator/ # 同步协调器
|
||
├── text_extractor/ # 文本提取器
|
||
├── diff_analyzer/ # 差异分析器
|
||
├── translation_pipeline/ # 翻译管道
|
||
├── review_queue/ # 审核队列
|
||
├── patch_generator/ # Patch 生成器
|
||
└── release_manager/ # 发布管理器
|
||
```
|
||
|
||
---
|
||
|
||
## 第三部分:Blue Archive 客户端集成方案分析
|
||
|
||
### 3.1 可能的集成方案
|
||
|
||
#### 方案 A:客户端资源替换(推荐)⭐
|
||
|
||
**原理**:
|
||
1. 工具下载官方资源到本地
|
||
2. 解析 AssetBundle,提取文本
|
||
3. 翻译后重新打包 AssetBundle
|
||
4. 替换客户端的资源文件
|
||
|
||
**优点**:
|
||
- ✅ 不修改游戏可执行文件,安全性高
|
||
- ✅ 支持增量更新
|
||
- ✅ 易于回滚
|
||
- ✅ 可以离线工作
|
||
|
||
**缺点**:
|
||
- ⚠️ 需要深入理解 Unity AssetBundle 格式
|
||
- ⚠️ Unity 版本升级需要适配
|
||
|
||
**维护成本**:中等
|
||
**更新成本**:低
|
||
**兼容性**:高
|
||
|
||
**架构要求**:
|
||
```
|
||
Client Integration Layer:
|
||
├── AssetBundleReplacer # 资源替换器
|
||
├── IntegrityVerifier # 完整性验证
|
||
└── RollbackManager # 回滚管理
|
||
```
|
||
|
||
---
|
||
|
||
#### 方案 B:代理服务器模式
|
||
|
||
**原理**:
|
||
1. 在客户端和游戏服务器之间插入代理
|
||
2. 拦截资源下载请求
|
||
3. 返回翻译后的资源
|
||
|
||
**优点**:
|
||
- ✅ 不需要修改客户端文件
|
||
- ✅ 动态更新翻译
|
||
|
||
**缺点**:
|
||
- ❌ 需要用户配置代理
|
||
- ❌ 可能影响游戏性能
|
||
- ❌ 需要持续运行服务
|
||
- ❌ 官方可能检测并封禁
|
||
|
||
**维护成本**:高
|
||
**更新成本**:低
|
||
**兼容性**:中
|
||
|
||
**不推荐**:维护成本高,用户体验差
|
||
|
||
---
|
||
|
||
#### 方案 C:内存补丁模式
|
||
|
||
**原理**:
|
||
1. Hook 游戏进程
|
||
2. 在内存中替换文本
|
||
|
||
**优点**:
|
||
- ✅ 不修改文件
|
||
|
||
**缺点**:
|
||
- ❌ 技术复杂度极高
|
||
- ❌ 容易被反作弊系统检测
|
||
- ❌ 每次游戏更新都可能失效
|
||
- ❌ 不同平台需要不同实现
|
||
|
||
**维护成本**:极高
|
||
**更新成本**:极高
|
||
**兼容性**:低
|
||
|
||
**不推荐**:风险高,维护成本不可持续
|
||
|
||
---
|
||
|
||
### 3.2 推荐方案:方案 A(客户端资源替换)
|
||
|
||
#### 实施步骤
|
||
|
||
**Step 1:资源定位**
|
||
```
|
||
ClientResourceLocator:
|
||
- 识别客户端安装路径
|
||
- 定位 AssetBundle 文件位置
|
||
- 建立资源索引
|
||
```
|
||
|
||
**Step 2:资源备份**
|
||
```
|
||
BackupManager:
|
||
- 首次运行时备份原始资源
|
||
- 支持多版本备份
|
||
- 快速恢复机制
|
||
```
|
||
|
||
**Step 3:资源替换**
|
||
```
|
||
ResourceReplacer:
|
||
- 验证资源完整性
|
||
- 原子替换(要么全部成功,要么全部回滚)
|
||
- 更新资源索引
|
||
```
|
||
|
||
**Step 4:启动验证**
|
||
```
|
||
LaunchVerifier:
|
||
- 游戏启动前检查资源完整性
|
||
- 自动修复损坏的资源
|
||
- 生成诊断报告
|
||
```
|
||
|
||
---
|
||
|
||
|
||
## 第四部分:自动化流程设计
|
||
|
||
### 4.1 完整的官方更新适配流程
|
||
|
||
```mermaid
|
||
graph TD
|
||
A[官方发布新版本] --> B[版本检测服务]
|
||
B --> C{是否有新版本?}
|
||
C -->|是| D[下载新 Manifest]
|
||
C -->|否| Z[等待]
|
||
|
||
D --> E[Manifest 差异分析]
|
||
E --> F[识别变更的资源]
|
||
|
||
F --> G[资源同步下载]
|
||
G --> H[存入 CAS]
|
||
|
||
H --> I[AssetBundle 解析]
|
||
I --> J[文本提取]
|
||
|
||
J --> K[文本差异分析]
|
||
K --> L{有新增文本?}
|
||
|
||
L -->|是| M[查询翻译记忆库]
|
||
L -->|否| Y[完成]
|
||
|
||
M --> N{记忆库命中?}
|
||
N -->|全部命中| S[应用翻译]
|
||
N -->|部分未命中| O[AI 翻译]
|
||
|
||
O --> P[术语库替换]
|
||
P --> Q[加入审核队列]
|
||
|
||
Q --> R[人工审核]
|
||
R --> S[应用翻译]
|
||
|
||
S --> T[重新打包 AssetBundle]
|
||
T --> U[生成 Patch]
|
||
|
||
U --> V[完整性测试]
|
||
V --> W[发布到仓库]
|
||
W --> X[通知用户]
|
||
X --> Y[完成]
|
||
```
|
||
|
||
### 4.2 关键服务设计
|
||
|
||
#### 4.2.1 版本检测服务
|
||
|
||
```rust
|
||
pub struct VersionDetector {
|
||
region: GameRegion, // JP, Global, CN, etc.
|
||
check_interval: Duration,
|
||
}
|
||
|
||
impl VersionDetector {
|
||
/// 检测是否有新版本
|
||
pub async fn check_for_updates(&self) -> Result<Option<GameVersion>> {
|
||
// 1. 获取官方 API 最新版本号
|
||
// 2. 与本地记录对比
|
||
// 3. 返回版本信息
|
||
}
|
||
|
||
/// 下载新版本的 Manifest
|
||
pub async fn fetch_manifest(&self, version: &GameVersion) -> Result<RawManifest> {
|
||
// 从 CDN 下载 Manifest
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 4.2.2 差异分析器
|
||
|
||
```rust
|
||
pub struct DiffAnalyzer {
|
||
cas: Arc<CasRepository>,
|
||
}
|
||
|
||
impl DiffAnalyzer {
|
||
/// 分析两个版本之间的资源差异
|
||
pub async fn analyze_manifest_diff(
|
||
&self,
|
||
old_version: &Manifest,
|
||
new_version: &Manifest,
|
||
) -> Result<ManifestDiff> {
|
||
// 返回:新增、修改、删除的资源列表
|
||
}
|
||
|
||
/// 分析文本差异
|
||
pub async fn analyze_text_diff(
|
||
&self,
|
||
old_texts: &[ExtractedText],
|
||
new_texts: &[ExtractedText],
|
||
) -> Result<TextDiff> {
|
||
// 返回:新增、修改、删除的文本
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 4.2.3 翻译管道
|
||
|
||
```rust
|
||
pub struct TranslationPipeline {
|
||
memory: Arc<TranslationMemory>,
|
||
glossary: Arc<Glossary>,
|
||
providers: Vec<Box<dyn TranslationProvider>>,
|
||
}
|
||
|
||
impl TranslationPipeline {
|
||
/// 处理待翻译文本
|
||
pub async fn process(&self, texts: Vec<SourceText>) -> Result<Vec<TranslationResult>> {
|
||
// 1. 查询翻译记忆库
|
||
// 2. 未命中的发送给 AI
|
||
// 3. 应用术语库
|
||
// 4. 返回结果
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 4.2.4 审核队列
|
||
|
||
```rust
|
||
pub struct ReviewQueue {
|
||
db: Pool<Postgres>,
|
||
}
|
||
|
||
impl ReviewQueue {
|
||
/// 添加待审核项
|
||
pub async fn enqueue(&self, item: ReviewItem) -> Result<QueueId>;
|
||
|
||
/// 获取待审核项
|
||
pub async fn fetch_pending(&self, limit: usize) -> Result<Vec<ReviewItem>>;
|
||
|
||
/// 提交审核结果
|
||
pub async fn submit_review(&self, id: QueueId, result: ReviewResult) -> Result<()>;
|
||
}
|
||
```
|
||
|
||
### 4.3 自动化程度设计
|
||
|
||
**完全自动化**(无需人工干预):
|
||
- ✅ 版本检测
|
||
- ✅ Manifest 下载
|
||
- ✅ 资源同步
|
||
- ✅ AssetBundle 解析
|
||
- ✅ 文本提取
|
||
- ✅ 差异分析
|
||
- ✅ 翻译记忆库查询
|
||
- ✅ AI 翻译
|
||
- ✅ 术语应用
|
||
|
||
**半自动化**(需要人工审核):
|
||
- ⚠️ 新增术语的添加
|
||
- ⚠️ AI 翻译质量审核
|
||
- ⚠️ 关键剧情翻译确认
|
||
|
||
**手动操作**(首次或特殊情况):
|
||
- 🔧 术语库初始化
|
||
- 🔧 翻译风格指南制定
|
||
- 🔧 异常情况处理
|
||
|
||
**目标**:90% 的更新可以在 1 小时内自动完成,仅 10% 需要人工审核。
|
||
|
||
---
|
||
|
||
## 第五部分:适配 Unity/Manifest 变化的架构设计
|
||
|
||
### 5.1 核心设计原则
|
||
|
||
**原则 1:版本即插件**
|
||
- 每个 Unity 版本对应一个 Adapter 插件
|
||
- 新版本 = 新增插件,不修改已有代码
|
||
|
||
**原则 2:格式即 Driver**
|
||
- 每种 Manifest 格式对应一个 Driver
|
||
- 自动检测格式,加载对应 Driver
|
||
|
||
**原则 3:解耦核心与适配**
|
||
- 核心业务逻辑不依赖具体版本
|
||
- 通过抽象接口与适配层通信
|
||
|
||
### 5.2 Unity 版本适配架构
|
||
|
||
```
|
||
adapters/
|
||
├── unity/
|
||
│ ├── adapter_trait.rs # Unity Adapter 接口定义
|
||
│ ├── version_2019_4/ # Unity 2019.4 适配器
|
||
│ │ ├── assetbundle_parser.rs
|
||
│ │ └── serialization.rs
|
||
│ ├── version_2021_3/ # Unity 2021.3 适配器
|
||
│ │ ├── assetbundle_parser.rs
|
||
│ │ └── serialization.rs
|
||
│ └── version_2022_3/ # Unity 2022.3 适配器
|
||
│ ├── assetbundle_parser.rs
|
||
│ └── serialization.rs
|
||
└── registry.rs # 适配器注册表
|
||
```
|
||
|
||
**接口设计**:
|
||
```rust
|
||
pub trait UnityAdapter: Send + Sync {
|
||
/// 适配器名称(例如 "Unity-2019.4")
|
||
fn name(&self) -> &str;
|
||
|
||
/// 支持的 Unity 版本范围
|
||
fn supported_versions(&self) -> VersionRange;
|
||
|
||
/// 检测是否可以处理这个 AssetBundle
|
||
fn can_handle(&self, bundle: &RawAssetBundle) -> bool;
|
||
|
||
/// 解析 AssetBundle
|
||
fn parse(&self, bundle: &RawAssetBundle) -> Result<ParsedAssetBundle>;
|
||
|
||
/// 序列化回 AssetBundle
|
||
fn serialize(&self, parsed: &ParsedAssetBundle) -> Result<Vec<u8>>;
|
||
}
|
||
|
||
pub struct UnityAdapterRegistry {
|
||
adapters: Vec<Box<dyn UnityAdapter>>,
|
||
}
|
||
|
||
impl UnityAdapterRegistry {
|
||
/// 自动选择合适的适配器
|
||
pub fn select_adapter(&self, bundle: &RawAssetBundle) -> Result<&dyn UnityAdapter> {
|
||
for adapter in &self.adapters {
|
||
if adapter.can_handle(bundle) {
|
||
return Ok(adapter.as_ref());
|
||
}
|
||
}
|
||
Err(Error::NoSuitableAdapter)
|
||
}
|
||
}
|
||
```
|
||
|
||
**新增 Unity 版本的步骤**:
|
||
1. 创建新目录:`adapters/unity/version_XXXX_X/`
|
||
2. 实现 `UnityAdapter` trait
|
||
3. 在 `registry.rs` 中注册
|
||
4. **无需修改核心代码!**
|
||
|
||
---
|
||
|
||
### 5.3 Manifest 格式适配架构
|
||
|
||
```
|
||
adapters/
|
||
├── manifest/
|
||
│ ├── driver_trait.rs # Manifest Driver 接口
|
||
│ ├── format_v1/ # 第一代格式
|
||
│ │ └── parser.rs
|
||
│ ├── format_v2/ # 第二代格式
|
||
│ │ └── parser.rs
|
||
│ ├── format_v3/ # 第三代格式(假设未来会有)
|
||
│ │ └── parser.rs
|
||
│ └── registry.rs
|
||
```
|
||
|
||
**接口设计**:
|
||
```rust
|
||
pub trait ManifestDriver: Send + Sync {
|
||
/// Driver 名称
|
||
fn name(&self) -> &str;
|
||
|
||
/// 格式版本标识
|
||
fn format_version(&self) -> &str;
|
||
|
||
/// 检测是否可以解析这个 Manifest
|
||
fn can_parse(&self, raw_data: &[u8]) -> bool;
|
||
|
||
/// 解析 Manifest
|
||
fn parse(&self, raw_data: &[u8]) -> Result<GenericManifest>;
|
||
}
|
||
|
||
/// 通用 Manifest 结构(所有格式都转换到这个结构)
|
||
pub struct GenericManifest {
|
||
pub version: String,
|
||
pub resources: Vec<ResourceEntry>,
|
||
pub metadata: HashMap<String, String>,
|
||
}
|
||
|
||
pub struct ResourceEntry {
|
||
pub path: String,
|
||
pub hash: String,
|
||
pub size: u64,
|
||
pub url: String,
|
||
}
|
||
```
|
||
|
||
**新增格式的步骤**:
|
||
1. 创建新目录:`adapters/manifest/format_vX/`
|
||
2. 实现 `ManifestDriver` trait
|
||
3. 注册到 Registry
|
||
4. **无需修改核心代码!**
|
||
|
||
---
|
||
|
||
|
||
## 第六部分:必须立即重构的模块
|
||
|
||
### 6.1 Critical 级别(必须在继续开发前完成)
|
||
|
||
#### 🔴 C1: 建立业务领域模型
|
||
|
||
**当前状态**:只有技术组件,没有业务抽象
|
||
**必须重构的原因**:所有后续开发都依赖清晰的领域模型
|
||
**不改的后果**:项目会变成一堆技术组件的堆砌,无法形成完整系统
|
||
|
||
**需要的领域模型**:
|
||
```rust
|
||
// 核心领域对象
|
||
pub struct GameClient {
|
||
region: GameRegion,
|
||
version: GameVersion,
|
||
install_path: PathBuf,
|
||
resources: ResourceIndex,
|
||
}
|
||
|
||
pub struct GameVersion {
|
||
major: u32,
|
||
minor: u32,
|
||
patch: u32,
|
||
revision: String,
|
||
unity_version: UnityVersion,
|
||
}
|
||
|
||
pub struct ResourceIndex {
|
||
manifest: Manifest,
|
||
asset_bundles: HashMap<String, AssetBundleInfo>,
|
||
}
|
||
|
||
pub struct TranslationProject {
|
||
source_version: GameVersion,
|
||
target_language: Language,
|
||
translations: TranslationSet,
|
||
status: ProjectStatus,
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
#### 🔴 C2: 设计客户端集成层
|
||
|
||
**当前状态**:完全缺失
|
||
**必须重构的原因**:这是项目的核心价值所在
|
||
**不改的后果**:做出来的工具无法实际使用
|
||
|
||
**需要的集成层**:
|
||
```rust
|
||
pub trait ClientIntegration {
|
||
/// 发现客户端安装
|
||
fn discover_installation(&self) -> Result<Vec<GameClient>>;
|
||
|
||
/// 备份原始资源
|
||
fn backup_resources(&self, client: &GameClient) -> Result<BackupId>;
|
||
|
||
/// 应用翻译
|
||
fn apply_translation(&self, client: &GameClient, patch: &Patch) -> Result<()>;
|
||
|
||
/// 验证完整性
|
||
fn verify_integrity(&self, client: &GameClient) -> Result<IntegrityReport>;
|
||
|
||
/// 回滚到原始状态
|
||
fn rollback(&self, client: &GameClient, backup_id: BackupId) -> Result<()>;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
#### 🔴 C3: 建立 Adapter 架构
|
||
|
||
**当前状态**:直接依赖具体实现
|
||
**必须重构的原因**:未来版本变化时需要全部重写
|
||
**不改的后果**:每次官方更新都需要大规模重构
|
||
|
||
**需要重构的模块**:
|
||
1. `bat-assetbundle` → 改为基于 Adapter 的架构
|
||
2. Manifest 解析 → 改为基于 Driver 的架构
|
||
3. 所有版本相关的代码 → 改为插件化
|
||
|
||
---
|
||
|
||
### 6.2 High 级别(第一个迭代必须完成)
|
||
|
||
#### 🟠 H1: 重新设计 CAS 存储
|
||
|
||
**当前问题**:Storage 和 RefCounter 分离,没有事务保证
|
||
|
||
**重构方案**:
|
||
```rust
|
||
// 统一的 CAS Repository
|
||
pub struct CasRepository {
|
||
storage: Box<dyn ObjectStorage>,
|
||
metadata: Pool<Sqlite>,
|
||
}
|
||
|
||
impl CasRepository {
|
||
/// 存储对象(原子操作)
|
||
pub async fn store(&self, data: &[u8]) -> Result<ObjectId> {
|
||
let mut tx = self.metadata.begin().await?;
|
||
|
||
// 1. 计算 Hash
|
||
let hash = compute_hash(data);
|
||
|
||
// 2. 检查是否存在
|
||
if self.object_exists(&hash, &mut tx).await? {
|
||
// 3a. 增加引用计数
|
||
self.increment_ref(&hash, &mut tx).await?;
|
||
} else {
|
||
// 3b. 存储数据
|
||
self.storage.put(&hash, data).await?;
|
||
// 4. 记录元数据
|
||
self.insert_metadata(&hash, data.len(), &mut tx).await?;
|
||
}
|
||
|
||
tx.commit().await?;
|
||
Ok(ObjectId::from(hash))
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
#### 🟠 H2: 建立工作流引擎
|
||
|
||
**当前问题**:没有工作流设计
|
||
|
||
**重构方案**:
|
||
```rust
|
||
pub struct WorkflowEngine {
|
||
steps: Vec<Box<dyn WorkflowStep>>,
|
||
context: WorkflowContext,
|
||
}
|
||
|
||
pub trait WorkflowStep: Send + Sync {
|
||
fn name(&self) -> &str;
|
||
async fn execute(&self, ctx: &mut WorkflowContext) -> Result<StepResult>;
|
||
async fn rollback(&self, ctx: &mut WorkflowContext) -> Result<()>;
|
||
}
|
||
|
||
// 标准工作流:官方更新适配
|
||
pub struct OfficialUpdateWorkflow {
|
||
steps: [
|
||
VersionDetectionStep,
|
||
ManifestDownloadStep,
|
||
ResourceSyncStep,
|
||
TextExtractionStep,
|
||
DiffAnalysisStep,
|
||
TranslationStep,
|
||
ReviewStep,
|
||
PatchGenerationStep,
|
||
PublishStep,
|
||
],
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
#### 🟠 H3: 定义标准数据格式
|
||
|
||
**当前问题**:没有定义中间数据格式
|
||
|
||
**需要的标准格式**:
|
||
```rust
|
||
/// 提取的文本(标准格式)
|
||
pub struct ExtractedText {
|
||
pub id: TextId, // 唯一标识
|
||
pub source: TextSource, // 来源(哪个资源文件)
|
||
pub context: TextContext, // 上下文信息
|
||
pub content: String, // 文本内容
|
||
pub metadata: TextMetadata, // 元数据
|
||
}
|
||
|
||
pub struct TextSource {
|
||
pub asset_bundle: String,
|
||
pub asset_path: String,
|
||
pub object_type: String,
|
||
pub field_path: Vec<String>,
|
||
}
|
||
|
||
/// 翻译后的文本
|
||
pub struct TranslatedText {
|
||
pub source_id: TextId,
|
||
pub target_language: Language,
|
||
pub translation: String,
|
||
pub provider: String,
|
||
pub confidence: f32,
|
||
pub reviewed: bool,
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 6.3 Medium 级别(可以逐步优化)
|
||
|
||
#### 🟡 M1: FFI 层设计
|
||
|
||
**当前问题**:只有占位代码
|
||
|
||
**建议**:
|
||
- 先完成 Rust 端的核心功能
|
||
- 然后设计稳定的 C ABI
|
||
- 最后实现 Go 绑定
|
||
|
||
**不急迫的原因**:可以先用纯 Rust 实现原型,验证设计后再做 FFI
|
||
|
||
---
|
||
|
||
#### 🟡 M2: 性能优化
|
||
|
||
**当前问题**:没有性能测试和优化
|
||
|
||
**建议**:
|
||
- 先保证功能正确性
|
||
- 再用 Benchmark 找瓶颈
|
||
- 最后针对性优化
|
||
|
||
**不急迫的原因**:过早优化是万恶之源
|
||
|
||
---
|
||
|
||
### 6.4 Low 级别(未来可选)
|
||
|
||
#### 🟢 L1: Web 后台
|
||
|
||
**建议**:核心 CLI 工具稳定后再做
|
||
|
||
#### 🟢 L2: API Server
|
||
|
||
**建议**:先做单机版,需求明确后再做服务端
|
||
|
||
---
|
||
|
||
## 第七部分:当前目录结构评估与重构建议
|
||
|
||
### 7.1 当前目录结构问题
|
||
|
||
**问题 1:缺少领域层**
|
||
```
|
||
当前:
|
||
crates/
|
||
├── bat-cas-engine/ # 技术组件
|
||
├── bat-assetbundle/ # 技术组件
|
||
├── bat-patch/ # 技术组件
|
||
└── bat-ffi/ # 技术组件
|
||
|
||
缺少:
|
||
- 没有业务领域模型
|
||
- 没有应用服务层
|
||
- 没有集成层
|
||
```
|
||
|
||
**问题 2:模块划分不清晰**
|
||
```
|
||
internal/ # Go 私有包
|
||
├── downloader/ # 这是基础设施
|
||
├── manifest/ # 这是领域对象
|
||
├── storage/ # 这是基础设施
|
||
├── config/ # 这是基础设施
|
||
└── extractor/ # 这是应用服务
|
||
|
||
混在一起,职责不清!
|
||
```
|
||
|
||
**问题 3:适配层缺失**
|
||
```
|
||
应该有但没有:
|
||
adapters/
|
||
├── unity/ # Unity 版本适配器
|
||
├── manifest/ # Manifest 格式适配器
|
||
└── client/ # 客户端平台适配器
|
||
```
|
||
|
||
---
|
||
|
||
### 7.2 推荐的新目录结构
|
||
|
||
```
|
||
BlueArchiveToolkit/
|
||
├── core/ # 核心领域层(Rust)
|
||
│ ├── domain/ # 领域模型
|
||
│ │ ├── game_client.rs
|
||
│ │ ├── game_version.rs
|
||
│ │ ├── resource.rs
|
||
│ │ ├── translation.rs
|
||
│ │ └── mod.rs
|
||
│ ├── repositories/ # 仓储接口
|
||
│ │ ├── cas_repository.rs
|
||
│ │ ├── translation_repository.rs
|
||
│ │ └── mod.rs
|
||
│ └── services/ # 领域服务
|
||
│ ├── version_service.rs
|
||
│ ├── translation_service.rs
|
||
│ └── mod.rs
|
||
│
|
||
├── adapters/ # 适配器层(Rust)
|
||
│ ├── unity/ # Unity 版本适配
|
||
│ │ ├── adapter_trait.rs
|
||
│ │ ├── unity_2019_4/
|
||
│ │ ├── unity_2021_3/
|
||
│ │ └── registry.rs
|
||
│ ├── manifest/ # Manifest 格式适配
|
||
│ │ ├── driver_trait.rs
|
||
│ │ ├── format_v1/
|
||
│ │ ├── format_v2/
|
||
│ │ └── registry.rs
|
||
│ └── client/ # 客户端平台适配
|
||
│ ├── windows.rs
|
||
│ ├── android.rs
|
||
│ └── ios.rs
|
||
│
|
||
├── infrastructure/ # 基础设施层(Rust)
|
||
│ ├── cas/ # CAS 存储实现
|
||
│ │ ├── repository_impl.rs
|
||
│ │ ├── file_storage.rs
|
||
│ │ └── s3_storage.rs
|
||
│ ├── downloader/ # 下载器
|
||
│ ├── parser/ # 底层解析器
|
||
│ └── crypto/ # 加密工具
|
||
│
|
||
├── application/ # 应用服务层(Go)
|
||
│ ├── workflows/ # 工作流
|
||
│ │ ├── official_update.go
|
||
│ │ ├── manual_translation.go
|
||
│ │ └── patch_generation.go
|
||
│ ├── commands/ # 命令处理器
|
||
│ │ ├── sync.go
|
||
│ │ ├── extract.go
|
||
│ │ ├── translate.go
|
||
│ │ └── patch.go
|
||
│ └── queries/ # 查询处理器
|
||
│ ├── version_query.go
|
||
│ └── translation_query.go
|
||
│
|
||
├── api/ # API 层(Go)
|
||
│ ├── http/ # HTTP API
|
||
│ ├── grpc/ # gRPC API(可选)
|
||
│ └── cli/ # CLI 入口
|
||
│ └── main.go
|
||
│
|
||
├── web/ # 前端(Vue 3)
|
||
│ ├── admin/
|
||
│ └── shared/
|
||
│
|
||
├── shared/ # 共享代码
|
||
│ ├── types/ # 类型定义
|
||
│ ├── errors/ # 错误定义
|
||
│ └── utils/ # 工具函数
|
||
│
|
||
├── migrations/ # 数据库迁移
|
||
├── docs/ # 文档
|
||
├── scripts/ # 脚本
|
||
└── deployments/ # 部署配置
|
||
```
|
||
|
||
---
|
||
|
||
|
||
### 7.3 新目录结构的优势
|
||
|
||
**1. 清晰的分层架构**
|
||
- 核心领域层:业务逻辑,不依赖外部
|
||
- 适配器层:隔离变化,易于扩展
|
||
- 基础设施层:技术实现,可替换
|
||
- 应用服务层:编排业务流程
|
||
- API 层:对外接口
|
||
|
||
**2. 依赖关系清晰**
|
||
```
|
||
API → Application → Core ← Adapters ← Infrastructure
|
||
↑
|
||
Domain (最核心,不依赖任何外部)
|
||
```
|
||
|
||
**3. 易于测试**
|
||
- 核心层:纯业务逻辑,易于单元测试
|
||
- 适配器层:Mock 接口,易于集成测试
|
||
- 应用层:Mock 依赖,易于端到端测试
|
||
|
||
**4. 易于扩展**
|
||
- 新增 Unity 版本:添加新适配器
|
||
- 新增 Manifest 格式:添加新 Driver
|
||
- 新增翻译 Provider:实现接口即可
|
||
|
||
---
|
||
|
||
## 第八部分:技术风险评估
|
||
|
||
### 8.1 高风险(发生概率高 + 影响大)
|
||
|
||
#### ⚠️ R1: Unity 版本升级导致 AssetBundle 格式变化
|
||
|
||
**发生概率**:**90%**(官方必然会升级)
|
||
**影响程度**:**极高**(整个解析系统失效)
|
||
**维护成本**:**当前设计:极高 / 新设计:低**
|
||
|
||
**缓解措施**:
|
||
- ✅ 立即实施 Adapter 架构
|
||
- ✅ 为每个 Unity 版本建立独立适配器
|
||
- ✅ 建立自动化测试套件
|
||
|
||
---
|
||
|
||
#### ⚠️ R2: Manifest 格式变化
|
||
|
||
**发生概率**:**70%**
|
||
**影响程度**:**高**(资源同步失败)
|
||
**维护成本**:**当前设计:高 / 新设计:低**
|
||
|
||
**缓解措施**:
|
||
- ✅ 实施 Driver 架构
|
||
- ✅ 支持多版本 Manifest 并存
|
||
- ✅ 建立格式自动检测机制
|
||
|
||
---
|
||
|
||
#### ⚠️ R3: 官方增加反破解机制
|
||
|
||
**发生概率**:**50%**
|
||
**影响程度**:**极高**(工具完全失效)
|
||
**维护成本**:**极高**
|
||
|
||
**缓解措施**:
|
||
- ⚠️ 采用最小侵入性的方案(资源替换)
|
||
- ⚠️ 不修改游戏可执行文件
|
||
- ⚠️ 不使用 Hook 技术
|
||
- ⚠️ 提供快速回滚机制
|
||
|
||
---
|
||
|
||
### 8.2 中风险
|
||
|
||
#### ⚠️ R4: 新增的资源类型无法解析
|
||
|
||
**发生概率**:**60%**
|
||
**影响程度**:**中**(部分内容无法翻译)
|
||
**维护成本**:**当前设计:中 / 新设计:低**
|
||
|
||
**缓解措施**:
|
||
- ✅ 插件化的解析器架构
|
||
- ✅ 支持动态加载新解析器
|
||
|
||
---
|
||
|
||
#### ⚠️ R5: AI API 限流或成本过高
|
||
|
||
**发生概率**:**40%**
|
||
**影响程度**:**中**(翻译速度下降)
|
||
**维护成本**:**低**
|
||
|
||
**缓解措施**:
|
||
- ✅ 支持多个 Provider
|
||
- ✅ 实现请求队列和限流
|
||
- ✅ 最大化利用翻译记忆库
|
||
|
||
---
|
||
|
||
### 8.3 低风险
|
||
|
||
#### 🟢 R6: 数据库性能瓶颈
|
||
|
||
**发生概率**:**20%**
|
||
**影响程度**:**低**(响应变慢)
|
||
**维护成本**:**低**
|
||
|
||
**缓解措施**:
|
||
- 索引优化
|
||
- 查询优化
|
||
- 必要时分库分表
|
||
|
||
---
|
||
|
||
## 第九部分:其他关键问题
|
||
|
||
### 9.1 没有考虑的问题
|
||
|
||
#### 问题 1:多区域支持
|
||
|
||
**当前状况**:架构假设只有一个游戏版本
|
||
|
||
**实际情况**:
|
||
- 日服(JP)
|
||
- 国际服(Global)
|
||
- 韩服(KR)
|
||
- 国服(CN)- 可能有特殊审查要求
|
||
|
||
每个区域的:
|
||
- Manifest 地址不同
|
||
- 资源 CDN 不同
|
||
- 更新时间不同
|
||
- 可能有独占内容
|
||
|
||
**需要的设计**:
|
||
```rust
|
||
pub enum GameRegion {
|
||
Japan,
|
||
Global,
|
||
Korea,
|
||
China,
|
||
}
|
||
|
||
pub struct RegionConfig {
|
||
manifest_url: String,
|
||
cdn_urls: Vec<String>,
|
||
api_endpoints: Vec<String>,
|
||
special_handling: Option<RegionHandler>,
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
#### 问题 2:增量更新策略
|
||
|
||
**当前状况**:没有明确的增量更新策略
|
||
|
||
**问题**:
|
||
- 用户不应该每次都下载全部资源
|
||
- 需要智能判断哪些需要更新
|
||
- 需要支持差异化更新
|
||
|
||
**需要的设计**:
|
||
```rust
|
||
pub struct UpdateStrategy {
|
||
/// 计算需要更新的资源
|
||
fn calculate_delta(
|
||
&self,
|
||
local: &ResourceIndex,
|
||
remote: &Manifest,
|
||
) -> Vec<ResourceUpdate>;
|
||
|
||
/// 优先级排序(先下载重要的)
|
||
fn prioritize(&self, updates: Vec<ResourceUpdate>) -> Vec<ResourceUpdate>;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
#### 问题 3:错误恢复机制
|
||
|
||
**当前状况**:没有设计错误恢复
|
||
|
||
**问题**:
|
||
- 下载中断如何恢复?
|
||
- 翻译失败如何重试?
|
||
- Patch 应用失败如何回滚?
|
||
|
||
**需要的设计**:
|
||
```rust
|
||
pub trait Recoverable {
|
||
/// 保存检查点
|
||
fn save_checkpoint(&self) -> Result<CheckpointId>;
|
||
|
||
/// 从检查点恢复
|
||
fn restore_from_checkpoint(&self, id: CheckpointId) -> Result<()>;
|
||
|
||
/// 清理检查点
|
||
fn cleanup_checkpoint(&self, id: CheckpointId) -> Result<()>;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
#### 问题 4:版本兼容性矩阵
|
||
|
||
**当前状况**:没有定义兼容性规则
|
||
|
||
**问题**:
|
||
- 工具版本 1.0 能否处理游戏版本 2.0 的资源?
|
||
- 旧的翻译能否应用到新版本?
|
||
- 如何处理不兼容的情况?
|
||
|
||
**需要的设计**:
|
||
```rust
|
||
pub struct CompatibilityMatrix {
|
||
/// 检查工具版本是否支持游戏版本
|
||
fn is_compatible(
|
||
&self,
|
||
tool_version: &Version,
|
||
game_version: &GameVersion,
|
||
) -> CompatibilityResult;
|
||
|
||
/// 获取升级路径
|
||
fn get_upgrade_path(
|
||
&self,
|
||
from: &Version,
|
||
to: &Version,
|
||
) -> Vec<Version>;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
#### 问题 5:用户数据迁移
|
||
|
||
**当前状况**:没有考虑数据迁移
|
||
|
||
**问题**:
|
||
- 工具升级时如何迁移用户数据?
|
||
- 如何保证数据完整性?
|
||
- 如何支持降级?
|
||
|
||
**需要的设计**:
|
||
```rust
|
||
pub trait Migratable {
|
||
fn current_version(&self) -> Version;
|
||
fn migrate_from(&self, version: Version) -> Result<()>;
|
||
fn can_downgrade_to(&self, version: Version) -> bool;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
#### 问题 6:并发控制
|
||
|
||
**当前状况**:CAS 存储有并发问题
|
||
|
||
**问题**:
|
||
- 多个进程同时访问 CAS 怎么办?
|
||
- 如何防止数据竞争?
|
||
- 如何保证原子性?
|
||
|
||
**需要的设计**:
|
||
```rust
|
||
pub struct ConcurrencyControl {
|
||
lock_manager: LockManager,
|
||
}
|
||
|
||
impl ConcurrencyControl {
|
||
/// 获取排他锁
|
||
async fn acquire_exclusive(&self, resource: &str) -> Result<Lock>;
|
||
|
||
/// 获取共享锁
|
||
async fn acquire_shared(&self, resource: &str) -> Result<Lock>;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
#### 问题 7:监控和可观测性
|
||
|
||
**当前状况**:没有监控设计
|
||
|
||
**问题**:
|
||
- 如何知道系统运行状况?
|
||
- 如何追踪问题?
|
||
- 如何收集性能数据?
|
||
|
||
**需要的设计**:
|
||
```rust
|
||
pub struct Telemetry {
|
||
metrics: MetricsCollector,
|
||
traces: TraceCollector,
|
||
logs: LogCollector,
|
||
}
|
||
|
||
// 关键指标
|
||
- 下载速度
|
||
- 翻译质量
|
||
- API 响应时间
|
||
- 错误率
|
||
- 资源使用情况
|
||
```
|
||
|
||
---
|
||
|
||
#### 问题 8:安全性
|
||
|
||
**当前状况**:没有安全设计
|
||
|
||
**问题**:
|
||
- 如何防止恶意 Patch?
|
||
- 如何验证资源完整性?
|
||
- 如何保护用户隐私?
|
||
|
||
**需要的设计**:
|
||
```rust
|
||
pub struct SecurityValidator {
|
||
/// 验证 Patch 签名
|
||
fn verify_patch_signature(&self, patch: &Patch) -> Result<bool>;
|
||
|
||
/// 检查资源完整性
|
||
fn check_integrity(&self, resource: &Resource) -> Result<bool>;
|
||
|
||
/// 加密敏感数据
|
||
fn encrypt_sensitive_data(&self, data: &[u8]) -> Result<Vec<u8>>;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
#### 问题 9:测试策略
|
||
|
||
**当前状况**:只有少量单元测试
|
||
|
||
**问题**:
|
||
- 如何保证代码质量?
|
||
- 如何测试适配器?
|
||
- 如何测试工作流?
|
||
|
||
**需要的测试层次**:
|
||
```
|
||
1. 单元测试(Unit Tests)
|
||
- 每个模块独立测试
|
||
- Mock 所有依赖
|
||
|
||
2. 集成测试(Integration Tests)
|
||
- 测试模块间交互
|
||
- 使用真实数据库(测试环境)
|
||
|
||
3. 端到端测试(E2E Tests)
|
||
- 测试完整工作流
|
||
- 使用真实游戏资源(脱敏)
|
||
|
||
4. 性能测试(Performance Tests)
|
||
- Benchmark 关键路径
|
||
- 压力测试
|
||
|
||
5. 兼容性测试(Compatibility Tests)
|
||
- 测试不同 Unity 版本
|
||
- 测试不同 Manifest 格式
|
||
```
|
||
|
||
---
|
||
|
||
#### 问题 10:文档策略
|
||
|
||
**当前状况**:文档偏技术,缺少用户视角
|
||
|
||
**问题**:
|
||
- 用户如何使用工具?
|
||
- 开发者如何贡献代码?
|
||
- 如何编写插件?
|
||
|
||
**需要的文档**:
|
||
```
|
||
docs/
|
||
├── user-guide/ # 用户指南
|
||
│ ├── installation.md
|
||
│ ├── first-translation.md
|
||
│ └── troubleshooting.md
|
||
├── developer-guide/ # 开发者指南
|
||
│ ├── architecture.md
|
||
│ ├── contributing.md
|
||
│ └── code-style.md
|
||
├── plugin-guide/ # 插件开发指南
|
||
│ ├── unity-adapter.md
|
||
│ ├── manifest-driver.md
|
||
│ └── translation-provider.md
|
||
└── api-reference/ # API 参考
|
||
├── rust-api.md
|
||
└── go-api.md
|
||
```
|
||
|
||
---
|
||
|
||
|
||
## 第十部分:完整重构方案
|
||
|
||
### 10.1 重构优先级和时间线
|
||
|
||
#### Phase 0:立即暂停(已完成 ✅)
|
||
- 停止继续实现技术细节
|
||
- 完成架构审查
|
||
|
||
#### Phase 1:核心架构重构(2-3 周)
|
||
|
||
**Week 1:领域建模**
|
||
- [ ] 定义核心领域对象(GameClient, GameVersion, Resource, Translation)
|
||
- [ ] 设计仓储接口(Repository Interfaces)
|
||
- [ ] 实现领域服务(Domain Services)
|
||
- [ ] 编写领域层测试
|
||
|
||
**Week 2:适配器架构**
|
||
- [ ] 设计 Unity Adapter 接口
|
||
- [ ] 实现第一个 Unity 适配器(当前使用的版本)
|
||
- [ ] 设计 Manifest Driver 接口
|
||
- [ ] 实现第一个 Manifest Driver
|
||
- [ ] 设计客户端集成接口
|
||
|
||
**Week 3:基础设施重构**
|
||
- [ ] 重构 CAS 为统一的 Repository
|
||
- [ ] 实现事务支持
|
||
- [ ] 重新组织目录结构
|
||
- [ ] 迁移现有代码到新架构
|
||
|
||
**产出物**:
|
||
- 清晰的领域模型
|
||
- 可扩展的适配器架构
|
||
- 重构后的代码库
|
||
|
||
---
|
||
|
||
#### Phase 2:工作流实现(2-3 周)
|
||
|
||
**Week 4-5:核心工作流**
|
||
- [ ] 实现版本检测服务
|
||
- [ ] 实现资源同步工作流
|
||
- [ ] 实现文本提取工作流
|
||
- [ ] 实现差异分析器
|
||
|
||
**Week 6:翻译工作流**
|
||
- [ ] 实现翻译记忆库
|
||
- [ ] 实现术语库
|
||
- [ ] 实现翻译管道
|
||
- [ ] 实现审核队列
|
||
|
||
**产出物**:
|
||
- 完整的自动化工作流
|
||
- 可测试的业务流程
|
||
|
||
---
|
||
|
||
#### Phase 3:客户端集成(2 周)
|
||
|
||
**Week 7-8:集成层实现**
|
||
- [ ] 实现客户端发现
|
||
- [ ] 实现资源备份
|
||
- [ ] 实现资源替换
|
||
- [ ] 实现完整性验证
|
||
- [ ] 实现回滚机制
|
||
|
||
**产出物**:
|
||
- 可用的客户端集成
|
||
- 端到端测试通过
|
||
|
||
---
|
||
|
||
#### Phase 4:打磨和优化(2 周)
|
||
|
||
**Week 9-10**
|
||
- [ ] 性能优化
|
||
- [ ] 错误处理完善
|
||
- [ ] 日志和监控
|
||
- [ ] 文档完善
|
||
- [ ] 用户指南
|
||
|
||
**产出物**:
|
||
- 可发布的 Alpha 版本
|
||
|
||
---
|
||
|
||
### 10.2 新架构的模块依赖图
|
||
|
||
```mermaid
|
||
graph TB
|
||
subgraph "API Layer"
|
||
CLI[CLI]
|
||
HTTP[HTTP API]
|
||
end
|
||
|
||
subgraph "Application Layer"
|
||
WF[Workflows]
|
||
CMD[Commands]
|
||
end
|
||
|
||
subgraph "Domain Layer"
|
||
DOM[Domain Models]
|
||
SVC[Domain Services]
|
||
REPO[Repository Interfaces]
|
||
end
|
||
|
||
subgraph "Adapter Layer"
|
||
UNITY[Unity Adapters]
|
||
MANIFEST[Manifest Drivers]
|
||
CLIENT[Client Adapters]
|
||
end
|
||
|
||
subgraph "Infrastructure Layer"
|
||
CAS[CAS Repository]
|
||
DL[Downloader]
|
||
DB[Database]
|
||
end
|
||
|
||
CLI --> WF
|
||
HTTP --> WF
|
||
WF --> CMD
|
||
CMD --> SVC
|
||
SVC --> DOM
|
||
SVC --> REPO
|
||
REPO --> CAS
|
||
REPO --> DB
|
||
SVC --> UNITY
|
||
SVC --> MANIFEST
|
||
CMD --> CLIENT
|
||
CLIENT --> CAS
|
||
|
||
style DOM fill:#90EE90
|
||
style UNITY fill:#FFB6C1
|
||
style MANIFEST fill:#FFB6C1
|
||
style CLIENT fill:#FFB6C1
|
||
```
|
||
|
||
---
|
||
|
||
### 10.3 关键设计决策
|
||
|
||
#### 决策 1:Rust 为核心,Go 为应用层
|
||
|
||
**理由**:
|
||
- Rust:性能关键路径(解析、Patch、CAS)
|
||
- Go:业务编排、HTTP API、CLI
|
||
- 优势互补
|
||
|
||
**权衡**:
|
||
- ✅ 发挥各语言优势
|
||
- ⚠️ FFI 有一定复杂度
|
||
- ✅ 但隔离清晰,便于测试
|
||
|
||
---
|
||
|
||
#### 决策 2:采用资源替换而非内存 Hook
|
||
|
||
**理由**:
|
||
- 维护成本低
|
||
- 兼容性好
|
||
- 安全性高
|
||
- 易于回滚
|
||
|
||
**权衡**:
|
||
- ✅ 长期维护成本低
|
||
- ⚠️ 需要深入理解 AssetBundle
|
||
- ✅ 但这是一次性成本
|
||
|
||
---
|
||
|
||
#### 决策 3:插件化架构
|
||
|
||
**理由**:
|
||
- Unity 版本必然升级
|
||
- Manifest 格式可能变化
|
||
- 需要支持扩展
|
||
|
||
**权衡**:
|
||
- ✅ 长期可维护
|
||
- ⚠️ 初期开发成本略高
|
||
- ✅ 但避免未来大规模重构
|
||
|
||
---
|
||
|
||
#### 决策 4:工作流引擎
|
||
|
||
**理由**:
|
||
- 业务流程复杂
|
||
- 需要错误恢复
|
||
- 需要可观测性
|
||
|
||
**权衡**:
|
||
- ✅ 流程清晰
|
||
- ✅ 易于扩展
|
||
- ⚠️ 需要学习成本
|
||
|
||
---
|
||
|
||
### 10.4 技术债务清单
|
||
|
||
#### 必须立即偿还
|
||
- ❌ 缺少领域模型
|
||
- ❌ 缺少适配器架构
|
||
- ❌ CAS 缺少事务
|
||
- ❌ 缺少客户端集成
|
||
|
||
#### 第一个版本前偿还
|
||
- ⚠️ 工作流设计
|
||
- ⚠️ 错误恢复机制
|
||
- ⚠️ 监控和日志
|
||
|
||
#### 可以延后
|
||
- 🟢 性能优化
|
||
- 🟢 Web 后台
|
||
- 🟢 API Server
|
||
|
||
---
|
||
|
||
## 第十一部分:行动计划
|
||
|
||
### 11.1 立即行动(本周)
|
||
|
||
**任务 1:确认架构方向**
|
||
- [ ] 审查本文档
|
||
- [ ] 确认重构范围
|
||
- [ ] 确认时间线
|
||
|
||
**任务 2:准备重构**
|
||
- [ ] 备份当前代码
|
||
- [ ] 创建 refactor 分支
|
||
- [ ] 准备测试环境
|
||
|
||
**任务 3:开始领域建模**
|
||
- [ ] 定义核心领域对象
|
||
- [ ] 编写领域层代码
|
||
- [ ] 编写单元测试
|
||
|
||
---
|
||
|
||
### 11.2 第一周目标
|
||
|
||
**交付物**:
|
||
- ✅ 完整的领域模型(Rust)
|
||
- ✅ 核心接口定义
|
||
- ✅ 通过测试的领域层
|
||
|
||
**验收标准**:
|
||
- 代码编译通过
|
||
- 所有单元测试通过
|
||
- 文档更新
|
||
|
||
---
|
||
|
||
### 11.3 第一个月目标
|
||
|
||
**交付物**:
|
||
- ✅ 重构后的架构
|
||
- ✅ 适配器框架
|
||
- ✅ 核心工作流
|
||
|
||
**里程碑**:
|
||
- M1:领域层完成(Week 1)
|
||
- M2:适配器层完成(Week 2)
|
||
- M3:基础设施完成(Week 3)
|
||
- M4:工作流完成(Week 5)
|
||
|
||
---
|
||
|
||
### 11.4 三个月目标
|
||
|
||
**交付物**:
|
||
- ✅ 可用的 Alpha 版本
|
||
- ✅ 完整文档
|
||
- ✅ 测试覆盖 > 80%
|
||
|
||
**里程碑**:
|
||
- M5:客户端集成完成(Week 8)
|
||
- M6:端到端测试通过(Week 9)
|
||
- M7:Alpha 版本发布(Week 10)
|
||
|
||
---
|
||
|
||
## 第十二部分:总结与建议
|
||
|
||
### 12.1 核心结论
|
||
|
||
1. **当前架构不可持续** ❌
|
||
- 缺少业务领域建模
|
||
- 缺少适配层设计
|
||
- 缺少客户端集成
|
||
- 无法应对未来变化
|
||
|
||
2. **必须立即重构** ⚠️
|
||
- 继续开发会积累技术债
|
||
- 未来重构成本呈指数增长
|
||
- 现在重构成本最低
|
||
|
||
3. **重构方向明确** ✅
|
||
- 领域驱动设计
|
||
- 适配器+插件架构
|
||
- 工作流引擎
|
||
- 清晰的分层
|
||
|
||
---
|
||
|
||
### 12.2 关键建议
|
||
|
||
#### 建议 1:先做对,再做快
|
||
|
||
不要为了快速实现功能而妥协架构质量。好的架构会让后续开发更快。
|
||
|
||
#### 建议 2:接受重构成本
|
||
|
||
当前已写的代码中,约 30-40% 需要重构或重写。这是必要的投资。
|
||
|
||
#### 建议 3:边重构边测试
|
||
|
||
每重构一个模块,立即编写测试。不要等到最后。
|
||
|
||
#### 建议 4:文档同步更新
|
||
|
||
代码重构的同时更新文档,保持一致性。
|
||
|
||
#### 建议 5:小步快跑
|
||
|
||
按周交付,每周都有可验证的成果。
|
||
|
||
---
|
||
|
||
### 12.3 成功标准
|
||
|
||
**技术标准**:
|
||
- ✅ 编译通过,无警告
|
||
- ✅ 测试覆盖率 > 80%
|
||
- ✅ 所有 Critical 问题解决
|
||
- ✅ 架构文档完整
|
||
|
||
**业务标准**:
|
||
- ✅ 能够完成一次完整的官方更新适配
|
||
- ✅ 翻译质量达标
|
||
- ✅ 用户可以正常使用
|
||
|
||
**可维护性标准**:
|
||
- ✅ 新增 Unity 版本只需要添加适配器
|
||
- ✅ 新增 Manifest 格式只需要添加 Driver
|
||
- ✅ 代码易读、易测试、易扩展
|
||
|
||
---
|
||
|
||
### 12.4 风险与应对
|
||
|
||
**风险 1:重构时间超出预期**
|
||
|
||
**应对**:
|
||
- 采用迭代方式
|
||
- 先完成核心,再完善细节
|
||
- 保持可运行状态
|
||
|
||
**风险 2:需求理解偏差**
|
||
|
||
**应对**:
|
||
- 尽早实现端到端原型
|
||
- 及时验证假设
|
||
- 快速迭代
|
||
|
||
**风险 3:技术难点卡住**
|
||
|
||
**应对**:
|
||
- 预留缓冲时间
|
||
- 及时寻求帮助
|
||
- 准备备选方案
|
||
|
||
---
|
||
|
||
## 附录:代码示例
|
||
|
||
### A1. 核心领域对象示例
|
||
|
||
```rust
|
||
// core/domain/game_client.rs
|
||
|
||
use std::path::PathBuf;
|
||
use crate::domain::{GameVersion, ResourceIndex, GameRegion};
|
||
|
||
/// 游戏客户端
|
||
///
|
||
/// 代表用户本地安装的 Blue Archive 游戏客户端
|
||
pub struct GameClient {
|
||
/// 客户端 ID
|
||
id: ClientId,
|
||
|
||
/// 安装路径
|
||
install_path: PathBuf,
|
||
|
||
/// 当前版本
|
||
version: GameVersion,
|
||
|
||
/// 区域
|
||
region: GameRegion,
|
||
|
||
/// 资源索引
|
||
resources: ResourceIndex,
|
||
|
||
/// 客户端状态
|
||
status: ClientStatus,
|
||
}
|
||
|
||
impl GameClient {
|
||
/// 发现本地安装的客户端
|
||
pub fn discover() -> Result<Vec<GameClient>> {
|
||
todo!()
|
||
}
|
||
|
||
/// 验证客户端完整性
|
||
pub fn verify_integrity(&self) -> Result<IntegrityReport> {
|
||
todo!()
|
||
}
|
||
|
||
/// 获取当前版本
|
||
pub fn current_version(&self) -> &GameVersion {
|
||
&self.version
|
||
}
|
||
|
||
/// 检查是否有可用更新
|
||
pub async fn check_for_updates(&self) -> Result<Option<GameVersion>> {
|
||
todo!()
|
||
}
|
||
}
|
||
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||
pub enum ClientStatus {
|
||
/// 原始状态(未修改)
|
||
Pristine,
|
||
|
||
/// 已应用翻译
|
||
Translated,
|
||
|
||
/// 损坏(需要修复)
|
||
Corrupted,
|
||
|
||
/// 未知状态
|
||
Unknown,
|
||
}
|
||
```
|
||
|
||
### A2. Unity 适配器示例
|
||
|
||
```rust
|
||
// adapters/unity/unity_2021_3/assetbundle_parser.rs
|
||
|
||
use crate::adapters::unity::UnityAdapter;
|
||
use crate::core::domain::AssetBundle;
|
||
|
||
pub struct Unity2021_3Adapter {
|
||
// 配置
|
||
}
|
||
|
||
impl UnityAdapter for Unity2021_3Adapter {
|
||
fn name(&self) -> &str {
|
||
"Unity-2021.3"
|
||
}
|
||
|
||
fn supported_versions(&self) -> VersionRange {
|
||
VersionRange::new("2021.3.0", "2021.3.99")
|
||
}
|
||
|
||
fn can_handle(&self, bundle: &RawAssetBundle) -> bool {
|
||
// 检查文件头部的版本信息
|
||
bundle.version().major == 2021
|
||
&& bundle.version().minor == 3
|
||
}
|
||
|
||
fn parse(&self, bundle: &RawAssetBundle) -> Result<ParsedAssetBundle> {
|
||
// Unity 2021.3 特定的解析逻辑
|
||
todo!()
|
||
}
|
||
|
||
fn serialize(&self, parsed: &ParsedAssetBundle) -> Result<Vec<u8>> {
|
||
// Unity 2021.3 特定的序列化逻辑
|
||
todo!()
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 结语
|
||
|
||
这份架构审查报告指出了当前项目的核心问题:**过度关注技术实现,而忽视了业务领域建模和可扩展性设计**。
|
||
|
||
如果不立即重构,项目将在 1-3 年内陷入技术债务泥潭,最终可能需要推倒重来。
|
||
|
||
好的消息是:问题已经被识别,解决方案也很明确。现在重构的成本是最低的,收益是最大的。
|
||
|
||
**建议立即启动重构,按照本文档规划的路线图执行。**
|
||
|
||
---
|
||
|
||
**文档版本**:v1.0
|
||
**创建日期**:2026-06-27
|
||
**作者**:Claude (Chief Architect)
|
||
**状态**:待审核
|
||
|