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);
 }
Example #2
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);
        }
Example #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,