Add compatible IPC for now.

This commit is contained in:
Ottermandias 2023-06-22 14:02:36 +02:00
parent 1aba34f34a
commit 63e82d19dc
9 changed files with 392 additions and 305 deletions

View file

@ -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<int> _apiVersionProvider;
private readonly FuncProvider<(int Major, int Minor)> _apiVersionsProvider;
public static FuncSubscriber<int> 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);
}

View file

@ -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<string, string> _applyAllProvider;
private readonly ActionProvider<string, Character?> _applyAllToCharacterProvider;
private readonly ActionProvider<string, string> _applyOnlyEquipmentProvider;
private readonly ActionProvider<string, Character?> _applyOnlyEquipmentToCharacterProvider;
private readonly ActionProvider<string, string> _applyOnlyCustomizationProvider;
private readonly ActionProvider<string, Character?> _applyOnlyCustomizationToCharacterProvider;
public static ActionSubscriber<string, string> ApplyAllSubscriber(DalamudPluginInterface pi)
=> new(pi, LabelApplyAll);
public static ActionSubscriber<string, Character?> ApplyAllToCharacterSubscriber(DalamudPluginInterface pi)
=> new(pi, LabelApplyAllToCharacter);
public static ActionSubscriber<string, string> ApplyOnlyEquipmentSubscriber(DalamudPluginInterface pi)
=> new(pi, LabelApplyOnlyEquipment);
public static ActionSubscriber<string, Character?> ApplyOnlyEquipmentToCharacterSubscriber(DalamudPluginInterface pi)
=> new(pi, LabelApplyOnlyEquipmentToCharacter);
public static ActionSubscriber<string, string> ApplyOnlyCustomizationSubscriber(DalamudPluginInterface pi)
=> new(pi, LabelApplyOnlyCustomization);
public static ActionSubscriber<string, Character?> 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<ActorIdentifier> 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;
}
}
}

View file

@ -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<string, string?> _getAllCustomizationProvider;
private readonly FuncProvider<Character?, string?> _getAllCustomizationFromCharacterProvider;
public static FuncSubscriber<string, string?> GetAllCustomizationSubscriber(DalamudPluginInterface pi)
=> new(pi, LabelGetAllCustomization);
public static FuncSubscriber<Character?, string?> 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<ActorIdentifier> 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);
}
}

View file

@ -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<string> _revertProvider;
private readonly ActionProvider<Character?> _revertCharacterProvider;
public static ActionSubscriber<string> RevertSubscriber(DalamudPluginInterface pi)
=> new(pi, LabelRevert);
public static ActionSubscriber<Character?> 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<ActorIdentifier> actors)
{
foreach (var id in actors)
{
if (_stateManager.TryGetValue(id, out var state))
_stateManager.ResetState(state);
}
}
}

View file

