backup commit :D

This commit is contained in:
EricPlayZ
2024-05-01 03:42:17 +03:00
parent 4879e68867
commit 9a980ca48c
12 changed files with 8921 additions and 8753 deletions

View File

@ -222,7 +222,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<TargetExt>.asi</TargetExt>
<TargetName>EGameTools</TargetName>
<GenerateManifest>false</GenerateManifest>
<GenerateManifest>true</GenerateManifest>
<LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64)</LibraryPath>
<IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);</IncludePath>
</PropertyGroup>

View File

@ -53,6 +53,8 @@ Thank you everyone for the support <3)" },
{ "v1.1.4",
R"(- Added compatibility with v1.16.1 hotfix update
- 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 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.))" }
};
}

View File

@ -220,25 +220,12 @@ namespace Core {
//AddVectoredExceptionHandler(0, &VectoredExceptionHandler);
spdlog::warn("Initializing config");
Config::InitConfig();
CreateSymlinkForLoadingFiles();
spdlog::warn("Sorting Player Variables");
GamePH::PlayerVariables::SortPlayerVars();
spdlog::info("Player Variables sorted");
spdlog::warn("Initializing MinHook");
MH_Initialize();
spdlog::info("Initialized MinHook");
spdlog::warn("Getting game version");
GameVersionCheck();
spdlog::warn("Hooking DX11/DX12 renderer");
std::thread([]() {
LoopHookRenderer();
spdlog::info("Hooked \"DX11/DX12 renderer\"!");
}).detach();
spdlog::warn("Initializing config");
Config::InitConfig();
CreateSymlinkForLoadingFiles();
for (auto& hook : *Utils::Hook::HookBase::GetInstances()) {
spdlog::warn("Hooking \"{}\"", hook->name.data());
@ -248,11 +235,14 @@ namespace Core {
}).detach();
}
std::thread([]() {
while (!Engine::GameSpeedHandler::initialized)
Engine::GameSpeedHandler::Setup();
spdlog::warn("Sorting Player Variables");
GamePH::PlayerVariables::SortPlayerVars();
spdlog::info("Player Variables sorted");
spdlog::info("GameSpeedHandler has been set up successfully!");
spdlog::warn("Hooking DX11/DX12 renderer");
std::thread([]() {
LoopHookRenderer();
spdlog::info("Hooked \"DX11/DX12 renderer\"!");
}).detach();
const HANDLE proc = GetCurrentProcess();

View File

@ -7,11 +7,30 @@ namespace Core {
extern void Cleanup();
}
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;
}
}
static HANDLE hMainThread{};
BOOL APIENTRY DllMain(HMODULE hModule, DWORD64 ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
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);
hMainThread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)Core::MainThread, hModule, 0, nullptr);

View File

@ -5,7 +5,7 @@ namespace Engine {
float speed = 1.0;
bool initialized = false;
#pragma region GetTickCount64Hook
/*#pragma region GetTickCount64Hook
ULONGLONG GTC64_BaseTime = 0;
ULONGLONG GTC64_OffsetTime = 0;
@ -62,6 +62,6 @@ namespace Engine {
}
speed = gameSpeed;
}
}*/
}
}

View File

@ -4,7 +4,7 @@ namespace Engine {
extern float speed;
extern bool initialized;
void Setup();
void SetGameSpeed(float gameSpeed);
/*void Setup();
void SetGameSpeed(float gameSpeed);*/
}
}

View File

