changed VarManagerBase alongside the other var management classes

This commit is contained in:
EricPlayZ
2025-02-23 06:48:04 +02:00
parent 0c7b625a9c
commit e88031630d
29 changed files with 826 additions and 706 deletions

View File

@ -13,10 +13,10 @@
<ItemGroup>
<ClCompile Include="deps\memscan\memscan.c" />
<ClCompile Include="deps\memscan\util\util.c" />
<ClCompile Include="Offsets.cpp" />
<ClCompile Include="SaveGameManager.cpp" />
<ClCompile Include="src\ClassHelpers.cpp" />
<ClCompile Include="src\Core\Core.cpp" />
<ClCompile Include="src\Core\SaveGameManager.cpp" />
<ClCompile Include="src\Core\SteamAPI.cpp" />
<ClCompile Include="src\dllmain.cpp" />
<ClCompile Include="src\Engine\CBulletPhysicsCharacter.cpp" />
<ClCompile Include="src\Engine\CGame.cpp" />
@ -34,6 +34,9 @@
<ClCompile Include="src\Engine\CVideoSettings.cpp" />
<ClCompile Include="src\Engine\Engine_Misc.cpp" />
<ClCompile Include="src\Engine\VarBase.cpp" />
<ClCompile Include="src\Engine\VarManagerBase.cpp" />
<ClCompile Include="src\Engine\VarMapBase.cpp" />
<ClCompile Include="src\Engine\VarRef.cpp" />
<ClCompile Include="src\GamePH\CoPlayerRestrictions.cpp" />
<ClCompile Include="src\GamePH\DayNightCycle.cpp" />
<ClCompile Include="src\GamePH\FreeCamera.cpp" />
@ -55,6 +58,7 @@
<ClCompile Include="src\GamePH\TimeWeather\CSystem.cpp" />
<ClCompile Include="src\GamePH\TPPCameraDI.cpp" />
<ClCompile Include="src\Mtx34.cpp" />
<ClCompile Include="src\Offsets.cpp" />
<ClCompile Include="src\Utils\Files.cpp" />
<ClCompile Include="src\Utils\Hook.cpp" />
<ClCompile Include="src\Utils\Memory.cpp" />
@ -62,13 +66,10 @@
<ClCompile Include="src\Utils\Sigscan.cpp" />
<ClCompile Include="src\Utils\Time.cpp" />
<ClCompile Include="src\Utils\Values.cpp" />
<ClCompile Include="src\Utils\WinMemory.cpp" />
<ClCompile Include="src\Vec2.cpp" />
<ClCompile Include="src\Vec3.cpp" />
<ClCompile Include="src\Vec4.cpp" />
<ClCompile Include="SteamAPI.cpp" />
<ClCompile Include="VarManagerBase.cpp" />
<ClCompile Include="VarMapBase.cpp" />
<ClCompile Include="WinMemory.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\EGSDK\ClassHelpers.h" />
@ -95,6 +96,7 @@
<ClInclude Include="include\EGSDK\Engine\VarBase.h" />
<ClInclude Include="include\EGSDK\Engine\VarManagerBase.h" />
<ClInclude Include="include\EGSDK\Engine\VarMapBase.h" />
<ClInclude Include="include\EGSDK\Engine\VarRef.h" />
<ClInclude Include="include\EGSDK\Exports.h" />
<ClInclude Include="include\EGSDK\GamePH\CameraFPPDI.h" />
<ClInclude Include="include\EGSDK\GamePH\CoBaseCameraProxy.h" />

View File

@ -133,21 +133,9 @@
<ClCompile Include="src\GamePH\CoPlayerRestrictions.cpp">
<Filter>src\GamePH</Filter>
</ClCompile>
<ClCompile Include="SaveGameManager.cpp">
<Filter>src\Core</Filter>
</ClCompile>
<ClCompile Include="SteamAPI.cpp">
<Filter>src\Core</Filter>
</ClCompile>
<ClCompile Include="Offsets.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="src\Engine\CVars.cpp">
<Filter>src\Engine</Filter>
</ClCompile>
<ClCompile Include="WinMemory.cpp">
<Filter>src\Utils</Filter>
</ClCompile>
<ClCompile Include="src\Engine\IBaseCamera.cpp">
<Filter>src\Engine</Filter>
</ClCompile>
@ -166,15 +154,30 @@
<ClCompile Include="src\Vec2.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="VarMapBase.cpp">
<Filter>src\Engine</Filter>
</ClCompile>
<ClCompile Include="VarManagerBase.cpp">
<Filter>src\Engine</Filter>
</ClCompile>
<ClCompile Include="src\Engine\VarBase.cpp">
<Filter>src\Engine</Filter>
</ClCompile>
<ClCompile Include="src\Core\SaveGameManager.cpp">
<Filter>src\Core</Filter>
</ClCompile>
<ClCompile Include="src\Core\SteamAPI.cpp">
<Filter>src\Core</Filter>
</ClCompile>
<ClCompile Include="src\Offsets.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="src\Utils\WinMemory.cpp">
<Filter>src\Utils</Filter>
</ClCompile>
<ClCompile Include="src\Engine\VarRef.cpp">
<Filter>src\Engine</Filter>
</ClCompile>
<ClCompile Include="src\Engine\VarMapBase.cpp">
<Filter>src\Engine</Filter>
</ClCompile>
<ClCompile Include="src\Engine\VarManagerBase.cpp">
<Filter>src\Engine</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="include">
@ -419,5 +422,8 @@
<ClInclude Include="include\EGSDK\Engine\VarBase.h">
<Filter>include\Engine</Filter>
</ClInclude>
<ClInclude Include="include\EGSDK\Engine\VarRef.h">
<Filter>include\Engine</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -1,137 +0,0 @@
#include <EGSDK\Offsets.h>
#include <EGSDK\Engine\CBulletPhysicsCharacter.h>
#include <EGSDK\Engine\CGame.h>
#include <EGSDK\Engine\CVideoSettings.h>
#include <EGSDK\GamePH\CoPlayerRestrictions.h>
#include <EGSDK\GamePH\FreeCamera.h>
#include <EGSDK\GamePH\GameDI_PH.h>
#include <EGSDK\GamePH\LocalClientDI.h>
#include <EGSDK\GamePH\PlayerDI_PH.h>
#include <EGSDK\GamePH\PlayerState.h>
#include <EGSDK\GamePH\SessionCooperativeDI.h>
#include <EGSDK\ClassHelpers.h>
namespace EGSDK {
bool OffsetManager::initialized = false;
void OffsetManager::InitializeOffsetsAndPatterns() {
if (initialized)
return;
AddOffsets(11200, {
{ "OnPostUpdate", 0x378 },
{ GetOffsetNameFromClassMember(&Engine::CBulletPhysicsCharacter::playerPos2), 0x880 },
{ GetOffsetNameFromClassMember(&Engine::CBulletPhysicsCharacter::playerPos), 0x898 },
{ GetOffsetNameFromClassMember(&Engine::CBulletPhysicsCharacter::playerDownwardVelocity), 0xC18 },
{ GetOffsetNameFromClassMember(&Engine::CGame::pCLevel), 0x380 },
{ GetOffsetNameFromClassMember(&Engine::CVideoSettings::extraFOV), 0x78 },
{ GetOffsetNameFromClassMember(&GamePH::CoPlayerRestrictions::flags), 0x1C0 },
{ GetOffsetNameFromClassMember(&GamePH::FreeCamera::enableSpeedMultiplier1), 0x4C },
{ GetOffsetNameFromClassMember(&GamePH::FreeCamera::enableSpeedMultiplier2), 0x4D },
{ GetOffsetNameFromClassMember(&GamePH::FreeCamera::speedMultiplier), 0x150 },
//{ GetOffsetNameFromClassMember(&GamePH::FreeCamera::mouseSensitivityMultiplier), 0x1A0 },
{ GetOffsetNameFromClassMember(&GamePH::GameDI_PH::blockPauseGameOnPlayerAfk), 0x830 },
{ GetOffsetNameFromClassMember(&GamePH::GameDI_PH::pSessionCooperativeDI), 0xE8 },
{ GetOffsetNameFromClassMember(&GamePH::LocalClientDI::pPlayerDI_PH), 0x88 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::pCoPhysicsProperty), 0xE8 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::pInventoryContainerDI), 0x550 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::nextPlayerOrientation), 0xC68 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::restrictionsEnabled), 0x2CF0 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::enableTPPModel1), 0x2DC1 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::enableTPPModel2), 0x2DC2 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerState::playerVariables), 0x280 },
{ GetOffsetNameFromClassMember(&GamePH::SessionCooperativeDI::pLocalClientDI), 0xD10 },
});
AddOffsets(12001, {
{ "OnPostUpdate", 0x3A8 },
{ GetOffsetNameFromClassMember(&Engine::CBulletPhysicsCharacter::playerPos2), 0xCB8 },
{ GetOffsetNameFromClassMember(&Engine::CBulletPhysicsCharacter::playerPos), 0xCD0 },
{ GetOffsetNameFromClassMember(&Engine::CBulletPhysicsCharacter::playerDownwardVelocity), 0x1050 },
{ GetOffsetNameFromClassMember(&Engine::CGame::pCLevel), 0x390 },
{ GetOffsetNameFromClassMember(&Engine::CVideoSettings::extraFOV), 0x7C },
{ GetOffsetNameFromClassMember(&GamePH::CoPlayerRestrictions::flags), 0x1F0 },
{ GetOffsetNameFromClassMember(&GamePH::FreeCamera::enableSpeedMultiplier1), 0x42 },
{ GetOffsetNameFromClassMember(&GamePH::FreeCamera::enableSpeedMultiplier2), 0x43 },
{ GetOffsetNameFromClassMember(&GamePH::FreeCamera::speedMultiplier), 0x1CC },
{ GetOffsetNameFromClassMember(&GamePH::GameDI_PH::blockPauseGameOnPlayerAfk), 0x910 },
{ GetOffsetNameFromClassMember(&GamePH::GameDI_PH::pSessionCooperativeDI), 0x130 },
{ GetOffsetNameFromClassMember(&GamePH::LocalClientDI::pPlayerDI_PH), 0x90 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::pCoPhysicsProperty), 0xF0 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::pInventoryContainerDI), 0x470 },
//{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::pPlayerFppVis_PH), 0x420 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::nextPlayerOrientation), 0xB88 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::restrictionsEnabled), 0x3520 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::enableTPPModel1), 0x35E9 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::enableTPPModel2), 0x35EA },
{ GetOffsetNameFromClassMember(&GamePH::PlayerState::playerVariables), 0x300 },
{ GetOffsetNameFromClassMember(&GamePH::SessionCooperativeDI::pLocalClientDI), 0xE08 },
});
AddPatterns(11200, {
{ "LoadPlayerVars", { "40 55 53 57 48 8D AC 24 ?? ?? ?? ?? B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 2B E0 33 FF", Utils::SigScan::PatternType::Address } },
{ "PlayerState", { "48 8B 3D [?? ?? ?? ?? 4C 8B EA", Utils::SigScan::PatternType::RelativePointer } },
{ "SaveGameCRCBoolCheck", { "FF 50 ?? [40 22 FB 0F 85 ?? ?? ?? ?? 0F B6 05 ?? ?? ?? ?? 48 8D 1D", Utils::SigScan::PatternType::Address } },
{ "IsNotOutOfMapBounds", { "48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 41 56 41 57 48 83 EC ?? 4C 8B C2", Utils::SigScan::PatternType::Address } },
{ "IsNotOutOfMissionBounds", { "48 89 5C 24 ?? 57 48 83 EC ?? 4C 8B C2 48 8B F9", Utils::SigScan::PatternType::Address } },
{ "PlaySoundEvent", { "4C 8B DC 49 89 5B ?? 49 89 73 ?? 57 48 81 EC ?? ?? ?? ?? 4C 8B 4C 24 ?? 48 8B F9 4D 8B D0 66 C7 84 24 ?? ?? ?? ?? ?? ?? 49 8B C1 66 C7 84 24", Utils::SigScan::PatternType::Address } },
{ "GetPlayerRestrictionsFlags", { "48 89 5C 24 ?? 57 48 83 EC ?? 48 8B F9 48 8B DA 48 8B CA E8 ?? ?? ?? ?? 48 8B 4F", Utils::SigScan::PatternType::Address } },
{ "EnablePlayerRestrictionsSubFunc", { "40 53 48 83 EC ?? 48 8B D9 48 81 C1 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B CB 48 83 C4 ?? 5B E9 ?? ?? ?? ?? CC CC CC CC CC CC CC CC CC CC CC CC CC CC 48 89 4C 24", Utils::SigScan::PatternType::Address } },
{ "DisablePlayerRestrictionsSubFunc", { "48 89 5C 24 ?? 48 89 6C 24 ?? 56 57 41 54 41 56 41 57 48 83 EC ?? 0F B7 81", Utils::SigScan::PatternType::Address } },
{ "HandlePlayerRestrictions", { "40 57 48 83 EC ?? 48 89 5C 24 ?? 48 8B F9 48 89 6C 24 ?? 0F B6 A9", Utils::SigScan::PatternType::Address } }
});
AddPatterns(12001, {
{ "LoadPlayerVars", { "48 89 4C 24 ?? B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 2B E0 48 8B 8C 24", Utils::SigScan::PatternType::Address } },
{ "PlayerState", { "48 8B 35 [?? ?? ?? ?? 4C 8B F2 48 8B F9", Utils::SigScan::PatternType::RelativePointer } },
{ "SaveGameCRCBoolCheck", { "FF 50 ?? [40 22 DF 0F 85 ?? ?? ?? ?? 0F B6 05 ?? ?? ?? ?? 48 8D 3D", Utils::SigScan::PatternType::Address } },
{ "IsNotOutOfMapBounds", { "48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 41 56 41 57 48 83 EC ?? 4C 8B F9 48 85 D2", Utils::SigScan::PatternType::Address } },
{ "IsNotOutOfMissionBounds", { "48 89 5C 24 ?? 57 48 83 EC ?? 48 8B F9 48 85 D2 74 ?? 48 8D 8A", Utils::SigScan::PatternType::Address } },
{ "PlaySoundEvent", { "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 } },
{ "GetPlayerRestrictionsFlags", { "48 89 5C 24 ?? 57 48 83 EC ?? 48 8B D9 48 8B FA 48 8B CA E8 ?? ?? ?? ?? 48 8B 4B", Utils::SigScan::PatternType::Address } },
{ "EnablePlayerRestrictionsSubFunc", { "40 53 48 83 EC ?? 48 8B D9 48 81 C1 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B CB 48 83 C4 ?? 5B E9 ?? ?? ?? ?? CC CC CC CC CC CC CC CC CC CC CC CC CC CC 40 57", Utils::SigScan::PatternType::Address } },
{ "DisablePlayerRestrictionsSubFunc", { "48 89 5C 24 ?? 48 89 6C 24 ?? 56 57 41 54 41 56 41 57 48 83 EC ?? 0F B6 81", Utils::SigScan::PatternType::Address } },
{ "HandlePlayerRestrictions", { "40 57 48 83 EC ?? 48 89 5C 24 ?? 48 8B F9 48 89 74 24 ?? 0F B6 B1", Utils::SigScan::PatternType::Address } }
});
initialized = true;
}
DWORD OffsetManager::GetOffset(const std::string& offsetName) {
if (!initialized)
return 0;
auto& offsets = GetOffsetsMap();
if (offsets.find(Core::gameVer) != offsets.end() && offsets[Core::gameVer].find(offsetName) != offsets[Core::gameVer].end())
return offsets[Core::gameVer][offsetName];
SPDLOG_ERROR("Offset not found for key: \"{}\" in version: {}", offsetName, Core::gameVer);
return 0;
}
Utils::SigScan::Pattern OffsetManager::GetPattern(const std::string& patternName) {
if (!initialized)
return {};
auto& patterns = GetPatternsMap();
if (patterns.find(Core::gameVer) != patterns.end() && patterns[Core::gameVer].find(patternName) != patterns[Core::gameVer].end())
return patterns[Core::gameVer][patternName];
SPDLOG_ERROR("Pattern not found for key: \"{}\" in version: {}", patternName, Core::gameVer);
return {};
}
void OffsetManager::AddOffsets(DWORD gameVer, const std::unordered_map<std::string, DWORD>& offsets) {
GetOffsetsMap()[gameVer] = offsets;
}
void OffsetManager::AddPatterns(DWORD gameVer, const std::unordered_map<std::string, Utils::SigScan::Pattern>& patterns) {
GetPatternsMap()[gameVer] = patterns;
}
std::unordered_map<DWORD, std::unordered_map<std::string, DWORD>>& OffsetManager::GetOffsetsMap() {
static std::unordered_map<DWORD, std::unordered_map<std::string, DWORD>> offsetsMap;
return offsetsMap;
}
std::unordered_map<DWORD, std::unordered_map<std::string, Utils::SigScan::Pattern>>& OffsetManager::GetPatternsMap() {
static std::unordered_map<DWORD, std::unordered_map<std::string, Utils::SigScan::Pattern>> patternsMap;
return patternsMap;
}
}

