Updated to Risa's changes
This commit is contained in:
1
.gitmodules
vendored
1
.gitmodules
vendored
@@ -17,4 +17,3 @@
|
||||
[submodule "submodules/ECommonsLite"]
|
||||
path = submodules/ECommonsLite
|
||||
url = https://github.com/Aether-Tools/ECommonsLite.git
|
||||
branch = main
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Dalamud.NET.Sdk/12.0.2">
|
||||
<Project Sdk="Dalamud.NET.Sdk/13.0.0">
|
||||
|
||||
<PropertyGroup>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
|
||||
14
CustomizePlus.GameData/Extensions/ActorExtensions.cs
Normal file
14
CustomizePlus.GameData/Extensions/ActorExtensions.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace CustomizePlus.GameData.Extensions;
|
||||
|
||||
public static unsafe class ActorExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns if this actor is currently being rendered by the game or only exists as invisible object table entry.
|
||||
/// </summary>
|
||||
public static bool IsRenderedByGame(this Actor actor)
|
||||
{
|
||||
return actor.AsCharacter->DrawObject != null && actor.Model.AsCharacterBase != null;
|
||||
}
|
||||
}
|
||||
@@ -6,20 +6,23 @@ using System.Collections.Frozen;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using CustomizePlus.GameData.ReverseSearchDictionaries.Bases;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
|
||||
namespace CustomizePlus.GameData.ReverseSearchDictionaries;
|
||||
|
||||
#pragma warning disable SeStringEvaluator
|
||||
|
||||
/// <summary> A dictionary that matches names to battle npc ids. </summary>
|
||||
public sealed class ReverseSearchDictBNpc(IDalamudPluginInterface pluginInterface, Logger log, IDataManager gameData)
|
||||
: ReverseNameDictionary(pluginInterface, log, gameData, "ReverseSearchBNpcs", Penumbra.GameData.DataContainers.Version.DictBNpc, () => CreateBNpcData(gameData))
|
||||
public sealed class ReverseSearchDictBNpc(IDalamudPluginInterface pluginInterface, Logger log, IDataManager gameData, ISeStringEvaluator evaluator)
|
||||
: ReverseNameDictionary(pluginInterface, log, gameData, "ReverseSearchBNpcs", Penumbra.GameData.DataContainers.Version.DictBNpc, () => CreateBNpcData(gameData, evaluator))
|
||||
{
|
||||
/// <summary> Create the data. </summary>
|
||||
private static IReadOnlyDictionary<string, uint> CreateBNpcData(IDataManager gameData)
|
||||
private static IReadOnlyDictionary<string, uint> CreateBNpcData(IDataManager gameData, ISeStringEvaluator evaluator)
|
||||
{
|
||||
var sheet = gameData.GetExcelSheet<BNpcName>(gameData.Language)!;
|
||||
var dict = new Dictionary<string, uint>((int)sheet.Count);
|
||||
foreach (var n in sheet.Where(n => n.Singular.ByteLength > 0))
|
||||
dict.TryAdd(DataUtility.ToTitleCaseExtended(n.Singular, (Dalamud.Game.ClientLanguage)n.Article), n.RowId);
|
||||
dict.TryAdd(evaluator.EvaluateObjStr(ObjectKind.BattleNpc, n.RowId, gameData.Language), n.RowId);
|
||||
return dict.ToFrozenDictionary();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,20 +6,23 @@ using System.Collections.Frozen;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using CustomizePlus.GameData.ReverseSearchDictionaries.Bases;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
|
||||
namespace CustomizePlus.GameData.ReverseSearchDictionaries;
|
||||
|
||||
#pragma warning disable SeStringEvaluator
|
||||
|
||||
/// <summary> A dictionary that matches companion names to their ids. </summary>
|
||||
public sealed class ReverseSearchDictCompanion(IDalamudPluginInterface pluginInterface, Logger log, IDataManager gameData)
|
||||
: ReverseNameDictionary(pluginInterface, log, gameData, "ReverseSearchCompanions", Penumbra.GameData.DataContainers.Version.DictCompanion, () => CreateCompanionData(gameData))
|
||||
public sealed class ReverseSearchDictCompanion(IDalamudPluginInterface pluginInterface, Logger log, IDataManager gameData, ISeStringEvaluator evaluator)
|
||||
: ReverseNameDictionary(pluginInterface, log, gameData, "ReverseSearchCompanions", Penumbra.GameData.DataContainers.Version.DictCompanion, () => CreateCompanionData(gameData, evaluator))
|
||||
{
|
||||
/// <summary> Create the data. </summary>
|
||||
private static IReadOnlyDictionary<string, uint> CreateCompanionData(IDataManager gameData)
|
||||
private static IReadOnlyDictionary<string, uint> CreateCompanionData(IDataManager gameData, ISeStringEvaluator evaluator)
|
||||
{
|
||||
var sheet = gameData.GetExcelSheet<Companion>(gameData.Language)!;
|
||||
var dict = new Dictionary<string, uint>((int)sheet.Count);
|
||||
foreach (var c in sheet.Where(c => c.Singular.ByteLength > 0 && c.Order < ushort.MaxValue))
|
||||
dict.TryAdd(DataUtility.ToTitleCaseExtended(c.Singular, (Dalamud.Game.ClientLanguage)c.Article), c.RowId);
|
||||
dict.TryAdd(evaluator.EvaluateObjStr(ObjectKind.Companion, c.RowId, gameData.Language), c.RowId);
|
||||
return dict.ToFrozenDictionary();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,20 +6,23 @@ using System.Collections.Frozen;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using CustomizePlus.GameData.ReverseSearchDictionaries.Bases;
|
||||
using Lumina.Excel.Sheets;
|
||||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
|
||||
namespace CustomizePlus.GameData.ReverseSearchDictionaries;
|
||||
|
||||
#pragma warning disable SeStringEvaluator
|
||||
|
||||
/// <summary> A dictionary that matches names to event npc ids. </summary>
|
||||
public sealed class ReverseSearchDictENpc(IDalamudPluginInterface pluginInterface, Logger log, IDataManager gameData)
|
||||
: ReverseNameDictionary(pluginInterface, log, gameData, "ReverseSearchENpcs", Penumbra.GameData.DataContainers.Version.DictENpc, () => CreateENpcData(gameData))
|
||||
public sealed class ReverseSearchDictENpc(IDalamudPluginInterface pluginInterface, Logger log, IDataManager gameData, ISeStringEvaluator evaluator)
|
||||
: ReverseNameDictionary(pluginInterface, log, gameData, "ReverseSearchENpcs", Penumbra.GameData.DataContainers.Version.DictENpc, () => CreateENpcData(gameData, evaluator))
|
||||
{
|
||||
/// <summary> Create the data. </summary>
|
||||
private static IReadOnlyDictionary<string, uint> CreateENpcData(IDataManager gameData)
|
||||
private static IReadOnlyDictionary<string, uint> CreateENpcData(IDataManager gameData, ISeStringEvaluator evaluator)
|
||||
{
|
||||
var sheet = gameData.GetExcelSheet<ENpcResident>(gameData.Language)!;
|
||||
var dict = new Dictionary<string, uint>((int)sheet.Count);
|
||||
foreach (var n in sheet.Where(e => e.Singular.ByteLength > 0))
|
||||
dict.TryAdd(DataUtility.ToTitleCaseExtended(n.Singular, (Dalamud.Game.ClientLanguage)n.Article), n.RowId);
|
||||
dict.TryAdd(evaluator.EvaluateObjStr(ObjectKind.EventNpc, n.RowId, gameData.Language), n.RowId);
|
||||
return dict.ToFrozenDictionary();
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ public sealed class ReverseSearchDictMount(IDalamudPluginInterface pluginInterfa
|
||||
{
|
||||
if (m.Singular.ByteLength > 0 && m.Order >= 0)
|
||||
{
|
||||
dict.TryAdd(DataUtility.ToTitleCaseExtended(m.Singular, (Dalamud.Game.ClientLanguage)m.Article), m.RowId);
|
||||
dict.TryAdd(DataUtility.ToTitleCaseExtended(m.Singular, gameData.Language), m.RowId);
|
||||
}
|
||||
else if (m.Unknown1.ByteLength > 0)
|
||||
{
|
||||
|
||||
@@ -48,7 +48,7 @@ public partial class CustomizePlusIpc
|
||||
.Where(x => x.ProfileType == ProfileType.Normal)
|
||||
.Select(x =>
|
||||
{
|
||||
string path = _profileFileSystem.FindLeaf(x, out var leaf) ? leaf.FullName() : x.Name.Text;
|
||||
string path = _profileFileSystem.TryGetValue(x, out var leaf) ? leaf.FullName() : x.Name.Text;
|
||||
var charactersList = new List<IPCCharacterDataTuple>(x.Characters.Count);
|
||||
|
||||
foreach (var character in x.Characters)
|
||||
|
||||
@@ -147,6 +147,12 @@ public unsafe sealed class ArmatureManager : IDisposable
|
||||
foreach (var obj in _objectManager)
|
||||
{
|
||||
var actorIdentifier = obj.Key.CreatePermanent();
|
||||
|
||||
//warn: in cutscenes the game creates a copy of your character and object #0,
|
||||
//so we need to check if there is at least one object being rendered
|
||||
if (obj.Value.Objects == null || obj.Value.Objects.Count == 0 || !obj.Value.Objects.Any(x => x.IsRenderedByGame()))
|
||||
continue;
|
||||
|
||||
if (!Armatures.ContainsKey(actorIdentifier))
|
||||
{
|
||||
var activeProfile = _profileManager.GetEnabledProfilesByActor(actorIdentifier).FirstOrDefault();
|
||||
@@ -173,7 +179,8 @@ public unsafe sealed class ArmatureManager : IDisposable
|
||||
|
||||
var activeProfile = _profileManager.GetEnabledProfilesByActor(actorIdentifier).FirstOrDefault();
|
||||
Profile? oldProfile = armature.Profile;
|
||||
if (activeProfile != armature.Profile)
|
||||
bool profileChange = activeProfile != armature.Profile;
|
||||
if (profileChange)
|
||||
{
|
||||
if (activeProfile == null)
|
||||
{
|
||||
@@ -197,11 +204,27 @@ public unsafe sealed class ArmatureManager : IDisposable
|
||||
|
||||
armature.RebuildBoneTemplateBinding();
|
||||
|
||||
//warn: might be a bit of a performance hit on profiles with a lot of templates/bones
|
||||
//warn: this must be done after RebuildBoneTemplateBinding or it will not work
|
||||
if (profileChange &&
|
||||
oldProfile.Templates.Where(x => x.Bones.ContainsKey("n_root")).Any())
|
||||
{
|
||||
_logger.Debug($"Resetting root transform for {armature} because new profile doesn't have root edits");
|
||||
|
||||
if (obj.Value.Objects != null)
|
||||
{
|
||||
//Reset root translation
|
||||
foreach (var actor in obj.Value.Objects)
|
||||
ApplyRootTranslation(armature, actor, true);
|
||||
}
|
||||
}
|
||||
|
||||
_event.Invoke(ArmatureChanged.Type.Updated, armature, (activeProfile, oldProfile));
|
||||
}
|
||||
|
||||
//Needed because skeleton sometimes appears to be not ready when armature is created
|
||||
//and also because we want to keep armature up to date with any character skeleton changes
|
||||
//Needed because:
|
||||
//* Skeleton sometimes appears to be not ready when armature is created
|
||||
//* We want to keep armature up to date with any character skeleton changes
|
||||
TryLinkSkeleton(armature);
|
||||
}
|
||||
}
|
||||
@@ -240,10 +263,10 @@ public unsafe sealed class ArmatureManager : IDisposable
|
||||
/// </summary>
|
||||
private bool TryLinkSkeleton(Armature armature)
|
||||
{
|
||||
|
||||
if (!_objectManager.ContainsKey(armature.ActorIdentifier))
|
||||
return false;
|
||||
|
||||
//we assume that all other objects are a copy of object #0
|
||||
var actor = _objectManager[armature.ActorIdentifier].Objects[0];
|
||||
|
||||
if (!armature.IsBuilt || armature.IsSkeletonUpdated(actor.Model.AsCharacterBase))
|
||||
@@ -329,7 +352,7 @@ public unsafe sealed class ArmatureManager : IDisposable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply root bone translation. If reset = true then this will only reset translation if it was edited in supplied armature.
|
||||
/// Apply root bone translation. If reset = true then this will forcibly reset translation to in-game value.
|
||||
/// </summary>
|
||||
private void ApplyRootTranslation(Armature arm, Actor actor, bool reset = false)
|
||||
{
|
||||
@@ -341,18 +364,18 @@ public unsafe sealed class ArmatureManager : IDisposable
|
||||
var cBase = actor.Model.AsCharacterBase;
|
||||
if (cBase != null)
|
||||
{
|
||||
//warn: hotpath for characters with n_root edits. IsApproximately might have some performance hit.
|
||||
var rootBoneTransform = arm.GetAppliedBoneTransform("n_root");
|
||||
if (rootBoneTransform == null ||
|
||||
rootBoneTransform.Translation.IsApproximately(Vector3.Zero, 0.00001f))
|
||||
return;
|
||||
|
||||
if (reset)
|
||||
{
|
||||
cBase->DrawObject.Object.Position = actor.AsObject->Position;
|
||||
return;
|
||||
}
|
||||
|
||||
//warn: hotpath for characters with n_root edits. IsApproximately might have some performance hit.
|
||||
var rootBoneTransform = arm.GetAppliedBoneTransform("n_root");
|
||||
if (rootBoneTransform == null ||
|
||||
rootBoneTransform.Translation.IsApproximately(Vector3.Zero, 0.00001f))
|
||||
return;
|
||||
|
||||
if (rootBoneTransform.Translation.X == 0 &&
|
||||
rootBoneTransform.Translation.Y == 0 &&
|
||||
rootBoneTransform.Translation.Z == 0)
|
||||
|
||||
@@ -63,6 +63,18 @@ public class PluginConfiguration : IPluginConfiguration, ISavable
|
||||
|
||||
public bool IncognitoMode { get; set; } = false;
|
||||
|
||||
public float CurrentTemplateSelectorWidth { get; set; } = 200f;
|
||||
|
||||
public float TemplateSelectorMinimumScale { get; set; } = 0.1f;
|
||||
|
||||
public float TemplateSelectorMaximumScale { get; set; } = 0.5f;
|
||||
|
||||
public float CurrentProfileSelectorWidth { get; set; } = 200f;
|
||||
|
||||
public float ProfileSelectorMinimumScale { get; set; } = 0.1f;
|
||||
|
||||
public float ProfileSelectorMaximumScale { get; set; } = 0.5f;
|
||||
|
||||
public List<string> ViewedMessageWindows { get; set; } = new();
|
||||
}
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@ internal static class Constants
|
||||
|
||||
/// <summary>
|
||||
/// Movement hook address, used for position offset and other changes which cannot be done in main hook
|
||||
/// Client::Game::Object::GameObject_UpdateVisualPosition
|
||||
/// </summary>
|
||||
public const string MovementHookAddress = "E8 ?? ?? ?? ?? 84 DB 74 3A";
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Utility;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using System.Text;
|
||||
|
||||
namespace CustomizePlus.Core.Helpers;
|
||||
|
||||
@@ -67,21 +66,15 @@ public static class CtrlHelper
|
||||
}
|
||||
|
||||
public static bool ArrowToggle(string label, ref bool value)
|
||||
{//ImGuiNative.ArrowButton(label, value ? ImGuiDir.Down : ImGuiDir.Right);
|
||||
unsafe // temporary fix
|
||||
{
|
||||
var toggled = ImGui.ArrowButton(label, value ? ImGuiDir.Down : ImGuiDir.Right);
|
||||
|
||||
if (toggled)
|
||||
{
|
||||
var utf8Label = Encoding.UTF8.GetBytes(label + "\0");
|
||||
|
||||
fixed (byte* labelPtr = utf8Label)
|
||||
{
|
||||
bool toggled = ImGuiNative.ArrowButton(labelPtr, value ? ImGuiDir.Down : ImGuiDir.Right) != 0;
|
||||
|
||||
if (toggled)
|
||||
value = !value;
|
||||
|
||||
return value;
|
||||
}
|
||||
value = !value;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static void AddHoverText(string text)
|
||||
|
||||
@@ -25,7 +25,6 @@ using CustomizePlus.UI.Windows.MainWindow.Tabs.Debug;
|
||||
using CustomizePlus.UI.Windows.MainWindow.Tabs.Profiles;
|
||||
using CustomizePlus.UI.Windows.MainWindow.Tabs.Templates;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Log;
|
||||
@@ -59,10 +58,10 @@ public static class ServiceManagerBuilder
|
||||
.AddApi();
|
||||
|
||||
DalamudServices.AddServices(services, pi);
|
||||
services.AddDalamudService<ISeStringEvaluator>(pi);
|
||||
|
||||
services.AddIServices(typeof(EquipItem).Assembly);
|
||||
services.AddIServices(typeof(Plugin).Assembly);
|
||||
services.AddIServices(typeof(CutsceneService).Assembly);
|
||||
services.AddIServices(typeof(CutsceneService).Assembly);
|
||||
services.AddIServices(typeof(ImRaii).Assembly);
|
||||
|
||||
services.CreateProvider();
|
||||
|
||||
@@ -8,6 +8,8 @@ using OtterGui.Services;
|
||||
|
||||
namespace CustomizePlus.Core.Services.Dalamud;
|
||||
|
||||
#pragma warning disable SeStringEvaluator
|
||||
|
||||
public class DalamudServices
|
||||
{
|
||||
public static void AddServices(ServiceManager services, IDalamudPluginInterface pi)
|
||||
@@ -27,6 +29,7 @@ public class DalamudServices
|
||||
.AddDalamudService<IPluginLog>(pi)
|
||||
.AddDalamudService<ITargetManager>(pi)
|
||||
.AddDalamudService<INotificationManager>(pi)
|
||||
.AddDalamudService<IContextMenu>(pi);
|
||||
.AddDalamudService<IContextMenu>(pi)
|
||||
.AddDalamudService<ISeStringEvaluator>(pi);
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,6 @@ public class HookingService : IDisposable
|
||||
private readonly ProfileManager _profileManager;
|
||||
private readonly ArmatureManager _armatureManager;
|
||||
private readonly GameStateService _gameStateService;
|
||||
private readonly DalamudBranchService _dalamudBranchService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
private Hook<RenderDelegate>? _renderManagerHook;
|
||||
@@ -46,7 +45,6 @@ public class HookingService : IDisposable
|
||||
ProfileManager profileManager,
|
||||
ArmatureManager armatureManager,
|
||||
GameStateService gameStateService,
|
||||
DalamudBranchService dalamudBranchService,
|
||||
Logger logger)
|
||||
{
|
||||
_configuration = configuration;
|
||||
@@ -55,7 +53,6 @@ public class HookingService : IDisposable
|
||||
_profileManager = profileManager;
|
||||
_armatureManager = armatureManager;
|
||||
_gameStateService = gameStateService;
|
||||
_dalamudBranchService = dalamudBranchService;
|
||||
_logger = logger;
|
||||
|
||||
ReloadHooks();
|
||||
@@ -75,12 +72,6 @@ public class HookingService : IDisposable
|
||||
RenderHookFailed = false;
|
||||
MovementHookFailed = false;
|
||||
|
||||
if(!_dalamudBranchService.AllowPluginToRun)
|
||||
{
|
||||
_logger.Error("Not reloading hooks because the plugin is not allowed to run. (Branch Service)");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (_configuration.PluginEnabled)
|
||||
|
||||
@@ -21,22 +21,18 @@ public class SupportLogBuilderService
|
||||
private readonly ProfileManager _profileManager;
|
||||
private readonly ArmatureManager _armatureManager;
|
||||
private readonly IDalamudPluginInterface _dalamudPluginInterface;
|
||||
private readonly DalamudBranchService _dalamudBranchService;
|
||||
|
||||
public SupportLogBuilderService(
|
||||
PluginConfiguration configuration,
|
||||
TemplateManager templateManager,
|
||||
ProfileManager profileManager,
|
||||
ArmatureManager armatureManager,
|
||||
IDalamudPluginInterface dalamudPluginInterface,
|
||||
DalamudBranchService dalamudBranchService)
|
||||
IDalamudPluginInterface dalamudPluginInterface)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_templateManager = templateManager;
|
||||
_profileManager = profileManager;
|
||||
_armatureManager = armatureManager;
|
||||
_dalamudPluginInterface = dalamudPluginInterface;
|
||||
_dalamudBranchService = dalamudBranchService;
|
||||
}
|
||||
|
||||
public string BuildSupportLog()
|
||||
@@ -45,7 +41,6 @@ public class SupportLogBuilderService
|
||||
sb.AppendLine("**Settings**");
|
||||
sb.Append($"> **`Plugin Version: `** {VersionHelper.Version}\n");
|
||||
sb.Append($"> **`Commit Hash: `** {ThisAssembly.Git.Commit}+{ThisAssembly.Git.Sha}\n");
|
||||
sb.Append($"> **`Dalamud Branch: `** {_dalamudBranchService.CurrentBranchName} ({_dalamudBranchService.CurrentBranch})\n");
|
||||
sb.Append($"> **`Plugin enabled: `** {_configuration.PluginEnabled}\n");
|
||||
sb.AppendLine("**Settings -> Editor Settings**");
|
||||
sb.Append($"> **`Preview character (editor): `** {_configuration.EditorConfiguration.PreviewCharacter.Incognito(null)}\n");
|
||||
|
||||
@@ -12,18 +12,15 @@ public class UserNotifierService : IDisposable
|
||||
{
|
||||
private readonly IClientState _clientState;
|
||||
private readonly ChatService _chatService;
|
||||
private readonly DalamudBranchService _dalamudBranchService;
|
||||
private readonly PopupSystem _popupSystem;
|
||||
|
||||
public UserNotifierService(
|
||||
IClientState clientState,
|
||||
ChatService chatService,
|
||||
DalamudBranchService dalamudBranchService,
|
||||
PopupSystem popupSystem)
|
||||
{
|
||||
_clientState = clientState;
|
||||
_chatService = chatService;
|
||||
_dalamudBranchService = dalamudBranchService;
|
||||
_popupSystem = popupSystem;
|
||||
|
||||
NotifyUser(true);
|
||||
@@ -46,17 +43,5 @@ public class UserNotifierService : IDisposable
|
||||
if (VersionHelper.IsTesting)
|
||||
_chatService.PrintInChat($"You are running testing version of Customize+! Some features like integration with other plugins might not function correctly.",
|
||||
ChatService.ChatMessageColor.Warning);
|
||||
|
||||
if (!_dalamudBranchService.AllowPluginToRun)
|
||||
{
|
||||
_chatService.PrintInChat(DalamudBranchService.PluginDisabledMessage,
|
||||
ChatService.ChatMessageColor.Error);
|
||||
|
||||
if (displayOptionalMessages)
|
||||
{
|
||||
if(_popupSystem.ShowPopup(PopupSystem.Messages.PluginDisabledNonReleaseDalamud))
|
||||
UIGlobals.PlayChatSoundEffect(11);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<Project Sdk="Dalamud.NET.Sdk/13.0.0">
|
||||
<PropertyGroup>
|
||||
<AssemblyTitle>CustomizePlus</AssemblyTitle>
|
||||
<Version>2.0.0.1</Version>
|
||||
<Version>2.0.0.0</Version>
|
||||
<Description>Customize+</Description>
|
||||
<Copyright></Copyright>
|
||||
<PackageProjectUrl>https://github.com/Aether-Tools/CustomizePlus</PackageProjectUrl>
|
||||
@@ -36,10 +36,6 @@
|
||||
<ProjectReference Include="..\CustomizePlus.GameData\CustomizePlus.GameData.csproj" />
|
||||
<ProjectReference Include="..\submodules\ECommonsLite\ECommonsLite\ECommonsLite.csproj" />
|
||||
<ProjectReference Include="..\submodules\OtterGui\OtterGui.csproj" />
|
||||
<Reference Include="Dalamud.Bindings.ImGui">
|
||||
<Private>false</Private>
|
||||
<HintPath>$(DalamudLibPath)\Dalamud.Bindings.ImGui.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -48,10 +44,6 @@
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Update="DalamudPackager" Version="13.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<DefineConstants>INCOGNIFY_STRINGS</DefineConstants>
|
||||
</PropertyGroup>-->
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"Description": "A plugin that allows you to customize your character beyond FFXIV limitations by directly editing bone parameters.",
|
||||
"InternalName": "CustomizePlus",
|
||||
"ApplicableVersion": "any",
|
||||
"AssemblyVersion": "2.0.0.1",
|
||||
"AssemblyVersion": "2.0.0.0",
|
||||
"DalamudApiLevel": 13,
|
||||
"TestingDalamudApiLevel": 13,
|
||||
"Tags": [
|
||||
|
||||
@@ -46,15 +46,6 @@ public class ProfileFileSystem : FileSystem<Profile>, IDisposable, ISavable
|
||||
_profileChanged.Unsubscribe(OnProfileChange);
|
||||
}
|
||||
|
||||
// Search the entire filesystem for the leaf corresponding to a profile.
|
||||
public bool FindLeaf(Profile profile, [NotNullWhen(true)] out Leaf? leaf)
|
||||
{
|
||||
leaf = Root.GetAllDescendants(ISortMode<Profile>.Lexicographical)
|
||||
.OfType<Leaf>()
|
||||
.FirstOrDefault(l => l.Value == profile);
|
||||
return leaf != null;
|
||||
}
|
||||
|
||||
private void OnProfileChange(ProfileChanged.Type type, Profile? profile, object? data)
|
||||
{
|
||||
switch (type)
|
||||
@@ -75,14 +66,14 @@ public class ProfileFileSystem : FileSystem<Profile>, IDisposable, ISavable
|
||||
|
||||
return;
|
||||
case ProfileChanged.Type.Deleted:
|
||||
if (FindLeaf(profile, out var leaf1))
|
||||
if (TryGetValue(profile, out var leaf1))
|
||||
Delete(leaf1);
|
||||
return;
|
||||
case ProfileChanged.Type.ReloadedAll:
|
||||
Reload();
|
||||
return;
|
||||
case ProfileChanged.Type.Renamed when data is string oldName:
|
||||
if (!FindLeaf(profile, out var leaf2))
|
||||
if (!TryGetValue(profile, out var leaf2))
|
||||
return;
|
||||
|
||||
var old = oldName.FixName();
|
||||
|
||||
@@ -47,15 +47,6 @@ public sealed class TemplateFileSystem : FileSystem<Template>, IDisposable, ISav
|
||||
_templateChanged.Unsubscribe(OnTemplateChange);
|
||||
}
|
||||
|
||||
// Search the entire filesystem for the leaf corresponding to a template.
|
||||
public bool FindLeaf(Template template, [NotNullWhen(true)] out Leaf? leaf)
|
||||
{
|
||||
leaf = Root.GetAllDescendants(ISortMode<Template>.Lexicographical)
|
||||
.OfType<Leaf>()
|
||||
.FirstOrDefault(l => l.Value == template);
|
||||
return leaf != null;
|
||||
}
|
||||
|
||||
private void OnTemplateChange(TemplateChanged.Type type, Template? template, object? data)
|
||||
{
|
||||
switch (type)
|
||||
@@ -76,14 +67,14 @@ public sealed class TemplateFileSystem : FileSystem<Template>, IDisposable, ISav
|
||||
|
||||
return;
|
||||
case TemplateChanged.Type.Deleted:
|
||||
if (FindLeaf(template, out var leaf1))
|
||||
if (TryGetValue(template, out var leaf1))
|
||||
Delete(leaf1);
|
||||
return;
|
||||
case TemplateChanged.Type.ReloadedAll:
|
||||
Reload();
|
||||
return;
|
||||
case TemplateChanged.Type.Renamed when data is string oldName:
|
||||
if (!FindLeaf(template, out var leaf2))
|
||||
if (!TryGetValue(template, out var leaf2))
|
||||
return;
|
||||
|
||||
var old = oldName.FixName();
|
||||
|
||||
@@ -29,6 +29,7 @@ public class CPlusChangeLog
|
||||
Add2_0_7_9(Changelog);
|
||||
Add2_0_7_15(Changelog);
|
||||
Add2_0_7_16(Changelog);
|
||||
Add2_0_7_23(Changelog);
|
||||
}
|
||||
|
||||
private (int, ChangeLogDisplayType) ConfigData()
|
||||
@@ -41,6 +42,18 @@ public class CPlusChangeLog
|
||||
_config.Save();
|
||||
}
|
||||
|
||||
private static void Add2_0_7_23(Changelog log)
|
||||
=> log.NextVersion("Version 2.0.7.23")
|
||||
.RegisterImportant("Support for 7.3 and Dalamud API 13.")
|
||||
.RegisterEntry("IPC version updated to 6.1. (2.0.7.20)")
|
||||
.RegisterEntry("Added Profile.AddPlayerCharacter and Profile.RemovePlayerCharacter IPC endpoints. (by Caraxi)", 1)
|
||||
.RegisterEntry("Left side selectors in \"Templates\" and \"Profiles\" tabs can now be resized.")
|
||||
.RegisterEntry("Fixed crashes on login/logout.")
|
||||
.RegisterEntry("This usually happened when when \"Apply Profiles on Character Select Screen\" and/or \"Automatically Set Current Character as Editor Preview Character\" options are enabled in settings.", 1)
|
||||
.RegisterEntry("Fixed root transforms sometimes not resetting when toggling between profiles until character is moved.")
|
||||
.RegisterEntry("Fixed an issue where profiles would attempt to be applied to objects not currently drawn on the screen.")
|
||||
.RegisterEntry("Slight refactoring of user interface code.");
|
||||
|
||||
private static void Add2_0_7_16(Changelog log)
|
||||
=> log.NextVersion("Version 2.0.7.16")
|
||||
.RegisterImportant("Support for update 7.2 and Dalamud API 12.");
|
||||
|
||||
@@ -20,22 +20,19 @@ public class PluginStateBlock
|
||||
private readonly GameStateService _gameStateService;
|
||||
private readonly HookingService _hookingService;
|
||||
private readonly CustomizePlusIpc _ipcService;
|
||||
private readonly DalamudBranchService _dalamudBranchService;
|
||||
|
||||
public PluginStateBlock(
|
||||
BoneEditorPanel boneEditorPanel,
|
||||
PluginConfiguration configuration,
|
||||
GameStateService gameStateService,
|
||||
HookingService hookingService,
|
||||
CustomizePlusIpc ipcService,
|
||||
DalamudBranchService dalamudBranchService)
|
||||
CustomizePlusIpc ipcService)
|
||||
{
|
||||
_boneEditorPanel = boneEditorPanel;
|
||||
_configuration = configuration;
|
||||
_gameStateService = gameStateService;
|
||||
_hookingService = hookingService;
|
||||
_ipcService = ipcService;
|
||||
_dalamudBranchService = dalamudBranchService;
|
||||
}
|
||||
|
||||
public void Draw(float yPos)
|
||||
@@ -79,12 +76,6 @@ public class PluginStateBlock
|
||||
severity = PluginStateSeverity.Error;
|
||||
message = "Detected failure in IPC. Integrations with other plugins will not function.";
|
||||
}
|
||||
else if (!_dalamudBranchService.AllowPluginToRun)
|
||||
{
|
||||
severity = PluginStateSeverity.Error;
|
||||
message = "You are running unsupported version of Dalamud, hover for more information.";
|
||||
hoverInfo = "Regular users are not supposed to run Customize+ on development or testing versions of Dalamud.\nThis is not supported and therefore Customize+ has disabled itself.";
|
||||
}
|
||||
else if(VersionHelper.IsTesting)
|
||||
{
|
||||
severity = PluginStateSeverity.Warning;
|
||||
|
||||
@@ -15,6 +15,7 @@ using CustomizePlus.Profiles.Data;
|
||||
using CustomizePlus.Templates.Events;
|
||||
using CustomizePlus.Templates.Data;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Raii;
|
||||
|
||||
namespace CustomizePlus.UI.Windows.Controls;
|
||||
|
||||
@@ -23,6 +24,10 @@ public abstract class TemplateComboBase : FilterComboCache<Tuple<Template, strin
|
||||
private readonly PluginConfiguration _configuration;
|
||||
private readonly TemplateChanged _templateChanged;
|
||||
// protected readonly TabSelected TabSelected;
|
||||
|
||||
private bool _isCurrentSelectionDirty;
|
||||
private Template? _currentTemplate;
|
||||
|
||||
protected float InnerWidth;
|
||||
|
||||
protected TemplateComboBase(
|
||||
@@ -47,31 +52,27 @@ public abstract class TemplateComboBase : FilterComboCache<Tuple<Template, strin
|
||||
|
||||
protected override bool DrawSelectable(int globalIdx, bool selected)
|
||||
{
|
||||
var ret = base.DrawSelectable(globalIdx, selected);
|
||||
var (design, path) = Items[globalIdx];
|
||||
if (path.Length > 0 && design.Name != path)
|
||||
{
|
||||
var start = ImGui.GetItemRectMin();
|
||||
var pos = start.X + ImGui.CalcTextSize(design.Name.ToString()).X;
|
||||
var maxSize = ImGui.GetWindowPos().X + ImGui.GetWindowContentRegionMax().X;
|
||||
var remainingSpace = maxSize - pos;
|
||||
var requiredSize = ImGui.CalcTextSize(path).X + ImGui.GetStyle().ItemInnerSpacing.X;
|
||||
var offset = remainingSpace - requiredSize;
|
||||
if (ImGui.GetScrollMaxY() == 0)
|
||||
offset -= ImGui.GetStyle().ItemInnerSpacing.X;
|
||||
|
||||
if (offset < ImGui.GetStyle().ItemSpacing.X)
|
||||
ImGuiUtil.HoverTooltip(path);
|
||||
else
|
||||
ImGui.GetWindowDrawList().AddText(start with { X = pos + offset },
|
||||
ImGui.GetColorU32(ImGuiCol.TextDisabled), path);
|
||||
}
|
||||
var (template, path) = Items[globalIdx];
|
||||
bool ret;
|
||||
|
||||
using var color = ImRaii.PushColor(ImGuiCol.Text, ColorId.UsedTemplate.Value());
|
||||
ret = base.DrawSelectable(globalIdx, selected);
|
||||
DrawPath(path, template);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static void DrawPath(string path, Template template)
|
||||
{
|
||||
if (path.Length <= 0 || template.Name == path)
|
||||
return;
|
||||
|
||||
DrawRightAligned(template.Name, path, ImGui.GetColorU32(ImGuiCol.TextDisabled));
|
||||
}
|
||||
|
||||
protected bool Draw(Template? currentTemplate, string? label, float width)
|
||||
{
|
||||
_currentTemplate = currentTemplate;
|
||||
UpdateCurrentSelection();
|
||||
InnerWidth = 400 * ImGuiHelpers.GlobalScale;
|
||||
CurrentSelectionIdx = Math.Max(Items.IndexOf(p => currentTemplate == p.Item1), 0);
|
||||
CurrentSelection = Items[CurrentSelectionIdx];
|
||||
@@ -79,9 +80,54 @@ public abstract class TemplateComboBase : FilterComboCache<Tuple<Template, strin
|
||||
var ret = Draw("##template", name, string.Empty, width, ImGui.GetTextLineHeightWithSpacing())
|
||||
&& CurrentSelection != null;
|
||||
|
||||
_currentTemplate = null;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected override void OnMouseWheel(string preview, ref int _2, int steps)
|
||||
{
|
||||
if (!ReferenceEquals(_currentTemplate, CurrentSelection?.Item1))
|
||||
CurrentSelectionIdx = -1;
|
||||
|
||||
base.OnMouseWheel(preview, ref _2, steps);
|
||||
}
|
||||
|
||||
private void UpdateCurrentSelection()
|
||||
{
|
||||
if (!_isCurrentSelectionDirty)
|
||||
return;
|
||||
|
||||
var priorState = IsInitialized;
|
||||
if (priorState)
|
||||
Cleanup();
|
||||
CurrentSelectionIdx = Items.IndexOf(s => ReferenceEquals(s.Item1, CurrentSelection?.Item1));
|
||||
if (CurrentSelectionIdx >= 0)
|
||||
{
|
||||
UpdateSelection(Items[CurrentSelectionIdx]);
|
||||
}
|
||||
else if (Items.Count > 0)
|
||||
{
|
||||
CurrentSelectionIdx = 0;
|
||||
UpdateSelection(Items[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateSelection(null);
|
||||
}
|
||||
|
||||
if (!priorState)
|
||||
Cleanup();
|
||||
_isCurrentSelectionDirty = false;
|
||||
}
|
||||
|
||||
protected override int UpdateCurrentSelected(int currentSelected)
|
||||
{
|
||||
CurrentSelectionIdx = Items.IndexOf(p => _currentTemplate == p.Item1);
|
||||
UpdateSelection(CurrentSelectionIdx >= 0 ? Items[CurrentSelectionIdx] : null);
|
||||
return CurrentSelectionIdx;
|
||||
}
|
||||
|
||||
protected override string ToString(Tuple<Template, string> obj)
|
||||
=> obj.Item1.Name.Text;
|
||||
|
||||
@@ -96,22 +142,31 @@ public abstract class TemplateComboBase : FilterComboCache<Tuple<Template, strin
|
||||
|
||||
private void OnTemplateChange(TemplateChanged.Type type, Template template, object? data = null)
|
||||
{
|
||||
switch (type)
|
||||
_isCurrentSelectionDirty = type switch
|
||||
{
|
||||
case TemplateChanged.Type.Created:
|
||||
case TemplateChanged.Type.Renamed:
|
||||
Cleanup();
|
||||
break;
|
||||
case TemplateChanged.Type.Deleted:
|
||||
Cleanup();
|
||||
if (CurrentSelection?.Item1 == template)
|
||||
{
|
||||
CurrentSelectionIdx = -1;
|
||||
CurrentSelection = null;
|
||||
}
|
||||
TemplateChanged.Type.Created => true,
|
||||
TemplateChanged.Type.Renamed => true,
|
||||
TemplateChanged.Type.Deleted => true,
|
||||
_ => _isCurrentSelectionDirty,
|
||||
};
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
private static void DrawRightAligned(string leftText, string text, uint color)
|
||||
{
|
||||
var start = ImGui.GetItemRectMin();
|
||||
var pos = start.X + ImGui.CalcTextSize(leftText).X;
|
||||
var maxSize = ImGui.GetWindowPos().X + ImGui.GetWindowContentRegionMax().X;
|
||||
var remainingSpace = maxSize - pos;
|
||||
var requiredSize = ImGui.CalcTextSize(text).X + ImGui.GetStyle().ItemInnerSpacing.X;
|
||||
var offset = remainingSpace - requiredSize;
|
||||
if (ImGui.GetScrollMaxY() == 0)
|
||||
offset -= ImGui.GetStyle().ItemInnerSpacing.X;
|
||||
|
||||
if (offset < ImGui.GetStyle().ItemSpacing.X)
|
||||
ImGuiUtil.HoverTooltip(text);
|
||||
else
|
||||
ImGui.GetWindowDrawList().AddText(start with { X = pos + offset },
|
||||
color, text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +184,7 @@ public sealed class TemplateCombo : TemplateComboBase
|
||||
PluginConfiguration configuration)
|
||||
: base(
|
||||
() => templateManager.Templates
|
||||
.Select(d => new Tuple<Template, string>(d, fileSystem.FindLeaf(d, out var l) ? l.FullName() : string.Empty))
|
||||
.Select(d => new Tuple<Template, string>(d, fileSystem.TryGetValue(d, out var l) ? l.FullName() : string.Empty))
|
||||
.OrderBy(d => d.Item2)
|
||||
.ToList(), logger, templateChanged,/* tabSelected, */configuration)
|
||||
{
|
||||
|
||||
@@ -38,7 +38,6 @@ public class MainWindow : Window, IDisposable
|
||||
private readonly TemplateEditorManager _templateEditorManager;
|
||||
private readonly PluginConfiguration _configuration;
|
||||
private readonly HookingService _hookingService;
|
||||
private readonly DalamudBranchService _dalamudBranchService;
|
||||
|
||||
private readonly TemplateEditorEvent _templateEditorEvent;
|
||||
|
||||
@@ -61,7 +60,6 @@ public class MainWindow : Window, IDisposable
|
||||
TemplateEditorManager templateEditorManager,
|
||||
PluginConfiguration configuration,
|
||||
HookingService hookingService,
|
||||
DalamudBranchService dalamudBranchService,
|
||||
TemplateEditorEvent templateEditorEvent
|
||||
) : base($"Customize+ {VersionHelper.Version}###CPlusMainWindow")
|
||||
{
|
||||
@@ -77,7 +75,6 @@ public class MainWindow : Window, IDisposable
|
||||
_templateEditorManager = templateEditorManager;
|
||||
_configuration = configuration;
|
||||
_hookingService = hookingService;
|
||||
_dalamudBranchService = dalamudBranchService;
|
||||
|
||||
_templateEditorEvent = templateEditorEvent;
|
||||
|
||||
@@ -101,7 +98,7 @@ public class MainWindow : Window, IDisposable
|
||||
{
|
||||
var yPos = ImGui.GetCursorPosY();
|
||||
|
||||
using (var disabled = ImRaii.Disabled(_hookingService.RenderHookFailed || _hookingService.MovementHookFailed || !_dalamudBranchService.AllowPluginToRun))
|
||||
using (var disabled = ImRaii.Disabled(_hookingService.RenderHookFailed || _hookingService.MovementHookFailed))
|
||||
{
|
||||
LockWindowClosureIfNeeded();
|
||||
ImGuiEx.EzTabBar("##tabs", null, _switchToTab, [
|
||||
|
||||
@@ -96,7 +96,7 @@ public class StateMonitoringTab
|
||||
{
|
||||
foreach (var kvPair in _objectManager)
|
||||
{
|
||||
var show = ImGui.CollapsingHeader($"{kvPair.Key} ({kvPair.Value.Objects.Count} objects)###object-{kvPair.Key}");
|
||||
var show = ImGui.CollapsingHeader($"{kvPair.Key} ({kvPair.Value.Objects.Count} objects [{kvPair.Value.Objects.Count(x => x.IsRenderedByGame())} rendered])###object-{kvPair.Key}");
|
||||
|
||||
if (!show)
|
||||
continue;
|
||||
@@ -124,7 +124,7 @@ public class StateMonitoringTab
|
||||
ImGui.Text($"Count: {kvPair.Value.Objects.Count}");
|
||||
foreach (var item in kvPair.Value.Objects)
|
||||
{
|
||||
ImGui.Text($"[{item.Index}] - {item}, valid: {item.Valid}");
|
||||
ImGui.Text($"[{item.Index}] - {item}, valid: {item.Valid}, rendered: {item.IsRenderedByGame()}");
|
||||
}
|
||||
|
||||
ImGui.Spacing();
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
using Dalamud.Interface;
|
||||
using CustomizePlus.Configuration.Data;
|
||||
using CustomizePlus.Game.Services;
|
||||
using CustomizePlus.GameData.Extensions;
|
||||
using CustomizePlus.Profiles;
|
||||
using CustomizePlus.Profiles.Data;
|
||||
using CustomizePlus.Profiles.Events;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.FileSystem.Selector;
|
||||
using OtterGui.Filesystem;
|
||||
using OtterGui.Log;
|
||||
using OtterGui;
|
||||
using System;
|
||||
using static CustomizePlus.UI.Windows.MainWindow.Tabs.Profiles.ProfileFileSystemSelector;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Filesystem;
|
||||
using OtterGui.FileSystem.Selector;
|
||||
using OtterGui.Log;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
using CustomizePlus.Profiles;
|
||||
using CustomizePlus.Configuration.Data;
|
||||
using CustomizePlus.Profiles.Data;
|
||||
using CustomizePlus.Game.Services;
|
||||
using CustomizePlus.Profiles.Events;
|
||||
using CustomizePlus.GameData.Extensions;
|
||||
using System.Linq;
|
||||
using OtterGui.Text;
|
||||
using static CustomizePlus.UI.Windows.MainWindow.Tabs.Profiles.ProfileFileSystemSelector;
|
||||
|
||||
namespace CustomizePlus.UI.Windows.MainWindow.Tabs.Profiles;
|
||||
|
||||
@@ -48,18 +48,27 @@ public class ProfileFileSystemSelector : FileSystemSelector<Profile, ProfileStat
|
||||
public ColorId Color;
|
||||
}
|
||||
|
||||
|
||||
protected override float CurrentWidth
|
||||
=> _configuration.UISettings.CurrentProfileSelectorWidth * ImUtf8.GlobalScale;
|
||||
|
||||
protected override float MinimumAbsoluteRemainder
|
||||
=> 670 * ImUtf8.GlobalScale;
|
||||
=> 470 * ImUtf8.GlobalScale;
|
||||
|
||||
protected override float MinimumScaling
|
||||
=> _configuration.UISettings.ProfileSelectorMinimumScale;
|
||||
|
||||
protected override float MaximumScaling
|
||||
=> _configuration.UISettings.ProfileSelectorMaximumScale;
|
||||
|
||||
protected override void SetSize(Vector2 size)
|
||||
{
|
||||
base.SetSize(size);
|
||||
var adaptedSize = MathF.Round(size.X / ImUtf8.GlobalScale);
|
||||
if (adaptedSize == _configuration.UISettings.CurrentProfileSelectorWidth)
|
||||
return;
|
||||
|
||||
_configuration.UISettings.CurrentProfileSelectorWidth = adaptedSize;
|
||||
_configuration.Save();
|
||||
}
|
||||
|
||||
public ProfileFileSystemSelector(
|
||||
|
||||
@@ -20,7 +20,6 @@ using CustomizePlus.GameData.Extensions;
|
||||
using CustomizePlus.Core.Extensions;
|
||||
using Dalamud.Interface.Components;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Text;
|
||||
|
||||
namespace CustomizePlus.UI.Windows.MainWindow.Tabs.Profiles;
|
||||
|
||||
@@ -68,7 +67,7 @@ public class ProfilePanel
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
using var group = ImUtf8.Group();
|
||||
using var group = ImRaii.Group();
|
||||
if (_selector.SelectedPaths.Count > 1)
|
||||
{
|
||||
DrawMultiSelection();
|
||||
@@ -194,7 +193,7 @@ public class ProfilePanel
|
||||
{
|
||||
using (var table = ImRaii.Table("BasicSettings", 2))
|
||||
{
|
||||
ImGui.TableSetupColumn("BasicCol1", ImGuiTableColumnFlags.WidthFixed, 200);
|
||||
ImGui.TableSetupColumn("BasicCol1", ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("lorem ipsum dolor").X);
|
||||
ImGui.TableSetupColumn("BasicCol2", ImGuiTableColumnFlags.WidthStretch);
|
||||
|
||||
ImGuiUtil.DrawFrameColumn("Profile Name");
|
||||
@@ -506,7 +505,7 @@ public class ProfilePanel
|
||||
if (source)
|
||||
{
|
||||
ImGui.TextUnformatted($"Moving template #{index + 1:D2}...");
|
||||
if (ImGui.SetDragDropPayload(dragDropLabel, ReadOnlySpan<byte>.Empty, 0))
|
||||
if (ImGui.SetDragDropPayload(dragDropLabel, null, 0))
|
||||
{
|
||||
_dragIndex = index;
|
||||
}
|
||||
|
||||
@@ -368,10 +368,12 @@ public class SettingsTab
|
||||
xPos -= ImGui.GetStyle().ScrollbarSize + ImGui.GetStyle().FramePadding.X;
|
||||
|
||||
ImGui.SetCursorPos(new Vector2(xPos, 0));
|
||||
DrawUrlButton("Join Discord for Support", "https://discord.gg/KvGJCCnG8t", DiscordColor, width);
|
||||
DrawUrlButton("Join Discord for Support", "https://discord.gg/KvGJCCnG8t", DiscordColor, width,
|
||||
"Join Discord server run by community volunteers who can help you with your questions. Opens https://discord.gg/KvGJCCnG8t in your web browser.");
|
||||
|
||||
ImGui.SetCursorPos(new Vector2(xPos, ImGui.GetFrameHeightWithSpacing()));
|
||||
DrawUrlButton("Support developer using Ko-fi", "https://ko-fi.com/risadev", DonateColor, width);
|
||||
DrawUrlButton("Support developer using Ko-fi", "https://ko-fi.com/risadev", DonateColor, width,
|
||||
"Any donations made are voluntary and treated as a token of gratitude for work done on Customize+. Opens https://ko-fi.com/risadev in your web browser.");
|
||||
|
||||
ImGui.SetCursorPos(new Vector2(xPos, 2 * ImGui.GetFrameHeightWithSpacing()));
|
||||
if (ImGui.Button("Copy Support Info to Clipboard"))
|
||||
@@ -387,7 +389,7 @@ public class SettingsTab
|
||||
}
|
||||
|
||||
/// <summary> Draw a button to open some url. </summary>
|
||||
private void DrawUrlButton(string text, string url, uint buttonColor, float width)
|
||||
private void DrawUrlButton(string text, string url, uint buttonColor, float width, string? description = null)
|
||||
{
|
||||
using var color = ImRaii.PushColor(ImGuiCol.Button, buttonColor);
|
||||
if (ImGui.Button(text, new Vector2(width, 0)))
|
||||
@@ -404,7 +406,7 @@ public class SettingsTab
|
||||
_messageService.NotificationMessage($"Unable to open url {url}.", NotificationType.Error, false);
|
||||
}
|
||||
|
||||
ImGuiUtil.HoverTooltip($"Open {url}");
|
||||
ImGuiUtil.HoverTooltip(description ?? $"Open {url}");
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
using Dalamud.Interface;
|
||||
using CustomizePlus.Anamnesis;
|
||||
using CustomizePlus.Configuration.Data;
|
||||
using CustomizePlus.Configuration.Data.Version2;
|
||||
using CustomizePlus.Configuration.Data.Version3;
|
||||
using CustomizePlus.Configuration.Helpers;
|
||||
using CustomizePlus.Core.Helpers;
|
||||
using CustomizePlus.Profiles;
|
||||
using CustomizePlus.Profiles.Data;
|
||||
using CustomizePlus.Profiles.Events;
|
||||
using CustomizePlus.Templates;
|
||||
using CustomizePlus.Templates.Data;
|
||||
using CustomizePlus.Templates.Events;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.ImGuiFileDialog;
|
||||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Newtonsoft.Json;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Filesystem;
|
||||
using OtterGui.FileSystem.Selector;
|
||||
using OtterGui.Log;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using static CustomizePlus.UI.Windows.MainWindow.Tabs.Templates.TemplateFileSystemSelector;
|
||||
using Newtonsoft.Json;
|
||||
using System.Linq;
|
||||
using Dalamud.Interface.ImGuiFileDialog;
|
||||
using System.IO;
|
||||
using CustomizePlus.Templates;
|
||||
using CustomizePlus.Configuration.Data;
|
||||
using CustomizePlus.Profiles;
|
||||
using CustomizePlus.Core.Helpers;
|
||||
using CustomizePlus.Anamnesis;
|
||||
using CustomizePlus.Profiles.Data;
|
||||
using CustomizePlus.Templates.Events;
|
||||
using CustomizePlus.Profiles.Events;
|
||||
using CustomizePlus.Templates.Data;
|
||||
using CustomizePlus.Configuration.Helpers;
|
||||
using CustomizePlus.Configuration.Data.Version3;
|
||||
using CustomizePlus.Configuration.Data.Version2;
|
||||
using Dalamud.Interface.ImGuiNotification;
|
||||
using OtterGui.Text;
|
||||
|
||||
namespace CustomizePlus.UI.Windows.MainWindow.Tabs.Templates;
|
||||
|
||||
@@ -66,18 +66,29 @@ public class TemplateFileSystemSelector : FileSystemSelector<Template, TemplateS
|
||||
public ColorId Color;
|
||||
}
|
||||
|
||||
protected override float CurrentWidth
|
||||
=> _configuration.UISettings.CurrentTemplateSelectorWidth * ImUtf8.GlobalScale;
|
||||
|
||||
protected override float MinimumAbsoluteRemainder
|
||||
=> 670 * ImUtf8.GlobalScale;
|
||||
=> 470 * ImUtf8.GlobalScale;
|
||||
|
||||
protected override float MinimumScaling
|
||||
=> _configuration.UISettings.TemplateSelectorMinimumScale;
|
||||
|
||||
protected override float MaximumScaling
|
||||
=> _configuration.UISettings.TemplateSelectorMaximumScale;
|
||||
|
||||
protected override void SetSize(Vector2 size)
|
||||
{
|
||||
base.SetSize(size);
|
||||
var adaptedSize = MathF.Round(size.X / ImUtf8.GlobalScale);
|
||||
if (adaptedSize == _configuration.UISettings.CurrentTemplateSelectorWidth)
|
||||
return;
|
||||
|
||||
_configuration.UISettings.CurrentTemplateSelectorWidth = adaptedSize;
|
||||
_configuration.Save();
|
||||
}
|
||||
|
||||
public TemplateFileSystemSelector(
|
||||
TemplateFileSystem fileSystem,
|
||||
IKeyState keyState,
|
||||
@@ -215,7 +226,6 @@ public class TemplateFileSystemSelector : FileSystemSelector<Template, TemplateS
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void DrawStealTemplatePopup()
|
||||
{
|
||||
if (!ImGuiUtil.OpenNameField("##StealTemplate", ref _newName))
|
||||
@@ -230,7 +240,7 @@ public class TemplateFileSystemSelector : FileSystemSelector<Template, TemplateS
|
||||
|
||||
foreach (var template in profile.Templates)
|
||||
{
|
||||
if(profile.Characters.First().PlayerName.ToString().ToLower() == _playerNameSteal.ToLower())
|
||||
if (profile.Characters.First().PlayerName.ToString().ToLower() == _playerNameSteal.ToLower())
|
||||
{
|
||||
var copiedTemplate = new Template(template);
|
||||
_templateManager.Clone(copiedTemplate, _newName, true);
|
||||
@@ -327,29 +337,6 @@ public class TemplateFileSystemSelector : FileSystemSelector<Template, TemplateS
|
||||
ImGui.OpenPopup("##NewTemplate");
|
||||
}
|
||||
|
||||
private void ClipboardImportButton(Vector2 size)
|
||||
{
|
||||
if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Clipboard.ToIconString(), size, "Try to import a template from your clipboard.", false,
|
||||
true))
|
||||
return;
|
||||
|
||||
if (_editorManager.IsEditorActive)
|
||||
{
|
||||
ShowEditorWarningPopup();
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_clipboardText = ImGui.GetClipboardText();
|
||||
ImGui.OpenPopup("##NewTemplate");
|
||||
}
|
||||
catch
|
||||
{
|
||||
_messageService.NotificationMessage("Could not import data from clipboard.", NotificationType.Error, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void StealButton(Vector2 size)
|
||||
{
|
||||
if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Baby.ToIconString(), size, "Steal from targeted player", false,
|
||||
@@ -395,6 +382,29 @@ public class TemplateFileSystemSelector : FileSystemSelector<Template, TemplateS
|
||||
}
|
||||
}
|
||||
|
||||
private void ClipboardImportButton(Vector2 size)
|
||||
{
|
||||
if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Clipboard.ToIconString(), size, "Try to import a template from your clipboard.", false,
|
||||
true))
|
||||
return;
|
||||
|
||||
if (_editorManager.IsEditorActive)
|
||||
{
|
||||
ShowEditorWarningPopup();
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_clipboardText = ImGui.GetClipboardText();
|
||||
ImGui.OpenPopup("##NewTemplate");
|
||||
}
|
||||
catch
|
||||
{
|
||||
_messageService.NotificationMessage("Could not import data from clipboard.", NotificationType.Error, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void AnamnesisImportButton(Vector2 size)
|
||||
{
|
||||
if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.FileImport.ToIconString(), size, "Import a template from anamnesis pose file (scaling only)", false,
|
||||
|
||||
@@ -49,7 +49,5 @@ public partial class PopupSystem
|
||||
RegisterPopup(Messages.ClipboardDataUnsupported, "Clipboard data you are trying to use cannot be used in this version of Customize+.");
|
||||
|
||||
RegisterPopup(Messages.ClipboardDataNotLongTerm, "Warning: clipboard data is not designed to be used as long-term way of storing your templates.\nCompatibility of copied data between different Customize+ versions is not guaranteed.", true, new Vector2(5, 10));
|
||||
|
||||
RegisterPopup(Messages.PluginDisabledNonReleaseDalamud, DalamudBranchService.PluginDisabledMessage + "\nThis notification will not be shown again.", true, new Vector2(5, 6));
|
||||
}
|
||||
}
|
||||
|
||||
1
submodules/ECommonsLite
Submodule
1
submodules/ECommonsLite
Submodule
Submodule submodules/ECommonsLite added at 59509f4510
398
submodules/ECommonsLite/.gitignore
vendored
398
submodules/ECommonsLite/.gitignore
vendored
@@ -1,398 +0,0 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.tlog
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
|
||||
*.vbp
|
||||
|
||||
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
||||
*.dsw
|
||||
*.dsp
|
||||
|
||||
# Visual Studio 6 technical files
|
||||
*.ncb
|
||||
*.aps
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# Visual Studio History (VSHistory) files
|
||||
.vshistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
|
||||
# VS Code files for those working on multiple tools
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
*.code-workspace
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Windows Installer files from build outputs
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# JetBrains Rider
|
||||
*.sln.iml
|
||||
@@ -1,25 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.10.35004.147
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ECommonsLite", "ECommonsLite\ECommonsLite.csproj", "{2F14DE07-8C8C-44D0-950B-60D2E942EF50}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{2F14DE07-8C8C-44D0-950B-60D2E942EF50}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2F14DE07-8C8C-44D0-950B-60D2E942EF50}.Debug|x64.Build.0 = Debug|x64
|
||||
{2F14DE07-8C8C-44D0-950B-60D2E942EF50}.Release|x64.ActiveCfg = Release|x64
|
||||
{2F14DE07-8C8C-44D0-950B-60D2E942EF50}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {CBF7B859-9282-49CD-9D29-E09FB3480574}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,35 +0,0 @@
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Game.ClientState.Objects;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Services;
|
||||
using ECommonsLite.Logging;
|
||||
using System;
|
||||
|
||||
namespace ECommonsLite.DalamudServices;
|
||||
#nullable disable
|
||||
|
||||
public class Svc
|
||||
{
|
||||
[PluginService] public static IDalamudPluginInterface PluginInterface { get; private set; }
|
||||
[PluginService] public static IFramework Framework { get; private set; }
|
||||
[PluginService] public static IPluginLog Log { get; private set; }
|
||||
|
||||
internal static bool IsInitialized = false;
|
||||
public static void Init(IDalamudPluginInterface pi)
|
||||
{
|
||||
if(IsInitialized)
|
||||
{
|
||||
PluginLog.Debug("Services already initialized, skipping");
|
||||
}
|
||||
IsInitialized = true;
|
||||
try
|
||||
{
|
||||
pi.Create<Svc>();
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
ex.Log();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
<Project Sdk="Dalamud.NET.Sdk/13.0.0">
|
||||
|
||||
<PropertyGroup>
|
||||
<NoWarn>CS1591;CA1401;CS0649;CS8632;CS0414;CS0169;IDE1006;CS0419</NoWarn>
|
||||
<Optimize>True</Optimize>
|
||||
<IsTrimmable>false</IsTrimmable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<Use_DalamudPackager>false</Use_DalamudPackager>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,38 +0,0 @@
|
||||
using Dalamud.Plugin;
|
||||
using ECommonsLite.DalamudServices;
|
||||
using ECommonsLite.EzIpcManager;
|
||||
using ECommonsLite.Logging;
|
||||
using Serilog.Events;
|
||||
using System.Reflection;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace ECommonsLite;
|
||||
|
||||
public static class ECommonsLiteMain
|
||||
{
|
||||
public static IDalamudPlugin Instance = null;
|
||||
public static bool Disposed { get; private set; } = false;
|
||||
//test
|
||||
public static void Init(IDalamudPluginInterface pluginInterface, IDalamudPlugin instance, params Module[] modules)
|
||||
{
|
||||
Instance = instance;
|
||||
GenericHelpers.Safe(() => Svc.Init(pluginInterface));
|
||||
#if DEBUG
|
||||
var type = "debug build";
|
||||
#elif RELEASE
|
||||
var type = "release build";
|
||||
#else
|
||||
var type = "unknown build";
|
||||
#endif
|
||||
PluginLog.Information($"This is ECommonsLite v{typeof(ECommonsLiteMain).Assembly.GetName().Version} ({type}) and {Svc.PluginInterface.InternalName} v{instance.GetType().Assembly.GetName().Version}. Hello!");
|
||||
Svc.Log.MinimumLogLevel = LogEventLevel.Verbose;
|
||||
}
|
||||
|
||||
public static void Dispose()
|
||||
{
|
||||
Disposed = true;
|
||||
GenericHelpers.Safe(EzIPC.Dispose);
|
||||
Instance = null;
|
||||
}
|
||||
}
|
||||
@@ -1,303 +0,0 @@
|
||||
using ECommonsLite.DalamudServices;
|
||||
using ECommonsLite.Logging;
|
||||
using ECommonsLite.Reflection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ECommonsLite.EzIpcManager;
|
||||
|
||||
/// <summary>
|
||||
/// Provides easier way to interact with Dalamud IPC.<br></br>
|
||||
/// See EzIPC.md for example use.
|
||||
/// </summary>
|
||||
public static class EzIPC
|
||||
{
|
||||
/// <summary>
|
||||
/// Event that fires whenever an exception occurs in any of safe invocation wrapper methods.
|
||||
/// </summary>
|
||||
public static event Action<Exception>? OnSafeInvocationException;
|
||||
|
||||
internal static void InvokeOnSafeInvocationException(Exception e) => OnSafeInvocationException?.Invoke(e);
|
||||
|
||||
private static List<EzIPCDisposalToken> Unregister = [];
|
||||
private static Type[] FuncTypes = [typeof(Func<>), typeof(Func<,>), typeof(Func<,,>), typeof(Func<,,,>), typeof(Func<,,,,>), typeof(Func<,,,,,>), typeof(Func<,,,,,,>), typeof(Func<,,,,,,,>), typeof(Func<,,,,,,,,>), typeof(Func<,,,,,,,,,>)];
|
||||
private static Type[] ActionTypes = [typeof(Action<>), typeof(Action<,>), typeof(Action<,,>), typeof(Action<,,,>), typeof(Action<,,,,>), typeof(Action<,,,,,>), typeof(Action<,,,,,,>), typeof(Action<,,,,,,,>), typeof(Action<,,,,,,,,>), typeof(Action<,,,,,,,,,>)];
|
||||
|
||||
/// <summary>
|
||||
/// Initializes IPC provider and subscriber for an instance type. Static methods or field/properties/properties will be ignored, register them separately via static Init if you must.<br></br>
|
||||
/// Each method that have <see cref="EzIPCAttribute"/> or <see cref="EzIPCEventAttribute"/> will be registered for IPC under "Prefix.IPCName" tag. If prefix is not specified, it is your plugin's internal name. If IPCName is not specified, it is method name.<br></br>
|
||||
/// Each Action and Function field/property that have <see cref="EzIPCAttribute"/> will be assigned delegate that represents respective GetIPCSubscriber. Each Action field/property that have <see cref="EzIPCEventAttribute"/> will be assigned to become respective tag's event trigger. Make sure to explicitly specify prefix if you're interacting with other plugin's IPC.<br></br>
|
||||
/// You do not need to dispose IPC methods in any way. Everything is disposed upon calling <see cref="ECommonsLiteMain.Dispose"/>.
|
||||
/// </summary>
|
||||
/// <param name="instance">Instance of a class that has EzIPC methods and field/properties/properties.</param>
|
||||
/// <param name="prefix">Name prefix</param>
|
||||
/// <param name="safeWrapper">Type of a safe invocation wrapper to be used for IPC calls. Wrappers, when used, will silently drop exceptions and return default object if invocation has failed. You can subscribe to <see cref="EzIPC.OnSafeInvocationException"/> event to observe these exceptions.</param>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <returns>Array of disposal tokens that can be used to dispose registered providers and event subscription. <b>Typical use of EzIPC never has any need to store and deal with these tokens</b>; you only ever need them when you want to unregister IPC before your plugin's Dispose method is called.</returns>
|
||||
public static EzIPCDisposalToken[] Init(object instance, string? prefix = null, SafeWrapper safeWrapper = SafeWrapper.None) => Init(instance, instance.GetType(), prefix, safeWrapper);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes IPC provider and subscriber for a static type.<br></br>
|
||||
/// Each method that have <see cref="EzIPCAttribute"/> or <see cref="EzIPCEventAttribute"/> will be registered for IPC under "Prefix.IPCName" tag. If prefix is not specified, it is your plugin's internal name. If IPCName is not specified, it is method name.<br></br>
|
||||
/// Each Action and Function field/property that have <see cref="EzIPCAttribute"/> will be assigned delegate that represents respective GetIPCSubscriber. Each Action field/property that have <see cref="EzIPCEventAttribute"/> will be assigned to become respective tag's event trigger. Make sure to explicitly specify prefix if you're interacting with other plugin's IPC.<br></br>
|
||||
/// You do not need to dispose IPC methods in any way. Everything is disposed upon calling <see cref="ECommonsLiteMain.Dispose"/>.
|
||||
/// </summary>
|
||||
/// <param name="staticType">Type of a static class that has EzIPC methods and field/properties/properties.</param>
|
||||
/// <param name="prefix">Name prefix</param>
|
||||
/// <param name="safeWrapper">Type of a safe invocation wrapper to be used for IPC calls. Wrappers, when used, will silently drop exceptions and return default object if invocation has failed. You can subscribe to <see cref="EzIPC.OnSafeInvocationException"/> event to observe these exceptions.</param>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <returns>Array of disposal tokens that can be used to dispose registered providers and event subscription. <b>Typical use of EzIPC never has any need to store and deal with these tokens</b>; you only ever need them when you want to unregister IPC before your plugin's Dispose method is called.</returns>
|
||||
public static EzIPCDisposalToken[] Init(Type staticType, string? prefix = null, SafeWrapper safeWrapper = SafeWrapper.None) => Init(null, staticType, prefix, safeWrapper);
|
||||
|
||||
private static EzIPCDisposalToken[] Init(object? instance, Type instanceType, string? prefix, SafeWrapper safeWrapper)
|
||||
{
|
||||
if(safeWrapper == SafeWrapper.Inherit) throw new InvalidOperationException($"{nameof(SafeWrapper.Inherit)} is only valid option when used in EzIPC attribute. Please choose your desired SafeWrapper.");
|
||||
var ret = new List<EzIPCDisposalToken>();
|
||||
var bFlags = BindingFlags.Public | BindingFlags.NonPublic | (instance != null ? BindingFlags.Instance : BindingFlags.Static);
|
||||
//init provider
|
||||
prefix ??= Svc.PluginInterface.InternalName;
|
||||
foreach(var method in instanceType.GetMethods(bFlags))
|
||||
{
|
||||
try
|
||||
{
|
||||
var attr = method.GetCustomAttributes(true).OfType<EzIPCAttribute>().FirstOrDefault();
|
||||
if(attr != null)
|
||||
{
|
||||
PluginLog.Information($"[EzIPC Provider] Attempting to register {instanceType.Name}.{method.Name} as IPC method ({method.GetParameters().Length})");
|
||||
var ipcName = attr.IPCName ?? method.Name;
|
||||
ipcName = ipcName.Replace("%m", method.Name);
|
||||
ipcName = ipcName.Replace("%p", Svc.PluginInterface.InternalName);
|
||||
var reg = FindIpcProvider(method.GetParameters().Length + 1) ?? throw new NullReferenceException("[EzIPC Provider] Could not retrieve GetIpcProvider. Did you called EzIPC.Init before ECommonsMain.Init or specified more than 9 arguments?");
|
||||
var isAction = method.ReturnType == typeof(void);
|
||||
var genericArray = (Type[])[.. method.GetParameters().Select(x => x.ParameterType), isAction ? attr.ActionLastGenericType : method.ReturnType];
|
||||
var genericMethod = reg.MakeGenericMethod([.. genericArray]);
|
||||
var name = attr.ApplyPrefix ? $"{prefix}.{ipcName}" : ipcName;
|
||||
PluginLog.Information($"[EzIPC Provider] Registering IPC method {name} with method {instanceType.FullName}.{method.Name}");
|
||||
genericMethod.Invoke(Svc.PluginInterface, [name]).Call(isAction ? "RegisterAction" : "RegisterFunc", [ReflectionHelper.CreateDelegate(method, instance)], true);
|
||||
var token = new EzIPCDisposalToken(name, false, () =>
|
||||
{
|
||||
PluginLog.Information($"[EzIPC Provider] Unregistering IPC method {name}");
|
||||
genericMethod.Invoke(Svc.PluginInterface, [name]).Call(isAction ? "UnregisterAction" : "UnregisterFunc", [], true);
|
||||
});
|
||||
ret.Add(token);
|
||||
Unregister.Add(token);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
PluginLog.Error($"[EzIPC Provider] Failed to initialize provider for {instanceType.Name}.{method.Name}");
|
||||
e.Log();
|
||||
}
|
||||
}
|
||||
|
||||
//init subscriber
|
||||
foreach(var reference in instanceType.GetFieldPropertyUnions(bFlags))
|
||||
{
|
||||
try
|
||||
{
|
||||
var attr = reference.GetCustomAttributes(true).OfType<EzIPCAttribute>().FirstOrDefault();
|
||||
if(attr != null)
|
||||
{
|
||||
var ipcName = attr.IPCName ?? reference.Name;
|
||||
ipcName = ipcName.Replace("%m", reference.Name);
|
||||
ipcName = ipcName.Replace("%p", Svc.PluginInterface.InternalName);
|
||||
var isNonGenericAction = reference.UnionType == typeof(Action);
|
||||
if(isNonGenericAction || reference.UnionType.GetGenericTypeDefinition().EqualsAny([.. FuncTypes, .. ActionTypes]))
|
||||
{
|
||||
var wrapper = attr.Wrapper == SafeWrapper.Inherit ? safeWrapper : attr.Wrapper;
|
||||
PluginLog.Information($"[EzIPC Subscriber] Attempting to assign IPC method to {instanceType.Name}.{reference.Name} with wrapper {wrapper}");
|
||||
var isAction = isNonGenericAction || reference.UnionType.GetGenericTypeDefinition().EqualsAny(ActionTypes);
|
||||
var genericArgsLen = reference.UnionType.GetGenericArguments().Length;
|
||||
var reg = FindIpcSubscriber(genericArgsLen + (isAction ? 1 : 0)) ?? throw new NullReferenceException("Could not retrieve GetIpcSubscriber. Did you called EzIPC.Init before ECommonsMain.Init or specified more than 9 arguments?");
|
||||
var genericArgs = reference.UnionType.IsGenericType ? reference.UnionType.GetGenericArguments() : [];
|
||||
var adjustedGenericArgs = isAction ? [.. genericArgs, attr.ActionLastGenericType] : genericArgs;
|
||||
var genericMethod = reg.MakeGenericMethod(adjustedGenericArgs);
|
||||
var name = attr.ApplyPrefix ? $"{prefix}.{ipcName}" : ipcName;
|
||||
var callerInfo = genericMethod.Invoke(Svc.PluginInterface, [name])!;
|
||||
var invocationDelegate = ReflectionHelper.CreateDelegate(callerInfo.GetType().GetMethod(isAction ? "InvokeAction" : "InvokeFunc"), callerInfo);
|
||||
if(wrapper != SafeWrapper.None)
|
||||
{
|
||||
var safeWrapperObj = CreateSafeWrapper(wrapper, adjustedGenericArgs) ?? throw new NullReferenceException("Safe wrapper creation failed. Please report this exception to developer.");
|
||||
var safeWrapperMethod = safeWrapperObj.GetType().GetMethod(isAction ? "InvokeAction" : "InvokeFunction", ReflectionHelper.AllFlags);
|
||||
safeWrapperObj.SetFoP(isAction ? "Action" : "Function", invocationDelegate);
|
||||
reference.SetValue(instance, ReflectionHelper.CreateDelegate(safeWrapperMethod, safeWrapperObj));
|
||||
}
|
||||
else
|
||||
{
|
||||
reference.SetValue(instance, invocationDelegate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
PluginLog.Error($"[EzIPC Subscriber] Failed to initialize subscriber for {instanceType.Name}.{reference.Name}");
|
||||
e.Log();
|
||||
}
|
||||
}
|
||||
|
||||
//init subscriber event
|
||||
prefix ??= Svc.PluginInterface.InternalName;
|
||||
foreach(var method in instanceType.GetMethods(bFlags))
|
||||
{
|
||||
try
|
||||
{
|
||||
var attr = method.GetCustomAttributes(true).OfType<EzIPCEventAttribute>().FirstOrDefault();
|
||||
if(attr != null)
|
||||
{
|
||||
PluginLog.Information($"[EzIPC Subscriber] Attempting to register {instanceType.Name}.{method.Name} as IPC event ({method.GetParameters().Length})");
|
||||
var ipcName = attr.IPCName ?? method.Name;
|
||||
ipcName = ipcName.Replace("%m", method.Name);
|
||||
ipcName = ipcName.Replace("%p", Svc.PluginInterface.InternalName);
|
||||
var reg = FindIpcSubscriber(method.GetParameters().Length + 1) ?? throw new NullReferenceException("[EzIPC Provider] Could not retrieve FindIpcSubscriber. Did you called EzIPC.Init before ECommonsMain.Init or specified more than 9 arguments?");
|
||||
if(method.ReturnType != typeof(void)) throw new InvalidOperationException($"Event method must have void return value");
|
||||
var genericArray = (Type[])[.. method.GetParameters().Select(x => x.ParameterType), attr.ActionLastGenericType];
|
||||
var genericMethod = reg.MakeGenericMethod([.. genericArray]);
|
||||
var name = attr.ApplyPrefix ? $"{prefix}.{ipcName}" : ipcName;
|
||||
PluginLog.Information($"[EzIPC Subscriber] Registering IPC event {name} with method {instanceType.FullName}.{method.Name}");
|
||||
var d = ReflectionHelper.CreateDelegate(method, instance);
|
||||
genericMethod.Invoke(Svc.PluginInterface, [name]).Call("Subscribe", [d], true);
|
||||
var token = new EzIPCDisposalToken(name, true, () =>
|
||||
{
|
||||
PluginLog.Information($"[EzIPC Subscriber] Unregistering IPC event {name}");
|
||||
genericMethod.Invoke(Svc.PluginInterface, [name]).Call("Unsubscribe", [d], true);
|
||||
});
|
||||
Unregister.Add(token);
|
||||
ret.Add(token);
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
PluginLog.Error($"[EzIPC Subscriber] Failed to subscribe for event for {instanceType.Name}.{method.Name}");
|
||||
e.Log();
|
||||
}
|
||||
}
|
||||
|
||||
//init provider event
|
||||
foreach(var reference in instanceType.GetFieldPropertyUnions(bFlags))
|
||||
{
|
||||
try
|
||||
{
|
||||
var attr = reference.GetCustomAttributes(true).OfType<EzIPCEventAttribute>().FirstOrDefault();
|
||||
if(attr != null)
|
||||
{
|
||||
var ipcName = attr.IPCName ?? reference.Name;
|
||||
ipcName = ipcName.Replace("%m", reference.Name);
|
||||
ipcName = ipcName.Replace("%p", Svc.PluginInterface.InternalName);
|
||||
var isNonGenericAction = reference.UnionType == typeof(Action);
|
||||
if(isNonGenericAction || reference.UnionType.GetGenericTypeDefinition().EqualsAny(ActionTypes))
|
||||
{
|
||||
PluginLog.Information($"[EzIPC Provider] Attempting to assign IPC event to {instanceType.Name}.{reference.Name}");
|
||||
var reg = FindIpcProvider(reference.UnionType.GetGenericArguments().Length + 1) ?? throw new NullReferenceException("Could not retrieve GetIpcProvider. Did you called EzIPC.Init before ECommonsMain.Init or specified more than 9 arguments?");
|
||||
var genericArgs = reference.UnionType.IsGenericType ? reference.UnionType.GetGenericArguments() : [];
|
||||
var genericMethod = reg.MakeGenericMethod([.. genericArgs, attr.ActionLastGenericType]);
|
||||
var name = attr.ApplyPrefix ? $"{prefix}.{ipcName}" : ipcName;
|
||||
var callerInfo = genericMethod.Invoke(Svc.PluginInterface, [name])!;
|
||||
reference.SetValue(instance, ReflectionHelper.CreateDelegate(callerInfo.GetType().GetMethod("SendMessage"), callerInfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
PluginLog.Error($"[EzIPC Provider] Failed to initialize event provider for {instanceType.Name}.{reference.Name}");
|
||||
e.Log();
|
||||
}
|
||||
}
|
||||
return [.. ret];
|
||||
}
|
||||
|
||||
internal static void Dispose()
|
||||
{
|
||||
foreach(var token in Unregister)
|
||||
{
|
||||
try
|
||||
{
|
||||
token.Dispose();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
PluginLog.Error($"Error while unregistering IPC");
|
||||
e.Log();
|
||||
}
|
||||
}
|
||||
Unregister.Clear();
|
||||
OnSafeInvocationException = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches for IPC provider function with specified number of generic arguments
|
||||
/// </summary>
|
||||
/// <param name="numGenericArgs"></param>
|
||||
/// <returns></returns>
|
||||
public static MethodInfo? FindIpcProvider(int numGenericArgs)
|
||||
{
|
||||
foreach(var m in Svc.PluginInterface.GetType().GetMethods(ReflectionHelper.AllFlags))
|
||||
{
|
||||
if(m.Name == "GetIpcProvider" && m.IsGenericMethod && m.GetGenericArguments().Length == numGenericArgs)
|
||||
{
|
||||
return m;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches for IPC subscriber function with specified number of generic arguments
|
||||
/// </summary>
|
||||
/// <param name="numGenericArgs"></param>
|
||||
/// <returns></returns>
|
||||
public static MethodInfo? FindIpcSubscriber(int numGenericArgs)
|
||||
{
|
||||
foreach(var m in Svc.PluginInterface.GetType().GetMethods(ReflectionHelper.AllFlags))
|
||||
{
|
||||
if(m.Name == "GetIpcSubscriber" && m.IsGenericMethod && m.GetGenericArguments().Length == numGenericArgs)
|
||||
{
|
||||
return m;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static object? CreateSafeWrapper(SafeWrapper wrapperKind, Type[] adjustedGenericArgs)
|
||||
{
|
||||
Type? type = null;
|
||||
if(wrapperKind == SafeWrapper.IPCException)
|
||||
{
|
||||
type = adjustedGenericArgs.Length switch
|
||||
{
|
||||
1 => typeof(SafeWrapperIPC.Wrapper<>),
|
||||
2 => typeof(SafeWrapperIPC.Wrapper<,>),
|
||||
3 => typeof(SafeWrapperIPC.Wrapper<,,>),
|
||||
4 => typeof(SafeWrapperIPC.Wrapper<,,,>),
|
||||
5 => typeof(SafeWrapperIPC.Wrapper<,,,,>),
|
||||
6 => typeof(SafeWrapperIPC.Wrapper<,,,,,>),
|
||||
7 => typeof(SafeWrapperIPC.Wrapper<,,,,,,>),
|
||||
8 => typeof(SafeWrapperIPC.Wrapper<,,,,,,,>),
|
||||
9 => typeof(SafeWrapperIPC.Wrapper<,,,,,,,,>),
|
||||
_ => throw new ArgumentOutOfRangeException(GetThrowString()),
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
type = adjustedGenericArgs.Length switch
|
||||
{
|
||||
1 => typeof(SafeWrapperAny.Wrapper<>),
|
||||
2 => typeof(SafeWrapperAny.Wrapper<,>),
|
||||
3 => typeof(SafeWrapperAny.Wrapper<,,>),
|
||||
4 => typeof(SafeWrapperAny.Wrapper<,,,>),
|
||||
5 => typeof(SafeWrapperAny.Wrapper<,,,,>),
|
||||
6 => typeof(SafeWrapperAny.Wrapper<,,,,,>),
|
||||
7 => typeof(SafeWrapperAny.Wrapper<,,,,,,>),
|
||||
8 => typeof(SafeWrapperAny.Wrapper<,,,,,,,>),
|
||||
9 => typeof(SafeWrapperAny.Wrapper<,,,,,,,,>),
|
||||
_ => throw new ArgumentOutOfRangeException(GetThrowString()),
|
||||
};
|
||||
}
|
||||
type = type.MakeGenericType(adjustedGenericArgs);
|
||||
return Activator.CreateInstance(type);
|
||||
|
||||
string GetThrowString() => $"Could not find safe wrapper of {wrapperKind} kind with {adjustedGenericArgs.Length} arguments";
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
IPC provider side example:
|
||||
```C#
|
||||
public class IPCProvider()
|
||||
{
|
||||
//Internal plugin name is MyPlugin
|
||||
public IPCProvider()
|
||||
{
|
||||
EzIPC.Init(this);
|
||||
}
|
||||
|
||||
[EzIPC]
|
||||
public void MyIPCAction() //will register as MyPlugin.MyIPCAction
|
||||
{
|
||||
DoThings();
|
||||
}
|
||||
|
||||
[EzIPC("RenamedFunction")]
|
||||
public int MyIPCFunction() //will register as MyPlugin.RenamedFunction
|
||||
{
|
||||
return DoOtherThings();
|
||||
}
|
||||
|
||||
[EzIPCEvent] public Action Event; //Provides delegate for firing events
|
||||
[EzIPCEvent] public Action<int> AwesomeEvent;
|
||||
}
|
||||
```
|
||||
|
||||
IPC subscriber (consumer) side example:
|
||||
```C#
|
||||
public class IPCSubscriber()
|
||||
{
|
||||
public IPCSubscriber()
|
||||
{
|
||||
EzIPC.Init(this, "MyPlugin");
|
||||
}
|
||||
|
||||
[EzIPC] public readonly Action MyIPCAction; //retrieves delegate for MyPlugin.MyIPCAction
|
||||
[EzIPC("RenamedFunction")] public readonly Func<int> SinceItsRenamedFieldCanHaveAnyName;
|
||||
|
||||
[EzIPC("OtherPlugin_OtherAction", applyPrefix:false)] public Action OtherPluginAction;
|
||||
//you can define full tag without prefix for plugins
|
||||
//that don't follow this standard naming convention or
|
||||
//if you want to get IPC from multiple plugins in one class
|
||||
|
||||
[EzIPCEvent] //event subscription
|
||||
void Event()
|
||||
{
|
||||
DoSomething();
|
||||
}
|
||||
|
||||
[EzIPCEvent]
|
||||
void AwesomeEvent(int a1)
|
||||
{
|
||||
DoSomethingElse(a1);
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,26 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace ECommonsLite.EzIpcManager;
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
|
||||
public class EzIPCAttribute : Attribute
|
||||
{
|
||||
public string? IPCName;
|
||||
public bool ApplyPrefix;
|
||||
public Type ActionLastGenericType;
|
||||
public SafeWrapper Wrapper = SafeWrapper.Inherit;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes <see cref="EzIPCAttribute"/>.
|
||||
/// </summary>
|
||||
/// <param name="iPCName">IPC method name.</param>
|
||||
/// <param name="applyPrefix">Whether to apply prefix before name or not.</param>
|
||||
/// <param name="actionLastGenericType">Dummy return type used as a last generic argument for actions. When omitted, typeof(object) is used.</param>
|
||||
/// <param name="wrapper">Wrapper type</param>
|
||||
public EzIPCAttribute(string? iPCName = null, bool applyPrefix = true, Type? actionLastGenericType = null, SafeWrapper wrapper = SafeWrapper.Inherit)
|
||||
{
|
||||
IPCName = iPCName;
|
||||
ApplyPrefix = applyPrefix;
|
||||
ActionLastGenericType = actionLastGenericType ?? typeof(object);
|
||||
Wrapper = wrapper;
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
using ECommonsLite.Logging;
|
||||
using System;
|
||||
|
||||
namespace ECommonsLite.EzIpcManager;
|
||||
/// <summary>
|
||||
/// Represents EzIPC token, which can be used to manually dispose IPC when you want fine-grained control over disposing IPC. Any undisposed tokens are disposed during ECommonsMain's dispose so <b>you do not need to manually dispose tokens</b>.
|
||||
/// </summary>
|
||||
public sealed class EzIPCDisposalToken
|
||||
{
|
||||
/// <summary>
|
||||
/// Full IPC tag
|
||||
/// </summary>
|
||||
public readonly string IpcTag;
|
||||
/// <summary>
|
||||
/// Whether the token is event subscription
|
||||
/// </summary>
|
||||
public readonly bool IsEvent;
|
||||
/// <summary>
|
||||
/// Whether the token was already disposed
|
||||
/// </summary>
|
||||
public bool IsDisposed { get; private set; } = false;
|
||||
|
||||
private readonly Action DisposeAction;
|
||||
|
||||
internal EzIPCDisposalToken(string name, bool isEvent, Action disposeAction)
|
||||
{
|
||||
IpcTag = name ?? throw new ArgumentNullException(nameof(name));
|
||||
IsEvent = isEvent;
|
||||
DisposeAction = disposeAction ?? throw new ArgumentNullException(nameof(disposeAction));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes token, unregistering IPC provider or event subscription, if not already disposed.<br></br>
|
||||
/// <b>You do not need to call this method unless you specifically want to unregister your IPC before plugin unloads.</b>
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if(!IsDisposed)
|
||||
{
|
||||
IsDisposed = true;
|
||||
try
|
||||
{
|
||||
DisposeAction();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
PluginLog.Error($"[EzIPC Disposer] Error while disposing EzIPC");
|
||||
e.Log();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace ECommonsLite.EzIpcManager;
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Field, AllowMultiple = false)]
|
||||
public class EzIPCEventAttribute : Attribute
|
||||
{
|
||||
public string? IPCName;
|
||||
public bool ApplyPrefix;
|
||||
public Type ActionLastGenericType;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes <see cref="EzIPCAttribute"/>.
|
||||
/// </summary>
|
||||
/// <param name="iPCName">IPC method name.</param>
|
||||
/// <param name="applyPrefix">Whether to apply prefix before name or not.</param>
|
||||
/// /// <param name="actionLastGenericType">Dummy return type used as a last generic argument for actions. When omitted, typeof(object) is used.</param>
|
||||
public EzIPCEventAttribute(string? iPCName = null, bool applyPrefix = true, Type? actionLastGenericType = null)
|
||||
{
|
||||
IPCName = iPCName;
|
||||
ApplyPrefix = applyPrefix;
|
||||
ActionLastGenericType = actionLastGenericType ?? typeof(object);
|
||||
}
|
||||
}
|
||||
@@ -1,315 +0,0 @@
|
||||
using Dalamud.Plugin.Ipc.Exceptions;
|
||||
using System;
|
||||
|
||||
namespace ECommonsLite.EzIpcManager;
|
||||
#pragma warning disable CS1573 // Parameter has no matching param tag in the XML comment (but other parameters do)
|
||||
public static class EzIPCExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Tries to invoke previously obtained action delegate via <see cref="EzIPC"/> safely. Does not throws <see cref="IpcNotReadyError"/>.
|
||||
/// </summary>
|
||||
/// <returns>Whether invocation did not throw <see cref="IpcNotReadyError"/></returns>
|
||||
public static bool TryInvoke<T1, T2, T3, T4, T5, T6, T7, T8>(this Action<T1, T2, T3, T4, T5, T6, T7, T8> action, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8)
|
||||
{
|
||||
try
|
||||
{
|
||||
action(a1, a2, a3, a4, a5, a6, a7, a8);
|
||||
return true;
|
||||
}
|
||||
catch(IpcNotReadyError)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Tries to invoke previously obtained action delegate via <see cref="EzIPC"/> safely. Does not throws <see cref="IpcNotReadyError"/>.
|
||||
/// </summary>
|
||||
/// <returns>Whether invocation did not throw <see cref="IpcNotReadyError"/></returns>
|
||||
public static bool TryInvoke<T1, T2, T3, T4, T5, T6, T7>(this Action<T1, T2, T3, T4, T5, T6, T7> action, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7)
|
||||
{
|
||||
try
|
||||
{
|
||||
action(a1, a2, a3, a4, a5, a6, a7);
|
||||
return true;
|
||||
}
|
||||
catch(IpcNotReadyError)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Tries to invoke previously obtained action delegate via <see cref="EzIPC"/> safely. Does not throws <see cref="IpcNotReadyError"/>.
|
||||
/// </summary>
|
||||
/// <returns>Whether invocation did not throw <see cref="IpcNotReadyError"/></returns>
|
||||
public static bool TryInvoke<T1, T2, T3, T4, T5, T6>(this Action<T1, T2, T3, T4, T5, T6> action, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6)
|
||||
{
|
||||
try
|
||||
{
|
||||
action(a1, a2, a3, a4, a5, a6);
|
||||
return true;
|
||||
}
|
||||
catch(IpcNotReadyError)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Tries to invoke previously obtained action delegate via <see cref="EzIPC"/> safely. Does not throws <see cref="IpcNotReadyError"/>.
|
||||
/// </summary>
|
||||
/// <returns>Whether invocation did not throw <see cref="IpcNotReadyError"/></returns>
|
||||
public static bool TryInvoke<T1, T2, T3, T4, T5>(this Action<T1, T2, T3, T4, T5> action, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
|
||||
{
|
||||
try
|
||||
{
|
||||
action(a1, a2, a3, a4, a5);
|
||||
return true;
|
||||
}
|
||||
catch(IpcNotReadyError)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Tries to invoke previously obtained action delegate via <see cref="EzIPC"/> safely. Does not throws <see cref="IpcNotReadyError"/>.
|
||||
/// </summary>
|
||||
/// <returns>Whether invocation did not throw <see cref="IpcNotReadyError"/></returns>
|
||||
public static bool TryInvoke<T1, T2, T3, T4>(this Action<T1, T2, T3, T4> action, T1 a1, T2 a2, T3 a3, T4 a4)
|
||||
{
|
||||
try
|
||||
{
|
||||
action(a1, a2, a3, a4);
|
||||
return true;
|
||||
}
|
||||
catch(IpcNotReadyError)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Tries to invoke previously obtained action delegate via <see cref="EzIPC"/> safely. Does not throws <see cref="IpcNotReadyError"/>.
|
||||
/// </summary>
|
||||
/// <returns>Whether invocation did not throw <see cref="IpcNotReadyError"/></returns>
|
||||
public static bool TryInvoke<T1, T2, T3>(this Action<T1, T2, T3> action, T1 a1, T2 a2, T3 a3)
|
||||
{
|
||||
try
|
||||
{
|
||||
action(a1, a2, a3);
|
||||
return true;
|
||||
}
|
||||
catch(IpcNotReadyError)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Tries to invoke previously obtained action delegate via <see cref="EzIPC"/> safely. Does not throws <see cref="IpcNotReadyError"/>.
|
||||
/// </summary>
|
||||
/// <returns>Whether invocation did not throw <see cref="IpcNotReadyError"/></returns>
|
||||
public static bool TryInvoke<T1, T2>(this Action<T1, T2> action, T1 a1, T2 a2)
|
||||
{
|
||||
try
|
||||
{
|
||||
action(a1, a2);
|
||||
return true;
|
||||
}
|
||||
catch(IpcNotReadyError)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Tries to invoke previously obtained action delegate via <see cref="EzIPC"/> safely. Does not throws <see cref="IpcNotReadyError"/>.
|
||||
/// </summary>
|
||||
/// <returns>Whether invocation did not throw <see cref="IpcNotReadyError"/></returns>
|
||||
public static bool TryInvoke<T1>(this Action<T1> action, T1 a1)
|
||||
{
|
||||
try
|
||||
{
|
||||
action(a1);
|
||||
return true;
|
||||
}
|
||||
catch(IpcNotReadyError)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Tries to invoke previously obtained action delegate via <see cref="EzIPC"/> safely. Does not throws <see cref="IpcNotReadyError"/>.
|
||||
/// </summary>
|
||||
/// <returns>Whether invocation did not throw <see cref="IpcNotReadyError"/></returns>
|
||||
public static bool TryInvoke(this Action action)
|
||||
{
|
||||
try
|
||||
{
|
||||
action();
|
||||
return true;
|
||||
}
|
||||
catch(IpcNotReadyError)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to invoke previously obtained function delegate via <see cref="EzIPC"/> safely. Does not throws <see cref="IpcNotReadyError"/>.
|
||||
/// </summary>
|
||||
/// <param name="ret">Result returned by a function if invocation succeeded</param>
|
||||
/// <returns>Whether invocation did not throw <see cref="IpcNotReadyError"/></returns>
|
||||
public static bool TryInvoke<T1, T2, T3, T4, T5, T6, T7, T8, TRet>(this Func<T1, T2, T3, T4, T5, T6, T7, T8, TRet> function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, out TRet? ret)
|
||||
{
|
||||
try
|
||||
{
|
||||
ret = function(a1, a2, a3, a4, a5, a6, a7, a8);
|
||||
return true;
|
||||
}
|
||||
catch(IpcNotReadyError)
|
||||
{
|
||||
ret = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Tries to invoke previously obtained function delegate via <see cref="EzIPC"/> safely. Does not throws <see cref="IpcNotReadyError"/>.
|
||||
/// </summary>
|
||||
/// <param name="ret">Result returned by a function if invocation succeeded</param>
|
||||
/// <returns>Whether invocation did not throw <see cref="IpcNotReadyError"/></returns>
|
||||
public static bool TryInvoke<T1, T2, T3, T4, T5, T6, T7, TRet>(this Func<T1, T2, T3, T4, T5, T6, T7, TRet> function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, out TRet? ret)
|
||||
{
|
||||
try
|
||||
{
|
||||
ret = function(a1, a2, a3, a4, a5, a6, a7);
|
||||
return true;
|
||||
}
|
||||
catch(IpcNotReadyError)
|
||||
{
|
||||
ret = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Tries to invoke previously obtained function delegate via <see cref="EzIPC"/> safely. Does not throws <see cref="IpcNotReadyError"/>.
|
||||
/// </summary>
|
||||
/// <param name="ret">Result returned by a function if invocation succeeded</param>
|
||||
/// <returns>Whether invocation did not throw <see cref="IpcNotReadyError"/></returns>
|
||||
public static bool TryInvoke<T1, T2, T3, T4, T5, T6, TRet>(this Func<T1, T2, T3, T4, T5, T6, TRet> function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, out TRet? ret)
|
||||
{
|
||||
try
|
||||
{
|
||||
ret = function(a1, a2, a3, a4, a5, a6);
|
||||
return true;
|
||||
}
|
||||
catch(IpcNotReadyError)
|
||||
{
|
||||
ret = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Tries to invoke previously obtained function delegate via <see cref="EzIPC"/> safely. Does not throws <see cref="IpcNotReadyError"/>.
|
||||
/// </summary>
|
||||
/// <param name="ret">Result returned by a function if invocation succeeded</param>
|
||||
/// <returns>Whether invocation did not throw <see cref="IpcNotReadyError"/></returns>
|
||||
public static bool TryInvoke<T1, T2, T3, T4, T5, TRet>(this Func<T1, T2, T3, T4, T5, TRet> function, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, out TRet? ret)
|
||||
{
|
||||
try
|
||||
{
|
||||
ret = function(a1, a2, a3, a4, a5);
|
||||
return true;
|
||||
}
|
||||
catch(IpcNotReadyError)
|
||||
{
|
||||
ret = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Tries to invoke previously obtained function delegate via <see cref="EzIPC"/> safely. Does not throws <see cref="IpcNotReadyError"/>.
|
||||
/// </summary>
|
||||
/// <param name="ret">Result returned by a function if invocation succeeded</param>
|
||||
/// <returns>Whether invocation did not throw <see cref="IpcNotReadyError"/></returns>
|
||||
public static bool TryInvoke<T1, T2, T3, T4, TRet>(this Func<T1, T2, T3, T4, TRet> function, T1 a1, T2 a2, T3 a3, T4 a4, out TRet? ret)
|
||||
{
|
||||
try
|
||||
{
|
||||
ret = function(a1, a2, a3, a4);
|
||||
return true;
|
||||
}
|
||||
catch(IpcNotReadyError)
|
||||
{
|
||||
ret = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Tries to invoke previously obtained function delegate via <see cref="EzIPC"/> safely. Does not throws <see cref="IpcNotReadyError"/>.
|
||||
/// </summary>
|
||||
/// <param name="ret">Result returned by a function if invocation succeeded</param>
|
||||
/// <returns>Whether invocation did not throw <see cref="IpcNotReadyError"/></returns>
|
||||
public static bool TryInvoke<T1, T2, T3, TRet>(this Func<T1, T2, T3, TRet> function, T1 a1, T2 a2, T3 a3, out TRet? ret)
|
||||
{
|
||||
try
|
||||
{
|
||||
ret = function(a1, a2, a3);
|
||||
return true;
|
||||
}
|
||||
catch(IpcNotReadyError)
|
||||
{
|
||||
ret = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Tries to invoke previously obtained function delegate via <see cref="EzIPC"/> safely. Does not throws <see cref="IpcNotReadyError"/>.
|
||||
/// </summary>
|
||||
/// <param name="ret">Result returned by a function if invocation succeeded</param>
|
||||
/// <returns>Whether invocation did not throw <see cref="IpcNotReadyError"/></returns>
|
||||
public static bool TryInvoke<T1, T2, TRet>(this Func<T1, T2, TRet> function, T1 a1, T2 a2, out TRet? ret)
|
||||
{
|
||||
try
|
||||
{
|
||||
ret = function(a1, a2);
|
||||
return true;
|
||||
}
|
||||
catch(IpcNotReadyError)
|
||||
{
|
||||
ret = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Tries to invoke previously obtained function delegate via <see cref="EzIPC"/> safely. Does not throws <see cref="IpcNotReadyError"/>.
|
||||
/// </summary>
|
||||
/// <param name="ret">Result returned by a function if invocation succeeded</param>
|
||||
/// <returns>Whether invocation did not throw <see cref="IpcNotReadyError"/></returns>
|
||||
public static bool TryInvoke<T1, TRet>(this Func<T1, TRet> function, T1 a1, out TRet? ret)
|
||||
{
|
||||
try
|
||||
{
|
||||
ret = function(a1);
|
||||
return true;
|
||||
}
|
||||
catch(IpcNotReadyError)
|
||||
{
|
||||
ret = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Tries to invoke previously obtained function delegate via <see cref="EzIPC"/> safely. Does not throws <see cref="IpcNotReadyError"/>.
|
||||
/// </summary>
|
||||
/// <param name="ret">Result returned by a function if invocation succeeded</param>
|
||||
/// <returns>Whether invocation did not throw <see cref="IpcNotReadyError"/></returns>
|
||||
public static bool TryInvoke<TRet>(this Func<TRet> function, out TRet? ret)
|
||||
{
|
||||
try
|
||||
{
|
||||
ret = function();
|
||||
return true;
|
||||
}
|
||||
catch(IpcNotReadyError)
|
||||
{
|
||||
ret = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace ECommonsLite.EzIpcManager;
|
||||
[Obfuscation(Exclude = true)]
|
||||
public enum SafeWrapper
|
||||
{
|
||||
/// <summary>
|
||||
/// Directly call IPC, don't use any wrapper
|
||||
/// </summary>
|
||||
None,
|
||||
/// <summary>
|
||||
/// Only catch and discard IPCException
|
||||
/// </summary>
|
||||
IPCException,
|
||||
/// <summary>
|
||||
/// Catch and discard all exceptions
|
||||
/// </summary>
|
||||
AnyException,
|
||||
#pragma warning disable
|
||||
/// <summary>
|
||||
/// Inherit default setting from <see cref="EzIPC.Init"/> call
|
||||
/// </summary>
|
||||
#pragma warning restore
|
||||
Inherit = 255
|
||||
}
|
||||
@@ -1,286 +0,0 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ECommonsLite.EzIpcManager;
|
||||
#nullable disable
|
||||
[Obfuscation(Exclude = true)]
|
||||
internal static class SafeWrapperAny
|
||||
{
|
||||
internal class Wrapper<T1, T2, T3, T4, T5, T6, T7, T8, TRet>()
|
||||
{
|
||||
internal Action<T1, T2, T3, T4, T5, T6, T7, T8> Action;
|
||||
internal Func<T1, T2, T3, T4, T5, T6, T7, T8, TRet> Function;
|
||||
|
||||
internal void InvokeAction(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8)
|
||||
{
|
||||
try
|
||||
{
|
||||
Action(a1, a2, a3, a4, a5, a6, a7, a8);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
}
|
||||
internal TRet InvokeFunction(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Function(a1, a2, a3, a4, a5, a6, a7, a8);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
internal class Wrapper<T1, T2, T3, T4, T5, T6, T7, TRet>()
|
||||
{
|
||||
internal Action<T1, T2, T3, T4, T5, T6, T7> Action;
|
||||
internal Func<T1, T2, T3, T4, T5, T6, T7, TRet> Function;
|
||||
|
||||
internal void InvokeAction(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7)
|
||||
{
|
||||
try
|
||||
{
|
||||
Action(a1, a2, a3, a4, a5, a6, a7);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
internal TRet InvokeFunction(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Function(a1, a2, a3, a4, a5, a6, a7);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
internal class Wrapper<T1, T2, T3, T4, T5, T6, TRet>()
|
||||
{
|
||||
internal Action<T1, T2, T3, T4, T5, T6> Action;
|
||||
internal Func<T1, T2, T3, T4, T5, T6, TRet> Function;
|
||||
|
||||
internal void InvokeAction(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6)
|
||||
{
|
||||
try
|
||||
{
|
||||
Action(a1, a2, a3, a4, a5, a6);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
internal TRet InvokeFunction(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Function(a1, a2, a3, a4, a5, a6);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
internal class Wrapper<T1, T2, T3, T4, T5, TRet>()
|
||||
{
|
||||
internal Action<T1, T2, T3, T4, T5> Action;
|
||||
internal Func<T1, T2, T3, T4, T5, TRet> Function;
|
||||
|
||||
internal void InvokeAction(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
|
||||
{
|
||||
try
|
||||
{
|
||||
Action(a1, a2, a3, a4, a5);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
internal TRet InvokeFunction(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Function(a1, a2, a3, a4, a5);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
internal class Wrapper<T1, T2, T3, T4, TRet>()
|
||||
{
|
||||
internal Action<T1, T2, T3, T4> Action;
|
||||
internal Func<T1, T2, T3, T4, TRet> Function;
|
||||
|
||||
internal void InvokeAction(T1 a1, T2 a2, T3 a3, T4 a4)
|
||||
{
|
||||
try
|
||||
{
|
||||
Action(a1, a2, a3, a4);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
internal TRet InvokeFunction(T1 a1, T2 a2, T3 a3, T4 a4)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Function(a1, a2, a3, a4);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
internal class Wrapper<T1, T2, T3, TRet>()
|
||||
{
|
||||
internal Action<T1, T2, T3> Action;
|
||||
internal Func<T1, T2, T3, TRet> Function;
|
||||
|
||||
internal void InvokeAction(T1 a1, T2 a2, T3 a3)
|
||||
{
|
||||
try
|
||||
{
|
||||
Action(a1, a2, a3);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
internal TRet InvokeFunction(T1 a1, T2 a2, T3 a3)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Function(a1, a2, a3);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
internal class Wrapper<T1, T2, TRet>()
|
||||
{
|
||||
internal Action<T1, T2> Action;
|
||||
internal Func<T1, T2, TRet> Function;
|
||||
|
||||
internal void InvokeAction(T1 a1, T2 a2)
|
||||
{
|
||||
try
|
||||
{
|
||||
Action(a1, a2);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
internal TRet InvokeFunction(T1 a1, T2 a2)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Function(a1, a2);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
internal class Wrapper<T1, TRet>()
|
||||
{
|
||||
internal Action<T1> Action;
|
||||
internal Func<T1, TRet> Function;
|
||||
|
||||
internal void InvokeAction(T1 a1)
|
||||
{
|
||||
try
|
||||
{
|
||||
Action(a1);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
internal TRet InvokeFunction(T1 a1)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Function(a1);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
internal class Wrapper<TRet>()
|
||||
{
|
||||
internal Action Action;
|
||||
internal Func<TRet> Function;
|
||||
|
||||
internal void InvokeAction()
|
||||
{
|
||||
try
|
||||
{
|
||||
Action();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
internal TRet InvokeFunction()
|
||||
{
|
||||
try
|
||||
{
|
||||
return Function();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,287 +0,0 @@
|
||||
using Dalamud.Plugin.Ipc.Exceptions;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ECommonsLite.EzIpcManager;
|
||||
#nullable disable
|
||||
[Obfuscation(Exclude = true)]
|
||||
internal static class SafeWrapperIPC
|
||||
{
|
||||
internal class Wrapper<T1, T2, T3, T4, T5, T6, T7, T8, TRet>()
|
||||
{
|
||||
internal Action<T1, T2, T3, T4, T5, T6, T7, T8> Action;
|
||||
internal Func<T1, T2, T3, T4, T5, T6, T7, T8, TRet> Function;
|
||||
|
||||
internal void InvokeAction(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8)
|
||||
{
|
||||
try
|
||||
{
|
||||
Action(a1, a2, a3, a4, a5, a6, a7, a8);
|
||||
}
|
||||
catch(IpcNotReadyError e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
}
|
||||
internal TRet InvokeFunction(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Function(a1, a2, a3, a4, a5, a6, a7, a8);
|
||||
}
|
||||
catch(IpcNotReadyError e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
internal class Wrapper<T1, T2, T3, T4, T5, T6, T7, TRet>()
|
||||
{
|
||||
internal Action<T1, T2, T3, T4, T5, T6, T7> Action;
|
||||
internal Func<T1, T2, T3, T4, T5, T6, T7, TRet> Function;
|
||||
|
||||
internal void InvokeAction(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7)
|
||||
{
|
||||
try
|
||||
{
|
||||
Action(a1, a2, a3, a4, a5, a6, a7);
|
||||
}
|
||||
catch(IpcNotReadyError e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
internal TRet InvokeFunction(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Function(a1, a2, a3, a4, a5, a6, a7);
|
||||
}
|
||||
catch(IpcNotReadyError e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
internal class Wrapper<T1, T2, T3, T4, T5, T6, TRet>()
|
||||
{
|
||||
internal Action<T1, T2, T3, T4, T5, T6> Action;
|
||||
internal Func<T1, T2, T3, T4, T5, T6, TRet> Function;
|
||||
|
||||
internal void InvokeAction(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6)
|
||||
{
|
||||
try
|
||||
{
|
||||
Action(a1, a2, a3, a4, a5, a6);
|
||||
}
|
||||
catch(IpcNotReadyError e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
internal TRet InvokeFunction(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Function(a1, a2, a3, a4, a5, a6);
|
||||
}
|
||||
catch(IpcNotReadyError e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
internal class Wrapper<T1, T2, T3, T4, T5, TRet>()
|
||||
{
|
||||
internal Action<T1, T2, T3, T4, T5> Action;
|
||||
internal Func<T1, T2, T3, T4, T5, TRet> Function;
|
||||
|
||||
internal void InvokeAction(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
|
||||
{
|
||||
try
|
||||
{
|
||||
Action(a1, a2, a3, a4, a5);
|
||||
}
|
||||
catch(IpcNotReadyError e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
internal TRet InvokeFunction(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Function(a1, a2, a3, a4, a5);
|
||||
}
|
||||
catch(IpcNotReadyError e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
internal class Wrapper<T1, T2, T3, T4, TRet>()
|
||||
{
|
||||
internal Action<T1, T2, T3, T4> Action;
|
||||
internal Func<T1, T2, T3, T4, TRet> Function;
|
||||
|
||||
internal void InvokeAction(T1 a1, T2 a2, T3 a3, T4 a4)
|
||||
{
|
||||
try
|
||||
{
|
||||
Action(a1, a2, a3, a4);
|
||||
}
|
||||
catch(IpcNotReadyError e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
internal TRet InvokeFunction(T1 a1, T2 a2, T3 a3, T4 a4)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Function(a1, a2, a3, a4);
|
||||
}
|
||||
catch(IpcNotReadyError e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
internal class Wrapper<T1, T2, T3, TRet>()
|
||||
{
|
||||
internal Action<T1, T2, T3> Action;
|
||||
internal Func<T1, T2, T3, TRet> Function;
|
||||
|
||||
internal void InvokeAction(T1 a1, T2 a2, T3 a3)
|
||||
{
|
||||
try
|
||||
{
|
||||
Action(a1, a2, a3);
|
||||
}
|
||||
catch(IpcNotReadyError e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
internal TRet InvokeFunction(T1 a1, T2 a2, T3 a3)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Function(a1, a2, a3);
|
||||
}
|
||||
catch(IpcNotReadyError e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
internal class Wrapper<T1, T2, TRet>()
|
||||
{
|
||||
internal Action<T1, T2> Action;
|
||||
internal Func<T1, T2, TRet> Function;
|
||||
|
||||
internal void InvokeAction(T1 a1, T2 a2)
|
||||
{
|
||||
try
|
||||
{
|
||||
Action(a1, a2);
|
||||
}
|
||||
catch(IpcNotReadyError e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
internal TRet InvokeFunction(T1 a1, T2 a2)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Function(a1, a2);
|
||||
}
|
||||
catch(IpcNotReadyError e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
internal class Wrapper<T1, TRet>()
|
||||
{
|
||||
internal Action<T1> Action;
|
||||
internal Func<T1, TRet> Function;
|
||||
|
||||
internal void InvokeAction(T1 a1)
|
||||
{
|
||||
try
|
||||
{
|
||||
Action(a1);
|
||||
}
|
||||
catch(IpcNotReadyError e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
internal TRet InvokeFunction(T1 a1)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Function(a1);
|
||||
}
|
||||
catch(IpcNotReadyError e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
internal class Wrapper<TRet>()
|
||||
{
|
||||
internal Action Action;
|
||||
internal Func<TRet> Function;
|
||||
|
||||
internal void InvokeAction()
|
||||
{
|
||||
try
|
||||
{
|
||||
Action();
|
||||
}
|
||||
catch(IpcNotReadyError e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
internal TRet InvokeFunction()
|
||||
{
|
||||
try
|
||||
{
|
||||
return Function();
|
||||
}
|
||||
catch(IpcNotReadyError e)
|
||||
{
|
||||
EzIPC.InvokeOnSafeInvocationException(e);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using ECommonsLite.Logging;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.String;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
#nullable disable
|
||||
|
||||
namespace ECommonsLite;
|
||||
|
||||
public static unsafe partial class GenericHelpers
|
||||
{
|
||||
public static void Log(this Exception e)
|
||||
{
|
||||
PluginLog.Error($"{e.Message}\n{e.StackTrace ?? ""}");
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool EqualsAny<T>(this T obj, params T[] values)
|
||||
{
|
||||
return values.Any(x => x.Equals(obj));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Safe(System.Action a, bool suppressErrors = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
a();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (!suppressErrors) PluginLog.Error($"{e.Message}\n{e.StackTrace ?? ""}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Action = System.Action;
|
||||
|
||||
namespace ECommonsLite.ImGuiMethods;
|
||||
#nullable disable
|
||||
|
||||
public static unsafe partial class ImGuiEx
|
||||
{
|
||||
public static void EzTabBar(string id, params (string name, Action function, Vector4? color, bool child)[] tabs) => EzTabBar(id, null, tabs);
|
||||
public static void EzTabBar(string id, string KoFiTransparent, params (string name, Action function, Vector4? color, bool child)[] tabs) => EzTabBar(id, KoFiTransparent, null, tabs);
|
||||
public static void EzTabBar(string id, string KoFiTransparent, string openTabName, params (string name, Action function, Vector4? color, bool child)[] tabs) => EzTabBar(id, KoFiTransparent, openTabName, ImGuiTabBarFlags.None, tabs);
|
||||
public static void EzTabBar(string id, string KoFiTransparent, string openTabName, ImGuiTabBarFlags flags, params (string name, Action function, Vector4? color, bool child)[] tabs)
|
||||
{
|
||||
ImGui.BeginTabBar(id, flags);
|
||||
foreach (var x in tabs)
|
||||
{
|
||||
if (x.name == null) continue;
|
||||
if (x.color != null)
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, x.color.Value);
|
||||
}
|
||||
if (ImGui.BeginTabItem(x.name, openTabName == x.name ? ImGuiTabItemFlags.SetSelected : ImGuiTabItemFlags.None))
|
||||
{
|
||||
if (x.color != null)
|
||||
{
|
||||
ImGui.PopStyleColor();
|
||||
}
|
||||
if (x.child) ImGui.BeginChild(x.name + "child");
|
||||
x.function();
|
||||
if (x.child) ImGui.EndChild();
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x.color != null)
|
||||
{
|
||||
ImGui.PopStyleColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
//if (KoFiTransparent != null) PatreonBanner.RightTransparentTab();
|
||||
ImGui.EndTabBar();
|
||||
}
|
||||
|
||||
public static unsafe bool BeginTabItem(string label, ImGuiTabItemFlags flags)
|
||||
{
|
||||
throw new NotImplementedException("Switch to using ImGui.BeginTabItem. It now has version without \"close\".");
|
||||
}
|
||||
internal static unsafe byte* Allocate(int byteCount)
|
||||
{
|
||||
return (byte*)(void*)Marshal.AllocHGlobal(byteCount);
|
||||
}
|
||||
|
||||
internal static unsafe void Free(byte* ptr)
|
||||
{
|
||||
Marshal.FreeHGlobal((IntPtr)ptr);
|
||||
}
|
||||
|
||||
internal static unsafe int GetUtf8(string s, byte* utf8Bytes, int utf8ByteCount)
|
||||
{
|
||||
fixed (char* chars = s)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(chars, s.Length, utf8Bytes, utf8ByteCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
using ECommonsLite.DalamudServices;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace ECommonsLite.Logging;
|
||||
|
||||
public static class PluginLog
|
||||
{
|
||||
|
||||
public static void Information(string s)
|
||||
{
|
||||
Svc.Log.Information($"{s}");
|
||||
}
|
||||
public static void Error(string s)
|
||||
{
|
||||
Svc.Log.Error($"{s}");
|
||||
}
|
||||
public static void Fatal(string s)
|
||||
{
|
||||
Svc.Log.Fatal($"{s}");
|
||||
}
|
||||
public static void Debug(string s)
|
||||
{
|
||||
Svc.Log.Debug($"{s}");
|
||||
}
|
||||
public static void Verbose(string s)
|
||||
{
|
||||
Svc.Log.Verbose($"{s}");
|
||||
}
|
||||
public static void Warning(string s)
|
||||
{
|
||||
Svc.Log.Warning($"{s}");
|
||||
}
|
||||
public static void LogInformation(string s)
|
||||
{
|
||||
Information(s);
|
||||
}
|
||||
public static void LogError(string s)
|
||||
{
|
||||
Error(s);
|
||||
}
|
||||
public static void LogFatal(string s)
|
||||
{
|
||||
Fatal(s);
|
||||
}
|
||||
public static void LogDebug(string s)
|
||||
{
|
||||
Debug(s);
|
||||
}
|
||||
public static void LogVerbose(string s)
|
||||
{
|
||||
Verbose(s);
|
||||
}
|
||||
public static void LogWarning(string s)
|
||||
{
|
||||
Warning(s);
|
||||
}
|
||||
public static void Log(string s)
|
||||
{
|
||||
Information(s);
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ECommonsLite.Reflection.FieldPropertyUnion;
|
||||
/// <summary>
|
||||
/// Interface that represents union of FieldInfo and PropertyInfo. Allows access to common methods and properties.
|
||||
/// </summary>
|
||||
public interface IFieldPropertyUnion
|
||||
{
|
||||
public Type UnionType { get; }
|
||||
public bool IsSpecialName { get; }
|
||||
public object? GetRawConstantValue();
|
||||
public object? GetValue(object? obj);
|
||||
public void SetValue(object? obj, object? value);
|
||||
public void SetValue(object? obj, object? value, BindingFlags invokeAttr, Binder? binder, CultureInfo? culture);
|
||||
|
||||
//MemberInfo
|
||||
public string Name { get; }
|
||||
public MemberTypes MemberType { get; }
|
||||
public Type? DeclaringType { get; }
|
||||
public Type? ReflectedType { get; }
|
||||
public System.Reflection.Module Module { get; }
|
||||
public bool IsDefined(Type attributeType, bool inherit);
|
||||
public object[] GetCustomAttributes(bool inherit);
|
||||
public object[] GetCustomAttributes(Type attributeType, bool inherit);
|
||||
public T? GetCustomAttribute<T>() where T : Attribute;
|
||||
public IEnumerable<T> GetCustomAttributes<T>() where T : Attribute;
|
||||
|
||||
public IEnumerable<CustomAttributeData> CustomAttributes { get; }
|
||||
public bool IsCollectible { get; }
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ECommonsLite.Reflection.FieldPropertyUnion;
|
||||
public class UnionField : IFieldPropertyUnion
|
||||
{
|
||||
public readonly FieldInfo FieldInfo;
|
||||
public UnionField(FieldInfo fieldInfo)
|
||||
{
|
||||
FieldInfo = fieldInfo;
|
||||
}
|
||||
|
||||
public string Name => FieldInfo.Name;
|
||||
|
||||
public Type UnionType => FieldInfo.FieldType;
|
||||
|
||||
public Type? DeclaringType => FieldInfo.DeclaringType;
|
||||
|
||||
public MemberTypes MemberType => FieldInfo.MemberType;
|
||||
|
||||
public Type? ReflectedType => FieldInfo.ReflectedType;
|
||||
|
||||
public bool IsSpecialName => FieldInfo.IsSpecialName;
|
||||
|
||||
public System.Reflection.Module Module => FieldInfo.Module;
|
||||
|
||||
public IEnumerable<CustomAttributeData> CustomAttributes => FieldInfo.CustomAttributes;
|
||||
|
||||
public bool IsCollectible => FieldInfo.IsCollectible;
|
||||
|
||||
public object[] GetCustomAttributes(bool inherit) => FieldInfo.GetCustomAttributes(inherit);
|
||||
|
||||
public object[] GetCustomAttributes(Type attributeType, bool inherit) => FieldInfo.GetCustomAttributes(attributeType, inherit);
|
||||
|
||||
public T? GetCustomAttribute<T>() where T : Attribute => FieldInfo.GetCustomAttribute<T>();
|
||||
public IEnumerable<T> GetCustomAttributes<T>() where T : Attribute => FieldInfo.GetCustomAttributes<T>();
|
||||
|
||||
public object? GetRawConstantValue() => FieldInfo.GetRawConstantValue();
|
||||
|
||||
public object? GetValue(object? obj) => FieldInfo.GetValue(obj);
|
||||
|
||||
public bool IsDefined(Type attributeType, bool inherit) => FieldInfo.IsDefined(attributeType, inherit);
|
||||
|
||||
public void SetValue(object? obj, object? value) => FieldInfo.SetValue(obj, value);
|
||||
|
||||
public void SetValue(object? obj, object? value, BindingFlags invokeAttr, Binder? binder, CultureInfo? culture) => FieldInfo.SetValue(obj, value, invokeAttr, binder, culture);
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ECommonsLite.Reflection.FieldPropertyUnion;
|
||||
public class UnionProperty : IFieldPropertyUnion
|
||||
{
|
||||
public readonly PropertyInfo PropertyInfo;
|
||||
public UnionProperty(PropertyInfo propertyInfo)
|
||||
{
|
||||
PropertyInfo = propertyInfo;
|
||||
}
|
||||
|
||||
public string Name => PropertyInfo.Name;
|
||||
|
||||
public Type UnionType => PropertyInfo.PropertyType;
|
||||
|
||||
public Type? DeclaringType => PropertyInfo.DeclaringType;
|
||||
|
||||
public MemberTypes MemberType => PropertyInfo.MemberType;
|
||||
|
||||
public Type? ReflectedType => PropertyInfo.ReflectedType;
|
||||
|
||||
public bool IsSpecialName => PropertyInfo.IsSpecialName;
|
||||
|
||||
public System.Reflection.Module Module => PropertyInfo.Module;
|
||||
|
||||
public IEnumerable<CustomAttributeData> CustomAttributes => PropertyInfo.CustomAttributes;
|
||||
|
||||
public bool IsCollectible => PropertyInfo.IsCollectible;
|
||||
|
||||
public object[] GetCustomAttributes(bool inherit) => PropertyInfo.GetCustomAttributes(inherit);
|
||||
|
||||
public object[] GetCustomAttributes(Type attributeType, bool inherit) => PropertyInfo.GetCustomAttributes(attributeType, inherit);
|
||||
public T? GetCustomAttribute<T>() where T : Attribute => PropertyInfo.GetCustomAttribute<T>();
|
||||
public IEnumerable<T> GetCustomAttributes<T>() where T : Attribute => PropertyInfo.GetCustomAttributes<T>();
|
||||
|
||||
public object? GetRawConstantValue() => PropertyInfo.GetRawConstantValue();
|
||||
|
||||
public object? GetValue(object? obj) => PropertyInfo.GetValue(obj);
|
||||
|
||||
public bool IsDefined(Type attributeType, bool inherit) => PropertyInfo.IsDefined(attributeType, inherit);
|
||||
|
||||
public void SetValue(object? obj, object? value) => PropertyInfo.SetValue(obj, value);
|
||||
|
||||
public void SetValue(object? obj, object? value, BindingFlags invokeAttr, Binder? binder, CultureInfo? culture) => PropertyInfo.SetValue(obj, value, invokeAttr, binder, null, culture);
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ECommonsLite.Reflection;
|
||||
#nullable disable
|
||||
|
||||
public static partial class ReflectionHelper
|
||||
{
|
||||
public const BindingFlags AllFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
|
||||
public const BindingFlags StaticFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
|
||||
public const BindingFlags InstanceFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
|
||||
|
||||
/// <summary>
|
||||
/// Gets field or property of an instance object.
|
||||
/// </summary>
|
||||
/// <param name="obj">Instance containing field/property.</param>
|
||||
/// <param name="name">Name of the field/property</param>
|
||||
/// <returns>Value of a field/property</returns>
|
||||
public static object GetFoP(this object obj, string name)
|
||||
{
|
||||
return obj.GetType().GetField(name, AllFlags)?.GetValue(obj)
|
||||
?? obj.GetType().GetProperty(name, AllFlags)?.GetValue(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets field or property of an instance object.
|
||||
/// </summary>
|
||||
/// <param name="obj">Instance containing field/property.</param>
|
||||
/// <param name="name">Name of the field/property</param>
|
||||
/// <returns>Value of a field/property</returns>
|
||||
public static T GetFoP<T>(this object obj, string name)
|
||||
{
|
||||
return (T)GetFoP(obj, name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a field or property of an instance object.
|
||||
/// </summary>
|
||||
/// <param name="obj">Instance containing field/property.</param>
|
||||
/// <param name="name">Name of the field/property</param>
|
||||
/// <param name="value">Value to set</param>
|
||||
public static void SetFoP(this object obj, string name, object value)
|
||||
{
|
||||
var field = obj.GetType().GetField(name, AllFlags);
|
||||
if(field != null)
|
||||
{
|
||||
field.SetValue(obj, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
obj.GetType().GetProperty(name, AllFlags).SetValue(obj, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subject for future refactoring and changes!
|
||||
/// </summary>
|
||||
public static object GetStaticFoP(this object obj, string type, string name)
|
||||
{
|
||||
return obj.GetType().Assembly.GetType(type).GetField(name, StaticFlags)?.GetValue(null)
|
||||
?? obj.GetType().Assembly.GetType(type).GetProperty(name, StaticFlags)?.GetValue(null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subject for future refactoring and changes!
|
||||
/// </summary>
|
||||
public static T GetStaticFoP<T>(this object obj, string type, string name)
|
||||
{
|
||||
return (T)GetStaticFoP(obj, type, name);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Subject for future refactoring and changes!
|
||||
/// </summary>
|
||||
public static void SetStaticFoP(this object obj, string type, string name, object value)
|
||||
{
|
||||
var field = obj.GetType().Assembly.GetType(type).GetField(name, StaticFlags);
|
||||
if(field != null)
|
||||
{
|
||||
field.SetValue(null, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
obj.GetType().Assembly.GetType(type).GetProperty(name, StaticFlags).SetValue(null, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to call a non-generic instance method.
|
||||
/// </summary>
|
||||
/// <param name="obj">Instance containing method</param>
|
||||
/// <param name="name">Method's name</param>
|
||||
/// <param name="params">Method's parameters</param>
|
||||
/// <param name="matchExactArgumentTypes">Whether to search for exact method types. Set this to true if you're dealing with ambiguous overloads.</param>
|
||||
/// <returns>Object returned by the target method</returns>
|
||||
public static object Call(this object obj, string name, object[] @params, bool matchExactArgumentTypes = false)
|
||||
{
|
||||
MethodInfo info;
|
||||
if(!matchExactArgumentTypes)
|
||||
{
|
||||
info = obj.GetType().GetMethod(name, AllFlags);
|
||||
}
|
||||
else
|
||||
{
|
||||
info = obj.GetType().GetMethod(name, AllFlags, @params.Select(x => x.GetType()).ToArray());
|
||||
}
|
||||
return info.Invoke(obj, @params);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to call a non-generic instance method.
|
||||
/// </summary>
|
||||
/// <param name="obj">Instance containing method</param>
|
||||
/// <param name="name">Method's name</param>
|
||||
/// <param name="params">Method's parameters</param>
|
||||
/// <param name="matchExactArgumentTypes">Whether to search for exact method types. Set this to true if you're dealing with ambiguous overloads.</param>
|
||||
/// <returns>Object returned by the target method</returns>
|
||||
public static T Call<T>(this object obj, string name, object[] @params, bool matchExactArgumentTypes = false)
|
||||
{
|
||||
return (T)Call(obj, name, @params, matchExactArgumentTypes);
|
||||
}
|
||||
}
|
||||
@@ -1,187 +0,0 @@
|
||||
using ECommonsLite.Reflection.FieldPropertyUnion;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace ECommonsLite.Reflection;
|
||||
#nullable disable
|
||||
public static partial class ReflectionHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Searches for a static method in the array of assemblies.
|
||||
/// </summary>
|
||||
/// <param name="assemblies">Assemblies to search in</param>
|
||||
/// <param name="typeName">Fully qualified class name</param>
|
||||
/// <param name="typeArguments">Type arguments, if necessary. Leave as null if type is non-generic.</param>
|
||||
/// <param name="methodName">Static method name</param>
|
||||
/// <param name="methodTypeArguments">Method type arguments, if necessary. Leave as null if method is non-generic.</param>
|
||||
/// <param name="parameterTypes">Method parameters types.</param>
|
||||
/// <returns>MethodInfo of a method that was found or null.</returns>
|
||||
public static MethodInfo FindStaticMethodInAssemblies(IEnumerable<Assembly> assemblies, string typeName, Type[] typeArguments, string methodName, Type[] methodTypeArguments, Type[] parameterTypes)
|
||||
{
|
||||
MethodInfo methodInfo = null;
|
||||
foreach(var t in FindTypesInAssemblies(assemblies, [(typeName, typeArguments)]))
|
||||
{
|
||||
if(t != null)
|
||||
{
|
||||
methodInfo = t.GetMethod(methodName, AllFlags, parameterTypes);
|
||||
if(methodInfo != null)
|
||||
{
|
||||
if(methodTypeArguments != null && methodTypeArguments.Length > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
methodInfo = methodInfo.MakeGenericMethod(methodTypeArguments);
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
methodInfo = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return methodInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches for specified non-generic types in specified assembly list.
|
||||
/// </summary>
|
||||
/// <param name="assemblies">Assemblies to search in</param>
|
||||
/// <param name="typeNames">A list of requested types names</param>
|
||||
/// <returns>A list of requested types. Please check resulting list length to ensure all types were found.</returns>
|
||||
public static List<Type> FindTypesInAssemblies(IEnumerable<Assembly> assemblies, IEnumerable<string> typeNames)
|
||||
{
|
||||
var genericArgs = new List<Type>();
|
||||
foreach(var x in typeNames)
|
||||
{
|
||||
foreach(var a in assemblies)
|
||||
{
|
||||
var type = a.GetType(x, false);
|
||||
if(type != null)
|
||||
{
|
||||
genericArgs.Add(type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return genericArgs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches for specified generic and non-generic types in specified assembly list.
|
||||
/// </summary>
|
||||
/// <param name="assemblies">Assemblies to search in</param>
|
||||
/// <param name="typeNames">A list of tuples of requested types names and generic argument types. Array of types can be left empty or null to specify that this type is non-generic.</param>
|
||||
/// <returns>A list of requested types. Please check resulting list length to ensure all types were found.</returns>
|
||||
public static List<Type> FindTypesInAssemblies(IEnumerable<Assembly> assemblies, IEnumerable<(string TypeName, Type[] TypeArguments)> typeNames)
|
||||
{
|
||||
var genericArgs = new List<Type>();
|
||||
foreach(var x in typeNames)
|
||||
{
|
||||
foreach(var a in assemblies)
|
||||
{
|
||||
var type = a.GetType(x.TypeName, false);
|
||||
if(type != null)
|
||||
{
|
||||
if(x.TypeArguments != null && x.TypeArguments.Length > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
type = type.MakeGenericType(x.TypeArguments);
|
||||
genericArgs.Add(type);
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
type = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
genericArgs.Add(type);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return genericArgs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts array of objects into array of these objects' types.
|
||||
/// </summary>
|
||||
/// <param name="objects"></param>
|
||||
/// <returns></returns>
|
||||
public static Type[] GetTypes(this IEnumerable<object> objects)
|
||||
{
|
||||
return objects.Select(x => x.GetType()).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates delegate to a method by MethodInfo
|
||||
/// </summary>
|
||||
/// <param name="methodInfo">MethodInfo of a method for which a delegate will be created.</param>
|
||||
/// <param name="target">Instance object that is hosting the method. Pass null if a method is static.</param>
|
||||
/// <returns></returns>
|
||||
public static Delegate CreateDelegate(MethodInfo methodInfo, object target)
|
||||
{
|
||||
Func<Type[], Type> getType;
|
||||
var isAction = methodInfo.ReturnType.Equals((typeof(void)));
|
||||
var types = methodInfo.GetParameters().Select(p => p.ParameterType);
|
||||
|
||||
if(isAction)
|
||||
{
|
||||
getType = Expression.GetActionType;
|
||||
}
|
||||
else
|
||||
{
|
||||
getType = Expression.GetFuncType;
|
||||
types = types.Concat(new[] { methodInfo.ReturnType });
|
||||
}
|
||||
|
||||
if(methodInfo.IsStatic)
|
||||
{
|
||||
return Delegate.CreateDelegate(getType(types.ToArray()), methodInfo);
|
||||
}
|
||||
|
||||
return Delegate.CreateDelegate(getType(types.ToArray()), target, methodInfo.Name);
|
||||
}
|
||||
|
||||
public static IFieldPropertyUnion[] GetFieldPropertyUnions(this Type type, BindingFlags bindingFlags = BindingFlags.Default)
|
||||
{
|
||||
var ret = new List<IFieldPropertyUnion>();
|
||||
foreach(var item in type.GetFields(bindingFlags))
|
||||
{
|
||||
//if (item.GetCustomAttribute<CompilerGeneratedAttribute>() != null) continue;
|
||||
ret.Add(new UnionField(item));
|
||||
}
|
||||
foreach(var item in type.GetProperties(bindingFlags))
|
||||
{
|
||||
//if (item.GetCustomAttribute<CompilerGeneratedAttribute>() != null) continue;
|
||||
ret.Add(new UnionProperty(item));
|
||||
}
|
||||
return [.. ret];
|
||||
}
|
||||
|
||||
public static IFieldPropertyUnion? GetFieldPropertyUnion(this Type type, string name, BindingFlags bindingFlags = BindingFlags.Default)
|
||||
{
|
||||
var f = type.GetField(name, bindingFlags);
|
||||
if(f != null)
|
||||
{
|
||||
return new UnionField(f);
|
||||
}
|
||||
var p = type.GetProperty(name, bindingFlags);
|
||||
if(p != null)
|
||||
{
|
||||
return new UnionProperty(p);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace ECommonsLite .Schedulers;
|
||||
|
||||
public interface IScheduler : IDisposable
|
||||
{
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
using ECommonsLite.DalamudServices;
|
||||
using ECommonsLite.Logging;
|
||||
using System;
|
||||
|
||||
namespace ECommonsLite.Schedulers;
|
||||
|
||||
public class TickScheduler : IScheduler
|
||||
{
|
||||
private long ExecuteAt;
|
||||
private Action Action;
|
||||
public bool Disposed { get; private set; } = false;
|
||||
|
||||
public TickScheduler(Action function, long delayMS = 0)
|
||||
{
|
||||
ExecuteAt = Environment.TickCount64 + delayMS;
|
||||
this.Action = function;
|
||||
Svc.Framework.Update += Execute;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if(!Disposed)
|
||||
{
|
||||
Svc.Framework.Update -= Execute;
|
||||
}
|
||||
Disposed = true;
|
||||
}
|
||||
|
||||
private void Execute(object _)
|
||||
{
|
||||
if(Environment.TickCount64 < ExecuteAt) return;
|
||||
try
|
||||
{
|
||||
Action();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
PluginLog.Error(e.Message + "\n" + e.StackTrace ?? "");
|
||||
}
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
@@ -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=="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Aether Tools
|
||||
|
||||
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.
|
||||
@@ -1,9 +0,0 @@
|
||||
# ECommonsLite
|
||||
This repository contains lightweight version of [ECommons](https://github.com/NightmareXIV/ECommons) library containing only essential features used by Customize+.
|
||||
|
||||
## Acknowledgements
|
||||
* Limiana and ECommons Contributors for [ECommons](https://github.com/NightmareXIV/ECommons).
|
||||
* Everyone who contributed code and features through pull requests.
|
||||
|
||||
## License
|
||||
All files in this repository are licensed under the license listed in LICENSE.md file unless stated otherwise. By contributing the code into this repository you agreeing with licensing submitted code under this license.
|
||||
Reference in New Issue
Block a user