feat: add custom dalamud link payload handling

This commit is contained in:
Anna 2022-01-03 16:41:02 -05:00
parent 24034dcc99
commit 60ca21cacf
Signed by: anna
GPG Key ID: 0B391D8F06FCD9E0
6 changed files with 51 additions and 21 deletions

View File

@ -4,9 +4,11 @@ using Dalamud.Game.Text.SeStringHandling;
namespace ChatTwo; namespace ChatTwo;
internal abstract class Chunk { internal abstract class Chunk {
internal SeString? Source { get; set; }
internal Payload? Link { get; set; } internal Payload? Link { get; set; }
protected Chunk(Payload? link) { protected Chunk(SeString? source, Payload? link) {
this.Source = source;
this.Link = link; this.Link = link;
} }
} }
@ -18,11 +20,11 @@ internal class TextChunk : Chunk {
internal bool Italic { get; set; } internal bool Italic { get; set; }
internal string Content { get; set; } internal string Content { get; set; }
internal TextChunk(Payload? link, string content) : base(link) { internal TextChunk(SeString? source, Payload? link, string content) : base(source, link) {
this.Content = content; this.Content = content;
} }
internal TextChunk(Payload? link, ChatType? fallbackColour, uint? foreground, uint? glow, bool italic, string content) : base(link) { internal TextChunk(SeString? source, Payload? link, ChatType? fallbackColour, uint? foreground, uint? glow, bool italic, string content) : base(source, link) {
this.FallbackColour = fallbackColour; this.FallbackColour = fallbackColour;
this.Foreground = foreground; this.Foreground = foreground;
this.Glow = glow; this.Glow = glow;
@ -34,7 +36,7 @@ internal class TextChunk : Chunk {
internal class IconChunk : Chunk { internal class IconChunk : Chunk {
internal BitmapFontIcon Icon { get; set; } internal BitmapFontIcon Icon { get; set; }
public IconChunk(Payload? link, BitmapFontIcon icon) : base(link) { public IconChunk(SeString? source, Payload? link, BitmapFontIcon icon) : base(source, link) {
this.Icon = icon; this.Icon = icon;
} }
} }

View File

@ -1,4 +1,5 @@
using System.Numerics; using System.Numerics;
using System.Reflection;
using ChatTwo.Ui; using ChatTwo.Ui;
using ChatTwo.Util; using ChatTwo.Util;
using Dalamud.Game.ClientState.Objects.SubKinds; using Dalamud.Game.ClientState.Objects.SubKinds;
@ -54,12 +55,12 @@ internal sealed class PayloadHandler {
} }
} }
internal void Click(Payload payload, ImGuiMouseButton button) { internal void Click(Chunk chunk, Payload payload, ImGuiMouseButton button) {
PluginLog.Log($"clicked {payload} with {button}"); PluginLog.Log($"clicked {payload} with {button}");
switch (button) { switch (button) {
case ImGuiMouseButton.Left: case ImGuiMouseButton.Left:
this.LeftClickPayload(payload); this.LeftClickPayload(chunk, payload);
break; break;
case ImGuiMouseButton.Right: case ImGuiMouseButton.Right:
this.RightClickPayload(payload); this.RightClickPayload(payload);
@ -145,7 +146,7 @@ internal sealed class PayloadHandler {
this.Log.DrawChunks(desc.ToList()); this.Log.DrawChunks(desc.ToList());
} }
private void LeftClickPayload(Payload payload) { private void LeftClickPayload(Chunk chunk, Payload payload) {
switch (payload) { switch (payload) {
case MapLinkPayload map: { case MapLinkPayload map: {
this.Ui.Plugin.GameGui.OpenMapWithMapLink(map); this.Ui.Plugin.GameGui.OpenMapWithMapLink(map);
@ -156,11 +157,38 @@ internal sealed class PayloadHandler {
break; break;
} }
case DalamudLinkPayload link: { case DalamudLinkPayload link: {
this.ClickLinkPayload(chunk, payload, link);
break; break;
} }
} }
} }
private void ClickLinkPayload(Chunk chunk, Payload payload, DalamudLinkPayload link) {
if (chunk.Source is not { } source) {
return;
}
var start = source.Payloads.IndexOf(payload);
var end = source.Payloads.IndexOf(RawPayload.LinkTerminator);
if (start == -1 || end == -1) {
return;
}
var payloads = source.Payloads.Skip(start).Take(end - start + 1).ToList();
var chatGui = this.Ui.Plugin.ChatGui;
var field = chatGui.GetType().GetField("dalamudLinkHandlers", BindingFlags.Instance | BindingFlags.NonPublic);
if (field == null || field.GetValue(chatGui) is not Dictionary<(string PluginName, uint CommandId), Action<uint, SeString>> dict || !dict.TryGetValue((link.Plugin, link.CommandId), out var action)) {
return;
}
try {
action(link.CommandId, new SeString(payloads));
} catch (Exception ex) {
PluginLog.LogError(ex, "Error executing DalamudLinkPayload handler");
}
}
private void RightClickPayload(Payload payload) { private void RightClickPayload(Payload payload) {
switch (payload) { switch (payload) {
case PlayerPayload player: { case PlayerPayload player: {

View File

@ -86,11 +86,11 @@ internal class Store : IDisposable {
var senderChunks = new List<Chunk>(); var senderChunks = new List<Chunk>();
if (formatting is { IsPresent: true }) { if (formatting is { IsPresent: true }) {
senderChunks.Add(new TextChunk(null, formatting.Before) { senderChunks.Add(new TextChunk(null, null, formatting.Before) {
FallbackColour = chatCode.Type, FallbackColour = chatCode.Type,
}); });
senderChunks.AddRange(ChunkUtil.ToChunks(sender, chatCode.Type)); senderChunks.AddRange(ChunkUtil.ToChunks(sender, chatCode.Type));
senderChunks.Add(new TextChunk(null, formatting.After) { senderChunks.Add(new TextChunk(null, null, formatting.After) {
FallbackColour = chatCode.Type, FallbackColour = chatCode.Type,
}); });
} }

View File

@ -94,7 +94,7 @@ internal sealed class ChatLog : IUiComponent {
if (tab.DisplayTimestamp) { if (tab.DisplayTimestamp) {
var timestamp = message.Date.ToLocalTime().ToString("t"); var timestamp = message.Date.ToLocalTime().ToString("t");
this.DrawChunk(new TextChunk(null, $"[{timestamp}]") { this.DrawChunk(new TextChunk(null, null, $"[{timestamp}]") {
Foreground = 0xFFFFFFFF, Foreground = 0xFFFFFFFF,
}); });
ImGui.SameLine(); ImGui.SameLine();
@ -298,7 +298,7 @@ internal sealed class ChatLog : IUiComponent {
var uv0 = new Vector2(bounds.Value.X, bounds.Value.Y - 2) / texSize; var uv0 = new Vector2(bounds.Value.X, bounds.Value.Y - 2) / texSize;
var uv1 = new Vector2(bounds.Value.X + bounds.Value.Z, bounds.Value.Y - 2 + bounds.Value.W) / texSize; var uv1 = new Vector2(bounds.Value.X + bounds.Value.Z, bounds.Value.Y - 2 + bounds.Value.W) / texSize;
ImGui.Image(this._fontIcon.ImGuiHandle, size, uv0, uv1); ImGui.Image(this._fontIcon.ImGuiHandle, size, uv0, uv1);
ImGuiUtil.PostPayload(chunk.Link, handler); ImGuiUtil.PostPayload(chunk, handler);
} }
return; return;
@ -325,7 +325,7 @@ internal sealed class ChatLog : IUiComponent {
ImGui.PushFont(this.Ui.ItalicFont.Value); ImGui.PushFont(this.Ui.ItalicFont.Value);
} }
ImGuiUtil.WrapText(text.Content, chunk.Link, handler); ImGuiUtil.WrapText(text.Content, chunk, handler);
if (text.Italic && this.Ui.ItalicFont.HasValue) { if (text.Italic && this.Ui.ItalicFont.HasValue) {
ImGui.PopFont(); ImGui.PopFont();

View File

@ -14,7 +14,7 @@ internal static class ChunkUtil {
Payload? link = null; Payload? link = null;
void Append(string text) { void Append(string text) {
chunks.Add(new TextChunk(link, text) { chunks.Add(new TextChunk(msg, link, text) {
FallbackColour = defaultColour, FallbackColour = defaultColour,
Foreground = foreground.Count > 0 ? foreground.Peek() : null, Foreground = foreground.Count > 0 ? foreground.Peek() : null,
Glow = glow.Count > 0 ? glow.Peek() : null, Glow = glow.Count > 0 ? glow.Peek() : null,
@ -47,13 +47,13 @@ internal static class ChunkUtil {
break; break;
case PayloadType.AutoTranslateText: case PayloadType.AutoTranslateText:
chunks.Add(new IconChunk(link, BitmapFontIcon.AutoTranslateBegin)); chunks.Add(new IconChunk(msg, link, BitmapFontIcon.AutoTranslateBegin));
var autoText = ((AutoTranslatePayload) payload).Text; var autoText = ((AutoTranslatePayload) payload).Text;
Append(autoText.Substring(2, autoText.Length - 4)); Append(autoText.Substring(2, autoText.Length - 4));
chunks.Add(new IconChunk(link, BitmapFontIcon.AutoTranslateEnd)); chunks.Add(new IconChunk(msg, link, BitmapFontIcon.AutoTranslateEnd));
break; break;
case PayloadType.Icon: case PayloadType.Icon:
chunks.Add(new IconChunk(link, ((IconPayload) payload).Icon)); chunks.Add(new IconChunk(msg, link, ((IconPayload) payload).Icon));
break; break;
case PayloadType.MapLink: case PayloadType.MapLink:
case PayloadType.Quest: case PayloadType.Quest:

View File

@ -1,5 +1,4 @@
using System.Text; using System.Text;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Interface; using Dalamud.Interface;
using ImGuiNET; using ImGuiNET;
@ -12,7 +11,8 @@ internal static class ImGuiUtil {
ImGuiMouseButton.Right, ImGuiMouseButton.Right,
}; };
internal static void PostPayload(Payload? payload, PayloadHandler? handler) { internal static void PostPayload(Chunk chunk, PayloadHandler? handler) {
var payload = chunk.Link;
if (payload != null && ImGui.IsItemHovered()) { if (payload != null && ImGui.IsItemHovered()) {
ImGui.SetMouseCursor(ImGuiMouseCursor.Hand); ImGui.SetMouseCursor(ImGuiMouseCursor.Hand);
handler?.Hover(payload); handler?.Hover(payload);
@ -24,15 +24,15 @@ internal static class ImGuiUtil {
foreach (var button in Buttons) { foreach (var button in Buttons) {
if (ImGui.IsItemClicked(button)) { if (ImGui.IsItemClicked(button)) {
handler.Click(payload, button); handler.Click(chunk, payload, button);
} }
} }
} }
internal static unsafe void WrapText(string csText, Payload? payload, PayloadHandler? handler) { internal static unsafe void WrapText(string csText, Chunk chunk, PayloadHandler? handler) {
void Text(byte* text, byte* textEnd) { void Text(byte* text, byte* textEnd) {
ImGuiNative.igTextUnformatted(text, textEnd); ImGuiNative.igTextUnformatted(text, textEnd);
PostPayload(payload, handler); PostPayload(chunk, handler);
} }
if (csText.Length == 0) { if (csText.Length == 0) {