Improve ecs query performance;

This commit is contained in:
2025-10-12 19:49:05 +09:00
parent 682200cbf1
commit 6d1b510ac1
27 changed files with 1546 additions and 992 deletions

View File

@@ -64,7 +64,8 @@ internal class ComponentPool<T> : IComponentPool<T>
_lookup.AsSpan().Fill(Entity.INVALID_ID);
}
public ComponentPool() : this(16)
public ComponentPool()
: this(16)
{
}
@@ -217,12 +218,19 @@ internal class ScriptComponentPool : IComponentPool<ScriptComponent>
private Dictionary<Entity, List<ScriptComponent>>? _scriptComponents;
private List<ScriptComponent>? _executionList;
private readonly World _world;
internal IReadOnlyDictionary<Entity, List<ScriptComponent>>? ScriptComponents => _scriptComponents;
internal IReadOnlyList<ScriptComponent>? ExecutionList => _executionList;
public bool IsInitialized => _scriptComponents != null;
public int Count => _scriptComponents?.Keys.Count ?? 0;
public ScriptComponentPool(World world)
{
_world = world;
}
internal void Initialize(int capacity = 16)
{
_scriptComponents ??= new(capacity);
@@ -263,14 +271,15 @@ internal class ScriptComponentPool : IComponentPool<ScriptComponent>
Initialize();
}
if (!_scriptComponents!.TryGetValue(entity, out var scriptList))
{
scriptList = new();
_scriptComponents[entity] = scriptList;
}
ref var scriptList = ref CollectionsMarshal.GetValueRefOrAddDefault(_scriptComponents!, entity, out var exists);
scriptList ??= new List<ScriptComponent>();
scriptList.Add(component);
component.Owner = entity;
component._world = _world;
component.Enable = true;
component.Initialize();
}
public bool Remove<T>(Entity entity)
@@ -472,22 +481,23 @@ internal struct ComponentStorage : IDisposable
private int _currentCapacity = 16;
private IComponentPool?[] _componentPools = new IComponentPool[16];
private UnsafeBitSet?[] _componentEntityMasks = new UnsafeBitSet?[16];
private UnsafeBitSet[] _componentEntityMasks = new UnsafeBitSet[16];
private readonly Dictionary<TypeHandle, int> _typeIDMap = new(16);
private readonly Dictionary<int, TypeHandle> _typeHandleMap = new(16);
private readonly ScriptComponentPool _scriptComponentPool = new();
private readonly ScriptComponentPool _scriptComponentPool;
private readonly World _world;
internal ComponentStorage(World world)
{
_world = world;
_scriptComponentPool = new ScriptComponentPool(world);
}
internal readonly IReadOnlyList<IComponentPool?> ComponentPools => _componentPools;
internal readonly IReadOnlyList<UnsafeBitSet?> ComponentEntityMasks => _componentEntityMasks;
internal readonly IReadOnlyList<UnsafeBitSet> ComponentEntityMasks => _componentEntityMasks;
internal readonly ScriptComponentPool ScriptComponentPool => _scriptComponentPool;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -641,29 +651,7 @@ internal struct ComponentStorage : IDisposable
return TryGetMask(TypeHandle.Get<T>(), out bitSet);
}
public UnsafeBitSet GetOrCreateMask<T>()
where T : unmanaged, IComponentData
{
var typeHandle = TypeHandle.Get<T>();
if (!_typeIDMap.TryGetValue(typeHandle, out var id))
{
id = GetTypeID<T>();
_typeIDMap[typeHandle] = id;
_typeHandleMap[id] = typeHandle;
}
if (id >= _currentCapacity)
{
Resize(_currentCapacity * 2);
}
ref var set = ref _componentEntityMasks[id];
set ??= new UnsafeBitSet();
return set.Value;
}
public UnsafeBitSet GetOrCreateMask(TypeHandle typeHandle)
public ref UnsafeBitSet GetOrCreateMask(TypeHandle typeHandle)
{
if (!_typeIDMap.TryGetValue(typeHandle, out var id))
{
@@ -678,14 +666,23 @@ internal struct ComponentStorage : IDisposable
}
ref var set = ref _componentEntityMasks[id];
set ??= new UnsafeBitSet();
if (!set.IsCreated)
{
set = new UnsafeBitSet();
}
return set.Value;
return ref set;
}
public UnsafeBitSet GetOrCreateMask(Type type)
public ref UnsafeBitSet GetOrCreateMask<T>()
where T : unmanaged, IComponentData
{
return GetOrCreateMask(TypeHandle.Get(type));
return ref GetOrCreateMask(TypeHandle.Get<T>());
}
public ref UnsafeBitSet GetOrCreateMask(Type type)
{
return ref GetOrCreateMask(TypeHandle.Get(type));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -710,7 +707,7 @@ internal struct ComponentStorage : IDisposable
foreach (var bitSet in _componentEntityMasks)
{
bitSet?.Dispose();
bitSet.Dispose();
}
_scriptComponentPool.Dispose();

View File

@@ -2,7 +2,9 @@
public abstract class ScriptComponent : IComponentData
{
private bool _enable = true;
private bool _enable;
internal World _world = null!;
/// <summary>
/// Gets or sets a value indicating whether this script component is enabled.
@@ -38,6 +40,11 @@ public abstract class ScriptComponent : IComponentData
internal set;
}
/// <summary>
/// Gets the EntityManager instance associated with the current world.
/// </summary>
protected EntityManager EntityManager => _world.EntityManager;
/// <summary>
/// Gets or sets the priority of the script component.
/// Change this during runtime does not affect the execution order.
@@ -58,6 +65,13 @@ public abstract class ScriptComponent : IComponentData
{
}
/// <summary>
/// Called when the script component is initialized.
/// </summary>
public virtual void Initialize()
{
}
/// <summary>
/// Called when the script component is started.
/// </summary>

View File

@@ -8,6 +8,11 @@
</PropertyGroup>
<ItemGroup>
<None Include="Template\ForEach.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>ForEach.tt</DependentUpon>
</None>
<None Include="Template\QueryItem.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
@@ -32,6 +37,10 @@
</ItemGroup>
<ItemGroup>
<None Update="Template\ForEach.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>ForEach.cs</LastGenOutput>
</None>
<None Update="Template\QueryEnumerable.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>QueryEnumerable.cs</LastGenOutput>
@@ -59,6 +68,11 @@
</ItemGroup>
<ItemGroup>
<Compile Update="Template\ForEach.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>ForEach.tt</DependentUpon>
</Compile>
<Compile Update="Template\Helpers.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>

View File

@@ -0,0 +1,42 @@
using Ghost.Core;
namespace Ghost.Entities.Query;
public struct QueryBuilder
{
private QueryFilter _filter;
public QueryBuilder()
{
_filter = new QueryFilter();
}
public QueryBuilder WithAll<T>()
{
_filter._all.Add(TypeHandle.Get<T>());
return this;
}
public QueryBuilder WithAny<T>()
{
_filter._any.Add(TypeHandle.Get<T>());
return this;
}
public QueryBuilder WithAbsent<T>()
{
_filter._absent.Add(TypeHandle.Get<T>());
return this;
}
public QueryBuilder WithDisabled<T>()
{
_filter._disabled.Add(TypeHandle.Get<T>());
return this;
}
public readonly QueryFilter Build()
{
return _filter;
}
}

View File

@@ -1,98 +1,98 @@
using Ghost.Core;
using Ghost.Entities.Components;
using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections;
using System.Runtime.CompilerServices;
namespace Ghost.Entities.Query;
[Flags]
internal enum FilterMode
public struct QueryFilter : IDisposable
{
All = 1 << 0,
Any = 1 << 1,
Absent = 1 << 2,
Disabled = 1 << 3,
}
private readonly Stack.Scope _scope;
internal readonly struct FilterEntry(TypeHandle id, FilterMode mode)
{
public readonly TypeHandle typeHandle = id;
public readonly FilterMode mode = mode;
}
internal UnsafeList<TypeHandle> _all;
internal UnsafeList<TypeHandle> _any;
internal UnsafeList<TypeHandle> _absent;
internal UnsafeList<TypeHandle> _disabled;
internal struct QueryFilter()
{
internal List<TypeHandle> _all = new(6);
internal List<TypeHandle> _any = new(6);
internal List<TypeHandle> _absent = new(6);
internal List<TypeHandle> _disabled = new(6);
public QueryFilter()
{
_scope = AllocationManager.CreateStackScope();
public readonly UnsafeBitSet ComputeFilterBitMask(World world)
_all = new UnsafeList<TypeHandle>(4, Allocator.Stack);
_any = new UnsafeList<TypeHandle>(4, Allocator.Stack);
_absent = new UnsafeList<TypeHandle>(4, Allocator.Stack);
_disabled = new UnsafeList<TypeHandle>(4, Allocator.Stack);
}
public readonly UnsafeBitSet ComputeFilterBitMask(World world, Allocator allocator)
{
UnsafeBitSet allMask = default;
UnsafeBitSet anyMask = default;
UnsafeBitSet absentMask = default;
using var scope = AllocationManager.CreateStackScope();
foreach (var typeHandle in _all)
{
var mask = world.ComponentStorage.GetOrCreateMask(typeHandle);
if (!allMask.IsCreated)
{
allMask = new UnsafeBitSet(mask.Length, Allocator.Stack, AllocationOption.Clear);
allMask.SetAll();
}
allMask.AndOperation(mask);
}
foreach (var typeHandle in _any)
{
var mask = world.ComponentStorage.GetOrCreateMask(typeHandle);
if (!anyMask.IsCreated)
{
anyMask = new UnsafeBitSet(mask.Length, Allocator.Stack, AllocationOption.Clear);
}
anyMask.OrOperation(mask);
}
foreach (var typeHandle in _absent)
{
var mask = world.ComponentStorage.GetOrCreateMask(typeHandle);
if (!absentMask.IsCreated)
{
absentMask = new UnsafeBitSet(mask.Length, Allocator.Stack, AllocationOption.Clear);
}
absentMask.OrOperation(mask);
}
var result = new UnsafeBitSet(world.EntityManager.EntityCount, Allocator.Persistent);
var result = new UnsafeBitSet(world.EntityManager.EntityCount, allocator);
result.SetAll();
if (allMask.IsCreated)
using (AllocationManager.CreateStackScope())
{
result.AndOperation(allMask);
allMask.Dispose();
}
foreach (var typeHandle in _all)
{
var mask = world.ComponentStorage.GetOrCreateMask(typeHandle);
if (anyMask.IsCreated)
{
result.AndOperation(anyMask);
anyMask.Dispose();
}
if (!allMask.IsCreated)
{
allMask = new UnsafeBitSet(mask.Length, Allocator.Stack, AllocationOption.None);
allMask.SetAll();
}
if (absentMask.IsCreated)
{
result.AndOperation(~absentMask);
absentMask.Dispose();
allMask.AndOperation(mask);
}
foreach (var typeHandle in _any)
{
var mask = world.ComponentStorage.GetOrCreateMask(typeHandle);
if (!anyMask.IsCreated)
{
anyMask = new UnsafeBitSet(mask.Length, Allocator.Stack);
}
anyMask.OrOperation(mask);
}
foreach (var typeHandle in _absent)
{
var mask = world.ComponentStorage.GetOrCreateMask(typeHandle);
if (!absentMask.IsCreated)
{
absentMask = new UnsafeBitSet(mask.Length, Allocator.Stack);
}
absentMask.OrOperation(mask);
}
if (allMask.IsCreated)
{
result.AndOperation(allMask);
}
if (anyMask.IsCreated)
{
result.AndOperation(anyMask);
}
if (absentMask.IsCreated)
{
result.AndOperation(~absentMask);
}
}
return result;
}
public readonly void Dispose()
{
_scope.Dispose();
}
}

View File

@@ -3,11 +3,12 @@ using System.Runtime.CompilerServices;
namespace Ghost.Entities.Query;
public interface IQueryTypeParameter
public interface IQueryTypeParameter<T>
where T : IComponentData
{
}
public ref struct CompRef<T> : IQueryTypeParameter
public ref struct CompRef<T> : IQueryTypeParameter<T>
where T : IComponentData
{
internal ref T _value;
@@ -42,7 +43,7 @@ public ref struct CompRef<T> : IQueryTypeParameter
}
}
public ref struct CompRO<T> : IQueryTypeParameter
public readonly ref struct CompRO<T> : IQueryTypeParameter<T>
where T : IComponentData
{
internal readonly ref T _value;

View File

@@ -0,0 +1,12 @@
namespace Ghost.Entities;
public delegate void ForEach<T0>(ref T0 t0Component);
public delegate void ForEach<T0, T1>(ref T0 t0Component,ref T1 t1Component);
public delegate void ForEach<T0, T1, T2>(ref T0 t0Component,ref T1 t1Component,ref T2 t2Component);
public delegate void ForEach<T0, T1, T2, T3>(ref T0 t0Component,ref T1 t1Component,ref T2 t2Component,ref T3 t3Component);
public delegate void ForEach<T0, T1, T2, T3, T4>(ref T0 t0Component,ref T1 t1Component,ref T2 t2Component,ref T3 t3Component,ref T4 t4Component);
public delegate void ForEach<T0, T1, T2, T3, T4, T5>(ref T0 t0Component,ref T1 t1Component,ref T2 t2Component,ref T3 t3Component,ref T4 t4Component,ref T5 t5Component);
public delegate void ForEach<T0, T1, T2, T3, T4, T5, T6>(ref T0 t0Component,ref T1 t1Component,ref T2 t2Component,ref T3 t3Component,ref T4 t4Component,ref T5 t5Component,ref T6 t6Component);
public delegate void ForEach<T0, T1, T2, T3, T4, T5, T6, T7>(ref T0 t0Component,ref T1 t1Component,ref T2 t2Component,ref T3 t3Component,ref T4 t4Component,ref T5 t5Component,ref T6 t6Component,ref T7 t7Component);

View File

@@ -0,0 +1,16 @@
<#@ template language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ include file="Helpers.ttinclude" #>
namespace Ghost.Entities;
<# for (var i = 1; i <= Amount; i++)
{
var generics = AppendGenerics(i);
var compGenerics = AppendGenericRefParameters(i);
#>
public delegate void ForEach<<#= generics #>>(<#= compGenerics #>);
<# } #>

File diff suppressed because it is too large Load Diff

View File

@@ -8,6 +8,7 @@
using Ghost.Core;
using Ghost.Entities.Components;
using Ghost.Entities.Query;
using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections;
namespace Ghost.Entities;
@@ -23,9 +24,11 @@ var constructorParams = Enumerable.Range(0, arity)
.Aggregate((a, b) => a + ", " + b);
#>
public struct QueryEnumerable<<#= generics #>>
public unsafe ref struct QueryEnumerable<<#= generics #>>
<#= restrictions #>
{
private QueryFilter _filter;
private readonly World _world;
<# for (int i = 0; i < arity; i++){ #>
@@ -33,11 +36,13 @@ public struct QueryEnumerable<<#= generics #>>
<# } #>
private readonly int _count;
private QueryFilter _filters;
internal readonly QueryFilter Filters => _filters;
internal QueryEnumerable(World world, <#= poolParams #>, int count)
{
_filter = new();
<# for (int i = 0; i < arity; i++) {#>
_filter._all.Add(TypeHandle.Get<T<#= i #>>());
<# } #>
_world = world;
<# for (int i = 0; i < arity; i++) { #>
@@ -45,39 +50,54 @@ public struct QueryEnumerable<<#= generics #>>
<# } #>
_count = count;
_filters = new();
<# for (int i = 0; i < arity; i++) {#>
_filters._all.Add(TypeHandle.Get<T<#= i #>>());
<# } #>
}
public readonly Enumerator GetEnumerator() => new (_world, <#= constructorParams #>, _count, _filters);
internal QueryEnumerable(World world, <#= poolParams #>, int count, ref readonly QueryFilter filter)
{
_filter = filter;
_world = world;
<# for (int i = 0; i < arity; i++) { #>
_pool<#= i #> = pool<#= i #>;
<# } #>
_count = count;
}
#pragma warning disable CS9084 // Struct member returns 'this' or other instance members by reference
public Enumerator GetEnumerator() => new(_world, <#= constructorParams #>, _count, ref _filter);
#pragma warning restore CS9084 // Struct member returns 'this' or other instance members by reference
public ref struct Enumerator
{
private readonly World _world;
private ref QueryFilter _filter;
private UnsafeBitSet _filterMask;
private readonly ReadOnlySpan<Entity> _entities;
private readonly Stack.Scope _stackScope;
<# for (int i = 0; i < arity; i++){ #>
private readonly ComponentPool<T<#= i #>> _pool<#= i #>;
<# } #>
private int _index;
private readonly int _count;
private int _count;
private UnsafeBitSet _filterMask;
public QueryItem<<#= generics #>> Current
{
get;
private set;
}
internal Enumerator(World world, <#= poolParams #>, int count, QueryFilter filters)
internal Enumerator(World world, <#= poolParams #>, int count, ref QueryFilter filter)
{
_world = world;
_entities = _world.EntityManager.Entities;
_stackScope = AllocationManager.CreateStackScope();
_filter = ref filter;
_filterMask = _filter.ComputeFilterBitMask(world, Allocator.Stack);
_entities = world.EntityManager.Entities;
<# for (int i = 0; i < arity; i++){ #>
_pool<#= i #> = pool<#= i #>;
@@ -85,7 +105,6 @@ public struct QueryEnumerable<<#= generics #>>
_count = count;
_index = -1;
_filterMask = filters.ComputeFilterBitMask(_world);
Current = default;
}
@@ -93,52 +112,60 @@ public struct QueryEnumerable<<#= generics #>>
public bool MoveNext()
{
_index = _filterMask.NextSetBit(_index + 1);
if (_index < 0 || _index >= _world.EntityManager.EntityCount)
if (_index < 0 || _count <= 0)
{
return false;
}
_count--;
Current = new QueryItem<<#= generics #>>(_entities[_index], <#= constructorParams #>);
return true;
}
public readonly void Dispose()
{
_stackScope.Dispose();
_filter.Dispose();
}
}
<# for (int i = 1; i <= ExtensionAmount; i++) {
var compGenerics = AppendGenerics(i, "TComponent");
var compRestrictions = AppendGenericRestrictions(i, "TComponent", "unmanaged, IComponentData");
#>
public readonly QueryEnumerable<<#= generics #>> WithAll<<#= compGenerics #>>()
public QueryEnumerable<<#= generics #>> WithAll<<#= compGenerics #>>()
<#= compRestrictions #>
{
<# for (int j = 0; j < i; j++) {#>
_filters._all.Add(TypeHandle.Get<TComponent<#= j #>>());
_filter._all.Add(TypeHandle.Get<TComponent<#= j #>>());
<# } #>
return this;
}
public readonly QueryEnumerable<<#= generics #>> WithAny<<#= compGenerics #>>()
public QueryEnumerable<<#= generics #>> WithAny<<#= compGenerics #>>()
<#= compRestrictions #>
{
<# for (int j = 0; j < i; j++) {#>
_filters._any.Add(TypeHandle.Get<TComponent<#= j #>>());
_filter._any.Add(TypeHandle.Get<TComponent<#= j #>>());
<# } #>
return this;
}
public readonly QueryEnumerable<<#= generics #>> WithAbsent<<#= compGenerics #>>()
public QueryEnumerable<<#= generics #>> WithAbsent<<#= compGenerics #>>()
<#= compRestrictions #>
{
<# for (int j = 0; j < i; j++) {#>
_filters._absent.Add(TypeHandle.Get<TComponent<#= j #>>());
_filter._absent.Add(TypeHandle.Get<TComponent<#= j #>>());
<# } #>
return this;
}
public readonly QueryEnumerable<<#= generics #>> WithDisabled<<#= compGenerics #>>()
public QueryEnumerable<<#= generics #>> WithDisabled<<#= compGenerics #>>()
<#= compRestrictions #>
{
<# for (int j = 0; j < i; j++) {#>
_filters._disabled.Add(TypeHandle.Get<TComponent<#= j #>>());
_filter._disabled.Add(TypeHandle.Get<TComponent<#= j #>>());
<# } #>
return this;
}

View File

@@ -26,7 +26,7 @@ public readonly struct QueryItem<T0>
{
entity = _entity;
c0 = new(ref _pool0.GetRef(_entity));
c0 = new (ref _pool0.GetRef(_entity));
}
}
@@ -54,8 +54,8 @@ public readonly struct QueryItem<T0, T1>
{
entity = _entity;
c0 = new(ref _pool0.GetRef(_entity));
c1 = new(ref _pool1.GetRef(_entity));
c0 = new (ref _pool0.GetRef(_entity));
c1 = new (ref _pool1.GetRef(_entity));
}
}
@@ -86,9 +86,9 @@ public readonly struct QueryItem<T0, T1, T2>
{
entity = _entity;
c0 = new(ref _pool0.GetRef(_entity));
c1 = new(ref _pool1.GetRef(_entity));
c2 = new(ref _pool2.GetRef(_entity));
c0 = new (ref _pool0.GetRef(_entity));
c1 = new (ref _pool1.GetRef(_entity));
c2 = new (ref _pool2.GetRef(_entity));
}
}
@@ -122,10 +122,10 @@ public readonly struct QueryItem<T0, T1, T2, T3>
{
entity = _entity;
c0 = new(ref _pool0.GetRef(_entity));
c1 = new(ref _pool1.GetRef(_entity));
c2 = new(ref _pool2.GetRef(_entity));
c3 = new(ref _pool3.GetRef(_entity));
c0 = new (ref _pool0.GetRef(_entity));
c1 = new (ref _pool1.GetRef(_entity));
c2 = new (ref _pool2.GetRef(_entity));
c3 = new (ref _pool3.GetRef(_entity));
}
}
@@ -162,11 +162,11 @@ public readonly struct QueryItem<T0, T1, T2, T3, T4>
{
entity = _entity;
c0 = new(ref _pool0.GetRef(_entity));
c1 = new(ref _pool1.GetRef(_entity));
c2 = new(ref _pool2.GetRef(_entity));
c3 = new(ref _pool3.GetRef(_entity));
c4 = new(ref _pool4.GetRef(_entity));
c0 = new (ref _pool0.GetRef(_entity));
c1 = new (ref _pool1.GetRef(_entity));
c2 = new (ref _pool2.GetRef(_entity));
c3 = new (ref _pool3.GetRef(_entity));
c4 = new (ref _pool4.GetRef(_entity));
}
}
@@ -206,12 +206,12 @@ public readonly struct QueryItem<T0, T1, T2, T3, T4, T5>
{
entity = _entity;
c0 = new(ref _pool0.GetRef(_entity));
c1 = new(ref _pool1.GetRef(_entity));
c2 = new(ref _pool2.GetRef(_entity));
c3 = new(ref _pool3.GetRef(_entity));
c4 = new(ref _pool4.GetRef(_entity));
c5 = new(ref _pool5.GetRef(_entity));
c0 = new (ref _pool0.GetRef(_entity));
c1 = new (ref _pool1.GetRef(_entity));
c2 = new (ref _pool2.GetRef(_entity));
c3 = new (ref _pool3.GetRef(_entity));
c4 = new (ref _pool4.GetRef(_entity));
c5 = new (ref _pool5.GetRef(_entity));
}
}
@@ -254,13 +254,13 @@ public readonly struct QueryItem<T0, T1, T2, T3, T4, T5, T6>
{
entity = _entity;
c0 = new(ref _pool0.GetRef(_entity));
c1 = new(ref _pool1.GetRef(_entity));
c2 = new(ref _pool2.GetRef(_entity));
c3 = new(ref _pool3.GetRef(_entity));
c4 = new(ref _pool4.GetRef(_entity));
c5 = new(ref _pool5.GetRef(_entity));
c6 = new(ref _pool6.GetRef(_entity));
c0 = new (ref _pool0.GetRef(_entity));
c1 = new (ref _pool1.GetRef(_entity));
c2 = new (ref _pool2.GetRef(_entity));
c3 = new (ref _pool3.GetRef(_entity));
c4 = new (ref _pool4.GetRef(_entity));
c5 = new (ref _pool5.GetRef(_entity));
c6 = new (ref _pool6.GetRef(_entity));
}
}
@@ -306,14 +306,14 @@ public readonly struct QueryItem<T0, T1, T2, T3, T4, T5, T6, T7>
{
entity = _entity;
c0 = new(ref _pool0.GetRef(_entity));
c1 = new(ref _pool1.GetRef(_entity));
c2 = new(ref _pool2.GetRef(_entity));
c3 = new(ref _pool3.GetRef(_entity));
c4 = new(ref _pool4.GetRef(_entity));
c5 = new(ref _pool5.GetRef(_entity));
c6 = new(ref _pool6.GetRef(_entity));
c7 = new(ref _pool7.GetRef(_entity));
c0 = new (ref _pool0.GetRef(_entity));
c1 = new (ref _pool1.GetRef(_entity));
c2 = new (ref _pool2.GetRef(_entity));
c3 = new (ref _pool3.GetRef(_entity));
c4 = new (ref _pool4.GetRef(_entity));
c5 = new (ref _pool5.GetRef(_entity));
c6 = new (ref _pool6.GetRef(_entity));
c7 = new (ref _pool7.GetRef(_entity));
}
}

View File

@@ -1,6 +1,7 @@
using Ghost.Entities.Components;
using Ghost.Entities.Query;
namespace Ghost.Entities;
@@ -10,7 +11,9 @@ public partial class World
where T0 : unmanaged, IComponentData
{
if (!(_componentStorage.TryGetPool<T0>(out var pool0)))
{
return default;
}
return new QueryEnumerable<T0>(
this,
@@ -18,11 +21,28 @@ public partial class World
pool0.Count);
}
public QueryEnumerable<T0> QueryFilter<T0>(ref readonly QueryFilter filter)
where T0 : unmanaged, IComponentData
{
if (!(_componentStorage.TryGetPool<T0>(out var pool0)))
{
return default;
}
return new QueryEnumerable<T0>(
this,
pool0,
pool0.Count,
in filter);
}
public QueryEnumerable<T0, T1> Query<T0, T1>()
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData
{
if (!(_componentStorage.TryGetPool<T0>(out var pool0) && _componentStorage.TryGetPool<T1>(out var pool1)))
{
return default;
}
return new QueryEnumerable<T0, T1>(
this,
@@ -30,11 +50,28 @@ public partial class World
pool0.Count);
}
public QueryEnumerable<T0, T1> QueryFilter<T0, T1>(ref readonly QueryFilter filter)
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData
{
if (!(_componentStorage.TryGetPool<T0>(out var pool0) && _componentStorage.TryGetPool<T1>(out var pool1)))
{
return default;
}
return new QueryEnumerable<T0, T1>(
this,
pool0, pool1,
pool0.Count,
in filter);
}
public QueryEnumerable<T0, T1, T2> Query<T0, T1, T2>()
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData
{
if (!(_componentStorage.TryGetPool<T0>(out var pool0) && _componentStorage.TryGetPool<T1>(out var pool1) && _componentStorage.TryGetPool<T2>(out var pool2)))
{
return default;
}
return new QueryEnumerable<T0, T1, T2>(
this,
@@ -42,11 +79,28 @@ public partial class World
pool0.Count);
}
public QueryEnumerable<T0, T1, T2> QueryFilter<T0, T1, T2>(ref readonly QueryFilter filter)
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData
{
if (!(_componentStorage.TryGetPool<T0>(out var pool0) && _componentStorage.TryGetPool<T1>(out var pool1) && _componentStorage.TryGetPool<T2>(out var pool2)))
{
return default;
}
return new QueryEnumerable<T0, T1, T2>(
this,
pool0, pool1, pool2,
pool0.Count,
in filter);
}
public QueryEnumerable<T0, T1, T2, T3> Query<T0, T1, T2, T3>()
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData
{
if (!(_componentStorage.TryGetPool<T0>(out var pool0) && _componentStorage.TryGetPool<T1>(out var pool1) && _componentStorage.TryGetPool<T2>(out var pool2) && _componentStorage.TryGetPool<T3>(out var pool3)))
{
return default;
}
return new QueryEnumerable<T0, T1, T2, T3>(
this,
@@ -54,11 +108,28 @@ public partial class World
pool0.Count);
}
public QueryEnumerable<T0, T1, T2, T3> QueryFilter<T0, T1, T2, T3>(ref readonly QueryFilter filter)
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData
{
if (!(_componentStorage.TryGetPool<T0>(out var pool0) && _componentStorage.TryGetPool<T1>(out var pool1) && _componentStorage.TryGetPool<T2>(out var pool2) && _componentStorage.TryGetPool<T3>(out var pool3)))
{
return default;
}
return new QueryEnumerable<T0, T1, T2, T3>(
this,
pool0, pool1, pool2, pool3,
pool0.Count,
in filter);
}
public QueryEnumerable<T0, T1, T2, T3, T4> Query<T0, T1, T2, T3, T4>()
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData where T4 : unmanaged, IComponentData
{
if (!(_componentStorage.TryGetPool<T0>(out var pool0) && _componentStorage.TryGetPool<T1>(out var pool1) && _componentStorage.TryGetPool<T2>(out var pool2) && _componentStorage.TryGetPool<T3>(out var pool3) && _componentStorage.TryGetPool<T4>(out var pool4)))
{
return default;
}
return new QueryEnumerable<T0, T1, T2, T3, T4>(
this,
@@ -66,11 +137,28 @@ public partial class World
pool0.Count);
}
public QueryEnumerable<T0, T1, T2, T3, T4> QueryFilter<T0, T1, T2, T3, T4>(ref readonly QueryFilter filter)
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData where T4 : unmanaged, IComponentData
{
if (!(_componentStorage.TryGetPool<T0>(out var pool0) && _componentStorage.TryGetPool<T1>(out var pool1) && _componentStorage.TryGetPool<T2>(out var pool2) && _componentStorage.TryGetPool<T3>(out var pool3) && _componentStorage.TryGetPool<T4>(out var pool4)))
{
return default;
}
return new QueryEnumerable<T0, T1, T2, T3, T4>(
this,
pool0, pool1, pool2, pool3, pool4,
pool0.Count,
in filter);
}
public QueryEnumerable<T0, T1, T2, T3, T4, T5> Query<T0, T1, T2, T3, T4, T5>()
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData where T4 : unmanaged, IComponentData where T5 : unmanaged, IComponentData
{
if (!(_componentStorage.TryGetPool<T0>(out var pool0) && _componentStorage.TryGetPool<T1>(out var pool1) && _componentStorage.TryGetPool<T2>(out var pool2) && _componentStorage.TryGetPool<T3>(out var pool3) && _componentStorage.TryGetPool<T4>(out var pool4) && _componentStorage.TryGetPool<T5>(out var pool5)))
{
return default;
}
return new QueryEnumerable<T0, T1, T2, T3, T4, T5>(
this,
@@ -78,11 +166,28 @@ public partial class World
pool0.Count);
}
public QueryEnumerable<T0, T1, T2, T3, T4, T5> QueryFilter<T0, T1, T2, T3, T4, T5>(ref readonly QueryFilter filter)
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData where T4 : unmanaged, IComponentData where T5 : unmanaged, IComponentData
{
if (!(_componentStorage.TryGetPool<T0>(out var pool0) && _componentStorage.TryGetPool<T1>(out var pool1) && _componentStorage.TryGetPool<T2>(out var pool2) && _componentStorage.TryGetPool<T3>(out var pool3) && _componentStorage.TryGetPool<T4>(out var pool4) && _componentStorage.TryGetPool<T5>(out var pool5)))
{
return default;
}
return new QueryEnumerable<T0, T1, T2, T3, T4, T5>(
this,
pool0, pool1, pool2, pool3, pool4, pool5,
pool0.Count,
in filter);
}
public QueryEnumerable<T0, T1, T2, T3, T4, T5, T6> Query<T0, T1, T2, T3, T4, T5, T6>()
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData where T4 : unmanaged, IComponentData where T5 : unmanaged, IComponentData where T6 : unmanaged, IComponentData
{
if (!(_componentStorage.TryGetPool<T0>(out var pool0) && _componentStorage.TryGetPool<T1>(out var pool1) && _componentStorage.TryGetPool<T2>(out var pool2) && _componentStorage.TryGetPool<T3>(out var pool3) && _componentStorage.TryGetPool<T4>(out var pool4) && _componentStorage.TryGetPool<T5>(out var pool5) && _componentStorage.TryGetPool<T6>(out var pool6)))
{
return default;
}
return new QueryEnumerable<T0, T1, T2, T3, T4, T5, T6>(
this,
@@ -90,11 +195,28 @@ public partial class World
pool0.Count);
}
public QueryEnumerable<T0, T1, T2, T3, T4, T5, T6> QueryFilter<T0, T1, T2, T3, T4, T5, T6>(ref readonly QueryFilter filter)
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData where T4 : unmanaged, IComponentData where T5 : unmanaged, IComponentData where T6 : unmanaged, IComponentData
{
if (!(_componentStorage.TryGetPool<T0>(out var pool0) && _componentStorage.TryGetPool<T1>(out var pool1) && _componentStorage.TryGetPool<T2>(out var pool2) && _componentStorage.TryGetPool<T3>(out var pool3) && _componentStorage.TryGetPool<T4>(out var pool4) && _componentStorage.TryGetPool<T5>(out var pool5) && _componentStorage.TryGetPool<T6>(out var pool6)))
{
return default;
}
return new QueryEnumerable<T0, T1, T2, T3, T4, T5, T6>(
this,
pool0, pool1, pool2, pool3, pool4, pool5, pool6,
pool0.Count,
in filter);
}
public QueryEnumerable<T0, T1, T2, T3, T4, T5, T6, T7> Query<T0, T1, T2, T3, T4, T5, T6, T7>()
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData where T4 : unmanaged, IComponentData where T5 : unmanaged, IComponentData where T6 : unmanaged, IComponentData where T7 : unmanaged, IComponentData
{
if (!(_componentStorage.TryGetPool<T0>(out var pool0) && _componentStorage.TryGetPool<T1>(out var pool1) && _componentStorage.TryGetPool<T2>(out var pool2) && _componentStorage.TryGetPool<T3>(out var pool3) && _componentStorage.TryGetPool<T4>(out var pool4) && _componentStorage.TryGetPool<T5>(out var pool5) && _componentStorage.TryGetPool<T6>(out var pool6) && _componentStorage.TryGetPool<T7>(out var pool7)))
{
return default;
}
return new QueryEnumerable<T0, T1, T2, T3, T4, T5, T6, T7>(
this,
@@ -102,4 +224,19 @@ public partial class World
pool0.Count);
}
public QueryEnumerable<T0, T1, T2, T3, T4, T5, T6, T7> QueryFilter<T0, T1, T2, T3, T4, T5, T6, T7>(ref readonly QueryFilter filter)
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData where T4 : unmanaged, IComponentData where T5 : unmanaged, IComponentData where T6 : unmanaged, IComponentData where T7 : unmanaged, IComponentData
{
if (!(_componentStorage.TryGetPool<T0>(out var pool0) && _componentStorage.TryGetPool<T1>(out var pool1) && _componentStorage.TryGetPool<T2>(out var pool2) && _componentStorage.TryGetPool<T3>(out var pool3) && _componentStorage.TryGetPool<T4>(out var pool4) && _componentStorage.TryGetPool<T5>(out var pool5) && _componentStorage.TryGetPool<T6>(out var pool6) && _componentStorage.TryGetPool<T7>(out var pool7)))
{
return default;
}
return new QueryEnumerable<T0, T1, T2, T3, T4, T5, T6, T7>(
this,
pool0, pool1, pool2, pool3, pool4, pool5, pool6, pool7,
pool0.Count,
in filter);
}
}

View File

@@ -6,6 +6,7 @@
<#@ include file="Helpers.ttinclude" #>
using Ghost.Entities.Components;
using Ghost.Entities.Query;
namespace Ghost.Entities;
@@ -24,7 +25,9 @@ public partial class World
<#= restrictions #>
{
if (!(<#= tryGetPools #>))
{
return default;
}
return new QueryEnumerable<<#= generics #>>(
this,
@@ -32,5 +35,20 @@ public partial class World
<#= countSource #>);
}
public QueryEnumerable<<#= generics #>> QueryFilter<<#= generics #>>(ref readonly QueryFilter filter)
<#= restrictions #>
{
if (!(<#= tryGetPools #>))
{
return default;
}
return new QueryEnumerable<<#= generics #>>(
this,
<#= poolParams #>,
<#= countSource #>,
in filter);
}
<# } #>
}

View File

@@ -1,6 +1,7 @@
using Ghost.Entities.Components;
using Ghost.Entities.Query;
using Ghost.Entities.Systems;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -51,6 +52,8 @@ public partial class World : IDisposable, IEquatable<World>
private readonly ComponentStorage _componentStorage;
private readonly SystemStorage _systemStorage;
private bool _isDisposed = false;
internal ComponentStorage ComponentStorage => _componentStorage;
public WorldID ID => _id;
@@ -67,6 +70,11 @@ public partial class World : IDisposable, IEquatable<World>
_systemStorage = new SystemStorage(this);
}
~World()
{
Dispose();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CompRef<T> GetSingleton<T>()
where T : unmanaged, IComponentData
@@ -87,29 +95,20 @@ public partial class World : IDisposable, IEquatable<World>
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[Conditional("GHOST_EDITOR")]
public void NotifyComponentChanged(Entity entity, Type type)
{
//#if GHOST_EDITOR
ComponentChanged?.Invoke(this, entity, type);
//#endif
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[Conditional("GHOST_EDITOR")]
public void NotifyComponentChanged<T>(Entity entity)
where T : unmanaged, IComponentData
{
NotifyComponentChanged(entity, typeof(T));
}
public void Dispose()
{
_entityManager.Dispose();
_componentStorage.Dispose();
_systemStorage.Dispose();
s_freeWorldSlots.Enqueue(_id);
}
public bool Equals(World? other)
{
if (other is null)
@@ -144,4 +143,22 @@ public partial class World : IDisposable, IEquatable<World>
{
return !(left == right);
}
public void Dispose()
{
if (_isDisposed)
{
return;
}
_entityManager.Dispose();
_componentStorage.Dispose();
_systemStorage.Dispose();
s_freeWorldSlots.Enqueue(_id);
_isDisposed = true;
GC.SuppressFinalize(this);
}
}