Add functions to get a plugin by assembly

This is intended for advanced IPC scenarios, for example, accepting
a delegate or an object and identifying which plugin it originates
from, in order to display integration information to the user, and/or
to release references when the originating plugin is unloaded/reloaded
if it forgot to clean after itself.
This commit is contained in:
Exter-N 2025-11-10 04:41:01 +01:00
parent dabe7d777b
commit 65237f84a2
3 changed files with 50 additions and 0 deletions

View file

@ -5,6 +5,7 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Threading.Tasks;
using Dalamud.Configuration;
@ -269,6 +270,30 @@ internal sealed class DalamudPluginInterface : IDalamudPluginInterface, IDisposa
return true;
}
/// <summary>
/// Gets the plugin the given assembly is part of.
/// </summary>
/// <param name="assembly">The assembly to check.</param>
/// <returns>The plugin the given assembly is part of, or null if this is a shared assembly or if this information cannot be determined.</returns>
public IExposedPlugin? GetPlugin(Assembly assembly)
=> AssemblyLoadContext.GetLoadContext(assembly) switch
{
null => null,
var context => this.GetPlugin(context),
};
/// <summary>
/// Gets the plugin that loads in the given context.
/// </summary>
/// <param name="context">The context to check.</param>
/// <returns>The plugin that loads in the given context, or null if this isn't a plugin's context or if this information cannot be determined.</returns>
public IExposedPlugin? GetPlugin(AssemblyLoadContext context)
=> Service<PluginManager>.Get().InstalledPlugins.FirstOrDefault(p => p.LoadsIn(context)) switch
{
null => null,
var p => new ExposedPlugin(p),
};
#region IPC
/// <inheritdoc cref="DataShare.GetOrCreateData{T}"/>

View file

@ -1,6 +1,8 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Reflection;
using System.Runtime.Loader;
using System.Threading.Tasks;
using Dalamud.Configuration;
@ -180,6 +182,20 @@ public interface IDalamudPluginInterface
/// <returns>Returns false if the DalamudInterface was null.</returns>
bool OpenDeveloperMenu();
/// <summary>
/// Gets the plugin the given assembly is part of.
/// </summary>
/// <param name="assembly">The assembly to check.</param>
/// <returns>The plugin the given assembly is part of, or null if this is a shared assembly or if this information cannot be determined.</returns>
IExposedPlugin? GetPlugin(Assembly assembly);
/// <summary>
/// Gets the plugin that loads in the given context.
/// </summary>
/// <param name="context">The context to check.</param>
/// <returns>The plugin that loads in the given context, or null if this isn't a plugin's context or if this information cannot be determined.</returns>
IExposedPlugin? GetPlugin(AssemblyLoadContext context);
/// <inheritdoc cref="DataShare.GetOrCreateData{T}"/>
T GetOrCreateData<T>(string tag, Func<T> dataGenerator) where T : class;

View file

@ -3,6 +3,7 @@ using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.ExceptionServices;
using System.Runtime.Loader;
using System.Threading;
using System.Threading.Tasks;
@ -553,6 +554,14 @@ internal class LocalPlugin : IAsyncDisposable
});
}
/// <summary>
/// Checks whether this plugin loads in the given load context.
/// </summary>
/// <param name="context">The load context to check.</param>
/// <returns>Whether this plugin loads in the given load context.</returns>
public bool LoadsIn(AssemblyLoadContext context)
=> this.loader?.LoadContext == context;
/// <summary>
/// Save this plugin manifest.
/// </summary>