Add support for Blueprint Overrides, and make more progress on the hotkey widget.
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
* UE Wingman Widgets: cannot edit 'Is Variable' flag or widget name.
|
||||
|
||||
TSharedPtr<INameValidatorInterface> NameValidator = MakeShareable(new FKismetNameValidator(Blueprint, OldObjectName));
|
||||
* UE Wingman Function Overrides.
|
||||
|
||||
|
||||
* Keyboard Event Handling
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "WingServer.h"
|
||||
#include "WingBasics.h"
|
||||
#include "WingFetcher.h"
|
||||
#include "WingUtils.h"
|
||||
#include "Engine/Blueprint.h"
|
||||
#include "EdGraphSchema_K2.h"
|
||||
#include "Kismet2/BlueprintEditorUtils.h"
|
||||
#include "BlueprintOverride_Add.generated.h"
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
UCLASS()
|
||||
class UWing_BlueprintOverride_Add : public UWingHandler
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UPROPERTY(EditAnywhere, meta=(Description="Blueprint path"))
|
||||
FString Blueprint;
|
||||
|
||||
UPROPERTY(EditAnywhere, meta=(Description="Function to override, in Class|Function format"))
|
||||
FString Function;
|
||||
|
||||
virtual void Register() override
|
||||
{
|
||||
UWingServer::AddHandler(this,
|
||||
TEXT("Add a function override to a Blueprint."));
|
||||
}
|
||||
|
||||
virtual void Handle() override
|
||||
{
|
||||
WingFetcher F(WingOut::Stdout);
|
||||
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
|
||||
if (!BP) return;
|
||||
|
||||
// Find the function by matching against the menu string format (Class|Function)
|
||||
TArray<UFunction*> Overridable = WingUtils::GetOverridableFunctions(BP);
|
||||
UFunction* OverrideFunc = nullptr;
|
||||
for (UFunction* Candidate : Overridable)
|
||||
{
|
||||
FString MenuString = WingUtils::GetFunctionMenuString(Candidate);
|
||||
if (MenuString.Equals(Function, ESearchCase::IgnoreCase))
|
||||
{
|
||||
OverrideFunc = Candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!OverrideFunc)
|
||||
{
|
||||
WingOut::Stdout.Printf(TEXT("ERROR: '%s' is not an overridable function in this Blueprint.\n"), *Function);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if it already exists
|
||||
FName FuncName = OverrideFunc->GetFName();
|
||||
TSet<FName> ExistingNames;
|
||||
FBlueprintEditorUtils::GetAllGraphNames(BP, ExistingNames);
|
||||
if (ExistingNames.Contains(FuncName))
|
||||
{
|
||||
WingOut::Stdout.Printf(TEXT("ERROR: Override graph '%s' already exists.\n"), *Function);
|
||||
return;
|
||||
}
|
||||
|
||||
UClass* OverrideFuncClass = WingUtils::GetFunctionClass(OverrideFunc);
|
||||
|
||||
UEdGraph* NewGraph = FBlueprintEditorUtils::CreateNewGraph(BP, FuncName,
|
||||
UEdGraph::StaticClass(), UEdGraphSchema_K2::StaticClass());
|
||||
if (!NewGraph)
|
||||
{
|
||||
WingOut::Stdout.Print(TEXT("ERROR: Failed to create graph.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
FBlueprintEditorUtils::AddFunctionGraph(BP, NewGraph, /*bIsUserCreated=*/false, OverrideFuncClass);
|
||||
|
||||
WingOut::Stdout.Printf(TEXT("Created override: %s\n"), *WingUtils::FormatName(NewGraph));
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "WingServer.h"
|
||||
#include "WingBasics.h"
|
||||
#include "WingFetcher.h"
|
||||
#include "WingUtils.h"
|
||||
#include "Engine/Blueprint.h"
|
||||
#include "Kismet2/BlueprintEditorUtils.h"
|
||||
#include "BlueprintOverride_ShowMenu.generated.h"
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
UCLASS()
|
||||
class UWing_BlueprintOverride_ShowMenu : public UWingHandler
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UPROPERTY(EditAnywhere, meta=(Description="Blueprint path"))
|
||||
FString Blueprint;
|
||||
|
||||
virtual void Register() override
|
||||
{
|
||||
UWingServer::AddHandler(this,
|
||||
TEXT("Show the functions that can be overridden in a Blueprint."));
|
||||
}
|
||||
|
||||
virtual void Handle() override
|
||||
{
|
||||
WingFetcher F(WingOut::Stdout);
|
||||
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
|
||||
if (!BP) return;
|
||||
|
||||
TArray<UFunction*> Results = WingUtils::GetOverridableFunctions(BP);
|
||||
for (UFunction *Func : Results)
|
||||
{
|
||||
UClass *Class = WingUtils::GetFunctionClass(Func);
|
||||
WingOut::Stdout.Print(WingUtils::GetFunctionMenuString(Func));
|
||||
WingOut::Stdout.Print(TEXT("\n"));
|
||||
}
|
||||
if (Results.IsEmpty())
|
||||
WingOut::Stdout.Print(TEXT("No overridable functions.\n"));
|
||||
}
|
||||
};
|
||||
@@ -33,9 +33,10 @@ FName FWingGraphAction::GetSpawnerOwnerClass(const UBlueprintNodeSpawner* Spawne
|
||||
|
||||
if (const UBlueprintVariableNodeSpawner* VariableSpawner = Cast<UBlueprintVariableNodeSpawner>(Spawner))
|
||||
{
|
||||
if (VariableSpawner->IsLocalVariable()) return FName(TEXT("LocalVariable"));
|
||||
return GetPropertyClassName(VariableSpawner->GetVarProperty());
|
||||
}
|
||||
|
||||
|
||||
if (const UBlueprintDelegateNodeSpawner* DelegateSpawner = Cast<UBlueprintDelegateNodeSpawner>(Spawner))
|
||||
{
|
||||
return GetPropertyClassName(DelegateSpawner->GetDelegateProperty());
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
#include "WidgetBlueprint.h"
|
||||
#include "Blueprint/WidgetTree.h"
|
||||
|
||||
// Blueprint override helpers
|
||||
#include "EdGraphSchema_K2.h"
|
||||
#include "ObjectEditorUtils.h"
|
||||
|
||||
// Reparent validation
|
||||
#include "Engine/LevelScriptActor.h"
|
||||
#include "Animation/AnimInstance.h"
|
||||
@@ -403,6 +407,79 @@ bool WingUtils::CheckNewObjectNotNull(UObject *Obj, const TCHAR *Kind, WingOut E
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Blueprint override helpers
|
||||
// ============================================================
|
||||
|
||||
bool WingUtils::CanBlueprintOverride(UBlueprint* BP, const UFunction* Function)
|
||||
{
|
||||
if (!Function) return false;
|
||||
if (!UEdGraphSchema_K2::CanKismetOverrideFunction(Function)) return false;
|
||||
UClass* HiddenFromClass = BP->SkeletonGeneratedClass ? BP->SkeletonGeneratedClass->GetSuperClass() : BP->ParentClass.Get();
|
||||
if (HiddenFromClass && FObjectEditorUtils::IsFunctionHiddenFromClass(Function, HiddenFromClass)) return false;
|
||||
if (Function->HasAnyFunctionFlags(FUNC_Private)) return false;
|
||||
if (!BP->AllowFunctionOverride(Function)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
TArray<UFunction*> WingUtils::GetOverridableFunctions(UBlueprint *BP)
|
||||
{
|
||||
TArray<UFunction *> Candidates, Results;
|
||||
TSet<UFunction*> Seen;
|
||||
|
||||
UClass* ParentClass = BP->SkeletonGeneratedClass ? BP->SkeletonGeneratedClass->GetSuperClass() : BP->ParentClass.Get();
|
||||
for (TFieldIterator<UFunction> FunctionIt(ParentClass, EFieldIteratorFlags::IncludeSuper); FunctionIt; ++FunctionIt)
|
||||
{
|
||||
Candidates.Add(*FunctionIt);
|
||||
}
|
||||
for (const FBPInterfaceDescription& InterfaceDesc : BP->ImplementedInterfaces)
|
||||
{
|
||||
UClass* InterfaceClass = InterfaceDesc.Interface.Get();
|
||||
if (!InterfaceClass) continue;
|
||||
for (TFieldIterator<UFunction> FunctionIt(InterfaceClass, EFieldIteratorFlags::IncludeSuper); FunctionIt; ++FunctionIt)
|
||||
{
|
||||
Candidates.Add(*FunctionIt);
|
||||
}
|
||||
}
|
||||
for (UClass* TempClass = BP->ParentClass.Get(); TempClass; TempClass = TempClass->GetSuperClass())
|
||||
{
|
||||
for (const FImplementedInterface& Interface : TempClass->Interfaces)
|
||||
{
|
||||
for (TFieldIterator<UFunction> FunctionIt(Interface.Class, EFieldIteratorFlags::IncludeSuper); FunctionIt; ++FunctionIt)
|
||||
{
|
||||
Candidates.Add(*FunctionIt);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (UFunction *Candidate : Candidates)
|
||||
{
|
||||
if (!Seen.Contains(Candidate))
|
||||
{
|
||||
Seen.Add(Candidate);
|
||||
if (CanBlueprintOverride(BP, Candidate)) Results.Add(Candidate);
|
||||
}
|
||||
}
|
||||
return Results;
|
||||
}
|
||||
|
||||
UClass *WingUtils::GetFunctionClass(UFunction *Func)
|
||||
{
|
||||
UClass *Class = Func->GetOuterUClass();
|
||||
UBlueprintGeneratedClass *BPGC = Cast<UBlueprintGeneratedClass>(Class);
|
||||
if (BPGC) return BPGC->GetAuthoritativeClass();
|
||||
else return Class;
|
||||
}
|
||||
|
||||
FString WingUtils::GetFunctionMenuString(UFunction *Func)
|
||||
{
|
||||
UClass *Class = GetFunctionClass(Func);
|
||||
TStringBuilder<256> Result;
|
||||
Result.Append(FormatName(Class));
|
||||
Result.AppendChar('|');
|
||||
Result.Append(FormatName(Func));
|
||||
return Result.ToString();
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Reparent validation
|
||||
// ============================================================
|
||||
|
||||
@@ -280,6 +280,12 @@ public:
|
||||
static FString GetHandlerName(UClass* HandlerClass);
|
||||
static FString GetHandlerGroup(UClass* HandlerClass);
|
||||
|
||||
// ----- Blueprint override helpers -----
|
||||
static bool CanBlueprintOverride(UBlueprint* BP, const UFunction* Function);
|
||||
static TArray<UFunction*> GetOverridableFunctions(UBlueprint *BP);
|
||||
static UClass *GetFunctionClass(UFunction *Func);
|
||||
static FString GetFunctionMenuString(UFunction *Func);
|
||||
|
||||
// ----- Reparent validation -----
|
||||
static bool CanReparentBlueprint(UClass* CurrentGenerated, UClass* Proposed);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user