diff --git a/next-env.d.ts b/next-env.d.ts
index 9edff1c..c4b7818 100644
--- a/next-env.d.ts
+++ b/next-env.d.ts
@@ -1,6 +1,6 @@
///
///
-import "./.next/types/routes.d.ts";
+import "./.next/dev/types/routes.d.ts";
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
diff --git a/src-tauri/src/cmds.rs b/src-tauri/src/cmds.rs
index 75d60ce..0c4e8a8 100644
--- a/src-tauri/src/cmds.rs
+++ b/src-tauri/src/cmds.rs
@@ -64,8 +64,8 @@ pub fn kill_game() -> Result {
}
#[tauri::command]
-pub fn check_process_running(process_name: &str) -> Result {
- Ok(common::check_process_running(process_name))
+pub async fn check_process_running(process_name: &str) -> Result {
+ Ok(common::check_process_running_async(process_name).await)
}
#[tauri::command]
diff --git a/src-tauri/src/tool/common.rs b/src-tauri/src/tool/common.rs
index 84ddc96..f5af0ee 100644
--- a/src-tauri/src/tool/common.rs
+++ b/src-tauri/src/tool/common.rs
@@ -120,6 +120,41 @@ pub fn check_process_running(name: &str) -> bool {
}
}
+// 异步版本的进程检测函数
+pub async fn check_process_running_async(name: &str) -> bool {
+ use tokio::process::Command;
+
+ // 使用tasklist命令检查进程是否存在
+ #[cfg(windows)]
+ {
+ let mut cmd = Command::new("tasklist");
+ cmd.args(&["/FI", &format!("IMAGENAME eq {}", name)]);
+ cmd.creation_flags(CREATE_NO_WINDOW);
+
+ match cmd.output().await {
+ Ok(output) => {
+ let stdout = String::from_utf8_lossy(&output.stdout);
+ // 检查输出中是否包含进程名(排除表头)
+ stdout.contains(name) && stdout.contains("exe")
+ }
+ Err(_) => false,
+ }
+ }
+
+ #[cfg(not(windows))]
+ {
+ // 对于非Windows系统,可以使用pgrep命令
+ let mut cmd = Command::new("pgrep");
+ cmd.arg("-f");
+ cmd.arg(name);
+
+ match cmd.output().await {
+ Ok(output) => !output.stdout.is_empty(),
+ Err(_) => false,
+ }
+ }
+}
+
mod tests {
#[test]
fn test_open_path() {
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
index 7543a60..13496da 100644
--- a/src-tauri/tauri.conf.json
+++ b/src-tauri/tauri.conf.json
@@ -52,7 +52,7 @@
},
"productName": "CS工具箱",
"mainBinaryName": "cstb",
- "version": "0.0.6-beta.9",
+ "version": "0.0.6-beta.8",
"identifier": "upup.cool",
"plugins": {
"deep-link": {
diff --git a/src/components/cstb/FpsTest/hooks/useGameMonitor.ts b/src/components/cstb/FpsTest/hooks/useGameMonitor.ts
index 8ee5b5a..3d6fe10 100644
--- a/src/components/cstb/FpsTest/hooks/useGameMonitor.ts
+++ b/src/components/cstb/FpsTest/hooks/useGameMonitor.ts
@@ -1,32 +1,3 @@
-import { useState, useEffect, useCallback } from "react"
-import { invoke } from "@tauri-apps/api/core"
-
-export function useGameMonitor() {
- const [isGameRunning, setIsGameRunning] = useState(false)
-
- // 检测游戏是否运行
- const checkGameRunning = useCallback(async () => {
- try {
- const result = await invoke("check_process_running", {
- processName: "cs2.exe",
- }).catch(() => false)
- setIsGameRunning(result)
- return result
- } catch {
- setIsGameRunning(false)
- return false
- }
- }, [])
-
- // 定期检测游戏运行状态
- useEffect(() => {
- void checkGameRunning()
- const interval = setInterval(() => {
- void checkGameRunning()
- }, 3000)
- return () => clearInterval(interval)
- }, [checkGameRunning])
-
- return { isGameRunning, checkGameRunning }
-}
+// 使用全局游戏状态监控,避免重复检测
+export { useGlobalGameMonitor as useGameMonitor } from "@/hooks/useGlobalGameMonitor"
diff --git a/src/components/cstb/UpdateChecker.tsx b/src/components/cstb/UpdateChecker.tsx
index ba0a07e..048c60c 100644
--- a/src/components/cstb/UpdateChecker.tsx
+++ b/src/components/cstb/UpdateChecker.tsx
@@ -16,15 +16,9 @@ import { invoke } from "@tauri-apps/api/core"
import { listen } from "@tauri-apps/api/event"
import { relaunch } from "@tauri-apps/plugin-process"
import { addToast } from "@heroui/react"
-import { useAppStore } from "@/store/app"
+import { useAppStore, type UpdateInfo } from "@/store/app"
import { MarkdownRender } from "@/components/markdown"
-interface UpdateInfo {
- version: string
- notes?: string
- download_url: string
-}
-
interface UpdateCheckerProps {
customEndpoint?: string
includePrerelease?: boolean
@@ -38,10 +32,11 @@ export function UpdateChecker({
}: UpdateCheckerProps) {
const app = useAppStore()
const [checking, setChecking] = useState(false)
- const [downloading, setDownloading] = useState(false)
- const [updateInfo, setUpdateInfo] = useState(null)
- const [downloadProgress, setDownloadProgress] = useState(0)
- const [downloadCompleted, setDownloadCompleted] = useState(false)
+ // 从 store 读取状态
+ const updateInfo = app.state.updateInfo
+ const downloading = app.state.downloading
+ const downloadProgress = app.state.downloadProgress
+ const downloadCompleted = app.state.downloadCompleted
const {
isOpen: isChangelogOpen,
onOpen: onChangelogOpen,
@@ -52,27 +47,27 @@ export function UpdateChecker({
useEffect(() => {
const unlisten = listen("update-download-progress", (event) => {
const progress = event.payload
- setDownloadProgress(progress)
+ app.setDownloadProgress(progress)
// 如果进度达到 100%,标记下载完成
if (progress === 100) {
- setDownloading(false)
- setDownloadCompleted(true)
+ app.setDownloading(false)
+ app.setDownloadCompleted(true)
}
})
return () => {
unlisten.then((fn) => fn())
}
- }, [])
+ }, [app.setDownloadProgress, app.setDownloading, app.setDownloadCompleted])
// 检查更新
const handleCheckUpdate = async () => {
setChecking(true)
- setUpdateInfo(null)
- setDownloadProgress(0)
- setDownloading(false)
- setDownloadCompleted(false)
+ app.setUpdateInfo(null)
+ app.setDownloadProgress(0)
+ app.setDownloading(false)
+ app.setDownloadCompleted(false)
try {
// 根据是否包含测试版来选择不同的 endpoint
@@ -97,7 +92,7 @@ export function UpdateChecker({
})
if (result) {
- setUpdateInfo(result)
+ app.setUpdateInfo(result)
// 更新 store 中的更新状态和最新版本号
app.setHasUpdate(true)
app.setLatestVersion(result.version)
@@ -110,6 +105,7 @@ export function UpdateChecker({
// 没有更新,更新 store 状态
app.setHasUpdate(false)
app.setLatestVersion("")
+ app.setUpdateInfo(null)
addToast({
title: "已是最新版本",
color: "default",
@@ -132,18 +128,18 @@ export function UpdateChecker({
return
}
- setDownloading(true)
- setDownloadProgress(0)
- setDownloadCompleted(false)
+ app.setDownloading(true)
+ app.setDownloadProgress(0)
+ app.setDownloadCompleted(false)
try {
// 使用官方 updater 插件,传递 useCdn 参数
await invoke("download_app_update", { useCdn: useCdn })
// 下载完成,标记状态
- setDownloadProgress(100)
- setDownloading(false)
- setDownloadCompleted(true)
+ app.setDownloadProgress(100)
+ app.setDownloading(false)
+ app.setDownloadCompleted(true)
addToast({
title: "下载完成",
@@ -164,9 +160,9 @@ export function UpdateChecker({
color: "danger",
})
}
- setDownloadProgress(0)
- setDownloading(false)
- setDownloadCompleted(false)
+ app.setDownloadProgress(0)
+ app.setDownloading(false)
+ app.setDownloadCompleted(false)
}
}
@@ -174,9 +170,9 @@ export function UpdateChecker({
const handleCancelDownload = async () => {
try {
await invoke("cancel_download_update")
- setDownloading(false)
- setDownloadProgress(0)
- setDownloadCompleted(false)
+ app.setDownloading(false)
+ app.setDownloadProgress(0)
+ app.setDownloadCompleted(false)
addToast({
title: "已取消下载",
color: "default",
diff --git a/src/components/cstb/VideoSetting.tsx b/src/components/cstb/VideoSetting.tsx
index 576fd01..e25523a 100644
--- a/src/components/cstb/VideoSetting.tsx
+++ b/src/components/cstb/VideoSetting.tsx
@@ -9,35 +9,21 @@ import { useSteamStore } from "@/store/steam"
import { useDebounce, useDebounceFn, useThrottleFn } from "ahooks"
import { invoke } from "@tauri-apps/api/core"
import { listen } from "@tauri-apps/api/event"
+import { useGlobalGameMonitor } from "@/hooks/useGlobalGameMonitor"
const VideoSetting = () => {
const [hide, setHide] = useState(false)
const [edit, setEdit] = useState(false)
- const [isGameRunning, setIsGameRunning] = useState(false)
const tool = useToolStore()
const steam = useSteamStore()
+ // 使用全局游戏状态监控,避免重复检测
+ const { isGameRunning, checkGameRunning } = useGlobalGameMonitor()
// 使用 ref 存储 edit 的最新值,供 throttle 回调使用
const editRef = useRef(edit)
useEffect(() => {
editRef.current = edit
}, [edit])
- // 检测游戏是否运行
- const checkGameRunning = useCallback(async () => {
- try {
- // 尝试检测cs2.exe进程
- const result = await invoke("check_process_running", {
- processName: "cs2.exe",
- }).catch(() => false)
- setIsGameRunning(result)
- return result
- } catch {
- // 如果命令不存在,使用简单的检测方法
- setIsGameRunning(false)
- return false
- }
- }, [])
-
// 防抖的读取函数
const { run: debouncedGetVideoConfig } = useDebounceFn(
async () => {
@@ -286,16 +272,6 @@ const VideoSetting = () => {
const [vconfig, setVconfig] = useState(tool.state.videoSetting)
- // 初始化时检测游戏运行状态
- useEffect(() => {
- void checkGameRunning()
- // 定期检测游戏运行状态
- const interval = setInterval(() => {
- void checkGameRunning()
- }, 4000)
- return () => clearInterval(interval)
- }, [checkGameRunning])
-
useEffect(() => {
if (steam.state.steamDirValid && steam.currentUser())
void tool.getVideoConfig(steam.state.steamDir, steam.currentUser()?.steam_id32 || 0)
diff --git a/src/hooks/useGlobalGameMonitor.ts b/src/hooks/useGlobalGameMonitor.ts
new file mode 100644
index 0000000..f40298b
--- /dev/null
+++ b/src/hooks/useGlobalGameMonitor.ts
@@ -0,0 +1,65 @@
+import { useEffect, useRef } from "react"
+import { useToolStore } from "@/store/tool"
+
+// 全局检测间隔(毫秒)- 增加到5秒以减少性能影响
+const CHECK_INTERVAL = 5000
+
+// 全局检测状态管理
+let globalInterval: NodeJS.Timeout | null = null
+let subscriberCount = 0
+
+/**
+ * 全局游戏状态监控 Hook
+ * 多个组件可以共享同一个检测循环,避免重复检测
+ *
+ * @param enabled 是否启用检测(默认 true)
+ * @returns 游戏运行状态和手动检测函数
+ */
+export function useGlobalGameMonitor(enabled: boolean = true) {
+ const tool = useToolStore()
+ const isGameRunning = tool.state.isGameRunning
+ const checkGameRunning = tool.checkGameRunning
+ const enabledRef = useRef(enabled)
+
+ // 更新 enabled 引用
+ useEffect(() => {
+ enabledRef.current = enabled
+ }, [enabled])
+
+ useEffect(() => {
+ if (!enabled) {
+ return
+ }
+
+ // 增加订阅者计数
+ subscriberCount++
+
+ // 如果这是第一个订阅者,启动全局检测循环
+ if (subscriberCount === 1) {
+ // 立即检测一次
+ void checkGameRunning()
+
+ // 启动定期检测
+ globalInterval = setInterval(() => {
+ void checkGameRunning()
+ }, CHECK_INTERVAL)
+ }
+
+ // 清理函数:减少订阅者计数
+ return () => {
+ subscriberCount--
+
+ // 如果没有订阅者了,停止检测循环
+ if (subscriberCount === 0 && globalInterval) {
+ clearInterval(globalInterval)
+ globalInterval = null
+ }
+ }
+ }, [enabled, checkGameRunning])
+
+ return {
+ isGameRunning,
+ checkGameRunning,
+ }
+}
+
diff --git a/src/store/app.ts b/src/store/app.ts
index 2d16b18..d13ad07 100644
--- a/src/store/app.ts
+++ b/src/store/app.ts
@@ -4,10 +4,20 @@ import { DEFAULT_STORE_CONFIG } from "./config"
import { enable, disable } from "@tauri-apps/plugin-autostart"
import { LazyStore } from '@tauri-apps/plugin-store';
+interface UpdateInfo {
+ version: string
+ notes?: string
+ download_url: string
+}
+
const defaultValue = {
version: "0.0.1",
hasUpdate: false,
latestVersion: "", // 最新版本号
+ updateInfo: null as UpdateInfo | null, // 更新信息
+ downloading: false, // 是否正在下载
+ downloadProgress: 0, // 下载进度 0-100
+ downloadCompleted: false, // 下载是否完成
inited: false,
notice: "",
useMirror: true, // 默认使用镜像源(CDN 加速)
@@ -19,6 +29,8 @@ const defaultValue = {
steamUsersViewMode: "list-large" as "card" | "list" | "list-large",
}
+export type { UpdateInfo }
+
export const appStore = store("app", { ...defaultValue }, DEFAULT_STORE_CONFIG)
export const useAppStore = () => {
@@ -31,6 +43,10 @@ export const useAppStore = () => {
setVersion,
setHasUpdate,
setLatestVersion,
+ setUpdateInfo,
+ setDownloading,
+ setDownloadProgress,
+ setDownloadCompleted,
setInited,
setNotice,
setUseMirror,
@@ -56,6 +72,18 @@ const setHasUpdate = (hasUpdate: boolean) => {
const setLatestVersion = (latestVersion: string) => {
appStore.state.latestVersion = latestVersion
}
+const setUpdateInfo = (updateInfo: UpdateInfo | null) => {
+ appStore.state.updateInfo = updateInfo
+}
+const setDownloading = (downloading: boolean) => {
+ appStore.state.downloading = downloading
+}
+const setDownloadProgress = (downloadProgress: number) => {
+ appStore.state.downloadProgress = downloadProgress
+}
+const setDownloadCompleted = (downloadCompleted: boolean) => {
+ appStore.state.downloadCompleted = downloadCompleted
+}
const setInited = (inited: boolean) => {
appStore.state.inited = inited
}
@@ -100,6 +128,10 @@ const resetAppStore = () => {
setVersion(defaultValue.version)
setHasUpdate(defaultValue.hasUpdate)
setLatestVersion(defaultValue.latestVersion)
+ setUpdateInfo(defaultValue.updateInfo)
+ setDownloading(defaultValue.downloading)
+ setDownloadProgress(defaultValue.downloadProgress)
+ setDownloadCompleted(defaultValue.downloadCompleted)
setInited(defaultValue.inited)
setNotice(defaultValue.notice)
setUseMirror(defaultValue.useMirror)
diff --git a/src/store/tool.ts b/src/store/tool.ts
index c002450..ac4fa60 100644
--- a/src/store/tool.ts
+++ b/src/store/tool.ts
@@ -124,6 +124,7 @@ const defaultValue = {
launchIndex: 0,
powerPlan: 0,
autoCloseGame: true, // 帧数测试自动关闭游戏
+ isGameRunning: false, // 游戏运行状态(全局共享)
videoSetting: {
version: "15",
vendor_id: "0",
@@ -191,6 +192,8 @@ export const useToolStore = () => {
setVideoConfig,
addLaunchOption,
resetToolStore,
+ setIsGameRunning,
+ checkGameRunning,
}
}
@@ -288,10 +291,28 @@ const addLaunchOption = (option: LaunchOption) => {
sendCurrentLaunchOptionToTray(toolStore.state.launchIndex)
}
+const setIsGameRunning = (running: boolean) => {
+ toolStore.state.isGameRunning = running
+}
+
+const checkGameRunning = async (): Promise => {
+ try {
+ const result = await invoke("check_process_running", {
+ processName: "cs2.exe",
+ }).catch(() => false)
+ setIsGameRunning(result)
+ return result
+ } catch {
+ setIsGameRunning(false)
+ return false
+ }
+}
+
const resetToolStore = () => {
setLaunchOptions(defaultValue.launchOptions)
setLaunchIndex(defaultValue.launchIndex)
setPowerPlan(defaultValue.powerPlan)
setAutoCloseGame(defaultValue.autoCloseGame)
setVideoSetting(defaultValue.videoSetting)
+ setIsGameRunning(defaultValue.isGameRunning)
}