From 10c560f822d1ef4a9b9dfb550638127b7b3a71de Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 21 Jan 2026 12:50:18 +0000 Subject: [PATCH 01/18] Initial plan From 6db4a3b1807d0d305538a6b83ba9cad047f542d0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 21 Jan 2026 13:01:23 +0000 Subject: [PATCH 02/18] docs: add comprehensive documentation for DropOut launcher Co-authored-by: HsiangNianian <44714368+HsiangNianian@users.noreply.github.com> --- packages/docs/README.md | 159 ++++- packages/docs/content/docs/architecture.mdx | 282 +++++++++ packages/docs/content/docs/development.mdx | 547 ++++++++++++++++++ .../content/docs/features/authentication.mdx | 267 +++++++++ packages/docs/content/docs/features/index.mdx | 177 ++++++ packages/docs/content/docs/features/java.mdx | 395 +++++++++++++ packages/docs/content/docs/features/meta.json | 9 + .../content/docs/features/mod-loaders.mdx | 410 +++++++++++++ .../docs/content/docs/getting-started.mdx | 162 ++++++ packages/docs/content/docs/index.mdx | 103 +++- packages/docs/content/docs/meta.json | 18 +- packages/docs/content/docs/test.mdx | 24 - .../docs/content/docs/troubleshooting.mdx | 524 +++++++++++++++++ 13 files changed, 3024 insertions(+), 53 deletions(-) create mode 100644 packages/docs/content/docs/architecture.mdx create mode 100644 packages/docs/content/docs/development.mdx create mode 100644 packages/docs/content/docs/features/authentication.mdx create mode 100644 packages/docs/content/docs/features/index.mdx create mode 100644 packages/docs/content/docs/features/java.mdx create mode 100644 packages/docs/content/docs/features/meta.json create mode 100644 packages/docs/content/docs/features/mod-loaders.mdx create mode 100644 packages/docs/content/docs/getting-started.mdx delete mode 100644 packages/docs/content/docs/test.mdx create mode 100644 packages/docs/content/docs/troubleshooting.mdx diff --git a/packages/docs/README.md b/packages/docs/README.md index 2b4c09a..055e479 100644 --- a/packages/docs/README.md +++ b/packages/docs/README.md @@ -1,14 +1,157 @@ -# docs +# DropOut Documentation -This is a React Router application generated with -[Create Fumadocs](https://github.com/fuma-nama/fumadocs). +This is the official documentation site for DropOut Minecraft Launcher, built with [Fumadocs](https://fumadocs.dev) and React Router v7. -Run development server: +## Overview + +The documentation covers: +- **Getting Started**: Installation and first-time setup +- **Features**: Detailed guides for all launcher features +- **Architecture**: Technical design and implementation details +- **Development**: Building and contributing to DropOut +- **Troubleshooting**: Common issues and solutions + +## Development + +### Prerequisites + +- Node.js 22+ +- pnpm 9+ + +### Setup + +Install dependencies: + +```bash +pnpm install +``` + +### Run Development Server ```bash -npm run dev -# or pnpm dev -# or -yarn dev ``` + +This starts the development server at `http://localhost:5173` with hot reload enabled. + +### Build for Production + +```bash +pnpm build +``` + +The production build will be output to the `build/` directory. + +### Type Checking + +```bash +pnpm types:check +``` + +### Linting and Formatting + +```bash +# Check code +pnpm lint + +# Format code +pnpm format +``` + +## Project Structure + +``` +packages/docs/ +├── content/ +│ └── docs/ # Documentation content (MDX) +│ ├── index.mdx # Home page +│ ├── getting-started.mdx +│ ├── architecture.mdx +│ ├── development.mdx +│ ├── troubleshooting.mdx +│ └── features/ # Feature-specific docs +├── app/ # React Router app +├── public/ # Static assets +├── source.config.ts # Fumadocs configuration +└── react-router.config.ts # React Router configuration +``` + +## Writing Documentation + +### MDX Format + +All documentation is written in MDX (Markdown with JSX): + +```mdx +--- +title: Page Title +description: Page description for SEO +--- + +# Page Title + +Content goes here... + + + + +``` + +### Available Components + +Fumadocs provides several components: + +- `` - Link cards +- `` - Card container +- `` - Info/warning boxes +- `` - Tabbed content +- `` - Numbered steps +- Code blocks with syntax highlighting + +### Adding New Pages + +1. Create new `.mdx` file in `content/docs/` +2. Add frontmatter with title and description +3. Write content using MDX +4. Update `meta.json` to include the page +5. Test locally with `pnpm dev` + +### Organizing Content + +Use `meta.json` files to organize navigation: + +```json +{ + "title": "Section Title", + "pages": [ + "page1", + "page2", + { + "title": "Subsection", + "pages": ["sub1", "sub2"] + } + ] +} +``` + +## Deployment + +The documentation is automatically deployed when changes are merged to the main branch. + +## Contributing + +1. Fork the repository +2. Create a feature branch +3. Make your changes +4. Test locally +5. Submit a pull request + +## Links + +- [DropOut Repository](https://github.com/HydroRoll-Team/DropOut) +- [Fumadocs](https://fumadocs.dev) +- [React Router](https://reactrouter.com) + +## License + +MIT License - see the main repository for details. diff --git a/packages/docs/content/docs/architecture.mdx b/packages/docs/content/docs/architecture.mdx new file mode 100644 index 0000000..f8cc8f4 --- /dev/null +++ b/packages/docs/content/docs/architecture.mdx @@ -0,0 +1,282 @@ +--- +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 (Svelte) +- **Framework**: Svelte 5 (with runes) +- **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 + +``` +┌─────────────────────────────────────────────────────────┐ +│ 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 │ + └──────────┘ └────────────┘ └────────────┘ +``` + +## Core Components + +### Frontend State Management + +DropOut uses **Svelte 5 runes** for reactive state management: + +```typescript +// stores/auth.svelte.ts +export class AuthState { + currentAccount = $state(null); // Reactive + isLoginModalOpen = $state(false); + + $effect(() => { // Side effects + // Auto-runs when dependencies change + }); +} +``` + +**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) + +### 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 { + 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/ +│ └── / +│ ├── .json +│ ├── .jar +│ └── natives/ +├── libraries/ +│ └── / +├── assets/ +│ ├── indexes/ +│ └── objects/ +├── instances/ +│ └── / +│ ├── mods/ +│ ├── config/ +│ └── saves/ +├── java/ +│ └── / +├── config.json +└── accounts.json +``` + +## Data Flow + +### Game Launch Sequence + +1. **Frontend**: User clicks "Launch Game" +2. **Command**: `start_game(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/docs/development.mdx b/packages/docs/content/docs/development.mdx new file mode 100644 index 0000000..f7beabb --- /dev/null +++ b/packages/docs/content/docs/development.mdx @@ -0,0 +1,547 @@ +--- +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 { + 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(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:** +``` +[scope]: + +[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 { + 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 + + + + + ``` + +2. **Import and use:** + ```svelte + + + + ``` + +### 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 + + + + ``` + +## 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/docs/features/authentication.mdx b/packages/docs/content/docs/features/authentication.mdx new file mode 100644 index 0000000..67e3c19 --- /dev/null +++ b/packages/docs/content/docs/features/authentication.mdx @@ -0,0 +1,267 @@ +--- +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/docs/features/index.mdx b/packages/docs/content/docs/features/index.mdx new file mode 100644 index 0000000..b36bb61 --- /dev/null +++ b/packages/docs/content/docs/features/index.mdx @@ -0,0 +1,177 @@ +--- +title: Features Overview +description: Comprehensive guide to all DropOut features +--- + +# Features Overview + +DropOut is packed with features designed for both casual players and power users. This guide covers all major capabilities. + +## Core Features + + + + + + + + + + +## Quick Feature Matrix + +| Feature | Status | Description | +|---------|--------|-------------| +| Microsoft Authentication | ✅ Complete | OAuth 2.0 with device code flow | +| Offline Authentication | ✅ Complete | Local accounts for offline play | +| Token Auto-refresh | ✅ Complete | Automatic refresh of expired tokens | +| Java Auto-detection | ✅ Complete | Scans system for Java installations | +| Java Download | ✅ Complete | Download Adoptium JDK/JRE versions | +| Fabric Support | ✅ Complete | Install and launch Fabric loader | +| Forge Support | ✅ Complete | Install and launch Forge loader | +| Instance System | ✅ Complete | Isolated game environments | +| GitHub Integration | ✅ Complete | View releases and changelogs | +| Concurrent Downloads | ✅ Complete | Multi-threaded asset downloads | +| Resume Downloads | ✅ Complete | Resume interrupted downloads | +| AI Assistant | ✅ Complete | Built-in troubleshooting helper | +| Config Editor | ✅ Complete | JSON/TOML configuration editor | +| Custom Resolution | ✅ Complete | Set game window dimensions | +| Memory Allocation | ✅ Complete | Customize JVM memory settings | +| Multi-account | 🚧 In Progress | Switch between multiple accounts | +| Mods Manager | 🚧 Planned | Enable/disable mods in launcher | +| Launcher Auto-update | 🚧 Planned | Self-updating mechanism | +| Custom Game Directory | 🚧 Planned | Choose game files location | +| Import Profiles | 🚧 Planned | Import from MultiMC/Prism | + +## Performance Features + +### Concurrent Downloads +- Configurable thread count (default: 10) +- Parallel asset and library downloads +- Progress tracking per file +- ETA calculation + +### Resume Support +- Interrupted downloads auto-resume +- `.part` files track progress +- Multi-segment downloads for large files +- Metadata files for state tracking + +### Caching +- Java catalog cached for 24 hours +- Version manifests cached locally +- Asset index caching +- Library deduplication + +## User Interface Features + +### Modern Design +- Dark mode enforced for eye comfort +- Particle background effects +- Clean, distraction-free layout +- Responsive design + +### Real-time Feedback +- Live download progress +- Game console output +- Log streaming +- Toast notifications + +### Settings Management +- Memory allocation slider +- Resolution customization +- Java path selection +- Thread count configuration +- Custom JVM arguments + +## Advanced Features + +### Version Inheritance +Modded versions (Fabric/Forge) automatically inherit from parent vanilla versions: +- Libraries merged from parent + mod loader +- Arguments combined and deduplicated +- Assets inherited from vanilla version + +### Native Library Extraction +- Platform-specific native extraction +- Automatic cleanup +- Proper library path configuration + +### Rules Engine +- OS-specific library filtering +- Feature flag support +- Architecture detection + +### Download Queue Persistence +- Save incomplete downloads +- Resume after launcher restart +- Queue priority management + +## Developer Features + +### Config Editor +Built-in JSON/TOML editor with: +- Syntax highlighting +- Validation +- Quick access to all configs + +### Log Access +- Real-time game logs +- Launcher debug logs +- Copy/export functionality + +### AI Assistant +- Troubleshooting guidance +- Error analysis +- Configuration help +- Documentation search + +## Coming Soon + +### Multi-account Management +- Switch between accounts easily +- Account profiles +- Quick switching + +### Mods Manager +- Browse and install mods +- Enable/disable mods +- Mod compatibility checking +- Version management + +### Profile Import +- Import from MultiMC +- Import from Prism Launcher +- Import from other launchers +- Preserve settings and saves + +### Launcher Auto-update +- Background update checks +- One-click updates +- Version history +- Rollback support + diff --git a/packages/docs/content/docs/features/java.mdx b/packages/docs/content/docs/features/java.mdx new file mode 100644 index 0000000..1afdab7 --- /dev/null +++ b/packages/docs/content/docs/features/java.mdx @@ -0,0 +1,395 @@ +--- +title: Java Management +description: Automatic Java detection, download, and installation +--- + +# Java Management + +DropOut provides comprehensive Java management, automatically detecting installed versions and downloading new ones as needed. + +## Auto-detection + +### System Scan + +DropOut scans multiple locations for Java installations: + +**Linux:** +- `/usr/lib/jvm/` +- `/usr/java/` +- `$JAVA_HOME` +- `PATH` environment variable + +**macOS:** +- `/Library/Java/JavaVirtualMachines/` +- `/System/Library/Java/JavaVirtualMachines/` +- `$JAVA_HOME` +- `PATH` environment variable + +**Windows:** +- `C:\Program Files\Java\` +- `C:\Program Files (x86)\Java\` +- `%JAVA_HOME%` +- `PATH` environment variable +- Windows Registry + +### Version Detection + +For each Java installation found, DropOut: +1. Runs `java -version` to get version info +2. Parses major version (8, 11, 17, 21, etc.) +3. Detects architecture (x64, ARM64) +4. Identifies vendor (Oracle, Adoptium, etc.) + +### Results + +All detected Java installations appear in Settings → Java: +- Version number +- Installation path +- Architecture +- Current selection status + +## Java Download + +### Adoptium Integration + +DropOut integrates with the Eclipse Adoptium API to download high-quality, free JDK/JRE builds. + +**Supported Versions:** +- Java 8 (LTS) +- Java 11 (LTS) +- Java 17 (LTS) +- Java 21 (LTS) +- Java 23+ (Latest) + +**Features:** +- Automatic platform detection +- Architecture-specific builds +- JDK or JRE selection +- Checksum verification + +### Download Process + +1. Navigate to Settings → Java +2. Click "Download Java" +3. Select version (e.g., Java 17) +4. Choose JDK or JRE +5. Click Download +6. Wait for download and extraction + +**Progress Tracking:** +- Real-time download speed +- ETA calculation +- Extraction progress +- Installation confirmation + +### Catalog Management + +The Java catalog is cached for 24 hours to improve performance: + +```rust +// Catalog structure +{ + "versions": [ + { + "version": "17.0.9+9", + "major": 17, + "url": "https://api.adoptium.net/...", + "sha256": "...", + "size": 123456789 + } + ], + "last_updated": 1234567890 +} +``` + +**Refresh:** +- Automatic after 24 hours +- Manual refresh in settings +- Forced refresh on download failure + +## Installation + +### Download Directory + +Downloaded Java runtimes are installed to: + +``` +~/.local/share/com.dropout.launcher/java/ (Linux) +~/Library/Application Support/com.dropout.launcher/java/ (macOS) +%APPDATA%/com.dropout.launcher/java/ (Windows) +``` + +### Directory Structure + +``` +java/ +├── jdk-17.0.9+9/ +│ ├── bin/ +│ │ └── java (or java.exe) +│ └── lib/ +├── jdk-21.0.1+12/ +│ ├── bin/ +│ └── lib/ +└── download_queue.json +``` + +### Extraction + +1. Download to `.part` file +2. Verify checksum +3. Extract archive: + - `.tar.gz` on Linux/macOS + - `.zip` on Windows +4. Move to `java//` directory +5. Set executable permissions (Unix) + +## Configuration + +### Memory Allocation + +Configure JVM memory in Settings: + +**Minimum Memory:** +- Default: 1024 MB +- Recommended: 2048 MB for vanilla +- Recommended: 4096+ MB for modded + +**Maximum Memory:** +- Default: 4096 MB +- Adjust based on your system RAM +- Leave 4GB for OS and other apps + +**Format:** +```bash +-Xms1024M -Xmx4096M +``` + +### Custom JVM Arguments + +Add custom JVM arguments for advanced configuration: + +**Common Arguments:** +```bash +# Garbage collection +-XX:+UseG1GC +-XX:+UnlockExperimentalVMOptions + +# Performance +-XX:G1NewSizePercent=20 +-XX:G1ReservePercent=20 +-XX:MaxGCPauseMillis=50 + +# Memory +-XX:G1HeapRegionSize=32M +``` + +### Java Path Selection + +**Auto-select:** +- DropOut recommends the best Java version for each Minecraft version +- Java 8 for Minecraft 1.12.2 and older +- Java 17 for Minecraft 1.18-1.20.4 +- Java 21 for Minecraft 1.20.5+ + +**Manual selection:** +1. Go to Settings → Java +2. Choose from detected installations +3. Or specify custom path + +## Version Recommendations + +### Minecraft Version → Java Version + +| Minecraft Version | Recommended Java | Minimum Java | +|-------------------|------------------|--------------| +| 1.7.10 and older | Java 8 | Java 8 | +| 1.8 - 1.12.2 | Java 8 | Java 8 | +| 1.13 - 1.16.5 | Java 8 or 11 | Java 8 | +| 1.17 - 1.17.1 | Java 16 | Java 16 | +| 1.18 - 1.20.4 | Java 17 | Java 17 | +| 1.20.5+ | Java 21 | Java 21 | + +### Modded Minecraft + +**Fabric:** +- Usually matches vanilla requirements +- Some mods may require newer Java + +**Forge:** +- May require specific Java versions +- Check mod loader documentation +- Often requires exact version match + +## Troubleshooting + +### Java Not Detected + +**Issue:** Installed Java not showing up + +**Solutions:** +1. Verify Java is in standard location +2. Check `JAVA_HOME` environment variable +3. Add Java `bin` directory to `PATH` +4. Restart DropOut +5. Manual path selection + +### Download Fails + +**Issue:** Java download doesn't complete + +**Solutions:** +1. Check internet connection +2. Verify disk space +3. Try different version +4. Clear download queue +5. Manual download from Adoptium + +### Wrong Java Version + +**Issue:** Game crashes due to Java version + +**Solutions:** +1. Check Minecraft version requirements +2. Download correct Java version +3. Select appropriate Java in settings +4. Verify Java path is correct + +### OutOfMemoryError + +**Issue:** Game crashes with memory error + +**Solutions:** +1. Increase maximum memory allocation +2. Close other applications +3. Upgrade system RAM +4. Use 64-bit Java +5. Optimize JVM arguments + +### Performance Issues + +**Issue:** Low FPS or stuttering + +**Solutions:** +1. Adjust memory allocation (not too high!) +2. Enable G1GC garbage collector +3. Add performance JVM arguments +4. Use newer Java version if compatible +5. Allocate 4-8GB for modpacks + +## API Reference + +### Tauri Commands + +**Detect Java Installations:** +```typescript +const javas = await invoke('detect_java_installations'); +// Returns: Array<{ path: string, version: string, major: number }> +``` + +**Get Java Catalog:** +```typescript +const catalog = await invoke('get_java_catalog'); +// Returns: { versions: Array, last_updated: number } +``` + +**Download Java:** +```typescript +await invoke('download_java', { + version: '17.0.9+9', + variant: 'jdk' // or 'jre' +}); +``` + +**Cancel Java Download:** +```typescript +await invoke('cancel_java_download'); +``` + +**Set Java Path:** +```typescript +await invoke('set_java_path', { path: '/path/to/java' }); +``` + +### Events + +**Download Progress:** +```typescript +listen('java-download-progress', (event) => { + const { percent, speed, eta } = event.payload; +}); +``` + +**Download Complete:** +```typescript +listen('java-download-complete', (event) => { + const { path, version } = event.payload; +}); +``` + +## Best Practices + +### For Players + +1. **Use Adoptium builds** - Free, high-quality, maintained +2. **Match Java to Minecraft** - Check version requirements +3. **Don't over-allocate memory** - Leave RAM for OS +4. **Keep Java updated** - Security and performance +5. **Use 64-bit Java** - Required for large memory + +### For Developers + +1. **Test multiple Java versions** - Ensure compatibility +2. **Document Java requirements** - Help users +3. **Handle missing Java** - Graceful fallbacks +4. **Validate Java path** - Before launching +5. **Provide clear errors** - When Java is wrong + +## Advanced Topics + +### Custom Java Installation + +To use a custom Java installation: + +1. Install Java manually +2. Note the installation path +3. In DropOut Settings → Java +4. Click "Custom Path" +5. Browse to Java executable +6. Verify version is correct + +### Java for Servers + +When running a Minecraft server: + +```bash +# Recommended server JVM arguments +-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 is supported for advanced users: + +1. Download GraalVM from graalvm.org +2. Install manually +3. Add to DropOut as custom Java +4. May improve performance +5. Test thoroughly before use + diff --git a/packages/docs/content/docs/features/meta.json b/packages/docs/content/docs/features/meta.json new file mode 100644 index 0000000..4725321 --- /dev/null +++ b/packages/docs/content/docs/features/meta.json @@ -0,0 +1,9 @@ +{ + "title": "Features", + "pages": [ + "index", + "authentication", + "java", + "mod-loaders" + ] +} diff --git a/packages/docs/content/docs/features/mod-loaders.mdx b/packages/docs/content/docs/features/mod-loaders.mdx new file mode 100644 index 0000000..a9616d6 --- /dev/null +++ b/packages/docs/content/docs/features/mod-loaders.mdx @@ -0,0 +1,410 @@ +--- +title: Mod Loaders +description: Fabric and Forge installation and management +--- + +# Mod Loaders + +DropOut supports the two most popular Minecraft mod loaders: Fabric and Forge. Both can be easily installed and managed directly from the launcher. + +## Fabric Support + +### Overview + +Fabric is a lightweight, modular modding toolchain focused on: +- Fast updates to new Minecraft versions +- Clean, minimal API +- Strong developer community +- Excellent performance + +### Installation + +1. Navigate to **Versions** tab +2. Click **"Install Fabric"** +3. Select Minecraft version +4. Choose Fabric loader version +5. Click **"Install"** +6. Wait for installation to complete + +### 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": [...] +} +``` + +### Fabric Versions + +**Loader Versions:** +- Latest stable (recommended) +- Specific versions for compatibility +- Beta/snapshot versions + +**Game Versions:** +- All Minecraft versions from 1.14+ +- Snapshots supported +- Combat Test versions + +### 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 API + +Fabric Loader ≠ Fabric API: +- **Fabric Loader**: Mod loader (installed by DropOut) +- **Fabric API**: Library mod (download separately) + +Many mods require Fabric API: +1. Download from [Modrinth](https://modrinth.com/mod/fabric-api) or [CurseForge](https://www.curseforge.com/minecraft/mc-mods/fabric-api) +2. Place in instance's `mods/` folder + +## Forge Support + +### Overview + +Forge is the original and most popular Minecraft mod loader: +- Extensive mod ecosystem +- Mature API +- Wide version support +- Large community + +### Installation + +1. Navigate to **Versions** tab +2. Click **"Install Forge"** +3. Select Minecraft version +4. Choose Forge version +5. Click **"Install"** +6. Wait for installer to run +7. Installation complete + +### How It Works + +**Forge Installer:** +```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 +``` + +**Profile Parsing:** +1. Forge installer creates version JSON +2. DropOut parses install profile +3. Extracts library dependencies +4. Processes processors (if any) +5. Generates launcher profile + +**Version Format:** +```json +{ + "id": "1.20.4-forge-49.0.26", + "inheritsFrom": "1.20.4", + "mainClass": "cpw.mods.bootstraplauncher.BootstrapLauncher", + "libraries": [...] +} +``` + +### Forge Versions + +**Release Types:** +- **Latest**: Most recent stable +- **Recommended**: Most stable for production +- **Specific**: Version-locked for compatibility + +**Minecraft Version Support:** +- Legacy versions (1.6.4+) +- Modern versions (1.13+) +- Latest versions (1.20+) + +### Library Management + +Forge has many libraries: + +**Core Libraries:** +- `net.minecraftforge:forge:` +- `net.minecraftforge:fmlloader:` +- `org.ow2.asm:asm:` + +**Resolution:** +```rust +// Forge Maven +"https://maven.minecraftforge.net/" + +// Dependencies may use: +// - Maven Central +// - Minecraft Libraries +``` + +### Forge Processors + +Some Forge versions run "processors" during installation: +- Bytecode manipulation +- Library patching +- Mapping generation + +DropOut handles these automatically. + +## Version Inheritance + +Both Fabric and Forge use Minecraft's inheritance system: + +### 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 +``` + +## Comparison + +| Feature | Fabric | Forge | +|---------|--------|-------| +| **Performance** | Excellent | Good | +| **Update Speed** | Very Fast | Moderate | +| **Mod Selection** | Growing | Extensive | +| **API Simplicity** | Simple | Complex | +| **Version Support** | 1.14+ | 1.6.4+ | +| **Developer Friendly** | Very | Moderate | +| **Stability** | Excellent | Excellent | + +## Installing Mods + +### Fabric Mods + +1. Create/select instance +2. Ensure Fabric is installed +3. Download mods from: + - [Modrinth](https://modrinth.com/) + - [CurseForge](https://www.curseforge.com/) + - [GitHub Releases](https://github.com/) +4. Place `.jar` files in `instances//mods/` +5. Launch game + +**Compatibility:** +- Check Minecraft version +- Check Fabric Loader version +- Check for Fabric API requirement +- Read mod dependencies + +### Forge Mods + +1. Create/select instance +2. Ensure Forge is installed +3. Download mods from: + - [CurseForge](https://www.curseforge.com/) + - [Modrinth](https://modrinth.com/) +4. Place `.jar` files in `instances//mods/` +5. Launch game + +**Compatibility:** +- Check Minecraft version exactly +- Check Forge version range +- Read mod dependencies +- Check for conflicts + +## Troubleshooting + +### Fabric Issues + +**"Fabric Loader not found"** +- Reinstall Fabric +- Check version JSON exists +- Verify libraries downloaded + +**"Mixin apply failed"** +- Mod incompatibility +- Remove conflicting mods +- Update Fabric Loader + +**"Fabric API required"** +- Download Fabric API +- Match Minecraft version +- Place in mods folder + +### Forge Issues + +**"Forge installer failed"** +- Verify Java installation +- Check disk space +- Try older Forge version +- Check logs for details + +**"Missing dependencies"** +- Install required mods +- Check mod version compatibility +- Read error message carefully + +**"Class not found"** +- Forge version mismatch +- Reinstall Forge +- Verify libraries downloaded + +### General Mod Issues + +**Crash on Launch:** +1. Check crash report +2. Identify problematic mod +3. Remove or update mod +4. Test with minimal mods +5. Add mods back incrementally + +**Performance Problems:** +1. Too many mods installed +2. Increase memory allocation +3. Install performance mods: + - Fabric: Sodium, Lithium + - Forge: OptiFine, Magnesium +4. Remove resource-heavy mods + +## API Reference + +### Tauri Commands + +**Install Fabric:** +```typescript +await invoke('install_fabric', { + minecraftVersion: '1.20.4', + loaderVersion: '0.15.0' +}); +``` + +**Install Forge:** +```typescript +await invoke('install_forge', { + minecraftVersion: '1.20.4', + forgeVersion: '49.0.26' +}); +``` + +**List Fabric Versions:** +```typescript +const versions = await invoke('get_fabric_versions', { + minecraftVersion: '1.20.4' +}); +``` + +**List Forge Versions:** +```typescript +const versions = await invoke('get_forge_versions', { + minecraftVersion: '1.20.4' +}); +``` + +### Events + +**Installation Progress:** +```typescript +listen('mod-loader-progress', (event) => { + const { stage, percent } = event.payload; + // Stages: "downloading", "installing", "processing", "complete" +}); +``` + +## Best Practices + +### For Players + +1. **Choose one mod loader** per instance +2. **Match versions exactly** - Minecraft and loader +3. **Read mod requirements** before installing +4. **Start small** - Add mods incrementally +5. **Backup worlds** before adding mods +6. **Check compatibility** lists +7. **Update cautiously** - Test in separate instance + +### For Modpack Creators + +1. **Document versions** - MC, loader, all mods +2. **Test thoroughly** - All features +3. **List dependencies** - Including API +4. **Provide changelog** - For updates +5. **Version lock** - For stability +6. **Include configs** - Pre-configured +7. **Test updates** - Before release + +## Future Features + +- **Mod browser** - Install mods from launcher +- **Automatic updates** - Keep mods current +- **Dependency resolution** - Auto-install requirements +- **Conflict detection** - Warn about incompatibilities +- **Profile export** - Share modpack configurations +- **CurseForge integration** - Direct modpack import +- **Modrinth integration** - Mod search and install + diff --git a/packages/docs/content/docs/getting-started.mdx b/packages/docs/content/docs/getting-started.mdx new file mode 100644 index 0000000..ac0fc1c --- /dev/null +++ b/packages/docs/content/docs/getting-started.mdx @@ -0,0 +1,162 @@ +--- +title: Getting Started +description: Quick start guide to using DropOut Minecraft Launcher +--- + +# Getting Started + +DropOut is a modern, reproducible, and developer-grade Minecraft launcher built with Tauri v2 and Rust. This guide will help you get started with installing and using DropOut. + +## Installation + +### Download Pre-built Binaries + +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` | + +### Linux Installation + +#### Using .deb Package +```bash +sudo dpkg -i dropout_*.deb +# Fix dependencies if needed +sudo apt-get install -f +``` + +#### Using AppImage +```bash +chmod +x dropout_*.AppImage +./dropout_*.AppImage +``` + +### macOS Installation + +1. Open the downloaded `.dmg` file +2. Drag DropOut to your Applications folder +3. If you see a security warning, go to System Preferences → Security & Privacy and allow the app + +### 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 + +## First Launch + +When you first launch DropOut, you'll need to: + +1. **Choose Authentication Method** + - **Microsoft Account**: Recommended for official Minecraft + - **Offline Mode**: For testing or offline play + +2. **Configure Java Runtime** + - DropOut will automatically detect installed Java versions + - You can download Java directly from the launcher if needed + +3. **Select Minecraft Version** + - Browse available Minecraft versions + - Choose vanilla or modded versions (Fabric/Forge) + +## Quick Start Tutorial + +### 1. Login + + + + + + +**Microsoft Login:** +1. Click "Login with Microsoft" +2. A device code will be displayed +3. Visit the URL shown and enter the code +4. Authorize the application +5. Return to DropOut - you'll be logged in automatically + +**Offline Login:** +1. Click "Offline Mode" +2. Enter a username +3. Click "Create Account" + +### 2. Install Minecraft + +1. Navigate to the **Versions** tab +2. Browse available Minecraft versions +3. Click on a version to install it +4. Wait for the download to complete + +### 3. Launch the Game + +1. Go to the **Home** tab +2. Select your desired version from the dropdown +3. Adjust settings if needed: + - Memory allocation (RAM) + - Window resolution + - Java path +4. Click **"Launch Game"** +5. Monitor the launch process in the console + +## Next Steps + + + + + + + + +## 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 +- **Java**: Java 17 or 21 (managed by DropOut) + +## 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/docs/index.mdx b/packages/docs/content/docs/index.mdx index 6c2e629..97e6228 100644 --- a/packages/docs/content/docs/index.mdx +++ b/packages/docs/content/docs/index.mdx @@ -1,32 +1,95 @@ --- -title: Hello World -description: | - Your first `document` - You'll love it! +title: Welcome to DropOut +description: Modern, reproducible, and developer-grade Minecraft launcher --- -Hey there! Fumadocs is the docs framework that also works on React Router! +# Welcome to DropOut -## Heading +DropOut is a modern Minecraft launcher built with Tauri v2 and Rust, designed for players who value control, transparency, and long-term stability. -Hello World +
+ DropOut Launcher +
+ +## Why DropOut? + +Most Minecraft launchers focus on getting you into the game. DropOut focuses on keeping your game **stable**, **debuggable**, and **reproducible**. + +- Your instance worked yesterday but broke today? → **DropOut makes it traceable.** +- Sharing a modpack means zipping gigabytes? → **DropOut shares exact dependency manifests.** +- Java, loader, mods, configs drift out of sync? → **DropOut locks them together.** + +This launcher is built for players who value control, transparency, and long-term stability. + +## Quick Links - - + + + + -```ts -console.log('I love React!'); -``` +## Key Features + +### 🚀 High Performance +Built with Rust and Tauri for minimal resource usage and fast startup times. + +### 🎨 Modern UI +Clean, distraction-free interface with Svelte 5, Tailwind CSS 4, and particle effects. + +### 🔐 Secure Authentication +Microsoft OAuth 2.0 with device code flow and offline authentication support. + +### 🔧 Mod Loader Support +Built-in installation for Fabric and Forge with automatic version management. + +### ☕ Java Management +Automatic detection of installed Java versions and integrated downloader for Adoptium JDK/JRE. -### Heading +### 📦 Instance System +Isolated game environments with independent configurations, mods, and saves. -#### Heading +### 🤖 AI Assistant +Built-in AI helper for troubleshooting, configuration, and guidance. + +### ⚡ Fast Downloads +Concurrent asset and library downloads with resume support and progress tracking. + +## Technology Stack + +- **Backend**: Rust with Tauri v2 +- **Frontend**: Svelte 5 with runes +- **Styling**: Tailwind CSS 4 +- **Build Tool**: Vite with Rolldown +- **Documentation**: Fumadocs with React Router + +## Community + +- **GitHub**: [HydroRoll-Team/DropOut](https://github.com/HydroRoll-Team/DropOut) +- **Issues**: [Report bugs](https://github.com/HydroRoll-Team/DropOut/issues) +- **Roadmap**: [View development roadmap](https://roadmap.sh/r/minecraft-launcher-dev) + +## License + +DropOut is open source software licensed under the MIT License. + +--- -| Head | Description | -| ------------------------------- | ----------------------------------- | -| `hello` | Hello World | -| very **important** | Hey | -| _Surprisingly_ | Fumadocs | -| very long text that looks weird | hello world hello world hello world | +Ready to get started? Check out the [Getting Started Guide](/docs/getting-started)! diff --git a/packages/docs/content/docs/meta.json b/packages/docs/content/docs/meta.json index bc00362..8ad7ea2 100644 --- a/packages/docs/content/docs/meta.json +++ b/packages/docs/content/docs/meta.json @@ -1,3 +1,19 @@ { - "pages": ["index", "..."] + "title": "Documentation", + "pages": [ + "index", + "getting-started", + "architecture", + { + "title": "Features", + "pages": [ + "features/index", + "features/authentication", + "features/java", + "features/mod-loaders" + ] + }, + "development", + "troubleshooting" + ] } diff --git a/packages/docs/content/docs/test.mdx b/packages/docs/content/docs/test.mdx deleted file mode 100644 index cac4d26..0000000 --- a/packages/docs/content/docs/test.mdx +++ /dev/null @@ -1,24 +0,0 @@ ---- -title: Test -description: A document to test Fumadocs ---- - -Hey there! - -## Cards - - - - - - -### CodeBlock - -```js -console.log('Hello World'); -``` - -#### List - -- Hello -- World diff --git a/packages/docs/content/docs/troubleshooting.mdx b/packages/docs/content/docs/troubleshooting.mdx new file mode 100644 index 0000000..33464d2 --- /dev/null +++ b/packages/docs/content/docs/troubleshooting.mdx @@ -0,0 +1,524 @@ +--- +title: Troubleshooting +description: Common issues and solutions for DropOut launcher +--- + +# Troubleshooting + +This guide covers common issues and their solutions. If you don't find your issue here, please [open an issue](https://github.com/HydroRoll-Team/DropOut/issues) on GitHub. + +## Installation Issues + +### Linux: Missing Dependencies + +**Issue:** Error about missing libraries during installation + +**Solution:** +```bash +# Ubuntu/Debian +sudo apt update +sudo apt install libwebkit2gtk-4.1-0 libgtk-3-0 + +# Fedora +sudo dnf install webkit2gtk4.1 gtk3 + +# Arch +sudo pacman -S webkit2gtk gtk3 +``` + +### macOS: "App is damaged" + +**Issue:** macOS says DropOut is damaged and can't be opened + +**Solution:** +1. Open Terminal +2. Run: `xattr -cr /Applications/DropOut.app` +3. Try opening again +4. Or: System Preferences → Security → Allow anyway + +### Windows: SmartScreen Warning + +**Issue:** Windows SmartScreen blocks the installer + +**Solution:** +1. Click "More info" +2. Click "Run anyway" +3. This is normal for new apps without extended validation certificates + +## Authentication Issues + +### Microsoft Login Fails + +**Issue:** Can't complete Microsoft login + +**Possible causes and solutions:** + +**1. Device code expired:** +- Codes expire after 15 minutes +- Start the login process again +- Complete authorization faster + +**2. Network issues:** +- Check internet connection +- Disable VPN temporarily +- Check firewall settings +- Try different network + +**3. Microsoft account issues:** +- Verify account owns Minecraft Java Edition +- Check at https://www.minecraft.net/profile +- Ensure account is not suspended + +**4. Browser problems:** +- Try different browser +- Clear browser cache +- Disable ad blockers +- Use incognito/private mode + +### Token Refresh Fails + +**Issue:** Token refresh fails, must re-login frequently + +**Solution:** +1. Log out completely +2. Delete `accounts.json` from app data directory +3. Log in again +4. If persists, check Microsoft account status + +### Offline Login Not Working + +**Issue:** Can't create offline account + +**Solution:** +- Username must be 3-16 characters +- Use only letters, numbers, underscore +- No special characters +- No spaces + +## Game Launch Issues + +### Java Not Found + +**Issue:** "No Java installation found" + +**Solutions:** + +**1. Auto-detect existing Java:** +- Settings → Java → Detect Installations +- If found, select it +- If not found, proceed to step 2 + +**2. Download Java via DropOut:** +- Settings → Java → Download Java +- Select appropriate version: + - Java 8 for Minecraft 1.12.2 and older + - Java 17 for Minecraft 1.18-1.20.4 + - Java 21 for Minecraft 1.20.5+ + +**3. Manual Java installation:** +- Download from [Adoptium](https://adoptium.net/) +- Install to system +- Restart DropOut +- Detect again + +### Wrong Java Version + +**Issue:** Game crashes with "Unsupported class file version" + +**Solution:** +Match Java version to Minecraft version: + +| Minecraft Version | Java Version | +|-------------------|--------------| +| 1.7.10 and older | Java 8 | +| 1.8 - 1.12.2 | Java 8 | +| 1.13 - 1.16.5 | Java 8 or 11 | +| 1.17 - 1.17.1 | Java 16 | +| 1.18 - 1.20.4 | Java 17 | +| 1.20.5+ | Java 21 | + +### OutOfMemoryError + +**Issue:** Game crashes with `java.lang.OutOfMemoryError` + +**Solutions:** + +**1. Increase memory allocation:** +- Settings → Memory +- Increase Maximum Memory: + - Vanilla: 4GB minimum + - Light mods: 6GB + - Heavy modpacks: 8-12GB +- Don't exceed 80% of system RAM + +**2. Use 64-bit Java:** +- Check current Java architecture +- Download 64-bit Java if needed +- 32-bit Java limited to ~2GB + +**3. Reduce render distance:** +- In-game Video Settings +- Lower render distance to 8-12 chunks + +**4. Optimize JVM arguments:** +```bash +-Xms4G -Xmx8G -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions +``` + +### Game Won't Start + +**Issue:** Game doesn't launch, no error message + +**Check:** + +**1. Log output:** +- Check game console in DropOut +- Look for error messages +- Common issues: + - Missing files + - Corrupted downloads + - Mod conflicts + +**2. Verify files:** +- Delete version folder +- Re-download version +- Try vanilla first before modded + +**3. Check permissions:** +- Ensure DropOut can write to game directory +- Check folder permissions +- On Linux: `chmod -R 755 ~/.local/share/com.dropout.launcher` + +## Download Issues + +### Downloads Fail + +**Issue:** Asset or library downloads fail + +**Solutions:** + +**1. Network issues:** +- Check internet connection +- Disable VPN +- Try different network +- Check firewall/antivirus + +**2. Resume downloads:** +- DropOut auto-resumes interrupted downloads +- Close and reopen DropOut +- Downloads should continue + +**3. Clear download cache:** +- Delete `.part` files in libraries/assets +- Restart download + +**4. Manually download:** +- Check logs for failing URL +- Download file manually +- Place in correct location + +### Slow Downloads + +**Issue:** Downloads are very slow + +**Solutions:** + +**1. Adjust thread count:** +- Settings → Downloads +- Try different thread counts: + - Too low: slow overall + - Too high: connection throttling + - Recommended: 5-10 threads + +**2. Network optimization:** +- Close bandwidth-heavy apps +- Use wired connection if possible +- Check for ISP throttling + +**3. Alternative CDN:** +- Mojang mirrors may be slow +- Try at different time of day + +## Mod Loader Issues + +### Fabric Installation Fails + +**Issue:** Can't install Fabric loader + +**Solutions:** + +**1. Check Minecraft version:** +- Fabric supports 1.14+ +- Older versions not supported +- Try newer Minecraft version + +**2. Network issues:** +- Check internet connection +- Fabric Meta API may be down +- Try again later + +**3. Manual installation:** +- Download Fabric from [fabricmc.net](https://fabricmc.net/) +- Use official installer +- Import profile to DropOut + +### Forge Installation Fails + +**Issue:** Forge installer fails or hangs + +**Solutions:** + +**1. Java version:** +- Ensure correct Java version +- Forge 1.17+ requires Java 16+ +- Older Forge may need Java 8 + +**2. Installer timeout:** +- Forge installer can be slow +- Wait up to 10 minutes +- Check logs for progress + +**3. Disk space:** +- Ensure sufficient free space +- Forge needs ~1GB temporarily +- Check `/tmp` on Linux + +**4. Manual installation:** +- Download Forge installer from [minecraftforge.net](https://files.minecraftforge.net/) +- Run installer manually +- Select install client +- Import profile + +### Mod Crashes + +**Issue:** Game crashes with mods installed + +**Solutions:** + +**1. Check compatibility:** +- Verify mod is for correct Minecraft version +- Check mod loader version requirements +- Read mod description for dependencies + +**2. Install dependencies:** +- Fabric mods often need Fabric API +- Some mods require libraries +- Check crash log for "missing" errors + +**3. Remove conflicting mods:** +- Disable mods one by one +- Identify problematic mod +- Check for known conflicts +- Update or replace mod + +**4. Update mods:** +- Use latest mod versions +- Check mod update notes +- Some updates fix crashes + +## Performance Issues + +### Low FPS + +**Issue:** Game runs slowly or stutters + +**Solutions:** + +**1. Allocate more memory:** +- Increase max memory to 6-8GB +- Don't over-allocate (causes GC pauses) + +**2. Install performance mods:** +- **Fabric**: Sodium, Lithium, Phosphor +- **Forge**: OptiFine, Magnesium, Rubidium + +**3. Optimize settings:** +- Lower render distance +- Disable fancy graphics +- Turn off particles +- Disable VSync if fps < 60 + +**4. Update graphics drivers:** +- Download latest from manufacturer +- NVIDIA: GeForce Experience +- AMD: Adrenalin +- Intel: Graphics Command Center + +**5. Close background apps:** +- Free up system resources +- Disable overlays (Discord, etc.) +- Check Task Manager for CPU/RAM hogs + +### Launcher Slow to Start + +**Issue:** DropOut takes long time to launch + +**Solutions:** + +**1. Check system resources:** +- Close unnecessary programs +- Ensure sufficient RAM available +- Check CPU usage + +**2. Antivirus interference:** +- Add DropOut to exceptions +- Temporarily disable to test +- Some AVs slow down significantly + +**3. Corrupted data:** +- Delete `cache` folder in app data +- Restart DropOut +- Will rebuild cache + +## UI Issues + +### Window Won't Open + +**Issue:** DropOut window doesn't appear + +**Solutions:** + +**1. Check if running:** +```bash +# Linux/macOS +ps aux | grep dropout + +# Windows +tasklist | findstr dropout +``` + +**2. Kill and restart:** +```bash +# Linux/macOS +pkill dropout + +# Windows +taskkill /F /IM dropout.exe +``` + +**3. Reset window position:** +- Delete window state config +- Restart DropOut + +### Graphics Glitches + +**Issue:** UI looks wrong or has visual artifacts + +**Solutions:** + +**1. Update graphics drivers:** +- Install latest drivers +- Restart system + +**2. Disable hardware acceleration:** +- Check if option exists in settings +- May reduce performance but fix glitches + +**3. Try different monitor:** +- Multi-monitor setups can cause issues +- Try on different display + +## File System Issues + +### Can't Access Game Directory + +**Issue:** Errors accessing game files + +**Solutions:** + +**1. Check permissions:** +```bash +# Linux +chmod -R 755 ~/.local/share/com.dropout.launcher + +# macOS +chmod -R 755 ~/Library/Application\ Support/com.dropout.launcher +``` + +**2. Check disk space:** +- Ensure sufficient free space +- Minecraft needs 2-10GB depending on mods +- Clean up old versions + +**3. Antivirus blocking:** +- Add game directory to exceptions +- Some AVs block file access + +### Corrupted Files + +**Issue:** Files appear corrupted or invalid + +**Solutions:** + +**1. Verify checksums:** +- DropOut verifies SHA1/SHA256 +- Failed verification triggers re-download + +**2. Re-download:** +- Delete corrupted file +- Launch version again +- DropOut will re-download + +**3. Clear cache:** +- Delete version folder entirely +- Re-install from scratch + +## Getting More Help + +### Collect Debug Information + +When reporting issues, include: + +**1. System information:** +- OS and version +- DropOut version +- Java version + +**2. Logs:** +- Launcher logs from console +- Game logs if applicable +- Error messages (full text) + +**3. Steps to reproduce:** +- What you did +- What you expected +- What actually happened + +**4. Screenshots:** +- Error messages +- UI issues +- Settings screens + +### Report Issues + +1. Search [existing issues](https://github.com/HydroRoll-Team/DropOut/issues) +2. If not found, [create new issue](https://github.com/HydroRoll-Team/DropOut/issues/new) +3. Use issue template +4. Provide all requested information +5. Be patient and responsive + +### Community Support + +- **GitHub Discussions**: Ask questions +- **Discord**: Real-time help (if available) +- **Documentation**: Check all guides + +## Known Issues + +### Currently Being Worked On + +- Multi-account switching (in progress) +- Custom game directory selection (planned) +- Launcher auto-update (planned) + +### Workarounds Available + +**Issue**: Can't switch between accounts easily +**Workaround**: Log out and log in with different account + +**Issue**: No built-in mod manager +**Workaround**: Manually manage mods in instance folder + +**Issue**: Can't import from other launchers +**Workaround**: Manually copy instance files + From 8254559aefad444532fefdf8b8f9b3117132c442 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 21 Jan 2026 13:23:03 +0000 Subject: [PATCH 03/18] docs: add Chinese translations for documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add development.mdx (开发指南) - Add troubleshooting.mdx (故障排除) - Add features/index.mdx (功能概览) - Add features/authentication.mdx (身份验证) - Add features/java.mdx (Java 管理) - Add features/mod-loaders.mdx (模组加载器) All translations maintain technical terms in English while translating content to simplified Chinese Co-authored-by: HsiangNianian <44714368+HsiangNianian@users.noreply.github.com> --- packages/docs/app/lib/source.ts | 10 + .../content/docs/{ => en}/architecture.mdx | 0 .../content/docs/{ => en}/development.mdx | 0 .../docs/{ => en}/features/authentication.mdx | 0 .../content/docs/{ => en}/features/index.mdx | 0 .../content/docs/{ => en}/features/java.mdx | 0 .../content/docs/{ => en}/features/meta.json | 0 .../docs/{ => en}/features/mod-loaders.mdx | 0 .../content/docs/{ => en}/getting-started.mdx | 0 packages/docs/content/docs/{ => en}/index.mdx | 0 packages/docs/content/docs/{ => en}/meta.json | 0 .../content/docs/{ => en}/troubleshooting.mdx | 0 .../docs/content/docs/zh/architecture.mdx | 282 +++++++++ packages/docs/content/docs/zh/development.mdx | 546 ++++++++++++++++++ .../docs/zh/features/authentication.mdx | 267 +++++++++ .../docs/content/docs/zh/features/index.mdx | 178 ++++++ .../docs/content/docs/zh/features/java.mdx | 394 +++++++++++++ .../docs/content/docs/zh/features/meta.json | 9 + .../content/docs/zh/features/mod-loaders.mdx | 410 +++++++++++++ .../docs/content/docs/zh/getting-started.mdx | 162 ++++++ packages/docs/content/docs/zh/index.mdx | 95 +++ packages/docs/content/docs/zh/meta.json | 19 + .../docs/content/docs/zh/troubleshooting.mdx | 523 +++++++++++++++++ packages/docs/source.config.ts | 1 + 24 files changed, 2896 insertions(+) rename packages/docs/content/docs/{ => en}/architecture.mdx (100%) rename packages/docs/content/docs/{ => en}/development.mdx (100%) rename packages/docs/content/docs/{ => en}/features/authentication.mdx (100%) rename packages/docs/content/docs/{ => en}/features/index.mdx (100%) rename packages/docs/content/docs/{ => en}/features/java.mdx (100%) rename packages/docs/content/docs/{ => en}/features/meta.json (100%) rename packages/docs/content/docs/{ => en}/features/mod-loaders.mdx (100%) rename packages/docs/content/docs/{ => en}/getting-started.mdx (100%) rename packages/docs/content/docs/{ => en}/index.mdx (100%) rename packages/docs/content/docs/{ => en}/meta.json (100%) rename packages/docs/content/docs/{ => en}/troubleshooting.mdx (100%) create mode 100644 packages/docs/content/docs/zh/architecture.mdx create mode 100644 packages/docs/content/docs/zh/development.mdx create mode 100644 packages/docs/content/docs/zh/features/authentication.mdx create mode 100644 packages/docs/content/docs/zh/features/index.mdx create mode 100644 packages/docs/content/docs/zh/features/java.mdx create mode 100644 packages/docs/content/docs/zh/features/meta.json create mode 100644 packages/docs/content/docs/zh/features/mod-loaders.mdx create mode 100644 packages/docs/content/docs/zh/getting-started.mdx create mode 100644 packages/docs/content/docs/zh/index.mdx create mode 100644 packages/docs/content/docs/zh/meta.json create mode 100644 packages/docs/content/docs/zh/troubleshooting.mdx diff --git a/packages/docs/app/lib/source.ts b/packages/docs/app/lib/source.ts index 97cf767..a8b5f50 100644 --- a/packages/docs/app/lib/source.ts +++ b/packages/docs/app/lib/source.ts @@ -1,7 +1,17 @@ import { loader } from 'fumadocs-core/source'; +import { createI18nProvider } from 'fumadocs-ui/i18n'; import { docs } from 'fumadocs-mdx:collections/server'; +export const { utils: i18n } = createI18nProvider({ + languages: [ + { name: 'English', locale: 'en' }, + { name: '简体中文', locale: 'zh' }, + ], + defaultLanguage: 'en', +}); + export const source = loader({ source: docs.toFumadocsSource(), baseUrl: '/docs', + i18n, }); diff --git a/packages/docs/content/docs/architecture.mdx b/packages/docs/content/docs/en/architecture.mdx similarity index 100% rename from packages/docs/content/docs/architecture.mdx rename to packages/docs/content/docs/en/architecture.mdx diff --git a/packages/docs/content/docs/development.mdx b/packages/docs/content/docs/en/development.mdx similarity index 100% rename from packages/docs/content/docs/development.mdx rename to packages/docs/content/docs/en/development.mdx diff --git a/packages/docs/content/docs/features/authentication.mdx b/packages/docs/content/docs/en/features/authentication.mdx similarity index 100% rename from packages/docs/content/docs/features/authentication.mdx rename to packages/docs/content/docs/en/features/authentication.mdx diff --git a/packages/docs/content/docs/features/index.mdx b/packages/docs/content/docs/en/features/index.mdx similarity index 100% rename from packages/docs/content/docs/features/index.mdx rename to packages/docs/content/docs/en/features/index.mdx diff --git a/packages/docs/content/docs/features/java.mdx b/packages/docs/content/docs/en/features/java.mdx similarity index 100% rename from packages/docs/content/docs/features/java.mdx rename to packages/docs/content/docs/en/features/java.mdx diff --git a/packages/docs/content/docs/features/meta.json b/packages/docs/content/docs/en/features/meta.json similarity index 100% rename from packages/docs/content/docs/features/meta.json rename to packages/docs/content/docs/en/features/meta.json diff --git a/packages/docs/content/docs/features/mod-loaders.mdx b/packages/docs/content/docs/en/features/mod-loaders.mdx similarity index 100% rename from packages/docs/content/docs/features/mod-loaders.mdx rename to packages/docs/content/docs/en/features/mod-loaders.mdx diff --git a/packages/docs/content/docs/getting-started.mdx b/packages/docs/content/docs/en/getting-started.mdx similarity index 100% rename from packages/docs/content/docs/getting-started.mdx rename to packages/docs/content/docs/en/getting-started.mdx diff --git a/packages/docs/content/docs/index.mdx b/packages/docs/content/docs/en/index.mdx similarity index 100% rename from packages/docs/content/docs/index.mdx rename to packages/docs/content/docs/en/index.mdx diff --git a/packages/docs/content/docs/meta.json b/packages/docs/content/docs/en/meta.json similarity index 100% rename from packages/docs/content/docs/meta.json rename to packages/docs/content/docs/en/meta.json diff --git a/packages/docs/content/docs/troubleshooting.mdx b/packages/docs/content/docs/en/troubleshooting.mdx similarity index 100% rename from packages/docs/content/docs/troubleshooting.mdx rename to packages/docs/content/docs/en/troubleshooting.mdx diff --git a/packages/docs/content/docs/zh/architecture.mdx b/packages/docs/content/docs/zh/architecture.mdx new file mode 100644 index 0000000..44066ad --- /dev/null +++ b/packages/docs/content/docs/zh/architecture.mdx @@ -0,0 +1,282 @@ +--- +title: 架构设计 +description: DropOut Minecraft 启动器的技术架构和设计 +--- + +# 架构设计 + +DropOut 采用现代技术栈构建,旨在实现高性能、安全性和跨平台兼容性。 + +## 技术栈 + +### 后端(Rust) +- **框架**: Tauri v2 +- **语言**: Rust(Edition 2021) +- **异步运行时**: Tokio +- **HTTP 客户端**: reqwest with native-tls + +### 前端(Svelte) +- **框架**: Svelte 5(with runes) +- **样式**: Tailwind CSS 4 +- **构建工具**: Vite with Rolldown +- **包管理器**: pnpm + +### 文档 +- **框架**: Fumadocs with React Router v7 +- **内容**: MDX 文件 +- **样式**: Tailwind CSS 4 + +## 系统架构 + +``` +┌─────────────────────────────────────────────────────────┐ +│ 前端(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 │ + └──────────┘ └────────────┘ └────────────┘ +``` + +## 核心组件 + +### 前端状态管理 + +DropOut 使用 **Svelte 5 runes** 进行响应式状态管理: + +```typescript +// stores/auth.svelte.ts +export class AuthState { + currentAccount = $state(null); // 响应式 + isLoginModalOpen = $state(false); + + $effect(() => { // 副作用 + // 依赖变化时自动运行 + }); +} +``` + +**关键 Stores:** +- `auth.svelte.ts`: 认证状态和登录流程 +- `settings.svelte.ts`: 启动器设置和 Java 检测 +- `game.svelte.ts`: 游戏运行状态和日志 +- `instances.svelte.ts`: 实例管理 +- `ui.svelte.ts`: UI 状态(提示、模态框、活动视图) + +### 后端架构 + +#### 命令模式 +所有 Tauri 命令遵循此结构: + +```rust +#[tauri::command] +async fn command_name( + window: Window, + state: State<'_, SomeState>, + param: Type, +) -> Result { + emit_log!(window, "状态消息"); + // 异步逻辑 + Ok(result) +} +``` + +#### 事件通信 + +**Rust → 前端(进度更新):** +```rust +window.emit("launcher-log", "正在下载...")?; +window.emit("download-progress", progress_struct)?; +``` + +**前端 → Rust(命令):** +```typescript +import { invoke } from "@tauri-apps/api/core"; +const result = await invoke("start_game", { versionId: "1.20.4" }); +``` + +### 核心模块 + +#### 认证(`core/auth.rs`) +- **微软 OAuth 2.0**: 设备代码流 +- **离线认证**: 本地 UUID 生成 +- **令牌管理**: 刷新令牌存储和自动刷新 +- **Xbox Live 集成**: 完整认证链 + +**认证流程:** +1. 设备代码请求 → MS 令牌 +2. Xbox Live 认证 +3. XSTS 授权 +4. Minecraft 令牌交换 +5. 配置文件获取 + +#### 下载器(`core/downloader.rs`) +- **并发下载**: 可配置线程池 +- **断点续传**: `.part` 和 `.part.meta` 文件 +- **多段下载**: 大文件分割成块 +- **校验和验证**: SHA1/SHA256 验证 +- **进度跟踪**: 实时事件到前端 + +#### Java 管理(`core/java.rs`) +- **自动检测**: 扫描系统路径 +- **Adoptium 集成**: 按需下载 JDK/JRE +- **目录缓存**: 版本列表 24 小时缓存 +- **安装**: 提取到应用数据目录 +- **取消**: 下载取消的原子标志 + +#### Fabric 支持(`core/fabric.rs`) +- **Meta API 集成**: 获取加载器版本 +- **配置文件生成**: 创建版本 JSON +- **库解析**: Maven 构件处理 + +#### Forge 支持(`core/forge.rs`) +- **安装程序执行**: 运行 Forge 安装程序 +- **配置文件解析**: 提取安装配置文件 +- **库管理**: 处理 Forge 特定库 + +#### 实例系统(`core/instance.rs`) +- **隔离**: 每个实例独立目录 +- **配置**: 每个实例的设置 +- **模组管理**: 实例特定模组 +- **版本锁定**: 可复现环境 + +#### 版本管理 +- **清单解析**(`manifest.rs`): Mojang 版本清单 +- **继承系统**(`version_merge.rs`): 父版本合并 +- **游戏版本**(`game_version.rs`): JSON 解析和验证 +- **规则引擎**(`rules.rs`): 操作系统/功能条件逻辑 + +### 文件结构 + +``` +~/.local/share/com.dropout.launcher/ (Linux) +~/Library/Application Support/com.dropout.launcher/ (macOS) +%APPDATA%/com.dropout.launcher/ (Windows) +├── versions/ +│ └── / +│ ├── .json +│ ├── .jar +│ └── natives/ +├── libraries/ +│ └── / +├── assets/ +│ ├── indexes/ +│ └── objects/ +├── instances/ +│ └── / +│ ├── mods/ +│ ├── config/ +│ └── saves/ +├── java/ +│ └── / +├── config.json +└── accounts.json +``` + +## 数据流 + +### 游戏启动序列 + +1. **前端**: 用户点击"启动游戏" +2. **命令**: 调用 `start_game(version_id)` +3. **后端处理**: + - 加载版本 JSON(带继承) + - 解析所有库 + - 下载缺少的资源 + - 提取原生库 + - 构建类路径 + - 构造 JVM 参数 + - 替换占位符 +4. **进程生成**: 使用参数启动 Java +5. **流日志**: 向前端发送 stdout/stderr +6. **监视**: 跟踪游戏进程状态 + +### 下载流程 + +1. **队列创建**: 要下载的文件列表 +2. **并发处理**: 信号量限制线程 +3. **恢复检查**: 验证现有 `.part` 文件 +4. **下载**: 大文件多段 +5. **验证**: 校验和验证 +6. **进度事件**: 实时更新到 UI +7. **完成**: 从 `.part` 移动到最终位置 + +### 认证流程 + +1. **设备代码请求**: 获取用户代码 + 设备代码 +2. **用户授权**: 用户访问 URL 并输入代码 +3. **令牌轮询**: 前端轮询完成 +4. **令牌交换**: MS 令牌 → Xbox → XSTS → Minecraft +5. **配置文件获取**: 获取用户名和 UUID +6. **存储**: 使用刷新令牌保存账户 +7. **自动刷新**: 过期时后台令牌刷新 + +## 平台特定考虑 + +### Linux +- 使用 GTK WebView(`webkit2gtk`) +- 从 `/usr/lib/jvm` 系统 Java 检测 +- 桌面文件集成 + +### macOS +- 使用系统 WebKit +- 应用程序包结构 +- 钥匙串集成用于安全存储 + +### Windows +- 使用 WebView2 运行时 +- 注册表 Java 检测 +- MSI 安装程序支持 +- 发布版本中无控制台窗口 + +## 性能优化 + +- **并发下载**: 并行资源/库下载 +- **延迟加载**: 按需加载版本清单 +- **缓存**: Java 目录、版本清单 +- **原生代码**: 用于 CPU 密集型操作的 Rust +- **异步 I/O**: 用于非阻塞操作的 Tokio + +## 安全功能 + +- **令牌加密**: 安全存储认证令牌 +- **仅 HTTPS**: 所有外部 API 调用 +- **校验和验证**: 文件完整性验证 +- **沙箱执行**: Tauri 安全模型 +- **无任意代码**: 无 eval 或动态代码执行 + diff --git a/packages/docs/content/docs/zh/development.mdx b/packages/docs/content/docs/zh/development.mdx new file mode 100644 index 0000000..6ba5b1d --- /dev/null +++ b/packages/docs/content/docs/zh/development.mdx @@ -0,0 +1,546 @@ +--- +title: 开发指南 +description: 从源代码构建、测试和贡献 DropOut +--- + +# 开发指南 + +本指南将帮助你设置开发环境、从源代码构建 DropOut,以及为项目做出贡献。 + +## 前置要求 + +### 必需软件 + +1. **Rust** (最新稳定版) + ```bash + # 通过 rustup 安装 + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + ``` + +2. **Node.js** (v22+) 和 **pnpm** (v9+) + ```bash + # 从 https://nodejs.org/ 安装 Node.js + # 安装 pnpm + npm install -g pnpm@9 + ``` + +3. **系统依赖** + + 按照你的平台参考 [Tauri 前置要求](https://v2.tauri.app/start/prerequisites/): + + **Linux (Debian/Ubuntu):** + ```bash + sudo apt update + sudo apt install libwebkit2gtk-4.1-dev \ + build-essential \ + curl \ + wget \ + file \ + libssl-dev \ + libayatana-appindicator3-dev \ + librsvg2-dev + ``` + + **macOS:** + ```bash + xcode-select --install + ``` + + **Windows:** + - 安装 [Microsoft Visual C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) + - 安装 [WebView2](https://developer.microsoft.com/microsoft-edge/webview2/) + +## 快速开始 + +### 克隆仓库 + +```bash +git clone https://github.com/HydroRoll-Team/DropOut.git +cd DropOut +``` + +### 安装依赖 + +**前端依赖:** +```bash +cd packages/ui +pnpm install +cd ../.. +``` + +**文档依赖:** +```bash +cd packages/docs +pnpm install +cd ../.. +``` + +### 开发模式 + +以开发模式运行 DropOut,支持热重载: + +```bash +cargo tauri dev +``` + +这将: +1. 启动前端开发服务器(Vite 在 5173 端口) +2. 编译 Rust 后端 +3. 打开 Tauri 窗口 +4. 为前端更改启用热重载 +5. 在 Rust 文件更改时重新编译 + +**终端输出:** +- 来自 Vite 的前端日志 +- Rust 标准输出/标准错误 +- 编译状态 + +### 构建生产版本 + +构建发布二进制文件: + +```bash +cargo tauri build +``` + +**输出位置:** +- **Linux**: `src-tauri/target/release/bundle/` + - `.deb` 软件包 + - `.AppImage` 包 +- **macOS**: `src-tauri/target/release/bundle/` + - `.dmg` 安装器 + - `.app` 包 +- **Windows**: `src-tauri/target/release/bundle/` + - `.msi` 安装器 + - `.exe` 可执行文件 + +## 项目结构 + +``` +DropOut/ +├── src-tauri/ # Rust 后端 +│ ├── src/ +│ │ ├── main.rs # Tauri 命令和入口点 +│ │ ├── core/ # 核心模块 +│ │ │ ├── auth.rs # 身份验证 +│ │ │ ├── downloader.rs # 下载管理器 +│ │ │ ├── fabric.rs # Fabric 支持 +│ │ │ ├── forge.rs # Forge 支持 +│ │ │ ├── java.rs # Java 管理 +│ │ │ ├── instance.rs # 实例系统 +│ │ │ └── ... +│ │ └── utils/ # 工具类 +│ └── Cargo.toml +├── packages/ +│ ├── ui/ # Svelte 5 前端 +│ │ ├── src/ +│ │ │ ├── App.svelte +│ │ │ ├── components/ +│ │ │ ├── stores/ # 状态管理 +│ │ │ └── lib/ +│ │ └── package.json +│ └── docs/ # 文档站点 +│ ├── content/docs/ +│ └── package.json +├── .github/ +│ └── workflows/ # CI/CD 流水线 +└── scripts/ # 构建脚本 +``` + +## 开发工作流 + +### 前端开发 + +**启动开发服务器:** +```bash +cd packages/ui +pnpm dev +``` + +**类型检查:** +```bash +pnpm check +``` + +**代码检查:** +```bash +pnpm lint +``` + +**格式化代码:** +```bash +pnpm format +``` + +### 后端开发 + +**运行 Rust 测试:** +```bash +cargo test +``` + +**检查代码:** +```bash +cargo check +``` + +**格式化代码:** +```bash +cargo fmt +``` + +**代码检查:** +```bash +cargo clippy +``` + +### 文档开发 + +**启动文档开发服务器:** +```bash +cd packages/docs +pnpm dev +``` + +**构建文档:** +```bash +pnpm build +``` + +**类型检查:** +```bash +pnpm types:check +``` + +## 代码风格 + +### Rust + +遵循标准 Rust 约定: +- 使用 `cargo fmt` 格式化 +- 使用 `cargo clippy` 检查 +- 编写文档注释 (`///`) +- 正确处理错误 +- 对 I/O 使用 async/await + +**示例:** +```rust +/// Starts the Microsoft authentication device flow +#[tauri::command] +async fn start_microsoft_login( + window: Window, +) -> Result { + emit_log!(window, "Starting Microsoft login..."); + + start_device_flow() + .await + .map_err(|e| e.to_string()) +} +``` + +### TypeScript/Svelte + +遵循项目约定: +- 使用 Svelte 5 runes (`$state`, `$effect`) +- 优先使用 TypeScript 而非 JavaScript +- 使用 Biome 进行格式化和检查 +- 遵循组件结构 + +**示例:** +```typescript +// stores/auth.svelte.ts +export class AuthState { + currentAccount = $state(null); + isLoginModalOpen = $state(false); + + async login(username: string) { + const account = await invoke('offline_login', { username }); + this.currentAccount = account; + } +} +``` + +## 测试 + +### 单元测试 + +**Rust:** +```rust +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_generate_offline_uuid() { + let uuid = generate_offline_uuid("Player"); + assert!(uuid.len() > 0); + } +} +``` + +**运行:** +```bash +cargo test +``` + +### 集成测试 + +测试完整应用程序: +1. 以开发模式构建:`cargo tauri dev` +2. 手动测试功能 +3. 检查控制台错误 +4. 验证 UI 行为 + +### CI 测试 + +GitHub Actions 在以下平台运行测试: +- Ubuntu(最新版) +- Arch Linux(Wayland) +- Windows(最新版) +- macOS(ARM64) + +查看工作流:`.github/workflows/test.yml` + +## 调试 + +### 前端调试 + +1. 在 Tauri 窗口中打开开发工具:`Ctrl+Shift+I`(Windows/Linux)或 `Cmd+Option+I`(macOS) +2. 检查控制台错误 +3. 使用 React DevTools 或 Svelte DevTools +4. 监控网络标签页查看 API 调用 + +### 后端调试 + +**打印调试:** +```rust +emit_log!(window, format!("Debug: {}", value)); +println!("Debug: {}", value); +``` + +**Rust 调试器:** +```bash +# 安装 rust-lldb 或 rust-gdb +cargo install rust-gdb + +# 调试 +rust-gdb target/debug/dropout +``` + +### 日志 + +**前端:** +```typescript +console.log("Info message"); +console.error("Error message"); +``` + +**后端:** +```rust +emit_log!(window, "Status update"); +eprintln!("Error: {}", error); +``` + +## 贡献 + +### 贡献工作流 + +1. **Fork** 仓库 +2. **创建**功能分支: + ```bash + git checkout -b feature/my-feature + ``` +3. **进行**更改 +4. **彻底测试** +5. **提交**时使用约定式提交: + ```bash + git commit -m "feat: add new feature" + ``` +6. **推送**到你的 fork: + ```bash + git push origin feature/my-feature + ``` +7. **创建** Pull Request + +### 提交消息 + +遵循 [约定式提交](https://www.conventionalcommits.org/): + +**格式:** +``` +[scope]: + +[optional body] + +[optional footer] +``` + +**类型:** +- `feat`: 新功能 +- `fix`: 错误修复 +- `docs`: 文档 +- `style`: 格式化 +- `refactor`: 代码重构 +- `perf`: 性能改进 +- `test`: 添加测试 +- `chore`: 维护 + +**示例:** +```bash +feat(auth): add offline authentication support +fix(java): resolve detection on Windows +docs: update installation guide +refactor(download): simplify progress tracking +``` + +### Pull Request 指南 + +**提交前:** +- [ ] 代码遵循风格指南 +- [ ] 测试在本地通过 +- [ ] 必要时更新文档 +- [ ] 没有提交不必要的文件 +- [ ] 提交消息清晰 + +**PR 描述:** +- 解释做了什么以及为什么 +- 链接相关 issue +- 列出破坏性更改 +- 为 UI 更改添加截图 + +### 代码审查 + +维护者将审查你的 PR: +- 代码质量和风格 +- 测试覆盖率 +- 文档 +- 性能影响 +- 安全影响 + +对反馈保持响应并进行要求的更改。 + +## 常见任务 + +### 添加 Tauri 命令 + +1. **在 `main.rs` 中定义命令:** + ```rust + #[tauri::command] + async fn my_command(param: String) -> Result { + Ok(format!("Received: {}", param)) + } + ``` + +2. **在构建器中注册:** + ```rust + .invoke_handler(tauri::generate_handler![ + my_command, + // ... 其他命令 + ]) + ``` + +3. **从前端调用:** + ```typescript + const result = await invoke('my_command', { param: 'value' }); + ``` + +### 添加 UI 组件 + +1. **创建组件文件:** + ```svelte + + + + + ``` + +2. **导入并使用:** + ```svelte + + + + ``` + +### 添加 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 + + + + ``` + +## 开发问题故障排除 + +### 构建失败 + +**"cannot find -lwebkit2gtk"** +```bash +# 安装 WebKit 依赖 +sudo apt install libwebkit2gtk-4.1-dev +``` + +**"pnpm not found"** +```bash +# 安装 pnpm +npm install -g pnpm@9 +``` + +**"Rust version too old"** +```bash +# 更新 Rust +rustup update +``` + +### 运行时问题 + +**"Failed to load dynamic library"** +- 重新构建:`cargo clean && cargo tauri dev` +- 检查库路径 +- 验证已安装依赖 + +**"CORS error"** +- 开发模式下正常 +- Tauri 自动处理 CORS + +**"Hot reload not working"** +- 检查 Vite 配置 +- 重启开发服务器 +- 清除浏览器缓存 + +## 资源 + +- [Tauri 文档](https://v2.tauri.app/) +- [Svelte 5 文档](https://svelte.dev/docs) +- [Rust 程序设计语言](https://doc.rust-lang.org/book/) +- [DropOut 仓库](https://github.com/HydroRoll-Team/DropOut) + +## 获取帮助 + +- **Issues**: [GitHub Issues](https://github.com/HydroRoll-Team/DropOut/issues) +- **讨论**: [GitHub Discussions](https://github.com/HydroRoll-Team/DropOut/discussions) +- **文档**: 本站点 diff --git a/packages/docs/content/docs/zh/features/authentication.mdx b/packages/docs/content/docs/zh/features/authentication.mdx new file mode 100644 index 0000000..d6bfb56 --- /dev/null +++ b/packages/docs/content/docs/zh/features/authentication.mdx @@ -0,0 +1,267 @@ +--- +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/docs/zh/features/index.mdx b/packages/docs/content/docs/zh/features/index.mdx new file mode 100644 index 0000000..0429234 --- /dev/null +++ b/packages/docs/content/docs/zh/features/index.mdx @@ -0,0 +1,178 @@ +--- +title: 功能概览 +description: DropOut 所有功能的综合指南 +--- + +# 功能概览 + +DropOut 功能丰富,既适合休闲玩家也适合高级用户。本指南涵盖所有主要功能。 + +## 核心功能 + + + + + + + + + + +## 快速功能矩阵 + +| 功能 | 状态 | 描述 | +|---------|--------|-------------| +| Microsoft 身份验证 | ✅ 完成 | 使用设备代码流的 OAuth 2.0 | +| 离线身份验证 | ✅ 完成 | 用于离线游玩的本地账户 | +| 令牌自动刷新 | ✅ 完成 | 自动刷新过期的令牌 | +| Java 自动检测 | ✅ 完成 | 扫描系统中的 Java 安装 | +| Java 下载 | ✅ 完成 | 下载 Adoptium JDK/JRE 版本 | +| Fabric 支持 | ✅ 完成 | 安装和启动 Fabric 加载器 | +| Forge 支持 | ✅ 完成 | 安装和启动 Forge 加载器 | +| 实例系统 | ✅ 完成 | 隔离的游戏环境 | +| GitHub 集成 | ✅ 完成 | 查看发布和更新日志 | +| 并发下载 | ✅ 完成 | 多线程资源下载 | +| 断点续传 | ✅ 完成 | 恢复中断的下载 | +| AI 助手 | ✅ 完成 | 内置故障排除助手 | +| 配置编辑器 | ✅ 完成 | JSON/TOML 配置编辑器 | +| 自定义分辨率 | ✅ 完成 | 设置游戏窗口尺寸 | +| 内存分配 | ✅ 完成 | 自定义 JVM 内存设置 | +| 多账户 | 🚧 进行中 | 在多个账户之间切换 | +| 模组管理器 | 🚧 计划中 | 在启动器中启用/禁用模组 | +| 启动器自动更新 | 🚧 计划中 | 自我更新机制 | +| 自定义游戏目录 | 🚧 计划中 | 选择游戏文件位置 | +| 导入配置文件 | 🚧 计划中 | 从 MultiMC/Prism 导入 | + +## 性能功能 + +### 并发下载 +- 可配置的线程数(默认:10) +- 并行资源和库下载 +- 每个文件的进度跟踪 +- ETA 计算 + +### 断点续传支持 +- 中断的下载自动恢复 +- `.part` 文件跟踪进度 +- 大文件的多段下载 +- 用于状态跟踪的元数据文件 + +### 缓存 +- Java 目录缓存 24 小时 +- 本地缓存版本清单 +- 资源索引缓存 +- 库去重 + +## 用户界面功能 + +### 现代设计 +- 强制暗色模式保护眼睛 +- 粒子背景效果 +- 简洁、无干扰的布局 +- 响应式设计 + +### 实时反馈 +- 实时下载进度 +- 游戏控制台输出 +- 日志流 +- Toast 通知 + +### 设置管理 +- 内存分配滑块 +- 分辨率自定义 +- Java 路径选择 +- 线程数配置 +- 自定义 JVM 参数 + +## 高级功能 + +### 版本继承 +模组版本(Fabric/Forge)自动从父原版版本继承: +- 从父版本 + 模组加载器合并库 +- 组合并去重参数 +- 从原版版本继承资源 + +### 原生库提取 +- 特定平台的原生提取 +- 自动清理 +- 正确的库路径配置 + +### 规则引擎 +- 特定操作系统的库过滤 +- 功能标志支持 +- 架构检测 + +### 下载队列持久化 +- 保存未完成的下载 +- 启动器重启后恢复 +- 队列优先级管理 + +## 开发者功能 + +### 配置编辑器 +内置 JSON/TOML 编辑器,具有: +- 语法高亮 +- 验证 +- 快速访问所有配置 + +### 日志访问 +- 实时游戏日志 +- 启动器调试日志 +- 复制/导出功能 + +### AI 助手 +- 故障排除指导 +- 错误分析 +- 配置帮助 +- 文档搜索 + +## 即将推出 + +### 多账户管理 +- 轻松切换账户 +- 账户配置文件 +- 快速切换 + +### 模组管理器 +- 浏览和安装模组 +- 启用/禁用模组 +- 模组兼容性检查 +- 版本管理 + +### 配置文件导入 +- 从 MultiMC 导入 +- 从 Prism Launcher 导入 +- 从其他启动器导入 +- 保留设置和存档 + +### 启动器自动更新 +- 后台更新检查 +- 一键更新 +- 版本历史 +- 回滚支持 + + diff --git a/packages/docs/content/docs/zh/features/java.mdx b/packages/docs/content/docs/zh/features/java.mdx new file mode 100644 index 0000000..bdc3c15 --- /dev/null +++ b/packages/docs/content/docs/zh/features/java.mdx @@ -0,0 +1,394 @@ +--- +title: Java 管理 +description: 自动 Java 检测、下载和安装 +--- + +# Java 管理 + +DropOut 提供全面的 Java 管理,自动检测已安装的版本并根据需要下载新版本。 + +## 自动检测 + +### 系统扫描 + +DropOut 扫描多个位置查找 Java 安装: + +**Linux:** +- `/usr/lib/jvm/` +- `/usr/java/` +- `$JAVA_HOME` +- `PATH` 环境变量 + +**macOS:** +- `/Library/Java/JavaVirtualMachines/` +- `/System/Library/Java/JavaVirtualMachines/` +- `$JAVA_HOME` +- `PATH` 环境变量 + +**Windows:** +- `C:\Program Files\Java\` +- `C:\Program Files (x86)\Java\` +- `%JAVA_HOME%` +- `PATH` 环境变量 +- Windows 注册表 + +### 版本检测 + +对于找到的每个 Java 安装,DropOut 会: +1. 运行 `java -version` 获取版本信息 +2. 解析主要版本(8、11、17、21 等) +3. 检测架构(x64、ARM64) +4. 识别供应商(Oracle、Adoptium 等) + +### 结果 + +所有检测到的 Java 安装都显示在设置 → Java 中: +- 版本号 +- 安装路径 +- 架构 +- 当前选择状态 + +## Java 下载 + +### Adoptium 集成 + +DropOut 集成了 Eclipse Adoptium API 以下载高质量的免费 JDK/JRE 构建版本。 + +**支持的版本:** +- Java 8(LTS) +- Java 11(LTS) +- Java 17(LTS) +- Java 21(LTS) +- Java 23+(最新版) + +**功能:** +- 自动平台检测 +- 特定架构的构建版本 +- JDK 或 JRE 选择 +- 校验和验证 + +### 下载过程 + +1. 导航到设置 → Java +2. 点击"下载 Java" +3. 选择版本(例如 Java 17) +4. 选择 JDK 或 JRE +5. 点击下载 +6. 等待下载和解压 + +**进度跟踪:** +- 实时下载速度 +- ETA 计算 +- 解压进度 +- 安装确认 + +### 目录管理 + +Java 目录缓存 24 小时以提高性能: + +```rust +// 目录结构 +{ + "versions": [ + { + "version": "17.0.9+9", + "major": 17, + "url": "https://api.adoptium.net/...", + "sha256": "...", + "size": 123456789 + } + ], + "last_updated": 1234567890 +} +``` + +**刷新:** +- 24 小时后自动刷新 +- 设置中手动刷新 +- 下载失败时强制刷新 + +## 安装 + +### 下载目录 + +下载的 Java 运行时安装到: + +``` +~/.local/share/com.dropout.launcher/java/ (Linux) +~/Library/Application Support/com.dropout.launcher/java/ (macOS) +%APPDATA%/com.dropout.launcher/java/ (Windows) +``` + +### 目录结构 + +``` +java/ +├── jdk-17.0.9+9/ +│ ├── bin/ +│ │ └── java (或 java.exe) +│ └── lib/ +├── jdk-21.0.1+12/ +│ ├── bin/ +│ └── lib/ +└── download_queue.json +``` + +### 解压 + +1. 下载到 `.part` 文件 +2. 验证校验和 +3. 解压存档: + - Linux/macOS 上的 `.tar.gz` + - Windows 上的 `.zip` +4. 移动到 `java//` 目录 +5. 设置可执行权限(Unix) + +## 配置 + +### 内存分配 + +在设置中配置 JVM 内存: + +**最小内存:** +- 默认:1024 MB +- 推荐:原版 2048 MB +- 推荐:模组 4096+ MB + +**最大内存:** +- 默认:4096 MB +- 根据系统 RAM 调整 +- 为操作系统和其他应用留出 4GB + +**格式:** +```bash +-Xms1024M -Xmx4096M +``` + +### 自定义 JVM 参数 + +为高级配置添加自定义 JVM 参数: + +**常用参数:** +```bash +# 垃圾回收 +-XX:+UseG1GC +-XX:+UnlockExperimentalVMOptions + +# 性能 +-XX:G1NewSizePercent=20 +-XX:G1ReservePercent=20 +-XX:MaxGCPauseMillis=50 + +# 内存 +-XX:G1HeapRegionSize=32M +``` + +### Java 路径选择 + +**自动选择:** +- DropOut 为每个 Minecraft 版本推荐最佳 Java 版本 +- Java 8 用于 Minecraft 1.12.2 及更早版本 +- Java 17 用于 Minecraft 1.18-1.20.4 +- Java 21 用于 Minecraft 1.20.5+ + +**手动选择:** +1. 前往设置 → Java +2. 从检测到的安装中选择 +3. 或指定自定义路径 + +## 版本推荐 + +### Minecraft 版本 → Java 版本 + +| Minecraft 版本 | 推荐 Java | 最低 Java | +|-------------------|------------------|--------------| +| 1.7.10 及更早 | Java 8 | Java 8 | +| 1.8 - 1.12.2 | Java 8 | Java 8 | +| 1.13 - 1.16.5 | Java 8 或 11 | Java 8 | +| 1.17 - 1.17.1 | Java 16 | Java 16 | +| 1.18 - 1.20.4 | Java 17 | Java 17 | +| 1.20.5+ | Java 21 | Java 21 | + +### 模组 Minecraft + +**Fabric:** +- 通常与原版要求匹配 +- 一些模组可能需要更新的 Java + +**Forge:** +- 可能需要特定的 Java 版本 +- 检查模组加载器文档 +- 通常需要完全匹配版本 + +## 故障排除 + +### 未检测到 Java + +**问题:** 已安装的 Java 未显示 + +**解决方案:** +1. 验证 Java 在标准位置 +2. 检查 `JAVA_HOME` 环境变量 +3. 将 Java `bin` 目录添加到 `PATH` +4. 重启 DropOut +5. 手动选择路径 + +### 下载失败 + +**问题:** Java 下载未完成 + +**解决方案:** +1. 检查互联网连接 +2. 验证磁盘空间 +3. 尝试不同版本 +4. 清除下载队列 +5. 从 Adoptium 手动下载 + +### Java 版本错误 + +**问题:** 由于 Java 版本导致游戏崩溃 + +**解决方案:** +1. 检查 Minecraft 版本要求 +2. 下载正确的 Java 版本 +3. 在设置中选择适当的 Java +4. 验证 Java 路径正确 + +### 内存不足错误 + +**问题:** 游戏因内存错误崩溃 + +**解决方案:** +1. 增加最大内存分配 +2. 关闭其他应用程序 +3. 升级系统 RAM +4. 使用 64 位 Java +5. 优化 JVM 参数 + +### 性能问题 + +**问题:** 低 FPS 或卡顿 + +**解决方案:** +1. 调整内存分配(不要太高!) +2. 启用 G1GC 垃圾收集器 +3. 添加性能 JVM 参数 +4. 如兼容使用更新的 Java 版本 +5. 为整合包分配 4-8GB + +## API 参考 + +### Tauri 命令 + +**检测 Java 安装:** +```typescript +const javas = await invoke('detect_java_installations'); +// 返回: Array<{ path: string, version: string, major: number }> +``` + +**获取 Java 目录:** +```typescript +const catalog = await invoke('get_java_catalog'); +// 返回: { versions: Array, last_updated: number } +``` + +**下载 Java:** +```typescript +await invoke('download_java', { + version: '17.0.9+9', + variant: 'jdk' // 或 'jre' +}); +``` + +**取消 Java 下载:** +```typescript +await invoke('cancel_java_download'); +``` + +**设置 Java 路径:** +```typescript +await invoke('set_java_path', { path: '/path/to/java' }); +``` + +### 事件 + +**下载进度:** +```typescript +listen('java-download-progress', (event) => { + const { percent, speed, eta } = event.payload; +}); +``` + +**下载完成:** +```typescript +listen('java-download-complete', (event) => { + const { path, version } = event.payload; +}); +``` + +## 最佳实践 + +### 对于玩家 + +1. **使用 Adoptium 构建版本** - 免费、高质量、维护良好 +2. **Java 与 Minecraft 版本匹配** - 检查版本要求 +3. **不要过度分配内存** - 为操作系统留出 RAM +4. **保持 Java 更新** - 安全性和性能 +5. **使用 64 位 Java** - 大内存所需 + +### 对于开发者 + +1. **测试多个 Java 版本** - 确保兼容性 +2. **记录 Java 要求** - 帮助用户 +3. **处理缺少的 Java** - 优雅的后备方案 +4. **启动前验证 Java 路径** +5. **提供清晰的错误** - 当 Java 错误时 + +## 高级主题 + +### 自定义 Java 安装 + +使用自定义 Java 安装: + +1. 手动安装 Java +2. 记录安装路径 +3. 在 DropOut 设置 → Java 中 +4. 点击"自定义路径" +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 支持高级用户: + +1. 从 graalvm.org 下载 GraalVM +2. 手动安装 +3. 作为自定义 Java 添加到 DropOut +4. 可能提高性能 +5. 使用前彻底测试 diff --git a/packages/docs/content/docs/zh/features/meta.json b/packages/docs/content/docs/zh/features/meta.json new file mode 100644 index 0000000..4725321 --- /dev/null +++ b/packages/docs/content/docs/zh/features/meta.json @@ -0,0 +1,9 @@ +{ + "title": "Features", + "pages": [ + "index", + "authentication", + "java", + "mod-loaders" + ] +} diff --git a/packages/docs/content/docs/zh/features/mod-loaders.mdx b/packages/docs/content/docs/zh/features/mod-loaders.mdx new file mode 100644 index 0000000..be5cfeb --- /dev/null +++ b/packages/docs/content/docs/zh/features/mod-loaders.mdx @@ -0,0 +1,410 @@ +--- +title: 模组加载器 +description: Fabric 和 Forge 安装和管理 +--- + +# 模组加载器 + +DropOut 支持两个最流行的 Minecraft 模组加载器:Fabric 和 Forge。两者都可以直接从启动器中轻松安装和管理。 + +## Fabric 支持 + +### 概述 + +Fabric 是一个轻量级、模块化的模组工具链,专注于: +- 快速更新至新的 Minecraft 版本 +- 干净、极简的 API +- 强大的开发者社区 +- 优异的性能 + +### 安装 + +1. 导航至 **Versions** 选项卡 +2. 点击 **"Install Fabric"** +3. 选择 Minecraft 版本 +4. 选择 Fabric 加载器版本 +5. 点击 **"Install"** +6. 等待安装完成 + +### 工作原理 + +**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": [...] +} +``` + +### Fabric 版本 + +**加载器版本:** +- 最新稳定版(推荐) +- 用于兼容性的特定版本 +- Beta/快照版本 + +**游戏版本:** +- 所有 1.14+ 的 Minecraft 版本 +- 支持快照版本 +- 支持战斗测试版本 + +### 库管理 + +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 API + +Fabric Loader ≠ Fabric API: +- **Fabric Loader**: 模组加载器(由 DropOut 安装) +- **Fabric API**: 库模组(单独下载) + +许多模组需要 Fabric API: +1. 从 [Modrinth](https://modrinth.com/mod/fabric-api) 或 [CurseForge](https://www.curseforge.com/minecraft/mc-mods/fabric-api) 下载 +2. 放置在实例的 `mods/` 文件夹中 + +## Forge 支持 + +### 概述 + +Forge 是原始的、最流行的 Minecraft 模组加载器: +- 广泛的模组生态系统 +- 成熟的 API +- 广泛的版本支持 +- 庞大的社区 + +### 安装 + +1. 导航至 **Versions** 选项卡 +2. 点击 **"Install Forge"** +3. 选择 Minecraft 版本 +4. 选择 Forge 版本 +5. 点击 **"Install"** +6. 等待安装程序运行 +7. 安装完成 + +### 工作原理 + +**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": [...] +} +``` + +### Forge 版本 + +**发布类型:** +- **Latest**: 最新的稳定版本 +- **Recommended**: 生产环境中最稳定的版本 +- **Specific**: 版本锁定以确保兼容性 + +**Minecraft 版本支持:** +- 旧版本 (1.6.4+) +- 现代版本 (1.13+) +- 最新版本 (1.20+) + +### 库管理 + +Forge 有许多库: + +**核心库:** +- `net.minecraftforge:forge:` +- `net.minecraftforge:fmlloader:` +- `org.ow2.asm:asm:` + +**解析:** +```rust +// Forge Maven +"https://maven.minecraftforge.net/" + +// Dependencies may use: +// - Maven Central +// - Minecraft Libraries +``` + +### Forge 处理器 + +某些 Forge 版本在安装期间运行"处理器": +- 字节码操纵 +- 库修补 +- 映射生成 + +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 | +|---------|--------|-------| +| **性能** | 优异 | 良好 | +| **更新速度** | 非常快 | 中等 | +| **模组选择** | 增长中 | 广泛 | +| **API 简洁性** | 简洁 | 复杂 | +| **版本支持** | 1.14+ | 1.6.4+ | +| **开发者友好** | 非常友好 | 中等 | +| **稳定性** | 优异 | 优异 | + +## 安装模组 + +### Fabric 模组 + +1. 创建/选择实例 +2. 确保 Fabric 已安装 +3. 从以下位置下载模组: + - [Modrinth](https://modrinth.com/) + - [CurseForge](https://www.curseforge.com/) + - [GitHub Releases](https://github.com/) +4. 将 `.jar` 文件放置在 `instances//mods/` +5. 启动游戏 + +**兼容性:** +- 检查 Minecraft 版本 +- 检查 Fabric Loader 版本 +- 检查 Fabric API 需求 +- 阅读模组依赖项 + +### Forge 模组 + +1. 创建/选择实例 +2. 确保 Forge 已安装 +3. 从以下位置下载模组: + - [CurseForge](https://www.curseforge.com/) + - [Modrinth](https://modrinth.com/) +4. 将 `.jar` 文件放置在 `instances//mods/` +5. 启动游戏 + +**兼容性:** +- 精确检查 Minecraft 版本 +- 检查 Forge 版本范围 +- 阅读模组依赖项 +- 检查冲突 + +## 故障排除 + +### Fabric 问题 + +**"Fabric Loader not found"** +- 重新安装 Fabric +- 检查版本 JSON 是否存在 +- 验证库是否已下载 + +**"Mixin apply failed"** +- 模组不兼容 +- 删除冲突的模组 +- 更新 Fabric Loader + +**"Fabric API required"** +- 下载 Fabric API +- 匹配 Minecraft 版本 +- 放置在 mods 文件夹中 + +### Forge 问题 + +**"Forge installer failed"** +- 验证 Java 安装 +- 检查磁盘空间 +- 尝试旧版本的 Forge +- 检查日志获取详细信息 + +**"Missing dependencies"** +- 安装所需的模组 +- 检查模组版本兼容性 +- 仔细阅读错误消息 + +**"Class not found"** +- Forge 版本不匹配 +- 重新安装 Forge +- 验证库是否已下载 + +### 常见模组问题 + +**启动时崩溃:** +1. 检查崩溃报告 +2. 识别有问题的模组 +3. 删除或更新模组 +4. 使用最少的模组测试 +5. 逐步添加模组回来 + +**性能问题:** +1. 安装了太多模组 +2. 增加内存分配 +3. 安装性能模组: + - Fabric: Sodium, Lithium + - Forge: OptiFine, Magnesium +4. 删除资源密集型模组 + +## 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" +}); +``` + +## 最佳实践 + +### 对于玩家 + +1. **每个实例选择一个模组加载器** +2. **精确匹配版本** - Minecraft 和加载器 +3. **安装前阅读模组要求** +4. **循序渐进** - 逐步添加模组 +5. **备份世界** - 添加模组前备份 +6. **检查兼容性** 列表 +7. **谨慎更新** - 在单独的实例中测试 + +### 对于模组包创建者 + +1. **记录版本** - MC、加载器、所有模组 +2. **彻底测试** - 所有功能 +3. **列出依赖项** - 包括 API +4. **提供更新日志** - 用于更新 +5. **版本锁定** - 为了稳定性 +6. **包含配置** - 预配置 +7. **测试更新** - 发布前测试 + +## 未来功能 + +- **模组浏览器** - 从启动器安装模组 +- **自动更新** - 保持模组最新 +- **依赖项解析** - 自动安装需求 +- **冲突检测** - 警告不兼容性 +- **配置文件导出** - 共享模组包配置 +- **CurseForge 集成** - 直接模组包导入 +- **Modrinth 集成** - 模组搜索和安装 + diff --git a/packages/docs/content/docs/zh/getting-started.mdx b/packages/docs/content/docs/zh/getting-started.mdx new file mode 100644 index 0000000..abc5dc9 --- /dev/null +++ b/packages/docs/content/docs/zh/getting-started.mdx @@ -0,0 +1,162 @@ +--- +title: 快速开始 +description: 使用 DropOut Minecraft 启动器的快速入门指南 +--- + +# 快速开始 + +DropOut 是一个使用 Tauri v2 和 Rust 构建的现代化、可复现、开发者级别的 Minecraft 启动器。本指南将帮助你开始安装和使用 DropOut。 + +## 安装 + +### 下载预编译二进制文件 + +从[发布页面](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 安装 + +#### 使用 .deb 包 +```bash +sudo dpkg -i dropout_*.deb +# 如果需要,修复依赖 +sudo apt-get install -f +``` + +#### 使用 AppImage +```bash +chmod +x dropout_*.AppImage +./dropout_*.AppImage +``` + +### macOS 安装 + +1. 打开下载的 `.dmg` 文件 +2. 将 DropOut 拖到应用程序文件夹 +3. 如果看到安全警告,转到系统偏好设置 → 安全性与隐私并允许该应用 + +### Windows 安装 + +#### 使用 .msi 安装程序 +1. 双击 `.msi` 文件 +2. 按照安装向导操作 +3. 从开始菜单启动 DropOut + +#### 使用 .exe 便携版 +1. 双击 `.exe` 文件 +2. DropOut 将直接运行,无需安装 + +## 首次启动 + +首次启动 DropOut 时,你需要: + +1. **选择认证方式** + - **微软账户**: 推荐用于官方 Minecraft + - **离线模式**: 用于测试或离线游戏 + +2. **配置 Java 运行时** + - DropOut 将自动检测已安装的 Java 版本 + - 如果需要,你可以直接从启动器下载 Java + +3. **选择 Minecraft 版本** + - 浏览可用的 Minecraft 版本 + - 选择原版或模组版本(Fabric/Forge) + +## 快速入门教程 + +### 1. 登录 + + + + + + +**微软登录:** +1. 点击"使用微软登录" +2. 将显示设备代码 +3. 访问显示的 URL 并输入代码 +4. 授权应用程序 +5. 返回 DropOut - 你将自动登录 + +**离线登录:** +1. 点击"离线模式" +2. 输入用户名 +3. 点击"创建账户" + +### 2. 安装 Minecraft + +1. 导航到**版本**标签 +2. 浏览可用的 Minecraft 版本 +3. 点击一个版本进行安装 +4. 等待下载完成 + +### 3. 启动游戏 + +1. 转到**主页**标签 +2. 从下拉菜单中选择你想要的版本 +3. 如果需要,调整设置: + - 内存分配(RAM) + - 窗口分辨率 + - Java 路径 +4. 点击**"启动游戏"** +5. 在控制台中监视启动过程 + +## 下一步 + + + + + + + + +## 系统要求 + +### 最低要求 +- **操作系统**: Windows 10+、macOS 11+ 或 Linux(基于 Debian) +- **内存**: 4GB(推荐 8GB 用于模组 Minecraft) +- **存储**: 启动器 + 游戏文件需要 2GB +- **Java**: 如果找不到,DropOut 会自动安装 + +### 推荐配置 +- **操作系统**: 你操作系统的最新稳定版本 +- **内存**: 16GB 以获得带模组的最佳性能 +- **存储**: 10GB+ 用于多个版本和模组 +- **Java**: Java 17 或 21(由 DropOut 管理) + +## 获取帮助 + +如果遇到问题: +- 查看[故障排除指南](/docs/troubleshooting) +- 在 [GitHub Issues](https://github.com/HsiangNianian/DropOut/issues) 上报告 bug +- 加入我们的社区讨论 + diff --git a/packages/docs/content/docs/zh/index.mdx b/packages/docs/content/docs/zh/index.mdx new file mode 100644 index 0000000..1c18be2 --- /dev/null +++ b/packages/docs/content/docs/zh/index.mdx @@ -0,0 +1,95 @@ +--- +title: 欢迎使用 DropOut +description: 现代化、可复现、开发者级别的 Minecraft 启动器 +--- + +# 欢迎使用 DropOut + +DropOut 是一个使用 Tauri v2 和 Rust 构建的现代 Minecraft 启动器,专为重视控制、透明度和长期稳定性的玩家设计。 + +
+ DropOut 启动器 +
+ +## 为什么选择 DropOut? + +大多数 Minecraft 启动器专注于让你进入游戏。DropOut 专注于保持你的游戏**稳定**、**可调试**和**可复现**。 + +- 你的实例昨天还能用,今天就坏了?→ **DropOut 让它可追溯。** +- 分享模组包意味着打包数GB的文件?→ **DropOut 分享精确的依赖清单。** +- Java、加载器、模组、配置不同步?→ **DropOut 将它们锁定在一起。** + +这个启动器是为重视控制、透明度和长期稳定性的玩家构建的。 + +## 快速链接 + + + + + + + + +## 核心特性 + +### 🚀 高性能 +使用 Rust 和 Tauri 构建,资源占用最小,启动速度极快。 + +### 🎨 现代化界面 +简洁、无干扰的界面,使用 Svelte 5、Tailwind CSS 4 和粒子效果。 + +### 🔐 安全认证 +微软 OAuth 2.0 设备代码流和离线认证支持。 + +### 🔧 模组加载器支持 +内置 Fabric 和 Forge 安装,自动版本管理。 + +### ☕ Java 管理 +自动检测已安装的 Java 版本,集成 Adoptium JDK/JRE 下载器。 + +### 📦 实例系统 +独立的游戏环境,具有独立的配置、模组和存档。 + +### 🤖 AI 助手 +内置 AI 帮助,用于故障排除、配置和指导。 + +### ⚡ 快速下载 +并发资源和库下载,支持断点续传和进度跟踪。 + +## 技术栈 + +- **后端**: Rust + Tauri v2 +- **前端**: Svelte 5 with runes +- **样式**: Tailwind CSS 4 +- **构建工具**: Vite with Rolldown +- **文档**: Fumadocs with React Router + +## 社区 + +- **GitHub**: [HydroRoll-Team/DropOut](https://github.com/HydroRoll-Team/DropOut) +- **问题反馈**: [报告 bug](https://github.com/HydroRoll-Team/DropOut/issues) +- **开发路线图**: [查看开发路线图](https://roadmap.sh/r/minecraft-launcher-dev) + +## 许可证 + +DropOut 是在 MIT 许可证下的开源软件。 + +--- + +准备好开始了吗?查看[快速开始指南](/docs/getting-started)! \ No newline at end of file diff --git a/packages/docs/content/docs/zh/meta.json b/packages/docs/content/docs/zh/meta.json new file mode 100644 index 0000000..8ad7ea2 --- /dev/null +++ b/packages/docs/content/docs/zh/meta.json @@ -0,0 +1,19 @@ +{ + "title": "Documentation", + "pages": [ + "index", + "getting-started", + "architecture", + { + "title": "Features", + "pages": [ + "features/index", + "features/authentication", + "features/java", + "features/mod-loaders" + ] + }, + "development", + "troubleshooting" + ] +} diff --git a/packages/docs/content/docs/zh/troubleshooting.mdx b/packages/docs/content/docs/zh/troubleshooting.mdx new file mode 100644 index 0000000..3785adc --- /dev/null +++ b/packages/docs/content/docs/zh/troubleshooting.mdx @@ -0,0 +1,523 @@ +--- +title: 故障排除 +description: DropOut 启动器常见问题和解决方案 +--- + +# 故障排除 + +本指南涵盖常见问题及其解决方案。如果在这里找不到你的问题,请在 GitHub 上[提交 issue](https://github.com/HydroRoll-Team/DropOut/issues)。 + +## 安装问题 + +### Linux:缺少依赖 + +**问题:** 安装时提示缺少库 + +**解决方案:** +```bash +# Ubuntu/Debian +sudo apt update +sudo apt install libwebkit2gtk-4.1-0 libgtk-3-0 + +# Fedora +sudo dnf install webkit2gtk4.1 gtk3 + +# Arch +sudo pacman -S webkit2gtk gtk3 +``` + +### macOS:"应用程序已损坏" + +**问题:** macOS 提示 DropOut 已损坏无法打开 + +**解决方案:** +1. 打开终端 +2. 运行:`xattr -cr /Applications/DropOut.app` +3. 再次尝试打开 +4. 或者:系统偏好设置 → 安全性 → 仍要打开 + +### Windows:SmartScreen 警告 + +**问题:** Windows SmartScreen 阻止安装程序 + +**解决方案:** +1. 点击"更多信息" +2. 点击"仍要运行" +3. 这对于没有扩展验证证书的新应用是正常的 + +## 身份验证问题 + +### Microsoft 登录失败 + +**问题:** 无法完成 Microsoft 登录 + +**可能原因和解决方案:** + +**1. 设备代码过期:** +- 代码在 15 分钟后过期 +- 重新开始登录过程 +- 更快地完成授权 + +**2. 网络问题:** +- 检查互联网连接 +- 暂时禁用 VPN +- 检查防火墙设置 +- 尝试不同的网络 + +**3. Microsoft 账户问题:** +- 验证账户拥有 Minecraft Java 版 +- 在 https://www.minecraft.net/profile 检查 +- 确保账户未被封禁 + +**4. 浏览器问题:** +- 尝试不同的浏览器 +- 清除浏览器缓存 +- 禁用广告拦截器 +- 使用无痕/隐私模式 + +### 令牌刷新失败 + +**问题:** 令牌刷新失败,必须频繁重新登录 + +**解决方案:** +1. 完全退出登录 +2. 从应用数据目录删除 `accounts.json` +3. 重新登录 +4. 如果持续存在,检查 Microsoft 账户状态 + +### 离线登录不工作 + +**问题:** 无法创建离线账户 + +**解决方案:** +- 用户名必须是 3-16 个字符 +- 仅使用字母、数字、下划线 +- 不使用特殊字符 +- 不使用空格 + +## 游戏启动问题 + +### 找不到 Java + +**问题:** "未找到 Java 安装" + +**解决方案:** + +**1. 自动检测现有 Java:** +- 设置 → Java → 检测安装 +- 如果找到,选择它 +- 如果未找到,进行步骤 2 + +**2. 通过 DropOut 下载 Java:** +- 设置 → Java → 下载 Java +- 选择适当的版本: + - Java 8 用于 Minecraft 1.12.2 及更早版本 + - Java 17 用于 Minecraft 1.18-1.20.4 + - Java 21 用于 Minecraft 1.20.5+ + +**3. 手动安装 Java:** +- 从 [Adoptium](https://adoptium.net/) 下载 +- 安装到系统 +- 重启 DropOut +- 再次检测 + +### Java 版本错误 + +**问题:** 游戏崩溃并提示"不支持的类文件版本" + +**解决方案:** +将 Java 版本与 Minecraft 版本匹配: + +| Minecraft 版本 | Java 版本 | +|-------------------|--------------| +| 1.7.10 及更早 | Java 8 | +| 1.8 - 1.12.2 | Java 8 | +| 1.13 - 1.16.5 | Java 8 或 11 | +| 1.17 - 1.17.1 | Java 16 | +| 1.18 - 1.20.4 | Java 17 | +| 1.20.5+ | Java 21 | + +### 内存不足错误 + +**问题:** 游戏崩溃并显示 `java.lang.OutOfMemoryError` + +**解决方案:** + +**1. 增加内存分配:** +- 设置 → 内存 +- 增加最大内存: + - 原版:最少 4GB + - 轻度模组:6GB + - 重度整合包:8-12GB +- 不要超过系统 RAM 的 80% + +**2. 使用 64 位 Java:** +- 检查当前 Java 架构 +- 如需要下载 64 位 Java +- 32 位 Java 限制在约 2GB + +**3. 降低渲染距离:** +- 游戏内视频设置 +- 将渲染距离降低到 8-12 区块 + +**4. 优化 JVM 参数:** +```bash +-Xms4G -Xmx8G -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions +``` + +### 游戏无法启动 + +**问题:** 游戏不启动,没有错误消息 + +**检查:** + +**1. 日志输出:** +- 检查 DropOut 中的游戏控制台 +- 查找错误消息 +- 常见问题: + - 文件缺失 + - 下载损坏 + - 模组冲突 + +**2. 验证文件:** +- 删除版本文件夹 +- 重新下载版本 +- 在模组版本之前先尝试原版 + +**3. 检查权限:** +- 确保 DropOut 可以写入游戏目录 +- 检查文件夹权限 +- 在 Linux 上:`chmod -R 755 ~/.local/share/com.dropout.launcher` + +## 下载问题 + +### 下载失败 + +**问题:** 资源或库下载失败 + +**解决方案:** + +**1. 网络问题:** +- 检查互联网连接 +- 禁用 VPN +- 尝试不同的网络 +- 检查防火墙/杀毒软件 + +**2. 恢复下载:** +- DropOut 自动恢复中断的下载 +- 关闭并重新打开 DropOut +- 下载应该继续 + +**3. 清除下载缓存:** +- 删除 libraries/assets 中的 `.part` 文件 +- 重新开始下载 + +**4. 手动下载:** +- 检查日志中失败的 URL +- 手动下载文件 +- 放置在正确位置 + +### 下载缓慢 + +**问题:** 下载非常慢 + +**解决方案:** + +**1. 调整线程数:** +- 设置 → 下载 +- 尝试不同的线程数: + - 太低:整体较慢 + - 太高:连接限流 + - 推荐:5-10 个线程 + +**2. 网络优化:** +- 关闭占用大量带宽的应用 +- 如可能使用有线连接 +- 检查 ISP 限速 + +**3. 备用 CDN:** +- Mojang 镜像可能很慢 +- 尝试在一天中的不同时间 + +## 模组加载器问题 + +### Fabric 安装失败 + +**问题:** 无法安装 Fabric 加载器 + +**解决方案:** + +**1. 检查 Minecraft 版本:** +- Fabric 支持 1.14+ +- 不支持更早版本 +- 尝试更新的 Minecraft 版本 + +**2. 网络问题:** +- 检查互联网连接 +- Fabric Meta API 可能宕机 +- 稍后再试 + +**3. 手动安装:** +- 从 [fabricmc.net](https://fabricmc.net/) 下载 Fabric +- 使用官方安装器 +- 将配置文件导入 DropOut + +### Forge 安装失败 + +**问题:** Forge 安装器失败或挂起 + +**解决方案:** + +**1. Java 版本:** +- 确保 Java 版本正确 +- Forge 1.17+ 需要 Java 16+ +- 更早的 Forge 可能需要 Java 8 + +**2. 安装器超时:** +- Forge 安装器可能很慢 +- 等待最多 10 分钟 +- 检查日志查看进度 + +**3. 磁盘空间:** +- 确保有足够的可用空间 +- Forge 临时需要约 1GB +- 检查 Linux 上的 `/tmp` + +**4. 手动安装:** +- 从 [minecraftforge.net](https://files.minecraftforge.net/) 下载 Forge 安装器 +- 手动运行安装器 +- 选择安装客户端 +- 导入配置文件 + +### 模组崩溃 + +**问题:** 安装模组后游戏崩溃 + +**解决方案:** + +**1. 检查兼容性:** +- 验证模组适用于正确的 Minecraft 版本 +- 检查模组加载器版本要求 +- 阅读模组说明了解依赖项 + +**2. 安装依赖项:** +- Fabric 模组通常需要 Fabric API +- 一些模组需要库 +- 检查崩溃日志中的"缺失"错误 + +**3. 移除冲突的模组:** +- 逐一禁用模组 +- 识别有问题的模组 +- 检查已知冲突 +- 更新或替换模组 + +**4. 更新模组:** +- 使用最新的模组版本 +- 检查模组更新说明 +- 一些更新修复崩溃 + +## 性能问题 + +### 低 FPS + +**问题:** 游戏运行缓慢或卡顿 + +**解决方案:** + +**1. 分配更多内存:** +- 将最大内存增加到 6-8GB +- 不要过度分配(导致 GC 暂停) + +**2. 安装性能模组:** +- **Fabric**: Sodium、Lithium、Phosphor +- **Forge**: OptiFine、Magnesium、Rubidium + +**3. 优化设置:** +- 降低渲染距离 +- 禁用精美图形 +- 关闭粒子 +- 如果 fps < 60 禁用垂直同步 + +**4. 更新显卡驱动:** +- 从制造商下载最新版本 +- NVIDIA: GeForce Experience +- AMD: Adrenalin +- Intel: Graphics Command Center + +**5. 关闭后台应用:** +- 释放系统资源 +- 禁用覆盖层(Discord 等) +- 检查任务管理器中的 CPU/RAM 占用 + +### 启动器启动缓慢 + +**问题:** DropOut 启动时间很长 + +**解决方案:** + +**1. 检查系统资源:** +- 关闭不必要的程序 +- 确保有足够的 RAM 可用 +- 检查 CPU 使用率 + +**2. 杀毒软件干扰:** +- 将 DropOut 添加到例外 +- 暂时禁用以测试 +- 一些杀毒软件会显著减慢速度 + +**3. 损坏的数据:** +- 删除应用数据中的 `cache` 文件夹 +- 重启 DropOut +- 将重建缓存 + +## UI 问题 + +### 窗口不打开 + +**问题:** DropOut 窗口不出现 + +**解决方案:** + +**1. 检查是否在运行:** +```bash +# Linux/macOS +ps aux | grep dropout + +# Windows +tasklist | findstr dropout +``` + +**2. 终止并重启:** +```bash +# Linux/macOS +pkill dropout + +# Windows +taskkill /F /IM dropout.exe +``` + +**3. 重置窗口位置:** +- 删除窗口状态配置 +- 重启 DropOut + +### 图形故障 + +**问题:** UI 看起来不对或有视觉伪影 + +**解决方案:** + +**1. 更新显卡驱动:** +- 安装最新驱动 +- 重启系统 + +**2. 禁用硬件加速:** +- 检查设置中是否存在选项 +- 可能会降低性能但修复故障 + +**3. 尝试不同的显示器:** +- 多显示器设置可能导致问题 +- 在不同显示器上尝试 + +## 文件系统问题 + +### 无法访问游戏目录 + +**问题:** 访问游戏文件时出错 + +**解决方案:** + +**1. 检查权限:** +```bash +# Linux +chmod -R 755 ~/.local/share/com.dropout.launcher + +# macOS +chmod -R 755 ~/Library/Application\ Support/com.dropout.launcher +``` + +**2. 检查磁盘空间:** +- 确保有足够的可用空间 +- Minecraft 需要 2-10GB,取决于模组 +- 清理旧版本 + +**3. 杀毒软件阻止:** +- 将游戏目录添加到例外 +- 一些杀毒软件会阻止文件访问 + +### 文件损坏 + +**问题:** 文件似乎损坏或无效 + +**解决方案:** + +**1. 验证校验和:** +- DropOut 验证 SHA1/SHA256 +- 验证失败会触发重新下载 + +**2. 重新下载:** +- 删除损坏的文件 +- 再次启动版本 +- DropOut 将重新下载 + +**3. 清除缓存:** +- 完全删除版本文件夹 +- 从头重新安装 + +## 获取更多帮助 + +### 收集调试信息 + +报告问题时,包括: + +**1. 系统信息:** +- 操作系统和版本 +- DropOut 版本 +- Java 版本 + +**2. 日志:** +- 控制台的启动器日志 +- 如适用的游戏日志 +- 错误消息(完整文本) + +**3. 重现步骤:** +- 你做了什么 +- 你期望什么 +- 实际发生了什么 + +**4. 截图:** +- 错误消息 +- UI 问题 +- 设置屏幕 + +### 报告问题 + +1. 搜索[现有 issues](https://github.com/HydroRoll-Team/DropOut/issues) +2. 如果未找到,[创建新 issue](https://github.com/HydroRoll-Team/DropOut/issues/new) +3. 使用 issue 模板 +4. 提供所有要求的信息 +5. 保持耐心和响应 + +### 社区支持 + +- **GitHub 讨论**:提问 +- **Discord**:实时帮助(如果可用) +- **文档**:查看所有指南 + +## 已知问题 + +### 目前正在处理 + +- 多账户切换(进行中) +- 自定义游戏目录选择(计划中) +- 启动器自动更新(计划中) + +### 可用的变通方法 + +**问题**:无法轻松切换账户 +**变通方法**:退出登录并使用不同账户登录 + +**问题**:没有内置模组管理器 +**变通方法**:在实例文件夹中手动管理模组 + +**问题**:无法从其他启动器导入 +**变通方法**:手动复制实例文件 diff --git a/packages/docs/source.config.ts b/packages/docs/source.config.ts index 0564068..1e8ac56 100644 --- a/packages/docs/source.config.ts +++ b/packages/docs/source.config.ts @@ -2,6 +2,7 @@ import { defineConfig, defineDocs } from 'fumadocs-mdx/config'; export const docs = defineDocs({ dir: 'content/docs', + i18n: true, }); export default defineConfig(); From fe0cb04b26a543d6107f93b1fe3ca751c4d43148 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 21 Jan 2026 13:26:25 +0000 Subject: [PATCH 04/18] docs: configure i18n support and update documentation README Co-authored-by: HsiangNianian <44714368+HsiangNianian@users.noreply.github.com> --- packages/docs/README.md | 71 ++++++++++++++++--- .../docs/content/docs/zh/features/meta.json | 2 +- packages/docs/content/docs/zh/meta.json | 4 +- 3 files changed, 64 insertions(+), 13 deletions(-) diff --git a/packages/docs/README.md b/packages/docs/README.md index 055e479..63b9290 100644 --- a/packages/docs/README.md +++ b/packages/docs/README.md @@ -11,6 +11,12 @@ The documentation covers: - **Development**: Building and contributing to DropOut - **Troubleshooting**: Common issues and solutions +### Multi-language Support + +The documentation is available in: +- **English** (default) - `content/docs/en/` +- **简体中文** (Simplified Chinese) - `content/docs/zh/` + ## Development ### Prerequisites @@ -34,6 +40,8 @@ pnpm dev This starts the development server at `http://localhost:5173` with hot reload enabled. +The documentation automatically supports language switching between English and Chinese. + ### Build for Production ```bash @@ -64,18 +72,50 @@ pnpm format packages/docs/ ├── content/ │ └── docs/ # Documentation content (MDX) -│ ├── index.mdx # Home page -│ ├── getting-started.mdx -│ ├── architecture.mdx -│ ├── development.mdx -│ ├── troubleshooting.mdx -│ └── features/ # Feature-specific docs +│ ├── en/ # English documentation +│ │ ├── index.mdx +│ │ ├── getting-started.mdx +│ │ ├── architecture.mdx +│ │ ├── development.mdx +│ │ ├── troubleshooting.mdx +│ │ └── features/ +│ └── zh/ # Chinese documentation +│ ├── index.mdx +│ ├── getting-started.mdx +│ ├── architecture.mdx +│ ├── development.mdx +│ ├── troubleshooting.mdx +│ └── features/ ├── app/ # React Router app ├── public/ # Static assets -├── source.config.ts # Fumadocs configuration +├── source.config.ts # Fumadocs configuration (i18n enabled) └── react-router.config.ts # React Router configuration ``` +## Internationalization (i18n) + +### Structure + +Documentation is organized by locale: +- English: `content/docs/en/` +- Chinese: `content/docs/zh/` + +Each locale has the same structure with translated content. + +### Configuration + +i18n is configured in: +- `source.config.ts`: Enables i18n support +- `app/lib/source.ts`: Defines available languages and default + +### Adding a New Language + +1. Create a new directory: `content/docs/{locale}/` +2. Copy the structure from `en/` or `zh/` +3. Translate all `.mdx` files +4. Update `meta.json` files with translated titles +5. Add the language to `app/lib/source.ts` + ## Writing Documentation ### MDX Format @@ -110,11 +150,22 @@ Fumadocs provides several components: ### Adding New Pages -1. Create new `.mdx` file in `content/docs/` +1. Create new `.mdx` file in `content/docs/{locale}/` 2. Add frontmatter with title and description 3. Write content using MDX 4. Update `meta.json` to include the page -5. Test locally with `pnpm dev` +5. Repeat for all supported languages +6. Test locally with `pnpm dev` + +### Translation Guidelines + +When translating content: +- Keep all code blocks in English +- Translate frontmatter (title, description) +- Keep technical terms (Tauri, Rust, Svelte, etc.) in English +- Translate UI elements and descriptions +- Keep all links and URLs unchanged +- Maintain the same structure and formatting ### Organizing Content @@ -142,7 +193,7 @@ The documentation is automatically deployed when changes are merged to the main 1. Fork the repository 2. Create a feature branch -3. Make your changes +3. Make your changes (in all supported languages) 4. Test locally 5. Submit a pull request diff --git a/packages/docs/content/docs/zh/features/meta.json b/packages/docs/content/docs/zh/features/meta.json index 4725321..2fb2ded 100644 --- a/packages/docs/content/docs/zh/features/meta.json +++ b/packages/docs/content/docs/zh/features/meta.json @@ -1,5 +1,5 @@ { - "title": "Features", + "title": "功能特性", "pages": [ "index", "authentication", diff --git a/packages/docs/content/docs/zh/meta.json b/packages/docs/content/docs/zh/meta.json index 8ad7ea2..527801e 100644 --- a/packages/docs/content/docs/zh/meta.json +++ b/packages/docs/content/docs/zh/meta.json @@ -1,11 +1,11 @@ { - "title": "Documentation", + "title": "文档", "pages": [ "index", "getting-started", "architecture", { - "title": "Features", + "title": "功能特性", "pages": [ "features/index", "features/authentication", From 2ff4c75054aab3753432441fed374a8edc3e79d5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 21 Jan 2026 17:02:49 +0000 Subject: [PATCH 05/18] docs: fix meta.json structure and build configuration for i18n Co-authored-by: HsiangNianian <44714368+HsiangNianian@users.noreply.github.com> --- packages/docs/app/lib/source.ts | 10 ---------- packages/docs/content/docs/en/meta.json | 10 +--------- packages/docs/content/docs/zh/meta.json | 10 +--------- packages/docs/react-router.config.ts | 18 ------------------ 4 files changed, 2 insertions(+), 46 deletions(-) diff --git a/packages/docs/app/lib/source.ts b/packages/docs/app/lib/source.ts index a8b5f50..97cf767 100644 --- a/packages/docs/app/lib/source.ts +++ b/packages/docs/app/lib/source.ts @@ -1,17 +1,7 @@ import { loader } from 'fumadocs-core/source'; -import { createI18nProvider } from 'fumadocs-ui/i18n'; import { docs } from 'fumadocs-mdx:collections/server'; -export const { utils: i18n } = createI18nProvider({ - languages: [ - { name: 'English', locale: 'en' }, - { name: '简体中文', locale: 'zh' }, - ], - defaultLanguage: 'en', -}); - export const source = loader({ source: docs.toFumadocsSource(), baseUrl: '/docs', - i18n, }); diff --git a/packages/docs/content/docs/en/meta.json b/packages/docs/content/docs/en/meta.json index 8ad7ea2..75bf27a 100644 --- a/packages/docs/content/docs/en/meta.json +++ b/packages/docs/content/docs/en/meta.json @@ -4,15 +4,7 @@ "index", "getting-started", "architecture", - { - "title": "Features", - "pages": [ - "features/index", - "features/authentication", - "features/java", - "features/mod-loaders" - ] - }, + "features", "development", "troubleshooting" ] diff --git a/packages/docs/content/docs/zh/meta.json b/packages/docs/content/docs/zh/meta.json index 527801e..4fd7ad1 100644 --- a/packages/docs/content/docs/zh/meta.json +++ b/packages/docs/content/docs/zh/meta.json @@ -4,15 +4,7 @@ "index", "getting-started", "architecture", - { - "title": "功能特性", - "pages": [ - "features/index", - "features/authentication", - "features/java", - "features/mod-loaders" - ] - }, + "features", "development", "troubleshooting" ] diff --git a/packages/docs/react-router.config.ts b/packages/docs/react-router.config.ts index cfcfbe4..51e8967 100644 --- a/packages/docs/react-router.config.ts +++ b/packages/docs/react-router.config.ts @@ -1,23 +1,5 @@ import type { Config } from '@react-router/dev/config'; -import { glob } from 'node:fs/promises'; -import { createGetUrl, getSlugs } from 'fumadocs-core/source'; - -const getUrl = createGetUrl('/docs'); export default { ssr: true, - async prerender({ getStaticPaths }) { - const paths: string[] = []; - const excluded: string[] = ['/api/search']; - - for (const path of getStaticPaths()) { - if (!excluded.includes(path)) paths.push(path); - } - - for await (const entry of glob('**/*.mdx', { cwd: 'content/docs' })) { - paths.push(getUrl(getSlugs(entry))); - } - - return paths; - }, } satisfies Config; From 63707fa434c37b61da7c8c0265553d1563d1e66b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 21 Jan 2026 17:22:58 +0000 Subject: [PATCH 06/18] docs: redesign home page with launcher showcase and fix routing Co-authored-by: HsiangNianian <44714368+HsiangNianian@users.noreply.github.com> --- packages/docs/app/routes.ts | 1 + packages/docs/app/routes/docs.tsx | 6 ++ packages/docs/app/routes/home.tsx | 141 +++++++++++++++++++++++++++--- packages/docs/public/image.png | Bin 0 -> 177250 bytes 4 files changed, 135 insertions(+), 13 deletions(-) create mode 100644 packages/docs/app/routes/docs.tsx create mode 100644 packages/docs/public/image.png diff --git a/packages/docs/app/routes.ts b/packages/docs/app/routes.ts index 60dd630..677030a 100644 --- a/packages/docs/app/routes.ts +++ b/packages/docs/app/routes.ts @@ -2,6 +2,7 @@ import { index, route, type RouteConfig } from '@react-router/dev/routes'; export default [ index('routes/home.tsx'), + route('docs', 'routes/docs.tsx'), route('docs/*', 'docs/page.tsx'), route('api/search', 'docs/search.ts'), ] satisfies RouteConfig; diff --git a/packages/docs/app/routes/docs.tsx b/packages/docs/app/routes/docs.tsx new file mode 100644 index 0000000..a1c1707 --- /dev/null +++ b/packages/docs/app/routes/docs.tsx @@ -0,0 +1,6 @@ +import type { Route } from './+types/docs'; +import { redirect } from 'react-router'; + +export function loader({}: Route.LoaderArgs) { + return redirect('/docs/en'); +} diff --git a/packages/docs/app/routes/home.tsx b/packages/docs/app/routes/home.tsx index 7f03ba9..b1f8516 100644 --- a/packages/docs/app/routes/home.tsx +++ b/packages/docs/app/routes/home.tsx @@ -5,25 +5,140 @@ import { baseOptions } from '@/lib/layout.shared'; export function meta({}: Route.MetaArgs) { return [ - { title: 'New React Router App' }, - { name: 'description', content: 'Welcome to React Router!' }, + { title: 'DropOut - Modern Minecraft Launcher' }, + { name: 'description', content: 'A modern, reproducible, and developer-grade Minecraft launcher built with Tauri v2 and Rust.' }, ]; } export default function Home() { return ( -
-

