From a3863c1263747d790cf3b69a3ae797740922116f Mon Sep 17 00:00:00 2001 From: Misaki Date: Thu, 11 Dec 2025 21:25:32 +0900 Subject: [PATCH] Update version support --- Ghost.Core/Result.cs | 22 + Ghost.Entities.Test/EntityTest.cs | 63 +- Ghost.Entities/Archetype.cs | 76 +- Ghost.Entities/Component.cs | 11 - Ghost.Entities/Ghost.Entities.csproj | 4 +- Ghost.Entities/Query.cs | 56 +- Ghost.Entities/System.cs | 12 +- .../EntityQuery.ComponentIterator.gen.cs | 257 ++++- .../EntityQuery.ComponentIterator.tt | 33 +- ...EntityQuery.EntityComponentIterator.gen.cs | 249 +++- .../EntityQuery.EntityComponentIterator.tt | 32 +- .../Templates/EntityQuery.ForEach.gen.cs | 83 +- .../Templates/EntityQuery.ForEach.tt | 7 +- .../Templates/EntityQuery.JobEntity.gen.cs | 1021 ++++++++++++++--- .../Templates/EntityQuery.JobEntity.tt | 71 +- Ghost.Entities/World.cs | 34 +- 16 files changed, 1699 insertions(+), 332 deletions(-) diff --git a/Ghost.Core/Result.cs b/Ghost.Core/Result.cs index 247a8ca..9b3605d 100644 --- a/Ghost.Core/Result.cs +++ b/Ghost.Core/Result.cs @@ -287,6 +287,17 @@ public static class ResultExtensions return result; } + public static Result OnSuccess(this Result result, Action action) + where E : struct, Enum + { + if (result.IsSuccess) + { + action(result.Value); + } + + return result; + } + public static Result OnFailed(this Result result, Action action) { if (result.IsFailure) @@ -306,4 +317,15 @@ public static class ResultExtensions return result; } + + public static Result OnFailed(this Result result, Action action) + where E : struct, Enum + { + if (result.IsFailure) + { + action(result.Error); + } + + return result; + } } diff --git a/Ghost.Entities.Test/EntityTest.cs b/Ghost.Entities.Test/EntityTest.cs index cb37d87..f6c6368 100644 --- a/Ghost.Entities.Test/EntityTest.cs +++ b/Ghost.Entities.Test/EntityTest.cs @@ -1,14 +1,15 @@ using Ghost.Test.Core; using Misaki.HighPerformance.Jobs; using Misaki.HighPerformance.Mathematics; +using System.Diagnostics; namespace Ghost.Entities.Test; -internal struct TestEntityQueryJob : IJobChunk +internal struct TestChunkQueryJob : IJobChunk { - public void Execute(ChunkView view, int threadIndex) + public readonly void Execute(ChunkView view, int threadIndex) { - var transforms = view.GetComponentData(); + var transforms = view.GetComponentDataRW(); for (var i = 0; i < view.Count; i++) { transforms[i].position += new float3(10, 10, 10); @@ -16,6 +17,14 @@ internal struct TestEntityQueryJob : IJobChunk } } +internal struct TestEntityQueryJob : IJobEntity +{ + public readonly void Execute(Entity entity, ref Transform transform, int index) + { + transform.position += new float3(5, 5, 5); + } +} + public partial class EntityTest : ITest { private JobScheduler _jobScheduler = null!; @@ -42,42 +51,44 @@ public partial class EntityTest : ITest var queryID = new QueryBuilder().WithAllRW().WithAbsent().Build(_world); ref var query = ref _world.GetEntityQueryReference(queryID); - // var testJob = new TestEntityQueryJob(); - // var handle = query.ScheduleChunkParallel(testJob, 64, JobHandle.Invalid); - // _jobScheduler.WaitComplete(handle); - - _world.EntityManager.AddScriptComponent(entity1); - _world.EntityManager.RemoveComponent(entity1); // This should destory the managed entity and call OnDestroy - _world.AdvanceVersion(); - query.ForEach((e, ref t) => - { - Console.WriteLine($"Entity {e} Has Position: {t.position}"); - }); + var testJob = new TestEntityQueryJob(); + var handle = query.ScheduleEntityParallel(testJob, 64, JobHandle.Invalid); + _jobScheduler.WaitComplete(handle); - //foreach (var (entity, transform) in query.GetEntityComponentIterator()) - //{ - // Console.WriteLine($"Entity {entity} Updated Position: {transform.Get().position}"); - //} + // _world.EntityManager.AddScriptComponent(entity1); + // _world.EntityManager.RemoveComponent(entity1); // This should destory the managed entity and call OnDestroy + + // query.ForEach((e, ref t) => + // { + // Console.WriteLine($"Entity {e} Has Position: {t.position}"); + // }); + // + // foreach (var (entity, transform) in query.GetEntityComponentIterator()) + // { + // Console.WriteLine($"Entity {entity} Updated Position: {transform.Get().position}"); + // } foreach (var chunk in query.GetChunkIterator()) { var transforms = chunk.GetComponentData(); var entities = chunk.GetEntities(); - var bits = chunk.GetEnableBits(); - var changed = chunk.HasChanged(0); - - var it = bits.GetIterator(); - while (it.Next(out var index) && index < chunk.Count) + if (chunk.HasChanged(0)) { - Console.WriteLine($"Entity {entities[index]} Updated Position: {transforms[index].position}"); + var bits = chunk.GetEnableBits(); + + var it = bits.GetIterator(); + while (it.Next(out var index) && index < chunk.Count) + { + Console.WriteLine($"Entity {entities[index]} Updated Position: {transforms[index].position}"); + } } } - _world.EntityManager.DestroyEntity(entity1); - _world.EntityManager.DestroyEntity(entity2); + Debug.Assert(_world.EntityManager.DestroyEntity(entity1) == Core.ErrorStatus.None); + Debug.Assert(_world.EntityManager.DestroyEntity(entity2) == Core.ErrorStatus.None); } public void Cleanup() diff --git a/Ghost.Entities/Archetype.cs b/Ghost.Entities/Archetype.cs index 58c9f2a..7807bc4 100644 --- a/Ghost.Entities/Archetype.cs +++ b/Ghost.Entities/Archetype.cs @@ -57,18 +57,33 @@ internal unsafe sealed class ChunkDebugView } var views = new List(); - ref var archetype = ref World.GetWorld(worldID).GetValueOrThrow() - .GetArchetypeReference(archetypeID); - - foreach (var layout in archetype._layouts) + var r = World.GetWorld(worldID); + if (!r) { - var type = Type.GetTypeFromHandle(RuntimeTypeHandle.FromIntPtr(ComponentRegister.s_runtimeIDToTypeHandle[layout.componentID])); + return []; + } + + ref var archetype = ref r.Value.GetArchetypeReference(archetypeID); + var it = archetype._signature.GetIterator(); + while (it.Next(out var index)) + { + var type = Type.GetTypeFromHandle(RuntimeTypeHandle.FromIntPtr(ComponentRegister.s_runtimeIDToTypeHandle[index])); + if (type == null) + { + continue; + } + + var layout = archetype.GetLayout(index).Value; var readMethod = typeof(ChunkDebugView) - .GetMethod(nameof(ReadComponentArray), System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance) + .GetMethod(nameof(ReadComponentArray), System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)! .MakeGenericMethod(type); // 3. Invoke it to get a Position[] or Velocity[] var array = readMethod.Invoke(this, [layout.offset]); + if (array == null) + { + continue; + } // 4. Wrap it in a nice label so the debugger shows "Position[]" views.Add(new ComponentArrayView(type.Name, array)); @@ -127,18 +142,6 @@ internal unsafe struct Chunk : IDisposable _versions.AsSpan().Fill(globalVersion); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void MarkChanged(int componentTypeId, int globalVersion) - { - _versions[componentTypeId] = globalVersion; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly int GetVersion(int componentTypeId) - { - return _versions[componentTypeId]; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly byte* GetUnsafePtr() { @@ -165,7 +168,8 @@ internal unsafe struct Archetype : IIdentifierType, IDisposable public int componentID; public int size; public int offset; - public int enableBitsOffset; // TODO: Support enableable component + public int enableBitsOffset; + public int versionIndex; } private struct Edge @@ -192,6 +196,7 @@ internal unsafe struct Archetype : IIdentifierType, IDisposable private int _entityIdsOffset; public readonly Identifier ID => _id; + public readonly Identifier WorldID => _worldID; public readonly int EntityCapacity => _entityCapacity; public readonly int ChunkCount => _chunks.Count; @@ -313,10 +318,11 @@ internal unsafe struct Archetype : IIdentifierType, IDisposable { _layouts[i] = new ComponentMemoryLayout { + componentID = components[i].id, offset = tempOffsets[i], size = components[i].size, - componentID = components[i].id, enableBitsOffset = tempBitmaskOffsets[i], + versionIndex = i }; _componentIDToLayoutIndex[components[i].id] = i; @@ -401,7 +407,7 @@ internal unsafe struct Archetype : IIdentifierType, IDisposable MemoryUtility.MemCpy(dst, pComponent, (nuint)size); var world = World.GetWorldUncheck(_worldID); - chunk.MarkChanged(componentID, world.Version); + MarkChanged(chunkIndex, componentID, world.Version); return ErrorStatus.None; } @@ -446,6 +452,34 @@ internal unsafe struct Archetype : IIdentifierType, IDisposable return _layouts[layoutIndex]; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly ErrorStatus MarkChanged(int chunkIndex, int componentTypeId, int globalVersion) + { + var layoutResult = GetLayout(componentTypeId); + if (layoutResult.IsFailure) + { + return layoutResult.Error; + } + + ref var chunk = ref _chunks[chunkIndex]; + chunk.GetVersionUnsafePtr()[layoutResult.Value.versionIndex] = globalVersion; + + return ErrorStatus.None; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Result GetVersion(int chunkIndex, int componentTypeId) + { + var layoutResult = GetLayout(componentTypeId); + if (layoutResult.Error != ErrorStatus.None) + { + return layoutResult.Error; + } + + ref var chunk = ref _chunks[chunkIndex]; + return chunk.GetVersionUnsafePtr()[layoutResult.Value.versionIndex]; + } + public ErrorStatus RemoveEntity(int chunkIndex, int rowIndex) { if (chunkIndex < 0 || chunkIndex >= _chunks.Count) diff --git a/Ghost.Entities/Component.cs b/Ghost.Entities/Component.cs index 3128cab..babe253 100644 --- a/Ghost.Entities/Component.cs +++ b/Ghost.Entities/Component.cs @@ -103,17 +103,6 @@ internal static class ComponentRegister } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void SetComponentLastWrite(Identifier typeId, int version) - { - lock (s_registeredComponents) - { - var info = s_registeredComponents[typeId]; - info.lastWriteVersion = version; - s_registeredComponents[typeId] = info; - } - } - public static int GetHashCode(params ReadOnlySpan> componentTypeIDs) { var largestID = 0; diff --git a/Ghost.Entities/Ghost.Entities.csproj b/Ghost.Entities/Ghost.Entities.csproj index a4429fe..ea70d6a 100644 --- a/Ghost.Entities/Ghost.Entities.csproj +++ b/Ghost.Entities/Ghost.Entities.csproj @@ -8,8 +8,8 @@ - True - True + False + False diff --git a/Ghost.Entities/Query.cs b/Ghost.Entities/Query.cs index 5eb979c..533037c 100644 --- a/Ghost.Entities/Query.cs +++ b/Ghost.Entities/Query.cs @@ -91,6 +91,7 @@ public readonly unsafe ref struct ChunkView private readonly int* _pVersion; private readonly int _entityOffset; private readonly int _entityCount; + private readonly int _currentVersion; public readonly int Count => _entityCount; @@ -101,6 +102,20 @@ public readonly unsafe ref struct ChunkView _entityOffset = archetype.EntityIDsOffset; _entityCount = chunk._count; _pVersion = chunk.GetVersionUnsafePtr(); + + _currentVersion = World.GetWorldUncheck(archetype.WorldID).Version; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Archetype.ComponentMemoryLayout GetLayout(Identifier id) + { + var layout = _layouts[id.value]; + if (layout.enableBitsOffset == -1) + { + throw new InvalidOperationException($"Component {id} is not exist in the archetype."); + } + + return layout; } /// @@ -112,7 +127,8 @@ public readonly unsafe ref struct ChunkView [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool HasChanged(Identifier id, int version) { - return version < _pVersion[id]; + var layout = GetLayout(id); + return version < _pVersion[layout.versionIndex]; } /// @@ -126,7 +142,8 @@ public readonly unsafe ref struct ChunkView public readonly bool HasChanged(int version) where T : unmanaged, IComponent { - return version < _pVersion[ComponentTypeID.value]; + var layout = GetLayout(ComponentTypeID.value); + return version < _pVersion[layout.versionIndex]; } /// @@ -163,6 +180,21 @@ public readonly unsafe ref struct ChunkView return new ReadOnlySpan(pEntity, _entityCount); } + /// + /// Gets a readonly span providing direct access to the component data of type T0 for structuralAll entities in the chunk. + /// + /// The type of component to access. Must be an unmanaged type that implements . + /// A readonly span of type containing the component data for each entity in the chunk. + /// Thrown if the specified component type is not present in the archetype. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan GetComponentData() + where T : unmanaged, IComponent + { + var layout = GetLayout(ComponentTypeID.value); + var pComponentData = _pChunkData + layout.offset; + return new ReadOnlySpan(pComponentData, _entityCount); + } + /// /// Gets a span providing direct access to the component data of type T0 for structuralAll entities in the chunk. /// @@ -170,10 +202,14 @@ public readonly unsafe ref struct ChunkView /// A span of type containing the component data for each entity in the chunk. /// Thrown if the specified component type is not present in the archetype. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span GetComponentData() + public Span GetComponentDataRW() where T : unmanaged, IComponent { - var layout = _layouts[ComponentTypeID.value]; + var compId = ComponentTypeID.value; + var layout = GetLayout(compId); + + _pVersion[layout.versionIndex] = _currentVersion; + var pComponentData = _pChunkData + layout.offset; return new Span(pComponentData, _entityCount); } @@ -190,11 +226,6 @@ public readonly unsafe ref struct ChunkView where T : unmanaged, IEnableableComponent { var layout = _layouts[ComponentTypeID.value]; - if (layout.enableBitsOffset == -1) - { - throw new InvalidOperationException($"Component {typeof(T).FullName} is not enableable."); - } - var maskBase = _pChunkData + layout.enableBitsOffset; return new SpanBitSet(new Span(maskBase, (_entityCount + 31) / 32)); } @@ -210,12 +241,7 @@ public readonly unsafe ref struct ChunkView public bool IsComponentEnabled(int index) where T : unmanaged, IEnableableComponent { - var layout = _layouts[ComponentTypeID.value]; - if (layout.enableBitsOffset == -1) - { - throw new InvalidOperationException($"Component {typeof(T).FullName} is not enableable."); - } - + var layout = GetLayout(ComponentTypeID.value); var pMask = _pChunkData + layout.enableBitsOffset; return EntityQuery.CheckBit(pMask, index); } diff --git a/Ghost.Entities/System.cs b/Ghost.Entities/System.cs index a86c69f..c77e7e7 100644 --- a/Ghost.Entities/System.cs +++ b/Ghost.Entities/System.cs @@ -1,6 +1,3 @@ -using Ghost.Core; -using Misaki.HighPerformance.Jobs; - namespace Ghost.Entities; public readonly ref struct SystemAPI @@ -235,7 +232,6 @@ public class SystemManager private readonly World _world; private readonly List _systems = new (); - private readonly Dictionary _systemTypeMap = new (); internal SystemManager(World world) { @@ -247,15 +243,17 @@ public class SystemManager { var system = new T(); _systems.Add(system); - _systemTypeMap[typeof(T)] = _systems.Count - 1; } public T GetSystem() where T : ISystem { - if (_systemTypeMap.TryGetValue(typeof(T), out var index)) + foreach (var system in _systems) { - return (T)_systems[index]; + if (system is T typedSystem) + { + return typedSystem; + } } throw new InvalidOperationException($"System of type {typeof(T).FullName} not found in SystemManager."); diff --git a/Ghost.Entities/Templates/EntityQuery.ComponentIterator.gen.cs b/Ghost.Entities/Templates/EntityQuery.ComponentIterator.gen.cs index 416517f..b641b76 100644 --- a/Ghost.Entities/Templates/EntityQuery.ComponentIterator.gen.cs +++ b/Ghost.Entities/Templates/EntityQuery.ComponentIterator.gen.cs @@ -1,5 +1,6 @@ using Ghost.Core; using Misaki.HighPerformance.LowLevel; +using Misaki.HighPerformance.LowLevel.Buffer; using Misaki.HighPerformance.LowLevel.Collections; using System.Runtime.CompilerServices; @@ -10,7 +11,7 @@ public unsafe partial struct EntityQuery public readonly ref struct ComponentIterator where T0 : unmanaged, IComponent { - public ref struct Enumerator + public ref struct Enumerator : IDisposable { private fixed int _compTypeIDs[1]; private fixed int _offsets[1]; @@ -19,6 +20,10 @@ public unsafe partial struct EntityQuery private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; private readonly EntityQueryMask _mask; private readonly World _world; + private readonly int _currentVersion; + + private readonly Stack.Scope _scope; + private UnsafeList _changedComponentIDs; private ref Archetype _currentArchetype; private ref Chunk _currentChunk; @@ -39,6 +44,22 @@ public unsafe partial struct EntityQuery _mask = mask; _world = world; + _scope = AllocationManager.CreateStackScope(); + _changedComponentIDs = new UnsafeList(1, _scope.AllocationHandle); + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i = 0; i < 1; i++) + { + if (id == _compTypeIDs[i]) + { + _changedComponentIDs.Add(id); + break; + } + } + } + Reset(); } @@ -58,6 +79,11 @@ public unsafe partial struct EntityQuery _offsets[index] = layout.offset; _compBasePtrs[index] = (long)(_chunkBasePtr + _offsets[index]); } + + for (var i = 0; i < _changedComponentIDs.Count; i++) + { + _currentArchetype.MarkChanged(_currentChunkIndex, _changedComponentIDs[i], _world.Version); + } } public bool MoveNext() @@ -124,6 +150,11 @@ public unsafe partial struct EntityQuery } } } + + public readonly void Dispose() + { + _scope.Dispose(); + } } private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; @@ -170,7 +201,7 @@ public unsafe partial struct EntityQuery } } - public ref struct Enumerator + public ref struct Enumerator : IDisposable { private fixed int _compTypeIDs[2]; private fixed int _offsets[2]; @@ -179,6 +210,10 @@ public unsafe partial struct EntityQuery private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; private readonly EntityQueryMask _mask; private readonly World _world; + private readonly int _currentVersion; + + private readonly Stack.Scope _scope; + private UnsafeList _changedComponentIDs; private ref Archetype _currentArchetype; private ref Chunk _currentChunk; @@ -203,6 +238,22 @@ public unsafe partial struct EntityQuery _mask = mask; _world = world; + _scope = AllocationManager.CreateStackScope(); + _changedComponentIDs = new UnsafeList(2, _scope.AllocationHandle); + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i = 0; i < 2; i++) + { + if (id == _compTypeIDs[i]) + { + _changedComponentIDs.Add(id); + break; + } + } + } + Reset(); } @@ -225,6 +276,11 @@ public unsafe partial struct EntityQuery _offsets[index] = layout.offset; _compBasePtrs[index] = (long)(_chunkBasePtr + _offsets[index]); } + + for (var i = 0; i < _changedComponentIDs.Count; i++) + { + _currentArchetype.MarkChanged(_currentChunkIndex, _changedComponentIDs[i], _world.Version); + } } public bool MoveNext() @@ -291,6 +347,11 @@ public unsafe partial struct EntityQuery } } } + + public readonly void Dispose() + { + _scope.Dispose(); + } } private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; @@ -342,7 +403,7 @@ public unsafe partial struct EntityQuery } } - public ref struct Enumerator + public ref struct Enumerator : IDisposable { private fixed int _compTypeIDs[3]; private fixed int _offsets[3]; @@ -351,6 +412,10 @@ public unsafe partial struct EntityQuery private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; private readonly EntityQueryMask _mask; private readonly World _world; + private readonly int _currentVersion; + + private readonly Stack.Scope _scope; + private UnsafeList _changedComponentIDs; private ref Archetype _currentArchetype; private ref Chunk _currentChunk; @@ -379,6 +444,22 @@ public unsafe partial struct EntityQuery _mask = mask; _world = world; + _scope = AllocationManager.CreateStackScope(); + _changedComponentIDs = new UnsafeList(3, _scope.AllocationHandle); + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i = 0; i < 3; i++) + { + if (id == _compTypeIDs[i]) + { + _changedComponentIDs.Add(id); + break; + } + } + } + Reset(); } @@ -402,6 +483,11 @@ public unsafe partial struct EntityQuery _offsets[index] = layout.offset; _compBasePtrs[index] = (long)(_chunkBasePtr + _offsets[index]); } + + for (var i = 0; i < _changedComponentIDs.Count; i++) + { + _currentArchetype.MarkChanged(_currentChunkIndex, _changedComponentIDs[i], _world.Version); + } } public bool MoveNext() @@ -468,6 +554,11 @@ public unsafe partial struct EntityQuery } } } + + public readonly void Dispose() + { + _scope.Dispose(); + } } private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; @@ -524,7 +615,7 @@ public unsafe partial struct EntityQuery } } - public ref struct Enumerator + public ref struct Enumerator : IDisposable { private fixed int _compTypeIDs[4]; private fixed int _offsets[4]; @@ -533,6 +624,10 @@ public unsafe partial struct EntityQuery private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; private readonly EntityQueryMask _mask; private readonly World _world; + private readonly int _currentVersion; + + private readonly Stack.Scope _scope; + private UnsafeList _changedComponentIDs; private ref Archetype _currentArchetype; private ref Chunk _currentChunk; @@ -565,6 +660,22 @@ public unsafe partial struct EntityQuery _mask = mask; _world = world; + _scope = AllocationManager.CreateStackScope(); + _changedComponentIDs = new UnsafeList(4, _scope.AllocationHandle); + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i = 0; i < 4; i++) + { + if (id == _compTypeIDs[i]) + { + _changedComponentIDs.Add(id); + break; + } + } + } + Reset(); } @@ -589,6 +700,11 @@ public unsafe partial struct EntityQuery _offsets[index] = layout.offset; _compBasePtrs[index] = (long)(_chunkBasePtr + _offsets[index]); } + + for (var i = 0; i < _changedComponentIDs.Count; i++) + { + _currentArchetype.MarkChanged(_currentChunkIndex, _changedComponentIDs[i], _world.Version); + } } public bool MoveNext() @@ -655,6 +771,11 @@ public unsafe partial struct EntityQuery } } } + + public readonly void Dispose() + { + _scope.Dispose(); + } } private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; @@ -716,7 +837,7 @@ public unsafe partial struct EntityQuery } } - public ref struct Enumerator + public ref struct Enumerator : IDisposable { private fixed int _compTypeIDs[5]; private fixed int _offsets[5]; @@ -725,6 +846,10 @@ public unsafe partial struct EntityQuery private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; private readonly EntityQueryMask _mask; private readonly World _world; + private readonly int _currentVersion; + + private readonly Stack.Scope _scope; + private UnsafeList _changedComponentIDs; private ref Archetype _currentArchetype; private ref Chunk _currentChunk; @@ -761,6 +886,22 @@ public unsafe partial struct EntityQuery _mask = mask; _world = world; + _scope = AllocationManager.CreateStackScope(); + _changedComponentIDs = new UnsafeList(5, _scope.AllocationHandle); + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i = 0; i < 5; i++) + { + if (id == _compTypeIDs[i]) + { + _changedComponentIDs.Add(id); + break; + } + } + } + Reset(); } @@ -786,6 +927,11 @@ public unsafe partial struct EntityQuery _offsets[index] = layout.offset; _compBasePtrs[index] = (long)(_chunkBasePtr + _offsets[index]); } + + for (var i = 0; i < _changedComponentIDs.Count; i++) + { + _currentArchetype.MarkChanged(_currentChunkIndex, _changedComponentIDs[i], _world.Version); + } } public bool MoveNext() @@ -852,6 +998,11 @@ public unsafe partial struct EntityQuery } } } + + public readonly void Dispose() + { + _scope.Dispose(); + } } private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; @@ -918,7 +1069,7 @@ public unsafe partial struct EntityQuery } } - public ref struct Enumerator + public ref struct Enumerator : IDisposable { private fixed int _compTypeIDs[6]; private fixed int _offsets[6]; @@ -927,6 +1078,10 @@ public unsafe partial struct EntityQuery private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; private readonly EntityQueryMask _mask; private readonly World _world; + private readonly int _currentVersion; + + private readonly Stack.Scope _scope; + private UnsafeList _changedComponentIDs; private ref Archetype _currentArchetype; private ref Chunk _currentChunk; @@ -967,6 +1122,22 @@ public unsafe partial struct EntityQuery _mask = mask; _world = world; + _scope = AllocationManager.CreateStackScope(); + _changedComponentIDs = new UnsafeList(6, _scope.AllocationHandle); + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i = 0; i < 6; i++) + { + if (id == _compTypeIDs[i]) + { + _changedComponentIDs.Add(id); + break; + } + } + } + Reset(); } @@ -993,6 +1164,11 @@ public unsafe partial struct EntityQuery _offsets[index] = layout.offset; _compBasePtrs[index] = (long)(_chunkBasePtr + _offsets[index]); } + + for (var i = 0; i < _changedComponentIDs.Count; i++) + { + _currentArchetype.MarkChanged(_currentChunkIndex, _changedComponentIDs[i], _world.Version); + } } public bool MoveNext() @@ -1059,6 +1235,11 @@ public unsafe partial struct EntityQuery } } } + + public readonly void Dispose() + { + _scope.Dispose(); + } } private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; @@ -1130,7 +1311,7 @@ public unsafe partial struct EntityQuery } } - public ref struct Enumerator + public ref struct Enumerator : IDisposable { private fixed int _compTypeIDs[7]; private fixed int _offsets[7]; @@ -1139,6 +1320,10 @@ public unsafe partial struct EntityQuery private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; private readonly EntityQueryMask _mask; private readonly World _world; + private readonly int _currentVersion; + + private readonly Stack.Scope _scope; + private UnsafeList _changedComponentIDs; private ref Archetype _currentArchetype; private ref Chunk _currentChunk; @@ -1183,6 +1368,22 @@ public unsafe partial struct EntityQuery _mask = mask; _world = world; + _scope = AllocationManager.CreateStackScope(); + _changedComponentIDs = new UnsafeList(7, _scope.AllocationHandle); + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i = 0; i < 7; i++) + { + if (id == _compTypeIDs[i]) + { + _changedComponentIDs.Add(id); + break; + } + } + } + Reset(); } @@ -1210,6 +1411,11 @@ public unsafe partial struct EntityQuery _offsets[index] = layout.offset; _compBasePtrs[index] = (long)(_chunkBasePtr + _offsets[index]); } + + for (var i = 0; i < _changedComponentIDs.Count; i++) + { + _currentArchetype.MarkChanged(_currentChunkIndex, _changedComponentIDs[i], _world.Version); + } } public bool MoveNext() @@ -1276,6 +1482,11 @@ public unsafe partial struct EntityQuery } } } + + public readonly void Dispose() + { + _scope.Dispose(); + } } private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; @@ -1352,7 +1563,7 @@ public unsafe partial struct EntityQuery } } - public ref struct Enumerator + public ref struct Enumerator : IDisposable { private fixed int _compTypeIDs[8]; private fixed int _offsets[8]; @@ -1361,6 +1572,10 @@ public unsafe partial struct EntityQuery private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; private readonly EntityQueryMask _mask; private readonly World _world; + private readonly int _currentVersion; + + private readonly Stack.Scope _scope; + private UnsafeList _changedComponentIDs; private ref Archetype _currentArchetype; private ref Chunk _currentChunk; @@ -1409,6 +1624,22 @@ public unsafe partial struct EntityQuery _mask = mask; _world = world; + _scope = AllocationManager.CreateStackScope(); + _changedComponentIDs = new UnsafeList(8, _scope.AllocationHandle); + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i = 0; i < 8; i++) + { + if (id == _compTypeIDs[i]) + { + _changedComponentIDs.Add(id); + break; + } + } + } + Reset(); } @@ -1437,6 +1668,11 @@ public unsafe partial struct EntityQuery _offsets[index] = layout.offset; _compBasePtrs[index] = (long)(_chunkBasePtr + _offsets[index]); } + + for (var i = 0; i < _changedComponentIDs.Count; i++) + { + _currentArchetype.MarkChanged(_currentChunkIndex, _changedComponentIDs[i], _world.Version); + } } public bool MoveNext() @@ -1503,6 +1739,11 @@ public unsafe partial struct EntityQuery } } } + + public readonly void Dispose() + { + _scope.Dispose(); + } } private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; diff --git a/Ghost.Entities/Templates/EntityQuery.ComponentIterator.tt b/Ghost.Entities/Templates/EntityQuery.ComponentIterator.tt index a4b7b8f..bde0b8e 100644 --- a/Ghost.Entities/Templates/EntityQuery.ComponentIterator.tt +++ b/Ghost.Entities/Templates/EntityQuery.ComponentIterator.tt @@ -6,6 +6,7 @@ <#@ include file="Helpers.ttinclude" #> using Ghost.Core; using Misaki.HighPerformance.LowLevel; +using Misaki.HighPerformance.LowLevel.Buffer; using Misaki.HighPerformance.LowLevel.Collections; using System.Runtime.CompilerServices; @@ -45,7 +46,7 @@ public unsafe partial struct EntityQuery } <# } #> - public ref struct Enumerator + public ref struct Enumerator : IDisposable { private fixed int _compTypeIDs[<#= i #>]; private fixed int _offsets[<#= i #>]; @@ -54,6 +55,10 @@ public unsafe partial struct EntityQuery private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; private readonly EntityQueryMask _mask; private readonly World _world; + private readonly int _currentVersion; + + private readonly Stack.Scope _scope; + private UnsafeList _changedComponentIDs; private ref Archetype _currentArchetype; private ref Chunk _currentChunk; @@ -76,6 +81,22 @@ public unsafe partial struct EntityQuery _mask = mask; _world = world; + _scope = AllocationManager.CreateStackScope(); + _changedComponentIDs = new UnsafeList(<#= i #>, _scope.AllocationHandle); + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i = 0; i < <#= i #>; i++) + { + if (id == _compTypeIDs[i]) + { + _changedComponentIDs.Add(id); + break; + } + } + } + Reset(); } @@ -103,6 +124,11 @@ public unsafe partial struct EntityQuery _offsets[index] = layout.offset; _compBasePtrs[index] = (long)(_chunkBasePtr + _offsets[index]); } + + for (var i = 0; i < _changedComponentIDs.Count; i++) + { + _currentArchetype.MarkChanged(_currentChunkIndex, _changedComponentIDs[i], _world.Version); + } } public bool MoveNext() @@ -169,6 +195,11 @@ public unsafe partial struct EntityQuery } } } + + public readonly void Dispose() + { + _scope.Dispose(); + } } private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; diff --git a/Ghost.Entities/Templates/EntityQuery.EntityComponentIterator.gen.cs b/Ghost.Entities/Templates/EntityQuery.EntityComponentIterator.gen.cs index 55e6534..adefdac 100644 --- a/Ghost.Entities/Templates/EntityQuery.EntityComponentIterator.gen.cs +++ b/Ghost.Entities/Templates/EntityQuery.EntityComponentIterator.gen.cs @@ -1,5 +1,6 @@ using Ghost.Core; using Misaki.HighPerformance.LowLevel; +using Misaki.HighPerformance.LowLevel.Buffer; using Misaki.HighPerformance.LowLevel.Collections; using System.Runtime.CompilerServices; @@ -30,7 +31,7 @@ public unsafe partial struct EntityQuery } } - public ref struct Enumerator + public ref struct Enumerator : IDisposable { private fixed int _compTypeIDs[1]; private fixed int _offsets[1]; @@ -40,6 +41,9 @@ public unsafe partial struct EntityQuery private readonly EntityQueryMask _mask; private readonly World _world; + private readonly Stack.Scope _scope; + private UnsafeList _changedComponentIDs; + private ref Archetype _currentArchetype; private ref Chunk _currentChunk; private byte* _chunkBasePtr; @@ -59,6 +63,22 @@ public unsafe partial struct EntityQuery _mask = mask; _world = world; + _scope = AllocationManager.CreateStackScope(); + _changedComponentIDs = new UnsafeList(1, _scope.AllocationHandle); + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i = 0; i < 1; i++) + { + if (id == _compTypeIDs[i]) + { + _changedComponentIDs.Add(id); + break; + } + } + } + Reset(); } @@ -81,6 +101,11 @@ public unsafe partial struct EntityQuery _offsets[index] = layout.offset; _compBasePtrs[index] = (long)(_chunkBasePtr + _offsets[index]); } + + for (var i = 0; i < _changedComponentIDs.Count; i++) + { + _currentArchetype.MarkChanged(_currentChunkIndex, _changedComponentIDs[i], _world.Version); + } } public bool MoveNext() @@ -147,6 +172,11 @@ public unsafe partial struct EntityQuery } } } + + public readonly void Dispose() + { + _scope.Dispose(); + } } private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; @@ -199,7 +229,7 @@ public unsafe partial struct EntityQuery } } - public ref struct Enumerator + public ref struct Enumerator : IDisposable { private fixed int _compTypeIDs[2]; private fixed int _offsets[2]; @@ -209,6 +239,9 @@ public unsafe partial struct EntityQuery private readonly EntityQueryMask _mask; private readonly World _world; + private readonly Stack.Scope _scope; + private UnsafeList _changedComponentIDs; + private ref Archetype _currentArchetype; private ref Chunk _currentChunk; private byte* _chunkBasePtr; @@ -232,6 +265,22 @@ public unsafe partial struct EntityQuery _mask = mask; _world = world; + _scope = AllocationManager.CreateStackScope(); + _changedComponentIDs = new UnsafeList(2, _scope.AllocationHandle); + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i = 0; i < 2; i++) + { + if (id == _compTypeIDs[i]) + { + _changedComponentIDs.Add(id); + break; + } + } + } + Reset(); } @@ -255,6 +304,11 @@ public unsafe partial struct EntityQuery _offsets[index] = layout.offset; _compBasePtrs[index] = (long)(_chunkBasePtr + _offsets[index]); } + + for (var i = 0; i < _changedComponentIDs.Count; i++) + { + _currentArchetype.MarkChanged(_currentChunkIndex, _changedComponentIDs[i], _world.Version); + } } public bool MoveNext() @@ -321,6 +375,11 @@ public unsafe partial struct EntityQuery } } } + + public readonly void Dispose() + { + _scope.Dispose(); + } } private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; @@ -378,7 +437,7 @@ public unsafe partial struct EntityQuery } } - public ref struct Enumerator + public ref struct Enumerator : IDisposable { private fixed int _compTypeIDs[3]; private fixed int _offsets[3]; @@ -388,6 +447,9 @@ public unsafe partial struct EntityQuery private readonly EntityQueryMask _mask; private readonly World _world; + private readonly Stack.Scope _scope; + private UnsafeList _changedComponentIDs; + private ref Archetype _currentArchetype; private ref Chunk _currentChunk; private byte* _chunkBasePtr; @@ -415,6 +477,22 @@ public unsafe partial struct EntityQuery _mask = mask; _world = world; + _scope = AllocationManager.CreateStackScope(); + _changedComponentIDs = new UnsafeList(3, _scope.AllocationHandle); + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i = 0; i < 3; i++) + { + if (id == _compTypeIDs[i]) + { + _changedComponentIDs.Add(id); + break; + } + } + } + Reset(); } @@ -439,6 +517,11 @@ public unsafe partial struct EntityQuery _offsets[index] = layout.offset; _compBasePtrs[index] = (long)(_chunkBasePtr + _offsets[index]); } + + for (var i = 0; i < _changedComponentIDs.Count; i++) + { + _currentArchetype.MarkChanged(_currentChunkIndex, _changedComponentIDs[i], _world.Version); + } } public bool MoveNext() @@ -505,6 +588,11 @@ public unsafe partial struct EntityQuery } } } + + public readonly void Dispose() + { + _scope.Dispose(); + } } private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; @@ -567,7 +655,7 @@ public unsafe partial struct EntityQuery } } - public ref struct Enumerator + public ref struct Enumerator : IDisposable { private fixed int _compTypeIDs[4]; private fixed int _offsets[4]; @@ -577,6 +665,9 @@ public unsafe partial struct EntityQuery private readonly EntityQueryMask _mask; private readonly World _world; + private readonly Stack.Scope _scope; + private UnsafeList _changedComponentIDs; + private ref Archetype _currentArchetype; private ref Chunk _currentChunk; private byte* _chunkBasePtr; @@ -608,6 +699,22 @@ public unsafe partial struct EntityQuery _mask = mask; _world = world; + _scope = AllocationManager.CreateStackScope(); + _changedComponentIDs = new UnsafeList(4, _scope.AllocationHandle); + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i = 0; i < 4; i++) + { + if (id == _compTypeIDs[i]) + { + _changedComponentIDs.Add(id); + break; + } + } + } + Reset(); } @@ -633,6 +740,11 @@ public unsafe partial struct EntityQuery _offsets[index] = layout.offset; _compBasePtrs[index] = (long)(_chunkBasePtr + _offsets[index]); } + + for (var i = 0; i < _changedComponentIDs.Count; i++) + { + _currentArchetype.MarkChanged(_currentChunkIndex, _changedComponentIDs[i], _world.Version); + } } public bool MoveNext() @@ -699,6 +811,11 @@ public unsafe partial struct EntityQuery } } } + + public readonly void Dispose() + { + _scope.Dispose(); + } } private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; @@ -766,7 +883,7 @@ public unsafe partial struct EntityQuery } } - public ref struct Enumerator + public ref struct Enumerator : IDisposable { private fixed int _compTypeIDs[5]; private fixed int _offsets[5]; @@ -776,6 +893,9 @@ public unsafe partial struct EntityQuery private readonly EntityQueryMask _mask; private readonly World _world; + private readonly Stack.Scope _scope; + private UnsafeList _changedComponentIDs; + private ref Archetype _currentArchetype; private ref Chunk _currentChunk; private byte* _chunkBasePtr; @@ -811,6 +931,22 @@ public unsafe partial struct EntityQuery _mask = mask; _world = world; + _scope = AllocationManager.CreateStackScope(); + _changedComponentIDs = new UnsafeList(5, _scope.AllocationHandle); + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i = 0; i < 5; i++) + { + if (id == _compTypeIDs[i]) + { + _changedComponentIDs.Add(id); + break; + } + } + } + Reset(); } @@ -837,6 +973,11 @@ public unsafe partial struct EntityQuery _offsets[index] = layout.offset; _compBasePtrs[index] = (long)(_chunkBasePtr + _offsets[index]); } + + for (var i = 0; i < _changedComponentIDs.Count; i++) + { + _currentArchetype.MarkChanged(_currentChunkIndex, _changedComponentIDs[i], _world.Version); + } } public bool MoveNext() @@ -903,6 +1044,11 @@ public unsafe partial struct EntityQuery } } } + + public readonly void Dispose() + { + _scope.Dispose(); + } } private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; @@ -975,7 +1121,7 @@ public unsafe partial struct EntityQuery } } - public ref struct Enumerator + public ref struct Enumerator : IDisposable { private fixed int _compTypeIDs[6]; private fixed int _offsets[6]; @@ -985,6 +1131,9 @@ public unsafe partial struct EntityQuery private readonly EntityQueryMask _mask; private readonly World _world; + private readonly Stack.Scope _scope; + private UnsafeList _changedComponentIDs; + private ref Archetype _currentArchetype; private ref Chunk _currentChunk; private byte* _chunkBasePtr; @@ -1024,6 +1173,22 @@ public unsafe partial struct EntityQuery _mask = mask; _world = world; + _scope = AllocationManager.CreateStackScope(); + _changedComponentIDs = new UnsafeList(6, _scope.AllocationHandle); + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i = 0; i < 6; i++) + { + if (id == _compTypeIDs[i]) + { + _changedComponentIDs.Add(id); + break; + } + } + } + Reset(); } @@ -1051,6 +1216,11 @@ public unsafe partial struct EntityQuery _offsets[index] = layout.offset; _compBasePtrs[index] = (long)(_chunkBasePtr + _offsets[index]); } + + for (var i = 0; i < _changedComponentIDs.Count; i++) + { + _currentArchetype.MarkChanged(_currentChunkIndex, _changedComponentIDs[i], _world.Version); + } } public bool MoveNext() @@ -1117,6 +1287,11 @@ public unsafe partial struct EntityQuery } } } + + public readonly void Dispose() + { + _scope.Dispose(); + } } private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; @@ -1194,7 +1369,7 @@ public unsafe partial struct EntityQuery } } - public ref struct Enumerator + public ref struct Enumerator : IDisposable { private fixed int _compTypeIDs[7]; private fixed int _offsets[7]; @@ -1204,6 +1379,9 @@ public unsafe partial struct EntityQuery private readonly EntityQueryMask _mask; private readonly World _world; + private readonly Stack.Scope _scope; + private UnsafeList _changedComponentIDs; + private ref Archetype _currentArchetype; private ref Chunk _currentChunk; private byte* _chunkBasePtr; @@ -1247,6 +1425,22 @@ public unsafe partial struct EntityQuery _mask = mask; _world = world; + _scope = AllocationManager.CreateStackScope(); + _changedComponentIDs = new UnsafeList(7, _scope.AllocationHandle); + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i = 0; i < 7; i++) + { + if (id == _compTypeIDs[i]) + { + _changedComponentIDs.Add(id); + break; + } + } + } + Reset(); } @@ -1275,6 +1469,11 @@ public unsafe partial struct EntityQuery _offsets[index] = layout.offset; _compBasePtrs[index] = (long)(_chunkBasePtr + _offsets[index]); } + + for (var i = 0; i < _changedComponentIDs.Count; i++) + { + _currentArchetype.MarkChanged(_currentChunkIndex, _changedComponentIDs[i], _world.Version); + } } public bool MoveNext() @@ -1341,6 +1540,11 @@ public unsafe partial struct EntityQuery } } } + + public readonly void Dispose() + { + _scope.Dispose(); + } } private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; @@ -1423,7 +1627,7 @@ public unsafe partial struct EntityQuery } } - public ref struct Enumerator + public ref struct Enumerator : IDisposable { private fixed int _compTypeIDs[8]; private fixed int _offsets[8]; @@ -1433,6 +1637,9 @@ public unsafe partial struct EntityQuery private readonly EntityQueryMask _mask; private readonly World _world; + private readonly Stack.Scope _scope; + private UnsafeList _changedComponentIDs; + private ref Archetype _currentArchetype; private ref Chunk _currentChunk; private byte* _chunkBasePtr; @@ -1480,6 +1687,22 @@ public unsafe partial struct EntityQuery _mask = mask; _world = world; + _scope = AllocationManager.CreateStackScope(); + _changedComponentIDs = new UnsafeList(8, _scope.AllocationHandle); + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i = 0; i < 8; i++) + { + if (id == _compTypeIDs[i]) + { + _changedComponentIDs.Add(id); + break; + } + } + } + Reset(); } @@ -1509,6 +1732,11 @@ public unsafe partial struct EntityQuery _offsets[index] = layout.offset; _compBasePtrs[index] = (long)(_chunkBasePtr + _offsets[index]); } + + for (var i = 0; i < _changedComponentIDs.Count; i++) + { + _currentArchetype.MarkChanged(_currentChunkIndex, _changedComponentIDs[i], _world.Version); + } } public bool MoveNext() @@ -1575,6 +1803,11 @@ public unsafe partial struct EntityQuery } } } + + public readonly void Dispose() + { + _scope.Dispose(); + } } private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; diff --git a/Ghost.Entities/Templates/EntityQuery.EntityComponentIterator.tt b/Ghost.Entities/Templates/EntityQuery.EntityComponentIterator.tt index 08d2aea..b9074c5 100644 --- a/Ghost.Entities/Templates/EntityQuery.EntityComponentIterator.tt +++ b/Ghost.Entities/Templates/EntityQuery.EntityComponentIterator.tt @@ -6,6 +6,7 @@ <#@ include file="Helpers.ttinclude" #> using Ghost.Core; using Misaki.HighPerformance.LowLevel; +using Misaki.HighPerformance.LowLevel.Buffer; using Misaki.HighPerformance.LowLevel.Collections; using System.Runtime.CompilerServices; @@ -49,7 +50,7 @@ public unsafe partial struct EntityQuery } } - public ref struct Enumerator + public ref struct Enumerator : IDisposable { private fixed int _compTypeIDs[<#= i #>]; private fixed int _offsets[<#= i #>]; @@ -59,6 +60,9 @@ public unsafe partial struct EntityQuery private readonly EntityQueryMask _mask; private readonly World _world; + private readonly Stack.Scope _scope; + private UnsafeList _changedComponentIDs; + private ref Archetype _currentArchetype; private ref Chunk _currentChunk; private byte* _chunkBasePtr; @@ -80,6 +84,22 @@ public unsafe partial struct EntityQuery _mask = mask; _world = world; + _scope = AllocationManager.CreateStackScope(); + _changedComponentIDs = new UnsafeList(<#= i #>, _scope.AllocationHandle); + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i = 0; i < <#= i #>; i++) + { + if (id == _compTypeIDs[i]) + { + _changedComponentIDs.Add(id); + break; + } + } + } + Reset(); } @@ -104,6 +124,11 @@ public unsafe partial struct EntityQuery _offsets[index] = layout.offset; _compBasePtrs[index] = (long)(_chunkBasePtr + _offsets[index]); } + + for (var i = 0; i < _changedComponentIDs.Count; i++) + { + _currentArchetype.MarkChanged(_currentChunkIndex, _changedComponentIDs[i], _world.Version); + } } public bool MoveNext() @@ -170,6 +195,11 @@ public unsafe partial struct EntityQuery } } } + + public readonly void Dispose() + { + _scope.Dispose(); + } } private readonly ReadOnlyUnsafeCollection> _matchingArchetypes; diff --git a/Ghost.Entities/Templates/EntityQuery.ForEach.gen.cs b/Ghost.Entities/Templates/EntityQuery.ForEach.gen.cs index f6a38cc..68e3224 100644 --- a/Ghost.Entities/Templates/EntityQuery.ForEach.gen.cs +++ b/Ghost.Entities/Templates/EntityQuery.ForEach.gen.cs @@ -1,6 +1,3 @@ - -using Ghost.Core; - namespace Ghost.Entities; public unsafe partial struct EntityQuery @@ -12,7 +9,7 @@ public unsafe partial struct EntityQuery var globalVersion = world.Version; var comp0TypeID = ComponentTypeID.value; - + var compTypeIDs = stackalloc int[] { comp0TypeID.value, @@ -31,7 +28,6 @@ public unsafe partial struct EntityQuery { if (id == compTypeIDs[i]) { - ComponentRegister.SetComponentLastWrite(id, globalVersion); changedCompIDs[changedCompCount] = id; changedCompCount++; break; @@ -67,7 +63,7 @@ public unsafe partial struct EntityQuery for (var j = 0; j < changedCompCount; j++) { - chunk.MarkChanged(changedCompIDs[i], globalVersion); + archetype.MarkChanged(chunkIndex, changedCompIDs[j], globalVersion); } for (var index = 0; index < 1; index++) @@ -99,7 +95,7 @@ public unsafe partial struct EntityQuery var comp0TypeID = ComponentTypeID.value; var comp1TypeID = ComponentTypeID.value; - + var compTypeIDs = stackalloc int[] { comp0TypeID.value, @@ -119,7 +115,6 @@ public unsafe partial struct EntityQuery { if (id == compTypeIDs[i]) { - ComponentRegister.SetComponentLastWrite(id, globalVersion); changedCompIDs[changedCompCount] = id; changedCompCount++; break; @@ -155,7 +150,7 @@ public unsafe partial struct EntityQuery for (var j = 0; j < changedCompCount; j++) { - chunk.MarkChanged(changedCompIDs[i], globalVersion); + archetype.MarkChanged(chunkIndex, changedCompIDs[j], globalVersion); } for (var index = 0; index < 2; index++) @@ -190,7 +185,7 @@ public unsafe partial struct EntityQuery var comp0TypeID = ComponentTypeID.value; var comp1TypeID = ComponentTypeID.value; var comp2TypeID = ComponentTypeID.value; - + var compTypeIDs = stackalloc int[] { comp0TypeID.value, @@ -211,7 +206,6 @@ public unsafe partial struct EntityQuery { if (id == compTypeIDs[i]) { - ComponentRegister.SetComponentLastWrite(id, globalVersion); changedCompIDs[changedCompCount] = id; changedCompCount++; break; @@ -247,7 +241,7 @@ public unsafe partial struct EntityQuery for (var j = 0; j < changedCompCount; j++) { - chunk.MarkChanged(changedCompIDs[i], globalVersion); + archetype.MarkChanged(chunkIndex, changedCompIDs[j], globalVersion); } for (var index = 0; index < 3; index++) @@ -285,7 +279,7 @@ public unsafe partial struct EntityQuery var comp1TypeID = ComponentTypeID.value; var comp2TypeID = ComponentTypeID.value; var comp3TypeID = ComponentTypeID.value; - + var compTypeIDs = stackalloc int[] { comp0TypeID.value, @@ -307,7 +301,6 @@ public unsafe partial struct EntityQuery { if (id == compTypeIDs[i]) { - ComponentRegister.SetComponentLastWrite(id, globalVersion); changedCompIDs[changedCompCount] = id; changedCompCount++; break; @@ -343,7 +336,7 @@ public unsafe partial struct EntityQuery for (var j = 0; j < changedCompCount; j++) { - chunk.MarkChanged(changedCompIDs[i], globalVersion); + archetype.MarkChanged(chunkIndex, changedCompIDs[j], globalVersion); } for (var index = 0; index < 4; index++) @@ -384,7 +377,7 @@ public unsafe partial struct EntityQuery var comp2TypeID = ComponentTypeID.value; var comp3TypeID = ComponentTypeID.value; var comp4TypeID = ComponentTypeID.value; - + var compTypeIDs = stackalloc int[] { comp0TypeID.value, @@ -407,7 +400,6 @@ public unsafe partial struct EntityQuery { if (id == compTypeIDs[i]) { - ComponentRegister.SetComponentLastWrite(id, globalVersion); changedCompIDs[changedCompCount] = id; changedCompCount++; break; @@ -443,7 +435,7 @@ public unsafe partial struct EntityQuery for (var j = 0; j < changedCompCount; j++) { - chunk.MarkChanged(changedCompIDs[i], globalVersion); + archetype.MarkChanged(chunkIndex, changedCompIDs[j], globalVersion); } for (var index = 0; index < 5; index++) @@ -487,7 +479,7 @@ public unsafe partial struct EntityQuery var comp3TypeID = ComponentTypeID.value; var comp4TypeID = ComponentTypeID.value; var comp5TypeID = ComponentTypeID.value; - + var compTypeIDs = stackalloc int[] { comp0TypeID.value, @@ -511,7 +503,6 @@ public unsafe partial struct EntityQuery { if (id == compTypeIDs[i]) { - ComponentRegister.SetComponentLastWrite(id, globalVersion); changedCompIDs[changedCompCount] = id; changedCompCount++; break; @@ -547,7 +538,7 @@ public unsafe partial struct EntityQuery for (var j = 0; j < changedCompCount; j++) { - chunk.MarkChanged(changedCompIDs[i], globalVersion); + archetype.MarkChanged(chunkIndex, changedCompIDs[j], globalVersion); } for (var index = 0; index < 6; index++) @@ -594,7 +585,7 @@ public unsafe partial struct EntityQuery var comp4TypeID = ComponentTypeID.value; var comp5TypeID = ComponentTypeID.value; var comp6TypeID = ComponentTypeID.value; - + var compTypeIDs = stackalloc int[] { comp0TypeID.value, @@ -619,7 +610,6 @@ public unsafe partial struct EntityQuery { if (id == compTypeIDs[i]) { - ComponentRegister.SetComponentLastWrite(id, globalVersion); changedCompIDs[changedCompCount] = id; changedCompCount++; break; @@ -655,7 +645,7 @@ public unsafe partial struct EntityQuery for (var j = 0; j < changedCompCount; j++) { - chunk.MarkChanged(changedCompIDs[i], globalVersion); + archetype.MarkChanged(chunkIndex, changedCompIDs[j], globalVersion); } for (var index = 0; index < 7; index++) @@ -705,7 +695,7 @@ public unsafe partial struct EntityQuery var comp5TypeID = ComponentTypeID.value; var comp6TypeID = ComponentTypeID.value; var comp7TypeID = ComponentTypeID.value; - + var compTypeIDs = stackalloc int[] { comp0TypeID.value, @@ -731,7 +721,6 @@ public unsafe partial struct EntityQuery { if (id == compTypeIDs[i]) { - ComponentRegister.SetComponentLastWrite(id, globalVersion); changedCompIDs[changedCompCount] = id; changedCompCount++; break; @@ -767,7 +756,7 @@ public unsafe partial struct EntityQuery for (var j = 0; j < changedCompCount; j++) { - chunk.MarkChanged(changedCompIDs[i], globalVersion); + archetype.MarkChanged(chunkIndex, changedCompIDs[j], globalVersion); } for (var index = 0; index < 8; index++) @@ -804,7 +793,7 @@ public unsafe partial struct EntityQuery var globalVersion = world.Version; var comp0TypeID = ComponentTypeID.value; - + var compTypeIDs = stackalloc int[] { comp0TypeID.value, @@ -823,7 +812,6 @@ public unsafe partial struct EntityQuery { if (id == compTypeIDs[i]) { - ComponentRegister.SetComponentLastWrite(id, globalVersion); changedCompIDs[changedCompCount] = id; changedCompCount++; break; @@ -859,7 +847,7 @@ public unsafe partial struct EntityQuery for (var j = 0; j < changedCompCount; j++) { - chunk.MarkChanged(changedCompIDs[i], globalVersion); + archetype.MarkChanged(chunkIndex, changedCompIDs[j], globalVersion); } for (var index = 0; index < 1; index++) @@ -892,7 +880,7 @@ public unsafe partial struct EntityQuery var comp0TypeID = ComponentTypeID.value; var comp1TypeID = ComponentTypeID.value; - + var compTypeIDs = stackalloc int[] { comp0TypeID.value, @@ -912,7 +900,6 @@ public unsafe partial struct EntityQuery { if (id == compTypeIDs[i]) { - ComponentRegister.SetComponentLastWrite(id, globalVersion); changedCompIDs[changedCompCount] = id; changedCompCount++; break; @@ -948,7 +935,7 @@ public unsafe partial struct EntityQuery for (var j = 0; j < changedCompCount; j++) { - chunk.MarkChanged(changedCompIDs[i], globalVersion); + archetype.MarkChanged(chunkIndex, changedCompIDs[j], globalVersion); } for (var index = 0; index < 2; index++) @@ -984,7 +971,7 @@ public unsafe partial struct EntityQuery var comp0TypeID = ComponentTypeID.value; var comp1TypeID = ComponentTypeID.value; var comp2TypeID = ComponentTypeID.value; - + var compTypeIDs = stackalloc int[] { comp0TypeID.value, @@ -1005,7 +992,6 @@ public unsafe partial struct EntityQuery { if (id == compTypeIDs[i]) { - ComponentRegister.SetComponentLastWrite(id, globalVersion); changedCompIDs[changedCompCount] = id; changedCompCount++; break; @@ -1041,7 +1027,7 @@ public unsafe partial struct EntityQuery for (var j = 0; j < changedCompCount; j++) { - chunk.MarkChanged(changedCompIDs[i], globalVersion); + archetype.MarkChanged(chunkIndex, changedCompIDs[j], globalVersion); } for (var index = 0; index < 3; index++) @@ -1080,7 +1066,7 @@ public unsafe partial struct EntityQuery var comp1TypeID = ComponentTypeID.value; var comp2TypeID = ComponentTypeID.value; var comp3TypeID = ComponentTypeID.value; - + var compTypeIDs = stackalloc int[] { comp0TypeID.value, @@ -1102,7 +1088,6 @@ public unsafe partial struct EntityQuery { if (id == compTypeIDs[i]) { - ComponentRegister.SetComponentLastWrite(id, globalVersion); changedCompIDs[changedCompCount] = id; changedCompCount++; break; @@ -1138,7 +1123,7 @@ public unsafe partial struct EntityQuery for (var j = 0; j < changedCompCount; j++) { - chunk.MarkChanged(changedCompIDs[i], globalVersion); + archetype.MarkChanged(chunkIndex, changedCompIDs[j], globalVersion); } for (var index = 0; index < 4; index++) @@ -1180,7 +1165,7 @@ public unsafe partial struct EntityQuery var comp2TypeID = ComponentTypeID.value; var comp3TypeID = ComponentTypeID.value; var comp4TypeID = ComponentTypeID.value; - + var compTypeIDs = stackalloc int[] { comp0TypeID.value, @@ -1203,7 +1188,6 @@ public unsafe partial struct EntityQuery { if (id == compTypeIDs[i]) { - ComponentRegister.SetComponentLastWrite(id, globalVersion); changedCompIDs[changedCompCount] = id; changedCompCount++; break; @@ -1239,7 +1223,7 @@ public unsafe partial struct EntityQuery for (var j = 0; j < changedCompCount; j++) { - chunk.MarkChanged(changedCompIDs[i], globalVersion); + archetype.MarkChanged(chunkIndex, changedCompIDs[j], globalVersion); } for (var index = 0; index < 5; index++) @@ -1284,7 +1268,7 @@ public unsafe partial struct EntityQuery var comp3TypeID = ComponentTypeID.value; var comp4TypeID = ComponentTypeID.value; var comp5TypeID = ComponentTypeID.value; - + var compTypeIDs = stackalloc int[] { comp0TypeID.value, @@ -1308,7 +1292,6 @@ public unsafe partial struct EntityQuery { if (id == compTypeIDs[i]) { - ComponentRegister.SetComponentLastWrite(id, globalVersion); changedCompIDs[changedCompCount] = id; changedCompCount++; break; @@ -1344,7 +1327,7 @@ public unsafe partial struct EntityQuery for (var j = 0; j < changedCompCount; j++) { - chunk.MarkChanged(changedCompIDs[i], globalVersion); + archetype.MarkChanged(chunkIndex, changedCompIDs[j], globalVersion); } for (var index = 0; index < 6; index++) @@ -1392,7 +1375,7 @@ public unsafe partial struct EntityQuery var comp4TypeID = ComponentTypeID.value; var comp5TypeID = ComponentTypeID.value; var comp6TypeID = ComponentTypeID.value; - + var compTypeIDs = stackalloc int[] { comp0TypeID.value, @@ -1417,7 +1400,6 @@ public unsafe partial struct EntityQuery { if (id == compTypeIDs[i]) { - ComponentRegister.SetComponentLastWrite(id, globalVersion); changedCompIDs[changedCompCount] = id; changedCompCount++; break; @@ -1453,7 +1435,7 @@ public unsafe partial struct EntityQuery for (var j = 0; j < changedCompCount; j++) { - chunk.MarkChanged(changedCompIDs[i], globalVersion); + archetype.MarkChanged(chunkIndex, changedCompIDs[j], globalVersion); } for (var index = 0; index < 7; index++) @@ -1504,7 +1486,7 @@ public unsafe partial struct EntityQuery var comp5TypeID = ComponentTypeID.value; var comp6TypeID = ComponentTypeID.value; var comp7TypeID = ComponentTypeID.value; - + var compTypeIDs = stackalloc int[] { comp0TypeID.value, @@ -1530,7 +1512,6 @@ public unsafe partial struct EntityQuery { if (id == compTypeIDs[i]) { - ComponentRegister.SetComponentLastWrite(id, globalVersion); changedCompIDs[changedCompCount] = id; changedCompCount++; break; @@ -1566,7 +1547,7 @@ public unsafe partial struct EntityQuery for (var j = 0; j < changedCompCount; j++) { - chunk.MarkChanged(changedCompIDs[i], globalVersion); + archetype.MarkChanged(chunkIndex, changedCompIDs[j], globalVersion); } for (var index = 0; index < 8; index++) diff --git a/Ghost.Entities/Templates/EntityQuery.ForEach.tt b/Ghost.Entities/Templates/EntityQuery.ForEach.tt index ff3516c..2e5e3ab 100644 --- a/Ghost.Entities/Templates/EntityQuery.ForEach.tt +++ b/Ghost.Entities/Templates/EntityQuery.ForEach.tt @@ -4,8 +4,6 @@ <#@ import namespace="System.Linq" #> <#@ import namespace="System.Text" #> <#@ include file="Helpers.ttinclude" #> -using Ghost.Core; - namespace Ghost.Entities; public unsafe partial struct EntityQuery @@ -30,7 +28,7 @@ public unsafe partial struct EntityQuery <# for (var localIndex = 0; localIndex < i; localIndex++) { #> var comp<#= localIndex #>TypeID = ComponentTypeID>.value; <# } #> - + var compTypeIDs = stackalloc int[] { <# for (var localIndex = 0; localIndex < i; localIndex++) { #> @@ -51,7 +49,6 @@ public unsafe partial struct EntityQuery { if (id == compTypeIDs[i]) { - ComponentRegister.SetComponentLastWrite(id, globalVersion); changedCompIDs[changedCompCount] = id; changedCompCount++; break; @@ -87,7 +84,7 @@ public unsafe partial struct EntityQuery for (var j = 0; j < changedCompCount; j++) { - chunk.MarkChanged(changedCompIDs[i], globalVersion); + archetype.MarkChanged(chunkIndex, changedCompIDs[j], globalVersion); } for (var index = 0; index < <#= i #>; index++) diff --git a/Ghost.Entities/Templates/EntityQuery.JobEntity.gen.cs b/Ghost.Entities/Templates/EntityQuery.JobEntity.gen.cs index 3ab41ff..e5f45ce 100644 --- a/Ghost.Entities/Templates/EntityQuery.JobEntity.gen.cs +++ b/Ghost.Entities/Templates/EntityQuery.JobEntity.gen.cs @@ -1,6 +1,5 @@ using Ghost.Core; using Misaki.HighPerformance.Jobs; -using Misaki.HighPerformance.LowLevel.Buffer; using Misaki.HighPerformance.LowLevel.Collections; namespace Ghost.Entities; @@ -15,27 +14,43 @@ internal unsafe struct JobEntityBatch : IJobParallelFor where TJob : unmanaged, IJobEntity where T0 : unmanaged, IComponent { + public fixed int componentIDs[1]; + public fixed bool componentRW[1]; + public TJob userJob; public UnsafeList chunks; + public UnsafeList chunkVersions; public UnsafeList chunkCount; public UnsafeList entityOffset; public UnsafeList offsets0; public UnsafeList bitsOffsets0; + public UnsafeList versionindices0; + + public int version; public void Execute(int loopIndex, int threadIndex) { // 1. Get the specific pChunk for this thread var pChunk = (byte*)chunks[loopIndex]; + var pVersions = (int*)chunkVersions[loopIndex]; var count = chunkCount[loopIndex]; var off0 = offsets0[loopIndex]; var enableOff0 = bitsOffsets0[loopIndex]; + var versionIndex0 = versionindices0[loopIndex]; var pEntity = (Entity*)(pChunk + entityOffset[loopIndex]); var ptr0 = (T0*)(pChunk + off0); + // 2. Update versions for RW components + if (componentRW[0]) + { + pVersions[versionIndex0] = version; + } + + // 3. Iterate all entities in this chunk for (var i = 0; i < count; i++) { if (enableOff0 != -1 && !EntityQuery.CheckBit(pChunk + enableOff0, i)) @@ -60,34 +75,57 @@ internal unsafe struct JobEntityBatch : IJobParallelFor where T0 : unmanaged, IComponent where T1 : unmanaged, IComponent { + public fixed int componentIDs[2]; + public fixed bool componentRW[2]; + public TJob userJob; public UnsafeList chunks; + public UnsafeList chunkVersions; public UnsafeList chunkCount; public UnsafeList entityOffset; public UnsafeList offsets0; public UnsafeList bitsOffsets0; + public UnsafeList versionindices0; public UnsafeList offsets1; public UnsafeList bitsOffsets1; + public UnsafeList versionindices1; + + public int version; public void Execute(int loopIndex, int threadIndex) { // 1. Get the specific pChunk for this thread var pChunk = (byte*)chunks[loopIndex]; + var pVersions = (int*)chunkVersions[loopIndex]; var count = chunkCount[loopIndex]; var off0 = offsets0[loopIndex]; var enableOff0 = bitsOffsets0[loopIndex]; + var versionIndex0 = versionindices0[loopIndex]; var off1 = offsets1[loopIndex]; var enableOff1 = bitsOffsets1[loopIndex]; + var versionIndex1 = versionindices1[loopIndex]; var pEntity = (Entity*)(pChunk + entityOffset[loopIndex]); var ptr0 = (T0*)(pChunk + off0); var ptr1 = (T1*)(pChunk + off1); + // 2. Update versions for RW components + if (componentRW[0]) + { + pVersions[versionIndex0] = version; + } + + if (componentRW[1]) + { + pVersions[versionIndex1] = version; + } + + // 3. Iterate all entities in this chunk for (var i = 0; i < count; i++) { if (enableOff0 != -1 && !EntityQuery.CheckBit(pChunk + enableOff0, i)) @@ -119,41 +157,71 @@ internal unsafe struct JobEntityBatch : IJobParallelFor where T1 : unmanaged, IComponent where T2 : unmanaged, IComponent { + public fixed int componentIDs[3]; + public fixed bool componentRW[3]; + public TJob userJob; public UnsafeList chunks; + public UnsafeList chunkVersions; public UnsafeList chunkCount; public UnsafeList entityOffset; public UnsafeList offsets0; public UnsafeList bitsOffsets0; + public UnsafeList versionindices0; public UnsafeList offsets1; public UnsafeList bitsOffsets1; + public UnsafeList versionindices1; public UnsafeList offsets2; public UnsafeList bitsOffsets2; + public UnsafeList versionindices2; + + public int version; public void Execute(int loopIndex, int threadIndex) { // 1. Get the specific pChunk for this thread var pChunk = (byte*)chunks[loopIndex]; + var pVersions = (int*)chunkVersions[loopIndex]; var count = chunkCount[loopIndex]; var off0 = offsets0[loopIndex]; var enableOff0 = bitsOffsets0[loopIndex]; + var versionIndex0 = versionindices0[loopIndex]; var off1 = offsets1[loopIndex]; var enableOff1 = bitsOffsets1[loopIndex]; + var versionIndex1 = versionindices1[loopIndex]; var off2 = offsets2[loopIndex]; var enableOff2 = bitsOffsets2[loopIndex]; + var versionIndex2 = versionindices2[loopIndex]; var pEntity = (Entity*)(pChunk + entityOffset[loopIndex]); var ptr0 = (T0*)(pChunk + off0); var ptr1 = (T1*)(pChunk + off1); var ptr2 = (T2*)(pChunk + off2); + // 2. Update versions for RW components + if (componentRW[0]) + { + pVersions[versionIndex0] = version; + } + + if (componentRW[1]) + { + pVersions[versionIndex1] = version; + } + + if (componentRW[2]) + { + pVersions[versionIndex2] = version; + } + + // 3. Iterate all entities in this chunk for (var i = 0; i < count; i++) { if (enableOff0 != -1 && !EntityQuery.CheckBit(pChunk + enableOff0, i)) @@ -192,41 +260,56 @@ internal unsafe struct JobEntityBatch : IJobParallelFor where T2 : unmanaged, IComponent where T3 : unmanaged, IComponent { + public fixed int componentIDs[4]; + public fixed bool componentRW[4]; + public TJob userJob; public UnsafeList chunks; + public UnsafeList chunkVersions; public UnsafeList chunkCount; public UnsafeList entityOffset; public UnsafeList offsets0; public UnsafeList bitsOffsets0; + public UnsafeList versionindices0; public UnsafeList offsets1; public UnsafeList bitsOffsets1; + public UnsafeList versionindices1; public UnsafeList offsets2; public UnsafeList bitsOffsets2; + public UnsafeList versionindices2; public UnsafeList offsets3; public UnsafeList bitsOffsets3; + public UnsafeList versionindices3; + + public int version; public void Execute(int loopIndex, int threadIndex) { // 1. Get the specific pChunk for this thread var pChunk = (byte*)chunks[loopIndex]; + var pVersions = (int*)chunkVersions[loopIndex]; var count = chunkCount[loopIndex]; var off0 = offsets0[loopIndex]; var enableOff0 = bitsOffsets0[loopIndex]; + var versionIndex0 = versionindices0[loopIndex]; var off1 = offsets1[loopIndex]; var enableOff1 = bitsOffsets1[loopIndex]; + var versionIndex1 = versionindices1[loopIndex]; var off2 = offsets2[loopIndex]; var enableOff2 = bitsOffsets2[loopIndex]; + var versionIndex2 = versionindices2[loopIndex]; var off3 = offsets3[loopIndex]; var enableOff3 = bitsOffsets3[loopIndex]; + var versionIndex3 = versionindices3[loopIndex]; var pEntity = (Entity*)(pChunk + entityOffset[loopIndex]); var ptr0 = (T0*)(pChunk + off0); @@ -234,6 +317,28 @@ internal unsafe struct JobEntityBatch : IJobParallelFor var ptr2 = (T2*)(pChunk + off2); var ptr3 = (T3*)(pChunk + off3); + // 2. Update versions for RW components + if (componentRW[0]) + { + pVersions[versionIndex0] = version; + } + + if (componentRW[1]) + { + pVersions[versionIndex1] = version; + } + + if (componentRW[2]) + { + pVersions[versionIndex2] = version; + } + + if (componentRW[3]) + { + pVersions[versionIndex3] = version; + } + + // 3. Iterate all entities in this chunk for (var i = 0; i < count; i++) { if (enableOff0 != -1 && !EntityQuery.CheckBit(pChunk + enableOff0, i)) @@ -279,47 +384,64 @@ internal unsafe struct JobEntityBatch : IJobParallelFo where T3 : unmanaged, IComponent where T4 : unmanaged, IComponent { + public fixed int componentIDs[5]; + public fixed bool componentRW[5]; + public TJob userJob; public UnsafeList chunks; + public UnsafeList chunkVersions; public UnsafeList chunkCount; public UnsafeList entityOffset; public UnsafeList offsets0; public UnsafeList bitsOffsets0; + public UnsafeList versionindices0; public UnsafeList offsets1; public UnsafeList bitsOffsets1; + public UnsafeList versionindices1; public UnsafeList offsets2; public UnsafeList bitsOffsets2; + public UnsafeList versionindices2; public UnsafeList offsets3; public UnsafeList bitsOffsets3; + public UnsafeList versionindices3; public UnsafeList offsets4; public UnsafeList bitsOffsets4; + public UnsafeList versionindices4; + + public int version; public void Execute(int loopIndex, int threadIndex) { // 1. Get the specific pChunk for this thread var pChunk = (byte*)chunks[loopIndex]; + var pVersions = (int*)chunkVersions[loopIndex]; var count = chunkCount[loopIndex]; var off0 = offsets0[loopIndex]; var enableOff0 = bitsOffsets0[loopIndex]; + var versionIndex0 = versionindices0[loopIndex]; var off1 = offsets1[loopIndex]; var enableOff1 = bitsOffsets1[loopIndex]; + var versionIndex1 = versionindices1[loopIndex]; var off2 = offsets2[loopIndex]; var enableOff2 = bitsOffsets2[loopIndex]; + var versionIndex2 = versionindices2[loopIndex]; var off3 = offsets3[loopIndex]; var enableOff3 = bitsOffsets3[loopIndex]; + var versionIndex3 = versionindices3[loopIndex]; var off4 = offsets4[loopIndex]; var enableOff4 = bitsOffsets4[loopIndex]; + var versionIndex4 = versionindices4[loopIndex]; var pEntity = (Entity*)(pChunk + entityOffset[loopIndex]); var ptr0 = (T0*)(pChunk + off0); @@ -328,6 +450,33 @@ internal unsafe struct JobEntityBatch : IJobParallelFo var ptr3 = (T3*)(pChunk + off3); var ptr4 = (T4*)(pChunk + off4); + // 2. Update versions for RW components + if (componentRW[0]) + { + pVersions[versionIndex0] = version; + } + + if (componentRW[1]) + { + pVersions[versionIndex1] = version; + } + + if (componentRW[2]) + { + pVersions[versionIndex2] = version; + } + + if (componentRW[3]) + { + pVersions[versionIndex3] = version; + } + + if (componentRW[4]) + { + pVersions[versionIndex4] = version; + } + + // 3. Iterate all entities in this chunk for (var i = 0; i < count; i++) { if (enableOff0 != -1 && !EntityQuery.CheckBit(pChunk + enableOff0, i)) @@ -380,53 +529,72 @@ internal unsafe struct JobEntityBatch : IJobParall where T4 : unmanaged, IComponent where T5 : unmanaged, IComponent { + public fixed int componentIDs[6]; + public fixed bool componentRW[6]; + public TJob userJob; public UnsafeList chunks; + public UnsafeList chunkVersions; public UnsafeList chunkCount; public UnsafeList entityOffset; public UnsafeList offsets0; public UnsafeList bitsOffsets0; + public UnsafeList versionindices0; public UnsafeList offsets1; public UnsafeList bitsOffsets1; + public UnsafeList versionindices1; public UnsafeList offsets2; public UnsafeList bitsOffsets2; + public UnsafeList versionindices2; public UnsafeList offsets3; public UnsafeList bitsOffsets3; + public UnsafeList versionindices3; public UnsafeList offsets4; public UnsafeList bitsOffsets4; + public UnsafeList versionindices4; public UnsafeList offsets5; public UnsafeList bitsOffsets5; + public UnsafeList versionindices5; + + public int version; public void Execute(int loopIndex, int threadIndex) { // 1. Get the specific pChunk for this thread var pChunk = (byte*)chunks[loopIndex]; + var pVersions = (int*)chunkVersions[loopIndex]; var count = chunkCount[loopIndex]; var off0 = offsets0[loopIndex]; var enableOff0 = bitsOffsets0[loopIndex]; + var versionIndex0 = versionindices0[loopIndex]; var off1 = offsets1[loopIndex]; var enableOff1 = bitsOffsets1[loopIndex]; + var versionIndex1 = versionindices1[loopIndex]; var off2 = offsets2[loopIndex]; var enableOff2 = bitsOffsets2[loopIndex]; + var versionIndex2 = versionindices2[loopIndex]; var off3 = offsets3[loopIndex]; var enableOff3 = bitsOffsets3[loopIndex]; + var versionIndex3 = versionindices3[loopIndex]; var off4 = offsets4[loopIndex]; var enableOff4 = bitsOffsets4[loopIndex]; + var versionIndex4 = versionindices4[loopIndex]; var off5 = offsets5[loopIndex]; var enableOff5 = bitsOffsets5[loopIndex]; + var versionIndex5 = versionindices5[loopIndex]; var pEntity = (Entity*)(pChunk + entityOffset[loopIndex]); var ptr0 = (T0*)(pChunk + off0); @@ -436,6 +604,38 @@ internal unsafe struct JobEntityBatch : IJobParall var ptr4 = (T4*)(pChunk + off4); var ptr5 = (T5*)(pChunk + off5); + // 2. Update versions for RW components + if (componentRW[0]) + { + pVersions[versionIndex0] = version; + } + + if (componentRW[1]) + { + pVersions[versionIndex1] = version; + } + + if (componentRW[2]) + { + pVersions[versionIndex2] = version; + } + + if (componentRW[3]) + { + pVersions[versionIndex3] = version; + } + + if (componentRW[4]) + { + pVersions[versionIndex4] = version; + } + + if (componentRW[5]) + { + pVersions[versionIndex5] = version; + } + + // 3. Iterate all entities in this chunk for (var i = 0; i < count; i++) { if (enableOff0 != -1 && !EntityQuery.CheckBit(pChunk + enableOff0, i)) @@ -495,59 +695,80 @@ internal unsafe struct JobEntityBatch : IJobPa where T5 : unmanaged, IComponent where T6 : unmanaged, IComponent { + public fixed int componentIDs[7]; + public fixed bool componentRW[7]; + public TJob userJob; public UnsafeList chunks; + public UnsafeList chunkVersions; public UnsafeList chunkCount; public UnsafeList entityOffset; public UnsafeList offsets0; public UnsafeList bitsOffsets0; + public UnsafeList versionindices0; public UnsafeList offsets1; public UnsafeList bitsOffsets1; + public UnsafeList versionindices1; public UnsafeList offsets2; public UnsafeList bitsOffsets2; + public UnsafeList versionindices2; public UnsafeList offsets3; public UnsafeList bitsOffsets3; + public UnsafeList versionindices3; public UnsafeList offsets4; public UnsafeList bitsOffsets4; + public UnsafeList versionindices4; public UnsafeList offsets5; public UnsafeList bitsOffsets5; + public UnsafeList versionindices5; public UnsafeList offsets6; public UnsafeList bitsOffsets6; + public UnsafeList versionindices6; + + public int version; public void Execute(int loopIndex, int threadIndex) { // 1. Get the specific pChunk for this thread var pChunk = (byte*)chunks[loopIndex]; + var pVersions = (int*)chunkVersions[loopIndex]; var count = chunkCount[loopIndex]; var off0 = offsets0[loopIndex]; var enableOff0 = bitsOffsets0[loopIndex]; + var versionIndex0 = versionindices0[loopIndex]; var off1 = offsets1[loopIndex]; var enableOff1 = bitsOffsets1[loopIndex]; + var versionIndex1 = versionindices1[loopIndex]; var off2 = offsets2[loopIndex]; var enableOff2 = bitsOffsets2[loopIndex]; + var versionIndex2 = versionindices2[loopIndex]; var off3 = offsets3[loopIndex]; var enableOff3 = bitsOffsets3[loopIndex]; + var versionIndex3 = versionindices3[loopIndex]; var off4 = offsets4[loopIndex]; var enableOff4 = bitsOffsets4[loopIndex]; + var versionIndex4 = versionindices4[loopIndex]; var off5 = offsets5[loopIndex]; var enableOff5 = bitsOffsets5[loopIndex]; + var versionIndex5 = versionindices5[loopIndex]; var off6 = offsets6[loopIndex]; var enableOff6 = bitsOffsets6[loopIndex]; + var versionIndex6 = versionindices6[loopIndex]; var pEntity = (Entity*)(pChunk + entityOffset[loopIndex]); var ptr0 = (T0*)(pChunk + off0); @@ -558,6 +779,43 @@ internal unsafe struct JobEntityBatch : IJobPa var ptr5 = (T5*)(pChunk + off5); var ptr6 = (T6*)(pChunk + off6); + // 2. Update versions for RW components + if (componentRW[0]) + { + pVersions[versionIndex0] = version; + } + + if (componentRW[1]) + { + pVersions[versionIndex1] = version; + } + + if (componentRW[2]) + { + pVersions[versionIndex2] = version; + } + + if (componentRW[3]) + { + pVersions[versionIndex3] = version; + } + + if (componentRW[4]) + { + pVersions[versionIndex4] = version; + } + + if (componentRW[5]) + { + pVersions[versionIndex5] = version; + } + + if (componentRW[6]) + { + pVersions[versionIndex6] = version; + } + + // 3. Iterate all entities in this chunk for (var i = 0; i < count; i++) { if (enableOff0 != -1 && !EntityQuery.CheckBit(pChunk + enableOff0, i)) @@ -624,65 +882,88 @@ internal unsafe struct JobEntityBatch : IJ where T6 : unmanaged, IComponent where T7 : unmanaged, IComponent { + public fixed int componentIDs[8]; + public fixed bool componentRW[8]; + public TJob userJob; public UnsafeList chunks; + public UnsafeList chunkVersions; public UnsafeList chunkCount; public UnsafeList entityOffset; public UnsafeList offsets0; public UnsafeList bitsOffsets0; + public UnsafeList versionindices0; public UnsafeList offsets1; public UnsafeList bitsOffsets1; + public UnsafeList versionindices1; public UnsafeList offsets2; public UnsafeList bitsOffsets2; + public UnsafeList versionindices2; public UnsafeList offsets3; public UnsafeList bitsOffsets3; + public UnsafeList versionindices3; public UnsafeList offsets4; public UnsafeList bitsOffsets4; + public UnsafeList versionindices4; public UnsafeList offsets5; public UnsafeList bitsOffsets5; + public UnsafeList versionindices5; public UnsafeList offsets6; public UnsafeList bitsOffsets6; + public UnsafeList versionindices6; public UnsafeList offsets7; public UnsafeList bitsOffsets7; + public UnsafeList versionindices7; + + public int version; public void Execute(int loopIndex, int threadIndex) { // 1. Get the specific pChunk for this thread var pChunk = (byte*)chunks[loopIndex]; + var pVersions = (int*)chunkVersions[loopIndex]; var count = chunkCount[loopIndex]; var off0 = offsets0[loopIndex]; var enableOff0 = bitsOffsets0[loopIndex]; + var versionIndex0 = versionindices0[loopIndex]; var off1 = offsets1[loopIndex]; var enableOff1 = bitsOffsets1[loopIndex]; + var versionIndex1 = versionindices1[loopIndex]; var off2 = offsets2[loopIndex]; var enableOff2 = bitsOffsets2[loopIndex]; + var versionIndex2 = versionindices2[loopIndex]; var off3 = offsets3[loopIndex]; var enableOff3 = bitsOffsets3[loopIndex]; + var versionIndex3 = versionindices3[loopIndex]; var off4 = offsets4[loopIndex]; var enableOff4 = bitsOffsets4[loopIndex]; + var versionIndex4 = versionindices4[loopIndex]; var off5 = offsets5[loopIndex]; var enableOff5 = bitsOffsets5[loopIndex]; + var versionIndex5 = versionindices5[loopIndex]; var off6 = offsets6[loopIndex]; var enableOff6 = bitsOffsets6[loopIndex]; + var versionIndex6 = versionindices6[loopIndex]; var off7 = offsets7[loopIndex]; var enableOff7 = bitsOffsets7[loopIndex]; + var versionIndex7 = versionindices7[loopIndex]; var pEntity = (Entity*)(pChunk + entityOffset[loopIndex]); var ptr0 = (T0*)(pChunk + off0); @@ -694,6 +975,48 @@ internal unsafe struct JobEntityBatch : IJ var ptr6 = (T6*)(pChunk + off6); var ptr7 = (T7*)(pChunk + off7); + // 2. Update versions for RW components + if (componentRW[0]) + { + pVersions[versionIndex0] = version; + } + + if (componentRW[1]) + { + pVersions[versionIndex1] = version; + } + + if (componentRW[2]) + { + pVersions[versionIndex2] = version; + } + + if (componentRW[3]) + { + pVersions[versionIndex3] = version; + } + + if (componentRW[4]) + { + pVersions[versionIndex4] = version; + } + + if (componentRW[5]) + { + pVersions[versionIndex5] = version; + } + + if (componentRW[6]) + { + pVersions[versionIndex6] = version; + } + + if (componentRW[7]) + { + pVersions[versionIndex7] = version; + } + + // 3. Iterate all entities in this chunk for (var i = 0; i < count; i++) { if (enableOff0 != -1 && !EntityQuery.CheckBit(pChunk + enableOff0, i)) @@ -745,38 +1068,44 @@ public unsafe partial struct EntityQuery { private struct DisposeJobEntity1 : IJob { - public UnsafeList chunkList; + public UnsafeList chunks; + public UnsafeList chunkVersions; public UnsafeList chunkEntityCounts; public UnsafeList entityOffsets; public UnsafeList offsets0; public UnsafeList bitsOffsets0; + public UnsafeList versionindices0; public void Execute(int threadIndex) { - chunkList.Dispose(); + chunks.Dispose(); + chunkVersions.Dispose(); chunkEntityCounts.Dispose(); entityOffsets.Dispose(); offsets0.Dispose(); bitsOffsets0.Dispose(); + versionindices0.Dispose(); } } - public JobHandle ScheduleEntityParallel(TJob jobData, Allocator allocator, int batchSize, JobHandle dependency) + public JobHandle ScheduleEntityParallel(TJob jobData, int batchSize, JobHandle dependency) where TJob : unmanaged, IJobEntity where T0 : unmanaged, IComponent { var world = World.GetWorld(_worldID).GetValueOrThrow(); // 1. Flatten the World - var chunkList = new UnsafeList(128, allocator); - var chunkEntityCounts = new UnsafeList(128, allocator); - var entityOffsets = new UnsafeList(128, allocator); + var chunks = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var chunkVersions = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var chunkEntityCounts = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var entityOffsets = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets0 = new UnsafeList(128, allocator); - var bitsOffsets0 = new UnsafeList(128, allocator); + var offsets0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); // Iterate the Query's matching archetypes foreach (var archID in _matchingArchetypes) @@ -797,12 +1126,14 @@ public unsafe partial struct EntityQuery { ref var chunkRef = ref arch.GetChunkReference(i); - chunkList.Add((IntPtr)chunkRef.GetUnsafePtr()); + chunks.Add((IntPtr)chunkRef.GetUnsafePtr()); + chunkVersions.Add((IntPtr)chunkRef.GetVersionUnsafePtr()); chunkEntityCounts.Add(chunkRef._count); entityOffsets.Add(arch.EntityIDsOffset); offsets0.Add(layout0.offset); bitsOffsets0.Add(layout0.enableBitsOffset); + versionIndices0.Add(layout0.versionIndex); } } @@ -811,26 +1142,46 @@ public unsafe partial struct EntityQuery var runner = new JobEntityBatch { userJob = jobData, - chunks = chunkList, + chunks = chunks, + chunkVersions = chunkVersions, chunkCount = chunkEntityCounts, entityOffset = entityOffsets, offsets0 = offsets0, bitsOffsets0 = bitsOffsets0, + versionindices0 = versionIndices0, + version = world.Version, }; - var jobHandle = world.JobScheduler.ScheduleParallel(ref runner, chunkList.Count, batchSize, dependency); + runner.componentIDs[0] = ComponentTypeID.value; + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i =0; i < 1; i++) + { + if (id == runner.componentIDs[i]) + { + runner.componentRW[i] = true; + break; + } + } + } + + var jobHandle = world.JobScheduler.ScheduleParallel(ref runner, chunks.Count, batchSize, dependency); // 3. Dispose the temp lists var disposeJob = new DisposeJobEntity1 { - chunkList = chunkList, + chunks = chunks, + chunkVersions = chunkVersions, chunkEntityCounts = chunkEntityCounts, entityOffsets = entityOffsets, offsets0 = offsets0, bitsOffsets0 = bitsOffsets0, + versionindices0 = versionIndices0, }; @@ -841,32 +1192,38 @@ public unsafe partial struct EntityQuery private struct DisposeJobEntity2 : IJob { - public UnsafeList chunkList; + public UnsafeList chunks; + public UnsafeList chunkVersions; public UnsafeList chunkEntityCounts; public UnsafeList entityOffsets; public UnsafeList offsets0; public UnsafeList bitsOffsets0; + public UnsafeList versionindices0; public UnsafeList offsets1; public UnsafeList bitsOffsets1; + public UnsafeList versionindices1; public void Execute(int threadIndex) { - chunkList.Dispose(); + chunks.Dispose(); + chunkVersions.Dispose(); chunkEntityCounts.Dispose(); entityOffsets.Dispose(); offsets0.Dispose(); bitsOffsets0.Dispose(); + versionindices0.Dispose(); offsets1.Dispose(); bitsOffsets1.Dispose(); + versionindices1.Dispose(); } } - public JobHandle ScheduleEntityParallel(TJob jobData, Allocator allocator, int batchSize, JobHandle dependency) + public JobHandle ScheduleEntityParallel(TJob jobData, int batchSize, JobHandle dependency) where TJob : unmanaged, IJobEntity where T0 : unmanaged, IComponent where T1 : unmanaged, IComponent @@ -874,15 +1231,18 @@ public unsafe partial struct EntityQuery var world = World.GetWorld(_worldID).GetValueOrThrow(); // 1. Flatten the World - var chunkList = new UnsafeList(128, allocator); - var chunkEntityCounts = new UnsafeList(128, allocator); - var entityOffsets = new UnsafeList(128, allocator); + var chunks = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var chunkVersions = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var chunkEntityCounts = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var entityOffsets = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets0 = new UnsafeList(128, allocator); - var bitsOffsets0 = new UnsafeList(128, allocator); + var offsets0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets1 = new UnsafeList(128, allocator); - var bitsOffsets1 = new UnsafeList(128, allocator); + var offsets1 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets1 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices1 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); // Iterate the Query's matching archetypes foreach (var archID in _matchingArchetypes) @@ -905,15 +1265,18 @@ public unsafe partial struct EntityQuery { ref var chunkRef = ref arch.GetChunkReference(i); - chunkList.Add((IntPtr)chunkRef.GetUnsafePtr()); + chunks.Add((IntPtr)chunkRef.GetUnsafePtr()); + chunkVersions.Add((IntPtr)chunkRef.GetVersionUnsafePtr()); chunkEntityCounts.Add(chunkRef._count); entityOffsets.Add(arch.EntityIDsOffset); offsets0.Add(layout0.offset); bitsOffsets0.Add(layout0.enableBitsOffset); + versionIndices0.Add(layout0.versionIndex); offsets1.Add(layout1.offset); bitsOffsets1.Add(layout1.enableBitsOffset); + versionIndices1.Add(layout1.versionIndex); } } @@ -922,32 +1285,54 @@ public unsafe partial struct EntityQuery var runner = new JobEntityBatch { userJob = jobData, - chunks = chunkList, + chunks = chunks, + chunkVersions = chunkVersions, chunkCount = chunkEntityCounts, entityOffset = entityOffsets, offsets0 = offsets0, bitsOffsets0 = bitsOffsets0, + versionindices0 = versionIndices0, offsets1 = offsets1, bitsOffsets1 = bitsOffsets1, + versionindices1 = versionIndices1, + version = world.Version, }; - var jobHandle = world.JobScheduler.ScheduleParallel(ref runner, chunkList.Count, batchSize, dependency); + runner.componentIDs[0] = ComponentTypeID.value; + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i =0; i < 1; i++) + { + if (id == runner.componentIDs[i]) + { + runner.componentRW[i] = true; + break; + } + } + } + + var jobHandle = world.JobScheduler.ScheduleParallel(ref runner, chunks.Count, batchSize, dependency); // 3. Dispose the temp lists var disposeJob = new DisposeJobEntity2 { - chunkList = chunkList, + chunks = chunks, + chunkVersions = chunkVersions, chunkEntityCounts = chunkEntityCounts, entityOffsets = entityOffsets, offsets0 = offsets0, bitsOffsets0 = bitsOffsets0, + versionindices0 = versionIndices0, offsets1 = offsets1, bitsOffsets1 = bitsOffsets1, + versionindices1 = versionIndices1, }; @@ -958,38 +1343,46 @@ public unsafe partial struct EntityQuery private struct DisposeJobEntity3 : IJob { - public UnsafeList chunkList; + public UnsafeList chunks; + public UnsafeList chunkVersions; public UnsafeList chunkEntityCounts; public UnsafeList entityOffsets; public UnsafeList offsets0; public UnsafeList bitsOffsets0; + public UnsafeList versionindices0; public UnsafeList offsets1; public UnsafeList bitsOffsets1; + public UnsafeList versionindices1; public UnsafeList offsets2; public UnsafeList bitsOffsets2; + public UnsafeList versionindices2; public void Execute(int threadIndex) { - chunkList.Dispose(); + chunks.Dispose(); + chunkVersions.Dispose(); chunkEntityCounts.Dispose(); entityOffsets.Dispose(); offsets0.Dispose(); bitsOffsets0.Dispose(); + versionindices0.Dispose(); offsets1.Dispose(); bitsOffsets1.Dispose(); + versionindices1.Dispose(); offsets2.Dispose(); bitsOffsets2.Dispose(); + versionindices2.Dispose(); } } - public JobHandle ScheduleEntityParallel(TJob jobData, Allocator allocator, int batchSize, JobHandle dependency) + public JobHandle ScheduleEntityParallel(TJob jobData, int batchSize, JobHandle dependency) where TJob : unmanaged, IJobEntity where T0 : unmanaged, IComponent where T1 : unmanaged, IComponent @@ -998,18 +1391,22 @@ public unsafe partial struct EntityQuery var world = World.GetWorld(_worldID).GetValueOrThrow(); // 1. Flatten the World - var chunkList = new UnsafeList(128, allocator); - var chunkEntityCounts = new UnsafeList(128, allocator); - var entityOffsets = new UnsafeList(128, allocator); + var chunks = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var chunkVersions = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var chunkEntityCounts = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var entityOffsets = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets0 = new UnsafeList(128, allocator); - var bitsOffsets0 = new UnsafeList(128, allocator); + var offsets0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets1 = new UnsafeList(128, allocator); - var bitsOffsets1 = new UnsafeList(128, allocator); + var offsets1 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets1 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices1 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets2 = new UnsafeList(128, allocator); - var bitsOffsets2 = new UnsafeList(128, allocator); + var offsets2 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets2 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices2 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); // Iterate the Query's matching archetypes foreach (var archID in _matchingArchetypes) @@ -1034,18 +1431,22 @@ public unsafe partial struct EntityQuery { ref var chunkRef = ref arch.GetChunkReference(i); - chunkList.Add((IntPtr)chunkRef.GetUnsafePtr()); + chunks.Add((IntPtr)chunkRef.GetUnsafePtr()); + chunkVersions.Add((IntPtr)chunkRef.GetVersionUnsafePtr()); chunkEntityCounts.Add(chunkRef._count); entityOffsets.Add(arch.EntityIDsOffset); offsets0.Add(layout0.offset); bitsOffsets0.Add(layout0.enableBitsOffset); + versionIndices0.Add(layout0.versionIndex); offsets1.Add(layout1.offset); bitsOffsets1.Add(layout1.enableBitsOffset); + versionIndices1.Add(layout1.versionIndex); offsets2.Add(layout2.offset); bitsOffsets2.Add(layout2.enableBitsOffset); + versionIndices2.Add(layout2.versionIndex); } } @@ -1054,38 +1455,62 @@ public unsafe partial struct EntityQuery var runner = new JobEntityBatch { userJob = jobData, - chunks = chunkList, + chunks = chunks, + chunkVersions = chunkVersions, chunkCount = chunkEntityCounts, entityOffset = entityOffsets, offsets0 = offsets0, bitsOffsets0 = bitsOffsets0, + versionindices0 = versionIndices0, offsets1 = offsets1, bitsOffsets1 = bitsOffsets1, + versionindices1 = versionIndices1, offsets2 = offsets2, bitsOffsets2 = bitsOffsets2, + versionindices2 = versionIndices2, + version = world.Version, }; - var jobHandle = world.JobScheduler.ScheduleParallel(ref runner, chunkList.Count, batchSize, dependency); + runner.componentIDs[0] = ComponentTypeID.value; + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i =0; i < 1; i++) + { + if (id == runner.componentIDs[i]) + { + runner.componentRW[i] = true; + break; + } + } + } + + var jobHandle = world.JobScheduler.ScheduleParallel(ref runner, chunks.Count, batchSize, dependency); // 3. Dispose the temp lists var disposeJob = new DisposeJobEntity3 { - chunkList = chunkList, + chunks = chunks, + chunkVersions = chunkVersions, chunkEntityCounts = chunkEntityCounts, entityOffsets = entityOffsets, offsets0 = offsets0, bitsOffsets0 = bitsOffsets0, + versionindices0 = versionIndices0, offsets1 = offsets1, bitsOffsets1 = bitsOffsets1, + versionindices1 = versionIndices1, offsets2 = offsets2, bitsOffsets2 = bitsOffsets2, + versionindices2 = versionIndices2, }; @@ -1096,44 +1521,54 @@ public unsafe partial struct EntityQuery private struct DisposeJobEntity4 : IJob { - public UnsafeList chunkList; + public UnsafeList chunks; + public UnsafeList chunkVersions; public UnsafeList chunkEntityCounts; public UnsafeList entityOffsets; public UnsafeList offsets0; public UnsafeList bitsOffsets0; + public UnsafeList versionindices0; public UnsafeList offsets1; public UnsafeList bitsOffsets1; + public UnsafeList versionindices1; public UnsafeList offsets2; public UnsafeList bitsOffsets2; + public UnsafeList versionindices2; public UnsafeList offsets3; public UnsafeList bitsOffsets3; + public UnsafeList versionindices3; public void Execute(int threadIndex) { - chunkList.Dispose(); + chunks.Dispose(); + chunkVersions.Dispose(); chunkEntityCounts.Dispose(); entityOffsets.Dispose(); offsets0.Dispose(); bitsOffsets0.Dispose(); + versionindices0.Dispose(); offsets1.Dispose(); bitsOffsets1.Dispose(); + versionindices1.Dispose(); offsets2.Dispose(); bitsOffsets2.Dispose(); + versionindices2.Dispose(); offsets3.Dispose(); bitsOffsets3.Dispose(); + versionindices3.Dispose(); } } - public JobHandle ScheduleEntityParallel(TJob jobData, Allocator allocator, int batchSize, JobHandle dependency) + public JobHandle ScheduleEntityParallel(TJob jobData, int batchSize, JobHandle dependency) where TJob : unmanaged, IJobEntity where T0 : unmanaged, IComponent where T1 : unmanaged, IComponent @@ -1143,21 +1578,26 @@ public unsafe partial struct EntityQuery var world = World.GetWorld(_worldID).GetValueOrThrow(); // 1. Flatten the World - var chunkList = new UnsafeList(128, allocator); - var chunkEntityCounts = new UnsafeList(128, allocator); - var entityOffsets = new UnsafeList(128, allocator); + var chunks = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var chunkVersions = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var chunkEntityCounts = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var entityOffsets = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets0 = new UnsafeList(128, allocator); - var bitsOffsets0 = new UnsafeList(128, allocator); + var offsets0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets1 = new UnsafeList(128, allocator); - var bitsOffsets1 = new UnsafeList(128, allocator); + var offsets1 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets1 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices1 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets2 = new UnsafeList(128, allocator); - var bitsOffsets2 = new UnsafeList(128, allocator); + var offsets2 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets2 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices2 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets3 = new UnsafeList(128, allocator); - var bitsOffsets3 = new UnsafeList(128, allocator); + var offsets3 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets3 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices3 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); // Iterate the Query's matching archetypes foreach (var archID in _matchingArchetypes) @@ -1184,21 +1624,26 @@ public unsafe partial struct EntityQuery { ref var chunkRef = ref arch.GetChunkReference(i); - chunkList.Add((IntPtr)chunkRef.GetUnsafePtr()); + chunks.Add((IntPtr)chunkRef.GetUnsafePtr()); + chunkVersions.Add((IntPtr)chunkRef.GetVersionUnsafePtr()); chunkEntityCounts.Add(chunkRef._count); entityOffsets.Add(arch.EntityIDsOffset); offsets0.Add(layout0.offset); bitsOffsets0.Add(layout0.enableBitsOffset); + versionIndices0.Add(layout0.versionIndex); offsets1.Add(layout1.offset); bitsOffsets1.Add(layout1.enableBitsOffset); + versionIndices1.Add(layout1.versionIndex); offsets2.Add(layout2.offset); bitsOffsets2.Add(layout2.enableBitsOffset); + versionIndices2.Add(layout2.versionIndex); offsets3.Add(layout3.offset); bitsOffsets3.Add(layout3.enableBitsOffset); + versionIndices3.Add(layout3.versionIndex); } } @@ -1207,44 +1652,70 @@ public unsafe partial struct EntityQuery var runner = new JobEntityBatch { userJob = jobData, - chunks = chunkList, + chunks = chunks, + chunkVersions = chunkVersions, chunkCount = chunkEntityCounts, entityOffset = entityOffsets, offsets0 = offsets0, bitsOffsets0 = bitsOffsets0, + versionindices0 = versionIndices0, offsets1 = offsets1, bitsOffsets1 = bitsOffsets1, + versionindices1 = versionIndices1, offsets2 = offsets2, bitsOffsets2 = bitsOffsets2, + versionindices2 = versionIndices2, offsets3 = offsets3, bitsOffsets3 = bitsOffsets3, + versionindices3 = versionIndices3, + version = world.Version, }; - var jobHandle = world.JobScheduler.ScheduleParallel(ref runner, chunkList.Count, batchSize, dependency); + runner.componentIDs[0] = ComponentTypeID.value; + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i =0; i < 1; i++) + { + if (id == runner.componentIDs[i]) + { + runner.componentRW[i] = true; + break; + } + } + } + + var jobHandle = world.JobScheduler.ScheduleParallel(ref runner, chunks.Count, batchSize, dependency); // 3. Dispose the temp lists var disposeJob = new DisposeJobEntity4 { - chunkList = chunkList, + chunks = chunks, + chunkVersions = chunkVersions, chunkEntityCounts = chunkEntityCounts, entityOffsets = entityOffsets, offsets0 = offsets0, bitsOffsets0 = bitsOffsets0, + versionindices0 = versionIndices0, offsets1 = offsets1, bitsOffsets1 = bitsOffsets1, + versionindices1 = versionIndices1, offsets2 = offsets2, bitsOffsets2 = bitsOffsets2, + versionindices2 = versionIndices2, offsets3 = offsets3, bitsOffsets3 = bitsOffsets3, + versionindices3 = versionIndices3, }; @@ -1255,50 +1726,62 @@ public unsafe partial struct EntityQuery private struct DisposeJobEntity5 : IJob { - public UnsafeList chunkList; + public UnsafeList chunks; + public UnsafeList chunkVersions; public UnsafeList chunkEntityCounts; public UnsafeList entityOffsets; public UnsafeList offsets0; public UnsafeList bitsOffsets0; + public UnsafeList versionindices0; public UnsafeList offsets1; public UnsafeList bitsOffsets1; + public UnsafeList versionindices1; public UnsafeList offsets2; public UnsafeList bitsOffsets2; + public UnsafeList versionindices2; public UnsafeList offsets3; public UnsafeList bitsOffsets3; + public UnsafeList versionindices3; public UnsafeList offsets4; public UnsafeList bitsOffsets4; + public UnsafeList versionindices4; public void Execute(int threadIndex) { - chunkList.Dispose(); + chunks.Dispose(); + chunkVersions.Dispose(); chunkEntityCounts.Dispose(); entityOffsets.Dispose(); offsets0.Dispose(); bitsOffsets0.Dispose(); + versionindices0.Dispose(); offsets1.Dispose(); bitsOffsets1.Dispose(); + versionindices1.Dispose(); offsets2.Dispose(); bitsOffsets2.Dispose(); + versionindices2.Dispose(); offsets3.Dispose(); bitsOffsets3.Dispose(); + versionindices3.Dispose(); offsets4.Dispose(); bitsOffsets4.Dispose(); + versionindices4.Dispose(); } } - public JobHandle ScheduleEntityParallel(TJob jobData, Allocator allocator, int batchSize, JobHandle dependency) + public JobHandle ScheduleEntityParallel(TJob jobData, int batchSize, JobHandle dependency) where TJob : unmanaged, IJobEntity where T0 : unmanaged, IComponent where T1 : unmanaged, IComponent @@ -1309,24 +1792,30 @@ public unsafe partial struct EntityQuery var world = World.GetWorld(_worldID).GetValueOrThrow(); // 1. Flatten the World - var chunkList = new UnsafeList(128, allocator); - var chunkEntityCounts = new UnsafeList(128, allocator); - var entityOffsets = new UnsafeList(128, allocator); + var chunks = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var chunkVersions = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var chunkEntityCounts = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var entityOffsets = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets0 = new UnsafeList(128, allocator); - var bitsOffsets0 = new UnsafeList(128, allocator); + var offsets0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets1 = new UnsafeList(128, allocator); - var bitsOffsets1 = new UnsafeList(128, allocator); + var offsets1 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets1 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices1 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets2 = new UnsafeList(128, allocator); - var bitsOffsets2 = new UnsafeList(128, allocator); + var offsets2 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets2 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices2 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets3 = new UnsafeList(128, allocator); - var bitsOffsets3 = new UnsafeList(128, allocator); + var offsets3 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets3 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices3 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets4 = new UnsafeList(128, allocator); - var bitsOffsets4 = new UnsafeList(128, allocator); + var offsets4 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets4 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices4 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); // Iterate the Query's matching archetypes foreach (var archID in _matchingArchetypes) @@ -1355,24 +1844,30 @@ public unsafe partial struct EntityQuery { ref var chunkRef = ref arch.GetChunkReference(i); - chunkList.Add((IntPtr)chunkRef.GetUnsafePtr()); + chunks.Add((IntPtr)chunkRef.GetUnsafePtr()); + chunkVersions.Add((IntPtr)chunkRef.GetVersionUnsafePtr()); chunkEntityCounts.Add(chunkRef._count); entityOffsets.Add(arch.EntityIDsOffset); offsets0.Add(layout0.offset); bitsOffsets0.Add(layout0.enableBitsOffset); + versionIndices0.Add(layout0.versionIndex); offsets1.Add(layout1.offset); bitsOffsets1.Add(layout1.enableBitsOffset); + versionIndices1.Add(layout1.versionIndex); offsets2.Add(layout2.offset); bitsOffsets2.Add(layout2.enableBitsOffset); + versionIndices2.Add(layout2.versionIndex); offsets3.Add(layout3.offset); bitsOffsets3.Add(layout3.enableBitsOffset); + versionIndices3.Add(layout3.versionIndex); offsets4.Add(layout4.offset); bitsOffsets4.Add(layout4.enableBitsOffset); + versionIndices4.Add(layout4.versionIndex); } } @@ -1381,50 +1876,78 @@ public unsafe partial struct EntityQuery var runner = new JobEntityBatch { userJob = jobData, - chunks = chunkList, + chunks = chunks, + chunkVersions = chunkVersions, chunkCount = chunkEntityCounts, entityOffset = entityOffsets, offsets0 = offsets0, bitsOffsets0 = bitsOffsets0, + versionindices0 = versionIndices0, offsets1 = offsets1, bitsOffsets1 = bitsOffsets1, + versionindices1 = versionIndices1, offsets2 = offsets2, bitsOffsets2 = bitsOffsets2, + versionindices2 = versionIndices2, offsets3 = offsets3, bitsOffsets3 = bitsOffsets3, + versionindices3 = versionIndices3, offsets4 = offsets4, bitsOffsets4 = bitsOffsets4, + versionindices4 = versionIndices4, + version = world.Version, }; - var jobHandle = world.JobScheduler.ScheduleParallel(ref runner, chunkList.Count, batchSize, dependency); + runner.componentIDs[0] = ComponentTypeID.value; + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i =0; i < 1; i++) + { + if (id == runner.componentIDs[i]) + { + runner.componentRW[i] = true; + break; + } + } + } + + var jobHandle = world.JobScheduler.ScheduleParallel(ref runner, chunks.Count, batchSize, dependency); // 3. Dispose the temp lists var disposeJob = new DisposeJobEntity5 { - chunkList = chunkList, + chunks = chunks, + chunkVersions = chunkVersions, chunkEntityCounts = chunkEntityCounts, entityOffsets = entityOffsets, offsets0 = offsets0, bitsOffsets0 = bitsOffsets0, + versionindices0 = versionIndices0, offsets1 = offsets1, bitsOffsets1 = bitsOffsets1, + versionindices1 = versionIndices1, offsets2 = offsets2, bitsOffsets2 = bitsOffsets2, + versionindices2 = versionIndices2, offsets3 = offsets3, bitsOffsets3 = bitsOffsets3, + versionindices3 = versionIndices3, offsets4 = offsets4, bitsOffsets4 = bitsOffsets4, + versionindices4 = versionIndices4, }; @@ -1435,56 +1958,70 @@ public unsafe partial struct EntityQuery private struct DisposeJobEntity6 : IJob { - public UnsafeList chunkList; + public UnsafeList chunks; + public UnsafeList chunkVersions; public UnsafeList chunkEntityCounts; public UnsafeList entityOffsets; public UnsafeList offsets0; public UnsafeList bitsOffsets0; + public UnsafeList versionindices0; public UnsafeList offsets1; public UnsafeList bitsOffsets1; + public UnsafeList versionindices1; public UnsafeList offsets2; public UnsafeList bitsOffsets2; + public UnsafeList versionindices2; public UnsafeList offsets3; public UnsafeList bitsOffsets3; + public UnsafeList versionindices3; public UnsafeList offsets4; public UnsafeList bitsOffsets4; + public UnsafeList versionindices4; public UnsafeList offsets5; public UnsafeList bitsOffsets5; + public UnsafeList versionindices5; public void Execute(int threadIndex) { - chunkList.Dispose(); + chunks.Dispose(); + chunkVersions.Dispose(); chunkEntityCounts.Dispose(); entityOffsets.Dispose(); offsets0.Dispose(); bitsOffsets0.Dispose(); + versionindices0.Dispose(); offsets1.Dispose(); bitsOffsets1.Dispose(); + versionindices1.Dispose(); offsets2.Dispose(); bitsOffsets2.Dispose(); + versionindices2.Dispose(); offsets3.Dispose(); bitsOffsets3.Dispose(); + versionindices3.Dispose(); offsets4.Dispose(); bitsOffsets4.Dispose(); + versionindices4.Dispose(); offsets5.Dispose(); bitsOffsets5.Dispose(); + versionindices5.Dispose(); } } - public JobHandle ScheduleEntityParallel(TJob jobData, Allocator allocator, int batchSize, JobHandle dependency) + public JobHandle ScheduleEntityParallel(TJob jobData, int batchSize, JobHandle dependency) where TJob : unmanaged, IJobEntity where T0 : unmanaged, IComponent where T1 : unmanaged, IComponent @@ -1496,27 +2033,34 @@ public unsafe partial struct EntityQuery var world = World.GetWorld(_worldID).GetValueOrThrow(); // 1. Flatten the World - var chunkList = new UnsafeList(128, allocator); - var chunkEntityCounts = new UnsafeList(128, allocator); - var entityOffsets = new UnsafeList(128, allocator); + var chunks = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var chunkVersions = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var chunkEntityCounts = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var entityOffsets = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets0 = new UnsafeList(128, allocator); - var bitsOffsets0 = new UnsafeList(128, allocator); + var offsets0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets1 = new UnsafeList(128, allocator); - var bitsOffsets1 = new UnsafeList(128, allocator); + var offsets1 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets1 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices1 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets2 = new UnsafeList(128, allocator); - var bitsOffsets2 = new UnsafeList(128, allocator); + var offsets2 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets2 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices2 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets3 = new UnsafeList(128, allocator); - var bitsOffsets3 = new UnsafeList(128, allocator); + var offsets3 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets3 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices3 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets4 = new UnsafeList(128, allocator); - var bitsOffsets4 = new UnsafeList(128, allocator); + var offsets4 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets4 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices4 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets5 = new UnsafeList(128, allocator); - var bitsOffsets5 = new UnsafeList(128, allocator); + var offsets5 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets5 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices5 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); // Iterate the Query's matching archetypes foreach (var archID in _matchingArchetypes) @@ -1547,27 +2091,34 @@ public unsafe partial struct EntityQuery { ref var chunkRef = ref arch.GetChunkReference(i); - chunkList.Add((IntPtr)chunkRef.GetUnsafePtr()); + chunks.Add((IntPtr)chunkRef.GetUnsafePtr()); + chunkVersions.Add((IntPtr)chunkRef.GetVersionUnsafePtr()); chunkEntityCounts.Add(chunkRef._count); entityOffsets.Add(arch.EntityIDsOffset); offsets0.Add(layout0.offset); bitsOffsets0.Add(layout0.enableBitsOffset); + versionIndices0.Add(layout0.versionIndex); offsets1.Add(layout1.offset); bitsOffsets1.Add(layout1.enableBitsOffset); + versionIndices1.Add(layout1.versionIndex); offsets2.Add(layout2.offset); bitsOffsets2.Add(layout2.enableBitsOffset); + versionIndices2.Add(layout2.versionIndex); offsets3.Add(layout3.offset); bitsOffsets3.Add(layout3.enableBitsOffset); + versionIndices3.Add(layout3.versionIndex); offsets4.Add(layout4.offset); bitsOffsets4.Add(layout4.enableBitsOffset); + versionIndices4.Add(layout4.versionIndex); offsets5.Add(layout5.offset); bitsOffsets5.Add(layout5.enableBitsOffset); + versionIndices5.Add(layout5.versionIndex); } } @@ -1576,56 +2127,86 @@ public unsafe partial struct EntityQuery var runner = new JobEntityBatch { userJob = jobData, - chunks = chunkList, + chunks = chunks, + chunkVersions = chunkVersions, chunkCount = chunkEntityCounts, entityOffset = entityOffsets, offsets0 = offsets0, bitsOffsets0 = bitsOffsets0, + versionindices0 = versionIndices0, offsets1 = offsets1, bitsOffsets1 = bitsOffsets1, + versionindices1 = versionIndices1, offsets2 = offsets2, bitsOffsets2 = bitsOffsets2, + versionindices2 = versionIndices2, offsets3 = offsets3, bitsOffsets3 = bitsOffsets3, + versionindices3 = versionIndices3, offsets4 = offsets4, bitsOffsets4 = bitsOffsets4, + versionindices4 = versionIndices4, offsets5 = offsets5, bitsOffsets5 = bitsOffsets5, + versionindices5 = versionIndices5, + version = world.Version, }; - var jobHandle = world.JobScheduler.ScheduleParallel(ref runner, chunkList.Count, batchSize, dependency); + runner.componentIDs[0] = ComponentTypeID.value; + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i =0; i < 1; i++) + { + if (id == runner.componentIDs[i]) + { + runner.componentRW[i] = true; + break; + } + } + } + + var jobHandle = world.JobScheduler.ScheduleParallel(ref runner, chunks.Count, batchSize, dependency); // 3. Dispose the temp lists var disposeJob = new DisposeJobEntity6 { - chunkList = chunkList, + chunks = chunks, + chunkVersions = chunkVersions, chunkEntityCounts = chunkEntityCounts, entityOffsets = entityOffsets, offsets0 = offsets0, bitsOffsets0 = bitsOffsets0, + versionindices0 = versionIndices0, offsets1 = offsets1, bitsOffsets1 = bitsOffsets1, + versionindices1 = versionIndices1, offsets2 = offsets2, bitsOffsets2 = bitsOffsets2, + versionindices2 = versionIndices2, offsets3 = offsets3, bitsOffsets3 = bitsOffsets3, + versionindices3 = versionIndices3, offsets4 = offsets4, bitsOffsets4 = bitsOffsets4, + versionindices4 = versionIndices4, offsets5 = offsets5, bitsOffsets5 = bitsOffsets5, + versionindices5 = versionIndices5, }; @@ -1636,62 +2217,78 @@ public unsafe partial struct EntityQuery private struct DisposeJobEntity7 : IJob { - public UnsafeList chunkList; + public UnsafeList chunks; + public UnsafeList chunkVersions; public UnsafeList chunkEntityCounts; public UnsafeList entityOffsets; public UnsafeList offsets0; public UnsafeList bitsOffsets0; + public UnsafeList versionindices0; public UnsafeList offsets1; public UnsafeList bitsOffsets1; + public UnsafeList versionindices1; public UnsafeList offsets2; public UnsafeList bitsOffsets2; + public UnsafeList versionindices2; public UnsafeList offsets3; public UnsafeList bitsOffsets3; + public UnsafeList versionindices3; public UnsafeList offsets4; public UnsafeList bitsOffsets4; + public UnsafeList versionindices4; public UnsafeList offsets5; public UnsafeList bitsOffsets5; + public UnsafeList versionindices5; public UnsafeList offsets6; public UnsafeList bitsOffsets6; + public UnsafeList versionindices6; public void Execute(int threadIndex) { - chunkList.Dispose(); + chunks.Dispose(); + chunkVersions.Dispose(); chunkEntityCounts.Dispose(); entityOffsets.Dispose(); offsets0.Dispose(); bitsOffsets0.Dispose(); + versionindices0.Dispose(); offsets1.Dispose(); bitsOffsets1.Dispose(); + versionindices1.Dispose(); offsets2.Dispose(); bitsOffsets2.Dispose(); + versionindices2.Dispose(); offsets3.Dispose(); bitsOffsets3.Dispose(); + versionindices3.Dispose(); offsets4.Dispose(); bitsOffsets4.Dispose(); + versionindices4.Dispose(); offsets5.Dispose(); bitsOffsets5.Dispose(); + versionindices5.Dispose(); offsets6.Dispose(); bitsOffsets6.Dispose(); + versionindices6.Dispose(); } } - public JobHandle ScheduleEntityParallel(TJob jobData, Allocator allocator, int batchSize, JobHandle dependency) + public JobHandle ScheduleEntityParallel(TJob jobData, int batchSize, JobHandle dependency) where TJob : unmanaged, IJobEntity where T0 : unmanaged, IComponent where T1 : unmanaged, IComponent @@ -1704,30 +2301,38 @@ public unsafe partial struct EntityQuery var world = World.GetWorld(_worldID).GetValueOrThrow(); // 1. Flatten the World - var chunkList = new UnsafeList(128, allocator); - var chunkEntityCounts = new UnsafeList(128, allocator); - var entityOffsets = new UnsafeList(128, allocator); + var chunks = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var chunkVersions = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var chunkEntityCounts = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var entityOffsets = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets0 = new UnsafeList(128, allocator); - var bitsOffsets0 = new UnsafeList(128, allocator); + var offsets0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets1 = new UnsafeList(128, allocator); - var bitsOffsets1 = new UnsafeList(128, allocator); + var offsets1 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets1 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices1 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets2 = new UnsafeList(128, allocator); - var bitsOffsets2 = new UnsafeList(128, allocator); + var offsets2 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets2 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices2 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets3 = new UnsafeList(128, allocator); - var bitsOffsets3 = new UnsafeList(128, allocator); + var offsets3 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets3 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices3 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets4 = new UnsafeList(128, allocator); - var bitsOffsets4 = new UnsafeList(128, allocator); + var offsets4 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets4 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices4 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets5 = new UnsafeList(128, allocator); - var bitsOffsets5 = new UnsafeList(128, allocator); + var offsets5 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets5 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices5 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets6 = new UnsafeList(128, allocator); - var bitsOffsets6 = new UnsafeList(128, allocator); + var offsets6 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets6 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices6 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); // Iterate the Query's matching archetypes foreach (var archID in _matchingArchetypes) @@ -1760,30 +2365,38 @@ public unsafe partial struct EntityQuery { ref var chunkRef = ref arch.GetChunkReference(i); - chunkList.Add((IntPtr)chunkRef.GetUnsafePtr()); + chunks.Add((IntPtr)chunkRef.GetUnsafePtr()); + chunkVersions.Add((IntPtr)chunkRef.GetVersionUnsafePtr()); chunkEntityCounts.Add(chunkRef._count); entityOffsets.Add(arch.EntityIDsOffset); offsets0.Add(layout0.offset); bitsOffsets0.Add(layout0.enableBitsOffset); + versionIndices0.Add(layout0.versionIndex); offsets1.Add(layout1.offset); bitsOffsets1.Add(layout1.enableBitsOffset); + versionIndices1.Add(layout1.versionIndex); offsets2.Add(layout2.offset); bitsOffsets2.Add(layout2.enableBitsOffset); + versionIndices2.Add(layout2.versionIndex); offsets3.Add(layout3.offset); bitsOffsets3.Add(layout3.enableBitsOffset); + versionIndices3.Add(layout3.versionIndex); offsets4.Add(layout4.offset); bitsOffsets4.Add(layout4.enableBitsOffset); + versionIndices4.Add(layout4.versionIndex); offsets5.Add(layout5.offset); bitsOffsets5.Add(layout5.enableBitsOffset); + versionIndices5.Add(layout5.versionIndex); offsets6.Add(layout6.offset); bitsOffsets6.Add(layout6.enableBitsOffset); + versionIndices6.Add(layout6.versionIndex); } } @@ -1792,62 +2405,94 @@ public unsafe partial struct EntityQuery var runner = new JobEntityBatch { userJob = jobData, - chunks = chunkList, + chunks = chunks, + chunkVersions = chunkVersions, chunkCount = chunkEntityCounts, entityOffset = entityOffsets, offsets0 = offsets0, bitsOffsets0 = bitsOffsets0, + versionindices0 = versionIndices0, offsets1 = offsets1, bitsOffsets1 = bitsOffsets1, + versionindices1 = versionIndices1, offsets2 = offsets2, bitsOffsets2 = bitsOffsets2, + versionindices2 = versionIndices2, offsets3 = offsets3, bitsOffsets3 = bitsOffsets3, + versionindices3 = versionIndices3, offsets4 = offsets4, bitsOffsets4 = bitsOffsets4, + versionindices4 = versionIndices4, offsets5 = offsets5, bitsOffsets5 = bitsOffsets5, + versionindices5 = versionIndices5, offsets6 = offsets6, bitsOffsets6 = bitsOffsets6, + versionindices6 = versionIndices6, + version = world.Version, }; - var jobHandle = world.JobScheduler.ScheduleParallel(ref runner, chunkList.Count, batchSize, dependency); + runner.componentIDs[0] = ComponentTypeID.value; + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i =0; i < 1; i++) + { + if (id == runner.componentIDs[i]) + { + runner.componentRW[i] = true; + break; + } + } + } + + var jobHandle = world.JobScheduler.ScheduleParallel(ref runner, chunks.Count, batchSize, dependency); // 3. Dispose the temp lists var disposeJob = new DisposeJobEntity7 { - chunkList = chunkList, + chunks = chunks, + chunkVersions = chunkVersions, chunkEntityCounts = chunkEntityCounts, entityOffsets = entityOffsets, offsets0 = offsets0, bitsOffsets0 = bitsOffsets0, + versionindices0 = versionIndices0, offsets1 = offsets1, bitsOffsets1 = bitsOffsets1, + versionindices1 = versionIndices1, offsets2 = offsets2, bitsOffsets2 = bitsOffsets2, + versionindices2 = versionIndices2, offsets3 = offsets3, bitsOffsets3 = bitsOffsets3, + versionindices3 = versionIndices3, offsets4 = offsets4, bitsOffsets4 = bitsOffsets4, + versionindices4 = versionIndices4, offsets5 = offsets5, bitsOffsets5 = bitsOffsets5, + versionindices5 = versionIndices5, offsets6 = offsets6, bitsOffsets6 = bitsOffsets6, + versionindices6 = versionIndices6, }; @@ -1858,68 +2503,86 @@ public unsafe partial struct EntityQuery private struct DisposeJobEntity8 : IJob { - public UnsafeList chunkList; + public UnsafeList chunks; + public UnsafeList chunkVersions; public UnsafeList chunkEntityCounts; public UnsafeList entityOffsets; public UnsafeList offsets0; public UnsafeList bitsOffsets0; + public UnsafeList versionindices0; public UnsafeList offsets1; public UnsafeList bitsOffsets1; + public UnsafeList versionindices1; public UnsafeList offsets2; public UnsafeList bitsOffsets2; + public UnsafeList versionindices2; public UnsafeList offsets3; public UnsafeList bitsOffsets3; + public UnsafeList versionindices3; public UnsafeList offsets4; public UnsafeList bitsOffsets4; + public UnsafeList versionindices4; public UnsafeList offsets5; public UnsafeList bitsOffsets5; + public UnsafeList versionindices5; public UnsafeList offsets6; public UnsafeList bitsOffsets6; + public UnsafeList versionindices6; public UnsafeList offsets7; public UnsafeList bitsOffsets7; + public UnsafeList versionindices7; public void Execute(int threadIndex) { - chunkList.Dispose(); + chunks.Dispose(); + chunkVersions.Dispose(); chunkEntityCounts.Dispose(); entityOffsets.Dispose(); offsets0.Dispose(); bitsOffsets0.Dispose(); + versionindices0.Dispose(); offsets1.Dispose(); bitsOffsets1.Dispose(); + versionindices1.Dispose(); offsets2.Dispose(); bitsOffsets2.Dispose(); + versionindices2.Dispose(); offsets3.Dispose(); bitsOffsets3.Dispose(); + versionindices3.Dispose(); offsets4.Dispose(); bitsOffsets4.Dispose(); + versionindices4.Dispose(); offsets5.Dispose(); bitsOffsets5.Dispose(); + versionindices5.Dispose(); offsets6.Dispose(); bitsOffsets6.Dispose(); + versionindices6.Dispose(); offsets7.Dispose(); bitsOffsets7.Dispose(); + versionindices7.Dispose(); } } - public JobHandle ScheduleEntityParallel(TJob jobData, Allocator allocator, int batchSize, JobHandle dependency) + public JobHandle ScheduleEntityParallel(TJob jobData, int batchSize, JobHandle dependency) where TJob : unmanaged, IJobEntity where T0 : unmanaged, IComponent where T1 : unmanaged, IComponent @@ -1933,33 +2596,42 @@ public unsafe partial struct EntityQuery var world = World.GetWorld(_worldID).GetValueOrThrow(); // 1. Flatten the World - var chunkList = new UnsafeList(128, allocator); - var chunkEntityCounts = new UnsafeList(128, allocator); - var entityOffsets = new UnsafeList(128, allocator); + var chunks = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var chunkVersions = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var chunkEntityCounts = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var entityOffsets = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets0 = new UnsafeList(128, allocator); - var bitsOffsets0 = new UnsafeList(128, allocator); + var offsets0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices0 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets1 = new UnsafeList(128, allocator); - var bitsOffsets1 = new UnsafeList(128, allocator); + var offsets1 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets1 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices1 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets2 = new UnsafeList(128, allocator); - var bitsOffsets2 = new UnsafeList(128, allocator); + var offsets2 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets2 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices2 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets3 = new UnsafeList(128, allocator); - var bitsOffsets3 = new UnsafeList(128, allocator); + var offsets3 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets3 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices3 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets4 = new UnsafeList(128, allocator); - var bitsOffsets4 = new UnsafeList(128, allocator); + var offsets4 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets4 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices4 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets5 = new UnsafeList(128, allocator); - var bitsOffsets5 = new UnsafeList(128, allocator); + var offsets5 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets5 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices5 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets6 = new UnsafeList(128, allocator); - var bitsOffsets6 = new UnsafeList(128, allocator); + var offsets6 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets6 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices6 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); - var offsets7 = new UnsafeList(128, allocator); - var bitsOffsets7 = new UnsafeList(128, allocator); + var offsets7 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets7 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices7 = new UnsafeList(128, JobScheduler.TempAllocatorHandle); // Iterate the Query's matching archetypes foreach (var archID in _matchingArchetypes) @@ -1994,33 +2666,42 @@ public unsafe partial struct EntityQuery { ref var chunkRef = ref arch.GetChunkReference(i); - chunkList.Add((IntPtr)chunkRef.GetUnsafePtr()); + chunks.Add((IntPtr)chunkRef.GetUnsafePtr()); + chunkVersions.Add((IntPtr)chunkRef.GetVersionUnsafePtr()); chunkEntityCounts.Add(chunkRef._count); entityOffsets.Add(arch.EntityIDsOffset); offsets0.Add(layout0.offset); bitsOffsets0.Add(layout0.enableBitsOffset); + versionIndices0.Add(layout0.versionIndex); offsets1.Add(layout1.offset); bitsOffsets1.Add(layout1.enableBitsOffset); + versionIndices1.Add(layout1.versionIndex); offsets2.Add(layout2.offset); bitsOffsets2.Add(layout2.enableBitsOffset); + versionIndices2.Add(layout2.versionIndex); offsets3.Add(layout3.offset); bitsOffsets3.Add(layout3.enableBitsOffset); + versionIndices3.Add(layout3.versionIndex); offsets4.Add(layout4.offset); bitsOffsets4.Add(layout4.enableBitsOffset); + versionIndices4.Add(layout4.versionIndex); offsets5.Add(layout5.offset); bitsOffsets5.Add(layout5.enableBitsOffset); + versionIndices5.Add(layout5.versionIndex); offsets6.Add(layout6.offset); bitsOffsets6.Add(layout6.enableBitsOffset); + versionIndices6.Add(layout6.versionIndex); offsets7.Add(layout7.offset); bitsOffsets7.Add(layout7.enableBitsOffset); + versionIndices7.Add(layout7.versionIndex); } } @@ -2029,68 +2710,102 @@ public unsafe partial struct EntityQuery var runner = new JobEntityBatch { userJob = jobData, - chunks = chunkList, + chunks = chunks, + chunkVersions = chunkVersions, chunkCount = chunkEntityCounts, entityOffset = entityOffsets, offsets0 = offsets0, bitsOffsets0 = bitsOffsets0, + versionindices0 = versionIndices0, offsets1 = offsets1, bitsOffsets1 = bitsOffsets1, + versionindices1 = versionIndices1, offsets2 = offsets2, bitsOffsets2 = bitsOffsets2, + versionindices2 = versionIndices2, offsets3 = offsets3, bitsOffsets3 = bitsOffsets3, + versionindices3 = versionIndices3, offsets4 = offsets4, bitsOffsets4 = bitsOffsets4, + versionindices4 = versionIndices4, offsets5 = offsets5, bitsOffsets5 = bitsOffsets5, + versionindices5 = versionIndices5, offsets6 = offsets6, bitsOffsets6 = bitsOffsets6, + versionindices6 = versionIndices6, offsets7 = offsets7, bitsOffsets7 = bitsOffsets7, + versionindices7 = versionIndices7, + version = world.Version, }; - var jobHandle = world.JobScheduler.ScheduleParallel(ref runner, chunkList.Count, batchSize, dependency); + runner.componentIDs[0] = ComponentTypeID.value; + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i =0; i < 1; i++) + { + if (id == runner.componentIDs[i]) + { + runner.componentRW[i] = true; + break; + } + } + } + + var jobHandle = world.JobScheduler.ScheduleParallel(ref runner, chunks.Count, batchSize, dependency); // 3. Dispose the temp lists var disposeJob = new DisposeJobEntity8 { - chunkList = chunkList, + chunks = chunks, + chunkVersions = chunkVersions, chunkEntityCounts = chunkEntityCounts, entityOffsets = entityOffsets, offsets0 = offsets0, bitsOffsets0 = bitsOffsets0, + versionindices0 = versionIndices0, offsets1 = offsets1, bitsOffsets1 = bitsOffsets1, + versionindices1 = versionIndices1, offsets2 = offsets2, bitsOffsets2 = bitsOffsets2, + versionindices2 = versionIndices2, offsets3 = offsets3, bitsOffsets3 = bitsOffsets3, + versionindices3 = versionIndices3, offsets4 = offsets4, bitsOffsets4 = bitsOffsets4, + versionindices4 = versionIndices4, offsets5 = offsets5, bitsOffsets5 = bitsOffsets5, + versionindices5 = versionIndices5, offsets6 = offsets6, bitsOffsets6 = bitsOffsets6, + versionindices6 = versionIndices6, offsets7 = offsets7, bitsOffsets7 = bitsOffsets7, + versionindices7 = versionIndices7, }; diff --git a/Ghost.Entities/Templates/EntityQuery.JobEntity.tt b/Ghost.Entities/Templates/EntityQuery.JobEntity.tt index 88070b9..a443e6e 100644 --- a/Ghost.Entities/Templates/EntityQuery.JobEntity.tt +++ b/Ghost.Entities/Templates/EntityQuery.JobEntity.tt @@ -6,7 +6,6 @@ <#@ include file="Helpers.ttinclude" #> using Ghost.Core; using Misaki.HighPerformance.Jobs; -using Misaki.HighPerformance.LowLevel.Buffer; using Misaki.HighPerformance.LowLevel.Collections; namespace Ghost.Entities; @@ -26,26 +25,35 @@ internal unsafe struct JobEntityBatch> : IJobParallelFor where TJob : unmanaged, IJobEntity<<#= generics #>> <#= restrictions #> { + public fixed int componentIDs[<#= i #>]; + public fixed bool componentRW[<#= i #>]; + public TJob userJob; public UnsafeList chunks; + public UnsafeList chunkVersions; public UnsafeList chunkCount; public UnsafeList entityOffset; <# for (var j = 0; j < i; j++){ #> public UnsafeList offsets<#= j #>; public UnsafeList bitsOffsets<#= j #>; + public UnsafeList versionindices<#= j #>; <# } #> + public int version; + public void Execute(int loopIndex, int threadIndex) { // 1. Get the specific pChunk for this thread var pChunk = (byte*)chunks[loopIndex]; + var pVersions = (int*)chunkVersions[loopIndex]; var count = chunkCount[loopIndex]; <# for (var j = 0; j < i; j++){ #> var off<#= j #> = offsets<#= j #>[loopIndex]; var enableOff<#= j #> = bitsOffsets<#= j #>[loopIndex]; + var versionIndex<#= j #> = versionindices<#= j #>[loopIndex]; <# } #> var pEntity = (Entity*)(pChunk + entityOffset[loopIndex]); @@ -53,6 +61,15 @@ internal unsafe struct JobEntityBatch> : IJobParallelFor var ptr<#= j #> = (<#= "T" + j #>*)(pChunk + off<#= j #>); <# } #> + // 2. Update versions for RW components +<# for (var j = 0; j < i; j++){ #> + if (componentRW[<#= j #>]) + { + pVersions[versionIndex<#= j #>] = version; + } + +<# } #> + // 3. Iterate all entities in this chunk for (var i = 0; i < count; i++) { <# for (var j = 0; j < i; j++){ #> @@ -77,43 +94,49 @@ public unsafe partial struct EntityQuery #> private struct DisposeJobEntity<#= i #> : IJob { - public UnsafeList chunkList; + public UnsafeList chunks; + public UnsafeList chunkVersions; public UnsafeList chunkEntityCounts; public UnsafeList entityOffsets; <# for (var j = 0; j < i; j++){ #> public UnsafeList offsets<#= j #>; public UnsafeList bitsOffsets<#= j #>; + public UnsafeList versionindices<#= j #>; <# } #> public void Execute(int threadIndex) { - chunkList.Dispose(); + chunks.Dispose(); + chunkVersions.Dispose(); chunkEntityCounts.Dispose(); entityOffsets.Dispose(); <# for (var j = 0; j < i; j++){ #> offsets<#= j #>.Dispose(); bitsOffsets<#= j #>.Dispose(); + versionindices<#= j #>.Dispose(); <# } #> } } - public JobHandle ScheduleEntityParallel>(TJob jobData, Allocator allocator, int batchSize, JobHandle dependency) + public JobHandle ScheduleEntityParallel>(TJob jobData, int batchSize, JobHandle dependency) where TJob : unmanaged, IJobEntity<<#= generics #>> <#= restrictions #> { var world = World.GetWorld(_worldID).GetValueOrThrow(); // 1. Flatten the World - var chunkList = new UnsafeList(128, allocator); - var chunkEntityCounts = new UnsafeList(128, allocator); - var entityOffsets = new UnsafeList(128, allocator); + var chunks = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var chunkVersions = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var chunkEntityCounts = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var entityOffsets = new UnsafeList(128, JobScheduler.TempAllocatorHandle); <# for (var j = 0; j < i; j++){ #> - var offsets<#= j #> = new UnsafeList(128, allocator); - var bitsOffsets<#= j #> = new UnsafeList(128, allocator); + var offsets<#= j #> = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var bitsOffsets<#= j #> = new UnsafeList(128, JobScheduler.TempAllocatorHandle); + var versionIndices<#= j #> = new UnsafeList(128, JobScheduler.TempAllocatorHandle); <# } #> // Iterate the Query's matching archetypes @@ -137,13 +160,15 @@ public unsafe partial struct EntityQuery { ref var chunkRef = ref arch.GetChunkReference(i); - chunkList.Add((IntPtr)chunkRef.GetUnsafePtr()); + chunks.Add((IntPtr)chunkRef.GetUnsafePtr()); + chunkVersions.Add((IntPtr)chunkRef.GetVersionUnsafePtr()); chunkEntityCounts.Add(chunkRef._count); entityOffsets.Add(arch.EntityIDsOffset); <# for (var j = 0; j < i; j++){ #> offsets<#= j #>.Add(layout<#= j #>.offset); bitsOffsets<#= j #>.Add(layout<#= j #>.enableBitsOffset); + versionIndices<#= j #>.Add(layout<#= j #>.versionIndex); <# } #> } @@ -153,29 +178,49 @@ public unsafe partial struct EntityQuery var runner = new JobEntityBatch> { userJob = jobData, - chunks = chunkList, + chunks = chunks, + chunkVersions = chunkVersions, chunkCount = chunkEntityCounts, entityOffset = entityOffsets, <# for (var j = 0; j < i; j++){ #> offsets<#= j #> = offsets<#= j #>, bitsOffsets<#= j #> = bitsOffsets<#= j #>, + versionindices<#= j #> = versionIndices<#= j #>, <# } #> + version = world.Version, }; - var jobHandle = world.JobScheduler.ScheduleParallel(ref runner, chunkList.Count, batchSize, dependency); + runner.componentIDs[0] = ComponentTypeID.value; + + var it = _mask.writeAccess.GetIterator(); + while (it.Next(out var id)) + { + for (var i =0; i < 1; i++) + { + if (id == runner.componentIDs[i]) + { + runner.componentRW[i] = true; + break; + } + } + } + + var jobHandle = world.JobScheduler.ScheduleParallel(ref runner, chunks.Count, batchSize, dependency); // 3. Dispose the temp lists var disposeJob = new DisposeJobEntity<#= i #> { - chunkList = chunkList, + chunks = chunks, + chunkVersions = chunkVersions, chunkEntityCounts = chunkEntityCounts, entityOffsets = entityOffsets, <# for (var j = 0; j < i; j++){ #> offsets<#= j #> = offsets<#= j #>, bitsOffsets<#= j #> = bitsOffsets<#= j #>, + versionindices<#= j #> = versionIndices<#= j #>, <# } #> }; diff --git a/Ghost.Entities/World.cs b/Ghost.Entities/World.cs index 5e9166e..94704c5 100644 --- a/Ghost.Entities/World.cs +++ b/Ghost.Entities/World.cs @@ -50,7 +50,17 @@ public partial class World [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static World GetWorldUncheck(Identifier id) { +#if DEBUG || GHOST_EDITOR + if (id.value < 0 || id.value >= s_worlds.Count) + { + throw new ArgumentOutOfRangeException(nameof(id), "World ID is out of range."); + } + + var world = s_worlds[id.value]; + return world is null ? throw new InvalidOperationException("World not found.") : world; +#else return s_worlds[id.value]!; +#endif } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -62,12 +72,7 @@ public partial class World } var world = s_worlds[id.value]; - if (world is null) - { - return ErrorStatus.NotFound; - } - - return world; + return world is null ? ErrorStatus.NotFound : world; } } @@ -80,6 +85,8 @@ public partial class World : IIdentifierType, IDisposable, IEquatable private readonly EntityCommandBuffer _entityCommandBuffer; private readonly EntityCommandBuffer[] _threadLocalECBs; + private readonly SystemManager _systemManager; + private UnsafeList _archetypes; private UnsafeList _entityQueries; @@ -106,6 +113,11 @@ public partial class World : IIdentifierType, IDisposable, IEquatable /// public EntityManager EntityManager => _entityManager; + /// + /// Gets the system manager for this world. + /// + public SystemManager SystemManager => _systemManager; + /// /// Gets the current version number of the world. /// @@ -124,16 +136,18 @@ public partial class World : IIdentifierType, IDisposable, IEquatable _id = id; _jobScheduler = jobScheduler; + _entityManager = new EntityManager(this, entityCapacity); + _entityCommandBuffer = new EntityCommandBuffer(_entityManager); + _threadLocalECBs = new EntityCommandBuffer[jobScheduler.WorkerCount]; + + _systemManager = new SystemManager(this); + _archetypes = new UnsafeList(16, Allocator.Persistent); _entityQueries = new UnsafeList(16, Allocator.Persistent); _archetypeLookup = new UnsafeHashMap>(16, Allocator.Persistent); _querieLookup = new UnsafeHashMap>(16, Allocator.Persistent); - _entityManager = new EntityManager(this, entityCapacity); - _entityCommandBuffer = new EntityCommandBuffer(_entityManager); - _threadLocalECBs = new EntityCommandBuffer[jobScheduler.WorkerCount]; - for (var i = 0; i < jobScheduler.WorkerCount; i++) { _threadLocalECBs[i] = new EntityCommandBuffer(_entityManager);