Browse Source

Added IConfigProvider and one implimentation

pull/46/head
Anairkoen Schno 5 years ago
parent
commit
9d2461b2eb
8 changed files with 170 additions and 112 deletions
  1. +100
    -0
      IPA.Loader/Config/ConfigProviders/JsonConfigProvider.cs
  2. +51
    -0
      IPA.Loader/Config/IConfigProvider.cs
  3. +1
    -1
      IPA.Loader/Config/IniFile.cs
  4. +1
    -1
      IPA.Loader/Config/ModPrefs.cs
  5. +0
    -103
      IPA.Loader/IConfigProvider.cs
  6. +4
    -3
      IPA.Loader/IPA.Loader.csproj
  7. +12
    -4
      IPA.Loader/Loader/PluginManager.cs
  8. +1
    -0
      IPA.Loader/Logging/Logger.cs

+ 100
- 0
IPA.Loader/Config/ConfigProviders/JsonConfigProvider.cs View File

@ -0,0 +1,100 @@
using IPA.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IPA.Config.ConfigProviders
{
internal class JsonConfigProvider : IConfigProvider
{
private JObject jsonObj;
public dynamic Dynamic => jsonObj;
public bool HasChanged { get; private set; } = false;
private string _filename = null;
public string Filename
{
get => _filename;
set
{
if (_filename != null)
throw new InvalidOperationException("Can only assign to Filename once");
_filename = value;
}
}
public void Load()
{
var finfo = new FileInfo(Filename + ".json");
if (finfo.Exists)
{
string json = finfo.OpenText().ReadToEnd();
try
{
jsonObj = JObject.Parse(json);
}
catch (Exception e)
{
Logger.config.Error($"Error parsing JSON in file {Filename}.json; resetting to empty JSON");
Logger.config.Error(e);
jsonObj = new JObject();
File.WriteAllText(finfo.FullName, JsonConvert.SerializeObject(jsonObj));
}
}
else
{
jsonObj = new JObject();
}
SetupListeners();
}
private void SetupListeners()
{
jsonObj.PropertyChanged += JsonObj_PropertyChanged;
jsonObj.ListChanged += JsonObj_ListChanged;
jsonObj.CollectionChanged += JsonObj_CollectionChanged;
}
private void JsonObj_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
HasChanged = true;
}
private void JsonObj_ListChanged(object sender, System.ComponentModel.ListChangedEventArgs e)
{
HasChanged = true;
}
private void JsonObj_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
HasChanged = true;
}
public T Parse<T>()
{
return jsonObj.ToObject<T>();
}
public void Save()
{
var finfo = new FileInfo(Filename + ".json");
File.WriteAllText(finfo.FullName, JsonConvert.SerializeObject(jsonObj));
}
public void Store<T>(T obj)
{
jsonObj = JObject.FromObject(obj);
SetupListeners();
HasChanged = true;
}
}
}

+ 51
- 0
IPA.Loader/Config/IConfigProvider.cs View File

@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IPA.Config
{
/// <summary>
/// An interface for configuration providers.
/// </summary>
public interface IConfigProvider
{
/// <summary>
/// Loads the data provided by this <see cref="IConfigProvider"/> into an object of type <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">the type of the object to parse into</typeparam>
/// <returns>the values from the config provider parsed into the object</returns>
T Parse<T>();
/// <summary>
/// Stores the data from <paramref name="obj"/> into the <see cref="IConfigProvider"/>.
/// </summary>
/// <typeparam name="T">the type of <paramref name="obj"/></typeparam>
/// <param name="obj">the object containing the data to save</param>
void Store<T>(T obj);
/// <summary>
/// Gets a dynamic object providing access to the configuration.
/// </summary>
dynamic Dynamic { get; }
#region State getters
/// <summary>
/// Returns <see langword="true"/> if object has changed since the last save
/// </summary>
bool HasChanged { get; }
/// <summary>
/// Will be set with the filename (no extension) to save to. When saving, the implimentation should add the appropriate extension. Should error if set multiple times.
/// </summary>
string Filename { set; }
/// <summary>
/// Saves configuration to file. Should error if not a root object.
/// </summary>
void Save();
/// <summary>
/// Loads the state of the file on disk.
/// </summary>
void Load();
#endregion
}
}

IPA.Loader/IniFile.cs → IPA.Loader/Config/IniFile.cs View File

