diff --git a/Cog.uproject b/Cog.uproject index b370cd6..6ea1ace 100644 --- a/Cog.uproject +++ b/Cog.uproject @@ -1,6 +1,6 @@ { "FileVersion": 3, - "EngineAssociation": "5.3", + "EngineAssociation": "5.5", "Category": "", "Description": "", "Modules": [ diff --git a/Plugins/Cog/Source/CogDebug/Private/CogDebug.cpp b/Plugins/Cog/Source/CogDebug/Private/CogDebug.cpp index f64dfd3..97696bf 100644 --- a/Plugins/Cog/Source/CogDebug/Private/CogDebug.cpp +++ b/Plugins/Cog/Source/CogDebug/Private/CogDebug.cpp @@ -3,13 +3,14 @@ #include "CogCommonDebugFilteredActorInterface.h" #include "CogDebugDrawHelper.h" #include "CogDebugReplicator.h" -#include "imgui.h" -#include "Engine/World.h" #include "Engine/Engine.h" +#include "Engine/World.h" +#include "imgui.h" #include "Kismet/KismetMathLibrary.h" +#include "Misc/EngineVersionComparison.h" //-------------------------------------------------------------------------------------------------------------------------- -TWeakObjectPtr FCogDebug::Selection; +TWeakObjectPtr FCogDebug::Selection[] = {}; FCogDebugSettings FCogDebug::Settings = FCogDebugSettings(); //-------------------------------------------------------------------------------------------------------------------------- @@ -32,7 +33,7 @@ bool FCogDebug::IsDebugActiveForObject(const UObject* WorldContextObject) return true; } - const bool Result = IsDebugActiveForObject_Internal(WorldContextObject, Selection.Get(), Settings.bIsFilteringBySelection); + const bool Result = IsDebugActiveForObject_Internal(WorldContextObject, Selection[GetPieSessionId()].Get(), Settings.bIsFilteringBySelection); return Result; } @@ -83,20 +84,32 @@ bool FCogDebug::IsDebugActiveForObject_Internal(const UObject* WorldContextObjec Outer = NewOuter; } - - return true; } //-------------------------------------------------------------------------------------------------------------------------- AActor* FCogDebug::GetSelection() { - return Selection.Get(); + return Selection[GetPieSessionId()].Get(); +} + +//-------------------------------------------------------------------------------------------------------------------------- +int32 FCogDebug::GetPieSessionId() +{ +#if UE_EDITOR +#if UE_VERSION_OLDER_THAN(5, 5, 0) + return GPlayInEditorID; +#else + return UE::GetPlayInEditorID(); +#endif +#else + return 0; +#endif } //-------------------------------------------------------------------------------------------------------------------------- void FCogDebug::SetSelection(const UWorld* World, AActor* Value) { - Selection = Value; + Selection[GetPieSessionId()] = Value; if (World != nullptr && World->GetNetMode() == NM_Client) { diff --git a/Plugins/Cog/Source/CogDebug/Private/CogDebugDrawHelper.cpp b/Plugins/Cog/Source/CogDebug/Private/CogDebugDrawHelper.cpp index 2661cdf..42f908c 100644 --- a/Plugins/Cog/Source/CogDebug/Private/CogDebugDrawHelper.cpp +++ b/Plugins/Cog/Source/CogDebug/Private/CogDebugDrawHelper.cpp @@ -2,9 +2,10 @@ #include "CogDebug.h" #include "Components/LineBatchComponent.h" -#include "Engine/Engine.h" -#include "DrawDebugHelpers.h" #include "Components/BoxComponent.h" +#include "DrawDebugHelpers.h" +#include "Engine/Engine.h" +#include "Engine/OverlapResult.h" namespace { diff --git a/Plugins/Cog/Source/CogDebug/Private/CogDebugLog.cpp b/Plugins/Cog/Source/CogDebug/Private/CogDebugLog.cpp index 6694218..8e2f424 100644 --- a/Plugins/Cog/Source/CogDebug/Private/CogDebugLog.cpp +++ b/Plugins/Cog/Source/CogDebug/Private/CogDebugLog.cpp @@ -130,10 +130,6 @@ FLogCategoryBase* FCogDebugLog::FindLogCategory(const FName CategoryName) { return LogCategoryInfo->LogCategory; } - else - { - return nullptr; - } return nullptr; } diff --git a/Plugins/Cog/Source/CogDebug/Public/CogDebug.h b/Plugins/Cog/Source/CogDebug/Public/CogDebug.h index b6e95b2..fb0519f 100644 --- a/Plugins/Cog/Source/CogDebug/Public/CogDebug.h +++ b/Plugins/Cog/Source/CogDebug/Public/CogDebug.h @@ -427,7 +427,11 @@ public: private: + static int32 GetPieSessionId(); + + static constexpr uint32 MaxPie = 16; + static bool IsDebugActiveForObject_Internal(const UObject* WorldContextObject, const AActor* InSelection, bool InIsFilteringBySelection); - static TWeakObjectPtr Selection; + static TWeakObjectPtr Selection[MaxPie]; }; diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineCollisionTester.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineCollisionTester.cpp index 98ce72e..c81c475 100644 --- a/Plugins/Cog/Source/CogEngine/Private/CogEngineCollisionTester.cpp +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineCollisionTester.cpp @@ -5,6 +5,7 @@ #include "Components/PrimitiveComponent.h" #include "Components/SceneComponent.h" #include "Engine/World.h" +#include "Engine/OverlapResult.h" //-------------------------------------------------------------------------------------------------------------------------- ACogEngineCollisionTester::ACogEngineCollisionTester(const FObjectInitializer& ObjectInitializer) diff --git a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Selection.cpp b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Selection.cpp index dbe97d1..7d70773 100644 --- a/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Selection.cpp +++ b/Plugins/Cog/Source/CogEngine/Private/CogEngineWindow_Selection.cpp @@ -5,6 +5,7 @@ #include "CogEngineWindow_ImGui.h" #include "CogImguiHelper.h" #include "CogImguiInputHelper.h" +#include "CogWindowConsoleCommandManager.h" #include "CogWindowManager.h" #include "CogWindowWidgets.h" #include "Components/PrimitiveComponent.h" @@ -27,11 +28,14 @@ void FCogEngineWindow_Selection::Initialize() Config = GetConfig(); - ConsoleCommands.Add(IConsoleManager::Get().RegisterConsoleCommand( + FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand( *ToggleSelectionModeCommand, TEXT("Toggle the actor selection mode"), - FConsoleCommandWithArgsDelegate::CreateLambda([this](const TArray& Args) { ToggleSelectionMode(); }), - ECVF_Cheat)); + GetWorld(), + FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray& InArgs, UWorld* InWorld) + { + ToggleSelectionMode(); + })); TryReapplySelection(); } @@ -50,10 +54,6 @@ void FCogEngineWindow_Selection::RenderHelp() //-------------------------------------------------------------------------------------------------------------------------- void FCogEngineWindow_Selection::Shutdown() { - for (IConsoleObject* ConsoleCommand : ConsoleCommands) - { - IConsoleManager::Get().UnregisterConsoleObject(ConsoleCommand); - } } //-------------------------------------------------------------------------------------------------------------------------- diff --git a/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Selection.h b/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Selection.h index 2235a5b..817efd4 100644 --- a/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Selection.h +++ b/Plugins/Cog/Source/CogEngine/Public/CogEngineWindow_Selection.h @@ -83,8 +83,6 @@ protected: ETraceTypeQuery TraceType = TraceTypeQuery1; - TArray ConsoleCommands; - TObjectPtr Config; ImGuiTextFilter Filter; diff --git a/Plugins/Cog/Source/CogImgui/Private/CogImguiContext.cpp b/Plugins/Cog/Source/CogImgui/Private/CogImguiContext.cpp index 5c8be05..5246c61 100644 --- a/Plugins/Cog/Source/CogImgui/Private/CogImguiContext.cpp +++ b/Plugins/Cog/Source/CogImgui/Private/CogImguiContext.cpp @@ -17,12 +17,41 @@ #include "imgui.h" #include "imgui_internal.h" #include "implot.h" +#include "Misc/EngineVersionComparison.h" #include "TextureResource.h" #include "Widgets/SViewport.h" #include "Widgets/SWindow.h" static UPlayerInput* GetPlayerInput(const UWorld* World); +FCogImGuiContextScope:: +FCogImGuiContextScope(FCogImguiContext& CogImguiContext) +{ + PrevContext = ImGui::GetCurrentContext(); + PrevPlotContext = ImPlot::GetCurrentContext(); + + ImGui::SetCurrentContext(CogImguiContext.ImGuiContext); + ImPlot::SetCurrentContext(CogImguiContext.PlotContext); +} + +FCogImGuiContextScope:: +FCogImGuiContextScope(ImGuiContext* GuiCtx, ImPlotContext* PlotCtx) +{ + PrevContext = ImGui::GetCurrentContext(); + PrevPlotContext = ImPlot::GetCurrentContext(); + + ImGui::SetCurrentContext(GuiCtx); + ImPlot::SetCurrentContext(PlotCtx); +} + +FCogImGuiContextScope:: +~FCogImGuiContextScope() +{ + ImGui::SetCurrentContext(PrevContext); + ImPlot::SetCurrentContext(PrevPlotContext); +} + + //-------------------------------------------------------------------------------------------------------------------------- void FCogImguiContext::Initialize() { @@ -45,7 +74,9 @@ void FCogImguiContext::Initialize() ImGuiContext = ImGui::CreateContext(); PlotContext = ImPlot::CreateContext(); + ImGui::SetCurrentContext(ImGuiContext); ImPlot::SetImGuiContext(ImGuiContext); + ImPlot::SetCurrentContext(PlotContext); ImGuiIO& IO = ImGui::GetIO(); IO.UserData = this; @@ -105,6 +136,13 @@ void FCogImguiContext::Initialize() //-------------------------------------------------------------------------------------------------------------------------- void FCogImguiContext::Shutdown() { + if (FSlateApplication::IsInitialized() == false) + { + return; + } + + FCogImGuiContextScope ImGuiContextScope(ImGuiContext, PlotContext); + ImGuiViewport* MainViewport = ImGui::GetMainViewport(); if (const FCogImGuiViewportData* ViewportData = static_cast(MainViewport->PlatformUserData)) { @@ -122,6 +160,7 @@ void FCogImguiContext::Shutdown() } GameViewport->RemoveViewportWidgetContent(MainWidget.ToSharedRef()); + GameViewport->RemoveViewportWidgetContent(InputCatcherWidget.ToSharedRef()); if (PlotContext) { @@ -139,6 +178,8 @@ void FCogImguiContext::Shutdown() //-------------------------------------------------------------------------------------------------------------------------- void FCogImguiContext::OnDisplayMetricsChanged(const FDisplayMetrics& DisplayMetrics) const { + FCogImGuiContextScope ImGuiContextScope(ImGuiContext, PlotContext); + ImGuiPlatformIO& PlatformIO = ImGui::GetPlatformIO(); PlatformIO.Monitors.resize(0); @@ -165,6 +206,8 @@ void FCogImguiContext::OnDisplayMetricsChanged(const FDisplayMetrics& DisplayMet //-------------------------------------------------------------------------------------------------------------------------- bool FCogImguiContext::BeginFrame(float InDeltaTime) { + FCogImGuiContextScope ImGuiContextScope(ImGuiContext, PlotContext); + //------------------------------------------------------------------------------------------------------- // Skip the first frame, to let the main widget update its TickSpaceGeometry which is returned by the // plateform callback ImGui_GetWindowPos. When using viewports Imgui needs to know the main viewport @@ -176,10 +219,6 @@ bool FCogImguiContext::BeginFrame(float InDeltaTime) return false; } - ImGui::SetCurrentContext(ImGuiContext); - ImPlot::SetImGuiContext(ImGuiContext); - ImPlot::SetCurrentContext(PlotContext); - ImGuiIO& IO = ImGui::GetIO(); IO.DeltaTime = InDeltaTime; IO.DisplaySize = FCogImguiHelper::ToImVec2(MainWidget->GetTickSpaceGeometry().GetAbsoluteSize()); @@ -287,6 +326,8 @@ bool FCogImguiContext::BeginFrame(float InDeltaTime) //-------------------------------------------------------------------------------------------------------------------------- void FCogImguiContext::EndFrame() { + FCogImGuiContextScope ImGuiContextScope(ImGuiContext, PlotContext); + ImGui::Render(); ImGui_RenderWindow(ImGui::GetMainViewport(), nullptr); @@ -686,6 +727,8 @@ void FCogImguiContext::SetDPIScale(float Value) //-------------------------------------------------------------------------------------------------------------------------- void FCogImguiContext::BuildFont() { + FCogImGuiContextScope ImGuiContextScope(ImGuiContext, PlotContext); + if (FontAtlasTexture != nullptr) { FontAtlasTexture->RemoveFromRoot(); @@ -703,7 +746,15 @@ void FCogImguiContext::BuildFont() int32 TextureWidth, TextureHeight, BytesPerPixel; IO.Fonts->GetTexDataAsRGBA32(&TextureDataRaw, &TextureWidth, &TextureHeight, &BytesPerPixel); - FontAtlasTexture = UTexture2D::CreateTransient(TextureWidth, TextureHeight, PF_R8G8B8A8, TEXT("ImGuiFontAtlas")); +#if UE_VERSION_OLDER_THAN(5, 5, 0) + const int32 PieSessionId = GPlayInEditorID; +#else + const int32 PieSessionId = UE::GetPlayInEditorID(); +#endif + + FString TextureName = FString::Format(TEXT("ImGuiFontAtlas{0}"), { PieSessionId }); + + FontAtlasTexture = UTexture2D::CreateTransient(TextureWidth, TextureHeight, PF_R8G8B8A8, *TextureName); FontAtlasTexture->Filter = TF_Bilinear; FontAtlasTexture->AddressX = TA_Wrap; FontAtlasTexture->AddressY = TA_Wrap; diff --git a/Plugins/Cog/Source/CogImgui/Private/CogImguiInputCatcherWidget.cpp b/Plugins/Cog/Source/CogImgui/Private/CogImguiInputCatcherWidget.cpp index b3bf534..ec99bca 100644 --- a/Plugins/Cog/Source/CogImgui/Private/CogImguiInputCatcherWidget.cpp +++ b/Plugins/Cog/Source/CogImgui/Private/CogImguiInputCatcherWidget.cpp @@ -93,6 +93,8 @@ FReply SCogImguiInputCatcherWidget::OnMouseButtonUp(const FGeometry& MyGeometry, //-------------------------------------------------------------------------------------------------------------------------- FReply SCogImguiInputCatcherWidget::HandleMouseButtonEvent(const FPointerEvent& MouseEvent, bool Down) { + FCogImGuiContextScope ImGuiContextScope(*Context); + if (Context->GetEnableInput() == false) { UE_LOG(LogCogImGui, VeryVerbose, TEXT("SCogImguiInputCatcherWidget::HandleMouseButtonEvent | Window:%s | Unhandled | EnableInput == false | Down:%d"), Window.IsValid() ? *Window->GetTitle().ToString() : *FString("None"), Down); @@ -110,6 +112,8 @@ FReply SCogImguiInputCatcherWidget::HandleMouseButtonEvent(const FPointerEvent& //-------------------------------------------------------------------------------------------------------------------------- FReply SCogImguiInputCatcherWidget::OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { + FCogImGuiContextScope ImGuiContextScope(*Context); + if (Context->GetEnableInput() == false) { return FReply::Unhandled(); diff --git a/Plugins/Cog/Source/CogImgui/Private/CogImguiModule.cpp b/Plugins/Cog/Source/CogImgui/Private/CogImguiModule.cpp index adf113f..8caa5dd 100644 --- a/Plugins/Cog/Source/CogImgui/Private/CogImguiModule.cpp +++ b/Plugins/Cog/Source/CogImgui/Private/CogImguiModule.cpp @@ -33,4 +33,4 @@ void FCogImguiModule::ShutdownModule() //-------------------------------------------------------------------------------------------------------------------------- #undef LOCTEXT_NAMESPACE -IMPLEMENT_MODULE(FCogImguiModule, CogImGui) \ No newline at end of file +IMPLEMENT_MODULE(FCogImguiModule, CogImgui) \ No newline at end of file diff --git a/Plugins/Cog/Source/CogImgui/Private/CogImguiWidget.cpp b/Plugins/Cog/Source/CogImgui/Private/CogImguiWidget.cpp index dd736e4..e1b24ef 100644 --- a/Plugins/Cog/Source/CogImgui/Private/CogImguiWidget.cpp +++ b/Plugins/Cog/Source/CogImgui/Private/CogImguiWidget.cpp @@ -112,6 +112,8 @@ FVector2D SCogImguiWidget::ComputeDesiredSize(float Scale) const //-------------------------------------------------------------------------------------------------------------------------- FReply SCogImguiWidget::OnKeyChar(const FGeometry& MyGeometry, const FCharacterEvent& CharacterEvent) { + FCogImGuiContextScope ImGuiContextScope(*Context); + ImGuiIO& IO = ImGui::GetIO(); IO.AddInputCharacter(FCogImguiInputHelper::CastInputChar(CharacterEvent.GetCharacter())); @@ -134,6 +136,8 @@ FReply SCogImguiWidget::OnKeyUp(const FGeometry& MyGeometry, const FKeyEvent& Ke //-------------------------------------------------------------------------------------------------------------------------- FReply SCogImguiWidget::HandleKeyEvent(const FKeyEvent& KeyEvent, bool Down) { + FCogImGuiContextScope ImGuiContextScope(*Context); + if (Context->GetEnableInput() == false) { return FReply::Unhandled(); @@ -196,6 +200,8 @@ FReply SCogImguiWidget::OnMouseButtonUp(const FGeometry& MyGeometry, const FPoin //-------------------------------------------------------------------------------------------------------------------------- FReply SCogImguiWidget::HandleMouseButtonEvent(const FPointerEvent& MouseEvent, bool Down) { + FCogImGuiContextScope ImGuiContextScope(*Context); + if (Context->GetEnableInput() == false) { UE_LOG(LogCogImGui, VeryVerbose, TEXT("SCogImguiWidget::HandleMouseButtonEvent | %s | Unhandled | EnableInput == false | Down:%d"), Window.IsValid() ? *Window->GetTitle().ToString() : *FString("None"), Down); @@ -212,6 +218,8 @@ FReply SCogImguiWidget::HandleMouseButtonEvent(const FPointerEvent& MouseEvent, //-------------------------------------------------------------------------------------------------------------------------- FReply SCogImguiWidget::OnMouseWheel(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { + FCogImGuiContextScope ImGuiContextScope(*Context); + if (Context->GetEnableInput() == false) { return FReply::Unhandled(); @@ -224,6 +232,8 @@ FReply SCogImguiWidget::OnMouseWheel(const FGeometry& MyGeometry, const FPointer //-------------------------------------------------------------------------------------------------------------------------- FReply SCogImguiWidget::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) { + FCogImGuiContextScope ImGuiContextScope(*Context); + if (Context->GetEnableInput() == false) { //UE_LOG(LogCogImGui, VeryVerbose, TEXT("SCogImguiWidget::OnMouseMove | Window:%s | Unhandled | EnableInput == false"), Window.IsValid() ? *Window->GetTitle().ToString() : *FString("None")); diff --git a/Plugins/Cog/Source/CogImgui/Public/CogImguiContext.h b/Plugins/Cog/Source/CogImgui/Public/CogImguiContext.h index c8d7b85..a9bef0e 100644 --- a/Plugins/Cog/Source/CogImgui/Public/CogImguiContext.h +++ b/Plugins/Cog/Source/CogImgui/Public/CogImguiContext.h @@ -25,6 +25,18 @@ struct COGIMGUI_API FCogImGuiViewportData TWeakPtr Widget = nullptr; }; + +struct COGIMGUI_API FCogImGuiContextScope +{ + UE_NODISCARD_CTOR explicit FCogImGuiContextScope(FCogImguiContext& CogImguiContext); + UE_NODISCARD_CTOR explicit FCogImGuiContextScope(ImGuiContext* GuiCtx, ImPlotContext* PlotCtx); + ~FCogImGuiContextScope(); + +private: + ImGuiContext* PrevContext = nullptr; + ImPlotContext* PrevPlotContext = nullptr; +}; + class COGIMGUI_API FCogImguiContext : public TSharedFromThis { public: @@ -65,6 +77,8 @@ public: private: + friend struct FCogImGuiContextScope; + void OnDisplayMetricsChanged(const FDisplayMetrics& DisplayMetrics) const; bool IsConsoleOpened() const; diff --git a/Plugins/Cog/Source/CogWindow/Private/CogWindowConsoleCommandManager.cpp b/Plugins/Cog/Source/CogWindow/Private/CogWindowConsoleCommandManager.cpp new file mode 100644 index 0000000..0db517a --- /dev/null +++ b/Plugins/Cog/Source/CogWindow/Private/CogWindowConsoleCommandManager.cpp @@ -0,0 +1,66 @@ +#include "CogWindowConsoleCommandManager.h" + +#include "Engine/World.h" + +TMap FCogWindowConsoleCommandManager::CommandMap; + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand(const TCHAR* InName, const TCHAR* InHelp, UWorld* InWorld, const FCogWindowConsoleCommandDelegate& InDelegate) +{ + FCogCommandInfo& commandInfo = CommandMap.FindOrAdd(InName); + + if (commandInfo.Receivers.Num() == 0) + { + commandInfo.ConsoleObject = IConsoleManager::Get().RegisterConsoleCommand + ( + InName, + InHelp, + FConsoleCommandWithWorldAndArgsDelegate::CreateLambda( + [InName](const TArray& Args, UWorld* InCommandWorld) + { + FCogCommandInfo* commandInfo = CommandMap.Find(InName); + if (commandInfo == nullptr) + { + return; + } + + for (auto& receiver : commandInfo->Receivers) + { + if (receiver.World == InCommandWorld) + { + receiver.Delegate.ExecuteIfBound(Args, InCommandWorld); + break; + } + } + }), + ECVF_Cheat + ); + } + + FCogCommandReceiver& receiver = commandInfo.Receivers.AddDefaulted_GetRef(); + receiver.World = InWorld; + receiver.Delegate = InDelegate; +} + +//-------------------------------------------------------------------------------------------------------------------------- +void FCogWindowConsoleCommandManager::UnregisterAllWorldConsoleCommands(const UWorld* InWorld) +{ + for (auto& kv : CommandMap) + { + FCogCommandInfo& commandInfo = kv.Value; + + for (int32 i = commandInfo.Receivers.Num() - 1; i >= 0; --i) + { + if (commandInfo.Receivers[i].World == InWorld) + { + commandInfo.Receivers.RemoveAt(i); + } + } + + if (commandInfo.Receivers.Num() == 0 && commandInfo.ConsoleObject != nullptr) + { + IConsoleManager::Get().UnregisterConsoleObject(commandInfo.ConsoleObject); + commandInfo.ConsoleObject = nullptr; + } + } +} \ No newline at end of file diff --git a/Plugins/Cog/Source/CogWindow/Private/CogWindowManager.cpp b/Plugins/Cog/Source/CogWindow/Private/CogWindowManager.cpp index d4f8ecd..237a706 100644 --- a/Plugins/Cog/Source/CogWindow/Private/CogWindowManager.cpp +++ b/Plugins/Cog/Source/CogWindow/Private/CogWindowManager.cpp @@ -3,6 +3,7 @@ #include "CogDebugDrawImGui.h" #include "CogImguiHelper.h" #include "CogImguiInputHelper.h" +#include "CogWindowConsoleCommandManager.h" #include "CogWindow_Layouts.h" #include "CogWindow_Settings.h" #include "CogWindow_Spacing.h" @@ -12,8 +13,10 @@ #include "GameFramework/PlayerInput.h" #include "HAL/IConsoleManager.h" #include "imgui_internal.h" +#include "Misc/EngineVersionComparison.h" FString UCogWindowManager::ToggleInputCommand = TEXT("Cog.ToggleInput"); +FString UCogWindowManager::DisableInputCommand = TEXT("Cog.DisableInput"); FString UCogWindowManager::LoadLayoutCommand = TEXT("Cog.LoadLayout"); FString UCogWindowManager::SaveLayoutCommand = TEXT("Cog.SaveLayout"); FString UCogWindowManager::ResetLayoutCommand = TEXT("Cog.ResetLayout"); @@ -28,13 +31,21 @@ void UCogWindowManager::PostInitProperties() { Super::PostInitProperties(); - if (bRegisterDefaultCommands) - { - if (RegisterDefaultCommandBindings()) - { - bRegisterDefaultCommands = false; - } - } + //if (bRegisterDefaultCommands) + //{ + // if (RegisterDefaultCommandBindings()) + // { + // bRegisterDefaultCommands = false; + // } + //} + + //------------------------------------------------------------------------------- + // Currently always register default commands. + // Since UE5.4, the ini files must have this to be saved: + // [SectionsToSave] + // bCanSaveAllSections = True + //------------------------------------------------------------------------------- + RegisterDefaultCommandBindings(); } //-------------------------------------------------------------------------------------------------------------------------- @@ -42,6 +53,8 @@ void UCogWindowManager::InitializeInternal() { Context.Initialize(); + FCogImGuiContextScope ImGuiContextScope(Context); + ImGuiSettingsHandler IniHandler; IniHandler.TypeName = "Cog"; IniHandler.TypeHash = ImHashStr("Cog"); @@ -61,29 +74,59 @@ void UCogWindowManager::InitializeInternal() LayoutsWindow = AddWindow("Window.Layouts", false); SettingsWindow = AddWindow("Window.Settings", false); - ConsoleCommands.Add(IConsoleManager::Get().RegisterConsoleCommand( - *ToggleInputCommand, + FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand( + *ToggleInputCommand, TEXT("Toggle the input focus between the Game and ImGui"), - FConsoleCommandWithArgsDelegate::CreateLambda([this](const TArray& Args) { ToggleInputMode(); }), - ECVF_Cheat)); + GetWorld(), + FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray& InArgs, UWorld* InWorld) + { + ToggleInputMode(); + })); - ConsoleCommands.Add(IConsoleManager::Get().RegisterConsoleCommand( + FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand( + *DisableInputCommand, + TEXT("Disable ImGui input"), + GetWorld(), + FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray& InArgs, UWorld* InWorld) + { + DisableInputMode(); + })); + + FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand( *ResetLayoutCommand, TEXT("Reset the layout."), - FConsoleCommandWithArgsDelegate::CreateLambda([this](const TArray& Args) { if (Args.Num() > 0) { ResetLayout(); }}), - ECVF_Cheat)); + GetWorld(), + FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray& InArgs, UWorld* InWorld) + { + if (InArgs.Num() > 0) + { + ResetLayout(); + } + })); - ConsoleCommands.Add(IConsoleManager::Get().RegisterConsoleCommand( + FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand( *LoadLayoutCommand, TEXT("Load the layout. Cog.LoadLayout "), - FConsoleCommandWithArgsDelegate::CreateLambda([this](const TArray& Args) { if (Args.Num() > 0) { LoadLayout(FCString::Atoi(*Args[0])); }}), - ECVF_Cheat)); + GetWorld(), + FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray& InArgs, UWorld* InWorld) + { + if (InArgs.Num() > 0) + { + LoadLayout(FCString::Atoi(*InArgs[0])); + } + })); - ConsoleCommands.Add(IConsoleManager::Get().RegisterConsoleCommand( - *SaveLayoutCommand, + FCogWindowConsoleCommandManager::RegisterWorldConsoleCommand( + *SaveLayoutCommand, TEXT("Save the layout. Cog.SaveLayout "), - FConsoleCommandWithArgsDelegate::CreateLambda([this](const TArray& Args) { if (Args.Num() > 0) { SaveLayout(FCString::Atoi(*Args[0])); }}), - ECVF_Cheat)); + GetWorld(), + FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray& InArgs, UWorld* InWorld) + { + if (InArgs.Num() > 0) + { + SaveLayout(FCString::Atoi(*InArgs[0])); + } + })); IsInitialized = true; } @@ -91,6 +134,8 @@ void UCogWindowManager::InitializeInternal() //-------------------------------------------------------------------------------------------------------------------------- void UCogWindowManager::Shutdown() { + FCogImGuiContextScope ImGuiContextScope(Context); + //------------------------------------------------------------ // Call PreSaveConfig before destroying imgui context // if PreSaveConfig needs to read ImGui IO for example @@ -104,7 +149,10 @@ void UCogWindowManager::Shutdown() // Destroy ImGui before destroying the windows to make sure // imgui serialize their visibility state in imgui.ini //------------------------------------------------------------ - Context.Shutdown(); + if (IsInitialized == true) + { + Context.Shutdown(); + } SaveConfig(); @@ -120,15 +168,14 @@ void UCogWindowManager::Shutdown() Config->SaveConfig(); } - for (IConsoleObject* ConsoleCommand : ConsoleCommands) - { - IConsoleManager::Get().UnregisterConsoleObject(ConsoleCommand); - } + FCogWindowConsoleCommandManager::UnregisterAllWorldConsoleCommands(GetWorld()); } //-------------------------------------------------------------------------------------------------------------------------- void UCogWindowManager::Tick(float DeltaTime) { + FCogImGuiContextScope ImGuiContextScope(Context); + if (GEngine->GameViewport == nullptr) { return; @@ -161,6 +208,8 @@ void UCogWindowManager::Tick(float DeltaTime) //-------------------------------------------------------------------------------------------------------------------------- void UCogWindowManager::Render(float DeltaTime) { + FCogImGuiContextScope ImGuiContextScope(Context); + ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0)); ImGui::DockSpaceOverViewport(0, ImGuiDockNodeFlags_PassthruCentralNode | ImGuiDockNodeFlags_NoDockingInCentralNode | ImGuiDockNodeFlags_AutoHideTabBar); ImGui::PopStyleColor(1); @@ -249,6 +298,8 @@ void UCogWindowManager::SetHideAllWindows(const bool Value) //-------------------------------------------------------------------------------------------------------------------------- void UCogWindowManager::ResetLayout() { + FCogImGuiContextScope ImGuiContextScope(Context); + for (const FCogWindow* Window : Windows) { ImGui::SetWindowPos(TCHAR_TO_ANSI(*Window->GetName()), ImVec2(10, 10), ImGuiCond_Always); @@ -280,6 +331,8 @@ void UCogWindowManager::LoadLayout(const int32 LayoutIndex) //-------------------------------------------------------------------------------------------------------------------------- void UCogWindowManager::SaveLayout(const int32 LayoutIndex) { + FCogImGuiContextScope ImGuiContextScope(Context); + const FString Filename = *FCogImguiHelper::GetIniFilePath(FString::Printf(TEXT("imgui_layout_%d"), LayoutIndex)); ImGui::SaveIniSettingsToDisk(TCHAR_TO_ANSI(*Filename)); } @@ -681,6 +734,10 @@ bool UCogWindowManager::RegisterDefaultCommandBindings() } UPlayerInput* PlayerInput = FCogImguiInputHelper::GetPlayerInput(*GetWorld()); + if (PlayerInput == nullptr) + { + return false; + } AddCommand(PlayerInput, "Cog.ToggleInput", EKeys::F1); AddCommand(PlayerInput, "Cog.LoadLayout 1", EKeys::F2); @@ -690,13 +747,17 @@ bool UCogWindowManager::RegisterDefaultCommandBindings() SortCommands(PlayerInput); PlayerInput->SaveConfig(); - return true; } //-------------------------------------------------------------------------------------------------------------------------- void UCogWindowManager::AddCommand(UPlayerInput* PlayerInput, const FString& Command, const FKey& Key) { + if (PlayerInput == nullptr) + { + return; + } + //--------------------------------------------------- // Reassign conflicting commands //--------------------------------------------------- @@ -788,3 +849,10 @@ void UCogWindowManager::ToggleInputMode() Context.SetEnableInput(!Context.GetEnableInput()); } +//-------------------------------------------------------------------------------------------------------------------------- +void UCogWindowManager::DisableInputMode() +{ + UE_LOG(LogCogImGui, Verbose, TEXT("UCogWindowManager::DisableInputMode")); + Context.SetEnableInput(false); +} + diff --git a/Plugins/Cog/Source/CogWindow/Public/CogWindowConsoleCommandManager.h b/Plugins/Cog/Source/CogWindow/Public/CogWindowConsoleCommandManager.h new file mode 100644 index 0000000..c15a759 --- /dev/null +++ b/Plugins/Cog/Source/CogWindow/Public/CogWindowConsoleCommandManager.h @@ -0,0 +1,39 @@ +#pragma once + +#include "CoreMinimal.h" +#include "HAL/IConsoleManager.h" +#include "Templates/Function.h" + +class UWorld; + +DECLARE_DELEGATE_TwoParams(FCogWindowConsoleCommandDelegate, const TArray&, UWorld*); + +//-------------------------------------------------------------------------------------------------------------------------- +struct FCogCommandReceiver +{ + UWorld* World = nullptr; + + FCogWindowConsoleCommandDelegate Delegate; +}; + +//-------------------------------------------------------------------------------------------------------------------------- +struct FCogCommandInfo +{ + IConsoleObject* ConsoleObject = nullptr; + + TArray Receivers; +}; + +//-------------------------------------------------------------------------------------------------------------------------- +struct COGWINDOW_API FCogWindowConsoleCommandManager +{ +public: + + static void RegisterWorldConsoleCommand(const TCHAR* InName, const TCHAR* InHelp, UWorld* InWorld, const FCogWindowConsoleCommandDelegate& InDelegate); + + static void UnregisterAllWorldConsoleCommands(const UWorld* InWorld); + +protected: + + static TMap CommandMap; +}; diff --git a/Plugins/Cog/Source/CogWindow/Public/CogWindowManager.h b/Plugins/Cog/Source/CogWindow/Public/CogWindowManager.h index 3f120d6..ae12a92 100644 --- a/Plugins/Cog/Source/CogWindow/Public/CogWindowManager.h +++ b/Plugins/Cog/Source/CogWindow/Public/CogWindowManager.h @@ -101,10 +101,12 @@ protected: virtual void RenderMenuItem(FCogWindow& Window, const char* MenuItemName); - void RenderMenuItemHelp(FCogWindow& Window); + virtual void RenderMenuItemHelp(FCogWindow& Window); virtual void ToggleInputMode(); + virtual void DisableInputMode(); + static void SettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*); static void SettingsHandler_ApplyAll(ImGuiContext* ctx, ImGuiSettingsHandler*); @@ -116,6 +118,8 @@ protected: static void SettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf); static FString ToggleInputCommand; + + static FString DisableInputCommand; static FString LoadLayoutCommand; @@ -155,8 +159,6 @@ protected: bool bHideAllWindows = false; bool IsInitialized = false; - - TArray ConsoleCommands; }; //-------------------------------------------------------------------------------------------------------------------------- diff --git a/README.md b/README.md index e41bbdd..2227390 100644 --- a/README.md +++ b/README.md @@ -446,8 +446,3 @@ class ACogSamplePlayerController ![Data Assets](https://github.com/arnaud-jamin/Cog/assets/13844285/1f4f3255-4104-4dfc-ab9e-fd34335c0289) -Currently, Cog does not properly work when running under a single process in multiplayer mode. You might want to disable the setting `Editor Preferences - Run Under One Process`: - -![image](https://github.com/arnaud-jamin/Cog/assets/13844285/6079b71c-bd41-4193-b3c6-aa76a70984e5) - - diff --git a/Source/CogSample.Target.cs b/Source/CogSample.Target.cs index c8d8b72..32b4e38 100644 --- a/Source/CogSample.Target.cs +++ b/Source/CogSample.Target.cs @@ -5,11 +5,9 @@ public class CogSampleTarget : TargetRules { public CogSampleTarget(TargetInfo Target) : base(Target) { - Type = TargetType.Game; - DefaultBuildSettings = BuildSettingsVersion.V2; - //IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_2; - ExtraModuleNames.Add("CogSample"); - //bUseUnityBuild = false; - //bUsePCHFiles = false; + Type = TargetType.Game; + DefaultBuildSettings = BuildSettingsVersion.V2; + DefaultBuildSettings = BuildSettingsVersion.Latest; + IncludeOrderVersion = EngineIncludeOrderVersion.Latest; } } diff --git a/Source/CogSample/CogSampleTargetAcquisition.cpp b/Source/CogSample/CogSampleTargetAcquisition.cpp index 0b5dba7..58cae34 100644 --- a/Source/CogSample/CogSampleTargetAcquisition.cpp +++ b/Source/CogSample/CogSampleTargetAcquisition.cpp @@ -7,6 +7,7 @@ #include "CogSampleLogCategories.h" #include "CogSampleTargetableInterface.h" #include "Components/CapsuleComponent.h" +#include "Engine/OverlapResult.h" #include "GameFramework/PlayerController.h" #if ENABLE_COG diff --git a/Source/CogSampleEditor.Target.cs b/Source/CogSampleEditor.Target.cs index 20b78b3..67ddc82 100644 --- a/Source/CogSampleEditor.Target.cs +++ b/Source/CogSampleEditor.Target.cs @@ -5,9 +5,10 @@ public class CogSampleEditorTarget : TargetRules { public CogSampleEditorTarget(TargetInfo Target) : base(Target) { - Type = TargetType.Editor; - DefaultBuildSettings = BuildSettingsVersion.V2; - //IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_2; - ExtraModuleNames.Add("CogSample"); - } + Type = TargetType.Editor; + DefaultBuildSettings = BuildSettingsVersion.V2; + DefaultBuildSettings = BuildSettingsVersion.Latest; + IncludeOrderVersion = EngineIncludeOrderVersion.Latest; + ExtraModuleNames.Add("CogSample"); + } }