public void AddMatchingArchetypes(EntityQueryDesc queryDesc, NativeList <EntityArchetype> foundArchetypes)
        {
            var anyCount  = queryDesc.Any.Length;
            var noneCount = queryDesc.None.Length;
            var allCount  = queryDesc.All.Length;

            fixed(ComponentType *any = queryDesc.Any)
            {
                fixed(ComponentType *none = queryDesc.None)
                {
                    fixed(ComponentType *all = queryDesc.All)
                    {
                        for (var i = EntityComponentStore->m_Archetypes.Count - 1; i >= 0; --i)
                        {
                            var archetype = EntityComponentStore->m_Archetypes.p[i];
                            if (archetype->EntityCount == 0)
                            {
                                continue;
                            }
                            if (!TestMatchingArchetypeAny(archetype, any, anyCount))
                            {
                                continue;
                            }
                            if (!TestMatchingArchetypeNone(archetype, none, noneCount))
                            {
                                continue;
                            }
                            if (!TestMatchingArchetypeAll(archetype, all, allCount))
                            {
                                continue;
                            }

                            var entityArchetype = new EntityArchetype {
                                Archetype = archetype
                            };
                            var found = foundArchetypes.Contains(entityArchetype);
                            if (!found)
                            {
                                foundArchetypes.Add(entityArchetype);
                            }
                        }
                    }
                }
            }
        }
        ArchetypeQuery *CreateQuery(ref UnsafeScratchAllocator unsafeScratchAllocator, ComponentType *requiredTypes, int count)
        {
            var allList  = new NativeList <ComponentType>(Allocator.Temp);
            var noneList = new NativeList <ComponentType>(Allocator.Temp);

            for (int i = 0; i != count; i++)
            {
                if (requiredTypes[i].AccessModeType == ComponentType.AccessMode.Exclude)
                {
                    noneList.Add(ComponentType.ReadOnly(requiredTypes[i].TypeIndex));
                }
                else
                {
                    allList.Add(requiredTypes[i]);
                }
            }

            // NativeList.ToArray requires GC Pinning, not supported in Tiny
            var allCount  = allList.Length;
            var noneCount = noneList.Length;
            var allTypes  = new ComponentType[allCount];
            var noneTypes = new ComponentType[noneCount];

            for (int i = 0; i < allCount; i++)
            {
                allTypes[i] = allList[i];
            }
            for (int i = 0; i < noneCount; i++)
            {
                noneTypes[i] = noneList[i];
            }

            var query = new EntityQueryDesc
            {
                All  = allTypes,
                None = noneTypes
            };

            allList.Dispose();
            noneList.Dispose();

            return(CreateQuery(ref unsafeScratchAllocator, new EntityQueryDesc[] { query }));
        }
