From 7e34f8c00cefb1e4f22faf00d315f4429308a81d Mon Sep 17 00:00:00 2001 From: goaaats <16760685+goaaats@users.noreply.github.com> Date: Wed, 19 Jan 2022 00:41:36 +0100 Subject: [PATCH] fix(ItemPayload): correctly handle EventItem, Collectible (closes #166) --- .../SeStringHandling/Payloads/ItemPayload.cs | 99 ++++++++++++++++--- 1 file changed, 85 insertions(+), 14 deletions(-) diff --git a/Dalamud/Game/Text/SeStringHandling/Payloads/ItemPayload.cs b/Dalamud/Game/Text/SeStringHandling/Payloads/ItemPayload.cs index fff92cadd..d7404506b 100644 --- a/Dalamud/Game/Text/SeStringHandling/Payloads/ItemPayload.cs +++ b/Dalamud/Game/Text/SeStringHandling/Payloads/ItemPayload.cs @@ -13,13 +13,13 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads /// public class ItemPayload : Payload { - private Item item; + private Item? item; // mainly to allow overriding the name (for things like owo) // TODO: even though this is present in some item links, it may not really have a use at all // For things like owo, changing the text payload is probably correct, whereas changing the // actual embedded name might not work properly. - private string? displayName = null; + private string? displayName; [JsonProperty] private uint itemId; @@ -36,7 +36,23 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads public ItemPayload(uint itemId, bool isHq, string? displayNameOverride = null) { this.itemId = itemId; - this.IsHQ = isHq; + this.Kind = isHq ? ItemKind.Hq : ItemKind.Normal; + this.displayName = displayNameOverride; + } + + /// + /// Initializes a new instance of the class. + /// Creates a payload representing an interactable item link for the specified item. + /// + /// The id of the item. + /// Kind of item to encode. + /// An optional name to include in the item link. Typically this should + /// be left as null, or set to the normal item name. Actual overrides are better done with the subsequent + /// TextPayload that is a part of a full item link in chat. + public ItemPayload(uint itemId, ItemKind kind = ItemKind.Normal, string? displayNameOverride = null) + { + this.itemId = itemId; + this.Kind = kind; this.displayName = displayNameOverride; } @@ -48,6 +64,32 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads { } + /// + /// Kinds of items that can be fetched from this payload. + /// + public enum ItemKind : uint + { + /// + /// Normal items. + /// + Normal, + + /// + /// Collectible Items. + /// + Collectible = 500_000, + + /// + /// High-Quality items. + /// + Hq = 1_000_000, + + /// + /// Event/Key items. + /// + EventItem = 2_000_000, + } + /// public override PayloadType Type => PayloadType.Item; @@ -55,7 +97,7 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads /// Gets or sets the displayed name for this item link. Note that incoming links only sometimes have names embedded, /// often the name is only present in a following text payload. /// - public string DisplayName + public string? DisplayName { get { @@ -82,24 +124,45 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads /// The value is evaluated lazily and cached. /// [JsonIgnore] - public Item Item => this.item ??= this.DataResolver.GetExcelSheet().GetRow(this.itemId); + public Item? Item => this.item ??= this.DataResolver.GetExcelSheet()!.GetRow(this.itemId); /// /// Gets a value indicating whether or not this item link is for a high-quality version of the item. /// [JsonProperty] - public bool IsHQ { get; private set; } = false; + public bool IsHQ => this.Kind == ItemKind.Hq; + + /// + /// Gets or sets the kind of item represented by this payload. + /// + public ItemKind Kind { get; set; } = ItemKind.Normal; + + /// + /// Initializes a new instance of the class. + /// Creates a payload representing an interactable item link for the specified item. + /// + /// The raw, unadjusted id of the item. + /// An optional name to include in the item link. Typically this should + /// be left as null, or set to the normal item name. Actual overrides are better done with the subsequent + /// TextPayload that is a part of a full item link in chat. + /// The created item payload. + public static ItemPayload FromRaw(uint rawItemId, string? displayNameOverride = null) + { + var (id, kind) = GetAdjustedId(rawItemId); + return new ItemPayload(id, kind, displayNameOverride); + } /// public override string ToString() { - return $"{this.Type} - ItemId: {this.itemId}, IsHQ: {this.IsHQ}, Name: {this.displayName ?? this.Item.Name}"; + return $"{this.Type} - ItemId: {this.itemId}, Kind: {this.Kind}, Name: {this.displayName ?? this.Item?.Name}"; } /// protected override byte[] EncodeImpl() { - var actualItemId = this.IsHQ ? this.itemId + 1000000 : this.itemId; + var actualItemId = this.itemId - (uint)this.Kind; + var idBytes = MakeInteger(actualItemId); var hasName = !string.IsNullOrEmpty(this.displayName); @@ -154,13 +217,10 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads /// protected override void DecodeImpl(BinaryReader reader, long endOfStream) { - this.itemId = GetInteger(reader); + var (id, kind) = GetAdjustedId(GetInteger(reader)); - if (this.itemId > 1000000) - { - this.itemId -= 1000000; - this.IsHQ = true; - } + this.itemId = id; + this.Kind = kind; if (reader.BaseStream.Position + 3 < endOfStream) { @@ -185,5 +245,16 @@ namespace Dalamud.Game.Text.SeStringHandling.Payloads this.displayName = Encoding.UTF8.GetString(itemNameBytes); } } + + private static (uint ItemId, ItemKind Kind) GetAdjustedId(uint rawItemId) + { + return rawItemId switch + { + > 500_000 and < 1_000_000 => (rawItemId - 500_000, ItemKind.Collectible), + > 1_000_000 and < 2_000_000 => (rawItemId - 1_000_000, ItemKind.Hq), + > 2_000_000 => (rawItemId - 2_000_000, ItemKind.EventItem), + _ => (rawItemId, ItemKind.Normal), + }; + } } }