This commit is contained in:
2025-08-22 02:19:48 +01:00
commit a4c82452be
373 changed files with 52044 additions and 0 deletions

3625
Penumbra.Api/.editorconfig Normal file

File diff suppressed because it is too large Load Diff

3
Penumbra.Api/.gitignore vendored Normal file
View File

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

View File

@@ -0,0 +1,66 @@
using Penumbra.Api.Enums;
namespace Penumbra.Api.Api;
/// <summary> API methods pertaining to collection management. </summary>
public interface IPenumbraApiCollection
{
/// <returns> A list of the GUIDs of all currently installed collections together with their display names, excluding the empty collection. </returns>
public Dictionary<Guid, string> GetCollections();
/// <summary> Returns all collections for which either
/// <list type="number">
/// <item> the name is equal to the given identifier up to case, </item>
/// <item> the identifier is parsable to a GUID and the GUID corresponds to an existing collection, </item>
/// <item> or the identifier is at least 8 characters long and the GUID as a hex-string starts with the identifier. </item>
/// </list>
/// </summary>
public List<(Guid Id, string Name)> GetCollectionsByIdentifier(string identifier);
/// <returns>A dictionary of affected items in <paramref name="collectionId"/> via GUID and known objects or null.</returns>
public Dictionary<string, object?> GetChangedItemsForCollection(Guid collectionId);
/// <returns> The GUID and name of the collection assigned to the given <paramref name="type"/>, the empty GUID for the empty collection, or null if nothing is assigned. </returns>
public (Guid Id, string Name)? GetCollection(ApiCollectionType type);
/// <returns>Return whether the object at <paramref name="gameObjectIdx" /> produces a valid identifier, if the identifier has a collection assigned, and the collection that affects the object.</returns>
public (bool ObjectValid, bool IndividualSet, (Guid Id, string Name) EffectiveCollection) GetCollectionForObject(int gameObjectIdx);
/// <summary>
/// Set a collection by GUID for a specific type.
/// </summary>
/// <param name="type">The collection type to set.</param>
/// <param name="collectionId">The GUID of the collection to set it to, null to remove the association if allowed. </param>
/// <param name="allowCreateNew">Allow only setting existing types or also creating an unset type.</param>
/// <param name="allowDelete">Allow deleting existing collections if <paramref name="collectionId"/> is empty.</param>
/// <returns>InvalidArgument if type is invalid,
/// NothingChanged if the new collection is the same as the old,<br />
/// AssignmentDeletionDisallowed if <paramref name="collectionId"/> is null and <paramref name="allowDelete"/> is false, and the assignment exists,<br />
/// or if Default, Current or Interface would be deleted.<br />
/// CollectionMissing if the new collection can not be found,<br />
/// AssignmentCreationDisallowed if <paramref name="allowCreateNew"/> is false and the assignment does not exist,<br />
/// or Success, as well as the GUID of the previous collection (empty if no assignment existed).
/// </returns>
public (PenumbraApiEc, (Guid Id, string Name)? OldCollection) SetCollection(ApiCollectionType type, Guid? collectionId, bool allowCreateNew,
bool allowDelete);
/// <summary>
/// Set a collection by GUID for a specific game object.
/// </summary>
/// <param name="gameObjectIdx">The index of the desired game object in the object table.</param>
/// <param name="collectionId">The GUID of the collection to set it to, null to remove the association if allowed. </param>
/// <param name="allowCreateNew">Allow only setting existing individuals or also creating a new individual assignment.</param>
/// <param name="allowDelete">Allow deleting existing individual assignments if <paramref name="collectionId"/> is null.</param>
/// <returns>InvalidIdentifier if <paramref name="gameObjectIdx"/> does not produce an existing game object or the object is not identifiable,
/// NothingChanged if the new collection is the same as the old,<br />
/// AssignmentDeletionDisallowed if <paramref name="collectionId"/> is null and <paramref name="allowDelete"/> is false, and the assignment exists,<br />
/// CollectionMissing if the new collection can not be found,<br />
/// AssignmentCreationDisallowed if <paramref name="allowCreateNew"/> is false and the assignment does not exist,<br />
/// or Success, as well as the name of the previous collection (empty if no assignment existed).</returns>
public (PenumbraApiEc, (Guid Id, string Name)? OldCollection) SetCollectionForObject(int gameObjectIdx, Guid? collectionId, bool allowCreateNew,
bool allowDelete);
/// <summary> Obtain a function object that can check if the current collection contains a given changed item by listing the mods changing it. </summary>
/// <remarks> Throws an <seealso cref="ObjectDisposedException"/> on invocation if the collection storage is not valid anymore, so clear this on <seealso cref="IpcSubscribers.Disposed"/>. </remarks>
public Func<string, (string ModDirectory, string ModName)[]> CheckCurrentChangedItemFunc();
}

View File

@@ -0,0 +1,28 @@
using Penumbra.Api.Enums;
namespace Penumbra.Api.Api;
/// <summary> API methods pertaining to the editing of mods or game files. </summary>
public interface IPenumbraApiEditing
{
/// <summary>
/// Convert the given texture file into a different type or format and potentially add mip maps.
/// </summary>
/// <param name="inputFile"> The path to the input file, which may be of .dds, .tex or .png format. </param>
/// <param name="outputFile"> The desired output path. Can be the same as input. </param>
/// <param name="textureType"> The file type and format to convert the data to. </param>
/// <param name="mipMaps"> Whether to add mip maps or not. Ignored for .png. </param>
/// <returns> A task for when the conversion is finished or has failed. </returns>
public Task ConvertTextureFile(string inputFile, string outputFile, TextureType textureType, bool mipMaps);
/// <summary>
/// Convert the given RGBA32 texture data into a different type or format and potentially add mip maps.
/// </summary>
/// <param name="rgbaData"> The input byte data for a picture given in RGBA32 format. </param>
/// <param name="width"> The width of the input picture. The height is computed from the size of <paramref name="rgbaData"/> and this. </param>
/// <param name="outputFile"> The desired output path. Can be the same as input. </param>
/// <param name="textureType"> The file type and format to convert the data to. </param>
/// <param name="mipMaps"> Whether to add mip maps or not. Ignored for .png. </param>
/// <returns> A task for when the conversion is finished or has failed. </returns>
public Task ConvertTextureData(byte[] rgbaData, int width, string outputFile, TextureType textureType, bool mipMaps);
}

View File

@@ -0,0 +1,52 @@
using Penumbra.Api.Enums;
namespace Penumbra.Api.Api;
/// <summary> API methods pertaining to the currently tracked game state. </summary>
public interface IPenumbraApiGameState
{
/// <param name="drawObject"></param>
/// <returns>The game object associated with the given <paramref name="drawObject">draw object</paramref>
/// and the GUID and name of the collection associated with this game object.</returns>
public (nint GameObject, (Guid Id, string Name) Collection) GetDrawObjectInfo(nint drawObject);
/// <summary>
/// Obtain the parent game object index for an unnamed cutscene actor by its <paramref name="actorIdx">index</paramref>.
/// </summary>
/// <param name="actorIdx"></param>
/// <returns>The parent game object index.</returns>
public int GetCutsceneParentIndex(int actorIdx);
/// <summary>
/// Set the cutscene parent of <paramref name="copyIdx"/> in Penumbras internal state to a new value.
/// </summary>
/// <param name="copyIdx"> The index of the cutscene actor to be changed. </param>
/// <param name="newParentIdx"> The new index of the cutscene actors parent or -1 for no parent. </param>
/// <returns> Success when the new parent could be set, or InvalidArgument if either index is out of its respective range. </returns>
/// <remarks>
/// Checks that the new parent exists as a game object if the value is not -1 before assigning. If it does not, InvalidArgument is given, too.
/// Please only use this for good reason and if you know what you are doing, probably only for actor copies you actually create yourself.
/// </remarks>
public PenumbraApiEc SetCutsceneParentIndex(int copyIdx, int newParentIdx);
/// <summary>
/// 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.
/// </summary>
/// <returns><inheritdoc cref="CreatingCharacterBaseDelegate"/></returns>
public event CreatingCharacterBaseDelegate? CreatingCharacterBase;
/// <summary>
/// Triggered after a character base was created if a corresponding gameObject could be found,
/// so you can apply flag changes after finishing.
/// </summary>
/// <returns><inheritdoc cref="CreatedCharacterBaseDelegate"/></returns>
public event CreatedCharacterBaseDelegate? CreatedCharacterBase;
/// <summary>
/// Triggered whenever a resource is redirected by Penumbra for a specific, identified game object.
/// Does not trigger if the resource is not requested for a known game object.
/// </summary>
/// <returns><inheritdoc cref="GameObjectResourceResolvedDelegate"/></returns>
public event GameObjectResourceResolvedDelegate? GameObjectResourceResolved;
}

View File

@@ -0,0 +1,41 @@
namespace Penumbra.Api.Api;
/// <summary> The entire API. </summary>
public interface IPenumbraApi : IPenumbraApiBase
{
/// <inheritdoc cref="IPenumbraApiCollection"/>
public IPenumbraApiCollection Collection { get; }
/// <inheritdoc cref="IPenumbraApiEditing"/>
public IPenumbraApiEditing Editing { get; }
/// <inheritdoc cref="IPenumbraApiGameState"/>
public IPenumbraApiGameState GameState { get; }
/// <inheritdoc cref="IPenumbraApiMeta"/>
public IPenumbraApiMeta Meta { get; }
/// <inheritdoc cref="IPenumbraApiMods"/>
public IPenumbraApiMods Mods { get; }
/// <inheritdoc cref="IPenumbraApiModSettings"/>
public IPenumbraApiModSettings ModSettings { get; }
/// <inheritdoc cref="IPenumbraApiPluginState"/>
public IPenumbraApiPluginState PluginState { get; }
/// <inheritdoc cref="IPenumbraApiRedraw"/>
public IPenumbraApiRedraw Redraw { get; }
/// <inheritdoc cref="IPenumbraApiResolve"/>
public IPenumbraApiResolve Resolve { get; }
/// <inheritdoc cref="IPenumbraApiResourceTree"/>
public IPenumbraApiResourceTree ResourceTree { get; }
/// <inheritdoc cref="IPenumbraApiTemporary"/>
public IPenumbraApiTemporary Temporary { get; }
/// <inheritdoc cref="IPenumbraApiUi"/>
public IPenumbraApiUi Ui { get; }
}

View File

@@ -0,0 +1,16 @@
namespace Penumbra.Api.Api;
/// <summary> Base interface for the API that is always available, regardless of version. </summary>
public interface IPenumbraApiBase
{
/// <summary>
/// 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.
/// </summary>
public (int Breaking, int Feature) ApiVersion { get; }
/// <summary> Whether the API is still usable. </summary>
public bool Valid { get; }
}

13
Penumbra.Api/Api/Meta.cs Normal file
View File

@@ -0,0 +1,13 @@
namespace Penumbra.Api.Api;
/// <summary> API methods pertaining to current metadata manipulations. </summary>
public interface IPenumbraApiMeta
{
/// <returns>A base64 encoded, zipped json-string with a prepended version-byte of the current manipulations
/// in the collection currently associated with the player.</returns>
public string GetPlayerMetaManipulations();
/// <returns>A base64 encoded, zipped json-string with a prepended version-byte of the current manipulations
/// in the given collection applying to the given game object or the default collection if it does not exist.</returns>
public string GetMetaManipulations(int gameObjectIdx);
}

View File

@@ -0,0 +1,77 @@
using Penumbra.Api.Enums;
using Penumbra.Api.Helpers;
namespace Penumbra.Api.Api;
/// <summary> API methods pertaining to the management of mod settings. </summary>
public interface IPenumbraApiModSettings
{
/// <summary>
/// Obtain the potential settings of a mod given by its <paramref name="modDirectory" /> name or <paramref name="modName" />.
/// </summary>
/// <returns>A dictionary of group names to lists of option names and the group type. Null if the mod could not be found.</returns>
public AvailableModSettings? GetAvailableModSettings(string modDirectory, string modName);
/// <summary>
/// Obtain the enabled state, the priority, the settings of a mod given by its <paramref name="modDirectory" /> name or <paramref name="modName" /> in the specified collection.
/// </summary>
/// <param name="collectionId">Specify the collection.</param>
/// <param name="modDirectory">Specify the mod via its directory name.</param>
/// <param name="modName">Specify the mod via its (non-unique) display name.</param>
/// <param name="ignoreInheritance">Whether the settings need to be from the given collection or can be inherited from any other by it. (True: given collection only)</param>
/// <param name="ignoreTemporary"> Whether the settings need to be actual settings or can be temporary. </param>
/// <param name="key"> The key for the settings lock. If <paramref name="ignoreTemporary"/> is false, settings with a key greater than 0 that is different from this will be ignored. </param>
/// <returns>ModMissing, CollectionMissing or Success. <para />
/// On Success, a tuple of Enabled State, Priority, a dictionary of option group names and lists of enabled option names and a bool whether the settings are inherited (true) or not.</returns>
public (PenumbraApiEc, (bool, int, Dictionary<string, List<string>>, bool, bool)?) GetCurrentModSettingsWithTemp(Guid collectionId,
string modDirectory, string modName, bool ignoreInheritance, bool ignoreTemporary, int key);
/// <inheritdoc cref="GetCurrentModSettingsWithTemp"/>
public (PenumbraApiEc, (bool, int, Dictionary<string, List<string>>, bool)?) GetCurrentModSettings(Guid collectionId,
string modDirectory, string modName, bool ignoreInheritance);
/// <summary> Obtain the enabled state, the priority, the settings of all mods in the specified collection. </summary>
/// <param name="collectionId"> Specify the collection. </param>
/// <param name="ignoreInheritance"> Whether the settings need to be from the given collection or can be inherited from any other by it. (True: given collection only) </param>
/// <param name="ignoreTemporary"> Whether the settings need to be actual settings or can be temporary. </param>
/// <param name="key"> The key for the settings lock. If <paramref name="ignoreTemporary"/> is false, settings with a key greater than 0 that is different from this will be ignored. </param>
/// <returns> CollectionMissing or Success, on Success, a dictionary of mod directory names to a tuple of (Enabled, Priority, Settings, Inherited, Temporary). Mods that have no settings at all are left out. </returns>
public (PenumbraApiEc, Dictionary<string, (bool, int, Dictionary<string, List<string>>, bool, bool)>?) GetAllModSettings(Guid collectionId,
bool ignoreInheritance, bool ignoreTemporary, int key);
/// <summary> Try to set the inheritance state of a mod in a collection. </summary>
/// <returns>ModMissing, CollectionMissing, InvalidArgument (GUID is nil), NothingChanged or Success.</returns>
public PenumbraApiEc TryInheritMod(Guid collectionId, string modDirectory, string modName, bool inherit);
/// <summary> Try to set the enabled state of a mod in a collection. </summary>
/// <returns>ModMissing, CollectionMissing, InvalidArgument (GUID is nil), NothingChanged or Success.</returns>
public PenumbraApiEc TrySetMod(Guid collectionId, string modDirectory, string modName, bool enabled);
/// <summary> Try to set the priority of a mod in a collection. </summary>
/// <returns>ModMissing, CollectionMissing, InvalidArgument (GUID is nil), NothingChanged or Success.</returns>
public PenumbraApiEc TrySetModPriority(Guid collectionId, string modDirectory, string modName, int priority);
/// <summary> Try to set a specific option group of a mod in the given collection to a specific value. </summary>
/// <remarks>Removes inheritance. Single Selection groups should provide a single option, Multi Selection can provide multiple.
/// If any setting can not be found, it will not change anything.</remarks>
/// <returns>ModMissing, CollectionMissing, OptionGroupMissing, SettingMissing, InvalidArgument (GUID is nil), NothingChanged or Success.</returns>
public PenumbraApiEc TrySetModSetting(Guid collectionId, string modDirectory, string modName, string optionGroupName, string optionName);
/// <inheritdoc cref="TrySetModSetting"/>
public PenumbraApiEc TrySetModSettings(Guid collectionId, string modDirectory, string modName, string optionGroupName,
IReadOnlyList<string> optionNames);
/// <summary> This event gets fired when any setting in any collection changes. </summary>
/// <returns><inheritdoc cref="ModSettingChangedDelegate" /></returns>
public event ModSettingChangedDelegate? ModSettingChanged;
/// <summary>
/// Copy all current settings for a mod to another mod.
/// </summary>
/// <param name="collectionId">Specify the collection to work in, leave null to do it in all collections.</param>
/// <param name="modDirectoryFrom">Specify the mod to take the settings from via its directory name.</param>
/// <param name="modDirectoryTo">Specify the mod to put the settings on via its directory name. If the mod does not exist, it will be added as unused settings.</param>
/// <returns>CollectionMissing if collectionName is not empty but does not exist or Success.</returns>
/// <remarks>If the target mod exists, the settings will be fixed before being applied. If the source mod does not exist, it will use unused settings if available and remove existing settings otherwise.</remarks>
public PenumbraApiEc CopyModSettings(Guid? collectionId, string modDirectoryFrom, string modDirectoryTo);
}

78
Penumbra.Api/Api/Mods.cs Normal file
View File

@@ -0,0 +1,78 @@
using Penumbra.Api.Enums;
namespace Penumbra.Api.Api;
/// <summary> API methods pertaining to management of mods. </summary>
public interface IPenumbraApiMods
{
/// <returns>A list of all installed mods. The first string is their directory name, the second string is their mod name.</returns>
public Dictionary<string, string> GetModList();
/// <summary> Try to unpack and install a valid mod file (.pmp, .ttmp, .ttmp2) as if installed manually. </summary>
/// <param name="modFilePackagePath">The file that should be unpacked.</param>
/// <returns>Success, MissingFile. Success does not indicate successful installing, just successful queueing for install.</returns>
public PenumbraApiEc InstallMod(string modFilePackagePath);
/// <summary> Try to reload an existing mod given by its <paramref name="modDirectory" /> name or <paramref name="modName" />.</summary>
/// <remarks>Reload is the same as if triggered by button press and might delete the mod if it is not valid anymore.</remarks>
/// <returns>ModMissing if the mod can not be found or Success</returns>
public PenumbraApiEc ReloadMod(string modDirectory, string modName);
/// <summary> Try to add a new mod inside the mod root directory.</summary>
/// <remarks>Note that success does only imply a successful call, not a successful mod load.</remarks>
/// <param name="modDirectory">The name (not full name) of the mod directory.</param>
/// <returns>FileMissing if <paramref name="modDirectory" /> does not exist, InvalidArgument if the path leads outside the root directory, Success otherwise.</returns>
public PenumbraApiEc AddMod(string modDirectory);
/// <summary>Try to delete a mod given by its <paramref name="modDirectory" /> name or <paramref name="modName" />.</summary>
/// <remarks>Note that success does only imply a successful call, not successful deletion.</remarks>
/// <returns>NothingDone if the mod can not be found, Success otherwise.</returns>
public PenumbraApiEc DeleteMod(string modDirectory, string modName);
/// <summary> Triggers whenever a mod is deleted. </summary>
/// <returns>The base directory name of the deleted mod.</returns>
public event Action<string>? ModDeleted;
/// <summary> Triggers whenever a mod is deleted. </summary>
/// <returns>The base directory name of the new mod.</returns>
public event Action<string>? ModAdded;
/// <summary> Triggers whenever a mods base name is changed from inside Penumbra. </summary>
/// <returns>The previous base directory name of the mod and the new base directory name of the mod.</returns>
public event Action<string, string>? ModMoved;
/// <summary>
/// Get the internal full filesystem path including search order for the specified mod
/// given by its <paramref name="modDirectory" /> name or <paramref name="modName" />.
/// </summary>
/// <returns>On Success, the full path, a bool indicating whether the entire path is default (true) or manually set (false),
/// and a bool indicating whether the sort order name ignoring the folder path is default (true) or manually set (false).
/// Otherwise, returns ModMissing if the mod can not be found.</returns>
public (PenumbraApiEc, string, bool, bool) GetModPath(string modDirectory, string modName);
/// <summary>
/// Set the internal search order and filesystem path of the specified mod
/// given by its <paramref name="modDirectory" /> name or <paramref name="modName" />
/// to the <paramref name="newPath" />.
/// </summary>
/// <returns>InvalidArgument if <paramref name="newPath" /> is empty, ModMissing if the mod can not be found,
/// PathRenameFailed if <paramref name="newPath"/> could not be set or Success.</returns>
public PenumbraApiEc SetModPath(string modDirectory, string modName, string newPath);
/// <summary> Get the overall changed items of a single mod given by its <paramref name="modDirectory"/> name or <paramref name="modName"/>, regardless of settings. </summary>
/// <returns> A possibly empty dictionary of affected items and known objects or null. </returns>
public Dictionary<string, object?> GetChangedItems(string modDirectory, string modName);
/// <summary> Get a dictionary of dictionaries to check all mods changed items. </summary>
/// <returns> A dictionary of mod identifier to changed item dictionary. </returns>
/// <remarks> Throws an <seealso cref="ObjectDisposedException"/> on access if the mod storage is not valid anymore, so clear this on <seealso cref="IpcSubscribers.Disposed"/>. </remarks>
public IReadOnlyDictionary<string, IReadOnlyDictionary<string, object?>> GetChangedItemAdapterDictionary();
/// <summary> Get a list of dictionaries to check all mods changed items. </summary>
/// <returns> A list all mods changed item dictionaries. </returns>
/// <remarks>
/// The order of mods is unspecified, but the same as in GetModList (assuming no changes in mods have taken place between calls). <br/>
/// Throws an <seealso cref="ObjectDisposedException"/> on access if the mod storage is not valid anymore, so clear this on <seealso cref="IpcSubscribers.Disposed"/>.
/// </remarks>
public IReadOnlyList<(string ModDirectory, IReadOnlyDictionary<string, object?> ChangedItems)> GetChangedItemAdapterList();
}

View File

@@ -0,0 +1,26 @@
namespace Penumbra.Api.Api;
/// <summary> API methods pertaining to Penumbras own state. </summary>
public interface IPenumbraApiPluginState
{
/// <returns> The full path of the current penumbra root directory. </returns>
public string GetModDirectory();
/// <returns> The entire current penumbra configuration as a json encoded string. </returns>
public string GetConfiguration();
/// <summary>
/// Fired whenever a mod directory change is finished.
/// </summary>
/// <returns>The full path of the mod directory and whether Penumbra treats it as valid.</returns>
public event Action<string, bool>? ModDirectoryChanged;
/// <returns>True if Penumbra is enabled, false otherwise.</returns>
public bool GetEnabledState();
/// <summary>
/// Fired whenever the enabled state of Penumbra changes.
/// </summary>
/// <returns>True if the new state is enabled, false if the new state is disabled</returns>
public event Action<bool>? EnabledChange;
}

View File

@@ -0,0 +1,23 @@
using Penumbra.Api.Enums;
namespace Penumbra.Api.Api;
/// <summary> API methods pertaining to the redrawing of actors. </summary>
public interface IPenumbraApiRedraw
{
/// <summary>
/// Queue redrawing of the actor with the given object <paramref name="gameObjectIndex" />, if it exists, with the given RedrawType <paramref name="setting"/>.
/// </summary>
public void RedrawObject(int gameObjectIndex, RedrawType setting);
/// <summary>
/// Queue redrawing of all currently available actors with the given RedrawType <paramref name="setting"/>.
/// </summary>
public void RedrawAll(RedrawType setting);
/// <summary>
/// Triggered whenever a game object is redrawn via Penumbra.
/// </summary>
/// /<returns><inheritdoc cref="GameObjectRedrawnDelegate"/></returns>
public event GameObjectRedrawnDelegate? GameObjectRedrawn;
}

View File

