This commit is contained in:
DCFApixels 2024-11-26 01:49:39 +08:00
parent 95eecf98e5
commit 2cc7a22e95
2 changed files with 94 additions and 90 deletions

View File

@ -181,8 +181,13 @@ namespace DCFApixels.DragonECS
public unsafe partial class EcsWorld public unsafe partial class EcsWorld
{ {
private List<WeakReference<EcsGroup>> _groups = new List<WeakReference<EcsGroup>>();
private Stack<EcsGroup> _groupsPool = new Stack<EcsGroup>(64);
private int*[] _groupSparsePagePool = new int*[64]; private int*[] _groupSparsePagePool = new int*[64];
private int _groupSparsePagePoolCount = 0; private int _groupSparsePagePoolCount = 0;
#region Pages
internal int* TakePage() internal int* TakePage()
{ {
if(_groupSparsePagePoolCount <= 0) if(_groupSparsePagePoolCount <= 0)
@ -192,7 +197,7 @@ namespace DCFApixels.DragonECS
} }
return _groupSparsePagePool[--_groupSparsePagePoolCount]; return _groupSparsePagePool[--_groupSparsePagePoolCount];
} }
internal void ReternPage(int* page) internal void ReturnPage(int* page)
{ {
if (_groupSparsePagePoolCount >= _groupSparsePagePool.Length) if (_groupSparsePagePoolCount >= _groupSparsePagePool.Length)
{ {
@ -205,6 +210,35 @@ namespace DCFApixels.DragonECS
} }
_groupSparsePagePool[_groupSparsePagePoolCount++] = page; _groupSparsePagePool[_groupSparsePagePoolCount++] = page;
} }
#endregion
#region Groups Pool
private void RemoveGroupAt(int index)
{
int last = _groups.Count - 1;
_groups[index] = _groups[last];
_groups.RemoveAt(last);
}
internal void RegisterGroup(EcsGroup group)
{
_groups.Add(new WeakReference<EcsGroup>(group));
}
internal EcsGroup GetFreeGroup()
{
EcsGroup result = _groupsPool.Count <= 0 ? new EcsGroup(this, _configs.GetWorldConfigOrDefault().GroupCapacity) : _groupsPool.Pop();
result._isReleased = false;
return result;
}
internal void ReleaseGroup(EcsGroup group)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (group.World != this) { Throw.World_GroupDoesNotBelongWorld(); }
#endif
group._isReleased = true;
group.Clear();
_groupsPool.Push(group);
}
#endregion
} }
#if ENABLE_IL2CPP #if ENABLE_IL2CPP
@ -213,14 +247,13 @@ namespace DCFApixels.DragonECS
#endif #endif
[DebuggerTypeProxy(typeof(DebuggerProxy))] [DebuggerTypeProxy(typeof(DebuggerProxy))]
//TODO переработать EcsGroup в структуру-обертку, чтобы когда вызывается Release то можно было занулить эту структуру, а может не перерабатывать, есть проблема с боксингом //TODO переработать EcsGroup в структуру-обертку, чтобы когда вызывается Release то можно было занулить эту структуру, а может не перерабатывать, есть проблема с боксингом
public unsafe class EcsGroup : IDisposable, IEnumerable<int>, IEntityStorage, ISet<int> public unsafe class EcsGroup : IDisposable, IEnumerable<int>, ISet<int>, IEntityStorage
{ {
internal const int PAGE_SIZE = Page.SIZE; internal const int PAGE_SIZE = PageSlot.SIZE;
private EcsWorld _source; private EcsWorld _source;
private int[] _dense; private int[] _dense; // 0 индекс для нулевой записи
private Page* _sparse; //Старший бит занят временной маркировкой в операциях над множествами private PageSlot* _sparsePages; //Старший бит занят временной маркировкой в операциях над множествами
private int _pagesCount; private int _sparsePagesCount;
private int _totalCapacity; private int _totalCapacity;
private int _count = 0; private int _count = 0;
internal bool _isReleased = true; internal bool _isReleased = true;
@ -300,8 +333,8 @@ namespace DCFApixels.DragonECS
_dense = new int[denseCapacity]; _dense = new int[denseCapacity];
//_sparse = new int[world.Capacity]; //_sparse = new int[world.Capacity];
_totalCapacity = world.Capacity; _totalCapacity = world.Capacity;
_pagesCount = CalcSparseSize(_totalCapacity); _sparsePagesCount = CalcSparseSize(_totalCapacity);
_sparse = UnmanagedArrayUtility.NewAndInit<Page>(_pagesCount); _sparsePages = UnmanagedArrayUtility.NewAndInit<PageSlot>(_sparsePagesCount);
} }
public void Dispose() public void Dispose()
{ {
@ -314,21 +347,21 @@ namespace DCFApixels.DragonECS
public bool Has(int entityID) public bool Has(int entityID)
{ {
//return _sparse[entityID] != 0; //return _sparse[entityID] != 0;
Page* page = _sparse + (entityID >> Page.SHIFT); PageSlot* page = _sparsePages + (entityID >> PageSlot.SHIFT);
ReadOnlySpan<int> span = default; ReadOnlySpan<int> span = default;
if (page->Indexes != null) if (page->Indexes != null)
{ {
span = new ReadOnlySpan<int>(page->Indexes, Page.SIZE); span = new ReadOnlySpan<int>(page->Indexes, PageSlot.SIZE);
} }
return page->Indexes != null && page->Indexes[entityID & Page.MASK] != 0; return page->Indexes != null && page->Indexes[entityID & PageSlot.MASK] != 0;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public int IndexOf(int entityID) public int IndexOf(int entityID)
{ {
//return _sparse[entityID]; //return _sparse[entityID];
Page* page = _sparse + (entityID >> Page.SHIFT); PageSlot* page = _sparsePages + (entityID >> PageSlot.SHIFT);
return page->Indexes != null ? page->Indexes[entityID & Page.MASK] : -1; return page->Indexes != null ? page->Indexes[entityID & PageSlot.MASK] : 0;
} }
#endregion #endregion
@ -354,21 +387,21 @@ namespace DCFApixels.DragonECS
{ {
if (++_count >= _dense.Length) if (++_count >= _dense.Length)
{ {
Array.Resize(ref _dense, _dense.Length << 1); Array.Resize(ref _dense, ArrayUtility.NormalizeSizeToPowerOfTwo(_count << 1));
} }
_dense[_count] = entityID; _dense[_count] = entityID;
//_sparse[entityID] = _count; //_sparse[entityID] = _count;
Page* page = _sparse + (entityID >> Page.SHIFT); PageSlot* page = _sparsePages + (entityID >> PageSlot.SHIFT);
if(page->Indexes == null) if(page->Count == 0)
{ {
page->Indexes = _source.TakePage(); page->Indexes = _source.TakePage();
if(page->Indexes == null) //if(page->Indexes == null)
{ //{
//
} //}
} }
page->Indexes[entityID & Page.MASK] = _count; page->Indexes[entityID & PageSlot.MASK] = _count;
page->Count++; page->Count++;
} }
@ -395,18 +428,24 @@ namespace DCFApixels.DragonECS
//_sparse[_dense[_count--]] = _sparse[entityID]; //_sparse[_dense[_count--]] = _sparse[entityID];
//_sparse[entityID] = 0; //_sparse[entityID] = 0;
Page* page = _sparse + (entityID >> Page.SHIFT); PageSlot* page = _sparsePages + (entityID >> PageSlot.SHIFT);
int localEntityID = entityID & Page.MASK; int localEntityID = entityID & PageSlot.MASK;
_dense[page->Indexes[localEntityID]] = _dense[_count]; _dense[page->Indexes[localEntityID]] = _dense[_count];
int localLastIndex = _dense[_count--]; int localLastIndex = _dense[_count--];
int* lastPageArray = (_sparse + (localLastIndex >> Page.SHIFT))->Indexes; int* lastPageArray = (_sparsePages + (localLastIndex >> PageSlot.SHIFT))->Indexes;
localLastIndex = localLastIndex & Page.MASK; localLastIndex = localLastIndex & PageSlot.MASK;
lastPageArray[localLastIndex] = page->Indexes[localEntityID]; lastPageArray[localLastIndex] = page->Indexes[localEntityID];
page->Indexes[localEntityID] = 0; if (--page->Count == 0)
page->Count--; {
_source.ReturnPage(page->Indexes);
}
else
{
page->Indexes[localEntityID] = 0;
}
} }
public void RemoveUnusedEntityIDs() public void RemoveUnusedEntityIDs()
@ -432,17 +471,17 @@ namespace DCFApixels.DragonECS
//{ //{
// _sparse[_dense[i]] = 0; // _sparse[_dense[i]] = 0;
//} //}
for (int i = 0; i < _pagesCount; i++) for (int i = 0; i < _sparsePagesCount; i++)
{ {
var page = _sparse + i; var page = _sparsePages + i;
if (page->Indexes != null) if (page->Indexes != null)
{ {
//TODO тут надо оптимизировать отчисткой не всего а по dense списку //TODO тут надо оптимизировать отчисткой не всего а по dense списку
for (int j = 0; j < Page.SIZE; j++) for (int j = 0; j < PageSlot.SIZE; j++)
{ {
page->Indexes[j] = 0; page->Indexes[j] = 0;
} }
_source.ReternPage(page->Indexes); _source.ReturnPage(page->Indexes);
page->Indexes = null; page->Indexes = null;
} }
page->Count = 0; page->Count = 0;
@ -669,7 +708,7 @@ namespace DCFApixels.DragonECS
{ {
if (Has(entityID)) if (Has(entityID))
{ {
Mark_Internal(entityID); MarkEntity_Internal(entityID);
} }
} }
ClearUnmarked_Internal(); ClearUnmarked_Internal();
@ -693,7 +732,7 @@ namespace DCFApixels.DragonECS
{ {
if (Has(entityID)) if (Has(entityID))
{ {
Mark_Internal(entityID); MarkEntity_Internal(entityID);
} }
} }
ClearUnmarked_Internal(); ClearUnmarked_Internal();
@ -1259,7 +1298,7 @@ namespace DCFApixels.DragonECS
{ {
if (result.Has(entityID)) if (result.Has(entityID))
{ {
result.Mark_Internal(entityID); result.MarkEntity_Internal(entityID);
} }
else else
{ {
@ -1335,22 +1374,22 @@ namespace DCFApixels.DragonECS
#region HiBitMarking #region HiBitMarking
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Mark_Internal(int entityID) private void MarkEntity_Internal(int entityID)
{ {
throw new NotImplementedException(); //throw new NotImplementedException();
//_sparse[entityID] |= int.MinValue; //_sparse[entityID] |= int.MinValue;
_dense[IndexOf(entityID)] |= int.MinValue;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool IsMark_Internal(int entityID) private bool IsMarkIndex_Internal(int index)
{ {
throw new NotImplementedException(); return (_dense[index] & int.MinValue) == int.MinValue;
//return (_sparse[entityID] & int.MinValue) == int.MinValue;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Unmark_Internal(int entityID) private void UnmarkIndex_Internal(int index)
{ {
throw new NotImplementedException(); _dense[index] &= int.MaxValue;
//_sparse[entityID] &= int.MaxValue;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ClearUnmarked_Internal() private void ClearUnmarked_Internal()
@ -1358,9 +1397,9 @@ namespace DCFApixels.DragonECS
for (int i = _count; i > 0; i--)//итерация в обратном порядке исключает ошибки при удалении элементов for (int i = _count; i > 0; i--)//итерация в обратном порядке исключает ошибки при удалении элементов
{ {
int entityID = _dense[i]; int entityID = _dense[i];
if (IsMark_Internal(entityID)) if (IsMarkIndex_Internal(i))
{ {
Unmark_Internal(entityID); UnmarkIndex_Internal(i);
} }
else else
{ {
@ -1374,9 +1413,9 @@ namespace DCFApixels.DragonECS
for (int i = _count; i > 0; i--)//итерация в обратном порядке исключает ошибки при удалении элементов for (int i = _count; i > 0; i--)//итерация в обратном порядке исключает ошибки при удалении элементов
{ {
int entityID = _dense[i]; int entityID = _dense[i];
if (IsMark_Internal(entityID)) if (IsMarkIndex_Internal(i))
{ {
Unmark_Internal(entityID); // Unmark_Internal должен быть до Remove_Internal UnmarkIndex_Internal(i); // Unmark_Internal должен быть до Remove_Internal
Remove_Internal(entityID); Remove_Internal(entityID);
} }
} }
@ -1393,9 +1432,9 @@ namespace DCFApixels.DragonECS
{ {
//Array.Resize(ref _sparse, newSize); //Array.Resize(ref _sparse, newSize);
_totalCapacity = newSize; _totalCapacity = newSize;
var oldPagesCount = _pagesCount; var oldPagesCount = _sparsePagesCount;
_pagesCount = CalcSparseSize(_totalCapacity); _sparsePagesCount = CalcSparseSize(_totalCapacity);
_sparse = UnmanagedArrayUtility.ResizeAndInit<Page>(_sparse, oldPagesCount, _pagesCount); _sparsePages = UnmanagedArrayUtility.ResizeAndInit<PageSlot>(_sparsePages, oldPagesCount, _sparsePagesCount);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void OnReleaseDelEntityBuffer_Internal(ReadOnlySpan<int> buffer) internal void OnReleaseDelEntityBuffer_Internal(ReadOnlySpan<int> buffer)
@ -1446,24 +1485,20 @@ namespace DCFApixels.DragonECS
} }
#endregion #endregion
//[MethodImpl(MethodImplOptions.AggressiveInlining)] #region PageSlot
//private static (int, int) GetPage(int index)
//{
// int pageIndex = index >> Page.SIZE;
// return (_sparse + pageIndex, index & Page.MASK);
//}
private static int CalcSparseSize(int capacity) private static int CalcSparseSize(int capacity)
{ {
return (capacity >> Page.SHIFT) + ((capacity & Page.MASK) == 0 ? 0 : 1); return (capacity >> PageSlot.SHIFT) + ((capacity & PageSlot.MASK) == 0 ? 0 : 1);
} }
private struct Page private struct PageSlot
{ {
public const int SHIFT = 6; // 64 public const int SHIFT = 6; // 64
public const int SIZE = 1 << SHIFT; public const int SIZE = 1 << SHIFT;
public const int MASK = SIZE - 1; public const int MASK = SIZE - 1;
public int* Indexes; public int* Indexes;
public int Count; public byte Count;
} }
#endregion
} }
} }

View File

@ -67,9 +67,6 @@ namespace DCFApixels.DragonECS
//обновляется в NewEntity и в DelEntity //обновляется в NewEntity и в DelEntity
private long _version = 0; private long _version = 0;
private List<WeakReference<EcsGroup>> _groups = new List<WeakReference<EcsGroup>>();
private Stack<EcsGroup> _groupsPool = new Stack<EcsGroup>(64);
private List<IEcsWorldEventListener> _listeners = new List<IEcsWorldEventListener>(); private List<IEcsWorldEventListener> _listeners = new List<IEcsWorldEventListener>();
private List<IEcsEntityEventListener> _entityListeners = new List<IEcsEntityEventListener>(); private List<IEcsEntityEventListener> _entityListeners = new List<IEcsEntityEventListener>();
@ -775,34 +772,6 @@ namespace DCFApixels.DragonECS
} }
#endregion #endregion
#region Groups Pool
private void RemoveGroupAt(int index)
{
int last = _groups.Count - 1;
_groups[index] = _groups[last];
_groups.RemoveAt(last);
}
internal void RegisterGroup(EcsGroup group)
{
_groups.Add(new WeakReference<EcsGroup>(group));
}
internal EcsGroup GetFreeGroup()
{
EcsGroup result = _groupsPool.Count <= 0 ? new EcsGroup(this, _configs.GetWorldConfigOrDefault().GroupCapacity) : _groupsPool.Pop();
result._isReleased = false;
return result;
}
internal void ReleaseGroup(EcsGroup group)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (group.World != this) { Throw.World_GroupDoesNotBelongWorld(); }
#endif
group._isReleased = true;
group.Clear();
_groupsPool.Push(group);
}
#endregion
#region Listeners #region Listeners
public void AddListener(IEcsWorldEventListener worldEventListener) public void AddListener(IEcsWorldEventListener worldEventListener)
{ {