Documentation Index
Fetch the complete documentation index at: https://mintlify.com/CCBlueX/LiquidLauncher/llms.txt
Use this file to discover all available pages before exploring further.
LiquidLauncher automatically downloads and manages Java runtimes, ensuring the correct version is always available.
Supported Distributions
The launcher supports three major Java distributions:
Eclipse Temurin
Default distribution
- Supports all LTS versions (8, 11, 17, 21)
- AdoptOpenJDK successor
- Excellent compatibility
GraalVM
Performance focused
- Java 17+ only
- Advanced optimizations
- Native image support
Azul Zulu
Enterprise ready
- All LTS versions
- Commercial support available
- Wide platform support
Distribution Selection
src-tauri/src/minecraft/java/distribution.rs
#[derive(Deserialize, Serialize, Clone)]
pub enum JavaDistribution {
#[serde(rename = "temurin")]
Temurin,
#[serde(rename = "graalvm")]
GraalVM,
#[serde(rename = "zulu")]
Zulu,
}
impl Default for JavaDistribution {
fn default() -> Self {
// Temurin supports any version of java
JavaDistribution::Temurin
}
}
The default distribution (Temurin) is automatically selected and supports all Java versions.
Automatic Download
Java runtimes are downloaded automatically when launching a build that requires them.
Download Process
Determine Required Version
Each build specifies its required Java version:src-tauri/src/app/client_api.rs
pub struct Build {
pub jre_distribution: JavaDistribution,
pub jre_version: u32,
// ...
}
Check If Installed
The launcher checks if the required runtime is already installedsrc-tauri/src/minecraft/java/jre_downloader.rs
let runtime_path = runtimes_folder.join(
format!("{}_{}", jre_distribution.get_name(), jre_version)
);
Download Runtime
If not present, downloads from the distribution’s CDN:src-tauri/src/minecraft/java/jre_downloader.rs
pub async fn jre_download<F>(
runtimes_folder: &Path,
jre_distribution: &JavaDistribution,
jre_version: &u32,
on_progress: F,
) -> Result<PathBuf>
where
F: Fn(u64, u64),
{
let url = jre_distribution.get_url(jre_version).await?;
let retrieved_bytes = download_file(&url, on_progress).await?;
// ...
}
Extract Archive
Extracts the downloaded archive (ZIP on Windows, TAR.GZ on Linux/macOS):src-tauri/src/minecraft/java/jre_downloader.rs
match OS {
OperatingSystem::WINDOWS => zip_extract(cursor, runtime_path.as_path()).await?,
OperatingSystem::LINUX | OperatingSystem::OSX => {
tar_gz_extract(cursor, runtime_path.as_path()).await?
}
_ => bail!("Unsupported OS"),
}
Locate Binary
Finds and verifies the Java executable
Download URLs
Each distribution has its own download URL format:
JavaDistribution::Temurin => {
let os_name = OS.get_adoptium_name()?;
format!(
"https://api.adoptium.net/v3/binary/latest/{}/ga/{}/{}/jre/hotspot/normal/eclipse?project=jdk",
jre_version, os_name, os_arch
)
}
Java Binary Location
The launcher automatically locates the Java binary based on the operating system:
src-tauri/src/minecraft/java/jre_downloader.rs
pub async fn find_java_binary(
runtimes_folder: &Path,
jre_distribution: &JavaDistribution,
jre_version: &u32,
) -> Result<PathBuf> {
let runtime_path = runtimes_folder.join(
format!("{}_{}", jre_distribution.get_name(), jre_version)
);
let mut files = fs::read_dir(&runtime_path).await?;
if let Some(jre_folder) = files.next_entry().await? {
let folder_path = jre_folder.path();
let java_binary = match OS {
OperatingSystem::WINDOWS => folder_path.join("bin").join("javaw.exe"),
OperatingSystem::OSX => folder_path
.join("Contents")
.join("Home")
.join("bin")
.join("java"),
_ => folder_path.join("bin").join("java"),
};
if java_binary.exists() {
return Ok(java_binary.absolutize()?.to_path_buf());
}
}
Err(anyhow::anyhow!("Failed to find JRE"))
}
Permissions Management
On Unix systems, the launcher ensures the Java binary has execution permissions:
src-tauri/src/minecraft/java/jre_downloader.rs
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let metadata = fs::metadata(&java_binary).await?;
if !metadata.permissions().mode() & 0o111 != 0 {
// try to change permissions
let mut permissions = metadata.permissions();
permissions.set_mode(0o111);
fs::set_permissions(&java_binary, permissions).await?;
}
}
This ensures downloaded Java runtimes are immediately executable without manual permission changes.
Runtime Execution
The JavaRuntime wrapper handles process execution:
src-tauri/src/minecraft/java/runtime.rs
pub struct JavaRuntime(PathBuf);
impl JavaRuntime {
pub async fn execute(&self, arguments: Vec<String>, game_dir: &Path) -> Result<Child> {
if !self.0.exists() {
bail!("Java runtime not found at: {}", self.0.display());
}
debug!("Executing Java runtime: {}", self.0.display());
let mut command = Command::new(&self.0);
command.current_dir(game_dir);
command.args(arguments);
command.stderr(Stdio::piped()).stdout(Stdio::piped());
let child = command.spawn()?;
Ok(child)
}
}
IO Handling
The launcher captures and processes stdout/stderr:
src-tauri/src/minecraft/java/runtime.rs
pub async fn handle_io<D: Send + Sync>(
&self,
running_task: &mut Child,
on_stdout: fn(&D, &[u8]) -> Result<()>,
on_stderr: fn(&D, &[u8]) -> Result<()>,
terminator: Receiver<()>,
data: &D,
) -> Result<()> {
let mut stdout = running_task.stdout.take().unwrap();
let mut stderr = running_task.stderr.take().unwrap();
loop {
tokio::select! {
read_len = stdout.read(&mut stdout_buf) => {
let _ = on_stdout(&data, &stdout_buf[..read_len?]);
},
read_len = stderr.read(&mut stderr_buf) => {
let _ = on_stderr(&data, &stderr_buf[..read_len?]);
},
_ = &mut terminator => {
running_task.kill().await?;
break;
},
exit_status = running_task.wait() => {
let code = exit_status?.code().unwrap_or(7900);
if code != 0 && code != -1073740791 {
bail!("Process exited with non-zero exit code: {}.", code);
}
break;
},
}
}
Ok(())
}
Version Support
Each distribution has different version support:
src-tauri/src/minecraft/java/distribution.rs
pub fn supports_version(&self, version: u32) -> bool {
match self {
JavaDistribution::Temurin => true, // Supports 8, 11, 17, 21
JavaDistribution::GraalVM => version >= 17, // Only supports 17+
JavaDistribution::Zulu => true, // Community builds for all LTS versions
}
}
If a build requires Java 8, GraalVM will automatically fall back to Temurin.
Custom Java Path
Advanced users can specify a custom Java installation:
src-tauri/src/app/options.rs
pub struct StartOptions {
pub java_distribution: DistributionSelection,
// ...
}
#[derive(Deserialize, Serialize, Clone)]
#[serde(tag = "type", content = "value")]
pub enum DistributionSelection {
#[serde(rename = "automatic")]
Automatic(String),
#[serde(rename = "custom")]
Custom(String),
#[serde(rename = "manual")]
Manual(JavaDistribution),
}
- Automatic: Launcher automatically selects the best distribution
- Manual: User chooses a specific distribution (Temurin, GraalVM, Zulu)
- Custom: User provides path to existing Java installation
Storage
Java runtimes are stored in the launcher’s data directory:
~/.liquidlauncher/runtimes/
├── temurin_8/
├── temurin_17/
├── temurin_21/
├── graalvm_17/
└── zulu_21/
Each runtime is isolated by distribution and version to prevent conflicts.
Version Selection
Each build specifies its required Java version
Auto-Updates
Java versions are updated with build updates