#if UNITY_ECS using System.Collections; using Svelto.Common; using Svelto.DataStructures; using Svelto.ECS.Native; using Svelto.ECS.Schedulers; using Unity.Entities; using Unity.Jobs; namespace Svelto.ECS.Extensions.Unity { /// /// Group of UECS/Svelto SystemBase engines that creates UECS entities. /// Svelto entities are submitted /// Svelto Add and remove callback are called /// OnUpdate of the systems are called /// finally the UECS command buffer is flushed /// Note: I cannot use Unity ComponentSystemGroups nor I can rely on the SystemBase Dependency field to /// solve external dependencies. External dependencies are tracked, but only linked to the UECS components operations /// With Dependency I cannot guarantee that an external container is used before previous jobs working on it are completed /// [DisableAutoCreation] public sealed class SveltoUECSEntitiesSubmissionGroup : SystemBase, IQueryingEntitiesEngine , IReactOnAddAndRemove , IReactOnSwap, ISveltoUECSSubmission { public SveltoUECSEntitiesSubmissionGroup(SimpleEntitiesSubmissionScheduler submissionScheduler) { _submissionScheduler = submissionScheduler; _engines = new FasterList(); _afterSubmissionEngines = new FasterList(); _beforeSubmissionEngines = new FasterList(); } protected override void OnCreate() { _ECBSystem = World.CreateSystem(); _entityQuery = GetEntityQuery(typeof(UpdateUECSEntityAfterSubmission)); } public EntitiesDB entitiesDB { get; set; } public void Ready() { } public void Add(ref UECSEntityComponent entityComponent, EGID egid) { } public void Remove(ref UECSEntityComponent entityComponent, EGID egid) { _ECB.DestroyEntity(entityComponent.uecsEntity); } public void MovedTo(ref UECSEntityComponent entityComponent, ExclusiveGroupStruct previousGroup, EGID egid) { _ECB.SetSharedComponent(entityComponent.uecsEntity, new UECSSveltoGroupID(egid.groupID)); } public void Add(SubmissionEngine engine) { Svelto.Console.LogDebug($"Add Engine {engine} to the UECS world {_ECBSystem.World.Name}"); _ECBSystem.World.AddSystem(engine); if (engine is IUpdateAfterSubmission afterSubmission) _afterSubmissionEngines.Add(afterSubmission); if (engine is IUpdateBeforeSubmission beforeSubmission) _beforeSubmissionEngines.Add(beforeSubmission); _engines.Add(engine); } public void SubmitEntities(JobHandle jobHandle) { if (_submissionScheduler.paused) return; using (var profiler = new PlatformProfiler("SveltoUECSEntitiesSubmissionGroup - PreSubmissionPhase")) { PreSubmissionPhase(ref jobHandle, profiler); //Submit Svelto Entities, calls Add/Remove/MoveTo that can be used by the IUECSSubmissionEngines using (profiler.Sample("Submit svelto entities")) { _submissionScheduler.SubmitEntities(); } AfterSubmissionPhase(profiler); } } public IEnumerator SubmitEntitiesAsync(JobHandle jobHandle, uint maxEntities) { if (_submissionScheduler.paused) yield break; using (var profiler = new PlatformProfiler("SveltoUECSEntitiesSubmissionGroup - PreSubmissionPhase")) { PreSubmissionPhase(ref jobHandle, profiler); var submitEntitiesAsync = _submissionScheduler.SubmitEntitiesAsync(maxEntities); //Submit Svelto Entities, calls Add/Remove/MoveTo that can be used by the IUECSSubmissionEngines while (true) { using (profiler.Sample("Submit svelto entities async")) { submitEntitiesAsync.MoveNext(); } if (submitEntitiesAsync.Current == true) { using (profiler.Yield()) yield return null; } else break; } AfterSubmissionPhase(profiler); } } void PreSubmissionPhase(ref JobHandle jobHandle, PlatformProfiler profiler) { JobHandle BeforeECBFlushEngines() { JobHandle jobHandle = default; //execute submission engines and complete jobs because of this I don't need to do _ECBSystem.AddJobHandleForProducer(Dependency); for (var index = 0; index < _beforeSubmissionEngines.count; index++) { ref var engine = ref _beforeSubmissionEngines[index]; using (profiler.Sample(engine.name)) { jobHandle = JobHandle.CombineDependencies(jobHandle, engine.BeforeSubmissionUpdate(jobHandle)); } } return jobHandle; } using (profiler.Sample("Complete All Pending Jobs")) { jobHandle.Complete(); } //prepare the entity command buffer to be used by the registered engines var entityCommandBuffer = _ECBSystem.CreateCommandBuffer(); foreach (var system in _engines) { system.ECB = entityCommandBuffer; } _ECB = entityCommandBuffer; RemovePreviousMarkingComponents(entityCommandBuffer); using (profiler.Sample("Before Submission Engines")) { BeforeECBFlushEngines().Complete(); } } void AfterSubmissionPhase(PlatformProfiler profiler) { JobHandle AfterECBFlushEngines() { JobHandle jobHandle = default; //execute submission engines and complete jobs because of this I don't need to do _ECBSystem.AddJobHandleForProducer(Dependency); for (var index = 0; index < _afterSubmissionEngines.count; index++) { ref var engine = ref _afterSubmissionEngines[index]; using (profiler.Sample(engine.name)) { jobHandle = JobHandle.CombineDependencies(jobHandle, engine.AfterSubmissionUpdate(jobHandle)); } } return jobHandle; } using (profiler.Sample("Flush Command Buffer")) { _ECBSystem.Update(); } ConvertPendingEntities().Complete(); using (profiler.Sample("After Submission Engines")) { AfterECBFlushEngines().Complete(); } } void RemovePreviousMarkingComponents(EntityCommandBuffer ECB) { ECB.RemoveComponentForEntityQuery(_entityQuery); } JobHandle ConvertPendingEntities() { if (_entityQuery.IsEmpty == false) { NativeEGIDMultiMapper mapper = entitiesDB.QueryNativeMappedEntities( entitiesDB.FindGroups(), Allocator.TempJob); Entities.ForEach((Entity id, ref UpdateUECSEntityAfterSubmission egidComponent) => { mapper.Entity(egidComponent.egid).uecsEntity = id; }).ScheduleParallel(); mapper.ScheduleDispose(Dependency); } return Dependency; } readonly SimpleEntitiesSubmissionScheduler _submissionScheduler; SubmissionEntitiesCommandBufferSystem _ECBSystem; readonly FasterList _engines; readonly FasterList _beforeSubmissionEngines; readonly FasterList _afterSubmissionEngines; [DisableAutoCreation] class SubmissionEntitiesCommandBufferSystem : EntityCommandBufferSystem { } protected override void OnUpdate() { } EntityQuery _entityQuery; EntityCommandBuffer _ECB; } public interface ISveltoUECSSubmission { void Add(SubmissionEngine engine); void SubmitEntities(JobHandle jobHandle); IEnumerator SubmitEntitiesAsync(JobHandle jobHandle, uint maxEntities); } } #endif