refactor(runtime): close canonical gameplay ownership

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>
This commit is contained in:
Erik 2026-07-26 09:48:51 +02:00
parent ce6fae7b38
commit 89e6b207f8
36 changed files with 1433 additions and 251 deletions

View file

@ -17,6 +17,36 @@ public interface IRuntimeCommunicationEventSource
IDisposable Subscribe(IRuntimeCommunicationObserver observer);
}
public readonly record struct RuntimeCommunicationOwnershipSnapshot(
bool IsDisposed,
bool CommandTargetsDisposed,
int StreamSubscriberCount,
int PendingDispatchCount,
bool IsDispatching,
int FriendCount,
int SquelchAccountCount,
int SquelchCharacterCount,
int SquelchGlobalTypeCount,
int NegotiatedRoomCount,
bool HasReplyTarget,
bool HasRetellTarget,
long DispatchFailureCount)
{
public bool IsConverged =>
IsDisposed
&& CommandTargetsDisposed
&& StreamSubscriberCount == 0
&& PendingDispatchCount == 0
&& !IsDispatching
&& FriendCount == 0
&& SquelchAccountCount == 0
&& SquelchCharacterCount == 0
&& SquelchGlobalTypeCount == 0
&& NegotiatedRoomCount == 0
&& !HasReplyTarget
&& !HasRetellTarget;
}
/// <summary>
/// Canonical presentation-independent owner for communication and social
/// state. Graphical, headless, plugin, and bot hosts borrow these exact
@ -59,6 +89,25 @@ public sealed class RuntimeCommunicationState : IDisposable
public long DispatchFailureCount => _events.DispatchFailureCount;
public Exception? LastDispatchFailure => _events.LastDispatchFailure;
public RuntimeCommunicationOwnershipSnapshot CaptureOwnership()
{
SquelchDatabase squelch = Squelch.Snapshot();
return new RuntimeCommunicationOwnershipSnapshot(
_disposed,
CommandTargets.IsDisposed,
SubscriberCount,
PendingDispatchCount,
IsDispatching,
Friends.Count,
squelch.Accounts.Count,
squelch.Characters.Count,
squelch.Global.MessageTypes.Count,
CountRooms(TurbineChat),
CommandTargets.LastIncomingTellSender is not null,
CommandTargets.LastOutgoingTellTarget is not null,
DispatchFailureCount);
}
public void ResetCommandTargets() => CommandTargets.ResetSession();
public void ResetChatIdentity() => Chat.ResetSessionIdentity();
public void ResetNegotiatedChannels() => TurbineChat.Reset();
@ -126,18 +175,19 @@ public sealed class RuntimeCommunicationState : IDisposable
return true;
}
private static int CountRooms(TurbineChatState state)
{
int count = 0;
if (state.AllegianceRoom != 0u) count++;
if (state.GeneralRoom != 0u) count++;
if (state.TradeRoom != 0u) count++;
if (state.LfgRoom != 0u) count++;
if (state.RoleplayRoom != 0u) count++;
if (state.SocietyRoom != 0u) count++;
if (state.OlthoiRoom != 0u) count++;
return count;
}
}
private static int CountRooms(TurbineChatState state)
{
int count = 0;
if (state.AllegianceRoom != 0u) count++;
if (state.GeneralRoom != 0u) count++;
if (state.TradeRoom != 0u) count++;
if (state.LfgRoom != 0u) count++;
if (state.RoleplayRoom != 0u) count++;
if (state.SocietyRoom != 0u) count++;
if (state.OlthoiRoom != 0u) count++;
return count;
}
}