mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2025-09-18 01:44:35 +08:00
Rework filters & pooling / optimization
This commit is contained in:
parent
467f2e07c7
commit
05aa578b96
108
src/EcsEntityArchetype.cs
Normal file
108
src/EcsEntityArchetype.cs
Normal file
@ -0,0 +1,108 @@
|
||||
using DCFApixels.DragonECS;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public abstract class EcsEntityArchetypeBuilder
|
||||
{
|
||||
public abstract inc<TComponent> Include<TComponent>() where TComponent : struct;
|
||||
public abstract exc<TComponent> Exclude<TComponent>() where TComponent : struct;
|
||||
public abstract opt<TComponent> Optional<TComponent>() where TComponent : struct;
|
||||
}
|
||||
public interface IEcsEntityArchetype
|
||||
{
|
||||
internal void AddEntity(int entityID);
|
||||
internal void RemoveEntity(int entityID);
|
||||
}
|
||||
public class EcsEntityArchetype<TWorldArchetype> : IEcsEntityArchetype
|
||||
where TWorldArchetype : EcsWorld<TWorldArchetype>
|
||||
{
|
||||
private int _id;
|
||||
internal EcsGroup group;
|
||||
|
||||
public int ID => _id;
|
||||
public EcsReadonlyGroup entities
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => group.Readonly;
|
||||
}
|
||||
|
||||
public EcsEntityArchetype(Builder b)
|
||||
{
|
||||
}
|
||||
|
||||
public EcsGroup.Enumerator GetEnumerator() => group.GetEnumerator();
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
void IEcsEntityArchetype.AddEntity(int entityID) => group.Add(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
void IEcsEntityArchetype.RemoveEntity(int entityID) => group.Remove(entityID);
|
||||
|
||||
#region Builder
|
||||
public sealed class Builder : EcsEntityArchetypeBuilder
|
||||
{
|
||||
private IEcsWorld _world;
|
||||
private List<int> _inc;
|
||||
private List<int> _exc;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal Builder(IEcsWorld world)
|
||||
{
|
||||
_world = world;
|
||||
_inc = new List<int>(8);
|
||||
_exc = new List<int>(4);
|
||||
}
|
||||
|
||||
public override inc<TComponent> Include<TComponent>() where TComponent : struct
|
||||
{
|
||||
_inc.Add(_world.GetComponentID<TComponent>());
|
||||
return new inc<TComponent>(_world.GetPool<TComponent>());
|
||||
}
|
||||
public override exc<TComponent> Exclude<TComponent>() where TComponent : struct
|
||||
{
|
||||
_exc.Add(_world.GetComponentID<TComponent>());
|
||||
return new exc<TComponent>(_world.GetPool<TComponent>());
|
||||
}
|
||||
public override opt<TComponent> Optional<TComponent>() where TComponent : struct
|
||||
{
|
||||
return new opt<TComponent>(_world.GetPool<TComponent>());
|
||||
}
|
||||
|
||||
internal void End(out EcsEntityArhetypeMask mask)
|
||||
{
|
||||
_inc.Sort();
|
||||
_exc.Sort();
|
||||
mask = new EcsEntityArhetypeMask(_world.ArchetypeType, _inc.ToArray(), _exc.ToArray());
|
||||
_world = null;
|
||||
_inc.Clear();
|
||||
_inc = null;
|
||||
_exc.Clear();
|
||||
_exc = null;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class EcsEntityArhetypeMask
|
||||
{
|
||||
internal readonly Type WorldArchetypeType;
|
||||
internal readonly int[] Inc;
|
||||
internal readonly int[] Exc;
|
||||
|
||||
public int IncCount => Inc.Length;
|
||||
public int ExcCount => Exc.Length;
|
||||
public EcsEntityArhetypeMask(Type worldArchetypeType, int[] inc, int[] exc)
|
||||
{
|
||||
WorldArchetypeType = worldArchetypeType;
|
||||
Inc = inc;
|
||||
Exc = exc;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
82
src/EcsFields.cs
Normal file
82
src/EcsFields.cs
Normal file
@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public interface IEcsFiled<TComponent>
|
||||
where TComponent : struct
|
||||
{
|
||||
public ref TComponent Write(int entityID);
|
||||
public ref readonly TComponent Read(int entityID);
|
||||
public bool Has(int entityID);
|
||||
public void Del(int entityID);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
|
||||
public readonly struct inc<TComponent> : IEcsFiled<TComponent>
|
||||
where TComponent : struct
|
||||
{
|
||||
private readonly EcsPool<TComponent> _pool;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal inc(EcsPool<TComponent> pool) => _pool = pool;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref TComponent Write(int entityID) => ref _pool.Write(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref readonly TComponent Read(int entityID) => ref _pool.Read(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Has(int entityID) => _pool.Has(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Del(int entityID) => _pool.Del(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override string ToString() => $"{(_pool == null ? "NULL" : _pool.World.ArchetypeType.Name)}inc<{typeof(TComponent).Name}>";
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static implicit operator inc<TComponent>(EcsEntityArchetypeBuilder buider) => buider.Include<TComponent>();
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
|
||||
public readonly struct exc<TComponent> : IEcsFiled<TComponent>
|
||||
where TComponent : struct
|
||||
{
|
||||
private readonly EcsPool<TComponent> _pool;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal exc(EcsPool<TComponent> pool) => _pool = pool;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref TComponent Write(int entityID) => ref _pool.Write(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref readonly TComponent Read(int entityID) => ref _pool.Read(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Has(int entityID) => _pool.Has(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Del(int entityID) => _pool.Del(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override string ToString() => $"{(_pool == null ? "NULL" : _pool.World.ArchetypeType.Name)}exc<{typeof(TComponent).Name}>";
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static implicit operator exc<TComponent>(EcsEntityArchetypeBuilder buider) => buider.Exclude<TComponent>();
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
|
||||
public readonly struct opt<TComponent> : IEcsFiled<TComponent>
|
||||
where TComponent : struct
|
||||
{
|
||||
private readonly EcsPool<TComponent> _pool;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal opt(EcsPool<TComponent> pool) => _pool = pool;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref TComponent Write(int entityID) => ref _pool.Write(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref readonly TComponent Read(int entityID) => ref _pool.Read(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Has(int entityID) => _pool.Has(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Del(int entityID) => _pool.Del(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override string ToString() => $"{(_pool == null ? "NULL" : _pool.World.ArchetypeType.Name)}opt<{typeof(TComponent).Name}>";
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static implicit operator opt<TComponent>(EcsEntityArchetypeBuilder buider) => buider.Optional<TComponent>();
|
||||
}
|
||||
}
|
@ -10,8 +10,8 @@ namespace DCFApixels.DragonECS
|
||||
public EcsFilter Relations<TComponent>() where TComponent : struct;
|
||||
rr
|
||||
}
|
||||
public sealed class EcsRelationTable<TArchetype> : IEcsRealationTable
|
||||
where TArchetype : EcsRelationTableArchetypeBase
|
||||
public sealed class EcsRelationTable<TWorldArchetype> : IEcsRealationTable
|
||||
where TWorldArchetype : EcsRelationTableArchetypeBase
|
||||
{
|
||||
public readonly IEcsWorld leftWorld;
|
||||
public readonly IEcsWorld rightWorld;
|
||||
@ -26,7 +26,7 @@ namespace DCFApixels.DragonECS
|
||||
private EcsNullPool _nullPool;
|
||||
|
||||
#region Properties
|
||||
public Type ArchetypeType => typeof(TArchetype);
|
||||
public Type ArchetypeType => typeof(TWorldArchetype);
|
||||
public int EntitesCount => _relationsCount;
|
||||
public int EntitesCapacity => _relations.Length;
|
||||
#endregion
|
||||
|
265
src/EcsTable.cs
265
src/EcsTable.cs
@ -1,265 +0,0 @@
|
||||
using DCFApixels.DragonECS;
|
||||
/*using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine.WSA;
|
||||
using static UnityEditor.Experimental.GraphView.Port;
|
||||
|
||||
namespace DCFApixels.Assets.DragonECS.src
|
||||
{
|
||||
public struct Pose { }
|
||||
public struct Health { }
|
||||
public struct Mana { }
|
||||
public struct EnemyTag { }
|
||||
|
||||
public class TestArhetype : EcsEntityArhetype<EcsDefaultWrold>
|
||||
{
|
||||
public inc<Pose> pose;
|
||||
public inc<Health> health;
|
||||
public opt<Mana> mana;
|
||||
public exc<EnemyTag> enemyTag;
|
||||
|
||||
public TestArhetype(Builder b) : base(b)
|
||||
{
|
||||
pose = b.Include<Pose>();
|
||||
health = b.Include<Health>();
|
||||
mana = b.Optional<Mana>();
|
||||
enemyTag = b.Exclude<EnemyTag>();
|
||||
}
|
||||
}
|
||||
public class TestSystem : IEcsRunSystem
|
||||
{
|
||||
private TestArhetype test;
|
||||
public void Run(EcsPipeline pipeline)
|
||||
{
|
||||
foreach (var e in test)
|
||||
{
|
||||
test.health.Read(e.id);
|
||||
test.pose.Write(e.id) = new Pose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public abstract class EcsWorldArhetype
|
||||
{
|
||||
public EcsWorldArhetype(IEcsWorld world) { }
|
||||
}
|
||||
|
||||
public interface IFakeWorld { }
|
||||
public class FakeWorld<TWorldArhetype> : IFakeWorld
|
||||
where TWorldArhetype : EcsWorldArhetype
|
||||
{
|
||||
public readonly TWorldArhetype data;
|
||||
|
||||
private EcsEntityArhetype<TWorldArhetype>[] _arhetypes;
|
||||
|
||||
|
||||
public FakeWorld()
|
||||
{
|
||||
_arhetypes = new EcsEntityArhetype<TWorldArhetype>[ArhetypeID.capacity];
|
||||
}
|
||||
|
||||
public TArhetype Arhetype<TArhetype>() where TArhetype : EcsEntityArhetype<TWorldArhetype>
|
||||
{
|
||||
int id = ArhetypeID<IEcsEntityArhetype>.id;
|
||||
if (_arhetypes.Length < ArhetypeID.capacity)
|
||||
Array.Resize(ref _arhetypes, ArhetypeID.capacity);
|
||||
|
||||
if (_arhetypes[id] == null)
|
||||
{
|
||||
EcsEntityArhetype<TWorldArhetype>.Builder builder = new EcsEntityArhetype<TWorldArhetype>.Builder(this);
|
||||
_arhetypes[id] = (TArhetype)Activator.CreateInstance(typeof(TArhetype), builder);
|
||||
builder.End();
|
||||
}
|
||||
|
||||
return (TArhetype)_arhetypes[id];
|
||||
}
|
||||
|
||||
|
||||
#region ArhetypeID
|
||||
private static class ArhetypeID
|
||||
{
|
||||
public static int count = 0;
|
||||
public static int capacity = 128;
|
||||
}
|
||||
private static class ArhetypeID<TArhetype>
|
||||
{
|
||||
public static int id;
|
||||
static ArhetypeID()
|
||||
{
|
||||
id = ArhetypeID.count++;
|
||||
if (ArhetypeID.count > ArhetypeID.capacity)
|
||||
ArhetypeID.capacity <<= 1;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
public interface IEcsEntityArhetype
|
||||
{
|
||||
internal void AddEntity(int entityID);
|
||||
internal void RemoveEntity(int entityID);
|
||||
}
|
||||
public class EcsEntityArhetype<TWorldArhetype> : IEcsEntityArhetype
|
||||
where TWorldArhetype : EcsWorldArhetype
|
||||
{
|
||||
private int _id;
|
||||
private EcsGroup _group;
|
||||
|
||||
public int ID => _id;
|
||||
public EcsReadonlyGroup entities
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _group.Readonly;
|
||||
}
|
||||
|
||||
public EcsEntityArhetype(Builder b) { }
|
||||
|
||||
public EcsGroup.Enumerator GetEnumerator() => _group.GetEnumerator();
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
void IEcsEntityArhetype.AddEntity(int entityID) => _group.Add(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
void IEcsEntityArhetype.RemoveEntity(int entityID) => _group.Remove(entityID);
|
||||
|
||||
#region Builder
|
||||
public class Builder
|
||||
{
|
||||
private IFakeWorld _world;
|
||||
private List<int> _inc;
|
||||
private List<int> _exc;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal Builder(IFakeWorld world)
|
||||
{
|
||||
_world = world;
|
||||
}
|
||||
|
||||
public inc<TComponent> Include<TComponent>() where TComponent : struct
|
||||
{
|
||||
_inc.Add(_world.GetComponentID<TComponent>());
|
||||
return new inc<TComponent>(_world.GetPool<TComponent>());
|
||||
}
|
||||
public exc<TComponent> Exclude<TComponent>() where TComponent : struct
|
||||
{
|
||||
_exc.Add(_world.GetComponentID<TComponent>());
|
||||
return new exc<TComponent>(_world.GetPool<TComponent>());
|
||||
}
|
||||
public opt<TComponent> Optional<TComponent>() where TComponent : struct
|
||||
{
|
||||
return new opt<TComponent>(_world.GetPool<TComponent>());
|
||||
}
|
||||
|
||||
internal void End(out EcsEntityArhetypeMask mask)
|
||||
{
|
||||
_inc.Sort();
|
||||
_exc.Sort();
|
||||
mask = new EcsEntityArhetypeMask(_world.ArchetypeType, _inc.ToArray(), _exc.ToArray());
|
||||
|
||||
_world = null;
|
||||
_inc.Clear();
|
||||
_inc = null;
|
||||
_exc.Clear();
|
||||
_exc = null;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
public interface IEcsFiled<TComponent>
|
||||
where TComponent : struct
|
||||
{
|
||||
public ref TComponent Write(int entityID);
|
||||
public ref readonly TComponent Read(int entityID);
|
||||
public bool Has(int entityID);
|
||||
public void Del(int entityID);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
|
||||
public readonly struct inc<TComponent> : IEcsFiled<TComponent>
|
||||
where TComponent : struct
|
||||
{
|
||||
private readonly EcsPool<TComponent> _pool;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal inc(EcsPool<TComponent> pool) => _pool = pool;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref TComponent Write(int entityID) => ref _pool.Write(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref readonly TComponent Read(int entityID) => ref _pool.Read(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Has(int entityID) => _pool.Has(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Del(int entityID) => _pool.Del(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override string ToString() => $"{(_pool == null ? "NULL" : _pool.World.ArchetypeType.Name)}inc<{typeof(TComponent).Name}>";
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
|
||||
public readonly struct exc<TComponent> : IEcsFiled<TComponent>
|
||||
where TComponent : struct
|
||||
{
|
||||
private readonly EcsPool<TComponent> _pool;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal exc(EcsPool<TComponent> pool) => _pool = pool;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref TComponent Write(int entityID) => ref _pool.Write(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref readonly TComponent Read(int entityID) => ref _pool.Read(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Has(int entityID) => _pool.Has(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Del(int entityID) => _pool.Del(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override string ToString() => $"{(_pool == null ? "NULL" : _pool.World.ArchetypeType.Name)}exc<{typeof(TComponent).Name}>";
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
|
||||
public readonly struct opt<TComponent> : IEcsFiled<TComponent>
|
||||
where TComponent : struct
|
||||
{
|
||||
private readonly EcsPool<TComponent> _pool;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal opt(EcsPool<TComponent> pool) => _pool = pool;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref TComponent Write(int entityID) => ref _pool.Write(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref readonly TComponent Read(int entityID) => ref _pool.Read(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Has(int entityID) => _pool.Has(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Del(int entityID) => _pool.Del(entityID);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override string ToString() => $"{(_pool == null ? "NULL" : _pool.World.ArchetypeType.Name)}opt<{typeof(TComponent).Name}>";
|
||||
}
|
||||
|
||||
public class EcsEntityArhetypeMask
|
||||
{
|
||||
internal readonly Type WorldArchetypeType;
|
||||
internal readonly int[] Inc;
|
||||
internal readonly int[] Exc;
|
||||
public EcsEntityArhetypeMask(Type worldArchetypeType, int[] inc, int[] exc)
|
||||
{
|
||||
WorldArchetypeType = worldArchetypeType;
|
||||
Inc = inc;
|
||||
Exc = exc;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
252
src/EcsWorld.cs
252
src/EcsWorld.cs
@ -17,7 +17,7 @@ namespace DCFApixels.DragonECS
|
||||
#endregion
|
||||
|
||||
#region Entities
|
||||
public EcsFilter Entities<TComponent>() where TComponent : struct;
|
||||
public TArhetype Entities<TArhetype>(out TArhetype entities) where TArhetype : IEcsEntityArchetype;
|
||||
|
||||
public ent NewEntity();
|
||||
public void DelEntity(ent entity);
|
||||
@ -56,8 +56,8 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class EcsWorld<TArchetype> : EcsWorld, IEcsWorld
|
||||
where TArchetype : EcsWorld<TArchetype>
|
||||
public abstract class EcsWorld<TWorldArchetype> : EcsWorld, IEcsWorld
|
||||
where TWorldArchetype : EcsWorld<TWorldArchetype>
|
||||
{
|
||||
private IntDispenser _entityDispenser;
|
||||
private int[] _denseEntities;
|
||||
@ -69,10 +69,10 @@ namespace DCFApixels.DragonECS
|
||||
private IEcsPool[] _pools;
|
||||
private EcsNullPool _nullPool;
|
||||
|
||||
private List<EcsFilter>[] _filtersByIncludedComponents;
|
||||
private List<EcsFilter>[] _filtersByExcludedComponents;
|
||||
private List<EcsGroup>[] _filtersByIncludedComponents;
|
||||
private List<EcsGroup>[] _filtersByExcludedComponents;
|
||||
|
||||
private EcsFilter[] _filters;
|
||||
private IEcsEntityArchetype[] _archetypes;
|
||||
|
||||
private EcsPipeline _pipeline;
|
||||
|
||||
@ -96,7 +96,7 @@ namespace DCFApixels.DragonECS
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
public Type ArchetypeType => typeof(TArchetype);
|
||||
public Type ArchetypeType => typeof(TWorldArchetype);
|
||||
public int ID => id;
|
||||
public EcsPipeline Pipeline => _pipeline;
|
||||
|
||||
@ -115,18 +115,18 @@ namespace DCFApixels.DragonECS
|
||||
FillArray(_pools, _nullPool);
|
||||
|
||||
_gens = new short[512];
|
||||
_filters = new EcsFilter[64];
|
||||
_archetypes = new EcsEntityArchetype<TWorldArchetype>[EntityArhetype.capacity];
|
||||
_groups = new List<EcsGroup>(128);
|
||||
|
||||
_denseEntities = new int[512];
|
||||
|
||||
_filtersByIncludedComponents = new List<EcsFilter>[16];
|
||||
_filtersByExcludedComponents = new List<EcsFilter>[16];
|
||||
_filtersByIncludedComponents = new List<EcsGroup>[16];
|
||||
_filtersByExcludedComponents = new List<EcsGroup>[16];
|
||||
|
||||
_poolRunnres = new PoolRunnres(_pipeline);
|
||||
_entityCreate = _pipeline.GetRunner<IEcsEntityCreate>();
|
||||
_entityDestry = _pipeline.GetRunner<IEcsEntityDestroy>();
|
||||
_pipeline.GetRunner<IEcsInject<TArchetype>>().Inject((TArchetype)this);
|
||||
_pipeline.GetRunner<IEcsInject<TWorldArchetype>>().Inject((TWorldArchetype)this);
|
||||
_pipeline.GetRunner<IEcsInject<IEcsWorld>>().Inject(this);
|
||||
_pipeline.GetRunner<IEcsWorldCreate>().OnWorldCreate(this);
|
||||
}
|
||||
@ -159,61 +159,70 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region GetFilter
|
||||
public EcsFilter Entities<TComponent>() where TComponent : struct => Filter<Inc<TComponent>, Exc>();
|
||||
public EcsFilter Filter<TInc>() where TInc : struct, IInc => Filter<TInc, Exc>();
|
||||
public EcsFilter Filter<TInc, TExc>() where TInc : struct, IInc where TExc : struct, IExc
|
||||
#region Entities
|
||||
public TEntityArhetype Entities<TEntityArhetype>(out TEntityArhetype entities) where TEntityArhetype : IEcsEntityArchetype
|
||||
{
|
||||
var mask = EcsMaskMap<TArchetype>.GetMask<TInc, TExc>();
|
||||
int uniqueID = EntityArhetype<TEntityArhetype>.uniqueID;
|
||||
if (_archetypes.Length < EntityArhetype.capacity)
|
||||
Array.Resize(ref _archetypes, EntityArhetype.capacity);
|
||||
|
||||
if (_filters.Length <= EcsMaskMap<TArchetype>.Capacity)
|
||||
if (_archetypes[uniqueID] == null)
|
||||
{
|
||||
Array.Resize(ref _filters, EcsMaskMap<TArchetype>.Capacity);
|
||||
}
|
||||
EcsEntityArchetype<TWorldArchetype>.Builder builder = new EcsEntityArchetype<TWorldArchetype>.Builder(this);
|
||||
_archetypes[uniqueID] = (TEntityArhetype)Activator.CreateInstance(typeof(TEntityArhetype), builder);
|
||||
builder.End(out EcsEntityArhetypeMask mask);
|
||||
|
||||
if (_filters[mask.UniqueID] == null)
|
||||
{
|
||||
_filters[mask.UniqueID] = NewFilter(mask);
|
||||
var filter = new EcsGroup(this);
|
||||
|
||||
((EcsEntityArchetype<TWorldArchetype>)_archetypes[uniqueID]).group = filter;
|
||||
|
||||
for (int i = 0; i < mask.IncCount; i++)
|
||||
{
|
||||
int componentID = mask.Inc[i];
|
||||
var list = _filtersByIncludedComponents[componentID];
|
||||
if (list == null)
|
||||
{
|
||||
list = new List<EcsGroup>(8);
|
||||
_filtersByIncludedComponents[componentID] = list;
|
||||
}
|
||||
list.Add(filter);
|
||||
}
|
||||
|
||||
for (int i = 0; i < mask.ExcCount; i++)
|
||||
{
|
||||
int componentID = mask.Exc[i];
|
||||
var list = _filtersByExcludedComponents[componentID];
|
||||
if (list == null)
|
||||
{
|
||||
list = new List<EcsGroup>(8);
|
||||
_filtersByExcludedComponents[componentID] = list;
|
||||
}
|
||||
list.Add(filter);
|
||||
}
|
||||
// scan exist entities for compatibility with new filter.
|
||||
for (int i = 0; i < _entitiesCount && _entitiesCount <= _denseEntities.Length; i++)
|
||||
{
|
||||
int entity = _denseEntities[i];
|
||||
if (IsMaskCompatible(mask.Inc, mask.Exc, entity))
|
||||
filter.Add(entity);
|
||||
}
|
||||
}
|
||||
return _filters[mask.UniqueID];
|
||||
entities = (TEntityArhetype)_archetypes[uniqueID];
|
||||
return entities;
|
||||
}
|
||||
|
||||
private EcsFilter NewFilter(EcsMask mask, int capacirty = 512)
|
||||
private bool IsMaskCompatible(int[] inc, int[] exc, int entity)
|
||||
{
|
||||
var filter = new EcsFilter(this, mask, capacirty);
|
||||
|
||||
for (int i = 0; i < mask.IncCount; i++)
|
||||
for (int i = 0, iMax = inc.Length; i < iMax; i++)
|
||||
{
|
||||
int componentID = mask.Inc[i];
|
||||
var list = _filtersByIncludedComponents[componentID];
|
||||
if (list == null)
|
||||
{
|
||||
list = new List<EcsFilter>(8);
|
||||
_filtersByIncludedComponents[componentID] = list;
|
||||
}
|
||||
list.Add(filter);
|
||||
if (!_pools[inc[i]].Has(entity))
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mask.ExcCount; i++)
|
||||
for (int i = 0, iMax = exc.Length; i < iMax; i++)
|
||||
{
|
||||
int componentID = mask.Exc[i];
|
||||
var list = _filtersByExcludedComponents[componentID];
|
||||
if (list == null)
|
||||
{
|
||||
list = new List<EcsFilter>(8);
|
||||
_filtersByExcludedComponents[componentID] = list;
|
||||
}
|
||||
list.Add(filter);
|
||||
if (_pools[exc[i]].Has(entity))
|
||||
return false;
|
||||
}
|
||||
// scan exist entities for compatibility with new filter.
|
||||
for (int i = 0; i < _entitiesCount && _entitiesCount <= _denseEntities.Length; i++)
|
||||
{
|
||||
int entity = _denseEntities[i];
|
||||
if (IsMaskCompatible(mask, entity))
|
||||
filter.Add(entity);
|
||||
}
|
||||
|
||||
return filter;
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -221,19 +230,19 @@ namespace DCFApixels.DragonECS
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool IsMaskCompatible<TInc>(int entityID) where TInc : struct, IInc
|
||||
{
|
||||
return IsMaskCompatible(EcsMaskMap<TArchetype>.GetMask<TInc, Exc>(), entityID);
|
||||
return IsMaskCompatible(EcsMaskMap<TWorldArchetype>.GetMask<TInc, Exc>(), entityID);
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool IsMaskCompatible<TInc, TExc>(int entityID) where TInc : struct, IInc where TExc : struct, IExc
|
||||
{
|
||||
return IsMaskCompatible(EcsMaskMap<TArchetype>.GetMask<TInc, TExc>(), entityID);
|
||||
return IsMaskCompatible(EcsMaskMap<TWorldArchetype>.GetMask<TInc, TExc>(), entityID);
|
||||
}
|
||||
|
||||
public bool IsMaskCompatible(EcsMask mask, int entity)
|
||||
{
|
||||
#if (DEBUG && !DISABLE_DRAGONECS_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
||||
if (mask.WorldArchetypeType != typeof(TArchetype))
|
||||
throw new EcsFrameworkException("mask.WorldArchetypeType != typeof(TArchetype)");
|
||||
if (mask.WorldArchetypeType != typeof(TWorldArchetype))
|
||||
throw new EcsFrameworkException("mask.WorldArchetypeType != typeof(TWorldArchetype)");
|
||||
#endif
|
||||
for (int i = 0, iMax = mask.IncCount; i < iMax; i++)
|
||||
{
|
||||
@ -251,8 +260,8 @@ namespace DCFApixels.DragonECS
|
||||
public bool IsMaskCompatibleWithout(EcsMask mask, int entity, int otherComponentID)
|
||||
{
|
||||
#if (DEBUG && !DISABLE_DRAGONECS_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
||||
if (mask.WorldArchetypeType != typeof(TArchetype))
|
||||
throw new EcsFrameworkException("mask.WorldArchetypeType != typeof(TArchetype)");
|
||||
if (mask.WorldArchetypeType != typeof(TWorldArchetype))
|
||||
throw new EcsFrameworkException("mask.WorldArchetypeType != typeof(TWorldArchetype)");
|
||||
#endif
|
||||
for (int i = 0, iMax = mask.IncCount; i < iMax; i++)
|
||||
{
|
||||
@ -277,30 +286,30 @@ namespace DCFApixels.DragonECS
|
||||
var includeList = _filtersByIncludedComponents[componentID];
|
||||
var excludeList = _filtersByExcludedComponents[componentID];
|
||||
|
||||
if (includeList != null)
|
||||
{
|
||||
foreach (var filter in includeList)
|
||||
{
|
||||
if (IsMaskCompatible(filter.Mask, entityID))
|
||||
{
|
||||
filter.entities.UncheckedAdd(entityID);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (excludeList != null)
|
||||
{
|
||||
foreach (var filter in excludeList)
|
||||
{
|
||||
if (IsMaskCompatibleWithout(filter.Mask, entityID, componentID))
|
||||
{
|
||||
filter.entities.UncheckedRemove(entityID);
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (includeList != null)
|
||||
// {
|
||||
// foreach (var filter in includeList)
|
||||
// {
|
||||
// if (IsMaskCompatible(filter.Mask, entityID))
|
||||
// {
|
||||
// filter.entities.UncheckedAdd(entityID);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (excludeList != null)
|
||||
// {
|
||||
// foreach (var filter in excludeList)
|
||||
// {
|
||||
// if (IsMaskCompatibleWithout(filter.Mask, entityID, componentID))
|
||||
// {
|
||||
// filter.entities.UncheckedRemove(entityID);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//TODO провести стресс тест для варианта выши и закоментированного ниже
|
||||
|
||||
// if (includeList != null) foreach (var filter in includeList) filter.entities.Add(entityID);
|
||||
// if (excludeList != null) foreach (var filter in excludeList) filter.entities.Remove(entityID);
|
||||
if (includeList != null) foreach (var filter in includeList) filter.Add(entityID);
|
||||
if (excludeList != null) foreach (var filter in excludeList) filter.Remove(entityID);
|
||||
}
|
||||
|
||||
void IEcsReadonlyTable.OnEntityComponentRemoved(int entityID, int componentID)
|
||||
@ -308,30 +317,30 @@ namespace DCFApixels.DragonECS
|
||||
var includeList = _filtersByIncludedComponents[componentID];
|
||||
var excludeList = _filtersByExcludedComponents[componentID];
|
||||
|
||||
if (includeList != null)
|
||||
{
|
||||
foreach (var filter in includeList)
|
||||
{
|
||||
if (IsMaskCompatible(filter.Mask, entityID))
|
||||
{
|
||||
filter.entities.UncheckedRemove(entityID);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (excludeList != null)
|
||||
{
|
||||
foreach (var filter in excludeList)
|
||||
{
|
||||
if (IsMaskCompatibleWithout(filter.Mask, entityID, componentID))
|
||||
{
|
||||
filter.entities.UncheckedAdd(entityID);
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (includeList != null)
|
||||
// {
|
||||
// foreach (var filter in includeList)
|
||||
// {
|
||||
// if (IsMaskCompatible(filter.Mask, entityID))
|
||||
// {
|
||||
// filter.entities.UncheckedRemove(entityID);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (excludeList != null)
|
||||
// {
|
||||
// foreach (var filter in excludeList)
|
||||
// {
|
||||
// if (IsMaskCompatibleWithout(filter.Mask, entityID, componentID))
|
||||
// {
|
||||
// filter.entities.UncheckedAdd(entityID);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//TODO провести стресс тест для варианта выши и закоментированного ниже
|
||||
|
||||
// if (includeList != null) foreach (var filter in includeList) filter.entities.Remove(entityID);
|
||||
// if (excludeList != null) foreach (var filter in excludeList) filter.entities.Add(entityID);
|
||||
if (includeList != null) foreach (var filter in includeList) filter.Remove(entityID);
|
||||
if (excludeList != null) foreach (var filter in excludeList) filter.Add(entityID);
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -386,7 +395,7 @@ namespace DCFApixels.DragonECS
|
||||
_nullPool = null;
|
||||
_filtersByIncludedComponents = null;
|
||||
_filtersByExcludedComponents = null;
|
||||
_filters = null;
|
||||
_archetypes = null;
|
||||
Realeze();
|
||||
}
|
||||
public void DestryWithPipeline()
|
||||
@ -396,7 +405,29 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Other
|
||||
void IEcsReadonlyTable.RegisterGroup(EcsGroup group)
|
||||
{
|
||||
_groups.Add(group);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Utils
|
||||
internal static class EntityArhetype
|
||||
{
|
||||
public static int increment = 0;
|
||||
public static int capacity = 128;
|
||||
}
|
||||
internal static class EntityArhetype<TArhetype>
|
||||
{
|
||||
public static int uniqueID;
|
||||
static EntityArhetype()
|
||||
{
|
||||
uniqueID = EntityArhetype.increment++;
|
||||
if (EntityArhetype.increment > EntityArhetype.capacity)
|
||||
EntityArhetype.capacity <<= 1;
|
||||
}
|
||||
}
|
||||
internal static class ComponentType
|
||||
{
|
||||
internal static int increment = 1;
|
||||
@ -416,7 +447,7 @@ namespace DCFApixels.DragonECS
|
||||
#if (DEBUG && !DISABLE_DRAGONECS_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
|
||||
if (ComponentType.increment + 1 > ushort.MaxValue)
|
||||
{
|
||||
throw new EcsFrameworkException($"No more room for new component for this {typeof(TArchetype).FullName} IWorldArchetype");
|
||||
throw new EcsFrameworkException($"No more room for new component for this {typeof(TWorldArchetype).FullName} IWorldArchetype");
|
||||
}
|
||||
#endif
|
||||
if (uniqueID >= ComponentType.types.Length)
|
||||
@ -443,13 +474,6 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Other
|
||||
void IEcsReadonlyTable.RegisterGroup(EcsGroup group)
|
||||
{
|
||||
_groups.Add(group);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 24)]
|
||||
|
@ -20,9 +20,6 @@ namespace DCFApixels.DragonECS
|
||||
public EcsPool<T> GetPool<T>() where T : struct;
|
||||
public EcsPool<T> UncheckedGetPool<T>() where T : struct;
|
||||
|
||||
public EcsFilter Filter<TInc>() where TInc : struct, IInc;
|
||||
public EcsFilter Filter<TInc, TExc>() where TInc : struct, IInc where TExc : struct, IExc;
|
||||
|
||||
public bool IsMaskCompatible<TInc>(int entity) where TInc : struct, IInc;
|
||||
public bool IsMaskCompatible<TInc, TExc>(int entity) where TInc : struct, IInc where TExc : struct, IExc;
|
||||
public bool IsMaskCompatible(EcsMask mask, int entity);
|
||||
|
@ -12,7 +12,7 @@ namespace DCFApixels.DragonECS
|
||||
public short Gen { get; }
|
||||
public short World { get; }
|
||||
}
|
||||
// id - 32 bits
|
||||
// uniqueID - 32 bits
|
||||
// gen - 16 bits
|
||||
// world - 16 bits
|
||||
[StructLayout(LayoutKind.Explicit, Pack = 2, Size = 8)]
|
||||
@ -71,7 +71,7 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
#region ToString
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override string ToString() => $"ent(id:{id} gen:{gen} world:{world})";
|
||||
public override string ToString() => $"ent(uniqueID:{id} gen:{gen} world:{world})";
|
||||
#endregion
|
||||
|
||||
#region operators
|
||||
|
Loading…
Reference in New Issue
Block a user