// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "Compilation/MovieSceneCompiledDataID.h" #include "CoreTypes.h" #include "EntitySystem/MovieSceneSequenceInstanceHandle.h" #include "Evaluation/MovieSceneEvaluationOperand.h" #include "Evaluation/MovieScenePlaybackCapabilities.h" #include "Evaluation/MovieScenePreAnimatedState.h" #include "MovieSceneSequenceID.h" #define UE_API MOVIESCENE_API class UMovieSceneSequence; class FMovieSceneEntitySystemRunner; class UMovieSceneCompiledDataManager; class UMovieSceneEntitySystemLinker; struct FMovieSceneObjectCache; struct FMovieSceneSequenceHierarchy; namespace UE::MovieScene { /** * Parameter structure for initializing a new shared playback state. */ struct FSharedPlaybackStateCreateParams { /** * The playback context in which the root sequence will be evaluated. */ UObject* PlaybackContext = nullptr; /** * The handle of the root sequence instance, if the created playback state * is meant to relate to an instance that has also been created inside * a runner/linker's instance registry. */ FRootInstanceHandle RootInstanceHandle; /** * The linker that will be evaluating the sequence that the created playback * state relates to. */ TObjectPtr Linker; /** * The compiled data manager with which the root sequence was compiled, or * will be compiled. If unset, the default global manager will be used. */ UMovieSceneCompiledDataManager* CompiledDataManager = nullptr; }; /** * A structure that stores playback state for an entire sequence hierarchy. */ struct FSharedPlaybackState : TSharedFromThis { public: UE_API FSharedPlaybackState(UMovieSceneEntitySystemLinker* InLinker = nullptr); UE_API FSharedPlaybackState( UMovieSceneSequence& InRootSequence, const FSharedPlaybackStateCreateParams& CreateParams); UE_API ~FSharedPlaybackState(); public: /** Gets the playback context */ UObject* GetPlaybackContext() const { return WeakPlaybackContext.Get(); } /** Gets the root sequence */ UMovieSceneSequence* GetRootSequence() const { return WeakRootSequence.Get(); } /** Gets the linker evaluating this root sequence */ UMovieSceneEntitySystemLinker* GetLinker() const { return WeakLinker.Get(); } /** Gets the compiled data manager that contains the data for the root sequence */ TObjectPtr GetCompiledDataManager() const { return CompiledDataManager; } /** Gets the handle of the root sequence */ const FRootInstanceHandle& GetRootInstanceHandle() const { return RootInstanceHandle; } /** Gets the compiled data ID for the root sequence */ const FMovieSceneCompiledDataID& GetRootCompiledDataID() const { return RootCompiledDataID; } /** Gets the pre-animated state utility for the sequence hierarchy */ const FMovieSceneInstancePreAnimatedState& GetPreAnimatedState() const { return PreAnimatedState; } /** Gets the pre-animated state utility for the sequence hierarchy */ FMovieSceneInstancePreAnimatedState& GetPreAnimatedState() { return PreAnimatedState; } public: // General utility methods /** Gets the runner evaluating this root sequence */ UE_API TSharedPtr GetRunner() const; /** Gets the hierarchy (if any) for this root sequence */ UE_API const FMovieSceneSequenceHierarchy* GetHierarchy() const; /** Gets a sub-sequence given an ID */ UE_API UMovieSceneSequence* GetSequence(FMovieSceneSequenceIDRef SequenceID) const; /** Finds the bound objects for the given object binding in the given (sub)sequence */ UE_API TArrayView> FindBoundObjects(const FGuid& ObjectBindingID, FMovieSceneSequenceIDRef SequenceID) const; /** Clears object caches for the entire sequence hierarchy. */ UE_API void ClearObjectCaches(); public: /** * Gets the capabilities container. */ FPlaybackCapabilities& GetCapabilities() { #if !UE_BUILD_SHIPPING ensureMsgf(IsInGameThread(), TEXT("Playback capabilities aren't meant to be thread-safe. Do not modify or access their container outside of the game thread.")); #endif return Capabilities; } /** * Gets the capabilities container. */ const FPlaybackCapabilities& GetCapabilities() const { #if !UE_BUILD_SHIPPING ensureMsgf(IsInGameThread(), TEXT("Playback capabilities aren't meant to be thread-safe. Do not modify or access their container outside of the game thread.")); #endif return Capabilities; } /** * Returns whether the root sequence has the specified capability. */ template bool HasCapability() const { #if !UE_BUILD_SHIPPING ensureMsgf(IsInGameThread(), TEXT("Playback capabilities aren't meant to be thread-safe. Do not modify or access their container outside of the game thread.")); #endif return Capabilities.HasCapability(); } /** * Finds the specified capability on the root sequence. */ template T* FindCapability() const { #if !UE_BUILD_SHIPPING ensureMsgf(IsInGameThread(), TEXT("Playback capabilities aren't meant to be thread-safe. Do not modify or access their container outside of the game thread.")); #endif return Capabilities.FindCapability(); } /** * Builds the specified capability for the root sequence. */ template T& AddCapability(ArgTypes&&... InArgs) { #if !UE_BUILD_SHIPPING ensureMsgf(IsInGameThread(), TEXT("Playback capabilities aren't meant to be thread-safe. Do not modify or access their container outside of the game thread.")); #endif T& Cap = Capabilities.AddCapability(Forward(InArgs)...); MaybeInitialize(Cap); return Cap; } /** * Adds the specified capability on the root sequence as a raw pointer. */ template T& AddCapabilityRaw(T* InPointer) { #if !UE_BUILD_SHIPPING ensureMsgf(IsInGameThread(), TEXT("Playback capabilities aren't meant to be thread-safe. Do not modify or access their container outside of the game thread.")); #endif T& Cap = Capabilities.AddCapabilityRaw(InPointer); MaybeInitialize(Cap); return Cap; } /** * Adds the specified capability on the root sequence as a shared pointer. */ template T& AddCapabilityShared(TSharedRef InSharedRef) { #if !UE_BUILD_SHIPPING ensureMsgf(IsInGameThread(), TEXT("Playback capabilities aren't meant to be thread-safe. Do not modify or access their container outside of the game thread.")); #endif T& Cap = Capabilities.AddCapabilityShared(InSharedRef); MaybeInitialize(Cap); return Cap; } /** * Adds the specified capability on the root sequence. * If the capability already exists, it must be stored inline, and its * value will be replaced by the new object. * If the template parameter is a sub-class of the playback capability, the previously * stored playback capability must not only have been stored inline, but must have * been of the same sub-class (or a sub-class with the exact same size and alignment). */ template T& SetOrAddCapability(ArgTypes&&... InArgs) { #if !UE_BUILD_SHIPPING ensureMsgf(IsInGameThread(), TEXT("Playback capabilities aren't meant to be thread-safe. Do not modify or access their container outside of the game thread.")); #endif if (HasCapability()) { T& Cap = Capabilities.OverwriteCapability(Forward(InArgs)...); MaybeInitialize(Cap); return Cap; } else { T& Cap = Capabilities.AddCapability(Forward(InArgs)...); MaybeInitialize(Cap); return Cap; } } /** * Adds the specified capability on the root sequence as a raw pointer. * If the capability already exists, it must be stored as a raw pointer and its * value will be replaced by the new pointer. */ template T& SetOrAddCapabilityRaw(T* InPointer) { #if !UE_BUILD_SHIPPING ensureMsgf(IsInGameThread(), TEXT("Playback capabilities aren't meant to be thread-safe. Do not modify or access their container outside of the game thread.")); #endif if (HasCapability()) { T& Cap = Capabilities.OverwriteCapabilityRaw(InPointer); MaybeInitialize(Cap); return Cap; } else { T& Cap = Capabilities.AddCapabilityRaw(InPointer); MaybeInitialize(Cap); return Cap; } } /** * Adds the specified capability on the root sequence as a shared pointer. * If the capability already exists, it must be stored as a shared pointer and its * value will be replaced by the new pointer. */ template T& SetOrAddCapabilityShared(TSharedRef InSharedRef) { #if !UE_BUILD_SHIPPING ensureMsgf(IsInGameThread(), TEXT("Playback capabilities aren't meant to be thread-safe. Do not modify or access their container outside of the game thread.")); #endif if (HasCapability()) { T& Cap = Capabilities.OverwriteCapabilityShared(InSharedRef); MaybeInitialize(Cap); return Cap; } else { T& Cap = Capabilities.AddCapabilityShared(InSharedRef); MaybeInitialize(Cap); return Cap; } } public: UE_API void InvalidateCachedData(); #if !UE_BUILD_SHIPPING void SetDebugBreakOnDestroy() { bDebugBreakOnDestroy = true; } #endif private: template void MaybeInitialize(T& Cap) { if constexpr (TPointerIsConvertibleFromTo::Value) { IPlaybackCapability* InterfacePtr = static_cast(&Cap); InterfacePtr->Initialize(SharedThis(this)); } } private: /** The root sequence */ TWeakObjectPtr WeakRootSequence; /** The playback context */ TWeakObjectPtr WeakPlaybackContext; /** The linker evaluating this root sequence */ TWeakObjectPtr WeakLinker; /** The compiled data manager that contains the data for the root sequence */ TObjectPtr CompiledDataManager; /** The handle of the root sequence */ FRootInstanceHandle RootInstanceHandle; /** The compiled data ID for the root sequence */ FMovieSceneCompiledDataID RootCompiledDataID; /** Playback capabilities for the root sequence */ FPlaybackCapabilities Capabilities; /** Pre-animated state utility for the sequence hierarchy */ FMovieSceneInstancePreAnimatedState PreAnimatedState; #if !UE_BUILD_SHIPPING bool bDebugBreakOnDestroy = false; #endif }; } // namespace UE::MovieScene #undef UE_API