fix changes

This commit is contained in:
Mikhail 2023-04-17 22:58:52 +08:00
parent c0b1d8ba5b
commit e7835a39d3
12 changed files with 521 additions and 254 deletions

30
src/Builtin/Components.cs Normal file
View File

@ -0,0 +1,30 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace DCFApixels.DragonECS
{
/// <summary>
/// Используется для реализации отношений. traget - это сущьность к которой крепится эта сущьность. other - это сущьность с которой traget образует связь
/// </summary>
[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;
/// <summary>alias for "target"</summary>
public EcsEntity left
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => target;
}
/// <summary>alias for "other"</summary>
public EcsEntity right
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => other;
}
}
}

View File

@ -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();
/// <summary>Equivalent of the EcsGroup.Clone() method</summary>
/// <returns>An editable clone of this EcsReadnolyGroup</returns>
[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<EcsGroup>
{
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,6 +266,7 @@ namespace DCFApixels.DragonECS
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
if (group.World != _source) throw new ArgumentException("groupFilter.World != World");
#endif
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

View File

@ -357,27 +357,27 @@ namespace DCFApixels.DragonECS
{
static Activator()
{
// var inc = new TInc().GetComponentsIDs<TWorldArchetype>();
// var exc = new TExc().GetComponentsIDs<TWorldArchetype>();
// Array.Sort(inc);
// Array.Sort(exc);
// var inc_ = new TInc().GetComponentsIDs<TWorldArchetype>();
// var exc_ = new TExc().GetComponentsIDs<TWorldArchetype>();
// Array.Sort(inc_);
// Array.Sort(exc_);
//
// Type thisType = typeof(Activator<TInc, TExc>);
//
// 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<TWorldArchetype>.ComponentType.types[inc[i]];
// sortedInc[i] = EcsWorld<TWorldArchetype>.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<TWorldArchetype>.ComponentType.types[exc[i]];
// sortedExc[i] = EcsWorld<TWorldArchetype>.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;

View File

@ -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<T> : 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<T> _componentResetHandler;
private PoolRunnres _poolRunnres;
#region Properites
public int Count => _itemsCount;
public int Capacity => _items.Length;
@ -120,6 +131,7 @@ namespace DCFApixels.DragonECS
return ref _items[itemIndex];
// }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T Write(int entityID)
{
// using (_writeMark.Auto())

View File

@ -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<int> _inc;
private List<int> _exc;
internal static TQuery Build<TQuery>(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<int>(8);
_exc = new List<int>(4);
}
internal static TQuery Build<TQuery>(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<TComponent> Include<TComponent>() where TComponent : struct
public override inc_<TComponent> Include<TComponent>() where TComponent : struct
{
_inc.Add(_world.GetComponentID<TComponent>());
return new inc<TComponent>(_world.GetPool<TComponent>());
return new inc_<TComponent>(_world.GetPool<TComponent>());
}
public override exc<TComponent> Exclude<TComponent>() where TComponent : struct
public override exc_<TComponent> Exclude<TComponent>() where TComponent : struct
{
_exc.Add(_world.GetComponentID<TComponent>());
return new exc<TComponent>(_world.GetPool<TComponent>());
return new exc_<TComponent>(_world.GetPool<TComponent>());
}
public override opt<TComponent> Optional<TComponent>() where TComponent : struct
public override opt_<TComponent> Optional<TComponent>() where TComponent : struct
{
return new opt<TComponent>(_world.GetPool<TComponent>());
return new opt_<TComponent>(_world.GetPool<TComponent>());
}
private void End(out EcsQueryMask mask)
@ -116,6 +78,64 @@ namespace DCFApixels.DragonECS
#endregion
}
public abstract class EcsJoinQuery : EcsQueryBase
{
private EcsPool<Attach> attachPool;
private ProfilerMarker _getEnumerator = new ProfilerMarker("EcsQuery.Execute");
protected sealed override void OnBuilt()
{
attachPool = World.GetPool<Attach>();
}
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<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 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;
}
}

View File

@ -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<TComponent>
public interface IEcsQueryMember { }
public interface IEcsQueryReadonlyField<TComponent> : IEcsQueryMember
{
public ref TComponent Read(ent entityID);
public bool Has(ent entityID);
}
public interface IEcsQueryField<TComponent> : IEcsQueryReadonlyField<TComponent>
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<TComponent> : IEcsQueryMember<TComponent>
public readonly struct inc_<TComponent> : IEcsQueryField<TComponent>
where TComponent : struct
{
private readonly EcsPool<TComponent> _pool;
internal readonly EcsPool<TComponent> pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal inc(EcsPool<TComponent> pool) => _pool = pool;
internal inc_(EcsPool<TComponent> 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<TComponent>(EcsQueryBuilder buider) => buider.Include<TComponent>();
public static implicit operator inc_<TComponent>(EcsQueryBuilderBase buider) => buider.Include<TComponent>();
}
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
public readonly struct exc<TComponent> : IEcsQueryMember<TComponent>
public readonly struct exc_<TComponent> : IEcsQueryField<TComponent>
where TComponent : struct
{
private readonly EcsPool<TComponent> _pool;
internal readonly EcsPool<TComponent> pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal exc(EcsPool<TComponent> pool) => _pool = pool;
internal exc_(EcsPool<TComponent> 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<TComponent>(EcsQueryBuilder buider) => buider.Exclude<TComponent>();
public static implicit operator exc_<TComponent>(EcsQueryBuilderBase buider) => buider.Exclude<TComponent>();
}
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
public readonly struct opt<TComponent> : IEcsQueryMember<TComponent>
public readonly struct opt_<TComponent> : IEcsQueryField<TComponent>
where TComponent : struct
{
private readonly EcsPool<TComponent> _pool;
internal readonly EcsPool<TComponent> pool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal opt(EcsPool<TComponent> pool) => _pool = pool;
internal opt_(EcsPool<TComponent> 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}>";
public static implicit operator opt_<TComponent>(EcsQueryBuilderBase buider) => buider.Optional<TComponent>();
}
#endregion
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator opt<TComponent>(EcsQueryBuilder buider) => buider.Optional<TComponent>();
}
// #region select_readonly
// [StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
// public readonly struct inc_readonly_<TComponent> : IEcsQueryReadonlyField<TComponent>
// where TComponent : struct
// {
// internal readonly EcsPool<TComponent> pool;
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// internal inc_readonly_(EcsPool<TComponent> 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_<TComponent>(EcsQueryBuilderBase buider) => buider.Include<TComponent>();
// public static implicit operator inc_readonly_<TComponent>(inc_<TComponent> o) => new inc_readonly_<TComponent>(o.pool);
// }
//
// [StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
// public readonly struct exc_readonly_<TComponent> : IEcsQueryReadonlyField<TComponent>
// where TComponent : struct
// {
// internal readonly EcsPool<TComponent> pool;
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// internal exc_readonly_(EcsPool<TComponent> 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_<TComponent>(EcsQueryBuilderBase buider) => buider.Exclude<TComponent>();
// public static implicit operator exc_readonly_<TComponent>(exc_<TComponent> o) => new exc_readonly_<TComponent>(o.pool);
// }
//
// [StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
// public readonly struct opt_readonly_<TComponent> : IEcsQueryReadonlyField<TComponent>
// where TComponent : struct
// {
// internal readonly EcsPool<TComponent> pool;
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// internal opt_readonly_(EcsPool<TComponent> 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_<TComponent>(EcsQueryBuilderBase buider) => buider.Optional<TComponent>();
// public static implicit operator opt_readonly_<TComponent>(opt_<TComponent> o) => new opt_readonly_<TComponent>(o.pool);
// }
// #endregion
//
// #region join
// [StructLayout(LayoutKind.Sequential, Pack = 8, Size = 8)]
// public readonly struct attach : IEcsQueryField<Attach>
// {
// internal readonly EcsPool<Attach> pool;
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// internal attach(EcsPool<Attach> 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<Attach>();
// public static implicit operator attach(inc_<Attach> o) => new attach(o.pool);
// }
// #endregion
}

View File

@ -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<EcsGroup> _groups;
private List<WeakReference<EcsGroup>> _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<EcsGroup>(128);
_groups = new List<WeakReference<EcsGroup>>();
_denseEntities = new int[512];
@ -154,7 +155,7 @@ namespace DCFApixels.DragonECS
_pipeline.GetRunner<IEcsInject<IEcsWorld>>().Inject(this);
_pipeline.GetRunner<IEcsWorldCreate>().OnWorldCreate(this);
_allEntites = new EcsGroup(this);
_allEntites = GetGroupFromPool();
}
#endregion
@ -181,17 +182,15 @@ namespace DCFApixels.DragonECS
#endregion
#region Query
public TQuery Query<TQuery>(out TQuery query) where TQuery : EcsQuery
public TQuery Query<TQuery>(out TQuery query) where TQuery : EcsQueryBase
{
int uniqueID = QueryType<TQuery>.uniqueID;
if (_queries.Length < QueryType.capacity)
Array.Resize(ref _queries, QueryType.capacity);
if (_queries[uniqueID] == null)
{
_queries[uniqueID] = EcsQuery.Builder.Build<TQuery>(this);
}
_queries[uniqueID] = EcsQueryBase.Builder.Build<TQuery>(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<EcsGroup>(group));
}
#endregion
@ -339,7 +349,8 @@ namespace DCFApixels.DragonECS
#region GroupsPool
private Stack<EcsGroup> _pool = new Stack<EcsGroup>(64);
EcsGroup IEcsWorld.GetGroupFromPool()
EcsGroup IEcsWorld.GetGroupFromPool() => GetGroupFromPool();
internal EcsGroup GetGroupFromPool()
{
if (_pool.Count <= 0)
return new EcsGroup(this);

View File

@ -4,8 +4,7 @@ using System.Runtime.InteropServices;
namespace DCFApixels.DragonECS
{
/// <summary>Permanent relation entity identifier</summary>
/// <summary>Strong identifier/Permanent entity identifier</summary>
[StructLayout(LayoutKind.Explicit, Pack = 2, Size = 8)]
public readonly partial struct EcsEntity : IEquatable<long>, IEquatable<EcsEntity>
{

View File

@ -1,74 +0,0 @@
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
}
}

View File

@ -4,8 +4,8 @@ using UnityEngine.Rendering;
namespace DCFApixels.DragonECS
{
#pragma warning disable CS0660, CS0661
/// <summary>Single frame entity identifier</summary>
#pragma warning disable CS0660, CS0661, IDE1006
/// <summary>Weak identifier/Single frame entity identifier</summary>
[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);
}
}

View File

@ -15,7 +15,7 @@ namespace DCFApixels.DragonECS
#region Methods
public EcsPool<T> GetPool<T>() where T : struct;
public ReadOnlySpan<EcsPool> GetAllPools();
public TQuery Query<TQuery>(out TQuery query) where TQuery : EcsQuery;
public TQuery Query<TQuery>(out TQuery query) where TQuery : EcsQueryBase;
public int GetComponentID<T>();
public bool IsMaskCompatible<TInc, TExc>(int entityID) where TInc : struct, IInc where TExc : struct, IExc;

203
src/Utils/SparseArray.cs Normal file
View File

@ -0,0 +1,203 @@
using System;
using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace DCFApixels
{
public class SparseArray<TValue>
{
public const int MIN_CAPACITY = 16;
private const int EMPTY = -1;
private int[] _buckets = Array.Empty<int>();
private Entry[] _entries = Array.Empty<Entry>();
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
}
}