mirror of
https://github.com/EricPlayZ/EGameTools.git
synced 2025-07-18 17:37:53 +08:00
- Added the ability of using .PAK mods inside "EGameTools\UserModFiles"; just drag and drop a .PAK inside the folder, rename it to whatever you like and enjoy! CREDITS TO @12brendon34 on Discord for finding out how to implement this feature!
- Added "Allow Grapple Hook in Safezone" (Player)
This commit is contained in:
@ -52,10 +52,12 @@ Thank you everyone for the support <3)" },
|
||||
- Fetch game version using Windows' API instead of using the game's function)" },
|
||||
{ "v1.2.0",
|
||||
R"(- Added compatibility with v1.16.1 hotfix update
|
||||
- Added the ability of using .PAK mods inside "EGameTools\UserModFiles"; just drag and drop a .PAK inside the folder, rename it to whatever you like and enjoy! CREDITS TO @12brendon34 on Discord for finding out how to implement this feature!
|
||||
- Added "Player Immunity" slider (Player)
|
||||
- Added "Unlimited Immunity" (Player)
|
||||
- Added "Unlimited Stamina" (Player)
|
||||
- Added "Invisible to Enemies" (Player)
|
||||
- Added "Allow Grapple Hook in Safezone" (Player)
|
||||
- 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 scanning 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
|
||||
@ -68,6 +70,8 @@ Thank you everyone for the support <3)" },
|
||||
- Fixed volatiles still being able to kill you when they jump on top of you while "God Mode" (Player) is enabled
|
||||
- Fixed "Disable Out of Bounds Timer" (Player) not working in missions
|
||||
- Fixed immunity drastically being lowered while rapidly changing the time forward with the "Time" slider (World) at night or while in a dark zone
|
||||
- Changed the config system to only write to the config file whenever there's a change in the mod menu)" }
|
||||
- Changed the config system to only write to the config file whenever there's a change in the mod menu
|
||||
|
||||
NOTE: Any mods that are put inside "EGameTools\UserModFiles" as a regular file (.scr or any other file that is usually present in .PAK mods) and NOT a .PAK file will make the game ignore the same files that are present in any of the .PAK mods inside "EGameTools\UserModFiles". I recommend using .PAK for most mods. If you run into issues, try extracting the files inside the PAK into the folder directly.)" }
|
||||
};
|
||||
}
|
@ -4349,6 +4349,7 @@ namespace Config {
|
||||
{ "Menu:Keybinds", "DisableOutOfBoundsTimerToggleKey", std::string("VK_NONE"), &Menu::Player::disableOutOfBoundsTimer, String},
|
||||
{ "Menu:Keybinds", "NightrunnerModeToggleKey", std::string("VK_F9"), &Menu::Player::nightrunnerMode, String},
|
||||
{ "Menu:Keybinds", "OneHandedModeToggleKey", std::string("VK_NONE"), &Menu::Player::oneHandedMode, String},
|
||||
{ "Menu:Keybinds", "AllowGrappleHookInSafezoneToggleKey", std::string("VK_NONE"), &Menu::Player::allowGrappleHookInSafezone, String},
|
||||
{ "Menu:Keybinds", "FreeCamToggleKey", std::string("VK_F3"), &Menu::Camera::freeCam, String},
|
||||
{ "Menu:Keybinds", "TeleportPlayerToCameraToggleKey", std::string("VK_F4"), &Menu::Camera::teleportPlayerToCamera, String},
|
||||
{ "Menu:Keybinds", "ThirdPersonToggleKey", std::string("VK_F1"), &Menu::Camera::thirdPersonCamera, String},
|
||||
@ -4366,6 +4367,7 @@ namespace Config {
|
||||
{ "Player:Misc", "DisableOutOfBoundsTimer", true, &Menu::Player::disableOutOfBoundsTimer, OPTION },
|
||||
{ "Player:Misc", "NightrunnerMode", false, &Menu::Player::nightrunnerMode, OPTION },
|
||||
{ "Player:Misc", "OneHandedMode", false, &Menu::Player::oneHandedMode, OPTION },
|
||||
{ "Player:Misc", "AllowGrappleHookInSafezone", false, &Menu::Player::allowGrappleHookInSafezone, OPTION },
|
||||
{ "Player:PlayerVariables", "Enabled", false, &Menu::Player::playerVariables, OPTION },
|
||||
{ "Player:PlayerVariables", "LastSaveSCRPath", std::string(), &Menu::Player::saveSCRPath, String },
|
||||
{ "Player:PlayerVariables", "LastLoadSCRFilePath", std::string(), &Menu::Player::loadSCRFilePath, String },
|
||||
|
@ -83,11 +83,10 @@ namespace Engine {
|
||||
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))
|
||||
if (!entry->is_directory())
|
||||
continue;
|
||||
|
||||
cachedUserModDirs.push_back(pathToDir.string());
|
||||
cachedUserModDirs.push_back(entry->path().string());
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
spdlog::error("Exception thrown while caching user mod directories: {}", e.what());
|
||||
@ -120,15 +119,18 @@ namespace Engine {
|
||||
if (!std::filesystem::exists(finalPath))
|
||||
continue;
|
||||
|
||||
finalPath.replace(0, userModFilesFullPath.size() + 1, ""); // replace entire path until mod folder with nothing
|
||||
finalPath.erase(0, userModFilesFullPath.size() + 1); // erase entire path until mod folder
|
||||
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
|
||||
DWORD64 finalAddr = reinterpret_cast<DWORD64>(filePath2);
|
||||
if (firstByte != 0x0)
|
||||
finalAddr |= (firstByte << 56);
|
||||
|
||||
const DWORD64 result = FsOpenHook.pOriginal(finalAddr, a2, a3);
|
||||
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 FsOpenHook.pOriginal(file, a2, a3);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -139,65 +141,65 @@ namespace Engine {
|
||||
}
|
||||
#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:
|
||||
// Thank you @12brendon34 on Discord for help with finding the function responsible for .PAK loading!
|
||||
#pragma region CResourceLoadingRuntimeCreate
|
||||
namespace fs {
|
||||
struct mount_path {
|
||||
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 DWORD64 mount(mount_path* path, USHORT flags, LPVOID* a3) {
|
||||
DWORD64(*pMount)(mount_path*, USHORT, LPVOID*) = (decltype(pMount))Utils::Memory::GetProcAddr("filesystem_x64_rwdi.dll", "?mount@fs@@YA_NAEBUmount_path@1@GPEAPEAVCFsMount@@@Z");
|
||||
if (!pMount)
|
||||
return 0;
|
||||
|
||||
return pMount(path, flags, a3);
|
||||
}
|
||||
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;
|
||||
static LPVOID GetCResourceLoadingRuntimeCreate() {
|
||||
return Utils::Memory::GetProcAddr("engine_x64_rwdi.dll", "?Create@CResourceLoadingRuntime@@SAPEAV1@_N@Z");
|
||||
}
|
||||
static LPVOID detourCResourceLoadingRuntimeCreate(bool noTexStreaming);
|
||||
Utils::Hook::MHook<LPVOID, LPVOID(*)(bool)> CResourceLoadingRuntimeCreateHook{ "CResourceLoadingRuntimeCreate", &GetCResourceLoadingRuntimeCreate, &detourCResourceLoadingRuntimeCreate };
|
||||
|
||||
static LPVOID detourCResourceLoadingRuntimeCreate(bool noTexStreaming) {
|
||||
std::string gamePath = userModFilesFullPath;
|
||||
Utils::Values::str_replace(gamePath, "\\ph\\source\\data\\EGameTools\\UserModFiles", "");
|
||||
|
||||
std::unique_ptr<fs::mount_path> pathPtr = std::make_unique<fs::mount_path>();
|
||||
pathPtr->gamePath = gamePath.c_str();
|
||||
|
||||
try {
|
||||
const auto rdi = std::filesystem::recursive_directory_iterator(userModFilesFullPath);
|
||||
for (auto entry = std::filesystem::begin(rdi); entry != std::filesystem::end(rdi); ++entry) {
|
||||
if (entry->is_directory())
|
||||
continue;
|
||||
std::string fullPakPath = entry->path().string();
|
||||
if (!Utils::Values::str_ends_with_ci(fullPakPath, ".pak"))
|
||||
continue;
|
||||
|
||||
std::string pakPath = fullPakPath;
|
||||
pakPath.erase(0, gamePath.size() + 1);
|
||||
|
||||
pathPtr->pakPath = pakPath.c_str();
|
||||
pathPtr->fullPakPath = fullPakPath.c_str();
|
||||
|
||||
spdlog::warn("Loading user PAK mod file \"{}\"", pakPath.c_str());
|
||||
if (!fs::mount(pathPtr.get(), 1, nullptr))
|
||||
spdlog::error("fs::mount returned 0! Something went wrong with loading user PAK mod file \"{}\"!\nPlease make sure the path to the file is no longer than 260 characters, and make sure the file is valid!", pakPath.c_str());
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
spdlog::error("Exception thrown while iterating over user mod directories for PAK loading: {}", e.what());
|
||||
}
|
||||
|
||||
return LoadDataPaksHook.pOriginal(a1, a2, a3);
|
||||
return CResourceLoadingRuntimeCreateHook.pOriginal(noTexStreaming);
|
||||
}
|
||||
#pragma endregion*/
|
||||
#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);
|
||||
|
@ -223,6 +223,18 @@ namespace GamePH {
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region CanUseGrappleHook
|
||||
static bool detourCanUseGrappleHook(LPVOID pInstance, bool a2);
|
||||
static Utils::Hook::MHook<LPVOID, bool(*)(LPVOID, bool)> CanUseGrappleHookHook{ "CanUseGrappleHook", &Offsets::Get_CanUseGrappleHook, &detourCanUseGrappleHook };
|
||||
|
||||
static bool detourCanUseGrappleHook(LPVOID pInstance, bool a2) {
|
||||
if (Menu::Player::allowGrappleHookInSafezone.GetValue())
|
||||
return true;
|
||||
|
||||
return CanUseGrappleHookHook.pOriginal(pInstance, a2);
|
||||
}
|
||||
#pragma endregion
|
||||
|
||||
#pragma region ByteHooks
|
||||
static unsigned char SaveGameCRCBoolCheckBytes[3] = { 0xB3, 0x01, 0x90 }; // mov bl, 01
|
||||
Utils::Hook::ByteHook<LPVOID> SaveGameCRCBoolCheckHook{ "SaveGameCRCBoolCheck", &Offsets::Get_SaveGameCRCBoolCheck, SaveGameCRCBoolCheckBytes, sizeof(SaveGameCRCBoolCheckBytes), &Menu::Misc::disableSavegameCRCCheck }; // and bl, dil
|
||||
|
@ -6443,6 +6443,7 @@ namespace Menu {
|
||||
KeyBindOption disableOutOfBoundsTimer{ VK_NONE };
|
||||
KeyBindOption nightrunnerMode{ VK_F9 };
|
||||
KeyBindOption oneHandedMode{ VK_NONE };
|
||||
KeyBindOption allowGrappleHookInSafezone{ VK_NONE };
|
||||
Option playerVariables{};
|
||||
|
||||
std::string saveSCRPath{};
|
||||
@ -6904,19 +6905,20 @@ namespace Menu {
|
||||
}
|
||||
ImGui::CheckboxHotkey("God Mode", &godMode, "Makes the player invincible");
|
||||
ImGui::SameLine();
|
||||
ImGui::CheckboxHotkey("Unlimited Immunity", &unlimitedImmunity, "Stops immunity from draining");
|
||||
ImGui::CheckboxHotkey("Unlimited Stamina", &unlimitedStamina, "Stops stamina from draining");
|
||||
ImGui::SameLine();
|
||||
ImGui::BeginDisabled(freezePlayer.GetChangesAreDisabled()); {
|
||||
ImGui::CheckboxHotkey("Freeze Player", &freezePlayer, "Freezes player position");
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
ImGui::CheckboxHotkey("Unlimited Immunity", &unlimitedImmunity, "Stops immunity from draining");
|
||||
ImGui::SameLine();
|
||||
ImGui::CheckboxHotkey("Unlimited Stamina", &unlimitedStamina, "Stops stamina from draining");
|
||||
ImGui::CheckboxHotkey("Invisible to Enemies", &invisibleToEnemies, "Makes the player invisible to the enemies");
|
||||
ImGui::SameLine();
|
||||
ImGui::CheckboxHotkey("Disable Out of Bounds Timer", &disableOutOfBoundsTimer, "Disables the timer that runs when out of map bounds or mission bounds");
|
||||
ImGui::CheckboxHotkey("Nightrunner Mode", &nightrunnerMode, "Makes Aiden super-human/infected");
|
||||
ImGui::SameLine();
|
||||
ImGui::CheckboxHotkey("One-handed Mode", &oneHandedMode, "Removes Aiden's left hand");
|
||||
ImGui::CheckboxHotkey("Allow Grapple Hook in Safezone", &allowGrappleHookInSafezone, "Allows player to use grapple hook while in a safezone");
|
||||
|
||||
ImGui::SeparatorText("Player Jump Parameters");
|
||||
if (ImGui::Button("Reload Jump Params", "Reloads jump_parameters.scr from any mod located inside EGameTools\\UserModFiles")) {
|
||||
|
@ -16,6 +16,7 @@ namespace Menu {
|
||||
extern KeyBindOption disableOutOfBoundsTimer;
|
||||
extern KeyBindOption nightrunnerMode;
|
||||
extern KeyBindOption oneHandedMode;
|
||||
extern KeyBindOption allowGrappleHookInSafezone;
|
||||
extern Option playerVariables;
|
||||
|
||||
extern std::string saveSCRPath;
|
||||
|
@ -70,6 +70,7 @@ struct Offsets {
|
||||
AddOffset(PlaySoundEvent, "gamedll_ph_x64_rwdi.dll", "4C 8B DC 49 89 5B ?? 49 89 73 ?? 57 48 81 EC ?? ?? ?? ?? 48 8B 44 24 ?? 48 8B F9 48 8B DA", Utils::SigScan::PatternType::Address, LPVOID)
|
||||
AddOffset(CalculateFallHeight, "gamedll_ph_x64_rwdi.dll", "40 55 56 48 8D AC 24 ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? 44 0F 29 9C 24", Utils::SigScan::PatternType::Address, LPVOID)
|
||||
AddOffset(PlayerHealthModuleKillPlayer, "gamedll_ph_x64_rwdi.dll", "40 53 48 83 EC ?? 48 8B 01 48 8B D9 FF 90 ?? ?? ?? ?? 84 C0 74 ?? 48 8B 4B ?? 48 81 C1 ?? ?? ?? ?? 48 8B 01 FF 50", Utils::SigScan::PatternType::Address, LPVOID)
|
||||
AddOffset(CanUseGrappleHook, "gamedll_ph_x64_rwdi.dll", "48 89 5C 24 ?? 57 48 83 EC ?? 48 8B 01 0F B6 FA 48 8B D9 FF 90 ?? ?? ?? ?? F6 80", Utils::SigScan::PatternType::Address, LPVOID)
|
||||
//AddOffset(CompareAndUpdateFloat, "gamedll_ph_x64_rwdi.dll", "0F 2F C1 73 ?? 0F 28 C1 C3", Utils::SigScan::PatternType::Address, LPVOID)
|
||||
//AddOffset(HandlePlayerImmunity, "gamedll_ph_x64_rwdi.dll", "48 8B C4 53 56 57 41 56 41 57", Utils::SigScan::PatternType::Address, LPVOID)
|
||||
//AddOffset(HandlePlayerImmunity2, "gamedll_ph_x64_rwdi.dll", "40 55 56 41 56 41 57 48 8D 6C 24 ?? 48 81 EC ?? ?? ?? ?? 48 8B F1 45 0F B6 F0", Utils::SigScan::PatternType::Address, LPVOID)
|
||||
|
@ -2,13 +2,23 @@
|
||||
|
||||
namespace Utils {
|
||||
namespace Values {
|
||||
const bool are_samef(float a, float b, float precision) { return abs(a - b) < precision; }
|
||||
bool str_ends_with_ci(std::string const& text, std::string const& substr) {
|
||||
if (substr.length() > text.length())
|
||||
return false;
|
||||
|
||||
auto it = std::search(text.rbegin(), text.rbegin() + substr.length(), substr.rbegin(), substr.rend(), [](char ch1, char ch2) {
|
||||
return std::toupper(ch1) == std::toupper(ch2);
|
||||
});
|
||||
return it == text.rbegin();
|
||||
}
|
||||
|
||||
bool are_samef(float a, float b, float precision) { return abs(a - b) < precision; }
|
||||
float round_decimal(float value, int decimal_places) {
|
||||
const double multiplier = std::pow(10.0f, decimal_places);
|
||||
return std::roundf(value * static_cast<float>(multiplier)) / static_cast<float>(multiplier);
|
||||
}
|
||||
|
||||
const bool str_replace(std::string& str, const std::string& from, const std::string& to) {
|
||||
bool str_replace(std::string& str, const std::string& from, const std::string& to) {
|
||||
const size_t start_pos = str.find(from);
|
||||
if (start_pos == std::string::npos)
|
||||
return false;
|
||||
|
@ -3,10 +3,12 @@
|
||||
|
||||
namespace Utils {
|
||||
namespace Values {
|
||||
extern const bool are_samef(float a, float b, float precision = 0.0001f);
|
||||
extern bool str_ends_with_ci(std::string const& text, std::string const& substr);
|
||||
|
||||
extern bool are_samef(float a, float b, float precision = 0.0001f);
|
||||
extern float round_decimal(float value, int decimal_places = 2);
|
||||
|
||||
extern const bool str_replace(std::string& str, const std::string& from, const std::string& to);
|
||||
extern bool str_replace(std::string& str, const std::string& from, const std::string& to);
|
||||
template <typename T> auto to_string(T val) {
|
||||
if constexpr (std::is_same<T, std::string>::value)
|
||||
return static_cast<std::string>(val);
|
||||
|
Reference in New Issue
Block a user