Use external library for API interface and IPC.

This commit is contained in:
Ottermandias 2022-10-08 02:02:33 +02:00
parent b3f048bfe6
commit 918d5db6a6
69 changed files with 4026 additions and 1873 deletions

View file

@ -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

4
.gitmodules vendored
View file

@ -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

1
Penumbra.Api Submodule

@ -0,0 +1 @@
Subproject commit 0064bb82be9729676e7bf3202ff1407283e6f088

View file

@ -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 ),
};
}
}

View file

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

View file

@ -1,10 +0,0 @@
namespace Penumbra.GameData.Enums
{
public enum MouseButton
{
None,
Left,
Right,
Middle,
}
}

View file

@ -34,6 +34,10 @@
<DalamudLibPath>$(AppData)\XIVLauncher\addon\Hooks\dev\</DalamudLibPath>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Penumbra.Api\Penumbra.Api.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="Dalamud">
<HintPath>$(DalamudLibPath)Dalamud.dll</HintPath>

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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 )

View file

@ -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<string>( 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();
}
}

View file

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

View file

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

View file

@ -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 )

View file

@ -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.

View file

@ -3,6 +3,7 @@ using Penumbra.Mods;
using System;
using System.Collections.Generic;
using System.Linq;
using Penumbra.Api.Enums;
namespace Penumbra.Collections;

View file

@ -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 )

View file

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

View file

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

View file

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

View file

@ -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 );

View file

@ -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()
{

View file

@ -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 )

View file

@ -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();

View file

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

View file

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

View file

@ -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,

View file

@ -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,

View file

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

View file

@ -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();

View file

@ -75,6 +75,7 @@
<ItemGroup>
<ProjectReference Include="..\OtterGui\OtterGui.csproj" />
<ProjectReference Include="..\Penumbra.GameData\Penumbra.GameData.csproj" />
<ProjectReference Include="..\Penumbra.Api\Penumbra.Api.csproj" />
</ItemGroup>
<ItemGroup>

View file

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

View file

@ -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.

View file

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

View file

@ -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();

View file

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

View file

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

View file

@ -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, )"
}
}
}
}

85
tmp/.editorconfig Normal file
View file

@ -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

3
tmp/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
bin/
obj/
.vs/

16
tmp/Delegates.cs Normal file
View file

@ -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 );

View file

@ -0,0 +1,9 @@
namespace Penumbra.Api.Enums;
public enum ChangedItemType
{
None,
Item,
Action,
Customization,
}

7
tmp/Enums/GroupType.cs Normal file
View file

@ -0,0 +1,7 @@
namespace Penumbra.Api.Enums;
public enum GroupType
{
Single,
Multi,
}

View file

@ -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.
}

9
tmp/Enums/MouseButton.cs Normal file
View file

@ -0,0 +1,9 @@
namespace Penumbra.Api.Enums;
public enum MouseButton
{
None,
Left,
Right,
Middle,
}

View file

@ -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,
}

View file

@ -1,4 +1,4 @@
namespace Penumbra.GameData.Enums;
namespace Penumbra.Api.Enums;
public enum RedrawType
{

View file

@ -0,0 +1,66 @@
using System;
using Dalamud.Logging;
using Dalamud.Plugin;
using Dalamud.Plugin.Ipc;
namespace Penumbra.Api.Helpers;
public sealed class ActionProvider<T1> : IDisposable
{
private ICallGateProvider<T1, object?>? _provider;
public ActionProvider( DalamudPluginInterface pi, string label, Action<T1> action )
{
try
{
_provider = pi.GetIpcProvider<T1, 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();
}
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();
}

View file

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

View file

@ -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();
}

View file

@ -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();
}

186
tmp/Helpers/FuncProvider.cs Normal file
View file

@ -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();
}

View file

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

View file

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

11
tmp/IPenumbraApiBase.cs Normal file
View file

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

76
tmp/Ipc/Collection.cs Normal file
View file

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

42
tmp/Ipc/Configuration.cs Normal file
View file

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

63
tmp/Ipc/GameState.cs Normal file
View file

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

30
tmp/Ipc/Meta.cs Normal file
View file

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

116
tmp/Ipc/ModSettings.cs Normal file
View file

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

81
tmp/Ipc/Mods.cs Normal file
View file

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

68
tmp/Ipc/PluginState.cs Normal file
View file

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

65
tmp/Ipc/Redraw.cs Normal file
View file

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

74
tmp/Ipc/Resolve.cs Normal file
View file

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

83
tmp/Ipc/Temporary.cs Normal file
View file

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

55
tmp/Ipc/Ui.cs Normal file
View file

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

47
tmp/Penumbra.Api.csproj Normal file
View file

@ -0,0 +1,47 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>
<LangVersion>preview</LangVersion>
<PlatformTarget>x64</PlatformTarget>
<AssemblyTitle>Penumbra.Api</AssemblyTitle>
<Company>absolute gangstas</Company>
<Product>Penumbra</Product>
<Copyright>Copyright © 2022</Copyright>
<FileVersion>1.0.0.0</FileVersion>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<OutputPath>bin\$(Configuration)\</OutputPath>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Nullable>enable</Nullable>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugType>full</DebugType>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
</PropertyGroup>
<PropertyGroup>
<MSBuildWarningsAsMessages>$(MSBuildWarningsAsMessages);MSB3277</MSBuildWarningsAsMessages>
</PropertyGroup>
<PropertyGroup>
<DalamudLibPath>$(AppData)\XIVLauncher\addon\Hooks\dev\</DalamudLibPath>
</PropertyGroup>
<ItemGroup>
<Reference Include="Dalamud">
<HintPath>$(DalamudLibPath)Dalamud.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Lumina">
<HintPath>$(DalamudLibPath)Lumina.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
</Project>

View file

@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ipc/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

4
tmp/README.md Normal file
View file

@ -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).