minecraft_java_rs_core/launcher/
options.rs1use std::path::PathBuf;
2
3use serde::{Deserialize, Serialize};
4
5use crate::models::{loader::LoaderType, minecraft::Authenticator};
6
7#[derive(Debug, Clone, Deserialize, Serialize)]
13pub struct LaunchOptions {
14 pub path: PathBuf,
17
18 pub version: String,
21
22 pub authenticator: Authenticator,
24
25 #[serde(default = "defaults::timeout_secs")]
27 pub timeout_secs: u64,
28
29 #[serde(default = "defaults::download_concurrency")]
31 pub download_concurrency: u32,
32
33 #[serde(default = "defaults::verify_concurrency")]
36 pub verify_concurrency: u32,
37
38 #[serde(default)]
39 pub memory: MemoryConfig,
40
41 #[serde(default)]
42 pub java: JavaOptions,
43
44 #[serde(default)]
45 pub loader: LoaderConfig,
46
47 #[serde(default)]
48 pub screen: ScreenConfig,
49
50 #[serde(default)]
52 pub verify: bool,
53
54 #[serde(default)]
56 pub game_args: Vec<String>,
57
58 #[serde(default)]
60 pub jvm_args: Vec<String>,
61
62 #[serde(default)]
65 pub instance: Option<String>,
66
67 #[serde(default)]
69 pub url: Option<String>,
70
71 #[serde(default)]
73 pub mcp: Option<String>,
74
75 #[serde(default)]
77 pub intel_enabled_mac: bool,
78
79 #[serde(default)]
82 pub bypass_offline: bool,
83
84 #[serde(default)]
89 pub skip_bundle_check: bool,
90
91 #[serde(default)]
98 pub force_ipv4: bool,
99
100 #[serde(default)]
112 pub dns: Option<std::net::IpAddr>,
113}
114
115impl LaunchOptions {
116 pub fn save_dir(&self) -> PathBuf {
119 match &self.instance {
120 Some(inst) => self.path.join("instances").join(inst),
121 None => self.path.clone(),
122 }
123 }
124
125 pub fn loader_dir(&self, name: &str) -> PathBuf {
129 match &self.loader.path {
130 Some(p) => PathBuf::from(p),
131 None => self.path.join("loader").join(name),
132 }
133 }
134
135 pub fn clamped_concurrency(&self) -> u32 {
140 self.download_concurrency.clamp(1, 64)
141 }
142
143 pub fn clamped_verify_concurrency(&self) -> u32 {
145 self.verify_concurrency.clamp(1, 16)
146 }
147}
148
149#[derive(Debug, Clone, Deserialize, Serialize)]
152pub struct MemoryConfig {
153 #[serde(default = "defaults::memory_min")]
155 pub min: String,
156 #[serde(default = "defaults::memory_max")]
158 pub max: String,
159}
160
161impl Default for MemoryConfig {
162 fn default() -> Self {
163 Self {
164 min: defaults::memory_min(),
165 max: defaults::memory_max(),
166 }
167 }
168}
169
170#[derive(Debug, Clone, Deserialize, Serialize, Default)]
173pub struct ScreenConfig {
174 pub width: Option<u32>,
175 pub height: Option<u32>,
176 #[serde(default)]
178 pub fullscreen: bool,
179}
180
181#[derive(Debug, Clone, Deserialize, Serialize)]
184pub struct JavaOptions {
185 #[serde(default)]
187 pub path: Option<PathBuf>,
188
189 #[serde(default)]
191 pub version: Option<String>,
192
193 #[serde(default = "defaults::java_image_type")]
195 pub image_type: String,
196}
197
198impl Default for JavaOptions {
199 fn default() -> Self {
200 Self {
201 path: None,
202 version: None,
203 image_type: defaults::java_image_type(),
204 }
205 }
206}
207
208#[derive(Debug, Clone, Deserialize, Serialize, Default)]
211pub struct LoaderConfig {
212 pub loader_type: Option<LoaderType>,
214
215 #[serde(default = "defaults::loader_build")]
218 pub build: String,
219
220 #[serde(default)]
222 pub enable: bool,
223
224 #[serde(default)]
227 pub path: Option<String>,
228
229 #[serde(default)]
232 pub config: Option<LoaderInnerConfig>,
233}
234
235#[derive(Debug, Clone, Deserialize, Serialize)]
237pub struct LoaderInnerConfig {
238 pub java_path: String,
239 pub minecraft_jar: String,
240 pub minecraft_json: String,
241}
242
243mod defaults {
246 pub fn timeout_secs() -> u64 {
247 10
248 }
249 pub fn download_concurrency() -> u32 {
250 5
251 }
252 pub fn verify_concurrency() -> u32 {
253 4
254 }
255 pub fn memory_min() -> String {
256 "1G".into()
257 }
258 pub fn memory_max() -> String {
259 "2G".into()
260 }
261 pub fn java_image_type() -> String {
262 "jre".into()
263 }
264 pub fn loader_build() -> String {
265 "latest".into()
266 }
267}
268
269#[cfg(test)]
272mod tests {
273 use super::*;
274
275 #[test]
276 fn save_dir_without_instance() {
277 let opts = make_opts(None);
278 assert_eq!(opts.save_dir(), PathBuf::from("/mc"));
279 }
280
281 #[test]
282 fn save_dir_with_instance() {
283 let opts = make_opts(Some("test-world".into()));
284 assert_eq!(opts.save_dir(), PathBuf::from("/mc/instances/test-world"));
285 }
286
287 #[test]
288 fn concurrency_clamp() {
289 let mut opts = make_opts(None);
290 opts.download_concurrency = 0;
291 assert_eq!(opts.clamped_concurrency(), 1);
292 opts.download_concurrency = 99;
293 assert_eq!(opts.clamped_concurrency(), 64);
294 opts.download_concurrency = 5;
295 assert_eq!(opts.clamped_concurrency(), 5);
296 }
297
298 #[test]
299 fn verify_concurrency_clamp() {
300 let mut opts = make_opts(None);
301 opts.verify_concurrency = 0;
302 assert_eq!(opts.clamped_verify_concurrency(), 1);
303 opts.verify_concurrency = 99;
304 assert_eq!(opts.clamped_verify_concurrency(), 16);
305 opts.verify_concurrency = 4;
306 assert_eq!(opts.clamped_verify_concurrency(), 4);
307 }
308
309 #[test]
310 fn memory_defaults() {
311 let m = MemoryConfig::default();
312 assert_eq!(m.min, "1G");
313 assert_eq!(m.max, "2G");
314 }
315
316 fn make_opts(instance: Option<String>) -> LaunchOptions {
317 use crate::models::minecraft::Authenticator;
318 LaunchOptions {
319 path: PathBuf::from("/mc"),
320 version: "1.20.4".into(),
321 authenticator: Authenticator {
322 access_token: "tok".into(),
323 name: "Player".into(),
324 uuid: "uuid".into(),
325 xbox_account: None,
326 user_properties: None,
327 client_id: None,
328 client_token: None,
329 },
330 timeout_secs: 10,
331 download_concurrency: 5,
332 verify_concurrency: 4,
333 memory: MemoryConfig::default(),
334 java: JavaOptions::default(),
335 loader: LoaderConfig::default(),
336 screen: ScreenConfig::default(),
337 verify: false,
338 game_args: vec![],
339 jvm_args: vec![],
340 instance,
341 url: None,
342 mcp: None,
343 intel_enabled_mac: false,
344 bypass_offline: false,
345 skip_bundle_check: false,
346 force_ipv4: false,
347 dns: None,
348 }
349 }
350}