mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2025-09-18 18:14:37 +08:00
Impl Thread Safety for static methods in EcsWorld
This commit is contained in:
parent
44a8894d65
commit
effa02e660
120
src/EcsWorld.cs
120
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(EcsWorldConfig config, short worldID = -1) : this(config == null ? ConfigContainer.Empty : new ConfigContainer().Set(config), worldID) { }
|
||||||
public EcsWorld(IConfigContainer configs = null, short worldID = -1)
|
public EcsWorld(IConfigContainer configs = null, short worldID = -1)
|
||||||
{
|
{
|
||||||
if (configs == null) { configs = ConfigContainer.Empty; }
|
lock (_lock)
|
||||||
bool nullWorld = this is NullWorld;
|
|
||||||
if (nullWorld == false && worldID == NULL_WORLD_ID)
|
|
||||||
{
|
{
|
||||||
EcsDebug.PrintWarning($"The world identifier cannot be {NULL_WORLD_ID}");
|
if (configs == null) { configs = ConfigContainer.Empty; }
|
||||||
}
|
bool nullWorld = this is NullWorld;
|
||||||
_configs = configs;
|
if (nullWorld == false && worldID == NULL_WORLD_ID)
|
||||||
EcsWorldConfig config = configs.GetWorldConfigOrDefault();
|
|
||||||
|
|
||||||
if (worldID < 0 || (worldID == NULL_WORLD_ID && nullWorld == false))
|
|
||||||
{
|
|
||||||
worldID = (short)_worldIdDispenser.UseFree();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (worldID != _worldIdDispenser.NullID)
|
|
||||||
{
|
{
|
||||||
_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);
|
worldID = (short)_worldIdDispenser.UseFree();
|
||||||
Throw.Exception("The world with the specified ID has already been created\r\n");
|
|
||||||
}
|
}
|
||||||
|
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<NullComponent>();
|
||||||
}
|
}
|
||||||
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<NullComponent>();
|
|
||||||
}
|
}
|
||||||
public void Destroy()
|
public void Destroy()
|
||||||
{
|
{
|
||||||
if (_isDestroyed)
|
lock (_lock)
|
||||||
{
|
|
||||||
EcsDebug.PrintWarning("The world is already destroyed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (id == NULL_WORLD_ID)
|
|
||||||
{
|
{
|
||||||
|
if (_isDestroyed)
|
||||||
|
{
|
||||||
|
EcsDebug.PrintWarning("The world is already destroyed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (id == NULL_WORLD_ID)
|
||||||
|
{
|
||||||
#if (DEBUG && !DISABLE_DEBUG)
|
#if (DEBUG && !DISABLE_DEBUG)
|
||||||
Throw.World_WorldCantBeDestroyed();
|
Throw.World_WorldCantBeDestroyed();
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_listeners.InvokeOnWorldDestroy();
|
_listeners.InvokeOnWorldDestroy();
|
||||||
_entityDispenser = null;
|
_entityDispenser = null;
|
||||||
_pools = null;
|
_pools = null;
|
||||||
_nullPool = null;
|
_nullPool = null;
|
||||||
_worlds[id] = null;
|
_worlds[id] = null;
|
||||||
ReleaseData(id);
|
ReleaseData(id);
|
||||||
_worldIdDispenser.Release(id);
|
_worldIdDispenser.Release(id);
|
||||||
_isDestroyed = true;
|
_isDestroyed = true;
|
||||||
_poolTypeCode_2_CmpTypeIDs = null;
|
_poolTypeCode_2_CmpTypeIDs = null;
|
||||||
_cmpTypeCode_2_CmpTypeIDs = null;
|
_cmpTypeCode_2_CmpTypeIDs = null;
|
||||||
|
|
||||||
foreach (var item in _executorCoures)
|
foreach (var item in _executorCoures)
|
||||||
{
|
{
|
||||||
item.Value.Destroy();
|
item.Value.Destroy();
|
||||||
|
}
|
||||||
|
//_entities - не обнуляется для работы entlong.IsAlive
|
||||||
}
|
}
|
||||||
//_entities - не обнуляется для работы entlong.IsAlive
|
|
||||||
}
|
}
|
||||||
//public void Clear() { }
|
//public void Clear() { }
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -26,29 +26,30 @@ namespace DCFApixels.DragonECS
|
|||||||
private const int DEL_ENT_BUFFER_MIN_SIZE = 64;
|
private const int DEL_ENT_BUFFER_MIN_SIZE = 64;
|
||||||
|
|
||||||
private static EcsWorld[] _worlds = Array.Empty<EcsWorld>();
|
private static EcsWorld[] _worlds = Array.Empty<EcsWorld>();
|
||||||
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<DataReleaser> _dataReleaseres = new List<DataReleaser>();
|
private static List<DataReleaser> _dataReleaseres = new List<DataReleaser>();
|
||||||
//public static int Copacity => Worlds.Length;
|
//public static int Copacity => Worlds.Length;
|
||||||
|
|
||||||
|
private static readonly object _lock = new object();
|
||||||
|
|
||||||
static EcsWorld()
|
static EcsWorld()
|
||||||
{
|
{
|
||||||
_worlds[NULL_WORLD_ID] = new NullWorld();
|
_worlds[NULL_WORLD_ID] = new NullWorld();
|
||||||
}
|
}
|
||||||
private static void ReleaseData(int worldID)
|
private static void ReleaseData(int worldID)
|
||||||
{
|
{// ts
|
||||||
for (int i = 0, iMax = _dataReleaseres.Count; i < iMax; i++)
|
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)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static EcsWorld GetWorld(short worldID)
|
public static EcsWorld GetWorld(short worldID)
|
||||||
{
|
{// ts
|
||||||
return _worlds[worldID];
|
return _worlds[worldID];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,6 +64,7 @@ namespace DCFApixels.DragonECS
|
|||||||
return ref WorldComponentPool<T>.GetForWorldUnchecked(worldID);
|
return ref WorldComponentPool<T>.GetForWorldUnchecked(worldID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private abstract class DataReleaser
|
private abstract class DataReleaser
|
||||||
{
|
{
|
||||||
public abstract void Release(int worldID);
|
public abstract void Release(int worldID);
|
||||||
@ -76,64 +78,84 @@ namespace DCFApixels.DragonECS
|
|||||||
private static short _recycledItemsCount;
|
private static short _recycledItemsCount;
|
||||||
private static IEcsWorldComponent<T> _interface = EcsWorldComponentHandler<T>.instance;
|
private static IEcsWorldComponent<T> _interface = EcsWorldComponentHandler<T>.instance;
|
||||||
|
|
||||||
|
private static readonly object _lock = new object();
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ref T Get(int itemIndex)
|
public static ref T Get(int itemIndex)
|
||||||
{
|
{// ts
|
||||||
return ref _items[itemIndex];
|
return ref _items[itemIndex];
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ref T GetForWorld(int worldID)
|
public static ref T GetForWorld(int worldID)
|
||||||
{
|
{// зависит от GetItemIndex
|
||||||
int index = GetItemIndex(worldID);
|
return ref Get(GetItemIndex(worldID));
|
||||||
return ref _items[index];
|
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static ref T GetForWorldUnchecked(int worldID)
|
public static ref T GetForWorldUnchecked(int worldID)
|
||||||
{
|
{// ts
|
||||||
#if (DEBUG && !DISABLE_DEBUG)
|
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (_mapping[worldID] <= 0) { Throw.UndefinedException(); }
|
if (_mapping[worldID] <= 0) { Throw.UndefinedException(); }
|
||||||
#endif
|
#endif
|
||||||
return ref _items[_mapping[worldID]];
|
return ref _items[_mapping[worldID]];
|
||||||
}
|
}
|
||||||
public static int GetItemIndex(int worldID)
|
public static int GetItemIndex(int worldID)
|
||||||
{
|
{// ts
|
||||||
if (_mapping.Length < _worlds.Length)
|
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];
|
short itemIndex = _mapping[worldID];
|
||||||
if (itemIndex <= 0)
|
|
||||||
|
if (itemIndex == 0)
|
||||||
{
|
{
|
||||||
if (_recycledItemsCount > 0)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
_count++;
|
itemIndex = _mapping[worldID];
|
||||||
itemIndex = _recycledItems[--_recycledItemsCount];
|
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;
|
return itemIndex;
|
||||||
}
|
}
|
||||||
private static void Release(int worldID)
|
private static void Release(int worldID)
|
||||||
{
|
{// ts
|
||||||
if (_mapping.Length < _worlds.Length)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
Array.Resize(ref _mapping, _worlds.Length);
|
if (_mapping.Length < _worlds.Length)
|
||||||
}
|
{
|
||||||
ref short itemIndex = ref _mapping[worldID];
|
Array.Resize(ref _mapping, _worlds.Length);
|
||||||
if (itemIndex != 0)
|
}
|
||||||
{
|
ref short itemIndex = ref _mapping[worldID];
|
||||||
_interface.OnDestroy(ref _items[itemIndex], _worlds[worldID]);
|
if (itemIndex != 0)
|
||||||
_recycledItems[_recycledItemsCount++] = itemIndex;
|
{
|
||||||
itemIndex = 0;
|
_interface.OnDestroy(ref _items[itemIndex], _worlds[worldID]);
|
||||||
|
_recycledItems[_recycledItemsCount++] = itemIndex;
|
||||||
|
itemIndex = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private sealed class Releaser : DataReleaser
|
private sealed class Releaser : DataReleaser
|
||||||
|
Loading…
Reference in New Issue
Block a user