Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ce7f3459d | ||
|
|
c8cbb51f43 | ||
|
|
9c53239276 | ||
|
|
af5ea259e9 | ||
|
|
162350699a | ||
|
|
2977398437 | ||
|
|
36dce5aa1e | ||
|
|
6935b852ce | ||
|
|
1c048e6aff | ||
|
|
84a659a2b1 | ||
|
|
db4ca22f95 | ||
|
|
284c4bb46d |
Generated
+46
-1
@@ -156,6 +156,12 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
|
checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android-tzdata"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "android_system_properties"
|
name = "android_system_properties"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
@@ -596,6 +602,20 @@ dependencies = [
|
|||||||
"libc",
|
"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",
|
||||||
|
"js-sys",
|
||||||
|
"num-traits",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows-link",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clipboard-win"
|
name = "clipboard-win"
|
||||||
version = "5.4.0"
|
version = "5.4.0"
|
||||||
@@ -1366,9 +1386,10 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gta-tools"
|
name = "gta-tools"
|
||||||
version = "0.4.0"
|
version = "0.4.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"catppuccin-egui",
|
"catppuccin-egui",
|
||||||
|
"chrono",
|
||||||
"dirs",
|
"dirs",
|
||||||
"eframe",
|
"eframe",
|
||||||
"egui_extras",
|
"egui_extras",
|
||||||
@@ -1426,6 +1447,30 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[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 0.61.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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]]
|
[[package]]
|
||||||
name = "icu_collections"
|
name = "icu_collections"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
|||||||
+2
-1
@@ -1,12 +1,13 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "gta-tools"
|
name = "gta-tools"
|
||||||
version = "0.4.0"
|
version = "0.4.1"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
catppuccin-egui = { version = "5.5.0", default-features = false, features = [
|
catppuccin-egui = { version = "5.5.0", default-features = false, features = [
|
||||||
"egui31",
|
"egui31",
|
||||||
] }
|
] }
|
||||||
|
chrono = "0.4.40"
|
||||||
dirs = "6.0.0"
|
dirs = "6.0.0"
|
||||||
eframe = "0.31.1"
|
eframe = "0.31.1"
|
||||||
egui_extras = { version = "0.31.1", features = ["image"] }
|
egui_extras = { version = "0.31.1", features = ["image"] }
|
||||||
|
|||||||
@@ -26,15 +26,18 @@ impl Default for AntiAfk {
|
|||||||
|
|
||||||
impl AntiAfk {
|
impl AntiAfk {
|
||||||
pub fn activate(&mut self) {
|
pub fn activate(&mut self) {
|
||||||
if util::win::is_window_focused(GTA_WINDOW_TITLE)
|
if can_activate() {
|
||||||
&& !util::win::is_any_key_pressed(&PRESS_KEYS)
|
|
||||||
{
|
|
||||||
send(&PRESS_KEYS);
|
send(&PRESS_KEYS);
|
||||||
}
|
}
|
||||||
self.interval = Instant::now();
|
self.interval = Instant::now();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn can_activate() -> bool {
|
||||||
|
use util::win::{is_any_key_pressed, is_cursor_visible, is_window_focused};
|
||||||
|
is_window_focused(GTA_WINDOW_TITLE) && !is_any_key_pressed(&PRESS_KEYS) && !is_cursor_visible()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn send(vk_codes: &[u8]) {
|
pub fn send(vk_codes: &[u8]) {
|
||||||
vk_codes.iter().for_each(|vk_code: &u8| unsafe {
|
vk_codes.iter().for_each(|vk_code: &u8| unsafe {
|
||||||
keybd_event(
|
keybd_event(
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ fn get_gta_pid(sysinfo: &mut System) -> u32 {
|
|||||||
.find(|(_, p)| p.name() == ENHANCED || p.name() == LEGACY)
|
.find(|(_, p)| p.name() == ENHANCED || p.name() == LEGACY)
|
||||||
{
|
{
|
||||||
return pid.as_u32();
|
return pid.as_u32();
|
||||||
};
|
}
|
||||||
u32::MAX
|
u32::MAX
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+35
-10
@@ -9,11 +9,15 @@ use crate::{
|
|||||||
gui::{persistent_state::PersistentState, settings::Settings},
|
gui::{persistent_state::PersistentState, settings::Settings},
|
||||||
util::{
|
util::{
|
||||||
self,
|
self,
|
||||||
consts::{ENHANCED, GTA_WINDOW_TITLE, LEGACY},
|
consts::{APP_STORAGE_PATH, ENHANCED, GTA_WINDOW_TITLE, LEGACY},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use eframe::egui;
|
use eframe::egui;
|
||||||
use std::time::{Duration, Instant};
|
use std::{
|
||||||
|
fs,
|
||||||
|
io::Write,
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
|
|
||||||
const WINDOW_SIZE: [f32; 2] = [240.0, 245.0];
|
const WINDOW_SIZE: [f32; 2] = [240.0, 245.0];
|
||||||
|
|
||||||
@@ -150,7 +154,7 @@ impl App {
|
|||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
if ui.button("Launch").clicked() {
|
if ui.button("Launch").clicked() {
|
||||||
features::launch::launch(&self.launch.selected);
|
features::launch::launch(&self.launch.selected);
|
||||||
};
|
}
|
||||||
build_combo_box::<features::launch::Platform>(ui, &mut self.launch.selected, "Launch");
|
build_combo_box::<features::launch::Platform>(ui, &mut self.launch.selected, "Launch");
|
||||||
});
|
});
|
||||||
let force_close_button = ui.add_sized(
|
let force_close_button = ui.add_sized(
|
||||||
@@ -160,7 +164,7 @@ impl App {
|
|||||||
if force_close_button.clicked() && !self.force_close.prompting {
|
if force_close_button.clicked() && !self.force_close.prompting {
|
||||||
self.force_close.prompting();
|
self.force_close.prompting();
|
||||||
self.flags.current_frame = true;
|
self.flags.current_frame = true;
|
||||||
};
|
}
|
||||||
if self.force_close.prompting
|
if self.force_close.prompting
|
||||||
&& self.force_close.interval.elapsed() <= Duration::from_secs(3)
|
&& self.force_close.interval.elapsed() <= Duration::from_secs(3)
|
||||||
{
|
{
|
||||||
@@ -224,13 +228,13 @@ impl App {
|
|||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
features::game_networking::block_all(&mut self.sysinfo);
|
features::game_networking::block_all(&mut self.sysinfo);
|
||||||
};
|
}
|
||||||
if ui
|
if ui
|
||||||
.add_sized([button_width, 18.0], egui::Button::new("Unblock"))
|
.add_sized([button_width, 18.0], egui::Button::new("Unblock"))
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
features::game_networking::unblock_all();
|
features::game_networking::unblock_all();
|
||||||
};
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
response.response.on_disabled_hover_text(
|
response.response.on_disabled_hover_text(
|
||||||
@@ -271,11 +275,18 @@ impl App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn show_debug(&mut self, _ctx: &egui::Context, ui: &mut egui::Ui) {
|
fn show_debug(&mut self, _ctx: &egui::Context, ui: &mut egui::Ui) {
|
||||||
ui.collapsing("times", |ui| {
|
if ui.button("open storage path").clicked() {
|
||||||
|
open::that_detached(APP_STORAGE_PATH.as_path()).unwrap();
|
||||||
|
}
|
||||||
|
ui.collapsing("anti afk", |ui| {
|
||||||
ui.label(format!(
|
ui.label(format!(
|
||||||
"anti afk timer: {}",
|
"timer: {}",
|
||||||
self.anti_afk.interval.elapsed().as_secs()
|
self.anti_afk.interval.elapsed().as_secs()
|
||||||
))
|
));
|
||||||
|
ui.label(format!(
|
||||||
|
"can activate: {}",
|
||||||
|
features::anti_afk::can_activate()
|
||||||
|
));
|
||||||
});
|
});
|
||||||
ui.collapsing("sysinfo", |ui| {
|
ui.collapsing("sysinfo", |ui| {
|
||||||
if ui.button("refresh all").clicked() {
|
if ui.button("refresh all").clicked() {
|
||||||
@@ -369,15 +380,29 @@ fn load_icon() -> egui::IconData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn panic_hook(panic_info: &std::panic::PanicHookInfo<'_>) {
|
||||||
|
let log_path = APP_STORAGE_PATH.join("panic.log");
|
||||||
|
let mut file = fs::File::options()
|
||||||
|
.create(true)
|
||||||
|
.append(true)
|
||||||
|
.open(log_path)
|
||||||
|
.unwrap();
|
||||||
|
let timestamp = chrono::Local::now().to_rfc3339();
|
||||||
|
let backtrace = std::backtrace::Backtrace::force_capture();
|
||||||
|
let message = format!("[{timestamp}]\n{panic_info}\n\n{backtrace}\n\n");
|
||||||
|
file.write_all(message.as_bytes()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::unnecessary_wraps)]
|
#[allow(clippy::unnecessary_wraps)]
|
||||||
fn app_creator(
|
fn app_creator(
|
||||||
cc: &eframe::CreationContext<'_>,
|
cc: &eframe::CreationContext<'_>,
|
||||||
) -> Result<Box<dyn eframe::App>, Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<Box<dyn eframe::App>, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
|
std::panic::set_hook(Box::new(panic_hook));
|
||||||
let mut app = Box::<App>::default();
|
let mut app = Box::<App>::default();
|
||||||
if let Some(persistent_state) = PersistentState::get() {
|
if let Some(persistent_state) = PersistentState::get() {
|
||||||
app.launch.selected = persistent_state.launcher;
|
app.launch.selected = persistent_state.launcher;
|
||||||
app.settings = persistent_state.settings;
|
app.settings = persistent_state.settings;
|
||||||
};
|
}
|
||||||
let elevated = util::win::is_elevated();
|
let elevated = util::win::is_elevated();
|
||||||
if app.settings.start_elevated && !elevated {
|
if app.settings.start_elevated && !elevated {
|
||||||
util::win::elevate(util::win::ElevationExitMethod::Forced);
|
util::win::elevate(util::win::ElevationExitMethod::Forced);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::{features::launch::Platform, gui::settings::Settings};
|
use crate::{features::launch::Platform, gui::settings::Settings, util::consts::APP_STORAGE_PATH};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
@@ -7,12 +7,7 @@ use std::{
|
|||||||
sync::LazyLock,
|
sync::LazyLock,
|
||||||
};
|
};
|
||||||
|
|
||||||
static CONFIG_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
|
static CONFIG_PATH: LazyLock<PathBuf> = LazyLock::new(|| APP_STORAGE_PATH.join("config.json"));
|
||||||
dirs::config_local_dir()
|
|
||||||
.unwrap()
|
|
||||||
.join("GTA Tools")
|
|
||||||
.join("config.json")
|
|
||||||
});
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct PersistentState {
|
pub struct PersistentState {
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
#![windows_subsystem = "windows"]
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||||
|
|
||||||
mod features;
|
mod features;
|
||||||
mod gui;
|
mod gui;
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
|
use std::{path::PathBuf, sync::LazyLock};
|
||||||
|
|
||||||
pub const ENHANCED: &str = "GTA5_Enhanced.exe";
|
pub const ENHANCED: &str = "GTA5_Enhanced.exe";
|
||||||
pub const LEGACY: &str = "GTA5.exe";
|
pub const LEGACY: &str = "GTA5.exe";
|
||||||
|
|
||||||
pub const GTA_WINDOW_TITLE: &str = "Grand Theft Auto V";
|
pub const GTA_WINDOW_TITLE: &str = "Grand Theft Auto V";
|
||||||
|
|
||||||
|
pub static APP_STORAGE_PATH: LazyLock<PathBuf> =
|
||||||
|
LazyLock::new(|| dirs::config_local_dir().unwrap().join("GTA Tools"));
|
||||||
|
|||||||
@@ -36,6 +36,6 @@ impl Countdown {
|
|||||||
self.i_string = self.i.to_string();
|
self.i_string = self.i.to_string();
|
||||||
if self.i == 0 {
|
if self.i == 0 {
|
||||||
self.reset();
|
self.reset();
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+31
-20
@@ -6,7 +6,10 @@ use windows::{
|
|||||||
UI::{
|
UI::{
|
||||||
Input::KeyboardAndMouse::GetAsyncKeyState,
|
Input::KeyboardAndMouse::GetAsyncKeyState,
|
||||||
Shell::ShellExecuteW,
|
Shell::ShellExecuteW,
|
||||||
WindowsAndMessaging::{GetForegroundWindow, GetWindowTextW, SW_NORMAL},
|
WindowsAndMessaging::{
|
||||||
|
CURSOR_SHOWING, CURSORINFO, GetCursorInfo, GetForegroundWindow, GetWindowTextW,
|
||||||
|
SW_NORMAL,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
core::{HSTRING, PCWSTR},
|
core::{HSTRING, PCWSTR},
|
||||||
@@ -17,11 +20,22 @@ pub enum ElevationExitMethod<'a> {
|
|||||||
Forced,
|
Forced,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_cursor_visible() -> bool {
|
||||||
|
let mut ci = CURSORINFO {
|
||||||
|
cbSize: u32::try_from(std::mem::size_of::<CURSORINFO>()).unwrap(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
unsafe {
|
||||||
|
GetCursorInfo(&mut ci).unwrap();
|
||||||
|
}
|
||||||
|
ci.flags == CURSOR_SHOWING
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::cast_sign_loss)]
|
#[allow(clippy::cast_sign_loss)]
|
||||||
pub fn is_window_focused(target_title: &str) -> bool {
|
pub fn is_window_focused(target_title: &str) -> bool {
|
||||||
|
let mut buffer = [0; 512];
|
||||||
unsafe {
|
unsafe {
|
||||||
let hwnd = GetForegroundWindow();
|
let hwnd = GetForegroundWindow();
|
||||||
let mut buffer: [u16; 512] = [0; 512];
|
|
||||||
let length = GetWindowTextW(hwnd, &mut buffer);
|
let length = GetWindowTextW(hwnd, &mut buffer);
|
||||||
let current_title = String::from_utf16_lossy(&buffer[..length as usize]);
|
let current_title = String::from_utf16_lossy(&buffer[..length as usize]);
|
||||||
current_title == target_title
|
current_title == target_title
|
||||||
@@ -30,7 +44,7 @@ pub fn is_window_focused(target_title: &str) -> bool {
|
|||||||
|
|
||||||
pub fn is_any_key_pressed(keys: &[u8]) -> bool {
|
pub fn is_any_key_pressed(keys: &[u8]) -> bool {
|
||||||
keys.iter()
|
keys.iter()
|
||||||
.any(|&key| unsafe { (i32::from(GetAsyncKeyState(i32::from(key))) & 0x8000) != 0 })
|
.any(|&key| unsafe { (GetAsyncKeyState(i32::from(key)) & i16::MIN) != 0 })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn elevate(closing: ElevationExitMethod) {
|
pub fn elevate(closing: ElevationExitMethod) {
|
||||||
@@ -52,24 +66,21 @@ pub fn elevate(closing: ElevationExitMethod) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_elevated() -> bool {
|
pub fn is_elevated() -> bool {
|
||||||
|
let mut token: HANDLE = HANDLE::default();
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut token: HANDLE = HANDLE::default();
|
if OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut token).is_err() {
|
||||||
if OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut token).is_ok() {
|
return false;
|
||||||
let mut elevation = TOKEN_ELEVATION::default();
|
|
||||||
let size = u32::try_from(std::mem::size_of::<TOKEN_ELEVATION>()).unwrap();
|
|
||||||
let mut ret_size = size;
|
|
||||||
let result = GetTokenInformation(
|
|
||||||
token,
|
|
||||||
TokenElevation,
|
|
||||||
Some((&raw mut elevation).cast()),
|
|
||||||
size,
|
|
||||||
&mut ret_size,
|
|
||||||
);
|
|
||||||
CloseHandle(token).unwrap();
|
|
||||||
if result.is_ok() && elevation.TokenIsElevated != 0 {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
false
|
let mut elevation = TOKEN_ELEVATION::default();
|
||||||
|
let mut size = u32::try_from(std::mem::size_of::<TOKEN_ELEVATION>()).unwrap();
|
||||||
|
let result = GetTokenInformation(
|
||||||
|
token,
|
||||||
|
TokenElevation,
|
||||||
|
Some((&raw mut elevation).cast()),
|
||||||
|
size,
|
||||||
|
&mut size,
|
||||||
|
);
|
||||||
|
CloseHandle(token).unwrap();
|
||||||
|
result.is_ok() && elevation.TokenIsElevated != 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user