mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2025-09-19 10:34:37 +08:00
Merge branch 'dev'
This commit is contained in:
commit
91933b974c
@ -4,19 +4,19 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
public interface IEcsPreInitProcess : IEcsSystem
|
public interface IEcsPreInitProcess : IEcsSystem
|
||||||
{
|
{
|
||||||
public void PreInit(EcsPipeline pipeline);
|
void PreInit(EcsPipeline pipeline);
|
||||||
}
|
}
|
||||||
public interface IEcsInitProcess : IEcsSystem
|
public interface IEcsInitProcess : IEcsSystem
|
||||||
{
|
{
|
||||||
public void Init(EcsPipeline pipeline);
|
void Init(EcsPipeline pipeline);
|
||||||
}
|
}
|
||||||
public interface IEcsRunProcess : IEcsSystem
|
public interface IEcsRunProcess : IEcsSystem
|
||||||
{
|
{
|
||||||
public void Run(EcsPipeline pipeline);
|
void Run(EcsPipeline pipeline);
|
||||||
}
|
}
|
||||||
public interface IEcsDestroyProcess : IEcsSystem
|
public interface IEcsDestroyProcess : IEcsSystem
|
||||||
{
|
{
|
||||||
public void Destroy(EcsPipeline pipeline);
|
void Destroy(EcsPipeline pipeline);
|
||||||
}
|
}
|
||||||
public interface IEcsBaseSystem : IEcsInitProcess, IEcsRunProcess, IEcsDestroyProcess { }
|
public interface IEcsBaseSystem : IEcsInitProcess, IEcsRunProcess, IEcsDestroyProcess { }
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ using System.Runtime.CompilerServices;
|
|||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
|
[DebugColor(DebugColor.White)]
|
||||||
public struct Parent : IEcsAttachComponent
|
public struct Parent : IEcsAttachComponent
|
||||||
{
|
{
|
||||||
public entlong entity;
|
public entlong entity;
|
||||||
@ -36,7 +37,7 @@ namespace DCFApixels.DragonECS
|
|||||||
public static bool TryGetRoot(this EcsAttachPool<Parent> parents, EcsSubject conditionSubject, int entityID, out int rootEntityID)
|
public static bool TryGetRoot(this EcsAttachPool<Parent> parents, EcsSubject conditionSubject, int entityID, out int rootEntityID)
|
||||||
{
|
{
|
||||||
rootEntityID = entityID;
|
rootEntityID = entityID;
|
||||||
while (parents.Has(rootEntityID) && parents.Read(rootEntityID).entity.TryGetID(out int child) && conditionSubject.IsMatches(child))
|
while (parents.Has(rootEntityID) && parents.Read(rootEntityID).entity.TryGetID(out int child) && !conditionSubject.IsMatches(child))
|
||||||
rootEntityID = child;
|
rootEntityID = child;
|
||||||
return rootEntityID != entityID;
|
return rootEntityID != entityID;
|
||||||
}
|
}
|
||||||
@ -47,5 +48,25 @@ namespace DCFApixels.DragonECS
|
|||||||
rootEntityID = child;
|
rootEntityID = child;
|
||||||
return rootEntityID != entityID;
|
return rootEntityID != entityID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool TryFindParentWithSubject(this EcsAttachPool<Parent> parents, EcsSubject conditionSubject, int entityID, out int resultEntityID)
|
||||||
|
{
|
||||||
|
resultEntityID = entityID;
|
||||||
|
while (parents.Has(resultEntityID) && parents.Read(resultEntityID).entity.TryGetID(out int child) && !conditionSubject.IsMatches(resultEntityID))
|
||||||
|
resultEntityID = child;
|
||||||
|
return conditionSubject.IsMatches(resultEntityID);
|
||||||
|
}
|
||||||
|
public static bool TryFindParentWith<TComponent>(this EcsAttachPool<Parent> parents, int entityID, out int resultEntityID) where TComponent : struct
|
||||||
|
{
|
||||||
|
var pool = parents.World.AllPools[parents.World.GetComponentID<TComponent>()];
|
||||||
|
resultEntityID = entityID;
|
||||||
|
while (!pool.Has(resultEntityID) &&
|
||||||
|
parents.Has(resultEntityID) &&
|
||||||
|
parents.Read(resultEntityID).entity.TryGetID(out int child))
|
||||||
|
{
|
||||||
|
resultEntityID = child;
|
||||||
|
}
|
||||||
|
return pool.Has(resultEntityID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,16 +38,16 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
public interface IEcsPreInject : IEcsSystem
|
public interface IEcsPreInject : IEcsSystem
|
||||||
{
|
{
|
||||||
public void PreInject(object obj);
|
void PreInject(object obj);
|
||||||
}
|
}
|
||||||
public interface IEcsInject<T> : IEcsSystem
|
public interface IEcsInject<T> : IEcsSystem
|
||||||
{
|
{
|
||||||
public void Inject(T obj);
|
void Inject(T obj);
|
||||||
}
|
}
|
||||||
public interface IEcsPreInitInjectProcess : IEcsSystem
|
public interface IEcsPreInitInjectProcess : IEcsSystem
|
||||||
{
|
{
|
||||||
public void OnPreInitInjectionBefore();
|
void OnPreInitInjectionBefore();
|
||||||
public void OnPreInitInjectionAfter();
|
void OnPreInitInjectionAfter();
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Internal
|
namespace Internal
|
||||||
@ -127,9 +127,7 @@ namespace DCFApixels.DragonECS
|
|||||||
EcsRunner.Destroy(injectCallbacksRunner);
|
EcsRunner.Destroy(injectCallbacksRunner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnPreInitInjectionBefore() { }
|
public void OnPreInitInjectionBefore() { }
|
||||||
|
|
||||||
public void OnPreInitInjectionAfter()
|
public void OnPreInitInjectionAfter()
|
||||||
{
|
{
|
||||||
_injectController = null;
|
_injectController = null;
|
||||||
|
@ -6,12 +6,9 @@ namespace DCFApixels.DragonECS
|
|||||||
public class SystemsBlockMarkerSystem : IEcsSystem
|
public class SystemsBlockMarkerSystem : IEcsSystem
|
||||||
{
|
{
|
||||||
public readonly string name;
|
public readonly string name;
|
||||||
|
public SystemsBlockMarkerSystem(string name) { this.name = name; }
|
||||||
|
}
|
||||||
|
|
||||||
public SystemsBlockMarkerSystem(string name)
|
|
||||||
{
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[DebugHide, DebugColor(DebugColor.Grey)]
|
[DebugHide, DebugColor(DebugColor.Grey)]
|
||||||
public class DeleteEmptyEntitesSystem : IEcsRunProcess, IEcsPreInject
|
public class DeleteEmptyEntitesSystem : IEcsRunProcess, IEcsPreInject
|
||||||
{
|
{
|
||||||
@ -21,7 +18,6 @@ namespace DCFApixels.DragonECS
|
|||||||
if (obj is EcsWorld world)
|
if (obj is EcsWorld world)
|
||||||
_worlds.Add(world);
|
_worlds.Add(world);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Run(EcsPipeline pipeline)
|
public void Run(EcsPipeline pipeline)
|
||||||
{
|
{
|
||||||
foreach (var world in _worlds)
|
foreach (var world in _worlds)
|
||||||
@ -36,7 +32,6 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
private TWorld _world;
|
private TWorld _world;
|
||||||
public void Inject(TWorld obj) => _world = obj;
|
public void Inject(TWorld obj) => _world = obj;
|
||||||
|
|
||||||
private sealed class Subject : EcsSubject
|
private sealed class Subject : EcsSubject
|
||||||
{
|
{
|
||||||
public EcsPool<TComponent> pool;
|
public EcsPool<TComponent> pool;
|
||||||
|
@ -4,15 +4,15 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
public interface IEcsComponentAdd : IEcsSystem
|
public interface IEcsComponentAdd : IEcsSystem
|
||||||
{
|
{
|
||||||
public void OnComponentAdd<T>(int entityID);
|
void OnComponentAdd<T>(int entityID);
|
||||||
}
|
}
|
||||||
public interface IEcsComponentWrite : IEcsSystem
|
public interface IEcsComponentWrite : IEcsSystem
|
||||||
{
|
{
|
||||||
public void OnComponentWrite<T>(int entityID);
|
void OnComponentWrite<T>(int entityID);
|
||||||
}
|
}
|
||||||
public interface IEcsComponentDel : IEcsSystem
|
public interface IEcsComponentDel : IEcsSystem
|
||||||
{
|
{
|
||||||
public void OnComponentDel<T>(int entityID);
|
void OnComponentDel<T>(int entityID);
|
||||||
}
|
}
|
||||||
public interface IEcsComponentLifecycle : IEcsComponentAdd, IEcsComponentWrite, IEcsComponentDel { }
|
public interface IEcsComponentLifecycle : IEcsComponentAdd, IEcsComponentWrite, IEcsComponentDel { }
|
||||||
|
|
||||||
@ -46,11 +46,11 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
public interface IEcsEntityCreate : IEcsSystem
|
public interface IEcsEntityCreate : IEcsSystem
|
||||||
{
|
{
|
||||||
public void OnEntityCreate(int entityID);
|
void OnEntityCreate(int entityID);
|
||||||
}
|
}
|
||||||
public interface IEcsEntityDestroy : IEcsSystem
|
public interface IEcsEntityDestroy : IEcsSystem
|
||||||
{
|
{
|
||||||
public void OnEntityDestroy(int entityID);
|
void OnEntityDestroy(int entityID);
|
||||||
}
|
}
|
||||||
public interface IEcsEntityLifecycle : IEcsEntityCreate, IEcsEntityDestroy { }
|
public interface IEcsEntityLifecycle : IEcsEntityCreate, IEcsEntityDestroy { }
|
||||||
|
|
||||||
@ -76,11 +76,11 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
public interface IEcsWorldCreate : IEcsSystem
|
public interface IEcsWorldCreate : IEcsSystem
|
||||||
{
|
{
|
||||||
public void OnWorldCreate(EcsWorld world);
|
void OnWorldCreate(EcsWorld world);
|
||||||
}
|
}
|
||||||
public interface IEcsWorldDestroy : IEcsSystem
|
public interface IEcsWorldDestroy : IEcsSystem
|
||||||
{
|
{
|
||||||
public void OnWorldDestroy(EcsWorld world);
|
void OnWorldDestroy(EcsWorld world);
|
||||||
}
|
}
|
||||||
public interface IEcsWorldLifecycle : IEcsWorldCreate, IEcsWorldDestroy { }
|
public interface IEcsWorldLifecycle : IEcsWorldCreate, IEcsWorldDestroy { }
|
||||||
|
|
||||||
|
@ -19,13 +19,11 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
color = new ColorRecord(r, g, b);
|
color = new ColorRecord(r, g, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DebugColorAttribute(DebugColor color)
|
public DebugColorAttribute(DebugColor color)
|
||||||
{
|
{
|
||||||
this.color = new ColorRecord((int)color);
|
this.color = new ColorRecord((int)color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 4)]
|
[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 4)]
|
||||||
private readonly struct ColorRecord // Union
|
private readonly struct ColorRecord // Union
|
||||||
{
|
{
|
||||||
@ -67,13 +65,31 @@ namespace DCFApixels.DragonECS
|
|||||||
/// <summary> Magenta. RGB is (255, 0, 255)</summary>
|
/// <summary> Magenta. RGB is (255, 0, 255)</summary>
|
||||||
Magenta = (255 << 24) + (000 << 16) + (255 << 8),
|
Magenta = (255 << 24) + (000 << 16) + (255 << 8),
|
||||||
|
|
||||||
/// <summary> Yellow. RGB is (255, 127, 0)</summary>
|
/// <summary> Yellow. RGB is (255, 165, 0)</summary>
|
||||||
Orange = (255 << 24) + (127 << 16) + (000 << 8),
|
Orange = (255 << 24) + (165 << 16) + (000 << 8),
|
||||||
|
/// <summary> Yellow. RGB is (255, 69, 0)</summary>
|
||||||
|
OrangeRed = (255 << 24) + (69 << 16) + (000 << 8),
|
||||||
|
/// <summary> Lime. RGB is (125, 255, 0)</summary>
|
||||||
|
Lime = (125 << 24) + (255 << 16) + (000 << 8),
|
||||||
|
/// <summary> Lime. RGB is (127, 255, 212)</summary>
|
||||||
|
Aquamarine = (127 << 24) + (255 << 16) + (212 << 8),
|
||||||
|
/// <summary> Lime. RGB is (218, 165, 32)</summary>
|
||||||
|
Goldenrod = (218 << 24) + (165 << 16) + (32 << 8),
|
||||||
|
/// <summary> Yellow. RGB is (255, 105, 180)</summary>
|
||||||
|
DeepPink = (255 << 24) + (105 << 16) + (180 << 8),
|
||||||
|
/// <summary> Yellow. RGB is (220, 20, 60)</summary>
|
||||||
|
Crimson = (220 << 24) + (20 << 16) + (60 << 8),
|
||||||
|
/// <summary> Yellow. RGB is (138, 43, 226)</summary>
|
||||||
|
BlueViolet = (138 << 24) + (43 << 16) + (226 << 8),
|
||||||
|
/// <summary> Yellow. RGB is (255, 3, 62)</summary>
|
||||||
|
AmericanRose = (255 << 24) + (3 << 16) + (62 << 8),
|
||||||
|
|
||||||
/// <summary> Grey/Gray. RGB is (127, 127, 127)</summary>
|
/// <summary> Grey/Gray. RGB is (127, 127, 127)</summary>
|
||||||
Gray = (127 << 24) + (127 << 16) + (127 << 8),
|
Gray = (127 << 24) + (127 << 16) + (127 << 8),
|
||||||
/// <summary> Grey/Gray. RGB is (127, 127, 127)</summary>
|
/// <summary> Grey/Gray. RGB is (127, 127, 127)</summary>
|
||||||
Grey = Gray,
|
Grey = Gray,
|
||||||
|
/// <summary> Grey/Gray. RGB is (192, 192, 192)</summary>
|
||||||
|
Silver = (192 << 24) + (192 << 16) + (192 << 8),
|
||||||
/// <summary> White. RGB is (255, 255, 255)</summary>
|
/// <summary> White. RGB is (255, 255, 255)</summary>
|
||||||
White = -1,
|
White = -1,
|
||||||
/// <summary> Black. RGB is (0, 0, 0)</summary>
|
/// <summary> Black. RGB is (0, 0, 0)</summary>
|
||||||
|
55
src/Debug/EcsDebugUtility.cs
Normal file
55
src/Debug/EcsDebugUtility.cs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace DCFApixels.DragonECS
|
||||||
|
{
|
||||||
|
public static class EcsDebugUtility
|
||||||
|
{
|
||||||
|
public static string GetGenericTypeName<T>(int maxDepth = 2) => GetGenericTypeName(typeof(T), maxDepth);
|
||||||
|
public static string GetGenericTypeName(Type type, int maxDepth = 2)
|
||||||
|
{
|
||||||
|
#if (DEBUG && !DISABLE_DEBUG)
|
||||||
|
string friendlyName = type.Name;
|
||||||
|
if (!type.IsGenericType || maxDepth == 0)
|
||||||
|
return friendlyName;
|
||||||
|
|
||||||
|
int iBacktick = friendlyName.IndexOf('`');
|
||||||
|
if (iBacktick > 0)
|
||||||
|
friendlyName = friendlyName.Remove(iBacktick);
|
||||||
|
|
||||||
|
friendlyName += "<";
|
||||||
|
Type[] typeParameters = type.GetGenericArguments();
|
||||||
|
for (int i = 0; i < typeParameters.Length; ++i)
|
||||||
|
{
|
||||||
|
string typeParamName = GetGenericTypeName(typeParameters[i], maxDepth - 1);
|
||||||
|
friendlyName += (i == 0 ? typeParamName : "," + typeParamName);
|
||||||
|
}
|
||||||
|
friendlyName += ">";
|
||||||
|
return friendlyName;
|
||||||
|
#else //optimization for release build
|
||||||
|
return type.Name;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetName<T>() => GetName(typeof(T));
|
||||||
|
public static string GetName(Type type)
|
||||||
|
{
|
||||||
|
var atr = type.GetCustomAttribute<DebugNameAttribute>();
|
||||||
|
return atr != null ? atr.name : GetGenericTypeName(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetDescription<T>() => GetDescription(typeof(T));
|
||||||
|
public static string GetDescription(Type type)
|
||||||
|
{
|
||||||
|
var atr = type.GetCustomAttribute<DebugDescriptionAttribute>();
|
||||||
|
return atr != null ? atr.description : string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static (byte, byte, byte) GetColorRGB<T>() => GetColorRGB(typeof(T));
|
||||||
|
public static (byte, byte, byte) GetColorRGB(Type type)
|
||||||
|
{
|
||||||
|
var atr = type.GetCustomAttribute<DebugColorAttribute>();
|
||||||
|
return atr != null ? (atr.r, atr.g, atr.b) : ((byte)255, (byte)255, (byte)255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -184,6 +184,13 @@ namespace DCFApixels.DragonECS
|
|||||||
AddInternal(system, layerName, true);
|
AddInternal(system, layerName, true);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
public Builder Remove<TSystem>()
|
||||||
|
{
|
||||||
|
_uniqueTypes.Remove(typeof(TSystem));
|
||||||
|
foreach (var list in _systems.Values)
|
||||||
|
list.RemoveAll(o => o is TSystem);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
private void AddInternal(IEcsSystem system, string layerName, bool isUnique)
|
private void AddInternal(IEcsSystem system, string layerName, bool isUnique)
|
||||||
{
|
{
|
||||||
if (layerName == null) layerName = _basicLayer;
|
if (layerName == null) layerName = _basicLayer;
|
||||||
|
@ -44,7 +44,7 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
internal static class EcsRunnerActivator
|
internal static class EcsRunnerActivator
|
||||||
{
|
{
|
||||||
private static Dictionary<Guid, Type> _runnerHandlerTypes; //interface guid/Runner handler type pairs;
|
private static Dictionary<Type, Type> _runnerHandlerTypes; //interface base type/Runner handler type pairs;
|
||||||
|
|
||||||
static EcsRunnerActivator()
|
static EcsRunnerActivator()
|
||||||
{
|
{
|
||||||
@ -69,11 +69,12 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
_runnerHandlerTypes = new Dictionary<Guid, Type>();
|
_runnerHandlerTypes = new Dictionary<Type, Type>();
|
||||||
foreach (var item in runnerHandlerTypes)
|
foreach (var item in runnerHandlerTypes)
|
||||||
{
|
{
|
||||||
Type interfaceType = item.BaseType.GenericTypeArguments[0];
|
Type interfaceType = item.BaseType.GenericTypeArguments[0];
|
||||||
_runnerHandlerTypes.Add(interfaceType.GUID, item);
|
// if(!_runnerHandlerTypes.ContainsKey(interfaceType.GUID))//TODO это кажется костыль, изначально все работало без этого ифа
|
||||||
|
_runnerHandlerTypes.Add(interfaceType.IsGenericType ? interfaceType.GetGenericTypeDefinition() : interfaceType, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delayedExceptions.Count > 0)
|
if (delayedExceptions.Count > 0)
|
||||||
@ -112,14 +113,8 @@ namespace DCFApixels.DragonECS
|
|||||||
internal static void InitFor<TInterface>() where TInterface : IEcsSystem
|
internal static void InitFor<TInterface>() where TInterface : IEcsSystem
|
||||||
{
|
{
|
||||||
Type interfaceType = typeof(TInterface);
|
Type interfaceType = typeof(TInterface);
|
||||||
Type nonGenericInterfaceType = interfaceType;
|
|
||||||
if (nonGenericInterfaceType.IsGenericType)
|
|
||||||
{
|
|
||||||
nonGenericInterfaceType = nonGenericInterfaceType.GetGenericTypeDefinition();
|
|
||||||
}
|
|
||||||
Guid interfaceGuid = nonGenericInterfaceType.GUID;
|
|
||||||
|
|
||||||
if (!_runnerHandlerTypes.TryGetValue(interfaceGuid, out Type runnerType))
|
if (!_runnerHandlerTypes.TryGetValue(interfaceType.IsGenericType ? interfaceType.GetGenericTypeDefinition() : interfaceType, out Type runnerType))
|
||||||
{
|
{
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
public sealed override TPool Exclude<TComponent, TPool>()
|
public sealed override TPool Exclude<TComponent, TPool>()
|
||||||
{
|
{
|
||||||
|
ExcludeImplicit<TComponent>();
|
||||||
return _world.GetPool<TComponent, TPool>();
|
return _world.GetPool<TComponent, TPool>();
|
||||||
}
|
}
|
||||||
public sealed override TPool Optional<TComponent, TPool>()
|
public sealed override TPool Optional<TComponent, TPool>()
|
||||||
|
134
src/EcsWorld.cs
134
src/EcsWorld.cs
@ -9,7 +9,7 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
internal sealed class EcsNullWorld : EcsWorld<EcsNullWorld>
|
internal sealed class EcsNullWorld : EcsWorld<EcsNullWorld>
|
||||||
{
|
{
|
||||||
public EcsNullWorld() : base(null, false) { }
|
public EcsNullWorld() : base(false) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class EcsWorld
|
public abstract class EcsWorld
|
||||||
@ -39,26 +39,24 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
internal IEcsPoolImplementation[] pools;
|
internal IEcsPoolImplementation[] pools;
|
||||||
private EcsNullPool _nullPool;
|
private EcsNullPool _nullPool;
|
||||||
|
private int _poolsCount = 0;
|
||||||
|
|
||||||
private EcsSubject[] _subjects;
|
private EcsSubject[] _subjects;
|
||||||
private EcsQueryExecutor[] _executors;
|
private EcsQueryExecutor[] _executors;
|
||||||
|
|
||||||
private EcsPipeline _pipeline;
|
|
||||||
|
|
||||||
private List<WeakReference<EcsGroup>> _groups;
|
private List<WeakReference<EcsGroup>> _groups;
|
||||||
private Stack<EcsGroup> _groupsPool = new Stack<EcsGroup>(64);
|
private Stack<EcsGroup> _groupsPool = new Stack<EcsGroup>(64);
|
||||||
|
|
||||||
private IEcsEntityCreate _entityCreate;
|
private List<IEcsWorldEventListener> _listeners;
|
||||||
private IEcsEntityDestroy _entityDestry;
|
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
public abstract Type Archetype { get; }
|
public abstract Type Archetype { get; }
|
||||||
public int UniqueID => uniqueID;
|
public int UniqueID => uniqueID;
|
||||||
public int Count => _entitiesCount;
|
public int Count => _entitiesCount;
|
||||||
public int Capacity => _entitesCapacity; //_denseEntities.Length;
|
public int Capacity => _entitesCapacity; //_denseEntities.Length;
|
||||||
public EcsPipeline Pipeline => _pipeline;
|
|
||||||
public EcsReadonlyGroup Entities => _allEntites.Readonly;
|
public EcsReadonlyGroup Entities => _allEntites.Readonly;
|
||||||
public ReadOnlySpan<IEcsPoolImplementation> AllPools => pools;
|
public ReadOnlySpan<IEcsPoolImplementation> AllPools => pools;// new ReadOnlySpan<IEcsPoolImplementation>(pools, 0, _poolsCount);
|
||||||
|
public int PoolsCount => _poolsCount;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors/Destroy
|
#region Constructors/Destroy
|
||||||
@ -67,11 +65,13 @@ namespace DCFApixels.DragonECS
|
|||||||
EcsNullWorld nullWorld = new EcsNullWorld();
|
EcsNullWorld nullWorld = new EcsNullWorld();
|
||||||
Worlds[0] = nullWorld;
|
Worlds[0] = nullWorld;
|
||||||
}
|
}
|
||||||
public EcsWorld(EcsPipeline pipline) : this(pipline, true) { }
|
public EcsWorld() : this(true) { }
|
||||||
internal EcsWorld(EcsPipeline pipline, bool isIndexable)
|
internal EcsWorld(bool isIndexable)
|
||||||
{
|
{
|
||||||
_entitesCapacity = 512;
|
_entitesCapacity = 512;
|
||||||
|
|
||||||
|
_listeners = new List<IEcsWorldEventListener>();
|
||||||
|
|
||||||
if (isIndexable)
|
if (isIndexable)
|
||||||
{
|
{
|
||||||
uniqueID = (short)_worldIdDispenser.GetFree();
|
uniqueID = (short)_worldIdDispenser.GetFree();
|
||||||
@ -82,8 +82,6 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
_worldTypeID = WorldMetaStorage.GetWorldId(Archetype);
|
_worldTypeID = WorldMetaStorage.GetWorldId(Archetype);
|
||||||
|
|
||||||
_pipeline = pipline ?? EcsPipeline.Empty;
|
|
||||||
if (!_pipeline.IsInit) pipline.Init();
|
|
||||||
_entityDispenser = new IntDispenser(0);
|
_entityDispenser = new IntDispenser(0);
|
||||||
_nullPool = EcsNullPool.instance;
|
_nullPool = EcsNullPool.instance;
|
||||||
pools = new IEcsPoolImplementation[512];
|
pools = new IEcsPoolImplementation[512];
|
||||||
@ -101,14 +99,8 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
_subjects = new EcsSubject[128];
|
_subjects = new EcsSubject[128];
|
||||||
_executors = new EcsQueryExecutor[128];
|
_executors = new EcsQueryExecutor[128];
|
||||||
|
|
||||||
_entityCreate = _pipeline.GetRunner<IEcsEntityCreate>();
|
|
||||||
_entityDestry = _pipeline.GetRunner<IEcsEntityDestroy>();
|
|
||||||
_pipeline.GetRunner<IEcsInject<EcsWorld>>().Inject(this);
|
|
||||||
_pipeline.GetRunner<IEcsWorldCreate>().OnWorldCreate(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Destroy()
|
public void Destroy()
|
||||||
{
|
{
|
||||||
_entityDispenser = null;
|
_entityDispenser = null;
|
||||||
@ -125,7 +117,6 @@ namespace DCFApixels.DragonECS
|
|||||||
public void DestryWithPipeline()
|
public void DestryWithPipeline()
|
||||||
{
|
{
|
||||||
Destroy();
|
Destroy();
|
||||||
_pipeline.Destroy();
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -151,7 +142,7 @@ namespace DCFApixels.DragonECS
|
|||||||
var pool = new TPool();
|
var pool = new TPool();
|
||||||
pools[uniqueID] = pool;
|
pools[uniqueID] = pool;
|
||||||
pool.OnInit(this, uniqueID);
|
pool.OnInit(this, uniqueID);
|
||||||
|
_poolsCount++;
|
||||||
//EcsDebug.Print(pool.GetType().FullName);
|
//EcsDebug.Print(pool.GetType().FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,7 +280,7 @@ namespace DCFApixels.DragonECS
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Entity
|
#region Entity
|
||||||
public int NewEntity()
|
public int NewEmptyEntity()
|
||||||
{
|
{
|
||||||
int entityID = _entityDispenser.GetFree();
|
int entityID = _entityDispenser.GetFree();
|
||||||
_entitiesCount++;
|
_entitiesCount++;
|
||||||
@ -316,15 +307,17 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
foreach (var item in pools)
|
foreach (var item in pools)
|
||||||
item.OnWorldResize(_gens.Length);
|
item.OnWorldResize(_gens.Length);
|
||||||
|
|
||||||
|
_listeners.InvokeOnWorldResize(_gens.Length);
|
||||||
}
|
}
|
||||||
_gens[entityID] &= GEN_BITS;
|
_gens[entityID] &= GEN_BITS;
|
||||||
_entityCreate.OnEntityCreate(entityID);
|
|
||||||
_allEntites.Add(entityID);
|
_allEntites.Add(entityID);
|
||||||
|
_listeners.InvokeOnNewEntity(entityID);
|
||||||
return entityID;
|
return entityID;
|
||||||
}
|
}
|
||||||
public entlong NewEntityLong()
|
public entlong NewEmptyEntityLong()
|
||||||
{
|
{
|
||||||
int e = NewEntity();
|
int e = NewEmptyEntity();
|
||||||
return GetEntityLong(e);
|
return GetEntityLong(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,7 +327,7 @@ namespace DCFApixels.DragonECS
|
|||||||
_delEntBuffer[_delEntBufferCount++] = entityID;
|
_delEntBuffer[_delEntBufferCount++] = entityID;
|
||||||
_gens[entityID] |= DEATH_GEN_BIT;
|
_gens[entityID] |= DEATH_GEN_BIT;
|
||||||
_entitiesCount--;
|
_entitiesCount--;
|
||||||
_entityDestry.OnEntityDestroy(entityID);
|
_listeners.InvokeOnDelEntity(entityID);
|
||||||
|
|
||||||
if (_delEntBufferCount >= _delEntBuffer.Length)
|
if (_delEntBufferCount >= _delEntBuffer.Length)
|
||||||
ReleaseDelEntityBuffer();
|
ReleaseDelEntityBuffer();
|
||||||
@ -350,12 +343,13 @@ namespace DCFApixels.DragonECS
|
|||||||
ReadOnlySpan<int> buffser = new ReadOnlySpan<int>(_delEntBuffer, 0, _delEntBufferCount);
|
ReadOnlySpan<int> buffser = new ReadOnlySpan<int>(_delEntBuffer, 0, _delEntBufferCount);
|
||||||
foreach (var pool in pools)
|
foreach (var pool in pools)
|
||||||
pool.OnReleaseDelEntityBuffer(buffser);
|
pool.OnReleaseDelEntityBuffer(buffser);
|
||||||
|
_listeners.InvokeOnReleaseDelEntityBuffer(buffser);
|
||||||
for (int i = 0; i < _delEntBufferCount; i++)
|
for (int i = 0; i < _delEntBufferCount; i++)
|
||||||
_entityDispenser.Release(_delEntBuffer[i]);
|
_entityDispenser.Release(_delEntBuffer[i]);
|
||||||
_delEntBufferCount = 0;
|
_delEntBufferCount = 0;
|
||||||
}
|
}
|
||||||
public short GetGen(int entityID) => _gens[entityID];
|
public short GetGen(int entityID) => _gens[entityID];
|
||||||
public short GetComponentCount(int entityID) => _componentCounts[entityID];
|
public short GetComponentsCount(int entityID) => _componentCounts[entityID];
|
||||||
public void DeleteEmptyEntites()
|
public void DeleteEmptyEntites()
|
||||||
{
|
{
|
||||||
foreach (var e in _allEntites)
|
foreach (var e in _allEntites)
|
||||||
@ -365,6 +359,30 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void CopyEntity(int fromEntityID, int toEntityID)
|
||||||
|
{
|
||||||
|
foreach (var pool in pools)
|
||||||
|
{
|
||||||
|
if(pool.Has(fromEntityID))
|
||||||
|
pool.Copy(fromEntityID, toEntityID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public int CloneEntity(int fromEntityID)
|
||||||
|
{
|
||||||
|
int newEntity = NewEmptyEntity();
|
||||||
|
CopyEntity(fromEntityID, newEntity);
|
||||||
|
return newEntity;
|
||||||
|
}
|
||||||
|
public void CloneEntity(int fromEntityID, int toEntityID)
|
||||||
|
{
|
||||||
|
CopyEntity(fromEntityID, toEntityID);
|
||||||
|
foreach (var pool in pools)
|
||||||
|
{
|
||||||
|
if (!pool.Has(fromEntityID)&& pool.Has(toEntityID))
|
||||||
|
pool.Del(toEntityID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal void IncrementEntityComponentCount(int entityID)
|
internal void IncrementEntityComponentCount(int entityID)
|
||||||
{
|
{
|
||||||
@ -374,7 +392,7 @@ namespace DCFApixels.DragonECS
|
|||||||
internal void DecrementEntityComponentCount(int entityID)
|
internal void DecrementEntityComponentCount(int entityID)
|
||||||
{
|
{
|
||||||
var count = --_componentCounts[entityID];
|
var count = --_componentCounts[entityID];
|
||||||
if(count == 0)
|
if(count == 0 && _allEntites.Has(entityID))
|
||||||
DelEntity(entityID);
|
DelEntity(entityID);
|
||||||
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
||||||
@ -406,6 +424,22 @@ namespace DCFApixels.DragonECS
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Debug
|
#region Debug
|
||||||
|
public void GetComponents(int entityID, List<object> list)
|
||||||
|
{
|
||||||
|
list.Clear();
|
||||||
|
var itemsCount = GetComponentsCount(entityID);
|
||||||
|
if (itemsCount == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (var i = 0; i < pools.Length; i++)
|
||||||
|
{
|
||||||
|
if (pools[i].Has(entityID))
|
||||||
|
list.Add(pools[i].GetRaw(entityID));
|
||||||
|
if (list.Count >= itemsCount)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// public int GetComponents(int entity, ref object[] list)
|
// public int GetComponents(int entity, ref object[] list)
|
||||||
// {
|
// {
|
||||||
// var entityOffset = GetRawEntityOffset(entity);
|
// var entityOffset = GetRawEntityOffset(entity);
|
||||||
@ -422,7 +456,7 @@ namespace DCFApixels.DragonECS
|
|||||||
// }
|
// }
|
||||||
// return itemsCount;
|
// return itemsCount;
|
||||||
// }
|
// }
|
||||||
//
|
|
||||||
// public int GetComponentTypes(int entity, ref Type[] list)
|
// public int GetComponentTypes(int entity, ref Type[] list)
|
||||||
// {
|
// {
|
||||||
// var entityOffset = GetRawEntityOffset(entity);
|
// var entityOffset = GetRawEntityOffset(entity);
|
||||||
@ -446,8 +480,8 @@ namespace DCFApixels.DragonECS
|
|||||||
where TWorldArchetype : EcsWorld<TWorldArchetype>
|
where TWorldArchetype : EcsWorld<TWorldArchetype>
|
||||||
{
|
{
|
||||||
public override Type Archetype => typeof(TWorldArchetype);
|
public override Type Archetype => typeof(TWorldArchetype);
|
||||||
public EcsWorld(EcsPipeline pipline) : base(pipline) { }
|
public EcsWorld() : base() { }
|
||||||
internal EcsWorld(EcsPipeline pipline, bool isIndexable) : base(pipline, isIndexable) { }
|
internal EcsWorld(bool isIndexable) : base(isIndexable) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Utils
|
#region Utils
|
||||||
@ -577,4 +611,46 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Callbacks Interface //TODO
|
||||||
|
public interface IEcsWorldEventListener
|
||||||
|
{
|
||||||
|
void OnWorldResize(int newSize);
|
||||||
|
void OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer);
|
||||||
|
void OnWorldDestroy();
|
||||||
|
void OnNewEntity(int entityID);
|
||||||
|
void OnDelEntity(int entityID);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Extensions
|
||||||
|
public static class WorldEventListExtensions
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void InvokeOnWorldResize(this List<IEcsWorldEventListener> self, int newSize)
|
||||||
|
{
|
||||||
|
for (int i = 0, iMax = self.Count; i < iMax; i++) self[i].OnWorldResize(newSize);
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void InvokeOnReleaseDelEntityBuffer(this List<IEcsWorldEventListener> self, ReadOnlySpan<int> buffer)
|
||||||
|
{
|
||||||
|
for (int i = 0, iMax = self.Count; i < iMax; i++) self[i].OnReleaseDelEntityBuffer(buffer);
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void InvokeOnWorldDestroy(this List<IEcsWorldEventListener> self)
|
||||||
|
{
|
||||||
|
for (int i = 0, iMax = self.Count; i < iMax; i++) self[i].OnWorldDestroy();
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void InvokeOnNewEntity(this List<IEcsWorldEventListener> self, int entityID)
|
||||||
|
{
|
||||||
|
for (int i = 0, iMax = self.Count; i < iMax; i++) self[i].OnNewEntity(entityID);
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void InvokeOnDelEntity(this List<IEcsWorldEventListener> self, int entityID)
|
||||||
|
{
|
||||||
|
for (int i = 0, iMax = self.Count; i < iMax; i++) self[i].OnDelEntity(entityID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,11 @@ namespace DCFApixels.DragonECS
|
|||||||
#endif
|
#endif
|
||||||
return group.GetEnumerator();
|
return group.GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return group.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,8 @@ namespace DCFApixels.DragonECS
|
|||||||
private bool[] _entityFlags;// index = entityID / value = entityFlag;/ value = 0 = no entityID
|
private bool[] _entityFlags;// index = entityID / value = entityFlag;/ value = 0 = no entityID
|
||||||
private T[] _items; //sparse
|
private T[] _items; //sparse
|
||||||
private int _count;
|
private int _count;
|
||||||
private PoolRunners _poolRunners;
|
|
||||||
|
private List<IEcsPoolEventListener> _listeners;
|
||||||
|
|
||||||
private EcsGroup _entities;
|
private EcsGroup _entities;
|
||||||
public EcsReadonlyGroup Entities
|
public EcsReadonlyGroup Entities
|
||||||
@ -47,7 +48,7 @@ namespace DCFApixels.DragonECS
|
|||||||
_source = world;
|
_source = world;
|
||||||
_id = componentID;
|
_id = componentID;
|
||||||
|
|
||||||
_poolRunners = new PoolRunners(world.Pipeline);
|
_listeners = new List<IEcsPoolEventListener>();
|
||||||
|
|
||||||
_entities = EcsGroup.New(world);
|
_entities = EcsGroup.New(world);
|
||||||
|
|
||||||
@ -71,9 +72,9 @@ namespace DCFApixels.DragonECS
|
|||||||
entityFlag = true;
|
entityFlag = true;
|
||||||
_count++;
|
_count++;
|
||||||
_entities.Add(entityID);
|
_entities.Add(entityID);
|
||||||
_poolRunners.add.OnComponentAdd<T>(entityID);
|
foreach (var item in _listeners) item.OnAdd(entityID);
|
||||||
}
|
}
|
||||||
_poolRunners.write.OnComponentWrite<T>(entityID);
|
foreach (var item in _listeners) item.OnWrite(entityID);
|
||||||
_items[entityID].Target = target;
|
_items[entityID].Target = target;
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@ -84,7 +85,7 @@ namespace DCFApixels.DragonECS
|
|||||||
if (_sanitizeTargetWorld >= 0 && target.world != _sanitizeTargetWorld) ThrowWorldDifferent<T>(entityID);
|
if (_sanitizeTargetWorld >= 0 && target.world != _sanitizeTargetWorld) ThrowWorldDifferent<T>(entityID);
|
||||||
_sanitizeTargetWorld = target.world;
|
_sanitizeTargetWorld = target.world;
|
||||||
#endif
|
#endif
|
||||||
_poolRunners.write.OnComponentWrite<T>(entityID);
|
_listeners.InvokeOnWrite(entityID);
|
||||||
_items[entityID].Target = target;
|
_items[entityID].Target = target;
|
||||||
}
|
}
|
||||||
public void AddOrSet(int entityID, entlong target)
|
public void AddOrSet(int entityID, entlong target)
|
||||||
@ -115,7 +116,7 @@ namespace DCFApixels.DragonECS
|
|||||||
_entities.Remove(entityID);
|
_entities.Remove(entityID);
|
||||||
_entityFlags[entityID] = false;
|
_entityFlags[entityID] = false;
|
||||||
_count--;
|
_count--;
|
||||||
_poolRunners.del.OnComponentDel<T>(entityID);
|
_listeners.InvokeOnDel(entityID);
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void TryDel(int entityID)
|
public void TryDel(int entityID)
|
||||||
@ -132,6 +133,16 @@ namespace DCFApixels.DragonECS
|
|||||||
else
|
else
|
||||||
Add(toEntityID, Read(fromEntityID).Target);
|
Add(toEntityID, Read(fromEntityID).Target);
|
||||||
}
|
}
|
||||||
|
public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
|
||||||
|
{
|
||||||
|
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
||||||
|
if (!Has(fromEntityID)) ThrowNotHaveComponent<T>(fromEntityID);
|
||||||
|
#endif
|
||||||
|
if (Has(toEntityID))
|
||||||
|
toWorld.GetPool<T>().Set(toEntityID, Read(fromEntityID).Target);
|
||||||
|
else
|
||||||
|
toWorld.GetPool<T>().Add(toEntityID, Read(fromEntityID).Target);
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region WorldCallbacks
|
#region WorldCallbacks
|
||||||
@ -167,6 +178,19 @@ namespace DCFApixels.DragonECS
|
|||||||
void IEcsPool.SetRaw(int entityID, object dataRaw) => ((IEcsPool<T>)this).Write(entityID) = (T)dataRaw;
|
void IEcsPool.SetRaw(int entityID, object dataRaw) => ((IEcsPool<T>)this).Write(entityID) = (T)dataRaw;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Listeners
|
||||||
|
public void AddListener(IEcsPoolEventListener listener)
|
||||||
|
{
|
||||||
|
if (listener == null) { throw new ArgumentNullException("listener is null"); }
|
||||||
|
_listeners.Add(listener);
|
||||||
|
}
|
||||||
|
public void RemoveListener(IEcsPoolEventListener listener)
|
||||||
|
{
|
||||||
|
if (listener == null) { throw new ArgumentNullException("listener is null"); }
|
||||||
|
_listeners.Remove(listener);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region IEnumerator - IntelliSense hack
|
#region IEnumerator - IntelliSense hack
|
||||||
IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw new NotImplementedException();
|
IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw new NotImplementedException();
|
||||||
IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException();
|
IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException();
|
||||||
|
@ -18,7 +18,8 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
private IEcsComponentReset<T> _componentResetHandler;
|
private IEcsComponentReset<T> _componentResetHandler;
|
||||||
private IEcsComponentCopy<T> _componentCopyHandler;
|
private IEcsComponentCopy<T> _componentCopyHandler;
|
||||||
private PoolRunners _poolRunners;
|
|
||||||
|
private List<IEcsPoolEventListener> _listeners;
|
||||||
|
|
||||||
#region Properites
|
#region Properites
|
||||||
public int Count => _count;
|
public int Count => _count;
|
||||||
@ -37,8 +38,10 @@ namespace DCFApixels.DragonECS
|
|||||||
_items = new T[world.Capacity];
|
_items = new T[world.Capacity];
|
||||||
_count = 0;
|
_count = 0;
|
||||||
|
|
||||||
|
_listeners = new List<IEcsPoolEventListener>();
|
||||||
|
|
||||||
_componentResetHandler = EcsComponentResetHandler<T>.instance;
|
_componentResetHandler = EcsComponentResetHandler<T>.instance;
|
||||||
_poolRunners = new PoolRunners(world.Pipeline);
|
_componentCopyHandler = EcsComponentCopyHandler<T>.instance;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -46,7 +49,7 @@ namespace DCFApixels.DragonECS
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public ref T Write(int entityID)
|
public ref T Write(int entityID)
|
||||||
{
|
{
|
||||||
_poolRunners.write.OnComponentWrite<T>(entityID);
|
_listeners.InvokeOnWrite(entityID);
|
||||||
return ref _items[entityID];
|
return ref _items[entityID];
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@ -63,6 +66,10 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
_componentCopyHandler.Copy(ref Write(fromEntityID), ref Write(toEntityID));
|
_componentCopyHandler.Copy(ref Write(fromEntityID), ref Write(toEntityID));
|
||||||
}
|
}
|
||||||
|
public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
|
||||||
|
{
|
||||||
|
_componentCopyHandler.Copy(ref Write(fromEntityID), ref toWorld.GetPool<T>().Write(toEntityID));
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Callbacks
|
#region Callbacks
|
||||||
@ -88,6 +95,19 @@ namespace DCFApixels.DragonECS
|
|||||||
void IEcsPool.SetRaw(int entityID, object dataRaw) => Write(entityID) = (T)dataRaw;
|
void IEcsPool.SetRaw(int entityID, object dataRaw) => Write(entityID) = (T)dataRaw;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Listeners
|
||||||
|
public void AddListener(IEcsPoolEventListener listener)
|
||||||
|
{
|
||||||
|
if (listener == null) { throw new ArgumentNullException("listener is null"); }
|
||||||
|
_listeners.Add(listener);
|
||||||
|
}
|
||||||
|
public void RemoveListener(IEcsPoolEventListener listener)
|
||||||
|
{
|
||||||
|
if (listener == null) { throw new ArgumentNullException("listener is null"); }
|
||||||
|
_listeners.Remove(listener);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region IEnumerator - IntelliSense hack
|
#region IEnumerator - IntelliSense hack
|
||||||
IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw new NotImplementedException();
|
IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw new NotImplementedException();
|
||||||
IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException();
|
IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException();
|
||||||
|
@ -21,7 +21,8 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
private IEcsComponentReset<T> _componentResetHandler;
|
private IEcsComponentReset<T> _componentResetHandler;
|
||||||
private IEcsComponentCopy<T> _componentCopyHandler;
|
private IEcsComponentCopy<T> _componentCopyHandler;
|
||||||
private PoolRunners _poolRunners;
|
|
||||||
|
private List<IEcsPoolEventListener> _listeners;
|
||||||
|
|
||||||
#region Properites
|
#region Properites
|
||||||
public int Count => _itemsCount;
|
public int Count => _itemsCount;
|
||||||
@ -45,9 +46,10 @@ namespace DCFApixels.DragonECS
|
|||||||
_items = new T[capacity];
|
_items = new T[capacity];
|
||||||
_itemsCount = 0;
|
_itemsCount = 0;
|
||||||
|
|
||||||
|
_listeners = new List<IEcsPoolEventListener>();
|
||||||
|
|
||||||
_componentResetHandler = EcsComponentResetHandler<T>.instance;
|
_componentResetHandler = EcsComponentResetHandler<T>.instance;
|
||||||
_componentCopyHandler = EcsComponentCopyHandler<T>.instance;
|
_componentCopyHandler = EcsComponentCopyHandler<T>.instance;
|
||||||
_poolRunners = new PoolRunners(world.Pipeline);
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -72,8 +74,7 @@ namespace DCFApixels.DragonECS
|
|||||||
Array.Resize(ref _items, _items.Length << 1);
|
Array.Resize(ref _items, _items.Length << 1);
|
||||||
}
|
}
|
||||||
this.IncrementEntityComponentCount(entityID);
|
this.IncrementEntityComponentCount(entityID);
|
||||||
_poolRunners.add.OnComponentAdd<T>(entityID);
|
_listeners.InvokeOnAddAndWrite(entityID);
|
||||||
_poolRunners.write.OnComponentWrite<T>(entityID);
|
|
||||||
return ref _items[itemIndex];
|
return ref _items[itemIndex];
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
@ -84,7 +85,7 @@ namespace DCFApixels.DragonECS
|
|||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
||||||
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
||||||
#endif
|
#endif
|
||||||
_poolRunners.write.OnComponentWrite<T>(entityID);
|
_listeners.InvokeOnWrite(entityID);
|
||||||
return ref _items[_mapping[entityID]];
|
return ref _items[_mapping[entityID]];
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@ -113,9 +114,9 @@ namespace DCFApixels.DragonECS
|
|||||||
Array.Resize(ref _items, _items.Length << 1);
|
Array.Resize(ref _items, _items.Length << 1);
|
||||||
}
|
}
|
||||||
this.IncrementEntityComponentCount(entityID);
|
this.IncrementEntityComponentCount(entityID);
|
||||||
_poolRunners.add.OnComponentAdd<T>(entityID);
|
_listeners.InvokeOnAdd(entityID);
|
||||||
}
|
}
|
||||||
_poolRunners.write.OnComponentWrite<T>(entityID);
|
_listeners.InvokeOnWrite(entityID);
|
||||||
return ref _items[itemIndex];
|
return ref _items[itemIndex];
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@ -136,7 +137,7 @@ namespace DCFApixels.DragonECS
|
|||||||
_mapping[entityID] = 0;
|
_mapping[entityID] = 0;
|
||||||
_itemsCount--;
|
_itemsCount--;
|
||||||
this.DecrementEntityComponentCount(entityID);
|
this.DecrementEntityComponentCount(entityID);
|
||||||
_poolRunners.del.OnComponentDel<T>(entityID);
|
_listeners.InvokeOnDel(entityID);
|
||||||
}
|
}
|
||||||
public void TryDel(int entityID)
|
public void TryDel(int entityID)
|
||||||
{
|
{
|
||||||
@ -147,10 +148,14 @@ namespace DCFApixels.DragonECS
|
|||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
||||||
if (!Has(fromEntityID)) ThrowNotHaveComponent<T>(fromEntityID);
|
if (!Has(fromEntityID)) ThrowNotHaveComponent<T>(fromEntityID);
|
||||||
#endif
|
#endif
|
||||||
if (Has(toEntityID))
|
_componentCopyHandler.Copy(ref Write(fromEntityID), ref TryAddOrWrite(toEntityID));
|
||||||
_componentCopyHandler.Copy(ref Write(fromEntityID), ref Write(toEntityID));
|
}
|
||||||
else
|
public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
|
||||||
_componentCopyHandler.Copy(ref Write(fromEntityID), ref Add(toEntityID));
|
{
|
||||||
|
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
||||||
|
if (!Has(fromEntityID)) ThrowNotHaveComponent<T>(fromEntityID);
|
||||||
|
#endif
|
||||||
|
_componentCopyHandler.Copy(ref Write(fromEntityID), ref toWorld.GetPool<T>().TryAddOrWrite(toEntityID));
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -175,6 +180,19 @@ namespace DCFApixels.DragonECS
|
|||||||
ref T IEcsPool<T>.Write(int entityID) => ref Write(entityID);
|
ref T IEcsPool<T>.Write(int entityID) => ref Write(entityID);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Listeners
|
||||||
|
public void AddListener(IEcsPoolEventListener listener)
|
||||||
|
{
|
||||||
|
if(listener == null) { throw new ArgumentNullException("listener is null"); }
|
||||||
|
_listeners.Add(listener);
|
||||||
|
}
|
||||||
|
public void RemoveListener(IEcsPoolEventListener listener)
|
||||||
|
{
|
||||||
|
if(listener == null) { throw new ArgumentNullException("listener is null"); }
|
||||||
|
_listeners.Remove(listener);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region IEnumerator - IntelliSense hack
|
#region IEnumerator - IntelliSense hack
|
||||||
IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw new NotImplementedException();
|
IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw new NotImplementedException();
|
||||||
IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException();
|
IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException();
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
using System;
|
using DCFApixels.DragonECS.Internal;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
@ -21,7 +23,22 @@ namespace DCFApixels.DragonECS
|
|||||||
object GetRaw(int entityID);
|
object GetRaw(int entityID);
|
||||||
void SetRaw(int entityID, object dataRaw);
|
void SetRaw(int entityID, object dataRaw);
|
||||||
void Copy(int fromEntityID, int toEntityID);
|
void Copy(int fromEntityID, int toEntityID);
|
||||||
|
void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Add/Remove Listeners
|
||||||
|
void AddListener(IEcsPoolEventListener listener);
|
||||||
|
void RemoveListener(IEcsPoolEventListener listener);
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
public interface IEcsPoolEventListener
|
||||||
|
{
|
||||||
|
/// <summary>Called after adding an entity to the pool, but before changing values.</summary>
|
||||||
|
void OnAdd(int entityID);
|
||||||
|
/// <summary>Is called when EcsPool.Write or EcsPool.Add is called, but before changing values.</summary>
|
||||||
|
void OnWrite(int entityID);
|
||||||
|
/// <summary>Called after deleting an entity from the pool</summary>
|
||||||
|
void OnDel(int entityID);
|
||||||
}
|
}
|
||||||
public interface IEcsPool<T>
|
public interface IEcsPool<T>
|
||||||
{
|
{
|
||||||
@ -41,6 +58,7 @@ namespace DCFApixels.DragonECS
|
|||||||
/// <summary>Only used to implement a custom pool. In other contexts use IEcsPool or IEcsPool<T>.</summary>
|
/// <summary>Only used to implement a custom pool. In other contexts use IEcsPool or IEcsPool<T>.</summary>
|
||||||
/// <typeparam name="T">Component type</typeparam>
|
/// <typeparam name="T">Component type</typeparam>
|
||||||
public interface IEcsPoolImplementation<T> : IEcsPool<T>, IEcsPoolImplementation { }
|
public interface IEcsPoolImplementation<T> : IEcsPool<T>, IEcsPoolImplementation { }
|
||||||
|
|
||||||
public static class EcsPoolThrowHalper
|
public static class EcsPoolThrowHalper
|
||||||
{
|
{
|
||||||
public static void ThrowAlreadyHasComponent<T>(int entityID)
|
public static void ThrowAlreadyHasComponent<T>(int entityID)
|
||||||
@ -76,7 +94,7 @@ namespace DCFApixels.DragonECS
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static bool IsNullOrDummy(this IEcsPool self)
|
public static bool IsNullOrDummy(this IEcsPool self)
|
||||||
{
|
{
|
||||||
return self == null || self is Internal.EcsNullPool;
|
return self == null || self == EcsNullPool.instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,11 +107,11 @@ namespace DCFApixels.DragonECS
|
|||||||
public static EcsNullPool instance => new EcsNullPool();
|
public static EcsNullPool instance => new EcsNullPool();
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
int IEcsPool.ComponentID => throw new NotImplementedException();
|
int IEcsPool.ComponentID => -1;
|
||||||
Type IEcsPool.ComponentType => typeof(NullComponent);
|
Type IEcsPool.ComponentType => typeof(NullComponent);
|
||||||
EcsWorld IEcsPool.World => throw new NotImplementedException();
|
EcsWorld IEcsPool.World => throw new NotImplementedException();
|
||||||
public int Count => 0;
|
public int Count => -1;
|
||||||
public int Capacity => 0;
|
public int Capacity => -1;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
@ -103,6 +121,7 @@ namespace DCFApixels.DragonECS
|
|||||||
object IEcsPool.GetRaw(int entityID) => throw new NotImplementedException();
|
object IEcsPool.GetRaw(int entityID) => throw new NotImplementedException();
|
||||||
void IEcsPool.SetRaw(int entity, object dataRaw) => throw new NotImplementedException();
|
void IEcsPool.SetRaw(int entity, object dataRaw) => throw new NotImplementedException();
|
||||||
void IEcsPool.Copy(int fromEntityID, int toEntityID) => throw new NotImplementedException();
|
void IEcsPool.Copy(int fromEntityID, int toEntityID) => throw new NotImplementedException();
|
||||||
|
void IEcsPool.Copy(int fromEntityID, EcsWorld toWorld, int toEntityID) => throw new NotImplementedException();
|
||||||
ref NullComponent IEcsPool<NullComponent>.Add(int entityID) => throw new NotImplementedException();
|
ref NullComponent IEcsPool<NullComponent>.Add(int entityID) => throw new NotImplementedException();
|
||||||
ref readonly NullComponent IEcsPool<NullComponent>.Read(int entityID) => throw new NotImplementedException();
|
ref readonly NullComponent IEcsPool<NullComponent>.Read(int entityID) => throw new NotImplementedException();
|
||||||
ref NullComponent IEcsPool<NullComponent>.Write(int entityID) => throw new NotImplementedException();
|
ref NullComponent IEcsPool<NullComponent>.Write(int entityID) => throw new NotImplementedException();
|
||||||
@ -114,6 +133,11 @@ namespace DCFApixels.DragonECS
|
|||||||
void IEcsPoolImplementation.OnWorldResize(int newSize) { }
|
void IEcsPoolImplementation.OnWorldResize(int newSize) { }
|
||||||
void IEcsPoolImplementation.OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer) { }
|
void IEcsPoolImplementation.OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer) { }
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Listeners
|
||||||
|
public void AddListener(IEcsPoolEventListener listener) { }
|
||||||
|
public void RemoveListener(IEcsPoolEventListener listener) { }
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
@ -191,4 +215,34 @@ namespace DCFApixels.DragonECS
|
|||||||
public void Copy(ref T from, ref T to) => _fakeInstnace.Copy(ref from, ref to);
|
public void Copy(ref T from, ref T to) => _fakeInstnace.Copy(ref from, ref to);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Extensions
|
||||||
|
public static class PoolEventListExtensions
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void InvokeOnAdd(this List<IEcsPoolEventListener> self, int entityID)
|
||||||
|
{
|
||||||
|
for (int i = 0, iMax = self.Count; i < iMax; i++) self[i].OnAdd(entityID);
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void InvokeOnAddAndWrite(this List<IEcsPoolEventListener> self, int entityID)
|
||||||
|
{
|
||||||
|
for (int i = 0, iMax = self.Count; i < iMax; i++)
|
||||||
|
{
|
||||||
|
self[i].OnAdd(entityID);
|
||||||
|
self[i].OnWrite(entityID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void InvokeOnWrite(this List<IEcsPoolEventListener> self, int entityID)
|
||||||
|
{
|
||||||
|
for (int i = 0, iMax = self.Count; i < iMax; i++) self[i].OnWrite(entityID);
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void InvokeOnDel(this List<IEcsPoolEventListener> self, int entityID)
|
||||||
|
{
|
||||||
|
for (int i = 0, iMax = self.Count; i < iMax; i++) self[i].OnDel(entityID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ namespace DCFApixels.DragonECS
|
|||||||
private int _count;
|
private int _count;
|
||||||
private T _component;
|
private T _component;
|
||||||
|
|
||||||
private PoolRunners _poolRunners;
|
private List<IEcsPoolEventListener> _listeners;
|
||||||
|
|
||||||
#region Properites
|
#region Properites
|
||||||
public ref T Instance
|
public ref T Instance
|
||||||
@ -40,7 +40,7 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
_mapping = new int[world.Capacity];
|
_mapping = new int[world.Capacity];
|
||||||
_count = 0;
|
_count = 0;
|
||||||
_poolRunners = new PoolRunners(world.Pipeline);
|
_listeners = new List<IEcsPoolEventListener>();
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -52,7 +52,7 @@ namespace DCFApixels.DragonECS
|
|||||||
#endif
|
#endif
|
||||||
_mapping[entityID] = ++_count;
|
_mapping[entityID] = ++_count;
|
||||||
this.IncrementEntityComponentCount(entityID);
|
this.IncrementEntityComponentCount(entityID);
|
||||||
_poolRunners.add.OnComponentAdd<T>(entityID);
|
_listeners.InvokeOnAddAndWrite(entityID);
|
||||||
return ref _component;
|
return ref _component;
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@ -61,7 +61,7 @@ namespace DCFApixels.DragonECS
|
|||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
||||||
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
||||||
#endif
|
#endif
|
||||||
_poolRunners.write.OnComponentWrite<T>(entityID);
|
_listeners.InvokeOnWrite(entityID);
|
||||||
return ref _component;
|
return ref _component;
|
||||||
}
|
}
|
||||||
public ref T TryAddOrWrite(int entityID)
|
public ref T TryAddOrWrite(int entityID)
|
||||||
@ -92,7 +92,7 @@ namespace DCFApixels.DragonECS
|
|||||||
_mapping[entityID] = 0;
|
_mapping[entityID] = 0;
|
||||||
_count--;
|
_count--;
|
||||||
this.DecrementEntityComponentCount(entityID);
|
this.DecrementEntityComponentCount(entityID);
|
||||||
_poolRunners.del.OnComponentDel<T>(entityID);
|
_listeners.InvokeOnDel(entityID);
|
||||||
}
|
}
|
||||||
public void TryDel(int entityID)
|
public void TryDel(int entityID)
|
||||||
{
|
{
|
||||||
@ -105,6 +105,13 @@ namespace DCFApixels.DragonECS
|
|||||||
#endif
|
#endif
|
||||||
TryAddOrWrite(toEntityID);
|
TryAddOrWrite(toEntityID);
|
||||||
}
|
}
|
||||||
|
public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
|
||||||
|
{
|
||||||
|
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
||||||
|
if (!Has(fromEntityID)) ThrowNotHaveComponent<T>(fromEntityID);
|
||||||
|
#endif
|
||||||
|
toWorld.GetPool<T>().TryAddOrWrite(toEntityID);
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Callbacks
|
#region Callbacks
|
||||||
@ -126,6 +133,19 @@ namespace DCFApixels.DragonECS
|
|||||||
void IEcsPool.SetRaw(int entityID, object dataRaw) => Instance = (T)dataRaw;
|
void IEcsPool.SetRaw(int entityID, object dataRaw) => Instance = (T)dataRaw;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Listeners
|
||||||
|
public void AddListener(IEcsPoolEventListener listener)
|
||||||
|
{
|
||||||
|
if (listener == null) { throw new ArgumentNullException("listener is null"); }
|
||||||
|
_listeners.Add(listener);
|
||||||
|
}
|
||||||
|
public void RemoveListener(IEcsPoolEventListener listener)
|
||||||
|
{
|
||||||
|
if (listener == null) { throw new ArgumentNullException("listener is null"); }
|
||||||
|
_listeners.Remove(listener);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region IEnumerator - IntelliSense hack
|
#region IEnumerator - IntelliSense hack
|
||||||
IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw new NotImplementedException();
|
IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw new NotImplementedException();
|
||||||
IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException();
|
IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException();
|
||||||
|
@ -15,7 +15,7 @@ namespace DCFApixels.DragonECS
|
|||||||
private bool[] _mapping;// index = entityID / value = itemIndex;/ value = 0 = no entityID
|
private bool[] _mapping;// index = entityID / value = itemIndex;/ value = 0 = no entityID
|
||||||
private int _count;
|
private int _count;
|
||||||
|
|
||||||
private PoolRunners _poolRunners;
|
private List<IEcsPoolEventListener> _listeners;
|
||||||
|
|
||||||
private T _fakeComponent;
|
private T _fakeComponent;
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ namespace DCFApixels.DragonECS
|
|||||||
_mapping = new bool[world.Capacity];
|
_mapping = new bool[world.Capacity];
|
||||||
_count = 0;
|
_count = 0;
|
||||||
|
|
||||||
_poolRunners = new PoolRunners(world.Pipeline);
|
_listeners = new List<IEcsPoolEventListener>();
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ namespace DCFApixels.DragonECS
|
|||||||
_count++;
|
_count++;
|
||||||
_mapping[entityID] = true;
|
_mapping[entityID] = true;
|
||||||
this.IncrementEntityComponentCount(entityID);
|
this.IncrementEntityComponentCount(entityID);
|
||||||
_poolRunners.add.OnComponentAdd<T>(entityID);
|
_listeners.InvokeOnAdd(entityID);
|
||||||
}
|
}
|
||||||
public void TryAdd(int entityID)
|
public void TryAdd(int entityID)
|
||||||
{
|
{
|
||||||
@ -58,7 +58,7 @@ namespace DCFApixels.DragonECS
|
|||||||
_count++;
|
_count++;
|
||||||
_mapping[entityID] = true;
|
_mapping[entityID] = true;
|
||||||
this.IncrementEntityComponentCount(entityID);
|
this.IncrementEntityComponentCount(entityID);
|
||||||
_poolRunners.add.OnComponentAdd<T>(entityID);
|
_listeners.InvokeOnAdd(entityID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@ -74,7 +74,7 @@ namespace DCFApixels.DragonECS
|
|||||||
_mapping[entityID] = false;
|
_mapping[entityID] = false;
|
||||||
_count--;
|
_count--;
|
||||||
this.DecrementEntityComponentCount(entityID);
|
this.DecrementEntityComponentCount(entityID);
|
||||||
_poolRunners.del.OnComponentDel<T>(entityID);
|
_listeners.InvokeOnDel(entityID);
|
||||||
}
|
}
|
||||||
public void TryDel(int entityID)
|
public void TryDel(int entityID)
|
||||||
{
|
{
|
||||||
@ -87,6 +87,13 @@ namespace DCFApixels.DragonECS
|
|||||||
#endif
|
#endif
|
||||||
TryAdd(toEntityID);
|
TryAdd(toEntityID);
|
||||||
}
|
}
|
||||||
|
public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
|
||||||
|
{
|
||||||
|
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
||||||
|
if (!Has(fromEntityID)) ThrowNotHaveComponent<T>(fromEntityID);
|
||||||
|
#endif
|
||||||
|
toWorld.GetPool<T>().TryAdd(toEntityID);
|
||||||
|
}
|
||||||
public void Set(int entityID, bool isHas)
|
public void Set(int entityID, bool isHas)
|
||||||
{
|
{
|
||||||
if (isHas)
|
if (isHas)
|
||||||
@ -100,6 +107,13 @@ namespace DCFApixels.DragonECS
|
|||||||
Del(entityID);
|
Del(entityID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public void Toggle(int entityID)
|
||||||
|
{
|
||||||
|
if (Has(entityID))
|
||||||
|
Del(entityID);
|
||||||
|
else
|
||||||
|
Add(entityID);
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Callbacks
|
#region Callbacks
|
||||||
@ -152,6 +166,19 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Listeners
|
||||||
|
public void AddListener(IEcsPoolEventListener listener)
|
||||||
|
{
|
||||||
|
if (listener == null) { throw new ArgumentNullException("listener is null"); }
|
||||||
|
_listeners.Add(listener);
|
||||||
|
}
|
||||||
|
public void RemoveListener(IEcsPoolEventListener listener)
|
||||||
|
{
|
||||||
|
if (listener == null) { throw new ArgumentNullException("listener is null"); }
|
||||||
|
_listeners.Remove(listener);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region IEnumerator - IntelliSense hack
|
#region IEnumerator - IntelliSense hack
|
||||||
IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw new NotImplementedException();
|
IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw new NotImplementedException();
|
||||||
IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException();
|
IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException();
|
||||||
|
@ -8,30 +8,22 @@ namespace DCFApixels.DragonECS
|
|||||||
public static void Fill<T>(T[] array, T value, int startIndex = 0, int length = -1)
|
public static void Fill<T>(T[] array, T value, int startIndex = 0, int length = -1)
|
||||||
{
|
{
|
||||||
if (length < 0)
|
if (length < 0)
|
||||||
{
|
|
||||||
length = array.Length;
|
length = array.Length;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
length = startIndex + length;
|
length = startIndex + length;
|
||||||
}
|
|
||||||
for (int i = startIndex; i < length; i++)
|
for (int i = startIndex; i < length; i++)
|
||||||
{
|
|
||||||
array[i] = value;
|
array[i] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
internal static unsafe class UnmanagedArray
|
internal static unsafe class UnmanagedArrayUtility
|
||||||
{
|
{
|
||||||
public static void* New<T>(int elementCount)
|
public static void* New<T>(int elementCount) where T : struct
|
||||||
where T : struct
|
|
||||||
{
|
{
|
||||||
return Marshal.AllocHGlobal(Marshal.SizeOf(typeof(T)) * elementCount).ToPointer();
|
return Marshal.AllocHGlobal(Marshal.SizeOf(typeof(T)) * elementCount).ToPointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void* NewAndInit<T>(int elementCount)
|
public static void* NewAndInit<T>(int elementCount) where T : struct
|
||||||
where T : struct
|
|
||||||
{
|
{
|
||||||
int newSizeInBytes = Marshal.SizeOf(typeof(T)) * elementCount;
|
int newSizeInBytes = Marshal.SizeOf(typeof(T)) * elementCount;
|
||||||
byte* newArrayPointer = (byte*)Marshal.AllocHGlobal(newSizeInBytes).ToPointer();
|
byte* newArrayPointer = (byte*)Marshal.AllocHGlobal(newSizeInBytes).ToPointer();
|
||||||
@ -39,7 +31,7 @@ namespace DCFApixels.DragonECS
|
|||||||
for (int i = 0; i < newSizeInBytes; i++)
|
for (int i = 0; i < newSizeInBytes; i++)
|
||||||
*(newArrayPointer + i) = 0;
|
*(newArrayPointer + i) = 0;
|
||||||
|
|
||||||
return (void*)newArrayPointer;
|
return newArrayPointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Free(void* pointerToUnmanagedMemory)
|
public static void Free(void* pointerToUnmanagedMemory)
|
||||||
@ -47,8 +39,7 @@ namespace DCFApixels.DragonECS
|
|||||||
Marshal.FreeHGlobal(new IntPtr(pointerToUnmanagedMemory));
|
Marshal.FreeHGlobal(new IntPtr(pointerToUnmanagedMemory));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void* Resize<T>(void* oldPointer, int newElementCount)
|
public static void* Resize<T>(void* oldPointer, int newElementCount) where T : struct
|
||||||
where T : struct
|
|
||||||
{
|
{
|
||||||
return (Marshal.ReAllocHGlobal(new IntPtr(oldPointer),
|
return (Marshal.ReAllocHGlobal(new IntPtr(oldPointer),
|
||||||
new IntPtr(Marshal.SizeOf(typeof(T)) * newElementCount))).ToPointer();
|
new IntPtr(Marshal.SizeOf(typeof(T)) * newElementCount))).ToPointer();
|
||||||
|
10
src/Utils/Extensions.cs
Normal file
10
src/Utils/Extensions.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace DCFApixels.DragonECS
|
||||||
|
{
|
||||||
|
public static class Extensions
|
||||||
|
{
|
||||||
|
public static entlong ToEntityLong(this int self, EcsWorld world)
|
||||||
|
{
|
||||||
|
return world.GetEntityLong(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,42 +1,49 @@
|
|||||||
using System;
|
//SparseArray. Analogous to Dictionary<int, T>, but faster.
|
||||||
|
//Benchmark result of indexer.get speed test with 300 elements:
|
||||||
|
//[Dictinary: 5.786us] [SparseArray: 2.047us].
|
||||||
|
using System;
|
||||||
using System.Diagnostics.Contracts;
|
using System.Diagnostics.Contracts;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace DCFApixels
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
public class SparseArray<TValue>
|
public class SparseArray<TValue>
|
||||||
{
|
{
|
||||||
public const int MIN_CAPACITY = 16;
|
public const int MIN_CAPACITY_BITS_OFFSET = 4;
|
||||||
|
public const int MIN_CAPACITY = 1 << MIN_CAPACITY_BITS_OFFSET;
|
||||||
private const int EMPTY = -1;
|
private const int EMPTY = -1;
|
||||||
|
|
||||||
private int[] _buckets = Array.Empty<int>();
|
private int[] _buckets = Array.Empty<int>();
|
||||||
private Entry[] _entries = Array.Empty<Entry>();
|
private Entry[] _entries = Array.Empty<Entry>();
|
||||||
|
private int[] _dense;
|
||||||
|
|
||||||
private int _count;
|
private int _count;
|
||||||
|
|
||||||
private int _freeList;
|
private int _freeList;
|
||||||
private int _freeCount;
|
private int _freeCount;
|
||||||
|
|
||||||
|
private int _modBitMask;
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
public TValue this[int key]
|
public ref TValue this[int key]
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
get => ref _entries[FindEntry(key)].value;
|
||||||
get => _entries[FindEntry(key)].value;
|
//set => Insert(key, value);
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
set => Insert(key, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Count => _count;
|
public int Count => _count;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
public SparseArray(int capacity = MIN_CAPACITY)
|
public SparseArray(int minCapacity = MIN_CAPACITY)
|
||||||
{
|
{
|
||||||
_buckets = new int[capacity];
|
minCapacity = NormalizeCapacity(minCapacity);
|
||||||
for (int i = 0; i < capacity; i++)
|
_buckets = new int[minCapacity];
|
||||||
|
for (int i = 0; i < minCapacity; i++)
|
||||||
_buckets[i] = EMPTY;
|
_buckets[i] = EMPTY;
|
||||||
_entries = new Entry[capacity];
|
_entries = new Entry[minCapacity];
|
||||||
|
_modBitMask = (minCapacity - 1) & 0x7FFFFFFF;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -53,19 +60,16 @@ namespace DCFApixels
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Find/Insert/Remove
|
#region Find/Insert/Remove
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private int FindEntry(int key)
|
private int FindEntry(int key)
|
||||||
{
|
{
|
||||||
key &= 0x7FFFFFFF;
|
for (int i = _buckets[key & _modBitMask]; i >= 0; i = _entries[i].next)
|
||||||
for (int i = _buckets[key % _buckets.Length]; i >= 0; i = _entries[i].next)
|
|
||||||
{
|
|
||||||
if (_entries[i].hashKey == key) return i;
|
if (_entries[i].hashKey == key) return i;
|
||||||
}
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
private void Insert(int key, TValue value)
|
private void Insert(int key, TValue value)
|
||||||
{
|
{
|
||||||
key &= 0x7FFFFFFF;
|
int targetBucket = key & _modBitMask;
|
||||||
int targetBucket = key % _buckets.Length;
|
|
||||||
|
|
||||||
for (int i = _buckets[targetBucket]; i >= 0; i = _entries[i].next)
|
for (int i = _buckets[targetBucket]; i >= 0; i = _entries[i].next)
|
||||||
{
|
{
|
||||||
@ -88,10 +92,9 @@ namespace DCFApixels
|
|||||||
if (_count == _entries.Length)
|
if (_count == _entries.Length)
|
||||||
{
|
{
|
||||||
Resize();
|
Resize();
|
||||||
targetBucket = key % _buckets.Length;
|
targetBucket = key & _modBitMask;
|
||||||
}
|
}
|
||||||
index = _count;
|
index = _count++;
|
||||||
_count++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_entries[index].next = _buckets[targetBucket];
|
_entries[index].next = _buckets[targetBucket];
|
||||||
@ -101,8 +104,7 @@ namespace DCFApixels
|
|||||||
}
|
}
|
||||||
public bool Remove(int key)
|
public bool Remove(int key)
|
||||||
{
|
{
|
||||||
key &= 0x7FFFFFFF;
|
int bucket = key & _modBitMask;
|
||||||
int bucket = key % _buckets.Length;
|
|
||||||
int last = -1;
|
int last = -1;
|
||||||
for (int i = _buckets[bucket]; i >= 0; last = i, i = _entries[i].next)
|
for (int i = _buckets[bucket]; i >= 0; last = i, i = _entries[i].next)
|
||||||
{
|
{
|
||||||
@ -168,6 +170,7 @@ namespace DCFApixels
|
|||||||
private void Resize()
|
private void Resize()
|
||||||
{
|
{
|
||||||
int newSize = _buckets.Length << 1;
|
int newSize = _buckets.Length << 1;
|
||||||
|
_modBitMask = (newSize - 1) & 0x7FFFFFFF;
|
||||||
|
|
||||||
Contract.Assert(newSize >= _entries.Length);
|
Contract.Assert(newSize >= _entries.Length);
|
||||||
int[] newBuckets = new int[newSize];
|
int[] newBuckets = new int[newSize];
|
||||||
@ -188,8 +191,61 @@ namespace DCFApixels
|
|||||||
_buckets = newBuckets;
|
_buckets = newBuckets;
|
||||||
_entries = newEntries;
|
_entries = newEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int NormalizeCapacity(int capacity)
|
||||||
|
{
|
||||||
|
int result = MIN_CAPACITY;
|
||||||
|
while (result < capacity) result <<= 1;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
//#region Enumerator
|
||||||
|
// public Enumerator GetEnumerator() => new Enumerator(this);
|
||||||
|
// public struct Enumerator
|
||||||
|
// {
|
||||||
|
// private SparseArray<TValue> _source;
|
||||||
|
// private int index;
|
||||||
|
// private int curretnItmeIndex;
|
||||||
|
//
|
||||||
|
// public ref readonly TValue Current
|
||||||
|
// {
|
||||||
|
// get
|
||||||
|
// {
|
||||||
|
// return ref _source._entries[curretnItmeIndex].value;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public Enumerator(SparseArray<TValue> source)
|
||||||
|
// {
|
||||||
|
// _source = source;
|
||||||
|
// index = 0;
|
||||||
|
// curretnItmeIndex = 0;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public bool MoveNext()
|
||||||
|
// {
|
||||||
|
// // Use unsigned comparison since we set index to dictionary.count+1 when the enumeration ends.
|
||||||
|
// // dictionary.count+1 could be negative if dictionary.count is Int32.MaxValue
|
||||||
|
// while ((uint)index < (uint)_source.count)
|
||||||
|
// {
|
||||||
|
// if (dictionary.entries[index].hashCode >= 0)
|
||||||
|
// {
|
||||||
|
// current = new KeyValuePair<TKey, TValue>(dictionary.entries[index].key, dictionary.entries[index].value);
|
||||||
|
// index++;
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
// index++;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// index = dictionary.count + 1;
|
||||||
|
// current = new KeyValuePair<TKey, TValue>();
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// #endregion
|
||||||
|
|
||||||
#region Utils
|
#region Utils
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||||
private struct Entry
|
private struct Entry
|
||||||
|
Loading…
Reference in New Issue
Block a user