merged variables list rendering logic into 1 class

This commit is contained in:
EricPlayZ
2025-02-24 03:14:01 +02:00
parent 5559600a94
commit e9323fa362
21 changed files with 363 additions and 334 deletions

View File

@ -75,6 +75,9 @@ namespace EGSDK::Engine {
using Base::GetDefaultVarRef;
using Base::GetCustomDefaultVarRef;
using VarT = CVar;
using VarMapT = CVarMap;
static std::optional<CVarRef> GetVarRef(uint32_t valueOffset);
static std::optional<CVarRef> GetCustomVarRef(uint32_t valueOffset);
static std::optional<CVarRef> GetDefaultVarRef(uint32_t valueOffset);

View File

@ -35,8 +35,8 @@ namespace EGSDK::Engine {
VarType GetType() const;
void SetType(VarType type);
protected:
static std::mutex writingMutex;
static std::shared_mutex readingMutex;
static std::mutex writeMutex;
static std::shared_mutex readMutex;
private:
static std::unordered_map<const VarBase*, std::string> varNames;
static std::unordered_map<const VarBase*, VarType> varTypes;

View File

@ -48,8 +48,8 @@ namespace EGSDK::Engine {
static std::unordered_map<std::string, std::any> prevVarValueMap;
static std::unordered_map<std::string, bool> prevBoolValueMap;
static std::unordered_map<std::string, uint64_t> varOwnerMap;
static std::mutex writingMutex;
static std::shared_mutex readingMutex;
static std::mutex writeMutex;
static std::shared_mutex readMutex;
static std::optional<VarRef<VarMapT, VarT>> _GetVarRef(const char* name, VarMapT& map);
@ -101,7 +101,7 @@ namespace EGSDK::Engine {
return;
uint64_t caller = reinterpret_cast<uint64_t>(returnAddr);
std::shared_lock lock(readingMutex);
std::shared_lock lock(readMutex);
const char* name = var->GetName();
@ -133,7 +133,7 @@ namespace EGSDK::Engine {
}
}
template <AllowedVarTypes T>
static void _SaveVariableAsDefault(VarRef<VarMapT, VarT>* var) {
static void _SaveVarAsDefault(VarRef<VarMapT, VarT>* var) {
if (!var)
return;

View File

@ -33,14 +33,14 @@ namespace EGSDK::Engine {
template <typename Callable, typename... Args>
void ForEach(Callable&& func, Args&&... args) {
std::shared_lock lock(readingMutex);
std::shared_lock lock(readMutex);
for (const auto& name : varsOrdered)
func(vars.at(name), std::forward<Args>(args)...);
}
protected:
std::unordered_map<std::string, std::unique_ptr<VarT>> vars;
std::vector<std::string> varsOrdered;
mutable std::mutex writingMutex;
mutable std::shared_mutex readingMutex;
mutable std::mutex writeMutex;
mutable std::shared_mutex readMutex;
};
}

View File

@ -64,8 +64,8 @@ namespace EGSDK::Engine {
VarMgrBase::template _ManageByBool<T>(this, valueIfTrue, valueIfFalse, boolVal, usePreviousVal);
}
template <AllowedVarTypes T>
void SaveVariableAsDefault() {
VarMgrBase::template _SaveVariableAsDefault<T>(this);
void SaveVarAsDefault() {
VarMgrBase::template _SaveVarAsDefault<T>(this);
}
template <AllowedVarTypes T>
void RestoreVarToDefault(bool restoreToSavedVars = false) {

View File

@ -54,6 +54,9 @@ namespace EGSDK::GamePH {
using Base::GetDefaultVarRef;
using Base::GetCustomDefaultVarRef;
using VarT = PlayerVar;
using VarMapT = PlayerVarMap;
static std::atomic<bool> gotPlayerVars;
#ifdef EGameSDK_EXPORTS

View File

@ -6,7 +6,7 @@ namespace EGSDK::Engine {
CVar::CVar(const std::string& name) : VarBase(name) {}
CVar::CVar(const std::string& name, VarType type) : VarBase(name, type) {}
VarValueType& CVar::GetValue() {
std::shared_lock lock(readingMutex);
std::shared_lock lock(readMutex);
auto it = varValues.find(this);
if (it == varValues.end()) {
switch (GetType()) {
@ -47,7 +47,7 @@ namespace EGSDK::Engine {
}
}
void CVar::SetValue(const VarValueType& value) {
std::lock_guard lock(writingMutex);
std::lock_guard lock(writeMutex);
auto& varData = varValues[this];
std::visit([&](auto&& val) {
@ -70,7 +70,7 @@ namespace EGSDK::Engine {
}, value);
}
void CVar::AddValuePtr(uint64_t* ptr) {
std::lock_guard lock(writingMutex);
std::lock_guard lock(writeMutex);
varValues[this].valuePtrs.push_back(ptr);
}
@ -88,7 +88,7 @@ namespace EGSDK::Engine {
}
std::unique_ptr<CVar>& CVarMap::try_emplace(std::unique_ptr<CVar> cVar) {
std::lock_guard lock(writingMutex);
std::lock_guard lock(writeMutex);
const std::string& name = cVar->GetName();
auto [it, inserted] = vars.try_emplace(name, std::move(cVar));
if (inserted) {
@ -99,12 +99,12 @@ namespace EGSDK::Engine {
return it->second;
}
CVar* CVarMap::Find(uint32_t valueOffset) const {
std::shared_lock lock(readingMutex);
std::shared_lock lock(readMutex);
auto it = varsByValueOffset.find(valueOffset);
return it == varsByValueOffset.end() ? nullptr : it->second;
}
void CVarMap::Erase(const std::string& name) {
std::lock_guard lock(writingMutex);
std::lock_guard lock(writeMutex);
auto it = vars.find(name);
if (it == vars.end())
return;
@ -118,7 +118,7 @@ namespace EGSDK::Engine {
}
bool CVarMap::none_of(uint32_t valueOffset) {
std::shared_lock lock(readingMutex);
std::shared_lock lock(readMutex);
return varsByValueOffset.find(valueOffset) == varsByValueOffset.end();
}

View File

@ -3,8 +3,8 @@
namespace EGSDK::Engine {
std::unordered_map<const VarBase*, std::string> VarBase::varNames{};
std::unordered_map<const VarBase*, VarType> VarBase::varTypes{};
std::mutex VarBase::writingMutex{};
std::shared_mutex VarBase::readingMutex{};
std::mutex VarBase::writeMutex{};
std::shared_mutex VarBase::readMutex{};
VarBase::VarBase(const std::string& name, VarType type) {
SetName(name);
@ -16,22 +16,22 @@ namespace EGSDK::Engine {
}
const char* VarBase::GetName() const {
std::shared_lock lock(readingMutex);
std::shared_lock lock(readMutex);
auto it = varNames.find(this);
return it != varNames.end() ? it->second.c_str() : nullptr;
}
void VarBase::SetName(const std::string& newName) {
std::lock_guard lock(writingMutex);
std::lock_guard lock(writeMutex);
varNames[this] = newName;
}
VarType VarBase::GetType() const {
std::shared_lock lock(readingMutex);
std::shared_lock lock(readMutex);
auto it = varTypes.find(this);
return it != varTypes.end() ? it->second : VarType::NONE;
}
void VarBase::SetType(VarType newType) {
std::lock_guard lock(writingMutex);
std::lock_guard lock(writeMutex);
varTypes[this] = newType;
}
}

View File

@ -21,9 +21,9 @@ namespace EGSDK::Engine {
std::unordered_map<std::string, uint64_t> VarManagerBase<VarMapT, VarT>::varOwnerMap{};
template <typename VarMapT, typename VarT>
std::mutex VarManagerBase<VarMapT, VarT>::writingMutex{};
std::mutex VarManagerBase<VarMapT, VarT>::writeMutex{};
template <typename VarMapT, typename VarT>
std::shared_mutex VarManagerBase<VarMapT, VarT>::readingMutex{};
std::shared_mutex VarManagerBase<VarMapT, VarT>::readMutex{};
template <typename VarMapT, typename VarT>
std::optional<VarRef<VarMapT, VarT>> VarManagerBase<VarMapT, VarT>::GetVarRefFromPtr(VarT* var) {
@ -74,7 +74,7 @@ namespace EGSDK::Engine {
template <typename VarMapT, typename VarT>
bool VarManagerBase<VarMapT, VarT>::_IsManagedByBool(const char* name) {
std::shared_lock lock(readingMutex);
std::shared_lock lock(readMutex);
return (prevBoolValueMap.find(name) != prevBoolValueMap.end()) && prevBoolValueMap[name];
}
template <typename VarMapT, typename VarT>

View File

@ -5,11 +5,11 @@
namespace EGSDK::Engine {
template <typename VarT>
VarMapBase<VarT>::VarMapBase() : vars(), varsOrdered(), writingMutex(), readingMutex() {}
VarMapBase<VarT>::VarMapBase() : vars(), varsOrdered(), writeMutex(), readMutex() {}
template <typename VarT>
std::unique_ptr<VarT>& VarMapBase<VarT>::try_emplace(std::unique_ptr<VarT> var) {
std::lock_guard lock(writingMutex);
std::lock_guard lock(writeMutex);
const std::string& name = var->GetName();
auto [it, inserted] = vars.try_emplace(name, std::move(var));
if (inserted)
@ -18,13 +18,13 @@ namespace EGSDK::Engine {
}
template <typename VarT>
VarT* VarMapBase<VarT>::Find(const std::string& name) const {
std::shared_lock lock(readingMutex);
std::shared_lock lock(readMutex);
auto it = vars.find(name);
return (it != vars.end()) ? it->second.get() : nullptr;
}
template <typename VarT>
void VarMapBase<VarT>::Erase(const std::string& name) {
std::lock_guard lock(writingMutex);
std::lock_guard lock(writeMutex);
auto it = vars.find(name);
if (it == vars.end())
return;
@ -36,22 +36,22 @@ namespace EGSDK::Engine {
template <typename VarT>
bool VarMapBase<VarT>::empty() const {
std::shared_lock lock(readingMutex);
std::shared_lock lock(readMutex);
return vars.empty();
}
template <typename VarT>
bool VarMapBase<VarT>::none_of(const std::string& name) const {
std::shared_lock lock(readingMutex);
std::shared_lock lock(readMutex);
return vars.find(name) == vars.end();
}
template <typename VarT>
size_t VarMapBase<VarT>::size() {
std::shared_lock lock(readingMutex);
std::shared_lock lock(readMutex);
return vars.size();
}
template <typename VarT>
void VarMapBase<VarT>::reserve(size_t count) {
std::lock_guard lock(writingMutex);
std::lock_guard lock(writeMutex);
vars.reserve(count);
varsOrdered.reserve(count);
}

View File

@ -15,7 +15,7 @@ namespace EGSDK::GamePH {
PlayerVar::PlayerVar(const std::string& name) : VarBase(name) {}
PlayerVar::PlayerVar(const std::string& name, Engine::VarType type) : Engine::VarBase(name, type) {}
Engine::VarValueType PlayerVar::GetValue() {
std::shared_lock lock(readingMutex);
std::shared_lock lock(readMutex);
switch (GetType()) {
case Engine::VarType::String:
return reinterpret_cast<const char*>(reinterpret_cast<uint64_t>(this->strValue.data) & 0x1FFFFFFFFFFFFFFF);
@ -28,7 +28,7 @@ namespace EGSDK::GamePH {
}
}
Engine::VarValueType PlayerVar::GetDefaultValue() {
std::shared_lock lock(readingMutex);
std::shared_lock lock(readMutex);
switch (GetType()) {
case Engine::VarType::String:
return reinterpret_cast<const char*>(reinterpret_cast<uint64_t>(this->defaultStrValue.data) & 0x1FFFFFFFFFFFFFFF);
@ -41,7 +41,7 @@ namespace EGSDK::GamePH {
}
}
void PlayerVar::SetValue(const Engine::VarValueType& value) {
std::lock_guard lock(writingMutex);
std::lock_guard lock(writeMutex);
std::visit([&](auto&& val) {
using T = std::decay_t<decltype(val)>;
if constexpr (std::is_same_v<T, std::string>) {

View File

@ -40,6 +40,7 @@
<ClCompile Include="src\Menu\Misc.cpp" />
<ClCompile Include="src\Menu\Player.cpp" />
<ClCompile Include="src\Menu\Teleport.cpp" />
<ClCompile Include="src\Menu\VarList.cpp" />
<ClCompile Include="src\Menu\Weapon.cpp" />
<ClCompile Include="src\Menu\World.cpp" />
<ClCompile Include="src\Utils\Texture.cpp" />
@ -65,6 +66,7 @@
<ClInclude Include="include\EGT\Menu\Misc.h" />
<ClInclude Include="include\EGT\Menu\Player.h" />
<ClInclude Include="include\EGT\Menu\Teleport.h" />
<ClInclude Include="include\EGT\Menu\VarList.h" />
<ClInclude Include="include\EGT\Menu\Weapon.h" />
<ClInclude Include="include\EGT\Menu\World.h" />
<ClInclude Include="include\EGT\Utils\Texture.h" />

View File

@ -165,6 +165,9 @@
<ClCompile Include="src\ImGui_impl\DeferredActions.cpp">
<Filter>src\ImGui_impl</Filter>
</ClCompile>
<ClCompile Include="src\Menu\VarList.cpp">
<Filter>src\Menu</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\EGT\Config\Config.h">
@ -236,5 +239,8 @@
<ClInclude Include="include\EGT\ImGui_impl\NextFrameTask.h">
<Filter>include\ImGui_impl</Filter>
</ClInclude>
<ClInclude Include="include\EGT\Menu\VarList.h">
<Filter>include\Menu</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -14,7 +14,7 @@ namespace EGT::ImGui_impl {
static void Process();
private:
static std::vector<std::function<void()>> actions;
static std::mutex writingMutex;
static std::shared_mutex readingMutex;
static std::mutex writeMutex;
static std::shared_mutex readMutex;
};
}

View File

@ -18,7 +18,7 @@ namespace EGT::ImGui_impl {
};
static std::vector<TaskEntry> taskQueue;
static std::mutex writingMutex;
static std::shared_mutex readingMutex;
static std::mutex writeMutex;
static std::shared_mutex readMutex;
};
}

View File

@ -0,0 +1,47 @@
#pragma once
#include <vector>
#include <string>
#include <memory>
#include <unordered_map>
#include <shared_mutex>
#include <ImGui\imguiex.h>
#include <EGSDK\Engine\VarBase.h>
#include <EGSDK\Engine\VarMapBase.h>
#include <EGSDK\Engine\VarManagerBase.h>
#include <EGT\ImGui_impl\DeferredActions.h>
namespace EGT {
namespace Menu {
template <typename VarManagerT>
class VarList {
public:
using VarT = typename VarManagerT::VarT;
using VarPtr = std::unique_ptr<VarT>;
VarList(const std::string& title);
VarList(const VarList&) = delete;
VarList& operator=(const VarList&) = delete;
VarList(VarList&&) noexcept = default;
VarList& operator=(VarList&&) noexcept = default;
void Render();
private:
std::string listTitle{};
std::vector<VarT*> filteredVars{};
bool restoreVarsToSavedVarsEnabled = false;
char searchFilter[64] = "";
char lastSearchFilter[64] = "";
void RestoreVarToDefault(VarT* varPtr);
void RestoreVarsToDefault();
void SaveVarAsDefault(const VarPtr& varPtr);
void SaveVarsAsDefault();
bool ShouldDisplayVar(const VarPtr& varPtr);
void UpdateFilteredList();
void RenderVar(VarT* var);
};
}
}

View File

@ -2,26 +2,26 @@
namespace EGT::ImGui_impl {
std::vector<std::function<void()>> DeferredActions::actions{};
std::mutex DeferredActions::writingMutex{};
std::shared_mutex DeferredActions::readingMutex{};
std::mutex DeferredActions::writeMutex{};
std::shared_mutex DeferredActions::readMutex{};
void DeferredActions::Add(const std::function<void()>& action) {
std::lock_guard lock(writingMutex);
std::lock_guard lock(writeMutex);
actions.push_back(action);
}
void DeferredActions::Clear() {
std::lock_guard lock(writingMutex);
std::lock_guard lock(writeMutex);
actions.clear();
}
bool DeferredActions::HasPendingActions() {
std::shared_lock lock(readingMutex);
std::shared_lock lock(readMutex);
return !actions.empty();
}
void DeferredActions::Process() {
std::vector<std::function<void()>> actionsToProcess;
{
std::lock_guard lock(writingMutex);
std::lock_guard lock(writeMutex);
actionsToProcess.swap(actions);
}

View File

@ -2,15 +2,15 @@
namespace EGT::ImGui_impl {
std::vector<NextFrameTask::TaskEntry> NextFrameTask::taskQueue;
std::mutex NextFrameTask::writingMutex{};
std::shared_mutex NextFrameTask::readingMutex{};
std::mutex NextFrameTask::writeMutex{};
std::shared_mutex NextFrameTask::readMutex{};
void NextFrameTask::AddTask(const Task& task, int delayFrames) {
std::lock_guard lock(writingMutex);
std::lock_guard lock(writeMutex);
taskQueue.emplace_back(TaskEntry{ delayFrames, task });
}
void NextFrameTask::ExecuteTasks() {
std::lock_guard lock(writingMutex);
std::lock_guard lock(writeMutex);
for (auto it = taskQueue.begin(); it != taskQueue.end();) {
if (it->framesRemaining <= 0) {
it->task();

View File

@ -5,8 +5,9 @@
#include <EGSDK\GamePH\GameDI_PH.h>
#include <EGSDK\GamePH\LevelDI.h>
#include <EGT\ImGui_impl\DeferredActions.h>
#include <EGT\Menu\Misc.h>
#include <EGT\GamePH\GamePH_Hooks.h>
#include <EGT\Menu\Misc.h>
#include <EGT\Menu\VarList.h>
namespace EGT::Menu {
namespace Misc {
@ -17,132 +18,13 @@ namespace EGT::Menu {
ImGui::Option disableDataPAKsCRCCheck{ false };
ImGui::Option increaseDataPAKsLimit{ false };
static char rendererCVarsSearchFilter[64];
static VarList<EGSDK::Engine::CVars> cVarsList{ "Renderer CVars List" };
static void RendererCVarsUpdate() {
EGSDK::Engine::CVars::ManageVarByBool("i_pp_taa_on", 0, 1, disableTAA.GetValue());
EGSDK::Engine::CVars::ManageVarByBool("i_pp_jitter_on", 0, 1, disableTAA.GetValue());
}
static bool ShouldDisplayVariable(const std::unique_ptr<EGSDK::Engine::CVar>& cVarPtr, const std::string& searchFilter) {
if (cVarPtr->GetType() == EGSDK::Engine::VarType::NONE)
return false;
if (searchFilter.empty())
return true;
// Convert searchFilter and variable name to lowercase
std::string lowerFilter = EGSDK::Utils::Values::to_lower(searchFilter);
std::string lowerKey = EGSDK::Utils::Values::to_lower(cVarPtr->GetName());
return lowerKey.find(lowerFilter) != std::string::npos;
}
static void RestoreVariableToDefault(const std::unique_ptr<EGSDK::Engine::CVar>& cVarPtr) {
auto cVar = EGSDK::Engine::CVars::GetVarRefFromPtr(cVarPtr.get());
ImGui_impl::DeferredActions::Add([cVar]() mutable {
switch (cVar->GetType()) {
case EGSDK::Engine::VarType::Float:
cVar->RestoreVarToDefault<float>();
break;
case EGSDK::Engine::VarType::Int:
cVar->RestoreVarToDefault<int>();
break;
case EGSDK::Engine::VarType::Vec3:
cVar->RestoreVarToDefault<EGSDK::Vec3>();
break;
case EGSDK::Engine::VarType::Vec4:
cVar->RestoreVarToDefault<EGSDK::Vec4>();
break;
default:
break;
}
});
}
static void RestoreVariablesToDefault() {
EGSDK::Engine::CVars::customVars.ForEach([](const std::unique_ptr<EGSDK::Engine::CVar>& cVarPtr) {
RestoreVariableToDefault(cVarPtr);
});
}
static void RenderRendererCVar(const std::unique_ptr<EGSDK::Engine::CVar>& cVarPtr) {
auto cVar = EGSDK::Engine::CVars::GetVarRefFromPtr(cVarPtr.get());
ImGui::BeginDisabled(cVar->IsManagedByBool());
switch (cVar->GetType()) {
case EGSDK::Engine::VarType::Float:
{
auto value = cVar->GetValue<float>();
if (!value)
return;
auto newValue = *value;
if (ImGui::InputFloat(cVar->GetName(), &newValue))
cVar->SetValueFromList(newValue);
break;
}
case EGSDK::Engine::VarType::Int:
{
auto value = cVar->GetValue<int>();
if (!value)
return;
auto newValue = *value;
if (ImGui::InputInt(cVar->GetName(), &newValue))
cVar->SetValueFromList(newValue);
break;
}
case EGSDK::Engine::VarType::Vec3:
{
auto value = cVar->GetValue<EGSDK::Vec3>();
if (!value)
return;
auto newValue = *value;
if (ImGui::InputFloat3(cVar->GetName(), reinterpret_cast<float*>(&newValue)))
cVar->SetValueFromList(newValue);
break;
}
case EGSDK::Engine::VarType::Vec4:
{
auto value = cVar->GetValue<EGSDK::Vec4>();
if (!value)
return;
auto newValue = *value;
if (ImGui::InputFloat4(cVar->GetName(), reinterpret_cast<float*>(&newValue)))
cVar->SetValueFromList(newValue);
break;
}
default:
break;
}
ImGui::EndDisabled();
ImGui::SameLine();
std::string restoreBtnName = "Restore##" + std::string(cVar->GetName());
ImGui::BeginDisabled(!cVar->HasCustomValue() || cVar->IsManagedByBool());
if (ImGui::Button(restoreBtnName.c_str(), "Restores renderer cvar to default"))
RestoreVariableToDefault(cVarPtr);
ImGui::EndDisabled();
}
static void HandleRendererCVarsList() {
ImGui::BeginDisabled(!EGSDK::Engine::CVars::AreAnyVarsPresent());
if (ImGui::CollapsingHeader("Renderer CVars list", ImGuiTreeNodeFlags_None)) {
ImGui::Indent();
ImGui::BeginDisabled(!EGSDK::Engine::CVars::AreAnyCustomVarsPresent() || EGSDK::Engine::CVars::AreAllCustomVarsManagedByBool());
if (ImGui::Button("Restore variables to default"))
RestoreVariablesToDefault();
ImGui::EndDisabled();
ImGui::Separator();
ImGui::InputTextWithHint("##RendererCVarsSearch", "Search variables", rendererCVarsSearchFilter, 64);
EGSDK::Engine::CVars::vars.ForEach([](std::unique_ptr<EGSDK::Engine::CVar>& cVarPtr) {
if (ShouldDisplayVariable(cVarPtr, rendererCVarsSearchFilter))
RenderRendererCVar(cVarPtr);
});
ImGui::Unindent();
}
ImGui::EndDisabled();
}
static void UpdateDisabledOptions() {
auto iLevel = EGSDK::GamePH::LevelDI::Get();
disableHUD.SetChangesAreDisabled(!iLevel || !iLevel->IsLoaded());
@ -184,7 +66,7 @@ namespace EGT::Menu {
ImGui::CheckboxHotkey("Disable TAA", &disableTAA, "Disables the TAA/anti-aliasing (only works if you have upscaling disabled)");
ImGui::SeparatorText("Scripting##Misc");
HandleRendererCVarsList();
cVarsList.Render();
ImGui::SeparatorText("Game Checks##Misc");
if (ImGui::Checkbox("Disable Savegame CRC Check *", &disableSavegameCRCCheck, "Stops the game from falsely saying your savegame is corrupt whenever you modify it outside of the game using a save editor"))

View File

@ -22,6 +22,7 @@
#include <EGT\Menu\Camera.h>
#include <EGT\Menu\Menu.h>
#include <EGT\Menu\Player.h>
#include <EGT\Menu\VarList.h>
namespace EGT::Menu {
namespace Player {
@ -48,8 +49,7 @@ namespace EGT::Menu {
std::string loadSCRFilePath{};
static bool debugEnabled = false;
static bool restoreVarsToSavedVarsEnabled = false;
static char varsSearchFilter[64];
static VarList<EGSDK::GamePH::PlayerVariables> playerVarList{ "Player Variables List" };
#pragma region Player Variables
static std::string getParamName(const std::string& str) {
@ -125,7 +125,7 @@ namespace EGT::Menu {
}
});
}
static void varsUpdate() {
static void ManagePlayerVars() {
if (!EGSDK::GamePH::PlayerVariables::gotPlayerVars)
return;
@ -225,67 +225,6 @@ namespace EGT::Menu {
ImGui::OpenPopup("Loaded player variables!");
}
static void RestoreVariableToDefault(EGSDK::GamePH::PlayerVar* playerVarPtr) {
auto playerVar = EGSDK::GamePH::PlayerVariables::GetVarRef(playerVarPtr->GetName());
if (!playerVar)
return;
ImGui_impl::DeferredActions::Add([playerVar]() mutable {
switch (playerVar->GetType()) {
case EGSDK::Engine::VarType::String:
break; // TO IMPLEMENT
case EGSDK::Engine::VarType::Float:
playerVar->RestoreVarToDefault<float>(restoreVarsToSavedVarsEnabled);
break;
case EGSDK::Engine::VarType::Bool:
playerVar->RestoreVarToDefault<bool>(restoreVarsToSavedVarsEnabled);
break;
default:
break;
}
});
}
static void RestoreVariablesToDefault() {
(restoreVarsToSavedVarsEnabled ? EGSDK::GamePH::PlayerVariables::vars : EGSDK::GamePH::PlayerVariables::customVars).ForEach([](std::unique_ptr<EGSDK::GamePH::PlayerVar>& playerVarPtr) {
RestoreVariableToDefault(playerVarPtr.get());
});
}
static void SaveVariableAsDefault(const std::unique_ptr<EGSDK::GamePH::PlayerVar>& playerVarPtr) {
auto playerVar = EGSDK::GamePH::PlayerVariables::GetVarRefFromPtr(playerVarPtr.get());
if (!playerVar)
return;
switch (playerVar->GetType()) {
case EGSDK::Engine::VarType::String:
break; // TO IMPLEMENT
case EGSDK::Engine::VarType::Float:
playerVar->SaveVariableAsDefault<float>();
break;
case EGSDK::Engine::VarType::Bool:
playerVar->SaveVariableAsDefault<bool>();
break;
default:
break;
}
}
static void SaveVariablesAsDefault() {
EGSDK::GamePH::PlayerVariables::vars.ForEach([](std::unique_ptr<EGSDK::GamePH::PlayerVar>& playerVarPtr) {
SaveVariableAsDefault(playerVarPtr);
});
ImGui::OpenPopup("Saved current player variables!");
}
static bool ShouldDisplayVariable(const std::unique_ptr<EGSDK::GamePH::PlayerVar>& playerVarPtr, const std::string& searchFilter) {
if (playerVarPtr->GetType() == EGSDK::Engine::VarType::String || playerVarPtr->GetType() == EGSDK::Engine::VarType::NONE) // TO IMPLEMENT
return false;
if (searchFilter.empty())
return true;
// 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(EGSDK::GamePH::PlayerVar* playerVarPtr) {
const float maxInputTextWidth = ImGui::CalcTextSize("0x0000000000000000").x;
std::string labelID = "##DebugAddrInputText" + std::string(playerVarPtr->GetName());
@ -305,106 +244,12 @@ namespace EGT::Menu {
ImGui::InputText(labelID.c_str(), const_cast<char*>(addrString.c_str()), strlen(addrString.c_str()), ImGuiInputTextFlags_ReadOnly);
ImGui::PopStyleColor();
}
static void RenderPlayerVariable(EGSDK::GamePH::PlayerVar* playerVarPtr) {
auto playerVar = EGSDK::GamePH::PlayerVariables::GetVarRefFromPtr(playerVarPtr);
if (!playerVar)
return;
ImGui::BeginDisabled(playerVar->IsManagedByBool());
switch (playerVar->GetType()) {
case EGSDK::Engine::VarType::String:
break; // TO IMPLEMENT
case EGSDK::Engine::VarType::Float:
{
auto value = playerVar->GetValue<float>();
if (!value)
return;
auto newValue = *value;
if (ImGui::InputFloat(playerVar->GetName(), &newValue))
playerVar->SetValueFromList(newValue);
break;
}
case EGSDK::Engine::VarType::Bool:
{
auto value = playerVar->GetValue<bool>();
if (!value)
return;
auto newValue = *value;
if (ImGui::Checkbox(playerVar->GetName(), &newValue))
playerVar->SetValueFromList(newValue);
break;
}
default:
break;
}
ImGui::EndDisabled();
ImGui::SameLine();
std::string restoreBtnName = "Restore##" + std::string(playerVarPtr->GetName());
ImGui::BeginDisabled(!playerVar->HasCustomValue() || playerVar->IsManagedByBool());
if (ImGui::Button(restoreBtnName.c_str(), "Restores player variable to default"))
RestoreVariableToDefault(playerVarPtr);
ImGui::EndDisabled();
if (debugEnabled)
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();
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")) {
std::filesystem::path _loadSCRFilePath = loadSCRFilePath;
ImGuiFileDialog::Instance()->OpenDialog("ChooseSCRLoadPath", "Choose File", ".scr", { !_loadSCRFilePath.empty() && std::filesystem::is_directory(_loadSCRFilePath.parent_path()) ? _loadSCRFilePath.parent_path().string() : "." });
}
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::BeginDisabled(!EGSDK::GamePH::PlayerVariables::AreAnyCustomVarsPresent() || EGSDK::GamePH::PlayerVariables::AreAllCustomVarsManagedByBool());
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("##PlayerVariablesSearch", "Search variables", varsSearchFilter, 64);
static std::vector<EGSDK::GamePH::PlayerVar*> filteredVars;
static char lastSearchFilter[64];
if (filteredVars.empty() || _strcmpi(varsSearchFilter, lastSearchFilter)) {
strcpy_s(lastSearchFilter, varsSearchFilter); // Update last search filter
filteredVars.clear();
EGSDK::GamePH::PlayerVariables::vars.ForEach([](std::unique_ptr<EGSDK::GamePH::PlayerVar>& playerVarPtr) {
if (ShouldDisplayVariable(playerVarPtr, varsSearchFilter))
filteredVars.push_back(playerVarPtr.get()); // Store raw pointer
});
}
ImGui::Text("Total variables: %zu", filteredVars.size()); // Debug info
ImGuiListClipper clipper;
clipper.Begin(filteredVars.size());
while (clipper.Step()) {
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; ++i)
RenderPlayerVariable(filteredVars[i]);
}
ImGui::Unindent();
}
playerVarList.Render();
ImGui::EndDisabled();
}
static void HandlePlayerVariablesDialogs() {
@ -574,7 +419,7 @@ namespace EGT::Menu {
PlayerImmunityUpdate();
PlayerRestrictionsUpdate();
varsUpdate();
ManagePlayerVars();
PlayerVarListValuesUpdate();
HandleToggles();

View File

@ -0,0 +1,241 @@
#include <EGT\Menu\VarList.h>
#include <EGSDK\GamePH\PlayerVariables.h>
#include <EGSDK\Engine\CVars.h>
namespace EGT {
namespace Menu {
template <typename VarManagerT>
VarList<VarManagerT>::VarList(const std::string& title) : listTitle(title) {}
template <typename VarManagerT>
void VarList<VarManagerT>::Render() {
ImGui::BeginDisabled(!VarManagerT::AreAnyVarsPresent());
if (ImGui::CollapsingHeader(listTitle.c_str(), 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")) {
// std::filesystem::path _loadSCRFilePath = loadSCRFilePath;
// ImGuiFileDialog::Instance()->OpenDialog("ChooseSCRLoadPath", "Choose File", ".scr", { !_loadSCRFilePath.empty() && std::filesystem::is_directory(_loadSCRFilePath.parent_path()) ? _loadSCRFilePath.parent_path().string() : "." });
//}
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::BeginDisabled(!VarManagerT::AreAnyCustomVarsPresent() || VarManagerT::AreAllCustomVarsManagedByBool());
if (ImGui::Button("Restore variables to default"))
RestoreVarsToDefault();
ImGui::EndDisabled();
ImGui::SameLine();
if (ImGui::Button("Save current variables as default", "Saves the current variables as default for whenever you use \"Restore variables to default\""))
SaveVarsAsDefault();
ImGui::Separator();
ImGui::InputTextWithHint("##SearchFilter", "Search variables...", searchFilter, sizeof(searchFilter));
UpdateFilteredList();
ImGui::Text("Total listed variables: %zu", filteredVars.size());
ImGuiListClipper clipper{};
clipper.Begin(filteredVars.size());
while (clipper.Step()) {
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; ++i)
RenderVar(filteredVars[i]);
}
ImGui::Unindent();
}
ImGui::EndDisabled();
}
template <typename VarManagerT>
void VarList<VarManagerT>::RestoreVarToDefault(VarT* varPtr) {
auto var = VarManagerT::GetVarRef(varPtr->GetName());
if (!var)
return;
ImGui_impl::DeferredActions::Add([this, var]() mutable {
switch (var->GetType()) {
case EGSDK::Engine::VarType::String:
break; // TO IMPLEMENT
case EGSDK::Engine::VarType::Float:
var->RestoreVarToDefault<float>(restoreVarsToSavedVarsEnabled);
break;
case EGSDK::Engine::VarType::Int:
var->RestoreVarToDefault<int>(restoreVarsToSavedVarsEnabled);
break;
case EGSDK::Engine::VarType::Vec3:
var->RestoreVarToDefault<EGSDK::Vec3>(restoreVarsToSavedVarsEnabled);
break;
case EGSDK::Engine::VarType::Vec4:
var->RestoreVarToDefault<EGSDK::Vec4>(restoreVarsToSavedVarsEnabled);
break;
case EGSDK::Engine::VarType::Bool:
var->RestoreVarToDefault<bool>(restoreVarsToSavedVarsEnabled);
break;
default:
break;
}
});
}
template <typename VarManagerT>
void VarList<VarManagerT>::RestoreVarsToDefault() {
(restoreVarsToSavedVarsEnabled ? VarManagerT::vars : VarManagerT::customVars).ForEach([this](VarPtr& varPtr) {
RestoreVarToDefault(varPtr.get());
});
}
template <typename VarManagerT>
void VarList<VarManagerT>::SaveVarAsDefault(const VarPtr& varPtr) {
auto var = VarManagerT::GetVarRefFromPtr(varPtr.get());
if (!var)
return;
switch (var->GetType()) {
case EGSDK::Engine::VarType::String:
break; // TO IMPLEMENT
case EGSDK::Engine::VarType::Float:
var->SaveVarAsDefault<float>();
break;
case EGSDK::Engine::VarType::Int:
var->SaveVarAsDefault<int>();
break;
case EGSDK::Engine::VarType::Vec3:
var->SaveVarAsDefault<EGSDK::Vec3>();
break;
case EGSDK::Engine::VarType::Vec4:
var->SaveVarAsDefault<EGSDK::Vec4>();
break;
case EGSDK::Engine::VarType::Bool:
var->SaveVarAsDefault<bool>();
break;
default:
break;
}
}
template <typename VarManagerT>
void VarList<VarManagerT>::SaveVarsAsDefault() {
VarManagerT::vars.ForEach([this](VarPtr& varPtr) {
SaveVarAsDefault(varPtr);
});
//ImGui::OpenPopup("Saved current player variables!");
}
template <typename VarManagerT>
bool VarList<VarManagerT>::ShouldDisplayVar(const VarPtr& varPtr) {
if (!searchFilter[0])
return true;
if (varPtr->GetType() == EGSDK::Engine::VarType::NONE)
return false;
// Convert searchFilter and variable name to lowercase
std::string lowerFilter = EGSDK::Utils::Values::to_lower(searchFilter);
std::string lowerKey = EGSDK::Utils::Values::to_lower(varPtr->GetName());
return lowerKey.find(lowerFilter) != std::string::npos;
}
template <typename VarManagerT>
void VarList<VarManagerT>::UpdateFilteredList() {
if (filteredVars.empty() || _strcmpi(searchFilter, lastSearchFilter)) {
strcpy_s(lastSearchFilter, searchFilter);
filteredVars.clear();
VarManagerT::vars.ForEach([this](VarPtr& varPtr) {
if (ShouldDisplayVar(varPtr))
filteredVars.push_back(varPtr.get());
});
}
}
template <typename VarManagerT>
void VarList<VarManagerT>::RenderVar(VarT* varPtr) {
auto var = VarManagerT::GetVarRefFromPtr(varPtr);
if (!var)
return;
ImGui::BeginDisabled(var->IsManagedByBool());
switch (var->GetType()) {
case EGSDK::Engine::VarType::String:
{
static char buffer[256];
//std::strncpy(buffer, value->c_str(), sizeof(buffer) - 1);
//buffer[sizeof(buffer) - 1] = '\0';
ImGui::BeginDisabled();
if (ImGui::InputText(var->GetName(), buffer, sizeof(buffer)))
var->SetValueFromList(std::string(buffer));
ImGui::EndDisabled();
ImGui::SetItemTooltip("STRING VARIABLES NOT IMPLEMENTED");
break; // TO IMPLEMENT
}
case EGSDK::Engine::VarType::Float:
{
auto value = var->GetValue<float>();
if (!value) return;
float newValue = *value;
if (ImGui::InputFloat(var->GetName(), &newValue))
var->SetValueFromList(newValue);
break;
}
case EGSDK::Engine::VarType::Int:
{
auto value = var->GetValue<int>();
if (!value)
return;
auto newValue = *value;
if (ImGui::InputInt(var->GetName(), &newValue))
var->SetValueFromList(newValue);
break;
}
case EGSDK::Engine::VarType::Vec3:
{
auto value = var->GetValue<EGSDK::Vec3>();
if (!value)
return;
auto newValue = *value;
if (ImGui::InputFloat3(var->GetName(), reinterpret_cast<float*>(&newValue)))
var->SetValueFromList(newValue);
break;
}
case EGSDK::Engine::VarType::Vec4:
{
auto value = var->GetValue<EGSDK::Vec4>();
if (!value)
return;
auto newValue = *value;
if (ImGui::InputFloat4(var->GetName(), reinterpret_cast<float*>(&newValue)))
var->SetValueFromList(newValue);
break;
}
case EGSDK::Engine::VarType::Bool:
{
auto value = var->GetValue<bool>();
if (!value) return;
bool newValue = *value;
if (ImGui::Checkbox(var->GetName(), &newValue))
var->SetValueFromList(newValue);
break;
}
default:
break;
}
ImGui::EndDisabled();
ImGui::SameLine();
std::string restoreBtnName = "Restore##" + std::string(var->GetName());
ImGui::BeginDisabled(!var->HasCustomValue() || var->IsManagedByBool());
if (ImGui::Button(restoreBtnName.c_str(), "Restores variable to default"))
RestoreVarToDefault(varPtr);
ImGui::EndDisabled();
//if (debugEnabled)
// RenderDebugInfo(playerVarPtr);
}
template class VarList<EGSDK::GamePH::PlayerVariables>;
template class VarList<EGSDK::Engine::CVars>;
}
}