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

@ -1,196 +1,218 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
namespace SekiroFpsUnlockAndMore namespace SekiroFpsUnlockAndMore
{ {
internal class GameData internal class GameData
{ {
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";
/** /**
<float>fFrameTick determines default frame rate limit in seconds <float>fFrameTick determines default frame rate limit in seconds
000000014116168D | C743 18 8988883C | mov dword ptr ds:[rbx+18],3C888889 | fFrameTick 000000014116168D | C743 18 8988883C | mov dword ptr ds:[rbx+18],3C888889 | fFrameTick
0000000141161694 | 4C:89AB 70020000 | mov qword ptr ds:[rbx+270],r13 | 0000000141161694 | 4C:89AB 70020000 | mov qword ptr ds:[rbx+270],r13 |
*/ */
internal const string PATTERN_FRAMELOCK = "88 88 3C 4C 89 AB"; // 88 88 3C 4C 89 AB // first byte (last in mem) can can be 88/90 instead of 89 due to precision loss on floating point numbers internal const string PATTERN_FRAMELOCK = "88 88 3C 4C 89 AB"; // 88 88 3C 4C 89 AB // first byte (last in mem) can can be 88/90 instead of 89 due to precision loss on floating point numbers
internal const string PATTERN_FRAMELOCK_MASK = "xxxxxx"; // mask for frame rate limiter signature scanning internal const string PATTERN_FRAMELOCK_MASK = "xxxxxx"; // mask for frame rate limiter signature scanning
internal const int PATTERN_FRAMELOCK_OFFSET = -1; // offset to byte array from found position internal const int PATTERN_FRAMELOCK_OFFSET = -1; // offset to byte array from found position
internal const string PATTERN_FRAMELOCK_FUZZY = "C7 43 00 00 00 00 00 4C 89 AB"; // C7 43 ?? ?? ?? ?? ?? 4C 89 AB internal const string PATTERN_FRAMELOCK_FUZZY = "C7 43 00 00 00 00 00 4C 89 AB"; // C7 43 ?? ?? ?? ?? ?? 4C 89 AB
internal const string PATTERN_FRAMELOCK_FUZZY_MASK = "xx?????xxx"; internal const string PATTERN_FRAMELOCK_FUZZY_MASK = "xx?????xxx";
internal const int PATTERN_FRAMELOCK_FUZZY_OFFSET = 3; internal const int PATTERN_FRAMELOCK_FUZZY_OFFSET = 3;
/** /**
Reference pointer pFrametimeRunningSpeed to speed table entry that gets used in calculations. Add or remove multiplications of 4bytes to pFrametimeRunningSpeed address to use a higher or lower <float>fFrametimeCriticalRunningSpeed from table Reference pointer pFrametimeRunningSpeed to speed table entry that gets used in calculations. Add or remove multiplications of 4bytes to pFrametimeRunningSpeed address to use a higher or lower <float>fFrametimeCriticalRunningSpeed from table
fFrametimeCriticalRunningSpeed should be roughly half the frame rate: 30 @ 60FPS limit, 50 @ 100FPS limit... fFrametimeCriticalRunningSpeed should be roughly half the frame rate: 30 @ 60FPS limit, 50 @ 100FPS limit...
00000001407D4E08 | F3:0F5905 90309202 | mulss xmm0,dword ptr ds:[1430F7EA0] | pFrametimeRunningSpeed->fFrametimeCriticalRunningSpeed 00000001407D4E08 | F3:0F5905 90309202 | mulss xmm0,dword ptr ds:[1430F7EA0] | pFrametimeRunningSpeed->fFrametimeCriticalRunningSpeed
*/ */
internal const string PATTERN_FRAMELOCK_SPEED_FIX = "F3 0F 59 05 00 30 92 02"; // F3 0F 59 05 ?? 30 92 02 | 0F 51 C2 F3 0F 59 05 ?? ?? ?? ?? 0F 2F F8 internal const string PATTERN_FRAMELOCK_SPEED_FIX = "F3 0F 59 05 00 30 92 02"; // F3 0F 59 05 ?? 30 92 02 | 0F 51 C2 F3 0F 59 05 ?? ?? ?? ?? 0F 2F F8
internal const string PATTERN_FRAMELOCK_SPEED_FIX_MASK = "xxxx?xxx"; internal const string PATTERN_FRAMELOCK_SPEED_FIX_MASK = "xxxx?xxx";
internal const int PATTERN_FRAMELOCK_SPEED_FIX_OFFSET = 4; internal const int PATTERN_FRAMELOCK_SPEED_FIX_OFFSET = 4;
/** /**
00000001430F7E10 00000001430F7E10
Key: Patch to pFrametimeRunningSpeed last byte Key: Patch to pFrametimeRunningSpeed last byte
Value: Value resolve in float table from pFrametimeRunningSpeed->fFrametimeCriticalRunningSpeed Value: Value resolve in float table from pFrametimeRunningSpeed->fFrametimeCriticalRunningSpeed
Hardcoded cause lazy -> if anyone knows how the table is calculated then tell me and I'll buy you a beer Hardcoded cause lazy -> if anyone knows how the table is calculated then tell me and I'll buy you a beer
*/ */
internal static Dictionary<byte[], float> PATCH_FRAMELOCK_SPEED_FIX_MATRIX = new Dictionary<byte[], float> internal static Dictionary<byte[], float> PATCH_FRAMELOCK_SPEED_FIX_MATRIX = new Dictionary<byte[], float>
{ {
{ new byte[1] {0x68}, 15f }, { new byte[1] {0x68}, 15f },
{ new byte[1] {0x6C}, 16f }, { new byte[1] {0x6C}, 16f },
{ new byte[1] {0x70}, 16.6667f }, { new byte[1] {0x70}, 16.6667f },
{ new byte[1] {0x74}, 18f }, { new byte[1] {0x74}, 18f },
{ new byte[1] {0x78}, 18.6875f }, { new byte[1] {0x78}, 18.6875f },
{ new byte[1] {0x7C}, 18.8516f }, { new byte[1] {0x7C}, 18.8516f },
{ new byte[1] {0x80}, 20f }, { new byte[1] {0x80}, 20f },
{ new byte[1] {0x84}, 24f }, { new byte[1] {0x84}, 24f },
{ new byte[1] {0x88}, 25f }, { new byte[1] {0x88}, 25f },
{ new byte[1] {0x8C}, 27.5f }, { new byte[1] {0x8C}, 27.5f },
{ new byte[1] {0x90}, 30f }, { new byte[1] {0x90}, 30f },
{ new byte[1] {0x94}, 32f }, { new byte[1] {0x94}, 32f },
{ new byte[1] {0x98}, 38.5f }, { new byte[1] {0x98}, 38.5f },
{ new byte[1] {0x9C}, 40f }, { new byte[1] {0x9C}, 40f },
{ new byte[1] {0xA0}, 48f }, { new byte[1] {0xA0}, 48f },
{ new byte[1] {0xA4}, 49.5f }, { new byte[1] {0xA4}, 49.5f },
{ new byte[1] {0xA8}, 50f }, { new byte[1] {0xA8}, 50f },
{ new byte[1] {0xAC}, 57.2958f }, { new byte[1] {0xAC}, 57.2958f },
{ new byte[1] {0xB0}, 60f }, { new byte[1] {0xB0}, 60f },
{ new byte[1] {0xB4}, 64f }, { new byte[1] {0xB4}, 64f },
{ new byte[1] {0xB8}, 66.75f }, { new byte[1] {0xB8}, 66.75f },
{ new byte[1] {0xBC}, 67f }, { new byte[1] {0xBC}, 67f },
{ new byte[1] {0xC0}, 78.8438f }, { new byte[1] {0xC0}, 78.8438f },
{ new byte[1] {0xC4}, 80f }, { new byte[1] {0xC4}, 80f },
{ new byte[1] {0xC8}, 84f }, { new byte[1] {0xC8}, 84f },
{ new byte[1] {0xCC}, 90f }, { new byte[1] {0xCC}, 90f },
{ new byte[1] {0xD0}, 93.8f }, { new byte[1] {0xD0}, 93.8f },
{ new byte[1] {0xD4}, 100f }, { new byte[1] {0xD4}, 100f },
{ new byte[1] {0xD8}, 120f }, { new byte[1] {0xD8}, 120f },
{ new byte[1] {0xDC}, 127f }, { new byte[1] {0xDC}, 127f },
{ new byte[1] {0xE0}, 128f }, { new byte[1] {0xE0}, 128f },
{ new byte[1] {0xE4}, 130f }, { new byte[1] {0xE4}, 130f },
{ new byte[1] {0xE8}, 140f }, { new byte[1] {0xE8}, 140f },
{ new byte[1] {0xEC}, 144f }, { new byte[1] {0xEC}, 144f },
{ new byte[1] {0xF0}, 150f } { new byte[1] {0xF0}, 150f }
}; };
internal static byte[] PATCH_FRAMELOCK_SPEED_FIX_DISABLE = new byte[1] { 0x90 }; // 30f internal static byte[] PATCH_FRAMELOCK_SPEED_FIX_DISABLE = new byte[1] { 0x90 }; // 30f
/// <summary> /// <summary>
/// Finds closest valid speed fix value for a frame rate limit. /// Finds closest valid speed fix value for a frame rate limit.
/// </summary> /// </summary>
/// <param name="frameLimit">The set frame rate limit.</param> /// <param name="frameLimit">The set frame rate limit.</param>
/// <returns>The byte patch of the closest speed fix.</returns> /// <returns>The byte patch of the closest speed fix.</returns>
internal static byte[] FindSpeedFixForRefreshRate(int frameLimit) internal static byte[] FindSpeedFixForRefreshRate(int frameLimit)
{ {
float idealSpeedFix = frameLimit / 2f; float idealSpeedFix = frameLimit / 2f;
KeyValuePair<byte[], float> closestSpeedFix = new KeyValuePair<byte[], float>(PATCH_FRAMELOCK_SPEED_FIX_DISABLE, 30f); KeyValuePair<byte[], float> closestSpeedFix = new KeyValuePair<byte[], float>(PATCH_FRAMELOCK_SPEED_FIX_DISABLE, 30f);
foreach (var speedFix in PATCH_FRAMELOCK_SPEED_FIX_MATRIX.OrderBy(kvp => kvp.Value)) foreach (var speedFix in PATCH_FRAMELOCK_SPEED_FIX_MATRIX.OrderBy(kvp => kvp.Value))
{ {
if (Math.Abs(idealSpeedFix - speedFix.Value) < Math.Abs(idealSpeedFix - closestSpeedFix.Value)) if (Math.Abs(idealSpeedFix - speedFix.Value) < Math.Abs(idealSpeedFix - closestSpeedFix.Value))
closestSpeedFix = speedFix; closestSpeedFix = speedFix;
} }
return closestSpeedFix.Key; return closestSpeedFix.Key;
} }
/** /**
Reference pointer pCurrentResolutionWidth to <int>iInternalGameWidth (and <int>iInternalGameHeight which is +4 bytes) Reference pointer pCurrentResolutionWidth to <int>iInternalGameWidth (and <int>iInternalGameHeight which is +4 bytes)
000000014114AC85 | 0F57D2 | xorps xmm2,xmm2 | 000000014114AC85 | 0F57D2 | xorps xmm2,xmm2 |
000000014114AC88 | 890D 92147D02 | mov dword ptr ds:[14391C120],ecx | pCurrentResolutionWidth->iInternalGameWidth 000000014114AC88 | 890D 92147D02 | mov dword ptr ds:[14391C120],ecx | pCurrentResolutionWidth->iInternalGameWidth
000000014114AC8E | 0F57C9 | xorps xmm1,xmm1 | 000000014114AC8E | 0F57C9 | xorps xmm1,xmm1 |
000000014114AC91 | 8915 8D147D02 | mov dword ptr ds:[14391C124],edx | pCurrentResolutionHeight->iInternalGameHeight 000000014114AC91 | 8915 8D147D02 | mov dword ptr ds:[14391C124],edx | pCurrentResolutionHeight->iInternalGameHeight
*/ */
internal const string PATTERN_RESOLUTION_POINTER = "0F 57 D2 89 0D 00 00 00 00 0F 57 C9"; // 0F 57 D2 89 0D ?? ?? ?? ?? 0F 57 C9 internal const string PATTERN_RESOLUTION_POINTER = "0F 57 D2 89 0D 00 00 00 00 0F 57 C9"; // 0F 57 D2 89 0D ?? ?? ?? ?? 0F 57 C9
internal const string PATTERN_RESOLUTION_POINTER_MASK = "xxxxx????xxx"; internal const string PATTERN_RESOLUTION_POINTER_MASK = "xxxxx????xxx";
internal const int PATTERN_RESOLUTION_POINTER_OFFSET = 3; internal const int PATTERN_RESOLUTION_POINTER_OFFSET = 3;
internal const int PATTERN_RESOLUTION_POINTER_INSTRUCTION_LENGTH = 6; internal const int PATTERN_RESOLUTION_POINTER_INSTRUCTION_LENGTH = 6;
/** /**
DATA SECTION. All resolutions are listed in memory as <int>width1 <int>height1 <int>width2 <int>height2 ... DATA SECTION. All resolutions are listed in memory as <int>width1 <int>height1 <int>width2 <int>height2 ...
Overwrite an unused one with desired new one. Some glitches, 1920x1080 and 1280x720 works best Overwrite an unused one with desired new one. Some glitches, 1920x1080 and 1280x720 works best
*/ */
internal const string PATTERN_RESOLUTION_DEFAULT = "80 07 00 00 38 04 00 00"; // 1920x1080 internal const string PATTERN_RESOLUTION_DEFAULT = "80 07 00 00 38 04 00 00"; // 1920x1080
internal const string PATTERN_RESOLUTION_DEFAULT_720 = "40 06 00 00 84 03 00 00"; // 1280x720 internal const string PATTERN_RESOLUTION_DEFAULT_720 = "40 06 00 00 84 03 00 00"; // 1280x720
internal const string PATTERN_RESOLUTION_DEFAULT_MASK = "xxxxxxxx"; internal const string PATTERN_RESOLUTION_DEFAULT_MASK = "xxxxxxxx";
internal static byte[] PATCH_RESOLUTION_DEFAULT_DISABLE = new byte[8] { 0x80, 0x07, 0x00, 0x00, 0x38, 0x04, 0x00, 0x00 }; internal static byte[] PATCH_RESOLUTION_DEFAULT_DISABLE = new byte[8] { 0x80, 0x07, 0x00, 0x00, 0x38, 0x04, 0x00, 0x00 };
internal static byte[] PATCH_RESOLUTION_DEFAULT_DISABLE_720 = new byte[8] { 0x40, 0x06, 0x00, 0x00, 0x84, 0x03, 0x00, 0x00 }; internal static byte[] PATCH_RESOLUTION_DEFAULT_DISABLE_720 = new byte[8] { 0x40, 0x06, 0x00, 0x00, 0x84, 0x03, 0x00, 0x00 };
/** /**
Conditional jump instruction that determines if 16/9 scaling for game is enforced or not, overwrite with non conditional JMP so widescreen won't get clinched Conditional jump instruction that determines if 16/9 scaling for game is enforced or not, overwrite with non conditional JMP so widescreen won't get clinched
000000014012967A | 74 47 | je sekiro.1401296C3 | conditional jump 000000014012967A | 74 47 | je sekiro.1401296C3 | conditional jump
000000014012967C | 47:8B94C7 1C020000 | mov r10d,dword ptr ds:[r15+r8*8+21C] | start of long resolution scaling calculation method within jump 000000014012967C | 47:8B94C7 1C020000 | mov r10d,dword ptr ds:[r15+r8*8+21C] | start of long resolution scaling calculation method within jump
*/ */
internal const string PATTERN_RESOLUTION_SCALING_FIX = "47 47 8B 94 C7 1C 02 00 00"; // 47 47 8B 94 C7 1C 02 00 00 internal const string PATTERN_RESOLUTION_SCALING_FIX = "47 47 8B 94 C7 1C 02 00 00"; // 47 47 8B 94 C7 1C 02 00 00
internal const string PATTERN_RESOLUTION_SCALING_FIX_MASK = "xxxxxxxxx"; internal const string PATTERN_RESOLUTION_SCALING_FIX_MASK = "xxxxxxxxx";
internal const int PATTERN_RESOLUTION_SCALING_FIX_OFFSET = -1; internal const int PATTERN_RESOLUTION_SCALING_FIX_OFFSET = -1;
internal static byte[] PATCH_RESOLUTION_SCALING_FIX_ENABLE = new byte[1] { 0xEB }; // JMP internal static byte[] PATCH_RESOLUTION_SCALING_FIX_ENABLE = new byte[1] { 0xEB }; // JMP
internal static byte[] PATCH_RESOLUTION_SCALING_FIX_DISABLE = new byte[1] { 0x74 }; // JE internal static byte[] PATCH_RESOLUTION_SCALING_FIX_DISABLE = new byte[1] { 0x74 }; // JE
/** /**
Reference pointer pFovTableEntry to FOV entry in game FOV table that gets used in FOV calculations. Overwrite pFovTableEntry address to use a higher or lower <float>fFOV from table Reference pointer pFovTableEntry to FOV entry in game FOV table that gets used in FOV calculations. Overwrite pFovTableEntry address to use a higher or lower <float>fFOV from table
0000000140739548 | F3:0F1008 | movss xmm1,dword ptr ds:[rax] | 0000000140739548 | F3:0F1008 | movss xmm1,dword ptr ds:[rax] |
000000014073954C | F3:0F590D 0CE79B02 | mulss xmm1,dword ptr ds:[1430F7C60] | pFovTableEntry->fFov 000000014073954C | F3:0F590D 0CE79B02 | mulss xmm1,dword ptr ds:[1430F7C60] | pFovTableEntry->fFov
*/ */
// credits to 'jackfuste' for original offset // credits to 'jackfuste' for original offset
internal const string PATTERN_FOVSETTING = "F3 0F 10 08 F3 0F 59 0D 00 00 9B 02"; // F3 0F 10 08 F3 0F 59 0D ?? ?? 9B 02 internal const string PATTERN_FOVSETTING = "F3 0F 10 08 F3 0F 59 0D 00 00 9B 02"; // F3 0F 10 08 F3 0F 59 0D ?? ?? 9B 02
internal const string PATTERN_FOVSETTING_MASK = "xxxxxxxx??xx"; internal const string PATTERN_FOVSETTING_MASK = "xxxxxxxx??xx";
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>
{ {
{ 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] {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%" }
}; };
internal static byte[] PATCH_FOVSETTING_DISABLE = new byte[2] { 0x0C, 0xE7 }; // + 0% internal static byte[] PATCH_FOVSETTING_DISABLE = new byte[2] { 0x0C, 0xE7 }; // + 0%
/** /**
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 |
0000000141149E96 | F3:0F5988 68020000 | mulss xmm1,dword ptr ds:[rax+268] | 00000001407AAC9C | 48:8B05 4DD03903 | mov rax,qword ptr ds:[143B47CF0] |
*/ 00000001407AACA3 | 8B88 8C000000 | mov ecx,dword ptr ds:[rax+8C] |
// credits to 'Zullie the Witch' for original offset 00000001407AACA9 | 898B F8000000 | mov dword ptr ds:[rbx+F8],ecx |
internal const string PATTERN_TIMESCALE = "48 8B 05 00 00 00 00 F3 0F 10 88 00 00 00 00 F3 0F"; // 48 8B 05 ?? ?? ?? ?? F3 0F 10 88 ?? ?? ?? ?? F3 0F 00000001407AACAF | 48:8B05 3AD03903 | mov rax,qword ptr ds:[143B47CF0] | pPlayerStatsRelated->[PlayerStats+0x90]->iPlayerDeaths
internal const string PATTERN_TIMESCALE_MASK = "xxx????xxxx????xx"; 00000001407AACB6 | 8B88 90000000 | mov ecx,dword ptr ds:[rax+90] | offset pPlayerStats->iPlayerDeaths
internal const int PATTERN_TIMESCALE_INSTRUCTION_LENGTH = 7; */
internal const int PATTERN_TIMESCALE_POINTER_OFFSET_OFFSET = 11; // 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";
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 internal const int PATTERN_PLAYER_DEATHS_OFFSET = 29;
00000001406BF1D7 | 48:8B1D 128C4A03 | mov rbx,qword ptr ds:[143B67DF0] | pPlayerStructRelated1->[pPlayerStructRelated2+0x88]->[pPlayerStructRelated3+0x1FF8]->[pPlayerStructRelated4+0x28]->[pPlayerStructRelated5+0xD00]->fTimescalePlayer internal const int PATTERN_PLAYER_DEATHS_INSTRUCTION_LENGTH = 7;
00000001406BF1DE | 48:85DB | test rbx,rbx | internal const int PATTERN_PLAYER_DEATHS_POINTER_OFFSET_OFFSET = 9;
00000001406BF1E1 | 74 3C | je sekiro.1406BF21F |
00000001406BF1E3 | 8B17 | mov edx,dword ptr ds:[rdi] | /**
*/ Reference pointer pTotalKills to <int>iTotalKills, does not get updated on every kill but mostly on every 2nd, includes own player deaths...
// credits to 'Zullie the Witch' for original offset 0000000141151838 | 48:8D0D A9A5B302 | lea rcx,qword ptr ds:[143C8BDE8] | pTotalKills->iTotalKills
internal const string PATTERN_TIMESCALE_PLAYER = "48 8B 1D 00 00 00 00 48 85 DB 74 3C 8B 17"; // 48 8B 1D ?? ?? ?? ?? 48 85 DB 74 3C 8B 17 000000014115183F | 891481 | mov dword ptr ds:[rcx+rax*4],edx |
internal const string PATTERN_TIMESCALE_PLAYER_MASK = "xxx????xxxxxxx"; 0000000141151842 | C3 | ret |
internal const int PATTERN_TIMESCALE_PLAYER_INSTRUCTION_LENGTH = 7; */
internal const int PATTERN_TIMESCALE_POINTER2_OFFSET = 0x88; // credits to 'Me_TheCat' for original offset
internal const int PATTERN_TIMESCALE_POINTER3_OFFSET = 0x1FF8; 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 int PATTERN_TIMESCALE_POINTER4_OFFSET = 0x28; 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] |
*/
// credits to 'Zullie the Witch' for original offset
internal const string PATTERN_TIMESCALE = "48 8B 05 00 00 00 00 F3 0F 10 88 00 00 00 00 F3 0F"; // 48 8B 05 ?? ?? ?? ?? F3 0F 10 88 ?? ?? ?? ?? F3 0F
internal const string PATTERN_TIMESCALE_MASK = "xxx????xxxx????xx";
internal const int PATTERN_TIMESCALE_INSTRUCTION_LENGTH = 7;
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
00000001406BF1D7 | 48:8B1D 128C4A03 | mov rbx,qword ptr ds:[143B67DF0] | pPlayerStructRelated1->[pPlayerStructRelated2+0x88]->[pPlayerStructRelated3+0x1FF8]->[pPlayerStructRelated4+0x28]->[pPlayerStructRelated5+0xD00]->fTimescalePlayer
00000001406BF1DE | 48:85DB | test rbx,rbx |
00000001406BF1E1 | 74 3C | je sekiro.1406BF21F |
00000001406BF1E3 | 8B17 | mov edx,dword ptr ds:[rdi] |
*/
// credits to 'Zullie the Witch' for original offset
internal const string PATTERN_TIMESCALE_PLAYER = "48 8B 1D 00 00 00 00 48 85 DB 74 3C 8B 17"; // 48 8B 1D ?? ?? ?? ?? 48 85 DB 74 3C 8B 17
internal const string PATTERN_TIMESCALE_PLAYER_MASK = "xxx????xxxxxxx";
internal const int PATTERN_TIMESCALE_PLAYER_INSTRUCTION_LENGTH = 7;
internal const int PATTERN_TIMESCALE_POINTER2_OFFSET = 0x88;
internal const int PATTERN_TIMESCALE_POINTER3_OFFSET = 0x1FF8;
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

@ -1,117 +1,109 @@
<Window x:Class="SekiroFpsUnlockAndMore.MainWindow" <Window x:Class="SekiroFpsUnlockAndMore.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
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">
<StackPanel Margin="10,10,10,0" Width="290" Height="Auto">
<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" />
<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 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" />
<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" />
<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 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" />
<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>
<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="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>
<DockPanel Margin="0,5,0,0" LastChildFill="False">
<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" />
</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">
<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" />
<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" />
<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}}"
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}}"
Focusable="False" Click="BGs0_Click" />
</DockPanel>
<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" />
<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" />
<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" />
<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}}"
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}}"
Focusable="False" Click="BPs0_Click" />
</DockPanel>
</StackPanel>
</Grid>
</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}}"
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" />
<TextBlock HorizontalAlignment="Left" TextWrapping="WrapWithOverflow" Margin="2,5,2,0" VerticalAlignment="Top" FontSize="11 px" IsEnabled="False">
<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">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">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 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">using Nvidia Control panel or AMD Radeon Settings.</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>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" Foreground="#FFF00000">See the link below for detailed information, guides, GSYNC support and an AMD fix.</Run>
</TextBlock.Inlines>
</TextBlock>
<Label HorizontalAlignment="Right" FontSize="12 px">
<Hyperlink NavigateUri="https://github.com/uberhalit/SekiroFpsUnlockAndMore" RequestNavigate="Hyperlink_RequestNavigate">
v1.1.0 - by uberhalit
</Hyperlink>
</Label>
<StatusBar DockPanel.Dock="Bottom" Margin="-10,0,-10,0" VerticalAlignment="Bottom">
<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"> <Grid Background="#FFF9F9F9">
<TextBlock Name="sbDeathCount"> <DockPanel>
<Run Text="Deaths:"/> <StackPanel DockPanel.Dock="Top" Margin="10,10,10,0" Width="290" Height="Auto">
<Run Text="{Binding Deaths}"/> <DockPanel LastChildFill="False">
</TextBlock> <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" />
</StatusBarItem> <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" />
<Separator Grid.Column="1" /> </DockPanel>
<StatusBarItem Grid.Column="2"> <DockPanel Margin="0,5,0,0" LastChildFill="False">
<TextBlock Name="sbKillCount"> <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" />
<Run Text="Kills:"/> <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" />
<Run Text="{Binding Kills}"/> <Label DockPanel.Dock="Right" Margin="0,0,0,0" Height="25" FontSize="14 px" Content="x" />
</TextBlock> <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" />
</StatusBarItem> </DockPanel>
</StatusBar> <DockPanel Margin="0,5,0,0" LastChildFill="False">
</StackPanel> <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" />
</Grid> <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"/>
</Window> </DockPanel>
<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" 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" />
</StackPanel>
<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" />
<Expander x:Name="exGameMods" Margin="-3,5,0,0" Height="Auto" FontSize="14 px" Header="Game modifications" IsExpanded="False">
<Grid Margin="3,0,0,0" Background="#FFF9F9F9">
<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" />
<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" />
<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}}"
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}}"
Focusable="False" Click="BGs0_Click" />
</DockPanel>
<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 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}}"
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}}"
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" />
<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" />
<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" />
</DockPanel>
</StackPanel>
</Grid>
</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}}"
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" />
<TextBlock Margin="2,5,2,0" FontSize="11 px" TextWrapping="WrapWithOverflow" IsEnabled="False">
<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">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">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 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">using Nvidia Control panel or AMD Radeon Settings.</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>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" Foreground="#FFF00000">See the link below for detailed information, guides, GSYNC support and an AMD fix.</Run>
</TextBlock.Inlines>
</TextBlock>
<Label HorizontalAlignment="Right" FontSize="12 px">
<Hyperlink NavigateUri="https://github.com/uberhalit/SekiroFpsUnlockAndMore" RequestNavigate="Hyperlink_RequestNavigate">
v1.1.1 - by uberhalit
</Hyperlink>
</Label>
</StackPanel>
<StatusBar DockPanel.Dock="Bottom" Height="25">
<StatusBarItem DockPanel.Dock="Left">
<TextBlock Name="sbDeathCount">
<Run Text="Deaths:" />
<Run Text="{Binding Deaths}" />
</TextBlock>
</StatusBarItem>
<Separator Margin="5,4,5,4" Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}"/>
<StatusBarItem DockPanel.Dock="Left">
<TextBlock Name="sbKillCount">
<Run Text="Kills:" />
<Run Text="{Binding Kills}" />
</TextBlock>
</StatusBarItem>
<Separator Margin="5,4,5,4" Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}"/>
<StatusBarItem DockPanel.Dock="Right" HorizontalAlignment="Right">
<TextBlock Name="sbStatus" />
</StatusBarItem>
</StatusBar>
</DockPanel>
</Grid>
</Window>

