diff options
| author | 2026-02-27 17:18:25 +0800 | |
|---|---|---|
| committer | 2026-02-27 17:18:25 +0800 | |
| commit | 81a62402ef6f8900ff092366121a9b7a4263ba52 (patch) | |
| tree | 119109c62331d4d26612e2df7726cee82d1871f5 /packages/docs/content/en/development | |
| parent | 3e3144a2c6c62375c2949cb5e9b03f17511fccbe (diff) | |
| download | DropOut-81a62402ef6f8900ff092366121a9b7a4263ba52.tar.gz DropOut-81a62402ef6f8900ff092366121a9b7a4263ba52.zip | |
Restructure docs into manual/development and add implementation docs (#94)
## Summary by Sourcery
Restructure documentation into separate manual and development sections,
introduce detailed internal implementation docs for auth/Java/mod
loaders, and update site navigation, landing page links, and MDX tooling
(Mermaid, card styling) to match the new structure and tech stack.
Enhancements:
- Enable Mermaid rendering support in the docs app and add a reusable
Mermaid React component.
- Refine Docs page rendering by customizing Card styling and removing
redundant in-page titles/descriptions rendered by the layout.
- Align docs source configuration and routing comments with the new
manual-based default paths.
Documentation:
- Split user-facing docs under a new manual section and move contributor
content into a dedicated development section for both English and
Chinese.
- Add comprehensive internal implementation documentation covering
authentication, Java management, mod loader/version merging, event bus,
and architecture patterns in both English and Chinese.
- Update existing feature docs (mod loaders, Java, authentication) and
getting-started/troubleshooting pages to be more conceptual, pointing to
implementation docs for technical details.
- Refresh architecture docs to reflect the React/Zustand frontend stack
and add Mermaid-based architecture diagrams.
- Adjust navigation labels, home-page CTAs, and doc links to target the
new manual/development structure and routes.
---------
Co-authored-by: 简律纯 <i@jyunko.cn>
Diffstat (limited to 'packages/docs/content/en/development')
| -rw-r--r-- | packages/docs/content/en/development/architecture.mdx | 293 | ||||
| -rw-r--r-- | packages/docs/content/en/development/guide.mdx | 546 | ||||
| -rw-r--r-- | packages/docs/content/en/development/implementation.mdx | 351 | ||||
| -rw-r--r-- | packages/docs/content/en/development/meta.json | 8 |
4 files changed, 1198 insertions, 0 deletions
diff --git a/packages/docs/content/en/development/architecture.mdx b/packages/docs/content/en/development/architecture.mdx new file mode 100644 index 0000000..6d59ab7 --- /dev/null +++ b/packages/docs/content/en/development/architecture.mdx @@ -0,0 +1,293 @@ +--- +title: Architecture +description: Technical architecture and design of DropOut Minecraft Launcher +--- + +# Architecture + +DropOut is built with a modern tech stack designed for performance, security, and cross-platform compatibility. + +## Technology Stack + +### Backend (Rust) +- **Framework**: Tauri v2 +- **Language**: Rust (Edition 2021) +- **Async Runtime**: Tokio +- **HTTP Client**: reqwest with native-tls + +### Frontend (React) +- **Framework**: React 19 +- **State Management**: Zustand +- **Router**: React Router v7 +- **Styling**: Tailwind CSS 4 +- **Build Tool**: Vite (with Rolldown) +- **Package Manager**: pnpm + +### Documentation +- **Framework**: Fumadocs with React Router v7 +- **Content**: MDX files +- **Styling**: Tailwind CSS 4 + +## System Architecture + +```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 **Zustand** for global state management: + +```typescript +// models/auth.ts +import { create } from "zustand"; + +interface AuthState { + account: Account | null; + loginMode: LoginMode | null; + // ... + setAccount: (account: Account | null) => void; +} + +export const useAuthStore = create<AuthState>((set) => ({ + account: null, + loginMode: null, + setAccount: (account) => set({ account }), + // ... +})); +``` + +**Key Stores:** +- `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 + +#### Command Pattern +All Tauri commands follow this structure: + +```rust +#[tauri::command] +async fn command_name( + window: Window, + state: State<'_, SomeState>, + param: Type, +) -> Result<ReturnType, String> { + emit_log!(window, "Status message"); + // Async logic + Ok(result) +} +``` + +#### Event Communication + +**Rust → Frontend (Progress Updates):** +```rust +window.emit("launcher-log", "Downloading...")?; +window.emit("download-progress", progress_struct)?; +``` + +**Frontend → Rust (Commands):** +```typescript +import { invoke } from "@tauri-apps/api/core"; +const result = await invoke("start_game", { versionId: "1.20.4" }); +``` + +### Core Modules + +#### Authentication (`core/auth.rs`) +- **Microsoft OAuth 2.0**: Device Code Flow +- **Offline Authentication**: Local UUID generation +- **Token Management**: Refresh token storage and auto-refresh +- **Xbox Live Integration**: Full authentication chain + +**Authentication Flow:** +1. Device Code Request → MS Token +2. Xbox Live Authentication +3. XSTS Authorization +4. Minecraft Token Exchange +5. Profile Fetching + +#### Downloader (`core/downloader.rs`) +- **Concurrent Downloads**: Configurable thread pool +- **Resume Support**: `.part` and `.part.meta` files +- **Multi-segment Downloads**: Large files split into chunks +- **Checksum Verification**: SHA1/SHA256 validation +- **Progress Tracking**: Real-time events to frontend + +#### Java Management (`core/java.rs`) +- **Auto-detection**: Scans system paths +- **Adoptium Integration**: Download JDK/JRE on-demand +- **Catalog Caching**: 24-hour cache for version lists +- **Installation**: Extracts to app data directory +- **Cancellation**: Atomic flag for download cancellation + +#### Fabric Support (`core/fabric.rs`) +- **Meta API Integration**: Fetch loader versions +- **Profile Generation**: Creates version JSON +- **Library Resolution**: Maven artifact handling + +#### Forge Support (`core/forge.rs`) +- **Installer Execution**: Runs Forge installer +- **Profile Parsing**: Extracts install profile +- **Library Management**: Handles Forge-specific libraries + +#### Instance System (`core/instance.rs`) +- **Isolation**: Separate directories per instance +- **Configuration**: Per-instance settings +- **Mod Management**: Instance-specific mods +- **Version Locking**: Reproducible environments + +#### Version Management +- **Manifest Parsing** (`manifest.rs`): Mojang version manifest +- **Inheritance System** (`version_merge.rs`): Parent version merging +- **Game Version** (`game_version.rs`): JSON parsing and validation +- **Rules Engine** (`rules.rs`): OS/feature conditional logic + +### File Structure + +``` +~/.local/share/com.dropout.launcher/ (Linux) +~/Library/Application Support/com.dropout.launcher/ (macOS) +%APPDATA%/com.dropout.launcher/ (Windows) +├── versions/ +│ └── <version_id>/ +│ ├── <version_id>.json +│ ├── <version_id>.jar +│ └── natives/ +├── libraries/ +│ └── <maven-path>/ +├── assets/ +│ ├── indexes/ +│ └── objects/ +├── instances/ +│ └── <instance_name>/ +│ ├── mods/ +│ ├── config/ +│ └── saves/ +├── java/ +│ └── <version>/ +├── config.json +└── accounts.json +``` + +## Data Flow + +### Game Launch Sequence + +1. **Frontend**: User clicks "Launch Game" +2. **Command**: `start_game(instance_id, version_id)` invoked +3. **Backend Processing**: + - Load version JSON (with inheritance) + - Resolve all libraries + - Download missing assets + - Extract native libraries + - Build classpath + - Construct JVM arguments + - Replace placeholders +4. **Process Spawn**: Launch Java with arguments +5. **Stream Logs**: Emit stdout/stderr to frontend +6. **Monitor**: Track game process status + +### Download Flow + +1. **Queue Creation**: List of files to download +2. **Concurrent Processing**: Semaphore-limited threads +3. **Resume Check**: Verify existing `.part` files +4. **Download**: Multi-segment for large files +5. **Verification**: Checksum validation +6. **Progress Events**: Real-time updates to UI +7. **Completion**: Move from `.part` to final location + +### Authentication Flow + +1. **Device Code Request**: Get user code + device code +2. **User Authorization**: User visits URL and enters code +3. **Token Polling**: Frontend polls for completion +4. **Token Exchange**: MS token → Xbox → XSTS → Minecraft +5. **Profile Fetch**: Get username and UUID +6. **Storage**: Save account with refresh token +7. **Auto-refresh**: Background token refresh on expiry + +## Platform-Specific Considerations + +### Linux +- Uses GTK WebView (`webkit2gtk`) +- System Java detection from `/usr/lib/jvm` +- Desktop file integration + +### macOS +- Uses system WebKit +- App bundle structure +- Keychain integration for secure storage + +### Windows +- Uses WebView2 runtime +- Registry Java detection +- MSI installer support +- No console window in release builds + +## Performance Optimizations + +- **Concurrent Downloads**: Parallel asset/library downloads +- **Lazy Loading**: Load version manifests on-demand +- **Caching**: Java catalog, version manifests +- **Native Code**: Rust for CPU-intensive operations +- **Async I/O**: Tokio for non-blocking operations + +## Security Features + +- **Token Encryption**: Secure storage of auth tokens +- **HTTPS Only**: All external API calls +- **Checksum Validation**: File integrity verification +- **Sandboxed Execution**: Tauri security model +- **No Arbitrary Code**: No eval or dynamic code execution diff --git a/packages/docs/content/en/development/guide.mdx b/packages/docs/content/en/development/guide.mdx new file mode 100644 index 0000000..8ff2906 --- /dev/null +++ b/packages/docs/content/en/development/guide.mdx @@ -0,0 +1,546 @@ +--- +title: Development Guide +description: Build, test, and contribute to DropOut +--- + +# Development Guide + +This guide will help you set up a development environment, build DropOut from source, and contribute to the project. + +## Prerequisites + +### Required Software + +1. **Rust** (latest stable) + ```bash + # Install via rustup + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + ``` + +2. **Node.js** (v22+) and **pnpm** (v9+) + ```bash + # Install Node.js from https://nodejs.org/ + # Install pnpm + npm install -g pnpm@9 + ``` + +3. **System Dependencies** + + Follow the [Tauri Prerequisites](https://v2.tauri.app/start/prerequisites/) for your platform: + + **Linux (Debian/Ubuntu):** + ```bash + sudo apt update + sudo apt install libwebkit2gtk-4.1-dev \ + build-essential \ + curl \ + wget \ + file \ + libssl-dev \ + libayatana-appindicator3-dev \ + librsvg2-dev + ``` + + **macOS:** + ```bash + xcode-select --install + ``` + + **Windows:** + - Install [Microsoft Visual C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) + - Install [WebView2](https://developer.microsoft.com/microsoft-edge/webview2/) + +## Getting Started + +### Clone the Repository + +```bash +git clone https://github.com/HydroRoll-Team/DropOut.git +cd DropOut +``` + +### Install Dependencies + +**Frontend dependencies:** +```bash +cd packages/ui +pnpm install +cd ../.. +``` + +**Documentation dependencies:** +```bash +cd packages/docs +pnpm install +cd ../.. +``` + +### Development Mode + +Run DropOut in development mode with hot reload: + +```bash +cargo tauri dev +``` + +This will: +1. Start the frontend dev server (Vite on port 5173) +2. Compile the Rust backend +3. Open the Tauri window +4. Enable hot reload for frontend changes +5. Recompile on Rust file changes + +**Terminal output:** +- Frontend logs from Vite +- Rust stdout/stderr +- Compilation status + +### Building for Production + +Build release binaries: + +```bash +cargo tauri build +``` + +**Output locations:** +- **Linux**: `src-tauri/target/release/bundle/` + - `.deb` package + - `.AppImage` bundle +- **macOS**: `src-tauri/target/release/bundle/` + - `.dmg` installer + - `.app` bundle +- **Windows**: `src-tauri/target/release/bundle/` + - `.msi` installer + - `.exe` executable + +## Project Structure + +``` +DropOut/ +├── src-tauri/ # Rust backend +│ ├── src/ +│ │ ├── main.rs # Tauri commands & entry point +│ │ ├── core/ # Core modules +│ │ │ ├── auth.rs # Authentication +│ │ │ ├── downloader.rs # Download manager +│ │ │ ├── fabric.rs # Fabric support +│ │ │ ├── forge.rs # Forge support +│ │ │ ├── java.rs # Java management +│ │ │ ├── instance.rs # Instance system +│ │ │ └── ... +│ │ └── utils/ # Utilities +│ └── Cargo.toml +├── packages/ +│ ├── ui/ # Svelte 5 frontend +│ │ ├── src/ +│ │ │ ├── App.svelte +│ │ │ ├── components/ +│ │ │ ├── stores/ # State management +│ │ │ └── lib/ +│ │ └── package.json +│ └── docs/ # Documentation site +│ ├── content/docs/ +│ └── package.json +├── .github/ +│ └── workflows/ # CI/CD pipelines +└── scripts/ # Build scripts +``` + +## Development Workflows + +### Frontend Development + +**Start dev server:** +```bash +cd packages/ui +pnpm dev +``` + +**Type checking:** +```bash +pnpm check +``` + +**Linting:** +```bash +pnpm lint +``` + +**Formatting:** +```bash +pnpm format +``` + +### Backend Development + +**Run Rust tests:** +```bash +cargo test +``` + +**Check code:** +```bash +cargo check +``` + +**Format code:** +```bash +cargo fmt +``` + +**Lint code:** +```bash +cargo clippy +``` + +### Documentation Development + +**Start docs dev server:** +```bash +cd packages/docs +pnpm dev +``` + +**Build docs:** +```bash +pnpm build +``` + +**Type check:** +```bash +pnpm types:check +``` + +## Code Style + +### Rust + +Follow standard Rust conventions: +- Use `cargo fmt` for formatting +- Use `cargo clippy` for linting +- Write documentation comments (`///`) +- Handle errors properly +- Use async/await for I/O + +**Example:** +```rust +/// Starts the Microsoft authentication device flow +#[tauri::command] +async fn start_microsoft_login( + window: Window, +) -> Result<DeviceCodeResponse, String> { + emit_log!(window, "Starting Microsoft login..."); + + start_device_flow() + .await + .map_err(|e| e.to_string()) +} +``` + +### TypeScript/Svelte + +Follow the project's conventions: +- Use Svelte 5 runes (`$state`, `$effect`) +- Prefer TypeScript over JavaScript +- Use Biome for formatting and linting +- Follow component structure + +**Example:** +```typescript +// stores/auth.svelte.ts +export class AuthState { + currentAccount = $state<Account | null>(null); + isLoginModalOpen = $state(false); + + async login(username: string) { + const account = await invoke('offline_login', { username }); + this.currentAccount = account; + } +} +``` + +## Testing + +### Unit Tests + +**Rust:** +```rust +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_generate_offline_uuid() { + let uuid = generate_offline_uuid("Player"); + assert!(uuid.len() > 0); + } +} +``` + +**Run:** +```bash +cargo test +``` + +### Integration Tests + +Test the full application: +1. Build in dev mode: `cargo tauri dev` +2. Manually test features +3. Check console for errors +4. Verify UI behavior + +### CI Tests + +GitHub Actions runs tests on: +- Ubuntu (latest) +- Arch Linux (Wayland) +- Windows (latest) +- macOS (ARM64) + +View workflow: `.github/workflows/test.yml` + +## Debugging + +### Frontend Debugging + +1. Open DevTools in Tauri window: `Ctrl+Shift+I` (Windows/Linux) or `Cmd+Option+I` (macOS) +2. Check Console for errors +3. Use React DevTools or Svelte DevTools +4. Monitor Network tab for API calls + +### Backend Debugging + +**Print debugging:** +```rust +emit_log!(window, format!("Debug: {}", value)); +println!("Debug: {}", value); +``` + +**Rust debugger:** +```bash +# Install rust-lldb or rust-gdb +cargo install rust-gdb + +# Debug +rust-gdb target/debug/dropout +``` + +### Logging + +**Frontend:** +```typescript +console.log("Info message"); +console.error("Error message"); +``` + +**Backend:** +```rust +emit_log!(window, "Status update"); +eprintln!("Error: {}", error); +``` + +## Contributing + +### Contribution Workflow + +1. **Fork** the repository +2. **Create** a feature branch: + ```bash + git checkout -b feature/my-feature + ``` +3. **Make** your changes +4. **Test** thoroughly +5. **Commit** with conventional commits: + ```bash + git commit -m "feat: add new feature" + ``` +6. **Push** to your fork: + ```bash + git push origin feature/my-feature + ``` +7. **Create** a pull request + +### Commit Messages + +Follow [Conventional Commits](https://www.conventionalcommits.org/): + +**Format:** +``` +<type>[scope]: <description> + +[optional body] + +[optional footer] +``` + +**Types:** +- `feat`: New feature +- `fix`: Bug fix +- `docs`: Documentation +- `style`: Formatting +- `refactor`: Code restructuring +- `perf`: Performance improvement +- `test`: Adding tests +- `chore`: Maintenance + +**Examples:** +```bash +feat(auth): add offline authentication support +fix(java): resolve detection on Windows +docs: update installation guide +refactor(download): simplify progress tracking +``` + +### Pull Request Guidelines + +**Before submitting:** +- [ ] Code follows style guidelines +- [ ] Tests pass locally +- [ ] Documentation updated if needed +- [ ] No unnecessary files committed +- [ ] Commit messages are clear + +**PR Description:** +- Explain what and why +- Link related issues +- List breaking changes +- Add screenshots for UI changes + +### Code Review + +Maintainers will review your PR for: +- Code quality and style +- Test coverage +- Documentation +- Performance impact +- Security implications + +Be responsive to feedback and make requested changes. + +## Common Tasks + +### Adding a Tauri Command + +1. **Define command in `main.rs`:** + ```rust + #[tauri::command] + async fn my_command(param: String) -> Result<String, String> { + Ok(format!("Received: {}", param)) + } + ``` + +2. **Register in builder:** + ```rust + .invoke_handler(tauri::generate_handler![ + my_command, + // ... other commands + ]) + ``` + +3. **Call from frontend:** + ```typescript + const result = await invoke('my_command', { param: 'value' }); + ``` + +### Adding a UI Component + +1. **Create component file:** + ```svelte + <!-- packages/ui/src/components/MyComponent.svelte --> + <script lang="ts"> + let count = $state(0); + </script> + + <button onclick={() => count++}> + Count: {count} + </button> + ``` + +2. **Import and use:** + ```svelte + <script> + import MyComponent from './components/MyComponent.svelte'; + </script> + + <MyComponent /> + ``` + +### Adding a Store + +1. **Create store file:** + ```typescript + // packages/ui/src/stores/mystore.svelte.ts + export class MyState { + value = $state(0); + + increment() { + this.value++; + } + } + + export const myState = new MyState(); + ``` + +2. **Use in components:** + ```svelte + <script> + import { myState } from '../stores/mystore.svelte'; + </script> + + <button onclick={() => myState.increment()}> + {myState.value} + </button> + ``` + +## Troubleshooting Development Issues + +### Build Failures + +**"cannot find -lwebkit2gtk"** +```bash +# Install WebKit dependencies +sudo apt install libwebkit2gtk-4.1-dev +``` + +**"pnpm not found"** +```bash +# Install pnpm +npm install -g pnpm@9 +``` + +**"Rust version too old"** +```bash +# Update Rust +rustup update +``` + +### Runtime Issues + +**"Failed to load dynamic library"** +- Rebuild: `cargo clean && cargo tauri dev` +- Check library paths +- Verify dependencies installed + +**"CORS error"** +- Normal in dev mode +- Tauri handles CORS automatically + +**"Hot reload not working"** +- Check Vite config +- Restart dev server +- Clear browser cache + +## Resources + +- [Tauri Documentation](https://v2.tauri.app/) +- [Svelte 5 Documentation](https://svelte.dev/docs) +- [Rust Book](https://doc.rust-lang.org/book/) +- [DropOut Repository](https://github.com/HydroRoll-Team/DropOut) + +## Getting Help + +- **Issues**: [GitHub Issues](https://github.com/HydroRoll-Team/DropOut/issues) +- **Discussions**: [GitHub Discussions](https://github.com/HydroRoll-Team/DropOut/discussions) +- **Documentation**: This site 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" + ] +} |