Compare commits
86 Commits
Author | SHA1 | Date | |
---|---|---|---|
d6320ed16a | |||
830a401c90 | |||
3d2176693e | |||
d3295b1d8c | |||
![]() |
fe5de199a1 | ||
cbb904a8d5 | |||
2a555e6440 | |||
![]() |
42893e5b53 | ||
563ed52f90 | |||
ddef5cb2cf | |||
![]() |
684787183c | ||
![]() |
fccdd6f91e | ||
![]() |
17095147a5 | ||
752679370a | |||
b4cad9c745 | |||
100c5612dc | |||
b8e0100bdf | |||
137db42446
|
|||
956d2009eb | |||
ec66da8b5e | |||
0555ee0db7
|
|||
837b487281
|
|||
9a0f2c062c
|
|||
![]() |
6e9c69c2a8 | ||
f0cef81b5e | |||
d8160effd0
|
|||
18da07763c
|
|||
3c448f2290
|
|||
cadc7e223f | |||
e1baca7940 | |||
c2e0cf65a8 | |||
a3d0408d6f | |||
9ca6931bb8 | |||
f22eff1f72 | |||
11e097d696 | |||
f7ecb45774 | |||
00a7328e3a | |||
c39229a28b | |||
00c56b0888
|
|||
15898d54c2
|
|||
6d5ed42e60 | |||
92a8e224ef | |||
669ceed2a9
|
|||
778d30ae26 | |||
d2212da456
|
|||
a3dfe35df6
|
|||
da6623741c
|
|||
abea8f0856
|
|||
1624a84cf1 | |||
ba852831aa
|
|||
5de9ad3a54
|
|||
4c8ce23e8a
|
|||
2be5f5d320
|
|||
c428f306ca
|
|||
3dde713c91
|
|||
3280446c7e
|
|||
a408e22a68 | |||
1b71cda403 | |||
eb8dbbd7f9 | |||
abc361faf0
|
|||
d5d3eef5f8 | |||
9f553e57d2 | |||
35af19f82e | |||
c113868b58 | |||
51c76e1b2a | |||
c58f66ff4a | |||
73b0040b3b | |||
cb00f73fc7 | |||
9e5398105e | |||
7c2f5445e1 | |||
ed4630cd51 | |||
ac231ef800 | |||
a3f5ee766a | |||
![]() |
8f8940b00b | ||
a697301895
|
|||
27a09aa420 | |||
86cb7d2221 | |||
bbf79bacac
|
|||
91d4cf8532 | |||
df7e6b2a51 | |||
b9ce34bf10 | |||
267fb2d25c | |||
291f005888
|
|||
2e1bc4840b | |||
8526f6c240 | |||
77d62b68b4 |
52
.gitea/workflows/build.yml
Normal file
52
.gitea/workflows/build.yml
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
name: .NET Build and Publish to Gitea
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: '*'
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: dotnet
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- name: Restore dependencies
|
||||||
|
run: dotnet restore
|
||||||
|
|
||||||
|
- name: Download Dalamud
|
||||||
|
run: |
|
||||||
|
mkdir -p $HOME/.xlcore/dalamud/Hooks/dev/
|
||||||
|
curl -L https://goatcorp.github.io/dalamud-distrib/stg/latest.zip -o latest.zip
|
||||||
|
unzip -o latest.zip -d $HOME/.xlcore/dalamud/Hooks/dev/
|
||||||
|
|
||||||
|
- name: Build project
|
||||||
|
run: dotnet build --no-restore --configuration Release --nologo
|
||||||
|
|
||||||
|
- name: Publish Windows executable
|
||||||
|
run: dotnet publish -c Release -r win-x64 --self-contained true -o ./publish
|
||||||
|
|
||||||
|
- name: Archive published files
|
||||||
|
run: zip -r SnowcloakClient.zip ./publish/*
|
||||||
|
|
||||||
|
- name: Create Gitea release
|
||||||
|
env:
|
||||||
|
GITEA_TOKEN: ${{ secrets.BUILD_SNOWCLOAK_CLIENT }}
|
||||||
|
run: |
|
||||||
|
API_URL="https://git.snowcloak-sync.com/api/v1/repos/Eauldane/SnowcloakClient/releases"
|
||||||
|
TAG="v$(date +%Y%m%d%H%M)"
|
||||||
|
# Create release
|
||||||
|
RELEASE_ID=$(curl -s -X POST \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
-d "{\"tag_name\":\"$TAG\",\"name\":\"Automated Build $TAG\",\"body\":\"Automated build artifact\"}" \
|
||||||
|
$API_URL | jq -r '.id')
|
||||||
|
echo "Release ID: $RELEASE_ID"
|
||||||
|
# Upload asset
|
||||||
|
curl -s -X POST \
|
||||||
|
-H "Authorization: token $GITEA_TOKEN" \
|
||||||
|
-F "name=SnowcloakClient.zip" \
|
||||||
|
-F "attachment=@SnowcloakClient.zip" \
|
||||||
|
"$API_URL/$RELEASE_ID/assets"
|
File diff suppressed because it is too large
Load Diff
3
Glamourer.Api/.gitignore
vendored
3
Glamourer.Api/.gitignore
vendored
@@ -1,3 +0,0 @@
|
|||||||
bin/
|
|
||||||
obj/
|
|
||||||
.vs/
|
|
@@ -1,14 +0,0 @@
|
|||||||
namespace Glamourer.Api.Api;
|
|
||||||
|
|
||||||
/// <summary> The full API available. </summary>
|
|
||||||
public interface IGlamourerApi : IGlamourerApiBase
|
|
||||||
{
|
|
||||||
/// <inheritdoc cref="IGlamourerApiDesigns"/>
|
|
||||||
public IGlamourerApiDesigns Designs { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiItems"/>
|
|
||||||
public IGlamourerApiItems Items { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState"/>
|
|
||||||
public IGlamourerApiState State { get; }
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
namespace Glamourer.Api.Api;
|
|
||||||
|
|
||||||
/// <summary> Basic API functions. </summary>
|
|
||||||
public interface IGlamourerApiBase
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Get the current API version of the Glamourer available in this installation.
|
|
||||||
/// Major version changes indicate incompatibilities, minor version changes are backward-compatible additions.
|
|
||||||
/// </summary>
|
|
||||||
public (int Major, int Minor) ApiVersion { get; }
|
|
||||||
}
|
|
@@ -1,33 +0,0 @@
|
|||||||
using Glamourer.Api.Enums;
|
|
||||||
|
|
||||||
namespace Glamourer.Api.Api;
|
|
||||||
|
|
||||||
/// <summary> All functions related to Glamourer designs. </summary>
|
|
||||||
public interface IGlamourerApiDesigns
|
|
||||||
{
|
|
||||||
/// <summary> Obtain a list of all available designs. </summary>
|
|
||||||
/// <returns> A dictionary of all designs from their GUID to their current display name. </returns>
|
|
||||||
public Dictionary<Guid, string> GetDesignList();
|
|
||||||
|
|
||||||
/// <summary> Apply an existing design to an actor. </summary>
|
|
||||||
/// <param name="designId"> The GUID of the design to apply. </param>
|
|
||||||
/// <param name="objectIndex"> The game object index of the actor to be manipulated. </param>
|
|
||||||
/// <param name="key"> A key to unlock or lock the state if necessary. </param>
|
|
||||||
/// <param name="flags"> The flags used for the reversion. Respects Once, Equipment, Customization, Lock (see <see cref="ApplyFlag"/>.)</param>
|
|
||||||
/// <returns> DesignNotFound, ActorNotFound, InvalidKey, Success. </returns>
|
|
||||||
public GlamourerApiEc ApplyDesign(Guid designId, int objectIndex, uint key, ApplyFlag flags);
|
|
||||||
|
|
||||||
/// <summary> Apply an existing design to an actor. </summary>
|
|
||||||
/// <param name="designId"> The GUID of the design to apply. </param>
|
|
||||||
/// <param name="playerName"> The name of the players to be manipulated. </param>
|
|
||||||
/// <param name="key"> A key to unlock or lock the state if necessary. </param>
|
|
||||||
/// <param name="flags"> The flags used for the reversion. Respects Once, Equipment, Customization, Lock (see <see cref="ApplyFlag"/>.)</param>
|
|
||||||
/// <returns> DesignNotFound, ActorNotFound, InvalidKey, Success. </returns>
|
|
||||||
/// /// <remarks>
|
|
||||||
/// The player does not have to be currently available as long as he has a persisted Glamourer state.<br/>
|
|
||||||
/// Only players are checked for name equality, no NPCs.<br/>
|
|
||||||
/// If multiple players of the same name are found, all of them are reverted.<br/>
|
|
||||||
/// Prefer to use the index-based function unless you need to get the state of someone currently unavailable.
|
|
||||||
/// </remarks>
|
|
||||||
public GlamourerApiEc ApplyDesignName(Guid designId, string playerName, uint key, ApplyFlag flags);
|
|
||||||
}
|
|
@@ -1,80 +0,0 @@
|
|||||||
using Glamourer.Api.Enums;
|
|
||||||
|
|
||||||
namespace Glamourer.Api.Api;
|
|
||||||
|
|
||||||
/// <summary> All functions related to items. </summary>
|
|
||||||
public interface IGlamourerApiItems
|
|
||||||
{
|
|
||||||
/// <summary> Set a single item on an actor. </summary>
|
|
||||||
/// <param name="objectIndex"> The game object index of the actor to be manipulated. </param>
|
|
||||||
/// <param name="slot"> The slot to apply the item to. </param>
|
|
||||||
/// <param name="itemId"> The (Custom) ID of the item to apply. </param>
|
|
||||||
/// <param name="stains"> The IDs of the stains to apply to the item. </param>
|
|
||||||
/// <param name="key"> A key to unlock or lock the state if necessary. </param>
|
|
||||||
/// <param name="flags"> The flags used for the reversion. Respects Once (see <see cref="ApplyFlag"/>.)</param>
|
|
||||||
/// <returns> ItemInvalid, ActorNotFound, ActorNotHuman, InvalidKey, Success. </returns>
|
|
||||||
/// <remarks> The item ID can be a custom item ID in Glamourer's format for models without an associated item, or a normal game item ID. </remarks>
|
|
||||||
public GlamourerApiEc SetItem(int objectIndex, ApiEquipSlot slot, ulong itemId, IReadOnlyList<byte> stains, uint key, ApplyFlag flags);
|
|
||||||
|
|
||||||
/// <summary> Set a single item on players. </summary>
|
|
||||||
/// <param name="playerName"> The name of the players to be manipulated. </param>
|
|
||||||
/// <param name="slot"> The slot to apply the item to. </param>
|
|
||||||
/// <param name="itemId"> The (Custom) ID of the item to apply. </param>
|
|
||||||
/// <param name="stains"> The IDs of the stains to apply to the item. </param>
|
|
||||||
/// <param name="key"> A key to unlock or lock the state if necessary. </param>
|
|
||||||
/// <param name="flags"> The flags used for the reversion. Respects Once (see <see cref="ApplyFlag"/>.)</param>
|
|
||||||
/// <returns> ItemInvalid, ActorNotFound, ActorNotHuman, InvalidKey, Success. </returns>
|
|
||||||
/// <remarks>
|
|
||||||
/// The item ID can be a custom item ID in Glamourer's format for models without an associated item, or a normal game item ID.<br/>
|
|
||||||
/// The player does not have to be currently available as long as he has a persisted Glamourer state.<br/>
|
|
||||||
/// Only players are checked for name equality, no NPCs.<br/>
|
|
||||||
/// If multiple players of the same name are found, all of them are modified.<br/>
|
|
||||||
/// Prefer to use the index-based function unless you need to get the state of someone currently unavailable.
|
|
||||||
/// </remarks>
|
|
||||||
public GlamourerApiEc SetItemName(string playerName, ApiEquipSlot slot, ulong itemId, IReadOnlyList<byte> stains, uint key,
|
|
||||||
ApplyFlag flags);
|
|
||||||
|
|
||||||
/// <summary> Set a single bonus item on an actor. </summary>
|
|
||||||
/// <param name="objectIndex"> The game object index of the actor to be manipulated. </param>
|
|
||||||
/// <param name="slot"> The bonus slot to apply the item to. </param>
|
|
||||||
/// <param name="bonusItemId"> The bonus item sheet ID of the item to apply (including stain). </param>
|
|
||||||
/// <param name="key"> A key to unlock or lock the state if necessary. </param>
|
|
||||||
/// <param name="flags"> The flags used for the reversion. Respects Once (see <see cref="ApplyFlag"/>.)</param>
|
|
||||||
/// <returns> ItemInvalid, ActorNotFound, ActorNotHuman, InvalidKey, Success. </returns>
|
|
||||||
/// <remarks> The bonus item ID can currently not be a custom item ID in Glamourer's format for models without an associated item. Use 0 to remove the bonus item. </remarks>
|
|
||||||
public GlamourerApiEc SetBonusItem(int objectIndex, ApiBonusSlot slot, ulong bonusItemId, uint key, ApplyFlag flags);
|
|
||||||
|
|
||||||
/// <summary> Set a single bonus item on an actor. </summary>
|
|
||||||
/// <param name="playerName"> The game object index of the actor to be manipulated. </param>
|
|
||||||
/// <param name="slot"> The bonus slot to apply the item to. </param>
|
|
||||||
/// <param name="bonusItemId"> The bonus item sheet ID of the item to apply (including stain). </param>
|
|
||||||
/// <param name="key"> A key to unlock or lock the state if necessary. </param>
|
|
||||||
/// <param name="flags"> The flags used for the reversion. Respects Once (see <see cref="ApplyFlag"/>.)</param>
|
|
||||||
/// <returns> ItemInvalid, ActorNotFound, ActorNotHuman, InvalidKey, Success. </returns>
|
|
||||||
/// <remarks>
|
|
||||||
/// The bonus item ID can currently not be a custom item ID in Glamourer's format for models without an associated item. Use 0 to remove the bonus item. <br/>
|
|
||||||
/// The player does not have to be currently available as long as he has a persisted Glamourer state.<br/>
|
|
||||||
/// Only players are checked for name equality, no NPCs.<br/>
|
|
||||||
/// If multiple players of the same name are found, all of them are modified.<br/>
|
|
||||||
/// Prefer to use the index-based function unless you need to get the state of someone currently unavailable.
|
|
||||||
/// </remarks>
|
|
||||||
public GlamourerApiEc SetBonusItemName(string playerName, ApiBonusSlot slot, ulong bonusItemId, uint key, ApplyFlag flags);
|
|
||||||
|
|
||||||
/// <summary> Set the defined Meta State flags to the active or inactive state on actor. </summary>
|
|
||||||
/// <param name="objectIndex"> The game object index of the actor to be manipulated. </param>
|
|
||||||
/// <param name="types"> The flags defining which meta states to update to the new value. This can be multiple at once. </param>
|
|
||||||
/// <param name="newValue"> The new value to update to. </param>
|
|
||||||
/// <param name="key"> A key to unlock or lock the state if necessary. </param>
|
|
||||||
/// <param name="flags"> The flags used for the reversion. Respects Once (see <see cref="ApplyFlag.Once"/>.)</param>
|
|
||||||
/// <returns> ItemInvalid, ActorNotFound, ActorNotHuman, InvalidKey, Success. </returns>
|
|
||||||
public GlamourerApiEc SetMetaState(int objectIndex, MetaFlag types, bool newValue, uint key, ApplyFlag flags);
|
|
||||||
|
|
||||||
/// <summary> Set the defined Meta State flags to the active or inactive state on actor (by name) </summary>
|
|
||||||
/// <param name="playerName"> The name of the players to be manipulated. </param>
|
|
||||||
/// <param name="types"> The flags defining which meta states to update to the new value. This can be multiple at once. </param>
|
|
||||||
/// <param name="newValue"> The new value to update to. </param>
|
|
||||||
/// <param name="key"> A key to unlock or lock the state if necessary. </param>
|
|
||||||
/// <param name="flags"> The flags used for the reversion. Respects Once (see <see cref="ApplyFlag.Once"/>.)</param>
|
|
||||||
/// <returns> ItemInvalid, ActorNotFound, ActorNotHuman, InvalidKey, Success. </returns>
|
|
||||||
public GlamourerApiEc SetMetaStateName(string playerName, MetaFlag types, bool newValue, uint key, ApplyFlag flags);
|
|
||||||
}
|
|
@@ -1,124 +0,0 @@
|
|||||||
using Glamourer.Api.Enums;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Glamourer.Api.Api;
|
|
||||||
|
|
||||||
/// <summary> Any functions related to Glamourer's state tracking. </summary>
|
|
||||||
public interface IGlamourerApiState
|
|
||||||
{
|
|
||||||
/// <summary> Get the current Glamourer state of an actor. </summary>
|
|
||||||
/// <param name="objectIndex"> The game object index of the desired actor. </param>
|
|
||||||
/// <param name="key"> A key to unlock the state if necessary. </param>
|
|
||||||
/// <returns> ActorNotFound, InvalidKey or Success, and the state on success. </returns>
|
|
||||||
/// <remarks> The actor does not need to have a prior Glamourer state as long as it can be found. </remarks>
|
|
||||||
public (GlamourerApiEc, JObject?) GetState(int objectIndex, uint key);
|
|
||||||
|
|
||||||
/// <summary> Get the current Glamourer state of a player character. </summary>
|
|
||||||
/// <param name="playerName"> The name of the desired player. </param>
|
|
||||||
/// <param name="key"> A key to unlock the state if necessary. </param>
|
|
||||||
/// <returns> ActorNotFound, InvalidKey or Success, and the state on success. </returns>
|
|
||||||
/// <remarks>
|
|
||||||
/// The player does not have to be currently available as long as he has a persisted Glamourer state.
|
|
||||||
/// Only players are checked for name equality, no NPCs.
|
|
||||||
/// If multiple players of the same name are found, the first is returned.
|
|
||||||
/// Prefer to use the index-based function unless you need to get the state of someone currently unavailable.
|
|
||||||
/// </remarks>
|
|
||||||
public (GlamourerApiEc, JObject?) GetStateName(string playerName, uint key);
|
|
||||||
|
|
||||||
/// <inheritdoc cref="GetState"/>
|
|
||||||
public (GlamourerApiEc, string?) GetStateBase64(int objectIndex, uint key);
|
|
||||||
|
|
||||||
/// <inheritdoc cref="GetStateName"/>
|
|
||||||
public (GlamourerApiEc, string?) GetStateBase64Name(string objectName, uint key);
|
|
||||||
|
|
||||||
/// <summary> Apply a supplied state to an actor. </summary>
|
|
||||||
/// <param name="applyState"> The state, which can be either a Glamourer-supplied JObject or a Base64 string. </param>
|
|
||||||
/// <param name="objectIndex"> The game object index of the actor to be manipulated. </param>
|
|
||||||
/// <param name="key"> A key to unlock or lock the state if necessary. </param>
|
|
||||||
/// <param name="flags"> The flags used for the application. Respects Once, Equipment, Customization and Lock (see <see cref="ApplyFlag"/>.) </param>
|
|
||||||
/// <returns> ActorNotFound, InvalidKey, ActorNotHuman, Success. </returns>
|
|
||||||
public GlamourerApiEc ApplyState(object applyState, int objectIndex, uint key, ApplyFlag flags);
|
|
||||||
|
|
||||||
/// <summary> Apply a supplied state to players. </summary>
|
|
||||||
/// <param name="applyState"> The state, which can be either a Glamourer-supplied JObject or a Base64 string. </param>
|
|
||||||
/// <param name="playerName"> The name of the player to be manipulated. </param>
|
|
||||||
/// <param name="key"> A key to unlock or lock the state if necessary. </param>
|
|
||||||
/// <param name="flags"> The flags used for the application. Respects Once, Equipment, Customization and Lock (see <see cref="ApplyFlag"/>.) </param>
|
|
||||||
/// <returns> ActorNotFound, InvalidKey, ActorNotHuman, Success. </returns>
|
|
||||||
/// <remarks>
|
|
||||||
/// The player does not have to be currently available as long as he has a persisted Glamourer state.<br/>
|
|
||||||
/// Only players are checked for name equality, no NPCs.<br/>
|
|
||||||
/// If multiple players of the same name are found, all of them are manipulated.<br/>
|
|
||||||
/// Prefer to use the index-based function unless you need to get the state of someone currently unavailable.
|
|
||||||
/// </remarks>
|
|
||||||
public GlamourerApiEc ApplyStateName(object applyState, string playerName, uint key, ApplyFlag flags);
|
|
||||||
|
|
||||||
/// <summary> Revert the Glamourer state of an actor to Game state. </summary>
|
|
||||||
/// <param name="objectIndex"> The game object index of the actor to be manipulated. </param>
|
|
||||||
/// <param name="key"> A key to unlock the state if necessary. </param>
|
|
||||||
/// <param name="flags"> The flags used for the reversion. Respects Equipment and Customization (see <see cref="ApplyFlag"/>.) </param>
|
|
||||||
/// <returns> ActorNotFound, InvalidKey, Success, NothingDone. </returns>
|
|
||||||
public GlamourerApiEc RevertState(int objectIndex, uint key, ApplyFlag flags);
|
|
||||||
|
|
||||||
/// <summary> Revert the Glamourer state of players to game state. </summary>
|
|
||||||
/// <param name="playerName"> The name of the players to be reverted. </param>
|
|
||||||
/// <param name="key"> A key to unlock the state if necessary. </param>
|
|
||||||
/// <param name="flags"> The flags used for the reversion. Respects Equipment and Customization (see <see cref="ApplyFlag"/>.) </param>
|
|
||||||
/// <returns> ActorNotFound, InvalidKey, Success, NothingDone. </returns>
|
|
||||||
/// /// <remarks>
|
|
||||||
/// The player does not have to be currently available as long as he has a persisted Glamourer state.<br/>
|
|
||||||
/// Only players are checked for name equality, no NPCs.<br/>
|
|
||||||
/// If multiple players of the same name are found, all of them are reverted.<br/>
|
|
||||||
/// Prefer to use the index-based function unless you need to get the state of someone currently unavailable.
|
|
||||||
/// </remarks>
|
|
||||||
public GlamourerApiEc RevertStateName(string playerName, uint key, ApplyFlag flags);
|
|
||||||
|
|
||||||
/// <summary> Unlock the Glamourer state of an actor with a key. </summary>
|
|
||||||
/// <param name="objectIndex"> The game object index of the actor to be manipulated. </param>
|
|
||||||
/// <param name="key"> A key to unlock the state. </param>
|
|
||||||
/// <returns> ActorNotFound, InvalidKey, Success, NothingDone. </returns>
|
|
||||||
public GlamourerApiEc UnlockState(int objectIndex, uint key);
|
|
||||||
|
|
||||||
/// <summary> Unlock the Glamourer state of players with a key. </summary>
|
|
||||||
/// <param name="playerName"> The name of the players to be unlocked. </param>
|
|
||||||
/// <param name="key"> A key to unlock the state. </param>
|
|
||||||
/// <returns> InvalidKey, Success, NothingDone. </returns>
|
|
||||||
public GlamourerApiEc UnlockStateName(string playerName, uint key);
|
|
||||||
|
|
||||||
/// <summary> Unlock all active glamourer states with a key. </summary>
|
|
||||||
/// <param name="key"> The key to unlock states with. </param>
|
|
||||||
/// <returns> The number of unlocked states. </returns>
|
|
||||||
public int UnlockAll(uint key);
|
|
||||||
|
|
||||||
/// <summary> Revert the Glamourer state of an actor to automation state. </summary>
|
|
||||||
/// <param name="objectIndex"> The game object index of the actor to be manipulated. </param>
|
|
||||||
/// <param name="key"> A key to unlock the state if necessary. </param>
|
|
||||||
/// <param name="flags"> The flags used for the reversion. Respects Once and Lock (see <see cref="ApplyFlag"/>.) </param>
|
|
||||||
/// <returns> ActorNotFound, InvalidKey, Success, NothingDone. </returns>
|
|
||||||
public GlamourerApiEc RevertToAutomation(int objectIndex, uint key, ApplyFlag flags);
|
|
||||||
|
|
||||||
/// <summary> Revert the Glamourer state of players to automation state. </summary>
|
|
||||||
/// <param name="playerName"> The name of the players to be reverted. </param>
|
|
||||||
/// <param name="key"> A key to unlock the state if necessary. </param>
|
|
||||||
/// <param name="flags"> The flags used for the reversion. Respects Once and Lock (see <see cref="ApplyFlag"/>.) </param>
|
|
||||||
/// <returns> ActorNotFound, InvalidKey, Success, NothingDone. </returns>
|
|
||||||
/// /// <remarks>
|
|
||||||
/// The player does not have to be currently available as long as he has a persisted Glamourer state.<br/>
|
|
||||||
/// Only players are checked for name equality, no NPCs.<br/>
|
|
||||||
/// If multiple players of the same name are found, all of them are reverted.<br/>
|
|
||||||
/// Prefer to use the index-based function unless you need to get the state of someone currently unavailable.
|
|
||||||
/// </remarks>
|
|
||||||
public GlamourerApiEc RevertToAutomationName(string playerName, uint key, ApplyFlag flags);
|
|
||||||
|
|
||||||
/// <summary> Invoked with the game object pointer (if available) whenever an actors tracked state changes. </summary>
|
|
||||||
public event Action<nint> StateChanged;
|
|
||||||
|
|
||||||
/// <summary> Invoked with the game object pointer (if available) whenever an actors tracked state changes, with the type of change. </summary>
|
|
||||||
public event Action<nint, StateChangeType> StateChangedWithType;
|
|
||||||
|
|
||||||
/// <summary> Invoked with the game object pointer (if available) whenever an actors tracked state finalizes a grouped change consisting of multiple smaller changes. </summary>
|
|
||||||
public event Action<nint, StateFinalizationType> StateFinalized;
|
|
||||||
|
|
||||||
/// <summary> Invoked when the player enters or leaves GPose (true => entered GPose, false => left GPose). </summary>
|
|
||||||
public event Action<bool>? GPoseChanged;
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
namespace Glamourer.Api.Enums;
|
|
||||||
|
|
||||||
/// <summary> Bonus item slots restricted to API-relevant slots. </summary>
|
|
||||||
public enum ApiBonusSlot : byte
|
|
||||||
{
|
|
||||||
/// <summary> No slot. </summary>
|
|
||||||
Unknown = 0,
|
|
||||||
|
|
||||||
/// <summary> The Glasses slot. </summary>
|
|
||||||
Glasses = 1,
|
|
||||||
}
|
|
@@ -1,45 +0,0 @@
|
|||||||
namespace Glamourer.Api.Enums;
|
|
||||||
|
|
||||||
/// <summary> Equip slots restricted to API-relevant slots, but compatible with GameData.EquipSlots. </summary>
|
|
||||||
public enum ApiEquipSlot : byte
|
|
||||||
{
|
|
||||||
/// <summary> No slot. </summary>
|
|
||||||
Unknown = 0,
|
|
||||||
|
|
||||||
/// <summary> Mainhand, also used for both-handed weapons. </summary>
|
|
||||||
MainHand = 1,
|
|
||||||
|
|
||||||
/// <summary> Offhand, used for shields or if you want to apply the offhand component of certain weapons. </summary>
|
|
||||||
OffHand = 2,
|
|
||||||
|
|
||||||
/// <summary> Head. </summary>
|
|
||||||
Head = 3,
|
|
||||||
|
|
||||||
/// <summary> Body. </summary>
|
|
||||||
Body = 4,
|
|
||||||
|
|
||||||
/// <summary> Hands. </summary>
|
|
||||||
Hands = 5,
|
|
||||||
|
|
||||||
/// <summary> Legs. </summary>
|
|
||||||
Legs = 7,
|
|
||||||
|
|
||||||
/// <summary> Feet. </summary>
|
|
||||||
Feet = 8,
|
|
||||||
|
|
||||||
/// <summary> Ears. </summary>
|
|
||||||
Ears = 9,
|
|
||||||
|
|
||||||
/// <summary> Neck. </summary>
|
|
||||||
Neck = 10,
|
|
||||||
|
|
||||||
/// <summary> Wrists. </summary>
|
|
||||||
Wrists = 11,
|
|
||||||
|
|
||||||
/// <summary> Right Finger. </summary>
|
|
||||||
RFinger = 12,
|
|
||||||
|
|
||||||
/// <summary> Left Finger. </summary>
|
|
||||||
/// <remarks> Not officially existing, means "weapon could be equipped in either hand" for the game. </remarks>
|
|
||||||
LFinger = 14,
|
|
||||||
}
|
|
@@ -1,31 +0,0 @@
|
|||||||
namespace Glamourer.Api.Enums;
|
|
||||||
|
|
||||||
/// <summary> Application flags that can be used in different situations. </summary>
|
|
||||||
[Flags]
|
|
||||||
public enum ApplyFlag : ulong
|
|
||||||
{
|
|
||||||
/// <summary> Apply the selected manipulation only once, without forcing the state into automation. </summary>
|
|
||||||
Once = 0x01,
|
|
||||||
|
|
||||||
/// <summary> Apply the selected manipulation on the equipment (might be more or less supported). </summary>
|
|
||||||
Equipment = 0x02,
|
|
||||||
|
|
||||||
/// <summary> Apply the selected manipulation on the customizations (might be more or less supported). </summary>
|
|
||||||
Customization = 0x04,
|
|
||||||
|
|
||||||
/// <summary> Lock the state with the given key after applying the selected manipulation </summary>
|
|
||||||
Lock = 0x08,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary> Extensions for apply flags. </summary>
|
|
||||||
public static class ApplyFlagEx
|
|
||||||
{
|
|
||||||
/// <summary> The default application flags for design-based manipulations. </summary>
|
|
||||||
public const ApplyFlag DesignDefault = ApplyFlag.Once | ApplyFlag.Equipment | ApplyFlag.Customization;
|
|
||||||
|
|
||||||
/// <summary> The default application flags for state-based manipulations. </summary>
|
|
||||||
public const ApplyFlag StateDefault = ApplyFlag.Equipment | ApplyFlag.Customization | ApplyFlag.Lock;
|
|
||||||
|
|
||||||
/// <summary> The default application flags for reverse manipulations. </summary>
|
|
||||||
public const ApplyFlag RevertDefault = ApplyFlag.Equipment | ApplyFlag.Customization;
|
|
||||||
}
|
|
@@ -1,29 +0,0 @@
|
|||||||
namespace Glamourer.Api.Enums;
|
|
||||||
|
|
||||||
/// <summary> Return codes for API functions. </summary>
|
|
||||||
public enum GlamourerApiEc
|
|
||||||
{
|
|
||||||
/// <summary> The function succeeded. </summary>
|
|
||||||
Success = 0,
|
|
||||||
|
|
||||||
/// <summary> The function did not encounter a problem, but also did not do anything. </summary>
|
|
||||||
NothingDone = 1,
|
|
||||||
|
|
||||||
/// <summary> The requested actor was not found. </summary>
|
|
||||||
ActorNotFound = 2,
|
|
||||||
|
|
||||||
/// <summary> The requested actor was not human, but should have been. </summary>
|
|
||||||
ActorNotHuman,
|
|
||||||
|
|
||||||
/// <summary> The requested design was not found. </summary>
|
|
||||||
DesignNotFound,
|
|
||||||
|
|
||||||
/// <summary> The requested item was not found or could not be applied to the requested slot. </summary>
|
|
||||||
ItemInvalid,
|
|
||||||
|
|
||||||
/// <summary> The state of an actor could not be manipulated because it was locked and the provided key could not unlock it. </summary>
|
|
||||||
InvalidKey,
|
|
||||||
|
|
||||||
/// <summary> The provided object could not be converted into a valid Glamourer state to apply. </summary>
|
|
||||||
InvalidState,
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
namespace Glamourer.Api.Enums;
|
|
||||||
|
|
||||||
/// <summary> Application flags for setting the meta state of an actor. </summary>
|
|
||||||
[Flags]
|
|
||||||
public enum MetaFlag : ulong
|
|
||||||
{
|
|
||||||
Wetness = 0x01,
|
|
||||||
HatState = 0x02,
|
|
||||||
VisorState = 0x04,
|
|
||||||
WeaponState = 0x08,
|
|
||||||
}
|
|
@@ -1,47 +0,0 @@
|
|||||||
namespace Glamourer.Api.Enums;
|
|
||||||
|
|
||||||
/// <summary> What type of information changed in a state. </summary>
|
|
||||||
public enum StateChangeType
|
|
||||||
{
|
|
||||||
/// <summary> A characters saved state had the model id changed. This means everything may have changed. </summary>
|
|
||||||
Model = 0,
|
|
||||||
|
|
||||||
/// <summary> A characters saved state had multiple customization values changed. </summary>
|
|
||||||
EntireCustomize = 1,
|
|
||||||
|
|
||||||
/// <summary> A characters saved state had a customization value changed. </summary>
|
|
||||||
Customize = 2,
|
|
||||||
|
|
||||||
/// <summary> A characters saved state had an equipment piece changed. </summary>
|
|
||||||
Equip = 3,
|
|
||||||
|
|
||||||
/// <summary> A characters saved state had its weapons changed. </summary>
|
|
||||||
Weapon = 4,
|
|
||||||
|
|
||||||
/// <summary> A characters saved state had a stain changed. </summary>
|
|
||||||
Stains = 5,
|
|
||||||
|
|
||||||
/// <summary> A characters saved state had a crest visibility changed. </summary>
|
|
||||||
Crest = 6,
|
|
||||||
|
|
||||||
/// <summary> A characters saved state had its customize parameter changed. </summary>
|
|
||||||
Parameter = 7,
|
|
||||||
|
|
||||||
/// <summary> A characters saved state had a material color table value changed. </summary>
|
|
||||||
MaterialValue = 8,
|
|
||||||
|
|
||||||
/// <summary> A characters saved state had a design applied. This means everything may have changed. </summary>
|
|
||||||
Design = 9,
|
|
||||||
|
|
||||||
/// <summary> A characters saved state had its state reset to its game values. </summary>
|
|
||||||
Reset = 10,
|
|
||||||
|
|
||||||
/// <summary> A characters saved state had a meta toggle changed. </summary>
|
|
||||||
Other = 11,
|
|
||||||
|
|
||||||
/// <summary> A characters state was reapplied. Data is null. </summary>
|
|
||||||
Reapply = 12,
|
|
||||||
|
|
||||||
/// <summary> A characters saved state had a bonus item changed. </summary>
|
|
||||||
BonusItem = 13,
|
|
||||||
}
|
|
@@ -1,36 +0,0 @@
|
|||||||
namespace Glamourer.Api.Enums;
|
|
||||||
|
|
||||||
/// <summary> What type of Glamourer process was performed on the actors state to update it. </summary>
|
|
||||||
public enum StateFinalizationType
|
|
||||||
{
|
|
||||||
/// <summary> A characters saved state had the model id altered. </summary>
|
|
||||||
ModelChange = 0,
|
|
||||||
|
|
||||||
/// <summary> A singular Design was applied to an actors state. </summary>
|
|
||||||
DesignApplied = 1,
|
|
||||||
|
|
||||||
/// <summary> A characters saved state had been reset to game values. </summary>
|
|
||||||
Revert = 2,
|
|
||||||
|
|
||||||
/// <summary> A characters saved state had only its customization data reset to game state. </summary>
|
|
||||||
RevertCustomize = 3,
|
|
||||||
|
|
||||||
/// <summary> A characters saved state had only its equipment data reset to game state. </summary>
|
|
||||||
RevertEquipment = 4,
|
|
||||||
|
|
||||||
/// <summary> A characters saved state had its advanced values reverted to game state. </summary>
|
|
||||||
RevertAdvanced = 5,
|
|
||||||
|
|
||||||
/// <summary> A characters saved state was reverted to automation state on top of their game state </summary>
|
|
||||||
RevertAutomation = 6,
|
|
||||||
|
|
||||||
/// <summary> A characters saved state had a generic reapply as a single operation. </summary>
|
|
||||||
Reapply = 7,
|
|
||||||
|
|
||||||
/// <summary> A characters saved state had their automation state reapplied over their existing state. </summary>
|
|
||||||
ReapplyAutomation = 8,
|
|
||||||
|
|
||||||
/// <summary> A characters save state finished applying all updated slots for game state on gearset change or initial load. </summary>
|
|
||||||
Gearset = 9,
|
|
||||||
}
|
|
||||||
|
|
@@ -1,34 +0,0 @@
|
|||||||
<Project Sdk="Dalamud.NET.Sdk/13.0.0">
|
|
||||||
<PropertyGroup>
|
|
||||||
<AssemblyTitle>Glamourer.Api</AssemblyTitle>
|
|
||||||
<Product>Glamourer</Product>
|
|
||||||
<Copyright>Copyright © 2025</Copyright>
|
|
||||||
<FileVersion>2.4.1.0</FileVersion>
|
|
||||||
<AssemblyVersion>2.4.1.0</AssemblyVersion>
|
|
||||||
<PackageVersion>2.4.1</PackageVersion>
|
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
|
||||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
|
||||||
<Title>Glamourer.Api</Title>
|
|
||||||
<Authors>Ottermandias</Authors>
|
|
||||||
<RepositoryUrl>https://github.com/Ottermandias/Glamourer</RepositoryUrl>
|
|
||||||
<Description>Auxiliary functions for Glamourers 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>
|
|
@@ -1,2 +0,0 @@
|
|||||||
<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>
|
|
@@ -1,4 +0,0 @@
|
|||||||
// Global using directives
|
|
||||||
|
|
||||||
global using System;
|
|
||||||
global using System.Collections.Generic;
|
|
@@ -1,114 +0,0 @@
|
|||||||
using Dalamud.Plugin;
|
|
||||||
using Dalamud.Plugin.Ipc;
|
|
||||||
|
|
||||||
namespace Glamourer.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);
|
|
||||||
}
|
|
@@ -1,234 +0,0 @@
|
|||||||
using Dalamud.Plugin;
|
|
||||||
using Dalamud.Plugin.Ipc;
|
|
||||||
using Dalamud.Plugin.Services;
|
|
||||||
|
|
||||||
namespace Glamourer.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();
|
|
||||||
}
|
|
@@ -1,394 +0,0 @@
|
|||||||
using Dalamud.Plugin;
|
|
||||||
using Dalamud.Plugin.Ipc;
|
|
||||||
using Dalamud.Plugin.Services;
|
|
||||||
|
|
||||||
namespace Glamourer.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 = new();
|
|
||||||
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();
|
|
||||||
}
|
|
@@ -1,224 +0,0 @@
|
|||||||
using Dalamud.Plugin;
|
|
||||||
using Dalamud.Plugin.Ipc;
|
|
||||||
|
|
||||||
namespace Glamourer.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();
|
|
||||||
}
|
|
@@ -1,217 +0,0 @@
|
|||||||
using Dalamud.Plugin;
|
|
||||||
using Dalamud.Plugin.Ipc;
|
|
||||||
using Dalamud.Plugin.Ipc.Exceptions;
|
|
||||||
|
|
||||||
namespace Glamourer.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);
|
|
||||||
}
|
|
@@ -1,26 +0,0 @@
|
|||||||
using Dalamud.IoC;
|
|
||||||
using Dalamud.Plugin;
|
|
||||||
using Dalamud.Plugin.Services;
|
|
||||||
|
|
||||||
namespace Glamourer.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!;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,52 +0,0 @@
|
|||||||
using Dalamud.Plugin;
|
|
||||||
using Glamourer.Api.Api;
|
|
||||||
using Glamourer.Api.Enums;
|
|
||||||
using Glamourer.Api.Helpers;
|
|
||||||
|
|
||||||
namespace Glamourer.Api.IpcSubscribers;
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiDesigns.GetDesignList"/>
|
|
||||||
public sealed class GetDesignList(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<Dictionary<Guid, string>>(pi, Label)
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{nameof(GetDesignList)}.V2";
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiDesigns.GetDesignList"/>
|
|
||||||
public new Dictionary<Guid, string> Invoke()
|
|
||||||
=> base.Invoke();
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static FuncProvider<Dictionary<Guid, string>> Provider(IDalamudPluginInterface pi, IGlamourerApiDesigns api)
|
|
||||||
=> new(pi, Label, api.GetDesignList);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiDesigns.ApplyDesign"/>
|
|
||||||
public sealed class ApplyDesign(IDalamudPluginInterface pi) : FuncSubscriber<Guid, int, uint, ulong, int>(pi, Label)
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApplyDesign)}";
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiDesigns.ApplyDesign"/>
|
|
||||||
public GlamourerApiEc Invoke(Guid designId, int objectIndex, uint key = 0, ApplyFlag flags = ApplyFlagEx.DesignDefault)
|
|
||||||
=> (GlamourerApiEc)Invoke(designId, objectIndex, key, (ulong)flags);
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static FuncProvider<Guid, int, uint, ulong, int> Provider(IDalamudPluginInterface pi, IGlamourerApiDesigns api)
|
|
||||||
=> new(pi, Label, (a, b, c, d) => (int)api.ApplyDesign(a, b, c, (ApplyFlag)d));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiDesigns.ApplyDesignName"/>
|
|
||||||
public sealed class ApplyDesignName(IDalamudPluginInterface pi) : FuncSubscriber<Guid, string, uint, ulong, int>(pi, Label)
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApplyDesignName)}";
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiDesigns.ApplyDesignName"/>
|
|
||||||
public GlamourerApiEc Invoke(Guid designId, string objectName, uint key = 0, ApplyFlag flags = ApplyFlagEx.DesignDefault)
|
|
||||||
=> (GlamourerApiEc)Invoke(designId, objectName, key, (ulong)flags);
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static FuncProvider<Guid, string, uint, ulong, int> Provider(IDalamudPluginInterface pi, IGlamourerApiDesigns api)
|
|
||||||
=> new(pi, Label, (a, b, c, d) => (int)api.ApplyDesignName(a, b, c, (ApplyFlag)d));
|
|
||||||
}
|
|
@@ -1,110 +0,0 @@
|
|||||||
using Dalamud.Plugin;
|
|
||||||
using Glamourer.Api.Api;
|
|
||||||
using Glamourer.Api.Enums;
|
|
||||||
using Glamourer.Api.Helpers;
|
|
||||||
|
|
||||||
namespace Glamourer.Api.IpcSubscribers;
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiItems.SetItem"/>
|
|
||||||
public sealed class SetItem(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<int, byte, ulong, IReadOnlyList<byte>, uint, ulong, int>(pi, Label)
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{nameof(SetItem)}.V3";
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiItems.SetItem"/>
|
|
||||||
public GlamourerApiEc Invoke(int objectIndex, ApiEquipSlot slot, ulong itemId, IReadOnlyList<byte> stain, uint key = 0,
|
|
||||||
ApplyFlag flags = ApplyFlag.Once)
|
|
||||||
=> (GlamourerApiEc)Invoke(objectIndex, (byte)slot, itemId, stain, key, (ulong)flags);
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static FuncProvider<int, byte, ulong, IReadOnlyList<byte>, uint, ulong, int> Provider(IDalamudPluginInterface pi,
|
|
||||||
IGlamourerApiItems api)
|
|
||||||
=> new(pi, Label, (a, b, c, d, e, f) => (int)api.SetItem(a, (ApiEquipSlot)b, c, d, e, (ApplyFlag)f));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiItems.SetItemName"/>
|
|
||||||
public sealed class SetItemName(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<string, byte, ulong, IReadOnlyList<byte>, uint, ulong, int>(pi, Label)
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{nameof(SetItemName)}.V2";
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiItems.SetItem"/>
|
|
||||||
public GlamourerApiEc Invoke(string objectName, ApiEquipSlot slot, ulong itemId, IReadOnlyList<byte> stain, uint key = 0,
|
|
||||||
ApplyFlag flags = ApplyFlag.Once)
|
|
||||||
=> (GlamourerApiEc)Invoke(objectName, (byte)slot, itemId, stain, key, (ulong)flags);
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static FuncProvider<string, byte, ulong, IReadOnlyList<byte>, uint, ulong, int> Provider(IDalamudPluginInterface pi,
|
|
||||||
IGlamourerApiItems api)
|
|
||||||
=> new(pi, Label, (a, b, c, d, e, f) => (int)api.SetItemName(a, (ApiEquipSlot)b, c, d, e, (ApplyFlag)f));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiItems.SetBonusItem"/>
|
|
||||||
public sealed class SetBonusItem(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<int, byte, ulong, uint, ulong, int>(pi, Label)
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{nameof(SetBonusItem)}";
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiItems.SetBonusItem"/>
|
|
||||||
public GlamourerApiEc Invoke(int objectIndex, ApiBonusSlot slot, ulong itemId, uint key = 0, ApplyFlag flags = ApplyFlag.Once)
|
|
||||||
=> (GlamourerApiEc)Invoke(objectIndex, (byte)slot, itemId, key, (ulong)flags);
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static FuncProvider<int, byte, ulong, uint, ulong, int> Provider(IDalamudPluginInterface pi, IGlamourerApiItems api)
|
|
||||||
=> new(pi, Label, (a, b, c, d, e) => (int)api.SetBonusItem(a, (ApiBonusSlot)b, c, d, (ApplyFlag)e));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiItems.SetBonusItemName"/>
|
|
||||||
public sealed class SetBonusItemName(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<string, byte, ulong, uint, ulong, int>(pi, Label)
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{nameof(SetBonusItemName)}.V2";
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiItems.SetBonusItemName"/>
|
|
||||||
public GlamourerApiEc Invoke(string objectName, ApiBonusSlot slot, ulong itemId, uint key = 0, ApplyFlag flags = ApplyFlag.Once)
|
|
||||||
=> (GlamourerApiEc)Invoke(objectName, (byte)slot, itemId, key, (ulong)flags);
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static FuncProvider<string, byte, ulong, uint, ulong, int> Provider(IDalamudPluginInterface pi, IGlamourerApiItems api)
|
|
||||||
=> new(pi, Label, (a, b, c, d, e) => (int)api.SetBonusItemName(a, (ApiBonusSlot)b, c, d, (ApplyFlag)e));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiItems.SetMetaState"/>
|
|
||||||
public sealed class SetMetaState(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<int, ulong, bool, uint, ulong, int>(pi, Label)
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{nameof(SetMetaState)}";
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiItems.SetMetaState"/>
|
|
||||||
public GlamourerApiEc Invoke(int objectIndex, MetaFlag types, bool newValue, uint key = 0,
|
|
||||||
ApplyFlag flags = ApplyFlag.Once)
|
|
||||||
=> (GlamourerApiEc)Invoke(objectIndex, (ulong)types, newValue, key, (ulong)flags);
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static FuncProvider<int, ulong, bool, uint, ulong, int> Provider(IDalamudPluginInterface pi,
|
|
||||||
IGlamourerApiItems api)
|
|
||||||
=> new(pi, Label, (a, b, c, d, e) => (int)api.SetMetaState(a, (MetaFlag)b, c, d, (ApplyFlag)e));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiItems.SetMetaStateName"/>
|
|
||||||
public sealed class SetMetaStateName(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<string, ulong, bool, uint, ulong, int>(pi, Label)
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{nameof(SetMetaStateName)}";
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiItems.SetMetaStateName"/>
|
|
||||||
public GlamourerApiEc Invoke(string objectName, MetaFlag types, bool newValue, uint key = 0,
|
|
||||||
ApplyFlag flags = ApplyFlag.Once)
|
|
||||||
=> (GlamourerApiEc)Invoke(objectName, (ulong)types, newValue, key, (ulong)flags);
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static FuncProvider<string, ulong, bool, uint, ulong, int> Provider(IDalamudPluginInterface pi,
|
|
||||||
IGlamourerApiItems api)
|
|
||||||
=> new(pi, Label, (a, b, c, d, e) => (int)api.SetMetaStateName(a, (MetaFlag)b, c, d, (ApplyFlag)e));
|
|
||||||
}
|
|
@@ -1,52 +0,0 @@
|
|||||||
using Dalamud.Game.ClientState.Objects.Types;
|
|
||||||
using Dalamud.Plugin;
|
|
||||||
using Glamourer.Api.Helpers;
|
|
||||||
|
|
||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
|
||||||
|
|
||||||
namespace Glamourer.Api.IpcSubscribers.Legacy;
|
|
||||||
|
|
||||||
public sealed class GetDesignList(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<(string Name, Guid Identifier)[]>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(GetDesignList)}";
|
|
||||||
|
|
||||||
public new (string Name, Guid Identifier)[] Invoke()
|
|
||||||
=> base.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ApplyByGuid(IDalamudPluginInterface pi)
|
|
||||||
: ActionSubscriber<Guid, string>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApplyByGuid)}";
|
|
||||||
|
|
||||||
public new void Invoke(Guid design, string name)
|
|
||||||
=> base.Invoke(design, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ApplyByGuidOnce(IDalamudPluginInterface pi)
|
|
||||||
: ActionSubscriber<Guid, string>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApplyByGuidOnce)}";
|
|
||||||
|
|
||||||
public new void Invoke(Guid design, string name)
|
|
||||||
=> base.Invoke(design, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ApplyByGuidToCharacter(IDalamudPluginInterface pi)
|
|
||||||
: ActionSubscriber<Guid, ICharacter?>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApplyByGuidToCharacter)}";
|
|
||||||
|
|
||||||
public new void Invoke(Guid design, ICharacter? character)
|
|
||||||
=> base.Invoke(design, character);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ApplyByGuidOnceToCharacter(IDalamudPluginInterface pi)
|
|
||||||
: ActionSubscriber<Guid, ICharacter?>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApplyByGuidOnceToCharacter)}";
|
|
||||||
|
|
||||||
public new void Invoke(Guid design, ICharacter? character)
|
|
||||||
=> base.Invoke(design, character);
|
|
||||||
}
|
|
@@ -1,66 +0,0 @@
|
|||||||
using Dalamud.Game.ClientState.Objects.Types;
|
|
||||||
using Dalamud.Plugin;
|
|
||||||
using Glamourer.Api.Api;
|
|
||||||
using Glamourer.Api.Enums;
|
|
||||||
using Glamourer.Api.Helpers;
|
|
||||||
|
|
||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
|
||||||
|
|
||||||
namespace Glamourer.Api.IpcSubscribers.Legacy;
|
|
||||||
|
|
||||||
public sealed class SetItem(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<ICharacter?, byte, ulong, byte, uint, int>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(SetItem)}";
|
|
||||||
|
|
||||||
public new GlamourerApiEc Invoke(ICharacter? character, byte slot, ulong itemId, byte stainId, uint key)
|
|
||||||
=> (GlamourerApiEc)base.Invoke(character, slot, itemId, stainId, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class SetItemOnce(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<ICharacter?, byte, ulong, byte, uint, int>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(SetItemOnce)}";
|
|
||||||
|
|
||||||
public new GlamourerApiEc Invoke(ICharacter? character, byte slot, ulong itemId, byte stainId, uint key)
|
|
||||||
=> (GlamourerApiEc)base.Invoke(character, slot, itemId, stainId, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class SetItemByActorName(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<string, byte, ulong, byte, uint, int>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(SetItemByActorName)}";
|
|
||||||
|
|
||||||
public new GlamourerApiEc Invoke(string actorName, byte slot, ulong itemId, byte stainId, uint key)
|
|
||||||
=> (GlamourerApiEc)base.Invoke(actorName, slot, itemId, stainId, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class SetItemOnceByActorName(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<string, byte, ulong, byte, uint, int>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(SetItemOnceByActorName)}";
|
|
||||||
|
|
||||||
public new GlamourerApiEc Invoke(string actorName, byte slot, ulong itemId, byte stainId, uint key)
|
|
||||||
=> (GlamourerApiEc)base.Invoke(actorName, slot, itemId, stainId, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class SetItemV2(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<int, byte, ulong, byte, uint, ulong, int>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(SetItem)}.V2";
|
|
||||||
|
|
||||||
public GlamourerApiEc Invoke(int objectIndex, ApiEquipSlot slot, ulong itemId, byte stain, uint key = 0, ApplyFlag flags = ApplyFlag.Once)
|
|
||||||
=> (GlamourerApiEc)Invoke(objectIndex, (byte)slot, itemId, stain, key, (ulong)flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class SetItemName(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<string, byte, ulong, byte, uint, ulong, int>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(SetItemName)}";
|
|
||||||
|
|
||||||
public GlamourerApiEc Invoke(string objectName, ApiEquipSlot slot, ulong itemId, byte stain, uint key = 0, ApplyFlag flags = ApplyFlag.Once)
|
|
||||||
=> (GlamourerApiEc)Invoke(objectName, (byte)slot, itemId, stain, key, (ulong)flags);
|
|
||||||
|
|
||||||
public static FuncProvider<string, byte, ulong, byte, uint, ulong, int> Provider(IDalamudPluginInterface pi, IGlamourerApiItems api)
|
|
||||||
=> new(pi, Label, (a, b, c, d, e, f) => (int)api.SetItemName(a, (ApiEquipSlot)b, c, [d], e, (ApplyFlag)f));
|
|
||||||
}
|
|
@@ -1,15 +0,0 @@
|
|||||||
using Dalamud.Plugin;
|
|
||||||
using Glamourer.Api.Helpers;
|
|
||||||
|
|
||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
|
||||||
|
|
||||||
namespace Glamourer.Api.IpcSubscribers.Legacy;
|
|
||||||
|
|
||||||
public sealed class ApiVersions(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<(int, int)>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApiVersions)}";
|
|
||||||
|
|
||||||
public new (int Major, int Minor) Invoke()
|
|
||||||
=> base.Invoke();
|
|
||||||
}
|
|
@@ -1,250 +0,0 @@
|
|||||||
using Dalamud.Game.ClientState.Objects.Types;
|
|
||||||
using Dalamud.Plugin;
|
|
||||||
using Glamourer.Api.Helpers;
|
|
||||||
|
|
||||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
|
||||||
|
|
||||||
namespace Glamourer.Api.IpcSubscribers.Legacy;
|
|
||||||
|
|
||||||
public sealed class Revert(IDalamudPluginInterface pi)
|
|
||||||
: ActionSubscriber<string>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(Revert)}";
|
|
||||||
|
|
||||||
public new void Invoke(string characterName)
|
|
||||||
=> base.Invoke(characterName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class RevertCharacter(IDalamudPluginInterface pi)
|
|
||||||
: ActionSubscriber<ICharacter?>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(RevertCharacter)}";
|
|
||||||
|
|
||||||
public new void Invoke(ICharacter? character)
|
|
||||||
=> base.Invoke(character);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class RevertLock(IDalamudPluginInterface pi)
|
|
||||||
: ActionSubscriber<string, uint>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(RevertLock)}";
|
|
||||||
|
|
||||||
public new void Invoke(string characterName, uint key)
|
|
||||||
=> base.Invoke(characterName, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class RevertCharacterLock(IDalamudPluginInterface pi)
|
|
||||||
: ActionSubscriber<ICharacter?, uint>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(RevertCharacterLock)}";
|
|
||||||
|
|
||||||
public new void Invoke(ICharacter? character, uint key)
|
|
||||||
=> base.Invoke(character, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class RevertToAutomation(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<string, uint, bool>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(RevertToAutomation)}";
|
|
||||||
|
|
||||||
public new bool Invoke(string characterName, uint key)
|
|
||||||
=> base.Invoke(characterName, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class RevertToAutomationCharacter(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<ICharacter?, uint, bool>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(RevertToAutomationCharacter)}";
|
|
||||||
|
|
||||||
public new bool Invoke(ICharacter? character, uint key)
|
|
||||||
=> base.Invoke(character, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class Unlock(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<ICharacter?, uint, bool>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(Unlock)}";
|
|
||||||
|
|
||||||
public new bool Invoke(ICharacter? character, uint key)
|
|
||||||
=> base.Invoke(character, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class UnlockName(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<string, uint, bool>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(UnlockName)}";
|
|
||||||
|
|
||||||
public new bool Invoke(string characterName, uint key)
|
|
||||||
=> base.Invoke(characterName, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class StateChanged
|
|
||||||
{
|
|
||||||
public const string Label = $"Penumbra.{nameof(StateChanged)}";
|
|
||||||
|
|
||||||
public static EventSubscriber<int, nint, Lazy<string>> Subscriber(IDalamudPluginInterface pi,
|
|
||||||
params Action<int, nint, Lazy<string>>[] actions)
|
|
||||||
=> new(pi, Label, actions);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class GetAllCustomization(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<string, string?>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(GetAllCustomization)}";
|
|
||||||
|
|
||||||
public new string? Invoke(string characterName)
|
|
||||||
=> base.Invoke(characterName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class GetAllCustomizationFromCharacter(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<ICharacter?, string?>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(GetAllCustomizationFromCharacter)}";
|
|
||||||
|
|
||||||
public new string? Invoke(ICharacter? character)
|
|
||||||
=> base.Invoke(character);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class GetAllCustomizationLocked(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<string, uint, string?>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(GetAllCustomizationLocked)}";
|
|
||||||
|
|
||||||
public new string? Invoke(string characterName, uint key)
|
|
||||||
=> base.Invoke(characterName, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class GetAllCustomizationFromLockedCharacter(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<ICharacter?, uint, string?>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(GetAllCustomizationFromLockedCharacter)}";
|
|
||||||
|
|
||||||
public new string? Invoke(ICharacter? character, uint key)
|
|
||||||
=> base.Invoke(character, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ApplyAll(IDalamudPluginInterface pi)
|
|
||||||
: ActionSubscriber<string, string>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApplyAll)}";
|
|
||||||
|
|
||||||
public new void Invoke(string characterName, string stateBase64)
|
|
||||||
=> base.Invoke(characterName, stateBase64);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ApplyAllOnce(IDalamudPluginInterface pi)
|
|
||||||
: ActionSubscriber<string, string>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApplyAllOnce)}";
|
|
||||||
|
|
||||||
public new void Invoke(string characterName, string stateBase64)
|
|
||||||
=> base.Invoke(characterName, stateBase64);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ApplyAllToCharacter(IDalamudPluginInterface pi)
|
|
||||||
: ActionSubscriber<ICharacter?, string>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApplyAllToCharacter)}";
|
|
||||||
|
|
||||||
public new void Invoke(ICharacter? character, string stateBase64)
|
|
||||||
=> base.Invoke(character, stateBase64);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ApplyAllOnceToCharacter(IDalamudPluginInterface pi)
|
|
||||||
: ActionSubscriber<ICharacter?, string>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApplyAllOnceToCharacter)}";
|
|
||||||
|
|
||||||
public new void Invoke(ICharacter? character, string stateBase64)
|
|
||||||
=> base.Invoke(character, stateBase64);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ApplyOnlyEquipment(IDalamudPluginInterface pi)
|
|
||||||
: ActionSubscriber<string, string>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApplyOnlyEquipment)}";
|
|
||||||
|
|
||||||
public new void Invoke(string characterName, string stateBase64)
|
|
||||||
=> base.Invoke(characterName, stateBase64);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ApplyOnlyEquipmentToCharacter(IDalamudPluginInterface pi)
|
|
||||||
: ActionSubscriber<ICharacter?, string>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApplyOnlyEquipmentToCharacter)}";
|
|
||||||
|
|
||||||
public new void Invoke(ICharacter? character, string stateBase64)
|
|
||||||
=> base.Invoke(character, stateBase64);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ApplyOnlyCustomization(IDalamudPluginInterface pi)
|
|
||||||
: ActionSubscriber<string, string>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApplyOnlyCustomization)}";
|
|
||||||
|
|
||||||
public new void Invoke(string characterName, string stateBase64)
|
|
||||||
=> base.Invoke(characterName, stateBase64);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ApplyOnlyCustomizationToCharacter(IDalamudPluginInterface pi)
|
|
||||||
: ActionSubscriber<ICharacter?, string>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApplyOnlyCustomizationToCharacter)}";
|
|
||||||
|
|
||||||
public new void Invoke(ICharacter? character, string stateBase64)
|
|
||||||
=> base.Invoke(character, stateBase64);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ApplyAllLock(IDalamudPluginInterface pi)
|
|
||||||
: ActionSubscriber<string, string, uint>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApplyAllLock)}";
|
|
||||||
|
|
||||||
public new void Invoke(string characterName, string stateBase64, uint key)
|
|
||||||
=> base.Invoke(characterName, stateBase64, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ApplyAllToCharacterLock(IDalamudPluginInterface pi)
|
|
||||||
: ActionSubscriber<ICharacter?, string, uint>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApplyAllToCharacterLock)}";
|
|
||||||
|
|
||||||
public new void Invoke(ICharacter? character, string stateBase64, uint key)
|
|
||||||
=> base.Invoke(character, stateBase64, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ApplyOnlyEquipmentLock(IDalamudPluginInterface pi)
|
|
||||||
: ActionSubscriber<string, string, uint>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApplyOnlyEquipmentLock)}";
|
|
||||||
|
|
||||||
public new void Invoke(string characterName, string stateBase64, uint key)
|
|
||||||
=> base.Invoke(characterName, stateBase64, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ApplyOnlyEquipmentToCharacterLock(IDalamudPluginInterface pi)
|
|
||||||
: ActionSubscriber<ICharacter?, string, uint>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApplyOnlyEquipmentToCharacterLock)}";
|
|
||||||
|
|
||||||
public new void Invoke(ICharacter? character, string stateBase64, uint key)
|
|
||||||
=> base.Invoke(character, stateBase64, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ApplyOnlyCustomizationLock(IDalamudPluginInterface pi)
|
|
||||||
: ActionSubscriber<string, string, uint>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApplyOnlyCustomizationLock)}";
|
|
||||||
|
|
||||||
public new void Invoke(string characterName, string stateBase64, uint key)
|
|
||||||
=> base.Invoke(characterName, stateBase64, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ApplyOnlyCustomizationToCharacterLock(IDalamudPluginInterface pi)
|
|
||||||
: ActionSubscriber<ICharacter?, string, uint>(pi, Label)
|
|
||||||
{
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApplyOnlyCustomizationToCharacterLock)}";
|
|
||||||
|
|
||||||
public new void Invoke(ICharacter? character, string stateBase64, uint key)
|
|
||||||
=> base.Invoke(character, stateBase64, key);
|
|
||||||
}
|
|
@@ -1,51 +0,0 @@
|
|||||||
using Dalamud.Plugin;
|
|
||||||
using Glamourer.Api.Api;
|
|
||||||
using Glamourer.Api.Helpers;
|
|
||||||
|
|
||||||
namespace Glamourer.Api.IpcSubscribers;
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiBase.ApiVersion"/>
|
|
||||||
public sealed class ApiVersion(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<(int, int)>(pi, Label)
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApiVersion)}.V2";
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiBase.ApiVersion"/>
|
|
||||||
public new (int Major, int Minor) Invoke()
|
|
||||||
=> base.Invoke();
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static FuncProvider<(int, int)> Provider(IDalamudPluginInterface pi, IGlamourerApiBase api)
|
|
||||||
=> new(pi, Label, () => api.ApiVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary> Triggered when the Glamourer API is initialized and ready. </summary>
|
|
||||||
public static class Initialized
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{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 Glamourer API is fully disposed and unavailable. </summary>
|
|
||||||
public static class Disposed
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{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);
|
|
||||||
}
|
|
@@ -1,311 +0,0 @@
|
|||||||
using Dalamud.Plugin;
|
|
||||||
using Glamourer.Api.Api;
|
|
||||||
using Glamourer.Api.Enums;
|
|
||||||
using Glamourer.Api.Helpers;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Glamourer.Api.IpcSubscribers;
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.GetState"/>
|
|
||||||
public sealed class GetState(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<int, uint, (int, JObject?)>(pi, Label)
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{nameof(GetState)}";
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.GetState"/>
|
|
||||||
public new (GlamourerApiEc, JObject?) Invoke(int objectIndex, uint key = 0)
|
|
||||||
{
|
|
||||||
var (ec, data) = base.Invoke(objectIndex, key);
|
|
||||||
return ((GlamourerApiEc)ec, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static FuncProvider<int, uint, (int, JObject?)> Provider(IDalamudPluginInterface pi, IGlamourerApiState api)
|
|
||||||
=> new(pi, Label, (a, b) =>
|
|
||||||
{
|
|
||||||
var (ec, data) = api.GetState(a, b);
|
|
||||||
return ((int)ec, data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.GetStateName"/>
|
|
||||||
public sealed class GetStateName(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<string, uint, (int, JObject?)>(pi, Label)
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{nameof(GetStateName)}";
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.GetStateName"/>
|
|
||||||
public new (GlamourerApiEc, JObject?) Invoke(string objectName, uint key = 0)
|
|
||||||
{
|
|
||||||
var (ec, data) = base.Invoke(objectName, key);
|
|
||||||
return ((GlamourerApiEc)ec, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static FuncProvider<string, uint, (int, JObject?)> Provider(IDalamudPluginInterface pi, IGlamourerApiState api)
|
|
||||||
=> new(pi, Label, (i, k) =>
|
|
||||||
{
|
|
||||||
var (ec, data) = api.GetStateName(i, k);
|
|
||||||
return ((int)ec, data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.GetStateBase64"/>
|
|
||||||
public sealed class GetStateBase64(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<int, uint, (int, string?)>(pi, Label)
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{nameof(GetStateBase64)}";
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.GetStateBase64"/>
|
|
||||||
public new (GlamourerApiEc, string?) Invoke(int objectIndex, uint key = 0)
|
|
||||||
{
|
|
||||||
var (ec, data) = base.Invoke(objectIndex, key);
|
|
||||||
return ((GlamourerApiEc)ec, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static FuncProvider<int, uint, (int, string?)> Provider(IDalamudPluginInterface pi, IGlamourerApiState api)
|
|
||||||
=> new(pi, Label, (a, b) =>
|
|
||||||
{
|
|
||||||
var (ec, data) = api.GetStateBase64(a, b);
|
|
||||||
return ((int)ec, data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.GetStateBase64Name"/>
|
|
||||||
public sealed class GetStateBase64Name(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<string, uint, (int, string?)>(pi, Label)
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{nameof(GetStateBase64Name)}";
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.GetStateBase64Name"/>
|
|
||||||
public new (GlamourerApiEc, string?) Invoke(string objectName, uint key = 0)
|
|
||||||
{
|
|
||||||
var (ec, data) = base.Invoke(objectName, key);
|
|
||||||
return ((GlamourerApiEc)ec, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static FuncProvider<string, uint, (int, string?)> Provider(IDalamudPluginInterface pi, IGlamourerApiState api)
|
|
||||||
=> new(pi, Label, (i, k) =>
|
|
||||||
{
|
|
||||||
var (ec, data) = api.GetStateBase64Name(i, k);
|
|
||||||
return ((int)ec, data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.ApplyState"/>
|
|
||||||
public sealed class ApplyState(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<object, int, uint, ulong, int>(pi, Label)
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApplyState)}";
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.ApplyState"/>
|
|
||||||
public GlamourerApiEc Invoke(JObject state, int objectIndex, uint key = 0, ApplyFlag flags = ApplyFlagEx.StateDefault)
|
|
||||||
=> (GlamourerApiEc)Invoke(state, objectIndex, key, (ulong)flags);
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.ApplyState"/>
|
|
||||||
public GlamourerApiEc Invoke(string base64State, int objectIndex, uint key = 0, ApplyFlag flags = ApplyFlagEx.StateDefault)
|
|
||||||
=> (GlamourerApiEc)Invoke(base64State, objectIndex, key, (ulong)flags);
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static FuncProvider<object, int, uint, ulong, int> Provider(IDalamudPluginInterface pi, IGlamourerApiState api)
|
|
||||||
=> new(pi, Label, (a, b, c, d) => (int)api.ApplyState(a, b, c, (ApplyFlag)d));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.ApplyStateName"/>
|
|
||||||
public sealed class ApplyStateName(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<object, string, uint, ulong, int>(pi, Label)
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{nameof(ApplyStateName)}";
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.ApplyState"/>
|
|
||||||
public GlamourerApiEc Invoke(JObject state, string objectName, uint key = 0, ApplyFlag flags = ApplyFlagEx.StateDefault)
|
|
||||||
=> (GlamourerApiEc)Invoke(state, objectName, key, (ulong)flags);
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.ApplyState"/>
|
|
||||||
public GlamourerApiEc Invoke(string base64State, string objectName, uint key = 0, ApplyFlag flags = ApplyFlagEx.StateDefault)
|
|
||||||
=> (GlamourerApiEc)Invoke(base64State, objectName, key, (ulong)flags);
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static FuncProvider<object, string, uint, ulong, int> Provider(IDalamudPluginInterface pi, IGlamourerApiState api)
|
|
||||||
=> new(pi, Label, (a, b, c, d) => (int)api.ApplyStateName(a, b, c, (ApplyFlag)d));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.RevertState"/>
|
|
||||||
public sealed class RevertState(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<int, uint, ulong, int>(pi, Label)
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{nameof(RevertState)}";
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.RevertState"/>
|
|
||||||
public GlamourerApiEc Invoke(int objectIndex, uint key = 0, ApplyFlag flags = ApplyFlagEx.RevertDefault)
|
|
||||||
=> (GlamourerApiEc)Invoke(objectIndex, key, (ulong)flags);
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static FuncProvider<int, uint, ulong, int> Provider(IDalamudPluginInterface pi, IGlamourerApiState api)
|
|
||||||
=> new(pi, Label, (a, b, c) => (int)api.RevertState(a, b, (ApplyFlag)c));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.RevertStateName"/>
|
|
||||||
public sealed class RevertStateName(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<string, uint, ulong, int>(pi, Label)
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{nameof(RevertStateName)}";
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.RevertStateName"/>
|
|
||||||
public GlamourerApiEc Invoke(string objectName, uint key = 0, ApplyFlag flags = ApplyFlagEx.RevertDefault)
|
|
||||||
=> (GlamourerApiEc)Invoke(objectName, key, (ulong)flags);
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static FuncProvider<string, uint, ulong, int> Provider(IDalamudPluginInterface pi, IGlamourerApiState api)
|
|
||||||
=> new(pi, Label, (a, b, c) => (int)api.RevertStateName(a, b, (ApplyFlag)c));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.UnlockState"/>
|
|
||||||
public sealed class UnlockState(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<int, uint, int>(pi, Label)
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{nameof(UnlockState)}";
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.UnlockState"/>
|
|
||||||
public new GlamourerApiEc Invoke(int objectIndex, uint key = 0)
|
|
||||||
=> (GlamourerApiEc)base.Invoke(objectIndex, key);
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static FuncProvider<int, uint, int> Provider(IDalamudPluginInterface pi, IGlamourerApiState api)
|
|
||||||
=> new(pi, Label, (a, b) => (int)api.UnlockState(a, b));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.UnlockStateName"/>
|
|
||||||
public sealed class UnlockStateName(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<string, uint, int>(pi, Label)
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{nameof(UnlockStateName)}";
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.UnlockStateName"/>
|
|
||||||
public new GlamourerApiEc Invoke(string objectName, uint key = 0)
|
|
||||||
=> (GlamourerApiEc)base.Invoke(objectName, key);
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static FuncProvider<string, uint, int> Provider(IDalamudPluginInterface pi, IGlamourerApiState api)
|
|
||||||
=> new(pi, Label, (a, b) => (int)api.UnlockStateName(a, b));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.UnlockAll"/>
|
|
||||||
public sealed class UnlockAll(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<uint, int>(pi, Label)
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{nameof(UnlockAll)}";
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.UnlockAll"/>
|
|
||||||
public new int Invoke(uint key)
|
|
||||||
=> base.Invoke(key);
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static FuncProvider<uint, int> Provider(IDalamudPluginInterface pi, IGlamourerApiState api)
|
|
||||||
=> new(pi, Label, api.UnlockAll);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.RevertToAutomation"/>
|
|
||||||
public sealed class RevertToAutomation(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<int, uint, ulong, int>(pi, Label)
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{nameof(RevertToAutomation)}.V2";
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.RevertToAutomation"/>
|
|
||||||
public GlamourerApiEc Invoke(int objectIndex, uint key = 0, ApplyFlag flags = ApplyFlagEx.RevertDefault)
|
|
||||||
=> (GlamourerApiEc)Invoke(objectIndex, key, (ulong)flags);
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static FuncProvider<int, uint, ulong, int> Provider(IDalamudPluginInterface pi, IGlamourerApiState api)
|
|
||||||
=> new(pi, Label, (a, b, c) => (int)api.RevertToAutomation(a, b, (ApplyFlag)c));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.RevertToAutomationName"/>
|
|
||||||
public sealed class RevertToAutomationName(IDalamudPluginInterface pi)
|
|
||||||
: FuncSubscriber<string, uint, ulong, int>(pi, Label)
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Glamourer.{nameof(RevertToAutomationName)}";
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.RevertToAutomationName"/>
|
|
||||||
public GlamourerApiEc Invoke(string objectName, uint key = 0, ApplyFlag flags = ApplyFlagEx.RevertDefault)
|
|
||||||
=> (GlamourerApiEc)Invoke(objectName, key, (ulong)flags);
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static FuncProvider<string, uint, ulong, int> Provider(IDalamudPluginInterface pi, IGlamourerApiState api)
|
|
||||||
=> new(pi, Label, (a, b, c) => (int)api.RevertToAutomationName(a, b, (ApplyFlag)c));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.StateChanged" />
|
|
||||||
public static class StateChanged
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Penumbra.{nameof(StateChanged)}.V2";
|
|
||||||
|
|
||||||
/// <summary> Create a new event subscriber. </summary>
|
|
||||||
public static EventSubscriber<nint> Subscriber(IDalamudPluginInterface pi, params Action<nint>[] actions)
|
|
||||||
=> new(pi, Label, actions);
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static EventProvider<nint> Provider(IDalamudPluginInterface pi, IGlamourerApiState api)
|
|
||||||
=> new(pi, Label, (t => api.StateChanged += t, t => api.StateChanged -= t));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.StateChangedWithType" />
|
|
||||||
public static class StateChangedWithType
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Penumbra.{nameof(StateChangedWithType)}";
|
|
||||||
|
|
||||||
/// <summary> Create a new event subscriber. </summary>
|
|
||||||
public static EventSubscriber<nint, StateChangeType> Subscriber(IDalamudPluginInterface pi, params Action<nint, StateChangeType>[] actions)
|
|
||||||
=> new(pi, Label, actions);
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static EventProvider<nint, StateChangeType> Provider(IDalamudPluginInterface pi, IGlamourerApiState api)
|
|
||||||
=> new(pi, Label, (t => api.StateChangedWithType += t, t => api.StateChangedWithType -= t));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.StateFinalized" />
|
|
||||||
public static class StateFinalized
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Penumbra.{nameof(StateFinalized)}";
|
|
||||||
|
|
||||||
/// <summary> Create a new event subscriber. </summary>
|
|
||||||
public static EventSubscriber<nint, StateFinalizationType> Subscriber(IDalamudPluginInterface pi, params Action<nint, StateFinalizationType>[] actions)
|
|
||||||
=> new(pi, Label, actions);
|
|
||||||
|
|
||||||
/// <summary> Create a provider. </summary>
|
|
||||||
public static EventProvider<nint, StateFinalizationType> Provider(IDalamudPluginInterface pi, IGlamourerApiState api)
|
|
||||||
=> new(pi, Label, (t => api.StateFinalized += t, t => api.StateFinalized -= t));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="IGlamourerApiState.GPoseChanged" />
|
|
||||||
public static class GPoseChanged
|
|
||||||
{
|
|
||||||
/// <summary> The label. </summary>
|
|
||||||
public const string Label = $"Penumbra.{nameof(GPoseChanged)}";
|
|
||||||
|
|
||||||
/// <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, IGlamourerApiState api)
|
|
||||||
=> new(pi, Label, (t => api.GPoseChanged += t, t => api.GPoseChanged -= t));
|
|
||||||
}
|
|
@@ -1,4 +0,0 @@
|
|||||||
# Glamourer
|
|
||||||
|
|
||||||
This is an auxiliary repository for Glamourers external API.
|
|
||||||
For more information, see the [main repo](https://github.com/Ottermandias/Glamourer).
|
|
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"version": 1,
|
|
||||||
"dependencies": {
|
|
||||||
"net9.0-windows7.0": {
|
|
||||||
"DotNet.ReproducibleBuilds": {
|
|
||||||
"type": "Direct",
|
|
||||||
"requested": "[1.2.25, )",
|
|
||||||
"resolved": "1.2.25",
|
|
||||||
"contentHash": "xCXiw7BCxHJ8pF6wPepRUddlh2dlQlbr81gXA72hdk4FLHkKXas7EH/n+fk5UCA/YfMqG1Z6XaPiUjDbUNBUzg=="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
630
LICENSE
630
LICENSE
@@ -1,21 +1,617 @@
|
|||||||
MIT License
|
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 19 November 2007
|
||||||
|
|
||||||
Copyright (c) 2022 Penumbra-Sync
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Preamble
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
The GNU Affero General Public License is a free, copyleft license for
|
||||||
copies or substantial portions of the Software.
|
software and other kinds of works, specifically designed to ensure
|
||||||
|
cooperation with the community in the case of network server software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
The licenses for most software and other practical works are designed
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
to take away your freedom to share and change the works. By contrast,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
our General Public Licenses are intended to guarantee your freedom to
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
share and change all versions of a program--to make sure it remains free
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
software for all its users.
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
Developers that use our General Public Licenses protect your rights
|
||||||
|
with two steps: (1) assert copyright on the software, and (2) offer
|
||||||
|
you this License which gives you legal permission to copy, distribute
|
||||||
|
and/or modify the software.
|
||||||
|
|
||||||
|
A secondary benefit of defending all users' freedom is that
|
||||||
|
improvements made in alternate versions of the program, if they
|
||||||
|
receive widespread use, become available for other developers to
|
||||||
|
incorporate. Many developers of free software are heartened and
|
||||||
|
encouraged by the resulting cooperation. However, in the case of
|
||||||
|
software used on network servers, this result may fail to come about.
|
||||||
|
The GNU General Public License permits making a modified version and
|
||||||
|
letting the public access it on a server without ever releasing its
|
||||||
|
source code to the public.
|
||||||
|
|
||||||
|
The GNU Affero General Public License is designed specifically to
|
||||||
|
ensure that, in such cases, the modified source code becomes available
|
||||||
|
to the community. It requires the operator of a network server to
|
||||||
|
provide the source code of the modified version running there to the
|
||||||
|
users of that server. Therefore, public use of a modified version, on
|
||||||
|
a publicly accessible server, gives the public access to the source
|
||||||
|
code of the modified version.
|
||||||
|
|
||||||
|
An older license, called the Affero General Public License and
|
||||||
|
published by Affero, was designed to accomplish similar goals. This is
|
||||||
|
a different license, not a version of the Affero GPL, but Affero has
|
||||||
|
released a new version of the Affero GPL which permits relicensing under
|
||||||
|
this license.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, if you modify the
|
||||||
|
Program, your modified version must prominently offer all users
|
||||||
|
interacting with it remotely through a computer network (if your version
|
||||||
|
supports such interaction) an opportunity to receive the Corresponding
|
||||||
|
Source of your version by providing access to the Corresponding Source
|
||||||
|
from a network server at no charge, through some standard or customary
|
||||||
|
means of facilitating copying of software. This Corresponding Source
|
||||||
|
shall include the Corresponding Source for any work covered by version 3
|
||||||
|
of the GNU General Public License that is incorporated pursuant to the
|
||||||
|
following paragraph.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the work with which it is combined will remain governed by version
|
||||||
|
3 of the GNU General Public License.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU Affero General Public License from time to time. Such new versions
|
||||||
|
will be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU Affero General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU Affero General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU Affero General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
21
LICENSE_MIT
Normal file
21
LICENSE_MIT
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 Penumbra-Sync
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
@@ -12,6 +12,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||||||
.editorconfig = .editorconfig
|
.editorconfig = .editorconfig
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SnowcloakSync", "SnowcloakSync\SnowcloakSync.csproj", "{E633A968-2FB8-48FF-8136-5EBAEDF8E6F3}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -36,6 +38,14 @@ Global
|
|||||||
{5A0B7434-8D89-4E90-B55C-B4A7AE1A6ADE}.Release|Any CPU.Build.0 = Release|Any CPU
|
{5A0B7434-8D89-4E90-B55C-B4A7AE1A6ADE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{5A0B7434-8D89-4E90-B55C-B4A7AE1A6ADE}.Release|x64.ActiveCfg = Release|Any CPU
|
{5A0B7434-8D89-4E90-B55C-B4A7AE1A6ADE}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
{5A0B7434-8D89-4E90-B55C-B4A7AE1A6ADE}.Release|x64.Build.0 = Release|Any CPU
|
{5A0B7434-8D89-4E90-B55C-B4A7AE1A6ADE}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{E633A968-2FB8-48FF-8136-5EBAEDF8E6F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{E633A968-2FB8-48FF-8136-5EBAEDF8E6F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{E633A968-2FB8-48FF-8136-5EBAEDF8E6F3}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{E633A968-2FB8-48FF-8136-5EBAEDF8E6F3}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{E633A968-2FB8-48FF-8136-5EBAEDF8E6F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{E633A968-2FB8-48FF-8136-5EBAEDF8E6F3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{E633A968-2FB8-48FF-8136-5EBAEDF8E6F3}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{E633A968-2FB8-48FF-8136-5EBAEDF8E6F3}.Release|x64.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@@ -122,24 +122,24 @@ public sealed class CacheMonitor : DisposableMediatorSubscriberBase
|
|||||||
|
|
||||||
public bool StorageisNTFS { get; private set; } = false;
|
public bool StorageisNTFS { get; private set; } = false;
|
||||||
|
|
||||||
public void StartMareWatcher(string? marePath)
|
public void StartMareWatcher(string? snowPath)
|
||||||
{
|
{
|
||||||
MareWatcher?.Dispose();
|
MareWatcher?.Dispose();
|
||||||
if (string.IsNullOrEmpty(marePath) || !Directory.Exists(marePath))
|
if (string.IsNullOrEmpty(snowPath) || !Directory.Exists(snowPath))
|
||||||
{
|
{
|
||||||
MareWatcher = null;
|
MareWatcher = null;
|
||||||
Logger.LogWarning("Mare file path is not set, cannot start the FSW for Mare.");
|
Logger.LogWarning("Snowcloak file path is not set, cannot start the FSW for Snowcloak.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DriveInfo di = new(new DirectoryInfo(_configService.Current.CacheFolder).Root.FullName);
|
DriveInfo di = new(new DirectoryInfo(_configService.Current.CacheFolder).Root.FullName);
|
||||||
StorageisNTFS = string.Equals("NTFS", di.DriveFormat, StringComparison.OrdinalIgnoreCase);
|
StorageisNTFS = string.Equals("NTFS", di.DriveFormat, StringComparison.OrdinalIgnoreCase);
|
||||||
Logger.LogInformation("Mare Storage is on NTFS drive: {isNtfs}", StorageisNTFS);
|
Logger.LogInformation("Snowcloak Storage is on NTFS drive: {isNtfs}", StorageisNTFS);
|
||||||
|
|
||||||
Logger.LogDebug("Initializing Mare FSW on {path}", marePath);
|
Logger.LogDebug("Initializing Mare FSW on {path}", snowPath);
|
||||||
MareWatcher = new()
|
MareWatcher = new()
|
||||||
{
|
{
|
||||||
Path = marePath,
|
Path = snowPath,
|
||||||
InternalBufferSize = 8388608,
|
InternalBufferSize = 8388608,
|
||||||
NotifyFilter = NotifyFilters.CreationTime
|
NotifyFilter = NotifyFilters.CreationTime
|
||||||
| NotifyFilters.LastWrite
|
| NotifyFilters.LastWrite
|
||||||
@@ -161,7 +161,7 @@ public sealed class CacheMonitor : DisposableMediatorSubscriberBase
|
|||||||
if (string.IsNullOrEmpty(substPath))
|
if (string.IsNullOrEmpty(substPath))
|
||||||
{
|
{
|
||||||
SubstWatcher = null;
|
SubstWatcher = null;
|
||||||
Logger.LogWarning("Mare file path is not set, cannot start the FSW for Mare.");
|
Logger.LogWarning("Snowcloak file path is not set, cannot start the FSW for Snowcloak.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,7 +197,7 @@ public sealed class CacheMonitor : DisposableMediatorSubscriberBase
|
|||||||
|
|
||||||
private void MareWatcher_FileChanged(object sender, FileSystemEventArgs e)
|
private void MareWatcher_FileChanged(object sender, FileSystemEventArgs e)
|
||||||
{
|
{
|
||||||
Logger.LogTrace("Mare FSW: FileChanged: {change} => {path}", e.ChangeType, e.FullPath);
|
Logger.LogTrace("Snowcloak FSW: FileChanged: {change} => {path}", e.ChangeType, e.FullPath);
|
||||||
|
|
||||||
if (!AllowedFileExtensions.Any(ext => e.FullPath.EndsWith(ext, StringComparison.OrdinalIgnoreCase))) return;
|
if (!AllowedFileExtensions.Any(ext => e.FullPath.EndsWith(ext, StringComparison.OrdinalIgnoreCase))) return;
|
||||||
|
|
||||||
|
@@ -27,9 +27,9 @@ public sealed class IpcCallerMoodles : IIpcCaller
|
|||||||
|
|
||||||
_moodlesApiVersion = pi.GetIpcSubscriber<int>("Moodles.Version");
|
_moodlesApiVersion = pi.GetIpcSubscriber<int>("Moodles.Version");
|
||||||
_moodlesOnChange = pi.GetIpcSubscriber<IPlayerCharacter, object>("Moodles.StatusManagerModified");
|
_moodlesOnChange = pi.GetIpcSubscriber<IPlayerCharacter, object>("Moodles.StatusManagerModified");
|
||||||
_moodlesGetStatus = pi.GetIpcSubscriber<nint, string>("Moodles.GetStatusManagerByPtr");
|
_moodlesGetStatus = pi.GetIpcSubscriber<nint, string>("Moodles.GetStatusManagerByPtrV2");
|
||||||
_moodlesSetStatus = pi.GetIpcSubscriber<nint, string, object>("Moodles.SetStatusManagerByPtr");
|
_moodlesSetStatus = pi.GetIpcSubscriber<nint, string, object>("Moodles.SetStatusManagerByPtrV2");
|
||||||
_moodlesRevertStatus = pi.GetIpcSubscriber<nint, object>("Moodles.ClearStatusManagerByPtr");
|
_moodlesRevertStatus = pi.GetIpcSubscriber<nint, object>("Moodles.ClearStatusManagerByPtrV2");
|
||||||
|
|
||||||
_moodlesOnChange.Subscribe(OnMoodlesChange);
|
_moodlesOnChange.Subscribe(OnMoodlesChange);
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ public sealed class IpcCallerMoodles : IIpcCaller
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
APIAvailable = _moodlesApiVersion.InvokeFunc() == 1;
|
APIAvailable = _moodlesApiVersion.InvokeFunc() == 3;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@@ -114,7 +114,7 @@ public sealed class IpcCallerPenumbra : DisposableMediatorSubscriberBase, IIpcCa
|
|||||||
bool penumbraAvailable = false;
|
bool penumbraAvailable = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
penumbraAvailable = _pluginLoaded && _pluginVersion >= new Version(1, 0, 1, 0);
|
penumbraAvailable = _pluginLoaded && _pluginVersion >= new Version(1, 5, 1, 0);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
penumbraAvailable &= _penumbraEnabled.Invoke();
|
penumbraAvailable &= _penumbraEnabled.Invoke();
|
||||||
@@ -225,9 +225,15 @@ public sealed class IpcCallerPenumbra : DisposableMediatorSubscriberBase, IIpcCa
|
|||||||
|
|
||||||
return await _dalamudUtil.RunOnFrameworkThread(() =>
|
return await _dalamudUtil.RunOnFrameworkThread(() =>
|
||||||
{
|
{
|
||||||
|
Guid collId;
|
||||||
var collName = "ElfSync_" + uid;
|
var collName = "ElfSync_" + uid;
|
||||||
var collId = _penumbraCreateNamedTemporaryCollection.Invoke(collName);
|
PenumbraApiEc penEC = _penumbraCreateNamedTemporaryCollection.Invoke(uid, collName, out collId);
|
||||||
logger.LogTrace("Creating Temp Collection {collName}, GUID: {collId}", collName, collId);
|
logger.LogTrace("Creating Temp Collection {collName}, GUID: {collId}", collName, collId);
|
||||||
|
if (penEC != PenumbraApiEc.Success)
|
||||||
|
{
|
||||||
|
logger.LogError("Failed to create temporary collection for {collName} with error code {penEC}. Please include this line in any error reports", collName, penEC);
|
||||||
|
return Guid.Empty;
|
||||||
|
}
|
||||||
return collId;
|
return collId;
|
||||||
|
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
|
@@ -30,12 +30,12 @@ public sealed class IpcCallerPetNames : IIpcCaller
|
|||||||
_dalamudUtil = dalamudUtil;
|
_dalamudUtil = dalamudUtil;
|
||||||
_mareMediator = mareMediator;
|
_mareMediator = mareMediator;
|
||||||
|
|
||||||
_petnamesReady = pi.GetIpcSubscriber<object>("PetRenamer.Ready");
|
_petnamesReady = pi.GetIpcSubscriber<object>("PetRenamer.OnReady");
|
||||||
_petnamesDisposing = pi.GetIpcSubscriber<object>("PetRenamer.Disposing");
|
_petnamesDisposing = pi.GetIpcSubscriber<object>("PetRenamer.OnDisposing");
|
||||||
_apiVersion = pi.GetIpcSubscriber<(uint, uint)>("PetRenamer.ApiVersion");
|
_apiVersion = pi.GetIpcSubscriber<(uint, uint)>("PetRenamer.ApiVersion");
|
||||||
_enabled = pi.GetIpcSubscriber<bool>("PetRenamer.Enabled");
|
_enabled = pi.GetIpcSubscriber<bool>("PetRenamer.IsEnabled");
|
||||||
|
|
||||||
_playerDataChanged = pi.GetIpcSubscriber<string, object>("PetRenamer.PlayerDataChanged");
|
_playerDataChanged = pi.GetIpcSubscriber<string, object>("PetRenamer.OnPlayerDataChanged");
|
||||||
_getPlayerData = pi.GetIpcSubscriber<string>("PetRenamer.GetPlayerData");
|
_getPlayerData = pi.GetIpcSubscriber<string>("PetRenamer.GetPlayerData");
|
||||||
_setPlayerData = pi.GetIpcSubscriber<string, object>("PetRenamer.SetPlayerData");
|
_setPlayerData = pi.GetIpcSubscriber<string, object>("PetRenamer.SetPlayerData");
|
||||||
_clearPlayerData = pi.GetIpcSubscriber<ushort, object>("PetRenamer.ClearPlayerData");
|
_clearPlayerData = pi.GetIpcSubscriber<ushort, object>("PetRenamer.ClearPlayerData");
|
||||||
@@ -56,7 +56,7 @@ public sealed class IpcCallerPetNames : IIpcCaller
|
|||||||
APIAvailable = _enabled?.InvokeFunc() ?? false;
|
APIAvailable = _enabled?.InvokeFunc() ?? false;
|
||||||
if (APIAvailable)
|
if (APIAvailable)
|
||||||
{
|
{
|
||||||
APIAvailable = _apiVersion?.InvokeFunc() is { Item1: 3, Item2: >= 1 };
|
APIAvailable = _apiVersion?.InvokeFunc() is { Item1: 4, Item2: >= 0 };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
@@ -7,6 +7,9 @@ namespace MareSynchronos.MareConfiguration.Configurations;
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class MareConfig : IMareConfiguration
|
public class MareConfig : IMareConfiguration
|
||||||
{
|
{
|
||||||
|
public bool SortSyncshellsByVRAM { get; set; } = false;
|
||||||
|
public int ExpectedTOSVersion = 2;
|
||||||
|
public int AcceptedTOSVersion { get; set; } = 0;
|
||||||
public bool AcceptedAgreement { get; set; } = false;
|
public bool AcceptedAgreement { get; set; } = false;
|
||||||
public string CacheFolder { get; set; } = string.Empty;
|
public string CacheFolder { get; set; } = string.Empty;
|
||||||
public bool DisableOptionalPluginWarnings { get; set; } = false;
|
public bool DisableOptionalPluginWarnings { get; set; } = false;
|
||||||
|
@@ -7,9 +7,9 @@ public class PlayerPerformanceConfig : IMareConfiguration
|
|||||||
public int Version { get; set; } = 1;
|
public int Version { get; set; } = 1;
|
||||||
public bool AutoPausePlayersExceedingThresholds { get; set; } = true;
|
public bool AutoPausePlayersExceedingThresholds { get; set; } = true;
|
||||||
public bool NotifyAutoPauseDirectPairs { get; set; } = true;
|
public bool NotifyAutoPauseDirectPairs { get; set; } = true;
|
||||||
public bool NotifyAutoPauseGroupPairs { get; set; } = false;
|
public bool NotifyAutoPauseGroupPairs { get; set; } = true;
|
||||||
public int VRAMSizeAutoPauseThresholdMiB { get; set; } = 500;
|
public int VRAMSizeAutoPauseThresholdMiB { get; set; } = 500;
|
||||||
public int TrisAutoPauseThresholdThousands { get; set; } = 175;
|
public int TrisAutoPauseThresholdThousands { get; set; } = 400;
|
||||||
public bool IgnoreDirectPairs { get; set; } = true;
|
public bool IgnoreDirectPairs { get; set; } = true;
|
||||||
public TextureShrinkMode TextureShrinkMode { get; set; } = TextureShrinkMode.Default;
|
public TextureShrinkMode TextureShrinkMode { get; set; } = TextureShrinkMode.Default;
|
||||||
public bool TextureShrinkDeleteOriginal { get; set; } = false;
|
public bool TextureShrinkDeleteOriginal { get; set; } = false;
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project Sdk="Dalamud.NET.Sdk/13.0.0">
|
<Project Sdk="Dalamud.NET.Sdk/13.1.0">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AssemblyName>Snowcloak</AssemblyName>
|
<AssemblyName>Snowcloak</AssemblyName>
|
||||||
<Version>0.1.7</Version>
|
<Version>0.3.0</Version>
|
||||||
<PackageProjectUrl>https://github.com/Eauldane/SnowcloakClient/</PackageProjectUrl>
|
<PackageProjectUrl>https://git.snowcloak-sync.com/Eauldane/SnowcloakClient/</PackageProjectUrl>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -14,37 +14,27 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Chaos.NaCl.Standard" Version="1.0.0" />
|
<PackageReference Include="Chaos.NaCl.Standard" Version="1.0.0" />
|
||||||
<PackageReference Include="Downloader" Version="3.3.4" />
|
<PackageReference Include="Downloader" Version="4.0.3" />
|
||||||
|
<PackageReference Include="Glamourer.Api" Version="2.6.0" />
|
||||||
<PackageReference Include="K4os.Compression.LZ4.Legacy" Version="1.3.8" />
|
<PackageReference Include="K4os.Compression.LZ4.Legacy" Version="1.3.8" />
|
||||||
<PackageReference Include="K4os.Compression.LZ4.Streams" Version="1.3.8" />
|
<PackageReference Include="K4os.Compression.LZ4.Streams" Version="1.3.8" />
|
||||||
<PackageReference Include="Meziantou.Analyzer" Version="2.0.212">
|
<PackageReference Include="MessagePack" Version="3.1.4" />
|
||||||
|
<PackageReference Include="MessagePack.Annotations" Version="3.1.4" />
|
||||||
|
<PackageReference Include="Meziantou.Analyzer" Version="2.0.219">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.8" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.9" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="9.0.8" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="9.0.9" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.8" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.9" />
|
||||||
|
<PackageReference Include="Penumbra.Api" Version="5.12.0" />
|
||||||
<PackageReference Include="SonarAnalyzer.CSharp" Version="10.15.0.120848">
|
<PackageReference Include="SonarAnalyzer.CSharp" Version="10.15.0.120848">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.14.0" />
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.14.0" />
|
||||||
</ItemGroup>
|
<PackageReference Update="DalamudPackager" Version="13.1.0" />
|
||||||
|
<PackageReference Include="System.IO.Pipelines" Version="9.0.9" />
|
||||||
<ItemGroup Condition="Exists('.\Penumbra.Api\Penumbra.Api.csproj')">
|
|
||||||
<ProjectReference Include=".\Penumbra.Api\Penumbra.Api.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup Condition="!Exists('.\Penumbra.Api\Penumbra.Api.csproj')">
|
|
||||||
<PackageReference Include="Penumbra.Api" Version="5.10.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup Condition="Exists('.\Glamourer.Api\Glamourer.Api.csproj')">
|
|
||||||
<ProjectReference Include=".\Glamourer.Api\Glamourer.Api.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup Condition="!Exists('.\Glamourer.Api\Glamourer.Api.csproj')">
|
|
||||||
<PackageReference Include="Glamourer.Api" Version="2.6.0" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
@@ -54,6 +44,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\MareAPI\MareSynchronosAPI\MareSynchronos.API.csproj" />
|
<ProjectReference Include="..\MareAPI\MareSynchronosAPI\MareSynchronos.API.csproj" />
|
||||||
|
<ProjectReference Include="..\SnowcloakSync\SnowcloakSync.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@@ -27,14 +27,13 @@ public class PairHandlerFactory
|
|||||||
private readonly PluginWarningNotificationService _pluginWarningNotificationManager;
|
private readonly PluginWarningNotificationService _pluginWarningNotificationManager;
|
||||||
private readonly PairAnalyzerFactory _pairAnalyzerFactory;
|
private readonly PairAnalyzerFactory _pairAnalyzerFactory;
|
||||||
private readonly VisibilityService _visibilityService;
|
private readonly VisibilityService _visibilityService;
|
||||||
private readonly NoSnapService _noSnapService;
|
|
||||||
|
|
||||||
public PairHandlerFactory(ILoggerFactory loggerFactory, GameObjectHandlerFactory gameObjectHandlerFactory, IpcManager ipcManager,
|
public PairHandlerFactory(ILoggerFactory loggerFactory, GameObjectHandlerFactory gameObjectHandlerFactory, IpcManager ipcManager,
|
||||||
FileDownloadManagerFactory fileDownloadManagerFactory, DalamudUtilService dalamudUtilService,
|
FileDownloadManagerFactory fileDownloadManagerFactory, DalamudUtilService dalamudUtilService,
|
||||||
PluginWarningNotificationService pluginWarningNotificationManager, IHostApplicationLifetime hostApplicationLifetime,
|
PluginWarningNotificationService pluginWarningNotificationManager, IHostApplicationLifetime hostApplicationLifetime,
|
||||||
FileCacheManager fileCacheManager, MareMediator mareMediator, PlayerPerformanceService playerPerformanceService,
|
FileCacheManager fileCacheManager, MareMediator mareMediator, PlayerPerformanceService playerPerformanceService,
|
||||||
ServerConfigurationManager serverConfigManager, PairAnalyzerFactory pairAnalyzerFactory,
|
ServerConfigurationManager serverConfigManager, PairAnalyzerFactory pairAnalyzerFactory,
|
||||||
MareConfigService configService, VisibilityService visibilityService, NoSnapService noSnapService)
|
MareConfigService configService, VisibilityService visibilityService)
|
||||||
{
|
{
|
||||||
_loggerFactory = loggerFactory;
|
_loggerFactory = loggerFactory;
|
||||||
_gameObjectHandlerFactory = gameObjectHandlerFactory;
|
_gameObjectHandlerFactory = gameObjectHandlerFactory;
|
||||||
@@ -50,13 +49,12 @@ public class PairHandlerFactory
|
|||||||
_pairAnalyzerFactory = pairAnalyzerFactory;
|
_pairAnalyzerFactory = pairAnalyzerFactory;
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
_visibilityService = visibilityService;
|
_visibilityService = visibilityService;
|
||||||
_noSnapService = noSnapService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public PairHandler Create(Pair pair)
|
public PairHandler Create(Pair pair)
|
||||||
{
|
{
|
||||||
return new PairHandler(_loggerFactory.CreateLogger<PairHandler>(), pair, _pairAnalyzerFactory.Create(pair), _gameObjectHandlerFactory,
|
return new PairHandler(_loggerFactory.CreateLogger<PairHandler>(), pair, _pairAnalyzerFactory.Create(pair), _gameObjectHandlerFactory,
|
||||||
_ipcManager, _fileDownloadManagerFactory.Create(), _pluginWarningNotificationManager, _dalamudUtilService, _hostApplicationLifetime,
|
_ipcManager, _fileDownloadManagerFactory.Create(), _pluginWarningNotificationManager, _dalamudUtilService, _hostApplicationLifetime,
|
||||||
_fileCacheManager, _mareMediator, _playerPerformanceService, _serverConfigManager, _configService, _visibilityService, _noSnapService);
|
_fileCacheManager, _mareMediator, _playerPerformanceService, _serverConfigManager, _configService, _visibilityService);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -32,7 +32,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
private readonly ServerConfigurationManager _serverConfigManager;
|
private readonly ServerConfigurationManager _serverConfigManager;
|
||||||
private readonly PluginWarningNotificationService _pluginWarningNotificationManager;
|
private readonly PluginWarningNotificationService _pluginWarningNotificationManager;
|
||||||
private readonly VisibilityService _visibilityService;
|
private readonly VisibilityService _visibilityService;
|
||||||
private readonly NoSnapService _noSnapService;
|
|
||||||
private CancellationTokenSource? _applicationCancellationTokenSource = new();
|
private CancellationTokenSource? _applicationCancellationTokenSource = new();
|
||||||
private Guid _applicationId;
|
private Guid _applicationId;
|
||||||
private Task? _applicationTask;
|
private Task? _applicationTask;
|
||||||
@@ -55,8 +54,7 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
FileCacheManager fileDbManager, MareMediator mediator,
|
FileCacheManager fileDbManager, MareMediator mediator,
|
||||||
PlayerPerformanceService playerPerformanceService,
|
PlayerPerformanceService playerPerformanceService,
|
||||||
ServerConfigurationManager serverConfigManager,
|
ServerConfigurationManager serverConfigManager,
|
||||||
MareConfigService configService, VisibilityService visibilityService,
|
MareConfigService configService, VisibilityService visibilityService) : base(logger, mediator)
|
||||||
NoSnapService noSnapService) : base(logger, mediator)
|
|
||||||
{
|
{
|
||||||
Pair = pair;
|
Pair = pair;
|
||||||
PairAnalyzer = pairAnalyzer;
|
PairAnalyzer = pairAnalyzer;
|
||||||
@@ -70,7 +68,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
_serverConfigManager = serverConfigManager;
|
_serverConfigManager = serverConfigManager;
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
_visibilityService = visibilityService;
|
_visibilityService = visibilityService;
|
||||||
_noSnapService = noSnapService;
|
|
||||||
|
|
||||||
_visibilityService.StartTracking(Pair.Ident);
|
_visibilityService.StartTracking(Pair.Ident);
|
||||||
|
|
||||||
@@ -319,24 +316,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RegisterGposeClones()
|
|
||||||
{
|
|
||||||
var name = PlayerName;
|
|
||||||
if (name == null)
|
|
||||||
return;
|
|
||||||
_ = _dalamudUtil.RunOnFrameworkThread(() =>
|
|
||||||
{
|
|
||||||
foreach (var actor in _dalamudUtil.GetGposeCharactersFromObjectTable())
|
|
||||||
{
|
|
||||||
if (actor == null) continue;
|
|
||||||
var gposeName = actor.Name.TextValue;
|
|
||||||
if (!name.Equals(gposeName, StringComparison.Ordinal))
|
|
||||||
continue;
|
|
||||||
_noSnapService.AddGposer(actor.ObjectIndex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task UndoApplicationAsync(Guid applicationId = default)
|
private async Task UndoApplicationAsync(Guid applicationId = default)
|
||||||
{
|
{
|
||||||
Logger.LogDebug($"Undoing application of {Pair.UserPair}");
|
Logger.LogDebug($"Undoing application of {Pair.UserPair}");
|
||||||
@@ -353,7 +332,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
await _ipcManager.Penumbra.RemoveTemporaryCollectionAsync(Logger, applicationId, _penumbraCollection).ConfigureAwait(false);
|
await _ipcManager.Penumbra.RemoveTemporaryCollectionAsync(Logger, applicationId, _penumbraCollection).ConfigureAwait(false);
|
||||||
_penumbraCollection = Guid.Empty;
|
_penumbraCollection = Guid.Empty;
|
||||||
RegisterGposeClones();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_dalamudUtil is { IsZoning: false, IsInCutscene: false } && !string.IsNullOrEmpty(name))
|
if (_dalamudUtil is { IsZoning: false, IsInCutscene: false } && !string.IsNullOrEmpty(name))
|
||||||
@@ -385,10 +363,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (_dalamudUtil.IsInCutscene && !string.IsNullOrEmpty(name))
|
|
||||||
{
|
|
||||||
_noSnapService.AddGposerNamed(name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@@ -86,8 +86,8 @@ public class Pair : DisposableMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
Name = name,
|
Name = name,
|
||||||
OnClicked = action,
|
OnClicked = action,
|
||||||
PrefixColor = 559,
|
PrefixColor = 526,
|
||||||
PrefixChar = 'L'
|
PrefixChar = 'S'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,11 +171,6 @@ public class Pair : DisposableMediatorSubscriberBase
|
|||||||
if (_serverConfigurationManager.IsUidBlacklisted(UserData.UID))
|
if (_serverConfigurationManager.IsUidBlacklisted(UserData.UID))
|
||||||
HoldApplication("Blacklist", maxValue: 1);
|
HoldApplication("Blacklist", maxValue: 1);
|
||||||
|
|
||||||
if (NoSnapService.AnyLoaded)
|
|
||||||
HoldApplication("NoSnap", maxValue: 1);
|
|
||||||
else
|
|
||||||
UnholdApplication("NoSnap", skipApplication: true);
|
|
||||||
|
|
||||||
CachedPlayer.ApplyCharacterData(Guid.NewGuid(), RemoveNotSyncedFiles(LastReceivedCharacterData.DeepClone())!, forced);
|
CachedPlayer.ApplyCharacterData(Guid.NewGuid(), RemoveNotSyncedFiles(LastReceivedCharacterData.DeepClone())!, forced);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,11 +235,17 @@ public class Pair : DisposableMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
string? noteOrName = GetNoteOrName();
|
string? noteOrName = GetNoteOrName();
|
||||||
|
|
||||||
if (noteOrName != null)
|
if (_mareConfig.Current.SortSyncshellsByVRAM)
|
||||||
|
{
|
||||||
|
return($"0{LastAppliedApproximateVRAMBytes}");
|
||||||
|
}
|
||||||
|
else if (noteOrName != null) {
|
||||||
return $"0{noteOrName}";
|
return $"0{noteOrName}";
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
return $"9{UserData.AliasOrUID}";
|
return $"9{UserData.AliasOrUID}";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public string GetPlayerNameHash()
|
public string GetPlayerNameHash()
|
||||||
{
|
{
|
||||||
@@ -331,6 +332,11 @@ public class Pair : DisposableMediatorSubscriberBase
|
|||||||
_logger.LogTrace("Nothing to remove");
|
_logger.LogTrace("Nothing to remove");
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
if (IsPaused)
|
||||||
|
{
|
||||||
|
_logger.LogTrace("Skipping data removal for paused user {uid}", UserData.UID);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
var ActiveGroupPairs = GroupPair.Where(p => !p.Value.GroupUserPermissions.IsPaused() && !p.Key.GroupUserPermissions.IsPaused()).ToList();
|
var ActiveGroupPairs = GroupPair.Where(p => !p.Value.GroupUserPermissions.IsPaused() && !p.Key.GroupUserPermissions.IsPaused()).ToList();
|
||||||
|
|
||||||
|
@@ -142,7 +142,6 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
collection.AddSingleton<IpcCallerMare>();
|
collection.AddSingleton<IpcCallerMare>();
|
||||||
collection.AddSingleton<IpcManager>();
|
collection.AddSingleton<IpcManager>();
|
||||||
collection.AddSingleton<NotificationService>();
|
collection.AddSingleton<NotificationService>();
|
||||||
collection.AddSingleton<NoSnapService>();
|
|
||||||
|
|
||||||
collection.AddSingleton((s) => new MareConfigService(pluginInterface.ConfigDirectory.FullName));
|
collection.AddSingleton((s) => new MareConfigService(pluginInterface.ConfigDirectory.FullName));
|
||||||
collection.AddSingleton((s) => new ServerConfigService(pluginInterface.ConfigDirectory.FullName));
|
collection.AddSingleton((s) => new ServerConfigService(pluginInterface.ConfigDirectory.FullName));
|
||||||
@@ -168,7 +167,6 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
collection.AddSingleton<IConfigService<IMareConfiguration>>(s => s.GetRequiredService<RemoteConfigCacheService>());
|
collection.AddSingleton<IConfigService<IMareConfiguration>>(s => s.GetRequiredService<RemoteConfigCacheService>());
|
||||||
collection.AddSingleton<ConfigurationMigrator>();
|
collection.AddSingleton<ConfigurationMigrator>();
|
||||||
collection.AddSingleton<ConfigurationSaveService>();
|
collection.AddSingleton<ConfigurationSaveService>();
|
||||||
collection.AddSingleton<RemoteConfigurationService>();
|
|
||||||
|
|
||||||
collection.AddSingleton<HubFactory>();
|
collection.AddSingleton<HubFactory>();
|
||||||
|
|
||||||
@@ -209,7 +207,6 @@ public sealed class Plugin : IDalamudPlugin
|
|||||||
collection.AddHostedService(p => p.GetRequiredService<EventAggregator>());
|
collection.AddHostedService(p => p.GetRequiredService<EventAggregator>());
|
||||||
collection.AddHostedService(p => p.GetRequiredService<MarePlugin>());
|
collection.AddHostedService(p => p.GetRequiredService<MarePlugin>());
|
||||||
collection.AddHostedService(p => p.GetRequiredService<IpcProvider>());
|
collection.AddHostedService(p => p.GetRequiredService<IpcProvider>());
|
||||||
collection.AddHostedService(p => p.GetRequiredService<NoSnapService>());
|
|
||||||
})
|
})
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
@@ -13,20 +13,18 @@ public sealed class CharaDataCharacterHandler : DisposableMediatorSubscriberBase
|
|||||||
private readonly GameObjectHandlerFactory _gameObjectHandlerFactory;
|
private readonly GameObjectHandlerFactory _gameObjectHandlerFactory;
|
||||||
private readonly DalamudUtilService _dalamudUtilService;
|
private readonly DalamudUtilService _dalamudUtilService;
|
||||||
private readonly IpcManager _ipcManager;
|
private readonly IpcManager _ipcManager;
|
||||||
private readonly NoSnapService _noSnapService;
|
|
||||||
private readonly Dictionary<string, HandledCharaDataEntry> _handledCharaData = new(StringComparer.Ordinal);
|
private readonly Dictionary<string, HandledCharaDataEntry> _handledCharaData = new(StringComparer.Ordinal);
|
||||||
|
|
||||||
public IReadOnlyDictionary<string, HandledCharaDataEntry> HandledCharaData => _handledCharaData;
|
public IReadOnlyDictionary<string, HandledCharaDataEntry> HandledCharaData => _handledCharaData;
|
||||||
|
|
||||||
public CharaDataCharacterHandler(ILogger<CharaDataCharacterHandler> logger, MareMediator mediator,
|
public CharaDataCharacterHandler(ILogger<CharaDataCharacterHandler> logger, MareMediator mediator,
|
||||||
GameObjectHandlerFactory gameObjectHandlerFactory, DalamudUtilService dalamudUtilService,
|
GameObjectHandlerFactory gameObjectHandlerFactory, DalamudUtilService dalamudUtilService,
|
||||||
IpcManager ipcManager, NoSnapService noSnapService)
|
IpcManager ipcManager)
|
||||||
: base(logger, mediator)
|
: base(logger, mediator)
|
||||||
{
|
{
|
||||||
_gameObjectHandlerFactory = gameObjectHandlerFactory;
|
_gameObjectHandlerFactory = gameObjectHandlerFactory;
|
||||||
_dalamudUtilService = dalamudUtilService;
|
_dalamudUtilService = dalamudUtilService;
|
||||||
_ipcManager = ipcManager;
|
_ipcManager = ipcManager;
|
||||||
_noSnapService = noSnapService;
|
|
||||||
mediator.Subscribe<GposeEndMessage>(this, msg =>
|
mediator.Subscribe<GposeEndMessage>(this, msg =>
|
||||||
{
|
{
|
||||||
foreach (var chara in _handledCharaData)
|
foreach (var chara in _handledCharaData)
|
||||||
@@ -94,7 +92,6 @@ public sealed class CharaDataCharacterHandler : DisposableMediatorSubscriberBase
|
|||||||
_handledCharaData.Remove(handled.Name);
|
_handledCharaData.Remove(handled.Name);
|
||||||
await _dalamudUtilService.RunOnFrameworkThread(async () =>
|
await _dalamudUtilService.RunOnFrameworkThread(async () =>
|
||||||
{
|
{
|
||||||
RemoveGposer(handled);
|
|
||||||
await RevertChara(handled.Name, handled.CustomizePlus).ConfigureAwait(false);
|
await RevertChara(handled.Name, handled.CustomizePlus).ConfigureAwait(false);
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
return true;
|
return true;
|
||||||
@@ -103,7 +100,6 @@ public sealed class CharaDataCharacterHandler : DisposableMediatorSubscriberBase
|
|||||||
internal void AddHandledChara(HandledCharaDataEntry handledCharaDataEntry)
|
internal void AddHandledChara(HandledCharaDataEntry handledCharaDataEntry)
|
||||||
{
|
{
|
||||||
_handledCharaData.Add(handledCharaDataEntry.Name, handledCharaDataEntry);
|
_handledCharaData.Add(handledCharaDataEntry.Name, handledCharaDataEntry);
|
||||||
_ = _dalamudUtilService.RunOnFrameworkThread(() => AddGposer(handledCharaDataEntry));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateHandledData(Dictionary<string, CharaDataMetaInfoExtendedDto?> newData)
|
public void UpdateHandledData(Dictionary<string, CharaDataMetaInfoExtendedDto?> newData)
|
||||||
@@ -134,23 +130,4 @@ public sealed class CharaDataCharacterHandler : DisposableMediatorSubscriberBase
|
|||||||
if (handler.Address == nint.Zero) return null;
|
if (handler.Address == nint.Zero) return null;
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetGposerObjectIndex(string name)
|
|
||||||
{
|
|
||||||
return _dalamudUtilService.GetGposeCharacterFromObjectTableByName(name, _dalamudUtilService.IsInGpose)?.ObjectIndex ?? -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddGposer(HandledCharaDataEntry handled)
|
|
||||||
{
|
|
||||||
int objectIndex = GetGposerObjectIndex(handled.Name);
|
|
||||||
if (objectIndex > 0)
|
|
||||||
_noSnapService.AddGposer(objectIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RemoveGposer(HandledCharaDataEntry handled)
|
|
||||||
{
|
|
||||||
int objectIndex = GetGposerObjectIndex(handled.Name);
|
|
||||||
if (objectIndex > 0)
|
|
||||||
_noSnapService.RemoveGposer(objectIndex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -72,7 +72,7 @@ public class ChatService : DisposableMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
var chatMsg = message.ChatMsg;
|
var chatMsg = message.ChatMsg;
|
||||||
var prefix = new SeStringBuilder();
|
var prefix = new SeStringBuilder();
|
||||||
prefix.AddText("[BnnuyChat] ");
|
prefix.AddText("[SnowChat] ");
|
||||||
_chatGui.Print(new XivChatEntry{
|
_chatGui.Print(new XivChatEntry{
|
||||||
MessageBytes = [..prefix.Build().Encode(), ..message.ChatMsg.PayloadContent],
|
MessageBytes = [..prefix.Build().Encode(), ..message.ChatMsg.PayloadContent],
|
||||||
Name = chatMsg.SenderName,
|
Name = chatMsg.SenderName,
|
||||||
|
@@ -14,8 +14,9 @@ namespace MareSynchronos.Services;
|
|||||||
|
|
||||||
public sealed class CommandManagerService : IDisposable
|
public sealed class CommandManagerService : IDisposable
|
||||||
{
|
{
|
||||||
private const string _commandName = "/sync";
|
private const string _commandName = "/snow";
|
||||||
private const string _commandName2 = "/snowcloak";
|
private const string _commandName2 = "/snowcloak";
|
||||||
|
private const string _commandName3 = "/sync";
|
||||||
|
|
||||||
private const string _ssCommandPrefix = "/ss";
|
private const string _ssCommandPrefix = "/ss";
|
||||||
|
|
||||||
@@ -48,6 +49,10 @@ public sealed class CommandManagerService : IDisposable
|
|||||||
{
|
{
|
||||||
HelpMessage = "Opens the Snowcloak UI"
|
HelpMessage = "Opens the Snowcloak UI"
|
||||||
});
|
});
|
||||||
|
_commandManager.AddHandler(_commandName3, new CommandInfo(OnCommand)
|
||||||
|
{
|
||||||
|
HelpMessage = "Opens the Snowcloak UI"
|
||||||
|
});
|
||||||
|
|
||||||
// Lazy registration of all possible /ss# commands which tbf is what the game does for linkshells anyway
|
// Lazy registration of all possible /ss# commands which tbf is what the game does for linkshells anyway
|
||||||
for (int i = 1; i <= ChatService.CommandMaxNumber; ++i)
|
for (int i = 1; i <= ChatService.CommandMaxNumber; ++i)
|
||||||
|
@@ -1,226 +0,0 @@
|
|||||||
using Dalamud.Plugin;
|
|
||||||
using MareSynchronos.Interop.Ipc;
|
|
||||||
using MareSynchronos.MareConfiguration.Models;
|
|
||||||
using MareSynchronos.Services.Mediator;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace MareSynchronos.Services;
|
|
||||||
|
|
||||||
public sealed class NoSnapService : IHostedService, IMediatorSubscriber
|
|
||||||
{
|
|
||||||
private record NoSnapConfig
|
|
||||||
{
|
|
||||||
[JsonPropertyName("listOfPlugins")]
|
|
||||||
public string[]? ListOfPlugins { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly ILogger<NoSnapService> _logger;
|
|
||||||
private readonly IDalamudPluginInterface _pluginInterface;
|
|
||||||
private readonly Dictionary<string, bool> _listOfPlugins = new(StringComparer.Ordinal)
|
|
||||||
{
|
|
||||||
["Snapper"] = false,
|
|
||||||
["Snappy"] = false,
|
|
||||||
["Meddle.Plugin"] = false,
|
|
||||||
};
|
|
||||||
private static readonly HashSet<int> _gposers = new();
|
|
||||||
private static readonly HashSet<string> _gposersNamed = new(StringComparer.Ordinal);
|
|
||||||
private readonly IHostApplicationLifetime _hostApplicationLifetime;
|
|
||||||
private readonly DalamudUtilService _dalamudUtilService;
|
|
||||||
private readonly IpcManager _ipcManager;
|
|
||||||
private readonly RemoteConfigurationService _remoteConfig;
|
|
||||||
|
|
||||||
public static bool AnyLoaded { get; private set; } = false;
|
|
||||||
public static string ActivePlugins { get; private set; } = string.Empty;
|
|
||||||
|
|
||||||
public MareMediator Mediator { get; init; }
|
|
||||||
|
|
||||||
public NoSnapService(ILogger<NoSnapService> logger, IDalamudPluginInterface pluginInterface, MareMediator mediator,
|
|
||||||
IHostApplicationLifetime hostApplicationLifetime, DalamudUtilService dalamudUtilService, IpcManager ipcManager,
|
|
||||||
RemoteConfigurationService remoteConfig)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
_pluginInterface = pluginInterface;
|
|
||||||
Mediator = mediator;
|
|
||||||
_hostApplicationLifetime = hostApplicationLifetime;
|
|
||||||
_dalamudUtilService = dalamudUtilService;
|
|
||||||
_ipcManager = ipcManager;
|
|
||||||
_remoteConfig = remoteConfig;
|
|
||||||
|
|
||||||
Mediator.Subscribe<GposeEndMessage>(this, msg => ClearGposeList());
|
|
||||||
Mediator.Subscribe<CutsceneEndMessage>(this, msg => ClearGposeList());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddGposer(int objectIndex)
|
|
||||||
{
|
|
||||||
if (AnyLoaded || _hostApplicationLifetime.ApplicationStopping.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
_logger.LogTrace("Immediately reverting object index {id}", objectIndex);
|
|
||||||
RevertAndRedraw(objectIndex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogTrace("Registering gposer object index {id}", objectIndex);
|
|
||||||
lock (_gposers)
|
|
||||||
_gposers.Add(objectIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveGposer(int objectIndex)
|
|
||||||
{
|
|
||||||
_logger.LogTrace("Un-registering gposer object index {id}", objectIndex);
|
|
||||||
lock (_gposers)
|
|
||||||
_gposers.Remove(objectIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddGposerNamed(string name)
|
|
||||||
{
|
|
||||||
if (AnyLoaded || _hostApplicationLifetime.ApplicationStopping.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
_logger.LogTrace("Immediately reverting {name}", name);
|
|
||||||
RevertAndRedraw(name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.LogTrace("Registering gposer {name}", name);
|
|
||||||
lock (_gposers)
|
|
||||||
_gposersNamed.Add(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ClearGposeList()
|
|
||||||
{
|
|
||||||
if (_gposers.Count > 0 || _gposersNamed.Count > 0)
|
|
||||||
_logger.LogTrace("Clearing gposer list");
|
|
||||||
lock (_gposers)
|
|
||||||
_gposers.Clear();
|
|
||||||
lock (_gposersNamed)
|
|
||||||
_gposersNamed.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RevertAndRedraw(int objIndex, Guid applicationId = default)
|
|
||||||
{
|
|
||||||
if (applicationId == default)
|
|
||||||
applicationId = Guid.NewGuid();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_ipcManager.Glamourer.RevertNow(_logger, applicationId, objIndex);
|
|
||||||
_ipcManager.Penumbra.RedrawNow(_logger, applicationId, objIndex);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RevertAndRedraw(string name, Guid applicationId = default)
|
|
||||||
{
|
|
||||||
if (applicationId == default)
|
|
||||||
applicationId = Guid.NewGuid();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_ipcManager.Glamourer.RevertByNameNow(_logger, applicationId, name);
|
|
||||||
var addr = _dalamudUtilService.GetPlayerCharacterFromCachedTableByName(name);
|
|
||||||
if (addr != 0)
|
|
||||||
{
|
|
||||||
var obj = _dalamudUtilService.CreateGameObject(addr);
|
|
||||||
if (obj != null)
|
|
||||||
_ipcManager.Penumbra.RedrawNow(_logger, applicationId, obj.ObjectIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RevertGposers()
|
|
||||||
{
|
|
||||||
List<int>? gposersList = null;
|
|
||||||
List<string>? gposersList2 = null;
|
|
||||||
|
|
||||||
lock (_gposers)
|
|
||||||
{
|
|
||||||
if (_gposers.Count > 0)
|
|
||||||
{
|
|
||||||
gposersList = _gposers.ToList();
|
|
||||||
_gposers.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (_gposersNamed)
|
|
||||||
{
|
|
||||||
if (_gposersNamed.Count > 0)
|
|
||||||
{
|
|
||||||
gposersList2 = _gposersNamed.ToList();
|
|
||||||
_gposersNamed.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gposersList == null && gposersList2 == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_logger.LogInformation("Reverting gposers");
|
|
||||||
|
|
||||||
_dalamudUtilService.RunOnFrameworkThread(() =>
|
|
||||||
{
|
|
||||||
Guid applicationId = Guid.NewGuid();
|
|
||||||
|
|
||||||
foreach (var gposer in gposersList ?? [])
|
|
||||||
RevertAndRedraw(gposer, applicationId);
|
|
||||||
|
|
||||||
foreach (var gposerName in gposersList2 ?? [])
|
|
||||||
RevertAndRedraw(gposerName, applicationId);
|
|
||||||
}).GetAwaiter().GetResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task StartAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var config = await _remoteConfig.GetConfigAsync<NoSnapConfig>("noSnap").ConfigureAwait(false) ?? new();
|
|
||||||
|
|
||||||
if (config.ListOfPlugins != null)
|
|
||||||
{
|
|
||||||
_listOfPlugins.Clear();
|
|
||||||
foreach (var pluginName in config.ListOfPlugins)
|
|
||||||
_listOfPlugins.TryAdd(pluginName, value: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var pluginName in _listOfPlugins.Keys)
|
|
||||||
{
|
|
||||||
_listOfPlugins[pluginName] = PluginWatcherService.GetInitialPluginState(_pluginInterface, pluginName)?.IsLoaded ?? false;
|
|
||||||
Mediator.SubscribeKeyed<PluginChangeMessage>(this, pluginName, (msg) =>
|
|
||||||
{
|
|
||||||
_listOfPlugins[pluginName] = msg.IsLoaded;
|
|
||||||
_logger.LogDebug("{pluginName} isLoaded = {isLoaded}", pluginName, msg.IsLoaded);
|
|
||||||
Update();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Update();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
RevertGposers();
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Update()
|
|
||||||
{
|
|
||||||
bool anyLoadedNow = _listOfPlugins.Values.Any(p => p);
|
|
||||||
|
|
||||||
if (AnyLoaded != anyLoadedNow)
|
|
||||||
{
|
|
||||||
AnyLoaded = anyLoadedNow;
|
|
||||||
Mediator.Publish(new RecalculatePerformanceMessage(null));
|
|
||||||
|
|
||||||
if (AnyLoaded)
|
|
||||||
{
|
|
||||||
RevertGposers();
|
|
||||||
var pluginList = string.Join(", ", _listOfPlugins.Where(p => p.Value).Select(p => p.Key));
|
|
||||||
Mediator.Publish(new NotificationMessage("Incompatible plugin loaded", $"Synced player appearances will not apply until incompatible plugins are disabled: {pluginList}.",
|
|
||||||
NotificationType.Error));
|
|
||||||
ActivePlugins = pluginList;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ActivePlugins = string.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,83 +0,0 @@
|
|||||||
using Chaos.NaCl;
|
|
||||||
using MareSynchronos.MareConfiguration;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using System.Net;
|
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Text.Json.Nodes;
|
|
||||||
|
|
||||||
namespace MareSynchronos.Services;
|
|
||||||
|
|
||||||
public sealed class RemoteConfigurationService
|
|
||||||
{
|
|
||||||
// private readonly static Dictionary<string, string> ConfigPublicKeys = new(StringComparer.Ordinal)
|
|
||||||
// {
|
|
||||||
// { "", "" },
|
|
||||||
// };
|
|
||||||
|
|
||||||
private readonly static string[] ConfigSources = [
|
|
||||||
"https://snowcloak-sync.com/config.json",
|
|
||||||
];
|
|
||||||
|
|
||||||
private readonly ILogger<RemoteConfigurationService> _logger;
|
|
||||||
private readonly RemoteConfigCacheService _configService;
|
|
||||||
private readonly Task _initTask;
|
|
||||||
|
|
||||||
public RemoteConfigurationService(ILogger<RemoteConfigurationService> logger, RemoteConfigCacheService configService)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
_configService = configService;
|
|
||||||
_initTask = Task.Run(DownloadConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<JsonObject> GetConfigAsync(string sectionName)
|
|
||||||
{
|
|
||||||
await _initTask.ConfigureAwait(false);
|
|
||||||
if (!_configService.Current.Configuration.TryGetPropertyValue(sectionName, out var section))
|
|
||||||
section = null;
|
|
||||||
return (section as JsonObject) ?? new();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<T?> GetConfigAsync<T>(string sectionName)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var json = await GetConfigAsync(sectionName).ConfigureAwait(false);
|
|
||||||
return JsonSerializer.Deserialize<T>(json);
|
|
||||||
}
|
|
||||||
catch (JsonException ex)
|
|
||||||
{
|
|
||||||
_logger.LogWarning(ex, "Invalid JSON in remote config: {sectionName}", sectionName);
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task DownloadConfig()
|
|
||||||
{
|
|
||||||
// Removed Lop's remote config code. Function exists purely to keep things clean.
|
|
||||||
LoadConfig();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool VerifySignature(string message, ulong ts, string signature, string pubKey)
|
|
||||||
{
|
|
||||||
byte[] msg = [.. BitConverter.GetBytes(ts), .. Encoding.UTF8.GetBytes(message)];
|
|
||||||
byte[] sig = Convert.FromBase64String(signature);
|
|
||||||
byte[] pub = Convert.FromBase64String(pubKey);
|
|
||||||
return Ed25519.Verify(sig, msg, pub);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LoadConfig()
|
|
||||||
{
|
|
||||||
ulong ts = 1755859494;
|
|
||||||
|
|
||||||
var configString = "{\"mainServer\":{\"api_url\":\"wss://hub.snowcloak-sync.com/\",\"hub_url\":\"wss://hub.snowcloak-sync.com/mare\"},\"noSnap\":{\"listOfPlugins\":[\"Snapper\",\"Snappy\",\"Meddle.Plugin\"]}}";
|
|
||||||
|
|
||||||
|
|
||||||
_configService.Current.Configuration = JsonNode.Parse(configString)!.AsObject();
|
|
||||||
_configService.Current.Timestamp = ts;
|
|
||||||
_configService.Save();
|
|
||||||
}
|
|
||||||
}
|
|
@@ -8,7 +8,7 @@
|
|||||||
"Tags": [
|
"Tags": [
|
||||||
"customization"
|
"customization"
|
||||||
],
|
],
|
||||||
"IconUrl": "https://i.imgur.com/cMKeOjm.jpeg",
|
"IconUrl": "https://raw.githubusercontent.com/Eauldane/SnowcloakClient/refs/heads/main/MareSynchronos/images/logo.png",
|
||||||
"RepoUrl": "https://github.com/Eauldane/SnowcloakClient",
|
"RepoUrl": "https://git.snowcloak-sync.com/Eauldane/SnowcloakClient",
|
||||||
"CanUnloadAsync": true
|
"CanUnloadAsync": true
|
||||||
}
|
}
|
||||||
|
@@ -1054,7 +1054,7 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase
|
|||||||
_configService.Current.OpenMareHubOnGposeStart = openInGpose;
|
_configService.Current.OpenMareHubOnGposeStart = openInGpose;
|
||||||
_configService.Save();
|
_configService.Save();
|
||||||
}
|
}
|
||||||
_uiSharedService.DrawHelpText("This will automatically open the import menu when loading into Gpose. If unchecked you can open the menu manually with /sync gpose");
|
_uiSharedService.DrawHelpText("This will automatically open the import menu when loading into Gpose. If unchecked you can open the menu manually with /snow gpose");
|
||||||
bool downloadDataOnConnection = _configService.Current.DownloadMcdDataOnConnection;
|
bool downloadDataOnConnection = _configService.Current.DownloadMcdDataOnConnection;
|
||||||
if (ImGui.Checkbox("Download Online Character Data on connecting", ref downloadDataOnConnection))
|
if (ImGui.Checkbox("Download Online Character Data on connecting", ref downloadDataOnConnection))
|
||||||
{
|
{
|
||||||
|
@@ -10,6 +10,7 @@ using MareSynchronos.MareConfiguration;
|
|||||||
using MareSynchronos.PlayerData.Handlers;
|
using MareSynchronos.PlayerData.Handlers;
|
||||||
using MareSynchronos.PlayerData.Pairs;
|
using MareSynchronos.PlayerData.Pairs;
|
||||||
using MareSynchronos.Services;
|
using MareSynchronos.Services;
|
||||||
|
using MareSynchronos.Services.CharaData;
|
||||||
using MareSynchronos.Services.Mediator;
|
using MareSynchronos.Services.Mediator;
|
||||||
using MareSynchronos.Services.ServerConfiguration;
|
using MareSynchronos.Services.ServerConfiguration;
|
||||||
using MareSynchronos.UI.Components;
|
using MareSynchronos.UI.Components;
|
||||||
@@ -24,11 +25,24 @@ using System.Diagnostics;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using MareSynchronos.API.Dto.Account;
|
||||||
|
using MareSynchronos.MareConfiguration.Models;
|
||||||
|
|
||||||
namespace MareSynchronos.UI;
|
namespace MareSynchronos.UI;
|
||||||
|
|
||||||
public class CompactUi : WindowMediatorSubscriberBase
|
public class CompactUi : WindowMediatorSubscriberBase
|
||||||
{
|
{
|
||||||
|
// selected menu for states
|
||||||
|
private enum Menu
|
||||||
|
{
|
||||||
|
IndividualPairs,
|
||||||
|
Syncshells
|
||||||
|
}
|
||||||
|
|
||||||
|
// currebnt selected tab and sidebar state
|
||||||
|
private Menu _selectedMenu = Menu.IndividualPairs;
|
||||||
|
private bool _sidebarCollapsed = false;
|
||||||
|
|
||||||
public float TransferPartHeight;
|
public float TransferPartHeight;
|
||||||
public float WindowContentWidth;
|
public float WindowContentWidth;
|
||||||
private readonly ApiController _apiController;
|
private readonly ApiController _apiController;
|
||||||
@@ -54,12 +68,19 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
private string _pairToAdd = string.Empty;
|
private string _pairToAdd = string.Empty;
|
||||||
private int _secretKeyIdx = -1;
|
private int _secretKeyIdx = -1;
|
||||||
private bool _showModalForUserAddition;
|
private bool _showModalForUserAddition;
|
||||||
private bool _showSyncShells;
|
|
||||||
private bool _wasOpen;
|
private bool _wasOpen;
|
||||||
|
private bool _registrationInProgress = false;
|
||||||
|
private bool _registrationSuccess = false;
|
||||||
|
private string? _registrationMessage;
|
||||||
|
private RegisterReplyDto? _registrationReply;
|
||||||
|
private readonly AccountRegistrationService _registerService;
|
||||||
|
private string _secretKey = string.Empty;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public CompactUi(ILogger<CompactUi> logger, UiSharedService uiShared, MareConfigService configService, ApiController apiController, PairManager pairManager, ChatService chatService,
|
public CompactUi(ILogger<CompactUi> logger, UiSharedService uiShared, MareConfigService configService, ApiController apiController, PairManager pairManager, ChatService chatService,
|
||||||
ServerConfigurationManager serverManager, MareMediator mediator, FileUploadManager fileTransferManager, UidDisplayHandler uidDisplayHandler, CharaDataManager charaDataManager,
|
ServerConfigurationManager serverManager, MareMediator mediator, FileUploadManager fileTransferManager, UidDisplayHandler uidDisplayHandler, CharaDataManager charaDataManager,
|
||||||
PerformanceCollectorService performanceCollectorService)
|
PerformanceCollectorService performanceCollectorService, AccountRegistrationService registerService)
|
||||||
: base(logger, mediator, "###SnowcloakSyncMainUI", performanceCollectorService)
|
: base(logger, mediator, "###SnowcloakSyncMainUI", performanceCollectorService)
|
||||||
{
|
{
|
||||||
_uiSharedService = uiShared;
|
_uiSharedService = uiShared;
|
||||||
@@ -67,6 +88,7 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
_apiController = apiController;
|
_apiController = apiController;
|
||||||
_pairManager = pairManager;
|
_pairManager = pairManager;
|
||||||
_serverManager = serverManager;
|
_serverManager = serverManager;
|
||||||
|
_registerService = registerService;
|
||||||
_fileTransferManager = fileTransferManager;
|
_fileTransferManager = fileTransferManager;
|
||||||
_uidDisplayHandler = uidDisplayHandler;
|
_uidDisplayHandler = uidDisplayHandler;
|
||||||
_charaDataManager = charaDataManager;
|
_charaDataManager = charaDataManager;
|
||||||
@@ -95,21 +117,166 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
Flags |= ImGuiWindowFlags.NoDocking;
|
Flags |= ImGuiWindowFlags.NoDocking;
|
||||||
|
|
||||||
|
// changed min size
|
||||||
SizeConstraints = new WindowSizeConstraints()
|
SizeConstraints = new WindowSizeConstraints()
|
||||||
{
|
{
|
||||||
MinimumSize = new Vector2(350, 400),
|
MinimumSize = new Vector2(500, 400),
|
||||||
MaximumSize = new Vector2(350, 2000),
|
MaximumSize = new Vector2(600, 2000),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void DrawInternal()
|
protected override void DrawInternal()
|
||||||
{
|
{
|
||||||
if (_serverManager.CurrentApiUrl.Equals(ApiController.SnowcloakServiceUri, StringComparison.Ordinal))
|
if (_serverManager.CurrentApiUrl.Equals(ApiController.SnowcloakServiceUri, StringComparison.Ordinal))
|
||||||
UiSharedService.AccentColor = new Vector4(1.0f, 0.8666f, 0.06666f, 1.0f);
|
UiSharedService.AccentColor = SnowcloakSync.Utils.Colours._snowcloakOnline;
|
||||||
else
|
else
|
||||||
UiSharedService.AccentColor = ImGuiColors.ParsedGreen;
|
UiSharedService.AccentColor = ImGuiColors.ParsedGreen;
|
||||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ImGui.GetStyle().WindowPadding.Y - 1f * ImGuiHelpers.GlobalScale + ImGui.GetStyle().ItemSpacing.Y);
|
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ImGui.GetStyle().WindowPadding.Y - 1f * ImGuiHelpers.GlobalScale + ImGui.GetStyle().ItemSpacing.Y);
|
||||||
|
|
||||||
|
DrawSidebar();
|
||||||
|
ImGui.SameLine();
|
||||||
|
DrawMainContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
//helper for buttons
|
||||||
|
private void DrawSidebarButton(Menu menu, FontAwesomeIcon icon, string label)
|
||||||
|
{
|
||||||
|
bool isActive = _selectedMenu == menu;
|
||||||
|
using var color = ImRaii.PushColor(ImGuiCol.Button, isActive ? UiSharedService.AccentColor : new Vector4(0, 0, 0, 0));
|
||||||
|
using var colorHovered = ImRaii.PushColor(ImGuiCol.ButtonHovered, isActive ? UiSharedService.AccentColor : ImGui.GetStyle().Colors[(int)ImGuiCol.ButtonHovered]);
|
||||||
|
using var colorActive = ImRaii.PushColor(ImGuiCol.ButtonActive, isActive ? UiSharedService.AccentColor : ImGui.GetStyle().Colors[(int)ImGuiCol.ButtonActive]);
|
||||||
|
|
||||||
|
if (_sidebarCollapsed)
|
||||||
|
{
|
||||||
|
// if the tab is collapsed state only show buttons not lable
|
||||||
|
if (_uiSharedService.IconButton(icon))
|
||||||
|
{
|
||||||
|
_selectedMenu = menu;
|
||||||
|
}
|
||||||
|
UiSharedService.AttachToolTip(label);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_uiSharedService.IconTextButton(icon, label, (165 - ImGui.GetStyle().WindowPadding.X * 2) * ImGuiHelpers.GlobalScale))
|
||||||
|
{
|
||||||
|
_selectedMenu = menu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// helper for buttons that dont cause state change
|
||||||
|
private void DrawSidebarAction(FontAwesomeIcon icon, string label, Action onClick)
|
||||||
|
{
|
||||||
|
if (_sidebarCollapsed)
|
||||||
|
{
|
||||||
|
// if the tab is collapsed state only show buttons not lable
|
||||||
|
if (_uiSharedService.IconButton(icon))
|
||||||
|
{
|
||||||
|
onClick();
|
||||||
|
}
|
||||||
|
UiSharedService.AttachToolTip(label);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_uiSharedService.IconTextButton(icon, label, (165 - ImGui.GetStyle().WindowPadding.X * 2) * ImGuiHelpers.GlobalScale))
|
||||||
|
{
|
||||||
|
onClick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void DrawSidebar()
|
||||||
|
{
|
||||||
|
// Adjust both values below to change size, 40 seems good to fit the buttons
|
||||||
|
// 150 seems decent enough to fit the text into it, could be smaller
|
||||||
|
// Elf note: Adjusted to 165 since "Character Analysis" hung off the end a bit
|
||||||
|
var sidebarWidth = (_sidebarCollapsed ? 40 : 165) * ImGuiHelpers.GlobalScale;
|
||||||
|
|
||||||
|
using (var child = ImRaii.Child("Sidebar", new Vector2(sidebarWidth, -1), true))
|
||||||
|
{
|
||||||
|
var collapseIcon = _sidebarCollapsed ? FontAwesomeIcon.ArrowRight : FontAwesomeIcon.ArrowLeft;
|
||||||
|
if (_uiSharedService.IconButton(collapseIcon))
|
||||||
|
{
|
||||||
|
_sidebarCollapsed = !_sidebarCollapsed;
|
||||||
|
}
|
||||||
|
UiSharedService.AttachToolTip(_sidebarCollapsed ? "Expand Sidebar" : "Collapse Sidebar");
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
|
||||||
|
// Buttons with state change
|
||||||
|
DrawSidebarButton(Menu.IndividualPairs, FontAwesomeIcon.User, "Individual Pairs");
|
||||||
|
DrawSidebarButton(Menu.Syncshells, FontAwesomeIcon.UserFriends, "Syncshells");
|
||||||
|
ImGui.Separator();
|
||||||
|
//buttons without state change
|
||||||
|
DrawSidebarAction(FontAwesomeIcon.PersonCircleQuestion, "Character Analysis",
|
||||||
|
() => Mediator.Publish(new UiToggleMessage(typeof(DataAnalysisUi))));
|
||||||
|
//Abbrivated because Character Data Hub is too long and loogs ugly in the lables
|
||||||
|
DrawSidebarAction(FontAwesomeIcon.Running, "Character Hub",
|
||||||
|
() => Mediator.Publish(new UiToggleMessage(typeof(CharaDataHubUi))));
|
||||||
|
DrawSidebarAction(FontAwesomeIcon.Cog, "Settings",
|
||||||
|
() => Mediator.Publish(new UiToggleMessage(typeof(SettingsUi))));
|
||||||
|
if (_apiController.ServerState is ServerState.Connected)
|
||||||
|
{
|
||||||
|
ImGui.Separator();
|
||||||
|
DrawSidebarAction(FontAwesomeIcon.UserCircle, "Edit Profile",
|
||||||
|
() => Mediator.Publish(new UiToggleMessage(typeof(EditProfileUi))));
|
||||||
|
}
|
||||||
|
|
||||||
|
float bottomElementsHeight = ImGui.GetFrameHeightWithSpacing() * 2;
|
||||||
|
var availableSpace = ImGui.GetContentRegionAvail().Y;
|
||||||
|
if (availableSpace > bottomElementsHeight)
|
||||||
|
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + availableSpace - bottomElementsHeight);
|
||||||
|
|
||||||
|
//transparent button shenenigans
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.Button, 0);
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, 0);
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.ButtonActive, 0);
|
||||||
|
ImGui.PushStyleVar(ImGuiStyleVar.FrameBorderSize, 0);
|
||||||
|
|
||||||
|
|
||||||
|
if (_apiController.ServerState is ServerState.Connected)
|
||||||
|
{
|
||||||
|
var userCount = _apiController.OnlineUsers.ToString(CultureInfo.InvariantCulture);
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.Text, UiSharedService.AccentColor);
|
||||||
|
DrawSidebarAction(FontAwesomeIcon.Users, $"{userCount} Users Online", () => { });
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed);
|
||||||
|
DrawSidebarAction(FontAwesomeIcon.ExclamationTriangle, "Not connected", () => { });
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
// restore normal button
|
||||||
|
ImGui.PopStyleVar();
|
||||||
|
ImGui.PopStyleColor(3);
|
||||||
|
var connectedIcon = _serverManager.CurrentServer!.FullPause ? FontAwesomeIcon.Unlink : FontAwesomeIcon.Link;
|
||||||
|
var color = UiSharedService.GetBoolColor(!_serverManager.CurrentServer!.FullPause);
|
||||||
|
|
||||||
|
if (_apiController.ServerState is not (ServerState.Reconnecting or ServerState.Disconnecting))
|
||||||
|
{
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.Text, color);
|
||||||
|
|
||||||
|
DrawSidebarAction(connectedIcon, !_serverManager.CurrentServer.FullPause ? "Disconnect": "Connect",
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
_serverManager.CurrentServer.FullPause = !_serverManager.CurrentServer.FullPause;
|
||||||
|
_serverManager.Save();
|
||||||
|
_ = _apiController.CreateConnections();
|
||||||
|
});
|
||||||
|
ImGui.PopStyleColor();
|
||||||
|
UiSharedService.AttachToolTip(!_serverManager.CurrentServer.FullPause ? "Disconnect from " + _serverManager.CurrentServer.ServerName : "Connect to " + _serverManager.CurrentServer.ServerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void DrawMainContent()
|
||||||
|
{
|
||||||
|
using (var child = ImRaii.Child("MainContent", new Vector2(-1, -1), false))
|
||||||
|
{
|
||||||
WindowContentWidth = UiSharedService.GetWindowContentRegionWidth();
|
WindowContentWidth = UiSharedService.GetWindowContentRegionWidth();
|
||||||
|
|
||||||
if (!_apiController.IsCurrentVersion)
|
if (!_apiController.IsCurrentVersion)
|
||||||
{
|
{
|
||||||
var ver = _apiController.CurrentClientVersion;
|
var ver = _apiController.CurrentClientVersion;
|
||||||
@@ -126,57 +293,22 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
using (ImRaii.PushId("header")) DrawUIDHeader();
|
using (ImRaii.PushId("header")) DrawUIDHeader();
|
||||||
ImGui.Separator();
|
|
||||||
using (ImRaii.PushId("serverstatus")) DrawServerStatus();
|
|
||||||
|
|
||||||
if (_apiController.ServerState is ServerState.Connected)
|
if (_apiController.ServerState is ServerState.Connected)
|
||||||
{
|
{
|
||||||
var hasShownSyncShells = _showSyncShells;
|
|
||||||
|
|
||||||
ImGui.PushFont(UiBuilder.IconFont);
|
|
||||||
if (!hasShownSyncShells)
|
|
||||||
{
|
|
||||||
ImGui.PushStyleColor(ImGuiCol.Button, ImGui.GetStyle().Colors[(int)ImGuiCol.ButtonHovered]);
|
|
||||||
}
|
|
||||||
if (ImGui.Button(FontAwesomeIcon.User.ToIconString(), new Vector2((UiSharedService.GetWindowContentRegionWidth() - ImGui.GetWindowContentRegionMin().X) / 2, 30 * ImGuiHelpers.GlobalScale)))
|
|
||||||
{
|
|
||||||
_showSyncShells = false;
|
|
||||||
}
|
|
||||||
if (!hasShownSyncShells)
|
|
||||||
{
|
|
||||||
ImGui.PopStyleColor();
|
|
||||||
}
|
|
||||||
ImGui.PopFont();
|
|
||||||
UiSharedService.AttachToolTip("Individual pairs");
|
|
||||||
|
|
||||||
ImGui.SameLine();
|
|
||||||
|
|
||||||
ImGui.PushFont(UiBuilder.IconFont);
|
|
||||||
if (hasShownSyncShells)
|
|
||||||
{
|
|
||||||
ImGui.PushStyleColor(ImGuiCol.Button, ImGui.GetStyle().Colors[(int)ImGuiCol.ButtonHovered]);
|
|
||||||
}
|
|
||||||
if (ImGui.Button(FontAwesomeIcon.UserFriends.ToIconString(), new Vector2((UiSharedService.GetWindowContentRegionWidth() - ImGui.GetWindowContentRegionMin().X) / 2, 30 * ImGuiHelpers.GlobalScale)))
|
|
||||||
{
|
|
||||||
_showSyncShells = true;
|
|
||||||
}
|
|
||||||
if (hasShownSyncShells)
|
|
||||||
{
|
|
||||||
ImGui.PopStyleColor();
|
|
||||||
}
|
|
||||||
ImGui.PopFont();
|
|
||||||
|
|
||||||
UiSharedService.AttachToolTip("Syncshells");
|
|
||||||
|
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
if (!hasShownSyncShells)
|
|
||||||
|
|
||||||
|
switch (_selectedMenu)
|
||||||
{
|
{
|
||||||
|
case Menu.IndividualPairs:
|
||||||
using (ImRaii.PushId("pairlist")) DrawPairList();
|
using (ImRaii.PushId("pairlist")) DrawPairList();
|
||||||
}
|
break;
|
||||||
else
|
case Menu.Syncshells:
|
||||||
{
|
|
||||||
using (ImRaii.PushId("syncshells")) _groupPanel.DrawSyncshells();
|
using (ImRaii.PushId("syncshells")) _groupPanel.DrawSyncshells();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
using (ImRaii.PushId("transfers")) DrawTransfers();
|
using (ImRaii.PushId("transfers")) DrawTransfers();
|
||||||
TransferPartHeight = ImGui.GetCursorPosY() - TransferPartHeight;
|
TransferPartHeight = ImGui.GetCursorPosY() - TransferPartHeight;
|
||||||
@@ -224,6 +356,7 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
Mediator.Publish(new CompactUiChange(_lastSize, _lastPosition));
|
Mediator.Publish(new CompactUiChange(_lastSize, _lastPosition));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override void OnClose()
|
public override void OnClose()
|
||||||
{
|
{
|
||||||
@@ -235,10 +368,44 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
ImGui.Dummy(new(10));
|
ImGui.Dummy(new(10));
|
||||||
var keys = _serverManager.CurrentServer!.SecretKeys;
|
var keys = _serverManager.CurrentServer!.SecretKeys;
|
||||||
|
ImGui.BeginDisabled(_registrationInProgress || _uiSharedService.ApiController.ServerState == ServerState.Connecting || _uiSharedService.ApiController.ServerState == ServerState.Reconnecting);
|
||||||
if (keys.Any())
|
if (keys.Any())
|
||||||
{
|
{
|
||||||
if (_secretKeyIdx == -1) _secretKeyIdx = keys.First().Key;
|
if (_secretKeyIdx == -1) _secretKeyIdx = keys.First().Key;
|
||||||
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Plus, "Add current character with secret key"))
|
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Plus, "Log in with XIVAuth (experimental)"))
|
||||||
|
{
|
||||||
|
_registrationInProgress = true;
|
||||||
|
_ = Task.Run(async () => {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var reply = await _registerService.XIVAuth(CancellationToken.None).ConfigureAwait(false);
|
||||||
|
if (!reply.Success)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Registration failed: {err}", reply.ErrorMessage);
|
||||||
|
_registrationMessage = reply.ErrorMessage;
|
||||||
|
if (_registrationMessage.IsNullOrEmpty())
|
||||||
|
_registrationMessage = "An unknown error occured. Please try again later.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_registrationMessage = "Account registered. Welcome to Snowcloak!";
|
||||||
|
_secretKey = reply.SecretKey ?? "";
|
||||||
|
_registrationReply = reply;
|
||||||
|
_registrationSuccess = true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(ex, "Registration failed");
|
||||||
|
_registrationSuccess = false;
|
||||||
|
_registrationMessage = "An unknown error occured. Please try again later.";
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_registrationInProgress = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Plus, "Add character with existing key"))
|
||||||
{
|
{
|
||||||
_serverManager.CurrentServer!.Authentications.Add(new MareConfiguration.Models.Authentication()
|
_serverManager.CurrentServer!.Authentications.Add(new MareConfiguration.Models.Authentication()
|
||||||
{
|
{
|
||||||
@@ -251,7 +418,43 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
_ = _apiController.CreateConnections();
|
_ = _apiController.CreateConnections();
|
||||||
}
|
}
|
||||||
|
ImGui.EndDisabled(); // _registrationInProgress || _registrationSuccess
|
||||||
|
|
||||||
|
if (_registrationInProgress)
|
||||||
|
{
|
||||||
|
ImGui.TextUnformatted("Waiting for the server...");
|
||||||
|
}
|
||||||
|
else if (!_registrationMessage.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
if (!_registrationSuccess)
|
||||||
|
ImGui.TextColored(ImGuiColors.DalamudYellow, _registrationMessage);
|
||||||
|
else
|
||||||
|
ImGui.TextWrapped(_registrationMessage);
|
||||||
|
}
|
||||||
|
if (_secretKey.Length > 0 && _secretKey.Length != 64)
|
||||||
|
{
|
||||||
|
UiSharedService.ColorTextWrapped("Your secret key must be exactly 64 characters long.", ImGuiColors.DalamudRed);
|
||||||
|
}
|
||||||
|
else if (_secretKey.Length == 64)
|
||||||
|
{
|
||||||
|
using var saveDisabled = ImRaii.Disabled(_uiSharedService.ApiController.ServerState == ServerState.Connecting || _uiSharedService.ApiController.ServerState == ServerState.Reconnecting);
|
||||||
|
if (ImGui.Button("Save and Connect"))
|
||||||
|
{
|
||||||
|
string keyName;
|
||||||
|
if (_serverManager.CurrentServer == null) _serverManager.SelectServer(0);
|
||||||
|
if (_registrationReply != null && _secretKey.Equals(_registrationReply.SecretKey, StringComparison.Ordinal))
|
||||||
|
keyName = _registrationReply.UID + $" (registered {DateTime.Now:yyyy-MM-dd})";
|
||||||
|
else
|
||||||
|
keyName = $"Secret Key added on Setup ({DateTime.Now:yyyy-MM-dd})";
|
||||||
|
_serverManager.CurrentServer!.SecretKeys.Add(_serverManager.CurrentServer.SecretKeys.Select(k => k.Key).LastOrDefault() + 1, new SecretKey()
|
||||||
|
{
|
||||||
|
FriendlyName = keyName,
|
||||||
|
Key = _secretKey,
|
||||||
|
});
|
||||||
|
_serverManager.AddCurrentCharacterToServer(save: false);
|
||||||
|
_ = Task.Run(() => _uiSharedService.ApiController.CreateConnections());
|
||||||
|
}
|
||||||
|
}
|
||||||
_uiSharedService.DrawCombo("Secret Key##addCharacterSecretKey", keys, (f) => f.Value.FriendlyName, (f) => _secretKeyIdx = f.Key);
|
_uiSharedService.DrawCombo("Secret Key##addCharacterSecretKey", keys, (f) => f.Value.FriendlyName, (f) => _secretKeyIdx = f.Key);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -362,87 +565,18 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
: (ImGui.GetWindowContentRegionMax().Y - ImGui.GetWindowContentRegionMin().Y) - TransferPartHeight - ImGui.GetCursorPosY();
|
: (ImGui.GetWindowContentRegionMax().Y - ImGui.GetWindowContentRegionMin().Y) - TransferPartHeight - ImGui.GetCursorPosY();
|
||||||
var users = GetFilteredUsers().OrderBy(u => u.GetPairSortKey(), StringComparer.Ordinal);
|
var users = GetFilteredUsers().OrderBy(u => u.GetPairSortKey(), StringComparer.Ordinal);
|
||||||
|
|
||||||
var onlineUsers = users.Where(u => u.UserPair!.OtherPermissions.IsPaired() && (u.IsOnline || u.UserPair!.OwnPermissions.IsPaused())).Select(c => new DrawUserPair("Online" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager)).ToList();
|
var onlineUsers = users.Where(u => u.UserPair!.OtherPermissions.IsPaired() && (u.IsOnline && !u.IsVisible && (!u.UserPair!.OtherPermissions.IsPaused() && !u.UserPair!.OwnPermissions.IsPaused()))).Select(c => new DrawUserPair("Online" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager)).ToList();
|
||||||
|
var pausedUsers = users.Where(u => u.UserPair!.OtherPermissions.IsPaired() && (u.UserPair!.OtherPermissions.IsPaused() || u.UserPair!.OwnPermissions.IsPaused())).Select(c => new DrawUserPair("Paused" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager)).ToList();
|
||||||
var visibleUsers = users.Where(u => u.IsVisible).Select(c => new DrawUserPair("Visible" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager)).ToList();
|
var visibleUsers = users.Where(u => u.IsVisible).Select(c => new DrawUserPair("Visible" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager)).ToList();
|
||||||
var offlineUsers = users.Where(u => !u.UserPair!.OtherPermissions.IsPaired() || (!u.IsOnline && !u.UserPair!.OwnPermissions.IsPaused())).Select(c => new DrawUserPair("Offline" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager)).ToList();
|
var offlineUsers = users.Where(u => !u.UserPair!.OtherPermissions.IsPaired() || !u.IsOnline && (!u.UserPair!.OwnPermissions.IsPaused() && !u.UserPair.OtherPermissions.IsPaused())).Select(c => new DrawUserPair("Offline" + c.UserData.UID, c, _uidDisplayHandler, _apiController, Mediator, _selectGroupForPairUi, _uiSharedService, _charaDataManager)).ToList();
|
||||||
|
|
||||||
ImGui.BeginChild("list", new Vector2(WindowContentWidth, ySize), border: false);
|
ImGui.BeginChild("list", new Vector2(WindowContentWidth, ySize), border: false);
|
||||||
|
|
||||||
_pairGroupsUi.Draw(visibleUsers, onlineUsers, offlineUsers);
|
_pairGroupsUi.Draw(visibleUsers, onlineUsers, pausedUsers, offlineUsers);
|
||||||
|
|
||||||
ImGui.EndChild();
|
ImGui.EndChild();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawServerStatus()
|
|
||||||
{
|
|
||||||
var buttonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Link);
|
|
||||||
var userCount = _apiController.OnlineUsers.ToString(CultureInfo.InvariantCulture);
|
|
||||||
var userSize = ImGui.CalcTextSize(userCount);
|
|
||||||
var textSize = ImGui.CalcTextSize("Users Online");
|
|
||||||
string shardConnection = string.Equals(_apiController.ServerInfo.ShardName, "Main", StringComparison.OrdinalIgnoreCase) ? string.Empty : $"Shard: {_apiController.ServerInfo.ShardName}";
|
|
||||||
var shardTextSize = ImGui.CalcTextSize(shardConnection);
|
|
||||||
var printShard = !string.IsNullOrEmpty(_apiController.ServerInfo.ShardName) && shardConnection != string.Empty;
|
|
||||||
|
|
||||||
if (_apiController.ServerState is ServerState.Connected)
|
|
||||||
{
|
|
||||||
ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth()) / 2 - (userSize.X + textSize.X) / 2 - ImGui.GetStyle().ItemSpacing.X / 2);
|
|
||||||
if (!printShard) ImGui.AlignTextToFramePadding();
|
|
||||||
ImGui.TextColored(ImGuiColors.ParsedGreen, userCount);
|
|
||||||
ImGui.SameLine();
|
|
||||||
if (!printShard) ImGui.AlignTextToFramePadding();
|
|
||||||
ImGui.TextUnformatted("Users Online");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ImGui.AlignTextToFramePadding();
|
|
||||||
ImGui.TextColored(ImGuiColors.DalamudRed, "Not connected to any server");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (printShard)
|
|
||||||
{
|
|
||||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ImGui.GetStyle().ItemSpacing.Y);
|
|
||||||
ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth()) / 2 - shardTextSize.X / 2);
|
|
||||||
ImGui.TextUnformatted(shardConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.SameLine();
|
|
||||||
if (printShard)
|
|
||||||
{
|
|
||||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ((userSize.Y + textSize.Y) / 2 + shardTextSize.Y) / 2 - ImGui.GetStyle().ItemSpacing.Y + buttonSize.Y / 2);
|
|
||||||
}
|
|
||||||
var color = UiSharedService.GetBoolColor(!_serverManager.CurrentServer!.FullPause);
|
|
||||||
var connectedIcon = !_serverManager.CurrentServer.FullPause ? FontAwesomeIcon.Link : FontAwesomeIcon.Unlink;
|
|
||||||
|
|
||||||
if (_apiController.ServerState is ServerState.Connected)
|
|
||||||
{
|
|
||||||
ImGui.SetCursorPosX(0 + ImGui.GetStyle().ItemSpacing.X);
|
|
||||||
if (_uiSharedService.IconButton(FontAwesomeIcon.UserCircle))
|
|
||||||
{
|
|
||||||
Mediator.Publish(new UiToggleMessage(typeof(EditProfileUi)));
|
|
||||||
}
|
|
||||||
UiSharedService.AttachToolTip("Edit your Profile");
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - buttonSize.X);
|
|
||||||
if (printShard)
|
|
||||||
{
|
|
||||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ((userSize.Y + textSize.Y) / 2 + shardTextSize.Y) / 2 - ImGui.GetStyle().ItemSpacing.Y + buttonSize.Y / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_apiController.ServerState is not (ServerState.Reconnecting or ServerState.Disconnecting))
|
|
||||||
{
|
|
||||||
ImGui.PushStyleColor(ImGuiCol.Text, color);
|
|
||||||
if (_uiSharedService.IconButton(connectedIcon))
|
|
||||||
{
|
|
||||||
_serverManager.CurrentServer.FullPause = !_serverManager.CurrentServer.FullPause;
|
|
||||||
_serverManager.Save();
|
|
||||||
_ = _apiController.CreateConnections();
|
|
||||||
}
|
|
||||||
ImGui.PopStyleColor();
|
|
||||||
UiSharedService.AttachToolTip(!_serverManager.CurrentServer.FullPause ? "Disconnect from " + _serverManager.CurrentServer.ServerName : "Connect to " + _serverManager.CurrentServer.ServerName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawTransfers()
|
private void DrawTransfers()
|
||||||
{
|
{
|
||||||
var currentUploads = _fileTransferManager.CurrentUploads.ToList();
|
var currentUploads = _fileTransferManager.CurrentUploads.ToList();
|
||||||
@@ -486,67 +620,39 @@ public class CompactUi : WindowMediatorSubscriberBase
|
|||||||
ImGui.SameLine(WindowContentWidth - textSize.X);
|
ImGui.SameLine(WindowContentWidth - textSize.X);
|
||||||
ImGui.TextUnformatted(downloadText);
|
ImGui.TextUnformatted(downloadText);
|
||||||
}
|
}
|
||||||
|
|
||||||
var bottomButtonWidth = (WindowContentWidth - ImGui.GetStyle().ItemSpacing.X) / 2;
|
|
||||||
|
|
||||||
if (_uiSharedService.IconTextButton(FontAwesomeIcon.PersonCircleQuestion, "Character Analysis", bottomButtonWidth))
|
|
||||||
{
|
|
||||||
Mediator.Publish(new UiToggleMessage(typeof(DataAnalysisUi)));
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.SameLine();
|
|
||||||
|
|
||||||
if (_uiSharedService.IconTextButton(FontAwesomeIcon.Running, "Character Data Hub", bottomButtonWidth))
|
|
||||||
{
|
|
||||||
Mediator.Publish(new UiToggleMessage(typeof(CharaDataHubUi)));
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.SameLine();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawUIDHeader()
|
private void DrawUIDHeader()
|
||||||
{
|
{
|
||||||
var uidText = GetUidText();
|
var uidText = GetUidText();
|
||||||
var buttonSizeX = 0f;
|
|
||||||
Vector2 uidTextSize;
|
|
||||||
|
|
||||||
using (_uiSharedService.UidFont.Push())
|
using (_uiSharedService.UidFont.Push())
|
||||||
{
|
{
|
||||||
uidTextSize = ImGui.CalcTextSize(uidText);
|
var uidTextSize = ImGui.CalcTextSize(uidText);
|
||||||
|
ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X) / 2 - (uidTextSize.X / 2));
|
||||||
|
ImGui.TextColored(GetUidColor(), uidText);
|
||||||
}
|
}
|
||||||
|
|
||||||
var originalPos = ImGui.GetCursorPos();
|
|
||||||
ImGui.SetWindowFontScale(1.5f);
|
|
||||||
var buttonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Cog);
|
|
||||||
buttonSizeX -= buttonSize.X - ImGui.GetStyle().ItemSpacing.X * 2;
|
|
||||||
ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - buttonSize.X);
|
|
||||||
ImGui.SetCursorPosY(originalPos.Y + uidTextSize.Y / 2 - buttonSize.Y / 2);
|
|
||||||
if (_uiSharedService.IconButton(FontAwesomeIcon.Cog))
|
|
||||||
{
|
|
||||||
Mediator.Publish(new OpenSettingsUiMessage());
|
|
||||||
}
|
|
||||||
UiSharedService.AttachToolTip("Open the Snowcloak Settings");
|
|
||||||
|
|
||||||
ImGui.SameLine(); //Important to draw the uidText consistently
|
|
||||||
ImGui.SetCursorPos(originalPos);
|
|
||||||
|
|
||||||
if (_apiController.ServerState is ServerState.Connected)
|
if (_apiController.ServerState is ServerState.Connected)
|
||||||
{
|
{
|
||||||
buttonSizeX += _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Copy).X - ImGui.GetStyle().ItemSpacing.X * 2;
|
if (ImGui.IsItemClicked())
|
||||||
ImGui.SetCursorPosY(originalPos.Y + uidTextSize.Y / 2 - buttonSize.Y / 2);
|
|
||||||
if (_uiSharedService.IconButton(FontAwesomeIcon.Copy))
|
|
||||||
{
|
{
|
||||||
ImGui.SetClipboardText(_apiController.DisplayName);
|
ImGui.SetClipboardText(_apiController.DisplayName);
|
||||||
}
|
}
|
||||||
UiSharedService.AttachToolTip("Copy your UID to clipboard");
|
UiSharedService.AttachToolTip("Click to copy");
|
||||||
ImGui.SameLine();
|
|
||||||
}
|
|
||||||
ImGui.SetWindowFontScale(1f);
|
|
||||||
|
|
||||||
ImGui.SetCursorPosY(originalPos.Y + buttonSize.Y / 2 - uidTextSize.Y / 2 - ImGui.GetStyle().ItemSpacing.Y / 2);
|
if (!string.Equals(_apiController.DisplayName, _apiController.UID, StringComparison.Ordinal))
|
||||||
ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMax().X + ImGui.GetWindowContentRegionMin().X) / 2 + buttonSizeX - uidTextSize.X / 2);
|
{
|
||||||
using (_uiSharedService.UidFont.Push())
|
var origTextSize = ImGui.CalcTextSize(_apiController.UID);
|
||||||
ImGui.TextColored(GetUidColor(), uidText);
|
ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X) / 2 - (origTextSize.X / 2));
|
||||||
|
ImGui.TextColored(GetUidColor(), _apiController.UID);
|
||||||
|
if (ImGui.IsItemClicked())
|
||||||
|
{
|
||||||
|
ImGui.SetClipboardText(_apiController.UID);
|
||||||
|
}
|
||||||
|
UiSharedService.AttachToolTip("Click to copy");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_apiController.ServerState is not ServerState.Connected)
|
if (_apiController.ServerState is not ServerState.Connected)
|
||||||
{
|
{
|
||||||
|
@@ -20,6 +20,7 @@ public class DrawGroupPair : DrawPairBase
|
|||||||
private readonly GroupPairFullInfoDto _fullInfoDto;
|
private readonly GroupPairFullInfoDto _fullInfoDto;
|
||||||
private readonly GroupFullInfoDto _group;
|
private readonly GroupFullInfoDto _group;
|
||||||
private readonly CharaDataManager _charaDataManager;
|
private readonly CharaDataManager _charaDataManager;
|
||||||
|
public long VRAMUsage { get; set; }
|
||||||
|
|
||||||
public DrawGroupPair(string id, Pair entry, ApiController apiController,
|
public DrawGroupPair(string id, Pair entry, ApiController apiController,
|
||||||
MareMediator mareMediator, GroupFullInfoDto group, GroupPairFullInfoDto fullInfoDto,
|
MareMediator mareMediator, GroupFullInfoDto group, GroupPairFullInfoDto fullInfoDto,
|
||||||
@@ -80,6 +81,7 @@ public class DrawGroupPair : DrawPairBase
|
|||||||
}
|
}
|
||||||
if (_pair.LastAppliedDataBytes >= 0)
|
if (_pair.LastAppliedDataBytes >= 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
presenceText += UiSharedService.TooltipSeparator;
|
presenceText += UiSharedService.TooltipSeparator;
|
||||||
presenceText += ((!_pair.IsVisible) ? "(Last) " : string.Empty) + "Mods Info" + Environment.NewLine;
|
presenceText += ((!_pair.IsVisible) ? "(Last) " : string.Empty) + "Mods Info" + Environment.NewLine;
|
||||||
presenceText += "Files Size: " + UiSharedService.ByteToString(_pair.LastAppliedDataBytes, true);
|
presenceText += "Files Size: " + UiSharedService.ByteToString(_pair.LastAppliedDataBytes, true);
|
||||||
@@ -127,6 +129,9 @@ public class DrawGroupPair : DrawPairBase
|
|||||||
|
|
||||||
protected override float DrawRightSide(float textPosY, float originalY)
|
protected override float DrawRightSide(float textPosY, float originalY)
|
||||||
{
|
{
|
||||||
|
var pauseIcon = _pair.IsPaused ? FontAwesomeIcon.Play : FontAwesomeIcon.Pause;
|
||||||
|
var pauseIconSize = _uiSharedService.GetIconButtonSize(pauseIcon);
|
||||||
|
var spacingX = ImGui.GetStyle().ItemSpacing.X;
|
||||||
var entryUID = _fullInfoDto.UserAliasOrUID;
|
var entryUID = _fullInfoDto.UserAliasOrUID;
|
||||||
var entryIsMod = _fullInfoDto.GroupPairStatusInfo.IsModerator();
|
var entryIsMod = _fullInfoDto.GroupPairStatusInfo.IsModerator();
|
||||||
var entryIsOwner = string.Equals(_pair.UserData.UID, _group.OwnerUID, StringComparison.Ordinal);
|
var entryIsOwner = string.Equals(_pair.UserData.UID, _group.OwnerUID, StringComparison.Ordinal);
|
||||||
@@ -145,19 +150,27 @@ public class DrawGroupPair : DrawPairBase
|
|||||||
bool showInfo = (individualAnimDisabled || individualSoundsDisabled || animDisabled || soundsDisabled);
|
bool showInfo = (individualAnimDisabled || individualSoundsDisabled || animDisabled || soundsDisabled);
|
||||||
bool showPlus = _pair.UserPair == null;
|
bool showPlus = _pair.UserPair == null;
|
||||||
bool showBars = (userIsOwner || (userIsModerator && !entryIsMod && !entryIsOwner)) || !_pair.IsPaused;
|
bool showBars = (userIsOwner || (userIsModerator && !entryIsMod && !entryIsOwner)) || !_pair.IsPaused;
|
||||||
|
bool showPause = true;
|
||||||
var spacing = ImGui.GetStyle().ItemSpacing.X;
|
var spacing = ImGui.GetStyle().ItemSpacing.X;
|
||||||
var permIcon = (individualAnimDisabled || individualSoundsDisabled || individualVFXDisabled) ? FontAwesomeIcon.ExclamationTriangle
|
var permIcon = (individualAnimDisabled || individualSoundsDisabled || individualVFXDisabled) ? FontAwesomeIcon.ExclamationTriangle
|
||||||
: ((soundsDisabled || animDisabled || vfxDisabled) ? FontAwesomeIcon.InfoCircle : FontAwesomeIcon.None);
|
: ((soundsDisabled || animDisabled || vfxDisabled) ? FontAwesomeIcon.InfoCircle : FontAwesomeIcon.None);
|
||||||
var runningIconWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Running).X;
|
var runningIconWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Running).X;
|
||||||
var infoIconWidth = UiSharedService.GetIconSize(permIcon).X;
|
var infoIconWidth = UiSharedService.GetIconSize(permIcon).X;
|
||||||
var plusButtonWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Plus).X;
|
var plusButtonWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Plus).X;
|
||||||
|
var pauseButtonWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Plus).X;
|
||||||
|
|
||||||
var barButtonWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars).X;
|
var barButtonWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars).X;
|
||||||
|
var barButtonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Bars);
|
||||||
|
|
||||||
|
var windowEndX = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth();
|
||||||
|
var rightSidePos = windowEndX - barButtonSize.X;
|
||||||
|
|
||||||
|
|
||||||
var pos = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() + spacing
|
var pos = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() + spacing
|
||||||
- (showShared ? (runningIconWidth + spacing) : 0)
|
- (showShared ? (runningIconWidth + spacing) : 0)
|
||||||
- (showInfo ? (infoIconWidth + spacing) : 0)
|
- (showInfo ? (infoIconWidth + spacing) : 0)
|
||||||
- (showPlus ? (plusButtonWidth + spacing) : 0)
|
- (showPlus ? (plusButtonWidth + spacing) : 0)
|
||||||
|
- (showPause ? (pauseButtonWidth + spacing) : 0)
|
||||||
- (showBars ? (barButtonWidth + spacing) : 0);
|
- (showBars ? (barButtonWidth + spacing) : 0);
|
||||||
|
|
||||||
ImGui.SameLine(pos);
|
ImGui.SameLine(pos);
|
||||||
@@ -264,6 +277,7 @@ public class DrawGroupPair : DrawPairBase
|
|||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (showPlus)
|
if (showPlus)
|
||||||
{
|
{
|
||||||
ImGui.SetCursorPosY(originalY);
|
ImGui.SetCursorPosY(originalY);
|
||||||
@@ -275,7 +289,37 @@ public class DrawGroupPair : DrawPairBase
|
|||||||
UiSharedService.AttachToolTip("Pair with " + entryUID + " individually");
|
UiSharedService.AttachToolTip("Pair with " + entryUID + " individually");
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
}
|
}
|
||||||
|
if (showPause)
|
||||||
|
{
|
||||||
|
//rightSidePos -= pauseIconSize.X + spacingX;
|
||||||
|
ImGui.SetCursorPosY(originalY);
|
||||||
|
|
||||||
|
if (_uiSharedService.IconButton(pauseIcon))
|
||||||
|
{
|
||||||
|
if (_pair.UserPair != null)
|
||||||
|
{
|
||||||
|
var perm = _pair.UserPair.OwnPermissions;
|
||||||
|
perm.SetPaused(!perm.IsPaused());
|
||||||
|
_ = _apiController.UserSetPairPermissions(new(_pair.UserData, perm));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var groupPerm = _fullInfoDto.GroupUserPermissions;
|
||||||
|
groupPerm.SetPaused(!groupPerm.IsPaused());
|
||||||
|
_ = _apiController.GroupChangeIndividualPermissionState(new GroupPairUserPermissionDto(
|
||||||
|
_group.Group,
|
||||||
|
_pair.UserData,
|
||||||
|
groupPerm
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UiSharedService.AttachToolTip(!_fullInfoDto.GroupUserPermissions.IsPaused()
|
||||||
|
? "Pause pairing with " + entryUID
|
||||||
|
: "Resume pairing with " + entryUID);
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
}
|
||||||
if (showBars)
|
if (showBars)
|
||||||
{
|
{
|
||||||
ImGui.SetCursorPosY(originalY);
|
ImGui.SetCursorPosY(originalY);
|
||||||
@@ -285,7 +329,6 @@ public class DrawGroupPair : DrawPairBase
|
|||||||
ImGui.OpenPopup("Popup");
|
ImGui.OpenPopup("Popup");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui.BeginPopup("Popup"))
|
if (ImGui.BeginPopup("Popup"))
|
||||||
{
|
{
|
||||||
if ((userIsModerator || userIsOwner) && !(entryIsMod || entryIsOwner))
|
if ((userIsModerator || userIsOwner) && !(entryIsMod || entryIsOwner))
|
||||||
|
@@ -19,6 +19,7 @@ public class DrawUserPair : DrawPairBase
|
|||||||
protected readonly MareMediator _mediator;
|
protected readonly MareMediator _mediator;
|
||||||
private readonly SelectGroupForPairUi _selectGroupForPairUi;
|
private readonly SelectGroupForPairUi _selectGroupForPairUi;
|
||||||
private readonly CharaDataManager _charaDataManager;
|
private readonly CharaDataManager _charaDataManager;
|
||||||
|
public long VramUsage { get; set; }
|
||||||
|
|
||||||
public DrawUserPair(string id, Pair entry, UidDisplayHandler displayHandler, ApiController apiController,
|
public DrawUserPair(string id, Pair entry, UidDisplayHandler displayHandler, ApiController apiController,
|
||||||
MareMediator mareMediator, SelectGroupForPairUi selectGroupForPairUi,
|
MareMediator mareMediator, SelectGroupForPairUi selectGroupForPairUi,
|
||||||
@@ -51,26 +52,27 @@ public class DrawUserPair : DrawPairBase
|
|||||||
{
|
{
|
||||||
connectionIcon = FontAwesomeIcon.PauseCircle;
|
connectionIcon = FontAwesomeIcon.PauseCircle;
|
||||||
connectionText = "Pairing status with " + _pair.UserData.AliasOrUID + " is paused";
|
connectionText = "Pairing status with " + _pair.UserData.AliasOrUID + " is paused";
|
||||||
connectionColor = ImGuiColors.DalamudYellow;
|
connectionColor = ImGuiColors.DalamudGrey;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
connectionIcon = FontAwesomeIcon.Check;
|
connectionIcon = FontAwesomeIcon.Snowflake;
|
||||||
connectionText = "You are paired with " + _pair.UserData.AliasOrUID;
|
connectionText = "You are paired with " + _pair.UserData.AliasOrUID;
|
||||||
connectionColor = ImGuiColors.ParsedGreen;
|
connectionColor = _pair.IsOnline ? SnowcloakSync.Utils.Colours._snowcloakOnline : ImGuiColors.DalamudGrey;
|
||||||
}
|
}
|
||||||
|
if (!_pair.IsVisible)
|
||||||
|
{
|
||||||
ImGui.SetCursorPosY(textPosY);
|
ImGui.SetCursorPosY(textPosY);
|
||||||
ImGui.PushFont(UiBuilder.IconFont);
|
ImGui.PushFont(UiBuilder.IconFont);
|
||||||
UiSharedService.ColorText(connectionIcon.ToIconString(), connectionColor);
|
UiSharedService.ColorText(connectionIcon.ToIconString(), connectionColor);
|
||||||
ImGui.PopFont();
|
ImGui.PopFont();
|
||||||
UiSharedService.AttachToolTip(connectionText);
|
UiSharedService.AttachToolTip(connectionText);
|
||||||
|
}
|
||||||
if (_pair is { IsOnline: true, IsVisible: true })
|
if (_pair is { IsOnline: true, IsVisible: true })
|
||||||
{
|
{
|
||||||
ImGui.SameLine();
|
|
||||||
ImGui.SetCursorPosY(textPosY);
|
ImGui.SetCursorPosY(textPosY);
|
||||||
ImGui.PushFont(UiBuilder.IconFont);
|
ImGui.PushFont(UiBuilder.IconFont);
|
||||||
UiSharedService.ColorText(FontAwesomeIcon.Eye.ToIconString(), ImGuiColors.ParsedGreen);
|
UiSharedService.ColorText(FontAwesomeIcon.Eye.ToIconString(), SnowcloakSync.Utils.Colours._snowcloakOnline);
|
||||||
if (ImGui.IsItemClicked())
|
if (ImGui.IsItemClicked())
|
||||||
{
|
{
|
||||||
_mediator.Publish(new TargetPairMessage(_pair));
|
_mediator.Publish(new TargetPairMessage(_pair));
|
||||||
@@ -84,6 +86,7 @@ public class DrawUserPair : DrawPairBase
|
|||||||
visibleTooltip += "Files Size: " + UiSharedService.ByteToString(_pair.LastAppliedDataBytes, true);
|
visibleTooltip += "Files Size: " + UiSharedService.ByteToString(_pair.LastAppliedDataBytes, true);
|
||||||
if (_pair.LastAppliedApproximateVRAMBytes >= 0)
|
if (_pair.LastAppliedApproximateVRAMBytes >= 0)
|
||||||
{
|
{
|
||||||
|
VramUsage = _pair.LastAppliedApproximateVRAMBytes;
|
||||||
visibleTooltip += Environment.NewLine + "Approx. VRAM Usage: " + UiSharedService.ByteToString(_pair.LastAppliedApproximateVRAMBytes, true);
|
visibleTooltip += Environment.NewLine + "Approx. VRAM Usage: " + UiSharedService.ByteToString(_pair.LastAppliedApproximateVRAMBytes, true);
|
||||||
}
|
}
|
||||||
if (_pair.LastAppliedDataTris >= 0)
|
if (_pair.LastAppliedDataTris >= 0)
|
||||||
@@ -97,6 +100,8 @@ public class DrawUserPair : DrawPairBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected override float DrawRightSide(float textPosY, float originalY)
|
protected override float DrawRightSide(float textPosY, float originalY)
|
||||||
{
|
{
|
||||||
var pauseIcon = _pair.UserPair!.OwnPermissions.IsPaused() ? FontAwesomeIcon.Play : FontAwesomeIcon.Pause;
|
var pauseIcon = _pair.UserPair!.OwnPermissions.IsPaused() ? FontAwesomeIcon.Play : FontAwesomeIcon.Pause;
|
||||||
|
@@ -418,16 +418,29 @@ internal sealed class GroupPanel
|
|||||||
ImGui.Indent(20);
|
ImGui.Indent(20);
|
||||||
if (_expandedGroupState[groupDto.GID])
|
if (_expandedGroupState[groupDto.GID])
|
||||||
{
|
{
|
||||||
var sortedPairs = pairsInGroup
|
IOrderedEnumerable<Pair> sortedPairs;
|
||||||
|
if (!_mareConfig.Current.SortSyncshellsByVRAM)
|
||||||
|
{
|
||||||
|
sortedPairs = pairsInGroup
|
||||||
.OrderByDescending(u => string.Equals(u.UserData.UID, groupDto.OwnerUID, StringComparison.Ordinal))
|
.OrderByDescending(u => string.Equals(u.UserData.UID, groupDto.OwnerUID, StringComparison.Ordinal))
|
||||||
.ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsModerator())
|
.ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsModerator())
|
||||||
.ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsPinned())
|
.ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsPinned())
|
||||||
.ThenBy(u => u.GetPairSortKey(), StringComparer.OrdinalIgnoreCase);
|
.ThenBy(u => u.GetPairSortKey(), StringComparer.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sortedPairs = pairsInGroup
|
||||||
|
.OrderByDescending(u => string.Equals(u.UserData.UID, groupDto.OwnerUID, StringComparison.Ordinal))
|
||||||
|
.ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsModerator())
|
||||||
|
.ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsPinned())
|
||||||
|
.ThenByDescending(u => u.LastAppliedApproximateVRAMBytes);
|
||||||
|
}
|
||||||
|
|
||||||
var visibleUsers = new List<DrawGroupPair>();
|
var visibleUsers = new List<DrawGroupPair>();
|
||||||
var onlineUsers = new List<DrawGroupPair>();
|
var onlineUsers = new List<DrawGroupPair>();
|
||||||
var offlineUsers = new List<DrawGroupPair>();
|
var offlineUsers = new List<DrawGroupPair>();
|
||||||
|
|
||||||
|
|
||||||
foreach (var pair in sortedPairs)
|
foreach (var pair in sortedPairs)
|
||||||
{
|
{
|
||||||
var drawPair = new DrawGroupPair(
|
var drawPair = new DrawGroupPair(
|
||||||
@@ -453,6 +466,8 @@ internal sealed class GroupPanel
|
|||||||
ImGui.TextUnformatted("Visible");
|
ImGui.TextUnformatted("Visible");
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
_uidDisplayHandler.RenderPairList(visibleUsers);
|
_uidDisplayHandler.RenderPairList(visibleUsers);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onlineUsers.Count > 0)
|
if (onlineUsers.Count > 0)
|
||||||
|
@@ -28,15 +28,15 @@ public class PairGroupsUi
|
|||||||
_uiSharedService = uiSharedService;
|
_uiSharedService = uiSharedService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Draw<T>(List<T> visibleUsers, List<T> onlineUsers, List<T> offlineUsers) where T : DrawPairBase
|
public void Draw<T>(List<T> visibleUsers, List<T> onlineUsers, List<T> pausedUsers, List<T> offlineUsers) where T : DrawPairBase
|
||||||
{
|
{
|
||||||
// Only render those tags that actually have pairs in them, otherwise
|
// Only render those tags that actually have pairs in them, otherwise
|
||||||
// we can end up with a bunch of useless pair groups
|
// we can end up with a bunch of useless pair groups
|
||||||
var tagsWithPairsInThem = _tagHandler.GetAllTagsSorted();
|
var tagsWithPairsInThem = _tagHandler.GetAllTagsSorted();
|
||||||
var allUsers = onlineUsers.Concat(offlineUsers).ToList();
|
var allUsers = onlineUsers.Concat(offlineUsers).Concat(pausedUsers).ToList();
|
||||||
if (typeof(T) == typeof(DrawUserPair))
|
if (typeof(T) == typeof(DrawUserPair))
|
||||||
{
|
{
|
||||||
DrawUserPairs(tagsWithPairsInThem, allUsers.Cast<DrawUserPair>().ToList(), visibleUsers.Cast<DrawUserPair>(), onlineUsers.Cast<DrawUserPair>(), offlineUsers.Cast<DrawUserPair>());
|
DrawUserPairs(tagsWithPairsInThem, allUsers.Cast<DrawUserPair>().ToList(), visibleUsers.Cast<DrawUserPair>(), onlineUsers.Cast<DrawUserPair>(), pausedUsers.Cast<DrawUserPair>(), offlineUsers.Cast<DrawUserPair>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,13 +91,19 @@ public class PairGroupsUi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawCategory(string tag, IEnumerable<DrawPairBase> onlineUsers, IEnumerable<DrawPairBase> allUsers, IEnumerable<DrawPairBase>? visibleUsers = null)
|
private void DrawCategory(string tag, IEnumerable<DrawPairBase> onlineUsers, IEnumerable<DrawPairBase> pausedUsers, IEnumerable<DrawPairBase> allUsers, IEnumerable<DrawPairBase>? visibleUsers = null)
|
||||||
{
|
{
|
||||||
IEnumerable<DrawPairBase> usersInThisTag;
|
IEnumerable<DrawPairBase> usersInThisTag;
|
||||||
HashSet<string>? otherUidsTaggedWithTag = null;
|
HashSet<string>? otherUidsTaggedWithTag = null;
|
||||||
bool isSpecialTag = false;
|
bool isSpecialTag = false;
|
||||||
int visibleInThisTag = 0;
|
int visibleInThisTag = 0;
|
||||||
if (tag is TagHandler.CustomOfflineTag or TagHandler.CustomOnlineTag or TagHandler.CustomVisibleTag or TagHandler.CustomUnpairedTag)
|
|
||||||
|
if (tag is TagHandler.CustomPausedTag)
|
||||||
|
{
|
||||||
|
usersInThisTag = pausedUsers;
|
||||||
|
isSpecialTag = true;
|
||||||
|
}
|
||||||
|
else if (tag is TagHandler.CustomOfflineTag or TagHandler.CustomOnlineTag or TagHandler.CustomVisibleTag or TagHandler.CustomUnpairedTag)
|
||||||
{
|
{
|
||||||
usersInThisTag = onlineUsers;
|
usersInThisTag = onlineUsers;
|
||||||
isSpecialTag = true;
|
isSpecialTag = true;
|
||||||
@@ -113,14 +119,13 @@ public class PairGroupsUi
|
|||||||
|
|
||||||
if (isSpecialTag && !usersInThisTag.Any()) return;
|
if (isSpecialTag && !usersInThisTag.Any()) return;
|
||||||
|
|
||||||
DrawName(tag, isSpecialTag, visibleInThisTag, usersInThisTag.Count(), otherUidsTaggedWithTag?.Count);
|
DrawName(tag, isSpecialTag, visibleInThisTag, usersInThisTag.Count(), pausedUsers.Count(), otherUidsTaggedWithTag?.Count);
|
||||||
if (!isSpecialTag)
|
if (!isSpecialTag)
|
||||||
{
|
{
|
||||||
using (ImRaii.PushId($"group-{tag}-buttons")) DrawButtons(tag, allUsers.Cast<DrawUserPair>().Where(p => otherUidsTaggedWithTag!.Contains(p.UID)).ToList());
|
using (ImRaii.PushId($"group-{tag}-buttons")) DrawButtons(tag, allUsers.Cast<DrawUserPair>().Where(p => otherUidsTaggedWithTag!.Contains(p.UID)).ToList());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Avoid uncomfortably close group names
|
|
||||||
if (!_tagHandler.IsTagOpen(tag))
|
if (!_tagHandler.IsTagOpen(tag))
|
||||||
{
|
{
|
||||||
var size = ImGui.CalcTextSize("").Y + ImGui.GetStyle().FramePadding.Y * 2f;
|
var size = ImGui.CalcTextSize("").Y + ImGui.GetStyle().FramePadding.Y * 2f;
|
||||||
@@ -151,18 +156,19 @@ public class PairGroupsUi
|
|||||||
UiSharedService.AttachToolTip($"Delete Group {tag} (Will not delete the pairs)" + Environment.NewLine + "Hold CTRL to delete");
|
UiSharedService.AttachToolTip($"Delete Group {tag} (Will not delete the pairs)" + Environment.NewLine + "Hold CTRL to delete");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawName(string tag, bool isSpecialTag, int visible, int online, int? total)
|
private void DrawName(string tag, bool isSpecialTag, int visible, int online, int paused, int? total)
|
||||||
{
|
{
|
||||||
string displayedName = tag switch
|
string displayedName = tag switch
|
||||||
{
|
{
|
||||||
TagHandler.CustomUnpairedTag => "Unpaired",
|
TagHandler.CustomUnpairedTag => "Unpaired",
|
||||||
TagHandler.CustomOfflineTag => "Offline",
|
TagHandler.CustomOfflineTag => "Offline",
|
||||||
TagHandler.CustomOnlineTag => _mareConfig.Current.ShowOfflineUsersSeparately ? "Online/Paused" : "Contacts",
|
TagHandler.CustomOnlineTag => _mareConfig.Current.ShowOfflineUsersSeparately ? "Online" : "Contacts",
|
||||||
|
TagHandler.CustomPausedTag => "Paused",
|
||||||
TagHandler.CustomVisibleTag => "Visible",
|
TagHandler.CustomVisibleTag => "Visible",
|
||||||
_ => tag
|
_ => tag
|
||||||
};
|
};
|
||||||
|
|
||||||
string resultFolderName = !isSpecialTag ? $"{displayedName} ({visible}/{online}/{total} Pairs)" : $"{displayedName} ({online} Pairs)";
|
string resultFolderName = !isSpecialTag ? $"{displayedName} ({visible}/{online}/{paused}/{total} Pairs)" : $"{displayedName} ({online} Pairs)";
|
||||||
|
|
||||||
// FontAwesomeIcon.CaretSquareDown : FontAwesomeIcon.CaretSquareRight
|
// FontAwesomeIcon.CaretSquareDown : FontAwesomeIcon.CaretSquareRight
|
||||||
var icon = _tagHandler.IsTagOpen(tag) ? FontAwesomeIcon.CaretSquareDown : FontAwesomeIcon.CaretSquareRight;
|
var icon = _tagHandler.IsTagOpen(tag) ? FontAwesomeIcon.CaretSquareDown : FontAwesomeIcon.CaretSquareRight;
|
||||||
@@ -184,7 +190,8 @@ public class PairGroupsUi
|
|||||||
ImGui.TextUnformatted($"Group {tag}");
|
ImGui.TextUnformatted($"Group {tag}");
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
ImGui.TextUnformatted($"{visible} Pairs visible");
|
ImGui.TextUnformatted($"{visible} Pairs visible");
|
||||||
ImGui.TextUnformatted($"{online} Pairs online/paused");
|
ImGui.TextUnformatted($"{online} Pairs online");
|
||||||
|
ImGui.TextUnformatted($"{paused} Pairs paused");
|
||||||
ImGui.TextUnformatted($"{total} Pairs total");
|
ImGui.TextUnformatted($"{total} Pairs total");
|
||||||
ImGui.EndTooltip();
|
ImGui.EndTooltip();
|
||||||
}
|
}
|
||||||
@@ -197,39 +204,45 @@ public class PairGroupsUi
|
|||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawUserPairs(List<string> tagsWithPairsInThem, List<DrawUserPair> allUsers, IEnumerable<DrawUserPair> visibleUsers, IEnumerable<DrawUserPair> onlineUsers, IEnumerable<DrawUserPair> offlineUsers)
|
private void DrawUserPairs(List<string> tagsWithPairsInThem, List<DrawUserPair> allUsers, IEnumerable<DrawUserPair> visibleUsers, IEnumerable<DrawUserPair> onlineUsers, IEnumerable<DrawUserPair> pausedUsers, IEnumerable<DrawUserPair> offlineUsers)
|
||||||
{
|
{
|
||||||
if (_mareConfig.Current.ShowVisibleUsersSeparately)
|
if (_mareConfig.Current.ShowVisibleUsersSeparately)
|
||||||
{
|
{
|
||||||
using (ImRaii.PushId("$group-VisibleCustomTag")) DrawCategory(TagHandler.CustomVisibleTag, visibleUsers, allUsers);
|
using (ImRaii.PushId("$group-VisibleCustomTag")) DrawCategory(TagHandler.CustomVisibleTag, visibleUsers, Enumerable.Empty<DrawUserPair>(), allUsers);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var tag in tagsWithPairsInThem)
|
foreach (var tag in tagsWithPairsInThem)
|
||||||
{
|
{
|
||||||
if (_mareConfig.Current.ShowOfflineUsersSeparately)
|
if (_mareConfig.Current.ShowOfflineUsersSeparately)
|
||||||
{
|
{
|
||||||
using (ImRaii.PushId($"group-{tag}")) DrawCategory(tag, onlineUsers, allUsers, visibleUsers);
|
using (ImRaii.PushId($"group-{tag}")) DrawCategory(tag, onlineUsers, pausedUsers, allUsers, visibleUsers);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
using (ImRaii.PushId($"group-{tag}")) DrawCategory(tag, allUsers, allUsers, visibleUsers);
|
using (ImRaii.PushId($"group-{tag}")) DrawCategory(tag, allUsers, Enumerable.Empty<DrawUserPair>(), allUsers, visibleUsers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_mareConfig.Current.ShowOfflineUsersSeparately)
|
if (_mareConfig.Current.ShowOfflineUsersSeparately)
|
||||||
{
|
{
|
||||||
using (ImRaii.PushId($"group-OnlineCustomTag")) DrawCategory(TagHandler.CustomOnlineTag,
|
using (ImRaii.PushId($"group-OnlineCustomTag")) DrawCategory(TagHandler.CustomOnlineTag,
|
||||||
onlineUsers.Where(u => !_tagHandler.HasAnyTag(u.UID)).ToList(), allUsers);
|
onlineUsers.Where(u => !_tagHandler.HasAnyTag(u.UID)).ToList(), Enumerable.Empty<DrawUserPair>(), allUsers);
|
||||||
|
if (pausedUsers.Any()) using (ImRaii.PushId("group-PausedCustomTag")) DrawCategory(TagHandler.CustomPausedTag,
|
||||||
|
Enumerable.Empty<DrawUserPair>(), pausedUsers, allUsers);
|
||||||
using (ImRaii.PushId($"group-OfflineCustomTag")) DrawCategory(TagHandler.CustomOfflineTag,
|
using (ImRaii.PushId($"group-OfflineCustomTag")) DrawCategory(TagHandler.CustomOfflineTag,
|
||||||
offlineUsers.Where(u => u.UserPair!.OtherPermissions.IsPaired()).ToList(), allUsers);
|
offlineUsers.Where(u => u.UserPair!.OtherPermissions.IsPaired()).ToList(), Enumerable.Empty<DrawUserPair>(), allUsers);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
using (ImRaii.PushId($"group-OnlineCustomTag")) DrawCategory(TagHandler.CustomOnlineTag,
|
using (ImRaii.PushId($"group-OnlineCustomTag")) DrawCategory(TagHandler.CustomOnlineTag,
|
||||||
onlineUsers.Concat(offlineUsers.Where(u => u.UserPair!.OtherPermissions.IsPaired())).Where(u => !_tagHandler.HasAnyTag(u.UID)).ToList(), allUsers);
|
onlineUsers.Concat(offlineUsers.Where(u => u.UserPair!.OtherPermissions.IsPaired())).Where(u => !_tagHandler.HasAnyTag(u.UID)).ToList(), Enumerable.Empty<DrawUserPair>(), allUsers);
|
||||||
}
|
}
|
||||||
|
|
||||||
using (ImRaii.PushId($"group-UnpairedCustomTag")) DrawCategory(TagHandler.CustomUnpairedTag,
|
using (ImRaii.PushId($"group-UnpairedCustomTag")) DrawCategory(TagHandler.CustomUnpairedTag,
|
||||||
offlineUsers.Where(u => !u.UserPair!.OtherPermissions.IsPaired()).ToList(), allUsers);
|
offlineUsers.Where(u => !u.UserPair!.OtherPermissions.IsPaired()).ToList(), Enumerable.Empty<DrawUserPair>(), allUsers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void PauseRemainingPairs(List<DrawUserPair> availablePairs)
|
private void PauseRemainingPairs(List<DrawUserPair> availablePairs)
|
||||||
{
|
{
|
||||||
foreach (var pairToPause in availablePairs.Where(pair => !pair.UserPair!.OwnPermissions.IsPaused()))
|
foreach (var pairToPause in availablePairs.Where(pair => !pair.UserPair!.OwnPermissions.IsPaused()))
|
||||||
|
@@ -203,10 +203,10 @@ public sealed class DtrEntry : IDisposable, IHostedService
|
|||||||
DtrStyle.Style4 => $"\xE03A {text}",
|
DtrStyle.Style4 => $"\xE03A {text}",
|
||||||
DtrStyle.Style5 => $"\xE033 {text}",
|
DtrStyle.Style5 => $"\xE033 {text}",
|
||||||
DtrStyle.Style6 => $"\xE038 {text}",
|
DtrStyle.Style6 => $"\xE038 {text}",
|
||||||
DtrStyle.Style7 => $"\xE05D {text}",
|
DtrStyle.Style7 => $"\xE044 {text}",
|
||||||
DtrStyle.Style8 => $"\xE03C{text}",
|
DtrStyle.Style8 => $"\xE03C{text}",
|
||||||
DtrStyle.Style9 => $"\xE040 {text} \xE041",
|
DtrStyle.Style9 => $"\xE040 {text} \xE041",
|
||||||
_ => $"\uE044 {text}"
|
_ => $"\uE05D {text}"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4,6 +4,7 @@ using Dalamud.Interface.Colors;
|
|||||||
using Dalamud.Interface.ImGuiFileDialog;
|
using Dalamud.Interface.ImGuiFileDialog;
|
||||||
using Dalamud.Interface.Textures.TextureWraps;
|
using Dalamud.Interface.Textures.TextureWraps;
|
||||||
using Dalamud.Interface.Utility;
|
using Dalamud.Interface.Utility;
|
||||||
|
using Dalamud.Utility;
|
||||||
using MareSynchronos.API.Data;
|
using MareSynchronos.API.Data;
|
||||||
using MareSynchronos.API.Dto.User;
|
using MareSynchronos.API.Dto.User;
|
||||||
using MareSynchronos.Services;
|
using MareSynchronos.Services;
|
||||||
@@ -28,14 +29,14 @@ public class EditProfileUi : WindowMediatorSubscriberBase
|
|||||||
private IDalamudTextureWrap? _pfpTextureWrap;
|
private IDalamudTextureWrap? _pfpTextureWrap;
|
||||||
private string _profileDescription = string.Empty;
|
private string _profileDescription = string.Empty;
|
||||||
private byte[] _profileImage = [];
|
private byte[] _profileImage = [];
|
||||||
private bool _showFileDialogError = false;
|
private string _showFileDialogError = string.Empty;
|
||||||
private bool _wasOpen;
|
private bool _wasOpen;
|
||||||
|
|
||||||
public EditProfileUi(ILogger<EditProfileUi> logger, MareMediator mediator,
|
public EditProfileUi(ILogger<EditProfileUi> logger, MareMediator mediator,
|
||||||
ApiController apiController, UiSharedService uiSharedService, FileDialogManager fileDialogManager,
|
ApiController apiController, UiSharedService uiSharedService, FileDialogManager fileDialogManager,
|
||||||
ServerConfigurationManager serverConfigurationManager,
|
ServerConfigurationManager serverConfigurationManager,
|
||||||
MareProfileManager mareProfileManager, PerformanceCollectorService performanceCollectorService)
|
MareProfileManager mareProfileManager, PerformanceCollectorService performanceCollectorService)
|
||||||
: base(logger, mediator, "Snowcloak Edit Profile###SnowcloakSyncEditProfileUI", performanceCollectorService)
|
: base(logger, mediator, "Snowcloak Profile Editor###SnowcloakSyncEditProfileUI", performanceCollectorService)
|
||||||
{
|
{
|
||||||
IsOpen = false;
|
IsOpen = false;
|
||||||
this.SizeConstraints = new()
|
this.SizeConstraints = new()
|
||||||
@@ -92,20 +93,13 @@ public class EditProfileUi : WindowMediatorSubscriberBase
|
|||||||
ImGui.Image(_pfpTextureWrap.Handle, ImGuiHelpers.ScaledVector2(_pfpTextureWrap.Width, _pfpTextureWrap.Height));
|
ImGui.Image(_pfpTextureWrap.Handle, ImGuiHelpers.ScaledVector2(_pfpTextureWrap.Width, _pfpTextureWrap.Height));
|
||||||
}
|
}
|
||||||
|
|
||||||
var spacing = ImGui.GetStyle().ItemSpacing.X;
|
var spacing = ImGui.GetStyle().ItemSpacing.X + 200;
|
||||||
ImGuiHelpers.ScaledRelativeSameLine(256, spacing);
|
ImGuiHelpers.ScaledRelativeSameLine(256, spacing);
|
||||||
using (_uiSharedService.GameFont.Push())
|
using (_uiSharedService.GameFont.Push())
|
||||||
{
|
{
|
||||||
var descriptionTextSize = ImGui.CalcTextSize(profile.Description, hideTextAfterDoubleHash: false, 256f);
|
var descriptionTextSize = ImGui.CalcTextSize(profile.Description, hideTextAfterDoubleHash: false, 256f);
|
||||||
var childFrame = ImGuiHelpers.ScaledVector2(256 + ImGui.GetStyle().WindowPadding.X + ImGui.GetStyle().WindowBorderSize, 256);
|
var childFrame = ImGuiHelpers.ScaledVector2(256 + ImGui.GetStyle().WindowPadding.X + ImGui.GetStyle().WindowBorderSize, 256);
|
||||||
if (descriptionTextSize.Y > childFrame.Y)
|
_adjustedForScollBarsOnlineProfile = (descriptionTextSize.Y > childFrame.Y);
|
||||||
{
|
|
||||||
_adjustedForScollBarsOnlineProfile = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_adjustedForScollBarsOnlineProfile = false;
|
|
||||||
}
|
|
||||||
childFrame = childFrame with
|
childFrame = childFrame with
|
||||||
{
|
{
|
||||||
X = childFrame.X + (_adjustedForScollBarsOnlineProfile ? ImGui.GetStyle().ScrollbarSize : 0),
|
X = childFrame.X + (_adjustedForScollBarsOnlineProfile ? ImGui.GetStyle().ScrollbarSize : 0),
|
||||||
@@ -122,9 +116,18 @@ public class EditProfileUi : WindowMediatorSubscriberBase
|
|||||||
ImGui.Checkbox("Is NSFW", ref nsfw);
|
ImGui.Checkbox("Is NSFW", ref nsfw);
|
||||||
ImGui.EndDisabled();
|
ImGui.EndDisabled();
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
_uiSharedService.BigText("Rules and Guidelines");
|
||||||
|
UiSharedService.ColorTextWrapped("Users that are paired with you (not paused) will be able to see your profile picture and description.", ImGuiColors.DalamudWhite);
|
||||||
|
UiSharedService.ColorTextWrapped("All users have the capability to report your profile if it violates the rules.", ImGuiColors.DalamudGrey);
|
||||||
|
UiSharedService.ColorTextWrapped(" - Please do NOT upload anything that can be considered highly illegal or obscene (beastiality, sexual acts depicting minors or anything representing a minor (including Lalafel), etc.)", ImGuiColors.DalamudRed);
|
||||||
|
UiSharedService.ColorTextWrapped(" - Please avoid the use of slurs, hate speech, threatening behaviour, etc.", ImGuiColors.DalamudRed);
|
||||||
|
UiSharedService.ColorTextWrapped(" - In the event we receive a report of an offensive profile, we may disable your profile forever or terminate your Snowcloak service account.", ImGuiColors.DalamudRed);
|
||||||
|
UiSharedService.ColorTextWrapped(" - You may not appeal any bans of your profile and or Snowcloak service account.", ImGuiColors.DalamudRed);
|
||||||
|
UiSharedService.ColorTextWrapped("Users who wish to mark their profile as NSFW should enable the toggle below.", ImGuiColors.DalamudWhite);
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
_uiSharedService.BigText("Profile Settings");
|
_uiSharedService.BigText("Profile Settings");
|
||||||
|
UiSharedService.ColorTextWrapped("Profile pictures must be cropped to 256x256px and have a file size of 250KiB or smaller.", ImGuiColors.DalamudGrey);
|
||||||
if (_uiSharedService.IconTextButton(FontAwesomeIcon.FileUpload, "Upload new profile picture"))
|
if (_uiSharedService.IconTextButton(FontAwesomeIcon.FileUpload, "Upload new profile picture"))
|
||||||
{
|
{
|
||||||
_fileDialogManager.OpenFileDialog("Select new Profile picture", ".png", (success, file) =>
|
_fileDialogManager.OpenFileDialog("Select new Profile picture", ".png", (success, file) =>
|
||||||
@@ -138,11 +141,10 @@ public class EditProfileUi : WindowMediatorSubscriberBase
|
|||||||
|
|
||||||
if (format.Width > 256 || format.Height > 256 || (fileContent.Length > 250 * 1024))
|
if (format.Width > 256 || format.Height > 256 || (fileContent.Length > 250 * 1024))
|
||||||
{
|
{
|
||||||
_showFileDialogError = true;
|
_showFileDialogError = format.Width > 256 || format.Height > 256 ? "ERROR: Image dimensions must be 256x256px or smaller." : fileContent.Length > 250 * 1024 ? "ERROR: File size was bigger than 250KiB" : "ERROR: An unknown error has occured.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
_showFileDialogError = string.Empty;
|
||||||
_showFileDialogError = false;
|
|
||||||
await _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), Disabled: false, IsNSFW: null, Convert.ToBase64String(fileContent), Description: null))
|
await _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), Disabled: false, IsNSFW: null, Convert.ToBase64String(fileContent), Description: null))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
});
|
});
|
||||||
@@ -155,9 +157,9 @@ public class EditProfileUi : WindowMediatorSubscriberBase
|
|||||||
_ = _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), Disabled: false, IsNSFW: null, "", Description: null));
|
_ = _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), Disabled: false, IsNSFW: null, "", Description: null));
|
||||||
}
|
}
|
||||||
UiSharedService.AttachToolTip("Clear your currently uploaded profile picture");
|
UiSharedService.AttachToolTip("Clear your currently uploaded profile picture");
|
||||||
if (_showFileDialogError)
|
if (!_showFileDialogError.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
UiSharedService.ColorTextWrapped("The profile picture must be a PNG file with a maximum height and width of 256px and 250KiB size", ImGuiColors.DalamudRed);
|
UiSharedService.ColorTextWrapped(_showFileDialogError, ImGuiColors.DalamudRed);
|
||||||
}
|
}
|
||||||
var isNsfw = profile.IsNSFW;
|
var isNsfw = profile.IsNSFW;
|
||||||
if (ImGui.Checkbox("Profile is NSFW", ref isNsfw))
|
if (ImGui.Checkbox("Profile is NSFW", ref isNsfw))
|
||||||
|
@@ -9,6 +9,7 @@ public class TagHandler
|
|||||||
public const string CustomOnlineTag = "Mare_Online";
|
public const string CustomOnlineTag = "Mare_Online";
|
||||||
public const string CustomUnpairedTag = "Mare_Unpaired";
|
public const string CustomUnpairedTag = "Mare_Unpaired";
|
||||||
public const string CustomVisibleTag = "Mare_Visible";
|
public const string CustomVisibleTag = "Mare_Visible";
|
||||||
|
public const string CustomPausedTag = "Mare_Paused";
|
||||||
private readonly ServerConfigurationManager _serverConfigurationManager;
|
private readonly ServerConfigurationManager _serverConfigurationManager;
|
||||||
|
|
||||||
public TagHandler(ServerConfigurationManager serverConfigurationManager)
|
public TagHandler(ServerConfigurationManager serverConfigurationManager)
|
||||||
|
@@ -151,7 +151,9 @@ public partial class IntroUi : WindowMediatorSubscriberBase
|
|||||||
UiSharedService.ColorText(readThis, ImGuiColors.DalamudRed);
|
UiSharedService.ColorText(readThis, ImGuiColors.DalamudRed);
|
||||||
ImGui.SetWindowFontScale(1.0f);
|
ImGui.SetWindowFontScale(1.0f);
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
|
UiSharedService.TextWrapped("""
|
||||||
|
To use Snowcloak, you must be over the age of 18, or 21 in some jurisdictions.
|
||||||
|
""");
|
||||||
UiSharedService.TextWrapped("""
|
UiSharedService.TextWrapped("""
|
||||||
All of the mod files currently active on your character as well as your current character state will be uploaded to the service you registered yourself at automatically. The plugin will exclusively upload the necessary mod files and not the whole mod.
|
All of the mod files currently active on your character as well as your current character state will be uploaded to the service you registered yourself at automatically. The plugin will exclusively upload the necessary mod files and not the whole mod.
|
||||||
""");
|
""");
|
||||||
@@ -165,7 +167,7 @@ public partial class IntroUi : WindowMediatorSubscriberBase
|
|||||||
The plugin creator tried their best to keep you secure. However, there is no guarantee for 100% security. Do not blindly pair your client with everyone.
|
The plugin creator tried their best to keep you secure. However, there is no guarantee for 100% security. Do not blindly pair your client with everyone.
|
||||||
""");
|
""");
|
||||||
UiSharedService.TextWrapped("""
|
UiSharedService.TextWrapped("""
|
||||||
Mod files that are saved on the service will remain on the service as long as there are requests for the files from clients. After a period of not being used, the mod files will be automatically deleted.
|
Mod files that are saved on the service will remain on the service as long as there are requests for the files from clients. After a period of not being used, the mod files may be automatically deleted.
|
||||||
""");
|
""");
|
||||||
UiSharedService.TextWrapped("""
|
UiSharedService.TextWrapped("""
|
||||||
Accounts that are inactive for ninety (90) days will be deleted for privacy reasons.
|
Accounts that are inactive for ninety (90) days will be deleted for privacy reasons.
|
||||||
@@ -261,6 +263,39 @@ public partial class IntroUi : WindowMediatorSubscriberBase
|
|||||||
ImGui.BeginDisabled(_registrationInProgress || _registrationSuccess || _secretKey.Length > 0);
|
ImGui.BeginDisabled(_registrationInProgress || _registrationSuccess || _secretKey.Length > 0);
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
ImGui.TextUnformatted("If you have not used Snowcloak before, click below to register a new account.");
|
ImGui.TextUnformatted("If you have not used Snowcloak before, click below to register a new account.");
|
||||||
|
if (_uiShared.IconTextButton(FontAwesomeIcon.Plus, "Log in with XIVAuth (experimental)"))
|
||||||
|
{
|
||||||
|
_registrationInProgress = true;
|
||||||
|
_ = Task.Run(async () => {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var reply = await _registerService.XIVAuth(CancellationToken.None).ConfigureAwait(false);
|
||||||
|
if (!reply.Success)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Registration failed: {err}", reply.ErrorMessage);
|
||||||
|
_registrationMessage = reply.ErrorMessage;
|
||||||
|
if (_registrationMessage.IsNullOrEmpty())
|
||||||
|
_registrationMessage = "An unknown error occured. Please try again later.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_registrationMessage = "Account registered. Welcome to Snowcloak!";
|
||||||
|
_secretKey = reply.SecretKey ?? "";
|
||||||
|
_registrationReply = reply;
|
||||||
|
_registrationSuccess = true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(ex, "Registration failed");
|
||||||
|
_registrationSuccess = false;
|
||||||
|
_registrationMessage = "An unknown error occured. Please try again later.";
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_registrationInProgress = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ImGui.SameLine();
|
||||||
if (_uiShared.IconTextButton(FontAwesomeIcon.Plus, "Register a new Snowcloak account"))
|
if (_uiShared.IconTextButton(FontAwesomeIcon.Plus, "Register a new Snowcloak account"))
|
||||||
{
|
{
|
||||||
_registrationInProgress = true;
|
_registrationInProgress = true;
|
||||||
@@ -296,7 +331,7 @@ public partial class IntroUi : WindowMediatorSubscriberBase
|
|||||||
ImGui.EndDisabled(); // _registrationInProgress || _registrationSuccess
|
ImGui.EndDisabled(); // _registrationInProgress || _registrationSuccess
|
||||||
if (_registrationInProgress)
|
if (_registrationInProgress)
|
||||||
{
|
{
|
||||||
ImGui.TextUnformatted("Sending request...");
|
ImGui.TextUnformatted("Waiting for the server...");
|
||||||
}
|
}
|
||||||
else if (!_registrationMessage.IsNullOrEmpty())
|
else if (!_registrationMessage.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
|
@@ -581,32 +581,32 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
_uiShared.BigText("Advanced");
|
_uiShared.BigText("Advanced");
|
||||||
|
|
||||||
bool mareApi = _configService.Current.MareAPI;
|
bool mareApi = _configService.Current.MareAPI;
|
||||||
if (ImGui.Checkbox("Enable Mare Synchronos API", ref mareApi))
|
if (ImGui.Checkbox("Enable Snowcloak Sync API", ref mareApi))
|
||||||
{
|
{
|
||||||
_configService.Current.MareAPI = mareApi;
|
_configService.Current.MareAPI = mareApi;
|
||||||
_configService.Save();
|
_configService.Save();
|
||||||
_ipcProvider.HandleMareImpersonation();
|
_ipcProvider.HandleMareImpersonation();
|
||||||
}
|
}
|
||||||
_uiShared.DrawHelpText("Enables handling of the Mare Synchronos API. This currently includes:\n\n" +
|
_uiShared.DrawHelpText("Enables handling of the Snowcloak Sync API. This currently includes:\n\n" +
|
||||||
" - MCDF loading support for other plugins\n" +
|
" - MCDF loading support for other plugins\n" +
|
||||||
" - Blocking Moodles applications to paired users\n\n" +
|
" - Blocking Moodles applications to paired users\n\n" +
|
||||||
"If the Mare Synchronos plugin is loaded while this option is enabled, control of its API will be relinquished.");
|
"If the Snowcloak Sync plugin is loaded while this option is enabled, control of its API will be relinquished.");
|
||||||
|
|
||||||
using (_ = ImRaii.PushIndent())
|
using (_ = ImRaii.PushIndent())
|
||||||
{
|
{
|
||||||
ImGui.SameLine(300.0f * ImGuiHelpers.GlobalScale);
|
ImGui.SameLine(300.0f * ImGuiHelpers.GlobalScale);
|
||||||
if (_ipcProvider.ImpersonationActive)
|
if (_ipcProvider.ImpersonationActive)
|
||||||
{
|
{
|
||||||
UiSharedService.ColorTextWrapped("Mare API active!", ImGuiColors.HealerGreen);
|
UiSharedService.ColorTextWrapped("Snowcloak API active!", ImGuiColors.HealerGreen);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!mareApi)
|
if (!mareApi)
|
||||||
UiSharedService.ColorTextWrapped("Mare API inactive: Option is disabled", ImGuiColors.DalamudYellow);
|
UiSharedService.ColorTextWrapped("Snowcloak API inactive: Option is disabled", ImGuiColors.DalamudYellow);
|
||||||
else if (_ipcProvider.MarePluginEnabled)
|
else if (_ipcProvider.MarePluginEnabled)
|
||||||
UiSharedService.ColorTextWrapped("Mare API inactive: Mare plugin is loaded", ImGuiColors.DalamudYellow);
|
UiSharedService.ColorTextWrapped("Snowcloak API inactive: Snowcloak plugin is loaded", ImGuiColors.DalamudYellow);
|
||||||
else
|
else
|
||||||
UiSharedService.ColorTextWrapped("Mare API inactive: Unknown reason", ImGuiColors.DalamudRed);
|
UiSharedService.ColorTextWrapped("Snowcloak API inactive: Unknown reason", ImGuiColors.DalamudRed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -956,6 +956,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
_uiShared.BigText("UI");
|
_uiShared.BigText("UI");
|
||||||
var showCharacterNames = _configService.Current.ShowCharacterNames;
|
var showCharacterNames = _configService.Current.ShowCharacterNames;
|
||||||
var showVisibleSeparate = _configService.Current.ShowVisibleUsersSeparately;
|
var showVisibleSeparate = _configService.Current.ShowVisibleUsersSeparately;
|
||||||
|
var sortSyncshellByVRAM = _configService.Current.SortSyncshellsByVRAM;
|
||||||
var showOfflineSeparate = _configService.Current.ShowOfflineUsersSeparately;
|
var showOfflineSeparate = _configService.Current.ShowOfflineUsersSeparately;
|
||||||
var showProfiles = _configService.Current.ProfilesShow;
|
var showProfiles = _configService.Current.ProfilesShow;
|
||||||
var showNsfwProfiles = _configService.Current.ProfilesAllowNsfw;
|
var showNsfwProfiles = _configService.Current.ProfilesAllowNsfw;
|
||||||
@@ -1074,13 +1075,20 @@ public class SettingsUi : WindowMediatorSubscriberBase
|
|||||||
_configService.Save();
|
_configService.Save();
|
||||||
}
|
}
|
||||||
_uiShared.DrawHelpText("This will show all currently visible users in a special 'Visible' group in the main UI.");
|
_uiShared.DrawHelpText("This will show all currently visible users in a special 'Visible' group in the main UI.");
|
||||||
|
if (ImGui.Checkbox("Sort visible syncshell users by VRAM usage", ref sortSyncshellByVRAM))
|
||||||
|
{
|
||||||
|
_configService.Current.SortSyncshellsByVRAM = sortSyncshellByVRAM;
|
||||||
|
_logger.LogWarning("Changing value: {sortSyncshellsByVRAM}", sortSyncshellByVRAM);
|
||||||
|
|
||||||
if (ImGui.Checkbox("Show separate Offline group", ref showOfflineSeparate))
|
_configService.Save();
|
||||||
|
}
|
||||||
|
_uiShared.DrawHelpText("This will put users using the most VRAM in a syncshell at the top of the list.");
|
||||||
|
if (ImGui.Checkbox("Group users by connection status", ref showOfflineSeparate))
|
||||||
{
|
{
|
||||||
_configService.Current.ShowOfflineUsersSeparately = showOfflineSeparate;
|
_configService.Current.ShowOfflineUsersSeparately = showOfflineSeparate;
|
||||||
_configService.Save();
|
_configService.Save();
|
||||||
}
|
}
|
||||||
_uiShared.DrawHelpText("This will show all currently offline users in a special 'Offline' group in the main UI.");
|
_uiShared.DrawHelpText("This will categorize users by their connection status in the main UI.");
|
||||||
|
|
||||||
if (ImGui.Checkbox("Show player names", ref showCharacterNames))
|
if (ImGui.Checkbox("Show player names", ref showCharacterNames))
|
||||||
{
|
{
|
||||||
|
@@ -851,16 +851,6 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase
|
|||||||
ImGui.TextColored(ImGuiColors.DalamudRed, "You need to install both Penumbra and Glamourer and keep them up to date to use Snowcloak.");
|
ImGui.TextColored(ImGuiColors.DalamudRed, "You need to install both Penumbra and Glamourer and keep them up to date to use Snowcloak.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (NoSnapService.AnyLoaded)
|
|
||||||
{
|
|
||||||
IconText(FontAwesomeIcon.ExclamationTriangle, ImGuiColors.DalamudYellow);
|
|
||||||
ImGui.SameLine();
|
|
||||||
var cursorX = ImGui.GetCursorPosX();
|
|
||||||
ImGui.TextColored(ImGuiColors.DalamudYellow, "Synced player appearances will not apply until incompatible plugins are disabled:");
|
|
||||||
ImGui.SetCursorPosX(cursorX + 16.0f);
|
|
||||||
ImGui.TextColored(ImGuiColors.DalamudYellow, NoSnapService.ActivePlugins);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@@ -20,7 +20,7 @@ public class PngHdr
|
|||||||
|
|
||||||
stream.ReadExactly(buffer[..8]);
|
stream.ReadExactly(buffer[..8]);
|
||||||
|
|
||||||
uint ihdrLength = BitConverter.ToUInt32(buffer);
|
uint ihdrLength = ReadBigEndianUInt32(buffer[..4]);
|
||||||
|
|
||||||
// The next four bytes will be the length of the IHDR section (it should be 13 bytes but we only need 8)
|
// The next four bytes will be the length of the IHDR section (it should be 13 bytes but we only need 8)
|
||||||
if (ihdrLength < 8)
|
if (ihdrLength < 8)
|
||||||
@@ -32,8 +32,8 @@ public class PngHdr
|
|||||||
|
|
||||||
stream.ReadExactly(buffer[..8]);
|
stream.ReadExactly(buffer[..8]);
|
||||||
|
|
||||||
uint width = BitConverter.ToUInt32(buffer);
|
uint width = ReadBigEndianUInt32(buffer[..4]);
|
||||||
uint height = BitConverter.ToUInt32(buffer[4..]);
|
uint height = ReadBigEndianUInt32(buffer[4..8]);
|
||||||
|
|
||||||
// Validate the width/height are non-negative and... that's all we care about!
|
// Validate the width/height are non-negative and... that's all we care about!
|
||||||
if (width > int.MaxValue || height > int.MaxValue)
|
if (width > int.MaxValue || height > int.MaxValue)
|
||||||
@@ -46,4 +46,12 @@ public class PngHdr
|
|||||||
return InvalidSize;
|
return InvalidSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Minimal helper for big-endian conversion
|
||||||
|
private static uint ReadBigEndianUInt32(ReadOnlySpan<byte> bytes)
|
||||||
|
{
|
||||||
|
return ((uint)bytes[0] << 24) |
|
||||||
|
((uint)bytes[1] << 16) |
|
||||||
|
((uint)bytes[2] << 8) |
|
||||||
|
bytes[3];
|
||||||
|
}
|
||||||
}
|
}
|
@@ -9,6 +9,8 @@ using System.Net.Http.Headers;
|
|||||||
using System.Net.Http.Json;
|
using System.Net.Http.Json;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
using Dalamud.Utility;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
namespace MareSynchronos.WebAPI;
|
namespace MareSynchronos.WebAPI;
|
||||||
|
|
||||||
@@ -17,18 +19,18 @@ public sealed class AccountRegistrationService : IDisposable
|
|||||||
private readonly HttpClient _httpClient;
|
private readonly HttpClient _httpClient;
|
||||||
private readonly ILogger<AccountRegistrationService> _logger;
|
private readonly ILogger<AccountRegistrationService> _logger;
|
||||||
private readonly ServerConfigurationManager _serverManager;
|
private readonly ServerConfigurationManager _serverManager;
|
||||||
private readonly RemoteConfigurationService _remoteConfig;
|
private readonly DalamudUtilService _dalamudUtilService;
|
||||||
|
|
||||||
private string GenerateSecretKey()
|
private string GenerateSecretKey()
|
||||||
{
|
{
|
||||||
return Convert.ToHexString(SHA256.HashData(RandomNumberGenerator.GetBytes(64)));
|
return Convert.ToHexString(SHA256.HashData(RandomNumberGenerator.GetBytes(64)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public AccountRegistrationService(ILogger<AccountRegistrationService> logger, ServerConfigurationManager serverManager, RemoteConfigurationService remoteConfig)
|
public AccountRegistrationService(ILogger<AccountRegistrationService> logger, DalamudUtilService dalamudUtilService, ServerConfigurationManager serverManager)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_serverManager = serverManager;
|
_serverManager = serverManager;
|
||||||
_remoteConfig = remoteConfig;
|
_dalamudUtilService = dalamudUtilService;
|
||||||
_httpClient = new(
|
_httpClient = new(
|
||||||
new HttpClientHandler
|
new HttpClientHandler
|
||||||
{
|
{
|
||||||
@@ -45,24 +47,78 @@ public sealed class AccountRegistrationService : IDisposable
|
|||||||
_httpClient.Dispose();
|
_httpClient.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<RegisterReplyDto> RegisterAccount(CancellationToken token)
|
public async Task<RegisterReplyDto> XIVAuth(CancellationToken token)
|
||||||
{
|
{
|
||||||
var authApiUrl = _serverManager.CurrentApiUrl;
|
var secretKey = GenerateSecretKey();
|
||||||
|
var hashedSecretKey = secretKey.GetHash256();
|
||||||
|
var playerName = _dalamudUtilService.GetPlayerNameAsync().GetAwaiter().GetResult();
|
||||||
|
var worldId = (ushort)_dalamudUtilService.GetHomeWorldIdAsync().GetAwaiter().GetResult();
|
||||||
|
var worldName = _dalamudUtilService.WorldData.Value[(worldId)];
|
||||||
|
|
||||||
// Override the API URL used for auth from remote config, if one is available
|
|
||||||
if (authApiUrl.Equals(ApiController.SnowcloakServiceUri, StringComparison.Ordinal))
|
|
||||||
|
var sessionID = Convert.ToBase64String(RandomNumberGenerator.GetBytes(32)).Replace('+', '-').Replace('/', '_').TrimEnd('=');
|
||||||
|
|
||||||
|
Uri handshakeUri = new Uri("https://account.snowcloak-sync.com/register");
|
||||||
|
var handshakePayload = new { session_id = sessionID, hashed_secret = hashedSecretKey, character_name = playerName, home_world = worldName };
|
||||||
|
var handshakeResponse = await _httpClient.PostAsJsonAsync(handshakeUri, handshakePayload, token).ConfigureAwait(false);
|
||||||
|
handshakeResponse.EnsureSuccessStatusCode();
|
||||||
|
var register = await handshakeResponse.Content.ReadFromJsonAsync<RegisterResponse>(cancellationToken: token)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
if (register is null || string.IsNullOrWhiteSpace(register.link_url) ||
|
||||||
|
string.IsNullOrWhiteSpace(register.poll_url))
|
||||||
{
|
{
|
||||||
var config = await _remoteConfig.GetConfigAsync<HubConnectionConfig>("mainServer").ConfigureAwait(false) ?? new();
|
return new RegisterReplyDto() { Success = false, ErrorMessage = "Malformed registration response." };
|
||||||
if (!string.IsNullOrEmpty(config.ApiUrl))
|
|
||||||
authApiUrl = config.ApiUrl;
|
|
||||||
else
|
|
||||||
authApiUrl = ApiController.SnowcloakServiceApiUri;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Util.OpenLink(register.link_url);
|
||||||
|
const int maxAttempts = 600 / 15; // Try once every 15 seconds for 10 minutes
|
||||||
|
var pollUri = new Uri(register.poll_url);
|
||||||
|
PollResponse? lastPoll = null;
|
||||||
|
for (int i = 0; i < maxAttempts; i++)
|
||||||
|
{
|
||||||
|
token.ThrowIfCancellationRequested();
|
||||||
|
using var resp = await _httpClient.GetAsync(pollUri, token).ConfigureAwait(false);
|
||||||
|
if (resp.StatusCode == HttpStatusCode.Gone)
|
||||||
|
{
|
||||||
|
// Server marked this as having been consumed already OR it got TLL'd out
|
||||||
|
return new RegisterReplyDto()
|
||||||
|
{
|
||||||
|
Success = false, ErrorMessage = "Registration session expired. Please try again."
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resp.StatusCode == HttpStatusCode.OK)
|
||||||
|
{
|
||||||
|
lastPoll = await resp.Content.ReadFromJsonAsync<PollResponse>(cancellationToken: token)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
if (lastPoll?.status?.Equals("bound", StringComparison.OrdinalIgnoreCase) == true)
|
||||||
|
{
|
||||||
|
// yay
|
||||||
|
return new RegisterReplyDto()
|
||||||
|
{
|
||||||
|
Success = true, ErrorMessage = null, UID = lastPoll?.uid, SecretKey = secretKey
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Pending, keep polling
|
||||||
|
}
|
||||||
|
await Task.Delay(TimeSpan.FromSeconds(15), token).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
// Timed out
|
||||||
|
return new RegisterReplyDto()
|
||||||
|
{
|
||||||
|
Success = false,
|
||||||
|
ErrorMessage =
|
||||||
|
"Timed out waiting for authorisation. Please try again, and complete the process within 10 minutes."
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
public async Task<RegisterReplyDto> RegisterAccount(CancellationToken token)
|
||||||
|
{
|
||||||
var secretKey = GenerateSecretKey();
|
var secretKey = GenerateSecretKey();
|
||||||
var hashedSecretKey = secretKey.GetHash256();
|
var hashedSecretKey = secretKey.GetHash256();
|
||||||
|
|
||||||
Uri postUri = MareAuth.AuthRegisterV2FullPath(new Uri(authApiUrl
|
Uri postUri = MareAuth.AuthRegisterV2FullPath(new Uri(_serverManager.CurrentApiUrl
|
||||||
.Replace("wss://", "https://", StringComparison.OrdinalIgnoreCase)
|
.Replace("wss://", "https://", StringComparison.OrdinalIgnoreCase)
|
||||||
.Replace("ws://", "http://", StringComparison.OrdinalIgnoreCase)));
|
.Replace("ws://", "http://", StringComparison.OrdinalIgnoreCase)));
|
||||||
|
|
||||||
@@ -81,4 +137,19 @@ public sealed class AccountRegistrationService : IDisposable
|
|||||||
SecretKey = secretKey
|
SecretKey = secretKey
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private sealed class RegisterResponse
|
||||||
|
{
|
||||||
|
public string link_url { get; set; } = "";
|
||||||
|
public string poll_url { get; set; } = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class PollResponse
|
||||||
|
{
|
||||||
|
public string status { get; set; } = "";
|
||||||
|
public string? uid { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using MareSynchronos.API.Data;
|
using MareSynchronos.API.Data;
|
||||||
|
using MareSynchronos.API.Dto.Group;
|
||||||
using MareSynchronos.API.Dto.User;
|
using MareSynchronos.API.Dto.User;
|
||||||
using Microsoft.AspNetCore.SignalR.Client;
|
using Microsoft.AspNetCore.SignalR.Client;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
@@ -19,10 +19,10 @@ public partial class ApiController
|
|||||||
await _mareHub!.SendAsync(nameof(GroupChangeGroupPermissionState), dto).ConfigureAwait(false);
|
await _mareHub!.SendAsync(nameof(GroupChangeGroupPermissionState), dto).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task GroupChangeIndividualPermissionState(GroupPairUserPermissionDto dto)
|
public Task GroupChangeIndividualPermissionState(GroupPairUserPermissionDto dto)
|
||||||
{
|
{
|
||||||
CheckConnection();
|
CheckConnection();
|
||||||
await _mareHub!.SendAsync(nameof(GroupChangeIndividualPermissionState), dto).ConfigureAwait(false);
|
return _mareHub!.InvokeAsync(nameof(GroupChangeIndividualPermissionState), dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task GroupChangeOwnership(GroupPairDto groupPair)
|
public async Task GroupChangeOwnership(GroupPairDto groupPair)
|
||||||
|
@@ -121,7 +121,7 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IM
|
|||||||
{
|
{
|
||||||
Logger.LogWarning("Multiple secret keys for current character");
|
Logger.LogWarning("Multiple secret keys for current character");
|
||||||
_connectionDto = null;
|
_connectionDto = null;
|
||||||
Mediator.Publish(new NotificationMessage("Multiple Identical Characters detected", "Your Service configuration has multiple characters with the same name and world set up. Delete the duplicates in the character management to be able to connect to Mare.",
|
Mediator.Publish(new NotificationMessage("Multiple Identical Characters detected", "Your Service configuration has multiple characters with the same name and world set up. Delete the duplicates in the character management to be able to connect.",
|
||||||
NotificationType.Error));
|
NotificationType.Error));
|
||||||
await StopConnection(ServerState.MultiChara).ConfigureAwait(false);
|
await StopConnection(ServerState.MultiChara).ConfigureAwait(false);
|
||||||
_connectionCancellationTokenSource?.Cancel();
|
_connectionCancellationTokenSource?.Cancel();
|
||||||
@@ -183,6 +183,8 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IM
|
|||||||
|
|
||||||
_connectionDto = await GetConnectionDto().ConfigureAwait(false);
|
_connectionDto = await GetConnectionDto().ConfigureAwait(false);
|
||||||
|
|
||||||
|
await CheckClientHealth().ConfigureAwait(false);
|
||||||
|
|
||||||
ServerState = ServerState.Connected;
|
ServerState = ServerState.Connected;
|
||||||
|
|
||||||
var currentClientVer = Assembly.GetExecutingAssembly().GetName().Version!;
|
var currentClientVer = Assembly.GetExecutingAssembly().GetName().Version!;
|
||||||
@@ -314,8 +316,12 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IM
|
|||||||
while (!ct.IsCancellationRequested && _mareHub != null)
|
while (!ct.IsCancellationRequested && _mareHub != null)
|
||||||
{
|
{
|
||||||
await Task.Delay(TimeSpan.FromSeconds(30), ct).ConfigureAwait(false);
|
await Task.Delay(TimeSpan.FromSeconds(30), ct).ConfigureAwait(false);
|
||||||
Logger.LogDebug("Checking Client Health State");
|
var healthy = await CheckClientHealth().ConfigureAwait(false);
|
||||||
_ = await CheckClientHealth().ConfigureAwait(false);
|
if (!healthy || _mareHub.State != HubConnectionState.Connected)
|
||||||
|
{
|
||||||
|
Logger.LogWarning("Health check failed, forcing reconnect. ClientHealth: {0} HubConnected: {1}", healthy, _mareHub.State != HubConnectionState.Connected);
|
||||||
|
await ForceResetConnection().ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,5 +484,30 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IM
|
|||||||
|
|
||||||
ServerState = state;
|
ServerState = state;
|
||||||
}
|
}
|
||||||
|
//Because this plugin really likes to bug out with connections, lets "fix" it....
|
||||||
|
public async Task ForceResetConnection()
|
||||||
|
{
|
||||||
|
if (!_initialized) return;
|
||||||
|
Logger.LogInformation("ForceReconnect called");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await StopConnection(ServerState.Disconnected).ConfigureAwait(false);
|
||||||
|
|
||||||
|
// Cancel any ongoing health checks to prevent conflicts
|
||||||
|
_healthCheckTokenSource?.Cancel();
|
||||||
|
_healthCheckTokenSource?.Dispose();
|
||||||
|
_healthCheckTokenSource = null;
|
||||||
|
|
||||||
|
await CreateConnections().ConfigureAwait(false);
|
||||||
|
|
||||||
|
Logger.LogInformation("ForceReconnect completed successfully");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogError(ex, "Failure during ForceReconnect, disconnecting");
|
||||||
|
await StopConnection(ServerState.Disconnected).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#pragma warning restore MA0040
|
#pragma warning restore MA0040
|
@@ -19,7 +19,6 @@ public class HubFactory : MediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
private readonly ILoggerProvider _loggingProvider;
|
private readonly ILoggerProvider _loggingProvider;
|
||||||
private readonly ServerConfigurationManager _serverConfigurationManager;
|
private readonly ServerConfigurationManager _serverConfigurationManager;
|
||||||
private readonly RemoteConfigurationService _remoteConfig;
|
|
||||||
private readonly TokenProvider _tokenProvider;
|
private readonly TokenProvider _tokenProvider;
|
||||||
private HubConnection? _instance;
|
private HubConnection? _instance;
|
||||||
private string _cachedConfigFor = string.Empty;
|
private string _cachedConfigFor = string.Empty;
|
||||||
@@ -27,11 +26,10 @@ public class HubFactory : MediatorSubscriberBase
|
|||||||
private bool _isDisposed = false;
|
private bool _isDisposed = false;
|
||||||
|
|
||||||
public HubFactory(ILogger<HubFactory> logger, MareMediator mediator,
|
public HubFactory(ILogger<HubFactory> logger, MareMediator mediator,
|
||||||
ServerConfigurationManager serverConfigurationManager, RemoteConfigurationService remoteConfig,
|
ServerConfigurationManager serverConfigurationManager,
|
||||||
TokenProvider tokenProvider, ILoggerProvider pluginLog) : base(logger, mediator)
|
TokenProvider tokenProvider, ILoggerProvider pluginLog) : base(logger, mediator)
|
||||||
{
|
{
|
||||||
_serverConfigurationManager = serverConfigurationManager;
|
_serverConfigurationManager = serverConfigurationManager;
|
||||||
_remoteConfig = remoteConfig;
|
|
||||||
_tokenProvider = tokenProvider;
|
_tokenProvider = tokenProvider;
|
||||||
_loggingProvider = pluginLog;
|
_loggingProvider = pluginLog;
|
||||||
}
|
}
|
||||||
@@ -87,16 +85,6 @@ public class HubFactory : MediatorSubscriberBase
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_serverConfigurationManager.CurrentApiUrl.Equals(ApiController.SnowcloakServiceUri, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
var mainServerConfig = await _remoteConfig.GetConfigAsync<HubConnectionConfig>("mainServer").ConfigureAwait(false) ?? new();
|
|
||||||
defaultConfig = mainServerConfig;
|
|
||||||
if (string.IsNullOrEmpty(mainServerConfig.ApiUrl))
|
|
||||||
defaultConfig.ApiUrl = ApiController.SnowcloakServiceApiUri;
|
|
||||||
if (string.IsNullOrEmpty(mainServerConfig.HubUrl))
|
|
||||||
defaultConfig.HubUrl = ApiController.SnowcloakServiceHubUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
string jsonResponse;
|
string jsonResponse;
|
||||||
|
|
||||||
if (stapledWellKnown != null)
|
if (stapledWellKnown != null)
|
||||||
|
@@ -20,16 +20,14 @@ public sealed class TokenProvider : IDisposable, IMediatorSubscriber
|
|||||||
private readonly HttpClient _httpClient;
|
private readonly HttpClient _httpClient;
|
||||||
private readonly ILogger<TokenProvider> _logger;
|
private readonly ILogger<TokenProvider> _logger;
|
||||||
private readonly ServerConfigurationManager _serverManager;
|
private readonly ServerConfigurationManager _serverManager;
|
||||||
private readonly RemoteConfigurationService _remoteConfig;
|
|
||||||
private readonly ConcurrentDictionary<JwtIdentifier, string> _tokenCache = new();
|
private readonly ConcurrentDictionary<JwtIdentifier, string> _tokenCache = new();
|
||||||
private readonly ConcurrentDictionary<string, string?> _wellKnownCache = new(StringComparer.Ordinal);
|
private readonly ConcurrentDictionary<string, string?> _wellKnownCache = new(StringComparer.Ordinal);
|
||||||
|
|
||||||
public TokenProvider(ILogger<TokenProvider> logger, ServerConfigurationManager serverManager, RemoteConfigurationService remoteConfig,
|
public TokenProvider(ILogger<TokenProvider> logger, ServerConfigurationManager serverManager,
|
||||||
DalamudUtilService dalamudUtil, MareMediator mareMediator)
|
DalamudUtilService dalamudUtil, MareMediator mareMediator)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_serverManager = serverManager;
|
_serverManager = serverManager;
|
||||||
_remoteConfig = remoteConfig;
|
|
||||||
_dalamudUtil = dalamudUtil;
|
_dalamudUtil = dalamudUtil;
|
||||||
_httpClient = new(
|
_httpClient = new(
|
||||||
new HttpClientHandler
|
new HttpClientHandler
|
||||||
@@ -70,23 +68,11 @@ public sealed class TokenProvider : IDisposable, IMediatorSubscriber
|
|||||||
Uri tokenUri;
|
Uri tokenUri;
|
||||||
HttpResponseMessage result;
|
HttpResponseMessage result;
|
||||||
|
|
||||||
var authApiUrl = _serverManager.CurrentApiUrl;
|
|
||||||
|
|
||||||
// Override the API URL used for auth from remote config, if one is available
|
|
||||||
if (authApiUrl.Equals(ApiController.SnowcloakServiceUri, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
var config = await _remoteConfig.GetConfigAsync<HubConnectionConfig>("mainServer").ConfigureAwait(false) ?? new();
|
|
||||||
if (!string.IsNullOrEmpty(config.ApiUrl))
|
|
||||||
authApiUrl = config.ApiUrl;
|
|
||||||
else
|
|
||||||
authApiUrl = ApiController.SnowcloakServiceApiUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_logger.LogDebug("GetNewToken: Requesting");
|
_logger.LogDebug("GetNewToken: Requesting");
|
||||||
|
|
||||||
tokenUri = MareAuth.AuthV2FullPath(new Uri(authApiUrl
|
tokenUri = MareAuth.AuthV2FullPath(new Uri(_serverManager.CurrentApiUrl
|
||||||
.Replace("wss://", "https://", StringComparison.OrdinalIgnoreCase)
|
.Replace("wss://", "https://", StringComparison.OrdinalIgnoreCase)
|
||||||
.Replace("ws://", "http://", StringComparison.OrdinalIgnoreCase)));
|
.Replace("ws://", "http://", StringComparison.OrdinalIgnoreCase)));
|
||||||
var secretKey = _serverManager.GetSecretKey(out _)!;
|
var secretKey = _serverManager.GetSecretKey(out _)!;
|
||||||
|
BIN
MareSynchronos/images/logo.png
Normal file
BIN
MareSynchronos/images/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 68 KiB |
@@ -10,9 +10,9 @@
|
|||||||
},
|
},
|
||||||
"DalamudPackager": {
|
"DalamudPackager": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[13.0.0, )",
|
"requested": "[13.1.0, )",
|
||||||
"resolved": "13.0.0",
|
"resolved": "13.1.0",
|
||||||
"contentHash": "Mb3cUDSK/vDPQ8gQIeuCw03EMYrej1B4J44a1AvIJ9C759p9XeqdU9Hg4WgOmlnlPe0G7ILTD32PKSUpkQNa8w=="
|
"contentHash": "XdoNhJGyFby5M/sdcRhnc5xTop9PHy+H50PTWpzLhJugjB19EDBiHD/AsiDF66RETM+0qKUdJBZrNuebn7qswQ=="
|
||||||
},
|
},
|
||||||
"DotNet.ReproducibleBuilds": {
|
"DotNet.ReproducibleBuilds": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
@@ -22,11 +22,11 @@
|
|||||||
},
|
},
|
||||||
"Downloader": {
|
"Downloader": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[3.3.4, )",
|
"requested": "[4.0.3, )",
|
||||||
"resolved": "3.3.4",
|
"resolved": "4.0.3",
|
||||||
"contentHash": "/M/c80e1L0WW1XrLSSiQhgFxk8rrfbpWiWDn2CeBg1tPD393Neo+v184yG/ThyhE9rrNp36yCrugiCmEbRf+VQ==",
|
"contentHash": "Vg1+UqPDstpMw2CKXV9XvB8jKHC95KQfbqPxQXvOMRMFnTov4Ixvvw6GZV5DXLnKuL2sfnmVYX9CaQtcURia1Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.Logging.Abstractions": "8.0.1"
|
"Microsoft.Extensions.Logging.Abstractions": "8.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Glamourer.Api": {
|
"Glamourer.Api": {
|
||||||
@@ -55,67 +55,84 @@
|
|||||||
"System.IO.Pipelines": "6.0.3"
|
"System.IO.Pipelines": "6.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"MessagePack": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[3.1.4, )",
|
||||||
|
"resolved": "3.1.4",
|
||||||
|
"contentHash": "BH0wlHWmVoZpbAPyyt2Awbq30C+ZsS3eHSkYdnyUAbqVJ22fAJDzn2xTieBeoT5QlcBzp61vHcv878YJGfi3mg==",
|
||||||
|
"dependencies": {
|
||||||
|
"MessagePack.Annotations": "3.1.4",
|
||||||
|
"MessagePackAnalyzer": "3.1.4",
|
||||||
|
"Microsoft.NET.StringTools": "17.11.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"MessagePack.Annotations": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[3.1.4, )",
|
||||||
|
"resolved": "3.1.4",
|
||||||
|
"contentHash": "aVWrDAkCdqxwQsz/q0ldPh2EFn48M99YUzE9OvZjMq2RNLKz4o2z88iGFvSvbMqOWRweRvKPHBJZe22PRqzslQ=="
|
||||||
|
},
|
||||||
"Meziantou.Analyzer": {
|
"Meziantou.Analyzer": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[2.0.212, )",
|
"requested": "[2.0.219, )",
|
||||||
"resolved": "2.0.212",
|
"resolved": "2.0.219",
|
||||||
"contentHash": "U91ktjjTRTccUs3Lk+hrLD9vW+2+lhnsOf4G1GpRSJi1pLn3uK5CU6wGP9Bmz1KlJs6Oz1GGoMhxQBoqQsmAuQ=="
|
"contentHash": "vknqxTO59DkRmsuyA3GoQ8zLODHTVrt2enVozcRLY22D3LRJm3qRNYIkpFl1lfejOsahrMwObtYzKLmWf7/XTQ=="
|
||||||
},
|
},
|
||||||
"Microsoft.AspNetCore.SignalR.Client": {
|
"Microsoft.AspNetCore.SignalR.Client": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[9.0.8, )",
|
"requested": "[9.0.9, )",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "cO+TZaWdhMn2cIYfPH9oFZaisJrx7X6SBAYdmGektPUAW2BYtMbH4HyLOnJ5CYo42zP9WgqhWHKqmoDm7+Ol5w==",
|
"contentHash": "xx1VCb/cxdOgKg+dQuTpZ3xR2/qpKvwD4iLIjFD+gDgsanVFtm/hEyfRg2nUUqF0UD9kyW0YUz2dsEL3GKjCGg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.AspNetCore.Http.Connections.Client": "9.0.8",
|
"Microsoft.AspNetCore.Http.Connections.Client": "9.0.9",
|
||||||
"Microsoft.AspNetCore.SignalR.Client.Core": "9.0.8"
|
"Microsoft.AspNetCore.SignalR.Client.Core": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.AspNetCore.SignalR.Protocols.MessagePack": {
|
"Microsoft.AspNetCore.SignalR.Protocols.MessagePack": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[9.0.8, )",
|
"requested": "[9.0.9, )",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "e6SC/Tp+SZKeEVYdu8blz9q4MkFW08D56IkQv9V3perF3a7v+GgGZ0DAY/HRS9zBuhFrqpXhJvxeHMw3PJLcOg==",
|
"contentHash": "OgsyQ8NgbWvkMV+Gqr0gVhOXw2AQuIZk/wN2KdnIyzj4I7qImHLPzGh31gc2Hns8T3n0UaJgBayFWLOOHV81mg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"MessagePack": "2.5.187",
|
"MessagePack": "2.5.187",
|
||||||
"Microsoft.AspNetCore.SignalR.Common": "9.0.8"
|
"Microsoft.AspNetCore.SignalR.Common": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Hosting": {
|
"Microsoft.Extensions.Hosting": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[9.0.8, )",
|
"requested": "[9.0.9, )",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "O2VlzORrBbS2it203k5FOHrudDdmdrJovA73P/shdRGeLzvet4e4yXhGx52V2PNjYBQ0IO5M4xiNcL+6xIX6Bg==",
|
"contentHash": "DmRsWH3g8yZGho/pLQ79hxhM2ctE1eDTZ/HbAnrD/uw8m+P2pRRJOoBVxlrhbhMP3/y3oAJoy0yITasfmilbTg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
"Microsoft.Extensions.Configuration": "9.0.9",
|
||||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
"Microsoft.Extensions.Configuration.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Configuration.Binder": "9.0.8",
|
"Microsoft.Extensions.Configuration.Binder": "9.0.9",
|
||||||
"Microsoft.Extensions.Configuration.CommandLine": "9.0.8",
|
"Microsoft.Extensions.Configuration.CommandLine": "9.0.9",
|
||||||
"Microsoft.Extensions.Configuration.EnvironmentVariables": "9.0.8",
|
"Microsoft.Extensions.Configuration.EnvironmentVariables": "9.0.9",
|
||||||
"Microsoft.Extensions.Configuration.FileExtensions": "9.0.8",
|
"Microsoft.Extensions.Configuration.FileExtensions": "9.0.9",
|
||||||
"Microsoft.Extensions.Configuration.Json": "9.0.8",
|
"Microsoft.Extensions.Configuration.Json": "9.0.9",
|
||||||
"Microsoft.Extensions.Configuration.UserSecrets": "9.0.8",
|
"Microsoft.Extensions.Configuration.UserSecrets": "9.0.9",
|
||||||
"Microsoft.Extensions.DependencyInjection": "9.0.8",
|
"Microsoft.Extensions.DependencyInjection": "9.0.9",
|
||||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Diagnostics": "9.0.8",
|
"Microsoft.Extensions.Diagnostics": "9.0.9",
|
||||||
"Microsoft.Extensions.FileProviders.Abstractions": "9.0.8",
|
"Microsoft.Extensions.FileProviders.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.FileProviders.Physical": "9.0.8",
|
"Microsoft.Extensions.FileProviders.Physical": "9.0.9",
|
||||||
"Microsoft.Extensions.Hosting.Abstractions": "9.0.8",
|
"Microsoft.Extensions.Hosting.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Logging": "9.0.8",
|
"Microsoft.Extensions.Logging": "9.0.9",
|
||||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8",
|
"Microsoft.Extensions.Logging.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Logging.Configuration": "9.0.8",
|
"Microsoft.Extensions.Logging.Configuration": "9.0.9",
|
||||||
"Microsoft.Extensions.Logging.Console": "9.0.8",
|
"Microsoft.Extensions.Logging.Console": "9.0.9",
|
||||||
"Microsoft.Extensions.Logging.Debug": "9.0.8",
|
"Microsoft.Extensions.Logging.Debug": "9.0.9",
|
||||||
"Microsoft.Extensions.Logging.EventLog": "9.0.8",
|
"Microsoft.Extensions.Logging.EventLog": "9.0.9",
|
||||||
"Microsoft.Extensions.Logging.EventSource": "9.0.8",
|
"Microsoft.Extensions.Logging.EventSource": "9.0.9",
|
||||||
"Microsoft.Extensions.Options": "9.0.8"
|
"Microsoft.Extensions.Options": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Penumbra.Api": {
|
"Penumbra.Api": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[5.10.0, )",
|
"requested": "[5.12.0, )",
|
||||||
"resolved": "5.10.0",
|
"resolved": "5.12.0",
|
||||||
"contentHash": "ZRIIXQCluNlLoI4I4gNYuYXqb7p48OR1P2/LcL27owToR/A/IG0mH8Ks2HguB/Kjq4RpCinaVkyufpGxGspbTA=="
|
"contentHash": "XGWviAZgokj2djpH50FWgM24jOTpKUuDHvd0HwrzBRY6BEMmpb3HfGIl8+BDE/DqbpH63u6aO2TvzUV6BmXT5w=="
|
||||||
},
|
},
|
||||||
"SonarAnalyzer.CSharp": {
|
"SonarAnalyzer.CSharp": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
@@ -133,6 +150,12 @@
|
|||||||
"Microsoft.IdentityModel.Tokens": "8.14.0"
|
"Microsoft.IdentityModel.Tokens": "8.14.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"System.IO.Pipelines": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[9.0.9, )",
|
||||||
|
"resolved": "9.0.9",
|
||||||
|
"contentHash": "VySjpsCLprojvat550Flrm3NQB982CPuDzILajqjQihFmrQXZPdQyktIbcpVPJyaExFYtAfY1DpwMdWQuS0kbw=="
|
||||||
|
},
|
||||||
"K4os.Compression.LZ4": {
|
"K4os.Compression.LZ4": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "1.3.8",
|
"resolved": "1.3.8",
|
||||||
@@ -143,329 +166,320 @@
|
|||||||
"resolved": "1.0.8",
|
"resolved": "1.0.8",
|
||||||
"contentHash": "Wp2F7BamQ2Q/7Hk834nV9vRQapgcr8kgv9Jvfm8J3D0IhDqZMMl+a2yxUq5ltJitvXvQfB8W6K4F4fCbw/P6YQ=="
|
"contentHash": "Wp2F7BamQ2Q/7Hk834nV9vRQapgcr8kgv9Jvfm8J3D0IhDqZMMl+a2yxUq5ltJitvXvQfB8W6K4F4fCbw/P6YQ=="
|
||||||
},
|
},
|
||||||
"MessagePack": {
|
"MessagePackAnalyzer": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "2.5.187",
|
"resolved": "3.1.4",
|
||||||
"contentHash": "uW4j8m4Nc+2Mk5n6arOChavJ9bLjkis0qWASOj2h2OwmfINuzYv+mjCHUymrYhmyyKTu3N+ObtTXAY4uQ7jIhg==",
|
"contentHash": "CTaSsN/liJ7MhLCAB7Z4ZLBNuVGCq9lt2BT/cbrc9vzGv89yK3CqIA+z9T19a11eQYl9etZHL6MQJgCqECRVpg=="
|
||||||
"dependencies": {
|
|
||||||
"MessagePack.Annotations": "2.5.187",
|
|
||||||
"Microsoft.NET.StringTools": "17.6.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"MessagePack.Annotations": {
|
|
||||||
"type": "Transitive",
|
|
||||||
"resolved": "2.5.198",
|
|
||||||
"contentHash": "3U9OvqQGTra+Mz1k1zfNAScSdNHobnqtQ51qdMGUZppkNDZJl0X/igq6Qz5zDBLEZoYqZrFtZwFx6wBJHHI8BA=="
|
|
||||||
},
|
},
|
||||||
"Microsoft.AspNetCore.Connections.Abstractions": {
|
"Microsoft.AspNetCore.Connections.Abstractions": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "mONfcKx7I4h6Rg+3b20bRyuy/GWz2yLsCNzKKqh1X4OfxnI7l0rdSxBwO203ebZFhjrdXnqMl7Op0N1FQ1Q5DQ==",
|
"contentHash": "bb9kWEjwFHfOxcflTdFjcYY0Cnvc0iqnEt5qQ3O73iKPx8v1jkc/LU5wohOCzIrhWsXREaLtQV1Y15SBISNJiA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.Features": "9.0.8"
|
"Microsoft.Extensions.Features": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.AspNetCore.Http.Connections.Client": {
|
"Microsoft.AspNetCore.Http.Connections.Client": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "Ob2n+H3358kvubgXu9hY95MZB6X91PUGJvtWaHGEX7eZ+9bYdUCYs57ukJiIziH+aD9yO9e36bgKIT1WJEtfmA==",
|
"contentHash": "Ciahjlswi4hylLMfI/gNhNYPuBp0BMP2E/vcG3J7U+wZqSSq8tEeHahEG6h9RF5zPFEISroGOIM6l1uxCP1BfA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.AspNetCore.Http.Connections.Common": "9.0.8",
|
"Microsoft.AspNetCore.Http.Connections.Common": "9.0.9",
|
||||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8",
|
"Microsoft.Extensions.Logging.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Options": "9.0.8",
|
"Microsoft.Extensions.Options": "9.0.9",
|
||||||
"System.Net.ServerSentEvents": "9.0.8"
|
"System.Net.ServerSentEvents": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.AspNetCore.Http.Connections.Common": {
|
"Microsoft.AspNetCore.Http.Connections.Common": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "150BRlecnjL+6C+yw/bDP49+ONh7BmaJZTRik6KtbaS+cWnEDVXnhE5PTKlFqCYBD5T8wdjKoF5+lzKHJUK47A==",
|
"contentHash": "S9ssCBd7Kc0sZN5kiHgvikyNqSI5bMyWYxrfl/Hu1S8ymwEhXFiDf2yFhgkapIiIHOXHjF7mgma2Gqmglivo5g==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.AspNetCore.Connections.Abstractions": "9.0.8"
|
"Microsoft.AspNetCore.Connections.Abstractions": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.AspNetCore.SignalR.Client.Core": {
|
"Microsoft.AspNetCore.SignalR.Client.Core": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "EZ4KaPVQ9rDxZYWQ1sYiPfXEbomhKwp5Fn/0q1XtOgTilV/nN2lgA06KTofVJSeVVRwYdlZggflcQNcKCG0xcg==",
|
"contentHash": "DRSFXVLcgCkYGBb6vtBgYUec+QnCbtQnMabk4p5zbtrqsJ19Uvfk36zNeJKgsBGmNt5HouWPuuB7KJP+IHDAOw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.AspNetCore.SignalR.Common": "9.0.8",
|
"Microsoft.AspNetCore.SignalR.Common": "9.0.9",
|
||||||
"Microsoft.AspNetCore.SignalR.Protocols.Json": "9.0.8",
|
"Microsoft.AspNetCore.SignalR.Protocols.Json": "9.0.9",
|
||||||
"Microsoft.Extensions.DependencyInjection": "9.0.8",
|
"Microsoft.Extensions.DependencyInjection": "9.0.9",
|
||||||
"Microsoft.Extensions.Logging": "9.0.8",
|
"Microsoft.Extensions.Logging": "9.0.9",
|
||||||
"System.Threading.Channels": "9.0.8"
|
"System.Threading.Channels": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.AspNetCore.SignalR.Common": {
|
"Microsoft.AspNetCore.SignalR.Common": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "oNOEDf2UGLU63Qi7LB8OJdfG1CGybVO34bhotpkvAQUJ5zH8Ewf7EvqeHlUgg6cVyrdC+vewOFxTysw212FTyw==",
|
"contentHash": "Fv/0TLXCOSpLsgHvL/tMJh4RpU/Ew7p9xET5VGOFjyCLkeZTNeZivzdZ0lHgKpSsQPmxvS45Csuj3qbr1O8zSw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.AspNetCore.Connections.Abstractions": "9.0.8",
|
"Microsoft.AspNetCore.Connections.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Options": "9.0.8"
|
"Microsoft.Extensions.Options": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.AspNetCore.SignalR.Protocols.Json": {
|
"Microsoft.AspNetCore.SignalR.Protocols.Json": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "9LtBkzS2iYOSiUx1NDI91abM5xxD5MUYtdlvwCtMMr6YdsMzHvDUrgPK2N3hpYE94vmj0srt423Kwd1aOqmGPg==",
|
"contentHash": "8X46a+p6AHdMDs1gNxTzQ+8rzb+/GetBmWgymUCbS8sNi2XQLlPg2jNRWykhIxqIh3UbDYV9cKe4SDLsFYSRtw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.AspNetCore.SignalR.Common": "9.0.8"
|
"Microsoft.AspNetCore.SignalR.Common": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Configuration": {
|
"Microsoft.Extensions.Configuration": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "6m+8Xgmf8UWL0p/oGqBM+0KbHE5/ePXbV1hKXgC59zEv0aa0DW5oiiyxDbK5kH5j4gIvyD5uWL0+HadKBJngvQ==",
|
"contentHash": "w87wF/90/VI0ZQBhf4rbMEeyEy0vi2WKjFmACsNAKNaorY+ZlVz7ddyXkbADvaWouMKffNmR0yQOGcrvSSvKGg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
"Microsoft.Extensions.Configuration.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
"Microsoft.Extensions.Primitives": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Configuration.Abstractions": {
|
"Microsoft.Extensions.Configuration.Abstractions": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "yNou2KM35RvzOh4vUFtl2l33rWPvOCoba+nzEDJ+BgD8aOL/jew4WPCibQvntRfOJ2pJU8ARygSMD+pdjvDHuA==",
|
"contentHash": "p5RKAY9POvs3axwA/AQRuJeM8AHuE8h4qbP1NxQeGm0ep46aXz1oCLAp/oOYxX1GsjStgdhHrN3XXLLXr0+b3w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
"Microsoft.Extensions.Primitives": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Configuration.Binder": {
|
"Microsoft.Extensions.Configuration.Binder": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "0vK9DnYrYChdiH3yRZWkkp4x4LbrfkWEdBc5HOsQ8t/0CLOWKXKkkhOE8A1shlex0hGydbGrhObeypxz/QTm+w==",
|
"contentHash": "6SIp/6Bngk4jm2W36JekZbiIbFPdE/eMUtrJEqIqHGpd1zar3jvgnwxnpWQfzUiGrkyY8q8s6V82zkkEZozghA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8"
|
"Microsoft.Extensions.Configuration.Abstractions": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Configuration.CommandLine": {
|
"Microsoft.Extensions.Configuration.CommandLine": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "vB6eDQ5prED5jHBqmSDNYzlCXsTSylYY7co9c7guhnz0zhx+jZ8BTHgO7y/Wl1dV2jAO15mKNWuyHRIRtWwGQg==",
|
"contentHash": "9bzGOcHoTi8ijrj0MHh5qUY6n9CuittZUqEOj5iE0ZJoSCfG0BI9nhcpd8MC9bOOgjZW5OeizKO8rgta9lSVyA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
"Microsoft.Extensions.Configuration": "9.0.9",
|
||||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8"
|
"Microsoft.Extensions.Configuration.Abstractions": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Configuration.EnvironmentVariables": {
|
"Microsoft.Extensions.Configuration.EnvironmentVariables": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "9qileEYXDodlPN9DfPd5sHSfU2nSrI1r5BHVqLaLyb/7mPi335cy4ar/0ix4tXb2Aer/Pu4e5/zdwxt7lrtSyQ==",
|
"contentHash": "AB8suTh4STAMGDkPer5vL0YNp09eplvbkIbOfFJ1z8D1zOiFF8Hipk9FhCLU4Ea6TosWmGrK30ZIUO9KvAeFcg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
"Microsoft.Extensions.Configuration": "9.0.9",
|
||||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8"
|
"Microsoft.Extensions.Configuration.Abstractions": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Configuration.FileExtensions": {
|
"Microsoft.Extensions.Configuration.FileExtensions": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "2jgx58Jpk3oKT7KRn8x/cFf3QDTjQP+KUbyBnynAcB2iBx1Eq9EdNMCu0QEbYuaZOaQru/Kwdffary+hn58Wwg==",
|
"contentHash": "fvgubCs++wTowHWuQ5TAyZV0S6ldA59U+tBVqFr4/WLd0oEf6ESbdBN2CFaVdn4sZqnarqMnl2O3++RG/Jrf/w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
"Microsoft.Extensions.Configuration": "9.0.9",
|
||||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
"Microsoft.Extensions.Configuration.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.FileProviders.Abstractions": "9.0.8",
|
"Microsoft.Extensions.FileProviders.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.FileProviders.Physical": "9.0.8",
|
"Microsoft.Extensions.FileProviders.Physical": "9.0.9",
|
||||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
"Microsoft.Extensions.Primitives": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Configuration.Json": {
|
"Microsoft.Extensions.Configuration.Json": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "vjxzcnL7ul322+kpvELisXaZl8/5MYs6JfI9DZLQWsao1nA/4FL48yPwDK986hbJTWc64JxOOaMym0SQ/dy32w==",
|
"contentHash": "PiPYo1GTinR2ECM80zYdZUIFmde6jj5DryXUcOJg3yIjh+KQMQr42e+COD03QUsUiqNkJk511wVTnVpTm2AVZA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
"Microsoft.Extensions.Configuration": "9.0.9",
|
||||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
"Microsoft.Extensions.Configuration.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Configuration.FileExtensions": "9.0.8",
|
"Microsoft.Extensions.Configuration.FileExtensions": "9.0.9",
|
||||||
"Microsoft.Extensions.FileProviders.Abstractions": "9.0.8"
|
"Microsoft.Extensions.FileProviders.Abstractions": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Configuration.UserSecrets": {
|
"Microsoft.Extensions.Configuration.UserSecrets": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "UgH18nQkuMJgxjn1539I83N6LhnKQlLhQm3ppe+PGsFpYsC6eGpF/1KvDRm/bmqsrg0NXhurrv4k2r0e8vWX/Q==",
|
"contentHash": "bFaNxfU8gQJX3K/Dd6XT0YIJ5ZVihdAY6Z02p2nVTUHjUsaWflLIucZOgB/ecSNnN3zbbBEf1oFC7q5NHTZIHw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
"Microsoft.Extensions.Configuration.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Configuration.Json": "9.0.8",
|
"Microsoft.Extensions.Configuration.Json": "9.0.9",
|
||||||
"Microsoft.Extensions.FileProviders.Abstractions": "9.0.8",
|
"Microsoft.Extensions.FileProviders.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.FileProviders.Physical": "9.0.8"
|
"Microsoft.Extensions.FileProviders.Physical": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.DependencyInjection": {
|
"Microsoft.Extensions.DependencyInjection": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "JJjI2Fa+QtZcUyuNjbKn04OjIUX5IgFGFu/Xc+qvzh1rXdZHLcnqqVXhR4093bGirTwacRlHiVg1XYI9xum6QQ==",
|
"contentHash": "zQV2WOSP+3z1EuK91ULxfGgo2Y75bTRnmJHp08+w/YXAyekZutX/qCd88/HOMNh35MDW9mJJJxPpMPS+1Rww8A==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8"
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
"Microsoft.Extensions.DependencyInjection.Abstractions": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "xY3lTjj4+ZYmiKIkyWitddrp1uL5uYiweQjqo4BKBw01ZC4HhcfgLghDpPZcUlppgWAFqFy9SgkiYWOMx365pw=="
|
"contentHash": "/hymojfWbE9AlDOa0mczR44m00Jj+T3+HZO0ZnVTI032fVycI0ZbNOVFP6kqZMcXiLSYXzR2ilcwaRi6dzeGyA=="
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Diagnostics": {
|
"Microsoft.Extensions.Diagnostics": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "BKkLCFXzJvNmdngeYBf72VXoZqTJSb1orvjdzDLaGobicoGFBPW8ug2ru1nnEewMEwJzMgnsjHQY8EaKWmVhKg==",
|
"contentHash": "gtzl9SD6CvFYOb92qEF41Z9rICzYniM342TWbbJwN3eLS6a5fCLFvO1pQGtpMSnP3h1zHXupMEeKSA9musWYCQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
"Microsoft.Extensions.Configuration": "9.0.9",
|
||||||
"Microsoft.Extensions.Diagnostics.Abstractions": "9.0.8",
|
"Microsoft.Extensions.Diagnostics.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Options.ConfigurationExtensions": "9.0.8"
|
"Microsoft.Extensions.Options.ConfigurationExtensions": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Diagnostics.Abstractions": {
|
"Microsoft.Extensions.Diagnostics.Abstractions": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "UDY7blv4DCyIJ/8CkNrQKLaAZFypXQavRZ2DWf/2zi1mxYYKKw2t8AOCBWxNntyPZHPGhtEmL3snFM98ADZqTw==",
|
"contentHash": "YHGmxccrVZ2Ar3eI+/NdbOHkd1/HzrHvmQ5yBsp0Gl7jTyBe6qcXNYjUt9v9JIO+Z14la44+YYEe63JSqs1fYg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Options": "9.0.8"
|
"Microsoft.Extensions.Options": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Features": {
|
"Microsoft.Extensions.Features": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "oyPrbpRFa0uWik3PMwpK1mbAr+inZTEkaBsnMjHyT74YN0ot6knA7OnyFLg+oM4MwW5PZIS4HHW9efy0+gj+oQ=="
|
"contentHash": "0MPp/tJ9cFsJCzEKG5g4fUSpwG7bAt9JGADPx5eAThWa9ii2wfOa6f3yxi1IoXWsWqVcq4xlRGrdUAZlpIYalw=="
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.FileProviders.Abstractions": {
|
"Microsoft.Extensions.FileProviders.Abstractions": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "4zZbQ4w+hCMm9J+z5NOj3giIPT2MhZxx05HX/MGuAmDBbjOuXlYIIRN+t4V6OLxy5nXZIcXO+dQMB/OWubuDkw==",
|
"contentHash": "M1ZhL9QkBQ/k6l/Wjgcli5zrV86HzytQ+gQiNtk9vs9Ge1fb17KKZil9T6jd15p2x/BGfXpup7Hg55CC0kkfig==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
"Microsoft.Extensions.Primitives": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.FileProviders.Physical": {
|
"Microsoft.Extensions.FileProviders.Physical": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "FlOe2i7UUIfY0l0ChaIYtlXjdWWutR4DMRKZaGD6z4G1uVTteFkbBfxUIoi1uGmrZQxXe/yv/cfwiT0tK2xyXA==",
|
"contentHash": "sRrPtEwbK23OCFOQ36Xn6ofiB0/nl54/BOdR7lJ/Vwg3XlyvUdmyXvFUS1EU5ltn+sQtbcPuy1l0hsysO8++SQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.FileProviders.Abstractions": "9.0.8",
|
"Microsoft.Extensions.FileProviders.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.FileSystemGlobbing": "9.0.8",
|
"Microsoft.Extensions.FileSystemGlobbing": "9.0.9",
|
||||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
"Microsoft.Extensions.Primitives": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.FileSystemGlobbing": {
|
"Microsoft.Extensions.FileSystemGlobbing": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "96Ub5LmwYfIGVoXkbe4kjs+ivK6fLBTwKJAOMfUNV0R+AkZRItlgROFqXEWMUlXBTPM1/kKu26Ueu5As6RDzJA=="
|
"contentHash": "iQAgORaVIlkhcpxFnVEfjqNWfQCwBEEH7x2IanTwGafA6Tb4xiBoDWySTxUo3MV2NUV/PmwS/8OhT/elPnJCnw=="
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Hosting.Abstractions": {
|
"Microsoft.Extensions.Hosting.Abstractions": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "WNrad20tySNCPe9aJUK7Wfwh+RiyLF+id02FKW8Qfc+HAzNQHazcqMXAbwG/kmbS89uvan/nKK1MufkRahjrJA==",
|
"contentHash": "ORA4dICNz7cuwupPkjXpSuoiK6GMg0aygInBIQCCFEimwoHntRKdJqB59faxq2HHJuTPW3NsZm5EjN5P5Zh6nQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
"Microsoft.Extensions.Configuration.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Diagnostics.Abstractions": "9.0.8",
|
"Microsoft.Extensions.Diagnostics.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.FileProviders.Abstractions": "9.0.8",
|
"Microsoft.Extensions.FileProviders.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8"
|
"Microsoft.Extensions.Logging.Abstractions": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Logging": {
|
"Microsoft.Extensions.Logging": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "Z/7ze+0iheT7FJeZPqJKARYvyC2bmwu3whbm/48BJjdlGVvgDguoCqJIkI/67NkroTYobd5geai1WheNQvWrgA==",
|
"contentHash": "MaCB0Y9hNDs4YLu3HCJbo199WnJT8xSgajG1JYGANz9FkseQ5f3v/llu3HxLI6mjDlu7pa7ps9BLPWjKzsAAzQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.DependencyInjection": "9.0.8",
|
"Microsoft.Extensions.DependencyInjection": "9.0.9",
|
||||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8",
|
"Microsoft.Extensions.Logging.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Options": "9.0.8"
|
"Microsoft.Extensions.Options": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Logging.Abstractions": {
|
"Microsoft.Extensions.Logging.Abstractions": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "pYnAffJL7ARD/HCnnPvnFKSIHnTSmWz84WIlT9tPeQ4lHNiu0Az7N/8itihWvcF8sT+VVD5lq8V+ckMzu4SbOw==",
|
"contentHash": "FEgpSF+Z9StMvrsSViaybOBwR0f0ZZxDm8xV5cSOFiXN/t+ys+rwAlTd/6yG7Ld1gfppgvLcMasZry3GsI9lGA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8"
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Logging.Configuration": {
|
"Microsoft.Extensions.Logging.Configuration": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "Us4evDN3lbp1beVgrpxkSXKrbntVGAK+YbSo9P9driiU9PK05+ShhgesJ3aj7SuDfr3mqqcEgrMJ87Vu8t5dhw==",
|
"contentHash": "Abuo+S0Sg+Ke6vzSh5Ell+lwJJM+CEIqg1ImtWnnqF6a/ibJkQnmFJi4/ekEw/0uAcdFKJXtGV7w6cFN0nyXeg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.Configuration": "9.0.8",
|
"Microsoft.Extensions.Configuration": "9.0.9",
|
||||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
"Microsoft.Extensions.Configuration.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Configuration.Binder": "9.0.8",
|
"Microsoft.Extensions.Configuration.Binder": "9.0.9",
|
||||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Logging": "9.0.8",
|
"Microsoft.Extensions.Logging": "9.0.9",
|
||||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8",
|
"Microsoft.Extensions.Logging.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Options": "9.0.8",
|
"Microsoft.Extensions.Options": "9.0.9",
|
||||||
"Microsoft.Extensions.Options.ConfigurationExtensions": "9.0.8"
|
"Microsoft.Extensions.Options.ConfigurationExtensions": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Logging.Console": {
|
"Microsoft.Extensions.Logging.Console": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "mPp9xB9MjiPuodh9z/+6zEGNj2kSVeXQtdbIBHlhUYqxX22gzJkx0ycPY42q4/OT/SzFV/TJ989Pa3sA/8ZBeA==",
|
"contentHash": "x3+W7IfW9Tg3sV+sU9N1039M4CqklaAecwhz9qNtjOCBdmg7h96JaL+NAvhYgZgweVJTJaxAvuO8I+ZZehE7Pg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Logging": "9.0.8",
|
"Microsoft.Extensions.Logging": "9.0.9",
|
||||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8",
|
"Microsoft.Extensions.Logging.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Logging.Configuration": "9.0.8",
|
"Microsoft.Extensions.Logging.Configuration": "9.0.9",
|
||||||
"Microsoft.Extensions.Options": "9.0.8"
|
"Microsoft.Extensions.Options": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Logging.Debug": {
|
"Microsoft.Extensions.Logging.Debug": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "OwHQFVITsONEoizShc1yNYTUvMq0kT9j/LhwAKMsA7OZqtrBXuqjosbSvzkJZ9o+KWAozDh5Y1Vtpe5p/8/1qA==",
|
"contentHash": "q8IbjIzTjfaGfuf9LAuG3X9BytAWj2hWhLU61rEkit847oaSSbcdx/yybY3yL9RgVG1u9ctk7kbCv18M+7Fi6Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Logging": "9.0.8",
|
"Microsoft.Extensions.Logging": "9.0.9",
|
||||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8"
|
"Microsoft.Extensions.Logging.Abstractions": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Logging.EventLog": {
|
"Microsoft.Extensions.Logging.EventLog": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "/gMwlll21UJcaXlitUqd+rs9jH36EJz5BpFVPshyOqz5u0qyV1pFnTWm5vhyx+g6gwVYENSLgpazR1urNv83xw==",
|
"contentHash": "1SX5+mv16SBb5NrtLNxIvUt8PHbdvDloZazQdxz1CNM39jG7yeF6olH3sceQ4ONF0oVD5mVUsTag0iVX4xgyog==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Logging": "9.0.8",
|
"Microsoft.Extensions.Logging": "9.0.9",
|
||||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8",
|
"Microsoft.Extensions.Logging.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Options": "9.0.8",
|
"Microsoft.Extensions.Options": "9.0.9",
|
||||||
"System.Diagnostics.EventLog": "9.0.8"
|
"System.Diagnostics.EventLog": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Logging.EventSource": {
|
"Microsoft.Extensions.Logging.EventSource": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "aGMFc/1P+315d07iyxSe6lEoZ0JjOPJ+Mfv9rrV2PvR2DFu1/pSi/SItHw1iChJOZgslNKJE97g1a9nLX3qQYA==",
|
"contentHash": "rGQi5mImot7tTFxj1tQWknWjOBHX1+gsX1WLmQNl5WHr4Sx1kXUBGDuRUjfx4c8pe/hcYHdalAmgk7RdusW6Jw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Logging": "9.0.8",
|
"Microsoft.Extensions.Logging": "9.0.9",
|
||||||
"Microsoft.Extensions.Logging.Abstractions": "9.0.8",
|
"Microsoft.Extensions.Logging.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Options": "9.0.8",
|
"Microsoft.Extensions.Options": "9.0.9",
|
||||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
"Microsoft.Extensions.Primitives": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Options": {
|
"Microsoft.Extensions.Options": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "OmTaQ0v4gxGQkehpwWIqPoEiwsPuG/u4HUsbOFoWGx4DKET2AXzopnFe/fE608FIhzc/kcg2p8JdyMRCCUzitQ==",
|
"contentHash": "loxGGHE1FC2AefwPHzrjPq7X92LQm64qnU/whKfo6oWaceewPUVYQJBJs3S3E2qlWwnCpeZ+dGCPTX+5dgVAuQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
"Microsoft.Extensions.Primitives": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Options.ConfigurationExtensions": {
|
"Microsoft.Extensions.Options.ConfigurationExtensions": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "eW2s6n06x0w6w4nsX+SvpgsFYkl+Y0CttYAt6DKUXeqprX+hzNqjSfOh637fwNJBg7wRBrOIRHe49gKiTgJxzQ==",
|
"contentHash": "n4DCdnn2qs6V5U06Sx62FySEAZsJiJJgOzrPHDh9hPK7c2W8hEabC76F3Re3tGPjpiKa02RvB6FxZyxo8iICzg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
|
"Microsoft.Extensions.Configuration.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Configuration.Binder": "9.0.8",
|
"Microsoft.Extensions.Configuration.Binder": "9.0.9",
|
||||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.9",
|
||||||
"Microsoft.Extensions.Options": "9.0.8",
|
"Microsoft.Extensions.Options": "9.0.9",
|
||||||
"Microsoft.Extensions.Primitives": "9.0.8"
|
"Microsoft.Extensions.Primitives": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.Primitives": {
|
"Microsoft.Extensions.Primitives": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "tizSIOEsIgSNSSh+hKeUVPK7xmTIjR8s+mJWOu1KXV3htvNQiPMFRMO17OdI1y/4ZApdBVk49u/08QGC9yvLug=="
|
"contentHash": "z4pyMePOrl733ltTowbN565PxBw1oAr8IHmIXNDiDqd22nFpYltX9KhrNC/qBWAG1/Zx5MHX+cOYhWJQYCO/iw=="
|
||||||
},
|
},
|
||||||
"Microsoft.IdentityModel.Abstractions": {
|
"Microsoft.IdentityModel.Abstractions": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
@@ -499,34 +513,32 @@
|
|||||||
},
|
},
|
||||||
"Microsoft.NET.StringTools": {
|
"Microsoft.NET.StringTools": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "17.6.3",
|
"resolved": "17.11.4",
|
||||||
"contentHash": "N0ZIanl1QCgvUumEL1laasU0a7sOE5ZwLZVTn0pAePnfhq8P7SvTjF8Axq+CnavuQkmdQpGNXQ1efZtu5kDFbA=="
|
"contentHash": "mudqUHhNpeqIdJoUx2YDWZO/I9uEDYVowan89R6wsomfnUJQk6HteoQTlNjZDixhT2B4IXMkMtgZtoceIjLRmA=="
|
||||||
},
|
},
|
||||||
"System.Diagnostics.EventLog": {
|
"System.Diagnostics.EventLog": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "gebRF3JLLJ76jz1CQpvwezNapZUjFq20JQsaGHzBH0DzlkHBLpdhwkOei9usiOkIGMwU/L0ALWpNe1JE+5/itw=="
|
"contentHash": "wpsUfnyv8E5K4WQaok6weewvAbQhcLwXFcHBm5U0gdEaBs85N//ssuYvRPFWwz2rO/9/DFP3A1sGMzUFBj8y3w=="
|
||||||
},
|
|
||||||
"System.IO.Pipelines": {
|
|
||||||
"type": "Transitive",
|
|
||||||
"resolved": "6.0.3",
|
|
||||||
"contentHash": "ryTgF+iFkpGZY1vRQhfCzX0xTdlV3pyaTTqRu2ETbEv+HlV7O6y7hyQURnghNIXvctl5DuZ//Dpks6HdL/Txgw=="
|
|
||||||
},
|
},
|
||||||
"System.Net.ServerSentEvents": {
|
"System.Net.ServerSentEvents": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "wrpra4YvKXL7VdsQMKPcPxyA8pXK22LcxaKGA8oEndgjLZ1ZSdKXTxEA2cPvvNpMEUBwZlgJ6oZYQ8aJcpapPg=="
|
"contentHash": "zEISfefh8BYD5m+GMsYJnodiTaz2fDBEOrLgYH7VsQhMIzNkcuSsg9Df/d3zywYX5ohCyCJ5AOax50XLKnXyjw=="
|
||||||
},
|
},
|
||||||
"System.Threading.Channels": {
|
"System.Threading.Channels": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.8",
|
"resolved": "9.0.9",
|
||||||
"contentHash": "kpvkzWJoHR9os3/4LL5feaTTLD92+XzTqPyYLU2tw2BoJ4MrWCfkjGXtL7MsdpV/20e1+SamCbrPj2L9ptwgBA=="
|
"contentHash": "AEgG1sVSp3H7oNYoXi350GeUnZdnP38EQHNK0kN5HCC6KoVoEkuTVr40lrVag99pd/NBr3tdNjPFElLLPI5BQg=="
|
||||||
},
|
},
|
||||||
"maresynchronos.api": {
|
"maresynchronos.api": {
|
||||||
"type": "Project",
|
"type": "Project",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"MessagePack.Annotations": "[2.5.198, )"
|
"MessagePack.Annotations": "[2.5.129, )"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"snowcloaksync": {
|
||||||
|
"type": "Project"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
3
Penumbra.Api/.gitignore
vendored
3
Penumbra.Api/.gitignore
vendored
@@ -1,3 +0,0 @@
|
|||||||
bin/
|
|
||||||
obj/
|
|
||||||
.vs/
|
|
@@ -1,66 +0,0 @@
|
|||||||
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();
|
|
||||||
}
|
|
@@ -1,28 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
@@ -1,52 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
@@ -1,41 +0,0 @@
|
|||||||
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; }
|
|
||||||
}
|
|
@@ -1,16 +0,0 @@
|
|||||||
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; }
|
|
||||||
}
|
|
@@ -1,13 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
@@ -1,77 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
@@ -1,78 +0,0 @@
|
|||||||
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();
|
|
||||||
}
|
|
@@ -1,26 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
@@ -1,23 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
@@ -1,64 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
@@ -1,73 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
@@ -1,147 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
@@ -1,59 +0,0 @@
|
|||||||
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();
|
|
||||||
}
|
|
@@ -1,42 +0,0 @@
|
|||||||
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);
|
|
@@ -1,97 +0,0 @@
|
|||||||
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,
|
|
||||||
}
|
|
@@ -1,23 +0,0 @@
|
|||||||
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,
|
|
||||||
}
|
|
@@ -1,17 +0,0 @@
|
|||||||
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,
|
|
||||||
}
|
|
@@ -1,39 +0,0 @@
|
|||||||
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,
|
|
||||||
}
|
|
@@ -1,34 +0,0 @@
|
|||||||
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,
|
|
||||||
}
|
|
@@ -1,12 +0,0 @@
|
|||||||
namespace Penumbra.Api.Enums;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Describes which mouse button was used to click an element.
|
|
||||||
/// </summary>
|
|
||||||
public enum MouseButton
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
Middle,
|
|
||||||
}
|
|
@@ -1,33 +0,0 @@
|
|||||||
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,
|
|
||||||
}
|
|
@@ -1,11 +0,0 @@
|
|||||||
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,
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user