diff options
| author | 2026-02-27 17:18:25 +0800 | |
|---|---|---|
| committer | 2026-02-27 17:18:25 +0800 | |
| commit | 81a62402ef6f8900ff092366121a9b7a4263ba52 (patch) | |
| tree | 119109c62331d4d26612e2df7726cee82d1871f5 /packages/docs/content/zh/development | |
| parent | 3e3144a2c6c62375c2949cb5e9b03f17511fccbe (diff) | |
| download | DropOut-81a62402ef6f8900ff092366121a9b7a4263ba52.tar.gz DropOut-81a62402ef6f8900ff092366121a9b7a4263ba52.zip | |
Restructure docs into manual/development and add implementation docs (#94)
## Summary by Sourcery
Restructure documentation into separate manual and development sections,
introduce detailed internal implementation docs for auth/Java/mod
loaders, and update site navigation, landing page links, and MDX tooling
(Mermaid, card styling) to match the new structure and tech stack.
Enhancements:
- Enable Mermaid rendering support in the docs app and add a reusable
Mermaid React component.
- Refine Docs page rendering by customizing Card styling and removing
redundant in-page titles/descriptions rendered by the layout.
- Align docs source configuration and routing comments with the new
manual-based default paths.
Documentation:
- Split user-facing docs under a new manual section and move contributor
content into a dedicated development section for both English and
Chinese.
- Add comprehensive internal implementation documentation covering
authentication, Java management, mod loader/version merging, event bus,
and architecture patterns in both English and Chinese.
- Update existing feature docs (mod loaders, Java, authentication) and
getting-started/troubleshooting pages to be more conceptual, pointing to
implementation docs for technical details.
- Refresh architecture docs to reflect the React/Zustand frontend stack
and add Mermaid-based architecture diagrams.
- Adjust navigation labels, home-page CTAs, and doc links to target the
new manual/development structure and routes.
---------
Co-authored-by: 简律纯 <i@jyunko.cn>
Diffstat (limited to 'packages/docs/content/zh/development')
| -rw-r--r-- | packages/docs/content/zh/development/architecture.mdx | 311 | ||||
| -rw-r--r-- | packages/docs/content/zh/development/implementation.mdx | 351 | ||||
| -rw-r--r-- | packages/docs/content/zh/development/index.mdx | 596 | ||||
| -rw-r--r-- | packages/docs/content/zh/development/meta.json | 8 |
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" + ] +} |