示例#1
0
            public void Execute()
            {
                var knownChunks     = ShadowChunksBySequenceNumber.GetKeyArray(Allocator.Temp);
                var processedChunks = new NativeHashMap <ulong, byte>(Chunks.Length, Allocator.Temp);

                for (var index = 0; index < Chunks.Length; index++)
                {
                    var chunk            = Chunks[index].m_Chunk;
                    var archetype        = chunk->Archetype;
                    var indexInTypeArray = ChunkDataUtility.GetIndexInTypeArray(archetype, TypeIndex);
                    if (indexInTypeArray == -1) // Archetype doesn't match required component
                    {
                        continue;
                    }

                    var version        = chunk->GetChangeVersion(0);
                    var sequenceNumber = chunk->SequenceNumber;
                    processedChunks[sequenceNumber] = 0;
                    var entityDataPtr = chunk->Buffer + archetype->Offsets[0];

                    if (ShadowChunksBySequenceNumber.TryGetValue(sequenceNumber, out var shadow))
                    {
                        if (!ChangeVersionUtility.DidChange(version, shadow.Version))
                        {
                            continue;
                        }

                        UnsafeUtility.MemCpy(shadow.EntityDataBuffer, entityDataPtr, chunk->Count * sizeof(Entity));

                        shadow.EntityCount = chunk->Count;
                        shadow.Version     = version;

                        ShadowChunksBySequenceNumber[sequenceNumber] = shadow;
                    }
                    else
                    {
                        ShadowChunksBySequenceNumber.Add(sequenceNumber, *(AllocatedShadowChunks + index));
                    }
                }

                for (var i = 0; i < knownChunks.Length; i++)
                {
                    var chunkSequenceNumber = knownChunks[i];
                    if (!processedChunks.ContainsKey(chunkSequenceNumber))
                    {
                        // This is a missing chunk
                        RemovedChunks.Add(chunkSequenceNumber);
                    }
                }

                knownChunks.Dispose();
                processedChunks.Dispose();
            }
    public void SwapComponents(ArchetypeChunk leftChunk, int leftIndex, ArchetypeChunk rightChunk, int rightIndex)
    {
        if (m_IsMainThread)
        {
            BeforeStructuralChange();
        }

        var globalSystemVersion = EntityComponentStore->GlobalSystemVersion;

        ChunkDataUtility.SwapComponents(leftChunk.m_Chunk, leftIndex, rightChunk.m_Chunk, rightIndex, 1,
                                        globalSystemVersion, globalSystemVersion);
    }
        public void SIZ_TagComponentZeroSize()
        {
            var entity0 = m_Manager.CreateEntity(typeof(EcsTestTag));

            unsafe {
                // a system ran, the version should match the global
                var chunk0           = m_Manager.Entities->GetComponentChunk(entity0);
                var archetype0       = chunk0->Archetype;
                var indexInTypeArray = ChunkDataUtility.GetIndexInTypeArray(chunk0->Archetype, TypeManager.GetTypeIndex <EcsTestTag>());

                Assert.AreEqual(0, archetype0->SizeOfs[indexInTypeArray]);
            }
        }
