Use attributes instead of abstract properties for metadata

This commit is contained in:
Bepis committed 2018-04-01 01:43:47 +11:00
1 parent 0ac964a7ce
commit 2cc67b441b
7 files changed
+170 -62

No files matched your search

+52
View File
@@ -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
View File
@@ -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
View File
@@ -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 (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;
}
}
}
+3 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
}
}