From e7835a39d304d20b7708fe5d64f3dccda6f0983c Mon Sep 17 00:00:00 2001
From: Mikhail <99481254+DCFApixels@users.noreply.github.com>
Date: Mon, 17 Apr 2023 22:58:52 +0800
Subject: [PATCH] fix changes
---
src/Builtin/Components.cs | 30 ++++
src/EcsGroup.cs | 46 +++----
src/EcsMask.cs | 18 +--
src/EcsPool.cs | 20 ++-
src/EcsQuery.cs | 172 ++++++++++++-----------
src/EcsQueryMember.cs | 155 +++++++++++++++------
src/EcsWorld.cs | 45 +++---
src/Entities/EcsEntity.cs | 3 +-
src/Entities/EcsRelation.cs | 74 ----------
src/Entities/ent.cs | 7 +-
src/Interfaces/IEcsReadonlyTable.cs | 2 +-
src/Utils/SparseArray.cs | 203 ++++++++++++++++++++++++++++
12 files changed, 521 insertions(+), 254 deletions(-)
create mode 100644 src/Builtin/Components.cs
delete mode 100644 src/Entities/EcsRelation.cs
create mode 100644 src/Utils/SparseArray.cs
diff --git a/src/Builtin/Components.cs b/src/Builtin/Components.cs
new file mode 100644
index 0000000..1c9d67c
--- /dev/null
+++ b/src/Builtin/Components.cs
@@ -0,0 +1,30 @@
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace DCFApixels.DragonECS
+{
+ ///
+ /// Используется для реализации отношений. traget - это сущьность к которой крепится эта сущьность. other - это сущьность с которой traget образует связь
+ ///
+ [StructLayout(LayoutKind.Explicit, Pack = 8, Size = 16)]
+ public readonly struct Attach
+ {
+ [FieldOffset(0), MarshalAs(UnmanagedType.U8)]
+ public readonly EcsEntity target;
+ [FieldOffset(1), MarshalAs(UnmanagedType.U8)]
+ public readonly EcsEntity other;
+
+ /// alias for "target"
+ public EcsEntity left
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => target;
+ }
+ /// alias for "other"
+ public EcsEntity right
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => other;
+ }
+ }
+}
diff --git a/src/EcsGroup.cs b/src/EcsGroup.cs
index ee0a76e..1097010 100644
--- a/src/EcsGroup.cs
+++ b/src/EcsGroup.cs
@@ -2,6 +2,7 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Unity.Profiling;
+using UnityEngine;
using delayedOp = System.Int32;
namespace DCFApixels.DragonECS
@@ -10,7 +11,6 @@ namespace DCFApixels.DragonECS
public readonly ref struct EcsReadonlyGroup
{
private readonly EcsGroup _source;
-
#region Constructors
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsReadonlyGroup(EcsGroup source) => _source = source;
@@ -49,11 +49,8 @@ namespace DCFApixels.DragonECS
public bool Contains(int entityID) => _source.Contains(entityID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsGroup.Enumerator GetEnumerator() => _source.GetEnumerator();
-
- /// Equivalent of the EcsGroup.Clone() method
- /// An editable clone of this EcsReadnolyGroup
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public EcsGroup Extract() => _source.Clone();
+ public EcsGroup Clone() => _source.Clone();
#endregion
#region Object
@@ -80,23 +77,10 @@ namespace DCFApixels.DragonECS
public static bool operator !=(EcsReadonlyGroup a, EcsReadonlyGroup b) => !a.Equals(b);
public static bool operator !=(EcsReadonlyGroup a, EcsGroup b) => !a.Equals(b);
#endregion
-
- #region Dispose/Release
- public void Dispose()
- {
- _source.Dispose();
- }
- public void Release()
- {
- _source.World.ReleaseGroup(_source);
- }
- #endregion
}
- // не может содержать значение 0
+ // индексация начинается с 1
// _delayedOps это int[] для отложенных операций, хранятся отложенные операции в виде int значения, если старший бит = 0 то это опреация добавленияб если = 1 то это операция вычитания
-
- // this collection can only store numbers greater than 0
public unsafe class EcsGroup : IDisposable, IEquatable
{
private const int DEALAYED_ADD = 0;
@@ -145,7 +129,8 @@ namespace DCFApixels.DragonECS
}
#endregion
- #region Constrcutors
+ #region Constrcutors/Finalizer
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsGroup New(IEcsWorld world)
{
return world.GetGroupFromPool();
@@ -164,6 +149,14 @@ namespace DCFApixels.DragonECS
_delayedOpsCount = 0;
_count = 0;
}
+
+ //защита от криворукости
+ //перед сборкой мусора снова создает сильную ссылку и возвращает в пул
+ //TODO переделат ьиил удалить, так как сборщик мусора просыпается только после 12к и более экземпляров, только тогда и вызывается финализатор, слишком жирно
+ ~EcsGroup()
+ {
+ Release();
+ }
#endregion
#region Contains
@@ -256,12 +249,10 @@ namespace DCFApixels.DragonECS
}
}
}
-
public void Clear()
{
_count = 0;
- for (int i = 0; i < _dense.Length; i++)
- _dense[i] = 0;
+ //массив _dense нет смысла очищать, испольщуется только область от 1 до _count
for (int i = 0; i < _sparse.Length; i++)
_sparse[i] = 0;
}
@@ -275,7 +266,8 @@ namespace DCFApixels.DragonECS
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
if (group.World != _source) throw new ArgumentException("groupFilter.World != World");
#endif
- Clear();
+ if(_count > 0)
+ Clear();
foreach (var item in group)
AggressiveAdd(item.id);
}
@@ -428,14 +420,14 @@ namespace DCFApixels.DragonECS
#region Enumerator
public ref struct Enumerator// : IDisposable
{
- // private readonly EcsGroup _source;
+ // private readonly EcsGroup source;
private readonly int[] _dense;
private readonly int _count;
private int _index;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator(EcsGroup group)
{
- // _source = group;
+ // source = group;
_dense = group._dense;
_count = group.Count;
_index = 0;
@@ -448,7 +440,7 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext() => ++_index <= _count && _count<_dense.Length; // <= потму что отсчет начинается с индекса 1 //_count < _dense.Length дает среде понять что проверки на выход за границы не нужны
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
- //public void Dispose() => _source.Unlock();
+ //public void Dispose() => source.Unlock();
}
#endregion
diff --git a/src/EcsMask.cs b/src/EcsMask.cs
index 543821a..5de79e2 100644
--- a/src/EcsMask.cs
+++ b/src/EcsMask.cs
@@ -357,27 +357,27 @@ namespace DCFApixels.DragonECS
{
static Activator()
{
- // var inc = new TInc().GetComponentsIDs();
- // var exc = new TExc().GetComponentsIDs();
- // Array.Sort(inc);
- // Array.Sort(exc);
+ // var inc_ = new TInc().GetComponentsIDs();
+ // var exc_ = new TExc().GetComponentsIDs();
+ // Array.Sort(inc_);
+ // Array.Sort(exc_);
//
// Type thisType = typeof(Activator);
//
// Type sortedIncType = typeof(TInc);
// if (sortedIncType.IsGenericType)
// {
- // Type[] sortedInc = new Type[inc.Length];
+ // Type[] sortedInc = new Type[inc_.Length];
// for (int i = 0; i < sortedInc.Length; i++)
- // sortedInc[i] = EcsWorld.ComponentType.types[inc[i]];
+ // sortedInc[i] = EcsWorld.ComponentType.types[inc_[i]];
// sortedIncType = sortedIncType.GetGenericTypeDefinition().MakeGenericType(sortedInc);
// }
// Type sortedExcType = typeof(TExc);
// if (sortedExcType.IsGenericType)
// {
- // Type[] sortedExc = new Type[exc.Length];
+ // Type[] sortedExc = new Type[exc_.Length];
// for (int i = 0; i < sortedExc.Length; i++)
- // sortedExc[i] = EcsWorld.ComponentType.types[exc[i]];
+ // sortedExc[i] = EcsWorld.ComponentType.types[exc_[i]];
// sortedExcType = sortedExcType.GetGenericTypeDefinition().MakeGenericType(sortedExc);
// }
//
@@ -393,7 +393,7 @@ namespace DCFApixels.DragonECS
// if (_count >= _capacity)
// _capacity <<= 1;
//
- // instance = new EcsMask(typeof(TWorldArchetype), id, inc, exc);
+ // instance = new EcsMask(typeof(TWorldArchetype), id, inc_, exc_);
}
public readonly static EcsMask instance;
diff --git a/src/EcsPool.cs b/src/EcsPool.cs
index 682e784..e46d52a 100644
--- a/src/EcsPool.cs
+++ b/src/EcsPool.cs
@@ -1,21 +1,25 @@
using System;
using System.Runtime.CompilerServices;
using Unity.Profiling;
-using UnityEngine;
namespace DCFApixels.DragonECS
{
public interface IEcsPool
{
+ #region Properties
public Type ComponentType { get; }
public int ComponentID { get; }
public IEcsWorld World { get; }
public int Count { get; }
public int Capacity { get; }
+ #endregion
+
+ #region Methods
public bool Has(int entityID);
public void Write(int entityID);
public void Del(int entityID);
internal void OnWorldResize(int newSize);
+ #endregion
}
public interface IEcsPool : IEcsPool where T : struct
{
@@ -28,13 +32,18 @@ namespace DCFApixels.DragonECS
{
public static EcsNullPool instance => new EcsNullPool(null);
private IEcsWorld _source;
- private EcsNullPool(IEcsWorld source) => _source = source;
private NullComponent fakeComponent;
+ private EcsNullPool(IEcsWorld source) => _source = source;
+
+ #region Properties
public Type ComponentType => typeof(NullComponent);
public int ComponentID => -1;
public IEcsWorld World => _source;
public int Count => 0;
public int Capacity => 1;
+ #endregion
+
+ #region Methods
public void Del(int index) { }
public override bool Has(int index) => false;
void IEcsPool.Write(int entityID) { }
@@ -42,6 +51,7 @@ namespace DCFApixels.DragonECS
public ref NullComponent Write(int entity) => ref fakeComponent;
void IEcsPool.OnWorldResize(int newSize) { }
internal override void OnWorldResize(int newSize) { }
+ #endregion
}
public abstract class EcsPool
{
@@ -62,6 +72,7 @@ namespace DCFApixels.DragonECS
private IEcsComponentReset _componentResetHandler;
private PoolRunnres _poolRunnres;
+
#region Properites
public int Count => _itemsCount;
public int Capacity => _items.Length;
@@ -115,11 +126,12 @@ namespace DCFApixels.DragonECS
_mapping[entityID] = itemIndex;
_componentResetHandler.Reset(ref _items[itemIndex]);
_poolRunnres.add.OnComponentAdd(entityID);
- }
+ }
_poolRunnres.write.OnComponentWrite(entityID);
return ref _items[itemIndex];
// }
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T Write(int entityID)
{
// using (_writeMark.Auto())
@@ -134,7 +146,7 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public sealed override bool Has(int entityID)
{
- // using (_hasMark.Auto())
+ // using (_hasMark.Auto())
return _mapping[entityID] > 0;
}
public void Del(int entityID)
diff --git a/src/EcsQuery.cs b/src/EcsQuery.cs
index 35c8143..7bb9e1d 100644
--- a/src/EcsQuery.cs
+++ b/src/EcsQuery.cs
@@ -1,106 +1,68 @@
using System;
using System.Collections.Generic;
using System.Reflection;
-using System.Runtime.CompilerServices;
using Unity.Profiling;
-using UnityEngine;
-using UnityEngine.UI;
namespace DCFApixels.DragonECS
{
- public abstract class EcsQuery
+ public abstract class EcsQueryBase
{
+ internal IEcsWorld source;
internal EcsGroup groupFilter;
internal EcsQueryMask mask;
- public IEcsWorld World => groupFilter.World;
-
- private ProfilerMarker _getEnumerator = new ProfilerMarker("EcsQuery.GetEnumerator");
-
-
- public EcsGroup.Enumerator GetEnumerator()
- {
- using (_getEnumerator.Auto())
- {
- var pools = World.GetAllPools();
-
- EcsReadonlyGroup all = World.Entities;
- groupFilter.Clear();
- foreach (var e in all)
- {
- int entityID = e.id;
-
- for (int i = 0, iMax = mask.Inc.Length; i < iMax; i++)
- {
- if (!pools[mask.Inc[i]].Has(entityID))
- {
- continue;
- }
- }
- for (int i = 0, iMax = mask.Exc.Length; i < iMax; i++)
- {
- if (pools[mask.Exc[i]].Has(entityID))
- {
- continue;
- }
- }
- groupFilter.AggressiveAdd(entityID);
- }
- groupFilter.Sort();
- return groupFilter.GetEnumerator();
- }
- }
- protected virtual void Init(Builder b) { }
+ public IEcsWorld World => source;
#region Builder
- public sealed class Builder : EcsQueryBuilder
+ protected virtual void Init(Builder b) { }
+ protected abstract void OnBuilt();
+ public abstract void Execute();
+ public sealed class Builder : EcsQueryBuilderBase
{
private IEcsWorld _world;
private List _inc;
private List _exc;
- internal static TQuery Build(IEcsWorld world) where TQuery : EcsQuery
- {
- Builder builder = new Builder(world);
-
- Type queryType = typeof(TQuery);
- ConstructorInfo constructorInfo = queryType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Builder) }, null);
- EcsQuery newQuery;
- if (constructorInfo != null)
- {
- newQuery = (EcsQuery)constructorInfo.Invoke(new object[] { builder });
- }
- else
- {
- newQuery = (EcsQuery)Activator.CreateInstance(typeof(TQuery));
- newQuery.Init(builder);
- }
-
- builder.End(out newQuery.mask);
- // newQuery.groupFilter = new EcsGroup(world);
- newQuery.groupFilter = EcsGroup.New(world);
- return (TQuery)(object)newQuery;
- }
-
private Builder(IEcsWorld world)
{
_world = world;
_inc = new List(8);
_exc = new List(4);
}
+ internal static TQuery Build(IEcsWorld world) where TQuery : EcsQueryBase
+ {
+ Builder builder = new Builder(world);
+ Type queryType = typeof(TQuery);
+ ConstructorInfo constructorInfo = queryType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Builder) }, null);
+ EcsQueryBase newQuery;
+ if (constructorInfo != null)
+ {
+ newQuery = (EcsQueryBase)constructorInfo.Invoke(new object[] { builder });
+ }
+ else
+ {
+ newQuery = (EcsQueryBase)Activator.CreateInstance(typeof(TQuery));
+ newQuery.Init(builder);
+ }
+ newQuery.groupFilter = EcsGroup.New(world);
+ newQuery.source = world;
+ builder.End(out newQuery.mask);
+ newQuery.OnBuilt();
+ return (TQuery)(object)newQuery;
+ }
- public override inc Include() where TComponent : struct
+ public override inc_ Include() where TComponent : struct
{
_inc.Add(_world.GetComponentID());
- return new inc(_world.GetPool());
+ return new inc_(_world.GetPool());
}
- public override exc Exclude() where TComponent : struct
+ public override exc_ Exclude() where TComponent : struct
{
_exc.Add(_world.GetComponentID());
- return new exc(_world.GetPool());
+ return new exc_(_world.GetPool());
}
- public override opt Optional() where TComponent : struct
+ public override opt_ Optional() where TComponent : struct
{
- return new opt(_world.GetPool());
+ return new opt_(_world.GetPool());
}
private void End(out EcsQueryMask mask)
@@ -116,6 +78,64 @@ namespace DCFApixels.DragonECS
#endregion
}
+ public abstract class EcsJoinQuery : EcsQueryBase
+ {
+ private EcsPool attachPool;
+
+ private ProfilerMarker _getEnumerator = new ProfilerMarker("EcsQuery.Execute");
+ protected sealed override void OnBuilt()
+ {
+ attachPool = World.GetPool();
+ }
+ public sealed override void Execute()
+ {
+ using (_getEnumerator.Auto())
+ {
+ throw new NotImplementedException();
+ }
+ }
+ public EcsGroup.Enumerator GetEnumerator()
+ {
+ return groupFilter.GetEnumerator();
+ }
+ }
+
+ public abstract class EcsQuery : EcsQueryBase
+ {
+ private ProfilerMarker _getEnumerator = new ProfilerMarker("EcsQuery.Execute");
+ protected sealed override void OnBuilt() { }
+ public sealed override void Execute()
+ {
+ using (_getEnumerator.Auto())
+ {
+ var pools = World.GetAllPools();
+
+ EcsReadonlyGroup all = World.Entities;
+ groupFilter.Clear();
+ foreach (var e in all)
+ {
+ int entityID = e.id;
+ for (int i = 0, iMax = mask.Inc.Length; i < iMax; i++)
+ {
+ if (!pools[mask.Inc[i]].Has(entityID))
+ continue;
+ }
+ for (int i = 0, iMax = mask.Exc.Length; i < iMax; i++)
+ {
+ if (pools[mask.Exc[i]].Has(entityID))
+ continue;
+ }
+ groupFilter.AggressiveAdd(entityID);
+ }
+ groupFilter.Sort();
+ }
+ }
+ public EcsGroup.Enumerator GetEnumerator()
+ {
+ return groupFilter.GetEnumerator();
+ }
+ }
+
public class EcsQueryMask : EcsComponentMask
{
public EcsQueryMask(Type worldArchetypeType, int[] inc, int[] exc)
@@ -125,10 +145,10 @@ namespace DCFApixels.DragonECS
Exc = exc;
}
}
- public abstract class EcsQueryBuilder
+ public abstract class EcsQueryBuilderBase
{
- public abstract inc Include() where TComponent : struct;
- public abstract exc Exclude() where TComponent : struct;
- public abstract opt Optional() where TComponent : struct;
+ public abstract inc_ Include() where TComponent : struct;
+ public abstract exc_ Exclude() where TComponent : struct;
+ public abstract opt_ Optional() where TComponent : struct;
}
}
diff --git a/src/EcsQueryMember.cs b/src/EcsQueryMember.cs
index 9128cd1..d2f5922 100644
--- a/src/EcsQueryMember.cs
+++ b/src/EcsQueryMember.cs
@@ -1,89 +1,160 @@
-using System;
-using System.Collections.Generic;
-using System.Runtime.CompilerServices;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace DCFApixels.DragonECS
{
- public interface IEcsQueryMember
+ public interface IEcsQueryMember { }
+ public interface IEcsQueryReadonlyField : IEcsQueryMember
+ {
+ public ref TComponent Read(ent entityID);
+ public bool Has(ent entityID);
+ }
+ public interface IEcsQueryField : IEcsQueryReadonlyField
where TComponent : struct
{
public ref TComponent Add(ent entityID);
public ref TComponent Write(ent entityID);
- public ref TComponent Read(ent entityID);
- public bool Has(ent entityID);
public void Del(ent entityID);
}
+ #region select
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
- public readonly struct inc : IEcsQueryMember
+ public readonly struct inc_ : IEcsQueryField
where TComponent : struct
{
- private readonly EcsPool _pool;
+ internal readonly EcsPool pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal inc(EcsPool pool) => _pool = pool;
+ internal inc_(EcsPool pool) => this.pool = pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ref TComponent Add(ent entityID) => ref _pool.Add(entityID.id);
+ public ref TComponent Add(ent entityID) => ref pool.Add(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ref TComponent Write(ent entityID) => ref _pool.Write(entityID.id);
+ public ref TComponent Write(ent entityID) => ref pool.Write(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ref TComponent Read(ent entityID) => ref _pool.Read(entityID.id);
+ public ref TComponent Read(ent entityID) => ref pool.Read(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool Has(ent entityID) => _pool.Has(entityID.id);
+ public bool Has(ent entityID) => pool.Has(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Del(ent entityID) => _pool.Del(entityID.id);
+ 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}>";
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static implicit operator inc(EcsQueryBuilder buider) => buider.Include();
+ public static implicit operator inc_(EcsQueryBuilderBase buider) => buider.Include();
}
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
- public readonly struct exc : IEcsQueryMember
+ public readonly struct exc_ : IEcsQueryField
where TComponent : struct
{
- private readonly EcsPool _pool;
+ internal readonly EcsPool pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal exc(EcsPool pool) => _pool = pool;
+ internal exc_(EcsPool pool) => this.pool = pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ref TComponent Add(ent entityID) => ref _pool.Add(entityID.id);
+ public ref TComponent Add(ent entityID) => ref pool.Add(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ref TComponent Write(ent entityID) => ref _pool.Write(entityID.id);
+ public ref TComponent Write(ent entityID) => ref pool.Write(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ref TComponent Read(ent entityID) => ref _pool.Read(entityID.id);
+ public ref TComponent Read(ent entityID) => ref pool.Read(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool Has(ent entityID) => _pool.Has(entityID.id);
+ public bool Has(ent entityID) => pool.Has(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Del(ent entityID) => _pool.Del(entityID.id);
+ 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}>";
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static implicit operator exc(EcsQueryBuilder buider) => buider.Exclude();
+ public static implicit operator exc_(EcsQueryBuilderBase buider) => buider.Exclude();
}
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
- public readonly struct opt : IEcsQueryMember
+ public readonly struct opt_ : IEcsQueryField
where TComponent : struct
{
- private readonly EcsPool _pool;
+ internal readonly EcsPool pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal opt(EcsPool pool) => _pool = pool;
+ internal opt_(EcsPool pool) => this.pool = pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ref TComponent Add(ent entityID) => ref _pool.Add(entityID.id);
+ public ref TComponent Add(ent entityID) => ref pool.Add(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ref TComponent Write(ent entityID) => ref _pool.Write(entityID.id);
+ public ref TComponent Write(ent entityID) => ref pool.Write(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ref TComponent Read(ent entityID) => ref _pool.Read(entityID.id);
+ public ref TComponent Read(ent entityID) => ref pool.Read(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool Has(ent entityID) => _pool.Has(entityID.id);
+ public bool Has(ent entityID) => pool.Has(entityID.id);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Del(ent entityID) => _pool.Del(entityID.id);
+ 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}>";
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static implicit operator opt(EcsQueryBuilder buider) => buider.Optional();
+ public static implicit operator opt_(EcsQueryBuilderBase buider) => buider.Optional();
}
+ #endregion
+
+ // #region select_readonly
+ // [StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
+ // public readonly struct inc_readonly_ : IEcsQueryReadonlyField
+ // where TComponent : struct
+ // {
+ // internal readonly EcsPool pool;
+ // [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ // internal inc_readonly_(EcsPool pool) => this.pool = pool;
+ // [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ // public ref TComponent Read(ent entityID) => ref pool.Read(entityID.id);
+ // [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ // public bool Has(ent entityID) => pool.Has(entityID.id);
+ // [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ //
+ // public static implicit operator inc_readonly_(EcsQueryBuilderBase buider) => buider.Include();
+ // public static implicit operator inc_readonly_(inc_ o) => new inc_readonly_(o.pool);
+ // }
+ //
+ // [StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
+ // public readonly struct exc_readonly_ : IEcsQueryReadonlyField
+ // where TComponent : struct
+ // {
+ // internal readonly EcsPool pool;
+ // [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ // internal exc_readonly_(EcsPool pool) => this.pool = pool;
+ // [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ // public ref TComponent Read(ent entityID) => ref pool.Read(entityID.id);
+ // [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ // public bool Has(ent entityID) => pool.Has(entityID.id);
+ // [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ //
+ // public static implicit operator exc_readonly_(EcsQueryBuilderBase buider) => buider.Exclude();
+ // public static implicit operator exc_readonly_(exc_ o) => new exc_readonly_(o.pool);
+ // }
+ //
+ // [StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
+ // public readonly struct opt_readonly_ : IEcsQueryReadonlyField
+ // where TComponent : struct
+ // {
+ // internal readonly EcsPool pool;
+ // [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ // internal opt_readonly_(EcsPool pool) => this.pool = pool;
+ // [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ // public ref TComponent Read(ent entityID) => ref pool.Read(entityID.id);
+ // [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ // public bool Has(ent entityID) => pool.Has(entityID.id);
+ // [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ //
+ // public static implicit operator opt_readonly_(EcsQueryBuilderBase buider) => buider.Optional();
+ // public static implicit operator opt_readonly_(opt_ o) => new opt_readonly_(o.pool);
+ // }
+ // #endregion
+ //
+ // #region join
+ // [StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
+ // public readonly struct attach : IEcsQueryField
+ // {
+ // internal readonly EcsPool pool;
+ // [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ // internal attach(EcsPool pool) => this.pool = pool;
+ // [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ // public ref Attach Add(ent entityID) => ref pool.Add(entityID.id);
+ // [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ // public ref Attach Write(ent entityID) => ref pool.Write(entityID.id);
+ // [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ // public ref Attach Read(ent entityID) => ref pool.Read(entityID.id);
+ // [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ // public bool Has(ent entityID) => pool.Has(entityID.id);
+ // [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ // public void Del(ent entityID) => pool.Del(entityID.id);
+ // [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ // public static implicit operator attach(EcsQueryBuilderBase buider) => buider.Include();
+ // public static implicit operator attach(inc_ o) => new attach(o.pool);
+ // }
+ // #endregion
}
diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs
index 99f65e1..2ced962 100644
--- a/src/EcsWorld.cs
+++ b/src/EcsWorld.cs
@@ -38,9 +38,9 @@ namespace DCFApixels.DragonECS
public readonly short id;
- protected EcsWorld(bool isIndexed)
+ protected EcsWorld(bool isIndexable)
{
- if(isIndexed == true)
+ if(isIndexable == true)
{
id = (short)_worldIdDispenser.GetFree();
if (id >= Worlds.Length)
@@ -74,11 +74,11 @@ namespace DCFApixels.DragonECS
private EcsPool[] _pools;
private EcsNullPool _nullPool;
- private EcsQuery[] _queries;
+ private EcsQueryBase[] _queries;
private EcsPipeline _pipeline;
- private List _groups;
+ private List> _groups;
public IEcsRealationTable[] _relationTables;
@@ -132,7 +132,8 @@ namespace DCFApixels.DragonECS
#endregion
#region Constructors
- public EcsWorld(EcsPipeline pipline = null) : base(true)
+ public EcsWorld(EcsPipeline pipline = null) : this(pipline, true) { }
+ internal EcsWorld(EcsPipeline pipline, bool isIndexable) : base(isIndexable)
{
_pipeline = pipline ?? EcsPipeline.Empty;
if (!_pipeline.IsInit) pipline.Init();
@@ -143,7 +144,7 @@ namespace DCFApixels.DragonECS
_gens = new short[512];
_queries = new EcsQuery[QueryType.capacity];
- _groups = new List(128);
+ _groups = new List>();
_denseEntities = new int[512];
@@ -153,8 +154,8 @@ namespace DCFApixels.DragonECS
_pipeline.GetRunner>().Inject((TWorldArchetype)this);
_pipeline.GetRunner>().Inject(this);
_pipeline.GetRunner().OnWorldCreate(this);
-
- _allEntites = new EcsGroup(this);
+
+ _allEntites = GetGroupFromPool();
}
#endregion
@@ -181,17 +182,15 @@ namespace DCFApixels.DragonECS
#endregion
#region Query
- public TQuery Query(out TQuery query) where TQuery : EcsQuery
+ public TQuery Query(out TQuery query) where TQuery : EcsQueryBase
{
int uniqueID = QueryType.uniqueID;
if (_queries.Length < QueryType.capacity)
Array.Resize(ref _queries, QueryType.capacity);
-
if (_queries[uniqueID] == null)
- {
- _queries[uniqueID] = EcsQuery.Builder.Build(this);
- }
+ _queries[uniqueID] = EcsQueryBase.Builder.Build(this);
query = (TQuery)_queries[uniqueID];
+ query.Execute();
return query;
}
#endregion
@@ -233,8 +232,19 @@ namespace DCFApixels.DragonECS
if (_gens.Length <= entityID)
{
Array.Resize(ref _gens, _gens.Length << 1);
- foreach (var item in _groups)
- item.OnWorldResize(_gens.Length);
+ for (int i = 0; i < _groups.Count; i++)
+ {
+ if (_groups[i].TryGetTarget(out EcsGroup group))
+ {
+ group.OnWorldResize(_gens.Length);
+ }
+ else
+ {
+ int last = _groups.Count - 1;
+ _groups[i--] = _groups[last];
+ _groups.RemoveAt(last);
+ }
+ }
foreach (var item in _pools)
item.OnWorldResize(_gens.Length);
}
@@ -286,7 +296,7 @@ namespace DCFApixels.DragonECS
#region Other
void IEcsReadonlyTable.RegisterGroup(EcsGroup group)
{
- _groups.Add(group);
+ _groups.Add(new WeakReference(group));
}
#endregion
@@ -339,7 +349,8 @@ namespace DCFApixels.DragonECS
#region GroupsPool
private Stack _pool = new Stack(64);
- EcsGroup IEcsWorld.GetGroupFromPool()
+ EcsGroup IEcsWorld.GetGroupFromPool() => GetGroupFromPool();
+ internal EcsGroup GetGroupFromPool()
{
if (_pool.Count <= 0)
return new EcsGroup(this);
diff --git a/src/Entities/EcsEntity.cs b/src/Entities/EcsEntity.cs
index 00059e9..3e5b476 100644
--- a/src/Entities/EcsEntity.cs
+++ b/src/Entities/EcsEntity.cs
@@ -4,8 +4,7 @@ using System.Runtime.InteropServices;
namespace DCFApixels.DragonECS
{
-
- /// Permanent relation entity identifier
+ /// Strong identifier/Permanent entity identifier
[StructLayout(LayoutKind.Explicit, Pack = 2, Size = 8)]
public readonly partial struct EcsEntity : IEquatable, IEquatable
{
diff --git a/src/Entities/EcsRelation.cs b/src/Entities/EcsRelation.cs
deleted file mode 100644
index ed55ff2..0000000
--- a/src/Entities/EcsRelation.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using System;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-namespace DCFApixels.DragonECS
-{
- /// Permanent relation entity identifier
- [StructLayout(LayoutKind.Explicit, Pack = 2, Size = 8)]
- public readonly partial struct EcsRelation : IEquatable, IEquatable
- {
- 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
- }
-}
diff --git a/src/Entities/ent.cs b/src/Entities/ent.cs
index c5ddd38..160744a 100644
--- a/src/Entities/ent.cs
+++ b/src/Entities/ent.cs
@@ -4,8 +4,8 @@ using UnityEngine.Rendering;
namespace DCFApixels.DragonECS
{
-#pragma warning disable CS0660, CS0661
- /// Single frame entity identifier
+#pragma warning disable CS0660, CS0661, IDE1006
+ /// Weak identifier/Single frame entity identifier
[StructLayout(LayoutKind.Sequential, Pack = 4, Size = 4)]
public readonly ref struct ent
{
@@ -25,5 +25,8 @@ namespace DCFApixels.DragonECS
public static bool operator !=(Null? _, ent b) => b.id != 0;
public struct Null { }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public EcsEntity ToStrong(IEcsWorld world) => world.GetEntity(id);
}
}
diff --git a/src/Interfaces/IEcsReadonlyTable.cs b/src/Interfaces/IEcsReadonlyTable.cs
index ec2b50d..fcb7a24 100644
--- a/src/Interfaces/IEcsReadonlyTable.cs
+++ b/src/Interfaces/IEcsReadonlyTable.cs
@@ -15,7 +15,7 @@ namespace DCFApixels.DragonECS
#region Methods
public EcsPool GetPool() where T : struct;
public ReadOnlySpan GetAllPools();
- public TQuery Query(out TQuery query) where TQuery : EcsQuery;
+ public TQuery Query(out TQuery query) where TQuery : EcsQueryBase;
public int GetComponentID();
public bool IsMaskCompatible(int entityID) where TInc : struct, IInc where TExc : struct, IExc;
diff --git a/src/Utils/SparseArray.cs b/src/Utils/SparseArray.cs
new file mode 100644
index 0000000..e89ec0c
--- /dev/null
+++ b/src/Utils/SparseArray.cs
@@ -0,0 +1,203 @@
+using System;
+using System.Diagnostics.Contracts;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace DCFApixels
+{
+ public class SparseArray
+ {
+ public const int MIN_CAPACITY = 16;
+ private const int EMPTY = -1;
+
+ private int[] _buckets = Array.Empty();
+ private Entry[] _entries = Array.Empty();
+
+ private int _count;
+
+ private int _freeList;
+ private int _freeCount;
+
+ #region Properties
+ public TValue this[int key]
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _entries[FindEntry(key)].value;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => Insert(key, value);
+ }
+
+ public int Count => _count;
+ #endregion
+
+ #region Constructors
+ public SparseArray(int capacity = MIN_CAPACITY)
+ {
+ _buckets = new int[capacity];
+ for (int i = 0; i < capacity; i++)
+ _buckets[i] = EMPTY;
+ _entries = new Entry[capacity];
+ }
+ #endregion
+
+ #region Add
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Add(int key, TValue value)
+ {
+#if DEBUG
+ if (Contains(key))
+ throw new ArgumentException("Contains(hashKey) is true");
+#endif
+ Insert(key, value);
+ }
+ #endregion
+
+ #region Find/Insert/Remove
+ private int FindEntry(int key)
+ {
+ key &= 0x7FFFFFFF;
+ for (int i = _buckets[key % _buckets.Length]; i >= 0; i = _entries[i].next)
+ {
+ if (_entries[i].hashKey == key) return i;
+ }
+ return -1;
+ }
+ private void Insert(int key, TValue value)
+ {
+ key &= 0x7FFFFFFF;
+ int targetBucket = key % _buckets.Length;
+
+ for (int i = _buckets[targetBucket]; i >= 0; i = _entries[i].next)
+ {
+ if (_entries[i].hashKey == key)
+ {
+ _entries[i].value = value;
+ return;
+ }
+ }
+
+ int index;
+ if (_freeCount > 0)
+ {
+ index = _freeList;
+ _freeList = _entries[index].next;
+ _freeCount--;
+ }
+ else
+ {
+ if (_count == _entries.Length)
+ {
+ Resize();
+ targetBucket = key % _buckets.Length;
+ }
+ index = _count;
+ _count++;
+ }
+
+ _entries[index].next = _buckets[targetBucket];
+ _entries[index].hashKey = key;
+ _entries[index].value = value;
+ _buckets[targetBucket] = index;
+ }
+ public bool Remove(int key)
+ {
+ key &= 0x7FFFFFFF;
+ int bucket = key % _buckets.Length;
+ int last = -1;
+ for (int i = _buckets[bucket]; i >= 0; last = i, i = _entries[i].next)
+ {
+ if (_entries[i].hashKey == key)
+ {
+ if (last < 0)
+ {
+ _buckets[bucket] = _entries[i].next;
+ }
+ else
+ {
+ _entries[last].next = _entries[i].next;
+ }
+ _entries[i].next = _freeList;
+ _entries[i].hashKey = -1;
+ _entries[i].value = default;
+ _freeList = i;
+ _freeCount++;
+ return true;
+ }
+ }
+ return false;
+ }
+ #endregion
+
+ #region TryGetValue
+ public bool TryGetValue(int key, out TValue value)
+ {
+ int index = FindEntry(key);
+ if (index < 0)
+ {
+ value = default;
+ return false;
+ }
+ value = _entries[index].value;
+ return true;
+ }
+ #endregion
+
+ #region Contains
+ public bool Contains(int key)
+ {
+ return FindEntry(key) >= 0;
+ }
+ #endregion
+
+ #region Clear
+ public void Clear()
+ {
+ if (_count > 0)
+ {
+ for (int i = 0; i < _buckets.Length; i++)
+ {
+ _buckets[i] = -1;
+ }
+ Array.Clear(_entries, 0, _count);
+ _count = 0;
+ }
+ }
+ #endregion
+
+ #region Resize
+ private void Resize()
+ {
+ int newSize = _buckets.Length << 1;
+
+ Contract.Assert(newSize >= _entries.Length);
+ int[] newBuckets = new int[newSize];
+ for (int i = 0; i < newBuckets.Length; i++)
+ newBuckets[i] = EMPTY;
+
+ Entry[] newEntries = new Entry[newSize];
+ Array.Copy(_entries, 0, newEntries, 0, _count);
+ for (int i = 0; i < _count; i++)
+ {
+ if (newEntries[i].hashKey >= 0)
+ {
+ int bucket = newEntries[i].hashKey % newSize;
+ newEntries[i].next = newBuckets[bucket];
+ newBuckets[bucket] = i;
+ }
+ }
+ _buckets = newBuckets;
+ _entries = newEntries;
+ }
+ #endregion
+
+ #region Utils
+ [StructLayout(LayoutKind.Sequential, Pack = 4)]
+ private struct Entry
+ {
+ public int next; // Index of next entry, -1 if last
+ public int hashKey;
+ public TValue value;
+ }
+ #endregion
+ }
+}
\ No newline at end of file