feat: add custom dalamud link payload handling

This commit is contained in:
Anna 2022-01-03 16:41:02 -05:00
parent 58efbf5b59
commit 8ce62fa24e
6 changed files with 51 additions and 21 deletions

View File

@ -4,9 +4,11 @@ using Dalamud.Game.Text.SeStringHandling;
namespace ChatTwo;
internal abstract class Chunk {
internal SeString? Source { get; set; }
internal Payload? Link { get; set; }
protected Chunk(Payload? link) {
protected Chunk(SeString? source, Payload? link) {
this.Source = source;
this.Link = link;
}
}
@ -18,11 +20,11 @@ internal class TextChunk : Chunk {
internal bool Italic { 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;
}
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.Foreground = foreground;
this.Glow = glow;
@ -34,7 +36,7 @@ internal class TextChunk : Chunk {
internal class IconChunk : Chunk {
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;
}
}

View File

@ -1,4 +1,5 @@
using System.Numerics;
using System.Reflection;
using ChatTwo.Ui;
using ChatTwo.Util;
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}");
switch (button) {
case ImGuiMouseButton.Left:
this.LeftClickPayload(payload);
this.LeftClickPayload(chunk, payload);
break;
case ImGuiMouseButton.Right:
this.RightClickPayload(payload);
@ -145,7 +146,7 @@ internal sealed class PayloadHandler {
this.Log.DrawChunks(desc.ToList());
}
private void LeftClickPayload(Payload payload) {
private void LeftClickPayload(Chunk chunk, Payload payload) {
switch (payload) {
case MapLinkPayload map: {
this.Ui.Plugin.GameGui.OpenMapWithMapLink(map);
@ -156,11 +157,38 @@ internal sealed class PayloadHandler {
break;
}
case DalamudLinkPayload link: {
this.ClickLinkPayload(chunk, payload, link);
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) {
switch (payload) {
case PlayerPayload player: {

View File

@ -86,11 +86,11 @@ internal class Store : IDisposable {
var senderChunks = new List<Chunk>();
if (formatting is { IsPresent: true }) {
senderChunks.Add(new TextChunk(null, formatting.Before) {
senderChunks.Add(new TextChunk(null, null, formatting.Before) {
FallbackColour = 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,
});
}

View File

@ -94,7 +94,7 @@ internal sealed class ChatLog : IUiComponent {
if (tab.DisplayTimestamp) {
var timestamp = message.Date.ToLocalTime().ToString("t");
this.DrawChunk(new TextChunk(null, $"[{timestamp}]") {
this.DrawChunk(new TextChunk(null, null, $"[{timestamp}]") {
Foreground = 0xFFFFFFFF,
});
ImGui.SameLine();
@ -298,7 +298,7 @@ internal sealed class ChatLog : IUiComponent {
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;
ImGui.Image(this._fontIcon.ImGuiHandle, size, uv0, uv1);
ImGuiUtil.PostPayload(chunk.Link, handler);
ImGuiUtil.PostPayload(chunk, handler);
}
return;
@ -325,7 +325,7 @@ internal sealed class ChatLog : IUiComponent {
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) {
ImGui.PopFont();

View File

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

View File

@ -1,5 +1,4 @@
using System.Text;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Interface;
using ImGuiNET;
@ -12,7 +11,8 @@ internal static class ImGuiUtil {
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()) {
ImGui.SetMouseCursor(ImGuiMouseCursor.Hand);
handler?.Hover(payload);
@ -24,15 +24,15 @@ internal static class ImGuiUtil {
foreach (var button in Buttons) {
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) {
ImGuiNative.igTextUnformatted(text, textEnd);
PostPayload(payload, handler);
PostPayload(chunk, handler);
}
if (csText.Length == 0) {