Beispiel #3
0
        /// <summary>
        /// Generates a detailed change set between <see cref="srcEntityManager"/> and <see cref="dstEntityManager"/>.
        /// All entities to be considered must have the <see cref="EntityGuid"/> component with a unique value.
        /// The resulting <see cref="Entities.EntityChanges"/> must be disposed when no longer needed.
        /// </summary>
        /// <remarks>
        /// When using the <see cref="EntityManagerDifferOptions.FastForwardShadowWorld"/> the destination world must be a direct ancestor to
        /// the source world, and must only be updated using this call or similar methods. There should be no direct changes to destination world.
        /// </remarks>
        internal static EntityChanges GetChanges(
            EntityManager srcEntityManager,
            EntityManager dstEntityManager,
            EntityManagerDifferOptions options,
            EntityQueryDesc entityQueryDesc,
            BlobAssetCache blobAssetCache,
            Allocator allocator)
        {
#if ENABLE_PROFILER || UNITY_EDITOR
            s_GetChangesProfilerMarker.Begin();
#endif
            CheckEntityGuidComponent(entityQueryDesc);

            var changes = default(EntityChanges);

            if (options == EntityManagerDifferOptions.None)
            {
                return(changes);
            }

            srcEntityManager.CompleteAllJobs();
            dstEntityManager.CompleteAllJobs();

            var srcEntityQuery = srcEntityManager.CreateEntityQuery(entityQueryDesc);
            var dstEntityQuery = dstEntityManager.CreateEntityQuery(entityQueryDesc);

            // Gather a set of a chunks to consider for diffing in both the src and dst worlds.
            using (var srcChunks = srcEntityQuery.CreateArchetypeChunkArray(Allocator.TempJob, out var srcChunksJob))
                using (var dstChunks = dstEntityQuery.CreateArchetypeChunkArray(Allocator.TempJob, out var dstChunksJob))
                {
                    JobHandle clearMissingReferencesJob = default;

                    if (CheckOption(options, EntityManagerDifferOptions.ClearMissingReferences))
                    {
                        // Opt-in feature.
                        // This is a special user case for references to destroyed entities.
                        // If entity is destroyed, any references to that entity will remain set but become invalid (i.e. broken).
                        // This option ensures that references to non-existent entities will be explicitly set to Entity.Null which
                        // will force it to be picked up in the change set.
                        ClearMissingReferences(srcEntityManager, srcChunks, out clearMissingReferencesJob, srcChunksJob);
                    }

                    // @TODO NET_DOTS does not support JobHandle.CombineDependencies with 3 arguments.
#if NET_DOTS
                    var archetypeChunkChangesJobDependencies = CombineDependencies(srcChunksJob, dstChunksJob, clearMissingReferencesJob);
#else
                    var archetypeChunkChangesJobDependencies = JobHandle.CombineDependencies(srcChunksJob, dstChunksJob, clearMissingReferencesJob);
#endif

                    // Broad phased chunk comparison.
                    using (var archetypeChunkChanges = GetArchetypeChunkChanges(
                               srcChunks: srcChunks,
                               dstChunks: dstChunks,
                               allocator: Allocator.TempJob,
                               jobHandle: out var archetypeChunkChangesJob,
                               dependsOn: archetypeChunkChangesJobDependencies))
                    {
                        // Explicitly sync at this point to parallelize subsequent jobs by chunk.
                        archetypeChunkChangesJob.Complete();

                        // Gather a sorted set of entities based on which chunks have changes.
                        using (var srcEntities = GetSortedEntitiesInChunk(
                                   archetypeChunkChanges.CreatedSrcChunks, Allocator.TempJob,
                                   jobHandle: out var srcEntitiesJob))
                            using (var dstEntities = GetSortedEntitiesInChunk(
                                       archetypeChunkChanges.DestroyedDstChunks, Allocator.TempJob,
                                       jobHandle: out var dstEntitiesJob))
                                using (var srcBlobAssets = GetReferencedBlobAssets(
                                           srcChunks, Allocator.TempJob,
                                           jobHandle: out var srcBlobAssetsJob))
                                    using (var dstBlobAssets = blobAssetCache.BlobAssetBatch->ToNativeList(Allocator.TempJob))
                                    {
                                        var duplicateEntityGuids    = default(NativeList <DuplicateEntityGuid>);
                                        var forwardEntityChanges    = default(EntityInChunkChanges);
                                        var reverseEntityChanges    = default(EntityInChunkChanges);
                                        var forwardComponentChanges = default(ComponentChanges);
                                        var reverseComponentChanges = default(ComponentChanges);
                                        var forwardBlobAssetChanges = default(BlobAssetChanges);
                                        var reverseBlobAssetChanges = default(BlobAssetChanges);

                                        try
                                        {
                                            JobHandle getDuplicateEntityGuidsJob = default;
                                            JobHandle forwardChangesJob          = default;
                                            JobHandle reverseChangesJob          = default;

                                            if (CheckOption(options, EntityManagerDifferOptions.ValidateUniqueEntityGuid))
                                            {
                                                // Guid validation will happen incrementally and only consider changed entities in the source world.
                                                duplicateEntityGuids = GetDuplicateEntityGuids(
                                                    srcEntities, Allocator.TempJob,
                                                    jobHandle: out getDuplicateEntityGuidsJob,
                                                    dependsOn: srcEntitiesJob);
                                            }

                                            if (CheckOption(options, EntityManagerDifferOptions.IncludeForwardChangeSet))
                                            {
                                                forwardEntityChanges = GetEntityInChunkChanges(
                                                    srcEntityManager,
                                                    dstEntityManager,
                                                    srcEntities,
                                                    dstEntities,
                                                    Allocator.TempJob,
                                                    jobHandle: out var forwardEntityChangesJob,
                                                    dependsOn: JobHandle.CombineDependencies(srcEntitiesJob, dstEntitiesJob));

                                                forwardComponentChanges = GetComponentChanges(
                                                    forwardEntityChanges,
 public EntityManagerDiffer(EntityManager sourceEntityManager, Allocator allocator, EntityQueryDesc entityQueryDesc = null)
 {
     m_SourceEntityManager = sourceEntityManager ?? throw new ArgumentNullException(nameof(sourceEntityManager));
     m_EntityQueryDesc     = entityQueryDesc ?? EntityGuidQueryDesc;
     m_ShadowWorld         = new World(sourceEntityManager.World.Name + " (Shadow)");
     m_ShadowEntityManager = m_ShadowWorld.EntityManager;
     m_BlobAssetCache      = new BlobAssetCache(allocator);
 }
Beispiel #5
0
        public EntityManagerDiffer(EntityManager sourceEntityManager, Allocator allocator, EntityQueryDesc entityQueryDesc = null)
        {
            m_SourceEntityManager = sourceEntityManager;

            m_EntityQueryDesc     = entityQueryDesc ?? EntityGuidQueryDesc;
            m_ShadowWorld         = new World(sourceEntityManager.World.Name + " (Shadow)", sourceEntityManager.World.Flags | WorldFlags.Shadow);
            m_ShadowEntityManager = m_ShadowWorld.EntityManager;
            m_BlobAssetCache      = new BlobAssetCache(allocator);
        }