heavily modify game_networking & fully implement save server blocking

This commit is contained in:
2025-11-21 11:09:18 +00:00
parent a58606c91d
commit 74132ec322
2 changed files with 167 additions and 73 deletions
+107 -36
View File
@@ -1,9 +1,13 @@
use crate::util::{
consts::game::{EXE_ENHANCED, EXE_LEGACY},
system_info::SystemInfo,
use crate::{
gui::settings::BlockMethod,
util::{
consts::game::{EXE_ENHANCED, EXE_LEGACY},
system_info::SystemInfo,
},
};
use std::{
path::Path,
error::Error,
path::{Path, PathBuf},
time::{Duration, Instant},
};
use strum::{Display, EnumIter};
@@ -22,6 +26,7 @@ use windows::{
};
const FILTER_NAME_EXE: &str = "[GTA Tools] Block outbound traffic for all of GTA V";
const FILTER_NAME_SAVE_SERVER: &str = "[GTA Tools] Block outbound traffic to Rockstar save server";
const INTERVAL: Duration = Duration::from_secs(3);
@@ -53,7 +58,11 @@ pub struct GameNetworking {
impl Default for GameNetworking {
fn default() -> Self {
Self {
blocked_status: Self::is_blocked().into(),
blocked_status: if Self::is_save_server_blocked().unwrap() == true {
Self::is_save_server_blocked().unwrap().into()
} else {
Self::is_exe_blocked().unwrap().into()
},
com_initialized: unsafe { CoInitializeEx(None, COINIT_MULTITHREADED) }.is_ok(),
timer: Instant::now(),
counting: false,
@@ -69,46 +78,89 @@ impl Drop for GameNetworking {
}
}
enum Mode {
EntireGame(PathBuf),
SaveServer(String),
}
impl GameNetworking {
pub fn block_exe(&mut self, system_info: &mut SystemInfo) {
fn block_generic(&mut self, mode: Mode) -> Result<(), Box<dyn Error>> {
let policy: INetFwPolicy2 =
unsafe { CoCreateInstance(&NetFwPolicy2, None, CLSCTX_INPROC_SERVER) }?;
let rules = unsafe { policy.Rules() }?;
unsafe { rules.Remove(&BSTR::from(FILTER_NAME_SAVE_SERVER)) }?;
let rule: INetFwRule = unsafe { CoCreateInstance(&NetFwRule, None, CLSCTX_INPROC_SERVER) }?;
unsafe { rule.SetName(&BSTR::from(FILTER_NAME_SAVE_SERVER)) }?;
match mode {
Mode::EntireGame(exe_path) => {
let exe_path = BSTR::from(exe_path.to_string_lossy().to_string());
unsafe { rule.SetApplicationName(&exe_path) }?;
}
Mode::SaveServer(save_server_ip) => {
unsafe { rule.SetRemoteAddresses(&BSTR::from(save_server_ip)) }?;
}
}
unsafe { rule.SetDirection(NET_FW_RULE_DIR_OUT) }?;
unsafe { rule.SetEnabled(true.into()) }?;
unsafe { rule.SetAction(NET_FW_ACTION_BLOCK) }?;
unsafe { rule.SetProtocol(NET_FW_IP_PROTOCOL_ANY.0) }?;
unsafe { rules.Add(&rule) }?;
Ok(())
}
fn unblock_generic(&mut self, filter_name: &str) -> Result<(), Box<dyn Error>> {
let policy: INetFwPolicy2 =
unsafe { CoCreateInstance(&NetFwPolicy2, None, CLSCTX_INPROC_SERVER) }?;
let rules = unsafe { policy.Rules() }?;
unsafe { rules.Remove(&BSTR::from(filter_name)) }?;
Ok(())
}
fn is_blocked_generic(filter_name: &str) -> Result<bool, Box<dyn Error>> {
let policy: INetFwPolicy2 =
unsafe { CoCreateInstance(&NetFwPolicy2, None, CLSCTX_INPROC_SERVER) }?;
let rules = unsafe { policy.Rules() }?;
let rule_exists = unsafe { rules.Item(&BSTR::from(filter_name)) }.is_ok();
Ok(rule_exists)
}
pub fn block_exe(&mut self, system_info: &mut SystemInfo) -> Result<(), Box<dyn Error>> {
let Some(exe_path) = get_game_exe_path(system_info) else {
self.blocked_status = BlockedStatus::Failed;
return;
return Ok(());
};
let policy: INetFwPolicy2 =
unsafe { CoCreateInstance(&NetFwPolicy2, None, CLSCTX_INPROC_SERVER) }.unwrap();
let rules = unsafe { policy.Rules() }.unwrap();
let exe_path = BSTR::from(exe_path.to_string_lossy().to_string());
unsafe { rules.Remove(&BSTR::from(FILTER_NAME_EXE)) }.unwrap();
let rule: INetFwRule =
unsafe { CoCreateInstance(&NetFwRule, None, CLSCTX_INPROC_SERVER) }.unwrap();
unsafe { rule.SetName(&BSTR::from(FILTER_NAME_EXE)) }.unwrap();
unsafe { rule.SetApplicationName(&exe_path) }.unwrap();
unsafe { rule.SetDirection(NET_FW_RULE_DIR_OUT) }.unwrap();
unsafe { rule.SetEnabled(true.into()) }.unwrap();
unsafe { rule.SetAction(NET_FW_ACTION_BLOCK) }.unwrap();
unsafe { rule.SetProtocol(NET_FW_IP_PROTOCOL_ANY.0) }.unwrap();
unsafe { rules.Add(&rule) }.unwrap();
self.blocked_status = Self::is_blocked().into();
self.block_generic(Mode::EntireGame(exe_path.to_path_buf()))?;
self.blocked_status = Self::is_exe_blocked()?.into();
Ok(())
}
pub fn unblock_exe(&mut self) {
let policy: INetFwPolicy2 =
unsafe { CoCreateInstance(&NetFwPolicy2, None, CLSCTX_INPROC_SERVER) }.unwrap();
let rules = unsafe { policy.Rules() }.unwrap();
unsafe { rules.Remove(&BSTR::from(FILTER_NAME_EXE)) }.unwrap();
self.blocked_status = Self::is_blocked().into();
pub fn unblock_exe(&mut self) -> Result<(), Box<dyn Error>> {
self.unblock_generic(FILTER_NAME_EXE)?;
self.blocked_status = Self::is_exe_blocked()?.into();
Ok(())
}
fn is_blocked() -> bool {
let policy: INetFwPolicy2 =
unsafe { CoCreateInstance(&NetFwPolicy2, None, CLSCTX_INPROC_SERVER) }.unwrap();
let rules = unsafe { policy.Rules() }.unwrap();
let exe_rule_exists = unsafe { rules.Item(&BSTR::from(FILTER_NAME_EXE)) }.is_ok();
exe_rule_exists
fn is_exe_blocked() -> Result<bool, Box<dyn Error>> {
Self::is_blocked_generic(FILTER_NAME_EXE)
}
pub fn reset_if_failed(&mut self) {
pub fn block_save_server(&mut self, save_server_ip: &str) -> Result<(), Box<dyn Error>> {
self.block_generic(Mode::SaveServer(save_server_ip.to_owned()))?;
self.blocked_status = Self::is_save_server_blocked()?.into();
Ok(())
}
pub fn unblock_save_server(&mut self) -> Result<(), Box<dyn Error>> {
self.unblock_generic(FILTER_NAME_SAVE_SERVER)?;
self.blocked_status = Self::is_save_server_blocked()?.into();
Ok(())
}
pub fn is_save_server_blocked() -> Result<bool, Box<dyn Error>> {
Self::is_blocked_generic(FILTER_NAME_SAVE_SERVER)
}
pub fn reset_indicator_if_failed(&mut self) {
if self.blocked_status == BlockedStatus::Failed && !self.counting {
self.counting = true;
self.timer = Instant::now();
@@ -118,7 +170,26 @@ impl GameNetworking {
&& self.timer.elapsed() >= INTERVAL
{
self.counting = false;
self.blocked_status = Self::is_blocked().into();
self.blocked_status = Self::is_exe_blocked().unwrap().into();
}
}
pub fn ensure_not_both_blocked_simultaneously(&mut self, block_method: BlockMethod) {
match block_method {
BlockMethod::EntireGame => {
if Self::is_save_server_blocked().unwrap() {
// ignoring the return because if this is an error the user can just thug it out at that point
let _ = self.unblock_save_server();
self.blocked_status = Self::is_exe_blocked().unwrap().into();
}
}
BlockMethod::SaveServer => {
if Self::is_exe_blocked().unwrap() {
// ignoring the return because if this is an error the user can just thug it out at that point
let _ = self.unblock_exe();
self.blocked_status = Self::is_save_server_blocked().unwrap().into();
}
}
}
}
}