From 2f95e86f5829ea58cf81f0464a76a5cc8a952c55 Mon Sep 17 00:00:00 2001 From: Truman Kilen Date: Sat, 8 Jun 2024 00:54:42 -0500 Subject: [PATCH] WIP tracy --- Cargo.lock | 57 +++++++++++++++++++++ hook/Cargo.toml | 3 ++ hook/src/hooks/mod.rs | 104 +++++++++++++++++++++++++++++++++++--- hook/src/lib.rs | 18 ++++--- hook_resolvers/src/lib.rs | 15 +++++- 5 files changed, 181 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b5c3312..b4c57c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1919,6 +1919,19 @@ dependencies = [ "system-deps", ] +[[package]] +name = "generator" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" +dependencies = [ + "cc", + "libc", + "log", + "rustversion", + "windows 0.48.0", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -2192,11 +2205,14 @@ dependencies = [ "postcard", "repak", "retour", + "seq-macro", "serde", "serde_json", "tokio", "tracing", "tracing-appender", + "tracing-subscriber", + "tracing-tracy", "widestring", "windows 0.52.0", ] @@ -2612,6 +2628,19 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "loom" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e045d70ddfbc984eacfa964ded019534e8f6cbf36f6410aee0ed5cefa5a9175" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + [[package]] name = "lzma-rs" version = "0.3.0" @@ -4878,6 +4907,34 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "tracing-tracy" +version = "0.11.0" +source = "git+https://github.com/trumank/rust_tracy_client.git?branch=static-linking#03be8471cb960a7f3dad502df34006e050169b17" +dependencies = [ + "tracing-core", + "tracing-subscriber", + "tracy-client", +] + +[[package]] +name = "tracy-client" +version = "0.17.0" +source = "git+https://github.com/trumank/rust_tracy_client.git?branch=static-linking#03be8471cb960a7f3dad502df34006e050169b17" +dependencies = [ + "loom", + "once_cell", + "tracy-client-sys", +] + +[[package]] +name = "tracy-client-sys" +version = "0.22.2" +source = "git+https://github.com/trumank/rust_tracy_client.git?branch=static-linking#03be8471cb960a7f3dad502df34006e050169b17" +dependencies = [ + "cc", +] + [[package]] name = "try-lock" version = "0.2.5" diff --git a/hook/Cargo.toml b/hook/Cargo.toml index 938a0d9..5aea56d 100644 --- a/hook/Cargo.toml +++ b/hook/Cargo.toml @@ -33,3 +33,6 @@ bitflags = "2.4.1" widestring = "1.0.2" tokio = { workspace = true, features = ["full"] } tracing-appender = "0.2.3" +seq-macro = "0.3.5" +tracing-subscriber = "0.3.18" +tracing-tracy = { git = "https://github.com/trumank/rust_tracy_client.git", branch = "static-linking" } diff --git a/hook/src/hooks/mod.rs b/hook/src/hooks/mod.rs index 3a94887..95f4ee1 100644 --- a/hook/src/hooks/mod.rs +++ b/hook/src/hooks/mod.rs @@ -3,6 +3,7 @@ mod server_list; use std::{ + collections::HashMap, ffi::c_void, path::{Path, PathBuf}, ptr::NonNull, @@ -17,7 +18,7 @@ use windows::Win32::System::Memory::{VirtualProtect, PAGE_EXECUTE_READWRITE}; use crate::{ globals, - ue::{self, FLinearColor, UObject}, + ue::{self, kismet::FFrame, FLinearColor, UFunction, UObject}, LOG_GUARD, }; @@ -28,6 +29,8 @@ retour::static_detour! { static DoesSaveGameExist: unsafe extern "system" fn(*const ue::FString, i32) -> bool; static UObjectTemperatureComponentTimerCallback: unsafe extern "system" fn(*mut c_void); static WinMain: unsafe extern "system" fn(*mut (), *mut (), *mut (), i32, *const ()) -> i32; + static FEngineLoopTick: unsafe extern "system" fn(*mut ()); + static UGameEngineTick: unsafe extern "system" fn(*mut (), f32, bool); } @@ -63,6 +66,20 @@ pub unsafe fn initialize() -> Result<()> { )?; WinMain.enable()?; + if let Ok(debug) = &globals().resolution.debug { + FEngineLoopTick.initialize( + std::mem::transmute(debug.fengine_loop_tick.0), + detour_fengine_loop_tick, + )?; + FEngineLoopTick.enable()?; + + UGameEngineTick.initialize( + std::mem::transmute(debug.ugame_engine_tick.0), + detour_ugame_engine_tick, + )?; + UGameEngineTick.enable()?; + } + HookUFunctionBind.initialize( std::mem::transmute(globals().resolution.core.as_ref().unwrap().ufunction_bind.0), move |function| { @@ -281,6 +298,72 @@ fn does_save_game_exist_detour(slot_name: *const ue::FString, user_index: i32) - } } +struct NativesArray([Option; 0x100]); + +static mut GNATIVES_OLD: NativesArray = NativesArray([None; 0x100]); +static mut NAME_CACHE: Option> = None; + +unsafe fn debug(expr: usize, ctx: *mut UObject, frame: *mut FFrame, ret: *mut c_void) { + if NAME_CACHE.is_none() { + NAME_CACHE = Some(Default::default()); + } + + let (index, path) = { + let stack = &*frame; + let func = &*(stack.node as *const UFunction); + + let index = 0; + //TODO causes issues for some reason + //let index = (stack.code as isize) + // .wrapping_sub(func.ustruct.script.as_ptr() as isize); + + let path = NAME_CACHE + .as_mut() + .unwrap_unchecked() + .entry(stack.node as usize) + .or_insert_with(|| { + func.ustruct + .ufield + .uobject + .uobject_base_utility + .uobject_base + .get_path_name(None) + }); + (index, path) + }; + + tracing::info_span!("kismet", path, index).in_scope(|| { + ((GNATIVES_OLD.0)[expr].unwrap())(ctx, frame, ret); + }); +} + +unsafe extern "system" fn hook_exec( + ctx: *mut UObject, + frame: *mut FFrame, + ret: *mut c_void, +) { + debug(N, ctx, frame, ret); +} + +unsafe fn hook_gnatives(gnatives: &mut NativesArray) { + seq_macro::seq!(N in 0..256 { + (GNATIVES_OLD.0)[N] = gnatives.0[N]; + gnatives.0[N] = Some(hook_exec::); + }); +} + +fn detour_fengine_loop_tick(this: *mut ()) { + tracing::warn_span!("FEngineLoop::Tick").in_scope(|| unsafe { + FEngineLoopTick.call(this); + }); +} + +fn detour_ugame_engine_tick(this: *mut (), delta_seconds: f32, b_idle_mode: bool) { + tracing::warn_span!("UGameEngine::Tick").in_scope(|| unsafe { + UGameEngineTick.call(this, delta_seconds, b_idle_mode); + }); +} + fn detour_main( h_instance: *mut (), h_prev_instance: *mut (), @@ -288,20 +371,25 @@ fn detour_main( n_cmd_show: i32, cmd_line: *const (), ) -> i32 { - let ret = unsafe { - WinMain.call( + unsafe { + if let Ok(debug) = &globals().resolution.debug { + tracing::info!("hooking GNatives"); + hook_gnatives((debug.gnatives.0 as *mut NativesArray).as_mut().unwrap()); + } + + let ret = WinMain.call( h_instance, h_prev_instance, lp_cmd_line, n_cmd_show, cmd_line, - ) - }; + ); - // about to exit, drop log guard - drop(unsafe { LOG_GUARD.take() }); + // about to exit, drop log guard + drop(LOG_GUARD.take()); - ret + ret + } } unsafe extern "system" fn exec_get_mod_json( diff --git a/hook/src/lib.rs b/hook/src/lib.rs index 7a6b28b..9ee5827 100644 --- a/hook/src/lib.rs +++ b/hook/src/lib.rs @@ -133,11 +133,17 @@ unsafe fn patch() -> Result<()> { let exe_path = std::env::current_exe().ok(); let bin_dir = exe_path.as_deref().and_then(Path::parent); - let guard = bin_dir - .and_then(|bin_dir| mint_lib::setup_logging(bin_dir.join("mint_hook.log"), "hook").ok()); - if guard.is_none() { - warn!("failed to set up logging"); - } + //let guard = bin_dir + // .and_then(|bin_dir| mint_lib::setup_logging(bin_dir.join("mint_hook.log"), "hook").ok()); + //if guard.is_none() { + // warn!("failed to set up logging"); + //} + use tracing_subscriber::layer::SubscriberExt; + + tracing::subscriber::set_global_default( + tracing_subscriber::registry().with(tracing_tracy::TracyLayer::default()), + ) + .expect("setup tracy layer"); let pak_path = bin_dir .and_then(Path::parent) @@ -156,7 +162,7 @@ unsafe fn patch() -> Result<()> { info!("PS scan: {:#x?}", resolution); GLOBALS = Some(Globals { resolution, meta }); - LOG_GUARD = guard; + //LOG_GUARD = guard; hooks::initialize()?; diff --git a/hook_resolvers/src/lib.rs b/hook_resolvers/src/lib.rs index 6b64d39..e3f0c87 100644 --- a/hook_resolvers/src/lib.rs +++ b/hook_resolvers/src/lib.rs @@ -1,9 +1,9 @@ use patternsleuth::resolvers::futures::future::join_all; use patternsleuth::resolvers::unreal::blueprint_library::UFunctionBind; use patternsleuth::resolvers::unreal::fname::{FNameCtorWchar, FNameToString}; -use patternsleuth::resolvers::unreal::game_loop::Main; +use patternsleuth::resolvers::unreal::game_loop::{FEngineLoopTick, Main, UGameEngineTick}; use patternsleuth::resolvers::unreal::gmalloc::GMalloc; -use patternsleuth::resolvers::unreal::kismet::{FFrameStep, FFrameStepExplicitProperty}; +use patternsleuth::resolvers::unreal::kismet::{FFrameStep, FFrameStepExplicitProperty, GNatives}; use patternsleuth::resolvers::unreal::save_game::{ UGameplayStaticsDoesSaveGameExist, UGameplayStaticsLoadGameFromMemory, UGameplayStaticsLoadGameFromSlot, UGameplayStaticsSaveGameToMemory, @@ -183,6 +183,16 @@ impl_try_collector! { } } +impl_try_collector! { + #[derive(Debug, PartialEq)] + #[cfg_attr(feature = "serde-resolvers", derive(Serialize, Deserialize))] + pub struct DebugResolution { + pub gnatives: GNatives, + pub ugame_engine_tick: UGameEngineTick, + pub fengine_loop_tick: FEngineLoopTick, + } +} + impl_collector! { #[derive(Debug, PartialEq)] #[cfg_attr(feature = "serde-resolvers", derive(Serialize, Deserialize))] @@ -193,5 +203,6 @@ impl_collector! { pub save_game: SaveGameResolution, pub gas_fix: GasFixResolution, pub core: CoreResolution, + pub debug: DebugResolution, } }