From b50ed4b99aa36b947dfbdce71275e4ddeb000a5c Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Fri, 2 Dec 2022 17:16:48 +0100 Subject: [PATCH] Add API events for mod deletion, addition or move. --- Penumbra.Api | 2 +- Penumbra/Api/IpcTester.cs | 80 ++++++++++++++++--- Penumbra/Api/PenumbraApi.cs | 22 +++++ Penumbra/Api/PenumbraIpcProviders.cs | 18 +++++ Penumbra/Mods/Manager/Mod.Manager.BasePath.cs | 4 +- 5 files changed, 113 insertions(+), 13 deletions(-) diff --git a/Penumbra.Api b/Penumbra.Api index 744698d1..1a3f9d50 160000 --- a/Penumbra.Api +++ b/Penumbra.Api @@ -1 +1 @@ -Subproject commit 744698d1295f4e629ab41d77f8872b1ff98fe501 +Subproject commit 1a3f9d501ad44e020500eb7d0a79f91a04e46c93 diff --git a/Penumbra/Api/IpcTester.cs b/Penumbra/Api/IpcTester.cs index ac532c1b..d6daf14c 100644 --- a/Penumbra/Api/IpcTester.cs +++ b/Penumbra/Api/IpcTester.cs @@ -93,6 +93,9 @@ public class IpcTester : IDisposable _gameState.CharacterBaseCreated.Enable(); _configuration.ModDirectoryChanged.Enable(); _gameState.GameObjectResourcePathResolved.Enable(); + _mods.DeleteSubscriber.Enable(); + _mods.AddSubscriber.Enable(); + _mods.MoveSubscriber.Enable(); _subscribed = true; } } @@ -114,6 +117,9 @@ public class IpcTester : IDisposable _gameState.CharacterBaseCreated.Disable(); _configuration.ModDirectoryChanged.Disable(); _gameState.GameObjectResourcePathResolved.Disable(); + _mods.DeleteSubscriber.Disable(); + _mods.AddSubscriber.Disable(); + _mods.MoveSubscriber.Disable(); _subscribed = false; } } @@ -133,6 +139,9 @@ public class IpcTester : IDisposable _gameState.CharacterBaseCreated.Dispose(); _configuration.ModDirectoryChanged.Dispose(); _gameState.GameObjectResourcePathResolved.Dispose(); + _mods.DeleteSubscriber.Dispose(); + _mods.AddSubscriber.Dispose(); + _mods.MoveSubscriber.Dispose(); _subscribed = false; } @@ -536,30 +545,34 @@ public class IpcTester : IDisposable } } - private unsafe void UpdateLastCreated( IntPtr gameObject, string _, IntPtr _2, IntPtr _3, IntPtr _4 ) + private void UpdateLastCreated( IntPtr gameObject, string _, IntPtr _2, IntPtr _3, IntPtr _4 ) { - var obj = ( FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* )gameObject; - _lastCreatedGameObjectName = new ByteString( obj->GetName() ).ToString(); + _lastCreatedGameObjectName = GetObjectName( gameObject ); _lastCreatedGameObjectTime = DateTimeOffset.Now; _lastCreatedDrawObject = IntPtr.Zero; } - private unsafe void UpdateLastCreated2( IntPtr gameObject, string _, IntPtr drawObject ) + private void UpdateLastCreated2( IntPtr gameObject, string _, IntPtr drawObject ) { - var obj = ( FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* )gameObject; - _lastCreatedGameObjectName = new ByteString( obj->GetName() ).ToString(); + _lastCreatedGameObjectName = GetObjectName( gameObject ); _lastCreatedGameObjectTime = DateTimeOffset.Now; _lastCreatedDrawObject = drawObject; } - private unsafe void UpdateGameObjectResourcePath( IntPtr gameObject, string gamePath, string fullPath ) + private void UpdateGameObjectResourcePath( IntPtr gameObject, string gamePath, string fullPath ) { - var obj = ( FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* )gameObject; - _lastResolvedObject = obj != null ? new ByteString( obj->GetName() ).ToString() : "Unknown"; + _lastResolvedObject = GetObjectName( gameObject ); _lastResolvedGamePath = gamePath; _lastResolvedFullPath = fullPath; _lastResolvedGamePathTime = DateTimeOffset.Now; } + + private static unsafe string GetObjectName( IntPtr gameObject ) + { + var obj = ( FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* )gameObject; + var name = obj != null ? obj->GetName() : null; + return name != null ? new ByteString( name ).ToString() : "Unknown"; + } } private class Resolve @@ -799,8 +812,38 @@ public class IpcTester : IDisposable private PenumbraApiEc _lastSetPathEc; private IList< (string, string) > _mods = new List< (string, string) >(); + public readonly EventSubscriber< string > DeleteSubscriber; + public readonly EventSubscriber< string > AddSubscriber; + public readonly EventSubscriber< string, string > MoveSubscriber; + + private DateTimeOffset _lastDeletedModTime = DateTimeOffset.UnixEpoch; + private string _lastDeletedMod = string.Empty; + private DateTimeOffset _lastAddedModTime = DateTimeOffset.UnixEpoch; + private string _lastAddedMod = string.Empty; + private DateTimeOffset _lastMovedModTime = DateTimeOffset.UnixEpoch; + private string _lastMovedModFrom = string.Empty; + private string _lastMovedModTo = string.Empty; + public Mods( DalamudPluginInterface pi ) - => _pi = pi; + { + _pi = pi; + DeleteSubscriber = Ipc.ModDeleted.Subscriber( pi, s => + { + _lastDeletedModTime = DateTimeOffset.UtcNow; + _lastDeletedMod = s; + } ); + AddSubscriber = Ipc.ModAdded.Subscriber( pi, s => + { + _lastAddedModTime = DateTimeOffset.UtcNow; + _lastAddedMod = s; + } ); + MoveSubscriber = Ipc.ModMoved.Subscriber( pi, ( s1, s2 ) => + { + _lastMovedModTime = DateTimeOffset.UtcNow; + _lastMovedModFrom = s1; + _lastMovedModTo = s2; + } ); + } public void Draw() { @@ -866,6 +909,23 @@ public class IpcTester : IDisposable ImGui.SameLine(); ImGui.TextUnformatted( _lastSetPathEc.ToString() ); + DrawIntro( Ipc.ModDeleted.Label, "Last Mod Deleted" ); + if( _lastDeletedModTime > DateTimeOffset.UnixEpoch ) + { + ImGui.TextUnformatted( $"{_lastDeletedMod} at {_lastDeletedModTime}" ); + } + + DrawIntro( Ipc.ModAdded.Label, "Last Mod Added" ); + if( _lastAddedModTime > DateTimeOffset.UnixEpoch ) + { + ImGui.TextUnformatted( $"{_lastAddedMod} at {_lastAddedModTime}" ); + } + + DrawIntro( Ipc.ModMoved.Label, "Last Mod Moved" ); + if( _lastMovedModTime > DateTimeOffset.UnixEpoch ) + { + ImGui.TextUnformatted( $"{_lastMovedModFrom} -> {_lastMovedModTo} at {_lastMovedModTime}" ); + } DrawModsPopup(); } diff --git a/Penumbra/Api/PenumbraApi.cs b/Penumbra/Api/PenumbraApi.cs index 7266c884..aa6bf84a 100644 --- a/Penumbra/Api/PenumbraApi.cs +++ b/Penumbra/Api/PenumbraApi.cs @@ -93,12 +93,14 @@ public class PenumbraApi : IDisposable, IPenumbraApi Penumbra.CollectionManager.CollectionChanged += SubscribeToNewCollections; Penumbra.ResourceLoader.ResourceLoaded += OnResourceLoaded; + Penumbra.ModManager.ModPathChanged += ModPathChangeSubscriber; } public unsafe void Dispose() { Penumbra.ResourceLoader.ResourceLoaded -= OnResourceLoaded; Penumbra.CollectionManager.CollectionChanged -= SubscribeToNewCollections; + Penumbra.ModManager.ModPathChanged -= ModPathChangeSubscriber; _penumbra = null; _lumina = null; foreach( var collection in Penumbra.CollectionManager ) @@ -405,6 +407,26 @@ public class PenumbraApi : IDisposable, IPenumbraApi return PenumbraApiEc.Success; } + public event Action< string >? ModDeleted; + public event Action< string >? ModAdded; + public event Action< string, string >? ModMoved; + + private void ModPathChangeSubscriber( ModPathChangeType type, Mod mod, DirectoryInfo? oldDirectory, + DirectoryInfo? newDirectory ) + { + switch( type ) + { + case ModPathChangeType.Deleted when oldDirectory != null: + ModDeleted?.Invoke( oldDirectory.Name ); + break; + case ModPathChangeType.Added when newDirectory != null: + ModAdded?.Invoke( newDirectory.Name ); + break; + case ModPathChangeType.Moved when newDirectory != null && oldDirectory != null: + ModMoved?.Invoke( oldDirectory.Name, newDirectory.Name ); + break; + } + } public (PenumbraApiEc, string, bool) GetModPath( string modDirectory, string modName ) { diff --git a/Penumbra/Api/PenumbraIpcProviders.cs b/Penumbra/Api/PenumbraIpcProviders.cs index 518d3638..dd042b99 100644 --- a/Penumbra/Api/PenumbraIpcProviders.cs +++ b/Penumbra/Api/PenumbraIpcProviders.cs @@ -75,6 +75,9 @@ public class PenumbraIpcProviders : IDisposable internal readonly FuncProvider< string, string, PenumbraApiEc > DeleteMod; internal readonly FuncProvider< string, string, (PenumbraApiEc, string, bool) > GetModPath; internal readonly FuncProvider< string, string, string, PenumbraApiEc > SetModPath; + internal readonly EventProvider< string > ModDeleted; + internal readonly EventProvider< string > ModAdded; + internal readonly EventProvider< string, string > ModMoved; // ModSettings internal readonly FuncProvider< string, string, IDictionary< string, (IList< string >, GroupType) >? > GetAvailableModSettings; @@ -167,6 +170,9 @@ public class PenumbraIpcProviders : IDisposable DeleteMod = Ipc.DeleteMod.Provider( pi, Api.DeleteMod ); GetModPath = Ipc.GetModPath.Provider( pi, Api.GetModPath ); SetModPath = Ipc.SetModPath.Provider( pi, Api.SetModPath ); + ModDeleted = Ipc.ModDeleted.Provider( pi, () => Api.ModDeleted += ModDeletedEvent, () => Api.ModDeleted -= ModDeletedEvent ); + ModAdded = Ipc.ModAdded.Provider( pi, () => Api.ModAdded += ModAddedEvent, () => Api.ModAdded -= ModAddedEvent ); + ModMoved = Ipc.ModMoved.Provider( pi, () => Api.ModMoved += ModMovedEvent, () => Api.ModMoved -= ModMovedEvent ); // ModSettings GetAvailableModSettings = Ipc.GetAvailableModSettings.Provider( pi, Api.GetAvailableModSettings ); @@ -259,6 +265,9 @@ public class PenumbraIpcProviders : IDisposable DeleteMod.Dispose(); GetModPath.Dispose(); SetModPath.Dispose(); + ModDeleted.Dispose(); + ModAdded.Dispose(); + ModMoved.Dispose(); // ModSettings GetAvailableModSettings.Dispose(); @@ -321,4 +330,13 @@ public class PenumbraIpcProviders : IDisposable private void ModSettingChangedEvent( ModSettingChange type, string collection, string mod, bool inherited ) => ModSettingChanged.Invoke( type, collection, mod, inherited ); + + private void ModDeletedEvent( string name ) + => ModDeleted.Invoke( name ); + + private void ModAddedEvent( string name ) + => ModAdded.Invoke( name ); + + private void ModMovedEvent( string from, string to ) + => ModMoved.Invoke( from, to ); } \ No newline at end of file diff --git a/Penumbra/Mods/Manager/Mod.Manager.BasePath.cs b/Penumbra/Mods/Manager/Mod.Manager.BasePath.cs index 9902ed57..8f092ed4 100644 --- a/Penumbra/Mods/Manager/Mod.Manager.BasePath.cs +++ b/Penumbra/Mods/Manager/Mod.Manager.BasePath.cs @@ -58,7 +58,7 @@ public partial class Mod return; } - MoveDataFile( oldDirectory, BasePath ); + MoveDataFile( oldDirectory, dir ); new ModBackup( mod ).Move( null, dir.Name ); dir.Refresh(); @@ -69,7 +69,7 @@ public partial class Mod return; } - ModPathChanged.Invoke( ModPathChangeType.Moved, mod, oldDirectory, BasePath ); + ModPathChanged.Invoke( ModPathChangeType.Moved, mod, oldDirectory, dir ); if( metaChange != ModDataChangeType.None ) { ModDataChanged?.Invoke( metaChange, mod, oldName );