#if UNITY_ECS
using System;
using Svelto.Common;
using Svelto.ECS.Schedulers;
using Unity.Entities;
using Unity.Jobs;
namespace Svelto.ECS.SveltoOnDOTS
{
///
/// This is a high level class to abstract the complexity of creating a Svelto ECS application that interacts
/// with DOTS ECS.
/// This is a JobifiedEngine and as such it expect to be ticked. Normally it must be executed in a
/// SortedEnginesGroup as step that happens after the Svelto jobified engines run.
///
/// The flow should be:
/// Svelto (GameLogic) Engines Run first
/// Then this Engine runs, which causes:
/// Jobs to be completed (it's a sync point)
/// Synchronizations engines to be executed (Svelto to DOTS ECS)
/// Submission of Entities to be executed
/// Svelto Add/Remove callbacks to be called
/// ISveltoOnDOTSStructuralEngine to be executed
/// DOTS ECS engines to be executed
/// Synchronizations engines to be executed (DOTS ECS To Svelto)
///
[Sequenced(nameof(JobifiedSveltoEngines.SveltoOnDOTS))]
public class SveltoOnDOTSEnginesGroup: IJobifiedEngine
{
public SveltoOnDOTSEnginesGroup(EnginesRoot enginesRoot)
{
DBC.ECS.Check.Require(
enginesRoot.scheduler is SimpleEntitiesSubmissionScheduler
, "The Engines root must use a EntitiesSubmissionScheduler scheduler implementation");
CreateUnityECSWorldForSvelto(enginesRoot.scheduler as SimpleEntitiesSubmissionScheduler, enginesRoot);
}
///
/// for the user to add pure DOTS ECS SystemBase/ISystem systems to the DOTS ECS world
///
public World world { get; private set; }
///
/// for the user to be able to explicitly submit entities. When SveltoOnDOTS is used, you must use this way, you cannot
/// submit entities directly from the EnginesRoot submission scheduler
///
public ISveltoOnDOTSSubmission submitter => _sveltoDotsEntitiesSubmissionGroup;
public JobHandle Execute(JobHandle inputDeps)
{
//this is a sync point, there won't be pending jobs after this
_sveltoDotsEntitiesSubmissionGroup.SubmitEntities(inputDeps);
//Mixed explicit job dependency and internal automatic ECS dependency system
//Write in to DOTS ECS entities so the DOTS ECS dependencies react on the components touched
var handle = _syncSveltoToDotsGroup.Execute(default);
//As long as pure DOTS ECS systems do not use external containers (like native arrays and so) the Unity
//automatic dependencies system will guarantee that there won't be race conditions
world.Update();
//this svelto group of DOTS ECS SystemBase systems
return _syncDotsToSveltoGroup.Execute(handle);
}
public string name => nameof(SveltoOnDOTSEnginesGroup);
public void AddSveltoToDOTSSyncEngine(SyncSveltoToDOTSEngine engine)
{
//it's a Svelto Engine/DOTS ECS SystemBase so it must be added in the DOTS ECS world AND svelto enginesRoot
#if UNITY_ECS_100
world.AddSystemManaged(engine);
#else
world.AddSystem(engine);
#endif
_enginesRoot.AddEngine(engine);
_syncSveltoToDotsGroup.Add(engine);
}
public void CreateDOTSToSveltoSyncEngine() where T:SyncSveltoToDOTSEngine, new()
{
//it's a Svelto Engine/DOTS ECS SystemBase so it must be added in the DOTS ECS world AND svelto enginesRoot
#if UNITY_ECS_100
T engine = world.GetOrCreateSystemManaged();
_enginesRoot.AddEngine(engine);
_syncSveltoToDotsGroup.Add(engine);
#else
throw new NotImplementedException();
#endif
}
public void AddDOTSToSveltoSyncEngine(SyncDOTSToSveltoEngine engine)
{
//it's a Svelto Engine/DOTS ECS SystemBase so it must be added in the DOTS ECS world AND svelto enginesRoot
#if UNITY_ECS_100
world.AddSystemManaged(engine);
#else
world.AddSystem(engine);
#endif
_enginesRoot.AddEngine(engine);
_syncDotsToSveltoGroup.Add(engine);
}
public void AddSveltoOnDOTSSubmissionEngine(ISveltoOnDOTSStructuralEngine submissionEngine)
{
_sveltoDotsEntitiesSubmissionGroup.Add(submissionEngine);
if (submissionEngine is IEngine enginesRootEngine)
_enginesRoot.AddEngine(enginesRootEngine);
}
public void Dispose()
{
world.Dispose();
}
void CreateUnityECSWorldForSvelto(SimpleEntitiesSubmissionScheduler scheduler, EnginesRoot enginesRoot)
{
world = new World("Svelto<>DOTS world");
var systems = DefaultWorldInitialization.GetAllSystems(WorldSystemFilterFlags.Default);
DefaultWorldInitialization.AddSystemsToRootLevelSystemGroups(world, systems);
World.DefaultGameObjectInjectionWorld = world;
//This is the DOTS ECS group that takes care of all the DOTS ECS systems that creates entities
//it also submits Svelto entities through the scheduler
var defaultSveltoOnDotsHandleLifeTimeEngine = new SveltoOnDOTSHandleLifeTimeEngine();
_sveltoDotsEntitiesSubmissionGroup = new SveltoOnDOTSEntitiesSubmissionGroup(scheduler);
enginesRoot.AddEngine(defaultSveltoOnDotsHandleLifeTimeEngine);
_sveltoDotsEntitiesSubmissionGroup.Add(defaultSveltoOnDotsHandleLifeTimeEngine);
enginesRoot.AddEngine(_sveltoDotsEntitiesSubmissionGroup);
#if UNITY_ECS_100
world.AddSystemManaged(_sveltoDotsEntitiesSubmissionGroup);
#else
world.AddSystem(_sveltoDotsEntitiesSubmissionGroup);
#endif
//This is the group that handles the DOTS ECS sync systems that copy the svelto entities values to DOTS ECS entities
_syncSveltoToDotsGroup = new SyncSveltoToDOTSGroup();
enginesRoot.AddEngine(_syncSveltoToDotsGroup);
//This is the group that handles the DOTS ECS sync systems that copy the DOTS ECS entities values to svelto entities
_syncDotsToSveltoGroup = new SyncDOTSToSveltoGroup();
enginesRoot.AddEngine(_syncDotsToSveltoGroup);
enginesRoot.AddEngine(this);
_enginesRoot = enginesRoot;
}
EnginesRoot _enginesRoot;
SveltoOnDOTSEntitiesSubmissionGroup _sveltoDotsEntitiesSubmissionGroup;
SyncSveltoToDOTSGroup _syncSveltoToDotsGroup;
SyncDOTSToSveltoGroup _syncDotsToSveltoGroup;
}
}
#endif