diff --git a/EGameSDK/include/EGSDK/Engine/CVars.h b/EGameSDK/include/EGSDK/Engine/CVars.h index 9f18c04..053f0fb 100644 --- a/EGameSDK/include/EGSDK/Engine/CVars.h +++ b/EGameSDK/include/EGSDK/Engine/CVars.h @@ -75,6 +75,9 @@ namespace EGSDK::Engine { using Base::GetDefaultVarRef; using Base::GetCustomDefaultVarRef; + using VarT = CVar; + using VarMapT = CVarMap; + static std::optional GetVarRef(uint32_t valueOffset); static std::optional GetCustomVarRef(uint32_t valueOffset); static std::optional GetDefaultVarRef(uint32_t valueOffset); diff --git a/EGameSDK/include/EGSDK/Engine/VarBase.h b/EGameSDK/include/EGSDK/Engine/VarBase.h index 0f6f8a2..3ba2fa3 100644 --- a/EGameSDK/include/EGSDK/Engine/VarBase.h +++ b/EGameSDK/include/EGSDK/Engine/VarBase.h @@ -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 varNames; static std::unordered_map varTypes; diff --git a/EGameSDK/include/EGSDK/Engine/VarManagerBase.h b/EGameSDK/include/EGSDK/Engine/VarManagerBase.h index 51a80b0..de201ed 100644 --- a/EGameSDK/include/EGSDK/Engine/VarManagerBase.h +++ b/EGameSDK/include/EGSDK/Engine/VarManagerBase.h @@ -48,8 +48,8 @@ namespace EGSDK::Engine { static std::unordered_map prevVarValueMap; static std::unordered_map prevBoolValueMap; static std::unordered_map varOwnerMap; - static std::mutex writingMutex; - static std::shared_mutex readingMutex; + static std::mutex writeMutex; + static std::shared_mutex readMutex; static std::optional> _GetVarRef(const char* name, VarMapT& map); @@ -101,7 +101,7 @@ namespace EGSDK::Engine { return; uint64_t caller = reinterpret_cast(returnAddr); - std::shared_lock lock(readingMutex); + std::shared_lock lock(readMutex); const char* name = var->GetName(); @@ -133,7 +133,7 @@ namespace EGSDK::Engine { } } template - static void _SaveVariableAsDefault(VarRef* var) { + static void _SaveVarAsDefault(VarRef* var) { if (!var) return; diff --git a/EGameSDK/include/EGSDK/Engine/VarMapBase.h b/EGameSDK/include/EGSDK/Engine/VarMapBase.h index 9b1255f..e2010b5 100644 --- a/EGameSDK/include/EGSDK/Engine/VarMapBase.h +++ b/EGameSDK/include/EGSDK/Engine/VarMapBase.h @@ -33,14 +33,14 @@ namespace EGSDK::Engine { template 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)...); } protected: std::unordered_map> vars; std::vector varsOrdered; - mutable std::mutex writingMutex; - mutable std::shared_mutex readingMutex; + mutable std::mutex writeMutex; + mutable std::shared_mutex readMutex; }; } \ No newline at end of file diff --git a/EGameSDK/include/EGSDK/Engine/VarRef.h b/EGameSDK/include/EGSDK/Engine/VarRef.h index 1ce1862..3d4288b 100644 --- a/EGameSDK/include/EGSDK/Engine/VarRef.h +++ b/EGameSDK/include/EGSDK/Engine/VarRef.h @@ -64,8 +64,8 @@ namespace EGSDK::Engine { VarMgrBase::template _ManageByBool(this, valueIfTrue, valueIfFalse, boolVal, usePreviousVal); } template - void SaveVariableAsDefault() { - VarMgrBase::template _SaveVariableAsDefault(this); + void SaveVarAsDefault() { + VarMgrBase::template _SaveVarAsDefault(this); } template void RestoreVarToDefault(bool restoreToSavedVars = false) { diff --git a/EGameSDK/include/EGSDK/GamePH/PlayerVariables.h b/EGameSDK/include/EGSDK/GamePH/PlayerVariables.h index 7a3b71a..fd4b7f5 100644 --- a/EGameSDK/include/EGSDK/GamePH/PlayerVariables.h +++ b/EGameSDK/include/EGSDK/GamePH/PlayerVariables.h @@ -54,6 +54,9 @@ namespace EGSDK::GamePH { using Base::GetDefaultVarRef; using Base::GetCustomDefaultVarRef; + using VarT = PlayerVar; + using VarMapT = PlayerVarMap; + static std::atomic gotPlayerVars; #ifdef EGameSDK_EXPORTS diff --git a/EGameSDK/src/Engine/CVars.cpp b/EGameSDK/src/Engine/CVars.cpp index 277ffc8..ba58e03 100644 --- a/EGameSDK/src/Engine/CVars.cpp +++ b/EGameSDK/src/Engine/CVars.cpp @@ -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& CVarMap::try_emplace(std::unique_ptr 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(); } diff --git a/EGameSDK/src/Engine/VarBase.cpp b/EGameSDK/src/Engine/VarBase.cpp index 9b5e877..b414500 100644 --- a/EGameSDK/src/Engine/VarBase.cpp +++ b/EGameSDK/src/Engine/VarBase.cpp @@ -3,8 +3,8 @@ namespace EGSDK::Engine { std::unordered_map VarBase::varNames{}; std::unordered_map 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; } } \ No newline at end of file diff --git a/EGameSDK/src/Engine/VarManagerBase.cpp b/EGameSDK/src/Engine/VarManagerBase.cpp index 1307a21..ecbb188 100644 --- a/EGameSDK/src/Engine/VarManagerBase.cpp +++ b/EGameSDK/src/Engine/VarManagerBase.cpp @@ -21,9 +21,9 @@ namespace EGSDK::Engine { std::unordered_map VarManagerBase::varOwnerMap{}; template - std::mutex VarManagerBase::writingMutex{}; + std::mutex VarManagerBase::writeMutex{}; template - std::shared_mutex VarManagerBase::readingMutex{}; + std::shared_mutex VarManagerBase::readMutex{}; template std::optional> VarManagerBase::GetVarRefFromPtr(VarT* var) { @@ -74,7 +74,7 @@ namespace EGSDK::Engine { template bool VarManagerBase::_IsManagedByBool(const char* name) { - std::shared_lock lock(readingMutex); + std::shared_lock lock(readMutex); return (prevBoolValueMap.find(name) != prevBoolValueMap.end()) && prevBoolValueMap[name]; } template diff --git a/EGameSDK/src/Engine/VarMapBase.cpp b/EGameSDK/src/Engine/VarMapBase.cpp index 4b43b1e..9fd2304 100644 --- a/EGameSDK/src/Engine/VarMapBase.cpp +++ b/EGameSDK/src/Engine/VarMapBase.cpp @@ -5,11 +5,11 @@ namespace EGSDK::Engine { template - VarMapBase::VarMapBase() : vars(), varsOrdered(), writingMutex(), readingMutex() {} + VarMapBase::VarMapBase() : vars(), varsOrdered(), writeMutex(), readMutex() {} template std::unique_ptr& VarMapBase::try_emplace(std::unique_ptr 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 VarT* VarMapBase::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 void VarMapBase::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 bool VarMapBase::empty() const { - std::shared_lock lock(readingMutex); + std::shared_lock lock(readMutex); return vars.empty(); } template bool VarMapBase::none_of(const std::string& name) const { - std::shared_lock lock(readingMutex); + std::shared_lock lock(readMutex); return vars.find(name) == vars.end(); } template size_t VarMapBase::size() { - std::shared_lock lock(readingMutex); + std::shared_lock lock(readMutex); return vars.size(); } template void VarMapBase::reserve(size_t count) { - std::lock_guard lock(writingMutex); + std::lock_guard lock(writeMutex); vars.reserve(count); varsOrdered.reserve(count); } diff --git a/EGameSDK/src/GamePH/PlayerVariables.cpp b/EGameSDK/src/GamePH/PlayerVariables.cpp index cd4c527..bb63569 100644 --- a/EGameSDK/src/GamePH/PlayerVariables.cpp +++ b/EGameSDK/src/GamePH/PlayerVariables.cpp @@ -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(reinterpret_cast(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(reinterpret_cast(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; if constexpr (std::is_same_v) { diff --git a/EGameTools/EGameTools.vcxproj b/EGameTools/EGameTools.vcxproj index 082ab73..26ceb86 100644 --- a/EGameTools/EGameTools.vcxproj +++ b/EGameTools/EGameTools.vcxproj @@ -40,6 +40,7 @@ + @@ -65,6 +66,7 @@ + diff --git a/EGameTools/EGameTools.vcxproj.filters b/EGameTools/EGameTools.vcxproj.filters index fa81b45..d0eaf47 100644 --- a/EGameTools/EGameTools.vcxproj.filters +++ b/EGameTools/EGameTools.vcxproj.filters @@ -165,6 +165,9 @@ src\ImGui_impl + + src\Menu + @@ -236,5 +239,8 @@ include\ImGui_impl + + include\Menu + \ No newline at end of file diff --git a/EGameTools/include/EGT/ImGui_impl/DeferredActions.h b/EGameTools/include/EGT/ImGui_impl/DeferredActions.h index 8fe3ba7..82734d4 100644 --- a/EGameTools/include/EGT/ImGui_impl/DeferredActions.h +++ b/EGameTools/include/EGT/ImGui_impl/DeferredActions.h @@ -14,7 +14,7 @@ namespace EGT::ImGui_impl { static void Process(); private: static std::vector> actions; - static std::mutex writingMutex; - static std::shared_mutex readingMutex; + static std::mutex writeMutex; + static std::shared_mutex readMutex; }; } \ No newline at end of file diff --git a/EGameTools/include/EGT/ImGui_impl/NextFrameTask.h b/EGameTools/include/EGT/ImGui_impl/NextFrameTask.h index a58f0db..710114d 100644 --- a/EGameTools/include/EGT/ImGui_impl/NextFrameTask.h +++ b/EGameTools/include/EGT/ImGui_impl/NextFrameTask.h @@ -18,7 +18,7 @@ namespace EGT::ImGui_impl { }; static std::vector taskQueue; - static std::mutex writingMutex; - static std::shared_mutex readingMutex; + static std::mutex writeMutex; + static std::shared_mutex readMutex; }; } \ No newline at end of file diff --git a/EGameTools/include/EGT/Menu/VarList.h b/EGameTools/include/EGT/Menu/VarList.h new file mode 100644 index 0000000..c570a6d --- /dev/null +++ b/EGameTools/include/EGT/Menu/VarList.h @@ -0,0 +1,47 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace EGT { + namespace Menu { + template + class VarList { + public: + using VarT = typename VarManagerT::VarT; + using VarPtr = std::unique_ptr; + + 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 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); + }; + } +} diff --git a/EGameTools/src/ImGui_impl/DeferredActions.cpp b/EGameTools/src/ImGui_impl/DeferredActions.cpp index 2bc67a7..8399dd2 100644 --- a/EGameTools/src/ImGui_impl/DeferredActions.cpp +++ b/EGameTools/src/ImGui_impl/DeferredActions.cpp @@ -2,26 +2,26 @@ namespace EGT::ImGui_impl { std::vector> 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& 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> actionsToProcess; { - std::lock_guard lock(writingMutex); + std::lock_guard lock(writeMutex); actionsToProcess.swap(actions); } diff --git a/EGameTools/src/ImGui_impl/NextFrameTask.cpp b/EGameTools/src/ImGui_impl/NextFrameTask.cpp index 3b40732..1203532 100644 --- a/EGameTools/src/ImGui_impl/NextFrameTask.cpp +++ b/EGameTools/src/ImGui_impl/NextFrameTask.cpp @@ -2,15 +2,15 @@ namespace EGT::ImGui_impl { std::vector 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(); diff --git a/EGameTools/src/Menu/Misc.cpp b/EGameTools/src/Menu/Misc.cpp index 7619605..30c6810 100644 --- a/EGameTools/src/Menu/Misc.cpp +++ b/EGameTools/src/Menu/Misc.cpp @@ -5,8 +5,9 @@ #include #include #include -#include #include +#include +#include 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 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& 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& 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(); - break; - case EGSDK::Engine::VarType::Int: - cVar->RestoreVarToDefault(); - break; - case EGSDK::Engine::VarType::Vec3: - cVar->RestoreVarToDefault(); - break; - case EGSDK::Engine::VarType::Vec4: - cVar->RestoreVarToDefault(); - break; - default: - break; - } - }); - } - static void RestoreVariablesToDefault() { - EGSDK::Engine::CVars::customVars.ForEach([](const std::unique_ptr& cVarPtr) { - RestoreVariableToDefault(cVarPtr); - }); - } - static void RenderRendererCVar(const std::unique_ptr& 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(); - 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(); - 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(); - if (!value) - return; - auto newValue = *value; - if (ImGui::InputFloat3(cVar->GetName(), reinterpret_cast(&newValue))) - cVar->SetValueFromList(newValue); - break; - } - case EGSDK::Engine::VarType::Vec4: - { - auto value = cVar->GetValue(); - if (!value) - return; - auto newValue = *value; - if (ImGui::InputFloat4(cVar->GetName(), reinterpret_cast(&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& 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")) diff --git a/EGameTools/src/Menu/Player.cpp b/EGameTools/src/Menu/Player.cpp index a1e3ca5..beea643 100644 --- a/EGameTools/src/Menu/Player.cpp +++ b/EGameTools/src/Menu/Player.cpp @@ -22,6 +22,7 @@ #include #include #include +#include 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 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(restoreVarsToSavedVarsEnabled); - break; - case EGSDK::Engine::VarType::Bool: - playerVar->RestoreVarToDefault(restoreVarsToSavedVarsEnabled); - break; - default: - break; - } - }); - } - static void RestoreVariablesToDefault() { - (restoreVarsToSavedVarsEnabled ? EGSDK::GamePH::PlayerVariables::vars : EGSDK::GamePH::PlayerVariables::customVars).ForEach([](std::unique_ptr& playerVarPtr) { - RestoreVariableToDefault(playerVarPtr.get()); - }); - } - static void SaveVariableAsDefault(const std::unique_ptr& 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(); - break; - case EGSDK::Engine::VarType::Bool: - playerVar->SaveVariableAsDefault(); - break; - default: - break; - } - } - static void SaveVariablesAsDefault() { - EGSDK::GamePH::PlayerVariables::vars.ForEach([](std::unique_ptr& playerVarPtr) { - SaveVariableAsDefault(playerVarPtr); - }); - ImGui::OpenPopup("Saved current player variables!"); - } - - static bool ShouldDisplayVariable(const std::unique_ptr& 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(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(); - 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(); - 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 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& 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(); diff --git a/EGameTools/src/Menu/VarList.cpp b/EGameTools/src/Menu/VarList.cpp new file mode 100644 index 0000000..2c34e39 --- /dev/null +++ b/EGameTools/src/Menu/VarList.cpp @@ -0,0 +1,241 @@ +#include +#include +#include + +namespace EGT { + namespace Menu { + template + VarList::VarList(const std::string& title) : listTitle(title) {} + + template + void VarList::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 + void VarList::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(restoreVarsToSavedVarsEnabled); + break; + case EGSDK::Engine::VarType::Int: + var->RestoreVarToDefault(restoreVarsToSavedVarsEnabled); + break; + case EGSDK::Engine::VarType::Vec3: + var->RestoreVarToDefault(restoreVarsToSavedVarsEnabled); + break; + case EGSDK::Engine::VarType::Vec4: + var->RestoreVarToDefault(restoreVarsToSavedVarsEnabled); + break; + case EGSDK::Engine::VarType::Bool: + var->RestoreVarToDefault(restoreVarsToSavedVarsEnabled); + break; + default: + break; + } + }); + } + template + void VarList::RestoreVarsToDefault() { + (restoreVarsToSavedVarsEnabled ? VarManagerT::vars : VarManagerT::customVars).ForEach([this](VarPtr& varPtr) { + RestoreVarToDefault(varPtr.get()); + }); + } + template + void VarList::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(); + break; + case EGSDK::Engine::VarType::Int: + var->SaveVarAsDefault(); + break; + case EGSDK::Engine::VarType::Vec3: + var->SaveVarAsDefault(); + break; + case EGSDK::Engine::VarType::Vec4: + var->SaveVarAsDefault(); + break; + case EGSDK::Engine::VarType::Bool: + var->SaveVarAsDefault(); + break; + default: + break; + } + } + template + void VarList::SaveVarsAsDefault() { + VarManagerT::vars.ForEach([this](VarPtr& varPtr) { + SaveVarAsDefault(varPtr); + }); + //ImGui::OpenPopup("Saved current player variables!"); + } + + template + bool VarList::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 + void VarList::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 + void VarList::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(); + 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(); + 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(); + if (!value) + return; + auto newValue = *value; + if (ImGui::InputFloat3(var->GetName(), reinterpret_cast(&newValue))) + var->SetValueFromList(newValue); + break; + } + case EGSDK::Engine::VarType::Vec4: + { + auto value = var->GetValue(); + if (!value) + return; + auto newValue = *value; + if (ImGui::InputFloat4(var->GetName(), reinterpret_cast(&newValue))) + var->SetValueFromList(newValue); + break; + } + case EGSDK::Engine::VarType::Bool: + { + auto value = var->GetValue(); + 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; + template class VarList; + } +}