From 428aade59ef6a074b709d874e1ee3f054837d0ee Mon Sep 17 00:00:00 2001 From: Anairkoen Schno Date: Sun, 5 Apr 2020 01:41:15 -0500 Subject: [PATCH] Transaction commit now correctly clones the transaction when scheduling processing on the Unity main thread --- IPA.Loader/Loader/PluginManager.cs | 7 ++++++- IPA.Loader/Loader/StateTransitionTransaction.cs | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/IPA.Loader/Loader/PluginManager.cs b/IPA.Loader/Loader/PluginManager.cs index 72b9ee46..48d2ffc0 100644 --- a/IPA.Loader/Loader/PluginManager.cs +++ b/IPA.Loader/Loader/PluginManager.cs @@ -85,7 +85,11 @@ namespace IPA.Loader if (!transaction.HasStateChanged) return TaskEx.WhenAll(); if (!UnityGame.OnMainThread) - return UnityMainThreadTaskScheduler.Factory.StartNew(() => CommitTransaction(transaction)).Unwrap(); + { + var transactionCopy = transaction.Clone(); + transaction.Dispose(); + return UnityMainThreadTaskScheduler.Factory.StartNew(() => CommitTransaction(transactionCopy)).Unwrap(); + } lock (commitTransactionLockObject) { @@ -94,6 +98,7 @@ namespace IPA.Loader || transaction.CurrentlyDisabled.Except(DisabledPlugins) .Concat(DisabledPlugins.Except(transaction.CurrentlyDisabled)).Any()) { // ensure that the transaction's base state reflects the current state, otherwise throw + transaction.Dispose(); throw new InvalidOperationException("Transaction no longer resembles the current state of plugins"); } diff --git a/IPA.Loader/Loader/StateTransitionTransaction.cs b/IPA.Loader/Loader/StateTransitionTransaction.cs index 41f6efef..e3209d00 100644 --- a/IPA.Loader/Loader/StateTransitionTransaction.cs +++ b/IPA.Loader/Loader/StateTransitionTransaction.cs @@ -237,6 +237,23 @@ namespace IPA.Loader /// if the plugins' state no longer matches this transaction's original state public Task Commit() => ThrowIfDisposed() ?? PluginManager.CommitTransaction(this); + /// + /// Clones this transaction to be identical, but with unrelated underlying sets. + /// + /// the new + /// if this object has been disposed + public StateTransitionTransaction Clone() + { + ThrowIfDisposed(); + var copy = new StateTransitionTransaction(CurrentlyEnabled, CurrentlyDisabled); + foreach (var toEnable in ToEnable) + copy.toEnable.Add(toEnable); + foreach (var toDisable in ToDisable) + copy.toDisable.Add(toDisable); + copy.stateChanged = stateChanged; + return copy; + } + private void ThrowIfDisposed() => ThrowIfDisposed(); private T ThrowIfDisposed() {