#pragma once #include "CoreMinimal.h" #include "WingServer.h" #include "WingHandler.h" #include "WingFetcher.h" #include "WingUtils.h" #include "EdGraph/EdGraph.h" #include "EdGraph/EdGraphNode.h" #include "Kismet2/KismetEditorUtilities.h" #include "Animation/AnimBlueprint.h" #include "Animation/AnimSequence.h" #include "AnimGraphNode_SequencePlayer.h" #include "AnimStateNode.h" #include "AnimationStateMachineGraph.h" #include "StateMachine_SetAnimation.generated.h" // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- UCLASS() class UWing_StateMachine_SetAnimation : public UObject, public IWingHandler { GENERATED_BODY() public: UPROPERTY(meta=(Description="Animation Blueprint package path")) FString Blueprint; UPROPERTY(meta=(Description="State machine graph name")) FString Graph; UPROPERTY(meta=(Description="Name of the state to modify")) FString StateName; UPROPERTY(meta=(Description="Animation asset package path to assign")) FString AnimationAsset; virtual FString GetDescription() const override { return TEXT("Set or replace the animation sequence played by a state in an animation state machine."); } virtual void Handle() override { // Resolve the anim blueprint WingFetcher F; UAnimBlueprint* AnimBP = F.Walk(Blueprint).Cast(); if (!AnimBP) return; // Find the state machine graph UAnimationStateMachineGraph* SMGraph = WingUtils::FindStateMachineGraph(AnimBP, Graph); if (!SMGraph) { UWingServer::Printf(TEXT("ERROR: State machine graph '%s' not found in %s\n"), *Graph, *WingUtils::FormatName(AnimBP)); return; } // Find the target state UAnimStateNode* StateNode = WingUtils::FindStateByName(SMGraph, StateName); if (!StateNode) return; UEdGraph* InnerGraph = StateNode->GetBoundGraph(); if (!InnerGraph) { UWingServer::Printf(TEXT("ERROR: State '%s' has no bound graph\n"), *StateName); return; } // Find the animation asset WingFetcher F2; UAnimSequence* AnimSeq = F2.Asset(AnimationAsset).Cast(); if (!AnimSeq) return; // Find existing SequencePlayer or create one UAnimGraphNode_SequencePlayer* SeqNode = nullptr; for (UEdGraphNode* Node : InnerGraph->Nodes) { SeqNode = Cast(Node); if (SeqNode) break; } bool bCreatedNew = false; if (!SeqNode) { SeqNode = NewObject(InnerGraph); SeqNode->CreateNewGuid(); SeqNode->PostPlacedNewNode(); SeqNode->AllocateDefaultPins(); SeqNode->NodePosX = 0; SeqNode->NodePosY = 0; InnerGraph->AddNode(SeqNode, false, false); bCreatedNew = true; } SeqNode->SetAnimationAsset(AnimSeq); // Compile FKismetEditorUtilities::CompileBlueprint(AnimBP); if (bCreatedNew) UWingServer::Printf(TEXT("Created sequence player in state '%s', assigned %s\n"), *StateName, *WingUtils::FormatName(AnimSeq)); else UWingServer::Printf(TEXT("Updated sequence player in state '%s' to %s\n"), *StateName, *WingUtils::FormatName(AnimSeq)); } };