// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "InstancedStruct.h" #include "StructView.h" #include "StateTreeInstanceData.generated.h" /** * StateTree instance data layout describes the layout of the instance data. */ struct STATETREEMODULE_API FStateTreeInstanceDataLayout { /** Struct describing each item in the layout. */ struct FLayoutItem { const UScriptStruct* ScriptStruct = nullptr; int32 Offset = 0; }; /** * Creates instance data layout from an array of structs. * @return shared pointer to the layout */ static TSharedPtr Create(TConstArrayView Structs); /** @retrun the memory size required for the instance data. */ int32 GetLayoutInstanceSize() const; /** @return the minimum alignment required by the instance data. */ int32 GetLayoutInstanceMinAlignment() const; /** @return number if items in the layout. */ int32 Num() const { return NumItems; } /** @return layout item at specified index */ FLayoutItem& GetMutableItem(const int32 Index) const { check(Index >= 0 && Index < NumItems); FLayoutItem* Items = GetItemsPtr(); return Items[Index]; } /** @return const layout item at specified index */ const FLayoutItem& GetItem(const int32 Index) const { return GetMutableItem(Index); } private: FStateTreeInstanceDataLayout() = default; FLayoutItem* GetItemsPtr() const { static constexpr int32 ItemsOffset = Align(sizeof(FStateTreeInstanceDataLayout), alignof( FLayoutItem)); return ( FLayoutItem*)((uint8*)(this) + ItemsOffset); } struct FLayoutMemoryDeleter { FORCEINLINE void operator()(FStateTreeInstanceDataLayout* Layout) const { FMemory::Free(Layout); } }; /** Number of items in the layout. */ int32 NumItems = 0; }; /** * StateTree instance data is used to store the runtime state of a StateTree. * The layout of the data is described in a FStateTreeInstanceDataLayout. */ USTRUCT() struct STATETREEMODULE_API FStateTreeInstanceData { GENERATED_BODY() FStateTreeInstanceData() = default; ~FStateTreeInstanceData() { Reset(); } /** Creates new layout from an array if instanced structs, and copies the values into the instance data. */ void Initialize(TConstArrayView InValues); /** Shares the layout from another instance data, and copies the data over. */ void CopyFrom(const FStateTreeInstanceData& InOther); /** Resets the data to empty. */ void Reset(); /** @return Number of items in the instance data. */ int32 Num() const { return Layout.IsValid() ? Layout->Num() : 0; } /** @return true if the instance is correctly initialized. */ bool IsValid() const { return Memory != nullptr && Layout.IsValid(); } /** @return the layout of the instance data. */ TSharedPtr GetLayout() const { return Layout; }; /** @return the script struct describing an item at specified index. */ const UScriptStruct* GetScriptStruct(const int32 Index) const { check(IsValid()); const FStateTreeInstanceDataLayout::FLayoutItem& Item = Layout->GetItem(Index); return Item.ScriptStruct; } /** @returns mutable reference to the struct at specified index, this getter assumes that all data is valid. */ template T& GetMutable(const int32 Index) const { check(IsValid()); const FStateTreeInstanceDataLayout::FLayoutItem& Item = Layout->GetItem(Index); check(Item.ScriptStruct != nullptr); check(Item.ScriptStruct == T::StaticStruct() || Item.ScriptStruct->IsChildOf(T::StaticStruct())); return *((T*)(Memory + Item.Offset)); } /** @returns mutable pointer to the struct at specified index, or nullptr if cast is not valid. */ template T* GetMutablePtr(const int32 Index) const { check(IsValid()); const FStateTreeInstanceDataLayout::FLayoutItem& Item = Layout->GetItem(Index); if (Item.ScriptStruct != nullptr && (Item.ScriptStruct == T::StaticStruct() || Item.ScriptStruct->IsChildOf(T::StaticStruct()))) { return (T*)(Memory + Item.Offset); } return nullptr; } /** @return view to the struct at specified index. */ FStructView GetMutable(const int32 Index) const { check(IsValid()); const FStateTreeInstanceDataLayout::FLayoutItem& Item = Layout->GetItem(Index); return FStructView(Item.ScriptStruct, Memory + Item.Offset); } /** @returns const reference to the struct at specified index, this getter assumes that all data is valid. */ template const T& Get(const int32 Index) const { return GetMutable(Index); } /** @returns const pointer to the struct at specified index, or nullptr if cast is not valid. */ template const T* GetPtr(const int32 Index) const { return GetMutablePtr(Index); } /** @return const view to the struct at specified index. */ FConstStructView Get(const int32 Index) const { return GetMutable(Index); } void AddStructReferencedObjects(class FReferenceCollector& Collector) const; private: void Allocate(const TSharedPtr& InLayout); uint8* Memory = nullptr; TSharedPtr Layout; }; template<> struct TStructOpsTypeTraits : public TStructOpsTypeTraitsBase2 { enum { WithAddStructReferencedObjects = true, }; };