feat: add .net 8 detection for experimental patcher stream

This commit is contained in:
2025-07-15 19:38:00 +02:00
parent 4fb2ab7bed
commit 4e1f76a713
6 changed files with 72 additions and 22 deletions

View File

@@ -14,7 +14,8 @@ use tokio::time::{Duration, sleep};
use crate::presence; use crate::presence;
use crate::utils::{ use crate::utils::{
check_folder_completeness, get_osu_config, get_osu_user_config, get_window_title_by_pid, check_folder_completeness, get_osu_config, get_osu_user_config, get_window_title_by_pid,
set_osu_config_vals, set_osu_user_config_vals, is_wmctrl_available, is_osuwinello_available is_net8_installed, is_osuwinello_available, is_wmctrl_available, set_osu_config_vals,
set_osu_user_config_vals,
}; };
#[tauri::command] #[tauri::command]
@@ -336,10 +337,8 @@ pub async fn run_osu_updater(folder: String) -> Result<(), String> {
sleep(Duration::from_millis(500)).await; sleep(Duration::from_millis(500)).await;
} }
// Wait for updater process to fully exit
let _ = updater_process.wait().await; let _ = updater_process.wait().await;
// Clean up update-related files
let force_update_files = [".require_update", "help.txt", "_pending"]; let force_update_files = [".require_update", "help.txt", "_pending"];
for update_file_name in &force_update_files { for update_file_name in &force_update_files {
let path = PathBuf::from(&folder).join(update_file_name); let path = PathBuf::from(&folder).join(update_file_name);
@@ -435,7 +434,7 @@ pub struct UpdateFile {
pub async fn get_ezpp_launcher_update_files( pub async fn get_ezpp_launcher_update_files(
folder: String, folder: String,
update_url: String, update_url: String,
update_stream: String update_stream: String,
) -> Result<(Vec<UpdateFile>, Vec<UpdateFile>), String> { ) -> Result<(Vec<UpdateFile>, Vec<UpdateFile>), String> {
let osu_path = PathBuf::from(folder); let osu_path = PathBuf::from(folder);
let client = Client::new(); let client = Client::new();
@@ -536,7 +535,6 @@ pub async fn download_ezpp_launcher_update_files(
.await .await
.map_err(|e| e.to_string())?; .map_err(|e| e.to_string())?;
// Emit progress to frontend
app.emit( app.emit(
"download-progress", "download-progress",
UpdateStatus { UpdateStatus {
@@ -716,3 +714,8 @@ pub fn has_wmctrl() -> bool {
pub fn has_osuwinello() -> bool { pub fn has_osuwinello() -> bool {
is_osuwinello_available() is_osuwinello_available()
} }
#[tauri::command]
pub async fn has_net8() -> bool {
is_net8_installed().await
}

View File

@@ -10,7 +10,8 @@ use crate::commands::{
get_osu_release_stream, get_osu_skin, get_osu_version, get_platform, get_skins_count, get_osu_release_stream, get_osu_skin, get_osu_version, get_platform, get_skins_count,
is_osu_running, open_url_in_browser, presence_connect, presence_disconnect, is_osu_running, open_url_in_browser, presence_connect, presence_disconnect,
presence_is_connected, presence_update_status, presence_update_user, replace_ui_files, run_osu, presence_is_connected, presence_update_status, presence_update_user, replace_ui_files, run_osu,
run_osu_updater, set_osu_config_values, set_osu_user_config_values, valid_osu_folder, has_osuwinello, has_wmctrl run_osu_updater, set_osu_config_values, set_osu_user_config_values, valid_osu_folder, has_osuwinello, has_wmctrl,
has_net8
}; };
#[cfg_attr(mobile, tauri::mobile_entry_point)] #[cfg_attr(mobile, tauri::mobile_entry_point)]
@@ -62,7 +63,8 @@ pub fn run() {
presence_update_user, presence_update_user,
presence_is_connected, presence_is_connected,
has_osuwinello, has_osuwinello,
has_wmctrl has_wmctrl,
has_net8
]) ])
.plugin(tauri_plugin_fs::init()) .plugin(tauri_plugin_fs::init())
.plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_dialog::init())

View File

@@ -239,13 +239,13 @@ pub fn get_window_title_by_pid(target_pid: Pid) -> String {
#[cfg(windows)] #[cfg(windows)]
pub fn get_window_title_by_pid(pid: Pid) -> String { pub fn get_window_title_by_pid(pid: Pid) -> String {
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use winapi::shared::windef::HWND; use winapi::shared::windef::HWND;
use winapi::um::winuser::{ use winapi::um::winuser::{
EnumWindows, GetWindowTextW, GetWindowThreadProcessId, IsWindowVisible, EnumWindows, GetWindowTextW, GetWindowThreadProcessId, IsWindowVisible,
}; };
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
extern "system" fn enum_windows_proc( extern "system" fn enum_windows_proc(
hwnd: HWND, hwnd: HWND,
@@ -266,7 +266,7 @@ pub fn get_window_title_by_pid(pid: Pid) -> String {
let title_str = title.to_string_lossy().into_owned(); let title_str = title.to_string_lossy().into_owned();
if !title_str.is_empty() { if !title_str.is_empty() {
*result.lock().unwrap() = Some(title_str); *result.lock().unwrap() = Some(title_str);
return 0 return 0;
} }
} }
} }
@@ -284,3 +284,26 @@ pub fn get_window_title_by_pid(pid: Pid) -> String {
} }
result.lock().unwrap().clone().unwrap_or_default() result.lock().unwrap().clone().unwrap_or_default()
} }
pub async fn is_net8_installed() -> bool {
use std::process::Command;
let output_result = Command::new("dotnet").arg("--list-runtimes").output();
match output_result {
Ok(output) => {
if !output.status.success() {
eprintln!(
"Error: `dotnet --list-runtimes` failed with status: {}",
output.status
);
eprintln!("stderr: {}", String::from_utf8_lossy(&output.stderr));
return false;
}
let stdout_str = String::from_utf8_lossy(&output.stdout);
stdout_str
.lines()
.any(|line| line.starts_with("Microsoft.WindowsDesktop.App 8."))
}
Err(_) => false,
}
}

View File

@@ -1,7 +1,7 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "ezpplauncher", "productName": "ezpplauncher",
"version": "3.0.0-beta.2", "version": "3.0.0-beta.5",
"identifier": "farm.ezpp.launcher", "identifier": "farm.ezpp.launcher",
"build": { "build": {
"beforeDevCommand": "bun run vite:dev", "beforeDevCommand": "bun run vite:dev",

View File

@@ -137,3 +137,5 @@ export const hasWMCTRL = async () =>
await invoke<boolean>('has_wmctrl'); await invoke<boolean>('has_wmctrl');
export const hasOsuWinello = async () => export const hasOsuWinello = async () =>
await invoke<boolean>('has_osuwinello'); await invoke<boolean>('has_osuwinello');
export const hasNet8 = async () =>
await invoke<boolean>('has_net8');

View File

@@ -90,6 +90,7 @@
getSkin, getSkin,
getSkinsCount, getSkinsCount,
getVersion, getVersion,
hasNet8,
hasOsuWinello, hasOsuWinello,
hasWMCTRL, hasWMCTRL,
isOsuCorrupted, isOsuCorrupted,
@@ -189,20 +190,20 @@
return; return;
} }
if($platform === "linux"){ if ($platform === 'linux') {
if(!(await hasWMCTRL())){ if (!(await hasWMCTRL())) {
toast.error('Hmmm...', { toast.error('Hmmm...', {
description: 'wmctrl seems to be missing, please install via AUR.', description: 'wmctrl seems to be missing, please install via AUR.',
}); });
launching.set(false); launching.set(false);
return; return;
} }
if(!(await hasOsuWinello())){ if (!(await hasOsuWinello())) {
toast.error('Hmmm...', { toast.error('Hmmm...', {
description: 'osu-winello seems to be missing, please install it.', description: 'osu-winello seems to be missing, please install it.',
}); });
launching.set(false); launching.set(false);
return; return;
} }
} }
@@ -1050,12 +1051,18 @@
> >
<div class="flex flex-col"> <div class="flex flex-col">
<Label class="text-sm" for="setting-custom-cursor">Patching</Label> <Label class="text-sm" for="setting-custom-cursor">Patching</Label>
<div class="text-muted-foreground text-xs">Shows misses in Relax and Autopilot {#if $platform !== "windows"}<span class="text-red-500 bg-red-800/20 border border-red-600/20 p-0.5 mx-1 px-2 rounded-lg">currently only on windows!</span> {/if}</div> <div class="text-muted-foreground text-xs">
Shows misses in Relax and Autopilot {#if $platform !== 'windows'}<span
class="text-red-500 bg-red-800/20 border border-red-600/20 p-0.5 mx-1 px-2 rounded-lg"
>currently only on windows!</span
>
{/if}
</div>
</div> </div>
<Checkbox <Checkbox
id="setting-custom-cursor" id="setting-custom-cursor"
checked={$platform === "windows" ? $patch : false} checked={$platform === 'windows' ? $patch : false}
disabled={$platform !== "windows"} disabled={$platform !== 'windows'}
onCheckedChange={async (e) => { onCheckedChange={async (e) => {
patch.set(e); patch.set(e);
$userSettings.save(); $userSettings.save();
@@ -1168,8 +1175,21 @@
<div class="flex flex-row w-full"> <div class="flex flex-row w-full">
<Select.Root <Select.Root
type="single" type="single"
value={$launcherStream} bind:value={$launcherStream}
onValueChange={async (newStream) => { onValueChange={async (newStream) => {
if (newStream === 'experimental' && (await hasNet8())) {
launcherStream.set('stable');
toast.error('.NET 8.0 Desktop Runtime not found!', {
action: {
label: 'Download .NET 8.0',
onClick: async () =>
await openURL(
'https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-8.0.18-windows-x64-installer'
),
},
});
return;
}
$userSettings.value('patcherStream').set(newStream); $userSettings.value('patcherStream').set(newStream);
launcherStream.set(newStream); launcherStream.set(newStream);
await $userSettings.save(); await $userSettings.save();