@ -4,7 +4,7 @@ using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace IPA
namespace IPA.Config
{
/// <summary>
/// Create a New INI file to store or load data

IPA.Loader/ModPrefs.cs → IPA.Loader/Config/ModPrefs.cs View File

@ -5,7 +5,7 @@ using System.Linq;
using System.Reflection;
using System.Text;
namespace IPA
namespace IPA.Config
{
/// <summary>
/// Allows to get and set preferences for your mod.

+ 0
- 103
IPA.Loader/IConfigProvider.cs View File

@ -1,103 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IPA
{
/// <summary>
/// An interface for configuration providers.
/// </summary>
public interface IConfigProvider
{
/// <summary>
/// Loads the data provided by this <see cref="IConfigProvider"/> into an object of type <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">the type of the object to parse into</typeparam>
/// <returns>the values from the config provider parsed into the object</returns>
T Parse<T>();
/// <summary>
/// Stores the data from <paramref name="obj"/> into the <see cref="IConfigProvider"/>.
/// </summary>
/// <remarks>
/// NOTE TO IMPLEMENTERS:
/// Since <see cref="Newtonsoft.Json"/> is bundled with this library, try to include support for its attributes.
/// </remarks>
/// <typeparam name="T">the type of <paramref name="obj"/></typeparam>
/// <param name="obj">the object containing the data to save</param>
void Store<T>(T obj);
#region Getters
/// <summary>
/// Gets the <see cref="IConfigProvider"/> acting as a sub-object for a given key.
/// </summary>
/// <param name="name">the name of the field with the <see cref="IConfigProvider"/></param>
/// <returns>an accessor for the selected sub-object</returns>
IConfigProvider GetSubObject(string name);
/// <summary>
/// Gets the value of type <typeparamref name="T"/> for key <paramref name="name"/>.
/// </summary>
/// <remarks>
/// If <typeparamref name="T"/> is <see cref="IConfigProvider"/>, behavior should be identical to <see cref="GetSubObject"/>.
/// </remarks>
/// <typeparam name="T">the type of the value to get</typeparam>
/// <param name="name">the name of the field to get the value of</param>
/// <returns>the value of the field</returns>
T Get<T>(string name); // can be IConfigProvider
/// <summary>
/// The non-generic version of <see cref="Get{T}"/>.
/// If key corresponds to a sub-object, will return an <see cref="IConfigProvider"/>.
/// </summary>
/// <param name="name">the name of the field to get the value of</param>
/// <returns>the value of the field</returns>
object Get(string name); // can return IConfigProvider
/// <summary>
/// Gets the value of type <typeparamref name="T"/> of the element at <paramref name="path"/>.
/// </summary>
/// <remarks>
/// If <typeparamref name="T"/> is <see cref="IConfigProvider"/>, behavior should be identical to <see cref="GetSubObject"/> if it were executed on the immediate parent of the target element.
/// </remarks>
/// <typeparam name="T">the type of the value to get</typeparam>
/// <param name="path">an ordered array specifying keys starting from the root (this)</param>
/// <returns>the value at path</returns>
T GetPath<T>(params string[] path);
/// <summary>
/// The non-generic version of <see cref="GetPath{T}(string[])"/>.
/// If key corresponds to a sub-object, will return an <see cref="IConfigProvider"/>.
/// </summary>
/// <param name="path">an ordered array specifying keys starting from the root (this)</param>
/// <returns>the value at path</returns>
object GetPath(params string[] path);
#endregion
#region Setters
/// <summary>
/// Sets the object for key '<paramref name="name"/>' to <paramref name="provider"/>.
/// </summary>
/// <param name="name">the key to set it as</param>
/// <param name="provider">the provider value</param>
void SetSubObject(string name, IConfigProvider provider); // argument should be same provider type
/// <summary>
/// Sets the value for key <paramref name="name"/> to <paramref name="value"/>.
/// </summary>
/// <remarks>
/// If <typeparamref name="T"/> is <see cref="IConfigProvider"/>, behavior should be identical to <see cref="SetSubObject(string, IConfigProvider)"/>.
/// </remarks>
/// <typeparam name="T">the type of the value to set</typeparam>
/// <param name="name">the key</param>
/// <param name="value">the value to set</param>
void Set<T>(string name, T value);
/// <summary>
/// Sets the value for path <paramref name="path"/> to <paramref name="value"/>.
/// </summary>
/// <remarks>
/// If <typeparamref name="T"/> is <see cref="IConfigProvider"/>, behavior should be identical to <see cref="SetSubObject(string, IConfigProvider)"/> if it were executed on the immediate parent of the target element.
/// </remarks>
/// <typeparam name="T">the type of the value to set</typeparam>
/// <param name="path">the path to the new value location</param>
/// <param name="value">the value to set</param>
void SetPath<T>(string[] path, T value);
#endregion
}
}

+ 4
- 3
IPA.Loader/IPA.Loader.csproj View File

@ -55,19 +55,20 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="IConfigProvider.cs" />
<Compile Include="Config\ConfigProviders\JsonConfigProvider.cs" />
<Compile Include="Config\IConfigProvider.cs" />
<Compile Include="Loader\Composite\CompositeBSPlugin.cs" />
<Compile Include="Logging\Printers\PluginSubLogPrinter.cs" />
<Compile Include="PluginInterfaces\BeatSaber\IBeatSaberPlugin.cs" />
<Compile Include="PluginInterfaces\BeatSaber\IEnhancedBeatSaberPlugin.cs" />
<Compile Include="PluginInterfaces\BeatSaber\ModsaberModInfo.cs" />
<Compile Include="PluginInterfaces\IGenericEnhancedPlugin.cs" />
<Compile Include="IniFile.cs" />
<Compile Include="Config\IniFile.cs" />
<Compile Include="PluginInterfaces\IPA\IEnhancedPlugin.cs" />
<Compile Include="PluginInterfaces\IPA\IPlugin.cs" />
<Compile Include="Logging\Logger.cs" />
<Compile Include="Logging\LogPrinter.cs" />
<Compile Include="ModPrefs.cs" />
<Compile Include="Config\ModPrefs.cs" />
<Compile Include="Utilities\ReflectionUtil.cs" />
<Compile Include="Loader\Composite\CompositeIPAPlugin.cs" />
<Compile Include="Logging\Printers\ColoredConsolePrinter.cs" />


+ 12
- 4
IPA.Loader/Loader/PluginManager.cs View File

@ -1,4 +1,6 @@
using IPA;
using IPA.Config;
using IPA.Config.ConfigProviders;
using IPA.Logging;
using IPA.Old;
using IPA.Updating;
@ -75,7 +77,7 @@ namespace IPA.Loader
}
private static List<IPlugin> _ipaPlugins = null;
internal static List<IConfigProvider> configProviders = new List<IConfigProvider>();
private static void LoadPlugins()
{
@ -205,9 +207,9 @@ namespace IPA.Loader
if (@ref.FullName == "IllusionPlugin.IBeatSaberPlugin") @ref.Namespace = "IPA"; //@ref.Name = "";
if (@ref.FullName == "IllusionPlugin.IEnhancedBeatSaberPlugin") @ref.Namespace = "IPA"; //@ref.Name = "";
if (@ref.FullName == "IllusionPlugin.BeatSaber.ModsaberModInfo") @ref.Namespace = "IPA"; //@ref.Name = "";
if (@ref.FullName == "IllusionPlugin.IniFile") @ref.Namespace = "IPA"; //@ref.Name = "";
if (@ref.FullName == "IllusionPlugin.IModPrefs") @ref.Namespace = "IPA"; //@ref.Name = "";
if (@ref.FullName == "IllusionPlugin.ModPrefs") @ref.Namespace = "IPA"; //@ref.Name = "";
if (@ref.FullName == "IllusionPlugin.IniFile") @ref.Namespace = "IPA.Config"; //@ref.Name = "";
if (@ref.FullName == "IllusionPlugin.IModPrefs") @ref.Namespace = "IPA.Config"; //@ref.Name = "";
if (@ref.FullName == "IllusionPlugin.ModPrefs") @ref.Namespace = "IPA.Config"; //@ref.Name = "";
if (@ref.FullName == "IllusionPlugin.Utils.ReflectionUtil") @ref.Namespace = "IPA.Utilities"; //@ref.Name = "";
if (@ref.FullName == "IllusionPlugin.Logging.Logger") @ref.Namespace = "IPA.Logging"; //@ref.Name = "";
if (@ref.FullName == "IllusionPlugin.Logging.LogPrinter") @ref.Namespace = "IPA.Logging"; //@ref.Name = "";
@ -258,6 +260,12 @@ namespace IPA.Loader
if (modPrefs == null) modPrefs = new ModPrefs(bsPlugin);
initArgs.Add(modPrefs);
}
else if (ptype.IsAssignableFrom(typeof(IConfigProvider)))
{
var configProvider = new JsonConfigProvider() { Filename = Path.Combine("UserData", $"{bsPlugin.Name}.{param.Name}") };
configProviders.Add(configProvider);
initArgs.Add(configProvider);
}
else
initArgs.Add(ptype.GetDefault());
}


+ 1
- 0
IPA.Loader/Logging/Logger.cs View File

@ -24,6 +24,7 @@ namespace IPA.Logging
internal static Logger updater => log.GetChildLogger("Updater");
internal static Logger libLoader => log.GetChildLogger("LibraryLoader");
internal static Logger loader => log.GetChildLogger("Loader");
internal static Logger config => log.GetChildLogger("Config");
internal static bool LogCreated => _log != null || UnityLogInterceptor._logger != null;
/// <summary>


Loading…
Cancel
Save