cleaned code for Player tab and Player Variables, made Player Variables code thread-safe

This commit is contained in:
EricPlayZ
2025-01-07 06:54:36 +02:00
parent c64cf6fc93
commit fdd82c56f1
8 changed files with 392 additions and 707 deletions

View File

@ -50,7 +50,7 @@ namespace EGSDK {
if (!checkForVTable || IsVftableScanningDisabled())
return ptr;
static const std::string expectedVtableName = Utils::Values::GetSimpleTypeName(typeid(T).name());
static const std::string expectedVtableName = Utils::Values::GetSimpleRTTITypeName(typeid(T).name());
if (Utils::RTTI::GetVTableNameFromVTPtr(*reinterpret_cast<T**>(ptr)) != expectedVtableName)
return nullptr;

View File

@ -2,9 +2,8 @@
#include <any>
#include <unordered_map>
#include <vector>
#include <memory>
#include <algorithm>
#include <mutex>
#include <atomic>
#include <EGSDK\ClassHelpers.h>
#include <EGSDK\Utils\Values.h>
@ -28,7 +27,9 @@ namespace EGSDK::GamePH {
private:
static std::unordered_map<PlayerVariable*, std::string> playerVarNames;
static std::unordered_map<PlayerVariable*, PlayerVarType> playerVarTypes;
static std::mutex mutex;
};
class EGameSDK_API StringPlayerVariable : public PlayerVariable {
public:
union {
@ -36,6 +37,10 @@ namespace EGSDK::GamePH {
EGSDK::ClassHelpers::buffer<0x10, const char*> defaultValue; // remove 0x2 bit to access ptr
};
explicit StringPlayerVariable(const std::string& name);
const char* GetValue();
const char* GetDefaultValue();
void SetValues(const std::string& value);
};
class EGameSDK_API FloatPlayerVariable : public PlayerVariable {
public:
@ -45,6 +50,8 @@ namespace EGSDK::GamePH {
};
explicit FloatPlayerVariable(const std::string& name);
float GetValue();
float GetDefaultValue();
void SetValues(float value);
};
class EGameSDK_API BoolPlayerVariable : public PlayerVariable {
@ -55,6 +62,8 @@ namespace EGSDK::GamePH {
};
explicit BoolPlayerVariable(const std::string& name);
bool GetValue();
bool GetDefaultValue();
void SetValues(bool value);
};
@ -68,17 +77,18 @@ namespace EGSDK::GamePH {
PlayerVarVector& operator=(PlayerVarVector&&) noexcept = default;
std::unique_ptr<PlayerVariable>& emplace_back(std::unique_ptr<PlayerVariable> playerVar);
auto begin();
auto end();
std::vector<std::unique_ptr<PlayerVariable>>::iterator begin();
std::vector<std::unique_ptr<PlayerVariable>>::iterator end();
bool empty();
bool none_of(const std::string& name);
auto FindIter(const std::string& name);
std::vector<std::unique_ptr<PlayerVariable>>::iterator FindIter(const std::string& name);
std::unique_ptr<PlayerVariable>* FindPtr(const std::string& name);
PlayerVariable* Find(const std::string& name);
auto Erase(const std::string& name);
std::vector<std::unique_ptr<PlayerVariable>>::iterator Erase(const std::string& name);
private:
std::vector<std::unique_ptr<PlayerVariable>> _playerVars{};
mutable std::mutex _mutex;
mutable std::mutex _mutex{};
};
class EGameSDK_API PlayerVariables {
@ -87,7 +97,7 @@ namespace EGSDK::GamePH {
static PlayerVarVector customPlayerVars;
static PlayerVarVector defaultPlayerVars;
static PlayerVarVector customDefaultPlayerVars;
static bool gotPlayerVars;
static std::atomic<bool> gotPlayerVars;
static std::unordered_map<std::string, std::any> prevPlayerVarValueMap;
static std::unordered_map<std::string, bool> prevBoolValueMap;
@ -98,225 +108,15 @@ namespace EGSDK::GamePH {
#endif
template <typename T>
static T getDefaultValue() {
static_assert(std::is_same_v<T, std::string> || std::is_same_v<T, float> || std::is_same_v<T, bool>, "Invalid type: value must be string, float or bool");
if constexpr (std::is_same_v<T, std::string>)
return {};
else if constexpr (std::is_same_v<T, float>)
return -404.0f;
else if constexpr (std::is_same_v<T, bool>)
return false;
else
return T();
}
static T GetPlayerVarValue(const std::string& name);
template <typename T>
static void ChangePlayerVar(const std::string& name, const T value, PlayerVariable* playerVar = nullptr);
template <typename T>
static void ChangePlayerVarFromList(const std::string& name, const T value, PlayerVariable* playerVar = nullptr);
template <typename T>
static T GetPlayerVarValue(const std::string& name) {
static_assert(std::is_same_v<T, std::string> || std::is_same_v<T, float> || std::is_same_v<T, bool>, "Invalid type: value must be string, float or bool");
if (!gotPlayerVars)
return getDefaultValue<T>();
auto playerVar = playerVars.Find(name);
if (!playerVar)
return getDefaultValue<T>();
if constexpr (std::is_same_v<T, std::string>) {
StringPlayerVariable* stringPlayerVar = reinterpret_cast<StringPlayerVariable*>(playerVar);
return stringPlayerVar->value.data;
} else if constexpr (std::is_same_v<T, float>) {
FloatPlayerVariable* floatPlayerVar = reinterpret_cast<FloatPlayerVariable*>(playerVar);
return floatPlayerVar->value.data;
} else if constexpr (std::is_same_v<T, bool>) {
BoolPlayerVariable* boolPlayerVar = reinterpret_cast<BoolPlayerVariable*>(playerVar);
return boolPlayerVar->value.data;
}
}
template <typename T>
static void ChangePlayerVar(const std::string& name, const T value) {
static_assert(std::is_same_v<T, std::string> || std::is_same_v<T, float> || std::is_same_v<T, bool>, "Invalid type: value must be string, float or bool");
if (!gotPlayerVars)
return;
auto playerVar = playerVars.Find(name);
if (!playerVar)
return;
if constexpr (std::is_same_v<T, std::string>) {
switch (playerVar->GetType()) {
case PlayerVarType::String:
// TO IMPLEMENT
break;
case PlayerVarType::Float:
{
std::string valueStr = Utils::Values::to_string(value);
float actualValue = std::stof(valueStr);
FloatPlayerVariable* floatPlayerVar = reinterpret_cast<FloatPlayerVariable*>(playerVar);
floatPlayerVar->SetValues(actualValue);
break;
}
case PlayerVarType::Bool:
{
std::string valueStr = Utils::Values::to_string(value);
bool actualValue = valueStr == "true";
BoolPlayerVariable* boolPlayerVar = reinterpret_cast<BoolPlayerVariable*>(playerVar);
boolPlayerVar->SetValues(actualValue);
break;
}
default:
break;
}
} else if constexpr (std::is_same_v<T, float>) {
if (playerVar->GetType() != PlayerVarType::Float)
return;
FloatPlayerVariable* floatPlayerVar = reinterpret_cast<FloatPlayerVariable*>(playerVar);
floatPlayerVar->SetValues(value);
} else if constexpr (std::is_same_v<T, bool>) {
if (playerVar->GetType() != PlayerVarType::Bool)
return;
BoolPlayerVariable* boolPlayerVar = reinterpret_cast<BoolPlayerVariable*>(playerVar);
boolPlayerVar->SetValues(value);
}
}
template <typename T>
static void ChangePlayerVarFromList(const std::string& name, const T value, PlayerVariable* playerVar = nullptr) {
static_assert(std::is_same_v<T, std::string> || std::is_same_v<T, float> || std::is_same_v<T, bool>, "Invalid type: value must be string, float or bool");
if (!gotPlayerVars)
return;
if (!playerVar) {
playerVar = playerVars.Find(name);
if (!playerVar)
return;
}
auto customPlayerVar = customPlayerVars.Find(name);
auto defPlayerVar = defaultPlayerVars.Find(name);
if constexpr (std::is_same_v<T, std::string>) {
switch (playerVar->GetType()) {
case PlayerVarType::String:
// TO IMPLEMENT
break;
case PlayerVarType::Float:
{
if (!customPlayerVar)
customPlayerVar = customPlayerVars.emplace_back(std::make_unique<FloatPlayerVariable>(name)).get();
std::string valueStr = Utils::Values::to_string(value);
float actualValue = std::stof(valueStr);
FloatPlayerVariable* floatPlayerVar = reinterpret_cast<FloatPlayerVariable*>(playerVar);
FloatPlayerVariable* customFloatPlayerVar = reinterpret_cast<FloatPlayerVariable*>(customPlayerVar);
if (!defPlayerVar) {
defPlayerVar = defaultPlayerVars.emplace_back(std::make_unique<FloatPlayerVariable>(name)).get();
FloatPlayerVariable* defFloatPlayerVar = reinterpret_cast<FloatPlayerVariable*>(defPlayerVar);
defFloatPlayerVar->SetValues(floatPlayerVar->value);
}
floatPlayerVar->SetValues(actualValue);
customFloatPlayerVar->SetValues(actualValue);
break;
}
case PlayerVarType::Bool:
{
if (!customPlayerVar)
customPlayerVar = customPlayerVars.emplace_back(std::make_unique<BoolPlayerVariable>(name)).get();
std::string valueStr = Utils::Values::to_string(value);
bool actualValue = valueStr == "true";
BoolPlayerVariable* boolPlayerVar = reinterpret_cast<BoolPlayerVariable*>(playerVar);
BoolPlayerVariable* customBoolPlayerVar = reinterpret_cast<BoolPlayerVariable*>(customPlayerVar);
if (!defPlayerVar) {
defPlayerVar = defaultPlayerVars.emplace_back(std::make_unique<BoolPlayerVariable>(name)).get();
BoolPlayerVariable* defBoolPlayerVar = reinterpret_cast<BoolPlayerVariable*>(defPlayerVar);
defBoolPlayerVar->SetValues(boolPlayerVar->value);
}
boolPlayerVar->SetValues(actualValue);
customBoolPlayerVar->SetValues(actualValue);
break;
}
default:
break;
}
} else if constexpr (std::is_same_v<T, float>) {
if (playerVar->GetType() != PlayerVarType::Float)
return;
if (!customPlayerVar)
customPlayerVar = customPlayerVars.emplace_back(std::make_unique<FloatPlayerVariable>(name)).get();
FloatPlayerVariable* floatPlayerVar = reinterpret_cast<FloatPlayerVariable*>(playerVar);
FloatPlayerVariable* customFloatPlayerVar = reinterpret_cast<FloatPlayerVariable*>(customPlayerVar);
if (!defPlayerVar) {
defPlayerVar = defaultPlayerVars.emplace_back(std::make_unique<FloatPlayerVariable>(name)).get();
FloatPlayerVariable* defFloatPlayerVar = reinterpret_cast<FloatPlayerVariable*>(defPlayerVar);
defFloatPlayerVar->SetValues(floatPlayerVar->value);
}
floatPlayerVar->SetValues(value);
customFloatPlayerVar->SetValues(value);
} else if constexpr (std::is_same_v<T, bool>) {
if (playerVar->GetType() != PlayerVarType::Bool)
return;
if (!customPlayerVar)
customPlayerVar = customPlayerVars.emplace_back(std::make_unique<BoolPlayerVariable>(name)).get();
BoolPlayerVariable* boolPlayerVar = reinterpret_cast<BoolPlayerVariable*>(playerVar);
BoolPlayerVariable* customBoolPlayerVar = reinterpret_cast<BoolPlayerVariable*>(customPlayerVar);
if (!defPlayerVar) {
defPlayerVar = defaultPlayerVars.emplace_back(std::make_unique<BoolPlayerVariable>(name)).get();
BoolPlayerVariable* defBoolPlayerVar = reinterpret_cast<BoolPlayerVariable*>(defPlayerVar);
defBoolPlayerVar->SetValues(boolPlayerVar->value);
}
boolPlayerVar->SetValues(value);
customBoolPlayerVar->SetValues(value);
}
}
template <typename T>
static void ManagePlayerVarByBool(const std::string& name, const T valueIfTrue, const T valueIfFalse, bool boolVal, bool usePreviousVal = true) {
if (!gotPlayerVars)
return;
if (prevPlayerVarValueMap.find(name) == prevPlayerVarValueMap.end())
prevPlayerVarValueMap[name] = GetPlayerVarValue<T>(name);
if (prevBoolValueMap.find(name) == prevBoolValueMap.end())
prevBoolValueMap[name] = false;
if (boolVal) {
if (!prevBoolValueMap[name])
prevPlayerVarValueMap[name] = GetPlayerVarValue<T>(name);
ChangePlayerVar(name, valueIfTrue);
prevBoolValueMap[name] = true;
} else if (prevBoolValueMap[name]) {
prevBoolValueMap[name] = false;
ChangePlayerVar(name, usePreviousVal ? std::any_cast<T>(prevPlayerVarValueMap[name]) : valueIfFalse);
prevPlayerVarValueMap.erase(name);
}
}
static bool IsPlayerVarManagedByBool(const std::string& name) {
if (!gotPlayerVars)
return false;
return prevBoolValueMap.find(name) != prevBoolValueMap.end() && prevBoolValueMap[name];
}
static void ManagePlayerVarByBool(const std::string& name, const T valueIfTrue, const T valueIfFalse, bool boolVal, bool usePreviousVal = true);
static bool IsPlayerVarManagedByBool(const std::string& name);
static PlayerVariables* Get();
};

View File

@ -4,12 +4,12 @@
namespace EGSDK::Utils {
namespace Values {
extern EGameSDK_API bool str_ends_with_ci(std::string const& text, std::string const& substr);
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_ends_with_ci(std::string const& text, std::string const& substr);
extern EGameSDK_API bool str_replace(std::string& str, const std::string& from, const std::string& to);
extern EGameSDK_API std::string to_lower(const std::string& str);
template <typename T>
auto to_string(T val) {
if constexpr (std::is_same<T, std::string>::value)
@ -18,6 +18,6 @@ namespace EGSDK::Utils {
return std::to_string(val);
}
extern EGameSDK_API std::string GetSimpleTypeName(std::string fullName);
extern EGameSDK_API std::string GetSimpleRTTITypeName(std::string fullName);
}
}

View File

@ -13,11 +13,15 @@ namespace EGSDK::GamePH {
std::unordered_map<PlayerVariable*, std::string> PlayerVariable::playerVarNames{};
std::unordered_map<PlayerVariable*, PlayerVarType> PlayerVariable::playerVarTypes{};
std::mutex PlayerVariable::mutex{};
PlayerVariable::PlayerVariable(const std::string& name) {
std::lock_guard<std::mutex> lock(mutex);
playerVarNames[this] = name;
playerVarTypes[this] = PlayerVarType::NONE;
}
const char* PlayerVariable::GetName() {
std::lock_guard<std::mutex> lock(mutex);
auto it = playerVarNames.find(this);
if (it != playerVarNames.end()) {
return it->second.c_str();
@ -25,9 +29,11 @@ namespace EGSDK::GamePH {
return nullptr;
}
void PlayerVariable::SetName(const std::string& newName) {
std::lock_guard<std::mutex> lock(mutex);
playerVarNames[this] = newName;
}
PlayerVarType PlayerVariable::GetType() {
std::lock_guard<std::mutex> lock(mutex);
auto it = playerVarTypes.find(this);
if (it != playerVarTypes.end()) {
return it->second;
@ -35,15 +41,37 @@ namespace EGSDK::GamePH {
return PlayerVarType::NONE;
}
void PlayerVariable::SetType(PlayerVarType newType) {
std::lock_guard<std::mutex> lock(mutex);
playerVarTypes[this] = newType;
}
StringPlayerVariable::StringPlayerVariable(const std::string& name) : PlayerVariable(name) {
SetType(PlayerVarType::String);
}
const char* StringPlayerVariable::GetValue() {
return reinterpret_cast<const char*>(reinterpret_cast<DWORD64>(this->value.data) & 0x1FFFFFFFFFFFFFFF);
}
const char* StringPlayerVariable::GetDefaultValue() {
return reinterpret_cast<const char*>(reinterpret_cast<DWORD64>(this->defaultValue.data) & 0x1FFFFFFFFFFFFFFF);
}
void StringPlayerVariable::SetValues(const std::string& value) {
DWORD64 firstByte = (reinterpret_cast<DWORD64>(this->value.data) >> 56) & 0xFF;
DWORD64 newValueAddr = reinterpret_cast<DWORD64>(value.c_str());
if (firstByte != 0x0)
newValueAddr |= (firstByte << 56);
this->value = reinterpret_cast<const char*>(newValueAddr);
this->defaultValue = reinterpret_cast<const char*>(newValueAddr);
}
FloatPlayerVariable::FloatPlayerVariable(const std::string& name) : PlayerVariable(name) {
SetType(PlayerVarType::Float);
}
float FloatPlayerVariable::GetValue() {
return this->value.data;
}
float FloatPlayerVariable::GetDefaultValue() {
return this->defaultValue.data;
}
void FloatPlayerVariable::SetValues(float value) {
this->value = value;
this->defaultValue = value;
@ -51,6 +79,12 @@ namespace EGSDK::GamePH {
BoolPlayerVariable::BoolPlayerVariable(const std::string& name) : PlayerVariable(name) {
SetType(PlayerVarType::Bool);
}
bool BoolPlayerVariable::GetValue() {
return this->value.data;
}
bool BoolPlayerVariable::GetDefaultValue() {
return this->defaultValue.data;
}
void BoolPlayerVariable::SetValues(bool value) {
this->value = value;
this->defaultValue = value;
@ -61,14 +95,17 @@ namespace EGSDK::GamePH {
_playerVars.emplace_back(std::move(playerVar));
return _playerVars.back();
}
auto PlayerVarVector::begin() {
std::vector<std::unique_ptr<PlayerVariable>>::iterator PlayerVarVector::begin() {
std::lock_guard<std::mutex> lock(_mutex);
return _playerVars.begin();
}
auto PlayerVarVector::end() {
std::vector<std::unique_ptr<PlayerVariable>>::iterator PlayerVarVector::end() {
std::lock_guard<std::mutex> lock(_mutex);
return _playerVars.end();
}
bool PlayerVarVector::empty() {
return _playerVars.empty();
}
bool PlayerVarVector::none_of(const std::string& name) {
std::lock_guard<std::mutex> lock(_mutex);
return std::none_of(_playerVars.begin(), _playerVars.end(), [&name](const auto& playerVar) {
@ -76,7 +113,7 @@ namespace EGSDK::GamePH {
});
}
auto PlayerVarVector::FindIter(const std::string& name) {
std::vector<std::unique_ptr<PlayerVariable>>::iterator PlayerVarVector::FindIter(const std::string& name) {
std::lock_guard<std::mutex> lock(_mutex);
auto playerVarIt = std::find_if(_playerVars.begin(), _playerVars.end(), [&name](const auto& playerVar) {
return playerVar->GetName() == name;
@ -93,7 +130,7 @@ namespace EGSDK::GamePH {
auto playerVarPtr = FindPtr(name);
return !playerVarPtr ? nullptr : playerVarPtr->get();
}
auto PlayerVarVector::Erase(const std::string& name) {
std::vector<std::unique_ptr<PlayerVariable>>::iterator PlayerVarVector::Erase(const std::string& name) {
std::lock_guard<std::mutex> lock(_mutex);
auto playerVarIt = FindIter(name);
if (playerVarIt != _playerVars.end())
@ -105,7 +142,7 @@ namespace EGSDK::GamePH {
PlayerVarVector PlayerVariables::customPlayerVars{};
PlayerVarVector PlayerVariables::defaultPlayerVars{};
PlayerVarVector PlayerVariables::customDefaultPlayerVars{};
bool PlayerVariables::gotPlayerVars = false;
std::atomic<bool> PlayerVariables::gotPlayerVars = false;
static bool sortedPlayerVars = false;
std::unordered_map<std::string, std::any> PlayerVariables::prevPlayerVarValueMap{};
@ -369,11 +406,9 @@ namespace EGSDK::GamePH {
return -404.0f;
else if constexpr (std::is_same_v<T, bool>)
return false;
else
return T();
}
template <typename T>
static T GetPlayerVarValue(const std::string& name) {
T PlayerVariables::GetPlayerVarValue(const std::string& name) {
static_assert(std::is_same_v<T, std::string> || std::is_same_v<T, float> || std::is_same_v<T, bool>, "Invalid type: value must be string, float or bool");
if (!gotPlayerVars)
@ -383,175 +418,103 @@ namespace EGSDK::GamePH {
if (!playerVar)
return getDefaultValue<T>();
if constexpr (std::is_same_v<T, std::string>) {
StringPlayerVariable* stringPlayerVar = reinterpret_cast<StringPlayerVariable*>(playerVar);
return stringPlayerVar->value.data;
} else if constexpr (std::is_same_v<T, float>) {
FloatPlayerVariable* floatPlayerVar = reinterpret_cast<FloatPlayerVariable*>(playerVar);
return floatPlayerVar->value.data;
} else if constexpr (std::is_same_v<T, bool>) {
BoolPlayerVariable* boolPlayerVar = reinterpret_cast<BoolPlayerVariable*>(playerVar);
return boolPlayerVar->value.data;
}
if constexpr (std::is_same_v<T, std::string>)
return reinterpret_cast<StringPlayerVariable*>(playerVar)->value.data;
else if constexpr (std::is_same_v<T, float>)
return reinterpret_cast<FloatPlayerVariable*>(playerVar)->value.data;
else if constexpr (std::is_same_v<T, bool>)
return reinterpret_cast<BoolPlayerVariable*>(playerVar)->value.data;
}
template <typename T>
static void ChangePlayerVar(const std::string& name, const T value) {
void PlayerVariables::ChangePlayerVar(const std::string& name, const T value, PlayerVariable* playerVar) {
static_assert(std::is_same_v<T, std::string> || std::is_same_v<T, float> || std::is_same_v<T, bool>, "Invalid type: value must be string, float or bool");
if (!gotPlayerVars)
return;
auto playerVar = playerVars.Find(name);
if (!playerVar)
playerVar = playerVars.Find(name);
if (!playerVar)
return;
if constexpr (std::is_same_v<T, std::string>) {
switch (playerVar->GetType()) {
case PlayerVarType::String:
// TO IMPLEMENT
break;
case PlayerVarType::Float:
{
std::string valueStr = Utils::Values::to_string(value);
float actualValue = std::stof(valueStr);
FloatPlayerVariable* floatPlayerVar = reinterpret_cast<FloatPlayerVariable*>(playerVar);
floatPlayerVar->SetValues(actualValue);
break;
}
case PlayerVarType::Bool:
{
std::string valueStr = Utils::Values::to_string(value);
bool actualValue = valueStr == "true";
BoolPlayerVariable* boolPlayerVar = reinterpret_cast<BoolPlayerVariable*>(playerVar);
boolPlayerVar->SetValues(actualValue);
break;
}
default:
break;
case PlayerVarType::String:
break; // TO IMPLEMENT
case PlayerVarType::Float:
ChangePlayerVar<float>(name, std::stof(Utils::Values::to_string(value)), playerVar);
break;
case PlayerVarType::Bool:
ChangePlayerVar<bool>(name, std::stof(Utils::Values::to_string(value)), playerVar);
break;
default:
break;
}
} else if constexpr (std::is_same_v<T, float>) {
if (playerVar->GetType() != PlayerVarType::Float)
return;
FloatPlayerVariable* floatPlayerVar = reinterpret_cast<FloatPlayerVariable*>(playerVar);
floatPlayerVar->SetValues(value);
if (playerVar->GetType() == PlayerVarType::Float)
reinterpret_cast<FloatPlayerVariable*>(playerVar)->SetValues(value);
} else if constexpr (std::is_same_v<T, bool>) {
if (playerVar->GetType() != PlayerVarType::Bool)
return;
BoolPlayerVariable* boolPlayerVar = reinterpret_cast<BoolPlayerVariable*>(playerVar);
boolPlayerVar->SetValues(value);
if (playerVar->GetType() == PlayerVarType::Bool)
reinterpret_cast<BoolPlayerVariable*>(playerVar)->SetValues(value);
}
}
template <typename T>
static void ChangePlayerVarFromList(const std::string& name, const T value, PlayerVariable* playerVar = nullptr) {
void PlayerVariables::ChangePlayerVarFromList(const std::string& name, const T value, PlayerVariable* playerVar) {
static_assert(std::is_same_v<T, std::string> || std::is_same_v<T, float> || std::is_same_v<T, bool>, "Invalid type: value must be string, float or bool");
if (!gotPlayerVars)
return;
if (!playerVar) {
if (!playerVar)
playerVar = playerVars.Find(name);
if (!playerVar)
return;
}
if (!playerVar)
return;
auto customPlayerVar = customPlayerVars.Find(name);
auto defPlayerVar = defaultPlayerVars.Find(name);
if constexpr (std::is_same_v<T, std::string>) {
switch (playerVar->GetType()) {
case PlayerVarType::String:
// TO IMPLEMENT
break;
case PlayerVarType::Float:
{
if (!customPlayerVar)
customPlayerVar = customPlayerVars.emplace_back(std::make_unique<FloatPlayerVariable>(name)).get();
std::string valueStr = Utils::Values::to_string(value);
float actualValue = std::stof(valueStr);
FloatPlayerVariable* floatPlayerVar = reinterpret_cast<FloatPlayerVariable*>(playerVar);
FloatPlayerVariable* customFloatPlayerVar = reinterpret_cast<FloatPlayerVariable*>(customPlayerVar);
if (!defPlayerVar) {
defPlayerVar = defaultPlayerVars.emplace_back(std::make_unique<FloatPlayerVariable>(name)).get();
FloatPlayerVariable* defFloatPlayerVar = reinterpret_cast<FloatPlayerVariable*>(defPlayerVar);
defFloatPlayerVar->SetValues(floatPlayerVar->value);
}
floatPlayerVar->SetValues(actualValue);
customFloatPlayerVar->SetValues(actualValue);
break;
}
case PlayerVarType::Bool:
{
if (!customPlayerVar)
customPlayerVar = customPlayerVars.emplace_back(std::make_unique<BoolPlayerVariable>(name)).get();
std::string valueStr = Utils::Values::to_string(value);
bool actualValue = valueStr == "true";
BoolPlayerVariable* boolPlayerVar = reinterpret_cast<BoolPlayerVariable*>(playerVar);
BoolPlayerVariable* customBoolPlayerVar = reinterpret_cast<BoolPlayerVariable*>(customPlayerVar);
if (!defPlayerVar) {
defPlayerVar = defaultPlayerVars.emplace_back(std::make_unique<BoolPlayerVariable>(name)).get();
BoolPlayerVariable* defBoolPlayerVar = reinterpret_cast<BoolPlayerVariable*>(defPlayerVar);
defBoolPlayerVar->SetValues(boolPlayerVar->value);
}
boolPlayerVar->SetValues(actualValue);
customBoolPlayerVar->SetValues(actualValue);
break;
}
default:
break;
case PlayerVarType::String:
break; // TO IMPLEMENT
case PlayerVarType::Float:
ChangePlayerVarFromList<float>(name, std::stof(Utils::Values::to_string(value)), playerVar);
break;
case PlayerVarType::Bool:
ChangePlayerVarFromList<bool>(name, std::stof(Utils::Values::to_string(value)), playerVar);
break;
default:
break;
}
} else if constexpr (std::is_same_v<T, float>) {
if (playerVar->GetType() != PlayerVarType::Float)
return;
if (!customPlayerVar)
customPlayerVar = customPlayerVars.emplace_back(std::make_unique<FloatPlayerVariable>(name)).get();
FloatPlayerVariable* floatPlayerVar = reinterpret_cast<FloatPlayerVariable*>(playerVar);
FloatPlayerVariable* customFloatPlayerVar = reinterpret_cast<FloatPlayerVariable*>(customPlayerVar);
if (!defPlayerVar) {
defPlayerVar = defaultPlayerVars.emplace_back(std::make_unique<FloatPlayerVariable>(name)).get();
FloatPlayerVariable* defFloatPlayerVar = reinterpret_cast<FloatPlayerVariable*>(defPlayerVar);
defFloatPlayerVar->SetValues(floatPlayerVar->value);
reinterpret_cast<FloatPlayerVariable*>(defPlayerVar)->SetValues(reinterpret_cast<FloatPlayerVariable*>(playerVar)->value);
}
floatPlayerVar->SetValues(value);
customFloatPlayerVar->SetValues(value);
reinterpret_cast<FloatPlayerVariable*>(playerVar)->SetValues(value);
reinterpret_cast<FloatPlayerVariable*>(customPlayerVar)->SetValues(value);
} else if constexpr (std::is_same_v<T, bool>) {
if (playerVar->GetType() != PlayerVarType::Bool)
return;
if (!customPlayerVar)
customPlayerVar = customPlayerVars.emplace_back(std::make_unique<BoolPlayerVariable>(name)).get();
BoolPlayerVariable* boolPlayerVar = reinterpret_cast<BoolPlayerVariable*>(playerVar);
BoolPlayerVariable* customBoolPlayerVar = reinterpret_cast<BoolPlayerVariable*>(customPlayerVar);
if (!defPlayerVar) {
defPlayerVar = defaultPlayerVars.emplace_back(std::make_unique<BoolPlayerVariable>(name)).get();
BoolPlayerVariable* defBoolPlayerVar = reinterpret_cast<BoolPlayerVariable*>(defPlayerVar);
defBoolPlayerVar->SetValues(boolPlayerVar->value);
reinterpret_cast<BoolPlayerVariable*>(defPlayerVar)->SetValues(reinterpret_cast<BoolPlayerVariable*>(playerVar)->value);
}
boolPlayerVar->SetValues(value);
customBoolPlayerVar->SetValues(value);
reinterpret_cast<BoolPlayerVariable*>(playerVar)->SetValues(value);
reinterpret_cast<BoolPlayerVariable*>(customPlayerVar)->SetValues(value);
}
}
template <typename T>
static void ManagePlayerVarByBool(const std::string& name, const T valueIfTrue, const T valueIfFalse, bool boolVal, bool usePreviousVal = true) {
void PlayerVariables::ManagePlayerVarByBool(const std::string& name, const T valueIfTrue, const T valueIfFalse, bool boolVal, bool usePreviousVal) {
if (!gotPlayerVars)
return;
@ -572,13 +535,27 @@ namespace EGSDK::GamePH {
prevPlayerVarValueMap.erase(name);
}
}
static bool IsPlayerVarManagedByBool(const std::string& name) {
bool PlayerVariables::IsPlayerVarManagedByBool(const std::string& name) {
if (!gotPlayerVars)
return false;
return prevBoolValueMap.find(name) != prevBoolValueMap.end() && prevBoolValueMap[name];
}
template EGameSDK_API std::string PlayerVariables::GetPlayerVarValue<std::string>(const std::string& name);
template EGameSDK_API float PlayerVariables::GetPlayerVarValue<float>(const std::string& name);
template EGameSDK_API bool PlayerVariables::GetPlayerVarValue<bool>(const std::string& name);
template EGameSDK_API void PlayerVariables::ChangePlayerVar<std::string>(const std::string& name, const std::string value, PlayerVariable* playerVar);
template EGameSDK_API void PlayerVariables::ChangePlayerVar<float>(const std::string& name, const float value, PlayerVariable* playerVar);
template EGameSDK_API void PlayerVariables::ChangePlayerVar<bool>(const std::string& name, const bool value, PlayerVariable* playerVar);
template EGameSDK_API void PlayerVariables::ChangePlayerVarFromList<std::string>(const std::string& name, const std::string value, PlayerVariable* playerVar);
template EGameSDK_API void PlayerVariables::ChangePlayerVarFromList<float>(const std::string& name, const float value, PlayerVariable* playerVar);
template EGameSDK_API void PlayerVariables::ChangePlayerVarFromList<bool>(const std::string& name, const bool value, PlayerVariable* playerVar);
template EGameSDK_API void PlayerVariables::ManagePlayerVarByBool(const std::string& name, const std::string valueIfTrue, const std::string valueIfFalse, bool boolVal, bool usePreviousVal);
template EGameSDK_API void PlayerVariables::ManagePlayerVarByBool<float>(const std::string& name, const float valueIfTrue, const float valueIfFalse, bool boolVal, bool usePreviousVal);
template EGameSDK_API void PlayerVariables::ManagePlayerVarByBool<bool>(const std::string& name, const bool valueIfTrue, const bool valueIfFalse, bool boolVal, bool usePreviousVal);
static PlayerVariables* GetOffset_PlayerVariables() {
PlayerState* playerState = PlayerState::Get();
return playerState ? playerState->playerVariables : nullptr;

View File

@ -7,19 +7,9 @@
namespace EGSDK::Utils {
namespace Values {
bool str_ends_with_ci(const std::string& text, const std::string& substr) {
if (substr.length() > text.length())
return false;
return std::equal(substr.rbegin(), substr.rend(), text.rbegin(), [](char ch1, char ch2) {
return std::toupper(ch1) == std::toupper(ch2);
});
}
__forceinline bool are_samef(float a, float b, float precision) {
return std::fabs(a - b) < precision;
}
float round_decimal(float value, int decimal_places) {
float multiplier = 1.0f;
for (int i = 0; i < decimal_places; ++i)
@ -28,6 +18,14 @@ namespace EGSDK::Utils {
return std::round(value * multiplier) / multiplier;
}
bool str_ends_with_ci(const std::string& text, const std::string& substr) {
if (substr.length() > text.length())
return false;
return std::equal(substr.rbegin(), substr.rend(), text.rbegin(), [](char ch1, char ch2) {
return std::toupper(ch1) == std::toupper(ch2);
});
}
bool str_replace(std::string& str, const std::string& from, const std::string& to) {
size_t start_pos = str.find(from);
if (start_pos == std::string::npos)
@ -36,8 +34,13 @@ namespace EGSDK::Utils {
str.replace(start_pos, from.length(), to);
return true;
}
std::string to_lower(const std::string& str) {
std::string lowerStr = str;
std::transform(lowerStr.begin(), lowerStr.end(), lowerStr.begin(), tolower);
return lowerStr;
}
std::string GetSimpleTypeName(std::string fullName) {
std::string GetSimpleRTTITypeName(std::string fullName) {
static const std::string class_prefix = "class ";
static const std::string struct_prefix = "struct ";
static const std::string enum_prefix = "enum ";

View File

@ -161,7 +161,7 @@ namespace EGT::Menu {
EGSDK::GamePH::ShowTPPModel(false);
}
}
static void UpdatePlayerVars() {
static void PlayerVarsUpdate() {
if (!EGSDK::GamePH::PlayerVariables::gotPlayerVars)
return;
@ -205,7 +205,7 @@ namespace EGT::Menu {
UpdateFOV();
FreeCamUpdate();
UpdateTPPModel();
UpdatePlayerVars();
PlayerVarsUpdate();
UpdateDisabledOptions();
HandleToggles();
}

View File

@ -48,7 +48,8 @@ namespace EGT::Menu {
static bool restoreVarsToSavedVarsEnabled = false;
static char playerVarsSearchFilter[64];
static std::string getParamName(const std::string &str) {
#pragma region Player Variables
static std::string getParamName(const std::string& str) {
size_t firstQuotePos = str.find_first_of("\"");
if (firstQuotePos == std::string::npos)
return {};
@ -57,8 +58,8 @@ namespace EGT::Menu {
return {};
return str.substr(firstQuotePos + 1, lastQuotePos - firstQuotePos - 1);
}
static std::string getParamValue(const std::string &str) {
}
static std::string getParamValue(const std::string& str) {
size_t firstQuotePos = str.find_first_of("\"");
if (firstQuotePos == std::string::npos)
return {};
@ -74,44 +75,15 @@ namespace EGT::Menu {
return str.substr(thirdQuotePos + 1, lastQuotePos - thirdQuotePos - 1);
}
static void replaceParamValue(std::string& str, const std::string& newValue) {
static void replaceParamValue(std::string& str, const std::string& newValue) {
const std::string value = getParamValue(str);
if (value.empty())
return;
EGSDK::Utils::Values::str_replace(str, value, newValue);
}
static void PlayerPositionUpdate() {
EGSDK::Engine::CBulletPhysicsCharacter* playerCharacter = EGSDK::Engine::CBulletPhysicsCharacter::Get();
if (!playerCharacter)
return;
EGSDK::GamePH::LevelDI* iLevel = EGSDK::GamePH::LevelDI::Get();
if (!iLevel)
return;
if ((freezePlayer.GetValue() || (Camera::freeCam.GetValue() && !Camera::teleportPlayerToCamera.GetValue())) && !iLevel->IsTimerFrozen()) {
playerCharacter->FreezeCharacter();
return;
}
EGSDK::Engine::CBulletPhysicsCharacter::posBeforeFreeze = playerCharacter->playerPos;
if (iLevel->IsTimerFrozen() || !Camera::freeCam.GetValue() || !Camera::teleportPlayerToCamera.GetValue())
return;
EGSDK::GamePH::FreeCamera* freeCam = EGSDK::GamePH::FreeCamera::Get();
if (!freeCam)
return;
EGSDK::Vector3 camPos{};
freeCam->GetPosition(&camPos);
if (camPos.isDefault())
return;
playerCharacter->MoveCharacter(camPos);
}
static void PlayerVarsUpdate() {
static void PlayerVarListValuesUpdate() {
if (!playerVariables.GetValue())
return;
@ -120,89 +92,39 @@ namespace EGT::Menu {
continue;
switch (customPlayerVar->GetType()) {
case EGSDK::GamePH::PlayerVarType::String:
// TO IMPLEMENT
break;
case EGSDK::GamePH::PlayerVarType::Float:
{
EGSDK::GamePH::FloatPlayerVariable* customFloatPlayerVar = reinterpret_cast<EGSDK::GamePH::FloatPlayerVariable*>(customPlayerVar.get());
EGSDK::GamePH::PlayerVariables::ChangePlayerVar(customFloatPlayerVar->GetName(), customFloatPlayerVar->value.data);
break;
}
case EGSDK::GamePH::PlayerVarType::Bool:
{
EGSDK::GamePH::BoolPlayerVariable* customBoolPlayerVar = reinterpret_cast<EGSDK::GamePH::BoolPlayerVariable*>(customPlayerVar.get());
EGSDK::GamePH::PlayerVariables::ChangePlayerVar(customBoolPlayerVar->GetName(), customBoolPlayerVar->value.data);
break;
}
default:
break;
case EGSDK::GamePH::PlayerVarType::String:
break; // TO IMPLEMENT
case EGSDK::GamePH::PlayerVarType::Float:
EGSDK::GamePH::PlayerVariables::ChangePlayerVar(customPlayerVar->GetName(), reinterpret_cast<EGSDK::GamePH::FloatPlayerVariable*>(customPlayerVar.get())->value.data);
break;
case EGSDK::GamePH::PlayerVarType::Bool:
EGSDK::GamePH::PlayerVariables::ChangePlayerVar(customPlayerVar->GetName(), reinterpret_cast<EGSDK::GamePH::BoolPlayerVariable*>(customPlayerVar.get())->value.data);
break;
default:
break;
}
}
}
static void PlayerHealthUpdate() {
EGSDK::GamePH::PlayerHealthModule* playerHealthModule = EGSDK::GamePH::PlayerHealthModule::Get();
if (!playerHealthModule)
return;
playerMaxHealth = playerHealthModule->maxHealth;
if (menuToggle.GetValue())
return;
EGSDK::GamePH::LevelDI* iLevel = EGSDK::GamePH::LevelDI::Get();
if (!iLevel || !iLevel->IsLoaded())
return;
playerHealth = playerHealthModule->health;
}
static void PlayerImmunityUpdate() {
EGSDK::GamePH::PlayerInfectionModule* playerInfectionModule = EGSDK::GamePH::PlayerInfectionModule::Get();
if (!playerInfectionModule)
return;
playerMaxImmunity = playerInfectionModule->maxImmunity * 100.0f;
if (menuToggle.GetValue())
return;
EGSDK::GamePH::LevelDI* iLevel = EGSDK::GamePH::LevelDI::Get();
if (!iLevel || !iLevel->IsLoaded())
return;
playerImmunity = playerInfectionModule->immunity * 100.0f;
}
static void UpdatePlayerVars() {
static void PlayerVarsUpdate() {
if (!EGSDK::GamePH::PlayerVariables::gotPlayerVars)
return;
EGSDK::GamePH::PlayerVariables::ManagePlayerVarByBool("NightRunnerItemForced", true, false, nightrunnerMode.GetValue());
EGSDK::GamePH::PlayerVariables::ManagePlayerVarByBool("NightRunnerFurySmashEnabled", true, false, nightrunnerMode.GetValue());
EGSDK::GamePH::PlayerVariables::ManagePlayerVarByBool("NightRunnerFuryGroundPoundEnabled", true, false, nightrunnerMode.GetValue());
EGSDK::GamePH::PlayerVariables::ManagePlayerVarByBool("AntizinDrainBlocked", true, false, unlimitedImmunity.GetValue());
EGSDK::GamePH::PlayerVariables::ManagePlayerVarByBool("InfiniteStamina", true, false, unlimitedStamina.GetValue());
EGSDK::GamePH::PlayerVariables::ManagePlayerVarByBool("UvFlashlightEnergyDrainFactor", 0.0f, 1.0f, unlimitedItems.GetValue());
EGSDK::GamePH::PlayerVariables::ManagePlayerVarByBool("DamageMulAll", 99999.0f, 0.0f, oneHitKill.GetValue(), true);
EGSDK::GamePH::PlayerVariables::ManagePlayerVarByBool("InVisibleToEnemies", true, false, invisibleToEnemies.GetValue());
EGSDK::GamePH::PlayerVariables::ManagePlayerVarByBool("LeftHandDisabled", true, false, oneHandedMode.GetValue());
}
static void UpdateDisabledOptions() {
freezePlayer.SetChangesAreDisabled(!EGSDK::Engine::CBulletPhysicsCharacter::Get());
}
static void HandleToggles() {
if (disableAirControl.HasChanged()) {
disableAirControl.SetPrevValue(disableAirControl.GetValue());
EGSDK::GamePH::ReloadJumps();
}
}
static void SaveVariablesToSCR() {
if (!std::filesystem::exists(saveSCRPath))
if (!std::filesystem::exists(saveSCRPath)) {
ImGui::OpenPopup("Failed saving player variables.");
return;
}
std::string tempPlayerVarsSCR = g_PlayerVariablesSCRFile;
@ -219,38 +141,34 @@ namespace EGT::Menu {
continue;
switch (playerVar->GetType()) {
case EGSDK::GamePH::PlayerVarType::String:
// TO IMPLEMENT
break;
case EGSDK::GamePH::PlayerVarType::Float: {
EGSDK::GamePH::FloatPlayerVariable* floatPlayerVar = reinterpret_cast<EGSDK::GamePH::FloatPlayerVariable*>(playerVar);
replaceParamValue(line, std::to_string(floatPlayerVar->value));
break;
}
case EGSDK::GamePH::PlayerVarType::Bool: {
EGSDK::GamePH::BoolPlayerVariable* boolPlayerVar = reinterpret_cast<EGSDK::GamePH::BoolPlayerVariable*>(playerVar);
replaceParamValue(line, boolPlayerVar ? "true" : "false");
break;
}
default:
break;
case EGSDK::GamePH::PlayerVarType::String:
break; // TO IMPLEMENT
case EGSDK::GamePH::PlayerVarType::Float:
replaceParamValue(line, std::to_string(reinterpret_cast<EGSDK::GamePH::FloatPlayerVariable*>(playerVar)->value));
break;
case EGSDK::GamePH::PlayerVarType::Bool:
replaceParamValue(line, reinterpret_cast<EGSDK::GamePH::BoolPlayerVariable*>(playerVar) ? "true" : "false");
break;
default:
break;
}
EGSDK::Utils::Values::str_replace(tempPlayerVarsSCR, origLine, line);
}
std::ofstream outFile(std::string(saveSCRPath) + "\\player_variables.scr", std::ios::binary);
std::ofstream outFile(saveSCRPath + "\\player_variables.scr", std::ios::binary);
if (!outFile.is_open()) {
ImGui::OpenPopup("Failed saving player variables.");
return;
}
outFile << tempPlayerVarsSCR;
outFile.close();
ImGui::OpenPopup("Saved player variables!");
}
static void LoadPlayerVariablesSCR() {
if (!std::filesystem::exists(loadSCRFilePath))
if (!std::filesystem::exists(loadSCRFilePath)) {
ImGui::OpenPopup("Failed loading player variables.");
return;
}
std::ifstream file(loadSCRFilePath);
if (!file.is_open()) {
@ -270,74 +188,9 @@ namespace EGT::Menu {
EGSDK::GamePH::PlayerVariables::ChangePlayerVar(name, value);
}
file.close();
ImGui::OpenPopup("Loaded player variables!");
}
static void RestoreVariablesToDefault() {
for (auto const& playerVarPtr : EGSDK::GamePH::PlayerVariables::playerVars) {
auto playerVar = playerVarPtr.get();
auto& defVars = restoreVarsToSavedVarsEnabled ? EGSDK::GamePH::PlayerVariables::customDefaultPlayerVars : EGSDK::GamePH::PlayerVariables::defaultPlayerVars;
auto defPlayerVar = defVars.Find(playerVar->GetName());
if (!defPlayerVar)
continue;
switch (playerVar->GetType()) {
case EGSDK::GamePH::PlayerVarType::String:
// TO IMPLEMENT
break;
case EGSDK::GamePH::PlayerVarType::Float: {
EGSDK::GamePH::FloatPlayerVariable* defFloatPlayerVar = reinterpret_cast<EGSDK::GamePH::FloatPlayerVariable*>(defPlayerVar);
EGSDK::GamePH::PlayerVariables::ChangePlayerVar(playerVar->GetName(), defFloatPlayerVar->value.data);
break;
}
case EGSDK::GamePH::PlayerVarType::Bool: {
EGSDK::GamePH::BoolPlayerVariable* defBoolPlayerVar = reinterpret_cast<EGSDK::GamePH::BoolPlayerVariable*>(defPlayerVar);
EGSDK::GamePH::PlayerVariables::ChangePlayerVar(playerVar->GetName(), defBoolPlayerVar->value.data);
break;
}
default:
break;
}
if (!restoreVarsToSavedVarsEnabled)
defVars.Erase(playerVar->GetName());
}
ImGui::OpenPopup("Restored player variables!");
}
static void SaveVariablesAsDefault() {
for (auto const& playerVarPtr : EGSDK::GamePH::PlayerVariables::playerVars) {
auto playerVar = playerVarPtr.get();
auto defCustomPlayerVar = EGSDK::GamePH::PlayerVariables::customDefaultPlayerVars.Find(playerVar->GetName());
if (!defCustomPlayerVar)
continue;
switch (playerVar->GetType()) {
case EGSDK::GamePH::PlayerVarType::String:
// TO IMPLEMENT
break;
case EGSDK::GamePH::PlayerVarType::Float: {
EGSDK::GamePH::FloatPlayerVariable* floatPlayerVar = reinterpret_cast<EGSDK::GamePH::FloatPlayerVariable*>(playerVar);
EGSDK::GamePH::FloatPlayerVariable* defCustomFloatPlayerVar = reinterpret_cast<EGSDK::GamePH::FloatPlayerVariable*>(defCustomPlayerVar);
defCustomFloatPlayerVar->value = floatPlayerVar->value;
break;
}
case EGSDK::GamePH::PlayerVarType::Bool: {
EGSDK::GamePH::BoolPlayerVariable* boolPlayerVar = reinterpret_cast<EGSDK::GamePH::BoolPlayerVariable*>(playerVar);
EGSDK::GamePH::BoolPlayerVariable* defCustomBoolPlayerVar = reinterpret_cast<EGSDK::GamePH::BoolPlayerVariable*>(defCustomPlayerVar);
defCustomBoolPlayerVar->value = boolPlayerVar->value;
break;
}
default:
break;
}
}
ImGui::OpenPopup("Saved current player variables!");
}
static void RestoreVariableToDefault(const std::string& name) {
auto& defVars = restoreVarsToSavedVarsEnabled ? EGSDK::GamePH::PlayerVariables::customDefaultPlayerVars : EGSDK::GamePH::PlayerVariables::defaultPlayerVars;
auto defPlayerVar = defVars.Find(name);
@ -345,53 +198,68 @@ namespace EGT::Menu {
return;
switch (defPlayerVar->GetType()) {
case EGSDK::GamePH::PlayerVarType::String:
// TO IMPLEMENT
break;
case EGSDK::GamePH::PlayerVarType::Float: {
EGSDK::GamePH::FloatPlayerVariable* defFloatPlayerVar = reinterpret_cast<EGSDK::GamePH::FloatPlayerVariable*>(defPlayerVar);
EGSDK::GamePH::PlayerVariables::ChangePlayerVar(name, defFloatPlayerVar->value.data);
break;
}
case EGSDK::GamePH::PlayerVarType::Bool: {
EGSDK::GamePH::BoolPlayerVariable* defBoolPlayerVar = reinterpret_cast<EGSDK::GamePH::BoolPlayerVariable*>(defPlayerVar);
EGSDK::GamePH::PlayerVariables::ChangePlayerVar(name, defBoolPlayerVar->value.data);
break;
}
default:
break;
case EGSDK::GamePH::PlayerVarType::String:
break; // TO IMPLEMENT
case EGSDK::GamePH::PlayerVarType::Float:
EGSDK::GamePH::PlayerVariables::ChangePlayerVar(name, reinterpret_cast<EGSDK::GamePH::FloatPlayerVariable*>(defPlayerVar)->value.data);
break;
case EGSDK::GamePH::PlayerVarType::Bool:
EGSDK::GamePH::PlayerVariables::ChangePlayerVar(name, reinterpret_cast<EGSDK::GamePH::BoolPlayerVariable*>(defPlayerVar)->value.data);
break;
default:
break;
}
if (!restoreVarsToSavedVarsEnabled) {
defVars.Erase(name);
auto customPlayerVar = EGSDK::GamePH::PlayerVariables::customPlayerVars.Find(name);
if (!customPlayerVar)
return;
EGSDK::GamePH::PlayerVariables::customPlayerVars.Erase(name);
if (customPlayerVar)
EGSDK::GamePH::PlayerVariables::customPlayerVars.Erase(name);
}
}
static void RestoreVariablesToDefault() {
for (const auto& playerVarPtr : (restoreVarsToSavedVarsEnabled ? EGSDK::GamePH::PlayerVariables::playerVars : EGSDK::GamePH::PlayerVariables::customPlayerVars))
RestoreVariableToDefault(playerVarPtr->GetName());
ImGui::OpenPopup("Restored player variables!");
}
static void SaveVariablesAsDefault() {
for (auto const& playerVarPtr : EGSDK::GamePH::PlayerVariables::playerVars) {
auto playerVar = playerVarPtr.get();
auto defCustomPlayerVar = EGSDK::GamePH::PlayerVariables::customDefaultPlayerVars.Find(playerVar->GetName());
if (!defCustomPlayerVar)
continue;
static bool shouldDisplayVariable(const std::unique_ptr<EGSDK::GamePH::PlayerVariable>& playerVarPtr, const std::string& searchFilter) {
switch (playerVar->GetType()) {
case EGSDK::GamePH::PlayerVarType::String:
break; // TO IMPLEMENT
case EGSDK::GamePH::PlayerVarType::Float:
reinterpret_cast<EGSDK::GamePH::FloatPlayerVariable*>(defCustomPlayerVar)->value = reinterpret_cast<EGSDK::GamePH::FloatPlayerVariable*>(playerVar)->value;
break;
case EGSDK::GamePH::PlayerVarType::Bool:
reinterpret_cast<EGSDK::GamePH::BoolPlayerVariable*>(defCustomPlayerVar)->value = reinterpret_cast<EGSDK::GamePH::BoolPlayerVariable*>(playerVar)->value;
break;
default:
break;
}
}
ImGui::OpenPopup("Saved current player variables!");
}
static bool ShouldDisplayVariable(const std::unique_ptr<EGSDK::GamePH::PlayerVariable>& playerVarPtr, const std::string& searchFilter) {
if (playerVarPtr->GetType() == EGSDK::GamePH::PlayerVarType::String || playerVarPtr->GetType() == EGSDK::GamePH::PlayerVarType::NONE) // TO IMPLEMENT
return false;
if (searchFilter.empty())
return true;
// Convert searchFilter to lowercase
std::string lowerFilter = searchFilter;
std::transform(lowerFilter.begin(), lowerFilter.end(), lowerFilter.begin(), ::tolower);
// Convert variable name to lowercase and check if it contains the filter
std::string lowerKey = playerVarPtr->GetName();
std::transform(lowerKey.begin(), lowerKey.end(), lowerKey.begin(), ::tolower);
// Convert searchFilter and variable name to lowercase
std::string lowerFilter = EGSDK::Utils::Values::to_lower(searchFilter);
std::string lowerKey = EGSDK::Utils::Values::to_lower(playerVarPtr->GetName());
return lowerKey.find(lowerFilter) != std::string::npos;
}
static void renderDebugInfo(const std::unique_ptr<EGSDK::GamePH::PlayerVariable>& playerVarPtr) {
static void RenderDebugInfo(const std::unique_ptr<EGSDK::GamePH::PlayerVariable>& playerVarPtr) {
const float maxInputTextWidth = ImGui::CalcTextSize("0x0000000000000000").x;
static std::string labelID{};
labelID = "##DebugAddrInputText" + std::string(playerVarPtr->GetName());
DWORD64 finalVarValueAddr = reinterpret_cast<DWORD64>(playerVarPtr.get()) + 0x8;
std::string labelID = "##DebugAddrInputText" + std::string(playerVarPtr->GetName());
DWORD64 finalVarValueAddr = reinterpret_cast<DWORD64>(playerVarPtr.get()) + 0x8; // 0x8 is PlayerVariable->value
std::stringstream ss;
if (finalVarValueAddr)
@ -399,47 +267,44 @@ namespace EGT::Menu {
else
ss << "NULL";
static std::string addrString{};
addrString = ss.str();
std::string addrString = ss.str();
ImGui::SameLine();
//ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ((ImGui::GetFrameHeight() - ImGui::GetTextLineHeight()) / 2.0f));
ImGui::SetNextItemWidth(maxInputTextWidth);
ImGui::PushStyleColor(ImGuiCol_Text, finalVarValueAddr ? IM_COL32(0, 255, 0, 255) : IM_COL32(255, 0, 0, 255));
ImGui::InputText(labelID.c_str(), const_cast<char*>(addrString.c_str()), strlen(addrString.c_str()), ImGuiInputTextFlags_ReadOnly);
ImGui::PopStyleColor();
}
static void renderPlayerVariable(const std::unique_ptr<EGSDK::GamePH::PlayerVariable>& playerVarPtr) {
static void RenderPlayerVariable(const std::unique_ptr<EGSDK::GamePH::PlayerVariable>& playerVarPtr) {
auto playerVar = playerVarPtr.get();
ImGui::BeginDisabled(EGSDK::GamePH::PlayerVariables::IsPlayerVarManagedByBool(playerVarPtr->GetName()));
{
switch (playerVarPtr->GetType()) {
case EGSDK::GamePH::PlayerVarType::String:
// TO IMPLEMENT
break;
case EGSDK::GamePH::PlayerVarType::Float: {
EGSDK::GamePH::FloatPlayerVariable* floatPlayerVar = reinterpret_cast<EGSDK::GamePH::FloatPlayerVariable*>(playerVarPtr.get());
float newValue = floatPlayerVar->value;
if (ImGui::InputFloat(floatPlayerVar->GetName(), &newValue))
EGSDK::GamePH::PlayerVariables::ChangePlayerVarFromList(floatPlayerVar->GetName(), newValue, playerVarPtr.get());
break;
}
case EGSDK::GamePH::PlayerVarType::Bool: {
EGSDK::GamePH::BoolPlayerVariable* boolPlayerVar = reinterpret_cast<EGSDK::GamePH::BoolPlayerVariable*>(playerVarPtr.get());
bool newValue = boolPlayerVar->value;
if (ImGui::Checkbox(boolPlayerVar->GetName(), &newValue))
EGSDK::GamePH::PlayerVariables::ChangePlayerVarFromList(boolPlayerVar->GetName(), newValue, playerVarPtr.get());
break;
}
default:
break;
case EGSDK::GamePH::PlayerVarType::String:
break; // TO IMPLEMENT
case EGSDK::GamePH::PlayerVarType::Float:
{
float newValue = reinterpret_cast<EGSDK::GamePH::FloatPlayerVariable*>(playerVar)->value;
if (ImGui::InputFloat(playerVar->GetName(), &newValue))
EGSDK::GamePH::PlayerVariables::ChangePlayerVarFromList(playerVar->GetName(), newValue, playerVar);
break;
}
case EGSDK::GamePH::PlayerVarType::Bool:
{
bool newValue = reinterpret_cast<EGSDK::GamePH::BoolPlayerVariable*>(playerVar)->value;
if (ImGui::Checkbox(playerVar->GetName(), &newValue))
EGSDK::GamePH::PlayerVariables::ChangePlayerVarFromList(playerVar->GetName(), newValue, playerVar);
break;
}
default:
break;
}
ImGui::EndDisabled();
}
ImGui::SameLine();
static std::string restoreBtnName{};
restoreBtnName = "Restore##" + std::string(playerVarPtr->GetName());
std::string restoreBtnName = "Restore##" + std::string(playerVarPtr->GetName());
ImGui::BeginDisabled(EGSDK::GamePH::PlayerVariables::customPlayerVars.none_of(playerVarPtr->GetName()) || EGSDK::GamePH::PlayerVariables::IsPlayerVarManagedByBool(playerVarPtr->GetName()));
{
@ -449,54 +314,65 @@ namespace EGT::Menu {
}
if (debugEnabled)
renderDebugInfo(playerVarPtr);
RenderDebugInfo(playerVarPtr);
}
static void HandlePlayerVariablesList() {
if (!playerVariables.GetValue())
return;
ImGui::BeginDisabled(!EGSDK::GamePH::PlayerVariables::gotPlayerVars); {
if (ImGui::CollapsingHeader("Player variables list", ImGuiTreeNodeFlags_None)) {
ImGui::Indent();
ImGui::BeginDisabled(!EGSDK::GamePH::PlayerVariables::gotPlayerVars);
if (ImGui::CollapsingHeader("Player Variables list", ImGuiTreeNodeFlags_None)) {
ImGui::Indent();
if (ImGui::Button("Save variables to file", "Saves current player variables to chosen file inside the file dialog"))
ImGuiFileDialog::Instance()->OpenDialog("ChooseSCRPath", "Choose Folder", nullptr, { saveSCRPath.empty() ? "." : saveSCRPath });
ImGui::SameLine();
if (ImGui::Button("Load variables from file", "Loads player variables from chosen file inside the file dialog"))
ImGuiFileDialog::Instance()->OpenDialog("ChooseSCRLoadPath", "Choose File", ".scr", { loadSCRFilePath.empty() ? "." : loadSCRFilePath });
if (ImGui::Button("Save variables to file", "Saves current player variables to chosen file inside the file dialog"))
ImGuiFileDialog::Instance()->OpenDialog("ChooseSCRPath", "Choose Folder", nullptr, { saveSCRPath.empty() ? "." : saveSCRPath });
ImGui::SameLine();
if (ImGui::Button("Load variables from file", "Loads player variables from chosen file inside the file dialog"))
ImGuiFileDialog::Instance()->OpenDialog("ChooseSCRLoadPath", "Choose File", ".scr", { loadSCRFilePath.empty() ? "." : loadSCRFilePath });
ImGui::Checkbox("Restore variables to saved variables", &restoreVarsToSavedVarsEnabled, "Sets whether or not \"Restore variables to default\" should restore variables to the ones saved by \"Save current variables as default\"");
ImGui::Checkbox("Debug Mode", &debugEnabled, "Shows text boxes alongside player variables, which will show the address in memory of each variable");
ImGui::Checkbox("Restore variables to saved variables", &restoreVarsToSavedVarsEnabled, "Sets whether or not \"Restore variables to default\" should restore variables to the ones saved by \"Save current variables as default\"");
ImGui::Checkbox("Debug Mode", &debugEnabled, "Shows text boxes alongside player variables, which will show the address in memory of each variable");
if (ImGui::Button("Restore variables to default"))
RestoreVariablesToDefault();
ImGui::SameLine();
if (ImGui::Button("Save current variables as default", "Saves the current player variables as default for whenever you use \"Restore variables to default\""))
SaveVariablesAsDefault();
ImGui::Separator();
ImGui::InputTextWithHint("##VarsSearch", "Search variables", playerVarsSearchFilter, 64);
for (auto const& playerVarPtr : EGSDK::GamePH::PlayerVariables::playerVars) {
if (!shouldDisplayVariable(playerVarPtr, playerVarsSearchFilter))
continue;
renderPlayerVariable(playerVarPtr);
}
ImGui::Unindent();
}
ImGui::BeginDisabled(EGSDK::GamePH::PlayerVariables::customPlayerVars.empty());
if (ImGui::Button("Restore variables to default"))
RestoreVariablesToDefault();
ImGui::EndDisabled();
ImGui::SameLine();
if (ImGui::Button("Save current variables as default", "Saves the current player variables as default for whenever you use \"Restore variables to default\""))
SaveVariablesAsDefault();
ImGui::Separator();
ImGui::InputTextWithHint("##VarsSearch", "Search variables", playerVarsSearchFilter, 64);
for (auto const& playerVarPtr : EGSDK::GamePH::PlayerVariables::playerVars) {
if (ShouldDisplayVariable(playerVarPtr, playerVarsSearchFilter))
RenderPlayerVariable(playerVarPtr);
}
ImGui::Unindent();
}
ImGui::EndDisabled();
}
static void DisplayPopupMessage(const char* popupTitle, const char* fmt, ...) {
if (ImGui::BeginPopupModal(popupTitle, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
va_list args;
va_start(args, fmt);
char buffer[512];
vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
ImGui::Text("%s", buffer);
if (ImGui::Button("OK", ImVec2(120.0f, 0.0f)))
ImGui::CloseCurrentPopup();
ImGui::EndPopup();
}
}
static void HandleDialogs() {
if (ImGuiFileDialog::Instance()->Display("ChooseSCRPath", ImGuiWindowFlags_NoCollapse, ImVec2(600.0f, 400.0f))) {
if (ImGuiFileDialog::Instance()->IsOk()) {
const std::string filePath = ImGuiFileDialog::Instance()->GetCurrentPath();
if (!filePath.empty()) {
saveSCRPath = ImGuiFileDialog::Instance()->GetCurrentPath();
SaveVariablesToSCR();
}
saveSCRPath = ImGuiFileDialog::Instance()->GetCurrentPath();
SaveVariablesToSCR();
}
ImGuiFileDialog::Instance()->Close();
}
@ -507,80 +383,109 @@ namespace EGT::Menu {
}
ImGuiFileDialog::Instance()->Close();
}
if (ImGui::BeginPopupModal("Failed reloading player jump parameters.", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("Could not find any \"jump_parameters.scr\" inside \"EGameTools\\UserModFiles\"! Please make sure a \"jump_parameters.scr\" file is present in the directory mentioned earlier.");
if (ImGui::Button("OK", ImVec2(120.0f, 0.0f)))
ImGui::CloseCurrentPopup();
ImGui::EndPopup();
}
if (ImGui::BeginPopupModal("Reloaded player jump parameters!", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("Player jump parameters have been reloaded! from \"EGameTools\\UserModFiles\"");
if (ImGui::Button("OK", ImVec2(120.0f, 0.0f)))
ImGui::CloseCurrentPopup();
ImGui::EndPopup();
}
if (ImGui::BeginPopupModal("Failed saving player variables.", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("There was an error opening a handle to the file \"%s\\player_variables.scr\"! The file is most likely already open in another program. Please close it!", saveSCRPath.c_str());
if (ImGui::Button("OK", ImVec2(120.0f, 0.0f)))
ImGui::CloseCurrentPopup();
ImGui::EndPopup();
}
if (ImGui::BeginPopupModal("Saved player variables!", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("Player variables have been saved to \"%s\\player_variables.scr\"!", saveSCRPath.c_str());
if (ImGui::Button("OK", ImVec2(120.0f, 0.0f)))
ImGui::CloseCurrentPopup();
ImGui::EndPopup();
}
if (ImGui::BeginPopupModal("Failed loading player variables.", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("There was an error opening the file \"%s\"! The file is most likely already open in another program. Please close it!", loadSCRFilePath.c_str());
if (ImGui::Button("OK", ImVec2(120.0f, 0.0f)))
ImGui::CloseCurrentPopup();
ImGui::EndPopup();
}
if (ImGui::BeginPopupModal("Loaded player variables!", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("Player variables have been loaded from \"%s\"!", loadSCRFilePath.c_str());
if (ImGui::Button("OK", ImVec2(120.0f, 0.0f)))
ImGui::CloseCurrentPopup();
ImGui::EndPopup();
}
if (ImGui::BeginPopupModal("Restored player variables!", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("All player variables have been restored to default (values from game load)!");
if (ImGui::Button("OK", ImVec2(120.0f, 0.0f)))
ImGui::CloseCurrentPopup();
ImGui::EndPopup();
}
if (ImGui::BeginPopupModal("Saved current player variables!", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("All current player variables have been stored as default! Now if you have \"Restore variables to saved variables\" enabled, restoring to default will restore player variables to the ones you have saved!");
if (ImGui::Button("OK", ImVec2(120.0f, 0.0f)))
ImGui::CloseCurrentPopup();
ImGui::EndPopup();
}
DisplayPopupMessage("Failed reloading player jump parameters.", "Could not find any \"jump_parameters.scr\" inside \"EGameTools\\UserModFiles\"! Please make sure a \"jump_parameters.scr\" file is present in the directory mentioned earlier.");
DisplayPopupMessage("Reloaded player jump parameters!", "Player jump parameters have been reloaded! from \"EGameTools\\UserModFiles\"");
DisplayPopupMessage("Failed saving player variables.", "There was an error opening a handle to the file \"%s\\player_variables.scr\"! The file is most likely already open in another program. Please close it!", saveSCRPath.c_str());
DisplayPopupMessage("Saved player variables!", "Player variables have been saved to \"%s\\player_variables.scr\"!", saveSCRPath.c_str());
DisplayPopupMessage("Failed loading player variables.", "There was an error opening the file \"%s\"! The file is most likely already open in another program. Please close it!", loadSCRFilePath.c_str());
DisplayPopupMessage("Loaded player variables!", "Player variables have been loaded from \"%s\"!", loadSCRFilePath.c_str());
DisplayPopupMessage("Restored player variables!", "All player variables have been restored to default values!");
DisplayPopupMessage("Saved current player variables!", "All current player variables have been stored as default! Now if you have \"Restore variables to saved variables\" enabled, restoring to default will restore player variables to the ones you have saved!");
}
static void UpdateMoney(bool updateSlider) {
EGSDK::GamePH::LevelDI* iLevel = EGSDK::GamePH::LevelDI::Get();
static void PlayerPositionUpdate() {
auto playerCharacter = EGSDK::Engine::CBulletPhysicsCharacter::Get();
if (!playerCharacter)
return;
auto iLevel = EGSDK::GamePH::LevelDI::Get();
if (!iLevel)
return;
if ((freezePlayer.GetValue() || (Camera::freeCam.GetValue() && !Camera::teleportPlayerToCamera.GetValue())) && !iLevel->IsTimerFrozen()) {
playerCharacter->FreezeCharacter();
return;
}
EGSDK::Engine::CBulletPhysicsCharacter::posBeforeFreeze = playerCharacter->playerPos;
if (iLevel->IsTimerFrozen() || !Camera::freeCam.GetValue() || !Camera::teleportPlayerToCamera.GetValue())
return;
auto freeCam = EGSDK::GamePH::FreeCamera::Get();
if (!freeCam)
return;
EGSDK::Vector3 camPos{};
freeCam->GetPosition(&camPos);
if (!camPos.isDefault())
playerCharacter->MoveCharacter(camPos);
}
static void PlayerHealthUpdate() {
auto playerHealthModule = EGSDK::GamePH::PlayerHealthModule::Get();
if (!playerHealthModule)
return;
playerMaxHealth = playerHealthModule->maxHealth;
if (menuToggle.GetValue())
return;
auto iLevel = EGSDK::GamePH::LevelDI::Get();
if (!iLevel || !iLevel->IsLoaded())
return;
EGSDK::GamePH::PlayerDI_PH* player = EGSDK::GamePH::PlayerDI_PH::Get();
if (!player)
playerHealth = playerHealthModule->health;
}
static void PlayerImmunityUpdate() {
auto playerInfectionModule = EGSDK::GamePH::PlayerInfectionModule::Get();
if (!playerInfectionModule)
return;
EGSDK::GamePH::InventoryContainerDI* invContainer = player->GetInventoryContainer();
playerMaxImmunity = playerInfectionModule->maxImmunity * 100.0f;
if (menuToggle.GetValue())
return;
auto iLevel = EGSDK::GamePH::LevelDI::Get();
if (!iLevel || !iLevel->IsLoaded())
return;
playerImmunity = playerInfectionModule->immunity * 100.0f;
}
static void UpdateDisabledOptions() {
freezePlayer.SetChangesAreDisabled(!EGSDK::Engine::CBulletPhysicsCharacter::Get());
}
static void HandleToggles() {
if (disableAirControl.HasChanged()) {
disableAirControl.SetPrevValue(disableAirControl.GetValue());
EGSDK::GamePH::ReloadJumps();
}
}
static void UpdateMoney(bool updateSlider) {
auto iLevel = EGSDK::GamePH::LevelDI::Get();
if (!iLevel || !iLevel->IsLoaded())
return;
auto playerDI = EGSDK::GamePH::PlayerDI_PH::Get();
if (!playerDI)
return;
auto invContainer = playerDI->GetInventoryContainer();
if (!invContainer)
return;
EGSDK::GamePH::InventoryMoney* invMoney = invContainer->GetInventoryMoney(0);
auto invMoney = invContainer->GetInventoryMoney(0);
if (!invMoney)
return;
updateSlider ? (oldWorldMoney = invMoney->oldWorldMoney) : (invMoney->oldWorldMoney = oldWorldMoney);
}
static bool isMoneyInteractionDisabled() {
EGSDK::GamePH::LevelDI* iLevel = EGSDK::GamePH::LevelDI::Get();
auto iLevel = EGSDK::GamePH::LevelDI::Get();
if (!iLevel || !iLevel->IsLoaded())
return true;
EGSDK::GamePH::PlayerDI_PH* player = EGSDK::GamePH::PlayerDI_PH::Get();
auto player = EGSDK::GamePH::PlayerDI_PH::Get();
if (!player)
return true;
EGSDK::GamePH::InventoryContainerDI* invContainer = player->GetInventoryContainer();
auto invContainer = player->GetInventoryContainer();
if (!invContainer || !invContainer->GetInventoryMoney(0))
return true;
@ -589,17 +494,20 @@ namespace EGT::Menu {
Tab Tab::instance{};
void Tab::Update() {
UpdateDisabledOptions();
PlayerPositionUpdate();
PlayerHealthUpdate();
PlayerImmunityUpdate();
UpdateDisabledOptions();
UpdatePlayerVars();
PlayerVarsUpdate();
PlayerVarListValuesUpdate();
HandleToggles();
}
void Tab::Render() {
ImGui::SeparatorText("Misc");
EGSDK::GamePH::PlayerHealthModule* playerHealthModule = EGSDK::GamePH::PlayerHealthModule::Get();
auto playerHealthModule = EGSDK::GamePH::PlayerHealthModule::Get();
ImGui::BeginDisabled(!playerHealthModule); {
if (ImGui::SliderFloat("Player Health", &playerHealth, 0.0f, playerMaxHealth, "%.2f") && playerHealthModule)
playerHealthModule->health = playerHealth;
@ -607,7 +515,7 @@ namespace EGT::Menu {
playerHealth = playerHealthModule->health;
ImGui::EndDisabled();
}
EGSDK::GamePH::PlayerInfectionModule* playerInfectionModule = EGSDK::GamePH::PlayerInfectionModule::Get();
auto playerInfectionModule = EGSDK::GamePH::PlayerInfectionModule::Get();
ImGui::BeginDisabled(!playerInfectionModule); {
if (ImGui::SliderFloat("Player Immunity", &playerImmunity, 0.0f, playerMaxImmunity, "%.2f") && playerInfectionModule)
playerInfectionModule->immunity = playerImmunity / 100.0f;
@ -616,10 +524,7 @@ namespace EGT::Menu {
ImGui::EndDisabled();
}
ImGui::BeginDisabled(isMoneyInteractionDisabled()); {
if (ImGui::DragInt("Old World Money", &oldWorldMoney, 2.0f, 0, 999999999))
UpdateMoney(false);
else
UpdateMoney(true);
UpdateMoney(!ImGui::DragInt("Old World Money", &oldWorldMoney, 2.0f, 0, 999999999));
ImGui::EndDisabled();
}
ImGui::CheckboxHotkey("God Mode", &godMode, "Makes the player invincible");

View File

@ -21,7 +21,7 @@ namespace EGT::Menu {
static constexpr float baseWeaponRecoilMul = 1.0f;
static constexpr float baseWeaponReloadMul = 1.0f;
static void UpdatePlayerVars() {
static void PlayerVarsUpdate() {
if (!EGSDK::GamePH::PlayerVariables::gotPlayerVars)
return;
@ -94,7 +94,7 @@ namespace EGT::Menu {
void Tab::Update() {
if (!Menu::menuToggle.GetValue())
UpdateWeaponDurability(true);
UpdatePlayerVars();
PlayerVarsUpdate();
}
void Tab::Render() {
ImGui::SeparatorText("Current Weapon##Weapon");