summaryrefslogtreecommitdiffstats
path: root/src/launcher
diff options
context:
space:
mode:
authorLibravatar bigfoot547 <[email protected]>2025-01-21 19:10:44 -0600
committerLibravatar bigfoot547 <[email protected]>2025-01-21 19:10:44 -0600
commit601586bc1263cb0e746181f8750a443ab0d4aaf1 (patch)
tree136b33558a29e26be9b68335d69a010c9f8e4777 /src/launcher
parentuse regular strings for jvm arguments (diff)
support jre specified in profile
Diffstat (limited to 'src/launcher')
-rw-r--r--src/launcher/runner.rs103
-rw-r--r--src/launcher/settings.rs11
2 files changed, 108 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()))
+ }
+}
diff --git a/src/launcher/settings.rs b/src/launcher/settings.rs
index e65b8b3..5c8cb27 100644
--- a/src/launcher/settings.rs
+++ b/src/launcher/settings.rs
@@ -161,6 +161,8 @@ pub struct Profile {
#[serde(default)]
jvm_arguments: Vec<String>,
+ #[serde(default)]
+ legacy_launch: bool,
resolution: Option<Resolution>
}
@@ -200,6 +202,7 @@ impl Profile {
java_runtime: None,
instance: instance_name.into(),
jvm_arguments: DEF_JVM_ARGUMENTS.iter().map(|s| String::from(*s)).collect(),
+ legacy_launch: false,
resolution: None
}
}
@@ -219,4 +222,12 @@ impl Profile {
pub fn get_resolution(&self) -> Option<Resolution> {
self.resolution
}
+
+ pub fn get_java_runtime(&self) -> Option<&String> {
+ self.java_runtime.as_ref()
+ }
+
+ pub fn is_legacy_launch(&self) -> bool {
+ self.legacy_launch
+ }
}