Files
integration/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_Create.h

103 lines
2.7 KiB
C
Raw Normal View History

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