Blueprints switch from data-only to full when modified in that way.
This commit is contained in:
65
Plugins/UEWingman/Source/UEWingman/Private/WingHacks.cpp
Normal file
65
Plugins/UEWingman/Source/UEWingman/Private/WingHacks.cpp
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#include "WingHacks.h"
|
||||||
|
#include "ToolMenuEntry.h"
|
||||||
|
#include "BlueprintEditor.h"
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Private member access via template explicit-instantiation loophole.
|
||||||
|
//
|
||||||
|
// The C++ standard says "the usual access checking rules do not
|
||||||
|
// apply to names used to specify explicit instantiations." So
|
||||||
|
// &FToolMenuEntry::Action is legal as a template argument in an
|
||||||
|
// explicit instantiation, even though Action is private.
|
||||||
|
//
|
||||||
|
// The WingPrivateAccessor template captures the member pointer and exposes it
|
||||||
|
// through a friend function that we can call from normal code.
|
||||||
|
//
|
||||||
|
// See: https://bloglitb.blogspot.com/2011/12/access-to-private-members-safer.html
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
template<typename Tag, typename Tag::type M>
|
||||||
|
struct WingPrivateAccessor
|
||||||
|
{
|
||||||
|
friend typename Tag::type GetPtr(Tag) { return M; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----- FToolMenuEntry::Action -----
|
||||||
|
|
||||||
|
struct Tag_FToolMenuEntry_Action
|
||||||
|
{
|
||||||
|
using type = FToolUIActionChoice FToolMenuEntry::*;
|
||||||
|
friend type GetPtr(Tag_FToolMenuEntry_Action);
|
||||||
|
};
|
||||||
|
template struct WingPrivateAccessor<Tag_FToolMenuEntry_Action, &FToolMenuEntry::Action>;
|
||||||
|
|
||||||
|
const FToolUIActionChoice& WingHacks::GetAction(const FToolMenuEntry& Entry)
|
||||||
|
{
|
||||||
|
return Entry.*GetPtr(Tag_FToolMenuEntry_Action());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- FToolMenuEntry::Command -----
|
||||||
|
|
||||||
|
struct Tag_FToolMenuEntry_Command
|
||||||
|
{
|
||||||
|
using type = TSharedPtr<const FUICommandInfo> FToolMenuEntry::*;
|
||||||
|
friend type GetPtr(Tag_FToolMenuEntry_Command);
|
||||||
|
};
|
||||||
|
template struct WingPrivateAccessor<Tag_FToolMenuEntry_Command, &FToolMenuEntry::Command>;
|
||||||
|
|
||||||
|
bool WingHacks::HasCommand(const FToolMenuEntry& Entry)
|
||||||
|
{
|
||||||
|
return Entry.*GetPtr(Tag_FToolMenuEntry_Command()) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----- FBlueprintEditor::bWasOpenedInDefaultsMode -----
|
||||||
|
|
||||||
|
struct Tag_FBlueprintEditor_DefaultsMode
|
||||||
|
{
|
||||||
|
using type = bool FBlueprintEditor::*;
|
||||||
|
friend type GetPtr(Tag_FBlueprintEditor_DefaultsMode);
|
||||||
|
};
|
||||||
|
template struct WingPrivateAccessor<Tag_FBlueprintEditor_DefaultsMode, &FBlueprintEditor::bWasOpenedInDefaultsMode>;
|
||||||
|
|
||||||
|
bool WingHacks::WasOpenedInDefaultsMode(FBlueprintEditor* Editor)
|
||||||
|
{
|
||||||
|
return Editor->*GetPtr(Tag_FBlueprintEditor_DefaultsMode());
|
||||||
|
}
|
||||||
@@ -6,8 +6,11 @@
|
|||||||
#include "Materials/Material.h"
|
#include "Materials/Material.h"
|
||||||
#include "Materials/MaterialExpression.h"
|
#include "Materials/MaterialExpression.h"
|
||||||
#include "Kismet2/BlueprintEditorUtils.h"
|
#include "Kismet2/BlueprintEditorUtils.h"
|
||||||
|
#include "BlueprintEditor.h"
|
||||||
#include "MaterialEditingLibrary.h"
|
#include "MaterialEditingLibrary.h"
|
||||||
#include "Subsystems/AssetEditorSubsystem.h"
|
#include "Subsystems/AssetEditorSubsystem.h"
|
||||||
|
#include "Engine/Blueprint.h"
|
||||||
|
#include "WingHacks.h"
|
||||||
|
|
||||||
void FWingNotifier::AddTouchedObject(UObject* Obj)
|
void FWingNotifier::AddTouchedObject(UObject* Obj)
|
||||||
{
|
{
|
||||||
@@ -20,6 +23,7 @@ void FWingNotifier::AddTouchedObject(UObject* Obj)
|
|||||||
|
|
||||||
void FWingNotifier::SendNotifications()
|
void FWingNotifier::SendNotifications()
|
||||||
{
|
{
|
||||||
|
UAssetEditorSubsystem* EditorSubsys = GEditor->GetEditorSubsystem<UAssetEditorSubsystem>();
|
||||||
TSet<UEdGraphNode*> Nodes;
|
TSet<UEdGraphNode*> Nodes;
|
||||||
TSet<UEdGraph*> Graphs;
|
TSet<UEdGraph*> Graphs;
|
||||||
TSet<UMaterial*> Materials;
|
TSet<UMaterial*> Materials;
|
||||||
@@ -59,7 +63,19 @@ void FWingNotifier::SendNotifications()
|
|||||||
for (UMaterial *Material : Materials)
|
for (UMaterial *Material : Materials)
|
||||||
UMaterialEditingLibrary::RebuildMaterialInstanceEditors(Material);
|
UMaterialEditingLibrary::RebuildMaterialInstanceEditors(Material);
|
||||||
for (UBlueprint *Blueprint : Blueprints)
|
for (UBlueprint *Blueprint : Blueprints)
|
||||||
|
{
|
||||||
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(Blueprint);
|
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(Blueprint);
|
||||||
|
IAssetEditorInstance *Editor = EditorSubsys->FindEditorForAsset(Blueprint, false);
|
||||||
|
if (Editor)
|
||||||
|
{
|
||||||
|
FBlueprintEditor* BPEditor = static_cast<FBlueprintEditor*>(Editor);
|
||||||
|
if (WingHacks::WasOpenedInDefaultsMode(BPEditor) && !FBlueprintEditorUtils::IsDataOnlyBlueprint(Blueprint))
|
||||||
|
{
|
||||||
|
EditorSubsys->CloseAllEditorsForAsset(Blueprint);
|
||||||
|
EditorSubsys->OpenEditorForAsset(Blueprint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FBlueprintEditorUtils::RefreshAllNodes(BP);
|
// FBlueprintEditorUtils::RefreshAllNodes(BP);
|
||||||
// FKismetEditorUtilities::CompileBlueprint(BP);
|
// FKismetEditorUtilities::CompileBlueprint(BP);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "WingToolMenu.h"
|
#include "WingToolMenu.h"
|
||||||
|
#include "WingHacks.h"
|
||||||
#include "ToolMenuEntry.h"
|
#include "ToolMenuEntry.h"
|
||||||
#include "ToolMenuDelegates.h"
|
#include "ToolMenuDelegates.h"
|
||||||
#include "ToolMenuContext.h"
|
#include "ToolMenuContext.h"
|
||||||
@@ -8,54 +9,6 @@
|
|||||||
#include "EdGraphSchema_K2.h"
|
#include "EdGraphSchema_K2.h"
|
||||||
#include "Framework/Commands/UIAction.h"
|
#include "Framework/Commands/UIAction.h"
|
||||||
|
|
||||||
// ============================================================
|
|
||||||
// Private member access via template explicit-instantiation loophole.
|
|
||||||
//
|
|
||||||
// The C++ standard says "the usual access checking rules do not
|
|
||||||
// apply to names used to specify explicit instantiations." So
|
|
||||||
// &FToolMenuEntry::Action is legal as a template argument in an
|
|
||||||
// explicit instantiation, even though Action is private.
|
|
||||||
//
|
|
||||||
// The WingPrivateAccessor template captures the member pointer and exposes it
|
|
||||||
// through a friend function that we can call from normal code.
|
|
||||||
//
|
|
||||||
// See: https://bloglitb.blogspot.com/2011/12/access-to-private-members-safer.html
|
|
||||||
// ============================================================
|
|
||||||
|
|
||||||
template<typename Tag, typename Tag::type M>
|
|
||||||
struct WingPrivateAccessor
|
|
||||||
{
|
|
||||||
friend typename Tag::type GetPtr(Tag) { return M; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// ----- FToolMenuEntry::Action -----
|
|
||||||
|
|
||||||
struct Tag_FToolMenuEntry_Action
|
|
||||||
{
|
|
||||||
using type = FToolUIActionChoice FToolMenuEntry::*;
|
|
||||||
friend type GetPtr(Tag_FToolMenuEntry_Action);
|
|
||||||
};
|
|
||||||
template struct WingPrivateAccessor<Tag_FToolMenuEntry_Action, &FToolMenuEntry::Action>;
|
|
||||||
|
|
||||||
static const FToolUIActionChoice& GetAction(const FToolMenuEntry& Entry)
|
|
||||||
{
|
|
||||||
return Entry.*GetPtr(Tag_FToolMenuEntry_Action());
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----- FToolMenuEntry::Command -----
|
|
||||||
|
|
||||||
struct Tag_FToolMenuEntry_Command
|
|
||||||
{
|
|
||||||
using type = TSharedPtr<const FUICommandInfo> FToolMenuEntry::*;
|
|
||||||
friend type GetPtr(Tag_FToolMenuEntry_Command);
|
|
||||||
};
|
|
||||||
template struct WingPrivateAccessor<Tag_FToolMenuEntry_Command, &FToolMenuEntry::Command>;
|
|
||||||
|
|
||||||
static bool HasCommand(const FToolMenuEntry& Entry)
|
|
||||||
{
|
|
||||||
return Entry.*GetPtr(Tag_FToolMenuEntry_Command()) != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// Given a menu entry label, and a pin name (possibly empty),
|
// Given a menu entry label, and a pin name (possibly empty),
|
||||||
// generate a better label for an LLM to type. The goal here
|
// generate a better label for an LLM to type. The goal here
|
||||||
@@ -227,10 +180,10 @@ TArray<FToolMenuEntry> WingToolMenu::GetMenuItems(UEdGraphNode *Node, const FToo
|
|||||||
|
|
||||||
bool WingToolMenu::CanExecute(const FToolMenuEntry& Entry, const FToolMenuContext& Context)
|
bool WingToolMenu::CanExecute(const FToolMenuEntry& Entry, const FToolMenuContext& Context)
|
||||||
{
|
{
|
||||||
if (HasCommand(Entry))
|
if (WingHacks::HasCommand(Entry))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const FToolUIActionChoice& Choice = GetAction(Entry);
|
const FToolUIActionChoice& Choice = WingHacks::GetAction(Entry);
|
||||||
|
|
||||||
if (const FToolUIAction* ToolAction = Choice.GetToolUIAction())
|
if (const FToolUIAction* ToolAction = Choice.GetToolUIAction())
|
||||||
{
|
{
|
||||||
@@ -254,10 +207,10 @@ bool WingToolMenu::CanExecute(const FToolMenuEntry& Entry, const FToolMenuContex
|
|||||||
|
|
||||||
bool WingToolMenu::Execute(const FToolMenuEntry& Entry, const FToolMenuContext& Context)
|
bool WingToolMenu::Execute(const FToolMenuEntry& Entry, const FToolMenuContext& Context)
|
||||||
{
|
{
|
||||||
if (HasCommand(Entry))
|
if (WingHacks::HasCommand(Entry))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const FToolUIActionChoice& Choice = GetAction(Entry);
|
const FToolUIActionChoice& Choice = WingHacks::GetAction(Entry);
|
||||||
|
|
||||||
if (const FToolUIAction* ToolAction = Choice.GetToolUIAction())
|
if (const FToolUIAction* ToolAction = Choice.GetToolUIAction())
|
||||||
{
|
{
|
||||||
|
|||||||
23
Plugins/UEWingman/Source/UEWingman/Public/WingHacks.h
Normal file
23
Plugins/UEWingman/Source/UEWingman/Public/WingHacks.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
|
||||||
|
struct FToolMenuEntry;
|
||||||
|
struct FToolUIActionChoice;
|
||||||
|
class FBlueprintEditor;
|
||||||
|
|
||||||
|
// Utility class that uses the C++ template explicit-instantiation
|
||||||
|
// loophole to access private members of engine classes.
|
||||||
|
// See WingHacks.cpp for details on the technique.
|
||||||
|
class WingHacks
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Access FToolMenuEntry::Action (private member).
|
||||||
|
static const FToolUIActionChoice& GetAction(const FToolMenuEntry& Entry);
|
||||||
|
|
||||||
|
// Check whether FToolMenuEntry::Command (private member) is set.
|
||||||
|
static bool HasCommand(const FToolMenuEntry& Entry);
|
||||||
|
|
||||||
|
// Check FBlueprintEditor::bWasOpenedInDefaultsMode (private member).
|
||||||
|
static bool WasOpenedInDefaultsMode(FBlueprintEditor* Editor);
|
||||||
|
};
|
||||||
@@ -10,8 +10,7 @@ class UEdGraphPin;
|
|||||||
class UGraphNodeContextMenuContext;
|
class UGraphNodeContextMenuContext;
|
||||||
|
|
||||||
// Utilities for manipulating UToolMenu structures.
|
// Utilities for manipulating UToolMenu structures.
|
||||||
// Uses the C++ template explicit-instantiation loophole to
|
// Uses WingHacks for private member access.
|
||||||
// bypass access checks — see WingToolMenu.cpp for details.
|
|
||||||
class WingToolMenu
|
class WingToolMenu
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
Reference in New Issue
Block a user