@ -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<int>(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<string, string?>(pi, LabelGetAllCustomization, GetAllCustomization);
_getAllCustomizationFromCharacterProvider =
new FuncProvider<Character?, string?>(pi, LabelGetAllCustomizationFromCharacter, GetAllCustomizationFromCharacter);
internal ICallGateProvider<string, string?>? ProviderGetAllCustomization;
internal ICallGateProvider<Character?, string?>? ProviderGetAllCustomizationFromCharacter;
internal ICallGateProvider<string, string, object>? ProviderApplyAll;
internal ICallGateProvider<string, Character?, object>? ProviderApplyAllToCharacter;
internal ICallGateProvider<string, string, object>? ProviderApplyOnlyCustomization;
internal ICallGateProvider<string, Character?, object>? ProviderApplyOnlyCustomizationToCharacter;
internal ICallGateProvider<string, string, object>? ProviderApplyOnlyEquipment;
internal ICallGateProvider<string, Character?, object>? ProviderApplyOnlyEquipmentToCharacter;
internal ICallGateProvider<string, object>? ProviderRevert;
internal ICallGateProvider<Character?, object>? ProviderRevertCharacter;
internal ICallGateProvider<int>? ProviderGetApiVersion;
_applyAllProvider = new ActionProvider<string, string>(pi, LabelApplyAll, ApplyAll);
_applyAllToCharacterProvider = new ActionProvider<string, Character?>(pi, LabelApplyAllToCharacter, ApplyAllToCharacter);
_applyOnlyEquipmentProvider = new ActionProvider<string, string>(pi, LabelApplyOnlyEquipment, ApplyOnlyEquipment);
_applyOnlyEquipmentToCharacterProvider =
new ActionProvider<string, Character?>(pi, LabelApplyOnlyEquipmentToCharacter, ApplyOnlyEquipmentToCharacter);
_applyOnlyCustomizationProvider = new ActionProvider<string, string>(pi, LabelApplyOnlyCustomization, ApplyOnlyCustomization);
_applyOnlyCustomizationToCharacterProvider =
new ActionProvider<string, Character?>(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<string>(pi, LabelRevert, Revert);
_revertCharacterProvider = new ActionProvider<Character?>(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<int>(LabelProviderApiVersion);
ProviderGetApiVersion.RegisterFunc(GetApiVersion);
}
catch (Exception ex)
{
PluginLog.Error(ex, $"Error registering IPC provider for {LabelProviderApiVersion}.");
}
private IEnumerable<ActorIdentifier> FindActors(string actorName)
{
if (actorName.Length == 0 || !ByteString.FromString(actorName, out var byteString))
return Array.Empty<ActorIdentifier>();
try
{
ProviderGetAllCustomization = _pluginInterface.GetIpcProvider<string, string?>(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<Character?, string?>(LabelProviderGetAllCustomizationFromCharacter);
ProviderGetAllCustomizationFromCharacter.RegisterFunc(GetAllCustomization);
}
catch (Exception ex)
{
PluginLog.Error(ex, $"Error registering IPC provider for {LabelProviderGetAllCustomizationFromCharacter}.");
}
private IEnumerable<ActorIdentifier> FindActors(Character? character)
{
var id = _actors.AwaitedService.FromObject(character, true, true, false);
if (!id.IsValid)
yield break;
try
{
ProviderApplyAll =
_pluginInterface.GetIpcProvider<string, string, object>(LabelProviderApplyAll);
ProviderApplyAll.RegisterAction(ApplyAll);
}
catch (Exception ex)
{
PluginLog.Error(ex, $"Error registering IPC provider for {LabelProviderApplyAll}.");
}
try
{
ProviderApplyAllToCharacter =
_pluginInterface.GetIpcProvider<string, Character?, object>(LabelProviderApplyAllToCharacter);
ProviderApplyAllToCharacter.RegisterAction(ApplyAll);
}
catch (Exception ex)
{
PluginLog.Error(ex, $"Error registering IPC provider for {LabelProviderApplyAll}.");
}
try
{
ProviderApplyOnlyCustomization =
_pluginInterface.GetIpcProvider<string, string, object>(LabelProviderApplyOnlyCustomization);
ProviderApplyOnlyCustomization.RegisterAction(ApplyOnlyCustomization);
}
catch (Exception ex)
{
PluginLog.Error(ex, $"Error registering IPC provider for {LabelProviderApplyOnlyCustomization}.");
}
try
{
ProviderApplyOnlyCustomizationToCharacter =
_pluginInterface.GetIpcProvider<string, Character?, object>(LabelProviderApplyOnlyCustomizationToCharacter);
ProviderApplyOnlyCustomizationToCharacter.RegisterAction(ApplyOnlyCustomization);
}
catch (Exception ex)
{
PluginLog.Error(ex, $"Error registering IPC provider for {LabelProviderApplyOnlyCustomization}.");
}
try
{
ProviderApplyOnlyEquipment =
_pluginInterface.GetIpcProvider<string, string, object>(LabelProviderApplyOnlyEquipment);
ProviderApplyOnlyEquipment.RegisterAction(ApplyOnlyEquipment);
}
catch (Exception ex)
{
PluginLog.Error(ex, $"Error registering IPC provider for {LabelProviderApplyOnlyEquipment}.");
}
try
{
ProviderApplyOnlyEquipmentToCharacter =
_pluginInterface.GetIpcProvider<string, Character?, object>(LabelProviderApplyOnlyEquipmentToCharacter);
ProviderApplyOnlyEquipmentToCharacter.RegisterAction(ApplyOnlyEquipment);
}
catch (Exception ex)
{
PluginLog.Error(ex, $"Error registering IPC provider for {LabelProviderApplyOnlyEquipment}.");
}
try
{
ProviderRevert =
_pluginInterface.GetIpcProvider<string, object>(LabelProviderRevert);
ProviderRevert.RegisterAction(Revert);
}
catch (Exception ex)
{
PluginLog.Error(ex, $"Error registering IPC provider for {LabelProviderRevert}.");
}
try
{
ProviderRevertCharacter =
_pluginInterface.GetIpcProvider<Character?, object>(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;
}
}

View file

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

View file

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

View file

@ -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;
}
/// <summary> Returns whether an offhand is valid given mainhand. </summary>

View file

@ -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<PenumbraChangedItemTooltip>();
private static IServiceCollection AddApi(this IServiceCollection services)
=> services.AddSingleton<CommandService>();
=> services.AddSingleton<CommandService>()
.AddSingleton<GlamourerIpc>();
}