Browse Source

More documentation

4.0.0-beta
Anairkoen Schno 4 years ago
parent
commit
e81e5bdf18
2 changed files with 203 additions and 174 deletions
  1. +175
    -174
      IPA.Loader/Config/Config.cs
  2. +28
    -0
      IPA.Loader/Loader/PluginInitInjector.cs

+ 175
- 174
IPA.Loader/Config/Config.cs View File

@ -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
{
/// <summary>
/// A class to handle updating ConfigProviders automatically
/// </summary>
public class Config
{
static Config()
{
JsonConfigProvider.RegisterConfig();
}
/// <summary>
/// Specifies that a particular parameter is preferred to use a particular <see cref="IConfigProvider" />.
/// If it is not available, also specifies backups. If none are available, the default is used.
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class PreferAttribute : Attribute
{
/// <summary>
/// The order of preference for the config type.
/// </summary>
/// <value>the list of config extensions in order of preference</value>
// ReSharper disable once UnusedAutoPropertyAccessor.Global
public string[] PreferenceOrder { get; private set; }
/// <inheritdoc />
/// <summary>
/// Constructs the attribute with a specific preference list. Each entry is the extension without a '.'
/// </summary>
/// <param name="preference">The preferences in order of preference.</param>
public PreferAttribute(params string[] preference)
{
PreferenceOrder = preference;
}
}
/// <summary>
/// Specifies a preferred config name, instead of using the plugin's name.
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class NameAttribute : Attribute
{
/// <summary>
/// The name to use for the config.
/// </summary>
/// <value>the name to use for the config</value>
// ReSharper disable once UnusedAutoPropertyAccessor.Global
public string Name { get; private set; }
/// <inheritdoc />
/// <summary>
/// Constructs the attribute with a specific name.
/// </summary>
/// <param name="name">the name to use for the config.</param>
public NameAttribute(string name)
{
Name = name;
}
}
private static readonly Dictionary<string, IConfigProvider> registeredProviders = new Dictionary<string, IConfigProvider>();
/// <summary>
/// Registers a <see cref="IConfigProvider"/> to use for configs.
/// </summary>
/// <typeparam name="T">the type to register</typeparam>
public static void Register<T>() where T : IConfigProvider => Register(typeof(T));
/// <summary>
/// Registers a <see cref="IConfigProvider"/> to use for configs.
/// </summary>
/// <param name="type">the type to register</param>
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);
}
/// <summary>
/// Gets a <see cref="Config"/> object using the specified list of preferred config types.
/// </summary>
/// <param name="configName">the name of the mod for this config</param>
/// <param name="extensions">the preferred config types to try to get</param>
/// <returns>a <see cref="Config"/> using the requested format, or of type JSON.</returns>
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<string>();
if (info.GetCustomAttribute<PreferAttribute>() is PreferAttribute prefer)
prefs = prefer.PreferenceOrder;
if (info.GetCustomAttribute<NameAttribute>() is NameAttribute name)
modName = name.Name;
return GetConfigFor(modName, prefs);
}
/// <summary>
/// Gets the name associated with this <see cref="Config"/> object.
/// </summary>
public string Name { get; }
/// <summary>
/// Gets the <see cref="IConfigProvider"/> associated with this <see cref="Config"/> object.
/// </summary>
public IConfigProvider Provider { get; }
internal IConfigStore Store = null;
internal readonly FileInfo File;
internal readonly ConfigProvider configProvider;
internal int Writes = 0;
/// <summary>
/// Sets this object's <see cref="IConfigStore"/>. Can only be called once.
/// </summary>
/// <param name="store">the <see cref="IConfigStore"/> to add to this instance</param>
/// <exception cref="InvalidOperationException">If this was called before.</exception>
public void SetStore(IConfigStore store)
{
if (Store != null)
throw new InvalidOperationException($"{nameof(SetStore)} can only be called once");
Store = store;
ConfigRuntime.ConfigChanged();
}
/// <summary>
/// Forces a synchronous load from disk.
/// </summary>
public void LoadSync() => LoadAsync().Wait();
/// <summary>
/// Forces an asynchronous load from disk.
/// </summary>
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
{
/// <summary>
/// An abstraction of a config file on disk, which handles synchronizing between a memory representation and the
/// disk representation.
/// </summary>
public class Config
{
static Config()
{
JsonConfigProvider.RegisterConfig();
}
/// <summary>
/// Specifies that a particular parameter is preferred to use a particular <see cref="IConfigProvider" />.
/// If it is not available, also specifies backups. If none are available, the default is used.
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class PreferAttribute : Attribute
{
/// <summary>
/// The order of preference for the config type.
/// </summary>
/// <value>the list of config extensions in order of preference</value>
// ReSharper disable once UnusedAutoPropertyAccessor.Global
public string[] PreferenceOrder { get; private set; }
/// <inheritdoc />
/// <summary>
/// Constructs the attribute with a specific preference list. Each entry is the extension without a '.'
/// </summary>
/// <param name="preference">The preferences in order of preference.</param>
public PreferAttribute(params string[] preference)
{
PreferenceOrder = preference;
}
}
/// <summary>
/// Specifies a preferred config name, instead of using the plugin's name.
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class NameAttribute : Attribute
{
/// <summary>
/// The name to use for the config.
/// </summary>
/// <value>the name to use for the config</value>
// ReSharper disable once UnusedAutoPropertyAccessor.Global
public string Name { get; private set; }
/// <inheritdoc />
/// <summary>
/// Constructs the attribute with a specific name.
/// </summary>
/// <param name="name">the name to use for the config.</param>
public NameAttribute(string name)
{
Name = name;
}
}
private static readonly Dictionary<string, IConfigProvider> registeredProviders = new Dictionary<string, IConfigProvider>();
/// <summary>
/// Registers a <see cref="IConfigProvider"/> to use for configs.
/// </summary>
/// <typeparam name="T">the type to register</typeparam>
public static void Register<T>() where T : IConfigProvider => Register(typeof(T));
/// <summary>
/// Registers a <see cref="IConfigProvider"/> to use for configs.
/// </summary>
/// <param name="type">the type to register</param>
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);
}
/// <summary>
/// Gets a <see cref="Config"/> object using the specified list of preferred config types.
/// </summary>
/// <param name="configName">the name of the mod for this config</param>
/// <param name="extensions">the preferred config types to try to get</param>
/// <returns>a <see cref="Config"/> using the requested format, or of type JSON.</returns>
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<string>();
if (info.GetCustomAttribute<PreferAttribute>() is PreferAttribute prefer)
prefs = prefer.PreferenceOrder;
if (info.GetCustomAttribute<NameAttribute>() is NameAttribute name)
modName = name.Name;
return GetConfigFor(modName, prefs);
}
/// <summary>
/// Gets the name associated with this <see cref="Config"/> object.
/// </summary>
public string Name { get; }
/// <summary>
/// Gets the <see cref="IConfigProvider"/> associated with this <see cref="Config"/> object.
/// </summary>
public IConfigProvider Provider { get; }
internal IConfigStore Store = null;
internal readonly FileInfo File;
internal readonly ConfigProvider configProvider;
internal int Writes = 0;
/// <summary>
/// Sets this object's <see cref="IConfigStore"/>. Can only be called once.
/// </summary>
/// <param name="store">the <see cref="IConfigStore"/> to add to this instance</param>
/// <exception cref="InvalidOperationException">If this was called before.</exception>
public void SetStore(IConfigStore store)
{
if (Store != null)
throw new InvalidOperationException($"{nameof(SetStore)} can only be called once");
Store = store;
ConfigRuntime.ConfigChanged();
}
/// <summary>
/// Forces a synchronous load from disk.
/// </summary>
public void LoadSync() => LoadAsync().Wait();
/// <summary>
/// Forces an asynchronous load from disk.
/// </summary>
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);
}
}
}

+ 28
- 0
IPA.Loader/Loader/PluginInitInjector.cs View File

@ -15,6 +15,34 @@ namespace IPA.Loader
/// <summary>
/// The type that handles value injecting into a plugin's initialization methods.
/// </summary>
/// <remarks>
/// The default injectors and what they provide are shown in this table.
/// <list type="table">
/// <listheader>
/// <term>Parameter Type</term>
/// <description>Injected Value</description>
/// </listheader>
/// <item>
/// <term><see cref="Logger"/></term>
/// <description>A <see cref="StandardLogger"/> specialized for the plugin being injected</description>
/// </item>
/// <item>
/// <term><see cref="PluginMetadata"/></term>
/// <description>The <see cref="PluginMetadata"/> of the plugin being injected</description>
/// </item>
/// <item>
/// <term><see cref="Config.Config"/></term>
/// <description>
/// <para>A <see cref="Config.Config"/> object for the plugin being injected.</para>
/// <para>
/// These parameters may have <see cref="Config.Config.NameAttribute"/> and <see cref="Config.Config.PreferAttribute"/> to control
/// how it is constructed.
/// </para>
/// </description>
/// </item>
/// </list>
/// 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.
/// </remarks>
public static class PluginInitInjector
{


Loading…
Cancel
Save