- Fixed long paths to mods inside UserModFiles causing a game crash or causing the mods to not load at all

- Added "Increase Data PAKs Limit" (Misc; requires game restart to apply) - you can now add more than 8 data PAKs, e.g. data8.pak, data9.pak, data10.pak, etc, up to 200 PAKs in total
- Added "Disable Data PAKs CRC Check" (Misc requires game restart to apply) - stops the game from detecting data PAKs, which allows you to use data PAK mods in multiplayer as well
- Added "Disable Savegame CRC Check" (Misc requires game restart to apply) - stops the game from falsely saying your savegame is corrupt whenever you modify it
- Changed the config system to only write to the config file whenever there's a change in the mod menu
This commit is contained in:
EricPlayZ
2024-05-02 05:04:50 +03:00
parent 9a980ca48c
commit ba953c90be
20 changed files with 117 additions and 81 deletions

View File

@ -30,7 +30,7 @@
<ClCompile Include="source\game\Engine\CoPhysicsProperty.cpp" />
<ClCompile Include="source\game\Engine\CVideoSettings.cpp" />
<ClCompile Include="source\game\Engine\engine_hooks.cpp" />
<ClCompile Include="source\game\Engine\GameSpeedHandler.cpp" />
<ClCompile Include="source\game\Engine\engine_misc.cpp" />
<ClCompile Include="source\game\GamePH\DayNightCycle.cpp" />
<ClCompile Include="source\game\GamePH\FreeCamera.cpp" />
<ClCompile Include="source\game\GamePH\GameDI_PH.cpp" />
@ -40,7 +40,7 @@
<ClCompile Include="source\game\GamePH\LevelDI.cpp" />
<ClCompile Include="source\game\GamePH\LocalClientDI.cpp" />
<ClCompile Include="source\game\GamePH\LogicalPlayer.cpp" />
<ClCompile Include="source\game\GamePH\Other.cpp" />
<ClCompile Include="source\game\GamePH\gameph_misc.cpp" />
<ClCompile Include="source\game\GamePH\PlayerDI_PH.cpp" />
<ClCompile Include="source\game\GamePH\PlayerHealthModule.cpp" />
<ClCompile Include="source\game\GamePH\PlayerObjProperties.cpp" />
@ -128,7 +128,7 @@
<ClInclude Include="source\game\Engine\CoPhysicsProperty.h" />
<ClInclude Include="source\game\Engine\CVideoSettings.h" />
<ClInclude Include="source\game\Engine\engine_hooks.h" />
<ClInclude Include="source\game\Engine\GameSpeedHandler.h" />
<ClInclude Include="source\game\Engine\engine_misc.h" />
<ClInclude Include="source\game\GamePH\CoBaseCameraProxy.h" />
<ClInclude Include="source\game\GamePH\DayNightCycle.h" />
<ClInclude Include="source\game\GamePH\FreeCamera.h" />
@ -138,7 +138,7 @@
<ClInclude Include="source\game\GamePH\LevelDI.h" />
<ClInclude Include="source\game\GamePH\LocalClientDI.h" />
<ClInclude Include="source\game\GamePH\LogicalPlayer.h" />
<ClInclude Include="source\game\GamePH\Other.h" />
<ClInclude Include="source\game\GamePH\gameph_misc.h" />
<ClInclude Include="source\game\GamePH\PlayerDI_PH.h" />
<ClInclude Include="source\game\GamePH\PlayerHealthModule.h" />
<ClInclude Include="source\game\GamePH\PlayerObjProperties.h" />

View File

@ -148,7 +148,7 @@
<ClCompile Include="source\game\GamePH\LogicalPlayer.cpp">
<Filter>game\GamePH</Filter>
</ClCompile>
<ClCompile Include="source\game\GamePH\Other.cpp">
<ClCompile Include="source\game\GamePH\gameph_misc.cpp">
<Filter>game\GamePH</Filter>
</ClCompile>
<ClCompile Include="source\game\GamePH\PlayerHealthModule.cpp">
@ -191,7 +191,7 @@
<ClCompile Include="source\menu\init.cpp">
<Filter>menu</Filter>
</ClCompile>
<ClCompile Include="source\game\Engine\GameSpeedHandler.cpp">
<ClCompile Include="source\game\Engine\engine_misc.cpp">
<Filter>game\Engine</Filter>
</ClCompile>
</ItemGroup>
@ -358,7 +358,7 @@
<ClInclude Include="source\game\GamePH\LogicalPlayer.h">
<Filter>game\GamePH</Filter>
</ClInclude>
<ClInclude Include="source\game\GamePH\Other.h">
<ClInclude Include="source\game\GamePH\gameph_misc.h">
<Filter>game\GamePH</Filter>
</ClInclude>
<ClInclude Include="source\game\GamePH\PlayerHealthModule.h">
@ -408,7 +408,7 @@
<ClInclude Include="source\menu\init.h">
<Filter>menu</Filter>
</ClInclude>
<ClInclude Include="source\game\Engine\GameSpeedHandler.h">
<ClInclude Include="source\game\Engine\engine_misc.h">
<Filter>game\Engine</Filter>
</ClInclude>
</ItemGroup>

