update where queries, fix query cache

This commit is contained in:
Mikhail 2024-11-05 15:50:03 +08:00
parent 36c74d5a4c
commit 8c442a66c0
8 changed files with 95 additions and 35 deletions

View File

@ -184,7 +184,7 @@ namespace DCFApixels.DragonECS
private TPool CachePool<TPool>() where TPool : IEcsPoolImplementation, new() private TPool CachePool<TPool>() where TPool : IEcsPoolImplementation, new()
{ {
var pool = _world.GetPoolInstance<TPool>(); var pool = _world.GetPoolInstance<TPool>();
if(_poolsBufferCount >= _poolsBuffer.Length) if (_poolsBufferCount >= _poolsBuffer.Length)
{ {
Array.Resize(ref _poolsBuffer, _poolsBuffer.Length << 1); Array.Resize(ref _poolsBuffer, _poolsBuffer.Length << 1);
} }

View File

@ -1,4 +1,5 @@
using DCFApixels.DragonECS.PoolsCore; using DCFApixels.DragonECS.Core;
using DCFApixels.DragonECS.PoolsCore;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS
{ {
@ -33,14 +34,8 @@ namespace DCFApixels.DragonECS
} }
} }
//TODO добавить сквозной кеш для инстансов TExecutor
//private readonly struct WhereCache<TExecutor> : IEcsWorldComponent<WhereCache<TExecutor>>
//{
// private readonly SparseArray<int, TExecutor> _pairs
//}
// Это не подохидт
internal readonly struct WhereQueryCache<TExecutor, TAspcet> : IEcsWorldComponent<WhereQueryCache<TExecutor, TAspcet>> internal readonly struct WhereQueryCache<TExecutor, TAspcet> : IEcsWorldComponent<WhereQueryCache<TExecutor, TAspcet>>
where TExecutor : EcsQueryExecutor, new() where TExecutor : MaskQueryExecutor, new()
where TAspcet : EcsAspect, new() where TAspcet : EcsAspect, new()
{ {
public readonly TExecutor Executor; public readonly TExecutor Executor;
@ -52,8 +47,8 @@ namespace DCFApixels.DragonECS
} }
void IEcsWorldComponent<WhereQueryCache<TExecutor, TAspcet>>.Init(ref WhereQueryCache<TExecutor, TAspcet> component, EcsWorld world) void IEcsWorldComponent<WhereQueryCache<TExecutor, TAspcet>>.Init(ref WhereQueryCache<TExecutor, TAspcet> component, EcsWorld world)
{ {
TExecutor instance = new TExecutor();
TAspcet aspect = world.GetAspect<TAspcet>(); TAspcet aspect = world.GetAspect<TAspcet>();
TExecutor instance = world.GetExecutorForMask<TExecutor>(aspect.Mask);
instance.Initialize(world, aspect.Mask); instance.Initialize(world, aspect.Mask);
component = new WhereQueryCache<TExecutor, TAspcet>(instance, aspect); component = new WhereQueryCache<TExecutor, TAspcet>(instance, aspect);
} }

View File

