diff --git a/bun.lockb b/bun.lockb index d1c7693..52a6cbe 100755 Binary files a/bun.lockb and b/bun.lockb differ 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")) }