@ -67,6 +67,8 @@ namespace Engine {
#pragma endregion
#pragma region fs::open
static const std::string userModFilesFullPath = "\\\\?\\" + std::filesystem::absolute("..\\..\\..\\source\\data\\EGameTools\\UserModFiles").string();
static std::vector<std::string> cachedUserModDirs{};
static Utils::Time::Timer timeSinceCache{ 0 };
static void CacheUserModDirs() {
@ -75,15 +77,18 @@ namespace Engine {
if (!cachedUserModDirs.empty())
cachedUserModDirs.clear();
const char* userModFilesPath = "..\\..\\..\\source\\data\\EGameTools\\UserModFiles";
cachedUserModDirs.push_back(userModFilesFullPath);
try {
const auto rdi = std::filesystem::recursive_directory_iterator(userModFilesFullPath);
for (auto entry = std::filesystem::begin(rdi); entry != std::filesystem::end(rdi); ++entry) {
const std::filesystem::path pathToDir = entry->path();
if (!std::filesystem::is_directory(pathToDir))
continue;
cachedUserModDirs.push_back(userModFilesPath);
for (const auto& entry : std::filesystem::recursive_directory_iterator(userModFilesPath)) {
const std::filesystem::path pathToDir = entry.path();
if (!std::filesystem::is_directory(pathToDir))
continue;
cachedUserModDirs.push_back(pathToDir.string());
cachedUserModDirs.push_back(pathToDir.string());
}
} catch (const std::exception& e) {
spdlog::error("Exception thrown while caching user mod directories: {}", e.what());
}
}
@ -91,7 +96,7 @@ namespace Engine {
return Utils::Memory::GetProcAddr("filesystem_x64_rwdi.dll", "?open@fs@@YAPEAUSFsFile@@V?$string_const@D@ttl@@W4TYPE@EFSMode@@W45FFSOpenFlags@@@Z");
}
static DWORD64 detourFsOpen(DWORD64 file, DWORD a2, DWORD a3);
static Utils::Hook::MHook<LPVOID, DWORD64(*)(DWORD64, DWORD, DWORD)> FsOpenHook{ "fs::open", &GetFsOpen, &detourFsOpen };
Utils::Hook::MHook<LPVOID, DWORD64(*)(DWORD64, DWORD, DWORD)> FsOpenHook{ "fs::open", &GetFsOpen, &detourFsOpen };
static DWORD64 detourFsOpen(DWORD64 file, DWORD a2, DWORD a3) {
const DWORD64 firstByte = (file >> 56) & 0xFF; // get first byte of addr
@ -107,22 +112,22 @@ namespace Engine {
}
std::string finalPath{};
try {
for (const auto& entry : cachedUserModDirs) {
finalPath = entry + "\\" + fileName;
if (!std::filesystem::exists(finalPath))
continue;
const std::string finalPath2 = std::filesystem::absolute(finalPath).string();
const char* filePath2 = finalPath2.c_str();
finalPath.replace(0, userModFilesFullPath.size() + 1, ""); // replace entire path until mod folder with nothing
const char* filePath2 = finalPath.c_str();
spdlog::warn("Loading user mod file \"{}\"", finalPath.c_str());
const DWORD64 finalAddr = firstByte != 0x0 ? (reinterpret_cast<DWORD64>(filePath2) | (firstByte << 56)) : reinterpret_cast<DWORD64>(filePath2); // restores first byte of addr if first byte was not 0
const DWORD64 result = FsOpenHook.pOriginal(finalAddr, a2, a3);
if (!result)
spdlog::error("fs::open returned 0! Something went wrong with loading user mod file \"{}\"!", finalPath.c_str());
if (!result) {
spdlog::error("fs::open returned 0! Something went wrong with loading user mod file \"{}\"!\nPlease make sure the path to the file is no longer than 260 characters!", finalPath.c_str());
}
return result;
}
} catch (const std::exception& e) {
@ -131,5 +136,128 @@ namespace Engine {
return FsOpenHook.pOriginal(file, a2, a3);
}
#pragma endregion
/*#pragma region FsNativeOpen
static LPVOID GetFsNativeOpen() {
return Utils::Memory::GetProcAddr("filesystem_x64_rwdi.dll", "?open@native@fs@@YAPEAUSFsFile@@PEAVCFsMount@@V?$string_const@D@ttl@@W4TYPE@EFSMode@@W47FFSOpenFlags@@@Z");
}
static DWORD64 detourFsNativeOpen(DWORD64 a1, DWORD64 a2, UINT a3, UINT a4);
static Utils::Hook::MHook<LPVOID, DWORD64(*)(DWORD64, DWORD64, UINT, UINT)> FsNativeOpenHook{ "FsNativeOpen", &GetFsNativeOpen, &detourFsNativeOpen };
static DWORD64 detourFsNativeOpen(DWORD64 a1, DWORD64 a2, UINT a3, UINT a4) {
return FsNativeOpenHook.pOriginal(a1, a2, a3, a4);
}
#pragma endregion
#pragma region LoadDataPaks
struct CPath {
public:
union {
const char* gamePath;
buffer<0x8, const char*> pakPath;
buffer<0x10, const char*> fullPakPath;
};
};
static LPVOID GetLoadDataPaks() {
return reinterpret_cast<LPVOID>(reinterpret_cast<DWORD64>(GetModuleHandleA("filesystem_x64_rwdi.dll")) + 0x29580);
}
static bool detourLoadDataPaks(DWORD64 a1, DWORD64 a2, DWORD64 a3);
static Utils::Hook::MHook<LPVOID, bool(*)(DWORD64, DWORD64, DWORD64)> LoadDataPaksHook{ "LoadDataPaks", &GetLoadDataPaks, &detourLoadDataPaks };
static bool detourLoadDataPaks(DWORD64 a1, DWORD64 a2, DWORD64 a3) {
CPath* cPath = reinterpret_cast<CPath*>(a2);
if ((cPath->fullPakPath & 0x1FFFFFFFFFFFFFFF) != 0) {
const DWORD64 firstByte = (cPath->fullPakPath >> 56) & 0xFF; // get first byte of addr
std::string gamePath = reinterpret_cast<const char*>(reinterpret_cast<DWORD64>(cPath->gamePath) & 0x1FFFFFFFFFFFFFFF);
DWORD64 origPakPath = reinterpret_cast<DWORD64>(const_cast<char*>(cPath->pakPath.data));
std::string pakPath = reinterpret_cast<const char*>(cPath->pakPath & 0x1FFFFFFFFFFFFFFF);
DWORD64 origFullPakPath = reinterpret_cast<DWORD64>(const_cast<char*>(cPath->fullPakPath.data));
std::string fullPakPath = reinterpret_cast<const char*>(cPath->fullPakPath & 0x1FFFFFFFFFFFFFFF);
if (pakPath == "ph/source/data0.pak") {
pakPath = "ph/source/data/EGameTools/UserModFiles/data8.pak";
const char* pakPathCStr = pakPath.c_str();
fullPakPath.replace(gamePath.size() + 1, fullPakPath.size(), "ph/source/data/EGameTools/UserModFiles/data8.pak");
const char* fullPakPathCStr = fullPakPath.c_str();
const DWORD64 finalAddrPakPath = firstByte != 0x0 ? (reinterpret_cast<DWORD64>(pakPathCStr) | (firstByte << 56)) : reinterpret_cast<DWORD64>(pakPathCStr);
const DWORD64 finalAddrFullPakPath= firstByte != 0x0 ? (reinterpret_cast<DWORD64>(fullPakPathCStr) | (firstByte << 56)) : reinterpret_cast<DWORD64>(fullPakPathCStr);
cPath->pakPath = reinterpret_cast<const char*>(finalAddrPakPath);
cPath->fullPakPath = reinterpret_cast<const char*>(finalAddrFullPakPath);
bool ret = LoadDataPaksHook.pOriginal(a1, a2, a3);
cPath->pakPath = reinterpret_cast<const char*>(origPakPath);
cPath->fullPakPath = reinterpret_cast<const char*>(origFullPakPath);
}
int i = 0;
}
return LoadDataPaksHook.pOriginal(a1, a2, a3);
}
#pragma endregion*/
#pragma region MountDataPaks
static DWORD64 detourMountDataPaks(DWORD64 a1, UINT a2, UINT a3, DWORD64* a4, DWORD64(*a5)(DWORD64, DWORD, DWORD64, char*, int), INT16 a6, DWORD64 a7, UINT a8);
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
#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;
}
#pragma endregion
#pragma region FsCheckZipCrc
static LPVOID GetFsCheckZipCrc() {
return Utils::Memory::GetProcAddr("filesystem_x64_rwdi.dll", "?check_zip_crc@izipped_buffer_file@fs@@QEAA_NXZ");
}
static bool detourFsCheckZipCrc(LPVOID instance);
Utils::Hook::MHook<LPVOID, bool(*)(LPVOID)> FsCheckZipCrcHook{ "FsCheckZipCrc", &GetFsCheckZipCrc, &detourFsCheckZipCrc };
static bool detourFsCheckZipCrc(LPVOID instance) {
return true;
}
#pragma endregion
#pragma region AuthenticateDataAddNewFile
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);
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

@ -3,10 +3,16 @@
template<size_t size, typename T> class buffer {
char buffer[size];
T data;
public:
T data;
operator T() { return data; }
T operator->() { return data; }
DWORD64 operator&(const DWORD64 other) const { return reinterpret_cast<DWORD64>(data) & other; }
DWORD64 operator>>(const int shift) const { return reinterpret_cast<DWORD64>(data) >> shift; }
DWORD64 operator<<(const int shift) const { return reinterpret_cast<DWORD64>(data) << shift; }
T& operator=(const T& other) { data = other; return data; }
T& operator*=(const T& other) { data *= other; return data; }
T operator*(const T& other) const { return data * other; }

View File

@ -10,6 +10,8 @@ namespace Menu {
float time = 0.0f;
static float timeBeforeFreeze = 0.0f;
float gameSpeed = 1.0f;
static float actualGameSpeed = gameSpeed;
static float gameSpeedBeforeSlowMo = gameSpeed;
KeyBindOption freezeTime{ VK_NONE };
KeyBindOption slowMotion{ '4' };
float slowMotionSpeed = 0.4f;
@ -52,25 +54,29 @@ namespace Menu {
}
static bool slowMoHasChanged = true;
static float initialGameSpeed = Engine::GameSpeedHandler::speed;
if (slowMotion.HasChangedTo(false)) {
static float gameSpeedAfterChange = 0.0f;
if (slowMoHasChanged)
initialGameSpeed = Engine::GameSpeedHandler::speed;
gameSpeedAfterChange = actualGameSpeed;
slowMotionSpeedLerp = ImGui::AnimateLerp("slowMotionSpeedLerp", initialGameSpeed, gameSpeed, slowMotionTransitionTime, slowMoHasChanged, &ImGui::AnimEaseInOutSine);
Engine::GameSpeedHandler::SetGameSpeed(slowMotionSpeedLerp);
slowMotionSpeedLerp = ImGui::AnimateLerp("slowMotionSpeedLerp", gameSpeedAfterChange, gameSpeedBeforeSlowMo, slowMotionTransitionTime, slowMoHasChanged, &ImGui::AnimEaseInOutSine);
iLevel->TimerSetSpeedUp(slowMotionSpeedLerp);
slowMoHasChanged = false;
if (Utils::Values::are_samef(Engine::GameSpeedHandler::speed, gameSpeed)) {
if (Utils::Values::are_samef(actualGameSpeed, gameSpeedBeforeSlowMo)) {
slowMoHasChanged = true;
slowMotion.SetPrevValue(false);
}
} else if (slowMotion.GetValue()) {
if (slowMotion.HasChanged())
initialGameSpeed = Engine::GameSpeedHandler::speed;
static float gameSpeedAfterChange = 0.0f;
if (slowMotion.HasChanged()) {
if (slowMoHasChanged)
gameSpeedBeforeSlowMo = actualGameSpeed;
gameSpeedAfterChange = actualGameSpeed;
}
slowMotionSpeedLerp = ImGui::AnimateLerp("slowMotionSpeedLerp", initialGameSpeed, slowMotionSpeed, slowMotionTransitionTime, slowMotion.HasChanged(), &ImGui::AnimEaseInOutSine);
Engine::GameSpeedHandler::SetGameSpeed(slowMotionSpeedLerp);
slowMotionSpeedLerp = ImGui::AnimateLerp("slowMotionSpeedLerp", gameSpeedAfterChange, slowMotionSpeed, slowMotionTransitionTime, slowMotion.HasChanged(), &ImGui::AnimEaseInOutSine);
iLevel->TimerSetSpeedUp(slowMotionSpeedLerp);
if (slowMotion.HasChanged()) {
slowMoHasChanged = true;
@ -82,13 +88,18 @@ namespace Menu {
time = dayNightCycle->time1 * 24.0f;
if (freezeTime.GetValue() && !Utils::Values::are_samef(time, timeBeforeFreeze, 0.009999f))
dayNightCycle->SetDaytime(timeBeforeFreeze);
if (!slowMotion.GetValue() && !slowMotion.HasChanged() && !Utils::Values::are_samef(gameSpeed, 1.0f))
iLevel->TimerSetSpeedUp(gameSpeed);
actualGameSpeed = iLevel->TimerGetSpeedUp();
}
}
void Tab::Render() {
GamePH::DayNightCycle* dayNightCycle = GamePH::DayNightCycle::Get();
GamePH::LevelDI* iLevel = GamePH::LevelDI::Get();
ImGui::SeparatorText("Time##World");
ImGui::BeginDisabled(!iLevel || !iLevel->IsLoaded() || !dayNightCycle); {
ImGui::BeginDisabled(!iLevel || !iLevel->IsLoaded() || !dayNightCycle);
{
static bool timeSliderBeingPressed = false;
if (ImGui::SliderFloat("Time", &time, 0.01f, 24.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp))
timeSliderBeingPressed = true;
@ -103,9 +114,15 @@ namespace Menu {
dayNightCycle->SetDaytime(timeBeforeFreeze);
}
ImGui::BeginDisabled(slowMotion.GetValue()); {
ImGui::BeginDisabled(slowMotion.GetValue());
{
if (ImGui::SliderFloat("Game Speed", &gameSpeed, 0.0f, 2.0f, "%.2fx"))
Engine::GameSpeedHandler::SetGameSpeed(gameSpeed);
iLevel->TimerSetSpeedUp(gameSpeed);
else if (iLevel && iLevel->IsLoaded()) {
if (!slowMotion.GetValue() && !slowMotion.HasChanged() && !Utils::Values::are_samef(gameSpeed, 1.0f))
iLevel->TimerSetSpeedUp(gameSpeed);
actualGameSpeed = iLevel->TimerGetSpeedUp();
}
ImGui::EndDisabled();
}
@ -122,7 +139,8 @@ namespace Menu {
const bool weatherDisabledFlag = !iLevel || !iLevel->IsLoaded() || !timeWeatherSystem;
ImGui::SeparatorText("Weather##World");
ImGui::BeginDisabled(weatherDisabledFlag); {
ImGui::BeginDisabled(weatherDisabledFlag);
{
if (ImGui::Combo("Weather", reinterpret_cast<int*>(&weather), weatherItems, IM_ARRAYSIZE(weatherItems)) && timeWeatherSystem)
timeWeatherSystem->SetForcedWeather(static_cast<GamePH::TimeWeather::EWeather::TYPE>(weather - 1));
ImGui::Text("Setting weather to: %s", !weatherDisabledFlag ? weatherItems[weather] : "");

View File

@ -49,6 +49,7 @@ struct Offsets {
// Functions
AddOffset(ReadVideoSettings, "engine_x64_rwdi.dll", "48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC ?? 48 8B FA 48 8B D9 45 84 C0", Utils::SigScan::PatternType::Address, LPVOID)
AddOffset(MountDataPaks, "engine_x64_rwdi.dll", "4C 8B DC 4D 89 4B ?? 45 89 43 ?? 89 54 24 ?? 49 89 4B", Utils::SigScan::PatternType::Address, LPVOID)
AddOffset(MoveCameraFromForwardUpPos, "engine_x64_rwdi.dll", "48 89 5C 24 ?? 57 48 83 EC ?? 49 8B C1 48 8B F9", Utils::SigScan::PatternType::Address, LPVOID)
AddOffset(CalculateFreeCamCollision, "gamedll_ph_x64_rwdi.dll", "48 8B C4 55 53 56 57 48 8D A8 ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? 83 B9", Utils::SigScan::PatternType::Address, LPVOID)
AddOffset(AllowCameraMovement, "gamedll_ph_x64_rwdi.dll", "89 91 ?? ?? ?? ?? C3 CC CC CC CC CC CC CC CC CC 48 8B C4 55 56", Utils::SigScan::PatternType::Address, LPVOID)

View File

@ -38,6 +38,8 @@ namespace Utils {
MHook(const std::string_view& name, GetTargetOffsetRetType(*pGetOffsetFunc)(), OrigType pDetour) : HookBase(name), pGetOffsetFunc(pGetOffsetFunc), pDetour(pDetour) {}
void HookLoop() override {
if (pOriginal)
return;
timeSpentHooking = Utils::Time::Timer(60000);
while (true) {
@ -71,6 +73,8 @@ namespace Utils {
VTHook(const std::string_view& name, GetTargetOffsetRetType(*pGetOffsetFunc)(), OrigType pDetour, DWORD offset) : HookBase(name), pGetOffsetFunc(pGetOffsetFunc), pDetour(pDetour), offset(offset) {}
void HookLoop() override {
if (pOriginal)
return;
timeSpentHooking = Utils::Time::Timer(60000);
while (true) {