Add IPC to set single items.

This commit is contained in:
Ottermandias 2023-12-23 13:08:20 +01:00
parent 03a0cb5514
commit aae4141550
4 changed files with 151 additions and 7 deletions

View file

@ -0,0 +1,92 @@
using System.Linq;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Plugin;
using Glamourer.Events;
using Glamourer.Services;
using Penumbra.Api.Helpers;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
namespace Glamourer.Api;
public partial class GlamourerIpc
{
public enum GlamourerErrorCode
{
Success,
ActorNotFound,
ActorNotHuman,
ItemInvalid,
}
public const string LabelSetItem = "Glamourer.SetItem";
public const string LabelSetItemByActorName = "Glamourer.SetItemByActorName";
private readonly FuncProvider<Character?, byte, ulong, uint, int> _setItemProvider;
private readonly FuncProvider<string, byte, ulong, uint, int> _setItemByActorNameProvider;
public static FuncSubscriber<Character?, byte, ulong, uint, int> SetItemSubscriber(DalamudPluginInterface pi)
=> new(pi, LabelSetItem);
public static FuncSubscriber<string, byte, ulong, uint, int> SetItemByActorNameSubscriber(DalamudPluginInterface pi)
=> new(pi, LabelSetItemByActorName);
private GlamourerErrorCode SetItem(Character? character, EquipSlot slot, CustomItemId itemId, uint key)
{
if (itemId.Id == 0)
itemId = ItemManager.NothingId(slot);
var item = _items.Resolve(slot, itemId);
if (!item.Valid)
return GlamourerErrorCode.ItemInvalid;
var identifier = _actors.FromObject(character, false, false, false);
if (!identifier.IsValid)
return GlamourerErrorCode.ActorNotFound;
if (!_stateManager.TryGetValue(identifier, out var state))
{
_objects.Update();
var data = _objects[identifier];
if (!data.Valid || !_stateManager.GetOrCreate(identifier, data.Objects[0], out state))
return GlamourerErrorCode.ActorNotFound;
}
if (!state.ModelData.IsHuman)
return GlamourerErrorCode.ActorNotHuman;
_stateManager.ChangeItem(state, slot, item, StateChanged.Source.Ipc, key);
return GlamourerErrorCode.Success;
}
private GlamourerErrorCode SetItemByActorName(string name, EquipSlot slot, CustomItemId itemId, uint key)
{
if (itemId.Id == 0)
itemId = ItemManager.NothingId(slot);
var item = _items.Resolve(slot, itemId);
if (!item.Valid)
return GlamourerErrorCode.ItemInvalid;
var found = false;
_objects.Update();
foreach (var identifier in FindActorsRevert(name).Distinct())
{
if (!_stateManager.TryGetValue(identifier, out var state))
{
var data = _objects[identifier];
if (!data.Valid || !_stateManager.GetOrCreate(identifier, data.Objects[0], out state))
continue;
}
if (!state.ModelData.IsHuman)
return GlamourerErrorCode.ActorNotHuman;
_stateManager.ChangeItem(state, slot, item, StateChanged.Source.Ipc, key);
found = true;
}
return found ? GlamourerErrorCode.Success : GlamourerErrorCode.ActorNotFound;
}
}

View file

