forked from Misaki/GhostEngine
Updated entity query
This commit is contained in:
@@ -15,13 +15,23 @@ public partial class ArcEntityTest : ITest
|
||||
public void Run()
|
||||
{
|
||||
var entity1 = _world.EntityManager.CreateEntity(ComponentTypeID<TransformData>.value);
|
||||
Console.WriteLine($"{entity1} Has Transform: {_world.EntityManager.HasComponent<TransformData>(entity1)}");
|
||||
var mesh = new MeshData { index = 1 };
|
||||
_world.EntityManager.AddComponent<MeshData>(entity1, ref mesh);
|
||||
Console.WriteLine($"{entity1} Has Mesh: {_world.EntityManager.HasComponent<MeshData>(entity1)}");
|
||||
|
||||
_world.EntityManager.DestoryEntity(entity1);
|
||||
Console.WriteLine($"{entity1} Has Transform: {_world.EntityManager.HasComponent<TransformData>(entity1)}");
|
||||
var queryID = new QueryBuilder().WithAll<TransformData>().Build(_world);
|
||||
ref var query = ref _world.GetEntityQueryReference(queryID);
|
||||
|
||||
foreach (var item in query)
|
||||
{
|
||||
var transforms = item.GetComponentData<TransformData>();
|
||||
Console.WriteLine($"Item Count: {item.Count}");
|
||||
for (var i = 0; i < item.Count; i++)
|
||||
{
|
||||
Console.WriteLine($"Entity Position: {transforms[i].position}");
|
||||
transforms[i].position = new float3(1, 2, 3);
|
||||
Console.WriteLine($"Updated Entity Position: {transforms[i].position}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Cleanup()
|
||||
|
||||
@@ -6,7 +6,7 @@ using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ghost.Entities;
|
||||
|
||||
internal unsafe struct Chuck : IDisposable
|
||||
internal unsafe struct Chunk : IDisposable
|
||||
{
|
||||
public const int CHUNK_SIZE = 16384; // 16 KB
|
||||
|
||||
@@ -22,7 +22,7 @@ internal unsafe struct Chuck : IDisposable
|
||||
|
||||
public int Capacity => _capacity;
|
||||
|
||||
public Chuck(int size, int capacity)
|
||||
public Chunk(int size, int capacity)
|
||||
{
|
||||
_data = new UnsafeArray<byte>(size, Allocator.Persistent);
|
||||
_capacity = capacity;
|
||||
@@ -59,11 +59,11 @@ internal unsafe struct Archetype : IIdentifierType, IDisposable
|
||||
private readonly Identifier<Archetype> _id;
|
||||
private readonly Identifier<World> _worldID;
|
||||
|
||||
private UnsafeBitSet _signature;
|
||||
private UnsafeList<Chuck> _chunks;
|
||||
private UnsafeArray<ComponentMemoryLayout> _layouts;
|
||||
private UnsafeArray<int> _componentIDToOffset;
|
||||
internal UnsafeBitSet _signature;
|
||||
internal UnsafeList<Chunk> _chunks;
|
||||
internal UnsafeArray<ComponentMemoryLayout> _layouts;
|
||||
|
||||
private UnsafeArray<int> _componentIDToOffset;
|
||||
// TODO: Is hash map better?
|
||||
private UnsafeList<Edge> _edgesAdd;
|
||||
private UnsafeList<Edge> _edgesRemove;
|
||||
@@ -75,10 +75,6 @@ internal unsafe struct Archetype : IIdentifierType, IDisposable
|
||||
|
||||
public Identifier<Archetype> ID => _id;
|
||||
|
||||
public UnsafeBitSet Signature => _signature;
|
||||
public UnsafeList<Chuck> Chunks => _chunks;
|
||||
public UnsafeArray<ComponentMemoryLayout> Layouts => _layouts;
|
||||
|
||||
public int EntityCapacity => _entityCapacity;
|
||||
public int ChunkCount => _chunks.Count;
|
||||
|
||||
@@ -90,14 +86,14 @@ internal unsafe struct Archetype : IIdentifierType, IDisposable
|
||||
if (componentIds.IsEmpty)
|
||||
{
|
||||
_signature = new UnsafeBitSet(1, Allocator.Persistent, AllocationOption.Clear);
|
||||
_chunks = new UnsafeList<Chuck>(4, Allocator.Persistent);
|
||||
_chunks = new UnsafeList<Chunk>(4, Allocator.Persistent);
|
||||
|
||||
_edgesAdd = new UnsafeList<Edge>(4, Allocator.Persistent);
|
||||
_edgesRemove = new UnsafeList<Edge>(4, Allocator.Persistent);
|
||||
|
||||
_signature.ClearAll();
|
||||
|
||||
_entityCapacity = Chuck.CHUNK_SIZE / sizeof(Entity);
|
||||
_entityCapacity = Chunk.CHUNK_SIZE / sizeof(Entity);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -112,7 +108,7 @@ internal unsafe struct Archetype : IIdentifierType, IDisposable
|
||||
}
|
||||
|
||||
_signature = new UnsafeBitSet(highestComponentID + 1, Allocator.Persistent, AllocationOption.Clear);
|
||||
_chunks = new UnsafeList<Chuck>(4, Allocator.Persistent);
|
||||
_chunks = new UnsafeList<Chunk>(4, Allocator.Persistent);
|
||||
|
||||
_edgesAdd = new UnsafeList<Edge>(4, Allocator.Persistent);
|
||||
_edgesRemove = new UnsafeList<Edge>(4, Allocator.Persistent);
|
||||
@@ -148,7 +144,7 @@ internal unsafe struct Archetype : IIdentifierType, IDisposable
|
||||
}
|
||||
|
||||
_maxComponentID = maxComponentID;
|
||||
_entityCapacity = Chuck.CHUNK_SIZE / bytesPerEntity;
|
||||
_entityCapacity = Chunk.CHUNK_SIZE / bytesPerEntity;
|
||||
_layouts = new UnsafeArray<ComponentMemoryLayout>(components.Length, Allocator.Persistent);
|
||||
_componentIDToOffset = new UnsafeArray<int>(_maxComponentID + 1, Allocator.Persistent);
|
||||
|
||||
@@ -176,7 +172,7 @@ internal unsafe struct Archetype : IIdentifierType, IDisposable
|
||||
tempOffsets[i] = currentOffset;
|
||||
currentOffset += _entityCapacity * size;
|
||||
|
||||
if (currentOffset > Chuck.CHUNK_SIZE)
|
||||
if (currentOffset > Chunk.CHUNK_SIZE)
|
||||
{
|
||||
fits = false;
|
||||
break;
|
||||
@@ -220,7 +216,7 @@ internal unsafe struct Archetype : IIdentifierType, IDisposable
|
||||
}
|
||||
|
||||
// Need to allocate a new chunk
|
||||
var newChunk = new Chuck(Chuck.CHUNK_SIZE, _entityCapacity);
|
||||
var newChunk = new Chunk(Chunk.CHUNK_SIZE, _entityCapacity);
|
||||
|
||||
rowIndex = 0;
|
||||
newChunk.Count++;
|
||||
@@ -234,9 +230,9 @@ internal unsafe struct Archetype : IIdentifierType, IDisposable
|
||||
{
|
||||
var chunk = _chunks[chunkIndex];
|
||||
var chunkBase = chunk.GetUnsafePtr();
|
||||
var pEntity = chunkBase + _entityIdsOffset + (sizeof(Entity) * rowIndex);
|
||||
var dst = chunkBase + _entityIdsOffset + (sizeof(Entity) * rowIndex);
|
||||
|
||||
MemoryUtility.MemCpy(&entity, pEntity, (nuint)sizeof(Entity));
|
||||
MemoryUtility.MemCpy(&entity, dst, (nuint)sizeof(Entity));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -253,7 +249,20 @@ internal unsafe struct Archetype : IIdentifierType, IDisposable
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref Chuck GetChunkReference(int index)
|
||||
public void* GetComponentDataPtr(int chunkIndex, int rowIndex, Identifier<IComponent> componentID)
|
||||
{
|
||||
var offset = _componentIDToOffset[componentID];
|
||||
var chunk = _chunks[chunkIndex];
|
||||
|
||||
var chunkBase = chunk.GetUnsafePtr();
|
||||
var size = ComponentRegister.GetComponentInfo(componentID).size;
|
||||
var dst = chunkBase + offset + (size * rowIndex);
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref Chunk GetChunkReference(int index)
|
||||
{
|
||||
return ref _chunks[index];
|
||||
}
|
||||
|
||||
@@ -110,13 +110,13 @@ public unsafe class EntityManager : IDisposable
|
||||
ref Archetype newArch, int newChunk, int newRow)
|
||||
{
|
||||
// Iterate every component type in the OLD archetype
|
||||
for (var i = 0; i < oldArch.Layouts.Count; i++)
|
||||
for (var i = 0; i < oldArch._layouts.Count; i++)
|
||||
{
|
||||
var layout = oldArch.Layouts[i];
|
||||
var layout = oldArch._layouts[i];
|
||||
|
||||
var src = oldArch.Chunks[oldChunk].GetUnsafePtr() + layout.offset + (layout.size * oldRow);
|
||||
var src = oldArch._chunks[oldChunk].GetUnsafePtr() + layout.offset + (layout.size * oldRow);
|
||||
var newOffset = newArch.GetOffset(layout.componentID); // O(1) Lookup
|
||||
var dst = oldArch.Chunks[oldChunk].GetUnsafePtr() + newOffset + (layout.size * newRow);
|
||||
var dst = oldArch._chunks[oldChunk].GetUnsafePtr() + newOffset + (layout.size * newRow);
|
||||
|
||||
MemoryUtility.MemCpy(src, dst, (nuint)layout.size);
|
||||
}
|
||||
@@ -133,7 +133,7 @@ public unsafe class EntityManager : IDisposable
|
||||
|
||||
// Build new archetype signature
|
||||
ref var oldArchetype = ref _world.GetArchetypeReference(location.archetypeID);
|
||||
var oldSignature = oldArchetype.Signature;
|
||||
var oldSignature = oldArchetype._signature;
|
||||
|
||||
// TODO: Check edge cache first.
|
||||
var newArcID = oldArchetype.GetEdgeAdd(componentID);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Ghost.Entities;
|
||||
|
||||
public unsafe class EntityQuery<T1, T2>
|
||||
public unsafe class EntityQueryy<T1, T2>
|
||||
where T1 : unmanaged, IComponent
|
||||
where T2 : unmanaged, IComponent
|
||||
{
|
||||
|
||||
263
Ghost.Entities/Query.cs
Normal file
263
Ghost.Entities/Query.cs
Normal file
@@ -0,0 +1,263 @@
|
||||
using Ghost.Core;
|
||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||
using Misaki.HighPerformance.LowLevel.Collections;
|
||||
|
||||
namespace Ghost.Entities;
|
||||
|
||||
public struct EntityQueryMask : IDisposable
|
||||
{
|
||||
public UnsafeBitSet all;
|
||||
public UnsafeBitSet any;
|
||||
public UnsafeBitSet absent;
|
||||
|
||||
public bool Matches(UnsafeBitSet archetypeSignature)
|
||||
{
|
||||
// 1. Check All: Archetype must have ALL bits set
|
||||
if (all.IsCreated && !archetypeSignature.All(all))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. Check None: Archetype must have NONE of these bits set
|
||||
if (absent.IsCreated && archetypeSignature.Any(absent))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3. Check Any: Archetype must have AT LEAST ONE of these bits (if Any is defined)
|
||||
if (any.IsCreated && any.Count != 0 && !archetypeSignature.Any(any))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var hash = 17;
|
||||
if (all.IsCreated) hash = hash * 23 + all.GetHashCode();
|
||||
if (absent.IsCreated) hash = hash * 23 + absent.GetHashCode();
|
||||
if (any.IsCreated) hash = hash * 23 + any.GetHashCode();
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
all.Dispose();
|
||||
any.Dispose();
|
||||
absent.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe struct EntityQuery : IIdentifierType, IDisposable
|
||||
{
|
||||
public readonly ref struct QueryItem
|
||||
{
|
||||
private readonly ref Archetype _archetype;
|
||||
private readonly ref Chunk _chunk;
|
||||
|
||||
public readonly int Count => _chunk.Count;
|
||||
|
||||
internal QueryItem(ref Archetype archetype, int chunkIndex)
|
||||
{
|
||||
_archetype = ref archetype;
|
||||
_chunk = ref archetype.GetChunkReference(chunkIndex);
|
||||
}
|
||||
|
||||
public readonly Span<T> GetComponentData<T>()
|
||||
where T : unmanaged, IComponent
|
||||
{
|
||||
var offset = _archetype.GetOffset(ComponentTypeID<T>.value);
|
||||
if (offset < 0)
|
||||
{
|
||||
throw new InvalidOperationException($"Archetype does not contain component of type {typeof(T)}");
|
||||
}
|
||||
|
||||
var ptr = (byte*)_chunk.GetUnsafePtr() + offset;
|
||||
return new Span<T>(ptr, _chunk.Count);
|
||||
}
|
||||
}
|
||||
|
||||
public ref struct ChunkEnumerator
|
||||
{
|
||||
private ReadOnlyUnsafeCollection<Identifier<Archetype>> _matchingArchetypes;
|
||||
private World _world;
|
||||
private int _archetypeIndex;
|
||||
private int _chunkIndex;
|
||||
|
||||
internal ChunkEnumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, World world)
|
||||
{
|
||||
_matchingArchetypes = matchingArchetypes;
|
||||
_world = world;
|
||||
_archetypeIndex = 0;
|
||||
_chunkIndex = -1;
|
||||
}
|
||||
|
||||
public QueryItem Current
|
||||
{
|
||||
get
|
||||
{
|
||||
ref var archetype = ref _world.GetArchetypeReference(_matchingArchetypes[_archetypeIndex]);
|
||||
return new QueryItem(ref archetype, _chunkIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
_chunkIndex++;
|
||||
|
||||
while (_archetypeIndex < _matchingArchetypes.Count)
|
||||
{
|
||||
ref var archetype = ref _world.GetArchetypeReference(_matchingArchetypes[_archetypeIndex]);
|
||||
if (_chunkIndex < archetype.ChunkCount)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
_chunkIndex = 0;
|
||||
_archetypeIndex++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_archetypeIndex = 0;
|
||||
_chunkIndex = -1;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private Identifier<World> _worldID;
|
||||
private EntityQueryMask _mask;
|
||||
private UnsafeList<Identifier<Archetype>> _matchingArchetypes;
|
||||
|
||||
internal EntityQuery(Identifier<World> worldID, EntityQueryMask mask)
|
||||
{
|
||||
_worldID = worldID;
|
||||
_mask = mask;
|
||||
_matchingArchetypes = new UnsafeList<Identifier<Archetype>>(8, Allocator.Persistent);
|
||||
}
|
||||
|
||||
// Called by World when a new archetype is created
|
||||
internal void AddArchetypeIfMatch(Archetype archetype)
|
||||
{
|
||||
if (_mask.Matches(archetype._signature))
|
||||
{
|
||||
_matchingArchetypes.Add(archetype.ID);
|
||||
}
|
||||
}
|
||||
|
||||
public ChunkEnumerator GetEnumerator()
|
||||
{
|
||||
var world = World.GetWorld(_worldID).Value;
|
||||
return new ChunkEnumerator(_matchingArchetypes.AsReadOnly(), world);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_mask.Dispose();
|
||||
_matchingArchetypes.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public ref struct QueryBuilder
|
||||
{
|
||||
private Stack.Scope _scope;
|
||||
|
||||
private UnsafeList<Identifier<IComponent>> _all;
|
||||
private UnsafeList<Identifier<IComponent>> _any;
|
||||
private UnsafeList<Identifier<IComponent>> _absent;
|
||||
|
||||
public QueryBuilder()
|
||||
{
|
||||
_scope = AllocationManager.CreateStackScope();
|
||||
|
||||
_all = new UnsafeList<Identifier<IComponent>>(4, Allocator.Stack);
|
||||
_any = new UnsafeList<Identifier<IComponent>>(4, Allocator.Stack);
|
||||
_absent = new UnsafeList<Identifier<IComponent>>(4, Allocator.Stack);
|
||||
}
|
||||
|
||||
public QueryBuilder WithAll<T>()
|
||||
where T : unmanaged, IComponent
|
||||
{
|
||||
_all.Add(ComponentTypeID<T>.value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryBuilder WithAny<T>()
|
||||
where T : unmanaged, IComponent
|
||||
{
|
||||
_any.Add(ComponentTypeID<T>.value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryBuilder WithNone<T>()
|
||||
where T : unmanaged, IComponent
|
||||
{
|
||||
_absent.Add(ComponentTypeID<T>.value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Identifier<EntityQuery> Build(World world)
|
||||
{
|
||||
// 1. Calculate max component ID to size the BitSets
|
||||
int maxID = 0;
|
||||
FindMax(_all, ref maxID);
|
||||
FindMax(_any, ref maxID);
|
||||
FindMax(_absent, ref maxID);
|
||||
|
||||
// 2. Create the Mask
|
||||
using var mask = new EntityQueryMask
|
||||
{
|
||||
all = new UnsafeBitSet(maxID + 1, Allocator.Stack),
|
||||
any = new UnsafeBitSet(maxID + 1, Allocator.Stack),
|
||||
absent = new UnsafeBitSet(maxID + 1, Allocator.Stack)
|
||||
};
|
||||
|
||||
// 3. Fill BitSets
|
||||
foreach (var id in _all) mask.all.SetBit(id);
|
||||
foreach (var id in _any) mask.any.SetBit(id);
|
||||
foreach (var id in _absent) mask.absent.SetBit(id);
|
||||
|
||||
// 4. Ask World for the Query (Cached)
|
||||
var queryID = world.GetEntityQueryIDByMaskHash(mask.GetHashCode());
|
||||
if (queryID.IsNotValid)
|
||||
{
|
||||
queryID = world.CreateEntityQuery(mask);
|
||||
ref var query = ref world.GetEntityQueryReference(queryID);
|
||||
for (var i = 0; i < world.ArchetypeCount; i++)
|
||||
{
|
||||
ref var archetype = ref world.GetArchetypeReference(i);
|
||||
query.AddArchetypeIfMatch(archetype);
|
||||
}
|
||||
}
|
||||
|
||||
Dispose();
|
||||
|
||||
return queryID;
|
||||
}
|
||||
|
||||
private void FindMax(UnsafeList<Identifier<IComponent>> list, ref int max)
|
||||
{
|
||||
foreach (var id in list)
|
||||
{
|
||||
if (id.value > max) max = id.value;
|
||||
}
|
||||
}
|
||||
|
||||
private void Dispose()
|
||||
{
|
||||
_all.Dispose();
|
||||
_any.Dispose();
|
||||
_absent.Dispose();
|
||||
|
||||
_scope.Dispose();
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,23 @@ public partial class World
|
||||
}
|
||||
}
|
||||
|
||||
public static void Destroy(Identifier<World> id)
|
||||
{
|
||||
lock (s_worlds)
|
||||
{
|
||||
if (id.value < 0 || id.value >= s_worlds.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var world = s_worlds[id.value];
|
||||
if (world is not null)
|
||||
{
|
||||
world.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Result<World, ResultStatus> GetWorld(Identifier<World> id)
|
||||
{
|
||||
@@ -54,13 +71,19 @@ public partial class World : IIdentifierType, IDisposable, IEquatable<World>
|
||||
{
|
||||
private readonly Identifier<World> _id;
|
||||
|
||||
private UnsafeList<Archetype> _archetypes;
|
||||
private UnsafeHashMap<int, Identifier<Archetype>> _archetypeLookup; // Signature Hash to Archetype ID
|
||||
private EntityManager _entityManager;
|
||||
private EntityCommandBuffer _entityCommandBuffer;
|
||||
|
||||
private UnsafeList<Archetype> _archetypes;
|
||||
private UnsafeList<EntityQuery> _entityQueries;
|
||||
|
||||
private UnsafeHashMap<int, Identifier<Archetype>> _archetypeLookup; // Signature Hash to Archetype ID
|
||||
private UnsafeHashMap<int, Identifier<EntityQuery>> _querieLookup; // Query Mask Hash to Query ID
|
||||
|
||||
private bool _disposed = false;
|
||||
|
||||
internal int ArchetypeCount => _archetypes.Count;
|
||||
|
||||
public Identifier<World> ID => _id;
|
||||
public EntityManager EntityManager => _entityManager;
|
||||
public EntityCommandBuffer EntityCommandBuffer => _entityCommandBuffer;
|
||||
@@ -70,7 +93,10 @@ public partial class World : IIdentifierType, IDisposable, IEquatable<World>
|
||||
_id = id;
|
||||
|
||||
_archetypes = new UnsafeList<Archetype>(16, Allocator.Persistent);
|
||||
_entityQueries = new UnsafeList<EntityQuery>(16, Allocator.Persistent);
|
||||
|
||||
_archetypeLookup = new UnsafeHashMap<int, Identifier<Archetype>>(16, Allocator.Persistent);
|
||||
_querieLookup = new UnsafeHashMap<int, Identifier<EntityQuery>>(16, Allocator.Persistent);
|
||||
|
||||
_entityManager = new EntityManager(this, entityCapacity);
|
||||
_entityCommandBuffer = new EntityCommandBuffer(_entityManager);
|
||||
@@ -90,12 +116,13 @@ public partial class World : IIdentifierType, IDisposable, IEquatable<World>
|
||||
_archetypes.Add(new Archetype(arcID, _id, componentTypeIDs));
|
||||
_archetypeLookup.Add(signatureHash, arcID);
|
||||
|
||||
return arcID;
|
||||
}
|
||||
for (int i = 0; i < _entityQueries.Count; i++)
|
||||
{
|
||||
ref var query = ref _entityQueries[i];
|
||||
query.AddArchetypeIfMatch(_archetypes[arcID.value]);
|
||||
}
|
||||
|
||||
internal ref Archetype GetArchetypeReference(Identifier<Archetype> id)
|
||||
{
|
||||
return ref _archetypes[id.value];
|
||||
return arcID;
|
||||
}
|
||||
|
||||
internal Identifier<Archetype> GetArchetypeIDBySignatureHash(int signatureHash)
|
||||
@@ -108,6 +135,35 @@ public partial class World : IIdentifierType, IDisposable, IEquatable<World>
|
||||
return Identifier<Archetype>.Invalid;
|
||||
}
|
||||
|
||||
internal ref Archetype GetArchetypeReference(Identifier<Archetype> id)
|
||||
{
|
||||
return ref _archetypes[id.value];
|
||||
}
|
||||
|
||||
internal Identifier<EntityQuery> CreateEntityQuery(EntityQueryMask mask)
|
||||
{
|
||||
var queryID = new Identifier<EntityQuery>(_entityQueries.Count);
|
||||
_entityQueries.Add(new EntityQuery(_id, mask));
|
||||
_querieLookup.Add(mask.GetHashCode(), queryID);
|
||||
|
||||
return queryID;
|
||||
}
|
||||
|
||||
internal Identifier<EntityQuery> GetEntityQueryIDByMaskHash(int maskHash)
|
||||
{
|
||||
if (_querieLookup.TryGetValue(maskHash, out var queryID))
|
||||
{
|
||||
return queryID;
|
||||
}
|
||||
|
||||
return Identifier<EntityQuery>.Invalid;
|
||||
}
|
||||
|
||||
public ref EntityQuery GetEntityQueryReference(Identifier<EntityQuery> id)
|
||||
{
|
||||
return ref _entityQueries[id.value];
|
||||
}
|
||||
|
||||
public bool Equals(World? other)
|
||||
{
|
||||
return other is not null && _id == other._id;
|
||||
@@ -141,11 +197,15 @@ public partial class World : IIdentifierType, IDisposable, IEquatable<World>
|
||||
}
|
||||
|
||||
_entityManager.Dispose();
|
||||
_entityCommandBuffer.Dispose();
|
||||
|
||||
_archetypes.Dispose();
|
||||
_entityQueries.Dispose();
|
||||
_archetypeLookup.Dispose();
|
||||
_querieLookup.Dispose();
|
||||
|
||||
s_freeWorldSlots.Enqueue(_id);
|
||||
s_worlds[_id] = null;
|
||||
|
||||
_disposed = true;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user