Beispiel #1
0
        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);
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        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));
        }
Beispiel #5
0
        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));
        }
Beispiel #7
0
        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;
                }
            }
        }
Beispiel #8
0
        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;
        }
Beispiel #9
0
        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);
                }
            }
        }
Beispiel #10
0
        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);
        }
Beispiel #11
0
        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);
        }
Beispiel #12
0
        public Span <T> GetComponentDataReadWrite <T>() where T : unmanaged
        {
            int typeIndex = TypeRegistry <T> .typeIndex;

            return(ChunkUtility.GetComponentData <T>(this.chunk, typeIndex));
        }
Beispiel #13
0
 public ReadOnlySpan <Entity> GetEntities() => ChunkUtility.GetEntities(chunk);