feat(auto-tell-tabs): implement HandleTell with sender extraction and tab lookup

This commit is contained in:
2026-05-02 13:01:27 +02:00
parent 4810e8b518
commit baa4d011e8
+91 -1
View File
@@ -1,5 +1,7 @@
using System;
using System.Linq;
using ChatTwo.Code;
using ChatTwo.Util;
namespace ChatTwo;
@@ -64,7 +66,95 @@ internal sealed class AutoTellTabsService : IDisposable
internal void HandleTell(Message message)
{
// Stub — implemented in Task 8.
if (!Plugin.Config.EnableAutoTellTabs)
{
return;
}
if (message.Code.Type != ChatType.TellIncoming && message.Code.Type != ChatType.TellOutgoing)
{
return;
}
var partner = ExtractTellPartner(message);
if (partner == null)
{
// Real message without a player payload — e.g. GM tells, which
// we deliberately skip. Warn once so we notice future regressions.
Plugin.Log.Warning("[AutoTellTabs] Could not extract tell partner from message; skipping spawn.");
return;
}
lock (_tempTabsLock)
{
var existing = FindTempTab(partner.Value.Name, partner.Value.World);
if (existing != null)
{
// Tab already exists; Tab.Matches has already routed this
// message via the MessageManager pipeline (see Task 2 sender
// filter).
return;
}
if (ActiveTempTabCount >= Plugin.Config.AutoTellTabsLimit)
{
DropOldestTempTab();
}
SpawnTempTab(partner.Value, message);
}
}
private (string Name, uint World)? ExtractTellPartner(Message message)
{
if (message.Code.Type == ChatType.TellIncoming)
{
// Incoming tell: the sender is the conversation partner.
var fromSender = ChunkUtil.TryGetPlayerPayload(message.Sender);
if (fromSender != null)
{
return (fromSender.PlayerName, fromSender.World.RowId);
}
return null;
}
// Outgoing tell: the local player is the sender, the partner shows
// 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
// the SetContextTellTarget game hook).
var fromContent = ChunkUtil.TryGetPlayerPayload(message.Content);
if (fromContent != null)
{
return (fromContent.PlayerName, fromContent.World.RowId);
}
var current = _plugin.CurrentTab.CurrentChannel.TellTarget
?? _plugin.CurrentTab.CurrentChannel.TempTellTarget;
if (current != null && current.IsSet())
{
return (current.Name, current.World);
}
return null;
}
private Tab? FindTempTab(string name, uint world)
{
return Plugin.Config.Tabs.FirstOrDefault(t =>
t.IsTempTab
&& t.TellTarget != null
&& string.Equals(t.TellTarget.Name, name, StringComparison.OrdinalIgnoreCase)
&& t.TellTarget.World == world);
}
private void DropOldestTempTab()
{
// Stub — implemented in Task 9.
}
private void SpawnTempTab((string Name, uint World) partner, Message currentMessage)
{
// Stub — implemented in Task 11.
}
internal void MarkGreeted(Tab tab)