mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2025-09-18 18:14:37 +08:00
Rework component ids
Remove WorldMetaStorage
This commit is contained in:
parent
5612fe047c
commit
112b96384d
@ -257,7 +257,7 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
internal class DebuggerProxy
|
internal class DebuggerProxy
|
||||||
{
|
{
|
||||||
public readonly Type worldType;
|
public readonly EcsWorld world;
|
||||||
public readonly int worldID;
|
public readonly int worldID;
|
||||||
public readonly int[] included;
|
public readonly int[] included;
|
||||||
public readonly int[] excluded;
|
public readonly int[] excluded;
|
||||||
@ -265,11 +265,11 @@ namespace DCFApixels.DragonECS
|
|||||||
public readonly Type[] excludedTypes;
|
public readonly Type[] excludedTypes;
|
||||||
public DebuggerProxy(EcsMask mask)
|
public DebuggerProxy(EcsMask mask)
|
||||||
{
|
{
|
||||||
worldType = WorldMetaStorage.GetWorldType(mask.worldID);
|
world = EcsWorld.GetWorld(mask.worldID);
|
||||||
worldID = mask.worldID;
|
worldID = mask.worldID;
|
||||||
included = mask.inc;
|
included = mask.inc;
|
||||||
excluded = mask.exc;
|
excluded = mask.exc;
|
||||||
Type converter(int o) => WorldMetaStorage.GetComponentType(worldID, o);
|
Type converter(int o) => world.GetComponentType(o);
|
||||||
includedTypes = included.Select(converter).ToArray();
|
includedTypes = included.Select(converter).ToArray();
|
||||||
excludedTypes = excluded.Select(converter).ToArray();
|
excludedTypes = excluded.Select(converter).ToArray();
|
||||||
}
|
}
|
||||||
|
@ -19,23 +19,6 @@ namespace DCFApixels.DragonECS
|
|||||||
component = default;
|
component = default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private TPool CreatePool<TPool>() where TPool : IEcsPoolImplementation, new()
|
|
||||||
{
|
|
||||||
int index = WorldMetaStorage.GetPoolID<TPool>(_worldTypeID);
|
|
||||||
if (index >= _pools.Length)
|
|
||||||
{
|
|
||||||
int oldCapacity = _pools.Length;
|
|
||||||
Array.Resize(ref _pools, _pools.Length << 1);
|
|
||||||
ArrayUtility.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length);
|
|
||||||
}
|
|
||||||
if (_pools[index] == _nullPool)
|
|
||||||
{
|
|
||||||
var pool = new TPool();
|
|
||||||
_pools[index] = pool;
|
|
||||||
pool.OnInit(this, index);
|
|
||||||
}
|
|
||||||
return (TPool)_pools[index];
|
|
||||||
}
|
|
||||||
internal readonly struct AspectCache<T> : IEcsWorldComponent<AspectCache<T>>
|
internal readonly struct AspectCache<T> : IEcsWorldComponent<AspectCache<T>>
|
||||||
where T : EcsAspect
|
where T : EcsAspect
|
||||||
{
|
{
|
||||||
|
@ -10,9 +10,6 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
public readonly short id;
|
public readonly short id;
|
||||||
|
|
||||||
private Type _worldType;
|
|
||||||
private int _worldTypeID;
|
|
||||||
|
|
||||||
private bool _isDestroyed;
|
private bool _isDestroyed;
|
||||||
|
|
||||||
private IntDispenser _entityDispenser;
|
private IntDispenser _entityDispenser;
|
||||||
@ -25,9 +22,6 @@ namespace DCFApixels.DragonECS
|
|||||||
private int[] _delEntBuffer;
|
private int[] _delEntBuffer;
|
||||||
private int _delEntBufferCount;
|
private int _delEntBufferCount;
|
||||||
|
|
||||||
internal IEcsPoolImplementation[] _pools;
|
|
||||||
private EcsNullPool _nullPool = EcsNullPool.instance;
|
|
||||||
|
|
||||||
private List<WeakReference<EcsGroup>> _groups = new List<WeakReference<EcsGroup>>();
|
private List<WeakReference<EcsGroup>> _groups = new List<WeakReference<EcsGroup>>();
|
||||||
private Stack<EcsGroup> _groupsPool = new Stack<EcsGroup>(64);
|
private Stack<EcsGroup> _groupsPool = new Stack<EcsGroup>(64);
|
||||||
|
|
||||||
@ -36,7 +30,6 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
public bool IsDestroyed => _isDestroyed;
|
public bool IsDestroyed => _isDestroyed;
|
||||||
public int WorldTypeID => _worldTypeID;
|
|
||||||
public int Count => _entitiesCount;
|
public int Count => _entitiesCount;
|
||||||
public int Capacity => _entitesCapacity; //_denseEntities.Length;
|
public int Capacity => _entitesCapacity; //_denseEntities.Length;
|
||||||
public EcsReadonlyGroup Entities => _allEntites.Readonly;
|
public EcsReadonlyGroup Entities => _allEntites.Readonly;
|
||||||
@ -51,15 +44,12 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
if (isIndexable)
|
if (isIndexable)
|
||||||
{
|
{
|
||||||
id = (short)_worldIdDispenser.GetFree();
|
id = (short)_worldIdDispenser.UseFree();
|
||||||
if (id >= Worlds.Length)
|
if (id >= Worlds.Length)
|
||||||
Array.Resize(ref Worlds, Worlds.Length << 1);
|
Array.Resize(ref Worlds, Worlds.Length << 1);
|
||||||
Worlds[id] = this;
|
Worlds[id] = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
_worldType = this.GetType();
|
|
||||||
_worldTypeID = WorldMetaStorage.GetWorldID(_worldType);
|
|
||||||
|
|
||||||
_entityDispenser = new IntDispenser(0);
|
_entityDispenser = new IntDispenser(0);
|
||||||
_pools = new IEcsPoolImplementation[512];
|
_pools = new IEcsPoolImplementation[512];
|
||||||
ArrayUtility.Fill(_pools, _nullPool);
|
ArrayUtility.Fill(_pools, _nullPool);
|
||||||
@ -83,42 +73,15 @@ namespace DCFApixels.DragonECS
|
|||||||
ReleaseData(id);
|
ReleaseData(id);
|
||||||
_worldIdDispenser.Release(id);
|
_worldIdDispenser.Release(id);
|
||||||
_isDestroyed = true;
|
_isDestroyed = true;
|
||||||
|
_poolIds = null;
|
||||||
|
_componentIds = null;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region ComponentInfo
|
|
||||||
public int GetComponentID<T>() => WorldMetaStorage.GetComponentID<T>(_worldTypeID);
|
|
||||||
public int GetComponentID(Type type) => WorldMetaStorage.GetComponentID(type, _worldTypeID);
|
|
||||||
public Type GetComponentType(int componentID) => WorldMetaStorage.GetComponentType(_worldTypeID, componentID);
|
|
||||||
public bool IsComponentTypeDeclared<T>() => IsComponentTypeDeclared(typeof(T));
|
|
||||||
public bool IsComponentTypeDeclared(Type type) => WorldMetaStorage.IsComponentTypeDeclared(_worldTypeID, type);
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Getters
|
#region Getters
|
||||||
#if UNITY_2020_3_OR_NEWER
|
#if UNITY_2020_3_OR_NEWER
|
||||||
[UnityEngine.Scripting.Preserve]
|
[UnityEngine.Scripting.Preserve]
|
||||||
#endif
|
#endif
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public TPool GetPool<TPool>() where TPool : IEcsPoolImplementation, new()
|
|
||||||
{
|
|
||||||
return Get<PoolCache<TPool>>().instance;
|
|
||||||
}
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public TPool UncheckedGetPool<TPool>() where TPool : IEcsPoolImplementation, new()
|
|
||||||
{
|
|
||||||
return UncheckedGet<PoolCache<TPool>>().instance;
|
|
||||||
}
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static TPool GetPool<TPool>(int worldID) where TPool : IEcsPoolImplementation, new()
|
|
||||||
{
|
|
||||||
return Get<PoolCache<TPool>>(worldID).instance;
|
|
||||||
}
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static TPool UncheckedGetPool<TPool>(int worldID) where TPool : IEcsPoolImplementation, new()
|
|
||||||
{
|
|
||||||
return UncheckedGet<PoolCache<TPool>>(worldID).instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public TAspect GetAspect<TAspect>() where TAspect : EcsAspect
|
public TAspect GetAspect<TAspect>() where TAspect : EcsAspect
|
||||||
{
|
{
|
||||||
|
107
src/EcsWorld.pools.cs
Normal file
107
src/EcsWorld.pools.cs
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
using DCFApixels.DragonECS.Internal;
|
||||||
|
using DCFApixels.DragonECS.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace DCFApixels.DragonECS
|
||||||
|
{
|
||||||
|
public abstract partial class EcsWorld
|
||||||
|
{
|
||||||
|
private SparseArray<int> _poolIds = new SparseArray<int>();
|
||||||
|
private SparseArray<int> _componentIds = new SparseArray<int>();
|
||||||
|
private int _poolsCount;
|
||||||
|
internal IEcsPoolImplementation[] _pools;
|
||||||
|
private EcsNullPool _nullPool = EcsNullPool.instance;
|
||||||
|
|
||||||
|
#region ComponentInfo
|
||||||
|
public int GetComponentID<T>() => DeclareComponentType(EcsTypeCode.Get<T>());
|
||||||
|
public int GetComponentID(Type type) => DeclareComponentType(EcsTypeCode.Get(type));
|
||||||
|
public bool IsComponentTypeDeclared<T>() => _componentIds.Contains(EcsTypeCode.Get<T>());
|
||||||
|
public bool IsComponentTypeDeclared(Type type) => _componentIds.Contains(EcsTypeCode.Get(type));
|
||||||
|
public Type GetComponentType(int componentID) => _pools[componentID].ComponentType;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Getters
|
||||||
|
|
||||||
|
#if UNITY_2020_3_OR_NEWER
|
||||||
|
[UnityEngine.Scripting.Preserve]
|
||||||
|
#endif
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public TPool GetPool<TPool>() where TPool : IEcsPoolImplementation, new()
|
||||||
|
{
|
||||||
|
return Get<PoolCache<TPool>>().instance;
|
||||||
|
}
|
||||||
|
#if UNITY_2020_3_OR_NEWER
|
||||||
|
[UnityEngine.Scripting.Preserve]
|
||||||
|
#endif
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public TPool UncheckedGetPool<TPool>() where TPool : IEcsPoolImplementation, new()
|
||||||
|
{
|
||||||
|
return UncheckedGet<PoolCache<TPool>>().instance;
|
||||||
|
}
|
||||||
|
#if UNITY_2020_3_OR_NEWER
|
||||||
|
[UnityEngine.Scripting.Preserve]
|
||||||
|
#endif
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static TPool GetPool<TPool>(int worldID) where TPool : IEcsPoolImplementation, new()
|
||||||
|
{
|
||||||
|
return Get<PoolCache<TPool>>(worldID).instance;
|
||||||
|
}
|
||||||
|
#if UNITY_2020_3_OR_NEWER
|
||||||
|
[UnityEngine.Scripting.Preserve]
|
||||||
|
#endif
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static TPool UncheckedGetPool<TPool>(int worldID) where TPool : IEcsPoolImplementation, new()
|
||||||
|
{
|
||||||
|
return UncheckedGet<PoolCache<TPool>>(worldID).instance;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Declare/Create
|
||||||
|
private int DeclareComponentType(int typeCode)
|
||||||
|
{
|
||||||
|
if (!_componentIds.TryGetValue(typeCode, out int componentId))
|
||||||
|
{
|
||||||
|
componentId = _poolsCount++;
|
||||||
|
_componentIds.Add(typeCode, componentId);
|
||||||
|
}
|
||||||
|
return componentId;
|
||||||
|
}
|
||||||
|
private TPool CreatePool<TPool>() where TPool : IEcsPoolImplementation, new()
|
||||||
|
{
|
||||||
|
if (_poolIds.Contains(EcsTypeCode.Get<TPool>()))
|
||||||
|
throw new EcsFrameworkException("The pool has already been created.");
|
||||||
|
|
||||||
|
Type componentType = typeof(TPool).GetInterfaces().First(o => o.IsGenericType && o.GetGenericTypeDefinition() == typeof(IEcsPoolImplementation<>));
|
||||||
|
int componentTypeCode = EcsTypeCode.Get(componentType);
|
||||||
|
|
||||||
|
if (_componentIds.TryGetValue(componentTypeCode, out int componentID))
|
||||||
|
{
|
||||||
|
_poolIds[componentTypeCode] = componentID;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
componentID = _poolsCount++;
|
||||||
|
_poolIds[componentTypeCode] = componentID;
|
||||||
|
_componentIds[componentTypeCode] = componentID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_poolsCount >= _pools.Length)
|
||||||
|
{
|
||||||
|
int oldCapacity = _pools.Length;
|
||||||
|
Array.Resize(ref _pools, _pools.Length << 1);
|
||||||
|
ArrayUtility.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_pools[componentID] == _nullPool)
|
||||||
|
{
|
||||||
|
var pool = new TPool();
|
||||||
|
_pools[componentID] = pool;
|
||||||
|
pool.OnInit(this, componentID);
|
||||||
|
}
|
||||||
|
return (TPool)_pools[componentID];
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -21,7 +21,7 @@ namespace DCFApixels.DragonECS
|
|||||||
private const int DEL_ENT_BUFFER_SIZE_OFFSET = 2;
|
private const int DEL_ENT_BUFFER_SIZE_OFFSET = 2;
|
||||||
|
|
||||||
private static EcsWorld[] Worlds = new EcsWorld[4];
|
private static EcsWorld[] Worlds = new EcsWorld[4];
|
||||||
private static IntDispenser _worldIdDispenser = new IntDispenser(0);
|
private static IdDispenser _worldIdDispenser = new IdDispenser(0);
|
||||||
|
|
||||||
private static List<DataReleaser> _dataReleaseres = new List<DataReleaser>();
|
private static List<DataReleaser> _dataReleaseres = new List<DataReleaser>();
|
||||||
|
|
||||||
@ -101,5 +101,8 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
internal sealed class EcsNullWorld : EcsWorld { }
|
internal sealed class EcsNullWorld : EcsWorld
|
||||||
|
{
|
||||||
|
internal EcsNullWorld() : base(false) { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
@ -9,7 +10,8 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
private static readonly Dictionary<Type, int> _codes = new Dictionary<Type, int>();
|
private static readonly Dictionary<Type, int> _codes = new Dictionary<Type, int>();
|
||||||
private static int _incremetn = 1;
|
private static int _incremetn = 1;
|
||||||
public static int GetCode(Type type)
|
public static int Count => _codes.Count;
|
||||||
|
public static int Get(Type type)
|
||||||
{
|
{
|
||||||
if (!_codes.TryGetValue(type, out int code))
|
if (!_codes.TryGetValue(type, out int code))
|
||||||
{
|
{
|
||||||
@ -18,10 +20,11 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
public static int Count => _codes.Count;
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static class Cache<T>
|
public static int Get<T>() => Cache<T>.code;
|
||||||
|
private static class Cache<T>
|
||||||
{
|
{
|
||||||
public static readonly int code = GetCode(typeof(T));
|
public static readonly int code = Get(typeof(T));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace DCFApixels
|
namespace DCFApixels.DragonECS.Utils
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
||||||
|
228
src/Utils/SparseArray.cs
Normal file
228
src/Utils/SparseArray.cs
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
//SparseArray. Analogous to Dictionary<int, T>, but faster.
|
||||||
|
//Benchmark result of indexer.get speed test with 300 elements:
|
||||||
|
//[Dictinary: 5.786us] [SparseArray: 2.047us].
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics.Contracts;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace DCFApixels.DragonECS.Utils
|
||||||
|
{
|
||||||
|
public class SparseArray<TValue>
|
||||||
|
{
|
||||||
|
public const int MIN_CAPACITY_BITS_OFFSET = 4;
|
||||||
|
public const int MIN_CAPACITY = 1 << MIN_CAPACITY_BITS_OFFSET;
|
||||||
|
private const int EMPTY = -1;
|
||||||
|
|
||||||
|
private int[] _buckets = Array.Empty<int>();
|
||||||
|
private Entry[] _entries = Array.Empty<Entry>();
|
||||||
|
|
||||||
|
private int _count;
|
||||||
|
|
||||||
|
private int _freeList;
|
||||||
|
private int _freeCount;
|
||||||
|
|
||||||
|
private int _modBitMask;
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
public TValue this[int keyX, int keyY]
|
||||||
|
{
|
||||||
|
get => _entries[FindEntry((keyX << 32) | keyY)].value;
|
||||||
|
set => Insert(keyX + (keyY << 32), value);
|
||||||
|
}
|
||||||
|
public TValue this[int key]
|
||||||
|
{
|
||||||
|
get => _entries[FindEntry(key)].value;
|
||||||
|
set => Insert(key, value);
|
||||||
|
}
|
||||||
|
public int Count => _count;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public SparseArray(int minCapacity = MIN_CAPACITY)
|
||||||
|
{
|
||||||
|
minCapacity = NormalizeCapacity(minCapacity);
|
||||||
|
_buckets = new int[minCapacity];
|
||||||
|
for (int i = 0; i < minCapacity; i++)
|
||||||
|
_buckets[i] = EMPTY;
|
||||||
|
_entries = new Entry[minCapacity];
|
||||||
|
_modBitMask = (minCapacity - 1) & 0x7FFFFFFF;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Add/Contains/Remove
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Add(int keyX, int keyY, TValue value) => Add((keyX << 32) | keyY, value);
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Add(int key, TValue value)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
if (Contains(key))
|
||||||
|
throw new ArgumentException("Contains(hashKey) is true");
|
||||||
|
#endif
|
||||||
|
Insert(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(int keyX, int keyY) => FindEntry((keyX << 32) | keyY) >= 0;
|
||||||
|
public bool Contains(int key) => FindEntry(key) >= 0;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool Remove(int keyX, int keyY) => Remove((keyX << 32) | keyY);
|
||||||
|
public bool Remove(int key)
|
||||||
|
{
|
||||||
|
int bucket = key & _modBitMask;
|
||||||
|
int last = -1;
|
||||||
|
for (int i = _buckets[bucket]; i >= 0; last = i, i = _entries[i].next)
|
||||||
|
{
|
||||||
|
if (_entries[i].hashKey == key)
|
||||||
|
{
|
||||||
|
if (last < 0)
|
||||||
|
{
|
||||||
|
_buckets[bucket] = _entries[i].next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_entries[last].next = _entries[i].next;
|
||||||
|
}
|
||||||
|
_entries[i].next = _freeList;
|
||||||
|
_entries[i].hashKey = -1;
|
||||||
|
_entries[i].value = default;
|
||||||
|
_freeList = i;
|
||||||
|
_freeCount++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Find/Insert
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private int FindEntry(int key)
|
||||||
|
{
|
||||||
|
for (int i = _buckets[key & _modBitMask]; i >= 0; i = _entries[i].next)
|
||||||
|
if (_entries[i].hashKey == key) return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
private void Insert(int key, TValue value)
|
||||||
|
{
|
||||||
|
int targetBucket = key & _modBitMask;
|
||||||
|
|
||||||
|
for (int i = _buckets[targetBucket]; i >= 0; i = _entries[i].next)
|
||||||
|
{
|
||||||
|
if (_entries[i].hashKey == key)
|
||||||
|
{
|
||||||
|
_entries[i].value = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int index;
|
||||||
|
if (_freeCount > 0)
|
||||||
|
{
|
||||||
|
index = _freeList;
|
||||||
|
_freeList = _entries[index].next;
|
||||||
|
_freeCount--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_count == _entries.Length)
|
||||||
|
{
|
||||||
|
Resize();
|
||||||
|
targetBucket = key & _modBitMask;
|
||||||
|
}
|
||||||
|
index = _count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
_entries[index].next = _buckets[targetBucket];
|
||||||
|
_entries[index].hashKey = key;
|
||||||
|
_entries[index].value = value;
|
||||||
|
_buckets[targetBucket] = index;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region TryGetValue
|
||||||
|
public bool TryGetValue(int keyX, int keyY, out TValue value)
|
||||||
|
{
|
||||||
|
int index = FindEntry((keyX << 32) | keyY);
|
||||||
|
if (index < 0)
|
||||||
|
{
|
||||||
|
value = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
value = _entries[index].value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public bool TryGetValue(int key, out TValue value)
|
||||||
|
{
|
||||||
|
int index = FindEntry(key);
|
||||||
|
if (index < 0)
|
||||||
|
{
|
||||||
|
value = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
value = _entries[index].value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Clear
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
if (_count > 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _buckets.Length; i++)
|
||||||
|
{
|
||||||
|
_buckets[i] = -1;
|
||||||
|
}
|
||||||
|
Array.Clear(_entries, 0, _count);
|
||||||
|
_count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Resize
|
||||||
|
private void Resize()
|
||||||
|
{
|
||||||
|
int newSize = _buckets.Length << 1;
|
||||||
|
_modBitMask = (newSize - 1) & 0x7FFFFFFF;
|
||||||
|
|
||||||
|
Contract.Assert(newSize >= _entries.Length);
|
||||||
|
int[] newBuckets = new int[newSize];
|
||||||
|
for (int i = 0; i < newBuckets.Length; i++)
|
||||||
|
newBuckets[i] = EMPTY;
|
||||||
|
|
||||||
|
Entry[] newEntries = new Entry[newSize];
|
||||||
|
Array.Copy(_entries, 0, newEntries, 0, _count);
|
||||||
|
for (int i = 0; i < _count; i++)
|
||||||
|
{
|
||||||
|
if (newEntries[i].hashKey >= 0)
|
||||||
|
{
|
||||||
|
int bucket = newEntries[i].hashKey % newSize;
|
||||||
|
newEntries[i].next = newBuckets[bucket];
|
||||||
|
newBuckets[bucket] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_buckets = newBuckets;
|
||||||
|
_entries = newEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int NormalizeCapacity(int capacity)
|
||||||
|
{
|
||||||
|
int result = MIN_CAPACITY;
|
||||||
|
while (result < capacity) result <<= 1;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Utils
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||||
|
private struct Entry
|
||||||
|
{
|
||||||
|
public int next; // Index of next entry, -1 if last
|
||||||
|
public int hashKey;
|
||||||
|
public TValue value;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -1,184 +0,0 @@
|
|||||||
using DCFApixels.DragonECS.Utils;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
|
||||||
{
|
|
||||||
//TODO этот класс требует переработки, изначально такая конструкция имела хорошую производительность, но сейчас он слишком раздулся
|
|
||||||
internal static class WorldMetaStorage
|
|
||||||
{
|
|
||||||
private static int _tokenCount = 0;
|
|
||||||
private static List<ResizerBase> _resizers = new List<ResizerBase>();
|
|
||||||
private static WorldTypeMeta[] _metas = new WorldTypeMeta[0];
|
|
||||||
private static Dictionary<Type, int> _worldIds = new Dictionary<Type, int>();
|
|
||||||
private static class WorldIndex<TWorldArchetype>
|
|
||||||
{
|
|
||||||
public static int id = GetWorldID(typeof(TWorldArchetype));
|
|
||||||
}
|
|
||||||
private static int GetToken(Type worldType)
|
|
||||||
{
|
|
||||||
WorldTypeMeta meta = new WorldTypeMeta(worldType);
|
|
||||||
meta.id = _tokenCount;
|
|
||||||
Array.Resize(ref _metas, ++_tokenCount);
|
|
||||||
_metas[_tokenCount - 1] = meta;
|
|
||||||
|
|
||||||
foreach (var item in _resizers)
|
|
||||||
item.Resize(_tokenCount);
|
|
||||||
return _tokenCount - 1;
|
|
||||||
}
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static int GetWorldID(Type worldType)
|
|
||||||
{
|
|
||||||
if (!_worldIds.TryGetValue(worldType, out int id))
|
|
||||||
{
|
|
||||||
id = GetToken(worldType);
|
|
||||||
_worldIds.Add(worldType, id);
|
|
||||||
}
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Type GetWorldType(int worldTypeID) => _metas[worldTypeID].worldType;
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static int GetWorldID<TWorldArchetype>() => WorldIndex<TWorldArchetype>.id;
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static int GetComponentID<T>(int worldID) => Component<T>.Get(worldID);
|
|
||||||
public static int GetComponentID(Type type, int worldID) => _metas[worldID].GetComponentID(type);
|
|
||||||
public static bool IsComponentTypeDeclared(int worldID, Type type) => _metas[worldID].IsDeclaredComponentType(type);
|
|
||||||
public static Type GetComponentType(int worldID, int componentID) => _metas[worldID].GetComponentType(componentID);
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static int GetPoolID<T>(int worldID) => Pool<T>.Get(worldID);
|
|
||||||
|
|
||||||
private abstract class ResizerBase
|
|
||||||
{
|
|
||||||
public abstract Type Type { get; }
|
|
||||||
public abstract int[] IDS { get; }
|
|
||||||
public abstract void Resize(int size);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Containers
|
|
||||||
public static class PoolComponentIdArrays
|
|
||||||
{
|
|
||||||
private static Dictionary<Type, int[]> _componentTypeArrayPairs = new Dictionary<Type, int[]>();
|
|
||||||
|
|
||||||
public static int[] GetIdsArray(Type type)
|
|
||||||
{
|
|
||||||
int targetSize = _tokenCount;
|
|
||||||
if (!_componentTypeArrayPairs.TryGetValue(type, out int[] result))
|
|
||||||
{
|
|
||||||
result = new int[targetSize];
|
|
||||||
for (int i = 0; i < result.Length; i++)
|
|
||||||
result[i] = -1;
|
|
||||||
_componentTypeArrayPairs.Add(type, result);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (result.Length < targetSize)
|
|
||||||
{
|
|
||||||
int oldSize = result.Length;
|
|
||||||
Array.Resize(ref result, targetSize);
|
|
||||||
ArrayUtility.Fill(result, -1, oldSize, targetSize);
|
|
||||||
_componentTypeArrayPairs[type] = result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int GetComponentID(Type type, int token)
|
|
||||||
{
|
|
||||||
GetIdsArray(type);
|
|
||||||
ref int id = ref _componentTypeArrayPairs[type][token];
|
|
||||||
if (id < 0)
|
|
||||||
id = _metas[token].DeclareComponentType(type);
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private static class Pool<T>
|
|
||||||
{
|
|
||||||
public static int[] ids;
|
|
||||||
private static Type componentType = typeof(T).GetGenericArguments()[0];
|
|
||||||
static Pool()
|
|
||||||
{
|
|
||||||
ids = PoolComponentIdArrays.GetIdsArray(componentType);
|
|
||||||
_resizers.Add(new Resizer());
|
|
||||||
}
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static int Get(int token)
|
|
||||||
{
|
|
||||||
ref int id = ref ids[token];
|
|
||||||
if (id < 0)
|
|
||||||
{
|
|
||||||
id = PoolComponentIdArrays.GetComponentID(componentType, token);
|
|
||||||
}
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
private sealed class Resizer : ResizerBase
|
|
||||||
{
|
|
||||||
public override Type Type => typeof(T);
|
|
||||||
public override int[] IDS => ids;
|
|
||||||
public override void Resize(int size)
|
|
||||||
{
|
|
||||||
ids = PoolComponentIdArrays.GetIdsArray(componentType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private static class Component<T>
|
|
||||||
{
|
|
||||||
public static int[] ids;
|
|
||||||
static Component()
|
|
||||||
{
|
|
||||||
ids = PoolComponentIdArrays.GetIdsArray(typeof(T));
|
|
||||||
_resizers.Add(new Resizer());
|
|
||||||
}
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static int Get(int token)
|
|
||||||
{
|
|
||||||
ref int id = ref ids[token];
|
|
||||||
if (id < 0)
|
|
||||||
{
|
|
||||||
id = PoolComponentIdArrays.GetComponentID(typeof(T), token);
|
|
||||||
}
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
private sealed class Resizer : ResizerBase
|
|
||||||
{
|
|
||||||
public override Type Type => typeof(T);
|
|
||||||
public override int[] IDS => ids;
|
|
||||||
public override void Resize(int size)
|
|
||||||
{
|
|
||||||
ids = PoolComponentIdArrays.GetIdsArray(typeof(T));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
private class WorldTypeMeta
|
|
||||||
{
|
|
||||||
public readonly Type worldType;
|
|
||||||
public int id;
|
|
||||||
public int componentCount;
|
|
||||||
public int worldComponentCount;
|
|
||||||
private Type[] _types = new Type[10];
|
|
||||||
private Dictionary<Type, int> _declaredComponentTypes = new Dictionary<Type, int>();
|
|
||||||
|
|
||||||
public WorldTypeMeta(Type worldType)
|
|
||||||
{
|
|
||||||
this.worldType = worldType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int DeclareComponentType(Type type)
|
|
||||||
{
|
|
||||||
int id = componentCount++;
|
|
||||||
if (_types.Length <= id)
|
|
||||||
Array.Resize(ref _types, id + 10);
|
|
||||||
_types[id] = type;
|
|
||||||
_declaredComponentTypes.Add(type, id);
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
public bool IsDeclaredComponentType(Type type) => _declaredComponentTypes.ContainsKey(type);
|
|
||||||
public Type GetComponentType(int componentID) => _types[componentID];
|
|
||||||
public int GetComponentID(Type type) => PoolComponentIdArrays.GetComponentID(type, id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 5e06cf4352ab9414293b145eb27daba7
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
Loading…
Reference in New Issue
Block a user