diff --git a/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj b/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj index 1cdfda74e..859d95957 100644 --- a/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj +++ b/Dalamud.CorePlugin/Dalamud.CorePlugin.csproj @@ -25,8 +25,8 @@ - - + + all diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index b844edd31..f7994e19e 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -67,8 +67,8 @@ - - + + all diff --git a/Dalamud/Game/ClientState/JobGauge/JobGauges.cs b/Dalamud/Game/ClientState/JobGauge/JobGauges.cs index e47bead36..67429956b 100644 --- a/Dalamud/Game/ClientState/JobGauge/JobGauges.cs +++ b/Dalamud/Game/ClientState/JobGauge/JobGauges.cs @@ -28,7 +28,7 @@ internal class JobGauges : IServiceType, IJobGauges } /// - public unsafe IntPtr Address => (nint)(CSJobGaugeManager.Instance()->CurrentGauge); + public unsafe IntPtr Address => (nint)(&CSJobGaugeManager.Instance()->EmptyGauge); /// public T Get() where T : JobGaugeBase diff --git a/Dalamud/Game/Config/SystemConfigOption.cs b/Dalamud/Game/Config/SystemConfigOption.cs index 5305e06d9..f7e3bd3f8 100644 --- a/Dalamud/Game/Config/SystemConfigOption.cs +++ b/Dalamud/Game/Config/SystemConfigOption.cs @@ -1436,4 +1436,46 @@ public enum SystemConfigOption /// [GameConfigOption("PadButton_R3", ConfigType.String)] PadButton_R3, + + /// + /// System option with the internal name ActiveInstanceGuid. + /// This option is a String. + /// + [GameConfigOption("ActiveInstanceGuid", ConfigType.String)] + ActiveInstanceGuid, + + /// + /// System option with the internal name ActiveProductGuid. + /// This option is a String. + /// + [GameConfigOption("ActiveProductGuid", ConfigType.String)] + ActiveProductGuid, + + /// + /// System option with the internal name MsqProgress. + /// This option is a UInt. + /// + [GameConfigOption("MsqProgress", ConfigType.UInt)] + MsqProgress, + + /// + /// System option with the internal name PromptConfigUpdate. + /// This option is a UInt. + /// + [GameConfigOption("PromptConfigUpdate", ConfigType.UInt)] + PromptConfigUpdate, + + /// + /// System option with the internal name TitleScreenType. + /// This option is a UInt. + /// + [GameConfigOption("TitleScreenType", ConfigType.UInt)] + TitleScreenType, + + /// + /// System option with the internal name FirstConfigBackup. + /// This option is a UInt. + /// + [GameConfigOption("FirstConfigBackup", ConfigType.UInt)] + FirstConfigBackup, } diff --git a/Dalamud/Game/Config/UiConfigOption.cs b/Dalamud/Game/Config/UiConfigOption.cs index bf329bd6c..1a44c3afa 100644 --- a/Dalamud/Game/Config/UiConfigOption.cs +++ b/Dalamud/Game/Config/UiConfigOption.cs @@ -118,6 +118,7 @@ public enum UiConfigOption /// System option with the internal name LockonDefaultZoom_179. /// This option is a Float. /// + [Obsolete("This option won't work. Use LockonDefaultZoom.")] [GameConfigOption("LockonDefaultZoom_179", ConfigType.Float)] LockonDefaultZoom_179, @@ -3578,4 +3579,25 @@ public enum UiConfigOption /// [GameConfigOption("PadMode", ConfigType.UInt)] PadMode, + + /// + /// System option with the internal name EnableMoveTiltCharacter. + /// This option is a UInt. + /// + [GameConfigOption("EnableMoveTiltCharacter", ConfigType.UInt)] + EnableMoveTiltCharacter, + + /// + /// System option with the internal name EnableMoveTiltMountGround. + /// This option is a UInt. + /// + [GameConfigOption("EnableMoveTiltMountGround", ConfigType.UInt)] + EnableMoveTiltMountGround, + + /// + /// System option with the internal name EnableMoveTiltMountFly. + /// This option is a UInt. + /// + [GameConfigOption("EnableMoveTiltMountFly", ConfigType.UInt)] + EnableMoveTiltMountFly, } diff --git a/Dalamud/Game/Gui/GameGui.cs b/Dalamud/Game/Gui/GameGui.cs index 54f4253cd..aecbb7201 100644 --- a/Dalamud/Game/Gui/GameGui.cs +++ b/Dalamud/Game/Gui/GameGui.cs @@ -32,12 +32,11 @@ internal sealed unsafe class GameGui : IInternalDisposableService, IGameGui { private static readonly ModuleLog Log = new("GameGui"); - [ServiceManager.ServiceDependency] - private readonly Framework framework = Service.Get(); - private readonly GameGuiAddressResolver address; private readonly Hook setGlobalBgmHook; + private readonly Hook handleItemHoverHook; + private readonly Hook handleItemOutHook; private readonly Hook handleActionHoverHook; private readonly Hook handleActionOutHook; private readonly Hook handleImmHook; @@ -57,6 +56,9 @@ internal sealed unsafe class GameGui : IInternalDisposableService, IGameGui this.setGlobalBgmHook = Hook.FromAddress(this.address.SetGlobalBgm, this.HandleSetGlobalBgmDetour); + this.handleItemHoverHook = Hook.FromAddress((nint)AgentItemDetail.StaticVirtualTablePointer->Update, this.HandleItemHoverDetour); + this.handleItemOutHook = Hook.FromAddress((nint)AgentItemDetail.StaticVirtualTablePointer->ReceiveEvent, this.HandleItemOutDetour); + this.handleActionHoverHook = Hook.FromAddress(AgentActionDetail.Addresses.HandleActionHover.Value, this.HandleActionHoverDetour); this.handleActionOutHook = Hook.FromAddress((nint)AgentActionDetail.StaticVirtualTablePointer->ReceiveEvent, this.HandleActionOutDetour); @@ -67,13 +69,13 @@ internal sealed unsafe class GameGui : IInternalDisposableService, IGameGui this.utf8StringFromSequenceHook = Hook.FromAddress(Utf8String.Addresses.Ctor_FromSequence.Value, this.Utf8StringFromSequenceDetour); this.setGlobalBgmHook.Enable(); + this.handleItemHoverHook.Enable(); + this.handleItemOutHook.Enable(); this.handleImmHook.Enable(); this.setUiVisibilityHook.Enable(); this.handleActionHoverHook.Enable(); this.handleActionOutHook.Enable(); this.utf8StringFromSequenceHook.Enable(); - - this.framework.Update += this.FrameworkUpdate; } // Hooked delegates @@ -252,9 +254,9 @@ internal sealed unsafe class GameGui : IInternalDisposableService, IGameGui /// void IInternalDisposableService.DisposeService() { - this.framework.Update -= this.FrameworkUpdate; - this.setGlobalBgmHook.Dispose(); + this.handleItemHoverHook.Dispose(); + this.handleItemOutHook.Dispose(); this.handleImmHook.Dispose(); this.setUiVisibilityHook.Dispose(); this.handleActionHoverHook.Dispose(); @@ -300,6 +302,46 @@ internal sealed unsafe class GameGui : IInternalDisposableService, IGameGui return retVal; } + private void HandleItemHoverDetour(AgentItemDetail* thisPtr, uint frameCount) + { + this.handleItemHoverHook.Original(thisPtr, frameCount); + + if (!thisPtr->IsAgentActive()) + return; + + var itemId = (ulong)thisPtr->ItemId; + if (this.HoveredItem == itemId) + return; + + this.HoveredItem = itemId; + this.HoveredItemChanged?.InvokeSafely(this, itemId); + + Log.Verbose($"HoveredItem changed: {itemId}"); + } + + private AtkValue* HandleItemOutDetour(AgentItemDetail* thisPtr, AtkValue* returnValue, AtkValue* values, uint valueCount, ulong eventKind) + { + var ret = this.handleItemOutHook.Original(thisPtr, returnValue, values, valueCount, eventKind); + + if (values != null && valueCount == 1 && values->Int == -1) + { + this.HoveredItem = 0; + + try + { + this.HoveredItemChanged?.Invoke(this, 0); + } + catch (Exception e) + { + Log.Error(e, "Could not dispatch HoveredItemChanged event."); + } + + Log.Verbose("HoveredItem changed: 0"); + } + + return ret; + } + private void HandleActionHoverDetour(AgentActionDetail* hoverState, ActionKind actionKind, uint actionId, int a4, byte a5) { this.handleActionHoverHook.Original(hoverState, actionKind, actionId, a4, a5); @@ -371,24 +413,6 @@ internal sealed unsafe class GameGui : IInternalDisposableService, IGameGui return thisPtr; // this function shouldn't need to return but the original asm moves this into rax before returning so be safe? } - - private unsafe void FrameworkUpdate(IFramework framework) - { - var agentItemDetail = AgentItemDetail.Instance(); - if (agentItemDetail != null) - { - var itemId = agentItemDetail->ItemId; - - if (this.HoveredItem != itemId) - { - Log.Verbose($"HoveredItem changed: {itemId}"); - - this.HoveredItem = itemId; - - this.HoveredItemChanged?.InvokeSafely(this, itemId); - } - } - } } /// diff --git a/Dalamud/Game/Inventory/GameInventoryItem.cs b/Dalamud/Game/Inventory/GameInventoryItem.cs index fb27346e0..a9b178411 100644 --- a/Dalamud/Game/Inventory/GameInventoryItem.cs +++ b/Dalamud/Game/Inventory/GameInventoryItem.cs @@ -122,7 +122,7 @@ public unsafe struct GameInventoryItem : IEquatable /// /// Gets the color used for this item. /// - public ReadOnlySpan Stains => new(Unsafe.AsPointer(ref this.InternalItem.Stains[0]), 2); + public ReadOnlySpan Stains => new(Unsafe.AsPointer(ref this.InternalItem.Stains[0]), 2); /// /// Gets the glamour id for this item. diff --git a/Dalamud/Game/Text/SeIconChar.cs b/Dalamud/Game/Text/SeIconChar.cs index 17924c671..00ffb7342 100644 --- a/Dalamud/Game/Text/SeIconChar.cs +++ b/Dalamud/Game/Text/SeIconChar.cs @@ -766,4 +766,54 @@ public enum SeIconChar /// The Japanese Eorzea time icon unicode character. /// EorzeaTimeJa = 0xE0DB, + + /// + /// The boxed, outlined number 0 icon unicode character. + /// + BoxedOutlinedNumber0 = 0xE0E0, + + /// + /// The boxed, outlined number 1 icon unicode character. + /// + BoxedOutlinedNumber1 = 0xE0E1, + + /// + /// The boxed, outlined number 2 icon unicode character. + /// + BoxedOutlinedNumber2 = 0xE0E2, + + /// + /// The boxed, outlined number 3 icon unicode character. + /// + BoxedOutlinedNumber3 = 0xE0E3, + + /// + /// The boxed, outlined number 4 icon unicode character. + /// + BoxedOutlinedNumber4 = 0xE0E4, + + /// + /// The boxed, outlined number 5 icon unicode character. + /// + BoxedOutlinedNumber5 = 0xE0E5, + + /// + /// The boxed, outlined number 6 icon unicode character. + /// + BoxedOutlinedNumber6 = 0xE0E6, + + /// + /// The boxed, outlined number 7 icon unicode character. + /// + BoxedOutlinedNumber7 = 0xE0E7, + + /// + /// The boxed, outlined number 8 icon unicode character. + /// + BoxedOutlinedNumber8 = 0xE0E8, + + /// + /// The boxed, outlined number 9 icon unicode character. + /// + BoxedOutlinedNumber9 = 0xE0E9, } diff --git a/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs b/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs index 2449cab1c..7678b395e 100644 --- a/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs +++ b/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs @@ -43,6 +43,7 @@ internal class DataWindow : Window, IDisposable new HookWidget(), new IconBrowserWidget(), new ImGuiWidget(), + new InventoryWidget(), new KeyStateWidget(), new MarketBoardWidget(), new NetworkMonitorWidget(), diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/InventoryWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/InventoryWidget.cs new file mode 100644 index 000000000..ac576da77 --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/InventoryWidget.cs @@ -0,0 +1,405 @@ +using System.Buffers.Binary; +using System.Numerics; +using System.Text; + +using Dalamud.Data; +using Dalamud.Game.Inventory; +using Dalamud.Game.Text; +using Dalamud.Interface.Textures; +using Dalamud.Interface.Textures.Internal; +using Dalamud.Interface.Utility; +using Dalamud.Interface.Utility.Raii; + +using FFXIVClientStructs.FFXIV.Client.Game; + +using ImGuiNET; + +using Lumina.Excel.Sheets; + +namespace Dalamud.Interface.Internal.Windows.Data.Widgets; + +#pragma warning disable SeStringRenderer + +/// +/// Widget for displaying inventory data. +/// +internal class InventoryWidget : IDataWindowWidget +{ + private DataManager dataManager; + private TextureManager textureManager; + private InventoryType? selectedInventoryType = InventoryType.Inventory1; + + /// + public string[]? CommandShortcuts { get; init; } = ["inv", "inventory"]; + + /// + public string DisplayName { get; init; } = "Inventory"; + + /// + public bool Ready { get; set; } + + /// + public void Load() + { + this.Ready = true; + } + + /// + public void Draw() + { + this.dataManager ??= Service.Get(); + this.textureManager ??= Service.Get(); + + this.DrawInventoryTypeList(); + + if (this.selectedInventoryType == null) + return; + + ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.X); + + this.DrawInventoryType((InventoryType)this.selectedInventoryType); + } + + private static string StripSoftHypen(string input) + { + return input.Replace("\u00AD", string.Empty); + } + + private unsafe void DrawInventoryTypeList() + { + using var table = ImRaii.Table("InventoryTypeTable", 2, ImGuiTableFlags.RowBg | ImGuiTableFlags.Borders | ImGuiTableFlags.ScrollY | ImGuiTableFlags.NoSavedSettings, new Vector2(300, -1)); + if (!table) return; + + ImGui.TableSetupColumn("Type"); + ImGui.TableSetupColumn("Size", ImGuiTableColumnFlags.WidthFixed, 40); + ImGui.TableSetupScrollFreeze(2, 1); + ImGui.TableHeadersRow(); + + foreach (var inventoryType in Enum.GetValues()) + { + var items = GameInventoryItem.GetReadOnlySpanOfInventory((GameInventoryType)inventoryType); + + using var itemDisabled = ImRaii.Disabled(items.IsEmpty); + + ImGui.TableNextRow(); + ImGui.TableNextColumn(); // Type + if (ImGui.Selectable(inventoryType.ToString(), this.selectedInventoryType == inventoryType, ImGuiSelectableFlags.SpanAllColumns)) + { + this.selectedInventoryType = inventoryType; + } + + using (var contextMenu = ImRaii.ContextPopupItem($"##InventoryContext{inventoryType}")) + { + if (contextMenu) + { + if (ImGui.MenuItem("Copy Name")) + { + ImGui.SetClipboardText(inventoryType.ToString()); + } + + if (ImGui.MenuItem("Copy Address")) + { + var container = InventoryManager.Instance()->GetInventoryContainer(inventoryType); + ImGui.SetClipboardText($"0x{(nint)container:X}"); + } + } + } + + ImGui.TableNextColumn(); // Size + ImGui.TextUnformatted(items.Length.ToString()); + } + } + + private unsafe void DrawInventoryType(InventoryType inventoryType) + { + var items = GameInventoryItem.GetReadOnlySpanOfInventory((GameInventoryType)inventoryType); + if (items.IsEmpty) + { + ImGui.TextUnformatted($"{inventoryType} is empty."); + return; + } + + using var itemTable = ImRaii.Table("InventoryItemTable", 4, ImGuiTableFlags.RowBg | ImGuiTableFlags.Borders | ImGuiTableFlags.ScrollY | ImGuiTableFlags.NoSavedSettings); + if (!itemTable) return; + ImGui.TableSetupColumn("Slot", ImGuiTableColumnFlags.WidthFixed, 40); + ImGui.TableSetupColumn("ItemId", ImGuiTableColumnFlags.WidthFixed, 70); + ImGui.TableSetupColumn("Quantity", ImGuiTableColumnFlags.WidthFixed, 70); + ImGui.TableSetupColumn("Item"); + ImGui.TableSetupScrollFreeze(0, 1); + ImGui.TableHeadersRow(); + + for (var slotIndex = 0; slotIndex < items.Length; slotIndex++) + { + var item = items[slotIndex]; + + using var disableditem = ImRaii.Disabled(item.ItemId == 0); + + ImGui.TableNextRow(); + ImGui.TableNextColumn(); // Slot + ImGui.TextUnformatted(slotIndex.ToString()); + + ImGui.TableNextColumn(); // ItemId + ImGuiHelpers.ClickToCopyText(item.ItemId.ToString()); + + ImGui.TableNextColumn(); // Quantity + ImGuiHelpers.ClickToCopyText(item.Quantity.ToString()); + + ImGui.TableNextColumn(); // Item + if (item.ItemId != 0 && item.Quantity != 0) + { + var itemName = this.GetItemName(item.ItemId); + var iconId = this.GetItemIconId(item.ItemId); + + if (item.IsHq) + itemName += " " + SeIconChar.HighQuality.ToIconString(); + + if (this.textureManager.Shared.TryGetFromGameIcon(new GameIconLookup(iconId, item.IsHq), out var tex) && tex.TryGetWrap(out var texture, out _)) + { + ImGui.Image(texture.ImGuiHandle, new Vector2(ImGui.GetTextLineHeight())); + + if (ImGui.IsItemHovered()) + { + ImGui.SetMouseCursor(ImGuiMouseCursor.Hand); + ImGui.BeginTooltip(); + ImGui.TextUnformatted("Click to copy IconId"); + ImGui.TextUnformatted($"ID: {iconId} – Size: {texture.Width}x{texture.Height}"); + ImGui.Image(texture.ImGuiHandle, new(texture.Width, texture.Height)); + ImGui.EndTooltip(); + } + + if (ImGui.IsItemClicked()) + ImGui.SetClipboardText(iconId.ToString()); + } + + ImGui.SameLine(); + + using var itemNameColor = ImRaii.PushColor(ImGuiCol.Text, this.GetItemRarityColor(item.ItemId)); + using var node = ImRaii.TreeNode($"{itemName}###{inventoryType}_{slotIndex}", ImGuiTreeNodeFlags.SpanAvailWidth); + itemNameColor.Dispose(); + + using (var contextMenu = ImRaii.ContextPopupItem($"{inventoryType}_{slotIndex}_ContextMenu")) + { + if (contextMenu) + { + if (ImGui.MenuItem("Copy Name")) + { + ImGui.SetClipboardText(itemName); + } + } + } + + if (!node) continue; + + using var itemInfoTable = ImRaii.Table($"{inventoryType}_{slotIndex}_Table", 2, ImGuiTableFlags.BordersInner | ImGuiTableFlags.NoSavedSettings); + if (!itemInfoTable) continue; + + ImGui.TableSetupColumn("Name", ImGuiTableColumnFlags.WidthFixed, 150); + ImGui.TableSetupColumn("Value"); + // ImGui.TableHeadersRow(); + + static void AddKeyValueRow(string fieldName, string value) + { + ImGui.TableNextRow(); + ImGui.TableNextColumn(); + ImGui.TextUnformatted(fieldName); + ImGui.TableNextColumn(); + ImGuiHelpers.ClickToCopyText(value); + } + + static void AddValueValueRow(string value1, string value2) + { + ImGui.TableNextRow(); + ImGui.TableNextColumn(); + ImGuiHelpers.ClickToCopyText(value1); + ImGui.TableNextColumn(); + ImGuiHelpers.ClickToCopyText(value2); + } + + AddKeyValueRow("ItemId", item.ItemId.ToString()); + AddKeyValueRow("Quantity", item.Quantity.ToString()); + AddKeyValueRow("GlamourId", item.GlamourId.ToString()); + + if (!this.IsEventItem(item.ItemId)) + { + AddKeyValueRow(item.IsCollectable ? "Collectability" : "Spiritbond", item.Spiritbond.ToString()); + + if (item.CrafterContentId != 0) + AddKeyValueRow("CrafterContentId", item.CrafterContentId.ToString()); + } + + var flagsBuilder = new StringBuilder(); + + if (item.IsHq) + { + flagsBuilder.Append("IsHq"); + } + + if (item.IsCompanyCrestApplied) + { + if (flagsBuilder.Length != 0) + flagsBuilder.Append(", "); + + flagsBuilder.Append("IsCompanyCrestApplied"); + } + + if (item.IsRelic) + { + if (flagsBuilder.Length != 0) + flagsBuilder.Append(", "); + + flagsBuilder.Append("IsRelic"); + } + + if (item.IsCollectable) + { + if (flagsBuilder.Length != 0) + flagsBuilder.Append(", "); + + flagsBuilder.Append("IsCollectable"); + } + + if (flagsBuilder.Length == 0) + flagsBuilder.Append("None"); + + AddKeyValueRow("Flags", flagsBuilder.ToString()); + + if (this.IsNormalItem(item.ItemId) && this.dataManager.Excel.GetSheet().TryGetRow(item.ItemId, out var itemRow)) + { + if (itemRow.DyeCount > 0) + { + ImGui.TableNextRow(); + ImGui.TableNextColumn(); + ImGui.TextUnformatted("Stains"); + ImGui.TableNextColumn(); + + using var stainTable = ImRaii.Table($"{inventoryType}_{slotIndex}_StainTable", 2, ImGuiTableFlags.BordersInner | ImGuiTableFlags.NoSavedSettings); + if (!stainTable) continue; + + ImGui.TableSetupColumn("Stain Id", ImGuiTableColumnFlags.WidthFixed, 80); + ImGui.TableSetupColumn("Name"); + ImGui.TableHeadersRow(); + + for (var i = 0; i < itemRow.DyeCount; i++) + { + AddValueValueRow(item.Stains[i].ToString(), this.GetStainName(item.Stains[i])); + } + } + + if (itemRow.MateriaSlotCount > 0) + { + ImGui.TableNextRow(); + ImGui.TableNextColumn(); + ImGui.TextUnformatted("Materia"); + ImGui.TableNextColumn(); + + using var materiaTable = ImRaii.Table($"{inventoryType}_{slotIndex}_MateriaTable", 2, ImGuiTableFlags.BordersInner | ImGuiTableFlags.NoSavedSettings); + if (!materiaTable) continue; + + ImGui.TableSetupColumn("Materia Id", ImGuiTableColumnFlags.WidthFixed, 80); + ImGui.TableSetupColumn("MateriaGrade Id"); + ImGui.TableHeadersRow(); + + for (var i = 0; i < Math.Min(itemRow.MateriaSlotCount, item.Materia.Length); i++) + { + AddValueValueRow(item.Materia[i].ToString(), item.MateriaGrade[i].ToString()); + } + } + } + } + } + } + + private bool IsEventItem(uint itemId) => itemId is > 2_000_000; + + private bool IsHighQuality(uint itemId) => itemId is > 1_000_000 and < 2_000_000; + + private bool IsCollectible(uint itemId) => itemId is > 500_000 and < 1_000_000; + + private bool IsNormalItem(uint itemId) => itemId is < 500_000; + + private uint GetBaseItemId(uint itemId) + { + if (this.IsEventItem(itemId)) return itemId; // uses EventItem sheet + if (this.IsHighQuality(itemId)) return itemId - 1_000_000; + if (this.IsCollectible(itemId)) return itemId - 500_000; + return itemId; + } + + private string GetItemName(uint itemId) + { + // EventItem + if (this.IsEventItem(itemId)) + { + return this.dataManager.Excel.GetSheet().TryGetRow(itemId, out var eventItemRow) + ? StripSoftHypen(eventItemRow.Name.ExtractText()) + : $"EventItem#{itemId}"; + } + + // HighQuality + if (this.IsHighQuality(itemId)) + itemId -= 1_000_000; + + // Collectible + if (this.IsCollectible(itemId)) + itemId -= 500_000; + + return this.dataManager.Excel.GetSheet().TryGetRow(itemId, out var itemRow) + ? StripSoftHypen(itemRow.Name.ExtractText()) + : $"Item#{itemId}"; + } + + private string GetStainName(uint stainId) + { + return this.dataManager.Excel.GetSheet().TryGetRow(stainId, out var stainRow) + ? StripSoftHypen(stainRow.Name.ExtractText()) + : $"Stain#{stainId}"; + } + + private uint GetItemRarityColorType(Item item, bool isEdgeColor = false) + { + return (isEdgeColor ? 548u : 547u) + item.Rarity * 2u; + } + + private uint GetItemRarityColorType(uint itemId, bool isEdgeColor = false) + { + // EventItem + if (this.IsEventItem(itemId)) + return this.GetItemRarityColorType(1, isEdgeColor); + + if (!this.dataManager.Excel.GetSheet().TryGetRow(this.GetBaseItemId(itemId), out var item)) + return this.GetItemRarityColorType(1, isEdgeColor); + + return this.GetItemRarityColorType(item, isEdgeColor); + } + + private uint GetItemRarityColor(uint itemId, bool isEdgeColor = false) + { + if (this.IsEventItem(itemId)) + return isEdgeColor ? 0xFF000000 : 0xFFFFFFFF; + + if (!this.dataManager.Excel.GetSheet().TryGetRow(this.GetBaseItemId(itemId), out var item)) + return isEdgeColor ? 0xFF000000 : 0xFFFFFFFF; + + var rowId = this.GetItemRarityColorType(item, isEdgeColor); + return this.dataManager.Excel.GetSheet().TryGetRow(rowId, out var color) + ? BinaryPrimitives.ReverseEndianness(color.UIForeground) | 0xFF000000 + : 0xFFFFFFFF; + } + + private uint GetItemIconId(uint itemId) + { + // EventItem + if (this.IsEventItem(itemId)) + return this.dataManager.Excel.GetSheet().TryGetRow(itemId, out var eventItem) ? eventItem.Icon : 0u; + + // HighQuality + if (this.IsHighQuality(itemId)) + itemId -= 1_000_000; + + // Collectible + if (this.IsCollectible(itemId)) + itemId -= 500_000; + + return this.dataManager.Excel.GetSheet().TryGetRow(itemId, out var item) ? item.Icon : 0u; + } +} diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/SeFontTestWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/SeFontTestWidget.cs index b59abbff1..69282a8e8 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/SeFontTestWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/SeFontTestWidget.cs @@ -1,6 +1,8 @@ using Dalamud.Game.Text; using ImGuiNET; +using System.Linq; + namespace Dalamud.Interface.Internal.Windows.Data.Widgets; /// @@ -28,8 +30,11 @@ internal class SeFontTestWidget : IDataWindowWidget { var specialChars = string.Empty; - for (var i = 0xE020; i <= 0xE0DB; i++) - specialChars += $"0x{i:X} - {(SeIconChar)i} - {(char)i}\n"; + var min = (char)Enum.GetValues().Min(); + var max = (char)Enum.GetValues().Max(); + + for (var i = min; i <= max; i++) + specialChars += $"0x{(int)i:X} - {(SeIconChar)i} - {i}\n"; ImGui.TextUnformatted(specialChars); } diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs index fca10adca..33a98af53 160000 --- a/lib/FFXIVClientStructs +++ b/lib/FFXIVClientStructs @@ -1 +1 @@ -Subproject commit fca10adcab3911c1be79cb0753987a2a02b7e058 +Subproject commit 33a98af530e52d5b54714ec9f7704c07bf9fdd91