Browse Source

Use attributes instead of abstract properties for metadata

Bepis 7 years ago
parent
commit
2cc67b441b

+ 52 - 0
BepInEx/Attributes.cs

@@ -0,0 +1,52 @@
+using System;
+
+namespace BepInEx
+{
+    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
+    public class BepInPlugin : Attribute
+    {
+        /// <summary>
+        /// The unique identifier of the plugin. Should not change between plugin versions.
+        /// </summary>
+        public string GUID { get; protected set; }
+
+        
+        /// <summary>
+        /// The user friendly name of the plugin. Is able to be changed between versions.
+        /// </summary>
+        public string Name { get; protected set; }
+
+        
+        /// <summary>
+        /// The specfic version of the plugin.
+        /// </summary>
+        public Version Version { get; protected set; }
+
+        public BepInPlugin(string GUID, string Name, Version Version)
+        {
+            this.GUID = GUID;
+            this.Name = Name;
+            this.Version = Version;
+        }
+    }
+
+    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+    public class BepInDependency : Attribute
+    {
+        public enum DependencyFlags
+        {
+            HardDependency = 1,
+            SoftDependency = 2
+        }
+
+        public string refGUID { get; protected set; }
+
+        public DependencyFlags Flags { get; protected set; }
+
+        public BepInDependency(string refGUID, DependencyFlags Flags = DependencyFlags.HardDependency)
+        {
+            this.refGUID = refGUID;
+            this.Flags = Flags;
+        }
+    }
+}

+ 1 - 14
BepInEx/BaseUnityPlugin.cs

@@ -8,19 +8,6 @@ namespace BepInEx
     /// </summary>
     public abstract class BaseUnityPlugin : MonoBehaviour
     {
-        /// <summary>
-        /// The unique identifier of the plugin. Should not change between plugin versions.
-        /// </summary>
-        public abstract string ID { get; }
 
-        /// <summary>
-        /// The user friendly name of the plugin. Is able to be changed between versions.
-        /// </summary>
-        public abstract string Name { get; }
-
-        /// <summary>
-        /// The specfic version of the plugin.
-        /// </summary>
-        public abstract Version Version { get; }
     }
-}
+}

+ 28 - 42
BepInEx/Chainloader.cs

@@ -50,7 +50,9 @@ namespace BepInEx
 
                 if (Directory.Exists(Utility.PluginsDirectory))
                 {
-                    var pluginTypes = LoadTypes<BaseUnityPlugin>(Utility.PluginsDirectory);
+                    var pluginTypes = TypeLoader.LoadTypes<BaseUnityPlugin>(Utility.PluginsDirectory).ToList();
+
+                    pluginTypes = TopologicalSort(pluginTypes, x => TypeLoader.GetDependencies(x, pluginTypes)).ToList();
 
                     BepInLogger.Log($"{pluginTypes.Count} plugins found");
 
@@ -58,7 +60,10 @@ namespace BepInEx
                     {
                         try
                         {
+                            var metadata = TypeLoader.GetMetadata(t);
+
                             var plugin = (BaseUnityPlugin)ManagerObject.AddComponent(t);
+
                             Plugins.Add(plugin);
                             BepInLogger.Log($"Loaded [{plugin.Name}]");
                         }
@@ -80,58 +85,39 @@ namespace BepInEx
             loaded = true;
         }
 
-        /// <summary>
-        /// Checks all plugins to see if a plugin with a certain ID is loaded.
-        /// </summary>
-        /// <param name="ID">The ID to check for.</param>
-        /// <returns></returns>
-        public static bool IsIDLoaded(string ID)
+        protected static IEnumerable<TNode> TopologicalSort<TNode>(
+            IEnumerable<TNode> nodes,
+            Func<TNode, IEnumerable<TNode>> dependencySelector)
         {
-            foreach (var plugin in Plugins)
-                if (plugin != null && plugin.enabled && plugin.ID == ID)
-                    return true;
 
-            return false;
-        }
+            List<TNode> sorted_list = new List<TNode>();
 
-        /// <summary>
-        /// Loads a list of types from a directory containing assemblies, that derive from a base type.
-        /// </summary>
-        /// <typeparam name="T">The specfiic base type to search for.</typeparam>
-        /// <param name="directory">The directory to search for assemblies.</param>
-        /// <returns>Returns a list of found derivative types.</returns>
-        public static List<Type> LoadTypes<T>(string directory)
-        {
-            List<Type> types = new List<Type>();
-            Type pluginType = typeof(T);
+            HashSet<TNode> visited = new HashSet<TNode>();
+            HashSet<TNode> sorted = new HashSet<TNode>();
+
+            foreach (TNode input in nodes)
+                Visit(input);
 
-            foreach (string dll in Directory.GetFiles(Path.GetFullPath(directory), "*.dll"))
+            return sorted_list;
+
+            void Visit(TNode node)
             {
-                try
+                if (visited.Contains(node))
                 {
-                    AssemblyName an = AssemblyName.GetAssemblyName(dll);
-                    Assembly assembly = Assembly.Load(an);
-
-                    foreach (Type type in assembly.GetTypes())
-                    {
-                        if (type.IsInterface || type.IsAbstract)
-                        {
-                            continue;
-                        }
-                        else
-                        {
-                            if (type.BaseType == pluginType)
-                                types.Add(type);
-                        }
-                    }
+                    if (!sorted.Contains(node))
+                        throw new Exception("Cyclic Dependency");
                 }
-                catch (BadImageFormatException)
+                else
                 {
+                    visited.Add(node);
 
+                    foreach (var dep in dependencySelector(node))
+                        Visit(dep);
+
+                    sorted.Add(node);
+                    sorted_list.Add(node);
                 }
             }
-
-            return types;
         }
     }
 }

