diff --git a/BepInEx.GUI.Loader/src/Patcher.cs b/BepInEx.GUI.Loader/src/EntryPoint.cs similarity index 93% rename from BepInEx.GUI.Loader/src/Patcher.cs rename to BepInEx.GUI.Loader/src/EntryPoint.cs index bba8d94..bed8f68 100644 --- a/BepInEx.GUI.Loader/src/Patcher.cs +++ b/BepInEx.GUI.Loader/src/EntryPoint.cs @@ -12,7 +12,7 @@ namespace BepInEx.GUI.Loader; -internal static class Patcher +internal static class EntryPoint { public static IEnumerable TargetDLLs { get; } = Array.Empty(); @@ -69,8 +69,12 @@ private static string FindGUIExecutable() if (fileName == $"{GuiFileName}.exe") { - Log.Info($"Found bepinex_gui executable in {filePath}"); - return filePath; + var versInfo = FileVersionInfo.GetVersionInfo(filePath); + if (versInfo.FileMajorPart == 3) + { + Log.Info($"Found bepinex_gui v3 executable in {filePath}"); + return filePath; + } } } diff --git a/Thunderstore/manifest.json b/Thunderstore/manifest.json index eb970bf..2ee4cd2 100644 --- a/Thunderstore/manifest.json +++ b/Thunderstore/manifest.json @@ -1,6 +1,6 @@ { "name": "BepInEx_GUI", - "version_number": "3.0.1", + "version_number": "3.0.2", "website_url": "https://github.com/risk-of-thunder/BepInEx.GUI", "description": "Graphical User Interface meant to replace the regular console host that is used by BepInEx when the config setting is enabled.", "dependencies": [] diff --git a/bepinex_gui/Cargo.lock b/bepinex_gui/Cargo.lock index 640952d..e939277 100644 --- a/bepinex_gui/Cargo.lock +++ b/bepinex_gui/Cargo.lock @@ -383,7 +383,7 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "bepinex_gui" -version = "3.0.1" +version = "3.0.2" dependencies = [ "byteorder", "clipboard", diff --git a/bepinex_gui/Cargo.toml b/bepinex_gui/Cargo.toml index a77a358..b8f9a24 100644 --- a/bepinex_gui/Cargo.toml +++ b/bepinex_gui/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bepinex_gui" -version = "3.0.1" +version = "3.0.2" authors = ["Risk of Thunder"] license = "MIT" description = "Graphical User Interface meant to replace the regular console host that is used by BepInEx" diff --git a/bepinex_gui/src/app.rs b/bepinex_gui/src/app.rs index 458ea22..15421a1 100644 --- a/bepinex_gui/src/app.rs +++ b/bepinex_gui/src/app.rs @@ -19,7 +19,7 @@ use crate::data::bepinex_mod::BepInExMod; use crate::views::disclaimer::Disclaimer; use crate::{theme, views}; -pub(crate) const NAME: &str = "BepInExGUI"; +pub const NAME: &str = "BepInExGUI"; pub struct BepInExGUI { pub app_launch_config: AppLaunchConfig, diff --git a/bepinex_gui/src/backend/file_explorer_utils.rs b/bepinex_gui/src/backend/file_explorer_utils.rs index 990fa17..5146d64 100644 --- a/bepinex_gui/src/backend/file_explorer_utils.rs +++ b/bepinex_gui/src/backend/file_explorer_utils.rs @@ -1,4 +1,8 @@ -use std::{os::windows::process::CommandExt, path::PathBuf, process::Command}; +use std::{ + os::windows::process::CommandExt, + path::{Path, PathBuf}, + process::Command, +}; pub fn open_path_in_explorer(file: &PathBuf) { if let Err(e) = (|| { @@ -21,22 +25,23 @@ pub fn open_path_in_explorer(file: &PathBuf) { } } -pub fn highlight_path_in_explorer(file: &std::path::PathBuf) { +pub fn highlight_path_in_explorer(file: &Path) { if let Err(e) = (|| { #[cfg(target_os = "windows")] { if let Some(s) = file.to_str() { - let mut s = s.replace("/", r#"\"#); - s.push_str("\""); + let mut s = s.replace('/', r#"\"#); + s.push('\"'); let s = s.as_str(); + return Command::new("explorer") .raw_arg("/select,\"".to_string() + s) .spawn(); } else { - return Err(std::io::Error::new( + Err(std::io::Error::new( std::io::ErrorKind::Other, "Can't convert PathBuf to_str", - )); + )) } } diff --git a/bepinex_gui/src/backend/mod.rs b/bepinex_gui/src/backend/mod.rs index 94c7a85..4f58a52 100644 --- a/bepinex_gui/src/backend/mod.rs +++ b/bepinex_gui/src/backend/mod.rs @@ -17,7 +17,7 @@ impl BepInExGUI { // Ideally this would be done in a init function, not constantly checked in an update function // L from eframe if !self.is_window_title_set { - frame.set_window_title(&self.app_launch_config.window_title()); + frame.set_window_title(self.app_launch_config.window_title()); self.is_window_title_set = true; } diff --git a/bepinex_gui/src/backend/network/packet_protocol.rs b/bepinex_gui/src/backend/network/packet_protocol.rs index e33561a..370e77c 100644 --- a/bepinex_gui/src/backend/network/packet_protocol.rs +++ b/bepinex_gui/src/backend/network/packet_protocol.rs @@ -7,7 +7,7 @@ use std::net::TcpStream; use crate::data::bepinex_log::LogLevel; -pub(crate) fn read_packet_length(tcp_stream: &mut TcpStream) -> Result { +pub fn read_packet_length(tcp_stream: &mut TcpStream) -> Result { const HEADER_SIZE: usize = size_of::(); let mut received_bytes = read_packet_internal(tcp_stream, HEADER_SIZE)?; @@ -18,9 +18,7 @@ pub(crate) fn read_packet_length(tcp_stream: &mut TcpStream) -> Result Result { +pub fn read_packet_log_level(tcp_stream: &mut TcpStream) -> Result { unsafe { let mut received_bytes = read_packet_internal(tcp_stream, size_of::())?; @@ -32,7 +30,7 @@ pub(crate) fn read_packet_log_level( } } -pub(crate) fn read_packet( +pub fn read_packet( tcp_stream: &mut TcpStream, size_to_read: usize, ) -> Result, std::io::Error> { @@ -47,30 +45,18 @@ fn read_packet_internal( ) -> Result, std::io::Error> { const BUFFER_SIZE: usize = 4096; - let mut packet_bytes: Vec = vec![]; - let mut read_stream_buffer = vec![0u8; size_to_read]; + let mut packet_bytes = Vec::with_capacity(size_to_read); let mut remaining_size_to_read = size_to_read; - loop { - read_stream_buffer.clear(); - read_stream_buffer.resize( - if remaining_size_to_read > BUFFER_SIZE { - BUFFER_SIZE - } else { - remaining_size_to_read - }, - 0, - ); + while remaining_size_to_read > 0 { + let bytes_read = BUFFER_SIZE.min(remaining_size_to_read); - match tcp_stream.read(&mut read_stream_buffer) { - Ok(bytes_read) => { - packet_bytes.extend_from_slice(&read_stream_buffer[..bytes_read]); + let mut read_stream_buffer = vec![0u8; bytes_read]; + match tcp_stream.read_exact(&mut read_stream_buffer) { + Ok(_) => { + packet_bytes.extend_from_slice(&read_stream_buffer); remaining_size_to_read -= bytes_read; - - if remaining_size_to_read <= 0 { - break; - } } Err(err) => return Err(err), } @@ -79,6 +65,6 @@ fn read_packet_internal( Ok(packet_bytes) } -pub(crate) fn packet_bytes_to_utf8_string(packet_bytes: &Vec) -> String { - unsafe { std::str::from_utf8_unchecked(&packet_bytes).to_string() } +pub fn packet_bytes_to_utf8_string(packet_bytes: &[u8]) -> String { + unsafe { std::str::from_utf8_unchecked(packet_bytes).to_string() } } diff --git a/bepinex_gui/src/backend/panic_handler.rs b/bepinex_gui/src/backend/panic_handler.rs index 939a977..ce67431 100644 --- a/bepinex_gui/src/backend/panic_handler.rs +++ b/bepinex_gui/src/backend/panic_handler.rs @@ -2,10 +2,13 @@ use std::panic; pub fn init() { panic::set_hook(Box::new(|panic_info| { - if let Some(s) = panic_info.payload().downcast_ref::<&str>() { - tracing::error!("panic occurred: {s:?}"); - } else { - tracing::error!("panic occurred"); - } + panic_info.payload().downcast_ref::<&str>().map_or_else( + || { + tracing::error!("panic occurred"); + }, + |s| { + tracing::error!("panic occurred: {s:?}"); + }, + ) })); } diff --git a/bepinex_gui/src/backend/process/mod.rs b/bepinex_gui/src/backend/process/mod.rs index 788e3c0..98ee8a8 100644 --- a/bepinex_gui/src/backend/process/mod.rs +++ b/bepinex_gui/src/backend/process/mod.rs @@ -23,20 +23,22 @@ use winapi::{ }; #[cfg(windows)] -pub(crate) fn for_each_thread(target_process_id: Pid, callback: impl Fn(HANDLE)) -> bool { +pub fn for_each_thread(target_process_id: Pid, callback: impl Fn(HANDLE)) -> bool { use sysinfo::PidExt; use winapi::um::winnt::THREAD_SUSPEND_RESUME; unsafe { let sys = sysinfo::System::new_all(); - if let Some(_) = sys.process(target_process_id) { + if sys.process(target_process_id).is_some() { let thread_snapshot = winapi::um::tlhelp32::CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); - let mut te32: THREADENTRY32 = Default::default(); - te32.dwSize = size_of::() as DWORD; - let te32_ptr = std::mem::transmute(&te32); + let mut te32: THREADENTRY32 = THREADENTRY32 { + dwSize: size_of::() as DWORD, + ..Default::default() + }; + let te32_ptr = std::ptr::addr_of_mut!(te32); if winapi::um::tlhelp32::Thread32First(thread_snapshot, te32_ptr) == 0 { tracing::error!("Thread32First fail"); @@ -51,7 +53,7 @@ pub(crate) fn for_each_thread(target_process_id: Pid, callback: impl Fn(HANDLE)) te32.th32ThreadID, ); - if open_thread_handle == std::ptr::null_mut() { + if open_thread_handle.is_null() { tracing::error!("OpenThread Failed"); break; } @@ -71,40 +73,40 @@ pub(crate) fn for_each_thread(target_process_id: Pid, callback: impl Fn(HANDLE)) return true; } - return false; + false } } #[cfg(not(windows))] -pub(crate) fn for_each_thread() { +pub fn for_each_thread() { // todo } #[cfg(windows)] -pub(crate) fn resume(target_process_id: Pid) -> bool { +pub fn resume(target_process_id: Pid) -> bool { for_each_thread(target_process_id, |thread_handle| unsafe { winapi::um::processthreadsapi::ResumeThread(thread_handle); }) } #[cfg(not(windows))] -pub(crate) fn resume(target_process_id: Pid) -> bool { +pub fn resume(target_process_id: Pid) -> bool { // todo } #[cfg(windows)] -pub(crate) fn suspend(target_process_id: Pid) -> bool { +pub fn suspend(target_process_id: Pid) -> bool { for_each_thread(target_process_id, |thread_handle| unsafe { winapi::um::processthreadsapi::SuspendThread(thread_handle); }) } #[cfg(not(windows))] -pub(crate) fn suspend(target_process_id: Pid) -> bool { +pub fn suspend(target_process_id: Pid) -> bool { // todo } -pub(crate) fn spawn_thread_is_process_dead( +pub fn spawn_thread_is_process_dead( target_process_id: Pid, should_check: Arc, out_true_when_process_is_dead: Arc, @@ -135,13 +137,11 @@ pub fn kill(target_process_id: Pid, callback: impl FnOnce()) { } #[cfg(windows)] -pub(crate) fn spawn_thread_check_if_process_is_hung( - callback: impl Fn() + std::marker::Send + 'static, -) { +pub fn spawn_thread_check_if_process_is_hung(callback: impl Fn() + std::marker::Send + 'static) { thread::spawn(move || -> io::Result<()> { unsafe { static mut CURRENT_PROCESS_ID: u32 = 0; - CURRENT_PROCESS_ID = GetCurrentProcessId() as u32; + CURRENT_PROCESS_ID = GetCurrentProcessId(); static mut GOT_RESULT: bool = false; @@ -155,7 +155,7 @@ pub(crate) fn spawn_thread_check_if_process_is_hung( } let mut proc_id: DWORD = 0 as DWORD; - let _ = GetWindowThreadProcessId(window, &mut proc_id as *mut DWORD); + let _ = GetWindowThreadProcessId(window, std::ptr::addr_of_mut!(proc_id)); if proc_id == CURRENT_PROCESS_ID { WINDOW_HANDLE = window; } diff --git a/bepinex_gui/src/backend/reset_app_if_window_hang.rs b/bepinex_gui/src/backend/reset_app_if_window_hang.rs index 52023ce..77029a8 100644 --- a/bepinex_gui/src/backend/reset_app_if_window_hang.rs +++ b/bepinex_gui/src/backend/reset_app_if_window_hang.rs @@ -14,7 +14,7 @@ use super::process; // the gui window not respond // bandaid fix that call winapi for checking if the window hung // and reset the process with a cleaned settings file if so -pub(crate) fn spawn_thread() { +pub fn spawn_thread() { process::spawn_thread_check_if_process_is_hung(|| { if let Some(app_ron_file_path) = config::get_app_ron_file_full_path() { let current_exe = diff --git a/bepinex_gui/src/backend/thunderstore/api.rs b/bepinex_gui/src/backend/thunderstore/api.rs index 6c46543..6e8086a 100644 --- a/bepinex_gui/src/backend/thunderstore/api.rs +++ b/bepinex_gui/src/backend/thunderstore/api.rs @@ -34,7 +34,7 @@ fn find_modding_discord_from_target_process_name( let json = reqwest::blocking::get(URL).and_then(|resp| resp.text())?; let communities = serde_json::from_str::(&json) - .and_then(|c| Ok(c.results))? + .map(|c| c.results)? .ok_or("no communities.results")?; let sys = sysinfo::System::new_all(); @@ -45,7 +45,7 @@ fn find_modding_discord_from_target_process_name( let proc_name_osstring = Path::new(&proc.name().to_lowercase()) .file_stem() - .and_then(|s| Some(s.to_os_string())) + .map(|s| s.to_os_string()) .ok_or("failed getting proc name from proc")? .into_string(); @@ -58,7 +58,7 @@ fn find_modding_discord_from_target_process_name( for community in communities { let community_name_lower = community .name - .and_then(|n| Some(n.to_lowercase().to_string())) + .map(|n| n.to_lowercase()) .ok_or("failed lowercasing")?; if proc_name.contains(&community_name_lower) || community_name_lower.contains(&proc_name) { @@ -69,7 +69,7 @@ fn find_modding_discord_from_target_process_name( } } - Err(format!("No community matching target process name {}", proc_name).into()) + Err(format!("No community matching target process name {proc_name}").into()) } pub fn open_modding_discord(target_process_id: Pid) { diff --git a/bepinex_gui/src/backend/window/window_topmost_on_target_start.rs b/bepinex_gui/src/backend/window/window_topmost_on_target_start.rs index 43c2c06..a993534 100644 --- a/bepinex_gui/src/backend/window/window_topmost_on_target_start.rs +++ b/bepinex_gui/src/backend/window/window_topmost_on_target_start.rs @@ -45,7 +45,7 @@ pub fn init(&self, target_process_id: Pid) {} fn is_current_process_in_front_of_target_process_window(target_process_id_: Pid) -> bool { unsafe { static mut CURRENT_PROCESS_ID: u32 = 0; - CURRENT_PROCESS_ID = GetCurrentProcessId() as u32; + CURRENT_PROCESS_ID = GetCurrentProcessId(); static mut TARGET_PROCESS_ID: u32 = 0; TARGET_PROCESS_ID = std::mem::transmute_copy(&target_process_id_); @@ -64,7 +64,7 @@ fn is_current_process_in_front_of_target_process_window(target_process_id_: Pid) } let mut proc_id: DWORD = 0 as DWORD; - let _ = GetWindowThreadProcessId(window, &mut proc_id as *mut DWORD); + let _ = GetWindowThreadProcessId(window, std::ptr::addr_of_mut!(proc_id)); if proc_id == TARGET_PROCESS_ID { let is_current_proc_in_front = GOT_CURRENT_PROC_WINDOW; if is_current_proc_in_front { @@ -89,7 +89,7 @@ fn is_current_process_in_front_of_target_process_window(target_process_id_: Pid) EnumWindows(Some(enum_window), 0 as LPARAM); - return GOT_CURRENT_PROC_WINDOW && GOT_RESULT; + GOT_CURRENT_PROC_WINDOW && GOT_RESULT } } #[cfg(not(windows))] @@ -98,7 +98,7 @@ fn is_current_process_in_front_of_target_process_window(&self, target_process_id fn set_topmost_current_process_window(set_topmost: bool) { unsafe { static mut CURRENT_PROCESS_ID: u32 = 0; - CURRENT_PROCESS_ID = GetCurrentProcessId() as u32; + CURRENT_PROCESS_ID = GetCurrentProcessId(); static mut SET_TOPMOST: bool = false; SET_TOPMOST = set_topmost; @@ -106,7 +106,7 @@ fn set_topmost_current_process_window(set_topmost: bool) { extern "system" fn enum_window(window: HWND, _: LPARAM) -> BOOL { unsafe { let mut proc_id: DWORD = 0 as DWORD; - let _ = GetWindowThreadProcessId(window, &mut proc_id as *mut DWORD); + let _ = GetWindowThreadProcessId(window, std::ptr::addr_of_mut!(proc_id)); if proc_id == CURRENT_PROCESS_ID { SetWindowPos( window, diff --git a/bepinex_gui/src/config/launch.rs b/bepinex_gui/src/config/launch.rs index 9eb7920..dcd3a06 100644 --- a/bepinex_gui/src/config/launch.rs +++ b/bepinex_gui/src/config/launch.rs @@ -18,17 +18,13 @@ pub struct AppLaunchConfig { impl AppLaunchConfig { const ARG_COUNT: usize = 8; - pub fn from(args: &Vec) -> Option { - if args.len() != AppLaunchConfig::ARG_COUNT { - tracing::error!("Problem with args {:?} {:?}", args.len(), args); - - None - } else { + pub fn from(args: &Vec) -> Option { + if args.len() == Self::ARG_COUNT { let bepinex_version = &args[1]; let target_name = &args[2]; let window_title = app::NAME.to_owned() + " " + bepinex_version + " - " + target_name; - Some(AppLaunchConfig { + Some(Self { target_name: target_name.into(), game_folder_full_path: (&args[3]).into(), bepinex_log_output_file_full_path: (&args[4]).into(), @@ -37,14 +33,18 @@ impl AppLaunchConfig { log_socket_port_receiver: args[7].parse::().unwrap(), window_title, }) + } else { + tracing::error!("Problem with args {:?} {:?}", args.len(), args); + + None } } - pub fn default() -> AppLaunchConfig { + pub fn default() -> Self { let bepinex_version_string = "5.4.19"; let target_name = "Risk of Rain 2"; - AppLaunchConfig { + Self { target_name : target_name.into(), game_folder_full_path: "C:\\Program Files (x86)\\Steam\\steamapps\\common\\Risk of Rain 2".into(), bepinex_log_output_file_full_path: "C:\\Program Files (x86)\\Steam\\steamapps\\common\\Risk of Rain 2\\BepInEx\\LogOutput.log".into(), @@ -59,23 +59,23 @@ impl AppLaunchConfig { self.target_name.as_ref() } - pub fn game_folder_full_path(&self) -> &PathBuf { + pub const fn game_folder_full_path(&self) -> &PathBuf { &self.game_folder_full_path } - pub fn bepinex_log_output_file_full_path(&self) -> &PathBuf { + pub const fn bepinex_log_output_file_full_path(&self) -> &PathBuf { &self.bepinex_log_output_file_full_path } - pub fn bepinex_gui_csharp_cfg_full_path(&self) -> &PathBuf { + pub const fn bepinex_gui_csharp_cfg_full_path(&self) -> &PathBuf { &self.bepinex_gui_csharp_cfg_full_path } - pub fn target_process_id(&self) -> Pid { + pub const fn target_process_id(&self) -> Pid { self.target_process_id } - pub fn log_socket_port_receiver(&self) -> u16 { + pub const fn log_socket_port_receiver(&self) -> u16 { self.log_socket_port_receiver } diff --git a/bepinex_gui/src/config/mod.rs b/bepinex_gui/src/config/mod.rs index 6261237..6591d74 100644 --- a/bepinex_gui/src/config/mod.rs +++ b/bepinex_gui/src/config/mod.rs @@ -71,37 +71,31 @@ impl Config { let mut current_settings_category_name: &str; - for line_ in reader.lines() { - match line_ { - Ok(line) => { - if line.starts_with('[') { - current_settings_category_name = line.split('[').collect::>()[1] - .split(']') - .collect::>()[0]; - tracing::info!( - "current_settings_category_name: {}", - current_settings_category_name - ); - } else if line.starts_with("##") { - } else if line.starts_with("# ") { - } else if line.contains('=') { - let setting = line.split('=').collect::>(); - let setting_name = setting[0].trim(); - let settings_current_value = setting[1].trim(); - - let bool_setting = settings_current_value.parse::(); - if let Ok(bool_value) = bool_setting { - tracing::info!("{:?}: {:?}", setting_name, bool_value); - if setting_name == "Close Window When Game Loaded" { - self.close_window_when_game_loaded = bool_value; - } else if setting_name == "Close Window When Game Closes" { - self.close_window_when_game_closes - .store(bool_value, Ordering::Relaxed); - } - } + for line in reader.lines().flatten() { + if line.starts_with('[') { + current_settings_category_name = line.split('[').collect::>()[1] + .split(']') + .collect::>()[0]; + tracing::info!( + "current_settings_category_name: {}", + current_settings_category_name + ); + } else if line.starts_with("##") || line.starts_with("# ") { + } else if line.contains('=') { + let setting = line.split('=').collect::>(); + let setting_name = setting[0].trim(); + let settings_current_value = setting[1].trim(); + + let bool_setting = settings_current_value.parse::(); + if let Ok(bool_value) = bool_setting { + tracing::info!("{:?}: {:?}", setting_name, bool_value); + if setting_name == "Close Window When Game Loaded" { + self.close_window_when_game_loaded = bool_value; + } else if setting_name == "Close Window When Game Closes" { + self.close_window_when_game_closes + .store(bool_value, Ordering::Relaxed); } } - Err(_) => {} } } @@ -117,8 +111,8 @@ impl Config { let mut lines: Vec = Vec::new(); - for line_ in reader.lines() { - match line_ { + for res in reader.lines() { + match res { Ok(line_) => { let mut line = line_.to_string(); if line_.contains('=') { @@ -160,10 +154,8 @@ impl Config { } pub fn get_app_ron_file_full_path() -> Option { - if let Some(proj_dirs) = directories_next::ProjectDirs::from("", "", app::NAME) { + directories_next::ProjectDirs::from("", "", app::NAME).map(|proj_dirs| { let data_dir = proj_dirs.data_dir().to_path_buf(); - Some(data_dir.join("app.ron")) - } else { - None - } + data_dir.join("app.ron") + }) } diff --git a/bepinex_gui/src/data/bepinex_log/file.rs b/bepinex_gui/src/data/bepinex_log/file.rs index 594feb2..93cb9eb 100644 --- a/bepinex_gui/src/data/bepinex_log/file.rs +++ b/bepinex_gui/src/data/bepinex_log/file.rs @@ -11,13 +11,13 @@ pub fn open_file_explorer_to_file_and_zip_it_if_needed( file_full_path: &PathBuf, zip_file_name: &str, ) { - if let Ok(file_metadata) = fs::metadata(&file_full_path) { + if let Ok(file_metadata) = fs::metadata(file_full_path) { let file_size_bytes = file_metadata.len(); - const ONE_MEGABYTE: u64 = 1000000; + const ONE_MEGABYTE: u64 = 1_000_000; // check log file size, if its more than size limit, just zip it if file_size_bytes >= ONE_MEGABYTE { let zip_file_full_path = file_full_path.parent().unwrap().join(zip_file_name); - match zip(&zip_file_full_path, &file_full_path) { + match zip(&zip_file_full_path, file_full_path) { Ok(_) => { file_explorer_utils::highlight_path_in_explorer(&zip_file_full_path); } @@ -54,7 +54,7 @@ pub fn zip, P2: AsRef>( Ok(()) } -pub(crate) fn full_path() -> Option { +pub fn full_path() -> Option { if let Some(directory_full_path) = paths::get_app_config_directory() { if std::fs::create_dir_all(&directory_full_path).is_ok() { return Some(directory_full_path.join("log.txt")); diff --git a/bepinex_gui/src/data/bepinex_log/mod.rs b/bepinex_gui/src/data/bepinex_log/mod.rs index dd3dbde..a5bcac5 100644 --- a/bepinex_gui/src/data/bepinex_log/mod.rs +++ b/bepinex_gui/src/data/bepinex_log/mod.rs @@ -25,36 +25,36 @@ pub enum LogLevel { impl Numeric for LogLevel { const INTEGRAL: bool = true; - const MIN: Self = LogLevel::None; + const MIN: Self = Self::None; - const MAX: Self = LogLevel::All; + const MAX: Self = Self::All; // this is needed for egui slider fn to_f64(self) -> f64 { match self { - LogLevel::None => 0.0, - LogLevel::Fatal => 1.0, - LogLevel::Error => 2.0, - LogLevel::Warning => 3.0, - LogLevel::Message => 4.0, - LogLevel::Info => 5.0, - LogLevel::Debug => 6.0, - LogLevel::All => 7.0, + Self::None => 0.0, + Self::Fatal => 1.0, + Self::Error => 2.0, + Self::Warning => 3.0, + Self::Message => 4.0, + Self::Info => 5.0, + Self::Debug => 6.0, + Self::All => 7.0, } } // this is needed for egui slider fn from_f64(num: f64) -> Self { match num { - x if x >= 0.0 && x < 1.0 => LogLevel::None, - x if x >= 1.0 && x < 2.0 => LogLevel::Fatal, - x if x >= 2.0 && x < 3.0 => LogLevel::Error, - x if x >= 3.0 && x < 4.0 => LogLevel::Warning, - x if x >= 4.0 && x < 5.0 => LogLevel::Message, - x if x >= 5.0 && x < 6.0 => LogLevel::Info, - x if x >= 6.0 && x < 7.0 => LogLevel::Debug, - x if x >= 7.0 && x < 8.0 => LogLevel::All, - _ => LogLevel::All, + x if (0.0..1.0).contains(&x) => Self::None, + x if (1.0..2.0).contains(&x) => Self::Fatal, + x if (2.0..3.0).contains(&x) => Self::Error, + x if (3.0..4.0).contains(&x) => Self::Warning, + x if (4.0..5.0).contains(&x) => Self::Message, + x if (5.0..6.0).contains(&x) => Self::Info, + x if (6.0..7.0).contains(&x) => Self::Debug, + x if (7.0..8.0).contains(&x) => Self::All, + _ => Self::All, } } } @@ -68,16 +68,16 @@ pub struct BepInExLogEntry { } impl BepInExLogEntry { - pub fn new(level: LogLevel, data: String) -> Self { + pub fn new(level: LogLevel, data: &str) -> Self { Self { level, - data: data.clone(), + data: data.to_string(), data_lowercase: data.to_lowercase(), is_selected: false, } } - pub fn level(&self) -> LogLevel { + pub const fn level(&self) -> LogLevel { self.level } diff --git a/bepinex_gui/src/data/bepinex_log/receiver.rs b/bepinex_gui/src/data/bepinex_log/receiver.rs index 2642b39..77a9616 100644 --- a/bepinex_gui/src/data/bepinex_log/receiver.rs +++ b/bepinex_gui/src/data/bepinex_log/receiver.rs @@ -28,8 +28,8 @@ impl LogReceiver { log_socket_port_receiver: u16, log_senders: Vec>, mod_senders: Vec>, - ) -> LogReceiver { - LogReceiver { + ) -> Self { + Self { log_socket_port_receiver, log_senders, mod_senders, @@ -98,10 +98,10 @@ impl LogReceiver { }); } - fn make_log_entry_from_packet_data(&self, log_level: LogLevel, string_packet_bytes: &Vec) { - let log_string = packet_protocol::packet_bytes_to_utf8_string(&string_packet_bytes); + fn make_log_entry_from_packet_data(&self, log_level: LogLevel, string_packet_bytes: &[u8]) { + let log_string = packet_protocol::packet_bytes_to_utf8_string(string_packet_bytes); - let log = BepInExLogEntry::new(log_level, log_string); + let log = BepInExLogEntry::new(log_level, &log_string); if log.data().contains("Loading [") { let split: Vec<&str> = log.data().split('[').collect(); diff --git a/bepinex_gui/src/logger/mod.rs b/bepinex_gui/src/logger/mod.rs index c3cf0d3..e5355fa 100644 --- a/bepinex_gui/src/logger/mod.rs +++ b/bepinex_gui/src/logger/mod.rs @@ -7,26 +7,31 @@ use tracing_subscriber::{fmt, Registry}; use crate::data::bepinex_log; pub fn init() { - if let Some(log_file_path) = bepinex_log::file::full_path() { - if let Ok(file) = File::create(log_file_path) { - let subscriber = Registry::default() - .with( - fmt::Layer::default() - .with_writer(Mutex::new(file)) - .with_ansi(false) - .with_line_number(true), - ) - .with( - fmt::Layer::default() - .with_writer(std::io::stdout) - .with_line_number(true), - ); - - let _ = tracing::subscriber::set_global_default(subscriber); - } else { + bepinex_log::file::full_path().map_or_else( + || { tracing_subscriber::fmt::init(); - } - } else { - tracing_subscriber::fmt::init(); - } + }, + |log_file_path| { + File::create(log_file_path).map_or_else( + |_err| { + tracing_subscriber::fmt::init(); + }, + |file| { + let subscriber = Registry::default() + .with( + fmt::Layer::default() + .with_writer(Mutex::new(file)) + .with_ansi(false) + .with_line_number(true), + ) + .with( + fmt::Layer::default() + .with_writer(std::io::stdout) + .with_line_number(true), + ); + let _ = tracing::subscriber::set_global_default(subscriber); + }, + ) + }, + ) } diff --git a/bepinex_gui/src/paths.rs b/bepinex_gui/src/paths.rs index 02fe8a3..4ca4708 100644 --- a/bepinex_gui/src/paths.rs +++ b/bepinex_gui/src/paths.rs @@ -2,10 +2,7 @@ use std::path::PathBuf; use crate::app; -pub(crate) fn get_app_config_directory() -> Option { - if let Some(proj_dirs) = directories_next::ProjectDirs::from("", "", app::NAME) { - Some(proj_dirs.data_dir().to_path_buf()) - } else { - None - } +pub fn get_app_config_directory() -> Option { + directories_next::ProjectDirs::from("", "", app::NAME) + .map(|proj_dirs| proj_dirs.data_dir().to_path_buf()) } diff --git a/bepinex_gui/src/theme.rs b/bepinex_gui/src/theme.rs index d013d02..e2687e7 100644 --- a/bepinex_gui/src/theme.rs +++ b/bepinex_gui/src/theme.rs @@ -1,4 +1,3 @@ -use eframe; use eframe::{egui::*, *}; fn parse_color(color: &str) -> egui::Color32 { @@ -63,15 +62,15 @@ fn get_aliased_color(json: &serde_json::Value, alias_path: &str) -> egui::Color3 } /// Margin on all sides of views. -pub fn view_padding() -> f32 { +pub const fn view_padding() -> f32 { 12.0 } -pub fn window_rounding() -> f32 { +pub const fn window_rounding() -> f32 { 12.0 } -pub fn small_rounding() -> f32 { +pub const fn small_rounding() -> f32 { 4.0 } @@ -190,7 +189,7 @@ pub fn get_dark_theme() -> egui::Style { egui_style } -pub(crate) fn configure_fonts(ctx: &Context) { +pub fn configure_fonts(ctx: &Context) { let mut font_def = FontDefinitions::default(); font_def.font_data.insert( "Comfortaa".to_string(), diff --git a/bepinex_gui/src/views/disclaimer.rs b/bepinex_gui/src/views/disclaimer.rs index eb9d2b5..36107de 100644 --- a/bepinex_gui/src/views/disclaimer.rs +++ b/bepinex_gui/src/views/disclaimer.rs @@ -37,8 +37,8 @@ For mod developers that like the old conhost console, you can enable it back by disclaimer.first_time_showing_it = false; } - if let Ok(_elapsed) = disclaimer.time_when_disclaimer_showed_up.unwrap().elapsed() { - let elapsed = _elapsed.as_secs() as i64; + if let Ok(elapsed_) = disclaimer.time_when_disclaimer_showed_up.unwrap().elapsed() { + let elapsed = elapsed_.as_secs() as i64; const NEEDED_TIME_BEFORE_CLOSABLE:i64 = 9; let can_close = elapsed > NEEDED_TIME_BEFORE_CLOSABLE; if can_close { diff --git a/bepinex_gui/src/views/mod.rs b/bepinex_gui/src/views/mod.rs index ccb65a1..3f30d5a 100644 --- a/bepinex_gui/src/views/mod.rs +++ b/bepinex_gui/src/views/mod.rs @@ -1,4 +1,4 @@ -pub(crate) use std::path::PathBuf; +use std::path::PathBuf; use eframe::{ self, @@ -14,10 +14,10 @@ use crate::{ data::bepinex_log, }; -pub(crate) mod components; -pub(crate) mod disclaimer; -pub(crate) mod tabs; -pub(crate) mod utils; +pub mod components; +pub mod disclaimer; +pub mod tabs; +pub mod utils; impl BepInExGUI { pub(crate) fn view_update(&mut self, ctx: &Context, frame: &mut eframe::Frame) { @@ -55,8 +55,7 @@ impl BepInExGUI { ui.spacing_mut().item_spacing.x = 1.; ui.spacing_mut().item_spacing.y = 1.; - let mut i = 0; - for tab in &self.tabs { + for (i, tab) in self.tabs.iter().enumerate() { if ui .add_sized( button_size, @@ -66,8 +65,6 @@ impl BepInExGUI { { self.config.selected_tab_index = i; } - - i += 1; } }); diff --git a/bepinex_gui/src/views/tabs/console.rs b/bepinex_gui/src/views/tabs/console.rs index b4c55be..3c95612 100644 --- a/bepinex_gui/src/views/tabs/console.rs +++ b/bepinex_gui/src/views/tabs/console.rs @@ -40,7 +40,7 @@ impl LogSelection { fn update_selection( &mut self, - ui_log_entry: Response, + ui_log_entry: &Response, clip_rect: &Rect, ui: &Ui, log_index: usize, @@ -84,11 +84,9 @@ impl LogSelection { } } } - } else { - if self.button_just_got_down { - self.index_of_first_selected_log = usize::MAX; - self.index_of_last_selected_log = usize::MAX; - } + } else if self.button_just_got_down { + self.index_of_first_selected_log = usize::MAX; + self.index_of_last_selected_log = usize::MAX; } } } @@ -186,12 +184,12 @@ impl ConsoleTab { } }); - self.auto_scroll_to_selection(scroll_area, ui); + self.auto_scroll_to_selection(&scroll_area, ui); } fn auto_scroll_to_selection( &mut self, - scroll_area: scroll_area::ScrollAreaOutput<()>, + scroll_area: &scroll_area::ScrollAreaOutput<()>, ui: &mut Ui, ) { if let Some(cursor_pos) = self.log_selection.cursor_pos_when_button_was_pressed { @@ -255,27 +253,24 @@ impl ConsoleTab { fn update_copy_logs_to_clipboard(&mut self, ctx: &Context) { if ctx.input(|i| i.modifiers.command) && ctx.input(|i| i.key_pressed(Key::C)) { - match ClipboardProvider::new() { - Ok(ctx_) => { - let mut ctx: ClipboardContext = ctx_; - - let selected_logs: Vec = self - .logs - .iter() - .filter(|x| x.is_selected) - .map(|x| x.data().to_string()) - .collect(); - - let selected_logs_string = selected_logs.join("\n"); - - match ctx.set_contents(selected_logs_string) { - Ok(_) => {} - Err(err) => { - tracing::error!("Failed copying logs to clipboard: {}", err); - } + if let Ok(ctx_) = ClipboardProvider::new() { + let mut ctx: ClipboardContext = ctx_; + + let selected_logs: Vec = self + .logs + .iter() + .filter(|x| x.is_selected) + .map(|x| x.data().to_string()) + .collect(); + + let selected_logs_string = selected_logs.join("\n"); + + match ctx.set_contents(selected_logs_string) { + Ok(_) => {} + Err(err) => { + tracing::error!("Failed copying logs to clipboard: {}", err); } } - Err(_) => {} } } } @@ -295,7 +290,7 @@ impl ConsoleTab { return; } - if !ConsoleTab::does_log_match_text_filter(&filter.text_lowercase, log) { + if !Self::does_log_match_text_filter(&filter.text_lowercase, log) { return; } @@ -323,17 +318,17 @@ impl ConsoleTab { log_heights.insert(i, log_height); } - log_selection.update_selection(ui_log_entry, clip_rect, ui, i); + log_selection.update_selection(&ui_log_entry, clip_rect, ui, i); } fn does_log_match_text_filter(text_filter_lowercase: &String, log: &BepInExLogEntry) -> bool { - if !text_filter_lowercase.is_empty() { - if !log.data_lowercase().contains(text_filter_lowercase) { - return false; - } + if !text_filter_lowercase.is_empty() + && !log.data_lowercase().contains(text_filter_lowercase) + { + return false; } - return true; + true } fn render_footer(&mut self, data: &AppLaunchConfig, gui_config: &mut Config, ctx: &Context) { @@ -357,8 +352,8 @@ impl ConsoleTab { views::BepInExGUI::render_useful_buttons_footer( ui, ctx, - &data.game_folder_full_path(), - &data.bepinex_log_output_file_full_path(), + data.game_folder_full_path(), + data.bepinex_log_output_file_full_path(), data.target_process_id(), ); }); @@ -366,43 +361,41 @@ impl ConsoleTab { fn render_console_first_time_disclaimer(&mut self, ctx: &Context, gui_config: &mut Config) { CentralPanel::default().show(ctx, |_| { - Window::new("Console Disclaimer") - .collapsible(false) - .anchor(Align2::CENTER_CENTER, Vec2::ZERO) - .show(ctx, |ui| { - ui.heading( + Window::new("Console Disclaimer") + .collapsible(false) + .anchor(Align2::CENTER_CENTER, Vec2::ZERO) + .show(ctx, |ui| { + ui.heading( r#"The console is meant to be used by mod developers. If any of your mods is malfunctioning and that you wish to receive help in the #tech-support channel of the discord: Please use the buttons below and use the "Copy Log File" button, and drag and drop it in the #tech-support channel."#); - if self.disclaimer.first_time_showing_it { - self.disclaimer.time_when_disclaimer_showed_up = - Some(SystemTime::now()); - self.disclaimer.first_time_showing_it = false; - } + if self.disclaimer.first_time_showing_it { + self.disclaimer.time_when_disclaimer_showed_up = Some(SystemTime::now()); + self.disclaimer.first_time_showing_it = false; + } - if let Ok(_elapsed) = - self.disclaimer.time_when_disclaimer_showed_up.unwrap().elapsed() + if let Ok(elapsed_) = self + .disclaimer + .time_when_disclaimer_showed_up + .unwrap() + .elapsed() + { + let elapsed = elapsed_.as_secs() as i64; + if 9 - elapsed >= 0 { + ui.label( + RichText::new((10 - elapsed).to_string()) + .font(FontId::proportional(20.0)), + ); + } else if ui + .button(RichText::new("Ok").font(FontId::proportional(20.0))) + .clicked() { - let elapsed = _elapsed.as_secs() as i64; - if 9 - elapsed >= 0 { - ui.label( - RichText::new((10 - elapsed).to_string()) - .font(FontId::proportional(20.0)), - ); - } else { - if ui - .button( - RichText::new("Ok").font(FontId::proportional(20.0)), - ) - .clicked() - { - gui_config.first_time_console_disclaimer = false; - } - } + gui_config.first_time_console_disclaimer = false; } - }); - }); + } + }); + }); } fn render_kill_gui_and_game_butto( @@ -415,12 +408,10 @@ Please use the buttons below and use the "Copy Log File" button, and drag and dr let kill_game_btn_size = views::utils::egui::compute_text_size(ui, kill_game_btn_text, true, false, None); - ui.add_space( - ui.available_width() - - pause_game_btn_size.x - - kill_game_btn_size.x - - (ui.spacing().item_spacing.x * 4.), - ); + ui.add_space(ui.spacing().item_spacing.x.mul_add( + -4., + ui.available_width() - pause_game_btn_size.x - kill_game_btn_size.x, + )); if ui .add(Button::new( @@ -442,7 +433,10 @@ Please use the buttons below and use the "Copy Log File" button, and drag and dr views::utils::egui::compute_text_size(ui, pause_game_btn_text, true, false, None); ui.add_space( - ui.available_width() - pause_game_btn_size.x - (ui.spacing().item_spacing.x * 2.), + ui.spacing() + .item_spacing + .x + .mul_add(-2., ui.available_width() - pause_game_btn_size.x), ); if ui @@ -465,7 +459,7 @@ Please use the buttons below and use the "Copy Log File" button, and drag and dr fn render_log_text_filter_input( &mut self, ui: &mut Ui, - mods_combo_box: Response, + mods_combo_box: &Response, gui_config: &mut Config, ) { if ui @@ -499,7 +493,7 @@ Please use the buttons below and use the "Copy Log File" button, and drag and dr if mods_combo_box.changed() { self.filter.text = if self.filter.selected_index_in_mods_combo_box == 0 { - "".to_string() + String::new() } else { self.mods[self.filter.selected_index_in_mods_combo_box] .name() @@ -539,7 +533,8 @@ fn make_log_render_decision( } else { return LogRenderDecision::RenderAndCacheHeight; } - return LogRenderDecision::RenderNormally; + + LogRenderDecision::RenderNormally } fn render_loading_text(ui: &mut Ui) { @@ -561,14 +556,9 @@ fn make_ui_log_entry(ui: &mut Ui, log: &mut BepInExLogEntry, log_color: Color32) fn get_color_from_log_level(log: &mut BepInExLogEntry, info_log_color: Color32) -> Color32 { match log.level() { - LogLevel::None => Color32::RED, - LogLevel::Fatal => Color32::RED, - LogLevel::Error => Color32::RED, + LogLevel::None | LogLevel::Fatal | LogLevel::Error => Color32::RED, LogLevel::Warning => Color32::YELLOW, - LogLevel::Message => info_log_color, - LogLevel::Info => info_log_color, - LogLevel::Debug => info_log_color, - LogLevel::All => info_log_color, + LogLevel::Message | LogLevel::Info | LogLevel::Debug | LogLevel::All => info_log_color, } } @@ -590,7 +580,7 @@ impl Tab for ConsoleTab { ui.label(RichText::new("Log Filtering: ").font(FontId::proportional(20.0))); let mods_combo_box = self.render_log_mod_filter(ui); - self.render_log_text_filter_input(ui, mods_combo_box, gui_config); + self.render_log_text_filter_input(ui, &mods_combo_box, gui_config); render_auto_scroll_to_bottom_checkbox(ui, gui_config); @@ -642,11 +632,8 @@ fn render_auto_scroll_to_bottom_checkbox(ui: &mut Ui, gui_config: &mut Config) { impl ConsoleTab { fn update_mod_receiver(&mut self) { - match self.mod_receiver.try_recv() { - Ok(mod_) => { - self.mods.push(mod_); - } - Err(_) => {} + if let Ok(mod_) = self.mod_receiver.try_recv() { + self.mods.push(mod_); } } @@ -660,10 +647,8 @@ impl ConsoleTab { self.logs.push(log); } Err(err) => match err { - crossbeam_channel::TryRecvError::Empty => { - break; - } - crossbeam_channel::TryRecvError::Disconnected => { + crossbeam_channel::TryRecvError::Disconnected + | crossbeam_channel::TryRecvError::Empty => { break; } }, diff --git a/bepinex_gui/src/views/tabs/general.rs b/bepinex_gui/src/views/tabs/general.rs index 158388e..daf4bbd 100644 --- a/bepinex_gui/src/views/tabs/general.rs +++ b/bepinex_gui/src/views/tabs/general.rs @@ -35,8 +35,8 @@ impl GeneralTab { app::BepInExGUI::render_useful_buttons_footer( ui, ctx, - &data.game_folder_full_path(), - &data.bepinex_log_output_file_full_path(), + data.game_folder_full_path(), + data.bepinex_log_output_file_full_path(), data.target_process_id(), ); }); @@ -70,11 +70,8 @@ impl GeneralTab { } fn update_mod_receiver(&mut self) { - match self.mod_receiver.try_recv() { - Ok(mod_) => { - self.mods.push(mod_); - } - Err(_) => {} + if let Ok(mod_) = self.mod_receiver.try_recv() { + self.mods.push(mod_); } } } @@ -102,7 +99,7 @@ impl Tab for GeneralTab { }); let loaded_mod_count = self.mods.len(); - let loaded_mods_text = format!("Loaded Mods: {}", loaded_mod_count); + let loaded_mods_text = format!("Loaded Mods: {loaded_mod_count}"); ui.label(RichText::new(loaded_mods_text).font(FontId::proportional(20.0))); } diff --git a/bepinex_gui/src/views/tabs/mod.rs b/bepinex_gui/src/views/tabs/mod.rs index fcc011a..3ba9ff1 100644 --- a/bepinex_gui/src/views/tabs/mod.rs +++ b/bepinex_gui/src/views/tabs/mod.rs @@ -1,8 +1,8 @@ use crate::config::{launch::AppLaunchConfig, Config}; -pub(crate) mod console; -pub(crate) mod general; -pub(crate) mod settings; +pub mod console; +pub mod general; +pub mod settings; pub trait Tab { fn name(&self) -> &str; diff --git a/bepinex_gui/src/views/tabs/settings.rs b/bepinex_gui/src/views/tabs/settings.rs index ac65ef2..e03653b 100644 --- a/bepinex_gui/src/views/tabs/settings.rs +++ b/bepinex_gui/src/views/tabs/settings.rs @@ -12,7 +12,7 @@ use super::Tab; pub struct SettingsTab {} impl SettingsTab { - pub fn new() -> Self { + pub const fn new() -> Self { Self {} } diff --git a/bepinex_gui/src/views/utils/egui/mod.rs b/bepinex_gui/src/views/utils/egui/mod.rs index cfa7183..2ec7c36 100644 --- a/bepinex_gui/src/views/utils/egui/mod.rs +++ b/bepinex_gui/src/views/utils/egui/mod.rs @@ -1,6 +1,6 @@ use eframe::egui::*; -pub(crate) fn compute_text_size( +pub fn compute_text_size( ui: &mut Ui, text: &str, is_heading: bool, @@ -12,18 +12,17 @@ pub(crate) fn compute_text_size( if is_heading { rich_text = rich_text.heading(); } else if let Some(font_size) = font_size_ { - rich_text = rich_text.font(FontId::proportional(font_size)) + rich_text = rich_text.font(FontId::proportional(font_size)); } let label = Label::new(rich_text).wrap(is_wrap); let label_layout_in_ui = label.layout_in_ui(ui); - let text_size = label_layout_in_ui.1.size(); - text_size + label_layout_in_ui.1.size() } -pub(crate) fn scroll_when_trying_to_select_stuff_above_or_under_rect( +pub fn scroll_when_trying_to_select_stuff_above_or_under_rect( ui: &mut Ui, rect: Rect, ) -> Option {