View File

@ -1,168 +0,0 @@
#include <spdlog\spdlog.h>
#include <EGSDK\Utils\Files.h>
#include <EGSDK\Core\Core.h>
#include <EGSDK\Core\SaveGameManager.h>
#include <EGSDK\Core\SteamAPI.h>
namespace EGSDK::Core {
std::filesystem::path SaveGameManager::saveGamePath{};
std::filesystem::path SaveGameManager::backupRootPath{};
int SaveGameManager::maxBackupSlots = 16;
std::chrono::minutes SaveGameManager::backupInterval{ 20 };
int SaveGameManager::currentBackupSlot = 0;
Utils::Time::Timer SaveGameManager::timeSpentInitializing{ 30000 };
bool SaveGameManager::initialized = false;
bool SaveGameManager::isInitializing = false;
bool SaveGameManager::triedInitializingWithSteam = false;
bool SaveGameManager::loopIsRunning = false;
void SaveGameManager::Init() {
if (initialized || isInitializing)
return;
isInitializing = true;
timeSpentInitializing.Reset();
while (true) {
if (timeSpentInitializing.DidTimePass()) {
if (!triedInitializingWithSteam) {
triedInitializingWithSteam = true;
timeSpentInitializing.Reset();
continue;
}
SPDLOG_ERROR("Failed initializing SaveGameManager after 20 seconds");
MessageBoxA(nullptr, "EGameSDK encountered an issue trying to initialize its Savegame Manager.\nPLEASE MANUALLY MAKE BACKUPS OF YOUR SAVEGAME BEFORE using EGameSDK and any other mods, such as EGameTools!", "Failed initializing SaveGameManager", MB_ICONERROR | MB_OK | MB_SETFOREGROUND);
return;
}
if (backupRootPath.empty()) {
SPDLOG_INFO("Getting SDK storage path");
std::filesystem::path sdkStoragePath = GetSDKStoragePath();
if (!sdkStoragePath.empty())
backupRootPath = sdkStoragePath / "SavegameBackups";
}
if (saveGamePath.empty()) {
SPDLOG_INFO("Detecting savegame path");
saveGamePath = !triedInitializingWithSteam ? DetectSaveGamePathSteam() : DetectSaveGamePathEpic();
}
if (!saveGamePath.empty() && !backupRootPath.empty())
break;
Sleep(2000);
}
SPDLOG_INFO("SaveGameManager initialization successful");
isInitializing = false;
initialized = true;
}
void SaveGameManager::Loop() {
if (!initialized || loopIsRunning)
return;
loopIsRunning = true;
SPDLOG_INFO("Initializing backup slot");
InitializeBackupSlot();
SPDLOG_INFO("Performing first savegame backup...");
PerformBackup();
while (true) {
std::this_thread::sleep_for(backupInterval);
SPDLOG_INFO("Performing periodic savegame backup...");
PerformBackup();
}
}
void SaveGameManager::PerformBackup() {
std::filesystem::path destinationPath = backupRootPath / ("Backup_" + std::to_string(currentBackupSlot));
if (triedInitializingWithSteam)
destinationPath = destinationPath / "out" / "storage";
try {
if (std::filesystem::exists(destinationPath))
std::filesystem::remove_all(destinationPath);
std::filesystem::create_directories(destinationPath);
std::filesystem::copy(saveGamePath, destinationPath, std::filesystem::copy_options::recursive);
SPDLOG_INFO("Backup successfully created in \"{}\"!", destinationPath.string());
// Calculate next backup slot and cleanup
int slotToDelete = (currentBackupSlot + 85) % 100;
std::filesystem::path deletePath = backupRootPath / ("Backup_" + std::to_string(slotToDelete));
if (std::filesystem::exists(deletePath)) {
std::filesystem::remove_all(deletePath);
SPDLOG_INFO("Deleted old backup folder: \"{}\"", deletePath.string());
}
currentBackupSlot = (currentBackupSlot + 1) % 100;
} catch (const std::exception& ex) {
SPDLOG_ERROR("Exception caught while trying to backup savegame: {}", ex.what());
}
}
void SaveGameManager::InitializeBackupSlot() {
int highestSlot = -1;
for (const auto& entry : std::filesystem::directory_iterator(backupRootPath)) {
if (entry.is_directory()) {
std::string folderName = entry.path().filename().string();
if (folderName.rfind("Backup_", 0) == 0) { // Check if it starts with "Backup_"
try {
int slotNumber = std::stoi(folderName.substr(7));
if (slotNumber > highestSlot)
highestSlot = slotNumber;
} catch (const std::exception& ex) {
SPDLOG_ERROR("Failed to parse backup folder name: \"{}\", exception: {}", folderName, ex.what());
}
}
}
}
if (highestSlot != -1) {
currentBackupSlot = (highestSlot + 1) % 100;
SPDLOG_INFO("Initialized current backup slot to: {}", currentBackupSlot);
} else
SPDLOG_INFO("No existing backups found. Starting with slot 0");
}
std::filesystem::path SaveGameManager::DetectSaveGamePathSteam() {
auto steamUser = SteamAPI::GetISteamUser();
if (!steamUser) {
SPDLOG_ERROR("Failed getting Steam user");
return {};
}
char userDataFolder[256];
if (!steamUser->GetUserDataFolder(userDataFolder, sizeof(userDataFolder))) {
SPDLOG_ERROR("Failed getting Steam user data path");
return {};
}
std::filesystem::path gameUserDataPath = userDataFolder;
if (gameUserDataPath.filename() == "local")
gameUserDataPath = gameUserDataPath.parent_path() / "remote";
if (!std::filesystem::exists(gameUserDataPath)) {
SPDLOG_ERROR("Savegame path does not exist: {}", gameUserDataPath.string());
return {};
}
return gameUserDataPath;
}
std::filesystem::path SaveGameManager::DetectSaveGamePathEpic() {
std::filesystem::path documentsPath = Utils::Files::GetDocumentsDir();
if (documentsPath.empty()) {
SPDLOG_ERROR("Failed getting user Documents path");
return {};
}
std::filesystem::path gameStoragePath = documentsPath / "dying light 2" / "out" / "storage";
if (!std::filesystem::exists(gameStoragePath)) {
SPDLOG_ERROR("Savegame path does not exist: {}", gameStoragePath.string());
return {};
}
return gameStoragePath;
}
}

