Unify the toolbar shortcut manager with Runtime inventory state, route retail-ordered shortcut and spellbook command effects through the canonical owners, and make retained controllers borrow those exact instances. Remove the item-interaction transaction fallback and add graphical/no-window parity plus failure-safe terminal ownership-ledger coverage. Co-authored-by: Codex <codex@openai.com>
93 lines
2.3 KiB
C#
93 lines
2.3 KiB
C#
namespace AcDream.Core.Chat;
|
|
|
|
/// <summary>
|
|
/// Presentation-independent reply/retell targets derived from the committed
|
|
/// chat transcript.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Incoming tells carry a non-zero sender GUID and update the reply target.
|
|
/// Local outgoing tell echoes carry a zero sender GUID and place the target
|
|
/// name in <see cref="ChatEntry.Sender"/>. This is the existing retail
|
|
/// <c>@reply</c>/<c>@retell</c> behavior formerly owned by <c>ChatVM</c>.
|
|
/// </remarks>
|
|
public sealed class ChatCommandTargetState : IDisposable
|
|
{
|
|
private readonly ChatLog _chat;
|
|
private readonly object _gate = new();
|
|
private string? _lastIncomingTellSender;
|
|
private string? _lastOutgoingTellTarget;
|
|
private bool _disposed;
|
|
|
|
public ChatCommandTargetState(ChatLog chat)
|
|
{
|
|
_chat = chat ?? throw new ArgumentNullException(nameof(chat));
|
|
_chat.EntryAppended += OnEntryAppended;
|
|
}
|
|
|
|
public string? LastIncomingTellSender
|
|
{
|
|
get
|
|
{
|
|
lock (_gate)
|
|
return _lastIncomingTellSender;
|
|
}
|
|
}
|
|
|
|
public string? LastOutgoingTellTarget
|
|
{
|
|
get
|
|
{
|
|
lock (_gate)
|
|
return _lastOutgoingTellTarget;
|
|
}
|
|
}
|
|
|
|
public bool IsDisposed
|
|
{
|
|
get
|
|
{
|
|
lock (_gate)
|
|
return _disposed;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Forget character-scoped command targets without clearing visible
|
|
/// transcript history.
|
|
/// </summary>
|
|
public void ResetSession()
|
|
{
|
|
lock (_gate)
|
|
{
|
|
_lastIncomingTellSender = null;
|
|
_lastOutgoingTellTarget = null;
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
lock (_gate)
|
|
{
|
|
if (_disposed)
|
|
return;
|
|
_disposed = true;
|
|
_chat.EntryAppended -= OnEntryAppended;
|
|
}
|
|
}
|
|
|
|
private void OnEntryAppended(ChatEntry entry)
|
|
{
|
|
if (entry.Kind != ChatKind.Tell || string.IsNullOrEmpty(entry.Sender))
|
|
return;
|
|
|
|
lock (_gate)
|
|
{
|
|
if (_disposed)
|
|
return;
|
|
if (entry.SenderGuid != 0u)
|
|
_lastIncomingTellSender = entry.Sender;
|
|
else
|
|
_lastOutgoingTellTarget = entry.Sender;
|
|
}
|
|
}
|
|
}
|