DragonECS/src/EcsRunner.cs

396 lines
14 KiB
C#
Raw Normal View History

using DCFApixels.DragonECS.Internal;
using DCFApixels.DragonECS.RunnersCore;
using System;
using System.Linq;
2024-10-31 14:48:56 +08:00
using System.Runtime.CompilerServices;
2023-05-26 04:25:09 +08:00
using static DCFApixels.DragonECS.EcsDebugUtility;
namespace DCFApixels.DragonECS
{
2024-06-13 18:04:18 +08:00
[MetaColor(MetaColor.DragonRose)]
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.OTHER_GROUP)]
[MetaDescription(EcsConsts.AUTHOR, "...")]
[MetaTags(MetaTags.HIDDEN)]
2024-10-12 00:08:12 +08:00
[MetaID("EF8A557C9201E6F04D4A76DC670BDE19")]
2024-06-05 14:39:19 +08:00
public interface IEcsProcess : IEcsMember { }
2023-03-16 01:49:14 +08:00
2023-04-23 17:55:01 +08:00
namespace RunnersCore
{
public abstract class EcsRunner
{
internal abstract void Init_Internal(EcsPipeline source);
#region CheckRunnerValide
public static void CheckRunnerTypeIsValide(Type runnerType, Type processInterfaceType)
{
#region DEBUG
#pragma warning disable IL2070 // 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The parameter of method does not have matching annotations.
Type targetInterface = processInterfaceType;
if (runnerType.IsAbstract || runnerType.IsInterface)
{
2024-11-06 19:55:33 +08:00
Throw.Exception("The instance of a runner cannot be abstract.");
}
2024-01-08 13:39:38 +08:00
Type GetRunnerBaseType(Type inType)
{
2024-01-08 13:39:38 +08:00
if (inType.IsGenericType && inType.GetGenericTypeDefinition() == typeof(EcsRunner<>))
{
2024-01-08 13:39:38 +08:00
return inType;
}
2024-01-08 13:39:38 +08:00
if (inType.BaseType != null)
{
2024-01-08 13:39:38 +08:00
return GetRunnerBaseType(inType.BaseType);
}
return null;
}
Type baseType = GetRunnerBaseType(runnerType);
Type baseTypeArgument = baseType.GenericTypeArguments[0];
if (baseTypeArgument != targetInterface)
{
Throw.UndefinedException();
}
if (!runnerType.GetInterfaces().Any(o => o == targetInterface))
{
throw new EcsRunnerImplementationException($"Runner {GetGenericTypeFullName(runnerType, 1)} does not implement interface {GetGenericTypeFullName(baseTypeArgument, 1)}.");
}
#pragma warning restore IL2070 // 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The parameter of method does not have matching annotations.
#endregion
2023-04-23 17:55:01 +08:00
}
#endregion
}
2024-06-13 18:04:18 +08:00
[MetaColor(MetaColor.DragonRose)]
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.OTHER_GROUP)]
[MetaDescription(EcsConsts.AUTHOR, "...")]
[MetaTags(MetaTags.HIDDEN)]
2024-10-12 00:08:12 +08:00
[MetaID("E49B557C92010E46DF1602972BC988BC")]
public interface IEcsRunner : IEcsProcess
{
EcsPipeline Pipeline { get; }
Type Interface { get; }
EcsProcessRaw ProcessRaw { get; }
bool IsEmpty { get; }
}
2024-10-31 14:48:56 +08:00
//TODO добавить функцию фильтрации систем по string, за счет создания отдельных ранеров для отдельных string
2024-06-13 18:04:18 +08:00
[MetaColor(MetaColor.DragonRose)]
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.OTHER_GROUP)]
[MetaDescription(EcsConsts.AUTHOR, "...")]
[MetaTags(MetaTags.HIDDEN)]
2024-10-12 00:08:12 +08:00
[MetaID("7DB3557C9201F85E0E1C17D7B19D9CEE")]
public abstract class EcsRunner<TProcess> : EcsRunner, IEcsRunner, IEcsProcess
where TProcess : IEcsProcess
{
2023-04-23 17:55:01 +08:00
private EcsPipeline _source;
private EcsProcess<TProcess> _process;
private bool _isInit = false;
2023-03-26 11:19:03 +08:00
2023-04-23 17:55:01 +08:00
#region Properties
public EcsPipeline Pipeline
{
get { return _source; }
}
public Type Interface
{
get { return typeof(TProcess); }
}
public EcsProcessRaw ProcessRaw
{
get { return _process; }
}
public EcsProcess<TProcess> Process
{
get { return _process; }
}
public bool IsEmpty
{
2024-02-22 23:48:10 +08:00
get { return _process.IsNullOrEmpty; }
}
2023-04-23 17:55:01 +08:00
#endregion
2023-03-27 17:34:12 +08:00
#region Constructor Init OnSetup
public EcsRunner() { }
internal override sealed void Init_Internal(EcsPipeline source)
2023-04-23 17:55:01 +08:00
{
if (_isInit)
{
2024-04-22 17:49:24 +08:00
Throw.Exception("Reinitialization.");
}
_isInit = true;
2023-04-23 17:55:01 +08:00
_source = source;
_process = source.GetProcess<TProcess>();
2023-04-23 17:55:01 +08:00
OnSetup();
}
protected virtual void OnSetup() { }
#endregion
2024-10-31 14:48:56 +08:00
#region Simple
public struct RunHelper
{
private readonly EcsProcess<TProcess> _process;
2024-10-31 15:27:53 +08:00
#if DEBUG && !DISABLE_DEBUG
2024-10-31 14:48:56 +08:00
private Delegate _cacheCheck;
private bool _cacheCheckInit;
private readonly EcsProfilerMarker[] _markers;
#endif
#region Constructors
2024-11-06 20:17:07 +08:00
public RunHelper(EcsRunner<TProcess> runner) : this(runner,
#if DEBUG && !DISABLE_DEBUG
typeof(TProcess).ToMeta().Name)
#else
string.Empty
#endif
{ }
2024-10-31 15:27:53 +08:00
public RunHelper(EcsRunner<TProcess> runner, string methodName)
2024-10-31 14:48:56 +08:00
{
_process = runner.Process;
2024-10-31 15:27:53 +08:00
#if DEBUG && !DISABLE_DEBUG
2024-10-31 14:48:56 +08:00
_cacheCheck = null;
_cacheCheckInit = false;
_markers = new EcsProfilerMarker[_process.Length];
for (int i = 0; i < _process.Length; i++)
{
_markers[i] = new EcsProfilerMarker($"{_process[i].GetMeta().Name}.{methodName}");
}
#endif
}
#endregion
2024-10-31 14:53:08 +08:00
#region Utils
2024-10-31 15:27:53 +08:00
#if DEBUG && !DISABLE_DEBUG
2024-10-31 14:48:56 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void CheckCache(Delegate d)
{
if (_cacheCheckInit == false)
{
if (_cacheCheck == null)
{
_cacheCheck = d;
}
else
{
if (ReferenceEquals(_cacheCheck, d) == false)
{
EcsDebug.PrintWarning("The delegate is not cached");
}
_cacheCheckInit = true;
}
}
}
2024-10-31 15:27:53 +08:00
#endif
2024-10-31 14:48:56 +08:00
#endregion
#region Do
2024-10-31 15:27:53 +08:00
#pragma warning disable CS0162 // Обнаружен недостижимый код
2024-10-31 14:48:56 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-10-31 14:53:08 +08:00
public void Run(Action<TProcess> translationCallback)
2024-10-31 14:48:56 +08:00
{
#if DEBUG && !DISABLE_DEBUG
2024-10-31 15:27:53 +08:00
CheckCache(translationCallback);
2024-10-31 14:48:56 +08:00
for (int i = 0, n = _process.Length < _markers.Length ? _process.Length : _markers.Length; i < n; i++)
{
_markers[i].Begin();
try
{
translationCallback(_process[i]);
}
catch (Exception e)
{
#if DISABLE_CATH_EXCEPTIONS
throw;
#endif
EcsDebug.PrintError(e);
}
_markers[i].End();
}
#else
foreach (var item in _process)
{
try
{
translationCallback(item);
}
catch (Exception e)
{
#if DISABLE_CATH_EXCEPTIONS
throw;
#endif
EcsDebug.PrintError(e);
}
}
#endif
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-10-31 15:27:53 +08:00
public void Run<T0>(Action<TProcess, T0> translationCallback, T0 t0)
2024-10-31 14:48:56 +08:00
{
#if DEBUG && !DISABLE_DEBUG
2024-10-31 15:27:53 +08:00
CheckCache(translationCallback);
2024-10-31 14:48:56 +08:00
for (int i = 0, n = _process.Length < _markers.Length ? _process.Length : _markers.Length; i < n; i++)
{
_markers[i].Begin();
try
{
translationCallback(_process[i], t0);
}
catch (Exception e)
{
#if DISABLE_CATH_EXCEPTIONS
throw;
#endif
EcsDebug.PrintError(e);
}
_markers[i].End();
}
#else
foreach (var item in _process)
{
try
{
2024-10-31 15:27:53 +08:00
translationCallback(item, t0);
2024-10-31 14:48:56 +08:00
}
catch (Exception e)
{
#if DISABLE_CATH_EXCEPTIONS
throw;
#endif
EcsDebug.PrintError(e);
}
}
#endif
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-10-31 15:27:53 +08:00
public void Run<T0, T1>(Action<TProcess, T0, T1> translationCallback, T0 t0, T1 t1)
2024-10-31 14:48:56 +08:00
{
#if DEBUG && !DISABLE_DEBUG
2024-10-31 15:27:53 +08:00
CheckCache(translationCallback);
2024-10-31 14:48:56 +08:00
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
{
2024-10-31 15:27:53 +08:00
translationCallback(item, t0, t1);
2024-10-31 14:48:56 +08:00
}
catch (Exception e)
{
#if DISABLE_CATH_EXCEPTIONS
throw;
#endif
EcsDebug.PrintError(e);
}
}
#endif
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-10-31 15:27:53 +08:00
public void Run<T0, T1, T2>(Action<TProcess, T0, T1, T2> translationCallback, T0 t0, T1 t1, T2 t2)
2024-10-31 14:48:56 +08:00
{
#if DEBUG && !DISABLE_DEBUG
2024-10-31 15:27:53 +08:00
CheckCache(translationCallback);
2024-10-31 14:48:56 +08:00
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
{
2024-10-31 15:27:53 +08:00
translationCallback(item, t0, t1, t2);
2024-10-31 14:48:56 +08:00
}
catch (Exception e)
{
#if DISABLE_CATH_EXCEPTIONS
throw;
#endif
EcsDebug.PrintError(e);
}
}
#endif
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-10-31 15:27:53 +08:00
public void Run<T0, T1, T2, T3>(Action<TProcess, T0, T1, T2, T3> translationCallback, T0 t0, T1 t1, T2 t2, T3 t3)
2024-10-31 14:48:56 +08:00
{
#if DEBUG && !DISABLE_DEBUG
2024-11-01 14:04:19 +08:00
CheckCache(translationCallback);
2024-10-31 14:48:56 +08:00
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
{
2024-10-31 15:27:53 +08:00
translationCallback(item, t0, t1, t2, t3);
2024-10-31 14:48:56 +08:00
}
catch (Exception e)
{
#if DISABLE_CATH_EXCEPTIONS
throw;
#endif
EcsDebug.PrintError(e);
}
}
#endif
}
2024-10-31 15:27:53 +08:00
#pragma warning restore CS0162 // Обнаружен недостижимый код
2024-10-31 14:48:56 +08:00
//------------------------
#endregion
}
#endregion
2023-04-23 17:55:01 +08:00
}
}
2023-05-26 04:25:09 +08:00
2023-03-30 01:57:10 +08:00
#region Extensions
public static class IEcsProcessExtensions
2023-03-30 01:57:10 +08:00
{
public static bool IsRunner(this IEcsProcess self)
2023-03-30 01:57:10 +08:00
{
return self is IEcsRunner;
}
}
#endregion
2024-10-31 14:48:56 +08:00
}