diff --git a/Glamourer/Api/GlamourerIpc.ApiVersions.cs b/Glamourer/Api/GlamourerIpc.ApiVersions.cs new file mode 100644 index 0000000..beea408 --- /dev/null +++ b/Glamourer/Api/GlamourerIpc.ApiVersions.cs @@ -0,0 +1,27 @@ +using System; +using Dalamud.Plugin; +using Penumbra.Api.Helpers; + +namespace Glamourer.Api; + +public partial class GlamourerIpc +{ + public const string LabelApiVersion = "Glamourer.ApiVersion"; + public const string LabelApiVersions = "Glamourer.ApiVersions"; + + private readonly FuncProvider _apiVersionProvider; + private readonly FuncProvider<(int Major, int Minor)> _apiVersionsProvider; + + public static FuncSubscriber ApiVersionSubscriber(DalamudPluginInterface pi) + => new(pi, LabelApiVersion); + + public static FuncSubscriber<(int Major, int Minor)> ApiVersionsSubscriber(DalamudPluginInterface pi) + => new(pi, LabelApiVersions); + + [Obsolete($"This call is obsolete, please use {nameof(ApiVersions)} instead.")] + public int ApiVersion() + => CurrentApiVersionMajor; + + public (int Major, int Minor) ApiVersions() + => (CurrentApiVersionMajor, CurrentApiVersionMinor); +} diff --git a/Glamourer/Api/GlamourerIpc.Apply.cs b/Glamourer/Api/GlamourerIpc.Apply.cs new file mode 100644 index 0000000..b3b20f7 --- /dev/null +++ b/Glamourer/Api/GlamourerIpc.Apply.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using Dalamud.Game.ClientState.Objects.Types; +using Dalamud.Plugin; +using Glamourer.Designs; +using Glamourer.Interop.Structs; +using Penumbra.Api.Helpers; +using Penumbra.GameData.Actors; + +namespace Glamourer.Api; + +public partial class GlamourerIpc +{ + public const string LabelApplyAll = "Glamourer.ApplyAll"; + public const string LabelApplyAllToCharacter = "Glamourer.ApplyAllToCharacter"; + public const string LabelApplyOnlyEquipment = "Glamourer.ApplyOnlyEquipment"; + public const string LabelApplyOnlyEquipmentToCharacter = "Glamourer.ApplyOnlyEquipmentToCharacter"; + public const string LabelApplyOnlyCustomization = "Glamourer.ApplyOnlyCustomization"; + public const string LabelApplyOnlyCustomizationToCharacter = "Glamourer.ApplyOnlyCustomizationToCharacter"; + + private readonly ActionProvider _applyAllProvider; + private readonly ActionProvider _applyAllToCharacterProvider; + private readonly ActionProvider _applyOnlyEquipmentProvider; + private readonly ActionProvider _applyOnlyEquipmentToCharacterProvider; + private readonly ActionProvider _applyOnlyCustomizationProvider; + private readonly ActionProvider _applyOnlyCustomizationToCharacterProvider; + + public static ActionSubscriber ApplyAllSubscriber(DalamudPluginInterface pi) + => new(pi, LabelApplyAll); + + public static ActionSubscriber ApplyAllToCharacterSubscriber(DalamudPluginInterface pi) + => new(pi, LabelApplyAllToCharacter); + + public static ActionSubscriber ApplyOnlyEquipmentSubscriber(DalamudPluginInterface pi) + => new(pi, LabelApplyOnlyEquipment); + + public static ActionSubscriber ApplyOnlyEquipmentToCharacterSubscriber(DalamudPluginInterface pi) + => new(pi, LabelApplyOnlyEquipmentToCharacter); + + public static ActionSubscriber ApplyOnlyCustomizationSubscriber(DalamudPluginInterface pi) + => new(pi, LabelApplyOnlyCustomization); + + public static ActionSubscriber ApplyOnlyCustomizationToCharacterSubscriber(DalamudPluginInterface pi) + => new(pi, LabelApplyOnlyCustomizationToCharacter); + + + public void ApplyAll(string base64, string characterName) + => ApplyDesign(CreateTemporaryFromBase64(base64, true, true), FindActors(characterName)); + + public void ApplyAllToCharacter(string base64, Character? character) + => ApplyDesign(CreateTemporaryFromBase64(base64, true, true), FindActors(character)); + + public void ApplyOnlyEquipment(string base64, string characterName) + => ApplyDesign(CreateTemporaryFromBase64(base64, false, true), FindActors(characterName)); + + public void ApplyOnlyEquipmentToCharacter(string base64, Character? character) + => ApplyDesign(CreateTemporaryFromBase64(base64, false, true), FindActors(character)); + + public void ApplyOnlyCustomization(string base64, string characterName) + => ApplyDesign(CreateTemporaryFromBase64(base64, true, false), FindActors(characterName)); + + public void ApplyOnlyCustomizationToCharacter(string base64, Character? character) + => ApplyDesign(CreateTemporaryFromBase64(base64, true, false), FindActors(character)); + + private void ApplyDesign(Design? design, IEnumerable actors) + { + if (design == null) + return; + + _objects.Update(); + foreach (var id in actors) + { + if (!_stateManager.TryGetValue(id, out var state)) + { + var data = _objects.TryGetValue(id, out var d) ? d : ActorData.Invalid; + if (!data.Valid || !_stateManager.GetOrCreate(id, data.Objects[0], out state)) + continue; + } + + _stateManager.ApplyDesign(design, state); + } + } + + private Design? CreateTemporaryFromBase64(string base64, bool customize, bool equip) + { + try + { + var ret = new Design(_items); + ret.MigrateBase64(_items, base64); + if (!customize) + { + ret.ApplyCustomize = 0; + ret.SetApplyWetness(false); + } + + if (!equip) + { + ret.ApplyEquip = 0; + ret.SetApplyHatVisible(false); + ret.SetApplyWeaponVisible(false); + ret.SetApplyVisorToggle(false); + } + + return ret; + } + catch (Exception ex) + { + Glamourer.Log.Error($"[IPC] Could not parse base64 string [{base64}]:\n{ex}"); + return null; + } + } +} diff --git a/Glamourer/Api/GlamourerIpc.GetCustomization.cs b/Glamourer/Api/GlamourerIpc.GetCustomization.cs new file mode 100644 index 0000000..de56904 --- /dev/null +++ b/Glamourer/Api/GlamourerIpc.GetCustomization.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using System.Linq; +using Dalamud.Game.ClientState.Objects.Types; +using Dalamud.Plugin; +using Glamourer.Customization; +using Glamourer.Designs; +using Glamourer.Structs; +using Penumbra.Api.Helpers; +using Penumbra.GameData.Actors; + +namespace Glamourer.Api; + +public partial class GlamourerIpc +{ + public const string LabelGetAllCustomization = "Glamourer.GetAllCustomization"; + public const string LabelGetAllCustomizationFromCharacter = "Glamourer.GetAllCustomizationFromCharacter"; + + private readonly FuncProvider _getAllCustomizationProvider; + private readonly FuncProvider _getAllCustomizationFromCharacterProvider; + + public static FuncSubscriber GetAllCustomizationSubscriber(DalamudPluginInterface pi) + => new(pi, LabelGetAllCustomization); + + public static FuncSubscriber GetAllCustomizationFromCharacterSubscriber(DalamudPluginInterface pi) + => new(pi, LabelGetAllCustomizationFromCharacter); + + public string? GetAllCustomization(string characterName) + => GetCustomization(FindActors(characterName)); + + public string? GetAllCustomizationFromCharacter(Character? character) + => GetCustomization(FindActors(character)); + + private string? GetCustomization(IEnumerable actors) + { + var actor = actors.FirstOrDefault(ActorIdentifier.Invalid); + if (!actor.IsValid) + return null; + + if (!_stateManager.TryGetValue(actor, out var state)) + { + _objects.Update(); + if (!_objects.TryGetValue(actor, out var data) || !data.Valid) + return null; + if (!_stateManager.GetOrCreate(actor, data.Objects[0], out state)) + return null; + } + + return DesignBase64Migration.CreateOldBase64(state.ModelData, EquipFlagExtensions.All, CustomizeFlagExtensions.All, true, true, + true, false); + } +} diff --git a/Glamourer/Api/GlamourerIpc.Revert.cs b/Glamourer/Api/GlamourerIpc.Revert.cs new file mode 100644 index 0000000..89d7c45 --- /dev/null +++ b/Glamourer/Api/GlamourerIpc.Revert.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using Dalamud.Game.ClientState.Objects.Types; +using Dalamud.Plugin; +using Penumbra.Api.Helpers; +using Penumbra.GameData.Actors; + +namespace Glamourer.Api; + +public partial class GlamourerIpc +{ + public const string LabelRevert = "Glamourer.Revert"; + public const string LabelRevertCharacter = "Glamourer.RevertCharacter"; + + private readonly ActionProvider _revertProvider; + private readonly ActionProvider _revertCharacterProvider; + + public static ActionSubscriber RevertSubscriber(DalamudPluginInterface pi) + => new(pi, LabelRevert); + + public static ActionSubscriber RevertCharacterSubscriber(DalamudPluginInterface pi) + => new(pi, LabelRevertCharacter); + + public void Revert(string characterName) + => Revert(FindActors(characterName)); + + public void RevertCharacter(Character? character) + => Revert(FindActors(character)); + + private void Revert(IEnumerable actors) + { + foreach (var id in actors) + { + if (_stateManager.TryGetValue(id, out var state)) + _stateManager.ResetState(state); + } + } +} diff --git a/Glamourer/Api/GlamourerIpc.cs b/Glamourer/Api/GlamourerIpc.cs index 1bdd18a..1f13781 100644 --- a/Glamourer/Api/GlamourerIpc.cs +++ b/Glamourer/Api/GlamourerIpc.cs @@ -1,318 +1,87 @@ -using Dalamud.Game.ClientState; -using Dalamud.Game.ClientState.Objects; -using Dalamud.Game.ClientState.Objects.Types; -using Dalamud.Logging; +using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Plugin; -using Dalamud.Plugin.Ipc; using System; -using Glamourer.Api; -using Glamourer.Designs; +using System.Collections.Generic; +using System.Linq; +using Glamourer.Interop; using Glamourer.Services; using Glamourer.State; -using Penumbra.Api.Enums; +using Penumbra.Api.Helpers; +using Penumbra.GameData.Actors; +using Penumbra.String; -namespace Glamourer; +namespace Glamourer.Api; -public partial class Glamourer +public partial class GlamourerIpc : IDisposable { - public class GlamourerIpc : IDisposable + public const int CurrentApiVersionMajor = 0; + public const int CurrentApiVersionMinor = 1; + + private readonly StateManager _stateManager; + private readonly ObjectManager _objects; + private readonly ActorService _actors; + private readonly ItemManager _items; + + public GlamourerIpc(DalamudPluginInterface pi, StateManager stateManager, ObjectManager objects, ActorService actors, ItemManager items) { - public const int CurrentApiVersion = 0; - public const string LabelProviderApiVersion = "Glamourer.ApiVersion"; - public const string LabelProviderGetAllCustomization = "Glamourer.GetAllCustomization"; - public const string LabelProviderGetAllCustomizationFromCharacter = "Glamourer.GetAllCustomizationFromCharacter"; - public const string LabelProviderApplyAll = "Glamourer.ApplyAll"; - public const string LabelProviderApplyAllToCharacter = "Glamourer.ApplyAllToCharacter"; - public const string LabelProviderApplyOnlyEquipment = "Glamourer.ApplyOnlyEquipment"; - public const string LabelProviderApplyOnlyEquipmentToCharacter = "Glamourer.ApplyOnlyEquipmentToCharacter"; - public const string LabelProviderApplyOnlyCustomization = "Glamourer.ApplyOnlyCustomization"; - public const string LabelProviderApplyOnlyCustomizationToCharacter = "Glamourer.ApplyOnlyCustomizationToCharacter"; - public const string LabelProviderRevert = "Glamourer.Revert"; - public const string LabelProviderRevertCharacter = "Glamourer.RevertCharacter"; + _stateManager = stateManager; + _objects = objects; + _actors = actors; + _items = items; + _apiVersionProvider = new FuncProvider(pi, LabelApiVersion, ApiVersion); + _apiVersionsProvider = new FuncProvider<(int Major, int Minor)>(pi, LabelApiVersions, ApiVersions); - private readonly ObjectTable _objectTable; - private readonly DalamudPluginInterface _pluginInterface; - private readonly ActiveDesign.Manager _stateManager; - private readonly ItemManager _items; - private readonly PenumbraAttach _penumbra; - private readonly ActorService _actors; + _getAllCustomizationProvider = new FuncProvider(pi, LabelGetAllCustomization, GetAllCustomization); + _getAllCustomizationFromCharacterProvider = + new FuncProvider(pi, LabelGetAllCustomizationFromCharacter, GetAllCustomizationFromCharacter); - internal ICallGateProvider? ProviderGetAllCustomization; - internal ICallGateProvider? ProviderGetAllCustomizationFromCharacter; - internal ICallGateProvider? ProviderApplyAll; - internal ICallGateProvider? ProviderApplyAllToCharacter; - internal ICallGateProvider? ProviderApplyOnlyCustomization; - internal ICallGateProvider? ProviderApplyOnlyCustomizationToCharacter; - internal ICallGateProvider? ProviderApplyOnlyEquipment; - internal ICallGateProvider? ProviderApplyOnlyEquipmentToCharacter; - internal ICallGateProvider? ProviderRevert; - internal ICallGateProvider? ProviderRevertCharacter; - internal ICallGateProvider? ProviderGetApiVersion; + _applyAllProvider = new ActionProvider(pi, LabelApplyAll, ApplyAll); + _applyAllToCharacterProvider = new ActionProvider(pi, LabelApplyAllToCharacter, ApplyAllToCharacter); + _applyOnlyEquipmentProvider = new ActionProvider(pi, LabelApplyOnlyEquipment, ApplyOnlyEquipment); + _applyOnlyEquipmentToCharacterProvider = + new ActionProvider(pi, LabelApplyOnlyEquipmentToCharacter, ApplyOnlyEquipmentToCharacter); + _applyOnlyCustomizationProvider = new ActionProvider(pi, LabelApplyOnlyCustomization, ApplyOnlyCustomization); + _applyOnlyCustomizationToCharacterProvider = + new ActionProvider(pi, LabelApplyOnlyCustomizationToCharacter, ApplyOnlyCustomizationToCharacter); - public GlamourerIpc(ObjectTable objectTable, DalamudPluginInterface pluginInterface, ActiveDesign.Manager stateManager, - ItemManager items, PenumbraAttach penumbra, ActorService actors) - { - _objectTable = objectTable; - _pluginInterface = pluginInterface; - _stateManager = stateManager; - _items = items; - _penumbra = penumbra; - _actors = actors; + _revertProvider = new ActionProvider(pi, LabelRevert, Revert); + _revertCharacterProvider = new ActionProvider(pi, LabelRevertCharacter, RevertCharacter); + } - InitializeProviders(); - } + public void Dispose() + { + _apiVersionProvider.Dispose(); + _apiVersionsProvider.Dispose(); - public void Dispose() - => DisposeProviders(); + _getAllCustomizationProvider.Dispose(); + _getAllCustomizationFromCharacterProvider.Dispose(); - private void DisposeProviders() - { - ProviderGetAllCustomization?.UnregisterFunc(); - ProviderGetAllCustomizationFromCharacter?.UnregisterFunc(); - ProviderApplyAll?.UnregisterAction(); - ProviderApplyAllToCharacter?.UnregisterAction(); - ProviderApplyOnlyCustomization?.UnregisterAction(); - ProviderApplyOnlyCustomizationToCharacter?.UnregisterAction(); - ProviderApplyOnlyEquipment?.UnregisterAction(); - ProviderApplyOnlyEquipmentToCharacter?.UnregisterAction(); - ProviderRevert?.UnregisterAction(); - ProviderRevertCharacter?.UnregisterAction(); - ProviderGetApiVersion?.UnregisterFunc(); - } + _applyAllProvider.Dispose(); + _applyAllToCharacterProvider.Dispose(); + _applyOnlyEquipmentProvider.Dispose(); + _applyOnlyEquipmentToCharacterProvider.Dispose(); + _applyOnlyCustomizationProvider.Dispose(); + _applyOnlyCustomizationToCharacterProvider.Dispose(); + _revertProvider.Dispose(); + _revertCharacterProvider.Dispose(); + } - private void InitializeProviders() - { - try - { - ProviderGetApiVersion = _pluginInterface.GetIpcProvider(LabelProviderApiVersion); - ProviderGetApiVersion.RegisterFunc(GetApiVersion); - } - catch (Exception ex) - { - PluginLog.Error(ex, $"Error registering IPC provider for {LabelProviderApiVersion}."); - } + private IEnumerable FindActors(string actorName) + { + if (actorName.Length == 0 || !ByteString.FromString(actorName, out var byteString)) + return Array.Empty(); - try - { - ProviderGetAllCustomization = _pluginInterface.GetIpcProvider(LabelProviderGetAllCustomization); - ProviderGetAllCustomization.RegisterFunc(GetAllCustomization); - } - catch (Exception ex) - { - PluginLog.Error(ex, $"Error registering IPC provider for {LabelProviderApplyOnlyEquipment}."); - } + _objects.Update(); + return _objects.Where(i => i.Key is { IsValid: true, Type: IdentifierType.Player } && i.Key.PlayerName == byteString) + .Select(i => i.Key); + } - try - { - ProviderGetAllCustomizationFromCharacter = - _pluginInterface.GetIpcProvider(LabelProviderGetAllCustomizationFromCharacter); - ProviderGetAllCustomizationFromCharacter.RegisterFunc(GetAllCustomization); - } - catch (Exception ex) - { - PluginLog.Error(ex, $"Error registering IPC provider for {LabelProviderGetAllCustomizationFromCharacter}."); - } + private IEnumerable FindActors(Character? character) + { + var id = _actors.AwaitedService.FromObject(character, true, true, false); + if (!id.IsValid) + yield break; - try - { - ProviderApplyAll = - _pluginInterface.GetIpcProvider(LabelProviderApplyAll); - ProviderApplyAll.RegisterAction(ApplyAll); - } - catch (Exception ex) - { - PluginLog.Error(ex, $"Error registering IPC provider for {LabelProviderApplyAll}."); - } - - try - { - ProviderApplyAllToCharacter = - _pluginInterface.GetIpcProvider(LabelProviderApplyAllToCharacter); - ProviderApplyAllToCharacter.RegisterAction(ApplyAll); - } - catch (Exception ex) - { - PluginLog.Error(ex, $"Error registering IPC provider for {LabelProviderApplyAll}."); - } - - try - { - ProviderApplyOnlyCustomization = - _pluginInterface.GetIpcProvider(LabelProviderApplyOnlyCustomization); - ProviderApplyOnlyCustomization.RegisterAction(ApplyOnlyCustomization); - } - catch (Exception ex) - { - PluginLog.Error(ex, $"Error registering IPC provider for {LabelProviderApplyOnlyCustomization}."); - } - - try - { - ProviderApplyOnlyCustomizationToCharacter = - _pluginInterface.GetIpcProvider(LabelProviderApplyOnlyCustomizationToCharacter); - ProviderApplyOnlyCustomizationToCharacter.RegisterAction(ApplyOnlyCustomization); - } - catch (Exception ex) - { - PluginLog.Error(ex, $"Error registering IPC provider for {LabelProviderApplyOnlyCustomization}."); - } - - try - { - ProviderApplyOnlyEquipment = - _pluginInterface.GetIpcProvider(LabelProviderApplyOnlyEquipment); - ProviderApplyOnlyEquipment.RegisterAction(ApplyOnlyEquipment); - } - catch (Exception ex) - { - PluginLog.Error(ex, $"Error registering IPC provider for {LabelProviderApplyOnlyEquipment}."); - } - - try - { - ProviderApplyOnlyEquipmentToCharacter = - _pluginInterface.GetIpcProvider(LabelProviderApplyOnlyEquipmentToCharacter); - ProviderApplyOnlyEquipmentToCharacter.RegisterAction(ApplyOnlyEquipment); - } - catch (Exception ex) - { - PluginLog.Error(ex, $"Error registering IPC provider for {LabelProviderApplyOnlyEquipment}."); - } - - try - { - ProviderRevert = - _pluginInterface.GetIpcProvider(LabelProviderRevert); - ProviderRevert.RegisterAction(Revert); - } - catch (Exception ex) - { - PluginLog.Error(ex, $"Error registering IPC provider for {LabelProviderRevert}."); - } - - try - { - ProviderRevertCharacter = - _pluginInterface.GetIpcProvider(LabelProviderRevertCharacter); - ProviderRevertCharacter.RegisterAction(Revert); - } - catch (Exception ex) - { - PluginLog.Error(ex, $"Error registering IPC provider for {LabelProviderRevert}."); - } - } - - private static int GetApiVersion() - => CurrentApiVersion; - - private void ApplyAll(string customization, string characterName) - { - foreach (var gameObject in _objectTable) - { - if (gameObject.Name.ToString() == characterName) - { - ApplyAll(customization, gameObject as Character); - return; - } - } - } - - private void ApplyAll(string customization, Character? character) - { - if (character == null) - return; - - var design = Design.CreateTemporaryFromBase64(_items, customization, true, true); - var active = _stateManager.GetOrCreateSave(character.Address); - _stateManager.ApplyDesign(active, design, false); - } - - private void ApplyOnlyCustomization(string customization, string characterName) - { - foreach (var gameObject in _objectTable) - { - if (gameObject.Name.ToString() == characterName) - { - ApplyOnlyCustomization(customization, gameObject as Character); - return; - } - } - } - - private void ApplyOnlyCustomization(string customization, Character? character) - { - if (character == null) - return; - - var design = Design.CreateTemporaryFromBase64(_items, customization, true, false); - var active = _stateManager.GetOrCreateSave(character.Address); - _stateManager.ApplyDesign(active, design, false); - } - - private void ApplyOnlyEquipment(string customization, string characterName) - { - foreach (var gameObject in _objectTable) - { - if (gameObject.Name.ToString() != characterName) - continue; - - ApplyOnlyEquipment(customization, gameObject as Character); - return; - } - } - - private void ApplyOnlyEquipment(string customization, Character? character) - { - if (character == null) - return; - - var design = Design.CreateTemporaryFromBase64(_items, customization, false, true); - var active = _stateManager.GetOrCreateSave(character.Address); - _stateManager.ApplyDesign(active, design, false); - } - - private void Revert(string characterName) - { - foreach (var gameObject in _objectTable) - { - if (gameObject.Name.ToString() != characterName) - continue; - - Revert(gameObject as Character); - } - } - - private void Revert(Character? character) - { - if (character == null) - return; - - var ident = _actors.AwaitedService.FromObject(character, true, false, false); - _stateManager.DeleteSave(ident); - _penumbra.RedrawObject(character.Address, RedrawType.Redraw); - } - - private string? GetAllCustomization(Character? character) - { - if (character == null) - return null; - - var ident = _actors.AwaitedService.FromObject(character, true, false, false); - if (!_stateManager.TryGetValue(ident, out var design)) - design = new ActiveDesign(_items, ident, character.Address); - - return design.CreateOldBase64(); - } - - private string? GetAllCustomization(string characterName) - { - foreach (var gameObject in _objectTable) - { - if (gameObject.Name.ToString() == characterName) - return GetAllCustomization(gameObject as Character); - } - - return null; - } + yield return id; } } diff --git a/Glamourer/Designs/DesignBase64Migration.cs b/Glamourer/Designs/DesignBase64Migration.cs index 58d9f54..3a18ec5 100644 --- a/Glamourer/Designs/DesignBase64Migration.cs +++ b/Glamourer/Designs/DesignBase64Migration.cs @@ -81,7 +81,7 @@ public static class DesignBase64Migration data.SetItem(EquipSlot.MainHand, main); data.SetStain(EquipSlot.MainHand, cur[0].Stain); var off = items.Identify(EquipSlot.OffHand, cur[1].Set, cur[1].Type, (byte)cur[1].Variant, main.Type); - if (!off.Valid) + if (main.Type.Offhand() != FullEquipType.Unknown && !off.Valid) throw new Exception($"Base64 string invalid, weapon could not be identified."); data.SetItem(EquipSlot.OffHand, off); diff --git a/Glamourer/Gui/Tabs/DebugTab.cs b/Glamourer/Gui/Tabs/DebugTab.cs index 5db76df..09157ba 100644 --- a/Glamourer/Gui/Tabs/DebugTab.cs +++ b/Glamourer/Gui/Tabs/DebugTab.cs @@ -3,10 +3,12 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Numerics; -using System.Runtime.CompilerServices; using Dalamud.Game.ClientState.Objects; +using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Interface; +using Dalamud.Plugin; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; +using Glamourer.Api; using Glamourer.Customization; using Glamourer.Designs; using Glamourer.Events; @@ -27,6 +29,7 @@ namespace Glamourer.Gui.Tabs; public unsafe class DebugTab : ITab { + private readonly DalamudPluginInterface _pluginInterface; private readonly Configuration _config; private readonly VisorService _visorService; private readonly ChangeCustomizeService _changeCustomizeService; @@ -36,6 +39,7 @@ public unsafe class DebugTab : ITab private readonly PenumbraService _penumbra; private readonly ObjectTable _objects; private readonly ObjectManager _objectManager; + private readonly GlamourerIpc _ipc; private readonly ItemManager _items; private readonly ActorService _actors; @@ -57,7 +61,7 @@ public unsafe class DebugTab : ITab UpdateSlotService updateSlotService, WeaponService weaponService, PenumbraService penumbra, ActorService actors, ItemManager items, CustomizationService customization, ObjectManager objectManager, DesignFileSystem designFileSystem, DesignManager designManager, StateManager state, Configuration config, - PenumbraChangedItemTooltip penumbraTooltip, MetaService metaService) + PenumbraChangedItemTooltip penumbraTooltip, MetaService metaService, GlamourerIpc ipc, DalamudPluginInterface pluginInterface) { _changeCustomizeService = changeCustomizeService; _visorService = visorService; @@ -74,7 +78,9 @@ public unsafe class DebugTab : ITab _state = state; _config = config; _penumbraTooltip = penumbraTooltip; - _metaService = metaService; + _metaService = metaService; + _ipc = ipc; + _pluginInterface = pluginInterface; } public ReadOnlySpan Label @@ -91,6 +97,7 @@ public unsafe class DebugTab : ITab DrawPenumbraHeader(); DrawDesigns(); DrawState(); + DrawIpc(); } #region Interop @@ -778,7 +785,7 @@ public unsafe class DebugTab : ITab return; ImGui.SetNextItemWidth(-1); - ImGui.InputTextWithHint("##base64", "Base 64 input...", ref _base64, 2048); + ImGui.InputTextWithHint("##base64", "Base 64 input...", ref _base64, 2047); if (ImGui.IsItemDeactivatedAfterEdit()) { try @@ -1108,4 +1115,86 @@ public unsafe class DebugTab : ITab } #endregion + + #region IPC + + private string _gameObjectName = string.Empty; + private string _base64Apply = string.Empty; + + private void DrawIpc() + { + if (!ImGui.CollapsingHeader("IPC Tester")) + return; + + ImGui.InputInt("Game Object Index", ref _gameObjectIndex, 0, 0); + ImGui.InputTextWithHint("##gameObject", "Character Name...", ref _gameObjectName, 64); + ImGui.InputTextWithHint("##base64", "Design Base64...", ref _base64Apply, 2047); + using var table = ImRaii.Table("##ipc", 2, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg); + if (!table) + return; + + ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApiVersions); + var (major, minor) = GlamourerIpc.ApiVersionsSubscriber(_pluginInterface).Invoke(); + ImGuiUtil.DrawTableColumn($"({major}, {minor})"); + + ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelGetAllCustomization); + ImGui.TableNextColumn(); + var base64 = GlamourerIpc.GetAllCustomizationSubscriber(_pluginInterface).Invoke(_gameObjectName); + if (base64 != null) + ImGuiUtil.CopyOnClickSelectable(base64); + else + ImGui.TextUnformatted("Error"); + + ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelGetAllCustomizationFromCharacter); + ImGui.TableNextColumn(); + base64 = GlamourerIpc.GetAllCustomizationFromCharacterSubscriber(_pluginInterface).Invoke(_objects[_gameObjectIndex] as Character); + if (base64 != null) + ImGuiUtil.CopyOnClickSelectable(base64); + else + ImGui.TextUnformatted("Error"); + + ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelRevert); + ImGui.TableNextColumn(); + if (ImGui.Button("Revert##Name")) + GlamourerIpc.RevertSubscriber(_pluginInterface).Invoke(_gameObjectName); + + ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelRevertCharacter); + ImGui.TableNextColumn(); + if (ImGui.Button("Revert##Character")) + GlamourerIpc.RevertCharacterSubscriber(_pluginInterface).Invoke(_objects[_gameObjectIndex] as Character); + + ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyAll); + ImGui.TableNextColumn(); + if (ImGui.Button("Apply##AllName")) + GlamourerIpc.ApplyAllSubscriber(_pluginInterface).Invoke(_base64Apply, _gameObjectName); + + ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyAllToCharacter); + ImGui.TableNextColumn(); + if (ImGui.Button("Apply##AllCharacter")) + GlamourerIpc.ApplyAllToCharacterSubscriber(_pluginInterface).Invoke(_base64Apply, _objects[_gameObjectIndex] as Character); + + ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyOnlyEquipment); + ImGui.TableNextColumn(); + if (ImGui.Button("Apply##EquipName")) + GlamourerIpc.ApplyOnlyEquipmentSubscriber(_pluginInterface).Invoke(_base64Apply, _gameObjectName); + + ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyOnlyEquipmentToCharacter); + ImGui.TableNextColumn(); + if (ImGui.Button("Apply##EquipCharacter")) + GlamourerIpc.ApplyOnlyEquipmentToCharacterSubscriber(_pluginInterface) + .Invoke(_base64Apply, _objects[_gameObjectIndex] as Character); + + ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyOnlyCustomization); + ImGui.TableNextColumn(); + if (ImGui.Button("Apply##CustomizeName")) + GlamourerIpc.ApplyOnlyCustomizationSubscriber(_pluginInterface).Invoke(_base64Apply, _gameObjectName); + + ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyOnlyCustomizationToCharacter); + ImGui.TableNextColumn(); + if (ImGui.Button("Apply##CustomizeCharacter")) + GlamourerIpc.ApplyOnlyCustomizationToCharacterSubscriber(_pluginInterface) + .Invoke(_base64Apply, _objects[_gameObjectIndex] as Character); + } + + #endregion } diff --git a/Glamourer/Services/ItemManager.cs b/Glamourer/Services/ItemManager.cs index 130f553..7016dab 100644 --- a/Glamourer/Services/ItemManager.cs +++ b/Glamourer/Services/ItemManager.cs @@ -186,7 +186,7 @@ public class ItemManager : IDisposable public bool IsOffhandValid(FullEquipType offType, uint offId, out EquipItem off) { off = Resolve(offType, offId); - return off.Valid; + return offType == FullEquipType.Unknown || off.Valid; } /// Returns whether an offhand is valid given mainhand. diff --git a/Glamourer/Services/ServiceManager.cs b/Glamourer/Services/ServiceManager.cs index 5e62308..7d6ad25 100644 --- a/Glamourer/Services/ServiceManager.cs +++ b/Glamourer/Services/ServiceManager.cs @@ -1,4 +1,5 @@ using Dalamud.Plugin; +using Glamourer.Api; using Glamourer.Designs; using Glamourer.Events; using Glamourer.Gui; @@ -99,5 +100,6 @@ public static class ServiceManager .AddSingleton(); private static IServiceCollection AddApi(this IServiceCollection services) - => services.AddSingleton(); + => services.AddSingleton() + .AddSingleton(); }