[feat] multi-resolution and batch testing
This commit is contained in:
@@ -221,15 +221,18 @@ export function FpsTest() {
|
|||||||
const [showResultsTable, setShowResultsTable] = useState(false)
|
const [showResultsTable, setShowResultsTable] = useState(false)
|
||||||
const [hardwareInfo, setHardwareInfo] = useState<AllSystemInfo | null>(null)
|
const [hardwareInfo, setHardwareInfo] = useState<AllSystemInfo | null>(null)
|
||||||
const [isGameRunning, setIsGameRunning] = useState(false)
|
const [isGameRunning, setIsGameRunning] = useState(false)
|
||||||
const [testNote, setTestNote] = useState<string>("") // 测试备注
|
|
||||||
const [editingNoteId, setEditingNoteId] = useState<string | null>(null) // 正在编辑的备注ID
|
const [editingNoteId, setEditingNoteId] = useState<string | null>(null) // 正在编辑的备注ID
|
||||||
const [editingNoteValue, setEditingNoteValue] = useState<string>("") // 正在编辑的备注内容
|
const [editingNoteValue, setEditingNoteValue] = useState<string>("") // 正在编辑的备注内容
|
||||||
const [customLaunchOption, setCustomLaunchOption] = useState<string>("") // 自定义启动项
|
// 从store读取配置数据
|
||||||
const [isResolutionEnabled, setIsResolutionEnabled] = useState<boolean>(true) // 是否启用分辨率和全屏设置
|
const testNote = fpsTest.state.config.testNote
|
||||||
const [resolutionWidth, setResolutionWidth] = useState<string>("") // 分辨率宽度
|
const customLaunchOption = fpsTest.state.config.customLaunchOption
|
||||||
const [resolutionHeight, setResolutionHeight] = useState<string>("") // 分辨率高度
|
const isResolutionEnabled = fpsTest.state.config.isResolutionEnabled
|
||||||
const [isFullscreen, setIsFullscreen] = useState<boolean>(true) // 全屏模式(默认全屏)
|
const resolutionWidth = fpsTest.state.config.resolutionWidth
|
||||||
const [batchTestCount, setBatchTestCount] = useState<number>(1) // 批量测试次数(1表示单次测试)
|
const resolutionHeight = fpsTest.state.config.resolutionHeight
|
||||||
|
const isFullscreen = fpsTest.state.config.isFullscreen
|
||||||
|
const batchTestCount = fpsTest.state.config.batchTestCount
|
||||||
|
const isResolutionGroupEnabled = fpsTest.state.config.isResolutionGroupEnabled
|
||||||
|
const resolutionGroup = fpsTest.state.config.resolutionGroup
|
||||||
const [batchTestProgress, setBatchTestProgress] = useState<{
|
const [batchTestProgress, setBatchTestProgress] = useState<{
|
||||||
current: number
|
current: number
|
||||||
total: number
|
total: number
|
||||||
@@ -253,6 +256,8 @@ export function FpsTest() {
|
|||||||
const testStartTimeRef = useRef<number | null>(null)
|
const testStartTimeRef = useRef<number | null>(null)
|
||||||
// 记录测试开始时的视频设置
|
// 记录测试开始时的视频设置
|
||||||
const testStartVideoSettingRef = useRef<typeof tool.state.videoSetting | null>(null)
|
const testStartVideoSettingRef = useRef<typeof tool.state.videoSetting | null>(null)
|
||||||
|
// 记录当前测试的分辨率信息(用于备注)
|
||||||
|
const currentTestResolutionRef = useRef<{ width: string; height: string; label: string } | null>(null)
|
||||||
|
|
||||||
// 检测游戏是否运行
|
// 检测游戏是否运行
|
||||||
const checkGameRunning = useCallback(async () => {
|
const checkGameRunning = useCallback(async () => {
|
||||||
@@ -277,14 +282,20 @@ export function FpsTest() {
|
|||||||
return () => clearInterval(interval)
|
return () => clearInterval(interval)
|
||||||
}, [checkGameRunning])
|
}, [checkGameRunning])
|
||||||
|
|
||||||
// 同步当前分辨率到状态(初始化时)
|
// 同步当前分辨率到store(初始化时)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (tool.state.videoSetting) {
|
if (tool.state.videoSetting) {
|
||||||
setResolutionWidth(tool.state.videoSetting.defaultres || "")
|
if (!fpsTest.state.config.resolutionWidth && !fpsTest.state.config.resolutionHeight) {
|
||||||
setResolutionHeight(tool.state.videoSetting.defaultresheight || "")
|
fpsTest.setResolution(
|
||||||
setIsFullscreen(tool.state.videoSetting.fullscreen === "1")
|
tool.state.videoSetting.defaultres || "",
|
||||||
|
tool.state.videoSetting.defaultresheight || ""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}, [tool.state.videoSetting])
|
if (fpsTest.state.config.isFullscreen === true && tool.state.videoSetting.fullscreen !== "1") {
|
||||||
|
fpsTest.setIsFullscreen(tool.state.videoSetting.fullscreen === "1")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [tool.state.videoSetting, fpsTest])
|
||||||
|
|
||||||
// 获取硬件信息
|
// 获取硬件信息
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -322,6 +333,7 @@ export function FpsTest() {
|
|||||||
testStartTimestampRef.current = null
|
testStartTimestampRef.current = null
|
||||||
testStartTimeRef.current = null
|
testStartTimeRef.current = null
|
||||||
testStartVideoSettingRef.current = null
|
testStartVideoSettingRef.current = null
|
||||||
|
currentTestResolutionRef.current = null
|
||||||
|
|
||||||
// 如果启用了自动关闭游戏,则关闭游戏
|
// 如果启用了自动关闭游戏,则关闭游戏
|
||||||
if (tool.state.autoCloseGame) {
|
if (tool.state.autoCloseGame) {
|
||||||
@@ -388,6 +400,11 @@ export function FpsTest() {
|
|||||||
timeoutRef.current = null
|
timeoutRef.current = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 测试结束后读取视频设置(检测分辨率)
|
||||||
|
if (steam.state.steamDirValid && steam.currentUser()) {
|
||||||
|
await tool.getVideoConfig(steam.state.steamDir, steam.currentUser()?.steam_id32 || 0)
|
||||||
|
}
|
||||||
|
|
||||||
// 提取 avg 和 p1 值
|
// 提取 avg 和 p1 值
|
||||||
const { avg, p1 } = extractFpsMetrics(parsed.data)
|
const { avg, p1 } = extractFpsMetrics(parsed.data)
|
||||||
|
|
||||||
@@ -396,20 +413,27 @@ export function FpsTest() {
|
|||||||
const testDate = now.toISOString()
|
const testDate = now.toISOString()
|
||||||
const mapConfig = BENCHMARK_MAPS[selectedMapIndex]
|
const mapConfig = BENCHMARK_MAPS[selectedMapIndex]
|
||||||
|
|
||||||
// 使用测试开始时的视频设置(如果有的话),否则使用当前的
|
// 使用读取到的视频设置(测试结束后读取的)
|
||||||
const currentVideoSetting =
|
const currentVideoSetting = tool.store.state.videoSetting
|
||||||
testStartVideoSettingRef.current || tool.store.state.videoSetting
|
|
||||||
|
|
||||||
// 如果是批量测试,保存结果到批量结果数组,否则直接保存
|
// 如果是批量测试,保存结果到批量结果数组,否则直接保存
|
||||||
const currentBatchProgress = batchTestProgress
|
const currentBatchProgress = batchTestProgress
|
||||||
|
const currentResolution = currentTestResolutionRef.current
|
||||||
if (currentBatchProgress) {
|
if (currentBatchProgress) {
|
||||||
const result = { avg, p1 }
|
const result = { avg, p1 }
|
||||||
setBatchTestResults((prev) => [...prev, result])
|
setBatchTestResults((prev) => [...prev, result])
|
||||||
batchTestResultsRef.current = [...batchTestResultsRef.current, result]
|
batchTestResultsRef.current = [...batchTestResultsRef.current, result]
|
||||||
|
|
||||||
// 添加带批量标识的备注
|
// 添加带批量标识和分辨率信息的备注
|
||||||
const batchNote = testNote
|
let batchNote = ""
|
||||||
? `${testNote} [批量${currentBatchProgress.current}/${currentBatchProgress.total}]`
|
if (currentResolution) {
|
||||||
|
batchNote = `[分辨率:${currentResolution.label}]`
|
||||||
|
}
|
||||||
|
if (testNote) {
|
||||||
|
batchNote = batchNote ? `${testNote} ${batchNote}` : testNote
|
||||||
|
}
|
||||||
|
batchNote = batchNote
|
||||||
|
? `${batchNote} [批量${currentBatchProgress.current}/${currentBatchProgress.total}]`
|
||||||
: `[批量${currentBatchProgress.current}/${currentBatchProgress.total}]`
|
: `[批量${currentBatchProgress.current}/${currentBatchProgress.total}]`
|
||||||
|
|
||||||
fpsTest.addResult({
|
fpsTest.addResult({
|
||||||
@@ -445,6 +469,13 @@ export function FpsTest() {
|
|||||||
// 不在这里处理,由startTest的循环处理
|
// 不在这里处理,由startTest的循环处理
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// 单次测试,添加分辨率信息到备注
|
||||||
|
let singleNote = testNote
|
||||||
|
if (currentResolution) {
|
||||||
|
const resolutionNote = `[分辨率:${currentResolution.label}]`
|
||||||
|
singleNote = singleNote ? `${testNote} ${resolutionNote}` : resolutionNote
|
||||||
|
}
|
||||||
|
|
||||||
fpsTest.addResult({
|
fpsTest.addResult({
|
||||||
id: `${now.getTime()}-${Math.random().toString(36).slice(2, 11)}`,
|
id: `${now.getTime()}-${Math.random().toString(36).slice(2, 11)}`,
|
||||||
testTime: parsed.timestamp,
|
testTime: parsed.timestamp,
|
||||||
@@ -470,12 +501,13 @@ export function FpsTest() {
|
|||||||
monitor: null,
|
monitor: null,
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
note: testNote, // 保存备注
|
note: singleNote, // 保存备注(包含分辨率信息)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清除保存的启动时视频设置
|
// 清除保存的启动时视频设置和分辨率信息
|
||||||
testStartVideoSettingRef.current = null
|
testStartVideoSettingRef.current = null
|
||||||
|
currentTestResolutionRef.current = null
|
||||||
|
|
||||||
if (!silent) {
|
if (!silent) {
|
||||||
if (avg !== null || p1 !== null) {
|
if (avg !== null || p1 !== null) {
|
||||||
@@ -530,6 +562,7 @@ export function FpsTest() {
|
|||||||
tool.state.autoCloseGame,
|
tool.state.autoCloseGame,
|
||||||
batchTestProgress,
|
batchTestProgress,
|
||||||
testNote,
|
testNote,
|
||||||
|
batchTestResults,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -557,6 +590,7 @@ export function FpsTest() {
|
|||||||
testStartTimestampRef.current = null
|
testStartTimestampRef.current = null
|
||||||
testStartTimeRef.current = null
|
testStartTimeRef.current = null
|
||||||
testStartVideoSettingRef.current = null
|
testStartVideoSettingRef.current = null
|
||||||
|
currentTestResolutionRef.current = null
|
||||||
addToast({
|
addToast({
|
||||||
title: "测试超时(200秒),测试失败",
|
title: "测试超时(200秒),测试失败",
|
||||||
variant: "flat",
|
variant: "flat",
|
||||||
@@ -599,7 +633,8 @@ export function FpsTest() {
|
|||||||
const runSingleTest = async (
|
const runSingleTest = async (
|
||||||
testIndex: number,
|
testIndex: number,
|
||||||
totalTests: number,
|
totalTests: number,
|
||||||
isFirstTest: boolean = false
|
isFirstTest: boolean = false,
|
||||||
|
resolution?: { width: string; height: string; label: string }
|
||||||
): Promise<boolean> => {
|
): Promise<boolean> => {
|
||||||
if (!steam.state.steamDir || !steam.state.cs2Dir) {
|
if (!steam.state.steamDir || !steam.state.cs2Dir) {
|
||||||
return false
|
return false
|
||||||
@@ -642,11 +677,18 @@ export function FpsTest() {
|
|||||||
// 构建启动参数:基础参数 + 分辨率和全屏设置 + 自定义启动项(如果有)
|
// 构建启动参数:基础参数 + 分辨率和全屏设置 + 自定义启动项(如果有)
|
||||||
let baseLaunchOption = `-allow_third_party_software -condebug -conclearlog +map_workshop ${mapConfig.workshopId} ${mapConfig.map}`
|
let baseLaunchOption = `-allow_third_party_software -condebug -conclearlog +map_workshop ${mapConfig.workshopId} ${mapConfig.map}`
|
||||||
|
|
||||||
|
// 使用传入的分辨率,如果没有则使用store中的分辨率
|
||||||
|
const currentResolution = resolution || {
|
||||||
|
width: resolutionWidth,
|
||||||
|
height: resolutionHeight,
|
||||||
|
label: `${resolutionWidth}x${resolutionHeight}`,
|
||||||
|
}
|
||||||
|
|
||||||
// 只有在启用分辨率和全屏设置时才添加相关参数
|
// 只有在启用分辨率和全屏设置时才添加相关参数
|
||||||
if (isResolutionEnabled) {
|
if (isResolutionEnabled) {
|
||||||
// 添加分辨率设置(如果有设置)
|
// 添加分辨率设置(如果有设置)
|
||||||
if (resolutionWidth && resolutionHeight) {
|
if (currentResolution.width && currentResolution.height) {
|
||||||
baseLaunchOption += ` -w ${resolutionWidth} -h ${resolutionHeight}`
|
baseLaunchOption += ` -w ${currentResolution.width} -h ${currentResolution.height}`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加全屏/窗口化设置
|
// 添加全屏/窗口化设置
|
||||||
@@ -669,29 +711,17 @@ export function FpsTest() {
|
|||||||
server: "worldwide",
|
server: "worldwide",
|
||||||
})
|
})
|
||||||
|
|
||||||
// 延迟读取视频设置(修复分辨率读取bug)
|
// 视频设置将在测试结束后读取(在readResult中)
|
||||||
// 等待游戏启动并应用分辨率设置(5秒)
|
// 保存当前测试的分辨率信息
|
||||||
// 批量测试的第一次不需要等待,因为游戏还没有启动过
|
currentTestResolutionRef.current = currentResolution
|
||||||
if (!isFirstTest) {
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 5000))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重新读取视频配置
|
|
||||||
if (steam.state.steamDirValid && steam.currentUser()) {
|
|
||||||
await tool.getVideoConfig(steam.state.steamDir, steam.currentUser()?.steam_id32 || 0)
|
|
||||||
// 再等待一下确保配置已更新
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1000))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存启动后的视频设置(延迟读取后的)
|
|
||||||
testStartVideoSettingRef.current = { ...tool.store.state.videoSetting }
|
|
||||||
|
|
||||||
|
const resolutionInfo = currentResolution ? ` (${currentResolution.label})` : ""
|
||||||
if (totalTests > 1) {
|
if (totalTests > 1) {
|
||||||
addToast({
|
addToast({
|
||||||
title: `批量测试 ${testIndex}/${totalTests}:已启动 ${mapConfig.label} 测试,正在自动监听结果...`,
|
title: `批量测试 ${testIndex}/${totalTests}${resolutionInfo}:已启动 ${mapConfig.label} 测试,正在自动监听结果...`,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
addToast({ title: `已启动 ${mapConfig.label} 测试,正在自动监听结果...` })
|
addToast({ title: `已启动 ${mapConfig.label} 测试${resolutionInfo},正在自动监听结果...` })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 开始自动监听文件更新
|
// 开始自动监听文件更新
|
||||||
@@ -730,6 +760,7 @@ export function FpsTest() {
|
|||||||
testStartTimestampRef.current = null
|
testStartTimestampRef.current = null
|
||||||
testStartTimeRef.current = null
|
testStartTimeRef.current = null
|
||||||
testStartVideoSettingRef.current = null
|
testStartVideoSettingRef.current = null
|
||||||
|
currentTestResolutionRef.current = null
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -746,14 +777,140 @@ export function FpsTest() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查是否启用分辨率组
|
||||||
|
if (isResolutionGroupEnabled && resolutionGroup.length === 0) {
|
||||||
|
addToast({ title: "请先添加分辨率到分辨率组", variant: "flat", color: "warning" })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const totalTests = batchTestCount
|
const totalTests = batchTestCount
|
||||||
batchTestAbortRef.current = false
|
batchTestAbortRef.current = false
|
||||||
setBatchTestResults([])
|
setBatchTestResults([])
|
||||||
batchTestResultsRef.current = []
|
batchTestResultsRef.current = []
|
||||||
|
|
||||||
if (totalTests > 1) {
|
// 如果启用了分辨率组,对每个分辨率进行批量测试
|
||||||
// 批量测试
|
if (isResolutionGroupEnabled && resolutionGroup.length > 0) {
|
||||||
setIsBatchTesting(true) // 设置批量测试状态
|
setIsBatchTesting(true)
|
||||||
|
const totalResolutions = resolutionGroup.length
|
||||||
|
const totalTestCount = totalResolutions * totalTests // 总测试次数
|
||||||
|
let globalTestIndex = 0
|
||||||
|
|
||||||
|
// 对每个分辨率进行批量测试
|
||||||
|
for (let resIndex = 0; resIndex < totalResolutions; resIndex++) {
|
||||||
|
if (batchTestAbortRef.current) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentResolution = resolutionGroup[resIndex]
|
||||||
|
// 为当前分辨率重置结果
|
||||||
|
batchTestResultsRef.current = []
|
||||||
|
|
||||||
|
// 对当前分辨率进行批量测试
|
||||||
|
for (let i = 1; i <= totalTests; i++) {
|
||||||
|
if (batchTestAbortRef.current) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
globalTestIndex++
|
||||||
|
setBatchTestProgress({ current: globalTestIndex, total: totalTestCount })
|
||||||
|
|
||||||
|
// 执行单次测试,第一次测试跳过5秒等待
|
||||||
|
const isFirstTest = resIndex === 0 && i === 1
|
||||||
|
const success = await runSingleTest(i, totalTests, isFirstTest, currentResolution)
|
||||||
|
|
||||||
|
if (!success && !batchTestAbortRef.current) {
|
||||||
|
addToast({
|
||||||
|
title: `分辨率 ${currentResolution.label} 批量测试 ${i}/${totalTests} 失败`,
|
||||||
|
variant: "flat",
|
||||||
|
color: "warning",
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果不是最后一次测试,等待5秒再继续
|
||||||
|
if (i < totalTests && !batchTestAbortRef.current) {
|
||||||
|
if (tool.state.autoCloseGame) {
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 3000))
|
||||||
|
try {
|
||||||
|
await invoke("kill_game").catch(() => {})
|
||||||
|
} catch (error) {
|
||||||
|
console.error("关闭游戏失败:", error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 5000))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 当前分辨率批量测试完成,计算平均值
|
||||||
|
const finalResults = batchTestResultsRef.current
|
||||||
|
if (!batchTestAbortRef.current && finalResults.length > 0) {
|
||||||
|
const validResults = finalResults.filter((r) => r.avg !== null || r.p1 !== null)
|
||||||
|
if (validResults.length > 0) {
|
||||||
|
const avgAvg =
|
||||||
|
validResults.reduce((sum, r) => sum + (r.avg || 0), 0) / validResults.length
|
||||||
|
const avgP1 = validResults.reduce((sum, r) => sum + (r.p1 || 0), 0) / validResults.length
|
||||||
|
|
||||||
|
const now = new Date()
|
||||||
|
const testDate = now.toISOString()
|
||||||
|
const month = String(now.getMonth() + 1).padStart(2, "0")
|
||||||
|
const day = String(now.getDate()).padStart(2, "0")
|
||||||
|
const hour = String(now.getHours()).padStart(2, "0")
|
||||||
|
const minute = String(now.getMinutes()).padStart(2, "0")
|
||||||
|
const second = String(now.getSeconds()).padStart(2, "0")
|
||||||
|
const testTime = `${month}/${day} ${hour}:${minute}:${second}`
|
||||||
|
|
||||||
|
let averageNote = `[分辨率:${currentResolution.label}]`
|
||||||
|
if (testNote) {
|
||||||
|
averageNote = `${testNote} ${averageNote}`
|
||||||
|
}
|
||||||
|
averageNote = `${averageNote} [批量${totalTests}次平均]`
|
||||||
|
|
||||||
|
fpsTest.addResult({
|
||||||
|
id: `${now.getTime()}-${Math.random().toString(36).slice(2, 11)}`,
|
||||||
|
testTime,
|
||||||
|
testDate,
|
||||||
|
mapName: mapConfig?.name || "unknown",
|
||||||
|
mapLabel: mapConfig?.label || "未知地图",
|
||||||
|
avg: avgAvg,
|
||||||
|
p1: avgP1,
|
||||||
|
rawResult: `分辨率${currentResolution.label}批量测试${totalTests}次平均值\n平均帧: ${avgAvg.toFixed(
|
||||||
|
1
|
||||||
|
)}\nP1低帧: ${avgP1.toFixed(1)}`,
|
||||||
|
videoSetting: tool.store.state.videoSetting,
|
||||||
|
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,
|
||||||
|
gpu: null,
|
||||||
|
monitor: null,
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
note: averageNote,
|
||||||
|
})
|
||||||
|
|
||||||
|
addToast({
|
||||||
|
title: `分辨率 ${currentResolution.label} 批量测试完成!平均值:avg ${avgAvg.toFixed(
|
||||||
|
1
|
||||||
|
)} FPS, p1 ${avgP1.toFixed(1)} FPS`,
|
||||||
|
color: "success",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setBatchTestProgress(null)
|
||||||
|
setBatchTestResults([])
|
||||||
|
setIsBatchTesting(false)
|
||||||
|
} else if (totalTests > 1) {
|
||||||
|
// 普通批量测试(不使用分辨率组)
|
||||||
|
setIsBatchTesting(true)
|
||||||
setBatchTestProgress({ current: 0, total: totalTests })
|
setBatchTestProgress({ current: 0, total: totalTests })
|
||||||
|
|
||||||
for (let i = 1; i <= totalTests; i++) {
|
for (let i = 1; i <= totalTests; i++) {
|
||||||
@@ -773,9 +930,7 @@ export function FpsTest() {
|
|||||||
|
|
||||||
// 如果不是最后一次测试,等待5秒再继续
|
// 如果不是最后一次测试,等待5秒再继续
|
||||||
if (i < totalTests && !batchTestAbortRef.current) {
|
if (i < totalTests && !batchTestAbortRef.current) {
|
||||||
// 确保游戏已关闭(如果自动关闭已启用,readResult中已经关闭了)
|
|
||||||
if (tool.state.autoCloseGame) {
|
if (tool.state.autoCloseGame) {
|
||||||
// 等待游戏关闭完成(readResult中延迟2秒关闭)
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 3000))
|
await new Promise((resolve) => setTimeout(resolve, 3000))
|
||||||
try {
|
try {
|
||||||
await invoke("kill_game").catch(() => {})
|
await invoke("kill_game").catch(() => {})
|
||||||
@@ -783,13 +938,11 @@ export function FpsTest() {
|
|||||||
console.error("关闭游戏失败:", error)
|
console.error("关闭游戏失败:", error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 等待5秒
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 5000))
|
await new Promise((resolve) => setTimeout(resolve, 5000))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 批量测试完成,计算平均值
|
// 批量测试完成,计算平均值
|
||||||
// 使用ref中收集的结果(确保获取到所有结果)
|
|
||||||
const finalResults = batchTestResultsRef.current
|
const finalResults = batchTestResultsRef.current
|
||||||
if (!batchTestAbortRef.current && finalResults.length > 0) {
|
if (!batchTestAbortRef.current && finalResults.length > 0) {
|
||||||
const validResults = finalResults.filter((r) => r.avg !== null || r.p1 !== null)
|
const validResults = finalResults.filter((r) => r.avg !== null || r.p1 !== null)
|
||||||
@@ -850,7 +1003,7 @@ export function FpsTest() {
|
|||||||
|
|
||||||
setBatchTestProgress(null)
|
setBatchTestProgress(null)
|
||||||
setBatchTestResults([])
|
setBatchTestResults([])
|
||||||
setIsBatchTesting(false) // 批量测试结束,重置状态
|
setIsBatchTesting(false)
|
||||||
} else {
|
} else {
|
||||||
// 单次测试
|
// 单次测试
|
||||||
await runSingleTest(1, 1, true)
|
await runSingleTest(1, 1, true)
|
||||||
@@ -965,20 +1118,9 @@ export function FpsTest() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 切换全屏/窗口化(仅更新本地状态,不修改视频配置文件)
|
|
||||||
const handleToggleFullscreen = () => {
|
|
||||||
setIsFullscreen(!isFullscreen)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置分辨率(仅更新本地状态,不修改视频配置文件)
|
|
||||||
const handleSetResolution = (width: string, height: string) => {
|
|
||||||
setResolutionWidth(width)
|
|
||||||
setResolutionHeight(height)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 应用预设分辨率
|
// 应用预设分辨率
|
||||||
const handlePresetResolution = (preset: { width: string; height: string; label: string }) => {
|
const handlePresetResolution = (preset: { width: string; height: string; label: string }) => {
|
||||||
void handleSetResolution(preset.width, preset.height)
|
fpsTest.setResolution(preset.width, preset.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -1198,7 +1340,7 @@ export function FpsTest() {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
aria-label="测试地图选择"
|
aria-label="测试地图选择"
|
||||||
size="md"
|
size="sm"
|
||||||
radius="lg"
|
radius="lg"
|
||||||
>
|
>
|
||||||
{BENCHMARK_MAPS.map((map, index) => (
|
{BENCHMARK_MAPS.map((map, index) => (
|
||||||
@@ -1215,7 +1357,7 @@ export function FpsTest() {
|
|||||||
onSelectionChange={(keys) => {
|
onSelectionChange={(keys) => {
|
||||||
const value = Array.from(keys)[0]
|
const value = Array.from(keys)[0]
|
||||||
if (value && !isMonitoring) {
|
if (value && !isMonitoring) {
|
||||||
setBatchTestCount(Number(value))
|
fpsTest.setBatchTestCount(Number(value))
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
isDisabled={isMonitoring}
|
isDisabled={isMonitoring}
|
||||||
@@ -1237,7 +1379,7 @@ export function FpsTest() {
|
|||||||
size="md"
|
size="md"
|
||||||
placeholder="输入测试备注"
|
placeholder="输入测试备注"
|
||||||
value={testNote}
|
value={testNote}
|
||||||
onValueChange={setTestNote}
|
onValueChange={fpsTest.setTestNote}
|
||||||
isDisabled={isMonitoring}
|
isDisabled={isMonitoring}
|
||||||
className="flex-1"
|
className="flex-1"
|
||||||
/>
|
/>
|
||||||
@@ -1245,6 +1387,7 @@ export function FpsTest() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{/* 启动项占满一行,右侧放置分辨率和全屏切换 */}
|
{/* 启动项占满一行,右侧放置分辨率和全屏切换 */}
|
||||||
<div className="flex items-start gap-4">
|
<div className="flex items-start gap-4">
|
||||||
{/* 自定义启动项 */}
|
{/* 自定义启动项 */}
|
||||||
@@ -1255,7 +1398,7 @@ export function FpsTest() {
|
|||||||
size="md"
|
size="md"
|
||||||
placeholder="输入自定义启动参数(可选)"
|
placeholder="输入自定义启动参数(可选)"
|
||||||
value={customLaunchOption}
|
value={customLaunchOption}
|
||||||
onValueChange={setCustomLaunchOption}
|
onValueChange={fpsTest.setCustomLaunchOption}
|
||||||
isDisabled={isMonitoring}
|
isDisabled={isMonitoring}
|
||||||
className="flex-1"
|
className="flex-1"
|
||||||
/>
|
/>
|
||||||
@@ -1266,8 +1409,32 @@ export function FpsTest() {
|
|||||||
<div className="flex items-end gap-2 shrink-0">
|
<div className="flex items-end gap-2 shrink-0">
|
||||||
{/* 分辨率设置 */}
|
{/* 分辨率设置 */}
|
||||||
<div className="flex flex-col gap-1.5">
|
<div className="flex flex-col gap-1.5">
|
||||||
<div className="flex items-center gap-1">
|
{/* 工具栏:分辨率标签 + 按钮 */}
|
||||||
<label className="text-xs text-default-500">分辨率</label>
|
<div className="flex items-center gap-2">
|
||||||
|
<label className="text-xs text-default-500 shrink-0">分辨率</label>
|
||||||
|
<div className="flex flex-wrap items-center gap-1">
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant={isResolutionGroupEnabled ? "solid" : "flat"}
|
||||||
|
color={isResolutionGroupEnabled ? "primary" : "default"}
|
||||||
|
onPress={() => {
|
||||||
|
if (!isMonitoring) {
|
||||||
|
const newValue = !isResolutionGroupEnabled
|
||||||
|
fpsTest.setIsResolutionGroupEnabled(newValue)
|
||||||
|
// 启用分辨率组时,自动启用分辨率功能
|
||||||
|
if (newValue && !isResolutionEnabled) {
|
||||||
|
fpsTest.setIsResolutionEnabled(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
isDisabled={isMonitoring}
|
||||||
|
className="h-5 min-w-[40px] px-1.5 text-xs font-medium"
|
||||||
|
>
|
||||||
|
<List size={14} />
|
||||||
|
多组
|
||||||
|
</Button>
|
||||||
|
{!isResolutionGroupEnabled && (
|
||||||
|
<>
|
||||||
<Dropdown placement="bottom-end" className="min-w-fit">
|
<Dropdown placement="bottom-end" className="min-w-fit">
|
||||||
<DropdownTrigger>
|
<DropdownTrigger>
|
||||||
<Button
|
<Button
|
||||||
@@ -1296,54 +1463,97 @@ export function FpsTest() {
|
|||||||
size="sm"
|
size="sm"
|
||||||
variant={isResolutionEnabled ? "solid" : "flat"}
|
variant={isResolutionEnabled ? "solid" : "flat"}
|
||||||
color={isResolutionEnabled ? "primary" : "default"}
|
color={isResolutionEnabled ? "primary" : "default"}
|
||||||
onPress={() => setIsResolutionEnabled(!isResolutionEnabled)}
|
onPress={() => fpsTest.setIsResolutionEnabled(!isResolutionEnabled)}
|
||||||
isDisabled={isMonitoring}
|
isDisabled={isMonitoring}
|
||||||
className="h-5 min-w-[40px] px-1.5 text-xs font-medium"
|
className="h-5 min-w-[40px] px-1.5 text-xs font-medium"
|
||||||
>
|
>
|
||||||
{isResolutionEnabled ? "启用" : "关闭"}
|
{isResolutionEnabled ? "启用" : "关闭"}
|
||||||
</Button>
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{isResolutionGroupEnabled && (
|
||||||
|
<>
|
||||||
|
<Dropdown placement="bottom-end" className="min-w-fit">
|
||||||
|
<DropdownTrigger>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="flat"
|
||||||
|
className="h-5 min-w-[40px] px-1.5 text-xs"
|
||||||
|
isDisabled={isMonitoring}
|
||||||
|
>
|
||||||
|
预设
|
||||||
|
</Button>
|
||||||
|
</DropdownTrigger>
|
||||||
|
<DropdownMenu aria-label="预设分辨率" className="">
|
||||||
|
{PRESET_RESOLUTIONS.map(
|
||||||
|
(preset: { width: string; height: string; label: string }) => (
|
||||||
|
<DropdownItem
|
||||||
|
key={preset.label}
|
||||||
|
onPress={() => {
|
||||||
|
if (!isMonitoring) {
|
||||||
|
fpsTest.addResolutionToGroup({
|
||||||
|
width: preset.width,
|
||||||
|
height: preset.height,
|
||||||
|
label: preset.label,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{preset.label}
|
||||||
|
</DropdownItem>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</DropdownMenu>
|
||||||
|
</Dropdown>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="flat"
|
||||||
|
onPress={() => {
|
||||||
|
if (!isMonitoring && resolutionWidth && resolutionHeight) {
|
||||||
|
fpsTest.addResolutionToGroup({
|
||||||
|
width: resolutionWidth,
|
||||||
|
height: resolutionHeight,
|
||||||
|
label: `${resolutionWidth}x${resolutionHeight}`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
isDisabled={isMonitoring || !resolutionWidth || !resolutionHeight}
|
||||||
|
className="h-5 min-w-[40px] px-1.5 text-xs"
|
||||||
|
>
|
||||||
|
添加
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* 主体:宽高输入框 + 全屏按钮(始终显示) */}
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<Input
|
<Input
|
||||||
size="md"
|
size="sm"
|
||||||
type="number"
|
type="number"
|
||||||
placeholder="宽"
|
placeholder="宽"
|
||||||
value={resolutionWidth}
|
value={resolutionWidth}
|
||||||
onValueChange={setResolutionWidth}
|
onValueChange={(val) => fpsTest.setResolution(val, resolutionHeight)}
|
||||||
isDisabled={!isResolutionEnabled || isMonitoring}
|
isDisabled={isResolutionGroupEnabled ? isMonitoring : (!isResolutionEnabled || isMonitoring)}
|
||||||
className="w-20"
|
className="w-20"
|
||||||
onBlur={() => {
|
|
||||||
if (resolutionWidth && resolutionHeight) {
|
|
||||||
void handleSetResolution(resolutionWidth, resolutionHeight)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<span className="text-xs text-default-400">x</span>
|
<span className="text-xs text-default-400">x</span>
|
||||||
<Input
|
<Input
|
||||||
size="md"
|
size="sm"
|
||||||
type="number"
|
type="number"
|
||||||
placeholder="高"
|
placeholder="高"
|
||||||
value={resolutionHeight}
|
value={resolutionHeight}
|
||||||
onValueChange={setResolutionHeight}
|
onValueChange={(val) => fpsTest.setResolution(resolutionWidth, val)}
|
||||||
isDisabled={!isResolutionEnabled || isMonitoring}
|
isDisabled={isResolutionGroupEnabled ? isMonitoring : (!isResolutionEnabled || isMonitoring)}
|
||||||
className="w-20"
|
className="w-20"
|
||||||
onBlur={() => {
|
|
||||||
if (resolutionWidth && resolutionHeight) {
|
|
||||||
void handleSetResolution(resolutionWidth, resolutionHeight)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 全屏/窗口化切换 */}
|
|
||||||
<div className="flex flex-col gap-1.5">
|
|
||||||
<div className="h-5" /> {/* 对齐标签高度 */}
|
|
||||||
<Button
|
<Button
|
||||||
size="md"
|
size="sm"
|
||||||
variant={isFullscreen ? "solid" : "flat"}
|
variant={isFullscreen ? "solid" : "flat"}
|
||||||
color={isFullscreen ? "primary" : "default"}
|
color={isFullscreen ? "primary" : "default"}
|
||||||
onPress={handleToggleFullscreen}
|
onPress={() => fpsTest.setIsFullscreen(!isFullscreen)}
|
||||||
isDisabled={!isResolutionEnabled || isMonitoring}
|
isDisabled={!isResolutionEnabled || isMonitoring}
|
||||||
className="font-medium"
|
className="font-medium"
|
||||||
>
|
>
|
||||||
@@ -1352,6 +1562,7 @@ export function FpsTest() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* 工具栏:按钮靠右对齐 */}
|
{/* 工具栏:按钮靠右对齐 */}
|
||||||
<div className="flex items-center justify-start gap-2">
|
<div className="flex items-center justify-start gap-2">
|
||||||
@@ -1404,6 +1615,30 @@ export function FpsTest() {
|
|||||||
手动读取结果
|
手动读取结果
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
{isResolutionGroupEnabled && (
|
||||||
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
|
{resolutionGroup.map((res, index) => (
|
||||||
|
<Chip
|
||||||
|
key={index}
|
||||||
|
size="sm"
|
||||||
|
variant="flat"
|
||||||
|
color="primary"
|
||||||
|
onClose={() => {
|
||||||
|
if (!isMonitoring) {
|
||||||
|
fpsTest.removeResolutionFromGroup(index)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
isCloseable={!isMonitoring}
|
||||||
|
>
|
||||||
|
{res.label}
|
||||||
|
</Chip>
|
||||||
|
))}
|
||||||
|
{resolutionGroup.length === 0 && (
|
||||||
|
<span className="text-xs text-default-400">暂无分辨率</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{isMonitoring && (
|
{isMonitoring && (
|
||||||
<Chip size="lg" color="primary" variant="flat" className="text-xs">
|
<Chip size="lg" color="primary" variant="flat" className="text-xs">
|
||||||
正在监听中...
|
正在监听中...
|
||||||
@@ -1482,3 +1717,4 @@ export function FpsTest() {
|
|||||||
</Card>
|
</Card>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,26 @@ export interface FpsTestResult {
|
|||||||
note?: string // 备注(可选,用于向后兼容)
|
note?: string // 备注(可选,用于向后兼容)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ResolutionGroupItem {
|
||||||
|
width: string
|
||||||
|
height: string
|
||||||
|
label: string
|
||||||
|
}
|
||||||
|
|
||||||
const defaultValue = {
|
const defaultValue = {
|
||||||
results: [] as FpsTestResult[],
|
results: [] as FpsTestResult[],
|
||||||
|
// FpsTest配置数据
|
||||||
|
config: {
|
||||||
|
batchTestCount: 1, // 批量测试次数
|
||||||
|
isResolutionGroupEnabled: false, // 是否启用分辨率组
|
||||||
|
resolutionGroup: [] as ResolutionGroupItem[], // 分辨率组列表
|
||||||
|
testNote: "", // 测试备注
|
||||||
|
customLaunchOption: "", // 自定义启动项
|
||||||
|
isResolutionEnabled: true, // 是否启用分辨率和全屏设置
|
||||||
|
resolutionWidth: "", // 分辨率宽度
|
||||||
|
resolutionHeight: "", // 分辨率高度
|
||||||
|
isFullscreen: true, // 全屏模式
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fpsTestStore = store(
|
export const fpsTestStore = store(
|
||||||
@@ -46,6 +64,17 @@ export const useFpsTestStore = () => {
|
|||||||
removeResult,
|
removeResult,
|
||||||
clearResults,
|
clearResults,
|
||||||
updateNote,
|
updateNote,
|
||||||
|
// 配置相关方法
|
||||||
|
setBatchTestCount,
|
||||||
|
setIsResolutionGroupEnabled,
|
||||||
|
setResolutionGroup,
|
||||||
|
addResolutionToGroup,
|
||||||
|
removeResolutionFromGroup,
|
||||||
|
setTestNote,
|
||||||
|
setCustomLaunchOption,
|
||||||
|
setIsResolutionEnabled,
|
||||||
|
setResolution,
|
||||||
|
setIsFullscreen,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,3 +103,56 @@ const updateNote = (id: string, note: string) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 配置相关方法
|
||||||
|
const setBatchTestCount = (count: number) => {
|
||||||
|
fpsTestStore.state.config.batchTestCount = count
|
||||||
|
}
|
||||||
|
|
||||||
|
const setIsResolutionGroupEnabled = (enabled: boolean) => {
|
||||||
|
fpsTestStore.state.config.isResolutionGroupEnabled = enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
const setResolutionGroup = (group: ResolutionGroupItem[]) => {
|
||||||
|
fpsTestStore.state.config.resolutionGroup = group
|
||||||
|
}
|
||||||
|
|
||||||
|
const addResolutionToGroup = (resolution: ResolutionGroupItem) => {
|
||||||
|
// 检查是否已存在相同分辨率
|
||||||
|
const exists = fpsTestStore.state.config.resolutionGroup.some(
|
||||||
|
(r) => r.width === resolution.width && r.height === resolution.height
|
||||||
|
)
|
||||||
|
if (!exists) {
|
||||||
|
fpsTestStore.state.config.resolutionGroup = [
|
||||||
|
...fpsTestStore.state.config.resolutionGroup,
|
||||||
|
resolution,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeResolutionFromGroup = (index: number) => {
|
||||||
|
fpsTestStore.state.config.resolutionGroup = fpsTestStore.state.config.resolutionGroup.filter(
|
||||||
|
(_, i) => i !== index
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const setTestNote = (note: string) => {
|
||||||
|
fpsTestStore.state.config.testNote = note
|
||||||
|
}
|
||||||
|
|
||||||
|
const setCustomLaunchOption = (option: string) => {
|
||||||
|
fpsTestStore.state.config.customLaunchOption = option
|
||||||
|
}
|
||||||
|
|
||||||
|
const setIsResolutionEnabled = (enabled: boolean) => {
|
||||||
|
fpsTestStore.state.config.isResolutionEnabled = enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
const setResolution = (width: string, height: string) => {
|
||||||
|
fpsTestStore.state.config.resolutionWidth = width
|
||||||
|
fpsTestStore.state.config.resolutionHeight = height
|
||||||
|
}
|
||||||
|
|
||||||
|
const setIsFullscreen = (isFullscreen: boolean) => {
|
||||||
|
fpsTestStore.state.config.isFullscreen = isFullscreen
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user