@@ -0,0 +1,64 @@
using Lumina.Data;
namespace Penumbra.Api.Api;
/// <summary> API methods pertaining to the resolving of paths. </summary>
public interface IPenumbraApiResolve
{
/// <summary>
/// Resolve a given <paramref name="gamePath" /> via Penumbra using the Base collection.
/// </summary>
/// <returns>The resolved path, or the given path if Penumbra would not manipulate it.</returns>
public string ResolveDefaultPath(string gamePath);
/// <summary>
/// Resolve a given <paramref name="gamePath" /> via Penumbra using the Interface collection.
/// </summary>
/// <returns>The resolved path, or the given path if Penumbra would not manipulate it.</returns>
public string ResolveInterfacePath(string gamePath);
/// <summary>
/// Resolve a given <paramref name="gamePath" /> via Penumbra using collection applying to the <paramref name="gameObjectIdx"/>
/// given by its index in the game object table.
/// </summary>
/// <remarks>If the object does not exist in the table, the default collection is used.</remarks>
/// <returns>The resolved path, or the given path if Penumbra would not manipulate it.</returns>
public string ResolveGameObjectPath(string gamePath, int gameObjectIdx);
/// <summary>
/// Resolve a given <paramref name="gamePath" /> via Penumbra using the collection currently applying to the player character.
/// </summary>
/// <returns>The resolved path, or the given path if Penumbra would not manipulate it.</returns>
public string ResolvePlayerPath(string gamePath);
/// <summary>
/// Reverse resolves a given local <paramref name="moddedPath" /> into its replacement in form of all applicable game paths
/// for the collection applying to the <paramref name="gameObjectIdx"/>th game object in the game object table.
/// </summary>
/// <remarks>If the object does not exist in the table, the default collection is used.</remarks>
/// <returns>A list of game paths resolving to the modded path.</returns>
public string[] ReverseResolveGameObjectPath(string moddedPath, int gameObjectIdx);
/// <summary>
/// Reverse resolves a given local <paramref name="moddedPath" /> into its replacement in form of all applicable game paths
/// for the collection currently applying to the player character.
/// </summary>
/// <returns>A list of game paths resolving to the modded path.</returns>
public string[] ReverseResolvePlayerPath(string moddedPath);
/// <summary>
/// Resolve all game paths in <paramref name="forward"/> and reserve all paths in <paramref name="reverse"/> at once.
/// </summary>
/// <param name="forward">Paths to forward-resolve.</param>
/// <param name="reverse">Paths to reverse-resolve.</param>
/// <returns>A pair of an array of forward-resolved single paths of the same length as <paramref name="forward"/> and an array of arrays of reverse-resolved paths.
/// The outer array has the same length as <paramref name="reverse"/> while each inner array can have arbitrary length.</returns>
public (string[], string[][]) ResolvePlayerPaths(string[] forward, string[] reverse);
/// <summary>
/// Resolve all game paths in <paramref name="forward"/> and reserve all paths in <paramref name="reverse"/> at once asynchronously.
/// </summary>
/// <inheritdoc cref="ResolvePlayerPaths"/>
/// <remarks> Can be called from outside of framework. Can theoretically produce incoherent state when collections change during evaluation. </remarks>
public Task<(string[], string[][])> ResolvePlayerPathsAsync(string[] forward, string[] reverse);
}

View File

@@ -0,0 +1,73 @@
using Newtonsoft.Json.Linq;
using Penumbra.Api.Enums;
using Penumbra.Api.Helpers;
namespace Penumbra.Api.Api;
/// <summary> API methods pertaining to the tracking of resources in use by actors. </summary>
public interface IPenumbraApiResourceTree
{
/// <summary>
/// Get the given game objects' resources, as dictionaries of actual paths (that may be FS paths for redirected resources, or game paths for swapped or vanilla resources) to game paths.
/// </summary>
/// <param name="gameObjects"> The game object indices for which to get the resources. </param>
/// <returns> An array of resource path dictionaries, of the same length and in the same order as the given game object index array. </returns>
/// <remarks> This function is best called right after the game objects are redrawn, as it may fail to resolve paths if relevant mod settings have changed since then. </remarks>
public Dictionary<string, HashSet<string>>?[] GetGameObjectResourcePaths(params ushort[] gameObjects);
/// <summary>
/// Get the player and player-owned game objects' resources, as dictionaries of actual paths (that may be FS paths for redirected resources, or game paths for swapped or vanilla resources) to game paths.
/// </summary>
/// <returns> A dictionary of game object indices to resource path dictionaries. </returns>
/// <remarks> This function is best called right after the game objects are redrawn, as it may fail to resolve paths if relevant mod settings have changed since then. </remarks>
public Dictionary<ushort, Dictionary<string, HashSet<string>>> GetPlayerResourcePaths();
/// <summary>
/// Get the given game objects' resources of a given type, as dictionaries of resource handles to actual paths and, optionally, names and icons.
/// </summary>
/// <param name="type"> Type of the resources to get, for example <see cref="ResourceType.Mtrl"/> for materials. </param>
/// <param name="withUiData"> Whether to get names and icons along with the paths. </param>
/// <param name="gameObjects"> The game object indices for which to get the resources. </param>
/// <returns> An array of resource information dictionaries, of the same length and in the same order as the given game object index array. </returns>
/// <remarks>
/// It is the caller's responsibility to make sure the returned resource handles are still in use on the game object's draw object before using them. <para />
/// Also, callers should not use UI data for non-UI purposes.
/// </remarks>
public GameResourceDict?[] GetGameObjectResourcesOfType(ResourceType type, bool withUiData,
params ushort[] gameObjects);
/// <summary>
/// Get the player and player-owned game objects' resources of a given type, as dictionaries of resource handles to actual paths and, optionally, names and icons.
/// </summary>
/// <param name="type"> Type of the resources to get, for example <see cref="ResourceType.Mtrl"/> for materials. </param>
/// <param name="withUiData"> Whether to get names and icons along with the paths. </param>
/// <returns> A dictionary of game object indices to resource information dictionaries. </returns>
/// <remarks>
/// It is the caller's responsibility to make sure the returned resource handles are still in use on the game object's draw object before using them. <para />
/// Also, callers should not use UI data for non-UI purposes.
/// </remarks>
public Dictionary<ushort, GameResourceDict> GetPlayerResourcesOfType(ResourceType type, bool withUiData);
/// <summary>
/// Get the given game objects' resource tree.
/// </summary>
/// <param name="withUiData"> Whether to get names and icons along with the paths. </param>
/// <param name="gameObjects"> The game object indices for which to get the resources. </param>
/// <returns> An array of resource tree JObjects, of the same length and in the same order as the given game object index array. </returns>
/// <remarks>
/// It is the caller's responsibility to make sure the returned resource handles are still in use on the game object's draw object before using them. <para />
/// Also, callers should not use UI data for non-UI purposes.
/// </remarks>
public JObject?[] GetGameObjectResourceTrees(bool withUiData, params ushort[] gameObjects);
/// <summary>
/// Get the player and player-owned game objects' resource trees.
/// </summary>
/// <param name="withUiData"> Whether to get names and icons along with the paths. </param>
/// <returns> A dictionary of game object indices to resource trees. </returns>
/// <remarks>
/// It is the caller's responsibility to make sure the returned resource handles are still in use on the game object's draw object before using them. <para />
/// Also, callers should not use UI data for non-UI purposes.
/// </remarks>
public Dictionary<ushort, JObject> GetPlayerResourceTrees(bool withUiData);
}

View File

@@ -0,0 +1,147 @@
using Penumbra.Api.Enums;
namespace Penumbra.Api.Api;
/// <summary> API methods pertaining to the management of temporary collections and mods. </summary>
public interface IPenumbraApiTemporary
{
/// <summary> Temporarily set the settings of a mod in a collection to given values. </summary>
/// <param name="collectionId"> The collection to manipulate. </param>
/// <param name="modDirectory"> Specify the mod via its directory name. </param>
/// <param name="modName"> Specify the mod via its (non-unique) display name. </param>
/// <param name="inherit"> Whether the mod should be forced to inherit from parent collections (if this is true, the other settings do not matter). </param>
/// <param name="enabled"> Whether the mod should be enabled or disabled. </param>
/// <param name="priority"> The desired priority for the mod. </param>
/// <param name="options"> The new settings for the mod, as a map of Group Name -> All enabled Options (should be only one for single select groups).</param>
/// <param name="source"> A string to describe the source of those temporary settings. This is displayed to the user. </param>
/// <param name="key"> An optional lock to prevent other plugins and the user from changing these settings. Changes in mod structure will still remove the settings. Use 0 for no lock, or negative numbers for an identification lock that does not prevent the user from editing the temporary settings, but allows you to use <seealso cref="RemoveAllTemporaryModSettings"/> with the same key to only remove your settings. </param>
/// <returns> Success, CollectionMissing if the collection does not exist, TemporarySettingImpossible if the collection can not have settings, ModMissing if the mod can not be identified, TemporarySettingDisallowed if there is already a temporary setting with a different key, OptionGroupMissing if a group can not be found, OptionMissing if an option can not be found. </returns>
/// <remarks> If not all groups are set in <paramref name="options"/>, they will be set to their default settings. </remarks>
public PenumbraApiEc SetTemporaryModSettings(Guid collectionId, string modDirectory, string modName, bool inherit, bool enabled, int priority,
IReadOnlyDictionary<string, IReadOnlyList<string>> options, string source, int key);
/// <summary> Temporarily set the settings of a mod in a collection to given values. </summary>
/// <param name="objectIndex"> The game object index of the object whose collection you want to change. </param>
/// <param name="modDirectory"> Specify the mod via its directory name. </param>
/// <param name="modName"> Specify the mod via its (non-unique) display name. </param>
/// <param name="inherit"> Whether the mod should be forced to inherit from parent collections (if this is true, the other settings do not matter). </param>
/// <param name="enabled"> Whether the mod should be enabled or disabled. </param>
/// <param name="priority"> The desired priority for the mod. </param>
/// <param name="options"> The new settings for the mod, as a map of Group Name -> All enabled Options (should be only one for single select groups).</param>
/// <param name="source"> A string to describe the source of those temporary settings. This is displayed to the user. </param>
/// <param name="key"> An optional lock to prevent other plugins and the user from changing these settings. Changes in mod structure will still remove the settings. Use 0 for no lock. </param>
/// <returns> Success, InvalidArgument if the game object does not exist, TemporarySettingImpossible if the collection can not have settings, ModMissing if the mod can not be identified, TemporarySettingDisallowed if there is already a temporary setting with a different key, OptionGroupMissing if a group can not be found, OptionMissing if an option can not be found. </returns>
/// <remarks> If not all groups are set in <paramref name="options"/>, they will be set to their default settings. </remarks>
public PenumbraApiEc SetTemporaryModSettingsPlayer(int objectIndex, string modDirectory, string modName, bool inherit, bool enabled, int priority,
IReadOnlyDictionary<string, IReadOnlyList<string>> options, string source, int key);
/// <summary> Temporarily set the settings of a mod in a collection to given values. </summary>
/// <param name="collectionId"> The collection to manipulate. </param>
/// <param name="modDirectory"> Specify the mod via its directory name. </param>
/// <param name="modName"> Specify the mod via its (non-unique) display name. </param>
/// <param name="key"> An optional key to a potential lock applied to those settings. </param>
/// <returns> Success, NothingDone if no temporary settings could be removed with this key, CollectionMissing if the collection does not exist, TemporarySettingDisallowed if the key did not correspond to the lock. </returns>
public PenumbraApiEc RemoveTemporaryModSettings(Guid collectionId, string modDirectory, string modName, int key);
/// <summary> Temporarily set the settings of a mod in a collection to given values. </summary>
/// <param name="objectIndex"> The game object index of the object whose collection you want to change. </param>
/// <param name="modDirectory"> Specify the mod via its directory name. </param>
/// <param name="modName"> Specify the mod via its (non-unique) display name. </param>
/// <param name="key"> An optional key to a potential lock applied to those settings. </param>
/// <returns> Success, NothingDone if the mod did not have temporary settings in this collection, InvalidArgument if the game object does not exist, TemporarySettingDisallowed if the key did not correspond to the lock. </returns>
public PenumbraApiEc RemoveTemporaryModSettingsPlayer(int objectIndex, string modDirectory, string modName, int key);
/// <summary> Temporarily set the settings of a mod in a collection to given values. </summary>
/// <param name="collectionId"> The collection to manipulate. </param>
/// <param name="key"> An optional key to a lock applied to those settings. All settings that use this key will be removed, all others ignored. </param>
/// <returns> Success, NothingDone if no temporary settings could be removed with this key, CollectionMissing if the collection does not exist. </returns>
public PenumbraApiEc RemoveAllTemporaryModSettings(Guid collectionId, int key);
/// <summary> Temporarily set the settings of a mod in a collection to given values. </summary>
/// <param name="objectIndex"> The game object index of the object whose collection you want to change. </param>
/// <param name="key"> An optional key to a lock applied to those settings. All settings that can be removed with this key will be removed, all others ignored. </param>
/// <returns> Success, NothingDone if no temporary settings could be removed with this key, InvalidArgument if the game object does not exist. </returns>
public PenumbraApiEc RemoveAllTemporaryModSettingsPlayer(int objectIndex, int key);
/// <summary> Create a temporary collection. </summary>
/// <param name="name"> The name for the collection. Arbitrary and only used internally for debugging. </param>
/// <returns> The GUID of the created temporary collection. </returns>
public Guid CreateTemporaryCollection(string name);
/// <summary> Remove the temporary collection of the given name. </summary>
/// <param name="collectionId"> The chosen temporary collection to remove. </param>
/// <returns> NothingChanged or Success. </returns>
public PenumbraApiEc DeleteTemporaryCollection(Guid collectionId);
/// <summary>
/// Assign an existing temporary collection to an actor that currently occupies a specific slot.
/// </summary>
/// <param name="collectionId">The chosen collection assigned to the actor.</param>
/// <param name="actorIndex">The current object table index of the actor.</param>
/// <param name="forceAssignment">Whether to assign even if the actor is already assigned either a temporary or a permanent collection.</param>
/// <returns>Success, InvalidArgument if the actor can not be identified, CollectionMissing if the collection does not exist, CharacterCollectionExists if <paramref name="forceAssignment"/> is false and the actor is already assigned a collection, and AssignmentDeletionFailed if <paramref name="forceAssignment"/> is true and the existing temporary assignment could not be deleted. </returns>
public PenumbraApiEc AssignTemporaryCollection(Guid collectionId, int actorIndex, bool forceAssignment);
/// <summary>
/// Set a temporary mod with the given paths, manipulations and priority and the name tag to all regular and temporary collections.
/// </summary>
/// <param name="tag">Custom name for the temporary mod.</param>
/// <param name="paths">List of redirections (can be swaps or redirections).</param>
/// <param name="manipString">Zipped Base64 string of meta manipulations.</param>
/// <param name="priority">Desired priority.</param>
/// <returns>InvalidGamePath, InvalidManipulation or Success.</returns>
public PenumbraApiEc AddTemporaryModAll(string tag, Dictionary<string, string> paths, string manipString, int priority);
/// <summary> Set a temporary mod with the given paths, manipulations and priority and the name tag to a specific collection.
/// </summary>
/// <param name="tag">Custom name for the temporary mod.</param>
/// <param name="collectionId">GUID of the collection the mod should apply to. Can be a temporary collection.</param>
/// <param name="paths">List of redirections (can be swaps or redirections).</param>
/// <param name="manipString">Zipped Base64 string of meta manipulations.</param>
/// <param name="priority">Desired priority.</param>
/// <returns>CollectionMissing, InvalidGamePath, InvalidManipulation, InvalidArgument (GUID is nil) or Success.</returns>
public PenumbraApiEc AddTemporaryMod(string tag, Guid collectionId, Dictionary<string, string> paths, string manipString,
int priority);
/// <summary>
/// Remove the temporary mod with the given tag and priority from the temporary mods applying to all collections, if it exists.
/// </summary>
/// <param name="tag">The tag to look for.</param>
/// <param name="priority">The initially provided priority.</param>
/// <returns>NothingDone or Success.</returns>
public PenumbraApiEc RemoveTemporaryModAll(string tag, int priority);
/// <summary>
/// Remove the temporary mod with the given tag and priority from the temporary mods applying to a specific collection, if it exists.
/// </summary>
/// <param name="tag">The tag to look for.</param>
/// <param name="collectionId">GUID of the collection the mod should apply to. Can be a temporary collection.</param>
/// <param name="priority">The initially provided priority.</param>
/// <returns>CollectionMissing, NothingDone or Success.</returns>
public PenumbraApiEc RemoveTemporaryMod(string tag, Guid collectionId, int priority);
/// <summary> Get the current temporary settings of a mod in the given collection. </summary>
/// <param name="collectionId"> The collection to query. </param>
/// <param name="modDirectory"> Specify the mod via its directory name. </param>
/// <param name="modName"> Specify the mod via its (non-unique) display name. </param>
/// <param name="key"> The key for the settings lock.</param>
/// <returns>
/// The settings as (ForceInherit, Enabled, Priority, Settings) or null if none are registered,
/// the registered source for the temporary settings or empty,
/// and Success, CollectionMissing, ModMissing or TemporarySettingDisallowed if the used key was > 0 and different from the provided key.
/// </returns>
public (PenumbraApiEc ErrorCode, (bool, bool, int, Dictionary<string, List<string>>)?, string) QueryTemporaryModSettings(Guid collectionId, string modDirectory,
string modName, int key);
/// <summary> Get the current temporary settings of a mod in the collection assigned to a given game object. </summary>
/// <param name="objectIndex"> The game object index of the object whose collection you want to change. </param>
/// <param name="modDirectory"> Specify the mod via its directory name. </param>
/// <param name="modName"> Specify the mod via its (non-unique) display name. </param>
/// <param name="key"> The key for the settings lock.</param>
/// <returns>
/// The settings as (ForceInherit, Enabled, Priority, Settings) or null if none are registered,
/// the registered source for the temporary settings or empty,
/// and Success, InvalidArgument if the game object does not exist, ModMissing, or TemporarySettingDisallowed if the used key was > 0 and different from the provided key.
/// </returns>
public (PenumbraApiEc ErrorCode, (bool, bool, int, Dictionary<string, List<string>>)? Settings, string Source) QueryTemporaryModSettingsPlayer(int objectIndex, string modDirectory, string modName, int key);
}

59
Penumbra.Api/Api/Ui.cs Normal file
View File

@@ -0,0 +1,59 @@
using Penumbra.Api.Enums;
namespace Penumbra.Api.Api;
/// <summary> API methods pertaining to Penumbras UI. </summary>
public interface IPenumbraApiUi
{
/// <summary>
/// Triggered when the user hovers over a listed changed object in a mod tab.<para />
/// Can be used to append tooltips.
/// </summary>
/// <returns> The type of the changed item and its ID if known. </returns>
public event Action<ChangedItemType, uint>? ChangedItemTooltip;
/// <summary>
/// Triggered when the user clicks a listed changed object in a mod tab.
/// </summary>
/// <returns> The mouse button clicked, the type of the changed item and its ID if known. </returns>
public event Action<MouseButton, ChangedItemType, uint>? ChangedItemClicked;
/// <summary>
/// Triggered before the settings tab bar for a mod is drawn, after the title group is drawn.
/// </summary>
/// <returns>The directory name of the currently selected mod, the total used width of the title bar and the width of the title box.</returns>
public event Action<string, float, float>? PreSettingsTabBarDraw;
/// <summary>
/// Triggered before the content of a mod settings panel is drawn.
/// </summary>
/// <returns>The directory name of the currently selected mod.</returns>
public event Action<string>? PreSettingsPanelDraw;
/// <summary>
/// Triggered after the Enabled Checkbox line in settings is drawn, but before options are drawn.
/// </summary>
/// <returns>The directory name of the currently selected mod.</returns>
public event Action<string>? PostEnabledDraw;
/// <summary>
/// Triggered after the content of a mod settings panel is drawn, but still in the child window.
/// </summary>
/// <returns>The directory name of the currently selected mod.</returns>
public event Action<string>? PostSettingsPanelDraw;
/// <summary>
/// Open the Penumbra main config window.
/// </summary>
/// <param name="tab">Open the window at a specific tab. Use TabType.None to not change the tab. </param>
/// <param name="modDirectory">Select a mod specified via its directory name in the mod tab, empty if none.</param>
/// <param name="modName">Select a mod specified via its mod name in the mod tab, empty if none.</param>
/// <returns>InvalidArgument if <paramref name="tab"/> is invalid,
/// ModMissing if <paramref name="modDirectory"/> or <paramref name="modName"/> are set non-empty and the mod does not exist,
/// Success otherwise.</returns>
/// <remarks>If <paramref name="tab"/> is not TabType.Mods, the mod will not be selected regardless of other parameters and ModMissing will not be returned.</remarks>
public PenumbraApiEc OpenMainWindow(TabType tab, string modDirectory, string modName);
/// <summary> Close the Penumbra main config window. </summary>
public void CloseMainWindow();
}

42
Penumbra.Api/Delegates.cs Normal file
View File

@@ -0,0 +1,42 @@
using Penumbra.Api.Enums;
namespace Penumbra.Api;
/// <summary>Used when a game object is redrawn by Penumbra.</summary>
/// <returns>The <paramref name="objectPtr" /> to the redrawn object and its <paramref name="objectTableIndex" />.</returns>
public delegate void GameObjectRedrawnDelegate(nint objectPtr, int objectTableIndex);
/// <summary>
/// Used when the setting of a mod is changed in any way.
/// </summary>
/// <returns>The <paramref name="type" /> of change, <para />
/// the <paramref name="collectionId" /> in which the setting is changed, <para />
/// the <paramref name="modDirectory" /> name of the mod, <para />
/// and whether the change was <paramref name="inherited" /> or not.</returns>
public delegate void ModSettingChangedDelegate(ModSettingChange type, Guid collectionId, string modDirectory, bool inherited);
/// <summary>
/// Used before a new character base draw object is created from a <paramref name="gameObject" />.
/// </summary>
/// <returns>A pointer to the source <paramref name="gameObject" />, <para />
/// the <paramref name="collectionId" /> used for the object, <para />
/// a pointer to the used <paramref name="modelId" /> (of type <c>ushort*</c>), <para />
/// a pointer to the <paramref name="customize" /> array, <para />
/// and a pointer to the <paramref name="equipData" /> array.</returns>
public delegate void CreatingCharacterBaseDelegate(nint gameObject, Guid collectionId, nint modelId, nint customize, nint equipData);
/// <summary>
/// Used after a character base <paramref name="drawObject" /> has been created from a <paramref name="gameObject" />.
/// </summary>
/// <returns>A pointer to the source <paramref name="gameObject" />, <para />
/// the <paramref name="collectionId" /> used for the object, <para />
/// a pointer to newly created <paramref name="drawObject" />.</returns>
public delegate void CreatedCharacterBaseDelegate(nint gameObject, Guid collectionId, nint drawObject);
/// <summary>
/// Used when a specific game object has resolved a path to a non-default path.
/// </summary>
/// <returns>A pointer to the source <paramref name="gameObject" />, <para />
/// the original <paramref name="gamePath" /> that was resolved by Penumbra, <para />
/// the resulting <paramref name="localPath" /> returned by Penumbra.</returns>
public delegate void GameObjectResourceResolvedDelegate(nint gameObject, string gamePath, string localPath);

View File

@@ -0,0 +1,97 @@
namespace Penumbra.Api.Enums;
public enum ApiCollectionType : byte
{
Yourself = 0,
MalePlayerCharacter,
FemalePlayerCharacter,
MaleNonPlayerCharacter,
FemaleNonPlayerCharacter,
NonPlayerChild,
NonPlayerElderly,
MaleMidlander,
FemaleMidlander,
MaleHighlander,
FemaleHighlander,
MaleWildwood,
FemaleWildwood,
MaleDuskwight,
FemaleDuskwight,
MalePlainsfolk,
FemalePlainsfolk,
MaleDunesfolk,
FemaleDunesfolk,
MaleSeekerOfTheSun,
FemaleSeekerOfTheSun,
MaleKeeperOfTheMoon,
FemaleKeeperOfTheMoon,
MaleSeawolf,
FemaleSeawolf,
MaleHellsguard,
FemaleHellsguard,
MaleRaen,
FemaleRaen,
MaleXaela,
FemaleXaela,
MaleHelion,
FemaleHelion,
MaleLost,
FemaleLost,
MaleRava,
FemaleRava,
MaleVeena,
FemaleVeena,
MaleMidlanderNpc,
FemaleMidlanderNpc,
MaleHighlanderNpc,
FemaleHighlanderNpc,
MaleWildwoodNpc,
FemaleWildwoodNpc,
MaleDuskwightNpc,
FemaleDuskwightNpc,
MalePlainsfolkNpc,
FemalePlainsfolkNpc,
MaleDunesfolkNpc,
FemaleDunesfolkNpc,
MaleSeekerOfTheSunNpc,
FemaleSeekerOfTheSunNpc,
MaleKeeperOfTheMoonNpc,
FemaleKeeperOfTheMoonNpc,
MaleSeawolfNpc,
FemaleSeawolfNpc,
MaleHellsguardNpc,
FemaleHellsguardNpc,
MaleRaenNpc,
FemaleRaenNpc,
MaleXaelaNpc,
FemaleXaelaNpc,
MaleHelionNpc,
FemaleHelionNpc,
MaleLostNpc,
FemaleLostNpc,
MaleRavaNpc,
FemaleRavaNpc,
MaleVeenaNpc,
FemaleVeenaNpc,
Default = 0xE0,
Interface = 0xE1,
Current = 0xE2,
}

