aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/packages/docs/content/zh/development
diff options
context:
space:
mode:
authorNtskwK <natsukawa247@outlook.com>2026-02-28 09:03:19 +0800
committerNtskwK <natsukawa247@outlook.com>2026-02-28 09:03:19 +0800
commitcc53b1cf260e1c67939e50608ef18764da616d55 (patch)
tree119109c62331d4d26612e2df7726cee82d1871f5 /packages/docs/content/zh/development
parentee37d044e473217daadd9ce26c7e2e2ad39a0490 (diff)
parent81a62402ef6f8900ff092366121a9b7a4263ba52 (diff)
downloadDropOut-cc53b1cf260e1c67939e50608ef18764da616d55.tar.gz
DropOut-cc53b1cf260e1c67939e50608ef18764da616d55.zip
Merge remote-tracking branch 'upstream/main'
Diffstat (limited to 'packages/docs/content/zh/development')
-rw-r--r--packages/docs/content/zh/development/architecture.mdx311
-rw-r--r--packages/docs/content/zh/development/implementation.mdx351
-rw-r--r--packages/docs/content/zh/development/index.mdx596
-rw-r--r--packages/docs/content/zh/development/meta.json8
4 files changed, 1266 insertions, 0 deletions
diff --git a/packages/docs/content/zh/development/architecture.mdx b/packages/docs/content/zh/development/architecture.mdx
new file mode 100644
index 0000000..4f47115
--- /dev/null
+++ b/packages/docs/content/zh/development/architecture.mdx
@@ -0,0 +1,311 @@
+---
+title: 架构设计
+description: DropOut Minecraft 启动器的技术架构和设计
+---
+
+# 架构设计
+
+DropOut 采用现代技术栈构建,旨在实现高性能、安全性和跨平台兼容性。
+
+## 技术栈
+
+### 后端(Rust)
+
+- **框架**: Tauri v2
+- **语言**: Rust(Edition 2021)
+- **异步运行时**: Tokio
+- **HTTP 客户端**: reqwest with native-tls
+
+### 前端(React)
+
+- **框架**: React 19
+- **状态管理**: Zustand
+- **路由**: React Router v7
+- **样式**: Tailwind CSS 4
+- **构建工具**: Vite (with Rolldown)
+- **包管理器**: pnpm
+
+### 文档
+
+- **框架**: Fumadocs with React Router v7
+- **内容**: MDX 文件
+- **样式**: Tailwind CSS 4
+
+## 系统架构
+
+```mermaid
+graph TB
+ subgraph Frontend["前端 (React 19)"]
+ direction LR
+ Stores[Zustand Stores] ~~~ Components[Components] ~~~ Pages[Pages] ~~~ Router[Router] ~~~ Particles[Particle Background]
+ end
+
+ subgraph TauriLayer["Tauri 通信层"]
+ direction LR
+ Commands[命令] ~~~ Events[事件/发射器]
+ end
+
+ subgraph Backend["后端 (Rust/Tauri)"]
+ direction TB
+ MainRS[main.rs 命令处理]
+
+ subgraph CoreModules["核心模块"]
+ direction LR
+ Auth[Auth] ~~~ Download[Download] ~~~ Java[Java] ~~~ Instance[Instance]
+ Fabric[Fabric] ~~~ Forge[Forge] ~~~ Config[Config] ~~~ Manifest[Manifest]
+ Auth ~~~ Fabric
+ end
+
+ subgraph Utils["工具和辅助函数"]
+ direction LR
+ ZipExtract[ZIP 提取] ~~~ PathUtils[路径工具]
+ end
+
+ MainRS --> CoreModules
+ CoreModules --> Utils
+ end
+
+ subgraph ExternalAPIs["外部 API"]
+ direction LR
+ Mojang[Mojang APIs] ~~~ FabricMeta[Fabric Meta] ~~~ ForgeMaven[Forge Maven]
+ end
+
+ Frontend <--> TauriLayer
+ TauriLayer <--> Backend
+ Backend <--> ExternalAPIs
+
+ style Frontend fill:#e3f2fd
+ style Backend fill:#fff3e0
+ style TauriLayer fill:#f3e5f5
+ style ExternalAPIs fill:#e8f5e9
+```
+
+## 核心组件
+
+### 前端状态管理
+
+DropOut 使用 **Zustand** 进行全局状态管理:
+
+```typescript
+// models/auth.ts
+import { create } from "zustand";
+
+interface AuthState {
+ account: Account | null;
+ loginMode: LoginMode | null;
+ // ...
+ setAccount: (account: Account | null) => void;
+}
+
+export const useAuthStore = create<AuthState>((set) => ({
+ account: null,
+ loginMode: null,
+ setAccount: (account) => set({ account }),
+ // ...
+}));
+```
+
+**关键 Stores:**
+
+- `models/auth.ts`: 认证状态和登录流程
+- `models/settings.ts`: 启动器设置和 Java 检测
+- `models/instance.ts`: 实例管理
+- `stores/game-store.ts`: 游戏运行状态
+- `stores/logs-store.ts`: 游戏日志流管理
+- `stores/ui-store.ts`: UI 状态(提示、模态框、活动视图)
+
+### 后端架构
+
+#### 命令模式
+
+所有 Tauri 命令遵循此结构:
+
+```rust
+#[tauri::command]
+async fn command_name(
+ window: Window,
+ state: State<'_, SomeState>,
+ param: Type,
+) -> Result<ReturnType, String> {
+ emit_log!(window, "状态消息");
+ // 异步逻辑
+ Ok(result)
+}
+```
+
+#### 事件通信
+
+**Rust → 前端(进度更新):**
+
+```rust
+window.emit("launcher-log", "正在下载...")?;
+window.emit("download-progress", progress_struct)?;
+```
+
+**前端 → Rust(命令):**
+
+```typescript
+import { invoke } from "@tauri-apps/api/core";
+const result = await invoke("start_game", { versionId: "1.20.4" });
+```
+
+### 核心模块
+
+#### 认证(`core/auth.rs`)
+
+- **微软 OAuth 2.0**: 设备代码流
+- **离线认证**: 本地 UUID 生成
+- **令牌管理**: 刷新令牌存储和自动刷新
+- **Xbox Live 集成**: 完整认证链
+
+**认证流程:**
+
+1. 设备代码请求 → MS 令牌
+2. Xbox Live 认证
+3. XSTS 授权
+4. Minecraft 令牌交换
+5. 配置文件获取
+
+#### 下载器(`core/downloader.rs`)
+
+- **并发下载**: 可配置线程池
+- **断点续传**: `.part` 和 `.part.meta` 文件
+- **多段下载**: 大文件分割成块
+- **校验和验证**: SHA1/SHA256 验证
+- **进度跟踪**: 实时事件到前端
+
+#### Java 管理(`core/java.rs`)
+
+- **自动检测**: 扫描系统路径
+- **Adoptium 集成**: 按需下载 JDK/JRE
+- **目录缓存**: 版本列表 24 小时缓存
+- **安装**: 提取到应用数据目录
+- **取消**: 下载取消的原子标志
+
+#### Fabric 支持(`core/fabric.rs`)
+
+- **Meta API 集成**: 获取加载器版本
+- **配置文件生成**: 创建版本 JSON
+- **库解析**: Maven 构件处理
+
+#### Forge 支持(`core/forge.rs`)
+
+- **安装程序执行**: 运行 Forge 安装程序
+- **配置文件解析**: 提取安装配置文件
+- **库管理**: 处理 Forge 特定库
+
+#### 实例系统(`core/instance.rs`)
+
+- **隔离**: 每个实例独立目录
+- **配置**: 每个实例的设置
+- **模组管理**: 实例特定模组
+- **版本锁定**: 可复现环境
+
+#### 版本管理
+
+- **清单解析**(`manifest.rs`): Mojang 版本清单
+- **继承系统**(`version_merge.rs`): 父版本合并
+- **游戏版本**(`game_version.rs`): JSON 解析和验证
+- **规则引擎**(`rules.rs`): 操作系统/功能条件逻辑
+
+### 文件结构
+
+```
+~/.local/share/com.dropout.launcher/ (Linux)
+~/Library/Application Support/com.dropout.launcher/ (macOS)
+%APPDATA%/com.dropout.launcher/ (Windows)
+├── versions/
+│ └── <version_id>/
+│ ├── <version_id>.json
+│ ├── <version_id>.jar
+│ └── natives/
+├── libraries/
+│ └── <maven-path>/
+├── assets/
+│ ├── indexes/
+│ └── objects/
+├── instances/
+│ └── <instance_name>/
+│ ├── mods/
+│ ├── config/
+│ └── saves/
+├── java/
+│ └── <version>/
+├── config.json
+└── accounts.json
+```
+
+## 数据流
+
+### 游戏启动序列
+
+1. **前端**: 用户点击"启动游戏"
+2. **命令**: 调用 `start_game(instance_id, version_id)`
+3. **后端处理**:
+ - 加载版本 JSON(带继承)
+ - 解析所有库
+ - 下载缺少的资源
+ - 提取原生库
+ - 构建类路径
+ - 构造 JVM 参数
+ - 替换占位符
+4. **进程生成**: 使用参数启动 Java
+5. **流日志**: 向前端发送 stdout/stderr
+6. **监视**: 跟踪游戏进程状态
+
+### 下载流程
+
+1. **队列创建**: 要下载的文件列表
+2. **并发处理**: 信号量限制线程
+3. **恢复检查**: 验证现有 `.part` 文件
+4. **下载**: 大文件多段
+5. **验证**: 校验和验证
+6. **进度事件**: 实时更新到 UI
+7. **完成**: 从 `.part` 移动到最终位置
+
+### 认证流程
+
+1. **设备代码请求**: 获取用户代码 + 设备代码
+2. **用户授权**: 用户访问 URL 并输入代码
+3. **令牌轮询**: 前端轮询完成
+4. **令牌交换**: MS 令牌 → Xbox → XSTS → Minecraft
+5. **配置文件获取**: 获取用户名和 UUID
+6. **存储**: 使用刷新令牌保存账户
+7. **自动刷新**: 过期时后台令牌刷新
+
+## 平台特定考虑
+
+### Linux
+
+- 使用 GTK WebView(`webkit2gtk`)
+- 从 `/usr/lib/jvm` 系统 Java 检测
+- 桌面文件集成
+
+### macOS
+
+- 使用系统 WebKit
+- 应用程序包结构
+- 钥匙串集成用于安全存储
+
+### Windows
+
+- 使用 WebView2 运行时
+- 注册表 Java 检测
+- MSI 安装程序支持
+- 发布版本中无控制台窗口
+
+## 性能优化
+
+- **并发下载**: 并行资源/库下载
+- **延迟加载**: 按需加载版本清单
+- **缓存**: Java 目录、版本清单
+- **原生代码**: 用于 CPU 密集型操作的 Rust
+- **异步 I/O**: 用于非阻塞操作的 Tokio
+
+## 安全功能
+
+- **令牌加密**: 安全存储认证令牌
+- **仅 HTTPS**: 所有外部 API 调用
+- **校验和验证**: 文件完整性验证
+- **沙箱执行**: Tauri 安全模型
+- **无任意代码**: 无 eval 或动态代码执行
diff --git a/packages/docs/content/zh/development/implementation.mdx b/packages/docs/content/zh/development/implementation.mdx
new file mode 100644
index 0000000..d7586aa
--- /dev/null
+++ b/packages/docs/content/zh/development/implementation.mdx
@@ -0,0 +1,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)。
diff --git a/packages/docs/content/zh/development/index.mdx b/packages/docs/content/zh/development/index.mdx
new file mode 100644
index 0000000..f562196
--- /dev/null
+++ b/packages/docs/content/zh/development/index.mdx
@@ -0,0 +1,596 @@
+---
+title: 开发指南
+description: 从源代码构建、测试和贡献 DropOut
+---
+
+# 开发指南
+
+本指南将帮助你设置开发环境、从源代码构建 DropOut,以及为项目做出贡献。
+
+## 前置要求
+
+### 必需软件
+
+1. **Rust** (最新稳定版)
+
+ ```bash
+ # 通过 rustup 安装
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
+ ```
+
+2. **Node.js** (v22+) 和 **pnpm** (v9+)
+
+ ```bash
+ # 从 https://nodejs.org/ 安装 Node.js
+ # 安装 pnpm
+ npm install -g pnpm@9
+ ```
+
+3. **系统依赖**
+
+ 按照你的平台参考 [Tauri 前置要求](https://v2.tauri.app/start/prerequisites/):
+
+ **Linux (Debian/Ubuntu):**
+
+ ```bash
+ sudo apt update
+ sudo apt install libwebkit2gtk-4.1-dev \
+ build-essential \
+ curl \
+ wget \
+ file \
+ libssl-dev \
+ libayatana-appindicator3-dev \
+ librsvg2-dev
+ ```
+
+ **macOS:**
+
+ ```bash
+ xcode-select --install
+ ```
+
+ **Windows:**
+ - 安装 [Microsoft Visual C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/)
+ - 安装 [WebView2](https://developer.microsoft.com/microsoft-edge/webview2/)
+
+## 快速开始
+
+### 克隆仓库
+
+```bash
+git clone https://github.com/HydroRoll-Team/DropOut.git
+cd DropOut
+```
+
+### 安装依赖
+
+**前端依赖:**
+
+```bash
+cd packages/ui
+pnpm install
+cd ../..
+```
+
+**文档依赖:**
+
+```bash
+cd packages/docs
+pnpm install
+cd ../..
+```
+
+### 开发模式
+
+以开发模式运行 DropOut,支持热重载:
+
+```bash
+cargo tauri dev
+```
+
+这将:
+
+1. 启动前端开发服务器(Vite 在 5173 端口)
+2. 编译 Rust 后端
+3. 打开 Tauri 窗口
+4. 为前端更改启用热重载
+5. 在 Rust 文件更改时重新编译
+
+**终端输出:**
+
+- 来自 Vite 的前端日志
+- Rust 标准输出/标准错误
+- 编译状态
+
+### 构建生产版本
+
+构建发布二进制文件:
+
+```bash
+cargo tauri build
+```
+
+**输出位置:**
+
+- **Linux**: `src-tauri/target/release/bundle/`
+ - `.deb` 软件包
+ - `.AppImage` 包
+- **macOS**: `src-tauri/target/release/bundle/`
+ - `.dmg` 安装器
+ - `.app` 包
+- **Windows**: `src-tauri/target/release/bundle/`
+ - `.msi` 安装器
+ - `.exe` 可执行文件
+
+## 项目结构
+
+```
+DropOut/
+├── src-tauri/ # Rust 后端
+│ ├── src/
+│ │ ├── main.rs # Tauri 命令和入口点
+│ │ ├── core/ # 核心模块
+│ │ │ ├── auth.rs # 身份验证
+│ │ │ ├── downloader.rs # 下载管理器
+│ │ │ ├── fabric.rs # Fabric 支持
+│ │ │ ├── forge.rs # Forge 支持
+│ │ │ ├── java.rs # Java 管理
+│ │ │ ├── instance.rs # 实例系统
+│ │ │ └── ...
+│ │ └── utils/ # 工具类
+│ └── Cargo.toml
+├── packages/
+│ ├── ui/ # Svelte 5 前端
+│ │ ├── src/
+│ │ │ ├── App.svelte
+│ │ │ ├── components/
+│ │ │ ├── stores/ # 状态管理
+│ │ │ └── lib/
+│ │ └── package.json
+│ └── docs/ # 文档站点
+│ ├── content/docs/
+│ └── package.json
+├── .github/
+│ └── workflows/ # CI/CD 流水线
+└── scripts/ # 构建脚本
+```
+
+## 开发工作流
+
+### 前端开发
+
+**启动开发服务器:**
+
+```bash
+cd packages/ui
+pnpm dev
+```
+
+**类型检查:**
+
+```bash
+pnpm check
+```
+
+**代码检查:**
+
+```bash
+pnpm lint
+```
+
+**格式化代码:**
+
+```bash
+pnpm format
+```
+
+### 后端开发
+
+**运行 Rust 测试:**
+
+```bash
+cargo test
+```
+
+**检查代码:**
+
+```bash
+cargo check
+```
+
+**格式化代码:**
+
+```bash
+cargo fmt
+```
+
+**代码检查:**
+
+```bash
+cargo clippy
+```
+
+### 文档开发
+
+**启动文档开发服务器:**
+
+```bash
+cd packages/docs
+pnpm dev
+```
+
+**构建文档:**
+
+```bash
+pnpm build
+```
+
+**类型检查:**
+
+```bash
+pnpm types:check
+```
+
+## 代码风格
+
+### Rust
+
+遵循标准 Rust 约定:
+
+- 使用 `cargo fmt` 格式化
+- 使用 `cargo clippy` 检查
+- 编写文档注释 (`///`)
+- 正确处理错误
+- 对 I/O 使用 async/await
+
+**示例:**
+
+```rust
+/// Starts the Microsoft authentication device flow
+#[tauri::command]
+async fn start_microsoft_login(
+ window: Window,
+) -> Result<DeviceCodeResponse, String> {
+ emit_log!(window, "Starting Microsoft login...");
+
+ start_device_flow()
+ .await
+ .map_err(|e| e.to_string())
+}
+```
+
+### TypeScript/Svelte
+
+遵循项目约定:
+
+- 使用 Svelte 5 runes (`$state`, `$effect`)
+- 优先使用 TypeScript 而非 JavaScript
+- 使用 Biome 进行格式化和检查
+- 遵循组件结构
+
+**示例:**
+
+```typescript
+// stores/auth.svelte.ts
+export class AuthState {
+ currentAccount = $state<Account | null>(null);
+ isLoginModalOpen = $state(false);
+
+ async login(username: string) {
+ const account = await invoke("offline_login", { username });
+ this.currentAccount = account;
+ }
+}
+```
+
+## 测试
+
+### 单元测试
+
+**Rust:**
+
+```rust
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_generate_offline_uuid() {
+ let uuid = generate_offline_uuid("Player");
+ assert!(uuid.len() > 0);
+ }
+}
+```
+
+**运行:**
+
+```bash
+cargo test
+```
+
+### 集成测试
+
+测试完整应用程序:
+
+1. 以开发模式构建:`cargo tauri dev`
+2. 手动测试功能
+3. 检查控制台错误
+4. 验证 UI 行为
+
+### CI 测试
+
+GitHub Actions 在以下平台运行测试:
+
+- Ubuntu(最新版)
+- Arch Linux(Wayland)
+- Windows(最新版)
+- macOS(ARM64)
+
+查看工作流:`.github/workflows/test.yml`
+
+## 调试
+
+### 前端调试
+
+1. 在 Tauri 窗口中打开开发工具:`Ctrl+Shift+I`(Windows/Linux)或 `Cmd+Option+I`(macOS)
+2. 检查控制台错误
+3. 使用 React DevTools 或 Svelte DevTools
+4. 监控网络标签页查看 API 调用
+
+### 后端调试
+
+**打印调试:**
+
+```rust
+emit_log!(window, format!("Debug: {}", value));
+println!("Debug: {}", value);
+```
+
+**Rust 调试器:**
+
+```bash
+# 安装 rust-lldb 或 rust-gdb
+cargo install rust-gdb
+
+# 调试
+rust-gdb target/debug/dropout
+```
+
+### 日志
+
+**前端:**
+
+```typescript
+console.log("Info message");
+console.error("Error message");
+```
+
+**后端:**
+
+```rust
+emit_log!(window, "Status update");
+eprintln!("Error: {}", error);
+```
+
+## 贡献
+
+### 贡献工作流
+
+1. **Fork** 仓库
+2. **创建**功能分支:
+ ```bash
+ git checkout -b feature/my-feature
+ ```
+3. **进行**更改
+4. **彻底测试**
+5. **提交**时使用约定式提交:
+ ```bash
+ git commit -m "feat: add new feature"
+ ```
+6. **推送**到你的 fork:
+ ```bash
+ git push origin feature/my-feature
+ ```
+7. **创建** Pull Request
+
+### 提交消息
+
+遵循 [约定式提交](https://www.conventionalcommits.org/):
+
+**格式:**
+
+```
+<type>[scope]: <description>
+
+[optional body]
+
+[optional footer]
+```
+
+**类型:**
+
+- `feat`: 新功能
+- `fix`: 错误修复
+- `docs`: 文档
+- `style`: 格式化
+- `refactor`: 代码重构
+- `perf`: 性能改进
+- `test`: 添加测试
+- `chore`: 维护
+
+**示例:**
+
+```bash
+feat(auth): add offline authentication support
+fix(java): resolve detection on Windows
+docs: update installation guide
+refactor(download): simplify progress tracking
+```
+
+### Pull Request 指南
+
+**提交前:**
+
+- [ ] 代码遵循风格指南
+- [ ] 测试在本地通过
+- [ ] 必要时更新文档
+- [ ] 没有提交不必要的文件
+- [ ] 提交消息清晰
+
+**PR 描述:**
+
+- 解释做了什么以及为什么
+- 链接相关 issue
+- 列出破坏性更改
+- 为 UI 更改添加截图
+
+### 代码审查
+
+维护者将审查你的 PR:
+
+- 代码质量和风格
+- 测试覆盖率
+- 文档
+- 性能影响
+- 安全影响
+
+对反馈保持响应并进行要求的更改。
+
+## 常见任务
+
+### 添加 Tauri 命令
+
+1. **在 `main.rs` 中定义命令:**
+
+ ```rust
+ #[tauri::command]
+ async fn my_command(param: String) -> Result<String, String> {
+ Ok(format!("Received: {}", param))
+ }
+ ```
+
+2. **在构建器中注册:**
+
+ ```rust
+ .invoke_handler(tauri::generate_handler![
+ my_command,
+ // ... 其他命令
+ ])
+ ```
+
+3. **从前端调用:**
+ ```typescript
+ const result = await invoke("my_command", { param: "value" });
+ ```
+
+### 添加 UI 组件
+
+1. **创建组件文件:**
+
+ ```svelte
+ <!-- packages/ui/src/components/MyComponent.svelte -->
+ <script lang="ts">
+ let count = $state(0);
+ </script>
+
+ <button onclick={() => count++}>
+ Count: {count}
+ </button>
+ ```
+
+2. **导入并使用:**
+
+ ```svelte
+ <script>
+ import MyComponent from './components/MyComponent.svelte';
+ </script>
+
+ <MyComponent />
+ ```
+
+### 添加 Store
+
+1. **创建 store 文件:**
+
+ ```typescript
+ // packages/ui/src/stores/mystore.svelte.ts
+ export class MyState {
+ value = $state(0);
+
+ increment() {
+ this.value++;
+ }
+ }
+
+ export const myState = new MyState();
+ ```
+
+2. **在组件中使用:**
+
+ ```svelte
+ <script>
+ import { myState } from '../stores/mystore.svelte';
+ </script>
+
+ <button onclick={() => myState.increment()}>
+ {myState.value}
+ </button>
+ ```
+
+## 开发问题故障排除
+
+### 构建失败
+
+**"cannot find -lwebkit2gtk"**
+
+```bash
+# 安装 WebKit 依赖
+sudo apt install libwebkit2gtk-4.1-dev
+```
+
+**"pnpm not found"**
+
+```bash
+# 安装 pnpm
+npm install -g pnpm@9
+```
+
+**"Rust version too old"**
+
+```bash
+# 更新 Rust
+rustup update
+```
+
+### 运行时问题
+
+**"Failed to load dynamic library"**
+
+- 重新构建:`cargo clean && cargo tauri dev`
+- 检查库路径
+- 验证已安装依赖
+
+**"CORS error"**
+
+- 开发模式下正常
+- Tauri 自动处理 CORS
+
+**"Hot reload not working"**
+
+- 检查 Vite 配置
+- 重启开发服务器
+- 清除浏览器缓存
+
+## 资源
+
+- [Tauri 文档](https://v2.tauri.app/)
+- [Svelte 5 文档](https://svelte.dev/docs)
+- [Rust 程序设计语言](https://doc.rust-lang.org/book/)
+- [DropOut 仓库](https://github.com/HydroRoll-Team/DropOut)
+
+## 获取帮助
+
+- **Issues**: [GitHub Issues](https://github.com/HydroRoll-Team/DropOut/issues)
+- **讨论**: [GitHub Discussions](https://github.com/HydroRoll-Team/DropOut/discussions)
+- **文档**: 本站点
diff --git a/packages/docs/content/zh/development/meta.json b/packages/docs/content/zh/development/meta.json
new file mode 100644
index 0000000..69cc009
--- /dev/null
+++ b/packages/docs/content/zh/development/meta.json
@@ -0,0 +1,8 @@
+{
+ "title": "开发文档",
+ "pages": [
+ "index",
+ "architecture",
+ "implementation"
+ ]
+}