rework identifier implementation

This commit is contained in:
Mikhail 2023-04-08 05:50:44 +08:00
parent 1ed1782e4a
commit b5f134845d
10 changed files with 205 additions and 145 deletions

View File

@ -38,23 +38,23 @@
public interface IEcsEntityCreate : IEcsSystem
{
public void OnEntityCreate(ent entity);
public void OnEntityCreate(EcsEntity entity);
}
public interface IEcsEntityDestroy : IEcsSystem
{
public void OnEntityDestroy(ent entity);
public void OnEntityDestroy(EcsEntity entity);
}
public interface IEcsEntityLifecycle : IEcsEntityCreate, IEcsEntityDestroy { }
public sealed class EcsEntityCreateRunner : EcsRunner<IEcsEntityCreate>, IEcsEntityCreate
{
public void OnEntityCreate(ent entity)
public void OnEntityCreate(EcsEntity entity)
{
foreach (var item in targets) item.OnEntityCreate(entity);
}
}
public sealed class EcsEntityDestroyRunner : EcsRunner<IEcsEntityDestroy>, IEcsEntityDestroy
{
public void OnEntityDestroy(ent entity)
public void OnEntityDestroy(EcsEntity entity)
{
foreach (var item in targets) item.OnEntityDestroy(entity);
}

View File

@ -5,8 +5,6 @@ using delayedOp = System.Int32;
namespace DCFApixels.DragonECS
{
[StructLayout(LayoutKind.Sequential, Pack = 0, Size = 8)]
public readonly ref struct EcsReadonlyGroup
{
@ -232,9 +230,9 @@ namespace DCFApixels.DragonECS
{
delayedOp op = _delayedOps[i];
if (op >= 0) //delayedOp.IsAdded
UncheckedAdd(op & int.MaxValue); //delayedOp.Entity
UncheckedAdd(op & int.MaxValue); //delayedOp.EcsEntity
else
UncheckedRemove(op & int.MaxValue); //delayedOp.Entity
UncheckedRemove(op & int.MaxValue); //delayedOp.EcsEntity
}
}
}
@ -266,7 +264,7 @@ namespace DCFApixels.DragonECS
public ent Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _source.World.GetEntity(_dense[_index]);
get => new ent(_dense[_index]);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext() => ++_index <= _count && _count<_dense.Length; // <= потму что отсчет начинается с индекса 1 //_count < _dense.Length дает среде понять что проверки на выход за границы не нужны

View File

@ -8,10 +8,10 @@ namespace DCFApixels.DragonECS
public interface IEcsQueryMember<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);
public ref TComponent Write(ent entityID);
public ref readonly TComponent Read(ent entityID);
public bool Has(ent entityID);
public void Del(ent entityID);
}
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
@ -22,21 +22,13 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal inc(EcsPool<TComponent> pool) => _pool = pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref TComponent Write(ent entity) => ref _pool.Write(entity.id);
public ref TComponent Write(ent entityID) => ref _pool.Write(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref TComponent Write(int entityID) => ref _pool.Write(entityID);
public ref readonly TComponent Read(ent entityID) => ref _pool.Read(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref readonly TComponent Read(ent entity) => ref _pool.Read(entity.id);
public bool Has(ent entityID) => _pool.Has(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref readonly TComponent Read(int entityID) => ref _pool.Read(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Has(ent entity) => _pool.Has(entity.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Has(int entityID) => _pool.Has(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Del(ent entity) => _pool.Del(entity.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Del(int entityID) => _pool.Del(entityID);
public void Del(ent entityID) => _pool.Del(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override string ToString() => $"{(_pool == null ? "NULL" : _pool.World.ArchetypeType.Name)}inc<{typeof(TComponent).Name}>";
@ -52,21 +44,13 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal exc(EcsPool<TComponent> pool) => _pool = pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref TComponent Write(ent entity) => ref _pool.Write(entity.id);
public ref TComponent Write(ent entityID) => ref _pool.Write(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref TComponent Write(int entityID) => ref _pool.Write(entityID);
public ref readonly TComponent Read(ent entityID) => ref _pool.Read(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref readonly TComponent Read(ent entity) => ref _pool.Read(entity.id);
public bool Has(ent entityID) => _pool.Has(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref readonly TComponent Read(int entityID) => ref _pool.Read(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Has(ent entity) => _pool.Has(entity.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Has(int entityID) => _pool.Has(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Del(ent entity) => _pool.Del(entity.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Del(int entityID) => _pool.Del(entityID);
public void Del(ent entityID) => _pool.Del(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override string ToString() => $"{(_pool == null ? "NULL" : _pool.World.ArchetypeType.Name)}exc<{typeof(TComponent).Name}>";
@ -82,21 +66,13 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal opt(EcsPool<TComponent> pool) => _pool = pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref TComponent Write(ent entity) => ref _pool.Write(entity.id);
public ref TComponent Write(ent entityID) => ref _pool.Write(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref TComponent Write(int entityID) => ref _pool.Write(entityID);
public ref readonly TComponent Read(ent entityID) => ref _pool.Read(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref readonly TComponent Read(ent entity) => ref _pool.Read(entity.id);
public bool Has(ent entityID) => _pool.Has(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref readonly TComponent Read(int entityID) => ref _pool.Read(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Has(ent entity) => _pool.Has(entity.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Has(int entityID) => _pool.Has(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Del(ent entity) => _pool.Del(entity.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Del(int entityID) => _pool.Del(entityID);
public void Del(ent entityID) => _pool.Del(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override string ToString() => $"{(_pool == null ? "NULL" : _pool.World.ArchetypeType.Name)}opt<{typeof(TComponent).Name}>";

35
src/EcsTable.cs Normal file
View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DCFApixels.DragonECS
{
public class EcsTable
{
private IEcsPool[] _pools;
private EcsNullPool _nullPool;
private int[] _denseEntities;
private int[] _sparceEntities;
private int _entitiesCount;
private List<EcsQueryBase>[] _filtersByIncludedComponents;
private List<EcsQueryBase>[] _filtersByExcludedComponents;
private EcsQueryBase[] _queries;
private List<EcsGroup> _groups;
#region Internal Properties
public int Count => _entitiesCount;
public int Capacity => _denseEntities.Length;
#endregion
public ReadOnlySpan<IEcsPool> GetAllPools() => new ReadOnlySpan<IEcsPool>(_pools);
//public int GetComponentID<T>() => ;
}
}

View File

@ -18,10 +18,10 @@ namespace DCFApixels.DragonECS
#endregion
#region Entities
public ent NewEntity();
public void DelEntity(ent entity);
public EcsEntity NewEntity();
public void DelEntity(EcsEntity entity);
public bool EntityIsAlive(int entityID, short gen);
public ent GetEntity(int entityID);
public EcsEntity GetEntity(int entityID);
public void Destroy();
#endregion
}
@ -344,7 +344,7 @@ namespace DCFApixels.DragonECS
#endregion
#region Entity
public ent NewEntity()
public EcsEntity NewEntity()
{
int entityID = _entityDispenser.GetFree();
if (_entityDispenser.LastInt >= _denseEntities.Length)
@ -360,11 +360,11 @@ namespace DCFApixels.DragonECS
item.OnWorldResize(_gens.Length);
}
_gens[entityID] |= short.MinValue;
ent entity = new ent(entityID, _gens[entityID]++, id);
EcsEntity entity = new EcsEntity(entityID, _gens[entityID]++, id);
_entityCreate.OnEntityCreate(entity);
return entity;
}
public void DelEntity(ent entity)
public void DelEntity(EcsEntity entity)
{
_entityDispenser.Release(entity.id);
_gens[entity.id] |= short.MinValue;
@ -373,9 +373,9 @@ namespace DCFApixels.DragonECS
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ent GetEntity(int entityID)
public EcsEntity GetEntity(int entityID)
{
return new ent(entityID, _gens[entityID], id);
return new EcsEntity(entityID, _gens[entityID], id);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool EntityIsAlive(int entityID, short gen)

View File

@ -1,28 +1,18 @@
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace DCFApixels.DragonECS
{
public interface IEntityRecord : ITabelRecord
{
public bool IsSpecific { get; }
internal long Full { get; }
public short Gen { get; }
public short World { get; }
}
// uniqueID - 32 bits
// gen - 16 bits
// world - 16 bits
[StructLayout(LayoutKind.Explicit, Pack = 2, Size = 8)]
public readonly partial struct ent :
IEquatable<long>,
IEquatable<ent>,
IEntityRecord
{
public static readonly ent NULL = default;
/// <summary>Permanent relation entity identifier</summary>
[StructLayout(LayoutKind.Explicit, Pack = 2, Size = 8)]
public readonly partial struct EcsEntity : IEquatable<long>, IEquatable<EcsEntity>
{
public static readonly EcsEntity NULL = default;
// uniqueID - 32 bits
// gen - 16 bits
// world - 16 bits
[FieldOffset(0)]
internal readonly long full; //Union
[FieldOffset(3)]
@ -32,69 +22,64 @@ namespace DCFApixels.DragonECS
[FieldOffset(0)]
public readonly short world;
#region IEntityRecord
bool IEntityRecord.IsSpecific => false;
long IEntityRecord.Full => full;
int ITabelRecord.Id => id;
short IEntityRecord.Gen => gen;
short IEntityRecord.World => world;
#endregion
public ent Ent
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => new ent(id);
}
#region Constructors
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ent(int id, short gen, short world) : this()
public EcsEntity(int id, short gen, short world) : this()
{
this.id = id;
this.gen = gen;
this.world = world;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ent(long full) : this()
internal EcsEntity(long full) : this()
{
this.full = full;
}
#endregion
#region GetHashCode
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() => unchecked((int)(full)) ^ (int)(full >> 32);
#endregion
#region Equals
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj) => obj is ent other && full == other.full;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(ent other) => full == other.full;
public bool Equals(EcsEntity other) => full == other.full;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(long other) => full == other;
#endregion
#region ToString
#region Object
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override string ToString() => $"ent(uniqueID:{id} gen:{gen} world:{world})";
public override int GetHashCode() => unchecked((int)full) ^ (int)(full >> 32);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override string ToString() => $"Entity(id:{id} gen:{gen} world:{world})";
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj) => obj is EcsEntity other && full == other.full;
#endregion
#region operators
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(in ent a, in ent b) => a.full == b.full;
public static bool operator ==(in EcsEntity a, in EcsEntity b) => a.full == b.full;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(in ent a, in ent b) => a.full != b.full;
public static bool operator !=(in EcsEntity a, in EcsEntity b) => a.full != b.full;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator long(in ent a) => a.full;
public static explicit operator long(in EcsEntity a) => a.full;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator int(in ent a) => a.id;
public static explicit operator ent(in EcsEntity a) => a.Ent;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator ent(in long a) => new ent(a);
public static explicit operator EcsEntity(in long a) => new EcsEntity(a);
#endregion
}
public readonly partial struct ent
public readonly partial struct EcsEntity
{
private static EcsProfilerMarker _IsNullMarker = new EcsProfilerMarker("ent.IsNull");
private static EcsProfilerMarker _ReadMarker = new EcsProfilerMarker("ent.Read");
private static EcsProfilerMarker _WriteMarker = new EcsProfilerMarker("ent.Write");
private static EcsProfilerMarker _HasMarker = new EcsProfilerMarker("ent.Has");
private static EcsProfilerMarker _DelMarker = new EcsProfilerMarker("ent.Del");
private static EcsProfilerMarker _IsNullMarker = new EcsProfilerMarker("EcsEntity.IsNull");
private static EcsProfilerMarker _ReadMarker = new EcsProfilerMarker("EcsEntity.Read");
private static EcsProfilerMarker _WriteMarker = new EcsProfilerMarker("EcsEntity.Write");
private static EcsProfilerMarker _HasMarker = new EcsProfilerMarker("EcsEntity.Has");
private static EcsProfilerMarker _DelMarker = new EcsProfilerMarker("EcsEntity.Del");
public bool IsNull
{
@ -140,15 +125,15 @@ namespace DCFApixels.DragonECS
public static partial class entExtensions
{
private static EcsProfilerMarker _IsAliveMarker = new EcsProfilerMarker("ent.IsAlive");
private static EcsProfilerMarker _IsAliveMarker = new EcsProfilerMarker("EcsEntity.IsAlive");
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsAlive(this ref ent self)
public static bool IsAlive(this ref EcsEntity self)
{
//using (_IsAliveMarker.Auto())
//{
bool result = EcsWorld.Worlds[self.world].EntityIsAlive(self.id, self.gen);
if (!result) self = ent.NULL;
if (!result) self = EcsEntity.NULL;
return result;
//}
}

View File

@ -0,0 +1,74 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace DCFApixels.DragonECS
{
/// <summary>Permanent relation entity identifier</summary>
[StructLayout(LayoutKind.Explicit, Pack = 2, Size = 8)]
public readonly partial struct EcsRelation : IEquatable<long>, IEquatable<EcsRelation>
{
public static readonly EcsEntity NULL = default;
// uniqueID - 32 bits
// gen - 16 bits
// world - 16 bits
[FieldOffset(0)]
internal readonly long full; //Union
[FieldOffset(3)]
public readonly int id;
[FieldOffset(1)]
public readonly short rightWorld;
[FieldOffset(0)]
public readonly short leftWorld;
public ent Ent
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => new ent(id);
}
#region Constructors
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsRelation(int id, short leftWorld, short rightWorld) : this()
{
this.id = id;
this.leftWorld = leftWorld;
this.rightWorld = rightWorld;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal EcsRelation(long full) : this()
{
this.full = full;
}
#endregion
#region Equals
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(EcsRelation other) => full == other.full;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(long other) => full == other;
#endregion
#region Object
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() => unchecked((int)full) ^ (int)(full >> 32);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override string ToString() => $"Relation(id:{id} leftWorld:{leftWorld} rightWorld:{rightWorld})";
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj) => obj is EcsRelation other && full == other.full;
#endregion
#region operators
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(in EcsRelation a, in EcsRelation b) => a.full == b.full;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(in EcsRelation a, in EcsRelation b) => a.full != b.full;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator long(in EcsRelation a) => a.full;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator ent(in EcsRelation a) => a.Ent;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator EcsRelation(in long a) => new EcsRelation(a);
#endregion
}
}

28
src/Entities/ent.cs Normal file
View File

@ -0,0 +1,28 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace DCFApixels.DragonECS
{
#pragma warning disable CS0660, CS0661
/// <summary>Single frame entity identifier</summary>
[StructLayout(LayoutKind.Sequential, Pack = 4, Size = 4)]
public readonly ref partial struct ent
{
internal readonly int id;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ent(int id) => this.id = id;
public static explicit operator ent(int id) => new ent(id);
public static explicit operator int(ent entityID) => entityID.id;
public static bool operator ==(ent a, ent b) => a.id == b.id;
public static bool operator !=(ent a, ent b) => a.id != b.id;
public static bool operator ==(ent a, Null? _) => a.id == 0;
public static bool operator ==(Null? _, ent b) => b.id == 0;
public static bool operator !=(ent a, Null? _) => a.id != 0;
public static bool operator !=(Null? _, ent b) => b.id != 0;
public struct Null { }
}
}

View File

@ -2,7 +2,7 @@
{
public interface ITabelRecord
{
//TODO rename to index; Так ent по определению станет идентификатором
//TODO rename to index; Так EcsEntity по определению станет идентификатором
public int Id { get; }
}
}

View File

@ -1,36 +0,0 @@
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace DCFApixels.DragonECS.TODO
{
//TODO реализовать систему отношений.
//идея есть миры-коннекторы, они являются наборами сущьностей-отношений
//сущьности отношения, это теже сущьности но их полный идентификатор - это 32 бита - одна сущьность и 32 - другая
//айди миров левой и правой части записываются в мир-коннектор и для конвертации айди сущьности в полный идентификатор, надо взять данные из него.
//Проблема: если хранить айди мира для левой части отношения в одном месте, а для правого в другом и только раграничивать на лево и право будет проблема с тем что связи работают только в одном направлении
//в этом мире вообще не будет вестиь учет гена, потому что для отношений он не нужен
//миры коннекторы можно назвать Relations или RealtionTable
[StructLayout(LayoutKind.Sequential, Pack = 0, Size = 8)]
public readonly ref partial struct rel
{
public readonly int id;
public readonly short leftWorld;
public readonly short rightWorld;
#region Constructors
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public rel(int id, short leftWorld, short rightWorld)
{
this.id = id;
this.leftWorld = leftWorld;
this.rightWorld = rightWorld;
}
#endregion
}
}