View File

@@ -0,0 +1,23 @@
namespace Penumbra.Api.Enums;
public enum ChangedItemIcon : uint
{
None = 0,
Unknown = 1,
Head = 2,
Body = 3,
Hands = 4,
Legs = 5,
Feet = 6,
Ears = 7,
Neck = 8,
Wrists = 9,
Finger = 10,
Mainhand = 11,
Offhand = 12,
Customization = 13,
Monster = 14,
Demihuman = 15,
Action = 16,
Emote = 17,
}

View File

@@ -0,0 +1,17 @@
namespace Penumbra.Api.Enums;
/// <summary>
/// Describes known types of changed items that could provide special care.
/// </summary>
public enum ChangedItemType
{
None = 0,
Item = 1,
Action = 2,
Customization = 3,
ItemOffhand = 4,
Unknown = 5,
Emote = 6,
Model = 7,
CustomArmor = 8,
}

View File

@@ -0,0 +1,39 @@
namespace Penumbra.Api.Enums;
/// <summary>
/// The selection type for mod option groups.
/// </summary>
public enum GroupType
{
/// <summary>
/// Exactly one option of this group has to be selected (if any exist).
/// </summary>
Single,
/// <summary>
/// Any number of options in this group can be toggled on or off at the same time.
/// Limits the number of options in a single group to 32 at the most.
/// Each option is its own data container, which are independent of each other.
/// </summary>
Multi,
/// <summary>
/// Any number of options in this group can be toggled on or off at the same time.
/// Affects a single IMC entry, to manipulate different parts of a model in a user-facing way.
/// </summary>
Imc,
/// <summary>
/// Any number of options in this group can be toggled on or off at the same time.
/// Limits the number of options in a single group to 8 at the most.
/// Each combination of options is its own data container, resulting in 2^N separate data containers.
/// </summary>
Combining,
/// <summary>
/// A group consisting of multiple separate subgroups where the options can depend on each other.
/// Each subgroup behaves the same way as its regular group type, just with optional dependencies on the other options.
/// The total number of options is still limited by the settings bit size.
/// </summary>
Complex,
}

View File

@@ -0,0 +1,34 @@
namespace Penumbra.Api.Enums;
/// <summary>
/// Describes the way a mod can change its settings.
/// </summary>
public enum ModSettingChange
{
/// <summary> It was set to inherit from other collections or not to inherit anymore. </summary>
Inheritance,
/// <summary> It was enabled or disabled. </summary>
EnableState,
/// <summary> Its priority was changed. </summary>
Priority,
/// <summary> A specific setting for an option group was changed. </summary>
Setting,
/// <summary> Multiple mods were set to inherit from other collections or not inherit anymore at once. </summary>
MultiInheritance,
/// <summary> Multiple mods were enabled or disabled at once. </summary>
MultiEnableState,
/// <summary> A temporary mod was enabled or disabled. </summary>
TemporaryMod,
/// <summary> A mod was edited. Only invoked on edits affecting the current players collection and for that for now. </summary>
Edited,
/// <summary> A temporary setting was added, removed or changed. </summary>
TemporarySetting,
}

View File

@@ -0,0 +1,12 @@
namespace Penumbra.Api.Enums;
/// <summary>
/// Describes which mouse button was used to click an element.
/// </summary>
public enum MouseButton
{
None,
Left,
Right,
Middle,
}

View File

@@ -0,0 +1,33 @@
namespace Penumbra.Api.Enums;
/// <summary>
/// Error codes returned by some Penumbra.Api calls.
/// </summary>
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,
CollectionExists = 13,
AssignmentCreationDisallowed = 14,
AssignmentDeletionDisallowed = 15,
InvalidIdentifier = 16,
SystemDisposed = 17,
AssignmentDeletionFailed = 18,
TemporarySettingDisallowed = 19,
TemporarySettingImpossible = 20,
UnknownError = 255,
}

View File

@@ -0,0 +1,11 @@
namespace Penumbra.Api.Enums;
/// <summary>
/// The way a specific game object shall be redrawn.
/// Actors can be redrawn immediately or after GPose.
/// </summary>
public enum RedrawType
{
Redraw,
AfterGPose,
}

View File

@@ -0,0 +1,79 @@
namespace Penumbra.Api.Enums;
public enum ResourceType : uint
{
Unknown = 0,
Aet = 0x00616574,
Amb = 0x00616D62,
Atch = 0x61746368,
Atex = 0x61746578,
Avfx = 0x61766678,
Awt = 0x00617774,
Bklb = 0x626B6C62,
Cmp = 0x00636D70,
Cutb = 0x63757462,
Dic = 0x00646963,
Eanb = 0x65616E62,
Eid = 0x00656964,
Envb = 0x656E7662,
Eqdp = 0x65716470,
Eqp = 0x00657170,
Eslb = 0x65736C63,
Essb = 0x65737362,
Est = 0x00657374,
Evp = 0x00657670,
Exd = 0x00657864,
Exh = 0x00657868,
Exl = 0x0065786C,
Fdt = 0x00666474,
Fpeb = 0x66706562,
Gfd = 0x00676664,
Ggd = 0x00676764,
Gmp = 0x00676D70,
Gzd = 0x00677A64,
Imc = 0x00696D63,
Kdb = 0x006B6462,
Kdlb = 0x6B646C62,
Lcb = 0x006C6362,
Lgb = 0x006C6762,
Luab = 0x6C756162,
Lvb = 0x006C7662,
Mdl = 0x006D646C,
Mlt = 0x006D6C74,
Mtrl = 0x6D74726C,
Obsb = 0x6F627362,
Pap = 0x00706170,
Pbd = 0x00706264,
Pcb = 0x00706362,
Phyb = 0x70687962,
Plt = 0x00706C74,
Scd = 0x00736364,
Sgb = 0x00736762,
Shcd = 0x73686364,
Shpk = 0x7368706B,
Sklb = 0x736B6C62,
Skp = 0x00736B70,
Stm = 0x0073746D,
Svb = 0x00737662,
Tera = 0x74657261,
Tex = 0x00746578,
Tmb = 0x00746D62,
Ugd = 0x00756764,
Uld = 0x00756C64,
Waoe = 0x77616F65,
Wtd = 0x00777464,
}
public static class ResourceTypeExtensions
{
public static ResourceType FromExtension(ReadOnlySpan<byte> ext)
=> ext.Length switch
{
0 => ResourceType.Unknown,
1 => (ResourceType)(ext[0] | 32),
2 => (ResourceType)(ext[0] | 32 | ((ext[1] | 32) << 8)),
3 => (ResourceType)(ext[0] | 32 | ((ext[1] | 32) << 8) | ((ext[2] | 32) << 16)),
4 => (ResourceType)(ext[0] | 32 | ((ext[1] | 32) << 8) | ((ext[2] | 32) << 16) | ((ext[2] | 32) << 24)),
_ => ResourceType.Unknown,
};
}

View File

@@ -0,0 +1,19 @@
namespace Penumbra.Api.Enums;
/// <summary>
/// The different tabs of the main window that are available.
/// </summary>
public enum TabType
{
None = -1,
Settings = 0,
Mods = 1,
Collections = 2,
ChangedItems = 3,
EffectiveChanges = 4,
ResourceWatcher = 5,
Debug = 6,
ResourceManager = 7,
OnScreen = 8,
Messages = 9,
}

View File

@@ -0,0 +1,37 @@
namespace Penumbra.Api.Enums;
/// <summary>
/// The different types of textures a given texture can be converted to.
/// </summary>
public enum TextureType
{
/// <summary> Convert the texture to .png. </summary>
Png = 0,
/// <summary> Keep the texture format as it is but save as .tex. </summary>
AsIsTex = 1,
/// <summary> Keep the texture format as it is but save as .dds. </summary>
AsIsDds = 2,
/// <summary> Convert the texture to RGBA32 and save as .tex. </summary>
RgbaTex = 3,
/// <summary> Convert the texture to RGBA32 and save as .dds. </summary>
RgbaDds = 4,
/// <summary> Convert the texture to BC3 and save as .tex. </summary>
Bc3Tex = 5,
/// <summary> Convert the texture to BC3 and save as .dds. </summary>
Bc3Dds = 6,
/// <summary> Convert the texture to BC3 and save as .tex. </summary>
Bc7Tex = 7,
/// <summary> Convert the texture to BC3 and save as .dds. </summary>
Bc7Dds = 8,
/// <summary> Convert the texture to .tga. </summary>
Targa = 9,
}

View File

@@ -0,0 +1,5 @@
// Global using directives
global using System;
global using System.Collections.Generic;
global using System.Threading.Tasks;

View File

