added +25% FOV option

moved costy patterscans to external thread
added check to game version
fixed whitespaces/tabstops
This commit is contained in:
uberhalit 2019-04-02 21:37:37 +02:00
parent af0e5a25da
commit af5458ada6
6 changed files with 243 additions and 222 deletions

View file

@ -1,7 +1,7 @@
# Sekiro FPS Unlocker and more # Sekiro FPS Unlocker and more
A small utility to remove frame rate limit, add custom resolutions with 21/9 widescreen support, change field of view (FOV), borderless window mode and various game modifications for [Sekiro: Shadows Die Twice](https://www.sekirothegame.com/) written in C#. A small utility to remove frame rate limit, add custom resolutions with 21/9 widescreen support, change field of view (FOV), borderless window mode and various game modifications for [Sekiro: Shadows Die Twice](https://www.sekirothegame.com/) written in C#.
Patches games memory while running, does not modify any game files. Wrks with every game version (legit steam & oh-not-so-legit), should work with all future updates. Also available [Nexus Mods](https://www.nexusmods.com/sekiro/mods/13/). Patches games memory while running, does not modify any game files. Works with every game version (legit steam & oh-not-so-legit), should work with all future updates. Also available [Nexus Mods](https://www.nexusmods.com/sekiro/mods/13/).
## Download ## Download
@ -130,7 +130,7 @@ The game enforces VSYNC and forces 60 Hz in fullscreen even on 144 Hz monitors s
7. Select either `DeathCounter.txt` (only tracks true deaths, excluding revives) or `TotalKillsCounter.txt` 7. Select either `DeathCounter.txt` (only tracks true deaths, excluding revives) or `TotalKillsCounter.txt`
8. Customize font style, color and position 8. Customize font style, color and position
9. To add additional counters repeat steps 4-7 9. To add additional counters repeat steps 4-7
10. [[!On Stream Display with OBS](https://camo.githubusercontent.com/007910d42ace53ee0db0ea8b61d525751b9d48a6/68747470733a2f2f692e696d6775722e636f6d2f4c39546e6f34462e706e67)](#) 10. [![On Stream Display with OBS](https://camo.githubusercontent.com/007910d42ace53ee0db0ea8b61d525751b9d48a6/68747470733a2f2f692e696d6775722e636f6d2f4c39546e6f34462e706e67)](#)
### To use any of the game modifications ### To use any of the game modifications
1. Start the game 1. Start the game

View file

@ -9,6 +9,7 @@ namespace SekiroFpsUnlockAndMore
internal const string PROCESS_NAME = "sekiro"; internal const string PROCESS_NAME = "sekiro";
internal const string PROCESS_TITLE = "Sekiro"; internal const string PROCESS_TITLE = "Sekiro";
internal const string PROCESS_DESCRIPTION = "Shadows Die Twice"; internal const string PROCESS_DESCRIPTION = "Shadows Die Twice";
internal const string PROCESS_EXE_VERSION = "1.2.0.0";
/** /**
@ -142,7 +143,7 @@ namespace SekiroFpsUnlockAndMore
internal const int PATTERN_FOVSETTING_OFFSET = 8; internal const int PATTERN_FOVSETTING_OFFSET = 8;
/** /**
00000001430F7C60 00000001430F7C60
Key: Patch to pFovTableEntry last 2 bytes Key: Patch to pFovTableEntry (last 2 bytes)
Value: Value resolve in float table from pFovTableEntry->fFov Value: Value resolve in float table from pFovTableEntry->fFov
*/ */
internal static Dictionary<byte[], string> PATCH_FOVSETTING_MATRIX = new Dictionary<byte[], string> internal static Dictionary<byte[], string> PATCH_FOVSETTING_MATRIX = new Dictionary<byte[], string>
@ -150,6 +151,7 @@ namespace SekiroFpsUnlockAndMore
{ new byte[2] {0x00, 0xE7}, "- 50%" }, { new byte[2] {0x00, 0xE7}, "- 50%" },
{ new byte[2] {0x04, 0xE7}, "- 10%" }, { new byte[2] {0x04, 0xE7}, "- 10%" },
{ new byte[2] {0x10, 0xE7}, "+ 15%" }, { new byte[2] {0x10, 0xE7}, "+ 15%" },
{ new byte[2] {0x42, 0x9B}, "+ 25%" },
{ new byte[2] {0x14, 0xE7}, "+ 40%" }, { new byte[2] {0x14, 0xE7}, "+ 40%" },
{ new byte[2] {0x18, 0xE7}, "+ 75%" }, { new byte[2] {0x18, 0xE7}, "+ 75%" },
{ new byte[2] {0x1C, 0xE7}, "+ 90%" } { new byte[2] {0x1C, 0xE7}, "+ 90%" }

View file

@ -6,6 +6,7 @@ using System.Threading;
using System.Diagnostics; using System.Diagnostics;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Input; using System.Windows.Input;
using System.ComponentModel;
using System.Windows.Interop; using System.Windows.Interop;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Threading; using System.Windows.Threading;
@ -36,9 +37,10 @@ namespace SekiroFpsUnlockAndMore
internal SettingsService _settingsService; internal SettingsService _settingsService;
internal StatusViewModel _statusViewModel = new StatusViewModel(); internal StatusViewModel _statusViewModel = new StatusViewModel();
internal readonly System.Timers.Timer _timerStatsCheck = new System.Timers.Timer(); internal readonly DispatcherTimer _dispatcherTimerGameCheck = new DispatcherTimer();
internal readonly DispatcherTimer _dispatcherTimerFreezeMem = new DispatcherTimer(); internal readonly DispatcherTimer _dispatcherTimerFreezeMem = new DispatcherTimer();
internal readonly DispatcherTimer _dispatcherTimerCheck = new DispatcherTimer(); internal readonly BackgroundWorker _bgwScanGame = new BackgroundWorker();
internal readonly System.Timers.Timer _timerStatsCheck = new System.Timers.Timer();
internal bool _running = false; internal bool _running = false;
internal bool _gameInitializing = false; internal bool _gameInitializing = false;
internal string _logPath; internal string _logPath;
@ -63,7 +65,7 @@ namespace SekiroFpsUnlockAndMore
var mutex = new Mutex(true, "sekiroFpsUnlockAndMore", out bool isNewInstance); var mutex = new Mutex(true, "sekiroFpsUnlockAndMore", out bool isNewInstance);
if (!isNewInstance) if (!isNewInstance)
{ {
MessageBox.Show("Another instance is already running!", "Sekiro FPS Unlocker and more"); MessageBox.Show("Another instance is already running!", "Sekiro FPS Unlocker and more", MessageBoxButton.OK, MessageBoxImage.Exclamation);
Environment.Exit(0); Environment.Exit(0);
} }
GC.KeepAlive(mutex); GC.KeepAlive(mutex);
@ -79,17 +81,24 @@ namespace SekiroFpsUnlockAndMore
IntPtr hWnd = new WindowInteropHelper(this).Handle; IntPtr hWnd = new WindowInteropHelper(this).Handle;
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", MessageBoxButton.OK, MessageBoxImage.Warning);
ComponentDispatcher.ThreadFilterMessage += new ThreadMessageEventHandler(ComponentDispatcherThreadFilterMessage); ComponentDispatcher.ThreadFilterMessage += new ThreadMessageEventHandler(ComponentDispatcherThreadFilterMessage);
_dispatcherTimerCheck.Tick += new EventHandler(async (object s, EventArgs a) => _bgwScanGame.DoWork += new DoWorkEventHandler(ReadGame);
_bgwScanGame.RunWorkerCompleted += new RunWorkerCompletedEventHandler(OnReadGameFinish);
_dispatcherTimerGameCheck.Tick += new EventHandler(async (object s, EventArgs a) =>
{ {
bool result = await CheckGame(); bool result = await CheckGame();
if (result) PatchGame(); if (result)
{
_bgwScanGame.RunWorkerAsync();
_dispatcherTimerGameCheck.Stop();
}
}); });
_dispatcherTimerCheck.Interval = new TimeSpan(0, 0, 0, 0, 2000); _dispatcherTimerGameCheck.Interval = new TimeSpan(0, 0, 0, 0, 2000);
_dispatcherTimerCheck.Start(); _dispatcherTimerGameCheck.Start();
_dispatcherTimerFreezeMem.Tick += new EventHandler(FreezeMemory); _dispatcherTimerFreezeMem.Tick += new EventHandler(FreezeMemory);
_dispatcherTimerFreezeMem.Interval = new TimeSpan(0, 0, 0, 0, 2000); _dispatcherTimerFreezeMem.Interval = new TimeSpan(0, 0, 0, 0, 2000);
@ -179,6 +188,9 @@ namespace SekiroFpsUnlockAndMore
/// </summary> /// </summary>
private Task<bool> CheckGame() private Task<bool> CheckGame()
{ {
// game process have been found last check and can be read now, aborting
if (_gameInitializing) return Task.FromResult(true);
Process[] procList = Process.GetProcessesByName(GameData.PROCESS_NAME); Process[] procList = Process.GetProcessesByName(GameData.PROCESS_NAME);
if (procList.Length < 1) if (procList.Length < 1)
return Task.FromResult(false); return Task.FromResult(false);
@ -220,7 +232,7 @@ namespace SekiroFpsUnlockAndMore
if (!_retryAccess) if (!_retryAccess)
{ {
UpdateStatus("no access to game...", Brushes.Red); UpdateStatus("no access to game...", Brushes.Red);
_dispatcherTimerCheck.Stop(); _dispatcherTimerGameCheck.Stop();
return Task.FromResult(false); return Task.FromResult(false);
} }
_gameHwnd = IntPtr.Zero; _gameHwnd = IntPtr.Zero;
@ -235,14 +247,23 @@ namespace SekiroFpsUnlockAndMore
return Task.FromResult(false); return Task.FromResult(false);
} }
// give the game some time to initialize string gameFileVersion = FileVersionInfo.GetVersionInfo(procList[0].MainModule.FileName).FileVersion;
if (!_gameInitializing) if (gameFileVersion != GameData.PROCESS_EXE_VERSION && !_settingsService.ApplicationSettings.gameVersionNotify)
{ {
MessageBox.Show("Unknown game version.\nSome functions might not work properly or even crash the game. Check for updates on this utility regularly following the link at the bottom.", "Sekiro FPS Unlocker and more", MessageBoxButton.OK, MessageBoxImage.Warning);
_settingsService.ApplicationSettings.gameVersionNotify = true;
}
// give the game some time to initialize
_gameInitializing = true; _gameInitializing = true;
return Task.FromResult(false); return Task.FromResult(false);
} }
//string gameFileVersion = FileVersionInfo.GetVersionInfo(procList[0].MainModule.FileName).FileVersion; /// <summary>
/// Read all game offsets and pointer (external).
/// </summary>
private void ReadGame(object sender, DoWorkEventArgs doWorkEventArgs)
{
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;
@ -253,83 +274,41 @@ namespace SekiroFpsUnlockAndMore
Debug.WriteLine("2. fFrameTick 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("fFrameTick not found...", Brushes.Red);
LogToFile("fFrameTick not found...");
_offset_framelock = 0x0; _offset_framelock = 0x0;
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("pFrametimeRunningSpeed 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("pFrametimeRunningSpeed no found...", Brushes.Red);
LogToFile("pFrametimeRunningSpeed not found...");
_offset_framelock_speed_fix = 0x0; _offset_framelock_speed_fix = 0x0;
this.cbFramelock.IsEnabled = false;
}
bool enableResolutionPatch = true; _offset_resolution_default = patternScan.FindPatternInternal((int)SystemParameters.PrimaryScreenWidth > 1280 ? GameData.PATTERN_RESOLUTION_DEFAULT : GameData.PATTERN_RESOLUTION_DEFAULT_720, GameData.PATTERN_RESOLUTION_DEFAULT_MASK, ' ');
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, ' ');
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);
LogToFile("default resolution not found...");
enableResolutionPatch = false;
_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);
LogToFile("scaling fix not found...");
enableResolutionPatch = false;
_offset_resolution_scaling_fix = 0x0; _offset_resolution_scaling_fix = 0x0;
}
long ref_pCurrentResolutionWidth = 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("ref_pCurrentResolutionWidth found at: 0x" + ref_pCurrentResolutionWidth.ToString("X")); Debug.WriteLine("ref_pCurrentResolutionWidth found at: 0x" + ref_pCurrentResolutionWidth.ToString("X"));
if (!IsValidAddress(ref_pCurrentResolutionWidth)) if (IsValidAddress(ref_pCurrentResolutionWidth))
{
UpdateStatus("re_pCurrentResolutionWidth not found...", Brushes.Red);
LogToFile("ref_pCurrentResolutionWidth not found...");
enableResolutionPatch = false;
}
else
{ {
_offset_resolution = DereferenceStaticX64Pointer(_gameAccessHwnd, ref_pCurrentResolutionWidth, GameData.PATTERN_RESOLUTION_POINTER_INSTRUCTION_LENGTH); _offset_resolution = DereferenceStaticX64Pointer(_gameAccessHwnd, ref_pCurrentResolutionWidth, GameData.PATTERN_RESOLUTION_POINTER_INSTRUCTION_LENGTH);
Debug.WriteLine("pCurrentResolutionWidth at: 0x" + _offset_resolution.ToString("X")); Debug.WriteLine("pCurrentResolutionWidth at: 0x" + _offset_resolution.ToString("X"));
if (!IsValidAddress(_offset_resolution)) if (!IsValidAddress(_offset_resolution))
{
UpdateStatus("pCurrentResolutionWidth not valid...", Brushes.Red);
LogToFile("pCurrentResolutionWidth not valid...");
_offset_resolution = 0x0; _offset_resolution = 0x0;
} }
}
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("pFovTableEntry 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("pFovTableEntry not found...", Brushes.Red);
LogToFile("pFovTableEntry not found...");
_offset_fovsetting = 0x0; _offset_fovsetting = 0x0;
this.cbFov.IsEnabled = false;
}
long ref_pPlayerStatsRelated = patternScan.FindPatternInternal(GameData.PATTERN_PLAYER_DEATHS, GameData.PATTERN_PLAYER_DEATHS_MASK, ' ') + GameData.PATTERN_PLAYER_DEATHS_OFFSET; long ref_pPlayerStatsRelated = patternScan.FindPatternInternal(GameData.PATTERN_PLAYER_DEATHS, GameData.PATTERN_PLAYER_DEATHS_MASK, ' ') + GameData.PATTERN_PLAYER_DEATHS_OFFSET;
Debug.WriteLine("ref_pPlayerStatsRelated found at: 0x" + ref_pPlayerStatsRelated.ToString("X")); Debug.WriteLine("ref_pPlayerStatsRelated found at: 0x" + ref_pPlayerStatsRelated.ToString("X"));
if (!IsValidAddress(ref_pPlayerStatsRelated)) 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); long pPlayerStatsRelated = DereferenceStaticX64Pointer(_gameAccessHwndStatic, ref_pPlayerStatsRelated, GameData.PATTERN_PLAYER_DEATHS_INSTRUCTION_LENGTH);
Debug.WriteLine("pPlayerStatsRelated found at: 0x" + pPlayerStatsRelated.ToString("X")); Debug.WriteLine("pPlayerStatsRelated found at: 0x" + pPlayerStatsRelated.ToString("X"));
@ -338,40 +317,22 @@ namespace SekiroFpsUnlockAndMore
int playerStatsToDeathsOffset = Read<Int32>(_gameAccessHwndStatic, ref_pPlayerStatsRelated + GameData.PATTERN_PLAYER_DEATHS_POINTER_OFFSET_OFFSET); int playerStatsToDeathsOffset = Read<Int32>(_gameAccessHwndStatic, ref_pPlayerStatsRelated + GameData.PATTERN_PLAYER_DEATHS_POINTER_OFFSET_OFFSET);
Debug.WriteLine("offset pPlayerStats->iPlayerDeaths found : 0x" + playerStatsToDeathsOffset.ToString("X")); Debug.WriteLine("offset pPlayerStats->iPlayerDeaths found : 0x" + playerStatsToDeathsOffset.ToString("X"));
if (playerStatsToDeathsOffset > 0) _offset_player_deaths = Read<Int64>(_gameAccessHwndStatic, pPlayerStatsRelated) + playerStatsToDeathsOffset; if (playerStatsToDeathsOffset > 0)
_offset_player_deaths = Read<Int64>(_gameAccessHwndStatic, pPlayerStatsRelated) + playerStatsToDeathsOffset;
Debug.WriteLine("iPlayerDeaths found at: 0x" + _offset_player_deaths.ToString("X")); Debug.WriteLine("iPlayerDeaths found at: 0x" + _offset_player_deaths.ToString("X"));
} }
} }
if (!IsValidAddress(_offset_player_deaths)) if (!IsValidAddress(_offset_player_deaths))
{
UpdateStatus("Player Deaths not found...", Brushes.Red);
LogToFile("Player Deaths not found...");
_offset_player_deaths = 0x0; _offset_player_deaths = 0x0;
this.cbLogStats.IsEnabled = false;
}
long ref_pTotalKills = patternScan.FindPatternInternal(GameData.PATTERN_TOTAL_KILLS, GameData.PATTERN_TOTAL_KILLS_MASK, ' '); long ref_pTotalKills = patternScan.FindPatternInternal(GameData.PATTERN_TOTAL_KILLS, GameData.PATTERN_TOTAL_KILLS_MASK, ' ');
Debug.WriteLine("ref_pTotalKills found at: 0x" + ref_pTotalKills.ToString("X")); Debug.WriteLine("ref_pTotalKills found at: 0x" + ref_pTotalKills.ToString("X"));
if (!IsValidAddress(ref_pTotalKills)) if (IsValidAddress(ref_pTotalKills))
{
UpdateStatus("ref_pTotalKills not found...", Brushes.Red);
LogToFile("ref_pTotalKills not found...");
this.cbLogStats.IsEnabled = false;
}
else
{ {
_offset_total_kills = DereferenceStaticX64Pointer(_gameAccessHwndStatic, ref_pTotalKills, GameData.PATTERN_TOTAL_KILLS_INSTRUCTION_LENGTH); _offset_total_kills = DereferenceStaticX64Pointer(_gameAccessHwndStatic, ref_pTotalKills, GameData.PATTERN_TOTAL_KILLS_INSTRUCTION_LENGTH);
if (!IsValidAddress(_offset_total_kills)) if (!IsValidAddress(_offset_total_kills))
{
UpdateStatus("pTotalKills not valid...", Brushes.Red);
LogToFile("pTotalKills not valid...");
_offset_total_kills = 0x0; _offset_total_kills = 0x0;
this.cbLogStats.IsEnabled = false;
} }
}
if (_offset_player_deaths > 0x0 && _offset_total_kills > 0x0) _timerStatsCheck.Start();
this.cbBorderless.IsEnabled = true;
long ref_pTimeRelated = patternScan.FindPatternInternal(GameData.PATTERN_TIMESCALE, GameData.PATTERN_TIMESCALE_MASK, ' '); long ref_pTimeRelated = patternScan.FindPatternInternal(GameData.PATTERN_TIMESCALE, GameData.PATTERN_TIMESCALE_MASK, ' ');
Debug.WriteLine("ref_pTimeRelated found at: 0x" + ref_pTimeRelated.ToString("X")); Debug.WriteLine("ref_pTimeRelated found at: 0x" + ref_pTimeRelated.ToString("X"));
@ -384,17 +345,9 @@ namespace SekiroFpsUnlockAndMore
_offset_timescale = Read<Int64>(_gameAccessHwndStatic, pTimescaleManager) + Read<Int32>(_gameAccessHwndStatic, ref_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("fTimescale 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;
} }
} }
}
if (_offset_timescale == 0x0)
{
UpdateStatus("fTimescale not found...", Brushes.Red);
LogToFile("fTimescale not found...");
this.cbGameSpeed.IsEnabled = false;
}
long pPlayerStructRelated1 = patternScan.FindPatternInternal(GameData.PATTERN_TIMESCALE_PLAYER, GameData.PATTERN_TIMESCALE_PLAYER_MASK, ' '); long pPlayerStructRelated1 = patternScan.FindPatternInternal(GameData.PATTERN_TIMESCALE_PLAYER, GameData.PATTERN_TIMESCALE_PLAYER_MASK, ' ');
Debug.WriteLine("pPlayerStructRelated1 found at: 0x" + pPlayerStructRelated1.ToString("X")); Debug.WriteLine("pPlayerStructRelated1 found at: 0x" + pPlayerStructRelated1.ToString("X"));
@ -420,7 +373,6 @@ namespace SekiroFpsUnlockAndMore
_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("fTimescalePlayer 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;
} }
} }
@ -428,18 +380,86 @@ namespace SekiroFpsUnlockAndMore
} }
} }
} }
/// <summary>
/// All game data has been read.
/// </summary>
private void OnReadGameFinish(object sender, RunWorkerCompletedEventArgs runWorkerCompletedEventArgs)
{
if (_offset_framelock == 0x0)
{
UpdateStatus("frame tick not found...", Brushes.Red);
LogToFile("frame tick not found...");
this.cbFramelock.IsEnabled = false;
}
if (_offset_framelock_speed_fix == 0x0)
{
UpdateStatus("running speed fix no found...", Brushes.Red);
LogToFile("running speed fix not found...");
this.cbFramelock.IsEnabled = false;
}
if ((int)SystemParameters.PrimaryScreenWidth < 1281) _use_resolution_720 = true;
if (_offset_resolution_default == 0x0)
{
UpdateStatus("default resolution not found...", Brushes.Red);
LogToFile("default resolution not found...");
this.cbAddResolution.IsEnabled = false;
}
if (_offset_resolution_scaling_fix == 0x0)
{
UpdateStatus("scaling fix not found...", Brushes.Red);
LogToFile("scaling fix not found...");
this.cbAddResolution.IsEnabled = false;
}
if (_offset_resolution == 0x0)
{
UpdateStatus("current resolution not found...", Brushes.Red);
LogToFile("current resolution not found...");
this.cbAddResolution.IsEnabled = false;
}
if (_offset_fovsetting == 0x0)
{
UpdateStatus("fov table not found...", Brushes.Red);
LogToFile("fov table not found...");
this.cbFov.IsEnabled = false;
}
if (_offset_player_deaths == 0x0)
{
UpdateStatus("player deaths not found...", Brushes.Red);
LogToFile("player deaths not found...");
this.cbLogStats.IsEnabled = false;
}
if (_offset_total_kills == 0x0)
{
UpdateStatus("player kills not found...", Brushes.Red);
LogToFile("player kills not found...");
this.cbLogStats.IsEnabled = false;
}
if (_offset_player_deaths > 0x0 && _offset_total_kills > 0x0)
_timerStatsCheck.Start();
this.cbBorderless.IsEnabled = true;
if (_offset_timescale == 0x0)
{
UpdateStatus("timescale not found...", Brushes.Red);
LogToFile("timescale not found...");
this.cbGameSpeed.IsEnabled = false;
}
if (_offset_timescale_player_pointer_start == 0x0) if (_offset_timescale_player_pointer_start == 0x0)
{ {
UpdateStatus("Playerscale not found...", Brushes.Red); UpdateStatus("player timescale not found...", Brushes.Red);
LogToFile("Playerscale not found..."); //LogToFile("player timescale not found...");
this.cbPlayerSpeed.IsEnabled = false; this.cbPlayerSpeed.IsEnabled = false;
} }
this.bPatch.IsEnabled = true; this.bPatch.IsEnabled = true;
_running = true; _running = true;
_dispatcherTimerCheck.Stop(); PatchGame();
return Task.FromResult(true);
} }
/// <summary> /// <summary>
@ -461,13 +481,11 @@ namespace SekiroFpsUnlockAndMore
{ {
_offset_timescale_player = Read<Int64>(_gameAccessHwndStatic, pPlayerStructRelated5) + GameData.PATTERN_TIMESCALE_POINTER5_OFFSET; _offset_timescale_player = Read<Int64>(_gameAccessHwndStatic, pPlayerStructRelated5) + GameData.PATTERN_TIMESCALE_POINTER5_OFFSET;
if (IsValidAddress(_offset_timescale_player)) if (IsValidAddress(_offset_timescale_player))
{
valid = true; valid = true;
} }
} }
} }
} }
}
if (!valid) _offset_timescale_player = 0x0; if (!valid) _offset_timescale_player = 0x0;
} }
@ -509,7 +527,7 @@ namespace SekiroFpsUnlockAndMore
this.cbGameSpeed.IsEnabled = true; this.cbGameSpeed.IsEnabled = true;
this.cbPlayerSpeed.IsEnabled = true; this.cbPlayerSpeed.IsEnabled = true;
UpdateStatus("waiting for game...", Brushes.White); UpdateStatus("waiting for game...", Brushes.White);
_dispatcherTimerCheck.Start(); _dispatcherTimerGameCheck.Start();
return false; return false;
} }
@ -821,7 +839,7 @@ namespace SekiroFpsUnlockAndMore
/// </summary> /// </summary>
private void StatsReadTimer(object sender, EventArgs e) private void StatsReadTimer(object sender, EventArgs e)
{ {
if (_gameAccessHwndStatic == IntPtr.Zero || _offset_player_deaths == 0x0 || _offset_total_kills == 0x0) return; if (!_running || _gameAccessHwndStatic == IntPtr.Zero || _offset_player_deaths == 0x0 || _offset_total_kills == 0x0) return;
int playerDeaths = Read<Int32>(_gameAccessHwndStatic, _offset_player_deaths); int playerDeaths = Read<Int32>(_gameAccessHwndStatic, _offset_player_deaths);
_statusViewModel.Deaths = playerDeaths; _statusViewModel.Deaths = playerDeaths;
if (_statLoggingEnabled) LogStatsFile(_deathCounterPath, playerDeaths.ToString()); if (_statLoggingEnabled) LogStatsFile(_deathCounterPath, playerDeaths.ToString());
@ -990,7 +1008,7 @@ namespace SekiroFpsUnlockAndMore
/// <returns>The static offset from the process to the referenced object.</returns> /// <returns>The static offset from the process to the referenced object.</returns>
private static Int64 DereferenceStaticX64Pointer(IntPtr hProcess, Int64 lpInstructionAddress, int instructionLength) private static Int64 DereferenceStaticX64Pointer(IntPtr hProcess, Int64 lpInstructionAddress, int instructionLength)
{ {
return lpInstructionAddress + Read<Int32>(hProcess, lpInstructionAddress + (instructionLength -0x04)) + instructionLength; return lpInstructionAddress + Read<Int32>(hProcess, lpInstructionAddress + (instructionLength - 0x04)) + instructionLength;
} }
/// <summary> /// <summary>

View file

@ -13,6 +13,7 @@ namespace SekiroFpsUnlockAndMore
* Settings definition * Settings definition
*/ */
[XmlElement] [XmlElement]
public bool gameVersionNotify { get; set; }
public bool cbFramelock { get; set; } public bool cbFramelock { get; set; }
[XmlElement] [XmlElement]
public int tbFramelock { get; set; } public int tbFramelock { get; set; }