Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions BepInEx.Core/Bootstrap/BaseChainloader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,18 @@

namespace BepInEx.Bootstrap;

/// <summary>Base chainloader used to load and manage plugins.</summary>
public abstract class BaseChainloader<TPlugin>
{
/// <summary>Name of the currently executing BepInEx assembly.</summary>
protected static readonly string CurrentAssemblyName = Assembly.GetExecutingAssembly().GetName().Name;
/// <summary>Version of the currently executing BepInEx assembly.</summary>
protected static readonly Version CurrentAssemblyVersion = Assembly.GetExecutingAssembly().GetName().Version;
private static readonly Dictionary<string, bool> RefCache = new();
private static Regex allowedGuidRegex { get; } = new(@"^[a-zA-Z0-9\._\-]+$");

/// <summary>
/// Analyzes the given type definition and attempts to convert it to a valid <see cref="PluginInfo" />
/// Analyzes the given type definition and attempts to convert it to a valid <see cref="PluginInfo" />
/// </summary>
/// <param name="type">Type definition to analyze.</param>
/// <param name="assemblyLocation">The filepath of the assembly, to keep as metadata.</param>
Expand Down Expand Up @@ -117,6 +120,9 @@ static bool ReferencesThisAssembly(AssemblyDefinition ass, HashSet<string> seen
}
return RefCache[key] = false;
}
/// <summary>Checks whether the assembly contains loadable plugins.</summary>
/// <param name="ass">Assembly definition to check.</param>
/// <returns>True if the assembly references BepInEx and contains plugin types, otherwise false.</returns>
protected static bool HasBepinPlugins(AssemblyDefinition ass)
{
if (!ReferencesThisAssembly(ass))
Expand All @@ -129,6 +135,9 @@ protected static bool HasBepinPlugins(AssemblyDefinition ass)
return true;
}

/// <summary>Checks whether the plugin targets an incompatible BepInEx version.</summary>
/// <param name="pluginInfo">Plugin metadata to check.</param>
/// <returns>True if the plugin targets a different BepInEx version, otherwise false.</returns>
protected static bool PluginTargetsWrongBepin(PluginInfo pluginInfo)
{
var pluginTarget = pluginInfo.TargettedBepInExVersion;
Expand All @@ -141,31 +150,34 @@ protected static bool PluginTargetsWrongBepin(PluginInfo pluginInfo)

#region Contract

/// <summary>Title displayed on the BepInEx console window.</summary>
protected virtual string ConsoleTitle => $"BepInEx {Utility.BepInExVersion} - {Paths.ProcessName}";

private bool _initialized;

/// <summary>
/// List of all <see cref="PluginInfo" /> instances loaded via the chainloader.
/// List of all <see cref="PluginInfo" /> instances loaded via the chainloader.
/// </summary>
public Dictionary<string, PluginInfo> Plugins { get; } = new();

/// <summary>
/// Collection of error chainloader messages that occured during plugin loading.
/// Contains information about what certain plugins were not loaded.
/// Collection of error chainloader messages that occured during plugin loading.
/// Contains information about what certain plugins were not loaded.
/// </summary>
public List<string> DependencyErrors { get; } = new();

/// <summary>
/// Occurs after a plugin is loaded.
/// Occurs after a plugin is loaded.
/// </summary>
public event Action<PluginInfo> PluginLoaded;

/// <summary>
/// Occurs after all plugins are loaded.
/// Occurs after all plugins are loaded.
/// </summary>
public event Action Finished;

/// <summary>Initializes the chainloader and loads all plugins.</summary>
/// <param name="gameExePath">Path to the game executable. If null, paths must already be initialized.</param>
public virtual void Initialize(string gameExePath = null)
{
if (_initialized)
Expand All @@ -190,6 +202,7 @@ public virtual void Initialize(string gameExePath = null)
Logger.Log(LogLevel.Message, "Chainloader initialized");
}

/// <summary>Initializes the console and disk loggers.</summary>
protected virtual void InitializeLoggers()
{
if (ConsoleManager.ConsoleEnabled && !ConsoleManager.ConsoleActive)
Expand Down Expand Up @@ -550,6 +563,10 @@ private static void TryRunModuleCtor(PluginInfo plugin, Assembly assembly)
}
}

/// <summary>Loads a plugin from the given assembly.</summary>
/// <param name="pluginInfo">Metadata of the plugin to load.</param>
/// <param name="pluginAssembly">Assembly containing the plugin.</param>
/// <returns>The loaded plugin instance.</returns>
public abstract TPlugin LoadPlugin(PluginInfo pluginInfo, Assembly pluginAssembly);

#endregion
Expand Down
50 changes: 28 additions & 22 deletions BepInEx.Core/Bootstrap/TypeLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,64 +11,64 @@
namespace BepInEx.Bootstrap;

