diff --git a/BepInEx/Attributes.cs b/BepInEx/Attributes.cs new file mode 100644 index 0000000..4334cd1 --- /dev/null +++ b/BepInEx/Attributes.cs @@ -0,0 +1,52 @@ +using System; + +namespace BepInEx +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] + public class BepInPlugin : Attribute + { + /// + /// 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 specfic version of the plugin. + /// + 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; + } + } +} diff --git a/BepInEx/BaseUnityPlugin.cs b/BepInEx/BaseUnityPlugin.cs index 7341c58..670c322 100644 --- a/BepInEx/BaseUnityPlugin.cs +++ b/BepInEx/BaseUnityPlugin.cs @@ -8,19 +8,6 @@ namespace BepInEx /// public abstract class BaseUnityPlugin : MonoBehaviour { - /// - /// The unique identifier of the plugin. Should not change between plugin versions. - /// - public abstract string ID { get; } - /// - /// The user friendly name of the plugin. Is able to be changed between versions. - /// - public abstract string Name { get; } - - /// - /// The specfic version of the plugin. - /// - public abstract Version Version { get; } } -} +} \ No newline at end of file diff --git a/BepInEx/Chainloader.cs b/BepInEx/Chainloader.cs index a95c1c6..ea7468f 100644 --- a/BepInEx/Chainloader.cs +++ b/BepInEx/Chainloader.cs @@ -50,7 +50,9 @@ namespace BepInEx if (Directory.Exists(Utility.PluginsDirectory)) { - var pluginTypes = LoadTypes(Utility.PluginsDirectory); + var pluginTypes = TypeLoader.LoadTypes(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; } - /// - /// Checks all plugins to see if a plugin with a certain ID is loaded. - /// - /// The ID to check for. - /// - public static bool IsIDLoaded(string ID) + protected static IEnumerable TopologicalSort( + IEnumerable nodes, + Func> dependencySelector) { - foreach (var plugin in Plugins) - if (plugin != null && plugin.enabled && plugin.ID == ID) - return true; - return false; - } + List sorted_list = new List(); - /// - /// Loads a list of types from a directory containing assemblies, that derive from a base type. - /// - /// The specfiic base type to search for. - /// The directory to search for assemblies. - /// Returns a list of found derivative types. - public static List LoadTypes(string directory) - { - List types = new List(); - Type pluginType = typeof(T); + HashSet visited = new HashSet(); + HashSet sorted = new HashSet(); - foreach (string dll in Directory.GetFiles(Path.GetFullPath(directory), "*.dll")) + foreach (TNode input in nodes) + Visit(input); + + 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; } } } diff --git a/BepInEx/Config.cs b/BepInEx/Config.cs index 27baf68..9932978 100644 --- a/BepInEx/Config.cs +++ b/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 } diff --git a/BepInEx/ConfigWrapper.cs b/BepInEx/ConfigWrapper.cs index b8eebdc..0217fae 100644 --- a/BepInEx/ConfigWrapper.cs +++ b/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) diff --git a/BepInEx/Properties/AssemblyInfo.cs b/BepInEx/Properties/AssemblyInfo.cs index c168196..0bd46e1 100644 --- a/BepInEx/Properties/AssemblyInfo.cs +++ b/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")] diff --git a/BepInEx/TypeLoader.cs b/BepInEx/TypeLoader.cs new file mode 100644 index 0000000..9e366da --- /dev/null +++ b/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 + { + /// + /// Loads a list of types from a directory containing assemblies, that derive from a base type. + /// + /// The specfiic base type to search for. + /// The directory to search for assemblies. + /// Returns a list of found derivative types. + public static IEnumerable LoadTypes(string directory) + { + List types = new List(); + 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 GetDependencies(Type Plugin, IEnumerable AllPlugins) + { + object[] attributes = Plugin.GetCustomAttributes(typeof(BepInDependency), true); + + List dependencyTypes = new List(); + + 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; + } + } +}