From ae0d17883021eeb13ef82cb100b1ab5fd8709629 Mon Sep 17 00:00:00 2001 From: NtskwK Date: Tue, 10 Feb 2026 09:37:43 +0800 Subject: [PATCH 1/5] docs: refactor documents --- packages/docs/content/zh/getting-started.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docs/content/zh/getting-started.mdx b/packages/docs/content/zh/getting-started.mdx index 05d9aa4..d36eaf5 100644 --- a/packages/docs/content/zh/getting-started.mdx +++ b/packages/docs/content/zh/getting-started.mdx @@ -111,7 +111,7 @@ chmod +x dropout_*.AppImage - 内存分配(RAM) - 窗口分辨率 - Java 路径 -4. 点击**"启动游戏"** +4. 点击**启动游戏** 5. 在控制台中监视启动过程 ## 下一步 From 4e118c9f12a830ac9a668e1ebf32e38cf3c6bdd5 Mon Sep 17 00:00:00 2001 From: NtskwK Date: Tue, 10 Feb 2026 16:21:30 +0800 Subject: [PATCH 2/5] docs: enhance card component styling and update home page button borders --- packages/docs/app/docs/page.tsx | 13 ++++++++++++- packages/docs/app/routes/home.tsx | 4 ++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/docs/app/docs/page.tsx b/packages/docs/app/docs/page.tsx index a9e3433..a4a3313 100644 --- a/packages/docs/app/docs/page.tsx +++ b/packages/docs/app/docs/page.tsx @@ -40,7 +40,18 @@ const clientLoader = browserCollections.docs.createClientLoader({ {frontmatter.title} {frontmatter.description} - + ( + + ), + Cards + }} + /> ); diff --git a/packages/docs/app/routes/home.tsx b/packages/docs/app/routes/home.tsx index 66b5333..aa6bdbb 100644 --- a/packages/docs/app/routes/home.tsx +++ b/packages/docs/app/routes/home.tsx @@ -107,7 +107,7 @@ export default function Home({ params }: Route.ComponentProps) { {t.hero.start} {t.hero.features} @@ -129,7 +129,7 @@ export default function Home({ params }: Route.ComponentProps) { {/* Features Grid */}
{t.features.items.map((item, i) => ( -
+

{item.title}

{item.desc} From 92db6c50d2b514d8958e5a070f9a3770f1372863 Mon Sep 17 00:00:00 2001 From: NtskwK Date: Tue, 10 Feb 2026 17:32:01 +0800 Subject: [PATCH 3/5] feat: add detailed implementation documentation for core modules --- .../en/{ => development}/architecture.mdx | 0 .../guide.mdx} | 0 .../content/en/development/implementation.mdx | 351 ++++++++++++++++++ .../docs/content/en/development/meta.json | 8 + .../docs/content/en/features/mod-loaders.mdx | 103 +---- .../zh/{ => development}/architecture.mdx | 0 .../guide.mdx} | 0 .../content/zh/development/implementation.mdx | 351 ++++++++++++++++++ .../docs/content/zh/development/meta.json | 8 + .../content/zh/features/authentication.mdx | 153 +------- packages/docs/content/zh/features/java.mdx | 122 +----- .../docs/content/zh/features/mod-loaders.mdx | 225 ++--------- 12 files changed, 769 insertions(+), 552 deletions(-) rename packages/docs/content/en/{ => development}/architecture.mdx (100%) rename packages/docs/content/en/{development.mdx => development/guide.mdx} (100%) create mode 100644 packages/docs/content/en/development/implementation.mdx create mode 100644 packages/docs/content/en/development/meta.json rename packages/docs/content/zh/{ => development}/architecture.mdx (100%) rename packages/docs/content/zh/{development.mdx => development/guide.mdx} (100%) create mode 100644 packages/docs/content/zh/development/implementation.mdx create mode 100644 packages/docs/content/zh/development/meta.json diff --git a/packages/docs/content/en/architecture.mdx b/packages/docs/content/en/development/architecture.mdx similarity index 100% rename from packages/docs/content/en/architecture.mdx rename to packages/docs/content/en/development/architecture.mdx diff --git a/packages/docs/content/en/development.mdx b/packages/docs/content/en/development/guide.mdx similarity index 100% rename from packages/docs/content/en/development.mdx rename to packages/docs/content/en/development/guide.mdx diff --git a/packages/docs/content/en/development/implementation.mdx b/packages/docs/content/en/development/implementation.mdx new file mode 100644 index 0000000..3ecadfe --- /dev/null +++ b/packages/docs/content/en/development/implementation.mdx @@ -0,0 +1,351 @@ +--- +title: Internal Implementation +description: Detailed implementation and technical specifications of DropOut core functions +--- + +# Internal Implementation + +This page details the technical implementation details, data structures, and processing flows of the launcher's core modules. + +## 1. Authentication System + +The authentication chain contains multiple asynchronous steps, and failure at any step will interrupt the entire process. DropOut uses the Microsoft Device Code Flow to achieve secure login without redirection. + +### 1.1 Detailed Process +1. **Device Code Request**: + - Call `https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode` + - Get user verification code and verification URL. +2. **Token Exchange**: Poll `/oauth2/v2.0/token` to get the primary Access Token and Refresh Token. +3. **Xbox Live Authentication**: Get `Token` and `uhs` (User Hash). +4. **XSTS Authorization**: Redirect to `rp://api.minecraftservices.com/`. +5. **Minecraft Login**: Exchange for the final game Access Token using the `XBL3.0 x=;` format token. + +### 1.2 Account Storage and Security +Account data is persisted in `accounts.json`, containing account type and encrypted token information: +```json +{ + "active_account_uuid": "...", + "accounts": [ + { + "type": "Microsoft", + "username": "...", + "uuid": "...", + "access_token": "...", + "refresh_token": "...", + "expires_at": 1234567890 + }, + { "type": "Offline", "username": "Player", "uuid": "..." } + ] +} +``` +**Offline UUID**: Uses a username-based deterministic UUID v3 to ensure consistency of local saves and configurations. + +```rust +// core/auth.rs implementation details +pub fn generate_offline_uuid(username: &str) -> String { + let namespace = Uuid::NAMESPACE_OID; + Uuid::new_v3(&namespace, username.as_bytes()).to_string() +} +``` + +### 1.3 Authentication Related APIs +| Command / Event | Type | Description | +| :--- | :--- | :--- | +| `start_microsoft_login` | Invoke | Start device flow and return verification code | +| `complete_microsoft_login` | Invoke | Poll and complete the full authentication chain | +| `login_offline` | Invoke | Create and switch to offline account | +| `auth-progress` | Event | Report authentication progress in real-time (e.g., "Xbox Live Auth...") | + +--- + +## 2. Java Runtime Management + +### 2.1 Catalogs and Metadata +The Java Catalog caches available versions and platform-specific links from Adoptium. +- **Storage**: `java_catalog.json` records SHA256 checksums and file sizes for each version. + +```json +// java_catalog.json structure example +{ + "releases": [ + { + "major_version": 17, + "image_type": "jdk", + "version": "17.0.9+9", + "download_url": "...", + "checksum": "...", + "file_size": 123456789 + } + ], + "cached_at": 1700000000 +} +``` + +- **Detection**: Executes `java -version` command on candidate paths and parses version strings and 64-Bit identifiers from `stderr` output. + +```rust +// core/java.rs detection logic +fn check_java_installation(path: &PathBuf) -> Option { + let mut cmd = Command::new(path); + cmd.arg("-version"); + // Parse "version" keyword information from stderr output +} +``` + +### 2.2 Automatic Installation Logic +1. **Download**: Supports resumable downloads; large files are downloaded in parallel segments. +2. **Extraction**: Handles archives for different operating systems (macOS handles .app structure inside .tar.gz, Windows handles .zip). +3. **Verification**: Mandatory hash verification after download ensures runtime environment integrity. + +### 2.3 Java Management Related APIs +| Command / Event | Type | Description | +| :--- | :--- | :--- | +| `detect_java` | Invoke | Scan system installed Java environments | +| `download_adoptium_java` | Invoke | Start asynchronous download and automatic extraction/configuration | +| `cancel_java_download` | Invoke | Cancel current download task via atomic flag | +| `java-download-progress` | Event | Report file size, speed, percentage, and ETA | + +--- + +## 3. Game Launch Logic & JVM Optimization + +### 3.1 Memory Allocation Scheme +- **Xmx & Xms**: It is recommended to set initial memory and maximum memory to be consistent. +- **Strategy**: The launcher automatically suggests optimal allocation based on total system memory and Java architecture, and parameters generated by the launcher have the highest priority. + +### 3.2 G1GC Optimization Strategy +For 1.17+ versions and high-load mod environments, DropOut injects a concise G1GC parameter chain by default: +```bash +-XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200 +-XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC +``` + +--- + +## 4. Mod Loader Mechanism + +### 4.1 Version Merging (Inheritance) +Mod loaders link to the vanilla Minecraft version JSON via the `inheritsFrom` field. + +```json +// Typical Fabric version config (partial) +{ + "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/" + } + ] +} +``` + +The following merging is performed during the launch phase: +1. **Library Priority**: Loader's own libraries (e.g., Fabric Loader) rank before vanilla libraries. +2. **Main Class Override**: `mainClass` is always taken from the child definition (i.e., the mod loader's entry point, like Fabric's `KnotClient`). +3. **Argument Chain**: Merge `jvm` and `game` argument arrays, automatically filtering out inapplicable system rules. + +```rust +// core/version_merge.rs merge core implementation +pub fn merge_versions(child: GameVersion, parent: GameVersion) -> GameVersion { + let mut merged_libraries = child.libraries; + merged_libraries.extend(parent.libraries); + // Merge argument logic and return new GameVersion instance +} +``` + +### 4.2 Library Path Resolution (Maven) +The launcher implements complete Maven path conversion logic: +`group:artifact:version` → `group_path/artifact/version/artifact-version.jar` + +```rust +// core/maven.rs coordinate conversion path logic +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 Mod Installation Interface +The launcher uses differentiated installation strategies based on different loader characteristics. + +#### Forge Installation Logic +For Forge, DropOut downloads the official Installer and invokes the standard installer via a Java subprocess, ensuring this process is completely consistent with the official flow (including bytecode patch generation). + +```rust +// core/forge.rs invoke official installer (simplified example) +Command::new(java_path) + .args(&[ + "-jar", + installer_path.to_str().unwrap(), + "--installClient", + game_dir.to_str().unwrap() + ]) + .output()?; +``` + +| Command / Event | Type | Description | +| :--- | :--- | :--- | +| `install_fabric` | Invoke | Download Fabric libraries and generate inheritance JSON | +| `install_forge` | Invoke | Run Forge Installer and perform bytecode patching | +| `mod-loader-progress` | Event | Report installation stage (e.g., "processing", "complete") | + +--- + +## 5. Communication & Monitoring System + +### 5.1 Event Bus +The backend sends asynchronous pulses to the upper layer via Tauri's `Window` instance. + +```rust +// Backend emit_log! macro simplifies log emission +macro_rules! emit_log { + ($window:expr, $msg:expr) => { + let _ = $window.emit("launcher-log", $msg); + println!("[Launcher] {}", $msg); + }; +} +``` + +- **`launcher-log`**: General console output stream for global operation trajectory recording. +- **`game-stdout` / `game-stderr`**: Capture game subprocess standard output and errors, transmitting to frontend in real-time via independent threads. + +```typescript +// Frontend listen example (Svelte 5) +import { listen } from "@tauri-apps/api/event"; + +const unlisten = await listen("launcher-log", (event) => { + logStore.addLine(event.payload); +}); +``` + +- **`version-installed`**: Notify UI to update version list status after asynchronous task completion. + +### 5.2 Launch Log Desensitization +To prevent sensitive information leakage to third-party log platforms, the launcher masks tokens before recording launch commands. + +```rust +// partial argument masking logic based on main.rs +let masked_args: Vec = args.iter().enumerate().map(|(i, arg)| { + if i > 0 && (args[i-1] == "--accessToken" || args[i-1] == "--uuid") { + "***".to_string() + } else { + arg.clone() + } +}).collect(); +``` + +--- + +## 6. Architecture & Development Standards + +### 6.1 Core Architecture Patterns + +#### Backend Command Pattern (Tauri) +All backend functions are encapsulated as asynchronous Commands and injected with global state via `State`. + +1. **Define Command**: +```rust +#[tauri::command] +async fn start_game( + window: Window, + auth_state: State<'_, AccountState>, + config_state: State<'_, ConfigState> +) -> Result { + emit_log!(window, "Starting game launch..."); + // Business logic... + Ok("Success".into()) +} +``` + +2. **Register Command (main.rs)**: +```rust +tauri::Builder::default() + .invoke_handler(tauri::generate_handler![start_game, ...]) +``` + +3. **Frontend Call**: +```typescript +import { invoke } from "@tauri-apps/api/core"; +// Argument names must correspond to Rust function parameters in snake_case/camelCase +const result = await invoke("start_game", { versionId: "1.20.4" }); +``` + +#### Error Handling Pattern +All Tauri commands uniformly return `Result`, where the Err type is fixed as String, allowing the frontend to display error messages directly. + +```rust +// Uniformly use map_err to convert errors to String +.await +.map_err(|e| e.to_string())?; + +// Frontend catch +try { + await invoke("...") +} catch (e) { + // e is the error string returned by Rust + console.error(e); +} +``` + +#### Frontend State Management (Svelte 5 Runes) +The frontend fully adopts Svelte 5's `Runes` system (`$state`, `$effect`) replacing the old `writable` stores. + +```typescript +// ui/src/stores/auth.svelte.ts +export class AuthState { + // Use $state to define reactive data + currentAccount = $state(null); + isLoginModalOpen = $state(false); + + constructor() { + // Initialization logic + } +} + +// Export singleton for global access +export const authState = new AuthState(); +``` + +#### Frontend View Routing (Manual Routing) +DropOut does not use conventional URL routing, but instead manages the currently active view component via global state. + +```typescript +// ui/src/stores/ui.svelte.ts +export class UIState { + activeView = $state("home"); // "home" | "versions" | "settings" + + setView(view: string) { + this.activeView = view; + } +} +``` + +```svelte + + + +{#if uiState.activeView === "home"} + +{:else if uiState.activeView === "settings"} + +{/if} +``` + +### 6.2 Development Best Practices +1. **Silent Refresh**: Check `expires_at` before calling `start_game`, and call `refresh_full_auth` if expired. +2. **UA Spoofing**: Microsoft auth WAF blocks requests with empty UA, so simulation of real UA in `reqwest` client is mandatory. +3. **Log Desensitization**: Sensitive parameter values like `--accessToken` and `--uuid` must be masked in launch logs. + +### 6.3 Future Roadmap +- **Multi-device Account Sync**: Explore OS-level encrypted storage solution to replace existing plaintext `accounts.json`. +- **Automatic Dependency Resolution**: Automatically parse and download prerequisite libraries from Modrinth/CurseForge when installing mods. +- **Intelligent Conflict Detection**: Scan `mods/` folder before launch to identify potential class conflicts or injection point errors. +- **Config Sharing**: Support one-click export/import of complete instance configuration packages (Modpacks). diff --git a/packages/docs/content/en/development/meta.json b/packages/docs/content/en/development/meta.json new file mode 100644 index 0000000..dc0d5c5 --- /dev/null +++ b/packages/docs/content/en/development/meta.json @@ -0,0 +1,8 @@ +{ + "title": "Development", + "pages": [ + "guide", + "architecture", + "implementation" + ] +} diff --git a/packages/docs/content/en/features/mod-loaders.mdx b/packages/docs/content/en/features/mod-loaders.mdx index d6fdf4f..8fdf019 100644 --- a/packages/docs/content/en/features/mod-loaders.mdx +++ b/packages/docs/content/en/features/mod-loaders.mdx @@ -28,31 +28,7 @@ Fabric is a lightweight, modular modding toolchain focused on: ### How It Works -**Meta API Integration:** -```rust -// Fetch available Fabric versions -let url = format!( - "https://meta.fabricmc.net/v2/versions/loader/{}", - minecraft_version -); -``` - -**Profile Generation:** -1. Fetch Fabric loader metadata -2. Download Fabric libraries -3. Generate version JSON with `inheritsFrom` -4. Merge with parent Minecraft version -5. Add to versions list - -**Version Format:** -```json -{ - "id": "fabric-loader-0.15.0-1.20.4", - "inheritsFrom": "1.20.4", - "mainClass": "net.fabricmc.loader.impl.launch.knot.KnotClient", - "libraries": [...] -} -``` +DropOut integrates with the Fabric Meta API to automatically fetch compatible loader versions. In the background, it generates the version JSON, handles library dependencies, and utilizes the inheritance system to ensure perfect compatibility with vanilla Minecraft. Detailed JSON structure can be found in [Technical Details](/docs/development/implementation#fabric-integration). ### Fabric Versions @@ -68,26 +44,7 @@ let url = format!( ### Library Management -Fabric libraries are resolved from Maven: - -**Main Library:** -``` -net.fabricmc:fabric-loader:0.15.0 -``` - -**Dependencies:** -- `net.fabricmc:tiny-mappings-parser` -- `net.fabricmc:sponge-mixin` -- `net.fabricmc:access-widener` - -**Download:** -```rust -// Maven resolution -let url = format!( - "https://maven.fabricmc.net/{}/{}", - artifact_path, filename -); -``` +Fabric's dependencies are typically hosted on its official Maven repository. DropOut automatically resolves and downloads all required library files. ### Fabric API @@ -164,22 +121,9 @@ java -jar forge-installer.jar --installClient ### Library Management -Forge has many libraries: - -**Core Libraries:** -- `net.minecraftforge:forge:` -- `net.minecraftforge:fmlloader:` -- `org.ow2.asm:asm:` +Forge's runtime depends on a significant number of library files, including its underlying `fmlloader` and bytecode manipulation libraries. DropOut automatically resolves the complex dependency tree and retrieves these files from both the official Forge Maven repository and Minecraft's official libraries. -**Resolution:** -```rust -// Forge Maven -"https://maven.minecraftforge.net/" - -// Dependencies may use: -// - Maven Central -// - Minecraft Libraries -``` +For detailed analysis logic of Forge libraries, refer to [Implementation Details: Forge Core Library Resolution](../development/implementation.mdx#core-library-resolution). ### Forge Processors @@ -192,44 +136,9 @@ DropOut handles these automatically. ## Version Inheritance -Both Fabric and Forge use Minecraft's inheritance system: +Both Fabric and Forge utilize Minecraft's version inheritance mechanism. In this model, the mod loader's version JSON only contains incremental changes relative to the vanilla version, addressed recursively upwards via the `inheritsFrom` field. -### Parent Version - -```json -{ - "id": "fabric-loader-0.15.0-1.20.4", - "inheritsFrom": "1.20.4" // Parent vanilla version -} -``` - -### Merging Process - -**Libraries:** -```rust -// Merged from both -parent_libraries + modded_libraries -// Duplicates removed -``` - -**Arguments:** -```rust -// Combined -parent_jvm_args + modded_jvm_args -parent_game_args + modded_game_args -``` - -**Assets:** -```rust -// Inherited from parent -assets = parent.assets -``` - -**Main Class:** -```rust -// Overridden by modded -main_class = modded.mainClass -``` +DropOut's launch engine automatically handles this complex merging of libraries, arguments, and assets. Detailed merging logic and code implementation can be viewed in [Implementation Details: Version Merging](../development/implementation.mdx#version-merging-mechanism). ## Comparison diff --git a/packages/docs/content/zh/architecture.mdx b/packages/docs/content/zh/development/architecture.mdx similarity index 100% rename from packages/docs/content/zh/architecture.mdx rename to packages/docs/content/zh/development/architecture.mdx diff --git a/packages/docs/content/zh/development.mdx b/packages/docs/content/zh/development/guide.mdx similarity index 100% rename from packages/docs/content/zh/development.mdx rename to packages/docs/content/zh/development/guide.mdx 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=;` 格式令牌换取最终的游戏 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 { + 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 = 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 { + 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`,其中 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(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 + + + +{#if uiState.activeView === "home"} + +{:else if uiState.activeView === "settings"} + +{/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/meta.json b/packages/docs/content/zh/development/meta.json new file mode 100644 index 0000000..69c4ead --- /dev/null +++ b/packages/docs/content/zh/development/meta.json @@ -0,0 +1,8 @@ +{ + "title": "开发文档", + "pages": [ + "guide", + "architecture", + "implementation" + ] +} diff --git a/packages/docs/content/zh/features/authentication.mdx b/packages/docs/content/zh/features/authentication.mdx index e83cc35..f14993e 100644 --- a/packages/docs/content/zh/features/authentication.mdx +++ b/packages/docs/content/zh/features/authentication.mdx @@ -19,50 +19,7 @@ DropOut 使用 **Device Code Flow** 进行 Microsoft 身份验证,具有以下 ### 身份验证流程 -身份验证链包含多个步骤: - -1. **Device Code** → 用户授权 -2. **MS Token** → 访问令牌 + 刷新令牌 -3. **Xbox Live** → Xbox 令牌 + UHS -4. **XSTS** → 安全令牌 -5. **Minecraft** → 游戏访问令牌 -6. **Profile** → 用户名 + UUID - -#### 第 1 步:设备代码请求 -1. 单击"使用 Microsoft 登录" -2. DropOut 从 Microsoft 请求设备代码 -3. 您会收到: - - 用户代码(例如 `A1B2-C3D4`) - - 验证 URL(通常为 `https://microsoft.com/link`) - - 设备代码(内部使用) - -#### 第 2 步:用户授权 -1. 在任何浏览器中访问验证 URL -2. 输入用户代码 -3. 使用 Microsoft 账户登录 -4. 授权 DropOut 访问您的 Minecraft 个人资料 - -#### 第 3 步:令牌交换 -- DropOut 轮询 Microsoft 检查授权完成 -- 授权后接收访问令牌和刷新令牌 -- 刷新令牌被存储以备将来登录使用 - -#### 第 4 步:Xbox Live 身份验证 -- Microsoft 令牌被交换为 Xbox Live 令牌 -- 检索用户哈希 (UHS) 用于下一步 - -#### 第 5 步:XSTS 授权 -- Xbox Live 令牌被用来获取 XSTS 令牌 -- 此令牌特定于 Minecraft 服务 - -#### 第 6 步:Minecraft 登录 -- XSTS 令牌被交换为 Minecraft 访问令牌 -- 使用端点:`/launcher/login` - -#### 第 7 步:个人资料获取 -- 检索您的 Minecraft 用户名 -- 获取您的 UUID -- 检查您是否拥有 Minecraft +身份验证链包含多个步骤。DropOut 自动处理这些复杂的交换过程,包括与 Microsoft、Xbox Live 和 Minecraft 服务的交互。如果您对详细的 API 实现感兴趣,请参阅[内部实现](/docs/development/implementation#身份验证)。 ### 令牌管理 @@ -77,12 +34,7 @@ DropOut 使用 **Device Code Flow** 进行 Microsoft 身份验证,具有以下 - 用于获取新的访问令牌 **自动刷新:** -```rust -// Automatic refresh when token expires -if account.expires_at < current_time { - refresh_full_auth(&account).await?; -} -``` +令牌过期时,DropOut 会在您启动游戏时尝试使用刷新令牌自动更新您的登录状态,确保您可以无缝开始游玩。 ### 安全考虑 @@ -128,12 +80,8 @@ if account.expires_at < current_time { ### 工作原理 **UUID 生成:** -```rust -// Deterministic UUID v3 from username -let uuid = generate_offline_uuid(&username); -``` +离线模式使用基于用户名的确定性 UUID 生成算法(UUID v3)。这意味着在同一个启动器实例中,相同的用户名始终会获得相同的 UUID,从而保持单人游戏存档的一致性。 -- 使用 UUID v3(基于命名空间) - 确定性:相同的用户名 = 相同的 UUID - 无需网络请求 @@ -149,23 +97,6 @@ let uuid = generate_offline_uuid(&username); - 不支持披风 - 无法使用 Microsoft 账户功能 -### 用例 - -**开发:** -```bash -# Testing mod development -cargo tauri dev -# Use offline mode to test quickly -``` - -**LAN 游玩:** -- 无需身份验证即可加入 LAN 世界 -- 托管 LAN 世界 - -**离线游玩:** -- 单人游戏无需网络 -- 无需身份验证 - ## 账户管理 ### 切换账户 @@ -178,23 +109,7 @@ cargo tauri dev ### 账户存储 -账户存储在 `accounts.json` 中: - -```json -{ - "current_account_id": "uuid-here", - "accounts": [ - { - "id": "uuid", - "type": "Microsoft", - "username": "PlayerName", - "access_token": "...", - "refresh_token": "...", - "expires_at": 1234567890 - } - ] -} -``` +账户数据存储在应用文件夹的 `accounts.json` 中。该文件包含已登录账户的加密令牌、过期时间和基本的个人资料信息。 ### 删除账户 @@ -206,61 +121,11 @@ cargo tauri dev ## API 参考 -### Tauri 命令 - -**启动 Microsoft 登录:** -```typescript -const { user_code, verification_uri } = await invoke('start_microsoft_login'); -``` - -**完成 Microsoft 登录:** -```typescript -const account = await invoke('complete_microsoft_login', { deviceCode }); -``` - -**离线登录:** -```typescript -const account = await invoke('offline_login', { username: 'Player' }); -``` - -**登出:** -```typescript -await invoke('logout'); -``` - -**获取当前账户:** -```typescript -const account = await invoke('get_current_account'); -``` - -### 事件 - -**身份验证状态:** -```typescript -listen('auth-status', (event) => { - console.log(event.payload); // "logged_in" | "logged_out" -}); -``` +关于身份验证的底层实现、OAuth 2.0 流程细节以及相关的 Tauri 命令接口,请参考开发文档:[实现细节:身份验证](../development/implementation.mdx#身份验证)。 ## 最佳实践 -### 对于玩家 - -1. **对官方服务器使用 Microsoft 账户** -2. **保护令牌安全** - 不要分享 accounts.json -3. **定期刷新令牌** - 通过登录来刷新 -4. **仅在测试时使用离线模式** - -### 对于开发者 - -1. **优雅地处理令牌过期** -2. **为网络故障实现重试逻辑** -3. **缓存账户数据** 以减少 API 调用 -4. **在游戏启动前验证令牌** - -## 未来增强 - -- **多账户支持**:轻松在账户之间切换 -- **账户配置文件**:保存每个账户的设置 -- **自动登录**:记住最后一个账户 -- **令牌加密**:为存储的令牌增强安全性 +1. **对官方服务器使用 Microsoft 账户**:为了能够加入官方服务器并使用正版皮肤,请务必使用 Microsoft 账户。 +2. **保护令牌安全**:不要向他人分享 `accounts.json` 文件或其内容,因为其中包含您的登录凭据。 +3. **定期刷新令牌**:长时间未使用的离线账户或过期的 Microsoft 令牌可以通过重新登录或启动游戏来刷新。 +4. **仅在测试时使用离线模式**:离线模式不支持皮肤和部分多人游戏功能。 diff --git a/packages/docs/content/zh/features/java.mdx b/packages/docs/content/zh/features/java.mdx index bdc3c15..6894ec1 100644 --- a/packages/docs/content/zh/features/java.mdx +++ b/packages/docs/content/zh/features/java.mdx @@ -84,23 +84,7 @@ DropOut 集成了 Eclipse Adoptium API 以下载高质量的免费 JDK/JRE 构 ### 目录管理 -Java 目录缓存 24 小时以提高性能: - -```rust -// 目录结构 -{ - "versions": [ - { - "version": "17.0.9+9", - "major": 17, - "url": "https://api.adoptium.net/...", - "sha256": "...", - "size": 123456789 - } - ], - "last_updated": 1234567890 -} -``` +DropOut 会缓存可用的 Java 版本列表,以加快加载速度,并自动处理不同步时的刷新工作。 **刷新:** - 24 小时后自动刷新 @@ -166,22 +150,14 @@ java/ ### 自定义 JVM 参数 -为高级配置添加自定义 JVM 参数: - -**常用参数:** -```bash -# 垃圾回收 --XX:+UseG1GC --XX:+UnlockExperimentalVMOptions +为高级配置添加自定义 JVM 参数。DropOut 为您提供了经过优化的默认配置,通常无需手动更改。 -# 性能 --XX:G1NewSizePercent=20 --XX:G1ReservePercent=20 --XX:MaxGCPauseMillis=50 +**参数说明:** +- **垃圾回收 (GC)**: 默认使用 G1GC,能够大幅减少大规模模组环境下的游戏卡顿。 +- **实验性选项**: 部分性能优化参数需要开启此开关才能生效。 +- **内存分块**: 优化大内存环境下的数据读写效率。 -# 内存 --XX:G1HeapRegionSize=32M -``` +关于每个参数的具体作用、推荐数值以及技术实现,请参考 [实现细节:JVM 参数优化](../development/implementation.mdx#参数优化与-jvm-配置)。 ### Java 路径选择 @@ -276,56 +252,6 @@ java/ 4. 如兼容使用更新的 Java 版本 5. 为整合包分配 4-8GB -## API 参考 - -### Tauri 命令 - -**检测 Java 安装:** -```typescript -const javas = await invoke('detect_java_installations'); -// 返回: Array<{ path: string, version: string, major: number }> -``` - -**获取 Java 目录:** -```typescript -const catalog = await invoke('get_java_catalog'); -// 返回: { versions: Array, last_updated: number } -``` - -**下载 Java:** -```typescript -await invoke('download_java', { - version: '17.0.9+9', - variant: 'jdk' // 或 'jre' -}); -``` - -**取消 Java 下载:** -```typescript -await invoke('cancel_java_download'); -``` - -**设置 Java 路径:** -```typescript -await invoke('set_java_path', { path: '/path/to/java' }); -``` - -### 事件 - -**下载进度:** -```typescript -listen('java-download-progress', (event) => { - const { percent, speed, eta } = event.payload; -}); -``` - -**下载完成:** -```typescript -listen('java-download-complete', (event) => { - const { path, version } = event.payload; -}); -``` - ## 最佳实践 ### 对于玩家 @@ -336,14 +262,6 @@ listen('java-download-complete', (event) => { 4. **保持 Java 更新** - 安全性和性能 5. **使用 64 位 Java** - 大内存所需 -### 对于开发者 - -1. **测试多个 Java 版本** - 确保兼容性 -2. **记录 Java 要求** - 帮助用户 -3. **处理缺少的 Java** - 优雅的后备方案 -4. **启动前验证 Java 路径** -5. **提供清晰的错误** - 当 Java 错误时 - ## 高级主题 ### 自定义 Java 安装 @@ -357,32 +275,6 @@ listen('java-download-complete', (event) => { 5. 浏览到 Java 可执行文件 6. 验证版本正确 -### 服务器用 Java - -运行 Minecraft 服务器时: - -```bash -# 推荐的服务器 JVM 参数 --Xms4G -Xmx4G \ --XX:+UseG1GC \ --XX:+ParallelRefProcEnabled \ --XX:MaxGCPauseMillis=200 \ --XX:+UnlockExperimentalVMOptions \ --XX:+DisableExplicitGC \ --XX:G1NewSizePercent=30 \ --XX:G1MaxNewSizePercent=40 \ --XX:G1HeapRegionSize=8M \ --XX:G1ReservePercent=20 \ --XX:G1HeapWastePercent=5 \ --XX:G1MixedGCCountTarget=4 \ --XX:InitiatingHeapOccupancyPercent=15 \ --XX:G1MixedGCLiveThresholdPercent=90 \ --XX:G1RSetUpdatingPauseTimePercent=5 \ --XX:SurvivorRatio=32 \ --XX:+PerfDisableSharedMem \ --XX:MaxTenuringThreshold=1 -``` - ### GraalVM GraalVM 支持高级用户: diff --git a/packages/docs/content/zh/features/mod-loaders.mdx b/packages/docs/content/zh/features/mod-loaders.mdx index 3687230..cbd8148 100644 --- a/packages/docs/content/zh/features/mod-loaders.mdx +++ b/packages/docs/content/zh/features/mod-loaders.mdx @@ -28,31 +28,7 @@ Fabric 是一个轻量级、模块化的模组工具链,专注于: ### 工作原理 -**Meta API 集成:** -```rust -// Fetch available Fabric versions -let url = format!( - "https://meta.fabricmc.net/v2/versions/loader/{}", - minecraft_version -); -``` - -**配置文件生成:** -1. 获取 Fabric 加载器元数据 -2. 下载 Fabric 库 -3. 使用 `inheritsFrom` 生成版本 JSON -4. 与父级 Minecraft 版本合并 -5. 添加至版本列表 - -**版本格式:** -```json -{ - "id": "fabric-loader-0.15.0-1.20.4", - "inheritsFrom": "1.20.4", - "mainClass": "net.fabricmc.loader.impl.launch.knot.KnotClient", - "libraries": [...] -} -``` +DropOut 集成了 Fabric 的 Meta API,能够自动获取兼容的加载器版本。在后台,它会生成版本 JSON,处理库依赖,并利用继承系统确保与原版 Minecraft 的完美兼容。详细的 JSON 结构可参阅[技术细节](/docs/development/implementation#fabric-集成)。 ### Fabric 版本 @@ -68,26 +44,7 @@ let url = format!( ### 库管理 -Fabric 库从 Maven 解析: - -**主库:** -``` -net.fabricmc:fabric-loader:0.15.0 -``` - -**依赖项:** -- `net.fabricmc:tiny-mappings-parser` -- `net.fabricmc:sponge-mixin` -- `net.fabricmc:access-widener` - -**下载:** -```rust -// Maven resolution -let url = format!( - "https://maven.fabricmc.net/{}/{}", - artifact_path, filename -); -``` +Fabric 的依赖项通常托管在其官方 Maven 仓库中。DropOut 自动解析并下载所有必需的库文件。 ### Fabric API @@ -121,34 +78,7 @@ Forge 是原始的、最流行的 Minecraft 模组加载器: ### 工作原理 -**Forge 安装程序:** -```rust -// Download Forge installer -let installer_url = format!( - "https://maven.minecraftforge.net/net/minecraftforge/forge/{}/forge-{}-installer.jar", - full_version, full_version -); - -// Run installer -java -jar forge-installer.jar --installClient -``` - -**配置文件解析:** -1. Forge 安装程序创建版本 JSON -2. DropOut 解析安装配置文件 -3. 提取库依赖项 -4. 处理处理器(如果有) -5. 生成启动器配置文件 - -**版本格式:** -```json -{ - "id": "1.20.4-forge-49.0.26", - "inheritsFrom": "1.20.4", - "mainClass": "cpw.mods.bootstraplauncher.BootstrapLauncher", - "libraries": [...] -} -``` +DropOut 会为您下载 Forge 安装程序。通过在后台以无头模式运行安装程序,我们能够生成所需的版本配置文件并处理复杂的补丁程序。详细实现请参考[技术实现](/docs/development/implementation#forge-支持)。 ### Forge 版本 @@ -164,22 +94,9 @@ java -jar forge-installer.jar --installClient ### 库管理 -Forge 有许多库: +Forge 的运行依赖于大量的库文件,包括底层的 `fmlloader` 和字节码操作库。DropOut 能够自动解析复杂的依赖树,并从 Forge 官方 Maven 仓库以及 Minecraft 官方库中获取这些文件。 -**核心库:** -- `net.minecraftforge:forge:` -- `net.minecraftforge:fmlloader:` -- `org.ow2.asm:asm:` - -**解析:** -```rust -// Forge Maven -"https://maven.minecraftforge.net/" - -// Dependencies may use: -// - Maven Central -// - Minecraft Libraries -``` +关于 Forge 库的详细解析逻辑,请参考[实现细节:Forge 核心库解析](../development/implementation.mdx#核心库解析)。 ### Forge 处理器 @@ -192,44 +109,14 @@ DropOut 自动处理这些操作。 ## 版本继承 -Fabric 和 Forge 都使用 Minecraft 的继承系统: - -### 父版本 - -```json -{ - "id": "fabric-loader-0.15.0-1.20.4", - "inheritsFrom": "1.20.4" // Parent vanilla version -} -``` - -### 合并过程 - -**库:** -```rust -// Merged from both -parent_libraries + modded_libraries -// Duplicates removed -``` - -**参数:** -```rust -// Combined -parent_jvm_args + modded_jvm_args -parent_game_args + modded_game_args -``` - -**资源:** -```rust -// Inherited from parent -assets = parent.assets -``` - -**主类:** -```rust -// Overridden by modded -main_class = modded.mainClass -``` +Fabric 和 Forge 都利用了 Minecraft 的版本继承机制。在这种模式下,模组加载器的版本 JSON 仅包含相对于原版版本的增量变化,通过 `inheritsFrom` 字段递归向上寻址。 + +DropOut 的启动引擎能够自动处理这种复杂的合并: +- **库 (Libraries)**:自动排重并确保加载顺序。 +- **参数 (Arguments)**:合并游戏参数与 JVM 参数。 +- **主类 (Main Class)**:自动切换至模组加载器的入口点。 + +具体的合并逻辑和代码实现请查看[实现细节:版本合并](../development/implementation.mdx#版本合并机制)。 ## 对比 @@ -334,76 +221,22 @@ main_class = modded.mainClass ## API 参考 -### Tauri 命令 - -**安装 Fabric:** -```typescript -await invoke('install_fabric', { - minecraftVersion: '1.20.4', - loaderVersion: '0.15.0' -}); -``` - -**安装 Forge:** -```typescript -await invoke('install_forge', { - minecraftVersion: '1.20.4', - forgeVersion: '49.0.26' -}); -``` - -**列出 Fabric 版本:** -```typescript -const versions = await invoke('get_fabric_versions', { - minecraftVersion: '1.20.4' -}); -``` - -**列出 Forge 版本:** -```typescript -const versions = await invoke('get_forge_versions', { - minecraftVersion: '1.20.4' -}); -``` - -### 事件 - -**安装进度:** -```typescript -listen('mod-loader-progress', (event) => { - const { stage, percent } = event.payload; - // Stages: "downloading", "installing", "processing", "complete" -}); -``` +如果您正在为 DropOut 开发自定义主题或进行二次开发,可以使用我们提供的 Tauri 命令和事件接口。 + +具体的命令接口、参数说明及进度推送事件详见开发文档:[实现细节:模组加载器 API](../development/implementation.mdx#api-参考)。 ## 最佳实践 -### 对于玩家 - -1. **每个实例选择一个模组加载器** -2. **精确匹配版本** - Minecraft 和加载器 -3. **安装前阅读模组要求** -4. **循序渐进** - 逐步添加模组 -5. **备份世界** - 添加模组前备份 -6. **检查兼容性** 列表 -7. **谨慎更新** - 在单独的实例中测试 - -### 对于模组包创建者 - -1. **记录版本** - MC、加载器、所有模组 -2. **彻底测试** - 所有功能 -3. **列出依赖项** - 包括 API -4. **提供更新日志** - 用于更新 -5. **版本锁定** - 为了稳定性 -6. **包含配置** - 预配置 -7. **测试更新** - 发布前测试 - -## 未来功能 - -- **模组浏览器** - 从启动器安装模组 -- **自动更新** - 保持模组最新 -- **依赖项解析** - 自动安装需求 -- **冲突检测** - 警告不兼容性 -- **配置文件导出** - 共享模组包配置 -- **CurseForge 集成** - 直接模组包导入 -- **Modrinth 集成** - 模组搜索和安装 +1. **每个实例选择一个模组加载器**:不要在同一个实例中混用 Fabric 和 Forge。 +2. **精确匹配版本**:确保 Minecraft 版本与模组加载器版本高度兼容。 +3. **安装前阅读要求**:许多模组需要额外的依赖库(如 Fabric API 或 Architectury)。 +4. **循序渐进**:首次构建模组包时,应分批添加模组以便于排查问题。 +5. **养成备份习惯**:在安装大型模组包或进行版本大更新前,请备份您的存档。 + +更多面向开发者和模组包创作者的进阶指南,请参阅[开发文档:分发最佳实践](../development/implementation.mdx#对于模组包modpack创建者)。 + +## 规划与展望 + +我们致力于为 DropOut 打造最便捷的模组体验。未来,我们计划引入模组浏览器、自动更新监控以及智能冲突检测等功能。 + +详见[开发路线图](../development/implementation.mdx#模组管理系统)。 From 7acca7d3da1fb15d7c199b86122702d2693bd1c1 Mon Sep 17 00:00:00 2001 From: NtskwK Date: Wed, 11 Feb 2026 09:56:14 +0800 Subject: [PATCH 4/5] chore(docs): remove title and description components --- packages/docs/app/docs/page.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/docs/app/docs/page.tsx b/packages/docs/app/docs/page.tsx index a4a3313..7ce13f1 100644 --- a/packages/docs/app/docs/page.tsx +++ b/packages/docs/app/docs/page.tsx @@ -37,8 +37,9 @@ const clientLoader = browserCollections.docs.createClientLoader({ component({ toc, frontmatter, default: Mdx }) { return ( - {frontmatter.title} - {frontmatter.description} + {/* 老王说不要这个 */} + {/* {frontmatter.title} + {frontmatter.description} */} Date: Wed, 11 Feb 2026 10:21:24 +0800 Subject: [PATCH 5/5] docs(docs): reorganize documentation structure into manual and development sections --- packages/docs/app/docs/page.tsx | 4 +- packages/docs/app/lib/layout.shared.tsx | 9 ++- packages/docs/app/lib/source.ts | 4 +- packages/docs/app/routes/docs.tsx | 8 +-- packages/docs/app/routes/home.tsx | 10 +-- packages/docs/content/en/getting-started.mdx | 55 ++++++++-------- .../content/zh/development/architecture.mdx | 20 +++++- .../zh/development/{guide.mdx => index.mdx} | 62 +++++++++++++++++-- .../docs/content/zh/development/meta.json | 2 +- .../{ => manual}/features/authentication.mdx | 0 .../zh/{ => manual}/features/index.mdx | 0 .../content/zh/{ => manual}/features/java.mdx | 0 .../zh/{ => manual}/features/meta.json | 0 .../zh/{ => manual}/features/mod-loaders.mdx | 0 .../zh/{ => manual}/getting-started.mdx | 59 ++++++++---------- .../docs/content/zh/{ => manual}/index.mdx | 2 +- packages/docs/content/zh/manual/meta.json | 10 +++ .../zh/{ => manual}/troubleshooting.mdx | 10 +-- packages/docs/content/zh/meta.json | 6 +- 19 files changed, 167 insertions(+), 94 deletions(-) rename packages/docs/content/zh/development/{guide.mdx => index.mdx} (98%) rename packages/docs/content/zh/{ => manual}/features/authentication.mdx (100%) rename packages/docs/content/zh/{ => manual}/features/index.mdx (100%) rename packages/docs/content/zh/{ => manual}/features/java.mdx (100%) rename packages/docs/content/zh/{ => manual}/features/meta.json (100%) rename packages/docs/content/zh/{ => manual}/features/mod-loaders.mdx (100%) rename packages/docs/content/zh/{ => manual}/getting-started.mdx (71%) rename packages/docs/content/zh/{ => manual}/index.mdx (94%) create mode 100644 packages/docs/content/zh/manual/meta.json rename packages/docs/content/zh/{ => manual}/troubleshooting.mdx (97%) diff --git a/packages/docs/app/docs/page.tsx b/packages/docs/app/docs/page.tsx index 7ce13f1..c93d732 100644 --- a/packages/docs/app/docs/page.tsx +++ b/packages/docs/app/docs/page.tsx @@ -11,8 +11,8 @@ import browserCollections from 'fumadocs-mdx:collections/browser'; export async function loader({ params }: Route.LoaderArgs) { // 从路由参数获取语言,如果没有则使用默认语言 - // URL 格式: /docs/getting-started (默认语言 zh) - // URL 格式: /en/docs/getting-started (英语) + // URL 格式: /docs/manual/getting-started (默认语言 zh) + // URL 格式: /en/docs/manual/getting-started (英语) const lang = (params.lang && i18n.languages.includes(params.lang as any)) ? (params.lang as 'zh' | 'en') : (i18n.defaultLanguage as 'zh' | 'en'); diff --git a/packages/docs/app/lib/layout.shared.tsx b/packages/docs/app/lib/layout.shared.tsx index 6e90ba0..b3595eb 100644 --- a/packages/docs/app/lib/layout.shared.tsx +++ b/packages/docs/app/lib/layout.shared.tsx @@ -16,8 +16,13 @@ export function baseOptions(locale: string): BaseLayoutProps { links: [ { type: 'main', - text: locale === 'zh' ? '文档' : 'Documentation', - url: `${localePrefix}/docs`, + text: locale === 'zh' ? '使用文档' : 'Manual', + url: `${localePrefix}/docs/manual`, + }, + { + type: 'main', + text: locale === 'zh' ? '开发文档' : 'Development', + url: `${localePrefix}/docs/development`, }, ], }; diff --git a/packages/docs/app/lib/source.ts b/packages/docs/app/lib/source.ts index bce9bf9..4d6cc3a 100644 --- a/packages/docs/app/lib/source.ts +++ b/packages/docs/app/lib/source.ts @@ -7,6 +7,6 @@ export const source = loader({ baseUrl: '/docs', i18n, // hideLocale: 'default-locale' 会自动生成正确的 URL: - // - 默认语言 (zh): /docs/getting-started - // - 其他语言 (en): /en/docs/getting-started + // - 默认语言 (zh): /docs/manual/getting-started + // - 其他语言 (en): /en/docs/manual/getting-started }); diff --git a/packages/docs/app/routes/docs.tsx b/packages/docs/app/routes/docs.tsx index 5154d27..5090ccf 100644 --- a/packages/docs/app/routes/docs.tsx +++ b/packages/docs/app/routes/docs.tsx @@ -6,11 +6,11 @@ import { i18n } from '@/lib/i18n'; export function loader({ params }: Route.LoaderArgs) { const lang = params.lang as string | undefined; - // 如果没有语言参数或是默认语言,重定向到 /docs/getting-started + // 如果没有语言参数或是默认语言,重定向到 /docs/manual/getting-started if (!lang || lang === i18n.defaultLanguage) { - return redirect('/docs/getting-started'); + return redirect('/docs/manual/getting-started'); } - // 其他语言重定向到 /:lang/docs/getting-started - return redirect(`/${lang}/docs/getting-started`); + // 其他语言重定向到 /:lang/docs/manual/getting-started + return redirect(`/${lang}/docs/manual/getting-started`); } diff --git a/packages/docs/app/routes/home.tsx b/packages/docs/app/routes/home.tsx index aa6bdbb..427bf4e 100644 --- a/packages/docs/app/routes/home.tsx +++ b/packages/docs/app/routes/home.tsx @@ -10,7 +10,7 @@ const texts = { subtitle: 'Modern. Reproducible. Developer-Grade.', description: 'Built with Tauri v2 and Rust for native performance and minimal resource usage', start: 'Get Started', - features: 'Features', + development: 'Development', }, features: { items: [ @@ -42,7 +42,7 @@ const texts = { subtitle: '现代、可复现、开发者级', description: '基于 Tauri v2 和 Rust 构建,拥有原生性能和极低的资源占用', start: '开始使用', - features: '功能特性', + development: '参与开发', }, features: { items: [ @@ -108,9 +108,9 @@ export default function Home({ params }: Route.ComponentProps) { - {t.hero.features} + {t.hero.development}

@@ -162,7 +162,7 @@ export default function Home({ params }: Route.ComponentProps) {

{t.cta.button} diff --git a/packages/docs/content/en/getting-started.mdx b/packages/docs/content/en/getting-started.mdx index 5219f40..c172289 100644 --- a/packages/docs/content/en/getting-started.mdx +++ b/packages/docs/content/en/getting-started.mdx @@ -13,17 +13,18 @@ DropOut is a modern, reproducible, and developer-grade Minecraft launcher built Download the latest release for your platform from the [Releases](https://github.com/HsiangNianian/DropOut/releases) page. -| Platform | Files | -| -------------- | ----------------------- | -| Linux x86_64 | `.deb`, `.AppImage` | -| Linux ARM64 | `.deb`, `.AppImage` | -| macOS ARM64 | `.dmg` | -| Windows x86_64 | `.msi`, `.exe` | -| Windows ARM64 | `.msi`, `.exe` | +| Platform | Files | +| -------------- | ------------------- | +| Linux x86_64 | `.deb`, `.AppImage` | +| Linux ARM64 | `.deb`, `.AppImage` | +| macOS ARM64 | `.dmg` | +| Windows x86_64 | `.msi`, `.exe` | +| Windows ARM64 | `.msi`, `.exe` | ### Linux Installation #### Using .deb Package + ```bash sudo dpkg -i dropout_*.deb # Fix dependencies if needed @@ -31,6 +32,7 @@ sudo apt-get install -f ``` #### Using AppImage + ```bash chmod +x dropout_*.AppImage ./dropout_*.AppImage @@ -45,11 +47,13 @@ chmod +x dropout_*.AppImage ### Windows Installation #### Using .msi Installer + 1. Double-click the `.msi` file 2. Follow the installation wizard 3. Launch DropOut from the Start Menu #### Using .exe Portable + 1. Double-click the `.exe` file 2. DropOut will run directly without installation @@ -74,17 +78,12 @@ When you first launch DropOut, you'll need to: ### 1. Login - - + + **Microsoft Login:** + 1. Click "Login with Microsoft" 2. A device code will be displayed 3. Visit the URL shown and enter the code @@ -92,6 +91,7 @@ When you first launch DropOut, you'll need to: 5. Return to DropOut - you'll be logged in automatically **Offline Login:** + 1. Click "Offline Mode" 2. Enter a username 3. Click "Create Account" @@ -117,23 +117,23 @@ When you first launch DropOut, you'll need to: ## Next Steps - - - - @@ -142,12 +142,14 @@ When you first launch DropOut, you'll need to: ## System Requirements ### Minimum Requirements + - **OS**: Windows 10+, macOS 11+, or Linux (Debian-based) - **RAM**: 4GB (8GB recommended for modded Minecraft) - **Storage**: 2GB for launcher + game files - **Java**: Auto-installed by DropOut if not found ### Recommended Requirements + - **OS**: Latest stable version of your OS - **RAM**: 16GB for optimal performance with mods - **Storage**: 10GB+ for multiple versions and mods @@ -156,6 +158,7 @@ When you first launch DropOut, you'll need to: ## Getting Help If you encounter issues: + - Check the [Troubleshooting Guide](/docs/troubleshooting) - Report bugs on [GitHub Issues](https://github.com/HsiangNianian/DropOut/issues) - Join our community discussions diff --git a/packages/docs/content/zh/development/architecture.mdx b/packages/docs/content/zh/development/architecture.mdx index 6a2a2df..b3809d0 100644 --- a/packages/docs/content/zh/development/architecture.mdx +++ b/packages/docs/content/zh/development/architecture.mdx @@ -10,18 +10,21 @@ DropOut 采用现代技术栈构建,旨在实现高性能、安全性和跨平 ## 技术栈 ### 后端(Rust) + - **框架**: Tauri v2 - **语言**: Rust(Edition 2021) - **异步运行时**: Tokio - **HTTP 客户端**: reqwest with native-tls ### 前端(Svelte) + - **框架**: Svelte 5(with runes) - **样式**: Tailwind CSS 4 - **构建工具**: Vite with Rolldown - **包管理器**: pnpm ### 文档 + - **框架**: Fumadocs with React Router v7 - **内容**: MDX 文件 - **样式**: Tailwind CSS 4 @@ -84,7 +87,7 @@ DropOut 使用 **Svelte 5 runes** 进行响应式状态管理: export class AuthState { currentAccount = $state(null); // 响应式 isLoginModalOpen = $state(false); - + $effect(() => { // 副作用 // 依赖变化时自动运行 }); @@ -92,6 +95,7 @@ export class AuthState { ``` **关键 Stores:** + - `auth.svelte.ts`: 认证状态和登录流程 - `settings.svelte.ts`: 启动器设置和 Java 检测 - `game.svelte.ts`: 游戏运行状态和日志 @@ -101,6 +105,7 @@ export class AuthState { ### 后端架构 #### 命令模式 + 所有 Tauri 命令遵循此结构: ```rust @@ -119,12 +124,14 @@ async fn command_name( #### 事件通信 **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" }); @@ -133,12 +140,14 @@ 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 授权 @@ -146,6 +155,7 @@ const result = await invoke("start_game", { versionId: "1.20.4" }); 5. 配置文件获取 #### 下载器(`core/downloader.rs`) + - **并发下载**: 可配置线程池 - **断点续传**: `.part` 和 `.part.meta` 文件 - **多段下载**: 大文件分割成块 @@ -153,6 +163,7 @@ const result = await invoke("start_game", { versionId: "1.20.4" }); - **进度跟踪**: 实时事件到前端 #### Java 管理(`core/java.rs`) + - **自动检测**: 扫描系统路径 - **Adoptium 集成**: 按需下载 JDK/JRE - **目录缓存**: 版本列表 24 小时缓存 @@ -160,22 +171,26 @@ const result = await invoke("start_game", { versionId: "1.20.4" }); - **取消**: 下载取消的原子标志 #### 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 解析和验证 @@ -249,16 +264,19 @@ const result = await invoke("start_game", { versionId: "1.20.4" }); ## 平台特定考虑 ### Linux + - 使用 GTK WebView(`webkit2gtk`) - 从 `/usr/lib/jvm` 系统 Java 检测 - 桌面文件集成 ### macOS + - 使用系统 WebKit - 应用程序包结构 - 钥匙串集成用于安全存储 ### Windows + - 使用 WebView2 运行时 - 注册表 Java 检测 - MSI 安装程序支持 diff --git a/packages/docs/content/zh/development/guide.mdx b/packages/docs/content/zh/development/index.mdx similarity index 98% rename from packages/docs/content/zh/development/guide.mdx rename to packages/docs/content/zh/development/index.mdx index 6ba5b1d..f562196 100644 --- a/packages/docs/content/zh/development/guide.mdx +++ b/packages/docs/content/zh/development/index.mdx @@ -12,12 +12,14 @@ description: 从源代码构建、测试和贡献 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 @@ -29,6 +31,7 @@ description: 从源代码构建、测试和贡献 DropOut 按照你的平台参考 [Tauri 前置要求](https://v2.tauri.app/start/prerequisites/): **Linux (Debian/Ubuntu):** + ```bash sudo apt update sudo apt install libwebkit2gtk-4.1-dev \ @@ -42,6 +45,7 @@ description: 从源代码构建、测试和贡献 DropOut ``` **macOS:** + ```bash xcode-select --install ``` @@ -62,6 +66,7 @@ cd DropOut ### 安装依赖 **前端依赖:** + ```bash cd packages/ui pnpm install @@ -69,6 +74,7 @@ cd ../.. ``` **文档依赖:** + ```bash cd packages/docs pnpm install @@ -84,6 +90,7 @@ cargo tauri dev ``` 这将: + 1. 启动前端开发服务器(Vite 在 5173 端口) 2. 编译 Rust 后端 3. 打开 Tauri 窗口 @@ -91,6 +98,7 @@ cargo tauri dev 5. 在 Rust 文件更改时重新编译 **终端输出:** + - 来自 Vite 的前端日志 - Rust 标准输出/标准错误 - 编译状态 @@ -104,6 +112,7 @@ cargo tauri build ``` **输出位置:** + - **Linux**: `src-tauri/target/release/bundle/` - `.deb` 软件包 - `.AppImage` 包 @@ -152,22 +161,26 @@ DropOut/ ### 前端开发 **启动开发服务器:** + ```bash cd packages/ui pnpm dev ``` **类型检查:** + ```bash pnpm check ``` **代码检查:** + ```bash pnpm lint ``` **格式化代码:** + ```bash pnpm format ``` @@ -175,21 +188,25 @@ pnpm format ### 后端开发 **运行 Rust 测试:** + ```bash cargo test ``` **检查代码:** + ```bash cargo check ``` **格式化代码:** + ```bash cargo fmt ``` **代码检查:** + ```bash cargo clippy ``` @@ -197,17 +214,20 @@ cargo clippy ### 文档开发 **启动文档开发服务器:** + ```bash cd packages/docs pnpm dev ``` **构建文档:** + ```bash pnpm build ``` **类型检查:** + ```bash pnpm types:check ``` @@ -217,6 +237,7 @@ pnpm types:check ### Rust 遵循标准 Rust 约定: + - 使用 `cargo fmt` 格式化 - 使用 `cargo clippy` 检查 - 编写文档注释 (`///`) @@ -224,6 +245,7 @@ pnpm types:check - 对 I/O 使用 async/await **示例:** + ```rust /// Starts the Microsoft authentication device flow #[tauri::command] @@ -231,7 +253,7 @@ async fn start_microsoft_login( window: Window, ) -> Result { emit_log!(window, "Starting Microsoft login..."); - + start_device_flow() .await .map_err(|e| e.to_string()) @@ -241,20 +263,22 @@ async fn start_microsoft_login( ### TypeScript/Svelte 遵循项目约定: + - 使用 Svelte 5 runes (`$state`, `$effect`) - 优先使用 TypeScript 而非 JavaScript - 使用 Biome 进行格式化和检查 - 遵循组件结构 **示例:** + ```typescript // stores/auth.svelte.ts export class AuthState { currentAccount = $state(null); isLoginModalOpen = $state(false); - + async login(username: string) { - const account = await invoke('offline_login', { username }); + const account = await invoke("offline_login", { username }); this.currentAccount = account; } } @@ -265,6 +289,7 @@ export class AuthState { ### 单元测试 **Rust:** + ```rust #[cfg(test)] mod tests { @@ -279,6 +304,7 @@ mod tests { ``` **运行:** + ```bash cargo test ``` @@ -286,6 +312,7 @@ cargo test ### 集成测试 测试完整应用程序: + 1. 以开发模式构建:`cargo tauri dev` 2. 手动测试功能 3. 检查控制台错误 @@ -294,6 +321,7 @@ cargo test ### CI 测试 GitHub Actions 在以下平台运行测试: + - Ubuntu(最新版) - Arch Linux(Wayland) - Windows(最新版) @@ -313,12 +341,14 @@ GitHub Actions 在以下平台运行测试: ### 后端调试 **打印调试:** + ```rust emit_log!(window, format!("Debug: {}", value)); println!("Debug: {}", value); ``` **Rust 调试器:** + ```bash # 安装 rust-lldb 或 rust-gdb cargo install rust-gdb @@ -330,12 +360,14 @@ rust-gdb target/debug/dropout ### 日志 **前端:** + ```typescript console.log("Info message"); console.error("Error message"); ``` **后端:** + ```rust emit_log!(window, "Status update"); eprintln!("Error: {}", error); @@ -367,6 +399,7 @@ eprintln!("Error: {}", error); 遵循 [约定式提交](https://www.conventionalcommits.org/): **格式:** + ``` [scope]: @@ -376,6 +409,7 @@ eprintln!("Error: {}", error); ``` **类型:** + - `feat`: 新功能 - `fix`: 错误修复 - `docs`: 文档 @@ -386,6 +420,7 @@ eprintln!("Error: {}", error); - `chore`: 维护 **示例:** + ```bash feat(auth): add offline authentication support fix(java): resolve detection on Windows @@ -396,6 +431,7 @@ refactor(download): simplify progress tracking ### Pull Request 指南 **提交前:** + - [ ] 代码遵循风格指南 - [ ] 测试在本地通过 - [ ] 必要时更新文档 @@ -403,6 +439,7 @@ refactor(download): simplify progress tracking - [ ] 提交消息清晰 **PR 描述:** + - 解释做了什么以及为什么 - 链接相关 issue - 列出破坏性更改 @@ -411,6 +448,7 @@ refactor(download): simplify progress tracking ### 代码审查 维护者将审查你的 PR: + - 代码质量和风格 - 测试覆盖率 - 文档 @@ -424,6 +462,7 @@ refactor(download): simplify progress tracking ### 添加 Tauri 命令 1. **在 `main.rs` 中定义命令:** + ```rust #[tauri::command] async fn my_command(param: String) -> Result { @@ -432,6 +471,7 @@ refactor(download): simplify progress tracking ``` 2. **在构建器中注册:** + ```rust .invoke_handler(tauri::generate_handler![ my_command, @@ -441,12 +481,13 @@ refactor(download): simplify progress tracking 3. **从前端调用:** ```typescript - const result = await invoke('my_command', { param: 'value' }); + const result = await invoke("my_command", { param: "value" }); ``` ### 添加 UI 组件 1. **创建组件文件:** + ```svelte