Browse Source

Documented plugin state management API

4.0.0-beta
Anairkoen Schno 4 years ago
parent
commit
c646f5a66e
2 changed files with 63 additions and 3 deletions
  1. +4
    -0
      IPA.Loader/Loader/PluginManager.cs
  2. +59
    -3
      IPA.Loader/Loader/StateTransitionTransaction.cs

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

@ -66,6 +66,10 @@ namespace IPA.Loader
public static PluginMetadata GetDisabledPluginFromId(string name) => public static PluginMetadata GetDisabledPluginFromId(string name) =>
DisabledPlugins.FirstOrDefault(p => p.Id == name); DisabledPlugins.FirstOrDefault(p => p.Id == name);
/// <summary>
/// Creates a new transaction for mod enabling and disabling mods simultaneously.
/// </summary>
/// <returns>a new <see cref="StateTransitionTransaction"/> that captures the current state of loaded mods</returns>
public static StateTransitionTransaction PluginStateTransaction() public static StateTransitionTransaction PluginStateTransaction()
=> new StateTransitionTransaction(AllPlugins, DisabledPlugins); => new StateTransitionTransaction(AllPlugins, DisabledPlugins);


+ 59
- 3
IPA.Loader/Loader/StateTransitionTransaction.cs View File

@ -6,6 +6,9 @@ using System.Threading.Tasks;
namespace IPA.Loader namespace IPA.Loader
{ {
/// <summary>
/// A class to represent a transaction for changing the state of loaded mods.
/// </summary>
public sealed class StateTransitionTransaction : IDisposable public sealed class StateTransitionTransaction : IDisposable
{ {
private readonly HashSet<PluginMetadata> currentlyEnabled; private readonly HashSet<PluginMetadata> currentlyEnabled;
@ -19,23 +22,64 @@ namespace IPA.Loader
currentlyDisabled = new HashSet<PluginMetadata>(disabled.ToArray()); currentlyDisabled = new HashSet<PluginMetadata>(disabled.ToArray());
} }
/// <summary>
/// Gets whether or not a game restart will be necessary to fully apply this transaction.
/// </summary>
/// <value><see langword="true"/> if any mod who's state is changed cannot be changed at runtime, <see langword="false"/> otherwise</value>
public bool WillNeedRestart => toEnable.Concat(toDisable).Any(m => m.RuntimeOptions != RuntimeOptions.DynamicInit); public bool WillNeedRestart => toEnable.Concat(toDisable).Any(m => m.RuntimeOptions != RuntimeOptions.DynamicInit);
internal IEnumerable<PluginMetadata> ToEnable => toEnable; internal IEnumerable<PluginMetadata> ToEnable => toEnable;
internal IEnumerable<PluginMetadata> ToDisable => toDisable; internal IEnumerable<PluginMetadata> ToDisable => toDisable;
public IEnumerable<PluginMetadata> EnabledPlugins => currentlyEnabled.Except(toDisable).Concat(toEnable);
public IEnumerable<PluginMetadata> DisabledPlugins => currentlyDisabled.Except(toEnable).Concat(toDisable);
/// <summary>
/// Gets a list of plugins that are enabled according to this transaction's current state.
/// </summary>
public IEnumerable<PluginMetadata> EnabledPlugins
=> ThrowIfDisposed<IEnumerable<PluginMetadata>>()
?? currentlyEnabled.Except(toDisable).Concat(toEnable);
/// <summary>
/// Gets a list of plugins that are disabled according to this transaction's current state.
/// </summary>
public IEnumerable<PluginMetadata> DisabledPlugins
=> ThrowIfDisposed<IEnumerable<PluginMetadata>>()
?? currentlyDisabled.Except(toEnable).Concat(toDisable);
/// <summary>
/// Checks if a plugin is enabled according to this transaction's current state.
/// </summary>
/// <remarks>
/// <para>This should be roughly equivalent to <c>EnabledPlugins.Contains(meta)</c>, but more performant.</para>
/// <para>This should also always return the inverse of <see cref="IsDisabled(PluginMetadata)"/> for valid plugins.</para>
/// </remarks>
/// <param name="meta">the plugin to check</param>
/// <returns><see langword="true"/> if the plugin is enabled, <see langword="false"/> otherwise</returns>
/// <seealso cref="EnabledPlugins"/>
/// <see cref="IsDisabled(PluginMetadata)"/>
public bool IsEnabled(PluginMetadata meta) public bool IsEnabled(PluginMetadata meta)
=> ThrowIfDisposed<bool>() => ThrowIfDisposed<bool>()
|| (currentlyEnabled.Contains(meta) && !toDisable.Contains(meta)) || (currentlyEnabled.Contains(meta) && !toDisable.Contains(meta))
|| toEnable.Contains(meta); || toEnable.Contains(meta);
/// <summary>
/// Checks if a plugin is disabled according to this transaction's current state.
/// </summary>
/// <remarks>
/// <para>This should be roughly equivalent to <c>DisabledPlugins.Contains(meta)</c>, but more performant.</para>
/// <para>This should also always return the inverse of <see cref="IsEnabled(PluginMetadata)"/> for valid plugins.</para>
/// </remarks>
/// <param name="meta">the plugin to check</param>
/// <returns><see langword="true"/> if the plugin is disabled, <see langword="false"/> otherwise</returns>
/// <seealso cref="DisabledPlugins"/>
/// <see cref="IsEnabled(PluginMetadata)"/>
public bool IsDisabled(PluginMetadata meta) public bool IsDisabled(PluginMetadata meta)
=> ThrowIfDisposed<bool>() => ThrowIfDisposed<bool>()
|| (currentlyDisabled.Contains(meta) && !toEnable.Contains(meta)) || (currentlyDisabled.Contains(meta) && !toEnable.Contains(meta))
|| toDisable.Contains(meta); || toDisable.Contains(meta);
/// <summary>
/// Enables a plugin in this transaction.
/// </summary>
/// <param name="meta">the plugin to enable</param>
/// <returns><see langword="true"/> if the transaction's state was changed, <see langword="false"/> otherwise</returns>
public bool Enable(PluginMetadata meta) public bool Enable(PluginMetadata meta)
{ // returns whether or not state was changed { // returns whether or not state was changed
ThrowIfDisposed(); ThrowIfDisposed();
@ -49,6 +93,11 @@ namespace IPA.Loader
return true; return true;
} }
/// <summary>
/// Disables a plugin in this transaction.
/// </summary>
/// <param name="meta">the plugin to disable</param>
/// <returns><see langword="true"/> if the transaction's state was changed, <see langword="false"/> otherwise</returns>
public bool Disable(PluginMetadata meta) public bool Disable(PluginMetadata meta)
{ // returns whether or not state was changed { // returns whether or not state was changed
ThrowIfDisposed(); ThrowIfDisposed();
@ -62,7 +111,11 @@ namespace IPA.Loader
return true; return true;
} }
public Task Commit() => PluginManager.CommitTransaction(this);
/// <summary>
/// Commits this transaction to actual state, enabling and disabling plugins as necessary.
/// </summary>
/// <returns>a <see cref="Task"/> which completes whenever all disables complete</returns>
public Task Commit() => ThrowIfDisposed<Task>() ?? PluginManager.CommitTransaction(this);
private void ThrowIfDisposed() => ThrowIfDisposed<byte>(); private void ThrowIfDisposed() => ThrowIfDisposed<byte>();
private T ThrowIfDisposed<T>() private T ThrowIfDisposed<T>()
@ -73,6 +126,9 @@ namespace IPA.Loader
} }
private bool disposed = false; private bool disposed = false;
/// <summary>
/// Disposes and discards this transaction without committing it.
/// </summary>
public void Dispose() public void Dispose()
=> disposed = true; => disposed = true;
} }


Loading…
Cancel
Save