Browse Source

Added checks for enablability and calls to enable/disable events

4.0.0-beta
Anairkoen Schno 4 years ago
parent
commit
1379900b3d
3 changed files with 71 additions and 17 deletions
  1. +1
    -0
      IPA.Loader/IPA.Loader.csproj
  2. +37
    -0
      IPA.Loader/Loader/CannotRuntimeDisableException.cs
  3. +33
    -17
      IPA.Loader/Loader/PluginManager.cs

+ 1
- 0
IPA.Loader/IPA.Loader.csproj View File

@ -107,6 +107,7 @@
<Compile Include="Config\Stores\ValueConverter.cs" /> <Compile Include="Config\Stores\ValueConverter.cs" />
<Compile Include="JsonConverters\AlmostVersionConverter.cs" /> <Compile Include="JsonConverters\AlmostVersionConverter.cs" />
<Compile Include="JsonConverters\MultilineStringConverter.cs" /> <Compile Include="JsonConverters\MultilineStringConverter.cs" />
<Compile Include="Loader\CannotRuntimeDisableException.cs" />
<Compile Include="Loader\Composite\CompositeBSPlugin.cs" /> <Compile Include="Loader\Composite\CompositeBSPlugin.cs" />
<Compile Include="Loader\DisabledConfig.cs" /> <Compile Include="Loader\DisabledConfig.cs" />
<Compile Include="Loader\Features\ConfigProviderFeature.cs" /> <Compile Include="Loader\Features\ConfigProviderFeature.cs" />


+ 37
- 0
IPA.Loader/Loader/CannotRuntimeDisableException.cs View File

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IPA.Loader
{
/// <summary>
/// Indicates that a plugin cannot be disabled at runtime. Generally not considered an error, however.
/// </summary>
[Serializable]
public class CannotRuntimeDisableException : Exception
{
/// <summary>
/// The plugin that cannot be disabled at runtime.
/// </summary>
public PluginMetadata Plugin { get; }
/// <summary>
/// Creates an exception for the given plugin metadata.
/// </summary>
/// <param name="plugin">the plugin that cannot be disabled</param>
public CannotRuntimeDisableException(PluginMetadata plugin) : base($"Cannot runtime disable plugin \"{plugin.Name}\" ({plugin.Id})")
=> Plugin = plugin;
/// <summary>
/// Creates an exception from a serialization context. Not currently implemented.
/// </summary>
/// <param name="serializationInfo"></param>
/// <param name="streamingContext"></param>
/// <exception cref="NotImplementedException"></exception>
protected CannotRuntimeDisableException(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext)
{
throw new NotImplementedException();
}
}
}

+ 33
- 17
IPA.Loader/Loader/PluginManager.cs View File

@ -88,7 +88,6 @@ namespace IPA.Loader
throw new InvalidOperationException("Transaction no longer resembles the current state of plugins"); throw new InvalidOperationException("Transaction no longer resembles the current state of plugins");
} }
var toEnable = transaction.ToEnable; var toEnable = transaction.ToEnable;
var toDisable = transaction.ToDisable; var toDisable = transaction.ToDisable;
transaction.Dispose(); transaction.Dispose();
@ -111,26 +110,35 @@ namespace IPA.Loader
foreach (var meta in enableOrder) foreach (var meta in enableOrder)
{ {
var executor = runtimeDisabledPlugins.FirstOrDefault(e => e.Metadata == meta); var executor = runtimeDisabledPlugins.FirstOrDefault(e => e.Metadata == meta);
if (executor != null)
runtimeDisabledPlugins.Remove(executor);
else
executor = PluginLoader.InitPlugin(meta, AllPlugins);
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
if (executor == null) continue; // couldn't initialize, skip to next
}
PluginLoader.DisabledPlugins.Remove(meta); PluginLoader.DisabledPlugins.Remove(meta);
DisabledConfig.Instance.DisabledModIds.Remove(meta.Id ?? meta.Name); DisabledConfig.Instance.DisabledModIds.Remove(meta.Id ?? meta.Name);
_bsPlugins.Add(executor);
try
{
executor.Enable();
}
catch (Exception e)
PluginEnabled(meta, meta.RuntimeOptions != RuntimeOptions.DynamicInit);
if (meta.RuntimeOptions == RuntimeOptions.DynamicInit)
{ {
Logger.loader.Error($"Error while enabling {meta.Id}:");
Logger.loader.Error(e);
// this should still be considered enabled, hence its position
_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
}
} }
} }
} }
@ -149,10 +157,15 @@ namespace IPA.Loader
foreach (var exec in disableExecs) foreach (var exec in disableExecs)
{ {
runtimeDisabledPlugins.Add(exec);
PluginLoader.DisabledPlugins.Add(exec.Metadata); PluginLoader.DisabledPlugins.Add(exec.Metadata);
DisabledConfig.Instance.DisabledModIds.Add(exec.Metadata.Id ?? exec.Metadata.Name); DisabledConfig.Instance.DisabledModIds.Add(exec.Metadata.Id ?? exec.Metadata.Name);
_bsPlugins.Remove(exec);
if (exec.Metadata.RuntimeOptions == RuntimeOptions.DynamicInit)
{
runtimeDisabledPlugins.Add(exec);
_bsPlugins.Remove(exec);
}
PluginDisabled(exec.Metadata, exec.Metadata.RuntimeOptions != RuntimeOptions.DynamicInit);
} }
var disableStructure = disableExecs.Select(MakeDisableExec); var disableStructure = disableExecs.Select(MakeDisableExec);
@ -163,6 +176,9 @@ namespace IPA.Loader
return task; return task;
else else
{ {
if (exec.Executor.Metadata.RuntimeOptions != RuntimeOptions.DynamicInit)
return TaskEx.FromException(new CannotRuntimeDisableException(exec.Executor.Metadata));
var res = TaskEx.WhenAll(exec.Dependents.Select(d => Disable(d, alreadyDisabled))) var res = TaskEx.WhenAll(exec.Dependents.Select(d => Disable(d, alreadyDisabled)))
.ContinueWith(t => TaskEx.WhenAll(t, exec.Executor.Disable())).Unwrap(); .ContinueWith(t => TaskEx.WhenAll(t, exec.Executor.Disable())).Unwrap();
// The WhenAll above allows us to wait for the executor to disable, but still propagate errors // The WhenAll above allows us to wait for the executor to disable, but still propagate errors


Loading…
Cancel
Save