use std::process::Command; use log::{debug, info}; use crate::{ config::Config, errors::McError, minecraft::manifests::{Library, Version}, platform::paths, }; fn build_classpath( config: &Config, version: &Version, ) -> Result { let sep = if cfg!(windows) { ";" } else { ":" }; let mut entries = Vec::new(); for library in &version.libraries { if !library_allowed(library) { continue; } if let Some(artifact) = &library.downloads.artifact { let path = paths::library_file(config, &artifact.path)?; entries.push(path.to_string_lossy().to_string()); } } let client_jar = paths::client_jar(config, &version.id)?; entries.push(client_jar.to_string_lossy().to_string()); Ok(entries.join(sep)) } pub fn launch(config: &Config, version: &Version) -> Result<(), McError> { let java = &config.java_path; let classpath = build_classpath(config, version)?; let natives_dir = paths::natives_dir(config, &version.id); if !natives_dir.exists() { return Err(McError::Runtime(format!( "Natives folder does not exist: {}", natives_dir.display() ))); } let asset_index_id = version .asset_index .as_ref() .ok_or_else(|| { McError::Runtime("Missing assetIndex in version.json".into()) })? .id .clone(); info!("Launching Minecraft {}", version.id); debug!("Classpath: {}", classpath); debug!("Natives: {}", natives_dir.display()); debug!("Asset index: {}", asset_index_id); let mut cmd = Command::new(java); cmd.arg(format!("-Xmx{}M", config.max_memory_mb)) .arg(format!("-Djava.library.path={}", natives_dir.display())); for arg in &config.jvm_args { cmd.arg(arg); } cmd.arg("-cp") .arg(classpath) .arg(&version.main_class); cmd.arg("--username") .arg(&config.username) .arg("--version") .arg(&version.id) .arg("--gameDir") .arg(paths::game_dir(config)) .arg("--assetsDir") .arg(paths::assets_dir(config)) .arg("--assetIndex") .arg(&asset_index_id) .arg("--uuid") .arg(&config.uuid) .arg("--userProperties") .arg("{}") .arg("--accessToken") .arg("0") .arg("--userType") .arg("legacy"); let status = cmd.status()?; if !status.success() { return Err(McError::Process("Minecraft exited with error".into())); } Ok(()) } fn library_allowed(lib: &Library) -> bool { let rules = match &lib.rules { | Some(r) => r, | None => return true, }; let mut allowed = false; for rule in rules { let os_match = match &rule.os { | Some(os) => os.name == "linux", | None => true, }; if os_match { allowed = rule.action == "allow"; } } allowed }