public ReadOnlySpan <Entity> GetEntities(EntityArchetype archetype) // Buffered? { Archetype * ptr = GetArchetypeInternal(archetype); Span <Entity> entities = new Entity[ptr->entityCount]; ChunkUtility.WriteEntitiesToBuffer(ptr->chunkArray->chunks, ptr->chunkArray->count, entities); return(entities); }
public static int CopyComponentData <T>(Chunk *chunk, int typeIndex, T *buffer, int count) where T : unmanaged { count = (count <= chunk->count) ? count : chunk->count; var indexInArchetype = ArchetypeUtility.GetTypeIndex(chunk->archetype, typeIndex); // Make sure that the type is in the archetype beforehand... var size = count * sizeof(T); Buffer.MemoryCopy(ChunkUtility.GetComponentPtrInBuffer <T>(chunk, indexInArchetype), buffer, size, size); return(count); }
public static Chunk *Rent(Archetype *archetype) { Chunk *chunk = count > 0 ? chunks[--count] : ChunkUtility.AllocateChunk(); ChunkUtility.ConstructChunk(chunk, archetype); // Mh, should this be done here? ChunkUtility.AssignSequenceNumber(chunk, nextSequenceNumber++); ++rentedCount; return(chunk); }
public bool SetComponentData <T>(Entity entity, T value) where T : unmanaged, IComponentData { if (!IsAlive(entity)) { return(false); } int typeIndex = TypeRegistry <T> .typeIndex; var entityInChunk = this.entityStore->entitiesInChunk[entity.index]; return(ChunkUtility.SetComponentData <T>(entityInChunk.chunk, entityInChunk.index, typeIndex, value)); }
public void MoveEntityToArchetype(Entity entity, Archetype *archetype) { var entityInChunk = this.entitiesInChunk[entity.index]; var chunkIndex = 0; Chunk *chunk = archetype->chunkArray->GetChunkWithEmptySlots(ref chunkIndex); int indexInChunk = chunk->count; // TODO: This is bad. Remove the legacy stuff and reimplement this to work on batches. Span <Entity> allocated = ChunkUtility.AllocateEntities_LEGACY(chunk, 1); allocated[0] = entity; ChunkUtility.CopyComponentData(entityInChunk.chunk, chunk, entityInChunk.index, indexInChunk); ChunkUtility.PatchEntityData(entityInChunk.chunk, entityInChunk.index, 1); this.entitiesInChunk[entity.index] = new EntityInChunk(chunk, indexInChunk, entityInChunk.version); }
public ref T RefComponentData <T>(Entity entity) where T : unmanaged, IComponentData { if (!IsAlive(entity)) { throw new InvalidOperationException("Cannot reference component data of a dead entity."); } int typeIndex = TypeRegistry <T> .typeIndex; var entityInChunk = this.entityStore->entitiesInChunk[entity.index]; var ptr = ChunkUtility.GetComponentDataPtr <T>(entityInChunk.chunk, entityInChunk.index, typeIndex); if (ptr == null) { throw new InvalidOperationException("Cannot reference non existent component data."); } return(ref Unsafe.AsRef <T>(ptr)); }
internal void CreateEntityInternal(Archetype *archetype, Span <Entity> entities) { this.entityStore->EnsureCapacity(entities.Length); this.entityStore->ReserveEntityBatch(entities); var allocatedEntityCount = 0; var chunkIndexInArray = 0; // This needs investigation: For some reason calling the ReserveEntityBatch // with the Span is faster than with the pointer..., even though the entire // fixed statement in the SSE branch is eliminated, as well as (possibly) the // ArgumentOutOfRange checks. // Because the count of entities and the entity size (with components) is known, // it should be possible to reserve the chunks beforehand, not allocating them // one by one in GetChunkWithEmptySlots(). fixed(Entity *ptr = entities) { // TODO: If the size of the entities is larger than a chunk allocating a chunk directly to // avoid fragmenting the entities to separate chunks with GetChunkWithEmptySlots may be better. while (allocatedEntityCount < entities.Length) { Chunk *chunk = archetype->chunkArray->GetChunkWithEmptySlots(ref chunkIndexInArray); var chunkCount = chunk->count; var buffer = ptr + allocatedEntityCount; var allocatedInChunk = ChunkUtility.AllocateEntities(chunk, buffer, entities.Length - allocatedEntityCount); for (int i = 0; i < allocatedInChunk; ++i) { Entity entity = buffer[i]; this.entityStore->entitiesInChunk[entity.index] = new EntityInChunk(chunk, chunkCount + i, entity.version); } allocatedEntityCount += allocatedInChunk; } } }
public void DestroyEntityBatchInChunk(EntityBatchInChunk entityBatchInChunk) { ChunkUtility.PatchEntityData(entityBatchInChunk.chunk, entityBatchInChunk.index, entityBatchInChunk.count); // TODO: This thing needs to be more efficent. var movedEntities = ChunkUtility.GetEntities(entityBatchInChunk.chunk); if (entityBatchInChunk.index < movedEntities.Length) // Copied from end? { movedEntities = movedEntities.Slice(entityBatchInChunk.index, Math.Min(movedEntities.Length, entityBatchInChunk.count)); for (int i = 0; i < movedEntities.Length; ++i) { var entityIndex = movedEntities[i].index; this.entitiesInChunk[entityIndex].chunk = entityBatchInChunk.chunk; this.entitiesInChunk[entityIndex].index = entityBatchInChunk.index + i; } } // TODO: Free chunks if chunk->count == 0 after patching entities ++this.version; }
internal void CreateEntityInternal_LEGACY(Archetype *archetype, Span <Entity> entities) { this.entityStore->EnsureCapacity(entities.Length); this.entityStore->ReserveEntityBatch(entities); var allocatedEntityCount = 0; var chunkIndexInArray = 0; while (allocatedEntityCount < entities.Length) { Chunk *chunk = archetype->chunkArray->GetChunkWithEmptySlots(ref chunkIndexInArray); int chunkCount = chunk->count; Span <Entity> entitiesInChunk = ChunkUtility.AllocateEntities_LEGACY(chunk, entities.Length - allocatedEntityCount); for (int i = 0; i < entitiesInChunk.Length; ++i) { Entity entity = entities[allocatedEntityCount++]; entitiesInChunk[i] = entity; this.entityStore->entitiesInChunk[entity.index] = new EntityInChunk(chunk, chunkCount + i, entity.version); } } }
internal EntityArchetype CreateArchetypeInternal(Span <int> componentTypes, Span <int> componentSizes, int absoluteBlockSize) { int hashCode = GetComponentTypeHash(componentTypes); if (this.archetypeStore->typeLookup.TryGet(hashCode, out EntityArchetype entityArchetype)) { return(entityArchetype); } int chunkCapacity = ChunkUtility.CalculateChunkBufferCapacity(absoluteBlockSize); if (chunkCapacity == 0) { throw new ArchetypeTooLargeException(absoluteBlockSize); } this.archetypeStore->EnsureCapacity(); int index = this.archetypeStore->count++; Archetype *archetype = this.archetypeStore->archetypes + index; // TODO: Move more stuff in the utility or avoid the utility. YOU DECIDE! ArchetypeUtility.ConstructComponentData(archetype, componentTypes, componentSizes, hashCode); ArchetypeUtility.CalculateComponentOffsets(archetype, chunkCapacity); archetype->chunkArray = ArchetypeChunkArray.Allocate(archetype); archetype->chunkCapacity = chunkCapacity; entityArchetype = new EntityArchetype(index); // Move to seperate method that takes Archetype* as argument? this.archetypeStore->typeLookup.Add(hashCode, entityArchetype); return(entityArchetype); }
public ReadOnlySpan <Entity> GetEntities(EntityQuery query) { var queryData = GetUpdatedQueryData(query); var archetypes = queryData->archetypes; var archetypeCount = queryData->archetypeCount; var entityCount = 0; for (int i = 0; i < archetypeCount; ++i) { entityCount += archetypes[i]->entityCount; } int entitiesInBuffer = 0; Span <Entity> entities = new Entity[entityCount]; for (int i = 0; i < archetypeCount; ++i) { var chunks = archetypes[i]->chunkArray->chunks; var chunkCount = archetypes[i]->chunkArray->count; entitiesInBuffer += ChunkUtility.WriteEntitiesToBuffer(chunks, chunkCount, entities.Slice(entitiesInBuffer)); } return(entities); }
public Span <T> GetComponentDataReadWrite <T>() where T : unmanaged { int typeIndex = TypeRegistry <T> .typeIndex; return(ChunkUtility.GetComponentData <T>(this.chunk, typeIndex)); }
public ReadOnlySpan <Entity> GetEntities() => ChunkUtility.GetEntities(chunk);