[feat] fps test results gathering

This commit is contained in:
2025-11-05 13:20:50 +08:00
parent c19adcc3f8
commit ce410f7a26
17 changed files with 363 additions and 116 deletions

View File

@@ -5,7 +5,11 @@ import { Chip, Code, Skeleton } from "@heroui/react"
import useSWR from "swr"
export default function Page() {
return <CfgxList />
return (
<section className="flex flex-col gap-4 overflow-hidden">
<CfgxList />
</section>
)
}
function CfgxList() {

View File

@@ -28,7 +28,7 @@ export default function Page() {
radius="full"
classNames={{
base: "min-w-0",
tabList: "gap-1",
tabList: "gap-0 p-0",
tab: "min-w-0 px-3",
tabContent: "text-xs",
}}

View File

@@ -12,12 +12,12 @@ import { Refresh, SettingConfig } from "@icon-park/react"
// import { version } from "@tauri-apps/plugin-os"
import { useEffect, useState } from "react"
import { type AllSystemInfo, allSysInfo } from "tauri-plugin-system-info-api"
import { FpsTest } from "@/components/cstb/FpsTest"
export default function Page() {
return (
<section className="flex flex-col gap-4 overflow-hidden rounded-lg">
<div className="flex flex-col gap-4 overflow-y-auto h-full hide-scrollbar">
<Card>
<div className="flex flex-col h-full gap-4 overflow-hidden hide-scrollbar">
<Card className="overflow-hidden">
<CardHeader>
<CardIcon type="menu">
<SettingConfig />
@@ -37,7 +37,6 @@ export default function Page() {
<HardwareInfo />
</CardBody>
</Card>
<FpsTest />
</div>
</section>
)

View File

@@ -10,7 +10,7 @@ import SmartTransfer from "@/components/cstb/SmartTranser"
const Home = () => {
return (
<section className="flex flex-col h-full gap-4">
<section className="flex flex-col h-full gap-4 overflow-hidden">
<div className="flex flex-grow w-full gap-4">
<Notice />
<SmartTransfer />

View File

@@ -12,42 +12,44 @@ export default function Page() {
const githubRepo = process.env.NEXT_PUBLIC_GITHUB_REPO || ""
return (
<div className="flex flex-col items-start gap-4 pt-2 pb-1">
<section className="flex flex-col gap-4 overflow-hidden">
<div className="flex flex-col items-start gap-4 pt-2 pb-1">
<div className="space-y-2">
<p className="text-sm">{app.state.version}</p>
<p className="text-sm">{app.state.hasUpdate ? "有" : "无"}</p>
<p className="text-sm">使{app.state.useMirror ? "是" : "否"}</p>
</div>
<div className="w-full border-t border-zinc-200 dark:border-zinc-800 pt-4">
<h3 className="text-sm font-semibold mb-3"></h3>
{/* <div className="w-full pt-4 border-t border-zinc-200 dark:border-zinc-800">
<h3 className="mb-3 text-sm font-semibold">更新检查</h3>
<UpdateChecker customEndpoint={customEndpoint} githubRepo={githubRepo} />
</div>
</div> */}
<div className="w-full border-t border-zinc-200 dark:border-zinc-800 pt-4 space-y-3">
<h3 className="text-sm font-semibold mb-3"></h3>
<div className="flex flex-col w-full pt-4 space-y-3 border-t border-zinc-200 dark:border-zinc-800">
<h3 className="mb-3 text-sm font-semibold"></h3>
<Switch
isSelected={app.state.autoStart}
size="sm"
onChange={(e) => app.setAutoStart(e.target.checked)}
>
{app.state.autoStart ? "开" : "关"}
</Switch>
<Switch
isSelected={app.state.startHidden}
size="sm"
onChange={(e) => app.setStartHidden(e.target.checked)}
>
{app.state.startHidden ? "开" : "关"}
</Switch>
<Switch
isSelected={app.state.hiddenOnClose}
size="sm"
onChange={(e) => app.setHiddenOnClose(e.target.checked)}
>
{app.state.hiddenOnClose ? "开" : "关"}
</Switch>
</div>
</div>
</div>
</section>
)
}

View File

@@ -5,12 +5,14 @@ export default function Page() {
const steam = useSteamStore()
return (
<div className="flex flex-col items-start gap-3 pt-2 pb-1">
<p>Steam路径{steam.state.steamDir}</p>
<p>{steam.state.cs2Dir}</p>
<p>Steam路径有效{steam.state.steamDirValid ? "是" : "否"}</p>
<p>{steam.state.cs2DirValid ? "是" : "否"}</p>
<p>Steam账号{steam.currentUser()?.account_name || " "}</p>
</div>
<section className="flex flex-col gap-4 overflow-hidden">
<div className="flex flex-col items-start gap-3 pt-2 pb-1">
<p>Steam路{steam.state.steamDir}</p>
<p>{steam.state.cs2Dir}</p>
<p>Steam路径有{steam.state.steamDirValid ? "是" : "否"}</p>
<p>{steam.state.cs2DirValid ? "是" : "否"}</p>
<p>Steam账号{steam.currentUser()?.account_name || " "}</p>
</div>
</section>
)
}

View File

@@ -1,4 +1,8 @@
"use client"
export default function Page() {
return <>Replay</>
return (
<section className="flex flex-col gap-4 overflow-hidden">
<>Replay</>
</section>
)
}

View File

@@ -1,11 +1,15 @@
"use client"
import VideoSetting from "@/components/cstb/VideoSetting"
import { FpsTest } from "@/components/cstb/FpsTest"
export default function Page() {
return (
<section className="flex flex-col h-full gap-4">
<VideoSetting />
<section className="flex flex-col h-full gap-4 overflow-hidden">
<div className="flex flex-col h-full gap-4 overflow-y-auto rounded-lg hide-scrollbar">
<VideoSetting />
<FpsTest />
</div>
</section>
)
}

View File

@@ -1,4 +1,8 @@
"use client"
export default function Page() {
return <div>Users</div>
return (
<section className="flex flex-col gap-4 overflow-hidden">
<div>Users</div>
</section>
)
}

View File

@@ -36,7 +36,8 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
addToast({
title: "登录失败",
description: "无法验证登录信息,请重试",
variant: "danger",
severity: "danger",
})
}
} catch (error) {
@@ -44,7 +45,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
addToast({
title: "登录失败",
description: error instanceof Error ? error.message : "未知错误",
variant: "danger",
severity: "danger",
})
} finally {
setLoading(false)

View File

@@ -16,7 +16,7 @@ const RoundedButton = ({
return (
<button
type="button"
className="flex items-center justify-center px-3 py-1 transition rounded-full select-none min-w-fit active:scale-95 hover:bg-black/10 text-zinc-700 dark:text-zinc-100 bg-black/5 dark:bg-white/5"
className="flex items-center justify-center px-3 py-1 transition rounded-full cursor-pointer select-none min-w-fit active:scale-95 hover:bg-black/10 text-zinc-700 dark:text-zinc-100 bg-black/5 dark:bg-white/5"
{...props}
>
{children}

View File

@@ -1,10 +1,13 @@
"use client"
import { useSteamStore } from "@/store/steam"
import { useToolStore } from "@/store/tool"
import { useFpsTestStore } from "@/store/fpsTest"
import { invoke } from "@tauri-apps/api/core"
import { Card, CardBody, CardHeader, CardIcon } from "../window/Card"
import { addToast, Button, Chip, Spinner, Switch } from "@heroui/react"
import { Card, CardBody, CardHeader, CardIcon, CardTool } from "../window/Card"
import { addToast, Button, Chip, Spinner, Switch, Table, TableHeader, TableColumn, TableBody, TableRow, TableCell } from "@heroui/react"
import { useState, useEffect, useRef, useCallback } from "react"
import { TestTube, Power } from "@icon-park/react"
import { TestTube, Power, List, Delete } from "@icon-park/react"
import { allSysInfo, type AllSystemInfo } from "tauri-plugin-system-info-api"
const BENCHMARK_MAPS = [
{
@@ -106,18 +109,79 @@ function compareTimestamps(timestamp1: string, timestamp2: string): boolean {
return date1 > date2
}
// 从 VProf 报告中提取 avg 和 p1 值
function extractFpsMetrics(result: string): { avg: number | null; p1: number | null } {
let avg: number | null = null
let p1: number | null = null
// 查找包含 avg 的行,支持多种格式:
// - "[VProf] FPS: Avg=239.5, P1=228.0" (等号格式)
// - "[VProf] avg: 123.45" (冒号格式)
// - "[VProf] avg 123.45" (空格格式)
const avgMatch = result.match(/avg[=:\s]+(\d+\.?\d*)/i)
if (avgMatch) {
avg = parseFloat(avgMatch[1])
}
// 查找包含 p1 的行,支持多种格式:
// - "P1=228.0" (等号格式)
// - "p1: 98.76" (冒号格式)
// - "p1 98.76" (空格格式)
const p1Match = result.match(/p1[=:\s]+(\d+\.?\d*)/i)
if (p1Match) {
p1 = parseFloat(p1Match[1])
}
// 如果找不到,尝试查找其他可能的格式
// 例如:查找包含 "fps" 和数字的行
if (!avg) {
const fpsMatch = result.match(/fps[=:\s]+(\d+\.?\d*)/i)
if (fpsMatch) {
avg = parseFloat(fpsMatch[1])
}
}
// 尝试查找 1% low 或类似的格式
if (!p1) {
const lowMatch = result.match(/(?:1%|1st|first).*?low[=:\s]+(\d+\.?\d*)/i)
if (lowMatch) {
p1 = parseFloat(lowMatch[1])
}
}
return { avg, p1 }
}
export function FpsTest() {
const steam = useSteamStore()
const tool = useToolStore()
const fpsTest = useFpsTestStore()
const [testing, setTesting] = useState(false)
const [testResult, setTestResult] = useState<string | null>(null)
const [testTimestamp, setTestTimestamp] = useState<string | null>(null)
const [selectedMap, setSelectedMap] = useState<string | null>(null)
const [selectedMapLabel, setSelectedMapLabel] = useState<string | null>(null)
const [autoCloseGame, setAutoCloseGame] = useState(false)
const [isMonitoring, setIsMonitoring] = useState(false)
const [showResultsTable, setShowResultsTable] = useState(false)
const [hardwareInfo, setHardwareInfo] = useState<AllSystemInfo | null>(null)
const monitoringIntervalRef = useRef<NodeJS.Timeout | null>(null)
// 记录测试开始的时间戳(用于过滤旧数据)
const testStartTimestampRef = useRef<string | null>(null)
// 获取硬件信息
useEffect(() => {
const fetchHardwareInfo = async () => {
try {
const sys = await allSysInfo()
setHardwareInfo(sys)
} catch (error) {
console.error("获取硬件信息失败:", error)
}
}
void fetchHardwareInfo()
}, [])
// 读取结果函数
const readResult = useCallback(
async (silent = false): Promise<boolean> => {
@@ -156,8 +220,48 @@ export function FpsTest() {
setTestTimestamp(parsed.timestamp)
// 成功读取后,清除测试开始时间戳(测试已完成)
testStartTimestampRef.current = null
// 提取 avg 和 p1 值
const { avg, p1 } = extractFpsMetrics(parsed.data)
// 保存测试结果(即使没有 selectedMap 也保存,使用 "未知地图" 作为默认值)
const now = new Date()
const testDate = now.toISOString()
const mapConfig = selectedMap ? BENCHMARK_MAPS.find(m => m.name === selectedMap) : null
// 从 store 直接获取最新的 videoSetting避免依赖项问题
const currentVideoSetting = tool.store.state.videoSetting
fpsTest.addResult({
id: `${now.getTime()}-${Math.random().toString(36).slice(2, 11)}`,
testTime: parsed.timestamp,
testDate,
mapName: selectedMap || "unknown",
mapLabel: mapConfig?.label || selectedMapLabel || "未知地图",
avg,
p1,
rawResult: parsed.data,
videoSetting: currentVideoSetting,
hardwareInfo: hardwareInfo ? {
cpu: hardwareInfo.cpus[0]?.brand || null,
cpuCount: hardwareInfo.cpu_count || null,
os: hardwareInfo.name && hardwareInfo.os_version
? `${hardwareInfo.name} ${hardwareInfo.os_version}`
: null,
memory: hardwareInfo.total_memory
? Math.round(hardwareInfo.total_memory / 1024 / 1024 / 1024)
: null,
} : null,
})
if (!silent) {
addToast({ title: "已读取测试结果" })
if (avg !== null || p1 !== null) {
addToast({
title: `已读取并保存测试结果${avg !== null ? ` (avg: ${avg.toFixed(1)} FPS)` : ""}${p1 !== null ? ` (p1: ${p1.toFixed(1)} FPS)` : ""}`
})
} else {
addToast({ title: "已读取并保存测试结果(未能提取帧数数据)" })
}
}
return true
} else if (!silent) {
@@ -184,7 +288,7 @@ export function FpsTest() {
return false
}
},
[steam.state.cs2Dir]
[steam.state.cs2Dir, selectedMap, selectedMapLabel, fpsTest, tool.store, hardwareInfo]
)
// 关闭游戏
@@ -253,6 +357,7 @@ export function FpsTest() {
setTesting(true)
setSelectedMap(mapConfig.name)
setSelectedMapLabel(mapConfig.label)
setTestResult(null)
setTestTimestamp(null)
@@ -299,72 +404,133 @@ export function FpsTest() {
<CardIcon>
<TestTube size={16} />
</CardIcon>
<CardTool>
<Button
size="sm"
variant={showResultsTable ? "solid" : "flat"}
onPress={() => setShowResultsTable(!showResultsTable)}
className="px-3"
>
<List size={14} className="mr-1" />
</Button>
</CardTool>
</CardHeader>
<CardBody>
<div className="flex flex-col gap-3">
<div className="flex flex-wrap items-center gap-2">
{BENCHMARK_MAPS.map((mapConfig) => (
{showResultsTable ? (
<div className="flex flex-col gap-3">
<div className="max-h-[500px] overflow-auto">
<Table aria-label="测试结果表格" selectionMode="none">
<TableHeader>
<TableColumn></TableColumn>
<TableColumn></TableColumn>
<TableColumn></TableColumn>
<TableColumn>P1帧数</TableColumn>
<TableColumn>CPU</TableColumn>
<TableColumn width={80}></TableColumn>
</TableHeader>
<TableBody emptyContent="暂无测试记录">
{fpsTest.state.results.map((result) => (
<TableRow key={result.id}>
<TableCell>{result.testTime}</TableCell>
<TableCell>{result.mapLabel}</TableCell>
<TableCell>
{result.avg !== null ? `${result.avg.toFixed(1)}` : "N/A"}
</TableCell>
<TableCell>
{result.p1 !== null ? `${result.p1.toFixed(1)}` : "N/A"}
</TableCell>
<TableCell>
{result.hardwareInfo?.cpu || "N/A"}
</TableCell>
<TableCell>
<Button
size="sm"
isIconOnly
variant="light"
onPress={() => {
fpsTest.removeResult(result.id)
addToast({
title: "已删除测试记录",
variant: "flat"
})
}}
className="min-w-8"
>
<Delete size={16} />
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</div>
) : (
<div className="flex flex-col gap-3">
<div className="flex flex-wrap items-center gap-2">
{BENCHMARK_MAPS.map((mapConfig) => (
<Button
key={mapConfig.name}
size="sm"
isDisabled={testing || isMonitoring}
onPress={() => {
void startTest(mapConfig)
}}
className="font-medium transition bg-blue-200 rounded-full select-none dark:bg-blue-900/60"
>
{testing && selectedMap === mapConfig.name ? (
<Spinner size="sm" className="mr-2" />
) : null}
{mapConfig.label}
</Button>
))}
<Button
key={mapConfig.name}
size="sm"
isDisabled={testing || isMonitoring}
isDisabled={isMonitoring}
onPress={() => {
void startTest(mapConfig)
void readResult()
}}
className="px-4 font-medium py-1.5 transition bg-blue-200 dark:bg-blue-900/60 rounded-full select-none"
className="font-medium transition bg-green-200 rounded-full select-none dark:bg-green-900/60"
>
{testing && selectedMap === mapConfig.name ? (
<Spinner size="sm" className="mr-2" />
) : null}
{mapConfig.label}
</Button>
))}
<Button
size="sm"
isDisabled={isMonitoring}
onPress={() => {
void readResult()
}}
className="px-4 font-medium py-1.5 transition bg-green-200 dark:bg-green-900/60 rounded-full select-none"
>
</Button>
<Button
size="sm"
onPress={() => {
void closeGame()
}}
className="px-4 font-medium py-1.5 transition bg-orange-200 dark:bg-orange-900/60 rounded-full select-none"
>
<Power className="mr-1" size={14} />
</Button>
<Switch size="sm" isSelected={autoCloseGame} onValueChange={setAutoCloseGame} className="ml-4">
</Switch>
{isMonitoring && (
<Chip size="sm" color="primary" variant="flat">
...
</Chip>
<Button
size="sm"
onPress={() => {
void closeGame()
}}
className="font-medium transition bg-orange-200 rounded-full select-none dark:bg-orange-900/60"
>
<Power size={14} />
</Button>
<Switch size="sm" isSelected={autoCloseGame} onValueChange={setAutoCloseGame} className="ml-4">
</Switch>
{isMonitoring && (
<Chip size="sm" color="primary" variant="flat">
...
</Chip>
)}
</div>
{testResult && (
<div className="mt-2">
<div className="flex items-center gap-2 mb-2">
{testTimestamp && (
<Chip size="sm" variant="flat" color="default">
: {testTimestamp}
</Chip>
)}
</div>
<pre className="p-3 overflow-auto font-mono text-xs rounded-md bg-black/5 dark:bg-white/5 hide-scrollbar">
{testResult}
</pre>
</div>
)}
</div>
{testResult && (
<div className="mt-2">
<div className="flex items-center gap-2 mb-2">
<Chip size="sm"></Chip>
{testTimestamp && (
<Chip size="sm" variant="flat" color="default">
: {testTimestamp}
</Chip>
)}
</div>
<pre className="p-3 overflow-auto font-mono text-xs rounded-md bg-black/5 dark:bg-white/5">
{testResult}
</pre>
</div>
)}
</div>
)}
</CardBody>
</Card>
)

View File

@@ -2,9 +2,9 @@
import { useState } from "react"
import { Button, Progress, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, useDisclosure } from "@heroui/react"
import { Download, Refresh, CheckCircle } from "@icon-park/react"
import { Download, Refresh, CheckCorrect } from "@icon-park/react"
import { invoke } from "@tauri-apps/api/core"
import { relaunch } from "@tauri-apps/api/process"
import { relaunch } from "@tauri-apps/plugin-process"
import { addToast } from "@heroui/react"
import { useAppStore } from "@/store/app"
@@ -159,8 +159,8 @@ export function UpdateChecker({ customEndpoint, githubRepo }: UpdateCheckerProps
{checking ? "检查中..." : "检查更新"}
</Button>
{app.state.hasUpdate && (
<span className="text-sm text-green-600 dark:text-green-400 flex items-center gap-1">
<CheckCircle size={16} />
<span className="flex items-center gap-1 text-sm text-green-600 dark:text-green-400">
<CheckCorrect size={16} />
</span>
)}
@@ -192,8 +192,8 @@ export function UpdateChecker({ customEndpoint, githubRepo }: UpdateCheckerProps
<ModalBody>
<div className="space-y-3">
<div>
<p className="text-sm font-semibold mb-1"></p>
<div className="text-sm text-zinc-600 dark:text-zinc-400 whitespace-pre-wrap">
<p className="mb-1 text-sm font-semibold"></p>
<div className="text-sm whitespace-pre-wrap text-zinc-600 dark:text-zinc-400">
{formatNotes(updateInfo?.notes)}
</div>
</div>

View File

@@ -20,7 +20,9 @@ const VideoSetting = () => {
const checkGameRunning = useCallback(async () => {
try {
// 尝试检测cs2.exe进程
const result = await invoke<boolean>("check_process_running", { processName: "cs2.exe" }).catch(() => false)
const result = await invoke<boolean>("check_process_running", {
processName: "cs2.exe",
}).catch(() => false)
setIsGameRunning(result)
return result
} catch {
@@ -310,12 +312,7 @@ const VideoSetting = () => {
<CardIcon>
<SettingConfig />
{isGameRunning && (
<Chip
size="sm"
color="warning"
variant="flat"
className="ml-2"
>
<Chip size="sm" color="warning" variant="flat" className="ml-2">
</Chip>
)}
@@ -354,10 +351,10 @@ const VideoSetting = () => {
// 检查游戏是否运行
const gameRunning = await checkGameRunning()
if (gameRunning) {
addToast({
title: "无法应用设置",
addToast({
title: "无法应用设置",
description: "检测到游戏正在运行,请先关闭游戏后再应用设置",
color: "warning"
color: "warning",
})
return
}
@@ -373,7 +370,7 @@ const VideoSetting = () => {
setEdit(false)
addToast({ title: "应用设置成功" })
}}
isDisabled={isGameRunning}
disabled={isGameRunning}
>
<Plus />
@@ -404,11 +401,7 @@ const VideoSetting = () => {
)}
</ToolButton>
<ToolButton
onClick={debouncedGetVideoConfig}
>
</ToolButton>
<ToolButton onClick={debouncedGetVideoConfig}></ToolButton>
<ToolButton onClick={() => setHide(!hide)}>
{hide ? (
<>
@@ -500,7 +493,8 @@ const VideoSetting = () => {
<div className="flex flex-col gap-1">
<span className="text-xs text-default-500"></span>
<span className="text-sm font-medium">
{tool.state.videoSetting.defaultres} × {tool.state.videoSetting.defaultresheight}
{tool.state.videoSetting.defaultres} ×{" "}
{tool.state.videoSetting.defaultresheight}
</span>
</div>
{videoSettings(tool.state.videoSetting).map((vid, index) => (

View File

@@ -11,7 +11,7 @@ export const ToolButton = ({ children, className, selected, ...rest }: ToolButto
<button
type="button"
className={cn(
"flex flex-shrink-0 gap-0.5 active:scale-95 items-center min-w-7 justify-center px-2 py-1.5 bg-black/5 transition hover:bg-black/10 dark:bg-white/5 dark:hover:bg-white/10 rounded-md text-sm leading-none",
"flex shrink-0 gap-0.5 active:scale-95 cursor-pointer items-center min-w-7 justify-center px-2 py-1.5 bg-black/5 transition hover:bg-black/10 dark:bg-white/5 dark:hover:bg-white/10 rounded-md text-sm leading-none",
className,
selected &&
"bg-purple-500/40 hover:bg-purple-500/20 text-purple-900 dark:text-purple-100 drop-shadow-sm dark:bg-purple-500/40 dark:hover:bg-purple-500/20"

65
src/store/fpsTest.ts Normal file
View File

@@ -0,0 +1,65 @@
import { store } from "@tauri-store/valtio"
import { useSnapshot } from "valtio"
import { DEFAULT_STORE_CONFIG } from "./config"
import type { AllSystemInfo } from "tauri-plugin-system-info-api"
import type { VideoSetting } from "./tool"
export interface FpsTestResult {
id: string // 唯一标识符,使用时间戳
testTime: string // 测试时间MM/DD HH:mm:ss
testDate: string // 测试日期ISO 格式,用于排序)
mapName: string // 测试地图名称
mapLabel: string // 测试地图标签
avg: number | null // 平均帧数
p1: number | null // P1 帧数最低1%帧数)
rawResult: string // 原始测试结果
videoSetting: VideoSetting | null // 画面设置参数
hardwareInfo: {
cpu: string | null
cpuCount: number | null
os: string | null
memory: number | null // GB
} | null // 硬件信息
}
const defaultValue = {
results: [] as FpsTestResult[],
}
export const fpsTestStore = store(
"fpsTest",
{ ...defaultValue },
DEFAULT_STORE_CONFIG,
)
export const useFpsTestStore = () => {
void fpsTestStore.start
const state = useSnapshot(fpsTestStore.state)
return {
state,
store: fpsTestStore,
addResult,
removeResult,
clearResults,
}
}
const addResult = (result: FpsTestResult) => {
fpsTestStore.state.results = [result, ...fpsTestStore.state.results]
// 限制最多保存100条记录
if (fpsTestStore.state.results.length > 100) {
fpsTestStore.state.results = fpsTestStore.state.results.slice(0, 100)
}
}
const removeResult = (id: string) => {
fpsTestStore.state.results = fpsTestStore.state.results.filter(
(r) => r.id !== id,
)
}
const clearResults = () => {
fpsTestStore.state.results = []
}

View File

@@ -4,6 +4,7 @@ import { appStore } from "./app"
import { authStore } from "./auth"
import { steamStore } from "./steam"
import { toolStore } from "./tool"
import { fpsTestStore } from "./fpsTest"
import path from "path"
export async function init() {
@@ -11,6 +12,7 @@ export async function init() {
await authStore.start()
await toolStore.start()
await steamStore.start()
await fpsTestStore.start()
const appConfigDirPath = await appConfigDir()
const setPath = commands.setStoreCollectionPath("valtio")
await setPath(path.resolve(appConfigDirPath, "cstb"))