From ad2bcae5ad5285210a8767d0262233a792a67395 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Wed, 6 Nov 2024 13:46:20 +0800 Subject: [PATCH] update Copy/Clone(Entity) add Move/Remove(Components) --- src/EcsAspect.cs | 28 ++--- src/EcsMask.cs | 10 +- src/EcsWorld.cs | 244 +++++++++++++++++++++++++++++++++++++++--- src/EcsWorld.pools.cs | 16 +-- 4 files changed, 257 insertions(+), 41 deletions(-) diff --git a/src/EcsAspect.cs b/src/EcsAspect.cs index 2bc26a1..98b7dfe 100644 --- a/src/EcsAspect.cs +++ b/src/EcsAspect.cs @@ -44,7 +44,7 @@ namespace DCFApixels.DragonECS internal EcsWorld _source; internal EcsMask _mask; private bool _isBuilt = false; - private IEcsPool[] _pools; + //private IEcsPool[] _pools; #region Properties public EcsMask Mask @@ -59,10 +59,10 @@ namespace DCFApixels.DragonECS { get { return _isBuilt; } } - public ReadOnlySpan Pools - { - get { return _pools; } - } + //public ReadOnlySpan Pools + //{ + // get { return _pools; } + //} /// /// Статическая инициализация означет что каждый новый эекземпляр идентичен другому, инициализация стандартным путем создает идентичные экземпляры, поэтому значение по умолчанию true. /// @@ -86,8 +86,8 @@ namespace DCFApixels.DragonECS private EcsWorld _world; private EcsStaticMask.Builder _maskBuilder; - private IEcsPool[] _poolsBuffer = new IEcsPool[8]; - private int _poolsBufferCount; + //private IEcsPool[] _poolsBuffer = new IEcsPool[8]; + //private int _poolsBufferCount; #region Properties public IncludeMarker Inc @@ -154,8 +154,8 @@ namespace DCFApixels.DragonECS } } newAspect._mask = staticMask.ToMask(world); - var pools = new IEcsPool[builder._poolsBufferCount]; - Array.Copy(builder._poolsBuffer, pools, pools.Length); + //var pools = new IEcsPool[builder._poolsBufferCount]; + //Array.Copy(builder._poolsBuffer, pools, pools.Length); newAspect._isBuilt = true; _constructorBuildersStackIndex--; @@ -184,11 +184,11 @@ namespace DCFApixels.DragonECS private TPool CachePool() where TPool : IEcsPoolImplementation, new() { var pool = _world.GetPoolInstance(); - if (_poolsBufferCount >= _poolsBuffer.Length) - { - Array.Resize(ref _poolsBuffer, _poolsBuffer.Length << 1); - } - _poolsBuffer[_poolsBufferCount++] = pool; + //if (_poolsBufferCount >= _poolsBuffer.Length) + //{ + // Array.Resize(ref _poolsBuffer, _poolsBuffer.Length << 1); + //} + //_poolsBuffer[_poolsBufferCount++] = pool; return pool; } private void IncludeImplicit(Type type) diff --git a/src/EcsMask.cs b/src/EcsMask.cs index ff565d1..660d218 100644 --- a/src/EcsMask.cs +++ b/src/EcsMask.cs @@ -717,11 +717,11 @@ namespace DCFApixels.DragonECS { while (_span.MoveNext()) { - int chunck = _span.Current << _entityComponentMaskLengthBitShift; + int entityLineStartIndex = _span.Current << _entityComponentMaskLengthBitShift; for (int i = 0; i < _sortIncChunckBuffer.Length; i++) { var bit = _sortIncChunckBuffer.ptr[i]; - if ((_entityComponentMasks[chunck + bit.chunkIndex] & bit.mask) != bit.mask) + if ((_entityComponentMasks[entityLineStartIndex + bit.chunkIndex] & bit.mask) != bit.mask) { goto skip; } @@ -729,7 +729,7 @@ namespace DCFApixels.DragonECS for (int i = 0; i < _sortExcChunckBuffer.Length; i++) { var bit = _sortExcChunckBuffer.ptr[i]; - if ((_entityComponentMasks[chunck + bit.chunkIndex] & bit.mask) != 0) + if ((_entityComponentMasks[entityLineStartIndex + bit.chunkIndex] & bit.mask) != 0) { goto skip; } @@ -848,11 +848,11 @@ namespace DCFApixels.DragonECS { while (_span.MoveNext()) { - int chunck = _span.Current << _entityComponentMaskLengthBitShift; + int entityLineStartIndex = _span.Current << _entityComponentMaskLengthBitShift; for (int i = 0; i < _sortIncChunckBuffer.Length; i++) { var bit = _sortIncChunckBuffer.ptr[i]; - if ((_entityComponentMasks[chunck + bit.chunkIndex] & bit.mask) != bit.mask) + if ((_entityComponentMasks[entityLineStartIndex + bit.chunkIndex] & bit.mask) != bit.mask) { goto skip; } diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index b03a848..9631376 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -458,11 +458,59 @@ namespace DCFApixels.DragonECS } #endregion - #region Copy/Clone - public void CopyEntity(int fromEntityID, int toEntityID) + //TODO протестить Copy Clone Move Remove + + #region CopyEntity + public unsafe void CopyEntity(int fromEntityID, int toEntityID) { - foreach (var pool in _pools) + const int COMPONENT_MASK_CHUNK_SIZE_HALF = COMPONENT_MASK_CHUNK_SIZE / 2; + int entityLineStartIndex = fromEntityID << _entityComponentMaskLengthBitShift; + int poolIndexWithoutOffset = 0; + for (int i = 0; i < _entityComponentMaskLength; i++) { + int chunk = _entityComponentMasks[i]; + poolIndexWithoutOffset += COMPONENT_MASK_CHUNK_SIZE; + if (chunk != 0) + { + if ((chunk & 0x0000FFFF) != 0) + { + int bit = 1; + for (int j = 0; j < COMPONENT_MASK_CHUNK_SIZE_HALF; j++) + { + if ((bit & chunk) != 0) + { + _pools[poolIndexWithoutOffset + j].Copy(fromEntityID, toEntityID); + } + bit <<= 1; + } + } + if ((chunk & -0x7FFF0000) != 0) + { + int bit = 0x00010000; + for (int j = COMPONENT_MASK_CHUNK_SIZE_HALF; j < COMPONENT_MASK_CHUNK_SIZE; j++) + { + if ((bit & chunk) != 0) + { + _pools[poolIndexWithoutOffset + j].Copy(fromEntityID, toEntityID); + } + bit <<= 1; + } + } + } + } + //foreach (var pool in _pools) + //{ + // if (pool.Has(fromEntityID)) + // { + // pool.Copy(fromEntityID, toEntityID); + // } + //} + } + public void CopyEntity(int fromEntityID, int toEntityID, ReadOnlySpan componentTypeIDs) + { + foreach (var poolID in componentTypeIDs) + { + var pool = _pools[poolID]; if (pool.Has(fromEntityID)) { pool.Copy(fromEntityID, toEntityID); @@ -471,26 +519,89 @@ namespace DCFApixels.DragonECS } public void CopyEntity(int fromEntityID, EcsWorld toWorld, int toEntityID) { - foreach (var pool in _pools) + const int COMPONENT_MASK_CHUNK_SIZE_HALF = COMPONENT_MASK_CHUNK_SIZE / 2; + int entityLineStartIndex = fromEntityID << _entityComponentMaskLengthBitShift; + int poolIndexWithoutOffset = 0; + for (int i = 0; i < _entityComponentMaskLength; i++) { + int chunk = _entityComponentMasks[i]; + poolIndexWithoutOffset += COMPONENT_MASK_CHUNK_SIZE; + if (chunk != 0) + { + if ((chunk & 0x0000FFFF) != 0) + { + int bit = 1; + for (int j = 0; j < COMPONENT_MASK_CHUNK_SIZE_HALF; j++) + { + if ((bit & chunk) != 0) + { + _pools[poolIndexWithoutOffset + j].Copy(fromEntityID, toWorld, toEntityID); + } + bit <<= 1; + } + } + if ((chunk & -0x7FFF0000) != 0) + { + int bit = 0x00010000; + for (int j = COMPONENT_MASK_CHUNK_SIZE_HALF; j < COMPONENT_MASK_CHUNK_SIZE; j++) + { + if ((bit & chunk) != 0) + { + _pools[poolIndexWithoutOffset + j].Copy(fromEntityID, toWorld, toEntityID); + } + bit <<= 1; + } + } + } + } + + //foreach (var pool in _pools) + //{ + // if (pool.Has(fromEntityID)) + // { + // pool.Copy(fromEntityID, toWorld, toEntityID); + // } + //} + } + public void CopyEntity(int fromEntityID, EcsWorld toWorld, int toEntityID, ReadOnlySpan componentTypeIDs) + { + foreach (var poolID in componentTypeIDs) + { + var pool = _pools[poolID]; if (pool.Has(fromEntityID)) { pool.Copy(fromEntityID, toWorld, toEntityID); } } } - public int CloneEntity(int fromEntityID) + #endregion + + #region CloneEntity + public int CloneEntity(int entityID) { int newEntity = NewEntity(); - CopyEntity(fromEntityID, newEntity); + CopyEntity(entityID, newEntity); return newEntity; } - public int CloneEntity(int fromEntityID, EcsWorld toWorld) + public int CloneEntity(int entityID, ReadOnlySpan componentTypeIDs) { int newEntity = NewEntity(); - CopyEntity(fromEntityID, toWorld, newEntity); + CopyEntity(entityID, newEntity, componentTypeIDs); return newEntity; } + public int CloneEntity(int entityID, EcsWorld toWorld) + { + int newEntity = NewEntity(); + CopyEntity(entityID, toWorld, newEntity); + return newEntity; + } + public int CloneEntity(int entityID, EcsWorld toWorld, ReadOnlySpan componentTypeIDs) + { + int newEntity = NewEntity(); + CopyEntity(entityID, toWorld, newEntity, componentTypeIDs); + return newEntity; + } + public void CloneEntity(int fromEntityID, int toEntityID) { CopyEntity(fromEntityID, toEntityID); @@ -505,6 +616,116 @@ namespace DCFApixels.DragonECS //public void CloneEntity(int fromEntityID, EcsWorld toWorld, int toEntityID) #endregion + #region MoveComponents + public void MoveComponents(int fromEntityID, int toEntityID) + { + const int COMPONENT_MASK_CHUNK_SIZE_HALF = COMPONENT_MASK_CHUNK_SIZE / 2; + int entityLineStartIndex = fromEntityID << _entityComponentMaskLengthBitShift; + int poolIndexWithoutOffset = 0; + for (int i = 0; i < _entityComponentMaskLength; i++) + { + int chunk = _entityComponentMasks[i]; + poolIndexWithoutOffset += COMPONENT_MASK_CHUNK_SIZE; + if (chunk != 0) + { + if ((chunk & 0x0000FFFF) != 0) + { + int bit = 1; + for (int j = 0; j < COMPONENT_MASK_CHUNK_SIZE_HALF; j++) + { + if ((bit & chunk) != 0) + { + var pool = _pools[poolIndexWithoutOffset + j]; + pool.Copy(fromEntityID, toEntityID); + pool.Del(fromEntityID); + } + bit <<= 1; + } + } + if ((chunk & -0x7FFF0000) != 0) + { + int bit = 0x00010000; + for (int j = COMPONENT_MASK_CHUNK_SIZE_HALF; j < COMPONENT_MASK_CHUNK_SIZE; j++) + { + if ((bit & chunk) != 0) + { + var pool = _pools[poolIndexWithoutOffset + j]; + pool.Copy(fromEntityID, toEntityID); + pool.Del(fromEntityID); + } + bit <<= 1; + } + } + } + } + } + public void MoveComponents(int fromEntityID, int toEntityID, ReadOnlySpan componentTypeIDs) + { + foreach (var poolID in componentTypeIDs) + { + var pool = _pools[poolID]; + if (pool.Has(fromEntityID)) + { + pool.Copy(fromEntityID, toEntityID); + pool.Del(fromEntityID); + } + } + } + #endregion + + #region RemoveComponents + public void RemoveComponents(int fromEntityID, int toEntityID) + { + const int COMPONENT_MASK_CHUNK_SIZE_HALF = COMPONENT_MASK_CHUNK_SIZE / 2; + int entityLineStartIndex = fromEntityID << _entityComponentMaskLengthBitShift; + int poolIndexWithoutOffset = 0; + for (int i = 0; i < _entityComponentMaskLength; i++) + { + int chunk = _entityComponentMasks[i]; + poolIndexWithoutOffset += COMPONENT_MASK_CHUNK_SIZE; + if (chunk != 0) + { + if ((chunk & 0x0000FFFF) != 0) + { + int bit = 1; + for (int j = 0; j < COMPONENT_MASK_CHUNK_SIZE_HALF; j++) + { + if ((bit & chunk) != 0) + { + _pools[poolIndexWithoutOffset + j].Del(fromEntityID); + } + bit <<= 1; + } + } + if ((chunk & -0x7FFF0000) != 0) + { + int bit = 0x00010000; + for (int j = COMPONENT_MASK_CHUNK_SIZE_HALF; j < COMPONENT_MASK_CHUNK_SIZE; j++) + { + if ((bit & chunk) != 0) + { + _pools[poolIndexWithoutOffset + j].Del(fromEntityID); + } + bit <<= 1; + } + } + } + } + } + public void MoveComponents(int fromEntityID, int toEntityID, ReadOnlySpan componentTypeIDs) + { + foreach (var poolID in componentTypeIDs) + { + var pool = _pools[poolID]; + if (pool.Has(fromEntityID)) + { + pool.Del(fromEntityID); + } + } + } + #endregion + + #endregion #region DelEntBuffer @@ -800,18 +1021,13 @@ namespace DCFApixels.DragonECS #endregion #region EntitySlot - [StructLayout(LayoutKind.Explicit, Pack = 4, Size = 4 * 3)] + [StructLayout(LayoutKind.Sequential)] private struct EntitySlot { public static readonly EntitySlot Empty = new EntitySlot(SLEEPING_GEN_FLAG, 0, false); - [FieldOffset(0)] public short gen; - [FieldOffset(2)] public short componentsCount; - [FieldOffset(4)] public bool isUsed; - //[FieldOffset(5)] - //public bool isLocked; public EntitySlot(short gen, short componentsCount, bool isUsed) { this.gen = gen; diff --git a/src/EcsWorld.pools.cs b/src/EcsWorld.pools.cs index 1274411..3320359 100644 --- a/src/EcsWorld.pools.cs +++ b/src/EcsWorld.pools.cs @@ -253,12 +253,12 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool TryRegisterEntityComponent(int entityID, int componentTypeID, EcsMaskChunck maskBit) { - ref int chunk = ref _entityComponentMasks[(entityID << _entityComponentMaskLengthBitShift) + maskBit.chunkIndex]; - int newChunk = chunk | maskBit.mask; - if (chunk != newChunk) + ref int entityLineStartIndex = ref _entityComponentMasks[(entityID << _entityComponentMaskLengthBitShift) + maskBit.chunkIndex]; + int newChunk = entityLineStartIndex | maskBit.mask; + if (entityLineStartIndex != newChunk) { UpVersion(); - chunk = newChunk; + entityLineStartIndex = newChunk; ref PoolSlot slot = ref _poolSlots[componentTypeID]; slot.count++; slot.version++; @@ -270,16 +270,16 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool TryUnregisterEntityComponent(int entityID, int componentTypeID, EcsMaskChunck maskBit) { - ref int chunk = ref _entityComponentMasks[(entityID << _entityComponentMaskLengthBitShift) + maskBit.chunkIndex]; - int newChunk = chunk & ~maskBit.mask; - if (chunk != newChunk) + ref int entityLineStartIndex = ref _entityComponentMasks[(entityID << _entityComponentMaskLengthBitShift) + maskBit.chunkIndex]; + int newChunk = entityLineStartIndex & ~maskBit.mask; + if (entityLineStartIndex != newChunk) { UpVersion(); ref PoolSlot slot = ref _poolSlots[componentTypeID]; slot.count--; slot.version++; var count = --_entities[entityID].componentsCount; - chunk = newChunk; + entityLineStartIndex = newChunk; if (count == 0 && IsUsed(entityID)) {