Fumadocs on React Router.

-

- The truly flexible docs framework on React.js. -

- - Open Docs - +
+ {/* Hero Section */} +
+

+ DropOut Minecraft Launcher +

+

+ Modern. Reproducible. Developer-Grade. +

+

+ Built with Tauri v2 and Rust for native performance and minimal resource usage +

+
+ + Get Started + + + Features + +
+
+ + {/* Launcher Showcase */} +
+
+ DropOut Launcher Interface +
+
+ + {/* Features Grid */} +
+
+
🚀
+

High Performance

+

+ Built with Rust and Tauri for minimal resource usage and fast startup times +

+
+
+
🎨
+

Modern UI

+

+ Clean, distraction-free interface with Svelte 5 and Tailwind CSS 4 +

+
+
+
🔐
+

Secure Auth

+

+ Microsoft OAuth 2.0 with device code flow and offline mode support +

+
+
+
🔧
+

Mod Loaders

+

+ Built-in support for Fabric and Forge with automatic version management +

+
+
+
+

Java Management

+

+ Auto-detection and integrated downloader for Adoptium JDK/JRE +

+
+
+
📦
+

Instance System

+

+ Isolated game environments with independent configs and mods +

+
+
+ + {/* Why DropOut Section */} +
+

Why DropOut?

