Files
integration/Plugins/BlueprintMCP/Source/BlueprintMCP/Private/Handlers/UMCPHandler_AddAnimStateTransition.h
2026-03-08 22:17:14 -04:00

111 lines
3.6 KiB
C++

#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPAssetFinder.h"
#include "MCPUtils.h"
#include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphNode.h"
#include "EdGraph/EdGraphPin.h"
#include "Kismet2/KismetEditorUtilities.h"
#include "Animation/AnimBlueprint.h"
#include "Animation/AnimSequence.h"
#include "Animation/BlendSpace.h"
#include "AnimGraphNode_SequencePlayer.h"
#include "AnimGraphNode_BlendSpacePlayer.h"
#include "AnimStateNode.h"
#include "AnimStateTransitionNode.h"
#include "AnimationStateMachineGraph.h"
#include "K2Node_VariableGet.h"
#include "UMCPHandler_AddAnimStateTransition.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS()
class UMCPHandler_AddAnimStateTransition : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Description="Animation Blueprint name or package path"))
FString Blueprint;
UPROPERTY(meta=(Description="State machine graph name"))
FString Graph;
UPROPERTY(meta=(Description="Name of the source state"))
FString FromState;
UPROPERTY(meta=(Description="Name of the target state"))
FString ToState;
UPROPERTY(meta=(Optional, Description="Crossfade duration in seconds"))
float CrossfadeDuration = 0.0f;
UPROPERTY(meta=(Optional, Description="Transition priority order"))
int32 Priority = 0;
UPROPERTY(meta=(Optional, Description="Whether the transition is bidirectional"))
bool BBidirectional = false;
virtual FString GetDescription() const override
{
return TEXT("Add a transition between two states in an animation state machine graph.");
}
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
{
MCPAssets<UAnimBlueprint> Assets;
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
UAnimationStateMachineGraph* SMGraph = MCPUtils::FindStateMachineGraph(Assets.Object(), Graph);
if (!SMGraph) { MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("State machine graph '%s' not found in '%s'"), *Graph, *Blueprint)); return; }
UAnimBlueprint* AnimBP = Assets.Object();
UAnimStateNode* FromStateNode = MCPUtils::FindStateByName(SMGraph, FromState, Result);
if (!FromStateNode) return;
UAnimStateNode* ToStateNode = MCPUtils::FindStateByName(SMGraph, ToState, Result);
if (!ToStateNode) return;
// Create transition node
UAnimStateTransitionNode* TransNode = NewObject<UAnimStateTransitionNode>(SMGraph);
TransNode->CreateNewGuid();
TransNode->PostPlacedNewNode();
TransNode->AllocateDefaultPins();
// Position between the two states
TransNode->NodePosX = (FromStateNode->NodePosX + ToStateNode->NodePosX) / 2;
TransNode->NodePosY = (FromStateNode->NodePosY + ToStateNode->NodePosY) / 2;
SMGraph->AddNode(TransNode, false, false);
TransNode->SetFlags(RF_Transactional);
// Connect: FromState output -> Transition input, Transition output -> ToState input
TransNode->CreateConnections(FromStateNode, ToStateNode);
// Set optional properties
if (Json->HasField(TEXT("crossfadeDuration")))
{
TransNode->CrossfadeDuration = CrossfadeDuration;
}
if (Json->HasField(TEXT("priority")))
{
TransNode->PriorityOrder = Priority;
}
if (Json->HasField(TEXT("bBidirectional")))
{
TransNode->Bidirectional = BBidirectional;
}
// Compile and save
FKismetEditorUtilities::CompileBlueprint(AnimBP);
bool bSaved = MCPUtils::SaveBlueprintPackage(AnimBP);
Result->SetStringField(TEXT("nodeId"), TransNode->NodeGuid.ToString());
Result->SetBoolField(TEXT("saved"), bSaved);
}
};