Files
UnrealEngine/Engine/Source/Runtime/MassEntity/Public/MassRelationManager.h
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

231 lines
10 KiB
C++

// 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<TArray<FMassRelationRoleInstanceHandle>, static_cast<uint32>(ERelationRole::MAX)> RelationEntityContainers;
bool IsEmpty() const
{
bool bIsEmpty = true;
for (const TArray<FMassRelationRoleInstanceHandle>& Container : RelationEntityContainers)
{
bIsEmpty = bIsEmpty && Container.IsEmpty();
}
return bIsEmpty;
}
TArray<FMassRelationRoleInstanceHandle>& operator[](const int32 Index)
{
return RelationEntityContainers[Index];
}
const TArray<FMassRelationRoleInstanceHandle>& operator[](const int32 Index) const
{
return RelationEntityContainers[Index];
}
TArray<FMassRelationRoleInstanceHandle>& operator[](const ERelationRole Index)
{
return (*this)[static_cast<int32>(Index)];
}
const TArray<FMassRelationRoleInstanceHandle>& operator[](const ERelationRole Index) const
{
return (*this)[static_cast<int32>(Index)];
}
};
TMap<FMassEntityHandle, FRelationInstanceData> RoleMap;
TArray<FMassEntityHandle> GetParticipants(const FMassEntityManager& EntityManager, const FMassEntityHandle RoleEntity, ERelationRole QueriedRole) const;
};
struct FRelationManager
{
UE_API explicit FRelationManager(FMassEntityManager& EntityManager);
template<UE::Mass::CRelation T>
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<FMassEntityHandle> CreateRelationInstances(TNotNull<const UScriptStruct*> RelationType, TArrayView<FMassEntityHandle> Subjects, TArrayView<FMassEntityHandle> 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<FMassEntityHandle> CreateRelationInstances(const FTypeHandle RelationTypeHandle, TArrayView<FMassEntityHandle> Subjects, TArrayView<FMassEntityHandle> 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<FMassEntityHandle> GetRelationSubjects(TNotNull<const UScriptStruct*> RelationType, const FMassEntityHandle ObjectEntity) const;
[[nodiscard]] TArray<FMassEntityHandle> 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<FMassEntityHandle> GetRelationObjects(TNotNull<const UScriptStruct*> RelationType, const FMassEntityHandle SubjectEntity) const;
[[nodiscard]] TArray<FMassEntityHandle> GetRelationObjects(const FTypeHandle RelationTypeHandle, const FMassEntityHandle SubjectEntity) const;
[[nodiscard]] TArray<FMassEntityHandle> GetRelationEntities(TConstArrayView<FMassRelationRoleInstanceHandle> RelationEntitiesContainer) const;
void GetRelationEntities(TConstArrayView<FMassRelationRoleInstanceHandle> RelationEntitiesContainer, TArray<FMassEntityHandle>& InOutEntityHandles) const;
[[nodiscard]] TArray<FMassEntityHandle> GetRoleEntities(TConstArrayView<FMassRelationRoleInstanceHandle> RelationEntitiesContainer) const;
void GetRoleEntities(TConstArrayView<FMassRelationRoleInstanceHandle> RelationEntitiesContainer, TArray<FMassEntityHandle>& InOutEntityHandles) const;
FTypeHandle GetRelationTypeHandle(TNotNull<const UScriptStruct*> 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<FMassEntityHandle> GetRelationObjects(const FRelationData& RelationData, const FMassEntityHandle SubjectEntity) const;
UE_API TArray<FMassEntityHandle> GetRelationSubjects(const FRelationData& RelationData, const FMassEntityHandle ObjectEntity) const;
const FRelationData* GetRelationData(const FTypeHandle RelationTypeHandle) const;
struct FHierarchyEntitiesContainer
{
void StoreUnique(const uint32 Depth, TArray<FMassEntityHandle>& InOutArray);
void StoreUnique(const uint32 Depth, FMassEntityHandle Handle);
TArray<FMassEntityHandle>& operator[](const uint32 Depth)
{
return ContainerPerLevel[Depth];
}
const TArray<FMassEntityHandle>& operator[](const uint32 Depth) const
{
return ContainerPerLevel[Depth];
}
uint32 Num() const
{
return static_cast<uint32>(ContainerPerLevel.Num());
}
protected:
TArray<TArray<FMassEntityHandle>> ContainerPerLevel;
TSet<FMassEntityHandle> ExistingElements;
};
void GatherHierarchy(const FRelationData& RelationData, const FMassEntityHandle SubjectHandle, FHierarchyEntitiesContainer& SubSubjects, uint32 Depth = 0) const;
FMassEntityManager& EntityManager;
const FTypeManager& TypeManager;
TMap<FTypeHandle, FRelationData> RelationsDataMap;
};
//-----------------------------------------------------------------------------
// INLINES
//-----------------------------------------------------------------------------
template<UE::Mass::CRelation T>
FMassEntityHandle FRelationManager::CreateRelationInstance(FMassEntityHandle Subject, FMassEntityHandle Object)
{
TArray<FMassEntityHandle> CreatedRelationshipEntities = CreateRelationInstances(T::StaticStruct(), TArrayView<FMassEntityHandle>(&Subject, 1), TArrayView<FMassEntityHandle>(&Object, 1));
return CreatedRelationshipEntities.IsEmpty() ? FMassEntityHandle() : CreatedRelationshipEntities[0];
}
inline FMassEntityHandle FRelationManager::CreateRelationInstance(const FTypeHandle RelationTypeHandle, FMassEntityHandle Subject, FMassEntityHandle Object)
{
TArray<FMassEntityHandle> CreatedRelationshipEntities = CreateRelationInstances(RelationTypeHandle, TArrayView<FMassEntityHandle>(&Subject, 1), TArrayView<FMassEntityHandle>(&Object, 1));
return CreatedRelationshipEntities.IsEmpty() ? FMassEntityHandle() : CreatedRelationshipEntities[0];
}
inline TArray<FMassEntityHandle> FRelationManager::CreateRelationInstances(TNotNull<const UScriptStruct*> RelationType, TArrayView<FMassEntityHandle> Subjects, TArrayView<FMassEntityHandle> 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<const UScriptStruct*> RelationType) const
{
checkf(UE::Mass::IsA<FMassRelation>(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<FMassEntityHandle> FRelationManager::GetRelationSubjects(TNotNull<const UScriptStruct*> RelationType, const FMassEntityHandle ObjectEntity) const
{
const FTypeHandle RelationTypeHandle = TypeManager.GetRelationTypeHandle(RelationType);
return GetRelationSubjects(RelationTypeHandle, ObjectEntity);
}
inline TArray<FMassEntityHandle> FRelationManager::GetRelationSubjects(const FTypeHandle RelationTypeHandle, const FMassEntityHandle ObjectEntity) const
{
const FRelationData& RelationData = GetRelationDataChecked(RelationTypeHandle);
return GetRelationSubjects(RelationData, ObjectEntity);
}
inline TArray<FMassEntityHandle> FRelationManager::GetRelationObjects(TNotNull<const UScriptStruct*> RelationType, const FMassEntityHandle SubjectEntity) const
{
const FTypeHandle RelationTypeHandle = TypeManager.GetRelationTypeHandle(RelationType);
return GetRelationObjects(RelationTypeHandle, SubjectEntity);
}
inline TArray<FMassEntityHandle> FRelationManager::GetRelationObjects(const FTypeHandle RelationTypeHandle, const FMassEntityHandle SubjectEntity) const
{
const FRelationData& RelationData = GetRelationDataChecked(RelationTypeHandle);
return GetRelationObjects(RelationData, SubjectEntity);
}
} // namespace UE::Mass
#undef UE_API