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 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 ComponentGroup CreateEntityGroup(ArchetypeManager typeMan, EntityDataManager *entityDataManager, ComponentType *requiredTypes, int requiredCount) { var hash = HashUtility.Fletcher32((ushort *)requiredTypes, requiredCount * sizeof(ComponentType) / sizeof(short)); var grp = GetCachedGroupData(hash, requiredTypes, requiredCount); if (grp != null) { return(new ComponentGroup(grp, m_JobSafetyManager, typeMan, entityDataManager)); } m_JobSafetyManager.CompleteAllJobsAndInvalidateArrays(); grp = (EntityGroupData *)m_GroupDataChunkAllocator.Allocate(sizeof(EntityGroupData), 8); grp->PrevGroup = m_LastGroupData; m_LastGroupData = grp; grp->RequiredComponentsCount = requiredCount; grp->RequiredComponents = (ComponentType *)m_GroupDataChunkAllocator.Construct(sizeof(ComponentType) * requiredCount, 4, requiredTypes); grp->ReaderTypesCount = 0; grp->WriterTypesCount = 0; grp->SubtractiveComponentsCount = 0; for (var i = 0; i != requiredCount; i++) { if (requiredTypes[i].AccessModeType == ComponentType.AccessMode.Subtractive) { grp->SubtractiveComponentsCount++; } if (!requiredTypes[i].RequiresJobDependency) { continue; } switch (requiredTypes[i].AccessModeType) { case ComponentType.AccessMode.ReadOnly: grp->ReaderTypesCount++; break; default: grp->WriterTypesCount++; break; } } grp->ReaderTypes = (int *)m_GroupDataChunkAllocator.Allocate(sizeof(int) * grp->ReaderTypesCount, 4); grp->WriterTypes = (int *)m_GroupDataChunkAllocator.Allocate(sizeof(int) * grp->WriterTypesCount, 4); var curReader = 0; var curWriter = 0; for (var i = 0; i != requiredCount; i++) { if (!requiredTypes[i].RequiresJobDependency) { continue; } switch (requiredTypes[i].AccessModeType) { case ComponentType.AccessMode.ReadOnly: grp->ReaderTypes[curReader++] = requiredTypes[i].TypeIndex; break; default: grp->WriterTypes[curWriter++] = requiredTypes[i].TypeIndex; break; } } grp->RequiredComponents = (ComponentType *)m_GroupDataChunkAllocator.Construct(sizeof(ComponentType) * requiredCount, 4, requiredTypes); grp->FirstMatchingArchetype = null; grp->LastMatchingArchetype = null; for (var type = typeMan.m_LastArchetype; type != null; type = type->PrevArchetype) { AddArchetypeIfMatching(type, grp); } m_GroupLookup.Add(hash, (IntPtr)grp); return(new ComponentGroup(grp, m_JobSafetyManager, typeMan, entityDataManager)); }