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.Events;
using Glamourer.Interop;
using Glamourer.Services;
using Glamourer.State;
using Penumbra.Api.Helpers;
using Penumbra.GameData.Actors;
@ -15,7 +16,7 @@ using Penumbra.String;
namespace Glamourer.Api;
public partial class GlamourerIpc : IDisposable
public sealed partial class GlamourerIpc : IDisposable
{
public const int CurrentApiVersionMajor = 0;
public const int CurrentApiVersionMinor = 4;
@ -25,15 +26,18 @@ public partial class GlamourerIpc : IDisposable
private readonly ActorManager _actors;
private readonly DesignConverter _designConverter;
private readonly AutoDesignApplier _autoDesignApplier;
private readonly ItemManager _items;
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;
_objects = objects;
_actors = actors;
_designConverter = designConverter;
_autoDesignApplier = autoDesignApplier;
_items = items;
_gPose = gPose;
_stateChangedEvent = stateChangedEvent;
_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);
_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);
_gPose.Subscribe(OnGPoseChanged, GPoseService.Priority.GlamourerIpc);
}
@ -114,6 +123,9 @@ public partial class GlamourerIpc : IDisposable
_stateChangedProvider.Dispose();
_gPose.Unsubscribe(OnGPoseChanged);
_gPoseChangedProvider.Dispose();
_setItemProvider.Dispose();
_setItemByActorNameProvider.Dispose();
}
private IEnumerable<ActorIdentifier> FindActors(string actorName)

View file

@ -1,10 +1,14 @@
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Interface.Utility;
using Dalamud.Plugin;
using Glamourer.Api;
using Glamourer.Interop;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Gui;
using Penumbra.GameData.Structs;
namespace Glamourer.Gui.Tabs.DebugTab;
@ -16,15 +20,20 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag
public bool Disabled
=> false;
private int _gameObjectIndex;
private string _gameObjectName = string.Empty;
private string _base64Apply = string.Empty;
private int _gameObjectIndex;
private CustomItemId _customItemId;
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.InputTextWithHint("##gameObject", "Character Name...", ref _gameObjectName, 64);
ImGui.InputTextWithHint("##base64", "Design Base64...", ref _base64Apply, 2047);
DrawItemIdInput();
using var table = ImRaii.Table("##ipc", 2, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg);
if (!table)
return;
@ -104,5 +113,36 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag
if (ImGui.Button("Revert##CustomizeCharacter"))
GlamourerIpc.RevertToAutomationCharacterSubscriber(_pluginInterface)
.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