diff --git a/src/Attributes.meta b/src/Attributes.meta new file mode 100644 index 0000000..ba94036 --- /dev/null +++ b/src/Attributes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 269d1f5d46517e14a8563d7f239fa559 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/Attributes/DebugColorAttribute.cs b/src/Attributes/DebugColorAttribute.cs new file mode 100644 index 0000000..80f32a4 --- /dev/null +++ b/src/Attributes/DebugColorAttribute.cs @@ -0,0 +1,78 @@ +using System; +using System.Runtime.InteropServices; + +namespace DCFApixels.DragonECS +{ + [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, Inherited = false, AllowMultiple = false)] + public sealed class DebugColorAttribute : Attribute + { + private ColorRecord color; + public byte r => color.r; + public byte g => color.g; + public byte b => color.b; + + public DebugColorAttribute(byte r, byte g, byte b) + { + color = new ColorRecord(r, g, b); + } + + public DebugColorAttribute(DebugColor color) + { + this.color = new ColorRecord((int)color); + } + + + [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 4)] + private readonly struct ColorRecord + { + [FieldOffset(0)] + public readonly int full; + [FieldOffset(3)] + public readonly byte r; + [FieldOffset(2)] + public readonly byte g; + [FieldOffset(1)] + public readonly byte b; + + public ColorRecord(byte r, byte g, byte b) : this() + { + this.r = r; + this.g = g; + this.b = b; + } + public ColorRecord(int full) : this() + { + this.full = full; + } + } + } + + public enum DebugColor + { + /// Red. RGB is (255, 0, 0) + Red = 255 << 8 * 3 + 000 << 8 * 2 + 000 << 8, + /// Green. RGB is (0, 255, 0) + Green = 000 << 8 * 3 + 255 << 8 * 2 + 000 << 8, + /// Blue. RGB is (0, 0, 255) + Blue = 000 << 8 * 3 + 000 << 8 * 2 + 255 << 8, + + /// Yellow. RGB is (255, 255, 0) + Yellow = 255 << 8 * 3 + 255 << 8 * 2 + 000 << 8, + /// Cyan. RGB is (0, 255, 255) + Cyan = 000 << 8 * 3 + 255 << 8 * 2 + 255 << 8, + /// Magenta. RGB is (255, 0, 255) + Magenta = 255 << 8 * 3 + 000 << 8 * 2 + 000 << 8, + + /// Yellow. RGB is (255, 127, 0) + Orange = (255 << 24) + (127 << 16) + (000 << 8), + + /// Grey/Gray. RGB is (127, 127, 127) + Gray = 127 << 8 * 3 + 127 << 8 * 2 + 127 << 8, + /// Grey/Gray. RGB is (127, 127, 127) + Grey = Gray, + /// White. RGB is (255, 255, 255) + White = -1, + /// Black. RGB is (0, 0, 0) + Black = 0, + } +} \ No newline at end of file diff --git a/src/EcsSession.cs.meta b/src/Attributes/DebugColorAttribute.cs.meta similarity index 83% rename from src/EcsSession.cs.meta rename to src/Attributes/DebugColorAttribute.cs.meta index 3bf7273..447044b 100644 --- a/src/EcsSession.cs.meta +++ b/src/Attributes/DebugColorAttribute.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 2ae31658c78bbf04cb755ac72be367dd +guid: 4b96ad0ff9cf7124d8539afccec8f1ae MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/src/Builtin/DefaultRunners.cs b/src/Builtin/DefaultRunners.cs index c7f3338..df7ba22 100644 --- a/src/Builtin/DefaultRunners.cs +++ b/src/Builtin/DefaultRunners.cs @@ -2,53 +2,49 @@ { public interface IEcsPreInitSystem : IEcsSystem { - public void PreInit(EcsSession session); + public void PreInit(EcsSystems systems); } public interface IEcsInitSystem : IEcsSystem { - public void Init(EcsSession session); + public void Init(EcsSystems systems); } public interface IEcsRunSystem : IEcsSystem { - public void Run(EcsSession session); + public void Run(EcsSystems systems); } public interface IEcsDestroySystem : IEcsSystem { - public void Destroy(EcsSession session); + public void Destroy(EcsSystems systems); } - public interface IEcsBaseSystem : - IEcsInitSystem, - IEcsRunSystem, - IEcsDestroySystem - { } + public interface IEcsBaseSystem : IEcsInitSystem, IEcsRunSystem, IEcsDestroySystem { } public sealed class EcsPreInitRunner : EcsRunner, IEcsPreInitSystem { - void IEcsPreInitSystem.PreInit(EcsSession session) + void IEcsPreInitSystem.PreInit(EcsSystems systems) { - foreach (var item in targets) item.PreInit(session); + foreach (var item in targets) item.PreInit(systems); } } public sealed class EcsInitRunner : EcsRunner, IEcsInitSystem { - void IEcsInitSystem.Init(EcsSession session) + void IEcsInitSystem.Init(EcsSystems systems) { - foreach (var item in targets) item.Init(session); + foreach (var item in targets) item.Init(systems); } } public sealed class EcsRunRunner : EcsRunner, IEcsRunSystem { - void IEcsRunSystem.Run(EcsSession session) + void IEcsRunSystem.Run(EcsSystems systems) { - foreach (var item in targets) item.Run(session); + foreach (var item in targets) item.Run(systems); } } public sealed class EcsDestroyRunner : EcsRunner, IEcsDestroySystem { - void IEcsDestroySystem.Destroy(EcsSession session) + void IEcsDestroySystem.Destroy(EcsSystems systems) { - foreach (var item in targets) item.Destroy(session); + foreach (var item in targets) item.Destroy(systems); } } } diff --git a/src/Builtin/InjectSystem.cs b/src/Builtin/InjectSystem.cs index 89af8b8..55e0a0d 100644 --- a/src/Builtin/InjectSystem.cs +++ b/src/Builtin/InjectSystem.cs @@ -4,6 +4,7 @@ { public void Inject(T obj); } + [DebugColor(DebugColor.Gray)] public sealed class InjectRunner : EcsRunner>, IEcsInject { void IEcsInject.Inject(T obj) @@ -15,6 +16,7 @@ } } + [DebugColor(DebugColor.Gray)] public class InjectSystem : IEcsPreInitSystem { private T _injectedData; @@ -24,37 +26,38 @@ _injectedData = injectedData; } - public void PreInit(EcsSession session) + public void PreInit(EcsSystems systems) { - var injector = session.GetRunner>(); + var injector = systems.GetRunner>(); injector.Inject(_injectedData); } } public static class InjectSystemExstensions { - public static EcsSession Inject(this EcsSession self, T data) + public static EcsSystems.Builder Inject(this EcsSystems.Builder self, T data) { self.Add(new InjectSystem(data)); return self; } - - public static EcsSession Inject(this EcsSession self, A dataA, B dataB) + public static EcsSystems.Builder Inject(this EcsSystems.Builder self, A a, B b) { - self.Inject(dataA).Inject(dataB); + self.Inject(a).Inject(b); return self; } - - public static EcsSession Inject(this EcsSession self, A dataA, B dataB, C dataC, D dataD) + public static EcsSystems.Builder Inject(this EcsSystems.Builder self, A a, B b, C c, D d) { - self.Inject(dataA).Inject(dataB).Inject(dataC).Inject(dataD); + self.Inject(a).Inject(b).Inject(c).Inject(d); return self; } - - public static EcsSession Inject(this EcsSession self, - A dataA, B dataB, C dataC, D dataD, E dataE) + public static EcsSystems.Builder Inject(this EcsSystems.Builder self, A a, B b, C c, D d, E e) { - self.Inject(dataA).Inject(dataB).Inject(dataC).Inject(dataD).Inject(dataE); + self.Inject(a).Inject(b).Inject(c).Inject(d).Inject(e); + return self; + } + public static EcsSystems.Builder Inject(this EcsSystems.Builder self, A a, B b, C c, D d, E e, F f) + { + self.Inject(a).Inject(b).Inject(c).Inject(d).Inject(e).Inject(f); return self; } } diff --git a/src/Consts.cs b/src/Consts.cs new file mode 100644 index 0000000..aa47446 --- /dev/null +++ b/src/Consts.cs @@ -0,0 +1,8 @@ +namespace DCFApixels.DragonECS +{ + public class EcsConsts + { + public const string EXCEPTION_MESSAGE_PREFIX = "[DragonECS] "; + public const string DEBUG_PREFIX = "[DEBUG] "; + } +} diff --git a/src/Exceptions/Exceptions.cs.meta b/src/Consts.cs.meta similarity index 83% rename from src/Exceptions/Exceptions.cs.meta rename to src/Consts.cs.meta index 6870be6..80ddce6 100644 --- a/src/Exceptions/Exceptions.cs.meta +++ b/src/Consts.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: f04087406e09f6042a341cf8fc41fabf +guid: 3c30dd6d8ecfdbd4aaceccd22bfb85c4 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/src/EcsFilter.cs b/src/EcsFilter.cs index b9997c0..fc56b20 100644 --- a/src/EcsFilter.cs +++ b/src/EcsFilter.cs @@ -13,31 +13,193 @@ namespace DCFApixels.DragonECS #region Incs public interface IInc : IMaskCondition { } - public struct Inc : IInc { public int[] GetComponentsIDs() where TWorldArchetype : IWorldArchetype => Array.Empty(); } public struct Inc : IInc { - public int[] GetComponentsIDs() - where TWorldArchetype : IWorldArchetype + public int[] GetComponentsIDs() where TWorldArchetype : IWorldArchetype { return new int[] { - EcsWorld.ComponentType.uniqueID + EcsWorld.ComponentType.uniqueID, }; } } public struct Inc : IInc { - public int[] GetComponentsIDs() - where TWorldArchetype : IWorldArchetype + public int[] GetComponentsIDs() where TWorldArchetype : IWorldArchetype { return new int[] { EcsWorld.ComponentType.uniqueID, - EcsWorld.ComponentType.uniqueID + EcsWorld.ComponentType.uniqueID, + }; + } + } + public struct Inc : IInc + { + public int[] GetComponentsIDs() where TWorldArchetype : IWorldArchetype + { + return new int[] + { + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + }; + } + } + public struct Inc : IInc + { + public int[] GetComponentsIDs() where TWorldArchetype : IWorldArchetype + { + return new int[] + { + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + }; + } + } + public struct Inc : IInc + { + public int[] GetComponentsIDs() where TWorldArchetype : IWorldArchetype + { + return new int[] + { + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + }; + } + } + public struct Inc : IInc + { + public int[] GetComponentsIDs() where TWorldArchetype : IWorldArchetype + { + return new int[] + { + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + }; + } + } + public struct Inc : IInc + { + public int[] GetComponentsIDs() where TWorldArchetype : IWorldArchetype + { + return new int[] + { + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + }; + } + } + public struct Inc : IInc + { + public int[] GetComponentsIDs() where TWorldArchetype : IWorldArchetype + { + return new int[] + { + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + }; + } + } + public struct Inc : IInc + { + public int[] GetComponentsIDs() where TWorldArchetype : IWorldArchetype + { + return new int[] + { + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + }; + } + } + public struct Inc : IInc + { + public int[] GetComponentsIDs() where TWorldArchetype : IWorldArchetype + { + return new int[] + { + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + }; + } + } + public struct Inc : IInc + { + public int[] GetComponentsIDs() where TWorldArchetype : IWorldArchetype + { + return new int[] + { + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + }; + } + } + public struct Inc : IInc + { + public int[] GetComponentsIDs() where TWorldArchetype : IWorldArchetype + { + return new int[] + { + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, }; } } @@ -45,15 +207,13 @@ namespace DCFApixels.DragonECS #region Excs public interface IExc : IMaskCondition { } - public struct Exc : IExc { public int[] GetComponentsIDs() where TWorldArchetype : IWorldArchetype => Array.Empty(); } public struct Exc : IExc { - public int[] GetComponentsIDs() - where TWorldArchetype : IWorldArchetype + public int[] GetComponentsIDs() where TWorldArchetype : IWorldArchetype { return new int[] { @@ -63,13 +223,66 @@ namespace DCFApixels.DragonECS } public struct Exc : IExc { - public int[] GetComponentsIDs() - where TWorldArchetype : IWorldArchetype + public int[] GetComponentsIDs() where TWorldArchetype : IWorldArchetype { return new int[] { EcsWorld.ComponentType.uniqueID, - EcsWorld.ComponentType.uniqueID + EcsWorld.ComponentType.uniqueID, + }; + } + } + public struct Exc : IExc + { + public int[] GetComponentsIDs() where TWorldArchetype : IWorldArchetype + { + return new int[] + { + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + }; + } + } + public struct Exc : IExc + { + public int[] GetComponentsIDs() where TWorldArchetype : IWorldArchetype + { + return new int[] + { + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + }; + } + } + public struct Exc : IExc + { + public int[] GetComponentsIDs() where TWorldArchetype : IWorldArchetype + { + return new int[] + { + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + }; + } + } + public struct Exc : IExc + { + public int[] GetComponentsIDs() where TWorldArchetype : IWorldArchetype + { + return new int[] + { + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, + EcsWorld.ComponentType.uniqueID, }; } } @@ -238,19 +451,4 @@ namespace DCFApixels.DragonECS #endregion } #endregion - - #region Utils - internal static class ArrayExt - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static T[] Sort(this T[] self) - { - Array.Sort(self); - - return self; - } - - - } - #endregion } diff --git a/src/EcsGroup.cs b/src/EcsGroup.cs index 5a40e05..563d47c 100644 --- a/src/EcsGroup.cs +++ b/src/EcsGroup.cs @@ -31,7 +31,7 @@ namespace DCFApixels.DragonECS #endregion #region Constrcutors - public EcsGroup(IEcsWorld world, int entitiesCapacity, int delayedOpsCapacity = 128) + public EcsGroup(IEcsWorld world, int entitiesCapacity, int delayedOpsCapacity = 32) { _source = world; _entities = new SparseSet(entitiesCapacity, entitiesCapacity); @@ -67,6 +67,11 @@ namespace DCFApixels.DragonECS } #endregion + #region Contains + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Contains(int entityID) => _entities.Contains(entityID); + #endregion + #region AddGroup/RemoveGroup public void AddGroup(IEcsReadonlyGroup group) { @@ -124,44 +129,28 @@ namespace DCFApixels.DragonECS private readonly EcsGroup _source; private readonly SparseSet _entities; private int _index; - private Entity _currentEntity; public Enumerator(EcsGroup group) { _source = group; _entities = group._entities; _index = -1; - _currentEntity = new Entity(group.World, -1); } - public Entity Current + public ent Current { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - _currentEntity.id = _entities[_index]; - return _currentEntity; - } + get { return _source.World.GetEntity(_entities[_index]); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() - { - return ++_index < _entities.Count; - } + public bool MoveNext() => ++_index < _entities.Count; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Dispose() - { - _source.Unlock(); - } + public void Dispose() => _source.Unlock(); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Reset() - { - _index = -1; - _currentEntity.id = -1; - } + public void Reset() => _index = -1; } private struct DelayedOp diff --git a/src/EcsPool.cs b/src/EcsPool.cs index 3964482..cb73ef7 100644 --- a/src/EcsPool.cs +++ b/src/EcsPool.cs @@ -1,7 +1,6 @@ using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; -using UnityEngine; using System; using System.Reflection; using System.Linq; diff --git a/src/EcsRunner.cs b/src/EcsRunner.cs index 0681f08..adeb10b 100644 --- a/src/EcsRunner.cs +++ b/src/EcsRunner.cs @@ -1,5 +1,8 @@ using System; +using System.Collections; using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq.Expressions; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; @@ -25,7 +28,12 @@ namespace DCFApixels.DragonECS } public interface IEcsSystem { } - public interface IEcsRunner { } + public interface IEcsRunner + { + public IList Targets { get; } + public object Filter { get; } + public bool IsHasFilter { get; } + } public static class IEcsProcessorExtensions @@ -36,10 +44,9 @@ namespace DCFApixels.DragonECS } } - internal static class EcsRunnerActivator { - private static Dictionary _runnerTypes; //interface guid/ Runner type pairs; + private static Dictionary _runnerHandlerTypes; //interface guid/Runner handler type pairs; static EcsRunnerActivator() { @@ -47,28 +54,28 @@ namespace DCFApixels.DragonECS Type runnerBaseType = typeof(EcsRunner<>); - List newRunnerTypes = new List(); - newRunnerTypes = Assembly.GetAssembly(runnerBaseType) + List runnerHandlerTypes = new List(); + runnerHandlerTypes = Assembly.GetAssembly(runnerBaseType) .GetTypes() .Where(type => type.BaseType != null && type.BaseType.IsGenericType && runnerBaseType == type.BaseType.GetGenericTypeDefinition()) .ToList(); -#if DEBUG - for (int i = 0; i < newRunnerTypes.Count; i++) +#if DEBUG || !DRAGONECS_NO_SANITIZE_CHECKS + for (int i = 0; i < runnerHandlerTypes.Count; i++) { - var e = CheckRunnerValide(newRunnerTypes[i]); + var e = CheckRunnerValide(runnerHandlerTypes[i]); if (e != null) { - newRunnerTypes.RemoveAt(i--); + runnerHandlerTypes.RemoveAt(i--); exceptions.Add(e); } } #endif - _runnerTypes = new Dictionary(); - foreach (var item in newRunnerTypes) + _runnerHandlerTypes = new Dictionary(); + foreach (var item in runnerHandlerTypes) { - Type intrf = item.GetInterfaces().Where(o => o != typeof(IEcsRunner) && o != typeof(IEcsSystem)).First(); //TODO оптимизировать это место - _runnerTypes.Add(intrf.GUID, item); + Type interfaceType = item.GetInterfaces().Where(o => o != typeof(IEcsRunner) && o != typeof(IEcsSystem)).First(); //TODO оптимизировать это место + _runnerHandlerTypes.Add(interfaceType.GUID, item); } if (exceptions.Count > 0) @@ -102,7 +109,7 @@ namespace DCFApixels.DragonECS } Guid interfaceGuid = nonGenericInterfaceType.GUID; - if (!_runnerTypes.TryGetValue(interfaceGuid, out Type runnerType)) + if (!_runnerHandlerTypes.TryGetValue(interfaceGuid, out Type runnerType)) { throw new Exception(); } @@ -111,16 +118,17 @@ namespace DCFApixels.DragonECS Type[] genericTypes = interfaceType.GetGenericArguments(); runnerType = runnerType.MakeGenericType(genericTypes); } - EcsRunner.Init(runnerType); + EcsRunner.Register(runnerType); } } public abstract class EcsRunner : IEcsSystem, IEcsRunner where TInterface : IEcsSystem { - internal static void Init(Type subclass) + #region Register + private static Type _subclass; + internal static void Register(Type subclass) { - #if DEBUG || !DRAGONECS_NO_SANITIZE_CHECKS if (_subclass != null) { @@ -141,8 +149,14 @@ namespace DCFApixels.DragonECS #endif _subclass = subclass; } + #endregion - public static TInterface Instantiate(IEnumerable targets, object filter) + #region FilterSystems + private static TInterface[] FilterSystems(IEnumerable targets) + { + return targets.Where(o => o is TInterface).Select(o => (TInterface)o).ToArray(); + } + private static TInterface[] FilterSystems(IEnumerable targets, object filter) { Type interfaceType = typeof(TInterface); @@ -166,32 +180,52 @@ namespace DCFApixels.DragonECS return atr == null || atr.interfaceType == interfaceType && atr.filter == null; }); } + return newTargets.Select(o => (TInterface)o).ToArray(); + } + #endregion - return Instantiate(newTargets.Select(o => (TInterface)o).ToArray()); - } - public static TInterface Instantiate(IEnumerable targets) - { - return Instantiate(targets.Where(o => o is TInterface).Select(o => (TInterface)o).ToArray()); - } - internal static TInterface Instantiate(TInterface[] targets) + #region Instantiate + private static TInterface Instantiate(TInterface[] targets, bool isHasFilter, object filter) { if (_subclass == null) EcsRunnerActivator.InitFor(); var instance = (EcsRunner)Activator.CreateInstance(_subclass); - return (TInterface)(IEcsSystem)instance.Set(targets); + return (TInterface)(IEcsSystem)instance.Set(targets, isHasFilter, filter); } - - private static Type _subclass; - - protected static void SetSublcass(Type type) => _subclass = type; + public static TInterface Instantiate(IEnumerable targets) + { + return Instantiate(FilterSystems(targets), false, null); + } + public static TInterface Instantiate(IEnumerable targets, object filter) + { + return Instantiate(FilterSystems(targets, filter), true, filter); + } + #endregion protected TInterface[] targets; + private ReadOnlyCollection _targetsSealed; + private object _filter; + private bool _isHasFilter; - private EcsRunner Set(TInterface[] targets) + public IList Targets => _targetsSealed; + public object Filter => _filter; + public bool IsHasFilter => _isHasFilter; + private EcsRunner Set(TInterface[] targets, bool isHasFilter, object filter) { this.targets = targets; + _targetsSealed = new ReadOnlyCollection(targets); + _filter = filter; + _isHasFilter = isHasFilter; return this; } + + internal void Rebuild(IEnumerable targets) + { + if(_isHasFilter) + Set(FilterSystems(targets), _isHasFilter, _filter); + else + Set(FilterSystems(targets, _filter), _isHasFilter, _filter); + } } } diff --git a/src/EcsSession.cs b/src/EcsSession.cs deleted file mode 100644 index 5b63fff..0000000 --- a/src/EcsSession.cs +++ /dev/null @@ -1,160 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Runtime.CompilerServices; - -namespace DCFApixels.DragonECS -{ - public class EcsWorldMap - { - private Dictionary<(Type, string), IEcsWorld> _worlds = new Dictionary<(Type, string), IEcsWorld>(8); - private bool _built = false; - - public void Add(EcsWorld world, string name = "") - where TArchetype : IWorldArchetype - { - if(_built) { throw new Exception($"Cant change built {nameof(EcsWorldMap)}"); } - _worlds.Add((typeof(TArchetype), name), world); - } - - public EcsWorld Get(string name ="") - where TArchetype : IWorldArchetype - { - return (EcsWorld)_worlds[(typeof(TArchetype), name)]; - } - - public IEcsWorld Get(Type type, string name = "") - { - return _worlds[(type, name)]; - } - - public void Build() - { - _built = true; - } - } - - public class EcsSession - { - private int _id; - - - private readonly List _allSystems; - private ReadOnlyCollection _allSystemsSealed; - - private bool _isInit = false; - private bool _isDestoryed = false; - - - private readonly Dictionary _runners; - private IEcsRunSystem _runRunnerCache; - - private readonly EcsWorldMap _worldMap; - - #region Properties - public ReadOnlyCollection AllProcessors => _allSystemsSealed; - - #endregion - - public EcsSession() - { - _allSystems = new List(128); - _runners = new Dictionary(); - _worldMap = new EcsWorldMap(); - } - - #region Runners - public T GetRunner() where T : IEcsSystem - { - Type type = typeof(T); - if (_runners.TryGetValue(type, out IEcsRunner result)) - { - return (T)result; - } - result = (IEcsRunner)EcsRunner.Instantiate(_allSystems); - _runners.Add(type, result); - return (T)result; - } - #endregion - - #region Configuration - public EcsSession Add(IEcsSystem system) - { - CheckInitForMethod(nameof(AddWorld)); - _allSystems.Add(system); - return this; - } - public EcsSession AddWorld(EcsWorld world, string name = "") - where TArchetype : IWorldArchetype - { - CheckInitForMethod(nameof(AddWorld)); - _worldMap.Add(world, name); - return this; - } - #endregion - - #region LifeCycle - public EcsSession Init() - { - CheckInitForMethod(nameof(Init)); - _worldMap.Build(); - _allSystemsSealed = _allSystems.AsReadOnly(); - _isInit = true; - - GetRunner>().Inject(_worldMap); - - GetRunner().PreInit(this); - GetRunner().Init(this); - - _runRunnerCache = GetRunner(); - - return this; - } - public void Run() - { - CheckDestroyForMethod(nameof(Run)); - - _runRunnerCache.Run(this); - } - public void Destroy() - { - CheckDestroyForMethod(nameof(Destroy)); - _isDestoryed = true; - - GetRunner().Destroy(this); - } - #endregion - - #region StateChecks - private void CheckInitForMethod(string methodName) - { - if (_isInit) - throw new MethodAccessException($"Запрещено вызывать метод {methodName}, после инициализации {nameof(EcsSession)}"); - } - private void CheckDestroyForMethod(string methodName) - { - if (_isDestoryed) - throw new MethodAccessException($"Запрещено вызывать метод {methodName}, после уничтожения {nameof(EcsSession)}"); - } - #endregion - - #region EntityConvert - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Entity ToEntity(in ent target) - { - throw new NotImplementedException(); - // return new Entity(null, target.id); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ent ToEnt(in Entity target) - { - throw new NotImplementedException(); - // return new ent(target.id, target.world._gens[target.id], -1000); - } - #endregion - - #region Utils - #endregion - } -} diff --git a/src/EcsSystems.cs b/src/EcsSystems.cs new file mode 100644 index 0000000..3e56afd --- /dev/null +++ b/src/EcsSystems.cs @@ -0,0 +1,196 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Runtime.CompilerServices; + +namespace DCFApixels.DragonECS +{ + public sealed class EcsSystems + { + private IEcsSystem[] _allSystems; + private Dictionary _runners; + private IEcsRunSystem _runRunnerCache; + + private ReadOnlyCollection _allSystemsSealed; + private ReadOnlyDictionary _allRunnersSealed; + + private bool _isDestoryed; + + #region Properties + public ReadOnlyCollection AllSystems => _allSystemsSealed; + public ReadOnlyDictionary AllRunners => _allRunnersSealed; + public bool IsDestoryed => _isDestoryed; + #endregion + + #region Constructors + private EcsSystems(IEcsSystem[] systems) + { + _allSystems = systems; + _runners = new Dictionary(); + + _allSystemsSealed = new ReadOnlyCollection(_allSystems); + _allRunnersSealed = new ReadOnlyDictionary(_runners); + + _isDestoryed = false; + + GetRunner().PreInit(this); + GetRunner().Init(this); + + _runRunnerCache = GetRunner(); + } + #endregion + + #region Runners + public T GetRunner() where T : IEcsSystem + { + Type type = typeof(T); + if (_runners.TryGetValue(type, out IEcsRunner result)) + return (T)result; + result = (IEcsRunner)EcsRunner.Instantiate(_allSystems); + _runners.Add(type, result); + return (T)result; + } + #endregion + + #region LifeCycle + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Run() + { +#if DEBUG || !DRAGONECS_NO_SANITIZE_CHECKS + CheckAfterDestroyForMethod(nameof(Run)); +#endif + _runRunnerCache.Run(this); + } + public void Destroy() + { +#if DEBUG || !DRAGONECS_NO_SANITIZE_CHECKS + CheckAfterDestroyForMethod(nameof(Destroy)); +#endif + _isDestoryed = true; + GetRunner().Destroy(this); + } + #endregion + + #region StateChecks +#if DEBUG || !DRAGONECS_NO_SANITIZE_CHECKS + private void CheckAfterDestroyForMethod(string methodName) + { + if (_isDestoryed) + throw new MethodAccessException($"It is forbidden to call method {methodName}, after destroying {nameof(EcsSystems)}"); + } +#endif + #endregion + + #region Builder + public static Builder New() + { + return new Builder(); + } + public class Builder + { + private const int KEYS_CAPACITY = 4; + private readonly HashSet _declaredBlockKeys; + private readonly List _blockExecutionOrder; + private readonly Dictionary> _systems; + private readonly object _basicBlocKey; + private bool _isBasicBlockDeclared; + private bool _isOnlyBasicBlock; + public Builder() + { + _basicBlocKey = new object(); + _declaredBlockKeys = new HashSet(KEYS_CAPACITY); + _blockExecutionOrder = new List(KEYS_CAPACITY); + _systems = new Dictionary>(KEYS_CAPACITY); + _isBasicBlockDeclared = false; + _isOnlyBasicBlock = true; + } + + public Builder Add(IEcsSystem system, object blockKey = null) + { + if (blockKey == null) blockKey = _basicBlocKey; + List list; + if (!_systems.TryGetValue(blockKey, out list)) + { + list = new List(); + _systems.Add(blockKey, list); + } + list.Add(system); + return this; + } + + public Builder Add(IEcsModule module) + { + module.ImportSystems(this); + return this; + } + + public Builder BasicSystemsBlock() + { + _isBasicBlockDeclared = true; + _blockExecutionOrder.Add(_basicBlocKey); + return this; + } + public Builder SystemsBlock(object blockKey) + { + if (blockKey == null) + return BasicSystemsBlock(); + + _isOnlyBasicBlock = false; + _blockExecutionOrder.Add(blockKey); + return this; + } + + public EcsSystems Build() + { + if (_isOnlyBasicBlock) + { + return new EcsSystems(_systems[_basicBlocKey].ToArray()); + } + + if(_isBasicBlockDeclared == false) + _blockExecutionOrder.Insert(0, _basicBlocKey); + + List result = new List(32); + + List basicBlockList = _systems[_basicBlocKey]; + + foreach (var item in _systems) + { + if (!_blockExecutionOrder.Contains(item.Key)) + { + basicBlockList.AddRange(item.Value); + } + } + foreach (var item in _blockExecutionOrder) + { + result.AddRange(_systems[item]); + } + + return new EcsSystems(result.ToArray()); + } + } + #endregion + } + + public interface IEcsModule + { + public void ImportSystems(EcsSystems.Builder builder); + } + + public static class EcsSystemsExt + { + public static bool IsNullOrDestroyed(this EcsSystems self) + { + return self == null || self.IsDestoryed; + } + public static EcsSystems.Builder Add(this EcsSystems.Builder self, IEnumerable range, object blockKey = null) + { + foreach (var item in range) + { + self.Add(item, blockKey); + } + return self; + } + } +} diff --git a/src/EcsSystems.cs.meta b/src/EcsSystems.cs.meta new file mode 100644 index 0000000..8ca8d30 --- /dev/null +++ b/src/EcsSystems.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bb5d6e45240ecad428d33758c4cc4c49 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index cea3950..c51946d 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -21,9 +21,11 @@ namespace DCFApixels.DragonECS #region Methods public EcsPool GetPool() where T : struct; - public EcsFilter GetFilter() where TInc : struct, IInc; + public EcsFilter Filter() where TInc : struct, IInc; public EcsFilter GetFilter() where TInc : struct, IInc where TExc : struct, IExc; public ent NewEntity(); + public bool EntityIsAlive(int entityID, short gen); + public ent GetEntity(int entityID); public void DelEntity(int entityID); public void Destroy(); @@ -64,7 +66,7 @@ namespace DCFApixels.DragonECS private EcsGroup _entities; private short[] _gens; - private short[] _componentCounts; + //private short[] _componentCounts; //TODO private IEcsPool[] _pools; private EcsNullPool _nullPool; @@ -86,7 +88,8 @@ namespace DCFApixels.DragonECS _entityDispenser = new IntDispenser(); _nullPool = new EcsNullPool(this); _pools = new IEcsPool[512]; - Array.Fill(_pools, _nullPool); + FillArray(_pools, _nullPool); + //Array.Fill(_pools, _nullPool); //TODO Fix it _gens = new short[512]; _filters = new EcsFilter[64]; _entities = new EcsGroup(this, 512); @@ -104,7 +107,8 @@ namespace DCFApixels.DragonECS { int oldCapacity = _pools.Length; Array.Resize(ref _pools, ComponentType.Capacity); - Array.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length); + FillArray(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length); + //Array.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length); //TODO Fix it Array.Resize(ref _filtersByIncludedComponents, ComponentType.Capacity); Array.Resize(ref _filtersByExcludedComponents, ComponentType.Capacity); @@ -121,7 +125,7 @@ namespace DCFApixels.DragonECS #region GetFilter - public EcsFilter GetFilter() where TInc : struct, IInc => GetFilter(); + public EcsFilter Filter() where TInc : struct, IInc => GetFilter(); public EcsFilter GetFilter() where TInc : struct, IInc where TExc : struct, IExc { var mask = EcsMaskMap.GetMask(); @@ -277,19 +281,32 @@ namespace DCFApixels.DragonECS } #endregion - #region NewEntity/DelEntity + #region Entity public ent NewEntity() { - int entid = _entityDispenser.GetFree(); - _entities.Add(entid); - if (_gens.Length < entid) Array.Resize(ref _gens, _gens.Length << 1); - return new ent(entid, _gens[entid]++, id); + int entityID = _entityDispenser.GetFree(); + _entities.Add(entityID); + if (_gens.Length <= entityID) + Array.Resize(ref _gens, _gens.Length << 1); + return new ent(entityID, _gens[entityID]++, id); + } + public ent GetEntity(int entityID) + { + if (_entities.Contains(entityID) == false) + return ent.NULL; + + return new ent(entityID, _gens[entityID], id); } public void DelEntity(int entityID) { _entityDispenser.Release(entityID); _entities.Remove(entityID); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool EntityIsAlive(int entityID, short gen) + { + return _entities.Contains(entityID) && _gens[entityID] == gen; + } #endregion #region Destroy @@ -329,6 +346,22 @@ namespace DCFApixels.DragonECS ComponentType.types[uniqueID] = typeof(T); } } + + private void FillArray(T[] array, T value, int startIndex = 0, int length = -1) + { + if (length < 0) + { + length = array.Length; + } + else + { + length = startIndex + length; + } + for (int i = startIndex; i < length; i++) + { + array[i] = value; + } + } #endregion } } diff --git a/src/Entity.cs b/src/Entity.cs index 7cc6ded..5630641 100644 --- a/src/Entity.cs +++ b/src/Entity.cs @@ -5,52 +5,34 @@ using System.Runtime.InteropServices; namespace DCFApixels.DragonECS { - [StructLayout(LayoutKind.Sequential, Pack = 0, Size = 8)] + // id - 32 bits + // gen - 16 bits + // world - 16 bits + [StructLayout(LayoutKind.Explicit, Pack = 2, Size = 8)] public readonly struct ent : IEquatable, IEquatable { public static readonly ent NULL = default; - // id - 32 bits - // gen - 16 bits - // world - 16 bits - public readonly long _full; - - #region Properties - [EditorBrowsable(EditorBrowsableState.Never)] - public int id - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => (int)(_full >> 32); - } - [EditorBrowsable(EditorBrowsableState.Never)] - public ushort gen - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => (ushort)((_full << 32) >> 48); - - } - [EditorBrowsable(EditorBrowsableState.Never)] - public short world - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => (short)((_full << 48) >> 48); - - } - #endregion + [FieldOffset(0)] + private readonly long _full; + [FieldOffset(3)] + public readonly int id; + [FieldOffset(1)] + public readonly short gen; + [FieldOffset(0)] + public readonly short world; #region Constructors [EditorBrowsable(EditorBrowsableState.Never)] - public ent(int id, short gen, short world) + public ent(int id, short gen, short world): this() { - _full = ((long)id) << 32; - _full += ((long)gen) << 16; - _full += world; + this.id = id; + this.gen = gen; + this.world = world; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ent(long value) + internal ent(long full) : this() { - _full = value; + _full = full; } #endregion @@ -64,14 +46,9 @@ namespace DCFApixels.DragonECS #region Equals [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(in ent other) - { - return _full == other._full; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) { - return obj is ent other && Equals(in other); + return obj is ent other && _full == other._full; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(ent other) @@ -85,26 +62,39 @@ namespace DCFApixels.DragonECS } #endregion + #region ToString + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override string ToString() => $"ent(id:{id} gen:{gen} world:{world})"; + #endregion + #region operators [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(in ent left, in ent right) => left.Equals(in right); + public static bool operator ==(in ent a, in ent b) => a._full == b._full; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(in ent left, in ent right) => !left.Equals(in right); + public static bool operator !=(in ent a, in ent b) => a._full != b._full; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator long(in ent eent) => eent._full; + public static explicit operator long(in ent a) => a._full; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator int(in ent eent) => eent.id; + public static explicit operator int(in ent a) => a.id; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator ent(in long value) => new ent(value); + public static explicit operator ent(in long a) => new ent(a); #endregion } public static partial class entExtensions { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsAlive(this ref ent self) + { + bool result = EcsWorld.Worlds[self.world].EntityIsAlive(self.id, self.gen); + if (!result) self = ent.NULL; + return result; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNull(this in ent self) { @@ -136,50 +126,4 @@ namespace DCFApixels.DragonECS EcsWorld.Worlds[self.world].GetPool().Del(self.id); } } - - public struct Entity - { - public IEcsWorld world; - public int id; - - public Entity(IEcsWorld world, int id) - { - this.world = world; - this.id = id; - } - } - - public static partial class EntityExtensions - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool IsNull(this in Entity self) - { - return self.world == null; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ref readonly T Read(this in Entity self) - where T : struct - { - return ref self.world.GetPool().Read(self.id); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ref T Write(this in Entity self) - where T : struct - { - return ref self.world.GetPool().Write(self.id); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool Has(this in Entity self) - where T : struct - { - return self.world.GetPool().Has(self.id); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Del(this in Entity self) - where T : struct - { - self.world.GetPool().Del(self.id); - } - } } diff --git a/src/Exceptions/EcsFrameworkException.cs b/src/Exceptions/EcsFrameworkException.cs index d61ce81..3b76834 100644 --- a/src/Exceptions/EcsFrameworkException.cs +++ b/src/Exceptions/EcsFrameworkException.cs @@ -7,8 +7,8 @@ namespace DCFApixels.DragonECS public class EcsFrameworkException : Exception { public EcsFrameworkException() { } - public EcsFrameworkException(string message) : base(Exceptions.MESSAGE_SUFFIX + message) { } - public EcsFrameworkException(string message, Exception inner) : base(Exceptions.MESSAGE_SUFFIX + message, inner) { } + public EcsFrameworkException(string message) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message) { } + public EcsFrameworkException(string message, Exception inner) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message, inner) { } protected EcsFrameworkException(SerializationInfo info, StreamingContext context) : base(info, context) { } } } diff --git a/src/Exceptions/Exceptions.cs b/src/Exceptions/Exceptions.cs deleted file mode 100644 index 3408d6d..0000000 --- a/src/Exceptions/Exceptions.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace DCFApixels.DragonECS -{ - internal static class Exceptions - { - public const string MESSAGE_SUFFIX = "[DragonECS] "; - } -} diff --git a/src/INFO.txt b/src/INFO.txt index 01ea03d..9f6392b 100644 --- a/src/INFO.txt +++ b/src/INFO.txt @@ -8,3 +8,9 @@ DCFAECS_NO_SANITIZE_CHECKS - отвключение дополнительных #if DEBUG || !DRAGONECS_NO_SANITIZE_CHECKS + + + // [EditorBrowsable(EditorBrowsableState.Never)] + + + //throw new EcsFrameworkException($"There is no suitable EcsRunner implementation for the {typeof(T).FullName} interface"); diff --git a/src/Utils/SparseSet.cs b/src/Utils/SparseSet.cs index 233c2a3..79f0636 100644 --- a/src/Utils/SparseSet.cs +++ b/src/Utils/SparseSet.cs @@ -80,7 +80,7 @@ namespace DCFApixels.DragonECS if (_count >= _dense.Length) Array.Resize(ref _dense, _dense.Length << 1); - if (value > _sparse.Length) + if (value >= _sparse.Length) { int neadedSpace = _sparse.Length; while (value >= neadedSpace)