Event dispatcher support complete

This commit is contained in:
2026-03-20 20:02:53 -04:00
parent 90b35f785e
commit 457c595081
4 changed files with 130 additions and 149 deletions

View File

@@ -1,142 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "WingServer.h"
#include "WingHandler.h"
#include "WingTypes.h"
#include "WingFetcher.h"
#include "WingJson.h"
#include "WingUtils.h"
#include "Engine/Blueprint.h"
#include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphPin.h"
#include "K2Node_FunctionEntry.h"
#include "K2Node_EditablePinBase.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "Blueprint_AddEventDispatcher.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
USTRUCT()
struct FDispatcherParamEntry
{
GENERATED_BODY()
UPROPERTY()
FString Name;
UPROPERTY()
FString Type;
};
UCLASS()
class UWing_Blueprint_AddEventDispatcher : public UObject, public IWingHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Description="Path to a blueprint, e.g. /Game/Foo/MyBlueprint"))
FString Blueprint;
UPROPERTY(meta=(Description="Name for the new event dispatcher"))
FString DispatcherName;
UPROPERTY(meta=(Optional, Description="Array of parameter objects, each with 'name' and 'type' fields"))
FWingJsonArray Parameters;
virtual FString GetDescription() const override
{
return TEXT("Create a new multicast event dispatcher on a Blueprint, optionally with parameters.");
}
virtual void Handle() override
{
WingFetcher F;
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
if (!BP) return;
FName DispatcherFName(*DispatcherName);
// Check for name uniqueness against existing variables
for (const FBPVariableDescription& Var : BP->NewVariables)
{
if (Var.VarName == DispatcherFName)
{
UWingServer::Printf(TEXT("Error: A variable or dispatcher named '%s' already exists.\n"), *DispatcherName);
return;
}
}
// Check against existing graphs (functions, macros, etc.)
if (!WingUtils::FindExactlyNoneNamed(DispatcherName, WingUtils::AllGraphs(BP), TEXT("Graph")))
return;
// Add a member variable with PC_MCDelegate pin type
FEdGraphPinType DelegateType;
DelegateType.PinCategory = UEdGraphSchema_K2::PC_MCDelegate;
if (!FBlueprintEditorUtils::AddMemberVariable(BP, DispatcherFName, DelegateType))
{
UWingServer::Printf(TEXT("Error: Failed to add delegate variable for '%s'.\n"), *DispatcherName);
return;
}
// Create the signature graph
const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();
UEdGraph* SigGraph = FBlueprintEditorUtils::CreateNewGraph(BP, DispatcherFName,
UEdGraph::StaticClass(), UEdGraphSchema_K2::StaticClass());
if (!SigGraph)
{
UWingServer::Print(TEXT("Error: Failed to create delegate signature graph.\n"));
return;
}
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);
// Add parameters if provided
int32 ParamCount = 0;
if (Parameters.Array.Num() > 0)
{
UK2Node_EditablePinBase* EntryNode = nullptr;
for (UK2Node_FunctionEntry* FE : WingUtils::AllNodes<UK2Node_FunctionEntry>(SigGraph))
{
EntryNode = FE;
break;
}
if (!EntryNode)
{
UWingServer::Print(TEXT("Error: Event dispatcher created but entry node not found — parameters could not be added.\n"));
return;
}
for (const TSharedPtr<FJsonValue>& ParamVal : Parameters.Array)
{
FDispatcherParamEntry Entry;
if (!WingJson::PopulateFromJson(FDispatcherParamEntry::StaticStruct(), &Entry, ParamVal)) return;
if (Entry.Name.IsEmpty() || Entry.Type.IsEmpty()) continue;
FEdGraphPinType PinType;
if (!UWingTypes::TextToType(Entry.Type, PinType))
return;
EntryNode->CreateUserDefinedPin(FName(*Entry.Name), PinType, EGPD_Output);
ParamCount++;
}
}
UWingServer::Printf(TEXT("Created event dispatcher '%s'"), *DispatcherName);
if (ParamCount > 0)
UWingServer::Printf(TEXT(" with %d parameter(s)"), ParamCount);
UWingServer::Print(TEXT(".\n"));
}
};

View File

@@ -27,7 +27,7 @@ public:
FString Blueprint; FString Blueprint;
UPROPERTY(meta=(Description="Name of the new event dispatcher")) UPROPERTY(meta=(Description="Name of the new event dispatcher"))
FString Name; FString Dispatcher;
UPROPERTY(meta=(Description="Arguments expressed as: int x,float y")) UPROPERTY(meta=(Description="Arguments expressed as: int x,float y"))
FString Arguments; FString Arguments;
@@ -44,9 +44,9 @@ public:
if (!BP) return; if (!BP) return;
// Check for valid proposed name // Check for valid proposed name
if (!WingUtils::FindExactlyNoneNamed(Name, BP->NewVariables, TEXT("Variable"))) return; if (!WingUtils::FindExactlyNoneNamed(Dispatcher, BP->NewVariables, TEXT("Variable"))) return;
if (!WingUtils::FindExactlyNoneNamed(Name, WingUtils::AllGraphs(BP), TEXT("Graph"))) return; if (!WingUtils::FindExactlyNoneNamed(Dispatcher, WingUtils::AllGraphs(BP), TEXT("Graph"))) return;
FString InternalName = WingUtils::CheckProposedName(Name); FString InternalName = WingUtils::CheckProposedName(Dispatcher);
if (InternalName.IsEmpty()) return; if (InternalName.IsEmpty()) return;
FName VarFName(InternalName); FName VarFName(InternalName);
@@ -58,7 +58,7 @@ public:
DelegateType.PinCategory = UEdGraphSchema_K2::PC_MCDelegate; DelegateType.PinCategory = UEdGraphSchema_K2::PC_MCDelegate;
if (!FBlueprintEditorUtils::AddMemberVariable(BP, VarFName, DelegateType)) if (!FBlueprintEditorUtils::AddMemberVariable(BP, VarFName, DelegateType))
{ {
UWingServer::Printf(TEXT("ERROR: Failed to add event dispatcher '%s' to %s\n"), *Name, *WingUtils::FormatName(BP)); UWingServer::Printf(TEXT("ERROR: Failed to add event dispatcher '%s' to %s\n"), *Dispatcher, *WingUtils::FormatName(BP));
return; return;
} }
@@ -68,7 +68,7 @@ public:
UEdGraph::StaticClass(), UEdGraphSchema_K2::StaticClass()); UEdGraph::StaticClass(), UEdGraphSchema_K2::StaticClass());
if (!SigGraph) if (!SigGraph)
{ {
UWingServer::Printf(TEXT("ERROR: Failed to create signature graph for '%s'\n"), *Name); UWingServer::Printf(TEXT("ERROR: Failed to create signature graph for '%s'\n"), *Dispatcher);
return; return;
} }
@@ -90,6 +90,6 @@ public:
} }
if (!WingFunctionArgs::SetArgs(EntryNode.Get(), Arguments)) return; if (!WingFunctionArgs::SetArgs(EntryNode.Get(), Arguments)) return;
UWingServer::Printf(TEXT("Created event dispatcher %s in %s\n"), *Name, *WingUtils::FormatName(BP)); UWingServer::Printf(TEXT("Created event dispatcher %s in %s\n"), *Dispatcher, *WingUtils::FormatName(BP));
} }
}; };

View File

@@ -0,0 +1,59 @@
#pragma once
#include "CoreMinimal.h"
#include "WingServer.h"
#include "WingHandler.h"
#include "WingFetcher.h"
#include "WingUtils.h"
#include "Engine/Blueprint.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "BlueprintDispatcher_Delete.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS()
class UWing_BlueprintDispatcher_Delete : 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 delete"))
FString Dispatcher;
virtual FString GetDescription() const override
{
return TEXT("Delete an event dispatcher from a Blueprint.");
}
virtual void Handle() override
{
WingFetcher F;
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
if (!BP) return;
FBPVariableDescription* Var = WingUtils::FindExactlyOneNamed(Dispatcher, BP->NewVariables, TEXT("Dispatcher"));
if (!Var) return;
TObjectPtr<UEdGraph>* SigGraph = WingUtils::FindExactlyOneNamed(Dispatcher, BP->DelegateSignatureGraphs, TEXT("Dispatcher Signature Graph"));
if (!SigGraph) return;
UEdGraph* Graph = *SigGraph;
FName VarFName = Var->VarName;
BP->Modify();
Graph->Modify();
// Remove the member variable (also destroys referencing nodes)
FBlueprintEditorUtils::RemoveMemberVariable(BP, VarFName);
// Remove the signature graph
FBlueprintEditorUtils::RemoveGraph(BP, Graph, EGraphRemoveFlags::Recompile);
UWingServer::Printf(TEXT("Deleted event dispatcher %s from %s\n"), *Dispatcher, *WingUtils::FormatName(BP));
}
};

View File

@@ -0,0 +1,64 @@
#pragma once
#include "CoreMinimal.h"
#include "WingServer.h"
#include "WingHandler.h"
#include "WingFetcher.h"
#include "WingUtils.h"
#include "WingFunctionArgs.h"
#include "Engine/Blueprint.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "BlueprintDispatcher_Modify.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS()
class UWing_BlueprintDispatcher_Modify : 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 modify"))
FString Dispatcher;
UPROPERTY(meta=(Description="New arguments expressed as: int x,float y"))
FString Arguments;
virtual FString GetDescription() const override
{
return TEXT("Modify the arguments of an existing Blueprint event dispatcher.");
}
virtual void Handle() override
{
WingFetcher F;
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
if (!BP) return;
FBPVariableDescription* Var = WingUtils::FindExactlyOneNamed(Dispatcher, BP->NewVariables, TEXT("Dispatcher"));
if (!Var) return;
TObjectPtr<UEdGraph>* SigGraph = WingUtils::FindExactlyOneNamed(Dispatcher, BP->DelegateSignatureGraphs, TEXT("Dispatcher Signature Graph"));
if (!SigGraph) return;
// Make sure the argument types are valid.
if (!WingFunctionArgs::CheckArgs(Arguments)) return;
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;
}
if (!WingFunctionArgs::SetArgs(EntryNode.Get(), Arguments)) return;
UWingServer::Printf(TEXT("Modified event dispatcher %s in %s\n"), *Dispatcher, *WingUtils::FormatName(BP));
}
};