diff --git a/.editorconfig b/.editorconfig
index e283b2a2..238bb1dc 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -37,7 +37,7 @@ resharper_autodetect_indent_settings=true
resharper_braces_redundant=true
resharper_constructor_or_destructor_body=expression_body
resharper_csharp_empty_block_style=together
-resharper_csharp_max_line_length=144
+resharper_csharp_max_line_length=180
resharper_csharp_space_within_array_access_brackets=true
resharper_enforce_line_ending_style=true
resharper_int_align_assignments=true
diff --git a/.gitmodules b/.gitmodules
index df7b5848..b5eb77bb 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -2,3 +2,7 @@
path = OtterGui
url = git@github.com:Ottermandias/OtterGui.git
branch = main
+[submodule "Penumbra.Api"]
+ path = Penumbra.Api
+ url = git@github.com:Ottermandias/Penumbra.Api.git
+ branch = main
diff --git a/Penumbra.Api b/Penumbra.Api
new file mode 160000
index 00000000..0064bb82
--- /dev/null
+++ b/Penumbra.Api
@@ -0,0 +1 @@
+Subproject commit 0064bb82be9729676e7bf3202ff1407283e6f088
diff --git a/Penumbra.GameData/Enums/ChangedItemExtensions.cs b/Penumbra.GameData/Enums/ChangedItemExtensions.cs
new file mode 100644
index 00000000..68674268
--- /dev/null
+++ b/Penumbra.GameData/Enums/ChangedItemExtensions.cs
@@ -0,0 +1,32 @@
+using System;
+using Lumina.Excel.GeneratedSheets;
+using Penumbra.Api.Enums;
+using Action = Lumina.Excel.GeneratedSheets.Action;
+
+namespace Penumbra.GameData.Enums;
+
+public static class ChangedItemExtensions
+{
+ public static (ChangedItemType, uint) ChangedItemToTypeAndId( object? item )
+ {
+ return item switch
+ {
+ null => ( ChangedItemType.None, 0 ),
+ Item i => ( ChangedItemType.Item, i.RowId ),
+ Action a => ( ChangedItemType.Action, a.RowId ),
+ _ => ( ChangedItemType.Customization, 0 ),
+ };
+ }
+
+ public static object? GetObject( this ChangedItemType type, uint id )
+ {
+ return type switch
+ {
+ ChangedItemType.None => null,
+ ChangedItemType.Item => ObjectIdentification.DataManager?.GetExcelSheet< Item >()?.GetRow( id ),
+ ChangedItemType.Action => ObjectIdentification.DataManager?.GetExcelSheet< Action >()?.GetRow( id ),
+ ChangedItemType.Customization => null,
+ _ => throw new ArgumentOutOfRangeException( nameof( type ), type, null ),
+ };
+ }
+}
\ No newline at end of file
diff --git a/Penumbra.GameData/Enums/ChangedItemType.cs b/Penumbra.GameData/Enums/ChangedItemType.cs
deleted file mode 100644
index fa33382d..00000000
--- a/Penumbra.GameData/Enums/ChangedItemType.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using System;
-using Lumina.Excel.GeneratedSheets;
-using Action = Lumina.Excel.GeneratedSheets.Action;
-
-namespace Penumbra.GameData.Enums
-{
- public enum ChangedItemType
- {
- None,
- Item,
- Action,
- Customization,
- }
-
- public static class ChangedItemExtensions
- {
- public static (ChangedItemType, uint) ChangedItemToTypeAndId( object? item )
- {
- return item switch
- {
- null => ( ChangedItemType.None, 0 ),
- Item i => ( ChangedItemType.Item, i.RowId ),
- Action a => ( ChangedItemType.Action, a.RowId ),
- _ => ( ChangedItemType.Customization, 0 ),
- };
- }
-
- public static object? GetObject( this ChangedItemType type, uint id )
- {
- return type switch
- {
- ChangedItemType.None => null,
- ChangedItemType.Item => ObjectIdentification.DataManager?.GetExcelSheet< Item >()?.GetRow( id ),
- ChangedItemType.Action => ObjectIdentification.DataManager?.GetExcelSheet< Action >()?.GetRow( id ),
- ChangedItemType.Customization => null,
- _ => throw new ArgumentOutOfRangeException( nameof( type ), type, null )
- };
- }
- }
-}
diff --git a/Penumbra.GameData/Enums/MouseButton.cs b/Penumbra.GameData/Enums/MouseButton.cs
deleted file mode 100644
index 99948d7c..00000000
--- a/Penumbra.GameData/Enums/MouseButton.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace Penumbra.GameData.Enums
-{
- public enum MouseButton
- {
- None,
- Left,
- Right,
- Middle,
- }
-}
\ No newline at end of file
diff --git a/Penumbra.GameData/Penumbra.GameData.csproj b/Penumbra.GameData/Penumbra.GameData.csproj
index ad466524..cb51d6dc 100644
--- a/Penumbra.GameData/Penumbra.GameData.csproj
+++ b/Penumbra.GameData/Penumbra.GameData.csproj
@@ -34,6 +34,10 @@
$(AppData)\XIVLauncher\addon\Hooks\dev\
+
+
+
+
$(DalamudLibPath)Dalamud.dll
diff --git a/Penumbra.sln b/Penumbra.sln
index b43c7565..33e5a03d 100644
--- a/Penumbra.sln
+++ b/Penumbra.sln
@@ -14,6 +14,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Penumbra.GameData", "Penumb
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OtterGui", "OtterGui\OtterGui.csproj", "{87750518-1A20-40B4-9FC1-22F906EFB290}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Penumbra.Api", "Penumbra.Api\Penumbra.Api.csproj", "{1FE4D8DF-B56A-464F-B39E-CDC0ED4167D4}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -32,6 +34,10 @@ Global
{87750518-1A20-40B4-9FC1-22F906EFB290}.Debug|Any CPU.Build.0 = Debug|Any CPU
{87750518-1A20-40B4-9FC1-22F906EFB290}.Release|Any CPU.ActiveCfg = Release|Any CPU
{87750518-1A20-40B4-9FC1-22F906EFB290}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1FE4D8DF-B56A-464F-B39E-CDC0ED4167D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1FE4D8DF-B56A-464F-B39E-CDC0ED4167D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1FE4D8DF-B56A-464F-B39E-CDC0ED4167D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1FE4D8DF-B56A-464F-B39E-CDC0ED4167D4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Penumbra/Api/IpcTester.cs b/Penumbra/Api/IpcTester.cs
index 1fd29dec..486eb826 100644
--- a/Penumbra/Api/IpcTester.cs
+++ b/Penumbra/Api/IpcTester.cs
@@ -1,76 +1,94 @@
-using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Interface;
using Dalamud.Plugin;
-using Dalamud.Plugin.Ipc;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
-using Penumbra.Collections;
using Penumbra.GameData.ByteString;
-using Penumbra.GameData.Enums;
using Penumbra.Mods;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Numerics;
-using System.Reflection;
+using Penumbra.Api.Enums;
+using Penumbra.Api.Helpers;
namespace Penumbra.Api;
public class IpcTester : IDisposable
{
- private readonly PenumbraIpc _ipc;
- private readonly DalamudPluginInterface _pi;
+ private readonly PenumbraIpcProviders _ipcProviders;
+ private bool _subscribed = true;
- private readonly ICallGateSubscriber< object? > _initialized;
- private readonly ICallGateSubscriber< object? > _disposed;
- private readonly ICallGateSubscriber< string, object? > _preSettingsDraw;
- private readonly ICallGateSubscriber< string, object? > _postSettingsDraw;
- private readonly ICallGateSubscriber< string, bool, object? > _modDirectoryChanged;
- private readonly ICallGateSubscriber< IntPtr, int, object? > _redrawn;
- 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 PluginState _pluginState;
+ private readonly Configuration _configuration;
+ private readonly Ui _ui;
+ private readonly Redrawing _redrawing;
+ private readonly GameState _gameState;
+ private readonly Resolve _resolve;
+ private readonly Collections _collections;
+ private readonly Meta _meta;
+ private readonly Mods _mods;
+ private readonly ModSettings _modSettings;
+ private readonly Temporary _temporary;
- private readonly List< DateTimeOffset > _initializedList = new();
- private readonly List< DateTimeOffset > _disposedList = new();
- private bool _subscribed = false;
-
-
- public IpcTester( DalamudPluginInterface pi, PenumbraIpc ipc )
+ public IpcTester( DalamudPluginInterface pi, PenumbraIpcProviders ipcProviders )
{
- _ipc = ipc;
- _pi = pi;
- _initialized = _pi.GetIpcSubscriber< object? >( PenumbraIpc.LabelProviderInitialized );
- _disposed = _pi.GetIpcSubscriber< object? >( PenumbraIpc.LabelProviderDisposed );
- _redrawn = _pi.GetIpcSubscriber< IntPtr, int, object? >( PenumbraIpc.LabelProviderGameObjectRedrawn );
- _preSettingsDraw = _pi.GetIpcSubscriber< string, object? >( PenumbraIpc.LabelProviderPreSettingsDraw );
- _postSettingsDraw = _pi.GetIpcSubscriber< string, object? >( PenumbraIpc.LabelProviderPostSettingsDraw );
- _settingChanged = _pi.GetIpcSubscriber< ModSettingChange, string, string, bool, object? >( PenumbraIpc.LabelProviderModSettingChanged );
- _modDirectoryChanged = _pi.GetIpcSubscriber< string, bool, object? >( PenumbraIpc.LabelProviderModDirectoryChanged );
- _characterBaseCreating =
- _pi.GetIpcSubscriber< IntPtr, string, IntPtr, IntPtr, IntPtr, object? >( PenumbraIpc.LabelProviderCreatingCharacterBase );
- _characterBaseCreated = _pi.GetIpcSubscriber< IntPtr, string, IntPtr, object? >( PenumbraIpc.LabelProviderCreatedCharacterBase );
- _gameObjectResourcePathResolved =
- _pi.GetIpcSubscriber< IntPtr, string, string, object? >( PenumbraIpc.LabelProviderGameObjectResourcePathResolved );
+ _ipcProviders = ipcProviders;
+ _pluginState = new PluginState( pi );
+ _configuration = new Configuration( pi );
+ _ui = new Ui( pi );
+ _redrawing = new Redrawing( pi );
+ _gameState = new GameState( pi );
+ _resolve = new Resolve( pi );
+ _collections = new Collections( pi );
+ _meta = new Meta( pi );
+ _mods = new Mods( pi );
+ _modSettings = new ModSettings( pi );
+ _temporary = new Temporary( pi );
+ UnsubscribeEvents();
+ }
+
+ public void Draw()
+ {
+ try
+ {
+ SubscribeEvents();
+ ImGui.TextUnformatted( $"API Version: {_ipcProviders.Api.ApiVersion.Breaking}.{_ipcProviders.Api.ApiVersion.Feature:D4}" );
+ _pluginState.Draw();
+ _configuration.Draw();
+ _ui.Draw();
+ _redrawing.Draw();
+ _gameState.Draw();
+ _resolve.Draw();
+ _collections.Draw();
+ _meta.Draw();
+ _mods.Draw();
+ _modSettings.Draw();
+ _temporary.Draw();
+ _temporary.DrawCollections();
+ _temporary.DrawMods();
+ }
+ catch( Exception e )
+ {
+ Penumbra.Log.Error( $"Error during IPC Tests:\n{e}" );
+ }
}
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 );
+ _pluginState.Initialized.Enable();
+ _pluginState.Disposed.Enable();
+ _redrawing.Redrawn.Enable();
+ _ui.PreSettingsDraw.Enable();
+ _ui.PostSettingsDraw.Enable();
+ _modSettings.SettingChanged.Enable();
+ _gameState.CharacterBaseCreating.Enable();
+ _gameState.CharacterBaseCreated.Enable();
+ _configuration.ModDirectoryChanged.Enable();
+ _gameState.GameObjectResourcePathResolved.Enable();
_subscribed = true;
}
}
@@ -79,75 +97,37 @@ public class IpcTester : IDisposable
{
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 );
+ _pluginState.Initialized.Disable();
+ _pluginState.Disposed.Disable();
+ _redrawing.Redrawn.Disable();
+ _ui.PreSettingsDraw.Disable();
+ _ui.PostSettingsDraw.Disable();
+ _ui.Tooltip.Disable();
+ _ui.Click.Disable();
+ _modSettings.SettingChanged.Disable();
+ _gameState.CharacterBaseCreating.Disable();
+ _gameState.CharacterBaseCreated.Disable();
+ _configuration.ModDirectoryChanged.Disable();
+ _gameState.GameObjectResourcePathResolved.Disable();
_subscribed = false;
}
}
public void Dispose()
- => UnsubscribeEvents();
-
- private void AddInitialized()
- => _initializedList.Add( DateTimeOffset.UtcNow );
-
- private void AddDisposed()
- => _disposedList.Add( DateTimeOffset.UtcNow );
-
- public void Draw()
{
- try
- {
- SubscribeEvents();
- DrawAvailable();
- DrawGeneral();
- DrawResolve();
- DrawRedraw();
- DrawChangedItems();
- DrawData();
- DrawSetting();
- DrawTemp();
- DrawTempCollections();
- DrawTempMods();
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error during IPC Tests:\n{e}" );
- }
- }
-
- private void DrawAvailable()
- {
- using var _ = ImRaii.TreeNode( "Availability" );
- if( !_ )
- {
- return;
- }
-
- ImGui.TextUnformatted( $"API Version: {_ipc.Api.ApiVersion.Breaking}.{_ipc.Api.ApiVersion.Feature:D4}" );
- ImGui.TextUnformatted( "Available subscriptions:" );
- using var indent = ImRaii.PushIndent();
-
- var dict = _ipc.GetType().GetFields( BindingFlags.Static | BindingFlags.Public ).Where( f => f.IsLiteral )
- .ToDictionary( f => f.Name, f => f.GetValue( _ipc ) as string );
- foreach( var provider in _ipc.GetType().GetFields( BindingFlags.Instance | BindingFlags.NonPublic ) )
- {
- var value = provider.GetValue( _ipc );
- if( value != null && dict.TryGetValue( "Label" + provider.Name, out var label ) )
- {
- ImGui.TextUnformatted( label );
- }
- }
+ _pluginState.Initialized.Dispose();
+ _pluginState.Disposed.Dispose();
+ _redrawing.Redrawn.Dispose();
+ _ui.PreSettingsDraw.Dispose();
+ _ui.PostSettingsDraw.Dispose();
+ _ui.Tooltip.Dispose();
+ _ui.Click.Dispose();
+ _modSettings.SettingChanged.Dispose();
+ _gameState.CharacterBaseCreating.Dispose();
+ _gameState.CharacterBaseCreated.Dispose();
+ _configuration.ModDirectoryChanged.Dispose();
+ _gameState.GameObjectResourcePathResolved.Dispose();
+ _subscribed = false;
}
private static void DrawIntro( string label, string info )
@@ -159,605 +139,849 @@ public class IpcTester : IDisposable
ImGui.TableNextColumn();
}
- private string _currentConfiguration = string.Empty;
- private string _lastDrawnMod = string.Empty;
- private DateTimeOffset _lastDrawnModTime = DateTimeOffset.MinValue;
- private void UpdateLastDrawnMod( string name )
- => ( _lastDrawnMod, _lastDrawnModTime ) = ( name, DateTimeOffset.Now );
-
- private string _lastModDirectory = string.Empty;
- private bool _lastModDirectoryValid = false;
- private DateTimeOffset _lastModDirectoryTime = DateTimeOffset.MinValue;
-
- private void UpdateModDirectoryChanged( string path, bool valid )
- => ( _lastModDirectory, _lastModDirectoryValid, _lastModDirectoryTime ) = ( path, valid, DateTimeOffset.Now );
-
- private void DrawGeneral()
+ private class PluginState
{
- using var _ = ImRaii.TreeNode( "General IPC" );
- if( !_ )
+ private readonly DalamudPluginInterface _pi;
+ public readonly EventSubscriber Initialized;
+ public readonly EventSubscriber Disposed;
+
+ private readonly List< DateTimeOffset > _initializedList = new();
+ private readonly List< DateTimeOffset > _disposedList = new();
+
+ public PluginState( DalamudPluginInterface pi )
{
- return;
+ _pi = pi;
+ Initialized = Ipc.Initialized.Subscriber( pi, AddInitialized );
+ Disposed = Ipc.Disposed.Subscriber( pi, AddDisposed );
}
- using var table = ImRaii.Table( string.Empty, 3, ImGuiTableFlags.SizingFixedFit );
-
- void DrawList( string label, string text, List< DateTimeOffset > list )
+ public void Draw()
{
- DrawIntro( label, text );
- if( list.Count == 0 )
+ using var _ = ImRaii.TreeNode( "Plugin State" );
+ if( !_ )
{
- ImGui.TextUnformatted( "Never" );
+ return;
}
- else
+
+ using var table = ImRaii.Table( string.Empty, 3, ImGuiTableFlags.SizingFixedFit );
+ if( !table )
{
- ImGui.TextUnformatted( list[ ^1 ].LocalDateTime.ToString( CultureInfo.CurrentCulture ) );
- if( list.Count > 1 && ImGui.IsItemHovered() )
+ return;
+ }
+
+ void DrawList( string label, string text, List< DateTimeOffset > list )
+ {
+ DrawIntro( label, text );
+ if( list.Count == 0 )
{
- ImGui.SetTooltip( string.Join( "\n",
- list.SkipLast( 1 ).Select( t => t.LocalDateTime.ToString( CultureInfo.CurrentCulture ) ) ) );
+ ImGui.TextUnformatted( "Never" );
+ }
+ else
+ {
+ ImGui.TextUnformatted( list[ ^1 ].LocalDateTime.ToString( CultureInfo.CurrentCulture ) );
+ if( list.Count > 1 && ImGui.IsItemHovered() )
+ {
+ ImGui.SetTooltip( string.Join( "\n",
+ list.SkipLast( 1 ).Select( t => t.LocalDateTime.ToString( CultureInfo.CurrentCulture ) ) ) );
+ }
+ }
+ }
+
+ DrawList( Ipc.Initialized.Label, "Last Initialized", _initializedList );
+ DrawList( Ipc.Disposed.Label, "Last Disposed", _disposedList );
+ DrawIntro( Ipc.ApiVersions.Label, "Current Version" );
+ var (breaking, features) = Ipc.ApiVersions.Subscriber( _pi ).Invoke();
+ ImGui.TextUnformatted( $"{breaking}.{features:D4}" );
+ }
+
+ private void AddInitialized()
+ => _initializedList.Add( DateTimeOffset.UtcNow );
+
+ private void AddDisposed()
+ => _disposedList.Add( DateTimeOffset.UtcNow );
+ }
+
+ private class Configuration
+ {
+ private readonly DalamudPluginInterface _pi;
+ public readonly EventSubscriber< string, bool > ModDirectoryChanged;
+
+ private string _currentConfiguration = string.Empty;
+ private string _lastModDirectory = string.Empty;
+ private bool _lastModDirectoryValid;
+ private DateTimeOffset _lastModDirectoryTime = DateTimeOffset.MinValue;
+
+ public Configuration( DalamudPluginInterface pi )
+ {
+ _pi = pi;
+ ModDirectoryChanged = Ipc.ModDirectoryChanged.Subscriber( pi, UpdateModDirectoryChanged );
+ }
+
+ public void Draw()
+ {
+ using var _ = ImRaii.TreeNode( "Configuration" );
+ if( !_ )
+ {
+ return;
+ }
+
+ using var table = ImRaii.Table( string.Empty, 3, ImGuiTableFlags.SizingFixedFit );
+ if( !table )
+ {
+ return;
+ }
+
+ DrawIntro( Ipc.GetModDirectory.Label, "Current Mod Directory" );
+ ImGui.TextUnformatted( Ipc.GetModDirectory.Subscriber( _pi ).Invoke() );
+ DrawIntro( Ipc.ModDirectoryChanged.Label, "Last Mod Directory Change" );
+ ImGui.TextUnformatted( _lastModDirectoryTime > DateTimeOffset.MinValue
+ ? $"{_lastModDirectory} ({( _lastModDirectoryValid ? "Valid" : "Invalid" )}) at {_lastModDirectoryTime}"
+ : "None" );
+ DrawIntro( Ipc.GetConfiguration.Label, "Configuration" );
+ if( ImGui.Button( "Get" ) )
+ {
+ _currentConfiguration = Ipc.GetConfiguration.Subscriber( _pi ).Invoke();
+ ImGui.OpenPopup( "Config Popup" );
+ }
+
+ DrawConfigPopup();
+ }
+
+ private void DrawConfigPopup()
+ {
+ ImGui.SetNextWindowSize( ImGuiHelpers.ScaledVector2( 500, 500 ) );
+ using var popup = ImRaii.Popup( "Config Popup" );
+ if( popup )
+ {
+ using( var font = ImRaii.PushFont( UiBuilder.MonoFont ) )
+ {
+ ImGuiUtil.TextWrapped( _currentConfiguration );
+ }
+
+ if( ImGui.Button( "Close", -Vector2.UnitX ) || !ImGui.IsWindowFocused() )
+ {
+ ImGui.CloseCurrentPopup();
}
}
}
- DrawList( PenumbraIpc.LabelProviderInitialized, "Last Initialized", _initializedList );
- DrawList( PenumbraIpc.LabelProviderDisposed, "Last Disposed", _disposedList );
- DrawIntro( PenumbraIpc.LabelProviderPostSettingsDraw, "Last Drawn Mod" );
- ImGui.TextUnformatted( _lastDrawnMod.Length > 0 ? $"{_lastDrawnMod} at {_lastDrawnModTime}" : "None" );
- DrawIntro( PenumbraIpc.LabelProviderApiVersions, "Current Version" );
- var (breaking, features) = _pi.GetIpcSubscriber< (int, int) >( PenumbraIpc.LabelProviderApiVersions ).InvokeFunc();
- ImGui.TextUnformatted( $"{breaking}.{features:D4}" );
- DrawIntro( PenumbraIpc.LabelProviderGetModDirectory, "Current Mod Directory" );
- ImGui.TextUnformatted( _pi.GetIpcSubscriber< string >( PenumbraIpc.LabelProviderGetModDirectory ).InvokeFunc() );
- DrawIntro( PenumbraIpc.LabelProviderModDirectoryChanged, "Last Mod Directory Change" );
- ImGui.TextUnformatted( _lastModDirectoryTime > DateTimeOffset.MinValue
- ? $"{_lastModDirectory} ({( _lastModDirectoryValid ? "Valid" : "Invalid" )}) at {_lastModDirectoryTime}"
- : "None" );
- DrawIntro( PenumbraIpc.LabelProviderGetConfiguration, "Configuration" );
- if( ImGui.Button( "Get" ) )
+ private void UpdateModDirectoryChanged( string path, bool valid )
+ => ( _lastModDirectory, _lastModDirectoryValid, _lastModDirectoryTime ) = ( path, valid, DateTimeOffset.Now );
+ }
+
+ private class Ui
+ {
+ private readonly DalamudPluginInterface _pi;
+ public readonly EventSubscriber< string > PreSettingsDraw;
+ public readonly EventSubscriber< string > PostSettingsDraw;
+ public readonly EventSubscriber< ChangedItemType, uint > Tooltip;
+ public readonly EventSubscriber< MouseButton, ChangedItemType, uint > Click;
+
+ private string _lastDrawnMod = string.Empty;
+ private DateTimeOffset _lastDrawnModTime = DateTimeOffset.MinValue;
+ private bool _subscribedToTooltip = false;
+ private bool _subscribedToClick = false;
+ private string _lastClicked = string.Empty;
+ private string _lastHovered = string.Empty;
+
+ public Ui( DalamudPluginInterface pi )
{
- _currentConfiguration = _pi.GetIpcSubscriber< string >( PenumbraIpc.LabelProviderGetConfiguration ).InvokeFunc();
- ImGui.OpenPopup( "Config Popup" );
+ _pi = pi;
+ PreSettingsDraw = Ipc.PreSettingsDraw.Subscriber( pi, UpdateLastDrawnMod );
+ PostSettingsDraw = Ipc.PostSettingsDraw.Subscriber( pi, UpdateLastDrawnMod );
+ Tooltip = Ipc.ChangedItemTooltip.Subscriber( pi, AddedTooltip );
+ Click = Ipc.ChangedItemClick.Subscriber( pi, AddedClick );
}
- ImGui.SetNextWindowSize( ImGuiHelpers.ScaledVector2( 500, 500 ) );
- using var popup = ImRaii.Popup( "Config Popup" );
- if( popup )
+ public void Draw()
{
- using( var font = ImRaii.PushFont( UiBuilder.MonoFont ) )
+ using var _ = ImRaii.TreeNode( "UI" );
+ if( !_ )
{
- ImGuiUtil.TextWrapped( _currentConfiguration );
+ return;
}
- if( ImGui.Button( "Close", -Vector2.UnitX ) || ImGui.IsWindowFocused() )
+ using var table = ImRaii.Table( string.Empty, 3, ImGuiTableFlags.SizingFixedFit );
+ if( !table )
{
- ImGui.CloseCurrentPopup();
+ return;
}
- }
- }
- private string _currentResolvePath = string.Empty;
- private string _currentResolveCharacter = string.Empty;
- private string _currentDrawObjectString = string.Empty;
- private string _currentReversePath = string.Empty;
- private IntPtr _currentDrawObject = IntPtr.Zero;
- private int _currentCutsceneActor = 0;
- 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;
+ DrawIntro( Ipc.PostSettingsDraw.Label, "Last Drawn Mod" );
+ ImGui.TextUnformatted( _lastDrawnMod.Length > 0 ? $"{_lastDrawnMod} at {_lastDrawnModTime}" : "None" );
- private unsafe void UpdateLastCreated( IntPtr gameObject, string _, IntPtr _2, IntPtr _3, IntPtr _4 )
- {
- var obj = ( FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* )gameObject;
- _lastCreatedGameObjectName = new Utf8String( obj->GetName() ).ToString();
- _lastCreatedGameObjectTime = DateTimeOffset.Now;
- _lastCreatedDrawObject = IntPtr.Zero;
- }
-
- private unsafe void UpdateLastCreated2( IntPtr gameObject, string _, IntPtr drawObject )
- {
- var obj = ( FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* )gameObject;
- _lastCreatedGameObjectName = new Utf8String( obj->GetName() ).ToString();
- _lastCreatedGameObjectTime = DateTimeOffset.Now;
- _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" );
- if( !_ )
- {
- return;
- }
-
- ImGui.InputTextWithHint( "##resolvePath", "Resolve this game path...", ref _currentResolvePath, Utf8GamePath.MaxGamePathLength );
- ImGui.InputTextWithHint( "##resolveCharacter", "Character Name (leave blank for default)...", ref _currentResolveCharacter, 32 );
- ImGui.InputTextWithHint( "##resolveInversePath", "Reverse-resolve this path...", ref _currentReversePath,
- Utf8GamePath.MaxGamePathLength );
- if( ImGui.InputTextWithHint( "##drawObject", "Draw Object Address..", ref _currentDrawObjectString, 16,
- ImGuiInputTextFlags.CharsHexadecimal ) )
- {
- _currentDrawObject = IntPtr.TryParse( _currentDrawObjectString, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var tmp )
- ? tmp
- : IntPtr.Zero;
- }
-
- ImGui.InputInt( "Cutscene Actor", ref _currentCutsceneActor, 0 );
-
- using var table = ImRaii.Table( string.Empty, 3, ImGuiTableFlags.SizingFixedFit );
- if( !table )
- {
- return;
- }
-
- DrawIntro( PenumbraIpc.LabelProviderResolveDefault, "Default Collection Resolve" );
- if( _currentResolvePath.Length != 0 )
- {
- ImGui.TextUnformatted( _pi.GetIpcSubscriber< string, string >( PenumbraIpc.LabelProviderResolveDefault )
- .InvokeFunc( _currentResolvePath ) );
- }
-
- DrawIntro( PenumbraIpc.LabelProviderResolveInterface, "Interface Collection Resolve" );
- if( _currentResolvePath.Length != 0 )
- {
- ImGui.TextUnformatted( _pi.GetIpcSubscriber< string, string >( PenumbraIpc.LabelProviderResolveInterface )
- .InvokeFunc( _currentResolvePath ) );
- }
-
- DrawIntro( PenumbraIpc.LabelProviderResolveCharacter, "Character Collection Resolve" );
- if( _currentResolvePath.Length != 0 && _currentResolveCharacter.Length != 0 )
- {
- ImGui.TextUnformatted( _pi.GetIpcSubscriber< string, string, string >( PenumbraIpc.LabelProviderResolveCharacter )
- .InvokeFunc( _currentResolvePath, _currentResolveCharacter ) );
- }
-
- DrawIntro( PenumbraIpc.LabelProviderGetDrawObjectInfo, "Draw Object Info" );
- if( _currentDrawObject == IntPtr.Zero )
- {
- ImGui.TextUnformatted( "Invalid" );
- }
- else
- {
- var (ptr, collection) = _pi.GetIpcSubscriber< IntPtr, (IntPtr, string) >( PenumbraIpc.LabelProviderGetDrawObjectInfo )
- .InvokeFunc( _currentDrawObject );
- ImGui.TextUnformatted( ptr == IntPtr.Zero ? $"No Actor Associated, {collection}" : $"{ptr:X}, {collection}" );
- }
-
- DrawIntro( PenumbraIpc.LabelProviderGetDrawObjectInfo, "Cutscene Parent" );
- ImGui.TextUnformatted( _pi.GetIpcSubscriber< int, int >( PenumbraIpc.LabelProviderGetCutsceneParentIndex )
- .InvokeFunc( _currentCutsceneActor ).ToString() );
-
- DrawIntro( PenumbraIpc.LabelProviderReverseResolvePath, "Reversed Game Paths" );
- if( _currentReversePath.Length > 0 )
- {
- var list = _pi.GetIpcSubscriber< string, string, string[] >( PenumbraIpc.LabelProviderReverseResolvePath )
- .InvokeFunc( _currentReversePath, _currentResolveCharacter );
- if( list.Length > 0 )
+ DrawIntro( Ipc.ChangedItemTooltip.Label, "Add Tooltip" );
+ if( ImGui.Checkbox( "##tooltip", ref _subscribedToTooltip ) )
{
- ImGui.TextUnformatted( list[ 0 ] );
- if( list.Length > 1 && ImGui.IsItemHovered() )
+ if( _subscribedToTooltip )
{
- ImGui.SetTooltip( string.Join( "\n", list.Skip( 1 ) ) );
+ Tooltip.Enable();
+ }
+ else
+ {
+ Tooltip.Disable();
}
}
- }
- DrawIntro( PenumbraIpc.LabelProviderReverseResolvePlayerPath, "Reversed Game Paths (Player)" );
- if( _currentReversePath.Length > 0 )
- {
- var list = _pi.GetIpcSubscriber< string, string[] >( PenumbraIpc.LabelProviderReverseResolvePlayerPath )
- .InvokeFunc( _currentReversePath );
- if( list.Length > 0 )
+ ImGui.SameLine();
+ ImGui.TextUnformatted( _lastHovered );
+
+ DrawIntro( Ipc.ChangedItemClick.Label, "Subscribe Click" );
+ if( ImGui.Checkbox( "##click", ref _subscribedToClick ) )
{
- ImGui.TextUnformatted( list[ 0 ] );
- if( list.Length > 1 && ImGui.IsItemHovered() )
+ if( _subscribedToClick )
{
- ImGui.SetTooltip( string.Join( "\n", list.Skip( 1 ) ) );
+ Click.Enable();
+ }
+ else
+ {
+ Click.Disable();
}
}
+
+ ImGui.SameLine();
+ ImGui.TextUnformatted( _lastClicked );
}
- DrawIntro( PenumbraIpc.LabelProviderCreatingCharacterBase, "Last Drawobject created" );
- if( _lastCreatedGameObjectTime < DateTimeOffset.Now )
+ private void UpdateLastDrawnMod( string name )
+ => ( _lastDrawnMod, _lastDrawnModTime ) = ( name, DateTimeOffset.Now );
+
+ private void AddedTooltip( ChangedItemType type, uint id )
{
- ImGui.TextUnformatted( _lastCreatedDrawObject != IntPtr.Zero
- ? $"0x{_lastCreatedDrawObject:X} for <{_lastCreatedGameObjectName}> at {_lastCreatedGameObjectTime}"
- : $"NULL for <{_lastCreatedGameObjectName}> at {_lastCreatedGameObjectTime}" );
+ _lastHovered = $"{type} {id} at {DateTime.UtcNow.ToLocalTime().ToString( CultureInfo.CurrentCulture )}";
+ ImGui.TextUnformatted( "IPC Test Successful" );
}
- DrawIntro( PenumbraIpc.LabelProviderGameObjectResourcePathResolved, "Last GamePath resolved" );
- if( _lastResolvedGamePathTime < DateTimeOffset.Now )
+ private void AddedClick( MouseButton button, ChangedItemType type, uint id )
{
- ImGui.TextUnformatted(
- $"{_lastResolvedGamePath} -> {_lastResolvedFullPath} for <{_lastResolvedObject}> at {_lastResolvedGamePathTime}" );
+ _lastClicked = $"{button}-click on {type} {id} at {DateTime.UtcNow.ToLocalTime().ToString( CultureInfo.CurrentCulture )}";
}
}
- private string _redrawName = string.Empty;
- private int _redrawIndex = 0;
- private string _lastRedrawnString = "None";
-
- private void SetLastRedrawn( IntPtr address, int index )
+ private class Redrawing
{
- if( index < 0 || index > Dalamud.Objects.Length || address == IntPtr.Zero || Dalamud.Objects[ index ]?.Address != address )
+ private readonly DalamudPluginInterface _pi;
+ public readonly EventSubscriber< IntPtr, int > Redrawn;
+
+ private string _redrawName = string.Empty;
+ private int _redrawIndex = 0;
+ private string _lastRedrawnString = "None";
+
+ public Redrawing( DalamudPluginInterface pi )
{
- _lastRedrawnString = "Invalid";
+ _pi = pi;
+ Redrawn = Ipc.GameObjectRedrawn.Subscriber( pi, SetLastRedrawn );
}
- _lastRedrawnString = $"{Dalamud.Objects[ index ]!.Name} (0x{address:X}, {index})";
- }
-
- private void DrawRedraw()
- {
- using var _ = ImRaii.TreeNode( "Redraw IPC" );
- if( !_ )
+ public void Draw()
{
- return;
- }
-
- using var table = ImRaii.Table( string.Empty, 3, ImGuiTableFlags.SizingFixedFit );
- if( !table )
- {
- return;
- }
-
- DrawIntro( PenumbraIpc.LabelProviderRedrawName, "Redraw by Name" );
- ImGui.SetNextItemWidth( 100 * ImGuiHelpers.GlobalScale );
- ImGui.InputTextWithHint( "##redrawName", "Name...", ref _redrawName, 32 );
- ImGui.SameLine();
- if( ImGui.Button( "Redraw##Name" ) )
- {
- _pi.GetIpcSubscriber< string, int, object? >( PenumbraIpc.LabelProviderRedrawName )
- .InvokeAction( _redrawName, ( int )RedrawType.Redraw );
- }
-
- DrawIntro( PenumbraIpc.LabelProviderRedrawObject, "Redraw Player Character" );
- if( ImGui.Button( "Redraw##pc" ) && Dalamud.ClientState.LocalPlayer != null )
- {
- _pi.GetIpcSubscriber< GameObject, int, object? >( PenumbraIpc.LabelProviderRedrawObject )
- .InvokeAction( Dalamud.ClientState.LocalPlayer, ( int )RedrawType.Redraw );
- }
-
- DrawIntro( PenumbraIpc.LabelProviderRedrawIndex, "Redraw by Index" );
- var tmp = _redrawIndex;
- ImGui.SetNextItemWidth( 100 * ImGuiHelpers.GlobalScale );
- if( ImGui.DragInt( "##redrawIndex", ref tmp, 0.1f, 0, Dalamud.Objects.Length ) )
- {
- _redrawIndex = Math.Clamp( tmp, 0, Dalamud.Objects.Length );
- }
-
- ImGui.SameLine();
- if( ImGui.Button( "Redraw##Index" ) )
- {
- _pi.GetIpcSubscriber< int, int, object? >( PenumbraIpc.LabelProviderRedrawIndex )
- .InvokeAction( _redrawIndex, ( int )RedrawType.Redraw );
- }
-
- DrawIntro( PenumbraIpc.LabelProviderRedrawAll, "Redraw All" );
- if( ImGui.Button( "Redraw##All" ) )
- {
- _pi.GetIpcSubscriber< int, object? >( PenumbraIpc.LabelProviderRedrawAll ).InvokeAction( ( int )RedrawType.Redraw );
- }
-
- DrawIntro( PenumbraIpc.LabelProviderGameObjectRedrawn, "Last Redrawn Object:" );
- ImGui.TextUnformatted( _lastRedrawnString );
- }
-
- private bool _subscribedToTooltip = false;
- private bool _subscribedToClick = false;
- private string _changedItemCollection = string.Empty;
- private IReadOnlyDictionary< string, object? > _changedItems = new Dictionary< string, object? >();
- private string _lastClicked = string.Empty;
- private string _lastHovered = string.Empty;
- private ICallGateSubscriber< ChangedItemType, uint, object? >? _tooltip;
- private ICallGateSubscriber< MouseButton, ChangedItemType, uint, object? >? _click;
-
- private void DrawChangedItems()
- {
- using var _ = ImRaii.TreeNode( "Changed Item IPC" );
- if( !_ )
- {
- return;
- }
-
- using var table = ImRaii.Table( string.Empty, 3, ImGuiTableFlags.SizingFixedFit );
- if( !table )
- {
- return;
- }
-
- DrawIntro( PenumbraIpc.LabelProviderChangedItemTooltip, "Add Tooltip" );
- if( ImGui.Checkbox( "##tooltip", ref _subscribedToTooltip ) )
- {
- _tooltip = _pi.GetIpcSubscriber< ChangedItemType, uint, object? >( PenumbraIpc.LabelProviderChangedItemTooltip );
- if( _subscribedToTooltip )
+ using var _ = ImRaii.TreeNode( "Redrawing" );
+ if( !_ )
{
- _tooltip.Subscribe( AddedTooltip );
+ return;
+ }
+
+ using var table = ImRaii.Table( string.Empty, 3, ImGuiTableFlags.SizingFixedFit );
+ if( !table )
+ {
+ return;
+ }
+
+ DrawIntro( Ipc.RedrawObjectByName.Label, "Redraw by Name" );
+ ImGui.SetNextItemWidth( 100 * ImGuiHelpers.GlobalScale );
+ ImGui.InputTextWithHint( "##redrawName", "Name...", ref _redrawName, 32 );
+ ImGui.SameLine();
+ if( ImGui.Button( "Redraw##Name" ) )
+ {
+ Ipc.RedrawObjectByName.Subscriber( _pi ).Invoke( _redrawName, RedrawType.Redraw );
+ }
+
+ DrawIntro( Ipc.RedrawObject.Label, "Redraw Player Character" );
+ if( ImGui.Button( "Redraw##pc" ) && Dalamud.ClientState.LocalPlayer != null )
+ {
+ Ipc.RedrawObject.Subscriber( _pi ).Invoke( Dalamud.ClientState.LocalPlayer, RedrawType.Redraw );
+ }
+
+ DrawIntro( Ipc.RedrawObjectByIndex.Label, "Redraw by Index" );
+ var tmp = _redrawIndex;
+ ImGui.SetNextItemWidth( 100 * ImGuiHelpers.GlobalScale );
+ if( ImGui.DragInt( "##redrawIndex", ref tmp, 0.1f, 0, Dalamud.Objects.Length ) )
+ {
+ _redrawIndex = Math.Clamp( tmp, 0, Dalamud.Objects.Length );
+ }
+
+ ImGui.SameLine();
+ if( ImGui.Button( "Redraw##Index" ) )
+ {
+ Ipc.RedrawObjectByIndex.Subscriber( _pi ).Invoke( _redrawIndex, RedrawType.Redraw );
+ }
+
+ DrawIntro( Ipc.RedrawAll.Label, "Redraw All" );
+ if( ImGui.Button( "Redraw##All" ) )
+ {
+ Ipc.RedrawAll.Subscriber( _pi ).Invoke( RedrawType.Redraw );
+ }
+
+ DrawIntro( Ipc.GameObjectRedrawn.Label, "Last Redrawn Object:" );
+ ImGui.TextUnformatted( _lastRedrawnString );
+ }
+
+ private void SetLastRedrawn( IntPtr address, int index )
+ {
+ if( index < 0 || index > Dalamud.Objects.Length || address == IntPtr.Zero || Dalamud.Objects[ index ]?.Address != address )
+ {
+ _lastRedrawnString = "Invalid";
+ }
+
+ _lastRedrawnString = $"{Dalamud.Objects[ index ]!.Name} (0x{address:X}, {index})";
+ }
+ }
+
+ private class GameState
+ {
+ private readonly DalamudPluginInterface _pi;
+ public readonly EventSubscriber< IntPtr, string, IntPtr, IntPtr, IntPtr > CharacterBaseCreating;
+ public readonly EventSubscriber< IntPtr, string, IntPtr > CharacterBaseCreated;
+ public readonly EventSubscriber< IntPtr, string, string > GameObjectResourcePathResolved;
+
+
+ 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 string _currentDrawObjectString = string.Empty;
+ private IntPtr _currentDrawObject = IntPtr.Zero;
+ private int _currentCutsceneActor = 0;
+
+ public GameState( DalamudPluginInterface pi )
+ {
+ _pi = pi;
+ CharacterBaseCreating = Ipc.CreatingCharacterBase.Subscriber( pi, UpdateLastCreated );
+ CharacterBaseCreated = Ipc.CreatedCharacterBase.Subscriber( pi, UpdateLastCreated2 );
+ GameObjectResourcePathResolved = Ipc.GameObjectResourcePathResolved.Subscriber( pi, UpdateGameObjectResourcePath );
+ }
+
+ public void Draw()
+ {
+ using var _ = ImRaii.TreeNode( "Game State" );
+ if( !_ )
+ {
+ return;
+ }
+
+ if( ImGui.InputTextWithHint( "##drawObject", "Draw Object Address..", ref _currentDrawObjectString, 16,
+ ImGuiInputTextFlags.CharsHexadecimal ) )
+ {
+ _currentDrawObject = IntPtr.TryParse( _currentDrawObjectString, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var tmp )
+ ? tmp
+ : IntPtr.Zero;
+ }
+
+ ImGui.InputInt( "Cutscene Actor", ref _currentCutsceneActor, 0 );
+ using var table = ImRaii.Table( string.Empty, 3, ImGuiTableFlags.SizingFixedFit );
+ if( !table )
+ {
+ return;
+ }
+
+ DrawIntro( Ipc.GetDrawObjectInfo.Label, "Draw Object Info" );
+ if( _currentDrawObject == IntPtr.Zero )
+ {
+ ImGui.TextUnformatted( "Invalid" );
}
else
{
- _tooltip.Unsubscribe( AddedTooltip );
+ var (ptr, collection) = Ipc.GetDrawObjectInfo.Subscriber( _pi ).Invoke( _currentDrawObject );
+ ImGui.TextUnformatted( ptr == IntPtr.Zero ? $"No Actor Associated, {collection}" : $"{ptr:X}, {collection}" );
}
- }
- ImGui.SameLine();
- ImGui.TextUnformatted( _lastHovered );
+ DrawIntro( Ipc.GetCutsceneParentIndex.Label, "Cutscene Parent" );
+ ImGui.TextUnformatted( Ipc.GetCutsceneParentIndex.Subscriber( _pi ).Invoke( _currentCutsceneActor ).ToString() );
- DrawIntro( PenumbraIpc.LabelProviderChangedItemClick, "Subscribe Click" );
- if( ImGui.Checkbox( "##click", ref _subscribedToClick ) )
- {
- _click = _pi.GetIpcSubscriber< MouseButton, ChangedItemType, uint, object? >( PenumbraIpc.LabelProviderChangedItemClick );
- if( _subscribedToClick )
+ DrawIntro( Ipc.CreatingCharacterBase.Label, "Last Drawobject created" );
+ if( _lastCreatedGameObjectTime < DateTimeOffset.Now )
{
- _click.Subscribe( AddedClick );
+ ImGui.TextUnformatted( _lastCreatedDrawObject != IntPtr.Zero
+ ? $"0x{_lastCreatedDrawObject:X} for <{_lastCreatedGameObjectName}> at {_lastCreatedGameObjectTime}"
+ : $"NULL for <{_lastCreatedGameObjectName}> at {_lastCreatedGameObjectTime}" );
}
- else
+
+ DrawIntro( Ipc.GameObjectResourcePathResolved.Label, "Last GamePath resolved" );
+ if( _lastResolvedGamePathTime < DateTimeOffset.Now )
{
- _click.Unsubscribe( AddedClick );
+ ImGui.TextUnformatted(
+ $"{_lastResolvedGamePath} -> {_lastResolvedFullPath} for <{_lastResolvedObject}> at {_lastResolvedGamePathTime}" );
}
}
- ImGui.SameLine();
- ImGui.TextUnformatted( _lastClicked );
-
- DrawIntro( PenumbraIpc.LabelProviderGetChangedItems, "Changed Item List" );
- ImGui.SetNextItemWidth( 200 * ImGuiHelpers.GlobalScale );
- ImGui.InputTextWithHint( "##changedCollection", "Collection Name...", ref _changedItemCollection, 64 );
- ImGui.SameLine();
- if( ImGui.Button( "Get" ) )
+ private unsafe void UpdateLastCreated( IntPtr gameObject, string _, IntPtr _2, IntPtr _3, IntPtr _4 )
{
- _changedItems = _pi.GetIpcSubscriber< string, IReadOnlyDictionary< string, object? > >( PenumbraIpc.LabelProviderGetChangedItems )
- .InvokeFunc( _changedItemCollection );
- ImGui.OpenPopup( "Changed Item List" );
+ var obj = ( FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* )gameObject;
+ _lastCreatedGameObjectName = new Utf8String( obj->GetName() ).ToString();
+ _lastCreatedGameObjectTime = DateTimeOffset.Now;
+ _lastCreatedDrawObject = IntPtr.Zero;
}
- ImGui.SetNextWindowSize( ImGuiHelpers.ScaledVector2( 500, 500 ) );
- using var p = ImRaii.Popup( "Changed Item List" );
- if( p )
+ private unsafe void UpdateLastCreated2( IntPtr gameObject, string _, IntPtr drawObject )
{
+ var obj = ( FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* )gameObject;
+ _lastCreatedGameObjectName = new Utf8String( obj->GetName() ).ToString();
+ _lastCreatedGameObjectTime = DateTimeOffset.Now;
+ _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 class Resolve
+ {
+ private readonly DalamudPluginInterface _pi;
+
+ private string _currentResolvePath = string.Empty;
+ private string _currentResolveCharacter = string.Empty;
+ private string _currentReversePath = string.Empty;
+
+ public Resolve( DalamudPluginInterface pi )
+ => _pi = pi;
+
+ public void Draw()
+ {
+ using var _ = ImRaii.TreeNode( "Resolving" );
+ if( !_ )
+ {
+ return;
+ }
+
+ ImGui.InputTextWithHint( "##resolvePath", "Resolve this game path...", ref _currentResolvePath, Utf8GamePath.MaxGamePathLength );
+ ImGui.InputTextWithHint( "##resolveCharacter", "Character Name (leave blank for default)...", ref _currentResolveCharacter, 32 );
+ ImGui.InputTextWithHint( "##resolveInversePath", "Reverse-resolve this path...", ref _currentReversePath,
+ Utf8GamePath.MaxGamePathLength );
+ using var table = ImRaii.Table( string.Empty, 3, ImGuiTableFlags.SizingFixedFit );
+ if( !table )
+ {
+ return;
+ }
+
+ DrawIntro( Ipc.ResolveDefaultPath.Label, "Default Collection Resolve" );
+ if( _currentResolvePath.Length != 0 )
+ {
+ ImGui.TextUnformatted( Ipc.ResolveDefaultPath.Subscriber( _pi ).Invoke( _currentResolvePath ) );
+ }
+
+ DrawIntro( Ipc.ResolveInterfacePath.Label, "Interface Collection Resolve" );
+ if( _currentResolvePath.Length != 0 )
+ {
+ ImGui.TextUnformatted( Ipc.ResolveInterfacePath.Subscriber( _pi ).Invoke( _currentResolvePath ) );
+ }
+
+ DrawIntro( Ipc.ResolvePlayerPath.Label, "Player Collection Resolve" );
+ if( _currentResolvePath.Length != 0 )
+ {
+ ImGui.TextUnformatted( Ipc.ResolvePlayerPath.Subscriber( _pi ).Invoke( _currentResolvePath ) );
+ }
+
+ DrawIntro( Ipc.ResolveCharacterPath.Label, "Character Collection Resolve" );
+ if( _currentResolvePath.Length != 0 && _currentResolveCharacter.Length != 0 )
+ {
+ ImGui.TextUnformatted( Ipc.ResolveCharacterPath.Subscriber( _pi ).Invoke( _currentResolvePath, _currentResolveCharacter ) );
+ }
+
+ DrawIntro( Ipc.ReverseResolvePath.Label, "Reversed Game Paths" );
+ if( _currentReversePath.Length > 0 )
+ {
+ var list = Ipc.ReverseResolvePath.Subscriber( _pi ).Invoke( _currentReversePath, _currentResolveCharacter );
+ if( list.Length > 0 )
+ {
+ ImGui.TextUnformatted( list[ 0 ] );
+ if( list.Length > 1 && ImGui.IsItemHovered() )
+ {
+ ImGui.SetTooltip( string.Join( "\n", list.Skip( 1 ) ) );
+ }
+ }
+ }
+
+ DrawIntro( Ipc.ReverseResolvePlayerPath.Label, "Reversed Game Paths (Player)" );
+ if( _currentReversePath.Length > 0 )
+ {
+ var list = Ipc.ReverseResolvePlayerPath.Subscriber( _pi ).Invoke( _currentReversePath );
+ if( list.Length > 0 )
+ {
+ ImGui.TextUnformatted( list[ 0 ] );
+ if( list.Length > 1 && ImGui.IsItemHovered() )
+ {
+ ImGui.SetTooltip( string.Join( "\n", list.Skip( 1 ) ) );
+ }
+ }
+ }
+ }
+ }
+
+ private class Collections
+ {
+ private readonly DalamudPluginInterface _pi;
+
+ private string _characterCollectionName = string.Empty;
+ private IList< string > _collections = new List< string >();
+ private string _changedItemCollection = string.Empty;
+ private IReadOnlyDictionary< string, object? > _changedItems = new Dictionary< string, object? >();
+
+ public Collections( DalamudPluginInterface pi )
+ => _pi = pi;
+
+ public void Draw()
+ {
+ using var _ = ImRaii.TreeNode( "Collections" );
+ if( !_ )
+ {
+ return;
+ }
+
+ using var table = ImRaii.Table( string.Empty, 3, ImGuiTableFlags.SizingFixedFit );
+ if( !table )
+ {
+ return;
+ }
+
+ DrawIntro( Ipc.GetCurrentCollectionName.Label, "Current Collection" );
+ ImGui.TextUnformatted( Ipc.GetCurrentCollectionName.Subscriber( _pi ).Invoke() );
+ DrawIntro( Ipc.GetDefaultCollectionName.Label, "Default Collection" );
+ ImGui.TextUnformatted( Ipc.GetDefaultCollectionName.Subscriber( _pi ).Invoke() );
+ DrawIntro( Ipc.GetInterfaceCollectionName.Label, "Interface Collection" );
+ ImGui.TextUnformatted( Ipc.GetInterfaceCollectionName.Subscriber( _pi ).Invoke() );
+ DrawIntro( Ipc.GetCharacterCollectionName.Label, "Character" );
+ ImGui.SetNextItemWidth( 200 * ImGuiHelpers.GlobalScale );
+ ImGui.InputTextWithHint( "##characterCollectionName", "Character Name...", ref _characterCollectionName, 64 );
+ var (c, s) = Ipc.GetCharacterCollectionName.Subscriber( _pi ).Invoke( _characterCollectionName );
+ ImGui.SameLine();
+ ImGui.TextUnformatted( $"{c}, {( s ? "Custom" : "Default" )}" );
+
+ DrawIntro( Ipc.GetCollections.Label, "Collections" );
+ if( ImGui.Button( "Get##Collections" ) )
+ {
+ _collections = Ipc.GetCollections.Subscriber( _pi ).Invoke();
+ ImGui.OpenPopup( "Collections" );
+ }
+
+ DrawIntro( Ipc.GetChangedItems.Label, "Changed Item List" );
+ ImGui.SetNextItemWidth( 200 * ImGuiHelpers.GlobalScale );
+ ImGui.InputTextWithHint( "##changedCollection", "Collection Name...", ref _changedItemCollection, 64 );
+ ImGui.SameLine();
+ if( ImGui.Button( "Get" ) )
+ {
+ _changedItems = Ipc.GetChangedItems.Subscriber( _pi ).Invoke( _changedItemCollection );
+ ImGui.OpenPopup( "Changed Item List" );
+ }
+
+ DrawChangedItemPopup();
+ DrawCollectionPopup();
+ }
+
+ private void DrawChangedItemPopup()
+ {
+ ImGui.SetNextWindowSize( ImGuiHelpers.ScaledVector2( 500, 500 ) );
+ using var p = ImRaii.Popup( "Changed Item List" );
+ if( !p )
+ {
+ return;
+ }
+
foreach( var item in _changedItems )
{
ImGui.TextUnformatted( item.Key );
}
- if( ImGui.Button( "Close", -Vector2.UnitX ) || ImGui.IsWindowFocused() )
+ if( ImGui.Button( "Close", -Vector2.UnitX ) || !ImGui.IsWindowFocused() )
+ {
+ ImGui.CloseCurrentPopup();
+ }
+ }
+
+ private void DrawCollectionPopup()
+ {
+ ImGui.SetNextWindowSize( ImGuiHelpers.ScaledVector2( 500, 500 ) );
+ using var p = ImRaii.Popup( "Collections" );
+ if( !p )
+ {
+ return;
+ }
+
+ foreach( var collection in _collections )
+ {
+ ImGui.TextUnformatted( collection );
+ }
+
+ if( ImGui.Button( "Close", -Vector2.UnitX ) || !ImGui.IsWindowFocused() )
{
ImGui.CloseCurrentPopup();
}
}
}
- private void AddedTooltip( ChangedItemType type, uint id )
+ private class Meta
{
- _lastHovered = $"{type} {id} at {DateTime.UtcNow.ToLocalTime().ToString( CultureInfo.CurrentCulture )}";
- ImGui.TextUnformatted( "IPC Test Successful" );
- }
+ private readonly DalamudPluginInterface _pi;
- private void AddedClick( MouseButton button, ChangedItemType type, uint id )
- {
- _lastClicked = $"{button}-click on {type} {id} at {DateTime.UtcNow.ToLocalTime().ToString( CultureInfo.CurrentCulture )}";
- }
+ private string _characterName = string.Empty;
- private string _characterCollectionName = string.Empty;
- private IList< (string, string) > _mods = new List< (string, string) >();
- private IList< string > _collections = new List< string >();
- private bool _collectionMode = false;
+ public Meta( DalamudPluginInterface pi )
+ => _pi = pi;
- private void DrawData()
- {
- using var _ = ImRaii.TreeNode( "Data IPC" );
- if( !_ )
+ public void Draw()
{
- return;
- }
-
- using var table = ImRaii.Table( string.Empty, 3, ImGuiTableFlags.SizingFixedFit );
- if( !table )
- {
- return;
- }
-
- DrawIntro( PenumbraIpc.LabelProviderCurrentCollectionName, "Current Collection" );
- ImGui.TextUnformatted( _pi.GetIpcSubscriber< string >( PenumbraIpc.LabelProviderCurrentCollectionName ).InvokeFunc() );
- DrawIntro( PenumbraIpc.LabelProviderDefaultCollectionName, "Default Collection" );
- ImGui.TextUnformatted( _pi.GetIpcSubscriber< string >( PenumbraIpc.LabelProviderDefaultCollectionName ).InvokeFunc() );
- DrawIntro( PenumbraIpc.LabelProviderInterfaceCollectionName, "Interface Collection" );
- ImGui.TextUnformatted( _pi.GetIpcSubscriber< string >( PenumbraIpc.LabelProviderInterfaceCollectionName ).InvokeFunc() );
- DrawIntro( PenumbraIpc.LabelProviderCharacterCollectionName, "Character" );
- ImGui.SetNextItemWidth( 200 * ImGuiHelpers.GlobalScale );
- ImGui.InputTextWithHint( "##characterCollectionName", "Character Name...", ref _characterCollectionName, 64 );
- var (c, s) = _pi.GetIpcSubscriber< string, (string, bool) >( PenumbraIpc.LabelProviderCharacterCollectionName )
- .InvokeFunc( _characterCollectionName );
- ImGui.SameLine();
- ImGui.TextUnformatted( $"{c}, {( s ? "Custom" : "Default" )}" );
-
- DrawIntro( PenumbraIpc.LabelProviderGetCollections, "Collections" );
- if( ImGui.Button( "Get##Collections" ) )
- {
- _collectionMode = true;
- _collections = _pi.GetIpcSubscriber< IList< string > >( PenumbraIpc.LabelProviderGetCollections ).InvokeFunc();
- ImGui.OpenPopup( "Ipc Data" );
- }
-
- DrawIntro( PenumbraIpc.LabelProviderGetMods, "Mods" );
- if( ImGui.Button( "Get##Mods" ) )
- {
- _collectionMode = false;
- _mods = _pi.GetIpcSubscriber< IList< (string, string) > >( PenumbraIpc.LabelProviderGetMods ).InvokeFunc();
- ImGui.OpenPopup( "Ipc Data" );
- }
-
- DrawIntro( PenumbraIpc.LabelProviderGetMetaManipulations, "Meta Manipulations" );
- if( ImGui.Button( "Copy to Clipboard" ) )
- {
- var base64 = _pi.GetIpcSubscriber< string, string >( PenumbraIpc.LabelProviderGetMetaManipulations )
- .InvokeFunc( _characterCollectionName );
- ImGui.SetClipboardText( base64 );
- }
-
- ImGui.SetNextWindowSize( ImGuiHelpers.ScaledVector2( 500, 500 ) );
- using var p = ImRaii.Popup( "Ipc Data" );
- if( p )
- {
- if( _collectionMode )
+ using var _ = ImRaii.TreeNode( "Meta" );
+ if( !_ )
{
- foreach( var collection in _collections )
- {
- ImGui.TextUnformatted( collection );
- }
- }
- else
- {
- foreach( var (modDir, modName) in _mods )
- {
- ImGui.TextUnformatted( $"{modDir}: {modName}" );
- }
+ return;
}
- if( ImGui.Button( "Close", -Vector2.UnitX ) || ImGui.IsWindowFocused() )
+ ImGui.InputTextWithHint( "##characterName", "Character Name...", ref _characterName, 64 );
+ using var table = ImRaii.Table( string.Empty, 3, ImGuiTableFlags.SizingFixedFit );
+ if( !table )
+ {
+ return;
+ }
+
+ DrawIntro( Ipc.GetMetaManipulations.Label, "Meta Manipulations" );
+ if( ImGui.Button( "Copy to Clipboard" ) )
+ {
+ var base64 = Ipc.GetMetaManipulations.Subscriber( _pi ).Invoke( _characterName );
+ ImGui.SetClipboardText( base64 );
+ }
+
+ DrawIntro( Ipc.GetPlayerMetaManipulations.Label, "Player Meta Manipulations" );
+ if( ImGui.Button( "Copy to Clipboard##Player" ) )
+ {
+ var base64 = Ipc.GetPlayerMetaManipulations.Subscriber( _pi ).Invoke();
+ ImGui.SetClipboardText( base64 );
+ }
+ }
+ }
+
+ private class Mods
+ {
+ private readonly DalamudPluginInterface _pi;
+
+ private string _modDirectory = string.Empty;
+ private string _modName = string.Empty;
+ private string _pathInput = string.Empty;
+ private PenumbraApiEc _lastReloadEc;
+ private PenumbraApiEc _lastAddEc;
+ private PenumbraApiEc _lastDeleteEc;
+ private PenumbraApiEc _lastSetPathEc;
+ private IList< (string, string) > _mods = new List< (string, string) >();
+
+ public Mods( DalamudPluginInterface pi )
+ => _pi = pi;
+
+ public void Draw()
+ {
+ using var _ = ImRaii.TreeNode( "Mods" );
+ if( !_ )
+ {
+ return;
+ }
+
+ ImGui.InputTextWithHint( "##modDir", "Mod Directory Name...", ref _modDirectory, 100 );
+ ImGui.InputTextWithHint( "##modName", "Mod Name...", ref _modName, 100 );
+ ImGui.InputTextWithHint( "##path", "New Path...", ref _pathInput, 100 );
+ using var table = ImRaii.Table( string.Empty, 3, ImGuiTableFlags.SizingFixedFit );
+ if( !table )
+ {
+ return;
+ }
+
+ DrawIntro( Ipc.GetMods.Label, "Mods" );
+ if( ImGui.Button( "Get##Mods" ) )
+ {
+ _mods = Ipc.GetMods.Subscriber( _pi ).Invoke();
+ ImGui.OpenPopup( "Mods" );
+ }
+
+ DrawIntro( Ipc.ReloadMod.Label, "Reload Mod" );
+ if( ImGui.Button( "Reload" ) )
+ {
+ _lastReloadEc = Ipc.ReloadMod.Subscriber( _pi ).Invoke( _modDirectory, _modName );
+ }
+
+ ImGui.SameLine();
+ ImGui.TextUnformatted( _lastReloadEc.ToString() );
+
+ DrawIntro( Ipc.AddMod.Label, "Add Mod" );
+ if( ImGui.Button( "Add" ) )
+ {
+ _lastAddEc = Ipc.AddMod.Subscriber( _pi ).Invoke( _modDirectory );
+ }
+
+ ImGui.SameLine();
+ ImGui.TextUnformatted( _lastAddEc.ToString() );
+
+ DrawIntro( Ipc.DeleteMod.Label, "Delete Mod" );
+ if( ImGui.Button( "Delete" ) )
+ {
+ _lastDeleteEc = Ipc.DeleteMod.Subscriber( _pi ).Invoke( _modDirectory, _modName );
+ }
+
+ ImGui.SameLine();
+ ImGui.TextUnformatted( _lastDeleteEc.ToString() );
+
+ DrawIntro( Ipc.GetModPath.Label, "Current Path" );
+ var (ec, path, def) = Ipc.GetModPath.Subscriber( _pi ).Invoke( _modDirectory, _modName );
+ ImGui.TextUnformatted( $"{path} ({( def ? "Custom" : "Default" )}) [{ec}]" );
+
+ DrawIntro( Ipc.SetModPath.Label, "Set Path" );
+ if( ImGui.Button( "Set" ) )
+ {
+ _lastSetPathEc = Ipc.SetModPath.Subscriber( _pi ).Invoke( _modDirectory, _modName, _pathInput );
+ }
+
+ ImGui.SameLine();
+ ImGui.TextUnformatted( _lastSetPathEc.ToString() );
+
+
+ DrawModsPopup();
+ }
+
+ private void DrawModsPopup()
+ {
+ ImGui.SetNextWindowSize( ImGuiHelpers.ScaledVector2( 500, 500 ) );
+ using var p = ImRaii.Popup( "Mods" );
+ if( !p )
+ {
+ return;
+ }
+
+ foreach( var (modDir, modName) in _mods )
+ {
+ ImGui.TextUnformatted( $"{modDir}: {modName}" );
+ }
+
+ if( ImGui.Button( "Close", -Vector2.UnitX ) || !ImGui.IsWindowFocused() )
{
ImGui.CloseCurrentPopup();
}
}
}
- private string _settingsModDirectory = string.Empty;
- private string _settingsModName = string.Empty;
- private string _settingsCollection = string.Empty;
- private bool _settingsAllowInheritance = true;
- private bool _settingsInherit = false;
- private bool _settingsEnabled = false;
- private int _settingsPriority = 0;
- private IDictionary< string, (IList< string >, SelectType) >? _availableSettings;
- private IDictionary< string, IList< string > >? _currentSettings = null;
- private PenumbraApiEc _lastSettingsError = PenumbraApiEc.Success;
- private ModSettingChange _lastSettingChangeType;
- private string _lastSettingChangeCollection = string.Empty;
- private string _lastSettingChangeMod = string.Empty;
- private bool _lastSettingChangeInherited;
- private DateTimeOffset _lastSettingChange;
- private PenumbraApiEc _lastReloadEc = PenumbraApiEc.Success;
-
-
- private void UpdateLastModSetting( ModSettingChange type, string collection, string mod, bool inherited )
+ private class ModSettings
{
- _lastSettingChangeType = type;
- _lastSettingChangeCollection = collection;
- _lastSettingChangeMod = mod;
- _lastSettingChangeInherited = inherited;
- _lastSettingChange = DateTimeOffset.Now;
- }
+ private readonly DalamudPluginInterface _pi;
+ public readonly EventSubscriber< ModSettingChange, string, string, bool > SettingChanged;
- private void DrawSetting()
- {
- using var _ = ImRaii.TreeNode( "Settings IPC" );
- if( !_ )
+ private PenumbraApiEc _lastSettingsError = PenumbraApiEc.Success;
+ private ModSettingChange _lastSettingChangeType;
+ private string _lastSettingChangeCollection = string.Empty;
+ private string _lastSettingChangeMod = string.Empty;
+ private bool _lastSettingChangeInherited;
+ private DateTimeOffset _lastSettingChange;
+
+ private string _settingsModDirectory = string.Empty;
+ private string _settingsModName = string.Empty;
+ private string _settingsCollection = string.Empty;
+ private bool _settingsAllowInheritance = true;
+ private bool _settingsInherit = false;
+ private bool _settingsEnabled = false;
+ private int _settingsPriority = 0;
+ private IDictionary< string, (IList< string >, GroupType) >? _availableSettings;
+ private IDictionary< string, IList< string > >? _currentSettings = null;
+
+ public ModSettings( DalamudPluginInterface pi )
{
- return;
+ _pi = pi;
+ SettingChanged = Ipc.ModSettingChanged.Subscriber( pi, UpdateLastModSetting );
}
- ImGui.InputTextWithHint( "##settingsDir", "Mod Directory Name...", ref _settingsModDirectory, 100 );
- ImGui.InputTextWithHint( "##settingsName", "Mod Name...", ref _settingsModName, 100 );
- ImGui.InputTextWithHint( "##settingsCollection", "Collection...", ref _settingsCollection, 100 );
- ImGui.Checkbox( "Allow Inheritance", ref _settingsAllowInheritance );
-
- using var table = ImRaii.Table( string.Empty, 3, ImGuiTableFlags.SizingFixedFit );
- if( !table )
+ public void Draw()
{
- return;
- }
-
- DrawIntro( "Last Error", _lastSettingsError.ToString() );
- DrawIntro( PenumbraIpc.LabelProviderModSettingChanged, "Last Mod Setting Changed" );
- ImGui.TextUnformatted( _lastSettingChangeMod.Length > 0
- ? $"{_lastSettingChangeType} of {_lastSettingChangeMod} in {_lastSettingChangeCollection}{( _lastSettingChangeInherited ? " (Inherited)" : string.Empty )} at {_lastSettingChange}"
- : "None" );
- DrawIntro( PenumbraIpc.LabelProviderGetAvailableModSettings, "Get Available Settings" );
- if( ImGui.Button( "Get##Available" ) )
- {
- _availableSettings = _pi
- .GetIpcSubscriber< string, string, IDictionary< string, (IList< string >, SelectType) >? >(
- PenumbraIpc.LabelProviderGetAvailableModSettings ).InvokeFunc( _settingsModDirectory, _settingsModName );
- _lastSettingsError = _availableSettings == null ? PenumbraApiEc.ModMissing : PenumbraApiEc.Success;
- }
-
- DrawIntro( PenumbraIpc.LabelProviderReloadMod, "Reload Mod" );
- if( ImGui.Button( "Reload" ) )
- {
- _lastReloadEc = _pi.GetIpcSubscriber< string, string, PenumbraApiEc >( PenumbraIpc.LabelProviderReloadMod )
- .InvokeFunc( _settingsModDirectory, _settingsModName );
- }
-
- ImGui.SameLine();
- ImGui.TextUnformatted( _lastReloadEc.ToString() );
-
- DrawIntro( PenumbraIpc.LabelProviderGetCurrentModSettings, "Get Current Settings" );
- if( ImGui.Button( "Get##Current" ) )
- {
- var ret = _pi
- .GetIpcSubscriber< string, string, string, bool, (PenumbraApiEc, (bool, int, IDictionary< string, IList< string > >, bool)?) >(
- PenumbraIpc.LabelProviderGetCurrentModSettings ).InvokeFunc( _settingsCollection, _settingsModDirectory, _settingsModName,
- _settingsAllowInheritance );
- _lastSettingsError = ret.Item1;
- if( ret.Item1 == PenumbraApiEc.Success )
+ using var _ = ImRaii.TreeNode( "Mod Settings" );
+ if( !_ )
{
- _settingsEnabled = ret.Item2?.Item1 ?? false;
- _settingsInherit = ret.Item2?.Item4 ?? false;
- _settingsPriority = ret.Item2?.Item2 ?? 0;
- _currentSettings = ret.Item2?.Item3;
+ return;
}
- else
+
+ ImGui.InputTextWithHint( "##settingsDir", "Mod Directory Name...", ref _settingsModDirectory, 100 );
+ ImGui.InputTextWithHint( "##settingsName", "Mod Name...", ref _settingsModName, 100 );
+ ImGui.InputTextWithHint( "##settingsCollection", "Collection...", ref _settingsCollection, 100 );
+ ImGui.Checkbox( "Allow Inheritance", ref _settingsAllowInheritance );
+
+ using var table = ImRaii.Table( string.Empty, 3, ImGuiTableFlags.SizingFixedFit );
+ if( !table )
{
- _currentSettings = null;
+ return;
}
- }
- DrawIntro( PenumbraIpc.LabelProviderTryInheritMod, "Inherit Mod" );
- ImGui.Checkbox( "##inherit", ref _settingsInherit );
- ImGui.SameLine();
- if( ImGui.Button( "Set##Inherit" ) )
- {
- _lastSettingsError = _pi.GetIpcSubscriber< string, string, string, bool, PenumbraApiEc >( PenumbraIpc.LabelProviderTryInheritMod )
- .InvokeFunc( _settingsCollection, _settingsModDirectory, _settingsModName, _settingsInherit );
- }
+ DrawIntro( "Last Error", _lastSettingsError.ToString() );
+ DrawIntro( Ipc.ModSettingChanged.Label, "Last Mod Setting Changed" );
+ ImGui.TextUnformatted( _lastSettingChangeMod.Length > 0
+ ? $"{_lastSettingChangeType} of {_lastSettingChangeMod} in {_lastSettingChangeCollection}{( _lastSettingChangeInherited ? " (Inherited)" : string.Empty )} at {_lastSettingChange}"
+ : "None" );
+ DrawIntro( Ipc.GetAvailableModSettings.Label, "Get Available Settings" );
+ if( ImGui.Button( "Get##Available" ) )
+ {
+ _availableSettings = Ipc.GetAvailableModSettings.Subscriber( _pi ).Invoke( _settingsModDirectory, _settingsModName );
+ _lastSettingsError = _availableSettings == null ? PenumbraApiEc.ModMissing : PenumbraApiEc.Success;
+ }
- DrawIntro( PenumbraIpc.LabelProviderTrySetMod, "Set Enabled" );
- ImGui.Checkbox( "##enabled", ref _settingsEnabled );
- ImGui.SameLine();
- if( ImGui.Button( "Set##Enabled" ) )
- {
- _lastSettingsError = _pi.GetIpcSubscriber< string, string, string, bool, PenumbraApiEc >( PenumbraIpc.LabelProviderTrySetMod )
- .InvokeFunc( _settingsCollection, _settingsModDirectory, _settingsModName, _settingsEnabled );
- }
- DrawIntro( PenumbraIpc.LabelProviderTrySetModPriority, "Set Priority" );
- ImGui.SetNextItemWidth( 200 * ImGuiHelpers.GlobalScale );
- ImGui.DragInt( "##Priority", ref _settingsPriority );
- ImGui.SameLine();
- if( ImGui.Button( "Set##Priority" ) )
- {
- _lastSettingsError = _pi
- .GetIpcSubscriber< string, string, string, int, PenumbraApiEc >( PenumbraIpc.LabelProviderTrySetModPriority )
- .InvokeFunc( _settingsCollection, _settingsModDirectory, _settingsModName, _settingsPriority );
- }
+ DrawIntro( Ipc.GetCurrentModSettings.Label, "Get Current Settings" );
+ if( ImGui.Button( "Get##Current" ) )
+ {
+ var ret = Ipc.GetCurrentModSettings.Subscriber( _pi ).Invoke( _settingsCollection, _settingsModDirectory, _settingsModName, _settingsAllowInheritance );
+ _lastSettingsError = ret.Item1;
+ if( ret.Item1 == PenumbraApiEc.Success )
+ {
+ _settingsEnabled = ret.Item2?.Item1 ?? false;
+ _settingsInherit = ret.Item2?.Item4 ?? false;
+ _settingsPriority = ret.Item2?.Item2 ?? 0;
+ _currentSettings = ret.Item2?.Item3;
+ }
+ else
+ {
+ _currentSettings = null;
+ }
+ }
+
+ DrawIntro( Ipc.TryInheritMod.Label, "Inherit Mod" );
+ ImGui.Checkbox( "##inherit", ref _settingsInherit );
+ ImGui.SameLine();
+ if( ImGui.Button( "Set##Inherit" ) )
+ {
+ _lastSettingsError = Ipc.TryInheritMod.Subscriber( _pi ).Invoke( _settingsCollection, _settingsModDirectory, _settingsModName, _settingsInherit );
+ }
+
+ DrawIntro( Ipc.TrySetMod.Label, "Set Enabled" );
+ ImGui.Checkbox( "##enabled", ref _settingsEnabled );
+ ImGui.SameLine();
+ if( ImGui.Button( "Set##Enabled" ) )
+ {
+ _lastSettingsError = Ipc.TrySetMod.Subscriber( _pi ).Invoke( _settingsCollection, _settingsModDirectory, _settingsModName, _settingsEnabled );
+ }
+
+ DrawIntro( Ipc.TrySetModPriority.Label, "Set Priority" );
+ ImGui.SetNextItemWidth( 200 * ImGuiHelpers.GlobalScale );
+ ImGui.DragInt( "##Priority", ref _settingsPriority );
+ ImGui.SameLine();
+ if( ImGui.Button( "Set##Priority" ) )
+ {
+ _lastSettingsError = Ipc.TrySetModPriority.Subscriber( _pi ).Invoke( _settingsCollection, _settingsModDirectory, _settingsModName, _settingsPriority );
+ }
+
+ DrawIntro( Ipc.TrySetModSetting.Label, "Set Setting(s)" );
+ if( _availableSettings == null )
+ {
+ return;
+ }
- DrawIntro( PenumbraIpc.LabelProviderTrySetModSetting, "Set Setting(s)" );
- if( _availableSettings != null )
- {
foreach( var (group, (list, type)) in _availableSettings )
{
using var id = ImRaii.PushId( group );
@@ -802,19 +1026,15 @@ public class IpcTester : IDisposable
ImGui.SameLine();
if( ImGui.Button( "Set##setting" ) )
{
- if( type == SelectType.Single )
+ if( type == GroupType.Single )
{
- _lastSettingsError = _pi
- .GetIpcSubscriber< string, string, string, string, string,
- PenumbraApiEc >( PenumbraIpc.LabelProviderTrySetModSetting ).InvokeFunc( _settingsCollection,
- _settingsModDirectory, _settingsModName, group, current.Count > 0 ? current[ 0 ] : string.Empty );
+ _lastSettingsError = Ipc.TrySetModSetting.Subscriber( _pi ).Invoke( _settingsCollection,
+ _settingsModDirectory, _settingsModName, group, current.Count > 0 ? current[ 0 ] : string.Empty );
}
else
{
- _lastSettingsError = _pi
- .GetIpcSubscriber< string, string, string, string, IReadOnlyList< string >,
- PenumbraApiEc >( PenumbraIpc.LabelProviderTrySetModSettings ).InvokeFunc( _settingsCollection,
- _settingsModDirectory, _settingsModName, group, current.ToArray() );
+ _lastSettingsError = Ipc.TrySetModSettings.Subscriber( _pi ).Invoke( _settingsCollection,
+ _settingsModDirectory, _settingsModName, group, current.ToArray() );
}
}
@@ -822,176 +1042,183 @@ public class IpcTester : IDisposable
ImGui.TextUnformatted( group );
}
}
+
+ private void UpdateLastModSetting( ModSettingChange type, string collection, string mod, bool inherited )
+ {
+ _lastSettingChangeType = type;
+ _lastSettingChangeCollection = collection;
+ _lastSettingChangeMod = mod;
+ _lastSettingChangeInherited = inherited;
+ _lastSettingChange = DateTimeOffset.Now;
+ }
}
- private string _tempCollectionName = string.Empty;
- private string _tempCharacterName = string.Empty;
- private bool _forceOverwrite = true;
- private string _tempModName = string.Empty;
- private PenumbraApiEc _lastTempError = PenumbraApiEc.Success;
- private string _lastCreatedCollectionName = string.Empty;
- private string _tempGamePath = "test/game/path.mtrl";
- private string _tempFilePath = "test/success.mtrl";
- private string _tempManipulation = string.Empty;
-
-
- private void DrawTemp()
+ private class Temporary
{
- using var _ = ImRaii.TreeNode( "Temp IPC" );
- if( !_ )
- {
- return;
- }
+ public readonly DalamudPluginInterface _pi;
- ImGui.InputTextWithHint( "##tempCollection", "Collection Name...", ref _tempCollectionName, 128 );
- ImGui.InputTextWithHint( "##tempCollectionChar", "Collection Character...", ref _tempCharacterName, 32 );
- ImGui.InputTextWithHint( "##tempMod", "Temporary Mod Name...", ref _tempModName, 32 );
- ImGui.InputTextWithHint( "##tempGame", "Game Path...", ref _tempGamePath, 256 );
- ImGui.InputTextWithHint( "##tempFile", "File Path...", ref _tempFilePath, 256 );
- ImGui.InputTextWithHint( "##tempManip", "Manipulation Base64 String...", ref _tempManipulation, 256 );
- ImGui.Checkbox( "Force Character Collection Overwrite", ref _forceOverwrite );
+ public Temporary( DalamudPluginInterface pi )
+ => _pi = pi;
- using var table = ImRaii.Table( string.Empty, 3, ImGuiTableFlags.SizingFixedFit );
- if( !table )
- {
- return;
- }
+ public string LastCreatedCollectionName = string.Empty;
- DrawIntro( "Last Error", _lastTempError.ToString() );
- DrawIntro( "Last Created Collection", _lastCreatedCollectionName );
- DrawIntro( PenumbraIpc.LabelProviderCreateTemporaryCollection, "Create Temporary Collection" );
- if( ImGui.Button( "Create##Collection" ) )
- {
- ( _lastTempError, _lastCreatedCollectionName ) =
- _pi.GetIpcSubscriber< string, string, bool, (PenumbraApiEc, string) >( PenumbraIpc.LabelProviderCreateTemporaryCollection )
- .InvokeFunc( _tempCollectionName, _tempCharacterName, _forceOverwrite );
- }
+ private string _tempCollectionName = string.Empty;
+ private string _tempCharacterName = string.Empty;
+ private string _tempModName = string.Empty;
+ private string _tempGamePath = "test/game/path.mtrl";
+ private string _tempFilePath = "test/success.mtrl";
+ private string _tempManipulation = string.Empty;
+ private PenumbraApiEc _lastTempError;
+ private bool _forceOverwrite;
- DrawIntro( PenumbraIpc.LabelProviderRemoveTemporaryCollection, "Remove Temporary Collection from Character" );
- if( ImGui.Button( "Delete##Collection" ) )
+ public void Draw()
{
- _lastTempError = _pi.GetIpcSubscriber< string, PenumbraApiEc >( PenumbraIpc.LabelProviderRemoveTemporaryCollection )
- .InvokeFunc( _tempCharacterName );
- }
+ using var _ = ImRaii.TreeNode( "Temporary" );
+ if( !_ )
+ {
+ return;
+ }
- DrawIntro( PenumbraIpc.LabelProviderAddTemporaryMod, "Add Temporary Mod to specific Collection" );
- if( ImGui.Button( "Add##Mod" ) )
- {
- _lastTempError = _pi
- .GetIpcSubscriber< string, string, Dictionary< string, string >, string, int, PenumbraApiEc >(
- PenumbraIpc.LabelProviderAddTemporaryMod )
- .InvokeFunc( _tempModName, _tempCollectionName,
+ ImGui.InputTextWithHint( "##tempCollection", "Collection Name...", ref _tempCollectionName, 128 );
+ ImGui.InputTextWithHint( "##tempCollectionChar", "Collection Character...", ref _tempCharacterName, 32 );
+ ImGui.InputTextWithHint( "##tempMod", "Temporary Mod Name...", ref _tempModName, 32 );
+ ImGui.InputTextWithHint( "##tempGame", "Game Path...", ref _tempGamePath, 256 );
+ ImGui.InputTextWithHint( "##tempFile", "File Path...", ref _tempFilePath, 256 );
+ ImGui.InputTextWithHint( "##tempManip", "Manipulation Base64 String...", ref _tempManipulation, 256 );
+ ImGui.Checkbox( "Force Character Collection Overwrite", ref _forceOverwrite );
+
+
+ using var table = ImRaii.Table( string.Empty, 3, ImGuiTableFlags.SizingFixedFit );
+ if( !table )
+ {
+ return;
+ }
+
+ DrawIntro( "Last Error", _lastTempError.ToString() );
+ DrawIntro( "Last Created Collection", LastCreatedCollectionName );
+ DrawIntro( Ipc.CreateTemporaryCollection.Label, "Create Temporary Collection" );
+ if( ImGui.Button( "Create##Collection" ) )
+ {
+ ( _lastTempError, LastCreatedCollectionName ) = Ipc.CreateTemporaryCollection.Subscriber( _pi ).Invoke( _tempCollectionName, _tempCharacterName, _forceOverwrite );
+ }
+
+ DrawIntro( Ipc.RemoveTemporaryCollection.Label, "Remove Temporary Collection from Character" );
+ if( ImGui.Button( "Delete##Collection" ) )
+ {
+ _lastTempError = Ipc.RemoveTemporaryCollection.Subscriber( _pi ).Invoke( _tempCharacterName );
+ }
+
+ DrawIntro( Ipc.AddTemporaryMod.Label, "Add Temporary Mod to specific Collection" );
+ if( ImGui.Button( "Add##Mod" ) )
+ {
+ _lastTempError = Ipc.AddTemporaryMod.Subscriber( _pi ).Invoke( _tempModName, _tempCollectionName,
new Dictionary< string, string > { { _tempGamePath, _tempFilePath } },
_tempManipulation.Length > 0 ? _tempManipulation : string.Empty, int.MaxValue );
- }
+ }
- DrawIntro( PenumbraIpc.LabelProviderAddTemporaryModAll, "Add Temporary Mod to all Collections" );
- if( ImGui.Button( "Add##All" ) )
- {
- _lastTempError = _pi
- .GetIpcSubscriber< string, Dictionary< string, string >, string, int, PenumbraApiEc >(
- PenumbraIpc.LabelProviderAddTemporaryModAll )
- .InvokeFunc( _tempModName, new Dictionary< string, string > { { _tempGamePath, _tempFilePath } },
+ DrawIntro( Ipc.AddTemporaryModAll.Label, "Add Temporary Mod to all Collections" );
+ if( ImGui.Button( "Add##All" ) )
+ {
+ _lastTempError = Ipc.AddTemporaryModAll.Subscriber( _pi ).Invoke( _tempModName, new Dictionary< string, string > { { _tempGamePath, _tempFilePath } },
_tempManipulation.Length > 0 ? _tempManipulation : string.Empty, int.MaxValue );
- }
+ }
- DrawIntro( PenumbraIpc.LabelProviderRemoveTemporaryMod, "Remove Temporary Mod from specific Collection" );
- if( ImGui.Button( "Remove##Mod" ) )
- {
- _lastTempError = _pi.GetIpcSubscriber< string, string, int, PenumbraApiEc >( PenumbraIpc.LabelProviderRemoveTemporaryMod )
- .InvokeFunc( _tempModName, _tempCollectionName, int.MaxValue );
- }
-
- DrawIntro( PenumbraIpc.LabelProviderRemoveTemporaryModAll, "Remove Temporary Mod from all Collections" );
- if( ImGui.Button( "Remove##ModAll" ) )
- {
- _lastTempError = _pi.GetIpcSubscriber< string, int, PenumbraApiEc >( PenumbraIpc.LabelProviderRemoveTemporaryModAll )
- .InvokeFunc( _tempModName, int.MaxValue );
- }
- }
-
- private void DrawTempCollections()
- {
- using var collTree = ImRaii.TreeNode( "Collections" );
- if( !collTree )
- {
- return;
- }
-
- using var table = ImRaii.Table( "##collTree", 5 );
- if( !table )
- {
- return;
- }
-
- foreach( var (character, collection) in Penumbra.TempMods.Collections )
- {
- ImGui.TableNextColumn();
- ImGui.TextUnformatted( character );
- ImGui.TableNextColumn();
- ImGui.TextUnformatted( collection.Name );
- ImGui.TableNextColumn();
- ImGui.TextUnformatted( collection.ResolvedFiles.Count.ToString() );
- ImGui.TableNextColumn();
- ImGui.TextUnformatted( collection.MetaCache?.Count.ToString() ?? "0" );
- ImGui.TableNextColumn();
- if( ImGui.Button( $"Save##{character}" ) )
+ DrawIntro( Ipc.RemoveTemporaryMod.Label, "Remove Temporary Mod from specific Collection" );
+ if( ImGui.Button( "Remove##Mod" ) )
{
- Mod.TemporaryMod.SaveTempCollection( collection, character );
+ _lastTempError = Ipc.RemoveTemporaryMod.Subscriber( _pi ).Invoke( _tempModName, _tempCollectionName, int.MaxValue );
+ }
+
+ DrawIntro( Ipc.RemoveTemporaryModAll.Label, "Remove Temporary Mod from all Collections" );
+ if( ImGui.Button( "Remove##ModAll" ) )
+ {
+ _lastTempError = Ipc.RemoveTemporaryModAll.Subscriber( _pi ).Invoke( _tempModName, int.MaxValue );
}
}
- }
- private void DrawTempMods()
- {
- using var modTree = ImRaii.TreeNode( "Mods" );
- if( !modTree )
+ public void DrawCollections()
{
- return;
- }
+ using var collTree = ImRaii.TreeNode( "Collections" );
+ if( !collTree )
+ {
+ return;
+ }
- using var table = ImRaii.Table( "##modTree", 5 );
+ using var table = ImRaii.Table( "##collTree", 5 );
+ if( !table )
+ {
+ return;
+ }
- void PrintList( string collectionName, IReadOnlyList< Mod.TemporaryMod > list )
- {
- foreach( var mod in list )
+ foreach( var (character, collection) in Penumbra.TempMods.Collections )
{
ImGui.TableNextColumn();
- ImGui.TextUnformatted( mod.Name );
+ ImGui.TextUnformatted( character );
ImGui.TableNextColumn();
- ImGui.TextUnformatted( mod.Priority.ToString() );
+ ImGui.TextUnformatted( collection.Name );
ImGui.TableNextColumn();
- ImGui.TextUnformatted( collectionName );
+ ImGui.TextUnformatted( collection.ResolvedFiles.Count.ToString() );
ImGui.TableNextColumn();
- ImGui.TextUnformatted( mod.Default.Files.Count.ToString() );
- if( ImGui.IsItemHovered() )
+ ImGui.TextUnformatted( collection.MetaCache?.Count.ToString() ?? "0" );
+ ImGui.TableNextColumn();
+ if( ImGui.Button( $"Save##{character}" ) )
{
- using var tt = ImRaii.Tooltip();
- foreach( var (path, file) in mod.Default.Files )
- {
- ImGui.TextUnformatted( $"{path} -> {file}" );
- }
- }
-
- ImGui.TableNextColumn();
- ImGui.TextUnformatted( mod.TotalManipulations.ToString() );
- if( ImGui.IsItemHovered() )
- {
- using var tt = ImRaii.Tooltip();
- foreach( var manip in mod.Default.Manipulations )
- {
- ImGui.TextUnformatted( manip.ToString() );
- }
+ Mod.TemporaryMod.SaveTempCollection( collection, character );
}
}
}
- if( table )
+ public void DrawMods()
{
- PrintList( "All", Penumbra.TempMods.ModsForAllCollections );
- foreach( var (collection, list) in Penumbra.TempMods.Mods )
+ using var modTree = ImRaii.TreeNode( "Mods" );
+ if( !modTree )
{
- PrintList( collection.Name, list );
+ return;
+ }
+
+ using var table = ImRaii.Table( "##modTree", 5 );
+
+ void PrintList( string collectionName, IReadOnlyList< Mod.TemporaryMod > list )
+ {
+ foreach( var mod in list )
+ {
+ ImGui.TableNextColumn();
+ ImGui.TextUnformatted( mod.Name );
+ ImGui.TableNextColumn();
+ ImGui.TextUnformatted( mod.Priority.ToString() );
+ ImGui.TableNextColumn();
+ ImGui.TextUnformatted( collectionName );
+ ImGui.TableNextColumn();
+ ImGui.TextUnformatted( mod.Default.Files.Count.ToString() );
+ if( ImGui.IsItemHovered() )
+ {
+ using var tt = ImRaii.Tooltip();
+ foreach( var (path, file) in mod.Default.Files )
+ {
+ ImGui.TextUnformatted( $"{path} -> {file}" );
+ }
+ }
+
+ ImGui.TableNextColumn();
+ ImGui.TextUnformatted( mod.TotalManipulations.ToString() );
+ if( ImGui.IsItemHovered() )
+ {
+ using var tt = ImRaii.Tooltip();
+ foreach( var manip in mod.Default.Manipulations )
+ {
+ ImGui.TextUnformatted( manip.ToString() );
+ }
+ }
+ }
+ }
+
+ if( table )
+ {
+ PrintList( "All", Penumbra.TempMods.ModsForAllCollections );
+ foreach( var (collection, list) in Penumbra.TempMods.Mods )
+ {
+ PrintList( collection.Name, list );
+ }
}
}
}
diff --git a/Penumbra/Api/PenumbraApi.cs b/Penumbra/Api/PenumbraApi.cs
index fad36b1c..2da860f2 100644
--- a/Penumbra/Api/PenumbraApi.cs
+++ b/Penumbra/Api/PenumbraApi.cs
@@ -4,7 +4,6 @@ using Newtonsoft.Json;
using OtterGui;
using Penumbra.Collections;
using Penumbra.GameData.ByteString;
-using Penumbra.GameData.Enums;
using Penumbra.Interop.Resolver;
using Penumbra.Interop.Structs;
using Penumbra.Meta.Manipulations;
@@ -15,6 +14,7 @@ using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
+using Penumbra.Api.Enums;
namespace Penumbra.Api;
@@ -272,7 +272,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
return Penumbra.ModManager.Select( m => ( m.ModPath.Name, m.Name.Text ) ).ToArray();
}
- public IDictionary< string, (IList< string >, SelectType) >? GetAvailableModSettings( string modDirectory, string modName )
+ public IDictionary< string, (IList< string >, GroupType) >? GetAvailableModSettings( string modDirectory, string modName )
{
CheckInitialized();
return Penumbra.ModManager.TryGetMod( modDirectory, modName, out var mod )
@@ -330,6 +330,56 @@ public class PenumbraApi : IDisposable, IPenumbraApi
return PenumbraApiEc.Success;
}
+ public PenumbraApiEc DeleteMod( string modDirectory, string modName )
+ {
+ CheckInitialized();
+ if( !Penumbra.ModManager.TryGetMod( modDirectory, modName, out var mod ) )
+ return PenumbraApiEc.NothingChanged;
+
+ Penumbra.ModManager.DeleteMod( mod.Index );
+ return PenumbraApiEc.Success;
+ }
+
+
+ public (PenumbraApiEc, string, bool) GetModPath( string modDirectory, string modName )
+ {
+ CheckInitialized();
+ if( !Penumbra.ModManager.TryGetMod( modDirectory, modName, out var mod )
+ || !_penumbra!.ModFileSystem.FindLeaf( mod, out var leaf ) )
+ {
+ return ( PenumbraApiEc.ModMissing, string.Empty, false );
+ }
+
+ var fullPath = leaf.FullName();
+
+ return ( PenumbraApiEc.Success, fullPath, !ModFileSystem.ModHasDefaultPath( mod, fullPath ) );
+ }
+
+ public PenumbraApiEc SetModPath( string modDirectory, string modName, string newPath )
+ {
+ CheckInitialized();
+ if( newPath.Length == 0 )
+ {
+ return PenumbraApiEc.InvalidArgument;
+ }
+
+ if( !Penumbra.ModManager.TryGetMod( modDirectory, modName, out var mod )
+ || !_penumbra!.ModFileSystem.FindLeaf( mod, out var leaf ) )
+ {
+ return PenumbraApiEc.ModMissing;
+ }
+
+ try
+ {
+ _penumbra.ModFileSystem.RenameAndMove( leaf, newPath );
+ return PenumbraApiEc.Success;
+ }
+ catch
+ {
+ return PenumbraApiEc.PathRenameFailed;
+ }
+ }
+
public PenumbraApiEc TryInheritMod( string collectionName, string modDirectory, string modName, bool inherit )
{
CheckInitialized();
@@ -405,7 +455,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
return PenumbraApiEc.OptionMissing;
}
- var setting = mod.Groups[ groupIdx ].Type == SelectType.Multi ? 1u << optionIdx : ( uint )optionIdx;
+ var setting = mod.Groups[ groupIdx ].Type == GroupType.Multi ? 1u << optionIdx : ( uint )optionIdx;
return collection.SetModSetting( mod.Index, groupIdx, setting ) ? PenumbraApiEc.Success : PenumbraApiEc.NothingChanged;
}
@@ -433,7 +483,7 @@ public class PenumbraApi : IDisposable, IPenumbraApi
var group = mod.Groups[ groupIdx ];
uint setting = 0;
- if( group.Type == SelectType.Single )
+ if( group.Type == GroupType.Single )
{
var optionIdx = optionNames.Count == 0 ? -1 : group.IndexOf( o => o.Name == optionNames[ ^1 ] );
if( optionIdx < 0 )
diff --git a/Penumbra/Api/PenumbraIpc.cs b/Penumbra/Api/PenumbraIpc.cs
deleted file mode 100644
index ab9496c5..00000000
--- a/Penumbra/Api/PenumbraIpc.cs
+++ /dev/null
@@ -1,878 +0,0 @@
-using Dalamud.Game.ClientState.Objects.Types;
-using Dalamud.Plugin;
-using Dalamud.Plugin.Ipc;
-using Penumbra.Collections;
-using Penumbra.GameData.Enums;
-using System;
-using System.Collections.Generic;
-
-namespace Penumbra.Api;
-
-public partial class PenumbraIpc : IDisposable
-{
- internal readonly IPenumbraApi Api;
- internal readonly IpcTester Tester;
-
- public PenumbraIpc( DalamudPluginInterface pi, IPenumbraApi api )
- {
- Api = api;
- Tester = new IpcTester( pi, this );
- InitializeGeneralProviders( pi );
- InitializeResolveProviders( pi );
- InitializeRedrawProviders( pi );
- InitializeChangedItemProviders( pi );
- InitializeDataProviders( pi );
- InitializeSettingProviders( pi );
- InitializeTempProviders( pi );
- ProviderInitialized?.SendMessage();
- InvokeModDirectoryChanged( Penumbra.ModManager.BasePath.FullName, Penumbra.ModManager.Valid );
- }
-
- public void Dispose()
- {
- DisposeDataProviders();
- DisposeChangedItemProviders();
- DisposeRedrawProviders();
- DisposeResolveProviders();
- DisposeGeneralProviders();
- DisposeSettingProviders();
- DisposeTempProviders();
- ProviderDisposed?.SendMessage();
- Tester.Dispose();
- }
-}
-
-public partial class PenumbraIpc
-{
- public const string LabelProviderInitialized = "Penumbra.Initialized";
- public const string LabelProviderDisposed = "Penumbra.Disposed";
- public const string LabelProviderApiVersion = "Penumbra.ApiVersion";
- public const string LabelProviderApiVersions = "Penumbra.ApiVersions";
- public const string LabelProviderGetModDirectory = "Penumbra.GetModDirectory";
- public const string LabelProviderModDirectoryChanged = "Penumbra.ModDirectoryChanged";
- public const string LabelProviderGetConfiguration = "Penumbra.GetConfiguration";
- public const string LabelProviderPreSettingsDraw = "Penumbra.PreSettingsDraw";
- public const string LabelProviderPostSettingsDraw = "Penumbra.PostSettingsDraw";
-
- internal ICallGateProvider< object? >? ProviderInitialized;
- internal ICallGateProvider< object? >? ProviderDisposed;
- internal ICallGateProvider< int >? ProviderApiVersion;
- internal ICallGateProvider< (int Breaking, int Features) >? ProviderApiVersions;
- internal ICallGateProvider< string >? ProviderGetModDirectory;
- internal ICallGateProvider< string, bool, object? >? ProviderModDirectoryChanged;
- internal ICallGateProvider< string >? ProviderGetConfiguration;
- internal ICallGateProvider< string, object? >? ProviderPreSettingsDraw;
- internal ICallGateProvider< string, object? >? ProviderPostSettingsDraw;
-
- private void InitializeGeneralProviders( DalamudPluginInterface pi )
- {
- try
- {
- ProviderInitialized = pi.GetIpcProvider< object? >( LabelProviderInitialized );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderInitialized}:\n{e}" );
- }
-
- try
- {
- ProviderDisposed = pi.GetIpcProvider< object? >( LabelProviderDisposed );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderDisposed}:\n{e}" );
- }
-
- try
- {
- ProviderApiVersion = pi.GetIpcProvider< int >( LabelProviderApiVersion );
- ProviderApiVersion.RegisterFunc( () =>
- {
- Penumbra.Log.Warning( $"{LabelProviderApiVersion} is outdated. Please use {LabelProviderApiVersions} instead." );
- return Api.ApiVersion.Breaking;
- } );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderApiVersion}:\n{e}" );
- }
-
- try
- {
- ProviderApiVersions = pi.GetIpcProvider< ( int, int ) >( LabelProviderApiVersions );
- ProviderApiVersions.RegisterFunc( () => Api.ApiVersion );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderApiVersions}:\n{e}" );
- }
-
- try
- {
- ProviderGetModDirectory = pi.GetIpcProvider< string >( LabelProviderGetModDirectory );
- ProviderGetModDirectory.RegisterFunc( Api.GetModDirectory );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderGetModDirectory}:\n{e}" );
- }
-
- try
- {
- ProviderModDirectoryChanged = pi.GetIpcProvider< string, bool, object? >( LabelProviderModDirectoryChanged );
- Api.ModDirectoryChanged += InvokeModDirectoryChanged;
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderModDirectoryChanged}:\n{e}" );
- }
-
- try
- {
- ProviderGetConfiguration = pi.GetIpcProvider< string >( LabelProviderGetConfiguration );
- ProviderGetConfiguration.RegisterFunc( Api.GetConfiguration );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderGetConfiguration}:\n{e}" );
- }
-
- try
- {
- ProviderPreSettingsDraw = pi.GetIpcProvider< string, object? >( LabelProviderPreSettingsDraw );
- Api.PreSettingsPanelDraw += InvokeSettingsPreDraw;
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderPreSettingsDraw}:\n{e}" );
- }
-
- try
- {
- ProviderPostSettingsDraw = pi.GetIpcProvider< string, object? >( LabelProviderPostSettingsDraw );
- Api.PostSettingsPanelDraw += InvokeSettingsPostDraw;
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderPostSettingsDraw}:\n{e}" );
- }
- }
-
- private void DisposeGeneralProviders()
- {
- ProviderGetConfiguration?.UnregisterFunc();
- ProviderGetModDirectory?.UnregisterFunc();
- ProviderApiVersion?.UnregisterFunc();
- ProviderApiVersions?.UnregisterFunc();
- Api.PreSettingsPanelDraw -= InvokeSettingsPreDraw;
- Api.PostSettingsPanelDraw -= InvokeSettingsPostDraw;
- Api.ModDirectoryChanged -= InvokeModDirectoryChanged;
- }
-
- private void InvokeSettingsPreDraw( string modDirectory )
- => ProviderPreSettingsDraw!.SendMessage( modDirectory );
-
- private void InvokeSettingsPostDraw( string modDirectory )
- => ProviderPostSettingsDraw!.SendMessage( modDirectory );
-
- private void InvokeModDirectoryChanged( string modDirectory, bool valid )
- => ProviderModDirectoryChanged?.SendMessage( modDirectory, valid );
-}
-
-public partial class PenumbraIpc
-{
- public const string LabelProviderRedrawObject = "Penumbra.RedrawObject";
- public const string LabelProviderRedrawName = "Penumbra.RedrawObjectByName";
- public const string LabelProviderRedrawIndex = "Penumbra.RedrawObjectByIndex";
- public const string LabelProviderRedrawAll = "Penumbra.RedrawAll";
- public const string LabelProviderGameObjectRedrawn = "Penumbra.GameObjectRedrawn";
-
- internal ICallGateProvider< string, int, object? >? ProviderRedrawName;
- internal ICallGateProvider< GameObject, int, object? >? ProviderRedrawObject;
- internal ICallGateProvider< int, int, object? >? ProviderRedrawIndex;
- internal ICallGateProvider< int, object? >? ProviderRedrawAll;
- internal ICallGateProvider< IntPtr, int, object? >? ProviderGameObjectRedrawn;
-
- private static RedrawType CheckRedrawType( int value )
- {
- var type = ( RedrawType )value;
- if( Enum.IsDefined( type ) )
- {
- return type;
- }
-
- throw new Exception( "The integer provided for a Redraw Function was not a valid RedrawType." );
- }
-
- private void InitializeRedrawProviders( DalamudPluginInterface pi )
- {
- try
- {
- ProviderRedrawName = pi.GetIpcProvider< string, int, object? >( LabelProviderRedrawName );
- ProviderRedrawName.RegisterAction( ( s, i ) => Api.RedrawObject( s, CheckRedrawType( i ) ) );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderRedrawName}:\n{e}" );
- }
-
- try
- {
- ProviderRedrawObject = pi.GetIpcProvider< GameObject, int, object? >( LabelProviderRedrawObject );
- ProviderRedrawObject.RegisterAction( ( s, i ) => Api.RedrawObject( s, CheckRedrawType( i ) ) );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderRedrawObject}:\n{e}" );
- }
-
- try
- {
- ProviderRedrawIndex = pi.GetIpcProvider< int, int, object? >( LabelProviderRedrawIndex );
- ProviderRedrawIndex.RegisterAction( ( idx, i ) => Api.RedrawObject( idx, CheckRedrawType( i ) ) );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderRedrawName}:\n{e}" );
- }
-
- try
- {
- ProviderRedrawAll = pi.GetIpcProvider< int, object? >( LabelProviderRedrawAll );
- ProviderRedrawAll.RegisterAction( i => Api.RedrawAll( CheckRedrawType( i ) ) );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderRedrawAll}:\n{e}" );
- }
-
- try
- {
- ProviderGameObjectRedrawn = pi.GetIpcProvider< IntPtr, int, object? >( LabelProviderGameObjectRedrawn );
- Api.GameObjectRedrawn += OnGameObjectRedrawn;
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderGameObjectRedrawn}:\n{e}" );
- }
- }
-
- private void OnGameObjectRedrawn( IntPtr objectAddress, int objectTableIndex )
- => ProviderGameObjectRedrawn?.SendMessage( objectAddress, objectTableIndex );
-
- private void DisposeRedrawProviders()
- {
- ProviderRedrawName?.UnregisterAction();
- ProviderRedrawObject?.UnregisterAction();
- ProviderRedrawIndex?.UnregisterAction();
- ProviderRedrawAll?.UnregisterAction();
- Api.GameObjectRedrawn -= OnGameObjectRedrawn;
- }
-}
-
-public partial class PenumbraIpc
-{
- public const string LabelProviderResolveDefault = "Penumbra.ResolveDefaultPath";
- public const string LabelProviderResolveInterface = "Penumbra.ResolveInterfacePath";
- 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;
- internal ICallGateProvider< string, string >? ProviderResolveInterface;
- internal ICallGateProvider< string, string, string >? ProviderResolveCharacter;
- internal ICallGateProvider< string, string >? ProviderResolvePlayer;
- internal ICallGateProvider< IntPtr, (IntPtr, string) >? ProviderGetDrawObjectInfo;
- internal ICallGateProvider< int, int >? ProviderGetCutsceneParentIndex;
- internal ICallGateProvider< string, string, string[] >? ProviderReverseResolvePath;
- internal ICallGateProvider< string, string[] >? ProviderReverseResolvePathPlayer;
- internal ICallGateProvider< IntPtr, string, IntPtr, IntPtr, IntPtr, object? >? ProviderCreatingCharacterBase;
- internal ICallGateProvider< IntPtr, string, IntPtr, object? >? ProviderCreatedCharacterBase;
- internal ICallGateProvider< IntPtr, string, string, object? >? ProviderGameObjectResourcePathResolved;
-
- private void InitializeResolveProviders( DalamudPluginInterface pi )
- {
- try
- {
- ProviderResolveDefault = pi.GetIpcProvider< string, string >( LabelProviderResolveDefault );
- ProviderResolveDefault.RegisterFunc( Api.ResolveDefaultPath );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderResolveDefault}:\n{e}" );
- }
-
- try
- {
- ProviderResolveInterface = pi.GetIpcProvider< string, string >( LabelProviderResolveInterface );
- ProviderResolveInterface.RegisterFunc( Api.ResolveInterfacePath );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderResolveInterface}:\n{e}" );
- }
-
- try
- {
- ProviderResolveCharacter = pi.GetIpcProvider< string, string, string >( LabelProviderResolveCharacter );
- ProviderResolveCharacter.RegisterFunc( Api.ResolvePath );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderResolveCharacter}:\n{e}" );
- }
-
- try
- {
- ProviderResolvePlayer = pi.GetIpcProvider< string, string >( LabelProviderResolvePlayer );
- ProviderResolvePlayer.RegisterFunc( Api.ResolvePlayerPath );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderResolveCharacter}:\n{e}" );
- }
-
- try
- {
- ProviderGetDrawObjectInfo = pi.GetIpcProvider< IntPtr, (IntPtr, string) >( LabelProviderGetDrawObjectInfo );
- ProviderGetDrawObjectInfo.RegisterFunc( Api.GetDrawObjectInfo );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderGetDrawObjectInfo}:\n{e}" );
- }
-
- try
- {
- ProviderGetCutsceneParentIndex = pi.GetIpcProvider< int, int >( LabelProviderGetCutsceneParentIndex );
- ProviderGetCutsceneParentIndex.RegisterFunc( Api.GetCutsceneParentIndex );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderGetCutsceneParentIndex}:\n{e}" );
- }
-
- try
- {
- ProviderReverseResolvePath = pi.GetIpcProvider< string, string, string[] >( LabelProviderReverseResolvePath );
- ProviderReverseResolvePath.RegisterFunc( Api.ReverseResolvePath );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderReverseResolvePath}:\n{e}" );
- }
-
- try
- {
- ProviderReverseResolvePathPlayer = pi.GetIpcProvider< string, string[] >( LabelProviderReverseResolvePlayerPath );
- ProviderReverseResolvePathPlayer.RegisterFunc( Api.ReverseResolvePlayerPath );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderReverseResolvePlayerPath}:\n{e}" );
- }
-
- try
- {
- ProviderCreatingCharacterBase =
- pi.GetIpcProvider< IntPtr, string, IntPtr, IntPtr, IntPtr, object? >( LabelProviderCreatingCharacterBase );
- Api.CreatingCharacterBase += CreatingCharacterBaseEvent;
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderCreatingCharacterBase}:\n{e}" );
- }
-
- try
- {
- ProviderCreatedCharacterBase =
- pi.GetIpcProvider< IntPtr, string, IntPtr, object? >( LabelProviderCreatedCharacterBase );
- Api.CreatedCharacterBase += CreatedCharacterBaseEvent;
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderCreatedCharacterBase}:\n{e}" );
- }
-
- try
- {
- ProviderGameObjectResourcePathResolved =
- pi.GetIpcProvider< IntPtr, string, string, object? >( LabelProviderGameObjectResourcePathResolved );
- Api.GameObjectResourceResolved += GameObjectResourceResolvedEvent;
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderGameObjectResourcePathResolved}:\n{e}" );
- }
- }
-
- private void GameObjectResourceResolvedEvent( IntPtr gameObject, string gamePath, string localPath )
- {
- ProviderGameObjectResourcePathResolved?.SendMessage( gameObject, gamePath, localPath );
- }
-
- private void DisposeResolveProviders()
- {
- ProviderGetDrawObjectInfo?.UnregisterFunc();
- ProviderGetCutsceneParentIndex?.UnregisterFunc();
- ProviderResolveDefault?.UnregisterFunc();
- ProviderResolveInterface?.UnregisterFunc();
- ProviderResolveCharacter?.UnregisterFunc();
- ProviderReverseResolvePath?.UnregisterFunc();
- ProviderReverseResolvePathPlayer?.UnregisterFunc();
- Api.CreatingCharacterBase -= CreatingCharacterBaseEvent;
- Api.CreatedCharacterBase -= CreatedCharacterBaseEvent;
- Api.GameObjectResourceResolved -= GameObjectResourceResolvedEvent;
- }
-
- private void CreatingCharacterBaseEvent( IntPtr gameObject, ModCollection collection, IntPtr modelId, IntPtr customize, IntPtr equipData )
- {
- ProviderCreatingCharacterBase?.SendMessage( gameObject, collection.Name, modelId, customize, equipData );
- }
-
- private void CreatedCharacterBaseEvent( IntPtr gameObject, ModCollection collection, IntPtr drawObject )
- {
- ProviderCreatedCharacterBase?.SendMessage( gameObject, collection.Name, drawObject );
- }
-}
-
-public partial class PenumbraIpc
-{
- public const string LabelProviderChangedItemTooltip = "Penumbra.ChangedItemTooltip";
- public const string LabelProviderChangedItemClick = "Penumbra.ChangedItemClick";
- public const string LabelProviderGetChangedItems = "Penumbra.GetChangedItems";
-
- internal ICallGateProvider< ChangedItemType, uint, object? >? ProviderChangedItemTooltip;
- internal ICallGateProvider< MouseButton, ChangedItemType, uint, object? >? ProviderChangedItemClick;
- internal ICallGateProvider< string, IReadOnlyDictionary< string, object? > >? ProviderGetChangedItems;
-
- private void OnClick( MouseButton click, object? item )
- {
- var (type, id) = ChangedItemExtensions.ChangedItemToTypeAndId( item );
- ProviderChangedItemClick?.SendMessage( click, type, id );
- }
-
- private void OnTooltip( object? item )
- {
- var (type, id) = ChangedItemExtensions.ChangedItemToTypeAndId( item );
- ProviderChangedItemTooltip?.SendMessage( type, id );
- }
-
- private void InitializeChangedItemProviders( DalamudPluginInterface pi )
- {
- try
- {
- ProviderChangedItemTooltip = pi.GetIpcProvider< ChangedItemType, uint, object? >( LabelProviderChangedItemTooltip );
- Api.ChangedItemTooltip += OnTooltip;
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderChangedItemTooltip}:\n{e}" );
- }
-
- try
- {
- ProviderChangedItemClick = pi.GetIpcProvider< MouseButton, ChangedItemType, uint, object? >( LabelProviderChangedItemClick );
- Api.ChangedItemClicked += OnClick;
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderChangedItemClick}:\n{e}" );
- }
-
- try
- {
- ProviderGetChangedItems = pi.GetIpcProvider< string, IReadOnlyDictionary< string, object? > >( LabelProviderGetChangedItems );
- ProviderGetChangedItems.RegisterFunc( Api.GetChangedItemsForCollection );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderChangedItemClick}:\n{e}" );
- }
- }
-
- private void DisposeChangedItemProviders()
- {
- ProviderGetChangedItems?.UnregisterFunc();
- Api.ChangedItemClicked -= OnClick;
- Api.ChangedItemTooltip -= OnTooltip;
- }
-}
-
-public partial class PenumbraIpc
-{
- public const string LabelProviderGetMods = "Penumbra.GetMods";
- public const string LabelProviderGetCollections = "Penumbra.GetCollections";
- public const string LabelProviderCurrentCollectionName = "Penumbra.GetCurrentCollectionName";
- public const string LabelProviderDefaultCollectionName = "Penumbra.GetDefaultCollectionName";
- public const string LabelProviderInterfaceCollectionName = "Penumbra.GetInterfaceCollectionName";
- public const string LabelProviderCharacterCollectionName = "Penumbra.GetCharacterCollectionName";
- public const string LabelProviderGetPlayerMetaManipulations = "Penumbra.GetPlayerMetaManipulations";
- public const string LabelProviderGetMetaManipulations = "Penumbra.GetMetaManipulations";
-
- internal ICallGateProvider< IList< (string, string) > >? ProviderGetMods;
- internal ICallGateProvider< IList< string > >? ProviderGetCollections;
- internal ICallGateProvider< string >? ProviderCurrentCollectionName;
- internal ICallGateProvider< string >? ProviderDefaultCollectionName;
- internal ICallGateProvider< string >? ProviderInterfaceCollectionName;
- internal ICallGateProvider< string, (string, bool) >? ProviderCharacterCollectionName;
- internal ICallGateProvider< string >? ProviderGetPlayerMetaManipulations;
- internal ICallGateProvider< string, string >? ProviderGetMetaManipulations;
-
- private void InitializeDataProviders( DalamudPluginInterface pi )
- {
- try
- {
- ProviderGetMods = pi.GetIpcProvider< IList< (string, string) > >( LabelProviderGetMods );
- ProviderGetMods.RegisterFunc( Api.GetModList );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderGetMods}:\n{e}" );
- }
-
- try
- {
- ProviderGetCollections = pi.GetIpcProvider< IList< string > >( LabelProviderGetCollections );
- ProviderGetCollections.RegisterFunc( Api.GetCollections );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderGetCollections}:\n{e}" );
- }
-
- try
- {
- ProviderCurrentCollectionName = pi.GetIpcProvider< string >( LabelProviderCurrentCollectionName );
- ProviderCurrentCollectionName.RegisterFunc( Api.GetCurrentCollection );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderCurrentCollectionName}:\n{e}" );
- }
-
- try
- {
- ProviderDefaultCollectionName = pi.GetIpcProvider< string >( LabelProviderDefaultCollectionName );
- ProviderDefaultCollectionName.RegisterFunc( Api.GetDefaultCollection );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderDefaultCollectionName}:\n{e}" );
- }
-
- try
- {
- ProviderInterfaceCollectionName = pi.GetIpcProvider( LabelProviderInterfaceCollectionName );
- ProviderInterfaceCollectionName.RegisterFunc( Api.GetInterfaceCollection );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderInterfaceCollectionName}:\n{e}" );
- }
-
- try
- {
- ProviderCharacterCollectionName = pi.GetIpcProvider< string, (string, bool) >( LabelProviderCharacterCollectionName );
- ProviderCharacterCollectionName.RegisterFunc( Api.GetCharacterCollection );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderCharacterCollectionName}:\n{e}" );
- }
-
- try
- {
- ProviderGetPlayerMetaManipulations = pi.GetIpcProvider< string >( LabelProviderGetPlayerMetaManipulations );
- ProviderGetPlayerMetaManipulations.RegisterFunc( Api.GetPlayerMetaManipulations );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderGetPlayerMetaManipulations}:\n{e}" );
- }
-
- try
- {
- ProviderGetMetaManipulations = pi.GetIpcProvider< string, string >( LabelProviderGetMetaManipulations );
- ProviderGetMetaManipulations.RegisterFunc( Api.GetMetaManipulations );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderGetMetaManipulations}:\n{e}" );
- }
- }
-
- private void DisposeDataProviders()
- {
- ProviderGetMods?.UnregisterFunc();
- ProviderGetCollections?.UnregisterFunc();
- ProviderCurrentCollectionName?.UnregisterFunc();
- ProviderDefaultCollectionName?.UnregisterFunc();
- ProviderInterfaceCollectionName?.UnregisterFunc();
- ProviderCharacterCollectionName?.UnregisterFunc();
- ProviderGetMetaManipulations?.UnregisterFunc();
- }
-}
-
-public partial class PenumbraIpc
-{
- public const string LabelProviderGetAvailableModSettings = "Penumbra.GetAvailableModSettings";
- public const string LabelProviderReloadMod = "Penumbra.ReloadMod";
- public const string LabelProviderAddMod = "Penumbra.AddMod";
- public const string LabelProviderGetCurrentModSettings = "Penumbra.GetCurrentModSettings";
- public const string LabelProviderTryInheritMod = "Penumbra.TryInheritMod";
- public const string LabelProviderTrySetMod = "Penumbra.TrySetMod";
- public const string LabelProviderTrySetModPriority = "Penumbra.TrySetModPriority";
- public const string LabelProviderTrySetModSetting = "Penumbra.TrySetModSetting";
- public const string LabelProviderTrySetModSettings = "Penumbra.TrySetModSettings";
- public const string LabelProviderModSettingChanged = "Penumbra.ModSettingChanged";
-
- internal ICallGateProvider< ModSettingChange, string, string, bool, object? >? ProviderModSettingChanged;
-
- internal ICallGateProvider< string, string, IDictionary< string, (IList< string >, Mods.SelectType) >? >? ProviderGetAvailableModSettings;
- internal ICallGateProvider< string, string, PenumbraApiEc >? ProviderReloadMod;
- internal ICallGateProvider< string, PenumbraApiEc >? ProviderAddMod;
-
- internal ICallGateProvider< string, string, string, bool, (PenumbraApiEc, (bool, int, IDictionary< string, IList< string > >, bool)?) >?
- ProviderGetCurrentModSettings;
-
- internal ICallGateProvider< string, string, string, bool, PenumbraApiEc >? ProviderTryInheritMod;
- internal ICallGateProvider< string, string, string, bool, PenumbraApiEc >? ProviderTrySetMod;
- internal ICallGateProvider< string, string, string, int, PenumbraApiEc >? ProviderTrySetModPriority;
- internal ICallGateProvider< string, string, string, string, string, PenumbraApiEc >? ProviderTrySetModSetting;
- internal ICallGateProvider< string, string, string, string, IReadOnlyList< string >, PenumbraApiEc >? ProviderTrySetModSettings;
-
- private void InitializeSettingProviders( DalamudPluginInterface pi )
- {
- try
- {
- ProviderModSettingChanged = pi.GetIpcProvider< ModSettingChange, string, string, bool, object? >( LabelProviderModSettingChanged );
- Api.ModSettingChanged += InvokeModSettingChanged;
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderModSettingChanged}:\n{e}" );
- }
-
- try
- {
- ProviderGetAvailableModSettings =
- pi.GetIpcProvider< string, string, IDictionary< string, (IList< string >, Mods.SelectType) >? >(
- LabelProviderGetAvailableModSettings );
- ProviderGetAvailableModSettings.RegisterFunc( Api.GetAvailableModSettings );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderGetAvailableModSettings}:\n{e}" );
- }
-
- try
- {
- ProviderReloadMod = pi.GetIpcProvider< string, string, PenumbraApiEc >( LabelProviderReloadMod );
- ProviderReloadMod.RegisterFunc( Api.ReloadMod );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderReloadMod}:\n{e}" );
- }
-
- try
- {
- ProviderAddMod = pi.GetIpcProvider< string, PenumbraApiEc >( LabelProviderAddMod );
- ProviderAddMod.RegisterFunc( Api.AddMod );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderChangedItemClick}:\n{e}" );
- }
-
- try
- {
- ProviderGetCurrentModSettings =
- pi.GetIpcProvider< string, string, string, bool, (PenumbraApiEc, (bool, int, IDictionary< string, IList< string > >, bool)?) >(
- LabelProviderGetCurrentModSettings );
- ProviderGetCurrentModSettings.RegisterFunc( Api.GetCurrentModSettings );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderGetCurrentModSettings}:\n{e}" );
- }
-
- try
- {
- ProviderTryInheritMod = pi.GetIpcProvider< string, string, string, bool, PenumbraApiEc >( LabelProviderTryInheritMod );
- ProviderTryInheritMod.RegisterFunc( Api.TryInheritMod );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderTryInheritMod}:\n{e}" );
- }
-
- try
- {
- ProviderTrySetMod = pi.GetIpcProvider< string, string, string, bool, PenumbraApiEc >( LabelProviderTrySetMod );
- ProviderTrySetMod.RegisterFunc( Api.TrySetMod );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderTrySetMod}:\n{e}" );
- }
-
- try
- {
- ProviderTrySetModPriority = pi.GetIpcProvider< string, string, string, int, PenumbraApiEc >( LabelProviderTrySetModPriority );
- ProviderTrySetModPriority.RegisterFunc( Api.TrySetModPriority );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderTrySetModPriority}:\n{e}" );
- }
-
- try
- {
- ProviderTrySetModSetting =
- pi.GetIpcProvider< string, string, string, string, string, PenumbraApiEc >( LabelProviderTrySetModSetting );
- ProviderTrySetModSetting.RegisterFunc( Api.TrySetModSetting );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderTrySetModSetting}:\n{e}" );
- }
-
- try
- {
- ProviderTrySetModSettings =
- pi.GetIpcProvider< string, string, string, string, IReadOnlyList< string >, PenumbraApiEc >( LabelProviderTrySetModSettings );
- ProviderTrySetModSettings.RegisterFunc( Api.TrySetModSettings );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderTrySetModSettings}:\n{e}" );
- }
- }
-
- private void DisposeSettingProviders()
- {
- Api.ModSettingChanged -= InvokeModSettingChanged;
- ProviderGetAvailableModSettings?.UnregisterFunc();
- ProviderReloadMod?.UnregisterFunc();
- ProviderAddMod?.UnregisterFunc();
- ProviderGetCurrentModSettings?.UnregisterFunc();
- ProviderTryInheritMod?.UnregisterFunc();
- ProviderTrySetMod?.UnregisterFunc();
- ProviderTrySetModPriority?.UnregisterFunc();
- ProviderTrySetModSetting?.UnregisterFunc();
- ProviderTrySetModSettings?.UnregisterFunc();
- }
-
- private void InvokeModSettingChanged( ModSettingChange type, string collection, string mod, bool inherited )
- => ProviderModSettingChanged?.SendMessage( type, collection, mod, inherited );
-}
-
-public partial class PenumbraIpc
-{
- public const string LabelProviderCreateTemporaryCollection = "Penumbra.CreateTemporaryCollection";
- public const string LabelProviderRemoveTemporaryCollection = "Penumbra.RemoveTemporaryCollection";
- public const string LabelProviderAddTemporaryModAll = "Penumbra.AddTemporaryModAll";
- public const string LabelProviderAddTemporaryMod = "Penumbra.AddTemporaryMod";
- public const string LabelProviderRemoveTemporaryModAll = "Penumbra.RemoveTemporaryModAll";
- public const string LabelProviderRemoveTemporaryMod = "Penumbra.RemoveTemporaryMod";
-
- internal ICallGateProvider< string, string, bool, (PenumbraApiEc, string) >? ProviderCreateTemporaryCollection;
- internal ICallGateProvider< string, PenumbraApiEc >? ProviderRemoveTemporaryCollection;
-
- internal ICallGateProvider< string, Dictionary< string, string >, string, int, PenumbraApiEc >?
- ProviderAddTemporaryModAll;
-
- internal ICallGateProvider< string, string, Dictionary< string, string >, string, int, PenumbraApiEc >?
- ProviderAddTemporaryMod;
-
- internal ICallGateProvider< string, int, PenumbraApiEc >? ProviderRemoveTemporaryModAll;
- internal ICallGateProvider< string, string, int, PenumbraApiEc >? ProviderRemoveTemporaryMod;
-
- private void InitializeTempProviders( DalamudPluginInterface pi )
- {
- try
- {
- ProviderCreateTemporaryCollection =
- pi.GetIpcProvider< string, string, bool, (PenumbraApiEc, string) >( LabelProviderCreateTemporaryCollection );
- ProviderCreateTemporaryCollection.RegisterFunc( Api.CreateTemporaryCollection );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderCreateTemporaryCollection}:\n{e}" );
- }
-
- try
- {
- ProviderRemoveTemporaryCollection =
- pi.GetIpcProvider< string, PenumbraApiEc >( LabelProviderRemoveTemporaryCollection );
- ProviderRemoveTemporaryCollection.RegisterFunc( Api.RemoveTemporaryCollection );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderRemoveTemporaryCollection}:\n{e}" );
- }
-
- try
- {
- ProviderAddTemporaryModAll =
- pi.GetIpcProvider< string, Dictionary< string, string >, string, int, PenumbraApiEc >(
- LabelProviderAddTemporaryModAll );
- ProviderAddTemporaryModAll.RegisterFunc( Api.AddTemporaryModAll );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderAddTemporaryModAll}:\n{e}" );
- }
-
- try
- {
- ProviderAddTemporaryMod =
- pi.GetIpcProvider< string, string, Dictionary< string, string >, string, int, PenumbraApiEc >(
- LabelProviderAddTemporaryMod );
- ProviderAddTemporaryMod.RegisterFunc( Api.AddTemporaryMod );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderAddTemporaryMod}:\n{e}" );
- }
-
- try
- {
- ProviderRemoveTemporaryModAll = pi.GetIpcProvider< string, int, PenumbraApiEc >( LabelProviderRemoveTemporaryModAll );
- ProviderRemoveTemporaryModAll.RegisterFunc( Api.RemoveTemporaryModAll );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderRemoveTemporaryModAll}:\n{e}" );
- }
-
- try
- {
- ProviderRemoveTemporaryMod = pi.GetIpcProvider< string, string, int, PenumbraApiEc >( LabelProviderRemoveTemporaryMod );
- ProviderRemoveTemporaryMod.RegisterFunc( Api.RemoveTemporaryMod );
- }
- catch( Exception e )
- {
- Penumbra.Log.Error( $"Error registering IPC provider for {LabelProviderRemoveTemporaryMod}:\n{e}" );
- }
- }
-
- private void DisposeTempProviders()
- {
- ProviderCreateTemporaryCollection?.UnregisterFunc();
- ProviderRemoveTemporaryCollection?.UnregisterFunc();
- ProviderAddTemporaryModAll?.UnregisterFunc();
- ProviderAddTemporaryMod?.UnregisterFunc();
- ProviderRemoveTemporaryModAll?.UnregisterFunc();
- ProviderRemoveTemporaryMod?.UnregisterFunc();
- }
-}
\ No newline at end of file
diff --git a/Penumbra/Api/PenumbraIpcProviders.cs b/Penumbra/Api/PenumbraIpcProviders.cs
new file mode 100644
index 00000000..26a982ce
--- /dev/null
+++ b/Penumbra/Api/PenumbraIpcProviders.cs
@@ -0,0 +1,307 @@
+using Dalamud.Game.ClientState.Objects.Types;
+using Dalamud.Plugin;
+using Penumbra.Collections;
+using Penumbra.GameData.Enums;
+using System;
+using System.Collections.Generic;
+using Penumbra.Api.Enums;
+using Penumbra.Api.Helpers;
+
+namespace Penumbra.Api;
+
+using CurrentSettings = ValueTuple< PenumbraApiEc, (bool, int, IDictionary< string, IList< string > >, bool)? >;
+
+public class PenumbraIpcProviders : IDisposable
+{
+ internal readonly IPenumbraApi Api;
+ internal readonly IpcTester Tester;
+
+ // Plugin State
+ internal readonly EventProvider Initialized;
+ internal readonly EventProvider Disposed;
+ internal readonly FuncProvider< int > ApiVersion;
+ internal readonly FuncProvider< (int Breaking, int Features) > ApiVersions;
+
+ // Configuration
+ internal readonly FuncProvider< string > GetModDirectory;
+ internal readonly FuncProvider< string > GetConfiguration;
+ internal readonly EventProvider< string, bool > ModDirectoryChanged;
+
+ // UI
+ internal readonly EventProvider< string > PreSettingsDraw;
+ internal readonly EventProvider< string > PostSettingsDraw;
+ internal readonly EventProvider< ChangedItemType, uint > ChangedItemTooltip;
+ internal readonly EventProvider< MouseButton, ChangedItemType, uint > ChangedItemClick;
+
+ // Redrawing
+ internal readonly ActionProvider< RedrawType > RedrawAll;
+ internal readonly ActionProvider< GameObject, RedrawType > RedrawObject;
+ internal readonly ActionProvider< int, RedrawType > RedrawObjectByIndex;
+ internal readonly ActionProvider< string, RedrawType > RedrawObjectByName;
+ internal readonly EventProvider< nint, int > GameObjectRedrawn;
+
+ // Game State
+ internal readonly FuncProvider< nint, (nint, string) > GetDrawObjectInfo;
+ internal readonly FuncProvider< int, int > GetCutsceneParentIndex;
+ internal readonly EventProvider< nint, string, nint, nint, nint > CreatingCharacterBase;
+ internal readonly EventProvider< nint, string, nint > CreatedCharacterBase;
+ internal readonly EventProvider< nint, string, string > GameObjectResourcePathResolved;
+
+ // Resolve
+ internal readonly FuncProvider< string, string > ResolveDefaultPath;
+ internal readonly FuncProvider< string, string > ResolveInterfacePath;
+ internal readonly FuncProvider< string, string > ResolvePlayerPath;
+ internal readonly FuncProvider< string, string, string > ResolveCharacterPath;
+ internal readonly FuncProvider< string, string, string[] > ReverseResolvePath;
+ internal readonly FuncProvider< string, string[] > ReverseResolvePathPlayer;
+
+ // Collections
+ internal readonly FuncProvider< IList< string > > GetCollections;
+ internal readonly FuncProvider< string > GetCurrentCollectionName;
+ internal readonly FuncProvider< string > GetDefaultCollectionName;
+ internal readonly FuncProvider< string > GetInterfaceCollectionName;
+ internal readonly FuncProvider< string, (string, bool) > GetCharacterCollectionName;
+ internal readonly FuncProvider< string, IReadOnlyDictionary< string, object? > > GetChangedItems;
+
+ // Meta
+ internal readonly FuncProvider< string > GetPlayerMetaManipulations;
+ internal readonly FuncProvider< string, string > GetMetaManipulations;
+
+ // Mods
+ internal readonly FuncProvider< IList< (string, string) > > GetMods;
+ internal readonly FuncProvider< string, string, PenumbraApiEc > ReloadMod;
+ internal readonly FuncProvider< string, PenumbraApiEc > AddMod;
+ internal readonly FuncProvider< string, string, PenumbraApiEc > DeleteMod;
+ internal readonly FuncProvider< string, string, (PenumbraApiEc, string, bool) > GetModPath;
+ internal readonly FuncProvider< string, string, string, PenumbraApiEc > SetModPath;
+
+ // ModSettings
+ internal readonly FuncProvider< string, string, IDictionary< string, (IList< string >, GroupType) >? > GetAvailableModSettings;
+ internal readonly FuncProvider< string, string, string, bool, CurrentSettings > GetCurrentModSettings;
+ internal readonly FuncProvider< string, string, string, bool, PenumbraApiEc > TryInheritMod;
+ internal readonly FuncProvider< string, string, string, bool, PenumbraApiEc > TrySetMod;
+ internal readonly FuncProvider< string, string, string, int, PenumbraApiEc > TrySetModPriority;
+ internal readonly FuncProvider< string, string, string, string, string, PenumbraApiEc > TrySetModSetting;
+ internal readonly FuncProvider< string, string, string, string, IReadOnlyList< string >, PenumbraApiEc > TrySetModSettings;
+ internal readonly EventProvider< ModSettingChange, string, string, bool > ModSettingChanged;
+
+ // Temporary
+ internal readonly FuncProvider< string, string, bool, (PenumbraApiEc, string) > CreateTemporaryCollection;
+ internal readonly FuncProvider< string, PenumbraApiEc > RemoveTemporaryCollection;
+ internal readonly FuncProvider< string, Dictionary< string, string >, string, int, PenumbraApiEc > AddTemporaryModAll;
+ internal readonly FuncProvider< string, string, Dictionary< string, string >, string, int, PenumbraApiEc > AddTemporaryMod;
+ internal readonly FuncProvider< string, int, PenumbraApiEc > RemoveTemporaryModAll;
+ internal readonly FuncProvider< string, string, int, PenumbraApiEc > RemoveTemporaryMod;
+
+ public PenumbraIpcProviders( DalamudPluginInterface pi, IPenumbraApi api )
+ {
+ Api = api;
+
+ // Plugin State
+ Initialized = Ipc.Initialized.Provider( pi );
+ Disposed = Ipc.Disposed.Provider( pi );
+ ApiVersion = Ipc.ApiVersion.Provider( pi, DeprecatedVersion );
+ ApiVersions = Ipc.ApiVersions.Provider( pi, () => Api.ApiVersion );
+
+ // Configuration
+ GetModDirectory = Ipc.GetModDirectory.Provider( pi, Api.GetModDirectory );
+ GetConfiguration = Ipc.GetConfiguration.Provider( pi, Api.GetConfiguration );
+ ModDirectoryChanged = Ipc.ModDirectoryChanged.Provider( pi, a => Api.ModDirectoryChanged += a, a => Api.ModDirectoryChanged -= a );
+
+ // UI
+ PreSettingsDraw = Ipc.PreSettingsDraw.Provider( pi, a => Api.PreSettingsPanelDraw += a, a => Api.PreSettingsPanelDraw -= a );
+ PostSettingsDraw = Ipc.PostSettingsDraw.Provider( pi, a => Api.PostSettingsPanelDraw += a, a => Api.PostSettingsPanelDraw -= a );
+ ChangedItemTooltip = Ipc.ChangedItemTooltip.Provider( pi, () => Api.ChangedItemTooltip += OnTooltip, () => Api.ChangedItemTooltip -= OnTooltip );
+ ChangedItemClick = Ipc.ChangedItemClick.Provider( pi, () => Api.ChangedItemClicked += OnClick, () => Api.ChangedItemClicked -= OnClick );
+
+ // Redrawing
+ RedrawAll = Ipc.RedrawAll.Provider( pi, Api.RedrawAll );
+ RedrawObject = Ipc.RedrawObject.Provider( pi, Api.RedrawObject );
+ RedrawObjectByIndex = Ipc.RedrawObjectByIndex.Provider( pi, Api.RedrawObject );
+ RedrawObjectByName = Ipc.RedrawObjectByName.Provider( pi, Api.RedrawObject );
+ GameObjectRedrawn = Ipc.GameObjectRedrawn.Provider( pi, () => Api.GameObjectRedrawn += OnGameObjectRedrawn, () => Api.GameObjectRedrawn -= OnGameObjectRedrawn );
+
+ // Game State
+ GetDrawObjectInfo = Ipc.GetDrawObjectInfo.Provider( pi, Api.GetDrawObjectInfo );
+ GetCutsceneParentIndex = Ipc.GetCutsceneParentIndex.Provider( pi, Api.GetCutsceneParentIndex );
+ CreatingCharacterBase = Ipc.CreatingCharacterBase.Provider( pi,
+ () => Api.CreatingCharacterBase += CreatingCharacterBaseEvent,
+ () => Api.CreatingCharacterBase -= CreatingCharacterBaseEvent );
+ CreatedCharacterBase = Ipc.CreatedCharacterBase.Provider( pi,
+ () => Api.CreatedCharacterBase += CreatedCharacterBaseEvent,
+ () => Api.CreatedCharacterBase -= CreatedCharacterBaseEvent );
+ GameObjectResourcePathResolved = Ipc.GameObjectResourcePathResolved.Provider( pi,
+ () => Api.GameObjectResourceResolved += GameObjectResourceResolvedEvent,
+ () => Api.GameObjectResourceResolved -= GameObjectResourceResolvedEvent );
+
+ // Resolve
+ ResolveDefaultPath = Ipc.ResolveDefaultPath.Provider( pi, Api.ResolveDefaultPath );
+ ResolveInterfacePath = Ipc.ResolveInterfacePath.Provider( pi, Api.ResolveInterfacePath );
+ ResolvePlayerPath = Ipc.ResolvePlayerPath.Provider( pi, Api.ResolvePlayerPath );
+ ResolveCharacterPath = Ipc.ResolveCharacterPath.Provider( pi, Api.ResolvePath );
+ ReverseResolvePath = Ipc.ReverseResolvePath.Provider( pi, Api.ReverseResolvePath );
+ ReverseResolvePathPlayer = Ipc.ReverseResolvePlayerPath.Provider( pi, Api.ReverseResolvePlayerPath );
+
+ // Collections
+ GetCollections = Ipc.GetCollections.Provider( pi, Api.GetCollections );
+ GetCurrentCollectionName = Ipc.GetCurrentCollectionName.Provider( pi, Api.GetCurrentCollection );
+ GetDefaultCollectionName = Ipc.GetDefaultCollectionName.Provider( pi, Api.GetDefaultCollection );
+ GetInterfaceCollectionName = Ipc.GetInterfaceCollectionName.Provider( pi, Api.GetInterfaceCollection );
+ GetCharacterCollectionName = Ipc.GetCharacterCollectionName.Provider( pi, Api.GetCharacterCollection );
+ GetChangedItems = Ipc.GetChangedItems.Provider( pi, Api.GetChangedItemsForCollection );
+
+ // Meta
+ GetPlayerMetaManipulations = Ipc.GetPlayerMetaManipulations.Provider( pi, Api.GetPlayerMetaManipulations );
+ GetMetaManipulations = Ipc.GetMetaManipulations.Provider( pi, Api.GetMetaManipulations );
+
+ // Mods
+ GetMods = Ipc.GetMods.Provider( pi, Api.GetModList );
+ ReloadMod = Ipc.ReloadMod.Provider( pi, Api.ReloadMod );
+ AddMod = Ipc.AddMod.Provider( pi, Api.AddMod );
+ DeleteMod = Ipc.DeleteMod.Provider( pi, Api.DeleteMod );
+ GetModPath = Ipc.GetModPath.Provider( pi, Api.GetModPath );
+ SetModPath = Ipc.SetModPath.Provider( pi, Api.SetModPath );
+
+ // ModSettings
+
+ GetAvailableModSettings = Ipc.GetAvailableModSettings.Provider( pi, Api.GetAvailableModSettings );
+ GetCurrentModSettings = Ipc.GetCurrentModSettings.Provider( pi, Api.GetCurrentModSettings );
+ TryInheritMod = Ipc.TryInheritMod.Provider( pi, Api.TryInheritMod );
+ TrySetMod = Ipc.TrySetMod.Provider( pi, Api.TrySetMod );
+ TrySetModPriority = Ipc.TrySetModPriority.Provider( pi, Api.TrySetModPriority );
+ TrySetModSetting = Ipc.TrySetModSetting.Provider( pi, Api.TrySetModSetting );
+ TrySetModSettings = Ipc.TrySetModSettings.Provider( pi, Api.TrySetModSettings );
+ ModSettingChanged = Ipc.ModSettingChanged.Provider( pi,
+ () => Api.ModSettingChanged += ModSettingChangedEvent,
+ () => Api.ModSettingChanged -= ModSettingChangedEvent );
+
+ // Temporary
+ CreateTemporaryCollection = Ipc.CreateTemporaryCollection.Provider( pi, Api.CreateTemporaryCollection );
+ RemoveTemporaryCollection = Ipc.RemoveTemporaryCollection.Provider( pi, Api.RemoveTemporaryCollection );
+ AddTemporaryModAll = Ipc.AddTemporaryModAll.Provider( pi, Api.AddTemporaryModAll );
+ AddTemporaryMod = Ipc.AddTemporaryMod.Provider( pi, Api.AddTemporaryMod );
+ RemoveTemporaryModAll = Ipc.RemoveTemporaryModAll.Provider( pi, Api.RemoveTemporaryModAll );
+ RemoveTemporaryMod = Ipc.RemoveTemporaryMod.Provider( pi, Api.RemoveTemporaryMod );
+
+ Tester = new IpcTester( pi, this );
+
+ Initialized.Invoke();
+ }
+
+ public void Dispose()
+ {
+ // Plugin State
+ Initialized.Dispose();
+ ApiVersion.Dispose();
+ ApiVersions.Dispose();
+
+ // Configuration
+ GetModDirectory.Dispose();
+ GetConfiguration.Dispose();
+ ModDirectoryChanged.Dispose();
+
+ // UI
+ PreSettingsDraw.Dispose();
+ PostSettingsDraw.Dispose();
+ ChangedItemTooltip.Dispose();
+ ChangedItemClick.Dispose();
+
+ // Redrawing
+ RedrawAll.Dispose();
+ RedrawObject.Dispose();
+ RedrawObjectByIndex.Dispose();
+ RedrawObjectByName.Dispose();
+ GameObjectRedrawn.Dispose();
+
+ // Game State
+ GetDrawObjectInfo.Dispose();
+ GetCutsceneParentIndex.Dispose();
+ CreatingCharacterBase.Dispose();
+ CreatedCharacterBase.Dispose();
+ GameObjectResourcePathResolved.Dispose();
+
+ // Resolve
+ ResolveDefaultPath.Dispose();
+ ResolveInterfacePath.Dispose();
+ ResolvePlayerPath.Dispose();
+ ResolveCharacterPath.Dispose();
+ ReverseResolvePath.Dispose();
+ ReverseResolvePathPlayer.Dispose();
+
+ // Collections
+ GetCollections.Dispose();
+ GetCurrentCollectionName.Dispose();
+ GetDefaultCollectionName.Dispose();
+ GetInterfaceCollectionName.Dispose();
+ GetCharacterCollectionName.Dispose();
+ GetChangedItems.Dispose();
+
+ // Meta
+ GetPlayerMetaManipulations.Dispose();
+ GetMetaManipulations.Dispose();
+
+ // Mods
+ GetMods.Dispose();
+ ReloadMod.Dispose();
+ AddMod.Dispose();
+ DeleteMod.Dispose();
+ GetModPath.Dispose();
+ SetModPath.Dispose();
+
+ // ModSettings
+ GetAvailableModSettings.Dispose();
+ GetCurrentModSettings.Dispose();
+ TryInheritMod.Dispose();
+ TrySetMod.Dispose();
+ TrySetModPriority.Dispose();
+ TrySetModSetting.Dispose();
+ TrySetModSettings.Dispose();
+ ModSettingChanged.Dispose();
+
+ // Temporary
+ CreateTemporaryCollection.Dispose();
+ RemoveTemporaryCollection.Dispose();
+ AddTemporaryModAll.Dispose();
+ AddTemporaryMod.Dispose();
+ RemoveTemporaryModAll.Dispose();
+ RemoveTemporaryMod.Dispose();
+
+ Disposed.Invoke();
+ Disposed.Dispose();
+ Tester.Dispose();
+ }
+
+ // Wrappers
+ private int DeprecatedVersion()
+ {
+ Penumbra.Log.Warning( $"{Ipc.ApiVersion.Label} is outdated. Please use {Ipc.ApiVersions.Label} instead." );
+ return Api.ApiVersion.Breaking;
+ }
+
+ private void OnClick( MouseButton click, object? item )
+ {
+ var (type, id) = ChangedItemExtensions.ChangedItemToTypeAndId( item );
+ ChangedItemClick.Invoke( click, type, id );
+ }
+
+ private void OnTooltip( object? item )
+ {
+ var (type, id) = ChangedItemExtensions.ChangedItemToTypeAndId( item );
+ ChangedItemTooltip.Invoke( type, id );
+ }
+
+ private void OnGameObjectRedrawn( IntPtr objectAddress, int objectTableIndex )
+ => GameObjectRedrawn.Invoke( objectAddress, objectTableIndex );
+
+ private void CreatingCharacterBaseEvent( IntPtr gameObject, string collectionName, IntPtr modelId, IntPtr customize, IntPtr equipData )
+ => CreatingCharacterBase.Invoke( gameObject, collectionName, modelId, customize, equipData );
+
+ private void CreatedCharacterBaseEvent( IntPtr gameObject, string collectionName, IntPtr drawObject )
+ => CreatedCharacterBase.Invoke( gameObject, collectionName, drawObject );
+
+ private void GameObjectResourceResolvedEvent( IntPtr gameObject, string gamePath, string localPath )
+ => GameObjectResourcePathResolved.Invoke( gameObject, gamePath, localPath );
+
+ private void ModSettingChangedEvent( ModSettingChange type, string collection, string mod, bool inherited )
+ => ModSettingChanged.Invoke( type, collection, mod, inherited );
+}
\ No newline at end of file
diff --git a/Penumbra/Api/RedrawController.cs b/Penumbra/Api/RedrawController.cs
index 9aef89b7..ad37c587 100644
--- a/Penumbra/Api/RedrawController.cs
+++ b/Penumbra/Api/RedrawController.cs
@@ -1,8 +1,8 @@
using EmbedIO;
using EmbedIO.Routing;
using EmbedIO.WebApi;
-using Penumbra.GameData.Enums;
using System.Threading.Tasks;
+using Penumbra.Api.Enums;
namespace Penumbra.Api;
diff --git a/Penumbra/Collections/ModCollection.Cache.cs b/Penumbra/Collections/ModCollection.Cache.cs
index d2bb2d92..2d2262cc 100644
--- a/Penumbra/Collections/ModCollection.Cache.cs
+++ b/Penumbra/Collections/ModCollection.Cache.cs
@@ -7,6 +7,7 @@ using Penumbra.Mods;
using System;
using System.Collections.Generic;
using System.Linq;
+using Penumbra.Api.Enums;
namespace Penumbra.Collections;
@@ -269,10 +270,10 @@ public partial class ModCollection
var config = settings.Settings[ groupIndex ];
switch( group.Type )
{
- case SelectType.Single:
+ case GroupType.Single:
AddSubMod( group[ ( int )config ], mod );
break;
- case SelectType.Multi:
+ case GroupType.Multi:
{
foreach( var (option, _) in group.WithIndex()
.Where( p => ( ( 1 << p.Item2 ) & config ) != 0 )
diff --git a/Penumbra/Collections/ModCollection.Changes.cs b/Penumbra/Collections/ModCollection.Changes.cs
index 32826dc8..fead3281 100644
--- a/Penumbra/Collections/ModCollection.Changes.cs
+++ b/Penumbra/Collections/ModCollection.Changes.cs
@@ -2,20 +2,10 @@ using Penumbra.Mods;
using System;
using System.Collections.Generic;
using System.Linq;
+using Penumbra.Api.Enums;
namespace Penumbra.Collections;
-// Different types a mod setting can change:
-public enum ModSettingChange
-{
- Inheritance, // it was set to inherit from other collections or not inherit anymore
- EnableState, // it was enabled or disabled
- Priority, // its priority was changed
- Setting, // a specific setting was changed
- MultiInheritance, // multiple mods were set to inherit from other collections or not inherit anymore.
- MultiEnableState, // multiple mods were enabled or disabled at once.
-}
-
public partial class ModCollection
{
// If the change type is a bool, oldValue will be 1 for true and 0 for false.
diff --git a/Penumbra/Collections/ModCollection.Inheritance.cs b/Penumbra/Collections/ModCollection.Inheritance.cs
index 16415a09..44403758 100644
--- a/Penumbra/Collections/ModCollection.Inheritance.cs
+++ b/Penumbra/Collections/ModCollection.Inheritance.cs
@@ -3,6 +3,7 @@ using Penumbra.Mods;
using System;
using System.Collections.Generic;
using System.Linq;
+using Penumbra.Api.Enums;
namespace Penumbra.Collections;
diff --git a/Penumbra/Import/TexToolsImporter.ModPack.cs b/Penumbra/Import/TexToolsImporter.ModPack.cs
index 0edef44e..ca8eb492 100644
--- a/Penumbra/Import/TexToolsImporter.ModPack.cs
+++ b/Penumbra/Import/TexToolsImporter.ModPack.cs
@@ -5,6 +5,7 @@ using System.Linq;
using System.Text;
using Newtonsoft.Json;
using OtterGui;
+using Penumbra.Api.Enums;
using Penumbra.Mods;
using Penumbra.Util;
using SharpCompress.Archives.Zip;
@@ -162,7 +163,7 @@ public partial class TexToolsImporter
foreach( var group in page.ModGroups.Where( group => group.GroupName.Length > 0 && group.OptionList.Length > 0 ) )
{
var allOptions = group.OptionList.Where( option => option.Name.Length > 0 && option.ModsJsons.Length > 0 ).ToList();
- var (numGroups, maxOptions) = group.SelectionType == SelectType.Single
+ var (numGroups, maxOptions) = group.SelectionType == GroupType.Single
? ( 1, allOptions.Count )
: ( 1 + allOptions.Count / IModGroup.MaxMultiOptions, IModGroup.MaxMultiOptions );
_currentGroupName = GetGroupName( group.GroupName, groupNames );
@@ -177,7 +178,7 @@ public partial class TexToolsImporter
?? new DirectoryInfo( Path.Combine( _currentModDirectory.FullName,
numGroups == 1 ? $"Group {groupPriority + 1}" : $"Group {groupPriority + 1}, Part {groupId + 1}" ) );
- uint? defaultSettings = group.SelectionType == SelectType.Multi ? 0u : null;
+ uint? defaultSettings = group.SelectionType == GroupType.Multi ? 0u : null;
for( var i = 0; i + optionIdx < allOptions.Count && i < maxOptions; ++i )
{
var option = allOptions[ i + optionIdx ];
@@ -195,7 +196,7 @@ public partial class TexToolsImporter
if( option.IsChecked )
{
- defaultSettings = group.SelectionType == SelectType.Multi
+ defaultSettings = group.SelectionType == GroupType.Multi
? ( defaultSettings!.Value | ( 1u << i ) )
: ( uint )i;
}
@@ -207,7 +208,7 @@ public partial class TexToolsImporter
// Handle empty options for single select groups without creating a folder for them.
// We only want one of those at most, and it should usually be the first option.
- if( group.SelectionType == SelectType.Single )
+ if( group.SelectionType == GroupType.Single )
{
var empty = group.OptionList.FirstOrDefault( o => o.Name.Length > 0 && o.ModsJsons.Length == 0 );
if( empty != null )
diff --git a/Penumbra/Import/TexToolsStructs.cs b/Penumbra/Import/TexToolsStructs.cs
index 51b73b90..bc85893c 100644
--- a/Penumbra/Import/TexToolsStructs.cs
+++ b/Penumbra/Import/TexToolsStructs.cs
@@ -1,4 +1,5 @@
using System;
+using Penumbra.Api.Enums;
using Penumbra.Mods;
namespace Penumbra.Import;
@@ -34,7 +35,7 @@ internal class ModPackPage
internal class ModGroup
{
public string GroupName = string.Empty;
- public SelectType SelectionType = SelectType.Single;
+ public GroupType SelectionType = GroupType.Single;
public OptionList[] OptionList = Array.Empty< OptionList >();
}
@@ -46,7 +47,7 @@ internal class OptionList
public string ImagePath = string.Empty;
public SimpleMod[] ModsJsons = Array.Empty< SimpleMod >();
public string GroupName = string.Empty;
- public SelectType SelectionType = SelectType.Single;
+ public GroupType SelectionType = GroupType.Single;
public bool IsChecked = false;
}
diff --git a/Penumbra/Interop/ObjectReloader.cs b/Penumbra/Interop/ObjectReloader.cs
index a04801b9..4fecf454 100644
--- a/Penumbra/Interop/ObjectReloader.cs
+++ b/Penumbra/Interop/ObjectReloader.cs
@@ -6,6 +6,7 @@ using Dalamud.Game.ClientState.Objects.Enums;
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.ClientState.Objects.Types;
using Penumbra.Api;
+using Penumbra.Api.Enums;
using Penumbra.GameData.Enums;
using Penumbra.Interop.Structs;
diff --git a/Penumbra/Interop/Resolver/PathResolver.DrawObjectState.cs b/Penumbra/Interop/Resolver/PathResolver.DrawObjectState.cs
index 40228fad..aa6e7ed4 100644
--- a/Penumbra/Interop/Resolver/PathResolver.DrawObjectState.cs
+++ b/Penumbra/Interop/Resolver/PathResolver.DrawObjectState.cs
@@ -149,7 +149,7 @@ public unsafe partial class PathResolver
try
{
var modelPtr = &a;
- CreatingCharacterBase?.Invoke( ( IntPtr )LastGameObject, _lastCreatedCollection!.ModCollection, ( IntPtr )modelPtr, b, c );
+ CreatingCharacterBase?.Invoke( ( IntPtr )LastGameObject, _lastCreatedCollection!.ModCollection.Name, ( IntPtr )modelPtr, b, c );
}
catch( Exception e )
{
@@ -163,7 +163,7 @@ public unsafe partial class PathResolver
if( LastGameObject != null && ret != IntPtr.Zero )
{
_drawObjectToObject[ ret ] = ( _lastCreatedCollection!, LastGameObject->ObjectIndex );
- CreatedCharacterBase?.Invoke( ( IntPtr )LastGameObject, _lastCreatedCollection!.ModCollection, ret );
+ CreatedCharacterBase?.Invoke( ( IntPtr )LastGameObject, _lastCreatedCollection!.ModCollection.Name, ret );
}
return ret;
diff --git a/Penumbra/Mods/Manager/Mod.Manager.Options.cs b/Penumbra/Mods/Manager/Mod.Manager.Options.cs
index 3e248c0e..704d1285 100644
--- a/Penumbra/Mods/Manager/Mod.Manager.Options.cs
+++ b/Penumbra/Mods/Manager/Mod.Manager.Options.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using OtterGui;
using OtterGui.Filesystem;
+using Penumbra.Api.Enums;
using Penumbra.GameData.ByteString;
using Penumbra.Meta.Manipulations;
using Penumbra.Util;
@@ -16,7 +17,7 @@ public sealed partial class Mod
public delegate void ModOptionChangeDelegate( ModOptionChangeType type, Mod mod, int groupIdx, int optionIdx, int movedToIdx );
public event ModOptionChangeDelegate ModOptionChanged;
- public void ChangeModGroupType( Mod mod, int groupIdx, SelectType type )
+ public void ChangeModGroupType( Mod mod, int groupIdx, GroupType type )
{
var group = mod._groups[ groupIdx ];
if( group.Type == type )
@@ -61,7 +62,7 @@ public sealed partial class Mod
ModOptionChanged.Invoke( ModOptionChangeType.GroupRenamed, mod, groupIdx, -1, -1 );
}
- public void AddModGroup( Mod mod, SelectType type, string newName )
+ public void AddModGroup( Mod mod, GroupType type, string newName )
{
if( !VerifyFileName( mod, null, newName, true ) )
{
@@ -70,7 +71,7 @@ public sealed partial class Mod
var maxPriority = mod._groups.Count == 0 ? 0 : mod._groups.Max( o => o.Priority ) + 1;
- mod._groups.Add( type == SelectType.Multi
+ mod._groups.Add( type == GroupType.Multi
? new MultiModGroup { Name = newName, Priority = maxPriority }
: new SingleModGroup { Name = newName, Priority = maxPriority } );
ModOptionChanged.Invoke( ModOptionChangeType.GroupAdded, mod, mod._groups.Count - 1, -1, -1 );
diff --git a/Penumbra/Mods/Mod.Creation.cs b/Penumbra/Mods/Mod.Creation.cs
index 184dc8cb..699fceaa 100644
--- a/Penumbra/Mods/Mod.Creation.cs
+++ b/Penumbra/Mods/Mod.Creation.cs
@@ -5,6 +5,7 @@ using System.Text;
using Dalamud.Utility;
using OtterGui.Classes;
using OtterGui.Filesystem;
+using Penumbra.Api.Enums;
using Penumbra.GameData.ByteString;
using Penumbra.Import;
@@ -62,12 +63,12 @@ public partial class Mod
}
// Create a file for an option group from given data.
- internal static void CreateOptionGroup( DirectoryInfo baseFolder, SelectType type, string name,
+ internal static void CreateOptionGroup( DirectoryInfo baseFolder, GroupType type, string name,
int priority, int index, uint defaultSettings, string desc, IEnumerable< ISubMod > subMods )
{
switch( type )
{
- case SelectType.Multi:
+ case GroupType.Multi:
{
var group = new MultiModGroup()
{
@@ -80,7 +81,7 @@ public partial class Mod
IModGroup.Save( group, baseFolder, index );
break;
}
- case SelectType.Single:
+ case GroupType.Single:
{
var group = new SingleModGroup()
{
diff --git a/Penumbra/Mods/Mod.Files.cs b/Penumbra/Mods/Mod.Files.cs
index c9c8683b..3f6a79b4 100644
--- a/Penumbra/Mods/Mod.Files.cs
+++ b/Penumbra/Mods/Mod.Files.cs
@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using Newtonsoft.Json.Linq;
using OtterGui;
+using Penumbra.Api.Enums;
using Penumbra.GameData.ByteString;
using Penumbra.Meta.Manipulations;
@@ -79,10 +80,10 @@ public partial class Mod
try
{
var json = JObject.Parse( File.ReadAllText( file.FullName ) );
- switch( json[ nameof( Type ) ]?.ToObject< SelectType >() ?? SelectType.Single )
+ switch( json[ nameof( Type ) ]?.ToObject< GroupType >() ?? GroupType.Single )
{
- case SelectType.Multi: return MultiModGroup.Load( mod, json, groupIdx );
- case SelectType.Single: return SingleModGroup.Load( mod, json, groupIdx );
+ case GroupType.Multi: return MultiModGroup.Load( mod, json, groupIdx );
+ case GroupType.Single: return SingleModGroup.Load( mod, json, groupIdx );
}
}
catch( Exception e )
diff --git a/Penumbra/Mods/Mod.Meta.Migration.cs b/Penumbra/Mods/Mod.Meta.Migration.cs
index f6bba3a3..69e33628 100644
--- a/Penumbra/Mods/Mod.Meta.Migration.cs
+++ b/Penumbra/Mods/Mod.Meta.Migration.cs
@@ -6,6 +6,7 @@ using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OtterGui;
+using Penumbra.Api.Enums;
using Penumbra.GameData.ByteString;
namespace Penumbra.Mods;
@@ -128,7 +129,7 @@ public sealed partial class Mod
switch( group.SelectionType )
{
- case SelectType.Multi:
+ case GroupType.Multi:
var optionPriority = 0;
var newMultiGroup = new MultiModGroup()
@@ -144,7 +145,7 @@ public sealed partial class Mod
}
break;
- case SelectType.Single:
+ case GroupType.Single:
if( group.Options.Count == 1 )
{
AddFilesToSubMod( mod._default, mod.ModPath, group.Options[ 0 ], seenMetaFiles );
@@ -209,7 +210,7 @@ public sealed partial class Mod
public string GroupName = string.Empty;
[JsonConverter( typeof( Newtonsoft.Json.Converters.StringEnumConverter ) )]
- public SelectType SelectionType = SelectType.Single;
+ public GroupType SelectionType = GroupType.Single;
public List< OptionV0 > Options = new();
diff --git a/Penumbra/Mods/ModFileSystem.cs b/Penumbra/Mods/ModFileSystem.cs
index 1060504c..c8cbdf22 100644
--- a/Penumbra/Mods/ModFileSystem.cs
+++ b/Penumbra/Mods/ModFileSystem.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
@@ -121,8 +122,7 @@ public sealed class ModFileSystem : FileSystem< Mod >, IDisposable
CreateLeaf( Root, name, mod );
break;
case ModPathChangeType.Deleted:
- var leaf = Root.GetAllDescendants( ISortMode< Mod >.Lexicographical ).OfType< Leaf >().FirstOrDefault( l => l.Value == mod );
- if( leaf != null )
+ if( FindLeaf( mod, out var leaf ) )
{
Delete( leaf );
}
@@ -137,6 +137,16 @@ public sealed class ModFileSystem : FileSystem< Mod >, IDisposable
}
}
+ // Search the entire filesystem for the leaf corresponding to a mod.
+ public bool FindLeaf( Mod mod, [NotNullWhen( true )] out Leaf? leaf )
+ {
+ leaf = Root.GetAllDescendants( ISortMode< Mod >.Lexicographical )
+ .OfType< Leaf >()
+ .FirstOrDefault( l => l.Value == mod );
+ return leaf != null;
+ }
+
+
// Used for saving and loading.
private static string ModToIdentifier( Mod mod )
=> mod.ModPath.Name;
@@ -144,15 +154,16 @@ public sealed class ModFileSystem : FileSystem< Mod >, IDisposable
private static string ModToName( Mod mod )
=> mod.Name.Text.FixName();
- private static (string, bool) SaveMod( Mod mod, string fullPath )
+ // Return whether a mod has a custom path or is just a numbered default path.
+ public static bool ModHasDefaultPath( Mod mod, string fullPath )
{
var regex = new Regex( $@"^{Regex.Escape( ModToName( mod ) )}( \(\d+\))?$" );
- // Only save pairs with non-default paths.
- if( regex.IsMatch( fullPath ) )
- {
- return ( string.Empty, false );
- }
-
- return ( ModToIdentifier( mod ), true );
+ return regex.IsMatch( fullPath );
}
+
+ private static (string, bool) SaveMod( Mod mod, string fullPath )
+ // Only save pairs with non-default paths.
+ => ModHasDefaultPath( mod, fullPath )
+ ? ( string.Empty, false )
+ : ( ModToIdentifier( mod ), true );
}
\ No newline at end of file
diff --git a/Penumbra/Mods/Subclasses/IModGroup.cs b/Penumbra/Mods/Subclasses/IModGroup.cs
index fb2d305a..0c1ebf2f 100644
--- a/Penumbra/Mods/Subclasses/IModGroup.cs
+++ b/Penumbra/Mods/Subclasses/IModGroup.cs
@@ -3,22 +3,17 @@ using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using OtterGui.Filesystem;
+using Penumbra.Api.Enums;
namespace Penumbra.Mods;
-public enum SelectType
-{
- Single,
- Multi,
-}
-
public interface IModGroup : IEnumerable< ISubMod >
{
public const int MaxMultiOptions = 32;
public string Name { get; }
public string Description { get; }
- public SelectType Type { get; }
+ public GroupType Type { get; }
public int Priority { get; }
public uint DefaultSettings { get; set; }
@@ -31,8 +26,8 @@ public interface IModGroup : IEnumerable< ISubMod >
public bool IsOption
=> Type switch
{
- SelectType.Single => Count > 1,
- SelectType.Multi => Count > 0,
+ GroupType.Single => Count > 1,
+ GroupType.Multi => Count > 0,
_ => false,
};
@@ -90,7 +85,7 @@ public interface IModGroup : IEnumerable< ISubMod >
j.WriteStartArray();
for( var idx = 0; idx < group.Count; ++idx )
{
- ISubMod.WriteSubMod( j, serializer, group[ idx ], basePath, group.Type == SelectType.Multi ? group.OptionPriority( idx ) : null );
+ ISubMod.WriteSubMod( j, serializer, group[ idx ], basePath, group.Type == GroupType.Multi ? group.OptionPriority( idx ) : null );
}
j.WriteEndArray();
@@ -98,7 +93,7 @@ public interface IModGroup : IEnumerable< ISubMod >
Penumbra.Log.Debug( $"Saved group file {file} for group {groupIdx + 1}: {group.Name}." );
}
- public IModGroup Convert( SelectType type );
+ public IModGroup Convert( GroupType type );
public bool MoveOption( int optionIdxFrom, int optionIdxTo );
public void UpdatePositions( int from = 0 );
}
\ No newline at end of file
diff --git a/Penumbra/Mods/Subclasses/Mod.Files.MultiModGroup.cs b/Penumbra/Mods/Subclasses/Mod.Files.MultiModGroup.cs
index 91bc304b..fe7b1173 100644
--- a/Penumbra/Mods/Subclasses/Mod.Files.MultiModGroup.cs
+++ b/Penumbra/Mods/Subclasses/Mod.Files.MultiModGroup.cs
@@ -7,6 +7,7 @@ using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OtterGui;
using OtterGui.Filesystem;
+using Penumbra.Api.Enums;
namespace Penumbra.Mods;
@@ -15,8 +16,8 @@ public partial class Mod
// Groups that allow all available options to be selected at once.
private sealed class MultiModGroup : IModGroup
{
- public SelectType Type
- => SelectType.Multi;
+ public GroupType Type
+ => GroupType.Multi;
public string Name { get; set; } = "Group";
public string Description { get; set; } = "A non-exclusive group of settings.";
@@ -79,12 +80,12 @@ public partial class Mod
return ret;
}
- public IModGroup Convert( SelectType type )
+ public IModGroup Convert( GroupType type )
{
switch( type )
{
- case SelectType.Multi: return this;
- case SelectType.Single:
+ case GroupType.Multi: return this;
+ case GroupType.Single:
var multi = new SingleModGroup()
{
Name = Name,
diff --git a/Penumbra/Mods/Subclasses/Mod.Files.SingleModGroup.cs b/Penumbra/Mods/Subclasses/Mod.Files.SingleModGroup.cs
index 3de02d5c..cfec230e 100644
--- a/Penumbra/Mods/Subclasses/Mod.Files.SingleModGroup.cs
+++ b/Penumbra/Mods/Subclasses/Mod.Files.SingleModGroup.cs
@@ -6,6 +6,7 @@ using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OtterGui;
using OtterGui.Filesystem;
+using Penumbra.Api.Enums;
namespace Penumbra.Mods;
@@ -14,8 +15,8 @@ public partial class Mod
// Groups that allow only one of their available options to be selected.
private sealed class SingleModGroup : IModGroup
{
- public SelectType Type
- => SelectType.Single;
+ public GroupType Type
+ => GroupType.Single;
public string Name { get; set; } = "Option";
public string Description { get; set; } = "A mutually exclusive group of settings.";
@@ -72,12 +73,12 @@ public partial class Mod
return ret;
}
- public IModGroup Convert( SelectType type )
+ public IModGroup Convert( GroupType type )
{
switch( type )
{
- case SelectType.Single: return this;
- case SelectType.Multi:
+ case GroupType.Single: return this;
+ case GroupType.Multi:
var multi = new MultiModGroup()
{
Name = Name,
diff --git a/Penumbra/Mods/Subclasses/ModSettings.cs b/Penumbra/Mods/Subclasses/ModSettings.cs
index 6e8c7343..7b2a23ab 100644
--- a/Penumbra/Mods/Subclasses/ModSettings.cs
+++ b/Penumbra/Mods/Subclasses/ModSettings.cs
@@ -4,6 +4,7 @@ using System.Linq;
using System.Numerics;
using OtterGui;
using OtterGui.Filesystem;
+using Penumbra.Api.Enums;
namespace Penumbra.Mods;
@@ -56,8 +57,8 @@ public class ModSettings
var config = Settings[ groupIdx ];
Settings[ groupIdx ] = group.Type switch
{
- SelectType.Single => ( uint )Math.Max( Math.Min( group.Count - 1, BitOperations.TrailingZeroCount( config ) ), 0 ),
- SelectType.Multi => 1u << ( int )config,
+ GroupType.Single => ( uint )Math.Max( Math.Min( group.Count - 1, BitOperations.TrailingZeroCount( config ) ), 0 ),
+ GroupType.Multi => 1u << ( int )config,
_ => config,
};
return config != Settings[ groupIdx ];
@@ -70,8 +71,8 @@ public class ModSettings
var config = Settings[ groupIdx ];
Settings[ groupIdx ] = group.Type switch
{
- SelectType.Single => config >= optionIdx ? config > 1 ? config - 1 : 0 : config,
- SelectType.Multi => Functions.RemoveBit( config, optionIdx ),
+ GroupType.Single => config >= optionIdx ? config > 1 ? config - 1 : 0 : config,
+ GroupType.Multi => Functions.RemoveBit( config, optionIdx ),
_ => config,
};
return config != Settings[ groupIdx ];
@@ -87,8 +88,8 @@ public class ModSettings
var config = Settings[ groupIdx ];
Settings[ groupIdx ] = group.Type switch
{
- SelectType.Single => config == optionIdx ? ( uint )movedToIdx : config,
- SelectType.Multi => Functions.MoveBit( config, optionIdx, movedToIdx ),
+ GroupType.Single => config == optionIdx ? ( uint )movedToIdx : config,
+ GroupType.Multi => Functions.MoveBit( config, optionIdx, movedToIdx ),
_ => config,
};
return config != Settings[ groupIdx ];
@@ -101,8 +102,8 @@ public class ModSettings
private static uint FixSetting( IModGroup group, uint value )
=> group.Type switch
{
- SelectType.Single => ( uint )Math.Min( value, group.Count - 1 ),
- SelectType.Multi => ( uint )( value & ( ( 1ul << group.Count ) - 1 ) ),
+ GroupType.Single => ( uint )Math.Min( value, group.Count - 1 ),
+ GroupType.Multi => ( uint )( value & ( ( 1ul << group.Count ) - 1 ) ),
_ => value,
};
@@ -202,7 +203,7 @@ public class ModSettings
}
var group = mod.Groups[ idx ];
- if( group.Type == SelectType.Single && setting < group.Count )
+ if( group.Type == GroupType.Single && setting < group.Count )
{
dict.Add( group.Name, new[] { group[ ( int )setting ].Name } );
}
diff --git a/Penumbra/Penumbra.cs b/Penumbra/Penumbra.cs
index 3c784c66..cd08a20b 100644
--- a/Penumbra/Penumbra.cs
+++ b/Penumbra/Penumbra.cs
@@ -16,6 +16,7 @@ using OtterGui.Classes;
using OtterGui.Log;
using OtterGui.Widgets;
using Penumbra.Api;
+using Penumbra.Api.Enums;
using Penumbra.GameData.Enums;
using Penumbra.Interop;
using Penumbra.UI;
@@ -57,16 +58,16 @@ public class Penumbra : IDalamudPlugin
public static FrameworkManager Framework { get; private set; } = null!;
public static int ImcExceptions = 0;
- public readonly ResourceLogger ResourceLogger;
- public readonly PathResolver PathResolver;
- public readonly ObjectReloader ObjectReloader;
- public readonly ModFileSystem ModFileSystem;
- public readonly PenumbraApi Api;
- public readonly PenumbraIpc Ipc;
- private readonly ConfigWindow _configWindow;
- private readonly LaunchButton _launchButton;
- private readonly WindowSystem _windowSystem;
- private readonly Changelog _changelog;
+ public readonly ResourceLogger ResourceLogger;
+ public readonly PathResolver PathResolver;
+ public readonly ObjectReloader ObjectReloader;
+ public readonly ModFileSystem ModFileSystem;
+ public readonly PenumbraApi Api;
+ public readonly PenumbraIpcProviders IpcProviders;
+ private readonly ConfigWindow _configWindow;
+ private readonly LaunchButton _launchButton;
+ private readonly WindowSystem _windowSystem;
+ private readonly Changelog _changelog;
internal WebServer? WebServer;
@@ -95,9 +96,9 @@ public class Penumbra : IDalamudPlugin
ModManager.DiscoverMods();
CollectionManager = new ModCollection.Manager( ModManager );
CollectionManager.CreateNecessaryCaches();
- ModFileSystem = ModFileSystem.Load();
- ObjectReloader = new ObjectReloader();
- PathResolver = new PathResolver( ResourceLoader );
+ ModFileSystem = ModFileSystem.Load();
+ ObjectReloader = new ObjectReloader();
+ PathResolver = new PathResolver( ResourceLoader );
Dalamud.Commands.AddHandler( CommandName, new CommandInfo( OnCommand )
{
@@ -133,8 +134,8 @@ public class Penumbra : IDalamudPlugin
ResidentResources.Reload();
}
- Api = new PenumbraApi( this );
- Ipc = new PenumbraIpc( Dalamud.PluginInterface, Api );
+ Api = new PenumbraApi( this );
+ IpcProviders = new PenumbraIpcProviders( Dalamud.PluginInterface, Api );
SubscribeItemLinks();
if( ImcExceptions > 0 )
{
@@ -279,7 +280,7 @@ public class Penumbra : IDalamudPlugin
{
ShutdownWebServer();
DisposeInterface();
- Ipc?.Dispose();
+ IpcProviders?.Dispose();
Api?.Dispose();
ObjectReloader?.Dispose();
ModFileSystem?.Dispose();
diff --git a/Penumbra/Penumbra.csproj b/Penumbra/Penumbra.csproj
index 624558c1..b7ab0231 100644
--- a/Penumbra/Penumbra.csproj
+++ b/Penumbra/Penumbra.csproj
@@ -75,6 +75,7 @@
+
diff --git a/Penumbra/UI/Classes/ModFileSystemSelector.cs b/Penumbra/UI/Classes/ModFileSystemSelector.cs
index 77c7dea1..1ccf0e3c 100644
--- a/Penumbra/UI/Classes/ModFileSystemSelector.cs
+++ b/Penumbra/UI/Classes/ModFileSystemSelector.cs
@@ -13,6 +13,7 @@ using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.Numerics;
+using Penumbra.Api.Enums;
namespace Penumbra.UI.Classes;
diff --git a/Penumbra/UI/ConfigWindow.DebugTab.cs b/Penumbra/UI/ConfigWindow.DebugTab.cs
index 8ced65cb..c9cf6284 100644
--- a/Penumbra/UI/ConfigWindow.DebugTab.cs
+++ b/Penumbra/UI/ConfigWindow.DebugTab.cs
@@ -444,11 +444,11 @@ public partial class ConfigWindow
{
if( !ImGui.CollapsingHeader( "IPC" ) )
{
- _window._penumbra.Ipc.Tester.UnsubscribeEvents();
+ _window._penumbra.IpcProviders.Tester.UnsubscribeEvents();
return;
}
- _window._penumbra.Ipc.Tester.Draw();
+ _window._penumbra.IpcProviders.Tester.Draw();
}
// Helper to print a property and its value in a 2-column table.
diff --git a/Penumbra/UI/ConfigWindow.Misc.cs b/Penumbra/UI/ConfigWindow.Misc.cs
index 5b302ade..e767f755 100644
--- a/Penumbra/UI/ConfigWindow.Misc.cs
+++ b/Penumbra/UI/ConfigWindow.Misc.cs
@@ -7,6 +7,7 @@ using Lumina.Data.Parsing;
using Lumina.Excel.GeneratedSheets;
using OtterGui;
using OtterGui.Raii;
+using Penumbra.Api.Enums;
using Penumbra.Collections;
using Penumbra.GameData.ByteString;
using Penumbra.GameData.Enums;
diff --git a/Penumbra/UI/ConfigWindow.ModPanel.Edit.cs b/Penumbra/UI/ConfigWindow.ModPanel.Edit.cs
index e3113bcb..e5948ee8 100644
--- a/Penumbra/UI/ConfigWindow.ModPanel.Edit.cs
+++ b/Penumbra/UI/ConfigWindow.ModPanel.Edit.cs
@@ -8,6 +8,7 @@ using Dalamud.Interface.Components;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
+using Penumbra.Api.Enums;
using Penumbra.Mods;
namespace Penumbra.UI;
@@ -236,7 +237,7 @@ public partial class ConfigWindow
if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Plus.ToIconString(), window._iconButtonSize,
tt, !nameValid, true ) )
{
- Penumbra.ModManager.AddModGroup( mod, SelectType.Single, _newGroupName );
+ Penumbra.ModManager.AddModGroup( mod, GroupType.Single, _newGroupName );
Reset();
}
}
@@ -496,7 +497,7 @@ public partial class ConfigWindow
ImGui.TableNextColumn();
- if( group.Type == SelectType.Single )
+ if( group.Type == GroupType.Single )
{
if( ImGui.RadioButton( "##default", group.DefaultSettings == optionIdx ) )
{
@@ -532,7 +533,7 @@ public partial class ConfigWindow
}
ImGui.TableNextColumn();
- if( group.Type == SelectType.Multi )
+ if( group.Type == GroupType.Multi )
{
if( Input.Priority( "##Priority", groupIdx, optionIdx, group.OptionPriority( optionIdx ), out var priority,
50 * ImGuiHelpers.GlobalScale ) )
@@ -564,7 +565,7 @@ public partial class ConfigWindow
}
ImGui.TableNextColumn();
- var canAddGroup = mod.Groups[ groupIdx ].Type != SelectType.Multi || mod.Groups[ groupIdx ].Count < IModGroup.MaxMultiOptions;
+ var canAddGroup = mod.Groups[ groupIdx ].Type != GroupType.Multi || mod.Groups[ groupIdx ].Count < IModGroup.MaxMultiOptions;
var validName = _newOptionName.Length > 0 && _newOptionNameIdx == groupIdx;
var tt = canAddGroup
? validName ? "Add a new option to this group." : "Please enter a name for the new option."
@@ -636,11 +637,11 @@ public partial class ConfigWindow
// Draw a combo to select single or multi group and switch between them.
private void DrawGroupCombo( IModGroup group, int groupIdx )
{
- static string GroupTypeName( SelectType type )
+ static string GroupTypeName( GroupType type )
=> type switch
{
- SelectType.Single => "Single Group",
- SelectType.Multi => "Multi Group",
+ GroupType.Single => "Single Group",
+ GroupType.Multi => "Multi Group",
_ => "Unknown",
};
@@ -651,16 +652,16 @@ public partial class ConfigWindow
return;
}
- if( ImGui.Selectable( GroupTypeName( SelectType.Single ), group.Type == SelectType.Single ) )
+ if( ImGui.Selectable( GroupTypeName( GroupType.Single ), group.Type == GroupType.Single ) )
{
- Penumbra.ModManager.ChangeModGroupType( _mod, groupIdx, SelectType.Single );
+ Penumbra.ModManager.ChangeModGroupType( _mod, groupIdx, GroupType.Single );
}
var canSwitchToMulti = group.Count <= IModGroup.MaxMultiOptions;
using var style = ImRaii.PushStyle( ImGuiStyleVar.Alpha, 0.5f, !canSwitchToMulti );
- if( ImGui.Selectable( GroupTypeName( SelectType.Multi ), group.Type == SelectType.Multi ) && canSwitchToMulti )
+ if( ImGui.Selectable( GroupTypeName( GroupType.Multi ), group.Type == GroupType.Multi ) && canSwitchToMulti )
{
- Penumbra.ModManager.ChangeModGroupType( _mod, groupIdx, SelectType.Multi );
+ Penumbra.ModManager.ChangeModGroupType( _mod, groupIdx, GroupType.Multi );
}
style.Pop();
diff --git a/Penumbra/UI/ConfigWindow.ModPanel.Settings.cs b/Penumbra/UI/ConfigWindow.ModPanel.Settings.cs
index 6c5582b8..feacb0bc 100644
--- a/Penumbra/UI/ConfigWindow.ModPanel.Settings.cs
+++ b/Penumbra/UI/ConfigWindow.ModPanel.Settings.cs
@@ -5,6 +5,7 @@ using OtterGui;
using OtterGui.Classes;
using OtterGui.Raii;
using OtterGui.Widgets;
+using Penumbra.Api.Enums;
using Penumbra.Collections;
using Penumbra.Mods;
using Penumbra.UI.Classes;
@@ -154,7 +155,7 @@ public partial class ConfigWindow
// If a description is provided, add a help marker besides it.
private void DrawSingleGroup( IModGroup group, int groupIdx )
{
- if( group.Type != SelectType.Single || !group.IsOption )
+ if( group.Type != GroupType.Single || !group.IsOption )
{
return;
}
@@ -193,7 +194,7 @@ public partial class ConfigWindow
// If a description is provided, add a help marker in the title.
private void DrawMultiGroup( IModGroup group, int groupIdx )
{
- if( group.Type != SelectType.Multi || !group.IsOption )
+ if( group.Type != GroupType.Multi || !group.IsOption )
{
return;
}
diff --git a/Penumbra/UI/ConfigWindow.ModsTab.cs b/Penumbra/UI/ConfigWindow.ModsTab.cs
index 35b01d19..ba88c75d 100644
--- a/Penumbra/UI/ConfigWindow.ModsTab.cs
+++ b/Penumbra/UI/ConfigWindow.ModsTab.cs
@@ -8,6 +8,7 @@ using System;
using System.Linq;
using System.Numerics;
using Dalamud.Interface;
+using Penumbra.Api.Enums;
using Penumbra.GameData.Enums;
namespace Penumbra.UI;
diff --git a/Penumbra/packages.lock.json b/Penumbra/packages.lock.json
index 3b072b89..b68a4adc 100644
--- a/Penumbra/packages.lock.json
+++ b/Penumbra/packages.lock.json
@@ -58,26 +58,17 @@
"System.ValueTuple": "4.5.0"
}
},
- "DirectXTex": {
- "type": "Project"
- },
- "directxtexc": {
- "type": "Project",
- "dependencies": {
- "DirectXTex": "[1.0.0, )"
- }
- },
"ottergui": {
"type": "Project"
},
- "ottertex": {
- "type": "Project",
- "dependencies": {
- "DirectXTexC": "[1.0.0, )"
- }
+ "penumbra.api": {
+ "type": "Project"
},
"penumbra.gamedata": {
- "type": "Project"
+ "type": "Project",
+ "dependencies": {
+ "Penumbra.Api": "[1.0.0, )"
+ }
}
}
}
diff --git a/tmp/.editorconfig b/tmp/.editorconfig
new file mode 100644
index 00000000..238bb1dc
--- /dev/null
+++ b/tmp/.editorconfig
@@ -0,0 +1,85 @@
+
+[*]
+charset=utf-8
+end_of_line=lf
+trim_trailing_whitespace=true
+insert_final_newline=false
+indent_style=space
+indent_size=4
+
+# Microsoft .NET properties
+csharp_new_line_before_members_in_object_initializers=false
+csharp_preferred_modifier_order=public, private, protected, internal, new, abstract, virtual, sealed, override, static, readonly, extern, unsafe, volatile, async:suggestion
+csharp_prefer_braces=true:none
+csharp_space_after_cast=false
+csharp_space_after_keywords_in_control_flow_statements=false
+csharp_space_between_method_call_parameter_list_parentheses=true
+csharp_space_between_method_declaration_parameter_list_parentheses=true
+csharp_space_between_parentheses=control_flow_statements,expressions,type_casts
+csharp_style_var_elsewhere=true:suggestion
+csharp_style_var_for_built_in_types=true:suggestion
+csharp_style_var_when_type_is_apparent=true:suggestion
+dotnet_style_parentheses_in_arithmetic_binary_operators=never_if_unnecessary:none
+dotnet_style_parentheses_in_other_binary_operators=never_if_unnecessary:none
+dotnet_style_parentheses_in_relational_binary_operators=never_if_unnecessary:none
+dotnet_style_predefined_type_for_locals_parameters_members=true:suggestion
+dotnet_style_predefined_type_for_member_access=true:suggestion
+dotnet_style_qualification_for_event=false:suggestion
+dotnet_style_qualification_for_field=false:suggestion
+dotnet_style_qualification_for_method=false:suggestion
+dotnet_style_qualification_for_property=false:suggestion
+dotnet_style_require_accessibility_modifiers=for_non_interface_members:suggestion
+
+# ReSharper properties
+resharper_align_multiline_binary_expressions_chain=false
+resharper_align_multiline_calls_chain=false
+resharper_autodetect_indent_settings=true
+resharper_braces_redundant=true
+resharper_constructor_or_destructor_body=expression_body
+resharper_csharp_empty_block_style=together
+resharper_csharp_max_line_length=180
+resharper_csharp_space_within_array_access_brackets=true
+resharper_enforce_line_ending_style=true
+resharper_int_align_assignments=true
+resharper_int_align_comments=true
+resharper_int_align_fields=true
+resharper_int_align_invocations=false
+resharper_int_align_nested_ternary=true
+resharper_int_align_properties=false
+resharper_int_align_switch_expressions=true
+resharper_int_align_switch_sections=true
+resharper_int_align_variables=true
+resharper_local_function_body=expression_body
+resharper_method_or_operator_body=expression_body
+resharper_place_attribute_on_same_line=false
+resharper_space_after_cast=false
+resharper_space_within_checked_parentheses=true
+resharper_space_within_default_parentheses=true
+resharper_space_within_nameof_parentheses=true
+resharper_space_within_single_line_array_initializer_braces=true
+resharper_space_within_sizeof_parentheses=true
+resharper_space_within_typeof_parentheses=true
+resharper_space_within_type_argument_angles=true
+resharper_space_within_type_parameter_angles=true
+resharper_use_indent_from_vs=false
+resharper_wrap_lines=true
+
+# ReSharper inspection severities
+resharper_arrange_redundant_parentheses_highlighting=hint
+resharper_arrange_this_qualifier_highlighting=hint
+resharper_arrange_type_member_modifiers_highlighting=hint
+resharper_arrange_type_modifiers_highlighting=hint
+resharper_built_in_type_reference_style_for_member_access_highlighting=hint
+resharper_built_in_type_reference_style_highlighting=hint
+resharper_redundant_base_qualifier_highlighting=warning
+resharper_suggest_var_or_type_built_in_types_highlighting=hint
+resharper_suggest_var_or_type_elsewhere_highlighting=hint
+resharper_suggest_var_or_type_simple_types_highlighting=hint
+resharper_web_config_module_not_resolved_highlighting=warning
+resharper_web_config_type_not_resolved_highlighting=warning
+resharper_web_config_wrong_module_highlighting=warning
+
+[*.{appxmanifest,asax,ascx,aspx,build,cg,cginc,compute,cs,cshtml,dtd,hlsl,hlsli,hlslinc,master,nuspec,razor,resw,resx,shader,skin,usf,ush,vb,xaml,xamlx,xoml,xsd}]
+indent_style=space
+indent_size=4
+tab_width=4
diff --git a/tmp/.gitignore b/tmp/.gitignore
new file mode 100644
index 00000000..3e168525
--- /dev/null
+++ b/tmp/.gitignore
@@ -0,0 +1,3 @@
+bin/
+obj/
+.vs/
\ No newline at end of file
diff --git a/tmp/Delegates.cs b/tmp/Delegates.cs
new file mode 100644
index 00000000..97726e81
--- /dev/null
+++ b/tmp/Delegates.cs
@@ -0,0 +1,16 @@
+using System;
+using Penumbra.Api.Enums;
+
+namespace Penumbra.Api;
+
+// Delegates used by different events.
+public delegate void ChangedItemHover( object? item );
+public delegate void ChangedItemClick( MouseButton button, object? item );
+public delegate void GameObjectRedrawn( IntPtr objectPtr, int objectTableIndex );
+public delegate void ModSettingChanged( ModSettingChange type, string collectionName, string modDirectory, bool inherited );
+
+public delegate void CreatingCharacterBaseDelegate( IntPtr gameObject, string collectionName, IntPtr modelId, IntPtr customize,
+ IntPtr equipData );
+
+public delegate void CreatedCharacterBaseDelegate( IntPtr gameObject, string collectionName, IntPtr drawObject );
+public delegate void GameObjectResourceResolvedDelegate( IntPtr gameObject, string gamePath, string localPath );
\ No newline at end of file
diff --git a/tmp/Enums/ChangedItemType.cs b/tmp/Enums/ChangedItemType.cs
new file mode 100644
index 00000000..5cc1b5a7
--- /dev/null
+++ b/tmp/Enums/ChangedItemType.cs
@@ -0,0 +1,9 @@
+namespace Penumbra.Api.Enums;
+
+public enum ChangedItemType
+{
+ None,
+ Item,
+ Action,
+ Customization,
+}
\ No newline at end of file
diff --git a/tmp/Enums/GroupType.cs b/tmp/Enums/GroupType.cs
new file mode 100644
index 00000000..65a8ed39
--- /dev/null
+++ b/tmp/Enums/GroupType.cs
@@ -0,0 +1,7 @@
+namespace Penumbra.Api.Enums;
+
+public enum GroupType
+{
+ Single,
+ Multi,
+}
\ No newline at end of file
diff --git a/tmp/Enums/ModSettingChange.cs b/tmp/Enums/ModSettingChange.cs
new file mode 100644
index 00000000..5e556d50
--- /dev/null
+++ b/tmp/Enums/ModSettingChange.cs
@@ -0,0 +1,12 @@
+namespace Penumbra.Api.Enums;
+
+// Different types a mod setting can change:
+public enum ModSettingChange
+{
+ Inheritance, // it was set to inherit from other collections or not inherit anymore
+ EnableState, // it was enabled or disabled
+ Priority, // its priority was changed
+ Setting, // a specific setting was changed
+ MultiInheritance, // multiple mods were set to inherit from other collections or not inherit anymore.
+ MultiEnableState, // multiple mods were enabled or disabled at once.
+}
\ No newline at end of file
diff --git a/tmp/Enums/MouseButton.cs b/tmp/Enums/MouseButton.cs
new file mode 100644
index 00000000..2917c0f8
--- /dev/null
+++ b/tmp/Enums/MouseButton.cs
@@ -0,0 +1,9 @@
+namespace Penumbra.Api.Enums;
+
+public enum MouseButton
+{
+ None,
+ Left,
+ Right,
+ Middle,
+}
\ No newline at end of file
diff --git a/tmp/Enums/PenumbraApiEc.cs b/tmp/Enums/PenumbraApiEc.cs
new file mode 100644
index 00000000..a37aefa8
--- /dev/null
+++ b/tmp/Enums/PenumbraApiEc.cs
@@ -0,0 +1,20 @@
+namespace Penumbra.Api.Enums;
+
+public enum PenumbraApiEc
+{
+ Success = 0,
+ NothingChanged = 1,
+ CollectionMissing = 2,
+ ModMissing = 3,
+ OptionGroupMissing = 4,
+ OptionMissing = 5,
+
+ CharacterCollectionExists = 6,
+ LowerPriority = 7,
+ InvalidGamePath = 8,
+ FileMissing = 9,
+ InvalidManipulation = 10,
+ InvalidArgument = 11,
+ PathRenameFailed = 12,
+ UnknownError = 255,
+}
\ No newline at end of file
diff --git a/Penumbra.GameData/Enums/RedrawType.cs b/tmp/Enums/RedrawType.cs
similarity index 61%
rename from Penumbra.GameData/Enums/RedrawType.cs
rename to tmp/Enums/RedrawType.cs
index 4b698377..0295554f 100644
--- a/Penumbra.GameData/Enums/RedrawType.cs
+++ b/tmp/Enums/RedrawType.cs
@@ -1,4 +1,4 @@
-namespace Penumbra.GameData.Enums;
+namespace Penumbra.Api.Enums;
public enum RedrawType
{
diff --git a/tmp/Helpers/ActionProvider.cs b/tmp/Helpers/ActionProvider.cs
new file mode 100644
index 00000000..c070dca8
--- /dev/null
+++ b/tmp/Helpers/ActionProvider.cs
@@ -0,0 +1,66 @@
+using System;
+using Dalamud.Logging;
+using Dalamud.Plugin;
+using Dalamud.Plugin.Ipc;
+
+namespace Penumbra.Api.Helpers;
+
+public sealed class ActionProvider : IDisposable
+{
+ private ICallGateProvider? _provider;
+
+ public ActionProvider( DalamudPluginInterface pi, string label, Action action )
+ {
+ try
+ {
+ _provider = pi.GetIpcProvider( label );
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Provider for {label}\n{e}" );
+ _provider = null;
+ }
+
+ _provider?.RegisterAction( action );
+ }
+
+ public void Dispose()
+ {
+ _provider?.UnregisterAction();
+ _provider = null;
+ GC.SuppressFinalize( this );
+ }
+
+ ~ActionProvider()
+ => Dispose();
+}
+
+public sealed class ActionProvider< T1, T2 > : IDisposable
+{
+ private ICallGateProvider< T1, T2, object? >? _provider;
+
+ public ActionProvider( DalamudPluginInterface pi, string label, Action< T1, T2 > action )
+ {
+ try
+ {
+ _provider = pi.GetIpcProvider< T1, T2, object? >( label );
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Provider for {label}\n{e}" );
+ _provider = null;
+ }
+
+ _provider?.RegisterAction( action );
+ }
+
+ public void Dispose()
+ {
+ _provider?.UnregisterAction();
+ _provider = null;
+ GC.SuppressFinalize( this );
+ }
+
+ ~ActionProvider()
+ => Dispose();
+}
\ No newline at end of file
diff --git a/tmp/Helpers/ActionSubscriber.cs b/tmp/Helpers/ActionSubscriber.cs
new file mode 100644
index 00000000..e924e4eb
--- /dev/null
+++ b/tmp/Helpers/ActionSubscriber.cs
@@ -0,0 +1,54 @@
+using System;
+using Dalamud.Logging;
+using Dalamud.Plugin;
+using Dalamud.Plugin.Ipc;
+
+namespace Penumbra.Api.Helpers;
+
+public readonly struct ActionSubscriber< T1 >
+{
+ private readonly ICallGateSubscriber< T1, object? >? _subscriber;
+
+ public bool Valid
+ => _subscriber != null;
+
+ public ActionSubscriber( DalamudPluginInterface pi, string label )
+ {
+ try
+ {
+ _subscriber = pi.GetIpcSubscriber< T1, object? >( label );
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Subscriber for {label}\n{e}" );
+ _subscriber = null;
+ }
+ }
+
+ public void Invoke( T1 a )
+ => _subscriber?.InvokeAction( a );
+}
+
+public readonly struct ActionSubscriber< T1, T2 >
+{
+ private readonly ICallGateSubscriber< T1, T2, object? >? _subscriber;
+
+ public bool Valid
+ => _subscriber != null;
+
+ public ActionSubscriber( DalamudPluginInterface pi, string label )
+ {
+ try
+ {
+ _subscriber = pi.GetIpcSubscriber< T1, T2, object? >( label );
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Subscriber for {label}\n{e}" );
+ _subscriber = null;
+ }
+ }
+
+ public void Invoke( T1 a, T2 b )
+ => _subscriber?.InvokeAction( a, b );
+}
\ No newline at end of file
diff --git a/tmp/Helpers/EventProvider.cs b/tmp/Helpers/EventProvider.cs
new file mode 100644
index 00000000..b623d41e
--- /dev/null
+++ b/tmp/Helpers/EventProvider.cs
@@ -0,0 +1,376 @@
+using System;
+using Dalamud.Logging;
+using Dalamud.Plugin;
+using Dalamud.Plugin.Ipc;
+
+namespace Penumbra.Api.Helpers;
+
+public sealed class EventProvider : IDisposable
+{
+ private ICallGateProvider< object? >? _provider;
+ private Delegate? _unsubscriber;
+
+ public EventProvider( DalamudPluginInterface pi, string label, (Action< Action > Add, Action< Action > Del)? subscribe = null )
+ {
+ _unsubscriber = null;
+ try
+ {
+ _provider = pi.GetIpcProvider< object? >( label );
+ subscribe?.Add( Invoke );
+ _unsubscriber = subscribe?.Del;
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Provider for {label}\n{e}" );
+ _provider = null;
+ }
+ }
+
+ public EventProvider( DalamudPluginInterface pi, string label, Action add, Action del )
+ {
+ _unsubscriber = null;
+ try
+ {
+ _provider = pi.GetIpcProvider< object? >( label );
+ add();
+ _unsubscriber = del;
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Provider for {label}\n{e}" );
+ _provider = null;
+ }
+ }
+
+ public void Invoke()
+ => _provider?.SendMessage();
+
+ public void Dispose()
+ {
+ switch( _unsubscriber )
+ {
+ case Action< Action > a:
+ a( Invoke );
+ break;
+ case Action b:
+ b();
+ break;
+ }
+
+ _unsubscriber = null;
+ _provider = null;
+ GC.SuppressFinalize( this );
+ }
+
+ ~EventProvider()
+ => Dispose();
+}
+
+public sealed class EventProvider< T1 > : IDisposable
+{
+ private ICallGateProvider< T1, object? >? _provider;
+ private Delegate? _unsubscriber;
+
+ public EventProvider( DalamudPluginInterface pi, string label, (Action< Action< T1 > > Add, Action< Action< T1 > > Del)? subscribe = null )
+ {
+ _unsubscriber = null;
+ try
+ {
+ _provider = pi.GetIpcProvider< T1, object? >( label );
+ subscribe?.Add( Invoke );
+ _unsubscriber = subscribe?.Del;
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Provider for {label}\n{e}" );
+ _provider = null;
+ }
+ }
+
+ public EventProvider( DalamudPluginInterface pi, string label, Action add, Action del )
+ {
+ _unsubscriber = null;
+ try
+ {
+ _provider = pi.GetIpcProvider< T1, object? >( label );
+ add();
+ _unsubscriber = del;
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Provider for {label}\n{e}" );
+ _provider = null;
+ }
+ }
+
+ public void Invoke( T1 a )
+ => _provider?.SendMessage( a );
+
+ public void Dispose()
+ {
+ switch( _unsubscriber )
+ {
+ case Action< Action< T1 > > a:
+ a( Invoke );
+ break;
+ case Action b:
+ b();
+ break;
+ }
+
+ _unsubscriber = null;
+ _provider = null;
+ GC.SuppressFinalize( this );
+ }
+
+ ~EventProvider()
+ => Dispose();
+}
+
+public sealed class EventProvider< T1, T2 > : IDisposable
+{
+ private ICallGateProvider< T1, T2, object? >? _provider;
+ private Delegate? _unsubscriber;
+
+ public EventProvider( DalamudPluginInterface pi, string label,
+ (Action< Action< T1, T2 > > Add, Action< Action< T1, T2 > > Del)? subscribe = null )
+ {
+ _unsubscriber = null;
+ try
+ {
+ _provider = pi.GetIpcProvider< T1, T2, object? >( label );
+ subscribe?.Add( Invoke );
+ _unsubscriber = subscribe?.Del;
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Provider for {label}\n{e}" );
+ _provider = null;
+ }
+ }
+
+ public EventProvider( DalamudPluginInterface pi, string label, Action add, Action del )
+ {
+ _unsubscriber = null;
+ try
+ {
+ _provider = pi.GetIpcProvider< T1, T2, object? >( label );
+ add();
+ _unsubscriber = del;
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Provider for {label}\n{e}" );
+ _provider = null;
+ }
+ }
+
+ public void Invoke( T1 a, T2 b )
+ => _provider?.SendMessage( a, b );
+
+ public void Dispose()
+ {
+ switch( _unsubscriber )
+ {
+ case Action< Action< T1, T2 > > a:
+ a( Invoke );
+ break;
+ case Action b:
+ b();
+ break;
+ }
+
+ _unsubscriber = null;
+ _provider = null;
+ GC.SuppressFinalize( this );
+ }
+
+ ~EventProvider()
+ => Dispose();
+}
+
+public sealed class EventProvider< T1, T2, T3 > : IDisposable
+{
+ private ICallGateProvider< T1, T2, T3, object? >? _provider;
+ private Delegate? _unsubscriber;
+
+ public EventProvider( DalamudPluginInterface pi, string label,
+ (Action< Action< T1, T2, T3 > > Add, Action< Action< T1, T2, T3 > > Del)? subscribe = null )
+ {
+ _unsubscriber = null;
+ try
+ {
+ _provider = pi.GetIpcProvider< T1, T2, T3, object? >( label );
+ subscribe?.Add( Invoke );
+ _unsubscriber = subscribe?.Del;
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Provider for {label}\n{e}" );
+ _provider = null;
+ }
+ }
+
+ public EventProvider( DalamudPluginInterface pi, string label, Action add, Action del )
+ {
+ _unsubscriber = null;
+ try
+ {
+ _provider = pi.GetIpcProvider< T1, T2, T3, object? >( label );
+ add();
+ _unsubscriber = del;
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Provider for {label}\n{e}" );
+ _provider = null;
+ }
+ }
+
+ public void Invoke( T1 a, T2 b, T3 c )
+ => _provider?.SendMessage( a, b, c );
+
+ public void Dispose()
+ {
+ switch( _unsubscriber )
+ {
+ case Action< Action< T1, T2, T3 > > a:
+ a( Invoke );
+ break;
+ case Action b:
+ b();
+ break;
+ }
+
+ _unsubscriber = null;
+ _provider = null;
+ GC.SuppressFinalize( this );
+ }
+
+ ~EventProvider()
+ => Dispose();
+}
+
+public sealed class EventProvider< T1, T2, T3, T4 > : IDisposable
+{
+ private ICallGateProvider< T1, T2, T3, T4, object? >? _provider;
+ private Delegate? _unsubscriber;
+
+ public EventProvider( DalamudPluginInterface pi, string label,
+ (Action< Action< T1, T2, T3, T4 > > Add, Action< Action< T1, T2, T3, T4 > > Del)? subscribe = null )
+ {
+ _unsubscriber = null;
+ try
+ {
+ _provider = pi.GetIpcProvider< T1, T2, T3, T4, object? >( label );
+ subscribe?.Add( Invoke );
+ _unsubscriber = subscribe?.Del;
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Provider for {label}\n{e}" );
+ _provider = null;
+ }
+ }
+
+ public EventProvider( DalamudPluginInterface pi, string label, Action add, Action del )
+ {
+ _unsubscriber = null;
+ try
+ {
+ _provider = pi.GetIpcProvider< T1, T2, T3, T4, object? >( label );
+ add();
+ _unsubscriber = del;
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Provider for {label}\n{e}" );
+ _provider = null;
+ }
+ }
+
+ public void Invoke( T1 a, T2 b, T3 c, T4 d )
+ => _provider?.SendMessage( a, b, c, d );
+
+ public void Dispose()
+ {
+ switch( _unsubscriber )
+ {
+ case Action< Action< T1, T2, T3, T4 > > a:
+ a( Invoke );
+ break;
+ case Action b:
+ b();
+ break;
+ }
+
+ _unsubscriber = null;
+ _provider = null;
+ GC.SuppressFinalize( this );
+ }
+
+ ~EventProvider()
+ => Dispose();
+}
+
+public sealed class EventProvider< T1, T2, T3, T4, T5 > : IDisposable
+{
+ private ICallGateProvider< T1, T2, T3, T4, T5, object? >? _provider;
+ private Delegate? _unsubscriber;
+
+ public EventProvider( DalamudPluginInterface pi, string label,
+ (Action< Action< T1, T2, T3, T4, T5 > > Add, Action< Action< T1, T2, T3, T4, T5 > > Del)? subscribe = null )
+ {
+ _unsubscriber = null;
+ try
+ {
+ _provider = pi.GetIpcProvider< T1, T2, T3, T4, T5, object? >( label );
+ subscribe?.Add( Invoke );
+ _unsubscriber = subscribe?.Del;
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Provider for {label}\n{e}" );
+ _provider = null;
+ }
+ }
+
+ public EventProvider( DalamudPluginInterface pi, string label, Action add, Action del )
+ {
+ _unsubscriber = null;
+ try
+ {
+ _provider = pi.GetIpcProvider< T1, T2, T3, T4, T5, object? >( label );
+ add();
+ _unsubscriber = del;
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Provider for {label}\n{e}" );
+ _provider = null;
+ }
+ }
+
+ public void Invoke( T1 a, T2 b, T3 c, T4 d, T5 e )
+ => _provider?.SendMessage( a, b, c, d, e );
+
+ public void Dispose()
+ {
+ switch( _unsubscriber )
+ {
+ case Action< Action< T1, T2, T3, T4, T5 > > a:
+ a( Invoke );
+ break;
+ case Action b:
+ b();
+ break;
+ }
+
+ _unsubscriber = null;
+ _provider = null;
+ GC.SuppressFinalize( this );
+ }
+
+ ~EventProvider()
+ => Dispose();
+}
\ No newline at end of file
diff --git a/tmp/Helpers/EventSubscriber.cs b/tmp/Helpers/EventSubscriber.cs
new file mode 100644
index 00000000..0df6bc11
--- /dev/null
+++ b/tmp/Helpers/EventSubscriber.cs
@@ -0,0 +1,607 @@
+using System;
+using System.Collections.Generic;
+using Dalamud.Logging;
+using Dalamud.Plugin;
+using Dalamud.Plugin.Ipc;
+
+namespace Penumbra.Api.Helpers;
+
+public sealed class EventSubscriber : IDisposable
+{
+ private readonly string _label;
+ private readonly Dictionary< Action, Action > _delegates = new();
+ private ICallGateSubscriber< object? >? _subscriber;
+ private bool _disabled;
+
+ public EventSubscriber( DalamudPluginInterface pi, string label, params Action[] actions )
+ {
+ _label = label;
+ try
+ {
+ _subscriber = pi.GetIpcSubscriber< object? >( label );
+ foreach( var action in actions )
+ {
+ Event += action;
+ }
+
+ _disabled = false;
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Subscriber for {label}\n{e}" );
+ _subscriber = null;
+ }
+ }
+
+ public void Enable()
+ {
+ if( _disabled && _subscriber != null )
+ {
+ foreach( var action in _delegates.Keys )
+ {
+ _subscriber.Subscribe( action );
+ }
+
+ _disabled = false;
+ }
+ }
+
+ public void Disable()
+ {
+ if( !_disabled )
+ {
+ if( _subscriber != null )
+ {
+ foreach( var action in _delegates.Keys )
+ {
+ _subscriber.Unsubscribe( action );
+ }
+ }
+
+ _disabled = true;
+ }
+ }
+
+ public event Action Event
+ {
+ add
+ {
+ if( _subscriber != null && !_delegates.ContainsKey( value ) )
+ {
+ void Action()
+ {
+ try
+ {
+ value();
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Exception invoking IPC event {_label}:\n{e}" );
+ }
+ }
+
+ if( _delegates.TryAdd( value, Action ) && !_disabled )
+ {
+ _subscriber.Subscribe( Action );
+ }
+ }
+ }
+ remove
+ {
+ if( _subscriber != null && _delegates.Remove( value, out var action ) )
+ {
+ _subscriber.Unsubscribe( action );
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ Disable();
+ _subscriber = null;
+ _delegates.Clear();
+ }
+
+ ~EventSubscriber()
+ => Dispose();
+}
+
+public sealed class EventSubscriber< T1 > : IDisposable
+{
+ private readonly string _label;
+ private readonly Dictionary< Action< T1 >, Action< T1 > > _delegates = new();
+ private ICallGateSubscriber< T1, object? >? _subscriber;
+ private bool _disabled;
+
+ public EventSubscriber( DalamudPluginInterface pi, string label, params Action< T1 >[] actions )
+ {
+ _label = label;
+ try
+ {
+ _subscriber = pi.GetIpcSubscriber< T1, object? >( label );
+ foreach( var action in actions )
+ {
+ Event += action;
+ }
+
+ _disabled = false;
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Subscriber for {label}\n{e}" );
+ _subscriber = null;
+ }
+ }
+
+ public void Enable()
+ {
+ if( _disabled && _subscriber != null )
+ {
+ foreach( var action in _delegates.Keys )
+ {
+ _subscriber.Subscribe( action );
+ }
+
+ _disabled = false;
+ }
+ }
+
+ public void Disable()
+ {
+ if( !_disabled )
+ {
+ if( _subscriber != null )
+ {
+ foreach( var action in _delegates.Keys )
+ {
+ _subscriber.Unsubscribe( action );
+ }
+ }
+
+ _disabled = true;
+ }
+ }
+
+ public event Action< T1 > Event
+ {
+ add
+ {
+ if( _subscriber != null && !_delegates.ContainsKey( value ) )
+ {
+ void Action( T1 a )
+ {
+ try
+ {
+ value( a );
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Exception invoking IPC event {_label}:\n{e}" );
+ }
+ }
+
+ if( _delegates.TryAdd( value, Action ) && !_disabled )
+ {
+ _subscriber.Subscribe( Action );
+ }
+ }
+ }
+ remove
+ {
+ if( _subscriber != null && _delegates.Remove( value, out var action ) )
+ {
+ _subscriber.Unsubscribe( action );
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ Disable();
+ _subscriber = null;
+ _delegates.Clear();
+ }
+
+ ~EventSubscriber()
+ => Dispose();
+}
+
+public sealed class EventSubscriber< T1, T2 > : IDisposable
+{
+ private readonly string _label;
+ private readonly Dictionary< Action< T1, T2 >, Action< T1, T2 > > _delegates = new();
+ private ICallGateSubscriber< T1, T2, object? >? _subscriber;
+ private bool _disabled;
+
+ public EventSubscriber( DalamudPluginInterface pi, string label, params Action< T1, T2 >[] actions )
+ {
+ _label = label;
+ try
+ {
+ _subscriber = pi.GetIpcSubscriber< T1, T2, object? >( label );
+ foreach( var action in actions )
+ {
+ Event += action;
+ }
+
+ _disabled = false;
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Subscriber for {label}\n{e}" );
+ _subscriber = null;
+ }
+ }
+
+ public void Enable()
+ {
+ if( _disabled && _subscriber != null )
+ {
+ foreach( var action in _delegates.Keys )
+ {
+ _subscriber.Subscribe( action );
+ }
+
+ _disabled = false;
+ }
+ }
+
+ public void Disable()
+ {
+ if( !_disabled )
+ {
+ if( _subscriber != null )
+ {
+ foreach( var action in _delegates.Keys )
+ {
+ _subscriber.Unsubscribe( action );
+ }
+ }
+
+ _disabled = true;
+ }
+ }
+
+ public event Action< T1, T2 > Event
+ {
+ add
+ {
+ if( _subscriber != null && !_delegates.ContainsKey( value ) )
+ {
+ void Action( T1 a, T2 b )
+ {
+ try
+ {
+ value( a, b );
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Exception invoking IPC event {_label}:\n{e}" );
+ }
+ }
+
+ if( _delegates.TryAdd( value, Action ) && !_disabled )
+ {
+ _subscriber.Subscribe( Action );
+ }
+ }
+ }
+ remove
+ {
+ if( _subscriber != null && _delegates.Remove( value, out var action ) )
+ {
+ _subscriber.Unsubscribe( action );
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ Disable();
+ _subscriber = null;
+ _delegates.Clear();
+ }
+
+ ~EventSubscriber()
+ => Dispose();
+}
+
+public sealed class EventSubscriber< T1, T2, T3 > : IDisposable
+{
+ private readonly string _label;
+ private readonly Dictionary< Action< T1, T2, T3 >, Action< T1, T2, T3 > > _delegates = new();
+ private ICallGateSubscriber< T1, T2, T3, object? >? _subscriber;
+ private bool _disabled;
+
+ public EventSubscriber( DalamudPluginInterface pi, string label, params Action< T1, T2, T3 >[] actions )
+ {
+ _label = label;
+ try
+ {
+ _subscriber = pi.GetIpcSubscriber< T1, T2, T3, object? >( label );
+ foreach( var action in actions )
+ {
+ Event += action;
+ }
+
+ _disabled = false;
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Subscriber for {label}\n{e}" );
+ _subscriber = null;
+ }
+ }
+
+ public void Enable()
+ {
+ if( _disabled && _subscriber != null )
+ {
+ foreach( var action in _delegates.Keys )
+ {
+ _subscriber.Subscribe( action );
+ }
+
+ _disabled = false;
+ }
+ }
+
+ public void Disable()
+ {
+ if( !_disabled )
+ {
+ if( _subscriber != null )
+ {
+ foreach( var action in _delegates.Keys )
+ {
+ _subscriber.Unsubscribe( action );
+ }
+ }
+
+ _disabled = true;
+ }
+ }
+
+ public event Action< T1, T2, T3 > Event
+ {
+ add
+ {
+ if( _subscriber != null && !_delegates.ContainsKey( value ) )
+ {
+ void Action( T1 a, T2 b, T3 c )
+ {
+ try
+ {
+ value( a, b, c );
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Exception invoking IPC event {_label}:\n{e}" );
+ }
+ }
+
+ if( _delegates.TryAdd( value, Action ) && !_disabled )
+ {
+ _subscriber.Subscribe( Action );
+ }
+ }
+ }
+ remove
+ {
+ if( _subscriber != null && _delegates.Remove( value, out var action ) )
+ {
+ _subscriber.Unsubscribe( action );
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ Disable();
+ _subscriber = null;
+ _delegates.Clear();
+ }
+
+ ~EventSubscriber()
+ => Dispose();
+}
+
+public sealed class EventSubscriber< T1, T2, T3, T4 > : IDisposable
+{
+ private readonly string _label;
+ private readonly Dictionary< Action< T1, T2, T3, T4 >, Action< T1, T2, T3, T4 > > _delegates = new();
+ private ICallGateSubscriber< T1, T2, T3, T4, object? >? _subscriber;
+ private bool _disabled;
+
+ public EventSubscriber( DalamudPluginInterface pi, string label, params Action< T1, T2, T3, T4 >[] actions )
+ {
+ _label = label;
+ try
+ {
+ _subscriber = pi.GetIpcSubscriber< T1, T2, T3, T4, object? >( label );
+ foreach( var action in actions )
+ {
+ Event += action;
+ }
+
+ _disabled = false;
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Subscriber for {label}\n{e}" );
+ _subscriber = null;
+ }
+ }
+
+ public void Enable()
+ {
+ if( _disabled && _subscriber != null )
+ {
+ foreach( var action in _delegates.Keys )
+ {
+ _subscriber.Subscribe( action );
+ }
+
+ _disabled = false;
+ }
+ }
+
+ public void Disable()
+ {
+ if( !_disabled )
+ {
+ if( _subscriber != null )
+ {
+ foreach( var action in _delegates.Keys )
+ {
+ _subscriber.Unsubscribe( action );
+ }
+ }
+
+ _disabled = true;
+ }
+ }
+
+ public event Action< T1, T2, T3, T4 > Event
+ {
+ add
+ {
+ if( _subscriber != null && !_delegates.ContainsKey( value ) )
+ {
+ void Action( T1 a, T2 b, T3 c, T4 d )
+ {
+ try
+ {
+ value( a, b, c, d );
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Exception invoking IPC event {_label}:\n{e}" );
+ }
+ }
+
+ if( _delegates.TryAdd( value, Action ) && !_disabled )
+ {
+ _subscriber.Subscribe( Action );
+ }
+ }
+ }
+ remove
+ {
+ if( _subscriber != null && _delegates.Remove( value, out var action ) )
+ {
+ _subscriber.Unsubscribe( action );
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ Disable();
+ _subscriber = null;
+ _delegates.Clear();
+ }
+
+ ~EventSubscriber()
+ => Dispose();
+}
+
+public sealed class EventSubscriber< T1, T2, T3, T4, T5 > : IDisposable
+{
+ private readonly string _label;
+ private readonly Dictionary< Action< T1, T2, T3, T4, T5 >, Action< T1, T2, T3, T4, T5 > > _delegates = new();
+ private ICallGateSubscriber< T1, T2, T3, T4, T5, object? >? _subscriber;
+ private bool _disabled;
+
+ public EventSubscriber( DalamudPluginInterface pi, string label, params Action< T1, T2, T3, T4, T5 >[] actions )
+ {
+ _label = label;
+ try
+ {
+ _subscriber = pi.GetIpcSubscriber< T1, T2, T3, T4, T5, object? >( label );
+ foreach( var action in actions )
+ {
+ Event += action;
+ }
+
+ _disabled = false;
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Subscriber for {label}\n{e}" );
+ _subscriber = null;
+ }
+ }
+
+ public void Enable()
+ {
+ if( _disabled && _subscriber != null )
+ {
+ foreach( var action in _delegates.Keys )
+ {
+ _subscriber.Subscribe( action );
+ }
+
+ _disabled = false;
+ }
+ }
+
+ public void Disable()
+ {
+ if( !_disabled )
+ {
+ if( _subscriber != null )
+ {
+ foreach( var action in _delegates.Keys )
+ {
+ _subscriber.Unsubscribe( action );
+ }
+ }
+
+ _disabled = true;
+ }
+ }
+
+ public event Action< T1, T2, T3, T4, T5 > Event
+ {
+ add
+ {
+ if( _subscriber != null && !_delegates.ContainsKey( value ) )
+ {
+ void Action( T1 a, T2 b, T3 c, T4 d, T5 e )
+ {
+ try
+ {
+ value( a, b, c, d, e );
+ }
+ catch( Exception ex )
+ {
+ PluginLog.Error( $"Exception invoking IPC event {_label}:\n{ex}" );
+ }
+ }
+
+ if( _delegates.TryAdd( value, Action ) && !_disabled )
+ {
+ _subscriber.Subscribe( Action );
+ }
+ }
+ }
+ remove
+ {
+ if( _subscriber != null && _delegates.Remove( value, out var action ) )
+ {
+ _subscriber.Unsubscribe( action );
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ Disable();
+ _subscriber = null;
+ _delegates.Clear();
+ }
+
+ ~EventSubscriber()
+ => Dispose();
+}
\ No newline at end of file
diff --git a/tmp/Helpers/FuncProvider.cs b/tmp/Helpers/FuncProvider.cs
new file mode 100644
index 00000000..fac61ce3
--- /dev/null
+++ b/tmp/Helpers/FuncProvider.cs
@@ -0,0 +1,186 @@
+using System;
+using Dalamud.Logging;
+using Dalamud.Plugin;
+using Dalamud.Plugin.Ipc;
+
+namespace Penumbra.Api.Helpers;
+
+public sealed class FuncProvider< TRet > : IDisposable
+{
+ private ICallGateProvider< TRet >? _provider;
+
+ public FuncProvider( DalamudPluginInterface pi, string label, Func< TRet > func )
+ {
+ try
+ {
+ _provider = pi.GetIpcProvider< TRet >( label );
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Provider for {label}\n{e}" );
+ _provider = null;
+ }
+
+ _provider?.RegisterFunc( func );
+ }
+
+ public void Dispose()
+ {
+ _provider?.UnregisterFunc();
+ _provider = null;
+ GC.SuppressFinalize( this );
+ }
+
+ ~FuncProvider()
+ => Dispose();
+}
+
+public sealed class FuncProvider< T1, TRet > : IDisposable
+{
+ private ICallGateProvider< T1, TRet >? _provider;
+
+ public FuncProvider( DalamudPluginInterface pi, string label, Func< T1, TRet > func )
+ {
+ try
+ {
+ _provider = pi.GetIpcProvider< T1, TRet >( label );
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Provider for {label}\n{e}" );
+ _provider = null;
+ }
+
+ _provider?.RegisterFunc( func );
+ }
+
+ public void Dispose()
+ {
+ _provider?.UnregisterFunc();
+ _provider = null;
+ GC.SuppressFinalize( this );
+ }
+
+ ~FuncProvider()
+ => Dispose();
+}
+
+public sealed class FuncProvider< T1, T2, TRet > : IDisposable
+{
+ private ICallGateProvider< T1, T2, TRet >? _provider;
+
+ public FuncProvider( DalamudPluginInterface pi, string label, Func< T1, T2, TRet > func )
+ {
+ try
+ {
+ _provider = pi.GetIpcProvider< T1, T2, TRet >( label );
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Provider for {label}\n{e}" );
+ _provider = null;
+ }
+
+ _provider?.RegisterFunc( func );
+ }
+
+ public void Dispose()
+ {
+ _provider?.UnregisterFunc();
+ _provider = null;
+ GC.SuppressFinalize( this );
+ }
+
+ ~FuncProvider()
+ => Dispose();
+}
+
+public sealed class FuncProvider< T1, T2, T3, TRet > : IDisposable
+{
+ private ICallGateProvider< T1, T2, T3, TRet >? _provider;
+
+ public FuncProvider( DalamudPluginInterface pi, string label, Func< T1, T2, T3, TRet > func )
+ {
+ try
+ {
+ _provider = pi.GetIpcProvider< T1, T2, T3, TRet >( label );
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Provider for {label}\n{e}" );
+ _provider = null;
+ }
+
+ _provider?.RegisterFunc( func );
+ }
+
+ public void Dispose()
+ {
+ _provider?.UnregisterFunc();
+ _provider = null;
+ GC.SuppressFinalize( this );
+ }
+
+ ~FuncProvider()
+ => Dispose();
+}
+
+public sealed class FuncProvider< T1, T2, T3, T4, TRet > : IDisposable
+{
+ private ICallGateProvider< T1, T2, T3, T4, TRet >? _provider;
+
+ public FuncProvider( DalamudPluginInterface pi, string label, Func< T1, T2, T3, T4, TRet > func )
+ {
+ try
+ {
+ _provider = pi.GetIpcProvider< T1, T2, T3, T4, TRet >( label );
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Provider for {label}\n{e}" );
+ _provider = null;
+ }
+
+ _provider?.RegisterFunc( func );
+ }
+
+ public void Dispose()
+ {
+ _provider?.UnregisterFunc();
+ _provider = null;
+ GC.SuppressFinalize( this );
+ }
+
+ ~FuncProvider()
+ => Dispose();
+}
+
+public sealed class FuncProvider< T1, T2, T3, T4, T5, TRet > : IDisposable
+{
+ private ICallGateProvider< T1, T2, T3, T4, T5, TRet >? _provider;
+
+ public FuncProvider( DalamudPluginInterface pi, string label, Func< T1, T2, T3, T4, T5, TRet > func )
+ {
+ try
+ {
+ _provider = pi.GetIpcProvider< T1, T2, T3, T4, T5, TRet >( label );
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Provider for {label}\n{e}" );
+ _provider = null;
+ }
+
+ _provider?.RegisterFunc( func );
+ }
+
+ public void Dispose()
+ {
+ _provider?.UnregisterFunc();
+ _provider = null;
+ GC.SuppressFinalize( this );
+ }
+
+ ~FuncProvider()
+ => Dispose();
+}
\ No newline at end of file
diff --git a/tmp/Helpers/FuncSubscriber.cs b/tmp/Helpers/FuncSubscriber.cs
new file mode 100644
index 00000000..3f8cbdda
--- /dev/null
+++ b/tmp/Helpers/FuncSubscriber.cs
@@ -0,0 +1,163 @@
+using System;
+using Dalamud.Logging;
+using Dalamud.Plugin;
+using Dalamud.Plugin.Ipc;
+using Dalamud.Plugin.Ipc.Exceptions;
+
+namespace Penumbra.Api.Helpers;
+
+public readonly struct FuncSubscriber< TRet >
+{
+ private readonly string _label;
+ private readonly ICallGateSubscriber< TRet >? _subscriber;
+
+ public bool Valid
+ => _subscriber != null;
+
+ public FuncSubscriber( DalamudPluginInterface pi, string label )
+ {
+ _label = label;
+ try
+ {
+ _subscriber = pi.GetIpcSubscriber< TRet >( label );
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Subscriber for {label}\n{e}" );
+ _subscriber = null;
+ }
+ }
+
+ public TRet Invoke()
+ => _subscriber != null ? _subscriber.InvokeFunc() : throw new IpcNotReadyError( _label );
+}
+
+public readonly struct FuncSubscriber< T1, TRet >
+{
+ private readonly string _label;
+ private readonly ICallGateSubscriber< T1, TRet >? _subscriber;
+
+ public bool Valid
+ => _subscriber != null;
+
+ public FuncSubscriber( DalamudPluginInterface pi, string label )
+ {
+ _label = label;
+ try
+ {
+ _subscriber = pi.GetIpcSubscriber< T1, TRet >( label );
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Subscriber for {label}\n{e}" );
+ _subscriber = null;
+ }
+ }
+
+ public TRet Invoke( T1 a )
+ => _subscriber != null ? _subscriber.InvokeFunc( a ) : throw new IpcNotReadyError( _label );
+}
+
+public readonly struct FuncSubscriber< T1, T2, TRet >
+{
+ private readonly string _label;
+ private readonly ICallGateSubscriber< T1, T2, TRet >? _subscriber;
+
+ public bool Valid
+ => _subscriber != null;
+
+ public FuncSubscriber( DalamudPluginInterface pi, string label )
+ {
+ _label = label;
+ try
+ {
+ _subscriber = pi.GetIpcSubscriber< T1, T2, TRet >( label );
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Subscriber for {label}\n{e}" );
+ _subscriber = null;
+ }
+ }
+
+ public TRet Invoke( T1 a, T2 b )
+ => _subscriber != null ? _subscriber.InvokeFunc( a, b ) : throw new IpcNotReadyError( _label );
+}
+
+public readonly struct FuncSubscriber< T1, T2, T3, TRet >
+{
+ private readonly string _label;
+ private readonly ICallGateSubscriber< T1, T2, T3, TRet >? _subscriber;
+
+ public bool Valid
+ => _subscriber != null;
+
+ public FuncSubscriber( DalamudPluginInterface pi, string label )
+ {
+ _label = label;
+ try
+ {
+ _subscriber = pi.GetIpcSubscriber< T1, T2, T3, TRet >( label );
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Subscriber for {label}\n{e}" );
+ _subscriber = null;
+ }
+ }
+
+ public TRet Invoke( T1 a, T2 b, T3 c )
+ => _subscriber != null ? _subscriber.InvokeFunc( a, b, c ) : throw new IpcNotReadyError( _label );
+}
+
+public readonly struct FuncSubscriber< T1, T2, T3, T4, TRet >
+{
+ private readonly string _label;
+ private readonly ICallGateSubscriber< T1, T2, T3, T4, TRet >? _subscriber;
+
+ public bool Valid
+ => _subscriber != null;
+
+ public FuncSubscriber( DalamudPluginInterface pi, string label )
+ {
+ _label = label;
+ try
+ {
+ _subscriber = pi.GetIpcSubscriber< T1, T2, T3, T4, TRet >( label );
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Subscriber for {label}\n{e}" );
+ _subscriber = null;
+ }
+ }
+
+ public TRet Invoke( T1 a, T2 b, T3 c, T4 d )
+ => _subscriber != null ? _subscriber.InvokeFunc( a, b, c, d ) : throw new IpcNotReadyError( _label );
+}
+
+public readonly struct FuncSubscriber< T1, T2, T3, T4, T5, TRet >
+{
+ private readonly string _label;
+ private readonly ICallGateSubscriber< T1, T2, T3, T4, T5, TRet >? _subscriber;
+
+ public bool Valid
+ => _subscriber != null;
+
+ public FuncSubscriber( DalamudPluginInterface pi, string label )
+ {
+ _label = label;
+ try
+ {
+ _subscriber = pi.GetIpcSubscriber< T1, T2, T3, T4, T5, TRet >( label );
+ }
+ catch( Exception e )
+ {
+ PluginLog.Error( $"Error registering IPC Subscriber for {label}\n{e}" );
+ _subscriber = null;
+ }
+ }
+
+ public TRet Invoke( T1 a, T2 b, T3 c, T4 d, T5 e )
+ => _subscriber != null ? _subscriber.InvokeFunc( a, b, c, d, e ) : throw new IpcNotReadyError( _label );
+}
\ No newline at end of file
diff --git a/Penumbra/Api/IPenumbraApi.cs b/tmp/IPenumbraApi.cs
similarity index 86%
rename from Penumbra/Api/IPenumbraApi.cs
rename to tmp/IPenumbraApi.cs
index 257cfbde..51860312 100644
--- a/Penumbra/Api/IPenumbraApi.cs
+++ b/tmp/IPenumbraApi.cs
@@ -1,63 +1,28 @@
using Dalamud.Game.ClientState.Objects.Types;
using Lumina.Data;
-using Penumbra.Collections;
-using Penumbra.GameData.Enums;
-using Penumbra.Mods;
using System;
using System.Collections.Generic;
+using Penumbra.Api.Enums;
namespace Penumbra.Api;
-public interface IPenumbraApiBase
-{
- // The API version is staggered in two parts.
- // The major/Breaking version only increments if there are changes breaking backwards compatibility.
- // The minor/Feature version increments any time there is something added
- // and resets when Breaking is incremented.
- public (int Breaking, int Feature) ApiVersion { get; }
- public bool Valid { get; }
-}
-
-public delegate void ChangedItemHover( object? item );
-public delegate void ChangedItemClick( MouseButton button, object? item );
-public delegate void GameObjectRedrawn( IntPtr objectPtr, int objectTableIndex );
-public delegate void ModSettingChanged( ModSettingChange type, string collectionName, string modDirectory, bool inherited );
-
-public delegate void CreatingCharacterBaseDelegate( IntPtr gameObject, ModCollection collection, IntPtr modelId, IntPtr customize,
- IntPtr equipData );
-
-public delegate void CreatedCharacterBaseDelegate( IntPtr gameObject, ModCollection collection, IntPtr drawObject );
-public delegate void GameObjectResourceResolvedDelegate( IntPtr gameObject, string gamePath, string localPath );
-
-public enum PenumbraApiEc
-{
- Success = 0,
- NothingChanged = 1,
- CollectionMissing = 2,
- ModMissing = 3,
- OptionGroupMissing = 4,
- OptionMissing = 5,
-
- CharacterCollectionExists = 6,
- LowerPriority = 7,
- InvalidGamePath = 8,
- FileMissing = 9,
- InvalidManipulation = 10,
- InvalidArgument = 11,
- UnknownError = 255,
-}
-
public interface IPenumbraApi : IPenumbraApiBase
{
+ #region Game State
+
// Obtain the currently set mod directory from the configuration.
public string GetModDirectory();
+ // Obtain the entire current penumbra configuration as a json encoded string.
+ public string GetConfiguration();
+
// Fired whenever a mod directory change is finished.
// Gives the full path of the mod directory and whether Penumbra treats it as valid.
public event Action< string, bool >? ModDirectoryChanged;
- // Obtain the entire current penumbra configuration as a json encoded string.
- public string GetConfiguration();
+ #endregion
+
+ #region UI
// Triggered when the user hovers over a listed changed object in a mod tab.
// Can be used to append tooltips.
@@ -70,8 +35,36 @@ public interface IPenumbraApi : IPenumbraApiBase
// Triggered when the user clicks a listed changed object in a mod tab.
public event ChangedItemClick? ChangedItemClicked;
+
+ #endregion
+
+ #region Redrawing
+
+ // Queue redrawing of all actors of the given name with the given RedrawType.
+ public void RedrawObject( string name, RedrawType setting );
+
+ // Queue redrawing of the specific actor with the given RedrawType. Should only be used when the actor is sure to be valid.
+ public void RedrawObject( GameObject gameObject, RedrawType setting );
+
+ // Queue redrawing of the actor with the given object table index, if it exists, with the given RedrawType.
+ public void RedrawObject( int tableIndex, RedrawType setting );
+
+ // Queue redrawing of all currently available actors with the given RedrawType.
+ public void RedrawAll( RedrawType setting );
+
+ // Triggered whenever a game object is redrawn via Penumbra.
public event GameObjectRedrawn? GameObjectRedrawn;
+ #endregion
+
+ #region Game State
+
+ // Obtain the game object associated with a given draw object and the name of the collection associated with this game object.
+ public (IntPtr, string) GetDrawObjectInfo( IntPtr drawObject );
+
+ // Obtain the parent game object index for an unnamed cutscene actor by its index.
+ public int GetCutsceneParentIndex( int actor );
+
// Triggered when a character base is created and a corresponding gameObject could be found,
// before the Draw Object is actually created, so customize and equipdata can be manipulated beforehand.
public event CreatingCharacterBaseDelegate? CreatingCharacterBase;
@@ -84,17 +77,9 @@ public interface IPenumbraApi : IPenumbraApiBase
// 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 );
+ #endregion
- // Queue redrawing of the specific actor with the given RedrawType. Should only be used when the actor is sure to be valid.
- public void RedrawObject( GameObject gameObject, RedrawType setting );
-
- // Queue redrawing of the actor with the given object table index, if it exists, with the given RedrawType.
- public void RedrawObject( int tableIndex, RedrawType setting );
-
- // Queue redrawing of all currently available actors with the given RedrawType.
- public void RedrawAll( RedrawType setting );
+ #region Resolving
// Resolve a given gamePath via Penumbra using the Default collection.
// Returns the given gamePath if penumbra would not manipulate it.
@@ -125,8 +110,9 @@ public interface IPenumbraApi : IPenumbraApiBase
// Try to load a given gamePath with the resolved path from Penumbra.
public T? GetFile< T >( string gamePath, string characterName ) where T : FileResource;
- // Gets a dictionary of effected items from a collection
- public IReadOnlyDictionary< string, object? > GetChangedItemsForCollection( string collectionName );
+ #endregion
+
+ #region Collections
// Obtain a list of the names of all currently installed collections.
public IList< string > GetCollections();
@@ -143,11 +129,24 @@ public interface IPenumbraApi : IPenumbraApiBase
// Obtain the name of the collection associated with characterName and whether it is configured or inferred from default.
public (string, bool) GetCharacterCollection( string characterName );
- // Obtain the game object associated with a given draw object and the name of the collection associated with this game object.
- public (IntPtr, string) GetDrawObjectInfo( IntPtr drawObject );
+ // Gets a dictionary of effected items from a collection
+ public IReadOnlyDictionary< string, object? > GetChangedItemsForCollection( string collectionName );
- // Obtain the parent game object index for an unnamed cutscene actor by its index.
- public int GetCutsceneParentIndex( int actor );
+ #endregion
+
+ #region Meta
+
+ // Obtain a base64 encoded, zipped json-string with a prepended version-byte of the current manipulations
+ // for the collection currently associated with the player.
+ public string GetPlayerMetaManipulations();
+
+ // Obtain a base64 encoded, zipped json-string with a prepended version-byte of the current manipulations
+ // for the given collection associated with the character name, or the default collection.
+ public string GetMetaManipulations( string characterName );
+
+ #endregion
+
+ #region Mods
// Obtain a list of all installed mods. The first string is their directory name, the second string is their mod name.
public IList< (string, string) > GetModList();
@@ -162,20 +161,29 @@ public interface IPenumbraApi : IPenumbraApiBase
// Note that success does only imply a successful call, not a successful mod load.
public PenumbraApiEc AddMod( string modDirectory );
- // Obtain a base64 encoded, zipped json-string with a prepended version-byte of the current manipulations
- // for the collection currently associated with the player.
- public string GetPlayerMetaManipulations();
+ // Try to delete a mod given by its modDirectory or its name.
+ // Returns NothingDone if the mod can not be found or success otherwise.
+ // Note that success does only imply a successful call, not successful deletion.
+ public PenumbraApiEc DeleteMod( string modDirectory, string modName );
- // Obtain a base64 encoded, zipped json-string with a prepended version-byte of the current manipulations
- // for the given collection associated with the character name, or the default collection.
- public string GetMetaManipulations( string characterName );
+ // Get the internal full filesystem path including search order for the specified mod.
+ // If success is returned, the second return value contains the full path
+ // and a bool indicating whether this is the default path (false) or a manually set one (true).
+ // Can return ModMissing or Success.
+ public (PenumbraApiEc, string, bool) GetModPath( string modDirectory, string modName );
+ // Set the internal search order and filesystem path of the specified mod to the given path.
+ // Returns InvalidArgument if newPath is empty, ModMissing if the mod can not be found,
+ // PathRenameFailed if newPath could not be set and Success otherwise.
+ public PenumbraApiEc SetModPath( string modDirectory, string modName, string newPath );
- // ############## Mod Settings #################
+ #endregion
+
+ #region Mod Settings
// Obtain the potential settings of a mod specified by its directory name first or mod name second.
// Returns null if the mod could not be found.
- public IDictionary< string, (IList< string >, SelectType) >? GetAvailableModSettings( string modDirectory, string modName );
+ public IDictionary< string, (IList< string >, GroupType) >? GetAvailableModSettings( string modDirectory, string modName );
// Obtain the enabled state, the priority, the settings of a mod specified by its directory name first or mod name second,
// and whether these settings are inherited, or null if the collection does not set them at all.
@@ -207,6 +215,10 @@ public interface IPenumbraApi : IPenumbraApiBase
// This event gets fired when any setting in any collection changes.
public event ModSettingChanged? ModSettingChanged;
+ #endregion
+
+ #region Temporary
+
// Create a temporary collection without actual settings but with a cache.
// If no character collection for this character exists or forceOverwriteCharacter is true,
// associate this collection to a specific character.
@@ -233,4 +245,6 @@ public interface IPenumbraApi : IPenumbraApiBase
// Remove the temporary mod with the given tag and priority from the temporary mods applying to the collection of the given name, which can be temporary.
// Can return Okay or NothingDone.
public PenumbraApiEc RemoveTemporaryMod( string tag, string collectionName, int priority );
+
+ #endregion
}
\ No newline at end of file
diff --git a/tmp/IPenumbraApiBase.cs b/tmp/IPenumbraApiBase.cs
new file mode 100644
index 00000000..e4c452b4
--- /dev/null
+++ b/tmp/IPenumbraApiBase.cs
@@ -0,0 +1,11 @@
+namespace Penumbra.Api;
+
+public interface IPenumbraApiBase
+{
+ // The API version is staggered in two parts.
+ // The major/Breaking version only increments if there are changes breaking backwards compatibility.
+ // The minor/Feature version increments any time there is something added
+ // and resets when Breaking is incremented.
+ public (int Breaking, int Feature) ApiVersion { get; }
+ public bool Valid { get; }
+}
\ No newline at end of file
diff --git a/tmp/Ipc/Collection.cs b/tmp/Ipc/Collection.cs
new file mode 100644
index 00000000..3c40cd17
--- /dev/null
+++ b/tmp/Ipc/Collection.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Collections.Generic;
+using Dalamud.Plugin;
+using Penumbra.Api.Helpers;
+
+namespace Penumbra.Api;
+
+public static partial class Ipc
+{
+ public static class GetCollections
+ {
+ public const string Label = $"Penumbra.{nameof( GetCollections )}";
+
+ public static FuncProvider< IList< string > > Provider( DalamudPluginInterface pi, Func< IList< string > > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< IList< string > > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class GetCurrentCollectionName
+ {
+ public const string Label = $"Penumbra.{nameof( GetCurrentCollectionName )}";
+
+ public static FuncProvider< string > Provider( DalamudPluginInterface pi, Func< string > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class GetDefaultCollectionName
+ {
+ public const string Label = $"Penumbra.{nameof( GetDefaultCollectionName )}";
+
+ public static FuncProvider< string > Provider( DalamudPluginInterface pi, Func< string > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class GetInterfaceCollectionName
+ {
+ public const string Label = $"Penumbra.{nameof( GetInterfaceCollectionName )}";
+
+ public static FuncProvider< string > Provider( DalamudPluginInterface pi, Func< string > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class GetCharacterCollectionName
+ {
+ public const string Label = $"Penumbra.{nameof( GetCharacterCollectionName )}";
+
+ public static FuncProvider< string, (string, bool) > Provider( DalamudPluginInterface pi, Func< string, (string, bool) > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, (string, bool) > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class GetChangedItems
+ {
+ public const string Label = $"Penumbra.{nameof( GetChangedItems )}";
+
+ public static FuncProvider< string, IReadOnlyDictionary< string, object? > > Provider( DalamudPluginInterface pi,
+ Func< string, IReadOnlyDictionary< string, object? > > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, IReadOnlyDictionary< string, object? > > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+}
\ No newline at end of file
diff --git a/tmp/Ipc/Configuration.cs b/tmp/Ipc/Configuration.cs
new file mode 100644
index 00000000..67033458
--- /dev/null
+++ b/tmp/Ipc/Configuration.cs
@@ -0,0 +1,42 @@
+using System;
+using Dalamud.Plugin;
+using Penumbra.Api.Helpers;
+
+namespace Penumbra.Api;
+
+public static partial class Ipc
+{
+ public static class GetModDirectory
+ {
+ public const string Label = $"Penumbra.{nameof( GetModDirectory )}";
+
+ public static FuncProvider< string > Provider( DalamudPluginInterface pi, Func< string > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class GetConfiguration
+ {
+ public const string Label = $"Penumbra.{nameof( GetConfiguration )}";
+
+ public static FuncProvider< string > Provider( DalamudPluginInterface pi, Func< string > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class ModDirectoryChanged
+ {
+ public const string Label = $"Penumbra.{nameof( ModDirectoryChanged )}";
+
+ public static EventProvider< string, bool > Provider( DalamudPluginInterface pi,
+ Action< Action< string, bool > > sub, Action< Action< string, bool > > unsub )
+ => new(pi, Label, ( sub, unsub ));
+
+ public static EventSubscriber< string, bool > Subscriber( DalamudPluginInterface pi, params Action< string, bool >[] actions )
+ => new(pi, Label, actions);
+ }
+}
\ No newline at end of file
diff --git a/tmp/Ipc/GameState.cs b/tmp/Ipc/GameState.cs
new file mode 100644
index 00000000..89889fda
--- /dev/null
+++ b/tmp/Ipc/GameState.cs
@@ -0,0 +1,63 @@
+using System;
+using Dalamud.Plugin;
+using Penumbra.Api.Helpers;
+
+namespace Penumbra.Api;
+
+public static partial class Ipc
+{
+ public static class GetDrawObjectInfo
+ {
+ public const string Label = $"Penumbra.{nameof( GetDrawObjectInfo )}";
+
+ public static FuncProvider< nint, (nint, string) > Provider( DalamudPluginInterface pi, Func< nint, (nint, string) > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< nint, (nint, string) > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class GetCutsceneParentIndex
+ {
+ public const string Label = $"Penumbra.{nameof( GetCutsceneParentIndex )}";
+
+ public static FuncProvider< int, int > Provider( DalamudPluginInterface pi, Func< int, int > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< int, int > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class CreatingCharacterBase
+ {
+ public const string Label = $"Penumbra.{nameof( CreatingCharacterBase )}";
+
+ public static EventProvider< nint, string, nint, nint, nint > Provider( DalamudPluginInterface pi, Action add, Action del )
+ => new(pi, Label, add, del);
+
+ public static EventSubscriber< nint, string, nint, nint, nint > Subscriber( DalamudPluginInterface pi, params Action< nint, string, nint, nint, nint >[] actions )
+ => new(pi, Label, actions);
+ }
+
+ public static class CreatedCharacterBase
+ {
+ public const string Label = $"Penumbra.{nameof( CreatedCharacterBase )}";
+
+ public static EventProvider< nint, string, nint > Provider( DalamudPluginInterface pi, Action add, Action del )
+ => new(pi, Label, add, del);
+
+ public static EventSubscriber< nint, string, nint > Subscriber( DalamudPluginInterface pi, params Action< nint, string, nint >[] actions )
+ => new(pi, Label, actions);
+ }
+
+ public static class GameObjectResourcePathResolved
+ {
+ public const string Label = $"Penumbra.{nameof( GameObjectResourcePathResolved )}";
+
+ public static EventProvider< nint, string, string > Provider( DalamudPluginInterface pi, Action add, Action del )
+ => new(pi, Label, add, del);
+
+ public static EventSubscriber< nint, string, string > Subscriber( DalamudPluginInterface pi, params Action< nint, string, string >[] actions )
+ => new(pi, Label, actions);
+ }
+}
\ No newline at end of file
diff --git a/tmp/Ipc/Meta.cs b/tmp/Ipc/Meta.cs
new file mode 100644
index 00000000..ef889f43
--- /dev/null
+++ b/tmp/Ipc/Meta.cs
@@ -0,0 +1,30 @@
+using System;
+using Dalamud.Plugin;
+using Penumbra.Api.Helpers;
+
+namespace Penumbra.Api;
+
+public static partial class Ipc
+{
+ public static class GetPlayerMetaManipulations
+ {
+ public const string Label = $"Penumbra.{nameof( GetPlayerMetaManipulations )}";
+
+ public static FuncProvider< string > Provider( DalamudPluginInterface pi, Func< string > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class GetMetaManipulations
+ {
+ public const string Label = $"Penumbra.{nameof( GetMetaManipulations )}";
+
+ public static FuncProvider< string, string > Provider( DalamudPluginInterface pi, Func< string, string > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, string > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+}
\ No newline at end of file
diff --git a/tmp/Ipc/ModSettings.cs b/tmp/Ipc/ModSettings.cs
new file mode 100644
index 00000000..8a0e9cf8
--- /dev/null
+++ b/tmp/Ipc/ModSettings.cs
@@ -0,0 +1,116 @@
+using System;
+using System.Collections.Generic;
+using Dalamud.Plugin;
+using Penumbra.Api.Enums;
+using Penumbra.Api.Helpers;
+
+namespace Penumbra.Api;
+
+using CurrentSettings = ValueTuple< PenumbraApiEc, (bool, int, IDictionary< string, IList< string > >, bool)? >;
+
+public static partial class Ipc
+{
+ public static class GetAvailableModSettings
+ {
+ public const string Label = $"Penumbra.{nameof( GetAvailableModSettings )}";
+
+ public static FuncProvider< string, string, IDictionary< string, (IList< string >, GroupType) >? > Provider(
+ DalamudPluginInterface pi, Func< string, string, IDictionary< string, (IList< string >, GroupType) >? > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, string, IDictionary< string, (IList< string >, GroupType) >? > Subscriber(
+ DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class GetCurrentModSettings
+ {
+ public const string Label = $"Penumbra.{nameof( GetCurrentModSettings )}";
+
+ public static FuncProvider< string, string, string, bool, CurrentSettings > Provider( DalamudPluginInterface pi,
+ Func< string, string, string, bool, CurrentSettings > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, string, string, bool, CurrentSettings > Subscriber(
+ DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class TryInheritMod
+ {
+ public const string Label = $"Penumbra.{nameof( TryInheritMod )}";
+
+ public static FuncProvider< string, string, string, bool, PenumbraApiEc > Provider( DalamudPluginInterface pi,
+ Func< string, string, string, bool, PenumbraApiEc > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, string, string, bool, PenumbraApiEc > Subscriber(
+ DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class TrySetMod
+ {
+ public const string Label = $"Penumbra.{nameof( TrySetMod )}";
+
+ public static FuncProvider< string, string, string, bool, PenumbraApiEc > Provider( DalamudPluginInterface pi,
+ Func< string, string, string, bool, PenumbraApiEc > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, string, string, bool, PenumbraApiEc > Subscriber(
+ DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class TrySetModPriority
+ {
+ public const string Label = $"Penumbra.{nameof( TrySetModPriority )}";
+
+ public static FuncProvider< string, string, string, int, PenumbraApiEc > Provider( DalamudPluginInterface pi,
+ Func< string, string, string, int, PenumbraApiEc > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, string, string, int, PenumbraApiEc > Subscriber(
+ DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class TrySetModSetting
+ {
+ public const string Label = $"Penumbra.{nameof( TrySetModSetting )}";
+
+ public static FuncProvider< string, string, string, string, string, PenumbraApiEc > Provider( DalamudPluginInterface pi,
+ Func< string, string, string, string, string, PenumbraApiEc > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, string, string, string, string, PenumbraApiEc > Subscriber(
+ DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class TrySetModSettings
+ {
+ public const string Label = $"Penumbra.{nameof( TrySetModSettings )}";
+
+ public static FuncProvider< string, string, string, string, IReadOnlyList< string >, PenumbraApiEc > Provider(
+ DalamudPluginInterface pi,
+ Func< string, string, string, string, IReadOnlyList< string >, PenumbraApiEc > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, string, string, string, IReadOnlyList< string >, PenumbraApiEc > Subscriber(
+ DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class ModSettingChanged
+ {
+ public const string Label = $"Penumbra.{nameof( ModSettingChanged )}";
+
+ public static EventProvider< ModSettingChange, string, string, bool > Provider( DalamudPluginInterface pi, Action add, Action del )
+ => new(pi, Label, add, del);
+
+ public static EventSubscriber< ModSettingChange, string, string, bool > Subscriber( DalamudPluginInterface pi,
+ params Action< ModSettingChange, string, string, bool >[] actions )
+ => new(pi, Label, actions);
+ }
+}
\ No newline at end of file
diff --git a/tmp/Ipc/Mods.cs b/tmp/Ipc/Mods.cs
new file mode 100644
index 00000000..d5d09036
--- /dev/null
+++ b/tmp/Ipc/Mods.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Collections.Generic;
+using Dalamud.Plugin;
+using Penumbra.Api.Enums;
+using Penumbra.Api.Helpers;
+
+namespace Penumbra.Api;
+
+public static partial class Ipc
+{
+ public static class GetMods
+ {
+ public const string Label = $"Penumbra.{nameof( GetMods )}";
+
+ public static FuncProvider< IList< (string, string) > > Provider( DalamudPluginInterface pi, Func< IList< (string, string) > > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< IList< (string, string) > > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class ReloadMod
+ {
+ public const string Label = $"Penumbra.{nameof( ReloadMod )}";
+
+ public static FuncProvider< string, string, PenumbraApiEc > Provider( DalamudPluginInterface pi,
+ Func< string, string, PenumbraApiEc > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, string, PenumbraApiEc > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class AddMod
+ {
+ public const string Label = $"Penumbra.{nameof( AddMod )}";
+
+ public static FuncProvider< string, PenumbraApiEc > Provider( DalamudPluginInterface pi,
+ Func< string, PenumbraApiEc > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, PenumbraApiEc > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class DeleteMod
+ {
+ public const string Label = $"Penumbra.{nameof( DeleteMod )}";
+
+ public static FuncProvider< string, string, PenumbraApiEc > Provider( DalamudPluginInterface pi,
+ Func< string, string, PenumbraApiEc > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, string, PenumbraApiEc > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class GetModPath
+ {
+ public const string Label = $"Penumbra.{nameof( GetModPath )}";
+
+ public static FuncProvider< string, string, (PenumbraApiEc, string, bool) > Provider( DalamudPluginInterface pi,
+ Func< string, string, (PenumbraApiEc, string, bool) > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, string, (PenumbraApiEc, string, bool) > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class SetModPath
+ {
+ public const string Label = $"Penumbra.{nameof( SetModPath )}";
+
+ public static FuncProvider< string, string, string, PenumbraApiEc > Provider( DalamudPluginInterface pi,
+ Func< string, string, string, PenumbraApiEc > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, string, string, PenumbraApiEc > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+}
\ No newline at end of file
diff --git a/tmp/Ipc/PluginState.cs b/tmp/Ipc/PluginState.cs
new file mode 100644
index 00000000..500bf1ee
--- /dev/null
+++ b/tmp/Ipc/PluginState.cs
@@ -0,0 +1,68 @@
+using System;
+using Dalamud.Plugin;
+using Penumbra.Api.Helpers;
+
+namespace Penumbra.Api;
+
+public static partial class Ipc
+{
+ public static class Initialized
+ {
+ public const string Label = $"Penumbra.{nameof( Initialized )}";
+
+ public static EventProvider Provider( DalamudPluginInterface pi )
+ => new(pi, Label);
+
+ public static EventSubscriber Subscriber( DalamudPluginInterface pi, params Action[] actions )
+ {
+ var ret = new EventSubscriber( pi, Label );
+ foreach( var action in actions )
+ {
+ ret.Event += action;
+ }
+
+ return ret;
+ }
+ }
+
+ public static class Disposed
+ {
+ public const string Label = $"Penumbra.{nameof( Disposed )}";
+
+ public static EventProvider Provider( DalamudPluginInterface pi )
+ => new(pi, Label);
+
+ public static EventSubscriber Subscriber( DalamudPluginInterface pi, params Action[] actions )
+ {
+ var ret = new EventSubscriber( pi, Label );
+ foreach( var action in actions )
+ {
+ ret.Event += action;
+ }
+
+ return ret;
+ }
+ }
+
+ public static class ApiVersion
+ {
+ public const string Label = $"Penumbra.{nameof( ApiVersion )}";
+
+ public static FuncProvider< int > Provider( DalamudPluginInterface pi, Func< int > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< int > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class ApiVersions
+ {
+ public const string Label = $"Penumbra.{nameof( ApiVersions )}";
+
+ public static FuncProvider< (int Breaking, int Features) > Provider( DalamudPluginInterface pi, Func< (int, int) > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< (int Breaking, int Features) > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+}
\ No newline at end of file
diff --git a/tmp/Ipc/Redraw.cs b/tmp/Ipc/Redraw.cs
new file mode 100644
index 00000000..396dfe8a
--- /dev/null
+++ b/tmp/Ipc/Redraw.cs
@@ -0,0 +1,65 @@
+using System;
+using Dalamud.Game.ClientState.Objects.Types;
+using Dalamud.Plugin;
+using Penumbra.Api.Enums;
+using Penumbra.Api.Helpers;
+
+namespace Penumbra.Api;
+
+public static partial class Ipc
+{
+ public static class RedrawAll
+ {
+ public const string Label = $"Penumbra.{nameof( RedrawAll )}";
+
+ public static ActionProvider< RedrawType > Provider( DalamudPluginInterface pi, Action< RedrawType > action )
+ => new(pi, Label, action);
+
+ public static ActionSubscriber< RedrawType > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class RedrawObject
+ {
+ public const string Label = $"Penumbra.{nameof( RedrawObject )}";
+
+ public static ActionProvider< GameObject, RedrawType > Provider( DalamudPluginInterface pi, Action< GameObject, RedrawType > action )
+ => new(pi, Label, action);
+
+ public static ActionSubscriber< GameObject, RedrawType > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class RedrawObjectByIndex
+ {
+ public const string Label = $"Penumbra.{nameof( RedrawObjectByIndex )}";
+
+ public static ActionProvider< int, RedrawType > Provider( DalamudPluginInterface pi, Action< int, RedrawType > action )
+ => new(pi, Label, action);
+
+ public static ActionSubscriber< int, RedrawType > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class RedrawObjectByName
+ {
+ public const string Label = $"Penumbra.{nameof( RedrawObjectByName )}";
+
+ public static ActionProvider< string, RedrawType > Provider( DalamudPluginInterface pi, Action< string, RedrawType > action )
+ => new(pi, Label, action);
+
+ public static ActionSubscriber< string, RedrawType > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class GameObjectRedrawn
+ {
+ public const string Label = $"Penumbra.{nameof( GameObjectRedrawn )}";
+
+ public static EventProvider< nint, int > Provider( DalamudPluginInterface pi, Action add, Action del )
+ => new(pi, Label, add, del);
+
+ public static EventSubscriber< nint, int > Subscriber( DalamudPluginInterface pi, params Action< nint, int >[] actions )
+ => new(pi, Label, actions);
+ }
+}
\ No newline at end of file
diff --git a/tmp/Ipc/Resolve.cs b/tmp/Ipc/Resolve.cs
new file mode 100644
index 00000000..8b9eb953
--- /dev/null
+++ b/tmp/Ipc/Resolve.cs
@@ -0,0 +1,74 @@
+using System;
+using Dalamud.Plugin;
+using Penumbra.Api.Helpers;
+
+namespace Penumbra.Api;
+
+public static partial class Ipc
+{
+ public static class ResolveDefaultPath
+ {
+ public const string Label = $"Penumbra.{nameof( ResolveDefaultPath )}";
+
+ public static FuncProvider< string, string > Provider( DalamudPluginInterface pi, Func< string, string > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, string > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class ResolveInterfacePath
+ {
+ public const string Label = $"Penumbra.{nameof( ResolveInterfacePath )}";
+
+ public static FuncProvider< string, string > Provider( DalamudPluginInterface pi, Func< string, string > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, string > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class ResolvePlayerPath
+ {
+ public const string Label = $"Penumbra.{nameof( ResolvePlayerPath )}";
+
+ public static FuncProvider< string, string > Provider( DalamudPluginInterface pi, Func< string, string > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, string > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class ResolveCharacterPath
+ {
+ public const string Label = $"Penumbra.{nameof( ResolveCharacterPath )}";
+
+ public static FuncProvider< string, string, string > Provider( DalamudPluginInterface pi, Func< string, string, string > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, string, string > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class ReverseResolvePath
+ {
+ public const string Label = $"Penumbra.{nameof( ReverseResolvePath )}";
+
+ public static FuncProvider< string, string, string[] > Provider( DalamudPluginInterface pi, Func< string, string, string[] > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, string, string[] > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class ReverseResolvePlayerPath
+ {
+ public const string Label = $"Penumbra.{nameof( ReverseResolvePlayerPath )}";
+
+ public static FuncProvider< string, string[] > Provider( DalamudPluginInterface pi, Func< string, string[] > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, string[] > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+}
\ No newline at end of file
diff --git a/tmp/Ipc/Temporary.cs b/tmp/Ipc/Temporary.cs
new file mode 100644
index 00000000..55af6f22
--- /dev/null
+++ b/tmp/Ipc/Temporary.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using Dalamud.Plugin;
+using Penumbra.Api.Enums;
+using Penumbra.Api.Helpers;
+
+namespace Penumbra.Api;
+
+public static partial class Ipc
+{
+ public static class CreateTemporaryCollection
+ {
+ public const string Label = $"Penumbra.{nameof( CreateTemporaryCollection )}";
+
+ public static FuncProvider< string, string, bool, (PenumbraApiEc, string) > Provider( DalamudPluginInterface pi,
+ Func< string, string, bool, (PenumbraApiEc, string) > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, string, bool, (PenumbraApiEc, string) > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class RemoveTemporaryCollection
+ {
+ public const string Label = $"Penumbra.{nameof( RemoveTemporaryCollection )}";
+
+ public static FuncProvider< string, PenumbraApiEc > Provider( DalamudPluginInterface pi,
+ Func< string, PenumbraApiEc > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, PenumbraApiEc > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class AddTemporaryModAll
+ {
+ public const string Label = $"Penumbra.{nameof( AddTemporaryModAll )}";
+
+ public static FuncProvider< string, Dictionary< string, string >, string, int, PenumbraApiEc > Provider(
+ DalamudPluginInterface pi, Func< string, Dictionary< string, string >, string, int, PenumbraApiEc > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, Dictionary< string, string >, string, int, PenumbraApiEc > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class AddTemporaryMod
+ {
+ public const string Label = $"Penumbra.{nameof( AddTemporaryMod )}";
+
+ public static FuncProvider< string, string, Dictionary< string, string >, string, int, PenumbraApiEc > Provider(
+ DalamudPluginInterface pi, Func< string, string, Dictionary< string, string >, string, int, PenumbraApiEc > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, string, Dictionary< string, string >, string, int, PenumbraApiEc > Subscriber(
+ DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class RemoveTemporaryModAll
+ {
+ public const string Label = $"Penumbra.{nameof( RemoveTemporaryModAll )}";
+
+ public static FuncProvider< string, int, PenumbraApiEc > Provider(
+ DalamudPluginInterface pi, Func< string, int, PenumbraApiEc > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, int, PenumbraApiEc > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+
+ public static class RemoveTemporaryMod
+ {
+ public const string Label = $"Penumbra.{nameof( RemoveTemporaryMod )}";
+
+ public static FuncProvider< string, string, int, PenumbraApiEc > Provider(
+ DalamudPluginInterface pi, Func< string, string, int, PenumbraApiEc > func )
+ => new(pi, Label, func);
+
+ public static FuncSubscriber< string, string, int, PenumbraApiEc > Subscriber( DalamudPluginInterface pi )
+ => new(pi, Label);
+ }
+}
\ No newline at end of file
diff --git a/tmp/Ipc/Ui.cs b/tmp/Ipc/Ui.cs
new file mode 100644
index 00000000..d88d6718
--- /dev/null
+++ b/tmp/Ipc/Ui.cs
@@ -0,0 +1,55 @@
+using System;
+using Dalamud.Plugin;
+using Penumbra.Api.Enums;
+using Penumbra.Api.Helpers;
+
+namespace Penumbra.Api;
+
+public static partial class Ipc
+{
+ public static class PreSettingsDraw
+ {
+ public const string Label = $"Penumbra.{nameof( PreSettingsDraw )}";
+
+ public static EventProvider< string > Provider( DalamudPluginInterface pi, Action< Action< string > > sub,
+ Action< Action< string > > unsub )
+ => new(pi, Label, ( sub, unsub ));
+
+ public static EventSubscriber< string > Subscriber( DalamudPluginInterface pi, params Action< string >[] actions )
+ => new(pi, Label, actions);
+ }
+
+ public static class PostSettingsDraw
+ {
+ public const string Label = $"Penumbra.{nameof( PostSettingsDraw )}";
+
+ public static EventProvider< string > Provider( DalamudPluginInterface pi, Action< Action< string > > sub,
+ Action< Action< string > > unsub )
+ => new(pi, Label, ( sub, unsub ));
+
+ public static EventSubscriber< string > Subscriber( DalamudPluginInterface pi, params Action< string >[] actions )
+ => new(pi, Label, actions);
+ }
+
+ public static class ChangedItemTooltip
+ {
+ public const string Label = $"Penumbra.{nameof( ChangedItemTooltip )}";
+
+ public static EventProvider< ChangedItemType, uint > Provider( DalamudPluginInterface pi, Action add, Action del )
+ => new(pi, Label, add, del);
+
+ public static EventSubscriber< ChangedItemType, uint > Subscriber( DalamudPluginInterface pi, params Action< ChangedItemType, uint >[] actions )
+ => new(pi, Label, actions);
+ }
+
+ public static class ChangedItemClick
+ {
+ public const string Label = $"Penumbra.{nameof( ChangedItemClick )}";
+
+ public static EventProvider< MouseButton, ChangedItemType, uint > Provider( DalamudPluginInterface pi, Action add, Action del )
+ => new(pi, Label, add, del);
+
+ public static EventSubscriber< MouseButton, ChangedItemType, uint > Subscriber( DalamudPluginInterface pi, params Action< MouseButton, ChangedItemType, uint >[] actions )
+ => new(pi, Label, actions);
+ }
+}
\ No newline at end of file
diff --git a/tmp/Penumbra.Api.csproj b/tmp/Penumbra.Api.csproj
new file mode 100644
index 00000000..8962883b
--- /dev/null
+++ b/tmp/Penumbra.Api.csproj
@@ -0,0 +1,47 @@
+
+
+ net6.0-windows
+ preview
+ x64
+ Penumbra.Api
+ absolute gangstas
+ Penumbra
+ Copyright © 2022
+ 1.0.0.0
+ 1.0.0.0
+ bin\$(Configuration)\
+ true
+ enable
+ true
+ false
+ false
+
+
+
+ full
+ DEBUG;TRACE
+
+
+
+ pdbonly
+
+
+
+ $(MSBuildWarningsAsMessages);MSB3277
+
+
+
+ $(AppData)\XIVLauncher\addon\Hooks\dev\
+
+
+
+
+ $(DalamudLibPath)Dalamud.dll
+ False
+
+
+ $(DalamudLibPath)Lumina.dll
+ False
+
+
+
diff --git a/tmp/Penumbra.Api.csproj.DotSettings b/tmp/Penumbra.Api.csproj.DotSettings
new file mode 100644
index 00000000..7d7508cb
--- /dev/null
+++ b/tmp/Penumbra.Api.csproj.DotSettings
@@ -0,0 +1,2 @@
+
+ True
\ No newline at end of file
diff --git a/tmp/README.md b/tmp/README.md
new file mode 100644
index 00000000..1e9bdf1a
--- /dev/null
+++ b/tmp/README.md
@@ -0,0 +1,4 @@
+# Penumbra
+
+This is an auxiliary repository for Penumbras external API.
+For more information, see the [main repo](https://github.com/xivdev/Penumbra).
\ No newline at end of file