using BetterAmongUs.Commands;
using BetterAmongUs.Modules.AntiCheat;
using System.Reflection;
using System.Runtime.Serialization;
namespace BetterAmongUs.Attributes;
///
/// Base attribute class for automatically discovering and registering instances of specific types through reflection.
///
internal abstract class AutoRegisterAttribute : Attribute
{
///
/// Scans the entire assembly and registers all instances of classes marked with subclasses.
///
internal static void Initialize()
{
var types = ModInfo.Assembly.GetTypes();
foreach (var type in types)
{
if (type.IsAbstract || !type.IsSealed)
continue;
if (!typeof(AutoRegisterAttribute).IsAssignableFrom(type))
continue;
var tempAttribute = (AutoRegisterAttribute)FormatterServices.GetUninitializedObject(type);
tempAttribute.Register();
}
}
///
/// When implemented in a derived class, registers individual instances.
///
protected abstract void Register();
}
///
/// Generic attribute for automatically registering static instances of a specified base type or interface.
///
/// The base type or interface that attributed classes must implement.
[AttributeUsage(AttributeTargets.Class)]
internal abstract class AutoRegisterAttribute : AutoRegisterAttribute where T : class
{
///
/// The collection of all discovered and registered instances of type .
///
protected static readonly List _instances = [];
///
/// Gets a read-only collection of all registered instances of type .
///
internal static IReadOnlyList Instances => _instances.AsReadOnly();
///
/// Retrieves a specific instance by its concrete type.
///
/// The concrete type of the instance to retrieve. Must inherit from or implement .
/// The instance of type if found, otherwise null.
internal static J? GetInstance() where J : T => (J?)_instances.FirstOrDefault(instance => instance.GetType() == typeof(J));
///
protected override void Register()
{
var types = ModInfo.Assembly.GetTypes();
foreach (var type in types)
{
if (type.GetCustomAttribute(GetType()) == null)
continue;
if (type.IsAbstract || type.IsInterface)
continue;
if (typeof(T).IsAssignableFrom(type))
{
var constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Type.EmptyTypes, null);
if (constructor != null)
{
if (constructor.Invoke(null) is T instance)
{
_instances.Add(instance);
}
}
}
}
}
}
// Class instances
internal sealed class RegisterCommandAttribute : AutoRegisterAttribute
{
}
internal sealed class RegisterRPCHandlerAttribute : AutoRegisterAttribute
{
}