// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "UObject/Class.h" #include "MassTypeManager.h" #include "MassEntityHandle.h" #include "MassEntityRelations.h" #define UE_API MASSENTITY_API struct FMassEntityHandle; struct FMassEntityManager; struct FMassExecutionContext; namespace UE::Mass { struct FTypeRegistry; struct FRelationManager; struct FRelationData { FRelationData(const FRelationTypeTraits& InTraits); const FRelationTypeTraits Traits; struct FRelationInstanceData { TStaticArray, static_cast(ERelationRole::MAX)> RelationEntityContainers; bool IsEmpty() const { bool bIsEmpty = true; for (const TArray& Container : RelationEntityContainers) { bIsEmpty = bIsEmpty && Container.IsEmpty(); } return bIsEmpty; } TArray& operator[](const int32 Index) { return RelationEntityContainers[Index]; } const TArray& operator[](const int32 Index) const { return RelationEntityContainers[Index]; } TArray& operator[](const ERelationRole Index) { return (*this)[static_cast(Index)]; } const TArray& operator[](const ERelationRole Index) const { return (*this)[static_cast(Index)]; } }; TMap RoleMap; TArray GetParticipants(const FMassEntityManager& EntityManager, const FMassEntityHandle RoleEntity, ERelationRole QueriedRole) const; }; struct FRelationManager { UE_API explicit FRelationManager(FMassEntityManager& EntityManager); template FMassEntityHandle CreateRelationInstance(FMassEntityHandle Subject, FMassEntityHandle Object); FMassEntityHandle CreateRelationInstance(const FTypeHandle RelationTypeHandle, FMassEntityHandle Subject, FMassEntityHandle Object); /** Creates a relation type handle with RelationType, and calls the other CreateRelationInstances implementation */ TArray CreateRelationInstances(TNotNull RelationType, TArrayView Subjects, TArrayView Objects); /** * Creates valid relation instances of type RelationTypeHandle, binding Subjects and Objects * Note that the input arrays can have their order modified by the function, all the relation pairs that are not valid, are moved to the back of the arrays * The number of elements in Subjects and Objects must match. */ UE_API TArray CreateRelationInstances(const FTypeHandle RelationTypeHandle, TArrayView Subjects, TArrayView Objects); UE_API bool DestroyRelationInstance(const FTypeHandle RelationTypeHandle, const FMassEntityHandle Subject, const FMassEntityHandle Object); UE_API bool DestroyRelationInstance(FMassRelationRoleInstanceHandle RelationHandle) const; /** Fetch all the entities that are "subjects" in instances of the given relation type, where ObjectEntity is the "object" of the relation */ [[nodiscard]] TArray GetRelationSubjects(TNotNull RelationType, const FMassEntityHandle ObjectEntity) const; [[nodiscard]] TArray GetRelationSubjects(const FTypeHandle RelationTypeHandle, const FMassEntityHandle ObjectEntity) const; /** Fetch all the entities that are "objects" in instances of the given relation type, where SubjectEntity is the "subject" of the relation */ [[nodiscard]] TArray GetRelationObjects(TNotNull RelationType, const FMassEntityHandle SubjectEntity) const; [[nodiscard]] TArray GetRelationObjects(const FTypeHandle RelationTypeHandle, const FMassEntityHandle SubjectEntity) const; [[nodiscard]] TArray GetRelationEntities(TConstArrayView RelationEntitiesContainer) const; void GetRelationEntities(TConstArrayView RelationEntitiesContainer, TArray& InOutEntityHandles) const; [[nodiscard]] TArray GetRoleEntities(TConstArrayView RelationEntitiesContainer) const; void GetRoleEntities(TConstArrayView RelationEntitiesContainer, TArray& InOutEntityHandles) const; FTypeHandle GetRelationTypeHandle(TNotNull RelationType) const; UE_API bool IsSubjectOfRelation(const FTypeHandle RelationTypeHandle, const FMassEntityHandle Subject, const FMassEntityHandle Object) const; UE_API bool IsSubjectOfRelation(const FRelationData& RelationDataInstance, const FMassEntityHandle Subject, const FMassEntityHandle Object) const; UE_API bool IsSubjectOfRelationRecursive(const FTypeHandle RelationTypeHandle, const FMassEntityHandle Subject, const FMassEntityHandle Object) const; UE_API bool IsSubjectOfRelationRecursive(const FRelationData& RelationDataInstance, const FMassEntityHandle Subject, const FMassEntityHandle Object) const; void OnRelationTypeRegistered(const FTypeHandle RegisteredTypeHandle, const FRelationTypeTraits& RelationTypeTraits); const FRelationData& GetRelationDataChecked(const FTypeHandle RelationTypeHandle) const; FRelationData& GetRelationDataChecked(const FTypeHandle RelationTypeHandle); protected: FRelationData& CreateRelationData(const FTypeHandle RelationTypeHandle); UE_API TArray GetRelationObjects(const FRelationData& RelationData, const FMassEntityHandle SubjectEntity) const; UE_API TArray GetRelationSubjects(const FRelationData& RelationData, const FMassEntityHandle ObjectEntity) const; const FRelationData* GetRelationData(const FTypeHandle RelationTypeHandle) const; struct FHierarchyEntitiesContainer { void StoreUnique(const uint32 Depth, TArray& InOutArray); void StoreUnique(const uint32 Depth, FMassEntityHandle Handle); TArray& operator[](const uint32 Depth) { return ContainerPerLevel[Depth]; } const TArray& operator[](const uint32 Depth) const { return ContainerPerLevel[Depth]; } uint32 Num() const { return static_cast(ContainerPerLevel.Num()); } protected: TArray> ContainerPerLevel; TSet ExistingElements; }; void GatherHierarchy(const FRelationData& RelationData, const FMassEntityHandle SubjectHandle, FHierarchyEntitiesContainer& SubSubjects, uint32 Depth = 0) const; FMassEntityManager& EntityManager; const FTypeManager& TypeManager; TMap RelationsDataMap; }; //----------------------------------------------------------------------------- // INLINES //----------------------------------------------------------------------------- template FMassEntityHandle FRelationManager::CreateRelationInstance(FMassEntityHandle Subject, FMassEntityHandle Object) { TArray CreatedRelationshipEntities = CreateRelationInstances(T::StaticStruct(), TArrayView(&Subject, 1), TArrayView(&Object, 1)); return CreatedRelationshipEntities.IsEmpty() ? FMassEntityHandle() : CreatedRelationshipEntities[0]; } inline FMassEntityHandle FRelationManager::CreateRelationInstance(const FTypeHandle RelationTypeHandle, FMassEntityHandle Subject, FMassEntityHandle Object) { TArray CreatedRelationshipEntities = CreateRelationInstances(RelationTypeHandle, TArrayView(&Subject, 1), TArrayView(&Object, 1)); return CreatedRelationshipEntities.IsEmpty() ? FMassEntityHandle() : CreatedRelationshipEntities[0]; } inline TArray FRelationManager::CreateRelationInstances(TNotNull RelationType, TArrayView Subjects, TArrayView Objects) { const FTypeHandle RelationTypeHandle = TypeManager.GetRelationTypeHandle(RelationType); if (!ensureMsgf(RelationTypeHandle.IsValid(), TEXT("%hs: Unknown relation type %s, make sure to register it first"), __FUNCTION__, *RelationType->GetName())) { return {}; } return CreateRelationInstances(RelationTypeHandle, Subjects, Objects); } inline FTypeHandle FRelationManager::GetRelationTypeHandle(TNotNull RelationType) const { checkf(UE::Mass::IsA(RelationType) , TEXT("Provided RelationType, %s, is not a relation type") , *RelationType->GetName()); return TypeManager.GetRelationTypeHandle(RelationType); } inline const FRelationData* FRelationManager::GetRelationData(const FTypeHandle RelationTypeHandle) const { return RelationsDataMap.Find(RelationTypeHandle); } inline const FRelationData& FRelationManager::GetRelationDataChecked(const FTypeHandle RelationTypeHandle) const { return RelationsDataMap.FindChecked(RelationTypeHandle); } inline FRelationData& FRelationManager::GetRelationDataChecked(const FTypeHandle RelationTypeHandle) { return RelationsDataMap.FindChecked(RelationTypeHandle); } inline TArray FRelationManager::GetRelationSubjects(TNotNull RelationType, const FMassEntityHandle ObjectEntity) const { const FTypeHandle RelationTypeHandle = TypeManager.GetRelationTypeHandle(RelationType); return GetRelationSubjects(RelationTypeHandle, ObjectEntity); } inline TArray FRelationManager::GetRelationSubjects(const FTypeHandle RelationTypeHandle, const FMassEntityHandle ObjectEntity) const { const FRelationData& RelationData = GetRelationDataChecked(RelationTypeHandle); return GetRelationSubjects(RelationData, ObjectEntity); } inline TArray FRelationManager::GetRelationObjects(TNotNull RelationType, const FMassEntityHandle SubjectEntity) const { const FTypeHandle RelationTypeHandle = TypeManager.GetRelationTypeHandle(RelationType); return GetRelationObjects(RelationTypeHandle, SubjectEntity); } inline TArray FRelationManager::GetRelationObjects(const FTypeHandle RelationTypeHandle, const FMassEntityHandle SubjectEntity) const { const FRelationData& RelationData = GetRelationDataChecked(RelationTypeHandle); return GetRelationObjects(RelationData, SubjectEntity); } } // namespace UE::Mass #undef UE_API