diff --git a/IPA.Loader/Config/Config.cs b/IPA.Loader/Config/Config.cs index 6d66174e..ecb77848 100644 --- a/IPA.Loader/Config/Config.cs +++ b/IPA.Loader/Config/Config.cs @@ -1,174 +1,175 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using IPA.Config.Providers; -using IPA.Utilities; -#if NET3 -using Net3_Proxy; -using Path = Net3_Proxy.Path; -using Array = Net3_Proxy.Array; -#endif - -namespace IPA.Config -{ - /// - /// A class to handle updating ConfigProviders automatically - /// - public class Config - { - static Config() - { - JsonConfigProvider.RegisterConfig(); - } - - /// - /// Specifies that a particular parameter is preferred to use a particular . - /// If it is not available, also specifies backups. If none are available, the default is used. - /// - [AttributeUsage(AttributeTargets.Parameter)] - public sealed class PreferAttribute : Attribute - { - /// - /// The order of preference for the config type. - /// - /// the list of config extensions in order of preference - // ReSharper disable once UnusedAutoPropertyAccessor.Global - public string[] PreferenceOrder { get; private set; } - - /// - /// - /// Constructs the attribute with a specific preference list. Each entry is the extension without a '.' - /// - /// The preferences in order of preference. - public PreferAttribute(params string[] preference) - { - PreferenceOrder = preference; - } - } - - /// - /// Specifies a preferred config name, instead of using the plugin's name. - /// - [AttributeUsage(AttributeTargets.Parameter)] - public sealed class NameAttribute : Attribute - { - /// - /// The name to use for the config. - /// - /// the name to use for the config - // ReSharper disable once UnusedAutoPropertyAccessor.Global - public string Name { get; private set; } - - /// - /// - /// Constructs the attribute with a specific name. - /// - /// the name to use for the config. - public NameAttribute(string name) - { - Name = name; - } - } - - private static readonly Dictionary registeredProviders = new Dictionary(); - - /// - /// Registers a to use for configs. - /// - /// the type to register - public static void Register() where T : IConfigProvider => Register(typeof(T)); - - /// - /// Registers a to use for configs. - /// - /// the type to register - public static void Register(Type type) - { - var inst = Activator.CreateInstance(type) as IConfigProvider; - if (inst == null) - throw new ArgumentException($"Type not an {nameof(IConfigProvider)}"); - - if (registeredProviders.ContainsKey(inst.Extension)) - throw new InvalidOperationException($"Extension provider for {inst.Extension} already exists"); - - registeredProviders.Add(inst.Extension, inst); - } - - /// - /// Gets a object using the specified list of preferred config types. - /// - /// the name of the mod for this config - /// the preferred config types to try to get - /// a using the requested format, or of type JSON. - public static Config GetConfigFor(string configName, params string[] extensions) - { - var chosenExt = extensions.FirstOrDefault(s => registeredProviders.ContainsKey(s)) ?? "json"; - var provider = registeredProviders[chosenExt]; - - var filename = Path.Combine(BeatSaber.UserDataPath, configName + "." + provider.Extension); - var config = new Config(configName, provider, new FileInfo(filename)); - - ConfigRuntime.RegisterConfig(config); - - return config; - } - - internal static Config GetConfigFor(string modName, ParameterInfo info) - { - var prefs = Array.Empty(); - if (info.GetCustomAttribute() is PreferAttribute prefer) - prefs = prefer.PreferenceOrder; - if (info.GetCustomAttribute() is NameAttribute name) - modName = name.Name; - - return GetConfigFor(modName, prefs); - } - - /// - /// Gets the name associated with this object. - /// - public string Name { get; } - /// - /// Gets the associated with this object. - /// - public IConfigProvider Provider { get; } - - internal IConfigStore Store = null; - internal readonly FileInfo File; - internal readonly ConfigProvider configProvider; - internal int Writes = 0; - - /// - /// Sets this object's . Can only be called once. - /// - /// the to add to this instance - /// If this was called before. - public void SetStore(IConfigStore store) - { - if (Store != null) - throw new InvalidOperationException($"{nameof(SetStore)} can only be called once"); - Store = store; - ConfigRuntime.ConfigChanged(); - } - - /// - /// Forces a synchronous load from disk. - /// - public void LoadSync() => LoadAsync().Wait(); - - /// - /// Forces an asynchronous load from disk. - /// - public Task LoadAsync() => ConfigRuntime.TriggerFileLoad(this); - - private Config(string name, IConfigProvider provider, FileInfo file) - { - Name = name; Provider = provider; File = file; - configProvider = new ConfigProvider(file, provider); - } - } -} +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using IPA.Config.Providers; +using IPA.Utilities; +#if NET3 +using Net3_Proxy; +using Path = Net3_Proxy.Path; +using Array = Net3_Proxy.Array; +#endif + +namespace IPA.Config +{ + /// + /// An abstraction of a config file on disk, which handles synchronizing between a memory representation and the + /// disk representation. + /// + public class Config + { + static Config() + { + JsonConfigProvider.RegisterConfig(); + } + + /// + /// Specifies that a particular parameter is preferred to use a particular . + /// If it is not available, also specifies backups. If none are available, the default is used. + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class PreferAttribute : Attribute + { + /// + /// The order of preference for the config type. + /// + /// the list of config extensions in order of preference + // ReSharper disable once UnusedAutoPropertyAccessor.Global + public string[] PreferenceOrder { get; private set; } + + /// + /// + /// Constructs the attribute with a specific preference list. Each entry is the extension without a '.' + /// + /// The preferences in order of preference. + public PreferAttribute(params string[] preference) + { + PreferenceOrder = preference; + } + } + + /// + /// Specifies a preferred config name, instead of using the plugin's name. + /// + [AttributeUsage(AttributeTargets.Parameter)] + public sealed class NameAttribute : Attribute + { + /// + /// The name to use for the config. + /// + /// the name to use for the config + // ReSharper disable once UnusedAutoPropertyAccessor.Global + public string Name { get; private set; } + + /// + /// + /// Constructs the attribute with a specific name. + /// + /// the name to use for the config. + public NameAttribute(string name) + { + Name = name; + } + } + + private static readonly Dictionary registeredProviders = new Dictionary(); + + /// + /// Registers a to use for configs. + /// + /// the type to register + public static void Register() where T : IConfigProvider => Register(typeof(T)); + + /// + /// Registers a to use for configs. + /// + /// the type to register + public static void Register(Type type) + { + var inst = Activator.CreateInstance(type) as IConfigProvider; + if (inst == null) + throw new ArgumentException($"Type not an {nameof(IConfigProvider)}"); + + if (registeredProviders.ContainsKey(inst.Extension)) + throw new InvalidOperationException($"Extension provider for {inst.Extension} already exists"); + + registeredProviders.Add(inst.Extension, inst); + } + + /// + /// Gets a object using the specified list of preferred config types. + /// + /// the name of the mod for this config + /// the preferred config types to try to get + /// a using the requested format, or of type JSON. + public static Config GetConfigFor(string configName, params string[] extensions) + { + var chosenExt = extensions.FirstOrDefault(s => registeredProviders.ContainsKey(s)) ?? "json"; + var provider = registeredProviders[chosenExt]; + + var filename = Path.Combine(BeatSaber.UserDataPath, configName + "." + provider.Extension); + var config = new Config(configName, provider, new FileInfo(filename)); + + ConfigRuntime.RegisterConfig(config); + + return config; + } + + internal static Config GetConfigFor(string modName, ParameterInfo info) + { + var prefs = Array.Empty(); + if (info.GetCustomAttribute() is PreferAttribute prefer) + prefs = prefer.PreferenceOrder; + if (info.GetCustomAttribute() is NameAttribute name) + modName = name.Name; + + return GetConfigFor(modName, prefs); + } + + /// + /// Gets the name associated with this object. + /// + public string Name { get; } + /// + /// Gets the associated with this object. + /// + public IConfigProvider Provider { get; } + + internal IConfigStore Store = null; + internal readonly FileInfo File; + internal readonly ConfigProvider configProvider; + internal int Writes = 0; + + /// + /// Sets this object's . Can only be called once. + /// + /// the to add to this instance + /// If this was called before. + public void SetStore(IConfigStore store) + { + if (Store != null) + throw new InvalidOperationException($"{nameof(SetStore)} can only be called once"); + Store = store; + ConfigRuntime.ConfigChanged(); + } + + /// + /// Forces a synchronous load from disk. + /// + public void LoadSync() => LoadAsync().Wait(); + + /// + /// Forces an asynchronous load from disk. + /// + public Task LoadAsync() => ConfigRuntime.TriggerFileLoad(this); + + private Config(string name, IConfigProvider provider, FileInfo file) + { + Name = name; Provider = provider; File = file; + configProvider = new ConfigProvider(file, provider); + } + } +} diff --git a/IPA.Loader/Loader/PluginInitInjector.cs b/IPA.Loader/Loader/PluginInitInjector.cs index 06196c33..9d9adc27 100644 --- a/IPA.Loader/Loader/PluginInitInjector.cs +++ b/IPA.Loader/Loader/PluginInitInjector.cs @@ -15,6 +15,34 @@ namespace IPA.Loader /// /// The type that handles value injecting into a plugin's initialization methods. /// + /// + /// The default injectors and what they provide are shown in this table. + /// + /// + /// Parameter Type + /// Injected Value + /// + /// + /// + /// A specialized for the plugin being injected + /// + /// + /// + /// The of the plugin being injected + /// + /// + /// + /// + /// A object for the plugin being injected. + /// + /// These parameters may have and to control + /// how it is constructed. + /// + /// + /// + /// + /// For all of the default injectors, only one of each will be generated, and any later parameters will recieve the same value as the first one. + /// public static class PluginInitInjector {