Files
UnrealEngine/Engine/Plugins/Animation/LiveLink/Source/LiveLinkMovieScene/Public/MovieScene/MovieSceneLiveLinkStructPropertyBindings.h
2025-05-18 13:04:45 +08:00

294 lines
10 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "UObject/UnrealType.h"
#include "UObject/WeakFieldPtr.h"
#define UE_API LIVELINKMOVIESCENE_API
/**
* Manages bindings to keyed properties of LiveLink UStructs.
*/
class FLiveLinkStructPropertyBindings
{
public:
UE_API FLiveLinkStructPropertyBindings(FName InPropertyName, const FString& InPropertyPath);
/**
* Rebuilds the property mappings for a specific UStruct, and adds them to the cache
*
* @param InContainer The type to cache property for
*/
UE_API void CacheBinding(const UScriptStruct& InStruct);
/**
* Gets the FProperty that is bound to the container
*
* @param InContainer The Struct that owns the property
* @return The property on the Struct if it exists
*/
UE_API FProperty* GetProperty(const UScriptStruct& InStruct) const;
/**
* Gets the current value of a property on a UStruct
*
* @param InStruct The struct to get the property from
* @param InSourceAddress The source address of the struct instance
* @return ValueType The current value
*/
template <typename ValueType>
UE_DEPRECATED(4.24, "This function is deprecated. Use a GetCurrentValueAt with InIndex set to 0 for the same result.")
ValueType GetCurrentValue(const UScriptStruct& InStruct, const void* InSourceAddress)
{
return GetCurrentValueAt<ValueType>(0, InStruct, InSourceAddress);
}
/**
* Gets the current value of a property at desired Index. Must be on ArrayProperty
*
* @param InIndex The index of the desired value in the ArrayProperty
* @param InStruct The struct to get the property from
* @param InSourceAddress The source address of the struct instance
* @return ValueType The current value
*/
template <typename ValueType>
ValueType GetCurrentValueAt(int32 InIndex, const UScriptStruct& InStruct, const void* InSourceAddress)
{
FPropertyWrapper FoundProperty = FindOrAdd(InStruct);
if (FProperty* Property = FoundProperty.GetProperty())
{
if (FArrayProperty* ArrayProperty = CastField<FArrayProperty>(Property))
{
const ValueType* BaseAddr = FoundProperty.GetPropertyAddress<ValueType>(InSourceAddress, 0);
FScriptArrayHelper ArrayHelper(ArrayProperty, BaseAddr);
ArrayHelper.ExpandForIndex(InIndex);
const ValueType* ValuePtr = reinterpret_cast<const ValueType*>(ArrayHelper.GetRawPtr(InIndex));
return ValuePtr ? *ValuePtr : ValueType();
}
else
{
checkSlow(InIndex >= 0 && InIndex < Property->ArrayDim);
const ValueType* BaseAddr = FoundProperty.GetPropertyAddress<ValueType>(InSourceAddress, InIndex);
return BaseAddr ? *BaseAddr : ValueType();
}
}
return ValueType();
}
/**
* Gets the current value of an enum property on a struct
*
* @param InStruct The struct to get the property from
* @param InSourceAddress The address of the instanced struct
* @return ValueType The current value
*/
UE_DEPRECATED(4.24, "This function is deprecated. Use a GetCurrentValueForEnumAt with InIndex set to 0 for the same result.")
int64 GetCurrentValueForEnum(const UScriptStruct& InStruct, const void* InSourceAddress)
{
return GetCurrentValueForEnumAt(0, InStruct, InSourceAddress);
}
/**
* Gets the current value of an enum property at desired index
*
* @param InIndex The index of the desired value in the ArrayProperty
* @param InStruct The struct to get the property from
* @param InSourceAddress The address of the instanced struct
* @return ValueType The current value
*/
UE_API int64 GetCurrentValueForEnumAt(int32 InIndex, const UScriptStruct& InStruct, const void* InSourceAddress);
/**
* Sets the current value of a property on an instance of a UStruct
*
* @param InStruct The struct to set the property on
* @param InSourceAddress The address of the instanced struct
* @param InValue The value to set
*/
template <typename ValueType>
UE_DEPRECATED(4.24, "This function is deprecated. Use a SetCurrentValueAt with InIndex set to 0 for the same result.")
void SetCurrentValue(const UScriptStruct& InStruct, void* InSourceAddress, typename TCallTraits<ValueType>::ParamType InValue)
{
SetCurrentValueAt<ValueType>(0, InStruct, InSourceAddress, InValue);
}
/**
* Sets the current value of a property on an instance of a UStruct
*
* @param InIndex The index in the array property to set the value on
* @param InStruct The struct to set the property on
* @param InSourceAddress The address of the instanced struct
* @param InValue The value to set
*/
template <typename ValueType>
void SetCurrentValueAt(int32 InIndex, const UScriptStruct& InStruct, void* InSourceAddress, typename TCallTraits<ValueType>::ParamType InValue)
{
FPropertyWrapper FoundProperty = FindOrAdd(InStruct);
if (FProperty* Property = FoundProperty.GetProperty())
{
if (FArrayProperty* ArrayProperty = CastField<FArrayProperty>(Property))
{
ValueType* BaseAddr = FoundProperty.GetPropertyAddress<ValueType>(InSourceAddress, 0);
FScriptArrayHelper ArrayHelper(ArrayProperty, BaseAddr);
ArrayHelper.ExpandForIndex(InIndex);
ValueType* ValuePtr = reinterpret_cast<ValueType*>(ArrayHelper.GetRawPtr(InIndex));
if (ValuePtr)
{
*ValuePtr = InValue;
}
}
else
{
checkSlow(InIndex >= 0 && InIndex < Property->ArrayDim);
ValueType* BaseAddr = FoundProperty.GetPropertyAddress<ValueType>(InSourceAddress, InIndex);
if (BaseAddr)
{
*BaseAddr = InValue;
}
}
}
}
/**
* Sets the current value of an Enum property on an instance of a UStruct
*
* @param InStruct The struct to set the property on
* @param InSourceAddress The address of the instanced struct
* @param InValue The value to set
*/
UE_DEPRECATED(4.24, "This function is deprecated. Use a SetCurrentValueForEnumAt with InIndex set to 0 for the same result.")
void SetCurrentValueForEnum(const UScriptStruct& InStruct, void* InSourceAddress, int64 InValue)
{
SetCurrentValueForEnumAt(0, InStruct, InSourceAddress, InValue);
}
/**
* Sets the current value of an Enum property on an instance of a UStruct to a certain Index
*
* @param InIndex, Index where to write the value
* @param InStruct The struct to set the property on
* @param InSourceAddress The address of the instanced struct
* @param InValue The value to set
*/
UE_API void SetCurrentValueForEnumAt(int32 InIndex, const UScriptStruct& InStruct, void* InSourceAddress, int64 InValue);
/** @return the property path that this binding was initialized from */
const FString& GetPropertyPath() const
{
return PropertyPath;
}
/** @return the property name that this binding was initialized from */
const FName& GetPropertyName() const
{
return PropertyName;
}
private:
struct FPropertyNameKey
{
FPropertyNameKey(FName InStructName, FName InPropertyName)
: StructName(InStructName), PropertyName(InPropertyName)
{}
bool operator==(const FPropertyNameKey& Other) const
{
return (StructName == Other.StructName) && (PropertyName == Other.PropertyName);
}
friend uint32 GetTypeHash(const FPropertyNameKey& Key)
{
return HashCombine(GetTypeHash(Key.StructName), GetTypeHash(Key.PropertyName));
}
FName StructName;
FName PropertyName;
};
struct FPropertyWrapper
{
TWeakFieldPtr<FProperty> Property;
int64 DeltaAddress;
FProperty* GetProperty() const
{
FProperty* PropertyPtr = Property.Get();
if (PropertyPtr && !PropertyPtr->HasAnyFlags(RF_BeginDestroyed | RF_FinishDestroyed))
{
return PropertyPtr;
}
return nullptr;
}
template<typename ValueType>
ValueType* GetPropertyAddress(void* BaseContainerAddress, int32 Index) const
{
FProperty* PropertyPtr = GetProperty();
const PTRINT NewAddress = (PTRINT)BaseContainerAddress + DeltaAddress;
return PropertyPtr ? PropertyPtr->ContainerPtrToValuePtr<ValueType>((void*)NewAddress, Index) : nullptr;
}
template<typename ValueType>
const ValueType* GetPropertyAddress(const void* BaseContainerAddress, int32 Index) const
{
FProperty* PropertyPtr = GetProperty();
const PTRINT NewAddress = (PTRINT)BaseContainerAddress + DeltaAddress;
return PropertyPtr ? PropertyPtr->ContainerPtrToValuePtr<const ValueType>((void*)NewAddress, Index) : nullptr;
}
FPropertyWrapper()
: Property(nullptr)
, DeltaAddress(0)
{}
};
static UE_API FPropertyWrapper FindPropertyRecursive(const UScriptStruct* InStruct, TArray<FString>& InPropertyNames, uint32 Index, void* ContainerAddress, int32 PreviousDelta);
static UE_API FPropertyWrapper FindProperty(const UScriptStruct& InStruct, const FString& InPropertyName);
/** Find or add the FPropertyWrapper for the specified struct */
FPropertyWrapper FindOrAdd(const UScriptStruct& InStruct)
{
FPropertyNameKey Key(InStruct.GetFName(), PropertyName);
const FPropertyWrapper* PropertyWrapper = PropertyCache.Find(Key);
if (PropertyWrapper)
{
return *PropertyWrapper;
}
CacheBinding(InStruct);
return PropertyCache.FindRef(Key);
}
private:
/** Mapping of UStructs property */
static UE_API TMap<FPropertyNameKey, FPropertyWrapper> PropertyCache;
/** Path to the property we are bound to */
FString PropertyPath;
/** Actual name of the property we are bound to */
FName PropertyName;
};
/** Explicit specializations for bools */
template<>
UE_DEPRECATED(4.24, "This function is deprecated. Use a GetCurrentValueAt with InIndex set to 0 for the same result.")
LIVELINKMOVIESCENE_API bool FLiveLinkStructPropertyBindings::GetCurrentValue<bool>(const UScriptStruct& InStruct, const void* InSourceAddress);
template<>
UE_DEPRECATED(4.24, "This function is deprecated. Use a SetCurrentValueAt with InIndex set to 0 for the same result.")
LIVELINKMOVIESCENE_API void FLiveLinkStructPropertyBindings::SetCurrentValue<bool>(const UScriptStruct& InStruct, void* InSourceAddress, TCallTraits<bool>::ParamType InValue);
template<> LIVELINKMOVIESCENE_API bool FLiveLinkStructPropertyBindings::GetCurrentValueAt<bool>(int32 InIndex, const UScriptStruct& InStruct, const void* InSourceAddress);
template<> LIVELINKMOVIESCENE_API void FLiveLinkStructPropertyBindings::SetCurrentValueAt<bool>(int32 InIndex, const UScriptStruct& InStruct, void* InSourceAddress, TCallTraits<bool>::ParamType InValue);
#undef UE_API