Halfway done with Dispatcher stuff
This commit is contained in:
BIN
Content/Testing/BP_Test.uasset
LFS
BIN
Content/Testing/BP_Test.uasset
LFS
Binary file not shown.
@@ -0,0 +1,100 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "WingServer.h"
|
||||||
|
#include "WingHandler.h"
|
||||||
|
#include "WingFetcher.h"
|
||||||
|
#include "WingJson.h"
|
||||||
|
#include "WingBlueprintVar.h"
|
||||||
|
#include "WingUtils.h"
|
||||||
|
#include "Engine/Blueprint.h"
|
||||||
|
#include "EdGraphSchema_K2.h"
|
||||||
|
#include "Kismet2/BlueprintEditorUtils.h"
|
||||||
|
#include "BlueprintDispatcher_Create.generated.h"
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
UCLASS()
|
||||||
|
class UWing_BlueprintDispatcher_Create : public UObject, public IWingHandler
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPROPERTY(meta=(Description="Blueprint name or package path"))
|
||||||
|
FString Blueprint;
|
||||||
|
|
||||||
|
UPROPERTY(meta=(Description="Name of the new event dispatcher"))
|
||||||
|
FString Name;
|
||||||
|
|
||||||
|
UPROPERTY(meta=(Optional, Description="Configuration: DelegateArgs, Category, Description, InstanceEditable, BlueprintReadOnly, Private, etc."))
|
||||||
|
FWingJsonObject Config;
|
||||||
|
|
||||||
|
virtual FString GetDescription() const override
|
||||||
|
{
|
||||||
|
return TEXT("Add a new event dispatcher to a Blueprint. Pass Config to set parameters, category, flags, etc.");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Handle() override
|
||||||
|
{
|
||||||
|
WingFetcher F;
|
||||||
|
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
|
||||||
|
if (!BP) return;
|
||||||
|
|
||||||
|
// Check for duplicate variable name
|
||||||
|
FName VarFName(*WingUtils::UnsanitizeName(Name));
|
||||||
|
if (FBlueprintEditorUtils::FindNewVariableIndex(BP, VarFName) != INDEX_NONE)
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR: Variable or dispatcher '%s' already exists in %s\n"), *Name, *WingUtils::FormatName(BP));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (UEdGraph* Graph : WingUtils::AllGraphs(BP))
|
||||||
|
{
|
||||||
|
if (Graph->GetFName() == VarFName)
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR: A graph named '%s' already exists in %s\n"), *Name, *WingUtils::FormatName(BP));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the delegate variable
|
||||||
|
FEdGraphPinType DelegateType;
|
||||||
|
DelegateType.PinCategory = UEdGraphSchema_K2::PC_MCDelegate;
|
||||||
|
if (!FBlueprintEditorUtils::AddMemberVariable(BP, VarFName, DelegateType))
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR: Failed to add event dispatcher '%s' to %s\n"), *Name, *WingUtils::FormatName(BP));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the signature graph
|
||||||
|
const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
|
||||||
|
UEdGraph* SigGraph = FBlueprintEditorUtils::CreateNewGraph(BP, VarFName,
|
||||||
|
UEdGraph::StaticClass(), UEdGraphSchema_K2::StaticClass());
|
||||||
|
if (!SigGraph)
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR: Failed to create signature graph for '%s'\n"), *Name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SigGraph->bEditable = false;
|
||||||
|
K2Schema->CreateDefaultNodesForGraph(*SigGraph);
|
||||||
|
K2Schema->CreateFunctionGraphTerminators(*SigGraph, static_cast<UClass*>(nullptr));
|
||||||
|
K2Schema->AddExtraFunctionFlags(SigGraph, FUNC_BlueprintCallable | FUNC_BlueprintEvent | FUNC_Public);
|
||||||
|
K2Schema->MarkFunctionEntryAsEditable(SigGraph, true);
|
||||||
|
BP->DelegateSignatureGraphs.Add(SigGraph);
|
||||||
|
|
||||||
|
// Find the newly created variable and apply config
|
||||||
|
FWingBlueprintVar Editor(BP, Name);
|
||||||
|
if (Editor.NotFound()) return;
|
||||||
|
|
||||||
|
if (Config.Json && Config.Json->Values.Num() > 0)
|
||||||
|
{
|
||||||
|
if (!Editor.ApplyJson(Config.Json.Get()))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UWingServer::Printf(TEXT("Created event dispatcher %s in %s\n"), *Name, *WingUtils::FormatName(BP));
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "WingServer.h"
|
||||||
|
#include "WingHandler.h"
|
||||||
|
#include "WingFetcher.h"
|
||||||
|
#include "WingUtils.h"
|
||||||
|
#include "WingBlueprintVar.h"
|
||||||
|
#include "Engine/Blueprint.h"
|
||||||
|
#include "BlueprintDispatcher_Dump.generated.h"
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
UCLASS()
|
||||||
|
class UWing_BlueprintDispatcher_Dump : public UObject, public IWingHandler
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPROPERTY(meta=(Description="Blueprint name or package path"))
|
||||||
|
FString Blueprint;
|
||||||
|
|
||||||
|
UPROPERTY(meta=(Description="Name of the event dispatcher to inspect"))
|
||||||
|
FString Dispatcher;
|
||||||
|
|
||||||
|
virtual FString GetDescription() const override
|
||||||
|
{
|
||||||
|
return TEXT("Show all editable properties of a Blueprint event dispatcher.");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Handle() override
|
||||||
|
{
|
||||||
|
WingFetcher F;
|
||||||
|
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
|
||||||
|
if (!BP) return;
|
||||||
|
|
||||||
|
FWingBlueprintVar Editor(BP, Dispatcher);
|
||||||
|
if (Editor.NotFound()) return;
|
||||||
|
if (!Editor.IsEventDispatcher())
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR: '%s' is not an event dispatcher\n"), *Dispatcher);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UWingServer::Printf(TEXT("Event dispatcher %s in %s:\n"), *Dispatcher, *WingUtils::FormatName(BP));
|
||||||
|
Editor.Dump();
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -67,6 +67,7 @@ public:
|
|||||||
UWingServer::Print(TEXT("\nVariables:\n"));
|
UWingServer::Print(TEXT("\nVariables:\n"));
|
||||||
for (const FBPVariableDescription& V : BP->NewVariables)
|
for (const FBPVariableDescription& V : BP->NewVariables)
|
||||||
{
|
{
|
||||||
|
if (V.VarType.PinCategory == UEdGraphSchema_K2::PC_MCDelegate) continue;
|
||||||
UWingServer::Printf(TEXT(" %s %s"),
|
UWingServer::Printf(TEXT(" %s %s"),
|
||||||
*UWingTypes::TypeToText(V.VarType),
|
*UWingTypes::TypeToText(V.VarType),
|
||||||
*WingUtils::FormatName(V));
|
*WingUtils::FormatName(V));
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
#include "WingBlueprintVar.h"
|
#include "WingBlueprintVar.h"
|
||||||
|
#include "WingFunctionArgs.h"
|
||||||
#include "WingJson.h"
|
#include "WingJson.h"
|
||||||
#include "WingServer.h"
|
#include "WingServer.h"
|
||||||
#include "WingTypes.h"
|
#include "WingTypes.h"
|
||||||
#include "WingUtils.h"
|
#include "WingUtils.h"
|
||||||
#include "EdGraphSchema_K2.h"
|
#include "EdGraphSchema_K2.h"
|
||||||
|
#include "K2Node_EditablePinBase.h"
|
||||||
#include "Kismet2/BlueprintEditorUtils.h"
|
#include "Kismet2/BlueprintEditorUtils.h"
|
||||||
|
|
||||||
FWingBlueprintVar::FWingBlueprintVar(UBlueprint* BP, const FString& VarName)
|
FWingBlueprintVar::FWingBlueprintVar(UBlueprint* BP, const FString& VarName)
|
||||||
@@ -11,13 +13,34 @@ FWingBlueprintVar::FWingBlueprintVar(UBlueprint* BP, const FString& VarName)
|
|||||||
Desc = WingUtils::FindExactlyOneNamed(VarName, BP->NewVariables);
|
Desc = WingUtils::FindExactlyOneNamed(VarName, BP->NewVariables);
|
||||||
if (!Desc) return;
|
if (!Desc) return;
|
||||||
|
|
||||||
// Try to find the default value property on the CDO.
|
if (Desc->VarType.PinCategory == UEdGraphSchema_K2::PC_MCDelegate)
|
||||||
if (BP->GeneratedClass)
|
|
||||||
{
|
{
|
||||||
UObject* CDO = BP->GeneratedClass->GetDefaultObject();
|
// Find the matching signature graph by name.
|
||||||
FProperty* Prop = BP->GeneratedClass->FindPropertyByName(Desc->VarName);
|
for (UEdGraph* Graph : BP->DelegateSignatureGraphs)
|
||||||
if (CDO && Prop)
|
{
|
||||||
DefaultValueProp = FWingProperty(Prop, CDO);
|
if (Graph->GetFName() == Desc->VarName)
|
||||||
|
{
|
||||||
|
SigGraph = Graph;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!SigGraph)
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR: Signature graph not found for event dispatcher '%s'\n"), *VarName);
|
||||||
|
Desc = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Try to find the default value property on the CDO.
|
||||||
|
if (BP->GeneratedClass)
|
||||||
|
{
|
||||||
|
UObject* CDO = BP->GeneratedClass->GetDefaultObject();
|
||||||
|
FProperty* Prop = BP->GeneratedClass->FindPropertyByName(Desc->VarName);
|
||||||
|
if (CDO && Prop)
|
||||||
|
DefaultValueProp = FWingProperty(Prop, CDO);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,6 +48,7 @@ void FWingBlueprintVar::Dump()
|
|||||||
{
|
{
|
||||||
LoadFlags();
|
LoadFlags();
|
||||||
LoadDefault();
|
LoadDefault();
|
||||||
|
LoadDelegateArgs();
|
||||||
TArray<FWingProperty> Props = MergedProperties();
|
TArray<FWingProperty> Props = MergedProperties();
|
||||||
for (FWingProperty& P : Props)
|
for (FWingProperty& P : Props)
|
||||||
{
|
{
|
||||||
@@ -38,6 +62,7 @@ void FWingBlueprintVar::Dump()
|
|||||||
bool FWingBlueprintVar::ApplyJson(const FJsonObject* Json)
|
bool FWingBlueprintVar::ApplyJson(const FJsonObject* Json)
|
||||||
{
|
{
|
||||||
bool bHasDefault = Json->HasField(TEXT("DefaultValue"));
|
bool bHasDefault = Json->HasField(TEXT("DefaultValue"));
|
||||||
|
bool bHasDelegateArgs = Json->HasField(TEXT("DelegateArgs"));
|
||||||
bool bHasType = Json->HasField(TEXT("VarType"));
|
bool bHasType = Json->HasField(TEXT("VarType"));
|
||||||
if (bHasDefault && bHasType)
|
if (bHasDefault && bHasType)
|
||||||
{
|
{
|
||||||
@@ -49,6 +74,7 @@ bool FWingBlueprintVar::ApplyJson(const FJsonObject* Json)
|
|||||||
}
|
}
|
||||||
|
|
||||||
LoadFlags();
|
LoadFlags();
|
||||||
|
LoadDelegateArgs();
|
||||||
|
|
||||||
TArray<FWingProperty> Props = MergedProperties();
|
TArray<FWingProperty> Props = MergedProperties();
|
||||||
if (!WingJson::PopulateFromJson(Props, Json, true))
|
if (!WingJson::PopulateFromJson(Props, Json, true))
|
||||||
@@ -56,7 +82,9 @@ bool FWingBlueprintVar::ApplyJson(const FJsonObject* Json)
|
|||||||
|
|
||||||
SaveFlags();
|
SaveFlags();
|
||||||
if (bHasDefault)
|
if (bHasDefault)
|
||||||
return SaveDefault();
|
if (!SaveDefault()) return false;
|
||||||
|
if (bHasDelegateArgs)
|
||||||
|
if (!SaveDelegateArgs()) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +110,18 @@ void FWingBlueprintVar::LoadDefault()
|
|||||||
DefaultValue.Empty();
|
DefaultValue.Empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FWingBlueprintVar::LoadDelegateArgs()
|
||||||
|
{
|
||||||
|
if (!SigGraph) return;
|
||||||
|
TWeakObjectPtr<UK2Node_EditablePinBase> EntryNode;
|
||||||
|
TWeakObjectPtr<UK2Node_EditablePinBase> ResultNode;
|
||||||
|
FBlueprintEditorUtils::GetEntryAndResultNodes(SigGraph, EntryNode, ResultNode);
|
||||||
|
if (EntryNode.IsValid())
|
||||||
|
DelegateArgs = WingFunctionArgs::GetArgs(EntryNode.Get());
|
||||||
|
else
|
||||||
|
DelegateArgs.Empty();
|
||||||
|
}
|
||||||
|
|
||||||
void FWingBlueprintVar::SaveFlags()
|
void FWingBlueprintVar::SaveFlags()
|
||||||
{
|
{
|
||||||
// CPF flags
|
// CPF flags
|
||||||
@@ -125,6 +165,20 @@ bool FWingBlueprintVar::SaveDefault()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FWingBlueprintVar::SaveDelegateArgs()
|
||||||
|
{
|
||||||
|
if (!SigGraph) return true;
|
||||||
|
TWeakObjectPtr<UK2Node_EditablePinBase> EntryNode;
|
||||||
|
TWeakObjectPtr<UK2Node_EditablePinBase> ResultNode;
|
||||||
|
FBlueprintEditorUtils::GetEntryAndResultNodes(SigGraph, EntryNode, ResultNode);
|
||||||
|
if (!EntryNode.IsValid())
|
||||||
|
{
|
||||||
|
UWingServer::Print(TEXT("ERROR: Entry node not found in delegate signature graph\n"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return WingFunctionArgs::SetArgs(EntryNode.Get(), DelegateArgs);
|
||||||
|
}
|
||||||
|
|
||||||
TArray<FWingProperty> FWingBlueprintVar::MergedProperties()
|
TArray<FWingProperty> FWingBlueprintVar::MergedProperties()
|
||||||
{
|
{
|
||||||
TArray<FWingProperty> Props = FWingProperty::GetAll(
|
TArray<FWingProperty> Props = FWingProperty::GetAll(
|
||||||
@@ -139,9 +193,20 @@ TArray<FWingProperty> FWingBlueprintVar::MergedProperties()
|
|||||||
Props.Append(FWingProperty::GetAll(
|
Props.Append(FWingProperty::GetAll(
|
||||||
FWingBlueprintVar::StaticStruct(), this, (EPropertyFlags)0));
|
FWingBlueprintVar::StaticStruct(), this, (EPropertyFlags)0));
|
||||||
|
|
||||||
// Remove DefaultValue if we don't have a CDO property to back it.
|
if (SigGraph)
|
||||||
if (!DefaultValueProp)
|
{
|
||||||
|
FWingProperty::Remove(Props, TEXT("VarType"));
|
||||||
FWingProperty::Remove(Props, TEXT("DefaultValue"));
|
FWingProperty::Remove(Props, TEXT("DefaultValue"));
|
||||||
|
FWingProperty::Remove(Props, TEXT("ExposeOnSpawn"));
|
||||||
|
FWingProperty::Remove(Props, TEXT("ExposeToCinematics"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FWingProperty::Remove(Props, TEXT("DelegateArgs"));
|
||||||
|
// Remove DefaultValue if we don't have a CDO property to back it.
|
||||||
|
if (!DefaultValueProp)
|
||||||
|
FWingProperty::Remove(Props, TEXT("DefaultValue"));
|
||||||
|
}
|
||||||
|
|
||||||
return Props;
|
return Props;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,13 @@ struct FWingBlueprintVar
|
|||||||
|
|
||||||
FBPVariableDescription* Desc = nullptr;
|
FBPVariableDescription* Desc = nullptr;
|
||||||
FWingProperty DefaultValueProp;
|
FWingProperty DefaultValueProp;
|
||||||
|
UEdGraph* SigGraph = nullptr;
|
||||||
|
|
||||||
FWingBlueprintVar() = default;
|
FWingBlueprintVar() = default;
|
||||||
FWingBlueprintVar(UBlueprint* BP, const FString& VarName);
|
FWingBlueprintVar(UBlueprint* BP, const FString& VarName);
|
||||||
|
|
||||||
bool NotFound() const { return Desc == nullptr; }
|
bool NotFound() const { return Desc == nullptr; }
|
||||||
|
bool IsEventDispatcher() const { return SigGraph != nullptr; }
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, meta=(Optional, Description="Default value in Unreal text format"))
|
UPROPERTY(EditAnywhere, meta=(Optional, Description="Default value in Unreal text format"))
|
||||||
FString DefaultValue;
|
FString DefaultValue;
|
||||||
@@ -43,6 +45,9 @@ struct FWingBlueprintVar
|
|||||||
UPROPERTY(EditAnywhere, meta=(Optional, Description="Expose to cinematics/sequencer"))
|
UPROPERTY(EditAnywhere, meta=(Optional, Description="Expose to cinematics/sequencer"))
|
||||||
bool ExposeToCinematics = false;
|
bool ExposeToCinematics = false;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, meta=(Optional, Description="Delegate parameters, e.g. 'int x,float y'"))
|
||||||
|
FString DelegateArgs;
|
||||||
|
|
||||||
// Load from Desc, populate from JSON, save back to Desc.
|
// Load from Desc, populate from JSON, save back to Desc.
|
||||||
bool ApplyJson(const FJsonObject* Json);
|
bool ApplyJson(const FJsonObject* Json);
|
||||||
|
|
||||||
@@ -52,7 +57,9 @@ struct FWingBlueprintVar
|
|||||||
private:
|
private:
|
||||||
void LoadFlags();
|
void LoadFlags();
|
||||||
void LoadDefault();
|
void LoadDefault();
|
||||||
|
void LoadDelegateArgs();
|
||||||
void SaveFlags();
|
void SaveFlags();
|
||||||
bool SaveDefault();
|
bool SaveDefault();
|
||||||
|
bool SaveDelegateArgs();
|
||||||
TArray<FWingProperty> MergedProperties();
|
TArray<FWingProperty> MergedProperties();
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user