/// <summary>
/// A cacheable metadata item. Can be used with <see cref="TypeLoader.LoadAssemblyCache{T}" /> and
/// <see cref="TypeLoader.SaveAssemblyCache{T}" /> to cache plugin metadata.
/// A cacheable metadata item. Can be used with <see cref="TypeLoader.LoadAssemblyCache{T}" /> and
/// <see cref="TypeLoader.SaveAssemblyCache{T}" /> to cache plugin metadata.
/// </summary>
public interface ICacheable
{
/// <summary>
/// Serialize the object into a binary format.
/// Serialize the object into a binary format.
/// </summary>
/// <param name="bw"></param>
void Save(BinaryWriter bw);

/// <summary>
/// Loads the object from binary format.
/// Loads the object from binary format.
/// </summary>
/// <param name="br"></param>
void Load(BinaryReader br);
}

/// <summary>
/// A cached assembly.
/// A cached assembly.
/// </summary>
/// <typeparam name="T"></typeparam>
public class CachedAssembly<T> where T : ICacheable
{
/// <summary>
/// List of cached items inside the assembly.
/// List of cached items inside the assembly.
/// </summary>
public List<T> CacheItems { get; set; }

/// <summary>
/// Hash of the assembly. Used to verify that the assembly hasn't been changed.
/// Hash of the assembly. Used to verify that the assembly hasn't been changed.
/// </summary>
public string Hash { get; set; }
}

/// <summary>
/// Provides methods for loading specified types from an assembly.
/// Provides methods for loading specified types from an assembly.
/// </summary>
public static class TypeLoader
{
/// <summary>
/// Default assembly resolved used by the <see cref="TypeLoader" />
/// Default assembly resolved used by the <see cref="TypeLoader" />
/// </summary>
public static readonly DefaultAssemblyResolver CecilResolver;

/// <summary>
/// Default reader parameters used by <see cref="TypeLoader" />
/// Default reader parameters used by <see cref="TypeLoader" />
/// </summary>
public static readonly ReaderParameters ReaderParameters;

/// <summary>Additional directories searched when resolving assemblies.</summary>
public static HashSet<string> SearchDirectories = new();

private static readonly Dictionary<string, string> AssemblyPathByName = new(StringComparer.InvariantCultureIgnoreCase);

/// <summary>
/// Maps every managed assembly file in a directory to its assembly name, so files whose
/// filename does not match the assembly name (e.g. renamed by the user) still resolve.
/// First file wins when two files share an assembly name.
/// Maps every managed assembly file in a directory to its assembly name, so files whose filename does not match the assembly name (e.g. renamed by the user) still resolve.
/// First file wins when two files share an assembly name.
/// </summary>
public static void RegisterAssemblyPaths(string directory)
{
Expand All @@ -92,6 +92,10 @@ public static void RegisterAssemblyPaths(string directory)
}
}

/// <summary>Tries to get the registered file path of an assembly.</summary>
/// <param name="name">Name of the assembly to look up.</param>
/// <param name="path">File path of the assembly, if registered.</param>
/// <returns>True if the assembly path was found and exists, otherwise false.</returns>
public static bool TryGetRegisteredAssemblyPath(string name, out string path) =>
AssemblyPathByName.TryGetValue(name, out path) && File.Exists(path);

Expand All @@ -112,6 +116,10 @@ static TypeLoader()
CecilResolver.ResolveFailure += CecilResolveOnFailure;
}

