/// Gets a dynamic object providing access to the configuration.
/// </summary>
/// <value>a dynamically bound object to use to access config values directly</value>
dynamicDynamic{get;}
#region State getters
/// <summary>
/// Returns <see langword="true"/> if object has changed since the last save
/// </summary>
/// <value><see langword="true"/> if object has changed since the last save, else <see langword="false"/></value>
boolHasChanged{get;}
/// <summary>
/// Returns <see langword="true"/> if the data in memory has been changed - notably including loads.
/// </summary>
/// <value><see langword="true"/> if the data in memory has been changed, else <see langword="false"/></value>
boolInMemoryChanged{get;set;}
/// <summary>
/// Will be set with the filename (no extension) to save to. When saving, the implementation should add the appropriate extension. Should error if set multiple times.
/// </summary>
/// <value>the extensionless filename to save to</value>
stringFilename{set;}
/// <summary>
/// Gets the last time the config was modified.
/// </summary>
/// <value>the last time the config file was modified</value>
DateTimeLastModified{get;}
/// <summary>
/// Saves configuration to file. Should error if not a root object.
/// Called before a plugin's Init method is called. This will not be called if there is no Init method. This should never throw an exception. An exception will abort the loading of the plugin with an error.
/// Called before a plugin's `Init` method is called. This will not be called if there is no `Init` method. This should never throw an exception. An exception will abort the loading of the plugin with an error.
/// </summary>
/// <param name="plugin">the plugin to be initialized</param>
/// <returns>whether or not to call the Init method</returns>
publicoverridestringToString()=>$"{Name}({Id}@{Version})({PluginType?.FullName}) from '{Utils.GetRelativePath(File?.FullName, BeatSaber.InstallPath)}'";