aboutsummaryrefslogtreecommitdiffstats
path: root/src/config
diff options
context:
space:
mode:
Diffstat (limited to 'src/config')
-rw-r--r--src/config/file.rs26
-rw-r--r--src/config/loader.rs129
-rw-r--r--src/config/mod.rs17
-rw-r--r--src/config/runtime.rs95
4 files changed, 206 insertions, 61 deletions
diff --git a/src/config/file.rs b/src/config/file.rs
new file mode 100644
index 0000000..17f2cb2
--- /dev/null
+++ b/src/config/file.rs
@@ -0,0 +1,26 @@
1use std::path::PathBuf;
2
3use serde::Deserialize;
4
5use crate::minecraft::launcher::JavaRuntime;
6
7#[derive(Debug, Deserialize)]
8pub struct FileConfig {
9 pub username: String,
10 pub uuid: String,
11 pub version: String,
12 pub max_memory_mb: u32,
13
14 #[serde(default)]
15 pub jvm_args: Vec<String>,
16
17 #[serde(default)]
18 pub runtimes: Vec<JavaRuntime>,
19
20 #[serde(default)]
21 pub java_path: String,
22
23 pub data_dir: PathBuf,
24 // pub cache_dir: PathBuf,
25 // pub config_dir: PathBuf,
26}
diff --git a/src/config/loader.rs b/src/config/loader.rs
index d4b142e..47514e5 100644
--- a/src/config/loader.rs
+++ b/src/config/loader.rs
@@ -1,65 +1,90 @@
1use std::{env::var, fs::read_to_string, path::PathBuf}; 1use std::{env, fs::read_to_string, path::PathBuf};
2
3use directories::ProjectDirs; 2use directories::ProjectDirs;
4use serde::Deserialize; 3use uuid::Uuid;
5 4
5use super::{file::FileConfig, runtime::RuntimeConfig};
6use crate::{constants::*, errors::McError}; 6use crate::{constants::*, errors::McError};
7#[allow(dead_code)] 7
8#[derive(Debug, Deserialize)] 8pub struct ConfigLoader;
9pub struct Config { 9
10 pub username: String, 10impl ConfigLoader {
11 pub uuid: String, 11 pub fn load(cfg_file: Option<&PathBuf>) -> Result<RuntimeConfig, McError> {
12 pub version: String, 12 let path = match cfg_file {
13 pub java_path: String, 13 | Some(p) => p.clone(),
14 pub max_memory_mb: u32, 14 | None => Self::default_config_path()?,
15 pub data_dir: PathBuf, 15 };
16 pub cache_dir: PathBuf, 16
17 pub config_dir: PathBuf, 17 let mut file_cfg = if path.exists() {
18 #[serde(default)] 18 Self::read_file(&path)?
19 pub jvm_args: Vec<String>,
20}
21impl Config {
22 pub fn load() -> Result<Self, McError> {
23 let cfg_path = default_config_path()?;
24 let mut cfg: Config = if cfg_path.exists() {
25 let txt = read_to_string(&cfg_path)?;
26 toml::from_str(&txt).map_err(|e| McError::Config(e.to_string()))?
27 } else { 19 } else {
28 Self::default() 20 Self::default_file_config()?
29 }; 21 };
30 if let Ok(v) = var("MC_USERNAME") { 22
31 cfg.username = v; 23 Self::apply_env_overrides(&mut file_cfg);
32 } 24
33 if let Ok(v) = var("MC_VERSION") { 25 Ok(RuntimeConfig::from_file(file_cfg))
34 cfg.version = v; 26 }
35 } 27
36 if let Ok(v) = var("MC_JAVA_PATH") { 28 fn read_file(path: &PathBuf) -> Result<FileConfig, McError> {
37 cfg.java_path = v; 29 let content = read_to_string(path).map_err(|e| {
38 } 30 McError::Config(format!(
39 if let Ok(v) = var("MC_MAX_MEMORY_MB") { 31 "Failed to read config file {}: {}",
40 cfg.max_memory_mb = v.parse().unwrap_or(cfg.max_memory_mb); 32 path.display(),
41 } 33 e
42 Ok(cfg) 34 ))
35 })?;
36
37 toml::from_str(&content).map_err(|e| {
38 McError::Config(format!("Failed to parse config file: {}", e))
39 })
43 } 40 }
44 41
45 fn default() -> Self { 42 fn apply_env_overrides(cfg: &mut FileConfig) {
46 let base = 43 cfg.username = env::var(ENV_USERNAME)
47 ProjectDirs::from("com", "example", "dml").expect("platform dirs"); 44 .unwrap_or_else(|_| DEFAULT_USERNAME.to_string());
48 Self { 45
49 username: "Player".into(), 46 cfg.version = env::var(ENV_VERSION)
50 uuid: uuid::Uuid::new_v4().to_string(), 47 .unwrap_or_else(|_| DEFAULT_VERSION.to_string());
48
49 cfg.java_path = env::var(ENV_JAVA_PATH)
50 .unwrap_or_else(|_| DEFAULT_JAVA_PATH.to_string());
51
52 cfg.max_memory_mb = env::var(ENV_MAX_MEMORY_MB)
53 .ok()
54 .and_then(|v| v.parse().ok())
55 .unwrap_or(DEFAULT_MAX_MEMORY_MB);
56 }
57
58 fn default_config_path() -> Result<PathBuf, McError> {
59 let base = ProjectDirs::from(
60 DEFAULT_COMPANY,
61 DEFAULT_PROJECT_GROUP,
62 DEFAULT_PROJECT_NAME,
63 )
64 .ok_or_else(|| McError::Config(DEFAULT_ERR_PLATFORM_DIR.into()))?;
65
66 Ok(base.config_dir().join(DEFAULT_CONFIG_FILENAME))
67 }
68
69 fn default_file_config() -> Result<FileConfig, McError> {
70 let base = ProjectDirs::from(
71 DEFAULT_COMPANY,
72 DEFAULT_PROJECT_GROUP,
73 DEFAULT_PROJECT_NAME,
74 )
75 .ok_or_else(|| McError::Config(DEFAULT_ERR_PLATFORM_DIR.into()))?;
76
77 Ok(FileConfig {
78 username: DEFAULT_USERNAME.into(),
79 uuid: Uuid::new_v4().to_string(),
51 version: DEFAULT_VERSION.into(), 80 version: DEFAULT_VERSION.into(),
52 java_path: DEFAULT_JAVA_PATH.into(),
53 max_memory_mb: DEFAULT_MAX_MEMORY_MB, 81 max_memory_mb: DEFAULT_MAX_MEMORY_MB,
82 java_path: DEFAULT_JAVA_PATH.into(),
54 data_dir: base.data_dir().into(), 83 data_dir: base.data_dir().into(),
55 cache_dir: base.cache_dir().into(), 84 // cache_dir: base.cache_dir().into(),
56 config_dir: base.config_dir().into(), 85 // config_dir: base.config_dir().into(),
57 jvm_args: vec![], 86 jvm_args: vec![],
58 } 87 runtimes: vec![],
88 })
59 } 89 }
60} 90}
61fn default_config_path() -> Result<PathBuf, McError> {
62 let base = ProjectDirs::from("com", "example", "dml")
63 .ok_or_else(|| McError::Config("cannot determine config dir".into()))?;
64 Ok(base.config_dir().join("config.toml"))
65}
diff --git a/src/config/mod.rs b/src/config/mod.rs
index 066154a..a375dda 100644
--- a/src/config/mod.rs
+++ b/src/config/mod.rs
@@ -1,12 +1,11 @@
1//! Configuration module for the DML launcher. 1//! Configuration module for the DML launcher.
2//!
3//! This module contains submodules and helpers for loading, parsing, and
4//! managing configuration files and settings. It abstracts the details
5//! of where configuration is stored and how it is represented in memory.
6//!
7//! # Submodules
8//! - `loader`: Functions to load and parse configuration from disk or
9//! environment variables.
10 2
3pub mod file;
11pub mod loader; 4pub mod loader;
12pub use loader::Config; 5pub mod runtime;
6
7pub use loader::ConfigLoader;
8pub use runtime::RuntimeConfig;
9
10/// Backwards-compatibility alias so existing code can keep using `Config`
11pub type Config = RuntimeConfig;
diff --git a/src/config/runtime.rs b/src/config/runtime.rs
new file mode 100644
index 0000000..46857f0
--- /dev/null
+++ b/src/config/runtime.rs
@@ -0,0 +1,95 @@
1use std::path::PathBuf;
2
3use super::file::FileConfig;
4use crate::{constants::*, minecraft::launcher::JavaRuntime};
5
6/// Configuration for the runtime environment used to launch Minecraft.
7///
8/// The `RuntimeConfig` struct holds the configuration settings required to
9/// launch Minecraft with a specific Java runtime. This includes details about
10/// the user, the Minecraft version, the available Java runtimes, and JVM options.
11///
12/// The `RuntimeConfig` struct is typically used by the launcher to store and
13/// manage the necessary settings for running the game. It also supports
14/// dynamic configuration by allowing the addition of Java runtimes and the
15/// specification of system paths and arguments.
16#[derive(Debug)]
17#[derive(Default)]
18pub struct RuntimeConfig {
19 /// The username of the player running Minecraft.
20 pub username: String,
21
22 /// The UUID (unique identifier) of the user.
23 pub uuid: String,
24
25 /// The version of Minecraft that the user is running.
26 pub version: String,
27
28 /// The maximum amount of memory (in megabytes) allocated to the Java process.
29 /// This setting determines how much memory the Minecraft instance can use.
30 pub max_memory_mb: u32,
31
32 /// A list of arguments to pass to the JVM when launching Minecraft.
33 /// These arguments can be used to customize the JVM's behavior, such as
34 /// memory settings, garbage collection options, etc.
35 pub jvm_args: Vec<String>,
36
37 /// A list of Java runtime environments available for Minecraft.
38 /// If no specific Java runtime is provided, the default one is used.
39 pub runtimes: Vec<JavaRuntime>,
40
41 /// The directory where Minecraft data (e.g., worlds, logs, configs) is stored.
42 /// This path is critical for loading and saving game data.
43 pub data_dir: PathBuf,
44}
45
46impl RuntimeConfig {
47 /// Creates a new `RuntimeConfig` instance from a `FileConfig`.
48 ///
49 /// This method takes a `FileConfig` object (typically loaded from a configuration file)
50 /// and constructs a `RuntimeConfig` instance. It ensures that if no runtimes are defined
51 /// but a Java path is provided, a default Java runtime is created based on the specified path.
52 ///
53 /// # Parameters
54 /// - `file`: A `FileConfig` instance containing initial configuration values for the
55 /// Minecraft runtime. This includes user details, Minecraft version, JVM arguments,
56 /// and the path to Java (if specified).
57 ///
58 /// # Returns
59 /// - A `RuntimeConfig` instance initialized with the values from `file`. If no runtimes
60 /// were provided in `file` but a Java path was given, the method will add a default Java runtime.
61 ///
62 /// # Example
63 /// ```rust
64 /// let file_config = FileConfig {
65 /// username: "Player1".into(),
66 /// uuid: "1234-5678-9101".into(),
67 /// version: "1.18.2".into(),
68 /// max_memory_mb: 2048,
69 /// jvm_args: vec!["-Xmx2G".into()],
70 /// runtimes: Vec::new(),
71 /// java_path: "/path/to/java".into(),
72 /// data_dir: "/path/to/minecraft/data".into(),
73 /// };
74 ///
75 /// let runtime_config = RuntimeConfig::from_file(file_config);
76 /// ```
77 pub fn from_file(mut file: FileConfig) -> Self {
78 if file.runtimes.is_empty() && !file.java_path.is_empty() {
79 file.runtimes.push(JavaRuntime {
80 major: DEFAULT_JAVA_MAJOR,
81 path: PathBuf::from(&file.java_path),
82 });
83 }
84
85 Self {
86 username: file.username,
87 uuid: file.uuid,
88 version: file.version,
89 max_memory_mb: file.max_memory_mb,
90 jvm_args: file.jvm_args,
91 runtimes: file.runtimes,
92 data_dir: file.data_dir,
93 }
94 }
95}