View File

@ -1,39 +0,0 @@
#include <EGSDK\Core\SteamAPI.h>
#include <EGSDK\Utils\Memory.h>
#include <EGSDK\Utils\WinMemory.h>
namespace EGSDK::Core {
ISteamClient* SteamAPI::SteamClient() {
return Utils::Memory::SafeCallFunction("steam_api64.dll", "SteamClient", nullptr);
}
HSteamUser SteamAPI::GetHSteamUser() {
return Utils::Memory::SafeCallFunction("steam_api64.dll", "SteamAPI_GetHSteamUser", -1);
}
HSteamPipe SteamAPI::GetHSteamPipe() {
return Utils::Memory::SafeCallFunction("steam_api64.dll", "SteamAPI_GetHSteamPipe", -1);
}
ISteamUser* SteamAPI::GetISteamUser() {
auto steamClient = SteamClient();
if (!steamClient)
return nullptr;
auto hSteamUser = SteamAPI::GetHSteamUser();
auto hSteamPipe = SteamAPI::GetHSteamPipe();
if (!hSteamUser || !hSteamPipe)
return {};
return steamClient->GetISteamUser(hSteamUser, hSteamPipe, STEAMUSER_INTERFACE_VERSION);
}
ISteamUtils* SteamAPI::GetISteamUtils() {
auto steamClient = SteamClient();
if (!steamClient)
return nullptr;
auto hSteamPipe = SteamAPI::GetHSteamPipe();
if (!hSteamPipe)
return {};
return steamClient->GetISteamUtils(hSteamPipe, STEAMUTILS_INTERFACE_VERSION);
}
}

View File

@ -1,63 +0,0 @@
#include <EGSDK\Engine\VarManagerBase.h>
#include <EGSDK\Engine\CVars.h>
#include <EGSDK\GamePH\PlayerVariables.h>
namespace EGSDK::Engine {
template <typename VarMapT, typename VarT>
VarMapT VarManagerBase<VarMapT, VarT>::vars{};
template <typename VarMapT, typename VarT>
VarMapT VarManagerBase<VarMapT, VarT>::customVars{};
template <typename VarMapT, typename VarT>
VarMapT VarManagerBase<VarMapT, VarT>::defaultVars{};
template <typename VarMapT, typename VarT>
VarMapT VarManagerBase<VarMapT, VarT>::defaultCustomVars{};
template <typename VarMapT, typename VarT>
std::recursive_mutex VarManagerBase<VarMapT, VarT>::mutex{};
template <typename VarMapT, typename VarT>
std::unordered_map<std::string, std::any> VarManagerBase<VarMapT, VarT>::prevVarValueMap{};
template <typename VarMapT, typename VarT>
std::unordered_map<std::string, bool> VarManagerBase<VarMapT, VarT>::prevBoolValueMap{};
template <typename VarMapT, typename VarT>
std::unordered_map<std::string, uint64_t> VarManagerBase<VarMapT, VarT>::varOwnerMap{};
template <typename VarMapT, typename VarT>
bool VarManagerBase<VarMapT, VarT>::AreAnyVarsPresent() {
return !vars.empty();
}
template <typename VarMapT, typename VarT>
bool VarManagerBase<VarMapT, VarT>::AreAnyCustomVarsPresent() {
return !customVars.empty();
}
template <typename VarMapT, typename VarT>
bool VarManagerBase<VarMapT, VarT>::AreAllCustomVarsManagedByBool() {
bool allManagedByBool = true;
customVars.ForEach([&allManagedByBool](const std::unique_ptr<VarT>& varPtr) {
if (!_IsManagedByBool(varPtr->GetName())) {
allManagedByBool = false;
return;
}
});
return allManagedByBool;
}
template <typename VarMapT, typename VarT>
bool VarManagerBase<VarMapT, VarT>::_IsManagedByBool(const char* name) {
std::lock_guard lock(mutex);
return prevBoolValueMap.find(name) != prevBoolValueMap.end() && prevBoolValueMap[name];
}
template <typename VarMapT, typename VarT>
bool VarManagerBase<VarMapT, VarT>::_IsManagedByBool(VarRef<VarMapT, VarT>* var) {
return _IsManagedByBool(var->GetName());
}
template <typename VarMapT, typename VarT>
bool VarManagerBase<VarMapT, VarT>::_HasCustomValue(VarRef<VarMapT, VarT>* var) {
return !customVars.none_of(var->GetName());
}
template EGameSDK_API class VarManagerBase<CVarMap, CVar>;
template EGameSDK_API class VarManagerBase<GamePH::PlayerVarMap, GamePH::PlayerVar>;
}

View File

@ -1,59 +0,0 @@
#include <EGSDK\Engine\VarMapBase.h>
#include <EGSDK\Engine\CVars.h>
#include <EGSDK\GamePH\PlayerVariables.h>
namespace EGSDK::Engine {
template <typename VarT>
std::unique_ptr<VarT>& VarMapBase<VarT>::try_emplace(std::unique_ptr<VarT> var) {
std::lock_guard lock(mutex);
const std::string& name = var->GetName();
auto [it, inserted] = vars.try_emplace(name, std::move(var));
if (inserted)
varsOrdered.emplace_back(name);
return it->second;
}
template <typename VarT>
bool VarMapBase<VarT>::empty() const {
std::lock_guard lock(mutex);
return vars.empty();
}
template <typename VarT>
bool VarMapBase<VarT>::none_of(const std::string& name) const {
std::lock_guard lock(mutex);
return vars.find(name) == vars.end();
}
template <typename VarT>
void VarMapBase<VarT>::reserve(size_t count) {
std::lock_guard lock(mutex);
vars.reserve(count);
}
template <typename VarT>
size_t VarMapBase<VarT>::size() {
std::lock_guard lock(mutex);
return vars.size();
}
template <typename VarT>
VarT* VarMapBase<VarT>::Find(const std::string& name) const {
std::lock_guard lock(mutex);
auto it = vars.find(name);
return (it != vars.end()) ? it->second.get() : nullptr;
}
template <typename VarT>
void VarMapBase<VarT>::Erase(const std::string& name) {
std::lock_guard lock(mutex);
auto it = vars.find(name);
if (it == vars.end())
return;
auto orderIt = std::find(varsOrdered.begin(), varsOrdered.end(), name);
if (orderIt != varsOrdered.end())
varsOrdered.erase(orderIt);
vars.erase(it);
}
template EGameSDK_API class VarMapBase<CVar>;
template EGameSDK_API class VarMapBase<GamePH::PlayerVar>;
}

View File

@ -1,39 +0,0 @@
#include <unordered_map>
#include <EGSDK\Utils\WinMemory.h>
namespace EGSDK::Utils {
namespace Memory {
HMODULE GetCallingDLLModule(void* callerAddress) {
HMODULE callerModule{};
if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR)callerAddress, &callerModule))
return callerModule;
return nullptr;
}
MODULEINFO GetModuleInfo(const char* szModule) {
if (!szModule)
return MODULEINFO();
static std::unordered_map<std::string_view, MODULEINFO> moduleInfoCache;
auto it = moduleInfoCache.find(szModule);
if (it != moduleInfoCache.end())
return it->second;
HMODULE hModule = GetModuleHandle(szModule);
if (hModule == 0)
return MODULEINFO();
MODULEINFO moduleInfo{};
GetModuleInformation(GetCurrentProcess(), hModule, &moduleInfo, sizeof(MODULEINFO));
moduleInfoCache[szModule] = moduleInfo;
return moduleInfoCache[szModule];
}
FARPROC GetProcAddr(const std::string_view& module, const std::string_view& funcName) {
HMODULE moduleHandle = GetModuleHandle(module.data());
if (!moduleHandle)
return nullptr;
return GetProcAddress(moduleHandle, funcName.data());
}
}
}

View File

