diff options
Diffstat (limited to 'packages/docs/content/en/development/implementation.mdx')
| -rw-r--r-- | packages/docs/content/en/development/implementation.mdx | 351 |
1 files changed, 351 insertions, 0 deletions
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). |