Add Emotes to Changed Items.

This commit is contained in:
Ottermandias 2023-09-06 21:15:05 +02:00
parent a890258cf5
commit 6cc89f3e7c
3 changed files with 115 additions and 37 deletions

@ -1 +1 @@
Subproject commit 43f6737d4baa7988a5fe23096f20827bc54e6812 Subproject commit bd7e79262a0db06e27e61b98ab0a31ebb881be2a

View file

@ -27,22 +27,23 @@ public class ChangedItemDrawer : IDisposable
[Flags] [Flags]
public enum ChangedItemIcon : uint public enum ChangedItemIcon : uint
{ {
Head = 0x0001, Head = 0x00_00_01,
Body = 0x0002, Body = 0x00_00_02,
Hands = 0x0004, Hands = 0x00_00_04,
Legs = 0x0008, Legs = 0x00_00_08,
Feet = 0x0010, Feet = 0x00_00_10,
Ears = 0x0020, Ears = 0x00_00_20,
Neck = 0x0040, Neck = 0x00_00_40,
Wrists = 0x0080, Wrists = 0x00_00_80,
Finger = 0x0100, Finger = 0x00_01_00,
Monster = 0x0200, Monster = 0x00_02_00,
Demihuman = 0x0400, Demihuman = 0x00_04_00,
Customization = 0x0800, Customization = 0x00_08_00,
Action = 0x1000, Action = 0x00_10_00,
Mainhand = 0x2000, Mainhand = 0x00_20_00,
Offhand = 0x4000, Offhand = 0x00_40_00,
Unknown = 0x8000, Unknown = 0x00_80_00,
Emote = 0x01_00_00,
} }
public const ChangedItemIcon AllFlags = (ChangedItemIcon)0xFFFF; public const ChangedItemIcon AllFlags = (ChangedItemIcon)0xFFFF;
@ -51,10 +52,11 @@ public class ChangedItemDrawer : IDisposable
private readonly Configuration _config; private readonly Configuration _config;
private readonly ExcelSheet<Item> _items; private readonly ExcelSheet<Item> _items;
private readonly CommunicatorService _communicator; private readonly CommunicatorService _communicator;
private readonly Dictionary<ChangedItemIcon, TextureWrap> _icons = new(16); private readonly Dictionary<ChangedItemIcon, TextureWrap> _icons = new(16);
private float _smallestIconWidth; private float _smallestIconWidth;
public ChangedItemDrawer(UiBuilder uiBuilder, IDataManager gameData, ITextureProvider textureProvider, CommunicatorService communicator, Configuration config) public ChangedItemDrawer(UiBuilder uiBuilder, IDataManager gameData, ITextureProvider textureProvider, CommunicatorService communicator,
Configuration config)
{ {
_items = gameData.GetExcelSheet<Item>()!; _items = gameData.GetExcelSheet<Item>()!;
uiBuilder.RunWhenUiPrepared(() => CreateEquipSlotIcons(uiBuilder, gameData, textureProvider), true); uiBuilder.RunWhenUiPrepared(() => CreateEquipSlotIcons(uiBuilder, gameData, textureProvider), true);
@ -164,6 +166,7 @@ public class ChangedItemDrawer : IDisposable
ChangedItemIcon.Offhand, ChangedItemIcon.Offhand,
ChangedItemIcon.Customization, ChangedItemIcon.Customization,
ChangedItemIcon.Action, ChangedItemIcon.Action,
ChangedItemIcon.Emote,
ChangedItemIcon.Monster, ChangedItemIcon.Monster,
ChangedItemIcon.Demihuman, ChangedItemIcon.Demihuman,
ChangedItemIcon.Unknown, ChangedItemIcon.Unknown,
@ -182,14 +185,12 @@ public class ChangedItemDrawer : IDisposable
using var popup = ImRaii.ContextPopupItem(type.ToString()); using var popup = ImRaii.ContextPopupItem(type.ToString());
if (popup) if (popup)
{
if (ImGui.MenuItem("Enable Only This")) if (ImGui.MenuItem("Enable Only This"))
{ {
_config.ChangedItemFilter = type; _config.ChangedItemFilter = type;
_config.Save(); _config.Save();
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
} }
}
if (ImGui.IsItemHovered()) if (ImGui.IsItemHovered())
{ {
@ -238,6 +239,8 @@ public class ChangedItemDrawer : IDisposable
{ {
if (name.StartsWith("Action: ")) if (name.StartsWith("Action: "))
iconType = ChangedItemIcon.Action; iconType = ChangedItemIcon.Action;
else if (name.StartsWith("Emote: "))
iconType = ChangedItemIcon.Emote;
else if (name.StartsWith("Customization: ")) else if (name.StartsWith("Customization: "))
iconType = ChangedItemIcon.Customization; iconType = ChangedItemIcon.Customization;
break; break;
@ -306,6 +309,7 @@ public class ChangedItemDrawer : IDisposable
ChangedItemIcon.Demihuman => "Demi-Human", ChangedItemIcon.Demihuman => "Demi-Human",
ChangedItemIcon.Customization => "Customization", ChangedItemIcon.Customization => "Customization",
ChangedItemIcon.Action => "Action", ChangedItemIcon.Action => "Action",
ChangedItemIcon.Emote => "Emote",
ChangedItemIcon.Mainhand => "Weapon (Mainhand)", ChangedItemIcon.Mainhand => "Weapon (Mainhand)",
ChangedItemIcon.Offhand => "Weapon (Offhand)", ChangedItemIcon.Offhand => "Weapon (Offhand)",
_ => "Other", _ => "Other",
@ -354,21 +358,47 @@ public class ChangedItemDrawer : IDisposable
Add(ChangedItemIcon.Demihuman, textureProvider.GetTextureFromGame("ui/icon/062000/062041_hr1.tex", true)); Add(ChangedItemIcon.Demihuman, textureProvider.GetTextureFromGame("ui/icon/062000/062041_hr1.tex", true));
Add(ChangedItemIcon.Customization, textureProvider.GetTextureFromGame("ui/icon/062000/062043_hr1.tex", true)); Add(ChangedItemIcon.Customization, textureProvider.GetTextureFromGame("ui/icon/062000/062043_hr1.tex", true));
Add(ChangedItemIcon.Action, textureProvider.GetTextureFromGame("ui/icon/062000/062001_hr1.tex", true)); Add(ChangedItemIcon.Action, textureProvider.GetTextureFromGame("ui/icon/062000/062001_hr1.tex", true));
Add(ChangedItemIcon.Emote, LoadEmoteTexture(gameData, uiBuilder));
Add(ChangedItemIcon.Unknown, LoadUnknownTexture(gameData, uiBuilder));
Add(AllFlags, textureProvider.GetTextureFromGame("ui/icon/114000/114052_hr1.tex", true)); Add(AllFlags, textureProvider.GetTextureFromGame("ui/icon/114000/114052_hr1.tex", true));
_smallestIconWidth = _icons.Values.Min(i => i.Width);
return true;
}
private static unsafe TextureWrap? LoadUnknownTexture(IDataManager gameData, UiBuilder uiBuilder)
{
var unk = gameData.GetFile<TexFile>("ui/uld/levelup2_hr1.tex"); var unk = gameData.GetFile<TexFile>("ui/uld/levelup2_hr1.tex");
if (unk == null) if (unk == null)
return true; return null;
var image = unk.GetRgbaImageData(); var image = unk.GetRgbaImageData();
var bytes = new byte[unk.Header.Height * unk.Header.Height * 4]; var bytes = new byte[unk.Header.Height * unk.Header.Height * 4];
var diff = 2 * (unk.Header.Height - unk.Header.Width); var diff = 2 * (unk.Header.Height - unk.Header.Width);
for (var y = 0; y < unk.Header.Height; ++y) for (var y = 0; y < unk.Header.Height; ++y)
image.AsSpan(4 * y * unk.Header.Width, 4 * unk.Header.Width).CopyTo(bytes.AsSpan(4 * y * unk.Header.Height + diff)); image.AsSpan(4 * y * unk.Header.Width, 4 * unk.Header.Width).CopyTo(bytes.AsSpan(4 * y * unk.Header.Height + diff));
Add(ChangedItemIcon.Unknown, uiBuilder.LoadImageRaw(bytes, unk.Header.Height, unk.Header.Height, 4));
_smallestIconWidth = _icons.Values.Min(i => i.Width); return uiBuilder.LoadImageRaw(bytes, unk.Header.Height, unk.Header.Height, 4);
}
return true; private static unsafe TextureWrap? LoadEmoteTexture(IDataManager gameData, UiBuilder uiBuilder)
{
var emote = gameData.GetFile<TexFile>("ui/icon/000000/000019_hr1.tex");
if (emote == null)
return null;
var image2 = emote.GetRgbaImageData();
fixed (byte* ptr = image2)
{
var color = (uint*)ptr;
for (var i = 0; i < image2.Length / 4; ++i)
{
if (color[i] == 0xFF000000)
image2[i * 4 + 3] = 0;
}
}
return uiBuilder.LoadImageRaw(image2, emote.Header.Width, emote.Header.Height, 4);
} }
} }

View file

@ -4,6 +4,7 @@ using System.Linq;
using System.Numerics; using System.Numerics;
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Interface.Windowing; using Dalamud.Interface.Windowing;
using Dalamud.Utility;
using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Client.Game.Group; using FFXIVClientStructs.FFXIV.Client.Game.Group;
using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.Game.Object;
@ -66,6 +67,7 @@ public class DebugTab : Window, ITab
private readonly FrameworkManager _framework; private readonly FrameworkManager _framework;
private readonly TextureManager _textureManager; private readonly TextureManager _textureManager;
private readonly SkinFixer _skinFixer; private readonly SkinFixer _skinFixer;
private readonly IdentifierService _identifier;
public DebugTab(StartTracker timer, PerformanceTracker performance, Configuration config, CollectionManager collectionManager, public DebugTab(StartTracker timer, PerformanceTracker performance, Configuration config, CollectionManager collectionManager,
ValidityChecker validityChecker, ModManager modManager, HttpApi httpApi, ActorService actorService, ValidityChecker validityChecker, ModManager modManager, HttpApi httpApi, ActorService actorService,
@ -73,7 +75,7 @@ public class DebugTab : Window, ITab
ResourceManagerService resourceManager, PenumbraIpcProviders ipc, CollectionResolver collectionResolver, ResourceManagerService resourceManager, PenumbraIpcProviders ipc, CollectionResolver collectionResolver,
DrawObjectState drawObjectState, PathState pathState, SubfileHelper subfileHelper, IdentifiedCollectionCache identifiedCollectionCache, DrawObjectState drawObjectState, PathState pathState, SubfileHelper subfileHelper, IdentifiedCollectionCache identifiedCollectionCache,
CutsceneService cutsceneService, ModImportManager modImporter, ImportPopup importPopup, FrameworkManager framework, CutsceneService cutsceneService, ModImportManager modImporter, ImportPopup importPopup, FrameworkManager framework,
TextureManager textureManager, SkinFixer skinFixer) TextureManager textureManager, SkinFixer skinFixer, IdentifierService identifier)
: base("Penumbra Debug Window", ImGuiWindowFlags.NoCollapse, false) : base("Penumbra Debug Window", ImGuiWindowFlags.NoCollapse, false)
{ {
IsOpen = true; IsOpen = true;
@ -107,6 +109,7 @@ public class DebugTab : Window, ITab
_framework = framework; _framework = framework;
_textureManager = textureManager; _textureManager = textureManager;
_skinFixer = skinFixer; _skinFixer = skinFixer;
_identifier = identifier;
} }
public ReadOnlySpan<byte> Label public ReadOnlySpan<byte> Label
@ -138,12 +141,10 @@ public class DebugTab : Window, ITab
ImGui.NewLine(); ImGui.NewLine();
DrawDebugCharacterUtility(); DrawDebugCharacterUtility();
ImGui.NewLine(); ImGui.NewLine();
DrawStainTemplates(); DrawData();
ImGui.NewLine(); ImGui.NewLine();
DrawDebugTabMetaLists(); DrawDebugTabMetaLists();
ImGui.NewLine(); ImGui.NewLine();
DrawDebugResidentResources();
ImGui.NewLine();
DrawResourceProblems(); DrawResourceProblems();
ImGui.NewLine(); ImGui.NewLine();
DrawPlayerModelInfo(); DrawPlayerModelInfo();
@ -370,7 +371,9 @@ public class DebugTab : Window, ITab
{ {
ImGuiUtil.DrawTableColumn($"{((GameObject*)obj.Address)->ObjectIndex}"); ImGuiUtil.DrawTableColumn($"{((GameObject*)obj.Address)->ObjectIndex}");
ImGuiUtil.DrawTableColumn($"0x{obj.Address:X}"); ImGuiUtil.DrawTableColumn($"0x{obj.Address:X}");
ImGuiUtil.DrawTableColumn((obj.Address == nint.Zero) ? string.Empty : $"0x{(nint)((Character*)obj.Address)->GameObject.GetDrawObject():X}"); ImGuiUtil.DrawTableColumn(obj.Address == nint.Zero
? string.Empty
: $"0x{(nint)((Character*)obj.Address)->GameObject.GetDrawObject():X}");
var identifier = _actorService.AwaitedService.FromObject(obj, false, true, false); var identifier = _actorService.AwaitedService.FromObject(obj, false, true, false);
ImGuiUtil.DrawTableColumn(_actorService.AwaitedService.ToString(identifier)); ImGuiUtil.DrawTableColumn(_actorService.AwaitedService.ToString(identifier));
var id = obj.ObjectKind == ObjectKind.BattleNpc ? $"{identifier.DataId} | {obj.DataId}" : identifier.DataId.ToString(); var id = obj.ObjectKind == ObjectKind.BattleNpc ? $"{identifier.DataId} | {obj.DataId}" : identifier.DataId.ToString();
@ -546,9 +549,49 @@ public class DebugTab : Window, ITab
} }
} }
private void DrawData()
{
if (!ImGui.CollapsingHeader("Game Data"))
return;
DrawEmotes();
DrawStainTemplates();
}
private string _emoteSearchFile = string.Empty;
private string _emoteSearchName = string.Empty;
private void DrawEmotes()
{
using var mainTree = TreeNode("Emotes");
if (!mainTree)
return;
ImGui.InputText("File Name", ref _emoteSearchFile, 256);
ImGui.InputText("Emote Name", ref _emoteSearchName, 256);
using var table = Table("##table", 2, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.SizingFixedFit, new Vector2(-1, 12 * ImGui.GetTextLineHeightWithSpacing()));
if (!table)
return;
var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeightWithSpacing());
var dummy = ImGuiClip.FilteredClippedDraw(_identifier.AwaitedService.Emotes, skips,
p => p.Key.Contains(_emoteSearchFile, StringComparison.OrdinalIgnoreCase)
&& (_emoteSearchName.Length == 0
|| p.Value.Any(s => s.Name.ToDalamudString().TextValue.Contains(_emoteSearchName, StringComparison.OrdinalIgnoreCase))),
p =>
{
ImGui.TableNextColumn();
ImGui.TextUnformatted(p.Key);
ImGui.TableNextColumn();
ImGui.TextUnformatted(string.Join(", ", p.Value.Select(v => v.Name.ToDalamudString().TextValue)));
});
ImGuiClip.DrawEndDummy(dummy, ImGui.GetTextLineHeightWithSpacing());
}
private void DrawStainTemplates() private void DrawStainTemplates()
{ {
if (!ImGui.CollapsingHeader("Staining Templates")) using var mainTree = TreeNode("Staining Templates");
if (!mainTree)
return; return;
foreach (var (key, data) in _stains.StmFile.Entries) foreach (var (key, data) in _stains.StmFile.Entries)
@ -625,16 +668,15 @@ public class DebugTab : Window, ITab
ImGui.TableNextRow(); ImGui.TableNextRow();
continue; continue;
} }
UiHelpers.Text(resource); UiHelpers.Text(resource);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
var data = (nint)ResourceHandle.GetData(resource); var data = (nint)ResourceHandle.GetData(resource);
var length = ResourceHandle.GetLength(resource); var length = ResourceHandle.GetLength(resource);
if (ImGui.Selectable($"0x{data:X}")) if (ImGui.Selectable($"0x{data:X}"))
{
if (data != nint.Zero && length > 0) if (data != nint.Zero && length > 0)
ImGui.SetClipboardText(string.Join("\n", ImGui.SetClipboardText(string.Join("\n",
new ReadOnlySpan<byte>((byte*)data, (int)length).ToArray().Select(b => b.ToString("X2")))); new ReadOnlySpan<byte>((byte*)data, (int)length).ToArray().Select(b => b.ToString("X2"))));
}
ImGuiUtil.HoverTooltip("Click to copy bytes to clipboard."); ImGuiUtil.HoverTooltip("Click to copy bytes to clipboard.");
ImGui.TableNextColumn(); ImGui.TableNextColumn();
@ -655,7 +697,9 @@ public class DebugTab : Window, ITab
ImGui.TextUnformatted($"{_characterUtility.DefaultResource(intern).Size}"); ImGui.TextUnformatted($"{_characterUtility.DefaultResource(intern).Size}");
} }
else else
{
ImGui.TableNextColumn(); ImGui.TableNextColumn();
}
} }
} }
@ -679,7 +723,8 @@ public class DebugTab : Window, ITab
/// <summary> Draw information about the resident resource files. </summary> /// <summary> Draw information about the resident resource files. </summary>
private unsafe void DrawDebugResidentResources() private unsafe void DrawDebugResidentResources()
{ {
if (!ImGui.CollapsingHeader("Resident Resources")) using var tree = TreeNode("Resident Resources");
if (!tree)
return; return;
if (_residentResources.Address == null || _residentResources.Address->NumResources == 0) if (_residentResources.Address == null || _residentResources.Address->NumResources == 0)
@ -703,8 +748,10 @@ public class DebugTab : Window, ITab
private static void DrawCopyableAddress(string label, nint address) private static void DrawCopyableAddress(string label, nint address)
{ {
using (var _ = PushFont(UiBuilder.MonoFont)) using (var _ = PushFont(UiBuilder.MonoFont))
{
if (ImGui.Selectable($"0x{address:X16} {label}")) if (ImGui.Selectable($"0x{address:X16} {label}"))
ImGui.SetClipboardText($"{address:X16}"); ImGui.SetClipboardText($"{address:X16}");
}
ImGuiUtil.HoverTooltip("Click to copy address to clipboard."); ImGuiUtil.HoverTooltip("Click to copy address to clipboard.");
} }
@ -789,9 +836,10 @@ public class DebugTab : Window, ITab
if (!header) if (!header)
return; return;
DrawCopyableAddress("CharacterUtility", _characterUtility.Address); DrawCopyableAddress("CharacterUtility", _characterUtility.Address);
DrawCopyableAddress("ResidentResourceManager", _residentResources.Address); DrawCopyableAddress("ResidentResourceManager", _residentResources.Address);
DrawCopyableAddress("Device", Device.Instance()); DrawCopyableAddress("Device", Device.Instance());
DrawDebugResidentResources();
} }
/// <summary> Draw resources with unusual reference count. </summary> /// <summary> Draw resources with unusual reference count. </summary>