/// <summary>Resolves Cecil assembly references that failed the default resolution.</summary>
/// <param name="sender">Source of the event.</param>
/// <param name="reference">Reference of the assembly that failed to resolve.</param>
/// <returns>The resolved assembly definition, or null if it could not be resolved.</returns>
public static AssemblyDefinition CecilResolveOnFailure(object sender, AssemblyNameReference reference)
{
if (!Utility.TryParseAssemblyName(reference.FullName, out var name))
Expand Down Expand Up @@ -149,21 +157,20 @@ public static AssemblyDefinition CecilResolveOnFailure(object sender, AssemblyNa
}

/// <summary>
/// Event fired when <see cref="TypeLoader" /> fails to resolve a type during type loading.
/// Event fired when <see cref="TypeLoader" /> fails to resolve a type during type loading.
/// </summary>
public static event AssemblyResolveEventHandler AssemblyResolve;

/// <summary>
/// Looks up assemblies in the given directory and locates all types that can be loaded and collects their metadata.
/// Looks up assemblies in the given directory and locates all types that can be loaded and collects their metadata.
/// </summary>
/// <typeparam name="T">The specific base type to search for.</typeparam>
/// <param name="directory">The directory to search for assemblies.</param>
/// <param name="typeSelector">A function to check if a type should be selected and to build the type metadata.</param>
/// <param name="assemblyFilter">A filter function to quickly determine if the assembly can be loaded.</param>
/// <param name="cacheName">The name of the cache to get cached types from.</param>
/// <returns>
/// A dictionary of all assemblies in the directory and the list of type metadatas of types that match the
/// selector.
/// A dictionary of all assemblies in the directory and the list of type metadatas of types that match the selector.
/// </returns>
public static Dictionary<string, List<T>> FindPluginTypes<T>(string directory,
Func<TypeDefinition, string, T> typeSelector,
Expand Down Expand Up @@ -224,13 +231,12 @@ public static Dictionary<string, List<T>> FindPluginTypes<T>(string directory,
}

/// <summary>
/// Loads an index of type metadatas from a cache.
/// Loads an index of type metadatas from a cache.
/// </summary>
/// <param name="cacheName">Name of the cache</param>
/// <typeparam name="T">Cacheable item</typeparam>
/// <returns>
/// Cached type metadatas indexed by the path of the assembly that defines the type. If no cache is defined,
/// return null.
/// Cached type metadatas indexed by the path of the assembly that defines the type. If no cache is defined, return null.
/// </returns>
public static Dictionary<string, CachedAssembly<T>> LoadAssemblyCache<T>(string cacheName)
where T : ICacheable, new()
Expand Down Expand Up @@ -277,7 +283,7 @@ public static Dictionary<string, CachedAssembly<T>> LoadAssemblyCache<T>(string
}

/// <summary>
/// Saves indexed type metadata into a cache.
/// Saves indexed type metadata into a cache.
/// </summary>
/// <param name="cacheName">Name of the cache</param>
/// <param name="entries">List of plugin metadatas indexed by the path to the assembly that contains the types</param>
Expand Down Expand Up @@ -319,7 +325,7 @@ public static void SaveAssemblyCache<T>(string cacheName,
}

/// <summary>
/// Converts TypeLoadException to a readable string.
/// Converts TypeLoadException to a readable string.
/// </summary>
/// <param name="ex">TypeLoadException</param>
/// <returns>Readable representation of the exception</returns>
Expand Down
10 changes: 5 additions & 5 deletions BepInEx.Core/Configuration/AcceptableValueBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace BepInEx.Configuration;

/// <summary>
/// Base type of all classes representing and enforcing acceptable values of config settings.
/// Base type of all classes representing and enforcing acceptable values of config settings.
/// </summary>
public abstract class AcceptableValueBase
{
Expand All @@ -14,22 +14,22 @@ protected AcceptableValueBase(Type valueType)
}

/// <summary>
/// Type of the supported values.
/// Type of the supported values.
/// </summary>
public Type ValueType { get; }

/// <summary>
/// Change the value to be acceptable, if it's not already.
/// Change the value to be acceptable, if it's not already.
/// </summary>
public abstract object Clamp(object value);

/// <summary>
/// Check if the value is an acceptable value.
/// Check if the value is an acceptable value.
/// </summary>
public abstract bool IsValid(object value);

/// <summary>
/// Get the string for use in config files.
/// Get the string for use in config files.
/// </summary>
public abstract string ToDescriptionString();
}
8 changes: 4 additions & 4 deletions BepInEx.Core/Configuration/AcceptableValueList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
namespace BepInEx.Configuration;

/// <summary>
/// Specify the list of acceptable values for a setting.
/// Specify the list of acceptable values for a setting.
/// </summary>
public class AcceptableValueList<T> : AcceptableValueBase where T : IEquatable<T>
{
/// <summary>
/// Specify the list of acceptable values for a setting.
/// If the setting does not equal any of the values, it will be set to the first one.
/// Specify the list of acceptable values for a setting.
/// If the setting does not equal any of the values, it will be set to the first one.
/// </summary>
public AcceptableValueList(params T[] acceptableValues) : base(typeof(T))
{
Expand All @@ -22,7 +22,7 @@ public AcceptableValueList(params T[] acceptableValues) : base(typeof(T))
}

/// <summary>
/// List of values that a setting can take.
/// List of values that a setting can take.
/// </summary>
public virtual T[] AcceptableValues { get; }

Expand Down
6 changes: 3 additions & 3 deletions BepInEx.Core/Configuration/AcceptableValueRange.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace BepInEx.Configuration;

/// <summary>
/// Specify the range of acceptable values for a setting.
/// Specify the range of acceptable values for a setting.
/// </summary>
public class AcceptableValueRange<T> : AcceptableValueBase where T : IComparable
{
Expand All @@ -23,12 +23,12 @@ public AcceptableValueRange(T minValue, T maxValue) : base(typeof(T))
}

/// <summary>
/// Lowest acceptable value
/// Lowest acceptable value
/// </summary>
public virtual T MinValue { get; }

/// <summary>
/// Highest acceptable value
/// Highest acceptable value
/// </summary>
public virtual T MaxValue { get; }

Expand Down
Loading
Loading