示例#4
0
            unsafe bool DidChangeInternal(World world, IEnumerable <GameObject> targets, IEnumerable <int> selectedComponentTypes)
            {
                if (world != m_LastWorld)
                {
                    m_LastWorld = world;
                    return(true);
                }

                if (m_LastConversionData == EntityConversionData.Null)
                {
                    // @TODO Handle multiple targets correctly.
                    m_LastConversionData = EntityConversionUtility.GetConversionData(targets, world).FirstOrDefault();

                    if (m_LastConversionData == EntityConversionData.Null)
                    {
                        return(false);
                    }

                    m_LastChunk = world.EntityManager.GetChunk(m_LastConversionData.PrimaryEntity);
                    return(true);
                }

                var chunk = world.EntityManager.GetChunk(m_LastConversionData.PrimaryEntity);

                if (null == chunk.m_Chunk || chunk != m_LastChunk)
                {
                    m_LastChunk = chunk;
                    return(true);
                }

                foreach (var typeIndex in selectedComponentTypes)
                {
                    var typeIndexInArchetype = ChunkDataUtility.GetIndexInTypeArray(m_LastChunk.m_Chunk->Archetype, typeIndex);
                    if (typeIndexInArchetype == -1)
                    {
                        continue;
                    }
                    var typeChangeVersion = m_LastChunk.m_Chunk->GetChangeVersion(typeIndexInArchetype);

                    if (ChangeVersionUtility.DidChange(typeChangeVersion, m_LastGlobalSystemVersion))
                    {
                        m_LastGlobalSystemVersion = world.EntityManager.GlobalSystemVersion;

                        return(true);
                    }
                }

                return(false);
            }
        public void SIZ_TagComponentDoesNotChangeCapacity()
        {
            var entity0 = m_Manager.CreateEntity(typeof(EcsTestData));
            var entity1 = m_Manager.CreateEntity(typeof(EcsTestData), typeof(EcsTestTag));

            unsafe {
                // a system ran, the version should match the global
                var chunk0     = m_Manager.Entities->GetComponentChunk(entity0);
                var chunk1     = m_Manager.Entities->GetComponentChunk(entity1);
                var archetype0 = chunk0->Archetype;
                var archetype1 = chunk1->Archetype;

                ChunkDataUtility.GetIndexInTypeArray(chunk0->Archetype, TypeManager.GetTypeIndex <EcsTestData2>());

                Assert.AreEqual(archetype0->BytesPerInstance, archetype1->BytesPerInstance);
            }
        }
        public void SIZ_TagComponentDoesNotChangeCapacity()
        {
            var entity0 = m_Manager.CreateEntity(typeof(EcsTestData));
            var entity1 = m_Manager.CreateEntity(typeof(EcsTestData), typeof(EcsTestTag));

            unsafe {
                // a system ran, the version should match the global
                var chunk0     = m_Manager.EntityComponentStore->GetChunk(entity0);
                var chunk1     = m_Manager.EntityComponentStore->GetChunk(entity1);
                var archetype0 = chunk0->Archetype;
                var archetype1 = chunk1->Archetype;

                ChunkDataUtility.GetIndexInTypeArray(chunk0->Archetype, TypeManager.GetTypeIndex <EcsTestData2>());

                Assert.True(ChunkDataUtility.AreLayoutCompatible(archetype0, archetype1));
            }
        }
        public void AddSharedComponentToMultipleEntitiesIncompatibleChunkLayouts()
        {
            // The goal of this test is to verify that the moved IComponentData keeps the same values from
            // before the addition of the shared component.
            var archetype           = m_Manager.CreateArchetype(typeof(EcsTestData));
            var archetypeWithShared = m_Manager.CreateArchetype(typeof(EcsTestData), typeof(EcsTestSharedCompWithMaxChunkCapacity));

            unsafe
            {
                Assert.IsFalse(ChunkDataUtility.AreLayoutCompatible(archetype.Archetype, archetypeWithShared.Archetype));
            }

            var       query       = m_Manager.CreateEntityQuery(typeof(EcsTestData));
            const int numEntities = 5000;

            using (var entities = new NativeArray <Entity>(numEntities, Allocator.Persistent))
            {
                m_Manager.CreateEntity(archetype, entities);

                for (int i = 0; i < entities.Length; ++i)
                {
                    m_Manager.SetComponentData(entities[i], new EcsTestData(i));
                }

                foreach (var e in entities)
                {
                    Assert.IsFalse(m_Manager.HasComponent <EcsTestSharedCompWithMaxChunkCapacity>(e));
                }

                m_Manager.AddSharedComponentData(query, new EcsTestSharedCompWithMaxChunkCapacity(17));
                var chunk              = m_Manager.GetChunk(entities[0]);
                int maxChunkCapacity   = TypeManager.GetTypeInfo <EcsTestSharedCompWithMaxChunkCapacity>().MaximumChunkCapacity;
                int expectedChunkCount = (numEntities + maxChunkCapacity - 1) / maxChunkCapacity;
                Assert.AreEqual(expectedChunkCount, chunk.Archetype.ChunkCount);

                // Ensure that the moved components have the correct values.
                for (int i = 0; i < entities.Length; ++i)
                {
                    Assert.IsTrue(m_Manager.HasComponent <EcsTestSharedCompWithMaxChunkCapacity>(entities[i]));
                    Assert.AreEqual(17, m_Manager.GetSharedComponentData <EcsTestSharedCompWithMaxChunkCapacity>(entities[i]).Value);
                    Assert.AreEqual(i, m_Manager.GetComponentData <EcsTestData>(entities[i]).value);
                }
            }
        }
        public unsafe void ArchetypeIsManaged()
        {
            var types = new ComponentType[]
            {
                typeof(EcsTestData),
                typeof(ConversionTestHybridComponent),
#if !UNITY_DISABLE_MANAGED_COMPONENTS
                typeof(EcsTestManagedComponent)
#endif
            };

            var archetype = m_Manager.CreateArchetype(types).Archetype;

            Assert.IsFalse(archetype->IsManaged(ChunkDataUtility.GetIndexInTypeArray(archetype, types[0].TypeIndex)));
            Assert.IsTrue(archetype->IsManaged(ChunkDataUtility.GetIndexInTypeArray(archetype, types[1].TypeIndex)));
#if !UNITY_DISABLE_MANAGED_COMPONENTS
            Assert.IsTrue(archetype->IsManaged(ChunkDataUtility.GetIndexInTypeArray(archetype, types[2].TypeIndex)));
#endif
        }
