mirror of
https://github.com/EricPlayZ/EGameTools.git
synced 2025-07-18 17:37:53 +08:00
lots of CPU performance optimization
This commit is contained in:
@ -9,65 +9,63 @@
|
||||
#include <EGSDK\Exports.h>
|
||||
|
||||
namespace EGSDK {
|
||||
namespace ClassHelpers {
|
||||
namespace ClassHelpers {
|
||||
#pragma pack(1)
|
||||
template<size_t size, typename T>
|
||||
class buffer {
|
||||
char buffer[size];
|
||||
public:
|
||||
T data;
|
||||
template<size_t size, typename T>
|
||||
class buffer {
|
||||
char buffer[size];
|
||||
public:
|
||||
T data;
|
||||
|
||||
operator T() { return data; }
|
||||
T operator->() { return 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; }
|
||||
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; }
|
||||
T& operator/=(const T& other) { data /= other; return data; }
|
||||
T operator/(const T& other) const { return data / other; }
|
||||
T& operator+=(const T& other) { data += other; return data; }
|
||||
T operator+(const T& other) const { return data + other; }
|
||||
T& operator-=(const T& other) { data -= other; return data; }
|
||||
T operator-(const T& other) const { return data - other; }
|
||||
};
|
||||
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; }
|
||||
T& operator/=(const T& other) { data /= other; return data; }
|
||||
T operator/(const T& other) const { return data / other; }
|
||||
T& operator+=(const T& other) { data += other; return data; }
|
||||
T operator+(const T& other) const { return data + other; }
|
||||
T& operator-=(const T& other) { data -= other; return data; }
|
||||
T operator-(const T& other) const { return data - other; }
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
extern EGameSDK_API bool IsVftableScanningDisabled();
|
||||
extern EGameSDK_API void SetIsVftableScanningDisabled(bool value);
|
||||
extern EGameSDK_API bool IsVftableScanningDisabled();
|
||||
extern EGameSDK_API void SetIsVftableScanningDisabled(bool value);
|
||||
|
||||
template <typename T, typename GetOffsetFunc, typename... Args>
|
||||
T* _SafeGetImpl(GetOffsetFunc getOffset, bool isDoublePtr, std::string_view className, Args... args) {
|
||||
if (!getOffset(args...))
|
||||
return nullptr;
|
||||
template <typename T, typename GetOffsetFunc, typename... Args>
|
||||
__forceinline T* _SafeGetImpl(GetOffsetFunc getOffset, bool isDoublePtr, bool checkForVTable, Args... args) {
|
||||
auto offset = getOffset(args...);
|
||||
if (!offset)
|
||||
return nullptr;
|
||||
|
||||
T* ptr = isDoublePtr ? *reinterpret_cast<T**>(getOffset(args...)) : reinterpret_cast<T*>(getOffset(args...));
|
||||
if (Utils::Memory::IsBadReadPtr(ptr))
|
||||
return nullptr;
|
||||
T* ptr = isDoublePtr ? *reinterpret_cast<T**>(offset) : reinterpret_cast<T*>(offset);
|
||||
if (Utils::Memory::IsBadReadPtr(ptr))
|
||||
return nullptr;
|
||||
|
||||
if (IsVftableScanningDisabled())
|
||||
return ptr;
|
||||
|
||||
if (!className.empty() && !Utils::RTTI::IsClassVTableNameEqualTo(ptr, className))
|
||||
return nullptr;
|
||||
else if (className.empty() && !Utils::RTTI::IsClassVTableNameEqualTo(ptr, Utils::Values::GetSimpleTypeName(typeid(T).name())))
|
||||
return nullptr;
|
||||
if (!checkForVTable || IsVftableScanningDisabled())
|
||||
return ptr;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
template <typename T, typename GetOffsetFunc, typename... Args>
|
||||
T* SafeGetter(GetOffsetFunc getOffset, bool isDoublePtr = true, std::string_view className = {}, Args... args) {
|
||||
return Utils::Memory::SafeExecution::Execute<T*>(
|
||||
reinterpret_cast<uint64_t>(&_SafeGetImpl<T, GetOffsetFunc, Args...>),
|
||||
nullptr,
|
||||
reinterpret_cast<void*>(getOffset),
|
||||
isDoublePtr,
|
||||
className,
|
||||
args...
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
static const std::string expectedVtableName = Utils::Values::GetSimpleTypeName(typeid(T).name());
|
||||
if (Utils::RTTI::GetVTableNameFromVTPtr(*reinterpret_cast<T**>(ptr)) != expectedVtableName)
|
||||
return nullptr;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template <typename T, typename GetOffsetFunc, typename... Args>
|
||||
__forceinline T* SafeGetter(GetOffsetFunc getOffset, bool isDoublePtr = true, bool checkForVTable = true, Args... args) {
|
||||
__try {
|
||||
return _SafeGetImpl<T>(getOffset, isDoublePtr, checkForVTable, args...);
|
||||
} __except (Utils::Memory::SafeExecution::fail(GetExceptionCode(), GetExceptionInformation())) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -25,7 +25,8 @@ namespace EGSDK::GamePH {
|
||||
static bool SortPlayerVars();
|
||||
#endif
|
||||
|
||||
template <typename T> static T getDefaultValue() {
|
||||
template <typename T>
|
||||
static T getDefaultValue() {
|
||||
if constexpr (std::is_same<T, std::string>::value)
|
||||
return {};
|
||||
else if constexpr (std::is_same<T, bool>::value)
|
||||
@ -36,7 +37,8 @@ namespace EGSDK::GamePH {
|
||||
return T();
|
||||
}
|
||||
|
||||
template <typename T> static T GetPlayerVar(const std::string& playerVar) {
|
||||
template <typename T>
|
||||
static T GetPlayerVar(const std::string& playerVar) {
|
||||
static_assert(std::is_same<T, bool>::value || std::is_same<T, float>::value || std::is_same<T, std::string>::value, "Invalid type: value must be bool, float or string");
|
||||
|
||||
if (!gotPlayerVars)
|
||||
@ -51,7 +53,8 @@ namespace EGSDK::GamePH {
|
||||
|
||||
return *reinterpret_cast<T*>(it->second.first);
|
||||
}
|
||||
template <typename T> static void ChangePlayerVar(const std::string& playerVar, const T value) {
|
||||
template <typename T>
|
||||
static void ChangePlayerVar(const std::string& playerVar, const T value) {
|
||||
static_assert(std::is_same<T, bool>::value || std::is_same<T, float>::value || std::is_same<T, std::string>::value, "Invalid type: value must be bool, float or string");
|
||||
|
||||
if (!gotPlayerVars)
|
||||
@ -89,7 +92,8 @@ namespace EGSDK::GamePH {
|
||||
static std::unordered_map<std::string, std::any> prevPlayerVarValueMap;
|
||||
static std::unordered_map<std::string, bool> prevBoolValueMap;
|
||||
|
||||
template <typename T> static void ManagePlayerVarByBool(const std::string& playerVar, const T valueIfTrue, const T valueIfFalse, bool boolVal, bool usePreviousVal = true) {
|
||||
template <typename T>
|
||||
static void ManagePlayerVarByBool(const std::string& playerVar, const T valueIfTrue, const T valueIfFalse, bool boolVal, bool usePreviousVal = true) {
|
||||
if (!gotPlayerVars)
|
||||
return;
|
||||
|
||||
|
@ -31,8 +31,6 @@ namespace EGSDK {
|
||||
AddOffset(CInput, "engine_x64_rwdi.dll", "48 8B 0D [?? ?? ?? ?? 48 85 C9 74 ?? 48 8B 01 84 D2", Utils::SigScan::PatternType::RelativePointer, DWORD64**) // g_CInput
|
||||
|
||||
// Player vars related
|
||||
//AddVTOffset(TypedFieldMetaFloatPlayerVariable, "gamedll_ph_x64_rwdi.dll", "?$TypedFieldMeta@VFloatPlayerVariable@@@?$FieldsCollection@VPlayerVariables@@@constds", void*)
|
||||
//AddVTOffset(TypedFieldMetaBoolPlayerVariable, "gamedll_ph_x64_rwdi.dll", "?$TypedFieldMeta@VBoolPlayerVariable@@@?$FieldsCollection@VPlayerVariables@@@constds", void*)
|
||||
AddOffset(LoadPlayerVars, "gamedll_ph_x64_rwdi.dll", "48 89 4C 24 ?? B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 2B E0 48 8B 8C 24", Utils::SigScan::PatternType::Address, void*)
|
||||
AddOffset(PlayerState, "gamedll_ph_x64_rwdi.dll", "48 8B 35 [?? ?? ?? ?? 4C 8B F2 48 8B F9", Utils::SigScan::PatternType::RelativePointer, void*)
|
||||
|
||||
|
@ -6,21 +6,25 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <shared_mutex>
|
||||
#include <EGSDK\Exports.h>
|
||||
|
||||
namespace EGSDK::Utils {
|
||||
namespace Memory {
|
||||
static const BYTE SigScanWildCard = 0xAA;
|
||||
static const std::string_view SigScanWildCardStr = "AA";
|
||||
static constexpr BYTE SigScanWildCard = 0xAA;
|
||||
static constexpr std::string_view SigScanWildCardStr = "AA";
|
||||
|
||||
class EGameSDK_API SafeExecution {
|
||||
public:
|
||||
static int fail(unsigned int code, struct _EXCEPTION_POINTERS* ep);
|
||||
|
||||
template<typename T = void*, typename R = T, typename... Args>
|
||||
static T Execute(uint64_t ptr, R ret, Args... args) {
|
||||
template<typename T = void*, typename... Args>
|
||||
static T Execute(uint64_t ptr, T ret, Args... args) {
|
||||
__try {
|
||||
return reinterpret_cast<T(__stdcall*)(Args...)>(ptr)(args...);
|
||||
using FunctionType = T(__stdcall*)(Args...);
|
||||
auto func = reinterpret_cast<FunctionType>(ptr);
|
||||
return func(args...);
|
||||
} __except (fail(GetExceptionCode(), GetExceptionInformation())) {
|
||||
return ret;
|
||||
}
|
||||
@ -29,7 +33,9 @@ namespace EGSDK::Utils {
|
||||
template<typename... Args>
|
||||
static void ExecuteVoid(uint64_t ptr, Args... args) {
|
||||
__try {
|
||||
return reinterpret_cast<void(__stdcall*)(Args...)>(ptr)(args...);
|
||||
using FunctionType = void(__stdcall*)(Args...);
|
||||
auto func = reinterpret_cast<FunctionType>(ptr);
|
||||
func(args...);
|
||||
} __except (fail(GetExceptionCode(), GetExceptionInformation())) {
|
||||
|
||||
}
|
||||
@ -70,71 +76,82 @@ namespace EGSDK::Utils {
|
||||
*/
|
||||
// COPYRIGHT NOTICE - START
|
||||
template <typename T>
|
||||
bool IsBadMemPtr(const bool write, T* ptr, const std::size_t size) {
|
||||
const auto min_ptr = 0x10000;
|
||||
const auto max_ptr = 0x000F000000000000;
|
||||
bool IsBadMemPtr(bool write, T* ptr, std::size_t size) {
|
||||
struct PointerHash {
|
||||
std::size_t operator()(const void* ptr) const {
|
||||
return reinterpret_cast<std::size_t>(ptr) >> 12; // Reduce collisions by using shifted addresses.
|
||||
}
|
||||
};
|
||||
|
||||
static std::unordered_map<void*, MEMORY_BASIC_INFORMATION, PointerHash> memoryCache{};
|
||||
static std::shared_mutex cacheMutex{};
|
||||
|
||||
constexpr DWORD64 min_ptr = 0x10000;
|
||||
constexpr DWORD64 max_ptr = 0x000F000000000000;
|
||||
|
||||
if (ptr == nullptr || reinterpret_cast<DWORD64>(ptr) < min_ptr || reinterpret_cast<DWORD64>(ptr) >= max_ptr)
|
||||
return true;
|
||||
|
||||
DWORD mask = PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY;
|
||||
DWORD mask = write
|
||||
? (PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)
|
||||
: (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY);
|
||||
|
||||
if (write)
|
||||
mask = PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY;
|
||||
|
||||
auto current = reinterpret_cast<BYTE*>(ptr);
|
||||
const auto last = current + size;
|
||||
|
||||
// So we are considering the region:
|
||||
// [ptr, ptr+size)
|
||||
BYTE* current = reinterpret_cast<BYTE*>(ptr);
|
||||
const BYTE* last = current + size;
|
||||
|
||||
while (current < last) {
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
MEMORY_BASIC_INFORMATION mbi{};
|
||||
{
|
||||
std::shared_lock lock(cacheMutex);
|
||||
auto pageAlignedAddr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(current) & ~0xFFF);
|
||||
auto it = memoryCache.find(pageAlignedAddr);
|
||||
if (it != memoryCache.end())
|
||||
mbi = it->second;
|
||||
else {
|
||||
lock.unlock();
|
||||
if (VirtualQuery(reinterpret_cast<LPCVOID>(pageAlignedAddr), &mbi, sizeof mbi) == 0)
|
||||
return true;
|
||||
|
||||
// We couldn't get any information on this region.
|
||||
// Let's not risk any read/write operation.
|
||||
if (VirtualQuery(reinterpret_cast<LPCVOID>(current), &mbi, sizeof mbi) == 0)
|
||||
std::unique_lock writeLock(cacheMutex);
|
||||
memoryCache[pageAlignedAddr] = mbi;
|
||||
}
|
||||
}
|
||||
|
||||
if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS) || (mbi.Protect & mask) == 0)
|
||||
return true;
|
||||
|
||||
// We can't perform our desired read/write operations in this region.
|
||||
if ((mbi.Protect & mask) == 0)
|
||||
return true;
|
||||
|
||||
// We can't access this region.
|
||||
if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS))
|
||||
return true;
|
||||
|
||||
// Let's consider the next region.
|
||||
current = reinterpret_cast<BYTE*>(mbi.BaseAddress) + mbi.RegionSize;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
template <typename T>
|
||||
bool IsBadReadPtr(T* ptr, const std::size_t size) {
|
||||
__forceinline bool IsBadReadPtr(T* ptr, const std::size_t size) {
|
||||
return IsBadMemPtr(false, ptr, size);
|
||||
}
|
||||
template <typename T>
|
||||
bool IsBadReadPtr(T* ptr) {
|
||||
return IsBadReadPtr(ptr, sizeof ptr);
|
||||
__forceinline bool IsBadReadPtr(T* ptr) {
|
||||
return IsBadReadPtr(ptr, sizeof(ptr));
|
||||
}
|
||||
template <typename T>
|
||||
bool IsBadWritePtr(T* ptr, const std::size_t size) {
|
||||
__forceinline bool IsBadWritePtr(T* ptr, const std::size_t size) {
|
||||
return IsBadMemPtr(true, ptr, size);
|
||||
}
|
||||
template <typename T>
|
||||
bool IsBadWritePtr(T* ptr) {
|
||||
return IsBadWritePtr(ptr, sizeof ptr);
|
||||
__forceinline bool IsBadWritePtr(T* ptr) {
|
||||
return IsBadWritePtr(ptr, sizeof(ptr));
|
||||
}
|
||||
// COPYRIGHT NOTICE - END
|
||||
|
||||
template <std::size_t Index, typename ReturnType = void, typename... Args> __forceinline ReturnType CallVT(void* instance, Args... args) {
|
||||
template <std::size_t Index, typename ReturnType = void, typename... Args>
|
||||
__forceinline ReturnType CallVT(void* instance, Args... args) {
|
||||
using Fn = ReturnType(__thiscall*)(void*, Args...);
|
||||
|
||||
auto function = (*reinterpret_cast<Fn**>(instance))[Index];
|
||||
return function(instance, args...);
|
||||
}
|
||||
template <std::size_t Index, typename ReturnType = void, typename... Args> __forceinline ReturnType CallFromVT(void* instance, void* vtable, Args... args) {
|
||||
template <std::size_t Index, typename ReturnType = void, typename... Args>
|
||||
__forceinline ReturnType CallFromVT(void* instance, void* vtable, Args... args) {
|
||||
using Fn = ReturnType(__thiscall*)(void*, Args...);
|
||||
|
||||
auto function = reinterpret_cast<Fn*>(vtable)[Index];
|
||||
@ -142,41 +159,57 @@ namespace EGSDK::Utils {
|
||||
}
|
||||
|
||||
template <typename ReturnType, typename... Args>
|
||||
static ReturnType _SafeCallFunction(const char* moduleName, const char* functionName, ReturnType ret, Args... args) {
|
||||
__forceinline ReturnType SafeCallFunction(const char* moduleName, const char* functionName, ReturnType ret, Args... args) {
|
||||
using FunctionType = ReturnType(__stdcall*)(Args...);
|
||||
FunctionType function = reinterpret_cast<FunctionType>(Utils::Memory::GetProcAddr(moduleName, functionName));
|
||||
if (!function)
|
||||
return ret;
|
||||
|
||||
return Utils::Memory::SafeExecution::Execute<ReturnType>(reinterpret_cast<uint64_t>(function), ReturnType(), args...);
|
||||
__try {
|
||||
return function(args...);
|
||||
} __except (SafeExecution::fail(GetExceptionCode(), GetExceptionInformation())) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
template <typename... Args>
|
||||
static void _SafeCallFunctionVoid(const char* moduleName, const char* functionName, Args... args) {
|
||||
__forceinline void SafeCallFunctionVoid(const char* moduleName, const char* functionName, Args... args) {
|
||||
using FunctionType = void(__stdcall*)(Args...);
|
||||
FunctionType function = reinterpret_cast<FunctionType>(Utils::Memory::GetProcAddr(moduleName, functionName));
|
||||
if (!function)
|
||||
return;
|
||||
|
||||
return Utils::Memory::SafeExecution::ExecuteVoid(reinterpret_cast<uint64_t>(function), args...);
|
||||
__try {
|
||||
function(args...);
|
||||
} __except (SafeExecution::fail(GetExceptionCode(), GetExceptionInformation())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ReturnType, typename GetOffsetFunc, typename... Args>
|
||||
static ReturnType _SafeCallFunctionOffset(GetOffsetFunc getOffset, ReturnType ret, Args... args) {
|
||||
__forceinline ReturnType SafeCallFunctionOffset(GetOffsetFunc getOffset, ReturnType ret, Args... args) {
|
||||
using FunctionType = ReturnType(__stdcall*)(Args...);
|
||||
FunctionType function = reinterpret_cast<FunctionType>(getOffset());
|
||||
if (!function)
|
||||
return ret;
|
||||
|
||||
return Utils::Memory::SafeExecution::Execute<ReturnType>(reinterpret_cast<uint64_t>(function), ReturnType(), args...);
|
||||
__try {
|
||||
return function(args...);
|
||||
} __except (SafeExecution::fail(GetExceptionCode(), GetExceptionInformation())) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
template <typename GetOffsetFunc, typename... Args>
|
||||
static void _SafeCallFunctionOffsetVoid(GetOffsetFunc getOffset, Args... args) {
|
||||
__forceinline void SafeCallFunctionOffsetVoid(GetOffsetFunc getOffset, Args... args) {
|
||||
using FunctionType = void(__stdcall*)(Args...);
|
||||
FunctionType function = reinterpret_cast<FunctionType>(getOffset());
|
||||
if (!function)
|
||||
return;
|
||||
|
||||
return Utils::Memory::SafeExecution::ExecuteVoid(reinterpret_cast<uint64_t>(function), args...);
|
||||
__try {
|
||||
function(args...);
|
||||
} __except (SafeExecution::fail(GetExceptionCode(), GetExceptionInformation())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#pragma endregion
|
||||
}
|
||||
|
@ -8,7 +8,5 @@ namespace EGSDK::Utils {
|
||||
namespace RTTI {
|
||||
extern EGameSDK_API std::string GetVTableNameFromVTPtr(void* vtPtr);
|
||||
extern EGameSDK_API std::string GetVTableName(void* classPtr);
|
||||
extern EGameSDK_API bool IsClassVTableNameEqualTo(void* classPtr, std::string_view tableName);
|
||||
extern EGameSDK_API bool IsVTableNameEqualTo(void* vtPtr, std::string_view tableName);
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ namespace EGSDK::Utils {
|
||||
namespace Values {
|
||||
extern EGameSDK_API bool str_ends_with_ci(std::string const& text, std::string const& substr);
|
||||
|
||||
extern EGameSDK_API bool are_samef(float a, float b, float precision = 0.0001f);
|
||||
extern EGameSDK_API __forceinline bool are_samef(float a, float b, float precision = 0.0001f);
|
||||
extern EGameSDK_API float round_decimal(float value, int decimal_places = 2);
|
||||
|
||||
extern EGameSDK_API bool str_replace(std::string& str, const std::string& from, const std::string& to);
|
||||
|
@ -6,22 +6,22 @@
|
||||
|
||||
namespace EGSDK::Engine {
|
||||
Vector3* CBaseCamera::GetForwardVector(Vector3* outForwardVec) {
|
||||
return Utils::Memory::_SafeCallFunction<Vector3*>("engine_x64_rwdi.dll", "?GetForwardVector@IBaseCamera@@QEBA?BVvec3@@XZ", nullptr, this, outForwardVec);
|
||||
return Utils::Memory::SafeCallFunction<Vector3*>("engine_x64_rwdi.dll", "?GetForwardVector@IBaseCamera@@QEBA?BVvec3@@XZ", nullptr, this, outForwardVec);
|
||||
}
|
||||
Vector3* CBaseCamera::GetUpVector(Vector3* outUpVec) {
|
||||
return Utils::Memory::_SafeCallFunction<Vector3*>("engine_x64_rwdi.dll", "?GetUpVector@IBaseCamera@@QEBA?BVvec3@@XZ", nullptr, this, outUpVec);
|
||||
return Utils::Memory::SafeCallFunction<Vector3*>("engine_x64_rwdi.dll", "?GetUpVector@IBaseCamera@@QEBA?BVvec3@@XZ", nullptr, this, outUpVec);
|
||||
}
|
||||
Vector3* CBaseCamera::GetLeftVector(Vector3* outLeftVec) {
|
||||
return Utils::Memory::_SafeCallFunction<Vector3*>("engine_x64_rwdi.dll", "?GetLeftVector@IBaseCamera@@QEBA?BVvec3@@XZ", nullptr, this, outLeftVec);
|
||||
return Utils::Memory::SafeCallFunction<Vector3*>("engine_x64_rwdi.dll", "?GetLeftVector@IBaseCamera@@QEBA?BVvec3@@XZ", nullptr, this, outLeftVec);
|
||||
}
|
||||
Vector3* CBaseCamera::GetPosition(Vector3* outPos) {
|
||||
return Utils::Memory::_SafeCallFunction<Vector3*>("engine_x64_rwdi.dll", "?GetPosition@IBaseCamera@@UEBA?BVvec3@@XZ", nullptr, this, outPos);
|
||||
return Utils::Memory::SafeCallFunction<Vector3*>("engine_x64_rwdi.dll", "?GetPosition@IBaseCamera@@UEBA?BVvec3@@XZ", nullptr, this, outPos);
|
||||
}
|
||||
|
||||
void CBaseCamera::SetPosition(const Vector3* pos) {
|
||||
Utils::Memory::_SafeCallFunctionVoid("engine_x64_rwdi.dll", "?SetPosition@IBaseCamera@@QEAAXAEBVvec3@@@Z", this, pos);
|
||||
Utils::Memory::SafeCallFunctionVoid("engine_x64_rwdi.dll", "?SetPosition@IBaseCamera@@QEAAXAEBVvec3@@@Z", this, pos);
|
||||
}
|
||||
void CBaseCamera::SetFOV(float fov) {
|
||||
Utils::Memory::_SafeCallFunctionVoid("engine_x64_rwdi.dll", "?SetFOV@IBaseCamera@@QEAAXM@Z", this, fov);
|
||||
Utils::Memory::SafeCallFunctionVoid("engine_x64_rwdi.dll", "?SetFOV@IBaseCamera@@QEAAXM@Z", this, fov);
|
||||
}
|
||||
}
|
@ -9,6 +9,6 @@ namespace EGSDK::Engine {
|
||||
return pCLevel2 ? pCLevel2->pCGSObject2 : nullptr;
|
||||
}
|
||||
CGSObject2* CGSObject2::Get() {
|
||||
return ClassHelpers::SafeGetter<CGSObject2>(GetOffset_CGSObject2, false);
|
||||
return ClassHelpers::SafeGetter<CGSObject2>(GetOffset_CGSObject2, false, false);
|
||||
}
|
||||
}
|
@ -9,6 +9,6 @@ namespace EGSDK::Engine {
|
||||
return pCLobbySteam ? pCLobbySteam->pCGame : nullptr;
|
||||
}
|
||||
CGame* CGame::Get() {
|
||||
return ClassHelpers::SafeGetter<CGame>(GetOffset_CGame, false);
|
||||
return ClassHelpers::SafeGetter<CGame>(GetOffset_CGame, false, false);
|
||||
}
|
||||
}
|
@ -9,6 +9,6 @@ namespace EGSDK::Engine {
|
||||
return pCGSObject ? pCGSObject->pCLevel2 : nullptr;
|
||||
}
|
||||
CLevel2* CLevel2::Get() {
|
||||
return ClassHelpers::SafeGetter<CLevel2>(GetOffset_CLevel2, false);
|
||||
return ClassHelpers::SafeGetter<CLevel2>(GetOffset_CLevel2, false, false);
|
||||
}
|
||||
}
|
@ -9,6 +9,6 @@ namespace EGSDK::Engine {
|
||||
return pPlayerDI_PH ? pPlayerDI_PH->pCoPhysicsProperty : nullptr;
|
||||
}
|
||||
CoPhysicsProperty* CoPhysicsProperty::Get() {
|
||||
return ClassHelpers::SafeGetter<CoPhysicsProperty>(GetOffset_CoPhysicsProperty, false);
|
||||
return ClassHelpers::SafeGetter<CoPhysicsProperty>(GetOffset_CoPhysicsProperty, false, false);
|
||||
}
|
||||
}
|
@ -3,6 +3,6 @@
|
||||
|
||||
namespace EGSDK::Engine {
|
||||
void AuthenticateDataResultsClear(void* instance) {
|
||||
Utils::Memory::_SafeCallFunctionVoid("engine_x64_rwdi.dll", "?Clear@Results@AuthenticateData@@QEAAXXZ", instance);
|
||||
Utils::Memory::SafeCallFunctionVoid("engine_x64_rwdi.dll", "?Clear@Results@AuthenticateData@@QEAAXXZ", instance);
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
namespace EGSDK::GamePH {
|
||||
void FreeCamera::AllowCameraMovement(int mode) {
|
||||
Utils::Memory::_SafeCallFunctionOffsetVoid(Offsets::Get_AllowCameraMovement, this, mode);
|
||||
Utils::Memory::SafeCallFunctionOffsetVoid(Offsets::Get_AllowCameraMovement, this, mode);
|
||||
}
|
||||
|
||||
FreeCamera* FreeCamera::Get() {
|
||||
|
@ -6,10 +6,10 @@
|
||||
|
||||
namespace EGSDK::GamePH {
|
||||
float GameDI_PH::GetGameTimeDelta() {
|
||||
return Utils::Memory::_SafeCallFunction<float>("engine_x64_rwdi.dll", "?GetGameTimeDelta@IGame@@QEBAMXZ", -1.0f, this);
|
||||
return Utils::Memory::SafeCallFunction<float>("engine_x64_rwdi.dll", "?GetGameTimeDelta@IGame@@QEBAMXZ", -1.0f, this);
|
||||
}
|
||||
void GameDI_PH::TogglePhotoMode(bool doNothing, bool setAsOptionalCamera) {
|
||||
Utils::Memory::_SafeCallFunctionOffsetVoid(Offsets::Get_TogglePhotoMode2, this, doNothing, setAsOptionalCamera);
|
||||
Utils::Memory::SafeCallFunctionOffsetVoid(Offsets::Get_TogglePhotoMode2, this, doNothing, setAsOptionalCamera);
|
||||
}
|
||||
|
||||
static GameDI_PH* GetOffset_GameDI_PH() {
|
||||
|
@ -9,6 +9,6 @@ namespace EGSDK::GamePH {
|
||||
return pGameDI_PH ? reinterpret_cast<GameDI_PH2*>(reinterpret_cast<DWORD64>(pGameDI_PH) + Offsets::Get_gameDI_PH2_offset()) : nullptr;
|
||||
}
|
||||
GameDI_PH2* GameDI_PH2::Get() {
|
||||
return ClassHelpers::SafeGetter<GameDI_PH2>(GetOffset_GameDI_PH2, false);
|
||||
return ClassHelpers::SafeGetter<GameDI_PH2>(GetOffset_GameDI_PH2, false, false);
|
||||
}
|
||||
}
|
@ -54,9 +54,9 @@ namespace EGSDK::GamePH {
|
||||
if (!pPlayerDI_PH)
|
||||
return;
|
||||
|
||||
Utils::Memory::_SafeCallFunctionOffsetVoid(Offsets::Get_ShowTPPModelFunc3, pPlayerDI_PH, showTPPModel);
|
||||
Utils::Memory::SafeCallFunctionOffsetVoid(Offsets::Get_ShowTPPModelFunc3, pPlayerDI_PH, showTPPModel);
|
||||
}
|
||||
bool ReloadJumps() {
|
||||
return Utils::Memory::_SafeCallFunctionOffset<bool>(Offsets::Get_ReloadJumps, false);
|
||||
return Utils::Memory::SafeCallFunctionOffset<bool>(Offsets::Get_ReloadJumps, false);
|
||||
}
|
||||
}
|
||||
|
@ -5,9 +5,9 @@
|
||||
|
||||
namespace EGSDK::GamePH {
|
||||
static InventoryMoney* GetOffset_InventoryMoney(InventoryContainerDI* pInventoryContainerDI, UINT indexMaybe) {
|
||||
return Utils::Memory::_SafeCallFunctionOffset<InventoryMoney*>(Offsets::Get_PlayerGetInventoryMoney, nullptr, pInventoryContainerDI, indexMaybe);
|
||||
return Utils::Memory::SafeCallFunctionOffset<InventoryMoney*>(Offsets::Get_PlayerGetInventoryMoney, nullptr, pInventoryContainerDI, indexMaybe);
|
||||
}
|
||||
InventoryMoney* InventoryContainerDI::GetInventoryMoney(UINT indexMaybe) {
|
||||
return ClassHelpers::SafeGetter<InventoryMoney>(GetOffset_InventoryMoney, false, {}, this, indexMaybe);
|
||||
return ClassHelpers::SafeGetter<InventoryMoney>(GetOffset_InventoryMoney, false, true, this, indexMaybe);
|
||||
}
|
||||
}
|
@ -8,6 +8,6 @@ namespace EGSDK::GamePH {
|
||||
return reinterpret_cast<ItemDescWithContext*>(reinterpret_cast<DWORD64>(pInventoryItem) + 0x40);
|
||||
}
|
||||
ItemDescWithContext* InventoryItem::GetItemDescCtx() {
|
||||
return ClassHelpers::SafeGetter<ItemDescWithContext>(GetOffset_ItemDescWithContext, false, {}, this);
|
||||
return ClassHelpers::SafeGetter<ItemDescWithContext>(GetOffset_ItemDescWithContext, false, true, this);
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ namespace EGSDK::GamePH {
|
||||
bool LevelDI::hasLoaded = false;
|
||||
|
||||
bool LevelDI::IsLoading() {
|
||||
return Utils::Memory::_SafeCallFunction<bool>("engine_x64_rwdi.dll", "?IsLoading@ILevel@@QEBA_NXZ", true, this);
|
||||
return Utils::Memory::SafeCallFunction<bool>("engine_x64_rwdi.dll", "?IsLoading@ILevel@@QEBA_NXZ", true, this);
|
||||
}
|
||||
bool LevelDI::IsLoaded() {
|
||||
if (IsLoading() || !GamePH::PlayerDI_PH::Get()) {
|
||||
@ -38,31 +38,31 @@ namespace EGSDK::GamePH {
|
||||
hasLoaded = false;
|
||||
}
|
||||
void* LevelDI::GetViewCamera() {
|
||||
return Utils::Memory::_SafeCallFunction<void*>("engine_x64_rwdi.dll", "?GetViewCamera@ILevel@@QEBAPEAVIBaseCamera@@XZ", nullptr, this);
|
||||
return Utils::Memory::SafeCallFunction<void*>("engine_x64_rwdi.dll", "?GetViewCamera@ILevel@@QEBAPEAVIBaseCamera@@XZ", nullptr, this);
|
||||
}
|
||||
float LevelDI::GetTimeDelta() {
|
||||
return Utils::Memory::_SafeCallFunction<float>("gamedll_ph_x64_rwdi.dll", "?GetTimeDelta@IGSObject@@UEBAMXZ", 0.0f, this);
|
||||
return Utils::Memory::SafeCallFunction<float>("gamedll_ph_x64_rwdi.dll", "?GetTimeDelta@IGSObject@@UEBAMXZ", 0.0f, this);
|
||||
}
|
||||
void LevelDI::SetViewCamera(void* viewCam) {
|
||||
Utils::Memory::_SafeCallFunctionVoid("gamedll_ph_x64_rwdi.dll", "?SetViewCamera@ILevel@@UEAAXPEAVIBaseCamera@@@Z_0", this, viewCam);
|
||||
Utils::Memory::SafeCallFunctionVoid("gamedll_ph_x64_rwdi.dll", "?SetViewCamera@ILevel@@UEAAXPEAVIBaseCamera@@@Z_0", this, viewCam);
|
||||
}
|
||||
float LevelDI::GetTimePlayed() {
|
||||
return Utils::Memory::_SafeCallFunction<float>("gamedll_ph_x64_rwdi.dll", "?GetTimePlayed@ILevel@@UEBAMXZ", 0.0f, this);
|
||||
return Utils::Memory::SafeCallFunction<float>("gamedll_ph_x64_rwdi.dll", "?GetTimePlayed@ILevel@@UEBAMXZ", 0.0f, this);
|
||||
}
|
||||
void LevelDI::ShowUIManager(bool enabled) {
|
||||
Utils::Memory::_SafeCallFunctionVoid("engine_x64_rwdi.dll", "?ShowUIManager@ILevel@@QEAAX_N@Z", this, enabled);
|
||||
Utils::Memory::SafeCallFunctionVoid("engine_x64_rwdi.dll", "?ShowUIManager@ILevel@@QEAAX_N@Z", this, enabled);
|
||||
}
|
||||
bool LevelDI::IsTimerFrozen() {
|
||||
return Utils::Memory::_SafeCallFunction<bool>("engine_x64_rwdi.dll", "?IsTimerFrozen@ILevel@@QEBA_NXZ", false, this);
|
||||
return Utils::Memory::SafeCallFunction<bool>("engine_x64_rwdi.dll", "?IsTimerFrozen@ILevel@@QEBA_NXZ", false, this);
|
||||
}
|
||||
float LevelDI::TimerGetSpeedUp() {
|
||||
return Utils::Memory::_SafeCallFunction<float>("engine_x64_rwdi.dll", "?TimerGetSpeedUp@ILevel@@QEBAMXZ", -1.0f, this);
|
||||
return Utils::Memory::SafeCallFunction<float>("engine_x64_rwdi.dll", "?TimerGetSpeedUp@ILevel@@QEBAMXZ", -1.0f, this);
|
||||
}
|
||||
void LevelDI::TimerSetSpeedUp(float timeScale) {
|
||||
Utils::Memory::_SafeCallFunctionVoid("engine_x64_rwdi.dll", "?TimerSetSpeedUp@ILevel@@QEAAXM@Z", this, timeScale);
|
||||
Utils::Memory::SafeCallFunctionVoid("engine_x64_rwdi.dll", "?TimerSetSpeedUp@ILevel@@QEAAXM@Z", this, timeScale);
|
||||
}
|
||||
TimeWeather::CSystem* LevelDI::GetTimeWeatherSystem() {
|
||||
return Utils::Memory::_SafeCallFunction<TimeWeather::CSystem*>("engine_x64_rwdi.dll", "?GetTimeWeatherSystem@ILevel@@QEBAPEAVCSystem@TimeWeather@@XZ", nullptr, this);
|
||||
return Utils::Memory::SafeCallFunction<TimeWeather::CSystem*>("engine_x64_rwdi.dll", "?GetTimeWeatherSystem@ILevel@@QEBAPEAVCSystem@TimeWeather@@XZ", nullptr, this);
|
||||
}
|
||||
|
||||
static LevelDI* GetOffset_LevelDI() {
|
||||
|
@ -7,17 +7,17 @@
|
||||
|
||||
namespace EGSDK::GamePH {
|
||||
static InventoryItem* GetOffset_CurrentWeapon(PlayerDI_PH* pPlayerDI_PH, UINT indexMaybe) {
|
||||
return Utils::Memory::_SafeCallFunctionOffset<InventoryItem*>(Offsets::Get_PlayerGetCurrentWeapon, nullptr, pPlayerDI_PH, indexMaybe);
|
||||
return Utils::Memory::SafeCallFunctionOffset<InventoryItem*>(Offsets::Get_PlayerGetCurrentWeapon, nullptr, pPlayerDI_PH, indexMaybe);
|
||||
}
|
||||
InventoryItem* PlayerDI_PH::GetCurrentWeapon(UINT indexMaybe) {
|
||||
return ClassHelpers::SafeGetter<InventoryItem>(GetOffset_CurrentWeapon, false, {}, this, indexMaybe);
|
||||
}
|
||||
|
||||
static InventoryContainerDI* GetOffset_InventoryContainer(PlayerDI_PH* pPlayerDI_PH) {
|
||||
static InventoryContainerDI* GetOffset_InventoryContainerDI(PlayerDI_PH* pPlayerDI_PH) {
|
||||
return reinterpret_cast<InventoryContainerDI*>(*reinterpret_cast<DWORD64*>(reinterpret_cast<DWORD64>(pPlayerDI_PH) + 0x470));
|
||||
}
|
||||
InventoryContainerDI* PlayerDI_PH::GetInventoryContainer() {
|
||||
return ClassHelpers::SafeGetter<InventoryContainerDI>(GetOffset_InventoryContainer, false, {}, this);
|
||||
return ClassHelpers::SafeGetter<InventoryContainerDI>(GetOffset_InventoryContainerDI, false, true, this);
|
||||
}
|
||||
|
||||
static PlayerDI_PH* GetOffset_PlayerDI_PH() {
|
||||
@ -25,6 +25,6 @@ namespace EGSDK::GamePH {
|
||||
return pLocalClientDI ? pLocalClientDI->pPlayerDI_PH : nullptr;
|
||||
}
|
||||
PlayerDI_PH* PlayerDI_PH::Get() {
|
||||
return ClassHelpers::SafeGetter<PlayerDI_PH>(GetOffset_PlayerDI_PH, false);
|
||||
return ClassHelpers::SafeGetter<PlayerDI_PH>(GetOffset_PlayerDI_PH, false, false);
|
||||
}
|
||||
}
|
@ -20,7 +20,7 @@ namespace EGSDK::GamePH {
|
||||
return pPlayerHealthModule;
|
||||
}
|
||||
PlayerHealthModule* PlayerHealthModule::Get() {
|
||||
return ClassHelpers::SafeGetter<PlayerHealthModule>(GetOffset_PlayerHealthModule, false);
|
||||
return ClassHelpers::SafeGetter<PlayerHealthModule>(GetOffset_PlayerHealthModule, false, false);
|
||||
}
|
||||
|
||||
void PlayerHealthModule::EmplaceBack(PlayerHealthModule* ptr) {
|
||||
|
@ -20,7 +20,7 @@ namespace EGSDK::GamePH {
|
||||
return pPlayerInfectionModule;
|
||||
}
|
||||
PlayerInfectionModule* PlayerInfectionModule::Get() {
|
||||
return ClassHelpers::SafeGetter<PlayerInfectionModule>(GetOffset_PlayerInfectionModule, false);
|
||||
return ClassHelpers::SafeGetter<PlayerInfectionModule>(GetOffset_PlayerInfectionModule, false, false);
|
||||
}
|
||||
|
||||
void PlayerInfectionModule::EmplaceBack(PlayerInfectionModule* ptr) {
|
||||
|
@ -30,37 +30,37 @@ namespace EGSDK::GamePH {
|
||||
|
||||
it->second.first.template emplace<T>(varValue);
|
||||
}
|
||||
static void processPlayerVar(DWORD64** (*playerVarsGetter)(), std::pair<std::string, std::pair<void*, std::string>>& var) {
|
||||
static void processPlayerVar(DWORD64*(*playerVarsGetter)(), std::pair<std::string, std::pair<void*, std::string>>& var) {
|
||||
static int offset = 0;
|
||||
__try {
|
||||
while (true) {
|
||||
const bool isFloatPlayerVar = Utils::RTTI::IsClassVTableNameEqualTo(*(playerVarsGetter() + offset), "FloatPlayerVariable");
|
||||
const bool isBoolPlayerVar = Utils::RTTI::IsClassVTableNameEqualTo(*(playerVarsGetter() + offset), "BoolPlayerVariable");
|
||||
static const std::string floatPlayerVarClassName = "FloatPlayerVariable";
|
||||
static const std::string boolPlayerVarClassName = "BoolPlayerVariable";
|
||||
|
||||
if (isFloatPlayerVar || isBoolPlayerVar) {
|
||||
var.second.first = playerVarsGetter() + offset + VAR_LOC_OFFSET;
|
||||
const std::string& varName = var.first;
|
||||
while (true) {
|
||||
const std::string vTableName = Utils::RTTI::GetVTableName(playerVarsGetter() + offset);
|
||||
const bool isFloatPlayerVar = vTableName == floatPlayerVarClassName;
|
||||
const bool isBoolPlayerVar = vTableName == boolPlayerVarClassName;
|
||||
|
||||
if (isFloatPlayerVar) {
|
||||
float* varValue = reinterpret_cast<float*>(var.second.first);
|
||||
updateDefaultVar(GamePH::PlayerVariables::playerVarsDefault, varName, *varValue);
|
||||
updateDefaultVar(GamePH::PlayerVariables::playerCustomVarsDefault, varName, *varValue);
|
||||
if (isFloatPlayerVar || isBoolPlayerVar) {
|
||||
var.second.first = playerVarsGetter() + offset + VAR_LOC_OFFSET;
|
||||
const std::string& varName = var.first;
|
||||
|
||||
offset += FLOAT_VAR_OFFSET;
|
||||
} else {
|
||||
bool* varValue = reinterpret_cast<bool*>(var.second.first);
|
||||
updateDefaultVar(GamePH::PlayerVariables::playerVarsDefault, varName, *varValue);
|
||||
updateDefaultVar(GamePH::PlayerVariables::playerCustomVarsDefault, varName, *varValue);
|
||||
if (isFloatPlayerVar) {
|
||||
float* varValue = reinterpret_cast<float*>(var.second.first);
|
||||
updateDefaultVar(GamePH::PlayerVariables::playerVarsDefault, varName, *varValue);
|
||||
updateDefaultVar(GamePH::PlayerVariables::playerCustomVarsDefault, varName, *varValue);
|
||||
|
||||
offset += BOOL_VAR_OFFSET;
|
||||
}
|
||||
offset += FLOAT_VAR_OFFSET;
|
||||
} else {
|
||||
bool* varValue = reinterpret_cast<bool*>(var.second.first);
|
||||
updateDefaultVar(GamePH::PlayerVariables::playerVarsDefault, varName, *varValue);
|
||||
updateDefaultVar(GamePH::PlayerVariables::playerCustomVarsDefault, varName, *varValue);
|
||||
|
||||
break;
|
||||
} else
|
||||
offset += 1;
|
||||
}
|
||||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
SPDLOG_ERROR("Failed to process player variable: {}", var.first);
|
||||
offset += BOOL_VAR_OFFSET;
|
||||
}
|
||||
|
||||
break;
|
||||
} else
|
||||
offset += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,8 +72,13 @@ namespace EGSDK::GamePH {
|
||||
if (!Get())
|
||||
return;
|
||||
|
||||
for (auto& var : playerVars)
|
||||
processPlayerVar(reinterpret_cast<DWORD64**(*)()>(&Get), var);
|
||||
for (auto& var : playerVars) {
|
||||
__try {
|
||||
processPlayerVar(reinterpret_cast<DWORD64*(*)()>(&Get), var);
|
||||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
SPDLOG_ERROR("Failed to process player variable: {}", var.first);
|
||||
}
|
||||
}
|
||||
|
||||
gotPlayerVars = true;
|
||||
}
|
||||
@ -88,17 +93,17 @@ namespace EGSDK::GamePH {
|
||||
{ PlayerVariables::PlayerVarType::Bool, "constds::FieldsCollection<PlayerVariables>::TypedFieldMeta<BoolPlayerVariable>" }
|
||||
};
|
||||
|
||||
bool isRetInstruction(BYTE* address) {
|
||||
static bool isRetInstruction(BYTE* address) {
|
||||
//return address[0] == 0xC3 && address[1] == 0xCC;
|
||||
return address[0] == 0x00 && address[1] == 0x00 && address[2] == 0xC3 && address[3] == 0xCC;
|
||||
}
|
||||
bool isLeaInstruction(BYTE* address, BYTE REX, BYTE ModRM) {
|
||||
static bool isLeaInstruction(BYTE* address, BYTE REX, BYTE ModRM) {
|
||||
return address[0] == REX && address[1] == 0x8D && address[2] == ModRM;
|
||||
}
|
||||
bool isCallInstruction(BYTE* address) {
|
||||
static bool isCallInstruction(BYTE* address) {
|
||||
return address[0] == 0xE8 && address[4] != 0xE8;
|
||||
}
|
||||
bool isBelowFuncSizeLimit(BYTE* address, DWORD64 startOfFunc, size_t sizeLimit) {
|
||||
static bool isBelowFuncSizeLimit(BYTE* address, DWORD64 startOfFunc, size_t sizeLimit) {
|
||||
return (reinterpret_cast<DWORD64>(address) - startOfFunc) < sizeLimit;
|
||||
}
|
||||
|
||||
@ -127,7 +132,7 @@ namespace EGSDK::GamePH {
|
||||
|
||||
return playerVarName;
|
||||
}
|
||||
PlayerVariables::PlayerVarType getPlayerVarType(BYTE*& funcAddress, DWORD64 startOfFunc) {
|
||||
static PlayerVariables::PlayerVarType getPlayerVarType(BYTE*& funcAddress, DWORD64 startOfFunc) {
|
||||
PlayerVariables::PlayerVarType playerVarType = PlayerVariables::PlayerVarType::NONE;
|
||||
|
||||
while (!playerVarType && !isRetInstruction(funcAddress) && isBelowFuncSizeLimit(funcAddress, startOfFunc, MAX_FUNC_SIZE)) {
|
||||
@ -150,14 +155,14 @@ namespace EGSDK::GamePH {
|
||||
}
|
||||
|
||||
metaVTAddrFromFunc = Utils::Memory::CalcTargetAddrOfRelativeInstr(reinterpret_cast<DWORD64>(loadVarFuncAddress), 3);
|
||||
if (!Utils::RTTI::IsVTableNameEqualTo(reinterpret_cast<DWORD64*>(metaVTAddrFromFunc), varType.className)) {
|
||||
if (Utils::RTTI::GetVTableNameFromVTPtr(reinterpret_cast<DWORD64*>(metaVTAddrFromFunc)) != varType.className) {
|
||||
metaVTAddrFromFunc = 0;
|
||||
loadVarFuncAddress++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (Utils::RTTI::IsVTableNameEqualTo(reinterpret_cast<DWORD64*>(metaVTAddrFromFunc), varType.className)) {
|
||||
if (Utils::RTTI::GetVTableNameFromVTPtr(reinterpret_cast<DWORD64*>(metaVTAddrFromFunc)) == varType.className) {
|
||||
playerVarType = varType.type;
|
||||
break;
|
||||
}
|
||||
@ -216,6 +221,6 @@ namespace EGSDK::GamePH {
|
||||
return pPlayerState ? pPlayerState->pPlayerVariables : nullptr;
|
||||
}
|
||||
PlayerVariables* PlayerVariables::Get() {
|
||||
return ClassHelpers::SafeGetter<PlayerVariables>(GetOffset_PlayerVariables, false);
|
||||
return ClassHelpers::SafeGetter<PlayerVariables>(GetOffset_PlayerVariables, false, false);
|
||||
}
|
||||
}
|
@ -7,10 +7,10 @@
|
||||
namespace EGSDK::GamePH {
|
||||
namespace TimeWeather {
|
||||
void CSystem::SetForcedWeather(int weather) {
|
||||
Utils::Memory::_SafeCallFunctionVoid("engine_x64_rwdi.dll", "?SetForcedWeather@CSystem@TimeWeather@@QEAAXW4TYPE@EWeather@@VApiDebugAccess@2@@Z", this, weather);
|
||||
Utils::Memory::SafeCallFunctionVoid("engine_x64_rwdi.dll", "?SetForcedWeather@CSystem@TimeWeather@@QEAAXW4TYPE@EWeather@@VApiDebugAccess@2@@Z", this, weather);
|
||||
}
|
||||
int CSystem::GetCurrentWeather() {
|
||||
return Utils::Memory::_SafeCallFunction<int>("engine_x64_rwdi.dll", "?GetCurrentWeather@CSystem@TimeWeather@@QEBA?AW4TYPE@EWeather@@XZ", EWeather::TYPE::Default, this);
|
||||
return Utils::Memory::SafeCallFunction<int>("engine_x64_rwdi.dll", "?GetCurrentWeather@CSystem@TimeWeather@@QEBA?AW4TYPE@EWeather@@XZ", EWeather::TYPE::Default, this);
|
||||
}
|
||||
|
||||
static CSystem* GetOffset_CSystem() {
|
||||
@ -18,7 +18,7 @@ namespace EGSDK::GamePH {
|
||||
return pLevelDI ? pLevelDI->GetTimeWeatherSystem() : nullptr;
|
||||
}
|
||||
CSystem* CSystem::Get() {
|
||||
return ClassHelpers::SafeGetter<CSystem>(GetOffset_CSystem, false);
|
||||
return ClassHelpers::SafeGetter<CSystem>(GetOffset_CSystem, false, false);
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <unordered_map>
|
||||
#include <shared_mutex>
|
||||
#include <DbgHelp.h>
|
||||
#include <memscan\memscan.h>
|
||||
#include <EGSDK\Utils\RTTI.h>
|
||||
@ -13,64 +14,93 @@
|
||||
namespace EGSDK::Utils {
|
||||
namespace RTTI {
|
||||
static std::unordered_map<DWORD64, std::string> vtableAddressCache{};
|
||||
static std::shared_mutex vtableCacheMutex;
|
||||
|
||||
static std::string _GetVTableNameFromVTPtr(void* vtPtr) {
|
||||
if (Utils::Memory::IsBadReadPtr(vtPtr))
|
||||
return "bad_read_vtable";
|
||||
DWORD64 vtableStructAddr = reinterpret_cast<DWORD64>(vtPtr);
|
||||
if (auto it = vtableAddressCache.find(vtableStructAddr); it != vtableAddressCache.end())
|
||||
return it->second;
|
||||
static __forceinline std::string CacheEmptyResult(DWORD64 vtableStructAddr) {
|
||||
std::unique_lock lock(vtableCacheMutex);
|
||||
vtableAddressCache.try_emplace(vtableStructAddr, "");
|
||||
return {};
|
||||
}
|
||||
|
||||
DWORD64 objectLocatorAddr = *reinterpret_cast<DWORD64*>(vtableStructAddr - sizeof(DWORD64));
|
||||
std::string GetVTableNameFromVTPtr(void* vtPtr) {
|
||||
if (Utils::Memory::IsBadReadPtr(vtPtr))
|
||||
return "bad_read_vtable";
|
||||
|
||||
DWORD64 baseOffset = *reinterpret_cast<DWORD64*>(objectLocatorAddr + 0x14);
|
||||
DWORD64 baseAddr = objectLocatorAddr - baseOffset;
|
||||
DWORD64 vtableStructAddr = reinterpret_cast<DWORD64>(vtPtr);
|
||||
|
||||
DWORD classHierarchyDescriptorOffset = *reinterpret_cast<DWORD*>(objectLocatorAddr + 0x10);
|
||||
DWORD64 classHierarchyDescriptorAddr = baseAddr + classHierarchyDescriptorOffset;
|
||||
{
|
||||
std::shared_lock lock(vtableCacheMutex);
|
||||
if (auto it = vtableAddressCache.find(vtableStructAddr); it != vtableAddressCache.end())
|
||||
return it->second;
|
||||
}
|
||||
|
||||
int baseClassCount = *reinterpret_cast<int*>(classHierarchyDescriptorAddr + 0x8);
|
||||
if (baseClassCount == 0 || baseClassCount > 24)
|
||||
return {};
|
||||
DWORD64* objectLocatorPtr = reinterpret_cast<DWORD64*>(vtableStructAddr - sizeof(DWORD64));
|
||||
if (Utils::Memory::IsBadReadPtr(objectLocatorPtr))
|
||||
return CacheEmptyResult(vtableStructAddr);
|
||||
|
||||
DWORD baseClassArrayOffset = *reinterpret_cast<DWORD*>(classHierarchyDescriptorAddr + 0xC);
|
||||
DWORD64 baseClassArrayAddr = baseAddr + baseClassArrayOffset;
|
||||
DWORD64 objectLocatorAddr = *objectLocatorPtr;
|
||||
DWORD64* baseOffsetPtr = reinterpret_cast<DWORD64*>(objectLocatorAddr + 0x14);
|
||||
if (Utils::Memory::IsBadReadPtr(baseOffsetPtr))
|
||||
return CacheEmptyResult(vtableStructAddr);
|
||||
|
||||
DWORD baseClassDescriptorOffset = *reinterpret_cast<DWORD*>(baseClassArrayAddr);
|
||||
DWORD64 baseClassDescriptorAddr = baseAddr + baseClassDescriptorOffset;
|
||||
DWORD64 baseOffset = *baseOffsetPtr;
|
||||
DWORD64 baseAddr = objectLocatorAddr - baseOffset;
|
||||
|
||||
DWORD typeDescriptorOffset = *reinterpret_cast<DWORD*>(baseClassDescriptorAddr);
|
||||
DWORD64 typeDescriptorAddr = baseAddr + typeDescriptorOffset;
|
||||
DWORD* classHierarchyDescriptorOffsetPtr = reinterpret_cast<DWORD*>(objectLocatorAddr + 0x10);
|
||||
if (Utils::Memory::IsBadReadPtr(classHierarchyDescriptorOffsetPtr))
|
||||
return CacheEmptyResult(vtableStructAddr);
|
||||
|
||||
std::string decoratedClassName = "?" + std::string(reinterpret_cast<const char*>(typeDescriptorAddr + 0x14));
|
||||
char outUndecoratedClassName[255]{};
|
||||
UnDecorateSymbolName(decoratedClassName.c_str(), outUndecoratedClassName, sizeof(outUndecoratedClassName), UNDNAME_NAME_ONLY);
|
||||
DWORD classHierarchyDescriptorOffset = *classHierarchyDescriptorOffsetPtr;
|
||||
DWORD64 classHierarchyDescriptorAddr = baseAddr + classHierarchyDescriptorOffset;
|
||||
|
||||
vtableAddressCache[vtableStructAddr] = outUndecoratedClassName;
|
||||
int* baseClassCountPtr = reinterpret_cast<int*>(classHierarchyDescriptorAddr + 0x8);
|
||||
if (Utils::Memory::IsBadReadPtr(baseClassCountPtr) || *baseClassCountPtr == 0 || *baseClassCountPtr > 24)
|
||||
return CacheEmptyResult(vtableStructAddr);
|
||||
|
||||
return outUndecoratedClassName;
|
||||
}
|
||||
static std::string _GetVTableName(void* classPtr) {
|
||||
if (Utils::Memory::IsBadReadPtr(classPtr))
|
||||
return "bad_read_class";
|
||||
return _GetVTableNameFromVTPtr(*reinterpret_cast<DWORD64**>(classPtr));
|
||||
}
|
||||
DWORD* baseClassArrayOffsetPtr = reinterpret_cast<DWORD*>(classHierarchyDescriptorAddr + 0xC);
|
||||
if (Utils::Memory::IsBadReadPtr(baseClassArrayOffsetPtr))
|
||||
return CacheEmptyResult(vtableStructAddr);
|
||||
|
||||
std::string GetVTableNameFromVTPtr(void* vtPtr) {
|
||||
std::string result = _GetVTableNameFromVTPtr(vtPtr);
|
||||
if (result.empty())
|
||||
vtableAddressCache.try_emplace(*reinterpret_cast<DWORD64*>(vtPtr), "");
|
||||
DWORD baseClassArrayOffset = *baseClassArrayOffsetPtr;
|
||||
DWORD64 baseClassArrayAddr = baseAddr + baseClassArrayOffset;
|
||||
|
||||
return result;
|
||||
}
|
||||
std::string GetVTableName(void* classPtr) {
|
||||
std::string result = _GetVTableName(classPtr);
|
||||
if (result.empty())
|
||||
vtableAddressCache.try_emplace(*reinterpret_cast<DWORD64*>(classPtr), "");
|
||||
DWORD* baseClassDescriptorOffsetPtr = reinterpret_cast<DWORD*>(baseClassArrayAddr);
|
||||
if (Utils::Memory::IsBadReadPtr(baseClassDescriptorOffsetPtr))
|
||||
return CacheEmptyResult(vtableStructAddr);
|
||||
|
||||
return result;
|
||||
}
|
||||
bool IsClassVTableNameEqualTo(void* classPtr, std::string_view tableName) { return GetVTableName(classPtr) == tableName; }
|
||||
bool IsVTableNameEqualTo(void* vtPtr, std::string_view tableName) { return GetVTableNameFromVTPtr(vtPtr) == tableName; }
|
||||
DWORD baseClassDescriptorOffset = *baseClassDescriptorOffsetPtr;
|
||||
DWORD64 baseClassDescriptorAddr = baseAddr + baseClassDescriptorOffset;
|
||||
|
||||
DWORD* typeDescriptorOffsetPtr = reinterpret_cast<DWORD*>(baseClassDescriptorAddr);
|
||||
if (Utils::Memory::IsBadReadPtr(typeDescriptorOffsetPtr))
|
||||
return CacheEmptyResult(vtableStructAddr);
|
||||
|
||||
DWORD typeDescriptorOffset = *typeDescriptorOffsetPtr;
|
||||
DWORD64 typeDescriptorAddr = baseAddr + typeDescriptorOffset;
|
||||
|
||||
const char* decoratedClassNameCStr = reinterpret_cast<const char*>(typeDescriptorAddr + 0x14);
|
||||
std::string decoratedClassName = "?" + std::string(decoratedClassNameCStr);
|
||||
|
||||
char outUndecoratedClassNameCStr[255]{};
|
||||
if (UnDecorateSymbolName(decoratedClassName.c_str(), outUndecoratedClassNameCStr, sizeof(outUndecoratedClassNameCStr), UNDNAME_NAME_ONLY) == 0)
|
||||
return CacheEmptyResult(vtableStructAddr);
|
||||
|
||||
std::string result(outUndecoratedClassNameCStr);
|
||||
|
||||
// Cache the valid result
|
||||
{
|
||||
std::unique_lock lock(vtableCacheMutex);
|
||||
vtableAddressCache[vtableStructAddr] = result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
std::string GetVTableName(void* classPtr) {
|
||||
if (Utils::Memory::IsBadReadPtr(classPtr))
|
||||
return "bad_read_class";
|
||||
|
||||
void* vtablePtr = *reinterpret_cast<void**>(classPtr);
|
||||
return GetVTableNameFromVTPtr(vtablePtr);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,29 +1,35 @@
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <cmath>
|
||||
#include <EGSDK\Utils\Values.h>
|
||||
|
||||
namespace EGSDK::Utils {
|
||||
namespace Values {
|
||||
bool str_ends_with_ci(std::string const& text, std::string const& substr) {
|
||||
bool str_ends_with_ci(const std::string& text, const std::string& 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::equal(substr.rbegin(), substr.rend(), text.rbegin(), [](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; }
|
||||
__forceinline bool are_samef(float a, float b, float precision) {
|
||||
return std::fabs(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);
|
||||
float multiplier = 1.0f;
|
||||
for (int i = 0; i < decimal_places; ++i)
|
||||
multiplier *= 10.0f;
|
||||
|
||||
return std::round(value * multiplier) / multiplier;
|
||||
}
|
||||
|
||||
bool str_replace(std::string& str, const std::string& from, const std::string& to) {
|
||||
const size_t start_pos = str.find(from);
|
||||
size_t start_pos = str.find(from);
|
||||
if (start_pos == std::string::npos)
|
||||
return false;
|
||||
|
||||
@ -32,12 +38,16 @@ namespace EGSDK::Utils {
|
||||
}
|
||||
|
||||
std::string GetSimpleTypeName(std::string fullName) {
|
||||
if (fullName.compare(0, 6, "class ") == 0)
|
||||
fullName.erase(0, 6);
|
||||
else if (fullName.compare(0, 7, "struct ") == 0)
|
||||
fullName.erase(0, 7);
|
||||
else if (fullName.compare(0, 5, "enum ") == 0)
|
||||
fullName.erase(0, 5);
|
||||
static const std::string class_prefix = "class ";
|
||||
static const std::string struct_prefix = "struct ";
|
||||
static const std::string enum_prefix = "enum ";
|
||||
|
||||
if (fullName.compare(0, class_prefix.size(), class_prefix) == 0)
|
||||
fullName.erase(0, class_prefix.size());
|
||||
else if (fullName.compare(0, struct_prefix.size(), struct_prefix) == 0)
|
||||
fullName.erase(0, struct_prefix.size());
|
||||
else if (fullName.compare(0, enum_prefix.size(), enum_prefix) == 0)
|
||||
fullName.erase(0, enum_prefix.size());
|
||||
|
||||
size_t pos = fullName.find_last_of("::");
|
||||
if (pos != std::string::npos)
|
||||
|
@ -4,10 +4,12 @@
|
||||
<LocalDebuggerCommand>D:\Program Files (x86)\Steam\steamapps\common\Dying Light 2\ph\work\bin\x64\DyingLightGame_x64_rwdi.exe</LocalDebuggerCommand>
|
||||
<LocalDebuggerWorkingDirectory>D:\Program Files (x86)\Steam\steamapps\common\Dying Light 2\ph\work\bin\x64</LocalDebuggerWorkingDirectory>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
<LocalDebuggerAttach>false</LocalDebuggerAttach>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LocalDebuggerCommand>D:\Program Files (x86)\Steam\steamapps\common\Dying Light 2\ph\work\bin\x64\DyingLightGame_x64_rwdi.exe</LocalDebuggerCommand>
|
||||
<LocalDebuggerWorkingDirectory>D:\Program Files (x86)\Steam\steamapps\common\Dying Light 2\ph\work\bin\x64</LocalDebuggerWorkingDirectory>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
<LocalDebuggerAttach>false</LocalDebuggerAttach>
|
||||
</PropertyGroup>
|
||||
</Project>
|
Reference in New Issue
Block a user