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

443 lines
16 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Containers/ArrayView.h"
#include "CoreMinimal.h"
#include "CoreTypes.h"
#include "Misc/AssertionMacros.h"
#include "Misc/Guid.h"
#include "MovieSceneFwd.h"
#include "MovieSceneSequenceID.h"
#include "Templates/TypeHash.h"
#include "UObject/Class.h"
#include "UObject/ObjectMacros.h"
#include "UObject/WeakObjectPtrTemplates.h"
#include "MovieSceneObjectBindingID.generated.h"
class FArchive;
class IMovieScenePlayer;
class UMovieSceneSequence;
struct FMovieSceneSequenceHierarchy;
namespace UE
{
namespace MovieScene
{
struct FSequenceInstance;
struct FSharedPlaybackState;
/**
* A binding ID whose target is resolved relative to the owner of this ID (either internal or external to that sequence through a parent or grandparent)
* Should be used for asignment to any serialized FMovieSceneObjectBindingID
* Represented by a local object binding ID and a parent index to which it is relative
*/
struct FRelativeObjectBindingID
{
FRelativeObjectBindingID(const FGuid& InGuid)
: Guid(InGuid)
, SequenceID(MovieSceneSequenceID::Root)
, ResolveParentIndex(0)
{}
FRelativeObjectBindingID(const FGuid& InGuid, FMovieSceneSequenceID InSequenceID)
: Guid(InGuid)
, SequenceID(InSequenceID)
, ResolveParentIndex(0)
{}
FRelativeObjectBindingID(const FGuid& InGuid, FMovieSceneSequenceID InSequenceID, int32 InParentIndex)
: Guid(InGuid)
, SequenceID(InSequenceID)
, ResolveParentIndex(InParentIndex)
{}
/**
* Construction from a root sequence asset
*
* @param SourceSequenceID Absolute sequence ID within RootSequence that represents the start of the path (ie, the sequence that this binding ID is serialized within)
* @param TargetSequenceID Absolute sequence ID within RootSequence that holds the target object
* @param TargetGuid The GUID of the object binding within TargetSequenceID that represents the object at runtime
* @param RootSequence The root sequence asset
*/
MOVIESCENE_API FRelativeObjectBindingID(FMovieSceneSequenceID SourceSequenceID, FMovieSceneSequenceID TargetSequenceID, const FGuid& TargetGuid, UMovieSceneSequence* RootSequence);
/**
* Construction from a root sequence Hierarchy
*
* @param SourceSequenceID Absolute sequence ID within Hierarchy that represents the start of the path (ie, the sequence that this binding ID is serialized within)
* @param TargetSequenceID Absolute sequence ID within Hierarchy that holds the target object
* @param TargetGuid The GUID of the object binding within TargetSequenceID that represents the object at runtime
* @param Hierarchy The hierachy to use for computation of the relative path. Many be nullptr where Source and Targets are both MovieSceneSequenceID::Root
*/
MOVIESCENE_API FRelativeObjectBindingID(FMovieSceneSequenceID SourceSequenceID, FMovieSceneSequenceID TargetSequenceID, const FGuid& TargetGuid, const FMovieSceneSequenceHierarchy* Hierarchy);
/**
* Construction from a root sequence Player
*
* @param SourceSequenceID Absolute sequence ID within Player's root sequence hierarchy that represents the start of the path (ie, the sequence that this binding ID is serialized within)
* @param TargetSequenceID Absolute sequence ID within Player's root sequence hierarchy that holds the target object
* @param TargetGuid The GUID of the object binding within TargetSequenceID that represents the object at runtime
* @param Player The movie scene player that is currently playing the root sequence
*/
MOVIESCENE_API FRelativeObjectBindingID(FMovieSceneSequenceID SourceSequenceID, FMovieSceneSequenceID TargetSequenceID, const FGuid& TargetGuid, TSharedRef<const FSharedPlaybackState> SharedPlaybackState);
MOVIESCENE_API FRelativeObjectBindingID(FMovieSceneSequenceID SourceSequenceID, FMovieSceneSequenceID TargetSequenceID, const FGuid& TargetGuid, IMovieScenePlayer& Player);
/** GUID of the Object Binding (ie, FMovieSceneBinding::GetObjectGuid) */
FGuid Guid;
/** The sequence ID that the object binding is found within - relative to nth parent specified by ResolveParentIndex */
FMovieSceneSequenceID SequenceID;
/** The parent index denoting where to resolve this binding from */
int32 ResolveParentIndex;
private:
void ConstructInternal(FMovieSceneSequenceID SourceSequenceID, FMovieSceneSequenceID TargetSequenceID, const FGuid& TargetGuid, const FMovieSceneSequenceHierarchy* Hierarchy);
};
/**
* A binding ID that is only resolveable through a fixed root sequence.
* Use of this type should be reserved for editor code dealing with a specific sequence hierarchy
* where hashing or comparison is required.
* The SequenceID member is always an absolute sequence ID
*/
struct FFixedObjectBindingID
{
FFixedObjectBindingID()
{}
FFixedObjectBindingID(const FGuid& InGuid, FMovieSceneSequenceID InSequenceID)
: Guid(InGuid)
, SequenceID(InSequenceID)
{}
public:
friend uint32 GetTypeHash(const FFixedObjectBindingID& A)
{
return GetTypeHash(A.Guid) ^ GetTypeHash(A.SequenceID);
}
friend bool operator==(const FFixedObjectBindingID& A, const FFixedObjectBindingID& B)
{
return A.Guid == B.Guid && A.SequenceID == B.SequenceID;
}
friend bool operator!=(const FFixedObjectBindingID& A, const FFixedObjectBindingID& B)
{
return A.Guid != B.Guid || A.SequenceID != B.SequenceID;
}
public:
/**
* Convert this fixed binding ID to one that is resolved relative to the specified Sequence.
*
* @param SourceSequenceID The sequence ID to make this fixed ID relative to
* @param InPlayer The active movie scene player to retrieve a root sequence hierarchy from
* @return A new binding ID that will resolve relative to the specified sequence
*/
MOVIESCENE_API FRelativeObjectBindingID ConvertToRelative(FMovieSceneSequenceID SourceSequenceID, TSharedRef<const FSharedPlaybackState> SharedPlaybackState) const;
MOVIESCENE_API FRelativeObjectBindingID ConvertToRelative(FMovieSceneSequenceID SourceSequenceID, IMovieScenePlayer& InPlayer) const;
/**
* Convert this fixed binding ID to one that is resolved relative to the specified Sequence.
*
* @param SourceSequenceID The sequence ID to make this fixed ID relative to
* @param Hierarchy The hierarchy that represents the root sequence that SourceSequenceID is contained within
* @return A new binding ID that will resolve relative to the specified sequence
*/
MOVIESCENE_API FRelativeObjectBindingID ConvertToRelative(FMovieSceneSequenceID SourceSequenceID, const FMovieSceneSequenceHierarchy* Hierarchy) const;
public:
/** GUID of the Object Binding (ie, FMovieSceneBinding::GetObjectGuid) */
FGuid Guid;
/** The sequence ID that the object binding is found within */
FMovieSceneSequenceID SequenceID;
};
} // namespace MovieScene
} // namespace UE
/** Enumeration specifying how a movie scene object binding ID relates to the sequence */
UENUM()
enum class EMovieSceneObjectBindingSpace : uint8
{
/** The object binding sequence ID resolves from a local sequence (ie, it may need to accumulate a parent sequence ID before it resolves correctly) */
Local,
/** The object binding sequence ID resolves from the root of the sequence */
Root,
/** Default value for any newly-constructed bindings */
Unused UMETA(Hidden),
};
/**
* Persistent identifier to a specific object binding within a sequence hierarchy.
*
* Binding IDs come in 3 flavors with Local and External being preferred as they are reslilient towards sequences being authored in isolation or included in other root sequences:
* Local: (ResolveParentIndex == 0) SequenceID relates to _this sequence's_ local hierarchy; represents an object binding within the same sequence as the ID is resolved, or inside one of its sub-sequences. Sequence ID must be remapped at runtime.
* External: (ResolveParentIndex > 0) SequenceID is local to the parent sequence of this one denoted by the parent index (ie, 1 = parent, 2 = grandparent etc). Sequence ID must be remapped at runtime.
* Fixed: Represents a binding anywhere in the sequence; always resolved from the root sequence.
*
* Fixed bindings will break if the sequence is evaluated inside a different root sequence.
*/
USTRUCT(BlueprintType, meta=(HasNativeMake))
struct FMovieSceneObjectBindingID
{
using FSharedPlaybackState = UE::MovieScene::FSharedPlaybackState;
GENERATED_BODY()
/**
* Default construction to a root empty. Only to be used for UObject serialization and default UObject construction
*/
FMovieSceneObjectBindingID()
// Defaults purposefully match the equivalent of a legacy root binding
// such that any pre-existing ::Root space binding upgrades to ResolveParentIndex = -1
// and ::Local space bindings will get upgraded in PostSerialize
: SequenceID(int32(MovieSceneSequenceID::Root.GetInternalValue()))
, ResolveParentIndex(FixedRootSequenceParentIndex)
{
LegacyInit();
}
/**
* Construction from an external object binding ID
*/
FMovieSceneObjectBindingID(const UE::MovieScene::FRelativeObjectBindingID& InID)
: Guid(InID.Guid)
, SequenceID(InID.SequenceID.GetInternalValue())
, ResolveParentIndex(InID.ResolveParentIndex)
{
LegacyInit();
}
/**
* Construction from a fixed object binding ID
*/
FMovieSceneObjectBindingID(const UE::MovieScene::FFixedObjectBindingID& InID)
: Guid(InID.Guid)
, SequenceID(InID.SequenceID.GetInternalValue())
, ResolveParentIndex(FixedRootSequenceParentIndex)
{
LegacyInit();
}
public:
/**
* Assignment from an external object binding ID
*/
FMovieSceneObjectBindingID& operator=(const UE::MovieScene::FRelativeObjectBindingID& InID)
{
Guid = InID.Guid;
SequenceID = InID.SequenceID.GetInternalValue();
ResolveParentIndex = InID.ResolveParentIndex;
return *this;
}
/**
* Assignment from a fixed object binding ID
*/
FMovieSceneObjectBindingID& operator=(const UE::MovieScene::FFixedObjectBindingID& InID)
{
Guid = InID.Guid;
SequenceID = InID.SequenceID.GetInternalValue();
ResolveParentIndex = FixedRootSequenceParentIndex;
return *this;
}
public:
friend uint32 GetTypeHash(const FMovieSceneObjectBindingID& A)
{
return GetTypeHash(A.Guid) ^ GetTypeHash(A.SequenceID);
}
friend bool operator==(const FMovieSceneObjectBindingID& A, const FMovieSceneObjectBindingID& B)
{
return A.Guid == B.Guid && A.SequenceID == B.SequenceID && A.ResolveParentIndex == B.ResolveParentIndex;
}
friend bool operator!=(const FMovieSceneObjectBindingID& A, const FMovieSceneObjectBindingID& B)
{
return A.Guid != B.Guid || A.SequenceID != B.SequenceID || A.ResolveParentIndex != B.ResolveParentIndex;
}
public:
/**
* Check whether this object binding ID has been set to something valied
* @note: does not imply that the ID resolves to a valid object
*/
bool IsValid() const
{
return Guid.IsValid();
}
/**
* Check whether this binding is fixed to the root sequence - these bindings should be avoided or fixed up where possible to ensure portability
*/
bool IsFixedBinding() const
{
return Guid.IsValid() && ResolveParentIndex == FixedRootSequenceParentIndex;
}
/**
* Access the guid that identifies the object binding within the sequence
*/
const FGuid& GetGuid() const
{
return Guid;
}
/**
* Set the guid that identifies the object binding within the sequence
*/
void SetGuid(const FGuid& InGuid)
{
#if WITH_EDITORONLY_DATA
ensureMsgf(Space_DEPRECATED == EMovieSceneObjectBindingSpace::Unused, TEXT("Assigning a GUID for a binding which has no type specifier - consider using Local / External / Fixed instead"));
#endif
Guid = InGuid;
}
/**
* Get the relative sequence ID for this binding.
* @note: The meaning of this sequence ID is dependent upon ResolveParentIndex so should only be used where the context is known
*/
FMovieSceneSequenceID GetRelativeSequenceID() const
{
return FMovieSceneSequenceID(SequenceID);
}
/**
* Resolve this binding ID to a fixed object binding ID resolvable from the root sequence
*
* @param SourceSequenceID The source sequence ID that owns this binding ID
* @param Player The movie scene player that is currently playing the root sequence
* @return A fixed binding ID whose SequenceID relates to the root sequence hierarchy
*/
MOVIESCENE_API UE::MovieScene::FFixedObjectBindingID ResolveToFixed(FMovieSceneSequenceID SourceSequenceID, TSharedRef<const FSharedPlaybackState> SharedPlaybackState) const;
MOVIESCENE_API UE::MovieScene::FFixedObjectBindingID ResolveToFixed(FMovieSceneSequenceID SourceSequenceID, IMovieScenePlayer& Player) const;
/**
* Resolve the sequence ID for this binding for the root sequence
*
* @param SourceSequenceID The source sequence ID that owns this binding ID
* @param Player The movie scene player that is currently playing the sequence
* @return The sequence ID that holds the target object
*/
MOVIESCENE_API FMovieSceneSequenceID ResolveSequenceID(FMovieSceneSequenceID SourceSequenceID, TSharedRef<const FSharedPlaybackState> SharedPlaybackState) const;
MOVIESCENE_API FMovieSceneSequenceID ResolveSequenceID(FMovieSceneSequenceID SourceSequenceID, IMovieScenePlayer& Player) const;
/**
* Resolve the sequence ID for this binding for the root sequence
*
* @param SourceSequenceID The source sequence ID that owns this binding ID
* @param Hierarchy The hierachy to use for computation of the relative path. Many be nullptr where Source and Targets are both MovieSceneSequenceID::Root
* @return The sequence ID that holds the target object
*/
MOVIESCENE_API FMovieSceneSequenceID ResolveSequenceID(FMovieSceneSequenceID SourceSequenceID, const FMovieSceneSequenceHierarchy* Hierarchy) const;
/**
* Resolve all the bound objects for this binding ID
*
* @param SourceSequenceID The source sequence ID that owns this binding ID
* @param Hierarchy The hierachy to use for computation of the relative path. Many be nullptr where Source and Targets are both MovieSceneSequenceID::Root
* @return An array view of all bound objects
*/
MOVIESCENE_API TArrayView<TWeakObjectPtr<>> ResolveBoundObjects(FMovieSceneSequenceID SourceSequenceID, TSharedRef<const FSharedPlaybackState> SharedPlaybackState) const;
MOVIESCENE_API TArrayView<TWeakObjectPtr<>> ResolveBoundObjects(FMovieSceneSequenceID SourceSequenceID, IMovieScenePlayer& Player) const;
/**
* Resolve all the bound objects for this binding ID
*
* @param SequenceInstance The sequence instance for the sub sequence that is resolving the binding
* @return An array view of all bound objects
*/
MOVIESCENE_API TArrayView<TWeakObjectPtr<>> ResolveBoundObjects(const UE::MovieScene::FSequenceInstance& SequenceInstance) const;
/**
* Reinterpret this binding ID as a fixed binding. Should only be used when ResolveParentIndex == -1, although this is not enforced.
*/
UE::MovieScene::FFixedObjectBindingID ReinterpretAsFixed() const
{
return UE::MovieScene::FFixedObjectBindingID(Guid, FMovieSceneSequenceID(SequenceID));
}
public:
#if WITH_EDITORONLY_DATA
void PostSerialize(const FArchive& Ar);
#endif
private:
static constexpr int32 FixedRootSequenceParentIndex = -1;
/** Identifier for the object binding within the sequence */
UPROPERTY(EditAnywhere, Category="Binding")
FGuid Guid;
/** Sequence ID stored as an int32 so that it can be used in the blueprint VM */
UPROPERTY()
int32 SequenceID;
/** The parent index to resolve the sequence ID from. 0 signifies the sequence this binding ID is serialized within, -1 signifies the root sequence (previously EMovieSceneObjectBindingSpace::Root) */
UPROPERTY()
int32 ResolveParentIndex;
private:
void LegacyInit()
{
#if WITH_EDITORONLY_DATA
Space_DEPRECATED = EMovieSceneObjectBindingSpace::Unused;
#endif
}
#if WITH_EDITORONLY_DATA
/** DEPRECATED: The binding's resolution space */
UPROPERTY()
EMovieSceneObjectBindingSpace Space_DEPRECATED;
#endif // WITH_EDITORONLY_DATA
};
template<> struct TStructOpsTypeTraits<FMovieSceneObjectBindingID> : public TStructOpsTypeTraitsBase2<FMovieSceneObjectBindingID>
{
#if WITH_EDITORONLY_DATA
enum
{
WithPostSerialize = true,
};
#endif
};