mirror of
https://github.com/LCE-Hub/LCE-Emerald-Launcher.git
synced 2026-08-20 04:27:29 +00:00
feat: Intel macOS Support!
This commit is contained in:
parent
a844ebb12a
commit
e3be6078ff
|
|
@ -201,9 +201,15 @@ async fn launch_game_desktop(
|
|||
let gptk_no_hud = macos::find_executable_recursive(&toolkit_dir, "gameportingtoolkit-no-hud")
|
||||
.or_else(|| macos::find_executable_recursive(&toolkit_dir, "gameportingtoolkit"));
|
||||
|
||||
let wine_binary = macos::find_executable_recursive(&toolkit_dir, "wine64")
|
||||
.or_else(|| macos::find_executable_recursive(&toolkit_dir, "wine"))
|
||||
.ok_or_else(|| "Unable to locate wine binary inside runtime.".to_string())?;
|
||||
let is_intel = std::env::consts::ARCH == "x86_64";
|
||||
let wine_binary = if is_intel {
|
||||
macos::find_executable_recursive(&toolkit_dir, "wine")
|
||||
.or_else(|| macos::find_executable_recursive(&toolkit_dir, "wine64"))
|
||||
} else {
|
||||
macos::find_executable_recursive(&toolkit_dir, "wine64")
|
||||
.or_else(|| macos::find_executable_recursive(&toolkit_dir, "wine"))
|
||||
}
|
||||
.ok_or_else(|| "Unable to locate wine binary inside runtime.".to_string())?;
|
||||
|
||||
let wine_bin_dir = wine_binary
|
||||
.parent()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
//neo: TODO: Intel macOS support
|
||||
|
||||
//neo: thanks Huckle for the Intel macOS support reference code lol
|
||||
use tauri::AppHandle;
|
||||
#[cfg(target_os = "macos")]
|
||||
use std::io::Write;
|
||||
|
|
@ -57,6 +56,14 @@ pub async fn setup_macos_runtime(window: tauri::Window, app: AppHandle) -> Resul
|
|||
assets: Vec<GithubAsset>,
|
||||
}
|
||||
|
||||
let is_intel = std::env::consts::ARCH == "x86_64";
|
||||
|
||||
let repo = if is_intel {
|
||||
"Gcenx/macOS_Wine_builds"
|
||||
} else {
|
||||
"Gcenx/game-porting-toolkit"
|
||||
};
|
||||
|
||||
macos::emit_macos_setup_progress(
|
||||
&window,
|
||||
"resolving",
|
||||
|
|
@ -66,7 +73,7 @@ pub async fn setup_macos_runtime(window: tauri::Window, app: AppHandle) -> Resul
|
|||
|
||||
let client = reqwest::Client::new();
|
||||
let release_text = client
|
||||
.get("https://api.github.com/repos/Gcenx/game-porting-toolkit/releases/latest")
|
||||
.get(format!("https://api.github.com/repos/{}/releases/latest", repo))
|
||||
.header("User-Agent", "Emerald-Legacy-Launcher")
|
||||
.send()
|
||||
.await
|
||||
|
|
@ -82,7 +89,15 @@ pub async fn setup_macos_runtime(window: tauri::Window, app: AppHandle) -> Resul
|
|||
let asset = release
|
||||
.assets
|
||||
.iter()
|
||||
.find(|a| a.name.ends_with(".tar.xz") || a.name.ends_with(".tar.gz"))
|
||||
.find(|a| {
|
||||
let is_archive =
|
||||
a.name.ends_with(".tar.xz") || a.name.ends_with(".tar.gz");
|
||||
if is_intel {
|
||||
is_archive && a.name.contains("staging")
|
||||
} else {
|
||||
is_archive
|
||||
}
|
||||
})
|
||||
.ok_or_else(|| "No compatible runtime asset found in latest release.".to_string())?;
|
||||
|
||||
let runtime_dir = macos::get_macos_runtime_dir(&app);
|
||||
|
|
@ -173,9 +188,14 @@ pub async fn setup_macos_runtime(window: tauri::Window, app: AppHandle) -> Resul
|
|||
}
|
||||
|
||||
fs::create_dir_all(&prefix_dir).map_err(|e| e.to_string())?;
|
||||
let wine_binary = macos::find_executable_recursive(&toolkit_dir, "wine64")
|
||||
.or_else(|| macos::find_executable_recursive(&toolkit_dir, "wine"))
|
||||
.ok_or_else(|| "Unable to locate wine binary inside runtime.".to_string())?;
|
||||
let wine_binary = if is_intel {
|
||||
macos::find_executable_recursive(&toolkit_dir, "wine")
|
||||
.or_else(|| macos::find_executable_recursive(&toolkit_dir, "wine64"))
|
||||
} else {
|
||||
macos::find_executable_recursive(&toolkit_dir, "wine64")
|
||||
.or_else(|| macos::find_executable_recursive(&toolkit_dir, "wine"))
|
||||
}
|
||||
.ok_or_else(|| "Unable to locate wine binary inside runtime.".to_string())?;
|
||||
|
||||
let wine_bin_dir = wine_binary
|
||||
.parent()
|
||||
|
|
@ -215,6 +235,181 @@ pub async fn setup_macos_runtime(window: tauri::Window, app: AppHandle) -> Resul
|
|||
return Err("Wine prefix initialization failed".into());
|
||||
}
|
||||
|
||||
if is_intel {
|
||||
macos::emit_macos_setup_progress(
|
||||
&window,
|
||||
"dxvk",
|
||||
"Fetching latest DXVK…".into(),
|
||||
None,
|
||||
);
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct DxvkAsset {
|
||||
name: String,
|
||||
browser_download_url: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct DxvkRelease {
|
||||
assets: Vec<DxvkAsset>,
|
||||
}
|
||||
|
||||
let dxvk_release_text = client
|
||||
.get("https://api.github.com/repos/Gcenx/DXVK-macOS/releases/latest")
|
||||
.header("User-Agent", "Emerald-Legacy-Launcher")
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| e.to_string())?
|
||||
.error_for_status()
|
||||
.map_err(|e| e.to_string())?
|
||||
.text()
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let dxvk_release: DxvkRelease =
|
||||
serde_json::from_str(&dxvk_release_text).map_err(|e| e.to_string())?;
|
||||
let dxvk_asset = dxvk_release
|
||||
.assets
|
||||
.iter()
|
||||
.find(|a| {
|
||||
let is_archive =
|
||||
a.name.ends_with(".tar.xz") || a.name.ends_with(".tar.gz");
|
||||
is_archive && !a.name.contains("builtin")
|
||||
})
|
||||
.ok_or_else(|| "No compatible DXVK asset found.".to_string())?;
|
||||
|
||||
macos::emit_macos_setup_progress(
|
||||
&window,
|
||||
"dxvk_downloading",
|
||||
"Downloading DXVK…".into(),
|
||||
Some(0.0),
|
||||
);
|
||||
|
||||
let dxvk_archive_path = runtime_dir.join(format!("dxvk_{}", dxvk_asset.name));
|
||||
let dxvk_response = client
|
||||
.get(&dxvk_asset.browser_download_url)
|
||||
.header("User-Agent", "Emerald-Legacy-Launcher")
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| e.to_string())?
|
||||
.error_for_status()
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let dxvk_total = dxvk_response.content_length().unwrap_or(0) as f64;
|
||||
let mut dxvk_file = fs::File::create(&dxvk_archive_path).map_err(|e| e.to_string())?;
|
||||
let mut dxvk_downloaded = 0.0;
|
||||
let mut dxvk_last_percent: i64 = -1;
|
||||
let mut dxvk_stream = dxvk_response.bytes_stream();
|
||||
while let Some(chunk) = dxvk_stream.next().await {
|
||||
let chunk = chunk.map_err(|e| e.to_string())?;
|
||||
dxvk_file.write_all(&chunk).map_err(|e| e.to_string())?;
|
||||
dxvk_downloaded += chunk.len() as f64;
|
||||
if dxvk_total > 0.0 {
|
||||
let percent = (dxvk_downloaded / dxvk_total * 100.0).clamp(0.0, 100.0);
|
||||
let rounded = percent.floor() as i64;
|
||||
if rounded != dxvk_last_percent {
|
||||
dxvk_last_percent = rounded;
|
||||
macos::emit_macos_setup_progress(
|
||||
&window,
|
||||
"dxvk_downloading",
|
||||
format!("Downloading DXVK… {}%", rounded),
|
||||
Some(percent),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
drop(dxvk_file);
|
||||
macos::emit_macos_setup_progress(
|
||||
&window,
|
||||
"dxvk_extracting",
|
||||
"Extracting DXVK…".into(),
|
||||
None,
|
||||
);
|
||||
|
||||
let dxvk_dir = runtime_dir.join("dxvk");
|
||||
fs::create_dir_all(&dxvk_dir).map_err(|e| e.to_string())?;
|
||||
let status = Command::new("tar")
|
||||
.args([
|
||||
"-xf",
|
||||
dxvk_archive_path
|
||||
.to_str()
|
||||
.ok_or_else(|| "Invalid DXVK archive path".to_string())?,
|
||||
"-C",
|
||||
dxvk_dir
|
||||
.to_str()
|
||||
.ok_or_else(|| "Invalid DXVK extraction path".to_string())?,
|
||||
])
|
||||
.stdin(Stdio::null())
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::piped())
|
||||
.status()
|
||||
.map_err(|e| e.to_string())?;
|
||||
let _ = fs::remove_file(&dxvk_archive_path);
|
||||
if !status.success() {
|
||||
return Err(format!("DXVK extraction failed with status: {:?}", status));
|
||||
}
|
||||
|
||||
macos::emit_macos_setup_progress(
|
||||
&window,
|
||||
"dxvk_patching",
|
||||
"Patching runtime with DXVK…".into(),
|
||||
None,
|
||||
);
|
||||
|
||||
let system32 = prefix_dir.join("drive_c/windows/system32");
|
||||
let syswow64 = prefix_dir.join("drive_c/windows/syswow64");
|
||||
let _ = fs::create_dir_all(&system32);
|
||||
let _ = fs::create_dir_all(&syswow64);
|
||||
let copy_dir = |src_dir: &std::path::Path, dst_dir: &std::path::Path| -> Result<(), String> {
|
||||
if !src_dir.exists() {
|
||||
return Ok(());
|
||||
}
|
||||
for entry in fs::read_dir(src_dir).map_err(|e| e.to_string())? {
|
||||
let entry = entry.map_err(|e| e.to_string())?;
|
||||
let path = entry.path();
|
||||
if path.extension().and_then(|e| e.to_str()) == Some("dll") {
|
||||
let dest = dst_dir.join(path.file_name().unwrap());
|
||||
fs::copy(&path, &dest).map_err(|e| e.to_string())?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
|
||||
let dxvk_x64 = dxvk_dir.join("x64");
|
||||
let dxvk_x32 = dxvk_dir.join("x32");
|
||||
copy_dir(&dxvk_x64, &system32)?;
|
||||
copy_dir(&dxvk_x32, &syswow64)?;
|
||||
for dll_name in &["d3d11", "dxgi"] {
|
||||
let mut reg_cmd = Command::new(&wine_binary);
|
||||
reg_cmd
|
||||
.args(["reg", "add", "HKCU\\Software\\Wine\\DllOverrides"])
|
||||
.arg("/v")
|
||||
.arg(dll_name)
|
||||
.arg("/t")
|
||||
.arg("REG_SZ")
|
||||
.arg("/d")
|
||||
.arg("native,builtin")
|
||||
.arg("/f");
|
||||
reg_cmd
|
||||
.env("WINEPREFIX", &prefix_dir)
|
||||
.env("WINEDEBUG", "-all")
|
||||
.env(
|
||||
"PATH",
|
||||
format!(
|
||||
"{}:{}",
|
||||
wine_bin_dir.to_string_lossy(),
|
||||
std::env::var("PATH").unwrap_or_default()
|
||||
),
|
||||
)
|
||||
.stdin(Stdio::null())
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null());
|
||||
let _ = reg_cmd.status();
|
||||
}
|
||||
|
||||
let _ = fs::remove_dir_all(&dxvk_dir);
|
||||
}
|
||||
|
||||
macos::emit_macos_setup_progress(&window, "done", "Setup complete.".into(), Some(100.0));
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,9 @@ pub fn is_macos_runtime_installed(app: &AppHandle) -> bool {
|
|||
if !toolkit_dir.exists() {
|
||||
return false;
|
||||
}
|
||||
let candidates = ["Game Porting Toolkit.app"];
|
||||
candidates.iter().any(|name| find_executable_recursive(&toolkit_dir, name).is_some())
|
||||
if find_executable_recursive(&toolkit_dir, "Game Porting Toolkit.app").is_some() {
|
||||
return true;
|
||||
}
|
||||
find_executable_recursive(&toolkit_dir, "wine").is_some()
|
||||
|| find_executable_recursive(&toolkit_dir, "wine64").is_some()
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue