// This must be run after chunks have been remapped since FreeChunksBySharedComponents needs the shared component // indices in the chunks to be remapped public void Execute(int index) { var srcArchetype = remapArchetypes[index].srcArchetype; var dstArchetype = remapArchetypes[index].dstArchetype; UnsafeLinkedListNode.InsertListBefore(dstArchetype->ChunkList.End, &srcArchetype->ChunkList); if (srcArchetype->NumSharedComponents == 0) { if (!srcArchetype->ChunkListWithEmptySlots.IsEmpty) { UnsafeLinkedListNode.InsertListBefore(dstArchetype->ChunkListWithEmptySlots.End, &srcArchetype->ChunkListWithEmptySlots); } } else { remapArchetypes[index].dstArchetype->FreeChunksBySharedComponents.AppendFrom(&remapArchetypes[index].srcArchetype->FreeChunksBySharedComponents); } dstArchetype->EntityCount += srcArchetype->EntityCount; dstArchetype->ChunkCount += srcArchetype->ChunkCount; srcArchetype->EntityCount = 0; srcArchetype->ChunkCount = 0; }
public void ConstructChunk(Archetype *archetype, Chunk *chunk, int *sharedComponentDataIndices) { chunk->Archetype = archetype; chunk->Count = 0; chunk->Capacity = archetype->ChunkCapacity; chunk->ChunkListNode = new UnsafeLinkedListNode(); chunk->ChunkListWithEmptySlotsNode = new UnsafeLinkedListNode(); var numSharedComponents = archetype->NumSharedComponents; var numTypes = archetype->TypesCount; var sharedComponentOffset = Chunk.GetSharedComponentOffset(numSharedComponents); var changeVersionOffset = Chunk.GetChangedComponentOffset(numTypes, numSharedComponents); chunk->SharedComponentValueArray = (int *)((byte *)chunk + sharedComponentOffset); chunk->ChangeVersion = (uint *)((byte *)chunk + changeVersionOffset); archetype->ChunkList.Add(&chunk->ChunkListNode); archetype->ChunkCount += 1; Assert.IsTrue(!archetype->ChunkList.IsEmpty); Assert.IsTrue(chunk == (Chunk *)archetype->ChunkList.Back); if (numSharedComponents == 0) { archetype->ChunkListWithEmptySlots.Add(&chunk->ChunkListWithEmptySlotsNode); Assert.IsTrue(chunk == GetChunkFromEmptySlotNode(archetype->ChunkListWithEmptySlots.Back)); Assert.IsTrue(!archetype->ChunkListWithEmptySlots.IsEmpty); } else { var sharedComponentValueArray = chunk->SharedComponentValueArray; UnsafeUtility.MemCpy(sharedComponentValueArray, sharedComponentDataIndices, archetype->NumSharedComponents * sizeof(int)); for (var i = 0; i < archetype->NumSharedComponents; ++i) { var sharedComponentIndex = sharedComponentValueArray[i]; m_SharedComponentManager.AddReference(sharedComponentIndex); } archetype->FreeChunksBySharedComponents.Add(chunk); Assert.IsTrue(archetype->FreeChunksBySharedComponents.GetChunkWithEmptySlots(sharedComponentDataIndices, archetype->NumSharedComponents) != null); } if (archetype->NumManagedArrays > 0) { chunk->ManagedArrayIndex = AllocateManagedArrayStorage(archetype->NumManagedArrays * chunk->Capacity); } else { chunk->ManagedArrayIndex = -1; } for (var i = 0; i < archetype->TypesCount; i++) { chunk->ChangeVersion[i] = 0; } }
public void ConstructChunk(Archetype *archetype, Chunk *chunk, int *sharedComponentDataIndices) { chunk->Archetype = archetype; chunk->Count = 0; chunk->Capacity = archetype->ChunkCapacity; chunk->ChunkListNode = new UnsafeLinkedListNode(); chunk->ChunkListWithEmptySlotsNode = new UnsafeLinkedListNode(); chunk->SharedComponentValueArray = (int *)((byte *)chunk + Chunk.GetSharedComponentOffset(archetype->NumSharedComponents)); chunk->ChangeVersion = (uint *)((byte *)chunk + Chunk.GetChangedComponentOffset(archetype->TypesCount, archetype->NumSharedComponents)); archetype->ChunkList.Add(&chunk->ChunkListNode); archetype->ChunkCount += 1; archetype->ChunkListWithEmptySlots.Add(&chunk->ChunkListWithEmptySlotsNode); Assert.IsTrue(!archetype->ChunkList.IsEmpty); Assert.IsTrue(!archetype->ChunkListWithEmptySlots.IsEmpty); Assert.IsTrue(chunk == (Chunk *)archetype->ChunkList.Back); Assert.IsTrue(chunk == GetChunkFromEmptySlotNode(archetype->ChunkListWithEmptySlots.Back)); if (archetype->NumManagedArrays > 0) { chunk->ManagedArrayIndex = AllocateManagedArrayStorage(archetype->NumManagedArrays * chunk->Capacity); } else { chunk->ManagedArrayIndex = -1; } for (var i = 0; i < archetype->TypesCount; i++) { chunk->ChangeVersion[i] = 0; } if (archetype->NumSharedComponents <= 0) { return; } var sharedComponentValueArray = chunk->SharedComponentValueArray; CopySharedComponentDataIndexArray(sharedComponentValueArray, sharedComponentDataIndices, chunk->Archetype->NumSharedComponents); if (sharedComponentDataIndices == null) { return; } for (var i = 0; i < archetype->NumSharedComponents; ++i) { m_SharedComponentManager.AddReference(sharedComponentValueArray[i]); } }
public void ConstructChunk(Archetype *archetype, Chunk *chunk, int *sharedComponentDataIndices) { chunk->Archetype = archetype; chunk->Count = 0; chunk->Capacity = archetype->ChunkCapacity; chunk->ChunkListNode = new UnsafeLinkedListNode(); chunk->ChunkListWithEmptySlotsNode = new UnsafeLinkedListNode(); chunk->SharedComponentValueArray = (int *)((byte *)(chunk) + Chunk.GetSharedComponentOffset(archetype->NumSharedComponents)); archetype->ChunkList.Add(&chunk->ChunkListNode); archetype->ChunkListWithEmptySlots.Add(&chunk->ChunkListWithEmptySlotsNode); Assert.IsTrue(!archetype->ChunkList.IsEmpty); Assert.IsTrue(!archetype->ChunkListWithEmptySlots.IsEmpty); Assert.IsTrue(chunk == (Chunk *)(archetype->ChunkList.Back)); Assert.IsTrue(chunk == GetChunkFromEmptySlotNode(archetype->ChunkListWithEmptySlots.Back)); if (archetype->NumManagedArrays > 0) { chunk->ManagedArrayIndex = m_ManagedArrays.Count; var man = new ManagedArrayStorage(); man.Chunk = chunk; man.ManagedArray = new object[archetype->NumManagedArrays * chunk->Capacity]; m_ManagedArrays.Add(man); } else { chunk->ManagedArrayIndex = -1; } if (archetype->NumSharedComponents <= 0) { return; } var sharedComponentValueArray = chunk->SharedComponentValueArray; CopySharedComponentDataIndexArray(sharedComponentValueArray, sharedComponentDataIndices, chunk->Archetype->NumSharedComponents); if (sharedComponentDataIndices == null) { return; } for (var i = 0; i < archetype->NumSharedComponents; ++i) { m_SharedComponentManager.AddReference(sharedComponentValueArray[i]); } }
void AddMultiple(UnsafeLinkedListNode *list) { var firstChunk = ArchetypeManager.GetChunkFromEmptySlotNode(list->Begin); UInt32 hash = GetHashCode(firstChunk->SharedComponentValueArray, firstChunk->Archetype->NumSharedComponents); int * sharedComponentDataIndices = firstChunk->SharedComponentValueArray; int numSharedComponents = firstChunk->Archetype->NumSharedComponents; Node *node = &buckets[hash & hashMask]; Node *lastNode = &buckets[hashMask]; Node *freeNode = null; while (!node->IsFree()) { if (!node->IsDeleted()) { if (node->CheckEqual(hash, sharedComponentDataIndices, numSharedComponents)) { UnsafeLinkedListNode.InsertListBefore(node->list.End, list); return; } } else { if (freeNode == null) { freeNode = node; } } node = node + 1; if (node > lastNode) { node = buckets; } } if (freeNode == null) { freeNode = node; --emptyNodes; } freeNode->hash = hash; UnsafeLinkedListNode.InitializeList(&freeNode->list); UnsafeLinkedListNode.InsertListBefore(freeNode->list.End, list); if (ShouldGrow(emptyNodes)) { Grow(); } }
public ArchetypeManager(SharedComponentDataManager sharedComponentManager) { m_SharedComponentManager = sharedComponentManager; m_TypeLookup = new NativeMultiHashMap <uint, IntPtr>(256, Allocator.Persistent); m_EmptyChunkPool = (UnsafeLinkedListNode *)m_ArchetypeChunkAllocator.Allocate(sizeof(UnsafeLinkedListNode), UnsafeUtility.AlignOf <UnsafeLinkedListNode>()); UnsafeLinkedListNode.InitializeList(m_EmptyChunkPool); #if UNITY_ASSERTIONS // Buffer should be 16 byte aligned to ensure component data layout itself can gurantee being aligned var offset = UnsafeUtility.GetFieldOffset(typeof(Chunk).GetField("Buffer")); Assert.IsTrue(offset % 16 == 0, "Chunk buffer must be 16 byte aligned"); #endif }
public void Add(Chunk *chunk) { int * sharedComponentDataIndices = chunk->SharedComponentValueArray; int numSharedComponents = chunk->Archetype->NumSharedComponents; uint hash = GetHashCode(sharedComponentDataIndices, numSharedComponents); Node *node = &buckets[hash & hashMask]; Node *lastNode = &buckets[hashMask]; Node *freeNode = null; while (!node->IsFree()) { if (!node->IsDeleted()) { if (node->CheckEqual(hash, sharedComponentDataIndices, numSharedComponents)) { node->list.Add(&chunk->ChunkListWithEmptySlotsNode); return; } } else { if (freeNode == null) { freeNode = node; } } node = node + 1; if (node > lastNode) { node = buckets; } } if (freeNode == null) { freeNode = node; --emptyNodes; } freeNode->hash = hash; UnsafeLinkedListNode.InitializeList(&freeNode->list); freeNode->list.Add(&chunk->ChunkListWithEmptySlotsNode); if (ShouldGrow(emptyNodes)) { Grow(); } }
private unsafe void AddMultiple(UnsafeLinkedListNode *list) { Chunk *chunkPtr = ref ArchetypeManager.GetChunkFromEmptySlotNode(list.Begin); uint hashCode = this.GetHashCode(chunkPtr->SharedComponentValueArray, chunkPtr->Archetype.NumSharedComponents); int * sharedComponentValueArray = chunkPtr->SharedComponentValueArray; int numSharedComponents = chunkPtr->Archetype.NumSharedComponents; Node * buckets = this.buckets + ((hashCode & this.hashMask) * sizeof(Node)); Node * nodePtr2 = this.buckets + (this.hashMask * sizeof(Node)); Node * nodePtr3 = null; while (true) { if (buckets.IsFree()) { if (nodePtr3 == null) { nodePtr3 = buckets; this.emptyNodes--; } nodePtr3->hash = hashCode; UnsafeLinkedListNode.InitializeList(&nodePtr3->list); UnsafeLinkedListNode.InsertListBefore(nodePtr3->list.End, list); if (this.ShouldGrow(this.emptyNodes)) { this.Grow(); } break; } if (!buckets.IsDeleted()) { if (buckets.CheckEqual(hashCode, sharedComponentValueArray, numSharedComponents)) { UnsafeLinkedListNode.InsertListBefore(buckets->list.End, list); break; } } else if (nodePtr3 == null) { nodePtr3 = buckets; } buckets++; if (buckets > nodePtr2) { buckets = this.buckets; } } }
public unsafe void Add(Chunk *chunk) { int * sharedComponentValueArray = chunk.SharedComponentValueArray; int numSharedComponents = chunk.Archetype.NumSharedComponents; uint hashCode = this.GetHashCode(sharedComponentValueArray, numSharedComponents); Node *buckets = this.buckets + ((hashCode & this.hashMask) * sizeof(Node)); Node *nodePtr2 = this.buckets + (this.hashMask * sizeof(Node)); Node *nodePtr3 = null; while (true) { if (buckets.IsFree()) { if (nodePtr3 == null) { nodePtr3 = buckets; this.emptyNodes--; } nodePtr3->hash = hashCode; UnsafeLinkedListNode.InitializeList(&nodePtr3->list); nodePtr3->list.Add(&chunk.ChunkListWithEmptySlotsNode); if (this.ShouldGrow(this.emptyNodes)) { this.Grow(); } break; } if (!buckets.IsDeleted()) { if (buckets.CheckEqual(hashCode, sharedComponentValueArray, numSharedComponents)) { buckets->list.Add(&chunk.ChunkListWithEmptySlotsNode); break; } } else if (nodePtr3 == null) { nodePtr3 = buckets; } buckets++; if (buckets > nodePtr2) { buckets = this.buckets; } } }
public static void MoveChunks(ArchetypeManager srcArchetypeManager, EntityDataManager *srcEntityDataManager, SharedComponentDataManager srcSharedComponents, ArchetypeManager dstArchetypeManager, EntityGroupManager dstGroupManager, SharedComponentDataManager dstSharedComponentDataManager, EntityDataManager *dstEntityDataManager, SharedComponentDataManager dstSharedComponents) { var entitiesArray = new NativeArray <Entity>(Chunk.kMaximumEntitiesPerChunk, Allocator.Temp); var entitiesPtr = (Entity *)entitiesArray.GetUnsafePtr(); var srcArchetype = srcArchetypeManager.m_LastArchetype; while (srcArchetype != null) { if (srcArchetype->EntityCount != 0) { if (srcArchetype->NumManagedArrays != 0) { throw new ArgumentException("MoveEntitiesFrom is not supported with managed arrays"); } var dstArchetype = dstArchetypeManager.GetOrCreateArchetype(srcArchetype->Types, srcArchetype->TypesCount, dstGroupManager); for (var c = srcArchetype->ChunkList.Begin; c != srcArchetype->ChunkList.End; c = c->Next) { Chunk *chunk = (Chunk *)c; EntityDataManager.FreeDataEntitiesInChunk(srcEntityDataManager, chunk, chunk->Count); dstEntityDataManager->AllocateEntities(dstArchetype, chunk, 0, chunk->Count, entitiesPtr); chunk->Archetype = dstArchetype; if (dstArchetype->NumSharedComponents > 0) { dstSharedComponents.MoveSharedComponents(srcSharedComponents, chunk->SharedComponentValueArray, dstArchetype->NumSharedComponents); } } //@TODO: Patch Entity references in IComponentData... UnsafeLinkedListNode.InsertListBefore(dstArchetype->ChunkList.End, &srcArchetype->ChunkList); UnsafeLinkedListNode.InsertListBefore(dstArchetype->ChunkListWithEmptySlots.End, &srcArchetype->ChunkListWithEmptySlots); dstArchetype->EntityCount += srcArchetype->EntityCount; srcArchetype->EntityCount = 0; } srcArchetype = srcArchetype->PrevArchetype; } entitiesArray.Dispose(); }
public Archetype *GetOrCreateArchetype(ComponentTypeInArchetype *types, int count, EntityGroupManager groupManager) { var type = GetExistingArchetype(types, count); if (type != null) { return(type); } AssertArchetypeComponents(types, count); // This is a new archetype, allocate it and add it to the hash map type = (Archetype *)m_ArchetypeChunkAllocator.Allocate(sizeof(Archetype), 8); type->TypesCount = count; type->Types = (ComponentTypeInArchetype *)m_ArchetypeChunkAllocator.Construct( sizeof(ComponentTypeInArchetype) * count, 4, types); type->EntityCount = 0; type->ChunkCount = 0; type->NumSharedComponents = 0; type->SharedComponentOffset = null; var disabledTypeIndex = TypeManager.GetTypeIndex <Disabled>(); type->Disabled = false; for (var i = 0; i < count; ++i) { if (TypeManager.GetComponentType(types[i].TypeIndex).Category == TypeManager.TypeCategory.ISharedComponentData) { ++type->NumSharedComponents; } if (types[i].TypeIndex == disabledTypeIndex) { type->Disabled = true; } } // Compute how many IComponentData types store Entities and need to be patched. // Types can have more than one entity, which means that this count is not necessarily // the same as the type count. int scalarEntityPatchCount = 0; int bufferEntityPatchCount = 0; for (var i = 0; i < count; ++i) { var ct = TypeManager.GetComponentType(types[i].TypeIndex); var entityOffsets = ct.EntityOffsets; if (entityOffsets == null) { continue; } if (ct.BufferCapacity >= 0) { bufferEntityPatchCount += entityOffsets.Length; } else { scalarEntityPatchCount += entityOffsets.Length; } } var chunkDataSize = Chunk.GetChunkBufferSize(type->TypesCount, type->NumSharedComponents); // FIXME: proper alignment type->Offsets = (int *)m_ArchetypeChunkAllocator.Allocate(sizeof(int) * count, 4); type->SizeOfs = (int *)m_ArchetypeChunkAllocator.Allocate(sizeof(int) * count, 4); type->TypeMemoryOrder = (int *)m_ArchetypeChunkAllocator.Allocate(sizeof(int) * count, 4); type->ScalarEntityPatches = (EntityRemapUtility.EntityPatchInfo *)m_ArchetypeChunkAllocator.Allocate(sizeof(EntityRemapUtility.EntityPatchInfo) * scalarEntityPatchCount, 4); type->ScalarEntityPatchCount = scalarEntityPatchCount; type->BufferEntityPatches = (EntityRemapUtility.BufferEntityPatchInfo *)m_ArchetypeChunkAllocator.Allocate(sizeof(EntityRemapUtility.BufferEntityPatchInfo) * bufferEntityPatchCount, 4); type->BufferEntityPatchCount = bufferEntityPatchCount; var bytesPerInstance = 0; for (var i = 0; i < count; ++i) { var cType = TypeManager.GetComponentType(types[i].TypeIndex); var sizeOf = cType.SizeInChunk; // Note that this includes internal capacity and header overhead for buffers. type->SizeOfs[i] = sizeOf; bytesPerInstance += sizeOf; } type->ChunkCapacity = chunkDataSize / bytesPerInstance; #if ENABLE_UNITY_COLLECTIONS_CHECKS if (bytesPerInstance > chunkDataSize) { throw new ArgumentException( $"Entity archetype component data is too large. The maximum component data is {chunkDataSize} but the component data is {bytesPerInstance}"); } Assert.IsTrue(Chunk.kMaximumEntitiesPerChunk >= type->ChunkCapacity); #endif // For serialization a stable ordering of the components in the // chunk is desired. The type index is not stable, since it depends // on the order in which types are added to the TypeManager. // A permutation of the types ordered by a TypeManager-generated // memory ordering is used instead. var memoryOrderings = new NativeArray <UInt64>(count, Allocator.Temp); for (int i = 0; i < count; ++i) { memoryOrderings[i] = TypeManager.GetComponentType(types[i].TypeIndex).MemoryOrdering; } for (int i = 0; i < count; ++i) { int index = i; while (index > 1 && memoryOrderings[i] < memoryOrderings[type->TypeMemoryOrder[index - 1]]) { type->TypeMemoryOrder[index] = type->TypeMemoryOrder[index - 1]; --index; } type->TypeMemoryOrder[index] = i; } memoryOrderings.Dispose(); var usedBytes = 0; for (var i = 0; i < count; ++i) { var index = type->TypeMemoryOrder[i]; var sizeOf = type->SizeOfs[index]; type->Offsets[index] = usedBytes; usedBytes += sizeOf * type->ChunkCapacity; } type->NumManagedArrays = 0; type->ManagedArrayOffset = null; for (var i = 0; i < count; ++i) { if (TypeManager.GetComponentType(types[i].TypeIndex).Category == TypeManager.TypeCategory.Class) { ++type->NumManagedArrays; } } if (type->NumManagedArrays > 0) { type->ManagedArrayOffset = (int *)m_ArchetypeChunkAllocator.Allocate(sizeof(int) * count, 4); var mi = 0; for (var i = 0; i < count; ++i) { var cType = TypeManager.GetComponentType(types[i].TypeIndex); if (cType.Category == TypeManager.TypeCategory.Class) { type->ManagedArrayOffset[i] = mi++; } else { type->ManagedArrayOffset[i] = -1; } } } if (type->NumSharedComponents > 0) { type->SharedComponentOffset = (int *)m_ArchetypeChunkAllocator.Allocate(sizeof(int) * count, 4); var mi = 0; for (var i = 0; i < count; ++i) { var cType = TypeManager.GetComponentType(types[i].TypeIndex); if (cType.Category == TypeManager.TypeCategory.ISharedComponentData) { type->SharedComponentOffset[i] = mi++; } else { type->SharedComponentOffset[i] = -1; } } } // Fill in arrays of scalar and buffer entity patches var scalarPatchInfo = type->ScalarEntityPatches; var bufferPatchInfo = type->BufferEntityPatches; for (var i = 0; i != count; i++) { var ct = TypeManager.GetComponentType(types[i].TypeIndex); var offsets = ct.EntityOffsets; if (ct.BufferCapacity >= 0) { bufferPatchInfo = EntityRemapUtility.AppendBufferEntityPatches(bufferPatchInfo, offsets, type->Offsets[i], type->SizeOfs[i], ct.ElementSize); } else { scalarPatchInfo = EntityRemapUtility.AppendEntityPatches(scalarPatchInfo, offsets, type->Offsets[i], type->SizeOfs[i]); } } type->ScalarEntityPatchCount = scalarEntityPatchCount; type->BufferEntityPatchCount = bufferEntityPatchCount; // Update the list of all created archetypes type->PrevArchetype = m_LastArchetype; m_LastArchetype = type; UnsafeLinkedListNode.InitializeList(&type->ChunkList); UnsafeLinkedListNode.InitializeList(&type->ChunkListWithEmptySlots); type->FreeChunksBySharedComponents.Init(8); m_TypeLookup.Add(GetHash(types, count), (IntPtr)type); type->SystemStateCleanupComplete = ArchetypeSystemStateCleanupComplete(type); type->SystemStateCleanupNeeded = ArchetypeSystemStateCleanupNeeded(type); groupManager.OnArchetypeAdded(type); return(type); }
public Archetype *GetOrCreateArchetype(ComponentTypeInArchetype *types, int count, EntityGroupManager groupManager) { var type = GetExistingArchetype(types, count); if (type != null) { return(type); } AssertArchetypeComponents(types, count); // This is a new archetype, allocate it and add it to the hash map type = (Archetype *)m_ArchetypeChunkAllocator.Allocate(sizeof(Archetype), 8); type->TypesCount = count; type->Types = (ComponentTypeInArchetype *)m_ArchetypeChunkAllocator.Construct(sizeof(ComponentTypeInArchetype) * count, 4, types); type->EntityCount = 0; type->NumSharedComponents = 0; type->SharedComponentOffset = null; for (var i = 0; i < count; ++i) { if (TypeManager.GetComponentType(types[i].TypeIndex).Category == TypeManager.TypeCategory.ISharedComponentData) { ++type->NumSharedComponents; } } var chunkDataSize = Chunk.GetChunkBufferSize(type->NumSharedComponents); // FIXME: proper alignment type->Offsets = (int *)m_ArchetypeChunkAllocator.Allocate(sizeof(int) * count, 4); type->SizeOfs = (int *)m_ArchetypeChunkAllocator.Allocate(sizeof(int) * count, 4); var bytesPerInstance = 0; for (var i = 0; i < count; ++i) { var cType = TypeManager.GetComponentType(types[i].TypeIndex); var sizeOf = cType.SizeInChunk * types[i].FixedArrayLengthMultiplier; type->SizeOfs[i] = sizeOf; bytesPerInstance += sizeOf; } type->ChunkCapacity = chunkDataSize / bytesPerInstance; Assert.IsTrue(Chunk.kMaximumEntitiesPerChunk >= type->ChunkCapacity); var usedBytes = 0; for (var i = 0; i < count; ++i) { var sizeOf = type->SizeOfs[i]; type->Offsets[i] = usedBytes; usedBytes += sizeOf * type->ChunkCapacity; } type->NumManagedArrays = 0; type->ManagedArrayOffset = null; for (var i = 0; i < count; ++i) { if (TypeManager.GetComponentType(types[i].TypeIndex).Category == TypeManager.TypeCategory.Class) { ++type->NumManagedArrays; } } if (type->NumManagedArrays > 0) { type->ManagedArrayOffset = (int *)m_ArchetypeChunkAllocator.Allocate(sizeof(int) * count, 4); var mi = 0; for (var i = 0; i < count; ++i) { var cType = TypeManager.GetComponentType(types[i].TypeIndex); if (cType.Category == TypeManager.TypeCategory.Class) { type->ManagedArrayOffset[i] = mi++; } else { type->ManagedArrayOffset[i] = -1; } } } if (type->NumSharedComponents > 0) { type->SharedComponentOffset = (int *)m_ArchetypeChunkAllocator.Allocate(sizeof(int) * count, 4); var mi = 0; for (var i = 0; i < count; ++i) { var cType = TypeManager.GetComponentType(types[i].TypeIndex); if (cType.Category == TypeManager.TypeCategory.ISharedComponentData) { type->SharedComponentOffset[i] = mi++; } else { type->SharedComponentOffset[i] = -1; } } } // Update the list of all created archetypes type->PrevArchetype = m_LastArchetype; m_LastArchetype = type; UnsafeLinkedListNode.InitializeList(&type->ChunkList); UnsafeLinkedListNode.InitializeList(&type->ChunkListWithEmptySlots); m_TypeLookup.Add(GetHash(types, count), (IntPtr)type); groupManager.OnArchetypeAdded(type); return(type); }
public static void MoveChunks(ArchetypeManager srcArchetypeManager, EntityDataManager *srcEntityDataManager, SharedComponentDataManager srcSharedComponents, ArchetypeManager dstArchetypeManager, EntityGroupManager dstGroupManager, SharedComponentDataManager dstSharedComponentDataManager, EntityDataManager *dstEntityDataManager, SharedComponentDataManager dstSharedComponents) { var entityRemapping = new NativeArray <EntityRemapUtility.EntityRemapInfo>(srcEntityDataManager->Capacity, Allocator.Temp); var entityPatches = new NativeList <EntityRemapUtility.EntityPatchInfo>(128, Allocator.Temp); dstEntityDataManager->AllocateEntitiesForRemapping(srcEntityDataManager, ref entityRemapping); var srcArchetype = srcArchetypeManager.m_LastArchetype; while (srcArchetype != null) { if (srcArchetype->EntityCount != 0) { if (srcArchetype->NumManagedArrays != 0) { throw new ArgumentException("MoveEntitiesFrom is not supported with managed arrays"); } var dstArchetype = dstArchetypeManager.GetOrCreateArchetype(srcArchetype->Types, srcArchetype->TypesCount, dstGroupManager); entityPatches.Clear(); for (var i = 1; i != dstArchetype->TypesCount; i++) { EntityRemapUtility.AppendEntityPatches(ref entityPatches, TypeManager.GetComponentType(dstArchetype->Types[i].TypeIndex).EntityOffsets, dstArchetype->Offsets[i], dstArchetype->SizeOfs[i]); } for (var c = srcArchetype->ChunkList.Begin; c != srcArchetype->ChunkList.End; c = c->Next) { var chunk = (Chunk *)c; dstEntityDataManager->RemapChunk(dstArchetype, chunk, 0, chunk->Count, ref entityRemapping); EntityRemapUtility.PatchEntities(ref entityPatches, chunk->Buffer, chunk->Count, ref entityRemapping); chunk->Archetype = dstArchetype; if (dstArchetype->NumSharedComponents > 0) { dstSharedComponents.MoveSharedComponents(srcSharedComponents, chunk->SharedComponentValueArray, dstArchetype->NumSharedComponents); } } UnsafeLinkedListNode.InsertListBefore(dstArchetype->ChunkList.End, &srcArchetype->ChunkList); if (!srcArchetype->ChunkListWithEmptySlots.IsEmpty) { UnsafeLinkedListNode.InsertListBefore(dstArchetype->ChunkListWithEmptySlots.End, &srcArchetype->ChunkListWithEmptySlots); } dstArchetype->EntityCount += srcArchetype->EntityCount; dstArchetype->ChunkCount += srcArchetype->ChunkCount; srcArchetype->EntityCount = 0; srcArchetype->ChunkCount = 0; } srcArchetype = srcArchetype->PrevArchetype; } srcEntityDataManager->FreeAllEntities(); entityRemapping.Dispose(); entityPatches.Dispose(); }
public Archetype *GetOrCreateArchetype(ComponentTypeInArchetype *types, int count, EntityGroupManager groupManager) { var type = GetExistingArchetype(types, count); if (type != null) { return(type); } AssertArchetypeComponents(types, count); // This is a new archetype, allocate it and add it to the hash map type = (Archetype *)m_ArchetypeChunkAllocator.Allocate(sizeof(Archetype), 8); type->TypesCount = count; type->Types = (ComponentTypeInArchetype *)m_ArchetypeChunkAllocator.Construct( sizeof(ComponentTypeInArchetype) * count, 4, types); type->EntityCount = 0; type->ChunkCount = 0; type->NumSharedComponents = 0; type->SharedComponentOffset = null; for (var i = 0; i < count; ++i) { if (TypeManager.GetComponentType(types[i].TypeIndex).Category == TypeManager.TypeCategory.ISharedComponentData) { ++type->NumSharedComponents; } } var chunkDataSize = Chunk.GetChunkBufferSize(type->TypesCount, type->NumSharedComponents); // FIXME: proper alignment type->Offsets = (int *)m_ArchetypeChunkAllocator.Allocate(sizeof(int) * count, 4); type->SizeOfs = (int *)m_ArchetypeChunkAllocator.Allocate(sizeof(int) * count, 4); type->TypeMemoryOrder = (int *)m_ArchetypeChunkAllocator.Allocate(sizeof(int) * count, 4); var bytesPerInstance = 0; for (var i = 0; i < count; ++i) { var cType = TypeManager.GetComponentType(types[i].TypeIndex); var sizeOf = cType.SizeInChunk * types[i].FixedArrayLengthMultiplier; type->SizeOfs[i] = sizeOf; bytesPerInstance += sizeOf; } type->ChunkCapacity = chunkDataSize / bytesPerInstance; #if ENABLE_UNITY_COLLECTIONS_CHECKS if (bytesPerInstance > chunkDataSize) { throw new ArgumentException( $"Entity archetype component data is too large. The maximum component data is {chunkDataSize} but the component data is {bytesPerInstance}"); } Assert.IsTrue(Chunk.kMaximumEntitiesPerChunk >= type->ChunkCapacity); #endif // For serialization a stable ordering of the components in the // chunk is desired. The type index is not stable, since it depends // on the order in which types are added to the TypeManager. // A permutation of the types ordered by a TypeManager-generated // memory ordering is used instead. var memoryOrderings = new NativeArray <UInt64>(count, Allocator.Temp); for (int i = 0; i < count; ++i) { memoryOrderings[i] = TypeManager.GetComponentType(types[i].TypeIndex).MemoryOrdering; } for (int i = 0; i < count; ++i) { int index = i; while (index > 1 && memoryOrderings[i] < memoryOrderings[type->TypeMemoryOrder[index - 1]]) { type->TypeMemoryOrder[index] = type->TypeMemoryOrder[index - 1]; --index; } type->TypeMemoryOrder[index] = i; } memoryOrderings.Dispose(); var usedBytes = 0; for (var i = 0; i < count; ++i) { var index = type->TypeMemoryOrder[i]; var sizeOf = type->SizeOfs[index]; type->Offsets[index] = usedBytes; usedBytes += sizeOf * type->ChunkCapacity; } type->NumManagedArrays = 0; type->ManagedArrayOffset = null; for (var i = 0; i < count; ++i) { if (TypeManager.GetComponentType(types[i].TypeIndex).Category == TypeManager.TypeCategory.Class) { ++type->NumManagedArrays; } } if (type->NumManagedArrays > 0) { type->ManagedArrayOffset = (int *)m_ArchetypeChunkAllocator.Allocate(sizeof(int) * count, 4); var mi = 0; for (var i = 0; i < count; ++i) { var cType = TypeManager.GetComponentType(types[i].TypeIndex); if (cType.Category == TypeManager.TypeCategory.Class) { type->ManagedArrayOffset[i] = mi++; } else { type->ManagedArrayOffset[i] = -1; } } } if (type->NumSharedComponents > 0) { type->SharedComponentOffset = (int *)m_ArchetypeChunkAllocator.Allocate(sizeof(int) * count, 4); var mi = 0; for (var i = 0; i < count; ++i) { var cType = TypeManager.GetComponentType(types[i].TypeIndex); if (cType.Category == TypeManager.TypeCategory.ISharedComponentData) { type->SharedComponentOffset[i] = mi++; } else { type->SharedComponentOffset[i] = -1; } } } // Update the list of all created archetypes type->PrevArchetype = m_LastArchetype; m_LastArchetype = type; UnsafeLinkedListNode.InitializeList(&type->ChunkList); UnsafeLinkedListNode.InitializeList(&type->ChunkListWithEmptySlots); m_TypeLookup.Add(GetHash(types, count), (IntPtr)type); type->SystemStateCleanupComplete = ArchetypeSystemStateCleanupComplete(type); type->SystemStateCleanupNeeded = ArchetypeSystemStateCleanupNeeded(type); groupManager.OnArchetypeAdded(type); return(type); }