From 543c3344d11093ed80eab3bd28b3ca9c82b8567e Mon Sep 17 00:00:00 2001 From: Purp1e <47248616+Purple-CSGO@users.noreply.github.com> Date: Wed, 5 Nov 2025 02:24:17 +0800 Subject: [PATCH] [feat] fps benchmark one-key testing --- bun.lockb | Bin 425132 -> 425085 bytes package.json | 28 +-- src-tauri/Cargo.lock | 172 +++++++-------- src-tauri/src/cmds.rs | 67 ++++++ src-tauri/src/main.rs | 2 + src/app/(main)/gear/page.tsx | 44 ++-- src/app/globals.css | 4 + src/components/cstb/FpsTest.tsx | 371 ++++++++++++++++++++++++++++++++ src/store/index.ts | 5 +- 9 files changed, 562 insertions(+), 131 deletions(-) create mode 100644 src/components/cstb/FpsTest.tsx diff --git a/bun.lockb b/bun.lockb index d1c76930efcb2593784ed625cdb31f5863545f9d..52a6cbe627a856d4a89bc5fd88d3b16b6ce1645a 100755 GIT binary patch delta 40034 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 SY&_Hblvvrfugzuq&j$d+Q$<<; delta 40268 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 diff --git a/package.json b/package.json index ca35777..20e0c36 100644 --- a/package.json +++ b/package.json @@ -22,21 +22,21 @@ "@icon-park/react": "^1.4.2", "@reactuses/core": "6.0.1", "@supabase/ssr": "0.6.1", - "@tauri-apps/api": "2.4.0", + "@tauri-apps/api": "^2.9.0", "@tauri-apps/plugin-autostart": "^2.5.1", - "@tauri-apps/plugin-cli": "~2.2.1", - "@tauri-apps/plugin-clipboard-manager": "2.2.2", - "@tauri-apps/plugin-deep-link": "~2.2.1", - "@tauri-apps/plugin-dialog": "~2.2.2", - "@tauri-apps/plugin-fs": "2.2.0", - "@tauri-apps/plugin-global-shortcut": "2.2.0", - "@tauri-apps/plugin-http": "2.4.2", - "@tauri-apps/plugin-notification": "2.2.2", - "@tauri-apps/plugin-os": "2.2.1", - "@tauri-apps/plugin-process": "2.2.0", - "@tauri-apps/plugin-shell": "~2.2.2", + "@tauri-apps/plugin-cli": "^2.4.1", + "@tauri-apps/plugin-clipboard-manager": "^2.3.2", + "@tauri-apps/plugin-deep-link": "^2.4.5", + "@tauri-apps/plugin-dialog": "^2.4.2", + "@tauri-apps/plugin-fs": "^2.4.4", + "@tauri-apps/plugin-global-shortcut": "^2.3.1", + "@tauri-apps/plugin-http": "^2.5.4", + "@tauri-apps/plugin-notification": "^2.3.3", + "@tauri-apps/plugin-os": "^2.3.2", + "@tauri-apps/plugin-process": "^2.3.1", + "@tauri-apps/plugin-shell": "^2.3.3", "@tauri-apps/plugin-store": "^2.4.1", - "@tauri-store/valtio": "2.1.1", + "@tauri-store/valtio": "^3.2.0", "@types/throttle-debounce": "^5.0.2", "ahooks": "^3.9.6", "framer-motion": "^12.23.24", @@ -51,7 +51,7 @@ }, "devDependencies": { "@tailwindcss/postcss": "^4.1.16", - "@tauri-apps/cli": "^2.9.2", + "@tauri-apps/cli": "^2.9.3", "@testing-library/dom": "^10.4.1", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.0", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 57f3a31..3ae7431 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -44,9 +44,9 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -540,9 +540,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.43" +version = "1.2.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2" +checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3" dependencies = [ "find-msvc-tools", "shlex", @@ -607,18 +607,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.50" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623" +checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.50" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0" +checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" dependencies = [ "anstream", "anstyle", @@ -2051,9 +2051,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -2064,9 +2064,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -2077,11 +2077,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -2092,42 +2091,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -2216,9 +2211,9 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "iri-string" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" dependencies = [ "memchr", "serde", @@ -2311,9 +2306,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "js-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", @@ -2450,9 +2445,9 @@ checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "litrs" @@ -2589,9 +2584,9 @@ dependencies = [ [[package]] name = "moxcms" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692af879e4d9383c0fd9dec15524af6b6977c8bf1c6b278a4526d5341347c574" +checksum = "0fbdd3d7436f8b5e892b8b7ea114271ff0fa00bc5acae845d53b07d498616ef6" dependencies = [ "num-traits", "pxfm", @@ -3446,9 +3441,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -4019,9 +4014,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.34" +version = "0.23.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9586e9ee2b4f8fab52a0048ca7334d7024eef48e2cb9407e3497bb7cab7fa7" +checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" dependencies = [ "once_cell", "ring", @@ -4033,9 +4028,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" dependencies = [ "web-time", "zeroize", @@ -4043,9 +4038,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.7" +version = "0.103.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ "ring", "rustls-pki-types", @@ -4111,9 +4106,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" +checksum = "1317c3bf3e7df961da95b0a56a172a02abead31276215a0497241a7624b487ce" dependencies = [ "dyn-clone", "ref-cast", @@ -4315,7 +4310,7 @@ dependencies = [ "indexmap 1.9.3", "indexmap 2.12.0", "schemars 0.9.0", - "schemars 1.0.4", + "schemars 1.0.5", "serde_core", "serde_json", "serde_with_macros", @@ -5423,9 +5418,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -5496,9 +5491,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.16" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" dependencies = [ "bytes", "futures-core", @@ -5785,9 +5780,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-segmentation" @@ -5884,9 +5879,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version-compare" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" [[package]] name = "version_check" @@ -5956,9 +5951,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", @@ -5967,25 +5962,11 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.108", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-futures" -version = "0.4.54" +version = "0.4.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" +checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" dependencies = [ "cfg-if", "js-sys", @@ -5996,9 +5977,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6006,22 +5987,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn 2.0.108", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] @@ -6114,9 +6095,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" dependencies = [ "js-sys", "wasm-bindgen", @@ -6178,9 +6159,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8" +checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" dependencies = [ "rustls-pki-types", ] @@ -6755,9 +6736,9 @@ dependencies = [ [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "wry" @@ -6850,11 +6831,10 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -6862,9 +6842,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", @@ -6983,9 +6963,9 @@ checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -6994,9 +6974,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -7005,9 +6985,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", diff --git a/src-tauri/src/cmds.rs b/src-tauri/src/cmds.rs index fc34809..79ad95e 100644 --- a/src-tauri/src/cmds.rs +++ b/src-tauri/src/cmds.rs @@ -6,6 +6,8 @@ use crate::wrap_err; use anyhow::Result; use std::fs::File; use std::fs; +use std::path::Path; +use std::io::{BufRead, BufReader}; use tauri::path::BaseDirectory; use tauri::Manager; @@ -188,3 +190,68 @@ pub async fn analyze_replay(app: tauri::AppHandle, path: &str) -> Result Result { + // cs_path 是类似 "game\bin\win64" 的路径,需要向上找到 game\csgo\console.log + let path = Path::new(cs_path); + // 向上找到 game 目录 + if let Some(game_dir) = path.ancestors().find(|p| { + p.file_name() + .and_then(|n| n.to_str()) + .map(|n| n == "game") + .unwrap_or(false) + }) { + let console_log_path = game_dir.join("csgo").join("console.log"); + Ok(console_log_path.to_string_lossy().to_string()) + } else { + Err("无法找到 game 目录".to_string()) + } +} + +#[tauri::command] +pub fn read_vprof_report(console_log_path: &str) -> Result { + let path = Path::new(console_log_path); + + if !path.exists() { + return Err("console.log 文件不存在".to_string()); + } + + let file = File::open(path).map_err(|e| format!("无法打开文件: {}", e))?; + let reader = BufReader::new(file); + + let mut vprof_lines = Vec::new(); + let mut in_vprof_section = false; + let mut empty_line_count = 0; + + for line_result in reader.lines() { + let line = line_result.map_err(|e| format!("读取行错误: {}", e))?; + + // 检测 [VProf] 标记 + if line.contains("[VProf]") { + in_vprof_section = true; + empty_line_count = 0; + vprof_lines.push(line.clone()); + } else if in_vprof_section { + // 如果在 VProf 部分中 + if line.trim().is_empty() { + empty_line_count += 1; + // 如果遇到两个连续的空行,结束 VProf 部分 + if empty_line_count >= 2 { + break; + } + vprof_lines.push(line.clone()); + } else { + empty_line_count = 0; + vprof_lines.push(line.clone()); + } + } + } + + if vprof_lines.is_empty() { + return Err("未找到 [VProf] 报告".to_string()); + } + + Ok(vprof_lines.join("\n")) +} diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 900f83e..69fafa8 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -132,6 +132,8 @@ fn main() { cmds::set_cs2_video_config, cmds::check_path, cmds::analyze_replay, + cmds::get_console_log_path, + cmds::read_vprof_report, on_button_clicked ]) .run(tauri::generate_context!()) diff --git a/src/app/(main)/gear/page.tsx b/src/app/(main)/gear/page.tsx index 887370d..0e748d4 100644 --- a/src/app/(main)/gear/page.tsx +++ b/src/app/(main)/gear/page.tsx @@ -12,28 +12,34 @@ 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 ( - - - - 硬件 - - - {/* - - 云同步 - */} - - 刷新 - - - +
+
+ + + + 硬件 + + + {/* + + 云同步 + */} + + 刷新 + + + - - - - + + + + + +
+
) } diff --git a/src/app/globals.css b/src/app/globals.css index 58fda60..3f3a112 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -24,4 +24,8 @@ a { /* 隐藏滚动条 */ .hide-scrollbar::-webkit-scrollbar { display: none; +} +.hide-scrollbar { + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ } \ No newline at end of file diff --git a/src/components/cstb/FpsTest.tsx b/src/components/cstb/FpsTest.tsx new file mode 100644 index 0000000..314e356 --- /dev/null +++ b/src/components/cstb/FpsTest.tsx @@ -0,0 +1,371 @@ +"use client" +import { useSteamStore } from "@/store/steam" +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 { useState, useEffect, useRef, useCallback } from "react" +import { TestTube, Power } from "@icon-park/react" + +const BENCHMARK_MAPS = [ + { + name: "de_dust2_benchmark", + workshopId: "3240880604", + map: "de_dust2_benchmark", + label: "Dust2 Benchmark", + }, + { + name: "de_ancient", + workshopId: "3472126051", + map: "de_ancient", + label: "Ancient", + }, +] + +// 解析性能报告,提取时间戳和性能数据 +function parseVProfReport(rawReport: string): { timestamp: string; data: string } | null { + if (!rawReport) return null + + const lines = rawReport.split("\n") + let timestamp = "" + let inPerformanceSection = false + const performanceLines: string[] = [] + + for (const line of lines) { + // 提取时间戳:格式如 "11/05 01:51:27 [VProf] -- Performance report --" + const timestampMatch = line.match( + /(\d{2}\/\d{2}\s+\d{2}:\d{2}:\d{2})\s+\[VProf\]\s+--\s+Performance\s+report\s+--/ + ) + if (timestampMatch) { + timestamp = timestampMatch[1] + inPerformanceSection = true + // 也包含 Performance report 这一行,但移除时间戳 + const lineWithoutTimestamp = line.trim().replace(/^\d{2}\/\d{2}\s+\d{2}:\d{2}:\d{2}\s+/, "") + performanceLines.push(lineWithoutTimestamp) + continue + } + + // 如果在性能报告部分 + if (inPerformanceSection) { + const trimmedLine = line.trim() + + // 只收集包含 [VProf] 的行 + if (trimmedLine.includes("[VProf]")) { + // 移除行首的时间戳(格式:MM/DD HH:mm:ss ) + // 例如:"11/05 02:13:56 [VProf] ..." -> "[VProf] ..." + const lineWithoutTimestamp = trimmedLine.replace(/^\d{2}\/\d{2}\s+\d{2}:\d{2}:\d{2}\s+/, "") + performanceLines.push(lineWithoutTimestamp) + } + // 如果遇到空行且已经有数据,可能是报告结束,但不直接结束,因为可能还有更多数据 + // 如果后续没有 [VProf] 行的数据,空行会被过滤掉 + } + } + + if (performanceLines.length === 0) return null + + return { + timestamp, + data: performanceLines.join("\n").trim(), + } +} + +// 比较时间戳(格式:MM/DD HH:mm:ss) +// 返回 true 如果 timestamp1 晚于 timestamp2 +function compareTimestamps(timestamp1: string, timestamp2: string): boolean { + // 解析时间戳:MM/DD HH:mm:ss + const parseTimestamp = (ts: string) => { + const match = ts.match(/(\d{2})\/(\d{2})\s+(\d{2}):(\d{2}):(\d{2})/) + if (!match) return null + const [, month, day, hour, minute, second] = match.map(Number) + return { month, day, hour, minute, second } + } + + const ts1 = parseTimestamp(timestamp1) + const ts2 = parseTimestamp(timestamp2) + + if (!ts1 || !ts2) return false + + // 使用当前年份作为基准 + const now = new Date() + const currentYear = now.getFullYear() + + // 创建日期对象,尝试当前年份 + let date1 = new Date(currentYear, ts1.month - 1, ts1.day, ts1.hour, ts1.minute, ts1.second) + let date2 = new Date(currentYear, ts2.month - 1, ts2.day, ts2.hour, ts2.minute, ts2.second) + + // 如果 date1 早于 date2,可能是跨年了(比如 date1 是 1月,date2 是 12月) + // 在这种情况下,给 date1 加一年 + if (date1 < date2) { + // 检查是否可能是跨年(月份相差很大) + const monthDiff = (ts1.month - ts2.month + 12) % 12 + if (monthDiff > 6) { + // 可能是跨年,给 date1 加一年 + date1 = new Date(currentYear + 1, ts1.month - 1, ts1.day, ts1.hour, ts1.minute, ts1.second) + } + } + + return date1 > date2 +} + +export function FpsTest() { + const steam = useSteamStore() + const [testing, setTesting] = useState(false) + const [testResult, setTestResult] = useState(null) + const [testTimestamp, setTestTimestamp] = useState(null) + const [selectedMap, setSelectedMap] = useState(null) + const [autoCloseGame, setAutoCloseGame] = useState(false) + const [isMonitoring, setIsMonitoring] = useState(false) + const monitoringIntervalRef = useRef(null) + // 记录测试开始的时间戳(用于过滤旧数据) + const testStartTimestampRef = useRef(null) + + // 读取结果函数 + const readResult = useCallback( + async (silent = false): Promise => { + if (!steam.state.cs2Dir) { + if (!silent) { + addToast({ title: "请先配置 CS2 路径", variant: "flat" }) + } + return false + } + + try { + // 获取 console.log 路径 + const consoleLogPath = await invoke("get_console_log_path", { + csPath: steam.state.cs2Dir, + }) + + // 读取 VProf 报告 + const report = await invoke("read_vprof_report", { + consoleLogPath: consoleLogPath, + }) + + if (report && report.trim().length > 0) { + const parsed = parseVProfReport(report) + if (parsed) { + // 如果设置了测试开始时间且是自动监听(silent=true),验证报告时间戳是否晚于测试开始时间 + // 手动读取(silent=false)时允许读取任何结果 + if (silent && testStartTimestampRef.current) { + // 如果报告时间戳早于或等于测试开始时间,则视为旧数据,忽略 + if (!compareTimestamps(parsed.timestamp, testStartTimestampRef.current)) { + // 这是旧数据,不处理 + return false + } + } + + setTestResult(parsed.data) + setTestTimestamp(parsed.timestamp) + // 成功读取后,清除测试开始时间戳(测试已完成) + testStartTimestampRef.current = null + if (!silent) { + addToast({ title: "已读取测试结果" }) + } + return true + } else if (!silent) { + addToast({ + title: "未能解析测试结果", + variant: "flat", + }) + } + } else if (!silent) { + addToast({ + title: "未能读取测试结果,请确保测试已完成", + variant: "flat", + }) + } + return false + } catch (error) { + if (!silent) { + console.error("读取结果失败:", error) + addToast({ + title: `读取结果失败: ${error instanceof Error ? error.message : String(error)}`, + variant: "flat", + }) + } + return false + } + }, + [steam.state.cs2Dir] + ) + + // 关闭游戏 + const closeGame = useCallback(async () => { + try { + await invoke("kill_game") + addToast({ title: "已关闭CS2" }) + setIsMonitoring(false) + if (monitoringIntervalRef.current) { + clearInterval(monitoringIntervalRef.current) + monitoringIntervalRef.current = null + } + } catch (error) { + console.error("关闭游戏失败:", error) + addToast({ + title: `关闭游戏失败: ${error instanceof Error ? error.message : String(error)}`, + variant: "flat", + }) + } + }, []) + + // 开始监控文件更新 + useEffect(() => { + if (isMonitoring && steam.state.cs2Dir) { + // 每2秒检查一次文件更新 + monitoringIntervalRef.current = setInterval(async () => { + const success = await readResult(true) // 静默读取 + if (success) { + // 读取成功,停止监控 + setIsMonitoring(false) + if (monitoringIntervalRef.current) { + clearInterval(monitoringIntervalRef.current) + monitoringIntervalRef.current = null + } + + // 如果启用了自动关闭游戏,则关闭游戏 + if (autoCloseGame) { + setTimeout(() => { + void closeGame() + }, 2000) // 延迟2秒关闭,让用户看到结果 + } + } + }, 2000) // 每2秒检查一次 + } else { + // 停止监控 + if (monitoringIntervalRef.current) { + clearInterval(monitoringIntervalRef.current) + monitoringIntervalRef.current = null + } + } + + // 清理函数 + return () => { + if (monitoringIntervalRef.current) { + clearInterval(monitoringIntervalRef.current) + monitoringIntervalRef.current = null + } + } + }, [isMonitoring, steam.state.cs2Dir, autoCloseGame, readResult, closeGame]) + + const startTest = async (mapConfig: (typeof BENCHMARK_MAPS)[0]) => { + if (!steam.state.steamDir || !steam.state.cs2Dir) { + addToast({ title: "请先配置 Steam 和 CS2 路径", variant: "flat", color: "warning" }) + return + } + + setTesting(true) + setSelectedMap(mapConfig.name) + setTestResult(null) + setTestTimestamp(null) + + // 记录测试开始时间戳(格式:MM/DD HH:mm:ss) + const now = new Date() + 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") + testStartTimestampRef.current = `${month}/${day} ${hour}:${minute}:${second}` + + try { + const launchOption = `-allow_third_party_software -condebug -conclearlog +map_workshop ${mapConfig.workshopId} ${mapConfig.map}` + + // 启动游戏 + await invoke("launch_game", { + steamPath: `${steam.state.steamDir}\\steam.exe`, + launchOption: launchOption, + server: "worldwide", + }) + + addToast({ title: `已启动 ${mapConfig.label} 测试,正在自动监听结果...` }) + setTesting(false) + + // 开始自动监听文件更新 + setIsMonitoring(true) + } catch (error) { + console.error("启动测试失败:", error) + addToast({ + title: `启动测试失败: ${error instanceof Error ? error.message : String(error)}`, + variant: "flat", + }) + setTesting(false) + setIsMonitoring(false) + // 启动失败,清除测试开始时间戳 + testStartTimestampRef.current = null + } + } + + return ( + + + + 帧数测试 + + + +
+
+ {BENCHMARK_MAPS.map((mapConfig) => ( + + ))} + + + + 测试完成自动关闭游戏 + + {isMonitoring && ( + + 正在监听中... + + )} +
+ + {testResult && ( +
+
+ 测试结果 + {testTimestamp && ( + + 测试时间: {testTimestamp} + + )} +
+
+                {testResult}
+              
+
+ )} +
+
+
+ ) +} diff --git a/src/store/index.ts b/src/store/index.ts index bd09a09..3480e6a 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -1,5 +1,5 @@ import { appConfigDir } from "@tauri-apps/api/path" -import { setStoreCollectionPath } from "@tauri-store/valtio" +import { commands } from "@tauri-store/shared" import { appStore } from "./app" import { steamStore } from "./steam" import { toolStore } from "./tool" @@ -10,5 +10,6 @@ export async function init() { await toolStore.start() await steamStore.start() const appConfigDirPath = await appConfigDir() - await setStoreCollectionPath(path.resolve(appConfigDirPath, "cstb")) + const setPath = commands.setStoreCollectionPath("valtio") + await setPath(path.resolve(appConfigDirPath, "cstb")) }