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 })); }
/// <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); }
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); }