diff options
| author | 2026-02-27 17:18:25 +0800 | |
|---|---|---|
| committer | 2026-02-27 17:18:25 +0800 | |
| commit | 81a62402ef6f8900ff092366121a9b7a4263ba52 (patch) | |
| tree | 119109c62331d4d26612e2df7726cee82d1871f5 /packages | |
| 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')
38 files changed, 1404 insertions, 1171 deletions
diff --git a/packages/docs/app/components/mermaid.tsx b/packages/docs/app/components/mermaid.tsx new file mode 100644 index 0000000..bb25f2d --- /dev/null +++ b/packages/docs/app/components/mermaid.tsx @@ -0,0 +1,29 @@ +'use client'; + +import { useEffect, useRef } from 'react'; +import mermaid from 'mermaid'; + +mermaid.initialize({ + startOnLoad: false, + theme: 'default', +}); + +export function Mermaid({ chart }: { chart: string }) { + const ref = useRef<HTMLDivElement>(null); + + useEffect(() => { + if (ref.current) { + mermaid.run({ + nodes: [ref.current], + }); + } + }, [chart]); + + return ( + <div className="not-prose my-6"> + <div ref={ref} className="mermaid"> + {chart} + </div> + </div> + ); +} diff --git a/packages/docs/app/docs/page.tsx b/packages/docs/app/docs/page.tsx index a9e3433..49ad005 100644 --- a/packages/docs/app/docs/page.tsx +++ b/packages/docs/app/docs/page.tsx @@ -8,20 +8,21 @@ import { i18n } from '@/lib/i18n'; import { baseOptions } from '@/lib/layout.shared'; import { useFumadocsLoader } from 'fumadocs-core/source/client'; import browserCollections from 'fumadocs-mdx:collections/browser'; +import { Mermaid } from '@/components/mermaid'; 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'); - + // 获取文档路径 slugs const slugs = params['*']?.split('/').filter((v) => v.length > 0) || []; - + const page = source.getPage(slugs, lang); - + if (!page) { throw new Response('Not found', { status: 404 }); } @@ -37,10 +38,23 @@ const clientLoader = browserCollections.docs.createClientLoader({ component({ toc, frontmatter, default: Mdx }) { return ( <DocsPage toc={toc}> - <DocsTitle>{frontmatter.title}</DocsTitle> - <DocsDescription>{frontmatter.description}</DocsDescription> + {/* 老王说不要这个 */} + {/* <DocsTitle>{frontmatter.title}</DocsTitle> + <DocsDescription>{frontmatter.description}</DocsDescription> */} <DocsBody> - <Mdx components={{ ...defaultMdxComponents, Card, Cards }} /> + <Mdx + components={{ + ...defaultMdxComponents, + Card: (props: React.ComponentProps<typeof Card>) => ( + <Card + {...props} + className={`border-blue-600/20 hover:border-blue-600/50 transition-colors ${props.className || ''}`} + /> + ), + Cards, + Mermaid + }} + /> </DocsBody> </DocsPage> ); 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 66b5333..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: [ @@ -107,10 +107,10 @@ export default function Home({ params }: Route.ComponentProps) { {t.hero.start} </a> <a - className="bg-fd-secondary hover:bg-fd-secondary/80 text-fd-secondary-foreground font-semibold rounded-lg px-6 py-3 transition-colors cursor-pointer" - href={`${localePrefix}/docs/features`} + className="bg-fd-secondary hover:bg-fd-secondary/80 text-fd-secondary-foreground font-semibold rounded-lg px-6 py-3 transition-colors cursor-pointer border border-blue-600/50" + href={`${localePrefix}/docs/development`} > - {t.hero.features} + {t.hero.development} </a> </div> </div> @@ -129,7 +129,7 @@ export default function Home({ params }: Route.ComponentProps) { {/* Features Grid */} <div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6 mb-16"> {t.features.items.map((item, i) => ( - <div key={i} className="p-6 rounded-lg border border-fd-border bg-fd-card"> + <div key={i} className="p-6 rounded-lg border border-blue-600/20 bg-fd-card hover:border-blue-600/50 transition-colors"> <h3 className="font-semibold text-lg mb-2">{item.title}</h3> <p className="text-sm text-fd-muted-foreground"> {item.desc} @@ -162,7 +162,7 @@ export default function Home({ params }: Route.ComponentProps) { </p> <a className="inline-block bg-blue-600 hover:bg-blue-700 text-white font-semibold rounded-lg px-8 py-3 transition-colors" - href={`${localePrefix}/docs/getting-started`} + href={`${localePrefix}/docs/manual/getting-started`} > {t.cta.button} </a> diff --git a/packages/docs/content/en/architecture.mdx b/packages/docs/content/en/development/architecture.mdx index 5f55c5e..6d59ab7 100644 --- a/packages/docs/content/en/architecture.mdx +++ b/packages/docs/content/en/development/architecture.mdx @@ -15,10 +15,12 @@ DropOut is built with a modern tech stack designed for performance, security, an - **Async Runtime**: Tokio - **HTTP Client**: reqwest with native-tls -### Frontend (Svelte) -- **Framework**: Svelte 5 (with runes) +### Frontend (React) +- **Framework**: React 19 +- **State Management**: Zustand +- **Router**: React Router v7 - **Styling**: Tailwind CSS 4 -- **Build Tool**: Vite with Rolldown +- **Build Tool**: Vite (with Rolldown) - **Package Manager**: pnpm ### Documentation @@ -28,75 +30,85 @@ DropOut is built with a modern tech stack designed for performance, security, an ## System Architecture -``` -┌─────────────────────────────────────────────────────────┐ -│ Frontend (Svelte 5) │ -│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ │ -│ │ Stores │ │Components│ │ UI Views │ │Particles│ │ -│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬────┘ │ -│ │ │ │ │ │ -│ └─────────────┴─────────────┴──────────────┘ │ -│ │ │ -│ Tauri Commands │ -│ Events/Emitters │ -└──────────────────────────┬──────────────────────────────┘ - │ -┌──────────────────────────┴──────────────────────────────┐ -│ Backend (Rust/Tauri) │ -│ ┌─────────────────────────────────────────────────┐ │ -│ │ main.rs (Commands) │ │ -│ └──────────────┬──────────────────────────────────┘ │ -│ │ │ -│ ┌──────────────┴───────────────────────────────┐ │ -│ │ Core Modules │ │ -│ │ ┌──────┐ ┌────────┐ ┌──────┐ ┌──────────┐ │ │ -│ │ │ Auth │ │Download│ │ Java │ │ Instance │ │ │ -│ │ └──────┘ └────────┘ └──────┘ └──────────┘ │ │ -│ │ ┌──────┐ ┌────────┐ ┌──────┐ ┌──────────┐ │ │ -│ │ │Fabric│ │ Forge │ │Config│ │Manifest │ │ │ -│ │ └──────┘ └────────┘ └──────┘ └──────────┘ │ │ -│ └──────────────────────────────────────────────┘ │ -│ │ -│ ┌─────────────────────────────────────────────────┐ │ -│ │ Utils & Helpers │ │ -│ │ • ZIP extraction • Path utilities │ │ -│ └─────────────────────────────────────────────────┘ │ -└──────────────────────────┬──────────────────────────────┘ - │ - External APIs - │ - ┌──────────────────┼──────────────────┐ - │ │ │ - ┌─────┴────┐ ┌──────┴─────┐ ┌──────┴─────┐ - │ Mojang │ │ Fabric │ │ Forge │ - │ APIs │ │ Meta │ │ Maven │ - └──────────┘ └────────────┘ └────────────┘ +```mermaid +graph TB + subgraph Frontend["Frontend (React 19)"] + direction LR + Stores[Zustand Stores] ~~~ Components[Components] ~~~ Pages[Pages] ~~~ Router[Router] ~~~ Particles[Particle Background] + end + + subgraph TauriLayer["Tauri Communication"] + direction LR + Commands[Commands] ~~~ Events[Events/Emitters] + end + + subgraph Backend["Backend (Rust/Tauri)"] + direction TB + MainRS[main.rs Command Handler] + + subgraph CoreModules["Core Modules"] + direction LR + Auth[Auth] ~~~ Download[Download] ~~~ Java[Java] ~~~ Instance[Instance] + Fabric[Fabric] ~~~ Forge[Forge] ~~~ Config[Config] ~~~ Manifest[Manifest] + Auth ~~~ Fabric + end + + subgraph Utils["Utils & Helpers"] + direction LR + ZipExtract[ZIP Extract] ~~~ PathUtils[Path Utils] + end + + MainRS --> CoreModules + CoreModules --> Utils + end + + subgraph ExternalAPIs["External APIs"] + 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 ``` ## Core Components ### Frontend State Management -DropOut uses **Svelte 5 runes** for reactive state management: +DropOut uses **Zustand** for global state management: ```typescript -// stores/auth.svelte.ts -export class AuthState { - currentAccount = $state<Account | null>(null); // Reactive - isLoginModalOpen = $state(false); - - $effect(() => { // Side effects - // Auto-runs when dependencies change - }); +// 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 }), + // ... +})); ``` **Key Stores:** -- `auth.svelte.ts`: Authentication state and login flow -- `settings.svelte.ts`: Launcher settings and Java detection -- `game.svelte.ts`: Game running state and logs -- `instances.svelte.ts`: Instance management -- `ui.svelte.ts`: UI state (toasts, modals, active view) +- `models/auth.ts`: Authentication state and login flow +- `models/settings.ts`: Launcher settings and Java detection +- `models/instance.ts`: Instance management +- `stores/game-store.ts`: Game running state status +- `stores/logs-store.ts`: Game log stream management +- `stores/ui-store.ts`: UI state (toasts, modals, active view) ### Backend Architecture @@ -213,7 +225,7 @@ const result = await invoke("start_game", { versionId: "1.20.4" }); ### Game Launch Sequence 1. **Frontend**: User clicks "Launch Game" -2. **Command**: `start_game(version_id)` invoked +2. **Command**: `start_game(instance_id, version_id)` invoked 3. **Backend Processing**: - Load version JSON (with inheritance) - Resolve all libraries diff --git a/packages/docs/content/en/development.mdx b/packages/docs/content/en/development/guide.mdx index 8ff2906..8ff2906 100644 --- a/packages/docs/content/en/development.mdx +++ b/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=<uhs>;<xsts_token>` 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<JavaInstallation> { + 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<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. 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<String, String> { + 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<T, String>`, 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<Account | null>(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 +<!-- App.svelte --> +<script> + import { uiState } from "./stores/ui.svelte"; +</script> + +{#if uiState.activeView === "home"} + <HomeView /> +{:else if uiState.activeView === "settings"} + <SettingsView /> +{/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/authentication.mdx b/packages/docs/content/en/features/authentication.mdx deleted file mode 100644 index b6fc4ba..0000000 --- a/packages/docs/content/en/features/authentication.mdx +++ /dev/null @@ -1,266 +0,0 @@ ---- -title: Authentication -description: Microsoft OAuth and offline authentication in DropOut ---- - -# Authentication - -DropOut supports two authentication methods: Microsoft Account (for official Minecraft) and Offline Mode (for testing and offline play). - -## Microsoft Authentication - -### Overview - -DropOut uses the **Device Code Flow** for Microsoft authentication, which: -- Doesn't require a redirect URL (no browser integration) -- Works on any device with a browser -- Provides a simple code-based authentication -- Fully compliant with Microsoft OAuth 2.0 - -### Authentication Process - -The authentication chain consists of multiple steps: - -1. **Device Code** → User authorization -2. **MS Token** → Access + refresh tokens -3. **Xbox Live** → Xbox token + UHS -4. **XSTS** → Security token -5. **Minecraft** → Game access token -6. **Profile** → Username + UUID - -#### Step 1: Device Code Request -1. Click "Login with Microsoft" -2. DropOut requests a device code from Microsoft -3. You receive: - - User code (e.g., `A1B2-C3D4`) - - Verification URL (usually `https://microsoft.com/link`) - - Device code (used internally) - -#### Step 2: User Authorization -1. Visit the verification URL in any browser -2. Enter the user code -3. Sign in with your Microsoft account -4. Authorize DropOut to access your Minecraft profile - -#### Step 3: Token Exchange -- DropOut polls Microsoft for authorization completion -- Once authorized, receives an access token and refresh token -- Refresh token is stored for future logins - -#### Step 4: Xbox Live Authentication -- Microsoft token is exchanged for Xbox Live token -- Retrieves User Hash (UHS) for next step - -#### Step 5: XSTS Authorization -- Xbox Live token is used to get XSTS token -- This token is specific to Minecraft services - -#### Step 6: Minecraft Login -- XSTS token is exchanged for Minecraft access token -- Uses endpoint: `/launcher/login` - -#### Step 7: Profile Fetching -- Retrieves your Minecraft username -- Fetches your UUID -- Checks if you own Minecraft - -### Token Management - -**Access Token:** -- Short-lived (typically 1 hour) -- Used for game authentication -- Automatically refreshed when expired - -**Refresh Token:** -- Long-lived (typically 90 days) -- Stored securely in `accounts.json` -- Used to obtain new access tokens - -**Auto-refresh:** -```rust -// Automatic refresh when token expires -if account.expires_at < current_time { - refresh_full_auth(&account).await?; -} -``` - -### Security Considerations - -- Tokens are stored in platform-specific app data directory -- HTTPS only for all API calls -- No credentials stored (only tokens) -- User-Agent header required (bypasses MS WAF) - -### Troubleshooting Microsoft Login - -**"Device code expired"** -- Codes expire after 15 minutes -- Start the login process again - -**"Authorization pending"** -- Normal during the waiting phase -- Complete authorization in the browser - -**"Invalid token"** -- Token may have expired -- Log out and log back in - -**"You don't own Minecraft"** -- Verify your Microsoft account owns Minecraft Java Edition -- Check at https://www.minecraft.net/profile - -## Offline Authentication - -### Overview - -Offline mode creates a local account that doesn't require internet connectivity or a Microsoft account. This is useful for: -- Testing and development -- Playing without internet -- LAN multiplayer -- Mod development - -### Creating an Offline Account - -1. Click "Offline Mode" in the login screen -2. Enter a username (3-16 characters) -3. Click "Create Account" - -### How It Works - -**UUID Generation:** -```rust -// Deterministic UUID v3 from username -let uuid = generate_offline_uuid(&username); -``` - -- Uses UUID v3 (namespace-based) -- Deterministic: same username = same UUID -- No network requests - -**Authentication:** -- Returns `"null"` as access token -- Minecraft accepts null token in offline mode -- Username and UUID stored locally - -### Limitations - -- Cannot join online servers -- No skin support -- No cape support -- No Microsoft account features - -### Use Cases - -**Development:** -```bash -# Testing mod development -cargo tauri dev -# Use offline mode to test quickly -``` - -**LAN Play:** -- Join LAN worlds without authentication -- Host LAN worlds - -**Offline Play:** -- Singleplayer without internet -- No authentication required - -## Account Management - -### Switching Accounts - -Currently, DropOut supports one active account at a time. Multi-account support is planned. - -**To switch accounts:** -1. Log out of current account -2. Log in with new account - -### Account Storage - -Accounts are stored in `accounts.json`: - -```json -{ - "current_account_id": "uuid-here", - "accounts": [ - { - "id": "uuid", - "type": "Microsoft", - "username": "PlayerName", - "access_token": "...", - "refresh_token": "...", - "expires_at": 1234567890 - } - ] -} -``` - -### Deleting Accounts - -To remove an account: -1. Open Settings -2. Navigate to Accounts -3. Click "Log Out" -4. Or manually delete `accounts.json` - -## API Reference - -### Tauri Commands - -**Start Microsoft Login:** -```typescript -const { user_code, verification_uri } = await invoke('start_microsoft_login'); -``` - -**Complete Microsoft Login:** -```typescript -const account = await invoke('complete_microsoft_login', { deviceCode }); -``` - -**Offline Login:** -```typescript -const account = await invoke('offline_login', { username: 'Player' }); -``` - -**Logout:** -```typescript -await invoke('logout'); -``` - -**Get Current Account:** -```typescript -const account = await invoke('get_current_account'); -``` - -### Events - -**Authentication Status:** -```typescript -listen('auth-status', (event) => { - console.log(event.payload); // "logged_in" | "logged_out" -}); -``` - -## Best Practices - -### For Players - -1. **Use Microsoft Account** for official servers -2. **Keep tokens secure** - don't share accounts.json -3. **Refresh tokens regularly** by logging in -4. **Use offline mode** only for testing - -### For Developers - -1. **Handle token expiration** gracefully -2. **Implement retry logic** for network failures -3. **Cache account data** to reduce API calls -4. **Validate tokens** before game launch - -## Future Enhancements - -- **Multi-account support**: Switch between accounts easily -- **Account profiles**: Save per-account settings -- **Auto-login**: Remember last account -- **Token encryption**: Enhanced security for stored tokens diff --git a/packages/docs/content/en/manual/features/authentication.mdx b/packages/docs/content/en/manual/features/authentication.mdx new file mode 100644 index 0000000..f7a1f69 --- /dev/null +++ b/packages/docs/content/en/manual/features/authentication.mdx @@ -0,0 +1,131 @@ +--- +title: Authentication +description: Microsoft OAuth and offline authentication in DropOut +--- + +# Authentication + +DropOut supports two authentication methods: Microsoft Account (for official Minecraft) and Offline Mode (for testing and offline play). + +## Microsoft Authentication + +### Overview + +DropOut uses the **Device Code Flow** for Microsoft authentication, featuring: +- No redirect URL required (no browser integration needed) +- Works on any device with a browser +- Provides simple code-based authentication +- Fully compliant with Microsoft OAuth 2.0 standards + +### Authentication Process + +The authentication chain consists of multiple steps. DropOut automatically handles these complex exchange processes, including interactions with Microsoft, Xbox Live, and Minecraft services. If you are interested in detailed API implementation, please refer to [Internal Implementation](/docs/development/implementation#1-authentication-system). + +### Token Management + +**Access Token:** +- Short-lived (typically 1 hour) +- Used for game authentication +- Automatically refreshed when expired + +**Refresh Token:** +- Long-lived (typically 90 days) +- Stored securely in `accounts.json` +- Used to obtain new access tokens + +**Auto-refresh:** +When the token expires, DropOut attempts to automatically update your login status using the refresh token when you launch the game, ensuring a seamless start. + +### Security Considerations + +- Tokens are stored in the platform-specific application data directory +- All API calls use HTTPS only +- No credentials stored (only tokens) +- User-Agent header required (bypasses MS WAF) + +### Troubleshooting Microsoft Login + +**"Device code expired"** +- The code expires after 15 minutes +- Restart the login process + +**"Authorization pending"** +- Normal during the waiting phase +- Complete authorization in your browser + +**"Invalid token"** +- The token may have expired +- Log out and log back in (use "Switch Account" to clear token) + +**"You don't own Minecraft"** +- Verify your Microsoft account owns Minecraft: Java Edition +- Check at https://www.minecraft.net/profile + +## Offline Authentication + +### Overview + +Offline mode creates a local account that does not require an internet connection or a Microsoft account. This is useful for: +- Testing and development +- Playing without internet +- LAN multiplayer +- Mod development + +### Creating an Offline Account + +1. Click "Offline Mode" on the login screen +2. Enter a username (3-16 characters) +3. Click "Create Account" + +### How It Works + +**UUID Generation:** +Offline mode uses a deterministic UUID generation algorithm based on the username (UUID v3). This means the same username will always get the same UUID in the same launcher instance, maintaining single-player save consistency. + +- Deterministic: Same username = Same UUID +- No network requests needed + +**Authentication:** +- Returns `"null"` as the access token +- Minecraft accepts empty tokens in offline mode +- Username and UUID are stored locally + +### Limitations + +- Cannot join online servers (online-mode=true) +- No custom skins support +- No capes support +- Cannot use Microsoft account features + +## Account Management + +### Switching Accounts + +Currently, DropOut supports only one active account at a time. Multi-account support is planned. + +**Steps to switch accounts:** +1. Log out of the current account +2. Log in with the new account + +### Account Storage + +Account data is stored in `accounts.json` within the application folder. This file contains encrypted tokens, expiration times, and basic profile information for logged-in accounts. + +### Deleting an Account + +Steps to delete an account: +1. Open Settings +2. Navigate to Account +3. Click "Log out" +4. Or manually delete `accounts.json` + +## API Reference + +For low-level implementation of authentication, OAuth 2.0 flow details, and related Tauri command interfaces, please refer to the development documentation: [Implementation Details: Authentication](/docs/development/implementation#1-authentication-system). + +## Best Practices + +1. **Use Microsoft Account for Official Servers**: To join official servers and use official skins, always use a Microsoft account. +2. **Keep Tokens Secure**: Do not share the `accounts.json` file or its contents with others, as it contains your login credentials. +3. **Refresh Tokens Regularly**: Long-unused offline accounts or expired Microsoft tokens can be refreshed by re-logging in or launching the game. +4. **Use Offline Mode Only for Testing**: Offline mode does not support skins and some multiplayer features. diff --git a/packages/docs/content/en/features/index.mdx b/packages/docs/content/en/manual/features/index.mdx index 3a463d0..3a463d0 100644 --- a/packages/docs/content/en/features/index.mdx +++ b/packages/docs/content/en/manual/features/index.mdx diff --git a/packages/docs/content/en/features/java.mdx b/packages/docs/content/en/manual/features/java.mdx index 21b95a9..21b95a9 100644 --- a/packages/docs/content/en/features/java.mdx +++ b/packages/docs/content/en/manual/features/java.mdx diff --git a/packages/docs/content/en/features/meta.json b/packages/docs/content/en/manual/features/meta.json index 4725321..4725321 100644 --- a/packages/docs/content/en/features/meta.json +++ b/packages/docs/content/en/manual/features/meta.json diff --git a/packages/docs/content/en/features/mod-loaders.mdx b/packages/docs/content/en/manual/features/mod-loaders.mdx index d6fdf4f..8fdf019 100644 --- a/packages/docs/content/en/features/mod-loaders.mdx +++ b/packages/docs/content/en/manual/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:<version>` -- `net.minecraftforge:fmlloader:<version>` -- `org.ow2.asm:asm:<version>` +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/en/getting-started.mdx b/packages/docs/content/en/manual/getting-started.mdx index 5219f40..c172289 100644 --- a/packages/docs/content/en/getting-started.mdx +++ b/packages/docs/content/en/manual/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 <Cards> - <Card - title="Microsoft Account" - description="Login with your official Minecraft account" - /> - <Card - title="Offline Mode" - description="Create a local profile for offline play" - /> + <Card title="Microsoft Account" description="Login with your official Minecraft account" /> + <Card title="Offline Mode" description="Create a local profile for offline play" /> </Cards> **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 <Cards> - <Card - title="Features" - href="/docs/features" + <Card + title="Features" + href="/docs/manual/features" description="Learn about all the features DropOut offers" /> - <Card - title="Instances" - href="/docs/features/instances" + <Card + title="Instances" + href="/docs/manual/features/instances" description="Create isolated game environments" /> - <Card - title="Mod Loaders" - href="/docs/features/mod-loaders" + <Card + title="Mod Loaders" + href="/docs/manual/features/mod-loaders" description="Install and manage Fabric and Forge" /> - <Card - title="Troubleshooting" + <Card + title="Troubleshooting" href="/docs/troubleshooting" description="Common issues and solutions" /> @@ -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/en/index.mdx b/packages/docs/content/en/manual/index.mdx index 9dee19f..9dee19f 100644 --- a/packages/docs/content/en/index.mdx +++ b/packages/docs/content/en/manual/index.mdx diff --git a/packages/docs/content/en/manual/meta.json b/packages/docs/content/en/manual/meta.json new file mode 100644 index 0000000..38506c1 --- /dev/null +++ b/packages/docs/content/en/manual/meta.json @@ -0,0 +1,9 @@ +{ + "title": "User Manual", + "pages": [ + "index", + "getting-started", + "features", + "troubleshooting" + ] +} diff --git a/packages/docs/content/en/troubleshooting.mdx b/packages/docs/content/en/manual/troubleshooting.mdx index 6d97819..6d97819 100644 --- a/packages/docs/content/en/troubleshooting.mdx +++ b/packages/docs/content/en/manual/troubleshooting.mdx diff --git a/packages/docs/content/en/meta.json b/packages/docs/content/en/meta.json index 75bf27a..a877cab 100644 --- a/packages/docs/content/en/meta.json +++ b/packages/docs/content/en/meta.json @@ -1,11 +1,7 @@ { "title": "Documentation", "pages": [ - "index", - "getting-started", - "architecture", - "features", - "development", - "troubleshooting" + "manual", + "development" ] } diff --git a/packages/docs/content/zh/architecture.mdx b/packages/docs/content/zh/development/architecture.mdx index 6a2a2df..4f47115 100644 --- a/packages/docs/content/zh/architecture.mdx +++ b/packages/docs/content/zh/development/architecture.mdx @@ -10,97 +10,114 @@ DropOut 采用现代技术栈构建,旨在实现高性能、安全性和跨平 ## 技术栈 ### 后端(Rust) + - **框架**: Tauri v2 - **语言**: Rust(Edition 2021) - **异步运行时**: Tokio - **HTTP 客户端**: reqwest with native-tls -### 前端(Svelte) -- **框架**: Svelte 5(with runes) +### 前端(React) + +- **框架**: React 19 +- **状态管理**: Zustand +- **路由**: React Router v7 - **样式**: Tailwind CSS 4 -- **构建工具**: Vite with Rolldown +- **构建工具**: Vite (with Rolldown) - **包管理器**: pnpm ### 文档 + - **框架**: Fumadocs with React Router v7 - **内容**: MDX 文件 - **样式**: Tailwind CSS 4 ## 系统架构 -``` -┌─────────────────────────────────────────────────────────┐ -│ 前端(Svelte 5) │ -│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ │ -│ │ Stores │ │Components│ │ UI Views │ │Particles│ │ -│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬────┘ │ -│ │ │ │ │ │ -│ └─────────────┴─────────────┴──────────────┘ │ -│ │ │ -│ Tauri 命令 │ -│ 事件/发射器 │ -└──────────────────────────┬──────────────────────────────┘ - │ -┌──────────────────────────┴──────────────────────────────┐ -│ 后端(Rust/Tauri) │ -│ ┌─────────────────────────────────────────────────┐ │ -│ │ main.rs(命令) │ │ -│ └──────────────┬──────────────────────────────────┘ │ -│ │ │ -│ ┌──────────────┴───────────────────────────────┐ │ -│ │ 核心模块 │ │ -│ │ ┌──────┐ ┌────────┐ ┌──────┐ ┌──────────┐ │ │ -│ │ │ Auth │ │Download│ │ Java │ │ Instance │ │ │ -│ │ └──────┘ └────────┘ └──────┘ └──────────┘ │ │ -│ │ ┌──────┐ ┌────────┐ ┌──────┐ ┌──────────┐ │ │ -│ │ │Fabric│ │ Forge │ │Config│ │Manifest │ │ │ -│ │ └──────┘ └────────┘ └──────┘ └──────────┘ │ │ -│ └──────────────────────────────────────────────┘ │ -│ │ -│ ┌─────────────────────────────────────────────────┐ │ -│ │ 工具和辅助函数 │ │ -│ │ • ZIP 提取 • 路径工具 │ │ -│ └─────────────────────────────────────────────────┘ │ -└──────────────────────────┬──────────────────────────────┘ - │ - 外部 API - │ - ┌──────────────────┼──────────────────┐ - │ │ │ - ┌─────┴────┐ ┌──────┴─────┐ ┌──────┴─────┐ - │ Mojang │ │ Fabric │ │ Forge │ - │ APIs │ │ Meta │ │ Maven │ - └──────────┘ └────────────┘ └────────────┘ +```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 使用 **Svelte 5 runes** 进行响应式状态管理: +DropOut 使用 **Zustand** 进行全局状态管理: ```typescript -// stores/auth.svelte.ts -export class AuthState { - currentAccount = $state<Account | null>(null); // 响应式 - isLoginModalOpen = $state(false); - - $effect(() => { // 副作用 - // 依赖变化时自动运行 - }); +// 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:** -- `auth.svelte.ts`: 认证状态和登录流程 -- `settings.svelte.ts`: 启动器设置和 Java 检测 -- `game.svelte.ts`: 游戏运行状态和日志 -- `instances.svelte.ts`: 实例管理 -- `ui.svelte.ts`: UI 状态(提示、模态框、活动视图) + +- `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 @@ -119,12 +136,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 +152,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 +167,7 @@ const result = await invoke("start_game", { versionId: "1.20.4" }); 5. 配置文件获取 #### 下载器(`core/downloader.rs`) + - **并发下载**: 可配置线程池 - **断点续传**: `.part` 和 `.part.meta` 文件 - **多段下载**: 大文件分割成块 @@ -153,6 +175,7 @@ const result = await invoke("start_game", { versionId: "1.20.4" }); - **进度跟踪**: 实时事件到前端 #### Java 管理(`core/java.rs`) + - **自动检测**: 扫描系统路径 - **Adoptium 集成**: 按需下载 JDK/JRE - **目录缓存**: 版本列表 24 小时缓存 @@ -160,22 +183,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 解析和验证 @@ -213,7 +240,7 @@ const result = await invoke("start_game", { versionId: "1.20.4" }); ### 游戏启动序列 1. **前端**: 用户点击"启动游戏" -2. **命令**: 调用 `start_game(version_id)` +2. **命令**: 调用 `start_game(instance_id, version_id)` 3. **后端处理**: - 加载版本 JSON(带继承) - 解析所有库 @@ -249,16 +276,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/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.mdx b/packages/docs/content/zh/development/index.mdx index 6ba5b1d..f562196 100644 --- a/packages/docs/content/zh/development.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<DeviceCodeResponse, String> { 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<Account | null>(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/): **格式:** + ``` <type>[scope]: <description> @@ -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<String, String> { @@ -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 <!-- packages/ui/src/components/MyComponent.svelte --> <script lang="ts"> @@ -459,6 +500,7 @@ refactor(download): simplify progress tracking ``` 2. **导入并使用:** + ```svelte <script> import MyComponent from './components/MyComponent.svelte'; @@ -470,20 +512,22 @@ refactor(download): simplify progress tracking ### 添加 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'; @@ -499,18 +543,21 @@ refactor(download): simplify progress tracking ### 构建失败 **"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 @@ -519,15 +566,18 @@ rustup update ### 运行时问题 **"Failed to load dynamic library"** + - 重新构建:`cargo clean && cargo tauri dev` - 检查库路径 - 验证已安装依赖 **"CORS error"** + - 开发模式下正常 - Tauri 自动处理 CORS **"Hot reload not working"** + - 检查 Vite 配置 - 重启开发服务器 - 清除浏览器缓存 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" + ] +} diff --git a/packages/docs/content/zh/features/authentication.mdx b/packages/docs/content/zh/features/authentication.mdx deleted file mode 100644 index e83cc35..0000000 --- a/packages/docs/content/zh/features/authentication.mdx +++ /dev/null @@ -1,266 +0,0 @@ ---- -title: 身份验证 -description: DropOut 中的 Microsoft OAuth 和离线身份验证 ---- - -# 身份验证 - -DropOut 支持两种身份验证方法:Microsoft 账户(用于官方 Minecraft)和离线模式(用于测试和离线游玩)。 - -## Microsoft 身份验证 - -### 概述 - -DropOut 使用 **Device Code Flow** 进行 Microsoft 身份验证,具有以下特点: -- 无需重定向 URL(无需浏览器集成) -- 适用于任何拥有浏览器的设备 -- 提供简单的基于代码的身份验证 -- 完全符合 Microsoft OAuth 2.0 标准 - -### 身份验证流程 - -身份验证链包含多个步骤: - -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 - -### 令牌管理 - -**访问令牌:** -- 短期有效(通常为 1 小时) -- 用于游戏身份验证 -- 过期时自动刷新 - -**刷新令牌:** -- 长期有效(通常为 90 天) -- 安全存储在 `accounts.json` 中 -- 用于获取新的访问令牌 - -**自动刷新:** -```rust -// Automatic refresh when token expires -if account.expires_at < current_time { - refresh_full_auth(&account).await?; -} -``` - -### 安全考虑 - -- 令牌存储在平台特定的应用数据目录中 -- 所有 API 调用仅使用 HTTPS -- 不存储凭据(仅存储令牌) -- 需要 User-Agent 标头(绕过 MS WAF) - -### Microsoft 登录故障排除 - -**"Device code expired"(设备代码已过期)** -- 代码在 15 分钟后过期 -- 重新开始登录流程 - -**"Authorization pending"(授权待处理)** -- 在等待阶段很正常 -- 在浏览器中完成授权 - -**"Invalid token"(无效令牌)** -- 令牌可能已过期 -- 登出后重新登录 - -**"You don't own Minecraft"(您不拥有 Minecraft)** -- 验证您的 Microsoft 账户拥有 Minecraft Java Edition -- 在 https://www.minecraft.net/profile 检查 - -## 离线身份验证 - -### 概述 - -离线模式创建一个不需要互联网连接或 Microsoft 账户的本地账户。这对以下情况很有用: -- 测试和开发 -- 无网络游玩 -- LAN 多人游戏 -- Mod 开发 - -### 创建离线账户 - -1. 在登录屏幕单击"离线模式" -2. 输入用户名(3-16 个字符) -3. 单击"创建账户" - -### 工作原理 - -**UUID 生成:** -```rust -// Deterministic UUID v3 from username -let uuid = generate_offline_uuid(&username); -``` - -- 使用 UUID v3(基于命名空间) -- 确定性:相同的用户名 = 相同的 UUID -- 无需网络请求 - -**身份验证:** -- 返回 `"null"` 作为访问令牌 -- Minecraft 在离线模式下接受空令牌 -- 用户名和 UUID 本地存储 - -### 限制 - -- 无法加入在线服务器 -- 不支持皮肤 -- 不支持披风 -- 无法使用 Microsoft 账户功能 - -### 用例 - -**开发:** -```bash -# Testing mod development -cargo tauri dev -# Use offline mode to test quickly -``` - -**LAN 游玩:** -- 无需身份验证即可加入 LAN 世界 -- 托管 LAN 世界 - -**离线游玩:** -- 单人游戏无需网络 -- 无需身份验证 - -## 账户管理 - -### 切换账户 - -目前 DropOut 一次只支持一个活跃账户。多账户支持正在规划中。 - -**切换账户的步骤:** -1. 登出当前账户 -2. 使用新账户登录 - -### 账户存储 - -账户存储在 `accounts.json` 中: - -```json -{ - "current_account_id": "uuid-here", - "accounts": [ - { - "id": "uuid", - "type": "Microsoft", - "username": "PlayerName", - "access_token": "...", - "refresh_token": "...", - "expires_at": 1234567890 - } - ] -} -``` - -### 删除账户 - -删除账户的步骤: -1. 打开设置 -2. 导航到账户 -3. 单击"登出" -4. 或手动删除 `accounts.json` - -## 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" -}); -``` - -## 最佳实践 - -### 对于玩家 - -1. **对官方服务器使用 Microsoft 账户** -2. **保护令牌安全** - 不要分享 accounts.json -3. **定期刷新令牌** - 通过登录来刷新 -4. **仅在测试时使用离线模式** - -### 对于开发者 - -1. **优雅地处理令牌过期** -2. **为网络故障实现重试逻辑** -3. **缓存账户数据** 以减少 API 调用 -4. **在游戏启动前验证令牌** - -## 未来增强 - -- **多账户支持**:轻松在账户之间切换 -- **账户配置文件**:保存每个账户的设置 -- **自动登录**:记住最后一个账户 -- **令牌加密**:为存储的令牌增强安全性 diff --git a/packages/docs/content/zh/manual/features/authentication.mdx b/packages/docs/content/zh/manual/features/authentication.mdx new file mode 100644 index 0000000..cd5b622 --- /dev/null +++ b/packages/docs/content/zh/manual/features/authentication.mdx @@ -0,0 +1,131 @@ +--- +title: 身份验证 +description: DropOut 中的 Microsoft OAuth 和离线身份验证 +--- + +# 身份验证 + +DropOut 支持两种身份验证方法:Microsoft 账户(用于官方 Minecraft)和离线模式(用于测试和离线游玩)。 + +## Microsoft 身份验证 + +### 概述 + +DropOut 使用 **Device Code Flow** 进行 Microsoft 身份验证,具有以下特点: +- 无需重定向 URL(无需浏览器集成) +- 适用于任何拥有浏览器的设备 +- 提供简单的基于代码的身份验证 +- 完全符合 Microsoft OAuth 2.0 标准 + +### 身份验证流程 + +身份验证链包含多个步骤。DropOut 自动处理这些复杂的交换过程,包括与 Microsoft、Xbox Live 和 Minecraft 服务的交互。如果您对详细的 API 实现感兴趣,请参阅[内部实现](/docs/development/implementation#1-身份验证系统-authentication)。 + +### 令牌管理 + +**访问令牌:** +- 短期有效(通常为 1 小时) +- 用于游戏身份验证 +- 过期时自动刷新 + +**刷新令牌:** +- 长期有效(通常为 90 天) +- 安全存储在 `accounts.json` 中 +- 用于获取新的访问令牌 + +**自动刷新:** +令牌过期时,DropOut 会在您启动游戏时尝试使用刷新令牌自动更新您的登录状态,确保您可以无缝开始游玩。 + +### 安全考虑 + +- 令牌存储在平台特定的应用数据目录中 +- 所有 API 调用仅使用 HTTPS +- 不存储凭据(仅存储令牌) +- 需要 User-Agent 标头(绕过 MS WAF) + +### Microsoft 登录故障排除 + +**"Device code expired"(设备代码已过期)** +- 代码在 15 分钟后过期 +- 重新开始登录流程 + +**"Authorization pending"(授权待处理)** +- 在等待阶段很正常 +- 在浏览器中完成授权 + +**"Invalid token"(无效令牌)** +- 令牌可能已过期 +- 登出后重新登录 + +**"You don't own Minecraft"(您不拥有 Minecraft)** +- 验证您的 Microsoft 账户拥有 Minecraft Java Edition +- 在 https://www.minecraft.net/profile 检查 + +## 离线身份验证 + +### 概述 + +离线模式创建一个不需要互联网连接或 Microsoft 账户的本地账户。这对以下情况很有用: +- 测试和开发 +- 无网络游玩 +- LAN 多人游戏 +- Mod 开发 + +### 创建离线账户 + +1. 在登录屏幕单击"离线模式" +2. 输入用户名(3-16 个字符) +3. 单击"创建账户" + +### 工作原理 + +**UUID 生成:** +离线模式使用基于用户名的确定性 UUID 生成算法(UUID v3)。这意味着在同一个启动器实例中,相同的用户名始终会获得相同的 UUID,从而保持单人游戏存档的一致性。 + +- 确定性:相同的用户名 = 相同的 UUID +- 无需网络请求 + +**身份验证:** +- 返回 `"null"` 作为访问令牌 +- Minecraft 在离线模式下接受空令牌 +- 用户名和 UUID 本地存储 + +### 限制 + +- 无法加入在线服务器 +- 不支持皮肤 +- 不支持披风 +- 无法使用 Microsoft 账户功能 + +## 账户管理 + +### 切换账户 + +目前 DropOut 一次只支持一个活跃账户。多账户支持正在规划中。 + +**切换账户的步骤:** +1. 登出当前账户 +2. 使用新账户登录 + +### 账户存储 + +账户数据存储在应用文件夹的 `accounts.json` 中。该文件包含已登录账户的加密令牌、过期时间和基本的个人资料信息。 + +### 删除账户 + +删除账户的步骤: +1. 打开设置 +2. 导航到账户 +3. 单击"登出" +4. 或手动删除 `accounts.json` + +## API 参考 + +关于身份验证的底层实现、OAuth 2.0 流程细节以及相关的 Tauri 命令接口,请参考开发文档:[实现细节:身份验证](../development/implementation.mdx#1-身份验证系统-authentication)。 + +## 最佳实践 + +1. **对官方服务器使用 Microsoft 账户**:为了能够加入官方服务器并使用正版皮肤,请务必使用 Microsoft 账户。 +2. **保护令牌安全**:不要向他人分享 `accounts.json` 文件或其内容,因为其中包含您的登录凭据。 +3. **定期刷新令牌**:长时间未使用的离线账户或过期的 Microsoft 令牌可以通过重新登录或启动游戏来刷新。 +4. **仅在测试时使用离线模式**:离线模式不支持皮肤和部分多人游戏功能。 diff --git a/packages/docs/content/zh/features/index.mdx b/packages/docs/content/zh/manual/features/index.mdx index bb53ce2..bb53ce2 100644 --- a/packages/docs/content/zh/features/index.mdx +++ b/packages/docs/content/zh/manual/features/index.mdx diff --git a/packages/docs/content/zh/features/java.mdx b/packages/docs/content/zh/manual/features/java.mdx index bdc3c15..6894ec1 100644 --- a/packages/docs/content/zh/features/java.mdx +++ b/packages/docs/content/zh/manual/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<JavaVersion>, 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/meta.json b/packages/docs/content/zh/manual/features/meta.json index 2fb2ded..2fb2ded 100644 --- a/packages/docs/content/zh/features/meta.json +++ b/packages/docs/content/zh/manual/features/meta.json diff --git a/packages/docs/content/zh/features/mod-loaders.mdx b/packages/docs/content/zh/manual/features/mod-loaders.mdx index 3687230..cbd8148 100644 --- a/packages/docs/content/zh/features/mod-loaders.mdx +++ b/packages/docs/content/zh/manual/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:<version>` -- `net.minecraftforge:fmlloader:<version>` -- `org.ow2.asm:asm:<version>` - -**解析:** -```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#模组管理系统)。 diff --git a/packages/docs/content/zh/getting-started.mdx b/packages/docs/content/zh/manual/getting-started.mdx index d36eaf5..5d8c8c5 100644 --- a/packages/docs/content/zh/getting-started.mdx +++ b/packages/docs/content/zh/manual/getting-started.mdx @@ -5,7 +5,7 @@ description: 使用 DropOut Minecraft 启动器的快速入门指南 # 快速开始 -DropOut 是一个使用 Tauri v2 和 Rust 构建的现代化、可复现、开发者级别的 Minecraft 启动器。本指南将帮助你开始安装和使用 DropOut。 +DropOut 是一个使用 Tauri v2 构建的现代化、可复现、开发者级别的 Minecraft 启动器。本指南将帮助你开始安装和使用 DropOut。 ## 安装 @@ -13,17 +13,18 @@ DropOut 是一个使用 Tauri v2 和 Rust 构建的现代化、可复现、开 从[发布页面](https://github.com/HsiangNianian/DropOut/releases)下载适合你平台的最新版本。 -| 平台 | 文件 | -| -------------- | ----------------------- | -| Linux x86_64 | `.deb`, `.AppImage` | -| Linux ARM64 | `.deb`, `.AppImage` | -| macOS ARM64 | `.dmg` | -| Windows x86_64 | `.msi`, `.exe` | -| Windows ARM64 | `.msi`, `.exe` | +| 平台 | 文件 | +| -------------- | ------------------- | +| Linux x86_64 | `.deb`, `.AppImage` | +| Linux ARM64 | `.deb`, `.AppImage` | +| macOS ARM64 | `.dmg` | +| Windows x86_64 | `.msi`, `.exe` | +| Windows ARM64 | `.msi`, `.exe` | ### Linux 安装 #### 使用 .deb 包 + ```bash sudo dpkg -i dropout_*.deb # 如果需要,修复依赖 @@ -31,6 +32,7 @@ sudo apt-get install -f ``` #### 使用 AppImage + ```bash chmod +x dropout_*.AppImage ./dropout_*.AppImage @@ -45,11 +47,13 @@ chmod +x dropout_*.AppImage ### Windows 安装 #### 使用 .msi 安装程序 + 1. 双击 `.msi` 文件 2. 按照安装向导操作 3. 从开始菜单启动 DropOut #### 使用 .exe 便携版 + 1. 双击 `.exe` 文件 2. DropOut 将直接运行,无需安装 @@ -74,17 +78,12 @@ chmod +x dropout_*.AppImage ### 1. 登录 <Cards> - <Card - title="微软账户" - description="使用你的官方 Minecraft 账户登录" - /> - <Card - title="离线模式" - description="创建本地配置文件进行离线游戏" - /> + <Card title="微软账户" description="使用你的官方 Minecraft 账户登录" /> + <Card title="离线模式" description="创建本地配置文件进行离线游戏" /> </Cards> **微软登录:** + 1. 点击"使用微软登录" 2. 将显示设备代码 3. 访问显示的 URL 并输入代码 @@ -92,6 +91,7 @@ chmod +x dropout_*.AppImage 5. 返回 DropOut - 你将自动登录 **离线登录:** + 1. 点击"离线模式" 2. 输入用户名 3. 点击"创建账户" @@ -117,37 +117,27 @@ chmod +x dropout_*.AppImage ## 下一步 <Cards> - <Card - title="功能特性" - href="/docs/features" - description="了解 DropOut 提供的所有功能" - /> - <Card - title="实例管理" - href="/docs/features/instances" - description="创建隔离的游戏环境" - /> - <Card - title="模组加载器" - href="/docs/features/mod-loaders" + <Card title="功能特性" href="/docs/manual/features" description="了解 DropOut 提供的所有功能" /> + <Card title="实例管理" href="/docs/manual/features/instances" description="创建隔离的游戏环境" /> + <Card + title="模组加载器" + href="/docs/manual/features/mod-loaders" description="安装和管理 Fabric 和 Forge" /> - <Card - title="故障排除" - href="/docs/troubleshooting" - description="常见问题和解决方案" - /> + <Card title="故障排除" href="/docs/troubleshooting" description="常见问题和解决方案" /> </Cards> ## 系统要求 ### 最低要求 + - **操作系统**: Windows 10+、macOS 11+ 或 Linux(基于 Debian) - **内存**: 4GB(推荐 8GB 用于模组 Minecraft) - **存储**: 启动器 + 游戏文件需要 2GB - **Java**: 如果找不到,DropOut 会自动安装 ### 推荐配置 + - **操作系统**: 你操作系统的最新稳定版本 - **内存**: 16GB 以获得带模组的最佳性能 - **存储**: 10GB+ 用于多个版本和模组 @@ -156,6 +146,7 @@ chmod +x dropout_*.AppImage ## 获取帮助 如果遇到问题: + - 查看[故障排除指南](/docs/troubleshooting) - 在 [GitHub Issues](https://github.com/HsiangNianian/DropOut/issues) 上报告 bug - 加入我们的社区讨论 diff --git a/packages/docs/content/zh/index.mdx b/packages/docs/content/zh/manual/index.mdx index b554cca..1b74743 100644 --- a/packages/docs/content/zh/index.mdx +++ b/packages/docs/content/zh/manual/index.mdx @@ -5,7 +5,7 @@ description: 现代化、可复现、开发者级别的 Minecraft 启动器 # 欢迎使用 DropOut -DropOut 是一个使用 Tauri v2 和 Rust 构建的现代 Minecraft 启动器,专为重视控制、透明度和长期稳定性的玩家设计。 +DropOut 是一个使用 Tauri v2 构建的现代 Minecraft 启动器,专为重视控制、透明度和长期稳定性的玩家设计。 <div style={{ textAlign: 'center', margin: '2rem 0' }}> <img src="/image.png" alt="DropOut 启动器" style={{ maxWidth: '700px', borderRadius: '8px' }} /> diff --git a/packages/docs/content/zh/manual/meta.json b/packages/docs/content/zh/manual/meta.json new file mode 100644 index 0000000..cc3767a --- /dev/null +++ b/packages/docs/content/zh/manual/meta.json @@ -0,0 +1,10 @@ +{ + "title": "使用文档", + "pages": [ + "index", + "getting-started", + "architecture", + "features", + "troubleshooting" + ] +} diff --git a/packages/docs/content/zh/troubleshooting.mdx b/packages/docs/content/zh/manual/troubleshooting.mdx index c077528..ba0ec66 100644 --- a/packages/docs/content/zh/troubleshooting.mdx +++ b/packages/docs/content/zh/manual/troubleshooting.mdx @@ -508,16 +508,16 @@ chmod -R 700 ~/Library/Application\ Support/com.dropout.launcher ### 目前正在处理 - 多账户切换(进行中) -- 自定义游戏目录选择(计划中) +- 选择自定义游戏目录(计划中) - 启动器自动更新(计划中) -### 可用的变通方法 +### 解决方案 **问题**:无法轻松切换账户 -**变通方法**:退出登录并使用不同账户登录 +**解决方案**:退出登录并使用不同账户登录 **问题**:没有内置模组管理器 -**变通方法**:在实例文件夹中手动管理模组 +**解决方案**:在实例文件夹中手动管理模组 **问题**:无法从其他启动器导入 -**变通方法**:手动复制实例文件 +**解决方案**:手动复制实例文件 diff --git a/packages/docs/content/zh/meta.json b/packages/docs/content/zh/meta.json index 4fd7ad1..b0825f3 100644 --- a/packages/docs/content/zh/meta.json +++ b/packages/docs/content/zh/meta.json @@ -1,11 +1,7 @@ { "title": "文档", "pages": [ - "index", - "getting-started", - "architecture", - "features", "development", - "troubleshooting" + "manual" ] } diff --git a/packages/docs/package.json b/packages/docs/package.json index 18a5bf3..4ee4baf 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -18,11 +18,13 @@ "fumadocs-mdx": "14.2.6", "fumadocs-ui": "16.4.7", "isbot": "^5.1.32", + "mermaid": "^11.12.3", "react": "^19.2.3", "react-dom": "^19.2.3", "react-router": "^7.12.0" }, "devDependencies": { + "@biomejs/biome": "^2.3.11", "@react-router/dev": "^7.12.0", "@tailwindcss/vite": "^4.1.18", "@types/mdx": "^2.0.13", @@ -33,7 +35,6 @@ "tailwindcss": "^4.1.18", "typescript": "^5.9.3", "vite": "^7.3.1", - "vite-tsconfig-paths": "^6.0.4", - "@biomejs/biome": "^2.3.11" + "vite-tsconfig-paths": "^6.0.4" } } diff --git a/packages/docs/source.config.ts b/packages/docs/source.config.ts index d67a91b..7880853 100644 --- a/packages/docs/source.config.ts +++ b/packages/docs/source.config.ts @@ -1,7 +1,12 @@ import { defineConfig, defineDocs } from 'fumadocs-mdx/config'; +import { remarkMdxMermaid } from 'fumadocs-core/mdx-plugins'; export const docs = defineDocs({ dir: 'content', }); -export default defineConfig(); +export default defineConfig({ + mdxOptions: { + remarkPlugins: [remarkMdxMermaid], + }, +}); |