File diff suppressed because it is too large Load diff

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

@ -1,112 +1,109 @@
using System; using System;
using System.IO; using System.IO;
using System.Windows; using System.Windows;
using System.Xml.Serialization; using System.Xml.Serialization;
namespace SekiroFpsUnlockAndMore
{
[XmlRoot("SekiroFpsUnlockAndMore")]
[Serializable]
public class SettingsService
{
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
*/
[XmlElement]
public bool cbFramelock { get; set; }
[XmlElement]
public int tbFramelock { get; set; }
[XmlElement]
public bool cbAddResolution { get; set; }
[XmlElement]
public int tbWidth { get; set; }
[XmlElement]
public int tbHeight { get; set; }
[XmlElement]
public bool cbFov { get; set; }
[XmlElement]
public int cbSelectFov { get; set; }
[XmlElement]
public bool cbBorderless { get; set; }
[XmlElement]
public bool cbBorderlessStretch { get; set; }
[XmlElement]
public bool exGameMods { get; set; }
[XmlElement]
public bool cbGameSpeed { get; set; }
[XmlElement]
public int tbGameSpeed { get; set; }
[XmlElement]
public bool cbPlayerSpeed { get; set; }
[XmlElement]
public int tbPlayerSpeed { get; set; }
[XmlElement]
public bool cbLogStats { get; set; }
public SettingsService() { } namespace SekiroFpsUnlockAndMore
{
/// <summary> [XmlRoot("SekiroFpsUnlockAndMore")]
/// Create a settings provider to load and save settings. [Serializable]
/// </summary> public class ApplicationSettings
/// <param name="settingsFilePath">The file path to the settings file.</param> {
public SettingsService(string settingsFilePath = null) /**
{ * Settings definition
if (settingsFilePath != null) */
{ [XmlElement]
sConfigurationPath = settingsFilePath; public bool cbFramelock { get; set; }
settings = new SettingsService(); [XmlElement]
} public int tbFramelock { get; set; }
} [XmlElement]
public bool cbAddResolution { get; set; }
/// <summary> [XmlElement]
/// Load settings from file into settings property. public int tbWidth { get; set; }
/// </summary> [XmlElement]
/// <returns></returns> public int tbHeight { get; set; }
internal bool Load() [XmlElement]
{ public bool cbFov { get; set; }
if (!File.Exists(sConfigurationPath)) return false; [XmlElement]
public int cbSelectFov { get; set; }
XmlSerializer xmlSerializer = new XmlSerializer(typeof(SettingsService)); [XmlElement]
using (StreamReader streamReader = new StreamReader(sConfigurationPath)) public bool cbBorderless { get; set; }
{ [XmlElement]
try public bool cbBorderlessStretch { get; set; }
{ [XmlElement]
settings = (SettingsService)xmlSerializer.Deserialize(streamReader); public bool cbLogStats { get; set; }
return true; [XmlElement]
} public bool exGameMods { get; set; }
catch (Exception ex) [XmlElement]
{ public bool cbGameSpeed { get; set; }
MessageBox.Show("Error while loading configuration file:\n" + ex.Message, "Sekiro FPS Unlocker and more"); [XmlElement]
} public int tbGameSpeed { get; set; }
} [XmlElement]
return false; public bool cbPlayerSpeed { get; set; }
} [XmlElement]
public int tbPlayerSpeed { get; set; }
/// <summary> }
/// Save settings from settings property to file.
/// </summary> public class SettingsService
internal void Save() {
{ private readonly string _sConfigurationPath = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location) + @"\config.xml";
XmlSerializer xmlSerializer = new XmlSerializer(typeof(SettingsService));
using (StreamWriter streamReader = new StreamWriter(sConfigurationPath)) /// <summary>
{ /// Read and store settings here.
try /// </summary>
{ public ApplicationSettings ApplicationSettings;
xmlSerializer.Serialize(streamReader, settings);
} /// <summary>
catch (Exception ex) /// Create a settings provider to load and save settings.
{ /// </summary>
MessageBox.Show("Error while writing configuration file:\n" + ex.Message, "Sekiro FPS Unlocker and more"); /// <param name="settingsFilePath">The file path to the settings file.</param>
} public SettingsService(string settingsFilePath = null)
} {
} if (settingsFilePath != null) _sConfigurationPath = settingsFilePath;
} ApplicationSettings = new ApplicationSettings();
} }
/// <summary>
/// Load settings from file into settings property.
/// </summary>
/// <returns></returns>
internal bool Load()
{
if (!File.Exists(_sConfigurationPath)) return false;
XmlSerializer xmlSerializer = new XmlSerializer(typeof(ApplicationSettings));
using (StreamReader streamReader = new StreamReader(_sConfigurationPath))
{
try
{
ApplicationSettings = (ApplicationSettings)xmlSerializer.Deserialize(streamReader);
return true;
}
catch (Exception ex)
{
MessageBox.Show("Error while loading configuration file:\n" + ex.Message, "Sekiro FPS Unlocker and more");
}
}
return false;
}
/// <summary>
/// Save settings from settings property to file.
/// </summary>
internal void Save()
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(ApplicationSettings));
using (StreamWriter streamReader = new StreamWriter(_sConfigurationPath))
{
try
{
xmlSerializer.Serialize(streamReader, ApplicationSettings);
}
catch (Exception ex)
{
MessageBox.Show("Error while writing configuration file:\n" + ex.Message, "Sekiro FPS Unlocker and more");
}
}
}
}
}

View file

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