[API13] Fire ActivePluginsChanged after a plugin loaded/unloaded (#2334)

* Fire ActivePluginsChanged after a plugin loaded/unloaded

* Add ActivePluginsChangedEventArgs

* Use past tense
This commit is contained in:
Haselnussbomber 2025-08-04 03:28:44 +02:00 committed by GitHub
parent 7131ad36a6
commit 191dfb57e3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 70 additions and 22 deletions

View file

@ -0,0 +1,31 @@
using System.Collections.Generic;
namespace Dalamud.Plugin;
/// <summary>
/// Contains data about changes to the list of active plugins.
/// </summary>
public class ActivePluginsChangedEventArgs : EventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="ActivePluginsChangedEventArgs"/> class
/// with the specified parameters.
/// </summary>
/// <param name="kind">The kind of change that triggered the event.</param>
/// <param name="affectedInternalNames">The internal names of the plugins affected by the change.</param>
internal ActivePluginsChangedEventArgs(PluginListInvalidationKind kind, IEnumerable<string> affectedInternalNames)
{
this.Kind = kind;
this.AffectedInternalNames = affectedInternalNames;
}
/// <summary>
/// Gets the invalidation kind that caused this event to be fired.
/// </summary>
public PluginListInvalidationKind Kind { get; }
/// <summary>
/// Gets the InternalNames of affected plugins.
/// </summary>
public IEnumerable<string> AffectedInternalNames { get; }
}

View file

@ -488,15 +488,14 @@ internal sealed class DalamudPluginInterface : IDalamudPluginInterface, IDisposa
/// <summary>
/// Dispatch the active plugins changed event.
/// </summary>
/// <param name="kind">What action caused this event to be fired.</param>
/// <param name="affectedThisPlugin">If this plugin was affected by the change.</param>
internal void NotifyActivePluginsChanged(PluginListInvalidationKind kind, bool affectedThisPlugin)
/// <param name="args">The event arguments containing information about the change.</param>
internal void NotifyActivePluginsChanged(ActivePluginsChangedEventArgs args)
{
foreach (var action in Delegate.EnumerateInvocationList(this.ActivePluginsChanged))
{
try
{
action(kind, affectedThisPlugin);
action(args);
}
catch (Exception ex)
{

View file

@ -32,9 +32,8 @@ public interface IDalamudPluginInterface
/// <summary>
/// Delegate for events that listen to changes to the list of active plugins.
/// </summary>
/// <param name="kind">What action caused this event to be fired.</param>
/// <param name="affectedThisPlugin">If this plugin was affected by the change.</param>
public delegate void ActivePluginsChangedDelegate(PluginListInvalidationKind kind, bool affectedThisPlugin);
/// <param name="args">The event arguments containing information about the change.</param>
public delegate void ActivePluginsChangedDelegate(ActivePluginsChangedEventArgs args);
/// <summary>
/// Event that gets fired when loc is changed

View file

@ -1292,6 +1292,23 @@ internal class PluginManager : IInternalDisposableService
/// <returns>The calling plugin, or null.</returns>
public LocalPlugin? FindCallingPlugin() => this.FindCallingPlugin(new StackTrace());
/// <summary>
/// Notifies all plugins that the active plugins list changed.
/// </summary>
/// <param name="kind">The invalidation kind.</param>
/// <param name="affectedInternalNames">The affected plugins.</param>
public void NotifyPluginsForStateChange(PluginListInvalidationKind kind, IEnumerable<string> affectedInternalNames)
{
foreach (var installedPlugin in this.installedPluginsList)
{
if (!installedPlugin.IsLoaded || installedPlugin.DalamudInterface == null)
continue;
installedPlugin.DalamudInterface.NotifyActivePluginsChanged(
new ActivePluginsChangedEventArgs(kind, affectedInternalNames));
}
}
/// <summary>
/// Resolves the services that a plugin may have a dependency on.<br />
/// This is required, as the lifetime of a plugin cannot be longer than PluginManager,
@ -1821,20 +1838,6 @@ internal class PluginManager : IInternalDisposableService
this.OnInstalledPluginsChanged?.InvokeSafely();
}
private void NotifyPluginsForStateChange(PluginListInvalidationKind kind, IEnumerable<string> affectedInternalNames)
{
foreach (var installedPlugin in this.installedPluginsList)
{
if (!installedPlugin.IsLoaded || installedPlugin.DalamudInterface == null)
continue;
installedPlugin.DalamudInterface.NotifyActivePluginsChanged(
kind,
// ReSharper disable once PossibleMultipleEnumeration
affectedInternalNames.Contains(installedPlugin.Manifest.InternalName));
}
}
private void LoadAndStartLoadSyncPlugins()
{
try

View file

@ -395,6 +395,9 @@ internal class LocalPlugin : IAsyncDisposable
this.dalamudInterface);
this.State = PluginState.Loaded;
Log.Information("Finished loading {PluginName}", this.InternalName);
var manager = Service<PluginManager>.Get();
manager.NotifyPluginsForStateChange(PluginListInvalidationKind.Loaded, [this.manifest.InternalName]);
}
catch (Exception ex)
{
@ -470,6 +473,9 @@ internal class LocalPlugin : IAsyncDisposable
this.State = PluginState.Unloaded;
Log.Information("Finished unloading {PluginName}", this.InternalName);
var manager = Service<PluginManager>.Get();
manager.NotifyPluginsForStateChange(PluginListInvalidationKind.Unloaded, [this.manifest.InternalName]);
}
catch (Exception ex)
{

View file

@ -1,10 +1,20 @@
namespace Dalamud.Plugin;
namespace Dalamud.Plugin;
/// <summary>
/// Causes for a change to the plugin list.
/// </summary>
public enum PluginListInvalidationKind
{
/// <summary>
/// A plugin was loaded.
/// </summary>
Loaded,
/// <summary>
/// A plugin was unloaded.
/// </summary>
Unloaded,
/// <summary>
/// An installer-initiated update reloaded plugins.
/// </summary>