@@ -0,0 +1,136 @@
using Dalamud.Plugin;
using Dalamud.Plugin.Ipc;
namespace Penumbra.Api.Helpers;
/// <summary>
/// Specialized disposable Provider for Actions.
/// </summary>
public sealed class ActionProvider : IDisposable
{
private ICallGateProvider<object?>? _provider;
public ActionProvider(IDalamudPluginInterface pi, string label, Action action)
{
try
{
_provider = pi.GetIpcProvider<object?>(label);
}
catch (Exception e)
{
PluginLogHelper.WriteError(pi, $"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();
}
/// <summary>
/// Specialized disposable Provider for Actions.
/// </summary>
public sealed class ActionProvider<T1> : IDisposable
{
private ICallGateProvider<T1, object?>? _provider;
public ActionProvider(IDalamudPluginInterface pi, string label, Action<T1> action)
{
try
{
_provider = pi.GetIpcProvider<T1, object?>(label);
}
catch (Exception e)
{
PluginLogHelper.WriteError(pi, $"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();
}
/// <summary>
/// <inheritdoc cref="ActionProvider{T1}"/>
/// </summary>
public sealed class ActionProvider<T1, T2> : IDisposable
{
private ICallGateProvider<T1, T2, object?>? _provider;
public ActionProvider(IDalamudPluginInterface pi, string label, Action<T1, T2> action)
{
try
{
_provider = pi.GetIpcProvider<T1, T2, object?>(label);
}
catch (Exception e)
{
PluginLogHelper.WriteError(pi, $"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();
}
/// <summary>
/// <inheritdoc cref="ActionProvider{T1}"/>
/// </summary>
public sealed class ActionProvider<T1, T2, T3> : IDisposable
{
private ICallGateProvider<T1, T2, T3, object?>? _provider;
public ActionProvider(IDalamudPluginInterface pi, string label, Action<T1, T2, T3> action)
{
try
{
_provider = pi.GetIpcProvider<T1, T2, T3, object?>(label);
}
catch (Exception e)
{
PluginLogHelper.WriteError(pi, $"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,114 @@
using Dalamud.Plugin;
using Dalamud.Plugin.Ipc;
namespace Penumbra.Api.Helpers;
/// <summary>
/// Specialized subscriber only allowing to invoke actions.
/// </summary>
public class ActionSubscriber
{
private readonly ICallGateSubscriber<object?>? _subscriber;
/// <summary> Whether the subscriber could successfully be created. </summary>
public bool Valid
=> _subscriber != null;
protected ActionSubscriber(IDalamudPluginInterface pi, string label)
{
try
{
_subscriber = pi.GetIpcSubscriber<object?>(label);
}
catch (Exception e)
{
PluginLogHelper.WriteError(pi, $"Error registering IPC Subscriber for {label}\n{e}");
_subscriber = null;
}
}
/// <summary> Invoke the action. See the source of the subscriber for details.</summary>
protected void Invoke()
=> _subscriber?.InvokeAction();
}
/// <inheritdoc cref="ActionSubscriber"/>
public class ActionSubscriber<T1>
{
private readonly ICallGateSubscriber<T1, object?>? _subscriber;
/// <summary> Whether the subscriber could successfully be created. </summary>
public bool Valid
=> _subscriber != null;
protected ActionSubscriber(IDalamudPluginInterface pi, string label)
{
try
{
_subscriber = pi.GetIpcSubscriber<T1, object?>(label);
}
catch (Exception e)
{
PluginLogHelper.WriteError(pi, $"Error registering IPC Subscriber for {label}\n{e}");
_subscriber = null;
}
}
/// <summary> Invoke the action. See the source of the subscriber for details.</summary>
protected void Invoke(T1 a)
=> _subscriber?.InvokeAction(a);
}
/// <inheritdoc cref="ActionSubscriber"/>
public class ActionSubscriber<T1, T2>
{
private readonly ICallGateSubscriber<T1, T2, object?>? _subscriber;
/// <inheritdoc cref="ActionSubscriber{T1}.Valid"/>
public bool Valid
=> _subscriber != null;
protected ActionSubscriber(IDalamudPluginInterface pi, string label)
{
try
{
_subscriber = pi.GetIpcSubscriber<T1, T2, object?>(label);
}
catch (Exception e)
{
PluginLogHelper.WriteError(pi, $"Error registering IPC Subscriber for {label}\n{e}");
_subscriber = null;
}
}
/// <inheritdoc cref="ActionSubscriber.Invoke"/>
protected void Invoke(T1 a, T2 b)
=> _subscriber?.InvokeAction(a, b);
}
/// <inheritdoc cref="ActionSubscriber"/>
public class ActionSubscriber<T1, T2, T3>
{
private readonly ICallGateSubscriber<T1, T2, T3, object?>? _subscriber;
/// <inheritdoc cref="ActionSubscriber{T1}.Valid"/>
public bool Valid
=> _subscriber != null;
protected ActionSubscriber(IDalamudPluginInterface pi, string label)
{
try
{
_subscriber = pi.GetIpcSubscriber<T1, T2, T3, object?>(label);
}
catch (Exception e)
{
PluginLogHelper.WriteError(pi, $"Error registering IPC Subscriber for {label}\n{e}");
_subscriber = null;
}
}
/// <inheritdoc cref="ActionSubscriber.Invoke"/>
protected void Invoke(T1 a, T2 b, T3 c)
=> _subscriber?.InvokeAction(a, b, c);
}

View File

@@ -0,0 +1,152 @@
using System.Collections;
using System.Runtime.CompilerServices;
namespace Penumbra.Api.Helpers;
/// <summary> A dictionary that implicitly can be converted to a read-only dictionary with different value type. </summary>
/// <typeparam name="TKey"> The type of the keys. </typeparam>
/// <typeparam name="TValueFrom"> The actual type of the values. </typeparam>
/// <typeparam name="TValueTo"> The read-only type of the values. </typeparam>
public abstract class ConvertingDict<TKey, TValueFrom, TValueTo>(IReadOnlyDictionary<TKey, TValueFrom> dict)
: IReadOnlyDictionary<TKey, TValueTo>
where TKey : notnull
{
/// <summary> Obtain the original dictionary. </summary>
public IReadOnlyDictionary<TKey, TValueFrom> Original
=> dict;
/// <summary> Conversion between values. </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
protected abstract TValueTo ConvertValue(in TValueFrom from);
/// <inheritdoc/>
public bool ContainsKey(TKey key)
=> dict.ContainsKey(key);
/// <inheritdoc/>
public bool TryGetValue(TKey key, out TValueTo value)
{
if (dict.TryGetValue(key, out var v))
{
value = ConvertValue(v);
return true;
}
value = default!;
return false;
}
/// <inheritdoc/>
public TValueTo this[TKey key]
=> ConvertValue(dict[key]);
public IEnumerable<TKey> Keys
=> dict.Keys;
/// <inheritdoc/>
public IEnumerable<TValueTo> Values
{
get
{
foreach (var value in dict.Values)
yield return ConvertValue(value);
}
}
/// <inheritdoc/>
public int Count
=> dict.Count;
/// <inheritdoc/>
public IEnumerator<KeyValuePair<TKey, TValueTo>> GetEnumerator()
{
foreach (var kvp in dict)
yield return new KeyValuePair<TKey, TValueTo>(kvp.Key, ConvertValue(kvp.Value));
}
IEnumerator IEnumerable.GetEnumerator()
=> GetEnumerator();
}
/// <summary> A dictionary that implicitly can be converted to a read-only dictionary with different value type. </summary>
/// <typeparam name="TKeyFrom"> The actual type of the keys. </typeparam>
/// <typeparam name="TKeyTo"> The read-only type of the keys. </typeparam>
/// <typeparam name="TValueFrom"> The actual type of the values. </typeparam>
/// <typeparam name="TValueTo"> The read-only type of the values. </typeparam>
public abstract class ConvertingDict<TKeyFrom, TKeyTo, TValueFrom, TValueTo>(IReadOnlyDictionary<TKeyFrom, TValueFrom> dict)
: IReadOnlyDictionary<TKeyTo, TValueTo>
where TKeyFrom : notnull
where TKeyTo : notnull
{
/// <summary> Obtain the original dictionary. </summary>
public IReadOnlyDictionary<TKeyFrom, TValueFrom> Original
=> dict;
/// <summary> Conversion between keys. </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
protected abstract TKeyTo ConvertKey(in TKeyFrom from);
/// <summary> Conversion between keys. </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
protected abstract TKeyFrom ConvertKeyBack(in TKeyTo from);
/// <summary> Conversion between values. </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
protected abstract TValueTo ConvertValue(in TValueFrom from);
/// <inheritdoc/>
public bool ContainsKey(TKeyTo key)
=> dict.ContainsKey(ConvertKeyBack(key));
/// <inheritdoc/>
public bool TryGetValue(TKeyTo key, out TValueTo value)
{
if (dict.TryGetValue(ConvertKeyBack(key), out var v))
{
value = ConvertValue(v);
return true;
}
value = default!;
return false;
}
/// <inheritdoc/>
public TValueTo this[TKeyTo key]
=> ConvertValue(dict[ConvertKeyBack(key)]);
/// <inheritdoc/>
public IEnumerable<TKeyTo> Keys
{
get
{
foreach (var key in dict.Keys)
yield return ConvertKey(key);
}
}
/// <inheritdoc/>
public IEnumerable<TValueTo> Values
{
get
{
foreach (var value in dict.Values)
yield return ConvertValue(value);
}
}
/// <inheritdoc/>
public IEnumerator<KeyValuePair<TKeyTo, TValueTo>> GetEnumerator()
{
foreach (var kvp in dict)
yield return new KeyValuePair<TKeyTo, TValueTo>(ConvertKey(kvp.Key), ConvertValue(kvp.Value));
}
/// <inheritdoc/>
IEnumerator IEnumerable.GetEnumerator()
=> GetEnumerator();
/// <inheritdoc/>
public int Count
=> dict.Count;
}

View File

@@ -0,0 +1,53 @@
using System.Runtime.CompilerServices;
using Penumbra.Api.Enums;
namespace Penumbra.Api.Helpers;
/// <summary> Wrapper dictionary. </summary>
public sealed class GameResourceDict(IReadOnlyDictionary<nint, (string, string, uint)> dict)
: ConvertingDict<nint, (string, string, uint), (string, string, ChangedItemIcon)>(dict)
{
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
protected override (string, string, ChangedItemIcon) ConvertValue(in (string, string, uint) from)
=> (from.Item1, from.Item2, (ChangedItemIcon)from.Item3);
/// <summary> Create dictionary or null. </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static GameResourceDict? Create(IReadOnlyDictionary<nint, (string, string, uint)>? dict)
=> dict == null ? null : new GameResourceDict(dict);
}
/// <summary> Wrapper dictionary. </summary>
public sealed class AvailableModSettings(IReadOnlyDictionary<string, (string[], int)> dict)
: ConvertingDict<string, (string[], int), (string[], GroupType)>(dict)
{
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
protected override (string[], GroupType) ConvertValue(in (string[], int) from)
=> (from.Item1, (GroupType)from.Item2);
/// <summary> Create dictionary or null. </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static AvailableModSettings? Create(IReadOnlyDictionary<string, (string[], int)>? dict)
=> dict == null ? null : new AvailableModSettings(dict);
}
public record ResourceNodeDto
{
public required ResourceType Type { get; init; }
public required ChangedItemIcon Icon { get; init; }
public required string? Name { get; init; }
public required string? GamePath { get; init; }
public required string ActualPath { get; init; }
public required nint ObjectAddress { get; init; }
public required nint ResourceHandle { get; init; }
public required List<ResourceNodeDto> Children { get; init; }
}
public record ResourceTreeDto
{
public required string Name { get; init; }
public required ushort RaceCode { get; init; }
public required List<ResourceNodeDto> Nodes { get; init; }
}

View File

@@ -0,0 +1,465 @@
using Dalamud.Plugin;
using Dalamud.Plugin.Ipc;
using Dalamud.Plugin.Services;
namespace Penumbra.Api.Helpers;
/// <summary>
/// Specialized disposable Provider for Events.<para />
/// Will execute the unsubscriber action on dispose if any is provided.<para />
/// Can only be invoked and disposed.
/// </summary>
public sealed class EventProvider : IDisposable
{
private readonly IPluginLog _log;
private ICallGateProvider<object?>? _provider;
private Delegate? _unsubscriber;
public EventProvider(IDalamudPluginInterface pi, string label, (Action<Action> Add, Action<Action> Del)? subscribe = null)
{
_unsubscriber = null;
_log = PluginLogHelper.GetLog(pi);
try
{
_provider = pi.GetIpcProvider<object?>(label);
subscribe?.Add(Invoke);
_unsubscriber = subscribe?.Del;
}
catch (Exception e)
{
_log.Error($"Error registering IPC Provider for {label}\n{e}");
_provider = null;
}
}
public EventProvider(IDalamudPluginInterface pi, string label, Action<EventProvider> add, Action<EventProvider> del)
{
_unsubscriber = null;
_log = PluginLogHelper.GetLog(pi);
try
{
_provider = pi.GetIpcProvider<object?>(label);
add(this);
_unsubscriber = del;
}
catch (Exception e)
{
_log.Error($"Error registering IPC Provider for {label}\n{e}");
_provider = null;
}
}
/// <summary> Invoke the event.</summary>
public void Invoke()
{
try
{
_provider?.SendMessage();
}
catch (Exception e)
{
_log.Error($"Exception thrown on IPC event:\n{e}");
}
}
public void Dispose()
{
switch (_unsubscriber)
{
case Action<Action> a:
a(Invoke);
break;
case Action<EventProvider> b:
b(this);
break;
}
_unsubscriber = null;
_provider = null;
GC.SuppressFinalize(this);
}
~EventProvider()
=> Dispose();
}
/// <inheritdoc cref="EventProvider"/>
public sealed class EventProvider<T1> : IDisposable
{
private readonly IPluginLog _log;
private ICallGateProvider<T1, object?>? _provider;
private Delegate? _unsubscriber;
public EventProvider(IDalamudPluginInterface pi, string label, (Action<Action<T1>> Add, Action<Action<T1>> Del)? subscribe = null)
{
_unsubscriber = null;
_log = PluginLogHelper.GetLog(pi);
try
{
_provider = pi.GetIpcProvider<T1, object?>(label);
subscribe?.Add(Invoke);
_unsubscriber = subscribe?.Del;
}
catch (Exception e)
{
_log.Error($"Error registering IPC Provider for {label}\n{e}");
_provider = null;
}
}
public EventProvider(IDalamudPluginInterface pi, string label, Action<EventProvider<T1>> add, Action<EventProvider<T1>> del)
{
_unsubscriber = null;
_log = PluginLogHelper.GetLog(pi);
try
{
_provider = pi.GetIpcProvider<T1, object?>(label);
add(this);
_unsubscriber = del;
}
catch (Exception e)
{
_log.Error($"Error registering IPC Provider for {label}\n{e}");
_provider = null;
}
}
/// <inheritdoc cref="EventProvider.Invoke"/>
public void Invoke(T1 a)
{
try
{
_provider?.SendMessage(a);
}
catch (Exception e)
{
_log.Error($"Exception thrown on IPC event:\n{e}");
}
}
public void Dispose()
{
switch (_unsubscriber)
{
case Action<Action<T1>> a:
a(Invoke);
break;
case Action<EventProvider<T1>> b:
b(this);
break;
}
_unsubscriber = null;
_provider = null;
GC.SuppressFinalize(this);
}
~EventProvider()
=> Dispose();
}
/// <inheritdoc cref="EventProvider"/>
public sealed class EventProvider<T1, T2> : IDisposable
{
private readonly IPluginLog _log;
private ICallGateProvider<T1, T2, object?>? _provider;
private Delegate? _unsubscriber;
public EventProvider(IDalamudPluginInterface pi, string label,
(Action<Action<T1, T2>> Add, Action<Action<T1, T2>> Del)? subscribe = null)
{
_unsubscriber = null;
_log = PluginLogHelper.GetLog(pi);
try
{
_provider = pi.GetIpcProvider<T1, T2, object?>(label);
subscribe?.Add(Invoke);
_unsubscriber = subscribe?.Del;
}
catch (Exception e)
{
_log.Error($"Error registering IPC Provider for {label}\n{e}");
_provider = null;
}
}
public EventProvider(IDalamudPluginInterface pi, string label, Action<EventProvider<T1, T2>> add, Action<EventProvider<T1, T2>> del)
{
_unsubscriber = null;
_log = PluginLogHelper.GetLog(pi);
try
{
_provider = pi.GetIpcProvider<T1, T2, object?>(label);
add(this);
_unsubscriber = del;
}
catch (Exception e)
{
_log.Error($"Error registering IPC Provider for {label}\n{e}");
_provider = null;
}
}
/// <inheritdoc cref="EventProvider.Invoke"/>
public void Invoke(T1 a, T2 b)
{
try
{
_provider?.SendMessage(a, b);
}
catch (Exception e)
{
_log.Error($"Exception thrown on IPC event:\n{e}");
}
}
public void Dispose()
{
switch (_unsubscriber)
{
case Action<Action<T1, T2>> a:
a(Invoke);
break;
case Action<EventProvider<T1, T2>> b:
b(this);
break;
}
_unsubscriber = null;
_provider = null;
GC.SuppressFinalize(this);
}
~EventProvider()
=> Dispose();
}
/// <inheritdoc cref="EventProvider"/>
public sealed class EventProvider<T1, T2, T3> : IDisposable
{
private readonly IPluginLog _log;
private ICallGateProvider<T1, T2, T3, object?>? _provider;
private Delegate? _unsubscriber;
public EventProvider(IDalamudPluginInterface pi, string label,
(Action<Action<T1, T2, T3>> Add, Action<Action<T1, T2, T3>> Del)? subscribe = null)
{
_unsubscriber = null;
_log = PluginLogHelper.GetLog(pi);
try
{
_provider = pi.GetIpcProvider<T1, T2, T3, object?>(label);
subscribe?.Add(Invoke);
_unsubscriber = subscribe?.Del;
}
catch (Exception e)
{
_log.Error($"Error registering IPC Provider for {label}\n{e}");
_provider = null;
}
}
public EventProvider(IDalamudPluginInterface pi, string label, Action<EventProvider<T1, T2, T3>> add, Action<EventProvider<T1, T2, T3>> del)
{
_unsubscriber = null;
_log = PluginLogHelper.GetLog(pi);
try
{
_provider = pi.GetIpcProvider<T1, T2, T3, object?>(label);
add(this);
_unsubscriber = del;
}
catch (Exception e)
{
_log.Error($"Error registering IPC Provider for {label}\n{e}");
_provider = null;
}
}
/// <inheritdoc cref="EventProvider.Invoke"/>
public void Invoke(T1 a, T2 b, T3 c)
{
try
{
_provider?.SendMessage(a, b, c);
}
catch (Exception e)
{
_log.Error($"Exception thrown on IPC event:\n{e}");
}
}
public void Dispose()
{
switch (_unsubscriber)
{
case Action<Action<T1, T2, T3>> a:
a(Invoke);
break;
case Action<EventProvider<T1, T2, T3>> b:
b(this);
break;
}
_unsubscriber = null;
_provider = null;
GC.SuppressFinalize(this);
}
~EventProvider()
=> Dispose();
}
/// <inheritdoc cref="EventProvider"/>
public sealed class EventProvider<T1, T2, T3, T4> : IDisposable
{
private readonly IPluginLog _log;
private ICallGateProvider<T1, T2, T3, T4, object?>? _provider;
private Delegate? _unsubscriber;
public EventProvider(IDalamudPluginInterface pi, string label,
(Action<Action<T1, T2, T3, T4>> Add, Action<Action<T1, T2, T3, T4>> Del)? subscribe = null)
{
_unsubscriber = null;
_log = PluginLogHelper.GetLog(pi);
try
{
_provider = pi.GetIpcProvider<T1, T2, T3, T4, object?>(label);
subscribe?.Add(Invoke);
_unsubscriber = subscribe?.Del;
}
catch (Exception e)
{
_log.Error($"Error registering IPC Provider for {label}\n{e}");
_provider = null;
}
}
public EventProvider(IDalamudPluginInterface pi, string label, Action<EventProvider<T1, T2, T3, T4>> add,
Action<EventProvider<T1, T2, T3, T4>> del)
{
_unsubscriber = null;
_log = PluginLogHelper.GetLog(pi);
try
{
_provider = pi.GetIpcProvider<T1, T2, T3, T4, object?>(label);
add(this);
_unsubscriber = del;
}
catch (Exception e)
{
_log.Error($"Error registering IPC Provider for {label}\n{e}");
_provider = null;
}
}
/// <inheritdoc cref="EventProvider.Invoke"/>
public void Invoke(T1 a, T2 b, T3 c, T4 d)
{
try
{
_provider?.SendMessage(a, b, c, d);
}
catch (Exception e)
{
_log.Error($"Exception thrown on IPC event:\n{e}");
}
}
public void Dispose()
{
switch (_unsubscriber)
{
case Action<Action<T1, T2, T3, T4>> a:
a(Invoke);
break;
case Action<EventProvider<T1, T2, T3, T4>> b:
b(this);
break;
}
_unsubscriber = null;
_provider = null;
GC.SuppressFinalize(this);
}
~EventProvider()
=> Dispose();
}
/// <inheritdoc cref="EventProvider"/>
public sealed class EventProvider<T1, T2, T3, T4, T5> : IDisposable
{
private readonly IPluginLog _log;
private ICallGateProvider<T1, T2, T3, T4, T5, object?>? _provider;
private Delegate? _unsubscriber;
public EventProvider(IDalamudPluginInterface pi, string label,
(Action<Action<T1, T2, T3, T4, T5>> Add, Action<Action<T1, T2, T3, T4, T5>> Del)? subscribe = null)
{
_unsubscriber = null;
_log = PluginLogHelper.GetLog(pi);
try
{
_provider = pi.GetIpcProvider<T1, T2, T3, T4, T5, object?>(label);
subscribe?.Add(Invoke);
_unsubscriber = subscribe?.Del;
}
catch (Exception e)
{
_log.Error($"Error registering IPC Provider for {label}\n{e}");
_provider = null;
}
}
public EventProvider(IDalamudPluginInterface pi, string label, Action<EventProvider<T1, T2, T3, T4, T5>> add,
Action<EventProvider<T1, T2, T3, T4, T5>> del)
{
_unsubscriber = null;
_log = PluginLogHelper.GetLog(pi);
try
{
_provider = pi.GetIpcProvider<T1, T2, T3, T4, T5, object?>(label);
add(this);
_unsubscriber = del;
}
catch (Exception e)
{
_log.Error($"Error registering IPC Provider for {label}\n{e}");
_provider = null;
}
}
/// <inheritdoc cref="EventProvider.Invoke"/>
public void Invoke(T1 a, T2 b, T3 c, T4 d, T5 e)
{
try
{
_provider?.SendMessage(a, b, c, d, e);
}
catch (Exception ex)
{
_log.Error($"Exception thrown on IPC event:\n{ex}");
}
}
public void Dispose()
{
switch (_unsubscriber)
{
case Action<Action<T1, T2, T3, T4, T5>> a:
a(Invoke);
break;
case Action<EventProvider<T1, T2, T3, T4, T5>> b:
b(this);
break;
}
_unsubscriber = null;
_provider = null;
GC.SuppressFinalize(this);
}
~EventProvider()
=> Dispose();
}

View File

@@ -0,0 +1,582 @@
using Dalamud.Plugin;
using Dalamud.Plugin.Ipc;
using Dalamud.Plugin.Services;
namespace Penumbra.Api.Helpers;
/// <summary>
/// Specialized disposable Subscriber for Events.<para />
/// Subscriptions are wrapped to be individually exception-safe.<para/>
/// Can be enabled and disabled.<para/>
/// </summary>
public sealed class EventSubscriber : IDisposable
{
private readonly string _label;
private readonly IPluginLog _log;
private readonly Dictionary<Action, Action> _delegates = new();
private ICallGateSubscriber<object?>? _subscriber;
private bool _disabled;
public EventSubscriber(IDalamudPluginInterface pi, string label, params Action[] actions)
{
_label = label;
_log = PluginLogHelper.GetLog(pi);
try
{
_subscriber = pi.GetIpcSubscriber<object?>(label);
foreach (var action in actions)
Event += action;
_disabled = false;
}
catch (Exception e)
{
_log.Error($"Error registering IPC Subscriber for {label}\n{e}");
_subscriber = null;
}
}
/// <summary>
/// Enable all currently subscribed actions registered with this EventSubscriber.
/// Does nothing if it is already enabled.
/// </summary>
public void Enable()
{
if (_disabled && _subscriber != null)
{
foreach (var action in _delegates.Values)
_subscriber.Subscribe(action);
_disabled = false;
}
}
/// <summary>
/// Disable all subscribed actions registered with this EventSubscriber.
/// Does nothing if it is already disabled.
/// Does not forget the actions, only disables them.
/// </summary>
public void Disable()
{
if (!_disabled)
{
if (_subscriber != null)
foreach (var action in _delegates.Values)
_subscriber.Unsubscribe(action);
_disabled = true;
}
}
/// <summary>
/// Add or remove an action to the IPC event, if it is valid.
/// </summary>
public event Action Event
{
add
{
if (_subscriber != null && !_delegates.ContainsKey(value))
{
void Action()
{
try
{
value();
}
catch (Exception e)
{
_log.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();
}
/// <summary><inheritdoc cref="EventSubscriber"/> </summary>
public sealed class EventSubscriber<T1> : IDisposable
{
private readonly string _label;
private readonly IPluginLog _log;
private readonly Dictionary<Action<T1>, Action<T1>> _delegates = new();
private ICallGateSubscriber<T1, object?>? _subscriber;
private bool _disabled;
public EventSubscriber(IDalamudPluginInterface pi, string label, params Action<T1>[] actions)
{
_label = label;
_log = PluginLogHelper.GetLog(pi);
try
{
_subscriber = pi.GetIpcSubscriber<T1, object?>(label);
foreach (var action in actions)
Event += action;
_disabled = false;
}
catch (Exception e)
{
_log.Error($"Error registering IPC Subscriber for {label}\n{e}");
_subscriber = null;
}
}
/// <summary><inheritdoc cref="EventSubscriber.Enable"/> </summary>
public void Enable()
{
if (_disabled && _subscriber != null)
{
foreach (var action in _delegates.Values)
_subscriber.Subscribe(action);
_disabled = false;
}
}
/// <summary><inheritdoc cref="EventSubscriber.Disable"/> </summary>
public void Disable()
{
if (!_disabled)
{
if (_subscriber != null)
foreach (var action in _delegates.Values)
_subscriber.Unsubscribe(action);
_disabled = true;
}
}
/// <summary><inheritdoc cref="EventSubscriber.Event"/> </summary>
public event Action<T1> Event
{
add
{
if (_subscriber != null && !_delegates.ContainsKey(value))
{
void Action(T1 a)
{
try
{
value(a);
}
catch (Exception e)
{
_log.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();
}
/// <summary><inheritdoc cref="EventSubscriber"/> </summary>
public sealed class EventSubscriber<T1, T2> : IDisposable
{
private readonly string _label;
private readonly IPluginLog _log;
private readonly Dictionary<Action<T1, T2>, Action<T1, T2>> _delegates = new();
private ICallGateSubscriber<T1, T2, object?>? _subscriber;
private bool _disabled;
public EventSubscriber(IDalamudPluginInterface pi, string label, params Action<T1, T2>[] actions)
{
_label = label;
_log = PluginLogHelper.GetLog(pi);
try
{
_subscriber = pi.GetIpcSubscriber<T1, T2, object?>(label);
foreach (var action in actions)
Event += action;
_disabled = false;
}
catch (Exception e)
{
_log.Error($"Error registering IPC Subscriber for {label}\n{e}");
_subscriber = null;
}
}
/// <summary><inheritdoc cref="EventSubscriber.Enable"/> </summary>
public void Enable()
{
if (_disabled && _subscriber != null)
{
foreach (var action in _delegates.Values)
_subscriber.Subscribe(action);
_disabled = false;
}
}
/// <summary><inheritdoc cref="EventSubscriber.Disable"/> </summary>
public void Disable()
{
if (!_disabled)
{
if (_subscriber != null)
foreach (var action in _delegates.Values)
_subscriber.Unsubscribe(action);
_disabled = true;
}
}
/// <summary><inheritdoc cref="EventSubscriber.Event"/> </summary>
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)
{
_log.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();
}
/// <summary><inheritdoc cref="EventSubscriber"/> </summary>
public sealed class EventSubscriber<T1, T2, T3> : IDisposable
{
private readonly string _label;
private readonly IPluginLog _log;
private readonly Dictionary<Action<T1, T2, T3>, Action<T1, T2, T3>> _delegates = [];
private ICallGateSubscriber<T1, T2, T3, object?>? _subscriber;
private bool _disabled;
public EventSubscriber(IDalamudPluginInterface pi, string label, params Action<T1, T2, T3>[] actions)
{
_label = label;
_log = PluginLogHelper.GetLog(pi);
try
{
_subscriber = pi.GetIpcSubscriber<T1, T2, T3, object?>(label);
foreach (var action in actions)
Event += action;
_disabled = false;
}
catch (Exception e)
{
_log.Error($"Error registering IPC Subscriber for {label}\n{e}");
_subscriber = null;
}
}
/// <summary><inheritdoc cref="EventSubscriber.Enable"/> </summary>
public void Enable()
{
if (_disabled && _subscriber != null)
{
foreach (var action in _delegates.Values)
_subscriber.Subscribe(action);
_disabled = false;
}
}
/// <summary><inheritdoc cref="EventSubscriber.Disable"/> </summary>
public void Disable()
{
if (!_disabled)
{
if (_subscriber != null)
foreach (var action in _delegates.Values)
_subscriber.Unsubscribe(action);
_disabled = true;
}
}
/// <summary><inheritdoc cref="EventSubscriber.Event"/> </summary>
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)
{
_log.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();
}
/// <summary><inheritdoc cref="EventSubscriber"/> </summary>
public sealed class EventSubscriber<T1, T2, T3, T4> : IDisposable
{
private readonly string _label;
private readonly IPluginLog _log;
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(IDalamudPluginInterface pi, string label, params Action<T1, T2, T3, T4>[] actions)
{
_label = label;
_log = PluginLogHelper.GetLog(pi);
try
{
_subscriber = pi.GetIpcSubscriber<T1, T2, T3, T4, object?>(label);
foreach (var action in actions)
Event += action;
_disabled = false;
}
catch (Exception e)
{
_log.Error($"Error registering IPC Subscriber for {label}\n{e}");
_subscriber = null;
}
}
/// <summary><inheritdoc cref="EventSubscriber.Enable"/> </summary>
public void Enable()
{
if (_disabled && _subscriber != null)
{
foreach (var action in _delegates.Values)
_subscriber.Subscribe(action);
_disabled = false;
}
}
/// <summary><inheritdoc cref="EventSubscriber.Disable"/> </summary>
public void Disable()
{
if (!_disabled)
{
if (_subscriber != null)
foreach (var action in _delegates.Values)
_subscriber.Unsubscribe(action);
_disabled = true;
}
}
/// <summary><inheritdoc cref="EventSubscriber.Event"/> </summary>
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)
{
_log.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();
}
/// <summary><inheritdoc cref="EventSubscriber"/> </summary>
public sealed class EventSubscriber<T1, T2, T3, T4, T5> : IDisposable
{
private readonly string _label;
private readonly IPluginLog _log;
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(IDalamudPluginInterface pi, string label, params Action<T1, T2, T3, T4, T5>[] actions)
{
_label = label;
_log = PluginLogHelper.GetLog(pi);
try
{
_subscriber = pi.GetIpcSubscriber<T1, T2, T3, T4, T5, object?>(label);
foreach (var action in actions)
Event += action;
_disabled = false;
}
catch (Exception e)
{
_log.Error($"Error registering IPC Subscriber for {label}\n{e}");
_subscriber = null;
}
}
/// <summary><inheritdoc cref="EventSubscriber.Enable"/> </summary>
public void Enable()
{
if (_disabled && _subscriber != null)
{
foreach (var action in _delegates.Values)
_subscriber.Subscribe(action);
_disabled = false;
}
}
/// <summary><inheritdoc cref="EventSubscriber.Disable"/> </summary>
public void Disable()
{
if (!_disabled)
{
if (_subscriber != null)
foreach (var action in _delegates.Values)
_subscriber.Unsubscribe(action);
_disabled = true;
}
}
/// <summary><inheritdoc cref="EventSubscriber.Event"/> </summary>
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)
{
_log.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();
}

View File

@@ -0,0 +1,223 @@
using Dalamud.Plugin;
using Dalamud.Plugin.Ipc;
namespace Penumbra.Api.Helpers;
/// <summary>
/// Specialized disposable Provider for Funcs.
/// </summary>
public sealed class FuncProvider<TRet> : IDisposable
{
private ICallGateProvider<TRet>? _provider;
public FuncProvider(IDalamudPluginInterface pi, string label, Func<TRet> func)
{
try
{
_provider = pi.GetIpcProvider<TRet>(label);
}
catch (Exception e)
{
PluginLogHelper.WriteError(pi, $"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();
}
/// <inheritdoc cref="FuncProvider{TRet}"/>
public sealed class FuncProvider<T1, TRet> : IDisposable
{
private ICallGateProvider<T1, TRet>? _provider;
public FuncProvider(IDalamudPluginInterface pi, string label, Func<T1, TRet> func)
{
try
{
_provider = pi.GetIpcProvider<T1, TRet>(label);
}
catch (Exception e)
{
PluginLogHelper.WriteError(pi, $"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();
}
/// <inheritdoc cref="FuncProvider{TRet}"/>
public sealed class FuncProvider<T1, T2, TRet> : IDisposable
{
private ICallGateProvider<T1, T2, TRet>? _provider;
public FuncProvider(IDalamudPluginInterface pi, string label, Func<T1, T2, TRet> func)
{
try
{
_provider = pi.GetIpcProvider<T1, T2, TRet>(label);
}
catch (Exception e)
{
PluginLogHelper.WriteError(pi, $"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();
}
/// <inheritdoc cref="FuncProvider{TRet}"/>
public sealed class FuncProvider<T1, T2, T3, TRet> : IDisposable
{
private ICallGateProvider<T1, T2, T3, TRet>? _provider;
public FuncProvider(IDalamudPluginInterface pi, string label, Func<T1, T2, T3, TRet> func)
{
try
{
_provider = pi.GetIpcProvider<T1, T2, T3, TRet>(label);
}
catch (Exception e)
{
PluginLogHelper.WriteError(pi, $"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();
}
/// <inheritdoc cref="FuncProvider{TRet}"/>
public sealed class FuncProvider<T1, T2, T3, T4, TRet> : IDisposable
{
private ICallGateProvider<T1, T2, T3, T4, TRet>? _provider;
public FuncProvider(IDalamudPluginInterface pi, string label, Func<T1, T2, T3, T4, TRet> func)
{
try
{
_provider = pi.GetIpcProvider<T1, T2, T3, T4, TRet>(label);
}
catch (Exception e)
{
PluginLogHelper.WriteError(pi, $"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();
}
/// <inheritdoc cref="FuncProvider{TRet}"/>
public sealed class FuncProvider<T1, T2, T3, T4, T5, TRet> : IDisposable
{
private ICallGateProvider<T1, T2, T3, T4, T5, TRet>? _provider;
public FuncProvider(IDalamudPluginInterface 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)
{
PluginLogHelper.WriteError(pi, $"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();
}
/// <inheritdoc cref="FuncProvider{TRet}"/>
public sealed class FuncProvider<T1, T2, T3, T4, T5, T6, TRet> : IDisposable
{
private ICallGateProvider<T1, T2, T3, T4, T5, T6, TRet>? _provider;
public FuncProvider(IDalamudPluginInterface pi, string label, Func<T1, T2, T3, T4, T5, T6, TRet> func)
{
try
{
_provider = pi.GetIpcProvider<T1, T2, T3, T4, T5, T6, TRet>(label);
}
catch (Exception e)
{
PluginLogHelper.WriteError(pi, $"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,217 @@
using Dalamud.Plugin;
using Dalamud.Plugin.Ipc;
using Dalamud.Plugin.Ipc.Exceptions;
namespace Penumbra.Api.Helpers;
/// <summary>
/// Specialized subscriber only allowing to invoke functions with a return.
/// </summary>
public class FuncSubscriber<TRet>
{
private readonly string _label;
private readonly ICallGateSubscriber<TRet>? _subscriber;
/// <summary> Whether the subscriber could successfully be created. </summary>
public bool Valid
=> _subscriber != null;
/// <inheritdoc cref="FuncSubscriber{TRet}"/>
protected FuncSubscriber(IDalamudPluginInterface pi, string label)
{
_label = label;
try
{
_subscriber = pi.GetIpcSubscriber<TRet>(label);
}
catch (Exception e)
{
PluginLogHelper.WriteError(pi, $"Error registering IPC Subscriber for {label}\n{e}");
_subscriber = null;
}
}
/// <summary> Invoke the function. See the source of the subscriber for details.</summary>
protected TRet Invoke()
=> _subscriber != null ? _subscriber.InvokeFunc() : throw new IpcNotReadyError(_label);
}
/// <inheritdoc cref="FuncSubscriber{TRet}"/>
public class FuncSubscriber<T1, TRet>
{
private readonly string _label;
private readonly ICallGateSubscriber<T1, TRet>? _subscriber;
/// <inheritdoc cref="FuncSubscriber{TRet}.Valid"/>
public bool Valid
=> _subscriber != null;
/// <inheritdoc cref="FuncSubscriber{TRet}"/>
protected FuncSubscriber(IDalamudPluginInterface pi, string label)
{
_label = label;
try
{
_subscriber = pi.GetIpcSubscriber<T1, TRet>(label);
}
catch (Exception e)
{
PluginLogHelper.WriteError(pi, $"Error registering IPC Subscriber for {label}\n{e}");
_subscriber = null;
}
}
/// <inheritdoc cref="FuncSubscriber{TRet}.Invoke"/>
protected TRet Invoke(T1 a)
=> _subscriber != null ? _subscriber.InvokeFunc(a) : throw new IpcNotReadyError(_label);
}
/// <inheritdoc cref="FuncSubscriber{TRet}"/>
public class FuncSubscriber<T1, T2, TRet>
{
private readonly string _label;
private readonly ICallGateSubscriber<T1, T2, TRet>? _subscriber;
/// <inheritdoc cref="FuncSubscriber{TRet}.Valid"/>
public bool Valid
=> _subscriber != null;
/// <inheritdoc cref="FuncSubscriber{TRet}"/>
protected FuncSubscriber(IDalamudPluginInterface pi, string label)
{
_label = label;
try
{
_subscriber = pi.GetIpcSubscriber<T1, T2, TRet>(label);
}
catch (Exception e)
{
PluginLogHelper.WriteError(pi, $"Error registering IPC Subscriber for {label}\n{e}");
_subscriber = null;
}
}
/// <inheritdoc cref="FuncSubscriber{TRet}.Invoke"/>
protected TRet Invoke(T1 a, T2 b)
=> _subscriber != null ? _subscriber.InvokeFunc(a, b) : throw new IpcNotReadyError(_label);
}
/// <inheritdoc cref="FuncSubscriber{TRet}"/>
public class FuncSubscriber<T1, T2, T3, TRet>
{
private readonly string _label;
private readonly ICallGateSubscriber<T1, T2, T3, TRet>? _subscriber;
/// <inheritdoc cref="FuncSubscriber{TRet}.Valid"/>
public bool Valid
=> _subscriber != null;
/// <inheritdoc cref="FuncSubscriber{TRet}"/>
protected FuncSubscriber(IDalamudPluginInterface pi, string label)
{
_label = label;
try
{
_subscriber = pi.GetIpcSubscriber<T1, T2, T3, TRet>(label);
}
catch (Exception e)
{
PluginLogHelper.WriteError(pi, $"Error registering IPC Subscriber for {label}\n{e}");
_subscriber = null;
}
}
/// <inheritdoc cref="FuncSubscriber{TRet}.Invoke"/>
protected TRet Invoke(T1 a, T2 b, T3 c)
=> _subscriber != null ? _subscriber.InvokeFunc(a, b, c) : throw new IpcNotReadyError(_label);
}
/// <inheritdoc cref="FuncSubscriber{TRet}"/>
public class FuncSubscriber<T1, T2, T3, T4, TRet>
{
private readonly string _label;
private readonly ICallGateSubscriber<T1, T2, T3, T4, TRet>? _subscriber;
/// <inheritdoc cref="FuncSubscriber{TRet}.Valid"/>
public bool Valid
=> _subscriber != null;
/// <inheritdoc cref="FuncSubscriber{TRet}"/>
protected FuncSubscriber(IDalamudPluginInterface pi, string label)
{
_label = label;
try
{
_subscriber = pi.GetIpcSubscriber<T1, T2, T3, T4, TRet>(label);
}
catch (Exception e)
{
PluginLogHelper.WriteError(pi, $"Error registering IPC Subscriber for {label}\n{e}");
_subscriber = null;
}
}
/// <inheritdoc cref="FuncSubscriber{TRet}.Invoke"/>
protected TRet Invoke(T1 a, T2 b, T3 c, T4 d)
=> _subscriber != null ? _subscriber.InvokeFunc(a, b, c, d) : throw new IpcNotReadyError(_label);
}
/// <inheritdoc cref="FuncSubscriber{TRet}"/>
public class FuncSubscriber<T1, T2, T3, T4, T5, TRet>
{
private readonly string _label;
private readonly ICallGateSubscriber<T1, T2, T3, T4, T5, TRet>? _subscriber;
/// <inheritdoc cref="FuncSubscriber{TRet}.Valid"/>
public bool Valid
=> _subscriber != null;
/// <inheritdoc cref="FuncSubscriber{TRet}"/>
protected FuncSubscriber(IDalamudPluginInterface pi, string label)
{
_label = label;
try
{
_subscriber = pi.GetIpcSubscriber<T1, T2, T3, T4, T5, TRet>(label);
}
catch (Exception e)
{
PluginLogHelper.WriteError(pi, $"Error registering IPC Subscriber for {label}\n{e}");
_subscriber = null;
}
}
/// <inheritdoc cref="FuncSubscriber{TRet}.Invoke"/>
protected 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);
}
/// <inheritdoc cref="FuncSubscriber{TRet}"/>
public class FuncSubscriber<T1, T2, T3, T4, T5, T6, TRet>
{
private readonly string _label;
private readonly ICallGateSubscriber<T1, T2, T3, T4, T5, T6, TRet>? _subscriber;
/// <inheritdoc cref="FuncSubscriber{TRet}.Valid"/>
public bool Valid
=> _subscriber != null;
/// <inheritdoc cref="FuncSubscriber{TRet}"/>
protected FuncSubscriber(IDalamudPluginInterface pi, string label)
{
_label = label;
try
{
_subscriber = pi.GetIpcSubscriber<T1, T2, T3, T4, T5, T6, TRet>(label);
}
catch (Exception e)
{
PluginLogHelper.WriteError(pi, $"Error registering IPC Subscriber for {label}\n{e}");
_subscriber = null;
}
}
/// <inheritdoc cref="FuncSubscriber{TRet}.Invoke"/>
protected TRet Invoke(T1 a, T2 b, T3 c, T4 d, T5 e, T6 f)
=> _subscriber != null ? _subscriber.InvokeFunc(a, b, c, d, e, f) : throw new IpcNotReadyError(_label);
}

View File

@@ -0,0 +1,26 @@
using Dalamud.IoC;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
namespace Penumbra.Api.Helpers;
internal class PluginLogHelper
{
[PluginService]
private static IPluginLog? _log { get; set; }
private PluginLogHelper(IDalamudPluginInterface pi)
=> pi.Inject(this);
public static void WriteError(IDalamudPluginInterface pi, string errorMessage)
=> GetLog(pi).Error(errorMessage);
public static IPluginLog GetLog(IDalamudPluginInterface pi)
{
if (_log != null)
return _log;
_ = new PluginLogHelper(pi);
return _log!;
}
}

View File

@@ -0,0 +1,154 @@
using Dalamud.Plugin;
using Penumbra.Api.Api;
using Penumbra.Api.Enums;
using Penumbra.Api.Helpers;
namespace Penumbra.Api.IpcSubscribers;
/// <inheritdoc cref="IPenumbraApiCollection.GetCollections"/>
public sealed class GetCollections(IDalamudPluginInterface pi)
: FuncSubscriber<Dictionary<Guid, string>>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetCollections)}.V5";
/// <inheritdoc cref="IPenumbraApiCollection.GetCollections"/>
public new Dictionary<Guid, string> Invoke()
=> base.Invoke();
/// <summary> Create a provider. </summary>
public static FuncProvider<Dictionary<Guid, string>> Provider(IDalamudPluginInterface pi, IPenumbraApiCollection api)
=> new(pi, Label, api.GetCollections);
}
/// <inheritdoc cref="IPenumbraApiCollection.GetCollectionsByIdentifier"/>
public sealed class GetCollectionsByIdentifier(IDalamudPluginInterface pi)
: FuncSubscriber<string, List<(Guid Id, string Name)>>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetCollectionsByIdentifier)}";
/// <inheritdoc cref="IPenumbraApiCollection.GetCollectionsByIdentifier"/>
public new List<(Guid Id, string Name)> Invoke(string name)
=> base.Invoke(name);
/// <summary> Create a provider. </summary>
public static FuncProvider<string, List<(Guid Id, string Name)>> Provider(IDalamudPluginInterface pi, IPenumbraApiCollection api)
=> new(pi, Label, api.GetCollectionsByIdentifier);
}
/// <inheritdoc cref="IPenumbraApiCollection.GetChangedItemsForCollection"/>
public sealed class GetChangedItemsForCollection(IDalamudPluginInterface pi)
: FuncSubscriber<Guid, Dictionary<string, object?>>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetChangedItemsForCollection)}";
/// <inheritdoc cref="IPenumbraApiCollection.GetChangedItemsForCollection"/>
public new Dictionary<string, object?> Invoke(Guid collectionId)
=> base.Invoke(collectionId);
/// <summary> Create a provider. </summary>
public static FuncProvider<Guid, Dictionary<string, object?>> Provider(IDalamudPluginInterface pi, IPenumbraApiCollection api)
=> new(pi, Label, api.GetChangedItemsForCollection);
}
/// <inheritdoc cref="IPenumbraApiCollection.GetCollection"/>
public sealed class GetCollection(IDalamudPluginInterface pi)
: FuncSubscriber<byte, (Guid Id, string Name)?>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetCollection)}";
/// <inheritdoc cref="IPenumbraApiCollection.GetCollection"/>
public (Guid Id, string Name)? Invoke(ApiCollectionType type)
=> Invoke((byte)type);
/// <summary> Create a provider. </summary>
public static FuncProvider<byte, (Guid Id, string Name)?> Provider(IDalamudPluginInterface pi, IPenumbraApiCollection api)
=> new(pi, Label, b => api.GetCollection((ApiCollectionType)b));
}
/// <inheritdoc cref="IPenumbraApiCollection.GetCollectionForObject"/>
public sealed class GetCollectionForObject(IDalamudPluginInterface pi)
: FuncSubscriber<int, (bool ObjectValid, bool IndividualSet, (Guid Id, string Name) EffectiveCollection)>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetCollectionForObject)}.V5";
/// <inheritdoc cref="IPenumbraApiCollection.GetCollectionForObject"/>
public new (bool ObjectValid, bool IndividualSet, (Guid Id, string Name) EffectiveCollection) Invoke(int gameObjectIdx)
=> base.Invoke(gameObjectIdx);
/// <summary> Create a provider. </summary>
public static FuncProvider<int, (bool ObjectValid, bool IndividualSet, (Guid Id, string Name) EffectiveCollection)>
Provider(IDalamudPluginInterface pi, IPenumbraApiCollection api)
=> new(pi, Label, api.GetCollectionForObject);
}
/// <inheritdoc cref="IPenumbraApiCollection.SetCollection"/>
public sealed class SetCollection(IDalamudPluginInterface pi)
: FuncSubscriber<byte, Guid?, bool, bool, (int, (Guid Id, string Name)? OldCollection)>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(SetCollection)}";
/// <inheritdoc cref="IPenumbraApiCollection.SetCollectionForObject"/>
public (PenumbraApiEc, (Guid Id, string Name)? OldCollection) Invoke(ApiCollectionType type, Guid? collectionId,
bool allowCreateNew = true, bool allowDelete = true)
{
var (ec, pair) = Invoke((byte)type, collectionId, allowCreateNew, allowDelete);
return ((PenumbraApiEc)ec, pair);
}
/// <summary> Create a provider. </summary>
public static FuncProvider<byte, Guid?, bool, bool, (int, (Guid Id, string Name)? OldCollection)>
Provider(IDalamudPluginInterface pi, IPenumbraApiCollection api)
=> new(pi, Label, (t, g, a, b) =>
{
var (ret, collection) = api.SetCollection((ApiCollectionType)t, g, a, b);
return ((int)ret, collection);
});
}
/// <inheritdoc cref="IPenumbraApiCollection.SetCollectionForObject"/>
public sealed class SetCollectionForObject(IDalamudPluginInterface pi)
: FuncSubscriber<int, Guid?, bool, bool, (int, (Guid Id, string Name)? OldCollection)>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(SetCollectionForObject)}.V5";
/// <inheritdoc cref="IPenumbraApiCollection.SetCollectionForObject"/>
public new (PenumbraApiEc, (Guid Id, string Name)? OldCollection) Invoke(int gameObjectIdx, Guid? collectionId, bool allowCreateNew = true,
bool allowDelete = true)
{
var (ec, pair) = base.Invoke(gameObjectIdx, collectionId, allowCreateNew, allowDelete);
return ((PenumbraApiEc)ec, pair);
}
/// <summary> Create a provider. </summary>
public static FuncProvider<int, Guid?, bool, bool, (int, (Guid Id, string Name)? OldCollection)>
Provider(IDalamudPluginInterface pi, IPenumbraApiCollection api)
=> new(pi, Label, (i, g, a, b) =>
{
var (ret, collection) = api.SetCollectionForObject(i, g, a, b);
return ((int)ret, collection);
});
}
/// <inheritdoc cref="IPenumbraApiCollection.CheckCurrentChangedItemFunc"/>
public sealed class CheckCurrentChangedItemFunc(IDalamudPluginInterface pi)
: FuncSubscriber<Func<string, (string ModDirectory, string ModName)[]>>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(CheckCurrentChangedItemFunc)}";
/// <inheritdoc cref="IPenumbraApiCollection.CheckCurrentChangedItemFunc"/>
public new Func<string, (string ModDirectory, string ModName)[]> Invoke()
=> base.Invoke();
/// <summary> Create a provider. </summary>
public static FuncProvider<Func<string, (string ModDirectory, string ModName)[]>>
Provider(IDalamudPluginInterface pi, IPenumbraApiCollection api)
=> new(pi, Label, api.CheckCurrentChangedItemFunc);
}

View File

@@ -0,0 +1,38 @@
using Dalamud.Plugin;
using Penumbra.Api.Api;
using Penumbra.Api.Enums;
using Penumbra.Api.Helpers;
namespace Penumbra.Api.IpcSubscribers;
/// <inheritdoc cref="IPenumbraApiEditing.ConvertTextureFile"/>
public sealed class ConvertTextureFile(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, int, bool, Task>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(ConvertTextureFile)}";
/// <inheritdoc cref="IPenumbraApiEditing.ConvertTextureFile"/>
public Task Invoke(string inputFile, string outputFile, TextureType textureType, bool mipMaps = true)
=> Invoke(inputFile, outputFile, (int)textureType, mipMaps);
/// <summary> Create a provider. </summary>
public static FuncProvider<string, string, int, bool, Task> Provider(IDalamudPluginInterface pi, IPenumbraApiEditing api)
=> new(pi, Label, (a, b, c, d) => api.ConvertTextureFile(a, b, (TextureType)c, d));
}
/// <inheritdoc cref="IPenumbraApiEditing.ConvertTextureData"/>
public sealed class ConvertTextureData(IDalamudPluginInterface pi)
: FuncSubscriber<byte[], int, string, int, bool, Task>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(ConvertTextureData)}";
/// <inheritdoc cref="IPenumbraApiEditing.ConvertTextureData"/>
public Task Invoke(byte[] rgbaData, int width, string outputFile, TextureType textureType, bool mipMaps = true)
=> Invoke(rgbaData, width, outputFile, (int)textureType, mipMaps);
/// <summary> Create a provider. </summary>
public static FuncProvider<byte[], int, string, int, bool, Task> Provider(IDalamudPluginInterface pi, IPenumbraApiEditing api)
=> new(pi, Label, (a, b, c, d, e) => api.ConvertTextureData(a, b, c, (TextureType)d, e));
}

View File

@@ -0,0 +1,100 @@
using Dalamud.Plugin;
using Penumbra.Api.Api;
using Penumbra.Api.Enums;
using Penumbra.Api.Helpers;
namespace Penumbra.Api.IpcSubscribers;
/// <inheritdoc cref="IPenumbraApiGameState.GetDrawObjectInfo"/>
public sealed class GetDrawObjectInfo(IDalamudPluginInterface pi)
: FuncSubscriber<nint, (nint, (Guid, string))>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetDrawObjectInfo)}.V5";
/// <inheritdoc cref="IPenumbraApiGameState.GetDrawObjectInfo"/>
public new (nint GameObject, (Guid Id, string Name) AssociatedCollection) Invoke(nint drawObjectAddress)
=> base.Invoke(drawObjectAddress);
/// <summary> Create a provider. </summary>
public static FuncProvider<nint, (nint, (Guid, string))> Provider(IDalamudPluginInterface pi, IPenumbraApiGameState api)
=> new(pi, Label, api.GetDrawObjectInfo);
}
/// <inheritdoc cref="IPenumbraApiGameState.GetCutsceneParentIndex"/>
public sealed class GetCutsceneParentIndex(IDalamudPluginInterface pi)
: FuncSubscriber<int, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetCutsceneParentIndex)}";
/// <inheritdoc cref="IPenumbraApiGameState.GetCutsceneParentIndex"/>
public new int Invoke(int actorIndex)
=> base.Invoke(actorIndex);
/// <summary> Create a provider. </summary>
public static FuncProvider<int, int> Provider(IDalamudPluginInterface pi, IPenumbraApiGameState api)
=> new(pi, Label, api.GetCutsceneParentIndex);
}
/// <inheritdoc cref="IPenumbraApiGameState.SetCutsceneParentIndex"/>
public sealed class SetCutsceneParentIndex(IDalamudPluginInterface pi)
: FuncSubscriber<int, int, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(SetCutsceneParentIndex)}.V5";
/// <inheritdoc cref="IPenumbraApiGameState.SetCutsceneParentIndex"/>
public new PenumbraApiEc Invoke(int copyIdx, int newParentIdx)
=> (PenumbraApiEc)base.Invoke(copyIdx, newParentIdx);
/// <summary> Create a provider. </summary>
public static FuncProvider<int, int, int> Provider(IDalamudPluginInterface pi, IPenumbraApiGameState api)
=> new(pi, Label, (a, b) => (int) api.SetCutsceneParentIndex(a, b));
}
/// <inheritdoc cref="IPenumbraApiGameState.CreatingCharacterBase"/>
public static class CreatingCharacterBase
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(CreatingCharacterBase)}.V5";
/// <summary> Create a new event subscriber. </summary>
public static EventSubscriber<nint, Guid, nint, nint, nint> Subscriber(IDalamudPluginInterface pi,
params Action<nint, Guid, nint, nint, nint>[] actions)
=> new(pi, Label, actions);
/// <summary> Create a provider. </summary>
public static EventProvider<nint, Guid, nint, nint, nint> Provider(IDalamudPluginInterface pi, IPenumbraApiGameState api)
=> new(pi, Label, t => api.CreatingCharacterBase += t.Invoke, t => api.CreatingCharacterBase -= t.Invoke);
}
/// <inheritdoc cref="IPenumbraApiGameState.CreatedCharacterBase"/>
public static class CreatedCharacterBase
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(CreatedCharacterBase)}.V5";
/// <summary> Create a new event subscriber. </summary>
public static EventSubscriber<nint, Guid, nint> Subscriber(IDalamudPluginInterface pi, params Action<nint, Guid, nint>[] actions)
=> new(pi, Label, actions);
/// <summary> Create a provider. </summary>
public static EventProvider<nint, Guid, nint> Provider(IDalamudPluginInterface pi, IPenumbraApiGameState api)
=> new(pi, Label, t => api.CreatedCharacterBase += t.Invoke, t => api.CreatedCharacterBase -= t.Invoke);
}
/// <inheritdoc cref="IPenumbraApiGameState.GameObjectResourceResolved"/>
public static class GameObjectResourcePathResolved
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GameObjectResourcePathResolved)}";
/// <summary> Create a new event subscriber. </summary>
public static EventSubscriber<nint, string, string> Subscriber(IDalamudPluginInterface pi, params Action<nint, string, string>[] actions)
=> new(pi, Label, actions);
/// <summary> Create a provider. </summary>
public static EventProvider<nint, string, string> Provider(IDalamudPluginInterface pi, IPenumbraApiGameState api)
=> new(pi, Label, t => api.GameObjectResourceResolved += t.Invoke, t => api.GameObjectResourceResolved -= t.Invoke);
}

View File

@@ -0,0 +1,99 @@
using Dalamud.Plugin;
using Penumbra.Api.Enums;
using Penumbra.Api.Helpers;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace Penumbra.Api.IpcSubscribers.Legacy;
public sealed class GetCollections(IDalamudPluginInterface pi)
: FuncSubscriber<IList<string>>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(GetCollections)}";
public new IList<string> Invoke()
=> base.Invoke();
}
public sealed class GetCurrentCollectionName(IDalamudPluginInterface pi)
: FuncSubscriber<string>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(GetCurrentCollectionName)}";
public new string Invoke()
=> base.Invoke();
}
public sealed class GetDefaultCollectionName(IDalamudPluginInterface pi)
: FuncSubscriber<string>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(GetDefaultCollectionName)}";
public new string Invoke()
=> base.Invoke();
}
public sealed class GetInterfaceCollectionName(IDalamudPluginInterface pi)
: FuncSubscriber<string>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(GetInterfaceCollectionName)}";
public new string Invoke()
=> base.Invoke();
}
public sealed class GetCharacterCollectionName(IDalamudPluginInterface pi)
: FuncSubscriber<string, (string, bool)>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(GetCharacterCollectionName)}";
public new (string, bool) Invoke(string characterName)
=> base.Invoke(characterName);
}
public sealed class GetChangedItems(IDalamudPluginInterface pi)
: FuncSubscriber<string, IReadOnlyDictionary<string, object?>>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(GetChangedItems)}";
public new IReadOnlyDictionary<string, object?> Invoke(string collectionName)
=> base.Invoke(collectionName);
}
public sealed class GetCollectionForType(IDalamudPluginInterface pi)
: FuncSubscriber<ApiCollectionType, string>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(GetCollectionForType)}";
public new string Invoke(ApiCollectionType collectionType)
=> base.Invoke(collectionType);
}
public sealed class SetCollectionForType(IDalamudPluginInterface pi)
: FuncSubscriber<ApiCollectionType, string, bool, bool, (PenumbraApiEc, string)>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(SetCollectionForType)}";
public new (PenumbraApiEc ErrorCode, string OldCollectionName) Invoke(ApiCollectionType collectionType, string collectionName,
bool allowCreateNew = true, bool allowDelete = true)
=> base.Invoke(collectionType, collectionName, allowCreateNew, allowDelete);
}
public sealed class GetCollectionForObject(IDalamudPluginInterface pi)
: FuncSubscriber<int, (bool, bool, string)>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(GetCollectionForObject)}";
public new (bool ObjectValid, bool IndividualSet, string CollectionName) Invoke(int objectIndex)
=> base.Invoke(objectIndex);
}
public sealed class SetCollectionForObject(IDalamudPluginInterface pi)
: FuncSubscriber<int, string, bool, bool, (PenumbraApiEc, string)>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(SetCollectionForObject)}";
public new (PenumbraApiEc ErrorCode, string OldCollectionName) Invoke(int objectIndex, string collectionName, bool allowCreateNew = true,
bool allowDelete = true)
=> base.Invoke(objectIndex, collectionName, allowCreateNew, allowDelete);
}

View File

@@ -0,0 +1,43 @@
using Dalamud.Plugin;
using Penumbra.Api.Enums;
using Penumbra.Api.Helpers;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace Penumbra.Api.IpcSubscribers.Legacy;
public sealed class GetDrawObjectInfo(IDalamudPluginInterface pi)
: FuncSubscriber<nint, (nint, string)>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(GetDrawObjectInfo)}";
public new (nint GameObjectAddress, string CollectionName) Invoke(nint drawObjectAddress)
=> base.Invoke(drawObjectAddress);
}
public sealed class SetCutsceneParentIndex(IDalamudPluginInterface pi)
: FuncSubscriber<int, int, PenumbraApiEc>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(SetCutsceneParentIndex)}";
public new PenumbraApiEc Invoke(int cutsceneObjectIndex, int newParentIndex)
=> base.Invoke(cutsceneObjectIndex, newParentIndex);
}
public static class CreatingCharacterBase
{
public const string Label = $"Penumbra.{nameof(CreatingCharacterBase)}";
public static EventSubscriber<nint, string, nint, nint, nint> Subscriber(IDalamudPluginInterface 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 EventSubscriber<nint, string, nint> Subscriber(IDalamudPluginInterface pi,
params Action<nint, string, nint>[] actions)
=> new(pi, Label, actions);
}

View File

@@ -0,0 +1,24 @@
using Dalamud.Plugin;
using Penumbra.Api.Helpers;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace Penumbra.Api.IpcSubscribers.Legacy;
public sealed class GetMetaManipulations(IDalamudPluginInterface pi)
: FuncSubscriber<string, string>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(GetMetaManipulations)}";
public new string Invoke(string objectName)
=> base.Invoke(objectName);
}
public sealed class GetGameObjectMetaManipulations(IDalamudPluginInterface pi)
: FuncSubscriber<int, string>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(GetGameObjectMetaManipulations)}";
public new string Invoke(int objectIndex)
=> base.Invoke(objectIndex);
}

View File

@@ -0,0 +1,92 @@
using Dalamud.Plugin;
using Penumbra.Api.Api;
using Penumbra.Api.Enums;
using Penumbra.Api.Helpers;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace Penumbra.Api.IpcSubscribers.Legacy;
using CurrentSettings = ValueTuple<PenumbraApiEc, (bool, int, IDictionary<string, IList<string>>, bool)?>;
public sealed class GetAvailableModSettings(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, IDictionary<string, (IList<string>, GroupType)>?>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(GetAvailableModSettings)}";
public new IDictionary<string, (IList<string>, GroupType)>? Invoke(string modDirectory, string modName = "")
=> base.Invoke(modDirectory, modName);
}
public sealed class GetCurrentModSettings(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, string, bool, CurrentSettings>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(GetCurrentModSettings)}";
public new CurrentSettings Invoke(string collectionName, string modDirectory, string modName = "", bool ignoreInheritance = false)
=> base.Invoke(collectionName, modDirectory, modName, ignoreInheritance);
}
public sealed class TryInheritMod(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, string, bool, PenumbraApiEc>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(TryInheritMod)}";
public PenumbraApiEc Invoke(string collectionName, string modDirectory, bool inherit, string modName = "")
=> Invoke(collectionName, modDirectory, modName, inherit);
}
public sealed class TrySetMod(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, string, bool, PenumbraApiEc>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(TrySetMod)}";
public PenumbraApiEc Invoke(string collectionName, string modDirectory, bool enabled, string modName = "")
=> Invoke(collectionName, modDirectory, modName, enabled);
}
public sealed class TrySetModPriority(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, string, int, PenumbraApiEc>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(TrySetModPriority)}";
public PenumbraApiEc Invoke(string collectionName, string modDirectory, int priority, string modName = "")
=> Invoke(collectionName, modDirectory, modName, priority);
}
public sealed class TrySetModSetting(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, string, string, string, PenumbraApiEc>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(TrySetModSetting)}";
public new PenumbraApiEc Invoke(string collectionName, string modDirectory, string groupName, string setting, string modName = "")
=> base.Invoke(collectionName, modDirectory, modName, groupName, setting);
}
public sealed class TrySetModSettings(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, string, string, IReadOnlyList<string>, PenumbraApiEc>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(TrySetModSettings)}";
public PenumbraApiEc Invoke(string collectionName, string modDirectory, string groupName, IReadOnlyList<string> settings,
string modName = "")
=> Invoke(collectionName, modDirectory, modName, groupName, settings);
}
public static class ModSettingChanged
{
public const string Label = $"Penumbra.{nameof(ModSettingChanged)}.V5";
public static EventSubscriber<ModSettingChange, string, string, bool> Subscriber(IDalamudPluginInterface pi,
params Action<ModSettingChange, string, string, bool>[] actions)
=> new(pi, Label, actions);
}
public sealed class CopyModSettings(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, string, PenumbraApiEc>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(CopyModSettings)}";
public new PenumbraApiEc Invoke(string collectionName, string modDirectoryFrom, string modDirectoryTo)
=> base.Invoke(collectionName, modDirectoryFrom, modDirectoryTo);
}