+
+
+

+ Your instance worked yesterday but broke today? +
+ → DropOut makes it traceable. +

+
+
+

+ Sharing a modpack means zipping gigabytes? +
+ → DropOut shares exact dependency manifests. +

+
+
+

+ Java, loader, mods, configs drift out of sync? +
+ → DropOut locks them together. +

+
+
+
+ + {/* CTA Section */} +
+

Ready to get started?

+

+ Check out the documentation to learn more about DropOut +

+ + Read the Docs + +
); diff --git a/packages/docs/public/image.png b/packages/docs/public/image.png new file mode 100644 index 0000000000000000000000000000000000000000..5bd52e134008efacdcd2e92e2e737674cddecda3 GIT binary patch literal 177250 zcmdSA^?_l-Mzrlxo7eHIbS`0 z!g+q!eX;Y*%zfW;-7(h;A)h`NVV`~W@O}mrQE5!goa$-aS-lL zKT0VN-oa4gQ*6oh5?y*ILNAok&9d#4!4{0e^e%wF)B& z_~WAfe}1HE>qHQEAjQ|$|L4s?!Bs@T2Yk9{rcu=TzjlowseVD=iF0wPMcszCZ$kc0 zkJc^mwJz>1K!@@MU&=>B_P?_Zj-{i@NRgdJx5ci8T(DLCvo0b#Vz%!We1m=@JmpOG zWh4GwqL@bEZ;r6&1n{sFlfC8T|BO~)d=e^Cq90_LaOFHn>EZkJZ<`c$1w8H~0-tfo zTtg~ugOKE3BT-S7b|Ezg(Z(|-JgQEv&zOmMXa4Ot__9R=fg#J~kmLQ(C%Y5J&h8^H z!N@=8OG!avPEJ{M=>k+RTxKA@56&DzMwIDUGM?;=TU3@AmLsm;g-~uJK_k- zFsSvfDa2Gmkl#9{JcO%ldZ_Q1_O-={0Qx!|n@!YH2Ivr_{?6JhZTzjH2vq!=^Zfqp z+#9Xz9+@P?q2?TRzF&chUFd(omScPrnf5)^byVgMFtO>bzN6aLwmd^@+MLIZwN^Q~ z(erEW%|G)yYswbE>B?WE?lG5-{4z@+N&tUE;5kA7Vmev%t-bhbm!ZMWpL%6nlqKLv z6_NOiUpeAii5S$Tl_;O%zp}0*V)!e8eOeKyJ8Bspvo7YiMOT9iu;DaOEdyTOrH4P^!&1O}QAo)XV*)abe z^{*%~bo+4d5-mwG*yB>Ttx}h_%1mO4ZPw1DA6fy9!2o+Y`W23r2jvPPudM%@BY5y- zDSUj|arxWnhmVMSo&7&Xd-$ZK9=V;2S7$pS-JH&q$@=cw`HOP?4CIN%2axXNE zWxkfPjF+7popRHR%3Vhq>{doC$@O=lV7mEn^nG_tnQOPPA>2KwYu#%7;8=al#d`j~ zzJl>h>tq}daxe+IDe}5^l=cNJ9Eoak*-t69sA+OZnz@{RVvZD+&;`7{;2eftM^=on z!2aZ$cv&W1MQJW6*OIj$8mxarU7sOBk;3^c^_wJtvy4kI=FND_+s#Sw2t$ZzuNMux z;QXt9UIv7gah#NKN0o`ntD$F=s08g^o?0XEVh2>DqzEZ+q|NF7lS~wn>7`bkRE}C% zPgAFFzYY60OxEp4y(8%mWyfs&h5JvE!ge0=$I!7mDHa%;PIjA=qjd+ponRsrL&Q}? z)66U>mOZIWEYA4HqmdittVKhXYCayKHnvnA6{Bzl<8xsRWs|A|vJ<)W4l>C9ta)cslkH zQW*Yc(45Lpn<0a|asg*=%8?Oh!|8pL>iwHxGl5k z0wgj)myS9r=IodwM115tTK`lM3UhrkDYS&aOHvj9N*%Rt&aCzf1c`f(%J4;hFe}o+ z&)9Zk;d*pic&677Awly%hn`!}iU+x=JK4OhX#GkH*|i>_TQjk775jM_zGw@Xg`h$1 z(`e7;l6EOj{(#P$UP_QTDB;dE&uvttS{I8JMVF41bZ$+5>$w>=p8FDa$ze*R5nRxO zpE>XUPN*FT(%gvnt^@G?H;h1w4&SfCOw8J`rT4X@z$my${deLkTG1GMrj3Xm^{qA3B>|Z`Z2m!Qs~N zSI}^pJKG_en~#t3%azE@b0%7G2UWOQxG?dq$D|uH-dwfVI*8-`N-q&L1CgUL6nEY2 zW_BI6Fcy3W*&0rtrvc}adaP>rUoz9?Wm3U3UuJe4Z=ze}>qg z?@A)E4%?VYdWD|a=2O2S)(9mIHylZ5wp+M2vx1P(vk9uH||k zzKSE_$2}E3)Sil2C8qu-e*c2UzJx z`Gm76pnvI%>}FryJA_B*7LnBT{OkT>KK5vjR{=O5xissp1LPT#8X8#+@)$1v_3;+O z{+yVo&Mqr_NT{i)Cw7C-$@+WHg-{7RuWGWyO-*SsJ;BnPTwDhgIJmeQpq3K}Nl7G9 zw=Im9GeleCPc+S6YY979!8`*2l-5XaBZ!>gsGmshxqCXzo(CSh#;�j&!= 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 BWmf Date: Thu, 22 Jan 2026 10:11:16 +0800 Subject: [PATCH 07/18] Update packages/docs/content/docs/en/features/index.mdx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- packages/docs/content/docs/en/features/index.mdx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/docs/content/docs/en/features/index.mdx b/packages/docs/content/docs/en/features/index.mdx index b36bb61..9b1d1af 100644 --- a/packages/docs/content/docs/en/features/index.mdx +++ b/packages/docs/content/docs/en/features/index.mdx @@ -12,32 +12,32 @@ DropOut is packed with features designed for both casual players and power users From 6fdf5d2a7a8e9944f40d1d4340b827b06f304bc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=AE=80=E5=BE=8B=E7=BA=AF?= Date: Thu, 22 Jan 2026 10:11:30 +0800 Subject: [PATCH 08/18] Update packages/docs/content/docs/zh/troubleshooting.mdx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- packages/docs/content/docs/zh/troubleshooting.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/docs/content/docs/zh/troubleshooting.mdx b/packages/docs/content/docs/zh/troubleshooting.mdx index 3785adc..ade6977 100644 --- a/packages/docs/content/docs/zh/troubleshooting.mdx +++ b/packages/docs/content/docs/zh/troubleshooting.mdx @@ -429,10 +429,10 @@ taskkill /F /IM dropout.exe **1. 检查权限:** ```bash # Linux -chmod -R 755 ~/.local/share/com.dropout.launcher +chmod -R 700 ~/.local/share/com.dropout.launcher # macOS -chmod -R 755 ~/Library/Application\ Support/com.dropout.launcher +chmod -R 700 ~/Library/Application\ Support/com.dropout.launcher ``` **2. 检查磁盘空间:** From d8e2571de77fc21340f29946620dad5f09ebe990 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=AE=80=E5=BE=8B=E7=BA=AF?= Date: Thu, 22 Jan 2026 10:11:58 +0800 Subject: [PATCH 09/18] Update packages/docs/content/docs/zh/troubleshooting.mdx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- packages/docs/content/docs/zh/troubleshooting.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docs/content/docs/zh/troubleshooting.mdx b/packages/docs/content/docs/zh/troubleshooting.mdx index ade6977..c077528 100644 --- a/packages/docs/content/docs/zh/troubleshooting.mdx +++ b/packages/docs/content/docs/zh/troubleshooting.mdx @@ -187,7 +187,7 @@ sudo pacman -S webkit2gtk gtk3 **3. 检查权限:** - 确保 DropOut 可以写入游戏目录 - 检查文件夹权限 -- 在 Linux 上:`chmod -R 755 ~/.local/share/com.dropout.launcher` +- 在 Linux 上:`chmod -R 700 ~/.local/share/com.dropout.launcher`(仅当前用户可访问) ## 下载问题 From d3b5ea2ca1c90d84998f62ebb5f64043c8e01501 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=AE=80=E5=BE=8B=E7=BA=AF?= Date: Thu, 22 Jan 2026 10:12:15 +0800 Subject: [PATCH 10/18] Update packages/docs/content/docs/en/troubleshooting.mdx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- packages/docs/content/docs/en/troubleshooting.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docs/content/docs/en/troubleshooting.mdx b/packages/docs/content/docs/en/troubleshooting.mdx index 33464d2..a97e5d1 100644 --- a/packages/docs/content/docs/en/troubleshooting.mdx +++ b/packages/docs/content/docs/en/troubleshooting.mdx @@ -187,7 +187,7 @@ Match Java version to Minecraft version: **3. Check permissions:** - Ensure DropOut can write to game directory - Check folder permissions -- On Linux: `chmod -R 755 ~/.local/share/com.dropout.launcher` +- On Linux: ensure the launcher directory is only accessible by your user, e.g. `chmod 700 ~/.local/share/com.dropout.launcher` ## Download Issues From 17f6e8390124493031c0d1a3b27382f29524394a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=AE=80=E5=BE=8B=E7=BA=AF?= Date: Thu, 22 Jan 2026 10:12:25 +0800 Subject: [PATCH 11/18] Update packages/docs/content/docs/en/troubleshooting.mdx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- packages/docs/content/docs/en/troubleshooting.mdx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/docs/content/docs/en/troubleshooting.mdx b/packages/docs/content/docs/en/troubleshooting.mdx index a97e5d1..491fdaa 100644 --- a/packages/docs/content/docs/en/troubleshooting.mdx +++ b/packages/docs/content/docs/en/troubleshooting.mdx @@ -428,11 +428,13 @@ taskkill /F /IM dropout.exe **1. Check permissions:** ```bash -# Linux -chmod -R 755 ~/.local/share/com.dropout.launcher +# Linux (set secure owner-only permissions) +sudo chown -R "$USER":"$USER" ~/.local/share/com.dropout.launcher +chmod -R u+rwX,go-rwx ~/.local/share/com.dropout.launcher -# macOS -chmod -R 755 ~/Library/Application\ Support/com.dropout.launcher +# macOS (set secure owner-only permissions) +sudo chown -R "$USER":"$USER" ~/Library/Application\ Support/com.dropout.launcher +chmod -R u+rwX,go-rwx ~/Library/Application\ Support/com.dropout.launcher ``` **2. Check disk space:** From ee8b60dbeaaf70bcf7ba88b3cfe9756d07b4e430 Mon Sep 17 00:00:00 2001 From: HsiangNianian Date: Thu, 22 Jan 2026 10:56:11 +0800 Subject: [PATCH 12/18] chore: Update favicon.ico in public directory --- packages/docs/public/favicon.ico | Bin 15086 -> 27104 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/packages/docs/public/favicon.ico b/packages/docs/public/favicon.ico index 5dbdfcddcb14182535f6d32d1c900681321b1aa3..be3c2851b4f72c5244ab5d5be5ce3b69c90acb7a 100644 GIT binary patch literal 27104 zcmd42by!v1+C98B4bq^bl%yc3glrlm1rZhL?u|$&-7Q_xAqa>Hh)4=-x)BkP?gr`Z zZ*F{^bDneFbKdhi*Za@swf1twTs7xC$34cF69|GqSP%mP1pYBV!&nex2DXTafA5o` zL69Ui1W{7{-Z#O3pa-}R#LN48pBEp3$_PLi$>00m$RTK+3bl>;#{gXy1?RaTDCEA1 z9049R9ymy#ATRsi;v^`51D*#txVr8@5Y}r2S*eH4u+=*BOlHkjEt}^~YvFBOdG<=i zg*GE)e=L?^>8})v()k6L)(&5kTe;>2iCXs;iJ$cHn2pFc2*yAk!#1=ON{X3I>u4mzpkPVSJL*G5pt?Z_8j&0eqCqJ{4V* zT_tS||6_HEqoBje9g4%>EvzE%!|Wf`WID~S01vHDCXK03)?vj}fEc)A{h1+O>?q$| zt7doB!kT&E#-k`@KWDnK5FBR16t8RVY#`=htpew!M*6Qb$kn{pYt(D*TRmF>5}P-K z%?unQMjUljIWTz(SZ0JbXuC|yT&_4I*`$X=`7=w#SyZ>sxI+|ya+{yOblr<|A)-5; z=4o~9fk<&B#J!U%lw919_jM)gXpf2-E z_Nn)A6b4yK_)@x)dMG|yGM6yoqACRS#l#5;(xi~%}m-Ci|nAAF%=m$bn-aH5U9@uKk#M2=F$Glym8%BeICcZ&evjx+&5DO zoqrJ=SV)rKH`cjQg7=n}2GtQID{DwgBN)dHp?3Xk!ivM0AHTm`LRTo_5N7BhuR_p$ zy^?O|G`v+!)wcLhk;w42)^?OOU6YKhC-F>gvZHUfO&F|A`R9sE;g@;JZ9OgxC1yjK z5z6c!iKAvjO0Yqx)@HCA+*immMfJ|utNJP=lZ@zM_j?_QP=b3F+_2l0^q#YS#b-toz zG<{3&{Irr6{xWaO^r>r?+s0sPEqUi03DbQH^~AmeG~~gpld;~klkPPeN81y2x}8ky zV!fhhS=odMd()5QLCmXfqb7q+RO_GBRkKL1j;McHiq%^dl#!yflv3FSW>9 zJ3ac3THshqQ$cRz|4S zM{^K+1_Bw~9|;7pnA81i7?!>e8vmNDyl;bUK%?;Cu~J$2Ji_McOuFd0>9(3svGX9+ zp67bIGB#(&-ADl!h7o9RUK4a-J}gNbXar97h_sAD?McBa_%uo6Z1}`ppSSvG`M&na z^27^uLN`AuLpZ!m)!Cwz zAwgIWDQS-sX^b=L&W0Q^Q6N@JmP0CioQWL2T)z&DnF(z~KFgFz*8k(Z4V|Cm>3$qb zPes~){=A|cN-%trghaWot))8q{WmQcQbQTu%|P4jr0UgUcOkZ~sne5G`^8V{vn94y zoqyz2-xAdx`7mIuLMu_PjT~^=z_L9}BEN-rdvctKLd4XhA54n4udq3<2xYYBe$%IA z=suf*m99{>`gDhj^xfnOQ{V{ba7Yq6xXDgw`=yRSGV6z;*#qm=UMtz)2Y6+;G}2_Y z2R}2~N4z%ni*@H|#a6|$-aD31=}v$=8HdB=F+D@t`;y^e5tm#05V*gOn)A20^H0v?r0m z+Y6&!>??dDPz04j>4F^ZyVLzoF2dFXlJZK`|X^%56z$%4@i& zZ5RUvG_8LxxU*?n2BLI8vR~$a>U0d#{rL6;u<8U8k~s09M>xjJeD}y2k4SU&y38(d z3oz6f&_D_Xg($2mlk$ea0zs6`2-_e1;27Up757bW&(|=c)$oQs5=ag_|1oSxV;ojY z;B5mT0J?c!$0fc+U37khUQT4wb#!a7nuP8Qo8Ec9g3O&H8H+nQ)ahG8qU_+7q1rU2nY zHCa7xnySA8oIMX4;n2^PCHWoSn={I%@Vu?=HCoigITeJE*{CUG=t} z>xXFT?WyUwccgu2^$CVBXFg6h>o3Q<1Za3%;!Z=Ro%*3Ga{T@{1aWhTeG z%(2aZSw^C&h}QGfqO3*eqDDhqplwMkUT+xsJZ5Gp++)6kr8l{9Ap$vdFfV?-u^`bE zn{h$}fO*)y`=ock;hANmbx-J!I``(j#I~EVqCb1i%yhHEhrM*!gz{}{tTE<+o7ECSY;))Yj=KE@k<)ZOjCeZ&bU|2DlWWbJd+4W#SS`*n*ju=e zPhQ}>gP`8@l@_{-dW593g~>#t{cWy$lZVaJB?;uYRBE_i zTC3jQgcpp}Z|rR2@9Q#M5&Qb){blq%VS5P})~_Z@=1u4!BR*iaXWH(xrVGzq+B)@& z*0Cjm^Cq6BAMUXZQJ20z#oK^D1iCaOxa9H*j~TH&)jpeAKl3ltHelOdsUoDwwVb{4CvUjuI8hJW z%t|n!GVuCqY#|EW`c8fs?Bl(H_(D-wVi!n)05vE_;6#9xgPwAq#V)Cm3ov2m zqNo%Q84mmmfAr#qzjX)%u1EDN-kwe!GgMDFxu#7d6pBg22@=WwiZLif#(RM=8fb?> z5Oit(|9~+lJ=Jv?q}u5r{9sPhmP0^AgSWFFNWZ8p9Y&CV)4RP)?A!#oA5bwt} zp({-LFmL+Gqt=o!&Qcd^1_e0%Lr?+oXnuT9%*XCiz@8xmXb?-1lrjtkZnVaRi#l5e z#6g__zBe<%K|%p_7E~clmjmzo9YdOb`tKB{2`Nu{E~5rxwv$j8EsARpRtcMtpV*fT zM&M3s`d4HygT}-rMcbtPy^R45N`fzez*9iO0E)Y}w>OxGT|VlFRXxA4h!gOU04T^o zfU9N2_pAw^5fj!HAXk2u1$Z`sqEmw{l;9@_fg;UtB915AM9!h*&X@F-ZcPL+3URDH z_1tT%jX|EIAk7_&{kmkY^hDYS3JOX|OPYPsy5T}NKk;=mQW72%+%Pr8ShRP&sKL5+ zX<=hPRkU3KPLOWD)?2-O?1?L+>lJ87iHjM$z<@i#B`EkYHoFm>kcjAGw|i|Jpin*s zLeUu0o*3SMyfNTfPMhjYg*%`04fqpjb~V+Hi>wWac6ZjCy#J(im4pQX8gh+74d?RD z_qRx-WIyT^EgnV2KK?R2?Z09UBoL72+ z+7QCALx>0)gg^!lWsuKLYUvZ~tW>x|xB0em43yaIn!dM_ConKpJ*p&;+{ZSbx}4t8 zbGEGEuotcUqcLQ2T&$zI5yVE6Bwns%=DPXLX;|%gG(adOa+IXo2T~L?_Ax5-7(>jZ ziM)0~hc0yHJ=tf@&UNi%+O!fc!rXe&=bkxr7YFII77KZD$$5E*Vtc*dEEbvZ0Zd^; z7NZR4LSB%1FCrDX=p_|hf9O@fsA>|!FJe_g(U6ucH@|oPYR;9G?8~OT4qF9!$(y6% zUyw(_KQywgq_%?qPdQd-5bTNk9m?~bpvJbPHl$5hNsI(npjh>5^H)VwQje!3SgJaf zoZMZ=8yfwY4tN4lf=1vR4b}J1(J)+uKki;9GMy9x(VPbMWjfaDN2x5{X;AfYWn1PI}L6{A1)6cL|3HR#>p8E=^?kfpqXK$@7-IU0s0Ks=| ztDjhmR_bTc8x0ua`ZSIBO%>;Hw-6t}7<2 zAV)CZD$vr=ZSwP+PFMGfx^orisL}_Ww6D8UAP$p?$;ubE39i(w%s*f zMyiLctNG+8&Li@~SC_gL1R!D%zc2%u5s0!5o#%ARwrwV(mesw@h?Q{ft6fh{U-hrf zTD;CVMwDs7H^>!qInwo4w#(gLc1sQ1t!62-DK?+n)|i~qp2D|!BTXuGd_lxsRBBX$ z$B@RhXl??68vs8DcniEe?FLX6vh9R3$(-+;wZ&jfjv+lV z0(n-VKgUOu6g_NGDX1-)SGhJQa<;{D7S(Koo+kwla*>z`Ip1)mixZ_4eV(ecBEwxk zB;t95A(YAq-^5ils!cSeX(}0PcdxD2KWnD9J1yQutfrb(3g+LV+m530IyFbWT!OCQ zHl4Dwsp@YJ#Y8n-2I_osCr=_gX>EQ^??^56_PB$q9jC-5dPYxdx;#U z9IxSwk*8|oFw-t}wlPrqa^h%p!pPX+(uIut)=0l=B!~({zVe!PqMZNx%ZWow9~)sBZ;NT%rwKW;$c z-YYITm#eLM>%G5Dzs3r?j_Nv!UeZ!})yV>FH>Xkubj=_FK?m{fdJ~r!2Qj39B+9Tq@T+>camcxtrsAN_tJ`@({JFVQ*&Fu3;ZY2b+$uAG zL`UUURsr0Qp%3VFDj*YpMEe#_FI~;>vQE8G-G2IpUd&*!-5&NiMlQ3U+bAhxSiLuF zlZgba4jv2JL{nhm?Wq@Rp(G>u{OZHNH9=X9&;8z24NFd*nD(i{``5ez``#8+us|&k zDq+H-Y!KU$Wqd7^5J;ja*q=c1MUYiPF#r(E9n_q^b(=@sCFIsI@;tRusoCcI=-wdq z>+HJ(aVX(ssbuU9Wt3({RDc^me~^Md(UZntHb;Mozy+0(BcF6lZY-iX!A)C~#HLLtZ!)6Kiwv?d z0ft=)1PSnk96eNJ>s1gSueMaPBm64qeVkR$Hr)rmVP5y?JFyNq4mp?no$8_8liiH- z>ya*PVLw@;l@Crp50Lx_t{yQ3=y>)^h8QVaA&z2CgowIXW zK3NK_glDSTT218K?V%@JZOV{8FRIT~X4n8*0@MZ|g?}FTGi3rezfWS29%NHi?j)?E zqBAU^G_j9(icxS2+%(Ch7F-C)Vh}Oo0uW1P<`#e+LJA;2_8nMrg0H1nBZ_E(&-IXg`o|QQa&34lrjF3{n>4NPz+GbHPgibv<*s zMhuJyu*e&Ux`yc;< zUXTRmB`@^CJ4?H92qI7TKj?+&UY@7MD5L$q`K5O z*rvrOb0Gwgf$j4@PA9#EQz*cN{?kI?yI_Q>wg0e4ZvZM8)pQC7F=%ICB7o}m2DA_m zThJa5sBLBtHWI*K01^8y3o1Nh1mhY1?(F}=ZJGqs!i&4n0q+Ar2~ZDo3Q55G{__C= zH5YE+%l@Z@8>6RLu&4V!Edi5Bf2#y2CKv}q=YLxv{>&Fv45}``SW*tTR&u{Q9GZ1f@}J2+DV{L^+JE4y6C^zQ3q8A+Ez=csY%ZBAZU9r!Ig~F_QCVEne%yy z!@~6=l^AIb9~zPiLtL5=JC`a$95UpJOl}h2YG_Y`4Z|f#C;_4biIlS@ zD;pXdWzzl*tW=9GYNqEGMCsne^ix)!0--V__Z8zaJPRO^2{XCC_`;O zRyO4>YS6H?Z=HH575na+`rvMtjh!#xpb?L1%H7{R15FYKKZjh}s8s90mx$wdEr9Qc zb=qr8|GtfTWN)=xMEf9C3WY2h21+r5kar-a^kcLE0}!ZQiyh++2JQf$G60nI0qh5L zAU$NV5+(RcU%=Ps&wPVM2kj~p{c(MG<=)RqnfoHoLnU&5(v9GNX0twhdS54~_|SW(sf$0EI<9SplA$l z8|G-s%+1>M(^~j^&V+xv_QR`N703e-&q)ohm$A0{c=)PfodFrgG+9M&v4%)d-VpGW zWX-+NB`NN6nd^94eM#466WSYoL2Zr8Ay08BmIOBep9tygn=D*v*eFhiRaDcaTmz2naMgefhi))(DhyHQ^!sr3%{~rN9D)%YR z6Nx#leUIbylEY~syCYpal4L_gav$RVr!3%4{Fn3q2--#Bm{K;%&ePSh?dJ~Ym<>aDw z64DD#bxldAUkTYQSP*_fw;8qabUI%DY|f=ghOWc$=Cl1Fx1{a`Ff#$w(%|a^f32?C zZ4F`#=)1)T5~PYEI}w6xfYx}%IR9=^7=x5`h=u!Xke6_zXTFf(7V9G*I&D3p*N+O< znK|N^5WpYhE`hO+I1rw13AU6Rr+Ox6ys>erKE7AfCNpvN$R%(OaxNI1T9Vjqbsuo@ zAUZX|0#X$)ED$E%KS?dzn}WP3BR%qkOm|q*2wg_?&(S7!$0qJL+?m!yTnoXL{B8Z9 zh9$TK*qgQ%qg2m#dJI=uoF-Mz=bwJMl|`<%nNzqh`IUZVTjIRr2?8;FGq@9F|HwJ6fmNAaWAvo`CR zmiN!PWhP!u9QfsZPl$H0J>uV@@!EJ;=(4E2nOwAa{TDqgDa%Fp!6cJkCkCzQbmpt) zUA$OCt8dy6mS_n9*q}c9&n{I{VgXQR!#UplKfNe3W)A(xW)Rlo}gF4lYW@FE9bJQZ0`fp$2KQ z1ef@n2@FvKU0q1baK=K~!xXY`0rdtc>{la?kCBs%LXNbBq=wQAT~pUx+6b)R^@ivE{(0i@(^E~o^?tgRZ?_-& zQEIiW)C@OPtS?D4uAiRKmz2~5^!+B9{))VvlS^*EGHY-dKWx?u9n<+#E^cJ&(e$+N zBDB)a1iTv5*Q>*ufkXN`4}&y6G(PR*bskx{{xf6lB99dqiv_=aUOoO^EUZNJT+?%( z=*%Cy3j&ajV=xKFwJBSFv;{7KrbTU0-Q$KNigW?JeoG16><;<*Ig7-c}v&vY#rr^4;RE>VC)HOd0C zTU1zg2@sFLom{zW${2*ZOj^EtrG{$gYNAq!u!TvUym#o*tG?u>#d%YXcbEGrgT5) znm1wnn>B*EQO?6$OCwr2s{%(|76BM)%mSDYe|pP*@_T?A5co8rH>9&xvMj>85j?6x z=?-f_XK_p4W1cuhVKFdAq0ELqNY5WE=;A$p>w+HHzsMF8iBv#iP^_1`wtIjz;Q7sZ zy4Y@_{9Ig|nmv?`B|)J<(#!}<8Tx050w~5`q)yCRX)qn_uR@3nO_Id|jK)V+Ma0@} z^ZzZ{yIQO!i`u=}S-G5odYzt&7}vVN3{^IOjV;6rEdH|70Yb4#>n^I1gA&uf(% zC0>oa6XObqZs?gni$VIGe`0(8K>vVL)*V)p zvs^nalrX6{CN*`75RgJcIb106{!a_&k)eQAqS1hmXq(U4nA9#bbWj_taSVBJleDDc z*7~v4k64<~;~U6M=NB1+zwB5c6sv1j1|)Lku(;cyFekH8MCt^NVJ*0uXa=B=YflyrsL5!fMbB_uqLd!1AWi0o+4U= z@qY{hzc>^%xOEpbE^%@GpEohQ={6TB%K3UC$+;4+-COd!xKo6x#k`J$oMH<|N;mK# zZ=(yHVrHDPWHcV+Ig!#_1(f=dQA%(_OAFSG*tuRt5~r& z11zXH_0Zey*H024@>KGiAxc-&zdK*EWIS7bc0z?n^-|Egnrr=GfJW?cM) zx3s1Hj1Ed_2N~1w$u(S26uN`q`#)^0f4Rfzj1oz*Wzns*gPq$zN(e6akXZ5>8PmaM z5L?qc`yHPxfgc5AZH2z96yDGGETxavG!#v1^omOyXgNS$1E~J@Y&xY1umlI z62t(rX+9LQ;2v<=hp4xkeNStYQ2F@ZIRet8U_cD0Tx6Gtn|0{K>8ZqYZQdz<(Y_Ut zvBlN*QuqZkC_uhY7*1a6k%QyIOadrV74TCQJUO|bxCev7!}WqOfLwfkE|x^_?=6SF zja8xWME+YcN%+1?#{L{1&u*^r_?zXZ*7IGSEda%7iP9Vm^ZdW%6UyveH~*oP)IE>i zm|VD0;b?hbqx@Z4{jIkp0dxD*sO$o}P#zc15v>8F9e+@n0rhjG{!8EI|A&Un zf9+cRk9zoTy`GEI0sKp9;LQIkrT!1C_CHGe3FiL{&;N|pZ%@u!B+xW;{Hh~ndLRDp zekKf@hCvs8rjGqvFo*s2=7pa*yz1fNtkWOAQ1l}H-J2Mb8?O*UF%<1v+%&BQeT7g5TvRDfzH>ej>p$GQ{Mcrp)@fzbVO?xLb)s14hE}q26PY*WOkluS zi5A0_Y&4j+xF~KmPl-;aa97OSD3VEa zHU#d_R`UJ41rfrH7R?3?C&PHX zQzaRQ6Nyp@@zFn#^>Kt?ncjX02T$VX=~4MC-NePOM@;2&M(hIKB}pbdO}IJuvBl_! zx5;uA_#85q+-P%rHUqpsyYvv$RjjhJ2WND~5-l|M&0qZ@#1fmz{W) z&!6o6Y)Ccy)!&{lg+cDZ#1lD(%a#e=%7sf+7Fkq=prdF zF`o{u4tqy7PvZnNF0QXH)ayTaf|J+RzTWFlFOM&j>U$#ll?HmClH6&J0<<4*VmJ;cP4g)FSrlQh$t>&7>Y&f0B7qpKftCSB)JS{_r zCXnYr2S*y~%ImAzgvZ6m?#Mn}wH?AHVtmUhb-D(3EQ_z+x=eWU>sFTKE28pod$QVR zGYcDosu@jvgKxygWtEp>D{Ljbr5c~RK3NbgJ`!vA zEzFOs#O&7F+K{PVL)<%isgL-xVrw(Ds6;B!7^u+E(Vy^oiPL#*z`AU$W(UqI3b0ek zh$bJJV?d#IF}KkDp%s2;*xfEA`A|fBzU; z&o-LBj&PS|XX>NYRs8+SZTO;m6n0JD zYZfVQGwz=+PSGAP_U3EeAngy6GOnQ!D&%PWoF8Ciw$hxYe}20RG4#^N6k~dZ7fs~Q z@7?*dm8Sl!Qmnqbp4s|)=!eR3U$jmS)CD}Jb%G2lBE66L&{SVjsK2-76&9|W$hOXU z1hb(s@eYBt4Py4D$EJFOhZ8tY9WFR;tl$0?xgh9RPapiArS?XtPR);%-a-z_myOyM zjR{ZR)@5PQ)A*#=)(~K8X&=5Z_`rsNdj7g48v|YGK+%k;yZOSBeJx)l!fbA6Lq4Qr#x>ou{sp^84h-Qm@ zYdiVlxU}x2-X^PSz`S?xb;3)VAdXRHtE2>%dh#Y`!mD^=voXZp&dOIYrH)vMWi?ZKjkQGmKKfH7u8g3a`7BreZd))=qQiX z&XhE(%HV$b-YHYFROBW(Zz)Np=J1l^>rd~n)H~kCkrfHAPO*iZ!X?@{v2RNWk9kV( zMu(3)d!s^(F&~t>D`L>qeob}Z-mCAvoZsTmPR{3IcY{0f4l z#pl8F+h&I!t@^LS_fLB6-@pH?oo;P(%DFG>=jM#u{Yh>URk7~DMpJ5gk2h?BD>z#r zn+SCOMjoMA(=@Vgxn?}}TDoNj5ebQJ^9v00d5!7CPaFv&!&{1xHu6*u&tsi3TI9hT z&!HB-2Qn$DRW94gjcnuCCCY5}Nd67=hPXaQ?$00Z`Y>&j>KI#$lLEo5*=9}S$)d!` z?%kcT7vVGi%H>&5!`YzZXu?ktPzHN9Gu(gOo7a4gE5i2@hwZ+_5hI20_@aY}q~)Bn z3z?ni;1jBt7QGDd8MX(97~EPn@)tH`WiM4w`XQz^IvrFbb@NA`3Rzj@Zdr?++R>#Z z!EIQFOib7#y?G0AsWA)D{H5!AdGbDWZJHH7QImM@a|#6!m0Hw>Im*8&9+2}OQ@M(J z`)Xk{m7j6^4O&ml_=M*wlHDBUGjVzyJ-7j6i8$B-r6l-l72QllLF$36!$d>N65PXDBui~tq6|E+BJN&G-IgF3DC#*mQk2Axtc-qyE{XSMm9udUp@K!sPx|JwrqvOc9#2kUT_j)^eDT4 zsUe9#173C!SS%z$0;#gWz#sF?AVb=N+Ti>mU!o9J#(Fg^EET3Jf-*7@Y}CVQnM!HB z38s#cF+RWO7iBtY(-xP15s%j?cz>XQ(rWf=?xiF(7Aa6cMq7;hk;;qwAl!doVZzi> zQiNMa|a;ZGa&vSXfNQi7Xk~Z5a)(Tg@8FPm}gbDG;fr_b~H(lpE zPD?zcTrwtoTh-mmr;fOzqhpGbLjd7bNLETbAo=`Wfvd8Rn3u1?U}9T9Xr?L4=AP|D zEqbIxak~B&yKeH_&6h2tybV}UUt>NnMP3!sRj)4+tJy3ctTZpbO~^G#tkHKCyga{1 zxzUxRzT8WAZg3v#IJrrQ#?LIvt(A=>VROS`J!7d4s~%%nrBEl>3d1k=FX~n?H}?TvvanE(?yTjl#z3I-l-A2lm@r*9;`&WG@Uzb zHTCZ3rQ!SO(b?QY-#h8KQYBV>C#!y9VxUu-!0zlG;a~^n`!)KnbOLmX`60&fc~@}> z`Ha^I26Q8Sv8Tp0Z{F;h0vnNiS`6=<{*81!r+&`T~4Npz=l z?pfEv5g)Re;C)O(yJ2pTR@dr%>(A8=mpy(c=CuVK9aXw>%AD1!QNg-H-sYuPo%q%p zcnd(`c<0^CXPt5`BBs!1NiqtR^xFYMWr+IWQfoDR?U%VnXpVcby}g&GaKyiKH=t{0 zLjyxz>gefb_qu0iS0iOff2me%JH#gn^o14*j2(;@(bw1Cr@$*9Y+~XYRKlBjn)-5Z zh*7p@r%_rQrZm4Uq`vi*zMVqy_=VAS4)x3EXNlLaz%+bIIeXbJNBfJmS>)MA5cQ*x z%w<&?G?}xVU8*JhC>ST!q)dm>kdKXx+~!wNuR7Dt1mhPT1dqA*UcYI3c~(z(gf)W` zIFs7eIC@i|hCNttv5}_NEKek@kmg?Wd9N!foXZ`o5Z(JgLiM=jp(-Zx>Mf8 zk~vigc)YS~E^u7bx-wV0y0S90zsqmPU&opNFW`pe$gY(;_b3qFNjZG!aqx4@$#*|X6X8eHUGdimTFg(<9WzxQx)js9o#4W^79;y#Fkl2V2l|is##mF- zeR(KS-oV%G`!*i4`|OM;BI`W-N;=04LK^NC#pIRhO~=!RE0Kx5NBxqlcV3GlQpaVS#BTj3xamL()iXz)hSu%NO?-w!;-eDDV+*ek*liM%3 zVZi39KOAsifO93`ROT)N83;3Y%$*U&4u@~YF~O?2_fp!q8g{5%cG{uE&Z7oto+8>d z9DE)^tH9&SF2=mj_7yG#>gJc7R}^%kqPKqKCtc4>y?--S-DTsEhK|o%=d0IhJVbhN z*NMazTl4q&Xh(|Tu_wZe*&-TWlc!}7RQ7Q_t`#4@q%Iej#jYbvz>=Yd6KYS++BjSq zOA`FzxOaObEjaa8K=iITnfU;@a5Qfc3>Nj%O&+2d@Z@eWw*mXaa!%>TzARK{K?nb`;V4SLv`szPDqz;*3CbE z{VR}VSvC_dB=g0zL9zCbJbtxX6#bPgGInFx_dd!Kwk@-oybTKi*9m0>#*5m%u>Uff zhWEWDLM(e<3dl*%_#rTTOi?91O#RlwlPNP*A32IQ(Z4;ZtC?3FG>i*N!-{kNL=wSI zbfh=Z`QF#Dx{i4=jOLMOL#0qYih?|YZ+%v*r}qp~po@+gyyZGqJFu6z9$&N5zQZBO zL>XY-?ie?5#5Wkvn7QCu?epwg2)v{t_CrLpSia`N1av>I+rDcQWlU>C)_D-#&Be4n zrTd#X@$8AZ^*x3p;^ICoj98QIZKBYIrkLKlZ`S?jx%!sBOt zC++sFV5=)n!o2JJiP4|&eS0N&6|==P@Z0H02A^ymWP-8i%=O4U+i^^qyuk8%*j>2c zunCjYnKXW#9OLUl$f9ol1bKDQ>r1>Ul&OLhv&k%qUXw78eUdx(@qVi0U^P{M?}zkJ? z#r|6a%=fqQUD!{%Naq=qTBbj-5YKWoL1CD*H{U$hJ?C`mJs#G3$tF&5ll*1Fh)(Dh zPoejiMq4GO5e7yj4j*KUS&11OFAq?pTkhE&g*Gvf?B{;T2iun_%v7W*?Fp-vJNl$# z(4@Gf@avoR!DYdY=Vk}%u+@aEf1;wj*+eYE&_)srs zE4UFKO7d1c=hjo>LQt*zuF}g>oRJo*m=nG6uPJ z=cczB+bu~%3o&l}+A)<8>4*`GcB13rxb|)POIolaLBoE#i)>3EMsHLQ6T3w^A^DeY z<%U8=ek4tZ4q;|S@GO4ro`HRS+&Q|Vd|NsXmZ~QFURng3 zM{Yvt3yGM0;6z`W!kcqhz4_UsWU_A$x4uis5MpSl2=v|G>8h&?Yq(Ed7K0WyR!y6p zBQU7>HabF!b^b_JPp>0Z*gNFz_3S7t2`V2+C2ToT`@4p++n3`!Uf>Fl<@p6N+ux63 z42HE~u?u=zv~gH0YK-u1j5EH#vaf-4us>9hoM>Ih`sL8A^-S%dZy-jJ52ZK4C(QdE zXMO*Ei}=oUY=#7GhhgD&QI>5KKc7{5XIBTGVt@d=D}yg77@fsfUPZfMEAq002Qg*z zMho{7Ie|;5DwPjF1MPS`>QC~sxplnY@q&SUQRUCG7Y=XW(698Wz#b^e2u6~r*M6kE z!)b0Ug7NUcBGnV7^e)}!&NB7vEoEDXHJmBdAy`*!!~)En`F zl3_Z}en?RTknEg2Wiv8A-O%m#ese3oH=HGl{pg8U(3Sn#&!Od)lqF*-4#XaK-ADSz zcNy?PU&aU{ThYr$($?6PW!}Am3k$bl`HXY2vs0=W+|sXSSzg^!$hXDlql7%Z<#qbK z2R4}o$2;v)$zdYmP|KI26B9iWcdOvS;yS!H&85CdB@fwX-I;doAyzEZZh8;HV`P<( ztWQ;Zc(OW|YC|dBo83&BYL2nvBO$z~u}{}JTIpcde3`S@WYg$oS5o-$yZjATv1&{z zT59RmB*M>hx5LszoeZ~+*Jm=1L|?~^t?YiH?c2%lIlAjY)hka9{?PK{y$2p8H@Tmr zhTY8$7Kwhz%lYgN6cs6Vj(a_|IP6y# z5o2XnQv_`qdW~BTv9mQJYkuuyx7hD{%C%(++uCEOa7qoCCp4(V-zLcHdDn+_`|ca2 zT$wMb_Ro!95VDqTE&b4Eo{7ykz<64-Yo>F$8QHjGA8x^ecTeH!!YW4NYu@p*nJ>;~ z<~)<(LS8*a3Y7}^0T-nhaVu|rU;t_mz#@jJjg1Nl?+$B5vO01LtQyoFio32 zcHTp%K})RRJI$-QvBcX13^kvuTZ2D8$PBvUF_0TqR8&NCiGsVy>$KIacyIZAsZ?6< z)M*6zV6O+c+-ce(J^=&qr4q`>u>eIUzUAt8i}WmVPb+kt$2N8cM=7?`UgsHJ&FNxp zYFZCE1}=x(WzB(Q`lxDWGMd5@Zs>L#y%@_YlCrbgq};K|<3|gC`z*bO@j=<%f}xo4 z-w!tmzMK>4pD(8^)jaMrl-Mgjw5#HLIqpO0%UIwyhWR+|%7~i!l;jK-PqLZit7Oj~ zt)55Bbe=n{TzxqaW7C_mDr4(%9eo0L@xBlIGo4JYYOsCJZ*C(Z9(<1HQM6WXFag!> zl$TF?oo!@Hsg=CYcg8{9-V)c7sJWCE=t`^>SZDYsut7S%Rf`7K6fx5-oMrWX@*%oc zavuJ`L!Oq2t}0pKxv1G=~q*Voss)%exx|Nv&9nQh`3Tc@YF| z+A7l#!<=?K6Jy=_E~f{CaL6>GMY_x)3w0?0KOP{kyaOowHmU755kw!AoMjBO_ zruOBz8RoJdNNolSKzqm@-FhvGaE^;*Z`hi-f{OQ%RYST-@ z!x5j#-QbFdrqc*TI)VqKO+@soci$L8n9t{EuNgcdi_!1ab1M3RIdRlgaMByJUmYf= zt#^l)&SyZat~S!-2uUQP1phH!{J!63WUa~IW^lR6dVmCJ!`veWyTgvi&F3|{d!p6x z{0)$@#rY|whudEMuHu9hL4P?-;TKQ;T0T>E?rcW_D@H6r|h5o zM=B+}m+?fG`y)TO580pWIU&`H)kLvK)fscY3~NCkmCr&R?|d52c)c z8&BBGqCR0!AtE~2?CQOJRqC}p>Dn)`Km#t{_;`onqmD-hr`ooh0pbE?=*j(OoiA%| zG_LCndq4R>d7C%;C{jm$NnmCZ9@t443V(5g=~p2qVsPc180C$|bdUVd_{3M5#)o{4 z-<&i9V|GUax&LPDmLt1Wq{NPFnAV*}w_+xe8Lqse{H`^ z#>N%bjYx?KieIm;d^9zdtTd-=M?6?r_VSrl_+VW@4AhDv?o+~ zo-oO#aYk{V6Hu{jJyDl}^wM_uTGK)Gs%`Onl z%U8I_@uteOZRhCys*4Kb(5tZpmRlL3xQ={?K4WgATlrO&>Q}8k7N>f4y=TutMx>;L zPrg$l;%n&4EA6NA19}KI`qq;%xH^rCpx3|LpIdI(j~^vA?(& z0RNB_{GK(5`B-CC*FF^(TrEKlsL_ZQ+~F1(3HS=Kv><% zy8?Os+~Hb0hxsll^$F9G^H2Gi5Xk0w^Bi(Vsf9wvofur*pQ$&m zJT*Qik&wImV8qo^Dt8@Jxno+~piJ>8`M45^C;6-l-7z!2IV3MwYG=R5b@rndFJa3< z-}A6_Fp~dgZOYUn(q4OP|2alog+18TUPUP$ASFw zw*`W8ml(d?S`6Va^Ija0H|fV;vdkra^jKXWUVmjN(!t#HLA-+C=_2{Sy|?*=^VYoA z8BDW|!XCKdUVJqfAFevhkH;Es^;f>+tM>~wSyt7OdGtl?UiL0aEwy{el4j=L5Q1x1 zpDXD5?uJ!K+sYJ6sphNVWaDu42>bWY$4WD4mfVRu*Ys0IbR0bcs8qN~LemFw@CVE9_aLVKEu^e)XS^a=# zZkvtunc(ZPxA&|@R6Qt!G%jxSm;e&kVYg)`ar|8Fv|*joET~f4Wik+jP@H|wBs?UIh5Swuv?iE3)f{QC^hwA7P9!Bw8GB8 z83PZ6D@*v_b>H-RM_-fs;C<)7yJ1#-oHU4O;I;bW|F5#M3~H-;_jZutPH`>n7ThUX z+_eQ-9EwW`4rvP%cPLJ9cXtXDhhjyFyL<4w>GRBc{%6k2`EWjFPjc_QX4cNy>$W0>R259L_#DjHn-U5NC8tDWlK~` zdNZO_TM`AjCI^osS1e&+BaHE1Ssg`ZirwA)y6~~Sc%$0QOWPphC{QMd?t$&WX}y3L z))^%?haEItc)wCOHd>-kul%E&Ae;&KA@L24jM|$P-F<1A) zDJ&daJiIT)wmt8B6a^{n;|EN-LRxzuCDyq>Y6X0l@F|57Q~{X|w-}7s+@2S_aF8pL z8>v+tW&4iA8P1+!Cl^Cu3eS70XONQcDhb|4hB4Y=N*{H|{bjg4-u#fkUt?iW;xaslOygH= zuJg^gY~7aj}|*faHTGaOE!Kht|We02rB+C8TfH2h&IpAr0u0yMgzuE93a7z^t{eE z2jBLJHI2bn?U;axw!j#{+U?OwXVw1K{f*MNnxIG@`cIOC4eQlfEB4B+6Q3RJvXXkp zwhLacd4@y@MB8+v#VU2saWF;7Bv>9>(&H0!t!(v?DIp}<6ZTzCUF<_Jy8Qd>4Vf_# zZbgj(A_;&0X8SpU^77P?a_Kgo=-lp;nJ~J6(w`+6u6!)n74M=Sk{<=So?~FgU7OIZ zKumdgc?3hP{L*pj&AwiJ`QYP}-GY_nN4((gWeRo3xY%$XEtQwj2 z28xU(u49W0#p$LY{{i1&Y`)*J(z@Qiaa}B;wru8PJyctnS7PXSXcLn%2p0iHO#16n zJhmmt&k+fmK*j7qZ>!YVNp`Yy!dZnlLp$D5S@d)M{^N?QUqm%hy1TYHdx@|89Cd87 zmBrPSTTpr*Dq-$`fs+4D$9XQsqb`mZJl z7A`JwEkpjLO->tOgozZ{?TWCn4!ad`@iS*wJlBkLz49qG_l)^$^MdE5qQ45Y0Y>X2 zra&w-iIV5@AK#nx2j~-k^8pGZlgm*4Xj1Ffl|si|GIp;U9)bb()}P7UONd&uffys_ zR7`$Zd17`QyqdiY)qNiu#q70FGq(ziBH_IgRx~2bPsRlMVa$&jmSP7qSo!SbDuO0$ zQ<6qUpVaf)>pQVOm|7qOTvfqB_${knx?Q`wZMzZqF1I@Q z@Q}5@*UhM8n;vsK#!dpi!;`jV{#4V#v{b#Yx4{=>ExJ0wdZj~2Y_q!iYd`~uGdksh z9_m2E7)?7KPcOB{K!vRj6re5|#+ZODOO75$qB5AMqTFC&Q)!?DEU6a_bagO2{T~>^3gE*^6-N$6$C3Z z9PAe}rIQh-0S`+glR{m;n)VnEOmz2`e8lr_9uwJl^Y{&;mrq5Is?A;FxyI4~wC#ux2l8N(LMXT*Xuk>3b)CeBK7-KGi0(4S zHf2)=_$EO(boyo7tp?cJ6E4d@A>=4wmP_2 z`KG-0@niG1@MoD=`514SG5@e=ejB$d?|UhdjTOY@d`l2ee{cQuLEs%0hv%6K>dGB! z(r%YCQ*~WT`@Oxpk=xU2?-cc2D@k0J3rVpf(noiS`&C<+c?I8*fBIBzv}Z)A$$V+H=0Ux6+5Of#mSS#$2bfYT zo~<_aRi^>8w+ag&QN*|2{3B7jBj!1NJy9lb-(SSY+y}|rCqGYxAQ%l5n&@whUfziq zFn(HWBq>R{!x(sGj_Qo?n=MiYpE;cla{z@Gu<%)a6QUuPcV?;|8t<^vS89FZ%~IIE z#=dKMt4rgPRLAXOEiLiM^rD;_?=8j;fF-7nOU&z`?{_S%ABe^73F3s|B+k&;R-;XH zX9?1Xa${b!Gd6NU3l^|UN(Ge{ttk>#=w0|WH3V(f& znv5bfb_=h$K_pE_v|z)jIo_ECxHnw{cgF!AsVDCFZeNhW8GkrnY{P@P>gKk;%o=ig z0IDtyR$B`4aG6+FzjFQ^wPh}s;U9tyCJj=xFm%CXy!8HVa|MiOSj*Dn-#((JL&dxoY&3Vdd>`OMCGQd= zZH~;3M4J$GuEYy{Ig?bD7KneO)4u;C`2x!DwRcZT<$3KHNBt_dLlSj271AAT9xn|9 z@b5=XqwP^zDG(L$R4oUd+YErUMgkL~o2`8&=?!l*&mM0Qz z_Zi9C%y4vF%RHg}IpnKbBBSFSGj}eE5A8st1Y@=l;_lTi_a2GFp(1?*iK?T4$(v1M zCK~tq!N25sZhJxC`=+}k#ioMfkjj)7V`!d>kbYg=#ExfyU7PI?%^~(#fYi)fg~)?& z!YTb?^55&r5%)qYq{2XX#l1B(KLjF)=<)66XxPoJl0Pm4`%tcv~UkswAt!QbM6cUw?OR3!}@$%ZBCNTZdb3ez_~ zu{1N|X^nSEpdC5xZc%?_xI}Y<8>L(?MBQV^kFw;aHEW&X$j<}=#&@gj12rNg%E?}j5%TL$$^e7Mp= zLwsjSa}185vcpSNyxzuEXPBy}yntN`QngP#%WR3P8eJ95Ys+iQJ6X?oJ}hawN^l?0-QxACo&9j;61l4o6^eB%9&UB>WoLNs|LMan zqLqrfM3LqWRs~BIT0f)#tXNYV4+&C?&ka z-w~t}Nv092%1UFN7-@pz4~bn7HTaH?+-c{Icb@`o8o9s%n;?vcDq06feVjxOI3>YCB0EPDBuedUhCdn zK;?W>k&LPvU0ij%!~FfsdiT|$&k3pzXI$9kWbRW~VQSc)FVu3quT1UsSA|BNzO_%$ zGm9X+As$Nt_-j zsUP+eylNKHHhZ6iOzP(|NT?rM#>o_O zT5rDCOFt+pPc1EhEr)GhgID)G&ew`)B-1XEVqH@O$`D+yJL)9f?H%u{v!}S6sHuaJ zL72%57U!w2NcxF~?EAd87mmHMI(CHw;8c}H6DD|Z7`QwKR$D@KDFudvT}&>0oXPsq zc#cJ0dg_r&e)peG2_cswm*ey{R-%NwC zkScK6v*>=$IP(ZkhW3S;7!gog=z)!W*|+xA3mu~5{Bi|XkBVcp#T{kL9Z z)DJ^}Ipy`p%wmY%t`=I=EqC zH}YbdsV*#F{N0W~Kc3H>*uHooGX;7ZvrjLQu~wWFwv4>3tBNzeegAIk2}7UF_TM`> z(qu0P5==kzeZEYyj9t$Cd5X=JRn;NLw&>~MLd=JG6ppbK$k_p|0TUleJ$Z3Oh0fP} zB&uWP1>SUaDEq|#^F%3YRL!7-MVumrvU-WBpO!O#zqV8R7PgFoEM<8;9(W z&q;y$wk%p+jhmVVwG%_^V^Mf%HS zn}#IBOpI7ybza^#s&6yNQyE?hM_qo&DTH5&z0Yv5-!J?sxLq_jS(`Uq_D)WD62GLF zG-Ci;#*LDgoo>uKnOz!jysJk;C|J`cMD3g8P&0iRE+toGtHfP&XWfV0o{3RmAN(p)}i9zw6$mZecPlgvpa+GN=T6AfCS31T` zPaM@#K4}d_hFi4@ORKVjpZ<|*Q|+!QDW>B(wwT z(e73av%ab+EgH}R5I~q7S3^!VOw`*4faHS{r!|%vb&ESGb!j2^l1#~i@yVZOlWZjmJF;L@?Gff)Y-%5itaEu#?AYL0;u>Y%*xpRa zYC8N!ebu+%<4aVO{uf4WMk>skNI7ur2y(2Q{ZYkHiZFf-)lm#l4^^>-!A;F7-|HVV z%KHUj1De9Tuf!>46f_&;9f?5_NBe?H9}5+)r@D6+yb+b&c>ZIz+6u~e#rgUH_(~#k zM>zN>Fb6(o2%|7C(a>Gy_yshLh`!38m_dP8z$tFLzV!miWCug0&~_g+eq0{{yE+N* z`YfC*X92c0zx4~x?VV58=9MEHGk&GNX`ow3WK>#4K(?1|(M_UKT=Y1+_qh-fVu zCFivt*=EyRVhk0PM<2NeB%nQH2YlCJIlk)dk$r40>>UCFA<=;EJ&AE8B_3zf`m=&x z=nlzTtdXb?1_*ft0b~ZGSx**dDB!QV$Y@N|BCfY;D^U0!Rh+N>*pjuRPRn=)r_sDs zrke!IwVvs@uLcRR$v@+4CqeIq`9x`lq;GJqa;;X?Jv_b8oYxqFtO2#QKRj<%pn{Ip z#5qh>fUtiY+1wF^1UL@6)HRve*%?cp6=+sVUwaMitaK8z9&=jr14JE+cuz)Z_{%-V zdyBKx!Twgl+Bm0(;K+)~RR8gNJKf3~!&d!|etqm!>u>|s58FaH zO(1sDvHZeT8VBpf9nA&QuPa$4bbpUFJ3GC8{&HU;tpUCy3=GvxV&z5sm2 zy&&b~88lD+5~_P8b@$P`_qT~mE3&Q=A z0lKQ@Vl=T&#{++Rt3qARddtn$7}OxHNKJ+~x=Yg4Z7mvncFnlK==8bdONSVkhlJPZ z3YZ`}2Dq=VjZC=(tegQ?szZPbC;X0&TI;Nh3Maufp5hxE_gwX8&}0X?LI5x>Yv zGi?V3flphSupU^li`x9NBsq1=-=Ztga0B4-Yh9}XLM5)pv5f9>vTiQm;zn_X zIIpG??^8e}fx9*F`5J6^zB5-J(57>T8eaa#xo}HMDmf_`qI-w*6Hl|zih*(`tjE26 zZ3zGPU=`BUu|jA4a;|t0MK5p>PxImVZHHN$kQeA9AaXcln%h?VLJ9qky}px!*tbtB zcSu|&os@Nl4%KcoxQz1pSGWU{LZpg3l)G|S4E5WU`Y+|+X`8UQ=PNd5r{+>Dp?6|L z{idk!^iHVrvL}hx$#VY|{buG+Wb>-(Psk}w>4NA>jEfp`tvHR$RVZC5oy03C1o_MN zsYt2!nHUvwvl9xlGj^&e>i$bbl;1wD z?md?5Y!&bqor0dXCBMv*a3nY9k^J-Q!>`~Fdo4~eFw&d{xoD*41<-B(ZhG)MsVCDwG=aTjinb{@!(DN1|?_(lGM9U_wKEZbQQJbUvo6!Cm_R&vc3hx zdeZ#lwR1+H<~oU8)gFDVA@zky%qxo>ha6}3OUT<|VU|Cz`h8%U+-FmW9v&G$A||L2 zv)(OsBj*FaZ3AV$IXrp~(Oy8h?j^o=rE(Ig^VY@MtbKUd*cB2updL=e{`TSu(7G&` z)vK{$iZoRuYYnGOr~R~IamB*pDLMGt<71;^*l@X!RI#MzoHV5%MQLxC<$LzfWCN zAh3##oh1H-gp%sSPPp_FzaX}Gal`qRqh0mh`C@29;&p6ep_G*NPi6KM`qNryCe1PIJ8siIN1WZ(7qVa)RVtmC% z)Ch?tN+afMKm;5@rvorJk zcXnoOc4q51HBQnQH_jn!cAg&XI1?PlX>Kl^k8qq0;zkha`kY$Fxt#=KNJAE9CMdpW zqr4#g8`nTw191(+H4xW8Tmyru2I^3=J1G3emPxkPXA=3{vvuvse_WWSshqaqls^-m zgB7q8&Vk*aYRe?sn$n53dGH#%3y%^vxv{pL*-h0Z4bmb_(k6{FL7HWIz(V*HT#IcS z-wE{)+0x1U!RUPt3gB97%p}@oHxF4|6S*+Yw=_tLtxZ~`S=z6J?O^AfU>7qOX`JNBbV&8+bO0%@fhQitKIJ^O^ zpgIa__qD_y07t@DFlBJ)8SP_#^j{6jpaXt{U%=dx!qu=4u7^21lWEYHPPY5U3TcoQ zX_7W+lvZi>TapNk_X>k-KO%MC9iZp>1E`N34gHKd9tK&){jq2~7OsJ>!G0FzxQFw6G zm&Vb(2#-T|rM|n3>uAsG_hnbvUKFf3#ay@u4uTzia~NY%XgCHfx4^To4BDU@)HlV? z@EN=g^ymETa1sQK{kRwyE4Ax8?wT&GvaG@ASO}{&a17&^v`y z!oPdiSiia^oov(Z)QhG2&|FgE{M9_4hJROGbnj>#$~ZF$-G^|zPj*QApltKe?;u;uKHJ~-V!=VLkg7Kgct)l7u39f@%VG8e3f$N-B zAu3a4%ZGf)r+jPAYCSLt73m_J3}p>}6Tx0j(wg4vvKhP!DzgiWANiE;Ppvp}P2W@m z-VbYn+NXFF?6ngef5CfY6ZwKnWvNV4z6s^~yMXw2i5mv}jC$6$46g?G|CPAu{W5qF zDobS=zb2ILX9D827g*NtGe5w;>frjanY{f)hrBP_2ehBt1?`~ypvg_Ot4x1V+43P@Ve8>qd)9NX_jWdLo`Zfy zoeam9)@Dpym{4m@+LNxXBPjPKA7{3a&H+~xQvr>C_A;7=JrfK~$M2pCh>|xLz>W6SCs4qC|#V`)# z)0C|?$o>jzh<|-cpf

K7osU{Xp5PG4-K+L2G=)c3f&}H&M3wo7TlO_UJjQ-Oq&_ zjAc9=nNIYz{c3zxOiS5UfcE1}8#iI4@uy;$Q7>}u`j+OU0N<*Ezx$k{x_27+{s2Eg z`^=rhtIzCm!_UcJ?Db~Lh-=_))PT3{Q0{Mwdq;0>ZL%l3+;B&4!&xm#%HYAK|;b456Iv&&f$VQHf` z>$*K9w8T+paVwc7fLfMlhQ4)*zL_SG{~v4QR;IuX-(oRtYAhWOlh`NLoX0k$RUYMi z2Y!bqpdN}wz8q`-%>&Le@q|jFw92ErW-hma-le?S z-@OZt2EEUm4wLsuEMkt4zlyy29_3S50JAcQHTtgTC{P~%-mvCTzrjXOc|{}N`Cz`W zSj7CrXfa7lcsU0J(0uSX6G`54t^7}+OLM0n(|g4waOQ}bd3%!XLh?NX9|8G_|06Ie zD5F1)w5I~!et7lA{G^;uf7aqT`KE&2qx9|~O;s6t!gb`+zVLJyT2T)l*8l(j From a87268d575ec98d6986d6bc80bc8c41cf27e11c0 Mon Sep 17 00:00:00 2001 From: HsiangNianian Date: Thu, 22 Jan 2026 11:02:15 +0800 Subject: [PATCH 13/18] fix: update navigation title from 'React Router' to 'DropOut' --- packages/docs/app/lib/layout.shared.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docs/app/lib/layout.shared.tsx b/packages/docs/app/lib/layout.shared.tsx index af2b6f0..6c7a35d 100644 --- a/packages/docs/app/lib/layout.shared.tsx +++ b/packages/docs/app/lib/layout.shared.tsx @@ -3,7 +3,7 @@ import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared'; export function baseOptions(): BaseLayoutProps { return { nav: { - title: 'React Router', + title: 'DropOut', }, }; } From c309904c5ab5394938e92bb139fc0c40d87de055 Mon Sep 17 00:00:00 2001 From: NtskwK Date: Thu, 29 Jan 2026 10:15:55 +0800 Subject: [PATCH 14/18] feat(docs): enhance error boundary UI and add 404 page --- packages/docs/app/root.tsx | 27 ++++++++++++++++++++------ packages/docs/app/routes.ts | 1 + packages/docs/app/routes/not-found.tsx | 7 +++++++ 3 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 packages/docs/app/routes/not-found.tsx diff --git a/packages/docs/app/root.tsx b/packages/docs/app/root.tsx index 08b8aa8..a6c807e 100644 --- a/packages/docs/app/root.tsx +++ b/packages/docs/app/root.tsx @@ -1,5 +1,6 @@ import { isRouteErrorResponse, + Link, Links, Meta, Outlet, @@ -60,13 +61,27 @@ export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) { } return ( -

-

{message}

-

{details}

+
+

+ {message} +

+

{details}

+

+ Sorry, we couldn't find the page you're looking for. It might have been moved or deleted. +

+ + Return Home / 返回首页 + {stack && ( -
-          {stack}
-        
+
+

Error Stack

+
+            {stack}
+          
+
)}
); diff --git a/packages/docs/app/routes.ts b/packages/docs/app/routes.ts index 677030a..9acc429 100644 --- a/packages/docs/app/routes.ts +++ b/packages/docs/app/routes.ts @@ -5,4 +5,5 @@ export default [ route('docs', 'routes/docs.tsx'), route('docs/*', 'docs/page.tsx'), route('api/search', 'docs/search.ts'), + route('*', 'routes/not-found.tsx'), ] satisfies RouteConfig; diff --git a/packages/docs/app/routes/not-found.tsx b/packages/docs/app/routes/not-found.tsx new file mode 100644 index 0000000..1d9e041 --- /dev/null +++ b/packages/docs/app/routes/not-found.tsx @@ -0,0 +1,7 @@ +export function loader() { + throw new Response('Not Found', { status: 404 }); +} + +export default function NotFound() { + return null; +} From 2f4f8a39afeaea4a618317f7a34cb178164eea60 Mon Sep 17 00:00:00 2001 From: NtskwK Date: Thu, 29 Jan 2026 10:17:17 +0800 Subject: [PATCH 15/18] docs: fix relative links and image paths in documentation --- packages/docs/content/docs/en/features/index.mdx | 13 ++++++------- packages/docs/content/docs/en/index.mdx | 14 +++++++------- packages/docs/content/docs/zh/features/index.mdx | 14 ++++++-------- packages/docs/content/docs/zh/index.mdx | 14 +++++++------- 4 files changed, 26 insertions(+), 29 deletions(-) diff --git a/packages/docs/content/docs/en/features/index.mdx b/packages/docs/content/docs/en/features/index.mdx index 9b1d1af..19a6973 100644 --- a/packages/docs/content/docs/en/features/index.mdx +++ b/packages/docs/content/docs/en/features/index.mdx @@ -12,32 +12,32 @@ DropOut is packed with features designed for both casual players and power users @@ -174,4 +174,3 @@ Built-in JSON/TOML editor with: - One-click updates - Version history - Rollback support - diff --git a/packages/docs/content/docs/en/index.mdx b/packages/docs/content/docs/en/index.mdx index 97e6228..d9846ab 100644 --- a/packages/docs/content/docs/en/index.mdx +++ b/packages/docs/content/docs/en/index.mdx @@ -7,8 +7,8 @@ description: Modern, reproducible, and developer-grade Minecraft launcher DropOut is a modern Minecraft launcher built with Tauri v2 and Rust, designed for players who value control, transparency, and long-term stability. -
- DropOut Launcher +
+ DropOut Launcher
## Why DropOut? @@ -26,22 +26,22 @@ This launcher is built for players who value control, transparency, and long-ter @@ -92,4 +92,4 @@ DropOut is open source software licensed under the MIT License. --- -Ready to get started? Check out the [Getting Started Guide](/docs/getting-started)! +Ready to get started? Check out the [Getting Started Guide](getting-started)! diff --git a/packages/docs/content/docs/zh/features/index.mdx b/packages/docs/content/docs/zh/features/index.mdx index 0429234..3e03e83 100644 --- a/packages/docs/content/docs/zh/features/index.mdx +++ b/packages/docs/content/docs/zh/features/index.mdx @@ -12,32 +12,32 @@ DropOut 功能丰富,既适合休闲玩家也适合高级用户。本指南涵 @@ -174,5 +174,3 @@ DropOut 功能丰富,既适合休闲玩家也适合高级用户。本指南涵 - 一键更新 - 版本历史 - 回滚支持 - - diff --git a/packages/docs/content/docs/zh/index.mdx b/packages/docs/content/docs/zh/index.mdx index 1c18be2..27487cb 100644 --- a/packages/docs/content/docs/zh/index.mdx +++ b/packages/docs/content/docs/zh/index.mdx @@ -7,8 +7,8 @@ description: 现代化、可复现、开发者级别的 Minecraft 启动器 DropOut 是一个使用 Tauri v2 和 Rust 构建的现代 Minecraft 启动器,专为重视控制、透明度和长期稳定性的玩家设计。 -
- DropOut 启动器 +
+ DropOut 启动器
## 为什么选择 DropOut? @@ -26,22 +26,22 @@ DropOut 是一个使用 Tauri v2 和 Rust 构建的现代 Minecraft 启动器, @@ -92,4 +92,4 @@ DropOut 是在 MIT 许可证下的开源软件。 --- -准备好开始了吗?查看[快速开始指南](/docs/getting-started)! \ No newline at end of file +准备好开始了吗?查看[快速开始指南](getting-started)! From 9627912c1f7910f786c555a3a9485f0a8c4211bf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 30 Jan 2026 15:07:12 +0000 Subject: [PATCH 16/18] docs: remove emojis from documentation and home page Co-authored-by: HsiangNianian <44714368+HsiangNianian@users.noreply.github.com> --- packages/docs/app/routes/home.tsx | 6 --- .../docs/content/docs/en/features/index.mdx | 40 +++++++++---------- packages/docs/content/docs/en/index.mdx | 16 ++++---- .../docs/content/docs/zh/features/index.mdx | 40 +++++++++---------- packages/docs/content/docs/zh/index.mdx | 16 ++++---- 5 files changed, 56 insertions(+), 62 deletions(-) diff --git a/packages/docs/app/routes/home.tsx b/packages/docs/app/routes/home.tsx index b1f8516..1bd2235 100644 --- a/packages/docs/app/routes/home.tsx +++ b/packages/docs/app/routes/home.tsx @@ -55,42 +55,36 @@ export default function Home() { {/* Features Grid */}
-
🚀

