fix changes

This commit is contained in:
Mikhail 2023-04-15 00:23:46 +08:00
parent df54e7bac7
commit c0b1d8ba5b
7 changed files with 214 additions and 221 deletions

View File

@ -2,7 +2,6 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Unity.Profiling;
using static UnityEngine.Networking.UnityWebRequest;
using delayedOp = System.Int32;
namespace DCFApixels.DragonECS
@ -38,6 +37,11 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _source.CapacitySparce;
}
public bool IsReleazed
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _source.IsReleazed;
}
#endregion
#region Methods
@ -46,10 +50,10 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsGroup.Enumerator GetEnumerator() => _source.GetEnumerator();
public EcsGroup Extract()
{
return new EcsGroup(_source);
}
/// <summary>Equivalent of the EcsGroup.Clone() method</summary>
/// <returns>An editable clone of this EcsReadnolyGroup</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsGroup Extract() => _source.Clone();
#endregion
#region Object
@ -59,24 +63,41 @@ namespace DCFApixels.DragonECS
return _source.ToString();
return "NULL";
}
public override int GetHashCode() => _source.GetHashCode();
public override bool Equals(object obj) => obj is EcsGroup group && group == this;
public bool Equals(EcsReadonlyGroup other) => _source == other._source;
#endregion
#region Internal
internal void Release()
{
_source.World.ReleaseGroup(_source);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal EcsGroup GetGroupInternal() => _source;
#endregion
#region operators
public static bool operator ==(EcsReadonlyGroup a, EcsReadonlyGroup b) => a.Equals(b);
public static bool operator ==(EcsReadonlyGroup a, EcsGroup b) => a.Equals(b);
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
// _delayedOps это int[] для отложенных операций, хранятся отложенные операции в виде int значения, если старший бит = 0 то это опреация добавленияб если = 1 то это операция вычитания
// this collection can only store numbers greater than 0
public unsafe class EcsGroup
public unsafe class EcsGroup : IDisposable, IEquatable<EcsGroup>
{
private const int DEALAYED_ADD = 0;
private const int DEALAYED_REMOVE = int.MinValue;
@ -93,6 +114,8 @@ namespace DCFApixels.DragonECS
private int _lockCount;
private bool _isReleazed = true;
#region Properties
public IEcsWorld World => _source;
public int Count
@ -115,16 +138,25 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => new EcsReadonlyGroup(this);
}
public bool IsReleazed
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _isReleazed;
}
#endregion
#region Constrcutors
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsGroup(IEcsWorld source, int denseCapacity = 64, int delayedOpsCapacity = 128)
public static EcsGroup New(IEcsWorld world)
{
_source = source;
return world.GetGroupFromPool();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal EcsGroup(IEcsWorld world, int denseCapacity = 64, int delayedOpsCapacity = 128)
{
_source = world;
_source.RegisterGroup(this);
_dense = new int[denseCapacity];
_sparse = new int[source.EntitesCapacity];
_sparse = new int[world.EntitesCapacity];
_delayedOps = new delayedOp[delayedOpsCapacity];
@ -132,31 +164,13 @@ namespace DCFApixels.DragonECS
_delayedOpsCount = 0;
_count = 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsGroup(EcsGroup copyFrom, int delayedOpsCapacity = 128)
{
_source = copyFrom._source;
_source.RegisterGroup(this);
_dense = new int[copyFrom._dense.Length];
_sparse = new int[copyFrom._sparse.Length];
_delayedOps = new delayedOp[delayedOpsCapacity];
_lockCount = 0;
_delayedOpsCount = 0;
_count = 0;
foreach (var item in copyFrom)
AggressiveAdd(item.id);
}
#endregion
#region Contains
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Contains(int entityID)
{
return _sparse[entityID] > 0;
return _sparse[entityID] > 0;
}
#endregion
@ -229,12 +243,7 @@ namespace DCFApixels.DragonECS
}
#endregion
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void OnWorldResize(int newSize)
{
Array.Resize(ref _sparse, newSize);
}
#region Sort/Clear
public void Sort()
{
int increment = 1;
@ -247,9 +256,20 @@ namespace DCFApixels.DragonECS
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear() => _count = 0;
public void Clear()
{
_count = 0;
for (int i = 0; i < _dense.Length; i++)
_dense[i] = 0;
for (int i = 0; i < _sparse.Length; i++)
_sparse[i] = 0;
}
#endregion
#region CopyFrom/Clone
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyFrom(EcsReadonlyGroup group) => CopyFrom(group.GetGroupInternal());
public void CopyFrom(EcsGroup group)
{
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
@ -259,29 +279,20 @@ namespace DCFApixels.DragonECS
foreach (var item in group)
AggressiveAdd(item.id);
}
public void CopyFrom(EcsReadonlyGroup group)
public EcsGroup Clone()
{
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
if (group.World != _source) throw new ArgumentException("groupFilter.World != World");
#endif
Clear();
foreach (var item in group)
AggressiveAdd(item.id);
EcsGroup result = _source.GetGroupFromPool();
result.CopyFrom(this);
return result;
}
#endregion
#region Set operations
/// <summary>as Union sets</summary>
public void AddGroup(EcsGroup group)
{
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
if (_source != group.World) throw new ArgumentException("World != groupFilter.World");
#endif
foreach (var item in group)
if (!Contains(item.id))
AggressiveAdd(item.id);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void UnionWith(EcsReadonlyGroup group) => UnionWith(group.GetGroupInternal());
/// <summary>as Union sets</summary>
public void AddGroup(EcsReadonlyGroup group)
public void UnionWith(EcsGroup group)
{
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
if (_source != group.World) throw new ArgumentException("World != groupFilter.World");
@ -290,8 +301,12 @@ namespace DCFApixels.DragonECS
if (!Contains(item.id))
AggressiveAdd(item.id);
}
/// <summary>as Except sets</summary>
public void RemoveGroup(EcsGroup group)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ExceptWith(EcsReadonlyGroup group) => ExceptWith(group.GetGroupInternal());
/// <summary>as Except sets</summary>
public void ExceptWith(EcsGroup group)
{
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
if (_source != group.World) throw new ArgumentException("World != groupFilter.World");
@ -300,16 +315,10 @@ namespace DCFApixels.DragonECS
if (group.Contains(item.id))
AggressiveRemove(item.id);
}
/// <summary>as Except sets</summary>
public void RemoveGroup(EcsReadonlyGroup group)
{
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
if (_source != group.World) throw new ArgumentException("World != groupFilter.World");
#endif
foreach (var item in group)
if (Contains(item.id))
AggressiveRemove(item.id);
}
/// <summary>as Intersect sets</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AndWith(EcsReadonlyGroup group) => AndWith(group.GetGroupInternal());
/// <summary>as Intersect sets</summary>
public void AndWith(EcsGroup group)
{
@ -320,33 +329,15 @@ namespace DCFApixels.DragonECS
if (!group.Contains(item.id))
AggressiveRemove(item.id);
}
/// <summary>as Intersect sets</summary>
public void AndWith(EcsReadonlyGroup group)
{
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
if (World != group.World) throw new ArgumentException("World != groupFilter.World");
#endif
foreach (var item in this)
if (!group.Contains(item.id))
AggressiveRemove(item.id);
}
/// <summary>as Symmetric Except sets</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void XorWith(EcsReadonlyGroup group) => XorWith(group.GetGroupInternal());
/// <summary>as Symmetric Except sets</summary>
public void XorWith(EcsGroup group)
{
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
if (_source != group.World) throw new ArgumentException("World != groupFilter.World");
#endif
foreach (var item in group)
if (Contains(item.id))
AggressiveRemove(item.id);
else
AggressiveAdd(item.id);
}
/// <summary>as Symmetric Except sets</summary>
public void XorWith(EcsReadonlyGroup group)
{
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
if (_source != group.World) throw new ArgumentException("World != groupFilter.World");
#endif
foreach (var item in group)
if (Contains(item.id))
@ -358,7 +349,8 @@ namespace DCFApixels.DragonECS
#region Static Set operations
/// <summary>as Except sets</summary>
public static EcsReadonlyGroup Remove(EcsGroup a, EcsGroup b)
/// <returns>new group from pool</returns>
public static EcsGroup Except(EcsGroup a, EcsGroup b)
{
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
if (a._source != b._source) throw new ArgumentException("a.World != b.World");
@ -368,10 +360,11 @@ namespace DCFApixels.DragonECS
if (!b.Contains(item.id))
result.AggressiveAdd(item.id);
a._source.ReleaseGroup(a);
return result.Readonly;
return result;
}
/// <summary>as Intersect sets</summary>
public static EcsReadonlyGroup And(EcsGroup a, EcsGroup b)
/// <returns>new group from pool</returns>
public static EcsGroup And(EcsGroup a, EcsGroup b)
{
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
if (a._source != b._source) throw new ArgumentException("a.World != b.World");
@ -381,7 +374,21 @@ namespace DCFApixels.DragonECS
if (b.Contains(item.id))
result.AggressiveAdd(item.id);
a._source.ReleaseGroup(a);
return result.Readonly;
return result;
}
/// <summary>as Intersect sets</summary>
/// <returns>new group from pool</returns>
public static EcsGroup Union(EcsGroup a, EcsGroup b)
{
#if (DEBUG && !DISABLE_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
if (a._source != b._source) throw new ArgumentException("a.World != b.World");
#endif
EcsGroup result = a._source.GetGroupFromPool();
foreach (var item in a)
result.AggressiveAdd(item.id);
foreach (var item in a)
result.Add(item.id);
return result;
}
#endregion
@ -450,6 +457,51 @@ namespace DCFApixels.DragonECS
{
return string.Join(", ", _dense.AsSpan(1, _count).ToArray());
}
public override bool Equals(object obj) => obj is EcsGroup group && Equals(group);
public bool Equals(EcsReadonlyGroup other) => Equals(other.GetGroupInternal());
public bool Equals(EcsGroup other)
{
if (other.Count != Count)
return false;
foreach (var item in other)
if (!Contains(item.id))
return false;
return true;
}
public override int GetHashCode()
{
int hash = 0;
foreach (var item in this)
hash ^= 1 << (item.id % 32); //реализация от балды, так как не нужен, но фишка в том что хеш не учитывает порядок сущьностей, что явлется правильным поведением.
return hash;
}
#endregion
#region operators
public static bool operator ==(EcsGroup a, EcsGroup b) => a.Equals(b);
public static bool operator ==(EcsGroup a, EcsReadonlyGroup b) => a.Equals(b);
public static bool operator !=(EcsGroup a, EcsGroup b) => !a.Equals(b);
public static bool operator !=(EcsGroup a, EcsReadonlyGroup b) => !a.Equals(b);
#endregion
#region OnWorldResize
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void OnWorldResize(int newSize)
{
Array.Resize(ref _sparse, newSize);
}
#endregion
#region IDisposable/Release
public void Dispose()
{
Release();
}
public void Release()
{
_isReleazed = true;
_source.ReleaseGroup(this);
}
#endregion
}

View File

@ -10,7 +10,6 @@ namespace DCFApixels.DragonECS
public Type ComponentType { get; }
public int ComponentID { get; }
public IEcsWorld World { get; }
public EcsReadonlyGroup Entities { get; }
public int Count { get; }
public int Capacity { get; }
public bool Has(int entityID);
@ -34,7 +33,6 @@ namespace DCFApixels.DragonECS
public Type ComponentType => typeof(NullComponent);
public int ComponentID => -1;
public IEcsWorld World => _source;
public EcsReadonlyGroup Entities => default;
public int Count => 0;
public int Capacity => 1;
public void Del(int index) { }
@ -47,7 +45,6 @@ namespace DCFApixels.DragonECS
}
public abstract class EcsPool
{
internal EcsGroup entities;
public abstract bool Has(int entityID);
internal abstract void OnWorldResize(int newSize);
}
@ -66,7 +63,6 @@ namespace DCFApixels.DragonECS
private IEcsComponentReset<T> _componentResetHandler;
private PoolRunnres _poolRunnres;
#region Properites
public EcsReadonlyGroup Entities => entities.Readonly;
public int Count => _itemsCount;
public int Capacity => _items.Length;
public IEcsWorld World => _source;
@ -77,7 +73,6 @@ namespace DCFApixels.DragonECS
#region Constructors
internal EcsPool(IEcsWorld source, int id, int capacity, PoolRunnres poolRunnres)
{
entities = new EcsGroup(source);
_source = source;
_componentID = id;
@ -105,7 +100,6 @@ namespace DCFApixels.DragonECS
ref int itemIndex = ref _mapping[entityID];
if (itemIndex <= 0)
{
entities.Add(entityID);
if (_recycledItemsCount > 0)
{
itemIndex = _recycledItems[--_recycledItemsCount];
@ -147,8 +141,6 @@ namespace DCFApixels.DragonECS
{
// using (_delMark.Auto())
// {
entities.Remove(entityID);
if (_recycledItemsCount >= _recycledItems.Length)
Array.Resize(ref _recycledItems, _recycledItems.Length << 1);
_recycledItems[_recycledItemsCount++] = _mapping[entityID];
@ -168,7 +160,7 @@ namespace DCFApixels.DragonECS
#region Object
public override bool Equals(object obj) => base.Equals(obj);
public override int GetHashCode() => _source.GetHashCode() + ~ComponentID;
public override int GetHashCode() => _source.GetHashCode() ^ ~ComponentID;
#endregion
#region Internal

View File

@ -16,46 +16,37 @@ namespace DCFApixels.DragonECS
private ProfilerMarker _getEnumerator = new ProfilerMarker("EcsQuery.GetEnumerator");
public EcsGroup.Enumerator GetEnumerator()
{
using (_getEnumerator.Auto())
{
// groupFilter.Clear();
var pools = World.GetAllPools();
//
// if (mask.Inc.Length > 0)
// {
// groupFilter.CopyFrom(pools[mask.Inc[0]].entities);
// for (int i = 1; i < mask.Inc.Length; i++)
// {
// groupFilter.AndWith(pools[mask.Inc[i]].entities);
// }
// }
// else
// {
// groupFilter.CopyFrom(World.Entities);
// }
// for (int i = 0; i < mask.Exc.Length; i++)
// {
// groupFilter.RemoveGroup(pools[mask.Exc[i]].entities);
// }
//
// groupFilter.Sort();
// return groupFilter.GetEnumerator();
//
EcsReadonlyGroup sum = World.Entities;
for (int i = 0; i < mask.Inc.Length; i++)
var pools = World.GetAllPools();
EcsReadonlyGroup all = World.Entities;
groupFilter.Clear();
foreach (var e in all)
{
sum = EcsGroup.And(sum.GetGroupInternal(), pools[mask.Inc[i]].entities);
// Debug.Log("inc " + sum.ToString());
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);
}
for (int i = 0; i < mask.Exc.Length; i++)
{
sum = EcsGroup.Remove(sum.GetGroupInternal(), pools[mask.Exc[i]].entities);
// Debug.Log("exc " + sum.ToString());
}
//sum.GetGroupInternal().Sort();
return sum.GetEnumerator();
groupFilter.Sort();
return groupFilter.GetEnumerator();
}
}
protected virtual void Init(Builder b) { }
@ -85,7 +76,8 @@ namespace DCFApixels.DragonECS
}
builder.End(out newQuery.mask);
newQuery.groupFilter = new EcsGroup(world);
// newQuery.groupFilter = new EcsGroup(world);
newQuery.groupFilter = EcsGroup.New(world);
return (TQuery)(object)newQuery;
}
@ -96,7 +88,6 @@ namespace DCFApixels.DragonECS
_exc = new List<int>(4);
}
#region Init query member methods
public override inc<TComponent> Include<TComponent>() where TComponent : struct
{
_inc.Add(_world.GetComponentID<TComponent>());
@ -111,18 +102,14 @@ namespace DCFApixels.DragonECS
{
return new opt<TComponent>(_world.GetPool<TComponent>());
}
#endregion
private void End(out EcsQueryMask mask)
{
_inc.Sort();
_exc.Sort();
mask = new EcsQueryMask(_world.ArchetypeType, _inc.ToArray(), _exc.ToArray());
_world = null;
_inc.Clear();
_inc = null;
_exc.Clear();
_exc = null;
}
}

View File

@ -1,67 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace DCFApixels.DragonECS
{
public class EcsTable
{
private IEcsPool[] _pools;
private EcsNullPool _nullPool;
private short[] _gens;
private short[] _componentCounts;
private int _entitiesCount;
private List<EcsQuery>[] _filtersByIncludedComponents;
private List<EcsQuery>[] _filtersByExcludedComponents;
private EcsQuery[] _queries;
private List<EcsGroup> _groups;
#region Properties
public int Count => _entitiesCount;
public int Capacity => _gens.Length;
public ReadOnlySpan<IEcsPool> GetAllPools() => new ReadOnlySpan<IEcsPool>(_pools);
#endregion
#region internal Add/Has/Remove
internal void Add(int entityID)
{
int entity;
if (_entitiesCount >= _gens.Length)
{
Array.Resize(ref _gens, _gens.Length << 1);
Array.Resize(ref _componentCounts, _componentCounts.Length << 1);
}
_gens[_entitiesCount++]++;
_componentCounts[_entitiesCount++] = 0;
// if (_gens.Length <= entityID)
// {
// //TODO есть проблема что если передать слишком большой id такой алогоритм не сработает
// }
}
internal void Has(int entityID)
{
}
internal void Remove(int entityID)
{
}
#endregion
//public int GetComponentID<T>() => ;
}
}

View File

@ -33,7 +33,7 @@ namespace DCFApixels.DragonECS
public abstract class EcsWorld
{
internal static IEcsWorld[] Worlds = new IEcsWorld[8];
public static IEcsWorld[] Worlds = new IEcsWorld[8];
private static IntDispenser _worldIdDispenser = new IntDispenser(0);
public readonly short id;
@ -196,18 +196,12 @@ namespace DCFApixels.DragonECS
}
#endregion
#region IsMaskCompatible/IsMaskCompatibleWithout
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsMaskCompatible<TInc>(int entityID) where TInc : struct, IInc
{
return IsMaskCompatible(EcsMaskMap<TWorldArchetype>.GetMask<TInc, Exc>(), entityID);
}
#region IsMaskCompatible
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsMaskCompatible<TInc, TExc>(int entityID) where TInc : struct, IInc where TExc : struct, IExc
{
return IsMaskCompatible(EcsMaskMap<TWorldArchetype>.GetMask<TInc, TExc>(), entityID);
}
public bool IsMaskCompatible(EcsComponentMask mask, int entityID)
{
#if (DEBUG && !DISABLE_DRAGONECS_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
@ -348,9 +342,7 @@ namespace DCFApixels.DragonECS
EcsGroup IEcsWorld.GetGroupFromPool()
{
if (_pool.Count <= 0)
{
return new EcsGroup(this);
}
return _pool.Pop();
}
void IEcsWorld.ReleaseGroup(EcsGroup group)

View File

@ -1,5 +1,6 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using UnityEngine.Rendering;
namespace DCFApixels.DragonECS
{

36
src/TestPool.cs Normal file
View File

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DCFApixels.DragonECS.Test
{
public class TestWorld
{
public PoolToken RegisterPool<TComponent>()
{
return new PoolToken(1);
}
}
public readonly struct PoolToken
{
internal readonly ushort id;
public PoolToken(ushort id)
{
this.id = id;
}
}
//реализовать query так чтоб на вход он получал какуюто коллекцию и заполнял ее. по итогу на выходе запроса юзер будет иметь просто список
//таким образом во первых он сам может решить как его прокрутить, через for или foreach или еще как. во вторых можно будет прикрутить поддержку nativearray от unity
public class TestPool<TComponent>
{
private PoolToken _token;
public TestPool(TestWorld world)
{
_token = world.RegisterPool<TComponent>();
}
}
}