diff --git a/package.json b/package.json index 340db7f..f0eb6a1 100644 --- a/package.json +++ b/package.json @@ -8,11 +8,12 @@ "displayName": "DragonECS", "description": "C# Entity Component System Framework", "unity": "2020.3", - "version": "0.8.21", + "version": "0.8.23", "repository": { "type": "git", "url": "https://github.com/DCFApixels/DragonECS.git" }, + "dependencies": { }, "keywords": [ "ecs", diff --git a/src/Consts.cs b/src/Consts.cs index 49b7c80..efaf5d5 100644 --- a/src/Consts.cs +++ b/src/Consts.cs @@ -2,6 +2,7 @@ { public class EcsConsts { + public const string AUTHOR = "DCFApixels"; public const string FRAMEWORK_NAME = "DragonECS"; public const string EXCEPTION_MESSAGE_PREFIX = "[" + FRAMEWORK_NAME + "] "; @@ -55,7 +56,7 @@ #if DISABLE_DRAGONECS_DEBUGGER true; #else - false; + false; #endif } } diff --git a/src/DataInterfaces.cs b/src/DataInterfaces.cs index 81a8a70..66f4c12 100644 --- a/src/DataInterfaces.cs +++ b/src/DataInterfaces.cs @@ -36,18 +36,19 @@ namespace DCFApixels.DragonECS #endregion #region IEcsComponentReset - public interface IEcsComponentReset + public interface IEcsComponentLifecycle { - void Reset(ref T component); + void Enable(ref T component); + void Disable(ref T component); } public static class EcsComponentResetHandler { - public static readonly IEcsComponentReset instance; + public static readonly IEcsComponentLifecycle instance; public static readonly bool isHasHandler; static EcsComponentResetHandler() { T def = default; - if (def is IEcsComponentReset intrf) + if (def is IEcsComponentLifecycle intrf) { isHasHandler = true; instance = intrf; @@ -58,10 +59,12 @@ namespace DCFApixels.DragonECS instance = new DummyHandler(); } } - private sealed class DummyHandler : IEcsComponentReset + private sealed class DummyHandler : IEcsComponentLifecycle { [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Reset(ref T component) => component = default; + public void Enable(ref T component) => component = default; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Disable(ref T component) => component = default; } } #endregion diff --git a/src/Debug/EcsDebugUtility.cs b/src/Debug/EcsDebugUtility.cs index 91f9841..8a6d87c 100644 --- a/src/Debug/EcsDebugUtility.cs +++ b/src/Debug/EcsDebugUtility.cs @@ -1,6 +1,7 @@ using DCFApixels.DragonECS.Internal; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Reflection; @@ -30,7 +31,6 @@ namespace DCFApixels.DragonECS } private static string GetGenericTypeNameInternal(Type type, int maxDepth, bool isFull) { -#if (DEBUG && !DISABLE_DEBUG) string typeName = isFull ? type.FullName : type.Name; if (!type.IsGenericType || maxDepth == 0) { @@ -51,9 +51,6 @@ namespace DCFApixels.DragonECS genericParams += (i == 0 ? paramTypeName : $", {paramTypeName}"); } return $"{typeName}<{genericParams}>"; -#else //optimization for release build - return isFull ? type.FullName : type.Name; -#endif } #endregion @@ -315,6 +312,8 @@ namespace DCFApixels.DragonECS MetaGroup Group { get; } IReadOnlyCollection Tags { get; } } + + [DebuggerTypeProxy(typeof(DebuggerProxy))] public sealed class TypeMeta : ITypeMeta { internal readonly Type _type; @@ -351,7 +350,7 @@ namespace DCFApixels.DragonECS { if (_initFlags.HasFlag(InitFlag.Name) == false) { - (_name, _isCustomName) = MetaCacheGenerator.GetName(_type); + (_name, _isCustomName) = MetaGenerator.GetMetaName(_type); _initFlags |= InitFlag.Name; } } @@ -378,7 +377,7 @@ namespace DCFApixels.DragonECS { if (_initFlags.HasFlag(InitFlag.Color) == false) { - (_color, _isCustomColor) = MetaCacheGenerator.GetColor(_type); + (_color, _isCustomColor) = MetaGenerator.GetColor(_type); _initFlags |= InitFlag.Color; } } @@ -407,7 +406,7 @@ namespace DCFApixels.DragonECS { if (_initFlags.HasFlag(InitFlag.Description) == false) { - _description = MetaCacheGenerator.GetDescription(_type); + _description = MetaGenerator.GetDescription(_type); _initFlags |= InitFlag.Description; } return _description; @@ -422,7 +421,7 @@ namespace DCFApixels.DragonECS { if (_initFlags.HasFlag(InitFlag.Group) == false) { - _group = MetaCacheGenerator.GetGroup(_type); + _group = MetaGenerator.GetGroup(_type); _initFlags |= InitFlag.Group; } return _group; @@ -435,7 +434,7 @@ namespace DCFApixels.DragonECS { if (_initFlags.HasFlag(InitFlag.Tags) == false) { - _tags = MetaCacheGenerator.GetTags(_type); + _tags = MetaGenerator.GetTags(_type); _initFlags |= InitFlag.Tags; _isHidden = _tags.Contains(MetaTags.HIDDEN); } @@ -504,6 +503,106 @@ namespace DCFApixels.DragonECS All = Name | Group | Color | Description | Tags | TypeCode } #endregion + + #region Other + public override string ToString() + { + return Name; + } + private class DebuggerProxy : ITypeMeta + { + private readonly TypeMeta _meta; + public string Name + { + get { return _meta.Name; } + } + public MetaColor Color + { + get { return _meta.Color; } + } + public string Description + { + get { return _meta.Description; } + } + public MetaGroup Group + { + get { return _meta.Group; } + } + public IReadOnlyCollection Tags + { + get { return _meta.Tags; } + } + public DebuggerProxy(TypeMeta meta) + { + _meta = meta; + } + } + #endregion + + #region MetaGenerator + private static class MetaGenerator + { + private const int GENERIC_NAME_DEPTH = 3; + + #region GetMetaName + public static (string, bool) GetMetaName(Type type) + { + bool isCustom = type.TryGetCustomAttribute(out MetaNameAttribute atr) && string.IsNullOrEmpty(atr.name) == false; + if (isCustom) + { + if ((type.IsGenericType && atr.isHideGeneric == false) == false) + { + return (atr.name, isCustom); + } + string genericParams = ""; + Type[] typeParameters = type.GetGenericArguments(); + for (int i = 0; i < typeParameters.Length; ++i) + { + string paramTypeName = EcsDebugUtility.GetGenericTypeName(typeParameters[i], GENERIC_NAME_DEPTH); + genericParams += (i == 0 ? paramTypeName : $", {paramTypeName}"); + } + return ($"{atr.name}<{genericParams}>", isCustom); + } + return (EcsDebugUtility.GetGenericTypeName(type, GENERIC_NAME_DEPTH), isCustom); + } + #endregion + + #region GetColor + private static MetaColor AutoColor(Type type) + { + return new MetaColor(type.Name).Desaturate(0.48f) / 1.18f; + } + public static (MetaColor, bool) GetColor(Type type) + { + bool isCustom = type.TryGetCustomAttribute(out MetaColorAttribute atr); + return (isCustom ? atr.color : AutoColor(type), isCustom); + } + #endregion + + #region GetGroup + public static MetaGroup GetGroup(Type type) + { + return type.TryGetCustomAttribute(out MetaGroupAttribute atr) ? atr.Data : MetaGroup.Empty; + } + #endregion + + #region GetDescription + public static string GetDescription(Type type) + { + bool isCustom = type.TryGetCustomAttribute(out MetaDescriptionAttribute atr); + return isCustom ? atr.description : string.Empty; + } + #endregion + + #region GetTags + public static IReadOnlyCollection GetTags(Type type) + { + var atr = type.GetCustomAttribute(); + return atr != null ? atr.Tags : Array.Empty(); + } + #endregion + } + #endregion } public static class TypeMetaDataCachedExtensions @@ -517,55 +616,4 @@ namespace DCFApixels.DragonECS return EcsDebugUtility.GetTypeMeta(self); } } -} - -namespace DCFApixels.DragonECS.Internal -{ - internal static class MetaCacheGenerator - { - private const int GENERIC_NAME_DEPTH = 2; - - #region GetName - public static (string, bool) GetName(Type type) - { - bool isCustom = type.TryGetCustomAttribute(out MetaNameAttribute atr) && string.IsNullOrEmpty(atr.name) == false; - return (isCustom ? atr.name : EcsDebugUtility.GetGenericTypeName(type, GENERIC_NAME_DEPTH), isCustom); - } - #endregion - - #region GetColor - private static MetaColor AutoColor(Type type) - { - return new MetaColor(type.Name).Desaturate(0.48f) / 1.18f; - } - public static (MetaColor, bool) GetColor(Type type) - { - bool isCustom = type.TryGetCustomAttribute(out MetaColorAttribute atr); - return (isCustom ? atr.color : AutoColor(type), isCustom); - } - #endregion - - #region GetGroup - public static MetaGroup GetGroup(Type type) - { - return type.TryGetCustomAttribute(out MetaGroupAttribute atr) ? atr.Data : MetaGroup.Empty; - } - #endregion - - #region GetDescription - public static string GetDescription(Type type) - { - bool isCustom = type.TryGetCustomAttribute(out MetaDescriptionAttribute atr); - return isCustom ? atr.description : string.Empty; - } - #endregion - - #region GetTags - public static IReadOnlyCollection GetTags(Type type) - { - var atr = type.GetCustomAttribute(); - return atr != null ? atr.Tags : Array.Empty(); - } - #endregion - } } \ No newline at end of file diff --git a/src/Debug/MetaAttributes/MetaDescriptionAttribute.cs b/src/Debug/MetaAttributes/MetaDescriptionAttribute.cs index a5327d6..3260cc8 100644 --- a/src/Debug/MetaAttributes/MetaDescriptionAttribute.cs +++ b/src/Debug/MetaAttributes/MetaDescriptionAttribute.cs @@ -6,6 +6,9 @@ namespace DCFApixels.DragonECS public sealed class MetaDescriptionAttribute : EcsMetaAttribute { public readonly string description; - public MetaDescriptionAttribute(string description) => this.description = description; + public MetaDescriptionAttribute(string description) + { + this.description = description; + } } } diff --git a/src/Debug/MetaAttributes/MetaNameAttribute.cs b/src/Debug/MetaAttributes/MetaNameAttribute.cs index 449ad35..47b4a65 100644 --- a/src/Debug/MetaAttributes/MetaNameAttribute.cs +++ b/src/Debug/MetaAttributes/MetaNameAttribute.cs @@ -6,6 +6,11 @@ namespace DCFApixels.DragonECS public sealed class MetaNameAttribute : EcsMetaAttribute { public readonly string name; - public MetaNameAttribute(string name) => this.name = name; + public readonly bool isHideGeneric; + public MetaNameAttribute(string name, bool isHideGeneric = false) + { + this.name = name; + this.isHideGeneric = isHideGeneric; + } } } diff --git a/src/EcsAspect.cs b/src/EcsAspect.cs index 354bdcc..5aa3595 100644 --- a/src/EcsAspect.cs +++ b/src/EcsAspect.cs @@ -426,7 +426,7 @@ namespace DCFApixels.DragonECS { _builder = builder; } - public T GetInstance() + public T GetInstance() where T : IEcsPoolImplementation, new() { return _builder.IncludePool(); diff --git a/src/EcsPipeline.cs b/src/EcsPipeline.cs index 2d30c06..9baba80 100644 --- a/src/EcsPipeline.cs +++ b/src/EcsPipeline.cs @@ -3,6 +3,7 @@ using DCFApixels.DragonECS.RunnersCore; using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; @@ -282,7 +283,11 @@ namespace DCFApixels.DragonECS public EcsPipeline Build() { List result = new List(32); - List basicBlockList = _systems[_basicLayer]; + List basicBlockList; + if (_systems.TryGetValue(_basicLayer, out basicBlockList) == false) + { + basicBlockList = new List(); + } foreach (var item in _systems) { if (!Layers.Contains(item.Key)) @@ -489,9 +494,12 @@ namespace DCFApixels.DragonECS #endregion #region EcsProcess + [DebuggerTypeProxy(typeof(DebuggerProxy))] public readonly struct EcsProcessRaw : IEnumerable { private readonly Array _systems; + + #region Properties public int Length { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -501,26 +509,62 @@ namespace DCFApixels.DragonECS { get { return (IEcsProcess)_systems.GetValue(index); } } + #endregion + + #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] internal EcsProcessRaw(Array systems) { _systems = systems; } + #endregion + + #region Enumerator public IEnumerator GetEnumerator() { return _systems.GetEnumerator(); } + #endregion + + #region Internal [MethodImpl(MethodImplOptions.AggressiveInlining)] internal T[] GetSystems_Internal() { return (T[])_systems; } + #endregion + + #region DebuggerProxy + internal class DebuggerProxy + { + private EcsProcessRaw _process; + public IEnumerable Systems + { + get + { + return _process._systems.Cast().Select(o => o.GetMeta()).ToArray(); + } + } + public int Count + { + get { return _process.Length; } + } + public DebuggerProxy(EcsProcessRaw process) + { + _process = process; + } + } + #endregion } + + [DebuggerTypeProxy(typeof(EcsProcess<>.DebuggerProxy))] public readonly struct EcsProcess : IReadOnlyCollection where TProcess : IEcsProcess { public readonly static EcsProcess Empty = new EcsProcess(Array.Empty()); private readonly TProcess[] _systems; + + #region Properties public bool IsNullOrEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -541,11 +585,17 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _systems[index]; } } + #endregion + + #region Constructors [MethodImpl(MethodImplOptions.AggressiveInlining)] internal EcsProcess(TProcess[] systems) { _systems = systems; } + #endregion + + #region Converts public static explicit operator EcsProcess(EcsProcessRaw raw) { return new EcsProcess(raw.GetSystems_Internal()); @@ -554,6 +604,9 @@ namespace DCFApixels.DragonECS { return new EcsProcessRaw(process._systems); } + #endregion + + #region Enumerator [MethodImpl(MethodImplOptions.AggressiveInlining)] public Enumerator GetEnumerator() { return new Enumerator(_systems); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } @@ -581,6 +634,29 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Dispose() { } } + #endregion + + #region DebuggerProxy + internal class DebuggerProxy + { + private EcsProcess _process; + public IEnumerable Systems + { + get + { + return _process._systems.Select(o => o.GetMeta()).ToArray(); + } + } + public int Count + { + get { return _process.Length; } + } + public DebuggerProxy(EcsProcess process) + { + _process = process; + } + } + #endregion } #endregion } \ No newline at end of file diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index 8cc023b..914fdfd 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -162,8 +162,17 @@ namespace DCFApixels.DragonECS { if (_isDestroyed) { + EcsDebug.PrintWarning("The world is already destroyed"); return; } + if(id == NULL_WORLD_ID) + { +#if (DEBUG && !DISABLE_DEBUG) + Throw.World_WorldCantBeDestroyed(); +#endif + return; + } + _listeners.InvokeOnWorldDestroy(); _entityDispenser = null; _pools = null; _nullPool = null; @@ -173,6 +182,7 @@ namespace DCFApixels.DragonECS _isDestroyed = true; _poolTypeCode_2_CmpTypeIDs = null; _cmpTypeCode_2_CmpTypeIDs = null; + //_entities - не обнуляется для работы entlong.IsAlive } //public void Clear() { } #endregion diff --git a/src/EcsWorld.static.cs b/src/EcsWorld.static.cs index 47d501c..51f1fdf 100644 --- a/src/EcsWorld.static.cs +++ b/src/EcsWorld.static.cs @@ -131,7 +131,7 @@ namespace DCFApixels.DragonECS } private sealed class NullWorld : EcsWorld { - internal NullWorld() : base(ConfigContainer.Empty, 0) { } + internal NullWorld() : base(new EcsWorldConfig(4, 4, 4, 4, 4), 0) { } } } } diff --git a/src/Pools/EcsPool.cs b/src/Pools/EcsPool.cs index 6996a00..5ec6e00 100644 --- a/src/Pools/EcsPool.cs +++ b/src/Pools/EcsPool.cs @@ -20,8 +20,8 @@ namespace DCFApixels.DragonECS private int[] _recycledItems; private int _recycledItemsCount = 0; - private IEcsComponentReset _componentResetHandler = EcsComponentResetHandler.instance; - private bool _isHasComponentResetHandler = EcsComponentResetHandler.isHasHandler; + private IEcsComponentLifecycle _componentLifecycleHandler = EcsComponentResetHandler.instance; + private bool _isHasComponentLifecycleHandler = EcsComponentResetHandler.isHasHandler; private IEcsComponentCopy _componentCopyHandler = EcsComponentCopyHandler.instance; private bool _isHasComponentCopyHandler = EcsComponentCopyHandler.isHasHandler; @@ -78,7 +78,7 @@ namespace DCFApixels.DragonECS } _mediator.RegisterComponent(entityID, _componentTypeID, _maskBit); _listeners.InvokeOnAddAndGet(entityID); - ResetComponent(ref _items[itemIndex]); + EnableComponent(ref _items[itemIndex]); return ref _items[itemIndex]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -120,7 +120,7 @@ namespace DCFApixels.DragonECS _listeners.InvokeOnAdd(entityID); } _listeners.InvokeOnGet(entityID); - ResetComponent(ref _items[itemIndex]); + EnableComponent(ref _items[itemIndex]); return ref _items[itemIndex]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -134,7 +134,7 @@ namespace DCFApixels.DragonECS #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS if (itemIndex <= 0) { EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); } #endif - ResetComponent(ref _items[itemIndex]); + DisableComponent(ref _items[itemIndex]); if (_recycledItemsCount >= _recycledItems.Length) { Array.Resize(ref _recycledItems, _recycledItems.Length << 1); @@ -217,13 +217,25 @@ namespace DCFApixels.DragonECS } #endregion - #region Reset/Copy + #region Enable/Disable/Copy [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ResetComponent(ref T component) + private void EnableComponent(ref T component) { - if (_isHasComponentResetHandler) + if (_isHasComponentLifecycleHandler) { - _componentResetHandler.Reset(ref component); + _componentLifecycleHandler.Enable(ref component); + } + else + { + component = default; + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void DisableComponent(ref T component) + { + if (_isHasComponentLifecycleHandler) + { + _componentLifecycleHandler.Disable(ref component); } else { diff --git a/src/Utils/Exceptions.cs b/src/Utils/Exceptions.cs index 17fea7a..10bf0c5 100644 --- a/src/Utils/Exceptions.cs +++ b/src/Utils/Exceptions.cs @@ -103,12 +103,15 @@ namespace DCFApixels.DragonECS.Internal { throw new EcsFrameworkException($"An entity with identifier {entityID} is already contained in this world"); } - [MethodImpl(MethodImplOptions.NoInlining)] public static void World_PoolAlreadyCreated() { throw new EcsFrameworkException("The pool has already been created."); } + public static void World_WorldCantBeDestroyed() + { + throw new EcsFrameworkException("This world can't be destroyed"); + } [MethodImpl(MethodImplOptions.NoInlining)] internal static void Ent_ThrowIsNotAlive(entlong entity) diff --git a/src/entlong.cs b/src/entlong.cs index 73e2a32..b59df44 100644 --- a/src/entlong.cs +++ b/src/entlong.cs @@ -115,7 +115,7 @@ namespace DCFApixels.DragonECS world = EcsWorld.GetWorld(this.world); return IsAlive; } - public bool TryGetWorldID(out int worldID) + public bool TryGetWorldID(out short worldID) { worldID = world; return IsAlive; @@ -131,7 +131,7 @@ namespace DCFApixels.DragonECS gen = this.gen; id = this.id; } - public void Unpack(out int id, out int worldID) + public void Unpack(out int id, out short worldID) { worldID = world; id = this.id; @@ -155,7 +155,7 @@ namespace DCFApixels.DragonECS id = this.id; return IsAlive; } - public bool TryUnpack(out int id, out int worldID) + public bool TryUnpack(out int id, out short worldID) { worldID = world; id = this.id;