High Performance

Built with Rust and Tauri for minimal resource usage and fast startup times

-
🎨

Modern UI

Clean, distraction-free interface with Svelte 5 and Tailwind CSS 4

-
🔐

Secure Auth

Microsoft OAuth 2.0 with device code flow and offline mode support

-
🔧

Mod Loaders

Built-in support for Fabric and Forge with automatic version management

-

Java Management

Auto-detection and integrated downloader for Adoptium JDK/JRE

-
📦

Instance System

Isolated game environments with independent configs and mods diff --git a/packages/docs/content/docs/en/features/index.mdx b/packages/docs/content/docs/en/features/index.mdx index 19a6973..3a463d0 100644 --- a/packages/docs/content/docs/en/features/index.mdx +++ b/packages/docs/content/docs/en/features/index.mdx @@ -46,26 +46,26 @@ DropOut is packed with features designed for both casual players and power users | Feature | Status | Description | |---------|--------|-------------| -| Microsoft Authentication | ✅ Complete | OAuth 2.0 with device code flow | -| Offline Authentication | ✅ Complete | Local accounts for offline play | -| Token Auto-refresh | ✅ Complete | Automatic refresh of expired tokens | -| Java Auto-detection | ✅ Complete | Scans system for Java installations | -| Java Download | ✅ Complete | Download Adoptium JDK/JRE versions | -| Fabric Support | ✅ Complete | Install and launch Fabric loader | -| Forge Support | ✅ Complete | Install and launch Forge loader | -| Instance System | ✅ Complete | Isolated game environments | -| GitHub Integration | ✅ Complete | View releases and changelogs | -| Concurrent Downloads | ✅ Complete | Multi-threaded asset downloads | -| Resume Downloads | ✅ Complete | Resume interrupted downloads | -| AI Assistant | ✅ Complete | Built-in troubleshooting helper | -| Config Editor | ✅ Complete | JSON/TOML configuration editor | -| Custom Resolution | ✅ Complete | Set game window dimensions | -| Memory Allocation | ✅ Complete | Customize JVM memory settings | -| Multi-account | 🚧 In Progress | Switch between multiple accounts | -| Mods Manager | 🚧 Planned | Enable/disable mods in launcher | -| Launcher Auto-update | 🚧 Planned | Self-updating mechanism | -| Custom Game Directory | 🚧 Planned | Choose game files location | -| Import Profiles | 🚧 Planned | Import from MultiMC/Prism | +| Microsoft Authentication | Complete | OAuth 2.0 with device code flow | +| Offline Authentication | Complete | Local accounts for offline play | +| Token Auto-refresh | Complete | Automatic refresh of expired tokens | +| Java Auto-detection | Complete | Scans system for Java installations | +| Java Download | Complete | Download Adoptium JDK/JRE versions | +| Fabric Support | Complete | Install and launch Fabric loader | +| Forge Support | Complete | Install and launch Forge loader | +| Instance System | Complete | Isolated game environments | +| GitHub Integration | Complete | View releases and changelogs | +| Concurrent Downloads | Complete | Multi-threaded asset downloads | +| Resume Downloads | Complete | Resume interrupted downloads | +| AI Assistant | Complete | Built-in troubleshooting helper | +| Config Editor | Complete | JSON/TOML configuration editor | +| Custom Resolution | Complete | Set game window dimensions | +| Memory Allocation | Complete | Customize JVM memory settings | +| Multi-account | In Progress | Switch between multiple accounts | +| Mods Manager | Planned | Enable/disable mods in launcher | +| Launcher Auto-update | Planned | Self-updating mechanism | +| Custom Game Directory | Planned | Choose game files location | +| Import Profiles | Planned | Import from MultiMC/Prism | ## Performance Features diff --git a/packages/docs/content/docs/en/index.mdx b/packages/docs/content/docs/en/index.mdx index d9846ab..9dee19f 100644 --- a/packages/docs/content/docs/en/index.mdx +++ b/packages/docs/content/docs/en/index.mdx @@ -48,28 +48,28 @@ This launcher is built for players who value control, transparency, and long-ter ## Key Features -### 🚀 High Performance +### High Performance Built with Rust and Tauri for minimal resource usage and fast startup times. -### 🎨 Modern UI +### Modern UI Clean, distraction-free interface with Svelte 5, Tailwind CSS 4, and particle effects. -### 🔐 Secure Authentication +### Secure Authentication Microsoft OAuth 2.0 with device code flow and offline authentication support. -### 🔧 Mod Loader Support +### Mod Loader Support Built-in installation for Fabric and Forge with automatic version management. -### ☕ Java Management +### Java Management Automatic detection of installed Java versions and integrated downloader for Adoptium JDK/JRE. -### 📦 Instance System +### Instance System Isolated game environments with independent configurations, mods, and saves. -### 🤖 AI Assistant +### AI Assistant Built-in AI helper for troubleshooting, configuration, and guidance. -### ⚡ Fast Downloads +### Fast Downloads Concurrent asset and library downloads with resume support and progress tracking. ## Technology Stack diff --git a/packages/docs/content/docs/zh/features/index.mdx b/packages/docs/content/docs/zh/features/index.mdx index 3e03e83..bb53ce2 100644 --- a/packages/docs/content/docs/zh/features/index.mdx +++ b/packages/docs/content/docs/zh/features/index.mdx @@ -46,26 +46,26 @@ DropOut 功能丰富,既适合休闲玩家也适合高级用户。本指南涵 | 功能 | 状态 | 描述 | |---------|--------|-------------| -| Microsoft 身份验证 | ✅ 完成 | 使用设备代码流的 OAuth 2.0 | -| 离线身份验证 | ✅ 完成 | 用于离线游玩的本地账户 | -| 令牌自动刷新 | ✅ 完成 | 自动刷新过期的令牌 | -| Java 自动检测 | ✅ 完成 | 扫描系统中的 Java 安装 | -| Java 下载 | ✅ 完成 | 下载 Adoptium JDK/JRE 版本 | -| Fabric 支持 | ✅ 完成 | 安装和启动 Fabric 加载器 | -| Forge 支持 | ✅ 完成 | 安装和启动 Forge 加载器 | -| 实例系统 | ✅ 完成 | 隔离的游戏环境 | -| GitHub 集成 | ✅ 完成 | 查看发布和更新日志 | -| 并发下载 | ✅ 完成 | 多线程资源下载 | -| 断点续传 | ✅ 完成 | 恢复中断的下载 | -| AI 助手 | ✅ 完成 | 内置故障排除助手 | -| 配置编辑器 | ✅ 完成 | JSON/TOML 配置编辑器 | -| 自定义分辨率 | ✅ 完成 | 设置游戏窗口尺寸 | -| 内存分配 | ✅ 完成 | 自定义 JVM 内存设置 | -| 多账户 | 🚧 进行中 | 在多个账户之间切换 | -| 模组管理器 | 🚧 计划中 | 在启动器中启用/禁用模组 | -| 启动器自动更新 | 🚧 计划中 | 自我更新机制 | -| 自定义游戏目录 | 🚧 计划中 | 选择游戏文件位置 | -| 导入配置文件 | 🚧 计划中 | 从 MultiMC/Prism 导入 | +| Microsoft 身份验证 | 完成 | 使用设备代码流的 OAuth 2.0 | +| 离线身份验证 | 完成 | 用于离线游玩的本地账户 | +| 令牌自动刷新 | 完成 | 自动刷新过期的令牌 | +| Java 自动检测 | 完成 | 扫描系统中的 Java 安装 | +| Java 下载 | 完成 | 下载 Adoptium JDK/JRE 版本 | +| Fabric 支持 | 完成 | 安装和启动 Fabric 加载器 | +| Forge 支持 | 完成 | 安装和启动 Forge 加载器 | +| 实例系统 | 完成 | 隔离的游戏环境 | +| GitHub 集成 | 完成 | 查看发布和更新日志 | +| 并发下载 | 完成 | 多线程资源下载 | +| 断点续传 | 完成 | 恢复中断的下载 | +| AI 助手 | 完成 | 内置故障排除助手 | +| 配置编辑器 | 完成 | JSON/TOML 配置编辑器 | +| 自定义分辨率 | 完成 | 设置游戏窗口尺寸 | +| 内存分配 | 完成 | 自定义 JVM 内存设置 | +| 多账户 | 进行中 | 在多个账户之间切换 | +| 模组管理器 | 计划中 | 在启动器中启用/禁用模组 | +| 启动器自动更新 | 计划中 | 自我更新机制 | +| 自定义游戏目录 | 计划中 | 选择游戏文件位置 | +| 导入配置文件 | 计划中 | 从 MultiMC/Prism 导入 | ## 性能功能 diff --git a/packages/docs/content/docs/zh/index.mdx b/packages/docs/content/docs/zh/index.mdx index 27487cb..b554cca 100644 --- a/packages/docs/content/docs/zh/index.mdx +++ b/packages/docs/content/docs/zh/index.mdx @@ -48,28 +48,28 @@ DropOut 是一个使用 Tauri v2 和 Rust 构建的现代 Minecraft 启动器, ## 核心特性 -### 🚀 高性能 +### 高性能 使用 Rust 和 Tauri 构建,资源占用最小,启动速度极快。 -### 🎨 现代化界面 +### 现代化界面 简洁、无干扰的界面,使用 Svelte 5、Tailwind CSS 4 和粒子效果。 -### 🔐 安全认证 +### 安全认证 微软 OAuth 2.0 设备代码流和离线认证支持。 -### 🔧 模组加载器支持 +### 模组加载器支持 内置 Fabric 和 Forge 安装,自动版本管理。 -### ☕ Java 管理 +### Java 管理 自动检测已安装的 Java 版本,集成 Adoptium JDK/JRE 下载器。 -### 📦 实例系统 +### 实例系统 独立的游戏环境,具有独立的配置、模组和存档。 -### 🤖 AI 助手 +### AI 助手 内置 AI 帮助,用于故障排除、配置和指导。 -### ⚡ 快速下载 +### 快速下载 并发资源和库下载,支持断点续传和进度跟踪。 ## 技术栈 From b27777b625fb348f35e435276842668e16456967 Mon Sep 17 00:00:00 2001 From: NtskwK Date: Tue, 3 Feb 2026 11:19:09 +0800 Subject: [PATCH 17/18] feat(i18n): add multi-language support for docs --- packages/docs/app/docs/page.tsx | 51 +++--- packages/docs/app/docs/search.ts | 7 +- packages/docs/app/lib/i18n.ts | 8 + packages/docs/app/lib/layout.shared.tsx | 17 +- packages/docs/app/lib/source.ts | 5 + packages/docs/app/root.tsx | 20 ++- packages/docs/app/routes.ts | 19 ++- packages/docs/app/routes/docs.tsx | 14 +- packages/docs/app/routes/home.tsx | 196 ++++++++++++++---------- packages/docs/source.config.ts | 3 +- 10 files changed, 222 insertions(+), 118 deletions(-) create mode 100644 packages/docs/app/lib/i18n.ts diff --git a/packages/docs/app/docs/page.tsx b/packages/docs/app/docs/page.tsx index 2618989..a9e3433 100644 --- a/packages/docs/app/docs/page.tsx +++ b/packages/docs/app/docs/page.tsx @@ -1,51 +1,58 @@ import type { Route } from './+types/page'; +import defaultMdxComponents from 'fumadocs-ui/mdx'; import { DocsLayout } from 'fumadocs-ui/layouts/docs'; -import { DocsBody, DocsDescription, DocsPage, DocsTitle } from 'fumadocs-ui/layouts/docs/page'; +import { DocsPage, DocsBody, DocsDescription, DocsTitle } from 'fumadocs-ui/page'; +import { Card, Cards } from 'fumadocs-ui/components/card'; import { source } from '@/lib/source'; -import defaultMdxComponents from 'fumadocs-ui/mdx'; -import browserCollections from 'fumadocs-mdx:collections/browser'; +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'; export async function loader({ params }: Route.LoaderArgs) { - const slugs = params['*'].split('/').filter((v) => v.length > 0); - const page = source.getPage(slugs); - if (!page) throw new Response('Not found', { status: 404 }); + // 从路由参数获取语言,如果没有则使用默认语言 + // URL 格式: /docs/getting-started (默认语言 zh) + // URL 格式: /en/docs/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 }); + } return { path: page.path, - pageTree: await source.serializePageTree(source.getPageTree()), + pageTree: await source.serializePageTree(source.getPageTree(lang)), + lang, }; } const clientLoader = browserCollections.docs.createClientLoader({ - component( - { toc, frontmatter, default: Mdx }, - // you can define props for the `` component - props?: { - className?: string; - }, - ) { + component({ toc, frontmatter, default: Mdx }) { return ( - - {frontmatter.title} - + {frontmatter.title} {frontmatter.description} - + ); }, }); -export default function Page({ loaderData }: Route.ComponentProps) { - const { path, pageTree } = useFumadocsLoader(loaderData); +export default function Page({ loaderData, params }: Route.ComponentProps) { + const { pageTree, lang } = useFumadocsLoader(loaderData); return ( - - {clientLoader.useContent(path)} + + {clientLoader.useContent(loaderData.path)} ); } diff --git a/packages/docs/app/docs/search.ts b/packages/docs/app/docs/search.ts index 9603c72..a98edd5 100644 --- a/packages/docs/app/docs/search.ts +++ b/packages/docs/app/docs/search.ts @@ -3,8 +3,11 @@ import { createFromSource } from 'fumadocs-core/search/server'; import { source } from '@/lib/source'; const server = createFromSource(source, { - // https://docs.orama.com/docs/orama-js/supported-languages - language: 'english', + localeMap: { + zh: { + language: 'english', + }, + }, }); export async function loader({ request }: Route.LoaderArgs) { diff --git a/packages/docs/app/lib/i18n.ts b/packages/docs/app/lib/i18n.ts new file mode 100644 index 0000000..a9f18b1 --- /dev/null +++ b/packages/docs/app/lib/i18n.ts @@ -0,0 +1,8 @@ +import { defineI18n } from 'fumadocs-core/i18n'; + +export const i18n = defineI18n({ + defaultLanguage: 'zh', + languages: ['zh', 'en'], + hideLocale: 'default-locale', + parser: 'dir', // 使用目录结构 (content/zh/*, content/en/*) +}); diff --git a/packages/docs/app/lib/layout.shared.tsx b/packages/docs/app/lib/layout.shared.tsx index 6c7a35d..6e90ba0 100644 --- a/packages/docs/app/lib/layout.shared.tsx +++ b/packages/docs/app/lib/layout.shared.tsx @@ -1,9 +1,24 @@ import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared'; +import { i18n } from './i18n'; -export function baseOptions(): BaseLayoutProps { +export function baseOptions(locale: string): BaseLayoutProps { + // 默认语言(zh)不显示前缀,其他语言显示前缀 + const isDefaultLocale = locale === i18n.defaultLanguage; + const localePrefix = isDefaultLocale ? '' : `/${locale}`; + return { + i18n, nav: { title: 'DropOut', + url: localePrefix || '/', }, + githubUrl: 'https://github.com/HydroRoll-Team/DropOut', + links: [ + { + type: 'main', + text: locale === 'zh' ? '文档' : 'Documentation', + url: `${localePrefix}/docs`, + }, + ], }; } diff --git a/packages/docs/app/lib/source.ts b/packages/docs/app/lib/source.ts index 97cf767..bce9bf9 100644 --- a/packages/docs/app/lib/source.ts +++ b/packages/docs/app/lib/source.ts @@ -1,7 +1,12 @@ import { loader } from 'fumadocs-core/source'; import { docs } from 'fumadocs-mdx:collections/server'; +import { i18n } from './i18n'; export const source = loader({ source: docs.toFumadocsSource(), baseUrl: '/docs', + i18n, + // hideLocale: 'default-locale' 会自动生成正确的 URL: + // - 默认语言 (zh): /docs/getting-started + // - 其他语言 (en): /en/docs/getting-started }); diff --git a/packages/docs/app/root.tsx b/packages/docs/app/root.tsx index a6c807e..9032c80 100644 --- a/packages/docs/app/root.tsx +++ b/packages/docs/app/root.tsx @@ -6,11 +6,25 @@ import { Outlet, Scripts, ScrollRestoration, + useParams, } from 'react-router'; import { RootProvider } from 'fumadocs-ui/provider/react-router'; import type { Route } from './+types/root'; import './app.css'; +import { defineI18nUI } from 'fumadocs-ui/i18n'; +import { i18n } from './lib/i18n'; +const { provider } = defineI18nUI(i18n, { + translations: { + en: { + displayName: 'English', + }, + zh: { + displayName: '中文', + search: '查找文档', + }, + }, +}); export const links: Route.LinksFunction = () => [ { rel: 'preconnect', href: 'https://fonts.googleapis.com' }, { @@ -25,8 +39,10 @@ export const links: Route.LinksFunction = () => [ ]; export function Layout({ children }: { children: React.ReactNode }) { + const { lang = i18n.defaultLanguage } = useParams(); + return ( - + @@ -34,7 +50,7 @@ export function Layout({ children }: { children: React.ReactNode }) { - {children} + {children} diff --git a/packages/docs/app/routes.ts b/packages/docs/app/routes.ts index 9acc429..2997ecf 100644 --- a/packages/docs/app/routes.ts +++ b/packages/docs/app/routes.ts @@ -1,9 +1,16 @@ -import { index, route, type RouteConfig } from '@react-router/dev/routes'; +import { route, type RouteConfig } from '@react-router/dev/routes'; export default [ - index('routes/home.tsx'), - route('docs', 'routes/docs.tsx'), - route('docs/*', 'docs/page.tsx'), - route('api/search', 'docs/search.ts'), - route('*', 'routes/not-found.tsx'), + // Home routes: / and /:lang + route(':lang?', 'routes/home.tsx', { id: 'home' }), + + // Docs routes: /docs/* and /:lang/docs/* + route(':lang?/docs', 'routes/docs.tsx', { id: 'docs' }), + route(':lang?/docs/*', 'docs/page.tsx', { id: 'docs-page' }), + + // API routes + route('api/search', 'docs/search.ts', { id: 'api-search' }), + + // Catch-all 404 + route('*', 'routes/not-found.tsx', { id: 'not-found' }), ] satisfies RouteConfig; diff --git a/packages/docs/app/routes/docs.tsx b/packages/docs/app/routes/docs.tsx index a1c1707..5154d27 100644 --- a/packages/docs/app/routes/docs.tsx +++ b/packages/docs/app/routes/docs.tsx @@ -1,6 +1,16 @@ import type { Route } from './+types/docs'; import { redirect } from 'react-router'; -export function loader({}: Route.LoaderArgs) { - return redirect('/docs/en'); +import { i18n } from '@/lib/i18n'; + +export function loader({ params }: Route.LoaderArgs) { + const lang = params.lang as string | undefined; + + // 如果没有语言参数或是默认语言,重定向到 /docs/getting-started + if (!lang || lang === i18n.defaultLanguage) { + return redirect('/docs/getting-started'); + } + + // 其他语言重定向到 /:lang/docs/getting-started + return redirect(`/${lang}/docs/getting-started`); } diff --git a/packages/docs/app/routes/home.tsx b/packages/docs/app/routes/home.tsx index 1bd2235..66b5333 100644 --- a/packages/docs/app/routes/home.tsx +++ b/packages/docs/app/routes/home.tsx @@ -1,43 +1,117 @@ import type { Route } from './+types/home'; import { HomeLayout } from 'fumadocs-ui/layouts/home'; -import { Link } from 'react-router'; import { baseOptions } from '@/lib/layout.shared'; +import { i18n } from '@/lib/i18n'; -export function meta({}: Route.MetaArgs) { +const texts = { + en: { + hero: { + title: 'DropOut Minecraft Launcher', + subtitle: 'Modern. Reproducible. Developer-Grade.', + description: 'Built with Tauri v2 and Rust for native performance and minimal resource usage', + start: 'Get Started', + features: 'Features', + }, + features: { + items: [ + { title: 'High Performance', desc: 'Built with Rust and Tauri for minimal resource usage and fast startup times' }, + { title: 'Modern UI', desc: 'Clean, distraction-free interface with Svelte 5 and Tailwind CSS 4' }, + { title: 'Secure Auth', desc: 'Microsoft OAuth 2.0 with device code flow and offline mode support' }, + { title: 'Mod Loaders', desc: 'Built-in support for Fabric and Forge with automatic version management' }, + { title: 'Java Management', desc: 'Auto-detection and integrated downloader for Adoptium JDK/JRE' }, + { title: 'Instance System', desc: 'Isolated game environments with independent configs and mods' }, + ] + }, + why: { + title: 'Why DropOut?', + items: [ + { q: 'Your instance worked yesterday but broke today?', a: '→ DropOut makes it traceable.' }, + { q: 'Sharing a modpack means zipping gigabytes?', a: '→ DropOut shares exact dependency manifests.' }, + { q: 'Java, loader, mods, configs drift out of sync?', a: '→ DropOut locks them together.' }, + ] + }, + cta: { + title: 'Ready to get started?', + desc: 'Check out the documentation to learn more about DropOut', + button: 'Read the Docs', + } + }, + zh: { + hero: { + title: 'DropOut Minecraft 启动器', + subtitle: '现代、可复现、开发者级', + description: '基于 Tauri v2 和 Rust 构建,拥有原生性能和极低的资源占用', + start: '开始使用', + features: '功能特性', + }, + features: { + items: [ + { title: '高性能', desc: '使用 Rust 和 Tauri 构建,资源占用最小,启动速度极快' }, + { title: '现代化界面', desc: '简洁、无干扰的界面,使用 Svelte 5 和 Tailwind CSS 4' }, + { title: '安全认证', desc: '支持微软 OAuth 2.0 设备代码流和离线模式' }, + { title: '模组支持', desc: '内置 Fabric 和 Forge 支持,自动管理版本' }, + { title: 'Java 管理', desc: '自动检测并集成 Adoptium JDK/JRE 下载器' }, + { title: '实例系统', desc: '独立的游戏环境,独立的配置和模组' }, + ] + }, + why: { + title: '为什么选择 DropOut?', + items: [ + { q: '你的实例昨天还能用,今天就坏了?', a: '→ DropOut 让它可追溯。' }, + { q: '分享模组包意味着打包数GB的文件?', a: '→ DropOut 分享精确的依赖清单。' }, + { q: 'Java、加载器、模组、配置不同步?', a: '→ DropOut 将它们锁定在一起。' }, + ] + }, + cta: { + title: '准备好开始了?', + desc: '查看文档以了解更多关于 DropOut 的信息', + button: '阅读文档', + } + } +}; + +export function meta({ params }: Route.MetaArgs) { return [ { title: 'DropOut - Modern Minecraft Launcher' }, { name: 'description', content: 'A modern, reproducible, and developer-grade Minecraft launcher built with Tauri v2 and Rust.' }, ]; } -export default function Home() { +export default function Home({ params }: Route.ComponentProps) { + const lang = (params.lang as 'en' | 'zh') || i18n.defaultLanguage; + const t = texts[lang]; + + // 默认语言(zh)不显示前缀,其他语言显示前缀 + const isDefaultLocale = lang === i18n.defaultLanguage; + const localePrefix = isDefaultLocale ? '' : `/${lang}`; + return ( - +

