using System; using System.Linq; using Mono.Cecil; using Version = SemanticVersioning.Version; namespace BepInEx.Preloader.Core.Patching; /// /// This attribute denotes that a class is a patcher plugin, and specifies the required metadata. /// [AttributeUsage(AttributeTargets.Class)] public class PatcherPluginInfoAttribute : Attribute { /// The unique identifier of the plugin. Should not change between plugin versions. /// The user friendly name of the plugin. Is able to be changed between versions. /// The specific version of the plugin. public PatcherPluginInfoAttribute(string GUID, string Name, string Version) { this.GUID = GUID; this.Name = Name; this.Version = TryParseLongVersion(Version); } /// /// The unique identifier of the plugin. Should not change between plugin versions. /// public string GUID { get; protected set; } /// /// The user friendly name of the plugin. Is able to be changed between versions. /// public string Name { get; protected set; } /// /// The specific version of the plugin. /// public Version Version { get; protected set; } private static Version TryParseLongVersion(string version) { if (Version.TryParse(version, out var v)) return v; // no System.Version.TryParse() on .NET 3.5 try { var longVersion = new System.Version(version); return new Version(longVersion.Major, longVersion.Minor, longVersion.Build != -1 ? longVersion.Build : 0); } catch { } return null; } internal static PatcherPluginInfoAttribute FromCecilType(TypeDefinition td) { var attr = MetadataHelper.GetCustomAttributes(td, false).FirstOrDefault(); if (attr == null) return null; return new PatcherPluginInfoAttribute((string) attr.ConstructorArguments[0].Value, (string) attr.ConstructorArguments[1].Value, (string) attr.ConstructorArguments[2].Value); } internal static PatcherPluginInfoAttribute FromType(Type type) { var attributes = type.GetCustomAttributes(typeof(PatcherPluginInfoAttribute), false); if (attributes.Length == 0) return null; return (PatcherPluginInfoAttribute) attributes[0]; } } /// /// Defines an assembly that a patch method will target. /// [AttributeUsage(AttributeTargets.Method)] public class TargetAssemblyAttribute : Attribute { /// /// Marker used to indicate all possible assemblies to be targeted by a patch method. /// public const string AllAssemblies = "_all"; /// /// The short filename of the assembly. Use to mark all possible /// assemblies as targets. /// public TargetAssemblyAttribute(string targetAssembly) { TargetAssembly = targetAssembly; } /// /// The short filename of the assembly to target. /// public string TargetAssembly { get; } } /// /// Defines a type that a patch method will target. /// [AttributeUsage(AttributeTargets.Method)] public class TargetTypeAttribute : Attribute { /// The short filename of the assembly of which belongs to. /// The full name of the type to target for patching. public TargetTypeAttribute(string targetAssembly, string targetType) { TargetAssembly = targetAssembly; TargetType = targetType; } /// /// The short filename of the assembly to target. /// public string TargetAssembly { get; } /// /// The full name of the type to target for patching. /// public string TargetType { get; } }