#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 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(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); } };