View File

@ -55,6 +55,9 @@ Thank you everyone for the support <3)" },
- Fixed God Mode staying enabled after toggling FreeCam off
- Fixed player variables saving and loading using old version of player_variables.scr (which makes Max Health drop to negative infinite)
- Fixed long paths to mods inside UserModFiles causing a game crash or causing the mods to not load at all
- Added the possibility of adding more than 8 paks (up to 200 paks!) in "ph\source" (e.g. data8.pak, data9.pak, data10.pak, etc.))" }
- Added "Increase Data PAKs Limit" (Misc; requires game restart to apply) - you can now add more than 8 data PAKs, e.g. data8.pak, data9.pak, data10.pak, etc, up to 200 PAKs in total
- Added "Disable Data PAKs CRC Check" (Misc requires game restart to apply) - stops the game from detecting data PAKs, which allows you to use data PAK mods in multiplayer as well
- Added "Disable Savegame CRC Check" (Misc requires game restart to apply) - stops the game from falsely saying your savegame is corrupt whenever you modify it
- Changed the config system to only write to the config file whenever there's a change in the mod menu)" }
};
}

View File

@ -4374,6 +4374,9 @@ namespace Config {
{ "Camera:Misc", "DisablePhotoModeLimits", true, &Menu::Camera::disablePhotoModeLimits, OPTION },
{ "Camera:Misc", "DisableSafezoneFOVReduction", true, &Menu::Camera::disableSafezoneFOVReduction, OPTION },
{ "Misc:Misc", "DisableGamePauseWhileAFK", true, &Menu::Misc::disableGamePauseWhileAFK, OPTION },
{ "Misc:Misc", "DisableSavegameCRCCheck", true, &Menu::Misc::disableSavegameCRCCheck, OPTION },
{ "Misc:Misc", "DisableDataPAKsCRCCheck", true, &Menu::Misc::disableDataPAKsCRCCheck, OPTION },
{ "Misc:Misc", "IncreaseDataPAKsLimit", true, &Menu::Misc::increaseDataPAKsLimit, OPTION },
{ "World:Time", "SlowMotionSpeed", 0.4f, &Menu::World::slowMotionSpeed, Float },
{ "World:Time", "SlowMotionTransitionTime", 1.0f, &Menu::World::slowMotionTransitionTime, Float }
});
@ -4518,6 +4521,48 @@ namespace Config {
}
}
bool CheckForChangesInMem() {
try {
reader = inih::INIReader(configFileName);
std::string strValue{};
for (auto& entry : configVariablesDefault) {
switch (entry.type) {
case OPTION:
if (reader.Get(entry.section.data(), entry.key.data(), std::any_cast<bool>(entry.value)) != reinterpret_cast<Option*>(entry.optionPtr)->GetValue())
return true;
break;
case Float:
if (!Utils::Values::are_samef(reader.Get(entry.section.data(), entry.key.data(), std::any_cast<float>(entry.value)), *reinterpret_cast<float*>(entry.optionPtr)))
return true;
break;
case String:
strValue = reader.Get(entry.section.data(), entry.key.data(), std::any_cast<std::string>(entry.value));
if (entry.section == "Menu:Keybinds") {
KeyBindOption* option = reinterpret_cast<KeyBindOption*>(entry.optionPtr);
const auto itConfigVal = std::ranges::find(virtualKeyCodes, strValue, &Config::VKey::name);
const auto itMemVal = std::ranges::find(virtualKeyCodes, option->GetKeyBind(), &Config::VKey::code);
if (itConfigVal == virtualKeyCodes.end() || itMemVal == virtualKeyCodes.end())
break;
if (strValue != itMemVal->name)
return true;
break;
}
if (strValue != *reinterpret_cast<std::string*>(entry.optionPtr))
return true;
break;
}
}
return false;
} catch (const std::runtime_error& e) {
spdlog::error("Error checking for changes in memory: {}", e.what());
return false;
}
}
void SaveConfig() {
for (auto& entry : configVariables) {
switch (entry.type) {
@ -4547,6 +4592,8 @@ namespace Config {
inih::INIWriter writer{};
writer.write(configFileName, reader);
spdlog::info("Successfully updated config!");
savedConfig = true;
} catch (const std::runtime_error& e) {
spdlog::error("Error saving to file {}: {}", configFileName, e.what());
@ -4559,45 +4606,29 @@ namespace Config {
configLastWriteTime = configPreviousWriteTime;
}
void ConfigLoop() {
while (true) {
if (Core::exiting)
return;
Sleep(200);
while (!Core::exiting) {
Sleep(2000);
if (!ConfigExists()) {
CreateConfig();
Sleep(750);
configPreviousWriteTime = std::filesystem::last_write_time(configFileName);
continue;
}
// Check for config changes
configLastWriteTime = std::filesystem::last_write_time(configFileName);
if (configLastWriteTime != configPreviousWriteTime && !savedConfig) {
configPreviousWriteTime = configLastWriteTime;
Sleep(750);
ReadConfig(true);
continue;
} else if (configLastWriteTime != configPreviousWriteTime && savedConfig) {
configPreviousWriteTime = configLastWriteTime;
savedConfig = false;
}
}
}
void ConfigSaveLoop() {
while (true) {
if (Core::exiting)
return;
Sleep(10000);
if (!ConfigExists()) {
CreateConfig();
Sleep(200);
configPreviousWriteTime = std::filesystem::last_write_time(configFileName);
}
SaveConfig();
if (CheckForChangesInMem())
SaveConfig();
}
}
}

View File

@ -5,5 +5,4 @@ namespace Config {
extern void SaveConfig();
extern void InitConfig();
extern void ConfigLoop();
extern void ConfigSaveLoop();
}

View File

@ -2,8 +2,8 @@
#include "config\config.h"
#include "core.h"
#include "game\GamePH\LevelDI.h"
#include "game\GamePH\Other.h"
#include "game\GamePH\PlayerVariables.h"
#include "game\GamePH\gameph_misc.h"
#include "menu\menu.h"
#pragma region KeyBindOption
@ -37,7 +37,6 @@ namespace Core {
// Core
bool exiting = false;
static bool createdConfigThread = false;
int rendererAPI = 0;
DWORD gameVer = 0;
@ -162,13 +161,6 @@ namespace Core {
}
void OnPostUpdate() {
if (!createdConfigThread) {
std::thread(Config::ConfigLoop).detach();
std::thread(Config::ConfigSaveLoop).detach();
createdConfigThread = true;
}
if (!GamePH::PlayerVariables::gotPlayerVars)
GamePH::PlayerVariables::GetPlayerVars();
@ -225,6 +217,8 @@ namespace Core {
spdlog::warn("Initializing config");
Config::InitConfig();
std::thread(Config::ConfigLoop).detach();
CreateSymlinkForLoadingFiles();
for (auto& hook : *Utils::Hook::HookBase::GetInstances()) {

View File

@ -10,11 +10,9 @@ namespace Core {
namespace Engine {
namespace Hooks {
extern Utils::Hook::MHook<LPVOID, DWORD64(*)(DWORD64, UINT, UINT, DWORD64*, DWORD64(*)(DWORD64, DWORD, DWORD64, char*, int), INT16, DWORD64, UINT)> MountDataPaksHook;
extern Utils::Hook::MHook<LPVOID, DWORD64(*)(DWORD64, DWORD, DWORD)> FsOpenHook;
extern Utils::Hook::MHook<LPVOID, bool(*)(LPVOID, LPVOID)> FsCalcFileCrcHook;
extern Utils::Hook::MHook<LPVOID, LPVOID(*)(LPVOID)> AuthenticateDataAddNewFileHook;
extern Utils::Hook::MHook<LPVOID, void(*)(LPVOID)> AuthenticateDataAnalyzeHook;
extern Utils::Hook::MHook<LPVOID, bool(*)(LPVOID)> FsCheckZipCrcHook;
extern Utils::Hook::MHook<LPVOID, DWORD64(*)(DWORD64, DWORD, DWORD)> FsOpenHook;
}
}
@ -25,10 +23,8 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD64 ul_reason_for_call, LPVOID lpRese
case DLL_PROCESS_ATTACH: {
MH_Initialize();
Engine::Hooks::MountDataPaksHook.HookLoop();
Engine::Hooks::AuthenticateDataAnalyzeHook.HookLoop();
Engine::Hooks::AuthenticateDataAddNewFileHook.HookLoop();
Engine::Hooks::FsCheckZipCrcHook.HookLoop();
Engine::Hooks::FsCalcFileCrcHook.HookLoop();
Engine::Hooks::FsOpenHook.HookLoop();
DisableThreadLibraryCalls(hModule);

View File

@ -1,3 +1,4 @@
// UNUSED CPP
#include <pch.h>
namespace Engine {

View File

@ -1,4 +1,5 @@
#pragma once
// UNUSED HEADER
namespace Engine {
namespace GameSpeedHandler {
extern float speed;

View File

@ -1,12 +1,14 @@
#include <pch.h>
#include "..\GamePH\GameDI_PH.h"
#include "..\GamePH\LevelDI.h"
#include "..\GamePH\Other.h"
#include "..\GamePH\gameph_misc.h"
#include "..\GamePH\gen_TPPModel.h"
#include "..\core.h"
#include "..\menu\camera.h"
#include "..\menu\misc.h"
#include "..\offsets.h"
#include "CBaseCamera.h"
#include "engine_misc.h"
namespace Engine {
namespace Hooks {
@ -202,19 +204,15 @@ namespace Engine {
Utils::Hook::MHook<LPVOID, DWORD64(*)(DWORD64, UINT, UINT, DWORD64*, DWORD64(*)(DWORD64, DWORD, DWORD64, char*, int), INT16, DWORD64, UINT)> MountDataPaksHook{ "MountDataPaks", &Offsets::Get_MountDataPaks, &detourMountDataPaks };
static DWORD64 detourMountDataPaks(DWORD64 a1, UINT a2, UINT a3, DWORD64* a4, DWORD64(*a5)(DWORD64, DWORD, DWORD64, char*, int), INT16 a6, DWORD64 a7, UINT a8) {
return MountDataPaksHook.pOriginal(a1, a2, a3, a4, a5, a6, a7, 200);
}
#pragma endregion
static int i = 0;
if (a8 == 8)
i++;
else if (i < 3)
spdlog::error("MountDataPaks hook ran less than 3 times with the data PAKs limit set to 8. This means the increased data PAKs limit might not work correctly! If this error message appears and your data PAKs past \"data7.pak\" have not loaded, please contact author.");
#pragma region FsCalcFileCrc
static LPVOID GetFsCalcFileCrc() {
return Utils::Memory::GetProcAddr("filesystem_x64_rwdi.dll", "?calc_file_crc@fs@@YA_NAEAUcrc_calc_args@1@@Z");
}
static bool detourFsCalcFileCrc(LPVOID instance, LPVOID crcCalcArgs);
Utils::Hook::MHook<LPVOID, bool(*)(LPVOID, LPVOID)> FsCalcFileCrcHook{ "FsCalcFileCrc", &GetFsCalcFileCrc, &detourFsCalcFileCrc };
static bool detourFsCalcFileCrc(LPVOID instance, LPVOID crcCalcArgs) {
return true;
if (Menu::Misc::increaseDataPAKsLimit.GetValue())
a8 = 200;
return MountDataPaksHook.pOriginal(a1, a2, a3, a4, a5, a6, a7, a8);
}
#pragma endregion
@ -226,7 +224,7 @@ namespace Engine {
Utils::Hook::MHook<LPVOID, bool(*)(LPVOID)> FsCheckZipCrcHook{ "FsCheckZipCrc", &GetFsCheckZipCrc, &detourFsCheckZipCrc };
static bool detourFsCheckZipCrc(LPVOID instance) {
return true;
return Menu::Misc::disableSavegameCRCCheck.GetValue() ? true : FsCheckZipCrcHook.pOriginal(instance);
}
#pragma endregion
@ -234,30 +232,15 @@ namespace Engine {
static LPVOID GetAuthenticateDataAddNewFile() {
return Utils::Memory::GetProcAddr("engine_x64_rwdi.dll", "?AddNewFile@Results@AuthenticateData@@QEAAAEAVFile@12@XZ");
}
static void AuthenticateDataResultsClear(LPVOID instance) {
void(*func)(LPVOID instance) = reinterpret_cast<decltype(func)>(Utils::Memory::GetProcAddr("engine_x64_rwdi.dll", "?Clear@Results@AuthenticateData@@QEAAXXZ"));
func(instance);
}
static LPVOID detourAuthenticateDataAddNewFile(LPVOID instance);
Utils::Hook::MHook<LPVOID, LPVOID(*)(LPVOID)> AuthenticateDataAddNewFileHook{ "AuthenticateDataAddNewFile", &GetAuthenticateDataAddNewFile, &detourAuthenticateDataAddNewFile };
static LPVOID detourAuthenticateDataAddNewFile(LPVOID instance) {
LPVOID result = AuthenticateDataAddNewFileHook.pOriginal(instance);
AuthenticateDataResultsClear(instance);
if (Menu::Misc::disableDataPAKsCRCCheck.GetValue())
AuthenticateDataResultsClear(instance);
return result;
}
#pragma endregion
#pragma region AuthenticateDataAnalyze
static LPVOID GetAuthenticateDataAnalyze() {
return Utils::Memory::GetProcAddr("engine_x64_rwdi.dll", "?Analyze@Results@AuthenticateData@@QEAAXXZ");
}
static void detourAuthenticateDataAnalyze(LPVOID instance);
Utils::Hook::MHook<LPVOID, void(*)(LPVOID)> AuthenticateDataAnalyzeHook{ "AuthenticateDataAnalyze", &GetAuthenticateDataAnalyze, &detourAuthenticateDataAnalyze };
static void detourAuthenticateDataAnalyze(LPVOID instance) {
AuthenticateDataAnalyzeHook.pOriginal(instance);
}
#pragma endregion
}
}

View File

@ -0,0 +1,11 @@
#include <pch.h>
namespace Engine {
void AuthenticateDataResultsClear(LPVOID instance) {
void(*pAuthenticateDataResultsClear)(LPVOID instance) = (decltype(pAuthenticateDataResultsClear))Utils::Memory::GetProcAddr("engine_x64_rwdi.dll", "?Clear@Results@AuthenticateData@@QEAAXXZ");
if (!pAuthenticateDataResultsClear)
return;
pAuthenticateDataResultsClear(instance);
}
}

View File

@ -0,0 +1,6 @@
#pragma once
#include <minwindef.h>
namespace Engine {
extern void AuthenticateDataResultsClear(LPVOID instance);
}

View File

@ -5,8 +5,8 @@
#include "..\game\GamePH\FreeCamera.h"
#include "..\game\GamePH\GameDI_PH.h"
#include "..\game\GamePH\LevelDI.h"
#include "..\game\GamePH\Other.h"
#include "..\game\GamePH\PlayerVariables.h"
#include "..\game\GamePH\gameph_misc.h"
#include "..\game\GamePH\gen_TPPModel.h"
#include "..\offsets.h"
#include "camera.h"

View File

@ -1,6 +1,6 @@
#include <pch.h>
#include "..\changelog.h"
#include "..\game\GamePH\Other.h"
#include "..\game\GamePH\gameph_misc.h"
#include "menu.h"
namespace Menu {

View File

@ -1,5 +1,5 @@
#include <pch.h>
#include "..\game\GamePH\Other.h"
#include "..\game\GamePH\gameph_misc.h"
#include "menu.h"
namespace Menu {

View File

@ -7,6 +7,9 @@ namespace Menu {
namespace Misc {
KeyBindOption disableGamePauseWhileAFK{ VK_NONE };
KeyBindOption disableHUD{ VK_F8 };
Option disableSavegameCRCCheck{};
Option disableDataPAKsCRCCheck{};
Option increaseDataPAKsLimit{};
static void UpdateDisabledOptions() {
GamePH::LevelDI* iLevel = GamePH::LevelDI::Get();
@ -44,6 +47,11 @@ namespace Menu {
ImGui::CheckboxHotkey("Disable HUD", &disableHUD);
ImGui::EndDisabled();
}
ImGui::Checkbox("Disable Savegame CRC Check *", &disableSavegameCRCCheck);
ImGui::Checkbox("Disable Data PAKs CRC Check *", &disableDataPAKsCRCCheck);
ImGui::Checkbox("Increase Data PAKs Limit *", &increaseDataPAKsLimit);
ImGui::Separator();
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(IM_COL32(200, 0, 0, 255)), "* Option requires game restart to apply");
}
}
}

View File

@ -5,6 +5,9 @@ namespace Menu {
namespace Misc {
extern KeyBindOption disableGamePauseWhileAFK;
extern KeyBindOption disableHUD;
extern Option disableSavegameCRCCheck;
extern Option disableDataPAKsCRCCheck;
extern Option increaseDataPAKsLimit;
class Tab : MenuTab {
public:

View File

@ -3,9 +3,9 @@
#include "..\game\Engine\CBulletPhysicsCharacter.h"
#include "..\game\GamePH\FreeCamera.h"
#include "..\game\GamePH\LevelDI.h"
#include "..\game\GamePH\Other.h"
#include "..\game\GamePH\PlayerHealthModule.h"
#include "..\game\GamePH\PlayerVariables.h"
#include "..\game\GamePH\gameph_misc.h"
#include "camera.h"
#include "menu.h"
#include "player.h"