@ -73,6 +73,34 @@ namespace DCFApixels.DragonECS
private List<IEcsWorldEventListener> _listeners = new List<IEcsWorldEventListener>(); private List<IEcsWorldEventListener> _listeners = new List<IEcsWorldEventListener>();
private List<IEcsEntityEventListener> _entityListeners = new List<IEcsEntityEventListener>(); private List<IEcsEntityEventListener> _entityListeners = new List<IEcsEntityEventListener>();
private static Stack<EcsWorldConfig> _configInitOnlynStack = new Stack<EcsWorldConfig>(4);
protected internal static EcsWorldConfig Config_InitOnly
{
get
{
if (_configInitOnlynStack.TryPeek(out EcsWorldConfig result))
{
return result;
}
Throw.UndefinedException();
return null;
}
}
private readonly ref struct ConfigInitOnlyScope
{
private readonly Stack<EcsWorldConfig> _stack;
public ConfigInitOnlyScope(Stack<EcsWorldConfig> stack, EcsWorldConfig config)
{
_stack = stack;
_stack.Push(config);
}
public void Dispose()
{
_stack.Peek();
}
}
#region Properties #region Properties
EcsWorld IEntityStorage.World EcsWorld IEntityStorage.World
{ {
@ -143,6 +171,8 @@ namespace DCFApixels.DragonECS
lock (_worldLock) lock (_worldLock)
{ {
if (configs == null) { configs = ConfigContainer.Empty; } if (configs == null) { configs = ConfigContainer.Empty; }
_configInitOnlynStack.Push(configs.GetWorldConfigOrDefault());
bool nullWorld = this is NullWorld; bool nullWorld = this is NullWorld;
if (nullWorld == false && worldID == NULL_WORLD_ID) if (nullWorld == false && worldID == NULL_WORLD_ID)
{ {
@ -164,6 +194,7 @@ namespace DCFApixels.DragonECS
if (_worlds[worldID] != null) if (_worlds[worldID] != null)
{ {
_worldIdDispenser.Release(worldID); _worldIdDispenser.Release(worldID);
_configInitOnlynStack.Pop();
Throw.Exception("The world with the specified ID has already been created\r\n"); Throw.Exception("The world with the specified ID has already been created\r\n");
} }
} }
@ -181,6 +212,8 @@ namespace DCFApixels.DragonECS
_entityDispenser = new IdDispenser(entitiesCapacity, 0, OnEntityDispenserResized); _entityDispenser = new IdDispenser(entitiesCapacity, 0, OnEntityDispenserResized);
GetComponentTypeID<NullComponent>(); GetComponentTypeID<NullComponent>();
_configInitOnlynStack.Pop();
} }
} }
public void Destroy() public void Destroy()
@ -231,7 +264,7 @@ namespace DCFApixels.DragonECS
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void GetQueryCache<TExecutor, TAspect>(out TExecutor executor, out TAspect aspect) public void GetQueryCache<TExecutor, TAspect>(out TExecutor executor, out TAspect aspect)
where TExecutor : EcsQueryExecutor, new() where TExecutor : MaskQueryExecutor, new()
where TAspect : EcsAspect, new() where TAspect : EcsAspect, new()
{ {
ref var cmp = ref Get<WhereQueryCache<TExecutor, TAspect>>(); ref var cmp = ref Get<WhereQueryCache<TExecutor, TAspect>>();

View File

@ -1,4 +1,5 @@
using System; using DCFApixels.DragonECS.Core;
using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
#if ENABLE_IL2CPP #if ENABLE_IL2CPP
using Unity.IL2CPP.CompilerServices; using Unity.IL2CPP.CompilerServices;
@ -10,16 +11,16 @@ namespace DCFApixels.DragonECS.Internal
[Il2CppSetOption(Option.NullChecks, false)] [Il2CppSetOption(Option.NullChecks, false)]
[Il2CppSetOption(Option.ArrayBoundsChecks, false)] [Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif #endif
internal class EcsWhereExecutor : EcsQueryExecutor internal class EcsWhereExecutor : MaskQueryExecutor
{ {
private EcsMaskIterator _iterator; private EcsMaskIterator _iterator;
private int[] _filteredAllEntities = new int[32]; private int[] _filteredAllEntities = new int[32];
private int _filteredAllEntitiesCount = 0; private int _filteredAllEntitiesCount = 0;
private long _version;
private int[] _filteredEntities = null; private int[] _filteredEntities = null;
private int _filteredEntitiesCount = 0; private int _filteredEntitiesCount = 0;
private long _version;
private WorldStateVersionsChecker _versionsChecker; private WorldStateVersionsChecker _versionsChecker;
#region Properties #region Properties
@ -28,6 +29,11 @@ namespace DCFApixels.DragonECS.Internal
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _version; } get { return _version; }
} }
public sealed override bool IsCached
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _versionsChecker.Check(); }
}
#endregion #endregion
#region OnInitialize/OnDestroy #region OnInitialize/OnDestroy

