From 810c51ac139cd3139389a5d59ad122f4ec1e0551 Mon Sep 17 00:00:00 2001 From: Arnaud Jamin Date: Wed, 19 Mar 2025 12:59:37 -0400 Subject: [PATCH] Rework how replicators are spawned to simplify Cog integration - Replicators are now automatically spawned - Rework input management. - Add input shortcuts in the TimeScale window to change the time scale. --- .../Debug/Cheats/GE_Cheat_Invisible.uasset | Bin 24291 -> 8330 bytes .../A/8F/FGVI5ODN3IRJPMIZNYLQLC.uasset | Bin 0 -> 5110 bytes .../Cog/Source/Cog/Private/CogSubsystem.cpp | 218 ++++++++++++++---- Plugins/Cog/Source/Cog/Private/CogWidgets.cpp | 175 +++++++++++--- Plugins/Cog/Source/Cog/Private/CogWindow.cpp | 1 - .../Source/Cog/Private/CogWindow_Layouts.cpp | 45 ++-- .../Source/Cog/Private/CogWindow_Settings.cpp | 54 ++--- Plugins/Cog/Source/Cog/Public/CogHelper.h | 24 ++ .../Source/Cog/Public/CogPluginSubsystem.h | 15 ++ Plugins/Cog/Source/Cog/Public/CogSubsystem.h | 67 +++++- Plugins/Cog/Source/Cog/Public/CogWidgets.h | 58 ++++- Plugins/Cog/Source/Cog/Public/CogWindow.h | 3 + .../Cog/Source/Cog/Public/CogWindow_Layouts.h | 4 +- .../Source/Cog/Public/CogWindow_Settings.h | 67 ++++-- .../CogDebug/Public/CogDebugPluginSubsystem.h | 15 ++ .../CogDebug/Public/CogDebugSubsystem.h | 22 ++ .../Source/CogDebug/Public/CogDebugTrack.h | 4 +- .../CogEngine/Private/CogEngineReplicator.cpp | 1 + .../CogEngineWindow_CommandBindings.cpp | 2 +- .../Private/CogEngineWindow_Selection.cpp | 2 +- .../Private/CogEngineWindow_TimeScale.cpp | 162 +++++++++++-- .../CogEngine/Public/CogEngineSubsystem.h | 22 ++ .../Public/CogEngineWindow_Console.h | 2 +- .../Public/CogEngineWindow_TimeScale.h | 40 +++- .../CogImgui/Private/CogImguiContext.cpp | 2 +- .../CogImgui/Private/CogImguiInputHelper.cpp | 180 +++------------ .../CogImgui/Public/CogImguiInputHelper.h | 46 ++-- .../Source/CogImgui/Public/CogImguiKeyInfo.h | 59 ----- .../Source/CogImgui/Public/CogImguiWidget.h | 2 +- .../CogAbility/Public/CogAbilitySubsystem.h | 22 ++ .../Private/CogInputWindow_Gamepad.cpp | 2 +- 31 files changed, 880 insertions(+), 436 deletions(-) create mode 100644 Content/__ExternalActors__/Maps/L_Level2/A/8F/FGVI5ODN3IRJPMIZNYLQLC.uasset create mode 100644 Plugins/Cog/Source/Cog/Public/CogPluginSubsystem.h create mode 100644 Plugins/Cog/Source/CogDebug/Public/CogDebugPluginSubsystem.h create mode 100644 Plugins/Cog/Source/CogDebug/Public/CogDebugSubsystem.h create mode 100644 Plugins/Cog/Source/CogEngine/Public/CogEngineSubsystem.h delete mode 100644 Plugins/Cog/Source/CogImgui/Public/CogImguiKeyInfo.h create mode 100644 Plugins/CogAbility/Source/CogAbility/Public/CogAbilitySubsystem.h diff --git a/Content/Core/Debug/Cheats/GE_Cheat_Invisible.uasset b/Content/Core/Debug/Cheats/GE_Cheat_Invisible.uasset index 5cda6f31fac3cf1634726879d7a9d51f4842f9a5..ea3eb6809b48e927ab242f550b2236b7623262be 100644 GIT binary patch delta 2665 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 UBQJGFCd_KH|98VvMH~444|6NPn*aa+ diff --git a/Content/__ExternalActors__/Maps/L_Level2/A/8F/FGVI5ODN3IRJPMIZNYLQLC.uasset b/Content/__ExternalActors__/Maps/L_Level2/A/8F/FGVI5ODN3IRJPMIZNYLQLC.uasset new file mode 100644 index 0000000000000000000000000000000000000000..982b7050e0913cf6c19c10a748926f1ec936f3a7 GIT binary patch literal 5110 zcmb_gdvFuS8DGE<=Rrzc9%%!`fJ*>_bviw))$rk}XTNbh0fs zOdLuX8k%7!l(b2cHXTAz0v+09AekiP(Keld^pW8a0+TQ;3~kadLwO`Lp>e-&?^c!+ z^Y|m5=I-15eUIJ!cK6#o9s1t9XRi+p4XqwS$UUP8xdt5RZg_sa>3YeHn)Jr|-g{){ z+&33m^nlf`I^A6D;!FCQ`(NGk;j7)nfbAdWUU|Kyt*raN%E9;lcJ0sO0o(AvwAJft z!@EB?HhI^{KYcWQ7hsQ_SQ~vwtiABDuV&Yrefxjc2iP*@#$N|*d!@4zw`@(7PMh)_ zz^o5Heahi^v+Tv)CF?U&!eyB`$R zZ+Uq3`vX~{4=&eM*WuNdE{mJDA5Bl+{@Bzjb1Qay ze&z|+({;~;4=+369|bz-2Rkwrexu06=W0fmK&`yI!EP$Amt%4$B`+{ln5dkP3x8R9 z6FC@Bdi&(NNi38=9}a&*#n>B`!Vt!ACID~c$R^D{IuD04n27j5cjKN{x}||L!F(hop|Quk8lLFy>c=c4a=So z?22e8mLh-OcjougKvEZK>kPHa?nGNC799vF5JGG@)g6N9mnfNy7&cgJAnB!As6jT? zO`4x8s81-=l)V1N`*SDcSop!MY_O5H?55o~<@JdK%vD!6^f|7OiTguOVIraCi6nVE z`r0Xsmmj^gdE``tlr&cba19Pa!{+h-*k^t-PiBMB^~zyeNC_>MGekb#dGLWe1s61( zR2tgj!DN{GOncZk5T2o?`1bFp*-RREj8l{aY~1+Exn&hv$NBYVv5+^bR~XSau~F z*64fCo+ew;F@MW8v}YYZmmcJ$1*(VmTV`_-~nP_J-UkBnJ$1dp2nJlG(* zY(dUqbyzK&!B}Y#;RLX9Jo)uMjvvKbGOV9nsvNoTtEQJRBu$BAEKFvsT8ZPMG+X1J zLI%cpLc%>;NKEe&(8CiM>2`WkRkb`lJXw(Ds*GF)e>$z4>yPQp(`5ezz4;^PX%Jb! z3czRGpf!AGDYt(rLh{;W*zNS#*mCt4_MqkjZ%3R~9!ZbQ0nW!mx6osAa253M zMuRkxKcgxlpMf4OJEUAafQM96eOG7|yro#RGM?a!a6D{G3}d{|7sHX`PDJ`5r@b3c z<^el3^iCsgohzsSv?HfI6&Zf#wtuVk{;iq(FQ+{m6N^-3ez$OI(%of=OlBoVNrbXBB~5)s1VKx{|&IU00>UvAic5<&{d40Yyq* zi>FB!S>Bwf@9Wj4MMK!8AMkM?k(^GezCB_WI+NbYfTJhb)L)+P_Oye@UL$u25oe&4 z>+D(H=Z{o(u4wUE2GE~M4Zy6mt-L8Fin(PAihCP)ZziwV;iS4NZQ>;qeS=W;WJVeYb4_NieIjjqNlE;ndyvxrvkbwa@!2s8?|a8pgp+Xs3y ziXwI1;OvjcP2o(d0b*QetJS+Y1_B+9E+yPxPDNsVlfK*I4Cm+)y!z)YDfJF;2a6TA z&lgMK#V9viU3%O5+HPa%VwTheC&tKd(z(B z8v?JL+&WGvj1gg{&zDAZ4RYGIX(NQ>WUgm;Efz#^^lB0|dTda}<%xJX;z(ig|5WcH< z$sy`F$!ZBowO)UqUUYfwwxGL73JP2vS@LRFk)X>qzS1rU2Ae^!=tYCWF2E>E=1Rd{ zY0+m5Sc!2aV0FeB&N#z0Ze%#)Ob&I3p9A5WacW|sZ_a2pJIr=7)+7}%sO(GD8Vt;s z(-y~xoRNp~1b+n-bo)7v*FT^U7xXu|TL^w>AhAOb*Fo-D!_%EEZpJR7*e4D)xobXB>c|+3HKr+s(@daNNl69YjY_@Rj)I0%36^! z{Pa_MGWgwt6gjv~GetWorldContextFromWorld(World); + FWorldContext* WorldContext = GEngine->GetWorldContextFromWorld(&World); if (WorldContext == nullptr) { return; } @@ -77,7 +78,19 @@ void UCogSubsystem::TryInitialize(UWorld* World) SpaceWindows.Add(AddWindow("Spacing 4")); Settings = GetConfig(); - OnShortcutsDefined(); + + UCogWindowConfig_Settings* SettingsPtr = Settings.Get(); + AddShortcut(SettingsPtr, &UCogWindowConfig_Settings::Shortcut_ToggleImguiInput).BindLambda([this] () { ToggleInputMode(); }); + AddShortcut(SettingsPtr, &UCogWindowConfig_Settings::Shortcut_ToggleSelection).BindLambda([this] (){ SetActivateSelectionMode(!GetActivateSelectionMode()); }); + AddShortcut(SettingsPtr, &UCogWindowConfig_Settings::Shortcut_LoadLayout1).BindLambda([this] (){ LoadLayout(1); }); + AddShortcut(SettingsPtr, &UCogWindowConfig_Settings::Shortcut_LoadLayout2).BindLambda([this] (){ LoadLayout(2); }); + AddShortcut(SettingsPtr, &UCogWindowConfig_Settings::Shortcut_LoadLayout3).BindLambda([this] (){ LoadLayout(3); }); + AddShortcut(SettingsPtr, &UCogWindowConfig_Settings::Shortcut_LoadLayout4).BindLambda([this] (){ LoadLayout(4); }); + AddShortcut(SettingsPtr, &UCogWindowConfig_Settings::Shortcut_SaveLayout1).BindLambda([this] (){ SaveLayout(1); }); + AddShortcut(SettingsPtr, &UCogWindowConfig_Settings::Shortcut_SaveLayout2).BindLambda([this] (){ SaveLayout(2); }); + AddShortcut(SettingsPtr, &UCogWindowConfig_Settings::Shortcut_SaveLayout3).BindLambda([this] (){ SaveLayout(3); }); + AddShortcut(SettingsPtr, &UCogWindowConfig_Settings::Shortcut_SaveLayout4).BindLambda([this] (){ SaveLayout(4); }); + AddShortcut(SettingsPtr, &UCogWindowConfig_Settings::Shortcut_ResetLayout).BindLambda([this] (){ ResetLayout(); }); LayoutsWindow = AddWindow("Window.Layouts"); SettingsWindow = AddWindow("Window.Settings"); @@ -86,7 +99,7 @@ void UCogSubsystem::TryInitialize(UWorld* World) { InitializeWindow(Window); } - + FCogConsoleCommandManager::RegisterWorldConsoleCommand( *ToggleInputCommand, TEXT("Toggle the input focus between the Game and ImGui"), @@ -217,7 +230,7 @@ void UCogSubsystem::Tick(UWorld* InTickedWorld, ELevelTick InTickType, float InD //---------------------------------------------------------------------------------------------- if (World != CurrentWorld.Get()) { - NumExecBindingsChecked = INDEX_NONE; + RequestDisableCommandsConflictingWithShortcuts(); } CurrentWorld = World; @@ -226,30 +239,21 @@ void UCogSubsystem::Tick(UWorld* InTickedWorld, ELevelTick InTickType, float InD if (IsInitialized == false) { - TryInitialize(World); + TryInitialize(*World); return; } FCogImGuiContextScope ImGuiContextScope(Context); - UPlayerInput* PlayerInput = FCogImguiInputHelper::GetPlayerInput(*World); - if (PlayerInput != nullptr) + UpdateServerPlayerControllers(*World); + + if (UPlayerInput* PlayerInput = (LocalPlayerController != nullptr) ? LocalPlayerController->PlayerInput : nullptr) { - HandleInputs(*PlayerInput); - //------------------------------------------------------------------ // We must wait for the player input to be valid to disable // DebugExecBindings conflicting with our shortcuts. //------------------------------------------------------------------ - const int32 NewNumExecBindings = PlayerInput->DebugExecBindings.Num(); - if (NumExecBindingsChecked != NewNumExecBindings) - { - if (Settings->bDisableConflictingCommands) - { - FCogImguiInputHelper::DisableCommandsConflictingWithShortcuts(*PlayerInput); - } - NumExecBindingsChecked = NewNumExecBindings;; - } + TryDisableCommandsConflictingWithShortcuts(PlayerInput); } if (LayoutToLoad != -1) @@ -274,6 +278,77 @@ void UCogSubsystem::Tick(UWorld* InTickedWorld, ELevelTick InTickType, float InD } } +//-------------------------------------------------------------------------------------------------------------------------- +void UCogSubsystem::RequestDisableCommandsConflictingWithShortcuts() +{ + NumExecBindingsChecked = INDEX_NONE; +} + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogSubsystem::SetLocalPlayerController(APlayerController* PlayerController) +{ + if (LocalPlayerController == PlayerController) + { return; } + + LocalPlayerController = PlayerController; + + if (LocalPlayerController == nullptr) + { return; } + + UInputComponent* InputComponentPtr = NewObject(PlayerController, TEXT("Cog_Input")); + InputComponent = InputComponentPtr; + if (InputComponentPtr) + { + PlayerController->PushInputComponent(InputComponentPtr); + } + + for (FCogShortcut& Shortcut : Shortcuts) + { + BindShortcut(Shortcut); + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogSubsystem::UpdateServerPlayerControllers(UWorld& World) +{ + TArray PluginSubsystems; + + ServerPlayerControllers.RemoveAll([] (TWeakObjectPtr PlayerController) + { + return PlayerController.IsValid() == false; + }); + + for (FConstPlayerControllerIterator It = World.GetPlayerControllerIterator(); It; ++It) + { + APlayerController* PlayerController = It->Get(); + if (PlayerController == nullptr) + { continue; } + + if (PlayerController->IsLocalController()) + { + SetLocalPlayerController(PlayerController); + } + + if (World.GetNetMode() != NM_Client) + { + if (ServerPlayerControllers.Contains(PlayerController)) + { continue; } + + ServerPlayerControllers.Add(PlayerController); + + if (PluginSubsystems.IsEmpty()) + { + PluginSubsystems = GetOuterUGameInstance()->GetSubsystemArrayCopy(); + } + + for (UCogDebugPluginSubsystem* PluginSubsystem : PluginSubsystems) + { + PluginSubsystem->OnPlayerControllerReady(PlayerController); + } + } + } +} + //-------------------------------------------------------------------------------------------------------------------------- void UCogSubsystem::Render(float DeltaTime) { @@ -938,30 +1013,6 @@ void UCogSubsystem::DisableInputMode() Context.SetEnableInput(false); } -//-------------------------------------------------------------------------------------------------------------------------- -void UCogSubsystem::HandleInputs(const UPlayerInput& PlayerInput) -{ - if (Settings->bDisableShortcutsWhenImGuiWantTextInput && ImGui::GetIO().WantTextInput) - { return; } - - if (FCogImguiInputHelper::IsKeyInfoPressed(PlayerInput, Settings->ToggleImGuiInputShortcut)) - { - ToggleInputMode(); - } - else if (FCogImguiInputHelper::IsKeyInfoPressed(PlayerInput, Settings->ToggleSelectionShortcut)) - { - SetActivateSelectionMode(!GetActivateSelectionMode()); - } - - for (int i = 0; i < Settings->LoadLayoutShortcuts.Num(); ++i) - { - if (FCogImguiInputHelper::IsKeyInfoPressed(PlayerInput, Settings->LoadLayoutShortcuts[i])) - { - LoadLayout(i + 1); - } - } -} - //-------------------------------------------------------------------------------------------------------------------------- void UCogSubsystem::SetActivateSelectionMode(const bool Value) { @@ -987,14 +1038,79 @@ bool UCogSubsystem::GetActivateSelectionMode() const } //-------------------------------------------------------------------------------------------------------------------------- -void UCogSubsystem::OnShortcutsDefined() +FInputActionHandlerSignature& UCogSubsystem::AddShortcut(const UObject& InInstance, const FProperty& InProperty) { - TArray Shortcuts = { Settings->ToggleImGuiInputShortcut, Settings->ToggleSelectionShortcut }; - Shortcuts.Append(Settings->LoadLayoutShortcuts); - Shortcuts.Append(Settings->SaveLayoutShortcuts); - - FCogImguiInputHelper::SetShortcuts(Shortcuts); - - NumExecBindingsChecked = INDEX_NONE; + FCogShortcut& Shortcut = Shortcuts.AddDefaulted_GetRef(); + Shortcut.PropertyName = InProperty.GetFName(); + Shortcut.Config = &InInstance; + return Shortcut.Delegate; } +//-------------------------------------------------------------------------------------------------------------------------- +bool UCogSubsystem::BindShortcut(FCogShortcut& InShortcut) const +{ + UObject* Config = const_cast(InShortcut.Config.Get()); + if (Config == nullptr) + { return false; } + + const FStructProperty* StructProperty = CastField(Config->GetClass()->FindPropertyByName(InShortcut.PropertyName)); + if (StructProperty == nullptr) + { return false; } + + const FInputChord* InputChord = static_cast(StructProperty->ContainerPtrToValuePtr(Config)); + if (InputChord == nullptr) + { return false; } + + FInputKeyBinding InputBinding(*InputChord, IE_Pressed); + InputBinding.KeyDelegate.GetDelegateForManualSet() = InShortcut.Delegate; + InputComponent.Get()->KeyBindings.Add(InputBinding); + + InShortcut.InputChord = *InputChord; + + FCogImguiInputHelper::GetPrioritizedShortcuts().Add(*InputChord); + return true; +} + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogSubsystem::RebindShortcut(const UCogCommonConfig& InConfig, const FProperty& InProperty) +{ + // Ideally would unbind and rebind only the provided shortcut, but we currently rebind all shortcuts. + + UInputComponent* InputComponentPtr = InputComponent.Get(); + if (InputComponentPtr == nullptr) + { return; } + + for (auto& KeyBinding : InputComponentPtr->KeyBindings) + { + KeyBinding.KeyDelegate.Unbind(); + } + InputComponent.Get()->KeyBindings.Empty(); + + for (FCogShortcut& Shortcut : Shortcuts) + { + BindShortcut(Shortcut); + } + + RequestDisableCommandsConflictingWithShortcuts(); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void UCogSubsystem::TryDisableCommandsConflictingWithShortcuts(UPlayerInput* PlayerInput) +{ + const int32 NewNumExecBindings = PlayerInput->DebugExecBindings.Num(); + if (NumExecBindingsChecked == NewNumExecBindings) + { return; } + + NumExecBindingsChecked = NewNumExecBindings;; + + if (Settings->bDisableConflictingCommands == false) + { return; } + + TArray& PrioritizedShortcuts = FCogImguiInputHelper::GetPrioritizedShortcuts(); + for (const FCogShortcut& Shortcut : Shortcuts) + { + PrioritizedShortcuts.Add(Shortcut.InputChord); + } + + FCogImguiInputHelper::DisableCommandsConflictingWithShortcuts(*PlayerInput); +} \ No newline at end of file diff --git a/Plugins/Cog/Source/Cog/Private/CogWidgets.cpp b/Plugins/Cog/Source/Cog/Private/CogWidgets.cpp index 2058838..f2f41bd 100644 --- a/Plugins/Cog/Source/Cog/Private/CogWidgets.cpp +++ b/Plugins/Cog/Source/Cog/Private/CogWidgets.cpp @@ -515,18 +515,18 @@ bool FCogWidgets::CheckBoxState(const char* Label, ECheckBoxState& State, bool S } //-------------------------------------------------------------------------------------------------------------------------- -bool FCogWidgets::InputKey(const char* Label, FCogImGuiKeyInfo& KeyInfo) +bool FCogWidgets::InputChord(const char* Label, FInputChord& InInputChord) { ImGui::PushID(Label); ImGui::AlignTextToFramePadding(); ImGui::BeginDisabled(); - ImGui::SetNextItemWidth(ImGui::GetFontSize() * 10); + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15); ImGui::InputText("##Shortcut", const_cast(Label), IM_ARRAYSIZE(Label)); ImGui::EndDisabled(); ImGui::SameLine(); - const bool HasChanged = InputKey(KeyInfo); + const bool HasChanged = InputChord(InInputChord); ImGui::PopID(); @@ -534,18 +534,50 @@ bool FCogWidgets::InputKey(const char* Label, FCogImGuiKeyInfo& KeyInfo) } //-------------------------------------------------------------------------------------------------------------------------- -bool FCogWidgets::InputKey(FCogImGuiKeyInfo& KeyInfo) +bool FCogWidgets::InputChord(FInputChord& InInputChord) { bool HasKeyChanged = false; - ImGui::SetNextItemWidth(ImGui::GetFontSize() * 6); - if (ImGui::BeginCombo("##Key", TCHAR_TO_ANSI(*KeyInfo.Key.ToString()), ImGuiComboFlags_HeightLarge)) + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8); + HasKeyChanged |= Key(InInputChord.Key); + + bool Value = false; + + ImGui::SameLine(); + Value = static_cast(InInputChord.bCtrl); + HasKeyChanged |= ImGui::Selectable("Ctrl", &Value, ImGuiSelectableFlags_None, ImVec2(ImGui::GetFontSize() * 2, 0)); + InInputChord.bCtrl = Value; + + ImGui::SameLine(); + Value = static_cast(InInputChord.bShift); + HasKeyChanged |= ImGui::Selectable("Shift", &Value, ImGuiSelectableFlags_None, ImVec2(ImGui::GetFontSize() * 3, 0)); + InInputChord.bShift = Value; + + ImGui::SameLine(); + Value = static_cast(InInputChord.bAlt); + HasKeyChanged |= ImGui::Selectable("Alt", &Value, ImGuiSelectableFlags_None, ImVec2(ImGui::GetFontSize() * 2, 0)); + InInputChord.bAlt = Value; + + ImGui::SameLine(); + Value = static_cast(InInputChord.bCmd); + HasKeyChanged |= ImGui::Selectable("Cmd", &Value, ImGuiSelectableFlags_None, ImVec2(ImGui::GetFontSize() * 2, 0)); + InInputChord.bCmd = Value; + + return HasKeyChanged; +} + + +//-------------------------------------------------------------------------------------------------------------------------- +bool FCogWidgets::Key(FKey& InKey) +{ + bool HasKeyChanged = false; + if (ImGui::BeginCombo("##Key", TCHAR_TO_ANSI(*InKey.ToString()), ImGuiComboFlags_HeightLarge)) { { - bool IsSelected = KeyInfo.Key == FKey(); + bool IsSelected = InKey == FKey(); if (ImGui::Selectable("None", IsSelected)) { - KeyInfo.Key = FKey(); + InKey = FKey(); HasKeyChanged = true; } } @@ -566,45 +598,33 @@ bool FCogWidgets::InputKey(FCogImGuiKeyInfo& KeyInfo) continue; } - bool IsSelected = KeyInfo.Key == Key; + bool IsSelected = InKey == Key; if (ImGui::Selectable(TCHAR_TO_ANSI(*Key.ToString()), IsSelected)) { - KeyInfo.Key = Key; + InKey = Key; HasKeyChanged = true; } } ImGui::EndCombo(); } - ImGui::SameLine(); - HasKeyChanged |= CheckBoxState("Ctrl", KeyInfo.Ctrl); - - ImGui::SameLine(); - HasKeyChanged |= CheckBoxState("Shift", KeyInfo.Shift); - - ImGui::SameLine(); - HasKeyChanged |= CheckBoxState("Alt", KeyInfo.Alt); - - ImGui::SameLine(); - HasKeyChanged |= CheckBoxState("Cmd", KeyInfo.Cmd); - return HasKeyChanged; } //-------------------------------------------------------------------------------------------------------------------------- -bool FCogWidgets::KeyBind(FKeyBind& KeyBind) +bool FCogWidgets::KeyBind(FKeyBind& InKeyBind) { static char Buffer[256] = ""; - const auto Str = StringCast(*KeyBind.Command); + const auto Str = StringCast(*InKeyBind.Command); ImStrncpy(Buffer, Str.Get(), IM_ARRAYSIZE(Buffer)); - bool Disable = !KeyBind.bDisabled; + bool Disable = !InKeyBind.bDisabled; if (ImGui::Checkbox("##Disable", &Disable)) { - KeyBind.bDisabled = !Disable; + InKeyBind.bDisabled = !Disable; } - if (KeyBind.bDisabled) + if (InKeyBind.bDisabled) { ImGui::SetItemTooltip("Enable command"); } @@ -613,7 +633,7 @@ bool FCogWidgets::KeyBind(FKeyBind& KeyBind) ImGui::SetItemTooltip("Disable command"); } - if (KeyBind.bDisabled) + if (InKeyBind.bDisabled) { ImGui::BeginDisabled(); } @@ -624,21 +644,43 @@ bool FCogWidgets::KeyBind(FKeyBind& KeyBind) ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15); if (ImGui::InputText("##Command", Buffer, IM_ARRAYSIZE(Buffer))) { - KeyBind.Command = FString(Buffer); + InKeyBind.Command = FString(Buffer); HasChanged = true; } - FCogImGuiKeyInfo KeyInfo; - FCogImguiInputHelper::KeyBindToKeyInfo(KeyBind, KeyInfo); - ImGui::SameLine(); - if (InputKey(KeyInfo)) + ImGui::SetNextItemWidth(ImGui::GetFontSize() * 6); + HasChanged |= Key(InKeyBind.Key); + { - HasChanged = true; - FCogImguiInputHelper::KeyInfoToKeyBind(KeyInfo, KeyBind); + ImGui::SameLine(); + ECheckBoxState State = FCogImguiInputHelper::MakeCheckBoxState(InKeyBind.Control, InKeyBind.bIgnoreCtrl); + HasChanged |= CheckBoxState("Ctrl", State); + BREAK_CHECKBOX_STATE(State, InKeyBind.Control, InKeyBind.bIgnoreCtrl); } - if (KeyBind.bDisabled) + { + ImGui::SameLine(); + ECheckBoxState State = FCogImguiInputHelper::MakeCheckBoxState(InKeyBind.Shift, InKeyBind.bIgnoreShift); + HasChanged |= CheckBoxState("Shift", State); + BREAK_CHECKBOX_STATE(State, InKeyBind.Shift, InKeyBind.bIgnoreShift); + } + + { + ImGui::SameLine(); + ECheckBoxState State = FCogImguiInputHelper::MakeCheckBoxState(InKeyBind.Alt, InKeyBind.bIgnoreAlt); + HasChanged |= CheckBoxState("Alt", State); + BREAK_CHECKBOX_STATE(State, InKeyBind.Alt, InKeyBind.bIgnoreAlt); + } + + { + ImGui::SameLine(); + ECheckBoxState State = FCogImguiInputHelper::MakeCheckBoxState(InKeyBind.Cmd, InKeyBind.bIgnoreCmd); + HasChanged |= CheckBoxState("Cmd", State); + BREAK_CHECKBOX_STATE(State, InKeyBind.Cmd, InKeyBind.bIgnoreCmd); + } + + if (InKeyBind.bDisabled) { ImGui::EndDisabled(); } @@ -746,7 +788,7 @@ FString FCogWidgets::FormatSmallFloat(float InValue) } //-------------------------------------------------------------------------------------------------------------------------- -bool FCogWidgets::MultiChoiceButtonsFloat(TArray& InValues, float& InValue, const ImVec2& InSize, bool InInline) +bool FCogWidgets::MultiChoiceButtonsFloat(TArray& InValues, float& InValue, const ImVec2& InSize, bool InInline, float InTolerance) { ImGuiStyle& Style = ImGui::GetStyle(); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(Style.WindowPadding.x * 0.40f, static_cast(Style.WindowPadding.y * 0.60f))); @@ -762,7 +804,7 @@ bool FCogWidgets::MultiChoiceButtonsFloat(TArray& InValues, float& InValu const auto Text = StringCast(*FormatSmallFloat(ButtonValue)); ImGui::PushID(i); - if (MultiChoiceButton(Text.Get(), ButtonValue == InValue, InSize)) + if (MultiChoiceButton(Text.Get(), FMath::IsNearlyEqual(ButtonValue, InValue, InTolerance) , InSize)) { IsPressed = true; InValue = ButtonValue; @@ -1444,3 +1486,60 @@ ImVec2 FCogWidgets::ComputeScreenCornerLocation(const ImVec2& InAlignment, const ImVec2 Position = Viewport->WorkPos + (InAlignment * Viewport->WorkSize) - Offset; return Position; } + +//-------------------------------------------------------------------------------------------------------------------------- +FString FCogWidgets::GetStringAfterCharacter(const FString& InString, const TCHAR InChar) +{ + int32 Index = 0; + if (InString.FindChar(InChar, Index)) + { + return InString.RightChop(Index + 1); + } + + return FString(); +} + +//-------------------------------------------------------------------------------------------------------------------------- +FString FCogWidgets::FormatConfigName(const FString& InConfigName) +{ + return FName::NameToDisplayString(GetStringAfterCharacter(InConfigName, '_'), false); +} + +//-------------------------------------------------------------------------------------------------------------------------- +FString FCogWidgets::FormatShortcutName(const FString& InShortcutName) +{ + return FName::NameToDisplayString(InShortcutName.Replace(TEXT("Shortcut_"), TEXT("")), false); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogWidgets::TextInputChordProperty(UObject& InConfig, const FProperty& InInputChordProperty) +{ + const FInputChord* InputChord = InInputChordProperty.ContainerPtrToValuePtr(&InConfig); + if (InputChord == nullptr) + { return; } + + const auto Name = StringCast(*FormatShortcutName(InInputChordProperty.GetName())); + const auto Shortcut = StringCast(*FCogImguiInputHelper::InputChordToString(*InputChord)); + + ImGui::Text("%s", Name.Get()); + ImGui::SameLine(); + if (BeginRightAlign(Name.Get())) + { + ImGui::TextDisabled("%s", Shortcut.Get()); + EndRightAlign(); + } +} + +//-------------------------------------------------------------------------------------------------------------------------- +bool FCogWidgets::InputChordProperty(UObject& InConfig, const FProperty& InInputChordProperty) +{ + FInputChord* InputChord = InInputChordProperty.ContainerPtrToValuePtr(&InConfig); + if (InputChord == nullptr) + { return false; } + + const auto Name = StringCast(*FormatShortcutName(InInputChordProperty.GetName())); + + return FCogWidgets::InputChord(Name.Get(), *InputChord); +} + + \ No newline at end of file diff --git a/Plugins/Cog/Source/Cog/Private/CogWindow.cpp b/Plugins/Cog/Source/Cog/Private/CogWindow.cpp index 1e854b4..774a3bf 100644 --- a/Plugins/Cog/Source/Cog/Private/CogWindow.cpp +++ b/Plugins/Cog/Source/Cog/Private/CogWindow.cpp @@ -254,4 +254,3 @@ float FCogWindow::GetDpiScale() const { return GetOwner()->GetContext().GetDpiScale(); } - diff --git a/Plugins/Cog/Source/Cog/Private/CogWindow_Layouts.cpp b/Plugins/Cog/Source/Cog/Private/CogWindow_Layouts.cpp index 1a8efc2..8650952 100644 --- a/Plugins/Cog/Source/Cog/Private/CogWindow_Layouts.cpp +++ b/Plugins/Cog/Source/Cog/Private/CogWindow_Layouts.cpp @@ -27,45 +27,40 @@ void FCogWindow_Layouts::RenderContent() } ImGui::Separator(); - for (int32 i = 0; i < 4; ++i) - { - RenderLoadLayoutMenuItem(PlayerInput, i); - } + + UCogWindowConfig_Settings* Settings = GetOwner()->GetSettings(); + RenderLoadLayoutMenuItem(1, Settings->Shortcut_LoadLayout1); + RenderLoadLayoutMenuItem(2, Settings->Shortcut_LoadLayout2); + RenderLoadLayoutMenuItem(3, Settings->Shortcut_LoadLayout3); + RenderLoadLayoutMenuItem(4, Settings->Shortcut_LoadLayout4); ImGui::Separator(); - for (int32 i = 0; i < 4; ++i) - { - RenderSaveLayoutMenuItem(PlayerInput, i); - } - + RenderSaveLayoutMenuItem(1, Settings->Shortcut_SaveLayout1); + RenderSaveLayoutMenuItem(2, Settings->Shortcut_SaveLayout2); + RenderSaveLayoutMenuItem(3, Settings->Shortcut_SaveLayout3); + RenderSaveLayoutMenuItem(4, Settings->Shortcut_SaveLayout4); } //-------------------------------------------------------------------------------------------------------------------------- -void FCogWindow_Layouts::RenderLoadLayoutMenuItem(const UPlayerInput* PlayerInput, int LayoutIndex) +void FCogWindow_Layouts::RenderLoadLayoutMenuItem(int InLayoutIndex, const FInputChord& InInputChord) { - FString Shortcut; - if (GetOwner()->GetSettings()->LoadLayoutShortcuts.IsValidIndex(LayoutIndex)) - { - Shortcut = FCogImguiInputHelper::KeyInfoToString(GetOwner()->GetSettings()->LoadLayoutShortcuts[LayoutIndex]); - } + const auto Shortcut = StringCast(*FCogImguiInputHelper::InputChordToString(InInputChord)); + const auto Text = StringCast(*FString::Printf(TEXT("Load Layout %d"), InLayoutIndex)); - if (ImGui::MenuItem(TCHAR_TO_ANSI(*FString::Printf(TEXT("Load Layout %d"), LayoutIndex + 1)), TCHAR_TO_ANSI(*Shortcut))) + if (ImGui::MenuItem(Text.Get(), Shortcut.Get())) { - GetOwner()->LoadLayout(LayoutIndex + 1); + GetOwner()->LoadLayout(InLayoutIndex + 1); } } //-------------------------------------------------------------------------------------------------------------------------- -void FCogWindow_Layouts::RenderSaveLayoutMenuItem(const UPlayerInput* PlayerInput, int LayoutIndex) +void FCogWindow_Layouts::RenderSaveLayoutMenuItem(int InLayoutIndex, const FInputChord& InInputChord) { - FString Shortcut; - if (GetOwner()->GetSettings()->LoadLayoutShortcuts.IsValidIndex(LayoutIndex)) - { - Shortcut = FCogImguiInputHelper::KeyInfoToString(GetOwner()->GetSettings()->SaveLayoutShortcuts[LayoutIndex]); - } + const auto Shortcut = StringCast(*FCogImguiInputHelper::InputChordToString(InInputChord)); + const auto Text = StringCast(*FString::Printf(TEXT("Save Layout %d"), InLayoutIndex)); - if (ImGui::MenuItem(TCHAR_TO_ANSI(*FString::Printf(TEXT("Save Layout %d"), LayoutIndex + 1)), TCHAR_TO_ANSI(*Shortcut))) + if (ImGui::MenuItem(Text.Get(), Shortcut.Get())) { - GetOwner()->SaveLayout(LayoutIndex + 1); + GetOwner()->SaveLayout(InLayoutIndex + 1); } } \ No newline at end of file diff --git a/Plugins/Cog/Source/Cog/Private/CogWindow_Settings.cpp b/Plugins/Cog/Source/Cog/Private/CogWindow_Settings.cpp index 194d579..03ce0f9 100644 --- a/Plugins/Cog/Source/Cog/Private/CogWindow_Settings.cpp +++ b/Plugins/Cog/Source/Cog/Private/CogWindow_Settings.cpp @@ -80,7 +80,7 @@ void FCogWindow_Settings::RenderContent() Context.SetEnableInput(bEnableInput); } FCogWidgets::ItemTooltipWrappedText("Enable ImGui inputs. When enabled the ImGui menu is shown and inputs are forwarded to ImGui."); - FCogWidgets::MenuItemShortcut("EnableInputShortcut", FCogImguiInputHelper::KeyInfoToString(Config->ToggleImGuiInputShortcut)); + FCogWidgets::MenuItemShortcut("EnableInputShortcut", FCogImguiInputHelper::InputChordToString(Config->Shortcut_ToggleImguiInput)); //------------------------------------------------------------------------------------------- bool bShareKeyboard = Context.GetShareKeyboard(); @@ -244,24 +244,34 @@ void FCogWindow_Settings::RenderContent() //------------------------------------------------------------------------------------------- if (ImGui::CollapsingHeader("Shortcuts", ImGuiTreeNodeFlags_DefaultOpen)) { - RenderShortcut("Toggle ImGui Input", Config->ToggleImGuiInputShortcut); - RenderShortcut("Toggle Selection", Config->ToggleSelectionShortcut); - - ImGui::Separator(); - - static char Buffer[32]; - - for (int32 i = 0; i < Config->LoadLayoutShortcuts.Num(); ++i) + TArray>& Configs = GetOwner()->GetConfigs(); + for (TObjectPtr SomeConfig : Configs) { - ImFormatString(Buffer, IM_ARRAYSIZE(Buffer), "Load Layout %d", i + 1); - RenderShortcut(Buffer, Config->LoadLayoutShortcuts[i]); - } + TArray Properties; + for (TFieldIterator It(SomeConfig->GetClass()); It; ++It) + { + if (FStructProperty* StructProperty = CastField(*It)) + { + if (StructProperty->Struct == FInputChord::StaticStruct()) + { + Properties.Add(StructProperty); + } + } + } - ImGui::Separator(); - for (int32 i = 0; i < Config->SaveLayoutShortcuts.Num(); ++i) - { - ImFormatString(Buffer, IM_ARRAYSIZE(Buffer), "Save Layout %d", i + 1); - RenderShortcut(Buffer, Config->SaveLayoutShortcuts[i]); + if (Properties.Num() > 0) + { + auto ConfigName = StringCast(*FCogWidgets::FormatConfigName(SomeConfig->GetClass()->GetName())); + ImGui::SeparatorText(ConfigName.Get()); + + for (const FProperty* Property : Properties) + { + if (FCogWidgets::InputChordProperty(*SomeConfig, *Property)) + { + GetOwner()->RebindShortcut(*SomeConfig, *Property); + } + } + } } } @@ -311,14 +321,4 @@ void FCogWindow_Settings::SetDPIScale(float Value) const { Config->DPIScale = Value; GetOwner()->GetContext().SetDPIScale(Config->DPIScale); - //COG_NOTIFY(TEXT("DPI Scale: %0.2f"), Value); -} - -//-------------------------------------------------------------------------------------------------------------------------- -void FCogWindow_Settings::RenderShortcut(const char* Label, FCogImGuiKeyInfo& KeyInfo) -{ - if (FCogWidgets::InputKey(Label, KeyInfo)) - { - GetOwner()->OnShortcutsDefined(); - } } diff --git a/Plugins/Cog/Source/Cog/Public/CogHelper.h b/Plugins/Cog/Source/Cog/Public/CogHelper.h index 3e7e211..d53371d 100644 --- a/Plugins/Cog/Source/Cog/Public/CogHelper.h +++ b/Plugins/Cog/Source/Cog/Public/CogHelper.h @@ -19,6 +19,9 @@ public: static const T* GetFirstAssetByClass(); static const UObject* GetFirstAssetByClass(const TSubclassOf& AssetClass); + + template + static FProperty* FindProperty(TCLass* Instance, TMember TCLass::*PointerToMember); }; //---------------------------------------------------------------------------------------------------------------------- @@ -27,3 +30,24 @@ const T* FCogHelper::GetFirstAssetByClass() { return Cast(GetFirstAssetByClass(T::StaticClass())); } + +//---------------------------------------------------------------------------------------------------------------------- +template +FProperty* FCogHelper::FindProperty(TCLass* Instance, TMember TCLass::*PointerToMember) +{ + for (TFieldIterator It(Instance->GetClass()); It; ++It) + { + FProperty* Property = *It; + + if (Property == nullptr) + { continue; } + + const void* MemberAddress = &(Instance->*PointerToMember); + const void* PropertyAddress = Property->ContainerPtrToValuePtr(Instance); + + if (MemberAddress == PropertyAddress) + { return Property; } + } + + return nullptr; +} \ No newline at end of file diff --git a/Plugins/Cog/Source/Cog/Public/CogPluginSubsystem.h b/Plugins/Cog/Source/Cog/Public/CogPluginSubsystem.h new file mode 100644 index 0000000..f6d8119 --- /dev/null +++ b/Plugins/Cog/Source/Cog/Public/CogPluginSubsystem.h @@ -0,0 +1,15 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Engine/GameInstance.h" +#include "CogPluginSubsystem.generated.h" + +UCLASS(Abstract) +class COG_API UCogPluginSubsystem : public UGameInstanceSubsystem +{ + GENERATED_BODY() + +public: + + virtual void OnPlayerControllerSet(APlayerController* InController) {} +}; diff --git a/Plugins/Cog/Source/Cog/Public/CogSubsystem.h b/Plugins/Cog/Source/Cog/Public/CogSubsystem.h index 155d523..b047273 100644 --- a/Plugins/Cog/Source/Cog/Public/CogSubsystem.h +++ b/Plugins/Cog/Source/Cog/Public/CogSubsystem.h @@ -1,6 +1,7 @@ #pragma once #include "CoreMinimal.h" +#include "CogHelper.h" #include "CogImguiContext.h" #include "CogWindow_Settings.h" #include "imgui.h" @@ -19,6 +20,7 @@ struct ImGuiSettingsHandler; struct ImGuiTextBuffer; struct FKey; +//-------------------------------------------------------------------------------------------------------------------------- UCLASS() class COG_API UCogSubsystem : public UGameInstanceSubsystem { @@ -55,7 +57,7 @@ public: virtual void ResetAllWindowsConfig(); - const UCogWindowConfig_Settings* GetSettings() const { return Settings.Get(); } + UCogWindowConfig_Settings* GetSettings() const { return Settings.Get(); } UCogCommonConfig* GetConfig(const TSubclassOf& ConfigClass); @@ -67,17 +69,24 @@ public: template T* GetAsset(); + FInputActionHandlerSignature& AddShortcut(const UObject& InInstance, const FProperty& InProperty); + + template + FInputActionHandlerSignature& AddShortcut(TCLass* InInstance, TMember TCLass::*InPointerToMember); + + void RebindShortcut(const UCogCommonConfig& InConfig, const FProperty& InProperty); + const FCogImguiContext& GetContext() const { return Context; } FCogImguiContext& GetContext() { return Context; } - void OnShortcutsDefined(); - bool IsRenderingMainMenu() const { return IsRenderingInMainMenu; } static void AddCommand(UPlayerInput* PlayerInput, const FString& Command, const FKey& Key); static void SortCommands(UPlayerInput* PlayerInput); + + TArray>& GetConfigs() const { return Configs; }; protected: @@ -91,11 +100,24 @@ protected: TArray SubMenus; }; + struct FCogShortcut + { + FName PropertyName; + + TWeakObjectPtr Config; + + FInputActionHandlerSignature Delegate; + + FInputChord InputChord; + }; + virtual void Render(float DeltaTime); virtual void Tick(UWorld* InTickedWorld, ELevelTick InTickType, float InDeltaTime); - virtual void TryInitialize(UWorld* World); + virtual void TryInitialize(UWorld& World); + + virtual void UpdateServerPlayerControllers(UWorld& World); virtual void InitializeWindow(FCogWindow* Window); @@ -111,11 +133,17 @@ protected: virtual void RenderMenuItemHelp(FCogWindow& Window); + void SetLocalPlayerController(APlayerController* PlayerController); + virtual void ToggleInputMode(); virtual void DisableInputMode(); + + virtual void TryDisableCommandsConflictingWithShortcuts(UPlayerInput* PlayerInput); + + virtual void RequestDisableCommandsConflictingWithShortcuts(); - virtual void HandleInputs(const UPlayerInput& PlayerInput); + virtual bool BindShortcut(FCogShortcut& InShortcut) const; virtual void RenderWidgets(); @@ -154,12 +182,20 @@ protected: UPROPERTY() mutable TArray> Assets; + TArray> ServerPlayerControllers; + + TWeakObjectPtr LocalPlayerController; + + TWeakObjectPtr InputComponent; + FCogImguiContext Context; TArray Windows; TArray Widgets; + TArray Shortcuts; + int32 WidgetsOrderIndex = 0; TArray SpaceWindows; @@ -187,7 +223,8 @@ protected: bool IsRenderingInMainMenu = false; int32 NumExecBindingsChecked = 0; - + + FInputActionHandlerSignature InvalidShortcutDelegate; }; //-------------------------------------------------------------------------------------------------------------------------- @@ -212,4 +249,20 @@ template T* UCogSubsystem::GetAsset() { return Cast(GetAsset(T::StaticClass())); -} \ No newline at end of file +} + +//-------------------------------------------------------------------------------------------------------------------------- +template +FInputActionHandlerSignature& UCogSubsystem::AddShortcut(TCLass* InInstance, TMember TCLass::* InPointerToMember) +{ + if (InInstance == nullptr) + { return InvalidShortcutDelegate; } + + const FProperty* Property = FCogHelper::FindProperty(InInstance, InPointerToMember); + if (Property == nullptr) + { return InvalidShortcutDelegate; } + + return AddShortcut(*InInstance, *Property); +} + + diff --git a/Plugins/Cog/Source/Cog/Public/CogWidgets.h b/Plugins/Cog/Source/Cog/Public/CogWidgets.h index 35278ce..2c2b09d 100644 --- a/Plugins/Cog/Source/Cog/Public/CogWidgets.h +++ b/Plugins/Cog/Source/Cog/Public/CogWidgets.h @@ -6,6 +6,8 @@ #include +#include "CogHelper.h" + class AActor; class APawn; class FEnumProperty; @@ -14,7 +16,6 @@ class UEnum; class UObject; enum class ECheckBoxState : uint8; enum ECollisionChannel : int; -struct FCogImGuiKeyInfo; struct FKeyBind; using FCogWindowActorContextMenuFunction = TFunction; @@ -54,7 +55,7 @@ public: static bool MultiChoiceButtonsInt(TArray& Values, int32& Value, const ImVec2& Size = ImVec2(0, 0), bool InInline = true); - static bool MultiChoiceButtonsFloat(TArray& InValues, float& InValue, const ImVec2& InSize = ImVec2(0, 0), bool InInline = true); + static bool MultiChoiceButtonsFloat(TArray& InValues, float& InValue, const ImVec2& InSize = ImVec2(0, 0), bool InInline = true, float InTolerance = UE_SMALL_NUMBER); static void SliderWithReset(const char* Name, float* Value, float Min, float Max, const float& ResetValue, const char* Format); @@ -93,18 +94,21 @@ public: static bool ComboboxEnum(const char* Label, EnumType& Value); static bool ComboboxEnum(const char* Label, const UEnum* Enum, int64 CurrentValue, int64& NewValue); - + + static bool ComboboxEnum(const char* Label, const UObject* Object, const char* FieldName, uint8* PointerToEnumValue); static bool ComboboxEnum(const char* Label, const FEnumProperty* EnumProperty, uint8* PointerToEnumValue); static bool CheckBoxState(const char* Label, ECheckBoxState& State, bool ShowTooltip = true); - static bool InputKey(const char* Label, FCogImGuiKeyInfo& KeyInfo); + static bool InputChord(const char* Label, FInputChord& InInputChord); - static bool InputKey(FCogImGuiKeyInfo& KeyInfo); + static bool InputChord(FInputChord& InInputChord); - static bool KeyBind(FKeyBind& KeyBind); + static bool Key(FKey& InKey); + + static bool KeyBind(FKeyBind& InKeyBind); static bool ButtonWithTooltip(const char* Text, const char* Tooltip); @@ -140,6 +144,12 @@ public: static void MenuItemShortcut(const char* Id, const FString& Text); + template + static void InputChordProperty(TCLass* InConfig, TMember TCLass::* InInputChordPointerToMember); + + template + static void TextInputChordProperty(TCLass* InConfig, TMember TCLass::* InInputChordPointerToMember); + static bool BrowseToAssetButton(const UObject* InAsset, const ImVec2& InSize = ImVec2(0, 0)); static bool BrowseToAssetButton(const FAssetData& InAssetData, const ImVec2& InSize = ImVec2(0, 0)); @@ -168,6 +178,16 @@ public: static ImVec2 ComputeScreenCornerLocation(const FVector2f& InAlignment, const FIntVector2& InPadding); static ImVec2 ComputeScreenCornerLocation(const ImVec2& InAlignment, const ImVec2& InPadding); + + static FString GetStringAfterCharacter(const FString& InString, TCHAR InChar); + + static FString FormatConfigName(const FString& InConfigName); + + static FString FormatShortcutName(const FString& InShortcutName); + + static void TextInputChordProperty(UObject& InConfig, const FProperty& InInputChordProperty); + + static bool InputChordProperty(UObject& InConfig, const FProperty& InInputChordProperty); }; template @@ -227,4 +247,30 @@ template ImGui::PopID(); return Result; +} + +template +void FCogWidgets::InputChordProperty(TCLass* InConfig, TMember TCLass::* InInputChordPointerToMember) +{ + if (InConfig == nullptr) + { return; } + + FProperty* Property = FCogHelper::FindProperty(InConfig, InInputChordPointerToMember); + if (Property == nullptr) + { return; } + + InputChordProperty(*InConfig, *Property); +} + +template +void FCogWidgets::TextInputChordProperty(TCLass* InConfig, TMember TCLass::* InInputChordPointerToMember) +{ + if (InConfig == nullptr) + { return; } + + FProperty* Property = FCogHelper::FindProperty(InConfig, InInputChordPointerToMember); + if (Property == nullptr) + { return; } + + TextInputChordProperty(*InConfig, *Property); } \ No newline at end of file diff --git a/Plugins/Cog/Source/Cog/Public/CogWindow.h b/Plugins/Cog/Source/Cog/Public/CogWindow.h index ba4ea7c..a3b1e02 100644 --- a/Plugins/Cog/Source/Cog/Public/CogWindow.h +++ b/Plugins/Cog/Source/Cog/Public/CogWindow.h @@ -43,6 +43,8 @@ public: virtual void RenderSettings(); + virtual void BindInputs(UInputComponent* InputComponent) {} + ImGuiID GetID() const { return ID; } /** The full name of the window, that contains the path in the main menu. For example "Gameplay.Character.Effect" */ @@ -87,6 +89,7 @@ public: const UObject* GetAsset(const TSubclassOf& AssetClass) const; + protected: friend class UCogSubsystem; diff --git a/Plugins/Cog/Source/Cog/Public/CogWindow_Layouts.h b/Plugins/Cog/Source/Cog/Public/CogWindow_Layouts.h index deb4b67..00f93d2 100644 --- a/Plugins/Cog/Source/Cog/Public/CogWindow_Layouts.h +++ b/Plugins/Cog/Source/Cog/Public/CogWindow_Layouts.h @@ -17,7 +17,7 @@ protected: virtual void RenderContent() override; - virtual void RenderLoadLayoutMenuItem(const UPlayerInput* PlayerInput, int LayoutIndex); + virtual void RenderLoadLayoutMenuItem(int InLayoutIndex, const FInputChord& InInputChord); - virtual void RenderSaveLayoutMenuItem(const UPlayerInput* PlayerInput, int LayoutIndex); + virtual void RenderSaveLayoutMenuItem(int InLayoutIndex, const FInputChord& InInputChord); }; diff --git a/Plugins/Cog/Source/Cog/Public/CogWindow_Settings.h b/Plugins/Cog/Source/Cog/Public/CogWindow_Settings.h index 894658b..26c379c 100644 --- a/Plugins/Cog/Source/Cog/Public/CogWindow_Settings.h +++ b/Plugins/Cog/Source/Cog/Public/CogWindow_Settings.h @@ -31,8 +31,6 @@ protected: virtual void PreSaveConfig() override; - virtual void RenderShortcut(const char* Label, FCogImGuiKeyInfo& KeyInfo); - TObjectPtr Config = nullptr; }; @@ -98,19 +96,40 @@ public: UPROPERTY(Config) bool ShowWidgetBorders = false; + + UPROPERTY(Config) + FInputChord Shortcut_ToggleImguiInput = FInputChord(EKeys::F1); + + UPROPERTY(Config) + FInputChord Shortcut_ToggleSelection = FInputChord(EKeys::F5); + + UPROPERTY(Config) + FInputChord Shortcut_LoadLayout1 = FInputChord(EKeys::F2); + + UPROPERTY(Config) + FInputChord Shortcut_LoadLayout2 = FInputChord(EKeys::F3); + + UPROPERTY(Config) + FInputChord Shortcut_LoadLayout3 = FInputChord(EKeys::F4); + + UPROPERTY(Config) + FInputChord Shortcut_LoadLayout4 = FInputChord(); + + UPROPERTY(Config) + FInputChord Shortcut_SaveLayout1 = FInputChord(); + + UPROPERTY(Config) + FInputChord Shortcut_SaveLayout2 = FInputChord(); + + UPROPERTY(Config) + FInputChord Shortcut_SaveLayout3 = FInputChord(); + + UPROPERTY(Config) + FInputChord Shortcut_SaveLayout4 = FInputChord(); UPROPERTY(Config) - FCogImGuiKeyInfo ToggleImGuiInputShortcut = FCogImGuiKeyInfo(EKeys::F1); + FInputChord Shortcut_ResetLayout = FInputChord(); - UPROPERTY(Config) - FCogImGuiKeyInfo ToggleSelectionShortcut = FCogImGuiKeyInfo(EKeys::F5); - - UPROPERTY(Config) - TArray LoadLayoutShortcuts = { FCogImGuiKeyInfo(EKeys::F2), FCogImGuiKeyInfo(EKeys::F3), FCogImGuiKeyInfo(EKeys::F4), FCogImGuiKeyInfo()}; - - UPROPERTY(Config) - TArray SaveLayoutShortcuts = { FCogImGuiKeyInfo(), FCogImGuiKeyInfo(), FCogImGuiKeyInfo(), FCogImGuiKeyInfo()}; - //UPROPERTY(Config) //bool bNavEnableGamepad = false; @@ -129,17 +148,23 @@ public: bShowWindowsInMainMenu = true; bEnableInput = false; bShareMouse = false; + bShareMouseWithGameplay = false; bShareKeyboard = false; bNavEnableKeyboard = false; - bDisableConflictingCommands = true; + bDisableConflictingCommands = true; bDisableShortcutsWhenImGuiWantTextInput = false; - //bNavEnableGamepad = false; - //bNavNoCaptureInput = true; - - - ToggleImGuiInputShortcut = FCogImGuiKeyInfo(EKeys::F1); - ToggleSelectionShortcut = FCogImGuiKeyInfo(EKeys::F5); - LoadLayoutShortcuts = { FCogImGuiKeyInfo(EKeys::F2), FCogImGuiKeyInfo(EKeys::F3), FCogImGuiKeyInfo(EKeys::F4), FCogImGuiKeyInfo()}; - SaveLayoutShortcuts = { FCogImGuiKeyInfo(), FCogImGuiKeyInfo(), FCogImGuiKeyInfo(), FCogImGuiKeyInfo()}; + WidgetAlignment = ECogWidgetAlignment::Right; + ShowWidgetBorders = false; + Shortcut_ToggleImguiInput = FInputChord(EKeys::F1); + Shortcut_ToggleSelection = FInputChord(EKeys::F5); + Shortcut_LoadLayout1 = FInputChord(EKeys::F2); + Shortcut_LoadLayout2 = FInputChord(EKeys::F3); + Shortcut_LoadLayout3 = FInputChord(EKeys::F4); + Shortcut_LoadLayout4 = FInputChord(); + Shortcut_SaveLayout1 = FInputChord(); + Shortcut_SaveLayout2 = FInputChord(); + Shortcut_SaveLayout3 = FInputChord(); + Shortcut_SaveLayout4 = FInputChord(); + Shortcut_ResetLayout = FInputChord(); } }; \ No newline at end of file diff --git a/Plugins/Cog/Source/CogDebug/Public/CogDebugPluginSubsystem.h b/Plugins/Cog/Source/CogDebug/Public/CogDebugPluginSubsystem.h new file mode 100644 index 0000000..b700dbb --- /dev/null +++ b/Plugins/Cog/Source/CogDebug/Public/CogDebugPluginSubsystem.h @@ -0,0 +1,15 @@ +#pragma once + +#include "CoreMinimal.h" +#include "Engine/GameInstance.h" +#include "CogDebugPluginSubsystem.generated.h" + +UCLASS(Abstract) +class COGDEBUG_API UCogDebugPluginSubsystem : public UGameInstanceSubsystem +{ + GENERATED_BODY() + +public: + + virtual void OnPlayerControllerReady(APlayerController* InController) {} +}; diff --git a/Plugins/Cog/Source/CogDebug/Public/CogDebugSubsystem.h b/Plugins/Cog/Source/CogDebug/Public/CogDebugSubsystem.h new file mode 100644 index 0000000..bf06177 --- /dev/null +++ b/Plugins/Cog/Source/CogDebug/Public/CogDebugSubsystem.h @@ -0,0 +1,22 @@ +#pragma once + +#include "CoreMinimal.h" +#include "CogDebugReplicator.h" +#include "CogDebugPluginSubsystem.h" +#include "CogDebugSubsystem.generated.h" + +UCLASS() +class COGDEBUG_API UCogDebugSubsystem : public UCogDebugPluginSubsystem +{ + GENERATED_BODY() + +public: + + virtual void OnPlayerControllerReady(APlayerController* InController) override + { + if (InController != nullptr) + { + ACogDebugReplicator::Spawn(InController); + } + } +}; diff --git a/Plugins/Cog/Source/CogDebug/Public/CogDebugTrack.h b/Plugins/Cog/Source/CogDebug/Public/CogDebugTrack.h index e6db088..faca687 100644 --- a/Plugins/Cog/Source/CogDebug/Public/CogDebugTrack.h +++ b/Plugins/Cog/Source/CogDebug/Public/CogDebugTrack.h @@ -30,7 +30,5 @@ struct COGDEBUG_API FCogDebugTrack ECogDebugTrackType Type = ECogDebugTrackType::Value; - TWeakObjectPtr World; - FCogDebugTracker* Owner = nullptr; - }; +}; diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineReplicator.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineReplicator.cpp index 75179a7..220d5d3 100644 --- a/Plugins/Cog/Source/CogEngine/Private/CogEngineReplicator.cpp +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineReplicator.cpp @@ -3,6 +3,7 @@ #include "CogCommon.h" #include "CogCommonPossessorInterface.h" #include "CogEngineDataAsset.h" +#include "CogSubsystem.h" #include "Engine/EngineTypes.h" #include "Engine/World.h" #include "EngineUtils.h" diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_CommandBindings.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_CommandBindings.cpp index b141445..240584a 100644 --- a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_CommandBindings.cpp +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_CommandBindings.cpp @@ -54,7 +54,7 @@ void FCogEngineWindow_CommandBindings::RenderContent() "Disable the existing Unreal command shortcuts mapped to same shortcuts Cog is using. Typically, if the F1 shortcut is used to toggle Inputs, the Unreal wireframe command will get disabled." )) { - GetOwner()->OnShortcutsDefined(); + //GetOwner()->OnShortcutsDefined(); } for (FKeyBind& KeyBind : PlayerInput->DebugExecBindings) diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Selection.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Selection.cpp index a5d586e..13becb5 100644 --- a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Selection.cpp +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Selection.cpp @@ -339,7 +339,7 @@ void FCogEngineWindow_Selection::RenderPickButtonTooltip() { if (FCogWidgets::BeginItemTooltipWrappedText()) { - const FString Shortcut = FCogImguiInputHelper::KeyInfoToString(GetOwner()->GetSettings()->ToggleSelectionShortcut); + const FString Shortcut = FCogImguiInputHelper::InputChordToString(GetOwner()->GetSettings()->Shortcut_ToggleSelection); ImGui::Text("Enter selection mode to select an actor on screen. Change which actor type is selectable by clicking the selection combobox\n" "%s", TCHAR_TO_ANSI(*Shortcut)); FCogWidgets::EndItemTooltipWrappedText(); diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_TimeScale.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_TimeScale.cpp index 8e785e7..2ec735f 100644 --- a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_TimeScale.cpp +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_TimeScale.cpp @@ -2,10 +2,14 @@ #include "CogEngineReplicator.h" #include "CogImguiHelper.h" +#include "CogImguiInputHelper.h" +#include "CogSubsystem.h" #include "CogWidgets.h" #include "Engine/Engine.h" #include "Engine/World.h" + + //-------------------------------------------------------------------------------------------------------------------------- void FCogEngineWindow_TimeScale::Initialize() { @@ -15,6 +19,12 @@ void FCogEngineWindow_TimeScale::Initialize() bIsWidgetVisible = true; Config = GetConfig(); + + UCogEngineWindowConfig_TimeScale* ConfigPtr = Config.Get(); + GetOwner()->AddShortcut(ConfigPtr, &UCogEngineWindowConfig_TimeScale::Shortcut_FasterTimeScale).BindRaw(this, &FCogEngineWindow_TimeScale::FasterTimeScale); + GetOwner()->AddShortcut(ConfigPtr, &UCogEngineWindowConfig_TimeScale::Shortcut_SlowerTimeScale).BindRaw(this, &FCogEngineWindow_TimeScale::SlowerTimeScale); + GetOwner()->AddShortcut(ConfigPtr, &UCogEngineWindowConfig_TimeScale::Shortcut_ResetTimeScale).BindRaw(this, &FCogEngineWindow_TimeScale::ResetTimeScale); + GetOwner()->AddShortcut(ConfigPtr, &UCogEngineWindowConfig_TimeScale::Shortcut_ZeroTimeScale).BindRaw(this, &FCogEngineWindow_TimeScale::ZeroTimeScale); } //-------------------------------------------------------------------------------------------------------------------------- @@ -53,7 +63,14 @@ void FCogEngineWindow_TimeScale::RenderContextMenu() ImGui::SetItemTooltip("Color of the current time scale, in widget mode, when the time scale in not 1."); FCogWidgets::FloatArray("Time Scales", Config->TimeScales, 10, ImVec2(0, ImGui::GetFontSize() * 10)); - + + if (ImGui::CollapsingHeader("Shortcuts", ImGuiTreeNodeFlags_DefaultOpen)) + { + FCogWidgets::InputChord("Speed Up", Config->Shortcut_FasterTimeScale); + FCogWidgets::InputChord("Speed Down", Config->Shortcut_SlowerTimeScale); + FCogWidgets::InputChord("Reset Time", Config->Shortcut_ResetTimeScale); + } + ImGui::Separator(); FCogWindow::RenderContextMenu(); } @@ -71,16 +88,21 @@ void FCogEngineWindow_TimeScale::RenderMainMenuWidget() return; } - const float CurrentValue = Replicator->GetTimeDilation(); - if (CurrentValue != 1.0f) + float TimeDilation = GetTimeDilation(); + if (TimeDilation != 1.0f) { ImGui::PushStyleColor(ImGuiCol_Text, FCogImguiHelper::ToImVec4(Config->TimeScaleModifiedColor)); } + + if (FMath::IsNearlyZero(TimeDilation, 0.0001f)) + { + TimeDilation = 0.0f; + } - const auto CurrentValueText = StringCast(*FString::Printf(TEXT("x%g"), CurrentValue)); - const bool Open = ImGui::BeginMenu(CurrentValueText.Get()); + const auto Text = StringCast(*FString::Printf(TEXT("x%g"), TimeDilation)); + const bool Open = ImGui::BeginMenu(Text.Get()); - if (CurrentValue != 1) + if (TimeDilation != 1) { ImGui::PopStyleColor(); } @@ -90,16 +112,16 @@ void FCogEngineWindow_TimeScale::RenderMainMenuWidget() RenderContextMenu(); ImGui::EndPopup(); } - + if (Open) { for (int32 i = 0; i < Config->TimeScales.Num(); ++i) { const float Value = Config->TimeScales[i]; const auto ValueText = StringCast(*FString::Printf(TEXT("%g"), Value)); - if (ImGui::Selectable(ValueText.Get(), Value == Replicator->GetTimeDilation())) + if (ImGui::Selectable(ValueText.Get(), Value == TimeDilation)) { - Replicator->SetTimeDilation(Value); + SetCurrentTimeScale(*Replicator, Value); } } @@ -107,16 +129,128 @@ void FCogEngineWindow_TimeScale::RenderMainMenuWidget() } else { - ImGui::SetItemTooltip("Time Scale"); + if (ImGui::BeginItemTooltip()) + { + ImGui::Text("Time Scale: x%g", TimeDilation); + ImGui::Spacing(); + ImGui::Separator(); + FCogWidgets::TextInputChordProperty(Config.Get(), &UCogEngineWindowConfig_TimeScale::Shortcut_FasterTimeScale); + FCogWidgets::TextInputChordProperty(Config.Get(), &UCogEngineWindowConfig_TimeScale::Shortcut_SlowerTimeScale); + FCogWidgets::TextInputChordProperty(Config.Get(), &UCogEngineWindowConfig_TimeScale::Shortcut_ResetTimeScale); + FCogWidgets::TextInputChordProperty(Config.Get(), &UCogEngineWindowConfig_TimeScale::Shortcut_ZeroTimeScale); + ImGui::EndTooltip(); + } } } +//-------------------------------------------------------------------------------------------------------------------------- +int32 FCogEngineWindow_TimeScale::GetCurrentTimeScaleIndex(const ACogEngineReplicator& Replicator) const +{ + return GetTimeScaleIndex(Replicator.GetTimeDilation()); +} + +//-------------------------------------------------------------------------------------------------------------------------- +int32 FCogEngineWindow_TimeScale::GetTimeScaleIndex(float InTimeScale) const +{ + for (int32 i = 0; i < Config->TimeScales.Num(); ++i) + { + const float Value = Config->TimeScales[i]; + if (FMath::IsNearlyEqual(Value, InTimeScale)) + { return i; } + } + + return INDEX_NONE; +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_TimeScale::SetCurrentTimeScale(ACogEngineReplicator& Replicator, const float Value) const +{ + Replicator.SetTimeDilation(Value); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_TimeScale::SetCurrentTimeScaleIndex(ACogEngineReplicator& Replicator, int32 InTimeScaleIndex) const +{ + if (Config->TimeScales.IsValidIndex(InTimeScaleIndex) == false) + { return; } + + const float Value = Config->TimeScales[InTimeScaleIndex]; + + SetCurrentTimeScale(Replicator, Value); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_TimeScale::FasterTimeScale() +{ + ACogEngineReplicator* Replicator = ACogEngineReplicator::GetLocalReplicator(*GetWorld()); + if (Replicator == nullptr) + { return; } + + const int32 TimeScaleIndex = GetCurrentTimeScaleIndex(*Replicator); + if (TimeScaleIndex == INDEX_NONE) + { return; } + + SetCurrentTimeScaleIndex(*Replicator, TimeScaleIndex + 1); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_TimeScale::SlowerTimeScale() +{ + ACogEngineReplicator* Replicator = ACogEngineReplicator::GetLocalReplicator(*GetWorld()); + if (Replicator == nullptr) + { return; } + + const int32 TimeScaleIndex = GetCurrentTimeScaleIndex(*Replicator); + if (TimeScaleIndex == INDEX_NONE) + { return; } + + SetCurrentTimeScaleIndex(*Replicator, TimeScaleIndex - 1); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_TimeScale::ResetTimeScale() +{ + ACogEngineReplicator* Replicator = ACogEngineReplicator::GetLocalReplicator(*GetWorld()); + if (Replicator == nullptr) + { return; } + + SetCurrentTimeScale(*Replicator, 1.0f); +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogEngineWindow_TimeScale::ZeroTimeScale() +{ + ACogEngineReplicator* Replicator = ACogEngineReplicator::GetLocalReplicator(*GetWorld()); + if (Replicator == nullptr) + { return; } + + SetCurrentTimeScale(*Replicator, 0.0f); +} + +//-------------------------------------------------------------------------------------------------------------------------- +float FCogEngineWindow_TimeScale::GetTimeDilation() const +{ + const UWorld* World = GetWorld(); + if (World == nullptr) + { + return 1.0f; + } + + AWorldSettings* WorldSettings = World->GetWorldSettings(); + if (WorldSettings == nullptr) + { + return 1.0f; + } + + return WorldSettings->GetEffectiveTimeDilation(); +} + //-------------------------------------------------------------------------------------------------------------------------- void FCogEngineWindow_TimeScale::RenderTimeScaleChoices(ACogEngineReplicator* Replicator) { - float Value = Replicator->GetTimeDilation(); - if (FCogWidgets::MultiChoiceButtonsFloat(Config->TimeScales, Value, ImVec2(3.5f * FCogWidgets::GetFontWidth(), 0), Config->Inline)) + float TimeDilation = GetTimeDilation(); + if (FCogWidgets::MultiChoiceButtonsFloat(Config->TimeScales, TimeDilation, ImVec2(3.5f * FCogWidgets::GetFontWidth(), 0), Config->Inline, 0.0001f)) { - Replicator->SetTimeDilation(Value); + Replicator->SetTimeDilation(TimeDilation); } -} \ No newline at end of file +} diff --git a/Plugins/Cog/Source/CogEngine/Public/CogEngineSubsystem.h b/Plugins/Cog/Source/CogEngine/Public/CogEngineSubsystem.h new file mode 100644 index 0000000..6988a1a --- /dev/null +++ b/Plugins/Cog/Source/CogEngine/Public/CogEngineSubsystem.h @@ -0,0 +1,22 @@ +#pragma once + +#include "CoreMinimal.h" +#include "CogEngineReplicator.h" +#include "CogDebugPluginSubsystem.h" +#include "CogEngineSubsystem.generated.h" + +UCLASS() +class COGENGINE_API UCogEngineSubsystem : public UCogDebugPluginSubsystem +{ + GENERATED_BODY() + +public: + + virtual void OnPlayerControllerReady(APlayerController* InController) override + { + if (InController != nullptr) + { + ACogEngineReplicator::Spawn(InController); + } + } +}; diff --git a/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Console.h b/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Console.h index a0e0cb1..28dd809 100644 --- a/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Console.h +++ b/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Console.h @@ -123,7 +123,7 @@ public: SortCommands = false; DockInputInMenuBar = false; - FocusWidgetWhenAppearing = true; + FocusWidgetWhenAppearing = false; UseClipper = false; NumHistoryCommands = 10; CompletionMinimumCharacters = 1; diff --git a/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_TimeScale.h b/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_TimeScale.h index c84aa2f..913d717 100644 --- a/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_TimeScale.h +++ b/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_TimeScale.h @@ -2,6 +2,7 @@ #include "CoreMinimal.h" #include "CogEngineReplicator.h" +#include "CogImguiKeyInfo.h" #include "CogWindow.h" #include "CogEngineWindow_TimeScale.generated.h" @@ -27,6 +28,24 @@ protected: virtual void RenderTimeScaleChoices(ACogEngineReplicator* Replicator); + virtual int32 GetCurrentTimeScaleIndex(const ACogEngineReplicator& Replicator) const; + + virtual void SetCurrentTimeScaleIndex(ACogEngineReplicator& Replicator, int32 InTimeScaleIndex) const; + + virtual void FasterTimeScale(); + + virtual void SlowerTimeScale(); + + virtual void ResetTimeScale(); + + virtual void ZeroTimeScale(); + + virtual float GetTimeDilation() const; + + virtual int32 GetTimeScaleIndex(float InTimeScale) const; + + virtual void SetCurrentTimeScale(ACogEngineReplicator& Replicator, float Value) const; + TWeakObjectPtr Config; }; @@ -46,17 +65,34 @@ public: Inline = true; TimeScales = { 0.00f, 0.01f, 0.10f, 0.50f, 1.00f, 2.00f, 5.00f, 10.0f }; TimeScaleModifiedColor = FColor(255, 30, 210, 255); + + Shortcut_ZeroTimeScale = FInputChord(EKeys::NumPadZero); + Shortcut_ResetTimeScale = FInputChord(EKeys::NumPadOne); + Shortcut_FasterTimeScale = FInputChord(EKeys::Add); + Shortcut_SlowerTimeScale = FInputChord(EKeys::Subtract); } UPROPERTY(Config) float TimeScale = 1.0f; UPROPERTY(Config) - TArray TimeScales; + TArray TimeScales = { 0.00f, 0.01f, 0.10f, 0.50f, 1.00f, 2.00f, 5.00f, 10.0f }; UPROPERTY(Config) bool Inline = true; UPROPERTY(Config) - FColor TimeScaleModifiedColor = FColor(); + FColor TimeScaleModifiedColor = FColor(255, 30, 210, 255); + + UPROPERTY(Config) + FInputChord Shortcut_ZeroTimeScale = FInputChord(EKeys::NumPadZero); + + UPROPERTY(Config) + FInputChord Shortcut_ResetTimeScale = FInputChord(EKeys::NumPadOne); + + UPROPERTY(Config) + FInputChord Shortcut_FasterTimeScale = FInputChord(EKeys::Add); + + UPROPERTY(Config) + FInputChord Shortcut_SlowerTimeScale = FInputChord(EKeys::Subtract); }; \ No newline at end of file diff --git a/Plugins/Cog/Source/CogImgui/Private/CogImguiContext.cpp b/Plugins/Cog/Source/CogImgui/Private/CogImguiContext.cpp index 8a428f0..83cb8ef 100644 --- a/Plugins/Cog/Source/CogImgui/Private/CogImguiContext.cpp +++ b/Plugins/Cog/Source/CogImgui/Private/CogImguiContext.cpp @@ -265,7 +265,7 @@ bool FCogImguiContext::BeginFrame(float InDeltaTime) // Sometime the game can retake unaware that ImGui want to keep the focus and mouse unlock. // This typically happens when switching level. //------------------------------------------------------------------------------------------------------- - if (bRetakeFocus) + if (bRetakeFocus && IsConsoleOpened() == false) { SetEnableInput(true); bRetakeFocus = false; diff --git a/Plugins/Cog/Source/CogImgui/Private/CogImguiInputHelper.cpp b/Plugins/Cog/Source/CogImgui/Private/CogImguiInputHelper.cpp index 79c1184..6a5bf4a 100644 --- a/Plugins/Cog/Source/CogImgui/Private/CogImguiInputHelper.cpp +++ b/Plugins/Cog/Source/CogImgui/Private/CogImguiInputHelper.cpp @@ -17,7 +17,7 @@ #endif //WITH_EDITOR //-------------------------------------------------------------------------------------------------------------------------- - TArray FCogImguiInputHelper::CogShortcuts; + TArray FCogImguiInputHelper::CogPrioritizedShortcuts; //-------------------------------------------------------------------------------------------------------------------------- APlayerController* FCogImguiInputHelper::GetFirstLocalPlayerController(const UWorld& World) @@ -60,9 +60,9 @@ bool FCogImguiInputHelper::IsTopPriorityKeyEvent(const UPlayerInput& PlayerInput //------------------------------------------------------------------------------------------------ // We want the user to be able to use Cog shortcuts when imgui has the input. //------------------------------------------------------------------------------------------------ - for (const FCogImGuiKeyInfo& KeyInfo : CogShortcuts) + for (const FInputChord& InputChord : CogPrioritizedShortcuts) { - if (IsKeyEventMatchingKeyInfo(InKeyEvent, KeyInfo)) + if (IsInputChordMatchingKeyInfo(InKeyEvent, InputChord)) { return true; } } @@ -117,39 +117,6 @@ bool FCogImguiInputHelper::IsCheckBoxStateMatchingKeyBindModifier(ECheckBoxState return false; } -//-------------------------------------------------------------------------------------------------------------------------- -bool FCogImguiInputHelper::IsKeyEventMatchingKeyInfo(const FKeyEvent& InKeyEvent, const FCogImGuiKeyInfo& InKeyInfo) -{ - const bool Result = (InKeyInfo.Key == InKeyEvent.GetKey()) - && IsCheckBoxStateMatchingValue(InKeyInfo.Shift, InKeyEvent.IsShiftDown()) - && IsCheckBoxStateMatchingValue(InKeyInfo.Ctrl, InKeyEvent.IsControlDown()) - && IsCheckBoxStateMatchingValue(InKeyInfo.Alt, InKeyEvent.IsAltDown()) - && IsCheckBoxStateMatchingValue(InKeyInfo.Cmd, InKeyEvent.IsCommandDown()); - - return Result; -} - -//-------------------------------------------------------------------------------------------------------------------------- -#define BREAK_CHECKBOX_STATE(CheckBoxState, RequireValue, IgnoreValue) \ -{ \ - if (CheckBoxState == ECheckBoxState::Checked) \ - { \ - RequireValue = true; \ - IgnoreValue = false; \ - } \ - else if (CheckBoxState == ECheckBoxState::Unchecked) \ - { \ - RequireValue = false; \ - IgnoreValue = true; \ - } \ - else if (CheckBoxState == ECheckBoxState::Undetermined) \ - { \ - RequireValue = false; \ - IgnoreValue = false; \ - } \ -} \ - - //-------------------------------------------------------------------------------------------------------------------------- ECheckBoxState FCogImguiInputHelper::MakeCheckBoxState(uint8 RequireValue, uint8 IgnoreValue) { @@ -167,57 +134,29 @@ ECheckBoxState FCogImguiInputHelper::MakeCheckBoxState(uint8 RequireValue, uint8 } //-------------------------------------------------------------------------------------------------------------------------- -void FCogImguiInputHelper::KeyBindToKeyInfo(const FKeyBind& KeyBind, FCogImGuiKeyInfo& KeyInfo) +bool FCogImguiInputHelper::IsInputChordMatchingKeyInfo(const FKeyEvent& InKeyEvent, const FInputChord& InInputChord) { - KeyInfo.Key = KeyBind.Key; - KeyInfo.Shift = MakeCheckBoxState(KeyBind.Shift, KeyBind.bIgnoreShift); - KeyInfo.Ctrl = MakeCheckBoxState(KeyBind.Control, KeyBind.bIgnoreCtrl); - KeyInfo.Alt = MakeCheckBoxState(KeyBind.Alt, KeyBind.bIgnoreAlt); - KeyInfo.Alt = MakeCheckBoxState(KeyBind.Cmd, KeyBind.bIgnoreCmd); -} - - -//-------------------------------------------------------------------------------------------------------------------------- -void FCogImguiInputHelper::KeyInfoToKeyBind(const FCogImGuiKeyInfo& KeyInfo, FKeyBind& KeyBind) -{ - KeyBind.Key = KeyInfo.Key; - BREAK_CHECKBOX_STATE(KeyInfo.Shift, KeyBind.Shift, KeyBind.bIgnoreShift); - BREAK_CHECKBOX_STATE(KeyInfo.Ctrl, KeyBind.Control, KeyBind.bIgnoreCtrl); - BREAK_CHECKBOX_STATE(KeyInfo.Alt, KeyBind.Alt, KeyBind.bIgnoreAlt); - BREAK_CHECKBOX_STATE(KeyInfo.Cmd, KeyBind.Cmd, KeyBind.bIgnoreCmd); -} - -//-------------------------------------------------------------------------------------------------------------------------- -bool FCogImguiInputHelper::IsKeyBindMatchingKeyInfo(const FKeyBind& InKeyBind, const FCogImGuiKeyInfo& InKeyInfo) -{ - const bool Result = - InKeyBind.bDisabled == false - && (InKeyInfo.Key == InKeyBind.Key) - && IsCheckBoxStateMatchingKeyBindModifier(InKeyInfo.Shift, InKeyBind.Shift, InKeyBind.bIgnoreShift) - && IsCheckBoxStateMatchingKeyBindModifier(InKeyInfo.Ctrl, InKeyBind.Control, InKeyBind.bIgnoreCtrl) - && IsCheckBoxStateMatchingKeyBindModifier(InKeyInfo.Alt, InKeyBind.Alt, InKeyBind.bIgnoreAlt) - && IsCheckBoxStateMatchingKeyBindModifier(InKeyInfo.Cmd, InKeyBind.Cmd, InKeyBind.bIgnoreCmd); + const bool Result = (InInputChord.Key == InKeyEvent.GetKey()) + && (InInputChord.bShift == InKeyEvent.IsShiftDown()) + && (InInputChord.bCtrl == InKeyEvent.IsControlDown()) + && (InInputChord.bAlt == InKeyEvent.IsAltDown()) + && (InInputChord.bCmd == InKeyEvent.IsCommandDown()); return Result; } //-------------------------------------------------------------------------------------------------------------------------- -bool FCogImguiInputHelper::WasKeyInfoJustPressed(const APlayerController& PlayerController, const FCogImGuiKeyInfo& KeyInfo) +bool FCogImguiInputHelper::IsKeyBindMatchingInputChord(const FKeyBind& InKeyBind, const FInputChord& InInputChord) { - if (PlayerController.WasInputKeyJustPressed(KeyInfo.Key)) - { - const FModifierKeysState& ModifierKeys = FSlateApplication::Get().GetModifierKeys(); + const bool Result = + InKeyBind.bDisabled == false + && (InInputChord.Key == InKeyBind.Key) + && (InInputChord.bShift == InKeyBind.Shift) + && (InInputChord.bCtrl == InKeyBind.Control) + && (InInputChord.bAlt == InKeyBind.Alt) + && (InInputChord.bCmd == InKeyBind.Cmd); - const bool MatchCtrl = IsCheckBoxStateMatchingValue(KeyInfo.Ctrl, ModifierKeys.IsControlDown()); - const bool MatchAlt = IsCheckBoxStateMatchingValue(KeyInfo.Alt, ModifierKeys.IsAltDown()); - const bool MatchShift = IsCheckBoxStateMatchingValue(KeyInfo.Shift, ModifierKeys.IsShiftDown()); - const bool MatchCmd = IsCheckBoxStateMatchingValue(KeyInfo.Cmd, ModifierKeys.IsCommandDown()); - - const bool Result = MatchCtrl && MatchAlt && MatchShift && MatchCmd; - return Result; - } - - return false; + return Result; } //-------------------------------------------------------------------------------------------------------------------------- @@ -293,78 +232,35 @@ EMouseCursor::Type FCogImguiInputHelper::ToSlateMouseCursor(ImGuiMouseCursor Mou } //-------------------------------------------------------------------------------------------------------------------------- -FString FCogImguiInputHelper::CommandToString(const UWorld& World, const FString& Command) +FString FCogImguiInputHelper::InputChordToString(const FInputChord& InInputChord) { - const UPlayerInput* PlayerInput = GetPlayerInput(World); - if (PlayerInput == nullptr) - { - return FString(); - } - - const FKeyBind* Result = PlayerInput->DebugExecBindings.FindByPredicate([&](const FKeyBind& KeyBind) { return KeyBind.Command == Command; }); - if (Result == nullptr) - { - return FString(); - } - - return KeyBindToString(*Result); -} - -//-------------------------------------------------------------------------------------------------------------------------- -FString FCogImguiInputHelper::CommandToString(const UPlayerInput* PlayerInput, const FString& Command) -{ - if (PlayerInput == nullptr) - { - return FString(); - } - - const FKeyBind* Result = PlayerInput->DebugExecBindings.FindByPredicate([&](const FKeyBind& KeyBind) { return KeyBind.Command == Command; }); - if (Result == nullptr) - { - return FString(); - } - - return KeyBindToString(*Result); -} - -//-------------------------------------------------------------------------------------------------------------------------- -FString FCogImguiInputHelper::KeyBindToString(const FKeyBind& InKeyBind) -{ - FCogImGuiKeyInfo KeyInfo; - KeyBindToKeyInfo(InKeyBind, KeyInfo); - return KeyInfoToString(KeyInfo); -} - -//-------------------------------------------------------------------------------------------------------------------------- -FString FCogImguiInputHelper::KeyInfoToString(const FCogImGuiKeyInfo& InKeyInfo) -{ - if (InKeyInfo == FKey()) + if (InInputChord.Key == FKey()) { return FString(""); } FString Result = "["; - if (InKeyInfo.Alt == ECheckBoxState::Checked) + if (InInputChord.bAlt) { Result += FString("Alt "); } - if (InKeyInfo.Shift == ECheckBoxState::Checked) + if (InInputChord.bShift) { Result += FString("Shift "); } - if (InKeyInfo.Ctrl == ECheckBoxState::Checked) + if (InInputChord.bCtrl) { Result += FString("Ctrl "); } - if (InKeyInfo.Cmd == ECheckBoxState::Checked) + if (InInputChord.bCmd) { Result += FString("Cmd "); } - Result += InKeyInfo.Key.ToString(); + Result += InInputChord.Key.ToString(); Result += FString("]"); return Result; @@ -403,22 +299,6 @@ bool FCogImguiInputHelper::IsKeyEventMatchingKeyBind(const FKeyEvent& KeyEvent, return false; } -//-------------------------------------------------------------------------------------------------------------------------- -bool FCogImguiInputHelper::IsKeyInfoPressed(const UPlayerInput& PlayerInput, const FCogImGuiKeyInfo& InKeyInfo) -{ - const bool bKeyPressed = PlayerInput.WasJustPressed(InKeyInfo.Key); - if (bKeyPressed == false) - { return false; } - - if (IsCheckBoxStateMatchingValue(InKeyInfo.Ctrl, PlayerInput.IsCtrlPressed()) - && IsCheckBoxStateMatchingValue(InKeyInfo.Shift, PlayerInput.IsShiftPressed()) - && IsCheckBoxStateMatchingValue(InKeyInfo.Alt, PlayerInput.IsAltPressed()) - && IsCheckBoxStateMatchingValue(InKeyInfo.Cmd, PlayerInput.IsCmdPressed())) - { return true; } - - return false; -} - //-------------------------------------------------------------------------------------------------------------------------- bool FCogImguiInputHelper::IsKeyBoundToCommand(const UPlayerInput* InPlayerInput, const FKeyEvent& KeyEvent) { @@ -456,11 +336,11 @@ bool FCogImguiInputHelper::DisableCommandsConflictingWithShortcuts(UPlayerInput& { bool HasDisabled = false; - for (const FCogImGuiKeyInfo& Shortcut : CogShortcuts) + for (const FInputChord& Shortcut : CogPrioritizedShortcuts) { for (FKeyBind& KeyBind : PlayerInput.DebugExecBindings) { - if (IsKeyBindMatchingKeyInfo(KeyBind, Shortcut)) + if (IsKeyBindMatchingInputChord(KeyBind, Shortcut)) { KeyBind.bDisabled = true; HasDisabled = false; @@ -476,12 +356,6 @@ bool FCogImguiInputHelper::DisableCommandsConflictingWithShortcuts(UPlayerInput& return false; } -//-------------------------------------------------------------------------------------------------------------------------- -void FCogImguiInputHelper::SetShortcuts(const TArray& InShortcuts) -{ - CogShortcuts = InShortcuts; -} - //-------------------------------------------------------------------------------------------------------------------------- ImGuiKey FCogImguiInputHelper::ToImKey(const FKey& Key) { diff --git a/Plugins/Cog/Source/CogImgui/Public/CogImguiInputHelper.h b/Plugins/Cog/Source/CogImgui/Public/CogImguiInputHelper.h index 5033d58..9fcfa5f 100644 --- a/Plugins/Cog/Source/CogImgui/Public/CogImguiInputHelper.h +++ b/Plugins/Cog/Source/CogImgui/Public/CogImguiInputHelper.h @@ -8,12 +8,30 @@ class APlayerController; class UPlayerInput; class UWorld; enum class ECheckBoxState : uint8; -struct FCogImGuiKeyInfo; -struct FCogImGuiKeyInfo; struct FKey; struct FKeyBind; struct FKeyEvent; +//-------------------------------------------------------------------------------------------------------------------------- +#define BREAK_CHECKBOX_STATE(CheckBoxState, RequireValue, IgnoreValue) \ +{ \ + if (CheckBoxState == ECheckBoxState::Checked) \ + { \ + RequireValue = true; \ + IgnoreValue = false; \ + } \ + else if (CheckBoxState == ECheckBoxState::Unchecked) \ + { \ + RequireValue = false; \ + IgnoreValue = true; \ + } \ + else if (CheckBoxState == ECheckBoxState::Undetermined) \ + { \ + RequireValue = false; \ + IgnoreValue = false; \ + } \ +} \ + class COGIMGUI_API FCogImguiInputHelper { public: @@ -26,25 +44,17 @@ public: static bool IsTopPriorityKeyEvent(const UPlayerInput& PlayerInput, const FKeyEvent& InKeyEvent); - static bool WasKeyInfoJustPressed(const APlayerController& PlayerController, const FCogImGuiKeyInfo& KeyInfo); - static bool IsCheckBoxStateMatchingValue(ECheckBoxState CheckBoxState, bool bValue); static bool IsCheckBoxStateMatchingKeyBindModifier(ECheckBoxState InCheckBoxState, bool InRequireModifier, bool InIgnoreModifier); - static bool IsKeyEventMatchingKeyInfo(const FKeyEvent& InKeyEvent, const FCogImGuiKeyInfo& InKeyInfo); - - static bool IsKeyBindMatchingKeyInfo(const FKeyBind& InKeyBind, const FCogImGuiKeyInfo& InKeyInfo); - static bool IsKeyEventMatchingKeyBind(const FKeyEvent& KeyEvent, const FKeyBind& KeyBind); - static bool IsKeyInfoPressed(const UPlayerInput& PlayerInput, const FCogImGuiKeyInfo& InKeyInfo); - static ECheckBoxState MakeCheckBoxState(uint8 RequireValue, uint8 IgnoreValue); - static void KeyBindToKeyInfo(const FKeyBind& KeyBind, FCogImGuiKeyInfo& KeyInfo); + static bool IsInputChordMatchingKeyInfo(const FKeyEvent& InKeyEvent, const FInputChord& InInputChord); - static void KeyInfoToKeyBind(const FCogImGuiKeyInfo& KeyInfo, FKeyBind& KeyBind); + static bool IsKeyBindMatchingInputChord(const FKeyBind& InKeyBind, const FInputChord& InInputChord); static bool IsConsoleEvent(const FKeyEvent& KeyEvent); @@ -58,19 +68,13 @@ public: static EMouseCursor::Type ToSlateMouseCursor(ImGuiMouseCursor MouseCursor); - static FString CommandToString(const UWorld& World, const FString& Command); - - static FString CommandToString(const UPlayerInput* PlayerInput, const FString& Command); - - static FString KeyBindToString(const FKeyBind& InKeyBind); - - static FString KeyInfoToString(const FCogImGuiKeyInfo& InKeyInfo); + static FString InputChordToString(const FInputChord& InInputChord); static bool IsMouseInsideMainViewport(); static bool IsKeyBoundToCommand(const UPlayerInput* InPlayerInput, const FKeyEvent& KeyEvent); - static void SetShortcuts(const TArray& InShortcuts); + static TArray& GetPrioritizedShortcuts() { return CogPrioritizedShortcuts; } static bool DisableCommandsConflictingWithShortcuts(UPlayerInput& PlayerInput); @@ -81,5 +85,5 @@ public: } private: - static TArray CogShortcuts; + static TArray CogPrioritizedShortcuts; }; diff --git a/Plugins/Cog/Source/CogImgui/Public/CogImguiKeyInfo.h b/Plugins/Cog/Source/CogImgui/Public/CogImguiKeyInfo.h deleted file mode 100644 index 0f41035..0000000 --- a/Plugins/Cog/Source/CogImgui/Public/CogImguiKeyInfo.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "InputCoreTypes.h" -#include "Styling/SlateTypes.h" - -#include "CogImguiKeyInfo.generated.h" - -USTRUCT() -struct COGIMGUI_API FCogImGuiKeyInfo -{ - GENERATED_BODY() - - UPROPERTY(EditAnywhere, Category = "Input") - FKey Key = EKeys::Invalid; - - UPROPERTY(EditAnywhere, Category = "Input") - ECheckBoxState Shift = ECheckBoxState::Undetermined; - - UPROPERTY(EditAnywhere, Category = "Input") - ECheckBoxState Ctrl = ECheckBoxState::Undetermined; - - UPROPERTY(EditAnywhere, Category = "Input") - ECheckBoxState Alt = ECheckBoxState::Undetermined; - - UPROPERTY(EditAnywhere, Category = "Input") - ECheckBoxState Cmd = ECheckBoxState::Undetermined; - - FCogImGuiKeyInfo() - { - } - - FCogImGuiKeyInfo(const FKey InKey, - const ECheckBoxState InShift = ECheckBoxState::Undetermined, - const ECheckBoxState InCtrl = ECheckBoxState::Undetermined, - const ECheckBoxState InAlt = ECheckBoxState::Undetermined, - const ECheckBoxState InCmd = ECheckBoxState::Undetermined) - : Key(InKey) - , Shift(InShift) - , Ctrl(InCtrl) - , Alt(InAlt) - , Cmd(InCmd) - { - } - - friend bool operator==(const FCogImGuiKeyInfo& Lhs, const FCogImGuiKeyInfo& Rhs) - { - return Lhs.Key == Rhs.Key - && Lhs.Shift == Rhs.Shift - && Lhs.Ctrl == Rhs.Ctrl - && Lhs.Alt == Rhs.Alt - && Lhs.Cmd == Rhs.Cmd; - } - - friend bool operator!=(const FCogImGuiKeyInfo& Lhs, const FCogImGuiKeyInfo& Rhs) - { - return !(Lhs == Rhs); - } -}; \ No newline at end of file diff --git a/Plugins/Cog/Source/CogImgui/Public/CogImguiWidget.h b/Plugins/Cog/Source/CogImgui/Public/CogImguiWidget.h index cbca3bb..a67a9ef 100644 --- a/Plugins/Cog/Source/CogImgui/Public/CogImguiWidget.h +++ b/Plugins/Cog/Source/CogImgui/Public/CogImguiWidget.h @@ -59,7 +59,7 @@ public: TSharedPtr GetWindow() const { return Window; } void SetWindow(const TSharedPtr& Value) { Window = Value; } - + protected: FReply HandleKeyEvent(const FKeyEvent& KeyEvent, bool Down) const; diff --git a/Plugins/CogAbility/Source/CogAbility/Public/CogAbilitySubsystem.h b/Plugins/CogAbility/Source/CogAbility/Public/CogAbilitySubsystem.h new file mode 100644 index 0000000..f047604 --- /dev/null +++ b/Plugins/CogAbility/Source/CogAbility/Public/CogAbilitySubsystem.h @@ -0,0 +1,22 @@ +#pragma once + +#include "CoreMinimal.h" +#include "CogAbilityReplicator.h" +#include "CogDebugPluginSubsystem.h" +#include "CogAbilitySubsystem.generated.h" + +UCLASS() +class COGABILITY_API UCogAbilitySubsystem : public UCogDebugPluginSubsystem +{ + GENERATED_BODY() + +public: + + virtual void OnPlayerControllerReady(APlayerController* InController) override + { + if (InController != nullptr) + { + ACogAbilityReplicator::Spawn(InController); + } + } +}; diff --git a/Plugins/CogInput/Source/CogInput/Private/CogInputWindow_Gamepad.cpp b/Plugins/CogInput/Source/CogInput/Private/CogInputWindow_Gamepad.cpp index 628ce41..1ebf463 100644 --- a/Plugins/CogInput/Source/CogInput/Private/CogInputWindow_Gamepad.cpp +++ b/Plugins/CogInput/Source/CogInput/Private/CogInputWindow_Gamepad.cpp @@ -372,7 +372,7 @@ void FCogInputWindow_Gamepad::RenderContent() const ImVec2 ContentMin = ImGui::GetCursorScreenPos(); const ImVec2 ContentSize = ImGui::GetContentRegionAvail(); const ImVec2 ContentMax = ContentMin + ContentSize; - const ImVec2 OverlayOffset = ImVec2(0.0f, Config->bShowAsOverlay ? ImGui::GetFrameHeight() : 0.0f); + const ImVec2 OverlayOffset = ImVec2(0.0f, Config->bShowAsOverlay && IsWindowRenderedInMainMenu() == false ? ImGui::GetFrameHeight() : 0.0f); const ImVec2 Padding = ImVec2(Config->Border * 0.5f * ContentSize.x, Config->Border * 0.5f * ContentSize.x); CanvasMin = ContentMin + OverlayOffset + Padding;