using System; using System.Collections; using System.Collections.Generic; using Svelto.DataStructures; using Svelto.ECS.Internal; using Svelto.ECS.Schedulers; using Svelto.Utilities; using Svelto.WeakEvents; #if EXPERIMENTAL using Svelto.ECS.Experimental; using Svelto.ECS.Experimental.Internal; #endif #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR using Svelto.ECS.Profiler; #endif namespace Svelto.ECS { public partial class EnginesRoot : IDisposable { /// /// Engines root contextualize your engines and entities. You don't need to limit yourself to one EngineRoot /// as multiple engines root could promote separation of scopes. The EntitySubmissionScheduler checks /// periodically if new entity must be submited to the database and the engines. It's an external /// dependencies to be indipendent by the running platform as the user can define it. /// The EntitySubmissionScheduler cannot hold an EnginesRoot reference, that's why /// it must receive a weak reference of the EnginesRoot callback. /// public EnginesRoot(EntitySubmissionScheduler entityViewScheduler) { _entityViewEngines = new Dictionary>(); _otherEngines = new FasterList(); _entityViewsDB = new Dictionary(); _metaEntityViewsDB = new Dictionary(); _groupEntityViewsDB = new Dictionary>(); _entityViewsDBdic = new Dictionary(); _entityViewsToAdd = new DoubleBufferedEntityViews>(); _metaEntityViewsToAdd = new DoubleBufferedEntityViews>(); _groupedEntityViewsToAdd = new DoubleBufferedEntityViews>>(); _engineEntityViewDB = new EngineEntityViewDB(_entityViewsDB, _entityViewsDBdic, _metaEntityViewsDB, _groupEntityViewsDB); _scheduler = entityViewScheduler; _scheduler.Schedule(new WeakAction(SubmitEntityViews)); #if EXPERIMENTAL _sharedStructEntityViewLists = new SharedStructEntityViewLists(); _sharedGroupedStructEntityViewLists = new SharedGroupedStructEntityViewsLists(); _structEntityViewEngineType = typeof(IStructEntityViewEngine<>); _groupedStructEntityViewsEngineType = typeof(IGroupedStructEntityViewsEngine<>); _implementedInterfaceTypes = new Dictionary(); #endif #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Engine Debugger"); debugEngineObject.gameObject.AddComponent(); #endif } public void AddEngine(IEngine engine) { #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR Profiler.EngineProfiler.AddEngine(engine); #endif var engineType = engine.GetType(); #if EXPERIMENTAL bool engineAdded; var implementedInterfaces = engineType.GetInterfaces(); CollectImplementedInterfaces(implementedInterfaces); engineAdded = CheckSpecialEngine(engine); #endif var viewEngine = engine as IHandleEntityViewEngine; if (viewEngine != null) CheckEntityViewsEngine(viewEngine, engineType); else _otherEngines.Add(engine); var queryableEntityViewEngine = engine as IQueryingEntityViewEngine; if (queryableEntityViewEngine != null) { queryableEntityViewEngine.entityViewsDB = _engineEntityViewDB; queryableEntityViewEngine.Ready(); } } #if EXPERIMENTAL void CollectImplementedInterfaces(Type[] implementedInterfaces) { _implementedInterfaceTypes.Clear(); var type = typeof(IHandleEntityViewEngine); for (int index = 0; index < implementedInterfaces.Length; index++) { var interfaceType = implementedInterfaces[index]; if (type.IsAssignableFrom(interfaceType) == false) continue; if (false == interfaceType.IsGenericTypeEx()) { continue; } var genericTypeDefinition = interfaceType.GetGenericTypeDefinition(); _implementedInterfaceTypes.Add(genericTypeDefinition, interfaceType.GetGenericArguments()); } } bool CheckSpecialEngine(IEngine engine) { if (_implementedInterfaceTypes.Count == 0) return false; bool engineAdded = false; if (_implementedInterfaceTypes.ContainsKey(_structEntityViewEngineType)) { ((IStructEntityViewEngine)engine).CreateStructEntityViews (_sharedStructEntityViewLists); } if (_implementedInterfaceTypes.ContainsKey(_groupedStructEntityViewsEngineType)) { ((IGroupedStructEntityViewsEngine)engine).CreateStructEntityViews (_sharedGroupedStructEntityViewLists); } return engineAdded; } #endif void CheckEntityViewsEngine(IEngine engine, Type engineType) { var baseType = engineType.GetBaseType(); if (baseType.IsGenericTypeEx()) { var genericArguments = baseType.GetGenericArguments(); AddEngine(engine as IHandleEntityViewEngine, genericArguments, _entityViewEngines); #if EXPERIMENTAL var activableEngine = engine as IHandleActivableEntityEngine; if (activableEngine != null) AddEngine(activableEngine, genericArguments, _activableViewEntitiesEngines); #endif return; } throw new Exception("Not Supported Engine"); } //The T parameter allows to pass datastructure sthat not necessarly are //defined with IEngine, but must be defined with IEngine implementations static void AddEngine(T engine, Type[] types, Dictionary> engines) where T:IEngine { for (int i = 0; i < types.Length; i++) { FasterList list; var type = types[i]; if (engines.TryGetValue(type, out list) == false) { list = new FasterList(); engines.Add(type, list); } list.Add(engine); } } readonly Dictionary> _entityViewEngines; readonly FasterList _otherEngines; readonly Dictionary _entityViewsDB; readonly Dictionary _metaEntityViewsDB; readonly Dictionary> _groupEntityViewsDB; readonly Dictionary _entityViewsDBdic; readonly DoubleBufferedEntityViews> _entityViewsToAdd; readonly DoubleBufferedEntityViews> _metaEntityViewsToAdd; readonly DoubleBufferedEntityViews>> _groupedEntityViewsToAdd; readonly EntitySubmissionScheduler _scheduler; #if EXPERIMENTAL readonly Type _structEntityViewEngineType; readonly Type _groupedStructEntityViewsEngineType; readonly SharedStructEntityViewLists _sharedStructEntityViewLists; readonly SharedGroupedStructEntityViewsLists _sharedGroupedStructEntityViewLists; readonly Dictionary _implementedInterfaceTypes; #endif readonly EngineEntityViewDB _engineEntityViewDB; class DoubleBufferedEntityViews where T : class, IDictionary, new() { readonly T _entityViewsToAddBufferA = new T(); readonly T _entityViewsToAddBufferB = new T(); internal DoubleBufferedEntityViews() { this.other = _entityViewsToAddBufferA; this.current = _entityViewsToAddBufferB; } internal T other; internal T current; internal void Swap() { var toSwap = other; other = current; current = toSwap; } } } }