View File

@@ -0,0 +1,70 @@
using Dalamud.Plugin;
using Penumbra.Api.Enums;
using Penumbra.Api.Helpers;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace Penumbra.Api.IpcSubscribers.Legacy;
public sealed class GetMods(IDalamudPluginInterface pi)
: FuncSubscriber<IList<(string, string)>>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(GetMods)}";
public new IList<(string, string)> Invoke()
=> base.Invoke();
}
public sealed class ReloadMod(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, PenumbraApiEc>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(ReloadMod)}";
public new PenumbraApiEc Invoke(string modDirectory, string modName = "")
=> base.Invoke(modDirectory, modName);
}
public sealed class InstallMod(IDalamudPluginInterface pi)
: FuncSubscriber<string, PenumbraApiEc>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(InstallMod)}";
public new PenumbraApiEc Invoke(string modDirectory)
=> base.Invoke(modDirectory);
}
public sealed class AddMod(IDalamudPluginInterface pi)
: FuncSubscriber<string, PenumbraApiEc>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(AddMod)}";
public new PenumbraApiEc Invoke(string modDirectory)
=> base.Invoke(modDirectory);
}
public sealed class DeleteMod(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, PenumbraApiEc>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(DeleteMod)}";
public new PenumbraApiEc Invoke(string modDirectory, string modName = "")
=> base.Invoke(modDirectory, modName);
}
public sealed class GetModPath(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, (PenumbraApiEc, string, bool)>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(GetModPath)}";
public new (PenumbraApiEc ErrorCode, string Path, bool IsDefault) Invoke(string modDirectory, string modName = "")
=> base.Invoke(modDirectory, modName);
}
public sealed class SetModPath(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, string, PenumbraApiEc>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(SetModPath)}";
public new PenumbraApiEc Invoke(string modDirectory, string newPath, string modName = "")
=> base.Invoke(modDirectory, modName, newPath);
}

View File

@@ -0,0 +1,15 @@
using Dalamud.Plugin;
using Penumbra.Api.Helpers;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace Penumbra.Api.IpcSubscribers.Legacy;
public class ApiVersions(IDalamudPluginInterface pi)
: FuncSubscriber<(int Breaking, int Features)>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(ApiVersions)}";
public new (int Breaking, int Features) Invoke()
=> base.Invoke();
}

View File

@@ -0,0 +1,44 @@
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Plugin;
using Penumbra.Api.Enums;
using Penumbra.Api.Helpers;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace Penumbra.Api.IpcSubscribers.Legacy;
public sealed class RedrawAll(IDalamudPluginInterface pi)
: ActionSubscriber<RedrawType>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(RedrawAll)}";
public new void Invoke(RedrawType type)
=> base.Invoke(type);
}
public sealed class RedrawObject(IDalamudPluginInterface pi)
: ActionSubscriber<IGameObject, RedrawType>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(RedrawObject)}";
public new void Invoke(IGameObject gameObject, RedrawType type = RedrawType.Redraw)
=> base.Invoke(gameObject, type);
}
public sealed class RedrawObjectByIndex(IDalamudPluginInterface pi)
: ActionSubscriber<int, RedrawType>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(RedrawObjectByIndex)}";
public new void Invoke(int gameObjectIndex, RedrawType type = RedrawType.Redraw)
=> base.Invoke(gameObjectIndex, type);
}
public sealed class RedrawObjectByName(IDalamudPluginInterface pi)
: ActionSubscriber<string, RedrawType>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(RedrawObjectByName)}";
public new void Invoke(string gameObjectName, RedrawType type = RedrawType.Redraw)
=> base.Invoke(gameObjectName, type);
}

View File

@@ -0,0 +1,24 @@
using Dalamud.Plugin;
using Penumbra.Api.Helpers;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace Penumbra.Api.IpcSubscribers.Legacy;
public sealed class ResolveCharacterPath(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, string>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(ResolveCharacterPath)}";
public new string Invoke(string gamePath, string characterName)
=> base.Invoke(gamePath, characterName);
}
public sealed class ReverseResolvePath(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, string>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(ReverseResolvePath)}";
public new string Invoke(string gamePath, string characterName)
=> base.Invoke(gamePath, characterName);
}

View File

@@ -0,0 +1,83 @@
using Dalamud.Plugin;
using Penumbra.Api.Enums;
using Penumbra.Api.Helpers;
using ResourceType = Penumbra.Api.Enums.ResourceType;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace Penumbra.Api.IpcSubscribers.Legacy;
public sealed class GetGameObjectResourcePaths(IDalamudPluginInterface pi)
: FuncSubscriber<ushort[], IReadOnlyDictionary<string, string[]>?[]>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(GetGameObjectResourcePaths)}";
public new IReadOnlyDictionary<string, string[]>?[] Invoke(params ushort[] objectIndices)
=> base.Invoke(objectIndices);
}
public sealed class GetPlayerResourcePaths(IDalamudPluginInterface pi)
: FuncSubscriber<IReadOnlyDictionary<ushort, IReadOnlyDictionary<string, string[]>>>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(GetPlayerResourcePaths)}";
public new IReadOnlyDictionary<ushort, IReadOnlyDictionary<string, string[]>> Invoke()
=> base.Invoke();
}
public sealed class GetGameObjectResourcesOfType(IDalamudPluginInterface pi)
: FuncSubscriber<ResourceType, bool, ushort[], IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>?[]>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(GetGameObjectResourcesOfType)}";
public new IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>?[] Invoke(ResourceType type, bool withUiData = false,
params ushort[] indices)
=> base.Invoke(type, withUiData, indices);
}
public sealed class GetPlayerResourcesOfType(IDalamudPluginInterface pi)
: FuncSubscriber<ResourceType, bool, IReadOnlyDictionary<ushort, IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>>>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(GetPlayerResourcesOfType)}";
public new IReadOnlyDictionary<ushort, IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>> Invoke(ResourceType type,
bool withUiData = false)
=> base.Invoke(type, withUiData);
}
public sealed class GetGameObjectResourceTrees(IDalamudPluginInterface pi)
: FuncSubscriber<bool, ushort[], ResourceTree?[]>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(GetGameObjectResourceTrees)}";
public new ResourceTree?[] Invoke(bool withUiData = false, params ushort[] indices)
=> base.Invoke(withUiData, indices);
}
public sealed class GetPlayerResourceTrees(IDalamudPluginInterface pi)
: FuncSubscriber<bool, IReadOnlyDictionary<ushort, ResourceTree>>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(GetPlayerResourceTrees)}";
public new IReadOnlyDictionary<ushort, ResourceTree> Invoke(bool withUiData = false)
=> base.Invoke(withUiData);
}
public record ResourceTree
{
public required string Name { get; init; }
public required ushort RaceCode { get; init; }
public required List<ResourceNode> Nodes { get; init; }
}
public record ResourceNode
{
public required ResourceType Type { get; init; }
public required ChangedItemIcon Icon { get; init; }
public required string? Name { get; init; }
public required string? GamePath { get; init; }
public required string ActualPath { get; init; }
public required nint ObjectAddress { get; init; }
public required nint ResourceHandle { get; init; }
public required List<ResourceNode> Children { get; init; }
}

View File

@@ -0,0 +1,88 @@
using Dalamud.Plugin;
using Penumbra.Api.Enums;
using Penumbra.Api.Helpers;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace Penumbra.Api.IpcSubscribers.Legacy;
public sealed class CreateTemporaryCollection(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, bool, (PenumbraApiEc, string)>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(CreateTemporaryCollection)}";
public new (PenumbraApiEc ErrorCode, string CollectionName) Invoke(string tag, string character, bool forceOverwrite)
=> base.Invoke(tag, character, forceOverwrite);
}
public sealed class RemoveTemporaryCollection(IDalamudPluginInterface pi)
: FuncSubscriber<string, PenumbraApiEc>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(RemoveTemporaryCollection)}";
public new PenumbraApiEc Invoke(string collectionName)
=> base.Invoke(collectionName);
}
public sealed class CreateNamedTemporaryCollection(IDalamudPluginInterface pi)
: FuncSubscriber<string, PenumbraApiEc>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(CreateNamedTemporaryCollection)}";
public new PenumbraApiEc Invoke(string collectionName)
=> base.Invoke(collectionName);
}
public sealed class RemoveTemporaryCollectionByName(IDalamudPluginInterface pi)
: FuncSubscriber<string, PenumbraApiEc>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(RemoveTemporaryCollectionByName)}";
public new PenumbraApiEc Invoke(string collectionName)
=> base.Invoke(collectionName);
}
public sealed class AssignTemporaryCollection(IDalamudPluginInterface pi)
: FuncSubscriber<string, int, bool, PenumbraApiEc>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(AssignTemporaryCollection)}";
public new PenumbraApiEc Invoke(string collectionName, int gameObjectIndex, bool force)
=> base.Invoke(collectionName, gameObjectIndex, force);
}
public sealed class AddTemporaryModAll(IDalamudPluginInterface pi)
: FuncSubscriber<string, Dictionary<string, string>, string, int, PenumbraApiEc>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(AddTemporaryModAll)}";
public new PenumbraApiEc Invoke(string tag, Dictionary<string, string> files, string meta, int priority = 0)
=> base.Invoke(tag, files, meta, priority);
}
public sealed class AddTemporaryMod(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, Dictionary<string, string>, string, int, PenumbraApiEc>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(AddTemporaryMod)}";
public new PenumbraApiEc Invoke(string tag, string collectionName, Dictionary<string, string> files, string meta, int priority = 0)
=> base.Invoke(tag, collectionName, files, meta, priority);
}
public sealed class RemoveTemporaryModAll(IDalamudPluginInterface pi)
: FuncSubscriber<string, int, PenumbraApiEc>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(RemoveTemporaryModAll)}";
public new PenumbraApiEc Invoke(string tag, int priority = 0)
=> base.Invoke(tag, priority);
}
public sealed class RemoveTemporaryMod(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, int, PenumbraApiEc>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(RemoveTemporaryMod)}";
public new PenumbraApiEc Invoke(string tag, string collectionName, int priority = 0)
=> base.Invoke(tag, collectionName, priority);
}

View File

@@ -0,0 +1,16 @@
using Dalamud.Plugin;
using Penumbra.Api.Enums;
using Penumbra.Api.Helpers;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace Penumbra.Api.IpcSubscribers.Legacy;
public sealed class OpenMainWindow(IDalamudPluginInterface pi)
: FuncSubscriber<TabType, string, string, PenumbraApiEc>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(OpenMainWindow)}";
public new PenumbraApiEc Invoke(TabType tab, string modName, string modDirectory = "")
=> base.Invoke(tab, modName, modDirectory);
}

View File

@@ -0,0 +1,37 @@
using Dalamud.Plugin;
using Penumbra.Api.Api;
using Penumbra.Api.Helpers;
namespace Penumbra.Api.IpcSubscribers;
/// <inheritdoc cref="IPenumbraApiMeta.GetPlayerMetaManipulations"/>
public sealed class GetPlayerMetaManipulations(IDalamudPluginInterface pi)
: FuncSubscriber<string>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetPlayerMetaManipulations)}";
/// <inheritdoc cref="IPenumbraApiMeta.GetPlayerMetaManipulations"/>
public new string Invoke()
=> base.Invoke();
/// <summary> Create a provider. </summary>
public static FuncProvider<string> Provider(IDalamudPluginInterface pi, IPenumbraApiMeta api)
=> new(pi, Label, api.GetPlayerMetaManipulations);
}
/// <inheritdoc cref="IPenumbraApiMeta.GetMetaManipulations"/>
public sealed class GetMetaManipulations(IDalamudPluginInterface pi)
: FuncSubscriber<int, string>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetMetaManipulations)}.V5";
/// <inheritdoc cref="IPenumbraApiMeta.GetMetaManipulations"/>
public new string Invoke(int gameObjectIdx)
=> base.Invoke(gameObjectIdx);
/// <summary> Create a provider. </summary>
public static FuncProvider<int, string> Provider(IDalamudPluginInterface pi, IPenumbraApiMeta api)
=> new(pi, Label, api.GetMetaManipulations);
}

View File

@@ -0,0 +1,218 @@
using Dalamud.Plugin;
using Penumbra.Api.Api;
using Penumbra.Api.Enums;
using Penumbra.Api.Helpers;
namespace Penumbra.Api.IpcSubscribers;
using CurrentSettingsBase = ValueTuple<int, (bool, int, Dictionary<string, List<string>>, bool)?>;
using CurrentSettings = ValueTuple<PenumbraApiEc, (bool, int, Dictionary<string, List<string>>, bool)?>;
using CurrentSettingsTempBase = ValueTuple<int, (bool, int, Dictionary<string, List<string>>, bool, bool)?>;
using CurrentSettingsTemp = ValueTuple<PenumbraApiEc, (bool, int, Dictionary<string, List<string>>, bool, bool)?>;
/// <inheritdoc cref="IPenumbraApiModSettings.GetAvailableModSettings"/>
public sealed class GetAvailableModSettings(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, IReadOnlyDictionary<string, (string[], int)>?>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetAvailableModSettings)}.V5";
/// <inheritdoc cref="IPenumbraApiModSettings.GetAvailableModSettings"/>
public new IReadOnlyDictionary<string, (string[], GroupType)>? Invoke(string modDirectory, string modName = "")
=> AvailableModSettings.Create(base.Invoke(modDirectory, modName));
/// <summary> Create a provider. </summary>
public static FuncProvider<string, string, IReadOnlyDictionary<string, (string[], int)>?> Provider(IDalamudPluginInterface pi,
IPenumbraApiModSettings api)
=> new(pi, Label, (a, b) => api.GetAvailableModSettings(a, b)?.Original);
}
/// <inheritdoc cref="IPenumbraApiModSettings.GetCurrentModSettings"/>
public sealed class GetCurrentModSettings(IDalamudPluginInterface pi)
: FuncSubscriber<Guid, string, string, bool, CurrentSettingsBase>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetCurrentModSettings)}.V5";
/// <inheritdoc cref="IPenumbraApiModSettings.GetCurrentModSettings"/>
public new CurrentSettings Invoke(Guid collectionId, string modDirectory, string modName = "", bool ignoreInheritance = false)
{
var (ret, t) = base.Invoke(collectionId, modDirectory, modName, ignoreInheritance);
return ((PenumbraApiEc)ret, t);
}
/// <summary> Create a provider. </summary>
public static FuncProvider<Guid, string, string, bool, CurrentSettingsBase> Provider(IDalamudPluginInterface pi,
IPenumbraApiModSettings api)
=> new(pi, Label, (a, b, c, d) =>
{
var (ret, t) = api.GetCurrentModSettings(a, b, c, d);
return ((int)ret, t);
});
}
/// <inheritdoc cref="IPenumbraApiModSettings.GetCurrentModSettingsWithTemp"/>
public sealed class GetCurrentModSettingsWithTemp(IDalamudPluginInterface pi)
: FuncSubscriber<Guid, string, string, bool, bool, int, CurrentSettingsTempBase>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetCurrentModSettingsWithTemp)}";
/// <inheritdoc cref="IPenumbraApiModSettings.GetCurrentModSettingsWithTemp"/>
public new CurrentSettingsTemp Invoke(Guid collectionId, string modDirectory, string modName = "", bool ignoreInheritance = false,
bool ignoreTemporary = false, int key = 0)
{
var (ret, t) = base.Invoke(collectionId, modDirectory, modName, ignoreInheritance, ignoreTemporary, key);
return ((PenumbraApiEc)ret, t);
}
/// <summary> Create a provider. </summary>
public static FuncProvider<Guid, string, string, bool, bool, int, CurrentSettingsTempBase> Provider(IDalamudPluginInterface pi,
IPenumbraApiModSettings api)
=> new(pi, Label, (a, b, c, d, e, f) =>
{
var (ret, t) = api.GetCurrentModSettingsWithTemp(a, b, c, d, e, f);
return ((int)ret, t);
});
}
/// <inheritdoc cref="IPenumbraApiModSettings.GetAllModSettings"/>
public sealed class GetAllModSettings(IDalamudPluginInterface pi)
: FuncSubscriber<Guid, bool, bool, int, (int, Dictionary<string, (bool, int, Dictionary<string, List<string>>, bool, bool)>?)>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetAllModSettings)}";
/// <inheritdoc cref="IPenumbraApiModSettings.GetAllModSettings"/>
public new (PenumbraApiEc, Dictionary<string, (bool, int, Dictionary<string, List<string>>, bool, bool)>?) Invoke(Guid collectionId,
bool ignoreInheritance = false, bool ignoreTemporary = false, int key = 0)
{
var (ret, t) = base.Invoke(collectionId, ignoreInheritance, ignoreTemporary, key);
return ((PenumbraApiEc)ret, t);
}
/// <summary> Create a provider. </summary>
public static FuncProvider<Guid, bool, bool, int, (int, Dictionary<string, (bool, int, Dictionary<string, List<string>>, bool, bool)>?)>
Provider(IDalamudPluginInterface pi,
IPenumbraApiModSettings api)
=> new(pi, Label, (a, b, c, d) =>
{
var (ret, t) = api.GetAllModSettings(a, b, c, d);
return ((int)ret, t);
});
}
/// <inheritdoc cref="IPenumbraApiModSettings.TryInheritMod"/>
public sealed class TryInheritMod(IDalamudPluginInterface pi)
: FuncSubscriber<Guid, string, string, bool, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(TryInheritMod)}.V5";
/// <inheritdoc cref="IPenumbraApiModSettings.TryInheritMod"/>
public PenumbraApiEc Invoke(Guid collectionId, string modDirectory, bool inherit, string modName = "")
=> (PenumbraApiEc)Invoke(collectionId, modDirectory, modName, inherit);
/// <summary> Create a provider. </summary>
public static FuncProvider<Guid, string, string, bool, int> Provider(IDalamudPluginInterface pi, IPenumbraApiModSettings api)
=> new(pi, Label, (a, b, c, d) => (int)api.TryInheritMod(a, b, c, d));
}
/// <inheritdoc cref="IPenumbraApiModSettings.TrySetMod"/>
public sealed class TrySetMod(IDalamudPluginInterface pi)
: FuncSubscriber<Guid, string, string, bool, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(TrySetMod)}.V5";
/// <inheritdoc cref="IPenumbraApiModSettings.TrySetMod"/>
public PenumbraApiEc Invoke(Guid collectionId, string modDirectory, bool inherit, string modName = "")
=> (PenumbraApiEc)Invoke(collectionId, modDirectory, modName, inherit);
/// <summary> Create a provider. </summary>
public static FuncProvider<Guid, string, string, bool, int> Provider(IDalamudPluginInterface pi, IPenumbraApiModSettings api)
=> new(pi, Label, (a, b, c, d) => (int)api.TrySetMod(a, b, c, d));
}
/// <inheritdoc cref="IPenumbraApiModSettings.TrySetModPriority"/>
public sealed class TrySetModPriority(IDalamudPluginInterface pi)
: FuncSubscriber<Guid, string, string, int, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(TrySetModPriority)}.V5";
/// <inheritdoc cref="IPenumbraApiModSettings.TrySetModPriority"/>
public PenumbraApiEc Invoke(Guid collectionId, string modDirectory, int priority, string modName = "")
=> (PenumbraApiEc)Invoke(collectionId, modDirectory, modName, priority);
/// <summary> Create a provider. </summary>
public static FuncProvider<Guid, string, string, int, int> Provider(IDalamudPluginInterface pi, IPenumbraApiModSettings api)
=> new(pi, Label, (a, b, c, d) => (int)api.TrySetModPriority(a, b, c, d));
}
/// <inheritdoc cref="IPenumbraApiModSettings.TrySetModSetting"/>
public sealed class TrySetModSetting(IDalamudPluginInterface pi)
: FuncSubscriber<Guid, string, string, string, string, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(TrySetModSetting)}.V5";
/// <inheritdoc cref="IPenumbraApiModSettings.TrySetModSetting"/>
public new PenumbraApiEc Invoke(Guid collectionId, string modDirectory, string optionGroupName, string optionName, string modName = "")
=> (PenumbraApiEc)base.Invoke(collectionId, modDirectory, modName, optionGroupName, optionName);
/// <summary> Create a provider. </summary>
public static FuncProvider<Guid, string, string, string, string, int> Provider(IDalamudPluginInterface pi, IPenumbraApiModSettings api)
=> new(pi, Label, (a, b, c, d, e) => (int)api.TrySetModSetting(a, b, c, d, e));
}
/// <inheritdoc cref="IPenumbraApiModSettings.TrySetModSettings"/>
public sealed class TrySetModSettings(IDalamudPluginInterface pi)
: FuncSubscriber<Guid, string, string, string, IReadOnlyList<string>, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(TrySetModSettings)}.V5";
/// <inheritdoc cref="IPenumbraApiModSettings.TrySetModSettings"/>
public PenumbraApiEc Invoke(Guid collectionId, string modDirectory, string optionGroupName,
IReadOnlyList<string> optionNames, string modName = "")
=> (PenumbraApiEc)Invoke(collectionId, modDirectory, modName, optionGroupName, optionNames);
/// <summary> Create a provider. </summary>
public static FuncProvider<Guid, string, string, string, IReadOnlyList<string>, int> Provider(IDalamudPluginInterface pi,
IPenumbraApiModSettings api)
=> new(pi, Label, (a, b, c, d, e) => (int)api.TrySetModSettings(a, b, c, d, e));
}
/// <inheritdoc cref="IPenumbraApiModSettings.ModSettingChanged" />
public static class ModSettingChanged
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(ModSettingChanged)}.V5";
/// <summary> Create a new event subscriber. </summary>
public static EventSubscriber<ModSettingChange, Guid, string, bool> Subscriber(IDalamudPluginInterface pi,
params Action<ModSettingChange, Guid, string, bool>[] actions)
=> new(pi, Label, actions);
/// <summary> Create a provider. </summary>
public static EventProvider<ModSettingChange, Guid, string, bool> Provider(IDalamudPluginInterface pi, IPenumbraApiModSettings api)
=> new(pi, Label, t => api.ModSettingChanged += t.Invoke, t => api.ModSettingChanged -= t.Invoke);
}
/// <inheritdoc cref="IPenumbraApiModSettings.CopyModSettings"/>
public sealed class CopyModSettings(IDalamudPluginInterface pi)
: FuncSubscriber<Guid?, string, string, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(CopyModSettings)}.V5";
/// <inheritdoc cref="IPenumbraApiModSettings.CopyModSettings"/>
public new PenumbraApiEc Invoke(Guid? collectionId, string modDirectoryFrom, string modDirectoryTo)
=> (PenumbraApiEc)base.Invoke(collectionId, modDirectoryFrom, modDirectoryTo);
/// <summary> Create a provider. </summary>
public static FuncProvider<Guid?, string, string, int> Provider(IDalamudPluginInterface pi,
IPenumbraApiModSettings api)
=> new(pi, Label, (a, b, c) => (int)api.CopyModSettings(a, b, c));
}

View File

