diff --git a/bun.lockb b/bun.lockb index 37bb343..3517be0 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 4012284..a1800aa 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "@heroui/react": "^2.7.5", "@icon-park/react": "^1.4.2", "@reactuses/core": "6.0.1", - "@supabase/ssr": "^0.5.2", + "@supabase/ssr": "0.6.1", "@tauri-apps/api": "2.1.0", "@tauri-apps/plugin-clipboard-manager": "2.0.0", "@tauri-apps/plugin-deep-link": "~2.2.0", @@ -43,7 +43,6 @@ "react-dom": "^19.0.0", "swr": "^2.3.3", "tauri-plugin-system-info-api": "^2.0.10", - "tauri-plugin-valtio": "1.1.2", "throttle-debounce": "^5.0.2", "zustand": "5.0.1" }, diff --git a/src-tauri/src/cmds.rs b/src-tauri/src/cmds.rs index d415fbd..237ba66 100644 --- a/src-tauri/src/cmds.rs +++ b/src-tauri/src/cmds.rs @@ -39,8 +39,8 @@ pub fn get_steam_path() -> Result { } #[tauri::command] -pub fn get_cs_path(name: &str) -> Result { - wrap_err!(steam::path::get_cs_path(name)) +pub fn get_cs_path(name: &str, steam_dir: &str) -> Result { + wrap_err!(steam::path::get_cs_path(name, steam_dir)) } #[tauri::command] diff --git a/src-tauri/src/steam/path.rs b/src-tauri/src/steam/path.rs index f666caf..ad44004 100644 --- a/src-tauri/src/steam/path.rs +++ b/src-tauri/src/steam/path.rs @@ -3,35 +3,102 @@ // - CS2(CS:GO) Path #![allow(unused)] -use anyhow::Result; +use std::fs::{self, exists}; +use std::path::{Path, PathBuf}; + use crate::tool::common::get_exe_path; +use anyhow::Result; use super::reg; - pub fn get_steam_path() -> Result { + // Running steam.exe + #[cfg(target_os = "windows")] + if let Ok(steam_path) = get_exe_path("steam") { + // 去除结尾的 steam.exe 不区分大小写 + if let Some(parent_path) = Path::new(&steam_path).parent() { + return Ok(parent_path.to_string_lossy().to_string()); + } else { + return Err("Failed to get parent directory".into()); + } + } + // Windows Registry #[cfg(target_os = "windows")] if let Ok(reg) = reg::SteamReg::get_all() { return Ok(reg.steam_path); } - // Running steam.exe - #[cfg(target_os = "windows")] - if let Ok(steam_path) = get_exe_path("steam.exe") { - return Ok(steam_path); - } - Err("no steam path found".into()) } -pub fn get_cs_path(name: &str) -> Result { +pub fn get_cs_path(name: &str, steam_dir: &str) -> Result { if name != "csgo" && name != "cs2" { return Err("invalid cs name".into()); } + // 1. 优先检查 steam_dir 参数 + let steam_path = if steam_dir.is_empty() || !Path::new(steam_dir).exists() { + // 如果 steam_dir 不满足条件,调用 get_steam_path 获取路径 + let p = get_steam_path().map_err(|e| e.to_string())?; + PathBuf::from(p) + } else { + PathBuf::from(steam_dir) // 同样转换为PathBuf + }; + + let cs_path = steam_path + .join("steamapps\\common\\Counter-Strike Global Offensive\\game\\bin\\win64\\cs2.exe"); + if cs_path.exists() { + if let Some(parent) = cs_path.parent() { + return Ok(parent.to_string_lossy().to_string()); + } + } + + // 2. 通过注册表读取所有磁盘盘符 #[cfg(target_os = "windows")] - if let Ok(cs_path) = get_exe_path(&(name.to_owned() + ".exe")) { - return Ok(cs_path); + { + use winreg::enums::HKEY_LOCAL_MACHINE; + use winreg::RegKey; + + let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); + let mounted_devices = hklm + .open_subkey("SYSTEM\\MountedDevices") + .map_err(|e| e.to_string())?; + + // 获取所有盘符 + let drives: Vec = mounted_devices + .enum_values() + .filter_map(|v| { + let (name, _) = v.ok()?; + let name = name.to_string(); + if name.starts_with("\\DosDevices\\") { + Some(name.replace("\\DosDevices\\", "")) + } else { + None + } + }) + .collect(); + + // 遍历盘符,尝试查找 cs2.exe + let cs_path_suffix = "SteamLibrary\\steamapps\\common\\Counter-Strike Global Offensive\\game\\bin\\win64\\cs2.exe"; + for drive in drives { + let cs_path = Path::new(&drive).join(cs_path_suffix); + if cs_path.exists() { + if let Some(parent) = cs_path.parent() { + return Ok(parent.to_string_lossy().to_string()); + } + } + } + } + + // 3. 查找正在运行的cs2进程 + #[cfg(target_os = "windows")] + if let Ok(cs2_path) = get_exe_path("cs2") { + // 去除结尾的 steam.exe 不区分大小写 + if let Some(parent_path) = Path::new(&cs2_path).parent() { + return Ok(parent_path.to_string_lossy().to_string()); + } else { + return Err("Failed to get parent directory".into()); + } } Err("no cs path found".into()) @@ -46,4 +113,17 @@ mod tests { let path = get_steam_path().unwrap(); println!("{}", path); } + + #[test] + fn test_get_cs_path() { + let result = get_cs_path("cs2", ""); + assert!(result.is_ok() || result.is_err()); + println!("CS2 Path: {:?}", result); + + // 使用get_steam_path给到的路径 + let steam_dir = get_steam_path().unwrap(); + let result = get_cs_path("cs2", &steam_dir); + assert!(result.is_ok() || result.is_err()); + println!("CS2 Path: {:?}", result) + } } diff --git a/src-tauri/src/tool/common.rs b/src-tauri/src/tool/common.rs index 3019caa..aa9854c 100644 --- a/src-tauri/src/tool/common.rs +++ b/src-tauri/src/tool/common.rs @@ -1,5 +1,5 @@ -use std::process::Command; use std::os::windows::process::CommandExt; +use std::process::Command; const CREATE_NO_WINDOW: u32 = 0x08000000; // const DETACHED_PROCESS: u32 = 0x00000008; @@ -21,18 +21,29 @@ pub fn run_steam() -> std::io::Result { .output() } -// FIXME wmic is deprecated + pub fn get_exe_path(name: &str) -> Result { - let command = format!("/C wmic process where name='{}' get ExecutablePath", name); + // [原理] + // Powershell 运行 Get-Process name | Select-Object path + // 有name.exe运行时返回 + // Path + // ---- + // 进程路径 + let command = format!("Get-Process {} | Select-Object path", name); let args = command.split_whitespace().collect::>(); - let output = Command::new("cmd.exe").args(&args).output()?; + let output = Command::new("powershell.exe") + .args(&args) + .creation_flags(CREATE_NO_WINDOW) + .output()?; - let out = String::from_utf8_lossy(&output.stdout).trim().to_string(); + let out = String::from_utf8_lossy(&output.stdout).to_string(); - if out.contains("ExecutablePath") { + if out.contains("Path") { + let out = out.trim(); let spt: Vec<&str> = out.split("\r\n").collect(); - if spt.len() >= 2 { - return Ok(spt[1].to_string()); + + if spt.len() > 2 { + return Ok(spt[2].to_string()); } } Err(std::io::Error::new( @@ -68,4 +79,12 @@ mod tests { println!("test open path: {}", path); open_path(path).unwrap() } + + #[test] + fn test_get_exe_path() { + let path = get_exe_path("steam").expect("failed"); + println!("test get steam path: {}", path); + + get_exe_path("not_running").expect("failed"); + } } diff --git a/src/app/(main)/users/layout.tsx b/src/app/(main)/users/layout.tsx index 80eea61..d68f9e3 100644 --- a/src/app/(main)/users/layout.tsx +++ b/src/app/(main)/users/layout.tsx @@ -1,26 +1,13 @@ "use client" import SteamUsers from "@/components/cstb/SteamUsers" -import { - Card, - CardBody, - CardHeader, - CardIcon, - CardTool, -} from "@/components/window/Card" -import { ToolButton } from "@/components/window/ToolButton" -import { cn } from "@heroui/react" -import { - AssemblyLine, HardDisk, SettingConfig, - UploadOne -} from "@icon-park/react" -import { usePathname, useRouter } from "next/navigation" +// import { usePathname, useRouter } from "next/navigation" // import { platform } from "@tauri-apps/plugin-os" export default function PreferenceLayout({ children, }: { children: React.ReactNode }) { - const router = useRouter() - const pathname = usePathname() + // const router = useRouter() + // const pathname = usePathname() return (
diff --git a/src/app/providers.tsx b/src/app/providers.tsx index b368237..85f5ec8 100644 --- a/src/app/providers.tsx +++ b/src/app/providers.tsx @@ -13,13 +13,10 @@ export default function Providers({ children }: { children: React.ReactNode }) { return ( - + {children} diff --git a/src/components/cstb/CommonDir.tsx b/src/components/cstb/CommonDir.tsx index a31167a..3afe97d 100644 --- a/src/components/cstb/CommonDir.tsx +++ b/src/components/cstb/CommonDir.tsx @@ -2,7 +2,6 @@ import { addToast } from "@heroui/react" import { FolderFocusOne } from "@icon-park/react" import { Card, CardBody, CardHeader, CardIcon } from "../window/Card" import { invoke } from "@tauri-apps/api/core" -import { configDir } from "@tauri-apps/api/path" import { useSteamStore } from "@/store/steam" import path from "path" @@ -17,7 +16,7 @@ const RoundedButton = ({ return (
@@ -160,10 +170,16 @@ export function Prepare() { steam.setCsDir(value) }} description="cs2.exe所在文件夹" - errorMessage={"路径无效"} + errorMessage={"路径无效,建议启动游戏后点击自动获取,可以检测运行中的cs2"} isInvalid={!steam.state.cs2DirValid} /> - @@ -175,16 +191,19 @@ export function Prepare() { onPress={() => void autoGetPaths()} variant="ghost" color="default" - size="sm" + size="md" className="w-24" > 自动获取 @@ -64,6 +67,8 @@ const Nav = () => { {theme === "light" ? : } + + {/* { platform() === "windows" && ( */} <>