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/MaterialExpression.h"
|
||||
#include "Kismet2/BlueprintEditorUtils.h"
|
||||
#include "BlueprintEditor.h"
|
||||
#include "MaterialEditingLibrary.h"
|
||||
#include "Subsystems/AssetEditorSubsystem.h"
|
||||
#include "Engine/Blueprint.h"
|
||||
#include "WingHacks.h"
|
||||
|
||||
void FWingNotifier::AddTouchedObject(UObject* Obj)
|
||||
{
|
||||
@@ -20,6 +23,7 @@ void FWingNotifier::AddTouchedObject(UObject* Obj)
|
||||
|
||||
void FWingNotifier::SendNotifications()
|
||||
{
|
||||
UAssetEditorSubsystem* EditorSubsys = GEditor->GetEditorSubsystem<UAssetEditorSubsystem>();
|
||||
TSet<UEdGraphNode*> Nodes;
|
||||
TSet<UEdGraph*> Graphs;
|
||||
TSet<UMaterial*> Materials;
|
||||
@@ -59,7 +63,19 @@ void FWingNotifier::SendNotifications()
|
||||
for (UMaterial *Material : Materials)
|
||||
UMaterialEditingLibrary::RebuildMaterialInstanceEditors(Material);
|
||||
for (UBlueprint *Blueprint : Blueprints)
|
||||
{
|
||||
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);
|
||||
// FKismetEditorUtilities::CompileBlueprint(BP);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "WingToolMenu.h"
|
||||
#include "WingHacks.h"
|
||||
#include "ToolMenuEntry.h"
|
||||
#include "ToolMenuDelegates.h"
|
||||
#include "ToolMenuContext.h"
|
||||
@@ -8,54 +9,6 @@
|
||||
#include "EdGraphSchema_K2.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),
|
||||
// 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)
|
||||
{
|
||||
if (HasCommand(Entry))
|
||||
if (WingHacks::HasCommand(Entry))
|
||||
return false;
|
||||
|
||||
const FToolUIActionChoice& Choice = GetAction(Entry);
|
||||
const FToolUIActionChoice& Choice = WingHacks::GetAction(Entry);
|
||||
|
||||
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)
|
||||
{
|
||||
if (HasCommand(Entry))
|
||||
if (WingHacks::HasCommand(Entry))
|
||||
return false;
|
||||
|
||||
const FToolUIActionChoice& Choice = GetAction(Entry);
|
||||
const FToolUIActionChoice& Choice = WingHacks::GetAction(Entry);
|
||||
|
||||
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;
|
||||
|
||||
// Utilities for manipulating UToolMenu structures.
|
||||
// Uses the C++ template explicit-instantiation loophole to
|
||||
// bypass access checks — see WingToolMenu.cpp for details.
|
||||
// Uses WingHacks for private member access.
|
||||
class WingToolMenu
|
||||
{
|
||||
public:
|
||||
|
||||
Reference in New Issue
Block a user