feat(runtime): share chat commands and run login sequence
This commit is contained in:
parent
5535d0adac
commit
41b15efd4d
57 changed files with 1739 additions and 345 deletions
|
|
@ -1,5 +1,6 @@
|
|||
using System.Runtime.ExceptionServices;
|
||||
using AcDream.Core.Net;
|
||||
using AcDream.Runtime.Chat;
|
||||
|
||||
namespace AcDream.Runtime.Session;
|
||||
|
||||
|
|
@ -39,7 +40,8 @@ public sealed record LiveSessionHostBindings(
|
|||
/// <see cref="EnteredWorld"/>'s narrow <c>SetActiveCharacter(string)</c>
|
||||
/// fan-out, this exists so a status writer can emit the
|
||||
/// <c>enteredWorld</c> event's <c>characterId</c> field.</summary>
|
||||
Action<LiveSessionCharacterSelection> CharacterEntered);
|
||||
Action<LiveSessionCharacterSelection> CharacterEntered,
|
||||
LoginCommandSequence? LoginCommands = null);
|
||||
|
||||
/// <summary>
|
||||
/// Runtime host for the one canonical <see cref="LiveSessionController"/>.
|
||||
|
|
@ -47,7 +49,9 @@ public sealed record LiveSessionHostBindings(
|
|||
/// composition, but never mirrors session, generation, identity, routing, or
|
||||
/// command state.
|
||||
/// </summary>
|
||||
public sealed class LiveSessionHost : IRuntimeSessionCommands
|
||||
public sealed class LiveSessionHost
|
||||
: IRuntimeSessionCommands,
|
||||
IRuntimeLiveSessionFramePhase
|
||||
{
|
||||
private sealed class PendingRouteRollback(
|
||||
ILiveSessionCommandRouting? commands,
|
||||
|
|
@ -98,6 +102,7 @@ public sealed class LiveSessionHost : IRuntimeSessionCommands
|
|||
private readonly Action<LiveSessionCharacterSelection> _characterEntered;
|
||||
private readonly Action<RuntimeGenerationToken> _reset;
|
||||
private readonly LiveSessionLifecycleHost _lifecycle;
|
||||
private readonly LoginCommandSequence? _loginCommands;
|
||||
private PendingRouteRollback? _pendingRouteRollback;
|
||||
|
||||
public LiveSessionHost(
|
||||
|
|
@ -114,6 +119,7 @@ public sealed class LiveSessionHost : IRuntimeSessionCommands
|
|||
?? throw new ArgumentNullException(nameof(bindings.EnteredWorld));
|
||||
_characterEntered = bindings.CharacterEntered
|
||||
?? throw new ArgumentNullException(nameof(bindings.CharacterEntered));
|
||||
_loginCommands = bindings.LoginCommands;
|
||||
ArgumentNullException.ThrowIfNull(_routing.CreateEvents);
|
||||
ArgumentNullException.ThrowIfNull(_routing.CreateCommands);
|
||||
ArgumentNullException.ThrowIfNull(bindings.Reset);
|
||||
|
|
@ -176,6 +182,17 @@ public sealed class LiveSessionHost : IRuntimeSessionCommands
|
|||
RuntimeGenerationToken expectedGeneration) =>
|
||||
_controller.Stop(expectedGeneration);
|
||||
|
||||
/// <summary>
|
||||
/// Pumps the canonical network session first, then any due login command.
|
||||
/// Both graphical and headless frame loops use this host boundary so the
|
||||
/// sequencing contract cannot drift between them.
|
||||
/// </summary>
|
||||
public void Tick()
|
||||
{
|
||||
_controller.Tick();
|
||||
_loginCommands?.Tick(_controller.Generation, _controller.IsInWorld);
|
||||
}
|
||||
|
||||
private LiveSessionBinding BindSession(WorldSession session)
|
||||
{
|
||||
DrainPendingRouteRollback();
|
||||
|
|
@ -211,6 +228,7 @@ public sealed class LiveSessionHost : IRuntimeSessionCommands
|
|||
// state below. Treat physical route convergence as the same hard
|
||||
// barrier used by normal LiveSessionBinding teardown.
|
||||
DrainPendingRouteRollback();
|
||||
_loginCommands?.Cancel(retiringGeneration);
|
||||
_reset(retiringGeneration);
|
||||
}
|
||||
|
||||
|
|
@ -234,6 +252,7 @@ public sealed class LiveSessionHost : IRuntimeSessionCommands
|
|||
_enteredWorld.LoadCharacterSettings(name);
|
||||
_enteredWorld.ArmPlayerModeAutoEntry();
|
||||
_characterEntered(selection);
|
||||
_loginCommands?.EnteredWorld(_controller.Generation);
|
||||
}
|
||||
|
||||
private void RethrowWithRetryableRollback(
|
||||
|
|
|
|||
|
|
@ -228,6 +228,22 @@ public sealed class SessionStatusWriter
|
|||
error,
|
||||
});
|
||||
|
||||
public void LoginCommandFailed(
|
||||
string sessionId,
|
||||
int commandIndex,
|
||||
string command,
|
||||
string error) =>
|
||||
Write(new
|
||||
{
|
||||
v = VocabularyVersion,
|
||||
e = "loginCommandFailed",
|
||||
t = Now(),
|
||||
sessionId,
|
||||
commandIndex,
|
||||
command,
|
||||
error,
|
||||
});
|
||||
|
||||
public void Disconnected(string sessionId, string reason)
|
||||
{
|
||||
if (!IsEnabled)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue