ChatTwo/ChatTwo/PayloadHandler.cs

469 lines
15 KiB
C#
Raw Normal View History

2021-12-30 02:53:44 +00:00
using System.Numerics;
using System.Reflection;
2022-01-14 18:25:33 +00:00
using ChatTwo.Code;
2021-12-30 02:53:44 +00:00
using ChatTwo.Ui;
using ChatTwo.Util;
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads;
2022-01-15 18:55:43 +00:00
using Dalamud.Interface;
2021-12-30 02:53:44 +00:00
using Dalamud.Logging;
using Dalamud.Utility;
using ImGuiNET;
using ImGuiScene;
2022-02-01 21:46:46 +00:00
using Lumina.Excel.GeneratedSheets;
using Action = System.Action;
2021-12-30 02:53:44 +00:00
namespace ChatTwo;
internal sealed class PayloadHandler {
private const string PopupId = "chat2-context-popup";
2021-12-30 02:53:44 +00:00
private PluginUi Ui { get; }
private ChatLog Log { get; }
private (Chunk, Payload?)? Popup { get; set; }
2021-12-30 02:53:44 +00:00
private bool _handleTooltips;
2021-12-30 02:53:44 +00:00
private uint _hoveredItem;
private uint _hoverCounter;
private uint _lastHoverCounter;
internal PayloadHandler(PluginUi ui, ChatLog log) {
this.Ui = ui;
this.Log = log;
}
internal void Draw() {
this.DrawPopups();
if (this._handleTooltips && ++this._hoverCounter - this._lastHoverCounter > 1) {
GameFunctions.GameFunctions.CloseItemTooltip();
this._hoveredItem = 0;
this._hoverCounter = this._lastHoverCounter = 0;
this._handleTooltips = false;
}
}
private void DrawPopups() {
if (this.Popup == null) {
return;
}
var (chunk, payload) = this.Popup.Value;
if (PopupId == null || !ImGui.BeginPopup(PopupId)) {
this.Popup = null;
return;
}
ImGui.PushID(PopupId);
var drawn = false;
switch (payload) {
case PlayerPayload player: {
this.DrawPlayerPopup(chunk, player);
drawn = true;
break;
}
case ItemPayload item: {
this.DrawItemPopup(item);
drawn = true;
break;
2021-12-30 02:53:44 +00:00
}
}
2021-12-30 02:53:44 +00:00
this.ContextFooter(drawn, chunk);
2021-12-30 02:53:44 +00:00
ImGui.PopID();
ImGui.EndPopup();
}
private void ContextFooter(bool separator, Chunk chunk) {
if (separator) {
ImGui.Separator();
}
if (!ImGui.BeginMenu(this.Ui.Plugin.Name)) {
return;
}
ImGui.Checkbox("Screenshot mode", ref this.Ui.ScreenshotMode);
if (chunk.Message is { } message) {
if (ImGui.BeginMenu("Copy")) {
var text = message.Sender
.Concat(message.Content)
.Where(chunk => chunk is TextChunk)
.Cast<TextChunk>()
.Select(text => text.Content)
.Aggregate(string.Concat);
2022-02-04 10:05:52 +00:00
ImGui.InputTextMultiline(
"##chat2-copy",
ref text,
(uint) text.Length,
2022-02-04 10:10:38 +00:00
new Vector2(350, 100) * ImGuiHelpers.GlobalScale,
2022-02-04 10:05:52 +00:00
ImGuiInputTextFlags.ReadOnly
);
ImGui.EndMenu();
}
2021-12-30 02:53:44 +00:00
var col = ImGui.GetStyle().Colors[(int) ImGuiCol.TextDisabled];
ImGui.PushStyleColor(ImGuiCol.Text, col);
try {
ImGui.TextUnformatted(message.Code.Type.Name());
} finally {
ImGui.PopStyleColor();
}
2021-12-30 02:53:44 +00:00
}
ImGui.EndMenu();
2021-12-30 02:53:44 +00:00
}
internal void Click(Chunk chunk, Payload? payload, ImGuiMouseButton button) {
2021-12-30 02:53:44 +00:00
switch (button) {
case ImGuiMouseButton.Left:
this.LeftClickPayload(chunk, payload);
2021-12-30 02:53:44 +00:00
break;
case ImGuiMouseButton.Right:
2022-01-14 18:25:33 +00:00
this.RightClickPayload(chunk, payload);
2021-12-30 02:53:44 +00:00
break;
}
}
internal void Hover(Payload payload) {
2022-01-15 18:55:43 +00:00
var hoverSize = 250f * ImGuiHelpers.GlobalScale;
2021-12-30 02:53:44 +00:00
switch (payload) {
case StatusPayload status: {
2022-01-15 18:55:43 +00:00
this.DoHover(() => this.HoverStatus(status), hoverSize);
2021-12-30 02:53:44 +00:00
break;
}
case ItemPayload item: {
if (this.Ui.Plugin.Config.NativeItemTooltips) {
2022-02-01 21:46:46 +00:00
GameFunctions.GameFunctions.OpenItemTooltip(item.RawItemId);
2021-12-30 02:53:44 +00:00
this._handleTooltips = true;
2022-02-01 21:46:46 +00:00
if (this._hoveredItem != item.RawItemId) {
this._hoveredItem = item.RawItemId;
2021-12-30 02:53:44 +00:00
this._hoverCounter = this._lastHoverCounter = 0;
} else {
this._lastHoverCounter = this._hoverCounter;
}
break;
}
2022-01-15 18:55:43 +00:00
this.DoHover(() => this.HoverItem(item), hoverSize);
2021-12-30 02:53:44 +00:00
break;
}
}
}
private void DoHover(Action inside, float width) {
ImGui.SetNextWindowSize(new Vector2(width, -1f));
ImGui.BeginTooltip();
ImGui.PushTextWrapPos();
ImGui.PushStyleColor(ImGuiCol.Text, this.Ui.DefaultText);
try {
inside();
} finally {
ImGui.PopStyleColor();
ImGui.PopTextWrapPos();
ImGui.EndTooltip();
}
}
private static void InlineIcon(TextureWrap icon) {
var lineHeight = ImGui.CalcTextSize("A").Y;
2022-01-03 21:20:22 +00:00
var cursor = ImGui.GetCursorPos();
2022-01-15 18:55:43 +00:00
var size = new Vector2(icon.Width, icon.Height) * ImGuiHelpers.GlobalScale;
ImGui.Image(icon.ImGuiHandle, size);
ImGui.SameLine();
2022-01-15 18:55:43 +00:00
ImGui.SetCursorPos(cursor + new Vector2(size.X + 4, size.Y / 2 - lineHeight / 2));
}
2021-12-30 02:53:44 +00:00
private void HoverStatus(StatusPayload status) {
if (this.Ui.Plugin.TextureCache.GetStatus(status.Status) is { } icon) {
InlineIcon(icon);
}
2021-12-30 02:53:44 +00:00
var name = ChunkUtil.ToChunks(status.Status.Name.ToDalamudString(), null);
this.Log.DrawChunks(name.ToList());
ImGui.Separator();
var desc = ChunkUtil.ToChunks(status.Status.Description.ToDalamudString(), null);
this.Log.DrawChunks(desc.ToList());
}
private void HoverItem(ItemPayload item) {
if (item.Item == null) {
return;
}
2022-01-10 05:35:36 +00:00
if (this.Ui.Plugin.TextureCache.GetItem(item.Item, item.IsHQ) is { } icon) {
InlineIcon(icon);
}
2021-12-30 02:53:44 +00:00
var name = ChunkUtil.ToChunks(item.Item.Name.ToDalamudString(), null);
this.Log.DrawChunks(name.ToList());
ImGui.Separator();
var desc = ChunkUtil.ToChunks(item.Item.Description.ToDalamudString(), null);
this.Log.DrawChunks(desc.ToList());
}
private void LeftClickPayload(Chunk chunk, Payload? payload) {
2021-12-30 02:53:44 +00:00
switch (payload) {
case MapLinkPayload map: {
this.Ui.Plugin.GameGui.OpenMapWithMapLink(map);
break;
}
case QuestPayload quest: {
this.Ui.Plugin.Common.Functions.Journal.OpenQuest(quest.Quest);
break;
}
case DalamudLinkPayload link: {
this.ClickLinkPayload(chunk, payload, link);
2021-12-30 02:53:44 +00:00
break;
}
2022-01-16 06:29:44 +00:00
case PartyFinderPayload pf: {
this.Ui.Plugin.Functions.OpenPartyFinder(pf.Id);
break;
}
2022-02-04 00:19:27 +00:00
case AchievementPayload achievement: {
this.Ui.Plugin.Functions.OpenAchievement(achievement.Id);
break;
}
2022-01-11 06:58:32 +00:00
case RawPayload raw: {
if (Equals(raw, ChunkUtil.PeriodicRecruitmentLink)) {
GameFunctions.GameFunctions.OpenPartyFinder();
2022-01-11 06:58:32 +00:00
}
break;
}
2021-12-30 02:53:44 +00:00
}
}
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(Chunk chunk, Payload? payload) {
this.Popup = (chunk, payload);
ImGui.OpenPopup(PopupId);
2021-12-30 02:53:44 +00:00
}
2022-02-01 21:46:46 +00:00
private void DrawItemPopup(ItemPayload payload) {
if (payload.Kind == ItemPayload.ItemKind.EventItem) {
this.DrawEventItemPopup(payload);
return;
}
2022-02-01 21:46:46 +00:00
var item = this.Ui.Plugin.DataManager.GetExcelSheet<Item>()?.GetRow(payload.ItemId);
if (item == null) {
return;
}
var hq = payload.Kind == ItemPayload.ItemKind.Hq;
if (this.Ui.Plugin.TextureCache.GetItem(item, hq) is { } icon) {
InlineIcon(icon);
}
2022-02-01 21:46:46 +00:00
var name = item.Name.ToDalamudString();
if (hq) {
// hq symbol
name.Payloads.Add(new TextPayload(" "));
2022-02-01 21:46:46 +00:00
} else if (payload.Kind == ItemPayload.ItemKind.Collectible) {
name.Payloads.Add(new TextPayload(" "));
}
this.Log.DrawChunks(ChunkUtil.ToChunks(name, null).ToList(), false);
ImGui.Separator();
2022-02-01 21:46:46 +00:00
var realItemId = payload.RawItemId;
2022-02-01 21:46:46 +00:00
if (item.EquipSlotCategory.Row != 0) {
if (ImGui.Selectable("Try On")) {
this.Ui.Plugin.Functions.Context.TryOn(realItemId, 0);
}
if (ImGui.Selectable("Item Comparison")) {
this.Ui.Plugin.Functions.Context.OpenItemComparison(realItemId);
}
}
2022-02-01 21:46:46 +00:00
if (item.ItemSearchCategory.Value?.Category == 3) {
if (ImGui.Selectable("Search Recipes Using This Material")) {
2022-02-01 21:46:46 +00:00
this.Ui.Plugin.Functions.Context.SearchForRecipesUsingItem(payload.ItemId);
}
}
2022-01-11 04:48:36 +00:00
if (ImGui.Selectable("Search for Item")) {
this.Ui.Plugin.Functions.Context.SearchForItem(realItemId);
2022-01-11 04:48:36 +00:00
}
if (ImGui.Selectable("Link")) {
this.Ui.Plugin.Functions.Context.LinkItem(realItemId);
}
if (ImGui.Selectable("Copy Item Name")) {
ImGui.SetClipboardText(name.TextValue);
}
}
2022-02-01 21:46:46 +00:00
private void DrawEventItemPopup(ItemPayload payload) {
if (payload.Kind != ItemPayload.ItemKind.EventItem) {
return;
}
var item = this.Ui.Plugin.DataManager.GetExcelSheet<EventItem>()?.GetRow(payload.ItemId);
if (item == null) {
return;
}
if (this.Ui.Plugin.TextureCache.GetEventItem(item) is { } icon) {
InlineIcon(icon);
}
var name = item.Name.ToDalamudString();
this.Log.DrawChunks(ChunkUtil.ToChunks(name, null).ToList(), false);
ImGui.Separator();
var realItemId = payload.RawItemId;
if (ImGui.Selectable("Link")) {
this.Ui.Plugin.Functions.Context.LinkItem(realItemId);
}
if (ImGui.Selectable("Copy Item Name")) {
ImGui.SetClipboardText(name.TextValue);
}
}
2022-01-14 18:25:33 +00:00
private void DrawPlayerPopup(Chunk chunk, PlayerPayload player) {
2022-02-01 23:33:08 +00:00
var name = new List<Chunk> { new TextChunk(null, null, player.PlayerName) };
2021-12-30 02:53:44 +00:00
if (player.World.IsPublic) {
2022-02-01 23:33:08 +00:00
name.AddRange(new Chunk[] {
new IconChunk(null, null, BitmapFontIcon.CrossWorld),
new TextChunk(null, null, player.World.Name),
});
2021-12-30 02:53:44 +00:00
}
2022-02-01 23:33:08 +00:00
this.Log.DrawChunks(name, false);
2021-12-30 02:53:44 +00:00
ImGui.Separator();
2022-02-04 10:06:55 +00:00
if (ImGui.Selectable("Send Tell")) {
this.Log.Chat = $"/tell {player.PlayerName}";
if (player.World.IsPublic) {
this.Log.Chat += $"@{player.World.Name}";
}
2021-12-30 02:53:44 +00:00
2022-02-04 10:06:55 +00:00
this.Log.Chat += " ";
this.Log.Activate = true;
}
if (player.World.IsPublic) {
var party = this.Ui.Plugin.PartyList;
var leader = (ulong?) party[(int) party.PartyLeaderIndex]?.ContentId;
var isLeader = party.Length == 0 || this.Ui.Plugin.ClientState.LocalContentId == leader;
var member = party.FirstOrDefault(member => member.Name.TextValue == player.PlayerName && member.World.Id == player.World.RowId);
var isInParty = member != default;
if (isLeader) {
2022-02-01 23:33:08 +00:00
if (!isInParty && ImGui.BeginMenu("Invite to Party")) {
if (ImGui.Selectable("Same world")) {
this.Ui.Plugin.Functions.Party.InviteSameWorld(player.PlayerName, (ushort) player.World.RowId, chunk.Message?.ContentId ?? 0);
}
if (chunk.Message?.ContentId is not null or 0 && ImGui.Selectable("Different world")) {
this.Ui.Plugin.Functions.Party.InviteOtherWorld(chunk.Message!.ContentId);
}
ImGui.EndMenu();
}
if (isInParty && member != null) {
if (ImGui.Selectable("Promote")) {
this.Ui.Plugin.Functions.Party.Promote(player.PlayerName, (ulong) member.ContentId);
}
if (ImGui.Selectable("Kick from Party")) {
this.Ui.Plugin.Functions.Party.Kick(player.PlayerName, (ulong) member.ContentId);
}
}
}
2021-12-30 02:53:44 +00:00
var isFriend = this.Ui.Plugin.Common.Functions.FriendList.List.Any(friend => friend.Name.TextValue == player.PlayerName && friend.HomeWorld == player.World.RowId);
if (!isFriend && ImGui.Selectable("Send Friend Request")) {
this.Ui.Plugin.Functions.SendFriendRequest(player.PlayerName, (ushort) player.World.RowId);
}
2021-12-30 02:53:44 +00:00
2022-01-14 18:29:49 +00:00
if (ImGui.Selectable("Add to Blacklist")) {
this.Ui.Plugin.Functions.AddToBlacklist(player.PlayerName, (ushort) player.World.RowId);
}
2022-01-13 08:08:04 +00:00
if (this.Ui.Plugin.Functions.IsMentor() && ImGui.Selectable("Invite to Novice Network")) {
this.Ui.Plugin.Functions.Context.InviteToNoviceNetwork(player.PlayerName, (ushort) player.World.RowId);
}
2022-01-06 20:33:35 +00:00
}
2021-12-30 02:53:44 +00:00
2022-01-14 18:25:33 +00:00
var inputChannel = chunk.Message?.Code.Type.ToInputChannel();
if (inputChannel != null && ImGui.Selectable("Reply in Selected Chat Mode")) {
this.Ui.Plugin.Functions.Chat.SetChannel(inputChannel.Value);
this.Log.Activate = true;
}
2022-01-06 20:33:35 +00:00
if (ImGui.Selectable("Target") && this.FindCharacterForPayload(player) is { } obj) {
this.Ui.Plugin.TargetManager.SetTarget(obj);
}
2022-01-06 21:18:03 +00:00
2022-01-06 20:33:35 +00:00
// View Party Finder 0x2E
}
private PlayerCharacter? FindCharacterForPayload(PlayerPayload payload) {
foreach (var obj in this.Ui.Plugin.ObjectTable) {
if (obj is not PlayerCharacter character) {
continue;
}
if (character.Name.TextValue != payload.PlayerName) {
continue;
2021-12-30 02:53:44 +00:00
}
2022-01-06 20:33:35 +00:00
if (payload.World.IsPublic && character.HomeWorld.Id != payload.World.RowId) {
continue;
}
return character;
2021-12-30 02:53:44 +00:00
}
2022-01-06 20:33:35 +00:00
return null;
2021-12-30 02:53:44 +00:00
}
}