mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 10:17:22 +01:00
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:
parent
dcec076ca7
commit
87b9edb448
62 changed files with 441 additions and 381 deletions
|
|
@ -97,8 +97,6 @@ namespace Dalamud.CorePlugin
|
|||
this.Interface.UiBuilder.Draw -= this.OnDraw;
|
||||
|
||||
this.windowSystem.RemoveAllWindows();
|
||||
|
||||
this.Interface.ExplicitDispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ namespace Dalamud.Configuration.Internal;
|
|||
#pragma warning disable SA1015
|
||||
[InherentDependency<ReliableFileStorage>] // We must still have this when unloading
|
||||
#pragma warning restore SA1015
|
||||
internal sealed class DalamudConfiguration : IServiceType, IDisposable
|
||||
internal sealed class DalamudConfiguration : IInternalDisposableService
|
||||
{
|
||||
private static readonly JsonSerializerSettings SerializerSettings = new()
|
||||
{
|
||||
|
|
@ -502,7 +502,7 @@ internal sealed class DalamudConfiguration : IServiceType, IDisposable
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
// Make sure that we save, if a save is queued while we are shutting down
|
||||
this.Update();
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ using System.Threading.Tasks;
|
|||
using Dalamud.Common;
|
||||
using Dalamud.Configuration.Internal;
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Interface.Internal;
|
||||
using Dalamud.Plugin.Internal;
|
||||
using Dalamud.Storage;
|
||||
using Dalamud.Utility;
|
||||
|
|
@ -187,27 +186,6 @@ internal sealed class Dalamud : IServiceType
|
|||
this.unloadSignal.WaitOne();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose subsystems related to plugin handling.
|
||||
/// </summary>
|
||||
public void DisposePlugins()
|
||||
{
|
||||
// this must be done before unloading interface manager, in order to do rebuild
|
||||
// the correct cascaded WndProc (IME -> RawDX11Scene -> Game). Otherwise the game
|
||||
// will not receive any windows messages
|
||||
Service<DalamudIme>.GetNullable()?.Dispose();
|
||||
|
||||
// this must be done before unloading plugins, or it can cause a race condition
|
||||
// due to rendering happening on another thread, where a plugin might receive
|
||||
// a render call after it has been disposed, which can crash if it attempts to
|
||||
// use any resources that it freed in its own Dispose method
|
||||
Service<InterfaceManager>.GetNullable()?.Dispose();
|
||||
|
||||
Service<DalamudInterface>.GetNullable()?.Dispose();
|
||||
|
||||
Service<PluginManager>.GetNullable()?.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replace the current exception handler with the default one.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ namespace Dalamud.Data;
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IDataManager>]
|
||||
#pragma warning restore SA1015
|
||||
internal sealed class DataManager : IDisposable, IServiceType, IDataManager
|
||||
internal sealed class DataManager : IInternalDisposableService, IDataManager
|
||||
{
|
||||
private readonly Thread luminaResourceThread;
|
||||
private readonly CancellationTokenSource luminaCancellationTokenSource;
|
||||
|
|
@ -158,7 +158,7 @@ internal sealed class DataManager : IDisposable, IServiceType, IDataManager
|
|||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
void IDisposable.Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.luminaCancellationTokenSource.Cancel();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,7 +138,9 @@ public sealed class EntryPoint
|
|||
SerilogEventSink.Instance.LogLine += SerilogOnLogLine;
|
||||
|
||||
// Load configuration first to get some early persistent state, like log level
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
var fs = new ReliableFileStorage(Path.GetDirectoryName(info.ConfigurationPath)!);
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
var configuration = DalamudConfiguration.Load(info.ConfigurationPath!, fs);
|
||||
|
||||
// Set the appropriate logging level from the configuration
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace Dalamud.Game.Addon.Events;
|
|||
/// </summary>
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.EarlyLoadedService]
|
||||
internal unsafe class AddonEventManager : IDisposable, IServiceType
|
||||
internal unsafe class AddonEventManager : IInternalDisposableService
|
||||
{
|
||||
/// <summary>
|
||||
/// PluginName for Dalamud Internal use.
|
||||
|
|
@ -62,7 +62,7 @@ internal unsafe class AddonEventManager : IDisposable, IServiceType
|
|||
private delegate nint UpdateCursorDelegate(RaptureAtkModule* module);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.onUpdateCursor.Dispose();
|
||||
|
||||
|
|
@ -204,7 +204,7 @@ internal unsafe class AddonEventManager : IDisposable, IServiceType
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IAddonEventManager>]
|
||||
#pragma warning restore SA1015
|
||||
internal class AddonEventManagerPluginScoped : IDisposable, IServiceType, IAddonEventManager
|
||||
internal class AddonEventManagerPluginScoped : IInternalDisposableService, IAddonEventManager
|
||||
{
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly AddonEventManager eventManagerService = Service<AddonEventManager>.Get();
|
||||
|
|
@ -225,7 +225,7 @@ internal class AddonEventManagerPluginScoped : IDisposable, IServiceType, IAddon
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
// if multiple plugins force cursors and dispose without un-forcing them then all forces will be cleared.
|
||||
if (this.isForcingCursor)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace Dalamud.Game.Addon.Lifecycle;
|
|||
/// </summary>
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.EarlyLoadedService]
|
||||
internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
||||
internal unsafe class AddonLifecycle : IInternalDisposableService
|
||||
{
|
||||
private static readonly ModuleLog Log = new("AddonLifecycle");
|
||||
|
||||
|
|
@ -89,7 +89,7 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
|||
internal List<AddonLifecycleEventListener> EventListeners { get; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.onAddonSetupHook.Dispose();
|
||||
this.onAddonSetup2Hook.Dispose();
|
||||
|
|
@ -383,7 +383,7 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IAddonLifecycle>]
|
||||
#pragma warning restore SA1015
|
||||
internal class AddonLifecyclePluginScoped : IDisposable, IServiceType, IAddonLifecycle
|
||||
internal class AddonLifecyclePluginScoped : IInternalDisposableService, IAddonLifecycle
|
||||
{
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly AddonLifecycle addonLifecycleService = Service<AddonLifecycle>.Get();
|
||||
|
|
@ -391,7 +391,7 @@ internal class AddonLifecyclePluginScoped : IDisposable, IServiceType, IAddonLif
|
|||
private readonly List<AddonLifecycleEventListener> eventListeners = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
foreach (var listener in this.eventListeners)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace Dalamud.Game.ClientState;
|
|||
/// </summary>
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
internal sealed class ClientState : IDisposable, IServiceType, IClientState
|
||||
internal sealed class ClientState : IInternalDisposableService, IClientState
|
||||
{
|
||||
private static readonly ModuleLog Log = new("ClientState");
|
||||
|
||||
|
|
@ -115,7 +115,7 @@ internal sealed class ClientState : IDisposable, IServiceType, IClientState
|
|||
/// <summary>
|
||||
/// Dispose of managed and unmanaged resources.
|
||||
/// </summary>
|
||||
void IDisposable.Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.setupTerritoryTypeHook.Dispose();
|
||||
this.framework.Update -= this.FrameworkOnOnUpdateEvent;
|
||||
|
|
@ -196,7 +196,7 @@ internal sealed class ClientState : IDisposable, IServiceType, IClientState
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IClientState>]
|
||||
#pragma warning restore SA1015
|
||||
internal class ClientStatePluginScoped : IDisposable, IServiceType, IClientState
|
||||
internal class ClientStatePluginScoped : IInternalDisposableService, IClientState
|
||||
{
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly ClientState clientStateService = Service<ClientState>.Get();
|
||||
|
|
@ -257,7 +257,7 @@ internal class ClientStatePluginScoped : IDisposable, IServiceType, IClientState
|
|||
public bool IsGPosing => this.clientStateService.IsGPosing;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.clientStateService.TerritoryChanged -= this.TerritoryChangedForward;
|
||||
this.clientStateService.Login -= this.LoginForward;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ namespace Dalamud.Game.ClientState.Conditions;
|
|||
/// </summary>
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
internal sealed partial class Condition : IServiceType, ICondition
|
||||
internal sealed partial class Condition : IInternalDisposableService, ICondition
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the current max number of conditions. You can get this just by looking at the condition sheet and how many rows it has.
|
||||
|
|
@ -22,6 +22,8 @@ internal sealed partial class Condition : IServiceType, ICondition
|
|||
|
||||
private readonly bool[] cache = new bool[MaxConditionEntries];
|
||||
|
||||
private bool isDisposed;
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private Condition(ClientState clientState)
|
||||
{
|
||||
|
|
@ -35,6 +37,9 @@ internal sealed partial class Condition : IServiceType, ICondition
|
|||
this.framework.Update += this.FrameworkUpdate;
|
||||
}
|
||||
|
||||
/// <summary>Finalizes an instance of the <see cref="Condition" /> class.</summary>
|
||||
~Condition() => this.Dispose(false);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event ICondition.ConditionChangeDelegate? ConditionChange;
|
||||
|
||||
|
|
@ -60,6 +65,9 @@ internal sealed partial class Condition : IServiceType, ICondition
|
|||
public bool this[ConditionFlag flag]
|
||||
=> this[(int)flag];
|
||||
|
||||
/// <inheritdoc/>
|
||||
void IInternalDisposableService.DisposeService() => this.Dispose(true);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Any()
|
||||
{
|
||||
|
|
@ -89,6 +97,19 @@ internal sealed partial class Condition : IServiceType, ICondition
|
|||
return false;
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (this.isDisposed)
|
||||
return;
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
this.framework.Update -= this.FrameworkUpdate;
|
||||
}
|
||||
|
||||
this.isDisposed = true;
|
||||
}
|
||||
|
||||
private void FrameworkUpdate(IFramework unused)
|
||||
{
|
||||
for (var i = 0; i < MaxConditionEntries; i++)
|
||||
|
|
@ -112,44 +133,6 @@ internal sealed partial class Condition : IServiceType, ICondition
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides access to conditions (generally player state). You can check whether a player is in combat, mounted, etc.
|
||||
/// </summary>
|
||||
internal sealed partial class Condition : IDisposable
|
||||
{
|
||||
private bool isDisposed;
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="Condition" /> class.
|
||||
/// </summary>
|
||||
~Condition()
|
||||
{
|
||||
this.Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes this instance, alongside its hooks.
|
||||
/// </summary>
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
this.Dispose(true);
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (this.isDisposed)
|
||||
return;
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
this.framework.Update -= this.FrameworkUpdate;
|
||||
}
|
||||
|
||||
this.isDisposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plugin-scoped version of a Condition service.
|
||||
/// </summary>
|
||||
|
|
@ -159,7 +142,7 @@ internal sealed partial class Condition : IDisposable
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<ICondition>]
|
||||
#pragma warning restore SA1015
|
||||
internal class ConditionPluginScoped : IDisposable, IServiceType, ICondition
|
||||
internal class ConditionPluginScoped : IInternalDisposableService, ICondition
|
||||
{
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly Condition conditionService = Service<Condition>.Get();
|
||||
|
|
@ -185,7 +168,7 @@ internal class ConditionPluginScoped : IDisposable, IServiceType, ICondition
|
|||
public bool this[int flag] => this.conditionService[flag];
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.conditionService.ConditionChange -= this.ConditionChangedForward;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ namespace Dalamud.Game.ClientState.GamePad;
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IGamepadState>]
|
||||
#pragma warning restore SA1015
|
||||
internal unsafe class GamepadState : IDisposable, IServiceType, IGamepadState
|
||||
internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
|
||||
{
|
||||
private readonly Hook<ControllerPoll>? gamepadPoll;
|
||||
|
||||
|
|
@ -109,7 +109,7 @@ internal unsafe class GamepadState : IDisposable, IServiceType, IGamepadState
|
|||
/// <summary>
|
||||
/// Disposes this instance, alongside its hooks.
|
||||
/// </summary>
|
||||
void IDisposable.Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace Dalamud.Game.Command;
|
|||
/// </summary>
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
internal sealed class CommandManager : IServiceType, IDisposable, ICommandManager
|
||||
internal sealed class CommandManager : IInternalDisposableService, ICommandManager
|
||||
{
|
||||
private static readonly ModuleLog Log = new("Command");
|
||||
|
||||
|
|
@ -130,7 +130,7 @@ internal sealed class CommandManager : IServiceType, IDisposable, ICommandManage
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
void IDisposable.Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.chatGui.CheckMessageHandled -= this.OnCheckMessageHandled;
|
||||
}
|
||||
|
|
@ -170,7 +170,7 @@ internal sealed class CommandManager : IServiceType, IDisposable, ICommandManage
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<ICommandManager>]
|
||||
#pragma warning restore SA1015
|
||||
internal class CommandManagerPluginScoped : IDisposable, IServiceType, ICommandManager
|
||||
internal class CommandManagerPluginScoped : IInternalDisposableService, ICommandManager
|
||||
{
|
||||
private static readonly ModuleLog Log = new("Command");
|
||||
|
||||
|
|
@ -193,7 +193,7 @@ internal class CommandManagerPluginScoped : IDisposable, IServiceType, ICommandM
|
|||
public ReadOnlyDictionary<string, CommandInfo> Commands => this.commandManagerService.Commands;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
foreach (var command in this.pluginRegisteredCommands)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ namespace Dalamud.Game.Config;
|
|||
/// </summary>
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
internal sealed class GameConfig : IServiceType, IGameConfig, IDisposable
|
||||
internal sealed class GameConfig : IInternalDisposableService, IGameConfig
|
||||
{
|
||||
private readonly TaskCompletionSource tcsInitialization = new();
|
||||
private readonly TaskCompletionSource<GameConfigSection> tcsSystem = new();
|
||||
|
|
@ -195,7 +195,7 @@ internal sealed class GameConfig : IServiceType, IGameConfig, IDisposable
|
|||
public void Set(UiControlOption option, string value) => this.UiControl.Set(option.GetName(), value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
void IDisposable.Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
var ode = new ObjectDisposedException(nameof(GameConfig));
|
||||
this.tcsInitialization.SetExceptionIfIncomplete(ode);
|
||||
|
|
@ -248,7 +248,7 @@ internal sealed class GameConfig : IServiceType, IGameConfig, IDisposable
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IGameConfig>]
|
||||
#pragma warning restore SA1015
|
||||
internal class GameConfigPluginScoped : IDisposable, IServiceType, IGameConfig
|
||||
internal class GameConfigPluginScoped : IInternalDisposableService, IGameConfig
|
||||
{
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly GameConfig gameConfigService = Service<GameConfig>.Get();
|
||||
|
|
@ -295,7 +295,7 @@ internal class GameConfigPluginScoped : IDisposable, IServiceType, IGameConfig
|
|||
public GameConfigSection UiControl => this.gameConfigService.UiControl;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.gameConfigService.Changed -= this.ConfigChangedForward;
|
||||
this.initializationTask.ContinueWith(
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ namespace Dalamud.Game.DutyState;
|
|||
/// </summary>
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
internal unsafe class DutyState : IDisposable, IServiceType, IDutyState
|
||||
internal unsafe class DutyState : IInternalDisposableService, IDutyState
|
||||
{
|
||||
private readonly DutyStateAddressResolver address;
|
||||
private readonly Hook<SetupContentDirectNetworkMessageDelegate> contentDirectorNetworkMessageHook;
|
||||
|
|
@ -62,7 +62,7 @@ internal unsafe class DutyState : IDisposable, IServiceType, IDutyState
|
|||
private bool CompletedThisTerritory { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.contentDirectorNetworkMessageHook.Dispose();
|
||||
this.framework.Update -= this.FrameworkOnUpdateEvent;
|
||||
|
|
@ -168,7 +168,7 @@ internal unsafe class DutyState : IDisposable, IServiceType, IDutyState
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IDutyState>]
|
||||
#pragma warning restore SA1015
|
||||
internal class DutyStatePluginScoped : IDisposable, IServiceType, IDutyState
|
||||
internal class DutyStatePluginScoped : IInternalDisposableService, IDutyState
|
||||
{
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly DutyState dutyStateService = Service<DutyState>.Get();
|
||||
|
|
@ -200,7 +200,7 @@ internal class DutyStatePluginScoped : IDisposable, IServiceType, IDutyState
|
|||
public bool IsDutyStarted => this.dutyStateService.IsDutyStarted;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.dutyStateService.DutyStarted -= this.DutyStartedForward;
|
||||
this.dutyStateService.DutyWiped -= this.DutyWipedForward;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace Dalamud.Game;
|
|||
/// </summary>
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
internal sealed class Framework : IDisposable, IServiceType, IFramework
|
||||
internal sealed class Framework : IInternalDisposableService, IFramework
|
||||
{
|
||||
private static readonly ModuleLog Log = new("Framework");
|
||||
|
||||
|
|
@ -274,7 +274,7 @@ internal sealed class Framework : IDisposable, IServiceType, IFramework
|
|||
/// <summary>
|
||||
/// Dispose of managed and unmanaged resources.
|
||||
/// </summary>
|
||||
void IDisposable.Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.RunOnFrameworkThread(() =>
|
||||
{
|
||||
|
|
@ -469,7 +469,7 @@ internal sealed class Framework : IDisposable, IServiceType, IFramework
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IFramework>]
|
||||
#pragma warning restore SA1015
|
||||
internal class FrameworkPluginScoped : IDisposable, IServiceType, IFramework
|
||||
internal class FrameworkPluginScoped : IInternalDisposableService, IFramework
|
||||
{
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly Framework frameworkService = Service<Framework>.Get();
|
||||
|
|
@ -504,7 +504,7 @@ internal class FrameworkPluginScoped : IDisposable, IServiceType, IFramework
|
|||
public bool IsFrameworkUnloading => this.frameworkService.IsFrameworkUnloading;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.frameworkService.Update -= this.OnUpdateForward;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ namespace Dalamud.Game.Internal;
|
|||
/// This class disables anti-debug functionality in the game client.
|
||||
/// </summary>
|
||||
[ServiceManager.EarlyLoadedService]
|
||||
internal sealed partial class AntiDebug : IServiceType
|
||||
internal sealed class AntiDebug : IInternalDisposableService
|
||||
{
|
||||
private readonly byte[] nop = new byte[] { 0x31, 0xC0, 0x90, 0x90, 0x90, 0x90 };
|
||||
private byte[] original;
|
||||
|
|
@ -43,16 +43,25 @@ internal sealed partial class AntiDebug : IServiceType
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>Finalizes an instance of the <see cref="AntiDebug"/> class.</summary>
|
||||
~AntiDebug() => this.Disable();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the anti-debugging is enabled.
|
||||
/// </summary>
|
||||
public bool IsEnabled { get; private set; } = false;
|
||||
|
||||
/// <inheritdoc />
|
||||
void IInternalDisposableService.DisposeService() => this.Disable();
|
||||
|
||||
/// <summary>
|
||||
/// Enables the anti-debugging by overwriting code in memory.
|
||||
/// </summary>
|
||||
public void Enable()
|
||||
{
|
||||
if (this.IsEnabled)
|
||||
return;
|
||||
|
||||
this.original = new byte[this.nop.Length];
|
||||
if (this.debugCheckAddress != IntPtr.Zero && !this.IsEnabled)
|
||||
{
|
||||
|
|
@ -73,6 +82,9 @@ internal sealed partial class AntiDebug : IServiceType
|
|||
/// </summary>
|
||||
public void Disable()
|
||||
{
|
||||
if (!this.IsEnabled)
|
||||
return;
|
||||
|
||||
if (this.debugCheckAddress != IntPtr.Zero && this.original != null)
|
||||
{
|
||||
Log.Information($"Reverting debug check at 0x{this.debugCheckAddress.ToInt64():X}");
|
||||
|
|
@ -86,45 +98,3 @@ internal sealed partial class AntiDebug : IServiceType
|
|||
this.IsEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementing IDisposable.
|
||||
/// </summary>
|
||||
internal sealed partial class AntiDebug : IDisposable
|
||||
{
|
||||
private bool disposed = false;
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="AntiDebug"/> class.
|
||||
/// </summary>
|
||||
~AntiDebug() => this.Dispose(false);
|
||||
|
||||
/// <summary>
|
||||
/// Disposes of managed and unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes of managed and unmanaged resources.
|
||||
/// </summary>
|
||||
/// <param name="disposing">If this was disposed through calling Dispose() or from being finalized.</param>
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (this.disposed)
|
||||
return;
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
// If anti-debug is enabled and is being disposed, odds are either the game is exiting, or Dalamud is being reloaded.
|
||||
// If it is the latter, there's half a chance a debugger is currently attached. There's no real need to disable the
|
||||
// check in either situation anyways. However if Dalamud is being reloaded, the sig may fail so may as well undo it.
|
||||
this.Disable();
|
||||
}
|
||||
|
||||
this.disposed = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ namespace Dalamud.Game.Internal;
|
|||
/// This class implements in-game Dalamud options in the in-game System menu.
|
||||
/// </summary>
|
||||
[ServiceManager.EarlyLoadedService]
|
||||
internal sealed unsafe partial class DalamudAtkTweaks : IServiceType
|
||||
internal sealed unsafe class DalamudAtkTweaks : IInternalDisposableService
|
||||
{
|
||||
private readonly AtkValueChangeType atkValueChangeType;
|
||||
private readonly AtkValueSetString atkValueSetString;
|
||||
|
|
@ -40,6 +40,8 @@ internal sealed unsafe partial class DalamudAtkTweaks : IServiceType
|
|||
private readonly string locDalamudPlugins;
|
||||
private readonly string locDalamudSettings;
|
||||
|
||||
private bool disposed = false;
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private DalamudAtkTweaks(TargetSigScanner sigScanner)
|
||||
{
|
||||
|
|
@ -69,6 +71,9 @@ internal sealed unsafe partial class DalamudAtkTweaks : IServiceType
|
|||
this.hookAtkUnitBaseReceiveGlobalEvent.Enable();
|
||||
}
|
||||
|
||||
/// <summary>Finalizes an instance of the <see cref="DalamudAtkTweaks"/> class.</summary>
|
||||
~DalamudAtkTweaks() => this.Dispose(false);
|
||||
|
||||
private delegate void AgentHudOpenSystemMenuPrototype(void* thisPtr, AtkValue* atkValueArgs, uint menuSize);
|
||||
|
||||
private delegate void AtkValueChangeType(AtkValue* thisPtr, ValueType type);
|
||||
|
|
@ -79,6 +84,26 @@ internal sealed unsafe partial class DalamudAtkTweaks : IServiceType
|
|||
|
||||
private delegate IntPtr AtkUnitBaseReceiveGlobalEvent(AtkUnitBase* thisPtr, ushort cmd, uint a3, IntPtr a4, uint* a5);
|
||||
|
||||
/// <inheritdoc/>
|
||||
void IInternalDisposableService.DisposeService() => this.Dispose(true);
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (this.disposed)
|
||||
return;
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
this.hookAgentHudOpenSystemMenu.Dispose();
|
||||
this.hookUiModuleRequestMainCommand.Dispose();
|
||||
this.hookAtkUnitBaseReceiveGlobalEvent.Dispose();
|
||||
|
||||
// this.contextMenu.ContextMenuOpened -= this.ContextMenuOnContextMenuOpened;
|
||||
}
|
||||
|
||||
this.disposed = true;
|
||||
}
|
||||
|
||||
/*
|
||||
private void ContextMenuOnContextMenuOpened(ContextMenuOpenedArgs args)
|
||||
{
|
||||
|
|
@ -229,45 +254,3 @@ internal sealed unsafe partial class DalamudAtkTweaks : IServiceType
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements IDisposable.
|
||||
/// </summary>
|
||||
internal sealed partial class DalamudAtkTweaks : IDisposable
|
||||
{
|
||||
private bool disposed = false;
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="DalamudAtkTweaks"/> class.
|
||||
/// </summary>
|
||||
~DalamudAtkTweaks() => this.Dispose(false);
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of managed and unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of managed and unmanaged resources.
|
||||
/// </summary>
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (this.disposed)
|
||||
return;
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
this.hookAgentHudOpenSystemMenu.Dispose();
|
||||
this.hookUiModuleRequestMainCommand.Dispose();
|
||||
this.hookAtkUnitBaseReceiveGlobalEvent.Dispose();
|
||||
|
||||
// this.contextMenu.ContextMenuOpened -= this.ContextMenuOnContextMenuOpened;
|
||||
}
|
||||
|
||||
this.disposed = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace Dalamud.Game.Inventory;
|
|||
/// </summary>
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
internal class GameInventory : IDisposable, IServiceType
|
||||
internal class GameInventory : IInternalDisposableService
|
||||
{
|
||||
private readonly List<GameInventoryPluginScoped> subscribersPendingChange = new();
|
||||
private readonly List<GameInventoryPluginScoped> subscribers = new();
|
||||
|
|
@ -61,7 +61,7 @@ internal class GameInventory : IDisposable, IServiceType
|
|||
private unsafe delegate void RaptureAtkModuleUpdateDelegate(RaptureAtkModule* ram, float f1);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
lock (this.subscribersPendingChange)
|
||||
{
|
||||
|
|
@ -351,7 +351,7 @@ internal class GameInventory : IDisposable, IServiceType
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IGameInventory>]
|
||||
#pragma warning restore SA1015
|
||||
internal class GameInventoryPluginScoped : IDisposable, IServiceType, IGameInventory
|
||||
internal class GameInventoryPluginScoped : IInternalDisposableService, IGameInventory
|
||||
{
|
||||
private static readonly ModuleLog Log = new(nameof(GameInventoryPluginScoped));
|
||||
|
||||
|
|
@ -406,7 +406,7 @@ internal class GameInventoryPluginScoped : IDisposable, IServiceType, IGameInven
|
|||
public event IGameInventory.InventoryChangedDelegate<InventoryItemMergedArgs>? ItemMergedExplicit;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.gameInventoryService.Unsubscribe(this);
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ namespace Dalamud.Game.Network;
|
|||
/// </summary>
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
internal sealed class GameNetwork : IDisposable, IServiceType, IGameNetwork
|
||||
internal sealed class GameNetwork : IInternalDisposableService, IGameNetwork
|
||||
{
|
||||
private readonly GameNetworkAddressResolver address;
|
||||
private readonly Hook<ProcessZonePacketDownDelegate> processZonePacketDownHook;
|
||||
|
|
@ -59,7 +59,7 @@ internal sealed class GameNetwork : IDisposable, IServiceType, IGameNetwork
|
|||
public event IGameNetwork.OnNetworkMessageDelegate? NetworkMessage;
|
||||
|
||||
/// <inheritdoc/>
|
||||
void IDisposable.Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.processZonePacketDownHook.Dispose();
|
||||
this.processZonePacketUpHook.Dispose();
|
||||
|
|
@ -145,7 +145,7 @@ internal sealed class GameNetwork : IDisposable, IServiceType, IGameNetwork
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IGameNetwork>]
|
||||
#pragma warning restore SA1015
|
||||
internal class GameNetworkPluginScoped : IDisposable, IServiceType, IGameNetwork
|
||||
internal class GameNetworkPluginScoped : IInternalDisposableService, IGameNetwork
|
||||
{
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly GameNetwork gameNetworkService = Service<GameNetwork>.Get();
|
||||
|
|
@ -162,7 +162,7 @@ internal class GameNetworkPluginScoped : IDisposable, IServiceType, IGameNetwork
|
|||
public event IGameNetwork.OnNetworkMessageDelegate? NetworkMessage;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.gameNetworkService.NetworkMessage -= this.NetworkMessageForward;
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ namespace Dalamud.Game.Network.Internal;
|
|||
/// This class handles network notifications and uploading market board data.
|
||||
/// </summary>
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
internal unsafe class NetworkHandlers : IDisposable, IServiceType
|
||||
internal unsafe class NetworkHandlers : IInternalDisposableService
|
||||
{
|
||||
private readonly IMarketBoardUploader uploader;
|
||||
|
||||
|
|
@ -213,7 +213,7 @@ internal unsafe class NetworkHandlers : IDisposable, IServiceType
|
|||
/// <summary>
|
||||
/// Disposes of managed and unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.disposing = true;
|
||||
this.Dispose(this.disposing);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ namespace Dalamud.Game.Network.Internal;
|
|||
/// This class enables TCP optimizations in the game socket for better performance.
|
||||
/// </summary>
|
||||
[ServiceManager.EarlyLoadedService]
|
||||
internal sealed class WinSockHandlers : IDisposable, IServiceType
|
||||
internal sealed class WinSockHandlers : IInternalDisposableService
|
||||
{
|
||||
private Hook<SocketDelegate> ws2SocketHook;
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ internal sealed class WinSockHandlers : IDisposable, IServiceType
|
|||
/// <summary>
|
||||
/// Disposes of managed and unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.ws2SocketHook?.Dispose();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,6 +104,10 @@ public class SigScanner : IDisposable, ISigScanner
|
|||
/// <inheritdoc/>
|
||||
public ProcessModule Module { get; }
|
||||
|
||||
/// <summary>Gets or sets a value indicating whether this instance of <see cref="SigScanner"/> is meant to be a
|
||||
/// Dalamud service.</summary>
|
||||
private protected bool IsService { get; set; }
|
||||
|
||||
private IntPtr TextSectionTop => this.TextSectionBase + this.TextSectionSize;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -309,13 +313,11 @@ public class SigScanner : IDisposable, ISigScanner
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Free the memory of the copied module search area on object disposal, if applicable.
|
||||
/// </summary>
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
this.Save();
|
||||
Marshal.FreeHGlobal(this.moduleCopyPtr);
|
||||
if (!this.IsService)
|
||||
this.DisposeCore();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -337,6 +339,15 @@ public class SigScanner : IDisposable, ISigScanner
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Free the memory of the copied module search area on object disposal, if applicable.
|
||||
/// </summary>
|
||||
private protected void DisposeCore()
|
||||
{
|
||||
this.Save();
|
||||
Marshal.FreeHGlobal(this.moduleCopyPtr);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper for ScanText to get the correct address for IDA sigs that mark the first JMP or CALL location.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ namespace Dalamud.Game;
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<ISigScanner>]
|
||||
#pragma warning restore SA1015
|
||||
internal class TargetSigScanner : SigScanner, IServiceType
|
||||
internal class TargetSigScanner : SigScanner, IPublicDisposableService
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TargetSigScanner"/> class.
|
||||
|
|
@ -26,4 +26,14 @@ internal class TargetSigScanner : SigScanner, IServiceType
|
|||
: base(Process.GetCurrentProcess().MainModule!, doCopy, cacheFile)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
if (this.IsService)
|
||||
this.DisposeCore();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
void IPublicDisposableService.MarkDisposeOnlyFromService() => this.IsService = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ namespace Dalamud.Hooking.Internal;
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IGameInteropProvider>]
|
||||
#pragma warning restore SA1015
|
||||
internal class GameInteropProviderPluginScoped : IGameInteropProvider, IServiceType, IDisposable
|
||||
internal class GameInteropProviderPluginScoped : IGameInteropProvider, IInternalDisposableService
|
||||
{
|
||||
private readonly LocalPlugin plugin;
|
||||
private readonly SigScanner scanner;
|
||||
|
|
@ -83,7 +83,7 @@ internal class GameInteropProviderPluginScoped : IGameInteropProvider, IServiceT
|
|||
=> this.HookFromAddress(this.scanner.ScanText(signature), detour, backend);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
var notDisposed = this.trackedHooks.Where(x => !x.IsDisposed).ToArray();
|
||||
if (notDisposed.Length != 0)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ namespace Dalamud.Hooking.Internal;
|
|||
/// This class manages the final disposition of hooks, cleaning up any that have not reverted their changes.
|
||||
/// </summary>
|
||||
[ServiceManager.EarlyLoadedService]
|
||||
internal class HookManager : IDisposable, IServiceType
|
||||
internal class HookManager : IInternalDisposableService
|
||||
{
|
||||
/// <summary>
|
||||
/// Logger shared with <see cref="Unhooker"/>.
|
||||
|
|
@ -74,7 +74,7 @@ internal class HookManager : IDisposable, IServiceType
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
RevertHooks();
|
||||
TrackedHooks.Clear();
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ namespace Dalamud.Hooking.WndProcHook;
|
|||
/// Manages WndProc hooks for game main window and extra ImGui viewport windows.
|
||||
/// </summary>
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
internal sealed class WndProcHookManager : IServiceType, IDisposable
|
||||
internal sealed class WndProcHookManager : IInternalDisposableService
|
||||
{
|
||||
private static readonly ModuleLog Log = new(nameof(WndProcHookManager));
|
||||
|
||||
|
|
@ -56,7 +56,7 @@ internal sealed class WndProcHookManager : IServiceType, IDisposable
|
|||
public event WndProcEventDelegate? PostWndProc;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
if (this.dispatchMessageWHook.IsDisposed)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -6,3 +6,20 @@
|
|||
public interface IServiceType
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary><see cref="IDisposable"/>, but for <see cref="IServiceType"/>.</summary>
|
||||
/// <remarks>Use this to prevent services from accidentally being disposed by plugins or <c>using</c> clauses.</remarks>
|
||||
internal interface IInternalDisposableService : IServiceType
|
||||
{
|
||||
/// <summary>Disposes the service.</summary>
|
||||
void DisposeService();
|
||||
}
|
||||
|
||||
/// <summary>An <see cref="IInternalDisposableService"/> which happens to be public and needs to expose
|
||||
/// <see cref="IDisposable.Dispose"/>.</summary>
|
||||
internal interface IPublicDisposableService : IInternalDisposableService, IDisposable
|
||||
{
|
||||
/// <summary>Marks that only <see cref="IInternalDisposableService.DisposeService"/> should respond,
|
||||
/// while suppressing <see cref="IDisposable.Dispose"/>.</summary>
|
||||
void MarkDisposeOnlyFromService();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace Dalamud.Interface.DragDrop;
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IDragDropManager>]
|
||||
#pragma warning restore SA1015
|
||||
internal partial class DragDropManager : IDisposable, IDragDropManager, IServiceType
|
||||
internal partial class DragDropManager : IInternalDisposableService, IDragDropManager
|
||||
{
|
||||
private nint windowHandlePtr = nint.Zero;
|
||||
|
||||
|
|
@ -56,6 +56,9 @@ internal partial class DragDropManager : IDisposable, IDragDropManager, IService
|
|||
/// <summary> Gets the list of directory paths currently being dragged from an external application over any FFXIV-related viewport or stored from the last drop. </summary>
|
||||
public IReadOnlyList<string> Directories { get; private set; } = Array.Empty<string>();
|
||||
|
||||
/// <inheritdoc/>
|
||||
void IInternalDisposableService.DisposeService() => this.Disable();
|
||||
|
||||
/// <summary> Enable external drag and drop. </summary>
|
||||
public void Enable()
|
||||
{
|
||||
|
|
@ -99,10 +102,6 @@ internal partial class DragDropManager : IDisposable, IDragDropManager, IService
|
|||
this.ServiceAvailable = false;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="Disable"/>
|
||||
public void Dispose()
|
||||
=> this.Disable();
|
||||
|
||||
/// <inheritdoc cref="IDragDropManager.CreateImGuiSource(string, Func{IDragDropManager, bool}, Func{IDragDropManager, bool})"/>
|
||||
public void CreateImGuiSource(string label, Func<IDragDropManager, bool> validityCheck, Func<IDragDropManager, bool> tooltipBuilder)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ public sealed class SingleFontChooserDialog : IDisposable
|
|||
/// <summary>Initializes a new instance of the <see cref="SingleFontChooserDialog"/> class.</summary>
|
||||
/// <param name="newAsyncAtlas">A new instance of <see cref="IFontAtlas"/> created using
|
||||
/// <see cref="FontAtlasAutoRebuildMode.Async"/> as its auto-rebuild mode.</param>
|
||||
/// <remarks>The passed instance of <see cref="newAsyncAtlas"/> will be disposed after use. If you pass an atlas
|
||||
/// <remarks>The passed instance of <paramref see="newAsyncAtlas"/> will be disposed after use. If you pass an atlas
|
||||
/// that is already being used, then all the font handles under the passed atlas will be invalidated upon disposing
|
||||
/// this font chooser. Consider using <see cref="SingleFontChooserDialog(UiBuilder, bool, string?)"/> for automatic
|
||||
/// handling of font atlas derived from a <see cref="UiBuilder"/>, or even <see cref="CreateAuto"/> for automatic
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ namespace Dalamud.Interface.Internal;
|
|||
/// This class handles CJK IME.
|
||||
/// </summary>
|
||||
[ServiceManager.EarlyLoadedService]
|
||||
internal sealed unsafe class DalamudIme : IDisposable, IServiceType
|
||||
internal sealed unsafe class DalamudIme : IInternalDisposableService
|
||||
{
|
||||
private const int CImGuiStbTextCreateUndoOffset = 0xB57A0;
|
||||
private const int CImGuiStbTextUndoOffset = 0xB59C0;
|
||||
|
|
@ -200,7 +200,7 @@ internal sealed unsafe class DalamudIme : IDisposable, IServiceType
|
|||
this.candidateStrings.Count != 0 || this.ShowPartialConversion || this.inputModeIcon != default;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.interfaceManager.Draw -= this.Draw;
|
||||
this.ReleaseUnmanagedResources();
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ namespace Dalamud.Interface.Internal;
|
|||
/// This plugin implements all of the Dalamud interface separately, to allow for reloading of the interface and rapid prototyping.
|
||||
/// </summary>
|
||||
[ServiceManager.EarlyLoadedService]
|
||||
internal class DalamudInterface : IDisposable, IServiceType
|
||||
internal class DalamudInterface : IInternalDisposableService
|
||||
{
|
||||
private const float CreditsDarkeningMaxAlpha = 0.8f;
|
||||
|
||||
|
|
@ -209,7 +209,7 @@ internal class DalamudInterface : IDisposable, IServiceType
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.interfaceManager.Draw -= this.OnDraw;
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ namespace Dalamud.Interface.Internal;
|
|||
/// </para>
|
||||
/// </remarks>
|
||||
[ServiceManager.EarlyLoadedService]
|
||||
internal sealed unsafe class ImGuiClipboardFunctionProvider : IServiceType, IDisposable
|
||||
internal sealed unsafe class ImGuiClipboardFunctionProvider : IInternalDisposableService
|
||||
{
|
||||
private static readonly ModuleLog Log = new(nameof(ImGuiClipboardFunctionProvider));
|
||||
private readonly nint clipboardUserDataOriginal;
|
||||
|
|
@ -75,7 +75,7 @@ internal sealed unsafe class ImGuiClipboardFunctionProvider : IServiceType, IDis
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
if (!this.clipboardUserData.IsAllocated)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace Dalamud.Interface.Internal;
|
|||
/// Change push_texture_id to only have one condition.
|
||||
/// </summary>
|
||||
[ServiceManager.EarlyLoadedService]
|
||||
internal sealed unsafe class ImGuiDrawListFixProvider : IServiceType, IDisposable
|
||||
internal sealed unsafe class ImGuiDrawListFixProvider : IInternalDisposableService
|
||||
{
|
||||
private const int CImGuiImDrawListAddPolyLineOffset = 0x589B0;
|
||||
private const int CImGuiImDrawListAddRectFilled = 0x59FD0;
|
||||
|
|
@ -69,7 +69,7 @@ internal sealed unsafe class ImGuiDrawListFixProvider : IServiceType, IDisposabl
|
|||
ImDrawFlags flags);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.hookImDrawListAddPolyline.Dispose();
|
||||
this.hookImDrawListAddRectFilled.Dispose();
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Dalamud.Configuration.Internal;
|
||||
|
|
@ -51,7 +52,7 @@ namespace Dalamud.Interface.Internal;
|
|||
/// This class manages interaction with the ImGui interface.
|
||||
/// </summary>
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
internal class InterfaceManager : IDisposable, IServiceType
|
||||
internal class InterfaceManager : IInternalDisposableService
|
||||
{
|
||||
/// <summary>
|
||||
/// The default font size, in points.
|
||||
|
|
@ -69,10 +70,13 @@ internal class InterfaceManager : IDisposable, IServiceType
|
|||
[ServiceManager.ServiceDependency]
|
||||
private readonly WndProcHookManager wndProcHookManager = Service<WndProcHookManager>.Get();
|
||||
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly Framework framework = Service<Framework>.Get();
|
||||
|
||||
private readonly SwapChainVtableResolver address = new();
|
||||
private readonly Hook<SetCursorDelegate> setCursorHook;
|
||||
private RawDX11Scene? scene;
|
||||
|
||||
private Hook<SetCursorDelegate>? setCursorHook;
|
||||
private Hook<PresentDelegate>? presentHook;
|
||||
private Hook<ResizeBuffersDelegate>? resizeBuffersHook;
|
||||
|
||||
|
|
@ -87,8 +91,6 @@ internal class InterfaceManager : IDisposable, IServiceType
|
|||
[ServiceManager.ServiceConstructor]
|
||||
private InterfaceManager()
|
||||
{
|
||||
this.setCursorHook = Hook<SetCursorDelegate>.FromImport(
|
||||
null, "user32.dll", "SetCursor", 0, this.SetCursorDetour);
|
||||
}
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||
|
|
@ -233,25 +235,45 @@ internal class InterfaceManager : IDisposable, IServiceType
|
|||
/// <summary>
|
||||
/// Dispose of managed and unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
if (Service<Framework>.GetNullable() is { } framework)
|
||||
framework.RunOnFrameworkThread(Disposer).Wait();
|
||||
else
|
||||
Disposer();
|
||||
// Unload hooks from the framework thread if possible.
|
||||
// We're currently off the framework thread, as this function can only be called from
|
||||
// ServiceManager.UnloadAllServices, which is called from EntryPoint.RunThread.
|
||||
// The functions being unhooked are mostly called from the main thread, so unhooking from the main thread when
|
||||
// possible would avoid any chance of unhooking a function that currently is being called.
|
||||
// If unloading is initiated from "Unload Dalamud" /xldev menu, then the framework would still be running, as
|
||||
// Framework.Destroy has never been called and thus Framework.IsFrameworkUnloading cannot be true, and this
|
||||
// function will actually run the destroy from the framework thread.
|
||||
// Otherwise, as Framework.IsFrameworkUnloading should have been set, this code should run immediately.
|
||||
this.framework.RunOnFrameworkThread(ClearHooks).Wait();
|
||||
|
||||
// Below this point, hooks are guaranteed to be no longer called.
|
||||
|
||||
// A font resource lock outlives the parent handle and the owner atlas. It should be disposed.
|
||||
Interlocked.Exchange(ref this.defaultFontResourceLock, null)?.Dispose();
|
||||
|
||||
// Font handles become invalid after disposing the atlas, but just to be safe.
|
||||
this.DefaultFontHandle?.Dispose();
|
||||
this.DefaultFontHandle = null;
|
||||
|
||||
this.MonoFontHandle?.Dispose();
|
||||
this.MonoFontHandle = null;
|
||||
|
||||
this.IconFontHandle?.Dispose();
|
||||
this.IconFontHandle = null;
|
||||
|
||||
Interlocked.Exchange(ref this.dalamudAtlas, null)?.Dispose();
|
||||
Interlocked.Exchange(ref this.scene, null)?.Dispose();
|
||||
|
||||
this.wndProcHookManager.PreWndProc -= this.WndProcHookManagerOnPreWndProc;
|
||||
this.defaultFontResourceLock?.Dispose(); // lock outlives handle and atlas
|
||||
this.defaultFontResourceLock = null;
|
||||
this.dalamudAtlas?.Dispose();
|
||||
this.scene?.Dispose();
|
||||
return;
|
||||
|
||||
void Disposer()
|
||||
void ClearHooks()
|
||||
{
|
||||
this.setCursorHook.Dispose();
|
||||
this.presentHook?.Dispose();
|
||||
this.resizeBuffersHook?.Dispose();
|
||||
this.wndProcHookManager.PreWndProc -= this.WndProcHookManagerOnPreWndProc;
|
||||
Interlocked.Exchange(ref this.setCursorHook, null)?.Dispose();
|
||||
Interlocked.Exchange(ref this.presentHook, null)?.Dispose();
|
||||
Interlocked.Exchange(ref this.resizeBuffersHook, null)?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -693,7 +715,6 @@ internal class InterfaceManager : IDisposable, IServiceType
|
|||
"InterfaceManager accepts event registration and stuff even when the game window is not ready.")]
|
||||
private void ContinueConstruction(
|
||||
TargetSigScanner sigScanner,
|
||||
Framework framework,
|
||||
FontAtlasFactory fontAtlasFactory)
|
||||
{
|
||||
this.dalamudAtlas = fontAtlasFactory
|
||||
|
|
@ -731,7 +752,7 @@ internal class InterfaceManager : IDisposable, IServiceType
|
|||
this.DefaultFontHandle.ImFontChanged += (_, font) =>
|
||||
{
|
||||
var fontLocked = font.NewRef();
|
||||
Service<Framework>.Get().RunOnFrameworkThread(
|
||||
this.framework.RunOnFrameworkThread(
|
||||
() =>
|
||||
{
|
||||
// Update the ImGui default font.
|
||||
|
|
@ -765,6 +786,7 @@ internal class InterfaceManager : IDisposable, IServiceType
|
|||
Log.Error(ex, "Could not enable immersive mode");
|
||||
}
|
||||
|
||||
this.setCursorHook = Hook<SetCursorDelegate>.FromImport(null, "user32.dll", "SetCursor", 0, this.SetCursorDetour);
|
||||
this.presentHook = Hook<PresentDelegate>.FromAddress(this.address.Present, this.PresentDetour);
|
||||
this.resizeBuffersHook = Hook<ResizeBuffersDelegate>.FromAddress(this.address.ResizeBuffers, this.ResizeBuffersDetour);
|
||||
|
||||
|
|
@ -808,7 +830,7 @@ internal class InterfaceManager : IDisposable, IServiceType
|
|||
if (this.lastWantCapture && (!this.scene?.IsImGuiCursor(hCursor) ?? false) && this.OverrideGameCursor)
|
||||
return IntPtr.Zero;
|
||||
|
||||
return this.setCursorHook.IsDisposed
|
||||
return this.setCursorHook?.IsDisposed is not false
|
||||
? User32.SetCursor(new(hCursor, false)).DangerousGetHandle()
|
||||
: this.setCursorHook.Original(hCursor);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ namespace Dalamud.Interface.Internal;
|
|||
[ResolveVia<ITextureProvider>]
|
||||
[ResolveVia<ITextureSubstitutionProvider>]
|
||||
#pragma warning restore SA1015
|
||||
internal class TextureManager : IDisposable, IServiceType, ITextureProvider, ITextureSubstitutionProvider
|
||||
internal class TextureManager : IInternalDisposableService, ITextureProvider, ITextureSubstitutionProvider
|
||||
{
|
||||
private const string IconFileFormat = "ui/icon/{0:D3}000/{1}{2:D6}.tex";
|
||||
private const string HighResolutionIconFileFormat = "ui/icon/{0:D3}000/{1}{2:D6}_hr1.tex";
|
||||
|
|
@ -268,7 +268,7 @@ internal class TextureManager : IDisposable, IServiceType, ITextureProvider, ITe
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.fallbackTextureWrap?.Dispose();
|
||||
this.framework.Update -= this.FrameworkOnUpdate;
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ internal class GameInventoryTestWidget : IDataWindowWidget
|
|||
this.standardEnabled = false;
|
||||
if (!this.rawEnabled)
|
||||
{
|
||||
this.scoped.Dispose();
|
||||
((IInternalDisposableService)this.scoped).DisposeService();
|
||||
this.scoped = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -105,7 +105,7 @@ internal class GameInventoryTestWidget : IDataWindowWidget
|
|||
this.rawEnabled = false;
|
||||
if (!this.standardEnabled)
|
||||
{
|
||||
this.scoped.Dispose();
|
||||
((IInternalDisposableService)this.scoped).DisposeService();
|
||||
this.scoped = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -135,7 +135,7 @@ internal class GameInventoryTestWidget : IDataWindowWidget
|
|||
{
|
||||
if (ImGui.Button("Disable##all-disable"))
|
||||
{
|
||||
this.scoped?.Dispose();
|
||||
((IInternalDisposableService)this.scoped)?.DisposeService();
|
||||
this.scoped = null;
|
||||
this.standardEnabled = this.rawEnabled = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ namespace Dalamud.Interface.Internal.Windows;
|
|||
/// A cache for plugin icons and images.
|
||||
/// </summary>
|
||||
[ServiceManager.EarlyLoadedService]
|
||||
internal class PluginImageCache : IDisposable, IServiceType
|
||||
internal class PluginImageCache : IInternalDisposableService
|
||||
{
|
||||
/// <summary>
|
||||
/// Maximum plugin image width.
|
||||
|
|
@ -136,7 +136,7 @@ internal class PluginImageCache : IDisposable, IServiceType
|
|||
this.dalamudAssetManager.GetDalamudTextureWrap(DalamudAsset.LogoSmall, this.EmptyTexture);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.cancelToken.Cancel();
|
||||
this.downloadQueue.CompleteAdding();
|
||||
|
|
|
|||
|
|
@ -204,12 +204,12 @@ internal sealed partial class FontAtlasFactory
|
|||
{
|
||||
while (this.IsBuildInProgress)
|
||||
await Task.Delay(100);
|
||||
this.Garbage.Dispose();
|
||||
this.Clear();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Garbage.Dispose();
|
||||
this.Clear();
|
||||
}
|
||||
|
||||
return newRefCount;
|
||||
|
|
@ -227,6 +227,20 @@ internal sealed partial class FontAtlasFactory
|
|||
var axisSubstance = this.Substances.OfType<GamePrebakedFontHandle.HandleSubstance>().Single();
|
||||
return new(factory, this, axisSubstance, isAsync) { BuildStep = FontAtlasBuildStep.PreBuild };
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.Garbage.Dispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(
|
||||
e,
|
||||
$"Disposing {nameof(FontAtlasBuiltData)} of {this.Owner?.Name ?? "???"}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class DalamudFontAtlas : IFontAtlas, DisposeSafety.IDisposeCallback
|
||||
|
|
@ -547,13 +561,13 @@ internal sealed partial class FontAtlasFactory
|
|||
{
|
||||
if (this.buildIndex != rebuildIndex)
|
||||
{
|
||||
data.ExplicitDisposeIgnoreExceptions();
|
||||
data.Release();
|
||||
return;
|
||||
}
|
||||
|
||||
var prevBuiltData = this.builtData;
|
||||
this.builtData = data;
|
||||
prevBuiltData.ExplicitDisposeIgnoreExceptions();
|
||||
prevBuiltData?.Release();
|
||||
|
||||
this.buildTask = EmptyTask;
|
||||
fontsAndLocks.EnsureCapacity(data.Substances.Sum(x => x.RelevantHandles.Count));
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ namespace Dalamud.Interface.ManagedFontAtlas.Internals;
|
|||
/// </summary>
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
internal sealed partial class FontAtlasFactory
|
||||
: IServiceType, GamePrebakedFontHandle.IGameFontTextureProvider, IDisposable
|
||||
: IInternalDisposableService, GamePrebakedFontHandle.IGameFontTextureProvider
|
||||
{
|
||||
private readonly DisposeSafety.ScopedFinalizer scopedFinalizer = new();
|
||||
private readonly CancellationTokenSource cancellationTokenSource = new();
|
||||
|
|
@ -161,7 +161,7 @@ internal sealed partial class FontAtlasFactory
|
|||
this.dalamudAssetManager.IsStreamImmediatelyAvailable(DalamudAsset.LodestoneGameSymbol);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.cancellationTokenSource.Cancel();
|
||||
this.scopedFinalizer.Dispose();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Dalamud.Interface.Internal;
|
||||
|
|
@ -291,11 +292,15 @@ internal abstract class FontHandle : IFontHandle
|
|||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (Interlocked.Exchange(ref this.manager, null) is not { } managerToDisassociate)
|
||||
return;
|
||||
|
||||
if (this.pushedFonts.Count > 0)
|
||||
Log.Warning($"{nameof(IFontHandle)}.{nameof(IDisposable.Dispose)}: fonts were still in a stack.");
|
||||
this.Manager.FreeFontHandle(this);
|
||||
this.manager = null;
|
||||
|
||||
managerToDisassociate.FreeFontHandle(this);
|
||||
this.Disposed?.InvokeSafely();
|
||||
this.Disposed = null;
|
||||
this.ImFontChanged = null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ internal class TitleScreenMenu : IServiceType, ITitleScreenMenu
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<ITitleScreenMenu>]
|
||||
#pragma warning restore SA1015
|
||||
internal class TitleScreenMenuPluginScoped : IDisposable, IServiceType, ITitleScreenMenu
|
||||
internal class TitleScreenMenuPluginScoped : IInternalDisposableService, ITitleScreenMenu
|
||||
{
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly TitleScreenMenu titleScreenMenuService = Service<TitleScreenMenu>.Get();
|
||||
|
|
@ -204,7 +204,7 @@ internal class TitleScreenMenuPluginScoped : IDisposable, IServiceType, ITitleSc
|
|||
public IReadOnlyList<TitleScreenMenuEntry>? Entries => this.titleScreenMenuService.Entries;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
foreach (var entry in this.pluginEntries)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ using Dalamud.Interface.Internal.ManagedAsserts;
|
|||
using Dalamud.Interface.Internal.Notifications;
|
||||
using Dalamud.Interface.ManagedFontAtlas;
|
||||
using Dalamud.Interface.ManagedFontAtlas.Internals;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Internal.Types;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility;
|
||||
|
|
@ -605,6 +606,10 @@ public sealed class UiBuilder : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>Clean up resources allocated by this instance of <see cref="UiBuilder"/>.</summary>
|
||||
/// <remarks>Dalamud internal use only.</remarks>
|
||||
internal void DisposeInternal() => this.scopedFinalizer.Dispose();
|
||||
|
||||
/// <summary>
|
||||
/// Open the registered configuration UI, if it exists.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -96,6 +96,17 @@ internal class ServiceScopeImpl : IServiceScope
|
|||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var createdObject in this.scopeCreatedObjects.OfType<IDisposable>()) createdObject.Dispose();
|
||||
foreach (var createdObject in this.scopeCreatedObjects)
|
||||
{
|
||||
switch (createdObject)
|
||||
{
|
||||
case IInternalDisposableService d:
|
||||
d.DisposeService();
|
||||
break;
|
||||
case IDisposable d:
|
||||
d.Dispose();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ namespace Dalamud.Logging.Internal;
|
|||
/// Class responsible for tracking asynchronous tasks.
|
||||
/// </summary>
|
||||
[ServiceManager.EarlyLoadedService]
|
||||
internal class TaskTracker : IDisposable, IServiceType
|
||||
internal class TaskTracker : IInternalDisposableService
|
||||
{
|
||||
private static readonly ModuleLog Log = new("TT");
|
||||
private static readonly List<TaskInfo> TrackedTasksInternal = new();
|
||||
|
|
@ -119,7 +119,7 @@ internal class TaskTracker : IDisposable, IServiceType
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.scheduleAndStartHook?.Dispose();
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Dalamud.Logging;
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IPluginLog>]
|
||||
#pragma warning restore SA1015
|
||||
internal class ScopedPluginLogService : IServiceType, IPluginLog, IDisposable
|
||||
internal class ScopedPluginLogService : IServiceType, IPluginLog
|
||||
{
|
||||
private readonly LocalPlugin localPlugin;
|
||||
|
||||
|
|
@ -53,12 +53,6 @@ internal class ScopedPluginLogService : IServiceType, IPluginLog, IDisposable
|
|||
/// </summary>
|
||||
public ILogger Logger { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Fatal(string messageTemplate, params object[] values) =>
|
||||
this.Write(LogEventLevel.Fatal, null, messageTemplate, values);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ namespace Dalamud.Networking.Http;
|
|||
/// awareness.
|
||||
/// </summary>
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
internal class HappyHttpClient : IDisposable, IServiceType
|
||||
internal class HappyHttpClient : IInternalDisposableService
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HappyHttpClient"/> class.
|
||||
|
|
@ -58,7 +58,7 @@ internal class HappyHttpClient : IDisposable, IServiceType
|
|||
public HappyEyeballsCallback SharedHappyEyeballsCallback { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
void IDisposable.Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.SharedHttpClient.Dispose();
|
||||
this.SharedHappyEyeballsCallback.Dispose();
|
||||
|
|
|
|||
|
|
@ -452,26 +452,28 @@ public sealed class DalamudPluginInterface : IDisposable
|
|||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Unregister your plugin and dispose all references.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Dispose"/>
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
this.UiBuilder.ExplicitDispose();
|
||||
Service<ChatGui>.Get().RemoveChatLinkHandler(this.plugin.InternalName);
|
||||
Service<Localization>.Get().LocalizationChanged -= this.OnLocalizationChanged;
|
||||
Service<DalamudConfiguration>.Get().DalamudConfigurationSaved -= this.OnDalamudConfigurationSaved;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obsolete implicit dispose implementation. Should not be used.
|
||||
/// </summary>
|
||||
[Obsolete("Do not dispose \"DalamudPluginInterface\".", true)]
|
||||
/// <summary>This function will do nothing. Dalamud will dispose this object on plugin unload.</summary>
|
||||
[Obsolete("This function will do nothing. Dalamud will dispose this object on plugin unload.", true)]
|
||||
public void Dispose()
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
/// <summary>Unregister the plugin and dispose all references.</summary>
|
||||
/// <remarks>Dalamud internal use only.</remarks>
|
||||
internal void DisposeInternal()
|
||||
{
|
||||
Service<ChatGui>.Get().RemoveChatLinkHandler(this.plugin.InternalName);
|
||||
Service<Localization>.Get().LocalizationChanged -= this.OnLocalizationChanged;
|
||||
Service<DalamudConfiguration>.Get().DalamudConfigurationSaved -= this.OnDalamudConfigurationSaved;
|
||||
this.UiBuilder.DisposeInternal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispatch the active plugins changed event.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ namespace Dalamud.Plugin.Internal;
|
|||
[InherentDependency<DataShare>]
|
||||
|
||||
#pragma warning restore SA1015
|
||||
internal partial class PluginManager : IDisposable, IServiceType
|
||||
internal partial class PluginManager : IInternalDisposableService
|
||||
{
|
||||
/// <summary>
|
||||
/// Default time to wait between plugin unload and plugin assembly unload.
|
||||
|
|
@ -370,7 +370,7 @@ internal partial class PluginManager : IDisposable, IServiceType
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
var disposablePlugins =
|
||||
this.installedPluginsList.Where(plugin => plugin.State is PluginState.Loaded or PluginState.LoadError).ToArray();
|
||||
|
|
@ -410,7 +410,16 @@ internal partial class PluginManager : IDisposable, IServiceType
|
|||
// Now that we've waited enough, dispose the whole plugin.
|
||||
// Since plugins should have been unloaded above, this should be done quickly.
|
||||
foreach (var plugin in disposablePlugins)
|
||||
plugin.ExplicitDisposeIgnoreExceptions($"Error disposing {plugin.Name}", Log);
|
||||
{
|
||||
try
|
||||
{
|
||||
plugin.Dispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e, $"Error disposing {plugin.Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.assemblyLocationMonoHook?.Dispose();
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace Dalamud.Plugin.Internal.Profiles;
|
|||
/// Service responsible for profile-related chat commands.
|
||||
/// </summary>
|
||||
[ServiceManager.EarlyLoadedService]
|
||||
internal class ProfileCommandHandler : IServiceType, IDisposable
|
||||
internal class ProfileCommandHandler : IInternalDisposableService
|
||||
{
|
||||
private readonly CommandManager cmd;
|
||||
private readonly ProfileManager profileManager;
|
||||
|
|
@ -69,7 +69,7 @@ internal class ProfileCommandHandler : IServiceType, IDisposable
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
this.cmd.RemoveHandler("/xlenablecollection");
|
||||
this.cmd.RemoveHandler("/xldisablecollection");
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ internal class LocalPlugin : IDisposable
|
|||
this.instance = null;
|
||||
}
|
||||
|
||||
this.DalamudInterface?.ExplicitDispose();
|
||||
this.DalamudInterface?.DisposeInternal();
|
||||
this.DalamudInterface = null;
|
||||
|
||||
this.ServiceScope?.Dispose();
|
||||
|
|
@ -426,7 +426,7 @@ internal class LocalPlugin : IDisposable
|
|||
if (this.instance == null)
|
||||
{
|
||||
this.State = PluginState.LoadError;
|
||||
this.DalamudInterface.ExplicitDispose();
|
||||
this.DalamudInterface.DisposeInternal();
|
||||
Log.Error(
|
||||
$"Error while loading {this.Name}, failed to bind and call the plugin constructor");
|
||||
return;
|
||||
|
|
@ -499,7 +499,7 @@ internal class LocalPlugin : IDisposable
|
|||
|
||||
this.instance = null;
|
||||
|
||||
this.DalamudInterface?.ExplicitDispose();
|
||||
this.DalamudInterface?.DisposeInternal();
|
||||
this.DalamudInterface = null;
|
||||
|
||||
this.ServiceScope?.Dispose();
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using System.Diagnostics;
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
|
@ -175,7 +176,8 @@ internal static class ServiceManager
|
|||
foreach (var serviceType in GetConcreteServiceTypes())
|
||||
{
|
||||
var serviceKind = serviceType.GetServiceKind();
|
||||
Debug.Assert(serviceKind != ServiceKind.None, $"Service<{serviceType.FullName}> did not specify a kind");
|
||||
|
||||
CheckServiceTypeContracts(serviceType);
|
||||
|
||||
// Let IoC know about the interfaces this service implements
|
||||
serviceContainer.RegisterInterfaces(serviceType);
|
||||
|
|
@ -514,6 +516,44 @@ internal static class ServiceManager
|
|||
return ServiceKind.ProvidedService;
|
||||
}
|
||||
|
||||
/// <summary>Validate service type contracts, and throws exceptions accordingly.</summary>
|
||||
/// <param name="serviceType">An instance of <see cref="Type"/> that is supposed to be a service type.</param>
|
||||
/// <remarks>Does nothing on non-debug builds.</remarks>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void CheckServiceTypeContracts(Type serviceType)
|
||||
{
|
||||
#if DEBUG
|
||||
try
|
||||
{
|
||||
if (!serviceType.IsAssignableTo(typeof(IServiceType)))
|
||||
throw new InvalidOperationException($"Non-{nameof(IServiceType)} passed.");
|
||||
if (serviceType.GetServiceKind() == ServiceKind.None)
|
||||
throw new InvalidOperationException("Service type is not specified.");
|
||||
|
||||
var isServiceDisposable =
|
||||
serviceType.IsAssignableTo(typeof(IInternalDisposableService));
|
||||
var isAnyDisposable =
|
||||
isServiceDisposable
|
||||
|| serviceType.IsAssignableTo(typeof(IDisposable))
|
||||
|| serviceType.IsAssignableTo(typeof(IAsyncDisposable));
|
||||
if (isAnyDisposable && !isServiceDisposable)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"A service must be an {nameof(IInternalDisposableService)} without specifying " +
|
||||
$"{nameof(IDisposable)} nor {nameof(IAsyncDisposable)} if it is purely meant to be a service, " +
|
||||
$"or an {nameof(IPublicDisposableService)} if it also is allowed to be constructed not as a " +
|
||||
$"service to be used elsewhere and has to offer {nameof(IDisposable)} or " +
|
||||
$"{nameof(IAsyncDisposable)}. See {nameof(ReliableFileStorage)} for an example of " +
|
||||
$"{nameof(IPublicDisposableService)}.");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InvalidOperationException($"{serviceType.Name}: {e.Message}");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that this constructor will be called for early initialization.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -65,6 +65,12 @@ internal static class Service<T> where T : IServiceType
|
|||
None,
|
||||
}
|
||||
|
||||
/// <summary>Does nothing.</summary>
|
||||
/// <remarks>Used to invoke the static ctor.</remarks>
|
||||
public static void Nop()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the type in the service locator to the given object.
|
||||
/// </summary>
|
||||
|
|
@ -72,6 +78,8 @@ internal static class Service<T> where T : IServiceType
|
|||
public static void Provide(T obj)
|
||||
{
|
||||
ServiceManager.Log.Debug("Service<{0}>: Provided", typeof(T).Name);
|
||||
if (obj is IPublicDisposableService pds)
|
||||
pds.MarkDisposeOnlyFromService();
|
||||
instanceTcs.SetResult(obj);
|
||||
}
|
||||
|
||||
|
|
@ -297,23 +305,26 @@ internal static class Service<T> where T : IServiceType
|
|||
if (!instanceTcs.Task.IsCompletedSuccessfully)
|
||||
return;
|
||||
|
||||
var instance = instanceTcs.Task.Result;
|
||||
if (instance is IDisposable disposable)
|
||||
switch (instanceTcs.Task.Result)
|
||||
{
|
||||
ServiceManager.Log.Debug("Service<{0}>: Disposing", typeof(T).Name);
|
||||
try
|
||||
{
|
||||
disposable.Dispose();
|
||||
ServiceManager.Log.Debug("Service<{0}>: Disposed", typeof(T).Name);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ServiceManager.Log.Warning(e, "Service<{0}>: Dispose failure", typeof(T).Name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ServiceManager.Log.Debug("Service<{0}>: Unset", typeof(T).Name);
|
||||
case IInternalDisposableService d:
|
||||
ServiceManager.Log.Debug("Service<{0}>: Disposing", typeof(T).Name);
|
||||
try
|
||||
{
|
||||
d.DisposeService();
|
||||
ServiceManager.Log.Debug("Service<{0}>: Disposed", typeof(T).Name);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ServiceManager.Log.Warning(e, "Service<{0}>: Dispose failure", typeof(T).Name);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
ServiceManager.CheckServiceTypeContracts(typeof(T));
|
||||
ServiceManager.Log.Debug("Service<{0}>: Unset", typeof(T).Name);
|
||||
break;
|
||||
}
|
||||
|
||||
instanceTcs = new TaskCompletionSource<T>();
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ namespace Dalamud.Storage.Assets;
|
|||
#pragma warning disable SA1015
|
||||
[ResolveVia<IDalamudAssetManager>]
|
||||
#pragma warning restore SA1015
|
||||
internal sealed class DalamudAssetManager : IServiceType, IDisposable, IDalamudAssetManager
|
||||
internal sealed class DalamudAssetManager : IInternalDisposableService, IDalamudAssetManager
|
||||
{
|
||||
private const int DownloadAttemptCount = 10;
|
||||
private const int RenameAttemptCount = 10;
|
||||
|
|
@ -67,7 +67,13 @@ internal sealed class DalamudAssetManager : IServiceType, IDisposable, IDalamudA
|
|||
.Where(x => x.GetAttribute<DalamudAssetAttribute>()?.Required is true)
|
||||
.Select(this.CreateStreamAsync)
|
||||
.Select(x => x.ToContentDisposedTask()))
|
||||
.ContinueWith(_ => loadTimings.Dispose()),
|
||||
.ContinueWith(
|
||||
r =>
|
||||
{
|
||||
loadTimings.Dispose();
|
||||
return r;
|
||||
})
|
||||
.Unwrap(),
|
||||
"Prevent Dalamud from loading more stuff, until we've ensured that all required assets are available.");
|
||||
|
||||
Task.WhenAll(
|
||||
|
|
@ -83,7 +89,7 @@ internal sealed class DalamudAssetManager : IServiceType, IDisposable, IDalamudA
|
|||
public IDalamudTextureWrap Empty4X4 => this.GetDalamudTextureWrap(DalamudAsset.Empty4X4);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
lock (this.syncRoot)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -22,17 +22,22 @@ namespace Dalamud.Storage;
|
|||
/// This is not an early-loaded service, as it is needed before they are initialized.
|
||||
/// </remarks>
|
||||
[ServiceManager.ProvidedService]
|
||||
public class ReliableFileStorage : IServiceType, IDisposable
|
||||
[Api10ToDo("Make internal and IInternalDisposableService, and remove #pragma guard from the caller.")]
|
||||
public class ReliableFileStorage : IPublicDisposableService
|
||||
{
|
||||
private static readonly ModuleLog Log = new("VFS");
|
||||
|
||||
private readonly object syncRoot = new();
|
||||
|
||||
private SQLiteConnection? db;
|
||||
private bool isService;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ReliableFileStorage"/> class.
|
||||
/// </summary>
|
||||
/// <param name="vfsDbPath">Path to the VFS.</param>
|
||||
[Obsolete("Dalamud internal use only.", false)]
|
||||
[Api10ToDo("Make internal, and remove #pragma guard from the caller.")]
|
||||
public ReliableFileStorage(string vfsDbPath)
|
||||
{
|
||||
var databasePath = Path.Combine(vfsDbPath, "dalamudVfs.db");
|
||||
|
|
@ -288,9 +293,20 @@ public class ReliableFileStorage : IServiceType, IDisposable
|
|||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
this.db?.Dispose();
|
||||
if (!this.isService)
|
||||
this.DisposeCore();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
void IInternalDisposableService.DisposeService()
|
||||
{
|
||||
if (this.isService)
|
||||
this.DisposeCore();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
void IPublicDisposableService.MarkDisposeOnlyFromService() => this.isService = true;
|
||||
|
||||
/// <summary>
|
||||
/// Replace possible non-portable parts of a path with portable versions.
|
||||
/// </summary>
|
||||
|
|
@ -312,6 +328,8 @@ public class ReliableFileStorage : IServiceType, IDisposable
|
|||
this.db.CreateTable<DbFile>();
|
||||
}
|
||||
|
||||
private void DisposeCore() => this.db?.Dispose();
|
||||
|
||||
private class DbFile
|
||||
{
|
||||
[PrimaryKey]
|
||||
|
|
|
|||
|
|
@ -70,7 +70,16 @@ public static class DisposeSafety
|
|||
r =>
|
||||
{
|
||||
if (!r.IsCompletedSuccessfully)
|
||||
return ignoreAllExceptions ? Task.CompletedTask : r;
|
||||
{
|
||||
if (ignoreAllExceptions)
|
||||
{
|
||||
_ = r.Exception;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
r.Result.Dispose();
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ using Dalamud.Game.ClientState.Objects.SubKinds;
|
|||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Interface.Colors;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Logging.Internal;
|
||||
using ImGuiNET;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Serilog;
|
||||
|
|
@ -639,42 +638,6 @@ public static class Util
|
|||
throw new Win32Exception();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose this object.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to dispose.</param>
|
||||
/// <typeparam name="T">The type of object to dispose.</typeparam>
|
||||
internal static void ExplicitDispose<T>(this T obj) where T : IDisposable
|
||||
{
|
||||
obj.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose this object.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to dispose.</param>
|
||||
/// <param name="logMessage">Log message to print, if specified and an error occurs.</param>
|
||||
/// <param name="moduleLog">Module logger, if any.</param>
|
||||
/// <typeparam name="T">The type of object to dispose.</typeparam>
|
||||
internal static void ExplicitDisposeIgnoreExceptions<T>(
|
||||
this T obj, string? logMessage = null, ModuleLog? moduleLog = null) where T : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
obj.Dispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (logMessage == null)
|
||||
return;
|
||||
|
||||
if (moduleLog != null)
|
||||
moduleLog.Error(e, logMessage);
|
||||
else
|
||||
Log.Error(e, logMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a random, inoffensive, human-friendly string.
|
||||
/// </summary>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue