Got Cog jailbroken from the game viewport (a UCogEditorSubsystem instance can be within the editor's main frame now)

This commit is contained in:
2025-05-18 22:16:00 -04:00
parent 7acdda3679
commit b58f73da28
27 changed files with 914 additions and 101 deletions
+100
View File
@@ -0,0 +1,100 @@
#include "CogHelper.h"
#include "AssetRegistry/AssetRegistryModule.h"
#include "AssetRegistry/IAssetRegistry.h"
#include "CogDebug.h"
#include "GameFramework/PlayerController.h"
#include "imgui.h"
//----------------------------------------------------------------------------------------------------------------------
const UObject* FCogHelper::GetFirstAssetByClass(const TSubclassOf<UObject>& AssetClass)
{
const IAssetRegistry& AssetRegistry = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry")).Get();
TArray<FAssetData> Assets;
AssetRegistry.GetAssetsByClass(AssetClass->GetClassPathName(), Assets, true);
if (Assets.Num() == 0)
{
return nullptr;
}
const UObject* Asset = Assets[0].GetAsset();
return Asset;
}
//--------------------------------------------------------------------------------------------------------------------------
FString FCogHelper::GetActorName(const AActor* Actor)
{
if (Actor == nullptr)
{
return FString("none");
}
return GetActorName(*Actor);
}
//--------------------------------------------------------------------------------------------------------------------------
FString FCogHelper::GetActorName(const AActor& Actor)
{
#if WITH_EDITOR
const FCogDebugSettings& Settings = FCogDebug::Settings;
return Settings.ActorNameUseLabel ? Actor.GetActorLabel() : Actor.GetName();
#else //WITH_EDITOR
return Actor.GetName();
#endif //WITH_EDITOR
}
//-----------------------------------------------------------------------------------------
bool FCogHelper::ComputeBoundingBoxScreenPosition(const APlayerController* PlayerController, const FVector& Origin, const FVector& Extent, FVector2D& Min, FVector2D& Max)
{
FVector Corners[8];
Corners[0].Set(-Extent.X, -Extent.Y, -Extent.Z); // - - -
Corners[1].Set(Extent.X, -Extent.Y, -Extent.Z); // + - -
Corners[2].Set(-Extent.X, Extent.Y, -Extent.Z); // - + -
Corners[3].Set(-Extent.X, -Extent.Y, Extent.Z); // - - +
Corners[4].Set(Extent.X, Extent.Y, -Extent.Z); // + + -
Corners[5].Set(Extent.X, -Extent.Y, Extent.Z); // + - +
Corners[6].Set(-Extent.X, Extent.Y, Extent.Z); // - + +
Corners[7].Set(Extent.X, Extent.Y, Extent.Z); // + + +
Min.X = FLT_MAX;
Min.Y = FLT_MAX;
Max.X = -FLT_MAX;
Max.Y = -FLT_MAX;
for (int i = 0; i < 8; ++i)
{
FVector2D ScreenLocation;
if (PlayerController->ProjectWorldLocationToScreen(Origin + Corners[i], ScreenLocation, false) == false)
{
return false;
}
Min.X = FMath::Min(ScreenLocation.X, Min.X);
Min.Y = FMath::Min(ScreenLocation.Y, Min.Y);
Max.X = FMath::Max(ScreenLocation.X, Max.X);
Max.Y = FMath::Max(ScreenLocation.Y, Max.Y);
}
// Prevent getting large values when the camera get close to the target
ImVec2 DisplaySize = ImGui::GetIO().DisplaySize;
Min.X = FMath::Max(-DisplaySize.x, Min.X);
Min.Y = FMath::Max(-DisplaySize.y, Min.Y);
Max.X = FMath::Min(DisplaySize.x * 2, Max.X);
Max.Y = FMath::Min(DisplaySize.y * 2, Max.Y);
return true;
}
//--------------------------------------------------------------------------------------------------------------------------
bool FCogHelper::IsTraceChannelHidden(const UCollisionProfile& InCollisionProfile, const ECollisionChannel InCollisionChannel)
{
return false;
}
@@ -0,0 +1,36 @@
#pragma once
#include "CoreMinimal.h"
#include "HAL/IConsoleManager.h"
class UWorld;
DECLARE_DELEGATE_TwoParams(FCogWindowConsoleCommandDelegate, const TArray<FString>&, UWorld*);
//--------------------------------------------------------------------------------------------------------------------------
struct FCogCommandReceiver
{
int32 PIEInstance = INDEX_NONE;
FCogWindowConsoleCommandDelegate Delegate;
};
//--------------------------------------------------------------------------------------------------------------------------
struct FCogCommandInfo
{
IConsoleObject* ConsoleObject = nullptr;
TArray<FCogCommandReceiver> Receivers;
};
//--------------------------------------------------------------------------------------------------------------------------
struct COG_API FCogConsoleCommandManager
{
static void RegisterWorldConsoleCommand(const TCHAR* InName, const TCHAR* InHelp, UWorld* InWorld, const FCogWindowConsoleCommandDelegate& InDelegate);
static void UnregisterAllWorldConsoleCommands(const UWorld* InWorld);
protected:
static TMap<FString, FCogCommandInfo> CommandMap;
};
+2
View File
@@ -6,6 +6,8 @@ public class Cog : ModuleRules
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
OptimizeCode = CodeOptimization.Never;
PublicIncludePaths.AddRange(
new string[] {
}
+27 -22
View File
@@ -70,10 +70,12 @@ void UCogSubsystem::TryInitialize(UWorld& World)
{ return; }
UE_LOG(LogCogImGui, Verbose, TEXT("UCogSubsystem::TryInitialize | World:%s %p"), *World.GetName(), &World);
Context.Initialize(WorldContext->GameViewport.Get());
FCogImGuiContextScope ImGuiContextScope(Context);
Context = MakeUnique<FCogImguiContext>();
FCogImguiContext& ImguiCtx = * (FCogImguiContext*)(Context.Get());
ImguiCtx.Initialize(WorldContext->GameViewport.Get());
FCogImGuiContextScope ImGuiContextScope(* Context);
ImGuiSettingsHandler IniHandler;
IniHandler.TypeName = "Cog";
@@ -174,11 +176,16 @@ void UCogSubsystem::TryInitialize(UWorld& World)
//--------------------------------------------------------------------------------------------------------------------------
void UCogSubsystem::Shutdown()
{
FCogImGuiContextScope ImGuiContextScope(Context);
FCogConsoleCommandManager::UnregisterAllWorldConsoleCommands(GetWorld());
if (Context.IsValid() == false) {
return;
}
FCogImGuiContextScope ImGuiContextScope(* Context);
if (bIsInitialized)
{
Context.SaveSettings();
Context->SaveSettings();
}
for (FCogWindow* Window : Windows)
@@ -190,10 +197,8 @@ void UCogSubsystem::Shutdown()
if (bIsInitialized)
{
Context.Shutdown();
Context->Shutdown();
}
FCogConsoleCommandManager::UnregisterAllWorldConsoleCommands(GetWorld());
}
//--------------------------------------------------------------------------------------------------------------------------
@@ -246,7 +251,7 @@ void UCogSubsystem::Tick(float InDeltaTime)
return;
}
FCogImGuiContextScope ImGuiContextScope(Context);
FCogImGuiContextScope ImGuiContextScope(GetContext());
UpdatePlayerControllers(*World);
@@ -275,12 +280,12 @@ void UCogSubsystem::Tick(float InDeltaTime)
}
const bool ShouldSkipRendering = NetImgui::IsConnected() && bIsSelectionModeActive == false;
Context.SetSkipRendering(ShouldSkipRendering);
GetContext().SetSkipRendering(ShouldSkipRendering);
if (Context.BeginFrame(InDeltaTime))
if (GetContext().BeginFrame(InDeltaTime))
{
Render(InDeltaTime);
Context.EndFrame();
Context->EndFrame();
}
}
@@ -360,7 +365,7 @@ void UCogSubsystem::UpdatePlayerControllers(UWorld& World)
//--------------------------------------------------------------------------------------------------------------------------
void UCogSubsystem::Render(float DeltaTime)
{
FCogImGuiContextScope ImGuiContextScope(Context);
FCogImGuiContextScope ImGuiContextScope(GetContext());
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0));
ImGui::DockSpaceOverViewport(0, nullptr, ImGuiDockNodeFlags_PassthruCentralNode | ImGuiDockNodeFlags_NoDockingOverCentralNode | ImGuiDockNodeFlags_AutoHideTabBar);
@@ -376,12 +381,12 @@ void UCogSubsystem::Render(float DeltaTime)
// There is no need to have Imgui input enabled if the imgui rendering
// is only done on the NetImgui server. So we disable imgui input.
//----------------------------------------------------------------------
if (Context.GetEnableInput() && NetImgui::IsConnected() && bIsSelectionModeActive == false)
if (Context->GetEnableInput() && NetImgui::IsConnected() && bIsSelectionModeActive == false)
{
Context.SetEnableInput(false);
Context->SetEnableInput(false);
}
if ((Context.GetEnableInput() || NetImgui::IsConnected()) && bIsSelectionModeActive == false)
if ((Context->GetEnableInput() || NetImgui::IsConnected()) && bIsSelectionModeActive == false)
{
RenderMainMenu();
}
@@ -459,7 +464,7 @@ FCogWindow* UCogSubsystem::FindWindowByID(const ImGuiID ID)
//--------------------------------------------------------------------------------------------------------------------------
void UCogSubsystem::ResetLayout()
{
FCogImGuiContextScope ImGuiContextScope(Context);
FCogImGuiContextScope ImGuiContextScope(* Context);
for (const FCogWindow* Window : Windows)
{
@@ -492,7 +497,7 @@ void UCogSubsystem::LoadLayout(const int32 LayoutIndex)
//--------------------------------------------------------------------------------------------------------------------------
void UCogSubsystem::SaveLayout(const int32 LayoutIndex)
{
FCogImGuiContextScope ImGuiContextScope(Context);
FCogImGuiContextScope ImGuiContextScope(* Context);
const FString Filename = *FCogImguiHelper::GetIniFilePath(FString::Printf(TEXT("imgui_layout_%d"), LayoutIndex));
ImGui::SaveIniSettingsToDisk(TCHAR_TO_ANSI(*Filename));
@@ -1010,14 +1015,14 @@ const UObject* UCogSubsystem::GetAsset(const TSubclassOf<UObject>& AssetClass) c
void UCogSubsystem::ToggleInputMode()
{
UE_LOG(LogCogImGui, Verbose, TEXT("UCogSubsystem::ToggleInputMode"));
Context.SetEnableInput(!Context.GetEnableInput());
Context->SetEnableInput(! Context->GetEnableInput());
}
//--------------------------------------------------------------------------------------------------------------------------
void UCogSubsystem::DisableInputMode()
{
UE_LOG(LogCogImGui, Verbose, TEXT("UCogSubsystem::DisableInputMode"));
Context.SetEnableInput(false);
Context->SetEnableInput(false);
}
//--------------------------------------------------------------------------------------------------------------------------
@@ -1028,9 +1033,9 @@ void UCogSubsystem::SetActivateSelectionMode(const bool Value)
if (bIsSelectionModeActive)
{
bIsInputEnabledBeforeEnteringSelectionMode = GetContext().GetEnableInput();
bIsInputEnabledBeforeEnteringSelectionMode = Context->GetEnableInput();
Context.SetEnableInput(true);
Context->SetEnableInput(true);
}
else
{
+1 -1
View File
@@ -253,7 +253,7 @@ bool FCogWindow::IsWindowRenderedInMainMenu()
//--------------------------------------------------------------------------------------------------------------------------
float FCogWindow::GetDpiScale() const
{
return GetOwner()->GetContext().GetDpiScale();
return GetOwner()->GetContext().GetDPIScale();
}
//--------------------------------------------------------------------------------------------------------------------------
@@ -15,11 +15,12 @@ FCogWindow_Layouts::FCogWindow_Layouts()
//--------------------------------------------------------------------------------------------------------------------------
void FCogWindow_Layouts::RenderContent()
{
const UPlayerInput* PlayerInput = FCogImguiInputHelper::GetPlayerInput(*GetWorld());
if (PlayerInput == nullptr)
{
return;
}
bool bIsEditor = GetWorld()->IsEditorWorld();
const UPlayerInput* PlayerInput = FCogImguiInputHelper::GetPlayerInput(*GetWorld());
if (bIsEditor == false && PlayerInput == nullptr)
{
return;
}
if (ImGui::MenuItem("Reset Window Layout"))
{
@@ -31,7 +31,7 @@ void FCogWindow_Settings::Initialize()
GetOwner()->GetContext().SetDPIScale(Config->DPIScale);
FCogImguiContext& Context = GetOwner()->GetContext();
ICogImguiContext& Context = GetOwner()->GetContext();
Context.SetEnableInput(Config->bEnableInput);
Context.SetShareKeyboard(Config->bShareKeyboard);
Context.SetShareMouse(Config->bShareMouse);
@@ -52,7 +52,7 @@ void FCogWindow_Settings::PreSaveConfig()
//Config->bNavEnableGamepad = IO.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad;
//Config->bNavNoCaptureInput = IO.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard;
const FCogImguiContext& Context = GetOwner()->GetContext();
const ICogImguiContext& Context = GetOwner()->GetContext();
Config->bEnableInput = Context.GetEnableInput();
Config->bShareKeyboard = Context.GetShareKeyboard();
Config->bShareMouse = Context.GetShareMouse();
@@ -62,14 +62,15 @@ void FCogWindow_Settings::PreSaveConfig()
//--------------------------------------------------------------------------------------------------------------------------
void FCogWindow_Settings::RenderContent()
{
bool bIsEditor = GetWorld()->IsEditorWorld();
const UPlayerInput* PlayerInput = FCogImguiInputHelper::GetPlayerInput(*GetWorld());
if (PlayerInput == nullptr)
if (bIsEditor == false && PlayerInput == nullptr)
{
return;
}
ImGuiIO& IO = ImGui::GetIO();
FCogImguiContext& Context = GetOwner()->GetContext();
ICogImguiContext& Context = GetOwner()->GetContext();
//-------------------------------------------------------------------------------------------
if (ImGui::CollapsingHeader("Input", ImGuiTreeNodeFlags_DefaultOpen))
@@ -2,6 +2,7 @@
#include "AssetRegistry/AssetData.h"
#include "CoreMinimal.h"
#include "Engine/EngineTypes.h"
#include "Templates/SubclassOf.h"
class UCollisionProfile;
+7 -4
View File
@@ -23,6 +23,7 @@ struct ImGuiSettingsHandler;
struct ImGuiTextBuffer;
struct FKey;
//--------------------------------------------------------------------------------------------------------------------------
UCLASS()
class COG_API UCogSubsystem : public UTickableWorldSubsystem
@@ -82,9 +83,11 @@ public:
void RebindShortcut(const UCogCommonConfig& InConfig, const FProperty& InProperty);
const FCogImguiContext& GetContext() const { return Context; }
FCogImguiContext& GetContext() { return Context; }
ICogImguiContext const& GetContext() const { return * Context; }
ICogImguiContext& GetContext() { return * Context; }
//const FCogImguiContext& GetContext() const { return Context; }
//FCogImguiContext& GetContext() { return Context; }
bool IsRenderingMainMenu() const { return bIsRenderingInMainMenu; }
@@ -192,7 +195,7 @@ protected:
TWeakObjectPtr<UInputComponent> InputComponent;
FCogImguiContext Context;
TUniquePtr<ICogImguiContext> Context;
TArray<FCogWindow*> Windows;
@@ -46,7 +46,7 @@ enum class ECogWidgetAlignment
//--------------------------------------------------------------------------------------------------------------------------
UCLASS(Config = Cog)
class UCogWindowConfig_Settings : public UCogCommonConfig
class COG_API UCogWindowConfig_Settings : public UCogCommonConfig
{
GENERATED_BODY()
@@ -6,6 +6,8 @@ public class CogCommon : ModuleRules
{
bUseUnity = false;
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
OptimizeCode = CodeOptimization.Never;
PublicIncludePaths.AddRange(
new string[] {
@@ -6,6 +6,8 @@ public class CogImgui : ModuleRules
public CogImgui(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
OptimizeCode = CodeOptimization.Never;
PublicDependencyModuleNames.AddRange(new[]
{
@@ -23,6 +23,16 @@
#include "Widgets/SViewport.h"
#include "Widgets/SWindow.h"
//--------------------------------------------------------------------------------------------------------------------------
FCogImGuiContextScope::FCogImGuiContextScope(ICogImguiContext& CogImguiContext)
{
PrevContext = ImGui::GetCurrentContext();
PrevPlotContext = ImPlot::GetCurrentContext();
ImGui::SetCurrentContext(CogImguiContext.GetImGuiContext());
ImPlot::SetCurrentContext(CogImguiContext.GetImPlotContext());
}
//--------------------------------------------------------------------------------------------------------------------------
FCogImGuiContextScope::FCogImGuiContextScope(const FCogImguiContext& CogImguiContext)
{
@@ -455,7 +465,7 @@ void FCogImguiContext::ImGui_CreateWindow(ImGuiViewport* Viewport)
return;
}
FCogImguiContext* Context = ParentViewportData->Context;
FCogImguiContext* Context = (FCogImguiContext*)ParentViewportData->Context;
const bool bTooltipWindow = (Viewport->Flags & ImGuiViewportFlags_TopMost);
const bool bPopupWindow = (Viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon);
@@ -512,7 +522,7 @@ void FCogImguiContext::ImGui_CreateWindow(ImGuiViewport* Viewport)
ViewportData->Widget = Widget;
ViewportData->Window = Window;
ParentViewportData->Context->WindowToViewportMap.Add(Window, Viewport->ID);
Context->WindowToViewportMap.Add(Window, Viewport->ID);
Viewport->PlatformRequestResize = false;
}
@@ -153,16 +153,21 @@ FReply SCogImguiWidget::HandleKeyEvent(const FKeyEvent& KeyEvent, bool Down) con
return FReply::Unhandled();
}
if (const UWorld* World = Context->GetGameViewport()->GetWorld())
{
if (const UPlayerInput* PlayerInput = FCogImguiInputHelper::GetPlayerInput(*World))
{
if (FCogImguiInputHelper::IsTopPriorityKeyEvent(*PlayerInput, KeyEvent))
{
return FReply::Unhandled();
}
}
}
// TODO(Ed): Do we need a better way to know when the context is definitely an Cog Editor?
bool bIsEditor = Context->GetGameViewport() == nullptr;
if (bIsEditor == false)
{
if (const UWorld* World = Context->GetGameViewport()->GetWorld())
{
if (const UPlayerInput* PlayerInput = FCogImguiInputHelper::GetPlayerInput(*World))
{
if (FCogImguiInputHelper::IsTopPriorityKeyEvent(*PlayerInput, KeyEvent))
{
return FReply::Unhandled();
}
}
}
}
ImGuiIO& IO = ImGui::GetIO();
IO.AddKeyEvent(FCogImguiInputHelper::ToImKey(KeyEvent.GetKey()), Down);
@@ -6,6 +6,7 @@
#include "Templates/SharedPointer.h"
#include "UObject/StrongObjectPtr.h"
class ICogImguiContext;
class FCogImguiContext;
class IInputProcessor;
class SCogImguiWidget;
@@ -25,69 +26,109 @@ struct COGIMGUI_API FCogImGuiViewportData
TWeakPtr<SCogImguiWidget> Widget = nullptr;
};
class COGIMGUI_API ICogImguiContext
{
public:
virtual ~ICogImguiContext() {};
virtual TObjectPtr<const UGameViewportClient> GetGameViewport() const PURE_VIRTUAL(GetGameViewport, return(nullptr); );
virtual TSharedPtr<const SCogImguiWidget> GetMainWidget() const PURE_VIRTUAL(GetMainWidget, return(nullptr); );
virtual ImGuiContext* GetImGuiContext() PURE_VIRTUAL(GetImGuiContext, return nullptr; );
virtual ImPlotContext* GetImPlotContext() PURE_VIRTUAL(GetImPlotContext, return nullptr; );
virtual bool GetEnableInput() const PURE_VIRTUAL(GetEnableInput, return false; );
virtual void SetEnableInput(bool InValue) PURE_VIRTUAL(SetEnableInput);
virtual bool GetShareKeyboard() const PURE_VIRTUAL(GetEnableKeyboard, return false; );
virtual void SetShareKeyboard(bool InValue) PURE_VIRTUAL(SetShareKeyboard);
virtual bool GetShareMouse() const PURE_VIRTUAL(GetShareMouse, return false; );
virtual void SetShareMouse(bool InValue) PURE_VIRTUAL(SetShareMouse);
virtual bool GetShareMouseWithGameplay() const PURE_VIRTUAL(GetShareMouseWithGameplay, return false; );
virtual void SetShareMouseWithGameplay(bool InValue) PURE_VIRTUAL(SetShareMouseWithGameplay);
virtual bool GetWantCaptureMouse() const PURE_VIRTUAL(GetWantCaptureMouse, return(false); );
virtual float GetDPIScale() const PURE_VIRTUAL(GetDPIScale, return(0.0f); );
virtual void SetDPIScale(float Value) PURE_VIRTUAL(SetDPIScale);
virtual bool BeginFrame(float InDeltaTime) PURE_VIRTUAL(BeginFrame, return false; );
virtual void EndFrame() PURE_VIRTUAL(EndFrame);
virtual ImVec2 GetImguiMousePos() const PURE_VIRTUAL(GetImguiMousePos, return ImVec2{}; );
virtual bool GetSkipRendering() const PURE_VIRTUAL(GetSkipRendering, return(false); );
virtual void SetSkipRendering(bool skip) PURE_VIRTUAL(SkipRendering);
virtual void SaveSettings() const PURE_VIRTUAL(SaveSettings);
virtual void Shutdown() PURE_VIRTUAL(Shutdown);
virtual void OnImGuiWidgetFocusLost() PURE_VIRTUAL(OnImGuiWidgetFocusLost);
};
struct COGIMGUI_API FCogImGuiContextScope
{
UE_NODISCARD_CTOR explicit FCogImGuiContextScope(ICogImguiContext& CogImguiContext);
UE_NODISCARD_CTOR explicit FCogImGuiContextScope(const FCogImguiContext& CogImguiContext);
UE_NODISCARD_CTOR explicit FCogImGuiContextScope(ImGuiContext* GuiCtx, ImPlotContext* PlotCtx);
~FCogImGuiContextScope();
private:
protected:
ImGuiContext* PrevContext = nullptr;
ImPlotContext* PrevPlotContext = nullptr;
};
class COGIMGUI_API FCogImguiContext : public TSharedFromThis<FCogImguiContext>
class COGIMGUI_API FCogImguiContext
: public TSharedFromThis<FCogImguiContext>
, public ICogImguiContext
{
public:
#pragma region ICogImguiContext
bool BeginFrame(float InDeltaTime) override;
void EndFrame() override;
ImGuiContext* GetImGuiContext() override { return Context; }
ImPlotContext* GetImPlotContext() override { return PlotContext; }
TObjectPtr<const UGameViewportClient> GetGameViewport() const override { return GameViewport; }
TSharedPtr<const SCogImguiWidget> GetMainWidget() const override { return MainWidget; }
bool GetEnableInput() const override { return bEnableInput; }
void SetEnableInput(bool InValue) override;
bool GetShareKeyboard() const override { return bShareKeyboard; }
void SetShareKeyboard(bool Value) override { bShareKeyboard = Value; }
bool GetShareMouse() const override { return bShareMouse; }
void SetShareMouse(bool Value) override;
void SetShareMouseWithGameplay(bool Value) override;
bool GetShareMouseWithGameplay() const override { return bShareMouseWithGameplay; }
ImVec2 GetImguiMousePos() const override;
bool GetWantCaptureMouse() const override { return bWantCaptureMouse; }
float GetDPIScale() const override { return DpiScale; }
void SetDPIScale(float Value) override;
bool GetSkipRendering() const override;
void SetSkipRendering(bool Value) override;
void Shutdown() override;
void SaveSettings() const override;
void OnImGuiWidgetFocusLost() override;
#pragma endregion ICogImguiContext
void Initialize(UGameViewportClient* InGameViewport);
void Shutdown();
void SaveSettings() const;
bool GetEnableInput() const { return bEnableInput; }
void SetEnableInput(bool InValue);
bool GetWantCaptureMouse() const { return bWantCaptureMouse; }
bool GetShareMouse() const { return bShareMouse; }
void SetShareMouse(bool Value);
bool GetShareMouseWithGameplay() const { return bShareMouseWithGameplay; }
void SetShareMouseWithGameplay(bool Value);
bool GetShareKeyboard() const { return bShareKeyboard; }
void SetShareKeyboard(bool Value) { bShareKeyboard = Value; }
bool BeginFrame(float InDeltaTime);
void EndFrame();
float GetDpiScale() const { return DpiScale; }
void SetDPIScale(float Value);
bool GetSkipRendering() const;
void SetSkipRendering(bool Value);
ImVec2 GetImguiMousePos() const;
TObjectPtr<const UGameViewportClient> GetGameViewport() const { return GameViewport; }
TSharedPtr<const SCogImguiWidget> GetMainWidget() const { return MainWidget; }
void OnImGuiWidgetFocusLost();
static bool GetIsNetImguiInitialized() { return bIsNetImGuiInitialized; }
private:
protected:
friend struct FCogImGuiContextScope;
@@ -186,5 +227,4 @@ private:
bool bRetakeFocus = false;
static bool bIsNetImGuiInitialized;
};
@@ -6,7 +6,7 @@
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/SLeafWidget.h"
class FCogImguiContext;
class ICogImguiContext;
class SWindow;
class UGameViewportClient;
@@ -18,7 +18,7 @@ class COGIMGUI_API SCogImguiInputCatcherWidget : public SLeafWidget
public:
SLATE_BEGIN_ARGS(SCogImguiInputCatcherWidget) {}
SLATE_ARGUMENT(FCogImguiContext*, Context)
SLATE_ARGUMENT(ICogImguiContext*, Context)
SLATE_END_ARGS()
void Construct(const FArguments& InArgs);
@@ -59,7 +59,7 @@ protected:
void RefreshVisibility();
FCogImguiContext* Context = nullptr;
ICogImguiContext* Context = nullptr;
TSharedPtr<SWindow> Window = nullptr;
};
@@ -7,7 +7,7 @@
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/SLeafWidget.h"
class FCogImguiContext;
class ICogImguiContext;
class SWindow;
class UGameViewportClient;
@@ -19,7 +19,7 @@ class COGIMGUI_API SCogImguiWidget : public SLeafWidget
public:
SLATE_BEGIN_ARGS(SCogImguiWidget) {}
SLATE_ARGUMENT(FCogImguiContext*, Context)
SLATE_ARGUMENT(ICogImguiContext*, Context)
SLATE_END_ARGS()
void Construct(const FArguments& InArgs);
@@ -68,7 +68,7 @@ protected:
void RefreshVisibility();
FCogImguiContext* Context = nullptr;
ICogImguiContext* Context = nullptr;
TSharedPtr<SWindow> Window = nullptr;
+31
View File
@@ -0,0 +1,31 @@
{
"FileVersion": 3,
"Version": 1,
"VersionName": "1.0",
"FriendlyName": "Cog Editor",
"Description": "Cog: Editor Plugin for usage outside of the game viewport",
"Category": "Other",
"CreatedBy": "Edward R. Gonzalez",
"CreatedByURL": "",
"DocsURL": "",
"MarketplaceURL": "",
"SupportURL": "",
"CanContainContent": false,
"IsBetaVersion": false,
"IsExperimentalVersion": false,
"Installed": false,
"Modules":
[
{
"Name": "CogEditor",
"Type": "Editor",
"LoadingPhase": "Default"
}
],
"Plugins": [
{
"Name": "Cog",
"Enabled": true
}
]
}
@@ -0,0 +1,64 @@
using UnrealBuildTool;
public class CogEditor : ModuleRules
{
public CogEditor(ReadOnlyTargetRules Target) : base(Target)
{
bUseUnity = false;
bMergeUnityFiles = false;
IWYUSupport = IWYUSupport.None;
PCHUsage = PCHUsageMode.NoPCHs;
OptimizeCode = CodeOptimization.Never;
MinCpuArchX64 = MinimumCpuArchitectureX64.AVX512;
IncludeOrderVersion = EngineIncludeOrderVersion.Latest;
bCodeCoverage = false;
bDisableStaticAnalysis = true;
bValidateCircularDependencies = true;
bValidateFormatStrings = false;
bValidateInternalApi = false;
bEnableExceptions = false;
bEnableBufferSecurityChecks = false;
bEnableNonInlinedGenCppWarnings = false;
bIgnoreUnresolvedSymbols = false;
// bEnableUndefinedIdentifierWarnings = false;
bWarningsAsErrors = false;
ShadowVariableWarningLevel = UnrealBuildTool.WarningLevel.Off;
UndefinedIdentifierWarningLevel = UnrealBuildTool.WarningLevel.Off;
UndefinedIdentifierWarningLevel = WarningLevel.Off;
bEnableObjCAutomaticReferenceCounting = false;
bEnableObjCExceptions = false;
var Kilobyte = 1024;
NumIncludedBytesPerUnityCPPOverride = Kilobyte * 32;
MinFilesUsingPrecompiledHeaderOverride = 1;
#region Engine
PrivateDependencyModuleNames.AddRange(new string[]
{
"CoreUObject",
"Engine",
"Slate",
"SlateCore",
"UnrealEd"
});
#endregion Engine
#region Cog
PublicDependencyModuleNames.AddRange(new string[]
{
"Core",
"Cog",
"CogCommon",
"CogImgui",
"CogDebug",
});
#endregion Cog
}
}
@@ -0,0 +1,113 @@
#include "CogEditorImguiContext.h"
#include "CogImguiHelper.h"
#include "CogImguiInputCatcherWidget.h"
#include "CogImguiWidget.h"
#include "imgui_internal.h"
#include "Interfaces/IMainFrameModule.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "implot.h"
#include "Framework/Application/SlateApplication.h"
void FCogEditorImguiContext::Initialize()
{
IMGUI_CHECKVERSION();
IMainFrameModule& MainFrameModule = FModuleManager::LoadModuleChecked<IMainFrameModule>("MainFrame");
TSharedPtr<SWindow> MainWindow = MainFrameModule.GetParentWindow();
// ImGui Context must be created before creating widgets as widgets can receive events that uses the ImGui context right away.
Context = ImGui::CreateContext();
PlotContext = ImPlot::CreateContext();
ImGui::SetCurrentContext(Context);
ImPlot::SetImGuiContext(Context);
ImPlot::SetCurrentContext(PlotContext);
SAssignNew(MainWidget, SCogImguiWidget).Context(this);
SAssignNew(InputCatcherWidget, SCogImguiInputCatcherWidget).Context(this);
MainWindow->AddOverlaySlot() [
MainWidget.ToSharedRef()
];
MainWindow->AddOverlaySlot() [
InputCatcherWidget.ToSharedRef()
];
ImGuiIO& IO = ImGui::GetIO();
IO.UserData = this;
IO.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
IO.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
IO.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
IO.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
IO.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;
IO.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;
IO.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports;
IO.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport;
IO.BackendFlags |= ImGuiBackendFlags_RendererHasViewports;
IO.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;
//--------------------------------------------------------------------
//
//--------------------------------------------------------------------
ImGuiViewport* MainViewport = ImGui::GetMainViewport();
FCogImGuiViewportData* ViewportData = new FCogImGuiViewportData();
MainViewport->PlatformUserData = ViewportData;
ViewportData->Window = FSlateApplication::IsInitialized() ? FSlateApplication::Get().GetActiveTopLevelWindow() : nullptr;
ViewportData->Context = this;
ViewportData->Widget = MainWidget;
const auto InitFilenameTemp = StringCast<ANSICHAR>(*FCogImguiHelper::GetIniFilePath("imgui"));
ImStrncpy(IniFilename, InitFilenameTemp.Get(), IM_ARRAYSIZE(IniFilename));
IO.IniFilename = IniFilename;
ImGuiPlatformIO& PlatformIO = ImGui::GetPlatformIO();
PlatformIO.Platform_CreateWindow = ImGui_CreateWindow;
PlatformIO.Platform_DestroyWindow = ImGui_DestroyWindow;
PlatformIO.Platform_ShowWindow = ImGui_ShowWindow;
PlatformIO.Platform_SetWindowPos = ImGui_SetWindowPos;
PlatformIO.Platform_GetWindowPos = ImGui_GetWindowPos;
PlatformIO.Platform_SetWindowSize = ImGui_SetWindowSize;
PlatformIO.Platform_GetWindowSize = ImGui_GetWindowSize;
PlatformIO.Platform_SetWindowFocus = ImGui_SetWindowFocus;
PlatformIO.Platform_GetWindowFocus = ImGui_GetWindowFocus;
PlatformIO.Platform_GetWindowMinimized = ImGui_GetWindowMinimized;
PlatformIO.Platform_SetWindowTitle = ImGui_SetWindowTitle;
PlatformIO.Platform_SetWindowAlpha = ImGui_SetWindowAlpha;
PlatformIO.Platform_RenderWindow = ImGui_RenderWindow;
PlatformIO.Platform_ClipboardUserData = &ClipboardBuffer;
PlatformIO.Platform_GetClipboardTextFn = ImGui_GetClipboardTextFn;
PlatformIO.Platform_SetClipboardTextFn = ImGui_SetClipboardTextFn;
PlatformIO.Platform_OpenInShellFn = ImGui_OpenInShell;
if (FSlateApplication::IsInitialized())
{
if (const TSharedPtr<GenericApplication> PlatformApplication = FSlateApplication::Get().GetPlatformApplication())
{
FDisplayMetrics DisplayMetrics;
PlatformApplication->GetInitialDisplayMetrics(DisplayMetrics);
PlatformApplication->OnDisplayMetricsChanged().AddRaw(this, &FCogEditorImguiContext::OnDisplayMetricsChanged);
OnDisplayMetricsChanged(DisplayMetrics);
}
}
else
{
FMonitorInfo monitorInfo;
monitorInfo.bIsPrimary = true;
monitorInfo.DisplayRect = FPlatformRect(0, 0, 1080, 720);
FDisplayMetrics DisplayMetrics;
DisplayMetrics.MonitorInfo.Add(monitorInfo);
OnDisplayMetricsChanged(DisplayMetrics);
}
#if NETIMGUI_ENABLED
if (bIsNetImGuiInitialized == false)
{
NetImgui::Startup();
bIsNetImGuiInitialized = true;
}
#endif
}
@@ -0,0 +1,11 @@
#pragma once
#include "CogImguiContext.h"
class COGEDITOR_API FCogEditorImguiContext : public FCogImguiContext
{
public:
void Initialize(UGameViewportClient* viewport) = delete;
void Initialize();
};
@@ -0,0 +1,3 @@
#include "CogEditorMinimal.h"
DEFINE_LOG_CATEGORY(LogCogEditor);
@@ -0,0 +1,130 @@
#pragma once
/*----------------------------------------------------------------------------
Low level includes.
----------------------------------------------------------------------------*/
#include "CoreTypes.h"
/*----------------------------------------------------------------------------
Forward declarations
----------------------------------------------------------------------------*/
#include "CoreFwd.h"
#include "UObject/UObjectHierarchyFwd.h"
#include "Containers/ContainersFwd.h"
/*----------------------------------------------------------------------------
Commonly used headers
----------------------------------------------------------------------------*/
#include "Misc/VarArgs.h"
#include "Logging/LogVerbosity.h"
#include "UObject/ObjectMacros.h"
#include "Delegates/Delegate.h"
#include "Delegates/DelegateCombinations.h"
/*----------------------------------------------------------------------------*/
#include "CogEditorMinimal.generated.h"
#pragma region Engine Forwards
#pragma endregion Engine Forwards
#pragma region Cog Forwards
class UCogEditorModule;
class UCogEditorSubsystem;
#pragma endregion Cog Forwards
#pragma region Logging
// Straight from the Engine
UENUM(BlueprintType)
enum class ECogEditorVerbosity : uint8
{
/** Not used */
NoLogging = 0,
/** Always prints a fatal error to console (and log file) and crashes (even if logging is disabled) */
// Fatal,
// Just use GASA_Fatal...
/**
* Prints an error to console (and log file).
* Commandlets and the editor collect and report errors. Error messages result in commandlet failure.
*/
Error = ELogVerbosity::Error,
/**
* Prints a warning to console (and log file).
* Commandlets and the editor collect and report warnings. Warnings can be treated as an error.
*/
Warning,
/** Prints a message to console (and log file) */
Display,
/** Prints a message to a log file (does not print to console) */
Log,
/**
* Prints a verbose message to a log file (if Verbose logging is enabled for the given category,
* usually used for detailed logging)
*/
Verbose,
/**
* Prints a verbose message to a log file (if VeryVerbose logging is enabled,
* usually used for detailed logging that would otherwise spam output)
*/
VeryVerbose,
};
DECLARE_LOG_CATEGORY_EXTERN(LogCogEditor, Log, All);
namespace CogEditor
{
using ELogV = ECogEditorVerbosity;
// Works for Unreal 5.4, Win64 MSVC (untested in other scenarios, for now)
inline
void Log( FString Message
, ELogV Verbosity = ELogV::Log
, FLogCategoryBase& Category = LogCogEditor
, bool DumpStack = false
, int32 Line = __builtin_LINE()
, const ANSICHAR* File = __builtin_FILE()
, const ANSICHAR* Func = __builtin_FUNCTION() )
{
#if !UE_BUILD_SHIPPING && !NO_LOGGING
ELogVerbosity::Type EngineVerbosity = (ELogVerbosity::Type) Verbosity;
static UE::Logging::Private::FStaticBasicLogDynamicData LOG_Dynamic;
static UE::Logging::Private::FStaticBasicLogRecord
LOG_Static(TEXT("%s -- %hs %hs(%d)"), File, Line, EngineVerbosity, LOG_Dynamic);
if ((EngineVerbosity & ELogVerbosity::VerbosityMask) <= ELogVerbosity::COMPILED_IN_MINIMUM_VERBOSITY)
{
if ((EngineVerbosity & ELogVerbosity::VerbosityMask) <= Category.GetVerbosity())
{
if ( ! Category.IsSuppressed(EngineVerbosity))
{
if (DumpStack)
FDebug::DumpStackTraceToLog(EngineVerbosity);
BasicLog(Category, &LOG_Static, *Message, File, Func, Line);
}
}
}
#endif
}
}
#define CogEditor_Fatal(Message) UE_LOG( LogCogEditor, Fatal, TEXT("%s -- %hs %hs(%d)"), *Message, __builtin_FILE(), __func__, __builtin_LINE() );
#define CogEditor_Error(Message) UE_LOG( LogCogEditor, Error, TEXT("%s -- %hs %hs(%d)"), *Message, __builtin_File(), __func__, __builtin_LINE() );
#define CogEditor_Warning(Message) UE_LOG( LogCogEditor, Warning, TEXT("%s -- %hs %hs(%d)"), *Message, __builtin_File(), __func__, __builtin_LINE() );
#define CogEditor_Display(Message) UE_LOG( LogCogEditor, Display, TEXT("%s -- %hs %hs(%d)"), *Message, __builtin_File(), __func__, __builtin_LINE() );
#define CogEditor_Log(Message) UE_LOG( LogCogEditor, Log, TEXT("%s -- %hs %hs(%d)"), *Message, __builtin_File(), __func__, __builtin_LINE() );
#define CogEditor_Verbose(Message) UE_LOG( LogCogEditor, Verbose, TEXT("%s -- %hs %hs(%d)"), *Message, __builtin_File(), __func__, __builtin_LINE() );
#define CogEditor_VeryVerbose(Message) UE_LOG( LogCogEditor, VeryVerbose, TEXT("%s -- %hs %hs(%d)"), *Message, __builtin_File(), __func__, __builtin_LINE() );
#pragma endregion Logging
@@ -0,0 +1,17 @@
#include "CogEditorModule.h"
IMPLEMENT_MODULE(FCogEditorModule, CogEditor)
#define LOCTEXT_NAMESPACE "FCogEditorModule"
void FCogEditorModule::StartupModule()
{
}
void FCogEditorModule::ShutdownModule()
{
}
#undef LOCTEXT_NAMESPACE
@@ -0,0 +1,16 @@
#pragma once
#include "Modules/ModuleInterface.h"
#include "Modules/ModuleManager.h"
#include "CogEditorMinimal.h"
class COGEDITOR_API FCogEditorModule : public IModuleInterface
{
public:
static FCogEditorModule& Get() { return FModuleManager::LoadModuleChecked<FCogEditorModule>("CogEditor"); }
void StartupModule() override;
void ShutdownModule() override;
};
@@ -0,0 +1,182 @@
#include "CogEditorSubsystem.h"
#include "Editor.h"
#include "imgui_internal.h"
#include "CogConsoleCommandManager.h"
#include "CogWindow_Spacing.h"
#include "CogWindow_Layouts.h"
#include "CogWindow_Settings.h"
FString UCogEditorSubsystem::ToggleInputCommand = TEXT("CogEditor.ToggleInput");
FString UCogEditorSubsystem::DisableInputCommand = TEXT("CogEditor.DisableInput");
FString UCogEditorSubsystem::LoadLayoutCommand = TEXT("CogEditor.LoadLayout");
FString UCogEditorSubsystem::SaveLayoutCommand = TEXT("CogEditor.SaveLayout");
FString UCogEditorSubsystem::ResetLayoutCommand = TEXT("CogEditor.ResetLayout");
UE_DISABLE_OPTIMIZATION
ETickableTickType UCogEditorSubsystem::GetTickableTickType() const
{
return ETickableTickType::Never;
}
UE_ENABLE_OPTIMIZATION
void UCogEditorSubsystem::TryInitialize(UWorld& World)
{
// Super::TryInitialize(World);
if (bIsInitialized) {
return;
}
// FWorldContext* WorldContext = GEngine->GetWorldContextFromWorld(&World);
// if (WorldContext == nullptr) {
// return;
// }
// if (WorldContext->GameViewport == nullptr && IsRunningDedicatedServer() == false) {
// return;
// }
FWorldContext& WorldContext = GEditor->GetEditorWorldContext(false);
using namespace CogEditor;
Log(FString::Printf(TEXT("UCogSubsystem::TryInitialize | World:%s %p"), *World.GetName(), &World), ELogV::Verbose);
Context = MakeUnique<FCogEditorImguiContext>();
FCogEditorImguiContext& EditorCtx = *(FCogEditorImguiContext*)(Context.Get());
EditorCtx.Initialize();
FCogImGuiContextScope ImGuiContextScope(* Context);
ImGuiSettingsHandler IniHandler;
IniHandler.TypeName = "CogEditor";
IniHandler.TypeHash = ImHashStr("CogEditor");
IniHandler.ClearAllFn = SettingsHandler_ClearAll;
IniHandler.ReadOpenFn = SettingsHandler_ReadOpen;
IniHandler.ReadLineFn = SettingsHandler_ReadLine;
IniHandler.ApplyAllFn = SettingsHandler_ApplyAll;
IniHandler.WriteAllFn = SettingsHandler_WriteAll;
IniHandler.UserData = this;
ImGui::AddSettingsHandler(&IniHandler);
SpaceWindows.Add(AddWindow<FCogWindow_Spacing>("Spacing 1"));
SpaceWindows.Add(AddWindow<FCogWindow_Spacing>("Spacing 2"));
SpaceWindows.Add(AddWindow<FCogWindow_Spacing>("Spacing 3"));
SpaceWindows.Add(AddWindow<FCogWindow_Spacing>("Spacing 4"));
Settings = GetConfig<UCogWindowConfig_Settings>();
UCogWindowConfig_Settings* SettingsPtr = Settings.Get();
AddShortcut(SettingsPtr, &UCogWindowConfig_Settings::Shortcut_ToggleImguiInput).BindLambda([this] () { ToggleInputMode(); });
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<FCogWindow_Layouts>("Window.Layouts");
SettingsWindow = AddWindow<FCogWindow_Settings>("Window.Settings");
for (FCogWindow* Window : Windows)
{
InitializeWindow(Window);
}
FCogConsoleCommandManager::RegisterWorldConsoleCommand(
*ToggleInputCommand,
TEXT("Toggle the input focus between the Game and ImGui"),
GetWorld(),
FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray<FString>& InArgs, UWorld* InWorld)
{
ToggleInputMode();
}));
FCogConsoleCommandManager::RegisterWorldConsoleCommand(
*DisableInputCommand,
TEXT("Disable ImGui input"),
GetWorld(),
FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray<FString>& InArgs, UWorld* InWorld)
{
DisableInputMode();
}));
FCogConsoleCommandManager::RegisterWorldConsoleCommand(
*ResetLayoutCommand,
TEXT("Reset the layout."),
GetWorld(),
FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray<FString>& InArgs, UWorld* InWorld)
{
if (InArgs.Num() > 0)
{
ResetLayout();
}
}));
FCogConsoleCommandManager::RegisterWorldConsoleCommand(
*LoadLayoutCommand,
TEXT("Load the layout. CogEditor.LoadLayout <Index>"),
GetWorld(),
FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray<FString>& InArgs, UWorld* InWorld)
{
if (InArgs.Num() > 0)
{
LoadLayout(FCString::Atoi(*InArgs[0]));
}
}));
FCogConsoleCommandManager::RegisterWorldConsoleCommand(
*SaveLayoutCommand,
TEXT("Save the layout. CogEditor.SaveLayout <Index>"),
GetWorld(),
FCogWindowConsoleCommandDelegate::CreateLambda([this](const TArray<FString>& InArgs, UWorld* InWorld)
{
if (InArgs.Num() > 0)
{
SaveLayout(FCString::Atoi(*InArgs[0]));
}
}));
bIsInitialized = true;
}
UE_DISABLE_OPTIMIZATION
bool UCogEditorSubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
bool bIsEditorWorld = GetWorld() == GEditor->EditorWorld;
bool bParentCreate = Super::ShouldCreateSubsystem(Outer);
return bParentCreate && bIsEditorWorld;
}
UE_ENABLE_OPTIMIZATION
bool UCogEditorSubsystem::DoesSupportWorldType(const EWorldType::Type WorldType) const
{
return WorldType == EWorldType::Editor;
}
bool UCogEditorSubsystem::EditorTick(float DeltaTime)
{
Super::Tick(DeltaTime);
return true;
}
void UCogEditorSubsystem::PostInitialize()
{
Super::PostInitialize();
TickerDelegate = FTickerDelegate::CreateUObject(this, &UCogEditorSubsystem::EditorTick);
TickerDelegateHandle = FTSTicker::GetCoreTicker().AddTicker(TickerDelegate);
}
void UCogEditorSubsystem::Deinitialize()
{
Super::Deinitialize();
FTSTicker::GetCoreTicker().RemoveTicker(TickerDelegateHandle);
}
@@ -0,0 +1,38 @@
#pragma once
#include "CogEditorImguiContext.h"
#include "CogEditorMinimal.h"
#include "CogSubsystem.h"
#include "Containers/Ticker.h"
#include "CogEditorSubsystem.generated.h"
UCLASS()
class COGEDITOR_API UCogEditorSubsystem : public UCogSubsystem
{
GENERATED_BODY()
public:
ETickableTickType GetTickableTickType() const override;
void TryInitialize(UWorld& World) override;
bool ShouldCreateSubsystem(UObject* Outer) const override;
bool DoesSupportWorldType(const EWorldType::Type WorldType) const override;
bool EditorTick(float DeltaTime);
void PostInitialize() override;
void Deinitialize() override;
FTickerDelegate TickerDelegate;
FTSTicker::FDelegateHandle TickerDelegateHandle;
static FString EnableCommand;
static FString ToggleInputCommand;
static FString DisableInputCommand;
static FString LoadLayoutCommand;
static FString SaveLayoutCommand;
static FString ResetLayoutCommand;
};