This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ShrinkCommand
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
|
||||
public sealed class ShrinkCommandStaticRegistryAttribute : Attribute
|
||||
{
|
||||
public ShrinkCommandStaticRegistryAttribute(params Type[] subscriberTypes)
|
||||
{
|
||||
SubscriberTypes = subscriberTypes ?? Array.Empty<Type>();
|
||||
}
|
||||
|
||||
public Type[] SubscriberTypes { get; }
|
||||
}
|
||||
|
||||
internal static class ShrinkCommandGeneratedRegistry
|
||||
{
|
||||
public static IReadOnlyList<Type> GetStaticSubscriberTypes()
|
||||
{
|
||||
var types = new List<Type>();
|
||||
var seen = new HashSet<Type>();
|
||||
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
object[] attributes;
|
||||
try
|
||||
{
|
||||
attributes = assembly.GetCustomAttributes(typeof(ShrinkCommandStaticRegistryAttribute), false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var attribute in attributes.OfType<ShrinkCommandStaticRegistryAttribute>())
|
||||
{
|
||||
foreach (var subscriberType in attribute.SubscriberTypes ?? Array.Empty<Type>())
|
||||
{
|
||||
if (subscriberType == null || !seen.Add(subscriberType))
|
||||
continue;
|
||||
|
||||
types.Add(subscriberType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
public static void RegisterAll(ShrinkCommandService service)
|
||||
{
|
||||
if (service == null)
|
||||
throw new ArgumentNullException(nameof(service));
|
||||
|
||||
ShrinkCommandRegHelper.RegisterStaticCommandSubscriberTypes(service, GetStaticSubscriberTypes());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bf0049e5e80e56c469f020266fbe0ace
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,116 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ShrinkCommand
|
||||
{
|
||||
public static class ShrinkCommandRegHelper
|
||||
{
|
||||
public static void RegisterStaticCommands(ShrinkCommandService service)
|
||||
{
|
||||
if (service == null)
|
||||
throw new ArgumentNullException(nameof(service));
|
||||
|
||||
RegisterStaticCommandSubscriberTypes(service, ShrinkCommandGeneratedRegistry.GetStaticSubscriberTypes());
|
||||
}
|
||||
|
||||
public static void RegisterCommands(ShrinkCommandService service, object? target)
|
||||
{
|
||||
if (service == null)
|
||||
throw new ArgumentNullException(nameof(service));
|
||||
|
||||
RegisterCommandsInternal(service, target);
|
||||
}
|
||||
|
||||
public static void RegisterStaticCommandSubscriberTypes(
|
||||
ShrinkCommandService service,
|
||||
IEnumerable<Type> subscriberTypes)
|
||||
{
|
||||
if (service == null)
|
||||
throw new ArgumentNullException(nameof(service));
|
||||
if (subscriberTypes == null)
|
||||
throw new ArgumentNullException(nameof(subscriberTypes));
|
||||
|
||||
foreach (var type in subscriberTypes)
|
||||
{
|
||||
if (type == null || type.GetCustomAttribute<ShrinkCommandSubscriberAttribute>(false) == null)
|
||||
continue;
|
||||
|
||||
ScanMethodsAndRegister(service, null, type,
|
||||
type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
|
||||
}
|
||||
}
|
||||
|
||||
private static void RegisterCommandsInternal(ShrinkCommandService service, object? target)
|
||||
{
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
var ownerType = target.GetType();
|
||||
if (ownerType.GetCustomAttribute<ShrinkCommandSubscriberAttribute>(false) == null)
|
||||
return;
|
||||
|
||||
ScanMethodsAndRegister(service, target, ownerType,
|
||||
ownerType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic));
|
||||
}
|
||||
|
||||
private static void ScanMethodsAndRegister(
|
||||
ShrinkCommandService service,
|
||||
object? target,
|
||||
Type ownerType,
|
||||
MethodInfo[] methods)
|
||||
{
|
||||
foreach (var method in methods)
|
||||
{
|
||||
if (target != null && method.IsStatic)
|
||||
continue;
|
||||
|
||||
var attributes = method.GetCustomAttributes(typeof(ShrinkCommandAttribute), false)
|
||||
.Cast<ShrinkCommandAttribute>()
|
||||
.ToArray();
|
||||
if (attributes.Length == 0)
|
||||
continue;
|
||||
|
||||
foreach (var attribute in attributes)
|
||||
{
|
||||
try
|
||||
{
|
||||
service.RegisterCommand(new ShrinkCommandRegistration
|
||||
{
|
||||
Path = attribute.Path,
|
||||
Aliases = attribute.Aliases ?? Array.Empty<string>(),
|
||||
Description = attribute.Description,
|
||||
Permission = attribute.Permission,
|
||||
SourceKind = attribute.SourceKind,
|
||||
Hidden = attribute.Hidden,
|
||||
Handler = ShrinkCommandMethodAdapter.BuildHandler(target, method,
|
||||
ParseArgumentNames(attribute.Path))
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ShrinkCommandLogger.Warn(
|
||||
$"[ShrinkCommand] Failed to register {ownerType.FullName}.{method.Name}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string[] ParseArgumentNames(string path)
|
||||
{
|
||||
return path.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Where(token => token.Length >= 3 && token[0] == '<' && token[token.Length - 1] == '>')
|
||||
.Select(token =>
|
||||
{
|
||||
var name = token.Substring(1, token.Length - 2).Trim();
|
||||
if (name.EndsWith("...", StringComparison.Ordinal))
|
||||
name = name.Substring(0, name.Length - 3).Trim();
|
||||
return name;
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 14f2978c6779a9842bb62ac369b0cf53
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user