using System; using System.Collections.Generic; using System.Reflection; using Unity.Profiling; namespace DCFApixels.DragonECS { public abstract class EcsQueryBase { internal EcsWorld source; internal EcsGroup groupFilter; internal EcsQueryMask mask; public EcsWorld World => source; #region Builder protected virtual void Init(Builder b) { } protected abstract void OnBuild(Builder b); public abstract void ExecuteWhere(); public sealed class Builder : EcsQueryBuilderBase { private EcsWorld _world; private List _inc; private List _exc; public EcsWorld World => _world; private Builder(EcsWorld world) { _world = world; _inc = new List(8); _exc = new List(4); } internal static TQuery Build(EcsWorld world) where TQuery : EcsQueryBase { Builder builder = new Builder(world); Type queryType = typeof(TQuery); ConstructorInfo constructorInfo = queryType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Builder) }, null); EcsQueryBase newQuery; if (constructorInfo != null) { newQuery = (EcsQueryBase)constructorInfo.Invoke(new object[] { builder }); } else { newQuery = (EcsQueryBase)Activator.CreateInstance(typeof(TQuery)); newQuery.Init(builder); } newQuery.groupFilter = EcsGroup.New(world); newQuery.source = world; newQuery.OnBuild(builder); builder.End(out newQuery.mask); return (TQuery)(object)newQuery; } public sealed override TPool Include() { _inc.Add(_world.GetComponentID()); return _world.GetPool(); } public sealed override TPool Exclude() { _exc.Add(_world.GetComponentID()); return _world.GetPool(); } public sealed override TPool Optional() { return _world.GetPool(); } private void End(out EcsQueryMask mask) { _inc.Sort(); _exc.Sort(); mask = new EcsQueryMask(_world.Archetype, _inc.ToArray(), _exc.ToArray()); _world = null; _inc = null; _exc = null; } } #endregion protected void ExecuteWhere(EcsReadonlyGroup group, EcsGroup result) { var pools = World.GetAllPools(); result.Clear(); foreach (var e in group) { for (int i = 0, iMax = mask.Inc.Length; i < iMax; i++) { if (!pools[mask.Inc[i]].Has(e)) goto next; } for (int i = 0, iMax = mask.Exc.Length; i < iMax; i++) { if (pools[mask.Exc[i]].Has(e)) goto next; } result.AggressiveAdd(e); next: continue; } result.Sort(); } protected void ExecuteWhereAndSort(EcsReadonlyGroup group, EcsGroup result) { ExecuteWhere(group, result); result.Sort(); } } public abstract class EcsQuery : EcsQueryBase { private ProfilerMarker _execute = new ProfilerMarker("EcsQuery.ExecuteWhere"); protected sealed override void OnBuild(Builder b) { } public sealed override void ExecuteWhere() { using (_execute.Auto()) { ExecuteWhereAndSort(World.Entities, groupFilter); } } public EcsGroup.Enumerator GetEnumerator() { return groupFilter.GetEnumerator(); } } public class EcsQueryMask : EcsComponentMask { public EcsQueryMask(Type worldArchetypeType, int[] inc, int[] exc) { WorldArchetype = worldArchetypeType; Inc = inc; Exc = exc; } } public abstract class EcsQueryBuilderBase { public abstract TPool Include() where TComponent : struct where TPool : EcsPoolBase, new(); public abstract TPool Exclude() where TComponent : struct where TPool : EcsPoolBase, new(); public abstract TPool Optional() where TComponent : struct where TPool : EcsPoolBase, new(); } }