aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/packages/docs/content/zh/development/implementation.mdx
blob: d7586aad78abc4dda0d07efce04da2f8ba83a9ac (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
---
title: 内部实现
description: DropOut 核心功能的详细实现和技术规范
---

# 内部实现

本页详细介绍了启动器各个核心模块的技术实现细节、数据结构和处理流程。

## 1. 身份验证系统 (Authentication)

身份验证链包含多个异步步骤,任何一步失败都会中断整个流程。DropOut 采用 Microsoft Device Code Flow 实现免重定向的安全登录。

### 1.1 详细流程
1.  **设备代码请求**: 
    - 调用 `https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode`
    - 获取用户验证码及验证 URL。
2.  **令牌交换**: 轮询 `/oauth2/v2.0/token` 获取主访问令牌 (Access Token) 和刷新令牌 (Refresh Token)。
3.  **Xbox Live 认证**: 获取 `Token` 和 `uhs` (User Hash)。
4.  **XSTS 授权**: 重定向至 `rp://api.minecraftservices.com/`。
5.  **Minecraft 登录**: 使用 `XBL3.0 x=<uhs>;<xsts_token>` 格式令牌换取最终的游戏 Access Token。

### 1.2 账户存储与安全
账户数据持久化在 `accounts.json` 中,包含账户类型及加密后的令牌信息:
```json
{
  "active_account_uuid": "...",
  "accounts": [
    {
      "type": "Microsoft",
      "username": "...",
      "uuid": "...",
      "access_token": "...",
      "refresh_token": "...",
      "expires_at": 1234567890
    },
    { "type": "Offline", "username": "Player", "uuid": "..." }
  ]
}
```
**离线 UUID**: 使用基于用户名的确定性 UUID v3,确保本地存档和配置的一致性。

```rust
// core/auth.rs 实现详情
pub fn generate_offline_uuid(username: &str) -> String {
    let namespace = Uuid::NAMESPACE_OID;
    Uuid::new_v3(&namespace, username.as_bytes()).to_string()
}
```

### 1.3 身份验证相关接口
| 命令 / 事件 | 类型 | 说明 |
| :--- | :--- | :--- |
| `start_microsoft_login` | Invoke | 启动设备流并返回验证码 |
| `complete_microsoft_login` | Invoke | 轮询并完成全套身份验证链 |
| `login_offline` | Invoke | 创建并切换至离线账户 |
| `auth-progress` | Event | 实时上报认证进度(如 "Xbox Live Auth...") |

---

## 2. Java 运行环境管理 (Java Runtime)

### 2.1 目录与元数据
Java 目录 (Catalog) 缓存了来自 Adoptium 的可用版本及其平台特定链接。
-   **存储**: `java_catalog.json` 记录了各个版本的 SHA256 校验和及文件大小。

```json
// java_catalog.json 结构示例
{
  "releases": [
    {
      "major_version": 17,
      "image_type": "jdk",
      "version": "17.0.9+9",
      "download_url": "...",
      "checksum": "...",
      "file_size": 123456789
    }
  ],
  "cached_at": 1700000000
}
```

-   **检测**: 通过对候选路径执行 `java -version` 命令,解析其 `stderr` 输出中的版本字符串和 64-Bit 标识。

```rust
// core/java.rs 检测逻辑
fn check_java_installation(path: &PathBuf) -> Option<JavaInstallation> {
    let mut cmd = Command::new(path);
    cmd.arg("-version");
    // 解析 stderr 输出中的 "version" 关键字信息
}
```

### 2.2 自动安装逻辑
1.  **下载**: 支持断点续传,大型文件通过分片并行下载。
2.  **解压**: 针对不同操作系统处理压缩包(macOS 处理 .tar.gz 内部的 .app 结构,Windows 处理 .zip)。
3.  **验证**: 下载后强制进行哈希校验,确保运行时环境的完整性。

### 2.3 Java 管理相关接口
| 命令 / 事件 | 类型 | 说明 |
| :--- | :--- | :--- |
| `detect_java` | Invoke | 扫描系统已安装的 Java 环境 |
| `download_adoptium_java` | Invoke | 启动异步下载并自动解压配置 |
| `cancel_java_download` | Invoke | 通过原子标志位取消当前的下载任务 |
| `java-download-progress` | Event | 报告文件大小、速度、百分比和 ETA |

---

## 3. 游戏启动逻辑与 JVM 优化

### 3.1 内存分配方案
-   **Xmx & Xms**: 建议将初始内存与最大内存设为一致。
-   **策略**: 启动器会自动根据系统总内存和 Java 架构提示用户最优分配,且启动器生成的参数具有最高优先级。

### 3.2 G1GC 优化策略
针对 1.17+ 版本及高负载模组环境,DropOut 默认注入精简的 G1GC 参数链:
```bash
-XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200 
-XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC 
```

---

## 4. 模组加载机制 (Mod Loaders)

### 4.1 版本合并 (Inheritance)
模组加载器通过 `inheritsFrom` 字段链接原版 Minecraft 版本 JSON。

```json
// 典型的 Fabric 版本配置 (部分)
{
  "id": "fabric-loader-0.15.0-1.20.4",
  "inheritsFrom": "1.20.4",
  "mainClass": "net.fabricmc.loader.impl.launch.knot.KnotClient",
  "libraries": [
    {
      "name": "net.fabricmc:fabric-loader:0.15.0",
      "url": "https://maven.fabricmc.net/"
    }
  ]
}
```

启动阶段执行以下合并:
1.  **库优先级**: 加载器自身的库(如 Fabric Loader)排在原版库之前。
2.  **主类覆盖**: `mainClass` 始终取自子级定义(即模组加载器的入口,如 Fabric 的 `KnotClient`)。
3.  **参数链**: 合并 `jvm` 和 `game` 参数数组,自动剔除不适用的系统规则。

```rust
// core/version_merge.rs 合并核心实现
pub fn merge_versions(child: GameVersion, parent: GameVersion) -> GameVersion {
    let mut merged_libraries = child.libraries;
    merged_libraries.extend(parent.libraries);
    // 合并参数逻辑并返回新的 GameVersion 实例
}
```

### 4.2 库路径解析 (Maven)
启动器实现了完整的 Maven 路径转换逻辑:
`group:artifact:version` → `group_path/artifact/version/artifact-version.jar`

```rust
// core/maven.rs 坐标转换路径逻辑
pub fn to_path(&self) -> String {
    let group_path = self.group.replace('.', "/");
    format!("{}/{}/{}/{}-{}.{}", 
        group_path, self.artifact, self.version, 
        self.artifact, self.version, self.extension
    )
}
```

### 4.3 模组安装接口
启动器根据不同加载器的特性采用差异化安装策略。

#### Forge 安装逻辑
对于 Forge,DropOut 会下载官方 Installer 并通过子进程调用 Java 运行标准安装程序,确保这一过程与官方流程完全一致(包括字节码补丁生成)。

```rust
// core/forge.rs 调用官方安装器 (简化示例)
Command::new(java_path)
    .args(&[
        "-jar", 
        installer_path.to_str().unwrap(), 
        "--installClient", 
        game_dir.to_str().unwrap()
    ])
    .output()?;
```

| 命令 / 事件 | 类型 | 说明 |
| :--- | :--- | :--- |
| `install_fabric` | Invoke | 下载 Fabric 库并生成继承 JSON |
| `install_forge` | Invoke | 运行 Forge Installer 并执行字节码打桩 |
| `mod-loader-progress` | Event | 报告安装阶段(如 "processing", "complete") |

---

## 5. 通讯与监控系统

### 5.1 事件总线 (Event Bus)
后端通过 Tauri 的 `Window` 实例向上层发送异步脉冲。

```rust
// 后端 emit_log! 宏简化日志外发
macro_rules! emit_log {
    ($window:expr, $msg:expr) => {
        let _ = $window.emit("launcher-log", $msg);
        println!("[Launcher] {}", $msg);
    };
}
```

-   **`launcher-log`**: 通用的控制台输出流,用于全局操作轨迹记录。
-   **`game-stdout` / `game-stderr`**: 捕获游戏子进程的标准输出与错误,通过独立线程实时回传前端。

```typescript
// 前端监听示例 (Svelte 5)
import { listen } from "@tauri-apps/api/event";

const unlisten = await listen("launcher-log", (event) => {
    logStore.addLine(event.payload);
});
```

-   **`version-installed`**: 异步任务完成后通知 UI 更新版本列表状态。

### 5.2 启动日志脱敏
为防止敏感信息泄露至第三方日志平台,启动器在记录启动指令前会对令牌进行遮蔽。

```rust
// 基于 main.rs 的参数遮蔽逻辑 (部分)
let masked_args: Vec<String> = args.iter().enumerate().map(|(i, arg)| {
    if i > 0 && (args[i-1] == "--accessToken" || args[i-1] == "--uuid") {
        "***".to_string()
    } else {
        arg.clone()
    }
}).collect();
```

---

## 6. 架构与开发规范

### 6.1 核心架构模式

#### 后端命令模式 (Tauri)
所有后端功能均封装为异步 Command,并通过 `State` 注入全局状态。

1. **定义命令**:
```rust
#[tauri::command]
async fn start_game(
    window: Window,
    auth_state: State<'_, AccountState>,
    config_state: State<'_, ConfigState>
) -> Result<String, String> {
    emit_log!(window, "Starting game launch...");
    // 业务逻辑...
    Ok("Success".into())
}
```

2. **注册命令 (main.rs)**:
```rust
tauri::Builder::default()
    .invoke_handler(tauri::generate_handler![start_game, ...])
```

3. **前端调用**:
```typescript
import { invoke } from "@tauri-apps/api/core";
// 参数名需与 Rust 函数参数保持蛇形/驼峰对应
const result = await invoke("start_game", { versionId: "1.20.4" });
```

#### 错误处理模式
所有 Tauri 命令统一返回 `Result<T, String>`,其中 Err 类型固定为 String,以便前端直接展示错误信息。

```rust
// 统一使用 map_err 将错误转换为 String
.await
.map_err(|e| e.to_string())?;

// 前端捕获
try {
    await invoke("...")
} catch (e) {
    // e 即为 Rust 返回的错误字符串
    console.error(e); 
}
```

#### 前端状态管理 (Svelte 5 Runes)
前端全线采用 Svelte 5 的 `Runes` 系统 (`$state`, `$effect`) 替代旧版的 `writable` stores。

```typescript
// ui/src/stores/auth.svelte.ts
export class AuthState {
  // 使用 $state 定义响应式数据
  currentAccount = $state<Account | null>(null);
  isLoginModalOpen = $state(false);

  constructor() {
    // 初始化逻辑
  }
}

// 导出单例用于全局访问
export const authState = new AuthState();
```

#### 前端视图路由 (Manual Routing)
DropOut 不使用常规的 URL 路由,而是通过全局状态管理当前激活的视图组件。

```typescript
// ui/src/stores/ui.svelte.ts
export class UIState {
    activeView = $state("home"); // "home" | "versions" | "settings"
    
    setView(view: string) {
        this.activeView = view;
    }
}
```

```svelte
<!-- App.svelte -->
<script>
    import { uiState } from "./stores/ui.svelte";
</script>

{#if uiState.activeView === "home"}
    <HomeView />
{:else if uiState.activeView === "settings"}
    <SettingsView />
{/if}
```

### 6.2 开发最佳实践
1.  **静默刷新**: 在调用 `start_game` 前检查 `expires_at`,若过期则调用 `refresh_full_auth`。
2.  **UA 伪装**: 微软认证 WAF 会拦截空 UA 请求,务必在 `reqwest` 客户端中模拟真实 UA。
3.  **日志脱敏**: 启动日志中需屏蔽 `--accessToken` 和 `--uuid` 等敏感参数值。

### 6.3 未来路线图 (Roadmap)
-   **账户多端同步**: 探索 OS 级加密存储方案以替代现有明文 `accounts.json`。
-   **自动依赖解析**: 安装模组时自动解析并下载 Modrinth/CurseForge 上的前置库。
-   **智能冲突检测**: 启动前扫描 `mods/` 文件夹,识别潜在的类冲突或版本不匹配。
-   **配置文件共享**: 支持一键导出/导入完整的实例配置包(Modpack)。