From 0590c82d4f1667c2db582c75ae6234e46800ace0 Mon Sep 17 00:00:00 2001 From: Vinjul1704 Date: Sat, 24 Aug 2024 00:02:25 +0200 Subject: [PATCH 01/26] Initial FPS patch --- src/soulmods/src/games/x64/eldenring.rs | 57 ++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/src/soulmods/src/games/x64/eldenring.rs b/src/soulmods/src/games/x64/eldenring.rs index d5f7cb52..836e52e1 100644 --- a/src/soulmods/src/games/x64/eldenring.rs +++ b/src/soulmods/src/games/x64/eldenring.rs @@ -21,17 +21,24 @@ use log::info; static mut IGT_BUFFER: f32 = 0.0f32; static mut IGT_HOOK: Option = None; +static mut FPS_1_HOOK: Option = None; +static mut FPS_2_HOOK: Option = None; + + #[allow(unused_assignments)] pub fn init_eldenring() { unsafe { + // Get ER process let mut process = Process::new("eldenring.exe"); process.refresh().unwrap(); - let fn_increment_igt_address = process.scan_abs("increment igt", "48 c7 44 24 20 fe ff ff ff 0f 29 74 24 40 0f 28 f0 48 8b 0d ? ? ? ? 0f 28 c8 f3 0f 59 0d ? ? ? ?", 35, Vec::new()).unwrap().get_base_address(); + // AoB scan for timer patch + let fn_increment_igt_address = process.scan_abs("increment igt", "48 c7 44 24 20 fe ff ff ff 0f 29 74 24 40 0f 28 f0 48 8b 0d ? ? ? ? 0f 28 c8 f3 0f 59 0d ? ? ? ?", 35, Vec::new()).unwrap().get_base_address(); info!("increment IGT at 0x{:x}", fn_increment_igt_address); + // Timer patch unsafe extern "win64" fn increment_igt(registers: *mut Registers, _:usize) { let mut frame_delta = std::mem::transmute::((*registers).xmm0 as u32); @@ -53,7 +60,55 @@ pub fn init_eldenring() (*registers).xmm1 = std::mem::transmute::(floored_frame_delta) as u128; } + // Enable timer patch IGT_HOOK = Some(Hooker::new(fn_increment_igt_address, HookType::JmpBack(increment_igt), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); + + + // AoB scan for FPS patch 1 + let fn_fps_1_address = process.scan_abs("fps 1", "8b 83 64 02 00 00 89 83 b4 02 00 00", 0, Vec::new()).unwrap().get_base_address(); + info!("FPS 1 at 0x{:x}", fn_fps_1_address); + + // FPS patch 1 + unsafe extern "win64" fn fps_1(registers: *mut Registers, _:usize) + { + let ptr_flipper = (*registers).rbx as *const u8; + + let ptr_target_frame_delta = ptr_flipper.offset(0x1c) as *mut f32; + let ptr_0x20 = ptr_flipper.offset(0x20) as *mut i32; + let ptr_0x264 = ptr_flipper.offset(0x264) as *mut f32; + + let target_frame_delta = std::ptr::read_volatile(ptr_target_frame_delta); + let target_0x20 = (target_frame_delta * 10000000.0) as i32; + let target_0x264 = (target_0x20 as f32) / 10000000.0; + + std::ptr::write_volatile(ptr_0x20, target_0x20); + std::ptr::write_volatile(ptr_0x264, target_0x264); + } + + // Enable FPS patch 1 + FPS_1_HOOK = Some(Hooker::new(fn_fps_1_address, HookType::JmpBack(fps_1), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); + + + // AoB scan for FPS patch 2 + let fn_fps_2_address = process.scan_abs("fps 2", "48 89 04 cb 0f b6 83 74 02 00 00", 0, Vec::new()).unwrap().get_base_address(); + info!("FPS 2 at 0x{:x}", fn_fps_2_address); + + // FPS patch 2 + unsafe extern "win64" fn fps_2(registers: *mut Registers, _:usize) + { + let ptr_flipper = (*registers).rbx as *const u8; + + let ptr_target_frame_delta = ptr_flipper.offset(0x1c) as *mut f32; + let ptr_rcx8 = ptr_flipper.offset(((*registers).rcx as u32 * 8) as isize) as *mut i32; + + let target_frame_delta = std::ptr::read_volatile(ptr_target_frame_delta); + let target_rcx8 = (target_frame_delta * 10000000.0) as i32; + + std::ptr::write_volatile(ptr_rcx8, target_rcx8); + } + + // Enable FPS patch 2 + FPS_2_HOOK = Some(Hooker::new(fn_fps_2_address, HookType::JmpBack(fps_2), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); } } From c8bbdafa92c5c2b2ae9b6da5cafc28abeede0e78 Mon Sep 17 00:00:00 2001 From: Vinjul1704 Date: Sat, 24 Aug 2024 12:21:37 +0200 Subject: [PATCH 02/26] Fix FPS patch + renaming/commenting --- src/soulmods/src/games/x64/eldenring.rs | 73 +++++++++++++++---------- 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/src/soulmods/src/games/x64/eldenring.rs b/src/soulmods/src/games/x64/eldenring.rs index 836e52e1..fa9ee993 100644 --- a/src/soulmods/src/games/x64/eldenring.rs +++ b/src/soulmods/src/games/x64/eldenring.rs @@ -21,8 +21,8 @@ use log::info; static mut IGT_BUFFER: f32 = 0.0f32; static mut IGT_HOOK: Option = None; -static mut FPS_1_HOOK: Option = None; -static mut FPS_2_HOOK: Option = None; +static mut FPS_HOOK: Option = None; +static mut FPS_HISTORY_HOOK: Option = None; #[allow(unused_assignments)] @@ -64,51 +64,66 @@ pub fn init_eldenring() IGT_HOOK = Some(Hooker::new(fn_increment_igt_address, HookType::JmpBack(increment_igt), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); - // AoB scan for FPS patch 1 - let fn_fps_1_address = process.scan_abs("fps 1", "8b 83 64 02 00 00 89 83 b4 02 00 00", 0, Vec::new()).unwrap().get_base_address(); - info!("FPS 1 at 0x{:x}", fn_fps_1_address); + // AoB scan for FPS patch + let fn_fps_address = process.scan_abs("fps", "8b 83 64 02 00 00 89 83 b4 02 00 00", 0, Vec::new()).unwrap().get_base_address(); + info!("FPS at 0x{:x}", fn_fps_address); - // FPS patch 1 - unsafe extern "win64" fn fps_1(registers: *mut Registers, _:usize) + // FPS patch + // Sets the calculated frame delta to always be the target frame delta. + // It also sets the previous frames timestamp to be the current one minus the target frame delta. + // This makes it so the game always behaves as if it's running at the FPS limit, with slowdowns if the PC can't keep up. + // A second patch, "FPS history" below, is required in addition to this one to ensure accuracy. + unsafe extern "win64" fn fps(registers: *mut Registers, _:usize) { - let ptr_flipper = (*registers).rbx as *const u8; + let ptr_flipper = (*registers).rbx as *const u8; // Flipper struct - Contains all the stuff we need - let ptr_target_frame_delta = ptr_flipper.offset(0x1c) as *mut f32; - let ptr_0x20 = ptr_flipper.offset(0x20) as *mut i32; - let ptr_0x264 = ptr_flipper.offset(0x264) as *mut f32; + let ptr_target_frame_delta = ptr_flipper.offset(0x1c) as *mut f32; // Target frame delta - Set in a switch/case at the start + let ptr_timestamp_previous = ptr_flipper.offset(0x20) as *mut i64; // Previous frames timestamp + let ptr_timestamp_current = ptr_flipper.offset(0x28) as *mut i64; // Current frames timestamp + let ptr_frame_delta = ptr_flipper.offset(0x264) as *mut f32; // Current frames frame delta + // Read target frame data, the current timestamp and then calculate the timestamp diff at stable FPS let target_frame_delta = std::ptr::read_volatile(ptr_target_frame_delta); - let target_0x20 = (target_frame_delta * 10000000.0) as i32; - let target_0x264 = (target_0x20 as f32) / 10000000.0; + let timestamp_current = std::ptr::read_volatile(ptr_timestamp_current); + let timestamp_diff = (target_frame_delta * 10000000.0) as i32; - std::ptr::write_volatile(ptr_0x20, target_0x20); - std::ptr::write_volatile(ptr_0x264, target_0x264); + // Calculate the previous timestamp, as well as the frame delta + let timestamp_previous = timestamp_current - (timestamp_diff as i64); + let frame_delta = (timestamp_diff as f32) / 10000000.0; + + // Write values back + std::ptr::write_volatile(ptr_timestamp_previous, timestamp_previous); + std::ptr::write_volatile(ptr_frame_delta, frame_delta); } - // Enable FPS patch 1 - FPS_1_HOOK = Some(Hooker::new(fn_fps_1_address, HookType::JmpBack(fps_1), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); + // Enable FPS patch + FPS_HOOK = Some(Hooker::new(fn_fps_address, HookType::JmpBack(fps), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); - // AoB scan for FPS patch 2 - let fn_fps_2_address = process.scan_abs("fps 2", "48 89 04 cb 0f b6 83 74 02 00 00", 0, Vec::new()).unwrap().get_base_address(); - info!("FPS 2 at 0x{:x}", fn_fps_2_address); + // AoB scan for FPS history patch + let fn_fps_history_address = process.scan_abs("fps history", "48 89 04 cb 0f b6 83 74 02 00 00", 0, Vec::new()).unwrap().get_base_address(); + info!("FPS history at 0x{:x}", fn_fps_history_address); - // FPS patch 2 - unsafe extern "win64" fn fps_2(registers: *mut Registers, _:usize) + // FPS history patch + // Similar to the FPS patch, this sets the difference between the previous and current frames timestamps to the target frame delta. + // This gets stored in an array with 32 elements, possibly for calculating FPS averages. + unsafe extern "win64" fn fps_history(registers: *mut Registers, _:usize) { - let ptr_flipper = (*registers).rbx as *const u8; + let ptr_flipper = (*registers).rbx as *const u8; // Flipper struct - Contains all the stuff we need - let ptr_target_frame_delta = ptr_flipper.offset(0x1c) as *mut f32; - let ptr_rcx8 = ptr_flipper.offset(((*registers).rcx as u32 * 8) as isize) as *mut i32; + let ptr_target_frame_delta = ptr_flipper.offset(0x1c) as *mut f32; // Target frame delta - Set in a switch/case at the start + let ptr_frame_delta_history = ptr_flipper.offset(((*registers).rcx as u32 * 8) as isize) as *mut u64; // Frame delta history - In an array of 32, with the index incrementing each frame + // Read the target frame delta and calculate the frame delta timestamp let target_frame_delta = std::ptr::read_volatile(ptr_target_frame_delta); - let target_rcx8 = (target_frame_delta * 10000000.0) as i32; + let target_frame_delta_history = (target_frame_delta * 10000000.0) as u64; - std::ptr::write_volatile(ptr_rcx8, target_rcx8); + // Write values back + std::ptr::write_volatile(ptr_frame_delta_history, target_frame_delta_history); } - // Enable FPS patch 2 - FPS_2_HOOK = Some(Hooker::new(fn_fps_2_address, HookType::JmpBack(fps_2), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); + // Enable FPS history patch + FPS_HISTORY_HOOK = Some(Hooker::new(fn_fps_history_address, HookType::JmpBack(fps_history), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); } } From 8f7754963a8e5ce648c418d459d5c0ef62955f88 Mon Sep 17 00:00:00 2001 From: Vinjul1704 Date: Sat, 24 Aug 2024 16:43:05 +0200 Subject: [PATCH 03/26] Simple bool to control FPS patches --- src/soulmods/src/games/x64/eldenring.rs | 72 +++++++++++++++++-------- 1 file changed, 49 insertions(+), 23 deletions(-) diff --git a/src/soulmods/src/games/x64/eldenring.rs b/src/soulmods/src/games/x64/eldenring.rs index fa9ee993..0b3643ea 100644 --- a/src/soulmods/src/games/x64/eldenring.rs +++ b/src/soulmods/src/games/x64/eldenring.rs @@ -24,6 +24,8 @@ static mut IGT_HOOK: Option = None; static mut FPS_HOOK: Option = None; static mut FPS_HISTORY_HOOK: Option = None; +static mut FPS_HOOK_ENABLED: bool = true; + #[allow(unused_assignments)] pub fn init_eldenring() @@ -75,25 +77,28 @@ pub fn init_eldenring() // A second patch, "FPS history" below, is required in addition to this one to ensure accuracy. unsafe extern "win64" fn fps(registers: *mut Registers, _:usize) { - let ptr_flipper = (*registers).rbx as *const u8; // Flipper struct - Contains all the stuff we need + if (FPS_HOOK_ENABLED) + { + let ptr_flipper = (*registers).rbx as *const u8; // Flipper struct - Contains all the stuff we need - let ptr_target_frame_delta = ptr_flipper.offset(0x1c) as *mut f32; // Target frame delta - Set in a switch/case at the start - let ptr_timestamp_previous = ptr_flipper.offset(0x20) as *mut i64; // Previous frames timestamp - let ptr_timestamp_current = ptr_flipper.offset(0x28) as *mut i64; // Current frames timestamp - let ptr_frame_delta = ptr_flipper.offset(0x264) as *mut f32; // Current frames frame delta + let ptr_target_frame_delta = ptr_flipper.offset(0x1c) as *mut f32; // Target frame delta - Set in a switch/case at the start + let ptr_timestamp_previous = ptr_flipper.offset(0x20) as *mut i64; // Previous frames timestamp + let ptr_timestamp_current = ptr_flipper.offset(0x28) as *mut i64; // Current frames timestamp + let ptr_frame_delta = ptr_flipper.offset(0x264) as *mut f32; // Current frames frame delta - // Read target frame data, the current timestamp and then calculate the timestamp diff at stable FPS - let target_frame_delta = std::ptr::read_volatile(ptr_target_frame_delta); - let timestamp_current = std::ptr::read_volatile(ptr_timestamp_current); - let timestamp_diff = (target_frame_delta * 10000000.0) as i32; + // Read target frame data, the current timestamp and then calculate the timestamp diff at stable FPS + let target_frame_delta = std::ptr::read_volatile(ptr_target_frame_delta); + let timestamp_current = std::ptr::read_volatile(ptr_timestamp_current); + let timestamp_diff = (target_frame_delta * 10000000.0) as i32; - // Calculate the previous timestamp, as well as the frame delta - let timestamp_previous = timestamp_current - (timestamp_diff as i64); - let frame_delta = (timestamp_diff as f32) / 10000000.0; + // Calculate the previous timestamp, as well as the frame delta + let timestamp_previous = timestamp_current - (timestamp_diff as i64); + let frame_delta = (timestamp_diff as f32) / 10000000.0; - // Write values back - std::ptr::write_volatile(ptr_timestamp_previous, timestamp_previous); - std::ptr::write_volatile(ptr_frame_delta, frame_delta); + // Write values back + std::ptr::write_volatile(ptr_timestamp_previous, timestamp_previous); + std::ptr::write_volatile(ptr_frame_delta, frame_delta); + } } // Enable FPS patch @@ -109,17 +114,20 @@ pub fn init_eldenring() // This gets stored in an array with 32 elements, possibly for calculating FPS averages. unsafe extern "win64" fn fps_history(registers: *mut Registers, _:usize) { - let ptr_flipper = (*registers).rbx as *const u8; // Flipper struct - Contains all the stuff we need + if (FPS_HOOK_ENABLED) + { + let ptr_flipper = (*registers).rbx as *const u8; // Flipper struct - Contains all the stuff we need - let ptr_target_frame_delta = ptr_flipper.offset(0x1c) as *mut f32; // Target frame delta - Set in a switch/case at the start - let ptr_frame_delta_history = ptr_flipper.offset(((*registers).rcx as u32 * 8) as isize) as *mut u64; // Frame delta history - In an array of 32, with the index incrementing each frame + let ptr_target_frame_delta = ptr_flipper.offset(0x1c) as *mut f32; // Target frame delta - Set in a switch/case at the start + let ptr_frame_delta_history = ptr_flipper.offset(((*registers).rcx as u32 * 8) as isize) as *mut u64; // Frame delta history - In an array of 32, with the index incrementing each frame - // Read the target frame delta and calculate the frame delta timestamp - let target_frame_delta = std::ptr::read_volatile(ptr_target_frame_delta); - let target_frame_delta_history = (target_frame_delta * 10000000.0) as u64; + // Read the target frame delta and calculate the frame delta timestamp + let target_frame_delta = std::ptr::read_volatile(ptr_target_frame_delta); + let target_frame_delta_history = (target_frame_delta * 10000000.0) as u64; - // Write values back - std::ptr::write_volatile(ptr_frame_delta_history, target_frame_delta_history); + // Write values back + std::ptr::write_volatile(ptr_frame_delta_history, target_frame_delta_history); + } } // Enable FPS history patch @@ -127,6 +135,24 @@ pub fn init_eldenring() } } +#[no_mangle] +pub extern "C" fn fps_patch_disable() +{ + unsafe + { + FPS_HOOK_ENABLED = false; + } +} + +#[no_mangle] +pub extern "C" fn fps_patch_enable() +{ + unsafe + { + FPS_HOOK_ENABLED = true; + } +} + pub fn calculate_igt_corrections(mut frame_delta: f32, igt_frac: &mut f32) -> f32 { //convert to milliseconds From 2e1965e6486cd8f604a0ef488bc2b2c711eb5c78 Mon Sep 17 00:00:00 2001 From: Vinjul1704 Date: Sat, 24 Aug 2024 17:02:42 +0200 Subject: [PATCH 04/26] Fix int types --- src/soulmods/src/games/x64/eldenring.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/soulmods/src/games/x64/eldenring.rs b/src/soulmods/src/games/x64/eldenring.rs index 0b3643ea..2662cd22 100644 --- a/src/soulmods/src/games/x64/eldenring.rs +++ b/src/soulmods/src/games/x64/eldenring.rs @@ -82,8 +82,8 @@ pub fn init_eldenring() let ptr_flipper = (*registers).rbx as *const u8; // Flipper struct - Contains all the stuff we need let ptr_target_frame_delta = ptr_flipper.offset(0x1c) as *mut f32; // Target frame delta - Set in a switch/case at the start - let ptr_timestamp_previous = ptr_flipper.offset(0x20) as *mut i64; // Previous frames timestamp - let ptr_timestamp_current = ptr_flipper.offset(0x28) as *mut i64; // Current frames timestamp + let ptr_timestamp_previous = ptr_flipper.offset(0x20) as *mut u64; // Previous frames timestamp + let ptr_timestamp_current = ptr_flipper.offset(0x28) as *mut u64; // Current frames timestamp let ptr_frame_delta = ptr_flipper.offset(0x264) as *mut f32; // Current frames frame delta // Read target frame data, the current timestamp and then calculate the timestamp diff at stable FPS @@ -92,7 +92,7 @@ pub fn init_eldenring() let timestamp_diff = (target_frame_delta * 10000000.0) as i32; // Calculate the previous timestamp, as well as the frame delta - let timestamp_previous = timestamp_current - (timestamp_diff as i64); + let timestamp_previous = timestamp_current - (timestamp_diff as u64); let frame_delta = (timestamp_diff as f32) / 10000000.0; // Write values back From 1ced3d070845c2e95f51445a82948033a0674267 Mon Sep 17 00:00:00 2001 From: Vinjul1704 Date: Sat, 24 Aug 2024 17:22:52 +0200 Subject: [PATCH 05/26] Disable FPS patch by default --- src/soulmods/src/games/x64/eldenring.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/soulmods/src/games/x64/eldenring.rs b/src/soulmods/src/games/x64/eldenring.rs index d7abb50f..24a55ace 100644 --- a/src/soulmods/src/games/x64/eldenring.rs +++ b/src/soulmods/src/games/x64/eldenring.rs @@ -25,7 +25,7 @@ static mut IGT_HOOK: Option = None; static mut FPS_HOOK: Option = None; static mut FPS_HISTORY_HOOK: Option = None; -static mut FPS_HOOK_ENABLED: bool = true; +static mut FPS_HOOK_ENABLED: bool = false; #[allow(unused_assignments)] From ae5ac05ef659a022b30563ee48a78917a82474f3 Mon Sep 17 00:00:00 2001 From: Vinjul1704 Date: Sat, 24 Aug 2024 18:21:19 +0200 Subject: [PATCH 06/26] Auto toggle FPS patch every 10 seconds for testing --- src/SoulSplitter/SoulComponent.cs | 16 ++++++++++++++++ src/soulmods/src/games/x64/eldenring.rs | 13 +++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/SoulSplitter/SoulComponent.cs b/src/SoulSplitter/SoulComponent.cs index 36329eb4..2d97688a 100644 --- a/src/SoulSplitter/SoulComponent.cs +++ b/src/SoulSplitter/SoulComponent.cs @@ -32,6 +32,7 @@ using System.Reflection; using System.Windows.Forms; using SoulSplitter.Migrations; +using SoulMemory.Native; namespace SoulSplitter { @@ -44,6 +45,7 @@ public class SoulComponent : IComponent private ISplitter _splitter = null; private IGame _game = null; private DateTime _lastFailedRefresh = DateTime.MinValue; + private DateTime _lastFpsToggle = DateTime.MinValue; // Remove after tests private bool _previousBitBlt = false; public readonly MainWindow MainWindow; public SoulComponent(LiveSplitState state = null, bool shouldThrowOnInvalidInstallation = true) @@ -98,6 +100,20 @@ public void Update(IInvalidator invalidator, LiveSplitState state, float width, _lastFailedRefresh = DateTime.Now; } } + + // Remove after tests + var dateNow = DateTime.Now; + if (dateNow > _lastFpsToggle.AddSeconds(10)) + { + _lastFpsToggle = dateNow; + + var process = _game.GetProcess(); + var soulmods = process.GetModuleExportedFunctions("soulmods.dll"); + var func = soulmods.First(i => i.name == "fps_patch_toggle").address; + + process.Execute((IntPtr)func); + } + } catch (Exception e) { diff --git a/src/soulmods/src/games/x64/eldenring.rs b/src/soulmods/src/games/x64/eldenring.rs index 24a55ace..9881c1e6 100644 --- a/src/soulmods/src/games/x64/eldenring.rs +++ b/src/soulmods/src/games/x64/eldenring.rs @@ -139,7 +139,7 @@ pub fn init_eldenring() } #[no_mangle] -pub extern "C" fn fps_patch_disable() +pub extern "C" fn fps_patch_disable() // Disables FPS patch { unsafe { @@ -148,10 +148,19 @@ pub extern "C" fn fps_patch_disable() } #[no_mangle] -pub extern "C" fn fps_patch_enable() +pub extern "C" fn fps_patch_enable() // Enables FPS patch { unsafe { FPS_HOOK_ENABLED = true; } +} + +#[no_mangle] +pub extern "C" fn fps_patch_toggle() // Toggles FPS patch +{ + unsafe + { + FPS_HOOK_ENABLED = !FPS_HOOK_ENABLED; + } } \ No newline at end of file From 88c822826d534b4c996ffd5afe42a3fc12c46c49 Mon Sep 17 00:00:00 2001 From: Frank van der Stam Date: Sun, 25 Aug 2024 10:42:29 +0200 Subject: [PATCH 07/26] Fix a couple warnings about paranthesis in if statements --- src/soulmods/src/games/x64/eldenring.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/soulmods/src/games/x64/eldenring.rs b/src/soulmods/src/games/x64/eldenring.rs index 9881c1e6..1791da89 100644 --- a/src/soulmods/src/games/x64/eldenring.rs +++ b/src/soulmods/src/games/x64/eldenring.rs @@ -80,7 +80,7 @@ pub fn init_eldenring() // A second patch, "FPS history" below, is required in addition to this one to ensure accuracy. unsafe extern "win64" fn fps(registers: *mut Registers, _:usize) { - if (FPS_HOOK_ENABLED) + if FPS_HOOK_ENABLED { let ptr_flipper = (*registers).rbx as *const u8; // Flipper struct - Contains all the stuff we need @@ -117,7 +117,7 @@ pub fn init_eldenring() // This gets stored in an array with 32 elements, possibly for calculating FPS averages. unsafe extern "win64" fn fps_history(registers: *mut Registers, _:usize) { - if (FPS_HOOK_ENABLED) + if FPS_HOOK_ENABLED { let ptr_flipper = (*registers).rbx as *const u8; // Flipper struct - Contains all the stuff we need From 3b323180ca86dbe68899fa85665b35ba66a5a49a Mon Sep 17 00:00:00 2001 From: Frank van der Stam Date: Sun, 25 Aug 2024 11:22:05 +0200 Subject: [PATCH 08/26] Small cleanup. Move ER hook functions out of the init function. --- src/SoulMemory/EldenRing/EldenRing.cs | 29 ++++- src/SoulMemory/Native/Kernel32.cs | 10 +- src/SoulMemory/soulmods/Soulmods.cs | 7 +- src/SoulSplitter/SoulComponent.cs | 14 --- src/cli/Program.cs | 14 ++- src/soulmods/src/games/x64/eldenring.rs | 150 ++++++++++++------------ 6 files changed, 121 insertions(+), 103 deletions(-) diff --git a/src/SoulMemory/EldenRing/EldenRing.cs b/src/SoulMemory/EldenRing/EldenRing.cs index 98741d08..08ba6188 100644 --- a/src/SoulMemory/EldenRing/EldenRing.cs +++ b/src/SoulMemory/EldenRing/EldenRing.cs @@ -17,6 +17,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using SoulMemory.Memory; using SoulMemory.Native; using Pointer = SoulMemory.Memory.Pointer; @@ -40,7 +41,7 @@ public class EldenRing : IGame private long _positionOffset; private long _mapIdOffset; private long _playerInsOffset; - + private Dictionary _exportedFunctions; #region Refresh/init/reset ================================================================================================ public Process GetProcess() => _process; @@ -157,7 +158,8 @@ private ResultErr InitPointers() _igt.Clear(); return Result.Err(new RefreshError(RefreshErrorReason.UnknownException, "soulmods injection failed")); } - + + _exportedFunctions = _process.GetModuleExportedFunctions("soulmods.dll"); return Result.Ok(); } catch (Exception e) @@ -577,5 +579,28 @@ public void WriteInGameTimeMilliseconds(int milliseconds) } #endregion + + #region soulmods + + public void FpsPatchDisable() + { + var address = _exportedFunctions["fps_patch_disable"]; + _process.Execute((IntPtr)address); + } + + public void FpsPatchEnable() + { + var address = _exportedFunctions["fps_patch_enable"]; + _process.Execute((IntPtr)address); + } + + public void FpsPatchToggle() + { + var address = _exportedFunctions["fps_patch_toggle"]; + var ptr = (IntPtr)address; + _process.Execute((IntPtr)address); + } + + #endregion } } diff --git a/src/SoulMemory/Native/Kernel32.cs b/src/SoulMemory/Native/Kernel32.cs index 64d96e32..40424752 100644 --- a/src/SoulMemory/Native/Kernel32.cs +++ b/src/SoulMemory/Native/Kernel32.cs @@ -332,7 +332,7 @@ void CleanupSnapshot() - public static List<(string name, long address)> GetModuleExportedFunctions(this Process process, string hModuleName) + public static Dictionary GetModuleExportedFunctions(this Process process, string hModuleName) { var modules = process.GetModulesViaSnapshot(); var module = modules.First(i => i.szModule.ToLowerInvariant() == hModuleName.ToLowerInvariant()); @@ -362,12 +362,12 @@ void CleanupSnapshot() var ordinalTable = module.modBaseAddr.ToInt64() + exportTable.AddressOfNameOrdinals; var functionOffsetTable = module.modBaseAddr.ToInt64() + exportTable.AddressOfFunctions; - var functions = new List<(string name, long address)>(); + var functions = new Dictionary(); for (var i = 0; i < exportTable.NumberOfNames; i++) { - var EAT = module.modBaseAddr.ToInt64() + exportTable.AddressOfFunctions; + var eat = module.modBaseAddr.ToInt64() + exportTable.AddressOfFunctions; - var EATPtr = (IntPtr)EAT; + var eatPtr = (IntPtr)eat; //Function name offset is an array of 4byte numbers var functionNameOffset = process.ReadMemory(nameOffsetTable + i * sizeof(uint)).Unwrap(); @@ -380,7 +380,7 @@ void CleanupSnapshot() var functionOffset = process.ReadMemory(functionOffsetTable + i * sizeof(uint)).Unwrap(); var functionAddress = module.modBaseAddr.ToInt64() + functionOffset; - functions.Add((functionName, functionAddress)); + functions.Add(functionName, functionAddress); } return functions; diff --git a/src/SoulMemory/soulmods/Soulmods.cs b/src/SoulMemory/soulmods/Soulmods.cs index b88b1d7d..58a2be3a 100644 --- a/src/SoulMemory/soulmods/Soulmods.cs +++ b/src/SoulMemory/soulmods/Soulmods.cs @@ -75,14 +75,15 @@ public static bool Inject(Process process) - private static List<(string name, long address)> _soulmodsMethods; + private static Dictionary _soulmodsMethods; public static TSized RustCall(this Process process, string function, TSized? parameter = null) where TSized : struct { if (_soulmodsMethods == null) { _soulmodsMethods = process.GetModuleExportedFunctions("soulmods.dll"); } - var functionPtr = _soulmodsMethods.First(i => i.name == function).address; + + var functionPtr = _soulmodsMethods[function]; var buffer = process.Allocate(Marshal.SizeOf()); if (parameter.HasValue) @@ -100,7 +101,7 @@ public static void GetMorphemeMessages(Process process) { //Get function address var soulmods = process.GetModuleExportedFunctions("soulmods.dll"); - var func = soulmods.First(i => i.name == "GetQueuedDarkSouls2MorphemeMessages").address; + var func = soulmods["GetQueuedDarkSouls2MorphemeMessages"]; //Get buffer size var buffer = process.Allocate(4); diff --git a/src/SoulSplitter/SoulComponent.cs b/src/SoulSplitter/SoulComponent.cs index 2d97688a..e92afb3f 100644 --- a/src/SoulSplitter/SoulComponent.cs +++ b/src/SoulSplitter/SoulComponent.cs @@ -100,20 +100,6 @@ public void Update(IInvalidator invalidator, LiveSplitState state, float width, _lastFailedRefresh = DateTime.Now; } } - - // Remove after tests - var dateNow = DateTime.Now; - if (dateNow > _lastFpsToggle.AddSeconds(10)) - { - _lastFpsToggle = dateNow; - - var process = _game.GetProcess(); - var soulmods = process.GetModuleExportedFunctions("soulmods.dll"); - var func = soulmods.First(i => i.name == "fps_patch_toggle").address; - - process.Execute((IntPtr)func); - } - } catch (Exception e) { diff --git a/src/cli/Program.cs b/src/cli/Program.cs index 5e9271e0..813f1128 100644 --- a/src/cli/Program.cs +++ b/src/cli/Program.cs @@ -41,13 +41,21 @@ internal class Program [STAThread] static void Main(string[] args) { - GlobalHotKey.RegisterHotKey(ModifierKeys.Alt, Key.A, () =>{ Debug.WriteLine("A"); }); - GlobalHotKey.RegisterHotKey(ModifierKeys.Alt, Key.S, () =>{ Debug.WriteLine("S"); }); - GlobalHotKey.RegisterHotKey(ModifierKeys.Alt, Key.D, () =>{ Debug.WriteLine("D"); }); + //GlobalHotKey.RegisterHotKey(ModifierKeys.Alt, Key.A, () =>{ Debug.WriteLine("A"); }); + //GlobalHotKey.RegisterHotKey(ModifierKeys.Alt, Key.S, () =>{ Debug.WriteLine("S"); }); + //GlobalHotKey.RegisterHotKey(ModifierKeys.Alt, Key.D, () =>{ Debug.WriteLine("D"); }); //TestUi(); + + bool init = true; GameLoop((e) => { + if (init) + { + GlobalHotKey.RegisterHotKey(ModifierKeys.Alt, Key.A, e.FpsPatchToggle); + init = false; + } + var igtElapsed = TimeSpan.FromMilliseconds(e.GetInGameTimeMilliseconds()); Console.WriteLine($"IGT: {igtElapsed}"); }); diff --git a/src/soulmods/src/games/x64/eldenring.rs b/src/soulmods/src/games/x64/eldenring.rs index 1791da89..a982b350 100644 --- a/src/soulmods/src/games/x64/eldenring.rs +++ b/src/soulmods/src/games/x64/eldenring.rs @@ -43,96 +43,20 @@ pub fn init_eldenring() let fn_increment_igt_address = process.scan_abs("increment igt", "48 c7 44 24 20 fe ff ff ff 0f 29 74 24 40 0f 28 f0 48 8b 0d ? ? ? ? 0f 28 c8 f3 0f 59 0d ? ? ? ?", 35, Vec::new()).unwrap().get_base_address(); info!("increment IGT at 0x{:x}", fn_increment_igt_address); - // Timer patch - unsafe extern "win64" fn increment_igt(registers: *mut Registers, _:usize) - { - let mut frame_delta = std::mem::transmute::((*registers).xmm0 as u32); - //convert to milliseconds - frame_delta = frame_delta * 1000f32; - frame_delta = frame_delta * 0.96f32; //scale to IGT - - //Rather than casting, like the game does, make the behavior explicit by flooring - let mut floored_frame_delta = frame_delta.floor(); - let remainder = frame_delta - floored_frame_delta; - IGT_BUFFER = IGT_BUFFER + remainder; - - if IGT_BUFFER > 1.0f32 - { - IGT_BUFFER = IGT_BUFFER - 1f32; - floored_frame_delta += 1f32; - } - - (*registers).xmm1 = std::mem::transmute::(floored_frame_delta) as u128; - } - // Enable timer patch IGT_HOOK = Some(Hooker::new(fn_increment_igt_address, HookType::JmpBack(increment_igt), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); - // AoB scan for FPS patch let fn_fps_address = process.scan_abs("fps", "8b 83 64 02 00 00 89 83 b4 02 00 00", 0, Vec::new()).unwrap().get_base_address(); info!("FPS at 0x{:x}", fn_fps_address); - // FPS patch - // Sets the calculated frame delta to always be the target frame delta. - // It also sets the previous frames timestamp to be the current one minus the target frame delta. - // This makes it so the game always behaves as if it's running at the FPS limit, with slowdowns if the PC can't keep up. - // A second patch, "FPS history" below, is required in addition to this one to ensure accuracy. - unsafe extern "win64" fn fps(registers: *mut Registers, _:usize) - { - if FPS_HOOK_ENABLED - { - let ptr_flipper = (*registers).rbx as *const u8; // Flipper struct - Contains all the stuff we need - - let ptr_target_frame_delta = ptr_flipper.offset(0x1c) as *mut f32; // Target frame delta - Set in a switch/case at the start - let ptr_timestamp_previous = ptr_flipper.offset(0x20) as *mut u64; // Previous frames timestamp - let ptr_timestamp_current = ptr_flipper.offset(0x28) as *mut u64; // Current frames timestamp - let ptr_frame_delta = ptr_flipper.offset(0x264) as *mut f32; // Current frames frame delta - - // Read target frame data, the current timestamp and then calculate the timestamp diff at stable FPS - let target_frame_delta = std::ptr::read_volatile(ptr_target_frame_delta); - let timestamp_current = std::ptr::read_volatile(ptr_timestamp_current); - let timestamp_diff = (target_frame_delta * 10000000.0) as i32; - - // Calculate the previous timestamp, as well as the frame delta - let timestamp_previous = timestamp_current - (timestamp_diff as u64); - let frame_delta = (timestamp_diff as f32) / 10000000.0; - - // Write values back - std::ptr::write_volatile(ptr_timestamp_previous, timestamp_previous); - std::ptr::write_volatile(ptr_frame_delta, frame_delta); - } - } - // Enable FPS patch FPS_HOOK = Some(Hooker::new(fn_fps_address, HookType::JmpBack(fps), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); - // AoB scan for FPS history patch let fn_fps_history_address = process.scan_abs("fps history", "48 89 04 cb 0f b6 83 74 02 00 00", 0, Vec::new()).unwrap().get_base_address(); info!("FPS history at 0x{:x}", fn_fps_history_address); - // FPS history patch - // Similar to the FPS patch, this sets the difference between the previous and current frames timestamps to the target frame delta. - // This gets stored in an array with 32 elements, possibly for calculating FPS averages. - unsafe extern "win64" fn fps_history(registers: *mut Registers, _:usize) - { - if FPS_HOOK_ENABLED - { - let ptr_flipper = (*registers).rbx as *const u8; // Flipper struct - Contains all the stuff we need - - let ptr_target_frame_delta = ptr_flipper.offset(0x1c) as *mut f32; // Target frame delta - Set in a switch/case at the start - let ptr_frame_delta_history = ptr_flipper.offset(((*registers).rcx as u32 * 8) as isize) as *mut u64; // Frame delta history - In an array of 32, with the index incrementing each frame - - // Read the target frame delta and calculate the frame delta timestamp - let target_frame_delta = std::ptr::read_volatile(ptr_target_frame_delta); - let target_frame_delta_history = (target_frame_delta * 10000000.0) as u64; - - // Write values back - std::ptr::write_volatile(ptr_frame_delta_history, target_frame_delta_history); - } - } - // Enable FPS history patch FPS_HISTORY_HOOK = Some(Hooker::new(fn_fps_history_address, HookType::JmpBack(fps_history), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); } @@ -163,4 +87,78 @@ pub extern "C" fn fps_patch_toggle() // Toggles FPS patch { FPS_HOOK_ENABLED = !FPS_HOOK_ENABLED; } +} + + +unsafe extern "win64" fn increment_igt(registers: *mut Registers, _:usize) +{ + let mut frame_delta = std::mem::transmute::((*registers).xmm0 as u32); + //convert to milliseconds + frame_delta = frame_delta * 1000f32; + frame_delta = frame_delta * 0.96f32; //scale to IGT + + //Rather than casting, like the game does, make the behavior explicit by flooring + let mut floored_frame_delta = frame_delta.floor(); + let remainder = frame_delta - floored_frame_delta; + IGT_BUFFER = IGT_BUFFER + remainder; + + if IGT_BUFFER > 1.0f32 + { + IGT_BUFFER = IGT_BUFFER - 1f32; + floored_frame_delta += 1f32; + } + + (*registers).xmm1 = std::mem::transmute::(floored_frame_delta) as u128; +} + +// FPS patch +// Sets the calculated frame delta to always be the target frame delta. +// It also sets the previous frames timestamp to be the current one minus the target frame delta. +// This makes it so the game always behaves as if it's running at the FPS limit, with slowdowns if the PC can't keep up. +// A second patch, "FPS history" below, is required in addition to this one to ensure accuracy. +unsafe extern "win64" fn fps(registers: *mut Registers, _:usize) +{ + if FPS_HOOK_ENABLED + { + let ptr_flipper = (*registers).rbx as *const u8; // Flipper struct - Contains all the stuff we need + + let ptr_target_frame_delta = ptr_flipper.offset(0x1c) as *mut f32; // Target frame delta - Set in a switch/case at the start + let ptr_timestamp_previous = ptr_flipper.offset(0x20) as *mut u64; // Previous frames timestamp + let ptr_timestamp_current = ptr_flipper.offset(0x28) as *mut u64; // Current frames timestamp + let ptr_frame_delta = ptr_flipper.offset(0x264) as *mut f32; // Current frames frame delta + + // Read target frame data, the current timestamp and then calculate the timestamp diff at stable FPS + let target_frame_delta = std::ptr::read_volatile(ptr_target_frame_delta); + let timestamp_current = std::ptr::read_volatile(ptr_timestamp_current); + let timestamp_diff = (target_frame_delta * 10000000.0) as i32; + + // Calculate the previous timestamp, as well as the frame delta + let timestamp_previous = timestamp_current - (timestamp_diff as u64); + let frame_delta = (timestamp_diff as f32) / 10000000.0; + + // Write values back + std::ptr::write_volatile(ptr_timestamp_previous, timestamp_previous); + std::ptr::write_volatile(ptr_frame_delta, frame_delta); + } +} + +// FPS history patch +// Similar to the FPS patch, this sets the difference between the previous and current frames timestamps to the target frame delta. +// This gets stored in an array with 32 elements, possibly for calculating FPS averages. +unsafe extern "win64" fn fps_history(registers: *mut Registers, _:usize) +{ + if FPS_HOOK_ENABLED + { + let ptr_flipper = (*registers).rbx as *const u8; // Flipper struct - Contains all the stuff we need + + let ptr_target_frame_delta = ptr_flipper.offset(0x1c) as *mut f32; // Target frame delta - Set in a switch/case at the start + let ptr_frame_delta_history = ptr_flipper.offset(((*registers).rcx as u32 * 8) as isize) as *mut u64; // Frame delta history - In an array of 32, with the index incrementing each frame + + // Read the target frame delta and calculate the frame delta timestamp + let target_frame_delta = std::ptr::read_volatile(ptr_target_frame_delta); + let target_frame_delta_history = (target_frame_delta * 10000000.0) as u64; + + // Write values back + std::ptr::write_volatile(ptr_frame_delta_history, target_frame_delta_history); + } } \ No newline at end of file From ea01696666084c3da746c74a2283298da5080022 Mon Sep 17 00:00:00 2001 From: Vinjul1704 Date: Mon, 26 Aug 2024 14:55:48 +0200 Subject: [PATCH 09/26] Remove leftover date var --- src/SoulSplitter/SoulComponent.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/SoulSplitter/SoulComponent.cs b/src/SoulSplitter/SoulComponent.cs index e92afb3f..1beda6b8 100644 --- a/src/SoulSplitter/SoulComponent.cs +++ b/src/SoulSplitter/SoulComponent.cs @@ -45,7 +45,6 @@ public class SoulComponent : IComponent private ISplitter _splitter = null; private IGame _game = null; private DateTime _lastFailedRefresh = DateTime.MinValue; - private DateTime _lastFpsToggle = DateTime.MinValue; // Remove after tests private bool _previousBitBlt = false; public readonly MainWindow MainWindow; public SoulComponent(LiveSplitState state = null, bool shouldThrowOnInvalidInstallation = true) From 2faef61edced0d6c90ccd0ab0a1f9992eada42e5 Mon Sep 17 00:00:00 2001 From: Vinjul1704 Date: Mon, 26 Aug 2024 16:34:04 +0200 Subject: [PATCH 10/26] Add version comparison and pre-/post-DLC check. --- src/soulmods/src/games/x64/eldenring.rs | 30 +++-- src/soulmods/src/util/version.rs | 157 ++++++++++++++++-------- 2 files changed, 129 insertions(+), 58 deletions(-) diff --git a/src/soulmods/src/games/x64/eldenring.rs b/src/soulmods/src/games/x64/eldenring.rs index a982b350..32504bd2 100644 --- a/src/soulmods/src/games/x64/eldenring.rs +++ b/src/soulmods/src/games/x64/eldenring.rs @@ -18,6 +18,7 @@ use ilhook::x64::{Hooker, HookType, Registers, CallbackOption, HookFlags, HookPo use mem_rs::prelude::*; use log::info; use crate::util::GLOBAL_VERSION; +use crate::util::Version; static mut IGT_BUFFER: f32 = 0.0f32; static mut IGT_HOOK: Option = None; @@ -46,19 +47,28 @@ pub fn init_eldenring() // Enable timer patch IGT_HOOK = Some(Hooker::new(fn_increment_igt_address, HookType::JmpBack(increment_igt), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); - // AoB scan for FPS patch - let fn_fps_address = process.scan_abs("fps", "8b 83 64 02 00 00 89 83 b4 02 00 00", 0, Vec::new()).unwrap().get_base_address(); - info!("FPS at 0x{:x}", fn_fps_address); + if (GLOBAL_VERSION > Version { major: 2, minor: 0, build: 1, revision: 0 }) + { + info!("Post-DLC version detected."); - // Enable FPS patch - FPS_HOOK = Some(Hooker::new(fn_fps_address, HookType::JmpBack(fps), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); + // AoB scan for FPS patch + let fn_fps_address = process.scan_abs("fps", "8b 83 64 02 00 00 89 83 b4 02 00 00", 0, Vec::new()).unwrap().get_base_address(); + info!("FPS at 0x{:x}", fn_fps_address); - // AoB scan for FPS history patch - let fn_fps_history_address = process.scan_abs("fps history", "48 89 04 cb 0f b6 83 74 02 00 00", 0, Vec::new()).unwrap().get_base_address(); - info!("FPS history at 0x{:x}", fn_fps_history_address); + // Enable FPS patch + FPS_HOOK = Some(Hooker::new(fn_fps_address, HookType::JmpBack(fps), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); - // Enable FPS history patch - FPS_HISTORY_HOOK = Some(Hooker::new(fn_fps_history_address, HookType::JmpBack(fps_history), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); + // AoB scan for FPS history patch + let fn_fps_history_address = process.scan_abs("fps history", "48 89 04 cb 0f b6 83 74 02 00 00", 0, Vec::new()).unwrap().get_base_address(); + info!("FPS history at 0x{:x}", fn_fps_history_address); + + // Enable FPS history patch + FPS_HISTORY_HOOK = Some(Hooker::new(fn_fps_history_address, HookType::JmpBack(fps_history), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); + } + else + { + info!("Pre-DLC version detected."); + } } } diff --git a/src/soulmods/src/util/version.rs b/src/soulmods/src/util/version.rs index 14073c2e..6acd9a44 100644 --- a/src/soulmods/src/util/version.rs +++ b/src/soulmods/src/util/version.rs @@ -2,9 +2,11 @@ use std::ffi::c_void; use std::fmt::{Display, Formatter}; use std::mem::MaybeUninit; use std::path::PathBuf; +use std::cmp::Ordering; use windows::core::PCWSTR; use windows::Win32::Storage::FileSystem::{GET_FILE_VERSION_INFO_FLAGS, GetFileVersionInfoExW, GetFileVersionInfoSizeW, VerQueryValueW, VS_FIXEDFILEINFO}; + pub struct Version { pub major: u16, @@ -33,55 +35,114 @@ impl Version pub fn from_file_version_info(path: PathBuf) -> Self { unsafe + { + let mut os_str = path.into_os_string(); + os_str.push("\0"); + + let str = os_str.to_string_lossy(); + + let mut thing: Vec = str.encode_utf16().collect(); + let pcwstr = PCWSTR::from_raw(thing.as_mut_ptr()); + + let mut dwlen: u32 = 0; + let file_version_info_size = GetFileVersionInfoSizeW(pcwstr, Some(&mut dwlen)); + let mut buffer: Vec = vec![0; file_version_info_size as usize]; + + let get_file_version_info_result = GetFileVersionInfoExW( + GET_FILE_VERSION_INFO_FLAGS(0x02), + pcwstr, + 0, + file_version_info_size, + buffer.as_mut_ptr() as *mut c_void + ); + + if get_file_version_info_result.is_err() + { + return Version::default(); + } + + let mut pu_len = 0; + let mut info_ptr = MaybeUninit::<*const VS_FIXEDFILEINFO>::uninit(); + + let ver_query_value_w_result = VerQueryValueW( + buffer.as_mut_ptr() as *const c_void, + windows::core::w!("\\"), + info_ptr.as_mut_ptr().cast(), + &mut pu_len + ); + + if ver_query_value_w_result.0 == 0 { - let mut os_str = path.into_os_string(); - os_str.push("\0"); - - let str = os_str.to_string_lossy(); - - let mut thing: Vec = str.encode_utf16().collect(); - let pcwstr = PCWSTR::from_raw(thing.as_mut_ptr()); - - let mut dwlen: u32 = 0; - let file_version_info_size = GetFileVersionInfoSizeW(pcwstr, Some(&mut dwlen)); - let mut buffer: Vec = vec![0; file_version_info_size as usize]; - - let get_file_version_info_result = GetFileVersionInfoExW( - GET_FILE_VERSION_INFO_FLAGS(0x02), - pcwstr, - 0, - file_version_info_size, - buffer.as_mut_ptr() as *mut c_void - ); - - if get_file_version_info_result.is_err() - { - return Version::default(); - } - - let mut pu_len = 0; - let mut info_ptr = MaybeUninit::<*const VS_FIXEDFILEINFO>::uninit(); - - let ver_query_value_w_result = VerQueryValueW( - buffer.as_mut_ptr() as *const c_void, - windows::core::w!("\\"), - info_ptr.as_mut_ptr().cast(), - &mut pu_len - ); - - if ver_query_value_w_result.0 == 0 - { - return Version::default(); - } - - let fixed_file_info = *(info_ptr.assume_init()); - - Version{ - major: (fixed_file_info.dwFileVersionMS >> 16) as u16, - minor: fixed_file_info.dwFileVersionMS as u16, - build: (fixed_file_info.dwFileVersionLS >> 16) as u16, - revision: fixed_file_info.dwFileVersionLS as u16 - } + return Version::default(); + } + + let fixed_file_info = *(info_ptr.assume_init()); + + Version{ + major: (fixed_file_info.dwFileVersionMS >> 16) as u16, + minor: fixed_file_info.dwFileVersionMS as u16, + build: (fixed_file_info.dwFileVersionLS >> 16) as u16, + revision: fixed_file_info.dwFileVersionLS as u16 } + } } } + +impl PartialEq for Version +{ + fn eq(&self, other: &Self) -> bool + { + if (self.major == other.major && self.minor == other.minor && self.build == other.build && self.revision == other.revision) + { + return true; + } + else + { + return false; + } + } +} + +impl PartialOrd for Version +{ + fn partial_cmp(&self, other: &Self) -> Option + { + if self.major > other.major + { + return Some(Ordering::Greater); + } + else if self.major < other.major + { + return Some(Ordering::Less); + } + + if self.minor > other.minor + { + return Some(Ordering::Greater); + } + else if self.minor < other.minor + { + return Some(Ordering::Less); + } + + if self.build > other.build + { + return Some(Ordering::Greater); + } + else if self.build < other.build + { + return Some(Ordering::Less); + } + + if self.revision > other.revision + { + return Some(Ordering::Greater); + } + else if self.revision < other.revision + { + return Some(Ordering::Less); + } + + return Some(Ordering::Equal); + } +} \ No newline at end of file From 8e4bbb8f660d336a6721c373b8c9f69caa4fe959 Mon Sep 17 00:00:00 2001 From: Vinjul1704 Date: Mon, 26 Aug 2024 17:42:15 +0200 Subject: [PATCH 11/26] Fix warning in version.rs, implement FPS custom limit patch and fully implement pre-/post-DLC patches --- src/soulmods/src/games/x64/eldenring.rs | 118 ++++++++++++++++++++---- src/soulmods/src/util/version.rs | 2 +- 2 files changed, 101 insertions(+), 19 deletions(-) diff --git a/src/soulmods/src/games/x64/eldenring.rs b/src/soulmods/src/games/x64/eldenring.rs index 32504bd2..5697b463 100644 --- a/src/soulmods/src/games/x64/eldenring.rs +++ b/src/soulmods/src/games/x64/eldenring.rs @@ -20,13 +20,32 @@ use log::info; use crate::util::GLOBAL_VERSION; use crate::util::Version; +struct FpsOffsets +{ + target_frame_delta: isize, + frame_delta: isize, + timestamp_previous: isize, + timestamp_current: isize, + timestamp_history: u32, +} + static mut IGT_BUFFER: f32 = 0.0f32; static mut IGT_HOOK: Option = None; static mut FPS_HOOK: Option = None; static mut FPS_HISTORY_HOOK: Option = None; +static mut FPS_CUSTOM_LIMIT_HOOK: Option = None; static mut FPS_HOOK_ENABLED: bool = false; +static mut FPS_CUSTOM_LIMIT: f32 = 0.0f32; + +static mut FPS_OFFSETS: FpsOffsets = FpsOffsets { + target_frame_delta: 0x0, + frame_delta: 0x0, + timestamp_previous: 0x0, + timestamp_current: 0x0, + timestamp_history: 0, +}; #[allow(unused_assignments)] @@ -47,28 +66,66 @@ pub fn init_eldenring() // Enable timer patch IGT_HOOK = Some(Hooker::new(fn_increment_igt_address, HookType::JmpBack(increment_igt), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); + // AoBs for FPS patches + let mut fps_aob = ""; + let mut fps_history_aob = ""; + let mut fps_custom_limit_aob = ""; + + // Adjust AoBs and offsets for FPS patch based on version + // The relevant function was adjusted slightly with the release of the DLC if (GLOBAL_VERSION > Version { major: 2, minor: 0, build: 1, revision: 0 }) { info!("Post-DLC version detected."); - // AoB scan for FPS patch - let fn_fps_address = process.scan_abs("fps", "8b 83 64 02 00 00 89 83 b4 02 00 00", 0, Vec::new()).unwrap().get_base_address(); - info!("FPS at 0x{:x}", fn_fps_address); - - // Enable FPS patch - FPS_HOOK = Some(Hooker::new(fn_fps_address, HookType::JmpBack(fps), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); - - // AoB scan for FPS history patch - let fn_fps_history_address = process.scan_abs("fps history", "48 89 04 cb 0f b6 83 74 02 00 00", 0, Vec::new()).unwrap().get_base_address(); - info!("FPS history at 0x{:x}", fn_fps_history_address); + FPS_OFFSETS = FpsOffsets { + target_frame_delta: 0x1c, + frame_delta: 0x264, + timestamp_previous: 0x20, + timestamp_current: 0x28, + timestamp_history: 0, + }; - // Enable FPS history patch - FPS_HISTORY_HOOK = Some(Hooker::new(fn_fps_history_address, HookType::JmpBack(fps_history), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); + fps_aob = "8b 83 64 02 00 00 89 83 b4 02 00 00"; + fps_history_aob = "48 89 04 cb 0f b6 83 74 02 00 00"; + fps_custom_limit_aob = "0F 57 F6 44 38 BB D0 02 00 00"; } else { info!("Pre-DLC version detected."); + + FPS_OFFSETS = FpsOffsets { + target_frame_delta: 0x20, + frame_delta: 0x26c, + timestamp_previous: 0x28, + timestamp_current: 0x30, + timestamp_history: 68, + }; + + fps_aob = "8b 83 6c 02 00 00 89 83 bc 02 00 00"; + fps_history_aob = "48 89 44 cb 68 0f b6 83 7c 02 00 00"; + fps_custom_limit_aob = "0F 57 F6 44 38 BB D8 02 00 00"; } + + // AoB scan for FPS patch + let fn_fps_address = process.scan_abs("fps", fps_aob, 0, Vec::new()).unwrap().get_base_address(); + info!("FPS at 0x{:x}", fn_fps_address); + + // Enable FPS patch + FPS_HOOK = Some(Hooker::new(fn_fps_address, HookType::JmpBack(fps), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); + + // AoB scan for FPS history patch + let fn_fps_history_address = process.scan_abs("fps history", fps_history_aob, 0, Vec::new()).unwrap().get_base_address(); + info!("FPS history at 0x{:x}", fn_fps_history_address); + + // Enable FPS history patch + FPS_HISTORY_HOOK = Some(Hooker::new(fn_fps_history_address, HookType::JmpBack(fps_history), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); + + // AoB scan for FPS custom limit patch + let fn_fps_custom_limit_address = process.scan_abs("fps custom limit", fps_custom_limit_aob, 0, Vec::new()).unwrap().get_base_address(); + info!("FPS custom limit at 0x{:x}", fn_fps_custom_limit_address); + + // Enable FPS custom limit patch + FPS_CUSTOM_LIMIT_HOOK = Some(Hooker::new(fn_fps_custom_limit_address, HookType::JmpBack(fps_custom_limit), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); } } @@ -132,10 +189,10 @@ unsafe extern "win64" fn fps(registers: *mut Registers, _:usize) { let ptr_flipper = (*registers).rbx as *const u8; // Flipper struct - Contains all the stuff we need - let ptr_target_frame_delta = ptr_flipper.offset(0x1c) as *mut f32; // Target frame delta - Set in a switch/case at the start - let ptr_timestamp_previous = ptr_flipper.offset(0x20) as *mut u64; // Previous frames timestamp - let ptr_timestamp_current = ptr_flipper.offset(0x28) as *mut u64; // Current frames timestamp - let ptr_frame_delta = ptr_flipper.offset(0x264) as *mut f32; // Current frames frame delta + let ptr_target_frame_delta = ptr_flipper.offset(FPS_OFFSETS.target_frame_delta) as *mut f32; // Target frame delta - Set in a switch/case at the start + let ptr_timestamp_previous = ptr_flipper.offset(FPS_OFFSETS.timestamp_previous) as *mut u64; // Previous frames timestamp + let ptr_timestamp_current = ptr_flipper.offset(FPS_OFFSETS.timestamp_current) as *mut u64; // Current frames timestamp + let ptr_frame_delta = ptr_flipper.offset(FPS_OFFSETS.frame_delta) as *mut f32; // Current frames frame delta // Read target frame data, the current timestamp and then calculate the timestamp diff at stable FPS let target_frame_delta = std::ptr::read_volatile(ptr_target_frame_delta); @@ -161,8 +218,8 @@ unsafe extern "win64" fn fps_history(registers: *mut Registers, _:usize) { let ptr_flipper = (*registers).rbx as *const u8; // Flipper struct - Contains all the stuff we need - let ptr_target_frame_delta = ptr_flipper.offset(0x1c) as *mut f32; // Target frame delta - Set in a switch/case at the start - let ptr_frame_delta_history = ptr_flipper.offset(((*registers).rcx as u32 * 8) as isize) as *mut u64; // Frame delta history - In an array of 32, with the index incrementing each frame + let ptr_target_frame_delta = ptr_flipper.offset(FPS_OFFSETS.target_frame_delta) as *mut f32; // Target frame delta - Set in a switch/case at the start + let ptr_frame_delta_history = ptr_flipper.offset(((*registers).rcx as u32 * 8 + FPS_OFFSETS.timestamp_history) as isize) as *mut u64; // Frame delta history - In an array of 32, with the index incrementing each frame // Read the target frame delta and calculate the frame delta timestamp let target_frame_delta = std::ptr::read_volatile(ptr_target_frame_delta); @@ -171,4 +228,29 @@ unsafe extern "win64" fn fps_history(registers: *mut Registers, _:usize) // Write values back std::ptr::write_volatile(ptr_frame_delta_history, target_frame_delta_history); } +} + +// FPS custom limit patch +// This patch adjusts the target frame delta based on a custom set FPS limit. +// It is only active while the FPS patch is enabled too, and uses the default value if it's set to 0 or less. +// This does not allow you to go above the stock FPS limit. It is purely a QoL patch to improve glitch consistency, not an FPS unlocker. +unsafe extern "win64" fn fps_custom_limit(registers: *mut Registers, _:usize) +{ + if FPS_HOOK_ENABLED && FPS_CUSTOM_LIMIT > 0.0f32 + { + let ptr_flipper = (*registers).rbx as *const u8; // Flipper struct - Contains all the stuff we need + + let ptr_target_frame_delta = ptr_flipper.offset(FPS_OFFSETS.target_frame_delta) as *mut f32; // Target frame delta - Set in a switch/case at the start + + // Read the stock target frame delta and calculate the custom target frame delta + let target_frame_delta = std::ptr::read_volatile(ptr_target_frame_delta); + let custom_target_frame_delta = 1.0f32 / FPS_CUSTOM_LIMIT; + + // Make sure the custom target frame delta is higher than the stock one, in order to avoid going above the stock FPS limit + if custom_target_frame_delta > target_frame_delta + { + // Write values back + std::ptr::write_volatile(ptr_target_frame_delta, custom_target_frame_delta); + } + } } \ No newline at end of file diff --git a/src/soulmods/src/util/version.rs b/src/soulmods/src/util/version.rs index 6acd9a44..3ddf01fb 100644 --- a/src/soulmods/src/util/version.rs +++ b/src/soulmods/src/util/version.rs @@ -92,7 +92,7 @@ impl PartialEq for Version { fn eq(&self, other: &Self) -> bool { - if (self.major == other.major && self.minor == other.minor && self.build == other.build && self.revision == other.revision) + if self.major == other.major && self.minor == other.minor && self.build == other.build && self.revision == other.revision { return true; } From d0ded190bffbd88ce8d9045d8d8988e98be187e4 Mon Sep 17 00:00:00 2001 From: Vinjul1704 Date: Mon, 26 Aug 2024 19:09:23 +0200 Subject: [PATCH 12/26] Fix frame delta history offsets. --- src/soulmods/src/games/x64/eldenring.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/soulmods/src/games/x64/eldenring.rs b/src/soulmods/src/games/x64/eldenring.rs index 5697b463..a298b0a7 100644 --- a/src/soulmods/src/games/x64/eldenring.rs +++ b/src/soulmods/src/games/x64/eldenring.rs @@ -26,7 +26,7 @@ struct FpsOffsets frame_delta: isize, timestamp_previous: isize, timestamp_current: isize, - timestamp_history: u32, + timestamp_history: isize, } static mut IGT_BUFFER: f32 = 0.0f32; @@ -44,7 +44,7 @@ static mut FPS_OFFSETS: FpsOffsets = FpsOffsets { frame_delta: 0x0, timestamp_previous: 0x0, timestamp_current: 0x0, - timestamp_history: 0, + timestamp_history: 0x0, }; @@ -82,7 +82,7 @@ pub fn init_eldenring() frame_delta: 0x264, timestamp_previous: 0x20, timestamp_current: 0x28, - timestamp_history: 0, + timestamp_history: 0x0, }; fps_aob = "8b 83 64 02 00 00 89 83 b4 02 00 00"; @@ -98,7 +98,7 @@ pub fn init_eldenring() frame_delta: 0x26c, timestamp_previous: 0x28, timestamp_current: 0x30, - timestamp_history: 68, + timestamp_history: 0x68, }; fps_aob = "8b 83 6c 02 00 00 89 83 bc 02 00 00"; @@ -219,7 +219,7 @@ unsafe extern "win64" fn fps_history(registers: *mut Registers, _:usize) let ptr_flipper = (*registers).rbx as *const u8; // Flipper struct - Contains all the stuff we need let ptr_target_frame_delta = ptr_flipper.offset(FPS_OFFSETS.target_frame_delta) as *mut f32; // Target frame delta - Set in a switch/case at the start - let ptr_frame_delta_history = ptr_flipper.offset(((*registers).rcx as u32 * 8 + FPS_OFFSETS.timestamp_history) as isize) as *mut u64; // Frame delta history - In an array of 32, with the index incrementing each frame + let ptr_frame_delta_history = ptr_flipper.offset((*registers).rcx as isize * 0x8 + FPS_OFFSETS.timestamp_history) as *mut u64; // Frame delta history - In an array of 32, with the index incrementing each frame // Read the target frame delta and calculate the frame delta timestamp let target_frame_delta = std::ptr::read_volatile(ptr_target_frame_delta); From 671fc73b6a48b4079e64e764850560b82fd9442f Mon Sep 17 00:00:00 2001 From: Vinjul1704 Date: Mon, 26 Aug 2024 22:04:03 +0200 Subject: [PATCH 13/26] Add basic FPS patch toggle to UI. Needs improvement. --- .../Splitters/EldenRingSplitter.cs | 9 ++++++++ .../UI/EldenRing/EldenRingControl.xaml | 22 ++++++++++++++----- .../UI/EldenRing/EldenRingViewModel.cs | 7 ++++++ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/SoulSplitter/Splitters/EldenRingSplitter.cs b/src/SoulSplitter/Splitters/EldenRingSplitter.cs index ce0524b1..17176bb7 100644 --- a/src/SoulSplitter/Splitters/EldenRingSplitter.cs +++ b/src/SoulSplitter/Splitters/EldenRingSplitter.cs @@ -178,6 +178,15 @@ public void UpdateTimer(bool startAutomatically) _startAutomatically = startAutomatically; } + if (_eldenRingViewModel.FpsPatch) + { + _eldenRing.FpsPatchEnable(); + } + else + { + _eldenRing.FpsPatchDisable(); + } + switch (_timerState) { case TimerState.WaitForStart: diff --git a/src/SoulSplitter/UI/EldenRing/EldenRingControl.xaml b/src/SoulSplitter/UI/EldenRing/EldenRingControl.xaml index a1e16d55..de64aeba 100644 --- a/src/SoulSplitter/UI/EldenRing/EldenRingControl.xaml +++ b/src/SoulSplitter/UI/EldenRing/EldenRingControl.xaml @@ -80,12 +80,13 @@ 0 - 1 - 2 - 3 - 4 - 5 - 6 + 1 + 2 + 3 + 4 + 5 + 6 + 7 @@ -100,6 +101,7 @@ + @@ -116,6 +118,14 @@ + + + + _fpsPatch; + set => SetField(ref _fpsPatch, value); + } + private bool _fpsPatch = false; + public bool LockIgtToZero { get => _lockIgtToZero; From 79d2e73015f8a202ba81b79f7aecdf3866e3efdc Mon Sep 17 00:00:00 2001 From: Vinjul1704 Date: Mon, 26 Aug 2024 23:28:00 +0200 Subject: [PATCH 14/26] Fix FPS history patch AoB --- src/soulmods/src/games/x64/eldenring.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/soulmods/src/games/x64/eldenring.rs b/src/soulmods/src/games/x64/eldenring.rs index a298b0a7..67e3ec24 100644 --- a/src/soulmods/src/games/x64/eldenring.rs +++ b/src/soulmods/src/games/x64/eldenring.rs @@ -86,7 +86,7 @@ pub fn init_eldenring() }; fps_aob = "8b 83 64 02 00 00 89 83 b4 02 00 00"; - fps_history_aob = "48 89 04 cb 0f b6 83 74 02 00 00"; + fps_history_aob = "0f b6 83 74 02 00 00 89 44 cb 08"; fps_custom_limit_aob = "0F 57 F6 44 38 BB D0 02 00 00"; } else @@ -102,7 +102,7 @@ pub fn init_eldenring() }; fps_aob = "8b 83 6c 02 00 00 89 83 bc 02 00 00"; - fps_history_aob = "48 89 44 cb 68 0f b6 83 7c 02 00 00"; + fps_history_aob = "0f b6 83 7c 02 00 00 89 44 cb 70"; fps_custom_limit_aob = "0F 57 F6 44 38 BB D8 02 00 00"; } From 7afc9e06b0ef9e657963de60dd23c62caaa436a6 Mon Sep 17 00:00:00 2001 From: Vinjul1704 Date: Tue, 27 Aug 2024 21:53:08 +0200 Subject: [PATCH 15/26] Replace FPS patch enable/disable/toggle functions with get/set functions --- src/SoulMemory/EldenRing/EldenRing.cs | 26 +++++++++---------- .../Splitters/EldenRingSplitter.cs | 9 +------ src/soulmods/src/games/x64/eldenring.rs | 17 +++--------- 3 files changed, 18 insertions(+), 34 deletions(-) diff --git a/src/SoulMemory/EldenRing/EldenRing.cs b/src/SoulMemory/EldenRing/EldenRing.cs index 08ba6188..f8cfb4a3 100644 --- a/src/SoulMemory/EldenRing/EldenRing.cs +++ b/src/SoulMemory/EldenRing/EldenRing.cs @@ -582,23 +582,23 @@ public void WriteInGameTimeMilliseconds(int milliseconds) #region soulmods - public void FpsPatchDisable() + public bool FpsPatchGet() { - var address = _exportedFunctions["fps_patch_disable"]; - _process.Execute((IntPtr)address); + var address = _exportedFunctions["fps_patch_get"]; + var bPtr = _process.Allocate(1); + _process.Execute((IntPtr)address, bPtr); + var b = _process.ReadMemory(bPtr.ToInt64()).Unwrap(); + _process.Free(bPtr); + return b; } - public void FpsPatchEnable() + public void FpsPatchSet(bool b) { - var address = _exportedFunctions["fps_patch_enable"]; - _process.Execute((IntPtr)address); - } - - public void FpsPatchToggle() - { - var address = _exportedFunctions["fps_patch_toggle"]; - var ptr = (IntPtr)address; - _process.Execute((IntPtr)address); + var address = _exportedFunctions["fps_patch_set"]; + var bPtr = _process.Allocate(1); + _process.WriteProcessMemory(bPtr.ToInt64(), BitConverter.GetBytes(b)); + _process.Execute((IntPtr)address, bPtr); + _process.Free(bPtr); } #endregion diff --git a/src/SoulSplitter/Splitters/EldenRingSplitter.cs b/src/SoulSplitter/Splitters/EldenRingSplitter.cs index 17176bb7..e68a272e 100644 --- a/src/SoulSplitter/Splitters/EldenRingSplitter.cs +++ b/src/SoulSplitter/Splitters/EldenRingSplitter.cs @@ -178,14 +178,7 @@ public void UpdateTimer(bool startAutomatically) _startAutomatically = startAutomatically; } - if (_eldenRingViewModel.FpsPatch) - { - _eldenRing.FpsPatchEnable(); - } - else - { - _eldenRing.FpsPatchDisable(); - } + _eldenRing.FpsPatchSet(_eldenRingViewModel.FpsPatch); switch (_timerState) { diff --git a/src/soulmods/src/games/x64/eldenring.rs b/src/soulmods/src/games/x64/eldenring.rs index 67e3ec24..5683c4f6 100644 --- a/src/soulmods/src/games/x64/eldenring.rs +++ b/src/soulmods/src/games/x64/eldenring.rs @@ -130,29 +130,20 @@ pub fn init_eldenring() } #[no_mangle] -pub extern "C" fn fps_patch_disable() // Disables FPS patch +pub extern "C" fn fps_patch_get(b: &mut bool) // Get FPS patch status { unsafe { - FPS_HOOK_ENABLED = false; + *b = FPS_HOOK_ENABLED; } } #[no_mangle] -pub extern "C" fn fps_patch_enable() // Enables FPS patch +pub extern "C" fn fps_patch_set(b: &bool) // Set FPS patch status { unsafe { - FPS_HOOK_ENABLED = true; - } -} - -#[no_mangle] -pub extern "C" fn fps_patch_toggle() // Toggles FPS patch -{ - unsafe - { - FPS_HOOK_ENABLED = !FPS_HOOK_ENABLED; + FPS_HOOK_ENABLED = *b; } } From 2d462ce0e370a7a2ce74a0f93088fb821d03d437 Mon Sep 17 00:00:00 2001 From: Vinjul1704 Date: Tue, 27 Aug 2024 23:01:44 +0200 Subject: [PATCH 16/26] Add FPS limit get/set functions. --- src/SoulMemory/EldenRing/EldenRing.cs | 19 +++++++++++++++++++ src/soulmods/src/games/x64/eldenring.rs | 18 ++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/SoulMemory/EldenRing/EldenRing.cs b/src/SoulMemory/EldenRing/EldenRing.cs index f8cfb4a3..2ed51b1f 100644 --- a/src/SoulMemory/EldenRing/EldenRing.cs +++ b/src/SoulMemory/EldenRing/EldenRing.cs @@ -601,6 +601,25 @@ public void FpsPatchSet(bool b) _process.Free(bPtr); } + public float FpsLimitGet() + { + var address = _exportedFunctions["fps_limit_get"]; + var fPtr = _process.Allocate(4); + _process.Execute((IntPtr)address, fPtr); + var f = _process.ReadMemory(fPtr.ToInt64()).Unwrap(); + _process.Free(fPtr); + return f; + } + + public void FpsLimitSet(float f) + { + var address = _exportedFunctions["fps_limit_set"]; + var fPtr = _process.Allocate(4); + _process.WriteProcessMemory(fPtr.ToInt64(), BitConverter.GetBytes(f)); + _process.Execute((IntPtr)address, fPtr); + _process.Free(fPtr); + } + #endregion } } diff --git a/src/soulmods/src/games/x64/eldenring.rs b/src/soulmods/src/games/x64/eldenring.rs index 5683c4f6..062e0479 100644 --- a/src/soulmods/src/games/x64/eldenring.rs +++ b/src/soulmods/src/games/x64/eldenring.rs @@ -147,6 +147,24 @@ pub extern "C" fn fps_patch_set(b: &bool) // Set FPS patch status } } +#[no_mangle] +pub extern "C" fn fps_limit_get(f: &mut f32) // Get FPS custom limit +{ + unsafe + { + *f = FPS_CUSTOM_LIMIT; + } +} + +#[no_mangle] +pub extern "C" fn fps_limit_set(f: &f32) // Set FPS custom limit +{ + unsafe + { + FPS_CUSTOM_LIMIT = *f; + } +} + unsafe extern "win64" fn increment_igt(registers: *mut Registers, _:usize) { From 67a16fa45749bed8b2e9cec6f615eea5c923ebe2 Mon Sep 17 00:00:00 2001 From: Vinjul1704 Date: Tue, 27 Aug 2024 23:08:17 +0200 Subject: [PATCH 17/26] Fix FPS patch hotkey in CLI, now that the functions are different. --- src/cli/Program.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cli/Program.cs b/src/cli/Program.cs index 813f1128..bfcaf578 100644 --- a/src/cli/Program.cs +++ b/src/cli/Program.cs @@ -52,7 +52,11 @@ static void Main(string[] args) { if (init) { - GlobalHotKey.RegisterHotKey(ModifierKeys.Alt, Key.A, e.FpsPatchToggle); + GlobalHotKey.RegisterHotKey(ModifierKeys.Alt, Key.A, () => + { + var fpsPatchState = e.FpsPatchGet(); + e.FpsPatchSet(!fpsPatchState); + }); init = false; } From 27df1e645f0efbf75c75e8793813feb3f1e6c844 Mon Sep 17 00:00:00 2001 From: Vinjul1704 Date: Sat, 31 Aug 2024 14:32:50 +0200 Subject: [PATCH 18/26] Test stuff and hotkeys, minor fix in eldenring.rs, increase rust function call timeout to 10 seconds. --- src/SoulMemory/EldenRing/EldenRing.cs | 4 + src/SoulMemory/Native/Kernel32.cs | 2 +- .../Splitters/EldenRingSplitter.cs | 138 +++++++++++++++++- src/soulmods/src/games/x64/eldenring.rs | 10 +- 4 files changed, 146 insertions(+), 8 deletions(-) diff --git a/src/SoulMemory/EldenRing/EldenRing.cs b/src/SoulMemory/EldenRing/EldenRing.cs index 2ed51b1f..605af65c 100644 --- a/src/SoulMemory/EldenRing/EldenRing.cs +++ b/src/SoulMemory/EldenRing/EldenRing.cs @@ -18,6 +18,8 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using SoulMemory.Memory; using SoulMemory.Native; using Pointer = SoulMemory.Memory.Pointer; @@ -153,6 +155,8 @@ private ResultErr InitPointers() ApplyNoLogo(); + // Thread.Sleep(15 * 1000); // Delay soulmods injection to work around crashes. TODO: Fix the crashes in some other way. + if (!soulmods.Soulmods.Inject(_process)) { _igt.Clear(); diff --git a/src/SoulMemory/Native/Kernel32.cs b/src/SoulMemory/Native/Kernel32.cs index 40424752..9807b2d1 100644 --- a/src/SoulMemory/Native/Kernel32.cs +++ b/src/SoulMemory/Native/Kernel32.cs @@ -218,7 +218,7 @@ public static void Execute(this Process process, IntPtr startAddress, IntPtr? pa { process.NtSuspendProcess(); IntPtr thread = NativeMethods.CreateRemoteThread(process.Handle, IntPtr.Zero, 0, startAddress, parameter ?? IntPtr.Zero, 0, IntPtr.Zero); - NativeMethods.WaitForSingleObject(thread, 5000); + NativeMethods.WaitForSingleObject(thread, 10000); // set back to 5000 process.NtResumeProcess(); NativeMethods.CloseHandle(thread); } diff --git a/src/SoulSplitter/Splitters/EldenRingSplitter.cs b/src/SoulSplitter/Splitters/EldenRingSplitter.cs index e68a272e..e2952a41 100644 --- a/src/SoulSplitter/Splitters/EldenRingSplitter.cs +++ b/src/SoulSplitter/Splitters/EldenRingSplitter.cs @@ -24,6 +24,9 @@ using SoulSplitter.UI; using SoulSplitter.UI.EldenRing; using SoulSplitter.UI.Generic; +using SoulSplitter.Hotkeys; +using System.Windows.Input; +using System.Windows.Automation.Provider; namespace SoulSplitter.Splitters { @@ -170,16 +173,147 @@ private void ResetTimer() } + bool init = true; // TODO: Remove when UI hotkeys are implemented + // bool lastFpsPatchState = false; // TODO: Remove when mutex is implemented + bool test = false; public void UpdateTimer(bool startAutomatically) { + // Hardcoded hotkeys. TODO: Remove when UI hotkeys are implemented + if (init) + { + /* + // Danflesh + GlobalHotKey.RegisterHotKey(ModifierKeys.None, Key.Divide, () => + { + _eldenRingViewModel.FpsPatch = false; + }); + GlobalHotKey.RegisterHotKey(ModifierKeys.None, Key.Add, () => + { + if (_eldenRing.FpsLimitGet() == 60.0f && _eldenRingViewModel.FpsPatch) + { + _eldenRingViewModel.FpsPatch = false; + } + else + { + _eldenRing.FpsLimitSet(60.0f); + _eldenRingViewModel.FpsPatch = true; + } + }); + GlobalHotKey.RegisterHotKey(ModifierKeys.None, Key.Subtract, () => + { + if (_eldenRing.FpsLimitGet() == 36.1f && _eldenRingViewModel.FpsPatch) + { + _eldenRingViewModel.FpsPatch = false; + } + else + { + _eldenRing.FpsLimitSet(36.1f); + _eldenRingViewModel.FpsPatch = true; + } + }); + GlobalHotKey.RegisterHotKey(ModifierKeys.None, Key.Multiply, () => + { + if (_eldenRing.FpsLimitGet() == 34.0f && _eldenRingViewModel.FpsPatch) + { + _eldenRingViewModel.FpsPatch = false; + } + else + { + _eldenRing.FpsLimitSet(34.0f); + _eldenRingViewModel.FpsPatch = true; + } + }); + */ + + /* + // Regole + GlobalHotKey.RegisterHotKey(ModifierKeys.None, Key.OemBackslash, () => + { + if (_eldenRing.FpsLimitGet() == 36.1f && _eldenRingViewModel.FpsPatch) + { + _eldenRingViewModel.FpsPatch = false; + } + else + { + _eldenRing.FpsLimitSet(36.1f); + _eldenRingViewModel.FpsPatch = true; + } + }); + */ + + /* + // Pennek + GlobalHotKey.RegisterHotKey(ModifierKeys.None, Key.OemOpenBrackets, () => + { + if (_eldenRing.FpsLimitGet() == 57.0f && _eldenRingViewModel.FpsPatch) + { + _eldenRingViewModel.FpsPatch = false; + } + else + { + _eldenRing.FpsLimitSet(57.0f); + _eldenRingViewModel.FpsPatch = true; + } + }); + GlobalHotKey.RegisterHotKey(ModifierKeys.None, Key.OemCloseBrackets, () => + { + if (_eldenRing.FpsLimitGet() == 0.0f && _eldenRingViewModel.FpsPatch) + { + _eldenRingViewModel.FpsPatch = false; + } + else + { + _eldenRing.FpsLimitSet(0.0f); + _eldenRingViewModel.FpsPatch = true; + } + }); + GlobalHotKey.RegisterHotKey(ModifierKeys.None, Key.OemBackslash, () => + { + _eldenRingViewModel.FpsPatch = false; + }); + */ + GlobalHotKey.RegisterHotKey(ModifierKeys.None, Key.F2, () => + { + _eldenRing.FpsPatchSet(true); + }); + GlobalHotKey.RegisterHotKey(ModifierKeys.None, Key.F3, () => + { + _eldenRing.FpsPatchSet(false); + }); + GlobalHotKey.RegisterHotKey(ModifierKeys.None, Key.F4, () => + { + test = !test; + }); + init = false; + } + + + // _eldenRing.FpsPatchSet(false); + // _eldenRing.FpsPatchGet(); + + /* + if (lastFpsPatchState != _eldenRingViewModel.FpsPatch) + { + lastFpsPatchState = _eldenRingViewModel.FpsPatch; + _eldenRing.FpsPatchSet(_eldenRingViewModel.FpsPatch); + } + */ + + + if (test) + { + bool currentStatus = _eldenRing.FpsPatchGet(); + _eldenRing.FpsPatchSet(!currentStatus); + } + + + //Allow updates from the UI only when a run isn't in progress if (_timerState == TimerState.WaitForStart) { _startAutomatically = startAutomatically; } - _eldenRing.FpsPatchSet(_eldenRingViewModel.FpsPatch); - switch (_timerState) { case TimerState.WaitForStart: diff --git a/src/soulmods/src/games/x64/eldenring.rs b/src/soulmods/src/games/x64/eldenring.rs index 062e0479..f0be8a01 100644 --- a/src/soulmods/src/games/x64/eldenring.rs +++ b/src/soulmods/src/games/x64/eldenring.rs @@ -37,7 +37,7 @@ static mut FPS_HISTORY_HOOK: Option = None; static mut FPS_CUSTOM_LIMIT_HOOK: Option = None; static mut FPS_HOOK_ENABLED: bool = false; -static mut FPS_CUSTOM_LIMIT: f32 = 0.0f32; +static mut FPS_CUSTOM_LIMIT: f32 = 30.0f32; // Reset back to 0 after tests static mut FPS_OFFSETS: FpsOffsets = FpsOffsets { target_frame_delta: 0x0, @@ -130,7 +130,7 @@ pub fn init_eldenring() } #[no_mangle] -pub extern "C" fn fps_patch_get(b: &mut bool) // Get FPS patch status +pub extern "C" fn fps_patch_get(b: *mut bool) // Get FPS patch status { unsafe { @@ -139,7 +139,7 @@ pub extern "C" fn fps_patch_get(b: &mut bool) // Get FPS patch status } #[no_mangle] -pub extern "C" fn fps_patch_set(b: &bool) // Set FPS patch status +pub extern "C" fn fps_patch_set(b: *mut bool) // Set FPS patch status { unsafe { @@ -148,7 +148,7 @@ pub extern "C" fn fps_patch_set(b: &bool) // Set FPS patch status } #[no_mangle] -pub extern "C" fn fps_limit_get(f: &mut f32) // Get FPS custom limit +pub extern "C" fn fps_limit_get(f: *mut f32) // Get FPS custom limit { unsafe { @@ -157,7 +157,7 @@ pub extern "C" fn fps_limit_get(f: &mut f32) // Get FPS custom limit } #[no_mangle] -pub extern "C" fn fps_limit_set(f: &f32) // Set FPS custom limit +pub extern "C" fn fps_limit_set(f: *mut f32) // Set FPS custom limit { unsafe { From 801ae62d2970abde8e7e82524615eab47542bd59 Mon Sep 17 00:00:00 2001 From: Frank van der Stam Date: Sat, 31 Aug 2024 20:06:35 +0200 Subject: [PATCH 19/26] reuse allocated bool --- src/SoulMemory/EldenRing/EldenRing.cs | 24 +++++++++++++++--------- src/SoulMemory/Native/Kernel32.cs | 2 +- src/cli/Program.cs | 11 ++--------- src/soulmods/src/games/x64/eldenring.rs | 6 +++--- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/SoulMemory/EldenRing/EldenRing.cs b/src/SoulMemory/EldenRing/EldenRing.cs index 605af65c..1e64478e 100644 --- a/src/SoulMemory/EldenRing/EldenRing.cs +++ b/src/SoulMemory/EldenRing/EldenRing.cs @@ -188,6 +188,7 @@ private void ResetPointers() _menuManImp.Clear(); _virtualMemoryFlag.Clear(); _noLogo.Clear(); + _fpsPatch = IntPtr.Zero; } #endregion @@ -585,24 +586,29 @@ public void WriteInGameTimeMilliseconds(int milliseconds) #endregion #region soulmods - + private IntPtr _fpsPatch = IntPtr.Zero; public bool FpsPatchGet() { var address = _exportedFunctions["fps_patch_get"]; - var bPtr = _process.Allocate(1); - _process.Execute((IntPtr)address, bPtr); - var b = _process.ReadMemory(bPtr.ToInt64()).Unwrap(); - _process.Free(bPtr); + if (_fpsPatch == IntPtr.Zero) + { + _fpsPatch = _process.Allocate(1); + } + _process.Execute((IntPtr)address, _fpsPatch); + var b = _process.ReadMemory(_fpsPatch.ToInt64()).Unwrap(); + //_process.Free(bPtr); return b; } public void FpsPatchSet(bool b) { var address = _exportedFunctions["fps_patch_set"]; - var bPtr = _process.Allocate(1); - _process.WriteProcessMemory(bPtr.ToInt64(), BitConverter.GetBytes(b)); - _process.Execute((IntPtr)address, bPtr); - _process.Free(bPtr); + if (_fpsPatch == IntPtr.Zero) + { + _fpsPatch = _process.Allocate(1); + } + _process.WriteProcessMemory(_fpsPatch.ToInt64(), BitConverter.GetBytes(b)); + _process.Execute((IntPtr)address, _fpsPatch); } public float FpsLimitGet() diff --git a/src/SoulMemory/Native/Kernel32.cs b/src/SoulMemory/Native/Kernel32.cs index 9807b2d1..115973a2 100644 --- a/src/SoulMemory/Native/Kernel32.cs +++ b/src/SoulMemory/Native/Kernel32.cs @@ -218,7 +218,7 @@ public static void Execute(this Process process, IntPtr startAddress, IntPtr? pa { process.NtSuspendProcess(); IntPtr thread = NativeMethods.CreateRemoteThread(process.Handle, IntPtr.Zero, 0, startAddress, parameter ?? IntPtr.Zero, 0, IntPtr.Zero); - NativeMethods.WaitForSingleObject(thread, 10000); // set back to 5000 + NativeMethods.WaitForSingleObject(thread, 5000); // set back to 5000 process.NtResumeProcess(); NativeMethods.CloseHandle(thread); } diff --git a/src/cli/Program.cs b/src/cli/Program.cs index bfcaf578..15e853d0 100644 --- a/src/cli/Program.cs +++ b/src/cli/Program.cs @@ -50,15 +50,8 @@ static void Main(string[] args) bool init = true; GameLoop((e) => { - if (init) - { - GlobalHotKey.RegisterHotKey(ModifierKeys.Alt, Key.A, () => - { - var fpsPatchState = e.FpsPatchGet(); - e.FpsPatchSet(!fpsPatchState); - }); - init = false; - } + bool currentStatus = e.FpsPatchGet(); + e.FpsPatchSet(!currentStatus); var igtElapsed = TimeSpan.FromMilliseconds(e.GetInGameTimeMilliseconds()); Console.WriteLine($"IGT: {igtElapsed}"); diff --git a/src/soulmods/src/games/x64/eldenring.rs b/src/soulmods/src/games/x64/eldenring.rs index f0be8a01..f61f08cf 100644 --- a/src/soulmods/src/games/x64/eldenring.rs +++ b/src/soulmods/src/games/x64/eldenring.rs @@ -111,21 +111,21 @@ pub fn init_eldenring() info!("FPS at 0x{:x}", fn_fps_address); // Enable FPS patch - FPS_HOOK = Some(Hooker::new(fn_fps_address, HookType::JmpBack(fps), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); + //FPS_HOOK = Some(Hooker::new(fn_fps_address, HookType::JmpBack(fps), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); // AoB scan for FPS history patch let fn_fps_history_address = process.scan_abs("fps history", fps_history_aob, 0, Vec::new()).unwrap().get_base_address(); info!("FPS history at 0x{:x}", fn_fps_history_address); // Enable FPS history patch - FPS_HISTORY_HOOK = Some(Hooker::new(fn_fps_history_address, HookType::JmpBack(fps_history), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); + //FPS_HISTORY_HOOK = Some(Hooker::new(fn_fps_history_address, HookType::JmpBack(fps_history), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); // AoB scan for FPS custom limit patch let fn_fps_custom_limit_address = process.scan_abs("fps custom limit", fps_custom_limit_aob, 0, Vec::new()).unwrap().get_base_address(); info!("FPS custom limit at 0x{:x}", fn_fps_custom_limit_address); // Enable FPS custom limit patch - FPS_CUSTOM_LIMIT_HOOK = Some(Hooker::new(fn_fps_custom_limit_address, HookType::JmpBack(fps_custom_limit), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); + //FPS_CUSTOM_LIMIT_HOOK = Some(Hooker::new(fn_fps_custom_limit_address, HookType::JmpBack(fps_custom_limit), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); } } From 8dfae5b0201376f161f39f4b1f15f88a8917c3e1 Mon Sep 17 00:00:00 2001 From: Vinjul1704 Date: Sun, 1 Sep 2024 20:52:53 +0200 Subject: [PATCH 20/26] Re-enable FPS patch hooks. --- src/soulmods/src/games/x64/eldenring.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/soulmods/src/games/x64/eldenring.rs b/src/soulmods/src/games/x64/eldenring.rs index f61f08cf..f0be8a01 100644 --- a/src/soulmods/src/games/x64/eldenring.rs +++ b/src/soulmods/src/games/x64/eldenring.rs @@ -111,21 +111,21 @@ pub fn init_eldenring() info!("FPS at 0x{:x}", fn_fps_address); // Enable FPS patch - //FPS_HOOK = Some(Hooker::new(fn_fps_address, HookType::JmpBack(fps), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); + FPS_HOOK = Some(Hooker::new(fn_fps_address, HookType::JmpBack(fps), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); // AoB scan for FPS history patch let fn_fps_history_address = process.scan_abs("fps history", fps_history_aob, 0, Vec::new()).unwrap().get_base_address(); info!("FPS history at 0x{:x}", fn_fps_history_address); // Enable FPS history patch - //FPS_HISTORY_HOOK = Some(Hooker::new(fn_fps_history_address, HookType::JmpBack(fps_history), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); + FPS_HISTORY_HOOK = Some(Hooker::new(fn_fps_history_address, HookType::JmpBack(fps_history), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); // AoB scan for FPS custom limit patch let fn_fps_custom_limit_address = process.scan_abs("fps custom limit", fps_custom_limit_aob, 0, Vec::new()).unwrap().get_base_address(); info!("FPS custom limit at 0x{:x}", fn_fps_custom_limit_address); // Enable FPS custom limit patch - //FPS_CUSTOM_LIMIT_HOOK = Some(Hooker::new(fn_fps_custom_limit_address, HookType::JmpBack(fps_custom_limit), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); + FPS_CUSTOM_LIMIT_HOOK = Some(Hooker::new(fn_fps_custom_limit_address, HookType::JmpBack(fps_custom_limit), CallbackOption::None, 0, HookFlags::empty()).hook().unwrap()); } } From 352f45ce3fe1d867fa70166b24e7f430ecf30634 Mon Sep 17 00:00:00 2001 From: Vinjul1704 Date: Sun, 1 Sep 2024 20:54:02 +0200 Subject: [PATCH 21/26] Re-use float for fps limit. --- src/SoulMemory/EldenRing/EldenRing.cs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/SoulMemory/EldenRing/EldenRing.cs b/src/SoulMemory/EldenRing/EldenRing.cs index 1e64478e..0c6adbb1 100644 --- a/src/SoulMemory/EldenRing/EldenRing.cs +++ b/src/SoulMemory/EldenRing/EldenRing.cs @@ -611,23 +611,28 @@ public void FpsPatchSet(bool b) _process.Execute((IntPtr)address, _fpsPatch); } + private IntPtr _fpsLimit = IntPtr.Zero; public float FpsLimitGet() { var address = _exportedFunctions["fps_limit_get"]; - var fPtr = _process.Allocate(4); - _process.Execute((IntPtr)address, fPtr); - var f = _process.ReadMemory(fPtr.ToInt64()).Unwrap(); - _process.Free(fPtr); + if (_fpsLimit == IntPtr.Zero) + { + _fpsLimit = _process.Allocate(4); + } + _process.Execute((IntPtr)address, _fpsLimit); + var f = _process.ReadMemory(_fpsLimit.ToInt64()).Unwrap(); return f; } public void FpsLimitSet(float f) { var address = _exportedFunctions["fps_limit_set"]; - var fPtr = _process.Allocate(4); - _process.WriteProcessMemory(fPtr.ToInt64(), BitConverter.GetBytes(f)); - _process.Execute((IntPtr)address, fPtr); - _process.Free(fPtr); + if (_fpsLimit == IntPtr.Zero) + { + _fpsLimit = _process.Allocate(4); + } + _process.WriteProcessMemory(_fpsLimit.ToInt64(), BitConverter.GetBytes(f)); + _process.Execute((IntPtr)address, _fpsLimit); } #endregion From d88f9058cd3bd84cdb866d5e6381b3166f644f2f Mon Sep 17 00:00:00 2001 From: Vinjul1704 Date: Sun, 1 Sep 2024 21:00:37 +0200 Subject: [PATCH 22/26] Cleanup. --- src/SoulMemory/EldenRing/EldenRing.cs | 4 --- src/SoulMemory/Native/Kernel32.cs | 2 +- .../Splitters/EldenRingSplitter.cs | 30 ++++--------------- src/soulmods/src/games/x64/eldenring.rs | 2 +- 4 files changed, 8 insertions(+), 30 deletions(-) diff --git a/src/SoulMemory/EldenRing/EldenRing.cs b/src/SoulMemory/EldenRing/EldenRing.cs index 0c6adbb1..dc200274 100644 --- a/src/SoulMemory/EldenRing/EldenRing.cs +++ b/src/SoulMemory/EldenRing/EldenRing.cs @@ -17,9 +17,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; using SoulMemory.Memory; using SoulMemory.Native; using Pointer = SoulMemory.Memory.Pointer; @@ -596,7 +593,6 @@ public bool FpsPatchGet() } _process.Execute((IntPtr)address, _fpsPatch); var b = _process.ReadMemory(_fpsPatch.ToInt64()).Unwrap(); - //_process.Free(bPtr); return b; } diff --git a/src/SoulMemory/Native/Kernel32.cs b/src/SoulMemory/Native/Kernel32.cs index 115973a2..40424752 100644 --- a/src/SoulMemory/Native/Kernel32.cs +++ b/src/SoulMemory/Native/Kernel32.cs @@ -218,7 +218,7 @@ public static void Execute(this Process process, IntPtr startAddress, IntPtr? pa { process.NtSuspendProcess(); IntPtr thread = NativeMethods.CreateRemoteThread(process.Handle, IntPtr.Zero, 0, startAddress, parameter ?? IntPtr.Zero, 0, IntPtr.Zero); - NativeMethods.WaitForSingleObject(thread, 5000); // set back to 5000 + NativeMethods.WaitForSingleObject(thread, 5000); process.NtResumeProcess(); NativeMethods.CloseHandle(thread); } diff --git a/src/SoulSplitter/Splitters/EldenRingSplitter.cs b/src/SoulSplitter/Splitters/EldenRingSplitter.cs index e2952a41..97cc6181 100644 --- a/src/SoulSplitter/Splitters/EldenRingSplitter.cs +++ b/src/SoulSplitter/Splitters/EldenRingSplitter.cs @@ -173,13 +173,12 @@ private void ResetTimer() } - bool init = true; // TODO: Remove when UI hotkeys are implemented - // bool lastFpsPatchState = false; // TODO: Remove when mutex is implemented - bool test = false; + bool hotkeysCreated = true; // TODO: Remove when UI hotkeys are implemented + bool lastFpsPatchState = false; // TODO: Replace with proper get/set public void UpdateTimer(bool startAutomatically) { // Hardcoded hotkeys. TODO: Remove when UI hotkeys are implemented - if (init) + if (hotkeysCreated) { /* // Danflesh @@ -272,6 +271,7 @@ public void UpdateTimer(bool startAutomatically) _eldenRingViewModel.FpsPatch = false; }); */ + GlobalHotKey.RegisterHotKey(ModifierKeys.None, Key.F2, () => { _eldenRing.FpsPatchSet(true); @@ -280,33 +280,15 @@ public void UpdateTimer(bool startAutomatically) { _eldenRing.FpsPatchSet(false); }); - GlobalHotKey.RegisterHotKey(ModifierKeys.None, Key.F4, () => - { - test = !test; - }); - init = false; - } - - // _eldenRing.FpsPatchSet(false); - // _eldenRing.FpsPatchGet(); + hotkeysCreated = false; + } - /* if (lastFpsPatchState != _eldenRingViewModel.FpsPatch) { lastFpsPatchState = _eldenRingViewModel.FpsPatch; _eldenRing.FpsPatchSet(_eldenRingViewModel.FpsPatch); } - */ - - - if (test) - { - bool currentStatus = _eldenRing.FpsPatchGet(); - _eldenRing.FpsPatchSet(!currentStatus); - } - - //Allow updates from the UI only when a run isn't in progress if (_timerState == TimerState.WaitForStart) diff --git a/src/soulmods/src/games/x64/eldenring.rs b/src/soulmods/src/games/x64/eldenring.rs index f0be8a01..9f94f228 100644 --- a/src/soulmods/src/games/x64/eldenring.rs +++ b/src/soulmods/src/games/x64/eldenring.rs @@ -37,7 +37,7 @@ static mut FPS_HISTORY_HOOK: Option = None; static mut FPS_CUSTOM_LIMIT_HOOK: Option = None; static mut FPS_HOOK_ENABLED: bool = false; -static mut FPS_CUSTOM_LIMIT: f32 = 30.0f32; // Reset back to 0 after tests +static mut FPS_CUSTOM_LIMIT: f32 = 0.0f32; static mut FPS_OFFSETS: FpsOffsets = FpsOffsets { target_frame_delta: 0x0, From 0b15fd925353910c94e9e9ecb4770a5e61bae3ab Mon Sep 17 00:00:00 2001 From: Vinjul1704 Date: Sun, 1 Sep 2024 21:02:52 +0200 Subject: [PATCH 23/26] Test hotkeys for the FPS limit. --- src/SoulSplitter/Splitters/EldenRingSplitter.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/SoulSplitter/Splitters/EldenRingSplitter.cs b/src/SoulSplitter/Splitters/EldenRingSplitter.cs index 97cc6181..388eb0dc 100644 --- a/src/SoulSplitter/Splitters/EldenRingSplitter.cs +++ b/src/SoulSplitter/Splitters/EldenRingSplitter.cs @@ -280,6 +280,18 @@ public void UpdateTimer(bool startAutomatically) { _eldenRing.FpsPatchSet(false); }); + GlobalHotKey.RegisterHotKey(ModifierKeys.None, Key.F5, () => + { + _eldenRing.FpsLimitSet(0.0f); + }); + GlobalHotKey.RegisterHotKey(ModifierKeys.None, Key.F6, () => + { + _eldenRing.FpsLimitSet(40.0f); + }); + GlobalHotKey.RegisterHotKey(ModifierKeys.None, Key.F7, () => + { + _eldenRing.FpsLimitSet(25.0f); + }); hotkeysCreated = false; } From 51639d5a806a131959bed0a36fffe9382252c580 Mon Sep 17 00:00:00 2001 From: Vinjul1704 Date: Sun, 1 Sep 2024 21:24:11 +0200 Subject: [PATCH 24/26] Flip "hotkeysCreated" check to align with the name. --- src/SoulSplitter/Splitters/EldenRingSplitter.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/SoulSplitter/Splitters/EldenRingSplitter.cs b/src/SoulSplitter/Splitters/EldenRingSplitter.cs index 388eb0dc..5365f696 100644 --- a/src/SoulSplitter/Splitters/EldenRingSplitter.cs +++ b/src/SoulSplitter/Splitters/EldenRingSplitter.cs @@ -173,12 +173,12 @@ private void ResetTimer() } - bool hotkeysCreated = true; // TODO: Remove when UI hotkeys are implemented + bool hotkeysCreated = false; // TODO: Remove when UI hotkeys are implemented bool lastFpsPatchState = false; // TODO: Replace with proper get/set public void UpdateTimer(bool startAutomatically) { // Hardcoded hotkeys. TODO: Remove when UI hotkeys are implemented - if (hotkeysCreated) + if (!hotkeysCreated) { /* // Danflesh @@ -293,7 +293,7 @@ public void UpdateTimer(bool startAutomatically) _eldenRing.FpsLimitSet(25.0f); }); - hotkeysCreated = false; + hotkeysCreated = true; } if (lastFpsPatchState != _eldenRingViewModel.FpsPatch) From db3be7d1128c565cca20b337947f38cbe21b4399 Mon Sep 17 00:00:00 2001 From: Vinjul1704 Date: Sun, 1 Sep 2024 21:55:54 +0200 Subject: [PATCH 25/26] Remove old inject delay workaround --- src/SoulMemory/EldenRing/EldenRing.cs | 2 -- src/SoulSplitter/Splitters/EldenRingSplitter.cs | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/SoulMemory/EldenRing/EldenRing.cs b/src/SoulMemory/EldenRing/EldenRing.cs index dc200274..400c9cf2 100644 --- a/src/SoulMemory/EldenRing/EldenRing.cs +++ b/src/SoulMemory/EldenRing/EldenRing.cs @@ -152,8 +152,6 @@ private ResultErr InitPointers() ApplyNoLogo(); - // Thread.Sleep(15 * 1000); // Delay soulmods injection to work around crashes. TODO: Fix the crashes in some other way. - if (!soulmods.Soulmods.Inject(_process)) { _igt.Clear(); diff --git a/src/SoulSplitter/Splitters/EldenRingSplitter.cs b/src/SoulSplitter/Splitters/EldenRingSplitter.cs index 5365f696..bfd3c32c 100644 --- a/src/SoulSplitter/Splitters/EldenRingSplitter.cs +++ b/src/SoulSplitter/Splitters/EldenRingSplitter.cs @@ -272,6 +272,7 @@ public void UpdateTimer(bool startAutomatically) }); */ + // Testing GlobalHotKey.RegisterHotKey(ModifierKeys.None, Key.F2, () => { _eldenRing.FpsPatchSet(true); @@ -302,7 +303,7 @@ public void UpdateTimer(bool startAutomatically) _eldenRing.FpsPatchSet(_eldenRingViewModel.FpsPatch); } - //Allow updates from the UI only when a run isn't in progress + // Allow updates from the UI only when a run isn't in progress if (_timerState == TimerState.WaitForStart) { _startAutomatically = startAutomatically; From 33cda2e41a14d826aacd542b591d0654add1f407 Mon Sep 17 00:00:00 2001 From: Vinjul1704 Date: Sat, 28 Sep 2024 18:15:02 +0200 Subject: [PATCH 26/26] Fix crash when restarting the game while keeping livesplit open. --- src/SoulMemory/EldenRing/EldenRing.cs | 7 +++++-- src/SoulSplitter/Splitters/EldenRingSplitter.cs | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/SoulMemory/EldenRing/EldenRing.cs b/src/SoulMemory/EldenRing/EldenRing.cs index 400c9cf2..b5181a58 100644 --- a/src/SoulMemory/EldenRing/EldenRing.cs +++ b/src/SoulMemory/EldenRing/EldenRing.cs @@ -42,6 +42,9 @@ public class EldenRing : IGame private long _playerInsOffset; private Dictionary _exportedFunctions; + private IntPtr _fpsPatch = IntPtr.Zero; + private IntPtr _fpsLimit = IntPtr.Zero; + #region Refresh/init/reset ================================================================================================ public Process GetProcess() => _process; @@ -184,6 +187,7 @@ private void ResetPointers() _virtualMemoryFlag.Clear(); _noLogo.Clear(); _fpsPatch = IntPtr.Zero; + _fpsLimit = IntPtr.Zero; } #endregion @@ -581,7 +585,6 @@ public void WriteInGameTimeMilliseconds(int milliseconds) #endregion #region soulmods - private IntPtr _fpsPatch = IntPtr.Zero; public bool FpsPatchGet() { var address = _exportedFunctions["fps_patch_get"]; @@ -605,7 +608,7 @@ public void FpsPatchSet(bool b) _process.Execute((IntPtr)address, _fpsPatch); } - private IntPtr _fpsLimit = IntPtr.Zero; + public float FpsLimitGet() { var address = _exportedFunctions["fps_limit_get"]; diff --git a/src/SoulSplitter/Splitters/EldenRingSplitter.cs b/src/SoulSplitter/Splitters/EldenRingSplitter.cs index bfd3c32c..27d9215a 100644 --- a/src/SoulSplitter/Splitters/EldenRingSplitter.cs +++ b/src/SoulSplitter/Splitters/EldenRingSplitter.cs @@ -303,6 +303,8 @@ public void UpdateTimer(bool startAutomatically) _eldenRing.FpsPatchSet(_eldenRingViewModel.FpsPatch); } + // _eldenRing.FpsPatchSet(!_eldenRing.FpsPatchGet()); // TEMP SPAM TOGGLE + // Allow updates from the UI only when a run isn't in progress if (_timerState == TimerState.WaitForStart) {