// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "Containers/Map.h" #include "CoreMinimal.h" #include "Evaluation/MovieSceneEvaluationKey.h" #include "Evaluation/MovieSceneEvaluationOperand.h" #include "Evaluation/MovieSceneSequenceInstanceData.h" #include "HAL/Platform.h" #include "Misc/AssertionMacros.h" #include "MovieSceneFwd.h" #include "Stats/Stats.h" #include "Templates/TypeHash.h" #include "Templates/UniquePtr.h" class IMovieScenePlayer; /** * Unique identifier for shared persistent data entries (see FSharedPersistentDataKey) */ struct FMovieSceneSharedDataId { /** * Allocate a new unique identifier */ static MOVIESCENE_API FMovieSceneSharedDataId Allocate(); FMovieSceneSharedDataId(const FMovieSceneSharedDataId&) = default; FMovieSceneSharedDataId& operator=(const FMovieSceneSharedDataId&) = default; friend bool operator==(FMovieSceneSharedDataId A, FMovieSceneSharedDataId B) { return A.UniqueId == B.UniqueId; } friend uint32 GetTypeHash(FMovieSceneSharedDataId In) { return GetTypeHash(In.UniqueId); } private: FMovieSceneSharedDataId() {} uint32 UniqueId; }; /** * A key to a piece of data that is potentially shared between multiple tracks */ struct FSharedPersistentDataKey { /** * Construction from a shared data ID, and an operand */ FSharedPersistentDataKey(FMovieSceneSharedDataId InUniqueId, const FMovieSceneEvaluationOperand& InOperand) : UniqueId(InUniqueId) , Operand(InOperand) {} friend bool operator==(const FSharedPersistentDataKey& A, const FSharedPersistentDataKey& B) { return A.UniqueId == B.UniqueId && A.Operand == B.Operand; } friend uint32 GetTypeHash(const FSharedPersistentDataKey& In) { return HashCombine(GetTypeHash(In.Operand), GetTypeHash(In.UniqueId)); } /** The actual shared ID */ FMovieSceneSharedDataId UniqueId; /** The operand that this key relates to (may be invalid where the data pertains to root tracks) */ FMovieSceneEvaluationOperand Operand; }; /** * Interface that must be used for all persistent data objects */ struct IPersistentEvaluationData { virtual ~IPersistentEvaluationData(){} }; DECLARE_CYCLE_STAT(TEXT("Persistent Data Access"), MovieSceneEval_PersistentData_Access, STATGROUP_MovieSceneEval); /** * Structure that stores persistent data that track templates may need during evaluation. * Such data can be thought of as a cache which exists as long as the track is being evaluated. * The cache can store any abstract data provided it implements IPersistentEvaluationData. * Data is stored in buckets that is keyed on either the track (ie, accessible from all child templates/sections), or section (only accessible within the section) * Type-safety (through the templated methods) is the responsibility of the user. There should only ever be 1 type of data for each section/track association. */ struct FPersistentEvaluationData { /** * Proxy constructor from 2 externally owned maps for entity, and shared data */ MOVIESCENE_API FPersistentEvaluationData(IMovieScenePlayer& InPlayer); FPersistentEvaluationData(const FPersistentEvaluationData&) = delete; FPersistentEvaluationData& operator=(const FPersistentEvaluationData&) = delete; public: /** * User accessor functions for persistent data relating to the current track */ template T& GetOrAddTrackData() { return GetOrAdd(TrackKey); } template T& AddTrackData() { return Add(TrackKey); } template T& GetTrackData() { return Get(TrackKey); } template T* FindTrackData() { return Find(TrackKey); } /**~ Section data access is considered const as it can only ever be accessed from a single template (it can do whatever it likes with its own data) */ template T& GetTrackData() const { return Get(TrackKey); } template T* FindTrackData() const { return Find(TrackKey); } void ResetTrackData() { Reset(TrackKey); } /** * User accessor functions for persistent data relating to the current section */ template T& GetOrAddSectionData() { return GetOrAdd(SectionKey); } template T& AddSectionData() { return Add(SectionKey); } /**~ Section data access is considered const as it can only ever be accessed from a single template (it can do whatever it likes with its own data) */ template T& GetSectionData() const { return Get(SectionKey); } template T* FindSectionData() const { return Find(SectionKey); } void ResetSectionData() { Reset(SectionKey); } /** * Get the raw instance data for the current sequence */ MOVIESCENE_API const FMovieSceneSequenceInstanceData* GetInstanceData() const; /** * Get the player */ IMovieScenePlayer& GetMovieScenePlayer() const { return Player; } /** * Find the current sequence's instance data as the templated type, provided its type matches */ template const T* FindInstanceData() const { const FMovieSceneSequenceInstanceData* InstanceData = GetInstanceData(); if (InstanceData && (&InstanceData->GetScriptStruct() == T::StaticStruct())) { return static_cast(InstanceData); } return nullptr; } public: /** * Get the currently set track key (ie the track we're currently evaluating) */ const FMovieSceneEvaluationKey& GetTrackKey() const { return TrackKey; } /** * Get the currently set section key (ie the section we're currently evaluating) */ const FMovieSceneEvaluationKey& GetSectionKey() const { return SectionKey; } /** * Set the current track */ void SetTrackKey(const FMovieSceneEvaluationKey& Key) const { TrackKey = Key; } /** * Set the current section */ void SetSectionKey(const FMovieSceneEvaluationKey& Key) const { SectionKey = Key; } /** * Set the current section based off the current track with the specified section identifier */ const FMovieSceneEvaluationKey& DeriveSectionKey(uint32 InSectionIdentifier) const { SectionKey = TrackKey.AsSection(InSectionIdentifier); return SectionKey; } public: /** * User accessor functions for shared data keys */ template T& GetOrAdd(const FSharedPersistentDataKey& InKey) { MOVIESCENE_DETAILED_SCOPE_CYCLE_COUNTER(MovieSceneEval_PersistentData_Access) check(SharedData); if (TUniquePtr* Existing = SharedData->Find(InKey)) { return static_cast(*Existing->Get()); } return Add(InKey); } template T& Add(const FSharedPersistentDataKey& InKey) { MOVIESCENE_DETAILED_SCOPE_CYCLE_COUNTER(MovieSceneEval_PersistentData_Access) check(SharedData); T* Ptr = new T; SharedData->Add(InKey, TUniquePtr(Ptr)); return *Ptr; } template T* Find(const FSharedPersistentDataKey& InKey) { MOVIESCENE_DETAILED_SCOPE_CYCLE_COUNTER(MovieSceneEval_PersistentData_Access) if (ensure(SharedData)) { TUniquePtr* Existing = SharedData->Find(InKey); return Existing ? static_cast(Existing->Get()) : nullptr; } return nullptr; } template const T* Find(const FSharedPersistentDataKey& InKey) const { MOVIESCENE_DETAILED_SCOPE_CYCLE_COUNTER(MovieSceneEval_PersistentData_Access) if (ensure(SharedData)) { const TUniquePtr* Existing = SharedData->Find(InKey); return Existing ? static_cast(Existing->Get()) : nullptr; } return nullptr; } template T& Get(const FSharedPersistentDataKey& InKey) { MOVIESCENE_DETAILED_SCOPE_CYCLE_COUNTER(MovieSceneEval_PersistentData_Access) T* Ptr = Find(InKey); check(Ptr); return *Ptr; } template const T& Get(const FSharedPersistentDataKey& InKey) const { MOVIESCENE_DETAILED_SCOPE_CYCLE_COUNTER(MovieSceneEval_PersistentData_Access) const T* Ptr = Find(InKey); check(Ptr); return *Ptr; } void Reset(const FSharedPersistentDataKey& InKey) { MOVIESCENE_DETAILED_SCOPE_CYCLE_COUNTER(MovieSceneEval_PersistentData_Access) if (ensure(SharedData)) { SharedData->Remove(InKey); } } private: /** Implementation methods */ template T& GetOrAdd(const FMovieSceneEvaluationKey& InKey) { MOVIESCENE_DETAILED_SCOPE_CYCLE_COUNTER(MovieSceneEval_PersistentData_Access) check(EntityData); if (TUniquePtr* Existing = EntityData->Find(InKey)) { return static_cast(*Existing->Get()); } return Add(InKey); } template T& Add(const FMovieSceneEvaluationKey& InKey) { MOVIESCENE_DETAILED_SCOPE_CYCLE_COUNTER(MovieSceneEval_PersistentData_Access) check(EntityData); T* Ptr = new T; EntityData->Add(InKey, TUniquePtr(Ptr)); return *Ptr; } template T* Find(const FMovieSceneEvaluationKey& InKey) const { MOVIESCENE_DETAILED_SCOPE_CYCLE_COUNTER(MovieSceneEval_PersistentData_Access) if (ensure(EntityData)) { const TUniquePtr* Existing = EntityData->Find(InKey); return Existing ? static_cast(Existing->Get()) : nullptr; } return nullptr; } template T& Get(const FMovieSceneEvaluationKey& InKey) const { MOVIESCENE_DETAILED_SCOPE_CYCLE_COUNTER(MovieSceneEval_PersistentData_Access) T* Ptr = Find(InKey); check(Ptr); return *Ptr; } void Reset(const FMovieSceneEvaluationKey& InKey) { MOVIESCENE_DETAILED_SCOPE_CYCLE_COUNTER(MovieSceneEval_PersistentData_Access) if (ensure(EntityData)) { EntityData->Remove(InKey); } } private: /** The movie scene player */ IMovieScenePlayer& Player; /** Persistent data that's associated with a template entity (such as a track or a section) */ TMap>* EntityData; /** Persistent data that's shared across multiple template entities */ TMap>* SharedData; // The keys themselves are mutable since this a proxy representation of the data above. // For a const FPersistentEvaluationData& we can change the ptr to the persistent data, but we can't change the data itself (as with a const T*) mutable FMovieSceneEvaluationKey TrackKey; mutable FMovieSceneEvaluationKey SectionKey; };