heavily modify game_networking & fully implement save server blocking
This commit is contained in:
+107
-36
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+60
-37
@@ -160,15 +160,15 @@ impl App {
|
||||
egui::Frame::new()
|
||||
.outer_margin(egui::vec2(0.0, -2.0))
|
||||
.show(ui, |ui| {
|
||||
let response = ui.add_enabled_ui(self.flags.elevated, |ui| {
|
||||
ui.add_enabled_ui(self.flags.elevated, |ui| {
|
||||
let label = ui.horizontal(|ui| {
|
||||
let label = ui.label("Game's network access");
|
||||
let label = match self.settings.block_method {
|
||||
BlockMethod::EntireGame => ui.label("Game's network access"),
|
||||
BlockMethod::SaveServer => ui.label("Rockstar save server access"),
|
||||
};
|
||||
ui.add_space(1.0);
|
||||
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.reset_if_failed();
|
||||
ui.create_indicator_dot(self.game_networking.blocked_status);
|
||||
self.game_networking.reset_indicator_if_failed();
|
||||
label
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
@@ -179,19 +179,36 @@ impl App {
|
||||
.add_sized([button_width, 18.0], egui::Button::new("Block"))
|
||||
.clicked()
|
||||
{
|
||||
self.game_networking.block_exe(&mut self.system_info);
|
||||
match self.settings.block_method {
|
||||
BlockMethod::EntireGame => {
|
||||
self.game_networking
|
||||
.block_exe(&mut self.system_info)
|
||||
.unwrap();
|
||||
}
|
||||
BlockMethod::SaveServer => {
|
||||
self.game_networking
|
||||
.block_save_server(&self.settings.save_server_ip)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
if ui
|
||||
.add_sized([button_width, 18.0], egui::Button::new("Unblock"))
|
||||
.clicked()
|
||||
{
|
||||
self.game_networking.unblock_exe();
|
||||
match self.settings.block_method {
|
||||
BlockMethod::EntireGame => {
|
||||
self.game_networking.unblock_exe().unwrap();
|
||||
}
|
||||
BlockMethod::SaveServer => {
|
||||
self.game_networking.unblock_save_server().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
response.response.on_disabled_hover_text(
|
||||
"This requires administrator.\nUse the Elevate button.",
|
||||
);
|
||||
})
|
||||
.response
|
||||
.on_disabled_hover_text("This requires administrator.\nUse the Elevate button.");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -228,30 +245,36 @@ impl App {
|
||||
});
|
||||
});
|
||||
ui.collapsing("Network", |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
egui::ComboBox::from_id_salt("Block method")
|
||||
.selected_text(self.settings.block_method.to_string())
|
||||
.show_ui(ui, |ui| {
|
||||
ui.build_menu(&mut self.settings.block_method);
|
||||
});
|
||||
ui.label("Block method");
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_enabled_ui(
|
||||
self.settings.block_method == BlockMethod::SaveServer,
|
||||
|ui| {
|
||||
ui.add(
|
||||
egui::TextEdit::singleline(&mut self.settings.save_server_ip)
|
||||
.char_limit(15)
|
||||
.desired_width(92.0),
|
||||
);
|
||||
ui.label("Save server IP");
|
||||
if ui.button("↺").clicked() {
|
||||
self.settings.save_server_ip = String::from(ROCKSTAR_SAVE_SERVER);
|
||||
};
|
||||
},
|
||||
);
|
||||
});
|
||||
ui.add_enabled_ui(self.flags.elevated, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
egui::ComboBox::from_id_salt("Block method")
|
||||
.selected_text(self.settings.block_method.to_string())
|
||||
.show_ui(ui, |ui| {
|
||||
ui.build_menu(&mut self.settings.block_method);
|
||||
});
|
||||
ui.label("Block method");
|
||||
self.game_networking
|
||||
.ensure_not_both_blocked_simultaneously(self.settings.block_method);
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_enabled_ui(
|
||||
self.settings.block_method == BlockMethod::SaveServer,
|
||||
|ui| {
|
||||
ui.add(
|
||||
egui::TextEdit::singleline(&mut self.settings.save_server_ip)
|
||||
.char_limit(15)
|
||||
.desired_width(92.0),
|
||||
);
|
||||
ui.label("Save server IP");
|
||||
if ui.button("↺").clicked() {
|
||||
self.settings.save_server_ip = String::from(ROCKSTAR_SAVE_SERVER);
|
||||
};
|
||||
},
|
||||
);
|
||||
});
|
||||
})
|
||||
.response
|
||||
.on_disabled_hover_text("This requires administrator.\nUse the Elevate button.");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user