diff --git a/Cargo.lock b/Cargo.lock index 8f8a99f..d3a4864 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -59,7 +59,7 @@ dependencies = [ "accesskit_consumer", "hashbrown", "objc2 0.5.2", - "objc2-app-kit", + "objc2-app-kit 0.2.2", "objc2-foundation 0.2.2", ] @@ -167,19 +167,21 @@ dependencies = [ [[package]] name = "arboard" -version = "3.4.1" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df099ccb16cd014ff054ac1bf392c67feeef57164b05c42f037cd40f5d4357f4" +checksum = "c1df21f715862ede32a0c525ce2ca4d52626bb0007f8c18b87a384503ac33e70" dependencies = [ "clipboard-win", - "core-graphics", "image", "log", - "objc2 0.5.2", - "objc2-app-kit", - "objc2-foundation 0.2.2", + "objc2 0.6.0", + "objc2-app-kit 0.3.0", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation 0.3.0", "parking_lot", - "windows-sys 0.48.0", + "percent-encoding", + "windows-sys 0.59.0", "x11rb", ] @@ -500,9 +502,9 @@ dependencies = [ [[package]] name = "bytemuck_derive" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ff22c2722516255d1823ce3cc4bc0b154dbc9364be5c905d6baa6eccbbc8774" +checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" dependencies = [ "proc-macro2", "quote", @@ -558,9 +560,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.17" +version = "1.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" +checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c" dependencies = [ "jobserver", "libc", @@ -700,25 +702,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -828,7 +811,7 @@ dependencies = [ "js-sys", "log", "objc2 0.5.2", - "objc2-app-kit", + "objc2-app-kit 0.2.2", "objc2-foundation 0.2.2", "parking_lot", "percent-encoding", @@ -900,6 +883,21 @@ dependencies = [ "winit", ] +[[package]] +name = "egui_extras" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624659a2e972a46f4d5f646557906c55f1cd5a0836eddbe610fdf1afba1b4226" +dependencies = [ + "ahash", + "egui", + "enum-map", + "image", + "log", + "mime_guess2", + "profiling", +] + [[package]] name = "egui_glow" version = "0.31.1" @@ -918,12 +916,6 @@ dependencies = [ "winit", ] -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - [[package]] name = "emath" version = "0.31.1" @@ -939,6 +931,27 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" +[[package]] +name = "enum-map" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" +dependencies = [ + "enum-map-derive", + "serde", +] + +[[package]] +name = "enum-map-derive" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "enumflags2" version = "0.7.11" @@ -992,9 +1005,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", "windows-sys 0.59.0", @@ -1019,9 +1032,9 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ "event-listener", "pin-project-lite", @@ -1044,9 +1057,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", "miniz_oxide", @@ -1241,7 +1254,7 @@ dependencies = [ "glutin_wgl_sys", "libloading", "objc2 0.5.2", - "objc2-app-kit", + "objc2-app-kit 0.2.2", "objc2-foundation 0.2.2", "once_cell", "raw-window-handle", @@ -1336,6 +1349,7 @@ version = "0.1.2" dependencies = [ "catppuccin-egui", "eframe", + "egui_extras", "image", "open", "static_vcruntime", @@ -1428,9 +1442,9 @@ dependencies = [ [[package]] name = "icu_locid_transform_data" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" +checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" [[package]] name = "icu_normalizer" @@ -1452,9 +1466,9 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" +checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" [[package]] name = "icu_properties" @@ -1473,9 +1487,9 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" +checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" [[package]] name = "icu_provider" @@ -1550,9 +1564,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", "hashbrown", @@ -1601,10 +1615,11 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ + "getrandom 0.3.2", "libc", ] @@ -1665,7 +1680,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.9.0", "libc", - "redox_syscall 0.5.10", + "redox_syscall 0.5.11", ] [[package]] @@ -1704,9 +1719,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.26" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "malloc_buf" @@ -1757,10 +1772,28 @@ dependencies = [ ] [[package]] -name = "miniz_oxide" -version = "0.8.5" +name = "mime" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess2" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f54028747dfea8e8bf00d3c2d4e83cf023c1accfd5d436335456e9864940cb85" +dependencies = [ + "mime", + "phf", + "phf_shared", + "unicase", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" dependencies = [ "adler2", "simd-adler32", @@ -1935,6 +1968,18 @@ dependencies = [ "objc2-quartz-core", ] +[[package]] +name = "objc2-app-kit" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5906f93257178e2f7ae069efb89fbd6ee94f0592740b5f8a1512ca498814d0fb" +dependencies = [ + "bitflags 2.9.0", + "objc2 0.6.0", + "objc2-core-graphics", + "objc2-foundation 0.3.0", +] + [[package]] name = "objc2-cloud-kit" version = "0.2.2" @@ -1971,6 +2016,28 @@ dependencies = [ "objc2-foundation 0.2.2", ] +[[package]] +name = "objc2-core-foundation" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daeaf60f25471d26948a1c2f840e3f7d86f4109e3af4e8e4b5cd70c39690d925" +dependencies = [ + "bitflags 2.9.0", + "objc2 0.6.0", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dca602628b65356b6513290a21a6405b4d4027b8b250f0b98dddbb28b7de02" +dependencies = [ + "bitflags 2.9.0", + "objc2 0.6.0", + "objc2-core-foundation", + "objc2-io-surface", +] + [[package]] name = "objc2-core-image" version = "0.2.2" @@ -2022,6 +2089,18 @@ checksum = "3a21c6c9014b82c39515db5b396f91645182611c97d24637cf56ac01e5f8d998" dependencies = [ "bitflags 2.9.0", "objc2 0.6.0", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-surface" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "161a8b87e32610086e1a7a9e9ec39f84459db7b3a0881c1f16ca5a2605581c19" +dependencies = [ + "bitflags 2.9.0", + "objc2 0.6.0", + "objc2-core-foundation", ] [[package]] @@ -2032,7 +2111,7 @@ checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" dependencies = [ "block2", "objc2 0.5.2", - "objc2-app-kit", + "objc2-app-kit 0.2.2", "objc2-foundation 0.2.2", ] @@ -2118,9 +2197,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.1" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "open" @@ -2194,7 +2273,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.10", + "redox_syscall 0.5.11", "smallvec", "windows-targets 0.52.6", ] @@ -2217,6 +2296,50 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", + "unicase", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", + "unicase", +] + [[package]] name = "pin-project" version = "1.1.10" @@ -2339,9 +2462,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.37.2" +version = "0.37.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "165859e9e55f79d67b96c5d96f4e88b6f2695a1972849c15a6a3f5c59fc2c003" +checksum = "a4ce8c88de324ff838700f36fb6ab86c96df0e3c4ab6ef3a9b2044465cce1369" dependencies = [ "memchr", ] @@ -2397,26 +2520,6 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -2428,9 +2531,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" +checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" dependencies = [ "bitflags 2.9.0", ] @@ -2462,9 +2565,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96" +checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" dependencies = [ "bitflags 2.9.0", "errno", @@ -2585,6 +2688,12 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + [[package]] name = "slab" version = "0.4.9" @@ -2605,9 +2714,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" [[package]] name = "smithay-client-toolkit" @@ -2733,15 +2842,14 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.33.1" +version = "0.34.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fc858248ea01b66f19d8e8a6d55f41deaf91e9d495246fd01368d99935c6c01" +checksum = "a4b93974b3d3aeaa036504b8eefd4c039dced109171c1ae973f1dc63b2c7e4b2" dependencies = [ - "core-foundation-sys", "libc", "memchr", "ntapi", - "rayon", + "objc2-core-foundation", "windows 0.57.0", ] @@ -2754,7 +2862,7 @@ dependencies = [ "fastrand", "getrandom 0.3.2", "once_cell", - "rustix 1.0.3", + "rustix 1.0.5", "windows-sys 0.59.0", ] @@ -2950,6 +3058,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + [[package]] name = "unicode-ident" version = "1.0.18" @@ -3192,7 +3306,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484" dependencies = [ "proc-macro2", - "quick-xml 0.37.2", + "quick-xml 0.37.4", "quote", ] @@ -3303,9 +3417,9 @@ dependencies = [ [[package]] name = "wgpu-hal" -version = "24.0.2" +version = "24.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4317a17171dc20e6577bf606796794580accae0716a69edbc7388c86a3ec9f23" +checksum = "f112f464674ca69f3533248508ee30cb84c67cf06c25ff6800685f5e0294e259" dependencies = [ "android_system_properties", "arrayvec", @@ -3612,15 +3726,6 @@ dependencies = [ "windows-targets 0.42.2", ] -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-sys" version = "0.52.0" @@ -3841,7 +3946,7 @@ dependencies = [ "memmap2", "ndk", "objc2 0.5.2", - "objc2-app-kit", + "objc2-app-kit 0.2.2", "objc2-foundation 0.2.2", "objc2-ui-kit", "orbclient", diff --git a/Cargo.toml b/Cargo.toml index 7285e3f..11a3762 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,14 +8,16 @@ catppuccin-egui = { version = "5.5.0", default-features = false, features = [ "egui31", ] } eframe = "0.31.1" -image = { version = "0.25.6", default-features = false } +egui_extras = { version = "0.31.1", features = ["image"] } +image = { version = "0.25.6", default-features = false, features = ["png"] } open = "5.3.2" -sysinfo = "0.33.1" +sysinfo = "0.34.2" windows = { version = "0.61.1", features = [ "Win32_UI_Input_KeyboardAndMouse", "Win32_System_Threading", "Win32_UI_Shell", "Win32_UI_WindowsAndMessaging", + "Win32_Security", ] } winreg = "0.55.0" diff --git a/src/features/empty_session.rs b/src/features/empty_session.rs index 2386c22..fb0e672 100644 --- a/src/features/empty_session.rs +++ b/src/features/empty_session.rs @@ -21,7 +21,7 @@ impl Default for EmptySession { Self { disabled: false, interval: Instant::now(), - countdown: Countdown::new(features::empty_session::INTERVAL.as_secs() as usize), + countdown: Countdown::new(features::empty_session::INTERVAL.as_secs()), } } } diff --git a/src/features/force_close.rs b/src/features/force_close.rs index b8f7c0f..c2e8c49 100644 --- a/src/features/force_close.rs +++ b/src/features/force_close.rs @@ -1,9 +1,7 @@ +use crate::util::consts::{ENHANCED, LEGACY}; use std::time::Instant; use sysinfo::System; -const ENHANCED: &str = "GTA5_Enhanced.exe"; -const LEGACY: &str = "GTA5.exe"; - pub struct ForceClose { pub button_text: String, pub prompting: bool, @@ -20,6 +18,14 @@ impl Default for ForceClose { } } +impl ForceClose { + pub fn prompting(&mut self) { + self.button_text = "Are you sure?".to_string(); + self.prompting = true; + self.interval = Instant::now(); + } +} + pub fn activate(sysinfo: &mut System) { sysinfo.refresh_all(); sysinfo @@ -29,4 +35,5 @@ pub fn activate(sysinfo: &mut System) { .for_each(|(_, p)| { p.kill(); }); + sysinfo.refresh_all(); } diff --git a/src/features/game_networking.rs b/src/features/game_networking.rs new file mode 100644 index 0000000..cd9de0a --- /dev/null +++ b/src/features/game_networking.rs @@ -0,0 +1,76 @@ +use crate::util::consts::{ENHANCED, LEGACY}; +use std::{path::Path, process::Command}; +use sysinfo::System; + +const FILTER_NAME: &str = "[GTA Tools] Block all traffic for GTA V"; + +fn get_game_exe_path(sysinfo: &mut System) -> Option<&Path> { + sysinfo.refresh_all(); + if let Some((_, process)) = sysinfo + .processes() + .iter() + .find(|(_, p)| p.name() == ENHANCED || p.name() == LEGACY) + { + process.exe() + } else { + None + } +} + +pub fn block_all(sysinfo: &mut System) { + let Some(exe_path) = get_game_exe_path(sysinfo) else { + return; + }; + let exe_path = exe_path.display().to_string(); + Command::new("netsh") + .args([ + "advfirewall", + "firewall", + "add", + "rule", + &format!("name={FILTER_NAME}"), + "dir=out", + "action=block", + "protocol=ANY", + &format!("program={exe_path}"), + ]) + .spawn() + .unwrap(); + Command::new("netsh") + .args([ + "advfirewall", + "firewall", + "add", + "rule", + &format!("name={FILTER_NAME}"), + "dir=in", + "action=block", + "protocol=ANY", + &format!("program={exe_path}"), + ]) + .spawn() + .unwrap(); +} + +pub fn unblock_all() { + Command::new("netsh") + .args([ + "advfirewall", + "firewall", + "delete", + "rule", + &format!("name={FILTER_NAME}"), + ]) + .spawn() + .unwrap(); + Command::new("netsh") + .args([ + "advfirewall", + "firewall", + "delete", + "rule", + &format!("name={FILTER_NAME}"), + ]) + .spawn() + .unwrap(); +} diff --git a/src/features/mod.rs b/src/features/mod.rs index ff161c0..3ee91ec 100644 --- a/src/features/mod.rs +++ b/src/features/mod.rs @@ -1,4 +1,5 @@ pub mod anti_afk; pub mod empty_session; pub mod force_close; +pub mod game_networking; pub mod launch; diff --git a/src/gui.rs b/src/gui.rs index 3cbec90..7443852 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -6,26 +6,45 @@ use crate::{ force_close::ForceClose, launch::{Launch, Platform}, }, - util::elevate, + util::{ + consts::{ENHANCED, LEGACY}, + elevation, + }, }; use eframe::egui; use std::time::{Duration, Instant}; use sysinfo::System; use windows::Win32::Foundation::HANDLE; +#[derive(Default, PartialEq, Eq)] +pub enum Stage { + #[default] + Main, + About, + Debug, +} + pub struct App { - pub current_frame: bool, + stage: Stage, + debug: bool, + initialized: bool, + elevated: bool, + current_frame: bool, pub sysinfo: System, pub game_handle: HANDLE, - pub launch: Launch, - pub force_close: ForceClose, - pub empty_session: EmptySession, - pub anti_afk: AntiAfk, + launch: Launch, + force_close: ForceClose, + empty_session: EmptySession, + anti_afk: AntiAfk, } impl Default for App { fn default() -> Self { Self { + stage: Stage::default(), + initialized: false, + debug: false, + elevated: elevation::is_elevated(), current_frame: false, sysinfo: System::new_all(), game_handle: HANDLE::default(), @@ -39,114 +58,200 @@ impl Default for App { impl eframe::App for App { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { - catppuccin_egui::set_theme(ctx, catppuccin_egui::MOCHA); + if !self.initialized { + catppuccin_egui::set_theme(ctx, catppuccin_egui::MOCHA); + egui_extras::install_image_loaders(ctx); + self.initialized = true; + } ctx.request_repaint_after(Duration::from_millis(100)); - egui::CentralPanel::default().show(ctx, |ui| { - ui.horizontal(|ui| { - ui.label("Game"); - ui.add(egui::Separator::default().horizontal()); - }); - ui.horizontal(|ui| { - if ui.button("Launch").clicked() { - features::launch::launch(&self.launch.selected); - }; - egui::ComboBox::from_label("") - .selected_text(self.launch.selected.to_string()) - .width(125.0) - .show_ui(ui, |ui| { - ui.selectable_value( - &mut self.launch.selected, - Platform::Steam, - Platform::Steam.to_string(), - ); - ui.selectable_value( - &mut self.launch.selected, - Platform::Rockstar, - Platform::Rockstar.to_string(), - ); - ui.selectable_value( - &mut self.launch.selected, - Platform::Epic, - Platform::Epic.to_string(), - ); - }); - }); - let force_close_button = ui.button(&self.force_close.button_text); - if force_close_button.clicked() && !self.force_close.prompting { - self.force_close.button_text = "Are you sure?".to_string(); - self.force_close.prompting = true; - self.force_close.interval = Instant::now(); - self.current_frame = true; - }; - if self.force_close.prompting - && self.force_close.interval.elapsed() <= Duration::from_secs(3) - { - if force_close_button.clicked() && !self.current_frame { - features::force_close::activate(&mut self.sysinfo); - self.force_close = ForceClose::default(); + ctx.input(|i| { + if i.modifiers.all() && i.key_pressed(egui::Key::D) { + self.debug = !self.debug; + if !self.debug && self.stage == Stage::Debug { + self.stage = Stage::Main; } - } else { - self.force_close = ForceClose::default(); - } - if self.current_frame { - self.current_frame = false; } + }); + self.run_timers(); + egui::TopBottomPanel::bottom("bottom_panel").show(ctx, |ui| { ui.horizontal(|ui| { - ui.label("Session"); - ui.add(egui::Separator::default().horizontal()); - }); - ui.add_enabled_ui(!self.empty_session.disabled, |ui| { - ui.horizontal(|ui| { - if ui.button("Empty current session").clicked() { - self.empty_session.interval = Instant::now(); - self.empty_session.disabled = true; - features::empty_session::activate(self); + ui.selectable_value(&mut self.stage, Stage::Main, "Main"); + ui.selectable_value(&mut self.stage, Stage::About, "About"); + if self.debug { + ui.selectable_value(&mut self.stage, Stage::Debug, "Debug"); + } + ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { + let button = ui + .add_enabled(!self.elevated, egui::Button::new("Elevate")) + .on_disabled_hover_text("We are already running elevated."); + if button.clicked() { + elevation::elevate(); } - if self.empty_session.disabled { - self.empty_session.countdown.count(); - } else { - self.empty_session.countdown.reset(); - } - if self.empty_session.interval.elapsed() >= features::empty_session::INTERVAL { - features::empty_session::deactivate(self); - self.empty_session.disabled = false; - } - ui.label(&self.empty_session.countdown.i_string); }); }); - ui.checkbox(&mut self.anti_afk.enabled, "Anti AFK") - .on_hover_text("You should be tabbed in\nwhile this is enabled."); - if self.anti_afk.enabled - && self.anti_afk.interval.elapsed() >= features::anti_afk::INTERVAL - { - features::anti_afk::activate(); - self.anti_afk.interval = Instant::now(); - } - // ui.horizontal(|ui| { - // ui.label("Network"); - // ui.add(egui::Separator::default().horizontal()); - // }); - // if ui.button("Elevate").clicked() { - // elevate::elevate(); - // } - // ui.checkbox(&mut false, "Block connections to Rockstar"); - ui.with_layout(egui::Layout::bottom_up(egui::Align::Center), |ui| { - ui.horizontal(|ui| { - ui.horizontal(|ui| { - ui.spacing_mut().item_spacing.x = 0.0; - ui.label("with love from "); - ui.hyperlink_to("futile", "http://futile.eu"); - }); - ui.separator(); - ui.label(format!( - "v{} {}", - env!("CARGO_PKG_VERSION"), - if cfg!(debug_assertions) { "(dev)" } else { "" } - )); - }); - // ui.separator(); - }); }); + egui::CentralPanel::default().show(ctx, |ui| { + egui::ScrollArea::both() + .auto_shrink([false, false]) + .show(ui, |ui| match self.stage { + Stage::Main => { + self.header(ui, "Game"); + self.show_game(ctx, ui); + self.header(ui, "Session"); + self.show_session(ctx, ui); + self.header(ui, "Network"); + self.show_network(ctx, ui); + } + Stage::About => { + self.show_about(ctx, ui); + } + Stage::Debug => { + self.show_debug(ctx, ui); + } + }); + }); + } +} + +impl App { + fn header(&self, ui: &mut egui::Ui, text: &str) { + ui.horizontal(|ui| { + ui.label(text); + ui.add(egui::Separator::default().horizontal()); + }); + } + + fn show_game(&mut self, _ctx: &egui::Context, ui: &mut egui::Ui) { + ui.horizontal(|ui| { + if ui.button("Launch").clicked() { + features::launch::launch(&self.launch.selected); + }; + egui::ComboBox::from_label("") + .selected_text(self.launch.selected.to_string()) + .width(125.0) + .show_ui(ui, |ui| { + ui.selectable_value( + &mut self.launch.selected, + Platform::Steam, + Platform::Steam.to_string(), + ); + ui.selectable_value( + &mut self.launch.selected, + Platform::Rockstar, + Platform::Rockstar.to_string(), + ); + ui.selectable_value( + &mut self.launch.selected, + Platform::Epic, + Platform::Epic.to_string(), + ); + }); + }); + let force_close_button = ui.button(&self.force_close.button_text); + if force_close_button.clicked() && !self.force_close.prompting { + self.force_close.prompting(); + self.current_frame = true; + }; + if self.force_close.prompting + && self.force_close.interval.elapsed() <= Duration::from_secs(3) + { + if force_close_button.clicked() && !self.current_frame { + features::force_close::activate(&mut self.sysinfo); + self.force_close = ForceClose::default(); + } + } else { + self.force_close = ForceClose::default(); + } + if self.current_frame { + self.current_frame = false; + } + } + + fn show_session(&mut self, _ctx: &egui::Context, ui: &mut egui::Ui) { + ui.add_enabled_ui(!self.empty_session.disabled, |ui| { + ui.horizontal(|ui| { + if ui.button("Empty current session").clicked() { + self.empty_session.interval = Instant::now(); + self.empty_session.disabled = true; + features::empty_session::activate(self); + } + ui.label(&self.empty_session.countdown.i_string); + }); + }); + ui.checkbox(&mut self.anti_afk.enabled, "Anti AFK") + .on_hover_text("You should be tabbed in\nwhile this is enabled."); + if self.anti_afk.enabled && self.anti_afk.interval.elapsed() >= features::anti_afk::INTERVAL + { + features::anti_afk::activate(); + self.anti_afk.interval = Instant::now(); + } + } + + fn show_network(&mut self, _ctx: &egui::Context, ui: &mut egui::Ui) { + egui::Frame::new() + .inner_margin(egui::vec2(4.0, 4.0)) + .stroke(egui::Stroke::new(1.0, catppuccin_egui::MOCHA.overlay1)) + .show(ui, |ui| { + let response = ui.add_enabled_ui(self.elevated, |ui| { + ui.label("GTA's network access"); + ui.horizontal(|ui| { + if ui.button("Block").clicked() { + features::game_networking::block_all(&mut self.sysinfo); + }; + if ui.button("Unblock").clicked() { + features::game_networking::unblock_all(); + }; + }); + }); + response.response.on_disabled_hover_text( + "This requires you to be running as\nadministrator. Use the Elevate button.", + ) + }); + } + + fn show_about(&self, _ctx: &egui::Context, ui: &mut egui::Ui) { + ui.with_layout(egui::Layout::bottom_up(egui::Align::Center), |ui| { + ui.horizontal(|ui| { + ui.horizontal(|ui| { + ui.spacing_mut().item_spacing.x = 0.0; + ui.label("with love from "); + ui.hyperlink_to("futile", "http://futile.eu"); + }); + ui.separator(); + ui.label(format!( + "v{} {}", + env!("CARGO_PKG_VERSION"), + if cfg!(debug_assertions) { "(dev)" } else { "" } + )); + }); + ui.add(egui::Image::new(egui::include_image!("../assets/icon.png"))) + }); + } + + fn show_debug(&mut self, _ctx: &egui::Context, ui: &mut egui::Ui) { + let pid = self + .sysinfo + .processes() + .iter() + .find(|(_, p)| p.name() == ENHANCED || p.name() == LEGACY) + .map(|(pid, _)| pid.as_u32().to_string()) + .unwrap_or_else(|| "no pid found!".to_string()); + if ui.button("refresh sysinfo").clicked() { + self.sysinfo.refresh_all(); + } + ui.label(format!("gta pid: {pid}")); + } + + fn run_timers(&mut self) { + if self.empty_session.disabled { + self.empty_session.countdown.count(); + } else { + self.empty_session.countdown.reset(); + } + if self.empty_session.interval.elapsed() >= features::empty_session::INTERVAL { + features::empty_session::deactivate(self); + self.empty_session.disabled = false; + } } } @@ -158,7 +263,6 @@ fn load_icon() -> eframe::egui::IconData { let rgba = image.into_raw(); (rgba, width, height) }; - eframe::egui::IconData { rgba: icon_rgba, width: icon_width, @@ -171,7 +275,7 @@ pub fn run() { viewport: egui::ViewportBuilder::default() .with_resizable(false) .with_maximize_button(false) - .with_inner_size([250.0, 225.0]) + .with_inner_size([256.0, 232.0]) .with_icon(load_icon()), centered: true, ..Default::default() diff --git a/src/util/consts.rs b/src/util/consts.rs new file mode 100644 index 0000000..327faf8 --- /dev/null +++ b/src/util/consts.rs @@ -0,0 +1,2 @@ +pub const ENHANCED: &str = "GTA5_Enhanced.exe"; +pub const LEGACY: &str = "GTA5.exe"; diff --git a/src/util/countdown.rs b/src/util/countdown.rs index a191888..91f858f 100644 --- a/src/util/countdown.rs +++ b/src/util/countdown.rs @@ -1,15 +1,15 @@ use std::time::{Duration, Instant}; pub struct Countdown { - pub i: usize, - pub i_original: usize, + pub i: u64, + pub i_original: u64, pub i_string: String, pub interval: Instant, pub first_count: bool, } impl Countdown { - pub fn new(i: usize) -> Self { + pub fn new(i: u64) -> Self { Self { i, i_original: i, diff --git a/src/util/elevate.rs b/src/util/elevate.rs deleted file mode 100644 index 94047fc..0000000 --- a/src/util/elevate.rs +++ /dev/null @@ -1,19 +0,0 @@ -use windows::{ - Win32::UI::{Shell::ShellExecuteW, WindowsAndMessaging::SW_HIDE}, - core::{HSTRING, PCWSTR}, -}; - -pub fn elevate() { - let exe = std::env::current_exe().unwrap(); - unsafe { - ShellExecuteW( - None, - &HSTRING::from("runas"), - &HSTRING::from(exe.as_path()), - PCWSTR::null(), - PCWSTR::null(), - SW_HIDE, - ); - } - std::process::exit(0); -} diff --git a/src/util/elevation.rs b/src/util/elevation.rs new file mode 100644 index 0000000..f2a0bb3 --- /dev/null +++ b/src/util/elevation.rs @@ -0,0 +1,45 @@ +use windows::{ + Win32::Foundation::{CloseHandle, HANDLE}, + Win32::Security::{GetTokenInformation, TOKEN_ELEVATION, TOKEN_QUERY, TokenElevation}, + Win32::System::Threading::{GetCurrentProcess, OpenProcessToken}, + Win32::UI::{Shell::ShellExecuteW, WindowsAndMessaging::SW_HIDE}, + core::{HSTRING, PCWSTR}, +}; + +pub fn elevate() { + let exe = std::env::current_exe().unwrap(); + unsafe { + ShellExecuteW( + None, + &HSTRING::from("runas"), + &HSTRING::from(exe.as_path()), + PCWSTR::null(), + PCWSTR::null(), + SW_HIDE, + ); + } + std::process::exit(0); +} + +pub fn is_elevated() -> bool { + unsafe { + let mut token: HANDLE = HANDLE::default(); + if OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut token).is_ok() { + let mut elevation = TOKEN_ELEVATION::default(); + let size = std::mem::size_of::() as u32; + let mut ret_size = size; + let result = GetTokenInformation( + token, + TokenElevation, + Some(&mut elevation as *mut _ as *mut _), + size, + &mut ret_size, + ); + CloseHandle(token).unwrap(); + if result.is_ok() && elevation.TokenIsElevated != 0 { + return true; + } + } + false + } +} diff --git a/src/util/mod.rs b/src/util/mod.rs index b4bdd24..69cbec7 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -1,2 +1,3 @@ +pub mod consts; pub mod countdown; -pub mod elevate; +pub mod elevation;