@ -7,6 +7,7 @@ using Glamourer.Automation;
using Glamourer.Designs; using Glamourer.Designs;
using Glamourer.Events; using Glamourer.Events;
using Glamourer.Interop; using Glamourer.Interop;
using Glamourer.Services;
using Glamourer.State; using Glamourer.State;
using Penumbra.Api.Helpers; using Penumbra.Api.Helpers;
using Penumbra.GameData.Actors; using Penumbra.GameData.Actors;
@ -15,7 +16,7 @@ using Penumbra.String;
namespace Glamourer.Api; namespace Glamourer.Api;
public partial class GlamourerIpc : IDisposable public sealed partial class GlamourerIpc : IDisposable
{ {
public const int CurrentApiVersionMajor = 0; public const int CurrentApiVersionMajor = 0;
public const int CurrentApiVersionMinor = 4; public const int CurrentApiVersionMinor = 4;
@ -25,15 +26,18 @@ public partial class GlamourerIpc : IDisposable
private readonly ActorManager _actors; private readonly ActorManager _actors;
private readonly DesignConverter _designConverter; private readonly DesignConverter _designConverter;
private readonly AutoDesignApplier _autoDesignApplier; private readonly AutoDesignApplier _autoDesignApplier;
private readonly ItemManager _items;
public GlamourerIpc(DalamudPluginInterface pi, StateManager stateManager, ObjectManager objects, ActorManager actors, public GlamourerIpc(DalamudPluginInterface pi, StateManager stateManager, ObjectManager objects, ActorManager actors,
DesignConverter designConverter, StateChanged stateChangedEvent, GPoseService gPose, AutoDesignApplier autoDesignApplier) DesignConverter designConverter, StateChanged stateChangedEvent, GPoseService gPose, AutoDesignApplier autoDesignApplier,
ItemManager items)
{ {
_stateManager = stateManager; _stateManager = stateManager;
_objects = objects; _objects = objects;
_actors = actors; _actors = actors;
_designConverter = designConverter; _designConverter = designConverter;
_autoDesignApplier = autoDesignApplier; _autoDesignApplier = autoDesignApplier;
_items = items;
_gPose = gPose; _gPose = gPose;
_stateChangedEvent = stateChangedEvent; _stateChangedEvent = stateChangedEvent;
_apiVersionProvider = new FuncProvider<int>(pi, LabelApiVersion, ApiVersion); _apiVersionProvider = new FuncProvider<int>(pi, LabelApiVersion, ApiVersion);
@ -76,6 +80,11 @@ public partial class GlamourerIpc : IDisposable
_stateChangedProvider = new EventProvider<StateChanged.Type, nint, Lazy<string>>(pi, LabelStateChanged); _stateChangedProvider = new EventProvider<StateChanged.Type, nint, Lazy<string>>(pi, LabelStateChanged);
_gPoseChangedProvider = new EventProvider<bool>(pi, LabelGPoseChanged); _gPoseChangedProvider = new EventProvider<bool>(pi, LabelGPoseChanged);
_setItemProvider = new FuncProvider<Character?, byte, ulong, uint, int>(pi, LabelSetItem,
(idx, slot, item, key) => (int)SetItem(idx, (EquipSlot)slot, item, key));
_setItemByActorNameProvider = new FuncProvider<string, byte, ulong, uint, int>(pi, LabelSetItemByActorName,
(name, slot, item, key) => (int)SetItemByActorName(name, (EquipSlot)slot, item, key));
_stateChangedEvent.Subscribe(OnStateChanged, StateChanged.Priority.GlamourerIpc); _stateChangedEvent.Subscribe(OnStateChanged, StateChanged.Priority.GlamourerIpc);
_gPose.Subscribe(OnGPoseChanged, GPoseService.Priority.GlamourerIpc); _gPose.Subscribe(OnGPoseChanged, GPoseService.Priority.GlamourerIpc);
} }
@ -114,6 +123,9 @@ public partial class GlamourerIpc : IDisposable
_stateChangedProvider.Dispose(); _stateChangedProvider.Dispose();
_gPose.Unsubscribe(OnGPoseChanged); _gPose.Unsubscribe(OnGPoseChanged);
_gPoseChangedProvider.Dispose(); _gPoseChangedProvider.Dispose();
_setItemProvider.Dispose();
_setItemByActorNameProvider.Dispose();
} }
private IEnumerable<ActorIdentifier> FindActors(string actorName) private IEnumerable<ActorIdentifier> FindActors(string actorName)

View file

