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);