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
|
|
@ -8,6 +8,7 @@ using AcDream.Core.Chat;
|
|||
using AcDream.Core.Selection;
|
||||
using AcDream.Runtime;
|
||||
using AcDream.Runtime.Entities;
|
||||
using AcDream.Runtime.Gameplay;
|
||||
using AcDream.Runtime.Session;
|
||||
using AcDream.UI.Abstractions;
|
||||
|
||||
|
|
@ -36,7 +37,7 @@ internal sealed class CurrentGameRuntimeAdapter
|
|||
LocalPlayerIdentityState playerIdentity,
|
||||
LiveEntityRuntime entities,
|
||||
RuntimeEntityObjectLifetime entityObjects,
|
||||
ChatLog chat,
|
||||
RuntimeCommunicationState communication,
|
||||
ILocalPlayerControllerSource playerController,
|
||||
WorldRevealCoordinator worldReveal,
|
||||
IGameRuntimeClock clock,
|
||||
|
|
@ -50,7 +51,7 @@ internal sealed class CurrentGameRuntimeAdapter
|
|||
playerIdentity,
|
||||
entities,
|
||||
entityObjects,
|
||||
chat,
|
||||
communication,
|
||||
playerController,
|
||||
worldReveal,
|
||||
clock);
|
||||
|
|
@ -60,7 +61,7 @@ internal sealed class CurrentGameRuntimeAdapter
|
|||
_events = new CurrentGameRuntimeEventAdapter(
|
||||
_view,
|
||||
entityObjects,
|
||||
chat);
|
||||
communication);
|
||||
_commands = new CurrentGameRuntimeCommandAdapter(
|
||||
session,
|
||||
sessionHost,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using AcDream.Core.Chat;
|
||||
using AcDream.Runtime;
|
||||
using AcDream.Runtime.Entities;
|
||||
using AcDream.Runtime.Gameplay;
|
||||
|
||||
namespace AcDream.App.Runtime;
|
||||
|
||||
|
|
@ -25,14 +25,16 @@ internal sealed class CurrentGameRuntimeEventAdapter
|
|||
: IRuntimeEventSource,
|
||||
ICurrentGameRuntimeEventSink,
|
||||
IRuntimeEntityObjectObserver,
|
||||
IRuntimeCommunicationObserver,
|
||||
IDisposable
|
||||
{
|
||||
private readonly CurrentGameRuntimeViewAdapter _view;
|
||||
private readonly RuntimeEntityObjectLifetime _entityObjects;
|
||||
private readonly ChatLog _chat;
|
||||
private readonly RuntimeCommunicationState _communication;
|
||||
private readonly object _observerGate = new();
|
||||
private IRuntimeEventObserver[] _observers = [];
|
||||
private IDisposable? _entityObjectSubscription;
|
||||
private IDisposable? _communicationSubscription;
|
||||
private bool _ownerEventsAttached;
|
||||
private bool _disposed;
|
||||
|
||||
|
|
@ -42,12 +44,13 @@ internal sealed class CurrentGameRuntimeEventAdapter
|
|||
public CurrentGameRuntimeEventAdapter(
|
||||
CurrentGameRuntimeViewAdapter view,
|
||||
RuntimeEntityObjectLifetime entityObjects,
|
||||
ChatLog chat)
|
||||
RuntimeCommunicationState communication)
|
||||
{
|
||||
_view = view ?? throw new ArgumentNullException(nameof(view));
|
||||
_entityObjects = entityObjects
|
||||
?? throw new ArgumentNullException(nameof(entityObjects));
|
||||
_chat = chat ?? throw new ArgumentNullException(nameof(chat));
|
||||
_communication = communication
|
||||
?? throw new ArgumentNullException(nameof(communication));
|
||||
}
|
||||
|
||||
public IDisposable Subscribe(IRuntimeEventObserver observer)
|
||||
|
|
@ -175,7 +178,7 @@ internal sealed class CurrentGameRuntimeEventAdapter
|
|||
private void AttachOwnerEvents()
|
||||
{
|
||||
_entityObjectSubscription = _entityObjects.Events.Subscribe(this);
|
||||
_chat.EntryAppended += OnChatEntry;
|
||||
_communicationSubscription = _communication.Events.Subscribe(this);
|
||||
_ownerEventsAttached = true;
|
||||
}
|
||||
|
||||
|
|
@ -183,7 +186,8 @@ internal sealed class CurrentGameRuntimeEventAdapter
|
|||
{
|
||||
if (!_ownerEventsAttached)
|
||||
return;
|
||||
_chat.EntryAppended -= OnChatEntry;
|
||||
_communicationSubscription?.Dispose();
|
||||
_communicationSubscription = null;
|
||||
_entityObjectSubscription?.Dispose();
|
||||
_entityObjectSubscription = null;
|
||||
_ownerEventsAttached = false;
|
||||
|
|
@ -223,19 +227,13 @@ internal sealed class CurrentGameRuntimeEventAdapter
|
|||
}
|
||||
}
|
||||
|
||||
private void OnChatEntry(ChatEntry entry)
|
||||
public void OnChat(in RuntimeCommunicationEvent committed)
|
||||
{
|
||||
if (!TryObservers(out IRuntimeEventObserver[] observers))
|
||||
return;
|
||||
var delta = new RuntimeChatDelta(
|
||||
NextStamp(),
|
||||
new RuntimeChatEntry(
|
||||
_chat.Revision,
|
||||
entry.SenderGuid,
|
||||
(int)entry.Kind,
|
||||
entry.Sender,
|
||||
entry.Text,
|
||||
entry.ChannelName));
|
||||
committed.Entry);
|
||||
foreach (IRuntimeEventObserver observer in observers)
|
||||
{
|
||||
try
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using AcDream.Core.Chat;
|
|||
using AcDream.Core.Items;
|
||||
using AcDream.Runtime;
|
||||
using AcDream.Runtime.Entities;
|
||||
using AcDream.Runtime.Gameplay;
|
||||
using AcDream.Runtime.Session;
|
||||
|
||||
namespace AcDream.App.Runtime;
|
||||
|
|
@ -20,11 +21,10 @@ internal sealed class CurrentGameRuntimeViewAdapter : IGameRuntimeView
|
|||
private readonly LocalPlayerIdentityState _playerIdentity;
|
||||
private readonly LiveEntityRuntime _entities;
|
||||
private readonly ClientObjectTable _objects;
|
||||
private readonly ChatLog _chat;
|
||||
private readonly IGameRuntimeClock _clock;
|
||||
private readonly IRuntimeEntityView _entityView;
|
||||
private readonly IRuntimeInventoryView _inventoryView;
|
||||
private readonly ChatView _chatView;
|
||||
private readonly IRuntimeChatView _chatView;
|
||||
private readonly MovementView _movementView;
|
||||
private readonly PortalView _portalView;
|
||||
private bool _active = true;
|
||||
|
|
@ -34,7 +34,7 @@ internal sealed class CurrentGameRuntimeViewAdapter : IGameRuntimeView
|
|||
LocalPlayerIdentityState playerIdentity,
|
||||
LiveEntityRuntime entities,
|
||||
RuntimeEntityObjectLifetime entityObjects,
|
||||
ChatLog chat,
|
||||
RuntimeCommunicationState communication,
|
||||
ILocalPlayerControllerSource playerController,
|
||||
WorldRevealCoordinator worldReveal,
|
||||
IGameRuntimeClock clock)
|
||||
|
|
@ -45,12 +45,12 @@ internal sealed class CurrentGameRuntimeViewAdapter : IGameRuntimeView
|
|||
_entities = entities ?? throw new ArgumentNullException(nameof(entities));
|
||||
ArgumentNullException.ThrowIfNull(entityObjects);
|
||||
_objects = entityObjects.Objects;
|
||||
_chat = chat ?? throw new ArgumentNullException(nameof(chat));
|
||||
ArgumentNullException.ThrowIfNull(communication);
|
||||
_clock = clock ?? throw new ArgumentNullException(nameof(clock));
|
||||
|
||||
_entityView = entityObjects.EntityView;
|
||||
_inventoryView = entityObjects.InventoryView;
|
||||
_chatView = new ChatView(_chat);
|
||||
_chatView = communication.View;
|
||||
_movementView = new MovementView(
|
||||
playerController
|
||||
?? throw new ArgumentNullException(nameof(playerController)),
|
||||
|
|
@ -103,19 +103,13 @@ internal sealed class CurrentGameRuntimeViewAdapter : IGameRuntimeView
|
|||
_entities.MaterializedCount,
|
||||
_objects.ObjectCount,
|
||||
_objects.ContainerCount,
|
||||
_chat.Revision,
|
||||
_chat.Count,
|
||||
_chatView.Revision,
|
||||
_chatView.Count,
|
||||
_movementView.Snapshot,
|
||||
_portalView.Snapshot);
|
||||
|
||||
internal void Deactivate() => _active = false;
|
||||
|
||||
private sealed class ChatView(ChatLog owner) : IRuntimeChatView
|
||||
{
|
||||
public long Revision => owner.Revision;
|
||||
public int Count => owner.Count;
|
||||
}
|
||||
|
||||
private sealed class MovementView(
|
||||
ILocalPlayerControllerSource owner,
|
||||
IGameRuntimeClock clock)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue