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

This commit is contained in:
ed
2025-05-18 22:16:00 -04:00
parent 7acdda3679
commit b58f73da28
27 changed files with 914 additions and 101 deletions
@@ -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;
};