@ -10,7 +10,6 @@ namespace EGSDK::Engine {
union {
ClassHelpers::StaticBuffer<0x50, uint32_t> valueOffset;
};
explicit CVar(const std::string& name);
explicit CVar(const std::string& name, VarType type);
@ -44,19 +43,43 @@ namespace EGSDK::Engine {
class EGameSDK_API CVarMap : public VarMapBase<CVar> {
public:
using VarMapBase<CVar>::Find;
using VarMapBase<CVar>::none_of;
bool none_of(uint32_t valueOffset);
CVar* Find(uint32_t valueOffset) const;
using Base = VarMapBase<CVar>;
using Base::Find;
using Base::none_of;
std::unique_ptr<CVar>& try_emplace(std::unique_ptr<CVar> var) override;
CVar* Find(uint32_t valueOffset) const;
void Erase(const std::string& name) override;
bool none_of(uint32_t valueOffset);
private:
std::unordered_map<uint32_t, CVar*> varsByValueOffset;
};
class EGameSDK_API CVars : public VarManagerBase<CVarMap, CVar> {};
class EGameSDK_API CVarRef : public VarRef<CVarMap, CVar> {
public:
using Base = VarRef<CVarMap, CVar>;
CVarRef(uint32_t valueOffset, CVarMap& map);
uint32_t GetValueOffset() const;
void AddValuePtr(uint64_t* ptr);
private:
uint32_t valueOffset = 0;
};
class EGameSDK_API CVars : public VarManagerBase<CVarMap, CVar> {
public:
using Base = VarManagerBase<CVarMap, CVar>;
using Base::GetVarRef;
using Base::GetCustomVarRef;
using Base::GetDefaultVarRef;
using Base::GetCustomDefaultVarRef;
static std::optional<CVarRef> GetVarRef(uint32_t valueOffset);
static std::optional<CVarRef> GetCustomVarRef(uint32_t valueOffset);
static std::optional<CVarRef> GetDefaultVarRef(uint32_t valueOffset);
static std::optional<CVarRef> GetCustomDefaultVarRef(uint32_t valueOffset);
private:
static std::optional<CVarRef> _GetVarRef(uint32_t valueOffset, CVarMap& map);
};
}

View File

@ -3,6 +3,7 @@
#include <string>
#include <mutex>
#include <variant>
#include <type_traits>
#include <EGSDK\Exports.h>
#include <EGSDK\Vec3.h>
#include <EGSDK\Vec4.h>
@ -19,11 +20,12 @@ namespace EGSDK::Engine {
};
using VarValueType = std::variant<std::string, float, int, Vec3, Vec4, bool>;
template <typename T>
concept AllowedVarTypes = std::is_same_v<T, std::string> || std::is_same_v<T, float> || std::is_same_v<T, int> || std::is_same_v<T, Vec3> || std::is_same_v<T, Vec4> || std::is_same_v<T, bool>;
class EGameSDK_API VarBase {
public:
VarBase(const std::string& name);
VarBase(const std::string& name, VarType type);
VarBase(const std::string& name, VarType type = VarType::NONE);
~VarBase();
const char* GetName() const;

View File

@ -11,124 +11,27 @@
#include <EGSDK\Vec4.h>
#include <EGSDK\Utils\Values.h>
#include <EGSDK\Engine\VarBase.h>
#include <EGSDK\Engine\VarRef.h>
#include <EGSDK\Engine\VarMapBase.h>
#pragma intrinsic(_ReturnAddress)
namespace EGSDK::Engine {
template <typename T>
concept AllowedVarTypes = std::is_same_v<T, std::string> || std::is_same_v<T, float> || std::is_same_v<T, int> || std::is_same_v<T, Vec3> || std::is_same_v<T, Vec4> || std::is_same_v<T, bool>;
template <typename VarMapT, typename VarT>
class VarManagerBase;
template <typename VarMapT, typename VarT>
class VarRef {
public:
VarRef(VarT* var) : ptr(var) {
name = var->GetName();
}
VarRef(const char* name, VarMapT& map) : name(name), ptr(map.Find(name)) {}
const char* GetName() const {
return name;
}
VarType GetType() const {
return ptr ? ptr->GetType() : VarType::NONE;
}
VarT* GetPtr() const {
return ptr;
}
template <AllowedVarTypes T>
std::optional<T> GetValue() {
if (!ptr)
return std::nullopt;
auto value = ptr->GetValue();
auto variantValue = std::get_if<T>(&value);
return variantValue ? std::optional<T>(*variantValue) : std::nullopt;
}
template <AllowedVarTypes T>
void SetValue(T value) {
if (!ptr)
return;
if constexpr (std::is_same_v<T, std::string>) {
switch (ptr->GetType()) {
case VarType::Float:
SetValue<float>(std::stof(Utils::Values::to_string(value)));
return;
case VarType::Int:
SetValue<int>(std::stof(Utils::Values::to_string(value)));
return;
case VarType::Bool:
SetValue<bool>(std::stof(Utils::Values::to_string(value)));
return;
default:
break;
}
}
ptr->SetValue(value);
}
template <AllowedVarTypes T>
void SetValueFromList(T value) {
VarManagerBase<VarMapT, VarT>::template _SetValueFromList<T>(this, value);
}
bool IsManagedByBool() {
return VarManagerBase<VarMapT, VarT>::_IsManagedByBool(this);
}
bool HasCustomValue() {
return VarManagerBase<VarMapT, VarT>::_HasCustomValue(this);
}
template <AllowedVarTypes T>
void ManageByBool(T valueIfTrue, T valueIfFalse, bool boolVal, bool usePreviousVal = true) {
VarManagerBase<VarMapT, VarT>::template _ManageByBool<T>(this, valueIfTrue, valueIfFalse, boolVal, usePreviousVal);
}
template <AllowedVarTypes T>
void SaveVariableAsDefault() {
VarManagerBase<VarMapT, VarT>::template _SaveVariableAsDefault<T>(this);
}
template <AllowedVarTypes T>
void RestoreVarToDefault(bool restoreToSavedVars = false) {
VarManagerBase<VarMapT, VarT>::template _RestoreVarToDefault<T>(this, restoreToSavedVars);
}
private:
const char* name = nullptr;
VarT* ptr = nullptr;
};
template <typename VarMapT, typename VarT>
class EGameSDK_API VarManagerBase {
template <typename, typename>
friend class VarRef;
public:
static VarMapT vars;
static VarMapT customVars;
static VarMapT defaultVars;
static VarMapT defaultCustomVars;
static std::optional<VarRef<VarMapT, VarT>> GetVarRef(VarT* var) {
return std::optional<VarRef<VarMapT, VarT>>(VarRef<VarMapT, VarT>(var));
}
static std::optional<VarRef<VarMapT, VarT>> GetVarRef(const char* name) {
VarRef<VarMapT, VarT> varRef(name, vars);
return varRef.GetPtr() ? std::optional<VarRef<VarMapT, VarT>>(varRef) : std::nullopt;
}
static std::optional<VarRef<VarMapT, VarT>> GetCustomVarRef(const char* name) {
VarRef<VarMapT, VarT> varRef(name, customVars);
return varRef.GetPtr() ? std::optional<VarRef<VarMapT, VarT>>(varRef) : std::nullopt;
}
static std::optional<VarRef<VarMapT, VarT>> GetDefaultVarRef(const char* name) {
VarRef<VarMapT, VarT> varRef(name, defaultVars);
return varRef.GetPtr() ? std::optional<VarRef<VarMapT, VarT>>(varRef) : std::nullopt;
}
static std::optional<VarRef<VarMapT, VarT>> GetCustomDefaultVarRef(const char* name) {
VarRef<VarMapT, VarT> varRef(name, defaultCustomVars);
return varRef.GetPtr() ? std::optional<VarRef<VarMapT, VarT>>(varRef) : std::nullopt;
}
static std::optional<VarRef<VarMapT, VarT>> GetVarRef(VarT* var);
static std::optional<VarRef<VarMapT, VarT>> GetVarRef(const char* name);
static std::optional<VarRef<VarMapT, VarT>> GetCustomVarRef(const char* name);
static std::optional<VarRef<VarMapT, VarT>> GetDefaultVarRef(const char* name);
static std::optional<VarRef<VarMapT, VarT>> GetCustomDefaultVarRef(const char* name);
static bool AreAnyVarsPresent();
static bool AreAnyCustomVarsPresent();
@ -146,6 +49,8 @@ namespace EGSDK::Engine {
static std::unordered_map<std::string, uint64_t> varOwnerMap;
static std::recursive_mutex mutex;
static std::optional<VarRef<VarMapT, VarT>> _GetVarRef(const char* name, VarMapT& map);
static bool _IsManagedByBool(const char* name);
static bool _IsManagedByBool(VarRef<VarMapT, VarT>* var);
static bool _HasCustomValue(VarRef<VarMapT, VarT>* var);

View File

@ -5,29 +5,30 @@
#include <mutex>
#include <functional>
#include <string>
#include <type_traits>
#include <EGSDK\Exports.h>
#include <EGSDK\Engine\VarBase.h>
namespace EGSDK::Engine {
template <typename VarT>
class EGameSDK_API VarMapBase {
static_assert(std::is_base_of_v<VarBase, VarT>, "VarT must inherit from VarBase");
public:
VarMapBase() = default;
VarMapBase();
VarMapBase(const VarMapBase&) = delete;
VarMapBase& operator=(const VarMapBase&) = delete;
VarMapBase(VarMapBase&&) noexcept = default;
VarMapBase& operator=(VarMapBase&&) noexcept = default;
virtual ~VarMapBase() = default;
virtual std::unique_ptr<VarT>& try_emplace(std::unique_ptr<VarT> var);
VarT* Find(const std::string& name) const;
virtual void Erase(const std::string& name);
bool empty() const;
bool none_of(const std::string& name) const;
void reserve(size_t count);
size_t size();
VarT* Find(const std::string& name) const;
virtual void Erase(const std::string& name);
void reserve(size_t count);
template <typename Callable, typename... Args>
void ForEach(Callable&& func, Args&&... args) {
@ -36,8 +37,8 @@ namespace EGSDK::Engine {
func(vars.at(name), std::forward<Args>(args)...);
}
protected:
std::unordered_map<std::string, std::unique_ptr<VarT>> vars{};
std::vector<std::string> varsOrdered{};
mutable std::recursive_mutex mutex{};
std::unordered_map<std::string, std::unique_ptr<VarT>> vars;
std::vector<std::string> varsOrdered;
mutable std::recursive_mutex mutex;
};
}

View File

@ -0,0 +1,77 @@
#pragma once
#include <optional>
#include <EGSDK\Engine\VarBase.h>
namespace EGSDK::Engine {
template <typename VarMapT, typename VarT>
class EGameSDK_API VarManagerBase;
template <typename VarMapT, typename VarT>
class EGameSDK_API VarRef {
public:
using VarMgrBase = VarManagerBase<VarMapT, VarT>;
VarRef(VarT* var);
VarRef(const char* name, VarMapT& map);
const char* GetName() const;
VarType GetType() const;
VarT* GetPtr() const;
template <AllowedVarTypes T>
std::optional<T> GetValue() const {
if (!ptr)
return std::nullopt;
auto value = ptr->GetValue();
if (auto* typedValue = std::get_if<T>(&value))
return *typedValue;
return std::nullopt;
}
template <AllowedVarTypes T>
void SetValue(T value) {
if (!ptr)
return;
if constexpr (std::is_same_v<T, std::string>) {
switch (ptr->GetType()) {
case VarType::Float:
SetValue<float>(std::stof(Utils::Values::to_string(value)));
return;
case VarType::Int:
SetValue<int>(std::stof(Utils::Values::to_string(value)));
return;
case VarType::Bool:
SetValue<bool>(std::stof(Utils::Values::to_string(value)));
return;
default:
break;
}
}
ptr->SetValue(std::move(value));
}
template <AllowedVarTypes T>
void SetValueFromList(T value) {
VarMgrBase::template _SetValueFromList<T>(this, value);
}
bool IsManagedByBool();
bool HasCustomValue();
template <AllowedVarTypes T>
void ManageByBool(T valueIfTrue, T valueIfFalse, bool boolVal, bool usePreviousVal = true) {
VarMgrBase::template _ManageByBool<T>(this, valueIfTrue, valueIfFalse, boolVal, usePreviousVal);
}
template <AllowedVarTypes T>
void SaveVariableAsDefault() {
VarMgrBase::template _SaveVariableAsDefault<T>(this);
}
template <AllowedVarTypes T>
void RestoreVarToDefault(bool restoreToSavedVars = false) {
VarMgrBase::template _RestoreVarToDefault<T>(this, restoreToSavedVars);
}
protected:
const char* name;
VarT* ptr;
};
}

View File

@ -39,13 +39,20 @@ namespace EGSDK::GamePH {
class EGameSDK_API PlayerVarMap : public Engine::VarMapBase<PlayerVar> {
public:
using Engine::VarMapBase<PlayerVar>::Find;
using Engine::VarMapBase<PlayerVar>::none_of;
using Engine::VarMapBase<PlayerVar>::empty;
using Base = VarMapBase<PlayerVar>;
using Base::Find;
using Base::none_of;
using Base::empty;
};
class EGameSDK_API PlayerVariables : public Engine::VarManagerBase<PlayerVarMap, PlayerVar> {
public:
using Base = VarManagerBase<PlayerVarMap, PlayerVar>;
using Base::GetVarRef;
using Base::GetCustomVarRef;
using Base::GetDefaultVarRef;
using Base::GetCustomDefaultVarRef;
static std::atomic<bool> gotPlayerVars;
#ifdef EGameSDK_EXPORTS

View File

@ -1 +1,168 @@

#include <spdlog\spdlog.h>
#include <EGSDK\Utils\Files.h>
#include <EGSDK\Core\Core.h>
#include <EGSDK\Core\SaveGameManager.h>
#include <EGSDK\Core\SteamAPI.h>
namespace EGSDK::Core {
std::filesystem::path SaveGameManager::saveGamePath{};
std::filesystem::path SaveGameManager::backupRootPath{};
int SaveGameManager::maxBackupSlots = 16;
std::chrono::minutes SaveGameManager::backupInterval{ 20 };
int SaveGameManager::currentBackupSlot = 0;
Utils::Time::Timer SaveGameManager::timeSpentInitializing{ 30000 };
bool SaveGameManager::initialized = false;
bool SaveGameManager::isInitializing = false;
bool SaveGameManager::triedInitializingWithSteam = false;
bool SaveGameManager::loopIsRunning = false;
void SaveGameManager::Init() {
if (initialized || isInitializing)
return;
isInitializing = true;
timeSpentInitializing.Reset();
while (true) {
if (timeSpentInitializing.DidTimePass()) {
if (!triedInitializingWithSteam) {
triedInitializingWithSteam = true;
timeSpentInitializing.Reset();
continue;
}
SPDLOG_ERROR("Failed initializing SaveGameManager after 20 seconds");
MessageBoxA(nullptr, "EGameSDK encountered an issue trying to initialize its Savegame Manager.\nPLEASE MANUALLY MAKE BACKUPS OF YOUR SAVEGAME BEFORE using EGameSDK and any other mods, such as EGameTools!", "Failed initializing SaveGameManager", MB_ICONERROR | MB_OK | MB_SETFOREGROUND);
return;
}
if (backupRootPath.empty()) {
SPDLOG_INFO("Getting SDK storage path");
std::filesystem::path sdkStoragePath = GetSDKStoragePath();
if (!sdkStoragePath.empty())
backupRootPath = sdkStoragePath / "SavegameBackups";
}
if (saveGamePath.empty()) {
SPDLOG_INFO("Detecting savegame path");
saveGamePath = !triedInitializingWithSteam ? DetectSaveGamePathSteam() : DetectSaveGamePathEpic();
}
if (!saveGamePath.empty() && !backupRootPath.empty())
break;
Sleep(2000);
}
SPDLOG_INFO("SaveGameManager initialization successful");
isInitializing = false;
initialized = true;
}
void SaveGameManager::Loop() {
if (!initialized || loopIsRunning)
return;
loopIsRunning = true;
SPDLOG_INFO("Initializing backup slot");
InitializeBackupSlot();
SPDLOG_INFO("Performing first savegame backup...");
PerformBackup();
while (true) {
std::this_thread::sleep_for(backupInterval);
SPDLOG_INFO("Performing periodic savegame backup...");
PerformBackup();
}
}
void SaveGameManager::PerformBackup() {
std::filesystem::path destinationPath = backupRootPath / ("Backup_" + std::to_string(currentBackupSlot));
if (triedInitializingWithSteam)
destinationPath = destinationPath / "out" / "storage";
try {
if (std::filesystem::exists(destinationPath))
std::filesystem::remove_all(destinationPath);
std::filesystem::create_directories(destinationPath);
std::filesystem::copy(saveGamePath, destinationPath, std::filesystem::copy_options::recursive);
SPDLOG_INFO("Backup successfully created in \"{}\"!", destinationPath.string());
// Calculate next backup slot and cleanup
int slotToDelete = (currentBackupSlot + 85) % 100;
std::filesystem::path deletePath = backupRootPath / ("Backup_" + std::to_string(slotToDelete));
if (std::filesystem::exists(deletePath)) {
std::filesystem::remove_all(deletePath);
SPDLOG_INFO("Deleted old backup folder: \"{}\"", deletePath.string());
}
currentBackupSlot = (currentBackupSlot + 1) % 100;
} catch (const std::exception& ex) {
SPDLOG_ERROR("Exception caught while trying to backup savegame: {}", ex.what());
}
}
void SaveGameManager::InitializeBackupSlot() {
int highestSlot = -1;
for (const auto& entry : std::filesystem::directory_iterator(backupRootPath)) {
if (entry.is_directory()) {
std::string folderName = entry.path().filename().string();
if (folderName.rfind("Backup_", 0) == 0) { // Check if it starts with "Backup_"
try {
int slotNumber = std::stoi(folderName.substr(7));
if (slotNumber > highestSlot)
highestSlot = slotNumber;
} catch (const std::exception& ex) {
SPDLOG_ERROR("Failed to parse backup folder name: \"{}\", exception: {}", folderName, ex.what());
}
}
}
}
if (highestSlot != -1) {
currentBackupSlot = (highestSlot + 1) % 100;
SPDLOG_INFO("Initialized current backup slot to: {}", currentBackupSlot);
} else
SPDLOG_INFO("No existing backups found. Starting with slot 0");
}
std::filesystem::path SaveGameManager::DetectSaveGamePathSteam() {
auto steamUser = SteamAPI::GetISteamUser();
if (!steamUser) {
SPDLOG_ERROR("Failed getting Steam user");
return {};
}
char userDataFolder[256];
if (!steamUser->GetUserDataFolder(userDataFolder, sizeof(userDataFolder))) {
SPDLOG_ERROR("Failed getting Steam user data path");
return {};
}
std::filesystem::path gameUserDataPath = userDataFolder;
if (gameUserDataPath.filename() == "local")
gameUserDataPath = gameUserDataPath.parent_path() / "remote";
if (!std::filesystem::exists(gameUserDataPath)) {
SPDLOG_ERROR("Savegame path does not exist: {}", gameUserDataPath.string());
return {};
}
return gameUserDataPath;
}
std::filesystem::path SaveGameManager::DetectSaveGamePathEpic() {
std::filesystem::path documentsPath = Utils::Files::GetDocumentsDir();
if (documentsPath.empty()) {
SPDLOG_ERROR("Failed getting user Documents path");
return {};
}
std::filesystem::path gameStoragePath = documentsPath / "dying light 2" / "out" / "storage";
if (!std::filesystem::exists(gameStoragePath)) {
SPDLOG_ERROR("Savegame path does not exist: {}", gameStoragePath.string());
return {};
}
return gameStoragePath;
}
}

View File

@ -1 +1,39 @@

#include <EGSDK\Core\SteamAPI.h>
#include <EGSDK\Utils\Memory.h>
#include <EGSDK\Utils\WinMemory.h>
namespace EGSDK::Core {
ISteamClient* SteamAPI::SteamClient() {
return Utils::Memory::SafeCallFunction("steam_api64.dll", "SteamClient", nullptr);
}
HSteamUser SteamAPI::GetHSteamUser() {
return Utils::Memory::SafeCallFunction("steam_api64.dll", "SteamAPI_GetHSteamUser", -1);
}
HSteamPipe SteamAPI::GetHSteamPipe() {
return Utils::Memory::SafeCallFunction("steam_api64.dll", "SteamAPI_GetHSteamPipe", -1);
}
ISteamUser* SteamAPI::GetISteamUser() {
auto steamClient = SteamClient();
if (!steamClient)
return nullptr;
auto hSteamUser = SteamAPI::GetHSteamUser();
auto hSteamPipe = SteamAPI::GetHSteamPipe();
if (!hSteamUser || !hSteamPipe)
return {};
return steamClient->GetISteamUser(hSteamUser, hSteamPipe, STEAMUSER_INTERFACE_VERSION);
}
ISteamUtils* SteamAPI::GetISteamUtils() {
auto steamClient = SteamClient();
if (!steamClient)
return nullptr;
auto hSteamPipe = SteamAPI::GetHSteamPipe();
if (!hSteamPipe)
return {};
return steamClient->GetISteamUtils(hSteamPipe, STEAMUTILS_INTERFACE_VERSION);
}
}

View File

@ -98,11 +98,6 @@ namespace EGSDK::Engine {
}
return it->second;
}
bool CVarMap::none_of(uint32_t valueOffset) {
std::lock_guard lock(mutex);
return varsByValueOffset.find(valueOffset) == varsByValueOffset.end();
}
CVar* CVarMap::Find(uint32_t valueOffset) const {
std::lock_guard lock(mutex);
auto it = varsByValueOffset.find(valueOffset);
@ -121,4 +116,36 @@ namespace EGSDK::Engine {
varsByValueOffset.erase(it->second->valueOffset.data);
vars.erase(it);
}
bool CVarMap::none_of(uint32_t valueOffset) {
std::lock_guard lock(mutex);
return varsByValueOffset.find(valueOffset) == varsByValueOffset.end();
}
CVarRef::CVarRef(uint32_t valueOffset, CVarMap& map) : valueOffset(valueOffset), Base(map.Find(valueOffset)) {}
uint32_t CVarRef::GetValueOffset() const {
return valueOffset;
}
void CVarRef::AddValuePtr(uint64_t* ptr) {
if (!ptr)
return;
Base::ptr->AddValuePtr(ptr);
}
std::optional<CVarRef> CVars::GetVarRef(uint32_t valueOffset) {
return _GetVarRef(valueOffset, Base::vars);
}
std::optional<CVarRef> CVars::GetCustomVarRef(uint32_t valueOffset) {
return _GetVarRef(valueOffset, Base::customVars);
}
std::optional<CVarRef> CVars::GetDefaultVarRef(uint32_t valueOffset) {
return _GetVarRef(valueOffset, Base::defaultVars);
}
std::optional<CVarRef> CVars::GetCustomDefaultVarRef(uint32_t valueOffset) {
return _GetVarRef(valueOffset, Base::defaultCustomVars);
}
std::optional<CVarRef> CVars::_GetVarRef(uint32_t valueOffset, CVarMap& map) {
CVarRef varRef(valueOffset, map);
return varRef.GetPtr() ? std::optional<CVarRef>(varRef) : std::nullopt;
}
}

View File

@ -5,15 +5,10 @@ namespace EGSDK::Engine {
std::unordered_map<const VarBase*, VarType> VarBase::varTypes{};
std::recursive_mutex VarBase::mutex{};
VarBase::VarBase(const std::string& name) {
std::lock_guard lock(mutex);
varNames[this] = name;
varTypes[this] = VarType::NONE;
}
VarBase::VarBase(const std::string& name, VarType type) {
std::lock_guard lock(mutex);
varNames[this] = name;
varTypes[this] = type;
SetName(name);
SetType(type);
}
VarBase::~VarBase() {
std::lock_guard lock(mutex);
@ -24,9 +19,7 @@ namespace EGSDK::Engine {
const char* VarBase::GetName() const {
std::lock_guard lock(mutex);
auto it = varNames.find(this);
if (it != varNames.end())
return it->second.c_str();
return nullptr;
return it != varNames.end() ? it->second.c_str() : nullptr;
}
void VarBase::SetName(const std::string& newName) {
std::lock_guard lock(mutex);
@ -36,9 +29,7 @@ namespace EGSDK::Engine {
VarType VarBase::GetType() const {
std::lock_guard lock(mutex);
auto it = varTypes.find(this);
if (it != varTypes.end())
return it->second;
return VarType::NONE;
return it != varTypes.end() ? it->second : VarType::NONE;
}
void VarBase::SetType(VarType newType) {
std::lock_guard lock(mutex);

View File

@ -1 +1,89 @@

#include <algorithm>
#include <EGSDK\Engine\VarManagerBase.h>
#include <EGSDK\Engine\CVars.h>
#include <EGSDK\GamePH\PlayerVariables.h>
namespace EGSDK::Engine {
template <typename VarMapT, typename VarT>
VarMapT VarManagerBase<VarMapT, VarT>::vars{};
template <typename VarMapT, typename VarT>
VarMapT VarManagerBase<VarMapT, VarT>::customVars{};
template <typename VarMapT, typename VarT>
VarMapT VarManagerBase<VarMapT, VarT>::defaultVars{};
template <typename VarMapT, typename VarT>
VarMapT VarManagerBase<VarMapT, VarT>::defaultCustomVars{};
template <typename VarMapT, typename VarT>
std::unordered_map<std::string, std::any> VarManagerBase<VarMapT, VarT>::prevVarValueMap{};
template <typename VarMapT, typename VarT>
std::unordered_map<std::string, bool> VarManagerBase<VarMapT, VarT>::prevBoolValueMap{};
template <typename VarMapT, typename VarT>
std::unordered_map<std::string, uint64_t> VarManagerBase<VarMapT, VarT>::varOwnerMap{};
template <typename VarMapT, typename VarT>
std::recursive_mutex VarManagerBase<VarMapT, VarT>::mutex{};
template <typename VarMapT, typename VarT>
std::optional<VarRef<VarMapT, VarT>> VarManagerBase<VarMapT, VarT>::GetVarRef(VarT* var) {
return var ? std::optional<VarRef<VarMapT, VarT>>(VarRef<VarMapT, VarT>(var)) : std::nullopt;
}
template <typename VarMapT, typename VarT>
std::optional<VarRef<VarMapT, VarT>> VarManagerBase<VarMapT, VarT>::GetVarRef(const char* name) {
return _GetVarRef(name, vars);
}
template <typename VarMapT, typename VarT>
std::optional<VarRef<VarMapT, VarT>> VarManagerBase<VarMapT, VarT>::GetCustomVarRef(const char* name) {
return _GetVarRef(name, customVars);
}
template <typename VarMapT, typename VarT>
std::optional<VarRef<VarMapT, VarT>> VarManagerBase<VarMapT, VarT>::GetDefaultVarRef(const char* name) {
return _GetVarRef(name, defaultVars);
}
template <typename VarMapT, typename VarT>
std::optional<VarRef<VarMapT, VarT>> VarManagerBase<VarMapT, VarT>::GetCustomDefaultVarRef(const char* name) {
return _GetVarRef(name, defaultCustomVars);
}
template <typename VarMapT, typename VarT>
std::optional<VarRef<VarMapT, VarT>> VarManagerBase<VarMapT, VarT>::_GetVarRef(const char* name, VarMapT& map) {
VarRef<VarMapT, VarT> varRef(name, map);
return varRef.GetPtr() ? std::optional<VarRef<VarMapT, VarT>>(varRef) : std::nullopt;
}
template <typename VarMapT, typename VarT>
bool VarManagerBase<VarMapT, VarT>::AreAnyVarsPresent() {
return !vars.empty();
}
template <typename VarMapT, typename VarT>
bool VarManagerBase<VarMapT, VarT>::AreAnyCustomVarsPresent() {
return !customVars.empty();
}
template <typename VarMapT, typename VarT>
bool VarManagerBase<VarMapT, VarT>::AreAllCustomVarsManagedByBool() {
bool allManagedByBool = true;
vars.ForEach([&allManagedByBool](const std::unique_ptr<VarT>& varPtr) {
if (!_IsManagedByBool(varPtr->GetName())) {
allManagedByBool = false;
return;
}
});
return allManagedByBool;
}
template <typename VarMapT, typename VarT>
bool VarManagerBase<VarMapT, VarT>::_IsManagedByBool(const char* name) {
std::lock_guard<std::recursive_mutex> lock(mutex);
return (prevBoolValueMap.find(name) != prevBoolValueMap.end()) && prevBoolValueMap[name];
}
template <typename VarMapT, typename VarT>
bool VarManagerBase<VarMapT, VarT>::_IsManagedByBool(VarRef<VarMapT, VarT>* var) {
return _IsManagedByBool(var->GetName());
}
template <typename VarMapT, typename VarT>
bool VarManagerBase<VarMapT, VarT>::_HasCustomValue(VarRef<VarMapT, VarT>* var) {
return !customVars.none_of(var->GetName());
}
template class VarManagerBase<CVarMap, CVar>;
template class VarManagerBase<GamePH::PlayerVarMap, GamePH::PlayerVar>;
}

View File

@ -1 +1,66 @@

#include <algorithm>
#include <EGSDK\Engine\VarMapBase.h>
#include <EGSDK\Engine\CVars.h>
#include <EGSDK\GamePH\PlayerVariables.h>
namespace EGSDK::Engine {
template <typename VarT>
VarMapBase<VarT>::VarMapBase() : vars(), varsOrdered(), mutex() {}
template <typename VarT>
std::unique_ptr<VarT>& VarMapBase<VarT>::try_emplace(std::unique_ptr<VarT> var) {
std::lock_guard lock(mutex);
const std::string& name = var->GetName();
auto [it, inserted] = vars.try_emplace(name, std::move(var));
if (inserted)
varsOrdered.push_back(name);
return it->second;
}
template <typename VarT>
VarT* VarMapBase<VarT>::Find(const std::string& name) const {
std::lock_guard lock(mutex);
auto it = vars.find(name);
return (it != vars.end()) ? it->second.get() : nullptr;
}
template <typename VarT>
void VarMapBase<VarT>::Erase(const std::string& name) {
std::lock_guard lock(mutex);
auto it = vars.find(name);
if (it == vars.end())
return;
auto orderIt = std::find(varsOrdered.begin(), varsOrdered.end(), name);
if (orderIt != varsOrdered.end())
varsOrdered.erase(orderIt);
vars.erase(it);
}
template <typename VarT>
bool VarMapBase<VarT>::empty() const {
std::lock_guard lock(mutex);
return vars.empty();
}
template <typename VarT>
bool VarMapBase<VarT>::none_of(const std::string& name) const {
std::lock_guard lock(mutex);
return vars.find(name) == vars.end();
}
template <typename VarT>
size_t VarMapBase<VarT>::size() {
std::lock_guard lock(mutex);
return vars.size();
}
template <typename VarT>
void VarMapBase<VarT>::reserve(size_t count) {
std::lock_guard lock(mutex);
vars.reserve(count);
varsOrdered.reserve(count);
}
template class VarMapBase<CVar>;
template class VarMapBase<GamePH::PlayerVar>;
}

View File

@ -0,0 +1,37 @@
#include <EGSDK\Utils\Values.h>
#include <EGSDK\Engine\VarRef.h>
#include <EGSDK\Engine\VarBase.h>
#include <EGSDK\Engine\CVars.h>
#include <EGSDK\GamePH\PlayerVariables.h>
namespace EGSDK::Engine {
template <typename VarMapT, typename VarT>
VarRef<VarMapT, VarT>::VarRef(VarT* var) : name(var ? var->GetName() : nullptr), ptr(var) {}
template <typename VarMapT, typename VarT>
VarRef<VarMapT, VarT>::VarRef(const char* name, VarMapT& map) : name(name), ptr(map.Find(name)) {}
template <typename VarMapT, typename VarT>
const char* VarRef<VarMapT, VarT>::GetName() const {
return name;
}
template <typename VarMapT, typename VarT>
VarType VarRef<VarMapT, VarT>::GetType() const {
return ptr ? ptr->GetType() : VarType::NONE;
}
template <typename VarMapT, typename VarT>
VarT* VarRef<VarMapT, VarT>::GetPtr() const {
return ptr;
}
template <typename VarMapT, typename VarT>
bool VarRef<VarMapT, VarT>::IsManagedByBool() {
return VarMgrBase::_IsManagedByBool(this);
}
template <typename VarMapT, typename VarT>
bool VarRef<VarMapT, VarT>::HasCustomValue() {
return VarMgrBase::_HasCustomValue(this);
}
template class VarRef<CVarMap, CVar>;
template class VarRef<GamePH::PlayerVarMap, GamePH::PlayerVar>;
}

View File

@ -62,6 +62,7 @@ namespace EGSDK::GamePH {
}, value);
}
StringPlayerVariable::StringPlayerVariable(const std::string& name) : PlayerVar(name) {
SetType(Engine::VarType::String);
}

View File

@ -1 +1,137 @@

#include <EGSDK\Offsets.h>
#include <EGSDK\Engine\CBulletPhysicsCharacter.h>
#include <EGSDK\Engine\CGame.h>
#include <EGSDK\Engine\CVideoSettings.h>
#include <EGSDK\GamePH\CoPlayerRestrictions.h>
#include <EGSDK\GamePH\FreeCamera.h>
#include <EGSDK\GamePH\GameDI_PH.h>
#include <EGSDK\GamePH\LocalClientDI.h>
#include <EGSDK\GamePH\PlayerDI_PH.h>
#include <EGSDK\GamePH\PlayerState.h>
#include <EGSDK\GamePH\SessionCooperativeDI.h>
#include <EGSDK\ClassHelpers.h>
namespace EGSDK {
bool OffsetManager::initialized = false;
void OffsetManager::InitializeOffsetsAndPatterns() {
if (initialized)
return;
AddOffsets(11200, {
{ "OnPostUpdate", 0x378 },
{ GetOffsetNameFromClassMember(&Engine::CBulletPhysicsCharacter::playerPos2), 0x880 },
{ GetOffsetNameFromClassMember(&Engine::CBulletPhysicsCharacter::playerPos), 0x898 },
{ GetOffsetNameFromClassMember(&Engine::CBulletPhysicsCharacter::playerDownwardVelocity), 0xC18 },
{ GetOffsetNameFromClassMember(&Engine::CGame::pCLevel), 0x380 },
{ GetOffsetNameFromClassMember(&Engine::CVideoSettings::extraFOV), 0x78 },
{ GetOffsetNameFromClassMember(&GamePH::CoPlayerRestrictions::flags), 0x1C0 },
{ GetOffsetNameFromClassMember(&GamePH::FreeCamera::enableSpeedMultiplier1), 0x4C },
{ GetOffsetNameFromClassMember(&GamePH::FreeCamera::enableSpeedMultiplier2), 0x4D },
{ GetOffsetNameFromClassMember(&GamePH::FreeCamera::speedMultiplier), 0x150 },
//{ GetOffsetNameFromClassMember(&GamePH::FreeCamera::mouseSensitivityMultiplier), 0x1A0 },
{ GetOffsetNameFromClassMember(&GamePH::GameDI_PH::blockPauseGameOnPlayerAfk), 0x830 },
{ GetOffsetNameFromClassMember(&GamePH::GameDI_PH::pSessionCooperativeDI), 0xE8 },
{ GetOffsetNameFromClassMember(&GamePH::LocalClientDI::pPlayerDI_PH), 0x88 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::pCoPhysicsProperty), 0xE8 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::pInventoryContainerDI), 0x550 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::nextPlayerOrientation), 0xC68 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::restrictionsEnabled), 0x2CF0 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::enableTPPModel1), 0x2DC1 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::enableTPPModel2), 0x2DC2 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerState::playerVariables), 0x280 },
{ GetOffsetNameFromClassMember(&GamePH::SessionCooperativeDI::pLocalClientDI), 0xD10 },
});
AddOffsets(12001, {
{ "OnPostUpdate", 0x3A8 },
{ GetOffsetNameFromClassMember(&Engine::CBulletPhysicsCharacter::playerPos2), 0xCB8 },
{ GetOffsetNameFromClassMember(&Engine::CBulletPhysicsCharacter::playerPos), 0xCD0 },
{ GetOffsetNameFromClassMember(&Engine::CBulletPhysicsCharacter::playerDownwardVelocity), 0x1050 },
{ GetOffsetNameFromClassMember(&Engine::CGame::pCLevel), 0x390 },
{ GetOffsetNameFromClassMember(&Engine::CVideoSettings::extraFOV), 0x7C },
{ GetOffsetNameFromClassMember(&GamePH::CoPlayerRestrictions::flags), 0x1F0 },
{ GetOffsetNameFromClassMember(&GamePH::FreeCamera::enableSpeedMultiplier1), 0x42 },
{ GetOffsetNameFromClassMember(&GamePH::FreeCamera::enableSpeedMultiplier2), 0x43 },
{ GetOffsetNameFromClassMember(&GamePH::FreeCamera::speedMultiplier), 0x1CC },
{ GetOffsetNameFromClassMember(&GamePH::GameDI_PH::blockPauseGameOnPlayerAfk), 0x910 },
{ GetOffsetNameFromClassMember(&GamePH::GameDI_PH::pSessionCooperativeDI), 0x130 },
{ GetOffsetNameFromClassMember(&GamePH::LocalClientDI::pPlayerDI_PH), 0x90 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::pCoPhysicsProperty), 0xF0 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::pInventoryContainerDI), 0x470 },
//{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::pPlayerFppVis_PH), 0x420 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::nextPlayerOrientation), 0xB88 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::restrictionsEnabled), 0x3520 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::enableTPPModel1), 0x35E9 },
{ GetOffsetNameFromClassMember(&GamePH::PlayerDI_PH::enableTPPModel2), 0x35EA },
{ GetOffsetNameFromClassMember(&GamePH::PlayerState::playerVariables), 0x300 },
{ GetOffsetNameFromClassMember(&GamePH::SessionCooperativeDI::pLocalClientDI), 0xE08 },
});
AddPatterns(11200, {
{ "LoadPlayerVars", { "40 55 53 57 48 8D AC 24 ?? ?? ?? ?? B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 2B E0 33 FF", Utils::SigScan::PatternType::Address } },
{ "PlayerState", { "48 8B 3D [?? ?? ?? ?? 4C 8B EA", Utils::SigScan::PatternType::RelativePointer } },
{ "SaveGameCRCBoolCheck", { "FF 50 ?? [40 22 FB 0F 85 ?? ?? ?? ?? 0F B6 05 ?? ?? ?? ?? 48 8D 1D", Utils::SigScan::PatternType::Address } },
{ "IsNotOutOfMapBounds", { "48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 41 56 41 57 48 83 EC ?? 4C 8B C2", Utils::SigScan::PatternType::Address } },
{ "IsNotOutOfMissionBounds", { "48 89 5C 24 ?? 57 48 83 EC ?? 4C 8B C2 48 8B F9", Utils::SigScan::PatternType::Address } },
{ "PlaySoundEvent", { "4C 8B DC 49 89 5B ?? 49 89 73 ?? 57 48 81 EC ?? ?? ?? ?? 4C 8B 4C 24 ?? 48 8B F9 4D 8B D0 66 C7 84 24 ?? ?? ?? ?? ?? ?? 49 8B C1 66 C7 84 24", Utils::SigScan::PatternType::Address } },
{ "GetPlayerRestrictionsFlags", { "48 89 5C 24 ?? 57 48 83 EC ?? 48 8B F9 48 8B DA 48 8B CA E8 ?? ?? ?? ?? 48 8B 4F", Utils::SigScan::PatternType::Address } },
{ "EnablePlayerRestrictionsSubFunc", { "40 53 48 83 EC ?? 48 8B D9 48 81 C1 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B CB 48 83 C4 ?? 5B E9 ?? ?? ?? ?? CC CC CC CC CC CC CC CC CC CC CC CC CC CC 48 89 4C 24", Utils::SigScan::PatternType::Address } },
{ "DisablePlayerRestrictionsSubFunc", { "48 89 5C 24 ?? 48 89 6C 24 ?? 56 57 41 54 41 56 41 57 48 83 EC ?? 0F B7 81", Utils::SigScan::PatternType::Address } },
{ "HandlePlayerRestrictions", { "40 57 48 83 EC ?? 48 89 5C 24 ?? 48 8B F9 48 89 6C 24 ?? 0F B6 A9", Utils::SigScan::PatternType::Address } }
});
AddPatterns(12001, {
{ "LoadPlayerVars", { "48 89 4C 24 ?? B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 2B E0 48 8B 8C 24", Utils::SigScan::PatternType::Address } },
{ "PlayerState", { "48 8B 35 [?? ?? ?? ?? 4C 8B F2 48 8B F9", Utils::SigScan::PatternType::RelativePointer } },
{ "SaveGameCRCBoolCheck", { "FF 50 ?? [40 22 DF 0F 85 ?? ?? ?? ?? 0F B6 05 ?? ?? ?? ?? 48 8D 3D", Utils::SigScan::PatternType::Address } },
{ "IsNotOutOfMapBounds", { "48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 41 56 41 57 48 83 EC ?? 4C 8B F9 48 85 D2", Utils::SigScan::PatternType::Address } },
{ "IsNotOutOfMissionBounds", { "48 89 5C 24 ?? 57 48 83 EC ?? 48 8B F9 48 85 D2 74 ?? 48 8D 8A", Utils::SigScan::PatternType::Address } },
{ "PlaySoundEvent", { "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 } },
{ "GetPlayerRestrictionsFlags", { "48 89 5C 24 ?? 57 48 83 EC ?? 48 8B D9 48 8B FA 48 8B CA E8 ?? ?? ?? ?? 48 8B 4B", Utils::SigScan::PatternType::Address } },
{ "EnablePlayerRestrictionsSubFunc", { "40 53 48 83 EC ?? 48 8B D9 48 81 C1 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 8B CB 48 83 C4 ?? 5B E9 ?? ?? ?? ?? CC CC CC CC CC CC CC CC CC CC CC CC CC CC 40 57", Utils::SigScan::PatternType::Address } },
{ "DisablePlayerRestrictionsSubFunc", { "48 89 5C 24 ?? 48 89 6C 24 ?? 56 57 41 54 41 56 41 57 48 83 EC ?? 0F B6 81", Utils::SigScan::PatternType::Address } },
{ "HandlePlayerRestrictions", { "40 57 48 83 EC ?? 48 89 5C 24 ?? 48 8B F9 48 89 74 24 ?? 0F B6 B1", Utils::SigScan::PatternType::Address } }
});
initialized = true;
}
DWORD OffsetManager::GetOffset(const std::string& offsetName) {
if (!initialized)
return 0;
auto& offsets = GetOffsetsMap();
if (offsets.find(Core::gameVer) != offsets.end() && offsets[Core::gameVer].find(offsetName) != offsets[Core::gameVer].end())
return offsets[Core::gameVer][offsetName];
SPDLOG_ERROR("Offset not found for key: \"{}\" in version: {}", offsetName, Core::gameVer);
return 0;
}
Utils::SigScan::Pattern OffsetManager::GetPattern(const std::string& patternName) {
if (!initialized)
return {};
auto& patterns = GetPatternsMap();
if (patterns.find(Core::gameVer) != patterns.end() && patterns[Core::gameVer].find(patternName) != patterns[Core::gameVer].end())
return patterns[Core::gameVer][patternName];
SPDLOG_ERROR("Pattern not found for key: \"{}\" in version: {}", patternName, Core::gameVer);
return {};
}
void OffsetManager::AddOffsets(DWORD gameVer, const std::unordered_map<std::string, DWORD>& offsets) {
GetOffsetsMap()[gameVer] = offsets;
}
void OffsetManager::AddPatterns(DWORD gameVer, const std::unordered_map<std::string, Utils::SigScan::Pattern>& patterns) {
GetPatternsMap()[gameVer] = patterns;
}
std::unordered_map<DWORD, std::unordered_map<std::string, DWORD>>& OffsetManager::GetOffsetsMap() {
static std::unordered_map<DWORD, std::unordered_map<std::string, DWORD>> offsetsMap;
return offsetsMap;
}
std::unordered_map<DWORD, std::unordered_map<std::string, Utils::SigScan::Pattern>>& OffsetManager::GetPatternsMap() {
static std::unordered_map<DWORD, std::unordered_map<std::string, Utils::SigScan::Pattern>> patternsMap;
return patternsMap;
}
}

View File

@ -1 +1,39 @@

#include <unordered_map>
#include <EGSDK\Utils\WinMemory.h>
namespace EGSDK::Utils {
namespace Memory {
HMODULE GetCallingDLLModule(void* callerAddress) {
HMODULE callerModule{};
if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR)callerAddress, &callerModule))
return callerModule;
return nullptr;
}
MODULEINFO GetModuleInfo(const char* szModule) {
if (!szModule)
return MODULEINFO();
static std::unordered_map<std::string_view, MODULEINFO> moduleInfoCache;
auto it = moduleInfoCache.find(szModule);
if (it != moduleInfoCache.end())
return it->second;
HMODULE hModule = GetModuleHandle(szModule);
if (hModule == 0)
return MODULEINFO();
MODULEINFO moduleInfo{};
GetModuleInformation(GetCurrentProcess(), hModule, &moduleInfo, sizeof(MODULEINFO));
moduleInfoCache[szModule] = moduleInfo;
return moduleInfoCache[szModule];
}
FARPROC GetProcAddr(const std::string_view& module, const std::string_view& funcName) {
HMODULE moduleHandle = GetModuleHandle(module.data());
if (!moduleHandle)
return nullptr;
return GetProcAddress(moduleHandle, funcName.data());
}
}
}

View File

@ -1 +0,0 @@


View File

@ -159,10 +159,10 @@
<ClCompile Include="deps\ImGui\imguiex_animation.cpp">
<Filter>deps\ImGui</Filter>
</ClCompile>
<ClCompile Include="src\ImGui_impl\DeferredActions.cpp">
<ClCompile Include="src\ImGui_impl\NextFrameTask.cpp">
<Filter>src\ImGui_impl</Filter>
</ClCompile>
<ClCompile Include="src\ImGui_impl\NextFrameTask.cpp">
<ClCompile Include="src\ImGui_impl\DeferredActions.cpp">
<Filter>src\ImGui_impl</Filter>
</ClCompile>
</ItemGroup>

View File

@ -7,7 +7,7 @@ namespace EGT::Menu {
namespace Camera {
extern EGSDK::Vec3 cameraOffset;
extern float firstPersonFOV;
extern float originalFirstPersonFOVAfterZoomIn;
extern float originalFirstPersonFOVBeforeZoomIn;
extern ImGui::KeyBindOption firstPersonZoomIn;
extern ImGui::Option photoMode;

View File

@ -90,7 +90,7 @@ namespace EGT::Engine {
if (Menu::Camera::thirdPersonCamera.GetValue())
fov = static_cast<float>(Menu::Camera::thirdPersonFOV);
else if (!Menu::Camera::firstPersonZoomIn.IsKeyDown())
Menu::Camera::originalFirstPersonFOVAfterZoomIn = fov;
Menu::Camera::originalFirstPersonFOVBeforeZoomIn = fov;
return SetFOVHook.ExecuteCallbacksWithOriginal(pCBaseCamera, fov);
} };
@ -321,40 +321,41 @@ namespace EGT::Engine {
if (!varValuePtr)
return varValuePtr;
EGSDK::Engine::CVar* cVar = EGSDK::Engine::CVars::vars.Find(valueOffset);
auto cVar = EGSDK::Engine::CVars::GetVarRef(valueOffset);
if (!cVar)
return varValuePtr;
cVar->AddValuePtr(varValuePtr);
EGSDK::Engine::CVar* customCVar = EGSDK::Engine::CVars::customVars.Find(cVar->GetName());
//EGSDK::Engine::CVar* customCVar = EGSDK::Engine::CVars::customVars.Find(cVar->GetName());
auto customCVar = EGSDK::Engine::CVars::GetCustomVarRef(cVar->GetName());
if (!customCVar)
return varValuePtr;
switch (cVar->GetType()) {
case EGSDK::Engine::VarType::Float:
{
auto value = EGSDK::Engine::CVars::GetVarValue<float>(customCVar);
auto value = customCVar->GetValue<float>();
if (value)
cVar->SetValue(*value);
break;
}
case EGSDK::Engine::VarType::Int:
{
auto value = EGSDK::Engine::CVars::GetVarValue<int>(customCVar);
auto value = customCVar->GetValue<int>();
if (value)
cVar->SetValue(*value);
break;
}
case EGSDK::Engine::VarType::Vec3:
{
auto value = EGSDK::Engine::CVars::GetVarValue<EGSDK::Vec3>(customCVar);
auto value = customCVar->GetValue<EGSDK::Vec3>();
if (value)
cVar->SetValue(*value);
break;
}
case EGSDK::Engine::VarType::Vec4:
{
auto value = EGSDK::Engine::CVars::GetVarValue<EGSDK::Vec4>(customCVar);
auto value = customCVar->GetValue<EGSDK::Vec4>();
if (value)
cVar->SetValue(*value);
break;

View File

@ -20,7 +20,7 @@ namespace EGT::Menu {
EGSDK::Vec3 cameraOffset{};
float firstPersonFOV = baseFOV;
float originalFirstPersonFOVAfterZoomIn = firstPersonFOV;
float originalFirstPersonFOVBeforeZoomIn = firstPersonFOV;
ImGui::KeyBindOption firstPersonZoomIn{ false, 'Q', false };
static bool isZoomingIn = false;
@ -90,25 +90,39 @@ namespace EGT::Menu {
}
if (iLevel && iLevel->IsLoaded() && viewCam && !thirdPersonCamera.GetValue() && !freeCam.GetValue()) {
constexpr float level1Min = 42.0f;
constexpr float level2Min = 25.0f;
constexpr float level3Min = 15.0f;
if (firstPersonZoomIn.IsKeyDown()) {
if (firstPersonZoomIn.IsKeyPressed()) {
hasChangedZoomLevel = true;
if (!isZoomingIn) {
originalFirstPersonFOVAfterZoomIn = viewCam->GetFOV();
previousFirstPersonFOV = originalFirstPersonFOVAfterZoomIn;
originalFirstPersonFOVBeforeZoomIn = viewCam->GetFOV();
previousFirstPersonFOV = originalFirstPersonFOVBeforeZoomIn;
} else
previousFirstPersonFOV = firstPersonFOV;
float rawFOVLevel1 = originalFirstPersonFOVBeforeZoomIn - 25.0f;
float rawFOVLevel2 = originalFirstPersonFOVBeforeZoomIn - 45.0f;
if (std::abs(rawFOVLevel1 - level1Min) > 5.0f)
zoomLevel = 2;
else if (std::abs(rawFOVLevel2 - level2Min) > 5.0f)
zoomLevel = 3;
else
zoomLevel = 1;
}
isZoomingIn = true;
float targetFOV = previousFirstPersonFOV;
if (zoomLevel == 0)
targetFOV = std::max(originalFirstPersonFOVAfterZoomIn - 25.0f, 42.0f);
else if (zoomLevel == 1)
targetFOV = std::max(originalFirstPersonFOVAfterZoomIn - 45.0f, 25.0f);
if (zoomLevel == 1)
targetFOV = std::max(originalFirstPersonFOVBeforeZoomIn - 25.0f, level1Min);
else if (zoomLevel == 2)
targetFOV = std::max(originalFirstPersonFOVAfterZoomIn - 65.0f, 15.0f);
targetFOV = std::max(originalFirstPersonFOVBeforeZoomIn - 45.0f, level2Min);
else if (zoomLevel == 3)
targetFOV = std::max(originalFirstPersonFOVBeforeZoomIn - 65.0f, level3Min);
firstPersonFOV = ImGui::AnimateLerp("zoomInFOVLerp", previousFirstPersonFOV, targetFOV, 0.3f, hasChangedZoomLevel, &ImGui::AnimEaseOutSine);
viewCam->SetFOV(firstPersonFOV);
@ -116,28 +130,28 @@ namespace EGT::Menu {
if (ImGui::KeyBindOption::scrolledMouseWheelUp) {
ImGui::KeyBindOption::scrolledMouseWheelUp = false;
if (zoomLevel < 2) {
if (zoomLevel < 3) {
zoomLevel++;
previousFirstPersonFOV = firstPersonFOV;
hasChangedZoomLevel = true;
}
} else if (ImGui::KeyBindOption::scrolledMouseWheelDown) {
ImGui::KeyBindOption::scrolledMouseWheelDown = false;
if (zoomLevel > 0) {
if (zoomLevel > 1) {
zoomLevel--;
previousFirstPersonFOV = firstPersonFOV;
hasChangedZoomLevel = true;
}
}
} else {
zoomLevel = 0;
zoomLevel = 1;
if (firstPersonZoomIn.IsKeyReleased()) {
hasChangedZoomLevel = true;
previousFirstPersonFOV = firstPersonFOV;
}
if (!EGSDK::Utils::Values::are_samef(firstPersonFOV, originalFirstPersonFOVAfterZoomIn) && isZoomingIn) {
firstPersonFOV = ImGui::AnimateLerp("zoomInFOVLerp", previousFirstPersonFOV, originalFirstPersonFOVAfterZoomIn, 0.25f, hasChangedZoomLevel, &ImGui::AnimEaseOutSine);
if (!EGSDK::Utils::Values::are_samef(firstPersonFOV, originalFirstPersonFOVBeforeZoomIn) && isZoomingIn) {
firstPersonFOV = ImGui::AnimateLerp("zoomInFOVLerp", previousFirstPersonFOV, originalFirstPersonFOVBeforeZoomIn, 0.25f, hasChangedZoomLevel, &ImGui::AnimEaseOutSine);
viewCam->SetFOV(firstPersonFOV);
hasChangedZoomLevel = false;
} else
@ -251,7 +265,7 @@ namespace EGT::Menu {
lensDistortionJustEnabled = false;
}
EGSDK::GamePH::PlayerVariables::ChangeVar("FOVCorrection", goProMode.GetValue() ? (altLensDistortion / 100.0f) : (lensDistortion / 100.0f));
EGSDK::GamePH::PlayerVariables::GetVarRef("FOVCorrection")->SetValue(goProMode.GetValue() ? (altLensDistortion / 100.0f) : (lensDistortion / 100.0f));
EGSDK::GamePH::PlayerVariables::ManageVarByBool("SprintHeadCorrectionFactor", 0.0f, baseSprintHeadCorrectionFactor, goProMode.GetValue() ? goProMode.GetValue() : disableHeadCorrection.GetValue(), true);
}
static void UpdateDisabledOptions() {