using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace IPA.Loader { public sealed class StateTransitionTransaction : IDisposable { private readonly HashSet currentlyEnabled; private readonly HashSet currentlyDisabled; private readonly HashSet toEnable = new HashSet(); private readonly HashSet toDisable = new HashSet(); internal StateTransitionTransaction(IEnumerable enabled, IEnumerable disabled) { currentlyEnabled = new HashSet(enabled.ToArray()); currentlyDisabled = new HashSet(disabled.ToArray()); } public bool WillNeedRestart => toEnable.Concat(toDisable).Any(m => m.RuntimeOptions != RuntimeOptions.DynamicInit); internal IEnumerable ToEnable => toEnable; internal IEnumerable ToDisable => toDisable; public IEnumerable EnabledPlugins => currentlyEnabled.Except(toDisable).Concat(toEnable); public IEnumerable DisabledPlugins => currentlyDisabled.Except(toEnable).Concat(toDisable); public bool IsEnabled(PluginMetadata meta) => ThrowIfDisposed() || (currentlyEnabled.Contains(meta) && !toDisable.Contains(meta)) || toEnable.Contains(meta); public bool IsDisabled(PluginMetadata meta) => ThrowIfDisposed() || (currentlyDisabled.Contains(meta) && !toEnable.Contains(meta)) || toDisable.Contains(meta); public bool Enable(PluginMetadata meta) { // returns whether or not state was changed ThrowIfDisposed(); if (!currentlyEnabled.Contains(meta) && !currentlyDisabled.Contains(meta)) throw new ArgumentException(nameof(meta), "Plugin metadata does not represent a loadable plugin"); if (toEnable.Contains(meta)) return false; if (currentlyEnabled.Contains(meta) && !toDisable.Contains(meta)) return false; toDisable.Remove(meta); toEnable.Add(meta); return true; } public bool Disable(PluginMetadata meta) { // returns whether or not state was changed ThrowIfDisposed(); if (!currentlyEnabled.Contains(meta) && !currentlyDisabled.Contains(meta)) throw new ArgumentException(nameof(meta), "Plugin metadata does not represent a "); if (toEnable.Contains(meta)) return false; if (currentlyEnabled.Contains(meta) && !toDisable.Contains(meta)) return false; toDisable.Remove(meta); toEnable.Add(meta); return true; } public Task Commit() => PluginManager.CommitTransaction(this); private void ThrowIfDisposed() => ThrowIfDisposed(); private T ThrowIfDisposed() { if (disposed) throw new ObjectDisposedException(nameof(StateTransitionTransaction)); return default; } private bool disposed = false; public void Dispose() => disposed = true; } }