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 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(); }