internal static Task CommitTransaction(StateTransitionTransaction transaction) { if (!UnityGame.OnMainThread) { return(UnityMainThreadTaskScheduler.Factory.StartNew(() => CommitTransaction(transaction)).Unwrap()); } lock (commitTransactionLockObject) { if (transaction.CurrentlyEnabled.Except(AllPlugins) .Concat(AllPlugins.Except(transaction.CurrentlyEnabled)).Any() || transaction.CurrentlyDisabled.Except(DisabledPlugins) .Concat(DisabledPlugins.Except(transaction.CurrentlyDisabled)).Any()) { // ensure that the transaction's base state reflects the current state, otherwise throw throw new InvalidOperationException("Transaction no longer resembles the current state of plugins"); } var toEnable = transaction.ToEnable; var toDisable = transaction.ToDisable; transaction.Dispose(); using var disabledChangeTransaction = DisabledConfig.Instance.ChangeTransaction(); { // first enable the mods that need to be void DeTree(List <PluginMetadata> into, IEnumerable <PluginMetadata> tree) { foreach (var st in tree) { if (toEnable.Contains(st) && !into.Contains(st)) { DeTree(into, st.Dependencies); into.Add(st); } } } var enableOrder = new List <PluginMetadata>(); DeTree(enableOrder, toEnable); foreach (var meta in enableOrder) { var executor = runtimeDisabledPlugins.FirstOrDefault(e => e.Metadata == meta); if (meta.RuntimeOptions == RuntimeOptions.DynamicInit) { if (executor != null) { runtimeDisabledPlugins.Remove(executor); } else { executor = PluginLoader.InitPlugin(meta, AllPlugins); } if (executor == null) { continue; // couldn't initialize, skip to next } } PluginLoader.DisabledPlugins.Remove(meta); DisabledConfig.Instance.DisabledModIds.Remove(meta.Id ?? meta.Name); PluginEnabled?.Invoke(meta, meta.RuntimeOptions != RuntimeOptions.DynamicInit); if (meta.RuntimeOptions == RuntimeOptions.DynamicInit) { _bsPlugins.Add(executor); try { executor.Enable(); } catch (Exception e) { Logger.loader.Error($"Error while enabling {meta.Id}:"); Logger.loader.Error(e); // this should still be considered enabled, hence its position } } } } Task result; {
/// <summary> /// Enables a plugin that had been previously disabled. /// </summary> /// <param name="plugin">the plugin to enable</param> /// <returns>whether a restart is needed to activate</returns> public static bool EnablePlugin(PluginMetadata plugin) { if (plugin == null) { return(false); } if (plugin.IsBare) { Logger.loader.Warn($"Trying to enable bare manifest"); return(false); } if (!IsDisabled(plugin)) { return(false); } Logger.loader.Info($"Enabling {plugin.Name}"); DisabledConfig.Ref.Value.DisabledModIds.Remove(plugin.Id ?? plugin.Name); DisabledConfig.Provider.Store(DisabledConfig.Ref.Value); var needsRestart = true; var depsNeedRestart = plugin.Dependencies.Aggregate(false, (b, p) => EnablePlugin(p) || b); var runtimeInfo = runtimeDisabled.FirstOrDefault(p => p.Metadata == plugin); if (runtimeInfo != null && runtimeInfo.Plugin is IDisablablePlugin disable) { try { disable.OnEnable(); } catch (Exception e) { Logger.loader.Error($"Error occurred trying to enable {plugin.Name}"); Logger.loader.Error(e); } needsRestart = false; } else { PluginLoader.DisabledPlugins.Remove(plugin); if (runtimeInfo == null) { runtimeInfo = InitPlugin(plugin); needsRestart = false; } } if (runtimeInfo != null) { runtimeDisabled.Remove(runtimeInfo); } _bsPlugins.Add(runtimeInfo); try { PluginEnabled?.Invoke(runtimeInfo, needsRestart || depsNeedRestart); } catch (Exception e) { Logger.loader.Error($"Error occurred invoking enable event for {plugin.Name}"); Logger.loader.Error(e); } return(needsRestart || depsNeedRestart); }
protected virtual void OnPluginEnabled(PluginEventArgs e) { PluginEnabled?.Invoke(this, e); }
/// <summary> /// Triggers the PluginEnabled event /// </summary> protected virtual void OnPluginEnabled() { PluginEnabled?.Invoke(this, EventArgs.Empty); }