diff --git a/src/Debug/EcsDebug.cs b/src/Debug/EcsDebug.cs index 064b146..9fa86b2 100644 --- a/src/Debug/EcsDebug.cs +++ b/src/Debug/EcsDebug.cs @@ -1,6 +1,6 @@ using DCFApixels.DragonECS.Internal; using System; -using System.Collections.Generic; +using System.Collections.Concurrent; using System.Diagnostics; using System.Runtime.CompilerServices; @@ -116,6 +116,8 @@ namespace DCFApixels.DragonECS public abstract class DebugService { private static DebugService _instance; + private static object _lock = new object(); + public static DebugService Instance { get @@ -141,7 +143,7 @@ namespace DCFApixels.DragonECS public static Action OnServiceChanged = delegate { }; private IdDispenser _idDispenser = new IdDispenser(4, -1); - private Dictionary _nameIdTable = new Dictionary(); + private ConcurrentDictionary _nameIdTable = new ConcurrentDictionary(); public abstract void Print(string tag, object v); public abstract void Break(); public int RegisterMark(string name) @@ -149,8 +151,11 @@ namespace DCFApixels.DragonECS int id; if (!_nameIdTable.TryGetValue(name, out id)) { - id = _idDispenser.UseFree(); - _nameIdTable.Add(name, id); + lock (_lock) + { + id = _idDispenser.UseFree(); + _nameIdTable.TryAdd(name, id); + } } OnNewProfilerMark(id, name); return id; @@ -158,7 +163,8 @@ namespace DCFApixels.DragonECS public void DeleteMark(string name) { int id = _nameIdTable[name]; - _nameIdTable.Remove(name); + //TODO кажется этот TryRemove не подходит + _nameIdTable.TryRemove(name, out id); _idDispenser.Release(id); OnDelProfilerMark(id); } diff --git a/src/Debug/TypeMeta.cs b/src/Debug/TypeMeta.cs index 9ae6383..a696953 100644 --- a/src/Debug/TypeMeta.cs +++ b/src/Debug/TypeMeta.cs @@ -45,17 +45,22 @@ namespace DCFApixels.DragonECS private InitFlag _initFlags = InitFlag.None; + private static object _lock = new object(); + //private EcsMemberType _memberType; #region Constructors public static TypeMeta Get(Type type) { - if (_metaCache.TryGetValue(type, out TypeMeta result) == false) + lock (_lock) { - result = new TypeMeta(type); - _metaCache.Add(type, result); + if (_metaCache.TryGetValue(type, out TypeMeta result) == false) + { + result = new TypeMeta(type); + _metaCache.Add(type, result); + } + return result; } - return result; } private TypeMeta(Type type) { diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index b32e19f..97b3708 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -134,7 +134,7 @@ 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) { - lock (_lock) + lock (_worldLock) { if (configs == null) { configs = ConfigContainer.Empty; } bool nullWorld = this is NullWorld; @@ -180,7 +180,7 @@ namespace DCFApixels.DragonECS } public void Destroy() { - lock (_lock) + lock (_worldLock) { if (_isDestroyed) { @@ -707,7 +707,8 @@ namespace DCFApixels.DragonECS #endregion #region Debug Components - private static int[] _componentIDsBuffer = new int[64]; + [ThreadStatic] + private static int[] _componentIDsBuffer; public ReadOnlySpan GetComponentTypeIDsFor(int entityID) { int count = GetComponentTypeIDsFor(entityID, ref _componentIDsBuffer); @@ -733,6 +734,10 @@ namespace DCFApixels.DragonECS } private int GetComponentTypeIDsFor(int entityID, ref int[] componentIDs) { + if (componentIDs == null) + { + componentIDs = new int[64]; + } int count = 0; var itemsCount = GetComponentsCount(entityID); if (itemsCount <= 0) { return count; } diff --git a/src/EcsWorld.pools.cs b/src/EcsWorld.pools.cs index 48bca1b..0c17d30 100644 --- a/src/EcsWorld.pools.cs +++ b/src/EcsWorld.pools.cs @@ -3,6 +3,7 @@ using DCFApixels.DragonECS.PoolsCore; using System; using System.Linq; using System.Runtime.CompilerServices; +using System.Threading; namespace DCFApixels.DragonECS { @@ -149,80 +150,83 @@ namespace DCFApixels.DragonECS #region CreatePool private TPool CreatePool() where TPool : IEcsPoolImplementation, new() { - int poolTypeCode = EcsTypeCode.Get(); - if (_poolTypeCode_2_CmpTypeIDs.Contains(poolTypeCode)) + lock (_worldLock) { - Throw.World_PoolAlreadyCreated(); - } - TPool newPool = new TPool(); + int poolTypeCode = EcsTypeCode.Get(); + if (_poolTypeCode_2_CmpTypeIDs.Contains(poolTypeCode)) + { + Throw.World_PoolAlreadyCreated(); + } + TPool newPool = new TPool(); - Type componentType = newPool.ComponentType; + Type componentType = newPool.ComponentType; #if DEBUG //проверка соответсвия типов #pragma warning disable IL2090 // 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The generic parameter of the source method or type does not have matching annotations. - if (componentType != typeof(TPool).GetInterfaces() - .First(o => o.IsGenericType && o.GetGenericTypeDefinition() == typeof(IEcsPoolImplementation<>)) - .GetGenericArguments()[0]) - { - Throw.Exception("A custom pool must implement the interface IEcsPoolImplementation where T is the type that stores the pool."); - } + if (componentType != typeof(TPool).GetInterfaces() + .First(o => o.IsGenericType && o.GetGenericTypeDefinition() == typeof(IEcsPoolImplementation<>)) + .GetGenericArguments()[0]) + { + Throw.Exception("A custom pool must implement the interface IEcsPoolImplementation where T is the type that stores the pool."); + } #pragma warning restore IL2090 // 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The generic parameter of the source method or type does not have matching annotations. #endif - int componentTypeCode = EcsTypeCode.Get(componentType); + int componentTypeCode = EcsTypeCode.Get(componentType); - if (_cmpTypeCode_2_CmpTypeIDs.TryGetValue(componentTypeCode, out int componentTypeID)) - { - _poolTypeCode_2_CmpTypeIDs[poolTypeCode] = componentTypeID; - } - else - { - componentTypeID = _poolsCount++; - _poolTypeCode_2_CmpTypeIDs[poolTypeCode] = componentTypeID; - _cmpTypeCode_2_CmpTypeIDs[componentTypeCode] = componentTypeID; - } - - if (_poolsCount >= _pools.Length) - { - int oldCapacity = _pools.Length; - Array.Resize(ref _pools, _pools.Length << 1); - Array.Resize(ref _poolSlots, _pools.Length); - ArrayUtility.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length); - - int newEntityComponentMaskLength = CalcEntityComponentMaskLength(); //_pools.Length / COMPONENT_MASK_CHUNK_SIZE + 1; - int dif = newEntityComponentMaskLength - _entityComponentMaskLength; - if (dif > 0) + if (_cmpTypeCode_2_CmpTypeIDs.TryGetValue(componentTypeCode, out int componentTypeID)) { - int[] newEntityComponentMasks = new int[_entitiesCapacity * newEntityComponentMaskLength]; - int indxMax = _entityComponentMaskLength * _entitiesCapacity; - int indx = 0; - int newIndx = 0; - int nextIndx = _entityComponentMaskLength; - while (indx < indxMax) - { - while (indx < nextIndx) - { - newEntityComponentMasks[newIndx] = _entityComponentMasks[indx]; - indx++; - newIndx++; - } - newIndx += dif; - nextIndx += _entityComponentMaskLength; - } - SetEntityComponentMaskLength(newEntityComponentMaskLength); - _entityComponentMasks = newEntityComponentMasks; + _poolTypeCode_2_CmpTypeIDs[poolTypeCode] = componentTypeID; + } + else + { + componentTypeID = _poolsCount++; + _poolTypeCode_2_CmpTypeIDs[poolTypeCode] = componentTypeID; + _cmpTypeCode_2_CmpTypeIDs[componentTypeCode] = componentTypeID; } + if (_poolsCount >= _pools.Length) + { + int oldCapacity = _pools.Length; + Array.Resize(ref _pools, _pools.Length << 1); + Array.Resize(ref _poolSlots, _pools.Length); + ArrayUtility.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length); + + int newEntityComponentMaskLength = CalcEntityComponentMaskLength(); //_pools.Length / COMPONENT_MASK_CHUNK_SIZE + 1; + int dif = newEntityComponentMaskLength - _entityComponentMaskLength; + if (dif > 0) + { + int[] newEntityComponentMasks = new int[_entitiesCapacity * newEntityComponentMaskLength]; + int indxMax = _entityComponentMaskLength * _entitiesCapacity; + int indx = 0; + int newIndx = 0; + int nextIndx = _entityComponentMaskLength; + while (indx < indxMax) + { + while (indx < nextIndx) + { + newEntityComponentMasks[newIndx] = _entityComponentMasks[indx]; + indx++; + newIndx++; + } + newIndx += dif; + nextIndx += _entityComponentMaskLength; + } + SetEntityComponentMaskLength(newEntityComponentMaskLength); + _entityComponentMasks = newEntityComponentMasks; + } + + } + + var oldPool = _pools[componentTypeID]; + + if (oldPool != _nullPool) + { + Throw.UndefinedException(); + } + + _pools[componentTypeID] = newPool; + newPool.OnInit(this, _poolsMediator, componentTypeID); + return newPool; } - - var oldPool = _pools[componentTypeID]; - - if (oldPool != _nullPool) - { - Throw.UndefinedException(); - } - - _pools[componentTypeID] = newPool; - newPool.OnInit(this, _poolsMediator, componentTypeID); - return newPool; } #endregion diff --git a/src/EcsWorld.static.cs b/src/EcsWorld.static.cs index 5a093da..665a5d0 100644 --- a/src/EcsWorld.static.cs +++ b/src/EcsWorld.static.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Threading; namespace DCFApixels.DragonECS { @@ -31,7 +32,7 @@ namespace DCFApixels.DragonECS private static List _dataReleaseres = new List(); //public static int Copacity => Worlds.Length; - private static readonly object _lock = new object(); + private static readonly object _worldLock = new object(); static EcsWorld() { @@ -39,7 +40,7 @@ namespace DCFApixels.DragonECS } private static void ReleaseData(int worldID) {// ts - lock (_lock) + lock (_worldLock) { for (int i = 0, iMax = _dataReleaseres.Count; i < iMax; i++) { @@ -78,17 +79,15 @@ 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) + public static ref T GetItem(int itemIndex) {// ts return ref _items[itemIndex]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ref T GetForWorld(int worldID) {// зависит от GetItemIndex - return ref Get(GetItemIndex(worldID)); + return ref GetItem(GetItemIndex(worldID)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ref T GetForWorldUnchecked(int worldID) @@ -102,7 +101,7 @@ namespace DCFApixels.DragonECS {// ts if (_mapping.Length < _worlds.Length) { - lock (_lock) + lock (_worldLock) { if (_mapping.Length < _worlds.Length) { @@ -114,7 +113,7 @@ namespace DCFApixels.DragonECS if (itemIndex == 0) { - lock (_lock) + lock (_worldLock) { itemIndex = _mapping[worldID]; if (itemIndex <= 0) @@ -134,6 +133,7 @@ namespace DCFApixels.DragonECS { Array.Resize(ref _items, _items.Length << 1); } + _interface.Init(ref _items[itemIndex], _worlds[worldID]); _dataReleaseres.Add(new Releaser()); } @@ -143,7 +143,7 @@ namespace DCFApixels.DragonECS } private static void Release(int worldID) {// ts - lock (_lock) + lock (_worldLock) { if (_mapping.Length < _worlds.Length) { diff --git a/src/Internal/EcsTypeCode.cs b/src/Internal/EcsTypeCode.cs index d9aae26..e7bb23e 100644 --- a/src/Internal/EcsTypeCode.cs +++ b/src/Internal/EcsTypeCode.cs @@ -16,6 +16,7 @@ namespace DCFApixels.DragonECS.Internal { private static readonly Dictionary _codes = new Dictionary(); private static int _increment = 1; + private static object _lock = new object(); public static int Count { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -23,12 +24,15 @@ namespace DCFApixels.DragonECS.Internal } public static int Get(Type type) { - if (!_codes.TryGetValue(type, out int code)) + lock (_lock) { - code = _increment++; - _codes.Add(type, code); + if (!_codes.TryGetValue(type, out int code)) + { + code = _increment++; + _codes.Add(type, code); + } + return code; } - return code; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Get() { return EcsTypeCodeCache.code; }