Feature/logstats (#8)

Added an option to output player death counter and kill counter to statusbar and to files. Useful for display on twitch stream.
This commit is contained in:
Me_TheCat 2019-03-31 15:02:00 +03:00 committed by uberhalit
parent f0ad1e49fa
commit 12b6c52149
7 changed files with 267 additions and 89 deletions

View file

@ -25,6 +25,7 @@ Patches games memory while running, does not modify any game files. Wrks with ev
* automatically patch game on startup * automatically patch game on startup
* seamlessly switch between windowed, borderless and borderless fullscreen * seamlessly switch between windowed, borderless and borderless fullscreen
* hotkey for patching while in (borderless) window mode * hotkey for patching while in (borderless) window mode
* log and display hidden counters such as deaths/kill count
## Usage ## Usage

View file

@ -184,5 +184,13 @@ 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

@ -7,81 +7,111 @@
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.0" 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"> <StackPanel 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" />
</DockPanel> </DockPanel>
<DockPanel Margin="0,5,0,0" LastChildFill="False"> <DockPanel Margin="0,5,0,0" LastChildFill="False">
<CheckBox x:Name="cbAddResolution" DockPanel.Dock="Left" Margin="0,0,0,0" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Content="Add custom resolution:" Checked="CbAddResolution_Check_Handler" Unchecked="CbAddResolution_Check_Handler" /> <CheckBox x:Name="cbAddResolution" DockPanel.Dock="Left" Margin="0,0,0,0" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Content="Add custom resolution:" Checked="CbAddResolution_Check_Handler" Unchecked="CbAddResolution_Check_Handler" />
<TextBox x:Name="tbHeight" DockPanel.Dock="Right" Margin="0,0,0,0" Width="50" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Text="1080" MaxLength="4" PreviewTextInput="Numeric_PreviewTextInput" DataObject.Pasting="Numeric_PastingHandler" /> <TextBox x:Name="tbHeight" DockPanel.Dock="Right" Margin="0,0,0,0" Width="50" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Text="1080" MaxLength="4" PreviewTextInput="Numeric_PreviewTextInput" DataObject.Pasting="Numeric_PastingHandler" />
<Label DockPanel.Dock="Right" Margin="0,0,0,0" Height="25" FontSize="14 px" Content="x" /> <Label DockPanel.Dock="Right" Margin="0,0,0,0" Height="25" FontSize="14 px" Content="x" />
<TextBox x:Name="tbWidth" DockPanel.Dock="Right" Margin="0,0,0,0" Width="50" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Text="2560" MaxLength="4" PreviewTextInput="Numeric_PreviewTextInput" DataObject.Pasting="Numeric_PastingHandler" /> <TextBox x:Name="tbWidth" DockPanel.Dock="Right" Margin="0,0,0,0" Width="50" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Text="2560" MaxLength="4" PreviewTextInput="Numeric_PreviewTextInput" DataObject.Pasting="Numeric_PastingHandler" />
</DockPanel> </DockPanel>
<DockPanel Margin="0,5,0,0" LastChildFill="False"> <DockPanel Margin="0,5,0,0" LastChildFill="False">
<CheckBox x:Name="cbFov" DockPanel.Dock="Left" Margin="0,0,0,0" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Content="Increase FOV by:" Checked="CbFov_Check_Handler" Unchecked="CbFov_Check_Handler" /> <CheckBox x:Name="cbFov" DockPanel.Dock="Left" Margin="0,0,0,0" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Content="Increase FOV by:" Checked="CbFov_Check_Handler" Unchecked="CbFov_Check_Handler" />
<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" 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>
<Expander x:Name="exGameMods" Margin="-3,4,0,0" Height="Auto" FontSize="14 px" Header="Game modifications" IsExpanded="False"> <DockPanel Margin="0,5,0,0" LastChildFill="False">
<Grid Margin="3,0,0,0" Background="#FFF9F9F9"> <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" />
<StackPanel Width="Auto" Height="Auto"> </DockPanel>
<DockPanel Margin="0,3,0,0" LastChildFill="False"> <Expander x:Name="exGameMods" Margin="-3,4,0,0" Height="Auto" FontSize="14 px" Header="Game modifications" IsExpanded="False">
<CheckBox x:Name="cbGameSpeed" DockPanel.Dock="Left" Margin="0,0,0,0" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Content="Game speed (%):" Checked="CbGameSpeed_Check_Handler" Unchecked="CbGameSpeed_Check_Handler" /> <Grid Margin="3,0,0,0" Background="#FFF9F9F9">
<Button x:Name="bGs100" 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}}" <StackPanel Width="Auto" Height="Auto">
<DockPanel Margin="0,3,0,0" LastChildFill="False">
<CheckBox x:Name="cbGameSpeed" DockPanel.Dock="Left" Margin="0,0,0,0" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Content="Game speed (%):" Checked="CbGameSpeed_Check_Handler" Unchecked="CbGameSpeed_Check_Handler" />
<Button x:Name="bGs100" 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="BGs100_Click" /> Focusable="False" Click="BGs100_Click" />
<Button x:Name="bGsHigher" 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="bGsHigher" 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}}"
Focusable="False" Click="BGsHigher_Click" /> Focusable="False" Click="BGsHigher_Click" />
<TextBox x:Name="tbGameSpeed" DockPanel.Dock="Right" Margin="0,0,3,0" Width="30" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Text="100" TextAlignment="Center" MaxLength="3" PreviewTextInput="Numeric_PreviewTextInput" DataObject.Pasting="Numeric_PastingHandler" /> <TextBox x:Name="tbGameSpeed" DockPanel.Dock="Right" Margin="0,0,3,0" Width="30" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Text="100" TextAlignment="Center" MaxLength="3" PreviewTextInput="Numeric_PreviewTextInput" DataObject.Pasting="Numeric_PastingHandler" />
<Button x:Name="bGsLower" DockPanel.Dock="Right" Content="&lt;" Margin="0,0,3,0" Width="25" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" <Button x:Name="bGsLower" DockPanel.Dock="Right" Content="&lt;" Margin="0,0,3,0" Width="25" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
Focusable="False" Click="BGsLower_Click" /> Focusable="False" Click="BGsLower_Click" />
<Button x:Name="bGs0" DockPanel.Dock="Right" Content="0" Margin="0,0,3,0" Width="30" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" <Button x:Name="bGs0" DockPanel.Dock="Right" Content="0" Margin="0,0,3,0" Width="30" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
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 start the patcher." 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}}"
Focusable="False" Click="BPsHigher_Click" /> Focusable="False" Click="BPsHigher_Click" />
<TextBox x:Name="tbPlayerSpeed" DockPanel.Dock="Right" Margin="0,0,3,0" Width="30" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Text="100" TextAlignment="Center" MaxLength="3" PreviewTextInput="Numeric_PreviewTextInput" DataObject.Pasting="Numeric_PastingHandler" /> <TextBox x:Name="tbPlayerSpeed" DockPanel.Dock="Right" Margin="0,0,3,0" Width="30" Height="25" FontSize="14 px" VerticalContentAlignment="Center" Text="100" TextAlignment="Center" MaxLength="3" PreviewTextInput="Numeric_PreviewTextInput" DataObject.Pasting="Numeric_PastingHandler" />
<Button x:Name="bPsLower" DockPanel.Dock="Right" Content="&lt;" Margin="0,0,3,0" Width="25" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" <Button x:Name="bPsLower" DockPanel.Dock="Right" Content="&lt;" Margin="0,0,3,0" Width="25" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
Focusable="False" Click="BPsLower_Click" /> Focusable="False" Click="BPsLower_Click" />
<Button x:Name="bPs0" DockPanel.Dock="Right" Content="0" Margin="0,0,3,0" Width="30" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" <Button x:Name="bPs0" DockPanel.Dock="Right" Content="0" Margin="0,0,3,0" Width="30" Height="25" FontSize="14 px" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
Focusable="False" Click="BPs0_Click" /> Focusable="False" Click="BPs0_Click" />
</DockPanel> </DockPanel>
</StackPanel> </StackPanel>
</Grid> </Grid>
</Expander> </Expander>
<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 HorizontalAlignment="Left" TextWrapping="WrapWithOverflow" Margin="2,5,2,0" VerticalAlignment="Top" FontSize="11 px" 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>
<Run FontWeight="Bold" Foreground="#FFF00000">fullscreen mode and force disable VSYNC</Run> <Run FontWeight="Bold" Foreground="#FFF00000">fullscreen mode and force disable VSYNC</Run>
<Run FontWeight="Bold">with Nvidia Control panel or AMD Radeon Settings to get frame rate unlock working.</Run> <Run FontWeight="Bold">with Nvidia Control panel or AMD Radeon Settings to get frame rate unlock working.</Run>
<Run>To avoid stuttering it's recommended to disable VSYNC even with a 144 Hz monitor.</Run> <Run>To avoid stuttering it's recommended to disable VSYNC even with a 144 Hz monitor.</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>
<Run FontWeight="Bold" Foreground="#FFF00000">borderless window mode or force the game to run on highest available refresh rate</Run> <Run FontWeight="Bold" Foreground="#FFF00000">borderless window mode or force the game to run on highest available refresh rate</Run>
<Run FontWeight="Bold">using Nvidia Control panel or AMD Radeon Settings.</Run> <Run FontWeight="Bold">using Nvidia Control panel or AMD Radeon Settings.</Run>
<Run>Borderless window mode requires "Windowed" in game settings first.</Run> <Run>Borderless window mode requires "Windowed" in game settings first.</Run>
<Run FontWeight="Bold">Custom resolution adds 21/9 support and overwrites a default resolution, hud will be limited to 16/9.</Run> <Run FontWeight="Bold">Custom resolution adds 21/9 support and overwrites a default resolution, hud will be limited to 16/9.</Run>
<Run>Borderless window mode with custom resolution requires you to patch and set resolution first, then add borderless patch afterwards.</Run> <Run>Borderless window mode with custom resolution requires you to patch and set resolution first, then add borderless patch afterwards.</Run>
<Run FontWeight="Bold">To enable Player Speed modification you have to be ingame first.</Run> <Run FontWeight="Bold">To enable Player Speed modification you have to be ingame first.</Run>
<Run FontWeight="Bold" Foreground="#FFF00000">See the link below for detailed information, guides, GSYNC support and an AMD fix.</Run> <Run FontWeight="Bold" Foreground="#FFF00000">See the link below for detailed information, guides, GSYNC support and an AMD fix.</Run>
</TextBlock.Inlines> </TextBlock.Inlines>
</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.0 - by uberhalit
</Hyperlink> </Hyperlink>
</Label> </Label>
</StackPanel> <StatusBar DockPanel.Dock="Bottom" Margin="-10,0,-10,0" VerticalAlignment="Bottom">
</Grid> <StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<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">
<Run Text="Deaths:"/>
<Run Text="{Binding Deaths}"/>
</TextBlock>
</StatusBarItem>
<Separator Grid.Column="1" />
<StatusBarItem Grid.Column="2">
<TextBlock Name="sbKillCount">
<Run Text="Kills:"/>
<Run Text="{Binding Kills}"/>
</TextBlock>
</StatusBarItem>
</StatusBar>
</StackPanel>
</Grid>
</Window> </Window>

