update mask building

This commit is contained in:
Mikhail 2024-01-07 19:32:16 +08:00
parent b34f8add00
commit e9cdfbfb51
8 changed files with 82 additions and 145 deletions

View File

@ -514,7 +514,7 @@ namespace DCFApixels.DragonECS
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (_source != group.World) Throw.Group_ArgumentDifferentWorldsException();
#endif
if(group.Count > Count)
if (group.Count > Count)
{
foreach (var item in this)
if (group.Has(item))

View File

@ -37,7 +37,7 @@ namespace DCFApixels.DragonECS
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _values.IsEmpty;
}
}
#endregion
#region Constructors

View File

@ -17,5 +17,7 @@
public const string POST_END_LAYER = nameof(POST_END_LAYER);
public const string META_HIDDEN_TAG = "HiddenInDebagging";
public const int MAGIC_PRIME = 314159;
}
}

View File

@ -2,7 +2,6 @@
using DCFApixels.DragonECS.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
@ -34,20 +33,16 @@ namespace DCFApixels.DragonECS
public sealed class Builder : EcsAspectBuilderBase
{
private EcsWorld _world;
private HashSet<int> _inc;
private HashSet<int> _exc;
private List<Combined> _combined;
private EcsMask.Builder _maskBuilder;
public EcsWorld World => _world;
private Builder(EcsWorld world)
{
_world = world;
_combined = new List<Combined>();
_inc = new HashSet<int>();
_exc = new HashSet<int>();
_maskBuilder = new EcsMask.Builder(world);
}
internal static unsafe TAspect Build<TAspect>(EcsWorld world) where TAspect : EcsAspect
internal static unsafe TAspect New<TAspect>(EcsWorld world) where TAspect : EcsAspect
{
Builder builder = new Builder(world);
Type aspectType = typeof(TAspect);
@ -63,7 +58,7 @@ namespace DCFApixels.DragonECS
newAspect.Init(builder);
}
newAspect._source = world;
builder.End(out newAspect._mask);
builder.Build(out newAspect._mask);
newAspect._isInit = true;
newAspect._sortIncBuffer = new UnsafeArray<int>(newAspect._mask.inc.Length, true);
@ -92,7 +87,7 @@ namespace DCFApixels.DragonECS
return (TAspect)newAspect;
}
#region Include/Exclude/Optional
#region Include/Exclude/Optional/Combine
public sealed override TPool Include<TPool>()
{
IncludeImplicit(typeof(TPool).GetGenericArguments()[0]);
@ -109,27 +104,16 @@ namespace DCFApixels.DragonECS
}
private void IncludeImplicit(Type type)
{
int id = _world.GetComponentID(type);
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (_inc.Contains(id) || _exc.Contains(id)) Throw.ConstraintIsAlreadyContainedInMask(type);
#endif
_inc.Add(id);
_maskBuilder.Include(type);
}
private void ExcludeImplicit(Type type)
{
int id = _world.GetComponentID(type);
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (_inc.Contains(id) || _exc.Contains(id)) Throw.ConstraintIsAlreadyContainedInMask(type);
#endif
_exc.Add(id);
_maskBuilder.Exclude(type);
}
#endregion
#region Combine
public TOtherAspect Combine<TOtherAspect>(int order = 0) where TOtherAspect : EcsAspect
{
var result = _world.GetAspect<TOtherAspect>();
_combined.Add(new Combined(result, order));
_maskBuilder.CombineWith(result.Mask);
return result;
}
#endregion
@ -139,60 +123,9 @@ namespace DCFApixels.DragonECS
return new EcsWorldCmp<T>(_world.id);
}
private void End(out EcsMask mask)
private void Build(out EcsMask mask)
{
HashSet<int> maskInc;
HashSet<int> maskExc;
if (_combined.Count > 0)
{
maskInc = new HashSet<int>();
maskExc = new HashSet<int>();
_combined.Sort((a, b) => a.order - b.order);
foreach (var item in _combined)
{
EcsMask submask = item.aspect._mask;
maskInc.ExceptWith(submask.exc);//удаляю конфликтующие ограничения
maskExc.ExceptWith(submask.inc);//удаляю конфликтующие ограничения
maskInc.UnionWith(submask.inc);
maskExc.UnionWith(submask.exc);
}
maskInc.ExceptWith(_exc);//удаляю конфликтующие ограничения
maskExc.ExceptWith(_inc);//удаляю конфликтующие ограничения
maskInc.UnionWith(_inc);
maskExc.UnionWith(_exc);
}
else
{
maskInc = _inc;
maskExc = _exc;
}
Dictionary<int, int> r = new Dictionary<int, int>();
foreach (var id in maskInc)
{
var bit = EcsMaskChunck.FromID(id);
if (!r.TryAdd(bit.chankIndex, bit.mask))
r[bit.chankIndex] = r[bit.chankIndex] | bit.mask;
}
EcsMaskChunck[] incMasks = r.Select(o => new EcsMaskChunck(o.Key, o.Value)).ToArray();
r.Clear();
foreach (var id in maskExc)
{
var bit = EcsMaskChunck.FromID(id);
if (!r.TryAdd(bit.chankIndex, bit.mask))
r[bit.chankIndex] = r[bit.chankIndex] | bit.mask;
}
EcsMaskChunck[] excMasks = r.Select(o => new EcsMaskChunck(o.Key, o.Value)).ToArray();
var inc = maskInc.ToArray();
Array.Sort(inc);
var exc = maskExc.ToArray();
Array.Sort(exc);
mask = new EcsMask(0, _world.id, inc, exc, incMasks, excMasks);
_world = null;
_inc = null;
_exc = null;
mask = _maskBuilder.Build();
}
#region SupportReflectionHack
@ -281,7 +214,7 @@ namespace DCFApixels.DragonECS
int count = 0;
while (enumerator.MoveNext())
{
if(array.Length <= count)
if (array.Length <= count)
Array.Resize(ref array, array.Length << 1);
array[count++] = enumerator.Current;
}
@ -365,15 +298,11 @@ namespace DCFApixels.DragonECS
UnsafeArray<int> _sortExcBuffer = aspect._sortExcBuffer;
_sortIncChunckBuffer = aspect._sortIncChunckBuffer;
_sortExcChunckBuffer = aspect._sortExcChunckBuffer;
int[] counts = mask.World._poolComponentCounts;
#region Sort
IncCountComparer incComparer = new IncCountComparer(counts);
ExcCountComparer excComparer = new ExcCountComparer(counts);
#region Sort
UnsafeArraySortHalperX<int>.InsertionSort(_sortIncBuffer.ptr, _sortIncBuffer.Length, ref incComparer);
UnsafeArraySortHalperX<int>.InsertionSort(_sortExcBuffer.ptr, _sortExcBuffer.Length, ref excComparer);
@ -476,9 +405,6 @@ namespace DCFApixels.DragonECS
_preSortedExcBuffer[i] = EcsMaskChunck.FromID(_sortExcBuffer.ptr[i]);
}
//int _sortedIncBufferLength = mask.inc.Length;
//int _sortedExcBufferLength = mask.exc.Length;
//if (_sortIncChunckBuffer.Length > 1)//перенести этот чек в начала сортировки, для _incChunckMasks.Length == 1 сортировка не нужна
if (_sortIncBuffer.Length > 1)
{

View File

@ -4,7 +4,6 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using static Leopotam.EcsLite.EcsWorld;
namespace DCFApixels.DragonECS
{
@ -13,38 +12,17 @@ namespace DCFApixels.DragonECS
private Dictionary<EcsMask.BuilderMaskKey, EcsMask> _masks = new Dictionary<EcsMask.BuilderMaskKey, EcsMask>(256);
internal EcsMask GetMask_Internal(EcsMask.BuilderMaskKey maskKey)
{
if(!_masks.TryGetValue(maskKey, out EcsMask result))
if (!_masks.TryGetValue(maskKey, out EcsMask result))
{
int[] combinedInc = maskKey.inc;
int[] combinedExc = maskKey.exc;
Dictionary<int, int> r = new Dictionary<int, int>();
foreach (var id in combinedInc)
{
var bit = EcsMaskChunck.FromID(id);
if (!r.TryAdd(bit.chankIndex, bit.mask))
r[bit.chankIndex] = r[bit.chankIndex] | bit.mask;
}
EcsMaskChunck[] incMasks = r.Select(o => new EcsMaskChunck(o.Key, o.Value)).ToArray();
r.Clear();
foreach (var id in combinedExc)
{
var bit = EcsMaskChunck.FromID(id);
if (!r.TryAdd(bit.chankIndex, bit.mask))
r[bit.chankIndex] = r[bit.chankIndex] | bit.mask;
}
EcsMaskChunck[] excMasks = r.Select(o => new EcsMaskChunck(o.Key, o.Value)).ToArray();
result = new EcsMask(_masks.Count, id, combinedInc, combinedExc, incMasks, excMasks);
result = new EcsMask(_masks.Count, id, maskKey.inc, maskKey.exc);
_masks.Add(maskKey, result);
}
return result;
}
}
[DebuggerTypeProxy(typeof(DebuggerProxy))]
public sealed class EcsMask
public sealed class EcsMask : IEquatable<EcsMask>
{
internal readonly int id;
internal readonly int worldID;
@ -58,7 +36,7 @@ namespace DCFApixels.DragonECS
public ReadOnlySpan<int> Inc => inc;
/// <summary>Excluding constraints</summary>
public ReadOnlySpan<int> Exc => exc;
internal EcsMask(int id, int worldID, int[] inc, int[] exc, EcsMaskChunck[] incChunckMasks, EcsMaskChunck[] excChunckMasks)
internal EcsMask(int id, int worldID, int[] inc, int[] exc)
{
#if DEBUG
CheckConstraints(inc, exc);
@ -67,12 +45,43 @@ namespace DCFApixels.DragonECS
this.inc = inc;
this.exc = exc;
this.worldID = worldID;
this.incChunckMasks = incChunckMasks;
this.excChunckMasks = excChunckMasks;
//TODO пересесть с дикта на подсчет в цикле.
Dictionary<int, int> r = new Dictionary<int, int>();
foreach (var cmpID in inc)
{
var bit = EcsMaskChunck.FromID(cmpID);
if (!r.TryAdd(bit.chankIndex, bit.mask))
r[bit.chankIndex] = r[bit.chankIndex] | bit.mask;
}
EcsMaskChunck[] incMasks = r.Select(o => new EcsMaskChunck(o.Key, o.Value)).ToArray();
r.Clear();
foreach (var cmpID in exc)
{
var bit = EcsMaskChunck.FromID(cmpID);
if (!r.TryAdd(bit.chankIndex, bit.mask))
r[bit.chankIndex] = r[bit.chankIndex] | bit.mask;
}
EcsMaskChunck[] excMasks = r.Select(o => new EcsMaskChunck(o.Key, o.Value)).ToArray();
incChunckMasks = incMasks;
excChunckMasks = excMasks;
}
#region Object
public override string ToString() => CreateLogString(worldID, inc, exc);
public bool Equals(EcsMask mask)
{
return id == mask.id && worldID == mask.worldID;
}
public override bool Equals(object obj)
{
return obj is EcsMask mask && id == mask.id && Equals(mask);
}
public override int GetHashCode()
{
return unchecked(id ^ (worldID * EcsConsts.MAGIC_PRIME));
}
#endregion
#region Debug utils
@ -109,10 +118,12 @@ namespace DCFApixels.DragonECS
return $"Inc({string.Join(", ", inc)}) Exc({string.Join(", ", exc)})"; // Release optimization
#endif
}
internal class DebuggerProxy
{
public readonly int ID;
public readonly EcsWorld world;
public readonly int worldID;
private readonly int _worldID;
public readonly EcsMaskChunck[] includedChunkMasks;
public readonly EcsMaskChunck[] excludedChunkMasks;
public readonly int[] included;
@ -122,8 +133,9 @@ namespace DCFApixels.DragonECS
public DebuggerProxy(EcsMask mask)
{
ID = mask.id;
world = EcsWorld.GetWorld(mask.worldID);
worldID = mask.worldID;
_worldID = mask.worldID;
includedChunkMasks = mask.incChunckMasks;
excludedChunkMasks = mask.excChunckMasks;
included = mask.inc;
@ -132,10 +144,11 @@ namespace DCFApixels.DragonECS
includedTypes = included.Select(converter).ToArray();
excludedTypes = excluded.Select(converter).ToArray();
}
public override string ToString() => CreateLogString(worldID, included, excluded);
public override string ToString() => CreateLogString(_worldID, included, excluded);
}
#endregion
#region Builder
public readonly struct BuilderMaskKey : IEquatable<BuilderMaskKey>
{
public readonly int[] inc;
@ -173,7 +186,7 @@ namespace DCFApixels.DragonECS
}
}
#if DEBUG
if(other.hash != hash)
if (other.hash != hash)
{
throw new Exception("other.hash != hash");
}
@ -186,16 +199,14 @@ namespace DCFApixels.DragonECS
public class Builder
{
private EcsWorld _world;
private HashSet<int> _inc;
private HashSet<int> _exc;
private List<Combined> _combined;
private readonly EcsWorld _world;
private readonly HashSet<int> _inc = new HashSet<int>();
private readonly HashSet<int> _exc = new HashSet<int>();
private readonly List<Combined> _combined = new List<Combined>();
internal Builder(EcsWorld world)
{
_world = world;
_inc = new HashSet<int>();
_exc = new HashSet<int>();
}
public void Include<T>()
@ -269,23 +280,20 @@ namespace DCFApixels.DragonECS
var exc = combinedExc.ToArray();
Array.Sort(exc);
int keyHash = inc.Length + exc.Length;
for (int i = 0, iMax = inc.Length; i < iMax; i++)
unchecked
{
keyHash = unchecked(keyHash * 314159 + inc[i]);
int keyHash = inc.Length + exc.Length;
for (int i = 0, iMax = inc.Length; i < iMax; i++)
{
keyHash = keyHash * EcsConsts.MAGIC_PRIME + inc[i];
}
for (int i = 0, iMax = exc.Length; i < iMax; i++)
{
keyHash = keyHash * EcsConsts.MAGIC_PRIME - exc[i];
}
BuilderMaskKey key = new BuilderMaskKey(inc, exc, keyHash);
return _world.GetMask_Internal(key);
}
for (int i = 0, iMax = exc.Length; i < iMax; i++)
{
keyHash = unchecked(keyHash * 314159 - exc[i]);
}
BuilderMaskKey key = new BuilderMaskKey(inc, exc, keyHash);
_world = null;
_inc = null;
_exc = null;
_combined = null;
return _world.GetMask_Internal(key);
}
}
@ -299,6 +307,7 @@ namespace DCFApixels.DragonECS
this.order = order;
}
}
#endregion
}
[DebuggerTypeProxy(typeof(DebuggerProxy))]

View File

@ -23,7 +23,7 @@
public AspectCache(T instance) => this.instance = instance;
void IEcsWorldComponent<AspectCache<T>>.Init(ref AspectCache<T> component, EcsWorld world)
{
component = new AspectCache<T>(EcsAspect.Builder.Build<T>(world));
component = new AspectCache<T>(EcsAspect.Builder.New<T>(world));
}
void IEcsWorldComponent<AspectCache<T>>.OnDestroy(ref AspectCache<T> component, EcsWorld world)
{

View File

@ -142,7 +142,7 @@ namespace DCFApixels.DragonECS
#region Where Query
public EcsReadonlyGroup WhereToGroupFor<TAspect>(EcsSpan span, out TAspect aspect) where TAspect : EcsAspect
{
if(_isEnableReleaseDelEntBuffer)
if (_isEnableReleaseDelEntBuffer)
{
ReleaseDelEntityBufferAll();
}

View File

@ -96,7 +96,7 @@ namespace DCFApixels.DragonECS
{
itemIndex = ++_count;
}
if(_items.Length <= itemIndex)
if (_items.Length <= itemIndex)
{
Array.Resize(ref _items, _items.Length << 1);
}