+ 3 - 3
BepInEx/Config.cs

@@ -203,17 +203,17 @@ namespace BepInEx
 
         public static string GetEntry(this BaseUnityPlugin plugin, string key, string defaultValue = "")
         {
-            return GetEntry(key, defaultValue, plugin.ID);
+            return GetEntry(key, defaultValue, TypeLoader.GetMetadata(plugin).GUID);
         }
 
         public static void SetEntry(this BaseUnityPlugin plugin, string key, string value)
         {
-            SetEntry(key, value, plugin.ID);
+            SetEntry(key, value, TypeLoader.GetMetadata(plugin).GUID);
         }
 
         public static bool HasEntry(this BaseUnityPlugin plugin, string key)
         {
-            return HasEntry(key, plugin.ID);
+            return HasEntry(key, TypeLoader.GetMetadata(plugin).GUID);
         }
         #endregion Extensions
     }

+ 1 - 1
BepInEx/ConfigWrapper.cs

@@ -31,7 +31,7 @@ namespace BepInEx
 
         public ConfigWrapper(string key, BaseUnityPlugin plugin, T @default = default(T)) : this(key, @default)
         {
-            Section = plugin.ID;
+            Section = TypeLoader.GetMetadata(plugin).GUID;
         }
 
         public ConfigWrapper(string key, string section, T @default = default(T)) : this(key, @default)

+ 2 - 2
BepInEx/Properties/AssemblyInfo.cs

@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
 // You can specify all the values or you can default the Build and Revision Numbers
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: AssemblyVersion("3.0.0.0")]
+[assembly: AssemblyFileVersion("3.0.0.0")]

+ 83 - 0
BepInEx/TypeLoader.cs

@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+
+namespace BepInEx
+{
+    public static class TypeLoader
+    {
+        /// <summary>
+        /// Loads a list of types from a directory containing assemblies, that derive from a base type.
+        /// </summary>
+        /// <typeparam name="T">The specfiic base type to search for.</typeparam>
+        /// <param name="directory">The directory to search for assemblies.</param>
+        /// <returns>Returns a list of found derivative types.</returns>
+        public static IEnumerable<Type> LoadTypes<T>(string directory)
+        {
+            List<Type> types = new List<Type>();
+            Type pluginType = typeof(T);
+
+            foreach (string dll in Directory.GetFiles(Path.GetFullPath(directory), "*.dll"))
+            {
+                try
+                {
+                    AssemblyName an = AssemblyName.GetAssemblyName(dll);
+                    Assembly assembly = Assembly.Load(an);
+
+                    foreach (Type type in assembly.GetTypes())
+                    {
+                        if (type.IsInterface || type.IsAbstract)
+                        {
+                            continue;
+                        }
+                        else
+                        {
+                            if (type.BaseType == pluginType)
+                                types.Add(type);
+                        }
+                    }
+                }
+                catch (BadImageFormatException) { }
+            }
+
+            return types;
+        }
+
+        public static BepInPlugin GetMetadata(object Plugin)
+        {
+            return GetMetadata(Plugin.GetType());
+        }
+
+        public static BepInPlugin GetMetadata(Type PluginType)
+        {
+            object[] attributes = PluginType.GetCustomAttributes(typeof(BepInPlugin), false);
+
+            if (attributes.Length == 0)
+                return null;
+
+            return (BepInPlugin)attributes[0];
+        }
+
+        public static IEnumerable<Type> GetDependencies(Type Plugin, IEnumerable<Type> AllPlugins)
+        {
+            object[] attributes = Plugin.GetCustomAttributes(typeof(BepInDependency), true);
+
+            List<Type> dependencyTypes = new List<Type>();
+
+            foreach (BepInDependency dependency in attributes)
+            {
+                Type dependencyType = AllPlugins.FirstOrDefault(x => GetMetadata(x)?.GUID == dependency.refGUID);
+
+                if (dependencyType == null)
+                    throw new Exception("Cannot find dependency type.");
+
+                dependencyTypes.Add(dependencyType);
+            }
+
+            return dependencyTypes;
+        }
+    }
+}