View file

@ -11,6 +11,8 @@ 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
{ {
@ -26,21 +28,34 @@ 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_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 bool _use_resolution_720 = false;
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 readonly DispatcherTimer _dispatcherTimerCheck = new DispatcherTimer(); internal const string totalKillsFilename = "TotalKillsCounter.txt";
internal StatViewModel _statViewModel = new StatViewModel();
private bool _statLoggingEnabled = false;
internal readonly Timer _statRecordTimer = new Timer();
internal readonly DispatcherTimer _dispatcherTimerCheck = new DispatcherTimer();
internal bool _running = false; internal bool _running = false;
internal string _logPath; internal string _logPath;
internal bool _retryAccess = true; internal bool _retryAccess = true;
internal RECT _windowRect; internal RECT _windowRect;
public MainWindow()
public MainWindow()
{ {
InitializeComponent(); InitializeComponent();
} DataContext = _statViewModel;
}
/// <summary> /// <summary>
/// On window loaded. /// On window loaded.
@ -75,7 +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);
_statRecordTimer.Interval = 1500;
_statRecordTimer.Start();
}
/// <summary> /// <summary>
/// On window closing. /// On window closing.
@ -88,7 +107,9 @@ namespace SekiroFpsUnlockAndMore
UnregisterHotKey(hWnd, 9009); UnregisterHotKey(hWnd, 9009);
if (_gameAccessHwnd != IntPtr.Zero) if (_gameAccessHwnd != IntPtr.Zero)
CloseHandle(_gameAccessHwnd); CloseHandle(_gameAccessHwnd);
}
_statRecordTimer.Stop();
}
/// <summary> /// <summary>
/// Windows Message queue (Wndproc) to catch HotKeyPressed /// Windows Message queue (Wndproc) to catch HotKeyPressed
@ -126,7 +147,8 @@ namespace SekiroFpsUnlockAndMore
this.tbGameSpeed.Text = _settingsService.settings.tbGameSpeed.ToString(); this.tbGameSpeed.Text = _settingsService.settings.tbGameSpeed.ToString();
this.cbPlayerSpeed.IsChecked = _settingsService.settings.cbPlayerSpeed; this.cbPlayerSpeed.IsChecked = _settingsService.settings.cbPlayerSpeed;
this.tbPlayerSpeed.Text = _settingsService.settings.tbPlayerSpeed.ToString(); this.tbPlayerSpeed.Text = _settingsService.settings.tbPlayerSpeed.ToString();
} this.cbLogStats.IsChecked = _settingsService.settings.cbLogStats;
}
/// <summary> /// <summary>
/// Save all settings to configuration file. /// Save all settings to configuration file.
@ -147,7 +169,8 @@ namespace SekiroFpsUnlockAndMore
_settingsService.settings.tbGameSpeed = Convert.ToInt32(this.tbGameSpeed.Text); _settingsService.settings.tbGameSpeed = Convert.ToInt32(this.tbGameSpeed.Text);
_settingsService.settings.cbPlayerSpeed = this.cbPlayerSpeed.IsChecked == true; _settingsService.settings.cbPlayerSpeed = this.cbPlayerSpeed.IsChecked == true;
_settingsService.settings.tbPlayerSpeed = Convert.ToInt32(this.tbPlayerSpeed.Text); _settingsService.settings.tbPlayerSpeed = Convert.ToInt32(this.tbPlayerSpeed.Text);
_settingsService.Save(); _settingsService.settings.cbLogStats = this.cbLogStats.IsChecked == true;
_settingsService.Save();
} }
/// <summary> /// <summary>
@ -288,6 +311,29 @@ namespace SekiroFpsUnlockAndMore
this.cbFov.IsEnabled = false; this.cbFov.IsEnabled = false;
} }
//Game stats
_offset_player_deaths = patternScan.FindPatternInternal(GameData.PATTERN_PLAYER_DEATHS, GameData.PATTERN_PLAYER_DEATHS_MASK, ' ');
Debug.WriteLine("Player Deaths found at: 0x" + _offset_player_deaths.ToString("X"));
if (!IsValidAddress(_offset_player_deaths))
{
LogToFile("Player death counter not found...");
}
else
{
_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;
Debug.WriteLine("Total kills found at: 0x" + _offset_total_kills.ToString("X"));
if (!IsValidAddress(_offset_total_kills))
{
LogToFile("Total kills counter not found...");
}
else
{
_pointer_total_kills = DereferenceStaticX64Pointer(_gameAccessHwndStatic, _offset_total_kills, 0);
}
this.cbBorderless.IsEnabled = true; this.cbBorderless.IsEnabled = true;
long offset_pTimeRelated = patternScan.FindPatternInternal(GameData.PATTERN_TIMESCALE, GameData.PATTERN_TIMESCALE_MASK, ' '); long offset_pTimeRelated = patternScan.FindPatternInternal(GameData.PATTERN_TIMESCALE, GameData.PATTERN_TIMESCALE_MASK, ' ');
@ -353,7 +399,7 @@ namespace SekiroFpsUnlockAndMore
this.bPatch.IsEnabled = true; this.bPatch.IsEnabled = true;
_running = true; _running = true;
_dispatcherTimerCheck.Stop(); _dispatcherTimerCheck.Stop();
return Task.FromResult(true); return Task.FromResult(true);
} }
@ -655,11 +701,33 @@ namespace SekiroFpsUnlockAndMore
UpdateStatus(DateTime.Now.ToString("HH:mm:ss") + " Game unpatched!", Brushes.White); UpdateStatus(DateTime.Now.ToString("HH:mm:ss") + " Game unpatched!", Brushes.White);
} }
/// <summary> /// <summary>
/// Returns the hexadecimal representation of an IEEE-754 floating point number /// 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
/// </summary> /// </summary
/// <param name="input">The floating point number.</param> private void StatReadTimer(object sender, EventArgs e)
/// <returns>The hexadecimal representation of the input.</returns> {
if (_gameAccessHwndStatic == IntPtr.Zero) return;
if (IsValidAddress(_pointer_player_deaths))
{
int playerDeaths = Read<Int32>(_gameAccessHwndStatic, _pointer_player_deaths);
_statViewModel.Deaths = playerDeaths;
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
_statViewModel.Kills = totalKills;
if (_statLoggingEnabled) LogStatFile(totalKillsFilename, totalKills.ToString());
}
}
}
/// <summary>
/// Returns the hexadecimal representation of an IEEE-754 floating point number
/// </summary>
/// <param name="input">The floating point number.</param>
/// <returns>The hexadecimal representation of the input.</returns>
private static string GetHexRepresentationFromFloat(float input) private static string GetHexRepresentationFromFloat(float input)
{ {
uint f = BitConverter.ToUInt32(BitConverter.GetBytes(input), 0); uint f = BitConverter.ToUInt32(BitConverter.GetBytes(input), 0);
@ -848,7 +916,27 @@ namespace SekiroFpsUnlockAndMore
} }
} }
private void UpdateStatus(string text, Brush color) /// <summary>
/// Logs stat values to separate files for the use in OBS
/// </summary>
/// <param name="filename">File name</param>
/// <param name="msg">Just a single stat value</param>
private void LogStatFile(string filename, string value)
{
try
{
using (StreamWriter writer = new StreamWriter(filename, false))
{
writer.Write(value);
}
}
catch (Exception ex)
{
MessageBox.Show("Failed writing stat file: " + ex.Message, "Sekiro Fps Unlock And More");
}
}
private void UpdateStatus(string text, Brush color)
{ {
this.tbStatus.Background = color; this.tbStatus.Background = color;
this.tbStatus.Text = text; this.tbStatus.Text = text;
@ -985,7 +1073,12 @@ namespace SekiroFpsUnlockAndMore
if (this.cbPlayerSpeed.IsChecked == true) PatchPlayerSpeed(); if (this.cbPlayerSpeed.IsChecked == true) PatchPlayerSpeed();
} }
private void BPatch_Click(object sender, RoutedEventArgs e) private void CbStatChanged(object sender, RoutedEventArgs e)
{
_statLoggingEnabled = (bool)cbLogStats.IsChecked;
}
private void BPatch_Click(object sender, RoutedEventArgs e)
{ {
PatchGame(); PatchGame();
} }

View file

@ -63,6 +63,7 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
</ApplicationDefinition> </ApplicationDefinition>
<Compile Include="SettingsService.cs" /> <Compile Include="SettingsService.cs" />
<Compile Include="StatViewModel.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

@ -48,8 +48,10 @@ 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 SettingsService() { }
/// <summary> /// <summary>
/// Create a settings provider to load and save settings. /// Create a settings provider to load and save settings.

View file

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
namespace SekiroFpsUnlockAndMore
{
/// <summary>
/// For Status bar display
/// </summary>
class StatViewModel : INotifyPropertyChanged
{
private int _deaths = 0;
public int Deaths
{
get { return _deaths; }
set
{
_deaths = value;
OnPropertyChanged(new PropertyChangedEventArgs("Deaths"));
}
}
private int _kills = 0;
public int Kills
{
get { return _kills; }
set
{
_kills = value;
OnPropertyChanged(new PropertyChangedEventArgs("Kills"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
PropertyChanged?.Invoke(this, e);
}
}
}