refactor(runtime): own communication and social state
Construct chat history, negotiated channels, friends, squelch, and reply targets in one presentation-independent Runtime owner. Make live routing, retained UI, devtools, and current-runtime projections borrow the exact instances, preserve reconnect reset semantics, and publish failure-isolated reentrant-safe chat commits. Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
parent
e321410770
commit
c9d25ade50
19 changed files with 684 additions and 117 deletions
|
|
@ -27,6 +27,8 @@ public sealed class ChatVM : IDisposable
|
|||
public const int DefaultDisplayLimit = 20;
|
||||
|
||||
private readonly ChatLog _log;
|
||||
private readonly ChatCommandTargetState _commandTargets;
|
||||
private readonly bool _ownsCommandTargets;
|
||||
private readonly int _displayLimit;
|
||||
private bool _disposed;
|
||||
|
||||
|
|
@ -41,7 +43,8 @@ public sealed class ChatVM : IDisposable
|
|||
/// <c>chat.rs::ChatState::last_incoming_tell_sender</c> (line 74 +
|
||||
/// the assignment at line 152).
|
||||
/// </summary>
|
||||
public string? LastIncomingTellSender { get; private set; }
|
||||
public string? LastIncomingTellSender =>
|
||||
_commandTargets.LastIncomingTellSender;
|
||||
|
||||
/// <summary>
|
||||
/// Target of the most recent OUTGOING Tell (the player's own
|
||||
|
|
@ -52,7 +55,8 @@ public sealed class ChatVM : IDisposable
|
|||
/// <c>SenderGuid == 0</c> and the target name in <c>Sender</c> —
|
||||
/// that's the discriminator we capture here.
|
||||
/// </summary>
|
||||
public string? LastOutgoingTellTarget { get; private set; }
|
||||
public string? LastOutgoingTellTarget =>
|
||||
_commandTargets.LastOutgoingTellTarget;
|
||||
|
||||
/// <summary>
|
||||
/// Optional callback exposing the live framerate. Wired by
|
||||
|
|
@ -81,35 +85,25 @@ public sealed class ChatVM : IDisposable
|
|||
/// <see cref="RecentLines"/> call. Must be >= 1. Defaults to
|
||||
/// <see cref="DefaultDisplayLimit"/>.
|
||||
/// </param>
|
||||
public ChatVM(ChatLog log, int displayLimit = DefaultDisplayLimit)
|
||||
public ChatVM(
|
||||
ChatLog log,
|
||||
int displayLimit = DefaultDisplayLimit,
|
||||
ChatCommandTargetState? commandTargets = null)
|
||||
{
|
||||
_log = log ?? throw new ArgumentNullException(nameof(log));
|
||||
if (displayLimit < 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(displayLimit), displayLimit, "must be >= 1");
|
||||
_displayLimit = displayLimit;
|
||||
_log.EntryAppended += OnEntryAppended;
|
||||
}
|
||||
|
||||
private void OnEntryAppended(ChatEntry entry)
|
||||
{
|
||||
// Tell-tracking discriminator (SenderGuid):
|
||||
// != 0 = real incoming whisper; capture sender for /reply.
|
||||
// == 0 = our own outgoing echo via OnSelfSent; capture the
|
||||
// target (Sender field) for /retell.
|
||||
if (entry.Kind != ChatKind.Tell) return;
|
||||
if (string.IsNullOrEmpty(entry.Sender)) return;
|
||||
|
||||
if (entry.SenderGuid != 0)
|
||||
LastIncomingTellSender = entry.Sender;
|
||||
else
|
||||
LastOutgoingTellTarget = entry.Sender;
|
||||
_commandTargets = commandTargets ?? new ChatCommandTargetState(_log);
|
||||
_ownsCommandTargets = commandTargets is null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
_log.EntryAppended -= OnEntryAppended;
|
||||
if (_ownsCommandTargets)
|
||||
_commandTargets.Dispose();
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
|
|
@ -132,8 +126,7 @@ public sealed class ChatVM : IDisposable
|
|||
/// </summary>
|
||||
public void ResetSessionTargets()
|
||||
{
|
||||
LastIncomingTellSender = null;
|
||||
LastOutgoingTellTarget = null;
|
||||
_commandTargets.ResetSession();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue