#pragma once #include "CoreMinimal.h" #include "WingServer.h" #include "WingHandler.h" #include "WingFetcher.h" #include "WingJson.h" #include "WingUtils.h" #include "EdGraph/EdGraph.h" #include "EdGraph/EdGraphNode.h" #include "EdGraph/EdGraphSchema.h" #include "GraphNode_Create.generated.h" // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- USTRUCT() struct FSpawnNodeEntry { GENERATED_BODY() UPROPERTY() FString ActionName; UPROPERTY() int32 PosX = 0; UPROPERTY() int32 PosY = 0; }; UCLASS() class UWing_GraphNode_Create : public UObject, public IWingHandler { GENERATED_BODY() public: UPROPERTY(meta=(Description="Target graph")) FString Graph; UPROPERTY(meta=(Description="Array of {Type, posX, posY} objects. Use GraphNode_SearchTypes to find types.")) FWingJsonArray Nodes; virtual FString GetDescription() const override { return TEXT("Create nodes using the editor's action database. " "Use GraphNode_SearchTypes to find types."); } virtual void Handle() override { WingFetcher F; UEdGraph* TargetGraph = F.Walk(Graph).Cast(); if (!TargetGraph) return; int32 SuccessCount = 0; int32 TotalCount = Nodes.Array.Num(); for (const TSharedPtr& NodeVal : Nodes.Array) { FSpawnNodeEntry Entry; if (!WingJson::PopulateFromJson(FSpawnNodeEntry::StaticStruct(), &Entry, NodeVal)) continue; // Find the action by exact full name TArray> Matches = WingUtils::SearchGraphActions(TargetGraph, Entry.ActionName, 0, /*ExactMatch=*/true); if (Matches.Num() == 0) { UWingServer::Printf(TEXT("ERROR: No action found matching '%s'. Use GraphNodeSearchTypes to find available actions.\n"), *Entry.ActionName); continue; } if (Matches.Num() > 1) { UWingServer::Printf(TEXT("ERROR: Ambiguous: %d actions match '%s'.\n"), Matches.Num(), *Entry.ActionName); continue; } // Perform the action FVector2D Location(Entry.PosX, Entry.PosY); UEdGraphNode* NewNode = Matches[0]->PerformAction(TargetGraph, nullptr, Location, /*bSelectNewNode=*/false); if (!NewNode) { UWingServer::Printf(TEXT("ERROR: PerformAction returned null for '%s'.\n"), *Entry.ActionName); continue; } if (!NewNode->NodeGuid.IsValid()) NewNode->CreateNewGuid(); UWingServer::Printf(TEXT("Spawned: %s (%s)\n"), *WingUtils::FormatName(NewNode), *WingUtils::FormatName(NewNode->GetClass())); SuccessCount++; } UWingServer::Printf(TEXT("Spawned %d/%d nodes.\n"), SuccessCount, TotalCount); } };