@@ -0,0 +1,218 @@
using Dalamud.Plugin;
using Penumbra.Api.Api;
using Penumbra.Api.Enums;
using Penumbra.Api.Helpers;
namespace Penumbra.Api.IpcSubscribers;
/// <inheritdoc cref="IPenumbraApiMods.GetModList"/>
public sealed class GetModList(IDalamudPluginInterface pi)
: FuncSubscriber<Dictionary<string, string>>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetModList)}";
/// <inheritdoc cref="IPenumbraApiMods.GetModList"/>
public new Dictionary<string, string> Invoke()
=> base.Invoke();
/// <summary> Create a provider. </summary>
public static FuncProvider<Dictionary<string, string>> Provider(IDalamudPluginInterface pi, IPenumbraApiMods api)
=> new(pi, Label, api.GetModList);
}
/// <inheritdoc cref="IPenumbraApiMods.InstallMod"/>
public sealed class InstallMod(IDalamudPluginInterface pi)
: FuncSubscriber<string, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(InstallMod)}.V5";
/// <inheritdoc cref="IPenumbraApiMods.InstallMod"/>
public new PenumbraApiEc Invoke(string modFilePackagePath)
=> (PenumbraApiEc)base.Invoke(modFilePackagePath);
/// <summary> Create a provider. </summary>
public static FuncProvider<string, int> Provider(IDalamudPluginInterface pi, IPenumbraApiMods api)
=> new(pi, Label, a => (int)api.InstallMod(a));
}
/// <inheritdoc cref="IPenumbraApiMods.ReloadMod"/>
public sealed class ReloadMod(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(ReloadMod)}.V5";
/// <inheritdoc cref="IPenumbraApiMods.ReloadMod"/>
public new PenumbraApiEc Invoke(string modDirectory, string modName = "")
=> (PenumbraApiEc)base.Invoke(modDirectory, modName);
/// <summary> Create a provider. </summary>
public static FuncProvider<string, string, int> Provider(IDalamudPluginInterface pi, IPenumbraApiMods api)
=> new(pi, Label, (a, b) => (int)api.ReloadMod(a, b));
}
/// <inheritdoc cref="IPenumbraApiMods.AddMod"/>
public sealed class AddMod(IDalamudPluginInterface pi)
: FuncSubscriber<string, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(AddMod)}.V5";
/// <inheritdoc cref="IPenumbraApiMods.AddMod"/>
public new PenumbraApiEc Invoke(string modDirectory)
=> (PenumbraApiEc)base.Invoke(modDirectory);
/// <summary> Create a provider. </summary>
public static FuncProvider<string, int> Provider(IDalamudPluginInterface pi, IPenumbraApiMods api)
=> new(pi, Label, a => (int)api.AddMod(a));
}
/// <inheritdoc cref="IPenumbraApiMods.DeleteMod"/>
public sealed class DeleteMod(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(DeleteMod)}.V5";
/// <inheritdoc cref="IPenumbraApiMods.DeleteMod"/>
public new PenumbraApiEc Invoke(string modDirectory, string modName = "")
=> (PenumbraApiEc)base.Invoke(modDirectory, modName);
/// <summary> Create a provider. </summary>
public static FuncProvider<string, string, int> Provider(IDalamudPluginInterface pi, IPenumbraApiMods api)
=> new(pi, Label, (a, b) => (int)api.DeleteMod(a, b));
}
/// <inheritdoc cref="IPenumbraApiMods.ModDeleted" />
public static class ModDeleted
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(ModDeleted)}";
/// <summary> Create a new event subscriber. </summary>
public static EventSubscriber<string> Subscriber(IDalamudPluginInterface pi, params Action<string>[] actions)
=> new(pi, Label, actions);
/// <summary> Create a provider. </summary>
public static EventProvider<string> Provider(IDalamudPluginInterface pi, IPenumbraApiMods api)
=> new(pi, Label, (t => api.ModDeleted += t, t => api.ModDeleted -= t));
}
/// <inheritdoc cref="IPenumbraApiMods.ModAdded" />
public static class ModAdded
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(ModAdded)}";
/// <summary> Create a new event subscriber. </summary>
public static EventSubscriber<string> Subscriber(IDalamudPluginInterface pi, params Action<string>[] actions)
=> new(pi, Label, actions);
/// <summary> Create a provider. </summary>
public static EventProvider<string> Provider(IDalamudPluginInterface pi, IPenumbraApiMods api)
=> new(pi, Label, (t => api.ModAdded += t, t => api.ModAdded -= t));
}
/// <inheritdoc cref="IPenumbraApiMods.ModMoved" />
public static class ModMoved
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(ModMoved)}";
/// <summary> Create a new event subscriber. </summary>
public static EventSubscriber<string, string> Subscriber(IDalamudPluginInterface pi, params Action<string, string>[] actions)
=> new(pi, Label, actions);
/// <summary> Create a provider. </summary>
public static EventProvider<string, string> Provider(IDalamudPluginInterface pi, IPenumbraApiMods api)
=> new(pi, Label, (t => api.ModMoved += t, t => api.ModMoved -= t));
}
/// <inheritdoc cref="IPenumbraApiMods.GetModPath"/>
public sealed class GetModPath(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, (int, string, bool, bool)>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetModPath)}.V5";
/// <inheritdoc cref="IPenumbraApiMods.GetModPath"/>
public new (PenumbraApiEc, string FullPath, bool FullDefault, bool NameDefault) Invoke(string modDirectory, string modName = "")
{
var (ret, fullPath, fullDefault, nameDefault) = base.Invoke(modDirectory, modName);
return ((PenumbraApiEc)ret, fullPath, fullDefault, nameDefault);
}
/// <summary> Create a provider. </summary>
public static FuncProvider<string, string, (int, string, bool, bool)> Provider(IDalamudPluginInterface pi, IPenumbraApiMods api)
=> new(pi, Label, (a, b) =>
{
var (ret, fullPath, fullDefault, nameDefault) = api.GetModPath(a, b);
return ((int)ret, fullPath, fullDefault, nameDefault);
});
}
/// <inheritdoc cref="IPenumbraApiMods.SetModPath"/>
public sealed class SetModPath(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, string, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(SetModPath)}.V5";
/// <inheritdoc cref="IPenumbraApiMods.SetModPath"/>
public new PenumbraApiEc Invoke(string modDirectory, string newPath, string modName = "")
=> (PenumbraApiEc)base.Invoke(modDirectory, modName, newPath);
/// <summary> Create a provider. </summary>
public static FuncProvider<string, string, string, int> Provider(IDalamudPluginInterface pi, IPenumbraApiMods api)
=> new(pi, Label, (a, b, c) => (int)api.SetModPath(a, b, c));
}
/// <inheritdoc cref="IPenumbraApiMods.GetChangedItems"/>
public sealed class GetChangedItems(IDalamudPluginInterface pi)
: FuncSubscriber<string, string, Dictionary<string, object?>>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetChangedItems)}.V5";
/// <inheritdoc cref="IPenumbraApiMods.GetChangedItems"/>
public new Dictionary<string, object?> Invoke(string modDirectory, string modName)
=> base.Invoke(modDirectory, modName);
/// <summary> Create a provider. </summary>
public static FuncProvider<string, string, Dictionary<string, object?>> Provider(IDalamudPluginInterface pi, IPenumbraApiMods api)
=> new(pi, Label, api.GetChangedItems);
}
/// <inheritdoc cref="IPenumbraApiMods.GetChangedItemAdapterDictionary"/>
public sealed class GetChangedItemAdapterDictionary(IDalamudPluginInterface pi)
: FuncSubscriber<IReadOnlyDictionary<string, IReadOnlyDictionary<string, object?>>>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetChangedItemAdapterDictionary)}";
/// <inheritdoc cref="IPenumbraApiMods.GetChangedItemAdapterDictionary"/>
public new IReadOnlyDictionary<string, IReadOnlyDictionary<string, object?>> Invoke()
=> base.Invoke();
/// <summary> Create a provider. </summary>
public static FuncProvider<IReadOnlyDictionary<string, IReadOnlyDictionary<string, object?>>> Provider(IDalamudPluginInterface pi, IPenumbraApiMods api)
=> new(pi, Label, api.GetChangedItemAdapterDictionary);
}
/// <inheritdoc cref="IPenumbraApiMods.GetChangedItemAdapterList"/>
public sealed class GetChangedItemAdapterList(IDalamudPluginInterface pi)
: FuncSubscriber<IReadOnlyList<(string ModDirectory, IReadOnlyDictionary<string, object?> ChangedItems)>>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetChangedItemAdapterList)}";
/// <inheritdoc cref="IPenumbraApiMods.GetChangedItemAdapterList"/>
public new IReadOnlyList<(string ModDirectory, IReadOnlyDictionary<string, object?> ChangedItems)> Invoke()
=> base.Invoke();
/// <summary> Create a provider. </summary>
public static FuncProvider<IReadOnlyList<(string ModDirectory, IReadOnlyDictionary<string, object?> ChangedItems)>> Provider(IDalamudPluginInterface pi, IPenumbraApiMods api)
=> new(pi, Label, api.GetChangedItemAdapterList);
}

View File

@@ -0,0 +1,128 @@
using Dalamud.Plugin;
using Penumbra.Api.Api;
using Penumbra.Api.Helpers;
namespace Penumbra.Api.IpcSubscribers;
/// <summary>Triggered when the Penumbra API is initialized and ready.</summary>
public static class Initialized
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(Initialized)}";
/// <summary> Create a new event subscriber. </summary>
public static EventSubscriber Subscriber(IDalamudPluginInterface pi, params Action[] actions)
=> new(pi, Label, actions);
/// <summary> Create a provider. </summary>
public static EventProvider Provider(IDalamudPluginInterface pi)
=> new(pi, Label);
}
/// <summary>Triggered when the Penumbra API is fully disposed and unavailable.</summary>
public static class Disposed
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(Disposed)}";
/// <summary> Create a new event subscriber. </summary>
public static EventSubscriber Subscriber(IDalamudPluginInterface pi, params Action[] actions)
=> new(pi, Label, actions);
/// <summary> Create a provider. </summary>
public static EventProvider Provider(IDalamudPluginInterface pi)
=> new(pi, Label);
}
/// <inheritdoc cref="IPenumbraApiBase.ApiVersion"/>
public class ApiVersion(IDalamudPluginInterface pi)
: FuncSubscriber<(int Breaking, int Features)>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(ApiVersion)}.V5";
/// <inheritdoc cref="IPenumbraApiBase.ApiVersion"/>
public new (int Breaking, int Features) Invoke()
=> base.Invoke();
/// <summary> Create a provider. </summary>
public static FuncProvider<(int Breaking, int Features)> Provider(IDalamudPluginInterface pi, IPenumbraApiBase api)
=> new(pi, Label, () => api.ApiVersion);
}
/// <inheritdoc cref="IPenumbraApiPluginState.GetModDirectory"/>
public class GetModDirectory(IDalamudPluginInterface pi)
: FuncSubscriber<string>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetModDirectory)}";
/// <inheritdoc cref="IPenumbraApiPluginState.GetModDirectory"/>
public new string Invoke()
=> base.Invoke();
/// <summary> Create a provider. </summary>
public static FuncProvider<string> Provider(IDalamudPluginInterface pi, IPenumbraApiPluginState api)
=> new(pi, Label, api.GetModDirectory);
}
/// <inheritdoc cref="IPenumbraApiPluginState.GetConfiguration"/>
public class GetConfiguration(IDalamudPluginInterface pi)
: FuncSubscriber<string>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetConfiguration)}";
/// <inheritdoc cref="IPenumbraApiPluginState.GetConfiguration"/>
public new string Invoke()
=> base.Invoke();
/// <summary> Create a provider. </summary>
public static FuncProvider<string> Provider(IDalamudPluginInterface pi, IPenumbraApiPluginState api)
=> new(pi, Label, api.GetConfiguration);
}
/// <inheritdoc cref="IPenumbraApiPluginState.ModDirectoryChanged" />
public static class ModDirectoryChanged
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(ModDirectoryChanged)}";
/// <summary> Create a new event subscriber. </summary>
public static EventSubscriber<string, bool> Subscriber(IDalamudPluginInterface pi, params Action<string, bool>[] actions)
=> new(pi, Label, actions);
/// <summary> Create a provider. </summary>
public static EventProvider<string, bool> Provider(IDalamudPluginInterface pi, IPenumbraApiPluginState api)
=> new(pi, Label, (t => api.ModDirectoryChanged += t, t => api.ModDirectoryChanged -= t));
}
/// <inheritdoc cref="IPenumbraApiPluginState.GetEnabledState"/>
public class GetEnabledState(IDalamudPluginInterface pi)
: FuncSubscriber<bool>(pi, Label)
{
public const string Label = $"Penumbra.{nameof(GetEnabledState)}";
/// <inheritdoc cref="IPenumbraApiPluginState.GetEnabledState"/>
public new bool Invoke()
=> base.Invoke();
/// <summary> Create a provider. </summary>
public static FuncProvider<bool> Provider(IDalamudPluginInterface pi, IPenumbraApiPluginState api)
=> new(pi, Label, api.GetEnabledState);
}
/// <inheritdoc cref="IPenumbraApiPluginState.EnabledChange" />
public static class EnabledChange
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(EnabledChange)}";
/// <summary> Create a new event subscriber. </summary>
public static EventSubscriber<bool> Subscriber(IDalamudPluginInterface pi, params Action<bool>[] actions)
=> new(pi, Label, actions);
/// <summary> Create a provider. </summary>
public static EventProvider<bool> Provider(IDalamudPluginInterface pi, IPenumbraApiPluginState api)
=> new(pi, Label, (t => api.EnabledChange += t, t => api.EnabledChange -= t));
}

View File

@@ -0,0 +1,53 @@
using Dalamud.Plugin;
using Penumbra.Api.Api;
using Penumbra.Api.Enums;
using Penumbra.Api.Helpers;
namespace Penumbra.Api.IpcSubscribers;
/// <inheritdoc cref="IPenumbraApiRedraw.RedrawObject"/>
public sealed class RedrawObject(IDalamudPluginInterface pi)
: ActionSubscriber<int, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(RedrawObject)}.V5";
/// <inheritdoc cref="IPenumbraApiRedraw.RedrawObject"/>
public void Invoke(int gameObjectIndex, RedrawType setting = RedrawType.Redraw)
=> base.Invoke(gameObjectIndex, (int)setting);
/// <summary> Create a provider. </summary>
public static ActionProvider<int, int> Provider(IDalamudPluginInterface pi, IPenumbraApiRedraw api)
=> new(pi, Label, (a, b) => api.RedrawObject(a, (RedrawType)b));
}
/// <inheritdoc cref="IPenumbraApiRedraw.RedrawAll"/>
public sealed class RedrawAll(IDalamudPluginInterface pi)
: ActionSubscriber<int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(RedrawAll)}.V5";
/// <inheritdoc cref="IPenumbraApiRedraw.RedrawAll"/>
public void Invoke(RedrawType setting = RedrawType.Redraw)
=> base.Invoke((int)setting);
/// <summary> Create a provider. </summary>
public static ActionProvider<int> Provider(IDalamudPluginInterface pi, IPenumbraApiRedraw api)
=> new(pi, Label, a => api.RedrawAll((RedrawType)a));
}
/// <inheritdoc cref="IPenumbraApiRedraw.GameObjectRedrawn" />
public static class GameObjectRedrawn
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GameObjectRedrawn)}";
/// <summary> Create a new event subscriber. </summary>
public static EventSubscriber<nint, int> Subscriber(IDalamudPluginInterface pi, params Action<nint, int>[] actions)
=> new(pi, Label, actions);
/// <summary> Create a provider. </summary>
public static EventProvider<nint, int> Provider(IDalamudPluginInterface pi, IPenumbraApiRedraw api)
=> new(pi, Label, t => api.GameObjectRedrawn += t.Invoke, t => api.GameObjectRedrawn -= t.Invoke);
}

View File

@@ -0,0 +1,133 @@
using Dalamud.Plugin;
using Penumbra.Api.Api;
using Penumbra.Api.Helpers;
namespace Penumbra.Api.IpcSubscribers;
/// <inheritdoc cref="IPenumbraApiResolve.ResolveDefaultPath"/>
public sealed class ResolveDefaultPath(IDalamudPluginInterface pi)
: FuncSubscriber<string, string>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(ResolveDefaultPath)}";
/// <inheritdoc cref="IPenumbraApiResolve.ResolveDefaultPath"/>
public new string Invoke(string gamePath)
=> base.Invoke(gamePath);
/// <summary> Create a provider. </summary>
public static FuncProvider<string, string> Provider(IDalamudPluginInterface pi, IPenumbraApiResolve api)
=> new(pi, Label, api.ResolveDefaultPath);
}
/// <inheritdoc cref="IPenumbraApiResolve.ResolveInterfacePath"/>
public sealed class ResolveInterfacePath(IDalamudPluginInterface pi)
: FuncSubscriber<string, string>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(ResolveInterfacePath)}";
/// <inheritdoc cref="IPenumbraApiResolve.ResolveInterfacePath"/>
public new string Invoke(string gamePath)
=> base.Invoke(gamePath);
/// <summary> Create a provider. </summary>
public static FuncProvider<string, string> Provider(IDalamudPluginInterface pi, IPenumbraApiResolve api)
=> new(pi, Label, api.ResolveInterfacePath);
}
/// <inheritdoc cref="IPenumbraApiResolve.ResolveGameObjectPath"/>
public sealed class ResolveGameObjectPath(IDalamudPluginInterface pi)
: FuncSubscriber<string, int, string>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(ResolveGameObjectPath)}";
/// <inheritdoc cref="IPenumbraApiResolve.ResolveGameObjectPath"/>
public new string Invoke(string gamePath, int gameObjectIdx)
=> base.Invoke(gamePath, gameObjectIdx);
/// <summary> Create a provider. </summary>
public static FuncProvider<string, int, string> Provider(IDalamudPluginInterface pi, IPenumbraApiResolve api)
=> new(pi, Label, api.ResolveGameObjectPath);
}
/// <inheritdoc cref="IPenumbraApiResolve.ResolvePlayerPath"/>
public sealed class ResolvePlayerPath(IDalamudPluginInterface pi)
: FuncSubscriber<string, string>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(ResolvePlayerPath)}";
/// <inheritdoc cref="IPenumbraApiResolve.ResolvePlayerPath"/>
public new string Invoke(string gamePath)
=> base.Invoke(gamePath);
/// <summary> Create a provider. </summary>
public static FuncProvider<string, string> Provider(IDalamudPluginInterface pi, IPenumbraApiResolve api)
=> new(pi, Label, api.ResolvePlayerPath);
}
/// <inheritdoc cref="IPenumbraApiResolve.ReverseResolveGameObjectPath"/>
public sealed class ReverseResolveGameObjectPath(IDalamudPluginInterface pi)
: FuncSubscriber<string, int, string[]>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(ReverseResolveGameObjectPath)}";
/// <inheritdoc cref="IPenumbraApiResolve.ReverseResolveGameObjectPath"/>
public new string[] Invoke(string gamePath, int gameObjectIdx)
=> base.Invoke(gamePath, gameObjectIdx);
/// <summary> Create a provider. </summary>
public static FuncProvider<string, int, string[]> Provider(IDalamudPluginInterface pi, IPenumbraApiResolve api)
=> new(pi, Label, api.ReverseResolveGameObjectPath);
}
/// <inheritdoc cref="IPenumbraApiResolve.ReverseResolvePlayerPath"/>
public sealed class ReverseResolvePlayerPath(IDalamudPluginInterface pi)
: FuncSubscriber<string, string[]>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(ReverseResolvePlayerPath)}";
/// <inheritdoc cref="IPenumbraApiResolve.ReverseResolvePlayerPath"/>
public new string[] Invoke(string gamePath)
=> base.Invoke(gamePath);
/// <summary> Create a provider. </summary>
public static FuncProvider<string, string[]> Provider(IDalamudPluginInterface pi, IPenumbraApiResolve api)
=> new(pi, Label, api.ReverseResolvePlayerPath);
}
/// <inheritdoc cref="IPenumbraApiResolve.ResolvePlayerPaths"/>
public sealed class ResolvePlayerPaths(IDalamudPluginInterface pi)
: FuncSubscriber<string[], string[], (string[], string[][])>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(ResolvePlayerPaths)}";
/// <inheritdoc cref="IPenumbraApiResolve.ResolvePlayerPaths"/>
public new (string[], string[][]) Invoke(string[] forward, string[] reverse)
=> base.Invoke(forward, reverse);
/// <summary> Create a provider. </summary>
public static FuncProvider<string[], string[], (string[], string[][])> Provider(IDalamudPluginInterface pi, IPenumbraApiResolve api)
=> new(pi, Label, api.ResolvePlayerPaths);
}
/// <inheritdoc cref="IPenumbraApiResolve.ResolvePlayerPathsAsync"/>
public sealed class ResolvePlayerPathsAsync(IDalamudPluginInterface pi)
: FuncSubscriber<string[], string[], Task<(string[], string[][])>>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(ResolvePlayerPathsAsync)}";
/// <inheritdoc cref="IPenumbraApiResolve.ResolvePlayerPathsAsync"/>
public new Task<(string[], string[][])> Invoke(string[] forward, string[] reverse)
=> base.Invoke(forward, reverse);
/// <summary> Create a provider. </summary>
public static FuncProvider<string[], string[], Task<(string[], string[][])>> Provider(IDalamudPluginInterface pi, IPenumbraApiResolve api)
=> new(pi, Label, api.ResolvePlayerPathsAsync);
}

View File

@@ -0,0 +1,116 @@
using System.Linq;
using Dalamud.Plugin;
using Newtonsoft.Json.Linq;
using Penumbra.Api.Api;
using Penumbra.Api.Enums;
using Penumbra.Api.Helpers;
namespace Penumbra.Api.IpcSubscribers;
/// <inheritdoc cref="IPenumbraApiResourceTree.GetGameObjectResourcePaths"/>
public sealed class GetGameObjectResourcePaths(IDalamudPluginInterface pi)
: FuncSubscriber<ushort[], Dictionary<string, HashSet<string>>?[]>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetGameObjectResourcePaths)}.V5";
/// <inheritdoc cref="IPenumbraApiResourceTree.GetGameObjectResourcePaths"/>
public new Dictionary<string, HashSet<string>>?[] Invoke(params ushort[] gameObjectIndices)
=> base.Invoke(gameObjectIndices);
/// <summary> Create a provider. </summary>
public static FuncProvider<ushort[], Dictionary<string, HashSet<string>>?[]> Provider(IDalamudPluginInterface pi,
IPenumbraApiResourceTree api)
=> new(pi, Label, api.GetGameObjectResourcePaths);
}
/// <inheritdoc cref="IPenumbraApiResourceTree.GetPlayerResourcePaths"/>
public sealed class GetPlayerResourcePaths(IDalamudPluginInterface pi)
: FuncSubscriber<Dictionary<ushort, Dictionary<string, HashSet<string>>>>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetPlayerResourcePaths)}.V5";
/// <inheritdoc cref="IPenumbraApiResourceTree.GetPlayerResourcePaths"/>
public new Dictionary<ushort, Dictionary<string, HashSet<string>>> Invoke()
=> base.Invoke();
/// <summary> Create a provider. </summary>
public static FuncProvider<Dictionary<ushort, Dictionary<string, HashSet<string>>>> Provider(IDalamudPluginInterface pi,
IPenumbraApiResourceTree api)
=> new(pi, Label, api.GetPlayerResourcePaths);
}
/// <inheritdoc cref="IPenumbraApiResourceTree.GetGameObjectResourcesOfType"/>
public sealed class GetGameObjectResourcesOfType(IDalamudPluginInterface pi)
: FuncSubscriber<uint, bool, ushort[], IReadOnlyDictionary<nint, (string, string, uint)>?[]>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetGameObjectResourcesOfType)}.V5";
/// <inheritdoc cref="IPenumbraApiResourceTree.GetGameObjectResourcesOfType"/>
public IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>?[] Invoke(ResourceType type, bool withUiData = false,
params ushort[] gameObjectIndices)
=> Array.ConvertAll(Invoke((uint)type, withUiData, gameObjectIndices),
d => (IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>?)GameResourceDict.Create(d));
/// <summary> Create a provider. </summary>
public static FuncProvider<uint, bool, ushort[], IReadOnlyDictionary<nint, (string, string, uint)>?[]> Provider(IDalamudPluginInterface pi,
IPenumbraApiResourceTree api)
=> new(pi, Label,
(a, b, c) => Array.ConvertAll(api.GetGameObjectResourcesOfType((ResourceType)a, b, c), d => d?.Original));
}
/// <inheritdoc cref="IPenumbraApiResourceTree.GetPlayerResourcesOfType"/>
public sealed class GetPlayerResourcesOfType(IDalamudPluginInterface pi)
: FuncSubscriber<uint, bool, Dictionary<ushort, IReadOnlyDictionary<nint, (string, string, uint)>>>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetPlayerResourcesOfType)}.V5";
/// <inheritdoc cref="IPenumbraApiResourceTree.GetPlayerResourcesOfType"/>
public Dictionary<ushort, IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>> Invoke(ResourceType type, bool withUiData = false)
=> Invoke((uint)type, withUiData)
.ToDictionary(kvp => kvp.Key, kvp => (IReadOnlyDictionary<nint, (string, string, ChangedItemIcon)>)new GameResourceDict(kvp.Value));
/// <summary> Create a provider. </summary>
public static FuncProvider<uint, bool, Dictionary<ushort, IReadOnlyDictionary<nint, (string, string, uint)>>> Provider(
IDalamudPluginInterface pi,
IPenumbraApiResourceTree api)
=> new(pi, Label,
(a, b) => api.GetPlayerResourcesOfType((ResourceType)a, b)
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Original));
}
/// <inheritdoc cref="IPenumbraApiResourceTree.GetGameObjectResourceTrees"/>
public sealed class GetGameObjectResourceTrees(IDalamudPluginInterface pi)
: FuncSubscriber<bool, ushort[], JObject?[]>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetGameObjectResourceTrees)}.V5";
/// <inheritdoc cref="IPenumbraApiResourceTree.GetGameObjectResourceTrees"/>
public new ResourceTreeDto?[] Invoke(bool withUiData = false, params ushort[] gameObjectIndices)
=> Array.ConvertAll(base.Invoke(withUiData, gameObjectIndices), o => o?.ToObject<ResourceTreeDto>());
/// <summary> Create a provider. </summary>
public static FuncProvider<bool, ushort[], JObject?[]> Provider(IDalamudPluginInterface pi,
IPenumbraApiResourceTree api)
=> new(pi, Label, api.GetGameObjectResourceTrees);
}
/// <inheritdoc cref="IPenumbraApiResourceTree.GetPlayerResourceTrees"/>
public sealed class GetPlayerResourceTrees(IDalamudPluginInterface pi)
: FuncSubscriber<bool, Dictionary<ushort, JObject>>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(GetPlayerResourceTrees)}.V5";
/// <inheritdoc cref="IPenumbraApiResourceTree.GetPlayerResourceTrees"/>
public new Dictionary<ushort, ResourceTreeDto> Invoke(bool withUiData = false)
=> base.Invoke(withUiData).ToDictionary(kvp => kvp.Key, kvp => kvp.Value.ToObject<ResourceTreeDto>()!);
/// <summary> Create a provider. </summary>
public static FuncProvider<bool, Dictionary<ushort, JObject>> Provider(IDalamudPluginInterface pi, IPenumbraApiResourceTree api)
=> new(pi, Label, api.GetPlayerResourceTrees);
}

