diff --git a/HellionChat/PayloadHandler.cs b/HellionChat/PayloadHandler.cs index 21eb304..2aa27c5 100644 --- a/HellionChat/PayloadHandler.cs +++ b/HellionChat/PayloadHandler.cs @@ -11,6 +11,7 @@ using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using Dalamud.Utility; +using FFXIVClientStructs.FFXIV.Client.UI; using HellionChat.Code; using HellionChat.Resources; using HellionChat.Themes; @@ -19,6 +20,9 @@ using HellionChat.Ui.Windows; using HellionChat.Util; using Lumina.Excel.Sheets; using Microsoft.Extensions.Logging; +using Action = System.Action; +using ChatTwoPartyFinderPayload = HellionChat.Util.PartyFinderPayload; +using DalamudPartyFinderPayload = Dalamud.Game.Text.SeStringHandling.Payloads.PartyFinderPayload; namespace HellionChat; @@ -580,7 +584,251 @@ internal sealed class PayloadHandler ); } - internal void Hover(Payload payload) { } + internal void Hover(Payload payload) + { + var hoverSize = 350f * ImGuiHelpers.GlobalScale; - internal unsafe void Click(Chunk chunk, Payload? payload, ImGuiMouseButton button) { } + switch (payload) + { + case StatusPayload status: + DoHover(() => HoverStatus(status), hoverSize); + break; + case ItemPayload item: + if (Plugin.Config.NativeItemTooltips) + { + if (!HandleTooltips || HoveredItem != item.RawItemId) + { + HandleTooltips = true; + HoveredItem = item.RawItemId; + HoverCounter = LastHoverCounter = 0; + + GameFunctions.GameFunctions.OpenItemTooltip(item.RawItemId, item.Kind); + } + else + { + LastHoverCounter = HoverCounter; + } + + return; + } + + DoHover(() => HoverItem(item), hoverSize); + break; + case UriPayload uri: + DoHover(() => HoverUri(uri), hoverSize); + break; + } + } + + private void DoHover(Action drawAction, float spacingHorizontal) + { + ImGui.SetNextWindowSize(new Vector2(spacingHorizontal, -1f)); + + using (ImRaii.Tooltip()) + using (ImRaii.TextWrapPos(0.0f)) + using ( + ImRaii.PushColor( + ImGuiCol.Text, + ColourUtil.RgbaToVector4(_themes.Active.Colors.TextPrimary) + ) + ) + drawAction(); + } + + private void HoverStatus(StatusPayload status) + { + if ( + Plugin.TextureProvider.GetFromGameIcon(status.Status.Value.Icon).GetWrapOrDefault() is + { } icon + ) + InlineIcon(icon); + + var builder = new SeStringBuilder(); + var nameValue = status.Status.Value.Name.ToString(); + switch (status.Status.Value.StatusCategory) + { + case 1: + builder.AddUiForeground($"{SeIconChar.Buff.ToIconString()}{nameValue}", 517); + break; + case 2: + builder.AddUiForeground($"{SeIconChar.Debuff.ToIconString()}{nameValue}", 518); + break; + default: + builder.AddUiForeground(nameValue, 1); + break; + } + + var name = ChunkUtil.ToChunks(builder.BuiltString, ChunkSource.None, null); + _chunkRenderer.DrawChunks(name.ToList()); + ImGui.Separator(); + + var desc = ChunkUtil.ToChunks( + status.Status.Value.Description.ToDalamudString(), + ChunkSource.None, + null + ); + _chunkRenderer.DrawChunks(desc.ToList()); + } + + private void HoverItem(ItemPayload item) + { + if (item.Kind == ItemKind.EventItem) + { + HoverEventItem(item); + return; + } + + if (!Sheets.ItemSheet.TryGetRow(item.ItemId, out var resolvedItem)) + return; + + if ( + Plugin + .TextureProvider.GetFromGameIcon( + new GameIconLookup(resolvedItem.Icon, item.Kind == ItemKind.Hq) + ) + .GetWrapOrDefault() is + { } icon + ) + InlineIcon(icon); + + var name = ChunkUtil.ToChunks(resolvedItem.Name.ToDalamudString(), ChunkSource.None, null); + _chunkRenderer.DrawChunks(name.ToList()); + ImGui.Separator(); + + var desc = ChunkUtil.ToChunks( + resolvedItem.Description.ToDalamudString(), + ChunkSource.None, + null + ); + _chunkRenderer.DrawChunks(desc.ToList()); + } + + private void HoverEventItem(ItemPayload item) + { + if (!Sheets.EventItemSheet.TryGetRow(item.RawItemId, out var itemRow)) + return; + + if ( + Plugin + .TextureProvider.GetFromGameIcon(new GameIconLookup(itemRow.Icon)) + .GetWrapOrDefault() is + { } icon + ) + InlineIcon(icon); + + var name = ChunkUtil.ToChunks(itemRow.Name.ToDalamudString(), ChunkSource.None, null); + _chunkRenderer.DrawChunks(name.ToList()); + ImGui.Separator(); + + if (!Sheets.EventItemHelpSheet.TryGetRow(item.RawItemId, out var itemHelpRow)) + return; + + _chunkRenderer.DrawChunks( + ChunkUtil + .ToChunks(itemHelpRow.Description.ToDalamudString(), ChunkSource.None, null) + .ToList() + ); + } + + private void HoverUri(UriPayload uri) + { + ImGui.TextUnformatted(string.Format(Language.Context_URLDomain, uri.Uri.Authority)); + ImGuiUtil.WarningText(Language.Context_URLWarning); + } + + internal unsafe void Click(Chunk chunk, Payload? payload, ImGuiMouseButton button) + { + if (Plugin.Config.PlaySounds) + UIGlobals.PlaySoundEffect(PopupSfx); + + switch (button) + { + case ImGuiMouseButton.Left: + LeftClickPayload(chunk, payload); + break; + case ImGuiMouseButton.Right: + RightClickPayload(chunk, payload); + break; + } + } + + private unsafe void LeftClickPayload(Chunk chunk, Payload? payload) + { + switch (payload) + { + case MapLinkPayload map: + Plugin.GameGui.OpenMapWithMapLink(map); + break; + case QuestPayload quest: + GameFunctions.GameFunctions.OpenQuestLog(quest.Quest); + break; + case DalamudLinkPayload link: + ClickLinkPayload(chunk, payload, link); + break; + case DalamudPartyFinderPayload pf: + if ( + pf.LinkType + == DalamudPartyFinderPayload.PartyFinderLinkType.PartyFinderNotification + ) + GameFunctions.GameFunctions.OpenPartyFinder(); + else + GameFunctions.GameFunctions.OpenPartyFinder(pf.ListingId); + break; + case ChatTwoPartyFinderPayload pf: + GameFunctions.GameFunctions.OpenPartyFinder(pf.Id); + break; + case AchievementPayload achievement: + GameFunctions.GameFunctions.OpenAchievement(achievement.Id); + break; + case RawPayload raw: + if (Equals(raw, ChunkUtil.PeriodicRecruitmentLink)) + GameFunctions.GameFunctions.OpenPartyFinder(); + break; + case UriPayload uri: + WrapperUtil.TryOpenUri(uri.Uri); + break; + default: + RightClickPayload(chunk, payload); + break; + } + } + + private void ClickLinkPayload(Chunk chunk, Payload payload, DalamudLinkPayload link) + { + if (chunk.GetSeString() is not { } source) + return; + + var start = source.Payloads.IndexOf(payload); + var end = source.Payloads.IndexOf(RawPayload.LinkTerminator, start == -1 ? 0 : start); + if (start == -1 || end == -1) + return; + + var payloads = source.Payloads.Skip(start).Take(end - start + 1).ToList(); + if ( + !Plugin.ChatGui.RegisteredLinkHandlers.TryGetValue( + (link.Plugin, link.CommandId), + out var value + ) + ) + { + _logger.LogWarning("Could not find DalamudLinkHandlers"); + return; + } + + try + { + // Running XivCommon SendChat instantly, without RunOnTick, leads to a game freeze, for whatever reason + Plugin.Framework.RunOnTick(() => value.Invoke(link.CommandId, new SeString(payloads))); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error executing DalamudLinkPayload handler"); + } + } + + private void RightClickPayload(Chunk chunk, Payload? payload) + { + _popup = (chunk, payload); + ImGui.OpenPopup(PopupId); + } }