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

@ -1,4 +1,5 @@
using DCFApixels.DragonECS.PoolsCore;
using DCFApixels.DragonECS.Core;
using DCFApixels.DragonECS.PoolsCore;
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>>
where TExecutor : EcsQueryExecutor, new()
where TExecutor : MaskQueryExecutor, new()
where TAspcet : EcsAspect, new()
{
public readonly TExecutor Executor;
@ -52,8 +47,8 @@ namespace DCFApixels.DragonECS
}
void IEcsWorldComponent<WhereQueryCache<TExecutor, TAspcet>>.Init(ref WhereQueryCache<TExecutor, TAspcet> component, EcsWorld world)
{
TExecutor instance = new TExecutor();
TAspcet aspect = world.GetAspect<TAspcet>();
TExecutor instance = world.GetExecutorForMask<TExecutor>(aspect.Mask);
instance.Initialize(world, aspect.Mask);
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<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
EcsWorld IEntityStorage.World
{
@ -143,6 +171,8 @@ namespace DCFApixels.DragonECS
lock (_worldLock)
{
if (configs == null) { configs = ConfigContainer.Empty; }
_configInitOnlynStack.Push(configs.GetWorldConfigOrDefault());
bool nullWorld = this is NullWorld;
if (nullWorld == false && worldID == NULL_WORLD_ID)
{
@ -164,6 +194,7 @@ namespace DCFApixels.DragonECS
if (_worlds[worldID] != null)
{
_worldIdDispenser.Release(worldID);
_configInitOnlynStack.Pop();
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);
GetComponentTypeID<NullComponent>();
_configInitOnlynStack.Pop();
}
}
public void Destroy()
@ -231,7 +264,7 @@ namespace DCFApixels.DragonECS
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void GetQueryCache<TExecutor, TAspect>(out TExecutor executor, out TAspect aspect)
where TExecutor : EcsQueryExecutor, new()
where TExecutor : MaskQueryExecutor, new()
where TAspect : EcsAspect, new()
{
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;
#if ENABLE_IL2CPP
using Unity.IL2CPP.CompilerServices;
@ -10,16 +11,16 @@ namespace DCFApixels.DragonECS.Internal
[Il2CppSetOption(Option.NullChecks, false)]
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif
internal class EcsWhereExecutor : EcsQueryExecutor
internal class EcsWhereExecutor : MaskQueryExecutor
{
private EcsMaskIterator _iterator;
private int[] _filteredAllEntities = new int[32];
private int _filteredAllEntitiesCount = 0;
private long _version;
private int[] _filteredEntities = null;
private int _filteredEntitiesCount = 0;
private long _version;
private WorldStateVersionsChecker _versionsChecker;
#region Properties
@ -28,6 +29,11 @@ namespace DCFApixels.DragonECS.Internal
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _version; }
}
public sealed override bool IsCached
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _versionsChecker.Check(); }
}
#endregion
#region OnInitialize/OnDestroy

View File

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

View File

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

View File

@ -40,7 +40,7 @@ namespace DCFApixels.DragonECS
{
if (ReferenceEquals(entities, entities.World))
{
var executor = entities.World.GetExecutor<EcsWhereExecutor>(mask);
var executor = entities.World.GetExecutorForMask<EcsWhereExecutor>(mask);
return executor.Execute();
}
return entities.ToSpan().Where(mask);
@ -51,7 +51,7 @@ namespace DCFApixels.DragonECS
}
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);
}
#endregion
@ -85,7 +85,7 @@ namespace DCFApixels.DragonECS
{
if (ReferenceEquals(entities, entities.World))
{
EcsWhereExecutor executor = entities.World.GetExecutor<EcsWhereExecutor>(mask);
EcsWhereExecutor executor = entities.World.GetExecutorForMask<EcsWhereExecutor>(mask);
return executor.Execute(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)
{
var executor = span.World.GetExecutor<EcsWhereExecutor>(mask);
var executor = span.World.GetExecutorForMask<EcsWhereExecutor>(mask);
return executor.ExecuteFor(span);
}
#endregion
@ -130,7 +130,7 @@ namespace DCFApixels.DragonECS
{
if (ReferenceEquals(entities, entities.World))
{
EcsWhereToGroupExecutor executor = entities.World.GetExecutor<EcsWhereToGroupExecutor>(mask);
EcsWhereToGroupExecutor executor = entities.World.GetExecutorForMask<EcsWhereToGroupExecutor>(mask);
return executor.Execute();
}
return entities.ToSpan().WhereToGroup(mask);
@ -141,7 +141,7 @@ namespace DCFApixels.DragonECS
}
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);
}
#endregion