View File

@@ -0,0 +1,276 @@
using Dalamud.Plugin;
using Penumbra.Api.Api;
using Penumbra.Api.Enums;
using Penumbra.Api.Helpers;
using PseudoModSetting =
System.ValueTuple<bool, bool, int,
System.Collections.Generic.IReadOnlyDictionary<string, System.Collections.Generic.IReadOnlyList<string>>>;
namespace Penumbra.Api.IpcSubscribers;
/// <inheritdoc cref="IPenumbraApiTemporary.CreateTemporaryCollection"/>
public sealed class CreateTemporaryCollection(IDalamudPluginInterface pi)
: FuncSubscriber<string, Guid>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(CreateTemporaryCollection)}.V5";
/// <inheritdoc cref="IPenumbraApiTemporary.CreateTemporaryCollection"/>
public new Guid Invoke(string name = "")
=> base.Invoke(name);
/// <summary> Create a provider. </summary>
public static FuncProvider<string, Guid> Provider(IDalamudPluginInterface pi, IPenumbraApiTemporary api)
=> new(pi, Label, api.CreateTemporaryCollection);
}
/// <inheritdoc cref="IPenumbraApiTemporary.DeleteTemporaryCollection"/>
public sealed class DeleteTemporaryCollection(IDalamudPluginInterface pi)
: FuncSubscriber<Guid, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(DeleteTemporaryCollection)}.V5";
/// <inheritdoc cref="IPenumbraApiTemporary.DeleteTemporaryCollection"/>
public new PenumbraApiEc Invoke(Guid collectionId)
=> (PenumbraApiEc)base.Invoke(collectionId);
/// <summary> Create a provider. </summary>
public static FuncProvider<Guid, int> Provider(IDalamudPluginInterface pi, IPenumbraApiTemporary api)
=> new(pi, Label, g => (int)api.DeleteTemporaryCollection(g));
}
/// <inheritdoc cref="IPenumbraApiTemporary.AssignTemporaryCollection"/>
public sealed class AssignTemporaryCollection(IDalamudPluginInterface pi)
: FuncSubscriber<Guid, int, bool, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(AssignTemporaryCollection)}.V5";
/// <inheritdoc cref="IPenumbraApiTemporary.AssignTemporaryCollection"/>
public new PenumbraApiEc Invoke(Guid collectionId, int actorIndex, bool forceAssignment = true)
=> (PenumbraApiEc)base.Invoke(collectionId, actorIndex, forceAssignment);
/// <summary> Create a provider. </summary>
public static FuncProvider<Guid, int, bool, int> Provider(IDalamudPluginInterface pi, IPenumbraApiTemporary api)
=> new(pi, Label, (a, b, c) => (int)api.AssignTemporaryCollection(a, b, c));
}
/// <inheritdoc cref="IPenumbraApiTemporary.AddTemporaryModAll"/>
public sealed class AddTemporaryModAll(IDalamudPluginInterface pi)
: FuncSubscriber<string, Dictionary<string, string>, string, int, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(AddTemporaryModAll)}.V5";
/// <inheritdoc cref="IPenumbraApiTemporary.AddTemporaryModAll"/>
public new PenumbraApiEc Invoke(string tag, Dictionary<string, string> paths, string manipString, int priority)
=> (PenumbraApiEc)base.Invoke(tag, paths, manipString, priority);
/// <summary> Create a provider. </summary>
public static FuncProvider<string, Dictionary<string, string>, string, int, int> Provider(IDalamudPluginInterface pi,
IPenumbraApiTemporary api)
=> new(pi, Label, (a, b, c, d) => (int)api.AddTemporaryModAll(a, b, c, d));
}
/// <inheritdoc cref="IPenumbraApiTemporary.AddTemporaryMod"/>
public sealed class AddTemporaryMod(IDalamudPluginInterface pi)
: FuncSubscriber<string, Guid, Dictionary<string, string>, string, int, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(AddTemporaryMod)}.V5";
/// <inheritdoc cref="IPenumbraApiTemporary.AddTemporaryMod"/>
public new PenumbraApiEc Invoke(string tag, Guid collectionId, Dictionary<string, string> paths, string manipString, int priority)
=> (PenumbraApiEc)base.Invoke(tag, collectionId, paths, manipString, priority);
/// <summary> Create a provider. </summary>
public static FuncProvider<string, Guid, Dictionary<string, string>, string, int, int> Provider(IDalamudPluginInterface pi,
IPenumbraApiTemporary api)
=> new(pi, Label, (a, b, c, d, e) => (int)api.AddTemporaryMod(a, b, c, d, e));
}
/// <inheritdoc cref="IPenumbraApiTemporary.RemoveTemporaryModAll"/>
public sealed class RemoveTemporaryModAll(IDalamudPluginInterface pi)
: FuncSubscriber<string, int, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(RemoveTemporaryModAll)}.V5";
/// <inheritdoc cref="IPenumbraApiTemporary.RemoveTemporaryModAll"/>
public new PenumbraApiEc Invoke(string tag, int priority)
=> (PenumbraApiEc)base.Invoke(tag, priority);
/// <summary> Create a provider. </summary>
public static FuncProvider<string, int, int> Provider(IDalamudPluginInterface pi,
IPenumbraApiTemporary api)
=> new(pi, Label, (a, b) => (int)api.RemoveTemporaryModAll(a, b));
}
/// <inheritdoc cref="IPenumbraApiTemporary.RemoveTemporaryMod"/>
public sealed class RemoveTemporaryMod(IDalamudPluginInterface pi)
: FuncSubscriber<string, Guid, int, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(RemoveTemporaryMod)}.V5";
/// <inheritdoc cref="IPenumbraApiTemporary.RemoveTemporaryMod"/>
public new PenumbraApiEc Invoke(string tag, Guid collectionId, int priority)
=> (PenumbraApiEc)base.Invoke(tag, collectionId, priority);
/// <summary> Create a provider. </summary>
public static FuncProvider<string, Guid, int, int> Provider(IDalamudPluginInterface pi, IPenumbraApiTemporary api)
=> new(pi, Label, (a, b, c) => (int)api.RemoveTemporaryMod(a, b, c));
}
/// <inheritdoc cref="IPenumbraApiTemporary.SetTemporaryModSettings"/>
public sealed class SetTemporaryModSettings(IDalamudPluginInterface pi)
: FuncSubscriber<Guid, string, string, PseudoModSetting, string, int, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(SetTemporaryModSettings)}.V5";
/// <inheritdoc cref="IPenumbraApiTemporary.SetTemporaryModSettings"/>
public PenumbraApiEc Invoke(Guid collectionId, string modDirectory, bool inherit, bool enabled, int priority,
IReadOnlyDictionary<string, IReadOnlyList<string>> settings, string source, int key = 0, string modName = "")
=> (PenumbraApiEc)Invoke(collectionId, modDirectory, modName, (inherit, enabled, priority, settings), source, key);
/// <summary> Create a provider. </summary>
public static FuncProvider<Guid, string, string, PseudoModSetting, string, int, int> Provider(IDalamudPluginInterface pi,
IPenumbraApiTemporary api)
=> new(pi, Label, (a, b, c, d, e, f) => (int)api.SetTemporaryModSettings(a, b, c, d.Item1, d.Item2, d.Item3, d.Item4, e, f));
}
/// <inheritdoc cref="IPenumbraApiTemporary.SetTemporaryModSettingsPlayer"/>
public sealed class SetTemporaryModSettingsPlayer(IDalamudPluginInterface pi)
: FuncSubscriber<int, string, string, PseudoModSetting, string, int, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(SetTemporaryModSettingsPlayer)}.V5";
/// <inheritdoc cref="IPenumbraApiTemporary.SetTemporaryModSettingsPlayer"/>
public PenumbraApiEc Invoke(int objectIndex, string modDirectory, bool inherit, bool enabled, int priority,
IReadOnlyDictionary<string, IReadOnlyList<string>> settings, string source, int key = 0, string modName = "")
=> (PenumbraApiEc)Invoke(objectIndex, modDirectory, modName, (inherit, enabled, priority, settings), source, key);
/// <summary> Create a provider. </summary>
public static FuncProvider<int, string, string, PseudoModSetting, string, int, int> Provider(IDalamudPluginInterface pi,
IPenumbraApiTemporary api)
=> new(pi, Label, (a, b, c, d, e, f) => (int)api.SetTemporaryModSettingsPlayer(a, b, c, d.Item1, d.Item2, d.Item3, d.Item4, e, f));
}
/// <inheritdoc cref="IPenumbraApiTemporary.RemoveTemporaryModSettings"/>
public sealed class RemoveTemporaryModSettings(IDalamudPluginInterface pi)
: FuncSubscriber<Guid, string, string, int, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(RemoveTemporaryModSettings)}.V5";
/// <inheritdoc cref="IPenumbraApiTemporary.RemoveTemporaryModSettings"/>
public PenumbraApiEc Invoke(Guid collectionId, string modDirectory, int key = 0, string modName = "")
=> (PenumbraApiEc)base.Invoke(collectionId, modDirectory, modName, key);
/// <summary> Create a provider. </summary>
public static FuncProvider<Guid, string, string, int, int> Provider(IDalamudPluginInterface pi, IPenumbraApiTemporary api)
=> new(pi, Label, (a, b, c, d) => (int)api.RemoveTemporaryModSettings(a, b, c, d));
}
/// <inheritdoc cref="IPenumbraApiTemporary.RemoveTemporaryModSettingsPlayer"/>
public sealed class RemoveTemporaryModSettingsPlayer(IDalamudPluginInterface pi)
: FuncSubscriber<int, string, string, int, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(RemoveTemporaryModSettingsPlayer)}.V5";
/// <inheritdoc cref="IPenumbraApiTemporary.RemoveTemporaryModSettingsPlayer"/>
public PenumbraApiEc Invoke(int objectIndex, string modDirectory, int key = 0, string modName = "")
=> (PenumbraApiEc)base.Invoke(objectIndex, modDirectory, modName, key);
/// <summary> Create a provider. </summary>
public static FuncProvider<int, string, string, int, int> Provider(IDalamudPluginInterface pi, IPenumbraApiTemporary api)
=> new(pi, Label, (a, b, c, d) => (int)api.RemoveTemporaryModSettingsPlayer(a, b, c, d));
}
/// <inheritdoc cref="IPenumbraApiTemporary.RemoveAllTemporaryModSettings"/>
public sealed class RemoveAllTemporaryModSettings(IDalamudPluginInterface pi)
: FuncSubscriber<Guid, int, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(RemoveAllTemporaryModSettings)}.V5";
/// <inheritdoc cref="IPenumbraApiTemporary.RemoveAllTemporaryModSettings"/>
public new PenumbraApiEc Invoke(Guid collectionId, int key = 0)
=> (PenumbraApiEc)base.Invoke(collectionId, key);
/// <summary> Create a provider. </summary>
public static FuncProvider<Guid, int, int> Provider(IDalamudPluginInterface pi, IPenumbraApiTemporary api)
=> new(pi, Label, (a, b) => (int)api.RemoveAllTemporaryModSettings(a, b));
}
/// <inheritdoc cref="IPenumbraApiTemporary.RemoveAllTemporaryModSettingsPlayer"/>
public sealed class RemoveAllTemporaryModSettingsPlayer(IDalamudPluginInterface pi)
: FuncSubscriber<int, int, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(RemoveAllTemporaryModSettingsPlayer)}.V5";
/// <inheritdoc cref="IPenumbraApiTemporary.RemoveAllTemporaryModSettingsPlayer"/>
public new PenumbraApiEc Invoke(int objectIndex, int key = 0)
=> (PenumbraApiEc)base.Invoke(objectIndex, key);
/// <summary> Create a provider. </summary>
public static FuncProvider<int, int, int> Provider(IDalamudPluginInterface pi, IPenumbraApiTemporary api)
=> new(pi, Label, (a, b) => (int)api.RemoveAllTemporaryModSettingsPlayer(a, b));
}
/// <inheritdoc cref="IPenumbraApiTemporary.QueryTemporaryModSettings"/>
public sealed class QueryTemporaryModSettings(IDalamudPluginInterface pi)
: FuncSubscriber<Guid, string, string, int, (int, (bool, bool, int, Dictionary<string, List<string>>)?, string)>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(QueryTemporaryModSettings)}.V5";
/// <inheritdoc cref="IPenumbraApiTemporary.QueryTemporaryModSettings"/>
public PenumbraApiEc Invoke(Guid collectionId, string modDirectory,
out (bool ForceInherit, bool Enabled, int Priority, Dictionary<string, List<string>> Settings)? settings, out string source,
int key = 0, string modName = "")
{
(var ec, settings, source) = Invoke(collectionId, modDirectory, modName, key);
return (PenumbraApiEc)ec;
}
/// <summary> Create a provider. </summary>
public static FuncProvider<Guid, string, string, int, (int, (bool, bool, int, Dictionary<string, List<string>>)?, string)> Provider(
IDalamudPluginInterface pi, IPenumbraApiTemporary api)
=> new(pi, Label, (a, b, c, d) =>
{
var (ex, settings, source) = api.QueryTemporaryModSettings(a, b, c, d);
return ((int)ex, settings, source);
});
}
/// <inheritdoc cref="IPenumbraApiTemporary.QueryTemporaryModSettingsPlayer"/>
public sealed class QueryTemporaryModSettingsPlayer(IDalamudPluginInterface pi)
: FuncSubscriber<int, string, string, int, (int, (bool, bool, int, Dictionary<string, List<string>>)?, string)>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(QueryTemporaryModSettingsPlayer)}.V5";
/// <inheritdoc cref="IPenumbraApiTemporary.QueryTemporaryModSettingsPlayer"/>
public PenumbraApiEc Invoke(int objectIndex, string modDirectory,
out (bool ForceInherit, bool Enabled, int Priority, Dictionary<string, List<string>> Settings)? settings, out string source,
int key = 0, string modName = "")
{
(var ec, settings, source) = Invoke(objectIndex, modDirectory, modName, key);
return (PenumbraApiEc)ec;
}
/// <summary> Create a provider. </summary>
public static FuncProvider<int, string, string, int, (int, (bool, bool, int, Dictionary<string, List<string>>)?, string)> Provider(
IDalamudPluginInterface pi, IPenumbraApiTemporary api)
=> new(pi, Label, (a, b, c, d) =>
{
var (ex, settings, source) = api.QueryTemporaryModSettingsPlayer(a, b, c, d);
return ((int)ex, settings, source);
});
}

View File

@@ -0,0 +1,130 @@
using Dalamud.Plugin;
using Penumbra.Api.Api;
using Penumbra.Api.Enums;
using Penumbra.Api.Helpers;
namespace Penumbra.Api.IpcSubscribers;
/// <inheritdoc cref="IPenumbraApiUi.ChangedItemTooltip" />
public static class ChangedItemTooltip
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(ChangedItemTooltip)}";
/// <summary> Create a new event subscriber. </summary>
public static EventSubscriber<ChangedItemType, uint> Subscriber(IDalamudPluginInterface pi,
params Action<ChangedItemType, uint>[] actions)
=> new(pi, Label, actions);
/// <summary> Create a provider. </summary>
public static EventProvider<ChangedItemType, uint> Provider(IDalamudPluginInterface pi, IPenumbraApiUi api)
=> new(pi, Label, (d => api.ChangedItemTooltip += d, d => api.ChangedItemTooltip -= d));
}
/// <inheritdoc cref="IPenumbraApiUi.ChangedItemClicked" />
public static class ChangedItemClicked
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(ChangedItemClicked)}";
/// <summary> Create a new event subscriber. </summary>
public static EventSubscriber<MouseButton, ChangedItemType, uint> Subscriber(IDalamudPluginInterface pi,
params Action<MouseButton, ChangedItemType, uint>[] actions)
=> new(pi, Label, actions);
/// <summary> Create a provider. </summary>
public static EventProvider<MouseButton, ChangedItemType, uint> Provider(IDalamudPluginInterface pi, IPenumbraApiUi api)
=> new(pi, Label, (d => api.ChangedItemClicked += d, d => api.ChangedItemClicked -= d));
}
/// <inheritdoc cref="IPenumbraApiUi.PreSettingsTabBarDraw" />
public static class PreSettingsTabBarDraw
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(PreSettingsTabBarDraw)}";
/// <summary> Create a new event subscriber. </summary>
public static EventSubscriber<string, float, float> Subscriber(IDalamudPluginInterface pi, params Action<string, float, float>[] actions)
=> new(pi, Label, actions);
/// <summary> Create a provider. </summary>
public static EventProvider<string, float, float> Provider(IDalamudPluginInterface pi, IPenumbraApiUi api)
=> new(pi, Label, (d => api.PreSettingsTabBarDraw += d, d => api.PreSettingsTabBarDraw -= d));
}
/// <inheritdoc cref="IPenumbraApiUi.PreSettingsPanelDraw" />
public static class PreSettingsDraw
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(PreSettingsDraw)}";
/// <summary> Create a new event subscriber. </summary>
public static EventSubscriber<string> Subscriber(IDalamudPluginInterface pi, params Action<string>[] actions)
=> new(pi, Label, actions);
/// <summary> Create a provider. </summary>
public static EventProvider<string> Provider(IDalamudPluginInterface pi, IPenumbraApiUi api)
=> new(pi, Label, (d => api.PreSettingsPanelDraw += d, d => api.PreSettingsPanelDraw -= d));
}
/// <inheritdoc cref="IPenumbraApiUi.PostEnabledDraw" />
public static class PostEnabledDraw
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(PostEnabledDraw)}";
/// <summary> Create a new event subscriber. </summary>
public static EventSubscriber<string> Subscriber(IDalamudPluginInterface pi, params Action<string>[] actions)
=> new(pi, Label, actions);
/// <summary> Create a provider. </summary>
public static EventProvider<string> Provider(IDalamudPluginInterface pi, IPenumbraApiUi api)
=> new(pi, Label, (d => api.PostEnabledDraw += d, d => api.PostEnabledDraw -= d));
}
/// <inheritdoc cref="IPenumbraApiUi.PostSettingsPanelDraw" />
public static class PostSettingsDraw
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(PostSettingsDraw)}";
/// <summary> Create a new event subscriber. </summary>
public static EventSubscriber<string> Subscriber(IDalamudPluginInterface pi, params Action<string>[] actions)
=> new(pi, Label, actions);
/// <summary> Create a provider. </summary>
public static EventProvider<string> Provider(IDalamudPluginInterface pi, IPenumbraApiUi api)
=> new(pi, Label, (d => api.PostSettingsPanelDraw += d, d => api.PostSettingsPanelDraw -= d));
}
/// <inheritdoc cref="IPenumbraApiUi.OpenMainWindow"/>
public sealed class OpenMainWindow(IDalamudPluginInterface pi)
: FuncSubscriber<int, string, string, int>(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra.{nameof(OpenMainWindow)}.V5";
/// <inheritdoc cref="IPenumbraApiUi.OpenMainWindow"/>
public PenumbraApiEc Invoke(TabType tab, string modDirectory = "", string modName = "")
=> (PenumbraApiEc)Invoke((int)tab, modDirectory, modName);
/// <summary> Create a provider. </summary>
public static FuncProvider<int, string, string, int> Provider(IDalamudPluginInterface pi, IPenumbraApiUi api)
=> new(pi, Label, (a, b, c) => (int)api.OpenMainWindow((TabType)a, b, c));
}
/// <inheritdoc cref="IPenumbraApiUi.CloseMainWindow"/>
public sealed class CloseMainWindow(IDalamudPluginInterface pi)
: ActionSubscriber(pi, Label)
{
/// <summary> The label. </summary>
public const string Label = $"Penumbra{nameof(CloseMainWindow)}";
/// <inheritdoc cref="IPenumbraApiUi.CloseMainWindow"/>
public new void Invoke()
=> base.Invoke();
/// <summary> Create a provider. </summary>
public static ActionProvider Provider(IDalamudPluginInterface pi, IPenumbraApiUi api)
=> new(pi, Label, api.CloseMainWindow);
}

View File

@@ -0,0 +1,34 @@
<Project Sdk="Dalamud.NET.Sdk/13.0.0">
<PropertyGroup>
<AssemblyTitle>Penumbra.Api</AssemblyTitle>
<Product>Penumbra</Product>
<Copyright>Copyright © 2025</Copyright>
<FileVersion>5.6.1.0</FileVersion>
<AssemblyVersion>5.6.1.0</AssemblyVersion>
<PackageVersion>5.6.1</PackageVersion>
<PackageReadmeFile>README.md</PackageReadmeFile>
<OutputPath>bin\$(Configuration)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<Title>Penumbra.Api</Title>
<Authors>Ottermandias</Authors>
<RepositoryUrl>https://github.com/Ottermandias/Penumbra.Api</RepositoryUrl>
<Description>Auxiliary functions for Penumbras external API.</Description>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
<PropertyGroup>
<Use_DalamudPackager>false</Use_DalamudPackager>
</PropertyGroup>
<PropertyGroup>
<NoWarn>1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="\" />
</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
Penumbra.Api/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).

View File

@@ -0,0 +1,13 @@
{
"version": 1,
"dependencies": {
"net9.0-windows7.0": {
"DotNet.ReproducibleBuilds": {
"type": "Direct",
"requested": "[1.2.25, )",
"resolved": "1.2.25",
"contentHash": "xCXiw7BCxHJ8pF6wPepRUddlh2dlQlbr81gXA72hdk4FLHkKXas7EH/n+fk5UCA/YfMqG1Z6XaPiUjDbUNBUzg=="
}
}
}
}