1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
|
---
title: Internal Implementation
description: Detailed implementation and technical specifications of DropOut core functions
---
# Internal Implementation
This page details the technical implementation details, data structures, and processing flows of the launcher's core modules.
## 1. Authentication System
The authentication chain contains multiple asynchronous steps, and failure at any step will interrupt the entire process. DropOut uses the Microsoft Device Code Flow to achieve secure login without redirection.
### 1.1 Detailed Process
1. **Device Code Request**:
- Call `https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode`
- Get user verification code and verification URL.
2. **Token Exchange**: Poll `/oauth2/v2.0/token` to get the primary Access Token and Refresh Token.
3. **Xbox Live Authentication**: Get `Token` and `uhs` (User Hash).
4. **XSTS Authorization**: Redirect to `rp://api.minecraftservices.com/`.
5. **Minecraft Login**: Exchange for the final game Access Token using the `XBL3.0 x=<uhs>;<xsts_token>` format token.
### 1.2 Account Storage and Security
Account data is persisted in `accounts.json`, containing account type and encrypted token information:
```json
{
"active_account_uuid": "...",
"accounts": [
{
"type": "Microsoft",
"username": "...",
"uuid": "...",
"access_token": "...",
"refresh_token": "...",
"expires_at": 1234567890
},
{ "type": "Offline", "username": "Player", "uuid": "..." }
]
}
```
**Offline UUID**: Uses a username-based deterministic UUID v3 to ensure consistency of local saves and configurations.
```rust
// core/auth.rs implementation details
pub fn generate_offline_uuid(username: &str) -> String {
let namespace = Uuid::NAMESPACE_OID;
Uuid::new_v3(&namespace, username.as_bytes()).to_string()
}
```
### 1.3 Authentication Related APIs
| Command / Event | Type | Description |
| :--- | :--- | :--- |
| `start_microsoft_login` | Invoke | Start device flow and return verification code |
| `complete_microsoft_login` | Invoke | Poll and complete the full authentication chain |
| `login_offline` | Invoke | Create and switch to offline account |
| `auth-progress` | Event | Report authentication progress in real-time (e.g., "Xbox Live Auth...") |
---
## 2. Java Runtime Management
### 2.1 Catalogs and Metadata
The Java Catalog caches available versions and platform-specific links from Adoptium.
- **Storage**: `java_catalog.json` records SHA256 checksums and file sizes for each version.
```json
// java_catalog.json structure example
{
"releases": [
{
"major_version": 17,
"image_type": "jdk",
"version": "17.0.9+9",
"download_url": "...",
"checksum": "...",
"file_size": 123456789
}
],
"cached_at": 1700000000
}
```
- **Detection**: Executes `java -version` command on candidate paths and parses version strings and 64-Bit identifiers from `stderr` output.
```rust
// core/java.rs detection logic
fn check_java_installation(path: &PathBuf) -> Option<JavaInstallation> {
let mut cmd = Command::new(path);
cmd.arg("-version");
// Parse "version" keyword information from stderr output
}
```
### 2.2 Automatic Installation Logic
1. **Download**: Supports resumable downloads; large files are downloaded in parallel segments.
2. **Extraction**: Handles archives for different operating systems (macOS handles .app structure inside .tar.gz, Windows handles .zip).
3. **Verification**: Mandatory hash verification after download ensures runtime environment integrity.
### 2.3 Java Management Related APIs
| Command / Event | Type | Description |
| :--- | :--- | :--- |
| `detect_java` | Invoke | Scan system installed Java environments |
| `download_adoptium_java` | Invoke | Start asynchronous download and automatic extraction/configuration |
| `cancel_java_download` | Invoke | Cancel current download task via atomic flag |
| `java-download-progress` | Event | Report file size, speed, percentage, and ETA |
---
## 3. Game Launch Logic & JVM Optimization
### 3.1 Memory Allocation Scheme
- **Xmx & Xms**: It is recommended to set initial memory and maximum memory to be consistent.
- **Strategy**: The launcher automatically suggests optimal allocation based on total system memory and Java architecture, and parameters generated by the launcher have the highest priority.
### 3.2 G1GC Optimization Strategy
For 1.17+ versions and high-load mod environments, DropOut injects a concise G1GC parameter chain by default:
```bash
-XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200
-XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC
```
---
## 4. Mod Loader Mechanism
### 4.1 Version Merging (Inheritance)
Mod loaders link to the vanilla Minecraft version JSON via the `inheritsFrom` field.
```json
// Typical Fabric version config (partial)
{
"id": "fabric-loader-0.15.0-1.20.4",
"inheritsFrom": "1.20.4",
"mainClass": "net.fabricmc.loader.impl.launch.knot.KnotClient",
"libraries": [
{
"name": "net.fabricmc:fabric-loader:0.15.0",
"url": "https://maven.fabricmc.net/"
}
]
}
```
The following merging is performed during the launch phase:
1. **Library Priority**: Loader's own libraries (e.g., Fabric Loader) rank before vanilla libraries.
2. **Main Class Override**: `mainClass` is always taken from the child definition (i.e., the mod loader's entry point, like Fabric's `KnotClient`).
3. **Argument Chain**: Merge `jvm` and `game` argument arrays, automatically filtering out inapplicable system rules.
```rust
// core/version_merge.rs merge core implementation
pub fn merge_versions(child: GameVersion, parent: GameVersion) -> GameVersion {
let mut merged_libraries = child.libraries;
merged_libraries.extend(parent.libraries);
// Merge argument logic and return new GameVersion instance
}
```
### 4.2 Library Path Resolution (Maven)
The launcher implements complete Maven path conversion logic:
`group:artifact:version` → `group_path/artifact/version/artifact-version.jar`
```rust
// core/maven.rs coordinate conversion path logic
pub fn to_path(&self) -> String {
let group_path = self.group.replace('.', "/");
format!("{}/{}/{}/{}-{}.{}",
group_path, self.artifact, self.version,
self.artifact, self.version, self.extension
)
}
```
### 4.3 Mod Installation Interface
The launcher uses differentiated installation strategies based on different loader characteristics.
#### Forge Installation Logic
For Forge, DropOut downloads the official Installer and invokes the standard installer via a Java subprocess, ensuring this process is completely consistent with the official flow (including bytecode patch generation).
```rust
// core/forge.rs invoke official installer (simplified example)
Command::new(java_path)
.args(&[
"-jar",
installer_path.to_str().unwrap(),
"--installClient",
game_dir.to_str().unwrap()
])
.output()?;
```
| Command / Event | Type | Description |
| :--- | :--- | :--- |
| `install_fabric` | Invoke | Download Fabric libraries and generate inheritance JSON |
| `install_forge` | Invoke | Run Forge Installer and perform bytecode patching |
| `mod-loader-progress` | Event | Report installation stage (e.g., "processing", "complete") |
---
## 5. Communication & Monitoring System
### 5.1 Event Bus
The backend sends asynchronous pulses to the upper layer via Tauri's `Window` instance.
```rust
// Backend emit_log! macro simplifies log emission
macro_rules! emit_log {
($window:expr, $msg:expr) => {
let _ = $window.emit("launcher-log", $msg);
println!("[Launcher] {}", $msg);
};
}
```
- **`launcher-log`**: General console output stream for global operation trajectory recording.
- **`game-stdout` / `game-stderr`**: Capture game subprocess standard output and errors, transmitting to frontend in real-time via independent threads.
```typescript
// Frontend listen example (Svelte 5)
import { listen } from "@tauri-apps/api/event";
const unlisten = await listen("launcher-log", (event) => {
logStore.addLine(event.payload);
});
```
- **`version-installed`**: Notify UI to update version list status after asynchronous task completion.
### 5.2 Launch Log Desensitization
To prevent sensitive information leakage to third-party log platforms, the launcher masks tokens before recording launch commands.
```rust
// partial argument masking logic based on main.rs
let masked_args: Vec<String> = args.iter().enumerate().map(|(i, arg)| {
if i > 0 && (args[i-1] == "--accessToken" || args[i-1] == "--uuid") {
"***".to_string()
} else {
arg.clone()
}
}).collect();
```
---
## 6. Architecture & Development Standards
### 6.1 Core Architecture Patterns
#### Backend Command Pattern (Tauri)
All backend functions are encapsulated as asynchronous Commands and injected with global state via `State`.
1. **Define Command**:
```rust
#[tauri::command]
async fn start_game(
window: Window,
auth_state: State<'_, AccountState>,
config_state: State<'_, ConfigState>
) -> Result<String, String> {
emit_log!(window, "Starting game launch...");
// Business logic...
Ok("Success".into())
}
```
2. **Register Command (main.rs)**:
```rust
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![start_game, ...])
```
3. **Frontend Call**:
```typescript
import { invoke } from "@tauri-apps/api/core";
// Argument names must correspond to Rust function parameters in snake_case/camelCase
const result = await invoke("start_game", { versionId: "1.20.4" });
```
#### Error Handling Pattern
All Tauri commands uniformly return `Result<T, String>`, where the Err type is fixed as String, allowing the frontend to display error messages directly.
```rust
// Uniformly use map_err to convert errors to String
.await
.map_err(|e| e.to_string())?;
// Frontend catch
try {
await invoke("...")
} catch (e) {
// e is the error string returned by Rust
console.error(e);
}
```
#### Frontend State Management (Svelte 5 Runes)
The frontend fully adopts Svelte 5's `Runes` system (`$state`, `$effect`) replacing the old `writable` stores.
```typescript
// ui/src/stores/auth.svelte.ts
export class AuthState {
// Use $state to define reactive data
currentAccount = $state<Account | null>(null);
isLoginModalOpen = $state(false);
constructor() {
// Initialization logic
}
}
// Export singleton for global access
export const authState = new AuthState();
```
#### Frontend View Routing (Manual Routing)
DropOut does not use conventional URL routing, but instead manages the currently active view component via global state.
```typescript
// ui/src/stores/ui.svelte.ts
export class UIState {
activeView = $state("home"); // "home" | "versions" | "settings"
setView(view: string) {
this.activeView = view;
}
}
```
```svelte
<!-- App.svelte -->
<script>
import { uiState } from "./stores/ui.svelte";
</script>
{#if uiState.activeView === "home"}
<HomeView />
{:else if uiState.activeView === "settings"}
<SettingsView />
{/if}
```
### 6.2 Development Best Practices
1. **Silent Refresh**: Check `expires_at` before calling `start_game`, and call `refresh_full_auth` if expired.
2. **UA Spoofing**: Microsoft auth WAF blocks requests with empty UA, so simulation of real UA in `reqwest` client is mandatory.
3. **Log Desensitization**: Sensitive parameter values like `--accessToken` and `--uuid` must be masked in launch logs.
### 6.3 Future Roadmap
- **Multi-device Account Sync**: Explore OS-level encrypted storage solution to replace existing plaintext `accounts.json`.
- **Automatic Dependency Resolution**: Automatically parse and download prerequisite libraries from Modrinth/CurseForge when installing mods.
- **Intelligent Conflict Detection**: Scan `mods/` folder before launch to identify potential class conflicts or injection point errors.
- **Config Sharing**: Support one-click export/import of complete instance configuration packages (Modpacks).
|