mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2025-09-18 09:54:35 +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
|
||||
{
|
||||
public readonly Type worldType;
|
||||
public readonly EcsWorld world;
|
||||
public readonly int worldID;
|
||||
public readonly int[] included;
|
||||
public readonly int[] excluded;
|
||||
@ -265,11 +265,11 @@ namespace DCFApixels.DragonECS
|
||||
public readonly Type[] excludedTypes;
|
||||
public DebuggerProxy(EcsMask mask)
|
||||
{
|
||||
worldType = WorldMetaStorage.GetWorldType(mask.worldID);
|
||||
world = EcsWorld.GetWorld(mask.worldID);
|
||||
worldID = mask.worldID;
|
||||
included = mask.inc;
|
||||
excluded = mask.exc;
|
||||
Type converter(int o) => WorldMetaStorage.GetComponentType(worldID, o);
|
||||
Type converter(int o) => world.GetComponentType(o);
|
||||
includedTypes = included.Select(converter).ToArray();
|
||||
excludedTypes = excluded.Select(converter).ToArray();
|
||||
}
|
||||
|
@ -19,23 +19,6 @@ namespace DCFApixels.DragonECS
|
||||
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>>
|
||||
where T : EcsAspect
|
||||
{
|
||||
|
@ -10,9 +10,6 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
public readonly short id;
|
||||
|
||||
private Type _worldType;
|
||||
private int _worldTypeID;
|
||||
|
||||
private bool _isDestroyed;
|
||||
|
||||
private IntDispenser _entityDispenser;
|
||||
@ -25,9 +22,6 @@ namespace DCFApixels.DragonECS
|
||||
private int[] _delEntBuffer;
|
||||
private int _delEntBufferCount;
|
||||
|
||||
internal IEcsPoolImplementation[] _pools;
|
||||
private EcsNullPool _nullPool = EcsNullPool.instance;
|
||||
|
||||
private List<WeakReference<EcsGroup>> _groups = new List<WeakReference<EcsGroup>>();
|
||||
private Stack<EcsGroup> _groupsPool = new Stack<EcsGroup>(64);
|
||||
|
||||
@ -36,7 +30,6 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
#region Properties
|
||||
public bool IsDestroyed => _isDestroyed;
|
||||
public int WorldTypeID => _worldTypeID;
|
||||
public int Count => _entitiesCount;
|
||||
public int Capacity => _entitesCapacity; //_denseEntities.Length;
|
||||
public EcsReadonlyGroup Entities => _allEntites.Readonly;
|
||||
@ -51,15 +44,12 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
if (isIndexable)
|
||||
{
|
||||
id = (short)_worldIdDispenser.GetFree();
|
||||
id = (short)_worldIdDispenser.UseFree();
|
||||
if (id >= Worlds.Length)
|
||||
Array.Resize(ref Worlds, Worlds.Length << 1);
|
||||
Worlds[id] = this;
|
||||
}
|
||||
|
||||
_worldType = this.GetType();
|
||||
_worldTypeID = WorldMetaStorage.GetWorldID(_worldType);
|
||||
|
||||
_entityDispenser = new IntDispenser(0);
|
||||
_pools = new IEcsPoolImplementation[512];
|
||||
ArrayUtility.Fill(_pools, _nullPool);
|
||||
@ -83,42 +73,15 @@ namespace DCFApixels.DragonECS
|
||||
ReleaseData(id);
|
||||
_worldIdDispenser.Release(id);
|
||||
_isDestroyed = true;
|
||||
_poolIds = null;
|
||||
_componentIds = null;
|
||||
}
|
||||
#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
|
||||
#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;
|
||||
}
|
||||
[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)]
|
||||
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 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>();
|
||||
|
||||
@ -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.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
@ -9,7 +10,8 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
private static readonly Dictionary<Type, int> _codes = new Dictionary<Type, int>();
|
||||
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))
|
||||
{
|
||||
@ -18,10 +20,11 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
return code;
|
||||
}
|
||||
public static int Count => _codes.Count;
|
||||
internal static class Cache<T>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
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.Runtime.CompilerServices;
|
||||
|
||||
namespace DCFApixels
|
||||
namespace DCFApixels.DragonECS.Utils
|
||||
{
|
||||
[Serializable]
|
||||
[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