mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2026-04-22 01:45:55 +08:00
Rework
Rework runner system, SparseSet etc
This commit is contained in:
parent
b73652cb37
commit
66b136df92
@ -1,15 +0,0 @@
|
|||||||
namespace DCFApixels.DragonECS
|
|
||||||
{
|
|
||||||
public class FiltersProcessor : IEcsGReceive<_OnComponentAdded>, IEcsGReceive<_OnComponentRemoved>
|
|
||||||
{
|
|
||||||
void IEcsGReceive<_OnComponentAdded>.Do<T>(EcsSession session, in _OnComponentAdded message, in T obj)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void IEcsGReceive<_OnComponentRemoved>.Do<T>(EcsSession session, in _OnComponentRemoved message, in T obj)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -17,9 +17,8 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
void IDo<_PreInit>.Do(EcsSession session)
|
void IDo<_PreInit>.Do(EcsSession session)
|
||||||
{
|
{
|
||||||
_OnInject<T> m = new _OnInject<T>(_injectedData);
|
|
||||||
var messenger = session.GetMessenger<_OnInject<T>>();
|
var messenger = session.GetMessenger<_OnInject<T>>();
|
||||||
messenger.Send(in m);
|
messenger.Send(new _OnInject<T>(_injectedData));
|
||||||
messenger.Destroy();
|
messenger.Destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,13 +34,13 @@ namespace DCFApixels.DragonECS
|
|||||||
public EcsGroup(IEcsWorld world, int entitiesCapacity, int delayedOpsCapacity = 128)
|
public EcsGroup(IEcsWorld world, int entitiesCapacity, int delayedOpsCapacity = 128)
|
||||||
{
|
{
|
||||||
_source = world;
|
_source = world;
|
||||||
_entities = new SparseSet(entitiesCapacity);
|
_entities = new SparseSet(entitiesCapacity, entitiesCapacity);
|
||||||
_delayedOps = new DelayedOp[delayedOpsCapacity];
|
_delayedOps = new DelayedOp[delayedOpsCapacity];
|
||||||
_lockCount = 0;
|
_lockCount = 0;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region add/remove
|
#region Add/Remove
|
||||||
public void Add(int entityID)
|
public void Add(int entityID)
|
||||||
{
|
{
|
||||||
if (_lockCount > 0)
|
if (_lockCount > 0)
|
||||||
|
|||||||
@ -40,7 +40,7 @@ namespace DCFApixels.DragonECS
|
|||||||
public EcsPool(IEcsWorld source, int capacity)
|
public EcsPool(IEcsWorld source, int capacity)
|
||||||
{
|
{
|
||||||
_source = source;
|
_source = source;
|
||||||
_sparseSet = new SparseSet(capacity);
|
_sparseSet = new SparseSet(capacity, capacity);
|
||||||
|
|
||||||
_denseItems =new T[capacity];
|
_denseItems =new T[capacity];
|
||||||
}
|
}
|
||||||
@ -96,28 +96,4 @@ namespace DCFApixels.DragonECS
|
|||||||
public override int GetHashCode() => _source.GetHashCode() + ID;
|
public override int GetHashCode() => _source.GetHashCode() + ID;
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
public static partial class EntityExtensions
|
|
||||||
{
|
|
||||||
public static ref readonly T Read<T>(this in Entity self)
|
|
||||||
where T : struct
|
|
||||||
{
|
|
||||||
return ref self.world.GetPool<T>().Read(self.id);
|
|
||||||
}
|
|
||||||
public static ref T Write<T>(this in Entity self)
|
|
||||||
where T : struct
|
|
||||||
{
|
|
||||||
return ref self.world.GetPool<T>().Write(self.id);
|
|
||||||
}
|
|
||||||
public static bool Has<T>(this in Entity self)
|
|
||||||
where T : struct
|
|
||||||
{
|
|
||||||
return self.world.GetPool<T>().Has(self.id);
|
|
||||||
}
|
|
||||||
public static void Del<T>(this in Entity self)
|
|
||||||
where T : struct
|
|
||||||
{
|
|
||||||
self.world.GetPool<T>().Del(self.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,34 @@ using System.Runtime.CompilerServices;
|
|||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
|
public class EcsWorldMap
|
||||||
|
{
|
||||||
|
private Dictionary<(Type, string), IEcsWorld> _worlds = new Dictionary<(Type, string), IEcsWorld>(8);
|
||||||
|
private bool _built = false;
|
||||||
|
|
||||||
|
public void Add<TArchetype>(EcsWorld<TArchetype> world, string name = "")
|
||||||
|
where TArchetype : IWorldArchetype
|
||||||
|
{
|
||||||
|
if(_built) { throw new Exception($"Cant change built {nameof(EcsWorldMap)}"); }
|
||||||
|
_worlds.Add((typeof(TArchetype), name), world);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EcsWorld<TArchetype> Get<TArchetype>(string name ="")
|
||||||
|
where TArchetype : IWorldArchetype
|
||||||
|
{
|
||||||
|
return (EcsWorld<TArchetype>)_worlds[(typeof(TArchetype), name)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEcsWorld Get(Type type, string name = "")
|
||||||
|
{
|
||||||
|
return _worlds[(type, name)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Build()
|
||||||
|
{
|
||||||
|
_built = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class EcsSession
|
public class EcsSession
|
||||||
{
|
{
|
||||||
@ -18,14 +46,13 @@ namespace DCFApixels.DragonECS
|
|||||||
private bool _isInit = false;
|
private bool _isInit = false;
|
||||||
private bool _isDestoryed = false;
|
private bool _isDestoryed = false;
|
||||||
|
|
||||||
private int _worldIdIncrement;
|
|
||||||
private Dictionary<string, IEcsWorld> _worldsDict = new Dictionary<string, IEcsWorld>();
|
|
||||||
private List<IEcsWorld> _worlds = new List<IEcsWorld>();
|
|
||||||
|
|
||||||
private Dictionary<Type, IEcsProcessorsRunner> _runners;
|
private Dictionary<Type, IEcsProcessorsRunner> _runners;
|
||||||
private Dictionary<Type, IEcsProcessorsMessenger> _messengers;
|
private Dictionary<Type, IEcsProcessorsMessenger> _messengers;
|
||||||
private EcsProcessorsRunner<_Run> _runRunnerCache;
|
private EcsProcessorsRunner<_Run> _runRunnerCache;
|
||||||
|
|
||||||
|
private EcsWorldMap _worldMap = new EcsWorldMap();
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
public ReadOnlyCollection<IEcsProcessor> AllProcessors => _allProcessorsSealed;
|
public ReadOnlyCollection<IEcsProcessor> AllProcessors => _allProcessorsSealed;
|
||||||
|
|
||||||
@ -33,7 +60,6 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
#region React Runners/Messengers
|
#region React Runners/Messengers
|
||||||
public EcsProcessorsRunner<TDoTag> GetRunner<TDoTag>()
|
public EcsProcessorsRunner<TDoTag> GetRunner<TDoTag>()
|
||||||
where TDoTag : IEcsDoTag
|
|
||||||
{
|
{
|
||||||
Type type = typeof(TDoTag);
|
Type type = typeof(TDoTag);
|
||||||
if (_runners.TryGetValue(type, out IEcsProcessorsRunner result))
|
if (_runners.TryGetValue(type, out IEcsProcessorsRunner result))
|
||||||
@ -45,7 +71,6 @@ namespace DCFApixels.DragonECS
|
|||||||
return (EcsProcessorsRunner<TDoTag>)result;
|
return (EcsProcessorsRunner<TDoTag>)result;
|
||||||
}
|
}
|
||||||
internal void OnRunnerDetroyed<TDoTag>(EcsProcessorsRunner<TDoTag> target)
|
internal void OnRunnerDetroyed<TDoTag>(EcsProcessorsRunner<TDoTag> target)
|
||||||
where TDoTag : IEcsDoTag
|
|
||||||
{
|
{
|
||||||
_runners.Remove(typeof(TDoTag));
|
_runners.Remove(typeof(TDoTag));
|
||||||
}
|
}
|
||||||
@ -62,18 +87,6 @@ namespace DCFApixels.DragonECS
|
|||||||
_messengers.Add(type, result);
|
_messengers.Add(type, result);
|
||||||
return (EcsProcessorsMessenger<TMessege>)result;
|
return (EcsProcessorsMessenger<TMessege>)result;
|
||||||
}
|
}
|
||||||
public EcsProcessorsGMessenger<TMessege> GetGMessenger<TMessege>()
|
|
||||||
where TMessege : IEcsMessage
|
|
||||||
{
|
|
||||||
Type type = typeof(EcsProcessorsGMessenger<TMessege>);
|
|
||||||
if (_messengers.TryGetValue(type, out IEcsProcessorsMessenger result))
|
|
||||||
{
|
|
||||||
return (EcsProcessorsGMessenger<TMessege>)result;
|
|
||||||
}
|
|
||||||
result = new EcsProcessorsMessenger<TMessege>(this);
|
|
||||||
_messengers.Add(type, result);
|
|
||||||
return (EcsProcessorsGMessenger<TMessege>)result;
|
|
||||||
}
|
|
||||||
internal void OnMessengerDetroyed<TMessege>(IEcsProcessorsMessenger<TMessege> target)
|
internal void OnMessengerDetroyed<TMessege>(IEcsProcessorsMessenger<TMessege> target)
|
||||||
where TMessege : IEcsMessage
|
where TMessege : IEcsMessage
|
||||||
{
|
{
|
||||||
@ -85,7 +98,6 @@ namespace DCFApixels.DragonECS
|
|||||||
public EcsSession Add(IEcsProcessor system)
|
public EcsSession Add(IEcsProcessor system)
|
||||||
{
|
{
|
||||||
CheckInitForMethod(nameof(AddWorld));
|
CheckInitForMethod(nameof(AddWorld));
|
||||||
|
|
||||||
_allProcessors.Add(system);
|
_allProcessors.Add(system);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -93,8 +105,7 @@ namespace DCFApixels.DragonECS
|
|||||||
where TArchetype : IWorldArchetype
|
where TArchetype : IWorldArchetype
|
||||||
{
|
{
|
||||||
CheckInitForMethod(nameof(AddWorld));
|
CheckInitForMethod(nameof(AddWorld));
|
||||||
|
_worldMap.Add(world, name);
|
||||||
_worlds.Add(new EcsWorld(_worldIdIncrement++));
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,9 +115,12 @@ namespace DCFApixels.DragonECS
|
|||||||
public void Init()
|
public void Init()
|
||||||
{
|
{
|
||||||
CheckInitForMethod(nameof(Init));
|
CheckInitForMethod(nameof(Init));
|
||||||
|
_worldMap.Build();
|
||||||
_allProcessorsSealed = _allProcessors.AsReadOnly();
|
_allProcessorsSealed = _allProcessors.AsReadOnly();
|
||||||
_isInit = true;
|
_isInit = true;
|
||||||
|
|
||||||
|
GetMessenger<_OnInject<EcsWorldMap>>().Send(new _OnInject<EcsWorldMap>(_worldMap));
|
||||||
|
|
||||||
GetRunner<_PreInit>().Run();
|
GetRunner<_PreInit>().Run();
|
||||||
GetRunner<_Init>().Run();
|
GetRunner<_Init>().Run();
|
||||||
|
|
||||||
@ -158,6 +172,7 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region Utils
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,20 +8,16 @@ using System.Threading.Tasks;
|
|||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
public interface IWorldArchetype { }
|
public interface IWorldArchetype { }
|
||||||
public struct DefaultArchetype : IWorldArchetype { }
|
public struct DefaultWorld : IWorldArchetype { }
|
||||||
|
|
||||||
public interface IEcsWorld
|
public interface IEcsWorld
|
||||||
{
|
{
|
||||||
public const int MAX_WORLDS = byte.MaxValue; //Номер последнего мира 254
|
|
||||||
public const int DEAD_WORLD_ID = byte.MaxValue; //Зарезервированный номер мира для мертвых сущьностей
|
|
||||||
|
|
||||||
//private float _timeScale;//TODO реализовать собсвенныйтайм склей для разных миров
|
//private float _timeScale;//TODO реализовать собсвенныйтайм склей для разных миров
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
public ushort ID { get; internal set; }
|
|
||||||
public bool IsAlive { get; }
|
|
||||||
public bool IsEmpty { get; }
|
public bool IsEmpty { get; }
|
||||||
public Type ArchetypeType { get; }
|
public Type ArchetypeType { get; }
|
||||||
|
public int ID { get; }
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public EcsPool<T> GetPool<T>() where T : struct;
|
public EcsPool<T> GetPool<T>() where T : struct;
|
||||||
@ -36,15 +32,29 @@ namespace DCFApixels.DragonECS
|
|||||||
internal void OnEntityComponentRemoved(int entityID, int changedPoolID);
|
internal void OnEntityComponentRemoved(int entityID, int changedPoolID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class EcsWorld<TArchetype> : IEcsWorld
|
|
||||||
|
public abstract class EcsWorld
|
||||||
|
{
|
||||||
|
internal static IEcsWorld[] Worlds = new IEcsWorld[8];
|
||||||
|
private static IntDispenser _worldIdDispenser = new IntDispenser();
|
||||||
|
|
||||||
|
public readonly short id;
|
||||||
|
|
||||||
|
public EcsWorld()
|
||||||
|
{
|
||||||
|
id = (short)_worldIdDispenser.GetFree();
|
||||||
|
Worlds[id] = (IEcsWorld)this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class EcsWorld<TArchetype> : EcsWorld, IEcsWorld
|
||||||
where TArchetype : IWorldArchetype
|
where TArchetype : IWorldArchetype
|
||||||
{
|
{
|
||||||
private ushort _id = IEcsWorld.DEAD_WORLD_ID;
|
private IntDispenser _entityDispenser;
|
||||||
|
private EcsGroup _entities;
|
||||||
|
|
||||||
private SparseSet _componentIDToPoolID;
|
|
||||||
|
|
||||||
private SparseSet _entities = new SparseSet();
|
|
||||||
private short[] _gens;
|
private short[] _gens;
|
||||||
|
private short[] _componentCounts;
|
||||||
|
|
||||||
private IEcsPool[] _pools;
|
private IEcsPool[] _pools;
|
||||||
|
|
||||||
@ -54,22 +64,18 @@ namespace DCFApixels.DragonECS
|
|||||||
private EcsFilter[] _filters;
|
private EcsFilter[] _filters;
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
public ushort ID => _id;
|
|
||||||
ushort IEcsWorld.ID { get => _id; set => _id = value; }
|
|
||||||
|
|
||||||
public bool IsAlive => _id != IEcsWorld.DEAD_WORLD_ID;
|
|
||||||
public bool IsEmpty => _entities.Count < 0;
|
public bool IsEmpty => _entities.Count < 0;
|
||||||
public Type ArchetypeType => typeof(TArchetype);
|
public Type ArchetypeType => typeof(TArchetype);
|
||||||
|
public int ID => id;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
public EcsWorld()
|
public EcsWorld()
|
||||||
{
|
{
|
||||||
|
_entityDispenser = new IntDispenser();
|
||||||
_pools = new IEcsPool[512];
|
_pools = new IEcsPool[512];
|
||||||
_entities = new SparseSet(512);
|
_filters = new EcsFilter[64];
|
||||||
_componentIDToPoolID = new SparseSet(512);
|
_entities = new EcsGroup(this, 512);
|
||||||
_filters = new EcsFilter[512];
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -117,14 +123,14 @@ namespace DCFApixels.DragonECS
|
|||||||
BakedMask bakedMask = mask.GetBaked<TArchetype>();
|
BakedMask bakedMask = mask.GetBaked<TArchetype>();
|
||||||
for (int i = 0, iMax = bakedMask.IncCount; i < iMax; i++)
|
for (int i = 0, iMax = bakedMask.IncCount; i < iMax; i++)
|
||||||
{
|
{
|
||||||
if (!_pools[_componentIDToPoolID[bakedMask.Inc[i]]].Has(entity))
|
if (!_pools[bakedMask.Inc[i]].Has(entity))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0, iMax = bakedMask.ExcCount; i < iMax; i++)
|
for (int i = 0, iMax = bakedMask.ExcCount; i < iMax; i++)
|
||||||
{
|
{
|
||||||
if (_pools[_componentIDToPoolID[bakedMask.Exc[i]]].Has(entity))
|
if (_pools[bakedMask.Exc[i]].Has(entity))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -137,7 +143,7 @@ namespace DCFApixels.DragonECS
|
|||||||
BakedMask bakedMask = mask.GetBaked<TArchetype>();
|
BakedMask bakedMask = mask.GetBaked<TArchetype>();
|
||||||
for (int i = 0, iMax = bakedMask.IncCount; i < iMax; i++)
|
for (int i = 0, iMax = bakedMask.IncCount; i < iMax; i++)
|
||||||
{
|
{
|
||||||
int poolID = _componentIDToPoolID[bakedMask.Inc[i]];
|
int poolID = bakedMask.Inc[i];
|
||||||
if (poolID == otherPoolID || !_pools[poolID].Has(entity))
|
if (poolID == otherPoolID || !_pools[poolID].Has(entity))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -145,7 +151,7 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
for (int i = 0, iMax = bakedMask.ExcCount; i < iMax; i++)
|
for (int i = 0, iMax = bakedMask.ExcCount; i < iMax; i++)
|
||||||
{
|
{
|
||||||
int poolID = _componentIDToPoolID[bakedMask.Exc[i]];
|
int poolID = bakedMask.Exc[i];
|
||||||
if (poolID != otherPoolID && _pools[poolID].Has(entity))
|
if (poolID != otherPoolID && _pools[poolID].Has(entity))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -212,20 +218,18 @@ namespace DCFApixels.DragonECS
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region NewEntity
|
#region NewEntity
|
||||||
public Entity NewEntity()
|
public ent NewEntity()
|
||||||
{
|
{
|
||||||
int entityID = _entities.GetFree();
|
int entid = _entityDispenser.GetFree();
|
||||||
_entities.Normalize(ref _gens);
|
if(_gens.Length < entid) Array.Resize(ref _gens, _gens.Length << 1);
|
||||||
_gens[entityID]++;
|
return new ent(entid, _gens[entid]++, id);
|
||||||
|
|
||||||
return new Entity(this, entityID);
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Destroy
|
#region Destroy
|
||||||
public void Destroy()
|
public void Destroy()
|
||||||
{
|
{
|
||||||
_id = IEcsWorld.DEAD_WORLD_ID;
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -1,3 +1,6 @@
|
|||||||
Мервтый мир - значение byte 255, зарезервированный адишник мира, все что ссылается на мертвый мир считается так же мертвым.
|
Мервтый мир - значение byte 255, зарезервированный адишник мира, все что ссылается на мертвый мир считается так же мертвым.
|
||||||
|
|
||||||
DCFAECS_NO_SANITIZE_CHECKS - отвключение дополнительных проверок
|
DCFAECS_NO_SANITIZE_CHECKS - отвключение дополнительных проверок
|
||||||
|
|
||||||
|
public const int MAX_WORLDS = byte.MaxValue; //Номер последнего мира 254
|
||||||
|
public const int DEAD_WORLD_ID = byte.MaxValue; //Зарезервированный номер мира для мертвых сущьностей
|
||||||
@ -2,14 +2,12 @@
|
|||||||
{
|
{
|
||||||
public interface IEcsProcessor { }
|
public interface IEcsProcessor { }
|
||||||
|
|
||||||
public interface IEcsDoTag { }
|
public struct _PreInit { }
|
||||||
public struct _PreInit : IEcsDoTag { }
|
public struct _Init { }
|
||||||
public struct _Init : IEcsDoTag { }
|
public struct _Run { }
|
||||||
public struct _Run : IEcsDoTag { }
|
public struct _Destroy { }
|
||||||
public struct _Destroy : IEcsDoTag { }
|
public struct _PostDestroy { }
|
||||||
public struct _PostDestroy : IEcsDoTag { }
|
|
||||||
public interface IDo<TTag> : IEcsProcessor
|
public interface IDo<TTag> : IEcsProcessor
|
||||||
where TTag : IEcsDoTag
|
|
||||||
{
|
{
|
||||||
public void Do(EcsSession session);
|
public void Do(EcsSession session);
|
||||||
}
|
}
|
||||||
@ -53,19 +51,4 @@
|
|||||||
{
|
{
|
||||||
public void Do(EcsSession session, in TMessage m);
|
public void Do(EcsSession session, in TMessage m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public struct _OnComponentRemoved : IEcsMessage
|
|
||||||
{
|
|
||||||
public int entityID;
|
|
||||||
}
|
|
||||||
public struct _OnComponentAdded : IEcsMessage
|
|
||||||
{
|
|
||||||
public int entityID;
|
|
||||||
}
|
|
||||||
public interface IEcsGReceive<TMessage> : IEcsProcessor
|
|
||||||
where TMessage : IEcsMessage
|
|
||||||
{
|
|
||||||
public void Do<T>(EcsSession session, in TMessage m, in T obj);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,17 +31,17 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
// но чтобы значене default было NULL сульностью, мир хранится в виде ID + 1
|
// но чтобы значене default было NULL сульностью, мир хранится в виде ID + 1
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
public ushort world
|
public short world
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => (ushort)(((_full << 48) >> 48) - 1);
|
get => (short)(((_full << 48) >> 48) - 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
public ent(int id, short gen, ushort world)
|
public ent(int id, short gen, short world)
|
||||||
{
|
{
|
||||||
_full = ((long)id) << 32;
|
_full = ((long)id) << 32;
|
||||||
_full += ((long)gen) << 16;
|
_full += ((long)gen) << 16;
|
||||||
@ -104,22 +104,83 @@ namespace DCFApixels.DragonECS
|
|||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class entExtensions
|
public static partial class entExtensions
|
||||||
{
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static bool IsNull(this in ent self)
|
public static bool IsNull(this in ent self)
|
||||||
{
|
{
|
||||||
return self == ent.NULL;
|
return self == ent.NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ref readonly T Read<T>(this in ent self)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
return ref EcsWorld.Worlds[self.world].GetPool<T>().Read(self.id);
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ref T Write<T>(this in ent self)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
return ref EcsWorld.Worlds[self.world].GetPool<T>().Write(self.id);
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool Has<T>(this in ent self)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
return EcsWorld.Worlds[self.world].GetPool<T>().Has(self.id);
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void Del<T>(this in ent self)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
EcsWorld.Worlds[self.world].GetPool<T>().Del(self.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly ref struct Entity
|
public struct Entity
|
||||||
{
|
{
|
||||||
internal readonly IEcsWorld world;
|
public IEcsWorld world;
|
||||||
internal readonly int id;
|
public int id;
|
||||||
public Entity(IEcsWorld world, ent id)
|
|
||||||
|
public Entity(IEcsWorld world, int id)
|
||||||
{
|
{
|
||||||
this.world = world;
|
this.world = world;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static partial class EntityExtensions
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool IsNull(this in Entity self)
|
||||||
|
{
|
||||||
|
return self.world == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ref readonly T Read<T>(this in Entity self)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
return ref self.world.GetPool<T>().Read(self.id);
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static ref T Write<T>(this in Entity self)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
return ref self.world.GetPool<T>().Write(self.id);
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool Has<T>(this in Entity self)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
return self.world.GetPool<T>().Has(self.id);
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void Del<T>(this in Entity self)
|
||||||
|
where T : struct
|
||||||
|
{
|
||||||
|
self.world.GetPool<T>().Del(self.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,41 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
|
||||||
{
|
|
||||||
public class EcsProcessorsGMessenger<TMessage> : IEcsProcessorsMessenger<TMessage>, IDisposable
|
|
||||||
where TMessage : IEcsMessage
|
|
||||||
{
|
|
||||||
private readonly EcsSession _source;
|
|
||||||
private readonly IEcsGReceive<TMessage>[] _targets;
|
|
||||||
|
|
||||||
public EcsSession Source => _source;
|
|
||||||
public IReadOnlyList<IEcsGReceive<TMessage>> Targets => _targets;
|
|
||||||
|
|
||||||
internal EcsProcessorsGMessenger(EcsSession source)
|
|
||||||
{
|
|
||||||
_source = source;
|
|
||||||
List<IEcsGReceive<TMessage>> list = new List<IEcsGReceive<TMessage>>();
|
|
||||||
|
|
||||||
foreach (var item in _source.AllProcessors)
|
|
||||||
{
|
|
||||||
if (item is IEcsGReceive<TMessage> targetItem)
|
|
||||||
{
|
|
||||||
list.Add(targetItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_targets = list.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Send<T>(in TMessage message, in T obj)
|
|
||||||
{
|
|
||||||
foreach (var item in _targets)
|
|
||||||
{
|
|
||||||
item.Do(_source, in message, in obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Destroy() => _source.OnMessengerDetroyed(this);
|
|
||||||
void IDisposable.Dispose() => Destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -32,6 +32,10 @@ namespace DCFApixels.DragonECS
|
|||||||
_targets = list.ToArray();
|
_targets = list.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Send(TMessage message)
|
||||||
|
{
|
||||||
|
Send(in message);
|
||||||
|
}
|
||||||
public void Send(in TMessage message)
|
public void Send(in TMessage message)
|
||||||
{
|
{
|
||||||
foreach (var item in _targets)
|
foreach (var item in _targets)
|
||||||
|
|||||||
@ -9,7 +9,6 @@ namespace DCFApixels.DragonECS
|
|||||||
public void Run();
|
public void Run();
|
||||||
}
|
}
|
||||||
public class EcsProcessorsRunner<TDoTag> : IEcsProcessorsRunner, IDisposable
|
public class EcsProcessorsRunner<TDoTag> : IEcsProcessorsRunner, IDisposable
|
||||||
where TDoTag : IEcsDoTag
|
|
||||||
{
|
{
|
||||||
private readonly EcsSession _source;
|
private readonly EcsSession _source;
|
||||||
private readonly IDo<TDoTag>[] _targets;
|
private readonly IDo<TDoTag>[] _targets;
|
||||||
|
|||||||
126
src/React/RunnerHandler.cs
Normal file
126
src/React/RunnerHandler.cs
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace DCFApixels.DragonECS
|
||||||
|
{
|
||||||
|
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
|
||||||
|
sealed class RunnerFilterAttribute : Attribute
|
||||||
|
{
|
||||||
|
public readonly Type interfaceType;
|
||||||
|
public readonly object filter;
|
||||||
|
public RunnerFilterAttribute(Type interfaceType, object filter)
|
||||||
|
{
|
||||||
|
this.interfaceType = interfaceType;
|
||||||
|
this.filter = filter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IProcessor { }
|
||||||
|
|
||||||
|
public static class IProcessorExtensions
|
||||||
|
{
|
||||||
|
public static bool IsRunner(this IProcessor self)
|
||||||
|
{
|
||||||
|
return self is IRunner;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class RunnerActivator
|
||||||
|
{
|
||||||
|
private static bool _isInit = false;
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void Init()
|
||||||
|
{
|
||||||
|
if (_isInit) return;
|
||||||
|
Type targetType = typeof(Runner<>);
|
||||||
|
var subclasses = Assembly.GetAssembly(targetType).GetTypes().Where(type => type.BaseType != null && type.BaseType.IsGenericType && targetType == type.BaseType.GetGenericTypeDefinition());
|
||||||
|
foreach (var item in subclasses)
|
||||||
|
{
|
||||||
|
item.BaseType.GetMethod("Init", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] { item });
|
||||||
|
}
|
||||||
|
_isInit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IRunner { }
|
||||||
|
|
||||||
|
public abstract class Runner<TInterface> : IProcessor, IRunner
|
||||||
|
where TInterface : IProcessor
|
||||||
|
{
|
||||||
|
internal static void Init(Type subclass)
|
||||||
|
{
|
||||||
|
|
||||||
|
#if DEBUG || DCFAECS_NO_SANITIZE_CHECKS
|
||||||
|
if (_subclass != null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The Runner<{typeof(TInterface).FullName}> can only have one subclass");
|
||||||
|
}
|
||||||
|
|
||||||
|
Type interfaceType = typeof(TInterface);
|
||||||
|
|
||||||
|
var interfaces = interfaceType.GetInterfaces();
|
||||||
|
if (interfaceType.IsInterface == false)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"{typeof(TInterface).FullName} is not interface");
|
||||||
|
}
|
||||||
|
if (interfaces.Length != 1 || interfaces[0] != typeof(IProcessor))
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"{typeof(TInterface).FullName} does not directly inherit the {nameof(IProcessor)} interface");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
_subclass = subclass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TInterface Instantiate(IEnumerable<IProcessor> targets, object filter)
|
||||||
|
{
|
||||||
|
Type interfaceType = typeof(TInterface);
|
||||||
|
|
||||||
|
IEnumerable<IProcessor> newTargets;
|
||||||
|
|
||||||
|
if (filter != null)
|
||||||
|
{
|
||||||
|
newTargets = targets.Where(o =>
|
||||||
|
{
|
||||||
|
if (o is TInterface == false) return false;
|
||||||
|
var atr = o.GetType().GetCustomAttribute<RunnerFilterAttribute>();
|
||||||
|
return atr != null && atr.interfaceType == interfaceType && atr.filter.Equals(filter);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newTargets = targets.Where(o =>
|
||||||
|
{
|
||||||
|
if (o is TInterface == false) return false;
|
||||||
|
var atr = o.GetType().GetCustomAttribute<RunnerFilterAttribute>();
|
||||||
|
return atr == null || atr.interfaceType == interfaceType && atr.filter == null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Instantiate(newTargets.Select(o => (TInterface)o).ToArray());
|
||||||
|
}
|
||||||
|
public static TInterface Instantiate(IEnumerable<IProcessor> targets)
|
||||||
|
{
|
||||||
|
return Instantiate(targets.Where(o => o is TInterface).Select(o => (TInterface)o).ToArray());
|
||||||
|
}
|
||||||
|
internal static TInterface Instantiate(TInterface[] targets)
|
||||||
|
{
|
||||||
|
RunnerActivator.Init();
|
||||||
|
var instance = (Runner<TInterface>)Activator.CreateInstance(_subclass);
|
||||||
|
return (TInterface)(IProcessor)instance.Set(targets);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static Type _subclass;
|
||||||
|
protected TInterface[] targets;
|
||||||
|
|
||||||
|
private Runner<TInterface> Set(TInterface[] targets)
|
||||||
|
{
|
||||||
|
this.targets = targets;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: d340db685521a624792157f350923088
|
guid: ae6eb3472cd282b46b26ab9f1e97ec81
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
44
src/Utils/IntDispenser.cs
Normal file
44
src/Utils/IntDispenser.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace DCFApixels.DragonECS
|
||||||
|
{
|
||||||
|
internal sealed class IntDispenser
|
||||||
|
{
|
||||||
|
private readonly ConcurrentStack<int> _freeInts;
|
||||||
|
private int _increment;
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
public int LastInt => _increment;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructor
|
||||||
|
public IntDispenser()
|
||||||
|
{
|
||||||
|
_freeInts = new ConcurrentStack<int>();
|
||||||
|
_increment = 0;
|
||||||
|
}
|
||||||
|
public IntDispenser(int startIncrement)
|
||||||
|
{
|
||||||
|
_freeInts = new ConcurrentStack<int>();
|
||||||
|
_increment = startIncrement;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region GetFree/Release
|
||||||
|
public int GetFree()
|
||||||
|
{
|
||||||
|
if (!_freeInts.TryPop(out int result))
|
||||||
|
{
|
||||||
|
result = Interlocked.Increment(ref _increment);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Release(int released)
|
||||||
|
{
|
||||||
|
_freeInts.Push(released);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: db219c3a9acc0964f8808af51e32afc3
|
guid: a20cbd833c35ff3438f9fe003903c0c3
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@ -3,115 +3,124 @@ using System.Collections;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using coretype = System.Int32;
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
public class SparseSet : IEnumerable<coretype>, ICollection<coretype>, IReadOnlyCollection<coretype>
|
public class SparseSet : IEnumerable<int>, ICollection<int>, IReadOnlyCollection<int>
|
||||||
{
|
{
|
||||||
public const int DEFAULT_CAPACITY = 16;
|
public const int DEFAULT_DENSE_CAPACITY = 8;
|
||||||
public const int MAX_CAPACITY = coretype.MaxValue;
|
public const int DEFAULT_SPARSE_CAPACITY = 16;
|
||||||
|
|
||||||
private coretype[] _dense;
|
public const int MIN_CAPACITY = 4;
|
||||||
private coretype[] _sparse;
|
|
||||||
|
|
||||||
private coretype _count;
|
public const int MAX_CAPACITY = int.MaxValue;
|
||||||
|
|
||||||
private coretype _denseCapacity;
|
private int[] _dense;
|
||||||
|
private int[] _sparse;
|
||||||
|
|
||||||
|
private int _count;
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
public int Count => _count;
|
public int Count
|
||||||
public int CapacityDense
|
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => _denseCapacity;
|
get => _count;
|
||||||
}
|
}
|
||||||
public int CapacitySparse
|
public int CapacityDense
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => _dense.Length;
|
get => _dense.Length;
|
||||||
}
|
}
|
||||||
|
public int CapacitySparse
|
||||||
public coretype this[int index]
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => _sparse.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int this[int index]
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
#if DEBUG
|
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
ThrowHalper.CheckOutOfRange(this, (coretype)index);
|
#if DEBUG
|
||||||
|
ThrowHalper.CheckOutOfRange(this, index);
|
||||||
|
#endif
|
||||||
return _dense[index];
|
return _dense[index];
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
get => _dense[index];
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
public SparseSet() : this(DEFAULT_CAPACITY) { }
|
public SparseSet() : this(DEFAULT_DENSE_CAPACITY, DEFAULT_SPARSE_CAPACITY) { }
|
||||||
public SparseSet(coretype capacity)
|
public SparseSet(int denseCapacity, int sparseCapacity)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
denseCapacity = denseCapacity < MIN_CAPACITY ? MIN_CAPACITY : NormalizeCapacity(denseCapacity);
|
||||||
ThrowHalper.CheckCapacity(capacity);
|
sparseCapacity = sparseCapacity < MIN_CAPACITY ? MIN_CAPACITY : NormalizeCapacity(sparseCapacity);
|
||||||
#endif
|
|
||||||
_dense = new coretype[capacity];
|
_dense = new int[denseCapacity];
|
||||||
_sparse = new coretype[capacity];
|
_sparse = new int[sparseCapacity];
|
||||||
for (coretype i = 0; i < _sparse.Length; i++)
|
|
||||||
{
|
Reset();
|
||||||
_dense[i] = i;
|
|
||||||
_sparse[i] = i;
|
|
||||||
}
|
|
||||||
_count = 0;
|
|
||||||
_denseCapacity = 0;
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Add/AddRange/GetFree
|
#region Add/AddRange
|
||||||
public void Add<T>(coretype value, ref T[] normalizedArray)
|
public void Add<T>(int value, ref T[] normalizedArray)
|
||||||
{
|
{
|
||||||
Add(value);
|
Add(value);
|
||||||
Normalize(ref normalizedArray);
|
Normalize(ref normalizedArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
public void Add(int value)
|
||||||
public void Add(coretype value)
|
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
ThrowHalper.CheckValueIsPositive(value);
|
ThrowHalper.CheckValueIsPositive(value);
|
||||||
ThrowHalper.CheckValueNotContained(this, value);
|
ThrowHalper.CheckValueNotContained(this, value);
|
||||||
#endif
|
#endif
|
||||||
if (value > CapacitySparse)
|
if (_count >= _dense.Length)
|
||||||
|
Array.Resize(ref _dense, _dense.Length << 1);
|
||||||
|
|
||||||
|
if (value > _sparse.Length)
|
||||||
{
|
{
|
||||||
coretype neadedSpace = (coretype)_dense.Length;
|
int neadedSpace = _sparse.Length;
|
||||||
while (value >= neadedSpace) neadedSpace <<= 1;
|
while (value >= neadedSpace)
|
||||||
Resize(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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Swap(value, _count++);
|
_dense[_count] = value;
|
||||||
if (_count > _denseCapacity) _denseCapacity <<= 1;
|
_sparse[value] = _count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryAdd<T>(coretype value, ref T[] normalizedArray)
|
public bool TryAdd<T>(int value, ref T[] normalizedArray)
|
||||||
{
|
{
|
||||||
if (Contains(value)) return false;
|
if (Contains(value)) return false;
|
||||||
Add(value);
|
Add(value);
|
||||||
Normalize(ref normalizedArray);
|
Normalize(ref normalizedArray);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
public bool TryAdd(int value)
|
||||||
public bool TryAdd(coretype value)
|
|
||||||
{
|
{
|
||||||
if (Contains(value)) return false;
|
if (Contains(value)) return false;
|
||||||
Add(value);
|
Add(value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddRange<T>(IEnumerable<coretype> range, ref T[] normalizedArray)
|
public void AddRange<T>(IEnumerable<int> range, ref T[] normalizedArray)
|
||||||
{
|
{
|
||||||
AddRange(range);
|
AddRange(range);
|
||||||
Normalize(ref normalizedArray);
|
Normalize(ref normalizedArray);
|
||||||
}
|
}
|
||||||
public void AddRange(IEnumerable<coretype> range)
|
public void AddRange(IEnumerable<int> range)
|
||||||
{
|
{
|
||||||
foreach (var item in range)
|
foreach (var item in range)
|
||||||
{
|
{
|
||||||
@ -119,46 +128,28 @@ namespace DCFApixels.DragonECS
|
|||||||
Add(item);
|
Add(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Adds a value between 0 and Capacity to the array and returns it.</summary>
|
|
||||||
/// <returns>Value between 0 and Capacity</returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public coretype GetFree<T>(ref T[] normalizedArray)
|
|
||||||
{
|
|
||||||
coretype result = GetFree();
|
|
||||||
Normalize(ref normalizedArray);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
/// <summary>Adds a value between 0 and Capacity to the array and returns it.</summary>
|
|
||||||
/// <returns>Value between 0 and Capacity</returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public coretype GetFree()
|
|
||||||
{
|
|
||||||
if (++_count >= CapacitySparse) AddSpaces();
|
|
||||||
if (_count > _denseCapacity) _denseCapacity <<= 1;
|
|
||||||
return _dense[_count - 1];
|
|
||||||
}
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Contains
|
#region Contains
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Contains(coretype value)
|
public bool Contains(int value)
|
||||||
{
|
{
|
||||||
return value >= 0 && value < CapacitySparse && _sparse[value] < _count;
|
return value >= 0 && value < CapacitySparse && _sparse[value] >= 0;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Remove
|
#region Remove
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
public void Remove(int value)
|
||||||
public void Remove(coretype value)
|
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
ThrowHalper.CheckValueContained(this, value);
|
ThrowHalper.CheckValueContained(this, value);
|
||||||
#endif
|
#endif
|
||||||
Swap(_sparse[value], --_count);
|
_dense[_sparse[value]] = _dense[--_count];
|
||||||
|
_sparse[_dense[_count]] = _sparse[value];
|
||||||
|
_sparse[value] = -1;
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool TryRemove(coretype value)
|
public bool TryRemove(int value)
|
||||||
{
|
{
|
||||||
if (!Contains(value)) return false;
|
if (!Contains(value)) return false;
|
||||||
Remove(value);
|
Remove(value);
|
||||||
@ -166,7 +157,7 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void RemoveAt(coretype index)
|
public void RemoveAt(int index)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
ThrowHalper.CheckOutOfRange(this, index);
|
ThrowHalper.CheckOutOfRange(this, index);
|
||||||
@ -183,7 +174,7 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public int IndexOf(coretype value)
|
public int IndexOf(int value)
|
||||||
{
|
{
|
||||||
if (value < 0 || !Contains(value)) return -1;
|
if (value < 0 || !Contains(value)) return -1;
|
||||||
return _sparse[value];
|
return _sparse[value];
|
||||||
@ -191,8 +182,8 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
public void Sort()
|
public void Sort()
|
||||||
{
|
{
|
||||||
coretype increment = 0;
|
int increment = 0;
|
||||||
for (coretype i = 0; i < CapacitySparse; i++)
|
for (int i = 0; i < CapacitySparse; i++)
|
||||||
{
|
{
|
||||||
if (_sparse[i] < _count)
|
if (_sparse[i] < _count)
|
||||||
{
|
{
|
||||||
@ -204,18 +195,17 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
public void HardSort()
|
public void HardSort()
|
||||||
{
|
{
|
||||||
coretype inc = 0;
|
int inc = 0;
|
||||||
coretype inc2 = _count;
|
int inc2 = _count;
|
||||||
for (coretype i = 0; i < CapacitySparse; i++)
|
for (int i = 0; i < CapacitySparse; i++)
|
||||||
{
|
{
|
||||||
if (_sparse[i] < _count)
|
if (_sparse[i] >= 0)
|
||||||
{
|
{
|
||||||
_sparse[i] = inc;
|
_sparse[i] = inc;
|
||||||
_dense[inc++] = i;
|
_dense[inc++] = i;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_sparse[i] = inc2;
|
|
||||||
_dense[inc2++] = i;
|
_dense[inc2++] = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -225,14 +215,14 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
other._count = _count;
|
other._count = _count;
|
||||||
if (CapacitySparse != other.CapacitySparse)
|
if (CapacitySparse != other.CapacitySparse)
|
||||||
{
|
Array.Resize(ref other._sparse, CapacitySparse);
|
||||||
other.Resize(CapacitySparse);
|
if (CapacityDense != other.CapacityDense)
|
||||||
}
|
Array.Resize(ref other._dense, CapacityDense);
|
||||||
_dense.CopyTo(other._dense, 0);
|
|
||||||
_sparse.CopyTo(other._sparse, 0);
|
_sparse.CopyTo(other._sparse, 0);
|
||||||
|
_dense.CopyTo(other._dense, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CopyTo(coretype[] array, int arrayIndex)
|
public void CopyTo(int[] array, int arrayIndex)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (arrayIndex < 0) throw new ArgumentException("arrayIndex is less than 0");
|
if (arrayIndex < 0) throw new ArgumentException("arrayIndex is less than 0");
|
||||||
@ -243,6 +233,12 @@ namespace DCFApixels.DragonECS
|
|||||||
array[arrayIndex] = this[i];
|
array[arrayIndex] = this[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private int NormalizeCapacity(int value)
|
||||||
|
{
|
||||||
|
return value + (MIN_CAPACITY - (value % MIN_CAPACITY));
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Clear/Reset
|
#region Clear/Reset
|
||||||
@ -251,52 +247,26 @@ namespace DCFApixels.DragonECS
|
|||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
for (coretype i = 0; i < _dense.Length; i++)
|
//loop unwinding
|
||||||
|
for (int i = 0; i < _sparse.Length;)
|
||||||
{
|
{
|
||||||
_dense[i] = i;
|
_sparse[i++] = -1;
|
||||||
_sparse[i] = i;
|
_sparse[i++] = -1;
|
||||||
|
_sparse[i++] = -1;
|
||||||
|
_sparse[i++] = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void Reset(coretype newCapacity)
|
|
||||||
|
public void Reset(int newDenseCapacity, int newSparseCapacity)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
newDenseCapacity = newDenseCapacity < MIN_CAPACITY ? MIN_CAPACITY : NormalizeCapacity(newDenseCapacity);
|
||||||
ThrowHalper.CheckCapacity(newCapacity);
|
newSparseCapacity = newSparseCapacity < MIN_CAPACITY ? MIN_CAPACITY : NormalizeCapacity(newSparseCapacity);
|
||||||
#endif
|
|
||||||
|
if (CapacitySparse != newSparseCapacity)
|
||||||
|
Array.Resize(ref _sparse, newSparseCapacity);
|
||||||
|
if (CapacityDense != newDenseCapacity)
|
||||||
|
Array.Resize(ref _dense, newDenseCapacity);
|
||||||
Reset();
|
Reset();
|
||||||
Resize(newCapacity);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region AddSpace/Resize
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private void AddSpaces() => Resize((_count << 1));
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private void Resize(int newSpace)
|
|
||||||
{
|
|
||||||
coretype oldspace = (short)_dense.Length;
|
|
||||||
Array.Resize(ref _dense, newSpace);
|
|
||||||
Array.Resize(ref _sparse, newSpace);
|
|
||||||
|
|
||||||
for (coretype i = oldspace; i < newSpace; i++)
|
|
||||||
{
|
|
||||||
_dense[i] = i;
|
|
||||||
_sparse[i] = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Swap
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private void Swap(coretype fromIndex, coretype toIndex)
|
|
||||||
{
|
|
||||||
coretype value = _dense[toIndex];
|
|
||||||
coretype oldValue = _dense[fromIndex];
|
|
||||||
|
|
||||||
_dense[toIndex] = oldValue;
|
|
||||||
_dense[fromIndex] = value;
|
|
||||||
_sparse[_dense[fromIndex]] = fromIndex;
|
|
||||||
_sparse[_dense[toIndex]] = toIndex;
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -306,19 +276,19 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
public ref struct RefEnumerator
|
public ref struct RefEnumerator
|
||||||
{
|
{
|
||||||
private readonly coretype[] _dense;
|
private readonly int[] _dense;
|
||||||
private readonly coretype _count;
|
private readonly int _count;
|
||||||
private coretype _index;
|
private int _index;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public RefEnumerator(coretype[] values, coretype count)
|
public RefEnumerator(int[] values, int count)
|
||||||
{
|
{
|
||||||
_dense = values;
|
_dense = values;
|
||||||
_count = count;
|
_count = count;
|
||||||
_index = -1;
|
_index = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public coretype Current
|
public int Current
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => _dense[_index];
|
get => _dense[_index];
|
||||||
@ -334,20 +304,20 @@ namespace DCFApixels.DragonECS
|
|||||||
public void Reset() => _index = -1;
|
public void Reset() => _index = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerator<coretype> IEnumerable<coretype>.GetEnumerator() => new Enumerator(_dense, _count);
|
IEnumerator<int> IEnumerable<int>.GetEnumerator() => new Enumerator(_dense, _count);
|
||||||
IEnumerator IEnumerable.GetEnumerator() => new Enumerator(_dense, _count);
|
IEnumerator IEnumerable.GetEnumerator() => new Enumerator(_dense, _count);
|
||||||
public struct Enumerator : IEnumerator<coretype> //to implement the IEnumerable interface and use the ref structure, 2 Enumerators were created.
|
public struct Enumerator : IEnumerator<int> //to implement the IEnumerable interface and use the ref structure, 2 Enumerators were created.
|
||||||
{
|
{
|
||||||
private readonly coretype[] _dense;
|
private readonly int[] _dense;
|
||||||
private readonly coretype _count;
|
private readonly int _count;
|
||||||
private coretype _index;
|
private int _index;
|
||||||
public Enumerator(coretype[] values, coretype count)
|
public Enumerator(int[] values, int count)
|
||||||
{
|
{
|
||||||
_dense = values;
|
_dense = values;
|
||||||
_count = count;
|
_count = count;
|
||||||
_index = -1;
|
_index = -1;
|
||||||
}
|
}
|
||||||
public coretype Current => _dense[_index];
|
public int Current => _dense[_index];
|
||||||
object IEnumerator.Current => _dense[_index];
|
object IEnumerator.Current => _dense[_index];
|
||||||
public void Dispose() { }
|
public void Dispose() { }
|
||||||
public bool MoveNext() => ++_index < _count;
|
public bool MoveNext() => ++_index < _count;
|
||||||
@ -356,16 +326,16 @@ namespace DCFApixels.DragonECS
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region ICollection
|
#region ICollection
|
||||||
bool ICollection<coretype>.IsReadOnly => false;
|
bool ICollection<int>.IsReadOnly => false;
|
||||||
|
|
||||||
bool ICollection<coretype>.Remove(coretype value) => TryRemove(value);
|
bool ICollection<int>.Remove(int value) => TryRemove(value);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Debug
|
#region Debug
|
||||||
public string Log()
|
public string Log()
|
||||||
{
|
{
|
||||||
StringBuilder logbuild = new StringBuilder();
|
StringBuilder logbuild = new StringBuilder();
|
||||||
for (int i = 0; i < CapacitySparse; i++)
|
for (int i = 0; i < CapacityDense; i++)
|
||||||
{
|
{
|
||||||
logbuild.Append(_dense[i] + ", ");
|
logbuild.Append(_dense[i] + ", ");
|
||||||
}
|
}
|
||||||
@ -376,14 +346,14 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
logbuild.Append("\n\r --------------------------");
|
logbuild.Append("\n\r --------------------------");
|
||||||
logbuild.Append("\n\r");
|
logbuild.Append("\n\r");
|
||||||
for (int i = 0; i < CapacitySparse; i++)
|
for (int i = 0; i < CapacityDense; i++)
|
||||||
{
|
{
|
||||||
logbuild.Append((i < _count ? _dense[i].ToString() : "_") + ", ");
|
logbuild.Append((i < _count ? _dense[i].ToString() : "_") + ", ");
|
||||||
}
|
}
|
||||||
logbuild.Append("\n\r");
|
logbuild.Append("\n\r");
|
||||||
for (int i = 0; i < CapacitySparse; i++)
|
for (int i = 0; i < CapacitySparse; i++)
|
||||||
{
|
{
|
||||||
logbuild.Append((_sparse[i] < _count ? _sparse[i].ToString() : "_") + ", ");
|
logbuild.Append((_sparse[i] >= 0 ? _sparse[i].ToString() : "_") + ", ");
|
||||||
}
|
}
|
||||||
logbuild.Append("\n\r Count: " + _count);
|
logbuild.Append("\n\r Count: " + _count);
|
||||||
logbuild.Append("\n\r Capacity: " + CapacitySparse);
|
logbuild.Append("\n\r Capacity: " + CapacitySparse);
|
||||||
@ -396,7 +366,7 @@ namespace DCFApixels.DragonECS
|
|||||||
public bool IsValide_Debug()
|
public bool IsValide_Debug()
|
||||||
{
|
{
|
||||||
bool isPass = true;
|
bool isPass = true;
|
||||||
for (int index = 0; index < CapacitySparse; index++)
|
for (int index = 0; index < _count; index++)
|
||||||
{
|
{
|
||||||
int value = _dense[index];
|
int value = _dense[index];
|
||||||
isPass = isPass && _sparse[value] == index;
|
isPass = isPass && _sparse[value] == index;
|
||||||
@ -407,27 +377,27 @@ namespace DCFApixels.DragonECS
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
private static class ThrowHalper
|
private static class ThrowHalper
|
||||||
{
|
{
|
||||||
public static void CheckCapacity(coretype capacity)
|
public static void CheckCapacity(int capacity)
|
||||||
{
|
{
|
||||||
if (capacity < 0)
|
if (capacity < 0)
|
||||||
throw new ArgumentException("Capacity cannot be a negative number");
|
throw new ArgumentException("Capacity cannot be a negative number");
|
||||||
}
|
}
|
||||||
public static void CheckValueIsPositive(coretype value)
|
public static void CheckValueIsPositive(int value)
|
||||||
{
|
{
|
||||||
if (value < 0)
|
if (value < 0)
|
||||||
throw new ArgumentException("The SparseSet can only contain positive numbers");
|
throw new ArgumentException("The SparseSet can only contain positive numbers");
|
||||||
}
|
}
|
||||||
public static void CheckValueContained(SparseSet source, coretype value)
|
public static void CheckValueContained(SparseSet source, int value)
|
||||||
{
|
{
|
||||||
if (!source.Contains(value))
|
if (!source.Contains(value))
|
||||||
throw new ArgumentException($"Value {value} is not contained");
|
throw new ArgumentException($"Value {value} is not contained");
|
||||||
}
|
}
|
||||||
public static void CheckValueNotContained(SparseSet source, coretype value)
|
public static void CheckValueNotContained(SparseSet source, int value)
|
||||||
{
|
{
|
||||||
if (source.Contains(value))
|
if (source.Contains(value))
|
||||||
throw new ArgumentException($"Value {value} is already contained");
|
throw new ArgumentException($"Value {value} is already contained");
|
||||||
}
|
}
|
||||||
public static void CheckOutOfRange(SparseSet source, coretype index)
|
public static void CheckOutOfRange(SparseSet source, int index)
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= source.Count)
|
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.");
|
throw new ArgumentOutOfRangeException($"Index {index} was out of range. Must be non-negative and less than the size of the collection.");
|
||||||
|
|||||||
@ -14,7 +14,6 @@ namespace DCFApixels.DragonECS
|
|||||||
private void Start()
|
private void Start()
|
||||||
{
|
{
|
||||||
_ecsSession
|
_ecsSession
|
||||||
.AddWorld("")
|
|
||||||
.Add(new TestSystem())
|
.Add(new TestSystem())
|
||||||
.Inject(_data)
|
.Inject(_data)
|
||||||
.Init();
|
.Init();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user