Added FreezeMem for fTimescalePlayer

ApplicationSettings are decoupled from base class now
Cleanup
Refactor
This commit is contained in:
uberhalit 2019-04-01 04:11:18 +02:00
parent 12b6c52149
commit 772b69c1fb
7 changed files with 1743 additions and 1641 deletions

View file

@ -158,9 +158,38 @@ namespace SekiroFpsUnlockAndMore
/** /**
Reference pointer pTimeRelated to pTimescaleManager pointer, offset in struct to <float>fTimescale which acts as a global speed scale for almost all ingame calculations Reference pointer pPlayerStatsRelated to PlayerStats pointer, offset in struct to <int>iPlayerDeaths
0000000141149E87 | 48:8B05 3A24B402 | mov rax,qword ptr ds:[143C8C2C8] | pTimeRelated->[pTimescaleManager+0x360]->fTimescale 00000001407AAC92 | 0FB648 7A | movzx ecx,byte ptr ds:[rax+7A] |
0000000141149E8E | F3:0F1088 60030000 | movss xmm1,dword ptr ds:[rax+360] | offset from TimescaleManager->fTimescale 00000001407AAC96 | 888B F7000000 | mov byte ptr ds:[rbx+F7],cl |
00000001407AAC9C | 48:8B05 4DD03903 | mov rax,qword ptr ds:[143B47CF0] |
00000001407AACA3 | 8B88 8C000000 | mov ecx,dword ptr ds:[rax+8C] |
00000001407AACA9 | 898B F8000000 | mov dword ptr ds:[rbx+F8],ecx |
00000001407AACAF | 48:8B05 3AD03903 | mov rax,qword ptr ds:[143B47CF0] | pPlayerStatsRelated->[PlayerStats+0x90]->iPlayerDeaths
00000001407AACB6 | 8B88 90000000 | mov ecx,dword ptr ds:[rax+90] | offset pPlayerStats->iPlayerDeaths
*/
// credits to 'Me_TheCat' for original offset
internal const string PATTERN_PLAYER_DEATHS = "0F B6 48 00 88 8B 00 00 00 00 48 8B 05 00 00 00 00 8B 88 00 00 00 00 89 8B 00 00 00 00 48 8B 05 00 00 00 00 8B 88 00 00 00 00"; // 0F B6 48 ?? 88 8B ?? ?? 00 00 48 8B 05 ?? ?? ?? ?? 8B 88 ?? ?? 00 00 89 8B ?? ?? 00 00 48 8B 05 ?? ?? ?? ?? 8B 88 ?? ?? 00 00
internal const string PATTERN_PLAYER_DEATHS_MASK = "xxx?xx??xxxxx????xx??xxxx??xxxxx????xx??xx";
internal const int PATTERN_PLAYER_DEATHS_OFFSET = 29;
internal const int PATTERN_PLAYER_DEATHS_INSTRUCTION_LENGTH = 7;
internal const int PATTERN_PLAYER_DEATHS_POINTER_OFFSET_OFFSET = 9;
/**
Reference pointer pTotalKills to <int>iTotalKills, does not get updated on every kill but mostly on every 2nd, includes own player deaths...
0000000141151838 | 48:8D0D A9A5B302 | lea rcx,qword ptr ds:[143C8BDE8] | pTotalKills->iTotalKills
000000014115183F | 891481 | mov dword ptr ds:[rcx+rax*4],edx |
0000000141151842 | C3 | ret |
*/
// credits to 'Me_TheCat' for original offset
internal const string PATTERN_TOTAL_KILLS = "48 8D 0D 00 00 00 00 89 14 81 C3"; // 48 8D 0D ?? ?? ?? ?? 89 14 81 C3
internal const string PATTERN_TOTAL_KILLS_MASK = "xxx????xxxx";
internal const int PATTERN_TOTAL_KILLS_INSTRUCTION_LENGTH = 7;
/**
Reference pointer pTimeRelated to TimescaleManager pointer, offset in struct to <float>fTimescale which acts as a global speed scale for almost all ingame calculations
0000000141149E87 | 48:8B05 3A24B402 | mov rax,qword ptr ds:[143C8C2C8] | pTimeRelated->[TimescaleManager+0x360]->fTimescale
0000000141149E8E | F3:0F1088 60030000 | movss xmm1,dword ptr ds:[rax+360] | offset TimescaleManager->fTimescale
0000000141149E96 | F3:0F5988 68020000 | mulss xmm1,dword ptr ds:[rax+268] | 0000000141149E96 | F3:0F5988 68020000 | mulss xmm1,dword ptr ds:[rax+268] |
*/ */
// credits to 'Zullie the Witch' for original offset // credits to 'Zullie the Witch' for original offset
@ -169,6 +198,7 @@ namespace SekiroFpsUnlockAndMore
internal const int PATTERN_TIMESCALE_INSTRUCTION_LENGTH = 7; internal const int PATTERN_TIMESCALE_INSTRUCTION_LENGTH = 7;
internal const int PATTERN_TIMESCALE_POINTER_OFFSET_OFFSET = 11; internal const int PATTERN_TIMESCALE_POINTER_OFFSET_OFFSET = 11;
/** /**
Reference pointer pPlayerStructRelated1 to 4 more pointers up to player data class, offset in struct to <float>fTimescalePlayer which acts as a speed scale for the player character Reference pointer pPlayerStructRelated1 to 4 more pointers up to player data class, offset in struct to <float>fTimescalePlayer which acts as a speed scale for the player character
00000001406BF1D7 | 48:8B1D 128C4A03 | mov rbx,qword ptr ds:[143B67DF0] | pPlayerStructRelated1->[pPlayerStructRelated2+0x88]->[pPlayerStructRelated3+0x1FF8]->[pPlayerStructRelated4+0x28]->[pPlayerStructRelated5+0xD00]->fTimescalePlayer 00000001406BF1D7 | 48:8B1D 128C4A03 | mov rbx,qword ptr ds:[143B67DF0] | pPlayerStructRelated1->[pPlayerStructRelated2+0x88]->[pPlayerStructRelated3+0x1FF8]->[pPlayerStructRelated4+0x28]->[pPlayerStructRelated5+0xD00]->fTimescalePlayer
@ -184,13 +214,5 @@ namespace SekiroFpsUnlockAndMore
internal const int PATTERN_TIMESCALE_POINTER3_OFFSET = 0x1FF8; internal const int PATTERN_TIMESCALE_POINTER3_OFFSET = 0x1FF8;
internal const int PATTERN_TIMESCALE_POINTER4_OFFSET = 0x28; internal const int PATTERN_TIMESCALE_POINTER4_OFFSET = 0x28;
internal const int PATTERN_TIMESCALE_POINTER5_OFFSET = 0xD00; internal const int PATTERN_TIMESCALE_POINTER5_OFFSET = 0xD00;
// game stat values by Me_TheCat
internal const string PATTERN_PLAYER_DEATHS = "8B 88 90 00 00 00 89 8B FC 00 00 00 48 8B";
internal const string PATTERN_PLAYER_DEATHS_MASK = "xxxxxxxxx???xx";
internal const string PATTERN_TOTAL_KILLS = "48 8D 0D 00 00 00 00 89 14 81 C3";
internal const string PATTERN_TOTAL_KILLS_MASK = "xxx????xxxx";
internal const int PATTERN_TOTAL_KILLS_OFFSET = 7;
} }
} }

View file

@ -5,10 +5,11 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SekiroFpsUnlockAndMore" xmlns:local="clr-namespace:SekiroFpsUnlockAndMore"
mc:Ignorable="d" mc:Ignorable="d"
Title="Sekiro FPS Unlocker and more v1.1.0" Width="Auto" Height="Auto" SizeToContent="WidthAndHeight" ResizeMode="CanMinimize" Loaded="Window_Loaded" Closing="Window_Closing"> Title="Sekiro FPS Unlocker and more v1.1.1" Width="Auto" Height="Auto" SizeToContent="WidthAndHeight" ResizeMode="CanMinimize" Loaded="Window_Loaded" Closing="Window_Closing">
<Grid Background="#FFF9F9F9"> <Grid Background="#FFF9F9F9">
<StackPanel Margin="10,10,10,0" Width="290" Height="Auto"> <DockPanel>
<StackPanel DockPanel.Dock="Top" Margin="10,10,10,0" Width="290" Height="Auto">
<DockPanel LastChildFill="False"> <DockPanel LastChildFill="False">
<CheckBox x:Name="cbFramelock" DockPanel.Dock="Left" Margin="0,0,0,0" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Content="Frame rate lock:" IsChecked="True" Checked="CbFramelock_Check_Handler" Unchecked="CbFramelock_Check_Handler" /> <CheckBox x:Name="cbFramelock" DockPanel.Dock="Left" Margin="0,0,0,0" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Content="Frame rate lock:" IsChecked="True" Checked="CbFramelock_Check_Handler" Unchecked="CbFramelock_Check_Handler" />
<TextBox x:Name="tbFramelock" DockPanel.Dock="Right" Margin="0,0,0,0" Width="116" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Text="144" MaxLength="3" PreviewTextInput="Numeric_PreviewTextInput" DataObject.Pasting="Numeric_PastingHandler" /> <TextBox x:Name="tbFramelock" DockPanel.Dock="Right" Margin="0,0,0,0" Width="116" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Text="144" MaxLength="3" PreviewTextInput="Numeric_PreviewTextInput" DataObject.Pasting="Numeric_PastingHandler" />
@ -24,13 +25,11 @@
<ComboBox x:Name="cbSelectFov" DockPanel.Dock="Right" Margin="0,0,0,0" Width="116" Height="25" FontSize="14 px" SelectedValuePath="Key" DisplayMemberPath="Value" DropDownClosed="CbSelectFov_DropDownClosed"/> <ComboBox x:Name="cbSelectFov" DockPanel.Dock="Right" Margin="0,0,0,0" Width="116" Height="25" FontSize="14 px" SelectedValuePath="Key" DisplayMemberPath="Value" DropDownClosed="CbSelectFov_DropDownClosed"/>
</DockPanel> </DockPanel>
<StackPanel Margin="0,5,0,0" Orientation="Horizontal"> <StackPanel Margin="0,5,0,0" Orientation="Horizontal">
<CheckBox x:Name="cbBorderless" DockPanel.Dock="Left" Margin="0,0,0,0" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Content="Borderless window" IsEnabled="False" Checked="CbBorderless_Checked" Unchecked="CbBorderless_Unchecked"/> <CheckBox x:Name="cbBorderless" DockPanel.Dock="Left" Margin="0,0,0,0" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Content="Borderless window" ToolTip="To enable this set 'Windowed' mode in game options first." IsEnabled="False" Checked="CbBorderless_Checked" Unchecked="CbBorderless_Unchecked"/>
<CheckBox x:Name="cbBorderlessStretch" DockPanel.Dock="Right" Margin="10,0,0,0" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Content="Fullscreen stretch" IsEnabled="False" Checked="CbBorderlessStretch_Check_Handler" Unchecked="CbBorderlessStretch_Check_Handler" /> <CheckBox x:Name="cbBorderlessStretch" DockPanel.Dock="Right" Margin="10,0,0,0" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Content="Fullscreen stretch" IsEnabled="False" Checked="CbBorderlessStretch_Check_Handler" Unchecked="CbBorderlessStretch_Check_Handler" />
</StackPanel> </StackPanel>
<DockPanel Margin="0,5,0,0" LastChildFill="False"> <CheckBox x:Name="cbLogStats" Margin="0,5,0,0" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Content="Log stats to file (Deaths, Kills)" ToolTip="Check the guide on how to display these with OBS." Checked="CbStatChanged" Unchecked="CbStatChanged" />
<CheckBox x:Name="cbLogStats" Content="Log stats (Deaths, Enemies killed)" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top" FontSize="14 px" Checked="CbStatChanged" Unchecked="CbStatChanged" /> <Expander x:Name="exGameMods" Margin="-3,5,0,0" Height="Auto" FontSize="14 px" Header="Game modifications" IsExpanded="False">
</DockPanel>
<Expander x:Name="exGameMods" Margin="-3,4,0,0" Height="Auto" FontSize="14 px" Header="Game modifications" IsExpanded="False">
<Grid Margin="3,0,0,0" Background="#FFF9F9F9"> <Grid Margin="3,0,0,0" Background="#FFF9F9F9">
<StackPanel Width="Auto" Height="Auto"> <StackPanel Width="Auto" Height="Auto">
<DockPanel Margin="0,3,0,0" LastChildFill="False"> <DockPanel Margin="0,3,0,0" LastChildFill="False">
@ -46,7 +45,7 @@
Focusable="False" Click="BGs0_Click" /> Focusable="False" Click="BGs0_Click" />
</DockPanel> </DockPanel>
<DockPanel Margin="0,5,0,0" LastChildFill="False"> <DockPanel Margin="0,5,0,0" LastChildFill="False">
<CheckBox x:Name="cbPlayerSpeed" DockPanel.Dock="Left" Margin="0,0,0,0" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Content="Player speed (%):" ToolTip="To enable this start the game and load a save, then start the patcher." Checked="CbPlayerSpeed_Check_Handler" Unchecked="CbPlayerSpeed_Check_Handler" /> <CheckBox x:Name="cbPlayerSpeed" DockPanel.Dock="Left" Margin="0,0,0,0" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Content="Player speed (%):" ToolTip="To enable this start the game and load a save, then tick the checkbox." Checked="CbPlayerSpeed_Check_Handler" Unchecked="CbPlayerSpeed_Check_Handler" />
<Button x:Name="bPs100" DockPanel.Dock="Right" Content="100" Margin="0,0,0,0" Width="30" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" <Button x:Name="bPs100" DockPanel.Dock="Right" Content="100" Margin="0,0,0,0" Width="30" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
Focusable="False" Click="BPs100_Click" /> Focusable="False" Click="BPs100_Click" />
<Button x:Name="bPsHigher" DockPanel.Dock="Right" Content="&gt;" Margin="0,0,3,0" Width="25" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" <Button x:Name="bPsHigher" DockPanel.Dock="Right" Content="&gt;" Margin="0,0,3,0" Width="25" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
@ -63,7 +62,7 @@
<Button x:Name="bPatch" Margin="0,7,0,0" Width="290" Height="30" FontSize="14 px" IsEnabled="False" Content="Patch game (CTRL + P)" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" <Button x:Name="bPatch" Margin="0,7,0,0" Width="290" Height="30" FontSize="14 px" IsEnabled="False" Content="Patch game (CTRL + P)" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
Focusable="False" Click="BPatch_Click" /> Focusable="False" Click="BPatch_Click" />
<TextBox x:Name="tbStatus" Margin="0,5,0,0" Width="290" Height="25" FontSize="14 px" FontWeight="Bold" Text="waiting for game..." TextAlignment="Center" TextWrapping="NoWrap" IsEnabled="False" /> <TextBox x:Name="tbStatus" Margin="0,5,0,0" Width="290" Height="25" FontSize="14 px" FontWeight="Bold" Text="waiting for game..." TextAlignment="Center" TextWrapping="NoWrap" IsEnabled="False" />
<TextBlock HorizontalAlignment="Left" TextWrapping="WrapWithOverflow" Margin="2,5,2,0" VerticalAlignment="Top" FontSize="11 px" IsEnabled="False"> <TextBlock Margin="2,5,2,0" FontSize="11 px" TextWrapping="WrapWithOverflow" IsEnabled="False">
<TextBlock.Inlines> <TextBlock.Inlines>
<Run FontWeight="Bold" Foreground="#FF0046FF">This patcher does not modify game files, you have to start it every time.</Run> <Run FontWeight="Bold" Foreground="#FF0046FF">This patcher does not modify game files, you have to start it every time.</Run>
<Run FontWeight="Bold">If your monitor is 60 Hz you will have to use</Run> <Run FontWeight="Bold">If your monitor is 60 Hz you will have to use</Run>
@ -82,36 +81,29 @@
</TextBlock> </TextBlock>
<Label HorizontalAlignment="Right" FontSize="12 px"> <Label HorizontalAlignment="Right" FontSize="12 px">
<Hyperlink NavigateUri="https://github.com/uberhalit/SekiroFpsUnlockAndMore" RequestNavigate="Hyperlink_RequestNavigate"> <Hyperlink NavigateUri="https://github.com/uberhalit/SekiroFpsUnlockAndMore" RequestNavigate="Hyperlink_RequestNavigate">
v1.1.0 - by uberhalit v1.1.1 - by uberhalit
</Hyperlink> </Hyperlink>
</Label> </Label>
<StatusBar DockPanel.Dock="Bottom" Margin="-10,0,-10,0" VerticalAlignment="Bottom"> </StackPanel>
<StatusBar.ItemsPanel> <StatusBar DockPanel.Dock="Bottom" Height="25">
<ItemsPanelTemplate> <StatusBarItem DockPanel.Dock="Left">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
<StatusBarItem Grid.Column="0">
<TextBlock Name="sbDeathCount"> <TextBlock Name="sbDeathCount">
<Run Text="Deaths:" /> <Run Text="Deaths:" />
<Run Text="{Binding Deaths}" /> <Run Text="{Binding Deaths}" />
</TextBlock> </TextBlock>
</StatusBarItem> </StatusBarItem>
<Separator Grid.Column="1" /> <Separator Margin="5,4,5,4" Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}"/>
<StatusBarItem Grid.Column="2"> <StatusBarItem DockPanel.Dock="Left">
<TextBlock Name="sbKillCount"> <TextBlock Name="sbKillCount">
<Run Text="Kills:" /> <Run Text="Kills:" />
<Run Text="{Binding Kills}" /> <Run Text="{Binding Kills}" />
</TextBlock> </TextBlock>
</StatusBarItem> </StatusBarItem>
<Separator Margin="5,4,5,4" Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}"/>
<StatusBarItem DockPanel.Dock="Right" HorizontalAlignment="Right">
<TextBlock Name="sbStatus" />
</StatusBarItem>
</StatusBar> </StatusBar>
</StackPanel> </DockPanel>
</Grid> </Grid>
</Window> </Window>

View file

@ -1,5 +1,6 @@
using System; using System;
using System.IO; using System.IO;
using System.Timers;
using System.Windows; using System.Windows;
using System.Threading; using System.Threading;
using System.Diagnostics; using System.Diagnostics;
@ -11,8 +12,6 @@ using System.Windows.Threading;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Timers;
using Timer = System.Timers.Timer;
namespace SekiroFpsUnlockAndMore namespace SekiroFpsUnlockAndMore
{ {
@ -28,33 +27,31 @@ namespace SekiroFpsUnlockAndMore
internal long _offset_resolution_default = 0x0; internal long _offset_resolution_default = 0x0;
internal long _offset_resolution_scaling_fix = 0x0; internal long _offset_resolution_scaling_fix = 0x0;
internal long _offset_fovsetting = 0x0; internal long _offset_fovsetting = 0x0;
//game stat offsets internal long _offset_total_kills = 0x0;
internal long _offset_player_deaths = 0x0; internal long _offset_player_deaths = 0x0;
internal long _pointer_player_deaths = 0x0;
internal long _offset_timescale = 0x0; internal long _offset_timescale = 0x0;
internal long _offset_timescale_player = 0x0; internal long _offset_timescale_player = 0x0;
internal bool _use_resolution_720 = false; internal long _offset_timescale_player_pointer_start = 0x0;
internal long _offset_total_kills = 0x0;
internal long _pointer_total_kills = 0x0;
internal const string deathCounterFilename = "DeathCouner.txt";
internal SettingsService _settingsService; internal SettingsService _settingsService;
internal const string totalKillsFilename = "TotalKillsCounter.txt"; internal StatusViewModel _statusViewModel = new StatusViewModel();
internal StatViewModel _statViewModel = new StatViewModel(); internal readonly System.Timers.Timer _timerStatsCheck = new System.Timers.Timer();
private bool _statLoggingEnabled = false; internal readonly DispatcherTimer _dispatcherTimerFreezeMem = new DispatcherTimer();
internal readonly Timer _statRecordTimer = new Timer();
internal readonly DispatcherTimer _dispatcherTimerCheck = new DispatcherTimer(); internal readonly DispatcherTimer _dispatcherTimerCheck = new DispatcherTimer();
internal bool _running = false; internal bool _running = false;
internal string _logPath; internal string _logPath;
internal string _deathCounterPath;
internal string _killCounterPath;
internal bool _retryAccess = true; internal bool _retryAccess = true;
internal bool _use_resolution_720 = false;
internal bool _statLoggingEnabled = false;
internal RECT _windowRect; internal RECT _windowRect;
public MainWindow() public MainWindow()
{ {
InitializeComponent(); InitializeComponent();
DataContext = _statViewModel; DataContext = _statusViewModel;
} }
/// <summary> /// <summary>
@ -71,6 +68,9 @@ namespace SekiroFpsUnlockAndMore
GC.KeepAlive(mutex); GC.KeepAlive(mutex);
_logPath = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) + @"\SekiroFpsUnlockAndMore.log"; _logPath = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) + @"\SekiroFpsUnlockAndMore.log";
_deathCounterPath = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) + @"\DeathCounter.txt";
_killCounterPath = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) + @"\TotalKillsCounter.txt";
this.cbSelectFov.ItemsSource = GameData.PATCH_FOVSETTING_MATRIX; this.cbSelectFov.ItemsSource = GameData.PATCH_FOVSETTING_MATRIX;
this.cbSelectFov.SelectedIndex = 2; this.cbSelectFov.SelectedIndex = 2;
@ -80,7 +80,6 @@ namespace SekiroFpsUnlockAndMore
if (!RegisterHotKey(hWnd, 9009, MOD_CONTROL, VK_P)) if (!RegisterHotKey(hWnd, 9009, MOD_CONTROL, VK_P))
MessageBox.Show("Hotkey is already in use, it may not work.", "Sekiro FPS Unlocker and more"); MessageBox.Show("Hotkey is already in use, it may not work.", "Sekiro FPS Unlocker and more");
// add a hook for WindowsMessageQueue to recognize hotkey-press
ComponentDispatcher.ThreadFilterMessage += new ThreadMessageEventHandler(ComponentDispatcherThreadFilterMessage); ComponentDispatcher.ThreadFilterMessage += new ThreadMessageEventHandler(ComponentDispatcherThreadFilterMessage);
_dispatcherTimerCheck.Tick += new EventHandler(async (object s, EventArgs a) => _dispatcherTimerCheck.Tick += new EventHandler(async (object s, EventArgs a) =>
@ -91,9 +90,11 @@ namespace SekiroFpsUnlockAndMore
_dispatcherTimerCheck.Interval = new TimeSpan(0, 0, 0, 2); _dispatcherTimerCheck.Interval = new TimeSpan(0, 0, 0, 2);
_dispatcherTimerCheck.Start(); _dispatcherTimerCheck.Start();
_statRecordTimer.Elapsed += new ElapsedEventHandler(StatReadTimer); _dispatcherTimerFreezeMem.Tick += new EventHandler(FreezeMemory);
_statRecordTimer.Interval = 1500; _dispatcherTimerFreezeMem.Interval = new TimeSpan(0, 0, 0, 0, 2000);
_statRecordTimer.Start();
_timerStatsCheck.Elapsed += new ElapsedEventHandler(StatReadTimer);
_timerStatsCheck.Interval = 2000;
} }
/// <summary> /// <summary>
@ -101,14 +102,13 @@ namespace SekiroFpsUnlockAndMore
/// </summary> /// </summary>
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{ {
_timerStatsCheck.Stop();
SaveConfiguration(); SaveConfiguration();
ComponentDispatcher.ThreadFilterMessage -= ComponentDispatcherThreadFilterMessage; ComponentDispatcher.ThreadFilterMessage -= ComponentDispatcherThreadFilterMessage;
IntPtr hWnd = new WindowInteropHelper(this).Handle; IntPtr hWnd = new WindowInteropHelper(this).Handle;
UnregisterHotKey(hWnd, 9009); UnregisterHotKey(hWnd, 9009);
if (_gameAccessHwnd != IntPtr.Zero) if (_gameAccessHwnd != IntPtr.Zero)
CloseHandle(_gameAccessHwnd); CloseHandle(_gameAccessHwnd);
_statRecordTimer.Stop();
} }
/// <summary> /// <summary>
@ -133,21 +133,21 @@ namespace SekiroFpsUnlockAndMore
{ {
_settingsService = new SettingsService(Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) + @"\SekiroFpsUnlockAndMore.xml"); _settingsService = new SettingsService(Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) + @"\SekiroFpsUnlockAndMore.xml");
if (!_settingsService.Load()) return; if (!_settingsService.Load()) return;
this.cbFramelock.IsChecked = _settingsService.settings.cbFramelock; this.cbFramelock.IsChecked = _settingsService.ApplicationSettings.cbFramelock;
this.tbFramelock.Text = _settingsService.settings.tbFramelock.ToString(); this.tbFramelock.Text = _settingsService.ApplicationSettings.tbFramelock.ToString();
this.cbAddResolution.IsChecked = _settingsService.settings.cbAddResolution; this.cbAddResolution.IsChecked = _settingsService.ApplicationSettings.cbAddResolution;
this.tbWidth.Text = _settingsService.settings.tbWidth.ToString(); this.tbWidth.Text = _settingsService.ApplicationSettings.tbWidth.ToString();
this.tbHeight.Text = _settingsService.settings.tbHeight.ToString(); this.tbHeight.Text = _settingsService.ApplicationSettings.tbHeight.ToString();
this.cbFov.IsChecked = _settingsService.settings.cbFov; this.cbFov.IsChecked = _settingsService.ApplicationSettings.cbFov;
this.cbSelectFov.SelectedIndex = _settingsService.settings.cbSelectFov; this.cbSelectFov.SelectedIndex = _settingsService.ApplicationSettings.cbSelectFov;
this.cbBorderless.IsChecked = _settingsService.settings.cbBorderless; this.cbBorderless.IsChecked = _settingsService.ApplicationSettings.cbBorderless;
this.cbBorderlessStretch.IsChecked = _settingsService.settings.cbBorderlessStretch; this.cbBorderlessStretch.IsChecked = _settingsService.ApplicationSettings.cbBorderlessStretch;
this.exGameMods.IsExpanded = _settingsService.settings.exGameMods; this.exGameMods.IsExpanded = _settingsService.ApplicationSettings.exGameMods;
this.cbGameSpeed.IsChecked = _settingsService.settings.cbGameSpeed; this.cbGameSpeed.IsChecked = _settingsService.ApplicationSettings.cbGameSpeed;
this.tbGameSpeed.Text = _settingsService.settings.tbGameSpeed.ToString(); this.tbGameSpeed.Text = _settingsService.ApplicationSettings.tbGameSpeed.ToString();
this.cbPlayerSpeed.IsChecked = _settingsService.settings.cbPlayerSpeed; this.cbPlayerSpeed.IsChecked = _settingsService.ApplicationSettings.cbPlayerSpeed;
this.tbPlayerSpeed.Text = _settingsService.settings.tbPlayerSpeed.ToString(); this.tbPlayerSpeed.Text = _settingsService.ApplicationSettings.tbPlayerSpeed.ToString();
this.cbLogStats.IsChecked = _settingsService.settings.cbLogStats; this.cbLogStats.IsChecked = _settingsService.ApplicationSettings.cbLogStats;
} }
/// <summary> /// <summary>
@ -155,21 +155,21 @@ namespace SekiroFpsUnlockAndMore
/// </summary> /// </summary>
private void SaveConfiguration() private void SaveConfiguration()
{ {
_settingsService.settings.cbFramelock = this.cbFramelock.IsChecked == true; _settingsService.ApplicationSettings.cbFramelock = this.cbFramelock.IsChecked == true;
_settingsService.settings.tbFramelock = Convert.ToInt32(this.tbFramelock.Text); _settingsService.ApplicationSettings.tbFramelock = Convert.ToInt32(this.tbFramelock.Text);
_settingsService.settings.cbAddResolution = this.cbAddResolution.IsChecked == true; _settingsService.ApplicationSettings.cbAddResolution = this.cbAddResolution.IsChecked == true;
_settingsService.settings.tbWidth = Convert.ToInt32(this.tbWidth.Text); _settingsService.ApplicationSettings.tbWidth = Convert.ToInt32(this.tbWidth.Text);
_settingsService.settings.tbHeight = Convert.ToInt32(this.tbHeight.Text); _settingsService.ApplicationSettings.tbHeight = Convert.ToInt32(this.tbHeight.Text);
_settingsService.settings.cbFov = this.cbFov.IsChecked == true; _settingsService.ApplicationSettings.cbFov = this.cbFov.IsChecked == true;
_settingsService.settings.cbSelectFov = this.cbSelectFov.SelectedIndex; _settingsService.ApplicationSettings.cbSelectFov = this.cbSelectFov.SelectedIndex;
_settingsService.settings.cbBorderless = this.cbBorderless.IsChecked == true; _settingsService.ApplicationSettings.cbBorderless = this.cbBorderless.IsChecked == true;
_settingsService.settings.cbBorderlessStretch = this.cbBorderlessStretch.IsChecked == true; _settingsService.ApplicationSettings.cbBorderlessStretch = this.cbBorderlessStretch.IsChecked == true;
_settingsService.settings.exGameMods = this.exGameMods.IsExpanded; _settingsService.ApplicationSettings.exGameMods = this.exGameMods.IsExpanded;
_settingsService.settings.cbGameSpeed = this.cbGameSpeed.IsChecked == true; _settingsService.ApplicationSettings.cbGameSpeed = this.cbGameSpeed.IsChecked == true;
_settingsService.settings.tbGameSpeed = Convert.ToInt32(this.tbGameSpeed.Text); _settingsService.ApplicationSettings.tbGameSpeed = Convert.ToInt32(this.tbGameSpeed.Text);
_settingsService.settings.cbPlayerSpeed = this.cbPlayerSpeed.IsChecked == true; _settingsService.ApplicationSettings.cbPlayerSpeed = this.cbPlayerSpeed.IsChecked == true;
_settingsService.settings.tbPlayerSpeed = Convert.ToInt32(this.tbPlayerSpeed.Text); _settingsService.ApplicationSettings.tbPlayerSpeed = Convert.ToInt32(this.tbPlayerSpeed.Text);
_settingsService.settings.cbLogStats = this.cbLogStats.IsChecked == true; _settingsService.ApplicationSettings.cbLogStats = this.cbLogStats.IsChecked == true;
_settingsService.Save(); _settingsService.Save();
} }
@ -238,26 +238,26 @@ namespace SekiroFpsUnlockAndMore
PatternScan patternScan = new PatternScan(_gameAccessHwnd, _gameProc.MainModule); PatternScan patternScan = new PatternScan(_gameAccessHwnd, _gameProc.MainModule);
_offset_framelock = patternScan.FindPatternInternal(GameData.PATTERN_FRAMELOCK, GameData.PATTERN_FRAMELOCK_MASK, ' ') + GameData.PATTERN_FRAMELOCK_OFFSET; _offset_framelock = patternScan.FindPatternInternal(GameData.PATTERN_FRAMELOCK, GameData.PATTERN_FRAMELOCK_MASK, ' ') + GameData.PATTERN_FRAMELOCK_OFFSET;
Debug.WriteLine("1. Framelock found at: 0x" + _offset_framelock.ToString("X")); Debug.WriteLine("fFrameTick found at: 0x" + _offset_framelock.ToString("X"));
if (!IsValidAddress(_offset_framelock)) if (!IsValidAddress(_offset_framelock))
{ {
_offset_framelock = patternScan.FindPatternInternal(GameData.PATTERN_FRAMELOCK_FUZZY, GameData.PATTERN_FRAMELOCK_FUZZY_MASK, ' ') + GameData.PATTERN_FRAMELOCK_FUZZY_OFFSET; _offset_framelock = patternScan.FindPatternInternal(GameData.PATTERN_FRAMELOCK_FUZZY, GameData.PATTERN_FRAMELOCK_FUZZY_MASK, ' ') + GameData.PATTERN_FRAMELOCK_FUZZY_OFFSET;
Debug.WriteLine("2. Framelock found at: 0x" + _offset_framelock.ToString("X")); Debug.WriteLine("2. fFrameTick found at: 0x" + _offset_framelock.ToString("X"));
} }
if (!IsValidAddress(_offset_framelock)) if (!IsValidAddress(_offset_framelock))
{ {
UpdateStatus("framelock not found...", Brushes.Red); UpdateStatus("fFrameTick not found...", Brushes.Red);
LogToFile("framelock not found..."); LogToFile("fFrameTick not found...");
_offset_framelock = 0x0; _offset_framelock = 0x0;
this.cbFramelock.IsEnabled = false; this.cbFramelock.IsEnabled = false;
} }
_offset_framelock_speed_fix = patternScan.FindPatternInternal(GameData.PATTERN_FRAMELOCK_SPEED_FIX, GameData.PATTERN_FRAMELOCK_SPEED_FIX_MASK, ' ') + GameData.PATTERN_FRAMELOCK_SPEED_FIX_OFFSET; _offset_framelock_speed_fix = patternScan.FindPatternInternal(GameData.PATTERN_FRAMELOCK_SPEED_FIX, GameData.PATTERN_FRAMELOCK_SPEED_FIX_MASK, ' ') + GameData.PATTERN_FRAMELOCK_SPEED_FIX_OFFSET;
Debug.WriteLine("Speed fix found at: 0x" + _offset_framelock_speed_fix.ToString("X")); Debug.WriteLine("pFrametimeRunningSpeed at: 0x" + _offset_framelock_speed_fix.ToString("X"));
if (!IsValidAddress(_offset_framelock_speed_fix)) if (!IsValidAddress(_offset_framelock_speed_fix))
{ {
UpdateStatus("speed fix not found...", Brushes.Red); UpdateStatus("pFrametimeRunningSpeed no found...", Brushes.Red);
LogToFile("speed fix not found..."); LogToFile("pFrametimeRunningSpeed not found...");
_offset_framelock_speed_fix = 0x0; _offset_framelock_speed_fix = 0x0;
this.cbFramelock.IsEnabled = false; this.cbFramelock.IsEnabled = false;
} }
@ -265,7 +265,7 @@ namespace SekiroFpsUnlockAndMore
bool enableResolutionPatch = true; bool enableResolutionPatch = true;
if ((int) SystemParameters.PrimaryScreenWidth < 1281) _use_resolution_720 = true; if ((int) SystemParameters.PrimaryScreenWidth < 1281) _use_resolution_720 = true;
_offset_resolution_default = patternScan.FindPatternInternal(!_use_resolution_720 ? GameData.PATTERN_RESOLUTION_DEFAULT : GameData.PATTERN_RESOLUTION_DEFAULT_720, GameData.PATTERN_RESOLUTION_DEFAULT_MASK, ' '); _offset_resolution_default = patternScan.FindPatternInternal(!_use_resolution_720 ? GameData.PATTERN_RESOLUTION_DEFAULT : GameData.PATTERN_RESOLUTION_DEFAULT_720, GameData.PATTERN_RESOLUTION_DEFAULT_MASK, ' ');
Debug.WriteLine("Default resolution found at: 0x" + _offset_resolution_default.ToString("X")); Debug.WriteLine("default resolution found at: 0x" + _offset_resolution_default.ToString("X"));
if (!IsValidAddress(_offset_resolution_default)) if (!IsValidAddress(_offset_resolution_default))
{ {
UpdateStatus("default resolution not found...", Brushes.Red); UpdateStatus("default resolution not found...", Brushes.Red);
@ -274,7 +274,7 @@ namespace SekiroFpsUnlockAndMore
_offset_resolution_default = 0x0; _offset_resolution_default = 0x0;
} }
_offset_resolution_scaling_fix = patternScan.FindPatternInternal(GameData.PATTERN_RESOLUTION_SCALING_FIX, GameData.PATTERN_RESOLUTION_SCALING_FIX_MASK, ' ') + GameData.PATTERN_RESOLUTION_SCALING_FIX_OFFSET; _offset_resolution_scaling_fix = patternScan.FindPatternInternal(GameData.PATTERN_RESOLUTION_SCALING_FIX, GameData.PATTERN_RESOLUTION_SCALING_FIX_MASK, ' ') + GameData.PATTERN_RESOLUTION_SCALING_FIX_OFFSET;
Debug.WriteLine("Scaling fix found at: 0x" + _offset_resolution_scaling_fix.ToString("X")); Debug.WriteLine("scaling fix found at: 0x" + _offset_resolution_scaling_fix.ToString("X"));
if (!IsValidAddress(_offset_resolution_scaling_fix)) if (!IsValidAddress(_offset_resolution_scaling_fix))
{ {
UpdateStatus("scaling fix not found...", Brushes.Red); UpdateStatus("scaling fix not found...", Brushes.Red);
@ -282,70 +282,98 @@ namespace SekiroFpsUnlockAndMore
enableResolutionPatch = false; enableResolutionPatch = false;
_offset_resolution_scaling_fix = 0x0; _offset_resolution_scaling_fix = 0x0;
} }
long offset_resolution_pointer = patternScan.FindPatternInternal(GameData.PATTERN_RESOLUTION_POINTER, GameData.PATTERN_RESOLUTION_POINTER_MASK, ' ') + GameData.PATTERN_RESOLUTION_POINTER_OFFSET; long ref_pCurrentResolutionWidth = patternScan.FindPatternInternal(GameData.PATTERN_RESOLUTION_POINTER, GameData.PATTERN_RESOLUTION_POINTER_MASK, ' ') + GameData.PATTERN_RESOLUTION_POINTER_OFFSET;
Debug.WriteLine("Resolution pointer found at: 0x" + offset_resolution_pointer.ToString("X")); Debug.WriteLine("ref_pCurrentResolutionWidth found at: 0x" + ref_pCurrentResolutionWidth.ToString("X"));
if (!IsValidAddress(offset_resolution_pointer)) if (!IsValidAddress(ref_pCurrentResolutionWidth))
{ {
UpdateStatus("re_pCurrentResolutionWidth not found...", Brushes.Red);
LogToFile("ref_pCurrentResolutionWidth not found...");
enableResolutionPatch = false; enableResolutionPatch = false;
} }
else else
{ {
_offset_resolution = DereferenceStaticX64Pointer(_gameAccessHwnd, offset_resolution_pointer, GameData.PATTERN_RESOLUTION_POINTER_INSTRUCTION_LENGTH); _offset_resolution = DereferenceStaticX64Pointer(_gameAccessHwnd, ref_pCurrentResolutionWidth, GameData.PATTERN_RESOLUTION_POINTER_INSTRUCTION_LENGTH);
Debug.WriteLine("Resolution found at: 0x" + _offset_resolution.ToString("X")); Debug.WriteLine("pCurrentResolutionWidth at: 0x" + _offset_resolution.ToString("X"));
if (!IsValidAddress(_offset_resolution)) if (!IsValidAddress(_offset_resolution))
{ {
UpdateStatus("resolution not valid...", Brushes.Red); UpdateStatus("pCurrentResolutionWidth not valid...", Brushes.Red);
LogToFile("resolution not valid..."); LogToFile("pCurrentResolutionWidth not valid...");
_offset_resolution = 0x0; _offset_resolution = 0x0;
} }
} }
this.cbAddResolution.IsEnabled = enableResolutionPatch; this.cbAddResolution.IsEnabled = enableResolutionPatch;
_offset_fovsetting = patternScan.FindPatternInternal(GameData.PATTERN_FOVSETTING, GameData.PATTERN_FOVSETTING_MASK, ' ') + GameData.PATTERN_FOVSETTING_OFFSET; _offset_fovsetting = patternScan.FindPatternInternal(GameData.PATTERN_FOVSETTING, GameData.PATTERN_FOVSETTING_MASK, ' ') + GameData.PATTERN_FOVSETTING_OFFSET;
Debug.WriteLine("FOV found at: 0x" + _offset_fovsetting.ToString("X")); Debug.WriteLine("pFovTableEntry found at: 0x" + _offset_fovsetting.ToString("X"));
if (!IsValidAddress(_offset_fovsetting)) if (!IsValidAddress(_offset_fovsetting))
{ {
UpdateStatus("FOV not found...", Brushes.Red); UpdateStatus("pFovTableEntry not found...", Brushes.Red);
LogToFile("FOV not found..."); LogToFile("pFovTableEntry not found...");
_offset_fovsetting = 0x0; _offset_fovsetting = 0x0;
this.cbFov.IsEnabled = false; this.cbFov.IsEnabled = false;
} }
//Game stats long ref_pPlayerStatsRelated = patternScan.FindPatternInternal(GameData.PATTERN_PLAYER_DEATHS, GameData.PATTERN_PLAYER_DEATHS_MASK, ' ') + GameData.PATTERN_PLAYER_DEATHS_OFFSET;
_offset_player_deaths = patternScan.FindPatternInternal(GameData.PATTERN_PLAYER_DEATHS, GameData.PATTERN_PLAYER_DEATHS_MASK, ' '); Debug.WriteLine("ref_pPlayerStatsRelated found at: 0x" + ref_pPlayerStatsRelated.ToString("X"));
Debug.WriteLine("Player Deaths found at: 0x" + _offset_player_deaths.ToString("X")); if (!IsValidAddress(ref_pPlayerStatsRelated))
{
UpdateStatus("ref_pPlayerStatsRelated not found...", Brushes.Red);
LogToFile("ref_pPlayerStatsRelated not found...");
this.cbLogStats.IsEnabled = false;
}
else
{
long pPlayerStatsRelated = DereferenceStaticX64Pointer(_gameAccessHwndStatic, ref_pPlayerStatsRelated, GameData.PATTERN_PLAYER_DEATHS_INSTRUCTION_LENGTH);
Debug.WriteLine("pPlayerStatsRelated found at: 0x" + pPlayerStatsRelated.ToString("X"));
if (IsValidAddress(pPlayerStatsRelated))
{
int playerStatsToDeathsOffset = Read<Int32>(_gameAccessHwndStatic, ref_pPlayerStatsRelated + GameData.PATTERN_PLAYER_DEATHS_POINTER_OFFSET_OFFSET);
Debug.WriteLine("offset pPlayerStats->iPlayerDeaths found : 0x" + playerStatsToDeathsOffset.ToString("X"));
if (playerStatsToDeathsOffset > 0) _offset_player_deaths = Read<Int64>(_gameAccessHwndStatic, pPlayerStatsRelated) + playerStatsToDeathsOffset;
Debug.WriteLine("iPlayerDeaths found at: 0x" + _offset_player_deaths.ToString("X"));
}
}
if (!IsValidAddress(_offset_player_deaths)) if (!IsValidAddress(_offset_player_deaths))
{ {
LogToFile("Player death counter not found..."); UpdateStatus("Player Deaths not found...", Brushes.Red);
} LogToFile("Player Deaths not found...");
else _offset_player_deaths = 0x0;
{ this.cbLogStats.IsEnabled = false;
_pointer_player_deaths = Read<Int64>(_gameAccessHwndStatic, DereferenceStaticX64Pointer(_gameAccessHwndStatic, _offset_player_deaths, 0)) + 0x90;
} }
_offset_total_kills = patternScan.FindPatternInternal(GameData.PATTERN_TOTAL_KILLS, GameData.PATTERN_TOTAL_KILLS_MASK, ' ') + GameData.PATTERN_TOTAL_KILLS_OFFSET; long ref_pTotalKills = patternScan.FindPatternInternal(GameData.PATTERN_TOTAL_KILLS, GameData.PATTERN_TOTAL_KILLS_MASK, ' ');
Debug.WriteLine("Total kills found at: 0x" + _offset_total_kills.ToString("X")); Debug.WriteLine("ref_pTotalKills found at: 0x" + ref_pTotalKills.ToString("X"));
if (!IsValidAddress(_offset_total_kills)) if (!IsValidAddress(ref_pTotalKills))
{ {
LogToFile("Total kills counter not found..."); UpdateStatus("ref_pTotalKills not found...", Brushes.Red);
LogToFile("ref_pTotalKills not found...");
this.cbLogStats.IsEnabled = false;
} }
else else
{ {
_pointer_total_kills = DereferenceStaticX64Pointer(_gameAccessHwndStatic, _offset_total_kills, 0); _offset_total_kills = DereferenceStaticX64Pointer(_gameAccessHwndStatic, ref_pTotalKills, GameData.PATTERN_TOTAL_KILLS_INSTRUCTION_LENGTH);
if (!IsValidAddress(_offset_total_kills))
{
UpdateStatus("pTotalKills not valid...", Brushes.Red);
LogToFile("pTotalKills not valid...");
_offset_total_kills = 0x0;
this.cbLogStats.IsEnabled = false;
} }
}
if (_offset_player_deaths > 0x0 && _offset_total_kills > 0x0) _timerStatsCheck.Start();
this.cbBorderless.IsEnabled = true; this.cbBorderless.IsEnabled = true;
long offset_pTimeRelated = patternScan.FindPatternInternal(GameData.PATTERN_TIMESCALE, GameData.PATTERN_TIMESCALE_MASK, ' '); long ref_pTimeRelated = patternScan.FindPatternInternal(GameData.PATTERN_TIMESCALE, GameData.PATTERN_TIMESCALE_MASK, ' ');
Debug.WriteLine("pTimeRelated found at: 0x" + offset_pTimeRelated.ToString("X")); Debug.WriteLine("ref_pTimeRelated found at: 0x" + ref_pTimeRelated.ToString("X"));
if (IsValidAddress(offset_pTimeRelated)) if (IsValidAddress(ref_pTimeRelated))
{ {
long pTimescaleManager = DereferenceStaticX64Pointer(_gameAccessHwndStatic, offset_pTimeRelated, GameData.PATTERN_TIMESCALE_INSTRUCTION_LENGTH); long pTimescaleManager = DereferenceStaticX64Pointer(_gameAccessHwndStatic, ref_pTimeRelated, GameData.PATTERN_TIMESCALE_INSTRUCTION_LENGTH);
Debug.WriteLine("pTimescaleManager found at: 0x" + pTimescaleManager.ToString("X")); Debug.WriteLine("pTimescaleManager found at: 0x" + pTimescaleManager.ToString("X"));
if (IsValidAddress(pTimescaleManager)) if (IsValidAddress(pTimescaleManager))
{ {
_offset_timescale = Read<Int64>(_gameAccessHwndStatic, pTimescaleManager) + Read<Int32>(_gameAccessHwndStatic, offset_pTimeRelated + GameData.PATTERN_TIMESCALE_POINTER_OFFSET_OFFSET); _offset_timescale = Read<Int64>(_gameAccessHwndStatic, pTimescaleManager) + Read<Int32>(_gameAccessHwndStatic, ref_pTimeRelated + GameData.PATTERN_TIMESCALE_POINTER_OFFSET_OFFSET);
Debug.WriteLine("timescale found at: 0x" + _offset_timescale.ToString("X")); Debug.WriteLine("fTimescale found at: 0x" + _offset_timescale.ToString("X"));
if (!IsValidAddress(_offset_timescale)) if (!IsValidAddress(_offset_timescale))
{ {
_offset_timescale = 0x0; _offset_timescale = 0x0;
@ -354,8 +382,8 @@ namespace SekiroFpsUnlockAndMore
} }
if (_offset_timescale == 0x0) if (_offset_timescale == 0x0)
{ {
UpdateStatus("Timescale not found...", Brushes.Red); UpdateStatus("fTimescale not found...", Brushes.Red);
LogToFile("Timescale not found..."); LogToFile("fTimescale not found...");
this.cbGameSpeed.IsEnabled = false; this.cbGameSpeed.IsEnabled = false;
} }
@ -367,6 +395,7 @@ namespace SekiroFpsUnlockAndMore
Debug.WriteLine("pPlayerStructRelated2 found at: 0x" + pPlayerStructRelated2.ToString("X")); Debug.WriteLine("pPlayerStructRelated2 found at: 0x" + pPlayerStructRelated2.ToString("X"));
if (IsValidAddress(pPlayerStructRelated2)) if (IsValidAddress(pPlayerStructRelated2))
{ {
_offset_timescale_player_pointer_start = pPlayerStructRelated2;
long pPlayerStructRelated3 = Read<Int64>(_gameAccessHwndStatic, pPlayerStructRelated2) + GameData.PATTERN_TIMESCALE_POINTER2_OFFSET; long pPlayerStructRelated3 = Read<Int64>(_gameAccessHwndStatic, pPlayerStructRelated2) + GameData.PATTERN_TIMESCALE_POINTER2_OFFSET;
Debug.WriteLine("pPlayerStructRelated3 found at: 0x" + pPlayerStructRelated3.ToString("X")); Debug.WriteLine("pPlayerStructRelated3 found at: 0x" + pPlayerStructRelated3.ToString("X"));
if (IsValidAddress(pPlayerStructRelated3)) if (IsValidAddress(pPlayerStructRelated3))
@ -380,7 +409,7 @@ namespace SekiroFpsUnlockAndMore
if (IsValidAddress(pPlayerStructRelated5)) if (IsValidAddress(pPlayerStructRelated5))
{ {
_offset_timescale_player = Read<Int64>(_gameAccessHwndStatic, pPlayerStructRelated5) + GameData.PATTERN_TIMESCALE_POINTER5_OFFSET; _offset_timescale_player = Read<Int64>(_gameAccessHwndStatic, pPlayerStructRelated5) + GameData.PATTERN_TIMESCALE_POINTER5_OFFSET;
Debug.WriteLine("timescale found at: 0x" + _offset_timescale_player.ToString("X")); Debug.WriteLine("fTimescalePlayer found at: 0x" + _offset_timescale_player.ToString("X"));
if (!IsValidAddress(_offset_timescale_player)) if (!IsValidAddress(_offset_timescale_player))
{ {
_offset_timescale_player = 0x0; _offset_timescale_player = 0x0;
@ -390,7 +419,7 @@ namespace SekiroFpsUnlockAndMore
} }
} }
} }
if (_offset_timescale_player == 0x0) if (_offset_timescale_player_pointer_start == 0x0)
{ {
UpdateStatus("Playerscale not found...", Brushes.Red); UpdateStatus("Playerscale not found...", Brushes.Red);
LogToFile("Playerscale not found..."); LogToFile("Playerscale not found...");
@ -404,6 +433,35 @@ namespace SekiroFpsUnlockAndMore
return Task.FromResult(true); return Task.FromResult(true);
} }
/// <summary>
/// Read and refresh all offsets that can change on quick travel or save game loading.
/// </summary>
private void ReadIngameOffsets()
{
bool valid = false;
if (_offset_timescale_player_pointer_start > 0)
{
long pPlayerStructRelated3 = Read<Int64>(_gameAccessHwndStatic, _offset_timescale_player_pointer_start) + GameData.PATTERN_TIMESCALE_POINTER2_OFFSET;
if (IsValidAddress(pPlayerStructRelated3))
{
long pPlayerStructRelated4 = Read<Int64>(_gameAccessHwndStatic, pPlayerStructRelated3) + GameData.PATTERN_TIMESCALE_POINTER3_OFFSET;
if (IsValidAddress(pPlayerStructRelated4))
{
long pPlayerStructRelated5 = Read<Int64>(_gameAccessHwndStatic, pPlayerStructRelated4) + GameData.PATTERN_TIMESCALE_POINTER4_OFFSET;
if (IsValidAddress(pPlayerStructRelated5))
{
_offset_timescale_player = Read<Int64>(_gameAccessHwndStatic, pPlayerStructRelated5) + GameData.PATTERN_TIMESCALE_POINTER5_OFFSET;
if (IsValidAddress(_offset_timescale_player))
{
valid = true;
}
}
}
}
}
if (!valid) _offset_timescale_player = 0x0;
}
/// <summary> /// <summary>
/// Determines whether everything is ready for patching. /// Determines whether everything is ready for patching.
/// </summary> /// </summary>
@ -426,6 +484,8 @@ namespace SekiroFpsUnlockAndMore
_offset_resolution_default = 0x0; _offset_resolution_default = 0x0;
_offset_resolution_scaling_fix = 0x0; _offset_resolution_scaling_fix = 0x0;
_offset_fovsetting = 0x0; _offset_fovsetting = 0x0;
_offset_player_deaths = 0x0;
_offset_total_kills = 0x0;
_offset_timescale = 0x0; _offset_timescale = 0x0;
_offset_timescale_player = 0x0; _offset_timescale_player = 0x0;
this.cbFramelock.IsEnabled = true; this.cbFramelock.IsEnabled = true;
@ -649,7 +709,17 @@ namespace SekiroFpsUnlockAndMore
/// <param name="showStatus">Determines if status should be updated from within method, default is true.</param> /// <param name="showStatus">Determines if status should be updated from within method, default is true.</param>
private bool PatchPlayerSpeed(bool showStatus = true) private bool PatchPlayerSpeed(bool showStatus = true)
{ {
if (!this.cbPlayerSpeed.IsEnabled || _offset_timescale_player == 0x0 || !CanPatchGame()) return false; if (!this.cbPlayerSpeed.IsEnabled || !CanPatchGame()) return false;
if (this.cbPlayerSpeed.IsChecked == true)
{
if (_offset_timescale_player_pointer_start > 0x0) ReadIngameOffsets();
if (_offset_timescale_player == 0x0)
{
this.cbPlayerSpeed.IsChecked = false;
return false;
}
}
if (_offset_timescale_player == 0x0) return false;
if (this.cbPlayerSpeed.IsChecked == true) if (this.cbPlayerSpeed.IsChecked == true)
{ {
bool isNumber = Int32.TryParse(this.tbPlayerSpeed.Text, out int playerSpeed); bool isNumber = Int32.TryParse(this.tbPlayerSpeed.Text, out int playerSpeed);
@ -667,11 +737,13 @@ namespace SekiroFpsUnlockAndMore
if (timeScalePlayer < 0.01f) if (timeScalePlayer < 0.01f)
timeScalePlayer = 0.00001f; timeScalePlayer = 0.00001f;
WriteBytes(_gameAccessHwndStatic, _offset_timescale_player, BitConverter.GetBytes(timeScalePlayer)); WriteBytes(_gameAccessHwndStatic, _offset_timescale_player, BitConverter.GetBytes(timeScalePlayer));
if (!_dispatcherTimerFreezeMem.IsEnabled) _dispatcherTimerFreezeMem.Start();
} }
else if (this.cbPlayerSpeed.IsChecked == false) else if (this.cbPlayerSpeed.IsChecked == false)
{ {
WriteBytes(_gameAccessHwndStatic, _offset_timescale_player, BitConverter.GetBytes(1.0f)); WriteBytes(_gameAccessHwndStatic, _offset_timescale_player, BitConverter.GetBytes(1.0f));
if (showStatus) UpdateStatus(DateTime.Now.ToString("HH:mm:ss") + " Game unpatched!", Brushes.White); if (showStatus) UpdateStatus(DateTime.Now.ToString("HH:mm:ss") + " Game unpatched!", Brushes.White);
_dispatcherTimerFreezeMem.Stop();
return false; return false;
} }
@ -702,25 +774,48 @@ namespace SekiroFpsUnlockAndMore
} }
/// <summary> /// <summary>
/// Reads some hidden stats and outputs them to text files. Use to display counters on Twitch stream or just look at them and get disspointed /// Freeze values in memory that can't be patched to require no freezing easily.
/// </summary /// </summary>
private void FreezeMemory(object sender, EventArgs e)
{
if (!this.cbPlayerSpeed.IsEnabled || this.cbPlayerSpeed.IsChecked != true)
{
_dispatcherTimerFreezeMem.Stop();
return;
}
if (_offset_timescale_player_pointer_start == 0x0 || !CanPatchGame()) return;
if (_offset_timescale_player_pointer_start > 0x0) ReadIngameOffsets();
if (_offset_timescale_player == 0x0) return;
bool isNumber = Int32.TryParse(this.tbPlayerSpeed.Text, out int playerSpeed);
if (playerSpeed < 0 || !isNumber)
{
this.tbPlayerSpeed.Text = "100";
playerSpeed = 100;
}
else if (playerSpeed >= 999)
{
this.tbPlayerSpeed.Text = "999";
playerSpeed = 1000;
}
float timeScalePlayer = playerSpeed / 100f;
if (timeScalePlayer < 0.01f) timeScalePlayer = 0.00001f;
WriteBytes(_gameAccessHwndStatic, _offset_timescale_player, BitConverter.GetBytes(timeScalePlayer));
}
/// <summary>
/// Reads some hidden stats and outputs them to text files and status bar. Use to display counters on Twitch stream or just look at them and get disappointed.
/// </summary>
private void StatReadTimer(object sender, EventArgs e) private void StatReadTimer(object sender, EventArgs e)
{ {
if (_gameAccessHwndStatic == IntPtr.Zero) return; if (_gameAccessHwndStatic == IntPtr.Zero || _offset_player_deaths == 0x0 || _offset_total_kills == 0x0) return;
if (IsValidAddress(_pointer_player_deaths)) int playerDeaths = Read<Int32>(_gameAccessHwndStatic, _offset_player_deaths);
{ _statusViewModel.Deaths = playerDeaths;
int playerDeaths = Read<Int32>(_gameAccessHwndStatic, _pointer_player_deaths); if (_statLoggingEnabled) LogStatsFile(_deathCounterPath, playerDeaths.ToString());
_statViewModel.Deaths = playerDeaths; int totalKills = Read<Int32>(_gameAccessHwndStatic, _offset_total_kills);
if (_statLoggingEnabled) LogStatFile(deathCounterFilename, playerDeaths.ToString());
if (IsValidAddress(_pointer_total_kills))
{
int totalKills = Read<Int32>(_gameAccessHwndStatic, _pointer_total_kills);
totalKills -= playerDeaths; // Since this value seems to track every death, including the player totalKills -= playerDeaths; // Since this value seems to track every death, including the player
_statViewModel.Kills = totalKills; _statusViewModel.Kills = totalKills;
if (_statLoggingEnabled) LogStatFile(totalKillsFilename, totalKills.ToString()); if (_statLoggingEnabled) LogStatsFile(_killCounterPath, totalKills.ToString());
}
}
} }
/// <summary> /// <summary>
@ -917,22 +1012,22 @@ namespace SekiroFpsUnlockAndMore
} }
/// <summary> /// <summary>
/// Logs stat values to separate files for the use in OBS /// Logs stats values to separate files for use in OBS or similar.
/// </summary> /// </summary>
/// <param name="filename">File name</param> /// <param name="filename">The filepath to the status file.</param>
/// <param name="msg">Just a single stat value</param> /// <param name="msg">The value to write to the text file.</param>
private void LogStatFile(string filename, string value) private void LogStatsFile(string filename, string msg)
{ {
try try
{ {
using (StreamWriter writer = new StreamWriter(filename, false)) using (StreamWriter writer = new StreamWriter(filename, false))
{ {
writer.Write(value); writer.Write(msg);
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
MessageBox.Show("Failed writing stat file: " + ex.Message, "Sekiro Fps Unlock And More"); MessageBox.Show("Failed writing stats file: " + ex.Message, "Sekiro Fps Unlock And More");
} }
} }
@ -995,6 +1090,11 @@ namespace SekiroFpsUnlockAndMore
PatchWindow(); PatchWindow();
} }
private void CbStatChanged(object sender, RoutedEventArgs e)
{
_statLoggingEnabled = cbLogStats.IsChecked == true;
}
private void CbGameSpeed_Check_Handler(object sender, RoutedEventArgs e) private void CbGameSpeed_Check_Handler(object sender, RoutedEventArgs e)
{ {
PatchGameSpeed(); PatchGameSpeed();
@ -1073,11 +1173,6 @@ namespace SekiroFpsUnlockAndMore
if (this.cbPlayerSpeed.IsChecked == true) PatchPlayerSpeed(); if (this.cbPlayerSpeed.IsChecked == true) PatchPlayerSpeed();
} }
private void CbStatChanged(object sender, RoutedEventArgs e)
{
_statLoggingEnabled = (bool)cbLogStats.IsChecked;
}
private void BPatch_Click(object sender, RoutedEventArgs e) private void BPatch_Click(object sender, RoutedEventArgs e)
{ {
PatchGame(); PatchGame();

View file

@ -21,5 +21,5 @@ using System.Runtime.InteropServices;
ResourceDictionaryLocation.SourceAssembly ResourceDictionaryLocation.SourceAssembly
)] )]
[assembly: AssemblyVersion("1.1.0.1")] [assembly: AssemblyVersion("1.1.1.0")]
[assembly: AssemblyFileVersion("1.1.0.1")] [assembly: AssemblyFileVersion("1.1.1.0")]

View file

@ -63,7 +63,7 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
</ApplicationDefinition> </ApplicationDefinition>
<Compile Include="SettingsService.cs" /> <Compile Include="SettingsService.cs" />
<Compile Include="StatViewModel.cs" /> <Compile Include="StatusViewModel.cs" />
<Page Include="MainWindow.xaml"> <Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>

View file

@ -7,16 +7,8 @@ namespace SekiroFpsUnlockAndMore
{ {
[XmlRoot("SekiroFpsUnlockAndMore")] [XmlRoot("SekiroFpsUnlockAndMore")]
[Serializable] [Serializable]
public class SettingsService public class ApplicationSettings
{ {
private readonly string sConfigurationPath = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) + @"\config.xml";
/// <summary>
/// Read and store settings here.
/// </summary>
public SettingsService settings;
/** /**
* Settings definition * Settings definition
*/ */
@ -39,6 +31,8 @@ namespace SekiroFpsUnlockAndMore
[XmlElement] [XmlElement]
public bool cbBorderlessStretch { get; set; } public bool cbBorderlessStretch { get; set; }
[XmlElement] [XmlElement]
public bool cbLogStats { get; set; }
[XmlElement]
public bool exGameMods { get; set; } public bool exGameMods { get; set; }
[XmlElement] [XmlElement]
public bool cbGameSpeed { get; set; } public bool cbGameSpeed { get; set; }
@ -48,10 +42,16 @@ namespace SekiroFpsUnlockAndMore
public bool cbPlayerSpeed { get; set; } public bool cbPlayerSpeed { get; set; }
[XmlElement] [XmlElement]
public int tbPlayerSpeed { get; set; } public int tbPlayerSpeed { get; set; }
[XmlElement] }
public bool cbLogStats { get; set; }
public SettingsService() { } public class SettingsService
{
private readonly string _sConfigurationPath = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) + @"\config.xml";
/// <summary>
/// Read and store settings here.
/// </summary>
public ApplicationSettings ApplicationSettings;
/// <summary> /// <summary>
/// Create a settings provider to load and save settings. /// Create a settings provider to load and save settings.
@ -59,11 +59,8 @@ namespace SekiroFpsUnlockAndMore
/// <param name="settingsFilePath">The file path to the settings file.</param> /// <param name="settingsFilePath">The file path to the settings file.</param>
public SettingsService(string settingsFilePath = null) public SettingsService(string settingsFilePath = null)
{ {
if (settingsFilePath != null) if (settingsFilePath != null) _sConfigurationPath = settingsFilePath;
{ ApplicationSettings = new ApplicationSettings();
sConfigurationPath = settingsFilePath;
settings = new SettingsService();
}
} }
/// <summary> /// <summary>
@ -72,14 +69,14 @@ namespace SekiroFpsUnlockAndMore
/// <returns></returns> /// <returns></returns>
internal bool Load() internal bool Load()
{ {
if (!File.Exists(sConfigurationPath)) return false; if (!File.Exists(_sConfigurationPath)) return false;
XmlSerializer xmlSerializer = new XmlSerializer(typeof(SettingsService)); XmlSerializer xmlSerializer = new XmlSerializer(typeof(ApplicationSettings));
using (StreamReader streamReader = new StreamReader(sConfigurationPath)) using (StreamReader streamReader = new StreamReader(_sConfigurationPath))
{ {
try try
{ {
settings = (SettingsService)xmlSerializer.Deserialize(streamReader); ApplicationSettings = (ApplicationSettings)xmlSerializer.Deserialize(streamReader);
return true; return true;
} }
catch (Exception ex) catch (Exception ex)
@ -95,12 +92,12 @@ namespace SekiroFpsUnlockAndMore
/// </summary> /// </summary>
internal void Save() internal void Save()
{ {
XmlSerializer xmlSerializer = new XmlSerializer(typeof(SettingsService)); XmlSerializer xmlSerializer = new XmlSerializer(typeof(ApplicationSettings));
using (StreamWriter streamReader = new StreamWriter(sConfigurationPath)) using (StreamWriter streamReader = new StreamWriter(_sConfigurationPath))
{ {
try try
{ {
xmlSerializer.Serialize(streamReader, settings); xmlSerializer.Serialize(streamReader, ApplicationSettings);
} }
catch (Exception ex) catch (Exception ex)
{ {

View file

@ -1,15 +1,11 @@
using System; using System.ComponentModel;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
namespace SekiroFpsUnlockAndMore namespace SekiroFpsUnlockAndMore
{ {
/// <summary> /// <summary>
/// For Status bar display /// For Status bar display
/// </summary> /// </summary>
class StatViewModel : INotifyPropertyChanged class StatusViewModel : INotifyPropertyChanged
{ {
private int _deaths = 0; private int _deaths = 0;
public int Deaths public int Deaths