Add IInternal/PublicDisposableService (#1696)

* Add IInternal/PublicDisposableService

Plugins are exposed interfaces that are not inherited from
`IDisposable`, but services implementing plugin interfaces often
implement `IDisposable`. Some plugins may try to call
`IDisposable.Dispose` on everything provided, and it also is possible to
use `using` clause too eagerly while working on Dalamud itself, such as
writing `using var smth = await Service<SomeService>.GetAsync();`. Such
behaviors often lead to a difficult-to-debug errors, and making those
services either not an `IDisposable` or making `IDisposable.Dispose` do
nothing if the object has been loaded would prevent such errors. As
`ServiceManager` must be the only class dealing with construction and
disposal of services, `IInternalDisposableService` has been added to
limit who can dispose the object. `IPublicDisposableService` also has
been added to classes that can be constructed and accessed directly by
plugins; for those, `Dispose` will be ignored if the instance is a
service instance, and only `DisposeService` will respond.

In addition, `DalamudPluginInterface` and `UiBuilder` also have been
changed so that their `IDisposable.Dispose` no longer respond, and
instead, internal functions have been added to only allow disposal from
Dalamud.

* Cleanup

* Postmerge fixes

* More explanation on RunOnFrameworkThread(ClearHooks)

* Mark ReliableFileStorage public ctor obsolete

---------

Co-authored-by: goat <16760685+goaaats@users.noreply.github.com>
This commit is contained in:
srkizer 2024-03-17 00:58:05 +09:00 committed by GitHub
parent dcec076ca7
commit 87b9edb448
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
62 changed files with 441 additions and 381 deletions

View file

@ -29,7 +29,7 @@ namespace Dalamud.Game.Gui;
/// </summary>
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
internal sealed unsafe class ChatGui : IDisposable, IServiceType, IChatGui
internal sealed unsafe class ChatGui : IInternalDisposableService, IChatGui
{
private static readonly ModuleLog Log = new("ChatGui");
@ -109,7 +109,7 @@ internal sealed unsafe class ChatGui : IDisposable, IServiceType, IChatGui
/// <summary>
/// Dispose of managed and unmanaged resources.
/// </summary>
void IDisposable.Dispose()
void IInternalDisposableService.DisposeService()
{
this.printMessageHook.Dispose();
this.populateItemLinkHook.Dispose();
@ -409,7 +409,7 @@ internal sealed unsafe class ChatGui : IDisposable, IServiceType, IChatGui
#pragma warning disable SA1015
[ResolveVia<IChatGui>]
#pragma warning restore SA1015
internal class ChatGuiPluginScoped : IDisposable, IServiceType, IChatGui
internal class ChatGuiPluginScoped : IInternalDisposableService, IChatGui
{
[ServiceManager.ServiceDependency]
private readonly ChatGui chatGuiService = Service<ChatGui>.Get();
@ -447,7 +447,7 @@ internal class ChatGuiPluginScoped : IDisposable, IServiceType, IChatGui
public IReadOnlyDictionary<(string PluginName, uint CommandId), Action<uint, SeString>> RegisteredLinkHandlers => this.chatGuiService.RegisteredLinkHandlers;
/// <inheritdoc/>
public void Dispose()
void IInternalDisposableService.DisposeService()
{
this.chatGuiService.ChatMessage -= this.OnMessageForward;
this.chatGuiService.CheckMessageHandled -= this.OnCheckMessageForward;

View file

@ -28,7 +28,7 @@ namespace Dalamud.Game.Gui.ContextMenu;
/// </summary>
[InterfaceVersion("1.0")]
[ServiceManager.EarlyLoadedService]
internal sealed unsafe class ContextMenu : IDisposable, IServiceType, IContextMenu
internal sealed unsafe class ContextMenu : IInternalDisposableService, IContextMenu
{
private static readonly ModuleLog Log = new("ContextMenu");
@ -77,7 +77,7 @@ internal sealed unsafe class ContextMenu : IDisposable, IServiceType, IContextMe
private IReadOnlyList<MenuItem>? SubmenuItems { get; set; }
/// <inheritdoc/>
public void Dispose()
void IInternalDisposableService.DisposeService()
{
var manager = RaptureAtkUnitManager.Instance();
var menu = manager->GetAddonByName("ContextMenu");
@ -496,7 +496,7 @@ original:
#pragma warning disable SA1015
[ResolveVia<IContextMenu>]
#pragma warning restore SA1015
internal class ContextMenuPluginScoped : IDisposable, IServiceType, IContextMenu
internal class ContextMenuPluginScoped : IInternalDisposableService, IContextMenu
{
[ServiceManager.ServiceDependency]
private readonly ContextMenu parentService = Service<ContextMenu>.Get();
@ -514,7 +514,7 @@ internal class ContextMenuPluginScoped : IDisposable, IServiceType, IContextMenu
private object MenuItemsLock { get; } = new();
/// <inheritdoc/>
public void Dispose()
void IInternalDisposableService.DisposeService()
{
this.parentService.OnMenuOpened -= this.OnMenuOpenedForward;

View file

@ -22,7 +22,7 @@ namespace Dalamud.Game.Gui.Dtr;
/// </summary>
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
internal sealed unsafe class DtrBar : IDisposable, IServiceType, IDtrBar
internal sealed unsafe class DtrBar : IInternalDisposableService, IDtrBar
{
private const uint BaseNodeId = 1000;
@ -101,7 +101,7 @@ internal sealed unsafe class DtrBar : IDisposable, IServiceType, IDtrBar
}
/// <inheritdoc/>
void IDisposable.Dispose()
void IInternalDisposableService.DisposeService()
{
this.addonLifecycle.UnregisterListener(this.dtrPostDrawListener);
this.addonLifecycle.UnregisterListener(this.dtrPostRequestedUpdateListener);
@ -493,7 +493,7 @@ internal sealed unsafe class DtrBar : IDisposable, IServiceType, IDtrBar
#pragma warning disable SA1015
[ResolveVia<IDtrBar>]
#pragma warning restore SA1015
internal class DtrBarPluginScoped : IDisposable, IServiceType, IDtrBar
internal class DtrBarPluginScoped : IInternalDisposableService, IDtrBar
{
[ServiceManager.ServiceDependency]
private readonly DtrBar dtrBarService = Service<DtrBar>.Get();
@ -501,7 +501,7 @@ internal class DtrBarPluginScoped : IDisposable, IServiceType, IDtrBar
private readonly Dictionary<string, DtrBarEntry> pluginEntries = new();
/// <inheritdoc/>
public void Dispose()
void IInternalDisposableService.DisposeService()
{
foreach (var entry in this.pluginEntries)
{

View file

@ -16,7 +16,7 @@ namespace Dalamud.Game.Gui.FlyText;
/// </summary>
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
internal sealed class FlyTextGui : IDisposable, IServiceType, IFlyTextGui
internal sealed class FlyTextGui : IInternalDisposableService, IFlyTextGui
{
/// <summary>
/// The native function responsible for adding fly text to the UI. See <see cref="FlyTextGuiAddressResolver.AddFlyText"/>.
@ -78,7 +78,7 @@ internal sealed class FlyTextGui : IDisposable, IServiceType, IFlyTextGui
/// <summary>
/// Disposes of managed and unmanaged resources.
/// </summary>
public void Dispose()
void IInternalDisposableService.DisposeService()
{
this.createFlyTextHook.Dispose();
}
@ -277,7 +277,7 @@ internal sealed class FlyTextGui : IDisposable, IServiceType, IFlyTextGui
#pragma warning disable SA1015
[ResolveVia<IFlyTextGui>]
#pragma warning restore SA1015
internal class FlyTextGuiPluginScoped : IDisposable, IServiceType, IFlyTextGui
internal class FlyTextGuiPluginScoped : IInternalDisposableService, IFlyTextGui
{
[ServiceManager.ServiceDependency]
private readonly FlyTextGui flyTextGuiService = Service<FlyTextGui>.Get();
@ -294,7 +294,7 @@ internal class FlyTextGuiPluginScoped : IDisposable, IServiceType, IFlyTextGui
public event IFlyTextGui.OnFlyTextCreatedDelegate? FlyTextCreated;
/// <inheritdoc/>
public void Dispose()
void IInternalDisposableService.DisposeService()
{
this.flyTextGuiService.FlyTextCreated -= this.FlyTextCreatedForward;

View file

@ -27,7 +27,7 @@ namespace Dalamud.Game.Gui;
/// </summary>
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
internal sealed unsafe class GameGui : IDisposable, IServiceType, IGameGui
internal sealed unsafe class GameGui : IInternalDisposableService, IGameGui
{
private static readonly ModuleLog Log = new("GameGui");
@ -344,7 +344,7 @@ internal sealed unsafe class GameGui : IDisposable, IServiceType, IGameGui
/// <summary>
/// Disables the hooks and submodules of this module.
/// </summary>
void IDisposable.Dispose()
void IInternalDisposableService.DisposeService()
{
this.setGlobalBgmHook.Dispose();
this.handleItemHoverHook.Dispose();
@ -520,7 +520,7 @@ internal sealed unsafe class GameGui : IDisposable, IServiceType, IGameGui
#pragma warning disable SA1015
[ResolveVia<IGameGui>]
#pragma warning restore SA1015
internal class GameGuiPluginScoped : IDisposable, IServiceType, IGameGui
internal class GameGuiPluginScoped : IInternalDisposableService, IGameGui
{
[ServiceManager.ServiceDependency]
private readonly GameGui gameGuiService = Service<GameGui>.Get();
@ -558,7 +558,7 @@ internal class GameGuiPluginScoped : IDisposable, IServiceType, IGameGui
public HoveredAction HoveredAction => this.gameGuiService.HoveredAction;
/// <inheritdoc/>
public void Dispose()
void IInternalDisposableService.DisposeService()
{
this.gameGuiService.UiHideToggled -= this.UiHideToggledForward;
this.gameGuiService.HoveredItemChanged -= this.HoveredItemForward;

View file

@ -15,7 +15,7 @@ namespace Dalamud.Game.Gui.PartyFinder;
/// </summary>
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
internal sealed class PartyFinderGui : IDisposable, IServiceType, IPartyFinderGui
internal sealed class PartyFinderGui : IInternalDisposableService, IPartyFinderGui
{
private readonly PartyFinderAddressResolver address;
private readonly IntPtr memory;
@ -47,7 +47,7 @@ internal sealed class PartyFinderGui : IDisposable, IServiceType, IPartyFinderGu
/// <summary>
/// Dispose of managed and unmanaged resources.
/// </summary>
void IDisposable.Dispose()
void IInternalDisposableService.DisposeService()
{
this.receiveListingHook.Dispose();
@ -131,7 +131,7 @@ internal sealed class PartyFinderGui : IDisposable, IServiceType, IPartyFinderGu
#pragma warning disable SA1015
[ResolveVia<IPartyFinderGui>]
#pragma warning restore SA1015
internal class PartyFinderGuiPluginScoped : IDisposable, IServiceType, IPartyFinderGui
internal class PartyFinderGuiPluginScoped : IInternalDisposableService, IPartyFinderGui
{
[ServiceManager.ServiceDependency]
private readonly PartyFinderGui partyFinderGuiService = Service<PartyFinderGui>.Get();
@ -148,7 +148,7 @@ internal class PartyFinderGuiPluginScoped : IDisposable, IServiceType, IPartyFin
public event IPartyFinderGui.PartyFinderListingEventDelegate? ReceiveListing;
/// <inheritdoc/>
public void Dispose()
void IInternalDisposableService.DisposeService()
{
this.partyFinderGuiService.ReceiveListing -= this.ReceiveListingForward;

View file

@ -14,7 +14,7 @@ namespace Dalamud.Game.Gui.Toast;
/// </summary>
[InterfaceVersion("1.0")]
[ServiceManager.BlockingEarlyLoadedService]
internal sealed partial class ToastGui : IDisposable, IServiceType, IToastGui
internal sealed partial class ToastGui : IInternalDisposableService, IToastGui
{
private const uint QuestToastCheckmarkMagic = 60081;
@ -73,7 +73,7 @@ internal sealed partial class ToastGui : IDisposable, IServiceType, IToastGui
/// <summary>
/// Disposes of managed and unmanaged resources.
/// </summary>
void IDisposable.Dispose()
void IInternalDisposableService.DisposeService()
{
this.showNormalToastHook.Dispose();
this.showQuestToastHook.Dispose();
@ -383,7 +383,7 @@ internal sealed partial class ToastGui
#pragma warning disable SA1015
[ResolveVia<IToastGui>]
#pragma warning restore SA1015
internal class ToastGuiPluginScoped : IDisposable, IServiceType, IToastGui
internal class ToastGuiPluginScoped : IInternalDisposableService, IToastGui
{
[ServiceManager.ServiceDependency]
private readonly ToastGui toastGuiService = Service<ToastGui>.Get();
@ -408,7 +408,7 @@ internal class ToastGuiPluginScoped : IDisposable, IServiceType, IToastGui
public event IToastGui.OnErrorToastDelegate? ErrorToast;
/// <inheritdoc/>
public void Dispose()
void IInternalDisposableService.DisposeService()
{
this.toastGuiService.Toast -= this.ToastForward;
this.toastGuiService.QuestToast -= this.QuestToastForward;