diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index 9ef8610..b32e19f 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -134,77 +134,83 @@ namespace DCFApixels.DragonECS public EcsWorld(EcsWorldConfig config, short worldID = -1) : this(config == null ? ConfigContainer.Empty : new ConfigContainer().Set(config), worldID) { } public EcsWorld(IConfigContainer configs = null, short worldID = -1) { - if (configs == null) { configs = ConfigContainer.Empty; } - bool nullWorld = this is NullWorld; - if (nullWorld == false && worldID == NULL_WORLD_ID) + lock (_lock) { - EcsDebug.PrintWarning($"The world identifier cannot be {NULL_WORLD_ID}"); - } - _configs = configs; - EcsWorldConfig config = configs.GetWorldConfigOrDefault(); - - if (worldID < 0 || (worldID == NULL_WORLD_ID && nullWorld == false)) - { - worldID = (short)_worldIdDispenser.UseFree(); - } - else - { - if (worldID != _worldIdDispenser.NullID) + if (configs == null) { configs = ConfigContainer.Empty; } + bool nullWorld = this is NullWorld; + if (nullWorld == false && worldID == NULL_WORLD_ID) { - _worldIdDispenser.Use(worldID); + EcsDebug.PrintWarning($"The world identifier cannot be {NULL_WORLD_ID}"); } - if (_worlds[worldID] != null) + _configs = configs; + EcsWorldConfig config = configs.GetWorldConfigOrDefault(); + + if (worldID < 0 || (worldID == NULL_WORLD_ID && nullWorld == false)) { - _worldIdDispenser.Release(worldID); - Throw.Exception("The world with the specified ID has already been created\r\n"); + worldID = (short)_worldIdDispenser.UseFree(); } + else + { + if (worldID != _worldIdDispenser.NullID) + { + _worldIdDispenser.Use(worldID); + } + if (_worlds[worldID] != null) + { + _worldIdDispenser.Release(worldID); + Throw.Exception("The world with the specified ID has already been created\r\n"); + } + } + id = worldID; + _worlds[worldID] = this; + + _poolsMediator = new PoolsMediator(this); + _executorsMediator = new ExecutorMediator(this); + + int poolsCapacity = ArrayUtility.NormalizeSizeToPowerOfTwo(config.PoolsCapacity); + _pools = new IEcsPoolImplementation[poolsCapacity]; + _poolSlots = new PoolSlot[poolsCapacity]; + ArrayUtility.Fill(_pools, _nullPool); + + int entitiesCapacity = ArrayUtility.NormalizeSizeToPowerOfTwo(config.EntitiesCapacity); + _entityDispenser = new IdDispenser(entitiesCapacity, 0, OnEntityDispenserResized); + + GetComponentTypeID(); } - id = worldID; - _worlds[worldID] = this; - - _poolsMediator = new PoolsMediator(this); - _executorsMediator = new ExecutorMediator(this); - - int poolsCapacity = ArrayUtility.NormalizeSizeToPowerOfTwo(config.PoolsCapacity); - _pools = new IEcsPoolImplementation[poolsCapacity]; - _poolSlots = new PoolSlot[poolsCapacity]; - ArrayUtility.Fill(_pools, _nullPool); - - int entitiesCapacity = ArrayUtility.NormalizeSizeToPowerOfTwo(config.EntitiesCapacity); - _entityDispenser = new IdDispenser(entitiesCapacity, 0, OnEntityDispenserResized); - - GetComponentTypeID(); } public void Destroy() { - if (_isDestroyed) - { - EcsDebug.PrintWarning("The world is already destroyed"); - return; - } - if (id == NULL_WORLD_ID) + lock (_lock) { + if (_isDestroyed) + { + EcsDebug.PrintWarning("The world is already destroyed"); + return; + } + if (id == NULL_WORLD_ID) + { #if (DEBUG && !DISABLE_DEBUG) - Throw.World_WorldCantBeDestroyed(); + Throw.World_WorldCantBeDestroyed(); #endif - return; - } - _listeners.InvokeOnWorldDestroy(); - _entityDispenser = null; - _pools = null; - _nullPool = null; - _worlds[id] = null; - ReleaseData(id); - _worldIdDispenser.Release(id); - _isDestroyed = true; - _poolTypeCode_2_CmpTypeIDs = null; - _cmpTypeCode_2_CmpTypeIDs = null; + return; + } + _listeners.InvokeOnWorldDestroy(); + _entityDispenser = null; + _pools = null; + _nullPool = null; + _worlds[id] = null; + ReleaseData(id); + _worldIdDispenser.Release(id); + _isDestroyed = true; + _poolTypeCode_2_CmpTypeIDs = null; + _cmpTypeCode_2_CmpTypeIDs = null; - foreach (var item in _executorCoures) - { - item.Value.Destroy(); + foreach (var item in _executorCoures) + { + item.Value.Destroy(); + } + //_entities - не обнуляется для работы entlong.IsAlive } - //_entities - не обнуляется для работы entlong.IsAlive } //public void Clear() { } #endregion diff --git a/src/EcsWorld.static.cs b/src/EcsWorld.static.cs index c056edb..5a093da 100644 --- a/src/EcsWorld.static.cs +++ b/src/EcsWorld.static.cs @@ -26,29 +26,30 @@ namespace DCFApixels.DragonECS private const int DEL_ENT_BUFFER_MIN_SIZE = 64; private static EcsWorld[] _worlds = Array.Empty(); - private static IdDispenser _worldIdDispenser = new IdDispenser(4, 0, OnWorldIdDispenser); + private static IdDispenser _worldIdDispenser = new IdDispenser(4, 0, n => Array.Resize(ref _worlds, n)); private static List _dataReleaseres = new List(); //public static int Copacity => Worlds.Length; + private static readonly object _lock = new object(); + static EcsWorld() { _worlds[NULL_WORLD_ID] = new NullWorld(); } private static void ReleaseData(int worldID) - { - for (int i = 0, iMax = _dataReleaseres.Count; i < iMax; i++) + {// ts + lock (_lock) { - _dataReleaseres[i].Release(worldID); + for (int i = 0, iMax = _dataReleaseres.Count; i < iMax; i++) + { + _dataReleaseres[i].Release(worldID); + } } } - public static void OnWorldIdDispenser(int newSize) - { - Array.Resize(ref _worlds, newSize); - } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static EcsWorld GetWorld(short worldID) - { + {// ts return _worlds[worldID]; } @@ -63,6 +64,7 @@ namespace DCFApixels.DragonECS return ref WorldComponentPool.GetForWorldUnchecked(worldID); } + private abstract class DataReleaser { public abstract void Release(int worldID); @@ -76,64 +78,84 @@ namespace DCFApixels.DragonECS private static short _recycledItemsCount; private static IEcsWorldComponent _interface = EcsWorldComponentHandler.instance; + private static readonly object _lock = new object(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ref T Get(int itemIndex) - { + {// ts return ref _items[itemIndex]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ref T GetForWorld(int worldID) - { - int index = GetItemIndex(worldID); - return ref _items[index]; + {// зависит от GetItemIndex + return ref Get(GetItemIndex(worldID)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ref T GetForWorldUnchecked(int worldID) - { -#if (DEBUG && !DISABLE_DEBUG) + {// ts +#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS if (_mapping[worldID] <= 0) { Throw.UndefinedException(); } #endif return ref _items[_mapping[worldID]]; } public static int GetItemIndex(int worldID) - { + {// ts if (_mapping.Length < _worlds.Length) { - Array.Resize(ref _mapping, _worlds.Length); + lock (_lock) + { + if (_mapping.Length < _worlds.Length) + { + Array.Resize(ref _mapping, _worlds.Length); + } + } } - ref short itemIndex = ref _mapping[worldID]; - if (itemIndex <= 0) + short itemIndex = _mapping[worldID]; + + if (itemIndex == 0) { - if (_recycledItemsCount > 0) + lock (_lock) { - _count++; - itemIndex = _recycledItems[--_recycledItemsCount]; + itemIndex = _mapping[worldID]; + if (itemIndex <= 0) + { + if (_recycledItemsCount > 0) + { + _count++; + itemIndex = _recycledItems[--_recycledItemsCount]; + } + else + { + itemIndex = ++_count; + } + _mapping[worldID] = itemIndex; + + if (_items.Length <= itemIndex) + { + Array.Resize(ref _items, _items.Length << 1); + } + _interface.Init(ref _items[itemIndex], _worlds[worldID]); + _dataReleaseres.Add(new Releaser()); + } } - else - { - itemIndex = ++_count; - } - if (_items.Length <= itemIndex) - { - Array.Resize(ref _items, _items.Length << 1); - } - _interface.Init(ref _items[itemIndex], _worlds[worldID]); - _dataReleaseres.Add(new Releaser()); } return itemIndex; } private static void Release(int worldID) - { - if (_mapping.Length < _worlds.Length) + {// ts + lock (_lock) { - Array.Resize(ref _mapping, _worlds.Length); - } - ref short itemIndex = ref _mapping[worldID]; - if (itemIndex != 0) - { - _interface.OnDestroy(ref _items[itemIndex], _worlds[worldID]); - _recycledItems[_recycledItemsCount++] = itemIndex; - itemIndex = 0; + if (_mapping.Length < _worlds.Length) + { + Array.Resize(ref _mapping, _worlds.Length); + } + ref short itemIndex = ref _mapping[worldID]; + if (itemIndex != 0) + { + _interface.OnDestroy(ref _items[itemIndex], _worlds[worldID]); + _recycledItems[_recycledItemsCount++] = itemIndex; + itemIndex = 0; + } } } private sealed class Releaser : DataReleaser