/// <summary> /// Removes a set of components from a set of entities defined by a EntityQuery. /// </summary> /// <remarks> /// Removing a component changes an entity's archetype and results in the entity being moved to a different /// 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 defining the entities to modify.</param> /// <param name="types">The types of components to add.</param> public void RemoveComponent(EntityQuery entityQuery, ComponentTypes types) { if (entityQuery.CalculateEntityCount() == 0) { return; } // @TODO: Opportunity to do all components in batch on a per chunk basis. for (int i = 0; i != types.Length; i++) { RemoveComponent(entityQuery, types.GetComponentType(i)); } }
public static T[] ToComponentArray <T>(this EntityQuery group) where T : Component { int entityCount = group.CalculateEntityCount(); var arr = new T[entityCount]; var iterator = group.GetArchetypeChunkIterator(); var indexInEntityQuery = group.GetIndexInEntityQuery(TypeManager.GetTypeIndex <T>()); var entityCounter = 0; while (iterator.MoveNext()) { var chunk = iterator.CurrentArchetypeChunk; for (int entityIndex = 0; entityIndex < chunk.Count; ++entityIndex) { arr[entityCounter++] = (T)iterator.GetManagedObject(group.ManagedComponentStore, indexInEntityQuery, entityIndex); } } return(arr); }
public static T[] ToComponentArray <T>(this EntityQuery group) where T : Component { int length = group.CalculateEntityCount(); ComponentChunkIterator iterator = group.GetComponentChunkIterator(); var indexInComponentGroup = group.GetIndexInEntityQuery(TypeManager.GetTypeIndex <T>()); iterator.IndexInEntityQuery = indexInComponentGroup; var arr = new T[length]; var cache = default(ComponentChunkCache); for (int i = 0; i < length; ++i) { if (i < cache.CachedBeginIndex || i >= cache.CachedEndIndex) { iterator.MoveToEntityIndexAndUpdateCache(i, out cache, true); } arr[i] = (T)iterator.GetManagedObject(group.ManagedComponentStore, cache.CachedBeginIndex, i); } return(arr); }
/// <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
internal static void ApplyChangeSet( EntityManager entityManager, EntityQuery entityQuery, EntityQuery prefabQuery, EntityQuery linkedEntityGroupQuery, EntityChangeSet changeSet) { if (!changeSet.IsCreated) { return; } var entityCount = entityQuery.CalculateEntityCount(); using (var packedEntities = new NativeMultiHashMap <int, Entity>(entityCount, Allocator.TempJob)) using (var packedTypes = new NativeArray <ComponentType>(changeSet.TypeHashes.Length, Allocator.TempJob)) using (var entityGuidToEntity = new NativeMultiHashMap <EntityGuid, Entity>(entityCount, Allocator.TempJob)) using (var entityToEntityGuid = new NativeHashMap <Entity, EntityGuid>(entityQuery.CalculateEntityCount(), Allocator.TempJob)) { BuildEntityLookups( entityManager, entityQuery, entityGuidToEntity, entityToEntityGuid); BuildPackedLookups( changeSet, entityGuidToEntity, packedEntities, packedTypes); ApplyDestroyEntities( entityManager, changeSet, packedEntities, entityGuidToEntity); ApplyCreateEntities( entityManager, changeSet, packedEntities); #if UNITY_EDITOR ApplyEntityNames( entityManager, changeSet, packedEntities); #endif ApplyRemoveComponents( entityManager, changeSet.RemoveComponents, changeSet.Entities, packedEntities, packedTypes); ApplyAddComponents( entityManager, changeSet.AddComponents, changeSet.Entities, packedEntities, packedTypes); ApplySetSharedComponents( entityManager, changeSet.SetSharedComponents, changeSet.Entities, packedEntities, packedTypes); ApplySetComponents( entityManager, changeSet.SetComponents, changeSet.Payload, changeSet.Entities, packedEntities, packedTypes, entityGuidToEntity, entityToEntityGuid); var linkedEntityGroupEntitiesLength = CalculateLinkedEntityGroupEntitiesLength(entityManager, linkedEntityGroupQuery); using (var entityGuidToPrefab = new NativeHashMap <EntityGuid, Entity>(prefabQuery.CalculateEntityCount(), Allocator.TempJob)) using (var entityToLinkedEntityGroupRoot = new NativeHashMap <Entity, Entity>(linkedEntityGroupEntitiesLength, Allocator.TempJob)) { BuildPrefabAndLinkedEntityGroupLookups( entityManager, entityQuery, prefabQuery, linkedEntityGroupQuery, entityGuidToPrefab, entityToLinkedEntityGroupRoot); ApplyLinkedEntityGroupRemovals( entityManager, changeSet.LinkedEntityGroupRemovals, changeSet.Entities, packedEntities, entityGuidToEntity, entityToEntityGuid, entityToLinkedEntityGroupRoot); ApplyLinkedEntityGroupAdditions( entityManager, changeSet.LinkedEntityGroupAdditions, changeSet.Entities, packedEntities, entityGuidToEntity, entityToEntityGuid, entityGuidToPrefab, entityToLinkedEntityGroupRoot); ApplyEntityPatches( entityManager, changeSet.EntityPatches, changeSet.Entities, packedEntities, packedTypes, entityGuidToEntity, entityToEntityGuid, entityGuidToPrefab, entityToLinkedEntityGroupRoot); } } }
protected override void OnUpdate() { Entity cameraEntity = default; float3 cameraPosition = default; if (m_CameraQuery.CalculateEntityCount() > 0) { cameraEntity = m_CameraQuery.GetSingletonEntity(); var cameraObject = EntityManager.GetComponentObject <UnityEngine.Camera>(cameraEntity); cameraPosition = cameraObject.transform.position; } var player = this.GetFirstSelfGamePlayer(); if (!EntityManager.TryGetComponentData(player, out GameRhythmInputComponent playerCommand)) { Destroy(); return; } var cameraState = this.GetComputedCameraState(); var isWorldSpace = cameraState.StateData.Target != default; if (!EntityManager.HasComponent <UnitDescription>(cameraState.StateData.Target)) { isWorldSpace = false; } var canvasRect = m_Canvas.pixelRect; if (isWorldSpace && cameraEntity != default) { var translation = EntityManager.GetComponentData <Translation>(cameraState.StateData.Target); m_Canvas.renderMode = RenderMode.WorldSpace; m_Canvas.transform.position = new Vector3(translation.Value.x, translation.Value.y + 25 * 0.05f, cameraPosition.z + 10); m_Canvas.transform.localScale = Vector3.one * 0.05f; var rectTransform = m_Canvas.GetComponent <RectTransform>(); rectTransform.sizeDelta = new Vector2(100, 100); canvasRect.width = 90; canvasRect.height = 105; } else { m_Canvas.transform.position = Vector3.zero; m_Canvas.renderMode = RenderMode.ScreenSpaceCamera; m_Canvas.worldCamera = EntityManager.GetComponentObject <UnityEngine.Camera>(cameraEntity); } var pixelRange = new float2(canvasRect.width, canvasRect.height); Entity engine = default; if (cameraState.StateData.Target != default) { engine = PlayerComponentFinder.GetRelativeChild <RhythmEngineDescription>(EntityManager, m_EngineQuery, cameraState.StateData.Target, player); } else { engine = PlayerComponentFinder.FromQueryFindPlayerChild(m_EngineQuery, player); } if (engine == default) { Destroy(); return; } var process = EntityManager.GetComponentData <RhythmEngineLocalState>(engine); var settings = EntityManager.GetComponentData <RhythmEngineSettings>(engine); if (!EntityManager.HasComponent <RhythmEngineIsPlaying>(engine) || RhythmEngineUtility.GetFlowBeat(process.Elapsed, settings.BeatInterval) < 0) { Destroy(); return; } var key = 1; foreach (var ac in playerCommand.Actions) { if (!ac.InterFrame.HasBeenPressed(timeSystem.GetReport(player).Active)) { key++; continue; } var keyRange = new float2(); if (key <= 2) { if (key == 1) { keyRange.x = -0.35f; } else { keyRange.x = 0.35f; } keyRange.x += Random.Range(-0.025f, 0.025f); keyRange.y = Random.Range(-0.1f, 0.1f); } else { if (key == 3) { keyRange.y = -0.375f; } else { keyRange.y = 0.375f; } keyRange.y += Random.Range(-0.025f, 0.025f); keyRange.x = Random.Range(-0.1f, 0.1f); } keyRange += 0.5f; var width = pixelRange.x * 0.5f; var height = pixelRange.y * 0.5f; var keyPos = new float2(math.lerp(-width, width, keyRange.x), math.lerp(-height, height, keyRange.y)); var beGameObject = DrumBackendPools[key].Dequeue(); using (new SetTemporaryInjectionWorld(World)) { beGameObject.name = $"BackendPressure (Key: {key})"; beGameObject.SetActive(true); beGameObject.transform.SetParent(m_Canvas.transform, false); beGameObject.transform.localScale = m_Canvas.renderMode == RenderMode.WorldSpace ? Vector3.one * 0.7f : 0.008f * math.min(width, height) * Vector3.one; beGameObject.transform.localPosition = new Vector3(keyPos.x, keyPos.y, 0); beGameObject.transform.rotation = Quaternion.Euler(0, 0, Random.Range(-12.5f, 12.5f)); } var backend = beGameObject.GetComponent <UIDrumPressureBackend>(); backend.OnReset(); backend.SetTarget(EntityManager); backend.SetPresentationFromPool(DrumPresentationPools[key]); var prevRand = backend.rand; var absRealScore = math.abs(RhythmEngineUtility.GetScore(process.Elapsed, settings.BeatInterval)); backend.play = true; backend.key = key; backend.rand = DrumVariantCount[key]; backend.perfect = absRealScore <= FlowPressure.Perfect; backend.endTime = Time.ElapsedTime + 1; var i = 0; while (prevRand == DrumVariantCount[key] && i < 3) { DrumVariantCount[key] = Random.Range(0, 2); i++; } key++; } Entities.ForEach((UIDrumPressureBackend backend) => { var presentation = backend.Presentation; if (presentation != null) { if (backend.play) { var color = presentation.colors[backend.key - 1]; color.a = 1; foreach (var effectImage in presentation.effectImages) { effectImage.color = color; } presentation.drumImage.sprite = presentation.sprites[backend.key - 1]; backend.play = false; presentation.animator.SetBool(StrHashPerfect, backend.perfect); presentation.animator.SetInteger(StrHashKey, backend.key); presentation.animator.SetFloat(StrHashVariant, backend.rand); presentation.animator.SetTrigger(StrHashPlay); } presentation.animator.Update(Time.DeltaTime); } if (backend.endTime > Time.ElapsedTime) { return; } backend.Return(true, true); }).WithStructuralChanges().Run(); return; }