From 0f35dd69f9e018ffe363dd2d6d4b4c06621de3d2 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Mon, 5 Sep 2022 14:01:12 +0200 Subject: [PATCH] Add IPC test, optimize tester a little, only call event when game object available. --- Penumbra/Api/IPenumbraApi.cs | 4 +- Penumbra/Api/IpcTester.cs | 88 +++++++++++++++++++++------- Penumbra/Api/PenumbraApi.cs | 7 ++- Penumbra/Api/PenumbraIpc.cs | 23 ++++---- Penumbra/UI/ConfigWindow.DebugTab.cs | 1 + 5 files changed, 87 insertions(+), 36 deletions(-) diff --git a/Penumbra/Api/IPenumbraApi.cs b/Penumbra/Api/IPenumbraApi.cs index 57e13baa..05b56c80 100644 --- a/Penumbra/Api/IPenumbraApi.cs +++ b/Penumbra/Api/IPenumbraApi.cs @@ -80,7 +80,9 @@ public interface IPenumbraApi : IPenumbraApiBase // so you can apply flag changes after finishing. public event CreatedCharacterBaseDelegate? CreatedCharacterBase; - public event GameObjectResourceResolvedDelegate GameObjectResourceResolved; + // Triggered whenever a resource is redirected by Penumbra for a specific, identified game object. + // Does not trigger if the resource is not requested for a known game object. + public event GameObjectResourceResolvedDelegate? GameObjectResourceResolved; // Queue redrawing of all actors of the given name with the given RedrawType. public void RedrawObject( string name, RedrawType setting ); diff --git a/Penumbra/Api/IpcTester.cs b/Penumbra/Api/IpcTester.cs index c251eb35..f5140db4 100644 --- a/Penumbra/Api/IpcTester.cs +++ b/Penumbra/Api/IpcTester.cs @@ -33,9 +33,12 @@ public class IpcTester : IDisposable private readonly ICallGateSubscriber< ModSettingChange, string, string, bool, object? > _settingChanged; private readonly ICallGateSubscriber< IntPtr, string, IntPtr, IntPtr, IntPtr, object? > _characterBaseCreating; private readonly ICallGateSubscriber< IntPtr, string, IntPtr, object? > _characterBaseCreated; + private readonly ICallGateSubscriber< IntPtr, string, string, object? > _gameObjectResourcePathResolved; private readonly List< DateTimeOffset > _initializedList = new(); private readonly List< DateTimeOffset > _disposedList = new(); + private bool _subscribed = false; + public IpcTester( DalamudPluginInterface pi, PenumbraIpc ipc ) { @@ -51,31 +54,51 @@ public class IpcTester : IDisposable _characterBaseCreating = _pi.GetIpcSubscriber< IntPtr, string, IntPtr, IntPtr, IntPtr, object? >( PenumbraIpc.LabelProviderCreatingCharacterBase ); _characterBaseCreated = _pi.GetIpcSubscriber< IntPtr, string, IntPtr, object? >( PenumbraIpc.LabelProviderCreatedCharacterBase ); - _initialized.Subscribe( AddInitialized ); - _disposed.Subscribe( AddDisposed ); - _redrawn.Subscribe( SetLastRedrawn ); - _preSettingsDraw.Subscribe( UpdateLastDrawnMod ); - _postSettingsDraw.Subscribe( UpdateLastDrawnMod ); - _settingChanged.Subscribe( UpdateLastModSetting ); - _characterBaseCreating.Subscribe( UpdateLastCreated ); - _characterBaseCreated.Subscribe( UpdateLastCreated2 ); - _modDirectoryChanged.Subscribe( UpdateModDirectoryChanged ); + _gameObjectResourcePathResolved = + _pi.GetIpcSubscriber< IntPtr, string, string, object? >( PenumbraIpc.LabelProviderGameObjectResourcePathResolved ); + } + + private void SubscribeEvents() + { + if( !_subscribed ) + { + + _initialized.Subscribe( AddInitialized ); + _disposed.Subscribe( AddDisposed ); + _redrawn.Subscribe( SetLastRedrawn ); + _preSettingsDraw.Subscribe( UpdateLastDrawnMod ); + _postSettingsDraw.Subscribe( UpdateLastDrawnMod ); + _settingChanged.Subscribe( UpdateLastModSetting ); + _characterBaseCreating.Subscribe( UpdateLastCreated ); + _characterBaseCreated.Subscribe( UpdateLastCreated2 ); + _modDirectoryChanged.Subscribe( UpdateModDirectoryChanged ); + _gameObjectResourcePathResolved.Subscribe( UpdateGameObjectResourcePath ); + _subscribed = true; + } + } + + public void UnsubscribeEvents() + { + if( _subscribed ) + { + _initialized.Unsubscribe( AddInitialized ); + _disposed.Unsubscribe( AddDisposed ); + _redrawn.Subscribe( SetLastRedrawn ); + _tooltip?.Unsubscribe( AddedTooltip ); + _click?.Unsubscribe( AddedClick ); + _preSettingsDraw.Unsubscribe( UpdateLastDrawnMod ); + _postSettingsDraw.Unsubscribe( UpdateLastDrawnMod ); + _settingChanged.Unsubscribe( UpdateLastModSetting ); + _characterBaseCreating.Unsubscribe( UpdateLastCreated ); + _characterBaseCreated.Unsubscribe( UpdateLastCreated2 ); + _modDirectoryChanged.Unsubscribe( UpdateModDirectoryChanged ); + _gameObjectResourcePathResolved.Unsubscribe( UpdateGameObjectResourcePath ); + _subscribed = false; + } } public void Dispose() - { - _initialized.Unsubscribe( AddInitialized ); - _disposed.Unsubscribe( AddDisposed ); - _redrawn.Subscribe( SetLastRedrawn ); - _tooltip?.Unsubscribe( AddedTooltip ); - _click?.Unsubscribe( AddedClick ); - _preSettingsDraw.Unsubscribe( UpdateLastDrawnMod ); - _postSettingsDraw.Unsubscribe( UpdateLastDrawnMod ); - _settingChanged.Unsubscribe( UpdateLastModSetting ); - _characterBaseCreating.Unsubscribe( UpdateLastCreated ); - _characterBaseCreated.Unsubscribe( UpdateLastCreated2 ); - _modDirectoryChanged.Unsubscribe( UpdateModDirectoryChanged ); - } + => UnsubscribeEvents(); private void AddInitialized() => _initializedList.Add( DateTimeOffset.UtcNow ); @@ -87,6 +110,7 @@ public class IpcTester : IDisposable { try { + SubscribeEvents(); DrawAvailable(); DrawGeneral(); DrawResolve(); @@ -224,6 +248,10 @@ public class IpcTester : IDisposable private string _lastCreatedGameObjectName = string.Empty; private IntPtr _lastCreatedDrawObject = IntPtr.Zero; private DateTimeOffset _lastCreatedGameObjectTime = DateTimeOffset.MaxValue; + private string _lastResolvedGamePath = string.Empty; + private string _lastResolvedFullPath = string.Empty; + private string _lastResolvedObject = string.Empty; + private DateTimeOffset _lastResolvedGamePathTime = DateTimeOffset.MaxValue; private unsafe void UpdateLastCreated( IntPtr gameObject, string _, IntPtr _2, IntPtr _3, IntPtr _4 ) { @@ -241,6 +269,15 @@ public class IpcTester : IDisposable _lastCreatedDrawObject = drawObject; } + private unsafe void UpdateGameObjectResourcePath( IntPtr gameObject, string gamePath, string fullPath ) + { + var obj = ( FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* )gameObject; + _lastResolvedObject = obj != null ? new Utf8String( obj->GetName() ).ToString() : "Unknown"; + _lastResolvedGamePath = gamePath; + _lastResolvedFullPath = fullPath; + _lastResolvedGamePathTime = DateTimeOffset.Now; + } + private void DrawResolve() { using var _ = ImRaii.TreeNode( "Resolve IPC" ); @@ -336,6 +373,13 @@ public class IpcTester : IDisposable ? $"0x{_lastCreatedDrawObject:X} for <{_lastCreatedGameObjectName}> at {_lastCreatedGameObjectTime}" : $"NULL for <{_lastCreatedGameObjectName}> at {_lastCreatedGameObjectTime}" ); } + + DrawIntro( PenumbraIpc.LabelProviderGameObjectResourcePathResolved, "Last GamePath resolved" ); + if( _lastResolvedGamePathTime < DateTimeOffset.Now ) + { + ImGui.TextUnformatted( + $"{_lastResolvedGamePath} -> {_lastResolvedFullPath} for <{_lastResolvedObject}> at {_lastResolvedGamePathTime}" ); + } } private string _redrawName = string.Empty; diff --git a/Penumbra/Api/PenumbraApi.cs b/Penumbra/Api/PenumbraApi.cs index f6292d82..982d5c22 100644 --- a/Penumbra/Api/PenumbraApi.cs +++ b/Penumbra/Api/PenumbraApi.cs @@ -96,8 +96,11 @@ public class PenumbraApi : IDisposable, IPenumbraApi private unsafe void OnResourceLoaded( ResourceHandle* _, Utf8GamePath originalPath, FullPath? manipulatedPath, ResolveData resolveData ) { - GameObjectResourceResolved?.Invoke( resolveData.AssociatedGameObject, originalPath.ToString(), - manipulatedPath?.ToString() ?? originalPath.ToString() ); + if( resolveData.AssociatedGameObject != IntPtr.Zero ) + { + GameObjectResourceResolved?.Invoke( resolveData.AssociatedGameObject, originalPath.ToString(), + manipulatedPath?.ToString() ?? originalPath.ToString() ); + } } public event Action< string, bool >? ModDirectoryChanged diff --git a/Penumbra/Api/PenumbraIpc.cs b/Penumbra/Api/PenumbraIpc.cs index a38aecce..f7c6fd36 100644 --- a/Penumbra/Api/PenumbraIpc.cs +++ b/Penumbra/Api/PenumbraIpc.cs @@ -274,15 +274,15 @@ public partial class PenumbraIpc public partial class PenumbraIpc { - public const string LabelProviderResolveDefault = "Penumbra.ResolveDefaultPath"; - public const string LabelProviderResolveCharacter = "Penumbra.ResolveCharacterPath"; - public const string LabelProviderResolvePlayer = "Penumbra.ResolvePlayerPath"; - public const string LabelProviderGetDrawObjectInfo = "Penumbra.GetDrawObjectInfo"; - public const string LabelProviderGetCutsceneParentIndex = "Penumbra.GetCutsceneParentIndex"; - public const string LabelProviderReverseResolvePath = "Penumbra.ReverseResolvePath"; - public const string LabelProviderReverseResolvePlayerPath = "Penumbra.ReverseResolvePlayerPath"; - public const string LabelProviderCreatingCharacterBase = "Penumbra.CreatingCharacterBase"; - public const string LabelProviderCreatedCharacterBase = "Penumbra.CreatedCharacterBase"; + public const string LabelProviderResolveDefault = "Penumbra.ResolveDefaultPath"; + public const string LabelProviderResolveCharacter = "Penumbra.ResolveCharacterPath"; + public const string LabelProviderResolvePlayer = "Penumbra.ResolvePlayerPath"; + public const string LabelProviderGetDrawObjectInfo = "Penumbra.GetDrawObjectInfo"; + public const string LabelProviderGetCutsceneParentIndex = "Penumbra.GetCutsceneParentIndex"; + public const string LabelProviderReverseResolvePath = "Penumbra.ReverseResolvePath"; + public const string LabelProviderReverseResolvePlayerPath = "Penumbra.ReverseResolvePlayerPath"; + public const string LabelProviderCreatingCharacterBase = "Penumbra.CreatingCharacterBase"; + public const string LabelProviderCreatedCharacterBase = "Penumbra.CreatedCharacterBase"; public const string LabelProviderGameObjectResourcePathResolved = "Penumbra.GameObjectResourcePathResolved"; internal ICallGateProvider< string, string >? ProviderResolveDefault; @@ -294,7 +294,7 @@ public partial class PenumbraIpc internal ICallGateProvider< string, string[] >? ProviderReverseResolvePathPlayer; internal ICallGateProvider< IntPtr, string, IntPtr, IntPtr, IntPtr, object? >? ProviderCreatingCharacterBase; internal ICallGateProvider< IntPtr, string, IntPtr, object? >? ProviderCreatedCharacterBase; - internal ICallGateProvider? ProviderGameObjectResourcePathResolved; + internal ICallGateProvider< IntPtr, string, string, object? >? ProviderGameObjectResourcePathResolved; private void InitializeResolveProviders( DalamudPluginInterface pi ) { @@ -392,7 +392,8 @@ public partial class PenumbraIpc try { - ProviderGameObjectResourcePathResolved = pi.GetIpcProvider( LabelProviderGameObjectResourcePathResolved ); + ProviderGameObjectResourcePathResolved = + pi.GetIpcProvider< IntPtr, string, string, object? >( LabelProviderGameObjectResourcePathResolved ); Api.GameObjectResourceResolved += GameObjectResourceResolvdedEvent; } catch( Exception e ) diff --git a/Penumbra/UI/ConfigWindow.DebugTab.cs b/Penumbra/UI/ConfigWindow.DebugTab.cs index 59ea02d2..68169211 100644 --- a/Penumbra/UI/ConfigWindow.DebugTab.cs +++ b/Penumbra/UI/ConfigWindow.DebugTab.cs @@ -422,6 +422,7 @@ public partial class ConfigWindow { if( !ImGui.CollapsingHeader( "IPC" ) ) { + _window._penumbra.Ipc.Tester.UnsubscribeEvents(); return; }