diff --git a/ChatTwo/GameFunctions/Chat.cs b/ChatTwo/GameFunctions/Chat.cs index 29d47f2..626f11f 100755 --- a/ChatTwo/GameFunctions/Chat.cs +++ b/ChatTwo/GameFunctions/Chat.cs @@ -312,6 +312,36 @@ internal sealed unsafe class Chat : IDisposable // EurekaContextMenuTellHook!.Original(a1, playerName, worldName, worldId, accountId, contentId, reason); // } + /// + /// Returns true if the channel is any non-linkshell channel, or if the + /// linkshell actually exists. + /// + internal static bool ValidAnyLinkshell(InputChannel channel) + { + var idx = channel.LinkshellIndex(); + if (idx == uint.MaxValue || channel.IsExtraChatLinkshell()) + return true; + if (channel.IsLinkshell() && ValidLinkshell(idx)) + return true; + if (channel.IsCrossLinkshell() && ValidCrossLinkshell(idx)) + return true; + return false; + } + + internal static bool ValidLinkshell(uint idx) + { + if (idx > 7) + return false; + return InfoProxyLinkshell.Instance()->LinkShells[(int) idx].Id != 0; + } + + internal static bool ValidCrossLinkshell(uint idx) + { + if (idx > 7) + return false; + return InfoProxyCrossWorldLinkshell.Instance()->CrossWorldLinkshells[(int) idx].Name.Length > 0; + } + internal static void SetChannel(InputChannel channel, string? tellTarget = null) { // ExtraChat linkshells aren't supported in game so we never want to @@ -326,6 +356,8 @@ internal sealed unsafe class Chat : IDisposable var idx = channel.LinkshellIndex(); if (idx == uint.MaxValue) idx = 0; + if (!ValidAnyLinkshell(channel)) + return; RaptureShellModule.Instance()->ChangeChatChannel((int) channel, idx, target, true); target->Dtor(true); diff --git a/ChatTwo/GameFunctions/KeybindManager.cs b/ChatTwo/GameFunctions/KeybindManager.cs index 5ce87f9..c97ff13 100644 --- a/ChatTwo/GameFunctions/KeybindManager.cs +++ b/ChatTwo/GameFunctions/KeybindManager.cs @@ -8,6 +8,7 @@ using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.System.String; using FFXIVClientStructs.FFXIV.Client.UI; using ImGuiNET; +using ModifierFlag = ChatTwo.GameFunctions.Types.ModifierFlag; using ModifierFlag = ChatTwo.GameFunctions.Types.ModifierFlag; diff --git a/ChatTwo/Ui/ChatLogWindow.cs b/ChatTwo/Ui/ChatLogWindow.cs index e522c32..4e5b48f 100644 --- a/ChatTwo/Ui/ChatLogWindow.cs +++ b/ChatTwo/Ui/ChatLogWindow.cs @@ -172,6 +172,9 @@ public sealed class ChatLogWindow : Window if (info.Channel != null) { + if (!GameFunctions.Chat.ValidAnyLinkshell(info.Channel.Value)) + return; + var prevTemp = TempChannel; if (info.Permanent) SetChannel(info.Channel.Value); @@ -206,11 +209,21 @@ public sealed class ChatLogWindow : Window if (info.Channel is InputChannel.Linkshell1 && info.Rotate != RotateMode.None) { var idx = GameFunctions.Chat.RotateLinkshellHistory(mode); + if (idx < 0 || !GameFunctions.Chat.ValidLinkshell((uint)idx)) + { + TempChannel = 0; + return; + } TempChannel = info.Channel.Value + (uint) idx; } else if (info.Channel is InputChannel.CrossLinkshell1 && info.Rotate != RotateMode.None) { var idx = GameFunctions.Chat.RotateCrossLinkshellHistory(mode); + if (idx < 0 || !GameFunctions.Chat.ValidCrossLinkshell((uint)idx)) + { + TempChannel = 0; + return; + } TempChannel = info.Channel.Value + (uint) idx; } } @@ -480,10 +493,19 @@ public sealed class ChatLogWindow : Window public override void Draw() { - DrawChatLog(); - - AddPopOutsToDraw(); - DrawAutoComplete(); + try + { + DrawChatLog(); + AddPopOutsToDraw(); + DrawAutoComplete(); + } + catch (Exception e) + { + Plugin.Log.Error($"Error drawing Chat Log window: {e}"); + // Prevent recurring draw failures from constantly trying to grab + // input focus, which breaks every other ImGui window. + Activate = false; + } } private static bool IsChatMode => Plugin.Config.PreviewPosition is PreviewPosition.Inside or PreviewPosition.Tooltip;