You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

162 lines
6.2 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Reflection;
  6. using System.Runtime.CompilerServices;
  7. using IPA.Config.Providers;
  8. using IPA.Utilities;
  9. #if NET3
  10. using Net3_Proxy;
  11. using Path = Net3_Proxy.Path;
  12. using Array = Net3_Proxy.Array;
  13. #endif
  14. namespace IPA.Config
  15. {
  16. /// <summary>
  17. /// A class to handle updating ConfigProviders automatically
  18. /// </summary>
  19. public class Config
  20. {
  21. static Config()
  22. {
  23. //JsonConfigProvider.RegisterConfig();
  24. }
  25. /// <summary>
  26. /// Specifies that a particular parameter is preferred to be a specific type of <see cref="T:IPA.Config.IConfigProvider" />. If it is not available, also specifies backups. If none are available, the default is used.
  27. /// </summary>
  28. [AttributeUsage(AttributeTargets.Parameter)]
  29. public class PreferAttribute : Attribute
  30. {
  31. /// <summary>
  32. /// The order of preference for the config type.
  33. /// </summary>
  34. /// <value>the list of config extensions in order of preference</value>
  35. // ReSharper disable once UnusedAutoPropertyAccessor.Global
  36. public string[] PreferenceOrder { get; private set; }
  37. /// <inheritdoc />
  38. /// <summary>
  39. /// Constructs the attribute with a specific preference list. Each entry is the extension without a '.'
  40. /// </summary>
  41. /// <param name="preference">The preferences in order of preference.</param>
  42. public PreferAttribute(params string[] preference)
  43. {
  44. PreferenceOrder = preference;
  45. }
  46. }
  47. /// <summary>
  48. /// Specifies a preferred config name, instead of using the plugin's name.
  49. /// </summary>
  50. [AttributeUsage(AttributeTargets.Parameter)]
  51. public class NameAttribute : Attribute
  52. {
  53. /// <summary>
  54. /// The name to use for the config.
  55. /// </summary>
  56. /// <value>the name to use for the config</value>
  57. // ReSharper disable once UnusedAutoPropertyAccessor.Global
  58. public string Name { get; private set; }
  59. /// <inheritdoc />
  60. /// <summary>
  61. /// Constructs the attribute with a specific name.
  62. /// </summary>
  63. /// <param name="name">the name to use for the config.</param>
  64. public NameAttribute(string name)
  65. {
  66. Name = name;
  67. }
  68. }
  69. private static readonly Dictionary<string, IConfigProvider> registeredProviders = new Dictionary<string, IConfigProvider>();
  70. /// <summary>
  71. /// Registers a <see cref="IConfigProvider"/> to use for configs.
  72. /// </summary>
  73. /// <typeparam name="T">the type to register</typeparam>
  74. public static void Register<T>() where T : IConfigProvider => Register(typeof(T));
  75. /// <summary>
  76. /// Registers a <see cref="IConfigProvider"/> to use for configs.
  77. /// </summary>
  78. /// <param name="type">the type to register</param>
  79. public static void Register(Type type)
  80. {
  81. var inst = Activator.CreateInstance(type) as IConfigProvider;
  82. if (inst == null)
  83. throw new ArgumentException($"Type not an {nameof(IConfigProvider)}");
  84. if (registeredProviders.ContainsKey(inst.Extension))
  85. throw new InvalidOperationException($"Extension provider for {inst.Extension} already exists");
  86. registeredProviders.Add(inst.Extension, inst);
  87. }
  88. private static Dictionary<Config, FileInfo> files = new Dictionary<Config, FileInfo>();
  89. /// <summary>
  90. /// Gets a <see cref="Config"/> object using the specified list of preferred config types.
  91. /// </summary>
  92. /// <param name="configName">the name of the mod for this config</param>
  93. /// <param name="extensions">the preferred config types to try to get</param>
  94. /// <returns>a <see cref="Config"/> using the requested format, or of type JSON.</returns>
  95. public static Config GetConfigFor(string configName, params string[] extensions)
  96. {
  97. var chosenExt = extensions.FirstOrDefault(s => registeredProviders.ContainsKey(s)) ?? "json";
  98. var provider = registeredProviders[chosenExt];
  99. var config = new Config(configName, provider);
  100. var filename = Path.Combine(BeatSaber.UserDataPath, configName + "." + provider.Extension);
  101. files.Add(config, new FileInfo(filename));
  102. RegisterConfigObject(config);
  103. return config;
  104. }
  105. internal static Config GetProviderFor(string modName, ParameterInfo info)
  106. {
  107. var prefs = Array.Empty<string>();
  108. if (info.GetCustomAttribute<PreferAttribute>() is PreferAttribute prefer)
  109. prefs = prefer.PreferenceOrder;
  110. if (info.GetCustomAttribute<NameAttribute>() is NameAttribute name)
  111. modName = name.Name;
  112. return GetConfigFor(modName, prefs);
  113. }
  114. private static void RegisterConfigObject(Config obj)
  115. {
  116. // TODO: implement
  117. }
  118. /// <summary>
  119. /// Gets the name associated with this <see cref="Config"/> object.
  120. /// </summary>
  121. public string Name { get; private set; }
  122. /// <summary>
  123. /// Gets the <see cref="IConfigProvider"/> associated with this <see cref="Config"/> object.
  124. /// </summary>
  125. public IConfigProvider Provider { get; private set; }
  126. internal readonly HashSet<IConfigStore> Stores = new HashSet<IConfigStore>();
  127. /// <summary>
  128. /// Adds an <see cref="IConfigStore"/> to this <see cref="Config"/> object.
  129. /// </summary>
  130. /// <param name="store">the <see cref="IConfigStore"/> to add to this instance</param>
  131. /// <returns><see langword="true"/> if the <see cref="IConfigStore"/> was not already registered to this <see cref="Config"/> object,
  132. /// otherwise <see langword="false"/></returns>
  133. public bool AddStore(IConfigStore store) => Stores.Add(store);
  134. private Config(string name, IConfigProvider provider)
  135. {
  136. Name = name; Provider = provider;
  137. }
  138. }
  139. }