您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
1073 行
41 KiB
1073 行
41 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using Unity.Assertions;
|
|
using Unity.Collections;
|
|
using Unity.Collections.LowLevel.Unsafe;
|
|
using Unity.Jobs;
|
|
using UnityEngine;
|
|
using UnityEngine.Scripting;
|
|
|
|
[assembly: InternalsVisibleTo("Unity.Entities.Hybrid")]
|
|
[assembly: InternalsVisibleTo("Unity.Entities.Properties")]
|
|
|
|
namespace Unity.Entities
|
|
{
|
|
//@TODO: There is nothing prevent non-main thread (non-job thread) access of EntityMnaager.
|
|
// Static Analysis or runtime checks?
|
|
|
|
public class EntityArchetypeQuery
|
|
{
|
|
public ComponentType[] Any;
|
|
public ComponentType[] None;
|
|
public ComponentType[] All;
|
|
}
|
|
|
|
//@TODO: safety?
|
|
public unsafe struct EntityArchetype : IEquatable<EntityArchetype>
|
|
{
|
|
[NativeDisableUnsafePtrRestriction] internal Archetype* Archetype;
|
|
|
|
public bool Valid => Archetype != null;
|
|
|
|
public static bool operator ==(EntityArchetype lhs, EntityArchetype rhs)
|
|
{
|
|
return lhs.Archetype == rhs.Archetype;
|
|
}
|
|
|
|
public static bool operator !=(EntityArchetype lhs, EntityArchetype rhs)
|
|
{
|
|
return lhs.Archetype != rhs.Archetype;
|
|
}
|
|
|
|
public override bool Equals(object compare)
|
|
{
|
|
return this == (EntityArchetype) compare;
|
|
}
|
|
|
|
public bool Equals(EntityArchetype entityArchetype)
|
|
{
|
|
return Archetype == entityArchetype.Archetype;
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return (int) Archetype;
|
|
}
|
|
|
|
public ComponentType[] ComponentTypes
|
|
{
|
|
get
|
|
{
|
|
var types = new ComponentType[Archetype->TypesCount];
|
|
for (var i = 0; i < types.Length; ++i)
|
|
types[i] = Archetype->Types[i].ToComponentType();
|
|
return types;
|
|
}
|
|
}
|
|
|
|
public int ChunkCount => Archetype->ChunkCount;
|
|
}
|
|
|
|
public struct Entity : IEquatable<Entity>
|
|
{
|
|
public int Index;
|
|
public int Version;
|
|
|
|
public static bool operator ==(Entity lhs, Entity rhs)
|
|
{
|
|
return lhs.Index == rhs.Index && lhs.Version == rhs.Version;
|
|
}
|
|
|
|
public static bool operator !=(Entity lhs, Entity rhs)
|
|
{
|
|
return lhs.Index != rhs.Index || lhs.Version != rhs.Version;
|
|
}
|
|
|
|
public override bool Equals(object compare)
|
|
{
|
|
return this == (Entity) compare;
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return Index;
|
|
}
|
|
|
|
public static Entity Null => new Entity();
|
|
|
|
public bool Equals(Entity entity)
|
|
{
|
|
return entity.Index == Index && entity.Version == Version;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return $"Entity Index: {Index} Version: {Version}";
|
|
}
|
|
}
|
|
|
|
[Preserve]
|
|
public sealed unsafe class EntityManager : ScriptBehaviourManager
|
|
{
|
|
EntityDataManager* m_Entities;
|
|
|
|
ArchetypeManager m_ArchetypeManager;
|
|
EntityGroupManager m_GroupManager;
|
|
|
|
internal SharedComponentDataManager m_SharedComponentManager;
|
|
|
|
ExclusiveEntityTransaction m_ExclusiveEntityTransaction;
|
|
|
|
ComponentType* m_CachedComponentTypeArray;
|
|
ComponentTypeInArchetype* m_CachedComponentTypeInArchetypeArray;
|
|
|
|
internal object m_CachedComponentList;
|
|
|
|
internal EntityDataManager* Entities
|
|
{
|
|
get => m_Entities;
|
|
private set => m_Entities = value;
|
|
}
|
|
|
|
internal ArchetypeManager ArchetypeManager
|
|
{
|
|
get => m_ArchetypeManager;
|
|
private set => m_ArchetypeManager = value;
|
|
}
|
|
|
|
public int Version => IsCreated ? m_Entities->Version : 0;
|
|
|
|
public uint GlobalSystemVersion => IsCreated ? Entities->GlobalSystemVersion : 0;
|
|
|
|
public bool IsCreated => m_CachedComponentTypeArray != null;
|
|
|
|
public int EntityCapacity
|
|
{
|
|
get => Entities->Capacity;
|
|
set
|
|
{
|
|
BeforeStructuralChange();
|
|
Entities->Capacity = value;
|
|
}
|
|
}
|
|
|
|
internal ComponentJobSafetyManager ComponentJobSafetyManager { get; private set; }
|
|
|
|
public JobHandle ExclusiveEntityTransactionDependency
|
|
{
|
|
get => ComponentJobSafetyManager.ExclusiveTransactionDependency;
|
|
set => ComponentJobSafetyManager.ExclusiveTransactionDependency = value;
|
|
}
|
|
|
|
EntityManagerDebug m_Debug;
|
|
|
|
public EntityManagerDebug Debug => m_Debug ?? (m_Debug = new EntityManagerDebug(this));
|
|
|
|
protected override void OnBeforeCreateManagerInternal(World world, int capacity)
|
|
{
|
|
}
|
|
|
|
protected override void OnBeforeDestroyManagerInternal()
|
|
{
|
|
}
|
|
|
|
protected override void OnAfterDestroyManagerInternal()
|
|
{
|
|
}
|
|
|
|
protected override void OnCreateManager(int capacity)
|
|
{
|
|
TypeManager.Initialize();
|
|
|
|
Entities = (EntityDataManager*) UnsafeUtility.Malloc(sizeof(EntityDataManager), 64, Allocator.Persistent);
|
|
Entities->OnCreate(capacity);
|
|
|
|
m_SharedComponentManager = new SharedComponentDataManager();
|
|
|
|
ArchetypeManager = new ArchetypeManager(m_SharedComponentManager);
|
|
ComponentJobSafetyManager = new ComponentJobSafetyManager();
|
|
m_GroupManager = new EntityGroupManager(ComponentJobSafetyManager);
|
|
|
|
m_ExclusiveEntityTransaction = new ExclusiveEntityTransaction(ArchetypeManager, m_GroupManager,
|
|
m_SharedComponentManager, Entities);
|
|
|
|
m_CachedComponentTypeArray =
|
|
(ComponentType*) UnsafeUtility.Malloc(sizeof(ComponentType) * 32 * 1024, 16, Allocator.Persistent);
|
|
m_CachedComponentTypeInArchetypeArray =
|
|
(ComponentTypeInArchetype*) UnsafeUtility.Malloc(sizeof(ComponentTypeInArchetype) * 32 * 1024, 16,
|
|
Allocator.Persistent);
|
|
}
|
|
|
|
protected override void OnDestroyManager()
|
|
{
|
|
EndExclusiveEntityTransaction();
|
|
|
|
ComponentJobSafetyManager.PreDisposeCheck();
|
|
|
|
// Clean up all entities. This is needed to free all internal buffer allocations so memory is not leaked.
|
|
using (var allEntities = GetAllEntities())
|
|
{
|
|
DestroyEntity(allEntities);
|
|
}
|
|
|
|
ComponentJobSafetyManager.Dispose();
|
|
ComponentJobSafetyManager = null;
|
|
|
|
Entities->OnDestroy();
|
|
UnsafeUtility.Free(Entities, Allocator.Persistent);
|
|
Entities = null;
|
|
ArchetypeManager.Dispose();
|
|
ArchetypeManager = null;
|
|
m_GroupManager.Dispose();
|
|
m_GroupManager = null;
|
|
m_ExclusiveEntityTransaction.OnDestroyManager();
|
|
|
|
m_SharedComponentManager.Dispose();
|
|
|
|
UnsafeUtility.Free(m_CachedComponentTypeArray, Allocator.Persistent);
|
|
m_CachedComponentTypeArray = null;
|
|
|
|
UnsafeUtility.Free(m_CachedComponentTypeInArchetypeArray, Allocator.Persistent);
|
|
m_CachedComponentTypeInArchetypeArray = null;
|
|
}
|
|
|
|
internal override void InternalUpdate()
|
|
{
|
|
}
|
|
|
|
private int PopulatedCachedTypeArray(ComponentType* requiredComponents, int count)
|
|
{
|
|
m_CachedComponentTypeArray[0] = ComponentType.Create<Entity>();
|
|
for (var i = 0; i < count; ++i)
|
|
SortingUtilities.InsertSorted(m_CachedComponentTypeArray, i + 1, requiredComponents[i]);
|
|
return count + 1;
|
|
}
|
|
|
|
private int PopulatedCachedTypeInArchetypeArray(ComponentType* requiredComponents, int count)
|
|
{
|
|
m_CachedComponentTypeInArchetypeArray[0] = new ComponentTypeInArchetype(ComponentType.Create<Entity>());
|
|
for (var i = 0; i < count; ++i)
|
|
SortingUtilities.InsertSorted(m_CachedComponentTypeInArchetypeArray, i + 1, requiredComponents[i]);
|
|
return count + 1;
|
|
}
|
|
|
|
internal ComponentGroup CreateComponentGroup(ComponentType* requiredComponents, int count)
|
|
{
|
|
var typeArrayCount = PopulatedCachedTypeArray(requiredComponents, count);
|
|
return m_GroupManager.CreateEntityGroup(ArchetypeManager, Entities, m_CachedComponentTypeArray, typeArrayCount);
|
|
}
|
|
|
|
internal ComponentGroup CreateComponentGroup(params ComponentType[] requiredComponents)
|
|
{
|
|
fixed (ComponentType* requiredComponentsPtr = requiredComponents)
|
|
{
|
|
return CreateComponentGroup(requiredComponentsPtr, requiredComponents.Length);
|
|
}
|
|
}
|
|
|
|
internal EntityArchetype CreateArchetype(ComponentType* types, int count)
|
|
{
|
|
var cachedComponentCount = PopulatedCachedTypeInArchetypeArray(types, count);
|
|
|
|
// Lookup existing archetype (cheap)
|
|
EntityArchetype entityArchetype;
|
|
entityArchetype.Archetype =
|
|
ArchetypeManager.GetExistingArchetype(m_CachedComponentTypeInArchetypeArray, cachedComponentCount);
|
|
if (entityArchetype.Archetype != null)
|
|
return entityArchetype;
|
|
|
|
// Creating an archetype invalidates all iterators / jobs etc
|
|
// because it affects the live iteration linked lists...
|
|
BeforeStructuralChange();
|
|
|
|
entityArchetype.Archetype = ArchetypeManager.GetOrCreateArchetype(m_CachedComponentTypeInArchetypeArray,
|
|
cachedComponentCount, m_GroupManager);
|
|
return entityArchetype;
|
|
}
|
|
|
|
public EntityArchetype CreateArchetype(params ComponentType[] types)
|
|
{
|
|
fixed (ComponentType* typesPtr = types)
|
|
{
|
|
return CreateArchetype(typesPtr, types.Length);
|
|
}
|
|
}
|
|
|
|
public void CreateEntity(EntityArchetype archetype, NativeArray<Entity> entities)
|
|
{
|
|
CreateEntityInternal(archetype, (Entity*) entities.GetUnsafePtr(), entities.Length);
|
|
}
|
|
|
|
public Entity CreateEntity(EntityArchetype archetype)
|
|
{
|
|
Entity entity;
|
|
CreateEntityInternal(archetype, &entity, 1);
|
|
return entity;
|
|
}
|
|
|
|
public Entity CreateEntity(params ComponentType[] types)
|
|
{
|
|
return CreateEntity(CreateArchetype(types));
|
|
}
|
|
|
|
internal void CreateEntityInternal(EntityArchetype archetype, Entity* entities, int count)
|
|
{
|
|
BeforeStructuralChange();
|
|
Entities->CreateEntities(ArchetypeManager, archetype.Archetype, entities, count);
|
|
}
|
|
|
|
public void DestroyEntity(ComponentGroup componentGroupFilter)
|
|
{
|
|
BeforeStructuralChange();
|
|
|
|
// @TODO: Don't copy entity array,
|
|
// take advantage of inherent chunk structure to do faster destruction
|
|
var entityGroupArray = componentGroupFilter.GetEntityArray();
|
|
if (entityGroupArray.Length == 0)
|
|
return;
|
|
|
|
var entityArray = new NativeArray<Entity>(entityGroupArray.Length, Allocator.Temp,
|
|
NativeArrayOptions.UninitializedMemory);
|
|
entityGroupArray.CopyTo(entityArray);
|
|
if (entityArray.Length != 0)
|
|
Entities->TryRemoveEntityId((Entity*) entityArray.GetUnsafeReadOnlyPtr(), entityArray.Length,
|
|
ArchetypeManager, m_SharedComponentManager, m_GroupManager, m_CachedComponentTypeInArchetypeArray);
|
|
|
|
entityArray.Dispose();
|
|
}
|
|
|
|
public void DestroyEntity(NativeArray<Entity> entities)
|
|
{
|
|
DestroyEntityInternal((Entity*) entities.GetUnsafeReadOnlyPtr(), entities.Length);
|
|
}
|
|
|
|
public void DestroyEntity(NativeSlice<Entity> entities)
|
|
{
|
|
DestroyEntityInternal((Entity*) entities.GetUnsafeReadOnlyPtr(), entities.Length);
|
|
}
|
|
|
|
public void DestroyEntity(Entity entity)
|
|
{
|
|
DestroyEntityInternal(&entity, 1);
|
|
}
|
|
|
|
private void DestroyEntityInternal(Entity* entities, int count)
|
|
{
|
|
BeforeStructuralChange();
|
|
Entities->AssertEntitiesExist(entities, count);
|
|
Entities->TryRemoveEntityId(entities, count, ArchetypeManager, m_SharedComponentManager, m_GroupManager,
|
|
m_CachedComponentTypeInArchetypeArray);
|
|
}
|
|
|
|
public bool Exists(Entity entity)
|
|
{
|
|
return Entities->Exists(entity);
|
|
}
|
|
|
|
public bool HasComponent<T>(Entity entity)
|
|
{
|
|
return Entities->HasComponent(entity, ComponentType.Create<T>());
|
|
}
|
|
|
|
public bool HasComponent(Entity entity, ComponentType type)
|
|
{
|
|
return Entities->HasComponent(entity, type);
|
|
}
|
|
|
|
public Entity Instantiate(Entity srcEntity)
|
|
{
|
|
Entity entity;
|
|
InstantiateInternal(srcEntity, &entity, 1);
|
|
return entity;
|
|
}
|
|
|
|
public void Instantiate(Entity srcEntity, NativeArray<Entity> outputEntities)
|
|
{
|
|
InstantiateInternal(srcEntity, (Entity*) outputEntities.GetUnsafePtr(), outputEntities.Length);
|
|
}
|
|
|
|
internal void InstantiateInternal(Entity srcEntity, Entity* outputEntities, int count)
|
|
{
|
|
BeforeStructuralChange();
|
|
if (!Entities->Exists(srcEntity))
|
|
throw new ArgumentException("srcEntity is not a valid entity");
|
|
|
|
Entities->InstantiateEntities(ArchetypeManager, m_SharedComponentManager, m_GroupManager, srcEntity, outputEntities,
|
|
count, m_CachedComponentTypeInArchetypeArray);
|
|
}
|
|
|
|
public void AddComponent(Entity entity, ComponentType type)
|
|
{
|
|
BeforeStructuralChange();
|
|
Entities->AssertEntitiesExist(&entity, 1);
|
|
Entities->AddComponent(entity, type, ArchetypeManager, m_SharedComponentManager, m_GroupManager,
|
|
m_CachedComponentTypeInArchetypeArray);
|
|
}
|
|
|
|
public void RemoveComponent(Entity entity, ComponentType type)
|
|
{
|
|
BeforeStructuralChange();
|
|
Entities->AssertEntityHasComponent(entity, type);
|
|
Entities->RemoveComponent(entity, type, ArchetypeManager, m_SharedComponentManager, m_GroupManager,
|
|
m_CachedComponentTypeInArchetypeArray);
|
|
|
|
var archetype = Entities->GetArchetype(entity);
|
|
if (archetype->SystemStateCleanupComplete)
|
|
{
|
|
Entities->TryRemoveEntityId(&entity, 1, ArchetypeManager, m_SharedComponentManager, m_GroupManager,
|
|
m_CachedComponentTypeInArchetypeArray);
|
|
}
|
|
}
|
|
|
|
public void RemoveComponent<T>(Entity entity)
|
|
{
|
|
RemoveComponent(entity, ComponentType.Create<T>());
|
|
}
|
|
|
|
public void AddComponentData<T>(Entity entity, T componentData) where T : struct, IComponentData
|
|
{
|
|
AddComponent(entity, ComponentType.Create<T>());
|
|
SetComponentData(entity, componentData);
|
|
}
|
|
|
|
public void AddBuffer<T>(Entity entity) where T : struct, IBufferElementData
|
|
{
|
|
AddComponent(entity, ComponentType.Create<T>());
|
|
}
|
|
|
|
public ComponentDataFromEntity<T> GetComponentDataFromEntity<T>(bool isReadOnly = false)
|
|
where T : struct, IComponentData
|
|
{
|
|
var typeIndex = TypeManager.GetTypeIndex<T>();
|
|
return GetComponentDataFromEntity<T>(typeIndex, isReadOnly);
|
|
}
|
|
|
|
internal ComponentDataFromEntity<T> GetComponentDataFromEntity<T>(int typeIndex, bool isReadOnly)
|
|
where T : struct, IComponentData
|
|
{
|
|
#if ENABLE_UNITY_COLLECTIONS_CHECKS
|
|
var componentType = ComponentType.FromTypeIndex(typeIndex);
|
|
if (componentType.IsZeroSized)
|
|
throw new ArgumentException($"GetComponentDataFromEntity<{typeof(T)}> cannot be called on zero-sized IComponentData");
|
|
|
|
return new ComponentDataFromEntity<T>(typeIndex, Entities,
|
|
ComponentJobSafetyManager.GetSafetyHandle(typeIndex, isReadOnly));
|
|
#else
|
|
return new ComponentDataFromEntity<T>(typeIndex, m_Entities);
|
|
#endif
|
|
}
|
|
|
|
public BufferFromEntity<T> GetBufferFromEntity<T>(bool isReadOnly = false)
|
|
where T : struct, IBufferElementData
|
|
{
|
|
return GetBufferFromEntity<T>(TypeManager.GetTypeIndex<T>(), isReadOnly);
|
|
}
|
|
|
|
public BufferFromEntity<T> GetBufferFromEntity<T>(int typeIndex, bool isReadOnly = false)
|
|
where T : struct, IBufferElementData
|
|
{
|
|
#if ENABLE_UNITY_COLLECTIONS_CHECKS
|
|
return new BufferFromEntity<T>(typeIndex, Entities, isReadOnly,
|
|
ComponentJobSafetyManager.GetSafetyHandle(typeIndex, isReadOnly),
|
|
ComponentJobSafetyManager.GetBufferSafetyHandle(typeIndex));
|
|
#else
|
|
return new BufferFromEntity<T>(typeIndex, m_Entities, isReadOnly);
|
|
#endif
|
|
}
|
|
|
|
public T GetComponentData<T>(Entity entity) where T : struct, IComponentData
|
|
{
|
|
var typeIndex = TypeManager.GetTypeIndex<T>();
|
|
|
|
#if ENABLE_UNITY_COLLECTIONS_CHECKS
|
|
var componentType = ComponentType.FromTypeIndex(typeIndex);
|
|
if (componentType.IsZeroSized)
|
|
throw new ArgumentException($"GetComponentData<{typeof(T)}> cannot be called on zero-sized IComponentData");
|
|
#endif
|
|
|
|
Entities->AssertEntityHasComponent(entity, typeIndex);
|
|
ComponentJobSafetyManager.CompleteWriteDependency(typeIndex);
|
|
|
|
var ptr = Entities->GetComponentDataWithTypeRO(entity, typeIndex);
|
|
|
|
T value;
|
|
UnsafeUtility.CopyPtrToStructure(ptr, out value);
|
|
return value;
|
|
}
|
|
|
|
public void SetComponentData<T>(Entity entity, T componentData) where T : struct, IComponentData
|
|
{
|
|
var typeIndex = TypeManager.GetTypeIndex<T>();
|
|
|
|
#if ENABLE_UNITY_COLLECTIONS_CHECKS
|
|
var componentType = ComponentType.FromTypeIndex(typeIndex);
|
|
if (componentType.IsZeroSized)
|
|
throw new ArgumentException($"GetComponentData<{typeof(T)}> cannot be called on zero-sized IComponentData");
|
|
#endif
|
|
|
|
Entities->AssertEntityHasComponent(entity, typeIndex);
|
|
|
|
ComponentJobSafetyManager.CompleteReadAndWriteDependency(typeIndex);
|
|
|
|
var ptr = Entities->GetComponentDataWithTypeRW(entity, typeIndex, Entities->GlobalSystemVersion);
|
|
UnsafeUtility.CopyStructureToPtr(ref componentData, ptr);
|
|
}
|
|
|
|
internal void SetComponentObject(Entity entity, ComponentType componentType, object componentObject)
|
|
{
|
|
Entities->AssertEntityHasComponent(entity, componentType.TypeIndex);
|
|
|
|
//@TODO
|
|
Chunk* chunk;
|
|
int chunkIndex;
|
|
Entities->GetComponentChunk(entity, out chunk, out chunkIndex);
|
|
ArchetypeManager.SetManagedObject(chunk, componentType, chunkIndex, componentObject);
|
|
}
|
|
|
|
public int GetSharedComponentCount()
|
|
{
|
|
return m_SharedComponentManager.GetSharedComponentCount();
|
|
}
|
|
|
|
public void GetAllUniqueSharedComponentData<T>(List<T> sharedComponentValues)
|
|
where T : struct, ISharedComponentData
|
|
{
|
|
m_SharedComponentManager.GetAllUniqueSharedComponents(sharedComponentValues);
|
|
}
|
|
|
|
public void GetAllUniqueSharedComponentData<T>(List<T> sharedComponentValues, List<int> sharedComponentIndices)
|
|
where T : struct, ISharedComponentData
|
|
{
|
|
m_SharedComponentManager.GetAllUniqueSharedComponents(sharedComponentValues, sharedComponentIndices);
|
|
}
|
|
|
|
public T GetSharedComponentData<T>(Entity entity) where T : struct, ISharedComponentData
|
|
{
|
|
var typeIndex = TypeManager.GetTypeIndex<T>();
|
|
Entities->AssertEntityHasComponent(entity, typeIndex);
|
|
|
|
var sharedComponentIndex = Entities->GetSharedComponentDataIndex(entity, typeIndex);
|
|
return m_SharedComponentManager.GetSharedComponentData<T>(sharedComponentIndex);
|
|
}
|
|
|
|
public T GetSharedComponentData<T>(int sharedComponentIndex) where T : struct, ISharedComponentData
|
|
{
|
|
return m_SharedComponentManager.GetSharedComponentData<T>(sharedComponentIndex);
|
|
}
|
|
|
|
public void AddSharedComponentData<T>(Entity entity, T componentData) where T : struct, ISharedComponentData
|
|
{
|
|
//TODO: optimize this (no need to move the entity to a new chunk twice)
|
|
AddComponent(entity, ComponentType.Create<T>());
|
|
SetSharedComponentData(entity, componentData);
|
|
}
|
|
|
|
internal void AddSharedComponentDataBoxed(Entity entity, int typeIndex, int hashCode, object componentData)
|
|
{
|
|
//TODO: optimize this (no need to move the entity to a new chunk twice)
|
|
AddComponent(entity, ComponentType.FromTypeIndex(typeIndex));
|
|
SetSharedComponentDataBoxed(entity, typeIndex, hashCode, componentData);
|
|
}
|
|
|
|
public void SetSharedComponentData<T>(Entity entity, T componentData) where T : struct, ISharedComponentData
|
|
{
|
|
BeforeStructuralChange();
|
|
|
|
var typeIndex = TypeManager.GetTypeIndex<T>();
|
|
Entities->AssertEntityHasComponent(entity, typeIndex);
|
|
|
|
var newSharedComponentDataIndex = m_SharedComponentManager.InsertSharedComponent(componentData);
|
|
Entities->SetSharedComponentDataIndex(ArchetypeManager, m_SharedComponentManager, entity, typeIndex,
|
|
newSharedComponentDataIndex);
|
|
m_SharedComponentManager.RemoveReference(newSharedComponentDataIndex);
|
|
}
|
|
|
|
internal void SetSharedComponentDataBoxed(Entity entity, int typeIndex, int hashCode, object componentData)
|
|
{
|
|
BeforeStructuralChange();
|
|
|
|
Entities->AssertEntityHasComponent(entity, typeIndex);
|
|
|
|
var newSharedComponentDataIndex = 0;
|
|
if (componentData != null) // null means default
|
|
newSharedComponentDataIndex = m_SharedComponentManager.InsertSharedComponentAssumeNonDefault(typeIndex,
|
|
hashCode, componentData, TypeManager.GetTypeInfo(typeIndex).FastEqualityTypeInfo);
|
|
|
|
Entities->SetSharedComponentDataIndex(ArchetypeManager, m_SharedComponentManager, entity, typeIndex,
|
|
newSharedComponentDataIndex);
|
|
m_SharedComponentManager.RemoveReference(newSharedComponentDataIndex);
|
|
}
|
|
|
|
public DynamicBuffer<T> GetBuffer<T>(Entity entity) where T : struct, IBufferElementData
|
|
{
|
|
var typeIndex = TypeManager.GetTypeIndex<T>();
|
|
|
|
#if ENABLE_UNITY_COLLECTIONS_CHECKS
|
|
Entities->AssertEntityHasComponent(entity, typeIndex);
|
|
if (TypeManager.GetTypeInfo<T>().Category != TypeManager.TypeCategory.BufferData)
|
|
throw new ArgumentException(
|
|
$"GetBuffer<{typeof(T)}> may not be IComponentData or ISharedComponentData; currently {TypeManager.GetTypeInfo<T>().Category}");
|
|
#endif
|
|
|
|
ComponentJobSafetyManager.CompleteReadAndWriteDependency(typeIndex);
|
|
|
|
BufferHeader* header = (BufferHeader*) Entities->GetComponentDataWithTypeRW(entity, typeIndex, Entities->GlobalSystemVersion);
|
|
|
|
#if ENABLE_UNITY_COLLECTIONS_CHECKS
|
|
return new DynamicBuffer<T>(header, ComponentJobSafetyManager.GetSafetyHandle(typeIndex, false), ComponentJobSafetyManager.GetBufferSafetyHandle(typeIndex));
|
|
#else
|
|
return new DynamicBuffer<T>(header);
|
|
#endif
|
|
}
|
|
|
|
public NativeArray<Entity> GetAllEntities(Allocator allocator = Allocator.Temp)
|
|
{
|
|
BeforeStructuralChange();
|
|
|
|
var enabledQuery = new EntityArchetypeQuery
|
|
{
|
|
Any = Array.Empty<ComponentType>(),
|
|
None = Array.Empty<ComponentType>(),
|
|
All = Array.Empty<ComponentType>(),
|
|
};
|
|
var disabledQuery = new EntityArchetypeQuery
|
|
{
|
|
Any = Array.Empty<ComponentType>(),
|
|
None = Array.Empty<ComponentType>(),
|
|
All = new ComponentType[] {typeof(Disabled)}
|
|
};
|
|
var prefabQuery = new EntityArchetypeQuery
|
|
{
|
|
Any = Array.Empty<ComponentType>(),
|
|
None = Array.Empty<ComponentType>(),
|
|
All = new ComponentType[] {typeof(Prefab)}
|
|
};
|
|
var archetypes = new NativeList<EntityArchetype>(Allocator.TempJob);
|
|
|
|
AddMatchingArchetypes(enabledQuery, archetypes);
|
|
AddMatchingArchetypes(disabledQuery, archetypes);
|
|
AddMatchingArchetypes(prefabQuery, archetypes);
|
|
|
|
var chunks = CreateArchetypeChunkArray(archetypes, Allocator.TempJob);
|
|
var count = ArchetypeChunkArray.CalculateEntityCount(chunks);
|
|
var array = new NativeArray<Entity>(count, allocator);
|
|
var entityType = GetArchetypeChunkEntityType();
|
|
var offset = 0;
|
|
|
|
for (int i = 0; i < chunks.Length; i++)
|
|
{
|
|
var chunk = chunks[i];
|
|
var entities = chunk.GetNativeArray(entityType);
|
|
array.Slice(offset, entities.Length).CopyFrom(entities);
|
|
offset += entities.Length;
|
|
}
|
|
|
|
chunks.Dispose();
|
|
archetypes.Dispose();
|
|
|
|
return array;
|
|
}
|
|
|
|
public NativeArray<ComponentType> GetComponentTypes(Entity entity, Allocator allocator = Allocator.Temp)
|
|
{
|
|
Entities->AssertEntitiesExist(&entity, 1);
|
|
|
|
var archetype = Entities->GetArchetype(entity);
|
|
|
|
var components = new NativeArray<ComponentType>(archetype->TypesCount - 1, allocator);
|
|
|
|
for (var i = 1; i < archetype->TypesCount; i++)
|
|
components[i - 1] = archetype->Types[i].ToComponentType();
|
|
|
|
return components;
|
|
}
|
|
|
|
internal void SetBufferRaw(Entity entity, int componentTypeIndex, BufferHeader* tempBuffer, int sizeInChunk)
|
|
{
|
|
Entities->AssertEntityHasComponent(entity, componentTypeIndex);
|
|
|
|
ComponentJobSafetyManager.CompleteReadAndWriteDependency(componentTypeIndex);
|
|
|
|
var ptr = Entities->GetComponentDataWithTypeRW(entity, componentTypeIndex, Entities->GlobalSystemVersion);
|
|
|
|
BufferHeader.Destroy((BufferHeader*)ptr);
|
|
|
|
UnsafeUtility.MemCpy(ptr, tempBuffer, sizeInChunk);
|
|
}
|
|
|
|
public int GetComponentCount(Entity entity)
|
|
{
|
|
Entities->AssertEntitiesExist(&entity, 1);
|
|
var archetype = Entities->GetArchetype(entity);
|
|
return archetype->TypesCount - 1;
|
|
}
|
|
|
|
internal int GetComponentTypeIndex(Entity entity, int index)
|
|
{
|
|
Entities->AssertEntitiesExist(&entity, 1);
|
|
var archetype = Entities->GetArchetype(entity);
|
|
|
|
if ((uint) index >= archetype->TypesCount) return -1;
|
|
|
|
return archetype->Types[index + 1].TypeIndex;
|
|
}
|
|
|
|
internal void SetComponentDataRaw(Entity entity, int typeIndex, void* data, int size)
|
|
{
|
|
Entities->AssertEntityHasComponent(entity, typeIndex);
|
|
|
|
ComponentJobSafetyManager.CompleteReadAndWriteDependency(typeIndex);
|
|
|
|
var ptr = Entities->GetComponentDataWithTypeRW(entity, typeIndex, Entities->GlobalSystemVersion);
|
|
UnsafeUtility.MemCpy(ptr, data, size);
|
|
}
|
|
|
|
internal void* GetComponentDataRawRW(Entity entity, int typeIndex)
|
|
{
|
|
Entities->AssertEntityHasComponent(entity, typeIndex);
|
|
|
|
ComponentJobSafetyManager.CompleteReadAndWriteDependency(typeIndex);
|
|
|
|
var ptr = Entities->GetComponentDataWithTypeRW(entity, typeIndex, Entities->GlobalSystemVersion);
|
|
return ptr;
|
|
}
|
|
|
|
internal object GetSharedComponentData(Entity entity, int typeIndex)
|
|
{
|
|
Entities->AssertEntityHasComponent(entity, typeIndex);
|
|
|
|
var sharedComponentIndex = Entities->GetSharedComponentDataIndex(entity, typeIndex);
|
|
return m_SharedComponentManager.GetSharedComponentDataBoxed(sharedComponentIndex);
|
|
}
|
|
|
|
public int GetComponentOrderVersion<T>()
|
|
{
|
|
return Entities->GetComponentTypeOrderVersion(TypeManager.GetTypeIndex<T>());
|
|
}
|
|
|
|
public int GetSharedComponentOrderVersion<T>(T sharedComponent) where T : struct, ISharedComponentData
|
|
{
|
|
return m_SharedComponentManager.GetSharedComponentVersion(sharedComponent);
|
|
}
|
|
|
|
public ExclusiveEntityTransaction BeginExclusiveEntityTransaction()
|
|
{
|
|
ComponentJobSafetyManager.BeginExclusiveTransaction();
|
|
#if ENABLE_UNITY_COLLECTIONS_CHECKS
|
|
m_ExclusiveEntityTransaction.SetAtomicSafetyHandle(ComponentJobSafetyManager.ExclusiveTransactionSafety);
|
|
#endif
|
|
return m_ExclusiveEntityTransaction;
|
|
}
|
|
|
|
public void EndExclusiveEntityTransaction()
|
|
{
|
|
ComponentJobSafetyManager.EndExclusiveTransaction();
|
|
}
|
|
|
|
private void BeforeStructuralChange()
|
|
{
|
|
#if ENABLE_UNITY_COLLECTIONS_CHECKS
|
|
if (ComponentJobSafetyManager.IsInTransaction)
|
|
throw new InvalidOperationException(
|
|
"Access to EntityManager is not allowed after EntityManager.BeginExclusiveEntityTransaction(); has been called.");
|
|
#endif
|
|
ComponentJobSafetyManager.CompleteAllJobsAndInvalidateArrays();
|
|
}
|
|
|
|
//@TODO: Not clear to me what this method is really for...
|
|
public void CompleteAllJobs()
|
|
{
|
|
ComponentJobSafetyManager.CompleteAllJobsAndInvalidateArrays();
|
|
}
|
|
|
|
public void MoveEntitiesFrom(EntityManager srcEntities)
|
|
{
|
|
#if ENABLE_UNITY_COLLECTIONS_CHECKS
|
|
if (srcEntities == this)
|
|
throw new ArgumentException("srcEntities must not be the same as this EntityManager.");
|
|
|
|
if (!srcEntities.m_SharedComponentManager.AllSharedComponentReferencesAreFromChunks(srcEntities.ArchetypeManager))
|
|
throw new ArgumentException("EntityManager.MoveEntitiesFrom failed - All ISharedComponentData references must be from EntityManager. (For example ComponentGroup.SetFilter with a shared component type is not allowed during EntityManager.MoveEntitiesFrom)");
|
|
#endif
|
|
|
|
BeforeStructuralChange();
|
|
srcEntities.BeforeStructuralChange();
|
|
|
|
ArchetypeManager.MoveChunks(srcEntities, ArchetypeManager, m_GroupManager, Entities, m_SharedComponentManager, m_CachedComponentTypeInArchetypeArray);
|
|
|
|
//@TODO: Need to incrmeent the component versions based the moved chunks...
|
|
}
|
|
|
|
public void CheckInternalConsistency()
|
|
{
|
|
#if ENABLE_UNITY_COLLECTIONS_CHECKS
|
|
|
|
//@TODO: Validate from perspective of componentgroup...
|
|
//@TODO: Validate shared component data refcounts...
|
|
var entityCountEntityData = Entities->CheckInternalConsistency();
|
|
var entityCountArchetypeManager = ArchetypeManager.CheckInternalConsistency();
|
|
|
|
Assert.AreEqual(entityCountEntityData, entityCountArchetypeManager);
|
|
#endif
|
|
}
|
|
|
|
public List<Type> GetAssignableComponentTypes(Type interfaceType)
|
|
{
|
|
// #todo Cache this. It only can change when TypeManager.GetTypeCount() changes
|
|
var componentTypeCount = TypeManager.GetTypeCount();
|
|
var assignableTypes = new List<Type>();
|
|
for (var i = 0; i < componentTypeCount; i++)
|
|
{
|
|
var type = TypeManager.GetType(i);
|
|
if (interfaceType.IsAssignableFrom(type)) assignableTypes.Add(type);
|
|
}
|
|
|
|
return assignableTypes;
|
|
}
|
|
|
|
private bool TestMatchingArchetypeAny(Archetype* archetype, ComponentType* anyTypes, int anyCount)
|
|
{
|
|
if (anyCount == 0) return true;
|
|
|
|
var componentTypes = archetype->Types;
|
|
var componentTypesCount = archetype->TypesCount;
|
|
for (var i = 0; i < componentTypesCount; i++)
|
|
{
|
|
var componentTypeIndex = componentTypes[i].TypeIndex;
|
|
for (var j = 0; j < anyCount; j++)
|
|
{
|
|
var anyTypeIndex = anyTypes[j].TypeIndex;
|
|
if (componentTypeIndex == anyTypeIndex) return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private bool TestMatchingArchetypeNone(Archetype* archetype, ComponentType* noneTypes, int noneCount)
|
|
{
|
|
var componentTypes = archetype->Types;
|
|
var componentTypesCount = archetype->TypesCount;
|
|
for (var i = 0; i < componentTypesCount; i++)
|
|
{
|
|
var componentTypeIndex = componentTypes[i].TypeIndex;
|
|
for (var j = 0; j < noneCount; j++)
|
|
{
|
|
var noneTypeIndex = noneTypes[j].TypeIndex;
|
|
if (componentTypeIndex == noneTypeIndex) return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private bool TestMatchingArchetypeAll(Archetype* archetype, ComponentType* allTypes, int allCount)
|
|
{
|
|
var componentTypes = archetype->Types;
|
|
var componentTypesCount = archetype->TypesCount;
|
|
var foundCount = 0;
|
|
var disabledTypeIndex = TypeManager.GetTypeIndex<Disabled>();
|
|
var prefabTypeIndex = TypeManager.GetTypeIndex<Prefab>();
|
|
var requestedDisabled = false;
|
|
var requestedPrefab = false;
|
|
for (var i = 0; i < componentTypesCount; i++)
|
|
{
|
|
var componentTypeIndex = componentTypes[i].TypeIndex;
|
|
for (var j = 0; j < allCount; j++)
|
|
{
|
|
var allTypeIndex = allTypes[j].TypeIndex;
|
|
if (allTypeIndex == disabledTypeIndex)
|
|
requestedDisabled = true;
|
|
if (allTypeIndex == prefabTypeIndex)
|
|
requestedPrefab = true;
|
|
if (componentTypeIndex == allTypeIndex) foundCount++;
|
|
}
|
|
}
|
|
|
|
if (archetype->Disabled && (!requestedDisabled))
|
|
return false;
|
|
if (archetype->Prefab && (!requestedPrefab))
|
|
return false;
|
|
|
|
return foundCount == allCount;
|
|
}
|
|
|
|
public void AddMatchingArchetypes(EntityArchetypeQuery query, NativeList<EntityArchetype> foundArchetypes)
|
|
{
|
|
var anyCount = query.Any.Length;
|
|
var noneCount = query.None.Length;
|
|
var allCount = query.All.Length;
|
|
|
|
fixed (ComponentType* any = query.Any)
|
|
{
|
|
fixed (ComponentType* none = query.None)
|
|
{
|
|
fixed (ComponentType* all = query.All)
|
|
{
|
|
for (var archetype = ArchetypeManager.m_LastArchetype;
|
|
archetype != null;
|
|
archetype = archetype->PrevArchetype)
|
|
{
|
|
if (archetype->EntityCount == 0)
|
|
continue;
|
|
if (!TestMatchingArchetypeAny(archetype, any, anyCount))
|
|
continue;
|
|
if (!TestMatchingArchetypeNone(archetype, none, noneCount))
|
|
continue;
|
|
if (!TestMatchingArchetypeAll(archetype, all, allCount))
|
|
continue;
|
|
|
|
var entityArchetype = new EntityArchetype {Archetype = archetype};
|
|
var found = foundArchetypes.Contains(entityArchetype);
|
|
if (!found)
|
|
foundArchetypes.Add(entityArchetype);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public NativeArray<ArchetypeChunk> CreateArchetypeChunkArray(NativeList<EntityArchetype> archetypes,
|
|
Allocator allocator)
|
|
{
|
|
#if ENABLE_UNITY_COLLECTIONS_CHECKS
|
|
var safetyHandle = AtomicSafetyHandle.Create();
|
|
return ArchetypeChunkArray.Create(archetypes, allocator, safetyHandle);
|
|
#else
|
|
return ArchetypeChunkArray.Create(archetypes, allocator);
|
|
#endif
|
|
}
|
|
|
|
public NativeArray<ArchetypeChunk> CreateArchetypeChunkArray(EntityArchetypeQuery query, Allocator allocator)
|
|
{
|
|
var foundArchetypes = new NativeList<EntityArchetype>(Allocator.TempJob);
|
|
AddMatchingArchetypes(query, foundArchetypes);
|
|
var chunkStream = CreateArchetypeChunkArray(foundArchetypes, allocator);
|
|
foundArchetypes.Dispose();
|
|
return chunkStream;
|
|
}
|
|
|
|
public ArchetypeChunkComponentType<T> GetArchetypeChunkComponentType<T>(bool isReadOnly)
|
|
where T : struct, IComponentData
|
|
{
|
|
#if ENABLE_UNITY_COLLECTIONS_CHECKS
|
|
var typeIndex = TypeManager.GetTypeIndex<T>();
|
|
return new ArchetypeChunkComponentType<T>(
|
|
ComponentJobSafetyManager.GetSafetyHandle(typeIndex, isReadOnly), isReadOnly,
|
|
GlobalSystemVersion);
|
|
#else
|
|
return new ArchetypeChunkComponentType<T>(isReadOnly, GlobalSystemVersion);
|
|
#endif
|
|
}
|
|
|
|
public ArchetypeChunkBufferType<T> GetArchetypeChunkBufferType<T>(bool isReadOnly)
|
|
where T : struct, IBufferElementData
|
|
{
|
|
#if ENABLE_UNITY_COLLECTIONS_CHECKS
|
|
var typeIndex = TypeManager.GetTypeIndex<T>();
|
|
return new ArchetypeChunkBufferType<T>(
|
|
ComponentJobSafetyManager.GetSafetyHandle(typeIndex, isReadOnly),
|
|
ComponentJobSafetyManager.GetBufferSafetyHandle(typeIndex),
|
|
isReadOnly, GlobalSystemVersion);
|
|
#else
|
|
return new ArchetypeChunkBufferType<T>(isReadOnly,GlobalSystemVersion);
|
|
#endif
|
|
}
|
|
|
|
public ArchetypeChunkSharedComponentType<T> GetArchetypeChunkSharedComponentType<T>()
|
|
where T : struct, ISharedComponentData
|
|
{
|
|
#if ENABLE_UNITY_COLLECTIONS_CHECKS
|
|
return new ArchetypeChunkSharedComponentType<T>(
|
|
ComponentJobSafetyManager.GetSafetyHandle(TypeManager.GetTypeIndex<T>(), true));
|
|
#else
|
|
return new ArchetypeChunkSharedComponentType<T>(false);
|
|
#endif
|
|
}
|
|
|
|
public ArchetypeChunkEntityType GetArchetypeChunkEntityType()
|
|
{
|
|
#if ENABLE_UNITY_COLLECTIONS_CHECKS
|
|
return new ArchetypeChunkEntityType(
|
|
ComponentJobSafetyManager.GetSafetyHandle(TypeManager.GetTypeIndex<Entity>(), true));
|
|
#else
|
|
return new ArchetypeChunkEntityType(false);
|
|
#endif
|
|
}
|
|
|
|
public void PrepareForDeserialize()
|
|
{
|
|
Assert.AreEqual(0, Debug.EntityCount);
|
|
m_SharedComponentManager.PrepareForDeserialize();
|
|
}
|
|
|
|
public class EntityManagerDebug
|
|
{
|
|
private readonly EntityManager m_Manager;
|
|
|
|
public EntityManagerDebug(EntityManager entityManager)
|
|
{
|
|
m_Manager = entityManager;
|
|
}
|
|
|
|
public void PoisonUnusedDataInAllChunks(EntityArchetype archetype, byte value)
|
|
{
|
|
for (var c = archetype.Archetype->ChunkList.Begin; c != archetype.Archetype->ChunkList.End; c = c->Next)
|
|
ChunkDataUtility.PoisonUnusedChunkData((Chunk*) c, value);
|
|
}
|
|
|
|
public void SetGlobalSystemVersion(uint version)
|
|
{
|
|
m_Manager.Entities->GlobalSystemVersion = version;
|
|
}
|
|
|
|
public bool IsSharedComponentManagerEmpty()
|
|
{
|
|
return m_Manager.m_SharedComponentManager.IsEmpty();
|
|
}
|
|
|
|
internal static string GetArchetypeDebugString(Archetype* a)
|
|
{
|
|
var buf = new StringBuilder();
|
|
buf.Append("(");
|
|
|
|
for (var i = 0; i < a->TypesCount; i++)
|
|
{
|
|
var componentTypeInArchetype = a->Types[i];
|
|
if (i > 0)
|
|
buf.Append(", ");
|
|
buf.Append(componentTypeInArchetype.ToString());
|
|
}
|
|
|
|
buf.Append(")");
|
|
return buf.ToString();
|
|
}
|
|
|
|
public int EntityCount
|
|
{
|
|
get
|
|
{
|
|
var allEntities = m_Manager.GetAllEntities();
|
|
var count = allEntities.Length;
|
|
allEntities.Dispose();
|
|
return count;
|
|
}
|
|
}
|
|
|
|
public void LogEntityInfo(Entity entity)
|
|
{
|
|
var archetype = m_Manager.Entities->GetArchetype(entity);
|
|
Unity.Debug.Log($"Entity {entity.Index}.{entity.Version}");
|
|
for (var i = 0; i < archetype->TypesCount; i++)
|
|
{
|
|
var componentTypeInArchetype = archetype->Types[i];
|
|
Unity.Debug.Log($" - {componentTypeInArchetype.ToString()}");
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|