/// <summary>
        /// Moves a selection of the entities managed by the specified EntityManager to the <see cref="World"/> of this EntityManager
        /// and fills an array with their <see cref="Entity"/> objects.
        /// </summary>
        /// <remarks>
        /// After the move, the entities are managed by this EntityManager. Use the `output` array to make post-move
        /// changes to the transferred entities.
        ///
        /// Each world has one EntityManager, which manages all the entities in that world. This function
        /// allows you to transfer entities from one World to another.
        ///
        /// **Important:** This function creates a sync point, which means that the EntityManager waits for all
        /// currently running Jobs to complete before moving the entities and no additional Jobs can start before
        /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not
        /// be able to make use of the processing power of all available cores.
        /// </remarks>
        /// <param name="output">An array to receive the Entity objects of the transferred entities.</param>
        /// <param name="srcEntities">The EntityManager whose entities are appropriated.</param>
        /// <param name="filter">A EntityQuery that defines the entities to move. Must be part of the source
        /// World.</param>
        /// <param name="entityRemapping">A set of entity transformations to make during the transfer.</param>
        /// <exception cref="ArgumentException"></exception>
        public void MoveEntitiesFrom(out NativeArray <Entity> output, EntityManager srcEntities, EntityQuery filter,
                                     NativeArray <EntityRemapUtility.EntityRemapInfo> entityRemapping)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            if (filter.EntityComponentStore != srcEntities.EntityComponentStore)
            {
                throw new ArgumentException(
                          "EntityManager.MoveEntitiesFrom failed - srcEntities and filter must belong to the same World)");
            }
