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;
}