From 9ebc5d15adfe72fdbc28ab9260e6182ba8e07b30 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Tue, 31 Oct 2023 03:19:33 +0800 Subject: [PATCH] add auto processes fix folder naming implementation of process methods without interfaces --- src/{Subject.meta => Aspect.meta} | 0 src/{Subject => Aspect}/EcsAspectAuto.cs | 0 src/{Subject => Aspect}/EcsAspectAuto.cs.meta | 0 src/AutoProcesses.meta | 8 + src/AutoProcesses/AutoProcesses.cs | 190 ++++++++++++++++++ src/AutoProcesses/AutoProcesses.cs.meta | 11 + 6 files changed, 209 insertions(+) rename src/{Subject.meta => Aspect.meta} (100%) rename src/{Subject => Aspect}/EcsAspectAuto.cs (100%) rename src/{Subject => Aspect}/EcsAspectAuto.cs.meta (100%) create mode 100644 src/AutoProcesses.meta create mode 100644 src/AutoProcesses/AutoProcesses.cs create mode 100644 src/AutoProcesses/AutoProcesses.cs.meta diff --git a/src/Subject.meta b/src/Aspect.meta similarity index 100% rename from src/Subject.meta rename to src/Aspect.meta diff --git a/src/Subject/EcsAspectAuto.cs b/src/Aspect/EcsAspectAuto.cs similarity index 100% rename from src/Subject/EcsAspectAuto.cs rename to src/Aspect/EcsAspectAuto.cs diff --git a/src/Subject/EcsAspectAuto.cs.meta b/src/Aspect/EcsAspectAuto.cs.meta similarity index 100% rename from src/Subject/EcsAspectAuto.cs.meta rename to src/Aspect/EcsAspectAuto.cs.meta diff --git a/src/AutoProcesses.meta b/src/AutoProcesses.meta new file mode 100644 index 0000000..3985245 --- /dev/null +++ b/src/AutoProcesses.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 940670c38bca2c046879c73a9b47043b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/AutoProcesses/AutoProcesses.cs b/src/AutoProcesses/AutoProcesses.cs new file mode 100644 index 0000000..375b870 --- /dev/null +++ b/src/AutoProcesses/AutoProcesses.cs @@ -0,0 +1,190 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace DCFApixels.DragonECS +{ + public static class AutoProcesses + { + private static Dictionary _builders; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryGetCustomAttribute(Type self, out T attribute) where T : Attribute + { + attribute = self.GetCustomAttribute(); + return attribute != null; + } + static AutoProcesses() + { + _builders = new Dictionary(); + foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) + { + var types = assembly.GetTypes(); + foreach (var type in types) + { + if (type.IsGenericType) + continue; + if (TryGetCustomAttribute(type, out EcsProcessWrapperBuilderAttribute attr)) + { + MethodInfo method = type.GetMethod(attr.wrapperBuilderMethodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + BuilderHandler action = (BuilderHandler)Delegate.CreateDelegate(typeof(BuilderHandler), null, method); + _builders.Add(attr.processMethodName, action); + } + } + } + } + public static EcsPipeline.Builder AddAuto(this EcsPipeline.Builder self, object system, string layerName = null) + { + var methods = system.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + foreach (var method in methods) + { + if(_builders.TryGetValue(method.Name, out var builder)) + { + var process = builder(system, method); + if(process != null) + self.Add(process, layerName); + } + } + if(system is IEcsProcess systemInterface) + self.Add(systemInterface, layerName); + return self; + } + private delegate IEcsProcess BuilderHandler(object targete, MethodInfo method); + } + + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false, AllowMultiple = false)] + sealed class EcsProcessWrapperBuilderAttribute : Attribute + { + public readonly string processMethodName; + public readonly string wrapperBuilderMethodName; + public EcsProcessWrapperBuilderAttribute(string processMethodName, string wrapperBuilderMethodName = "Builder") + { + this.processMethodName = processMethodName; + this.wrapperBuilderMethodName = wrapperBuilderMethodName; + } + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + internal class IEcsProcessWrapperBase + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool CheckParameters(MethodInfo method, out bool isHasParam) + { + var parametres = method.GetParameters(); + isHasParam = false; + if (parametres.Length != 0 && (parametres[0].ParameterType != typeof(EcsPipeline))) + return false; + isHasParam = parametres.Length > 0; + return true; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Action CreateEmptyAction(object target, MethodInfo method) + { + return (Action)Delegate.CreateDelegate(typeof(Action), target, method); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Action CreateAction(object target, MethodInfo method) + { + return (Action)Delegate.CreateDelegate(typeof(Action), target, method); + } + } + internal class IEcsProcessEmptyWrapper : IEcsProcessWrapperBase, IEcsDebugName + { + public object system; + public Action a; + public string DebugName => EcsDebugUtility.GetNameForObject(system); + } + internal class IEcsProcessWrapper : IEcsProcessWrapperBase, IEcsDebugName + { + public object system; + public Action a; + public string DebugName => EcsDebugUtility.GetNameForObject(system); + } + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + [EcsProcessWrapperBuilder(nameof(PreInit), nameof(Builder))] + internal class IEcsPreInitProcessEmptyWrapper : IEcsProcessEmptyWrapper, IEcsPreInitProcess + { + public IEcsPreInitProcessEmptyWrapper(object target, Action a) { system = target; this.a = a; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PreInit(EcsPipeline pipeline) => a(); + public static IEcsProcess Builder(object target, MethodInfo method) + { + if (target is IEcsPreInitProcess) return null; + if (CheckParameters(method, out bool isHasParam)) + if (isHasParam) new IEcsPreInitProcessWrapper(target, CreateAction(target, method)); + else new IEcsPreInitProcessEmptyWrapper(target, CreateEmptyAction(target, method)); + return null; + } + } + internal class IEcsPreInitProcessWrapper : IEcsProcessWrapper, IEcsPreInitProcess + { + public IEcsPreInitProcessWrapper(object target, Action a) { system = target; this.a = a; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PreInit(EcsPipeline pipeline) => a(pipeline); + } + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + [EcsProcessWrapperBuilder(nameof(Init), nameof(Builder))] + internal class IEcsInitProcessEmptyWrapper : IEcsProcessEmptyWrapper, IEcsInitProcess + { + public IEcsInitProcessEmptyWrapper(object target, Action a) { system = target; this.a = a; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Init(EcsPipeline pipeline) => a(); + public static IEcsProcess Builder(object target, MethodInfo method) + { + if (target is IEcsInitProcess) return null; + if (CheckParameters(method, out bool isHasParam)) + if (isHasParam) new IEcsInitProcessWrapper(target, CreateAction(target, method)); + else new IEcsInitProcessEmptyWrapper(target, CreateEmptyAction(target, method)); + return null; + } + } + internal class IEcsInitProcessWrapper: IEcsProcessWrapper, IEcsInitProcess + { + public IEcsInitProcessWrapper(object target, Action a) { system = target; this.a = a; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Init(EcsPipeline pipeline) => a(pipeline); + } + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + [EcsProcessWrapperBuilder(nameof(Run), nameof(Builder))] + internal class IEcsRunProcessEmptyWrapper : IEcsProcessEmptyWrapper, IEcsRunProcess + { + public IEcsRunProcessEmptyWrapper(object target, Action a) { system = target; this.a = a; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Run(EcsPipeline pipeline) => a(); + public static IEcsProcess Builder(object target, MethodInfo method) + { + if (target is IEcsRunProcess) return null; + if (CheckParameters(method, out bool isHasParam)) + if (isHasParam) new IEcsRunProcessWrapper(target, CreateAction(target, method)); + else new IEcsRunProcessEmptyWrapper(target, CreateEmptyAction(target, method)); + return null; + } + } + internal class IEcsRunProcessWrapper : IEcsProcessWrapper, IEcsRunProcess + { + public IEcsRunProcessWrapper(object target, Action a) { system = target; this.a = a; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Run(EcsPipeline pipeline) => a(pipeline); + } + /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + [EcsProcessWrapperBuilder(nameof(Destroy), nameof(Builder))] + internal class IEcsDestroyProcessEmptyWrapper : IEcsProcessEmptyWrapper, IEcsDestroyProcess + { + public IEcsDestroyProcessEmptyWrapper(object target, Action a) { system = target; this.a = a; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Destroy(EcsPipeline pipeline) => a(); + public static IEcsProcess Builder(object target, MethodInfo method) + { + if (target is IEcsDestroyProcess) return null; + if (CheckParameters(method, out bool isHasParam)) + if (isHasParam) new IEcsDestroyProcessWrapper(target, CreateAction(target, method)); + else new IEcsDestroyProcessEmptyWrapper(target, CreateEmptyAction(target, method)); + return null; + } + } + internal class IEcsDestroyProcessWrapper : IEcsProcessWrapper, IEcsDestroyProcess + { + public IEcsDestroyProcessWrapper(object target, Action a) { system = target; this.a = a; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Destroy(EcsPipeline pipeline) => a(pipeline); + } +} diff --git a/src/AutoProcesses/AutoProcesses.cs.meta b/src/AutoProcesses/AutoProcesses.cs.meta new file mode 100644 index 0000000..666cd6b --- /dev/null +++ b/src/AutoProcesses/AutoProcesses.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b12c6a19f3706144c80a1d33f86ec659 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: