This commit is contained in:
DCFApixels 2025-03-10 13:00:30 +08:00
parent 7ef556556b
commit 5d6c095142
11 changed files with 442 additions and 160 deletions

View File

@ -30,6 +30,13 @@ namespace DCFApixels.DragonECS
{ {
void Run(); void Run();
} }
[MetaName(nameof(RunFinally))]
[MetaColor(MetaColor.DragonRose)]
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.PROCESSES_GROUP)]
public interface IEcsRunFinally : IEcsProcess
{
void RunFinally();
}
[MetaName(nameof(Destroy))] [MetaName(nameof(Destroy))]
[MetaColor(MetaColor.DragonRose)] [MetaColor(MetaColor.DragonRose)]
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.PROCESSES_GROUP)] [MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.PROCESSES_GROUP)]
@ -97,26 +104,45 @@ namespace DCFApixels.DragonECS.Internal
[MetaID("2098527C9201F260C840BFD50BC7E0BA")] [MetaID("2098527C9201F260C840BFD50BC7E0BA")]
internal sealed class EcsRunRunner : EcsRunner<IEcsRun>, IEcsRun internal sealed class EcsRunRunner : EcsRunner<IEcsRun>, IEcsRun
{ {
private readonly struct Pair
{
public readonly IEcsRun run;
public readonly IEcsRunFinally cleanup;
public Pair(IEcsRun run)
{
this.run = run;
cleanup = run as IEcsRunFinally;
}
}
private Pair[] _pairs;
#if DEBUG && !DISABLE_DEBUG #if DEBUG && !DISABLE_DEBUG
private EcsProfilerMarker[] _markers; private EcsProfilerMarker[] _markers;
#endif
protected override void OnSetup() protected override void OnSetup()
{ {
_pairs = new Pair[Process.Length];
for (int i = 0; i < Process.Length; i++)
{
_pairs[i] = new Pair(Process[i]);
}
#if DEBUG && !DISABLE_DEBUG
_markers = new EcsProfilerMarker[Process.Length]; _markers = new EcsProfilerMarker[Process.Length];
for (int i = 0; i < Process.Length; i++) for (int i = 0; i < Process.Length; i++)
{ {
_markers[i] = new EcsProfilerMarker($"{Process[i].GetMeta().Name}.{nameof(Run)}"); _markers[i] = new EcsProfilerMarker($"{Process[i].GetMeta().Name}.{nameof(Run)}");
} }
}
#endif #endif
}
public void Run() public void Run()
{ {
#if DEBUG && !DISABLE_DEBUG #if DEBUG && !DISABLE_DEBUG
for (int i = 0, n = Process.Length < _markers.Length ? Process.Length : _markers.Length; i < n; i++) for (int i = 0, n = _pairs.Length < _markers.Length ? _pairs.Length : _markers.Length; i < n; i++)
{ {
var pair = _pairs[i];
_markers[i].Begin(); _markers[i].Begin();
try try
{ {
Process[i].Run(); pair.run.Run();
} }
catch (Exception e) catch (Exception e)
{ {
@ -125,6 +151,10 @@ namespace DCFApixels.DragonECS.Internal
#endif #endif
EcsDebug.PrintError(e); EcsDebug.PrintError(e);
} }
finally
{
pair.cleanup?.RunFinally();
}
_markers[i].End(); _markers[i].End();
} }
#else #else

View File

@ -25,7 +25,63 @@ namespace DCFApixels.DragonECS
public static implicit operator Singleton<T>(SingletonMarker a) { return new Singleton<T>(a.Builder.World.ID); } public static implicit operator Singleton<T>(SingletonMarker a) { return new Singleton<T>(a.Builder.World.ID); }
} }
public abstract class EcsAspect : ITemplateNode, IComponentMask public interface IEcsAspect
{
EcsMask Mask { get; set; }
}
#region IEcsAspectExtensions tmp
// public static class IEcsAspectExtensions
// {
// public static void Apply(this IEcsAspect aspect, short worldID, int entityID)
// {
// EcsWorld world = EcsWorld.GetWorld(worldID);
// EcsMask mask = aspect.Mask;
// foreach (var incTypeID in mask._incs)
// {
// var pool = world.FindPoolInstance(incTypeID);
// if (pool != null)
// {
// if (pool.Has(entityID) == false)
// {
// pool.AddEmpty(entityID);
// }
// }
//#if DEBUG
// else
// {
// EcsDebug.PrintWarning("Component has not been added because the pool has not been initialized yet.");
// }
//#endif
// }
// foreach (var excTypeID in mask._excs)
// {
// var pool = world.FindPoolInstance(excTypeID);
// if (pool != null && pool.Has(entityID))
// {
// pool.Del(entityID);
// }
// }
// }
// }
#endregion
public static partial class API
{
public static IncludeMarker Inc
{
get { return EcsAspect.CurrentBuilder.Inc; }
}
public static ExcludeMarker Exc
{
get { return EcsAspect.CurrentBuilder.Exc; }
}
public static OptionalMarker Opt
{
get { return EcsAspect.CurrentBuilder.Opt; }
}
}
public abstract class EcsAspect : IEcsAspect, ITemplateNode, IComponentMask
{ {
#region Initialization Halpers #region Initialization Halpers
[ThreadStatic] [ThreadStatic]
@ -43,7 +99,7 @@ namespace DCFApixels.DragonECS
return _constructorBuildersStack[_constructorBuildersStackIndex]; return _constructorBuildersStack[_constructorBuildersStackIndex];
} }
} }
protected static Builder CurrentBuilder public static Builder CurrentBuilder
{ {
get { return B; } get { return B; }
} }
@ -77,6 +133,7 @@ namespace DCFApixels.DragonECS
public EcsMask Mask public EcsMask Mask
{ {
get { return _mask; } get { return _mask; }
set { }
} }
public EcsWorld World public EcsWorld World
{ {
@ -138,7 +195,8 @@ namespace DCFApixels.DragonECS
#region Constructors/New #region Constructors/New
private Builder() { } private Builder() { }
internal static unsafe TAspect New<TAspect>(EcsWorld world) where TAspect : EcsAspect, new()
internal static unsafe (TAspect aspect, EcsMask mask) New<TAspect>(EcsWorld world) where TAspect : new()
{ {
//Get Builder //Get Builder
if (_constructorBuildersStack == null) if (_constructorBuildersStack == null)
@ -168,26 +226,34 @@ namespace DCFApixels.DragonECS
//Building //Building
TAspect newAspect = new TAspect(); TAspect newAspect = new TAspect();
newAspect._source = world; EcsAspect builtinAspect = newAspect as EcsAspect;
newAspect.Init(builder); if(builtinAspect != null)
{
builtinAspect._source = world;
builtinAspect.Init(builder);
}
//Build Mask //Build Mask
if (staticMask == null) if (staticMask == null)
{ {
staticMask = builder._maskBuilder.Build(); staticMask = builder._maskBuilder.Build();
builder._maskBuilder = default; builder._maskBuilder = default;
if (newAspect.IsStaticInitialization) if (builtinAspect == null || builtinAspect.IsStaticInitialization)
{ {
_staticMaskCache.Add(typeof(TAspect), staticMask); _staticMaskCache.Add(typeof(TAspect), staticMask);
} }
} }
newAspect._mask = staticMask.ToMask(world); EcsMask mask = staticMask.ToMask(world);
//var pools = new IEcsPool[builder._poolsBufferCount]; if(builtinAspect != null)
//Array.Copy(builder._poolsBuffer, pools, pools.Length); {
newAspect._isBuilt = true; builtinAspect._mask = mask;
//var pools = new IEcsPool[builder._poolsBufferCount];
//Array.Copy(builder._poolsBuffer, pools, pools.Length);
builtinAspect._isBuilt = true;
}
_constructorBuildersStackIndex--; _constructorBuildersStackIndex--;
return newAspect; return (newAspect, mask);
} }
#endregion #endregion
@ -386,7 +452,9 @@ namespace DCFApixels.DragonECS
} }
} }
#endregion #endregion
}
namespace DCFApixels.DragonECS.Core
{
#region Constraint Markers #region Constraint Markers
public readonly ref struct IncludeMarker public readonly ref struct IncludeMarker
{ {

View File

@ -214,7 +214,7 @@ namespace DCFApixels.DragonECS
{ {
case IEcsProcess system: return AddSystem_Internal(system, settedAddParams); case IEcsProcess system: return AddSystem_Internal(system, settedAddParams);
case IEcsModule module: return AddModule_Internal(module, settedAddParams); case IEcsModule module: return AddModule_Internal(module, settedAddParams);
default: Throw.ArgumentException("Unsupported type"); return this; default: Throw.ArgumentException($"{raw.GetMeta().TypeName} Unsupported type"); return this;
} }
} }
#endregion #endregion

View File

@ -68,7 +68,7 @@ namespace DCFApixels.DragonECS
{ {
get { return _isInit; } get { return _isInit; }
} }
public bool IsDestoryed public bool IsDestroyed
{ {
get { return _isDestoryed; } get { return _isDestoryed; }
} }
@ -250,7 +250,7 @@ namespace DCFApixels.DragonECS
{ {
public static bool IsNullOrDestroyed(this EcsPipeline self) public static bool IsNullOrDestroyed(this EcsPipeline self)
{ {
return self == null || self.IsDestoryed; return self == null || self.IsDestroyed;
} }
public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, IEnumerable<IEcsProcess> range, string layerName = null) public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, IEnumerable<IEcsProcess> range, string layerName = null)
{ {

View File

@ -4,6 +4,7 @@ using System;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using static DCFApixels.DragonECS.EcsDebugUtility; using static DCFApixels.DragonECS.EcsDebugUtility;
#pragma warning disable CS0162 // Обнаружен недостижимый код
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS
{ {
@ -16,6 +17,7 @@ namespace DCFApixels.DragonECS
namespace RunnersCore namespace RunnersCore
{ {
//добавить инъекцию в раннеры
public abstract class EcsRunner public abstract class EcsRunner
{ {
internal abstract void Init_Internal(EcsPipeline source); internal abstract void Init_Internal(EcsPipeline source);
@ -57,6 +59,8 @@ namespace DCFApixels.DragonECS
#endif #endif
} }
#endregion #endregion
public delegate void ActionWithData<in TProcess, T>(TProcess process, ref T Data);
} }
[MetaColor(MetaColor.DragonRose)] [MetaColor(MetaColor.DragonRose)]
@ -124,7 +128,12 @@ namespace DCFApixels.DragonECS
#endregion #endregion
#region RunHelper #region RunHelper
public struct RunHelper #if DEBUG && !DISABLE_DEBUG
public
#else
public readonly
#endif
struct RunHelper
{ {
private readonly EcsProcess<TProcess> _process; private readonly EcsProcess<TProcess> _process;
#if DEBUG && !DISABLE_DEBUG #if DEBUG && !DISABLE_DEBUG
@ -182,7 +191,6 @@ namespace DCFApixels.DragonECS
#endregion #endregion
#region Do #region Do
#pragma warning disable CS0162 // Обнаружен недостижимый код
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Run(Action<TProcess> translationCallback) public void Run(Action<TProcess> translationCallback)
{ {
@ -223,7 +231,7 @@ namespace DCFApixels.DragonECS
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Run<T0>(Action<TProcess, T0> translationCallback, T0 t0) public void Run<TData>(ActionWithData<TProcess, TData> translationCallback, ref TData data)
{ {
#if DEBUG && !DISABLE_DEBUG #if DEBUG && !DISABLE_DEBUG
CheckCache(translationCallback); CheckCache(translationCallback);
@ -232,7 +240,7 @@ namespace DCFApixels.DragonECS
_markers[i].Begin(); _markers[i].Begin();
try try
{ {
translationCallback(_process[i], t0); translationCallback(_process[i], ref data);
} }
catch (Exception e) catch (Exception e)
{ {
@ -248,7 +256,7 @@ namespace DCFApixels.DragonECS
{ {
try try
{ {
translationCallback(item, t0); translationCallback(item, ref data);
} }
catch (Exception e) catch (Exception e)
{ {
@ -260,128 +268,205 @@ namespace DCFApixels.DragonECS
} }
#endif #endif
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Run<T0, T1>(Action<TProcess, T0, T1> translationCallback, T0 t0, T1 t1)
{
#if DEBUG && !DISABLE_DEBUG
CheckCache(translationCallback);
for (int i = 0, n = _process.Length < _markers.Length ? _process.Length : _markers.Length; i < n; i++)
{
_markers[i].Begin();
try
{
translationCallback(_process[i], t0, t1);
}
catch (Exception e)
{
#if DISABLE_CATH_EXCEPTIONS
throw;
#endif
EcsDebug.PrintError(e);
}
_markers[i].End();
}
#else
foreach (var item in _process)
{
try
{
translationCallback(item, t0, t1);
}
catch (Exception e)
{
#if DISABLE_CATH_EXCEPTIONS
throw;
#endif
EcsDebug.PrintError(e);
}
}
#endif
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Run<T0, T1, T2>(Action<TProcess, T0, T1, T2> translationCallback, T0 t0, T1 t1, T2 t2)
{
#if DEBUG && !DISABLE_DEBUG
CheckCache(translationCallback);
for (int i = 0, n = _process.Length < _markers.Length ? _process.Length : _markers.Length; i < n; i++)
{
_markers[i].Begin();
try
{
translationCallback(_process[i], t0, t1, t2);
}
catch (Exception e)
{
#if DISABLE_CATH_EXCEPTIONS
throw;
#endif
EcsDebug.PrintError(e);
}
_markers[i].End();
}
#else
foreach (var item in _process)
{
try
{
translationCallback(item, t0, t1, t2);
}
catch (Exception e)
{
#if DISABLE_CATH_EXCEPTIONS
throw;
#endif
EcsDebug.PrintError(e);
}
}
#endif
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Run<T0, T1, T2, T3>(Action<TProcess, T0, T1, T2, T3> translationCallback, T0 t0, T1 t1, T2 t2, T3 t3)
{
#if DEBUG && !DISABLE_DEBUG
CheckCache(translationCallback);
for (int i = 0, n = _process.Length < _markers.Length ? _process.Length : _markers.Length; i < n; i++)
{
_markers[i].Begin();
try
{
translationCallback(_process[i], t0, t1, t2, t3);
}
catch (Exception e)
{
#if DISABLE_CATH_EXCEPTIONS
throw;
#endif
EcsDebug.PrintError(e);
}
_markers[i].End();
}
#else
foreach (var item in _process)
{
try
{
translationCallback(item, t0, t1, t2, t3);
}
catch (Exception e)
{
#if DISABLE_CATH_EXCEPTIONS
throw;
#endif
EcsDebug.PrintError(e);
}
}
#endif
}
#pragma warning restore CS0162 // Обнаружен недостижимый код
//------------------------
#endregion #endregion
} }
#endregion #endregion
#region RunHelperWithFinally
#if DEBUG && !DISABLE_DEBUG
public
#else
public readonly
#endif
struct RunHelperWithFinally<TProcessFinally> where TProcessFinally : class, IEcsProcess
{
private readonly Pair[] _pairs;
#if DEBUG && !DISABLE_DEBUG
private Delegate _cacheCheck;
private Delegate _cacheCheckF;
private bool _cacheCheckInit;
private readonly EcsProfilerMarker[] _markers;
#endif
#region Constructors
public RunHelperWithFinally(EcsRunner<TProcess> runner) : this(runner,
#if DEBUG && !DISABLE_DEBUG
typeof(TProcess).ToMeta().Name)
#else
string.Empty)
#endif
{ }
public RunHelperWithFinally(EcsRunner<TProcess> runner, string methodName)
{
_pairs = new Pair[runner.Process.Length];
for (int i = 0; i < runner.Process.Length; i++)
{
_pairs[i] = new Pair(runner.Process[i]);
}
#if DEBUG && !DISABLE_DEBUG
_cacheCheck = null;
_cacheCheckF = null;
_cacheCheckInit = false;
_markers = new EcsProfilerMarker[_pairs.Length];
for (int i = 0; i < _pairs.Length; i++)
{
_markers[i] = new EcsProfilerMarker($"{_pairs[i].run.GetMeta().Name}.{methodName}");
}
#endif
}
#endregion
#region Utils
private readonly struct Pair
{
public readonly TProcess run;
public readonly TProcessFinally runFinally;
public Pair(TProcess run)
{
this.run = run;
runFinally = run as TProcessFinally;
}
}
#if DEBUG && !DISABLE_DEBUG
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void CheckCache(Delegate d, Delegate df)
{
if (_cacheCheckInit == false)
{
if (_cacheCheck == null)
{
_cacheCheck = d;
_cacheCheckF = df;
}
else
{
if (ReferenceEquals(_cacheCheck, d) == false || ReferenceEquals(_cacheCheckF, df) == false)
{
EcsDebug.PrintWarning("The delegate is not cached");
}
_cacheCheckInit = true;
}
}
}
#endif
#endregion
#region Do
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Run(
Action<TProcess> translationCallback,
Action<TProcessFinally> translationFinnalyCallback)
{
#if DEBUG && !DISABLE_DEBUG
CheckCache(translationCallback, translationFinnalyCallback);
for (int i = 0, n = _pairs.Length < _markers.Length ? _pairs.Length : _markers.Length; i < n; i++)
{
var pair = _pairs[i];
_markers[i].Begin();
try
{
translationCallback(pair.run);
}
catch (Exception e)
{
#if DISABLE_CATH_EXCEPTIONS
throw;
#endif
EcsDebug.PrintError(e);
}
finally
{
if(pair.runFinally != null)
{
translationFinnalyCallback(pair.runFinally);
}
}
_markers[i].End();
}
#else
foreach (var item in _pairs)
{
try
{
translationCallback(item.run);
}
catch (Exception e)
{
#if DISABLE_CATH_EXCEPTIONS
throw;
#endif
EcsDebug.PrintError(e);
}
finally
{
translationFinnalyCallback(item.runFinally);
}
}
#endif
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Run<TData>(
ActionWithData<TProcess, TData> translationCallback,
ActionWithData<TProcessFinally, TData> translationFinnalyCallback,
ref TData data)
{
#if DEBUG && !DISABLE_DEBUG
CheckCache(translationCallback, translationFinnalyCallback);
for (int i = 0, n = _pairs.Length < _markers.Length ? _pairs.Length : _markers.Length; i < n; i++)
{
var pair = _pairs[i];
_markers[i].Begin();
try
{
translationCallback(pair.run, ref data);
}
catch (Exception e)
{
#if DISABLE_CATH_EXCEPTIONS
throw;
#endif
EcsDebug.PrintError(e);
}
finally
{
if (pair.runFinally != null)
{
translationFinnalyCallback(pair.runFinally, ref data);
}
}
_markers[i].End();
}
#else
foreach (var pair in _pairs)
{
try
{
translationCallback(pair.run, t0);
}
catch (Exception e)
{
#if DISABLE_CATH_EXCEPTIONS
throw;
#endif
EcsDebug.PrintError(e);
}
finally
{
if (pair.runFinally != null)
{
translationFinnalyCallback(pair.runFinally, t0);
}
}
}
#endif
}
#endregion
}
#endregion
//----
} }
} }

View File

@ -20,13 +20,22 @@ namespace DCFApixels.DragonECS
} }
} }
internal readonly struct AspectCache<T> : IEcsWorldComponent<AspectCache<T>> internal readonly struct AspectCache<T> : IEcsWorldComponent<AspectCache<T>>
where T : EcsAspect, new() where T : new()
{ {
public readonly T Instance; public readonly T Instance;
public AspectCache(T instance) { Instance = instance; } public readonly EcsMask Mask;
public AspectCache(T instance, EcsMask mask)
{
Instance = instance;
Mask = mask;
}
void IEcsWorldComponent<AspectCache<T>>.Init(ref AspectCache<T> component, EcsWorld world) void IEcsWorldComponent<AspectCache<T>>.Init(ref AspectCache<T> component, EcsWorld world)
{ {
component = new AspectCache<T>(EcsAspect.Builder.New<T>(world)); #if DEBUG
AllowedInWorldsAttribute.CheckAllows<T>(world);
#endif
var result = EcsAspect.Builder.New<T>(world);
component = new AspectCache<T>(result.aspect, result.mask);
} }
void IEcsWorldComponent<AspectCache<T>>.OnDestroy(ref AspectCache<T> component, EcsWorld world) void IEcsWorldComponent<AspectCache<T>>.OnDestroy(ref AspectCache<T> component, EcsWorld world)
{ {
@ -36,7 +45,7 @@ namespace DCFApixels.DragonECS
internal readonly struct WhereQueryCache<TExecutor, TAspcet> : IEcsWorldComponent<WhereQueryCache<TExecutor, TAspcet>> internal readonly struct WhereQueryCache<TExecutor, TAspcet> : IEcsWorldComponent<WhereQueryCache<TExecutor, TAspcet>>
where TExecutor : MaskQueryExecutor, new() where TExecutor : MaskQueryExecutor, new()
where TAspcet : EcsAspect, new() where TAspcet : new()
{ {
public readonly TExecutor Executor; public readonly TExecutor Executor;
public readonly TAspcet Aspcet; public readonly TAspcet Aspcet;
@ -47,9 +56,9 @@ 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)
{ {
TAspcet aspect = world.GetAspect<TAspcet>(); TAspcet aspect = world.GetAspect<TAspcet>(out EcsMask mask);
TExecutor instance = world.GetExecutorForMask<TExecutor>(aspect.Mask); TExecutor instance = world.GetExecutorForMask<TExecutor>(mask);
instance.Initialize(world, aspect.Mask); instance.Initialize(world, mask);
component = new WhereQueryCache<TExecutor, TAspcet>(instance, aspect); component = new WhereQueryCache<TExecutor, TAspcet>(instance, aspect);
} }
void IEcsWorldComponent<WhereQueryCache<TExecutor, TAspcet>>.OnDestroy(ref WhereQueryCache<TExecutor, TAspcet> component, EcsWorld world) void IEcsWorldComponent<WhereQueryCache<TExecutor, TAspcet>>.OnDestroy(ref WhereQueryCache<TExecutor, TAspcet> component, EcsWorld world)

View File

@ -250,14 +250,21 @@ namespace DCFApixels.DragonECS
[UnityEngine.Scripting.Preserve] [UnityEngine.Scripting.Preserve]
#endif #endif
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public TAspect GetAspect<TAspect>() where TAspect : EcsAspect, new() public TAspect GetAspect<TAspect>() where TAspect : new()
{ {
return Get<AspectCache<TAspect>>().Instance; return Get<AspectCache<TAspect>>().Instance;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public TAspect GetAspect<TAspect>(out EcsMask mask) where TAspect : new()
{
var result = Get<AspectCache<TAspect>>();
mask = result.Mask;
return result.Instance;
}
[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 : MaskQueryExecutor, new() where TExecutor : MaskQueryExecutor, new()
where TAspect : EcsAspect, new() where TAspect : new()
{ {
ref var cmp = ref Get<WhereQueryCache<TExecutor, TAspect>>(); ref var cmp = ref Get<WhereQueryCache<TExecutor, TAspect>>();
executor = cmp.Executor; executor = cmp.Executor;
@ -270,6 +277,11 @@ namespace DCFApixels.DragonECS
return ref WorldComponentPool<T>.GetForWorld(ID); return ref WorldComponentPool<T>.GetForWorld(ID);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Has<T>() where T : struct
{
return WorldComponentPool<T>.Has(ID);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T GetUnchecked<T>() where T : struct public ref T GetUnchecked<T>() where T : struct
{ {
return ref WorldComponentPool<T>.GetForWorldUnchecked(ID); return ref WorldComponentPool<T>.GetForWorldUnchecked(ID);
@ -280,6 +292,11 @@ namespace DCFApixels.DragonECS
return ref WorldComponentPool<T>.GetForWorld(worldID); return ref WorldComponentPool<T>.GetForWorld(worldID);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Has<T>(short worldID) where T : struct
{
return WorldComponentPool<T>.Has(worldID);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref T GetUnchecked<T>(short worldID) where T : struct public static ref T GetUnchecked<T>(short worldID) where T : struct
{ {
return ref WorldComponentPool<T>.GetForWorldUnchecked(worldID); return ref WorldComponentPool<T>.GetForWorldUnchecked(worldID);
@ -874,6 +891,8 @@ namespace DCFApixels.DragonECS
#region Debug Components #region Debug Components
[ThreadStatic] [ThreadStatic]
private static int[] _componentIDsBuffer; private static int[] _componentIDsBuffer;
[ThreadStatic]
private static object[] _componentsBuffer;
public ReadOnlySpan<int> GetComponentTypeIDsFor(int entityID) public ReadOnlySpan<int> GetComponentTypeIDsFor(int entityID)
{ {
int count = GetComponentTypeIDsFor_Internal(entityID, ref _componentIDsBuffer); int count = GetComponentTypeIDsFor_Internal(entityID, ref _componentIDsBuffer);
@ -920,6 +939,19 @@ namespace DCFApixels.DragonECS
} }
} }
} }
public ReadOnlySpan<object> GetComponentsFor(int entityID)
{
int count = GetComponentTypeIDsFor_Internal(entityID, ref _componentIDsBuffer);
if (_componentsBuffer == null || _componentsBuffer.Length < count)
{
_componentsBuffer = new object[count];
}
for (int i = 0; i < count; i++)
{
_componentsBuffer[i] = _pools[_componentIDsBuffer[i]].GetRaw(entityID);
}
return new ReadOnlySpan<object>(_componentsBuffer, 0, count);
}
public void GetComponentsFor(int entityID, List<object> list) public void GetComponentsFor(int entityID, List<object> list)
{ {
list.Clear(); list.Clear();

View File

@ -169,6 +169,10 @@ namespace DCFApixels.DragonECS
Array.Resize(ref _items, _items.Length << 1); Array.Resize(ref _items, _items.Length << 1);
} }
#if DEBUG
AllowedInWorldsAttribute.CheckAllows<T>(_worlds[worldID]);
#endif
_interface.Init(ref _items[itemIndex], _worlds[worldID]); _interface.Init(ref _items[itemIndex], _worlds[worldID]);
var world = GetWorld(worldID); var world = GetWorld(worldID);

View File

@ -13,7 +13,7 @@ namespace DCFApixels.DragonECS
{ {
#region Where #region Where
public static EcsSpan Where<TCollection, TAspect>(this TCollection entities, out TAspect aspect) public static EcsSpan Where<TCollection, TAspect>(this TCollection entities, out TAspect aspect)
where TAspect : EcsAspect, new() where TAspect : new()
where TCollection : IEntityStorage where TCollection : IEntityStorage
{ {
if (ReferenceEquals(entities, entities.World)) if (ReferenceEquals(entities, entities.World))
@ -24,12 +24,12 @@ namespace DCFApixels.DragonECS
return entities.ToSpan().Where(out aspect); return entities.ToSpan().Where(out aspect);
} }
public static EcsSpan Where<TAspect>(this EcsReadonlyGroup group, out TAspect aspect) public static EcsSpan Where<TAspect>(this EcsReadonlyGroup group, out TAspect aspect)
where TAspect : EcsAspect, new() where TAspect : new()
{ {
return group.ToSpan().Where(out aspect); return group.ToSpan().Where(out aspect);
} }
public static EcsSpan Where<TAspect>(this EcsSpan span, out TAspect aspect) public static EcsSpan Where<TAspect>(this EcsSpan span, out TAspect aspect)
where TAspect : EcsAspect, new() where TAspect : new()
{ {
span.World.GetQueryCache(out EcsWhereExecutor executor, out aspect); span.World.GetQueryCache(out EcsWhereExecutor executor, out aspect);
return executor.ExecuteFor(span); return executor.ExecuteFor(span);
@ -58,7 +58,7 @@ namespace DCFApixels.DragonECS
#region Where with sort #region Where with sort
public static EcsSpan Where<TCollection, TAspect>(this TCollection entities, out TAspect aspect, Comparison<int> comparison) public static EcsSpan Where<TCollection, TAspect>(this TCollection entities, out TAspect aspect, Comparison<int> comparison)
where TAspect : EcsAspect, new() where TAspect : new()
where TCollection : IEntityStorage where TCollection : IEntityStorage
{ {
if (ReferenceEquals(entities, entities.World)) if (ReferenceEquals(entities, entities.World))
@ -69,12 +69,12 @@ namespace DCFApixels.DragonECS
return entities.ToSpan().Where(out aspect, comparison); return entities.ToSpan().Where(out aspect, comparison);
} }
public static EcsSpan Where<TAspect>(this EcsReadonlyGroup group, out TAspect aspect, Comparison<int> comparison) public static EcsSpan Where<TAspect>(this EcsReadonlyGroup group, out TAspect aspect, Comparison<int> comparison)
where TAspect : EcsAspect, new() where TAspect : new()
{ {
return group.ToSpan().Where(out aspect, comparison); return group.ToSpan().Where(out aspect, comparison);
} }
public static EcsSpan Where<TAspect>(this EcsSpan span, out TAspect aspect, Comparison<int> comparison) public static EcsSpan Where<TAspect>(this EcsSpan span, out TAspect aspect, Comparison<int> comparison)
where TAspect : EcsAspect, new() where TAspect : new()
{ {
span.World.GetQueryCache(out EcsWhereExecutor executor, out aspect); span.World.GetQueryCache(out EcsWhereExecutor executor, out aspect);
return executor.ExecuteFor(span, comparison); return executor.ExecuteFor(span, comparison);
@ -103,7 +103,7 @@ namespace DCFApixels.DragonECS
#region WhereToGroup #region WhereToGroup
public static EcsReadonlyGroup WhereToGroup<TCollection, TAspect>(this TCollection entities, out TAspect aspect) public static EcsReadonlyGroup WhereToGroup<TCollection, TAspect>(this TCollection entities, out TAspect aspect)
where TAspect : EcsAspect, new() where TAspect : new()
where TCollection : IEntityStorage where TCollection : IEntityStorage
{ {
if (ReferenceEquals(entities, entities.World)) if (ReferenceEquals(entities, entities.World))
@ -114,12 +114,12 @@ namespace DCFApixels.DragonECS
return entities.ToSpan().WhereToGroup(out aspect); return entities.ToSpan().WhereToGroup(out aspect);
} }
public static EcsReadonlyGroup WhereToGroup<TAspect>(this EcsReadonlyGroup group, out TAspect aspect) public static EcsReadonlyGroup WhereToGroup<TAspect>(this EcsReadonlyGroup group, out TAspect aspect)
where TAspect : EcsAspect, new() where TAspect : new()
{ {
return group.ToSpan().WhereToGroup(out aspect); return group.ToSpan().WhereToGroup(out aspect);
} }
public static EcsReadonlyGroup WhereToGroup<TAspect>(this EcsSpan span, out TAspect aspect) public static EcsReadonlyGroup WhereToGroup<TAspect>(this EcsSpan span, out TAspect aspect)
where TAspect : EcsAspect, new() where TAspect : new()
{ {
span.World.GetQueryCache(out EcsWhereToGroupExecutor executor, out aspect); span.World.GetQueryCache(out EcsWhereToGroupExecutor executor, out aspect);
return executor.ExecuteFor(span); return executor.ExecuteFor(span);

View File

@ -0,0 +1,43 @@
using DCFApixels.DragonECS.Internal;
using System;
namespace DCFApixels.DragonECS
{
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
public sealed class AllowedInWorldsAttribute : Attribute
{
public object[] AllowedWorlds;
public AllowedInWorldsAttribute(params object[] allowedWorlds)
{
AllowedWorlds = allowedWorlds;
}
public static void CheckAllows<T>(EcsWorld world)
{
Type componentType = typeof(T);
Type worldType = world.GetType();
if (componentType.TryGetAttribute(out AllowedInWorldsAttribute attribute))
{
foreach (var worldTag in attribute.AllowedWorlds)
{
bool result = false;
if (worldTag is Type worldTypeTag)
{
result = worldTypeTag == worldType;
}
else
{
string worldStringTag = worldTag.ToString();
result = world.Name == worldStringTag;
}
if (result)
{
return;
}
}
throw new EcsFrameworkException($"Using component {componentType.ToMeta().TypeName} is not allowed in the {worldType.ToMeta().TypeName} world.");
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a39694cb8b5876346968ef45a8272000
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: