// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "Containers/Array.h" #include "Containers/ArrayView.h" #include "Containers/ContainerAllocationPolicies.h" #include "Containers/Map.h" #include "CoreMinimal.h" #include "Delegates/Delegate.h" #include "Delegates/MulticastDelegateBase.h" #include "EntitySystem/MovieSceneSharedPlaybackState.h" #include "Evaluation/IMovieScenePlaybackCapability.h" #include "Evaluation/MovieSceneEvaluationKey.h" #include "Evaluation/PersistentEvaluationData.h" #include "HAL/Platform.h" #include "HAL/PlatformCrt.h" #include "Misc/Guid.h" #include "MovieSceneSequence.h" #include "MovieSceneSequenceID.h" #include "Templates/UniquePtr.h" #include "Templates/UnrealTypeTraits.h" #include "UObject/WeakObjectPtr.h" #include "UObject/WeakObjectPtrTemplates.h" #define UE_API MOVIESCENE_API class IMovieScenePlayer; class UMovieSceneSequence; class UObject; struct FMovieSceneEvaluationKey; struct FMovieSceneObjectBindingID; struct FSharedPersistentDataKey; struct IPersistentEvaluationData; namespace UE::MovieScene { struct FInstanceHandle; struct FSharedPlaybackState; /** * Playback capability for being notified of object bindings changing. */ struct IObjectBindingNotifyPlaybackCapability { UE_DECLARE_MOVIESCENE_PLAYBACK_CAPABILITY_API(MOVIESCENE_API, IObjectBindingNotifyPlaybackCapability) /** Called when multiple object bindings have changed. */ virtual void NotifyBindingsChanged() {} /** Called when a specific object binding has changed. */ virtual void NotifyBindingUpdate(const FGuid& InBindingId, FMovieSceneSequenceIDRef InSequenceID, TArrayView> BoundObjects) {} }; /** * Playback capability for storing static object binding overrides. */ struct IStaticBindingOverridesPlaybackCapability { UE_DECLARE_MOVIESCENE_PLAYBACK_CAPABILITY_API(MOVIESCENE_API, IStaticBindingOverridesPlaybackCapability) virtual ~IStaticBindingOverridesPlaybackCapability() {} /** Retrieves any override for the given operand */ virtual FMovieSceneEvaluationOperand* GetBindingOverride(const FMovieSceneEvaluationOperand& InOperand) = 0; /** Adds an override for the given operand */ virtual void AddBindingOverride(const FMovieSceneEvaluationOperand& InOperand, const FMovieSceneEvaluationOperand& InOverrideOperand) = 0; /** Removes any override set for the given operand */ virtual void RemoveBindingOverride(const FMovieSceneEvaluationOperand& InOperand) = 0; }; /** * A re-usable implementation of IStaticBindingOverridesPlaybackCapability. */ struct FStaticBindingOverrides : public IStaticBindingOverridesPlaybackCapability { UE_API virtual FMovieSceneEvaluationOperand* GetBindingOverride(const FMovieSceneEvaluationOperand& InOperand) override; UE_API virtual void AddBindingOverride(const FMovieSceneEvaluationOperand& InOperand, const FMovieSceneEvaluationOperand& InOverrideOperand) override; UE_API virtual void RemoveBindingOverride(const FMovieSceneEvaluationOperand& InOperand) override; private: TMap BindingOverrides; friend class ::IMovieScenePlayer; }; } // namespace UE::MovieScene /** * Object cache that looks up, resolves, and caches object bindings for a specific sequence */ struct FMovieSceneObjectCache { using FSharedPlaybackState = UE::MovieScene::FSharedPlaybackState; DECLARE_MULTICAST_DELEGATE_OneParam(FOnBindingInvalidated, const FGuid&); /** Invoked when a binding is either explicitly invalidated (as a result of a spawnable being spawned, or a binding override being added) * or when a previously resolved binding becomes invalid */ FOnBindingInvalidated OnBindingInvalidated; /** * Find all objects that are bound to the specified binding ID * @note Will look up, and cache any objects if the cache has been invalidated * * @param InBindingID The object binding GUID for a spawnable or posessable in a UMovieScene * @param Player The movie scene player that is playing back the sequence * @return An iterable type of all objects bound to the specified ID. */ MOVIESCENE_API TArrayView> FindBoundObjects(const FGuid& InBindingID, TSharedRef InSharedPlaybackState); /** * Find all objects that are bound to the specified binding ID * @note Does not update bindings if they are out of date, or invalid * * @param InBindingID The object binding GUID for a spawnable or posessable in a UMovieScene * @return An iterable type of all objects bound to the specified ID. */ MOVIESCENE_API TArrayView> IterateBoundObjects(const FGuid& InBindingID) const; /** * Set the sequence that this cache applies to * * @param InSequence The sequence that this cache applies to * @param InSequenceID The ID of the sequence within the root sequence */ MOVIESCENE_API void SetSequence(UMovieSceneSequence& InSequence, FMovieSceneSequenceIDRef InSequenceID, TSharedRef SharedPlaybackState); /** * Attempt deduce the posessable or spawnable that relates to the specified object * @note Will forcably resolve any out of date bindings in the entire sequence * * @param InObject The object whose binding ID is to be find * @param Player The movie scene player that is playing back the sequence * @return The object's spawnable or possessable GUID, or a zero GUID if it was not found */ MOVIESCENE_API FGuid FindObjectId(UObject& InObject, TSharedRef SharedPlaybackState); /** * Attempt deduce the posessable or spawnable that relates to the specified object * @note Does not clear the existing cache * * @param InObject The object whose binding ID is to be find * @param Player The movie scene player that is playing back the sequence * @return The object's spawnable or possessable GUID, or a zero GUID if it was not found */ MOVIESCENE_API FGuid FindCachedObjectId(UObject& InObject, TSharedRef SharedPlaybackState); /** * Invalidate any object bindings for objects that have been destroyed */ MOVIESCENE_API void InvalidateExpiredObjects(); /** * Invalidate the object bindings for a specific object binding ID in this sequence * * @param InGuid The object binding ID to invalidate bindings for */ MOVIESCENE_API void Invalidate(const FGuid& InGuid); /** * Invalidate the object bindings for a specific object binding ID in the specified sequence ID. * If the sequence ID matches this one, then we will look for the guid in this sequence. * If it does not, then we will see if any of our object bindings reference that one, and if so, they will be invalidated. * * @param InGuid The object binding ID to invalidate bindings for */ MOVIESCENE_API void Invalidate(const FGuid& InGuid, FMovieSceneSequenceIDRef InSequenceID); /** * Invalidate the object bindings for a specific object binding ID if they are not already invalidated * * @param InGuid The object binding ID to invalidate bindings for */ MOVIESCENE_API void InvalidateIfValid(const FGuid& InGuid); /* Gets the current activation on the provided binding. If no binding lifetime track is present, true will be returned. * @param InGuid The object binding ID */ MOVIESCENE_API bool GetBindingActivation(const FGuid& InGuid) const; /* Sets the binding to either active or inactive. Inactive bindings will invalidate and not resolve while inactive. * @param InGuid The object binding ID * @param bActive Where to activate or deactivate the binding. */ MOVIESCENE_API void SetBindingActivation(const FGuid& InGuid, bool bActive); /** * Completely erase all knowledge of, anc caches for all object bindings */ void Clear(TSharedRef SharedPlaybackState); /** * Get the sequence that this cache relates to */ UMovieSceneSequence* GetSequence() const { return WeakSequence.Get(); } /** * Get the current serial number of this cache */ uint32 GetSerialNumber() const { return SerialNumber; } /** * Filter all the object bindings in this object cache that contain the specified predicate object * * @param PredicateObject The object to filter by. Any bindings referencing this object will be added to the output array. * @param Player The movie scene player that is playing back the sequence * @param OutBindings (mandatory) Array to populate with bindings that relate to the object */ void FilterObjectBindings(UObject* PredicateObject, TSharedRef SharedPlaybackState, TArray* OutBindings); public: // Backwards compatible API, to be deprecated later MOVIESCENE_API TArrayView> FindBoundObjects(const FGuid& InBindingID, IMovieScenePlayer& Player); MOVIESCENE_API void SetSequence(UMovieSceneSequence& InSequence, FMovieSceneSequenceIDRef InSequenceID, IMovieScenePlayer& Player); MOVIESCENE_API FGuid FindObjectId(UObject& InObject, IMovieScenePlayer& Player); MOVIESCENE_API FGuid FindCachedObjectId(UObject& InObject, IMovieScenePlayer& Player); MOVIESCENE_API void Clear(IMovieScenePlayer& Player); MOVIESCENE_API void FilterObjectBindings(UObject* PredicateObject, IMovieScenePlayer& Player, TArray* OutBindings); private: /** * Update the bindings for the specified GUID * * @param InGuid The object binding ID to update bindings for * @param SharedPlaybackState The playback state for the sequence */ void UpdateBindings(const FGuid& InGuid, TSharedRef SharedPlaybackState); /** * Invalidate the object bindings for a specific object binding ID */ bool InvalidateInternal(const FGuid& InGuid); /** * Invalidate the object bindings for a specific object binding ID if they are not already invalidated */ bool InvalidateIfValidInternal(const FGuid& InGuid); /** * Update the serial number of this instance. */ void UpdateSerialNumber(); struct FBoundObjects { bool bUpToDate; TArray, TInlineAllocator<1>> Objects; }; private: /** The sequence that we're caching objects for */ TWeakObjectPtr WeakSequence; /** The sequence ID of the sequence within the root sequence */ FMovieSceneSequenceID SequenceID; template struct TFastGuidKeyFuncs : BaseKeyFuncs,FGuid,false> { typedef typename TTypeTraits::ConstPointerType KeyInitType; typedef const TPairInitializer::ConstInitType, typename TTypeTraits::ConstInitType>& ElementInitType; static FORCEINLINE KeyInitType GetSetKey(ElementInitType Element) { return Element.Key; } static FORCEINLINE bool Matches(KeyInitType A,KeyInitType B) { return A == B; } static FORCEINLINE uint32 GetKeyHash(KeyInitType Key) { return Key.A ^ Key.B ^ Key.C ^ Key.D; } }; /** A map of bound objects */ TMap> BoundObjects; /** Map of child bindings for any given object binding */ typedef TArray> FGuidArray; TMap> ChildBindings; /** For possessables in this scene that map to a binding in another scene (for example to a spawnable in another scene). * Stored as reverse-lookup for speed of invalidation. */ TMap ReverseMappedBindings; /* A set of inactive binding ids based on Binding Lifetime track. While inactive, these will be prevented from resolving.*/ TSet InactiveBindingIds; /** Serial number for this cache */ uint32 SerialNumber = 0; bool bReentrantUpdate = false; }; /** * Provides runtime evaluation functions with the ability to look up state from the main game environment */ struct FMovieSceneEvaluationState : public UE::MovieScene::IPlaybackCapability { using FSharedPlaybackState = UE::MovieScene::FSharedPlaybackState; UE_DECLARE_MOVIESCENE_PLAYBACK_CAPABILITY_API(MOVIESCENE_API, FMovieSceneEvaluationState) FMovieSceneEvaluationState() = default; FMovieSceneEvaluationState(const FMovieSceneEvaluationState&) = delete; FMovieSceneEvaluationState& operator=(const FMovieSceneEvaluationState&) = delete; /** * Assign a sequence to a specific ID * * @param InSequenceID The sequence ID to assign to * @param InSequence The sequence to assign */ MOVIESCENE_API void AssignSequence(FMovieSceneSequenceIDRef InSequenceID, UMovieSceneSequence& InSequence, TSharedRef SharedPlaybackState); /** * Attempt to locate a sequence from its ID * * @param InSequenceID The sequence ID to lookup */ MOVIESCENE_API UMovieSceneSequence* FindSequence(FMovieSceneSequenceIDRef InSequenceID) const; /** * Attempt to locate a sequence ID from a sequence * * @param InSequence The sequence to look up */ MOVIESCENE_API FMovieSceneSequenceID FindSequenceId(UMovieSceneSequence* InSequence) const; MOVIESCENE_API FMovieSceneSequenceID FindSequenceId(const UMovieSceneSequence* InSequence) const; /** * Attempt deduce the posessable or spawnable that relates to the specified object * @note Will forcably resolve any out of date bindings in the entire sequence * * @param InObject The object whose binding ID is to be find * @param Player The movie scene player that is playing back the sequence * @return The object's spawnable or possessable GUID, or a zero GUID if it was not found */ MOVIESCENE_API FGuid FindObjectId(UObject& Object, FMovieSceneSequenceIDRef InSequenceID, TSharedRef SharedPlaybackState); /** * Attempt deduce the posessable or spawnable that relates to the specified object * @note Does not clear the existing cache * * @param InObject The object whose binding ID is to be find * @param Player The movie scene player that is playing back the sequence * @return The object's spawnable or possessable GUID, or a zero GUID if it was not found */ MOVIESCENE_API FGuid FindCachedObjectId(UObject& Object, FMovieSceneSequenceIDRef InSequenceID, TSharedRef SharedPlaybackState); /** * Filter all the object bindings in this object cache that contain the specified predicate object * * @param PredicateObject The object to filter by. Any bindings referencing this object will be added to the output array. * @param Player The movie scene player that is playing back the sequence * @param OutBindings (mandatory) Array to populate with bindings that relate to the object */ MOVIESCENE_API void FilterObjectBindings(UObject* PredicateObject, TSharedRef SharedPlaybackState, TArray* OutBindings); /** * Find an object cache pertaining to the specified sequence * * @param InSequenceID The sequence ID to lookup */ FORCEINLINE FMovieSceneObjectCache* FindObjectCache(FMovieSceneSequenceIDRef SequenceID) { if (FVersionedObjectCache* Cache = ObjectCaches.Find(SequenceID)) { return &Cache->ObjectCache; } return nullptr; } /** * Find an object cache pertaining to the specified sequence * * @param InSequenceID The sequence ID to lookup */ FORCEINLINE const FMovieSceneObjectCache* FindObjectCache(FMovieSceneSequenceIDRef SequenceID) const { if (const FVersionedObjectCache* Cache = ObjectCaches.Find(SequenceID)) { return &Cache->ObjectCache; } return nullptr; } /** * Get an object cache pertaining to the specified sequence * * @param InSequenceID The sequence ID to lookup */ FORCEINLINE FMovieSceneObjectCache& GetObjectCache(FMovieSceneSequenceIDRef SequenceID) { FVersionedObjectCache* Cache = ObjectCaches.Find(SequenceID); if (!Cache) { Cache = &ObjectCaches.Add(SequenceID, FVersionedObjectCache()); } return Cache->ObjectCache; } /** * Locate objects bound to the specified object guid, in the specified sequence * @note: Objects lists are cached internally until they are invalidate. * * @param ObjectBindingID The object to resolve * @param SequenceID ID of the sequence to resolve for * * @return Iterable list of weak object pointers pertaining to the specified GUID */ TArrayView> FindBoundObjects(const FGuid& ObjectBindingID, FMovieSceneSequenceIDRef SequenceID, TSharedRef SharedPlaybackState) { FMovieSceneObjectCache* Cache = FindObjectCache(SequenceID); if (Cache) { return Cache->FindBoundObjects(ObjectBindingID, SharedPlaybackState); } return TArrayView>(); } /** * Locate objects bound to the specified sequence operand * @note: Objects lists are cached internally until they are invalidate. * * @param Operand The movie scene operand to resolve * * @return Iterable list of weak object pointers pertaining to the specified GUID */ TArrayView> FindBoundObjects(const FMovieSceneEvaluationOperand& Operand, TSharedRef SharedPlaybackState) { return FindBoundObjects(Operand.ObjectBindingID, Operand.SequenceID, SharedPlaybackState); } /** * Invalidate any object caches that may now contain expired objects */ MOVIESCENE_API void InvalidateExpiredObjects(); /** * Forcably invalidate the specified object binding in the specified sequence * * @param InGuid The object binding ID to invalidate * @param InSequenceID The sequence ID to which the object binding belongs */ MOVIESCENE_API void Invalidate(const FGuid& InGuid, FMovieSceneSequenceIDRef InSequenceID); /* Gets the current activation on the provided binding. If no binding lifetime track is present, true will be returned. * @param InGuid The object binding ID * @param InSequenceID The sequence ID to which the object binding belongs */ MOVIESCENE_API bool GetBindingActivation(const FGuid& InGuid, FMovieSceneSequenceIDRef InSequenceID) const; /* Sets the binding to either active or inactive. Inactive bindings will invalidate and not resolve while inactive. * @param InGuid The object binding ID * @param InSequenceID The sequence ID to which the object binding belongs * @param bActive Where to activate or deactivate the binding. */ MOVIESCENE_API void SetBindingActivation(const FGuid& InGuid, FMovieSceneSequenceIDRef InSequenceID, bool bActive); /** * Forcably clear all object caches */ MOVIESCENE_API void ClearObjectCaches(TSharedRef SharedPlaybackState); /** * Get the serial number for this state. */ MOVIESCENE_API uint32 GetSerialNumber(); /** A map of persistent evaluation data mapped by movie scene evaluation entity (i.e, a given track or section) */ TMap> PersistentEntityData; /** A map of persistent evaluation data mapped by shared evaluation key. Such data can be accessed from anywhere given an operand and a unique identifier. */ TMap> PersistentSharedData; public: /** IPlaybackCapability members */ MOVIESCENE_API virtual void Initialize(TSharedRef Owner) override; MOVIESCENE_API virtual void OnSubInstanceCreated(TSharedRef Owner, const UE::MovieScene::FInstanceHandle InstanceHandle) override; private: void RegisterObjectCacheEvents(UMovieSceneEntitySystemLinker* Linker, const UE::MovieScene::FInstanceHandle& InstanceHandle, const FMovieSceneSequenceID SequenceID); public: // Backwards compatible API, to be deprecated later MOVIESCENE_API void AssignSequence(FMovieSceneSequenceIDRef InSequenceID, UMovieSceneSequence& InSequence, IMovieScenePlayer& Player); MOVIESCENE_API FGuid FindObjectId(UObject& Object, FMovieSceneSequenceIDRef InSequenceID, IMovieScenePlayer& Player); MOVIESCENE_API FGuid FindCachedObjectId(UObject& Object, FMovieSceneSequenceIDRef InSequenceID, IMovieScenePlayer& Player); MOVIESCENE_API void FilterObjectBindings(UObject* PredicateObject, IMovieScenePlayer& Player, TArray* OutBindings); MOVIESCENE_API void ClearObjectCaches(IMovieScenePlayer& Player); private: /** Object cache with a last known serial of it */ struct FVersionedObjectCache { FMovieSceneObjectCache ObjectCache; FDelegateHandle OnInvalidateObjectBindingHandle; uint32 LastKnownSerial = 0; }; /** Maps of bound objects, arranged by template ID */ TMap ObjectCaches; /** Current serial number of this collection of caches */ uint32 SerialNumber = 0; }; #undef UE_API