diff options
| author | 2025-01-21 19:10:44 -0600 | |
|---|---|---|
| committer | 2025-01-21 19:10:44 -0600 | |
| commit | 601586bc1263cb0e746181f8750a443ab0d4aaf1 (patch) | |
| tree | 136b33558a29e26be9b68335d69a010c9f8e4777 /src/launcher/runner.rs | |
| parent | use regular strings for jvm arguments (diff) | |
support jre specified in profile
Diffstat (limited to 'src/launcher/runner.rs')
| -rw-r--r-- | src/launcher/runner.rs | 103 |
1 files changed, 97 insertions, 6 deletions
diff --git a/src/launcher/runner.rs b/src/launcher/runner.rs index 41b3ed1..50a9ff8 100644 --- a/src/launcher/runner.rs +++ b/src/launcher/runner.rs @@ -1,7 +1,10 @@ use std::borrow::Cow; use std::ffi::{OsStr, OsString}; use std::iter; +use std::path::{Path, PathBuf}; use std::process::Command; +use log::{debug, warn}; +use tokio::{fs, io}; use crate::util::AsJavaPath; use crate::version::{CompleteVersion, FeatureMatcher, OperatingSystem}; use super::rules::CompatCheck; @@ -113,12 +116,100 @@ pub fn build_arguments<'l, F: FeatureMatcher>(launch: &LaunchInfo<'l, F>, versio } pub fn run_the_game(launch: &Launch) -> Result<(), Box<dyn std::error::Error>> { - Command::new("java") - .args(launch.jvm_args.iter() - .map(|o| o.as_os_str()) - .chain(iter::once(OsStr::new(launch.main_class.as_str()))) - .chain(launch.game_args.iter().map(|o| o.as_os_str()))) - .current_dir(launch.instance_path.as_path().as_java_path()).spawn()?.wait()?; + if launch.runtime_legacy_launch { + Command::new(launch.runtime_path.as_path().as_java_path()) + .args(launch.jvm_args.iter() + .map(|o| o.as_os_str()) + .chain(iter::once(OsStr::new(launch.main_class.as_str()))) + .chain(launch.game_args.iter().map(|o| o.as_os_str()))) + .current_dir(launch.instance_path.as_path().as_java_path()).spawn()?.wait()?; + } else { + todo!("jni launch not supported :(") + } Ok(()) } + +#[allow(dead_code)] +mod windows { + pub const JNI_SEARCH_PATH: Option<&str> = Some("server/jvm.dll"); + pub const JAVA_SEARCH_PATH: Option<&str> = Some("bin/java.exe"); + pub const JRE_PLATFORM_KNOWN: bool = true; +} + +#[allow(dead_code)] +mod linux { + pub const JNI_SEARCH_PATH: Option<&str> = Some("server/libjvm.so"); + pub const JAVA_SEARCH_PATH: Option<&str> = Some("bin/java"); + pub const JRE_PLATFORM_KNOWN: bool = true; +} + +#[allow(dead_code)] +mod macos { + pub const JNI_SEARCH_PATH: Option<&str> = Some("server/libjvm.dylib"); + pub const JAVA_SEARCH_PATH: Option<&str> = Some("bin/java"); + pub const JRE_PLATFORM_KNOWN: bool = true; +} + +#[allow(dead_code)] +mod unknown { + pub const JNI_SEARCH_PATH: Option<&str> = None; + pub const JAVA_SEARCH_PATH: Option<&str> = None; + pub const JRE_PLATFORM_KNOWN: bool = false; +} + +#[cfg(target_os = "windows")] +use self::windows::*; +#[cfg(target_os = "linux")] +use self::linux::*; +#[cfg(target_os = "macos")] +use self::macos::*; +#[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))] +use self::unknown::*; + +fn search_java_sync(base: impl AsRef<Path>, legacy: bool) -> Result<Option<PathBuf>, io::Error> { + assert!(JRE_PLATFORM_KNOWN); + let search_path = Path::new(match legacy { + true => JAVA_SEARCH_PATH, + _ => JNI_SEARCH_PATH + }.unwrap()); + + let walker = walkdir::WalkDir::new(base.as_ref()).into_iter() + .filter_map(|e| e.ok()) + .filter(|e| e.file_type().is_dir()); + + for entry in walker { + let check_path = [base.as_ref(), entry.path(), Path::new(search_path)].into_iter().collect::<PathBuf>(); + match std::fs::metadata(check_path.as_path()) { + Err(e) if e.kind() == io::ErrorKind::NotFound => (), + Err(e) => return Err(e), + Ok(meta) if meta.is_file() => return Ok(Some(check_path)), + _ => () + } + } + + Ok(None) // not found (sadface) +} + +pub async fn find_java(base: impl AsRef<Path>, legacy: bool) -> Result<Option<PathBuf>, io::Error> { + let meta = fs::metadata(&base).await?; + if meta.is_dir() { // do search + if !JRE_PLATFORM_KNOWN { + warn!("Unknown platform! Cannot search for java executable in {}. Please specify the executable file manually.", base.as_ref().display()); + return Ok(None); + } + + let (tx, rx) = tokio::sync::oneshot::channel(); + let base = base.as_ref().to_path_buf(); // idc + + tokio::task::spawn_blocking(move || { + let res = search_java_sync(base, legacy); + let _ = tx.send(res); // I really don't care if the reader hung up + }).await.expect("jre search panicked"); + + rx.await.expect("jre search didn't send us a result") + } else { // we are pointed directly at a file. assume it's what we want + debug!("JRE path {} is a file ({}). Assuming it's what we want.", base.as_ref().display(), legacy); + Ok(Some(base.as_ref().to_path_buf())) + } +} |
