Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3158f71fb | ||
|
|
070e477fd4 | ||
|
|
7745bba10e | ||
|
|
8d7a0d12b9 | ||
|
|
b325ebb03c | ||
|
|
38c6402a12 | ||
|
|
2d42c0c3c4 | ||
|
|
a423721aee | ||
|
|
f3436c8ddc | ||
|
|
afcf0a87c0 | ||
|
|
73d610949f | ||
|
|
7f358d9adb | ||
|
|
7caa5421f7 | ||
|
|
ecac0d54aa | ||
|
|
a84401ca33 | ||
|
|
1bcd6b2c7d | ||
|
|
1dbdc0e4cb | ||
|
|
3610e44a08 | ||
|
|
f5fd22d35c | ||
|
|
022828b802 | ||
|
|
262d2d0720 | ||
|
|
2326edf97b | ||
|
|
301be82837 |
Generated
+56
-346
@@ -63,21 +63,6 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arboard"
|
||||
version = "3.5.0"
|
||||
@@ -128,12 +113,6 @@ version = "0.21.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@@ -266,18 +245,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"num-traits",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clipboard-win"
|
||||
version = "5.4.0"
|
||||
@@ -306,35 +273,6 @@ dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
"time",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cookie_store"
|
||||
version = "0.21.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2eac901828f88a5241ee0600950ab981148a18f2f756900ffba1b125ca6a3ef9"
|
||||
dependencies = [
|
||||
"cookie",
|
||||
"document-features",
|
||||
"idna",
|
||||
"indexmap",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"time",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.4"
|
||||
@@ -412,36 +350,6 @@ version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a"
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dispatch"
|
||||
version = "0.2.0"
|
||||
@@ -711,12 +619,6 @@ version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.5.0"
|
||||
@@ -763,17 +665,6 @@ dependencies = [
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.2"
|
||||
@@ -783,7 +674,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasi 0.14.2+wasi-0.2.4",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -864,14 +755,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gta-tools"
|
||||
version = "0.5.3"
|
||||
version = "0.6.0"
|
||||
dependencies = [
|
||||
"catppuccin-egui",
|
||||
"chrono",
|
||||
"dirs",
|
||||
"eframe",
|
||||
"egui_extras",
|
||||
"image",
|
||||
"nyquest",
|
||||
"nyquest-backend-winrt",
|
||||
"open",
|
||||
"semver",
|
||||
"serde",
|
||||
@@ -879,7 +770,6 @@ dependencies = [
|
||||
"static_vcruntime",
|
||||
"strum",
|
||||
"sysinfo",
|
||||
"ureq",
|
||||
"windows",
|
||||
"winreg",
|
||||
"winresource",
|
||||
@@ -912,47 +802,6 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"log",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_collections"
|
||||
version = "1.5.0"
|
||||
@@ -1174,7 +1023,7 @@ version = "0.1.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a"
|
||||
dependencies = [
|
||||
"getrandom 0.3.2",
|
||||
"getrandom",
|
||||
"libc",
|
||||
]
|
||||
|
||||
@@ -1349,12 +1198,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
@@ -1385,6 +1228,42 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nyquest"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a4722c65afdcbb836197802c2f5dc050825964bebbd9802086e54aef39208b0"
|
||||
dependencies = [
|
||||
"nyquest-interface",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nyquest-backend-winrt"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6252715c7ef065cdb3384bc7551195dd97cc509ea0db25570b2ae1e28b765552"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"nyquest-interface",
|
||||
"windows",
|
||||
"windows-collections",
|
||||
"windows-core",
|
||||
"windows-future",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nyquest-interface"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afabf0928178a75d8ded690f55faba7aa69d2998d4d8acca9c6ca4ac879c859d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc-sys"
|
||||
version = "0.3.5"
|
||||
@@ -1552,6 +1431,16 @@ dependencies = [
|
||||
"objc2-core-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-io-kit"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"objc2-core-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-io-surface"
|
||||
version = "0.3.1"
|
||||
@@ -1672,12 +1561,6 @@ dependencies = [
|
||||
"pathdiff",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "option-ext"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "orbclient"
|
||||
version = "0.3.48"
|
||||
@@ -1797,12 +1680,6 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "3.3.0"
|
||||
@@ -1881,17 +1758,6 @@ dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
|
||||
dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
"libredox",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "resvg"
|
||||
version = "0.37.0"
|
||||
@@ -1915,20 +1781,6 @@ dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"getrandom 0.2.15",
|
||||
"libc",
|
||||
"untrusted",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "roxmltree"
|
||||
version = "0.19.0"
|
||||
@@ -1948,47 +1800,6 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"rustls-webpki",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c"
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.103.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.20"
|
||||
@@ -2214,12 +2025,6 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "svgtypes"
|
||||
version = "0.13.0"
|
||||
@@ -2254,13 +2059,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.34.2"
|
||||
source = "git+https://github.com/GuillaumeGomez/sysinfo?rev=bcbb7b2b389b8800ff457773f48b130e710458fc#bcbb7b2b389b8800ff457773f48b130e710458fc"
|
||||
version = "0.35.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b897c8ea620e181c7955369a31be5f48d9a9121cb59fd33ecef9ff2a34323422"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"memchr",
|
||||
"ntapi",
|
||||
"objc2-core-foundation",
|
||||
"objc2-io-kit",
|
||||
"windows",
|
||||
]
|
||||
|
||||
@@ -2315,37 +2122,6 @@ dependencies = [
|
||||
"weezl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
"num-conv",
|
||||
"powerfmt",
|
||||
"serde",
|
||||
"time-core",
|
||||
"time-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-skia"
|
||||
version = "0.11.4"
|
||||
@@ -2450,45 +2226,6 @@ version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "ureq"
|
||||
version = "3.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7a3e9af6113ecd57b8c63d3cd76a385b2e3881365f1f489e54f49801d0c83ea"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"cookie_store",
|
||||
"flate2",
|
||||
"log",
|
||||
"percent-encoding",
|
||||
"rustls",
|
||||
"rustls-pemfile",
|
||||
"rustls-pki-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"ureq-proto",
|
||||
"utf-8",
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ureq-proto"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fadf18427d33828c311234884b7ba2afb57143e6e7e69fda7ee883b624661e36"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"http",
|
||||
"httparse",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.4"
|
||||
@@ -2506,7 +2243,7 @@ version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38b0a51b72ab80ca511d126b77feeeb4fb1e972764653e61feac30adc161a756"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"base64",
|
||||
"log",
|
||||
"pico-args",
|
||||
"usvg-parser",
|
||||
@@ -2544,12 +2281,6 @@ dependencies = [
|
||||
"tiny-skia-path",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf-8"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||
|
||||
[[package]]
|
||||
name = "utf16_iter"
|
||||
version = "1.0.5"
|
||||
@@ -2578,12 +2309,6 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.14.2+wasi-0.2.4"
|
||||
@@ -2797,15 +2522,6 @@ dependencies = [
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "0.26.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "weezl"
|
||||
version = "0.1.8"
|
||||
@@ -3358,12 +3074,6 @@ dependencies = [
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
|
||||
|
||||
[[package]]
|
||||
name = "zerovec"
|
||||
version = "0.10.4"
|
||||
|
||||
+4
-5
@@ -1,14 +1,12 @@
|
||||
[package]
|
||||
name = "gta-tools"
|
||||
version = "0.5.3"
|
||||
version = "0.6.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
catppuccin-egui = { version = "5.5.0", default-features = false, features = [
|
||||
"egui31",
|
||||
] }
|
||||
chrono = { version = "0.4.40", default-features = false, features = ["clock"] }
|
||||
dirs = "6.0.0"
|
||||
eframe = { version = "0.31.1", default-features = false, features = [
|
||||
"glow",
|
||||
"default_fonts",
|
||||
@@ -18,13 +16,14 @@ egui_extras = { version = "0.31.1", default-features = false, features = [
|
||||
"svg",
|
||||
] }
|
||||
image = { version = "0.25.6", default-features = false, features = ["png"] }
|
||||
nyquest = { version = "0.1.1", features = ["blocking", "json"] }
|
||||
nyquest-backend-winrt = { version = "0.1.0", features = ["blocking"] }
|
||||
open = "5.3.2"
|
||||
semver = "1.0.26"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
serde_json = "1.0.140"
|
||||
strum = { version = "0.27.1", features = ["derive"] }
|
||||
sysinfo = { git = "https://github.com/GuillaumeGomez/sysinfo", rev = "bcbb7b2b389b8800ff457773f48b130e710458fc" }
|
||||
ureq = { version = "3.0.11", features = ["json"] }
|
||||
sysinfo = "0.35.0"
|
||||
windows = { version = "0.61.1", features = [
|
||||
"Win32_UI_Input_KeyboardAndMouse",
|
||||
"Win32_System_Threading",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
A toolset of convenient things for GTA V Online.
|
||||
|
||||

|
||||

|
||||
|
||||
## Installing
|
||||
|
||||
@@ -11,3 +11,51 @@ Download the latest release [here](https://codeberg.org/futile/gta-tools/release
|
||||
|
||||
**Option 2** — <ins>Build from source</ins>
|
||||
You will need the Rust toolchain, which can be obtained [here](https://rustup.rs). Follow the instructions of its installer. Once you have Rust installed, clone this repo and navigate to it. At this point, you should probably `git checkout x.x.x`, where `x.x.x` is the latest tag. You can then run `cargo build --release`. Once you do that, you can use the binary located at `.\target\release\gta-tools.exe` in the same way as **Option 1**.
|
||||
|
||||
## Guide
|
||||
|
||||
Almost every[^1] feature of GTA Tools is Legacy/Enhanced-agnostic. Some functionality of GTA Tools requires administrator access. If necessary, GTA Tools can either be started as admin manually, or, the user can simply use the <kbd>Elevate</kbd> button to relaunch GTA Tools as admin.
|
||||
|
||||
It is recommended to use an up-to-date version of GTA Tools from [releases](https://codeberg.org/futile/gta-tools/releases). You can check for updates to your existing installation by going to the <kbd>About</kbd> page of GTA Tools and hovering the <kbd>↓</kbd> button near the version number.
|
||||
|
||||
#### Game
|
||||
|
||||
This section is quite simple.
|
||||
|
||||
There is a <kbd>Launch</kbd>[^1] feature, which will start your game on the chosen launcher (I am unsure if launching Epic Games works, let me know).
|
||||
|
||||
There is also a <kbd>Force close game</kbd> feature, which simply kills all game processes. This *does not* touch Rockstar Games Launcher or any other processes, only ones named `GTA5_Enhanced.exe` or `GTA5.exe`.
|
||||
|
||||
#### Session
|
||||
|
||||
This section also has two features.
|
||||
|
||||
The first being <kbd>Empty current session</kbd>, which "removes everyone" from your session by suspending your game for 10 seconds, and then resuming it. This method is exceedingly similar to the Resource Monitor method, but made convenient in one button. This can be useful in numerous ways:
|
||||
* You are stuck loading into a session
|
||||
* You are stuck loading into an interior
|
||||
* You are about to get griefed while doing a freemode mission
|
||||
* You want to quickly get a "new" session
|
||||
|
||||
The other feature is <kbd>Anti AFK</kbd>, which, when toggled, prevents you from getting kicked for idling by pressing keys on your keyboard every 60 seconds. At present, those keys are `VK_NUMPAD4` & `VK_NUMPAD6`, due to being a relatively good balance of keys that the game actually registers but don't interrupt gameplay too much if they activate while you're playing. You *must* be tabbed into GTA V for <kbd>Anti AFK</kbd> to work. While toggled, <kbd>Anti AFK</kbd> will only activate when all of the following conditions are true:
|
||||
* The `Grand Theft Auto V` window is currently focused
|
||||
* None of the designated keys are currently being pressed[^2]
|
||||
* The mouse cursor is not currently visible[^3]
|
||||
|
||||
#### Network
|
||||
|
||||
The last section has a single feature, <kbd>Game's network access</kbd>, with two buttons, <kbd>Block</kbd> and <kbd>Unblock</kbd>, and a coloured indicator dot. This feature requires administrator, and blocks/unblocks GTA V's entire internet access using the Windows Firewall. The coloured indicator dot has these meanings:
|
||||
* **Green** - the game is connected to the internet
|
||||
* **Yellow** - the game could not be found running, and thus was not blocked
|
||||
* **Red** - the game is blocked from the internet
|
||||
|
||||
This feature is primarily useful for **replay glitching**, which is an exploit that allows you to complete any heist/mission finale, get the money for it, and then be able to do it again right away. Here's how you can do a replay glitch:
|
||||
1. Get to the finale of a heist/contract/mission series, such as **The Contract: Dr. Dre**
|
||||
2. Complete the finale as normal
|
||||
3. Right *after* the **HEIST/MISSION PASSED** screen you get when you complete a finale (basically, when your cut is being shown), <kbd>Block</kbd> the game's internet access
|
||||
4. After a few seconds, you will be shown an error screen and kicked to the main menu
|
||||
5. At this point, <kbd>Unblock</kbd> the game's internet access and load back into online
|
||||
6. Finally, spend any amount of money, and you should receive the finale cut, but also be able to go play the finale again immediately
|
||||
|
||||
[^1]: <kbd>Launch</kbd> only launches Enhanced installations of the game.
|
||||
[^2]: Otherwise, if you are, for example, using those keys to fly a plane, <kbd>Anti AFK</kbd> activating could cancel the input.
|
||||
[^3]: Specifically, the Windows mouse cursor, not the in-game mouse cursor. This check is mostly used to prevent typing while you are in the Rockstar overlay.
|
||||
|
||||
@@ -57,6 +57,6 @@ fn send(vk_codes: &[VIRTUAL_KEY]) {
|
||||
};
|
||||
inputs.push(input);
|
||||
}
|
||||
unsafe { SendInput(&inputs, size_of::<INPUT>() as i32) };
|
||||
}
|
||||
unsafe { SendInput(&inputs, size_of::<INPUT>() as i32) };
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ impl ForceClose {
|
||||
*self = Self::default();
|
||||
}
|
||||
|
||||
fn finish_current_frame(&mut self) {
|
||||
const fn finish_current_frame(&mut self) {
|
||||
if self.current_frame {
|
||||
self.current_frame = false;
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ impl GameNetworking {
|
||||
in_rule_exists || out_rule_exists
|
||||
}
|
||||
|
||||
pub fn if_failed_return_to_unblocked(&mut self) {
|
||||
pub fn if_failed_return_to_boolean(&mut self) {
|
||||
if self.blocked_status == BlockedStatus::Failed && !self.counting {
|
||||
self.counting = true;
|
||||
self.timer = Instant::now();
|
||||
@@ -128,7 +128,7 @@ impl GameNetworking {
|
||||
&& self.timer.elapsed() >= INTERVAL
|
||||
{
|
||||
self.counting = false;
|
||||
self.blocked_status = BlockedStatus::Unblocked;
|
||||
self.blocked_status = Self::is_blocked().into();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,3 +4,4 @@ mod debug;
|
||||
pub mod run;
|
||||
pub mod settings;
|
||||
mod tools;
|
||||
mod ui_ext;
|
||||
+23
-14
@@ -1,6 +1,10 @@
|
||||
use crate::{
|
||||
features,
|
||||
gui::{settings::Settings, tools},
|
||||
gui::{
|
||||
settings::{Settings, Theme},
|
||||
tools,
|
||||
ui_ext::UiExt,
|
||||
},
|
||||
util::{consts::game::WINDOW_TITLE, meta::Meta, persistent_state::PersistentState, win},
|
||||
};
|
||||
use eframe::egui;
|
||||
@@ -57,7 +61,7 @@ impl eframe::App for App {
|
||||
.exact_height(25.0)
|
||||
.show(ctx, |ui| {
|
||||
ui.with_layout(egui::Layout::left_to_right(egui::Align::Center), |ui| {
|
||||
tools::build_menu::<Stage>(ui, &mut self.stage);
|
||||
ui.build_menu(&mut self.stage);
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
let button = ui
|
||||
.add_enabled(!self.flags.elevated, egui::Button::new("Elevate"))
|
||||
@@ -92,7 +96,7 @@ impl eframe::App for App {
|
||||
|
||||
impl App {
|
||||
fn show_game_section(&mut self, _ctx: &egui::Context, ui: &mut egui::Ui) {
|
||||
tools::header(ui, "Game");
|
||||
ui.header("Game");
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("Launch").clicked() {
|
||||
features::launch::launch(&self.launch.selected);
|
||||
@@ -101,7 +105,7 @@ impl App {
|
||||
.selected_text(self.launch.selected.to_string())
|
||||
.width(120.0)
|
||||
.show_ui(ui, |ui| {
|
||||
tools::build_menu(ui, &mut self.launch.selected);
|
||||
ui.build_menu(&mut self.launch.selected);
|
||||
});
|
||||
});
|
||||
let force_close_button = ui.add_sized(
|
||||
@@ -113,7 +117,7 @@ impl App {
|
||||
}
|
||||
|
||||
fn show_session_section(&mut self, _ctx: &egui::Context, ui: &mut egui::Ui) {
|
||||
tools::header(ui, "Session");
|
||||
ui.header("Session");
|
||||
ui.add_enabled_ui(!self.empty_session.disabled, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("Empty current session").clicked() {
|
||||
@@ -144,7 +148,7 @@ impl App {
|
||||
}
|
||||
|
||||
fn show_network_section(&mut self, _ctx: &egui::Context, ui: &mut egui::Ui) {
|
||||
tools::header(ui, "Network");
|
||||
ui.header("Network");
|
||||
egui::Frame::new()
|
||||
.outer_margin(egui::vec2(0.0, -2.0))
|
||||
.show(ui, |ui| {
|
||||
@@ -152,13 +156,11 @@ impl App {
|
||||
let label = ui.horizontal(|ui| {
|
||||
let label = ui.label("Game's network access");
|
||||
ui.add_space(1.0);
|
||||
ui.add(
|
||||
egui::Image::new(egui::include_image!("../../assets/circle.svg"))
|
||||
.max_size([4.0, 4.0].into())
|
||||
.tint(self.game_networking.blocked_status.to_color32()),
|
||||
)
|
||||
.on_hover_text("This turns yellow if GTA Tools\ncannot find your game.");
|
||||
self.game_networking.if_failed_return_to_unblocked();
|
||||
ui.create_indicator_dot(self.game_networking.blocked_status)
|
||||
.on_hover_text(
|
||||
"This turns yellow if GTA Tools\ncannot find your game.",
|
||||
);
|
||||
self.game_networking.if_failed_return_to_boolean();
|
||||
label
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
@@ -198,11 +200,18 @@ impl App {
|
||||
egui::ComboBox::from_id_salt("Theme")
|
||||
.selected_text(self.settings.theme.to_string())
|
||||
.show_ui(ui, |ui| {
|
||||
tools::build_menu(ui, &mut self.settings.theme);
|
||||
ui.build_menu(&mut self.settings.theme);
|
||||
});
|
||||
if selection != self.settings.theme {
|
||||
catppuccin_egui::set_theme(ctx, self.settings.theme.into());
|
||||
}
|
||||
if ui
|
||||
.add_visible(self.settings.theme == Theme::Auto, egui::Button::new("⟲"))
|
||||
.on_hover_text("Refresh theme")
|
||||
.clicked()
|
||||
{
|
||||
catppuccin_egui::set_theme(ctx, self.settings.theme.into());
|
||||
}
|
||||
});
|
||||
ui.checkbox(&mut self.settings.start_elevated, "Always start elevated");
|
||||
}
|
||||
|
||||
@@ -14,9 +14,3 @@ impl From<BlockedStatus> for egui::Color32 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockedStatus {
|
||||
pub fn to_color32(self) -> egui::Color32 {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
+58
-57
@@ -2,6 +2,7 @@ use crate::{
|
||||
gui::{
|
||||
app::{App, WINDOW_SIZE},
|
||||
tools,
|
||||
ui_ext::UiExt,
|
||||
},
|
||||
util::consts::{
|
||||
APP_STORAGE_PATH,
|
||||
@@ -11,6 +12,62 @@ use crate::{
|
||||
use eframe::egui;
|
||||
|
||||
impl App {
|
||||
fn add_debug_viewport_contents(&mut self, ui: &mut egui::Ui) {
|
||||
ui.collapsing("misc", |ui| {
|
||||
if ui.button("open storage path").clicked() {
|
||||
open::that_detached(APP_STORAGE_PATH.as_path()).unwrap();
|
||||
}
|
||||
ui.checkbox(
|
||||
&mut self.meta.newer_version_available,
|
||||
"spoof new version available",
|
||||
)
|
||||
.on_hover_text("(this could already be checked if\nthere actually IS a new version)");
|
||||
ui.scope(|ui| {
|
||||
use windows::Win32::UI::WindowsAndMessaging::{
|
||||
GetForegroundWindow, GetWindowTextW,
|
||||
};
|
||||
let mut buffer = [0; 512];
|
||||
let current_title = unsafe {
|
||||
let hwnd = GetForegroundWindow();
|
||||
let length = GetWindowTextW(hwnd, &mut buffer);
|
||||
String::from_utf16_lossy(&buffer[..length as usize])
|
||||
};
|
||||
ui.label(format!("focused: \"{current_title}\""));
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("blocked_status");
|
||||
egui::ComboBox::from_id_salt("blocked_status")
|
||||
.selected_text(self.game_networking.blocked_status.to_string())
|
||||
.show_ui(ui, |ui| {
|
||||
ui.build_menu(&mut self.game_networking.blocked_status);
|
||||
});
|
||||
});
|
||||
});
|
||||
ui.collapsing("anti afk", |ui| {
|
||||
ui.label(format!(
|
||||
"timer: {}",
|
||||
self.anti_afk.interval.elapsed().as_secs()
|
||||
));
|
||||
ui.label(format!("can activate: {}", self.anti_afk.can_activate()));
|
||||
});
|
||||
ui.collapsing("sysinfo", |ui| {
|
||||
if ui.button("refresh all").clicked() {
|
||||
self.sysinfo.refresh_all();
|
||||
}
|
||||
let pid = self
|
||||
.sysinfo
|
||||
.processes()
|
||||
.iter()
|
||||
.find(|(_, p)| p.name() == EXE_ENHANCED || p.name() == EXE_LEGACY)
|
||||
.map_or_else(
|
||||
|| "no pid found!".to_owned(),
|
||||
|(pid, _)| pid.as_u32().to_string(),
|
||||
);
|
||||
ui.label(format!("gta pid: {pid}"));
|
||||
});
|
||||
ui.collapsing("app state", |ui| ui.label(format!("{self:#?}")));
|
||||
}
|
||||
|
||||
pub fn show_debug_viewport(&mut self, ctx: &egui::Context) {
|
||||
let main = ctx.input(|i| i.viewport().outer_rect.unwrap_or(egui::Rect::EVERYTHING));
|
||||
let builder = egui::ViewportBuilder::default()
|
||||
@@ -30,63 +87,7 @@ impl App {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
egui::ScrollArea::both()
|
||||
.auto_shrink([false, true])
|
||||
.show(ui, |ui| {
|
||||
ui.collapsing("misc", |ui| {
|
||||
if ui.button("open storage path").clicked() {
|
||||
open::that_detached(APP_STORAGE_PATH.as_path()).unwrap();
|
||||
}
|
||||
ui.checkbox(
|
||||
&mut self.meta.newer_version_available,
|
||||
"spoof new version available",
|
||||
)
|
||||
.on_hover_text("(this could already be checked if\nthere actually IS a new version)");
|
||||
ui.scope(|ui| {
|
||||
use windows::Win32::UI::WindowsAndMessaging::{GetForegroundWindow, GetWindowTextW};
|
||||
let mut buffer = [0; 512];
|
||||
let current_title = unsafe {
|
||||
let hwnd = GetForegroundWindow();
|
||||
let length = GetWindowTextW(hwnd, &mut buffer);
|
||||
String::from_utf16_lossy(&buffer[..length as usize])
|
||||
};
|
||||
ui.label(format!("focused: \"{current_title}\""));
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("blocked_status");
|
||||
egui::ComboBox::from_id_salt("blocked_status")
|
||||
.selected_text(&self.game_networking.blocked_status.to_string())
|
||||
.show_ui(ui, |ui| {
|
||||
tools::build_menu(ui, &mut self.game_networking.blocked_status);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
ui.collapsing("anti afk", |ui| {
|
||||
ui.label(format!(
|
||||
"timer: {}",
|
||||
self.anti_afk.interval.elapsed().as_secs()
|
||||
));
|
||||
ui.label(format!(
|
||||
"can activate: {}",
|
||||
self.anti_afk.can_activate()
|
||||
));
|
||||
});
|
||||
ui.collapsing("sysinfo", |ui| {
|
||||
if ui.button("refresh all").clicked() {
|
||||
self.sysinfo.refresh_all();
|
||||
}
|
||||
let pid = self
|
||||
.sysinfo
|
||||
.processes()
|
||||
.iter()
|
||||
.find(|(_, p)| p.name() == EXE_ENHANCED || p.name() == EXE_LEGACY)
|
||||
.map_or_else(
|
||||
|| "no pid found!".to_owned(),
|
||||
|(pid, _)| pid.as_u32().to_string(),
|
||||
);
|
||||
ui.label(format!("gta pid: {pid}"));
|
||||
});
|
||||
ui.collapsing("app state", |ui| ui.label(format!("{self:#?}")));
|
||||
});
|
||||
.show(ui, |ui| self.add_debug_viewport_contents(ui));
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
+19
-8
@@ -3,10 +3,14 @@ use crate::{
|
||||
app::{App, WINDOW_SIZE},
|
||||
tools,
|
||||
},
|
||||
util::{self, consts::APP_STORAGE_PATH, persistent_state::PersistentState},
|
||||
util::{consts::APP_STORAGE_PATH, persistent_state::PersistentState, win},
|
||||
};
|
||||
use eframe::egui;
|
||||
use std::{fs::File, io::Write};
|
||||
use std::{
|
||||
fs::File,
|
||||
io::Write,
|
||||
time::{SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
|
||||
fn panic_hook(panic_info: &std::panic::PanicHookInfo<'_>) {
|
||||
let log_path = APP_STORAGE_PATH.join("panic.log");
|
||||
@@ -15,8 +19,11 @@ fn panic_hook(panic_info: &std::panic::PanicHookInfo<'_>) {
|
||||
.append(true)
|
||||
.open(log_path)
|
||||
.unwrap();
|
||||
let timestamp = chrono::Local::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, false);
|
||||
let backtrace = std::backtrace::Backtrace::force_capture();
|
||||
let timestamp = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
let backtrace = std::backtrace::Backtrace::capture();
|
||||
let message = format!("[{timestamp}]\n{panic_info}\nstack backtrace:\n{backtrace}\n");
|
||||
file.write_all(message.as_bytes()).unwrap();
|
||||
}
|
||||
@@ -26,8 +33,10 @@ fn app_creator(
|
||||
) -> Result<Box<dyn eframe::App>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
// use our own panic hook which logs all panics to a file
|
||||
std::panic::set_hook(Box::new(panic_hook));
|
||||
// initialize http client (nyquest) for windows
|
||||
nyquest_backend_winrt::register();
|
||||
// initialize App early to modify some things before returning it
|
||||
let mut app = Box::<App>::default();
|
||||
let mut app = Box::new(App::default());
|
||||
// load previously selected launch platform & settings from persistent state
|
||||
if let Some(persistent_state) = PersistentState::get() {
|
||||
app.launch.selected = persistent_state.launcher;
|
||||
@@ -35,16 +44,18 @@ fn app_creator(
|
||||
}
|
||||
// check if we're elevated. if not, and the user wants an elevated launch - relaunch elevated
|
||||
if !app.flags.elevated && app.settings.start_elevated {
|
||||
util::win::elevate(util::win::ElevationExitMethod::Forced);
|
||||
win::elevate(win::ElevationExitMethod::Forced);
|
||||
}
|
||||
// refresh sysinfo because it initializes with nothing
|
||||
app.sysinfo.refresh_all();
|
||||
// enable image loading support in egui
|
||||
egui_extras::install_image_loaders(&cc.egui_ctx);
|
||||
// set our initial theme, from earlier loaded settings
|
||||
// set our initial theme, from earlier loaded settings. we set the egui theme
|
||||
// to dark here to work around system theme based switching of the egui style
|
||||
cc.egui_ctx.set_theme(egui::Theme::Dark);
|
||||
catppuccin_egui::set_theme(&cc.egui_ctx, app.settings.theme.into());
|
||||
// apply some global styling that we like
|
||||
cc.egui_ctx.style_mut(|style| {
|
||||
cc.egui_ctx.all_styles_mut(|style| {
|
||||
style.spacing.item_spacing = egui::vec2(4.0, 4.0);
|
||||
style.interaction.selectable_labels = false;
|
||||
});
|
||||
|
||||
+13
-11
@@ -1,8 +1,12 @@
|
||||
use crate::util::win;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum::{Display, EnumIter};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Display, PartialEq, Eq, Serialize, Deserialize, EnumIter)]
|
||||
#[derive(Clone, Copy, Debug, Default, Display, PartialEq, Eq, Serialize, Deserialize, EnumIter)]
|
||||
pub enum Theme {
|
||||
#[default]
|
||||
#[strum(to_string = "Auto")]
|
||||
Auto,
|
||||
#[strum(to_string = "Catppuccin Latte")]
|
||||
CatppuccinLatte,
|
||||
#[strum(to_string = "Catppuccin Frappe")]
|
||||
@@ -16,6 +20,13 @@ pub enum Theme {
|
||||
impl From<Theme> for catppuccin_egui::Theme {
|
||||
fn from(val: Theme) -> Self {
|
||||
match val {
|
||||
Theme::Auto => {
|
||||
if win::is_system_theme_dark() {
|
||||
catppuccin_egui::MOCHA
|
||||
} else {
|
||||
catppuccin_egui::LATTE
|
||||
}
|
||||
}
|
||||
Theme::CatppuccinLatte => catppuccin_egui::LATTE,
|
||||
Theme::CatppuccinFrappe => catppuccin_egui::FRAPPE,
|
||||
Theme::CatppuccinMacchiato => catppuccin_egui::MACCHIATO,
|
||||
@@ -24,17 +35,8 @@ impl From<Theme> for catppuccin_egui::Theme {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
pub struct Settings {
|
||||
pub theme: Theme,
|
||||
pub start_elevated: bool,
|
||||
}
|
||||
|
||||
impl Default for Settings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
theme: Theme::CatppuccinMocha,
|
||||
start_elevated: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,25 +11,6 @@ pub fn load_icon() -> egui::IconData {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn header(ui: &mut egui::Ui, text: &str) {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(egui::RichText::new(text).font(egui::FontId::new(
|
||||
12.5,
|
||||
egui::FontFamily::Name("Ubuntu-Regular".into()),
|
||||
)));
|
||||
ui.add(egui::Separator::default().horizontal());
|
||||
});
|
||||
}
|
||||
|
||||
pub fn build_menu<E>(ui: &mut egui::Ui, current_value: &mut E)
|
||||
where
|
||||
E: strum::IntoEnumIterator + std::fmt::Display + std::cmp::PartialEq + Copy,
|
||||
{
|
||||
E::iter().for_each(|variant| {
|
||||
ui.selectable_value(current_value, variant, variant.to_string());
|
||||
});
|
||||
}
|
||||
|
||||
pub fn debug_keycombo_pressed(ctx: &egui::Context) -> bool {
|
||||
ctx.input(|i| i.modifiers.all() && i.key_pressed(egui::Key::D))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
use eframe::egui;
|
||||
|
||||
pub trait UiExt {
|
||||
fn header(&mut self, text: &str);
|
||||
fn build_menu<E>(&mut self, current_value: &mut E)
|
||||
where
|
||||
E: strum::IntoEnumIterator + std::fmt::Display + std::cmp::PartialEq + Copy;
|
||||
fn create_indicator_dot(&mut self, colour: impl Into<egui::Color32>) -> egui::Response;
|
||||
}
|
||||
|
||||
impl UiExt for egui::Ui {
|
||||
fn header(&mut self, text: &str) {
|
||||
self.horizontal(|ui| {
|
||||
ui.label(egui::RichText::new(text).font(egui::FontId::new(
|
||||
12.5,
|
||||
egui::FontFamily::Name("Ubuntu-Regular".into()),
|
||||
)));
|
||||
ui.add(egui::Separator::default().horizontal());
|
||||
});
|
||||
}
|
||||
|
||||
fn build_menu<E>(&mut self, current_value: &mut E)
|
||||
where
|
||||
E: strum::IntoEnumIterator + std::fmt::Display + std::cmp::PartialEq + Copy,
|
||||
{
|
||||
E::iter().for_each(|variant| {
|
||||
self.selectable_value(current_value, variant, variant.to_string());
|
||||
});
|
||||
}
|
||||
|
||||
fn create_indicator_dot(&mut self, colour: impl Into<egui::Color32>) -> egui::Response {
|
||||
self.add(
|
||||
egui::Image::new(egui::include_image!("../../assets/circle.svg"))
|
||||
.max_size([4.0, 4.0].into())
|
||||
.tint(colour),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
compile_error!("This application must be compiled on Windows.");
|
||||
|
||||
mod features;
|
||||
mod gui;
|
||||
mod util;
|
||||
|
||||
+23
-10
@@ -1,4 +1,6 @@
|
||||
use nyquest::{ClientBuilder, blocking::Request};
|
||||
use semver::Version;
|
||||
use serde::Deserialize;
|
||||
|
||||
const APP_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"));
|
||||
const CODEBERG_ENDPOINT_ROOT: &str = "https://codeberg.org/api/v1";
|
||||
@@ -12,24 +14,35 @@ pub struct Release {
|
||||
impl Default for Release {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
version: Version::parse(env!("CARGO_PKG_VERSION")).unwrap(),
|
||||
version: Version::new(0, 0, 0),
|
||||
download_url: String::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct LatestRelease {
|
||||
tag_name: String,
|
||||
assets: Vec<Asset>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Asset {
|
||||
browser_download_url: String,
|
||||
}
|
||||
|
||||
pub fn get_latest_release() -> Option<Release> {
|
||||
let request_url = format!("{CODEBERG_ENDPOINT_ROOT}/repos/futile/gta-tools/releases/latest");
|
||||
let ureq: ureq::Agent = ureq::Agent::config_builder()
|
||||
let client = ClientBuilder::default()
|
||||
.user_agent(APP_USER_AGENT)
|
||||
.build()
|
||||
.into();
|
||||
let mut response = ureq.get(request_url).call().ok()?;
|
||||
let json = response.body_mut().read_json::<serde_json::Value>().ok()?;
|
||||
let tag_name = json["tag_name"].as_str()?;
|
||||
let browser_download_url = json["assets"][0]["browser_download_url"].as_str()?;
|
||||
.build_blocking()
|
||||
.unwrap();
|
||||
let response = client.request(Request::get(request_url)).unwrap();
|
||||
let json = response.json::<LatestRelease>().ok()?;
|
||||
let tag_name = json.tag_name;
|
||||
let browser_download_url = &json.assets[0].browser_download_url;
|
||||
Some(Release {
|
||||
version: Version::parse(tag_name).expect("expected a valid semver pattern"),
|
||||
download_url: String::from(browser_download_url),
|
||||
version: Version::parse(&tag_name).ok()?,
|
||||
download_url: browser_download_url.to_owned(),
|
||||
})
|
||||
}
|
||||
|
||||
+4
-3
@@ -1,7 +1,8 @@
|
||||
use std::{path::PathBuf, sync::LazyLock};
|
||||
use std::{env, path::PathBuf, sync::LazyLock};
|
||||
|
||||
pub static APP_STORAGE_PATH: LazyLock<PathBuf> =
|
||||
LazyLock::new(|| dirs::config_local_dir().unwrap().join("GTA Tools"));
|
||||
pub static APP_STORAGE_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
PathBuf::from(env::var("LOCALAPPDATA").unwrap_or_else(|_| String::from("."))).join("GTA Tools")
|
||||
});
|
||||
|
||||
pub mod game {
|
||||
pub const EXE_ENHANCED: &str = "GTA5_Enhanced.exe";
|
||||
|
||||
@@ -83,3 +83,17 @@ pub fn is_elevated() -> bool {
|
||||
result.is_ok() && elevation.TokenIsElevated != 0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_system_theme_dark() -> bool {
|
||||
use winreg::RegKey;
|
||||
let hkcu = RegKey::predef(winreg::enums::HKEY_CURRENT_USER);
|
||||
let Ok(subkey) =
|
||||
hkcu.open_subkey("Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize")
|
||||
else {
|
||||
return true;
|
||||
};
|
||||
let Ok(dword): Result<u32, std::io::Error> = subkey.get_value("AppsUseLightTheme") else {
|
||||
return true;
|
||||
};
|
||||
dword != 1
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user