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",
"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",

View File

@ -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
}
}

View File

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

View File

@ -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<string> 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<string> 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<string> GetTags(Type type)
{
var atr = type.GetCustomAttribute<MetaTagsAttribute>();
return atr != null ? atr.Tags : Array.Empty<string>();
}
#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<string> GetTags(Type type)
{
var atr = type.GetCustomAttribute<MetaTagsAttribute>();
return atr != null ? atr.Tags : Array.Empty<string>();
}
#endregion
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -426,7 +426,7 @@ namespace DCFApixels.DragonECS
{
_builder = builder;
}
public T GetInstance<T>()
public T GetInstance<T>()
where T : IEcsPoolImplementation, new()
{
return _builder.IncludePool<T>();

View File

@ -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<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)
{
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<T>()
{
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>
where TProcess : IEcsProcess
{
public readonly static EcsProcess<TProcess> Empty = new EcsProcess<TProcess>(Array.Empty<TProcess>());
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<TProcess>(EcsProcessRaw raw)
{
return new EcsProcess<TProcess>(raw.GetSystems_Internal<TProcess>());
@ -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<TProcess> IEnumerable<TProcess>.GetEnumerator() { return GetEnumerator(); }
@ -581,6 +634,29 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
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
}

View File

@ -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

View File

@ -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) { }
}
}
}

View File

@ -20,8 +20,8 @@ namespace DCFApixels.DragonECS
private int[] _recycledItems;
private int _recycledItemsCount = 0;
private IEcsComponentReset<T> _componentResetHandler = EcsComponentResetHandler<T>.instance;
private bool _isHasComponentResetHandler = EcsComponentResetHandler<T>.isHasHandler;
private IEcsComponentLifecycle<T> _componentLifecycleHandler = EcsComponentResetHandler<T>.instance;
private bool _isHasComponentLifecycleHandler = EcsComponentResetHandler<T>.isHasHandler;
private IEcsComponentCopy<T> _componentCopyHandler = EcsComponentCopyHandler<T>.instance;
private bool _isHasComponentCopyHandler = EcsComponentCopyHandler<T>.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<T>(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
{

View File

@ -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)

View File

@ -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;