示例#9
0
        static unsafe void WriteChunkData(YamlWriter writer, EntityManager entityManager, NativeArray <EntityRemapUtility.EntityRemapInfo> entityRemapInfos, Chunk *initialChunk, Archetype *archetype, int archetypeIndex, bool dumpChunkRawData)
        {
            var    tempChunkMem = stackalloc byte[Chunk.kChunkSize];
            Chunk *tempChunk    = (Chunk *)tempChunkMem;

            if (dumpChunkRawData)
            {
                UnsafeUtility.MemCpy(tempChunk, initialChunk, Chunk.kChunkSize);

                byte *tempChunkBuffer = tempChunk->Buffer;

                BufferHeader.PatchAfterCloningChunk(tempChunk);
                EntityRemapUtility.PatchEntities(archetype->ScalarEntityPatches, archetype->ScalarEntityPatchCount, archetype->BufferEntityPatches, archetype->BufferEntityPatchCount, tempChunkBuffer, tempChunk->Count, ref entityRemapInfos);
                ClearChunkHeaderComponents(tempChunk);
                ChunkDataUtility.MemsetUnusedChunkData(tempChunk, 0);

                tempChunk->Archetype = (Archetype *)archetypeIndex;
            }

            using (writer.WriteCollection(k_ChunkDataCollectionTag))
            {
                using (writer.WriteCollection("Header"))
                {
                    WriteEntity(writer, nameof(Chunk.metaChunkEntity), initialChunk->metaChunkEntity);
                    writer.WriteKeyValue(nameof(Chunk.Capacity), initialChunk->Capacity);
                    writer.WriteKeyValue(nameof(Chunk.Count), initialChunk->Count);

                    if (dumpChunkRawData)
                    {
                        writer.WriteFormattedBinaryData("Header-RawData", tempChunk, Chunk.kBufferOffset);
                    }
                }

                // First pass to sort by component type
                var entitiesByChunkIndex   = new Dictionary <int, Entity>();
                var componentDataList      = new List <int>();
                var chunkComponentDataList = new List <int>();
                var chunkTypes             = archetype->Types;
                for (int typeI = 0; typeI < archetype->TypesCount; typeI++)
                {
                    var componentType         = &chunkTypes[typeI];
                    var type                  = TypeManager.GetType(componentType->TypeIndex);
                    ref readonly var typeInfo = ref TypeManager.GetTypeInfo(componentType->TypeIndex);
        public void AddSharedComponentIncompatibleChunkLayouts()
        {
            var archetype           = m_Manager.CreateArchetype(typeof(EcsTestData));
            var archetypeWithShared = m_Manager.CreateArchetype(typeof(EcsTestData), typeof(EcsTestSharedCompWithMaxChunkCapacity));

            unsafe
            {
                Assert.IsFalse(ChunkDataUtility.AreLayoutCompatible(archetype.Archetype, archetypeWithShared.Archetype));
            }

            var    query = m_Manager.CreateEntityQuery(typeof(EcsTestData));
            Entity e     = m_Manager.CreateEntity(archetype);

            Assert.IsFalse(m_Manager.HasComponent <EcsTestSharedCompWithMaxChunkCapacity>(e));

            m_Manager.AddSharedComponentData(query, new EcsTestSharedCompWithMaxChunkCapacity(17));

            Assert.IsTrue(m_Manager.HasComponent <EcsTestSharedCompWithMaxChunkCapacity>(e));
            Assert.AreEqual(17, m_Manager.GetSharedComponentData <EcsTestSharedCompWithMaxChunkCapacity>(e).Value);
        }
示例#11
0
        private static unsafe void ClearChunkHeaderComponents(Chunk *chunk)
        {
            int chunkHeaderTypeIndex = TypeManager.GetTypeIndex <ChunkHeader>();
            var archetype            = chunk->Archetype;
            var typeIndexInArchetype = ChunkDataUtility.GetIndexInTypeArray(chunk->Archetype, chunkHeaderTypeIndex);

            if (typeIndexInArchetype == -1)
            {
                return;
            }

            var buffer       = chunk->Buffer;
            var length       = chunk->Count;
            var startOffset  = archetype->Offsets[typeIndexInArchetype];
            var chunkHeaders = (ChunkHeader *)(buffer + startOffset);

            for (int i = 0; i < length; ++i)
            {
                chunkHeaders[i].chunk = null;
            }
        }
        public void AddSharedComponentViaAddComponentWithIncompatibleChunkLayouts()
        {
            var archetype           = m_Manager.CreateArchetype(typeof(EcsTestData));
            var archetypeWithShared = m_Manager.CreateArchetype(typeof(EcsTestData), typeof(EcsTestSharedCompWithMaxChunkCapacity));

            unsafe
            {
                Assert.IsFalse(ChunkDataUtility.AreLayoutCompatible(archetype.Archetype, archetypeWithShared.Archetype));
            }

            using (var entities = new NativeArray <Entity>(1, Allocator.TempJob))
            {
                m_Manager.CreateEntity(archetype, entities);
                Assert.IsFalse(m_Manager.HasComponent <EcsTestSharedCompWithMaxChunkCapacity>(entities[0]));

                m_Manager.AddComponent(entities, typeof(EcsTestSharedCompWithMaxChunkCapacity));

                Assert.IsTrue(m_Manager.HasComponent <EcsTestSharedCompWithMaxChunkCapacity>(entities[0]));
                Assert.AreEqual(0, m_Manager.GetSharedComponentData <EcsTestSharedCompWithMaxChunkCapacity>(entities[0]).Value);
            }
        }
示例#13
0
        private static unsafe int GenerateRemapInfo(EntityManager entityManager, EntityArchetype[] archetypeArray, NativeArray <EntityRemapUtility.EntityRemapInfo> entityRemapInfos)
        {
            int num   = 1;
            int num2  = 0;
            int index = 0;

            while (index < archetypeArray.Length)
            {
                Archetype *archetype = archetypeArray[index].Archetype;
                Chunk *    begin     = (Chunk *)archetype->ChunkList.Begin;
                while (true)
                {
                    if (begin == archetype->ChunkList.End)
                    {
                        index++;
                        break;
                    }
                    int num4 = 0;
                    while (true)
                    {
                        if (num4 >= begin->Count)
                        {
                            num2++;
                            begin = (Chunk *)begin->ChunkListNode.Next;
                            break;
                        }
                        Entity source = *((Entity *)ChunkDataUtility.GetComponentDataRO(begin, num4, 0));
                        Entity target = new Entity {
                            Version = 0,
                            Index   = num
                        };
                        EntityRemapUtility.AddEntityRemapping(ref entityRemapInfos, source, target);
                        num++;
                        num4++;
                    }
                }
            }
            return(num2);
        }
示例#14
0
        [StandaloneFixme] // IJob
        public void CHG_IncrementedOnInjection()
        {
            var entity0    = m_Manager.CreateEntity(typeof(EcsTestData), typeof(EcsTestData2));
            var bumpSystem = World.CreateManager <BumpVersionSystem>();

            var oldGlobalVersion = m_Manager.GlobalSystemVersion;

            bumpSystem.Update();

            var value0 = m_Manager.GetComponentData <EcsTestData2>(entity0).value0;

            Assert.AreEqual(10, value0);

            Assert.That(m_Manager.GlobalSystemVersion > oldGlobalVersion);

            unsafe {
                // a system ran, the version should match the global
                var chunk0    = m_Manager.Entities->GetComponentChunk(entity0);
                var td2index0 = ChunkDataUtility.GetIndexInTypeArray(chunk0->Archetype, TypeManager.GetTypeIndex <EcsTestData2>());
                Assert.AreEqual(m_Manager.GlobalSystemVersion, chunk0->GetChangeVersion(td2index0));
            }
        }
 public static unsafe void *GetComponentDataWithTypeRO(this ArchetypeChunk chunk, int chunkIndex, int typeIndex)
 {
     chunk.AssertEntityHasComponent(typeIndex);
     return(ChunkDataUtility.GetComponentDataWithTypeRO(chunk.m_Chunk, chunkIndex, typeIndex));
 }
        static unsafe void WriteChunkData(YamlWriter writer, EntityManager entityManager, Chunk *initialChunk, Archetype *archetype, bool dumpChunkRawData)
        {
            using (writer.WriteCollection(k_ChunkDataCollectionTag))
            {
                using (writer.WriteCollection("Header"))
                {
                    WriteEntity(writer, nameof(Chunk.metaChunkEntity), initialChunk->metaChunkEntity);
                    writer.WriteKeyValue(nameof(Chunk.Capacity), initialChunk->Capacity)
                    .WriteKeyValue(nameof(Chunk.Count), initialChunk->Count);

                    if (dumpChunkRawData)
                    {
                        writer.WriteFormattedBinaryData("RawData", initialChunk, Chunk.kBufferOffset);
                    }
                }

                // First pass to sort by component type
                var entitiesByChunkIndex   = new Dictionary <int, Entity>();
                var componentDataList      = new List <int>();
                var chunkComponentDataList = new List <int>();
                var chunkTypes             = archetype->Types;
                for (int typeI = 0; typeI < archetype->TypesCount; typeI++)
                {
                    var componentType = &chunkTypes[typeI];
                    var type          = TypeManager.GetType(componentType->TypeIndex);
                    var typeInfo      = TypeManager.GetTypeInfo(componentType->TypeIndex);

                    if (componentType->IsChunkComponent)
                    {
                        chunkComponentDataList.Add(typeI);
                    }

                    // Is it a Component Data ?
                    else if (typeof(IComponentData).IsAssignableFrom(type) || typeof(Entity).IsAssignableFrom(type) || typeof(IBufferElementData).IsAssignableFrom(type))
                    {
                        // Ignore Tag Component, no data to dump
                        if (typeInfo.IsZeroSized)
                        {
                            continue;
                        }

                        if (typeof(Entity).IsAssignableFrom(type))
                        {
                            componentDataList.Insert(0, typeI);

                            for (int i = 0; i < initialChunk->Count;)
                            {
                                var entity = (Entity)Marshal.PtrToStructure((IntPtr)initialChunk->Buffer + archetype->SizeOfs[0] * i, type);
                                if (entityManager.Exists(entity))
                                {
                                    entitiesByChunkIndex.Add(i, entity);
                                    i++;
                                }
                            }
                        }
                        else
                        {
                            componentDataList.Add(typeI);
                        }
                    }
                }

                // Parse the Component Data for this chunk and store them
                using (writer.WriteCollection(k_ComponentDataCollectionTag))
                {
                    foreach (var typeI in componentDataList)
                    {
                        var componentTypeInArchetype = &chunkTypes[typeI];
                        var componentType            = TypeManager.GetType(componentTypeInArchetype->TypeIndex);
                        var componentTypeInfo        = TypeManager.GetTypeInfo(componentTypeInArchetype->TypeIndex);
                        var componentExtractedInfo   = TypeDataExtractor.GetTypeExtractedInfo(componentType);

                        using (writer.WriteCollection(k_ComponentDataTag))
                        {
                            writer.WriteInlineMap("info", new[]
                            {
                                new KeyValuePair <object, object>(nameof(Type), componentType.Name),
                                new KeyValuePair <object, object>(nameof(TypeManager.TypeInfo.SizeInChunk), componentTypeInfo.SizeInChunk)
                            });

                            using (writer.WriteCollection("Entities"))
                            {
                                var indexInTypeArray       = ChunkDataUtility.GetIndexInTypeArray(archetype, componentTypeInArchetype->TypeIndex);
                                var componentOffsetInChunk = archetype->Offsets[indexInTypeArray];
                                var componentSize          = archetype->SizeOfs[indexInTypeArray];
                                var componentsBuffer       = initialChunk->Buffer + componentOffsetInChunk;
                                var entityData             = new Dictionary <string, string>();

                                // Dump all entities in this chunk
                                foreach (var kvp in entitiesByChunkIndex)
                                {
                                    var entity = kvp.Value;
                                    entityData.Clear();

                                    // Get the location of the component data
                                    var compData = componentsBuffer + kvp.Key * componentSize;

                                    // If the component we are dumping is a Dynamic Buffer
                                    if (typeof(IBufferElementData).IsAssignableFrom(componentType))
                                    {
                                        var header = (BufferHeader *)compData;
                                        var begin  = BufferHeader.GetElementPointer(header);
                                        var size   = Marshal.SizeOf(componentType);

                                        using (writer.WriteCollection(entity.ToString()))
                                        {
                                            for (var it = 0; it < header->Length; it++)
                                            {
                                                var item = begin + (size * it);
                                                entityData.Clear();

                                                // Dump each field of the current entity's component data
                                                foreach (var componentFieldInfo in componentExtractedInfo.Fields)
                                                {
                                                    var compDataObject = Marshal.PtrToStructure((IntPtr)item + componentFieldInfo.Offset, componentFieldInfo.Type);
                                                    entityData.Add(componentFieldInfo.Name, compDataObject.ToString());
                                                }
                                                writer.WriteInlineMap($"{it:0000}", entityData);
                                            }
                                        }
                                    }

                                    // If it's a Component Data
                                    else
                                    {
                                        // Dump each field of the current entity's component data
                                        foreach (var componentFieldInfo in componentExtractedInfo.Fields)
                                        {
                                            var compDataObject = Marshal.PtrToStructure((IntPtr)compData + componentFieldInfo.Offset, componentFieldInfo.Type);
                                            entityData.Add(componentFieldInfo.Name, compDataObject.ToString());
                                        }
                                        writer.WriteInlineMap(entity.ToString(), entityData);
                                    }
                                }
                                if (dumpChunkRawData)
                                {
                                    var csize = EntityComponentStore.GetComponentArraySize(componentSize, archetype->ChunkCapacity);
                                    writer.WriteFormattedBinaryData("RawData", componentsBuffer, csize, componentOffsetInChunk + Chunk.kBufferOffset);
                                }
                            }
                        }
                    }
                }
            }
        }
示例#17
0
        public static unsafe void SerializeWorld(EntityManager entityManager, BinaryWriter writer, out int[] sharedComponentsToSerialize, NativeArray <EntityRemapUtility.EntityRemapInfo> entityRemapInfos)
        {
            writer.Write(CurrentFileFormatVersion);
            var entityComponentStore = entityManager.EntityComponentStore;

            NativeHashMap <EntityArchetype, int> archetypeToIndex;

            EntityArchetype[] archetypeArray;
            GetAllArchetypes(entityComponentStore, out archetypeToIndex, out archetypeArray);

            var typeHashes = new NativeHashMap <ulong, int>(1024, Allocator.Temp);

            foreach (var archetype in archetypeArray)
            {
                for (int iType = 0; iType < archetype.Archetype->TypesCount; ++iType)
                {
                    var typeIndex = archetype.Archetype->Types[iType].TypeIndex;
                    var ti        = TypeManager.GetTypeInfo(typeIndex);
                    var hash      = ti.StableTypeHash;
                    typeHashes.TryAdd(hash, 0);
                }
            }
            var typeHashSet = typeHashes.GetKeyArray(Allocator.Temp);

            writer.Write(typeHashSet.Length);
            foreach (ulong hash in typeHashSet)
            {
                writer.Write(hash);
            }

            var typeHashToIndexMap = new NativeHashMap <ulong, int>(typeHashSet.Length, Allocator.Temp);

            for (int i = 0; i < typeHashes.Length; ++i)
            {
                typeHashToIndexMap.TryAdd(typeHashSet[i], i);
            }

            WriteArchetypes(writer, archetypeArray, typeHashToIndexMap);
            var sharedComponentMapping = GatherSharedComponents(archetypeArray, out var sharedComponentArraysTotalCount);
            var sharedComponentArrays  = new NativeArray <int>(sharedComponentArraysTotalCount, Allocator.Temp);

            FillSharedComponentArrays(sharedComponentArrays, archetypeArray, sharedComponentMapping);
            writer.Write(sharedComponentArrays.Length);
            writer.WriteArray(sharedComponentArrays);
            sharedComponentArrays.Dispose();

            //TODO: ensure chunks are defragged?

            var bufferPatches   = new NativeList <BufferPatchRecord>(128, Allocator.Temp);
            var totalChunkCount = GenerateRemapInfo(entityManager, archetypeArray, entityRemapInfos);

            writer.Write(totalChunkCount);

            GatherAllUsedBlobAssets(archetypeArray, out var blobAssetRefs, out var blobAssets);

            var blobAssetOffsets   = new NativeArray <int>(blobAssets.Length, Allocator.Temp);
            int totalBlobAssetSize = 0;

            int Align16(int x) => (x + 15) & ~15;

            for (int i = 0; i < blobAssets.Length; ++i)
            {
                totalBlobAssetSize += sizeof(BlobAssetHeader);
                blobAssetOffsets[i] = totalBlobAssetSize;
                totalBlobAssetSize += Align16(blobAssets[i].header->Length);
            }

            writer.Write(totalBlobAssetSize);

            var zeroBytes = int4.zero;

            for (int i = 0; i < blobAssets.Length; ++i)
            {
                var             blobAssetLength = blobAssets[i].header->Length;
                BlobAssetHeader header          = new BlobAssetHeader
                {
                    ValidationPtr = null, Allocator = Allocator.None, Length = Align16(blobAssetLength)
                };
                writer.WriteBytes(&header, sizeof(BlobAssetHeader));
                writer.WriteBytes(blobAssets[i].header + 1, blobAssetLength);
                writer.WriteBytes(&zeroBytes, header.Length - blobAssetLength);
            }

            var tempChunk = (Chunk *)UnsafeUtility.Malloc(Chunk.kChunkSize, 16, Allocator.Temp);

            for (int archetypeIndex = 0; archetypeIndex < archetypeArray.Length; ++archetypeIndex)
            {
                var archetype = archetypeArray[archetypeIndex].Archetype;
                for (var ci = 0; ci < archetype->Chunks.Count; ++ci)
                {
                    var chunk = archetype->Chunks.p[ci];
                    bufferPatches.Clear();

                    UnsafeUtility.MemCpy(tempChunk, chunk, Chunk.kChunkSize);
                    tempChunk->metaChunkEntity = EntityRemapUtility.RemapEntity(ref entityRemapInfos, tempChunk->metaChunkEntity);

                    // Prevent patching from touching buffers allocated memory
                    BufferHeader.PatchAfterCloningChunk(tempChunk);

                    byte *tempChunkBuffer = tempChunk->Buffer;
                    EntityRemapUtility.PatchEntities(archetype->ScalarEntityPatches, archetype->ScalarEntityPatchCount, archetype->BufferEntityPatches, archetype->BufferEntityPatchCount, tempChunkBuffer, tempChunk->Count, ref entityRemapInfos);
                    if (archetype->ContainsBlobAssetRefs)
                    {
                        PatchBlobAssetsInChunkBeforeSave(tempChunk, chunk, blobAssetOffsets, blobAssetRefs);
                    }

                    FillPatchRecordsForChunk(chunk, bufferPatches);

                    ClearChunkHeaderComponents(tempChunk);
                    ChunkDataUtility.MemsetUnusedChunkData(tempChunk, 0);
                    tempChunk->Archetype = (Archetype *)archetypeIndex;

                    if (archetype->NumManagedArrays != 0)
                    {
                        throw new ArgumentException("Serialization of GameObject components is not supported for pure entity scenes");
                    }

                    writer.WriteBytes(tempChunk, Chunk.kChunkSize);

                    writer.Write(bufferPatches.Length);

                    if (bufferPatches.Length > 0)
                    {
                        writer.WriteList(bufferPatches);

                        // Write heap backed data for each required patch.
                        // TODO: PERF: Investigate static-only deserialization could manage one block and mark in pointers somehow that they are not indiviual
                        for (int i = 0; i < bufferPatches.Length; ++i)
                        {
                            var patch  = bufferPatches[i];
                            var header = (BufferHeader *)OffsetFromPointer(tempChunk->Buffer, patch.ChunkOffset);
                            writer.WriteBytes(header->Pointer, patch.AllocSizeBytes);
                            BufferHeader.Destroy(header);
                        }
                    }
                }
            }

            blobAssetRefs.Dispose();
            blobAssets.Dispose();

            bufferPatches.Dispose();
            UnsafeUtility.Free(tempChunk, Allocator.Temp);

            sharedComponentsToSerialize = new int[sharedComponentMapping.Length - 1];

            using (var keyArray = sharedComponentMapping.GetKeyArray(Allocator.Temp))
                foreach (var key in keyArray)
                {
                    if (key == 0)
                    {
                        continue;
                    }

                    if (sharedComponentMapping.TryGetValue(key, out var val))
                    {
                        sharedComponentsToSerialize[val - 1] = key;
                    }
                }

            archetypeToIndex.Dispose();
            typeHashes.Dispose();
            typeHashSet.Dispose();
            typeHashToIndexMap.Dispose();
        }
示例#18
0
        public static unsafe void SerializeWorld(EntityManager entityManager, BinaryWriter writer, out int[] sharedComponentsToSerialize, NativeArray <EntityRemapUtility.EntityRemapInfo> entityRemapInfos)
        {
            writer.Write(CurrentFileFormatVersion);
            var archetypeManager = entityManager.ArchetypeManager;

            Dictionary <EntityArchetype, int> archetypeToIndex;

            EntityArchetype[] archetypeArray;
            GetAllArchetypes(archetypeManager, out archetypeToIndex, out archetypeArray);

            var typeindices = new HashSet <int>();

            foreach (var archetype in archetypeArray)
            {
                for (int iType = 0; iType < archetype.Archetype->TypesCount; ++iType)
                {
                    typeindices.Add(archetype.Archetype->Types[iType].TypeIndex & TypeManager.ClearFlagsMask);
                }
            }

            var typeArray = typeindices.Select(index =>
            {
                var type = TypeManager.GetType(index);
                var name = TypeManager.GetType(index).AssemblyQualifiedName;
                var hash = TypeManager.GetTypeInfo(index).StableTypeHash;
                return(new
                {
                    index,
                    type,
                    name,
                    hash,
                    utf8Name = Encoding.UTF8.GetBytes(name)
                });
            }).OrderBy(t => t.name).ToArray();

            int typeNameBufferSize = typeArray.Sum(t => t.utf8Name.Length + 1);

            writer.Write(typeArray.Length);
            foreach (var n in typeArray)
            {
                writer.Write(n.hash);
            }

            writer.Write(typeNameBufferSize);
            foreach (var n in typeArray)
            {
                writer.Write(n.utf8Name);
                writer.Write((byte)0);
            }

            var typeIndexMap = new Dictionary <int, int>();

            for (int i = 0; i < typeArray.Length; ++i)
            {
                typeIndexMap[typeArray[i].index] = i;
            }

            WriteArchetypes(writer, archetypeArray, typeIndexMap);
            var sharedComponentMapping = GatherSharedComponents(archetypeArray, out var sharedComponentArraysTotalCount);
            var sharedComponentArrays  = new NativeArray <int>(sharedComponentArraysTotalCount, Allocator.Temp);

            FillSharedComponentArrays(sharedComponentArrays, archetypeArray, sharedComponentMapping);
            writer.Write(sharedComponentArrays.Length);
            writer.WriteArray(sharedComponentArrays);
            sharedComponentArrays.Dispose();

            //TODO: ensure chunks are defragged?

            var bufferPatches   = new NativeList <BufferPatchRecord>(128, Allocator.Temp);
            var totalChunkCount = GenerateRemapInfo(entityManager, archetypeArray, entityRemapInfos);

            writer.Write(totalChunkCount);

            GatherAllUsedBlobAssets(archetypeArray, out var blobAssetRefs, out var blobAssets);

            var blobAssetOffsets   = new NativeArray <int>(blobAssets.Length, Allocator.Temp);
            int totalBlobAssetSize = 0;

            int Align16(int x) => (x + 15) & ~15;

            for (int i = 0; i < blobAssets.Length; ++i)
            {
                totalBlobAssetSize += sizeof(BlobAssetHeader);
                blobAssetOffsets[i] = totalBlobAssetSize;
                totalBlobAssetSize += Align16(blobAssets[i].header->Length);
            }

            writer.Write(totalBlobAssetSize);

            var zeroBytes = int4.zero;

            for (int i = 0; i < blobAssets.Length; ++i)
            {
                var             blobAssetLength = blobAssets[i].header->Length;
                BlobAssetHeader header          = new BlobAssetHeader
                {
                    ValidationPtr = null, Allocator = Allocator.None, Length = Align16(blobAssetLength)
                };
                writer.WriteBytes(&header, sizeof(BlobAssetHeader));
                writer.WriteBytes(blobAssets[i].header + 1, blobAssetLength);
                writer.WriteBytes(&zeroBytes, header.Length - blobAssetLength);
            }

            var tempChunk = (Chunk *)UnsafeUtility.Malloc(Chunk.kChunkSize, 16, Allocator.Temp);

            for (int archetypeIndex = 0; archetypeIndex < archetypeArray.Length; ++archetypeIndex)
            {
                var archetype = archetypeArray[archetypeIndex].Archetype;
                for (var ci = 0; ci < archetype->Chunks.Count; ++ci)
                {
                    var chunk = archetype->Chunks.p[ci];
                    bufferPatches.Clear();

                    UnsafeUtility.MemCpy(tempChunk, chunk, Chunk.kChunkSize);
                    tempChunk->metaChunkEntity = EntityRemapUtility.RemapEntity(ref entityRemapInfos, tempChunk->metaChunkEntity);

                    // Prevent patching from touching buffers allocated memory
                    BufferHeader.PatchAfterCloningChunk(tempChunk);

                    byte *tempChunkBuffer = tempChunk->Buffer;
                    EntityRemapUtility.PatchEntities(archetype->ScalarEntityPatches, archetype->ScalarEntityPatchCount, archetype->BufferEntityPatches, archetype->BufferEntityPatchCount, tempChunkBuffer, tempChunk->Count, ref entityRemapInfos);
                    if (archetype->ContainsBlobAssetRefs)
                    {
                        PatchBlobAssetsInChunkBeforeSave(tempChunk, chunk, blobAssetOffsets, blobAssetRefs);
                    }

                    FillPatchRecordsForChunk(chunk, bufferPatches);

                    ClearChunkHeaderComponents(tempChunk);
                    ChunkDataUtility.MemsetUnusedChunkData(tempChunk, 0);
                    tempChunk->Archetype = (Archetype *)archetypeIndex;

                    if (archetype->NumManagedArrays != 0)
                    {
                        throw new ArgumentException("Serialization of GameObject components is not supported for pure entity scenes");
                    }

                    writer.WriteBytes(tempChunk, Chunk.kChunkSize);

                    writer.Write(bufferPatches.Length);

                    if (bufferPatches.Length > 0)
                    {
                        writer.WriteList(bufferPatches);

                        // Write heap backed data for each required patch.
                        // TODO: PERF: Investigate static-only deserialization could manage one block and mark in pointers somehow that they are not indiviual
                        for (int i = 0; i < bufferPatches.Length; ++i)
                        {
                            var patch  = bufferPatches[i];
                            var header = (BufferHeader *)OffsetFromPointer(tempChunk->Buffer, patch.ChunkOffset);
                            writer.WriteBytes(header->Pointer, patch.AllocSizeBytes);
                            BufferHeader.Destroy(header);
                        }
                    }
                }
            }

            blobAssetRefs.Dispose();
            blobAssets.Dispose();

            bufferPatches.Dispose();
            UnsafeUtility.Free(tempChunk, Allocator.Temp);

            sharedComponentsToSerialize = new int[sharedComponentMapping.Count - 1];

            foreach (var i in sharedComponentMapping)
            {
                if (i.Key != 0)
                {
                    sharedComponentsToSerialize[i.Value - 1] = i.Key;
                }
            }
        }
            public void Execute(int index)
            {
                var chunk            = Chunks[index].m_Chunk;
                var archetype        = chunk->Archetype;
                var indexInTypeArray = ChunkDataUtility.GetIndexInTypeArray(archetype, TypeIndex);

                if (indexInTypeArray == -1) // Archetype doesn't match required component
                {
                    return;
                }

                var changesForChunk = GatheredChanges + index;

                if (ShadowChunksBySequenceNumber.TryGetValue(chunk->SequenceNumber, out var shadow))
                {
                    if (!ChangeVersionUtility.DidChange(chunk->GetChangeVersion(indexInTypeArray), shadow.ComponentVersion) &&
                        !ChangeVersionUtility.DidChange(chunk->GetChangeVersion(0), shadow.EntityVersion))
                    {
                        return;
                    }

                    if (!changesForChunk->AddedComponentEntities.IsCreated)
                    {
                        changesForChunk->AddedComponentEntities     = new UnsafeList(Allocator.TempJob);
                        changesForChunk->AddedComponentDataBuffer   = new UnsafeList(Allocator.TempJob);
                        changesForChunk->RemovedComponentEntities   = new UnsafeList(Allocator.TempJob);
                        changesForChunk->RemovedComponentDataBuffer = new UnsafeList(Allocator.TempJob);
                    }

                    var entityDataPtr    = chunk->Buffer + archetype->Offsets[0];
                    var componentDataPtr = chunk->Buffer + archetype->Offsets[indexInTypeArray];

                    var currentCount  = chunk->Count;
                    var previousCount = shadow.Count;

                    var i = 0;

                    for (; i < currentCount && i < previousCount; i++)
                    {
                        var currentComponentData  = componentDataPtr + ComponentSize * i;
                        var previousComponentData = shadow.ComponentDataBuffer + ComponentSize * i;

                        var entity         = *(Entity *)(entityDataPtr + sizeof(Entity) * i);
                        var previousEntity = *(Entity *)(shadow.EntityDataBuffer + sizeof(Entity) * i);

                        if (entity != previousEntity ||
                            UnsafeUtility.MemCmp(currentComponentData, previousComponentData, ComponentSize) != 0)
                        {
                            // CHANGED COMPONENT DATA!
                            OnRemovedComponent(changesForChunk, previousEntity, previousComponentData, ComponentSize);
                            OnNewComponent(changesForChunk, entity, currentComponentData, ComponentSize);
                        }
                    }

                    for (; i < currentCount; i++)
                    {
                        // NEW COMPONENT DATA!
                        var entity = *(Entity *)(entityDataPtr + sizeof(Entity) * i);
                        var currentComponentData = componentDataPtr + ComponentSize * i;
                        OnNewComponent(changesForChunk, entity, currentComponentData, ComponentSize);
                    }

                    for (; i < previousCount; i++)
                    {
                        // REMOVED COMPONENT DATA!
                        var entity = *(Entity *)(entityDataPtr + sizeof(Entity) * i);
                        var previousComponentData = shadow.ComponentDataBuffer + ComponentSize * i;
                        OnRemovedComponent(changesForChunk, entity, previousComponentData, ComponentSize);
                    }
                }
                else
                {
                    // This is a new chunk
                    var addedComponentDataBuffer = new UnsafeList(ComponentSize, 4, chunk->Count, Allocator.TempJob);
                    var addedComponentEntities   = new UnsafeList(sizeof(Entity), 4, chunk->Count, Allocator.TempJob);

                    var entityDataPtr    = chunk->Buffer + archetype->Offsets[0];
                    var componentDataPtr = chunk->Buffer + archetype->Offsets[indexInTypeArray];

                    addedComponentDataBuffer.AddRange <byte>(componentDataPtr, chunk->Count * ComponentSize);
                    addedComponentEntities.AddRange <Entity>(entityDataPtr, chunk->Count);

                    changesForChunk->AddedComponentDataBuffer = addedComponentDataBuffer;
                    changesForChunk->AddedComponentEntities   = addedComponentEntities;
                }
            }
            public void Execute(int index)
            {
                var chunk            = Chunks[index].m_Chunk;
                var archetype        = chunk->Archetype;
                var indexInTypeArray = ChunkDataUtility.GetIndexInTypeArray(archetype, TypeIndex);

                if (indexInTypeArray == -1) // Archetype doesn't match required component
                {
                    return;
                }

                var changesForChunk = GatheredChanges + index;

                if (ShadowChunksBySequenceNumber.TryGetValue(chunk->SequenceNumber, out var shadow))
                {
                    if (!ChangeVersionUtility.DidChange(chunk->GetChangeVersion(0), shadow.Version))
                    {
                        return;
                    }

                    if (!changesForChunk->AddedEntities.IsCreated)
                    {
                        changesForChunk->Chunk           = chunk;
                        changesForChunk->AddedEntities   = new UnsafeList(Allocator.TempJob);
                        changesForChunk->RemovedEntities = new UnsafeList(Allocator.TempJob);
                    }

                    var entityDataPtr = (Entity *)(chunk->Buffer + archetype->Offsets[0]);
                    var currentCount  = chunk->Count;
                    var previousCount = shadow.EntityCount;
                    var i             = 0;
                    for (; i < currentCount && i < previousCount; i++)
                    {
                        var currentEntity  = entityDataPtr[i];
                        var previousEntity = shadow.EntityDataBuffer[i];

                        if (currentEntity != previousEntity)
                        {
                            // CHANGED ENTITY!
                            changesForChunk->RemovedEntities.Add(previousEntity);
                            changesForChunk->AddedEntities.Add(currentEntity);
                        }
                    }

                    for (; i < currentCount; i++)
                    {
                        // NEW ENTITY!
                        changesForChunk->AddedEntities.Add(entityDataPtr[i]);
                    }

                    for (; i < previousCount; i++)
                    {
                        // REMOVED ENTITY!
                        changesForChunk->RemovedEntities.Add(shadow.EntityDataBuffer[i]);
                    }
                }
                else
                {
                    // This is a new chunk
                    var addedEntities = new UnsafeList(sizeof(Entity), 4, chunk->Count, Allocator.TempJob);
                    var entityDataPtr = chunk->Buffer + archetype->Offsets[0];
                    addedEntities.AddRange <Entity>(entityDataPtr, chunk->Count);
                    changesForChunk->Chunk         = chunk;
                    changesForChunk->AddedEntities = addedEntities;
                }
            }
        public void AreLayoutCompatibleSameArchetype()
        {
            var a = m_Manager.CreateArchetype();

            Assert.IsTrue(ChunkDataUtility.AreLayoutCompatible(a.Archetype, a.Archetype));
        }
            public void Execute()
            {
                var addedSharedComponentsCount   = 0;
                var removedSharedComponentsCount = 0;
                var removedEntityCurrentCount    = 0;
                var addedEntityCurrentCount      = 0;

                for (var i = 0; i < RemovedShadowChunks.Length; i++)
                {
                    var chunkSequenceNumber = RemovedShadowChunks[i];
                    var shadowChunk         = ShadowChunksBySequenceNumber[chunkSequenceNumber];

                    UnsafeUtility.MemCpy((Entity *)RemovedEntities.GetUnsafePtr() + removedEntityCurrentCount, shadowChunk.EntityDataBuffer, shadowChunk.EntityCount * sizeof(Entity));
                    UnsafeUtility.MemCpyReplicate((int *)RemovedEntitiesMappingToComponent.GetUnsafePtr() + removedEntityCurrentCount, &removedSharedComponentsCount, sizeof(int), shadowChunk.EntityCount);
                    removedEntityCurrentCount += shadowChunk.EntityCount;

                    IndicesInManagedComponentStore[removedSharedComponentsCount++] = SharedComponentValueIndexByChunk[chunkSequenceNumber];

                    ShadowChunksBySequenceNumber.Remove(chunkSequenceNumber);
                    SharedComponentValueIndexByChunk.Remove(chunkSequenceNumber);
                    UnsafeUtility.Free(shadowChunk.EntityDataBuffer, Allocator.Persistent);
                }

                for (var i = 0; i < GatheredChanges.Length; i++)
                {
                    var changes = GatheredChanges[i];
                    if (changes.RemovedEntities.Length == 0)
                    {
                        continue;
                    }

                    UnsafeUtility.MemCpy((Entity *)RemovedEntities.GetUnsafePtr() + removedEntityCurrentCount, changes.RemovedEntities.Ptr, changes.RemovedEntities.Length * sizeof(Entity));
                    UnsafeUtility.MemCpyReplicate((int *)RemovedEntitiesMappingToComponent.GetUnsafePtr() + removedEntityCurrentCount, &removedSharedComponentsCount, sizeof(int), changes.RemovedEntities.Length);
                    removedEntityCurrentCount += changes.RemovedEntities.Length;

                    IndicesInManagedComponentStore[removedSharedComponentsCount++] = SharedComponentValueIndexByChunk[changes.Chunk->SequenceNumber];
                }

                for (var i = 0; i < GatheredChanges.Length; i++)
                {
                    var changes = GatheredChanges[i];
                    if (changes.AddedEntities.Length == 0)
                    {
                        continue;
                    }

                    var chunkSequenceNumber = changes.Chunk->SequenceNumber;

                    if (changes.AddedEntities.Length > 0)
                    {
                        var archetype                 = changes.Chunk->Archetype;
                        var indexInTypeArray          = ChunkDataUtility.GetIndexInTypeArray(archetype, TypeIndex);
                        var sharedComponentValueArray = changes.Chunk->SharedComponentValues;
                        var sharedComponentOffset     = indexInTypeArray - archetype->FirstSharedComponent;
                        var sharedComponentDataIndex  = sharedComponentValueArray[sharedComponentOffset];

                        SharedComponentValueIndexByChunk[chunkSequenceNumber] = sharedComponentDataIndex;

                        UnsafeUtility.MemCpy((Entity *)AddedEntities.GetUnsafePtr() + addedEntityCurrentCount, changes.AddedEntities.Ptr, changes.AddedEntities.Length * sizeof(Entity));
                        var index = removedSharedComponentsCount + addedSharedComponentsCount;
                        UnsafeUtility.MemCpyReplicate((int *)AddedEntitiesMappingToComponent.GetUnsafePtr() + addedEntityCurrentCount, &index, sizeof(int), changes.AddedEntities.Length);
                        addedEntityCurrentCount += changes.AddedEntities.Length;

                        IndicesInManagedComponentStore[index] = sharedComponentDataIndex;
                        addedSharedComponentsCount++;
                    }
                }
            }
 public static unsafe void *GetComponentDataWithTypeRW(this ArchetypeChunk chunk, int chunkIndex, int typeIndex, uint globalSystemVersion)
 {
     chunk.AssertEntityHasComponent(typeIndex);
     return(ChunkDataUtility.GetComponentDataWithTypeRW(chunk.m_Chunk, chunkIndex, typeIndex, globalSystemVersion));
 }
 public static unsafe int GetIndexInTypeArray(this ArchetypeChunk chunk, int typeIndex)
 {
     return(ChunkDataUtility.GetIndexInTypeArray(chunk.m_Chunk->Archetype, typeIndex));
 }