@ -1,10 +1,14 @@
using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Interface.Utility;
using Dalamud.Plugin; using Dalamud.Plugin;
using Glamourer.Api; using Glamourer.Api;
using Glamourer.Interop; using Glamourer.Interop;
using ImGuiNET; using ImGuiNET;
using OtterGui; using OtterGui;
using OtterGui.Raii; using OtterGui.Raii;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Gui;
using Penumbra.GameData.Structs;
namespace Glamourer.Gui.Tabs.DebugTab; namespace Glamourer.Gui.Tabs.DebugTab;
@ -16,15 +20,20 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag
public bool Disabled public bool Disabled
=> false; => false;
private int _gameObjectIndex; private int _gameObjectIndex;
private string _gameObjectName = string.Empty; private CustomItemId _customItemId;
private string _base64Apply = string.Empty; private EquipSlot _slot = EquipSlot.Head;
private string _gameObjectName = string.Empty;
private string _base64Apply = string.Empty;
private GlamourerIpc.GlamourerErrorCode _setItemEc;
private GlamourerIpc.GlamourerErrorCode _setItemByActorNameEc;
public void Draw() public unsafe void Draw()
{ {
ImGui.InputInt("Game Object Index", ref _gameObjectIndex, 0, 0); ImGui.InputInt("Game Object Index", ref _gameObjectIndex, 0, 0);
ImGui.InputTextWithHint("##gameObject", "Character Name...", ref _gameObjectName, 64); ImGui.InputTextWithHint("##gameObject", "Character Name...", ref _gameObjectName, 64);
ImGui.InputTextWithHint("##base64", "Design Base64...", ref _base64Apply, 2047); ImGui.InputTextWithHint("##base64", "Design Base64...", ref _base64Apply, 2047);
DrawItemIdInput();
using var table = ImRaii.Table("##ipc", 2, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg); using var table = ImRaii.Table("##ipc", 2, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg);
if (!table) if (!table)
return; return;
@ -104,5 +113,36 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag
if (ImGui.Button("Revert##CustomizeCharacter")) if (ImGui.Button("Revert##CustomizeCharacter"))
GlamourerIpc.RevertToAutomationCharacterSubscriber(_pluginInterface) GlamourerIpc.RevertToAutomationCharacterSubscriber(_pluginInterface)
.Invoke(_objectManager.Objects[_gameObjectIndex] as Character, 1337); .Invoke(_objectManager.Objects[_gameObjectIndex] as Character, 1337);
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelSetItem);
ImGui.TableNextColumn();
if (ImGui.Button("Set##SetItem"))
_setItemEc = (GlamourerIpc.GlamourerErrorCode)GlamourerIpc.SetItemSubscriber(_pluginInterface)
.Invoke(_objectManager.Objects[_gameObjectIndex] as Character, (byte)_slot, _customItemId.Id, 1337);
if (_setItemEc != GlamourerIpc.GlamourerErrorCode.Success)
{
ImGui.SameLine();
ImGui.TextUnformatted(_setItemEc.ToString());
}
ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelSetItemByActorName);
ImGui.TableNextColumn();
if (ImGui.Button("Set##SetItemByActorName"))
_setItemByActorNameEc = (GlamourerIpc.GlamourerErrorCode)GlamourerIpc.SetItemByActorNameSubscriber(_pluginInterface)
.Invoke(_gameObjectName, (byte)_slot, _customItemId.Id, 1337);
if (_setItemByActorNameEc != GlamourerIpc.GlamourerErrorCode.Success)
{
ImGui.SameLine();
ImGui.TextUnformatted(_setItemByActorNameEc.ToString());
}
}
private unsafe void DrawItemIdInput()
{
var tmp = _customItemId.Id;
if (ImGui.InputScalar("Custom Item ID", ImGuiDataType.U64, (nint)(&tmp), nint.Zero, nint.Zero))
_customItemId = (CustomItemId)tmp;
ImGui.SameLine();
EquipSlotCombo.Draw("Equip Slot", string.Empty, 200 * ImGuiHelpers.GlobalScale, ref _slot);
} }
} }

@ -1 +1 @@
Subproject commit ed37f83424c11a5a601e74f4660cd52ebd68a7b3 Subproject commit 4af8775f0925ff89e6900c8816b03e0ffeb73f6d