Merge branch 'dev'

This commit is contained in:
Mikhail 2024-03-11 02:15:58 +08:00
commit 34a4a96251
13 changed files with 248 additions and 86 deletions

View File

@ -8,11 +8,12 @@
"displayName": "DragonECS", "displayName": "DragonECS",
"description": "C# Entity Component System Framework", "description": "C# Entity Component System Framework",
"unity": "2020.3", "unity": "2020.3",
"version": "0.8.21", "version": "0.8.23",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/DCFApixels/DragonECS.git" "url": "https://github.com/DCFApixels/DragonECS.git"
}, },
"dependencies": { },
"keywords": "keywords":
[ [
"ecs", "ecs",

View File

@ -2,6 +2,7 @@
{ {
public class EcsConsts public class EcsConsts
{ {
public const string AUTHOR = "DCFApixels";
public const string FRAMEWORK_NAME = "DragonECS"; public const string FRAMEWORK_NAME = "DragonECS";
public const string EXCEPTION_MESSAGE_PREFIX = "[" + FRAMEWORK_NAME + "] "; public const string EXCEPTION_MESSAGE_PREFIX = "[" + FRAMEWORK_NAME + "] ";

View File

@ -36,18 +36,19 @@ namespace DCFApixels.DragonECS
#endregion #endregion
#region IEcsComponentReset #region IEcsComponentReset
public interface IEcsComponentReset<T> public interface IEcsComponentLifecycle<T>
{ {
void Reset(ref T component); void Enable(ref T component);
void Disable(ref T component);
} }
public static class EcsComponentResetHandler<T> public static class EcsComponentResetHandler<T>
{ {
public static readonly IEcsComponentReset<T> instance; public static readonly IEcsComponentLifecycle<T> instance;
public static readonly bool isHasHandler; public static readonly bool isHasHandler;
static EcsComponentResetHandler() static EcsComponentResetHandler()
{ {
T def = default; T def = default;
if (def is IEcsComponentReset<T> intrf) if (def is IEcsComponentLifecycle<T> intrf)
{ {
isHasHandler = true; isHasHandler = true;
instance = intrf; instance = intrf;
@ -58,10 +59,12 @@ namespace DCFApixels.DragonECS
instance = new DummyHandler(); instance = new DummyHandler();
} }
} }
private sealed class DummyHandler : IEcsComponentReset<T> private sealed class DummyHandler : IEcsComponentLifecycle<T>
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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 #endregion

View File

@ -1,6 +1,7 @@
using DCFApixels.DragonECS.Internal; using DCFApixels.DragonECS.Internal;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
@ -30,7 +31,6 @@ namespace DCFApixels.DragonECS
} }
private static string GetGenericTypeNameInternal(Type type, int maxDepth, bool isFull) private static string GetGenericTypeNameInternal(Type type, int maxDepth, bool isFull)
{ {
#if (DEBUG && !DISABLE_DEBUG)
string typeName = isFull ? type.FullName : type.Name; string typeName = isFull ? type.FullName : type.Name;
if (!type.IsGenericType || maxDepth == 0) if (!type.IsGenericType || maxDepth == 0)
{ {
@ -51,9 +51,6 @@ namespace DCFApixels.DragonECS
genericParams += (i == 0 ? paramTypeName : $", {paramTypeName}"); genericParams += (i == 0 ? paramTypeName : $", {paramTypeName}");
} }
return $"{typeName}<{genericParams}>"; return $"{typeName}<{genericParams}>";
#else //optimization for release build
return isFull ? type.FullName : type.Name;
#endif
} }
#endregion #endregion
@ -315,6 +312,8 @@ namespace DCFApixels.DragonECS
MetaGroup Group { get; } MetaGroup Group { get; }
IReadOnlyCollection<string> Tags { get; } IReadOnlyCollection<string> Tags { get; }
} }
[DebuggerTypeProxy(typeof(DebuggerProxy))]
public sealed class TypeMeta : ITypeMeta public sealed class TypeMeta : ITypeMeta
{ {
internal readonly Type _type; internal readonly Type _type;
@ -351,7 +350,7 @@ namespace DCFApixels.DragonECS
{ {
if (_initFlags.HasFlag(InitFlag.Name) == false) if (_initFlags.HasFlag(InitFlag.Name) == false)
{ {
(_name, _isCustomName) = MetaCacheGenerator.GetName(_type); (_name, _isCustomName) = MetaGenerator.GetMetaName(_type);
_initFlags |= InitFlag.Name; _initFlags |= InitFlag.Name;
} }
} }
@ -378,7 +377,7 @@ namespace DCFApixels.DragonECS
{ {
if (_initFlags.HasFlag(InitFlag.Color) == false) if (_initFlags.HasFlag(InitFlag.Color) == false)
{ {
(_color, _isCustomColor) = MetaCacheGenerator.GetColor(_type); (_color, _isCustomColor) = MetaGenerator.GetColor(_type);
_initFlags |= InitFlag.Color; _initFlags |= InitFlag.Color;
} }
} }
@ -407,7 +406,7 @@ namespace DCFApixels.DragonECS
{ {
if (_initFlags.HasFlag(InitFlag.Description) == false) if (_initFlags.HasFlag(InitFlag.Description) == false)
{ {
_description = MetaCacheGenerator.GetDescription(_type); _description = MetaGenerator.GetDescription(_type);
_initFlags |= InitFlag.Description; _initFlags |= InitFlag.Description;
} }
return _description; return _description;
@ -422,7 +421,7 @@ namespace DCFApixels.DragonECS
{ {
if (_initFlags.HasFlag(InitFlag.Group) == false) if (_initFlags.HasFlag(InitFlag.Group) == false)
{ {
_group = MetaCacheGenerator.GetGroup(_type); _group = MetaGenerator.GetGroup(_type);
_initFlags |= InitFlag.Group; _initFlags |= InitFlag.Group;
} }
return _group; return _group;
@ -435,7 +434,7 @@ namespace DCFApixels.DragonECS
{ {
if (_initFlags.HasFlag(InitFlag.Tags) == false) if (_initFlags.HasFlag(InitFlag.Tags) == false)
{ {
_tags = MetaCacheGenerator.GetTags(_type); _tags = MetaGenerator.GetTags(_type);
_initFlags |= InitFlag.Tags; _initFlags |= InitFlag.Tags;
_isHidden = _tags.Contains(MetaTags.HIDDEN); _isHidden = _tags.Contains(MetaTags.HIDDEN);
} }
@ -504,32 +503,67 @@ namespace DCFApixels.DragonECS
All = Name | Group | Color | Description | Tags | TypeCode All = Name | Group | Color | Description | Tags | TypeCode
} }
#endregion #endregion
}
public static class TypeMetaDataCachedExtensions #region Other
public override string ToString()
{ {
public static TypeMeta GetMeta(this object self) return Name;
{
return EcsDebugUtility.GetTypeMeta(self);
} }
public static TypeMeta ToMeta(this Type self) private class DebuggerProxy : ITypeMeta
{ {
return EcsDebugUtility.GetTypeMeta(self); 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<string> Tags
{
get { return _meta.Tags; }
}
public DebuggerProxy(TypeMeta meta)
{
_meta = meta;
} }
} }
} #endregion
namespace DCFApixels.DragonECS.Internal #region MetaGenerator
{ private static class MetaGenerator
internal static class MetaCacheGenerator
{ {
private const int GENERIC_NAME_DEPTH = 2; private const int GENERIC_NAME_DEPTH = 3;
#region GetName #region GetMetaName
public static (string, bool) GetName(Type type) public static (string, bool) GetMetaName(Type type)
{ {
bool isCustom = type.TryGetCustomAttribute(out MetaNameAttribute atr) && string.IsNullOrEmpty(atr.name) == false; bool isCustom = type.TryGetCustomAttribute(out MetaNameAttribute atr) && string.IsNullOrEmpty(atr.name) == false;
return (isCustom ? atr.name : EcsDebugUtility.GetGenericTypeName(type, GENERIC_NAME_DEPTH), isCustom); 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 #endregion
@ -568,4 +602,18 @@ namespace DCFApixels.DragonECS.Internal
} }
#endregion #endregion
} }
#endregion
}
public static class TypeMetaDataCachedExtensions
{
public static TypeMeta GetMeta(this object self)
{
return EcsDebugUtility.GetTypeMeta(self);
}
public static TypeMeta ToMeta(this Type self)
{
return EcsDebugUtility.GetTypeMeta(self);
}
}
} }

View File

@ -6,6 +6,9 @@ namespace DCFApixels.DragonECS
public sealed class MetaDescriptionAttribute : EcsMetaAttribute public sealed class MetaDescriptionAttribute : EcsMetaAttribute
{ {
public readonly string description; public readonly string description;
public MetaDescriptionAttribute(string description) => this.description = description; public MetaDescriptionAttribute(string description)
{
this.description = description;
}
} }
} }

View File

@ -6,6 +6,11 @@ namespace DCFApixels.DragonECS
public sealed class MetaNameAttribute : EcsMetaAttribute public sealed class MetaNameAttribute : EcsMetaAttribute
{ {
public readonly string name; 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;
}
} }
} }

View File

@ -3,6 +3,7 @@ using DCFApixels.DragonECS.RunnersCore;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -282,7 +283,11 @@ namespace DCFApixels.DragonECS
public EcsPipeline Build() public EcsPipeline Build()
{ {
List<IEcsProcess> result = new List<IEcsProcess>(32); List<IEcsProcess> result = new List<IEcsProcess>(32);
List<IEcsProcess> basicBlockList = _systems[_basicLayer]; List<IEcsProcess> basicBlockList;
if (_systems.TryGetValue(_basicLayer, out basicBlockList) == false)
{
basicBlockList = new List<IEcsProcess>();
}
foreach (var item in _systems) foreach (var item in _systems)
{ {
if (!Layers.Contains(item.Key)) if (!Layers.Contains(item.Key))
@ -489,9 +494,12 @@ namespace DCFApixels.DragonECS
#endregion #endregion
#region EcsProcess #region EcsProcess
[DebuggerTypeProxy(typeof(DebuggerProxy))]
public readonly struct EcsProcessRaw : IEnumerable public readonly struct EcsProcessRaw : IEnumerable
{ {
private readonly Array _systems; private readonly Array _systems;
#region Properties
public int Length public int Length
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -501,26 +509,62 @@ namespace DCFApixels.DragonECS
{ {
get { return (IEcsProcess)_systems.GetValue(index); } get { return (IEcsProcess)_systems.GetValue(index); }
} }
#endregion
#region Constructors
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal EcsProcessRaw(Array systems) internal EcsProcessRaw(Array systems)
{ {
_systems = systems; _systems = systems;
} }
#endregion
#region Enumerator
public IEnumerator GetEnumerator() public IEnumerator GetEnumerator()
{ {
return _systems.GetEnumerator(); return _systems.GetEnumerator();
} }
#endregion
#region Internal
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal T[] GetSystems_Internal<T>() internal T[] GetSystems_Internal<T>()
{ {
return (T[])_systems; return (T[])_systems;
} }
#endregion
#region DebuggerProxy
internal class DebuggerProxy
{
private EcsProcessRaw _process;
public IEnumerable<TypeMeta> Systems
{
get
{
return _process._systems.Cast<IEcsProcess>().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<TProcess> : IReadOnlyCollection<TProcess> public readonly struct EcsProcess<TProcess> : IReadOnlyCollection<TProcess>
where TProcess : IEcsProcess where TProcess : IEcsProcess
{ {
public readonly static EcsProcess<TProcess> Empty = new EcsProcess<TProcess>(Array.Empty<TProcess>()); public readonly static EcsProcess<TProcess> Empty = new EcsProcess<TProcess>(Array.Empty<TProcess>());
private readonly TProcess[] _systems; private readonly TProcess[] _systems;
#region Properties
public bool IsNullOrEmpty public bool IsNullOrEmpty
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -541,11 +585,17 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _systems[index]; } get { return _systems[index]; }
} }
#endregion
#region Constructors
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal EcsProcess(TProcess[] systems) internal EcsProcess(TProcess[] systems)
{ {
_systems = systems; _systems = systems;
} }
#endregion
#region Converts
public static explicit operator EcsProcess<TProcess>(EcsProcessRaw raw) public static explicit operator EcsProcess<TProcess>(EcsProcessRaw raw)
{ {
return new EcsProcess<TProcess>(raw.GetSystems_Internal<TProcess>()); return new EcsProcess<TProcess>(raw.GetSystems_Internal<TProcess>());
@ -554,6 +604,9 @@ namespace DCFApixels.DragonECS
{ {
return new EcsProcessRaw(process._systems); return new EcsProcessRaw(process._systems);
} }
#endregion
#region Enumerator
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator GetEnumerator() { return new Enumerator(_systems); } public Enumerator GetEnumerator() { return new Enumerator(_systems); }
IEnumerator<TProcess> IEnumerable<TProcess>.GetEnumerator() { return GetEnumerator(); } IEnumerator<TProcess> IEnumerable<TProcess>.GetEnumerator() { return GetEnumerator(); }
@ -581,6 +634,29 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose() { } public void Dispose() { }
} }
#endregion
#region DebuggerProxy
internal class DebuggerProxy
{
private EcsProcess<TProcess> _process;
public IEnumerable<TypeMeta> Systems
{
get
{
return _process._systems.Select(o => o.GetMeta()).ToArray();
}
}
public int Count
{
get { return _process.Length; }
}
public DebuggerProxy(EcsProcess<TProcess> process)
{
_process = process;
}
}
#endregion
} }
#endregion #endregion
} }

View File

@ -162,8 +162,17 @@ namespace DCFApixels.DragonECS
{ {
if (_isDestroyed) if (_isDestroyed)
{ {
EcsDebug.PrintWarning("The world is already destroyed");
return; return;
} }
if(id == NULL_WORLD_ID)
{
#if (DEBUG && !DISABLE_DEBUG)
Throw.World_WorldCantBeDestroyed();
#endif
return;
}
_listeners.InvokeOnWorldDestroy();
_entityDispenser = null; _entityDispenser = null;
_pools = null; _pools = null;
_nullPool = null; _nullPool = null;
@ -173,6 +182,7 @@ namespace DCFApixels.DragonECS
_isDestroyed = true; _isDestroyed = true;
_poolTypeCode_2_CmpTypeIDs = null; _poolTypeCode_2_CmpTypeIDs = null;
_cmpTypeCode_2_CmpTypeIDs = null; _cmpTypeCode_2_CmpTypeIDs = null;
//_entities - не обнуляется для работы entlong.IsAlive
} }
//public void Clear() { } //public void Clear() { }
#endregion #endregion

View File

@ -131,7 +131,7 @@ namespace DCFApixels.DragonECS
} }
private sealed class NullWorld : EcsWorld private sealed class NullWorld : EcsWorld
{ {
internal NullWorld() : base(ConfigContainer.Empty, 0) { } internal NullWorld() : base(new EcsWorldConfig(4, 4, 4, 4, 4), 0) { }
} }
} }
} }

