fix: avoid switching to non-existent linkshell idx
Prevents switching channels to a non-existent linkshell index (for both regular linkshells and cross-world linkshells). ExtraChat linkshells are already validated separately. Prevents ChatLogWindow Draw failures from causing ChatTwo to grab input focus each frame if the exception occurs during an Activate event.
This commit is contained in:
@@ -312,6 +312,36 @@ internal sealed unsafe class Chat : IDisposable
|
|||||||
// EurekaContextMenuTellHook!.Original(a1, playerName, worldName, worldId, accountId, contentId, reason);
|
// EurekaContextMenuTellHook!.Original(a1, playerName, worldName, worldId, accountId, contentId, reason);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if the channel is any non-linkshell channel, or if the
|
||||||
|
/// linkshell actually exists.
|
||||||
|
/// </summary>
|
||||||
|
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)
|
internal static void SetChannel(InputChannel channel, string? tellTarget = null)
|
||||||
{
|
{
|
||||||
// ExtraChat linkshells aren't supported in game so we never want to
|
// 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();
|
var idx = channel.LinkshellIndex();
|
||||||
if (idx == uint.MaxValue)
|
if (idx == uint.MaxValue)
|
||||||
idx = 0;
|
idx = 0;
|
||||||
|
if (!ValidAnyLinkshell(channel))
|
||||||
|
return;
|
||||||
|
|
||||||
RaptureShellModule.Instance()->ChangeChatChannel((int) channel, idx, target, true);
|
RaptureShellModule.Instance()->ChangeChatChannel((int) channel, idx, target, true);
|
||||||
target->Dtor(true);
|
target->Dtor(true);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using Dalamud.Utility.Signatures;
|
|||||||
using FFXIVClientStructs.FFXIV.Client.System.String;
|
using FFXIVClientStructs.FFXIV.Client.System.String;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
using ModifierFlag = ChatTwo.GameFunctions.Types.ModifierFlag;
|
||||||
|
|
||||||
namespace ChatTwo.GameFunctions;
|
namespace ChatTwo.GameFunctions;
|
||||||
|
|
||||||
|
|||||||
@@ -172,6 +172,9 @@ public sealed class ChatLogWindow : Window
|
|||||||
|
|
||||||
if (info.Channel != null)
|
if (info.Channel != null)
|
||||||
{
|
{
|
||||||
|
if (!GameFunctions.Chat.ValidAnyLinkshell(info.Channel.Value))
|
||||||
|
return;
|
||||||
|
|
||||||
var prevTemp = TempChannel;
|
var prevTemp = TempChannel;
|
||||||
if (info.Permanent)
|
if (info.Permanent)
|
||||||
SetChannel(info.Channel.Value);
|
SetChannel(info.Channel.Value);
|
||||||
@@ -206,11 +209,21 @@ public sealed class ChatLogWindow : Window
|
|||||||
if (info.Channel is InputChannel.Linkshell1 && info.Rotate != RotateMode.None)
|
if (info.Channel is InputChannel.Linkshell1 && info.Rotate != RotateMode.None)
|
||||||
{
|
{
|
||||||
var idx = GameFunctions.Chat.RotateLinkshellHistory(mode);
|
var idx = GameFunctions.Chat.RotateLinkshellHistory(mode);
|
||||||
|
if (idx < 0 || !GameFunctions.Chat.ValidLinkshell((uint)idx))
|
||||||
|
{
|
||||||
|
TempChannel = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
TempChannel = info.Channel.Value + (uint) idx;
|
TempChannel = info.Channel.Value + (uint) idx;
|
||||||
}
|
}
|
||||||
else if (info.Channel is InputChannel.CrossLinkshell1 && info.Rotate != RotateMode.None)
|
else if (info.Channel is InputChannel.CrossLinkshell1 && info.Rotate != RotateMode.None)
|
||||||
{
|
{
|
||||||
var idx = GameFunctions.Chat.RotateCrossLinkshellHistory(mode);
|
var idx = GameFunctions.Chat.RotateCrossLinkshellHistory(mode);
|
||||||
|
if (idx < 0 || !GameFunctions.Chat.ValidCrossLinkshell((uint)idx))
|
||||||
|
{
|
||||||
|
TempChannel = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
TempChannel = info.Channel.Value + (uint) idx;
|
TempChannel = info.Channel.Value + (uint) idx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -480,10 +493,19 @@ public sealed class ChatLogWindow : Window
|
|||||||
|
|
||||||
public override void Draw()
|
public override void Draw()
|
||||||
{
|
{
|
||||||
DrawChatLog();
|
try
|
||||||
|
{
|
||||||
AddPopOutsToDraw();
|
DrawChatLog();
|
||||||
DrawAutoComplete();
|
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;
|
private static bool IsChatMode => Plugin.Config.PreviewPosition is PreviewPosition.Inside or PreviewPosition.Tooltip;
|
||||||
|
|||||||
Reference in New Issue
Block a user