View File

@ -1,4 +1,5 @@
using System.Runtime.CompilerServices; using DCFApixels.DragonECS.Core;
using System.Runtime.CompilerServices;
#if ENABLE_IL2CPP #if ENABLE_IL2CPP
using Unity.IL2CPP.CompilerServices; using Unity.IL2CPP.CompilerServices;
#endif #endif
@ -9,14 +10,14 @@ namespace DCFApixels.DragonECS.Internal
[Il2CppSetOption(Option.NullChecks, false)] [Il2CppSetOption(Option.NullChecks, false)]
[Il2CppSetOption(Option.ArrayBoundsChecks, false)] [Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif #endif
internal class EcsWhereToGroupExecutor : EcsQueryExecutor internal class EcsWhereToGroupExecutor : MaskQueryExecutor
{ {
private EcsMaskIterator _iterator; private EcsMaskIterator _iterator;
private EcsGroup _filteredAllGroup;
private long _version;
private EcsGroup _filteredAllGroup;
private EcsGroup _filteredGroup; private EcsGroup _filteredGroup;
private long _version;
private WorldStateVersionsChecker _versionsChecker; private WorldStateVersionsChecker _versionsChecker;
#region Properties #region Properties
@ -25,6 +26,11 @@ namespace DCFApixels.DragonECS.Internal
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _version; } get { return _version; }
} }
public sealed override bool IsCached
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _versionsChecker.Check(); }
}
#endregion #endregion
#region OnInitialize/OnDestroy #region OnInitialize/OnDestroy

View File

