From 17b4ec57ff5d009b78c4c79c02581b7279902214 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Tue, 30 Mar 2021 16:11:24 +0200 Subject: [PATCH 01/35] Big UI changes (full change list in description) - Made Overlay key available only in VKBindings system to prevent duplication - Moved Overlay key binding to Bindings widget - First time launch now has modal popup where user needs to bind Overlay key - Settings and Bindings widgets have now modal popups when there are unsaved changes - Added option to disable removing of dead key bindings (good for debugging) - Added toggle for ImGui Diagnostics widget - Reworked Settings widget (has two tabs, one for patches and one for developer options) - Fixed issue with console history in Console widget - Added DelayedSetTrapInputInImGui function to be used from within Overlay (needed because of design changes) - Reworked how widgets are enabled/disabled in Overlay - Mods now do not update/draw on first launch until Overlay key is bound --- src/CET.cpp | 3 +- src/Options.cpp | 31 ++---- src/Options.h | 4 +- src/VKBindings.cpp | 99 +++++++++++------- src/VKBindings.h | 6 +- src/d3d12/D3D12.cpp | 12 +++ src/d3d12/D3D12.h | 6 +- src/overlay/Overlay.cpp | 144 ++++++++++++++++---------- src/overlay/Overlay.h | 7 +- src/overlay/widgets/Bindings.cpp | 90 +++++++++++----- src/overlay/widgets/Bindings.h | 8 +- src/overlay/widgets/Console.cpp | 10 +- src/overlay/widgets/Console.h | 4 +- src/overlay/widgets/HelperWidgets.cpp | 10 +- src/overlay/widgets/HelperWidgets.h | 4 +- src/overlay/widgets/Settings.cpp | 140 +++++++++++++++++-------- src/overlay/widgets/Settings.h | 18 ++-- src/overlay/widgets/TweakDBEditor.cpp | 6 +- src/overlay/widgets/TweakDBEditor.h | 4 +- src/overlay/widgets/Widget.h | 4 +- src/scripting/LuaVM.cpp | 5 +- src/scripting/LuaVM.h | 1 + src/scripting/LuaVM_Hooks.cpp | 1 + 23 files changed, 398 insertions(+), 219 deletions(-) diff --git a/src/CET.cpp b/src/CET.cpp index 5b0ea787..7b9100d6 100644 --- a/src/CET.cpp +++ b/src/CET.cpp @@ -60,14 +60,13 @@ bool CET::IsRunning() noexcept CET::CET() : m_options(m_paths) - , m_bindings(m_paths) + , m_bindings(m_paths, m_options) , m_window(&m_overlay, &m_bindings, &m_d3d12) , m_d3d12(m_window, m_paths, m_options) , m_vm(m_paths, m_bindings, m_d3d12, m_options) , m_overlay(m_d3d12, m_bindings, m_options, m_vm) , m_tasks(m_options) { - m_bindings.Bind(m_options.OverlayKeyBind, m_overlay.GetBind()); m_bindings.ConnectUpdate(m_d3d12); m_vm.Initialize(); diff --git a/src/Options.cpp b/src/Options.cpp index bbed25fa..8f267e2e 100644 --- a/src/Options.cpp +++ b/src/Options.cpp @@ -5,8 +5,7 @@ void Options::Load() { - IsFirstLaunch = !exists(m_paths.Config()); - if (!IsFirstLaunch) + if (exists(m_paths.Config())) { std::ifstream configFile(m_paths.Config()); if(configFile) @@ -22,7 +21,8 @@ void Options::Load() PatchDisableVignette = config.value("disable_vignette", PatchDisableVignette); PatchDisableBoundaryTeleport = config.value("disable_boundary_teleport", PatchDisableBoundaryTeleport); PatchDisableWin7Vsync = config.value("disable_win7_vsync", PatchDisableWin7Vsync); - + + RemoveDeadBindings = config.value("cetdev_remove_dead_bindings", RemoveDeadBindings); DumpGameOptions = config.value("dump_game_options", DumpGameOptions); // font config @@ -30,22 +30,6 @@ void Options::Load() FontGlyphRanges = config.value("font_glyph_ranges", FontGlyphRanges); FontSize = config.value("font_size", FontSize); - OverlayKeyBind = config.value("overlay_key", OverlayKeyBind); - if (OverlayKeyBind == 0) - IsFirstLaunch = true; // is for sure in this case - - if (exists(m_paths.CETRoot() / "hotkeys.json")) - { - // encoded key bind was 32-bit number in old config, convert it to new 64-bit format - OverlayKeyBind = - { - ((OverlayKeyBind & 0x000000FF) << 8*0) - | ((OverlayKeyBind & 0x0000FF00) << 8*1) - | ((OverlayKeyBind & 0x00FF0000) << 8*2) - | ((OverlayKeyBind & 0xFF000000) << 8*3) - }; - } - // check old config names if (config.value("unlock_menu", false)) PatchEnableDebug = true; @@ -57,8 +41,7 @@ void Options::Load() void Options::Save() { nlohmann::json config; - - config["overlay_key"] = OverlayKeyBind; + config["enable_debug"] = PatchEnableDebug; config["remove_pedestrians"] = PatchRemovePedestrians; config["disable_async_compute"] = PatchAsyncCompute; @@ -69,6 +52,7 @@ void Options::Save() config["disable_vignette"] = PatchDisableVignette; config["disable_boundary_teleport"] = PatchDisableBoundaryTeleport; config["disable_win7_vsync"] = PatchDisableWin7Vsync; + config["cetdev_remove_dead_bindings"] = RemoveDeadBindings; config["dump_game_options"] = DumpGameOptions; config["font_path"] = FontPath; config["font_glyph_ranges"] = FontGlyphRanges; @@ -90,6 +74,7 @@ void Options::ResetToDefaults() PatchDisableVignette = false; PatchDisableBoundaryTeleport = false; PatchDisableWin7Vsync = false; + RemoveDeadBindings = true; DumpGameOptions = false; Save(); @@ -166,7 +151,5 @@ Options::Options(Paths& aPaths) } Load(); - - if (!IsFirstLaunch) - Save(); + Save(); } diff --git a/src/Options.h b/src/Options.h index 116430a1..88dd41bf 100644 --- a/src/Options.h +++ b/src/Options.h @@ -14,7 +14,6 @@ struct Options void ResetToDefaults(); Image GameImage; - uint64_t OverlayKeyBind{ 0 }; bool PatchEnableDebug{ false }; bool PatchRemovePedestrians{ false }; bool PatchAsyncCompute{ false }; @@ -30,7 +29,8 @@ struct Options std::string FontGlyphRanges{""}; float FontSize{ 13.0f }; bool ExeValid{ false }; - bool IsFirstLaunch{ false }; + bool IsFirstLaunch { true }; + bool RemoveDeadBindings { true }; private: diff --git a/src/VKBindings.cpp b/src/VKBindings.cpp index 59cb366d..71e3bb91 100644 --- a/src/VKBindings.cpp +++ b/src/VKBindings.cpp @@ -18,8 +18,9 @@ uint64_t VKBindInfo::Apply() return CodeBind; } -VKBindings::VKBindings(Paths& aPaths) +VKBindings::VKBindings(Paths& aPaths, const Options& aOptions) : m_paths(aPaths) + , m_options(aOptions) { } @@ -58,58 +59,67 @@ std::vector VKBindings::InitializeMods(std::vector aVKBi vkBindInfo.CodeBind = 0; } - // now, find all dead bindings - std::vector> deadIDToBinds; - for (auto& idToBind : m_idToBind) + // filter dead bindings if option is enabled (default) + if (m_options.RemoveDeadBindings) { - // always ignore internal CET binds here! - if (!idToBind.first.compare(0, 4, "cet.")) - continue; - - // TODO - try to avoid O(n^2) situation here - auto found = false; - for (auto& vkBindInfo : aVKBindInfos) + // now, find all dead bindings + std::vector> deadIDToBinds; + for (auto& idToBind : m_idToBind) { - found = (idToBind.first == vkBindInfo.Bind.ID); - if (found) + // always ignore internal CET binds here! + if (!idToBind.first.compare(0, 4, "cet.")) + continue; + + // TODO - try to avoid O(n^2) situation here + auto found = false; + for (auto& vkBindInfo : aVKBindInfos) { - // test if bind is hotkey and if not, check if bind is valid for input (which means it has single input key, not combo) - found = (vkBindInfo.Bind.IsHotkey() || ((idToBind.second & 0xFFFF000000000000) == idToBind.second)); - break; // we just reset found flag accordingly and exit here, we found valid entry, no need to continue regardless of result + found = (idToBind.first == vkBindInfo.Bind.ID); + if (found) + { + // test if bind is hotkey and if not, check if bind is valid for input (which means it has single input key, not combo) + found = (vkBindInfo.Bind.IsHotkey() || ((idToBind.second & 0xFFFF000000000000) == idToBind.second)); + break; // we just reset found flag accordingly and exit here, we found valid entry, no need to continue regardless of result + } } + + if (!found) + deadIDToBinds.emplace_back(idToBind); } - if (!found) - deadIDToBinds.emplace_back(idToBind); - } + // and remove them + for (auto& idToBind : deadIDToBinds) + { + m_idToBind.erase(idToBind.first); + m_binds.erase(idToBind.second); + } - // and remove them - for (auto& idToBind : deadIDToBinds) - { - m_idToBind.erase(idToBind.first); - m_binds.erase(idToBind.second); + // finally, save our filtered bindings back to not lose them + Save(); } - // finally, save our filtered bindings back to not lose them - Save(); + // insert CET overlay bind info + assert(m_pOverlay); // overlay must be set before first use! + const auto overlayKeyBind { m_pOverlay->GetBind() }; + const auto overlayKeyCodeIt { m_idToBind.find(overlayKeyBind.ID) }; + const auto overlayKeyCode { (overlayKeyCodeIt == m_idToBind.cend()) ? (0) : (overlayKeyCodeIt->second) }; + aVKBindInfos.insert(aVKBindInfos.cbegin(), VKBindInfo{overlayKeyBind, overlayKeyCode, overlayKeyCode, false}); // return corrected bindings return aVKBindInfos; } -void VKBindings::Load(const Overlay& aOverlay) +bool VKBindings::Load(const Overlay& aOverlay) { - auto parseConfig {[this, &aOverlay](const std::filesystem::path& path, bool old = false) -> bool { + auto parseConfig {[this, &aOverlay](const std::filesystem::path& path, bool old = false) -> std::pair { std::ifstream ifs { path }; if (ifs) { auto config { nlohmann::json::parse(ifs) }; + VKBind overlayBind { aOverlay.GetBind() }; + uint64_t overlayBindCode { 0 }; for (auto& it : config.items()) { - // properly auto-bind Overlay if it is present here (could be this is first start so it may not be - // in here yet) - auto vkBind { (it.key() == aOverlay.GetBind().ID) ? aOverlay.GetBind() : VKBind{ it.key() } }; - uint64_t key { it.value() }; if (old) { @@ -123,29 +133,46 @@ void VKBindings::Load(const Overlay& aOverlay) }; } + // properly auto-bind Overlay if it is present here (could be this is first start so it may not be + // in here yet) + VKBind vkBind { it.key() }; + if (it.key() == overlayBind.ID) + { + vkBind = overlayBind; + overlayBindCode = key; + } + const auto ret { Bind(key, vkBind) }; assert(ret); // we want this to never fail! } - return true; + return std::make_pair(true, overlayBindCode); } - return false; + return std::make_pair(false, 0); }}; // try to load from current path - if (!parseConfig(m_paths.VKBindings())) + auto [res, key] = parseConfig(m_paths.VKBindings()); + if (!res) { // if failed, try to look for old config auto oldPath = m_paths.CETRoot() / "hotkeys.json"; - if (parseConfig(oldPath, true)) + const auto [resOld, keyOld] = parseConfig(oldPath, true); + if (resOld) { // old config found and parsed, remove it and save it to current location remove(oldPath); Save(); + + // replace former res and key with ones from old config + res = resOld; + key = keyOld; } } m_pOverlay = &aOverlay; m_initialized = true; + + return res && key; } void VKBindings::Save() diff --git a/src/VKBindings.h b/src/VKBindings.h index ae0f4d7f..25a97c3c 100644 --- a/src/VKBindings.h +++ b/src/VKBindings.h @@ -72,11 +72,12 @@ constexpr USHORT VKBC_MWHEELDOWN { RI_MOUSE_WHEEL | 0 }; constexpr USHORT VKBC_MWHEELRIGHT { RI_MOUSE_HWHEEL | 1 }; constexpr USHORT VKBC_MWHEELLEFT { RI_MOUSE_HWHEEL | 0 }; +struct Options; struct Overlay; struct D3D12; struct VKBindings { - VKBindings(Paths& aPaths); + VKBindings(Paths& aPaths, const Options& aOptions); ~VKBindings() = default; [[nodiscard]] bool IsInitialized() const noexcept; @@ -87,7 +88,7 @@ struct VKBindings static uint64_t EncodeVKCodeBind(VKCodeBindDecoded aVKCodeBindDecoded); static const char* GetSpecialKeyName(USHORT aVKCode); - void Load(const Overlay& aOverlay); + bool Load(const Overlay& aOverlay); void Save(); void Update(); @@ -140,6 +141,7 @@ struct VKBindings bool m_initialized{ false }; Paths& m_paths; + const Options& m_options; const Overlay* m_pOverlay{ nullptr }; size_t m_connectUpdate{ static_cast(-1) }; diff --git a/src/d3d12/D3D12.cpp b/src/d3d12/D3D12.cpp index 4abcb43f..4a5eb382 100644 --- a/src/d3d12/D3D12.cpp +++ b/src/d3d12/D3D12.cpp @@ -18,6 +18,12 @@ void D3D12::SetTrapInputInImGui(bool aEnabled) m_trapInputInImGui = aEnabled; } +void D3D12::DelayedSetTrapInputInImGui(bool aEnabled) +{ + m_delayedTrapInputState = aEnabled; + m_delayedTrapInput = true; +} + LRESULT D3D12::OnWndProc(HWND ahWnd, UINT auMsg, WPARAM awParam, LPARAM alParam) { auto& d3d12 = CET::Get().GetD3D12(); @@ -28,6 +34,12 @@ LRESULT D3D12::OnWndProc(HWND ahWnd, UINT auMsg, WPARAM awParam, LPARAM alParam) if (res) return res; + if (d3d12.m_delayedTrapInput) + { + d3d12.SetTrapInputInImGui(m_delayedTrapInputState); + d3d12.m_delayedTrapInput = false; + } + if (d3d12.m_trapInputInImGui) // TODO: look into io.WantCaptureMouse and io.WantCaptureKeyboard { // ignore mouse & keyboard events diff --git a/src/d3d12/D3D12.h b/src/d3d12/D3D12.h index bc47c94b..48598a02 100644 --- a/src/d3d12/D3D12.h +++ b/src/d3d12/D3D12.h @@ -15,8 +15,9 @@ struct D3D12 D3D12(Window& aWindow, Paths& aPaths, Options& aOptions); ~D3D12(); - + void SetTrapInputInImGui(bool aEnabled); + void DelayedSetTrapInputInImGui(bool aEnabled); [[nodiscard]] bool IsTrapInputInImGui() const noexcept { return m_trapInputInImGui; } [[nodiscard]] bool IsInitialized() const noexcept { return m_initialized; } [[nodiscard]] SIZE GetResolution() const noexcept { return m_outSize; } @@ -77,4 +78,7 @@ struct D3D12 Paths& m_paths; Window& m_window; Options& m_options; + + std::atomic_bool m_delayedTrapInput{ false }; + std::atomic_bool m_delayedTrapInputState{ false }; }; diff --git a/src/overlay/Overlay.cpp b/src/overlay/Overlay.cpp index e87023be..3b289f52 100644 --- a/src/overlay/Overlay.cpp +++ b/src/overlay/Overlay.cpp @@ -16,10 +16,9 @@ void Overlay::PostInitialize() { if (m_options.IsFirstLaunch) { + m_showFirstTimeModal = true; Toggle(); - m_activeWidgetID = WidgetID::SETTINGS; } - m_widgets[static_cast(m_activeWidgetID)]->OnEnable(); m_initialized = true; } } @@ -41,14 +40,8 @@ Settings& Overlay::GetSettings() void Overlay::Toggle() { - m_enabled = !m_enabled; - - auto& d3d12 = CET::Get().GetD3D12(); - d3d12.SetTrapInputInImGui(m_enabled); - - ClipToCenter(RED4ext::CGameEngine::Get()->unkC0); - - m_toggled = true; + if (!m_toggled) + m_toggled = true; } bool Overlay::IsEnabled() const noexcept @@ -58,29 +51,78 @@ bool Overlay::IsEnabled() const noexcept VKBind Overlay::GetBind() const noexcept { - return m_VKBOverlay; + return m_VKBIOverlay.Bind; } void Overlay::Update() { if (!m_initialized) return; - - // always check for this event in Update + if (m_toggled) { if (m_enabled) - m_vm.OnOverlayOpen(); + { + if (m_widgets[static_cast(m_activeWidgetID)]->OnDisable()) + { + m_vm.OnOverlayClose(); + m_toggled = false; + m_enabled = false; + } + } else - m_vm.OnOverlayClose(); - m_toggled = false; + { + if (m_widgets[static_cast(m_activeWidgetID)]->OnEnable()) + { + m_vm.OnOverlayOpen(); + m_toggled = false; + m_enabled = true; + } + } + + if (!m_toggled) + { + auto& d3d12 = CET::Get().GetD3D12(); + d3d12.DelayedSetTrapInputInImGui(m_enabled); + ClipToCenter(RED4ext::CGameEngine::Get()->unkC0); + } } if (!m_enabled) return; - auto& d3d12 = CET::Get().GetD3D12(); + if (m_options.IsFirstLaunch) + { + if (m_showFirstTimeModal) + { + assert(!m_VKBIOverlay.CodeBind); + assert(!m_VKBIOverlay.SavedCodeBind); + assert(!m_VKBIOverlay.IsBinding); + + ImGui::OpenPopup("CET First Time Setup"); + m_showFirstTimeModal = false; + } + if (ImGui::BeginPopupModal("CET First Time Setup", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) + { + ImGui::Text("Please, bind some key combination for toggling overlay!\nCombo can be composed from up to 4 keys."); + ImGui::Separator(); + + HelperWidgets::BindWidget(m_VKBIOverlay, m_VKBIOverlay.Bind.ID); + if (m_VKBIOverlay.CodeBind) + { + m_VKBIOverlay.Apply(); + m_bindings.Save(); + m_options.IsFirstLaunch = false; + ImGui::CloseCurrentPopup(); + } + + ImGui::EndPopup(); + } + return; + } + + auto& d3d12 = CET::Get().GetD3D12(); const SIZE resolution = d3d12.GetResolution(); ImGui::SetNextWindowPos(ImVec2(resolution.cx * 0.2f, resolution.cy * 0.2f), ImGuiCond_FirstUseEver); @@ -88,36 +130,31 @@ void Overlay::Update() ImGui::SetNextWindowSizeConstraints(ImVec2(420, 315), ImVec2(FLT_MAX, FLT_MAX)); if (ImGui::Begin("Cyber Engine Tweaks")) { - const ImVec2 zeroVec = {0, 0}; - - if (!m_options.IsFirstLaunch) + const ImVec2 cZeroVec = {0, 0}; + + SetActiveWidget(HelperWidgets::ToolbarWidget()); + + if (m_activeWidgetID == WidgetID::CONSOLE) { - const WidgetID selectedID = HelperWidgets::ToolbarWidget(); - if (selectedID < WidgetID::COUNT) - SetActiveWidget(selectedID); - - if (m_activeWidgetID == WidgetID::CONSOLE) - { - if (ImGui::BeginChild("Console", zeroVec, true)) - m_console.Update(); - ImGui::EndChild(); - } - if (m_activeWidgetID == WidgetID::BINDINGS) - { - if (ImGui::BeginChild("Bindings", zeroVec, true)) - m_bindings.Update(); - ImGui::EndChild(); - } - if (m_activeWidgetID == WidgetID::TWEAKDB) - { - if (ImGui::BeginChild("TweakDB Editor", zeroVec, true)) - m_tweakDBEditor.Update(); - ImGui::EndChild(); - } + if (ImGui::BeginChild("Console", cZeroVec, true)) + m_console.Update(); + ImGui::EndChild(); + } + if (m_activeWidgetID == WidgetID::BINDINGS) + { + if (ImGui::BeginChild("Bindings", cZeroVec, true)) + m_bindings.Update(); + ImGui::EndChild(); + } + if (m_activeWidgetID == WidgetID::TWEAKDB) + { + if (ImGui::BeginChild("TweakDB Editor", cZeroVec, true)) + m_tweakDBEditor.Update(); + ImGui::EndChild(); } if (m_activeWidgetID == WidgetID::SETTINGS) { - if (ImGui::BeginChild("Settings", zeroVec, true)) + if (ImGui::BeginChild("Settings", cZeroVec, true)) m_settings.Update(); ImGui::EndChild(); } @@ -186,9 +223,9 @@ void Overlay::Hook() Overlay::Overlay(D3D12& aD3D12, VKBindings& aBindings, Options& aOptions, LuaVM& aVm) : m_console(aVm) , m_bindings(aBindings, *this, aVm) - , m_settings(*this, aBindings, aOptions) + , m_settings(aOptions) , m_tweakDBEditor(aVm) - , m_VKBOverlay{"cet.overlay_key", "Overlay Key", [this]() { Toggle(); }} + , m_VKBIOverlay{{"cet.overlay_key", "Overlay Key", [this]() { Toggle(); }}, 0, 0, false} , m_d3d12(aD3D12) , m_options(aOptions) , m_vm(aVm) @@ -200,7 +237,7 @@ Overlay::Overlay(D3D12& aD3D12, VKBindings& aBindings, Options& aOptions, LuaVM& Hook(); - aBindings.Load(*this); + m_options.IsFirstLaunch = !aBindings.Load(*this); m_connectInitialized = aD3D12.OnInitialized.Connect([this]() { PostInitialize(); }); m_connectUpdate = aD3D12.OnUpdate.Connect([this]() { Update(); }); @@ -214,12 +251,15 @@ Overlay::~Overlay() void Overlay::SetActiveWidget(WidgetID aNewActive) { - if (m_activeWidgetID != aNewActive) + if (aNewActive < WidgetID::COUNT) + m_nextActiveWidgetID = aNewActive; + + if (m_activeWidgetID != m_nextActiveWidgetID) { - if (m_activeWidgetID < WidgetID::COUNT) - m_widgets[static_cast(m_activeWidgetID)]->OnDisable(); - m_activeWidgetID = aNewActive; - if (m_activeWidgetID < WidgetID::COUNT) - m_widgets[static_cast(m_activeWidgetID)]->OnEnable(); + if (m_widgets[static_cast(m_activeWidgetID)]->OnDisable()) + { + if (m_widgets[static_cast(m_nextActiveWidgetID)]->OnEnable()) + m_activeWidgetID = m_nextActiveWidgetID; + } } } diff --git a/src/overlay/Overlay.h b/src/overlay/Overlay.h index b61dbb0a..8b2903d5 100644 --- a/src/overlay/Overlay.h +++ b/src/overlay/Overlay.h @@ -50,12 +50,15 @@ struct Overlay TClipToCenter* m_realClipToCenter{ nullptr }; - WidgetID m_activeWidgetID{WidgetID::CONSOLE }; + WidgetID m_activeWidgetID{ WidgetID::CONSOLE }; + WidgetID m_nextActiveWidgetID{ WidgetID::CONSOLE }; std::atomic_bool m_enabled{ false }; std::atomic_bool m_toggled{ false }; bool m_initialized{ false }; - VKBind m_VKBOverlay; + VKBindInfo m_VKBIOverlay; + + std::atomic_bool m_showFirstTimeModal{ false }; D3D12& m_d3d12; Options& m_options; diff --git a/src/overlay/widgets/Bindings.cpp b/src/overlay/widgets/Bindings.cpp index 9ad8ec6f..6959f07c 100644 --- a/src/overlay/widgets/Bindings.cpp +++ b/src/overlay/widgets/Bindings.cpp @@ -13,16 +13,60 @@ Bindings::Bindings(VKBindings& aBindings, Overlay& aOverlay, LuaVM& aVm) { } -void Bindings::OnEnable() +bool Bindings::OnEnable() { - Load(); - - m_bindings.StopRecordingBind(); + if (!m_enabled) + { + m_bindings.StopRecordingBind(); + Load(); + m_enabled = true; + } + return m_enabled; } -void Bindings::OnDisable() +bool Bindings::OnDisable() { - m_bindings.StopRecordingBind(); + if (m_enabled) + { + m_bindings.StopRecordingBind(); + + if (m_madeChanges) + { + if (!m_showChangesModal) + { + ImGui::OpenPopup("Unapplied changes"); + m_showChangesModal = true; + } + + if (ImGui::BeginPopupModal("Unapplied changes", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) + { + ImGui::Text("You have some unsaved changes.\nDo you wish to apply them or discard them?"); + ImGui::Separator(); + + if (ImGui::Button("Apply", ImVec2(120, 0))) + { + Save(); + m_showChangesModal = false; + m_madeChanges = false; + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("Discard", ImVec2(120, 0))) + { + Load(); + m_showChangesModal = false; + m_madeChanges = false; + ImGui::CloseCurrentPopup(); + } + ImGui::SetItemDefaultFocus(); + + ImGui::EndPopup(); + } + } + + m_enabled = m_madeChanges; + } + return !m_enabled; } void Bindings::Update() @@ -35,30 +79,28 @@ void Bindings::Update() ImGui::Spacing(); - if (ImGui::BeginChild("##BINDINGS_ACTUAL", ImVec2(0,0), true)) + if (ImGui::BeginChild("##BINDINGS")) { - if (m_vkBindInfos.empty()) - ImGui::Text("Looks empty here... Try to load some mod with bindings support!"); - else + // reset dirty state + m_madeChanges = false; + + std::string_view prevMod = ""; + for (auto& vkBindInfo : m_vkBindInfos) { - std::string_view prevMod = ""; - for (auto& vkBindInfo : m_vkBindInfos) + std::string_view curMod = vkBindInfo.Bind.ID; + curMod = curMod.substr(0, curMod.find('.')); + if (prevMod != curMod) { - std::string_view curMod = vkBindInfo.Bind.ID; - curMod = curMod.substr(0, curMod.find('.')); - if (prevMod != curMod) - { - if (!prevMod.empty()) - ImGui::Spacing(); + if (!prevMod.empty()) + ImGui::Spacing(); - std::string curModStr{curMod}; - ImGui::Text(curModStr.c_str()); + std::string curModStr { curMod }; + ImGui::Text(curModStr.c_str()); - prevMod = curMod; - } - - HelperWidgets::BindWidget(vkBindInfo, m_overlay.GetBind().ID); + prevMod = curMod; } + + m_madeChanges |= HelperWidgets::BindWidget(vkBindInfo, m_overlay.GetBind().ID); } } ImGui::EndChild(); diff --git a/src/overlay/widgets/Bindings.h b/src/overlay/widgets/Bindings.h index 46053868..d0ab7a68 100644 --- a/src/overlay/widgets/Bindings.h +++ b/src/overlay/widgets/Bindings.h @@ -10,8 +10,8 @@ struct Bindings : Widget Bindings(VKBindings& aBindings, Overlay& aOverlay, LuaVM& aVm); ~Bindings() override = default; - void OnEnable() override; - void OnDisable() override; + bool OnEnable() override; + bool OnDisable() override; void Update() override; void Load(); @@ -22,4 +22,8 @@ struct Bindings : Widget VKBindings& m_bindings; Overlay& m_overlay; LuaVM& m_vm; + + bool m_enabled{ false }; + bool m_madeChanges{ false }; + bool m_showChangesModal{ false }; }; diff --git a/src/overlay/widgets/Console.cpp b/src/overlay/widgets/Console.cpp index a816c80d..e82ef8d3 100644 --- a/src/overlay/widgets/Console.cpp +++ b/src/overlay/widgets/Console.cpp @@ -14,13 +14,15 @@ Console::Console(LuaVM& aVm) spdlog::get("scripting")->sinks().push_back(consoleSink); } -void Console::OnEnable() +bool Console::OnEnable() { m_focusConsoleInput = true; + return true; } -void Console::OnDisable() +bool Console::OnDisable() { + return true; } int Console::HandleConsoleHistory(ImGuiInputTextCallbackData* apData) @@ -50,9 +52,9 @@ int Console::HandleConsoleHistory(ImGuiInputTextCallbackData* apData) if (pStr) { - std::memcpy(apData->Buf, pStr->c_str(), pStr->size()); + std::memcpy(apData->Buf, pStr->c_str(), pStr->length() + 1); apData->BufDirty = true; - apData->BufTextLen = pStr->size(); + apData->BufTextLen = pStr->length(); apData->CursorPos = apData->BufTextLen; } diff --git a/src/overlay/widgets/Console.h b/src/overlay/widgets/Console.h index eecd37b1..2bca00f5 100644 --- a/src/overlay/widgets/Console.h +++ b/src/overlay/widgets/Console.h @@ -9,8 +9,8 @@ struct Console : Widget Console(LuaVM& aVm); ~Console() override = default; - void OnEnable() override; - void OnDisable() override; + bool OnEnable() override; + bool OnDisable() override; void Update() override; void Log(const std::string& acpText); diff --git a/src/overlay/widgets/HelperWidgets.cpp b/src/overlay/widgets/HelperWidgets.cpp index 1b663500..035c4bf0 100644 --- a/src/overlay/widgets/HelperWidgets.cpp +++ b/src/overlay/widgets/HelperWidgets.cpp @@ -27,7 +27,7 @@ namespace HelperWidgets return activeID; } - void BindWidget(VKBindInfo& aVKBindInfo, const std::string& acId) + bool BindWidget(VKBindInfo& aVKBindInfo, const std::string& acIdOverlay) { VKBindings& vkb { CET::Get().GetBindings() }; @@ -66,7 +66,7 @@ namespace HelperWidgets } ImGui::PopID(); - if (aVKBindInfo.CodeBind && (aVKBindInfo.Bind.ID != acId)) // make an exception for Overlay key + if (aVKBindInfo.CodeBind && (aVKBindInfo.Bind.ID != acIdOverlay)) // make an exception for Overlay key { ImGui::PushID(&aVKBindInfo.Bind.ID[1]); // same as PushID before, just make pointer a bit bigger :) ImGui::SameLine(); @@ -82,9 +82,11 @@ namespace HelperWidgets } ImGui::PopID(); } + + return (aVKBindInfo.CodeBind != aVKBindInfo.SavedCodeBind); } - void BoolWidget(const std::string& label, bool& current, bool saved) + bool BoolWidget(const std::string& label, bool& current, bool saved) { ImVec4 curTextColor = ImGui::GetStyleColorVec4(ImGuiCol_Text); if (current != saved) @@ -97,6 +99,8 @@ namespace HelperWidgets ImGui::SameLine(); ImGui::Checkbox(("##" + label).c_str(), ¤t); + + return (current != saved); } } diff --git a/src/overlay/widgets/HelperWidgets.h b/src/overlay/widgets/HelperWidgets.h index 4970615e..b25c8427 100644 --- a/src/overlay/widgets/HelperWidgets.h +++ b/src/overlay/widgets/HelperWidgets.h @@ -5,6 +5,6 @@ namespace HelperWidgets { WidgetID ToolbarWidget(); -void BindWidget(VKBindInfo& aVKBindInfo, const std::string& acId); -void BoolWidget(const std::string& label, bool& current, bool saved); +bool BindWidget(VKBindInfo& aVKBindInfo, const std::string& acIdOverlay); +bool BoolWidget(const std::string& label, bool& current, bool saved); } \ No newline at end of file diff --git a/src/overlay/widgets/Settings.cpp b/src/overlay/widgets/Settings.cpp index b11bd872..5220ab9e 100644 --- a/src/overlay/widgets/Settings.cpp +++ b/src/overlay/widgets/Settings.cpp @@ -4,25 +4,62 @@ #include "HelperWidgets.h" -#include - -Settings::Settings(Overlay& aOverlay, VKBindings& aBindings, Options& aOptions) - : m_bindings(aBindings) - , m_overlay(aOverlay) - , m_options(aOptions) +Settings::Settings(Options& aOptions) + : m_options(aOptions) { } -void Settings::OnEnable() +bool Settings::OnEnable() { - Load(); - - m_bindings.StopRecordingBind(); + if (!m_enabled) + { + Load(); + m_enabled = true; + } + return m_enabled; } -void Settings::OnDisable() +bool Settings::OnDisable() { - m_bindings.StopRecordingBind(); + if (m_enabled) + { + if (m_madeChanges) + { + if (!m_showChangesModal) + { + ImGui::OpenPopup("Unapplied changes"); + m_showChangesModal = true; + } + + if (ImGui::BeginPopupModal("Unapplied changes", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) + { + ImGui::Text("You have some unsaved changes.\nDo you wish to apply them or discard them?"); + ImGui::Separator(); + + if (ImGui::Button("Apply", ImVec2(120, 0))) + { + Save(); + m_showChangesModal = false; + m_madeChanges = false; + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("Discard", ImVec2(120, 0))) + { + Load(); + m_showChangesModal = false; + m_madeChanges = false; + ImGui::CloseCurrentPopup(); + } + ImGui::SetItemDefaultFocus(); + + ImGui::EndPopup(); + } + } + + m_enabled = m_madeChanges; + } + return !m_enabled; } void Settings::Update() @@ -37,40 +74,55 @@ void Settings::Update() ResetToDefaults(); ImGui::Spacing(); - - if (!m_options.IsFirstLaunch) - ImGui::BeginChild("##SETTINGS_ACTUAL", ImVec2(0,0), true); - - HelperWidgets::BindWidget(m_overlayKeyBindInfo, m_overlay.GetBind().ID); - - HelperWidgets::BoolWidget("AMD SMT Patch:", m_patchAmdSmt, m_options.PatchAmdSmt); - HelperWidgets::BoolWidget("Enable Debug Menu:", m_patchEnableDebug, m_options.PatchEnableDebug); - HelperWidgets::BoolWidget("Remove Pedestrians:", m_patchRemovePedestrians, m_options.PatchRemovePedestrians); - HelperWidgets::BoolWidget("Disable Async Compute:", m_patchAsyncCompute, m_options.PatchAsyncCompute); - HelperWidgets::BoolWidget("Disable Antialiasing:", m_patchAntialiasing, m_options.PatchAntialiasing); - HelperWidgets::BoolWidget("Skip Start Menu:", m_patchSkipStartMenu, m_options.PatchSkipStartMenu); - HelperWidgets::BoolWidget("Suppress Intro Movies:", m_patchDisableIntroMovies, m_options.PatchDisableIntroMovies); - HelperWidgets::BoolWidget("Disable Vignette:", m_patchDisableVignette, m_options.PatchDisableVignette); - HelperWidgets::BoolWidget("Disable Boundary Teleport:", m_patchDisableBoundaryTeleport, m_options.PatchDisableBoundaryTeleport); - HelperWidgets::BoolWidget("Disable V-Sync (Windows 7 only):", m_patchDisableWin7Vsync, m_options.PatchDisableWin7Vsync); - HelperWidgets::BoolWidget("Dump Game Options:", m_dumpGameOptions, m_options.DumpGameOptions); - - if (!m_options.IsFirstLaunch) - ImGui::EndChild(); - - // this needs to be performed at the end! - if (m_options.IsFirstLaunch && (m_overlayKeyBindInfo.SavedCodeBind != m_overlayKeyBindInfo.CodeBind)) + + if (ImGui::BeginTabBar("##SETTINGS", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton | ImGuiTabBarFlags_NoTooltip)) { - Save(); - Load(); + // reset dirty state + m_madeChanges = false; + + if (ImGui::BeginTabItem("Patches")) + { + if (ImGui::BeginChild("##SETTINGS_PATCHES")) + { + m_madeChanges |= HelperWidgets::BoolWidget("AMD SMT Patch:", m_patchAmdSmt, m_options.PatchAmdSmt); + m_madeChanges |= HelperWidgets::BoolWidget("Remove Pedestrians:", m_patchRemovePedestrians, m_options.PatchRemovePedestrians); + m_madeChanges |= HelperWidgets::BoolWidget("Disable Async Compute:", m_patchAsyncCompute, m_options.PatchAsyncCompute); + m_madeChanges |= HelperWidgets::BoolWidget("Disable Antialiasing:", m_patchAntialiasing, m_options.PatchAntialiasing); + m_madeChanges |= HelperWidgets::BoolWidget("Skip Start Menu:", m_patchSkipStartMenu, m_options.PatchSkipStartMenu); + m_madeChanges |= HelperWidgets::BoolWidget("Suppress Intro Movies:", m_patchDisableIntroMovies, m_options.PatchDisableIntroMovies); + m_madeChanges |= HelperWidgets::BoolWidget("Disable Vignette:", m_patchDisableVignette, m_options.PatchDisableVignette); + m_madeChanges |= HelperWidgets::BoolWidget("Disable Boundary Teleport:", m_patchDisableBoundaryTeleport, m_options.PatchDisableBoundaryTeleport); + m_madeChanges |= HelperWidgets::BoolWidget("Disable V-Sync (Windows 7 only):", m_patchDisableWin7Vsync, m_options.PatchDisableWin7Vsync); + } + ImGui::EndChild(); + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Dev")) + { + if (ImGui::BeginChild("##SETTINGS_DEV")) + { + + HelperWidgets::BoolWidget("Draw ImGui Diagnostic Window:", m_drawImGuiDiagnosticWindow, m_drawImGuiDiagnosticWindow); + if (m_drawImGuiDiagnosticWindow) + ImGui::ShowMetricsWindow(&m_drawImGuiDiagnosticWindow); + + m_madeChanges |= HelperWidgets::BoolWidget("Remove Dead Bindings:", m_removeDeadBindings, m_options.RemoveDeadBindings); + m_madeChanges |= HelperWidgets::BoolWidget("Enable Debug Menu:", m_patchEnableDebug, m_options.PatchEnableDebug); + m_madeChanges |= HelperWidgets::BoolWidget("Dump Game Options:", m_dumpGameOptions, m_options.DumpGameOptions); + } + ImGui::EndChild(); + ImGui::EndTabItem(); + } + + ImGui::EndTabBar(); } } void Settings::Load() { m_options.Load(); - - m_overlayKeyBindInfo.Fill(m_options.OverlayKeyBind, m_overlay.GetBind()); + m_patchEnableDebug = m_options.PatchEnableDebug; m_patchRemovePedestrians = m_options.PatchRemovePedestrians; m_patchAsyncCompute = m_options.PatchAsyncCompute; @@ -82,16 +134,11 @@ void Settings::Load() m_patchDisableBoundaryTeleport = m_options.PatchDisableBoundaryTeleport; m_patchDisableWin7Vsync = m_options.PatchDisableWin7Vsync; m_dumpGameOptions = m_options.DumpGameOptions; + m_removeDeadBindings = m_options.RemoveDeadBindings; } -void Settings::Save() +void Settings::Save() const { - if (m_overlayKeyBindInfo.SavedCodeBind != m_overlayKeyBindInfo.CodeBind) - { - m_options.OverlayKeyBind = m_overlayKeyBindInfo.Apply(); - m_bindings.Save(); // also save bindings in this case! - } - m_options.PatchEnableDebug = m_patchEnableDebug; m_options.PatchRemovePedestrians = m_patchRemovePedestrians; m_options.PatchAsyncCompute = m_patchAsyncCompute; @@ -103,6 +150,7 @@ void Settings::Save() m_options.PatchDisableBoundaryTeleport = m_patchDisableBoundaryTeleport; m_options.PatchDisableWin7Vsync = m_patchDisableWin7Vsync; m_options.DumpGameOptions = m_dumpGameOptions; + m_options.RemoveDeadBindings = m_removeDeadBindings; m_options.Save(); } diff --git a/src/overlay/widgets/Settings.h b/src/overlay/widgets/Settings.h index f2d12f43..4c888ced 100644 --- a/src/overlay/widgets/Settings.h +++ b/src/overlay/widgets/Settings.h @@ -8,19 +8,18 @@ struct Options; struct Settings : Widget { - Settings(Overlay& aOverlay, VKBindings& aBindings, Options& aOptions); + Settings(Options& aOptions); ~Settings() override = default; - void OnEnable() override; - void OnDisable() override; + bool OnEnable() override; + bool OnDisable() override; void Update() override; void Load(); - void Save(); + void Save() const; void ResetToDefaults(); private: - VKBindInfo m_overlayKeyBindInfo{ }; bool m_patchEnableDebug{ false }; bool m_patchRemovePedestrians{ false }; bool m_patchAsyncCompute{ false }; @@ -32,8 +31,11 @@ struct Settings : Widget bool m_patchDisableBoundaryTeleport{ false }; bool m_patchDisableWin7Vsync{ false }; bool m_dumpGameOptions{ false }; - bool m_telemetry{ true }; - VKBindings& m_bindings; - Overlay& m_overlay; + bool m_drawImGuiDiagnosticWindow{ false }; + bool m_removeDeadBindings{ true }; Options& m_options; + + bool m_enabled{ false }; + bool m_madeChanges{ false }; + bool m_showChangesModal{ false }; }; diff --git a/src/overlay/widgets/TweakDBEditor.cpp b/src/overlay/widgets/TweakDBEditor.cpp index b7543379..89c4a5a6 100644 --- a/src/overlay/widgets/TweakDBEditor.cpp +++ b/src/overlay/widgets/TweakDBEditor.cpp @@ -362,12 +362,14 @@ TweakDBEditor::TweakDBEditor(LuaVM& aVm) { } -void TweakDBEditor::OnEnable() +bool TweakDBEditor::OnEnable() { + return true; } -void TweakDBEditor::OnDisable() +bool TweakDBEditor::OnDisable() { + return true; } void TweakDBEditor::Update() diff --git a/src/overlay/widgets/TweakDBEditor.h b/src/overlay/widgets/TweakDBEditor.h index 08ce189f..90bf4a28 100644 --- a/src/overlay/widgets/TweakDBEditor.h +++ b/src/overlay/widgets/TweakDBEditor.h @@ -9,8 +9,8 @@ struct TweakDBEditor : Widget TweakDBEditor(LuaVM& aVm); ~TweakDBEditor() override = default; - void OnEnable() override; - void OnDisable() override; + bool OnEnable() override; + bool OnDisable() override; void Update() override; protected: diff --git a/src/overlay/widgets/Widget.h b/src/overlay/widgets/Widget.h index 8f7ab916..d1264230 100644 --- a/src/overlay/widgets/Widget.h +++ b/src/overlay/widgets/Widget.h @@ -13,7 +13,7 @@ struct Widget { virtual ~Widget() = default; - virtual void OnEnable() = 0; - virtual void OnDisable() = 0; + virtual bool OnEnable() = 0; + virtual bool OnDisable() = 0; virtual void Update() = 0; }; diff --git a/src/scripting/LuaVM.cpp b/src/scripting/LuaVM.cpp index 3cd1c286..84053950 100644 --- a/src/scripting/LuaVM.cpp +++ b/src/scripting/LuaVM.cpp @@ -27,7 +27,10 @@ void LuaVM::Update(float aDeltaTime) if (!m_initialized) return; - + + if (m_options.IsFirstLaunch) + return; + m_scripting.TriggerOnUpdate(aDeltaTime); m_scripting.TriggerOnDraw(); } diff --git a/src/scripting/LuaVM.h b/src/scripting/LuaVM.h index bc249266..26687157 100644 --- a/src/scripting/LuaVM.h +++ b/src/scripting/LuaVM.h @@ -85,6 +85,7 @@ struct LuaVM bool m_initialized{ false }; + Options& m_options; D3D12& m_d3d12; size_t m_connectUpdate; }; diff --git a/src/scripting/LuaVM_Hooks.cpp b/src/scripting/LuaVM_Hooks.cpp index 6ad8e83e..85278e01 100644 --- a/src/scripting/LuaVM_Hooks.cpp +++ b/src/scripting/LuaVM_Hooks.cpp @@ -80,6 +80,7 @@ void LuaVM::HookLogChannel(RED4ext::IScriptable*, RED4ext::CStackFrame* apStack, LuaVM::LuaVM(Paths& aPaths, VKBindings& aBindings, D3D12& aD3D12, Options& aOptions) : m_scripting(aPaths, aBindings, aD3D12, aOptions) + , m_options(aOptions) , m_d3d12(aD3D12) { Hook(aOptions); From 38390071ea79e407e6640ed8b1815a3fd91910aa Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Tue, 30 Mar 2021 17:25:28 +0200 Subject: [PATCH 02/35] Pull "Unapplied Changes" popup into helper widgets --- src/overlay/widgets/Bindings.cpp | 82 ++++++++++----------------- src/overlay/widgets/Bindings.h | 7 ++- src/overlay/widgets/HelperWidgets.cpp | 39 +++++++++++++ src/overlay/widgets/HelperWidgets.h | 4 ++ src/overlay/widgets/Settings.cpp | 37 +----------- src/overlay/widgets/Settings.h | 6 +- 6 files changed, 86 insertions(+), 89 deletions(-) diff --git a/src/overlay/widgets/Bindings.cpp b/src/overlay/widgets/Bindings.cpp index 6959f07c..3d5e7c4c 100644 --- a/src/overlay/widgets/Bindings.cpp +++ b/src/overlay/widgets/Bindings.cpp @@ -1,7 +1,6 @@ #include #include "Bindings.h" -#include "HelperWidgets.h" #include "overlay/Overlay.h" #include @@ -29,41 +28,7 @@ bool Bindings::OnDisable() if (m_enabled) { m_bindings.StopRecordingBind(); - - if (m_madeChanges) - { - if (!m_showChangesModal) - { - ImGui::OpenPopup("Unapplied changes"); - m_showChangesModal = true; - } - - if (ImGui::BeginPopupModal("Unapplied changes", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) - { - ImGui::Text("You have some unsaved changes.\nDo you wish to apply them or discard them?"); - ImGui::Separator(); - - if (ImGui::Button("Apply", ImVec2(120, 0))) - { - Save(); - m_showChangesModal = false; - m_madeChanges = false; - ImGui::CloseCurrentPopup(); - } - ImGui::SameLine(); - if (ImGui::Button("Discard", ImVec2(120, 0))) - { - Load(); - m_showChangesModal = false; - m_madeChanges = false; - ImGui::CloseCurrentPopup(); - } - ImGui::SetItemDefaultFocus(); - - ImGui::EndPopup(); - } - } - + m_madeChanges = (HelperWidgets::UnappliedChangesPopup(m_openChangesModal, m_madeChanges, m_saveCB, m_loadCB) == 0); m_enabled = m_madeChanges; } return !m_enabled; @@ -81,27 +46,35 @@ void Bindings::Update() if (ImGui::BeginChild("##BINDINGS")) { - // reset dirty state - m_madeChanges = false; + if (!m_luaVMReady && m_vm.IsInitialized()) + Load(); - std::string_view prevMod = ""; - for (auto& vkBindInfo : m_vkBindInfos) + if (m_luaVMReady) { - std::string_view curMod = vkBindInfo.Bind.ID; - curMod = curMod.substr(0, curMod.find('.')); - if (prevMod != curMod) + // reset dirty state + m_madeChanges = false; + + std::string_view prevMod = ""; + for (auto& vkBindInfo : m_vkBindInfos) { - if (!prevMod.empty()) - ImGui::Spacing(); + std::string_view curMod = vkBindInfo.Bind.ID; + curMod = curMod.substr(0, curMod.find('.')); + if (prevMod != curMod) + { + if (!prevMod.empty()) + ImGui::Spacing(); - std::string curModStr { curMod }; - ImGui::Text(curModStr.c_str()); + std::string curModStr{curMod}; + ImGui::Text(curModStr.c_str()); - prevMod = curMod; - } + prevMod = curMod; + } - m_madeChanges |= HelperWidgets::BindWidget(vkBindInfo, m_overlay.GetBind().ID); + m_madeChanges |= HelperWidgets::BindWidget(vkBindInfo, m_overlay.GetBind().ID); + } } + else + ImGui::Text("LuaVM is not yet initialized!"); } ImGui::EndChild(); @@ -110,11 +83,14 @@ void Bindings::Update() void Bindings::Load() { if (!m_vm.IsInitialized()) + { + m_luaVMReady = false; return; + } m_bindings.Load(m_overlay); - m_vkBindInfos = m_bindings.InitializeMods(m_vm.GetBinds()); + m_luaVMReady = true; } void Bindings::Save() @@ -122,7 +98,11 @@ void Bindings::Save() m_bindings.Save(); if (!m_vm.IsInitialized()) + { + m_luaVMReady = false; return; + } m_vkBindInfos = m_bindings.InitializeMods(m_vm.GetBinds()); + m_luaVMReady = true; } diff --git a/src/overlay/widgets/Bindings.h b/src/overlay/widgets/Bindings.h index d0ab7a68..fdeabd69 100644 --- a/src/overlay/widgets/Bindings.h +++ b/src/overlay/widgets/Bindings.h @@ -1,6 +1,7 @@ #pragma once #include "Widget.h" +#include "HelperWidgets.h" struct Overlay; struct LuaVM; @@ -22,8 +23,12 @@ struct Bindings : Widget VKBindings& m_bindings; Overlay& m_overlay; LuaVM& m_vm; + + HelperWidgets::TUCHPSave m_saveCB { [this](){ Save(); } }; + HelperWidgets::TUCHPLoad m_loadCB { [this](){ Load(); } }; + bool m_luaVMReady{ false }; bool m_enabled{ false }; bool m_madeChanges{ false }; - bool m_showChangesModal{ false }; + bool m_openChangesModal{ true }; }; diff --git a/src/overlay/widgets/HelperWidgets.cpp b/src/overlay/widgets/HelperWidgets.cpp index 035c4bf0..ea307478 100644 --- a/src/overlay/widgets/HelperWidgets.cpp +++ b/src/overlay/widgets/HelperWidgets.cpp @@ -103,4 +103,43 @@ namespace HelperWidgets return (current != saved); } + int32_t UnappliedChangesPopup(bool& aFirstTime, bool aMadeChanges, TUCHPSave aSaveCB, TUCHPLoad aLoadCB) + { + if (aMadeChanges) + { + int32_t res = 0; + if (aFirstTime) + { + ImGui::OpenPopup("Unapplied changes"); + aFirstTime = false; + } + + if (ImGui::BeginPopupModal("Unapplied changes", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) + { + ImGui::Text("You have some unsaved changes.\nDo you wish to apply them or discard them?"); + ImGui::Separator(); + + if (ImGui::Button("Apply", ImVec2(120, 0))) + { + aSaveCB(); + res = 1; + aFirstTime = true; + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("Discard", ImVec2(120, 0))) + { + aLoadCB(); + res = -1; + aFirstTime = true; + ImGui::CloseCurrentPopup(); + } + ImGui::SetItemDefaultFocus(); + + ImGui::EndPopup(); + } + return res; + } + return 1; // no changes, same as if we were to Apply + } } diff --git a/src/overlay/widgets/HelperWidgets.h b/src/overlay/widgets/HelperWidgets.h index b25c8427..d5f72224 100644 --- a/src/overlay/widgets/HelperWidgets.h +++ b/src/overlay/widgets/HelperWidgets.h @@ -7,4 +7,8 @@ namespace HelperWidgets WidgetID ToolbarWidget(); bool BindWidget(VKBindInfo& aVKBindInfo, const std::string& acIdOverlay); bool BoolWidget(const std::string& label, bool& current, bool saved); + +using TUCHPSave = std::function; +using TUCHPLoad = std::function; +int32_t UnappliedChangesPopup(bool& aFirstTime, bool aMadeChanges, TUCHPSave aSaveCB, TUCHPLoad aLoadCB); } \ No newline at end of file diff --git a/src/overlay/widgets/Settings.cpp b/src/overlay/widgets/Settings.cpp index 5220ab9e..f404aee7 100644 --- a/src/overlay/widgets/Settings.cpp +++ b/src/overlay/widgets/Settings.cpp @@ -2,8 +2,6 @@ #include "Settings.h" -#include "HelperWidgets.h" - Settings::Settings(Options& aOptions) : m_options(aOptions) { @@ -23,40 +21,7 @@ bool Settings::OnDisable() { if (m_enabled) { - if (m_madeChanges) - { - if (!m_showChangesModal) - { - ImGui::OpenPopup("Unapplied changes"); - m_showChangesModal = true; - } - - if (ImGui::BeginPopupModal("Unapplied changes", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) - { - ImGui::Text("You have some unsaved changes.\nDo you wish to apply them or discard them?"); - ImGui::Separator(); - - if (ImGui::Button("Apply", ImVec2(120, 0))) - { - Save(); - m_showChangesModal = false; - m_madeChanges = false; - ImGui::CloseCurrentPopup(); - } - ImGui::SameLine(); - if (ImGui::Button("Discard", ImVec2(120, 0))) - { - Load(); - m_showChangesModal = false; - m_madeChanges = false; - ImGui::CloseCurrentPopup(); - } - ImGui::SetItemDefaultFocus(); - - ImGui::EndPopup(); - } - } - + m_madeChanges = (HelperWidgets::UnappliedChangesPopup(m_openChangesModal, m_madeChanges, m_saveCB, m_loadCB) == 0); m_enabled = m_madeChanges; } return !m_enabled; diff --git a/src/overlay/widgets/Settings.h b/src/overlay/widgets/Settings.h index 4c888ced..7307c499 100644 --- a/src/overlay/widgets/Settings.h +++ b/src/overlay/widgets/Settings.h @@ -1,6 +1,7 @@ #pragma once #include "Widget.h" +#include "HelperWidgets.h" struct VKBindings; struct Overlay; @@ -35,7 +36,10 @@ struct Settings : Widget bool m_removeDeadBindings{ true }; Options& m_options; + HelperWidgets::TUCHPSave m_saveCB{[this]() { Save(); }}; + HelperWidgets::TUCHPLoad m_loadCB{[this]() { Load(); }}; + bool m_enabled{ false }; bool m_madeChanges{ false }; - bool m_showChangesModal{ false }; + bool m_openChangesModal{ true }; }; From 9c84b57c4f76b8e6479828957aa64a790c9f6e82 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Tue, 30 Mar 2021 17:31:27 +0200 Subject: [PATCH 03/35] Make BindWidget more general --- src/overlay/Overlay.cpp | 2 +- src/overlay/widgets/Bindings.cpp | 3 ++- src/overlay/widgets/Bindings.h | 4 +++- src/overlay/widgets/HelperWidgets.cpp | 4 ++-- src/overlay/widgets/HelperWidgets.h | 2 +- src/overlay/widgets/Settings.h | 4 ++-- 6 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/overlay/Overlay.cpp b/src/overlay/Overlay.cpp index 3b289f52..1fb87cf7 100644 --- a/src/overlay/Overlay.cpp +++ b/src/overlay/Overlay.cpp @@ -108,7 +108,7 @@ void Overlay::Update() ImGui::Text("Please, bind some key combination for toggling overlay!\nCombo can be composed from up to 4 keys."); ImGui::Separator(); - HelperWidgets::BindWidget(m_VKBIOverlay, m_VKBIOverlay.Bind.ID); + HelperWidgets::BindWidget(m_VKBIOverlay, false); if (m_VKBIOverlay.CodeBind) { m_VKBIOverlay.Apply(); diff --git a/src/overlay/widgets/Bindings.cpp b/src/overlay/widgets/Bindings.cpp index 3d5e7c4c..b8ae38cb 100644 --- a/src/overlay/widgets/Bindings.cpp +++ b/src/overlay/widgets/Bindings.cpp @@ -9,6 +9,7 @@ Bindings::Bindings(VKBindings& aBindings, Overlay& aOverlay, LuaVM& aVm) : m_bindings(aBindings) , m_overlay(aOverlay) , m_vm(aVm) + , m_overlayKeyID(m_overlay.GetBind().ID) { } @@ -70,7 +71,7 @@ void Bindings::Update() prevMod = curMod; } - m_madeChanges |= HelperWidgets::BindWidget(vkBindInfo, m_overlay.GetBind().ID); + m_madeChanges |= HelperWidgets::BindWidget(vkBindInfo, (vkBindInfo.Bind.ID != m_overlayKeyID)); } } else diff --git a/src/overlay/widgets/Bindings.h b/src/overlay/widgets/Bindings.h index fdeabd69..c8bd1ec0 100644 --- a/src/overlay/widgets/Bindings.h +++ b/src/overlay/widgets/Bindings.h @@ -23,7 +23,9 @@ struct Bindings : Widget VKBindings& m_bindings; Overlay& m_overlay; LuaVM& m_vm; - + + std::string m_overlayKeyID; + HelperWidgets::TUCHPSave m_saveCB { [this](){ Save(); } }; HelperWidgets::TUCHPLoad m_loadCB { [this](){ Load(); } }; diff --git a/src/overlay/widgets/HelperWidgets.cpp b/src/overlay/widgets/HelperWidgets.cpp index ea307478..97c4a463 100644 --- a/src/overlay/widgets/HelperWidgets.cpp +++ b/src/overlay/widgets/HelperWidgets.cpp @@ -27,7 +27,7 @@ namespace HelperWidgets return activeID; } - bool BindWidget(VKBindInfo& aVKBindInfo, const std::string& acIdOverlay) + bool BindWidget(VKBindInfo& aVKBindInfo, bool aUnbindable) { VKBindings& vkb { CET::Get().GetBindings() }; @@ -66,7 +66,7 @@ namespace HelperWidgets } ImGui::PopID(); - if (aVKBindInfo.CodeBind && (aVKBindInfo.Bind.ID != acIdOverlay)) // make an exception for Overlay key + if (aUnbindable && aVKBindInfo.CodeBind) { ImGui::PushID(&aVKBindInfo.Bind.ID[1]); // same as PushID before, just make pointer a bit bigger :) ImGui::SameLine(); diff --git a/src/overlay/widgets/HelperWidgets.h b/src/overlay/widgets/HelperWidgets.h index d5f72224..d4cb589d 100644 --- a/src/overlay/widgets/HelperWidgets.h +++ b/src/overlay/widgets/HelperWidgets.h @@ -5,7 +5,7 @@ namespace HelperWidgets { WidgetID ToolbarWidget(); -bool BindWidget(VKBindInfo& aVKBindInfo, const std::string& acIdOverlay); +bool BindWidget(VKBindInfo& aVKBindInfo, bool aUnbindable); bool BoolWidget(const std::string& label, bool& current, bool saved); using TUCHPSave = std::function; diff --git a/src/overlay/widgets/Settings.h b/src/overlay/widgets/Settings.h index 7307c499..a852951d 100644 --- a/src/overlay/widgets/Settings.h +++ b/src/overlay/widgets/Settings.h @@ -36,8 +36,8 @@ struct Settings : Widget bool m_removeDeadBindings{ true }; Options& m_options; - HelperWidgets::TUCHPSave m_saveCB{[this]() { Save(); }}; - HelperWidgets::TUCHPLoad m_loadCB{[this]() { Load(); }}; + HelperWidgets::TUCHPSave m_saveCB {[this](){ Save(); } }; + HelperWidgets::TUCHPLoad m_loadCB {[this](){ Load(); } }; bool m_enabled{ false }; bool m_madeChanges{ false }; From 37cc7e7391fd80d5ec22c34428e8b166c9135d8b Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Tue, 30 Mar 2021 17:35:09 +0200 Subject: [PATCH 04/35] Change ordering of members in Overlay --- src/overlay/Overlay.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/overlay/Overlay.h b/src/overlay/Overlay.h index 8b2903d5..a3e086d5 100644 --- a/src/overlay/Overlay.h +++ b/src/overlay/Overlay.h @@ -42,6 +42,8 @@ struct Overlay void SetActiveWidget(WidgetID aNewActive); + VKBindInfo m_VKBIOverlay{ { "cet.overlay_key", "Overlay Key", [this](){ Toggle(); } }, 0, 0, false }; + Console m_console; Bindings m_bindings; Settings m_settings; @@ -56,7 +58,6 @@ struct Overlay std::atomic_bool m_enabled{ false }; std::atomic_bool m_toggled{ false }; bool m_initialized{ false }; - VKBindInfo m_VKBIOverlay; std::atomic_bool m_showFirstTimeModal{ false }; From 92115bfe312565b55be297c9329b9914cd19638d Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Tue, 30 Mar 2021 18:05:15 +0200 Subject: [PATCH 05/35] Center text in modals + block LuaVM from updating when modal active --- src/overlay/Overlay.cpp | 15 ++++++++++++--- src/overlay/widgets/Bindings.cpp | 2 ++ src/overlay/widgets/HelperWidgets.cpp | 21 +++++++++++++++++---- src/overlay/widgets/Settings.cpp | 6 +++++- src/overlay/widgets/Settings.h | 8 +++++--- src/scripting/LuaVM.cpp | 10 ++++++---- src/scripting/LuaVM.h | 3 +++ 7 files changed, 50 insertions(+), 15 deletions(-) diff --git a/src/overlay/Overlay.cpp b/src/overlay/Overlay.cpp index 1fb87cf7..6ecdb881 100644 --- a/src/overlay/Overlay.cpp +++ b/src/overlay/Overlay.cpp @@ -101,11 +101,18 @@ void Overlay::Update() ImGui::OpenPopup("CET First Time Setup"); m_showFirstTimeModal = false; + m_vm.BlockUpdate(true); } if (ImGui::BeginPopupModal("CET First Time Setup", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { - ImGui::Text("Please, bind some key combination for toggling overlay!\nCombo can be composed from up to 4 keys."); + const auto shorterTextSz { ImGui::CalcTextSize("Combo can be composed from up to 4 keys.").x }; + const auto longerTextSz { ImGui::CalcTextSize("Please, bind some key combination for toggling overlay!").x }; + const auto diffTextSz { longerTextSz - shorterTextSz }; + + ImGui::Text("Please, bind some key combination for toggling overlay!"); + ImGui::SetCursorPosX(diffTextSz / 2); + ImGui::Text("Combo can be composed from up to 4 keys."); ImGui::Separator(); HelperWidgets::BindWidget(m_VKBIOverlay, false); @@ -114,6 +121,7 @@ void Overlay::Update() m_VKBIOverlay.Apply(); m_bindings.Save(); m_options.IsFirstLaunch = false; + m_vm.BlockUpdate(false); ImGui::CloseCurrentPopup(); } @@ -223,9 +231,8 @@ void Overlay::Hook() Overlay::Overlay(D3D12& aD3D12, VKBindings& aBindings, Options& aOptions, LuaVM& aVm) : m_console(aVm) , m_bindings(aBindings, *this, aVm) - , m_settings(aOptions) + , m_settings(aOptions, aVm) , m_tweakDBEditor(aVm) - , m_VKBIOverlay{{"cet.overlay_key", "Overlay Key", [this]() { Toggle(); }}, 0, 0, false} , m_d3d12(aD3D12) , m_options(aOptions) , m_vm(aVm) @@ -256,8 +263,10 @@ void Overlay::SetActiveWidget(WidgetID aNewActive) if (m_activeWidgetID != m_nextActiveWidgetID) { + assert(m_activeWidgetID < WidgetID::COUNT); if (m_widgets[static_cast(m_activeWidgetID)]->OnDisable()) { + assert(m_nextActiveWidgetID < WidgetID::COUNT); if (m_widgets[static_cast(m_nextActiveWidgetID)]->OnEnable()) m_activeWidgetID = m_nextActiveWidgetID; } diff --git a/src/overlay/widgets/Bindings.cpp b/src/overlay/widgets/Bindings.cpp index b8ae38cb..eef35ce3 100644 --- a/src/overlay/widgets/Bindings.cpp +++ b/src/overlay/widgets/Bindings.cpp @@ -29,7 +29,9 @@ bool Bindings::OnDisable() if (m_enabled) { m_bindings.StopRecordingBind(); + m_vm.BlockUpdate(m_madeChanges); m_madeChanges = (HelperWidgets::UnappliedChangesPopup(m_openChangesModal, m_madeChanges, m_saveCB, m_loadCB) == 0); + m_vm.BlockUpdate(m_madeChanges); m_enabled = m_madeChanges; } return !m_enabled; diff --git a/src/overlay/widgets/HelperWidgets.cpp b/src/overlay/widgets/HelperWidgets.cpp index 97c4a463..aa3fed78 100644 --- a/src/overlay/widgets/HelperWidgets.cpp +++ b/src/overlay/widgets/HelperWidgets.cpp @@ -46,6 +46,9 @@ namespace HelperWidgets std::string label { aVKBindInfo.Bind.Description + ':' }; if (aVKBindInfo.Bind.IsHotkey()) label.insert(0, "[HK] "); // insert [HK] prefix for hotkeys so user knows this input can be assigned up to 4-key combo + + ImGui::AlignTextToFramePadding(); + ImGui::PushStyleColor(ImGuiCol_Text, curTextColor); ImGui::PushID(&aVKBindInfo.Bind.Description); // ensure we have unique ID by using pointer to Description, is OK, pointer will not be used inside ImGui :P ImGui::Text(label.c_str()); @@ -91,7 +94,9 @@ namespace HelperWidgets ImVec4 curTextColor = ImGui::GetStyleColorVec4(ImGuiCol_Text); if (current != saved) curTextColor = ImVec4(1.0f, 1.0f, 0.0f, 1.0f); - + + ImGui::AlignTextToFramePadding(); + ImGui::PushStyleColor(ImGuiCol_Text, curTextColor); ImGui::Text(label.c_str()); ImGui::PopStyleColor(); @@ -116,10 +121,18 @@ namespace HelperWidgets if (ImGui::BeginPopupModal("Unapplied changes", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { - ImGui::Text("You have some unsaved changes.\nDo you wish to apply them or discard them?"); + const auto shorterTextSz { ImGui::CalcTextSize("You have some unsaved changes.").x }; + const auto longerTextSz { ImGui::CalcTextSize("Do you wish to apply them or discard them?").x }; + const auto diffTextSz { longerTextSz - shorterTextSz }; + + ImGui::SetCursorPosX(diffTextSz / 2); + ImGui::Text("You have some unsaved changes."); + ImGui::Text("Do you wish to apply them or discard them?"); ImGui::Separator(); - if (ImGui::Button("Apply", ImVec2(120, 0))) + const auto buttonWidth { (longerTextSz - ImGui::GetStyle().ItemSpacing.x) / 2 }; + + if (ImGui::Button("Apply", ImVec2(buttonWidth, 0))) { aSaveCB(); res = 1; @@ -127,7 +140,7 @@ namespace HelperWidgets ImGui::CloseCurrentPopup(); } ImGui::SameLine(); - if (ImGui::Button("Discard", ImVec2(120, 0))) + if (ImGui::Button("Discard", ImVec2(buttonWidth, 0))) { aLoadCB(); res = -1; diff --git a/src/overlay/widgets/Settings.cpp b/src/overlay/widgets/Settings.cpp index f404aee7..e3951290 100644 --- a/src/overlay/widgets/Settings.cpp +++ b/src/overlay/widgets/Settings.cpp @@ -1,9 +1,11 @@ #include #include "Settings.h" +#include -Settings::Settings(Options& aOptions) +Settings::Settings(Options& aOptions, LuaVM& aVm) : m_options(aOptions) + , m_vm(aVm) { } @@ -21,7 +23,9 @@ bool Settings::OnDisable() { if (m_enabled) { + m_vm.BlockUpdate(m_madeChanges); m_madeChanges = (HelperWidgets::UnappliedChangesPopup(m_openChangesModal, m_madeChanges, m_saveCB, m_loadCB) == 0); + m_vm.BlockUpdate(m_madeChanges); m_enabled = m_madeChanges; } return !m_enabled; diff --git a/src/overlay/widgets/Settings.h b/src/overlay/widgets/Settings.h index a852951d..70d78082 100644 --- a/src/overlay/widgets/Settings.h +++ b/src/overlay/widgets/Settings.h @@ -6,10 +6,11 @@ struct VKBindings; struct Overlay; struct Options; +struct LuaVM; struct Settings : Widget { - Settings(Options& aOptions); + Settings(Options& aOptions, LuaVM& aVm); ~Settings() override = default; bool OnEnable() override; @@ -35,9 +36,10 @@ struct Settings : Widget bool m_drawImGuiDiagnosticWindow{ false }; bool m_removeDeadBindings{ true }; Options& m_options; + LuaVM& m_vm; - HelperWidgets::TUCHPSave m_saveCB {[this](){ Save(); } }; - HelperWidgets::TUCHPLoad m_loadCB {[this](){ Load(); } }; + HelperWidgets::TUCHPSave m_saveCB { [this](){ Save(); } }; + HelperWidgets::TUCHPLoad m_loadCB { [this](){ Load(); } }; bool m_enabled{ false }; bool m_madeChanges{ false }; diff --git a/src/scripting/LuaVM.cpp b/src/scripting/LuaVM.cpp index 84053950..281b4cc5 100644 --- a/src/scripting/LuaVM.cpp +++ b/src/scripting/LuaVM.cpp @@ -25,10 +25,7 @@ void LuaVM::Update(float aDeltaTime) if (!m_initialized && m_logCount.load(std::memory_order_relaxed) > 0) PostInitialize(); - if (!m_initialized) - return; - - if (m_options.IsFirstLaunch) + if (!m_initialized || m_updateBlocked) return; m_scripting.TriggerOnUpdate(aDeltaTime); @@ -74,6 +71,11 @@ bool LuaVM::IsInitialized() const return m_initialized; } +void LuaVM::BlockUpdate(bool aBlockUpdate) +{ + m_updateBlocked = aBlockUpdate; +} + void LuaVM::RemoveTDBIDDerivedFrom(uint64_t aDBID) { std::lock_guard _{ m_tdbidLock }; diff --git a/src/scripting/LuaVM.h b/src/scripting/LuaVM.h index 26687157..e23e151f 100644 --- a/src/scripting/LuaVM.h +++ b/src/scripting/LuaVM.h @@ -40,6 +40,8 @@ struct LuaVM bool IsInitialized() const; + void BlockUpdate(bool aBlockUpdate); + // Used by TweakDB when you delete a custom record void RemoveTDBIDDerivedFrom(uint64_t aDBID); bool GetTDBIDDerivedFrom(uint64_t aDBID, std::vector& aDerivedList); @@ -84,6 +86,7 @@ struct LuaVM Scripting m_scripting; bool m_initialized{ false }; + bool m_updateBlocked{ false }; Options& m_options; D3D12& m_d3d12; From c6dfbf3a8eb72751c27076040eda3dfe11104794 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Tue, 30 Mar 2021 18:27:49 +0200 Subject: [PATCH 06/35] Fix "Unapplied Changes" in Settings, fix ImGui diagnostic window draw --- src/Options.h | 1 + src/overlay/Overlay.cpp | 3 +++ src/overlay/widgets/Settings.cpp | 37 ++++++++++++++++---------------- src/overlay/widgets/Settings.h | 1 - 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/Options.h b/src/Options.h index 88dd41bf..68ee0b7a 100644 --- a/src/Options.h +++ b/src/Options.h @@ -31,6 +31,7 @@ struct Options bool ExeValid{ false }; bool IsFirstLaunch { true }; bool RemoveDeadBindings { true }; + bool DrawImGuiDiagnosticWindow { false }; private: diff --git a/src/overlay/Overlay.cpp b/src/overlay/Overlay.cpp index 6ecdb881..8d61ad07 100644 --- a/src/overlay/Overlay.cpp +++ b/src/overlay/Overlay.cpp @@ -168,6 +168,9 @@ void Overlay::Update() } } ImGui::End(); + + if (m_options.DrawImGuiDiagnosticWindow) + ImGui::ShowMetricsWindow(&m_options.DrawImGuiDiagnosticWindow); } bool Overlay::IsInitialized() const noexcept diff --git a/src/overlay/widgets/Settings.cpp b/src/overlay/widgets/Settings.cpp index e3951290..c372c55b 100644 --- a/src/overlay/widgets/Settings.cpp +++ b/src/overlay/widgets/Settings.cpp @@ -46,44 +46,43 @@ void Settings::Update() if (ImGui::BeginTabBar("##SETTINGS", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton | ImGuiTabBarFlags_NoTooltip)) { - // reset dirty state - m_madeChanges = false; - + bool patchesChanged = false; if (ImGui::BeginTabItem("Patches")) { if (ImGui::BeginChild("##SETTINGS_PATCHES")) { - m_madeChanges |= HelperWidgets::BoolWidget("AMD SMT Patch:", m_patchAmdSmt, m_options.PatchAmdSmt); - m_madeChanges |= HelperWidgets::BoolWidget("Remove Pedestrians:", m_patchRemovePedestrians, m_options.PatchRemovePedestrians); - m_madeChanges |= HelperWidgets::BoolWidget("Disable Async Compute:", m_patchAsyncCompute, m_options.PatchAsyncCompute); - m_madeChanges |= HelperWidgets::BoolWidget("Disable Antialiasing:", m_patchAntialiasing, m_options.PatchAntialiasing); - m_madeChanges |= HelperWidgets::BoolWidget("Skip Start Menu:", m_patchSkipStartMenu, m_options.PatchSkipStartMenu); - m_madeChanges |= HelperWidgets::BoolWidget("Suppress Intro Movies:", m_patchDisableIntroMovies, m_options.PatchDisableIntroMovies); - m_madeChanges |= HelperWidgets::BoolWidget("Disable Vignette:", m_patchDisableVignette, m_options.PatchDisableVignette); - m_madeChanges |= HelperWidgets::BoolWidget("Disable Boundary Teleport:", m_patchDisableBoundaryTeleport, m_options.PatchDisableBoundaryTeleport); - m_madeChanges |= HelperWidgets::BoolWidget("Disable V-Sync (Windows 7 only):", m_patchDisableWin7Vsync, m_options.PatchDisableWin7Vsync); + patchesChanged = HelperWidgets::BoolWidget("AMD SMT Patch:", m_patchAmdSmt, m_options.PatchAmdSmt); + patchesChanged |= HelperWidgets::BoolWidget("Remove Pedestrians:", m_patchRemovePedestrians, m_options.PatchRemovePedestrians); + patchesChanged |= HelperWidgets::BoolWidget("Disable Async Compute:", m_patchAsyncCompute, m_options.PatchAsyncCompute); + patchesChanged |= HelperWidgets::BoolWidget("Disable Antialiasing:", m_patchAntialiasing, m_options.PatchAntialiasing); + patchesChanged |= HelperWidgets::BoolWidget("Skip Start Menu:", m_patchSkipStartMenu, m_options.PatchSkipStartMenu); + patchesChanged |= HelperWidgets::BoolWidget("Suppress Intro Movies:", m_patchDisableIntroMovies, m_options.PatchDisableIntroMovies); + patchesChanged |= HelperWidgets::BoolWidget("Disable Vignette:", m_patchDisableVignette, m_options.PatchDisableVignette); + patchesChanged |= HelperWidgets::BoolWidget("Disable Boundary Teleport:", m_patchDisableBoundaryTeleport, m_options.PatchDisableBoundaryTeleport); + patchesChanged |= HelperWidgets::BoolWidget("Disable V-Sync (Windows 7 only):", m_patchDisableWin7Vsync, m_options.PatchDisableWin7Vsync); } ImGui::EndChild(); ImGui::EndTabItem(); } - + + bool devChanged = false; if (ImGui::BeginTabItem("Dev")) { if (ImGui::BeginChild("##SETTINGS_DEV")) { - HelperWidgets::BoolWidget("Draw ImGui Diagnostic Window:", m_drawImGuiDiagnosticWindow, m_drawImGuiDiagnosticWindow); - if (m_drawImGuiDiagnosticWindow) - ImGui::ShowMetricsWindow(&m_drawImGuiDiagnosticWindow); + HelperWidgets::BoolWidget("Draw ImGui Diagnostic Window:", m_options.DrawImGuiDiagnosticWindow, m_options.DrawImGuiDiagnosticWindow); - m_madeChanges |= HelperWidgets::BoolWidget("Remove Dead Bindings:", m_removeDeadBindings, m_options.RemoveDeadBindings); - m_madeChanges |= HelperWidgets::BoolWidget("Enable Debug Menu:", m_patchEnableDebug, m_options.PatchEnableDebug); - m_madeChanges |= HelperWidgets::BoolWidget("Dump Game Options:", m_dumpGameOptions, m_options.DumpGameOptions); + devChanged = HelperWidgets::BoolWidget("Remove Dead Bindings:", m_removeDeadBindings, m_options.RemoveDeadBindings); + devChanged |= HelperWidgets::BoolWidget("Enable Debug Menu:", m_patchEnableDebug, m_options.PatchEnableDebug); + devChanged |= HelperWidgets::BoolWidget("Dump Game Options:", m_dumpGameOptions, m_options.DumpGameOptions); } ImGui::EndChild(); ImGui::EndTabItem(); } + m_madeChanges = patchesChanged || devChanged; + ImGui::EndTabBar(); } } diff --git a/src/overlay/widgets/Settings.h b/src/overlay/widgets/Settings.h index 70d78082..3bf42a22 100644 --- a/src/overlay/widgets/Settings.h +++ b/src/overlay/widgets/Settings.h @@ -33,7 +33,6 @@ struct Settings : Widget bool m_patchDisableBoundaryTeleport{ false }; bool m_patchDisableWin7Vsync{ false }; bool m_dumpGameOptions{ false }; - bool m_drawImGuiDiagnosticWindow{ false }; bool m_removeDeadBindings{ true }; Options& m_options; LuaVM& m_vm; From 90f996cd8408733340bea3d192fe16dd5b93e960 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Tue, 30 Mar 2021 18:43:23 +0200 Subject: [PATCH 07/35] Some more offseting --- src/overlay/Overlay.cpp | 3 ++- src/overlay/widgets/HelperWidgets.cpp | 8 ++++++-- src/overlay/widgets/HelperWidgets.h | 4 ++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/overlay/Overlay.cpp b/src/overlay/Overlay.cpp index 8d61ad07..a1cad98e 100644 --- a/src/overlay/Overlay.cpp +++ b/src/overlay/Overlay.cpp @@ -115,7 +115,8 @@ void Overlay::Update() ImGui::Text("Combo can be composed from up to 4 keys."); ImGui::Separator(); - HelperWidgets::BindWidget(m_VKBIOverlay, false); + // TODO - do not hardcode offset! this somewhat works temporarily... + HelperWidgets::BindWidget(m_VKBIOverlay, false, diffTextSz * 0.75f); if (m_VKBIOverlay.CodeBind) { m_VKBIOverlay.Apply(); diff --git a/src/overlay/widgets/HelperWidgets.cpp b/src/overlay/widgets/HelperWidgets.cpp index aa3fed78..2261d495 100644 --- a/src/overlay/widgets/HelperWidgets.cpp +++ b/src/overlay/widgets/HelperWidgets.cpp @@ -27,7 +27,7 @@ namespace HelperWidgets return activeID; } - bool BindWidget(VKBindInfo& aVKBindInfo, bool aUnbindable) + bool BindWidget(VKBindInfo& aVKBindInfo, bool aUnbindable, float offset_x) { VKBindings& vkb { CET::Get().GetBindings() }; @@ -49,6 +49,8 @@ namespace HelperWidgets ImGui::AlignTextToFramePadding(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + offset_x); + ImGui::PushStyleColor(ImGuiCol_Text, curTextColor); ImGui::PushID(&aVKBindInfo.Bind.Description); // ensure we have unique ID by using pointer to Description, is OK, pointer will not be used inside ImGui :P ImGui::Text(label.c_str()); @@ -89,7 +91,7 @@ namespace HelperWidgets return (aVKBindInfo.CodeBind != aVKBindInfo.SavedCodeBind); } - bool BoolWidget(const std::string& label, bool& current, bool saved) + bool BoolWidget(const std::string& label, bool& current, bool saved, float offset_x) { ImVec4 curTextColor = ImGui::GetStyleColorVec4(ImGuiCol_Text); if (current != saved) @@ -97,6 +99,8 @@ namespace HelperWidgets ImGui::AlignTextToFramePadding(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + offset_x); + ImGui::PushStyleColor(ImGuiCol_Text, curTextColor); ImGui::Text(label.c_str()); ImGui::PopStyleColor(); diff --git a/src/overlay/widgets/HelperWidgets.h b/src/overlay/widgets/HelperWidgets.h index d4cb589d..d0c0a016 100644 --- a/src/overlay/widgets/HelperWidgets.h +++ b/src/overlay/widgets/HelperWidgets.h @@ -5,8 +5,8 @@ namespace HelperWidgets { WidgetID ToolbarWidget(); -bool BindWidget(VKBindInfo& aVKBindInfo, bool aUnbindable); -bool BoolWidget(const std::string& label, bool& current, bool saved); +bool BindWidget(VKBindInfo& aVKBindInfo, bool aUnbindable, float offset_x = 0.0f); +bool BoolWidget(const std::string& label, bool& current, bool saved, float offset_x = 0.0f); using TUCHPSave = std::function; using TUCHPLoad = std::function; From 78c3ab7baa69c77c3f66c7fd89bdf1e573138a23 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Tue, 30 Mar 2021 18:54:51 +0200 Subject: [PATCH 08/35] Fix discard for Bindings widget --- src/overlay/widgets/Bindings.cpp | 15 +++++++++++++++ src/overlay/widgets/Bindings.h | 3 ++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/overlay/widgets/Bindings.cpp b/src/overlay/widgets/Bindings.cpp index eef35ce3..0b13146e 100644 --- a/src/overlay/widgets/Bindings.cpp +++ b/src/overlay/widgets/Bindings.cpp @@ -109,3 +109,18 @@ void Bindings::Save() m_vkBindInfos = m_bindings.InitializeMods(m_vm.GetBinds()); m_luaVMReady = true; } + +void Bindings::ResetChanges() +{ + for (auto& vkBindInfo : m_vkBindInfos) + { + if (vkBindInfo.CodeBind == vkBindInfo.SavedCodeBind) + continue; + + if (vkBindInfo.CodeBind) + m_bindings.UnBind(vkBindInfo.CodeBind); + if (vkBindInfo.SavedCodeBind) + m_bindings.Bind(vkBindInfo.SavedCodeBind, vkBindInfo.Bind); + vkBindInfo.CodeBind = vkBindInfo.SavedCodeBind; + } +} diff --git a/src/overlay/widgets/Bindings.h b/src/overlay/widgets/Bindings.h index c8bd1ec0..1fded2c0 100644 --- a/src/overlay/widgets/Bindings.h +++ b/src/overlay/widgets/Bindings.h @@ -17,6 +17,7 @@ struct Bindings : Widget void Load(); void Save(); + void ResetChanges(); private: std::vector m_vkBindInfos{ }; @@ -27,7 +28,7 @@ struct Bindings : Widget std::string m_overlayKeyID; HelperWidgets::TUCHPSave m_saveCB { [this](){ Save(); } }; - HelperWidgets::TUCHPLoad m_loadCB { [this](){ Load(); } }; + HelperWidgets::TUCHPLoad m_loadCB { [this](){ ResetChanges(); } }; bool m_luaVMReady{ false }; bool m_enabled{ false }; From 0b8a2b2f9b79e488b3694656d043932ecca1fa15 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Tue, 30 Mar 2021 20:23:33 +0200 Subject: [PATCH 09/35] Rename "UnappliedChangesPopup" to "UnsavedChangesPopup" + modify title --- src/overlay/widgets/Bindings.cpp | 2 +- src/overlay/widgets/HelperWidgets.cpp | 6 +++--- src/overlay/widgets/HelperWidgets.h | 2 +- src/overlay/widgets/Settings.cpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/overlay/widgets/Bindings.cpp b/src/overlay/widgets/Bindings.cpp index 0b13146e..1675f86c 100644 --- a/src/overlay/widgets/Bindings.cpp +++ b/src/overlay/widgets/Bindings.cpp @@ -30,7 +30,7 @@ bool Bindings::OnDisable() { m_bindings.StopRecordingBind(); m_vm.BlockUpdate(m_madeChanges); - m_madeChanges = (HelperWidgets::UnappliedChangesPopup(m_openChangesModal, m_madeChanges, m_saveCB, m_loadCB) == 0); + m_madeChanges = (HelperWidgets::UnsavedChangesPopup(m_openChangesModal, m_madeChanges, m_saveCB, m_loadCB) == 0); m_vm.BlockUpdate(m_madeChanges); m_enabled = m_madeChanges; } diff --git a/src/overlay/widgets/HelperWidgets.cpp b/src/overlay/widgets/HelperWidgets.cpp index 2261d495..1fd4f9c7 100644 --- a/src/overlay/widgets/HelperWidgets.cpp +++ b/src/overlay/widgets/HelperWidgets.cpp @@ -112,18 +112,18 @@ namespace HelperWidgets return (current != saved); } - int32_t UnappliedChangesPopup(bool& aFirstTime, bool aMadeChanges, TUCHPSave aSaveCB, TUCHPLoad aLoadCB) + int32_t UnsavedChangesPopup(bool& aFirstTime, bool aMadeChanges, TUCHPSave aSaveCB, TUCHPLoad aLoadCB) { if (aMadeChanges) { int32_t res = 0; if (aFirstTime) { - ImGui::OpenPopup("Unapplied changes"); + ImGui::OpenPopup("Unsaved changes"); aFirstTime = false; } - if (ImGui::BeginPopupModal("Unapplied changes", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) + if (ImGui::BeginPopupModal("Unsaved changes", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { const auto shorterTextSz { ImGui::CalcTextSize("You have some unsaved changes.").x }; const auto longerTextSz { ImGui::CalcTextSize("Do you wish to apply them or discard them?").x }; diff --git a/src/overlay/widgets/HelperWidgets.h b/src/overlay/widgets/HelperWidgets.h index d0c0a016..deb4919d 100644 --- a/src/overlay/widgets/HelperWidgets.h +++ b/src/overlay/widgets/HelperWidgets.h @@ -10,5 +10,5 @@ bool BoolWidget(const std::string& label, bool& current, bool saved, float offse using TUCHPSave = std::function; using TUCHPLoad = std::function; -int32_t UnappliedChangesPopup(bool& aFirstTime, bool aMadeChanges, TUCHPSave aSaveCB, TUCHPLoad aLoadCB); +int32_t UnsavedChangesPopup(bool& aFirstTime, bool aMadeChanges, TUCHPSave aSaveCB, TUCHPLoad aLoadCB); } \ No newline at end of file diff --git a/src/overlay/widgets/Settings.cpp b/src/overlay/widgets/Settings.cpp index c372c55b..69b519e8 100644 --- a/src/overlay/widgets/Settings.cpp +++ b/src/overlay/widgets/Settings.cpp @@ -24,7 +24,7 @@ bool Settings::OnDisable() if (m_enabled) { m_vm.BlockUpdate(m_madeChanges); - m_madeChanges = (HelperWidgets::UnappliedChangesPopup(m_openChangesModal, m_madeChanges, m_saveCB, m_loadCB) == 0); + m_madeChanges = (HelperWidgets::UnsavedChangesPopup(m_openChangesModal, m_madeChanges, m_saveCB, m_loadCB) == 0); m_vm.BlockUpdate(m_madeChanges); m_enabled = m_madeChanges; } From d9e3ec6c437fb8f81175297e6e3310074e963443 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Tue, 30 Mar 2021 21:12:44 +0200 Subject: [PATCH 10/35] Fix modal popup for Settings widget --- src/overlay/widgets/Settings.cpp | 30 ++++++++++++++---------------- src/overlay/widgets/Settings.h | 3 +++ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/overlay/widgets/Settings.cpp b/src/overlay/widgets/Settings.cpp index 69b519e8..ea5d2bc1 100644 --- a/src/overlay/widgets/Settings.cpp +++ b/src/overlay/widgets/Settings.cpp @@ -46,26 +46,24 @@ void Settings::Update() if (ImGui::BeginTabBar("##SETTINGS", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton | ImGuiTabBarFlags_NoTooltip)) { - bool patchesChanged = false; if (ImGui::BeginTabItem("Patches")) { if (ImGui::BeginChild("##SETTINGS_PATCHES")) { - patchesChanged = HelperWidgets::BoolWidget("AMD SMT Patch:", m_patchAmdSmt, m_options.PatchAmdSmt); - patchesChanged |= HelperWidgets::BoolWidget("Remove Pedestrians:", m_patchRemovePedestrians, m_options.PatchRemovePedestrians); - patchesChanged |= HelperWidgets::BoolWidget("Disable Async Compute:", m_patchAsyncCompute, m_options.PatchAsyncCompute); - patchesChanged |= HelperWidgets::BoolWidget("Disable Antialiasing:", m_patchAntialiasing, m_options.PatchAntialiasing); - patchesChanged |= HelperWidgets::BoolWidget("Skip Start Menu:", m_patchSkipStartMenu, m_options.PatchSkipStartMenu); - patchesChanged |= HelperWidgets::BoolWidget("Suppress Intro Movies:", m_patchDisableIntroMovies, m_options.PatchDisableIntroMovies); - patchesChanged |= HelperWidgets::BoolWidget("Disable Vignette:", m_patchDisableVignette, m_options.PatchDisableVignette); - patchesChanged |= HelperWidgets::BoolWidget("Disable Boundary Teleport:", m_patchDisableBoundaryTeleport, m_options.PatchDisableBoundaryTeleport); - patchesChanged |= HelperWidgets::BoolWidget("Disable V-Sync (Windows 7 only):", m_patchDisableWin7Vsync, m_options.PatchDisableWin7Vsync); + m_patchesChanged = HelperWidgets::BoolWidget("AMD SMT Patch:", m_patchAmdSmt, m_options.PatchAmdSmt); + m_patchesChanged |= HelperWidgets::BoolWidget("Remove Pedestrians:", m_patchRemovePedestrians, m_options.PatchRemovePedestrians); + m_patchesChanged |= HelperWidgets::BoolWidget("Disable Async Compute:", m_patchAsyncCompute, m_options.PatchAsyncCompute); + m_patchesChanged |= HelperWidgets::BoolWidget("Disable Antialiasing:", m_patchAntialiasing, m_options.PatchAntialiasing); + m_patchesChanged |= HelperWidgets::BoolWidget("Skip Start Menu:", m_patchSkipStartMenu, m_options.PatchSkipStartMenu); + m_patchesChanged |= HelperWidgets::BoolWidget("Suppress Intro Movies:", m_patchDisableIntroMovies, m_options.PatchDisableIntroMovies); + m_patchesChanged |= HelperWidgets::BoolWidget("Disable Vignette:", m_patchDisableVignette, m_options.PatchDisableVignette); + m_patchesChanged |= HelperWidgets::BoolWidget("Disable Boundary Teleport:", m_patchDisableBoundaryTeleport, m_options.PatchDisableBoundaryTeleport); + m_patchesChanged |= HelperWidgets::BoolWidget("Disable V-Sync (Windows 7 only):", m_patchDisableWin7Vsync, m_options.PatchDisableWin7Vsync); } ImGui::EndChild(); ImGui::EndTabItem(); } - - bool devChanged = false; + if (ImGui::BeginTabItem("Dev")) { if (ImGui::BeginChild("##SETTINGS_DEV")) @@ -73,15 +71,15 @@ void Settings::Update() HelperWidgets::BoolWidget("Draw ImGui Diagnostic Window:", m_options.DrawImGuiDiagnosticWindow, m_options.DrawImGuiDiagnosticWindow); - devChanged = HelperWidgets::BoolWidget("Remove Dead Bindings:", m_removeDeadBindings, m_options.RemoveDeadBindings); - devChanged |= HelperWidgets::BoolWidget("Enable Debug Menu:", m_patchEnableDebug, m_options.PatchEnableDebug); - devChanged |= HelperWidgets::BoolWidget("Dump Game Options:", m_dumpGameOptions, m_options.DumpGameOptions); + m_devChanged = HelperWidgets::BoolWidget("Remove Dead Bindings:", m_removeDeadBindings, m_options.RemoveDeadBindings); + m_devChanged |= HelperWidgets::BoolWidget("Enable Debug Menu:", m_patchEnableDebug, m_options.PatchEnableDebug); + m_devChanged |= HelperWidgets::BoolWidget("Dump Game Options:", m_dumpGameOptions, m_options.DumpGameOptions); } ImGui::EndChild(); ImGui::EndTabItem(); } - m_madeChanges = patchesChanged || devChanged; + m_madeChanges = m_patchesChanged || m_devChanged; ImGui::EndTabBar(); } diff --git a/src/overlay/widgets/Settings.h b/src/overlay/widgets/Settings.h index 3bf42a22..b7e3e608 100644 --- a/src/overlay/widgets/Settings.h +++ b/src/overlay/widgets/Settings.h @@ -43,4 +43,7 @@ struct Settings : Widget bool m_enabled{ false }; bool m_madeChanges{ false }; bool m_openChangesModal{ true }; + + bool m_patchesChanged{ false }; + bool m_devChanged{ false }; }; From 3430fa82ed0c3b3fdf303f0b16936268b3ad42e4 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Wed, 31 Mar 2021 12:54:30 +0200 Subject: [PATCH 11/35] Add ability to enable ImGui assertions (default on) Needs PR https://github.com/xmake-io/xmake-repo/pull/350 --- imgui_user_config.h | 5 +++++ src/Options.cpp | 8 ++++++-- src/Options.h | 1 + src/Utils.cpp | 12 ++++++++++++ src/Utils.h | 5 ++++- src/overlay/widgets/Settings.cpp | 13 +++++++++---- src/overlay/widgets/Settings.h | 2 ++ src/scripting/LuaSandbox.cpp | 1 + xmake.lua | 8 +++++--- 9 files changed, 45 insertions(+), 10 deletions(-) create mode 100644 imgui_user_config.h diff --git a/imgui_user_config.h b/imgui_user_config.h new file mode 100644 index 00000000..fb3a8eda --- /dev/null +++ b/imgui_user_config.h @@ -0,0 +1,5 @@ +#pragma once + +void ImGuiAssert(wchar_t const* acpMessage, wchar_t const* acpFile, unsigned aLine); + +#define IM_ASSERT(expression) (void)((!!(expression)) || (ImGuiAssert(_CRT_WIDE(#expression), _CRT_WIDE(__FILE__), (unsigned)(__LINE__)), 0)) \ No newline at end of file diff --git a/src/Options.cpp b/src/Options.cpp index 8f267e2e..cd282fea 100644 --- a/src/Options.cpp +++ b/src/Options.cpp @@ -11,7 +11,6 @@ void Options::Load() if(configFile) { auto config = nlohmann::json::parse(configFile); - PatchEnableDebug = config.value("enable_debug", PatchEnableDebug); PatchRemovePedestrians = config.value("remove_pedestrians", PatchRemovePedestrians); PatchSkipStartMenu = config.value("skip_start_menu", PatchSkipStartMenu); PatchAmdSmt = config.value("amd_smt", PatchAmdSmt); @@ -23,7 +22,9 @@ void Options::Load() PatchDisableWin7Vsync = config.value("disable_win7_vsync", PatchDisableWin7Vsync); RemoveDeadBindings = config.value("cetdev_remove_dead_bindings", RemoveDeadBindings); + EnableImGuiAssertions = config.value("cetdev_enable_imgui_assertions", EnableImGuiAssertions); DumpGameOptions = config.value("dump_game_options", DumpGameOptions); + PatchEnableDebug = config.value("enable_debug", PatchEnableDebug); // font config FontPath = config.value("font_path", FontPath); @@ -42,7 +43,6 @@ void Options::Save() { nlohmann::json config; - config["enable_debug"] = PatchEnableDebug; config["remove_pedestrians"] = PatchRemovePedestrians; config["disable_async_compute"] = PatchAsyncCompute; config["disable_antialiasing"] = PatchAntialiasing; @@ -52,8 +52,12 @@ void Options::Save() config["disable_vignette"] = PatchDisableVignette; config["disable_boundary_teleport"] = PatchDisableBoundaryTeleport; config["disable_win7_vsync"] = PatchDisableWin7Vsync; + config["cetdev_remove_dead_bindings"] = RemoveDeadBindings; + config["cetdev_enable_imgui_assertions"] = EnableImGuiAssertions; + config["enable_debug"] = PatchEnableDebug; config["dump_game_options"] = DumpGameOptions; + config["font_path"] = FontPath; config["font_glyph_ranges"] = FontGlyphRanges; config["font_size"] = FontSize; diff --git a/src/Options.h b/src/Options.h index 68ee0b7a..5abe43bc 100644 --- a/src/Options.h +++ b/src/Options.h @@ -32,6 +32,7 @@ struct Options bool IsFirstLaunch { true }; bool RemoveDeadBindings { true }; bool DrawImGuiDiagnosticWindow { false }; + bool EnableImGuiAssertions { true }; private: diff --git a/src/Utils.cpp b/src/Utils.cpp index bd8fb25d..d5e66e4a 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -2,6 +2,8 @@ #include "Utils.h" +#include "CET.h" + #include #include @@ -136,3 +138,13 @@ void MakeSolObjectImmutable(sol::object aObj, const sol::state_view& aStateView) // prevent adding new properties metatable[sol::meta_function::new_index] = []() {}; } + +// runtime assertions which can be enabled/disabled inside CET options +void ImGuiAssert(wchar_t const* acpMessage, wchar_t const* acpFile, unsigned aLine) +{ +#ifdef NDEBUG + __declspec(dllimport) void __cdecl _wassert(wchar_t const* _Message, wchar_t const* _File, unsigned _Line); +#endif + if (CET::Get().GetOptions().EnableImGuiAssertions) + _wassert(acpMessage, acpFile, aLine); +} diff --git a/src/Utils.h b/src/Utils.h index 56f3025c..71deeefc 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -12,4 +12,7 @@ std::shared_ptr CreateLogger(const std::filesystem::path& aPath, sol::object DeepCopySolObject(sol::object aObj, const sol::state_view& aStateView); // makes sol object immutable when accessed from lua -void MakeSolObjectImmutable(sol::object aObj, const sol::state_view& aStateView); \ No newline at end of file +void MakeSolObjectImmutable(sol::object aObj, const sol::state_view& aStateView); + +//// runtime assertions which can be enabled/disabled inside CET options +//void ImGuiAssert(wchar_t const* acpMessage, wchar_t const* acpFile, unsigned aLine); \ No newline at end of file diff --git a/src/overlay/widgets/Settings.cpp b/src/overlay/widgets/Settings.cpp index ea5d2bc1..d538130b 100644 --- a/src/overlay/widgets/Settings.cpp +++ b/src/overlay/widgets/Settings.cpp @@ -72,6 +72,7 @@ void Settings::Update() HelperWidgets::BoolWidget("Draw ImGui Diagnostic Window:", m_options.DrawImGuiDiagnosticWindow, m_options.DrawImGuiDiagnosticWindow); m_devChanged = HelperWidgets::BoolWidget("Remove Dead Bindings:", m_removeDeadBindings, m_options.RemoveDeadBindings); + m_devChanged |= HelperWidgets::BoolWidget("Enable ImGui Assertions:", m_enableImGuiAssertions, m_options.EnableImGuiAssertions); m_devChanged |= HelperWidgets::BoolWidget("Enable Debug Menu:", m_patchEnableDebug, m_options.PatchEnableDebug); m_devChanged |= HelperWidgets::BoolWidget("Dump Game Options:", m_dumpGameOptions, m_options.DumpGameOptions); } @@ -89,7 +90,6 @@ void Settings::Load() { m_options.Load(); - m_patchEnableDebug = m_options.PatchEnableDebug; m_patchRemovePedestrians = m_options.PatchRemovePedestrians; m_patchAsyncCompute = m_options.PatchAsyncCompute; m_patchAntialiasing = m_options.PatchAntialiasing; @@ -99,13 +99,15 @@ void Settings::Load() m_patchDisableVignette = m_options.PatchDisableVignette; m_patchDisableBoundaryTeleport = m_options.PatchDisableBoundaryTeleport; m_patchDisableWin7Vsync = m_options.PatchDisableWin7Vsync; - m_dumpGameOptions = m_options.DumpGameOptions; + m_removeDeadBindings = m_options.RemoveDeadBindings; + m_enableImGuiAssertions = m_options.EnableImGuiAssertions; + m_patchEnableDebug = m_options.PatchEnableDebug; + m_dumpGameOptions = m_options.DumpGameOptions; } void Settings::Save() const { - m_options.PatchEnableDebug = m_patchEnableDebug; m_options.PatchRemovePedestrians = m_patchRemovePedestrians; m_options.PatchAsyncCompute = m_patchAsyncCompute; m_options.PatchAntialiasing = m_patchAntialiasing; @@ -115,8 +117,11 @@ void Settings::Save() const m_options.PatchDisableVignette = m_patchDisableVignette; m_options.PatchDisableBoundaryTeleport = m_patchDisableBoundaryTeleport; m_options.PatchDisableWin7Vsync = m_patchDisableWin7Vsync; - m_options.DumpGameOptions = m_dumpGameOptions; + m_options.RemoveDeadBindings = m_removeDeadBindings; + m_options.EnableImGuiAssertions = m_enableImGuiAssertions; + m_options.PatchEnableDebug = m_patchEnableDebug; + m_options.DumpGameOptions = m_dumpGameOptions; m_options.Save(); } diff --git a/src/overlay/widgets/Settings.h b/src/overlay/widgets/Settings.h index b7e3e608..10f261bd 100644 --- a/src/overlay/widgets/Settings.h +++ b/src/overlay/widgets/Settings.h @@ -34,6 +34,8 @@ struct Settings : Widget bool m_patchDisableWin7Vsync{ false }; bool m_dumpGameOptions{ false }; bool m_removeDeadBindings{ true }; + bool m_enableImGuiAssertions{ true }; + Options& m_options; LuaVM& m_vm; diff --git a/src/scripting/LuaSandbox.cpp b/src/scripting/LuaSandbox.cpp index b95f9fe1..df3bb449 100644 --- a/src/scripting/LuaSandbox.cpp +++ b/src/scripting/LuaSandbox.cpp @@ -116,6 +116,7 @@ static constexpr const char* s_cGlobalExtraLibsWhitelist[] = "ImGuiTableBgTarget", "ImGuiMouseButton", "ImDrawCornerFlags", + "ImDrawFlags", "ImGuiCol", "ImGuiDir", "json" diff --git a/xmake.lua b/xmake.lua index add5d029..bc532083 100644 --- a/xmake.lua +++ b/xmake.lua @@ -1,4 +1,4 @@ -set_xmakever("2.5.1") +set_xmakever("2.5.2") set_languages("cxx20") set_arch("x64") @@ -9,6 +9,9 @@ add_requireconfs("sol2", { configs = { includes_lua = false } }) add_rules("mode.debug","mode.releasedbg", "mode.release") add_rules("plugin.vsxmake.autoupdate") +local imguiUserConfig = path.absolute("imgui_user_config.h") +add_requireconfs("imgui", { configs = { user_config = imguiUserConfig } }) + if is_mode("debug") then add_defines("CET_DEBUG") set_optimize("none") @@ -16,13 +19,12 @@ elseif is_mode("releasedbg") then add_defines("CET_DEBUG") set_optimize("fastest") elseif is_mode("release") then - add_requireconfs("imgui", { configs = { cxflags = "/DNDEBUG" } }) add_defines("NDEBUG") set_optimize("fastest") end add_cxflags("/bigobj", "/MP") -add_defines("RED4EXT_STATIC_LIB", "UNICODE") +add_defines("RED4EXT_STATIC_LIB", "UNICODE", "IMGUI_USER_CONFIG=\""..imguiUserConfig.."\"") before_build(function (target) import("modules.version") From 77bb1eb05a46b56d63e2a751ff97168efd3933c7 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Wed, 31 Mar 2021 15:16:13 +0200 Subject: [PATCH 12/35] Better ImGui assert --- imgui_user_config.h | 5 ----- src/Options.cpp | 9 +++++++++ src/Utils.cpp | 6 +++--- src/Utils.h | 5 +---- src/imgui_impl/imgui_user_config.h | 12 ++++++++++++ xmake.lua | 2 +- 6 files changed, 26 insertions(+), 13 deletions(-) delete mode 100644 imgui_user_config.h create mode 100644 src/imgui_impl/imgui_user_config.h diff --git a/imgui_user_config.h b/imgui_user_config.h deleted file mode 100644 index fb3a8eda..00000000 --- a/imgui_user_config.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -void ImGuiAssert(wchar_t const* acpMessage, wchar_t const* acpFile, unsigned aLine); - -#define IM_ASSERT(expression) (void)((!!(expression)) || (ImGuiAssert(_CRT_WIDE(#expression), _CRT_WIDE(__FILE__), (unsigned)(__LINE__)), 0)) \ No newline at end of file diff --git a/src/Options.cpp b/src/Options.cpp index cd282fea..dce82d22 100644 --- a/src/Options.cpp +++ b/src/Options.cpp @@ -3,6 +3,9 @@ #include "Paths.h" #include "Utils.h" +// global definition "Enable ImGui Assertions" +bool g_ImGuiAssertionsEnabled { true }; + void Options::Load() { if (exists(m_paths.Config())) @@ -37,6 +40,9 @@ void Options::Load() } configFile.close(); } + + // set global "Enable ImGui Assertions" + g_ImGuiAssertionsEnabled = EnableImGuiAssertions; } void Options::Save() @@ -64,6 +70,9 @@ void Options::Save() std::ofstream o(m_paths.Config()); o << config.dump(4) << std::endl; + + // set global "Enable ImGui Assertions" + g_ImGuiAssertionsEnabled = EnableImGuiAssertions; } void Options::ResetToDefaults() diff --git a/src/Utils.cpp b/src/Utils.cpp index d5e66e4a..9bda4c20 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -143,8 +143,8 @@ void MakeSolObjectImmutable(sol::object aObj, const sol::state_view& aStateView) void ImGuiAssert(wchar_t const* acpMessage, wchar_t const* acpFile, unsigned aLine) { #ifdef NDEBUG - __declspec(dllimport) void __cdecl _wassert(wchar_t const* _Message, wchar_t const* _File, unsigned _Line); + // inline _wassert decl for NDEBUG as it is not emitted inside assert.h header in this case + _ACRTIMP void __cdecl _wassert(wchar_t const* _Message, wchar_t const* _File, unsigned _Line); #endif - if (CET::Get().GetOptions().EnableImGuiAssertions) - _wassert(acpMessage, acpFile, aLine); + _wassert(acpMessage, acpFile, aLine); } diff --git a/src/Utils.h b/src/Utils.h index 71deeefc..56f3025c 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -12,7 +12,4 @@ std::shared_ptr CreateLogger(const std::filesystem::path& aPath, sol::object DeepCopySolObject(sol::object aObj, const sol::state_view& aStateView); // makes sol object immutable when accessed from lua -void MakeSolObjectImmutable(sol::object aObj, const sol::state_view& aStateView); - -//// runtime assertions which can be enabled/disabled inside CET options -//void ImGuiAssert(wchar_t const* acpMessage, wchar_t const* acpFile, unsigned aLine); \ No newline at end of file +void MakeSolObjectImmutable(sol::object aObj, const sol::state_view& aStateView); \ No newline at end of file diff --git a/src/imgui_impl/imgui_user_config.h b/src/imgui_impl/imgui_user_config.h new file mode 100644 index 00000000..dbd89d92 --- /dev/null +++ b/src/imgui_impl/imgui_user_config.h @@ -0,0 +1,12 @@ +#pragma once + +// global declaration "Enable ImGui Assertions" +extern bool g_ImGuiAssertionsEnabled; + +// runtime assertions which can be enabled/disabled inside CET options +void ImGuiAssert(wchar_t const* acpMessage, wchar_t const* acpFile, unsigned aLine); + +// custom assertion function macro for ImGui +#define IM_ASSERT(expression) (void)( \ + (g_ImGuiAssertionsEnabled && ((!!(expression)) || \ + (ImGuiAssert(_CRT_WIDE(#expression), _CRT_WIDE(__FILE__), (unsigned)(__LINE__)), 0)))) \ No newline at end of file diff --git a/xmake.lua b/xmake.lua index bc532083..0af3957a 100644 --- a/xmake.lua +++ b/xmake.lua @@ -9,7 +9,7 @@ add_requireconfs("sol2", { configs = { includes_lua = false } }) add_rules("mode.debug","mode.releasedbg", "mode.release") add_rules("plugin.vsxmake.autoupdate") -local imguiUserConfig = path.absolute("imgui_user_config.h") +local imguiUserConfig = path.absolute("src/imgui_impl/imgui_user_config.h") add_requireconfs("imgui", { configs = { user_config = imguiUserConfig } }) if is_mode("debug") then From 6727e1c665887bfa14ebbfa3702bcc0afddf17e5 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Wed, 31 Mar 2021 16:12:47 +0200 Subject: [PATCH 13/35] Use TiltedCore from master --- xmake.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xmake.lua b/xmake.lua index 0af3957a..c256ea5c 100644 --- a/xmake.lua +++ b/xmake.lua @@ -3,7 +3,7 @@ set_xmakever("2.5.2") set_languages("cxx20") set_arch("x64") -add_requires("spdlog", "nlohmann_json", "hopscotch-map", "minhook", "mem", "imgui 1.82", "sol2", "tiltedcore 0.2.1", "sqlite3", "luajit") +add_requires("spdlog", "nlohmann_json", "hopscotch-map", "minhook", "mem", "imgui 1.82", "sol2", "tiltedcore master", "sqlite3", "luajit") add_requireconfs("sol2", { configs = { includes_lua = false } }) add_rules("mode.debug","mode.releasedbg", "mode.release") From d547988d63d5124bc87c5b86647be655814ec004 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Wed, 31 Mar 2021 16:17:42 +0200 Subject: [PATCH 14/35] Fix _wassert signature --- src/Utils.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Utils.cpp b/src/Utils.cpp index 9bda4c20..ec4bd6a0 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -139,12 +139,13 @@ void MakeSolObjectImmutable(sol::object aObj, const sol::state_view& aStateView) metatable[sol::meta_function::new_index] = []() {}; } +#ifdef NDEBUG +// inline _wassert decl for NDEBUG as it is not emitted inside assert.h header in this case +extern "C" _ACRTIMP void __cdecl _wassert(wchar_t const* _Message, wchar_t const* _File, unsigned _Line); +#endif + // runtime assertions which can be enabled/disabled inside CET options void ImGuiAssert(wchar_t const* acpMessage, wchar_t const* acpFile, unsigned aLine) { -#ifdef NDEBUG - // inline _wassert decl for NDEBUG as it is not emitted inside assert.h header in this case - _ACRTIMP void __cdecl _wassert(wchar_t const* _Message, wchar_t const* _File, unsigned _Line); -#endif _wassert(acpMessage, acpFile, aLine); } From 9b8c3d00e1783bd8bda4907e7d44575b0a5b8d16 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Wed, 31 Mar 2021 17:10:12 +0200 Subject: [PATCH 15/35] Don't block LuaVM update, only draw --- src/Utils.cpp | 2 +- src/overlay/Overlay.cpp | 4 ++-- src/overlay/widgets/Bindings.cpp | 4 ++-- src/overlay/widgets/Settings.cpp | 4 ++-- src/scripting/LuaVM.cpp | 10 ++++++---- src/scripting/LuaVM.h | 6 +++--- 6 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/Utils.cpp b/src/Utils.cpp index ec4bd6a0..913a2a90 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -102,7 +102,7 @@ std::shared_ptr CreateLogger(const std::filesystem::path& aPath, // deep copies sol object (doesnt take into account potential duplicates) sol::object DeepCopySolObject(sol::object aObj, const sol::state_view& aStateView) { - if (aObj.get_type() != sol::type::table) + if ((aObj == sol::nil) || (aObj.get_type() != sol::type::table)) return aObj; sol::table src{aObj.as()}; sol::table copy{aStateView, sol::create}; diff --git a/src/overlay/Overlay.cpp b/src/overlay/Overlay.cpp index a1cad98e..cad54013 100644 --- a/src/overlay/Overlay.cpp +++ b/src/overlay/Overlay.cpp @@ -101,7 +101,7 @@ void Overlay::Update() ImGui::OpenPopup("CET First Time Setup"); m_showFirstTimeModal = false; - m_vm.BlockUpdate(true); + m_vm.BlockDraw(true); } if (ImGui::BeginPopupModal("CET First Time Setup", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) @@ -122,7 +122,7 @@ void Overlay::Update() m_VKBIOverlay.Apply(); m_bindings.Save(); m_options.IsFirstLaunch = false; - m_vm.BlockUpdate(false); + m_vm.BlockDraw(false); ImGui::CloseCurrentPopup(); } diff --git a/src/overlay/widgets/Bindings.cpp b/src/overlay/widgets/Bindings.cpp index 1675f86c..184e5f1d 100644 --- a/src/overlay/widgets/Bindings.cpp +++ b/src/overlay/widgets/Bindings.cpp @@ -29,9 +29,9 @@ bool Bindings::OnDisable() if (m_enabled) { m_bindings.StopRecordingBind(); - m_vm.BlockUpdate(m_madeChanges); + m_vm.BlockDraw(m_madeChanges); m_madeChanges = (HelperWidgets::UnsavedChangesPopup(m_openChangesModal, m_madeChanges, m_saveCB, m_loadCB) == 0); - m_vm.BlockUpdate(m_madeChanges); + m_vm.BlockDraw(m_madeChanges); m_enabled = m_madeChanges; } return !m_enabled; diff --git a/src/overlay/widgets/Settings.cpp b/src/overlay/widgets/Settings.cpp index d538130b..8ed3f446 100644 --- a/src/overlay/widgets/Settings.cpp +++ b/src/overlay/widgets/Settings.cpp @@ -23,9 +23,9 @@ bool Settings::OnDisable() { if (m_enabled) { - m_vm.BlockUpdate(m_madeChanges); + m_vm.BlockDraw(m_madeChanges); m_madeChanges = (HelperWidgets::UnsavedChangesPopup(m_openChangesModal, m_madeChanges, m_saveCB, m_loadCB) == 0); - m_vm.BlockUpdate(m_madeChanges); + m_vm.BlockDraw(m_madeChanges); m_enabled = m_madeChanges; } return !m_enabled; diff --git a/src/scripting/LuaVM.cpp b/src/scripting/LuaVM.cpp index 281b4cc5..2e763feb 100644 --- a/src/scripting/LuaVM.cpp +++ b/src/scripting/LuaVM.cpp @@ -25,11 +25,13 @@ void LuaVM::Update(float aDeltaTime) if (!m_initialized && m_logCount.load(std::memory_order_relaxed) > 0) PostInitialize(); - if (!m_initialized || m_updateBlocked) + if (!m_initialized) return; m_scripting.TriggerOnUpdate(aDeltaTime); - m_scripting.TriggerOnDraw(); + + if (!m_drawBlocked) + m_scripting.TriggerOnDraw(); } void LuaVM::ReloadAllMods() @@ -71,9 +73,9 @@ bool LuaVM::IsInitialized() const return m_initialized; } -void LuaVM::BlockUpdate(bool aBlockUpdate) +void LuaVM::BlockDraw(bool aBlockDraw) { - m_updateBlocked = aBlockUpdate; + m_drawBlocked = aBlockDraw; } void LuaVM::RemoveTDBIDDerivedFrom(uint64_t aDBID) diff --git a/src/scripting/LuaVM.h b/src/scripting/LuaVM.h index e23e151f..d6fb9c4d 100644 --- a/src/scripting/LuaVM.h +++ b/src/scripting/LuaVM.h @@ -39,8 +39,8 @@ struct LuaVM void Initialize(); bool IsInitialized() const; - - void BlockUpdate(bool aBlockUpdate); + + void BlockDraw(bool aBlockDraw); // Used by TweakDB when you delete a custom record void RemoveTDBIDDerivedFrom(uint64_t aDBID); @@ -86,7 +86,7 @@ struct LuaVM Scripting m_scripting; bool m_initialized{ false }; - bool m_updateBlocked{ false }; + bool m_drawBlocked{ false }; Options& m_options; D3D12& m_d3d12; From 29cf7b6726449806c5501fcb7b292afd384c727b Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Wed, 31 Mar 2021 17:58:55 +0200 Subject: [PATCH 16/35] Also log ImGui assertions to main log file --- src/Utils.cpp | 1 + xmake.lua | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Utils.cpp b/src/Utils.cpp index 913a2a90..61423aad 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -147,5 +147,6 @@ extern "C" _ACRTIMP void __cdecl _wassert(wchar_t const* _Message, wchar_t const // runtime assertions which can be enabled/disabled inside CET options void ImGuiAssert(wchar_t const* acpMessage, wchar_t const* acpFile, unsigned aLine) { + spdlog::error(L"ImGui assertion failed in file \"{ 0 }\" at line { 1 }! Expression ({ 2 }) evaluates to false!", acpFile, aLine, acpMessage); _wassert(acpMessage, acpFile, aLine); } diff --git a/xmake.lua b/xmake.lua index c256ea5c..7e00f1d1 100644 --- a/xmake.lua +++ b/xmake.lua @@ -6,12 +6,12 @@ set_arch("x64") add_requires("spdlog", "nlohmann_json", "hopscotch-map", "minhook", "mem", "imgui 1.82", "sol2", "tiltedcore master", "sqlite3", "luajit") add_requireconfs("sol2", { configs = { includes_lua = false } }) -add_rules("mode.debug","mode.releasedbg", "mode.release") -add_rules("plugin.vsxmake.autoupdate") - local imguiUserConfig = path.absolute("src/imgui_impl/imgui_user_config.h") add_requireconfs("imgui", { configs = { user_config = imguiUserConfig } }) +add_rules("mode.debug","mode.releasedbg", "mode.release") +add_rules("plugin.vsxmake.autoupdate") + if is_mode("debug") then add_defines("CET_DEBUG") set_optimize("none") @@ -24,7 +24,7 @@ elseif is_mode("release") then end add_cxflags("/bigobj", "/MP") -add_defines("RED4EXT_STATIC_LIB", "UNICODE", "IMGUI_USER_CONFIG=\""..imguiUserConfig.."\"") +add_defines("RED4EXT_STATIC_LIB", "UNICODE") before_build(function (target) import("modules.version") @@ -61,7 +61,7 @@ target("RED4ext.SDK") add_includedirs("vendor/RED4ext.SDK/include/", { public = true }) target("cyber_engine_tweaks") - add_defines("WIN32_LEAN_AND_MEAN", "NOMINMAX", "SOL_ALL_SAFETIES_ON", "WINVER=0x0601", "SOL_LUAJIT=1") -- WINVER=0x0601 == Windows 7, we need this specified now for some reason + add_defines("WIN32_LEAN_AND_MEAN", "NOMINMAX", "WINVER=0x0601", "SOL_ALL_SAFETIES_ON", "SOL_LUAJIT=1", "SPDLOG_WCHAR_TO_UTF8_SUPPORT", "IMGUI_USER_CONFIG=\""..imguiUserConfig.."\"") -- WINVER=0x0601 == Windows 7, we need this specified now for some reason set_pcxxheader("src/stdafx.h") set_kind("shared") set_filename("cyber_engine_tweaks.asi") From 48793618133d0844382bad533a5b9f188961a4ea Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Wed, 31 Mar 2021 18:21:00 +0200 Subject: [PATCH 17/35] Reset substates of change detection on OnDisable for Settings widget --- src/overlay/widgets/Settings.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/overlay/widgets/Settings.cpp b/src/overlay/widgets/Settings.cpp index 8ed3f446..c71a898a 100644 --- a/src/overlay/widgets/Settings.cpp +++ b/src/overlay/widgets/Settings.cpp @@ -28,6 +28,12 @@ bool Settings::OnDisable() m_vm.BlockDraw(m_madeChanges); m_enabled = m_madeChanges; } + if (!m_enabled) + { + // reset changes substates + m_patchesChanged = false; + m_devChanged = false; + } return !m_enabled; } From 3f13566329190ecefe130b0de7cd48dfc5a4902e Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Wed, 31 Mar 2021 18:52:12 +0200 Subject: [PATCH 18/35] Move ImGuiAssert into separate file dedicated to ImGui user config impl --- src/Utils.cpp | 14 -------------- src/imgui_impl/imgui_user_config.cpp | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 14 deletions(-) create mode 100644 src/imgui_impl/imgui_user_config.cpp diff --git a/src/Utils.cpp b/src/Utils.cpp index 61423aad..887e8fc7 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -2,8 +2,6 @@ #include "Utils.h" -#include "CET.h" - #include #include @@ -138,15 +136,3 @@ void MakeSolObjectImmutable(sol::object aObj, const sol::state_view& aStateView) // prevent adding new properties metatable[sol::meta_function::new_index] = []() {}; } - -#ifdef NDEBUG -// inline _wassert decl for NDEBUG as it is not emitted inside assert.h header in this case -extern "C" _ACRTIMP void __cdecl _wassert(wchar_t const* _Message, wchar_t const* _File, unsigned _Line); -#endif - -// runtime assertions which can be enabled/disabled inside CET options -void ImGuiAssert(wchar_t const* acpMessage, wchar_t const* acpFile, unsigned aLine) -{ - spdlog::error(L"ImGui assertion failed in file \"{ 0 }\" at line { 1 }! Expression ({ 2 }) evaluates to false!", acpFile, aLine, acpMessage); - _wassert(acpMessage, acpFile, aLine); -} diff --git a/src/imgui_impl/imgui_user_config.cpp b/src/imgui_impl/imgui_user_config.cpp new file mode 100644 index 00000000..69201a91 --- /dev/null +++ b/src/imgui_impl/imgui_user_config.cpp @@ -0,0 +1,16 @@ +#include + +// NOTE: imgui_user_config.h is included by imgui.h which is included with precompiled header, so no need to include it here once more + +#ifdef NDEBUG +// inline _wassert decl for NDEBUG as it is not emitted inside assert.h header in this case +extern "C" _ACRTIMP void __cdecl _wassert(wchar_t const* _Message, wchar_t const* _File, unsigned _Line); +#endif + +// runtime assertions which can be enabled/disabled inside CET options +void ImGuiAssert(wchar_t const* acpMessage, wchar_t const* acpFile, unsigned aLine) +{ + // TODO - it looks like assertions dont get logged for some weird reason, even though there is flush_on set for errors (even higher for debug) + spdlog::error(L"ImGui assertion failed in file \"{ 0 }\" at line { 1 }! Expression ({ 2 }) evaluates to false!", acpFile, aLine, acpMessage); + _wassert(acpMessage, acpFile, aLine); +} From 3ae2d763a5182d1082f3f61d6dc9217063663d40 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Wed, 31 Mar 2021 21:26:36 +0200 Subject: [PATCH 19/35] Some nicer formatting for Bindings widget mod headings --- src/overlay/Overlay.cpp | 4 +- src/overlay/widgets/Bindings.cpp | 29 ++++++++++++-- src/overlay/widgets/HelperWidgets.cpp | 8 ++-- src/overlay/widgets/TweakDBEditor.cpp | 58 +++++++++++++-------------- 4 files changed, 60 insertions(+), 39 deletions(-) diff --git a/src/overlay/Overlay.cpp b/src/overlay/Overlay.cpp index cad54013..43df660e 100644 --- a/src/overlay/Overlay.cpp +++ b/src/overlay/Overlay.cpp @@ -110,9 +110,9 @@ void Overlay::Update() const auto longerTextSz { ImGui::CalcTextSize("Please, bind some key combination for toggling overlay!").x }; const auto diffTextSz { longerTextSz - shorterTextSz }; - ImGui::Text("Please, bind some key combination for toggling overlay!"); + ImGui::TextUnformatted("Please, bind some key combination for toggling overlay!"); ImGui::SetCursorPosX(diffTextSz / 2); - ImGui::Text("Combo can be composed from up to 4 keys."); + ImGui::TextUnformatted("Combo can be composed from up to 4 keys."); ImGui::Separator(); // TODO - do not hardcode offset! this somewhat works temporarily... diff --git a/src/overlay/widgets/Bindings.cpp b/src/overlay/widgets/Bindings.cpp index 184e5f1d..97b1998b 100644 --- a/src/overlay/widgets/Bindings.cpp +++ b/src/overlay/widgets/Bindings.cpp @@ -64,11 +64,32 @@ void Bindings::Update() curMod = curMod.substr(0, curMod.find('.')); if (prevMod != curMod) { + // make it writable (also checks for "cet" modname) + std::string activeModName { (curMod == "cet") ? ("Cyber Engine Tweaks") : (curMod) }; + + // transform to nicer format till modinfo is in + bool capitalize = true; + std::ranges::transform(std::as_const(activeModName), activeModName.begin(), + [&capitalize](char c) + { + if (!std::isalnum(c)) + { + capitalize = true; + return ' '; + } + if (capitalize) + { + capitalize = false; + return static_cast(std::toupper(static_cast(c))); + } + return c; + }); + + // add vertical spacing when this is not first iteration if (!prevMod.empty()) ImGui::Spacing(); - - std::string curModStr{curMod}; - ImGui::Text(curModStr.c_str()); + + ImGui::TextUnformatted(activeModName.c_str()); prevMod = curMod; } @@ -77,7 +98,7 @@ void Bindings::Update() } } else - ImGui::Text("LuaVM is not yet initialized!"); + ImGui::TextUnformatted("LuaVM is not yet initialized!"); } ImGui::EndChild(); diff --git a/src/overlay/widgets/HelperWidgets.cpp b/src/overlay/widgets/HelperWidgets.cpp index 1fd4f9c7..fc029c63 100644 --- a/src/overlay/widgets/HelperWidgets.cpp +++ b/src/overlay/widgets/HelperWidgets.cpp @@ -53,7 +53,7 @@ namespace HelperWidgets ImGui::PushStyleColor(ImGuiCol_Text, curTextColor); ImGui::PushID(&aVKBindInfo.Bind.Description); // ensure we have unique ID by using pointer to Description, is OK, pointer will not be used inside ImGui :P - ImGui::Text(label.c_str()); + ImGui::TextUnformatted(label.c_str()); ImGui::PopID(); ImGui::PopStyleColor(); @@ -102,7 +102,7 @@ namespace HelperWidgets ImGui::SetCursorPosX(ImGui::GetCursorPosX() + offset_x); ImGui::PushStyleColor(ImGuiCol_Text, curTextColor); - ImGui::Text(label.c_str()); + ImGui::TextUnformatted(label.c_str()); ImGui::PopStyleColor(); ImGui::SameLine(); @@ -130,8 +130,8 @@ namespace HelperWidgets const auto diffTextSz { longerTextSz - shorterTextSz }; ImGui::SetCursorPosX(diffTextSz / 2); - ImGui::Text("You have some unsaved changes."); - ImGui::Text("Do you wish to apply them or discard them?"); + ImGui::TextUnformatted("You have some unsaved changes."); + ImGui::TextUnformatted("Do you wish to apply them or discard them?"); ImGui::Separator(); const auto buttonWidth { (longerTextSz - ImGui::GetStyle().ItemSpacing.x) / 2 }; diff --git a/src/overlay/widgets/TweakDBEditor.cpp b/src/overlay/widgets/TweakDBEditor.cpp index 89c4a5a6..0af451f0 100644 --- a/src/overlay/widgets/TweakDBEditor.cpp +++ b/src/overlay/widgets/TweakDBEditor.cpp @@ -377,7 +377,7 @@ void TweakDBEditor::Update() // LuaVM is initialized after TweakDB, let's wait for it if (!m_vm.IsInitialized()) { - ImGui::Text("TweakDB is not initialized yet"); + ImGui::TextUnformatted("TweakDB is not initialized yet"); return; } @@ -1118,22 +1118,22 @@ bool TweakDBEditor::DrawFlatQuaternion(RED4ext::TweakDBID aDBID, RED4ext::CStack int32_t flags = aReadOnly ? ImGuiInputTextFlags_ReadOnly : ImGuiInputTextFlags_EnterReturnsTrue; - ImGui::Text("I"); + ImGui::TextUnformatted("I"); ImGui::SameLine(); ImGui::SetNextItemWidth(-1); bool valueChanged = ImGui::InputFloat("##I", &i, 0.0f, 0.0f, "%f", flags); - ImGui::Text("J"); + ImGui::TextUnformatted("J"); ImGui::SameLine(); ImGui::SetNextItemWidth(-1); valueChanged |= ImGui::InputFloat("##J", &j, 0.0f, 0.0f, "%f", flags); - ImGui::Text("K"); + ImGui::TextUnformatted("K"); ImGui::SameLine(); ImGui::SetNextItemWidth(-1); valueChanged |= ImGui::InputFloat("##K", &k, 0.0f, 0.0f, "%f", flags); - ImGui::Text("R"); + ImGui::TextUnformatted("R"); ImGui::SameLine(); ImGui::SetNextItemWidth(-1); valueChanged |= ImGui::InputFloat("##R", &r, 0.0f, 0.0f, "%f", flags); @@ -1171,17 +1171,17 @@ bool TweakDBEditor::DrawFlatEulerAngles(RED4ext::TweakDBID aDBID, RED4ext::CStac int32_t flags = aReadOnly ? ImGuiInputTextFlags_ReadOnly : ImGuiInputTextFlags_EnterReturnsTrue; - ImGui::Text("Roll "); + ImGui::TextUnformatted("Roll "); ImGui::SameLine(); ImGui::SetNextItemWidth(-1); bool valueChanged = ImGui::InputFloat("##Roll", &roll, 0.0f, 0.0f, "%f", flags); - ImGui::Text("Pitch"); + ImGui::TextUnformatted("Pitch"); ImGui::SameLine(); ImGui::SetNextItemWidth(-1); valueChanged |= ImGui::InputFloat("##Pitch", &pitch, 0.0f, 0.0f, "%f", flags); - ImGui::Text("Yaw "); + ImGui::TextUnformatted("Yaw "); ImGui::SameLine(); ImGui::SetNextItemWidth(-1); valueChanged |= ImGui::InputFloat("##Yaw", &yaw, 0.0f, 0.0f, "%f", flags); @@ -1218,17 +1218,17 @@ bool TweakDBEditor::DrawFlatVector3(RED4ext::TweakDBID aDBID, RED4ext::CStackTyp int32_t flags = aReadOnly ? ImGuiInputTextFlags_ReadOnly : ImGuiInputTextFlags_EnterReturnsTrue; - ImGui::Text("X"); + ImGui::TextUnformatted("X"); ImGui::SameLine(); ImGui::SetNextItemWidth(-1); bool valueChanged = ImGui::InputFloat("##X", &x, 0.0f, 0.0f, "%f", flags); - ImGui::Text("Y"); + ImGui::TextUnformatted("Y"); ImGui::SameLine(); ImGui::SetNextItemWidth(-1); valueChanged |= ImGui::InputFloat("##Y", &y, 0.0f, 0.0f, "%f", flags); - ImGui::Text("Z"); + ImGui::TextUnformatted("Z"); ImGui::SameLine(); ImGui::SetNextItemWidth(-1); valueChanged |= ImGui::InputFloat("##Z", &z, 0.0f, 0.0f, "%f", flags); @@ -1264,12 +1264,12 @@ bool TweakDBEditor::DrawFlatVector2(RED4ext::TweakDBID aDBID, RED4ext::CStackTyp int32_t flags = aReadOnly ? ImGuiInputTextFlags_ReadOnly : ImGuiInputTextFlags_EnterReturnsTrue; - ImGui::Text("X"); + ImGui::TextUnformatted("X"); ImGui::SameLine(); ImGui::SetNextItemWidth(-1); bool valueChanged = ImGui::InputFloat("##X", &x, 0.0f, 0.0f, "%f", flags); - ImGui::Text("Y"); + ImGui::TextUnformatted("Y"); ImGui::SameLine(); ImGui::SetNextItemWidth(-1); valueChanged |= ImGui::InputFloat("##Y", &y, 0.0f, 0.0f, "%f", flags); @@ -1306,7 +1306,7 @@ bool TweakDBEditor::DrawFlatColor(RED4ext::TweakDBID aDBID, RED4ext::CStackType& rgba[3] = pColor->Alpha / 255.0f; aReadOnly = true; - ImGui::Text("'Color' is not supported yet"); + ImGui::TextUnformatted("'Color' is not supported yet"); ImGui::SameLine(); int32_t flags = aReadOnly ? ImGuiColorEditFlags_NoInputs : ImGuiColorEditFlags_None; @@ -1344,8 +1344,8 @@ bool TweakDBEditor::DrawFlatLocKeyWrapper(RED4ext::TweakDBID aDBID, RED4ext::CSt { auto* pLocKey = static_cast(aStackType.value); - ImGui::Text("This is a LocalizationKey"); - ImGui::Text("Game.GetLocalizedTextByKey(...)"); + ImGui::TextUnformatted("This is a LocalizationKey"); + ImGui::TextUnformatted("Game.GetLocalizedTextByKey(...)"); uint64_t key = pLocKey->unk00; int32_t flags = aReadOnly ? ImGuiInputTextFlags_ReadOnly : ImGuiInputTextFlags_EnterReturnsTrue; @@ -1507,8 +1507,8 @@ bool TweakDBEditor::DrawFlatCName(RED4ext::TweakDBID aDBID, RED4ext::CStackType& { auto* pCName = static_cast(aStackType.value); - ImGui::Text("This is not just a string."); - ImGui::Text("Game is expecting specific values."); + ImGui::TextUnformatted("This is not just a string."); + ImGui::TextUnformatted("Game is expecting specific values."); // Is it worth it to implement a dropdown like DrawTweakDBID? RED4ext::CName newCName; @@ -1745,7 +1745,7 @@ void TweakDBEditor::DrawRecordsTab() ImGui::TableNextColumn(); if (flat.m_isMissing) { - ImGui::Text("ERROR_FLAT_NOT_FOUND"); + ImGui::TextUnformatted("ERROR_FLAT_NOT_FOUND"); } else { @@ -1862,7 +1862,7 @@ void TweakDBEditor::DrawFlatsTab() ImGui::TableNextColumn(); if (flat.m_isMissing) { - ImGui::Text("ERROR_FLAT_NOT_FOUND"); + ImGui::TextUnformatted("ERROR_FLAT_NOT_FOUND"); } else { @@ -1886,13 +1886,13 @@ void TweakDBEditor::DrawAdvancedTab() if (CDPRTweakDBMetadata::Get()->IsInitialized()) { ImGui::PushStyleColor(ImGuiCol_Text, 0xFF00FF00); - ImGui::Text("'tweakdb.str' is loaded!"); + ImGui::TextUnformatted("'tweakdb.str' is loaded!"); ImGui::PopStyleColor(); } else { ImGui::PushStyleColor(ImGuiCol_Text, 0xFF0000FF); - ImGui::Text("'tweakdb.str' is not loaded."); + ImGui::TextUnformatted("'tweakdb.str' is not loaded."); ImGui::PopStyleColor(); ImGui::TreePush(); ImGui::PushStyleColor(ImGuiCol_FrameBg, IM_COL32_BLACK_TRANS); @@ -1900,8 +1900,8 @@ void TweakDBEditor::DrawAdvancedTab() char pLink[] = "https://www.cyberpunk.net/en/modding-support"; ImGui::InputText("##cdprLink", pLink, sizeof(pLink) - 1, ImGuiInputTextFlags_ReadOnly); ImGui::PopStyleColor(2); - ImGui::Text("1) Download and unpack 'Metadata'"); - ImGui::Text("2) Copy 'tweakdb.str' to 'plugins\\cyber_engine_tweaks\\tweakdb.str'"); + ImGui::TextUnformatted("1) Download and unpack 'Metadata'"); + ImGui::TextUnformatted("2) Copy 'tweakdb.str' to 'plugins\\cyber_engine_tweaks\\tweakdb.str'"); std::string cetDir = CET::Get().GetPaths().CETRoot().string(); ImGui::Text("Full path: %s", cetDir.c_str()); if (ImGui::Button("3) Load tweakdb.str")) @@ -1918,13 +1918,13 @@ void TweakDBEditor::DrawAdvancedTab() if (ResourcesList::Get()->IsInitialized()) { ImGui::PushStyleColor(ImGuiCol_Text, 0xFF00FF00); - ImGui::Text("'archivehashes.txt' is loaded!"); + ImGui::TextUnformatted("'archivehashes.txt' is loaded!"); ImGui::PopStyleColor(); } else { ImGui::PushStyleColor(ImGuiCol_Text, 0xFF0000FF); - ImGui::Text("'archivehashes.txt' is not loaded."); + ImGui::TextUnformatted("'archivehashes.txt' is not loaded."); ImGui::PopStyleColor(); ImGui::TreePush(); ImGui::PushStyleColor(ImGuiCol_FrameBg, IM_COL32_BLACK_TRANS); @@ -1932,8 +1932,8 @@ void TweakDBEditor::DrawAdvancedTab() char pLink[] = "https://github.com/WolvenKit/Wolvenkit/raw/master/WolvenKit.Common/Resources/archivehashes.zip"; ImGui::InputText("##wkitLink", pLink, sizeof(pLink) - 1, ImGuiInputTextFlags_ReadOnly); ImGui::PopStyleColor(2); - ImGui::Text("1) Download and unpack 'archivehashes.zip'"); - ImGui::Text("2) Copy 'archivehashes.txt' to 'plugins\\cyber_engine_tweaks\\archivehashes.txt'"); + ImGui::TextUnformatted("1) Download and unpack 'archivehashes.zip'"); + ImGui::TextUnformatted("2) Copy 'archivehashes.txt' to 'plugins\\cyber_engine_tweaks\\archivehashes.txt'"); std::string cetDir = CET::Get().GetPaths().CETRoot().string(); ImGui::Text("Full path: %s", cetDir.c_str()); if (ImGui::Button("3) Load archivehashes.txt")) @@ -2042,7 +2042,7 @@ void TweakDBEditor::DrawAdvancedTab() statusTimer = 0.0f; } } - ImGui::Text(status); + ImGui::TextUnformatted(status); } ImGui::EndChild(); } From 126913f3251872df5df01a1fd6b0bbcb906e4e67 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Thu, 1 Apr 2021 11:39:57 +0200 Subject: [PATCH 20/35] Register ImGui.TreePop with Lua --- src/sol_imgui/sol_imgui.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sol_imgui/sol_imgui.h b/src/sol_imgui/sol_imgui.h index 38082959..ed999026 100644 --- a/src/sol_imgui/sol_imgui.h +++ b/src/sol_imgui/sol_imgui.h @@ -2698,6 +2698,7 @@ namespace sol_ImGui sol::resolve(TreeNodeEx) )); ImGui.set_function("TreePush" , TreePush); + ImGui.set_function("TreePop" , TreePop); ImGui.set_function("GetTreeNodeToLabelSpacing" , GetTreeNodeToLabelSpacing); ImGui.set_function("CollapsingHeader" , sol::overload( sol::resolve(CollapsingHeader), From f3be239011d84ff2aa1a1fb4be7bc4752dcd987a Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Thu, 1 Apr 2021 13:19:19 +0200 Subject: [PATCH 21/35] Fix TweakDB assertion on SetFlat (affected only debug builds) --- src/reverse/TweakDB.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reverse/TweakDB.cpp b/src/reverse/TweakDB.cpp index 60fed90f..98afbc34 100644 --- a/src/reverse/TweakDB.cpp +++ b/src/reverse/TweakDB.cpp @@ -714,7 +714,7 @@ int32_t FlatPool::GetOrCreate(const RED4ext::CStackType& acStackType, HashType a int32_t existingTDBOffset = Get(acStackType, aHash); if (existingTDBOffset != -1) { - assert(existingTDBOffset == aTDBOffset); + assert((aTDBOffset == -1) || (existingTDBOffset == aTDBOffset)); return existingTDBOffset; } From 3e2684e548aba341f06750db6a4dfba71cce4852 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Thu, 1 Apr 2021 14:14:24 +0200 Subject: [PATCH 22/35] Update TiltedCore to 0.2.2 --- xmake.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xmake.lua b/xmake.lua index 9e655b01..146fed17 100644 --- a/xmake.lua +++ b/xmake.lua @@ -3,7 +3,7 @@ set_xmakever("2.5.2") set_languages("cxx20") set_arch("x64") -add_requires("spdlog", "nlohmann_json", "hopscotch-map", "minhook", "mem", "imgui 1.82", "sol2", "tiltedcore master", "sqlite3", "luajit") +add_requires("spdlog", "nlohmann_json", "hopscotch-map", "minhook", "mem", "imgui 1.82", "sol2", "tiltedcore 0.2.2", "sqlite3", "luajit") add_requireconfs("sol2", { configs = { includes_lua = false } }) local imguiUserConfig = path.absolute("src/imgui_impl/imgui_user_config.h") From 13375d79969ec7d13c9e79802682e17fc701e3a0 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Thu, 1 Apr 2021 18:13:35 +0200 Subject: [PATCH 23/35] Fix single inputs in VKBindings --- src/VKBindings.cpp | 88 +++++++++++++++++++++++++++++++++++++--------- src/VKBindings.h | 4 ++- 2 files changed, 75 insertions(+), 17 deletions(-) diff --git a/src/VKBindings.cpp b/src/VKBindings.cpp index 71e3bb91..f2f6106e 100644 --- a/src/VKBindings.cpp +++ b/src/VKBindings.cpp @@ -202,19 +202,34 @@ void VKBindings::Clear() m_recordingBind = {}; } +inline static bool FirstKeyMatches(uint64_t aFirst, uint64_t aSecond) +{ + return ((aFirst & 0xFFFF000000000000ull) == (aSecond & 0xFFFF000000000000ull)); +} + bool VKBindings::Bind(uint64_t aVKCodeBind, const VKBind& aBind) { - // bind check 1 + // bind check 1 (check for rebind and already bound case) { - auto bind = m_binds.find(aVKCodeBind); + auto bind = m_binds.lower_bound(aVKCodeBind); if (bind != m_binds.end()) { - if (bind->second.ID == aBind.ID) + if (bind->first == aVKCodeBind) { - bind->second.Handler = aBind.Handler; // rebind - return true; + if (bind->second.ID == aBind.ID) + { + bind->second.Handler = aBind.Handler; // rebind + return true; + } + return false; // combo already bound and it is not the same VKBind! + } + // in this case, we may have found a hotkey or single input starting with same key + if (FirstKeyMatches(aVKCodeBind, bind->first)) + { + // first char matches! lets check that both binds are hotkey in this case + if (aBind.IsInput() || bind->second.IsInput()) + return false; // one of these is not a hotkey! single inputs cannot start with same key as some hotkey and vice versa! } - return false; // combo already bound and it is not the same VKBind! } } @@ -551,9 +566,11 @@ bool VKBindings::IsLastRecordingKey(USHORT aVKCode) LRESULT VKBindings::RecordKeyDown(USHORT aVKCode) { - for (size_t i = 0; i < m_recordingLength; ++i) - if (m_recording[i] == aVKCode) - return 0; // ignore repeats + if (m_keyStates[aVKCode]) + return 0; // ignore repeats + + // mark key down + m_keyStates[aVKCode] = true; if (m_recordingLength >= m_recording.size()) { @@ -568,12 +585,7 @@ LRESULT VKBindings::RecordKeyDown(USHORT aVKCode) const VKBind* bind { VerifyRecording() }; if (m_isBindRecording) - { - if (m_recordingBind.IsInput()) - return RecordKeyUp(aVKCode); // instantly register bind for single inputs - return 0; // don't do anything else when bind is being recorded - } if (bind && (bind != VKBRecord_OK)) { @@ -592,6 +604,12 @@ LRESULT VKBindings::RecordKeyDown(USHORT aVKCode) const std::lock_guard lock(m_queuedCallbacksLock); m_queuedCallbacks.push(delayedCall); } + // reset recording for single input + if (bind->IsInput()) + { + m_recording.fill(0); + m_recordingLength = 0; + } } } } @@ -601,6 +619,44 @@ LRESULT VKBindings::RecordKeyDown(USHORT aVKCode) LRESULT VKBindings::RecordKeyUp(USHORT aVKCode) { + if (!m_keyStates[aVKCode]) + return 0; // ignore up event when we did not register down event + + // mark key up + m_keyStates[aVKCode] = false; + + // handle single inputs first + if (!m_recordingLength) + { + m_recording[m_recordingLength++] = aVKCode; + m_recordingResult = EncodeVKCodeBind(m_recording); + const auto* cpBind = VerifyRecording(); + if (cpBind && (cpBind != VKBRecord_OK)) + { + if (cpBind->IsInput()) + { + if (m_pOverlay && !m_pOverlay->IsEnabled()) // we dont want to handle bindings if overlay is open + { + if (cpBind->IsValid()) // prevention for freshly loaded bind from file without rebinding + { + const std::lock_guard lock(m_queuedCallbacksLock); + m_queuedCallbacks.push(cpBind->DelayedCall(false)); + } + } + else + { + // remark key as down! otherwise, bad things may happen... + m_keyStates[aVKCode] = true; + } + } + } + m_recordingResult = 0; + m_recording[0] = 0; + m_recordingLength = 0; // explicitly reset to 0, as VerifyRecording can make it 0 which would underflow if we decreased it... + return 0; + } + + // handle hotkeys for (size_t i = 0; i < m_recordingLength; ++i) { if (m_recording[i] == aVKCode) @@ -725,13 +781,13 @@ LRESULT VKBindings::HandleRAWInput(HRAWINPUT ahRAWInput) return RecordKeyUp(VK_XBUTTON2); case RI_MOUSE_WHEEL: { - const USHORT key { static_cast(RI_MOUSE_WHEEL | (m.usButtonData & 0x8000) ? 0 : 1) }; + const USHORT key { static_cast(RI_MOUSE_WHEEL | ((m.usButtonData & 0x8000) ? 0 : 1)) }; RecordKeyDown(key); return RecordKeyUp(key); } case RI_MOUSE_HWHEEL: { - const USHORT key{static_cast(RI_MOUSE_HWHEEL | (m.usButtonData & 0x8000) ? 0 : 1)}; + const USHORT key{static_cast(RI_MOUSE_HWHEEL | ((m.usButtonData & 0x8000) ? 0 : 1))}; RecordKeyDown(key); return RecordKeyUp(key); } diff --git a/src/VKBindings.h b/src/VKBindings.h index 25a97c3c..34b7c8c1 100644 --- a/src/VKBindings.h +++ b/src/VKBindings.h @@ -127,11 +127,13 @@ struct VKBindings LRESULT HandleRAWInput(HRAWINPUT ahRAWInput); + std::bitset<1 << 16> m_keyStates{ }; + std::map m_binds{ }; TiltedPhoques::Map m_idToBind{ }; std::mutex m_queuedCallbacksLock{ }; - std::queue> m_queuedCallbacks{}; + std::queue> m_queuedCallbacks{ }; VKCodeBindDecoded m_recording{ }; size_t m_recordingLength{ 0 }; From c3b5cf15774198b528a2062c2342e9fce2c0d965 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Fri, 2 Apr 2021 12:02:56 +0200 Subject: [PATCH 24/35] Use TaskQueue from TiltedCore instead of std queue+mutex in VKBindings --- src/VKBindings.cpp | 23 +++++------------------ src/VKBindings.h | 7 +++---- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/src/VKBindings.cpp b/src/VKBindings.cpp index f2f6106e..5bbb5f63 100644 --- a/src/VKBindings.cpp +++ b/src/VKBindings.cpp @@ -188,12 +188,7 @@ void VKBindings::Save() void VKBindings::Update() { - const std::lock_guard lock(m_queuedCallbacksLock); - while (!m_queuedCallbacks.empty()) - { - m_queuedCallbacks.front()(); - m_queuedCallbacks.pop(); - } + m_queuedCallbacks.Drain(); } void VKBindings::Clear() @@ -600,10 +595,8 @@ LRESULT VKBindings::RecordKeyDown(USHORT aVKCode) { auto delayedCall { bind->DelayedCall(true) }; if (delayedCall) - { - const std::lock_guard lock(m_queuedCallbacksLock); - m_queuedCallbacks.push(delayedCall); - } + m_queuedCallbacks.Add(delayedCall); + // reset recording for single input if (bind->IsInput()) { @@ -638,10 +631,7 @@ LRESULT VKBindings::RecordKeyUp(USHORT aVKCode) if (m_pOverlay && !m_pOverlay->IsEnabled()) // we dont want to handle bindings if overlay is open { if (cpBind->IsValid()) // prevention for freshly loaded bind from file without rebinding - { - const std::lock_guard lock(m_queuedCallbacksLock); - m_queuedCallbacks.push(cpBind->DelayedCall(false)); - } + m_queuedCallbacks.Add(cpBind->DelayedCall(false)); } else { @@ -690,10 +680,7 @@ LRESULT VKBindings::RecordKeyUp(USHORT aVKCode) if (!bind->second.ID.compare(0, 4, "cet.")) bind->second.Call(false); // we need to execute this immediately, otherwise cursor will not show on overlay toggle else - { - const std::lock_guard lock(m_queuedCallbacksLock); - m_queuedCallbacks.push(bind->second.DelayedCall(false)); - } + m_queuedCallbacks.Add(bind->second.DelayedCall(false)); } } return 0; diff --git a/src/VKBindings.h b/src/VKBindings.h index 34b7c8c1..82dd6616 100644 --- a/src/VKBindings.h +++ b/src/VKBindings.h @@ -129,11 +129,10 @@ struct VKBindings std::bitset<1 << 16> m_keyStates{ }; - std::map m_binds{ }; + std::map m_binds{ }; // this map needs to be ordered! TiltedPhoques::Map m_idToBind{ }; - - std::mutex m_queuedCallbacksLock{ }; - std::queue> m_queuedCallbacks{ }; + + TiltedPhoques::TaskQueue m_queuedCallbacks{ }; VKCodeBindDecoded m_recording{ }; size_t m_recordingLength{ 0 }; From 520ccad601cba223ab22d69ebd0f997ce7fcd060 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Fri, 2 Apr 2021 12:27:56 +0200 Subject: [PATCH 25/35] Cleanup --- src/overlay/widgets/Settings.cpp | 2 -- src/scripting/LuaVM.h | 3 +-- src/scripting/LuaVM_Hooks.cpp | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/overlay/widgets/Settings.cpp b/src/overlay/widgets/Settings.cpp index c71a898a..f4a88dc8 100644 --- a/src/overlay/widgets/Settings.cpp +++ b/src/overlay/widgets/Settings.cpp @@ -74,9 +74,7 @@ void Settings::Update() { if (ImGui::BeginChild("##SETTINGS_DEV")) { - HelperWidgets::BoolWidget("Draw ImGui Diagnostic Window:", m_options.DrawImGuiDiagnosticWindow, m_options.DrawImGuiDiagnosticWindow); - m_devChanged = HelperWidgets::BoolWidget("Remove Dead Bindings:", m_removeDeadBindings, m_options.RemoveDeadBindings); m_devChanged |= HelperWidgets::BoolWidget("Enable ImGui Assertions:", m_enableImGuiAssertions, m_options.EnableImGuiAssertions); m_devChanged |= HelperWidgets::BoolWidget("Enable Debug Menu:", m_patchEnableDebug, m_options.PatchEnableDebug); diff --git a/src/scripting/LuaVM.h b/src/scripting/LuaVM.h index d6fb9c4d..c8db10d7 100644 --- a/src/scripting/LuaVM.h +++ b/src/scripting/LuaVM.h @@ -87,8 +87,7 @@ struct LuaVM bool m_initialized{ false }; bool m_drawBlocked{ false }; - - Options& m_options; + D3D12& m_d3d12; size_t m_connectUpdate; }; diff --git a/src/scripting/LuaVM_Hooks.cpp b/src/scripting/LuaVM_Hooks.cpp index 85278e01..6ad8e83e 100644 --- a/src/scripting/LuaVM_Hooks.cpp +++ b/src/scripting/LuaVM_Hooks.cpp @@ -80,7 +80,6 @@ void LuaVM::HookLogChannel(RED4ext::IScriptable*, RED4ext::CStackFrame* apStack, LuaVM::LuaVM(Paths& aPaths, VKBindings& aBindings, D3D12& aD3D12, Options& aOptions) : m_scripting(aPaths, aBindings, aD3D12, aOptions) - , m_options(aOptions) , m_d3d12(aD3D12) { Hook(aOptions); From e35db2057f1ace01f40af60932a3fa0b1470dc8d Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Fri, 2 Apr 2021 14:32:31 +0200 Subject: [PATCH 26/35] Fix build --- src/overlay/widgets/Bindings.cpp | 14 -------------- src/overlay/widgets/HelperWidgets.cpp | 4 ++-- src/overlay/widgets/HelperWidgets.h | 2 +- 3 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/overlay/widgets/Bindings.cpp b/src/overlay/widgets/Bindings.cpp index cb3b8193..e7bbdcb8 100644 --- a/src/overlay/widgets/Bindings.cpp +++ b/src/overlay/widgets/Bindings.cpp @@ -145,21 +145,7 @@ void Bindings::ResetChanges() m_bindings.UnBind(vkBindInfo.CodeBind); if (vkBindInfo.SavedCodeBind) m_bindings.Bind(vkBindInfo.SavedCodeBind, vkBindInfo.Bind); - vkBindInfo.CodeBind = vkBindInfo.SavedCodeBind; - } -} - -void Bindings::ResetChanges() -{ - for (auto& vkBindInfo : m_vkBindInfos) - { - if (vkBindInfo.CodeBind == vkBindInfo.SavedCodeBind) - continue; - if (vkBindInfo.CodeBind) - m_bindings.UnBind(vkBindInfo.CodeBind); - if (vkBindInfo.SavedCodeBind) - m_bindings.Bind(vkBindInfo.SavedCodeBind, vkBindInfo.Bind); vkBindInfo.CodeBind = vkBindInfo.SavedCodeBind; } } diff --git a/src/overlay/widgets/HelperWidgets.cpp b/src/overlay/widgets/HelperWidgets.cpp index ed41644f..cd9321c4 100644 --- a/src/overlay/widgets/HelperWidgets.cpp +++ b/src/overlay/widgets/HelperWidgets.cpp @@ -27,7 +27,7 @@ namespace HelperWidgets return activeID; } - bool BindWidget(VKBindInfo& aVKBindInfo, bool aUnbindable, float offset_x) + bool BindWidget(VKBindInfo& aVKBindInfo, bool aUnbindable, float aOffsetX) { VKBindings& vkb { CET::Get().GetBindings() }; @@ -49,7 +49,7 @@ namespace HelperWidgets ImGui::AlignTextToFramePadding(); - ImGui::SetCursorPosX(ImGui::GetCursorPosX() + offset_x); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + aOffsetX); ImGui::PushStyleColor(ImGuiCol_Text, curTextColor); ImGui::PushID(&aVKBindInfo.Bind.Description); // ensure we have unique ID by using pointer to Description, is OK, pointer will not be used inside ImGui :P diff --git a/src/overlay/widgets/HelperWidgets.h b/src/overlay/widgets/HelperWidgets.h index 63a35a7e..a64b6595 100644 --- a/src/overlay/widgets/HelperWidgets.h +++ b/src/overlay/widgets/HelperWidgets.h @@ -5,7 +5,7 @@ namespace HelperWidgets { WidgetID ToolbarWidget(); -void BindWidget(VKBindInfo& aVKBindInfo, const std::string& acId); +bool BindWidget(VKBindInfo& aVKBindInfo, bool aUnbindable, float aOffsetX = 0.0f); bool BoolWidget(const std::string& aLabel, bool& aCurrent, bool aSaved, float aOffsetX = 0.0f); using TUCHPSave = std::function; From 4d79dc8c0fc63edee45e4af9c3d7211f85170af3 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Fri, 2 Apr 2021 14:50:20 +0200 Subject: [PATCH 27/35] Add missing option into ResetToDefaults in Options.cpp --- src/Options.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Options.cpp b/src/Options.cpp index c5bfaa05..77c67ee7 100644 --- a/src/Options.cpp +++ b/src/Options.cpp @@ -74,7 +74,6 @@ void Options::Save() void Options::ResetToDefaults() { - PatchEnableDebug = false; PatchRemovePedestrians = false; PatchAsyncCompute = false; PatchAntialiasing = false; @@ -84,7 +83,10 @@ void Options::ResetToDefaults() PatchDisableVignette = false; PatchDisableBoundaryTeleport = false; PatchDisableWin7Vsync = false; + RemoveDeadBindings = true; + EnableImGuiAssertions = true; + PatchEnableDebug = false; DumpGameOptions = false; Save(); From 649b7ffb495788cb6407f1b0c60dd45d8fa08489 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Fri, 2 Apr 2021 15:47:42 +0200 Subject: [PATCH 28/35] Add a bit more spacing in Bindings window between elements --- src/overlay/widgets/Bindings.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/overlay/widgets/Bindings.cpp b/src/overlay/widgets/Bindings.cpp index e7bbdcb8..9992ce37 100644 --- a/src/overlay/widgets/Bindings.cpp +++ b/src/overlay/widgets/Bindings.cpp @@ -93,11 +93,12 @@ void Bindings::Update() ImGui::Spacing(); ImGui::TextUnformatted(activeModName.c_str()); + ImGui::Spacing(); prevMod = curMod; } - m_madeChanges |= HelperWidgets::BindWidget(vkBindInfo, (vkBindInfo.Bind.ID != m_overlayKeyID)); + m_madeChanges |= HelperWidgets::BindWidget(vkBindInfo, (vkBindInfo.Bind.ID != m_overlayKeyID), 10.0f); } } else From 369380900615a7db71d090b73c9c3d8305f6d01d Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Fri, 2 Apr 2021 18:44:28 +0200 Subject: [PATCH 29/35] Fix alignemnt in TweakDB Editor and Console widgets --- src/overlay/widgets/Console.cpp | 3 +- src/overlay/widgets/TweakDBEditor.cpp | 62 +++++++++++++-------------- 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/src/overlay/widgets/Console.cpp b/src/overlay/widgets/Console.cpp index e82ef8d3..61c5cc4e 100644 --- a/src/overlay/widgets/Console.cpp +++ b/src/overlay/widgets/Console.cpp @@ -119,10 +119,9 @@ void Console::Update() ImGui::SetKeyboardFocusHere(); m_focusConsoleInput = false; } - ImGui::PushItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); const auto execute = ImGui::InputText("##InputCommand", m_Command, std::size(m_Command), ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackHistory, &HandleConsoleHistory, this); - ImGui::PopItemWidth(); ImGui::SetItemDefaultFocus(); if (execute) { diff --git a/src/overlay/widgets/TweakDBEditor.cpp b/src/overlay/widgets/TweakDBEditor.cpp index 0af451f0..8943532b 100644 --- a/src/overlay/widgets/TweakDBEditor.cpp +++ b/src/overlay/widgets/TweakDBEditor.cpp @@ -709,7 +709,7 @@ bool TweakDBEditor::DrawRecordDropdown(const char* acpLabel, RED4ext::TweakDBID& if (comboOpened) { static float searchTimer = 0.0f; - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); if (ImGui::InputTextWithHint("##dropdownSearch", "Search", s_tweakdbidFilterBuffer, sizeof(s_tweakdbidFilterBuffer))) { @@ -1057,7 +1057,7 @@ bool TweakDBEditor::DrawFlatTweakDBID(RED4ext::TweakDBID aDBID, RED4ext::CStackT if (aReadOnly) { - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); std::string recordName = GetTweakDBIDStringRecord(*pDBID); ImGui::InputText("", recordName.data(), recordName.size(), ImGuiInputTextFlags_ReadOnly); @@ -1076,17 +1076,17 @@ bool TweakDBEditor::DrawFlatTweakDBID(RED4ext::TweakDBID aDBID, RED4ext::CStackT } } - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); ImGui::InputScalar("##raw", ImGuiDataType_U64, aStackType.value, nullptr, nullptr, "%016llX", ImGuiInputTextFlags_ReadOnly); } else { RED4ext::TweakDBID dbid = *pDBID; - bool valueChanged = DrawRecordDropdown("", dbid, -1); + bool valueChanged = DrawRecordDropdown("", dbid, -FLT_MIN); int32_t flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CharsHexadecimal; - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); valueChanged |= ImGui::InputScalar("##raw", ImGuiDataType_U64, &dbid.value, nullptr, nullptr, "%016llX", flags); if (valueChanged) @@ -1120,22 +1120,22 @@ bool TweakDBEditor::DrawFlatQuaternion(RED4ext::TweakDBID aDBID, RED4ext::CStack ImGui::TextUnformatted("I"); ImGui::SameLine(); - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); bool valueChanged = ImGui::InputFloat("##I", &i, 0.0f, 0.0f, "%f", flags); ImGui::TextUnformatted("J"); ImGui::SameLine(); - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); valueChanged |= ImGui::InputFloat("##J", &j, 0.0f, 0.0f, "%f", flags); ImGui::TextUnformatted("K"); ImGui::SameLine(); - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); valueChanged |= ImGui::InputFloat("##K", &k, 0.0f, 0.0f, "%f", flags); ImGui::TextUnformatted("R"); ImGui::SameLine(); - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); valueChanged |= ImGui::InputFloat("##R", &r, 0.0f, 0.0f, "%f", flags); if (!aReadOnly && valueChanged) @@ -1173,17 +1173,17 @@ bool TweakDBEditor::DrawFlatEulerAngles(RED4ext::TweakDBID aDBID, RED4ext::CStac ImGui::TextUnformatted("Roll "); ImGui::SameLine(); - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); bool valueChanged = ImGui::InputFloat("##Roll", &roll, 0.0f, 0.0f, "%f", flags); ImGui::TextUnformatted("Pitch"); ImGui::SameLine(); - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); valueChanged |= ImGui::InputFloat("##Pitch", &pitch, 0.0f, 0.0f, "%f", flags); ImGui::TextUnformatted("Yaw "); ImGui::SameLine(); - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); valueChanged |= ImGui::InputFloat("##Yaw", &yaw, 0.0f, 0.0f, "%f", flags); if (!aReadOnly && valueChanged) @@ -1220,17 +1220,17 @@ bool TweakDBEditor::DrawFlatVector3(RED4ext::TweakDBID aDBID, RED4ext::CStackTyp ImGui::TextUnformatted("X"); ImGui::SameLine(); - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); bool valueChanged = ImGui::InputFloat("##X", &x, 0.0f, 0.0f, "%f", flags); ImGui::TextUnformatted("Y"); ImGui::SameLine(); - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); valueChanged |= ImGui::InputFloat("##Y", &y, 0.0f, 0.0f, "%f", flags); ImGui::TextUnformatted("Z"); ImGui::SameLine(); - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); valueChanged |= ImGui::InputFloat("##Z", &z, 0.0f, 0.0f, "%f", flags); if (!aReadOnly && valueChanged) @@ -1266,12 +1266,12 @@ bool TweakDBEditor::DrawFlatVector2(RED4ext::TweakDBID aDBID, RED4ext::CStackTyp ImGui::TextUnformatted("X"); ImGui::SameLine(); - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); bool valueChanged = ImGui::InputFloat("##X", &x, 0.0f, 0.0f, "%f", flags); ImGui::TextUnformatted("Y"); ImGui::SameLine(); - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); valueChanged |= ImGui::InputFloat("##Y", &y, 0.0f, 0.0f, "%f", flags); if (!aReadOnly && valueChanged) @@ -1310,7 +1310,7 @@ bool TweakDBEditor::DrawFlatColor(RED4ext::TweakDBID aDBID, RED4ext::CStackType& ImGui::SameLine(); int32_t flags = aReadOnly ? ImGuiColorEditFlags_NoInputs : ImGuiColorEditFlags_None; - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); bool valueChanged = ImGui::ColorEdit4("", rgba, flags | ImGuiColorEditFlags_AlphaPreview); // Color picker returns true everytime it changes // It will overkill the FlatValuePool @@ -1349,13 +1349,13 @@ bool TweakDBEditor::DrawFlatLocKeyWrapper(RED4ext::TweakDBID aDBID, RED4ext::CSt uint64_t key = pLocKey->unk00; int32_t flags = aReadOnly ? ImGuiInputTextFlags_ReadOnly : ImGuiInputTextFlags_EnterReturnsTrue; - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); bool valueChanged = ImGui::InputScalar("", ImGuiDataType_U64, &key, nullptr, nullptr, nullptr, flags); { RED4ext::CString localizedText; ExecuteGlobalFunction("GetLocalizedTextByKey", &localizedText, key); - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); ImGui::InputText("##string", (char*)localizedText.c_str(), localizedText.Length(), ImGuiInputTextFlags_ReadOnly); } @@ -1388,20 +1388,20 @@ bool TweakDBEditor::DrawFlatResourceAsyncRef(RED4ext::TweakDBID aDBID, RED4ext:: int32_t flags = aReadOnly ? ImGuiInputTextFlags_ReadOnly : ImGuiInputTextFlags_EnterReturnsTrue; flags |= ImGuiInputTextFlags_CharsHexadecimal; - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); bool valueChanged = ImGui::InputScalar("", ImGuiDataType_U64, &hashRef, nullptr, nullptr, "%016llX", flags); if (ResourcesList::Get()->IsInitialized()) { const std::string& resourceName = ResourcesList::Get()->Resolve(hashRef); - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); if (ImGui::BeginCombo("##resolvedHash", resourceName.c_str(), ImGuiComboFlags_HeightLargest)) { static float searchTimer = -1.0f; static int resourcesCount = 0; static char comboSearchStr[256]{}; - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); if (ImGui::InputTextWithHint("##dropdownSearch", "Search", comboSearchStr, sizeof(comboSearchStr))) { searchTimer = c_searchDelay; @@ -1517,7 +1517,7 @@ bool TweakDBEditor::DrawFlatCName(RED4ext::TweakDBID aDBID, RED4ext::CStackType& flags |= ImGuiInputTextFlags_NoUndoRedo; auto* pStr = pCName->ToString(); - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); auto [strChanged, pModifiedStr] = ImGui::InputTextCStr("", pStr, strlen(pStr), flags); if (strChanged) { @@ -1536,7 +1536,7 @@ bool TweakDBEditor::DrawFlatCName(RED4ext::TweakDBID aDBID, RED4ext::CStackType& } uint64_t hash = pCName->hash; - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); bool rawChanged = ImGui::InputScalar("##raw", ImGuiDataType_U64, &hash, nullptr, nullptr, "%016llX", flags | ImGuiInputTextFlags_CharsHexadecimal); if (rawChanged) @@ -1590,7 +1590,7 @@ bool TweakDBEditor::DrawFlatString(RED4ext::TweakDBID aDBID, RED4ext::CStackType auto* pCString = reinterpret_cast(aStackType.value); int32_t flags = aReadOnly ? ImGuiInputTextFlags_ReadOnly : ImGuiInputTextFlags_EnterReturnsTrue; - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); auto [valueChanged, pModifiedStr] = ImGui::InputTextCStr("", pCString->c_str(), pCString->Length(), flags); if (ImGui::IsItemHovered() && strnicmp(pCString->c_str(), "LocKey#", 7) == 0) { @@ -1622,7 +1622,7 @@ bool TweakDBEditor::DrawFlatFloat(RED4ext::TweakDBID aDBID, RED4ext::CStackType& auto* pFloat = reinterpret_cast(aStackType.value); float val = *pFloat; - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); bool valueChanged = ImGui::InputFloat( "", &val, 0, 0, "%f", aReadOnly ? ImGuiInputTextFlags_ReadOnly : ImGuiInputTextFlags_EnterReturnsTrue); if (valueChanged) @@ -1647,7 +1647,7 @@ bool TweakDBEditor::DrawFlatInt32(RED4ext::TweakDBID aDBID, RED4ext::CStackType& auto* pInt = static_cast(aStackType.value); int32_t val = *pInt; - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); bool valueChanged = ImGui::InputInt( "", &val, 0, 0, aReadOnly ? ImGuiInputTextFlags_ReadOnly : ImGuiInputTextFlags_EnterReturnsTrue); if (valueChanged) @@ -1736,7 +1736,7 @@ void TweakDBEditor::DrawRecordsTab() flat.Update(); ImGui::PushID(flat.m_name.c_str()); - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); ImGui::PushStyleColor(ImGuiCol_FrameBg, IM_COL32_BLACK_TRANS); ImGui::InputText("", flat.m_name.data(), flat.m_name.size(), ImGuiInputTextFlags_ReadOnly); ImGui::PopStyleColor(); @@ -1853,7 +1853,7 @@ void TweakDBEditor::DrawFlatsTab() flat.Update(); ImGui::PushID(flat.m_name.c_str()); - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); ImGui::PushStyleColor(ImGuiCol_FrameBg, IM_COL32_BLACK_TRANS); ImGui::InputText("", flat.m_name.data(), flat.m_name.size(), ImGuiInputTextFlags_ReadOnly); ImGui::PopStyleColor(); @@ -1985,7 +1985,7 @@ void TweakDBEditor::DrawAdvancedTab() if (ImGui::BeginCombo("Record type to create", recordTypeName.ToString(), ImGuiComboFlags_HeightLargest)) { - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); ImGui::InputTextWithHint("##dropdownSearch", "Search", comboSearchBuffer, sizeof(comboSearchBuffer)); if (ImGui::BeginChild("##dropdownScroll", ImVec2(0, g_comboDropdownHeight))) { From 0d9bf50ac8de234c807ddfd72ae79c9d4396dd87 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Fri, 2 Apr 2021 18:58:41 +0200 Subject: [PATCH 30/35] Rework Bindings widgets --- src/overlay/widgets/Bindings.cpp | 144 +++++++++++++++++--------- src/overlay/widgets/Bindings.h | 5 + src/overlay/widgets/HelperWidgets.cpp | 2 - 3 files changed, 98 insertions(+), 53 deletions(-) diff --git a/src/overlay/widgets/Bindings.cpp b/src/overlay/widgets/Bindings.cpp index 9992ce37..208f326c 100644 --- a/src/overlay/widgets/Bindings.cpp +++ b/src/overlay/widgets/Bindings.cpp @@ -34,6 +34,12 @@ bool Bindings::OnDisable() m_vm.BlockDraw(m_madeChanges); m_enabled = m_madeChanges; } + if (!m_enabled) + { + // reset changes substates + m_hotkeysChanged = false; + m_inputsChanged = false; + } return !m_enabled; } @@ -49,63 +55,32 @@ void Bindings::Update() ResetChanges(); ImGui::Spacing(); + + if (!m_luaVMReady && m_vm.IsInitialized()) + Load(); - if (ImGui::BeginChild("##BINDINGS")) + if (ImGui::BeginTabBar("##BINDINGS", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton | ImGuiTabBarFlags_NoTooltip)) { - if (!m_luaVMReady && m_vm.IsInitialized()) - Load(); - - if (m_luaVMReady) + if (ImGui::BeginTabItem("Hotkeys")) { - // reset dirty state - m_madeChanges = false; - - std::string_view prevMod = ""; - for (auto& vkBindInfo : m_vkBindInfos) - { - std::string_view curMod = vkBindInfo.Bind.ID; - curMod = curMod.substr(0, curMod.find('.')); - if (prevMod != curMod) - { - // make it writable (also checks for "cet" modname) - std::string activeModName { (curMod == "cet") ? ("Cyber Engine Tweaks") : (curMod) }; + if (ImGui::BeginChild("##BINDINGS_HOTKEYS")) + m_hotkeysChanged = DrawBindings(true); + ImGui::EndChild(); + ImGui::EndTabItem(); + } - // transform to nicer format till modinfo is in - bool capitalize = true; - std::ranges::transform(std::as_const(activeModName), activeModName.begin(), - [&capitalize](char c) - { - if (!std::isalnum(c)) - { - capitalize = true; - return ' '; - } - if (capitalize) - { - capitalize = false; - return static_cast(std::toupper(static_cast(c))); - } - return c; - }); - - // add vertical spacing when this is not first iteration - if (!prevMod.empty()) - ImGui::Spacing(); - - ImGui::TextUnformatted(activeModName.c_str()); - ImGui::Spacing(); + if (ImGui::BeginTabItem("Inputs")) + { + if (ImGui::BeginChild("##BINDINGS_INPUTS")) + m_inputsChanged = DrawBindings(false); + ImGui::EndChild(); + ImGui::EndTabItem(); + } - prevMod = curMod; - } + m_madeChanges = m_hotkeysChanged || m_inputsChanged; - m_madeChanges |= HelperWidgets::BindWidget(vkBindInfo, (vkBindInfo.Bind.ID != m_overlayKeyID), 10.0f); - } - } - else - ImGui::TextUnformatted("LuaVM is not yet initialized!"); - } - ImGui::EndChild(); - + ImGui::EndTabBar(); + } } void Bindings::Load() @@ -150,3 +125,70 @@ void Bindings::ResetChanges() vkBindInfo.CodeBind = vkBindInfo.SavedCodeBind; } } + +bool Bindings::DrawBindings(bool aDrawHotkeys) +{ + bool madeChanges = false; + + if (m_luaVMReady) + { + const std::string_view emptyMessageArg1 { (aDrawHotkeys) ? ("hotkeys") : ("inputs") }; + const std::string_view emptyMessageArg2 { (aDrawHotkeys) ? ("inputs") : ("hotkeys") }; + + std::string_view prevMod{""}; + size_t modBindsForType { 0 }; + for (auto& vkBindInfo : m_vkBindInfos) + { + std::string_view curMod { vkBindInfo.Bind.ID }; + curMod = curMod.substr(0, curMod.find('.')); + if (prevMod != curMod) + { + // make it writable (also checks for "cet" modname) + std::string activeModName { (curMod == "cet") ? ("Cyber Engine Tweaks") : (curMod) }; + + // transform to nicer format till modinfo is in + bool capitalize = true; + std::ranges::transform(std::as_const(activeModName), activeModName.begin(), [&capitalize](char c) { + if (!std::isalnum(c)) + { + capitalize = true; + return ' '; + } + if (capitalize) + { + capitalize = false; + return static_cast(std::toupper(static_cast(c))); + } + return c; + }); + + // add vertical spacing when this is not first iteration and check if we drawn anything + if (!prevMod.empty()) + { + if (!modBindsForType) + { + // we did not draw anything, write appropriate message so it is not empty + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10.0f); + ImGui::Text("This mod has no %s, but it should have some %s in other tab...", emptyMessageArg1, emptyMessageArg2); + } + ImGui::Spacing(); + } + + ImGui::TextUnformatted(activeModName.c_str()); + ImGui::Spacing(); + + prevMod = curMod; + } + + if (aDrawHotkeys == vkBindInfo.Bind.IsHotkey()) + { + madeChanges |= HelperWidgets::BindWidget(vkBindInfo, (vkBindInfo.Bind.ID != m_overlayKeyID), 10.0f); + ++modBindsForType; + } + } + } + else + ImGui::TextUnformatted("LuaVM is not yet initialized!"); + + return madeChanges; +}; diff --git a/src/overlay/widgets/Bindings.h b/src/overlay/widgets/Bindings.h index 1fded2c0..a0bbc8ab 100644 --- a/src/overlay/widgets/Bindings.h +++ b/src/overlay/widgets/Bindings.h @@ -20,6 +20,8 @@ struct Bindings : Widget void ResetChanges(); private: + bool DrawBindings(bool aDrawHotkeys); + std::vector m_vkBindInfos{ }; VKBindings& m_bindings; Overlay& m_overlay; @@ -34,4 +36,7 @@ struct Bindings : Widget bool m_enabled{ false }; bool m_madeChanges{ false }; bool m_openChangesModal{ true }; + + bool m_hotkeysChanged{ false }; + bool m_inputsChanged{ false }; }; diff --git a/src/overlay/widgets/HelperWidgets.cpp b/src/overlay/widgets/HelperWidgets.cpp index cd9321c4..44db4bdd 100644 --- a/src/overlay/widgets/HelperWidgets.cpp +++ b/src/overlay/widgets/HelperWidgets.cpp @@ -44,8 +44,6 @@ namespace HelperWidgets curTextColor = ImVec4(1.0f, 1.0f, 0.0f, 1.0f); std::string label { aVKBindInfo.Bind.Description + ':' }; - if (aVKBindInfo.Bind.IsHotkey()) - label.insert(0, "[HK] "); // insert [HK] prefix for hotkeys so user knows this input can be assigned up to 4-key combo ImGui::AlignTextToFramePadding(); From 404504f62d32f29537fec12fb8fd496e89bae426 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Fri, 2 Apr 2021 19:03:37 +0200 Subject: [PATCH 31/35] Code style --- src/VKBindings.cpp | 24 ++++++++++++------------ src/VKBindings.h | 6 +++--- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/VKBindings.cpp b/src/VKBindings.cpp index 5bbb5f63..43debfc0 100644 --- a/src/VKBindings.cpp +++ b/src/VKBindings.cpp @@ -18,9 +18,9 @@ uint64_t VKBindInfo::Apply() return CodeBind; } -VKBindings::VKBindings(Paths& aPaths, const Options& aOptions) +VKBindings::VKBindings(Paths& aPaths, const Options& acOptions) : m_paths(aPaths) - , m_options(aOptions) + , m_cOptions(acOptions) { } @@ -60,7 +60,7 @@ std::vector VKBindings::InitializeMods(std::vector aVKBi } // filter dead bindings if option is enabled (default) - if (m_options.RemoveDeadBindings) + if (m_cOptions.RemoveDeadBindings) { // now, find all dead bindings std::vector> deadIDToBinds; @@ -100,7 +100,7 @@ std::vector VKBindings::InitializeMods(std::vector aVKBi // insert CET overlay bind info assert(m_pOverlay); // overlay must be set before first use! - const auto overlayKeyBind { m_pOverlay->GetBind() }; + const auto overlayKeyBind { m_cpOverlay->GetBind() }; const auto overlayKeyCodeIt { m_idToBind.find(overlayKeyBind.ID) }; const auto overlayKeyCode { (overlayKeyCodeIt == m_idToBind.cend()) ? (0) : (overlayKeyCodeIt->second) }; aVKBindInfos.insert(aVKBindInfos.cbegin(), VKBindInfo{overlayKeyBind, overlayKeyCode, overlayKeyCode, false}); @@ -109,14 +109,14 @@ std::vector VKBindings::InitializeMods(std::vector aVKBi return aVKBindInfos; } -bool VKBindings::Load(const Overlay& aOverlay) +bool VKBindings::Load(const Overlay& acOverlay) { - auto parseConfig {[this, &aOverlay](const std::filesystem::path& path, bool old = false) -> std::pair { + auto parseConfig {[this, &acOverlay](const std::filesystem::path& path, bool old = false) -> std::pair { std::ifstream ifs { path }; if (ifs) { auto config { nlohmann::json::parse(ifs) }; - VKBind overlayBind { aOverlay.GetBind() }; + VKBind overlayBind { acOverlay.GetBind() }; uint64_t overlayBindCode { 0 }; for (auto& it : config.items()) { @@ -169,7 +169,7 @@ bool VKBindings::Load(const Overlay& aOverlay) } } - m_pOverlay = &aOverlay; + m_cpOverlay = &acOverlay; m_initialized = true; return res && key; @@ -584,7 +584,7 @@ LRESULT VKBindings::RecordKeyDown(USHORT aVKCode) if (bind && (bind != VKBRecord_OK)) { - if (m_pOverlay && m_pOverlay->IsEnabled()) + if (m_cpOverlay && m_cpOverlay->IsEnabled()) return 0; // we dont want to handle bindings if overlay is open and we are not in binding state! if (bind->IsValid()) // prevention for freshly loaded bind from file without rebinding @@ -628,7 +628,7 @@ LRESULT VKBindings::RecordKeyUp(USHORT aVKCode) { if (cpBind->IsInput()) { - if (m_pOverlay && !m_pOverlay->IsEnabled()) // we dont want to handle bindings if overlay is open + if (m_cpOverlay && !m_cpOverlay->IsEnabled()) // we dont want to handle bindings if overlay is open { if (cpBind->IsValid()) // prevention for freshly loaded bind from file without rebinding m_queuedCallbacks.Add(cpBind->DelayedCall(false)); @@ -672,7 +672,7 @@ LRESULT VKBindings::RecordKeyUp(USHORT aVKCode) const auto bind = m_binds.find(m_recordingResult); if (bind != m_binds.end()) { - if (m_pOverlay && m_pOverlay->IsEnabled() && (bind->second.ID != m_pOverlay->GetBind().ID)) + if (m_cpOverlay && m_cpOverlay->IsEnabled() && (bind->second.ID != m_cpOverlay->GetBind().ID)) return 0; // we dont want to handle bindings if toolbar is open and we are not in binding state! if (bind->second.IsValid()) // prevention for freshly loaded bind from file without rebinding @@ -740,7 +740,7 @@ LRESULT VKBindings::HandleRAWInput(HRAWINPUT ahRAWInput) } else if (raw->header.dwType == RIM_TYPEMOUSE) { - if (m_pOverlay && m_isBindRecording && (m_recordingBind.ID == m_pOverlay->GetBind().ID)) + if (m_cpOverlay && m_isBindRecording && (m_recordingBind.ID == m_cpOverlay->GetBind().ID)) return 0; // ignore mouse keys for toolbar key binding! const auto& m = raw->data.mouse; diff --git a/src/VKBindings.h b/src/VKBindings.h index 82dd6616..3d0822cd 100644 --- a/src/VKBindings.h +++ b/src/VKBindings.h @@ -77,7 +77,7 @@ struct Overlay; struct D3D12; struct VKBindings { - VKBindings(Paths& aPaths, const Options& aOptions); + VKBindings(Paths& aPaths, const Options& acOptions); ~VKBindings() = default; [[nodiscard]] bool IsInitialized() const noexcept; @@ -142,8 +142,8 @@ struct VKBindings bool m_initialized{ false }; Paths& m_paths; - const Options& m_options; - const Overlay* m_pOverlay{ nullptr }; + const Options& m_cOptions; + const Overlay* m_cpOverlay{ nullptr }; size_t m_connectUpdate{ static_cast(-1) }; }; From 4aa64b7833ec4df42e1605e42585d7c22c2be848 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Fri, 2 Apr 2021 19:21:02 +0200 Subject: [PATCH 32/35] Disable ImGui assertions by default --- src/Options.cpp | 2 +- src/Options.h | 2 +- src/imgui_impl/imgui_user_config.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Options.cpp b/src/Options.cpp index 77c67ee7..de0d3f15 100644 --- a/src/Options.cpp +++ b/src/Options.cpp @@ -85,7 +85,7 @@ void Options::ResetToDefaults() PatchDisableWin7Vsync = false; RemoveDeadBindings = true; - EnableImGuiAssertions = true; + EnableImGuiAssertions = false; PatchEnableDebug = false; DumpGameOptions = false; diff --git a/src/Options.h b/src/Options.h index 5abe43bc..7bc84ff4 100644 --- a/src/Options.h +++ b/src/Options.h @@ -32,7 +32,7 @@ struct Options bool IsFirstLaunch { true }; bool RemoveDeadBindings { true }; bool DrawImGuiDiagnosticWindow { false }; - bool EnableImGuiAssertions { true }; + bool EnableImGuiAssertions { false }; private: diff --git a/src/imgui_impl/imgui_user_config.cpp b/src/imgui_impl/imgui_user_config.cpp index 48e59db9..3bb621d7 100644 --- a/src/imgui_impl/imgui_user_config.cpp +++ b/src/imgui_impl/imgui_user_config.cpp @@ -3,7 +3,7 @@ // NOTE: imgui_user_config.h is included by imgui.h which is included with precompiled header, so no need to include it here once more // global definition "Enable ImGui Assertions" -bool g_ImGuiAssertionsEnabled{ true }; +bool g_ImGuiAssertionsEnabled{ false }; #ifdef NDEBUG // inline _wassert decl for NDEBUG as it is not emitted inside assert.h header in this case From f3fb4f49051759288132c4c2028c49ed04804d8a Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Fri, 2 Apr 2021 19:22:26 +0200 Subject: [PATCH 33/35] Code style --- src/VKBindings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/VKBindings.h b/src/VKBindings.h index 3d0822cd..00499f1b 100644 --- a/src/VKBindings.h +++ b/src/VKBindings.h @@ -88,7 +88,7 @@ struct VKBindings static uint64_t EncodeVKCodeBind(VKCodeBindDecoded aVKCodeBindDecoded); static const char* GetSpecialKeyName(USHORT aVKCode); - bool Load(const Overlay& aOverlay); + bool Load(const Overlay& acOverlay); void Save(); void Update(); From 98a569f434d258bcfeb0e8fbca13bd859df05474 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Fri, 2 Apr 2021 19:28:01 +0200 Subject: [PATCH 34/35] Fix reworked Bindings widget --- src/overlay/widgets/Bindings.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/overlay/widgets/Bindings.cpp b/src/overlay/widgets/Bindings.cpp index 208f326c..f57815ef 100644 --- a/src/overlay/widgets/Bindings.cpp +++ b/src/overlay/widgets/Bindings.cpp @@ -132,8 +132,8 @@ bool Bindings::DrawBindings(bool aDrawHotkeys) if (m_luaVMReady) { - const std::string_view emptyMessageArg1 { (aDrawHotkeys) ? ("hotkeys") : ("inputs") }; - const std::string_view emptyMessageArg2 { (aDrawHotkeys) ? ("inputs") : ("hotkeys") }; + const auto emptyMessageArg1 { (aDrawHotkeys) ? ("hotkeys") : ("inputs") }; + const auto emptyMessageArg2 { (aDrawHotkeys) ? ("inputs") : ("hotkeys") }; std::string_view prevMod{""}; size_t modBindsForType { 0 }; @@ -165,7 +165,7 @@ bool Bindings::DrawBindings(bool aDrawHotkeys) // add vertical spacing when this is not first iteration and check if we drawn anything if (!prevMod.empty()) { - if (!modBindsForType) + if (!modBindsForType && (prevMod != "cet")) { // we did not draw anything, write appropriate message so it is not empty ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10.0f); From 84e893b348bfa11104b94ecdfaa3c243ed3c4818 Mon Sep 17 00:00:00 2001 From: Andrej Redeky Date: Fri, 2 Apr 2021 19:34:21 +0200 Subject: [PATCH 35/35] Get rid of unnecessary ImGui::Text in reworked Bindings widget --- src/overlay/widgets/Bindings.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/overlay/widgets/Bindings.cpp b/src/overlay/widgets/Bindings.cpp index f57815ef..89e4b13e 100644 --- a/src/overlay/widgets/Bindings.cpp +++ b/src/overlay/widgets/Bindings.cpp @@ -132,8 +132,12 @@ bool Bindings::DrawBindings(bool aDrawHotkeys) if (m_luaVMReady) { - const auto emptyMessageArg1 { (aDrawHotkeys) ? ("hotkeys") : ("inputs") }; - const auto emptyMessageArg2 { (aDrawHotkeys) ? ("inputs") : ("hotkeys") }; + const char* cpEmptyMessage + { + (aDrawHotkeys) + ? ("This mod has no hotkeys, but it should have some inputs in other tab...") + : ("This mod has no inputs, but it should have some hotkeys in other tab...") + }; std::string_view prevMod{""}; size_t modBindsForType { 0 }; @@ -169,7 +173,7 @@ bool Bindings::DrawBindings(bool aDrawHotkeys) { // we did not draw anything, write appropriate message so it is not empty ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10.0f); - ImGui::Text("This mod has no %s, but it should have some %s in other tab...", emptyMessageArg1, emptyMessageArg2); + ImGui::TextUnformatted(cpEmptyMessage); } ImGui::Spacing(); }