Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
202554e03b | ||
|
|
da2b15a0b6 | ||
|
|
ccc27b1944 | ||
|
|
10168e84d1 |
Generated
+1
-1
@@ -1455,7 +1455,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gta-tools"
|
name = "gta-tools"
|
||||||
version = "0.5.0"
|
version = "0.5.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"catppuccin-egui",
|
"catppuccin-egui",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "gta-tools"
|
name = "gta-tools"
|
||||||
version = "0.5.0"
|
version = "0.5.1"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# GTA Tools
|
# GTA Tools
|
||||||
A toolset of convenient things for GTA 5 Online.
|
A toolset of convenient things for GTA V Online.
|
||||||
|
|
||||||

|

|
||||||
|
|||||||
+21
-15
@@ -7,8 +7,8 @@ const INTERVAL: Duration = Duration::from_secs(3);
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ForceClose {
|
pub struct ForceClose {
|
||||||
pub button_text: String,
|
pub button_text: String,
|
||||||
prompting: bool,
|
timer: Instant,
|
||||||
interval: Instant,
|
counting: bool,
|
||||||
current_frame: bool,
|
current_frame: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16,8 +16,8 @@ impl Default for ForceClose {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
button_text: "Force close game".to_owned(),
|
button_text: "Force close game".to_owned(),
|
||||||
prompting: false,
|
timer: Instant::now(),
|
||||||
interval: Instant::now(),
|
counting: false,
|
||||||
current_frame: false,
|
current_frame: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,22 +25,28 @@ impl Default for ForceClose {
|
|||||||
|
|
||||||
impl ForceClose {
|
impl ForceClose {
|
||||||
pub fn prompt(&mut self, force_close_button_clicked: bool, sysinfo: &mut System) {
|
pub fn prompt(&mut self, force_close_button_clicked: bool, sysinfo: &mut System) {
|
||||||
if force_close_button_clicked && !self.prompting {
|
if force_close_button_clicked && !self.counting {
|
||||||
*self = Self {
|
self.button_text = "Are you sure?".to_owned();
|
||||||
button_text: "Are you sure?".to_owned(),
|
self.timer = Instant::now();
|
||||||
prompting: true,
|
self.counting = true;
|
||||||
interval: Instant::now(),
|
self.current_frame = true;
|
||||||
current_frame: true,
|
|
||||||
}
|
}
|
||||||
}
|
if self.counting && self.timer.elapsed() >= INTERVAL {
|
||||||
if self.prompting && self.interval.elapsed() <= INTERVAL {
|
self.reset();
|
||||||
|
} else {
|
||||||
if force_close_button_clicked && !self.current_frame {
|
if force_close_button_clicked && !self.current_frame {
|
||||||
activate(sysinfo);
|
activate(sysinfo);
|
||||||
|
self.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.finish_current_frame();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset(&mut self) {
|
||||||
*self = Self::default();
|
*self = Self::default();
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
*self = Self::default();
|
fn finish_current_frame(&mut self) {
|
||||||
}
|
|
||||||
if self.current_frame {
|
if self.current_frame {
|
||||||
self.current_frame = false;
|
self.current_frame = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
use crate::util::consts::game::{EXE_ENHANCED, EXE_LEGACY};
|
use crate::util::consts::{
|
||||||
use std::path::Path;
|
colours,
|
||||||
|
game::{EXE_ENHANCED, EXE_LEGACY},
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
path::Path,
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
use sysinfo::System;
|
use sysinfo::System;
|
||||||
use windows::{
|
use windows::{
|
||||||
Win32::{
|
Win32::{
|
||||||
@@ -13,28 +19,63 @@ use windows::{
|
|||||||
CoUninitialize,
|
CoUninitialize,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
core::{BSTR, HRESULT},
|
core::BSTR,
|
||||||
};
|
};
|
||||||
|
|
||||||
const FILTER_NAME_IN: &str = "[GTA Tools] Block all inbound traffic for GTA V";
|
const FILTER_NAME_IN: &str = "[GTA Tools] Block all inbound traffic for GTA V";
|
||||||
const FILTER_NAME_OUT: &str = "[GTA Tools] Block all outbound traffic for GTA V";
|
const FILTER_NAME_OUT: &str = "[GTA Tools] Block all outbound traffic for GTA V";
|
||||||
|
|
||||||
|
const INTERVAL: Duration = Duration::from_secs(3);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
pub enum BlockedStatus {
|
||||||
|
Blocked,
|
||||||
|
Failed,
|
||||||
|
Unblocked,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<bool> for BlockedStatus {
|
||||||
|
fn from(value: bool) -> Self {
|
||||||
|
match value {
|
||||||
|
true => Self::Blocked,
|
||||||
|
false => Self::Unblocked,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<BlockedStatus> for eframe::egui::Color32 {
|
||||||
|
fn from(value: BlockedStatus) -> Self {
|
||||||
|
match value {
|
||||||
|
BlockedStatus::Blocked => colours::RED,
|
||||||
|
BlockedStatus::Failed => colours::YELLOW,
|
||||||
|
BlockedStatus::Unblocked => colours::GREEN,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockedStatus {
|
||||||
|
pub fn to_color32(&self) -> eframe::egui::Color32 {
|
||||||
|
(*self).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GameNetworking {
|
pub struct GameNetworking {
|
||||||
pub is_blocked: bool,
|
|
||||||
com_initialized: bool,
|
com_initialized: bool,
|
||||||
policy: INetFwPolicy2,
|
pub blocked_status: BlockedStatus,
|
||||||
|
timer: Instant,
|
||||||
|
counting: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for GameNetworking {
|
impl Default for GameNetworking {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let result = unsafe { CoInitializeEx(None, COINIT_MULTITHREADED) };
|
|
||||||
let mut gn = Self {
|
let mut gn = Self {
|
||||||
is_blocked: false,
|
blocked_status: BlockedStatus::Unblocked,
|
||||||
com_initialized: result != HRESULT(0x80010106u32 as i32),
|
com_initialized: unsafe { CoInitializeEx(None, COINIT_MULTITHREADED) }.is_ok(),
|
||||||
policy: unsafe { CoCreateInstance(&NetFwPolicy2, None, CLSCTX_INPROC_SERVER).unwrap() },
|
timer: Instant::now(),
|
||||||
|
counting: false,
|
||||||
};
|
};
|
||||||
gn.is_blocked = gn.is_blocked();
|
gn.blocked_status = gn.is_blocked().into();
|
||||||
gn
|
gn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,9 +93,12 @@ impl Drop for GameNetworking {
|
|||||||
impl GameNetworking {
|
impl GameNetworking {
|
||||||
pub fn block_all(&mut self, sysinfo: &mut System) {
|
pub fn block_all(&mut self, sysinfo: &mut System) {
|
||||||
let Some(exe_path) = get_game_exe_path(sysinfo) else {
|
let Some(exe_path) = get_game_exe_path(sysinfo) else {
|
||||||
|
self.blocked_status = BlockedStatus::Failed;
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let rules = unsafe { self.policy.Rules().unwrap() };
|
let policy: INetFwPolicy2 =
|
||||||
|
unsafe { CoCreateInstance(&NetFwPolicy2, None, CLSCTX_INPROC_SERVER).unwrap() };
|
||||||
|
let rules = unsafe { policy.Rules().unwrap() };
|
||||||
let filter_name_in = BSTR::from(FILTER_NAME_IN);
|
let filter_name_in = BSTR::from(FILTER_NAME_IN);
|
||||||
let filter_name_out = BSTR::from(FILTER_NAME_OUT);
|
let filter_name_out = BSTR::from(FILTER_NAME_OUT);
|
||||||
unsafe {
|
unsafe {
|
||||||
@@ -84,11 +128,13 @@ impl GameNetworking {
|
|||||||
outbound_rule.SetProtocol(NET_FW_IP_PROTOCOL_ANY.0).unwrap();
|
outbound_rule.SetProtocol(NET_FW_IP_PROTOCOL_ANY.0).unwrap();
|
||||||
rules.Add(&outbound_rule).unwrap();
|
rules.Add(&outbound_rule).unwrap();
|
||||||
}
|
}
|
||||||
self.is_blocked = self.is_blocked();
|
self.blocked_status = self.is_blocked().into();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unblock_all(&mut self) {
|
pub fn unblock_all(&mut self) {
|
||||||
let rules = unsafe { self.policy.Rules().unwrap() };
|
let policy: INetFwPolicy2 =
|
||||||
|
unsafe { CoCreateInstance(&NetFwPolicy2, None, CLSCTX_INPROC_SERVER).unwrap() };
|
||||||
|
let rules = unsafe { policy.Rules().unwrap() };
|
||||||
unsafe {
|
unsafe {
|
||||||
let result = rules.Remove(&BSTR::from(FILTER_NAME_IN));
|
let result = rules.Remove(&BSTR::from(FILTER_NAME_IN));
|
||||||
if let Err(ref why) = result {
|
if let Err(ref why) = result {
|
||||||
@@ -103,15 +149,31 @@ impl GameNetworking {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.is_blocked = self.is_blocked();
|
self.blocked_status = self.is_blocked().into();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_blocked(&self) -> bool {
|
fn is_blocked(&self) -> bool {
|
||||||
let rules = unsafe { self.policy.Rules().unwrap() };
|
let policy: INetFwPolicy2 =
|
||||||
|
unsafe { CoCreateInstance(&NetFwPolicy2, None, CLSCTX_INPROC_SERVER).unwrap() };
|
||||||
|
let rules = unsafe { policy.Rules().unwrap() };
|
||||||
let in_rule_exists = unsafe { rules.Item(&BSTR::from(FILTER_NAME_IN)).is_ok() };
|
let in_rule_exists = unsafe { rules.Item(&BSTR::from(FILTER_NAME_IN)).is_ok() };
|
||||||
let out_rule_exists = unsafe { rules.Item(&BSTR::from(FILTER_NAME_OUT)).is_ok() };
|
let out_rule_exists = unsafe { rules.Item(&BSTR::from(FILTER_NAME_OUT)).is_ok() };
|
||||||
in_rule_exists || out_rule_exists
|
in_rule_exists || out_rule_exists
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn if_failed_return_to_unblocked(&mut self) {
|
||||||
|
if self.blocked_status == BlockedStatus::Failed && !self.counting {
|
||||||
|
self.counting = true;
|
||||||
|
self.timer = Instant::now();
|
||||||
|
}
|
||||||
|
if self.blocked_status == BlockedStatus::Failed
|
||||||
|
&& self.counting
|
||||||
|
&& self.timer.elapsed() >= INTERVAL
|
||||||
|
{
|
||||||
|
self.counting = false;
|
||||||
|
self.blocked_status = BlockedStatus::Unblocked;
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_game_exe_path(sysinfo: &mut System) -> Option<&Path> {
|
fn get_game_exe_path(sysinfo: &mut System) -> Option<&Path> {
|
||||||
|
|||||||
+2
-5
@@ -156,15 +156,12 @@ impl App {
|
|||||||
{
|
{
|
||||||
self.game_networking.unblock_all();
|
self.game_networking.unblock_all();
|
||||||
}
|
}
|
||||||
let tint = match self.game_networking.is_blocked {
|
|
||||||
true => egui::Color32::from_hex("#f96554").unwrap(),
|
|
||||||
false => egui::Color32::from_hex("#68f954").unwrap(),
|
|
||||||
};
|
|
||||||
ui.add(
|
ui.add(
|
||||||
egui::Image::new(egui::include_image!("../../assets/circle.svg"))
|
egui::Image::new(egui::include_image!("../../assets/circle.svg"))
|
||||||
.max_size([4.0, 4.0].into())
|
.max_size([4.0, 4.0].into())
|
||||||
.tint(tint),
|
.tint(self.game_networking.blocked_status.to_color32()),
|
||||||
);
|
);
|
||||||
|
self.game_networking.if_failed_return_to_unblocked();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
response.response.on_disabled_hover_text(
|
response.response.on_disabled_hover_text(
|
||||||
|
|||||||
@@ -8,3 +8,10 @@ pub mod game {
|
|||||||
pub const EXE_LEGACY: &str = "GTA5.exe";
|
pub const EXE_LEGACY: &str = "GTA5.exe";
|
||||||
pub const WINDOW_TITLE: &str = "Grand Theft Auto V";
|
pub const WINDOW_TITLE: &str = "Grand Theft Auto V";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod colours {
|
||||||
|
use eframe::egui::Color32;
|
||||||
|
pub const RED: Color32 = Color32::from_rgb(249, 101, 84);
|
||||||
|
pub const YELLOW: Color32 = Color32::from_rgb(249, 236, 84);
|
||||||
|
pub const GREEN: Color32 = Color32::from_rgb(104, 249, 84);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user