// Copyright Epic Games, Inc. All Rights Reserved. #include "AnimationStateMachineLibrary.h" #include "Animation/AnimNode_StateMachine.h" #include "Animation/AnimNode_StateResult.h" #include "Animation/AnimInstanceProxy.h" #include UE_INLINE_GENERATED_CPP_BY_NAME(AnimationStateMachineLibrary) DEFINE_LOG_CATEGORY_STATIC(LogAnimationStateMachineLibrary, Verbose, All); void UAnimationStateMachineLibrary::ConvertToAnimationStateResult(const FAnimNodeReference& Node, FAnimationStateResultReference& AnimationState, EAnimNodeReferenceConversionResult& Result) { AnimationState = FAnimNodeReference::ConvertToType(Node, Result); } void UAnimationStateMachineLibrary::ConvertToAnimationStateMachine(const FAnimNodeReference& Node, FAnimationStateMachineReference& AnimationStateMachine, EAnimNodeReferenceConversionResult& Result) { AnimationStateMachine = FAnimNodeReference::ConvertToType(Node, Result); } bool UAnimationStateMachineLibrary::IsStateBlendingIn(const FAnimUpdateContext& UpdateContext, const FAnimationStateResultReference& Node) { bool bResult = false; Node.CallAnimNodeFunction( TEXT("IsStateBlendingIn"), [&UpdateContext, &bResult](FAnimNode_StateResult& StateResultNode) { if (const FAnimationUpdateContext* AnimationUpdateContext = UpdateContext.GetContext()) { IAnimClassInterface* AnimBlueprintClass = AnimationUpdateContext->GetAnimClass(); // Previous node to an FAnimNode_StateResult is always its owning FAnimNode_StateMachine const int32 MachineIndex = AnimBlueprintClass->GetAnimNodeProperties().Num() - 1 - AnimationUpdateContext->GetPreviousNodeId(); const int32 StateIndex = StateResultNode.GetStateIndex(); const FAnimInstanceProxy* AnimInstanceProxy = AnimationUpdateContext->AnimInstanceProxy; if (const FAnimNode_StateMachine* MachineInstance = AnimInstanceProxy->GetStateMachineInstance(MachineIndex)) { const int32 CurrentStateIndex = MachineInstance->GetCurrentState(); const float StateWeight = AnimInstanceProxy->GetRecordedStateWeight(MachineInstance->StateMachineIndexInClass, StateIndex); if ((StateWeight < 1.0f) && (CurrentStateIndex == StateIndex)) { bResult = true; } } } }); return bResult; } bool UAnimationStateMachineLibrary::IsStateBlendingOut(const FAnimUpdateContext& UpdateContext, const FAnimationStateResultReference& Node) { bool bResult = false; Node.CallAnimNodeFunction( TEXT("IsStateBlendingOut"), [&UpdateContext, &bResult](FAnimNode_StateResult& StateResultNode) { if (const FAnimationUpdateContext* AnimationUpdateContext = UpdateContext.GetContext()) { IAnimClassInterface* AnimBlueprintClass = AnimationUpdateContext->GetAnimClass(); // Previous node to an FAnimNode_StateResult is always its owning FAnimNode_StateMachine const int32 MachineIndex = AnimBlueprintClass->GetAnimNodeProperties().Num() - 1 - AnimationUpdateContext->GetPreviousNodeId(); const int32 StateIndex = StateResultNode.GetStateIndex(); const FAnimInstanceProxy* AnimInstanceProxy = AnimationUpdateContext->AnimInstanceProxy; if (const FAnimNode_StateMachine* MachineInstance = AnimInstanceProxy->GetStateMachineInstance(MachineIndex)) { const int32 CurrentStateIndex = MachineInstance->GetCurrentState(); const float StateWeight = AnimInstanceProxy->GetRecordedStateWeight(MachineInstance->StateMachineIndexInClass, StateIndex); if ((StateWeight > 0.0f) && (CurrentStateIndex != StateIndex)) { bResult = true; } } } }); return bResult; } void UAnimationStateMachineLibrary::SetState(const FAnimUpdateContext& UpdateContext, const FAnimationStateMachineReference& Node, FName TargetState, float Duration , TEnumAsByte BlendType, UBlendProfile* BlendProfile, EAlphaBlendOption AlphaBlendOption, UCurveFloat* CustomBlendCurve) { Node.CallAnimNodeFunction( TEXT("SetState"), [&UpdateContext, TargetState, Duration, BlendType, BlendProfile, AlphaBlendOption, CustomBlendCurve](FAnimNode_StateMachine& StateMachineNode) { if (const FAnimationUpdateContext* AnimationUpdateContext = UpdateContext.GetContext()) { const int32 CurrentStateIndex = StateMachineNode.GetCurrentState(); const int32 TargetStateIndex = StateMachineNode.GetStateIndex(TargetState); if(CurrentStateIndex != INDEX_NONE && TargetStateIndex != INDEX_NONE) { FAnimationTransitionBetweenStates TransitionInfo; TransitionInfo.PreviousState = CurrentStateIndex; TransitionInfo.NextState = TargetStateIndex; TransitionInfo.CrossfadeDuration = Duration; TransitionInfo.BlendMode = AlphaBlendOption; TransitionInfo.CustomCurve = CustomBlendCurve; TransitionInfo.BlendProfile = BlendProfile; TransitionInfo.LogicType = BlendType; StateMachineNode.TransitionToState(*AnimationUpdateContext, TransitionInfo); } } }); } FName UAnimationStateMachineLibrary::GetState(const FAnimUpdateContext& UpdateContext, const FAnimationStateMachineReference& Node) { FName OutName = NAME_None; Node.CallAnimNodeFunction( TEXT("GetState"), [&UpdateContext, &OutName](FAnimNode_StateMachine& StateMachineNode) { if (const FAnimationUpdateContext* AnimationUpdateContext = UpdateContext.GetContext()) { const int32 CurrentStateIndex = StateMachineNode.GetCurrentState(); OutName = StateMachineNode.GetStateInfo(CurrentStateIndex).StateName; } }); return OutName; } float UAnimationStateMachineLibrary::GetRelevantAnimTimeRemaining(const FAnimUpdateContext& UpdateContext, const FAnimationStateResultReference& Node) { float Result = MAX_flt; Node.CallAnimNodeFunction( TEXT("IsStateBlendingOut"), [&UpdateContext, &Result](FAnimNode_StateResult& StateResultNode) { if (const FAnimationUpdateContext* AnimationUpdateContext = UpdateContext.GetContext()) { IAnimClassInterface* AnimBlueprintClass = AnimationUpdateContext->GetAnimClass(); // Previous node to an FAnimNode_StateResult is always its owning FAnimNode_StateMachine const int32 MachineIndex = AnimBlueprintClass->GetAnimNodeProperties().Num() - 1 - AnimationUpdateContext->GetPreviousNodeId(); const int32 StateIndex = StateResultNode.GetStateIndex(); const FAnimInstanceProxy* AnimInstanceProxy = AnimationUpdateContext->AnimInstanceProxy; if (const FAnimNode_StateMachine* MachineInstance = AnimInstanceProxy->GetStateMachineInstance(MachineIndex)) { Result = MachineInstance->GetRelevantAnimTimeRemaining(AnimInstanceProxy, StateIndex); } } }); return Result; } float UAnimationStateMachineLibrary::GetRelevantAnimTimeRemainingFraction(const FAnimUpdateContext& UpdateContext, const FAnimationStateResultReference& Node) { float Result = 1.f; Node.CallAnimNodeFunction( TEXT("IsStateBlendingOut"), [&UpdateContext, &Result](FAnimNode_StateResult& StateResultNode) { if (const FAnimationUpdateContext* AnimationUpdateContext = UpdateContext.GetContext()) { IAnimClassInterface* AnimBlueprintClass = AnimationUpdateContext->GetAnimClass(); // Previous node to an FAnimNode_StateResult is always its owning FAnimNode_StateMachine const int32 MachineIndex = AnimBlueprintClass->GetAnimNodeProperties().Num() - 1 - AnimationUpdateContext->GetPreviousNodeId(); const int32 StateIndex = StateResultNode.GetStateIndex(); const FAnimInstanceProxy* AnimInstanceProxy = AnimationUpdateContext->AnimInstanceProxy; if (const FAnimNode_StateMachine* MachineInstance = AnimInstanceProxy->GetStateMachineInstance(MachineIndex)) { Result = MachineInstance->GetRelevantAnimTimeRemainingFraction(AnimInstanceProxy, StateIndex); } } }); return Result; }