fix(auto-tell-tabs): fall back to SeString payloads for tell sender extraction
This commit is contained in:
@@ -82,8 +82,14 @@ internal sealed class AutoTellTabsService : IDisposable
|
|||||||
if (partner == null)
|
if (partner == null)
|
||||||
{
|
{
|
||||||
// Real message without a player payload — e.g. GM tells, which
|
// Real message without a player payload — e.g. GM tells, which
|
||||||
// we deliberately skip. Warn once so we notice future regressions.
|
// we deliberately skip. The diagnostics make future regressions
|
||||||
Plugin.Log.Warning("[AutoTellTabs] Could not extract tell partner from message; skipping spawn.");
|
// (FFXIV changing tell payload shape, new edge cases) findable
|
||||||
|
// without having to crank up debug logging at the source.
|
||||||
|
Plugin.Log.Warning(
|
||||||
|
$"[AutoTellTabs] Could not extract tell partner. type={message.Code.Type}, " +
|
||||||
|
$"senderChunks={message.Sender.Count}, contentChunks={message.Content.Count}, " +
|
||||||
|
$"senderSourcePayloads={message.SenderSource?.Payloads?.Count ?? 0}, " +
|
||||||
|
$"contentSourcePayloads={message.ContentSource?.Payloads?.Count ?? 0}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,8 +117,12 @@ internal sealed class AutoTellTabsService : IDisposable
|
|||||||
{
|
{
|
||||||
if (message.Code.Type == ChatType.TellIncoming)
|
if (message.Code.Type == ChatType.TellIncoming)
|
||||||
{
|
{
|
||||||
// Incoming tell: the sender is the conversation partner.
|
// Incoming tell: the sender is the conversation partner. The
|
||||||
var fromSender = ChunkUtil.TryGetPlayerPayload(message.Sender);
|
// PlayerPayload normally rides on a chunk's Link slot, but for
|
||||||
|
// some tell types FFXIV only puts it in the raw SeString —
|
||||||
|
// fall back to that before giving up.
|
||||||
|
var fromSender = ChunkUtil.TryGetPlayerPayload(message.Sender)
|
||||||
|
?? ChunkUtil.TryGetPlayerPayload(message.SenderSource);
|
||||||
if (fromSender != null)
|
if (fromSender != null)
|
||||||
{
|
{
|
||||||
return (fromSender.PlayerName, fromSender.World.RowId);
|
return (fromSender.PlayerName, fromSender.World.RowId);
|
||||||
@@ -123,8 +133,11 @@ internal sealed class AutoTellTabsService : IDisposable
|
|||||||
// Outgoing tell: the local player is the sender, the partner shows
|
// Outgoing tell: the local player is the sender, the partner shows
|
||||||
// up either as a payload in the content (for tells typed via the
|
// up either as a payload in the content (for tells typed via the
|
||||||
// Chat 2 input bar) or as the channel's tracked tell target (set by
|
// Chat 2 input bar) or as the channel's tracked tell target (set by
|
||||||
// the SetContextTellTarget game hook).
|
// the SetContextTellTarget game hook). Same SeString fallback.
|
||||||
var fromContent = ChunkUtil.TryGetPlayerPayload(message.Content);
|
var fromContent = ChunkUtil.TryGetPlayerPayload(message.Content)
|
||||||
|
?? ChunkUtil.TryGetPlayerPayload(message.ContentSource)
|
||||||
|
?? ChunkUtil.TryGetPlayerPayload(message.Sender)
|
||||||
|
?? ChunkUtil.TryGetPlayerPayload(message.SenderSource);
|
||||||
if (fromContent != null)
|
if (fromContent != null)
|
||||||
{
|
{
|
||||||
return (fromContent.PlayerName, fromContent.World.RowId);
|
return (fromContent.PlayerName, fromContent.World.RowId);
|
||||||
|
|||||||
@@ -415,6 +415,26 @@ internal static class ChunkUtil
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fallback for tells where the PlayerPayload lives in the raw SeString
|
||||||
|
// payload list rather than on a chunk's Link slot. Same semantics as
|
||||||
|
// the chunk-walking variant above: returns the first PlayerPayload or
|
||||||
|
// null if the SeString has none.
|
||||||
|
internal static PlayerPayload? TryGetPlayerPayload(SeString? seString)
|
||||||
|
{
|
||||||
|
if (seString == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
foreach (var payload in seString.Payloads)
|
||||||
|
{
|
||||||
|
if (payload is PlayerPayload pp)
|
||||||
|
{
|
||||||
|
return pp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// True when the message's sender (or, as a fallback, content) carries a
|
// True when the message's sender (or, as a fallback, content) carries a
|
||||||
// PlayerPayload that matches the given identity. Used by both the
|
// PlayerPayload that matches the given identity. Used by both the
|
||||||
// Tab.Matches sender filter and the MessageStore tell-history scan.
|
// Tab.Matches sender filter and the MessageStore tell-history scan.
|
||||||
|
|||||||
Reference in New Issue
Block a user