diff --git a/Penumbra/Interop/Hooks/Resources/ResourceHandleDestructor.cs b/Penumbra/Interop/Hooks/Resources/ResourceHandleDestructor.cs index 5ddb7eaa..ac3f504a 100644 --- a/Penumbra/Interop/Hooks/Resources/ResourceHandleDestructor.cs +++ b/Penumbra/Interop/Hooks/Resources/ResourceHandleDestructor.cs @@ -3,6 +3,7 @@ using OtterGui.Classes; using OtterGui.Services; using Penumbra.GameData; using Penumbra.Interop.Structs; +using Penumbra.UI.ResourceWatcher; namespace Penumbra.Interop.Hooks.Resources; @@ -15,6 +16,9 @@ public sealed unsafe class ResourceHandleDestructor : EventWrapperPtr ShaderReplacementFixer, + + /// + ResourceWatcher, } public ResourceHandleDestructor(HookManager hooks) diff --git a/Penumbra/Interop/ResourceLoading/ResourceService.cs b/Penumbra/Interop/ResourceLoading/ResourceService.cs index 54c86777..0947d2ec 100644 --- a/Penumbra/Interop/ResourceLoading/ResourceService.cs +++ b/Penumbra/Interop/ResourceLoading/ResourceService.cs @@ -26,7 +26,6 @@ public unsafe class ResourceService : IDisposable, IRequiredService interop.InitializeFromAttributes(this); _getResourceSyncHook.Enable(); _getResourceAsyncHook.Enable(); - _resourceHandleDestructorHook.Enable(); _incRefHook = interop.HookFromAddress( (nint)CSResourceHandle.MemberFunctionPointers.IncRef, ResourceHandleIncRefDetour); @@ -51,7 +50,6 @@ public unsafe class ResourceService : IDisposable, IRequiredService { _getResourceSyncHook.Dispose(); _getResourceAsyncHook.Dispose(); - _resourceHandleDestructorHook.Dispose(); _incRefHook.Dispose(); _decRefHook.Dispose(); } @@ -67,8 +65,7 @@ public unsafe class ResourceService : IDisposable, IRequiredService /// Whether to request the resource synchronously or asynchronously. /// The returned resource handle. If this is not null, calling original will be skipped. public delegate void GetResourcePreDelegate(ref ResourceCategory category, ref ResourceType type, ref int hash, ref Utf8GamePath path, - Utf8GamePath original, - GetResourceParameters* parameters, ref bool sync, ref ResourceHandle* returnValue); + Utf8GamePath original, GetResourceParameters* parameters, ref bool sync, ref ResourceHandle* returnValue); /// /// Subscribers should be exception-safe. @@ -192,27 +189,4 @@ public unsafe class ResourceService : IDisposable, IRequiredService } #endregion - - #region Destructor - - /// Invoked before a resource handle is destructed. - /// The resource handle. - public delegate void ResourceHandleDtorDelegate(ResourceHandle* handle); - - /// - /// - /// Subscribers should be exception-safe. - /// - public event ResourceHandleDtorDelegate? ResourceHandleDestructor; - - [Signature(Sigs.ResourceHandleDestructor, DetourName = nameof(ResourceHandleDestructorDetour))] - private readonly Hook _resourceHandleDestructorHook = null!; - - private nint ResourceHandleDestructorDetour(ResourceHandle* handle) - { - ResourceHandleDestructor?.Invoke(handle); - return _resourceHandleDestructorHook.OriginalDisposeSafe(handle); - } - - #endregion } diff --git a/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs b/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs index a7d1a8c6..3bf4cd88 100644 --- a/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs +++ b/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs @@ -8,8 +8,10 @@ using Penumbra.Api.Enums; using Penumbra.Collections; using Penumbra.GameData.Actors; using Penumbra.GameData.Enums; +using Penumbra.Interop.Hooks.Resources; using Penumbra.Interop.ResourceLoading; using Penumbra.Interop.Structs; +using Penumbra.Services; using Penumbra.String; using Penumbra.String.Classes; using Penumbra.UI.Classes; @@ -21,28 +23,30 @@ public sealed class ResourceWatcher : IDisposable, ITab, IUiService public const int DefaultMaxEntries = 1024; public const RecordType AllRecords = RecordType.Request | RecordType.ResourceLoad | RecordType.FileLoad | RecordType.Destruction; - private readonly Configuration _config; - private readonly EphemeralConfig _ephemeral; - private readonly ResourceService _resources; - private readonly ResourceLoader _loader; - private readonly ActorManager _actors; - private readonly List _records = []; - private readonly ConcurrentQueue _newRecords = []; - private readonly ResourceWatcherTable _table; - private string _logFilter = string.Empty; - private Regex? _logRegex; - private int _newMaxEntries; + private readonly Configuration _config; + private readonly EphemeralConfig _ephemeral; + private readonly ResourceService _resources; + private readonly ResourceLoader _loader; + private readonly ResourceHandleDestructor _destructor; + private readonly ActorManager _actors; + private readonly List _records = []; + private readonly ConcurrentQueue _newRecords = []; + private readonly ResourceWatcherTable _table; + private string _logFilter = string.Empty; + private Regex? _logRegex; + private int _newMaxEntries; - public unsafe ResourceWatcher(ActorManager actors, Configuration config, ResourceService resources, ResourceLoader loader) + public unsafe ResourceWatcher(ActorManager actors, Configuration config, ResourceService resources, ResourceLoader loader, ResourceHandleDestructor destructor) { _actors = actors; _config = config; _ephemeral = config.Ephemeral; _resources = resources; + _destructor = destructor; _loader = loader; _table = new ResourceWatcherTable(config.Ephemeral, _records); _resources.ResourceRequested += OnResourceRequested; - _resources.ResourceHandleDestructor += OnResourceDestroyed; + _destructor.Subscribe(OnResourceDestroyed, ResourceHandleDestructor.Priority.ResourceWatcher); _loader.ResourceLoaded += OnResourceLoaded; _loader.FileLoaded += OnFileLoaded; UpdateFilter(_ephemeral.ResourceLoggingFilter, false); @@ -54,7 +58,7 @@ public sealed class ResourceWatcher : IDisposable, ITab, IUiService Clear(); _records.TrimExcess(); _resources.ResourceRequested -= OnResourceRequested; - _resources.ResourceHandleDestructor -= OnResourceDestroyed; + _destructor.Unsubscribe(OnResourceDestroyed); _loader.ResourceLoaded -= OnResourceLoaded; _loader.FileLoaded -= OnFileLoaded; }