mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2026-04-22 01:45:55 +08:00
Merge branch 'dev'
This commit is contained in:
commit
d8c73e3c0d
@ -1,72 +0,0 @@
|
|||||||
using System.ComponentModel;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
|
||||||
{
|
|
||||||
[DebugColor(DebugColor.White)]
|
|
||||||
public struct Parent : IEcsAttachComponent
|
|
||||||
{
|
|
||||||
public entlong entity;
|
|
||||||
|
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
||||||
public entlong Target
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get => entity;
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
set => entity = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ParentUtility
|
|
||||||
{
|
|
||||||
// public static int GetRootOrSelf(this HierarchySubject s, int entityID) => s.parents.GetRootOrSelf(entityID);
|
|
||||||
public static int GetRootOrSelf(this EcsAttachPool<Parent> parents, int entityID)
|
|
||||||
{
|
|
||||||
while (parents.Has(entityID) && parents.Read(entityID).entity.TryGetID(out int child))
|
|
||||||
entityID = child;
|
|
||||||
return entityID;
|
|
||||||
}
|
|
||||||
// public static bool IsRoot(this HierarchySubject s, int entityID) => s.parents.IsRoot(entityID);
|
|
||||||
public static bool IsRoot(this EcsAttachPool<Parent> parents, int entityID)
|
|
||||||
{
|
|
||||||
return !(parents.Has(entityID) && parents.Read(entityID).entity.IsAlive);
|
|
||||||
}
|
|
||||||
|
|
||||||
// public static bool TryGetRoot(this HierarchySubject s, int entityID, out int rootEntityID) => TryGetRoot(s.parents, entityID, out rootEntityID);
|
|
||||||
public static bool TryGetRoot(this EcsAttachPool<Parent> parents, EcsSubject conditionSubject, int entityID, out int rootEntityID)
|
|
||||||
{
|
|
||||||
rootEntityID = entityID;
|
|
||||||
while (parents.Has(rootEntityID) && parents.Read(rootEntityID).entity.TryGetID(out int child) && !conditionSubject.IsMatches(child))
|
|
||||||
rootEntityID = child;
|
|
||||||
return rootEntityID != entityID;
|
|
||||||
}
|
|
||||||
public static bool TryGetRoot(this EcsAttachPool<Parent> parents, int entityID, out int rootEntityID)
|
|
||||||
{
|
|
||||||
rootEntityID = entityID;
|
|
||||||
while (parents.Has(rootEntityID) && parents.Read(rootEntityID).entity.TryGetID(out int child))
|
|
||||||
rootEntityID = child;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -5,37 +5,8 @@ using System.Linq;
|
|||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
//TODO развить идею инжектов
|
//TODO развить идею инжектов
|
||||||
//1) добавить расширенный метод инжекта, с 2 джинерик-аргументами, первый базовый тип и второй инжектируемый тип.
|
//добавить контейнер, который автоматически создается, собирает в себя все пре-инжекты и авто-инжектится во все системы.
|
||||||
//напримере это будет работать так Inject<object, Foo> делает инжект объекта типа Foo для систем с IEcsInject<object> или с IEcsInject<Foo>
|
|
||||||
//2) добавить контейнер, который автоматически создается, собирает в себя все пре-инжекты и авто-инжектится во все системы.
|
|
||||||
//но это спорная идея
|
//но это спорная идея
|
||||||
namespace Internal
|
|
||||||
{
|
|
||||||
internal class PreInitInjectController
|
|
||||||
{
|
|
||||||
private EcsPipeline _source;
|
|
||||||
private InjectSystemBase[] _injectSystems;
|
|
||||||
private int _injectCount;
|
|
||||||
public PreInitInjectController(EcsPipeline source)
|
|
||||||
{
|
|
||||||
_injectCount = 0;
|
|
||||||
_source = source;
|
|
||||||
_injectSystems = _source.AllSystems.OfType<InjectSystemBase>().ToArray();
|
|
||||||
}
|
|
||||||
public bool OnInject()
|
|
||||||
{
|
|
||||||
_injectCount++;
|
|
||||||
return IsInjectionEnd;
|
|
||||||
}
|
|
||||||
public bool IsInjectionEnd => _injectCount >= _injectSystems.Length;
|
|
||||||
public void Destroy()
|
|
||||||
{
|
|
||||||
_source = null;
|
|
||||||
_injectSystems = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IEcsPreInject : IEcsSystem
|
public interface IEcsPreInject : IEcsSystem
|
||||||
{
|
{
|
||||||
void PreInject(object obj);
|
void PreInject(object obj);
|
||||||
@ -52,6 +23,29 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
namespace Internal
|
namespace Internal
|
||||||
{
|
{
|
||||||
|
internal class PreInitInjectController
|
||||||
|
{
|
||||||
|
private EcsPipeline _source;
|
||||||
|
private InjectSystemBase[] _injectSystems;
|
||||||
|
private int _injectCount;
|
||||||
|
public bool IsInjectionEnd => _injectCount >= _injectSystems.Length;
|
||||||
|
public PreInitInjectController(EcsPipeline source)
|
||||||
|
{
|
||||||
|
_injectCount = 0;
|
||||||
|
_source = source;
|
||||||
|
_injectSystems = _source.AllSystems.OfType<InjectSystemBase>().ToArray();
|
||||||
|
}
|
||||||
|
public bool OnInject()
|
||||||
|
{
|
||||||
|
_injectCount++;
|
||||||
|
return IsInjectionEnd;
|
||||||
|
}
|
||||||
|
public void Destroy()
|
||||||
|
{
|
||||||
|
_source = null;
|
||||||
|
_injectSystems = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
[DebugHide, DebugColor(DebugColor.Gray)]
|
[DebugHide, DebugColor(DebugColor.Gray)]
|
||||||
public sealed class EcsPreInjectRunner : EcsRunner<IEcsPreInject>, IEcsPreInject
|
public sealed class EcsPreInjectRunner : EcsRunner<IEcsPreInject>, IEcsPreInject
|
||||||
{
|
{
|
||||||
@ -86,55 +80,43 @@ namespace DCFApixels.DragonECS
|
|||||||
foreach (var item in targets) item.OnPreInitInjectionBefore();
|
foreach (var item in targets) item.OnPreInitInjectionBefore();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
public class InjectSystemBase { }
|
||||||
|
[DebugHide, DebugColor(DebugColor.Gray)]
|
||||||
public class InjectSystemBase { }
|
public class InjectSystem<T> : InjectSystemBase, IEcsPreInitProcess, IEcsInject<PreInitInjectController>, IEcsPreInitInjectProcess
|
||||||
|
|
||||||
[DebugHide, DebugColor(DebugColor.Gray)]
|
|
||||||
public class InjectSystem<T> : InjectSystemBase, IEcsPreInitProcess, IEcsInject<PreInitInjectController>, IEcsPreInitInjectProcess
|
|
||||||
{
|
|
||||||
private T _injectedData;
|
|
||||||
|
|
||||||
private PreInitInjectController _injectController;
|
|
||||||
void IEcsInject<PreInitInjectController>.Inject(PreInitInjectController obj) => _injectController = obj;
|
|
||||||
|
|
||||||
public InjectSystem(T injectedData)
|
|
||||||
{
|
{
|
||||||
_injectedData = injectedData;
|
private T _injectedData;
|
||||||
}
|
private PreInitInjectController _injectController;
|
||||||
|
void IEcsInject<PreInitInjectController>.Inject(PreInitInjectController obj) => _injectController = obj;
|
||||||
public void PreInit(EcsPipeline pipeline)
|
public InjectSystem(T injectedData)
|
||||||
{
|
|
||||||
if (_injectedData == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_injectController == null)
|
|
||||||
{
|
{
|
||||||
_injectController = new PreInitInjectController(pipeline);
|
_injectedData = injectedData;
|
||||||
var injectMapRunner = pipeline.GetRunner<IEcsInject<PreInitInjectController>>();
|
|
||||||
pipeline.GetRunner<IEcsPreInitInjectProcess>().OnPreInitInjectionBefore();
|
|
||||||
injectMapRunner.Inject(_injectController);
|
|
||||||
}
|
}
|
||||||
|
public void PreInit(EcsPipeline pipeline)
|
||||||
var injectRunnerGeneric = pipeline.GetRunner<IEcsInject<T>>();
|
|
||||||
injectRunnerGeneric.Inject(_injectedData);
|
|
||||||
|
|
||||||
if (_injectController.OnInject())
|
|
||||||
{
|
{
|
||||||
_injectController.Destroy();
|
if (_injectedData == null) return;
|
||||||
var injectCallbacksRunner = pipeline.GetRunner<IEcsPreInitInjectProcess>();
|
if (_injectController == null)
|
||||||
injectCallbacksRunner.OnPreInitInjectionAfter();
|
{
|
||||||
EcsRunner.Destroy(injectCallbacksRunner);
|
_injectController = new PreInitInjectController(pipeline);
|
||||||
|
var injectMapRunner = pipeline.GetRunner<IEcsInject<PreInitInjectController>>();
|
||||||
|
pipeline.GetRunner<IEcsPreInitInjectProcess>().OnPreInitInjectionBefore();
|
||||||
|
injectMapRunner.Inject(_injectController);
|
||||||
|
}
|
||||||
|
var injectRunnerGeneric = pipeline.GetRunner<IEcsInject<T>>();
|
||||||
|
injectRunnerGeneric.Inject(_injectedData);
|
||||||
|
if (_injectController.OnInject())
|
||||||
|
{
|
||||||
|
_injectController.Destroy();
|
||||||
|
var injectCallbacksRunner = pipeline.GetRunner<IEcsPreInitInjectProcess>();
|
||||||
|
injectCallbacksRunner.OnPreInitInjectionAfter();
|
||||||
|
EcsRunner.Destroy(injectCallbacksRunner);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
public void OnPreInitInjectionBefore() { }
|
||||||
public void OnPreInitInjectionBefore() { }
|
public void OnPreInitInjectionAfter() => _injectController = null;
|
||||||
public void OnPreInitInjectionAfter()
|
|
||||||
{
|
|
||||||
_injectController = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class InjectSystemExstensions
|
public static class InjectSystemExtensions
|
||||||
{
|
{
|
||||||
public static EcsPipeline.Builder Inject<T>(this EcsPipeline.Builder self, T data)
|
public static EcsPipeline.Builder Inject<T>(this EcsPipeline.Builder self, T data)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,11 +0,0 @@
|
|||||||
namespace DCFApixels.DragonECS
|
|
||||||
{
|
|
||||||
public sealed class HierarchySubject : EcsSubject
|
|
||||||
{
|
|
||||||
public readonly EcsAttachPool<Parent> parents;
|
|
||||||
public HierarchySubject(Builder b)
|
|
||||||
{
|
|
||||||
parents = b.Include<Parent>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,53 +1,51 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using DCFApixels.DragonECS.Internal;
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
[DebugHide, DebugColor(DebugColor.Black)]
|
namespace Internal
|
||||||
public class SystemsBlockMarkerSystem : IEcsSystem
|
|
||||||
{
|
{
|
||||||
public readonly string name;
|
[DebugHide, DebugColor(DebugColor.Black)]
|
||||||
public SystemsBlockMarkerSystem(string name) { this.name = name; }
|
public class SystemsBlockMarkerSystem : IEcsSystem
|
||||||
}
|
|
||||||
|
|
||||||
[DebugHide, DebugColor(DebugColor.Grey)]
|
|
||||||
public class DeleteEmptyEntitesSystem : IEcsRunProcess, IEcsPreInject
|
|
||||||
{
|
|
||||||
private List<EcsWorld> _worlds = new List<EcsWorld>();
|
|
||||||
public void PreInject(object obj)
|
|
||||||
{
|
{
|
||||||
if (obj is EcsWorld world)
|
public readonly string name;
|
||||||
_worlds.Add(world);
|
public SystemsBlockMarkerSystem(string name) => this.name = name;
|
||||||
}
|
}
|
||||||
public void Run(EcsPipeline pipeline)
|
[DebugHide, DebugColor(DebugColor.Grey)]
|
||||||
|
public class DeleteEmptyEntitesSystem : IEcsRunProcess, IEcsPreInject
|
||||||
{
|
{
|
||||||
foreach (var world in _worlds)
|
private List<EcsWorld> _worlds = new List<EcsWorld>();
|
||||||
world.DeleteEmptyEntites();
|
public void PreInject(object obj)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebugHide, DebugColor(DebugColor.Grey)]
|
|
||||||
public class DeleteOneFrameComponentSystem<TWorld, TComponent> : IEcsRunProcess, IEcsInject<TWorld>
|
|
||||||
where TWorld : EcsWorld<TWorld>
|
|
||||||
where TComponent : struct, IEcsComponent
|
|
||||||
{
|
|
||||||
private TWorld _world;
|
|
||||||
public void Inject(TWorld obj) => _world = obj;
|
|
||||||
private sealed class Subject : EcsSubject
|
|
||||||
{
|
|
||||||
public EcsPool<TComponent> pool;
|
|
||||||
public Subject(Builder b)
|
|
||||||
{
|
{
|
||||||
pool = b.Include<TComponent>();
|
if (obj is EcsWorld world)
|
||||||
|
_worlds.Add(world);
|
||||||
|
}
|
||||||
|
public void Run(EcsPipeline pipeline)
|
||||||
|
{
|
||||||
|
foreach (var world in _worlds)
|
||||||
|
world.DeleteEmptyEntites();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void Run(EcsPipeline pipeline)
|
[DebugHide, DebugColor(DebugColor.Grey)]
|
||||||
|
public class DeleteOneFrameComponentSystem<TWorld, TComponent> : IEcsRunProcess, IEcsInject<TWorld>
|
||||||
|
where TWorld : EcsWorld<TWorld>
|
||||||
|
where TComponent : struct, IEcsComponent
|
||||||
{
|
{
|
||||||
foreach (var e in _world.Where(out Subject s))
|
private sealed class Subject : EcsSubject
|
||||||
s.pool.Del(e);
|
{
|
||||||
|
public EcsPool<TComponent> pool;
|
||||||
|
public Subject(Builder b) => pool = b.Include<TComponent>();
|
||||||
|
}
|
||||||
|
private TWorld _world;
|
||||||
|
public void Inject(TWorld obj) => _world = obj;
|
||||||
|
public void Run(EcsPipeline pipeline)
|
||||||
|
{
|
||||||
|
foreach (var e in _world.Where(out Subject s))
|
||||||
|
s.pool.Del(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public static class DeleteOneFrameComponentSystemExtensions
|
||||||
public static class DeleteOneFrameComponentSystemExt
|
|
||||||
{
|
{
|
||||||
private const string AUTO_DEL_LAYER = nameof(AUTO_DEL_LAYER);
|
private const string AUTO_DEL_LAYER = nameof(AUTO_DEL_LAYER);
|
||||||
public static EcsPipeline.Builder AutoDel<TWorld, TComponent>(this EcsPipeline.Builder b)
|
public static EcsPipeline.Builder AutoDel<TWorld, TComponent>(this EcsPipeline.Builder b)
|
||||||
|
|||||||
@ -1,106 +0,0 @@
|
|||||||
using DCFApixels.DragonECS.RunnersCore;
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
|
||||||
{
|
|
||||||
public interface IEcsComponentAdd : IEcsSystem
|
|
||||||
{
|
|
||||||
void OnComponentAdd<T>(int entityID);
|
|
||||||
}
|
|
||||||
public interface IEcsComponentWrite : IEcsSystem
|
|
||||||
{
|
|
||||||
void OnComponentWrite<T>(int entityID);
|
|
||||||
}
|
|
||||||
public interface IEcsComponentDel : IEcsSystem
|
|
||||||
{
|
|
||||||
void OnComponentDel<T>(int entityID);
|
|
||||||
}
|
|
||||||
public interface IEcsComponentLifecycle : IEcsComponentAdd, IEcsComponentWrite, IEcsComponentDel { }
|
|
||||||
|
|
||||||
namespace Internal
|
|
||||||
{
|
|
||||||
[DebugColor(DebugColor.Orange)]
|
|
||||||
public sealed class EcsEntityAddComponentRunner : EcsRunner<IEcsComponentAdd>, IEcsComponentAdd
|
|
||||||
{
|
|
||||||
public void OnComponentAdd<T>(int entityID)
|
|
||||||
{
|
|
||||||
foreach (var item in targets) item.OnComponentAdd<T>(entityID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[DebugColor(DebugColor.Orange)]
|
|
||||||
public sealed class EcsEntityChangeComponentRunner : EcsRunner<IEcsComponentWrite>, IEcsComponentWrite
|
|
||||||
{
|
|
||||||
public void OnComponentWrite<T>(int entityID)
|
|
||||||
{
|
|
||||||
foreach (var item in targets) item.OnComponentWrite<T>(entityID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[DebugColor(DebugColor.Orange)]
|
|
||||||
public sealed class EcsEntityDelComponentRunner : EcsRunner<IEcsComponentDel>, IEcsComponentDel
|
|
||||||
{
|
|
||||||
public void OnComponentDel<T>(int entityID)
|
|
||||||
{
|
|
||||||
foreach (var item in targets) item.OnComponentDel<T>(entityID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IEcsEntityCreate : IEcsSystem
|
|
||||||
{
|
|
||||||
void OnEntityCreate(int entityID);
|
|
||||||
}
|
|
||||||
public interface IEcsEntityDestroy : IEcsSystem
|
|
||||||
{
|
|
||||||
void OnEntityDestroy(int entityID);
|
|
||||||
}
|
|
||||||
public interface IEcsEntityLifecycle : IEcsEntityCreate, IEcsEntityDestroy { }
|
|
||||||
|
|
||||||
namespace Internal
|
|
||||||
{
|
|
||||||
[DebugColor(DebugColor.Orange)]
|
|
||||||
public sealed class EcsEntityCreateRunner : EcsRunner<IEcsEntityCreate>, IEcsEntityCreate
|
|
||||||
{
|
|
||||||
public void OnEntityCreate(int entityID)
|
|
||||||
{
|
|
||||||
foreach (var item in targets) item.OnEntityCreate(entityID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[DebugColor(DebugColor.Orange)]
|
|
||||||
public sealed class EcsEntityDestroyRunner : EcsRunner<IEcsEntityDestroy>, IEcsEntityDestroy
|
|
||||||
{
|
|
||||||
public void OnEntityDestroy(int entityID)
|
|
||||||
{
|
|
||||||
foreach (var item in targets) item.OnEntityDestroy(entityID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IEcsWorldCreate : IEcsSystem
|
|
||||||
{
|
|
||||||
void OnWorldCreate(EcsWorld world);
|
|
||||||
}
|
|
||||||
public interface IEcsWorldDestroy : IEcsSystem
|
|
||||||
{
|
|
||||||
void OnWorldDestroy(EcsWorld world);
|
|
||||||
}
|
|
||||||
public interface IEcsWorldLifecycle : IEcsWorldCreate, IEcsWorldDestroy { }
|
|
||||||
|
|
||||||
namespace Internal
|
|
||||||
{
|
|
||||||
[DebugColor(DebugColor.Orange)]
|
|
||||||
public sealed class EcsWorldCreateRunner : EcsRunner<IEcsWorldCreate>, IEcsWorldCreate
|
|
||||||
{
|
|
||||||
public void OnWorldCreate(EcsWorld world)
|
|
||||||
{
|
|
||||||
foreach (var item in targets) item.OnWorldCreate(world);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[DebugColor(DebugColor.Orange)]
|
|
||||||
public sealed class EcsWorldDestryRunner : EcsRunner<IEcsWorldDestroy>, IEcsWorldDestroy
|
|
||||||
{
|
|
||||||
public void OnWorldDestroy(EcsWorld world)
|
|
||||||
{
|
|
||||||
foreach (var item in targets) item.OnWorldDestroy(world);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,5 +1,9 @@
|
|||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
|
internal sealed class EcsNullWorld : EcsWorld<EcsNullWorld>
|
||||||
|
{
|
||||||
|
public EcsNullWorld() : base(false) { }
|
||||||
|
}
|
||||||
public sealed class EcsDefaultWorld : EcsWorld<EcsDefaultWorld> { }
|
public sealed class EcsDefaultWorld : EcsWorld<EcsDefaultWorld> { }
|
||||||
public sealed class EcsEventWorld : EcsWorld<EcsEventWorld> { }
|
public sealed class EcsEventWorld : EcsWorld<EcsEventWorld> { }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,6 @@
|
|||||||
public const string DEBUG_WARNING_TAG = "WARNING";
|
public const string DEBUG_WARNING_TAG = "WARNING";
|
||||||
public const string DEBUG_ERROR_TAG = "ERROR";
|
public const string DEBUG_ERROR_TAG = "ERROR";
|
||||||
|
|
||||||
|
|
||||||
public const string PRE_BEGIN_LAYER = nameof(PRE_BEGIN_LAYER);
|
public const string PRE_BEGIN_LAYER = nameof(PRE_BEGIN_LAYER);
|
||||||
public const string BEGIN_LAYER = nameof(BEGIN_LAYER);
|
public const string BEGIN_LAYER = nameof(BEGIN_LAYER);
|
||||||
public const string BASIC_LAYER = nameof(BASIC_LAYER);
|
public const string BASIC_LAYER = nameof(BASIC_LAYER);
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using DCFApixels.DragonECS.Utils;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
@ -19,16 +20,13 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
public readonly ref struct AutoScope
|
public readonly ref struct AutoScope
|
||||||
{
|
{
|
||||||
private readonly int id;
|
private readonly int _id;
|
||||||
public AutoScope(int id)
|
public AutoScope(int id)
|
||||||
{
|
{
|
||||||
this.id = id;
|
_id = id;
|
||||||
EcsDebug.ProfileMarkBegin(id);
|
EcsDebug.ProfileMarkBegin(id);
|
||||||
}
|
}
|
||||||
public void Dispose()
|
public void Dispose() => EcsDebug.ProfileMarkEnd(_id);
|
||||||
{
|
|
||||||
EcsDebug.ProfileMarkEnd(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,20 +35,19 @@ namespace DCFApixels.DragonECS
|
|||||||
public static void Set<T>() where T : DebugService, new() => DebugService.Set<T>();
|
public static void Set<T>() where T : DebugService, new() => DebugService.Set<T>();
|
||||||
public static void Set(DebugService service) => DebugService.Set(service);
|
public static void Set(DebugService service) => DebugService.Set(service);
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void Print(object v) => DebugService.Instance.Print(v);
|
public static void Print(object v) => DebugService.Instance.Print(v);
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void Print(string tag, object v)
|
public static void Print(string tag, object v)
|
||||||
{
|
{
|
||||||
#if !DISABLE_DRAGONECS_DEBUG
|
#if !DISABLE_DRAGONECS_DEBUGGER
|
||||||
DebugService.Instance.Print(tag, v);
|
DebugService.Instance.Print(tag, v);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int RegisterMark(string name)
|
public static int RegisterMark(string name)
|
||||||
{
|
{
|
||||||
#if !DISABLE_DRAGONECS_DEBUG
|
#if !DISABLE_DRAGONECS_DEBUGGER
|
||||||
return DebugService.Instance.RegisterMark(name);
|
return DebugService.Instance.RegisterMark(name);
|
||||||
#else
|
#else
|
||||||
return 0;
|
return 0;
|
||||||
@ -59,21 +56,21 @@ namespace DCFApixels.DragonECS
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void DeleteMark(string name)
|
public static void DeleteMark(string name)
|
||||||
{
|
{
|
||||||
#if !DISABLE_DRAGONECS_DEBUG
|
#if !DISABLE_DRAGONECS_DEBUGGER
|
||||||
DebugService.Instance.DeleteMark(name);
|
DebugService.Instance.DeleteMark(name);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void ProfileMarkBegin(int id)
|
public static void ProfileMarkBegin(int id)
|
||||||
{
|
{
|
||||||
#if !DISABLE_DRAGONECS_DEBUG
|
#if !DISABLE_DRAGONECS_DEBUGGER
|
||||||
DebugService.Instance.ProfileMarkBegin(id);
|
DebugService.Instance.ProfileMarkBegin(id);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void ProfileMarkEnd(int id)
|
public static void ProfileMarkEnd(int id)
|
||||||
{
|
{
|
||||||
#if !DISABLE_DRAGONECS_DEBUG
|
#if !DISABLE_DRAGONECS_DEBUGGER
|
||||||
DebugService.Instance.ProfileMarkEnd(id);
|
DebugService.Instance.ProfileMarkEnd(id);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -145,7 +142,7 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
public DefaultDebugService()
|
public DefaultDebugService()
|
||||||
{
|
{
|
||||||
#if !DISABLE_DRAGONECS_DEBUG
|
#if !DISABLE_DRAGONECS_DEBUGGER
|
||||||
_stopwatchs = new Stopwatch[64];
|
_stopwatchs = new Stopwatch[64];
|
||||||
_stopwatchsNames= new string[64];
|
_stopwatchsNames= new string[64];
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -5,11 +5,14 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
public static class EcsDebugUtility
|
public static class EcsDebugUtility
|
||||||
{
|
{
|
||||||
|
public static string GetGenericTypeFullName<T>(int maxDepth = 2) => GetGenericTypeFullName(typeof(T), maxDepth);
|
||||||
|
public static string GetGenericTypeFullName(Type type, int maxDepth = 2) => GetGenericTypeNameInternal(type, maxDepth, true);
|
||||||
public static string GetGenericTypeName<T>(int maxDepth = 2) => GetGenericTypeName(typeof(T), maxDepth);
|
public static string GetGenericTypeName<T>(int maxDepth = 2) => GetGenericTypeName(typeof(T), maxDepth);
|
||||||
public static string GetGenericTypeName(Type type, int maxDepth = 2)
|
public static string GetGenericTypeName(Type type, int maxDepth = 2) => GetGenericTypeNameInternal(type, maxDepth, false);
|
||||||
|
private static string GetGenericTypeNameInternal(Type type, int maxDepth, bool isFull)
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG)
|
#if (DEBUG && !DISABLE_DEBUG)
|
||||||
string friendlyName = type.Name;
|
string friendlyName = isFull ? type.FullName : type.Name;
|
||||||
if (!type.IsGenericType || maxDepth == 0)
|
if (!type.IsGenericType || maxDepth == 0)
|
||||||
return friendlyName;
|
return friendlyName;
|
||||||
|
|
||||||
@ -21,7 +24,7 @@ namespace DCFApixels.DragonECS
|
|||||||
Type[] typeParameters = type.GetGenericArguments();
|
Type[] typeParameters = type.GetGenericArguments();
|
||||||
for (int i = 0; i < typeParameters.Length; ++i)
|
for (int i = 0; i < typeParameters.Length; ++i)
|
||||||
{
|
{
|
||||||
string typeParamName = GetGenericTypeName(typeParameters[i], maxDepth - 1);
|
string typeParamName = GetGenericTypeNameInternal(typeParameters[i], maxDepth - 1, false);//чтобы строка не была слишком длинной, используются сокращенные имена для типов аргументов
|
||||||
friendlyName += (i == 0 ? typeParamName : "," + typeParamName);
|
friendlyName += (i == 0 ? typeParamName : "," + typeParamName);
|
||||||
}
|
}
|
||||||
friendlyName += ">";
|
friendlyName += ">";
|
||||||
|
|||||||
147
src/EcsGroup.cs
147
src/EcsGroup.cs
@ -1,15 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Unity.Profiling;
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
using delayedOp = System.Int32;
|
using static DCFApixels.DragonECS.EcsGroup.ThrowHalper;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
using static EcsGroup.ThrowHalper;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 0, Size = 8)]
|
[StructLayout(LayoutKind.Sequential, Pack = 0, Size = 8)]
|
||||||
public readonly ref struct EcsReadonlyGroup
|
public readonly ref struct EcsReadonlyGroup
|
||||||
{
|
{
|
||||||
@ -45,7 +42,7 @@ namespace DCFApixels.DragonECS
|
|||||||
public bool IsReleazed
|
public bool IsReleazed
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => _source.IsReleazed;
|
get => _source.IsReleased;
|
||||||
}
|
}
|
||||||
public int this[int index]
|
public int this[int index]
|
||||||
{
|
{
|
||||||
@ -93,26 +90,13 @@ namespace DCFApixels.DragonECS
|
|||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
// индексация начинается с 1
|
|
||||||
// _delayedOps это int[] для отложенных операций, хранятся отложенные операции в виде int значения, если старший бит = 0 то это опреация добавленияб если = 1 то это операция вычитания
|
|
||||||
public unsafe class EcsGroup : IDisposable, IEquatable<EcsGroup>
|
public unsafe class EcsGroup : IDisposable, IEquatable<EcsGroup>
|
||||||
{
|
{
|
||||||
private const int DEALAYED_ADD = 0;
|
|
||||||
private const int DEALAYED_REMOVE = int.MinValue;
|
|
||||||
|
|
||||||
private EcsWorld _source;
|
private EcsWorld _source;
|
||||||
|
|
||||||
private int[] _dense;
|
private int[] _dense;
|
||||||
private int[] _sparse;
|
private int[] _sparse;
|
||||||
|
|
||||||
private int _count;
|
private int _count;
|
||||||
|
private bool _isReleased = true;
|
||||||
private delayedOp[] _delayedOps;
|
|
||||||
private int _delayedOpsCount;
|
|
||||||
|
|
||||||
private int _lockCount;
|
|
||||||
|
|
||||||
private bool _isReleazed = true;
|
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
public EcsWorld World => _source;
|
public EcsWorld World => _source;
|
||||||
@ -136,17 +120,17 @@ namespace DCFApixels.DragonECS
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => new EcsReadonlyGroup(this);
|
get => new EcsReadonlyGroup(this);
|
||||||
}
|
}
|
||||||
public bool IsReleazed
|
public bool IsReleased
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => _isReleazed;
|
get => _isReleased;
|
||||||
}
|
}
|
||||||
public int this[int index]
|
public int this[int index]
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (index < 0 || index >= Count) ThrowArgumentOutOfRange();
|
if (index < 0 || index >= Count) ThrowArgumentOutOfRange();
|
||||||
#endif
|
#endif
|
||||||
return _dense[index];
|
return _dense[index];
|
||||||
@ -161,27 +145,15 @@ namespace DCFApixels.DragonECS
|
|||||||
return world.GetGroupFromPool();
|
return world.GetGroupFromPool();
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal EcsGroup(EcsWorld world, int denseCapacity = 64, int delayedOpsCapacity = 128)
|
internal EcsGroup(EcsWorld world, int denseCapacity = 64)
|
||||||
{
|
{
|
||||||
_source = world;
|
_source = world;
|
||||||
_source.RegisterGroup(this);
|
_source.RegisterGroup(this);
|
||||||
_dense = new int[denseCapacity];
|
_dense = new int[denseCapacity];
|
||||||
_sparse = new int[world.Capacity];
|
_sparse = new int[world.Capacity];
|
||||||
|
|
||||||
_delayedOps = new delayedOp[delayedOpsCapacity];
|
|
||||||
|
|
||||||
_lockCount = 0;
|
|
||||||
_delayedOpsCount = 0;
|
|
||||||
_count = 0;
|
_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//защита от криворукости
|
|
||||||
//перед сборкой мусора снова создает сильную ссылку и возвращает в пул
|
|
||||||
//TODO переделат или удалить, так как сборщик мусора просыпается только после 12к и более экземпляров, только тогда и вызывается финализатор, слишком жирно
|
|
||||||
~EcsGroup()
|
|
||||||
{
|
|
||||||
Release();
|
|
||||||
}
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Has
|
#region Has
|
||||||
@ -211,17 +183,7 @@ namespace DCFApixels.DragonECS
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal void AddInternal(int entityID)
|
internal void AddInternal(int entityID)
|
||||||
{
|
{
|
||||||
//if (_lockCount > 0)
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
//{
|
|
||||||
// AddDelayedOp(entityID, DEALAYED_ADD);
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
AggressiveAdd(entityID);
|
|
||||||
}
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
internal void AggressiveAdd(int entityID)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (Has(entityID)) ThrowAlreadyContains(entityID);
|
if (Has(entityID)) ThrowAlreadyContains(entityID);
|
||||||
#endif
|
#endif
|
||||||
if (++_count >= _dense.Length)
|
if (++_count >= _dense.Length)
|
||||||
@ -239,17 +201,7 @@ namespace DCFApixels.DragonECS
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal void RemoveInternal(int entityID)
|
internal void RemoveInternal(int entityID)
|
||||||
{
|
{
|
||||||
//if (_lockCount > 0)
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
//{
|
|
||||||
// AddDelayedOp(entityID, DEALAYED_REMOVE);
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
AggressiveRemove(entityID);
|
|
||||||
}
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
internal void AggressiveRemove(int entityID)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (!Has(entityID)) ThrowDoesNotContain(entityID);
|
if (!Has(entityID)) ThrowDoesNotContain(entityID);
|
||||||
#endif
|
#endif
|
||||||
_dense[_sparse[entityID]] = _dense[_count];
|
_dense[_sparse[entityID]] = _dense[_count];
|
||||||
@ -257,22 +209,12 @@ namespace DCFApixels.DragonECS
|
|||||||
_sparse[entityID] = 0;
|
_sparse[entityID] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private void AddDelayedOp(int entityID, int isAddBitFlag)
|
|
||||||
{
|
|
||||||
if (_delayedOpsCount >= _delayedOps.Length)
|
|
||||||
{
|
|
||||||
Array.Resize(ref _delayedOps, _delayedOps.Length << 1);
|
|
||||||
}
|
|
||||||
_delayedOps[_delayedOpsCount++] = entityID | isAddBitFlag; // delayedOp = entityID add isAddBitFlag
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveUnusedEntityIDs()
|
public void RemoveUnusedEntityIDs()
|
||||||
{
|
{
|
||||||
foreach (var e in this)
|
foreach (var e in this)
|
||||||
{
|
{
|
||||||
if (!_source.IsUsed(e))
|
if (!_source.IsUsed(e))
|
||||||
AggressiveRemove(e);
|
RemoveInternal(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
@ -293,13 +235,13 @@ namespace DCFApixels.DragonECS
|
|||||||
public void CopyFrom(EcsReadonlyGroup group) => CopyFrom(group.GetGroupInternal());
|
public void CopyFrom(EcsReadonlyGroup group) => CopyFrom(group.GetGroupInternal());
|
||||||
public void CopyFrom(EcsGroup group)
|
public void CopyFrom(EcsGroup group)
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (group.World != _source) throw new ArgumentException("groupFilter.WorldIndex != WorldIndex");
|
if (group.World != _source) throw new ArgumentException("groupFilter.WorldIndex != WorldIndex");
|
||||||
#endif
|
#endif
|
||||||
if(_count > 0)
|
if(_count > 0)
|
||||||
Clear();
|
Clear();
|
||||||
foreach (var item in group)
|
foreach (var item in group)
|
||||||
AggressiveAdd(item);
|
AddInternal(item);
|
||||||
}
|
}
|
||||||
public EcsGroup Clone()
|
public EcsGroup Clone()
|
||||||
{
|
{
|
||||||
@ -316,12 +258,12 @@ namespace DCFApixels.DragonECS
|
|||||||
/// <summary>as Union sets</summary>
|
/// <summary>as Union sets</summary>
|
||||||
public void UnionWith(EcsGroup group)
|
public void UnionWith(EcsGroup group)
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (_source != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex");
|
if (_source != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex");
|
||||||
#endif
|
#endif
|
||||||
foreach (var item in group)
|
foreach (var item in group)
|
||||||
if (!Has(item))
|
if (!Has(item))
|
||||||
AggressiveAdd(item);
|
AddInternal(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>as Except sets</summary>
|
/// <summary>as Except sets</summary>
|
||||||
@ -330,12 +272,12 @@ namespace DCFApixels.DragonECS
|
|||||||
/// <summary>as Except sets</summary>
|
/// <summary>as Except sets</summary>
|
||||||
public void ExceptWith(EcsGroup group)
|
public void ExceptWith(EcsGroup group)
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (_source != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex");
|
if (_source != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex");
|
||||||
#endif
|
#endif
|
||||||
foreach (var item in this)
|
foreach (var item in this)
|
||||||
if (group.Has(item))
|
if (group.Has(item))
|
||||||
AggressiveRemove(item);
|
RemoveInternal(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>as Intersect sets</summary>
|
/// <summary>as Intersect sets</summary>
|
||||||
@ -344,12 +286,12 @@ namespace DCFApixels.DragonECS
|
|||||||
/// <summary>as Intersect sets</summary>
|
/// <summary>as Intersect sets</summary>
|
||||||
public void AndWith(EcsGroup group)
|
public void AndWith(EcsGroup group)
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (World != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex");
|
if (World != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex");
|
||||||
#endif
|
#endif
|
||||||
foreach (var item in this)
|
foreach (var item in this)
|
||||||
if (!group.Has(item))
|
if (!group.Has(item))
|
||||||
AggressiveRemove(item);
|
RemoveInternal(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>as Symmetric Except sets</summary>
|
/// <summary>as Symmetric Except sets</summary>
|
||||||
@ -358,14 +300,14 @@ namespace DCFApixels.DragonECS
|
|||||||
/// <summary>as Symmetric Except sets</summary>
|
/// <summary>as Symmetric Except sets</summary>
|
||||||
public void XorWith(EcsGroup group)
|
public void XorWith(EcsGroup group)
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (_source != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex");
|
if (_source != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex");
|
||||||
#endif
|
#endif
|
||||||
foreach (var item in group)
|
foreach (var item in group)
|
||||||
if (Has(item))
|
if (Has(item))
|
||||||
AggressiveRemove(item);
|
RemoveInternal(item);
|
||||||
else
|
else
|
||||||
AggressiveAdd(item);
|
AddInternal(item);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -374,13 +316,13 @@ namespace DCFApixels.DragonECS
|
|||||||
/// <returns>new group from pool</returns>
|
/// <returns>new group from pool</returns>
|
||||||
public static EcsGroup Except(EcsGroup a, EcsGroup b)
|
public static EcsGroup Except(EcsGroup a, EcsGroup b)
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (a._source != b._source) throw new ArgumentException("a.WorldIndex != b.WorldIndex");
|
if (a._source != b._source) throw new ArgumentException("a.WorldIndex != b.WorldIndex");
|
||||||
#endif
|
#endif
|
||||||
EcsGroup result = a._source.GetGroupFromPool();
|
EcsGroup result = a._source.GetGroupFromPool();
|
||||||
foreach (var item in a)
|
foreach (var item in a)
|
||||||
if (!b.Has(item))
|
if (!b.Has(item))
|
||||||
result.AggressiveAdd(item);
|
result.AddInternal(item);
|
||||||
a._source.ReleaseGroup(a);
|
a._source.ReleaseGroup(a);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -388,13 +330,13 @@ namespace DCFApixels.DragonECS
|
|||||||
/// <returns>new group from pool</returns>
|
/// <returns>new group from pool</returns>
|
||||||
public static EcsGroup And(EcsGroup a, EcsGroup b)
|
public static EcsGroup And(EcsGroup a, EcsGroup b)
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (a._source != b._source) throw new ArgumentException("a.WorldIndex != b.WorldIndex");
|
if (a._source != b._source) throw new ArgumentException("a.WorldIndex != b.WorldIndex");
|
||||||
#endif
|
#endif
|
||||||
EcsGroup result = a._source.GetGroupFromPool();
|
EcsGroup result = a._source.GetGroupFromPool();
|
||||||
foreach (var item in a)
|
foreach (var item in a)
|
||||||
if (b.Has(item))
|
if (b.Has(item))
|
||||||
result.AggressiveAdd(item);
|
result.AddInternal(item);
|
||||||
a._source.ReleaseGroup(a);
|
a._source.ReleaseGroup(a);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -402,12 +344,12 @@ namespace DCFApixels.DragonECS
|
|||||||
/// <returns>new group from pool</returns>
|
/// <returns>new group from pool</returns>
|
||||||
public static EcsGroup Union(EcsGroup a, EcsGroup b)
|
public static EcsGroup Union(EcsGroup a, EcsGroup b)
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (a._source != b._source) throw new ArgumentException("a.WorldIndex != b.WorldIndex");
|
if (a._source != b._source) throw new ArgumentException("a.WorldIndex != b.WorldIndex");
|
||||||
#endif
|
#endif
|
||||||
EcsGroup result = a._source.GetGroupFromPool();
|
EcsGroup result = a._source.GetGroupFromPool();
|
||||||
foreach (var item in a)
|
foreach (var item in a)
|
||||||
result.AggressiveAdd(item);
|
result.AddInternal(item);
|
||||||
foreach (var item in a)
|
foreach (var item in a)
|
||||||
result.Add(item);
|
result.Add(item);
|
||||||
return result;
|
return result;
|
||||||
@ -415,34 +357,9 @@ namespace DCFApixels.DragonECS
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region GetEnumerator
|
#region GetEnumerator
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private void Unlock()
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (_lockCount <= 0)
|
|
||||||
{
|
|
||||||
throw new Exception($"Invalid lock-unlock balance for {nameof(EcsGroup)}.");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (--_lockCount <= 0)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < _delayedOpsCount; i++)
|
|
||||||
{
|
|
||||||
delayedOp op = _delayedOps[i];
|
|
||||||
if (op >= 0) //delayedOp.IsAdded
|
|
||||||
AggressiveAdd(op & int.MaxValue); //delayedOp.EcsEntity
|
|
||||||
else
|
|
||||||
AggressiveRemove(op & int.MaxValue); //delayedOp.EcsEntity
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private ProfilerMarker _getEnumeratorReturn = new ProfilerMarker("EcsGroup.GetEnumerator");
|
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public Enumerator GetEnumerator()
|
public Enumerator GetEnumerator()
|
||||||
{
|
{
|
||||||
// _lockCount++;
|
|
||||||
return new Enumerator(this);
|
return new Enumerator(this);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
@ -538,13 +455,13 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
public void Release()
|
public void Release()
|
||||||
{
|
{
|
||||||
_isReleazed = true;
|
_isReleased = true;
|
||||||
_source.ReleaseGroup(this);
|
_source.ReleaseGroup(this);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region ThrowHalper
|
#region ThrowHalper
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
internal static class ThrowHalper
|
internal static class ThrowHalper
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
@ -558,6 +475,7 @@ namespace DCFApixels.DragonECS
|
|||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Extensions
|
||||||
public static class EcsGroupExtensions
|
public static class EcsGroupExtensions
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@ -571,4 +489,5 @@ namespace DCFApixels.DragonECS
|
|||||||
if (array.Length < self.CapacityDense) Array.Resize(ref array, self.CapacityDense);
|
if (array.Length < self.CapacityDense) Array.Resize(ref array, self.CapacityDense);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using DCFApixels.DragonECS.RunnersCore;
|
using DCFApixels.DragonECS.Internal;
|
||||||
|
using DCFApixels.DragonECS.RunnersCore;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -10,21 +11,6 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
public sealed class EcsPipeline
|
public sealed class EcsPipeline
|
||||||
{
|
{
|
||||||
private static EcsPipeline _empty;
|
|
||||||
public static EcsPipeline Empty
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if(_empty == null)
|
|
||||||
{
|
|
||||||
_empty = new EcsPipeline(Array.Empty<IEcsSystem>());
|
|
||||||
_empty.Init();
|
|
||||||
_empty._isEmptyDummy = true;
|
|
||||||
}
|
|
||||||
return _empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEcsSystem[] _allSystems;
|
private IEcsSystem[] _allSystems;
|
||||||
private Dictionary<Type, IEcsRunner> _runners;
|
private Dictionary<Type, IEcsRunner> _runners;
|
||||||
private IEcsRunProcess _runRunnerCache;
|
private IEcsRunProcess _runRunnerCache;
|
||||||
@ -104,7 +90,7 @@ namespace DCFApixels.DragonECS
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Run()
|
public void Run()
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
CheckBeforeInitForMethod(nameof(Run));
|
CheckBeforeInitForMethod(nameof(Run));
|
||||||
CheckAfterDestroyForMethod(nameof(Run));
|
CheckAfterDestroyForMethod(nameof(Run));
|
||||||
#endif
|
#endif
|
||||||
@ -115,7 +101,7 @@ namespace DCFApixels.DragonECS
|
|||||||
if (_isEmptyDummy)
|
if (_isEmptyDummy)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
CheckBeforeInitForMethod(nameof(Run));
|
CheckBeforeInitForMethod(nameof(Run));
|
||||||
#endif
|
#endif
|
||||||
if (_isDestoryed == true)
|
if (_isDestoryed == true)
|
||||||
@ -129,7 +115,7 @@ namespace DCFApixels.DragonECS
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region StateChecks
|
#region StateChecks
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
private void CheckBeforeInitForMethod(string methodName)
|
private void CheckBeforeInitForMethod(string methodName)
|
||||||
{
|
{
|
||||||
if (!_isInit)
|
if (!_isInit)
|
||||||
@ -159,7 +145,6 @@ namespace DCFApixels.DragonECS
|
|||||||
private HashSet<Type> _uniqueTypes;
|
private HashSet<Type> _uniqueTypes;
|
||||||
private readonly Dictionary<string, List<IEcsSystem>> _systems;
|
private readonly Dictionary<string, List<IEcsSystem>> _systems;
|
||||||
private readonly string _basicLayer;
|
private readonly string _basicLayer;
|
||||||
|
|
||||||
public readonly LayerList Layers;
|
public readonly LayerList Layers;
|
||||||
public Builder()
|
public Builder()
|
||||||
{
|
{
|
||||||
@ -197,10 +182,7 @@ namespace DCFApixels.DragonECS
|
|||||||
List<IEcsSystem> list;
|
List<IEcsSystem> list;
|
||||||
if (!_systems.TryGetValue(layerName, out list))
|
if (!_systems.TryGetValue(layerName, out list))
|
||||||
{
|
{
|
||||||
list = new List<IEcsSystem>
|
list = new List<IEcsSystem> { new SystemsBlockMarkerSystem(layerName.ToString()) };
|
||||||
{
|
|
||||||
new SystemsBlockMarkerSystem(layerName.ToString())
|
|
||||||
};
|
|
||||||
_systems.Add(layerName, list);
|
_systems.Add(layerName, list);
|
||||||
}
|
}
|
||||||
if ((_uniqueTypes.Add(system.GetType()) == false && isUnique))
|
if ((_uniqueTypes.Add(system.GetType()) == false && isUnique))
|
||||||
@ -219,8 +201,6 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
public EcsPipeline Build()
|
public EcsPipeline Build()
|
||||||
{
|
{
|
||||||
//EcsDebug.Print(string.Join(", ", Layers));
|
|
||||||
|
|
||||||
Add(new DeleteEmptyEntitesSystem(), EcsConsts.POST_END_LAYER);
|
Add(new DeleteEmptyEntitesSystem(), EcsConsts.POST_END_LAYER);
|
||||||
|
|
||||||
List<IEcsSystem> result = new List<IEcsSystem>(32);
|
List<IEcsSystem> result = new List<IEcsSystem>(32);
|
||||||
@ -350,30 +330,21 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
public interface IEcsModule
|
public interface IEcsModule
|
||||||
{
|
{
|
||||||
public void ImportSystems(EcsPipeline.Builder b);
|
void ImportSystems(EcsPipeline.Builder b);
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Extensions
|
#region Extensions
|
||||||
public static class EcsPipelineExtensions
|
public static class EcsPipelineExtensions
|
||||||
{
|
{
|
||||||
public static bool IsNullOrDestroyed(this EcsPipeline self)
|
public static bool IsNullOrDestroyed(this EcsPipeline self) => self == null || self.IsDestoryed;
|
||||||
{
|
|
||||||
return self == null || self.IsDestoryed;
|
|
||||||
}
|
|
||||||
public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, IEnumerable<IEcsSystem> range, string layerName = null)
|
public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, IEnumerable<IEcsSystem> range, string layerName = null)
|
||||||
{
|
{
|
||||||
foreach (var item in range)
|
foreach (var item in range) self.Add(item, layerName);
|
||||||
{
|
|
||||||
self.Add(item, layerName);
|
|
||||||
}
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
public static EcsPipeline.Builder AddUnique(this EcsPipeline.Builder self, IEnumerable<IEcsSystem> range, string layerName = null)
|
public static EcsPipeline.Builder AddUnique(this EcsPipeline.Builder self, IEnumerable<IEcsSystem> range, string layerName = null)
|
||||||
{
|
{
|
||||||
foreach (var item in range)
|
foreach (var item in range) self.AddUnique(item, layerName);
|
||||||
{
|
|
||||||
self.AddUnique(item, layerName);
|
|
||||||
}
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
public static EcsPipeline BuildAndInit(this EcsPipeline.Builder self)
|
public static EcsPipeline BuildAndInit(this EcsPipeline.Builder self)
|
||||||
@ -382,7 +353,6 @@ namespace DCFApixels.DragonECS
|
|||||||
result.Init();
|
result.Init();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ using System.Collections.ObjectModel;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using static DCFApixels.DragonECS.EcsDebugUtility;
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
@ -31,21 +32,19 @@ namespace DCFApixels.DragonECS
|
|||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
public interface IEcsRunner
|
public interface IEcsRunner
|
||||||
{
|
{
|
||||||
public EcsPipeline Source { get; }
|
EcsPipeline Source { get; }
|
||||||
public Type Interface { get; }
|
Type Interface { get; }
|
||||||
public IList Targets { get; }
|
IList Targets { get; }
|
||||||
public object Filter { get; }
|
object Filter { get; }
|
||||||
public bool IsHasFilter { get; }
|
bool IsHasFilter { get; }
|
||||||
public bool IsDestroyed { get; }
|
bool IsDestroyed { get; }
|
||||||
public bool IsEmpty { get; }
|
bool IsEmpty { get; }
|
||||||
|
void Destroy();
|
||||||
public void Destroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static class EcsRunnerActivator
|
internal static class EcsRunnerActivator
|
||||||
{
|
{
|
||||||
private static Dictionary<Type, Type> _runnerHandlerTypes; //interface base type/Runner handler type pairs;
|
private static Dictionary<Type, Type> _runnerHandlerTypes; //interface base type/Runner handler type pairs;
|
||||||
|
|
||||||
static EcsRunnerActivator()
|
static EcsRunnerActivator()
|
||||||
{
|
{
|
||||||
List<Exception> delayedExceptions = new List<Exception>();
|
List<Exception> delayedExceptions = new List<Exception>();
|
||||||
@ -58,25 +57,23 @@ namespace DCFApixels.DragonECS
|
|||||||
.Where(type => type.BaseType != null && type.BaseType.IsGenericType && runnerBaseType == type.BaseType.GetGenericTypeDefinition()));
|
.Where(type => type.BaseType != null && type.BaseType.IsGenericType && runnerBaseType == type.BaseType.GetGenericTypeDefinition()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
for (int i = 0; i < runnerHandlerTypes.Count; i++)
|
for (int i = 0; i < runnerHandlerTypes.Count; i++)
|
||||||
{
|
|
||||||
var e = CheckRunnerValide(runnerHandlerTypes[i]);
|
|
||||||
if (e != null)
|
|
||||||
{
|
{
|
||||||
runnerHandlerTypes.RemoveAt(i--);
|
var e = CheckRunnerValide(runnerHandlerTypes[i]);
|
||||||
delayedExceptions.Add(e);
|
if (e != null)
|
||||||
|
{
|
||||||
|
runnerHandlerTypes.RemoveAt(i--);
|
||||||
|
delayedExceptions.Add(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
_runnerHandlerTypes = new Dictionary<Type, 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];
|
||||||
// if(!_runnerHandlerTypes.ContainsKey(interfaceType.GUID))//TODO это кажется костыль, изначально все работало без этого ифа
|
_runnerHandlerTypes.Add(interfaceType.IsGenericType ? interfaceType.GetGenericTypeDefinition() : interfaceType, item);
|
||||||
_runnerHandlerTypes.Add(interfaceType.IsGenericType ? interfaceType.GetGenericTypeDefinition() : interfaceType, item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delayedExceptions.Count > 0)
|
if (delayedExceptions.Count > 0)
|
||||||
{
|
{
|
||||||
foreach (var item in delayedExceptions) EcsDebug.Print(EcsConsts.DEBUG_ERROR_TAG, item.Message);
|
foreach (var item in delayedExceptions) EcsDebug.Print(EcsConsts.DEBUG_ERROR_TAG, item.Message);
|
||||||
@ -91,24 +88,23 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
if (type.ReflectedType != null)
|
if (type.ReflectedType != null)
|
||||||
{
|
{
|
||||||
return new EcsRunnerImplementationException($"{type.FullName}.ReflectedType must be Null, but equal to {type.ReflectedType.FullName}.");
|
return new EcsRunnerImplementationException($"{GetGenericTypeFullName(type, 1)}.ReflectedType must be Null, but equal to {GetGenericTypeFullName(type.ReflectedType, 1)}.");
|
||||||
}
|
}
|
||||||
if (!baseTypeArgument.IsInterface)
|
if (!baseTypeArgument.IsInterface)
|
||||||
{
|
{
|
||||||
return new EcsRunnerImplementationException($"Argument T of class EcsRunner<T>, can only be an inetrface.The {baseTypeArgument.FullName} type is not an interface.");
|
return new EcsRunnerImplementationException($"Argument T of class EcsRunner<T>, can only be an inetrface. The {GetGenericTypeFullName(baseTypeArgument, 1)} type is not an interface.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var interfaces = type.GetInterfaces();
|
var interfaces = type.GetInterfaces();
|
||||||
|
|
||||||
if (!interfaces.Any(o => o == baseTypeArgument))
|
if (!interfaces.Any(o => o == baseTypeArgument))
|
||||||
{
|
{
|
||||||
return new EcsRunnerImplementationException($"Runner {type.FullName} does not implement interface {baseTypeArgument.FullName}.");
|
return new EcsRunnerImplementationException($"Runner {GetGenericTypeFullName(type, 1)} does not implement interface {GetGenericTypeFullName(baseTypeArgument, 1)}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static void InitFor<TInterface>() where TInterface : IEcsSystem
|
internal static void InitFor<TInterface>() where TInterface : IEcsSystem
|
||||||
{
|
{
|
||||||
@ -116,7 +112,7 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
if (!_runnerHandlerTypes.TryGetValue(interfaceType.IsGenericType ? interfaceType.GetGenericTypeDefinition() : interfaceType, out Type runnerType))
|
if (!_runnerHandlerTypes.TryGetValue(interfaceType.IsGenericType ? interfaceType.GetGenericTypeDefinition() : interfaceType, out Type runnerType))
|
||||||
{
|
{
|
||||||
throw new Exception();
|
throw new EcsRunnerImplementationException($"There is no implementation of a runner for the {GetGenericTypeFullName<TInterface>(1)} interface.");
|
||||||
}
|
}
|
||||||
if (interfaceType.IsGenericType)
|
if (interfaceType.IsGenericType)
|
||||||
{
|
{
|
||||||
@ -134,23 +130,23 @@ namespace DCFApixels.DragonECS
|
|||||||
private static Type _subclass;
|
private static Type _subclass;
|
||||||
internal static void Register(Type subclass)
|
internal static void Register(Type subclass)
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (_subclass != null)
|
if (_subclass != null)
|
||||||
{
|
{
|
||||||
throw new EcsRunnerImplementationException($"The Runner<{typeof(TInterface).FullName}> can have only one implementing subclass");
|
throw new EcsRunnerImplementationException($"The Runner<{typeof(TInterface).FullName}> can have only one implementing subclass");
|
||||||
}
|
}
|
||||||
|
|
||||||
Type interfaceType = typeof(TInterface);
|
Type interfaceType = typeof(TInterface);
|
||||||
|
|
||||||
var interfaces = interfaceType.GetInterfaces();
|
var interfaces = interfaceType.GetInterfaces();
|
||||||
if (interfaceType.IsInterface == false)
|
if (interfaceType.IsInterface == false)
|
||||||
{
|
{
|
||||||
throw new ArgumentException($"{typeof(TInterface).FullName} is not interface");
|
throw new ArgumentException($"{typeof(TInterface).FullName} is not interface");
|
||||||
}
|
}
|
||||||
if (interfaces.Length != 1 || interfaces[0] != typeof(IEcsSystem))
|
if (interfaces.Length != 1 || interfaces[0] != typeof(IEcsSystem))
|
||||||
{
|
{
|
||||||
throw new ArgumentException($"{typeof(TInterface).FullName} does not directly inherit the {nameof(IEcsSystem)} interface");
|
throw new ArgumentException($"{typeof(TInterface).FullName} does not directly inherit the {nameof(IEcsSystem)} interface");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
_subclass = subclass;
|
_subclass = subclass;
|
||||||
}
|
}
|
||||||
@ -192,9 +188,7 @@ namespace DCFApixels.DragonECS
|
|||||||
#region Instantiate
|
#region Instantiate
|
||||||
private static TInterface Instantiate(EcsPipeline source, TInterface[] targets, bool isHasFilter, object filter)
|
private static TInterface Instantiate(EcsPipeline source, TInterface[] targets, bool isHasFilter, object filter)
|
||||||
{
|
{
|
||||||
if (_subclass == null)
|
if (_subclass == null) EcsRunnerActivator.InitFor<TInterface>();
|
||||||
EcsRunnerActivator.InitFor<TInterface>();
|
|
||||||
|
|
||||||
var instance = (EcsRunner<TInterface>)Activator.CreateInstance(_subclass);
|
var instance = (EcsRunner<TInterface>)Activator.CreateInstance(_subclass);
|
||||||
return (TInterface)(IEcsSystem)instance.Set(source, targets, isHasFilter, filter);
|
return (TInterface)(IEcsSystem)instance.Set(source, targets, isHasFilter, filter);
|
||||||
}
|
}
|
||||||
@ -235,7 +229,6 @@ namespace DCFApixels.DragonECS
|
|||||||
OnSetup();
|
OnSetup();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Rebuild()
|
internal void Rebuild()
|
||||||
{
|
{
|
||||||
if (_isHasFilter)
|
if (_isHasFilter)
|
||||||
@ -243,7 +236,6 @@ namespace DCFApixels.DragonECS
|
|||||||
else
|
else
|
||||||
Set(_source, FilterSystems(_source.AllSystems, _filter), _isHasFilter, _filter);
|
Set(_source, FilterSystems(_source.AllSystems, _filter), _isHasFilter, _filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Destroy()
|
public void Destroy()
|
||||||
{
|
{
|
||||||
_isDestroyed = true;
|
_isDestroyed = true;
|
||||||
@ -254,11 +246,11 @@ namespace DCFApixels.DragonECS
|
|||||||
_filter = null;
|
_filter = null;
|
||||||
OnDestroy();
|
OnDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnSetup() { }
|
protected virtual void OnSetup() { }
|
||||||
protected virtual void OnDestroy() { }
|
protected virtual void OnDestroy() { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Extensions
|
#region Extensions
|
||||||
public static class EcsRunner
|
public static class EcsRunner
|
||||||
{
|
{
|
||||||
|
|||||||
@ -13,7 +13,6 @@ namespace DCFApixels.DragonECS
|
|||||||
internal EcsWorld source;
|
internal EcsWorld source;
|
||||||
[EditorBrowsable(EditorBrowsableState.Always)]
|
[EditorBrowsable(EditorBrowsableState.Always)]
|
||||||
internal EcsMask mask;
|
internal EcsMask mask;
|
||||||
|
|
||||||
private bool _isInit;
|
private bool _isInit;
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
@ -26,7 +25,7 @@ namespace DCFApixels.DragonECS
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
public bool IsMatches(int entityID) => source.IsMaskCompatible(mask, entityID);
|
public bool IsMatches(int entityID) => source.IsMatchesMask(mask, entityID);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Builder
|
#region Builder
|
||||||
@ -84,7 +83,7 @@ namespace DCFApixels.DragonECS
|
|||||||
public void IncludeImplicit<TComponent>()
|
public void IncludeImplicit<TComponent>()
|
||||||
{
|
{
|
||||||
int id = _world.GetComponentID<TComponent>();
|
int id = _world.GetComponentID<TComponent>();
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (_inc.Contains(id) || _exc.Contains(id)) throw new EcsFrameworkException($"{typeof(TComponent).Name} already in constraints list.");
|
if (_inc.Contains(id) || _exc.Contains(id)) throw new EcsFrameworkException($"{typeof(TComponent).Name} already in constraints list.");
|
||||||
#endif
|
#endif
|
||||||
_inc.Add(_world.GetComponentID<TComponent>());
|
_inc.Add(_world.GetComponentID<TComponent>());
|
||||||
@ -92,7 +91,7 @@ namespace DCFApixels.DragonECS
|
|||||||
public void ExcludeImplicit<TComponent>()
|
public void ExcludeImplicit<TComponent>()
|
||||||
{
|
{
|
||||||
int id = _world.GetComponentID<TComponent>();
|
int id = _world.GetComponentID<TComponent>();
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (_inc.Contains(id) || _exc.Contains(id)) throw new EcsFrameworkException($"{typeof(TComponent).Name} already in constraints list.");
|
if (_inc.Contains(id) || _exc.Contains(id)) throw new EcsFrameworkException($"{typeof(TComponent).Name} already in constraints list.");
|
||||||
#endif
|
#endif
|
||||||
_exc.Add(_world.GetComponentID<TComponent>());
|
_exc.Add(_world.GetComponentID<TComponent>());
|
||||||
@ -111,6 +110,7 @@ namespace DCFApixels.DragonECS
|
|||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Extensions
|
||||||
public static class EcsSubjectExtensions
|
public static class EcsSubjectExtensions
|
||||||
{
|
{
|
||||||
public static EcsSubjectIterator<TSubject> GetIterator<TSubject>(this TSubject self) where TSubject : EcsSubject
|
public static EcsSubjectIterator<TSubject> GetIterator<TSubject>(this TSubject self) where TSubject : EcsSubject
|
||||||
@ -122,6 +122,7 @@ namespace DCFApixels.DragonECS
|
|||||||
return new EcsSubjectIterator<TSubject>(self, sourceGroup);
|
return new EcsSubjectIterator<TSubject>(self, sourceGroup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region BuilderBase
|
#region BuilderBase
|
||||||
public abstract class EcsSubjectBuilderBase
|
public abstract class EcsSubjectBuilderBase
|
||||||
@ -135,20 +136,18 @@ namespace DCFApixels.DragonECS
|
|||||||
#region Mask
|
#region Mask
|
||||||
public sealed class EcsMask
|
public sealed class EcsMask
|
||||||
{
|
{
|
||||||
internal readonly Type WorldType;
|
internal readonly Type _worldType;
|
||||||
internal readonly int[] Inc;
|
internal readonly int[] _inc;
|
||||||
internal readonly int[] Exc;
|
internal readonly int[] _exc;
|
||||||
|
|
||||||
public EcsMask(Type worldType, int[] inc, int[] exc)
|
public EcsMask(Type worldType, int[] inc, int[] exc)
|
||||||
{
|
{
|
||||||
WorldType = worldType;
|
_worldType = worldType;
|
||||||
Inc = inc;
|
_inc = inc;
|
||||||
Exc = exc;
|
_exc = exc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"Inc({string.Join(", ", Inc)}) Exc({string.Join(", ", Exc)})";
|
return $"Inc({string.Join(", ", _inc)}) Exc({string.Join(", ", _exc)})";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
@ -181,7 +180,7 @@ namespace DCFApixels.DragonECS
|
|||||||
group.Clear();
|
group.Clear();
|
||||||
var enumerator = GetEnumerator();
|
var enumerator = GetEnumerator();
|
||||||
while (enumerator.MoveNext())
|
while (enumerator.MoveNext())
|
||||||
group.AggressiveAdd(enumerator.Current);
|
group.AddInternal(enumerator.Current);
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public Enumerator GetEnumerator() => new Enumerator(sourceGroup, s);
|
public Enumerator GetEnumerator() => new Enumerator(sourceGroup, s);
|
||||||
@ -207,9 +206,9 @@ namespace DCFApixels.DragonECS
|
|||||||
public Enumerator(EcsReadonlyGroup sourceGroup, EcsSubject subject)
|
public Enumerator(EcsReadonlyGroup sourceGroup, EcsSubject subject)
|
||||||
{
|
{
|
||||||
_sourceGroup = sourceGroup.GetEnumerator();
|
_sourceGroup = sourceGroup.GetEnumerator();
|
||||||
_inc = subject.mask.Inc;
|
_inc = subject.mask._inc;
|
||||||
_exc = subject.mask.Exc;
|
_exc = subject.mask._exc;
|
||||||
_pools = subject.World.pools;
|
_pools = subject.World._pools;
|
||||||
}
|
}
|
||||||
public int Current
|
public int Current
|
||||||
{
|
{
|
||||||
|
|||||||
249
src/EcsWorld.cs
249
src/EcsWorld.cs
@ -1,17 +1,11 @@
|
|||||||
using System;
|
using DCFApixels.DragonECS.Internal;
|
||||||
|
using DCFApixels.DragonECS.Utils;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
using Internal;
|
|
||||||
|
|
||||||
internal sealed class EcsNullWorld : EcsWorld<EcsNullWorld>
|
|
||||||
{
|
|
||||||
public EcsNullWorld() : base(false) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class EcsWorld
|
public abstract class EcsWorld
|
||||||
{
|
{
|
||||||
private const short GEN_BITS = 0x7fff;
|
private const short GEN_BITS = 0x7fff;
|
||||||
@ -20,6 +14,7 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
public static EcsWorld[] Worlds = new EcsWorld[8];
|
public static EcsWorld[] Worlds = new EcsWorld[8];
|
||||||
private static IntDispenser _worldIdDispenser = new IntDispenser(0);
|
private static IntDispenser _worldIdDispenser = new IntDispenser(0);
|
||||||
|
|
||||||
public readonly short uniqueID;
|
public readonly short uniqueID;
|
||||||
|
|
||||||
private int _worldTypeID;
|
private int _worldTypeID;
|
||||||
@ -27,17 +22,17 @@ namespace DCFApixels.DragonECS
|
|||||||
private IntDispenser _entityDispenser;
|
private IntDispenser _entityDispenser;
|
||||||
private int _entitiesCount;
|
private int _entitiesCount;
|
||||||
private int _entitesCapacity;
|
private int _entitesCapacity;
|
||||||
private short[] _gens; //старший бит указывает на то жива ли сущьность.
|
private short[] _gens; //старший бит указывает на то жива ли сущность
|
||||||
private short[] _componentCounts;
|
private short[] _componentCounts;
|
||||||
private EcsGroup _allEntites;
|
private EcsGroup _allEntites;
|
||||||
|
|
||||||
//буфер удаления откладывает освобождение андишников сущьностей.
|
//буфер удаления откладывает освобождение андишников сущностей.
|
||||||
//Нужен для того чтобы запускать некоторые процесыы связанные с удалением сущьности не по одному при каждом удалении, а пачкой
|
//Нужен для того чтобы запускать некоторые процесыы связанные с удалением сущности не по одному при каждом удалении, а пачкой
|
||||||
//В теории такой подход частично улучшает ситуацию с переполнением поколений
|
//В теории такой подход частично улучшает ситуацию с переполнением поколений
|
||||||
private int[] _delEntBuffer;
|
private int[] _delEntBuffer;
|
||||||
private int _delEntBufferCount;
|
private int _delEntBufferCount;
|
||||||
|
|
||||||
internal IEcsPoolImplementation[] pools;
|
internal IEcsPoolImplementation[] _pools;
|
||||||
private EcsNullPool _nullPool;
|
private EcsNullPool _nullPool;
|
||||||
private int _poolsCount = 0;
|
private int _poolsCount = 0;
|
||||||
|
|
||||||
@ -55,7 +50,7 @@ namespace DCFApixels.DragonECS
|
|||||||
public int Count => _entitiesCount;
|
public int Count => _entitiesCount;
|
||||||
public int Capacity => _entitesCapacity; //_denseEntities.Length;
|
public int Capacity => _entitesCapacity; //_denseEntities.Length;
|
||||||
public EcsReadonlyGroup Entities => _allEntites.Readonly;
|
public EcsReadonlyGroup Entities => _allEntites.Readonly;
|
||||||
public ReadOnlySpan<IEcsPoolImplementation> AllPools => pools;// new ReadOnlySpan<IEcsPoolImplementation>(pools, 0, _poolsCount);
|
public ReadOnlySpan<IEcsPoolImplementation> AllPools => _pools;// new ReadOnlySpan<IEcsPoolImplementation>(pools, 0, _poolsCount);
|
||||||
public int PoolsCount => _poolsCount;
|
public int PoolsCount => _poolsCount;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -84,8 +79,8 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
_entityDispenser = new IntDispenser(0);
|
_entityDispenser = new IntDispenser(0);
|
||||||
_nullPool = EcsNullPool.instance;
|
_nullPool = EcsNullPool.instance;
|
||||||
pools = new IEcsPoolImplementation[512];
|
_pools = new IEcsPoolImplementation[512];
|
||||||
ArrayUtility.Fill(pools, _nullPool);
|
ArrayUtility.Fill(_pools, _nullPool);
|
||||||
|
|
||||||
_gens = new short[_entitesCapacity];
|
_gens = new short[_entitesCapacity];
|
||||||
_componentCounts = new short[_entitesCapacity];
|
_componentCounts = new short[_entitesCapacity];
|
||||||
@ -106,7 +101,7 @@ namespace DCFApixels.DragonECS
|
|||||||
_entityDispenser = null;
|
_entityDispenser = null;
|
||||||
//_denseEntities = null;
|
//_denseEntities = null;
|
||||||
_gens = null;
|
_gens = null;
|
||||||
pools = null;
|
_pools = null;
|
||||||
_nullPool = null;
|
_nullPool = null;
|
||||||
_subjects = null;
|
_subjects = null;
|
||||||
_executors = null;
|
_executors = null;
|
||||||
@ -130,27 +125,27 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
int uniqueID = WorldMetaStorage.GetComponentId<TComponent>(_worldTypeID);
|
int uniqueID = WorldMetaStorage.GetComponentId<TComponent>(_worldTypeID);
|
||||||
|
|
||||||
if (uniqueID >= pools.Length)
|
if (uniqueID >= _pools.Length)
|
||||||
{
|
{
|
||||||
int oldCapacity = pools.Length;
|
int oldCapacity = _pools.Length;
|
||||||
Array.Resize(ref pools, pools.Length << 1);
|
Array.Resize(ref _pools, _pools.Length << 1);
|
||||||
ArrayUtility.Fill(pools, _nullPool, oldCapacity, oldCapacity - pools.Length);
|
ArrayUtility.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pools[uniqueID] == _nullPool)
|
if (_pools[uniqueID] == _nullPool)
|
||||||
{
|
{
|
||||||
var pool = new TPool();
|
var pool = new TPool();
|
||||||
pools[uniqueID] = pool;
|
_pools[uniqueID] = pool;
|
||||||
pool.OnInit(this, uniqueID);
|
pool.OnInit(this, uniqueID);
|
||||||
_poolsCount++;
|
_poolsCount++;
|
||||||
//EcsDebug.Print(pool.GetType().FullName);
|
//EcsDebug.Print(pool.GetType().FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (TPool)pools[uniqueID];
|
return (TPool)_pools[uniqueID];
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Queries
|
#region Subjects
|
||||||
public TSubject GetSubject<TSubject>() where TSubject : EcsSubject
|
public TSubject GetSubject<TSubject>() where TSubject : EcsSubject
|
||||||
{
|
{
|
||||||
int uniqueID = WorldMetaStorage.GetSubjectId<TSubject>(_worldTypeID);
|
int uniqueID = WorldMetaStorage.GetSubjectId<TSubject>(_worldTypeID);
|
||||||
@ -160,119 +155,60 @@ namespace DCFApixels.DragonECS
|
|||||||
_subjects[uniqueID] = EcsSubject.Builder.Build<TSubject>(this);
|
_subjects[uniqueID] = EcsSubject.Builder.Build<TSubject>(this);
|
||||||
return (TSubject)_subjects[uniqueID];
|
return (TSubject)_subjects[uniqueID];
|
||||||
}
|
}
|
||||||
#region Iterate
|
|
||||||
public EcsSubjectIterator<TSubject> IterateFor<TSubject>(EcsReadonlyGroup sourceGroup, out TSubject subject) where TSubject : EcsSubject
|
|
||||||
{
|
|
||||||
|
|
||||||
subject = GetSubject<TSubject>();
|
|
||||||
return subject.GetIteratorFor(sourceGroup);
|
|
||||||
}
|
|
||||||
public EcsSubjectIterator<TSubject> IterateFor<TSubject>(EcsReadonlyGroup sourceGroup) where TSubject : EcsSubject
|
|
||||||
{
|
|
||||||
return GetSubject<TSubject>().GetIteratorFor(sourceGroup);
|
|
||||||
}
|
|
||||||
public EcsSubjectIterator<TSubject> Iterate<TSubject>(out TSubject subject) where TSubject : EcsSubject
|
|
||||||
{
|
|
||||||
subject = GetSubject<TSubject>();
|
|
||||||
return subject.GetIterator();
|
|
||||||
}
|
|
||||||
public EcsSubjectIterator<TSubject> Iterate<TSubject>() where TSubject : EcsSubject
|
|
||||||
{
|
|
||||||
return GetSubject<TSubject>().GetIterator();
|
|
||||||
}
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Where
|
#region Queries
|
||||||
private EcsWhereExecutor<TSubject> GetWhereExecutor<TSubject>() where TSubject : EcsSubject
|
public TExecutor GetExecutor<TExecutor>(Func<EcsWorld, TExecutor> builder) where TExecutor: EcsQueryExecutor
|
||||||
{
|
{
|
||||||
int id = WorldMetaStorage.GetExecutorId<EcsWhereExecutor<TSubject>>(_worldTypeID);
|
int id = WorldMetaStorage.GetExecutorId<TExecutor>(_worldTypeID);
|
||||||
if (id >= _executors.Length)
|
if (id >= _executors.Length)
|
||||||
Array.Resize(ref _executors, _executors.Length << 1);
|
Array.Resize(ref _executors, _executors.Length << 1);
|
||||||
if (_executors[id] == null)
|
if (_executors[id] == null)
|
||||||
_executors[id] = new EcsWhereExecutor<TSubject>(GetSubject<TSubject>());
|
_executors[id] = builder(this);
|
||||||
return (EcsWhereExecutor<TSubject>)_executors[id];
|
return (TExecutor)_executors[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
private EcsWhereExecutor<TSubject> EcsWhereExecutorBuilder<TSubject>(EcsWorld world) where TSubject : EcsSubject
|
||||||
|
{
|
||||||
|
return new EcsWhereExecutor<TSubject>(world.GetSubject<TSubject>());
|
||||||
}
|
}
|
||||||
public EcsWhereResult<TSubject> WhereFor<TSubject>(EcsReadonlyGroup sourceGroup, out TSubject subject) where TSubject : EcsSubject
|
public EcsWhereResult<TSubject> WhereFor<TSubject>(EcsReadonlyGroup sourceGroup, out TSubject subject) where TSubject : EcsSubject
|
||||||
{
|
{
|
||||||
var executor = GetWhereExecutor<TSubject>();
|
var executor = GetExecutor(EcsWhereExecutorBuilder<TSubject>);
|
||||||
subject = executor.Subject;
|
subject = executor.Subject;
|
||||||
return executor.ExecuteFor(sourceGroup);
|
return executor.ExecuteFor(sourceGroup);
|
||||||
}
|
}
|
||||||
public EcsWhereResult<TSubject> WhereFor<TSubject>(EcsReadonlyGroup sourceGroup) where TSubject : EcsSubject
|
public EcsWhereResult<TSubject> WhereFor<TSubject>(EcsReadonlyGroup sourceGroup) where TSubject : EcsSubject
|
||||||
{
|
{
|
||||||
return GetWhereExecutor<TSubject>().ExecuteFor(sourceGroup);
|
return GetExecutor(EcsWhereExecutorBuilder<TSubject>).ExecuteFor(sourceGroup);
|
||||||
}
|
}
|
||||||
public EcsWhereResult<TSubject> Where<TSubject>(out TSubject subject) where TSubject : EcsSubject
|
public EcsWhereResult<TSubject> Where<TSubject>(out TSubject subject) where TSubject : EcsSubject
|
||||||
{
|
{
|
||||||
var executor = GetWhereExecutor<TSubject>();
|
var executor = GetExecutor(EcsWhereExecutorBuilder<TSubject>);
|
||||||
subject = executor.Subject;
|
subject = executor.Subject;
|
||||||
return executor.Execute();
|
return executor.Execute();
|
||||||
}
|
}
|
||||||
public EcsWhereResult<TSubject> Where<TSubject>() where TSubject : EcsSubject
|
public EcsWhereResult<TSubject> Where<TSubject>() where TSubject : EcsSubject
|
||||||
{
|
{
|
||||||
return GetWhereExecutor<TSubject>().Execute();
|
return GetExecutor(EcsWhereExecutorBuilder<TSubject>).Execute();
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Join
|
#region IsMatchesMask
|
||||||
private EcsJoinAttachExecutor<TSubject, TAttachComponent> GetJoinAttachExecutor<TSubject, TAttachComponent>()
|
public bool IsMatchesMask(EcsMask mask, int entityID)
|
||||||
where TSubject : EcsSubject
|
|
||||||
where TAttachComponent : struct, IEcsAttachComponent
|
|
||||||
{
|
{
|
||||||
int id = WorldMetaStorage.GetExecutorId<EcsJoinAttachExecutor<TSubject, TAttachComponent>>(_worldTypeID);
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (id >= _executors.Length)
|
if (mask._worldType != Archetype)
|
||||||
Array.Resize(ref _executors, _executors.Length << 1);
|
|
||||||
if (_executors[id] == null)
|
|
||||||
_executors[id] = new EcsJoinAttachExecutor<TSubject, TAttachComponent>(GetSubject<TSubject>());
|
|
||||||
return (EcsJoinAttachExecutor<TSubject, TAttachComponent>)_executors[id];
|
|
||||||
}
|
|
||||||
public EcsJoinAttachResult<TSubject, TAttachComponent> JoinFor<TSubject, TAttachComponent>(EcsReadonlyGroup sourceGroup, out TSubject subject)
|
|
||||||
where TSubject : EcsSubject
|
|
||||||
where TAttachComponent : struct, IEcsAttachComponent
|
|
||||||
{
|
|
||||||
var executor = GetJoinAttachExecutor<TSubject, TAttachComponent>();
|
|
||||||
subject = executor.Subject;
|
|
||||||
return executor.ExecuteFor(sourceGroup);
|
|
||||||
}
|
|
||||||
public EcsJoinAttachResult<TSubject, TAttachComponent> JoinFor<TSubject, TAttachComponent>(EcsReadonlyGroup sourceGroup)
|
|
||||||
where TSubject : EcsSubject
|
|
||||||
where TAttachComponent : struct, IEcsAttachComponent
|
|
||||||
{
|
|
||||||
return GetJoinAttachExecutor<TSubject, TAttachComponent>().ExecuteFor(sourceGroup);
|
|
||||||
}
|
|
||||||
public EcsJoinAttachResult<TSubject, TAttachComponent> Join<TSubject, TAttachComponent>(out TSubject subject)
|
|
||||||
where TSubject : EcsSubject
|
|
||||||
where TAttachComponent : struct, IEcsAttachComponent
|
|
||||||
{
|
|
||||||
var executor = GetJoinAttachExecutor<TSubject, TAttachComponent>();
|
|
||||||
subject = executor.Subject;
|
|
||||||
return executor.Execute();
|
|
||||||
}
|
|
||||||
public EcsJoinAttachResult<TSubject, TAttachComponent> Join<TSubject, TAttachComponent>()
|
|
||||||
where TSubject : EcsSubject
|
|
||||||
where TAttachComponent : struct, IEcsAttachComponent
|
|
||||||
{
|
|
||||||
return GetJoinAttachExecutor<TSubject, TAttachComponent>().Execute();
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region IsMaskCompatible
|
|
||||||
public bool IsMaskCompatible(EcsMask mask, int entityID)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (mask.WorldType != Archetype)
|
|
||||||
throw new EcsFrameworkException("mask.WorldArchetypeType != typeof(TTableArhetype)");
|
throw new EcsFrameworkException("mask.WorldArchetypeType != typeof(TTableArhetype)");
|
||||||
#endif
|
#endif
|
||||||
for (int i = 0, iMax = mask.Inc.Length; i < iMax; i++)
|
for (int i = 0, iMax = mask._inc.Length; i < iMax; i++)
|
||||||
{
|
{
|
||||||
if (!pools[mask.Inc[i]].Has(entityID))
|
if (!_pools[mask._inc[i]].Has(entityID))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (int i = 0, iMax = mask.Exc.Length; i < iMax; i++)
|
for (int i = 0, iMax = mask._exc.Length; i < iMax; i++)
|
||||||
{
|
{
|
||||||
if (pools[mask.Exc[i]].Has(entityID))
|
if (_pools[mask._exc[i]].Has(entityID))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -305,7 +241,7 @@ namespace DCFApixels.DragonECS
|
|||||||
_groups.RemoveAt(last);
|
_groups.RemoveAt(last);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (var item in pools)
|
foreach (var item in _pools)
|
||||||
item.OnWorldResize(_gens.Length);
|
item.OnWorldResize(_gens.Length);
|
||||||
|
|
||||||
_listeners.InvokeOnWorldResize(_gens.Length);
|
_listeners.InvokeOnWorldResize(_gens.Length);
|
||||||
@ -341,30 +277,30 @@ namespace DCFApixels.DragonECS
|
|||||||
public void ReleaseDelEntityBuffer()
|
public void ReleaseDelEntityBuffer()
|
||||||
{
|
{
|
||||||
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);
|
_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;
|
||||||
}
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public short GetGen(int entityID) => _gens[entityID];
|
public short GetGen(int entityID) => _gens[entityID];
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public short GetComponentsCount(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)
|
||||||
{
|
{
|
||||||
if (_componentCounts[e] <= 0)
|
if (_componentCounts[e] <= 0) DelEntity(e);
|
||||||
DelEntity(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CopyEntity(int fromEntityID, int toEntityID)
|
public void CopyEntity(int fromEntityID, int toEntityID)
|
||||||
{
|
{
|
||||||
foreach (var pool in pools)
|
foreach (var pool in _pools)
|
||||||
{
|
{
|
||||||
if(pool.Has(fromEntityID))
|
if(pool.Has(fromEntityID)) pool.Copy(fromEntityID, toEntityID);
|
||||||
pool.Copy(fromEntityID, toEntityID);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public int CloneEntity(int fromEntityID)
|
public int CloneEntity(int fromEntityID)
|
||||||
@ -376,7 +312,7 @@ namespace DCFApixels.DragonECS
|
|||||||
public void CloneEntity(int fromEntityID, int toEntityID)
|
public void CloneEntity(int fromEntityID, int toEntityID)
|
||||||
{
|
{
|
||||||
CopyEntity(fromEntityID, toEntityID);
|
CopyEntity(fromEntityID, toEntityID);
|
||||||
foreach (var pool in pools)
|
foreach (var pool in _pools)
|
||||||
{
|
{
|
||||||
if (!pool.Has(fromEntityID)&& pool.Has(toEntityID))
|
if (!pool.Has(fromEntityID)&& pool.Has(toEntityID))
|
||||||
pool.Del(toEntityID);
|
pool.Del(toEntityID);
|
||||||
@ -384,19 +320,14 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal void IncrementEntityComponentCount(int entityID)
|
internal void IncrementEntityComponentCount(int entityID) => _componentCounts[entityID]++;
|
||||||
{
|
|
||||||
_componentCounts[entityID]++;
|
|
||||||
}
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal void DecrementEntityComponentCount(int entityID)
|
internal void DecrementEntityComponentCount(int entityID)
|
||||||
{
|
{
|
||||||
var count = --_componentCounts[entityID];
|
var count = --_componentCounts[entityID];
|
||||||
if(count == 0 && _allEntites.Has(entityID))
|
if(count == 0 && _allEntites.Has(entityID)) DelEntity(entityID);
|
||||||
DelEntity(entityID);
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
|
if (count < 0) throw new EcsFrameworkException("нарушен баланс инкремента/декремента компонентов");
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (count < 0) throw new EcsFrameworkException("нарушен баланс инкремента.декремента компонентов");
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
@ -408,13 +339,12 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
internal EcsGroup GetGroupFromPool()
|
internal EcsGroup GetGroupFromPool()
|
||||||
{
|
{
|
||||||
if (_groupsPool.Count <= 0)
|
if (_groupsPool.Count <= 0) return new EcsGroup(this);
|
||||||
return new EcsGroup(this);
|
|
||||||
return _groupsPool.Pop();
|
return _groupsPool.Pop();
|
||||||
}
|
}
|
||||||
internal void ReleaseGroup(EcsGroup group)
|
internal void ReleaseGroup(EcsGroup group)
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (group.World != this)
|
if (group.World != this)
|
||||||
throw new ArgumentException("groupFilter.WorldIndex != this");
|
throw new ArgumentException("groupFilter.WorldIndex != this");
|
||||||
#endif
|
#endif
|
||||||
@ -431,10 +361,10 @@ namespace DCFApixels.DragonECS
|
|||||||
if (itemsCount == 0)
|
if (itemsCount == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (var i = 0; i < pools.Length; i++)
|
for (var i = 0; i < _pools.Length; i++)
|
||||||
{
|
{
|
||||||
if (pools[i].Has(entityID))
|
if (_pools[i].Has(entityID))
|
||||||
list.Add(pools[i].GetRaw(entityID));
|
list.Add(_pools[i].GetRaw(entityID));
|
||||||
if (list.Count >= itemsCount)
|
if (list.Count >= itemsCount)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -485,41 +415,25 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
|
|
||||||
#region Utils
|
#region Utils
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 24)]
|
|
||||||
internal readonly struct PoolRunners
|
|
||||||
{
|
|
||||||
public readonly IEcsComponentAdd add;
|
|
||||||
public readonly IEcsComponentWrite write;
|
|
||||||
public readonly IEcsComponentDel del;
|
|
||||||
|
|
||||||
public PoolRunners(EcsPipeline pipeline)
|
|
||||||
{
|
|
||||||
add = pipeline.GetRunner<IEcsComponentAdd>();
|
|
||||||
write = pipeline.GetRunner<IEcsComponentWrite>();
|
|
||||||
del = pipeline.GetRunner<IEcsComponentDel>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static class WorldMetaStorage
|
public static class WorldMetaStorage
|
||||||
{
|
{
|
||||||
private static List<Resizer> resizer = new List<Resizer>();
|
private static List<Resizer> _resizer = new List<Resizer>();
|
||||||
private static int tokenCount = 0;
|
private static int _tokenCount = 0;
|
||||||
private static int[] componentCounts = new int[0];
|
private static int[] _componentCounts = new int[0];
|
||||||
private static int[] queryCounts = new int[0];
|
private static int[] _subjectsCounts = new int[0];
|
||||||
|
|
||||||
private static Dictionary<Type, int> _worldIds = new Dictionary<Type, int>();
|
private static Dictionary<Type, int> _worldIds = new Dictionary<Type, int>();
|
||||||
|
|
||||||
private static class WorldIndex<TWorldArchetype>
|
private static class WorldIndex<TWorldArchetype>
|
||||||
{
|
{
|
||||||
public static int id = GetWorldId(typeof(TWorldArchetype));
|
public static int id = GetWorldId(typeof(TWorldArchetype));
|
||||||
}
|
}
|
||||||
private static int GetToken()
|
private static int GetToken()
|
||||||
{
|
{
|
||||||
tokenCount++;
|
_tokenCount++;
|
||||||
Array.Resize(ref componentCounts, tokenCount);
|
Array.Resize(ref _componentCounts, _tokenCount);
|
||||||
Array.Resize(ref queryCounts, tokenCount);
|
Array.Resize(ref _subjectsCounts, _tokenCount);
|
||||||
foreach (var item in resizer)
|
foreach (var item in _resizer)
|
||||||
item.Resize(tokenCount);
|
item.Resize(_tokenCount);
|
||||||
return tokenCount - 1;
|
return _tokenCount - 1;
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int GetWorldId(Type archetype)
|
public static int GetWorldId(Type archetype)
|
||||||
@ -557,17 +471,17 @@ namespace DCFApixels.DragonECS
|
|||||||
public static int[] ids;
|
public static int[] ids;
|
||||||
static Component()
|
static Component()
|
||||||
{
|
{
|
||||||
ids = new int[tokenCount];
|
ids = new int[_tokenCount];
|
||||||
for (int i = 0; i < ids.Length; i++)
|
for (int i = 0; i < ids.Length; i++)
|
||||||
ids[i] = -1;
|
ids[i] = -1;
|
||||||
resizer.Add(new Resizer<T>());
|
_resizer.Add(new Resizer<T>());
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int Get(int token)
|
public static int Get(int token)
|
||||||
{
|
{
|
||||||
ref int id = ref ids[token];
|
ref int id = ref ids[token];
|
||||||
if (id < 0)
|
if (id < 0)
|
||||||
id = componentCounts[token]++;
|
id = _componentCounts[token]++;
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -576,17 +490,17 @@ namespace DCFApixels.DragonECS
|
|||||||
public static int[] ids;
|
public static int[] ids;
|
||||||
static Subject()
|
static Subject()
|
||||||
{
|
{
|
||||||
ids = new int[tokenCount];
|
ids = new int[_tokenCount];
|
||||||
for (int i = 0; i < ids.Length; i++)
|
for (int i = 0; i < ids.Length; i++)
|
||||||
ids[i] = -1;
|
ids[i] = -1;
|
||||||
resizer.Add(new Resizer<T>());
|
_resizer.Add(new Resizer<T>());
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int Get(int token)
|
public static int Get(int token)
|
||||||
{
|
{
|
||||||
ref int id = ref ids[token];
|
ref int id = ref ids[token];
|
||||||
if (id < 0)
|
if (id < 0)
|
||||||
id = queryCounts[token]++;
|
id = _subjectsCounts[token]++;
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -595,24 +509,24 @@ namespace DCFApixels.DragonECS
|
|||||||
public static int[] ids;
|
public static int[] ids;
|
||||||
static Executor()
|
static Executor()
|
||||||
{
|
{
|
||||||
ids = new int[tokenCount];
|
ids = new int[_tokenCount];
|
||||||
for (int i = 0; i < ids.Length; i++)
|
for (int i = 0; i < ids.Length; i++)
|
||||||
ids[i] = -1;
|
ids[i] = -1;
|
||||||
resizer.Add(new Resizer<T>());
|
_resizer.Add(new Resizer<T>());
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int Get(int token)
|
public static int Get(int token)
|
||||||
{
|
{
|
||||||
ref int id = ref ids[token];
|
ref int id = ref ids[token];
|
||||||
if (id < 0)
|
if (id < 0)
|
||||||
id = queryCounts[token]++;
|
id = _subjectsCounts[token]++;
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Callbacks Interface //TODO
|
#region Callbacks Interface
|
||||||
public interface IEcsWorldEventListener
|
public interface IEcsWorldEventListener
|
||||||
{
|
{
|
||||||
void OnWorldResize(int newSize);
|
void OnWorldResize(int newSize);
|
||||||
@ -621,10 +535,7 @@ namespace DCFApixels.DragonECS
|
|||||||
void OnNewEntity(int entityID);
|
void OnNewEntity(int entityID);
|
||||||
void OnDelEntity(int entityID);
|
void OnDelEntity(int entityID);
|
||||||
}
|
}
|
||||||
#endregion
|
internal static class WorldEventListExtensions
|
||||||
|
|
||||||
#region Extensions
|
|
||||||
public static class WorldEventListExtensions
|
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void InvokeOnWorldResize(this List<IEcsWorldEventListener> self, int newSize)
|
public static void InvokeOnWorldResize(this List<IEcsWorldEventListener> self, int newSize)
|
||||||
|
|||||||
@ -1,189 +0,0 @@
|
|||||||
using Unity.Profiling;
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
|
||||||
{
|
|
||||||
public sealed class EcsJoinAttachExecutor<TSubject, TAttachComponent> : EcsQueryExecutor
|
|
||||||
where TSubject : EcsSubject
|
|
||||||
where TAttachComponent : struct, IEcsAttachComponent
|
|
||||||
{
|
|
||||||
private readonly TSubject _subject;
|
|
||||||
internal readonly EcsGroup _filteredGroup;
|
|
||||||
private EcsWorld _targetWorld;
|
|
||||||
|
|
||||||
private EcsAttachPool<TAttachComponent> _targetPool;
|
|
||||||
|
|
||||||
private int _targetWorldCapacity = -1;
|
|
||||||
private int _targetPoolCapacity = -1;
|
|
||||||
|
|
||||||
private int[] _mapping;
|
|
||||||
private int[] _counts;
|
|
||||||
private EntityLinkedList _linkedBasket;
|
|
||||||
|
|
||||||
private bool _isInitTargetWorld = false;
|
|
||||||
|
|
||||||
private ProfilerMarker _executeJoin = new ProfilerMarker("JoinAttachQuery.Join");
|
|
||||||
|
|
||||||
private long _executeVersion;
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
public TSubject Subject => _subject;
|
|
||||||
internal long ExecuteVersion => _executeVersion;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
public EcsJoinAttachExecutor(TSubject subject)
|
|
||||||
{
|
|
||||||
_subject = subject;
|
|
||||||
_filteredGroup = EcsGroup.New(subject.World);
|
|
||||||
_targetPool = subject.World.GetPool<TAttachComponent>();
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
public EcsJoinAttachResult<TSubject, TAttachComponent> Execute() => ExecuteFor(_targetPool.Entities);
|
|
||||||
public EcsJoinAttachResult<TSubject, TAttachComponent> ExecuteFor(EcsReadonlyGroup sourceGroup)
|
|
||||||
{
|
|
||||||
_executeJoin.Begin();
|
|
||||||
var world = _subject.World;
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (sourceGroup.IsNull) throw new System.ArgumentNullException();//TODO составить текст исключения.
|
|
||||||
#endif
|
|
||||||
if (!_isInitTargetWorld)
|
|
||||||
InitTargetWorlds(sourceGroup.World);
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
else
|
|
||||||
if (_targetWorld != sourceGroup.World) throw new System.ArgumentException();//TODO составить текст исключения. это проверка на то что пользователь использует правильный мир
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//Подготовка массивов
|
|
||||||
if (_targetWorldCapacity < _targetWorld.Capacity)
|
|
||||||
{
|
|
||||||
_targetWorldCapacity = _targetWorld.Capacity;
|
|
||||||
_mapping = new int[_targetWorldCapacity];
|
|
||||||
_counts = new int[_targetWorldCapacity];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ArrayUtility.Fill(_counts, 0);
|
|
||||||
ArrayUtility.Fill(_mapping, 0);
|
|
||||||
}
|
|
||||||
if (_targetPoolCapacity < _targetPool.Capacity)
|
|
||||||
{
|
|
||||||
_targetPoolCapacity = _targetPool.Capacity;
|
|
||||||
_linkedBasket.Resize(_targetPoolCapacity);
|
|
||||||
}
|
|
||||||
_linkedBasket.Clear();
|
|
||||||
//Конец подготовки массивов
|
|
||||||
|
|
||||||
var iterator = new EcsSubjectIterator<TSubject>(_subject, sourceGroup);
|
|
||||||
foreach (var attachID in iterator)
|
|
||||||
{
|
|
||||||
entlong attachTarget = _targetPool.Read(attachID).Target;
|
|
||||||
if (!attachTarget.IsAlive)
|
|
||||||
{
|
|
||||||
//_targetPool.Del(attachID);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int attachTargetID = attachTarget.id;
|
|
||||||
//if (!CheckMaskInternal(targetWorldWhereQuery.query.mask, attachTargetID)) continue; //TODO проверить что все работает //исчключить все аттачи, цели которых не входят в targetWorldWhereQuery
|
|
||||||
|
|
||||||
ref int nodeIndex = ref _mapping[attachTargetID];
|
|
||||||
if (nodeIndex <= 0)
|
|
||||||
nodeIndex = _linkedBasket.Add(attachID);
|
|
||||||
else
|
|
||||||
_linkedBasket.Insert(nodeIndex, attachID);
|
|
||||||
_counts[attachTargetID]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
_executeVersion++;
|
|
||||||
_executeJoin.End();
|
|
||||||
|
|
||||||
return new EcsJoinAttachResult<TSubject, TAttachComponent>(_subject, this , _executeVersion);
|
|
||||||
}
|
|
||||||
private void InitTargetWorlds(EcsWorld targetWorld)
|
|
||||||
{
|
|
||||||
_targetWorld = targetWorld;
|
|
||||||
|
|
||||||
_targetWorldCapacity = _targetWorld.Capacity;
|
|
||||||
_mapping = new int[_targetWorldCapacity];
|
|
||||||
_counts = new int[_targetWorldCapacity];
|
|
||||||
|
|
||||||
_targetPoolCapacity = _targetPool.Capacity;
|
|
||||||
_linkedBasket = new EntityLinkedList(_targetPoolCapacity);
|
|
||||||
_isInitTargetWorld = true;
|
|
||||||
}
|
|
||||||
internal sealed override void Destroy()
|
|
||||||
{
|
|
||||||
_filteredGroup.Release();
|
|
||||||
_targetWorld = null;
|
|
||||||
_mapping = null;
|
|
||||||
_counts = null;
|
|
||||||
_linkedBasket = null;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Internal result methods
|
|
||||||
internal bool Has(int attachedEnttiyID) => _filteredGroup.Has(attachedEnttiyID);
|
|
||||||
internal EntityLinkedList.EnumerableSpan GetNodes(int entityID) => _linkedBasket.Span(_mapping[entityID], _counts[entityID]);
|
|
||||||
internal int GetNode(int entityID) => _counts[entityID] > 0 ? _linkedBasket.Get(_mapping[entityID]) : 0;
|
|
||||||
internal int GetNodesCount(int entityID) => _counts[entityID];
|
|
||||||
internal bool HasNode(int entityID, int attachedEntityID) => _filteredGroup.Has(attachedEntityID) && _targetPool.Read(attachedEntityID).Target.id == entityID;
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
#region JoinAttachExecuter Results
|
|
||||||
public readonly ref struct EcsJoinAttachResult<TSubject, TAttachComponent>
|
|
||||||
where TSubject : EcsSubject
|
|
||||||
where TAttachComponent : struct, IEcsAttachComponent
|
|
||||||
{
|
|
||||||
public readonly TSubject s;
|
|
||||||
private readonly EcsJoinAttachExecutor<TSubject, TAttachComponent> _executer;
|
|
||||||
private readonly long _verison;
|
|
||||||
|
|
||||||
public bool IsRelevant => _verison == _executer.ExecuteVersion;
|
|
||||||
|
|
||||||
public EcsJoinAttachResult(TSubject s, EcsJoinAttachExecutor<TSubject, TAttachComponent> executer, long version)
|
|
||||||
{
|
|
||||||
this.s = s;
|
|
||||||
_executer = executer;
|
|
||||||
_verison = version;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Has(int attachedEnttiyID)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (!IsRelevant) throw new System.InvalidOperationException();//TODO составить текст исключения.
|
|
||||||
#endif
|
|
||||||
return _executer.Has(attachedEnttiyID);
|
|
||||||
}
|
|
||||||
public EntityLinkedList.EnumerableSpan GetNodes(int entityID)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (!IsRelevant) throw new System.InvalidOperationException();//TODO составить текст исключения.
|
|
||||||
#endif
|
|
||||||
return _executer.GetNodes(entityID);
|
|
||||||
}
|
|
||||||
public int GetNode(int entityID)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (!IsRelevant) throw new System.InvalidOperationException();//TODO составить текст исключения.
|
|
||||||
#endif
|
|
||||||
return _executer.GetNode(entityID);
|
|
||||||
}
|
|
||||||
public int GetNodesCount(int entityID)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (!IsRelevant) throw new System.InvalidOperationException();//TODO составить текст исключения.
|
|
||||||
#endif
|
|
||||||
return _executer.GetNodesCount(entityID);
|
|
||||||
}
|
|
||||||
public bool HasNode(int entityID, int attachedEntityID)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (!IsRelevant) throw new System.InvalidOperationException();//TODO составить текст исключения.
|
|
||||||
#endif
|
|
||||||
return _executer.HasNode(entityID, attachedEntityID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
@ -1,198 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Unity.Profiling;
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
|
||||||
{
|
|
||||||
public sealed class EcsJoinHierarchyExecutor<TSubject, TAttachComponent> : EcsQueryExecutor
|
|
||||||
where TSubject : EcsSubject
|
|
||||||
where TAttachComponent : struct, IEcsAttachComponent
|
|
||||||
{
|
|
||||||
private readonly TSubject _subject;
|
|
||||||
internal readonly EcsGroup _filteredGroup;
|
|
||||||
private EcsWorld _targetWorld;
|
|
||||||
|
|
||||||
private EcsAttachPool<TAttachComponent> _targetPool;
|
|
||||||
|
|
||||||
private int _targetWorldCapacity = -1;
|
|
||||||
private int _targetPoolCapacity = -1;
|
|
||||||
|
|
||||||
private int[] _mapping;
|
|
||||||
private int[] _counts;
|
|
||||||
private EntityLinkedList _linkedBasket;
|
|
||||||
|
|
||||||
private bool _isInitTargetWorld = false;
|
|
||||||
|
|
||||||
private ProfilerMarker _executeWhere = new ProfilerMarker("JoinAttachQuery.Where");
|
|
||||||
private ProfilerMarker _executeJoin = new ProfilerMarker("JoinAttachQuery.Join");
|
|
||||||
|
|
||||||
private long _executeVersion;
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
public TSubject Subject => _subject;
|
|
||||||
internal long ExecuteVersion => _executeVersion;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
public EcsJoinHierarchyExecutor(TSubject subject)
|
|
||||||
{
|
|
||||||
_subject = subject;
|
|
||||||
_filteredGroup = EcsGroup.New(subject.World);
|
|
||||||
_targetPool = subject.World.GetPool<TAttachComponent>();
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
public EcsJoinHierarchyResult<TSubject, TAttachComponent> Execute() => ExecuteFor(_targetPool.Entities);
|
|
||||||
public EcsJoinHierarchyResult<TSubject, TAttachComponent> ExecuteFor(EcsReadonlyGroup sourceGroup)
|
|
||||||
{
|
|
||||||
var world = _subject.World;
|
|
||||||
_executeJoin.Begin();
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (sourceGroup.IsNull) throw new ArgumentNullException();//TODO составить текст исключения.
|
|
||||||
#endif
|
|
||||||
if (!_isInitTargetWorld)
|
|
||||||
InitTargetWorlds(sourceGroup.World);
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
else
|
|
||||||
if (_targetWorld != sourceGroup.World) throw new ArgumentException();//TODO составить текст исключения. это проверка на то что пользователь использует правильный мир
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//Подготовка массивов
|
|
||||||
if (_targetWorldCapacity < _targetWorld.Capacity)
|
|
||||||
{
|
|
||||||
_targetWorldCapacity = _targetWorld.Capacity;
|
|
||||||
_mapping = new int[_targetWorldCapacity];
|
|
||||||
_counts = new int[_targetWorldCapacity];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ArrayUtility.Fill(_counts, 0);
|
|
||||||
ArrayUtility.Fill(_mapping, 0);
|
|
||||||
}
|
|
||||||
if (_targetPoolCapacity < _targetPool.Capacity)
|
|
||||||
{
|
|
||||||
_targetPoolCapacity = _targetPool.Capacity;
|
|
||||||
_linkedBasket.Resize(_targetPoolCapacity);
|
|
||||||
}
|
|
||||||
_linkedBasket.Clear();
|
|
||||||
//Конец подготовки массивов
|
|
||||||
|
|
||||||
var iterator = new EcsSubjectIterator<TSubject>(_subject, sourceGroup);
|
|
||||||
foreach (var attachID in iterator)
|
|
||||||
{
|
|
||||||
entlong attachTarget = _targetPool.Read(attachID).Target;
|
|
||||||
if (!attachTarget.IsAlive)
|
|
||||||
{
|
|
||||||
//_targetPool.Del(attachID);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int attachTargetID = attachTarget.id;
|
|
||||||
//if (!CheckMaskInternal(targetWorldWhereQuery.query.mask, attachTargetID)) continue; //TODO проверить что все работает //исчключить все аттачи, цели которых не входят в targetWorldWhereQuery
|
|
||||||
|
|
||||||
ref int nodeIndex = ref _mapping[attachTargetID];
|
|
||||||
if (nodeIndex <= 0)
|
|
||||||
nodeIndex = _linkedBasket.Add(attachID);
|
|
||||||
else
|
|
||||||
_linkedBasket.Insert(nodeIndex, attachID);
|
|
||||||
_counts[attachTargetID]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
_executeVersion++;
|
|
||||||
_executeJoin.End();
|
|
||||||
|
|
||||||
return new EcsJoinHierarchyResult<TSubject, TAttachComponent>(_subject, this , _executeVersion);
|
|
||||||
}
|
|
||||||
private void InitTargetWorlds(EcsWorld targetWorld)
|
|
||||||
{
|
|
||||||
_targetWorld = targetWorld;
|
|
||||||
|
|
||||||
_targetWorldCapacity = _targetWorld.Capacity;
|
|
||||||
_mapping = new int[_targetWorldCapacity];
|
|
||||||
_counts = new int[_targetWorldCapacity];
|
|
||||||
|
|
||||||
_targetPoolCapacity = _targetPool.Capacity;
|
|
||||||
_linkedBasket = new EntityLinkedList(_targetPoolCapacity);
|
|
||||||
_isInitTargetWorld = true;
|
|
||||||
}
|
|
||||||
internal sealed override void Destroy()
|
|
||||||
{
|
|
||||||
_filteredGroup.Release();
|
|
||||||
_targetWorld = null;
|
|
||||||
_mapping = null;
|
|
||||||
_counts = null;
|
|
||||||
_linkedBasket = null;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Internal result methods
|
|
||||||
internal bool Has(int attachedEnttiyID) => _filteredGroup.Has(attachedEnttiyID);
|
|
||||||
|
|
||||||
internal EntityLinkedList.EnumerableSpan GetNodes(int entityID) => _linkedBasket.Span(_mapping[entityID], _counts[entityID]);
|
|
||||||
internal int GetNode(int entityID) => _counts[entityID] > 0 ? _linkedBasket.Get(_mapping[entityID]) : 0;
|
|
||||||
internal int GetNodesCount(int entityID) => _counts[entityID];
|
|
||||||
internal bool HasNode(int entityID, int attachedEntityID) => _filteredGroup.Has(attachedEntityID) && _targetPool.Read(attachedEntityID).Target.id == entityID;
|
|
||||||
|
|
||||||
|
|
||||||
internal EntityLinkedList.EnumerableSpan GetSubNodes(int entityID) => throw new NotImplementedException();
|
|
||||||
internal int GetSubNode(int entityID) => throw new NotImplementedException();
|
|
||||||
internal bool GetSubNodesCount(int entityID, int attachedEntityID) => throw new NotImplementedException();
|
|
||||||
internal bool HasSubNode(int entityID, int attachedEntityID) => throw new NotImplementedException();
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
#region JoinAttachExecuter Results
|
|
||||||
public readonly ref struct EcsJoinHierarchyResult<TSubject, TAttachComponent>
|
|
||||||
where TSubject : EcsSubject
|
|
||||||
where TAttachComponent : struct, IEcsAttachComponent
|
|
||||||
{
|
|
||||||
public readonly TSubject s;
|
|
||||||
private readonly EcsJoinHierarchyExecutor<TSubject, TAttachComponent> _executer;
|
|
||||||
private readonly long _verison;
|
|
||||||
|
|
||||||
public bool IsRelevant => _verison == _executer.ExecuteVersion;
|
|
||||||
|
|
||||||
public EcsJoinHierarchyResult(TSubject s, EcsJoinHierarchyExecutor<TSubject, TAttachComponent> executer, long version)
|
|
||||||
{
|
|
||||||
this.s = s;
|
|
||||||
_executer = executer;
|
|
||||||
_verison = version;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Has(int attachedEnttiyID)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (!IsRelevant) throw new InvalidOperationException();//TODO составить текст исключения.
|
|
||||||
#endif
|
|
||||||
return _executer.Has(attachedEnttiyID);
|
|
||||||
}
|
|
||||||
public EntityLinkedList.EnumerableSpan GetNodes(int entityID)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (!IsRelevant) throw new InvalidOperationException();//TODO составить текст исключения.
|
|
||||||
#endif
|
|
||||||
return _executer.GetNodes(entityID);
|
|
||||||
}
|
|
||||||
public int GetNode(int entityID)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (!IsRelevant) throw new InvalidOperationException();//TODO составить текст исключения.
|
|
||||||
#endif
|
|
||||||
return _executer.GetNode(entityID);
|
|
||||||
}
|
|
||||||
public int GetNodesCount(int entityID)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (!IsRelevant) throw new InvalidOperationException();//TODO составить текст исключения.
|
|
||||||
#endif
|
|
||||||
return _executer.GetNodesCount(entityID);
|
|
||||||
}
|
|
||||||
public bool HasNode(int entityID, int attachedEntityID)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (!IsRelevant) throw new InvalidOperationException();//TODO составить текст исключения.
|
|
||||||
#endif
|
|
||||||
return _executer.HasNode(entityID, attachedEntityID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
@ -2,6 +2,7 @@
|
|||||||
{
|
{
|
||||||
public abstract class EcsQueryExecutor
|
public abstract class EcsQueryExecutor
|
||||||
{
|
{
|
||||||
internal abstract void Destroy();
|
internal void Destroy() => OnDestroy();
|
||||||
|
protected abstract void OnDestroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,14 +30,14 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
using (_executeWhere.Auto())
|
using (_executeWhere.Auto())
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (sourceGroup.IsNull) throw new System.ArgumentNullException();//TODO составить текст исключения.
|
if (sourceGroup.IsNull) throw new System.ArgumentNullException();//TODO составить текст исключения.
|
||||||
#endif
|
#endif
|
||||||
_subject.GetIteratorFor(sourceGroup).CopyTo(_filteredGroup);
|
_subject.GetIteratorFor(sourceGroup).CopyTo(_filteredGroup);
|
||||||
return new EcsWhereResult<TSubject>(this, _filteredGroup.Readonly);
|
return new EcsWhereResult<TSubject>(this, _filteredGroup.Readonly);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal sealed override void Destroy()
|
protected sealed override void OnDestroy()
|
||||||
{
|
{
|
||||||
_filteredGroup.Release();
|
_filteredGroup.Release();
|
||||||
}
|
}
|
||||||
@ -62,7 +62,7 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
public EcsGroup.Enumerator GetEnumerator()
|
public EcsGroup.Enumerator GetEnumerator()
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (!IsRelevant) throw new System.InvalidOperationException();//TODO составить текст исключения.
|
if (!IsRelevant) throw new System.InvalidOperationException();//TODO составить текст исключения.
|
||||||
#endif
|
#endif
|
||||||
return group.GetEnumerator();
|
return group.GetEnumerator();
|
||||||
|
|||||||
@ -1,224 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
|
||||||
{
|
|
||||||
using static EcsPoolThrowHalper;
|
|
||||||
//íå âëèÿåò íà ñ÷åò÷èê êîìïîíåíòîâ íà ñóùíîñòè
|
|
||||||
/// <summary>Pool for IEcsAttachComponent components</summary>
|
|
||||||
public sealed class EcsAttachPool<T> : IEcsPoolImplementation<T>, IEnumerable<T> //IntelliSense hack
|
|
||||||
where T : struct, IEcsAttachComponent
|
|
||||||
{
|
|
||||||
private EcsWorld _source;
|
|
||||||
private int _id;
|
|
||||||
|
|
||||||
private bool[] _entityFlags;// index = entityID / value = entityFlag;/ value = 0 = no entityID
|
|
||||||
private T[] _items; //sparse
|
|
||||||
private int _count;
|
|
||||||
|
|
||||||
private List<IEcsPoolEventListener> _listeners;
|
|
||||||
|
|
||||||
private EcsGroup _entities;
|
|
||||||
public EcsReadonlyGroup Entities
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
_entities.RemoveUnusedEntityIDs();
|
|
||||||
return _entities.Readonly;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
private short _sanitizeTargetWorld = -1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#region Properites
|
|
||||||
public int Count => _count;
|
|
||||||
public int Capacity => _items.Length;
|
|
||||||
public int ComponentID => _id;
|
|
||||||
public Type ComponentType => typeof(T);
|
|
||||||
public EcsWorld World => _source;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Init
|
|
||||||
void IEcsPoolImplementation.OnInit(EcsWorld world, int componentID)
|
|
||||||
{
|
|
||||||
_source = world;
|
|
||||||
_id = componentID;
|
|
||||||
|
|
||||||
_listeners = new List<IEcsPoolEventListener>();
|
|
||||||
|
|
||||||
_entities = EcsGroup.New(world);
|
|
||||||
|
|
||||||
_entityFlags = new bool[world.Capacity];
|
|
||||||
_items = new T[world.Capacity];
|
|
||||||
_count = 0;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
public void Add(int entityID, entlong target)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (_sanitizeTargetWorld > 0 && target.world != _sanitizeTargetWorld) ThrowWorldDifferent<T>(entityID);
|
|
||||||
_sanitizeTargetWorld = target.world;
|
|
||||||
if (Has(entityID)) ThrowAlreadyHasComponent<T>(entityID);
|
|
||||||
#endif
|
|
||||||
ref bool entityFlag = ref _entityFlags[entityID];
|
|
||||||
if (entityFlag == false)
|
|
||||||
{
|
|
||||||
entityFlag = true;
|
|
||||||
_count++;
|
|
||||||
_entities.Add(entityID);
|
|
||||||
foreach (var item in _listeners) item.OnAdd(entityID);
|
|
||||||
}
|
|
||||||
foreach (var item in _listeners) item.OnWrite(entityID);
|
|
||||||
_items[entityID].Target = target;
|
|
||||||
}
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void Set(int entityID, entlong target)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
|
||||||
if (_sanitizeTargetWorld >= 0 && target.world != _sanitizeTargetWorld) ThrowWorldDifferent<T>(entityID);
|
|
||||||
_sanitizeTargetWorld = target.world;
|
|
||||||
#endif
|
|
||||||
_listeners.InvokeOnWrite(entityID);
|
|
||||||
_items[entityID].Target = target;
|
|
||||||
}
|
|
||||||
public void AddOrSet(int entityID, entlong target)
|
|
||||||
{
|
|
||||||
if (Has(entityID))
|
|
||||||
Set(entityID, target);
|
|
||||||
else
|
|
||||||
Add(entityID, target);
|
|
||||||
}
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public ref readonly T Read(int entityID)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
|
||||||
#endif
|
|
||||||
return ref _items[entityID];
|
|
||||||
}
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool Has(int entityID)
|
|
||||||
{
|
|
||||||
return _entityFlags[entityID];
|
|
||||||
}
|
|
||||||
public void Del(int entityID)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
|
||||||
#endif
|
|
||||||
_entities.Remove(entityID);
|
|
||||||
_entityFlags[entityID] = false;
|
|
||||||
_count--;
|
|
||||||
_listeners.InvokeOnDel(entityID);
|
|
||||||
}
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void TryDel(int entityID)
|
|
||||||
{
|
|
||||||
if (Has(entityID)) Del(entityID);
|
|
||||||
}
|
|
||||||
public void Copy(int fromEntityID, int toEntityID)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (!Has(fromEntityID)) ThrowNotHaveComponent<T>(fromEntityID);
|
|
||||||
#endif
|
|
||||||
if (Has(toEntityID))
|
|
||||||
Set(toEntityID, Read(fromEntityID).Target);
|
|
||||||
else
|
|
||||||
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
|
|
||||||
|
|
||||||
#region WorldCallbacks
|
|
||||||
void IEcsPoolImplementation.OnWorldResize(int newSize)
|
|
||||||
{
|
|
||||||
Array.Resize(ref _entityFlags, newSize);
|
|
||||||
Array.Resize(ref _items, newSize);
|
|
||||||
}
|
|
||||||
void IEcsPoolImplementation.OnWorldDestroy() { }
|
|
||||||
void IEcsPoolImplementation.OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer)
|
|
||||||
{
|
|
||||||
foreach (var item in buffer)
|
|
||||||
TryDel(item);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Other
|
|
||||||
ref T IEcsPool<T>.Add(int entityID)
|
|
||||||
{
|
|
||||||
if (!Has(entityID))
|
|
||||||
Add(entityID, entlong.NULL);
|
|
||||||
return ref _items[entityID];
|
|
||||||
}
|
|
||||||
ref T IEcsPool<T>.Write(int entityID)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
|
||||||
#endif
|
|
||||||
return ref _items[entityID];
|
|
||||||
}
|
|
||||||
void IEcsPool.AddRaw(int entityID, object dataRaw) => ((IEcsPool<T>)this).Add(entityID) = (T)dataRaw;
|
|
||||||
object IEcsPool.GetRaw(int entityID) => Read(entityID);
|
|
||||||
void IEcsPool.SetRaw(int entityID, object dataRaw) => ((IEcsPool<T>)this).Write(entityID) = (T)dataRaw;
|
|
||||||
#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
|
|
||||||
IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw new NotImplementedException();
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException();
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IEcsAttachComponent
|
|
||||||
{
|
|
||||||
public entlong Target { get; set; }
|
|
||||||
}
|
|
||||||
public static class EcsAttachComponentPoolExt
|
|
||||||
{
|
|
||||||
public static EcsAttachPool<TAttachComponent> GetPool<TAttachComponent>(this EcsWorld self) where TAttachComponent : struct, IEcsAttachComponent
|
|
||||||
{
|
|
||||||
return self.GetPool<TAttachComponent, EcsAttachPool<TAttachComponent>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static EcsAttachPool<TAttachComponent> Include<TAttachComponent>(this EcsSubjectBuilderBase self) where TAttachComponent : struct, IEcsAttachComponent
|
|
||||||
{
|
|
||||||
return self.Include<TAttachComponent, EcsAttachPool<TAttachComponent>>();
|
|
||||||
}
|
|
||||||
public static EcsAttachPool<TAttachComponent> Exclude<TAttachComponent>(this EcsSubjectBuilderBase self) where TAttachComponent : struct, IEcsAttachComponent
|
|
||||||
{
|
|
||||||
return self.Exclude<TAttachComponent, EcsAttachPool<TAttachComponent>>();
|
|
||||||
}
|
|
||||||
public static EcsAttachPool<TAttachComponent> Optional<TAttachComponent>(this EcsSubjectBuilderBase self) where TAttachComponent : struct, IEcsAttachComponent
|
|
||||||
{
|
|
||||||
return self.Optional<TAttachComponent, EcsAttachPool<TAttachComponent>>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,140 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
|
||||||
{
|
|
||||||
//íå âëèÿåò íà ñ÷åò÷èê êîìïîíåíòîâ íà ñóùíîñòè
|
|
||||||
/// <summary>Pool for IEcsNotNullComponent components</summary>
|
|
||||||
public sealed class EcsNotNullPool<T> : IEcsPoolImplementation<T>, IEnumerable<T> //IntelliSense hack
|
|
||||||
where T : struct, IEcsNotNullComponent
|
|
||||||
{
|
|
||||||
private EcsWorld _source;
|
|
||||||
private int _id;
|
|
||||||
|
|
||||||
private T[] _items; //sparse
|
|
||||||
private int _count;
|
|
||||||
|
|
||||||
private IEcsComponentReset<T> _componentResetHandler;
|
|
||||||
private IEcsComponentCopy<T> _componentCopyHandler;
|
|
||||||
|
|
||||||
private List<IEcsPoolEventListener> _listeners;
|
|
||||||
|
|
||||||
#region Properites
|
|
||||||
public int Count => _count;
|
|
||||||
public int Capacity => _items.Length;
|
|
||||||
public int ComponentID => _id;
|
|
||||||
public Type ComponentType => typeof(T);
|
|
||||||
public EcsWorld World => _source;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Init
|
|
||||||
void IEcsPoolImplementation.OnInit(EcsWorld world, int componentID)
|
|
||||||
{
|
|
||||||
_source = world;
|
|
||||||
_id = componentID;
|
|
||||||
|
|
||||||
_items = new T[world.Capacity];
|
|
||||||
_count = 0;
|
|
||||||
|
|
||||||
_listeners = new List<IEcsPoolEventListener>();
|
|
||||||
|
|
||||||
_componentResetHandler = EcsComponentResetHandler<T>.instance;
|
|
||||||
_componentCopyHandler = EcsComponentCopyHandler<T>.instance;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public ref T Write(int entityID)
|
|
||||||
{
|
|
||||||
_listeners.InvokeOnWrite(entityID);
|
|
||||||
return ref _items[entityID];
|
|
||||||
}
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public ref readonly T Read(int entityID)
|
|
||||||
{
|
|
||||||
return ref _items[entityID];
|
|
||||||
}
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool Has(int entityID)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
public void Copy(int fromEntityID, int 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
|
|
||||||
|
|
||||||
#region Callbacks
|
|
||||||
void IEcsPoolImplementation.OnWorldResize(int newSize)
|
|
||||||
{
|
|
||||||
Array.Resize(ref _items, newSize);
|
|
||||||
}
|
|
||||||
void IEcsPoolImplementation.OnWorldDestroy() { }
|
|
||||||
void IEcsPoolImplementation.OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer)
|
|
||||||
{
|
|
||||||
foreach (var entityID in buffer)
|
|
||||||
_componentResetHandler.Reset(ref _items[entityID]);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Other
|
|
||||||
ref T IEcsPool<T>.Add(int entityID) => ref Write(entityID);
|
|
||||||
ref readonly T IEcsPool<T>.Read(int entityID) => ref Read(entityID);
|
|
||||||
ref T IEcsPool<T>.Write(int entityID) => ref Write(entityID);
|
|
||||||
void IEcsPool.Del(int entityID) { }
|
|
||||||
void IEcsPool.AddRaw(int entityID, object dataRaw) => Write(entityID) = (T)dataRaw;
|
|
||||||
object IEcsPool.GetRaw(int entityID) => Write(entityID);
|
|
||||||
void IEcsPool.SetRaw(int entityID, object dataRaw) => Write(entityID) = (T)dataRaw;
|
|
||||||
#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
|
|
||||||
IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw new NotImplementedException();
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException();
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Not null component. Is present on all entities, without explicit addition and cannot be deleted
|
|
||||||
/// </summary>
|
|
||||||
public interface IEcsNotNullComponent { }
|
|
||||||
public static class EcsNotNullPoolExt
|
|
||||||
{
|
|
||||||
public static EcsNotNullPool<TNotNullComponent> GetPool<TNotNullComponent>(this EcsWorld self) where TNotNullComponent : struct, IEcsNotNullComponent
|
|
||||||
{
|
|
||||||
return self.GetPool<TNotNullComponent, EcsNotNullPool<TNotNullComponent>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static EcsNotNullPool<TNotNullComponent> Include<TNotNullComponent>(this EcsSubjectBuilderBase self) where TNotNullComponent : struct, IEcsNotNullComponent
|
|
||||||
{
|
|
||||||
return self.Include<TNotNullComponent, EcsNotNullPool<TNotNullComponent>>();
|
|
||||||
}
|
|
||||||
public static EcsNotNullPool<TNotNullComponent> Exclude<TNotNullComponent>(this EcsSubjectBuilderBase self) where TNotNullComponent : struct, IEcsNotNullComponent
|
|
||||||
{
|
|
||||||
return self.Exclude<TNotNullComponent, EcsNotNullPool<TNotNullComponent>>();
|
|
||||||
}
|
|
||||||
public static EcsNotNullPool<TNotNullComponent> Optional<TNotNullComponent>(this EcsSubjectBuilderBase self) where TNotNullComponent : struct, IEcsNotNullComponent
|
|
||||||
{
|
|
||||||
return self.Optional<TNotNullComponent, EcsNotNullPool<TNotNullComponent>>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -7,7 +7,7 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
using static EcsPoolThrowHalper;
|
using static EcsPoolThrowHalper;
|
||||||
/// <summary>Pool for IEcsComponent components</summary>
|
/// <summary>Pool for IEcsComponent components</summary>
|
||||||
public sealed class EcsPool<T> : IEcsPoolImplementation<T>, IEnumerable<T> //IntelliSense hack
|
public sealed class EcsPool<T> : IEcsPoolImplementation<T>, IEnumerable<T> //IEnumerable<T> - IntelliSense hack
|
||||||
where T : struct, IEcsComponent
|
where T : struct, IEcsComponent
|
||||||
{
|
{
|
||||||
private EcsWorld _source;
|
private EcsWorld _source;
|
||||||
@ -59,7 +59,7 @@ namespace DCFApixels.DragonECS
|
|||||||
// using (_addMark.Auto())
|
// using (_addMark.Auto())
|
||||||
// {
|
// {
|
||||||
ref int itemIndex = ref _mapping[entityID];
|
ref int itemIndex = ref _mapping[entityID];
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (itemIndex > 0) ThrowAlreadyHasComponent<T>(entityID);
|
if (itemIndex > 0) ThrowAlreadyHasComponent<T>(entityID);
|
||||||
#endif
|
#endif
|
||||||
if (_recycledItemsCount > 0)
|
if (_recycledItemsCount > 0)
|
||||||
@ -82,7 +82,7 @@ namespace DCFApixels.DragonECS
|
|||||||
public ref T Write(int entityID)
|
public ref T Write(int entityID)
|
||||||
{
|
{
|
||||||
// using (_writeMark.Auto())
|
// using (_writeMark.Auto())
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
||||||
#endif
|
#endif
|
||||||
_listeners.InvokeOnWrite(entityID);
|
_listeners.InvokeOnWrite(entityID);
|
||||||
@ -92,7 +92,7 @@ namespace DCFApixels.DragonECS
|
|||||||
public ref readonly T Read(int entityID)
|
public ref readonly T Read(int entityID)
|
||||||
{
|
{
|
||||||
// using (_readMark.Auto())
|
// using (_readMark.Auto())
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
||||||
#endif
|
#endif
|
||||||
return ref _items[_mapping[entityID]];
|
return ref _items[_mapping[entityID]];
|
||||||
@ -126,7 +126,7 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
public void Del(int entityID)
|
public void Del(int entityID)
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
||||||
#endif
|
#endif
|
||||||
ref int itemIndex = ref _mapping[entityID];
|
ref int itemIndex = ref _mapping[entityID];
|
||||||
@ -145,14 +145,14 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
public void Copy(int fromEntityID, int toEntityID)
|
public void Copy(int fromEntityID, int toEntityID)
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (!Has(fromEntityID)) ThrowNotHaveComponent<T>(fromEntityID);
|
if (!Has(fromEntityID)) ThrowNotHaveComponent<T>(fromEntityID);
|
||||||
#endif
|
#endif
|
||||||
_componentCopyHandler.Copy(ref Write(fromEntityID), ref TryAddOrWrite(toEntityID));
|
_componentCopyHandler.Copy(ref Write(fromEntityID), ref TryAddOrWrite(toEntityID));
|
||||||
}
|
}
|
||||||
public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
|
public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (!Has(fromEntityID)) ThrowNotHaveComponent<T>(fromEntityID);
|
if (!Has(fromEntityID)) ThrowNotHaveComponent<T>(fromEntityID);
|
||||||
#endif
|
#endif
|
||||||
_componentCopyHandler.Copy(ref Write(fromEntityID), ref toWorld.GetPool<T>().TryAddOrWrite(toEntityID));
|
_componentCopyHandler.Copy(ref Write(fromEntityID), ref toWorld.GetPool<T>().TryAddOrWrite(toEntityID));
|
||||||
|
|||||||
@ -1,177 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
|
||||||
{
|
|
||||||
using static EcsPoolThrowHalper;
|
|
||||||
public sealed class EcsSinglePool<T> : IEcsPoolImplementation<T>, IEnumerable<T> //IntelliSense hack
|
|
||||||
where T : struct, IEcsSingleComponent
|
|
||||||
{
|
|
||||||
private EcsWorld _source;
|
|
||||||
private int _id;
|
|
||||||
|
|
||||||
private int[] _mapping;
|
|
||||||
|
|
||||||
private int _count;
|
|
||||||
private T _component;
|
|
||||||
|
|
||||||
private List<IEcsPoolEventListener> _listeners;
|
|
||||||
|
|
||||||
#region Properites
|
|
||||||
public ref T Instance
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get => ref _component;
|
|
||||||
}
|
|
||||||
public int Count => _count;
|
|
||||||
int IEcsPool.Capacity => -1;
|
|
||||||
public int ComponentID => _id;
|
|
||||||
public Type ComponentType => typeof(T);
|
|
||||||
public EcsWorld World => _source;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Init
|
|
||||||
void IEcsPoolImplementation.OnInit(EcsWorld world, int componentID)
|
|
||||||
{
|
|
||||||
_source = world;
|
|
||||||
_id = componentID;
|
|
||||||
|
|
||||||
_mapping = new int[world.Capacity];
|
|
||||||
_count = 0;
|
|
||||||
_listeners = new List<IEcsPoolEventListener>();
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
public ref T Add(int entityID)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (Has(entityID)) ThrowAlreadyHasComponent<T>(entityID);
|
|
||||||
#endif
|
|
||||||
_mapping[entityID] = ++_count;
|
|
||||||
this.IncrementEntityComponentCount(entityID);
|
|
||||||
_listeners.InvokeOnAddAndWrite(entityID);
|
|
||||||
return ref _component;
|
|
||||||
}
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public ref T Write(int entityID)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
|
||||||
#endif
|
|
||||||
_listeners.InvokeOnWrite(entityID);
|
|
||||||
return ref _component;
|
|
||||||
}
|
|
||||||
public ref T TryAddOrWrite(int entityID)
|
|
||||||
{
|
|
||||||
if (!Has(entityID))
|
|
||||||
return ref Add(entityID);
|
|
||||||
return ref Write(entityID);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public ref readonly T Read(int entityID)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
|
||||||
#endif
|
|
||||||
return ref _component;
|
|
||||||
}
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool Has(int entityID)
|
|
||||||
{
|
|
||||||
return _mapping[entityID] > 0;
|
|
||||||
}
|
|
||||||
public void Del(int entityID)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
|
||||||
#endif
|
|
||||||
_mapping[entityID] = 0;
|
|
||||||
_count--;
|
|
||||||
this.DecrementEntityComponentCount(entityID);
|
|
||||||
_listeners.InvokeOnDel(entityID);
|
|
||||||
}
|
|
||||||
public void TryDel(int entityID)
|
|
||||||
{
|
|
||||||
if (Has(entityID)) Del(entityID);
|
|
||||||
}
|
|
||||||
public void Copy(int fromEntityID, int toEntityID)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
|
||||||
if (!Has(fromEntityID)) ThrowNotHaveComponent<T>(fromEntityID);
|
|
||||||
#endif
|
|
||||||
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
|
|
||||||
|
|
||||||
#region Callbacks
|
|
||||||
void IEcsPoolImplementation.OnWorldResize(int newSize)
|
|
||||||
{
|
|
||||||
Array.Resize(ref _mapping, newSize);
|
|
||||||
}
|
|
||||||
void IEcsPoolImplementation.OnWorldDestroy() { }
|
|
||||||
void IEcsPoolImplementation.OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer)
|
|
||||||
{
|
|
||||||
foreach (var entityID in buffer)
|
|
||||||
TryDel(entityID);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Other
|
|
||||||
void IEcsPool.AddRaw(int entityID, object dataRaw) => Instance = (T)dataRaw;
|
|
||||||
object IEcsPool.GetRaw(int entityID) => Instance;
|
|
||||||
void IEcsPool.SetRaw(int entityID, object dataRaw) => Instance = (T)dataRaw;
|
|
||||||
#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
|
|
||||||
IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw new NotImplementedException();
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException();
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
/// <summary>Singleton component</summary>
|
|
||||||
public interface IEcsSingleComponent { }
|
|
||||||
public static class EcsSinglePoolExt
|
|
||||||
{
|
|
||||||
public static EcsSinglePool<TSingleComponent> GetPool<TSingleComponent>(this EcsWorld self)
|
|
||||||
where TSingleComponent : struct, IEcsSingleComponent
|
|
||||||
{
|
|
||||||
return self.GetPool<TSingleComponent, EcsSinglePool<TSingleComponent>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static EcsSinglePool<TSingleComponent> Include<TSingleComponent>(this EcsSubjectBuilderBase self) where TSingleComponent : struct, IEcsSingleComponent
|
|
||||||
{
|
|
||||||
return self.Include<TSingleComponent, EcsSinglePool<TSingleComponent>>();
|
|
||||||
}
|
|
||||||
public static EcsSinglePool<TSingleComponent> Exclude<TSingleComponent>(this EcsSubjectBuilderBase self) where TSingleComponent : struct, IEcsSingleComponent
|
|
||||||
{
|
|
||||||
return self.Exclude<TSingleComponent, EcsSinglePool<TSingleComponent>>();
|
|
||||||
}
|
|
||||||
public static EcsSinglePool<TSingleComponent> Optional<TSingleComponent>(this EcsSubjectBuilderBase self) where TSingleComponent : struct, IEcsSingleComponent
|
|
||||||
{
|
|
||||||
return self.Optional<TSingleComponent, EcsSinglePool<TSingleComponent>>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -6,7 +6,7 @@ using System.Runtime.CompilerServices;
|
|||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
using static EcsPoolThrowHalper;
|
using static EcsPoolThrowHalper;
|
||||||
public sealed class EcsTagPool<T> : IEcsPoolImplementation<T>, IEnumerable<T> //IntelliSense hack
|
public sealed class EcsTagPool<T> : IEcsPoolImplementation<T>, IEnumerable<T> //IEnumerable<T> - IntelliSense hack
|
||||||
where T : struct, IEcsTagComponent
|
where T : struct, IEcsTagComponent
|
||||||
{
|
{
|
||||||
private EcsWorld _source;
|
private EcsWorld _source;
|
||||||
@ -43,7 +43,7 @@ namespace DCFApixels.DragonECS
|
|||||||
#region Method
|
#region Method
|
||||||
public void Add(int entityID)
|
public void Add(int entityID)
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (Has(entityID)) ThrowAlreadyHasComponent<T>(entityID);
|
if (Has(entityID)) ThrowAlreadyHasComponent<T>(entityID);
|
||||||
#endif
|
#endif
|
||||||
_count++;
|
_count++;
|
||||||
@ -68,7 +68,7 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
public void Del(int entityID)
|
public void Del(int entityID)
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
||||||
#endif
|
#endif
|
||||||
_mapping[entityID] = false;
|
_mapping[entityID] = false;
|
||||||
@ -82,14 +82,14 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
public void Copy(int fromEntityID, int toEntityID)
|
public void Copy(int fromEntityID, int toEntityID)
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (!Has(fromEntityID)) ThrowNotHaveComponent<T>(fromEntityID);
|
if (!Has(fromEntityID)) ThrowNotHaveComponent<T>(fromEntityID);
|
||||||
#endif
|
#endif
|
||||||
TryAdd(toEntityID);
|
TryAdd(toEntityID);
|
||||||
}
|
}
|
||||||
public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
|
public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (!Has(fromEntityID)) ThrowNotHaveComponent<T>(fromEntityID);
|
if (!Has(fromEntityID)) ThrowNotHaveComponent<T>(fromEntityID);
|
||||||
#endif
|
#endif
|
||||||
toWorld.GetPool<T>().TryAdd(toEntityID);
|
toWorld.GetPool<T>().TryAdd(toEntityID);
|
||||||
@ -138,14 +138,14 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
ref readonly T IEcsPool<T>.Read(int entityID)
|
ref readonly T IEcsPool<T>.Read(int entityID)
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
||||||
#endif
|
#endif
|
||||||
return ref _fakeComponent;
|
return ref _fakeComponent;
|
||||||
}
|
}
|
||||||
ref T IEcsPool<T>.Write(int entityID)
|
ref T IEcsPool<T>.Write(int entityID)
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
||||||
#endif
|
#endif
|
||||||
return ref _fakeComponent;
|
return ref _fakeComponent;
|
||||||
@ -153,14 +153,14 @@ namespace DCFApixels.DragonECS
|
|||||||
void IEcsPool.AddRaw(int entityID, object dataRaw) => Add(entityID);
|
void IEcsPool.AddRaw(int entityID, object dataRaw) => Add(entityID);
|
||||||
object IEcsPool.GetRaw(int entityID)
|
object IEcsPool.GetRaw(int entityID)
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
||||||
#endif
|
#endif
|
||||||
return _fakeComponent;
|
return _fakeComponent;
|
||||||
}
|
}
|
||||||
void IEcsPool.SetRaw(int entityID, object dataRaw)
|
void IEcsPool.SetRaw(int entityID, object dataRaw)
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
if (!Has(entityID)) ThrowNotHaveComponent<T>(entityID);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,4 @@
|
|||||||
using System;
|
namespace DCFApixels.DragonECS.Utils
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
|
||||||
{
|
{
|
||||||
internal static class ArrayUtility
|
internal static class ArrayUtility
|
||||||
{
|
{
|
||||||
@ -15,34 +12,4 @@ namespace DCFApixels.DragonECS
|
|||||||
array[i] = value;
|
array[i] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static unsafe class UnmanagedArrayUtility
|
|
||||||
{
|
|
||||||
public static void* New<T>(int elementCount) where T : struct
|
|
||||||
{
|
|
||||||
return Marshal.AllocHGlobal(Marshal.SizeOf(typeof(T)) * elementCount).ToPointer();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void* NewAndInit<T>(int elementCount) where T : struct
|
|
||||||
{
|
|
||||||
int newSizeInBytes = Marshal.SizeOf(typeof(T)) * elementCount;
|
|
||||||
byte* newArrayPointer = (byte*)Marshal.AllocHGlobal(newSizeInBytes).ToPointer();
|
|
||||||
|
|
||||||
for (int i = 0; i < newSizeInBytes; i++)
|
|
||||||
*(newArrayPointer + i) = 0;
|
|
||||||
|
|
||||||
return newArrayPointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Free(void* pointerToUnmanagedMemory)
|
|
||||||
{
|
|
||||||
Marshal.FreeHGlobal(new IntPtr(pointerToUnmanagedMemory));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void* Resize<T>(void* oldPointer, int newElementCount) where T : struct
|
|
||||||
{
|
|
||||||
return (Marshal.ReAllocHGlobal(new IntPtr(oldPointer),
|
|
||||||
new IntPtr(Marshal.SizeOf(typeof(T)) * newElementCount))).ToPointer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
public class EntityLinkedList
|
public class EntityLinkedList
|
||||||
{
|
{
|
||||||
public const int Enter = 0;
|
private const int ENTER = 0;
|
||||||
|
|
||||||
private Node[] _nodes;
|
private Node[] _nodes;
|
||||||
private int _count;
|
private int _count;
|
||||||
@ -35,7 +35,7 @@ namespace DCFApixels.DragonECS
|
|||||||
//ArrayUtility.Fill(_nodes, Node.Empty);
|
//ArrayUtility.Fill(_nodes, Node.Empty);
|
||||||
for (int i = 0; i < _nodes.Length; i++)
|
for (int i = 0; i < _nodes.Length; i++)
|
||||||
_nodes[i].next = 0;
|
_nodes[i].next = 0;
|
||||||
_lastNodeIndex = Enter;
|
_lastNodeIndex = ENTER;
|
||||||
_count = 0;
|
_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
_nodes = nodes;
|
_nodes = nodes;
|
||||||
_index = -1;
|
_index = -1;
|
||||||
_next = Enter;
|
_next = ENTER;
|
||||||
}
|
}
|
||||||
public int Current => _nodes[_index].entityID;
|
public int Current => _nodes[_index].entityID;
|
||||||
public bool MoveNext()
|
public bool MoveNext()
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS.Utils
|
||||||
{
|
{
|
||||||
internal sealed class IntDispenser
|
internal sealed class IntDispenser
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
public static class Extensions
|
public static class IntExtensions
|
||||||
{
|
{
|
||||||
public static entlong ToEntityLong(this int self, EcsWorld world)
|
public static entlong ToEntityLong(this int self, EcsWorld world)
|
||||||
{
|
{
|
||||||
@ -1,259 +0,0 @@
|
|||||||
//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.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
|
||||||
{
|
|
||||||
public class SparseArray<TValue>
|
|
||||||
{
|
|
||||||
public const int MIN_CAPACITY_BITS_OFFSET = 4;
|
|
||||||
public const int MIN_CAPACITY = 1 << MIN_CAPACITY_BITS_OFFSET;
|
|
||||||
private const int EMPTY = -1;
|
|
||||||
|
|
||||||
private int[] _buckets = Array.Empty<int>();
|
|
||||||
private Entry[] _entries = Array.Empty<Entry>();
|
|
||||||
private int[] _dense;
|
|
||||||
|
|
||||||
private int _count;
|
|
||||||
|
|
||||||
private int _freeList;
|
|
||||||
private int _freeCount;
|
|
||||||
|
|
||||||
private int _modBitMask;
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
public ref TValue this[int key]
|
|
||||||
{
|
|
||||||
get => ref _entries[FindEntry(key)].value;
|
|
||||||
//set => Insert(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count => _count;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
public SparseArray(int minCapacity = MIN_CAPACITY)
|
|
||||||
{
|
|
||||||
minCapacity = NormalizeCapacity(minCapacity);
|
|
||||||
_buckets = new int[minCapacity];
|
|
||||||
for (int i = 0; i < minCapacity; i++)
|
|
||||||
_buckets[i] = EMPTY;
|
|
||||||
_entries = new Entry[minCapacity];
|
|
||||||
_modBitMask = (minCapacity - 1) & 0x7FFFFFFF;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Add
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void Add(int key, TValue value)
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
if (Contains(key))
|
|
||||||
throw new ArgumentException("Contains(hashKey) is true");
|
|
||||||
#endif
|
|
||||||
Insert(key, value);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Find/Insert/Remove
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private int FindEntry(int key)
|
|
||||||
{
|
|
||||||
for (int i = _buckets[key & _modBitMask]; i >= 0; i = _entries[i].next)
|
|
||||||
if (_entries[i].hashKey == key) return i;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
private void Insert(int key, TValue value)
|
|
||||||
{
|
|
||||||
int targetBucket = key & _modBitMask;
|
|
||||||
|
|
||||||
for (int i = _buckets[targetBucket]; i >= 0; i = _entries[i].next)
|
|
||||||
{
|
|
||||||
if (_entries[i].hashKey == key)
|
|
||||||
{
|
|
||||||
_entries[i].value = value;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int index;
|
|
||||||
if (_freeCount > 0)
|
|
||||||
{
|
|
||||||
index = _freeList;
|
|
||||||
_freeList = _entries[index].next;
|
|
||||||
_freeCount--;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (_count == _entries.Length)
|
|
||||||
{
|
|
||||||
Resize();
|
|
||||||
targetBucket = key & _modBitMask;
|
|
||||||
}
|
|
||||||
index = _count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
_entries[index].next = _buckets[targetBucket];
|
|
||||||
_entries[index].hashKey = key;
|
|
||||||
_entries[index].value = value;
|
|
||||||
_buckets[targetBucket] = index;
|
|
||||||
}
|
|
||||||
public bool Remove(int key)
|
|
||||||
{
|
|
||||||
int bucket = key & _modBitMask;
|
|
||||||
int last = -1;
|
|
||||||
for (int i = _buckets[bucket]; i >= 0; last = i, i = _entries[i].next)
|
|
||||||
{
|
|
||||||
if (_entries[i].hashKey == key)
|
|
||||||
{
|
|
||||||
if (last < 0)
|
|
||||||
{
|
|
||||||
_buckets[bucket] = _entries[i].next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_entries[last].next = _entries[i].next;
|
|
||||||
}
|
|
||||||
_entries[i].next = _freeList;
|
|
||||||
_entries[i].hashKey = -1;
|
|
||||||
_entries[i].value = default;
|
|
||||||
_freeList = i;
|
|
||||||
_freeCount++;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region TryGetValue
|
|
||||||
public bool TryGetValue(int key, out TValue value)
|
|
||||||
{
|
|
||||||
int index = FindEntry(key);
|
|
||||||
if (index < 0)
|
|
||||||
{
|
|
||||||
value = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
value = _entries[index].value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Contains
|
|
||||||
public bool Contains(int key)
|
|
||||||
{
|
|
||||||
return FindEntry(key) >= 0;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Clear
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
if (_count > 0)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < _buckets.Length; i++)
|
|
||||||
{
|
|
||||||
_buckets[i] = -1;
|
|
||||||
}
|
|
||||||
Array.Clear(_entries, 0, _count);
|
|
||||||
_count = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Resize
|
|
||||||
private void Resize()
|
|
||||||
{
|
|
||||||
int newSize = _buckets.Length << 1;
|
|
||||||
_modBitMask = (newSize - 1) & 0x7FFFFFFF;
|
|
||||||
|
|
||||||
Contract.Assert(newSize >= _entries.Length);
|
|
||||||
int[] newBuckets = new int[newSize];
|
|
||||||
for (int i = 0; i < newBuckets.Length; i++)
|
|
||||||
newBuckets[i] = EMPTY;
|
|
||||||
|
|
||||||
Entry[] newEntries = new Entry[newSize];
|
|
||||||
Array.Copy(_entries, 0, newEntries, 0, _count);
|
|
||||||
for (int i = 0; i < _count; i++)
|
|
||||||
{
|
|
||||||
if (newEntries[i].hashKey >= 0)
|
|
||||||
{
|
|
||||||
int bucket = newEntries[i].hashKey % newSize;
|
|
||||||
newEntries[i].next = newBuckets[bucket];
|
|
||||||
newBuckets[bucket] = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_buckets = newBuckets;
|
|
||||||
_entries = newEntries;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int NormalizeCapacity(int capacity)
|
|
||||||
{
|
|
||||||
int result = MIN_CAPACITY;
|
|
||||||
while (result < capacity) result <<= 1;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#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
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
|
||||||
private struct Entry
|
|
||||||
{
|
|
||||||
public int next; // Index of next entry, -1 if last
|
|
||||||
public int hashKey;
|
|
||||||
public TValue value;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,409 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
|
||||||
{
|
|
||||||
public class SparseSet : IEnumerable<int>, ICollection<int>, IReadOnlyCollection<int>
|
|
||||||
{
|
|
||||||
public const int DEFAULT_DENSE_CAPACITY = 8;
|
|
||||||
public const int DEFAULT_SPARSE_CAPACITY = 16;
|
|
||||||
|
|
||||||
public const int MIN_CAPACITY = 4;
|
|
||||||
|
|
||||||
public const int MAX_CAPACITY = int.MaxValue;
|
|
||||||
|
|
||||||
private int[] _dense;
|
|
||||||
private int[] _sparse;
|
|
||||||
|
|
||||||
private int _count;
|
|
||||||
|
|
||||||
#region Properties
|
|
||||||
public int Count
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get => _count;
|
|
||||||
}
|
|
||||||
public int CapacityDense
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get => _dense.Length;
|
|
||||||
}
|
|
||||||
public int CapacitySparse
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get => _sparse.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int this[int index]
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
ThrowHalper.CheckOutOfRange(this, index);
|
|
||||||
#endif
|
|
||||||
return _dense[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
public SparseSet() : this(DEFAULT_DENSE_CAPACITY, DEFAULT_SPARSE_CAPACITY) { }
|
|
||||||
public SparseSet(int denseCapacity, int sparseCapacity)
|
|
||||||
{
|
|
||||||
denseCapacity = denseCapacity < MIN_CAPACITY ? MIN_CAPACITY : NormalizeCapacity(denseCapacity);
|
|
||||||
sparseCapacity = sparseCapacity < MIN_CAPACITY ? MIN_CAPACITY : NormalizeCapacity(sparseCapacity);
|
|
||||||
|
|
||||||
_dense = new int[denseCapacity];
|
|
||||||
_sparse = new int[sparseCapacity];
|
|
||||||
|
|
||||||
Reset();
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Add/AddRange
|
|
||||||
public void Add<T>(int value, ref T[] normalizedArray)
|
|
||||||
{
|
|
||||||
Add(value);
|
|
||||||
Normalize(ref normalizedArray);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(int value)
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
ThrowHalper.CheckValueIsPositive(value);
|
|
||||||
ThrowHalper.CheckValueNotContained(this, value);
|
|
||||||
#endif
|
|
||||||
if (_count >= _dense.Length)
|
|
||||||
Array.Resize(ref _dense, _dense.Length << 1);
|
|
||||||
|
|
||||||
if (value >= _sparse.Length)
|
|
||||||
{
|
|
||||||
int neadedSpace = _sparse.Length;
|
|
||||||
while (value >= neadedSpace)
|
|
||||||
neadedSpace <<= 1;
|
|
||||||
int i = _sparse.Length;
|
|
||||||
Array.Resize(ref _sparse, neadedSpace);
|
|
||||||
//loop unwinding
|
|
||||||
for (; i < neadedSpace;)
|
|
||||||
{
|
|
||||||
_sparse[i++] = -1;
|
|
||||||
_sparse[i++] = -1;
|
|
||||||
_sparse[i++] = -1;
|
|
||||||
_sparse[i++] = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_dense[_count] = value;
|
|
||||||
_sparse[value] = _count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryAdd<T>(int value, ref T[] normalizedArray)
|
|
||||||
{
|
|
||||||
if (Contains(value)) return false;
|
|
||||||
Add(value);
|
|
||||||
Normalize(ref normalizedArray);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
public bool TryAdd(int value)
|
|
||||||
{
|
|
||||||
if (Contains(value)) return false;
|
|
||||||
Add(value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddRange<T>(IEnumerable<int> range, ref T[] normalizedArray)
|
|
||||||
{
|
|
||||||
AddRange(range);
|
|
||||||
Normalize(ref normalizedArray);
|
|
||||||
}
|
|
||||||
public void AddRange(IEnumerable<int> range)
|
|
||||||
{
|
|
||||||
foreach (var item in range)
|
|
||||||
{
|
|
||||||
if (Contains(item)) continue;
|
|
||||||
Add(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Contains
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool Contains(int value)
|
|
||||||
{
|
|
||||||
return value >= 0 && value < CapacitySparse && _sparse[value] >= 0;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Remove
|
|
||||||
public void Remove(int value)
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
ThrowHalper.CheckValueContained(this, value);
|
|
||||||
#endif
|
|
||||||
_dense[_sparse[value]] = _dense[--_count];
|
|
||||||
_sparse[_dense[_count]] = _sparse[value];
|
|
||||||
_sparse[value] = -1;
|
|
||||||
}
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool TryRemove(int value)
|
|
||||||
{
|
|
||||||
if (!Contains(value)) return false;
|
|
||||||
Remove(value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void RemoveAt(int index)
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
ThrowHalper.CheckOutOfRange(this, index);
|
|
||||||
#endif
|
|
||||||
Remove(_dense[index]);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Other
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void Normalize<T>(ref T[] array)
|
|
||||||
{
|
|
||||||
if (array.Length < CapacityDense) Array.Resize(ref array, CapacityDense);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public int IndexOf(int value)
|
|
||||||
{
|
|
||||||
if (value < 0 || !Contains(value)) return -1;
|
|
||||||
return _sparse[value];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Sort()
|
|
||||||
{
|
|
||||||
int increment = 0;
|
|
||||||
for (int i = 0; i < CapacitySparse; i++)
|
|
||||||
{
|
|
||||||
if (_sparse[i] < _count)
|
|
||||||
{
|
|
||||||
_sparse[i] = increment;
|
|
||||||
_dense[increment++] = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void HardSort()
|
|
||||||
{
|
|
||||||
int inc = 0;
|
|
||||||
int inc2 = _count;
|
|
||||||
for (int i = 0; i < CapacitySparse; i++)
|
|
||||||
{
|
|
||||||
if (_sparse[i] >= 0)
|
|
||||||
{
|
|
||||||
_sparse[i] = inc;
|
|
||||||
_dense[inc++] = i;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_dense[inc2++] = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CopyTo(SparseSet other)
|
|
||||||
{
|
|
||||||
other._count = _count;
|
|
||||||
if (CapacitySparse != other.CapacitySparse)
|
|
||||||
Array.Resize(ref other._sparse, CapacitySparse);
|
|
||||||
if (CapacityDense != other.CapacityDense)
|
|
||||||
Array.Resize(ref other._dense, CapacityDense);
|
|
||||||
_sparse.CopyTo(other._sparse, 0);
|
|
||||||
_dense.CopyTo(other._dense, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CopyTo(int[] array, int arrayIndex)
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
if (arrayIndex < 0) throw new ArgumentException("arrayIndex is less than 0");
|
|
||||||
if (arrayIndex + _count >= array.Length) throw new ArgumentException("The number of elements in the source List<T> is greater than the available space from arrayIndex to the end of the destination array.");
|
|
||||||
#endif
|
|
||||||
for (int i = 0; i < _count; i++, arrayIndex++)
|
|
||||||
{
|
|
||||||
array[arrayIndex] = this[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private int NormalizeCapacity(int value)
|
|
||||||
{
|
|
||||||
return value + (MIN_CAPACITY - (value % MIN_CAPACITY));
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Clear/Reset
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void Clear() => _count = 0;
|
|
||||||
public void Reset()
|
|
||||||
{
|
|
||||||
Clear();
|
|
||||||
//loop unwinding
|
|
||||||
for (int i = 0; i < _sparse.Length;)
|
|
||||||
{
|
|
||||||
_sparse[i++] = -1;
|
|
||||||
_sparse[i++] = -1;
|
|
||||||
_sparse[i++] = -1;
|
|
||||||
_sparse[i++] = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Reset(int newDenseCapacity, int newSparseCapacity)
|
|
||||||
{
|
|
||||||
newDenseCapacity = newDenseCapacity < MIN_CAPACITY ? MIN_CAPACITY : NormalizeCapacity(newDenseCapacity);
|
|
||||||
newSparseCapacity = newSparseCapacity < MIN_CAPACITY ? MIN_CAPACITY : NormalizeCapacity(newSparseCapacity);
|
|
||||||
|
|
||||||
if (CapacitySparse != newSparseCapacity)
|
|
||||||
Array.Resize(ref _sparse, newSparseCapacity);
|
|
||||||
if (CapacityDense != newDenseCapacity)
|
|
||||||
Array.Resize(ref _dense, newDenseCapacity);
|
|
||||||
Reset();
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Enumerator
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public RefEnumerator GetEnumerator() => new RefEnumerator(_dense, _count);
|
|
||||||
|
|
||||||
public ref struct RefEnumerator
|
|
||||||
{
|
|
||||||
private readonly int[] _dense;
|
|
||||||
private readonly int _count;
|
|
||||||
private int _index;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public RefEnumerator(int[] values, int count)
|
|
||||||
{
|
|
||||||
_dense = values;
|
|
||||||
_count = count;
|
|
||||||
_index = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Current
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get => _dense[_index];
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void Dispose() { }
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool MoveNext() => ++_index < _count;
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void Reset() => _index = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator<int> IEnumerable<int>.GetEnumerator() => new Enumerator(_dense, _count);
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => new Enumerator(_dense, _count);
|
|
||||||
public struct Enumerator : IEnumerator<int> //to implement the IEnumerable interface and use the ref structure, 2 Enumerators were created.
|
|
||||||
{
|
|
||||||
private readonly int[] _dense;
|
|
||||||
private readonly int _count;
|
|
||||||
private int _index;
|
|
||||||
public Enumerator(int[] values, int count)
|
|
||||||
{
|
|
||||||
_dense = values;
|
|
||||||
_count = count;
|
|
||||||
_index = -1;
|
|
||||||
}
|
|
||||||
public int Current => _dense[_index];
|
|
||||||
object IEnumerator.Current => _dense[_index];
|
|
||||||
public void Dispose() { }
|
|
||||||
public bool MoveNext() => ++_index < _count;
|
|
||||||
public void Reset() => _index = -1;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region ICollection
|
|
||||||
bool ICollection<int>.IsReadOnly => false;
|
|
||||||
|
|
||||||
bool ICollection<int>.Remove(int value) => TryRemove(value);
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Debug
|
|
||||||
public string Log()
|
|
||||||
{
|
|
||||||
StringBuilder logbuild = new StringBuilder();
|
|
||||||
for (int i = 0; i < CapacityDense; i++)
|
|
||||||
{
|
|
||||||
logbuild.Append(_dense[i] + ", ");
|
|
||||||
}
|
|
||||||
logbuild.Append("\n\r");
|
|
||||||
for (int i = 0; i < CapacitySparse; i++)
|
|
||||||
{
|
|
||||||
logbuild.Append(_sparse[i] + ", ");
|
|
||||||
}
|
|
||||||
logbuild.Append("\n\r --------------------------");
|
|
||||||
logbuild.Append("\n\r");
|
|
||||||
for (int i = 0; i < CapacityDense; i++)
|
|
||||||
{
|
|
||||||
logbuild.Append((i < _count ? _dense[i].ToString() : "_") + ", ");
|
|
||||||
}
|
|
||||||
logbuild.Append("\n\r");
|
|
||||||
for (int i = 0; i < CapacitySparse; i++)
|
|
||||||
{
|
|
||||||
logbuild.Append((_sparse[i] >= 0 ? _sparse[i].ToString() : "_") + ", ");
|
|
||||||
}
|
|
||||||
logbuild.Append("\n\r Count: " + _count);
|
|
||||||
logbuild.Append("\n\r Capacity: " + CapacitySparse);
|
|
||||||
logbuild.Append("\n\r IsValide: " + IsValide_Debug());
|
|
||||||
|
|
||||||
logbuild.Append("\n\r");
|
|
||||||
return logbuild.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsValide_Debug()
|
|
||||||
{
|
|
||||||
bool isPass = true;
|
|
||||||
for (int index = 0; index < _count; index++)
|
|
||||||
{
|
|
||||||
int value = _dense[index];
|
|
||||||
isPass = isPass && _sparse[value] == index;
|
|
||||||
}
|
|
||||||
return isPass;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
private static class ThrowHalper
|
|
||||||
{
|
|
||||||
public static void CheckCapacity(int capacity)
|
|
||||||
{
|
|
||||||
if (capacity < 0)
|
|
||||||
throw new ArgumentException("Capacity cannot be a negative number");
|
|
||||||
}
|
|
||||||
public static void CheckValueIsPositive(int value)
|
|
||||||
{
|
|
||||||
if (value < 0)
|
|
||||||
throw new ArgumentException("The SparseSet can only contain positive numbers");
|
|
||||||
}
|
|
||||||
public static void CheckValueContained(SparseSet source, int value)
|
|
||||||
{
|
|
||||||
if (!source.Contains(value))
|
|
||||||
throw new ArgumentException($"Value {value} is not contained");
|
|
||||||
}
|
|
||||||
public static void CheckValueNotContained(SparseSet source, int value)
|
|
||||||
{
|
|
||||||
if (source.Contains(value))
|
|
||||||
throw new ArgumentException($"Value {value} is already contained");
|
|
||||||
}
|
|
||||||
public static void CheckOutOfRange(SparseSet source, int index)
|
|
||||||
{
|
|
||||||
if (index < 0 || index >= source.Count)
|
|
||||||
throw new ArgumentOutOfRangeException($"Index {index} was out of range. Must be non-negative and less than the size of the collection.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
#pragma warning disable IDE1006
|
||||||
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
@ -6,9 +7,7 @@ using System.Runtime.InteropServices;
|
|||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
using static entlong.ThrowHalper;
|
using static entlong.ThrowHalper;
|
||||||
// uniqueID - 32 bits
|
// [ id 32 | gen 16 | world 16 ]
|
||||||
// gen - 16 bits
|
|
||||||
// world - 16 bits
|
|
||||||
/// <summary>Strong identifier/Permanent entity identifier</summary>
|
/// <summary>Strong identifier/Permanent entity identifier</summary>
|
||||||
[StructLayout(LayoutKind.Explicit, Pack = 2, Size = 8)]
|
[StructLayout(LayoutKind.Explicit, Pack = 2, Size = 8)]
|
||||||
public readonly struct entlong : IEquatable<long>, IEquatable<entlong>
|
public readonly struct entlong : IEquatable<long>, IEquatable<entlong>
|
||||||
@ -34,12 +33,6 @@ namespace DCFApixels.DragonECS
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => this == NULL;
|
get => this == NULL;
|
||||||
}
|
}
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
||||||
public bool IsNotNull
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get => this != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
public int ID
|
public int ID
|
||||||
@ -47,7 +40,7 @@ namespace DCFApixels.DragonECS
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (!IsAlive) ThrowIsNotAlive(this);
|
if (!IsAlive) ThrowIsNotAlive(this);
|
||||||
#endif
|
#endif
|
||||||
return id;
|
return id;
|
||||||
@ -59,7 +52,7 @@ namespace DCFApixels.DragonECS
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (!IsAlive) ThrowIsNotAlive(this);
|
if (!IsAlive) ThrowIsNotAlive(this);
|
||||||
#endif
|
#endif
|
||||||
return gen;
|
return gen;
|
||||||
@ -70,7 +63,7 @@ namespace DCFApixels.DragonECS
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (!IsAlive) ThrowIsNotAlive(this);
|
if (!IsAlive) ThrowIsNotAlive(this);
|
||||||
#endif
|
#endif
|
||||||
return EcsWorld.Worlds[world];
|
return EcsWorld.Worlds[world];
|
||||||
@ -82,7 +75,7 @@ namespace DCFApixels.DragonECS
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (!IsAlive) ThrowIsNotAlive(this);
|
if (!IsAlive) ThrowIsNotAlive(this);
|
||||||
#endif
|
#endif
|
||||||
return world;
|
return world;
|
||||||
@ -135,7 +128,7 @@ namespace DCFApixels.DragonECS
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public override int GetHashCode() => unchecked((int)full) ^ (int)(full >> 32);
|
public override int GetHashCode() => unchecked((int)full) ^ (int)(full >> 32);
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public override string ToString() => $"entity(id:{id} g:{gen} w:{world} {(IsAlive ? "alive" : "not alive")})";
|
public override string ToString() => $"entity(id:{id} g:{gen} w:{world} {(IsNull ? "null" : IsAlive ? "alive" : "not alive")})";
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public override bool Equals(object obj) => obj is entlong other && full == other.full;
|
public override bool Equals(object obj) => obj is entlong other && full == other.full;
|
||||||
#endregion
|
#endregion
|
||||||
@ -159,9 +152,9 @@ namespace DCFApixels.DragonECS
|
|||||||
public static void ThrowIsNotAlive(entlong entity)
|
public static void ThrowIsNotAlive(entlong entity)
|
||||||
{
|
{
|
||||||
if (entity.IsNull)
|
if (entity.IsNull)
|
||||||
throw new EcsFrameworkException("The entity identifier is null.");
|
throw new EcsFrameworkException($"The {entity} is null.");
|
||||||
else
|
else
|
||||||
throw new EcsFrameworkException("The entity is not alive.");
|
throw new EcsFrameworkException($"The {entity} is not alive.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user