From 4c5d3e8ae443a9c25eb6f0edccbf4754db899dae Mon Sep 17 00:00:00 2001
From: illusion0001 <37698908+illusion0001@users.noreply.github.com>
Date: Sat, 21 Oct 2023 20:59:42 -0500
Subject: [PATCH] Add NierReplicant.Fix
---
.github/README.md | 8 +
Windows-Game-Patches.sln | 10 +
include/helper.hpp | 2 +
.../NierReplicant.Fix.filters | 38 ++++
.../NierReplicant.Fix/NierReplicant.Fix.sln | 31 +++
.../NierReplicant.Fix/NierReplicant.Fix.user | 4 +
.../NierReplicant.Fix.vcxproj | 197 ++++++++++++++++++
.../NierReplicant.Fix.vcxproj.user | 4 +
source/NierReplicant.Fix/dllmain.cpp | 119 +++++++++++
source/Shared/helper.cpp | 16 ++
10 files changed, 429 insertions(+)
create mode 100644 source/NierReplicant.Fix/NierReplicant.Fix.filters
create mode 100644 source/NierReplicant.Fix/NierReplicant.Fix.sln
create mode 100644 source/NierReplicant.Fix/NierReplicant.Fix.user
create mode 100644 source/NierReplicant.Fix/NierReplicant.Fix.vcxproj
create mode 100644 source/NierReplicant.Fix/NierReplicant.Fix.vcxproj.user
create mode 100644 source/NierReplicant.Fix/dllmain.cpp
diff --git a/.github/README.md b/.github/README.md
index 7315b91..c62c99e 100644
--- a/.github/README.md
+++ b/.github/README.md
@@ -124,6 +124,14 @@
- `winmm.dll`
- `WoLong.Fix.asi`
+### **NieR Replicant ver.1.22474487139**
+ - Remove FPS Limit
+#### Installation
+- **Note:** ***Please make sure any executable hex edits are removed/reverted first***.
+ - Extract the following contents of the release zip in to the the game root folder.
+ - `winmm.dll`
+ - `NierReplicant.Fix.asi`
+
# Credits
- [Lyall](https://github.com/Lyall) for Project Template.
- [Ultimate ASI Loader](https://github.com/ThirteenAG/Ultimate-ASI-Loader) for ASI loading.
diff --git a/Windows-Game-Patches.sln b/Windows-Game-Patches.sln
index 35dfe97..4446e65 100644
--- a/Windows-Game-Patches.sln
+++ b/Windows-Game-Patches.sln
@@ -23,6 +23,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EldenRing.NoTAA", "source\E
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DeathStranding.Fix", "source\DeathStranding.Fix\DeathStranding.Fix.vcxproj", "{978C20F5-8939-458B-B124-B48BB16CCB98}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NierReplicant.Fix", "source\NierReplicant.Fix\NierReplicant.Fix.vcxproj", "{60BFBAD9-ACE9-4EE1-B643-05A1BD7A2993}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -111,6 +113,14 @@ Global
{978C20F5-8939-458B-B124-B48BB16CCB98}.Release|x64.Build.0 = Release|x64
{978C20F5-8939-458B-B124-B48BB16CCB98}.Release|x86.ActiveCfg = Release|Win32
{978C20F5-8939-458B-B124-B48BB16CCB98}.Release|x86.Build.0 = Release|Win32
+ {60BFBAD9-ACE9-4EE1-B643-05A1BD7A2993}.Debug|x64.ActiveCfg = Debug|x64
+ {60BFBAD9-ACE9-4EE1-B643-05A1BD7A2993}.Debug|x64.Build.0 = Debug|x64
+ {60BFBAD9-ACE9-4EE1-B643-05A1BD7A2993}.Debug|x86.ActiveCfg = Debug|Win32
+ {60BFBAD9-ACE9-4EE1-B643-05A1BD7A2993}.Debug|x86.Build.0 = Debug|Win32
+ {60BFBAD9-ACE9-4EE1-B643-05A1BD7A2993}.Release|x64.ActiveCfg = Release|x64
+ {60BFBAD9-ACE9-4EE1-B643-05A1BD7A2993}.Release|x64.Build.0 = Release|x64
+ {60BFBAD9-ACE9-4EE1-B643-05A1BD7A2993}.Release|x86.ActiveCfg = Release|Win32
+ {60BFBAD9-ACE9-4EE1-B643-05A1BD7A2993}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/include/helper.hpp b/include/helper.hpp
index b139627..957d4df 100644
--- a/include/helper.hpp
+++ b/include/helper.hpp
@@ -24,6 +24,8 @@ uintptr_t WritePatchPattern(const wchar_t* Patch_Pattern, const unsigned char* P
void WritePatchPattern_Hook(const wchar_t* Patch_Pattern, size_t Patch_Size, const wchar_t* Patch_Name, uint64_t Patch_Offset, void* Function_Target, uint64_t* Return_Address);
void WritePatchPattern_Int(uint32_t mode, const wchar_t* Patch_Pattern, void* Patch_Value, const wchar_t* Patch_Name, uint64_t Patch_Offset);
void WritePatchAddress(uint64_t Patch_Address, const unsigned char* Patch_Bytes, size_t Patch_Size, const wchar_t* Patch_Name, uint64_t Patch_Offset);
+void WritePatchAddressFloat32(uint64_t Patch_Address, const float* Patch_Bytes, const wchar_t* Patch_Name, uint64_t Patch_Offset);
+void WritePatchAddressFloat64(uint64_t Patch_Address, const double* Patch_Bytes, const wchar_t* Patch_Name, uint64_t Patch_Offset);
wchar_t* GetRunningPath(wchar_t* output);
uintptr_t FindAndPrintPatternW(const wchar_t* Patch_Pattern, const wchar_t* Pattern_Name, size_t offset = 0);
void Make32to64Hook(void* source_target, void* second_jmp, void* target_jmp, uint32_t source_size, const wchar_t* source_name, const wchar_t* second_jmp_name, const wchar_t* target_jmp_name);
diff --git a/source/NierReplicant.Fix/NierReplicant.Fix.filters b/source/NierReplicant.Fix/NierReplicant.Fix.filters
new file mode 100644
index 0000000..b9874c4
--- /dev/null
+++ b/source/NierReplicant.Fix/NierReplicant.Fix.filters
@@ -0,0 +1,38 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
\ No newline at end of file
diff --git a/source/NierReplicant.Fix/NierReplicant.Fix.sln b/source/NierReplicant.Fix/NierReplicant.Fix.sln
new file mode 100644
index 0000000..3288d8e
--- /dev/null
+++ b/source/NierReplicant.Fix/NierReplicant.Fix.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.5.33424.131
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NierReplicant.Fix", "NierReplicant.Fix.vcxproj", "{AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Debug|x64.ActiveCfg = Debug|x64
+ {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Debug|x64.Build.0 = Debug|x64
+ {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Debug|x86.ActiveCfg = Debug|Win32
+ {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Debug|x86.Build.0 = Debug|Win32
+ {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Release|x64.ActiveCfg = Release|x64
+ {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Release|x64.Build.0 = Release|x64
+ {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Release|x86.ActiveCfg = Release|Win32
+ {AB7A871D-2A06-48C6-863F-B8A0FE8F8E0B}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {CDD207AD-54BC-44A9-933A-5DFEDBD97F44}
+ EndGlobalSection
+EndGlobal
diff --git a/source/NierReplicant.Fix/NierReplicant.Fix.user b/source/NierReplicant.Fix/NierReplicant.Fix.user
new file mode 100644
index 0000000..88a5509
--- /dev/null
+++ b/source/NierReplicant.Fix/NierReplicant.Fix.user
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/source/NierReplicant.Fix/NierReplicant.Fix.vcxproj b/source/NierReplicant.Fix/NierReplicant.Fix.vcxproj
new file mode 100644
index 0000000..97b1d42
--- /dev/null
+++ b/source/NierReplicant.Fix/NierReplicant.Fix.vcxproj
@@ -0,0 +1,197 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {60BFBAD9-ACE9-4EE1-B643-05A1BD7A2993}
+ BrightMemoryInfiniteNoTAA
+ 10.0.22621.0
+
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ DynamicLibrary
+ true
+ ClangCL
+ Unicode
+
+
+ DynamicLibrary
+ false
+ ClangCL
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ \..\include\;$(IncludePath)
+ .asi
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+
+
+ \..\include\;$(IncludePath)
+ .asi
+ $(SolutionDir)$(Configuration)\
+ $(Configuration)\
+
+
+ .asi
+ $(Configuration)\
+
+
+ .asi
+ $(Configuration)\
+
+
+
+ Level3
+ true
+ UNICODE;_UNICODE;_CRT_SECURE_NO_WARNINGS;_USRDLL
+ true
+ NotUsing
+ pch.h
+ ..\..\include\;..\..\external\;%(AdditionalIncludeDirectories)
+
+
+ Windows
+ true
+ false
+
+
+
+
+ Level3
+ true
+ true
+ true
+ UNICODE;_UNICODE;_CRT_SECURE_NO_WARNINGS;_USRDLL
+ true
+ NotUsing
+ pch.h
+ ..\..\include\;..\..\external\;%(AdditionalIncludeDirectories)
+
+
+ Windows
+ true
+ true
+ true
+ false
+
+
+
+
+ Level3
+ true
+ UNICODE;_UNICODE;_USRDLL
+ true
+ NotUsing
+ pch.h
+ ..\..\include\;..\..\external\;%(AdditionalIncludeDirectories)
+ Default
+
+
+ NotSet
+
+
+ Windows
+ true
+ false
+
+
+ call $(MSBuildStartupDirectory)\set_git_ver.cmd
+
+
+
+
+ Level3
+ true
+ false
+ true
+ UNICODE;_UNICODE;_USRDLL
+ true
+ NotUsing
+ pch.h
+ ..\..\include\;..\..\external\;%(AdditionalIncludeDirectories)
+ Default
+
+
+ Disabled
+ NotSet
+
+
+ Windows
+ true
+ true
+ true
+ false
+
+
+ call $(MSBuildStartupDirectory)\set_git_ver.cmd
+
+
+ copy NUL $(OutDirFullPath)$(ProjectName)_winmm.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/source/NierReplicant.Fix/NierReplicant.Fix.vcxproj.user b/source/NierReplicant.Fix/NierReplicant.Fix.vcxproj.user
new file mode 100644
index 0000000..88a5509
--- /dev/null
+++ b/source/NierReplicant.Fix/NierReplicant.Fix.vcxproj.user
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/source/NierReplicant.Fix/dllmain.cpp b/source/NierReplicant.Fix/dllmain.cpp
new file mode 100644
index 0000000..43470f8
--- /dev/null
+++ b/source/NierReplicant.Fix/dllmain.cpp
@@ -0,0 +1,119 @@
+#include "stdafx.h"
+#include "helper.hpp"
+#include "memory.hpp"
+#include "git_ver.h"
+
+HMODULE baseModule = GetModuleHandle(NULL);
+
+#define wstr(s) L#s
+#define wxstr(s) wstr(s)
+#define _PROJECT_NAME L"NierReplicant.Fix"
+#define _PROJECT_LOG_PATH _PROJECT_NAME L".log"
+
+wchar_t exePath[_MAX_PATH] = { 0 };
+
+// INI Variables
+bool bFPSFix{};
+float fFPSMax{};
+
+void ReadConfig(void)
+{
+ inipp::Ini ini;
+ // Get game name and exe path
+ LOG(_PROJECT_NAME " Built: " __TIME__ " @ " __DATE__ "\n");
+ LOG(L"" GIT_COMMIT "\n");
+ LOG(L"" GIT_VER "\n");
+ LOG(L"" GIT_NUM "\n");
+ LOG(L"Game Name: %s\n", Memory::GetVersionProductName().c_str());
+ LOG(L"Game Path: %s\n", exePath);
+
+ // Initialize config
+ // UE4 games use launchers so config path is relative to launcher
+ std::wstring config_path = _PROJECT_NAME L".ini";
+ std::wifstream iniFile(config_path);
+ if (!iniFile)
+ {
+ // no ini, lets generate one.
+ LOG(L"Failed to load config file.\n");
+ std::wstring ini_defaults = L"[Settings]\n"
+ wstr(bFPSFix)" = true\n"
+ wstr(fFPSMax)" = 1000\n";
+ std::wofstream iniFile(config_path);
+ iniFile << ini_defaults;
+ bFPSFix = true;
+ fFPSMax = 1000.f;
+ LOG(L"Created default config file.\n");
+ }
+ else
+ {
+ ini.parse(iniFile);
+ inipp::get_value(ini.sections[L"Settings"], wstr(bFPSFix), bFPSFix);
+ inipp::get_value(ini.sections[L"Settings"], wstr(fFPSMax), fFPSMax);
+ }
+
+ // Log config parse
+ LOG(L"%s: %s (%i)\n", wstr(bFPSFix), GetBoolStr(bFPSFix), bFPSFix);
+ LOG(L"%s: %f\n", wstr(fFPSMax), fFPSMax);
+}
+
+void Remove30FPSCutscenes()
+{
+ if (fFPSMax < 1.)
+ {
+ LOG(L"Cannot set " wstr(fFPSMax) " to a value less than 1!\n");
+ LOG(L"Defaulting to 1000.f\n");
+ fFPSMax = 1000.f;
+ }
+ uint8_t* Write30FPSCutscenesResult = Memory::PatternScanW(baseModule, L"89 88 88 3c 00 00 00 a0 aa aa ea 3f 52 b8 1e 85 eb 51 fc 3f");
+ uint8_t* Write30FPSCutscenesResult2 = Memory::PatternScanW(baseModule, L"0f 94 c1 e8 ?? ?? ?? ?? 66 0f 6e b7 ?? ?? ?? ??");
+ if (Write30FPSCutscenesResult && Write30FPSCutscenesResult2)
+ {
+ uint64_t Write30FPSAddress = ((uintptr_t)Write30FPSCutscenesResult);
+ uint64_t Write30FPSAddress2 = ((uintptr_t)Write30FPSCutscenesResult2);
+ float value = (1.f / fFPSMax);
+ WritePatchAddressFloat32(Write30FPSAddress, &value, wstr(fFPSMax), 0);
+ // remove ugly Sleep
+ uint8_t xor_rcx_rcx[] = { 0x48, 0x31, 0xc9 };
+ WritePatchAddress(Write30FPSAddress2, xor_rcx_rcx, sizeof(xor_rcx_rcx), L"No sleep", 0);
+ }
+ else
+ {
+ LOG(L"Pattern scan failed.\n");
+ }
+}
+
+DWORD __stdcall Main()
+{
+ bLoggingEnabled = false;
+ bFPSFix = false;
+ fFPSMax = 0.;
+ wchar_t LogPath[_MAX_PATH] = { 0 };
+ wcscpy_s(exePath, _countof(exePath), GetRunningPath(exePath));
+ _snwprintf_s(LogPath, _countof(LogPath), _TRUNCATE, L"%s\\%s", exePath, _PROJECT_LOG_PATH);
+ LoggingInit(_PROJECT_NAME, LogPath);
+ ReadConfig();
+ if (bFPSFix)
+ Remove30FPSCutscenes();
+ LOG(L"Shutting down " wstr(fp_log) " file handle.\n");
+ fclose(fp_log);
+ return 0;
+}
+
+BOOL APIENTRY DllMain( HMODULE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved
+ )
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ {
+ Main();
+ }
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
diff --git a/source/Shared/helper.cpp b/source/Shared/helper.cpp
index 216b235..c5fb0bb 100644
--- a/source/Shared/helper.cpp
+++ b/source/Shared/helper.cpp
@@ -172,6 +172,22 @@ void WritePatchAddress(uint64_t Patch_Address, const unsigned char* Patch_Bytes,
ShowPatchInfo(Patch_Size, Patch_Address_Offset, Patch_Name, 0);
}
+void WritePatchAddressFloat32(uint64_t Patch_Address, const float* Patch_Bytes, const wchar_t* Patch_Name, uint64_t Patch_Offset)
+{
+ uint64_t Patch_Address_Offset = Patch_Address + Patch_Offset;
+ Memory::PatchBytes(Patch_Address_Offset, (const unsigned char*)Patch_Bytes, sizeof(float));
+ LOG("Write %f to 0x%llx\n", *Patch_Bytes, Patch_Address_Offset);
+ ShowPatchInfo(sizeof(float), Patch_Address_Offset, Patch_Name, 0);
+}
+
+void WritePatchAddressFloat64(uint64_t Patch_Address, const double* Patch_Bytes, const wchar_t* Patch_Name, uint64_t Patch_Offset)
+{
+ uint64_t Patch_Address_Offset = Patch_Address + Patch_Offset;
+ Memory::PatchBytes(Patch_Address_Offset, (const unsigned char*)Patch_Bytes, sizeof(double));
+ LOG("Write %llf to 0x%llx\n", Patch_Bytes, Patch_Address_Offset);
+ ShowPatchInfo(sizeof(double), Patch_Address_Offset, Patch_Name, 0);
+}
+
wchar_t* GetRunningPath(wchar_t* output)
{
GetModuleFileNameW(nullptr, output, MAX_PATH);