Files
UnrealEngine/Engine/Source/Runtime/MovieScene/Public/Evaluation/PreAnimatedState/MovieScenePreAnimatedStateExtension.h
2025-05-18 13:04:45 +08:00

477 lines
18 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Containers/Array.h"
#include "Containers/ContainerAllocationPolicies.h"
#include "Containers/Map.h"
#include "Containers/SortedMap.h"
#include "Containers/SparseArray.h"
#include "CoreTypes.h"
#include "EntitySystem/MovieScenePropertySystemTypes.h"
#include "EntitySystem/MovieSceneSequenceInstanceHandle.h"
#include "Evaluation/MovieSceneAnimTypeID.h"
#include "Evaluation/PreAnimatedState/IMovieScenePreAnimatedStorage.h"
#include "Evaluation/PreAnimatedState/MovieScenePreAnimatedStateTypes.h"
#include "Evaluation/PreAnimatedState/MovieScenePreAnimatedStorageID.h"
#include "Misc/AssertionMacros.h"
#include "Templates/Less.h"
#include "Templates/SharedPointer.h"
#include "Templates/UniquePtr.h"
#include "UObject/ObjectKey.h"
class FReferenceCollector;
class UMovieSceneEntitySystemLinker;
class UObject;
struct FMovieSceneAnimTypeID;
struct FScopedPreAnimatedCaptureSource;
struct IMovieScenePreAnimatedGlobalTokenProducer;
struct IMovieScenePreAnimatedTokenProducer;
namespace UE
{
namespace MovieScene
{
struct FAnimTypePreAnimatedStateObjectStorage;
struct FAnimTypePreAnimatedStateRootStorage;
struct FPreAnimatedEntityCaptureSource;
struct FPreAnimatedEvaluationHookCaptureSources;
struct FPreAnimatedStateEntry;
struct FPreAnimatedStateExtension;
struct FPreAnimatedTemplateCaptureSources;
struct FPreAnimatedTrackInstanceCaptureSources;
struct FPreAnimatedTrackInstanceInputCaptureSources;
struct FRestoreStateParams;
struct FSharedPlaybackState;
struct IPreAnimatedCaptureSource;
struct IPreAnimatedStorage;
/**
* Interface required for any logical grouping of pre-animated state
*/
struct IPreAnimatedStateGroupManager
{
virtual ~IPreAnimatedStateGroupManager(){}
virtual void InitializeGroupManager(FPreAnimatedStateExtension* Extension) = 0;
virtual void OnGroupDestroyed(FPreAnimatedStorageGroupHandle Group) = 0;
virtual void GatherStaleStorageGroups(TArray<FPreAnimatedStorageGroupHandle>& StaleGroupStorage) const = 0;
};
/**
* Pre-animated state extension that houses all cached values for objects animated by a specific UMovieSceneEntitySystemLinker
*
* - The presence of this extension denotes that pre-animated state should be stored in one form or another.
* If the extension is not present, this implies that there are no IMovieScenePlayers that need global Restore State, and no tracks set to 'Restore State'.
* FPreAnimatedStateExtension::NumRequestsForGlobalState defines whether this extension needs to cache any and all changes or not
* - Each specific 'type' of pre-animated state is defined by a unique StorageID (TPreAnimatedStorageID), registered through RegisterStorage
* - Pre-animated state is grouped into buckets in order to preserve significant ordering constraints (for instance, each object must restore state in the reverse order it was cached)
* - Groups are managed by registered IPreAnimatedStateGroupManager instances. The main implementation is FPreAnimatedObjectGroupManager, which maintains an object to group mapping
*/
struct FPreAnimatedStateExtension
{
public:
MOVIESCENE_API FPreAnimatedStateExtension();
MOVIESCENE_API ~FPreAnimatedStateExtension();
public:
MOVIESCENE_API void Initialize(UMovieSceneEntitySystemLinker* InLinker);
/**
* Called from TAutoRegisterPreAnimatedStorageID to register a new application-wide storage type
*/
template<typename StorageType>
static TPreAnimatedStorageID<StorageType> RegisterStorage()
{
FPreAnimatedStorageID StorageID = RegisterStorageInternal();
return static_cast<const TPreAnimatedStorageID<StorageType>&>(StorageID);
}
public:
/**
* Find a specific storage type by its ID.
* @return The typed storage, or nullptr if it does not exist in this linker
*/
template<typename StorageType>
TSharedPtr<StorageType> FindStorage(TPreAnimatedStorageID<StorageType> InStorageID) const
{
TSharedPtr<IPreAnimatedStorage> TypedStorage = StorageImplementations.FindRef(InStorageID);
return StaticCastSharedPtr<StorageType>(TypedStorage);
}
/**
* Add a specific storage type to this extension
*/
template<typename StorageType>
void AddStorage(TPreAnimatedStorageID<StorageType> InStorageID, TSharedPtr<StorageType> InStorage)
{
check(!StorageImplementations.Contains(InStorageID));
StorageImplementations.Add(InStorageID, InStorage);
}
/**
* Get a specific type of storage, creating it if it does not already exist
* @note The template type must have a static StorageID of type TPreAnimatedStorageID<StorageType>.
*/
template<typename StorageType>
TSharedPtr<StorageType> GetOrCreateStorage()
{
return GetOrCreateStorage(StorageType::StorageID);
}
/**
* Get a specific type of storage, creating it if it does not already exist
*/
template<typename StorageType>
TSharedPtr<StorageType> GetOrCreateStorage(TPreAnimatedStorageID<StorageType> InStorageID)
{
TSharedPtr<StorageType> Existing = FindStorage(InStorageID);
if (!Existing)
{
Existing = MakeShared<StorageType>();
Existing->Initialize(InStorageID, this);
AddStorage(InStorageID, Existing);
}
return Existing;
}
/**
* Get a genericly typed storage entry by its erased ID, failing an assertion if it does not exist
*/
TSharedPtr<IPreAnimatedStorage> GetStorageChecked(FPreAnimatedStorageID InStorageID) const
{
return StorageImplementations.FindChecked(InStorageID);
}
public:
/**
* Find a group manager by its type. Group managers enable logical grouping of entries to ensure the correct restoration order.
* @note The templated type must implement a static GroupManagerID member of type TPreAnimatedStorageID<GroupManagerType>
* @return A pointer to the group manager, or nullptr if it does not exist.
*/
template<typename GroupManagerType>
TSharedPtr<GroupManagerType> FindGroupManager() const
{
return StaticCastSharedPtr<GroupManagerType>(GroupManagers.FindRef(GroupManagerType::GroupManagerID).Pin());
}
/**
* Get or create a group manager by its type. Group managers enable logical grouping of entries to ensure the correct restoration order.
* @note The templated type must implement a static GroupManagerID member of type TPreAnimatedStorageID<GroupManagerType>
* @return A pointer to the group manager, or nullptr if it does not exist.
*/
template<typename GroupManagerType>
TSharedPtr<GroupManagerType> GetOrCreateGroupManager()
{
TSharedPtr<IPreAnimatedStateGroupManager> Existing = GroupManagers.FindRef(GroupManagerType::GroupManagerID).Pin();
if (!Existing)
{
Existing = MakeShared<GroupManagerType>();
Existing->InitializeGroupManager(this);
GroupManagers.Add(GroupManagerType::GroupManagerID, Existing);
}
return StaticCastSharedPtr<GroupManagerType>(Existing);
}
/**
* Called by group managers to allocate a new group
*/
MOVIESCENE_API FPreAnimatedStorageGroupHandle AllocateGroup(TSharedPtr<IPreAnimatedStateGroupManager> GroupManager);
/**
* Called by group managers to free an existing group
*/
MOVIESCENE_API void FreeGroup(FPreAnimatedStorageGroupHandle Index);
public:
/**
* Check if this extension has any current requests to capture global (persistent) state entries
*/
bool IsCapturingGlobalState() const
{
return NumRequestsForGlobalState > 0;
}
/**
* Check whether any previously cached entries may have become invalid due to a recent call to RestoreGlobalState
* If this function returns true, clients should consider re-saving pre-animated state even if it already did so
*/
bool AreEntriesInvalidated() const
{
return bEntriesInvalidated;
}
/**
* Resets the entry invalidation flag
*/
void ResetEntryInvalidation()
{
bEntriesInvalidated = false;
}
public:
/**
* Restore any state for any persistent tokens captured during the course of evaluation
*
* @param Params Parameters for restoration - if TerminalInstanceHandle is invalid then _all_ state will be restored, regardless of the instance it was cached from
*/
MOVIESCENE_API void RestoreGlobalState(const FRestoreStateParams& Params);
/**
* Discards any state for any persistent tokens captured during the course of evaluation without restoring it.
*
* @param Params Parameters for restoration - if TerminalInstanceHandle is invalid then _all_ state will be discarded, regardless of the instance it was cached from
*/
MOVIESCENE_API void DiscardGlobalState(const FRestoreStateParams& Params);
/**
* Restore any state cached for the specified group
*
* @params GroupHandle Handle to the group to restore
* @param Params Parameters for restoration
*/
MOVIESCENE_API void RestoreStateForGroup(FPreAnimatedStorageGroupHandle GroupHandle, const FRestoreStateParams& Params);
/**
* Called during Garbage Collection to clean up preanimated state on invalid bound objects. Does not restore state.
*/
void DiscardStaleObjectState();
/**
* Called during blueprint re-instancing to replace the object bound to a specific group handle with another.
*/
MOVIESCENE_API void ReplaceObjectForGroup(FPreAnimatedStorageGroupHandle GroupHandle, const FObjectKey& OldObject, const FObjectKey& NewObject);
/**
* Discard any transient state and all meta-data for any currently animating objects, whilst preserving the cached values internally.
* Calling this function will cause any currently animating 'RestoreState' sections to re-cache their values if they are re-evaluated
* Any 'RestoreState' sections which are deleted or subsequently not-evaluated will not cause their values to be restored
*/
MOVIESCENE_API void DiscardTransientState();
/**
* Discard any and all cached values for the specified group without restoring them.
* @note This function should only be used to forcibly serialize animated values into a level
*/
MOVIESCENE_API void DiscardStateForGroup(FPreAnimatedStorageGroupHandle GroupHandle);
/**
* Discard the specified cached value and any and all capture source tracking related to it.
*/
MOVIESCENE_API void DiscardStateForStorage(FPreAnimatedStorageID StorageID, FPreAnimatedStorageIndex StorageIndex);
/**
* Search for any captured state that originated from the specified root instance handle
* WARNING: This is a linear search across all state, and so is potentially very slow
*/
MOVIESCENE_API bool ContainsAnyStateForInstanceHandle(FRootInstanceHandle RootInstanceHandle) const;
public:
// These methods for globally saving pre-animated state shouldn't be used directly:
//
// - use FScopedPreAnimatedCaptureSource to capture from a specific source.
//
// - use the similar methods on SharedPlaybackState->GetPreAnimatedState() to save only when it's
// needed for that given sequence instance.
//
MOVIESCENE_API void SavePreAnimatedState(FMovieSceneAnimTypeID InTokenType, const IMovieScenePreAnimatedGlobalTokenProducer& Producer);
MOVIESCENE_API void SavePreAnimatedState(UObject& InObject, FMovieSceneAnimTypeID InTokenType, const IMovieScenePreAnimatedTokenProducer& Producer);
MOVIESCENE_API void SavePreAnimatedStateDirectly(FMovieSceneAnimTypeID InTokenType, const IMovieScenePreAnimatedGlobalTokenProducer& Producer);
MOVIESCENE_API void SavePreAnimatedStateDirectly(UObject& InObject, FMovieSceneAnimTypeID InTokenType, const IMovieScenePreAnimatedTokenProducer& Producer);
public:
MOVIESCENE_API FPreAnimatedEntityCaptureSource* GetEntityMetaData() const;
MOVIESCENE_API FPreAnimatedEntityCaptureSource* GetOrCreateEntityMetaData();
MOVIESCENE_API FPreAnimatedTrackInstanceCaptureSources* GetTrackInstanceMetaData() const;
MOVIESCENE_API FPreAnimatedTrackInstanceCaptureSources* GetOrCreateTrackInstanceMetaData();
MOVIESCENE_API FPreAnimatedTrackInstanceInputCaptureSources* GetTrackInstanceInputMetaData() const;
MOVIESCENE_API FPreAnimatedTrackInstanceInputCaptureSources* GetOrCreateTrackInstanceInputMetaData();
MOVIESCENE_API FPreAnimatedTemplateCaptureSources* GetTemplateMetaData() const;
MOVIESCENE_API FPreAnimatedTemplateCaptureSources* GetOrCreateTemplateMetaData();
MOVIESCENE_API FPreAnimatedEvaluationHookCaptureSources* GetEvaluationHookMetaData() const;
MOVIESCENE_API FPreAnimatedEvaluationHookCaptureSources* GetOrCreateEvaluationHookMetaData();
MOVIESCENE_API bool HasActiveCaptureSource() const;
MOVIESCENE_API void AddWeakCaptureSource(TWeakPtr<IPreAnimatedCaptureSource> InWeakMetaData);
MOVIESCENE_API void RemoveWeakCaptureSource(TWeakPtr<IPreAnimatedCaptureSource> InWeakMetaData);
MOVIESCENE_API void EnsureMetaData(const FPreAnimatedStateEntry& Entry);
MOVIESCENE_API void AddSourceMetaData(const FPreAnimatedStateEntry& Entry);
MOVIESCENE_API bool MetaDataExists(const FPreAnimatedStateEntry& Entry) const;
MOVIESCENE_API void AddMetaData(const FPreAnimatedStateMetaData& MetaData);
MOVIESCENE_API void RemoveMetaData(const FPreAnimatedStateMetaData& MetaData);
MOVIESCENE_API void UpdateMetaData(const FPreAnimatedStateMetaData& MetaData);
MOVIESCENE_API EPreAnimatedStorageRequirement GetStorageRequirement(const FPreAnimatedStateEntry& Entry) const;
private:
MOVIESCENE_API void FreeGroupInternal(FPreAnimatedStorageGroupHandle Handle);
MOVIESCENE_API void AddReferencedObjects(UMovieSceneEntitySystemLinker*, FReferenceCollector& ReferenceCollector);
using FContributionRemover = TFunctionRef<void(IPreAnimatedStorage&, FPreAnimatedStorageIndex)>;
void HandleMetaDataToRemove(
const FRestoreStateParams& Params,
TArrayView<FPreAnimatedStateMetaData> MetaDataToRemove,
FContributionRemover RemoveFunc);
public:
/** Called to handle replaced objects */
void OnObjectsReplaced(const TMap<UObject*, UObject*>& ReplacementMap);
/** The number of requests that have been made to capture global state - only one should exist per playing sequence */
uint32 NumRequestsForGlobalState;
private:
/** Meta-data pertaining to the entity IDs from which animated state originates */
TUniquePtr<FPreAnimatedEntityCaptureSource> EntityCaptureSource;
/** Meta-data pertaining to pre-animated state originating from track instances */
TUniquePtr<FPreAnimatedTrackInstanceCaptureSources> TrackInstanceCaptureSource;
/** Meta-data pertaining to pre-animated state originating from track instances from a specific input */
TUniquePtr<FPreAnimatedTrackInstanceInputCaptureSources> TrackInstanceInputCaptureSource;
/** Meta-data ledger for any pre-animated state that originates from track templates */
TUniquePtr<UE::MovieScene::FPreAnimatedTemplateCaptureSources> TemplateCaptureSource;
/** Meta-data ledger for any pre-animated state that originates from evaluation hooks */
TUniquePtr<UE::MovieScene::FPreAnimatedEvaluationHookCaptureSources> EvaluationHookCaptureSource;
/** Weakly held meta data provided by FMovieScenePreAnimatedState for various other origins */
TArray<TWeakPtr<IPreAnimatedCaptureSource>> WeakExternalCaptureSources;
/** Pointers to the storage for state bound to objects, organized by FMovieSceneAnimTypeID */
TWeakPtr<FAnimTypePreAnimatedStateObjectStorage> WeakGenericObjectStorage;
/** Pointers to the storage for state created from root tracks, or otherwise not bound to objects */
TWeakPtr<FAnimTypePreAnimatedStateRootStorage> WeakGenericRootStorage;
private:
friend struct ::FScopedPreAnimatedCaptureSource;
struct FAggregatePreAnimatedStateMetaData
{
FAggregatePreAnimatedStateMetaData(FPreAnimatedStateCachedValueHandle InValueHandle)
: ValueHandle(InValueHandle)
{}
FPreAnimatedStateCachedValueHandle ValueHandle;
FInstanceHandle TerminalInstanceHandle;
uint16 NumContributors = 0;
uint16 NumRestoreContributors = 0;
bool bWantedRestore = false;
bool bEligibleForGlobalRestore = false;
};
MOVIESCENE_API FAggregatePreAnimatedStateMetaData* FindMetaData(const FPreAnimatedStateEntry& Entry);
MOVIESCENE_API const FAggregatePreAnimatedStateMetaData* FindMetaData(const FPreAnimatedStateEntry& Entry) const;
MOVIESCENE_API FAggregatePreAnimatedStateMetaData* GetOrAddMetaDataInternal(const FPreAnimatedStateEntry& Entry);
struct FPreAnimatedGroupMetaData
{
TSharedPtr<IPreAnimatedStateGroupManager> GroupManagerPtr;
TArray<FAggregatePreAnimatedStateMetaData, TInlineAllocator<4>> AggregateMetaData;
};
TSparseArray<FPreAnimatedGroupMetaData> GroupMetaData;
TMap<FPreAnimatedStateCachedValueHandle, FAggregatePreAnimatedStateMetaData> UngroupedMetaData;
TSortedMap<FPreAnimatedStorageID, TSharedPtr<IPreAnimatedStorage>> StorageImplementations;
TSortedMap<FPreAnimatedStorageID, TWeakPtr<IPreAnimatedStateGroupManager>> GroupManagers;
/** Linker is always valid because this extension is owned by the Linker */
UMovieSceneEntitySystemLinker* Linker;
bool bEntriesInvalidated;
private:
static MOVIESCENE_API FPreAnimatedStorageID RegisterStorageInternal();
};
template<typename KeyType>
struct TPreAnimatedStateGroupManager : IPreAnimatedStateGroupManager, TSharedFromThis<TPreAnimatedStateGroupManager<KeyType>>
{
void InitializeGroupManager(FPreAnimatedStateExtension* InExtension) override
{
Extension = InExtension;
}
void OnGroupDestroyed(FPreAnimatedStorageGroupHandle Group) override
{
KeyType Temp = StorageGroupsToKey.FindChecked(Group);
StorageGroupsByKey.Remove(Temp);
StorageGroupsToKey.Remove(Group);
}
virtual void GatherStaleStorageGroups(TArray<FPreAnimatedStorageGroupHandle>& StaleGroupStorage) const override
{
}
FPreAnimatedStorageGroupHandle FindGroupForKey(const KeyType& InKey) const
{
return StorageGroupsByKey.FindRef(InKey);
}
FPreAnimatedStorageGroupHandle MakeGroupForKey(const KeyType& InKey)
{
FPreAnimatedStorageGroupHandle GroupHandle = StorageGroupsByKey.FindRef(InKey);
if (GroupHandle)
{
return GroupHandle;
}
GroupHandle = Extension->AllocateGroup(this->AsShared());
StorageGroupsByKey.Add(InKey, GroupHandle);
StorageGroupsToKey.Add(GroupHandle, InKey);
return GroupHandle;
}
protected:
TMap<KeyType, FPreAnimatedStorageGroupHandle> StorageGroupsByKey;
TMap<FPreAnimatedStorageGroupHandle, KeyType> StorageGroupsToKey;
FPreAnimatedStateExtension* Extension;
};
} // namespace MovieScene
} // namespace UE