View File

@ -20,8 +20,8 @@ namespace DCFApixels.DragonECS
private int[] _recycledItems; private int[] _recycledItems;
private int _recycledItemsCount = 0; private int _recycledItemsCount = 0;
private IEcsComponentReset<T> _componentResetHandler = EcsComponentResetHandler<T>.instance; private IEcsComponentLifecycle<T> _componentLifecycleHandler = EcsComponentResetHandler<T>.instance;
private bool _isHasComponentResetHandler = EcsComponentResetHandler<T>.isHasHandler; private bool _isHasComponentLifecycleHandler = EcsComponentResetHandler<T>.isHasHandler;
private IEcsComponentCopy<T> _componentCopyHandler = EcsComponentCopyHandler<T>.instance; private IEcsComponentCopy<T> _componentCopyHandler = EcsComponentCopyHandler<T>.instance;
private bool _isHasComponentCopyHandler = EcsComponentCopyHandler<T>.isHasHandler; private bool _isHasComponentCopyHandler = EcsComponentCopyHandler<T>.isHasHandler;
@ -78,7 +78,7 @@ namespace DCFApixels.DragonECS
} }
_mediator.RegisterComponent(entityID, _componentTypeID, _maskBit); _mediator.RegisterComponent(entityID, _componentTypeID, _maskBit);
_listeners.InvokeOnAddAndGet(entityID); _listeners.InvokeOnAddAndGet(entityID);
ResetComponent(ref _items[itemIndex]); EnableComponent(ref _items[itemIndex]);
return ref _items[itemIndex]; return ref _items[itemIndex];
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -120,7 +120,7 @@ namespace DCFApixels.DragonECS
_listeners.InvokeOnAdd(entityID); _listeners.InvokeOnAdd(entityID);
} }
_listeners.InvokeOnGet(entityID); _listeners.InvokeOnGet(entityID);
ResetComponent(ref _items[itemIndex]); EnableComponent(ref _items[itemIndex]);
return ref _items[itemIndex]; return ref _items[itemIndex];
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -134,7 +134,7 @@ namespace DCFApixels.DragonECS
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (itemIndex <= 0) { EcsPoolThrowHalper.ThrowNotHaveComponent<T>(entityID); } if (itemIndex <= 0) { EcsPoolThrowHalper.ThrowNotHaveComponent<T>(entityID); }
#endif #endif
ResetComponent(ref _items[itemIndex]); DisableComponent(ref _items[itemIndex]);
if (_recycledItemsCount >= _recycledItems.Length) if (_recycledItemsCount >= _recycledItems.Length)
{ {
Array.Resize(ref _recycledItems, _recycledItems.Length << 1); Array.Resize(ref _recycledItems, _recycledItems.Length << 1);
@ -217,13 +217,25 @@ namespace DCFApixels.DragonECS
} }
#endregion #endregion
#region Reset/Copy #region Enable/Disable/Copy
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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 else
{ {

View File

@ -103,12 +103,15 @@ namespace DCFApixels.DragonECS.Internal
{ {
throw new EcsFrameworkException($"An entity with identifier {entityID} is already contained in this world"); throw new EcsFrameworkException($"An entity with identifier {entityID} is already contained in this world");
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
public static void World_PoolAlreadyCreated() public static void World_PoolAlreadyCreated()
{ {
throw new EcsFrameworkException("The pool has already been created."); 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)] [MethodImpl(MethodImplOptions.NoInlining)]
internal static void Ent_ThrowIsNotAlive(entlong entity) internal static void Ent_ThrowIsNotAlive(entlong entity)

View File

@ -115,7 +115,7 @@ namespace DCFApixels.DragonECS
world = EcsWorld.GetWorld(this.world); world = EcsWorld.GetWorld(this.world);
return IsAlive; return IsAlive;
} }
public bool TryGetWorldID(out int worldID) public bool TryGetWorldID(out short worldID)
{ {
worldID = world; worldID = world;
return IsAlive; return IsAlive;
@ -131,7 +131,7 @@ namespace DCFApixels.DragonECS
gen = this.gen; gen = this.gen;
id = this.id; id = this.id;
} }
public void Unpack(out int id, out int worldID) public void Unpack(out int id, out short worldID)
{ {
worldID = world; worldID = world;
id = this.id; id = this.id;
@ -155,7 +155,7 @@ namespace DCFApixels.DragonECS
id = this.id; id = this.id;
return IsAlive; return IsAlive;
} }
public bool TryUnpack(out int id, out int worldID) public bool TryUnpack(out int id, out short worldID)
{ {
worldID = world; worldID = world;
id = this.id; id = this.id;