{/* Hero Section */} @@ -54,84 +128,44 @@ export default function Home() { {/* Features Grid */}
-
-

High Performance

-

- Built with Rust and Tauri for minimal resource usage and fast startup times -

-
-
-

Modern UI

-

- Clean, distraction-free interface with Svelte 5 and Tailwind CSS 4 -

-
-
-

Secure Auth

-

- Microsoft OAuth 2.0 with device code flow and offline mode support -

-
-
-

Mod Loaders

-

- Built-in support for Fabric and Forge with automatic version management -

-
-
-

Java Management

-

- Auto-detection and integrated downloader for Adoptium JDK/JRE -

-
-
-

Instance System

-

- Isolated game environments with independent configs and mods -

-
+ {t.features.items.map((item, i) => ( +
+

{item.title}

+

+ {item.desc} +

+
+ ))}
{/* Why DropOut Section */}
-

Why DropOut?

+

{t.why.title}

-
-

- Your instance worked yesterday but broke today? -
- → DropOut makes it traceable. -

-
-
-

- Sharing a modpack means zipping gigabytes? -
- → DropOut shares exact dependency manifests. -

-
-
-

- Java, loader, mods, configs drift out of sync? -
- → DropOut locks them together. -

-
+ {t.why.items.map((item, i) => ( +
+

+ {item.q} +
+ {item.a} +

+
+ ))}
{/* CTA Section */}
diff --git a/packages/docs/source.config.ts b/packages/docs/source.config.ts index 1e8ac56..d67a91b 100644 --- a/packages/docs/source.config.ts +++ b/packages/docs/source.config.ts @@ -1,8 +1,7 @@ import { defineConfig, defineDocs } from 'fumadocs-mdx/config'; export const docs = defineDocs({ - dir: 'content/docs', - i18n: true, + dir: 'content', }); export default defineConfig(); From ac7a7bceec82a02cf490bc928d989663fd8a3a30 Mon Sep 17 00:00:00 2001 From: NtskwK Date: Tue, 3 Feb 2026 11:23:08 +0800 Subject: [PATCH 18/18] docs: restructure documentation files --- packages/docs/content/{docs => }/en/architecture.mdx | 1 - packages/docs/content/{docs => }/en/development.mdx | 1 - packages/docs/content/{docs => }/en/features/authentication.mdx | 1 - packages/docs/content/{docs => }/en/features/index.mdx | 0 packages/docs/content/{docs => }/en/features/java.mdx | 1 - packages/docs/content/{docs => }/en/features/meta.json | 0 packages/docs/content/{docs => }/en/features/mod-loaders.mdx | 1 - packages/docs/content/{docs => }/en/getting-started.mdx | 1 - packages/docs/content/{docs => }/en/index.mdx | 0 packages/docs/content/{docs => }/en/meta.json | 0 packages/docs/content/{docs => }/en/troubleshooting.mdx | 1 - packages/docs/content/{docs => }/zh/architecture.mdx | 1 - packages/docs/content/{docs => }/zh/development.mdx | 0 packages/docs/content/{docs => }/zh/features/authentication.mdx | 1 - packages/docs/content/{docs => }/zh/features/index.mdx | 0 packages/docs/content/{docs => }/zh/features/java.mdx | 0 packages/docs/content/{docs => }/zh/features/meta.json | 0 packages/docs/content/{docs => }/zh/features/mod-loaders.mdx | 1 - packages/docs/content/{docs => }/zh/getting-started.mdx | 1 - packages/docs/content/{docs => }/zh/index.mdx | 0 packages/docs/content/{docs => }/zh/meta.json | 0 packages/docs/content/{docs => }/zh/troubleshooting.mdx | 0 22 files changed, 11 deletions(-) rename packages/docs/content/{docs => }/en/architecture.mdx (99%) rename packages/docs/content/{docs => }/en/development.mdx (99%) rename packages/docs/content/{docs => }/en/features/authentication.mdx (99%) rename packages/docs/content/{docs => }/en/features/index.mdx (100%) rename packages/docs/content/{docs => }/en/features/java.mdx (99%) rename packages/docs/content/{docs => }/en/features/meta.json (100%) rename packages/docs/content/{docs => }/en/features/mod-loaders.mdx (99%) rename packages/docs/content/{docs => }/en/getting-started.mdx (99%) rename packages/docs/content/{docs => }/en/index.mdx (100%) rename packages/docs/content/{docs => }/en/meta.json (100%) rename packages/docs/content/{docs => }/en/troubleshooting.mdx (99%) rename packages/docs/content/{docs => }/zh/architecture.mdx (99%) rename packages/docs/content/{docs => }/zh/development.mdx (100%) rename packages/docs/content/{docs => }/zh/features/authentication.mdx (99%) rename packages/docs/content/{docs => }/zh/features/index.mdx (100%) rename packages/docs/content/{docs => }/zh/features/java.mdx (100%) rename packages/docs/content/{docs => }/zh/features/meta.json (100%) rename packages/docs/content/{docs => }/zh/features/mod-loaders.mdx (99%) rename packages/docs/content/{docs => }/zh/getting-started.mdx (99%) rename packages/docs/content/{docs => }/zh/index.mdx (100%) rename packages/docs/content/{docs => }/zh/meta.json (100%) rename packages/docs/content/{docs => }/zh/troubleshooting.mdx (100%) diff --git a/packages/docs/content/docs/en/architecture.mdx b/packages/docs/content/en/architecture.mdx similarity index 99% rename from packages/docs/content/docs/en/architecture.mdx rename to packages/docs/content/en/architecture.mdx index f8cc8f4..5f55c5e 100644 --- a/packages/docs/content/docs/en/architecture.mdx +++ b/packages/docs/content/en/architecture.mdx @@ -279,4 +279,3 @@ const result = await invoke("start_game", { versionId: "1.20.4" }); - **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/docs/en/development.mdx b/packages/docs/content/en/development.mdx similarity index 99% rename from packages/docs/content/docs/en/development.mdx rename to packages/docs/content/en/development.mdx index f7beabb..8ff2906 100644 --- a/packages/docs/content/docs/en/development.mdx +++ b/packages/docs/content/en/development.mdx @@ -544,4 +544,3 @@ rustup update - **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/docs/en/features/authentication.mdx b/packages/docs/content/en/features/authentication.mdx similarity index 99% rename from packages/docs/content/docs/en/features/authentication.mdx rename to packages/docs/content/en/features/authentication.mdx index 67e3c19..b6fc4ba 100644 --- a/packages/docs/content/docs/en/features/authentication.mdx +++ b/packages/docs/content/en/features/authentication.mdx @@ -264,4 +264,3 @@ listen('auth-status', (event) => { - **Account profiles**: Save per-account settings - **Auto-login**: Remember last account - **Token encryption**: Enhanced security for stored tokens - diff --git a/packages/docs/content/docs/en/features/index.mdx b/packages/docs/content/en/features/index.mdx similarity index 100% rename from packages/docs/content/docs/en/features/index.mdx rename to packages/docs/content/en/features/index.mdx diff --git a/packages/docs/content/docs/en/features/java.mdx b/packages/docs/content/en/features/java.mdx similarity index 99% rename from packages/docs/content/docs/en/features/java.mdx rename to packages/docs/content/en/features/java.mdx index 1afdab7..21b95a9 100644 --- a/packages/docs/content/docs/en/features/java.mdx +++ b/packages/docs/content/en/features/java.mdx @@ -392,4 +392,3 @@ GraalVM is supported for advanced users: 3. Add to DropOut as custom Java 4. May improve performance 5. Test thoroughly before use - diff --git a/packages/docs/content/docs/en/features/meta.json b/packages/docs/content/en/features/meta.json similarity index 100% rename from packages/docs/content/docs/en/features/meta.json rename to packages/docs/content/en/features/meta.json diff --git a/packages/docs/content/docs/en/features/mod-loaders.mdx b/packages/docs/content/en/features/mod-loaders.mdx similarity index 99% rename from packages/docs/content/docs/en/features/mod-loaders.mdx rename to packages/docs/content/en/features/mod-loaders.mdx index a9616d6..d6fdf4f 100644 --- a/packages/docs/content/docs/en/features/mod-loaders.mdx +++ b/packages/docs/content/en/features/mod-loaders.mdx @@ -407,4 +407,3 @@ listen('mod-loader-progress', (event) => { - **Profile export** - Share modpack configurations - **CurseForge integration** - Direct modpack import - **Modrinth integration** - Mod search and install - diff --git a/packages/docs/content/docs/en/getting-started.mdx b/packages/docs/content/en/getting-started.mdx similarity index 99% rename from packages/docs/content/docs/en/getting-started.mdx rename to packages/docs/content/en/getting-started.mdx index ac0fc1c..5219f40 100644 --- a/packages/docs/content/docs/en/getting-started.mdx +++ b/packages/docs/content/en/getting-started.mdx @@ -159,4 +159,3 @@ 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/docs/en/index.mdx b/packages/docs/content/en/index.mdx similarity index 100% rename from packages/docs/content/docs/en/index.mdx rename to packages/docs/content/en/index.mdx diff --git a/packages/docs/content/docs/en/meta.json b/packages/docs/content/en/meta.json similarity index 100% rename from packages/docs/content/docs/en/meta.json rename to packages/docs/content/en/meta.json diff --git a/packages/docs/content/docs/en/troubleshooting.mdx b/packages/docs/content/en/troubleshooting.mdx similarity index 99% rename from packages/docs/content/docs/en/troubleshooting.mdx rename to packages/docs/content/en/troubleshooting.mdx index 491fdaa..6d97819 100644 --- a/packages/docs/content/docs/en/troubleshooting.mdx +++ b/packages/docs/content/en/troubleshooting.mdx @@ -523,4 +523,3 @@ When reporting issues, include: **Issue**: Can't import from other launchers **Workaround**: Manually copy instance files - diff --git a/packages/docs/content/docs/zh/architecture.mdx b/packages/docs/content/zh/architecture.mdx similarity index 99% rename from packages/docs/content/docs/zh/architecture.mdx rename to packages/docs/content/zh/architecture.mdx index 44066ad..6a2a2df 100644 --- a/packages/docs/content/docs/zh/architecture.mdx +++ b/packages/docs/content/zh/architecture.mdx @@ -279,4 +279,3 @@ const result = await invoke("start_game", { versionId: "1.20.4" }); - **校验和验证**: 文件完整性验证 - **沙箱执行**: Tauri 安全模型 - **无任意代码**: 无 eval 或动态代码执行 - diff --git a/packages/docs/content/docs/zh/development.mdx b/packages/docs/content/zh/development.mdx similarity index 100% rename from packages/docs/content/docs/zh/development.mdx rename to packages/docs/content/zh/development.mdx diff --git a/packages/docs/content/docs/zh/features/authentication.mdx b/packages/docs/content/zh/features/authentication.mdx similarity index 99% rename from packages/docs/content/docs/zh/features/authentication.mdx rename to packages/docs/content/zh/features/authentication.mdx index d6bfb56..e83cc35 100644 --- a/packages/docs/content/docs/zh/features/authentication.mdx +++ b/packages/docs/content/zh/features/authentication.mdx @@ -264,4 +264,3 @@ listen('auth-status', (event) => { - **账户配置文件**:保存每个账户的设置 - **自动登录**:记住最后一个账户 - **令牌加密**:为存储的令牌增强安全性 - diff --git a/packages/docs/content/docs/zh/features/index.mdx b/packages/docs/content/zh/features/index.mdx similarity index 100% rename from packages/docs/content/docs/zh/features/index.mdx rename to packages/docs/content/zh/features/index.mdx diff --git a/packages/docs/content/docs/zh/features/java.mdx b/packages/docs/content/zh/features/java.mdx similarity index 100% rename from packages/docs/content/docs/zh/features/java.mdx rename to packages/docs/content/zh/features/java.mdx diff --git a/packages/docs/content/docs/zh/features/meta.json b/packages/docs/content/zh/features/meta.json similarity index 100% rename from packages/docs/content/docs/zh/features/meta.json rename to packages/docs/content/zh/features/meta.json diff --git a/packages/docs/content/docs/zh/features/mod-loaders.mdx b/packages/docs/content/zh/features/mod-loaders.mdx similarity index 99% rename from packages/docs/content/docs/zh/features/mod-loaders.mdx rename to packages/docs/content/zh/features/mod-loaders.mdx index be5cfeb..3687230 100644 --- a/packages/docs/content/docs/zh/features/mod-loaders.mdx +++ b/packages/docs/content/zh/features/mod-loaders.mdx @@ -407,4 +407,3 @@ listen('mod-loader-progress', (event) => { - **配置文件导出** - 共享模组包配置 - **CurseForge 集成** - 直接模组包导入 - **Modrinth 集成** - 模组搜索和安装 - diff --git a/packages/docs/content/docs/zh/getting-started.mdx b/packages/docs/content/zh/getting-started.mdx similarity index 99% rename from packages/docs/content/docs/zh/getting-started.mdx rename to packages/docs/content/zh/getting-started.mdx index abc5dc9..05d9aa4 100644 --- a/packages/docs/content/docs/zh/getting-started.mdx +++ b/packages/docs/content/zh/getting-started.mdx @@ -159,4 +159,3 @@ chmod +x dropout_*.AppImage - 查看[故障排除指南](/docs/troubleshooting) - 在 [GitHub Issues](https://github.com/HsiangNianian/DropOut/issues) 上报告 bug - 加入我们的社区讨论 - diff --git a/packages/docs/content/docs/zh/index.mdx b/packages/docs/content/zh/index.mdx similarity index 100% rename from packages/docs/content/docs/zh/index.mdx rename to packages/docs/content/zh/index.mdx diff --git a/packages/docs/content/docs/zh/meta.json b/packages/docs/content/zh/meta.json similarity index 100% rename from packages/docs/content/docs/zh/meta.json rename to packages/docs/content/zh/meta.json diff --git a/packages/docs/content/docs/zh/troubleshooting.mdx b/packages/docs/content/zh/troubleshooting.mdx similarity index 100% rename from packages/docs/content/docs/zh/troubleshooting.mdx rename to packages/docs/content/zh/troubleshooting.mdx