public void Execute() { DstEntityComponentStore->AllocateManagedComponentIndices((int *)DstManagedIndices.GetUnsafePtr(), DstManagedIndices.Length); int srcCounter = 0; for (var iChunk = 0; iChunk < SrcEntityComponentStore->m_Archetypes.Length; ++iChunk) { var srcArchetype = SrcEntityComponentStore->m_Archetypes.Ptr[iChunk]; for (var j = 0; j < srcArchetype->Chunks.Count; ++j) { var chunk = srcArchetype->Chunks.p[j]; var firstManagedComponent = srcArchetype->FirstManagedComponent; var numManagedComponents = srcArchetype->NumManagedComponents; for (int i = 0; i < numManagedComponents; ++i) { int type = i + firstManagedComponent; var a = (int *)ChunkDataUtility.GetComponentDataRO(chunk, 0, type); for (int ei = 0; ei < chunk->Count; ++ei) { var managedComponentIndex = a[ei]; if (managedComponentIndex == 0) { continue; } SrcManagedIndices[srcCounter] = managedComponentIndex; a[ei] = DstManagedIndices[srcCounter++]; } } } } Assert.AreEqual(SrcManagedIndices.Length, srcCounter); }
public int CheckInternalConsistency() { var aliveEntities = 0; var entityType = TypeManager.GetTypeIndex <Entity>(); for (var i = 0; i != m_EntitiesCapacity; i++) { if (m_Entities[i].Chunk == null) { continue; } aliveEntities++; var archetype = m_Entities[i].Archetype; Assert.AreEqual(entityType, archetype->Types[0].TypeIndex); var entity = *(Entity *)ChunkDataUtility.GetComponentDataRO(m_Entities[i].Chunk, m_Entities[i].IndexInChunk, 0); Assert.AreEqual(i, entity.Index); Assert.AreEqual(m_Entities[i].Version, entity.Version); Assert.IsTrue(Exists(entity)); } return(aliveEntities); }
internal void AddExistingChunk(Chunk *chunk) { for (int iEntity = 0; iEntity < chunk->Count; ++iEntity) { var entity = (Entity *)ChunkDataUtility.GetComponentDataRO(chunk, iEntity, 0); m_Entities[entity->Index].Chunk = chunk; m_Entities[entity->Index].IndexInChunk = iEntity; m_Entities[entity->Index].Archetype = chunk->Archetype; } }
public void SetArchetype(ArchetypeManager typeMan, Entity entity, Archetype *archetype, int *sharedComponentDataIndices) { var chunk = typeMan.GetChunkWithEmptySlots(archetype, sharedComponentDataIndices); var chunkIndex = typeMan.AllocateIntoChunk(chunk); var oldArchetype = m_Entities[entity.Index].Archetype; var oldChunk = m_Entities[entity.Index].Chunk; var oldChunkIndex = m_Entities[entity.Index].IndexInChunk; ChunkDataUtility.Convert(oldChunk, oldChunkIndex, chunk, chunkIndex); if (chunk->ManagedArrayIndex >= 0 && oldChunk->ManagedArrayIndex >= 0) { ChunkDataUtility.CopyManagedObjects(typeMan, oldChunk, oldChunkIndex, chunk, chunkIndex, 1); } m_Entities[entity.Index].Archetype = archetype; m_Entities[entity.Index].Chunk = chunk; m_Entities[entity.Index].IndexInChunk = chunkIndex; var lastIndex = oldChunk->Count - 1; // No need to replace with ourselves if (lastIndex != oldChunkIndex) { var lastEntity = (Entity *)ChunkDataUtility.GetComponentDataRO(oldChunk, lastIndex, 0); m_Entities[lastEntity->Index].IndexInChunk = oldChunkIndex; ChunkDataUtility.Copy(oldChunk, lastIndex, oldChunk, oldChunkIndex, 1); if (oldChunk->ManagedArrayIndex >= 0) { ChunkDataUtility.CopyManagedObjects(typeMan, oldChunk, lastIndex, oldChunk, oldChunkIndex, 1); } } if (oldChunk->ManagedArrayIndex >= 0) { ChunkDataUtility.ClearManagedObjects(typeMan, oldChunk, lastIndex, 1); } --oldArchetype->EntityCount; typeMan.SetChunkCount(oldChunk, lastIndex); }
public void MoveEntityToChunk(ArchetypeManager typeMan, Entity entity, Chunk *newChunk, int newChunkIndex) { var oldChunk = m_Entities[entity.Index].Chunk; Assert.IsTrue(oldChunk->Archetype == newChunk->Archetype); var oldChunkIndex = m_Entities[entity.Index].IndexInChunk; ChunkDataUtility.Copy(oldChunk, oldChunkIndex, newChunk, newChunkIndex, 1); if (oldChunk->ManagedArrayIndex >= 0) { ChunkDataUtility.CopyManagedObjects(typeMan, oldChunk, oldChunkIndex, newChunk, newChunkIndex, 1); } m_Entities[entity.Index].Chunk = newChunk; m_Entities[entity.Index].IndexInChunk = newChunkIndex; var lastIndex = oldChunk->Count - 1; // No need to replace with ourselves if (lastIndex != oldChunkIndex) { var lastEntity = (Entity *)ChunkDataUtility.GetComponentDataRO(oldChunk, lastIndex, 0); m_Entities[lastEntity->Index].IndexInChunk = oldChunkIndex; ChunkDataUtility.Copy(oldChunk, lastIndex, oldChunk, oldChunkIndex, 1); if (oldChunk->ManagedArrayIndex >= 0) { ChunkDataUtility.CopyManagedObjects(typeMan, oldChunk, lastIndex, oldChunk, oldChunkIndex, 1); } } if (oldChunk->ManagedArrayIndex >= 0) { ChunkDataUtility.ClearManagedObjects(typeMan, oldChunk, lastIndex, 1); } newChunk->Archetype->EntityCount--; typeMan.SetChunkCount(oldChunk, oldChunk->Count - 1); }
public void PatchEntities(Archetype *archetype, Chunk *chunk, int entityCount, EntityRemapUtility.EntityRemapInfo *remapping) { #if !NET_DOTS var firstManagedComponent = archetype->FirstManagedComponent; var numManagedComponents = archetype->NumManagedComponents; for (int i = 0; i < numManagedComponents; ++i) { int type = i + firstManagedComponent; var a = (int *)ChunkDataUtility.GetComponentDataRO(chunk, 0, type); for (int ei = 0; ei < entityCount; ++ei) { if (a[ei] != 0) { var obj = m_ManagedComponentData[a[ei]]; EntityRemapUtility.PatchEntityInBoxedType(obj, remapping); } } } #endif }
public void Execute() { var count = DstManagedIndices.Length; DstEntityComponentStore->AllocateManagedComponentIndices((int *)DstManagedIndices.GetUnsafePtr(), count); int srcCounter = 0; for (var iChunk = 0; iChunk < Chunks.Length; ++iChunk) { var chunk = (Chunk *)Chunks[iChunk]; var srcArchetype = chunk->Archetype; var firstManagedComponent = srcArchetype->FirstManagedComponent; var numManagedComponents = srcArchetype->NumManagedComponents; for (int i = 0; i < numManagedComponents; ++i) { int type = i + firstManagedComponent; var a = (int *)ChunkDataUtility.GetComponentDataRO(chunk, 0, type); for (int ei = 0; ei < chunk->Count; ++ei) { var managedComponentIndex = a[ei]; if (managedComponentIndex == 0) { continue; } SrcManagedIndices[srcCounter] = managedComponentIndex; a[ei] = DstManagedIndices[srcCounter++]; } } } if (srcCounter < count) { DstEntityComponentStore->m_ManagedComponentFreeIndex.Add((int *)DstManagedIndices.GetUnsafePtr() + srcCounter, (count - srcCounter) * sizeof(int)); } *NonNullCount = srcCounter; }
public void CheckInternalConsistency(object[] managedComponentData) { Assert.IsTrue(ManagedChangesTracker.Empty); var managedComponentIndices = new UnsafeBitArray(m_ManagedComponentIndex, Allocator.Temp); Assert.IsTrue(managedComponentData.Length >= m_ManagedComponentIndex); for (int i = m_ManagedComponentIndex; i < managedComponentData.Length; ++i) { Assert.IsNull(managedComponentData[i]); } // Iterate by archetype var entityCountByArchetype = 0; for (var i = 0; i < m_Archetypes.Length; ++i) { var archetype = m_Archetypes.Ptr[i]; int managedTypeBegin = archetype->FirstManagedComponent; int managedTypeEnd = archetype->ManagedComponentsEnd; var countInArchetype = 0; for (var j = 0; j < archetype->Chunks.Count; ++j) { var chunk = archetype->Chunks.p[j]; Assert.IsTrue(chunk->Archetype == archetype); Assert.IsTrue(chunk->Capacity >= chunk->Count); Assert.AreEqual(chunk->Count, archetype->Chunks.GetChunkEntityCount(j)); var chunkEntities = (Entity *)chunk->Buffer; AssertEntitiesExist(chunkEntities, chunk->Count); if (!chunk->Locked) { if (chunk->Count < chunk->Capacity) { if (archetype->NumSharedComponents == 0) { Assert.IsTrue(chunk->ListWithEmptySlotsIndex >= 0 && chunk->ListWithEmptySlotsIndex < archetype->ChunksWithEmptySlots.Length); Assert.IsTrue( chunk == archetype->ChunksWithEmptySlots.Ptr[chunk->ListWithEmptySlotsIndex]); } else { Assert.IsTrue(archetype->FreeChunksBySharedComponents.Contains(chunk)); } } } countInArchetype += chunk->Count; if (chunk->Archetype->HasChunkHeader) // Chunk entities with chunk components are not supported { Assert.IsFalse(chunk->Archetype->HasChunkComponents); } Assert.AreEqual(chunk->Archetype->HasChunkComponents, chunk->metaChunkEntity != Entity.Null); if (chunk->metaChunkEntity != Entity.Null) { var chunkHeaderTypeIndex = TypeManager.GetTypeIndex <ChunkHeader>(); AssertEntitiesExist(&chunk->metaChunkEntity, 1); AssertEntityHasComponent(chunk->metaChunkEntity, chunkHeaderTypeIndex); var chunkHeader = *(ChunkHeader *)GetComponentDataWithTypeRO(chunk->metaChunkEntity, chunkHeaderTypeIndex); Assert.IsTrue(chunk == chunkHeader.ArchetypeChunk.m_Chunk); var metaChunk = GetChunk(chunk->metaChunkEntity); Assert.IsTrue(metaChunk->Archetype == chunk->Archetype->MetaChunkArchetype); } for (int iType = managedTypeBegin; iType < managedTypeEnd; ++iType) { var managedIndicesInChunk = (int *)(chunk->Buffer + archetype->Offsets[iType]); for (int ie = 0; ie < chunk->Count; ++ie) { var index = managedIndicesInChunk[ie]; if (index == 0) { continue; } Assert.IsTrue(index < m_ManagedComponentIndex, "Managed component index in chunk is out of range."); Assert.IsFalse(managedComponentIndices.IsSet(index), "Managed component index is used multiple times."); managedComponentIndices.Set(index, true); } } } Assert.AreEqual(countInArchetype, archetype->EntityCount); entityCountByArchetype += countInArchetype; } for (int i = 0; i < m_ManagedComponentIndex; ++i) { Assert.AreEqual(managedComponentData[i] != null, managedComponentIndices.IsSet(i)); } var freeManagedIndices = (int *)m_ManagedComponentFreeIndex.Ptr; var freeManagedCount = m_ManagedComponentFreeIndex.Length / sizeof(int); for (int i = 0; i < freeManagedCount; ++i) { var index = freeManagedIndices[i]; Assert.IsTrue(0 < index && index < m_ManagedComponentIndex, "Managed component index in free list is out of range."); Assert.IsFalse(managedComponentIndices.IsSet(index), "Managed component was marked as free but is used in chunk."); managedComponentIndices.Set(index, true); } Assert.IsTrue(m_ManagedComponentIndex - 1 == 0 || managedComponentIndices.TestAll(1, m_ManagedComponentIndex - 1), "Managed component index has leaked."); managedComponentIndices.Dispose(); // Iterate by free list Assert.IsTrue(m_EntityInChunkByEntity[m_NextFreeEntityIndex].Chunk == null); var entityCountByFreeList = EntitiesCapacity; int freeIndex = m_NextFreeEntityIndex; while (freeIndex != -1) { Assert.IsTrue(m_EntityInChunkByEntity[freeIndex].Chunk == null); Assert.IsTrue(freeIndex < EntitiesCapacity); freeIndex = m_EntityInChunkByEntity[freeIndex].IndexInChunk; entityCountByFreeList--; } // iterate by entities var entityCountByEntities = 0; var entityType = TypeManager.GetTypeIndex <Entity>(); for (var i = 0; i != EntitiesCapacity; i++) { var chunk = m_EntityInChunkByEntity[i].Chunk; if (chunk == null) { continue; } entityCountByEntities++; var archetype = m_ArchetypeByEntity[i]; Assert.AreEqual((IntPtr)archetype, (IntPtr)chunk->Archetype); Assert.AreEqual(entityType, archetype->Types[0].TypeIndex); Assert.IsTrue(m_EntityInChunkByEntity[i].IndexInChunk < m_EntityInChunkByEntity[i].Chunk->Count); var entity = *(Entity *)ChunkDataUtility.GetComponentDataRO(m_EntityInChunkByEntity[i].Chunk, m_EntityInChunkByEntity[i].IndexInChunk, 0); Assert.AreEqual(i, entity.Index); Assert.AreEqual(m_VersionByEntity[i], entity.Version); Assert.IsTrue(Exists(entity)); } Assert.AreEqual(entityCountByEntities, entityCountByArchetype); // Enabling this fails SerializeEntitiesWorksWithBlobAssetReferences. // There is some special entity 0 usage in the serialization code. // @TODO: Review with simon looks like a potential leak? //Assert.AreEqual(entityCountByEntities, entityCountByFreeList); }
// ---------------------------------------------------------------------------------------------------------- // Core, self-contained functions to change chunks. No other functions should actually move data from // one Chunk to another, or otherwise change the structure of a Chunk after creation. // ---------------------------------------------------------------------------------------------------------- /// <summary> /// Move subset of chunk data into another chunk. /// - Chunks can be of same archetype (but differ by shared component values) /// - Returns number moved. Caller handles if less than indicated in srcBatch. /// </summary> /// <returns></returns> int Move(EntityBatchInChunk srcBatch, Chunk *dstChunk) { var srcChunk = srcBatch.Chunk; var srcChunkIndex = srcBatch.StartIndex; var srcCount = srcBatch.Count; var srcArchetype = srcChunk->Archetype; var dstArchetype = dstChunk->Archetype; // Note (srcArchetype == dstArchetype) is valid // Archetypes can the the same, but chunks still differ because filter is different (e.g. shared component) int dstChunkIndex; var dstCount = AllocateIntoChunk(dstChunk, srcCount, out dstChunkIndex); // If can only move partial batch, move from the end so that remainder of batch isn't affected. srcChunkIndex = srcChunkIndex + srcCount - dstCount; ChunkDataUtility.Convert(srcChunk, srcChunkIndex, dstChunk, dstChunkIndex, dstCount); if (dstChunk->ManagedArrayIndex >= 0 && srcChunk->ManagedArrayIndex >= 0) { ManagedChangesTracker.CopyManagedObjects(srcChunk, srcChunkIndex, dstChunk, dstChunkIndex, dstCount); } var dstEntities = (Entity *)ChunkDataUtility.GetComponentDataRO(dstChunk, dstChunkIndex, 0); for (int i = 0; i < dstCount; i++) { var entity = dstEntities[i]; SetArchetype(entity, dstArchetype); SetEntityInChunk(entity, new EntityInChunk { Chunk = dstChunk, IndexInChunk = dstChunkIndex + i }); } // Fill in moved component data from the end. var srcTailIndex = srcChunkIndex + dstCount; var srcTailCount = srcChunk->Count - srcTailIndex; var fillCount = math.min(dstCount, srcTailCount); if (fillCount > 0) { var fillStartIndex = srcChunk->Count - fillCount; ChunkDataUtility.Copy(srcChunk, fillStartIndex, srcChunk, srcChunkIndex, fillCount); var fillEntities = (Entity *)ChunkDataUtility.GetComponentDataRO(srcChunk, srcChunkIndex, 0); for (int i = 0; i < fillCount; i++) { var entity = fillEntities[i]; SetEntityInChunk(entity, new EntityInChunk { Chunk = srcChunk, IndexInChunk = srcChunkIndex + i }); } if (srcChunk->ManagedArrayIndex >= 0) { ManagedChangesTracker.CopyManagedObjects(srcChunk, fillStartIndex, srcChunk, srcChunkIndex, fillCount); } } if (srcChunk->ManagedArrayIndex >= 0) { ManagedChangesTracker.ClearManagedObjects(srcChunk, srcChunk->Count - dstCount, dstCount); } srcArchetype->EntityCount -= dstCount; dstChunk->SetAllChangeVersions(GlobalSystemVersion); srcChunk->SetAllChangeVersions(GlobalSystemVersion); ManagedChangesTracker.IncrementComponentOrderVersion(srcArchetype, srcChunk->SharedComponentValues); IncrementComponentTypeOrderVersion(srcArchetype); ManagedChangesTracker.IncrementComponentOrderVersion(dstArchetype, dstChunk->SharedComponentValues); IncrementComponentTypeOrderVersion(dstArchetype); SetChunkCount(srcChunk, srcChunk->Count - dstCount); // Cannot DestroyEntities unless SystemStateCleanupComplete on the entity chunk. if (dstChunk->Archetype->SystemStateCleanupComplete) { DestroyEntities(dstEntities, dstCount); } return(dstCount); }
public void CheckInternalConsistency() { // Iterate by archetype var entityCountByArchetype = 0; for (var i = m_Archetypes.Length - 1; i >= 0; --i) { var archetype = m_Archetypes.Ptr[i]; var countInArchetype = 0; for (var j = 0; j < archetype->Chunks.Count; ++j) { var chunk = archetype->Chunks.p[j]; Assert.IsTrue(chunk->Archetype == archetype); Assert.IsTrue(chunk->Capacity >= chunk->Count); Assert.AreEqual(chunk->Count, archetype->Chunks.GetChunkEntityCount(j)); var chunkEntities = (Entity *)chunk->Buffer; AssertEntitiesExist(chunkEntities, chunk->Count); if (!chunk->Locked) { if (chunk->Count < chunk->Capacity) { if (archetype->NumSharedComponents == 0) { Assert.IsTrue(chunk->ListWithEmptySlotsIndex >= 0 && chunk->ListWithEmptySlotsIndex < archetype->ChunksWithEmptySlots.Length); Assert.IsTrue( chunk == archetype->ChunksWithEmptySlots.Ptr[chunk->ListWithEmptySlotsIndex]); } else { Assert.IsTrue(archetype->FreeChunksBySharedComponents.Contains(chunk)); } } } countInArchetype += chunk->Count; if (chunk->Archetype->HasChunkHeader) // Chunk entities with chunk components are not supported { Assert.IsFalse(chunk->Archetype->HasChunkComponents); } Assert.AreEqual(chunk->Archetype->HasChunkComponents, chunk->metaChunkEntity != Entity.Null); if (chunk->metaChunkEntity != Entity.Null) { var chunkHeaderTypeIndex = TypeManager.GetTypeIndex <ChunkHeader>(); AssertEntitiesExist(&chunk->metaChunkEntity, 1); AssertEntityHasComponent(chunk->metaChunkEntity, chunkHeaderTypeIndex); var chunkHeader = *(ChunkHeader *)GetComponentDataWithTypeRO(chunk->metaChunkEntity, chunkHeaderTypeIndex); Assert.IsTrue(chunk == chunkHeader.ArchetypeChunk.m_Chunk); var metaChunk = GetChunk(chunk->metaChunkEntity); Assert.IsTrue(metaChunk->Archetype == chunk->Archetype->MetaChunkArchetype); } } Assert.AreEqual(countInArchetype, archetype->EntityCount); entityCountByArchetype += countInArchetype; } // Iterate by free list Assert.IsTrue(m_EntityInChunkByEntity[m_NextFreeEntityIndex].Chunk == null); var entityCountByFreeList = EntitiesCapacity; int freeIndex = m_NextFreeEntityIndex; while (freeIndex != -1) { Assert.IsTrue(m_EntityInChunkByEntity[freeIndex].Chunk == null); Assert.IsTrue(freeIndex < EntitiesCapacity); freeIndex = m_EntityInChunkByEntity[freeIndex].IndexInChunk; entityCountByFreeList--; } // iterate by entities var entityCountByEntities = 0; var entityType = TypeManager.GetTypeIndex <Entity>(); for (var i = 0; i != EntitiesCapacity; i++) { var chunk = m_EntityInChunkByEntity[i].Chunk; if (chunk == null) { continue; } entityCountByEntities++; var archetype = m_ArchetypeByEntity[i]; Assert.AreEqual((IntPtr)archetype, (IntPtr)chunk->Archetype); Assert.AreEqual(entityType, archetype->Types[0].TypeIndex); Assert.IsTrue(m_EntityInChunkByEntity[i].IndexInChunk < m_EntityInChunkByEntity[i].Chunk->Count); var entity = *(Entity *)ChunkDataUtility.GetComponentDataRO(m_EntityInChunkByEntity[i].Chunk, m_EntityInChunkByEntity[i].IndexInChunk, 0); Assert.AreEqual(i, entity.Index); Assert.AreEqual(m_VersionByEntity[i], entity.Version); Assert.IsTrue(Exists(entity)); } Assert.AreEqual(entityCountByEntities, entityCountByArchetype); // Enabling this fails SerializeEntitiesWorksWithBlobAssetReferences. // There is some special entity 0 usage in the serialization code. // @TODO: Review with simon looks like a potential leak? //Assert.AreEqual(entityCountByEntities, entityCountByFreeList); }