#endif
            using (var chunks = filter.CreateArchetypeChunkArray(Allocator.TempJob))
            {
                MoveEntitiesFrom(out output, srcEntities, chunks, entityRemapping);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Sets the shared component of all entities in the query.
        /// </summary>
        /// <remarks>
        /// The component data stays in the same chunk, the internal shared component data indices will be adjusted.
        ///
        /// **Important:** This function creates a sync point, which means that the EntityManager waits for all
        /// currently running Jobs to complete before setting the component and no additional Jobs can start before
        /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not
        /// be able to make use of the processing power of all available cores.
        /// </remarks>
        /// <param name="entity">The entity</param>
        /// <param name="componentData">A shared component object containing the values to set.</param>
        /// <typeparam name="T">The shared component type.</typeparam>
        public void SetSharedComponentData <T>(EntityQuery query, T componentData) where T : struct, ISharedComponentData
        {
            using (var chunks = query.CreateArchetypeChunkArray(Allocator.TempJob))
            {
                if (chunks.Length == 0)
                {
                    return;
                }

                BeforeStructuralChange();

                var type = ComponentType.ReadWrite <T>();
                RemoveComponent(chunks, type);

                int sharedComponentIndex = ManagedComponentStore.InsertSharedComponent(componentData);
                AddSharedComponentData(chunks, sharedComponentIndex, type);
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Removes a component from the chunks identified by a EntityQuery.
        /// </summary>
        /// <remarks>
        /// A chunk component is common to all entities in a chunk. You can access a chunk <see cref="IComponentData"/>
        /// instance through either the chunk itself or through an entity stored in that chunk.
        ///
        /// **Important:** This function creates a sync point, which means that the EntityManager waits for all
        /// currently running Jobs to complete before removing the component and no additional Jobs can start before
        /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not
        /// be able to make use of the processing power of all available cores.
        /// </remarks>
        /// <param name="entityQuery">The EntityQuery identifying the chunks to modify.</param>
        /// <typeparam name="T">The type of component to remove.</typeparam>
        public void RemoveChunkComponentData <T>(EntityQuery entityQuery)
        {
            using (var chunks = entityQuery.CreateArchetypeChunkArray(Allocator.TempJob))
            {
                if (chunks.Length == 0)
                {
                    return;
                }
                BeforeStructuralChange();
                var archetypeChanges = EntityComponentStore->BeginArchetypeChangeTracking();

                EntityManagerChangeArchetypeUtility.RemoveComponent(chunks, ComponentType.ChunkComponent <T>(),
                                                                    EntityComponentStore, ManagedComponentStore);

                var changedArchetypes = EntityComponentStore->EndArchetypeChangeTracking(archetypeChanges);
                EntityGroupManager.AddAdditionalArchetypes(changedArchetypes);
            }
        }
Ejemplo n.º 4
0
        internal static void CopyAndReplaceChunks(
            EntityManager srcEntityManager,
            EntityManager dstEntityManager,
            EntityQuery dstEntityQuery,
            ArchetypeChunkChanges archetypeChunkChanges)
        {
            s_CopyAndReplaceChunksProfilerMarker.Begin();
            var dstAccess = dstEntityManager.GetCheckedEntityDataAccess();
            var srcAccess = srcEntityManager.GetCheckedEntityDataAccess();

            var archetypeChanges = dstAccess->EntityComponentStore->BeginArchetypeChangeTracking();

            DestroyChunks(dstEntityManager, archetypeChunkChanges.DestroyedDstChunks.Chunks);
            CloneAndAddChunks(srcEntityManager, dstEntityManager, archetypeChunkChanges.CreatedSrcChunks.Chunks);

            dstAccess->EntityComponentStore->EndArchetypeChangeTracking(archetypeChanges, dstAccess->EntityQueryManager);
            srcAccess->EntityComponentStore->InvalidateChunkListCacheForChangedArchetypes();
            dstAccess->EntityComponentStore->InvalidateChunkListCacheForChangedArchetypes();

            //@TODO-opt: use a query that searches for all chunks that have chunk components on it
            //@TODO-opt: Move this into a job
            // Any chunk might have been recreated, so the ChunkHeader might be invalid
            using (var allDstChunks = dstEntityQuery.CreateArchetypeChunkArray(Allocator.TempJob))
            {
                foreach (var chunk in allDstChunks)
                {
                    var metaEntity = chunk.m_Chunk->metaChunkEntity;
                    if (metaEntity != Entity.Null)
                    {
                        if (dstEntityManager.Exists(metaEntity))
                        {
                            dstEntityManager.SetComponentData(metaEntity, new ChunkHeader {
                                ArchetypeChunk = chunk
                            });
                        }
                    }
                }
            }

            srcAccess->EntityComponentStore->IncrementGlobalSystemVersion();
            dstAccess->EntityComponentStore->IncrementGlobalSystemVersion();
            s_CopyAndReplaceChunksProfilerMarker.End();
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Adds a shared component to a set of entities defined by a EntityQuery.
        /// </summary>
        /// <remarks>
        /// The fields of the `componentData` parameter are assigned to all of the added shared components.
        ///
        /// Adding a component to an entity changes its archetype and results in the entity being moved to a
        /// different chunk. The entity moves to a chunk with other entities that have the same shared component values.
        /// A new chunk is created if no chunk with the same archetype and shared component values currently exists.
        ///
        /// **Important:** This function creates a sync point, which means that the EntityManager waits for all
        /// currently running Jobs to complete before adding the component and no additional Jobs can start before
        /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not
        /// be able to make use of the processing power of all available cores.
        /// </remarks>
        /// <param name="entityQuery">The EntityQuery defining a set of entities to modify.</param>
        /// <param name="componentData">The data to set.</param>
        /// <typeparam name="T">The data type of the shared component.</typeparam>
        public void AddSharedComponentData <T>(EntityQuery entityQuery, T componentData)
            where T : struct, ISharedComponentData
        {
            var componentType = ComponentType.ReadWrite <T>();

            using (var chunks = entityQuery.CreateArchetypeChunkArray(Allocator.TempJob))
            {
                if (chunks.Length == 0)
                {
                    return;
                }
                BeforeStructuralChange();
                var newSharedComponentDataIndex = m_ManagedComponentStore.InsertSharedComponent(componentData);
                EntityComponentStore->AssertCanAddComponent(chunks, componentType);
                EntityManagerChangeArchetypeUtility.AddSharedComponent(chunks, componentType, newSharedComponentDataIndex,
                                                                       EntityComponentStore, ManagedComponentStore, EntityGroupManager);
                m_ManagedComponentStore.RemoveReference(newSharedComponentDataIndex);
            }
        }
Ejemplo n.º 6
0
        internal static unsafe JobHandle ScheduleInternal <T>(ref T jobData, EntityQuery query, JobHandle dependsOn, ScheduleMode mode)
            where T : struct, IJobChunk
        {
            using (var chunks = query.CreateArchetypeChunkArray(Allocator.Temp))
            {
                int currentChunk  = 0;
                int currentEntity = 0;
                foreach (var chunk in chunks)
                {
                    jobData.Execute(chunk, currentChunk, currentEntity);
                    currentChunk++;
                    currentEntity += chunk.Count;
                }
            }

            DoDeallocateOnJobCompletion(jobData);

            return(new JobHandle());
        }
        // ----------------------------------------------------------------------------------------------------------
        // INTERNAL
        // ----------------------------------------------------------------------------------------------------------

        void MoveEntitiesFromInternalQuery(EntityManager srcEntities, EntityQuery filter, NativeArray <EntityRemapUtility.EntityRemapInfo> entityRemapping)
        {
            var srcAccess  = srcEntities.GetCheckedEntityDataAccess();
            var selfAccess = GetCheckedEntityDataAccess();

#if ENABLE_UNITY_COLLECTIONS_CHECKS
            if (filter._GetImpl()->_Access != srcAccess)
            {
                throw new ArgumentException(
                          "EntityManager.MoveEntitiesFrom failed - srcEntities and filter must belong to the same World)");
            }

            if (srcEntities.m_EntityDataAccess == m_EntityDataAccess)
            {
                throw new ArgumentException("srcEntities must not be the same as this EntityManager.");
            }
#endif
            BeforeStructuralChange();
            srcEntities.BeforeStructuralChange();

            using (var chunks = filter.CreateArchetypeChunkArray(Allocator.TempJob))
            {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                for (int i = 0; i < chunks.Length; ++i)
                {
                    if (chunks[i].m_Chunk->Archetype->HasChunkHeader)
                    {
                        throw new ArgumentException("MoveEntitiesFrom can not move chunks that contain ChunkHeader components.");
                    }
                }
#endif

                var archetypeChanges = selfAccess->EntityComponentStore->BeginArchetypeChangeTracking();

                MoveChunksFromFiltered(chunks, entityRemapping, srcAccess->EntityComponentStore, srcAccess->ManagedComponentStore);

                selfAccess->EntityComponentStore->EndArchetypeChangeTracking(archetypeChanges, selfAccess->EntityQueryManager);
                selfAccess->EntityComponentStore->InvalidateChunkListCacheForChangedArchetypes();
                srcAccess->EntityComponentStore->InvalidateChunkListCacheForChangedArchetypes();
            }
        }
        public void SetSharedComponentData <T>(EntityQuery query, T componentData) where T : struct, ISharedComponentData
        {
            using (var chunks = query.CreateArchetypeChunkArray(Allocator.TempJob))
            {
                if (chunks.Length == 0)
                {
                    return;
                }

                var ecs = GetCheckedEntityDataAccess();

                ecs->BeforeStructuralChange();

                var type = ComponentType.ReadWrite <T>();
                ecs->RemoveComponent(chunks, type);

                int sharedComponentIndex = ecs->InsertSharedComponent(componentData);
                ecs->AddSharedComponentData(chunks, sharedComponentIndex, type);
                ecs->RemoveSharedComponentReference(sharedComponentIndex);
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Adds a component to each of the chunks identified by a EntityQuery and set the component values.
        /// </summary>
        /// <remarks>
        /// This function finds all chunks whose archetype satisfies the EntityQuery and adds the specified
        /// component to them.
        ///
        /// A chunk component is common to all entities in a chunk. You can access a chunk <see cref="IComponentData"/>
        /// instance through either the chunk itself or through an entity stored in that chunk.
        ///
        /// **Important:** This function creates a sync point, which means that the EntityManager waits for all
        /// currently running Jobs to complete before adding the component and no additional Jobs can start before
        /// the function is finished. A sync point can cause a drop in performance because the ECS framework may not
        /// be able to make use of the processing power of all available cores.
        /// </remarks>
        /// <param name="entityQuery">The EntityQuery identifying the chunks to modify.</param>
        /// <param name="componentData">The data to set.</param>
        /// <typeparam name="T">The type of component, which must implement IComponentData.</typeparam>
        public void AddChunkComponentData <T>(EntityQuery entityQuery, T componentData) where T : struct, IComponentData
        {
            using (var chunks = entityQuery.CreateArchetypeChunkArray(Allocator.TempJob))
            {
                if (chunks.Length == 0)
                {
                    return;
                }
                BeforeStructuralChange();
                EntityComponentStore->AssertCanAddChunkComponent(chunks, ComponentType.ChunkComponent <T>());

                var type      = ComponentType.ReadWrite <T>();
                var chunkType = ComponentType.FromTypeIndex(TypeManager.MakeChunkComponentTypeIndex(type.TypeIndex));

                using (var entityBatchList = m_EntityComponentStore->CreateEntityBatchList(chunks))
                {
                    EntityManagerChangeArchetypeUtility.AddComponent(entityBatchList, chunkType, 0,
                                                                     EntityComponentStore, ManagedComponentStore, EntityGroupManager);
                    m_EntityComponentStore->SetChunkComponent <T>(entityBatchList, componentData);
                }
            }
        }
Ejemplo n.º 10
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="EntityChanges"/> must be disposed when no longer needed.
        /// </summary>
        /// <remarks>
        /// For performance the <see cref="dstToSrcSequenceNumbers"/> is used to map chunks between the given worlds. If this is not provided, or is empty
        /// the tracker must evaluate all chunks, entities, and component data.
        ///
        /// 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 unsafe EntityChanges GetChanges(
            EntityManager srcEntityManager,
            EntityQuery srcEntityQuery,
            EntityManager dstEntityManager,
            EntityQuery dstEntityQuery,
            TypeInfoStream typeInfoStream,
            EntityManagerDifferOptions options,
            Allocator allocator)
        {
            var changes = new EntityChanges();

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

            if (options != EntityManagerDifferOptions.None)
            {
                var includeForwardChangeSet = (options & EntityManagerDifferOptions.IncludeForwardChangeSet) ==
                                              EntityManagerDifferOptions.IncludeForwardChangeSet;
                var includeReverseChangeSet = (options & EntityManagerDifferOptions.IncludeReverseChangeSet) ==
                                              EntityManagerDifferOptions.IncludeReverseChangeSet;
                var fastForwardShadowWorld = (options & EntityManagerDifferOptions.FastForwardShadowWorld) ==
                                             EntityManagerDifferOptions.FastForwardShadowWorld;
                var clearMissingReferences = (options & EntityManagerDifferOptions.ClearMissingReferences) ==
                                             EntityManagerDifferOptions.ClearMissingReferences;
                var validateUniqueEntityGuids = (options & EntityManagerDifferOptions.ValidateUniqueEntityGuid) ==
                                                EntityManagerDifferOptions.ValidateUniqueEntityGuid;

                // Query chunks that should be considered for change tracking.
                using (var srcChunks = srcEntityQuery.CreateArchetypeChunkArray(Allocator.TempJob))
                    using (var dstChunks = dstEntityQuery.CreateArchetypeChunkArray(Allocator.TempJob))
                    {
                        if (clearMissingReferences)
                        {
                            ArchetypeChunkChangeUtility.ClearMissingReferences(srcChunks,
                                                                               srcEntityManager.EntityComponentStore, srcEntityManager.GlobalSystemVersion,
                                                                               typeInfoStream);
                        }

                        // Compare the chunks and get a set of all changed chunks.
                        // @NOTE A modified chunk will appear as destroyed and then created.
                        using (var archetypeChunkChanges = ArchetypeChunkChangeUtility.GetArchetypeChunkChanges(srcChunks, dstChunks, Allocator.TempJob))
                        {
                            // If we have no chunk-level changes then there is no work to be done.
                            if (archetypeChunkChanges.HasChanges)
                            {
                                if (includeForwardChangeSet || includeReverseChangeSet)
                                {
                                    BuildComponentDataToEntityLookupTask <EntityGuid> buildSrcEntityGuidToEntityLookupTask =
                                        default;

                                    try
                                    {
                                        using (var buildSrcEntitiesTask =
                                                   new BuildEntityInChunkWithComponentTask <EntityGuid>(
                                                       archetypeChunkChanges.CreatedSrcChunks, Allocator.TempJob))
                                            using (var buildDstEntitiesTask =
                                                       new BuildEntityInChunkWithComponentTask <EntityGuid>(
                                                           archetypeChunkChanges.DestroyedDstChunks, Allocator.TempJob))
                                            {
                                                var handle = JobHandle.CombineDependencies(buildSrcEntitiesTask.Schedule(),
                                                                                           buildDstEntitiesTask.Schedule());

                                                if (validateUniqueEntityGuids)
                                                {
                                                    // Validation is expensive since we must run over the entire world. This is opt in.
                                                    buildSrcEntityGuidToEntityLookupTask =
                                                        new BuildComponentDataToEntityLookupTask <EntityGuid>(
                                                            srcEntityQuery.CalculateEntityCount(), Allocator.TempJob);
                                                    handle = JobHandle.CombineDependencies(handle,
                                                                                           buildSrcEntityGuidToEntityLookupTask.Schedule(srcChunks));
                                                }

                                                handle.Complete();

                                                if (validateUniqueEntityGuids &&
                                                    TryGetDuplicateComponents(
                                                        buildSrcEntityGuidToEntityLookupTask.GetComponentDataToEntityMap(),
                                                        out var duplicates))
                                                {
                                                    throw new DuplicateEntityGuidException(message:
                                                                                           $"Found {duplicates.Length} {nameof(EntityGuid)} components that are shared by more than one Entity, " +
                                                                                           $"see the {nameof(DuplicateEntityGuidException.DuplicateEntityGuids)} property for more information.")
                                                          {
                                                              DuplicateEntityGuids = duplicates
                                                          };
                                                }

                                                var srcState = new WorldState(
                                                    srcEntityManager,
                                                    buildSrcEntitiesTask.GetEntities()
                                                    );

                                                var dstState = new WorldState(
                                                    dstEntityManager,
                                                    buildDstEntitiesTask.GetEntities()
                                                    );

                                                BuildChangeSetTask buildForwardChangeSetTask = default;
                                                BuildChangeSetTask buildReverseChangeSetTask = default;

                                                try
                                                {
                                                    JobHandle buildForwardChangeSetJob = default;
                                                    JobHandle buildReverseChangeSetJob = default;

                                                    if (includeForwardChangeSet)
                                                    {
                                                        buildForwardChangeSetTask = new BuildChangeSetTask(dstState, srcState,
                                                                                                           typeInfoStream, Allocator.TempJob);
                                                        buildForwardChangeSetJob = buildForwardChangeSetTask.Schedule();
                                                    }

                                                    if (includeReverseChangeSet)
                                                    {
                                                        buildReverseChangeSetTask = new BuildChangeSetTask(srcState, dstState,
                                                                                                           typeInfoStream, Allocator.TempJob);
                                                        buildReverseChangeSetJob = buildReverseChangeSetTask.Schedule();
                                                    }

                                                    JobHandle.CombineDependencies(buildForwardChangeSetJob,
                                                                                  buildReverseChangeSetJob).Complete();

                                                    changes = new EntityChanges(
                                                        includeForwardChangeSet
                                                    ? buildForwardChangeSetTask.GetChangeSet(allocator)
                                                    : default,
                                                        includeReverseChangeSet
                                                    ? buildReverseChangeSetTask.GetChangeSet(allocator)
                                                    : default