@ -8,21 +8,40 @@ namespace DCFApixels.DragonECS
{ {
public partial class EcsWorld public partial class EcsWorld
{ {
private readonly Dictionary<(Type, object), EcsQueryExecutor> _executorCoures = new Dictionary<(Type, object), EcsQueryExecutor>(256); private readonly Dictionary<(Type, object), IQueryExecutorImplementation> _executorCoures = new Dictionary<(Type, object), IQueryExecutorImplementation>(Config_InitOnly.PoolComponentsCapacity);
public TExecutor GetExecutor<TExecutor>(IComponentMask mask) public TExecutor GetExecutorForMask<TExecutor>(IComponentMask gmask)
where TExecutor : EcsQueryExecutor, new() where TExecutor : MaskQueryExecutor, new()
{ {
var coreType = typeof(TExecutor); var coreType = typeof(TExecutor);
if (_executorCoures.TryGetValue((coreType, mask), out EcsQueryExecutor core) == false) //проверяет ключ по абстрактной маске
if (_executorCoures.TryGetValue((coreType, gmask), out IQueryExecutorImplementation executor) == false)
{ {
core = new TExecutor(); var mask = gmask.ToMask(this);
core.Initialize(this, mask.ToMask(this)); //проверяет ключ по конкретной маске, или что конкретная и абстрактая одна и таже
_executorCoures.Add((coreType, mask), core); if (mask == gmask ||
_executorCoures.TryGetValue((coreType, mask), out executor) == false)
{
TExecutor newCore = new TExecutor();
newCore.Initialize(this, mask);
executor = newCore;
}
_executorCoures.Add((coreType, gmask), executor);
} }
return (TExecutor)core; return (TExecutor)executor;
} }
} }
public abstract class EcsQueryExecutor }
namespace DCFApixels.DragonECS.Core
{
public interface IQueryExecutorImplementation
{
EcsWorld World { get; }
long Version { get; }
bool IsCached { get; }
void Destroy();
}
public abstract class MaskQueryExecutor : IQueryExecutorImplementation
{ {
private EcsWorld _source; private EcsWorld _source;
private EcsMask _mask; private EcsMask _mask;
@ -42,13 +61,14 @@ namespace DCFApixels.DragonECS
get { return _mask; } get { return _mask; }
} }
public abstract long Version { get; } public abstract long Version { get; }
public abstract bool IsCached { get; }
internal void Initialize(EcsWorld world, EcsMask mask) internal void Initialize(EcsWorld world, EcsMask mask)
{ {
_source = world; _source = world;
_mask = mask; _mask = mask;
OnInitialize(); OnInitialize();
} }
internal void Destroy() void IQueryExecutorImplementation.Destroy()
{ {
OnDestroy(); OnDestroy();
_source = null; _source = null;

View File

@ -40,7 +40,7 @@ namespace DCFApixels.DragonECS
{ {
if (ReferenceEquals(entities, entities.World)) if (ReferenceEquals(entities, entities.World))
{ {
var executor = entities.World.GetExecutor<EcsWhereExecutor>(mask); var executor = entities.World.GetExecutorForMask<EcsWhereExecutor>(mask);
return executor.Execute(); return executor.Execute();
} }
return entities.ToSpan().Where(mask); return entities.ToSpan().Where(mask);
@ -51,7 +51,7 @@ namespace DCFApixels.DragonECS
} }
public static EcsSpan Where(this EcsSpan span, IComponentMask mask) public static EcsSpan Where(this EcsSpan span, IComponentMask mask)
{ {
var executor = span.World.GetExecutor<EcsWhereExecutor>(mask); var executor = span.World.GetExecutorForMask<EcsWhereExecutor>(mask);
return executor.ExecuteFor(span); return executor.ExecuteFor(span);
} }
#endregion #endregion
@ -85,7 +85,7 @@ namespace DCFApixels.DragonECS
{ {
if (ReferenceEquals(entities, entities.World)) if (ReferenceEquals(entities, entities.World))
{ {
EcsWhereExecutor executor = entities.World.GetExecutor<EcsWhereExecutor>(mask); EcsWhereExecutor executor = entities.World.GetExecutorForMask<EcsWhereExecutor>(mask);
return executor.Execute(comparison); return executor.Execute(comparison);
} }
return entities.ToSpan().Where(mask, comparison); return entities.ToSpan().Where(mask, comparison);
@ -96,7 +96,7 @@ namespace DCFApixels.DragonECS
} }
public static EcsSpan Where(this EcsSpan span, IComponentMask mask, Comparison<int> comparison) public static EcsSpan Where(this EcsSpan span, IComponentMask mask, Comparison<int> comparison)
{ {
var executor = span.World.GetExecutor<EcsWhereExecutor>(mask); var executor = span.World.GetExecutorForMask<EcsWhereExecutor>(mask);
return executor.ExecuteFor(span); return executor.ExecuteFor(span);
} }
#endregion #endregion
@ -130,7 +130,7 @@ namespace DCFApixels.DragonECS
{ {
if (ReferenceEquals(entities, entities.World)) if (ReferenceEquals(entities, entities.World))
{ {
EcsWhereToGroupExecutor executor = entities.World.GetExecutor<EcsWhereToGroupExecutor>(mask); EcsWhereToGroupExecutor executor = entities.World.GetExecutorForMask<EcsWhereToGroupExecutor>(mask);
return executor.Execute(); return executor.Execute();
} }
return entities.ToSpan().WhereToGroup(mask); return entities.ToSpan().WhereToGroup(mask);
@ -141,7 +141,7 @@ namespace DCFApixels.DragonECS
} }
public static EcsReadonlyGroup WhereToGroup(this EcsSpan span, IComponentMask mask) public static EcsReadonlyGroup WhereToGroup(this EcsSpan span, IComponentMask mask)
{ {
var executor = span.World.GetExecutor<EcsWhereToGroupExecutor>(mask); var executor = span.World.GetExecutorForMask<EcsWhereToGroupExecutor>(mask);
return executor.ExecuteFor(span); return executor.ExecuteFor(span);
} }
#endregion #endregion