Files
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

383 lines
17 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "PropertyBindingPath.h"
#include "PropertyBindingTypes.h"
#include "UObject/Interface.h"
#include "UObject/WeakInterfacePtr.h"
#include "PropertyBindingBindingCollection.generated.h"
struct FPropertyBindingBindableStructDescriptor;
struct FPropertyBindingBinding;
struct FPropertyBindingDataView;
struct FPropertyBindingPath;
class IPropertyBindingBindingCollectionOwner;
// @todo: Should have a common interface for binding iterator that supports removal op to remove the need of Internal virtual functions
/**
* Base structure to inherit from to facilitate operations on property bindings.
* @see FPropertyBindingExtension, IPropertyBindingBindingCollectionOwner
*/
USTRUCT()
struct FPropertyBindingBindingCollection
{
GENERATED_BODY()
virtual ~FPropertyBindingBindingCollection() = default;
/** Result returned from a visitor functor indicating to continue or to quit early */
enum class EVisitResult : uint8
{
/** Stop iterating through bindings and early exit */
Break,
/** Continue to iterate through all bindings */
Continue
};
/** Get the associated bindings owner. */
IPropertyBindingBindingCollectionOwner* GetBindingsOwner() const
{
return BindingsOwner.GetInterface();
}
/** Sets associated bindings owner, used to validate added property paths. */
void SetBindingsOwner(TScriptInterface<IPropertyBindingBindingCollectionOwner> InBindingsOwner)
{
BindingsOwner = InBindingsOwner;
#if WITH_EDITOR
OnBindingsOwnerSet(BindingsOwner);
#endif
}
#if WITH_EDITOR
/** Enum describing what is required for a binding path to be considered a match for a binding */
enum class ESearchMode : uint8
{
/** Binding with exact matching path */
Exact,
/** Binding with path that matches but the binding path can be longer */
Includes,
};
/** Can be overridden by derived classed to track newly assigned bindings owner interface. */
virtual void OnBindingsOwnerSet(TScriptInterface<IPropertyBindingBindingCollectionOwner> InBindingsOwner)
{
}
/**
* Adds binding between source and destination paths. Removes any bindings to InTargetPath before adding the new one.
* @param InSourcePath Binding source property path.
* @param InTargetPath Binding target property path.
*/
PROPERTYBINDINGUTILS_API void AddBinding(const FPropertyBindingPath& InSourcePath, const FPropertyBindingPath& InTargetPath);
/**
* Removes all bindings to target path.
* @param InTargetPath Target property path.
* @param InSearchMode Requirement for InTargetPath to be considered a match for a binding
*/
PROPERTYBINDINGUTILS_API void RemoveBindings(const FPropertyBindingPath& InTargetPath, ESearchMode InSearchMode = ESearchMode::Exact);
/**
* Removes all bindings that match the predicate
* @param InPredicate Predicate to validate the binding
*/
PROPERTYBINDINGUTILS_API void RemoveBindings(TFunctionRef<bool(FPropertyBindingBinding&)> InPredicate);
/**
* Removes bindings which do not point to valid structs IDs.
* @param InValidStructs Set of struct IDs that are currently valid.
*/
PROPERTYBINDINGUTILS_API void RemoveInvalidBindings(const TMap<FGuid, const FPropertyBindingDataView>& InValidStructs);
/**
* Has any binding to the target path.
* @return True of the target path has any bindings.
*/
PROPERTYBINDINGUTILS_API bool HasBinding(const FPropertyBindingPath& InTargetPath, ESearchMode InSearchMode = ESearchMode::Exact) const;
/**
* @return binding to the target path.
*/
PROPERTYBINDINGUTILS_API const FPropertyBindingBinding* FindBinding(const FPropertyBindingPath& InTargetPath, ESearchMode InSearchMode = ESearchMode::Exact) const;
/**
* Copies property bindings from an existing struct to another.
* Overrides a binding to a specific property if it already exists in InToStructID.
* @param InFromStructID ID of the struct to copy from.
* @param InToStructID ID of the struct to copy to.
*/
PROPERTYBINDINGUTILS_API void CopyBindings(const FGuid InFromStructID, const FGuid InToStructID);
/**
* @return Source path for given target path, or null if binding does not exist.
*/
PROPERTYBINDINGUTILS_API const FPropertyBindingPath* GetBindingSource(const FPropertyBindingPath& InTargetPath) const;
/**
* Returns all pointers to bindings for a specified structs based in struct ID.
* @param InStructID ID of the struct to find bindings for.
* @param OutBindings Bindings for specified struct.
*/
PROPERTYBINDINGUTILS_API void GetBindingsFor(const FGuid InStructID, TArray<const FPropertyBindingBinding*>& OutBindings) const;
protected:
virtual FPropertyBindingBinding* AddBindingInternal(const FPropertyBindingPath& InSourcePath, const FPropertyBindingPath& InTargetPath) PURE_VIRTUAL(FPropertyBindingBindingCollection::AddBindingInternal, return nullptr; );
PROPERTYBINDINGUTILS_API virtual void CopyBindingsInternal(const FGuid InFromStructID, const FGuid InToStructID);
virtual void RemoveBindingsInternal(TFunctionRef<bool(FPropertyBindingBinding&)> InPredicate) PURE_VIRTUAL(FPropertyBindingBindingCollection::RemoveBindingsInternal, );
virtual bool HasBindingInternal(TFunctionRef<bool(const FPropertyBindingBinding&)> InPredicate) const PURE_VIRTUAL(FPropertyBindingBindingCollection::HasBindingInternal, return false; );
virtual const FPropertyBindingBinding* FindBindingInternal(TFunctionRef<bool(const FPropertyBindingBinding&)> InPredicate) const PURE_VIRTUAL(FPropertyBindingBindingCollection::FindBindingInternal, return nullptr; );
/** Copies property bindings from an existing struct to another. */
PROPERTYBINDINGUTILS_API void CopyBindingsImplementation(const FGuid InFromStructID, const FGuid InToStructID, TFunctionRef<bool(const FPropertyBindingBinding& Binding)> CanCopy);
/** Update newly added binding's segments from struct value so that the segments are up to date. */
PROPERTYBINDINGUTILS_API void UpdateSegmentsForNewlyAddedBinding(FPropertyBindingBinding& AddedBinding);
#endif // WITH_EDITOR
const UObject* GetLogOwner() const;
public:
FPropertyBindingCopyInfoBatch& AddCopyBatch()
{
return CopyBatches.AddDefaulted_GetRef();
}
int32 GetNumCopyBatches() const
{
return CopyBatches.Num();
}
const TArray<FPropertyBindingCopyInfoBatch>& GetCopyBatches() const
{
return CopyBatches;
}
TArray<FPropertyBindingCopyInfoBatch>& GetMutableCopyBatches()
{
return CopyBatches;
}
/** @return Number of bindable struct descriptors available in the collection. */
virtual int32 GetNumBindableStructDescriptors() const PURE_VIRTUAL(FPropertyBindingBindingCollection::GetNumBindableStructDescriptors, return INDEX_NONE;);
virtual const FPropertyBindingBindableStructDescriptor* GetBindableStructDescriptorFromHandle(FConstStructView InSourceHandleView) const PURE_VIRTUAL(FPropertyBindingBindingCollection::GetBindableStructDescriptorFromHandle, return nullptr; );
/** @return The amount of registered bindings. */
virtual int32 GetNumBindings() const PURE_VIRTUAL(FPropertyBindingBindingCollection::GetNumBindings, return INDEX_NONE;);
/**
* Iterates through all bindings and calls the provided function on each non-mutable binding.
* @param InFunction Function to call on each binding.
* @note To be able to modify the binding, use ForEachMutableBinding
* @note To be able to break iteration, use VisitBindings or VisitMutableBindings
* @see ForEachMutableBinding, VisitBindings, VisitMutableBindings
*/
virtual void ForEachBinding(TFunctionRef<void(const FPropertyBindingBinding& Binding)> InFunction) const PURE_VIRTUAL(FPropertyBindingBindingCollection::ForEachBinding, );
/**
* Iterates through all bindings between indices [Begin, End[ and calls the provided function on each non-mutable binding.
* @param InBegin Index of the first binding to process
* @param InEnd Index to one past the last binding to process
* @param InFunction Function to call on each binding.
* @note To be able to modify the binding, use ForEachMutableBinding
* @note To be able to break iteration, use VisitBindings or VisitMutableBindings
* @see ForEachMutableBinding, VisitBindings, VisitMutableBindings
*/
virtual void ForEachBinding(FPropertyBindingIndex16 InBegin, FPropertyBindingIndex16 InEnd, TFunctionRef<void(const FPropertyBindingBinding& Binding, const int32 BindingIndex)> InFunction) const PURE_VIRTUAL(FPropertyBindingBindingCollection::ForEachBinding, );
/**
* Iterates through all bindings and calls the provided function on each mutable binding.
* @param InFunction Function to call on each binding.
* @note For read access only, consider using ForEachBinding
* @note To be able to break iteration, use VisitBindings or VisitMutableBindings
* @see ForEachBinding, VisitBindings, VisitMutableBindings
*/
virtual void ForEachMutableBinding(TFunctionRef<void(FPropertyBindingBinding& Binding)> InFunction) PURE_VIRTUAL(FPropertyBindingBindingCollection::ForEachMutableBinding, );
/**
* Iterates through all bindings and calls the provided function on each non-mutable binding.
* That function must return whether the iteration should stop or not (i.e., EVisitResult::Break / Continue).
* @param InFunction Function to call on each binding and that indicates whether the visit should stop
* @note To be able to modify the binding use VisitMutableBindings
* @note If breaking the iteration is not required, consider using ForEachBinding or ForEachMutableBinding
* @see VisitMutableBindings, ForEachBinding, ForEachMutableBinding
*/
virtual void VisitBindings(TFunctionRef<EVisitResult(const FPropertyBindingBinding& Binding)> InFunction) const PURE_VIRTUAL(FPropertyBindingBindingCollection::VisitBindings, );
/**
* Iterates through all bindings and calls the provided function on each mutable binding.
* That function must return whether the iteration should stop or not (i.e., EVisitResult::Break / Continue).
* @param InFunction Function to call on each binding and that indicates whether the visit should stop.
* @note For read access only, consider using VisitBindings
* @note If breaking the iteration is not required, consider using ForEachBinding or ForEachMutableBinding
* @see VisitBindings, ForEachBinding, ForEachMutableBinding
*/
virtual void VisitMutableBindings(TFunctionRef<EVisitResult(FPropertyBindingBinding& Binding)> InFunction) PURE_VIRTUAL(FPropertyBindingBindingCollection::VisitMutableBindings, );
/**
* Clears all bindings and related data.
*/
PROPERTYBINDINGUTILS_API void Reset();
/**
* Optional virtual that derived classes could override to when bindings should be reset.
*/
virtual void OnReset()
{
}
/**
* Resolves paths to indirections.
* @return True if resolve succeeded.
*/
[[nodiscard]] PROPERTYBINDINGUTILS_API bool ResolvePaths();
/**
* Optional virtual that derived classes could override to resolve additional paths.
* @return True if resolve succeeded.
*/
[[nodiscard]] virtual bool OnResolvingPaths()
{
return true;
}
/**
* @return True if bindings have been resolved.
*/
bool IsValid() const
{
return bBindingsResolved;
}
/**
* Copies a property from Source to Target based on the provided Copy.
* @param Copy Describes which parameter and how is copied.
* @param SourceStructView Pointer and type for the source containing the property to be copied.
* @param TargetStructView Pointer and type for the target containing the property to be copied.
* @return true if the property was copied successfully.
*/
PROPERTYBINDINGUTILS_API bool CopyProperty(const FPropertyBindingCopyInfo& Copy, FPropertyBindingDataView SourceStructView, FPropertyBindingDataView TargetStructView) const;
/** @return copy batch at specified index. */
const FPropertyBindingCopyInfoBatch& GetBatch(const FPropertyBindingIndex16 TargetBatchIndex) const
{
check(TargetBatchIndex.IsValid());
return CopyBatches[TargetBatchIndex.Get()];
}
/** @return All the property copies for a specific batch. */
TConstArrayView<FPropertyBindingCopyInfo> GetBatchCopies(const FPropertyBindingIndex16 TargetBatchIndex) const
{
return GetBatchCopies(GetBatch(TargetBatchIndex));
}
/** @return All the property copies for a specific batch. */
TConstArrayView<FPropertyBindingCopyInfo> GetBatchCopies(const FPropertyBindingCopyInfoBatch& Batch) const
{
const int32 Count = Batch.BindingsEnd.Get() - Batch.BindingsBegin.Get();
if (Count == 0)
{
return {};
}
return MakeArrayView(&PropertyCopies[Batch.BindingsBegin.Get()], Count);
}
/**
* Resets copied properties in TargetStructView. Can be used e.g. to erase UObject references.
* @param TargetBatchIndex Batch index to copy (see FStateTreePropertyBindingCompiler).
* @param TargetStructView View to struct where properties are copied to.
* @return true if all resets succeeded (a reset can fail e.g. if source or destination struct view is invalid).
*/
PROPERTYBINDINGUTILS_API bool ResetObjects(const FPropertyBindingIndex16 TargetBatchIndex, FPropertyBindingDataView TargetStructView) const;
/**
* @return true if any of the elements in the property bindings contains any of the structs in the set.
*/
PROPERTYBINDINGUTILS_API bool ContainsAnyStruct(const TSet<const UStruct*>& InStructs) const;
/**
* Resolves copy info for a resolved binding.
* Will resolve CopyType, CopySize and Leaf Properties. The other information has already been set in ResolvePaths.
* @param InResolvedBinding Resolved Binding corresponding to the resulting copy type,
* @param InBindingSourceLeafIndirection Property path indirections of the leaf property of binding source,
* @param InBindingTargetLeafIndirection Property path indirections of the leaf property of binding target.
* @param OutCopyInfo Resulting copy type.
* @return true if copy was resolved, or false if no copy could be resolved.
*/
[[nodiscard]] PROPERTYBINDINGUTILS_API virtual bool ResolveBindingCopyInfo(const FPropertyBindingBinding& InResolvedBinding, const FPropertyBindingPathIndirection& InBindingSourceLeafIndirection, const FPropertyBindingPathIndirection& InBindingTargetLeafIndirection, FPropertyBindingCopyInfo& OutCopyInfo);
UE_DEPRECATED(5.7, "ResolveCopyType is deprecated. Use ResolveBindingCopyInfo instead.")
[[nodiscard]] static bool ResolveCopyType(const FPropertyBindingPathIndirection& SourceIndirection, const FPropertyBindingPathIndirection& TargetIndirection, FPropertyBindingCopyInfo& OutCopy, const UScriptStruct* StructReferenceType = nullptr)
{
return false;
}
protected:
#if WITH_EDITOR || WITH_PROPERTYBINDINGUTILS_DEBUG
[[nodiscard]] PROPERTYBINDINGUTILS_API FString DebugAsString() const;
#endif
[[nodiscard]] PROPERTYBINDINGUTILS_API bool ResolvePath(const UStruct* Struct, const FPropertyBindingPath& Path, FPropertyBindingPropertyIndirection& OutFirstIndirection, FPropertyBindingPathIndirection& OutLeafIndirection);
[[nodiscard]] PROPERTYBINDINGUTILS_API bool ResolvePath(const FPropertyBindingDataView DataView, const FPropertyBindingPath& Path, FPropertyBindingPropertyIndirection& OutFirstIndirection, FPropertyBindingPathIndirection& OutLeafIndirection);
/**
* Resolves what kind of copy type to use between specified property indirections and what should be the correct copy size.
* @param InSourceIndirection Leaf path indirection of the copy source,
* @param InTargetIndirection Leaf path indirection of the copy target.
* @param OutCopyInfo copy info to resolve
* @return true if it was resolved, or false if it cannot be resolved between paths.
*/
[[nodiscard]] PROPERTYBINDINGUTILS_API bool ResolveCopyInfoBetweenIndirections(const FPropertyBindingPathIndirection& InSourceIndirection, const FPropertyBindingPathIndirection& InTargetIndirection, FPropertyBindingCopyInfo& OutCopyInfo) const;
PROPERTYBINDINGUTILS_API bool PerformCopy(const FPropertyBindingCopyInfo& Copy, uint8* SourceAddress, uint8* TargetAddress) const;
PROPERTYBINDINGUTILS_API void PerformResetObjects(const FPropertyBindingCopyInfo& Copy, uint8* TargetAddress) const;
PROPERTYBINDINGUTILS_API uint8* GetAddress(FPropertyBindingDataView InStructView, const FPropertyBindingPropertyIndirection& FirstIndirection, const FProperty* LeafProperty) const;
virtual void VisitSourceStructDescriptorInternal(TFunctionRef<EVisitResult(const FPropertyBindingBindableStructDescriptor& Descriptor)> InFunction) const
{
}
//~ Following members are protected for deprecation reasons
protected:
/** Array of copy batches. */
UPROPERTY()
TArray<FPropertyBindingCopyInfoBatch> CopyBatches;
/** Array of property copies */
UPROPERTY(Transient)
TArray<FPropertyBindingCopyInfo> PropertyCopies;
private:
/** Array of property indirections, indexed by accesses*/
UPROPERTY(Transient)
TArray<FPropertyBindingPropertyIndirection> PropertyIndirections;
/** Flag indicating if the properties has been resolved successfully . */
bool bBindingsResolved = false;
protected:
UPROPERTY(Transient)
TScriptInterface<IPropertyBindingBindingCollectionOwner> BindingsOwner = nullptr;
/** Type for struct references copy type */
TObjectPtr<UScriptStruct> PropertyReferenceStructType;
/** Functor to handle property copy for EPropertyCopyType::StructReference */
TFunction<void(const FStructProperty& SourceStructProperty, uint8* SourceAddress, uint8* TargetAddress)> PropertyReferenceCopyFunc;
/** Functor to handle reset object for EPropertyCopyType::StructReference */
TFunction<void(uint8* TargetAddress)> PropertyReferenceResetFunc;
};
template<>
struct TStructOpsTypeTraits<FPropertyBindingBindingCollection> : public TStructOpsTypeTraitsBase2<FPropertyBindingBindingCollection>
{
enum
{
WithPureVirtual = true,
};
};