Files
UnrealEngineUWP/Engine/Source/Editor/AnimationModifiers/Private/AnimationModifiersAssetUserData.cpp
Jurre deBaare a5305f76a3 Contributed by Yupeng.Zhang from The Coalition:
Animation Modifier : Fix Modifier on Skeleton
Transfered the ownership of 'PreviouslyAppliedModifier' from an animation modifier instance to the animation sequence being applied.
This solved the following issue:
- Modifier on Skeleton cause USkeleton dirtied everytime the modifier is applied to an animation sequence.
- Modifier on Skeleton cannot be re-apply or reverted correctly.
- CanRevert & OutOfDate status for Modifier on Skeleton was not reflect the true status of all animation sequences referencing that skeleton.

- CurrentAnimSequence/CurrentSkeleton was not set on OnRevert()
- IAnimationDataController::FScopedBracket was not open on OnRevert() before re-apply modifier
- Stateful animation modifier can now be reverted correctly (Applied modifier instance is nolonger reverted after OnApply call)

#preflight 63775e0ff514e1ded99ef095

[CL 23191977 by Jurre deBaare in ue5-main branch]
2022-11-18 05:35:47 -05:00

123 lines
3.9 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "AnimationModifiersAssetUserData.h"
#include "AnimationModifier.h"
#include "UObject/UObjectThreadContext.h"
#include "HAL/PlatformCrt.h"
#include "Math/UnrealMathUtility.h"
#include "Misc/AssertionMacros.h"
#include "UObject/ObjectPtr.h"
#include "Animation/AnimSequence.h"
void UAnimationModifiersAssetUserData::AddAnimationModifier(UAnimationModifier* Instance)
{
AnimationModifierInstances.Add(Instance);
}
void UAnimationModifiersAssetUserData::RemoveAnimationModifierInstance(UAnimationModifier* Instance)
{
checkf(AnimationModifierInstances.Contains(Instance), TEXT("Instance suppose to be removed is not found"));
AnimationModifierInstances.Remove(Instance);
AppliedModifiers.Remove(Instance);
}
const TArray<UAnimationModifier*>& UAnimationModifiersAssetUserData::GetAnimationModifierInstances() const
{
return AnimationModifierInstances;
}
void UAnimationModifiersAssetUserData::ChangeAnimationModifierIndex(UAnimationModifier* Instance, int32 Direction)
{
checkf(AnimationModifierInstances.Contains(Instance), TEXT("Instance suppose to be moved is not found"));
const int32 CurrentIndex = AnimationModifierInstances.IndexOfByKey(Instance);
const int32 NewIndex = FMath::Clamp(CurrentIndex + Direction, 0, AnimationModifierInstances.Num() - 1);
if (CurrentIndex != NewIndex)
{
AnimationModifierInstances.Swap(CurrentIndex, NewIndex);
}
}
void UAnimationModifiersAssetUserData::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent)
{
RemoveInvalidModifiers();
Super::PostEditChangeProperty(PropertyChangedEvent);
}
#if WITH_EDITOR
void UAnimationModifiersAssetUserData::PostEditChangeOwner()
{
Super::PostEditChangeOwner();
// We cant call blueprint implemented functions while routing post load
if (FUObjectThreadContext::Get().IsRoutingPostLoad)
{
return;
}
UAnimSequence* ModifiedAnimSequence = Cast<UAnimSequence>(GetOuter());
if (!ModifiedAnimSequence)
{
return;
}
for (UAnimationModifier* Modifier : AnimationModifierInstances)
{
if (!Modifier->bReapplyPostOwnerChange || Modifier->IsCurrentlyApplyingModifier())
{
continue;
}
Modifier->ApplyToAnimationSequence(ModifiedAnimSequence);
}
}
#endif // WITH_EDITOR
void UAnimationModifiersAssetUserData::Serialize(FArchive& Ar)
{
Super::Serialize(Ar);
}
void UAnimationModifiersAssetUserData::PostLoad()
{
Super::PostLoad();
RemoveInvalidModifiers();
}
void UAnimationModifiersAssetUserData::RemoveInvalidModifiers()
{
// This will catch force-deleted blueprints to be removed from our stored array
AnimationModifierInstances.RemoveAll([](UAnimationModifier* Modifier) { return Modifier == nullptr; });
// The AssetUserData on this animation's skeleton
UAnimationModifiersAssetUserData* SkeletonAssetUserData = nullptr;
if (const UObject* OwnerAsset = GetOuter())
{
if (const UAnimSequence* Sequence = Cast<UAnimSequence>(OwnerAsset->GetOuter()))
{
if (USkeleton* Skeleton = Sequence->GetSkeleton())
{
SkeletonAssetUserData = Skeleton->GetAssetUserData< UAnimationModifiersAssetUserData>();
}
}
}
auto IsAppliedModifierValid = [this, SkeletonAssetUserData](const decltype(AppliedModifiers)::ElementType& Pair)
{
// The key (template modifier) from both animation sequence or skeleton should be loaded before this object
if (const UObject* MasterModifier = Pair.Key.ResolveObject())
{
if (const UObject* AssetData = MasterModifier->GetOuter())
{
// If the MasterModifier is not owned by us or the skeleton
// This asset user data must been re-parented
// Remove those stale applied-modifier information
return AssetData == this || AssetData == SkeletonAssetUserData;
}
}
return false;
};
// Remove all applied modifier instances of deleted modifier
AppliedModifiers = AppliedModifiers.FilterByPredicate([](const decltype(AppliedModifiers)::ElementType& Pair) { return Pair.Key.ResolveObject() != nullptr; });
}