feat: osu! updating and launching does now work

This commit is contained in:
2025-07-03 22:10:38 +02:00
parent bd5eb97f6e
commit 807485a7f3
7 changed files with 200 additions and 46 deletions

View File

@@ -2,7 +2,9 @@
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "Capability for the main window",
"windows": ["main"],
"windows": [
"main"
],
"permissions": [
"core:default",
"shell:allow-open",
@@ -13,6 +15,8 @@
"core:window:allow-minimize",
"core:window:allow-close",
"cors-fetch:default",
"core:window:allow-hide",
"core:window:allow-show",
"fs:default",
{
"identifier": "fs:allow-write",
@@ -71,4 +75,4 @@
]
}
]
}
}

View File

@@ -7,9 +7,11 @@ use sysinfo::System;
use winreg::RegKey;
use winreg::enums::*;
use crate::utils::get_window_title_by_pid;
use crate::utils::set_osu_user_config_value;
use crate::utils::{check_folder_completeness, get_osu_config, get_osu_user_config};
use crate::utils::{
check_folder_completeness, get_osu_config, get_osu_user_config, get_window_title_by_pid,
set_osu_user_config_val, set_osu_config_val
};
use std::os::windows::process::CommandExt;
#[tauri::command]
pub fn get_hwid() -> String {
@@ -214,24 +216,44 @@ pub fn get_osu_release_stream(folder: String) -> String {
.unwrap_or_else(|| "Stable40".to_string());
}
#[tauri::command]
pub fn set_osu_user_config_value(
osu_folder_path: String,
key: String,
value: String,
) -> Result<bool, String> {
set_osu_user_config_val(&osu_folder_path, &key, &value)
}
#[tauri::command]
pub fn set_osu_config_value(
osu_folder_path: String,
key: String,
value: String,
) -> Result<bool, String> {
set_osu_user_config_value(&osu_folder_path, &key, &value)
set_osu_config_val(&osu_folder_path, &key, &value)
}
#[tauri::command]
pub fn run_osu_updater(folder: String) -> Result<(), String> {
let osu_exe_path = PathBuf::from(folder).join("osu!.exe");
let mut updater_process = Command::new(osu_exe_path)
.arg("-repair")
.spawn()
.map_err(|e| e.to_string())?;
#[cfg(windows)]
const DETACHED_PROCESS: u32 = 0x00000008;
#[cfg(windows)]
const CREATE_NEW_PROCESS_GROUP: u32 = 0x00000200;
#[cfg(windows)]
let mut updater_process = Command::new(osu_exe_path)
.arg("-repair")
.creation_flags(DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP)
.spawn()
.map_err(|e| e.to_string())?;
#[cfg(not(windows))]
let mut updater_process = Command::new(osu_exe_path)
.arg("-repair")
.spawn()
.map_err(|e| e.to_string())?;
thread::sleep(Duration::from_millis(500));
@@ -246,15 +268,8 @@ pub fn run_osu_updater(folder: String) -> Result<(), String> {
let process_id = process.pid();
let window_title = get_window_title_by_pid(process_id);
println!("updater_process id: {}", updater_process.id());
println!("process_id: {}", process_id.as_u32());
println!("found osu!.exe process with window title: {}", window_title);
if !window_title.is_empty() {
println!("Killing osu!.exe process");
if !window_title.is_empty() && !window_title.contains("updater") {
if let Ok(_) = process.kill_and_wait() {
println!("osu!.exe process killed");
termination_thread_running = false;
break;
}
@@ -265,6 +280,7 @@ pub fn run_osu_updater(folder: String) -> Result<(), String> {
if !termination_thread_running {
break;
}
sys.refresh_processes(sysinfo::ProcessesToUpdate::All, true);
thread::sleep(Duration::from_millis(500));
}
@@ -272,3 +288,18 @@ pub fn run_osu_updater(folder: String) -> Result<(), String> {
Ok(())
}
#[tauri::command]
pub fn run_osu(folder: String) -> Result<(), String> {
let osu_exe_path = PathBuf::from(folder).join("osu!.exe");
let mut game_process = Command::new(osu_exe_path)
.arg("-devserver")
.arg("ez-pp.farm")
.spawn()
.map_err(|e| e.to_string())?;
game_process.wait().map_err(|e| e.to_string())?;
Ok(())
}

View File

@@ -5,7 +5,8 @@ pub mod commands;
pub mod utils;
use crate::commands::{
find_osu_installation, get_beatmapsets_count, get_hwid, get_osu_release_stream,
get_osu_version, get_skins_count, run_osu_updater, set_osu_config_value, valid_osu_folder,
get_osu_version, get_skins_count, run_osu, run_osu_updater, set_osu_config_value,
set_osu_user_config_value, valid_osu_folder,
};
#[cfg_attr(mobile, tauri::mobile_entry_point)]
@@ -32,7 +33,9 @@ pub fn run() {
get_osu_version,
get_osu_release_stream,
set_osu_config_value,
run_osu_updater
set_osu_user_config_value,
run_osu_updater,
run_osu
])
.plugin(tauri_plugin_fs::init())
.plugin(tauri_plugin_dialog::init())

View File

@@ -2,9 +2,7 @@ use std::ffi::OsString;
use std::fs;
use std::os::windows::ffi::OsStringExt;
use std::path::Path;
use std::ptr;
use sysinfo::Pid;
use winapi::um::winuser::{FindWindowW, GetWindowTextW, GetWindowThreadProcessId};
pub fn check_folder_completeness<P: AsRef<Path>>(folder_path: P, required_files: &[&str]) -> f32 {
let mut found = 0;
@@ -48,7 +46,7 @@ pub fn get_osu_user_config<P: AsRef<Path>>(
return Some(config_map);
}
pub fn set_osu_user_config_value(
pub fn set_osu_user_config_val(
osu_folder_path: &str,
key: &str,
value: &str,
@@ -88,6 +86,45 @@ pub fn set_osu_user_config_value(
Ok(true)
}
pub fn set_osu_config_val(
osu_folder_path: &str,
key: &str,
value: &str,
) -> Result<bool, String> {
let osu_config_path = Path::new(osu_folder_path).join("osu!.cfg");
if !osu_config_path.exists() {
return Ok(false);
}
let mut lines = fs::read_to_string(&osu_config_path)
.map_err(|e| e.to_string())?
.lines()
.map(|line| line.to_string())
.collect::<Vec<String>>();
let mut found_key = false;
for line in lines.iter_mut() {
if let Some((existing_key, _)) = line.split_once(" = ") {
if existing_key.trim() == key {
*line = format!("{} = {}", key, value);
found_key = true;
break;
}
}
}
if !found_key {
lines.push(format!("{} = {}", key, value));
}
let new_content = lines.join("\n") + "\n";
fs::write(&osu_config_path, new_content).map_err(|e| e.to_string())?;
Ok(true)
}
pub fn get_osu_config<P: AsRef<Path>>(
osu_folder_path: P,
) -> Option<std::collections::HashMap<String, String>> {
@@ -113,26 +150,46 @@ pub fn get_osu_config<P: AsRef<Path>>(
}
pub fn get_window_title_by_pid(pid: Pid) -> String {
let mut window_title = String::new();
use std::sync::{Arc, Mutex};
use winapi::shared::windef::HWND;
use winapi::um::winuser::{
EnumWindows, GetWindowTextW, GetWindowThreadProcessId, IsWindowVisible,
};
unsafe {
let hwnd = FindWindowW(ptr::null_mut(), ptr::null_mut());
extern "system" fn enum_windows_proc(
hwnd: HWND,
lparam: winapi::shared::minwindef::LPARAM,
) -> i32 {
unsafe {
let data = &mut *(lparam as *mut (u32, Arc<Mutex<Option<String>>>));
let target_pid = data.0;
let result = &data.1;
if hwnd.is_null() {
return String::new();
}
let mut process_id = 0;
GetWindowThreadProcessId(hwnd, &mut process_id);
if process_id == pid.as_u32() {
let mut title = vec![0u16; 512];
let length = GetWindowTextW(hwnd, title.as_mut_ptr(), title.len() as i32);
let title = OsString::from_wide(&title[..length as usize]);
window_title = title.to_string_lossy().into_owned();
let mut window_pid = 0u32;
GetWindowThreadProcessId(hwnd, &mut window_pid);
if window_pid == target_pid && IsWindowVisible(hwnd) != 0 {
let mut title = vec![0u16; 512];
let length = GetWindowTextW(hwnd, title.as_mut_ptr(), title.len() as i32);
if length > 0 {
let title = OsString::from_wide(&title[..length as usize]);
let title_str = title.to_string_lossy().into_owned();
if !title_str.is_empty() {
*result.lock().unwrap() = Some(title_str);
return 0; // Stop enumeration
}
}
}
1 // Continue enumeration
}
}
window_title
let result = Arc::new(Mutex::new(None));
let mut data = (pid.as_u32(), Arc::clone(&result));
unsafe {
EnumWindows(
Some(enum_windows_proc),
&mut data as *mut _ as winapi::shared::minwindef::LPARAM,
);
}
result.lock().unwrap().clone().unwrap_or_default()
}