feat(app): FA2 -- fellowship/allegiance command routing for graphical + headless hosts

Both LiveSocialSessionBindings construction sites updated together
(LiveSessionRuntimeFactory.cs, HeadlessSessionHost.cs) so the single
GameEventWiring.WireAll registration site serves both hosts identically
(the K-slice unification). CurrentGameRuntimeCommandAdapter implements
IRuntimeFellowshipCommands/IRuntimeAllegianceCommands over the App
command bus (LiveSessionCommandRouter gains 12 new *RuntimeCmd records
+ registrations + LiveSessionCommandBindings send delegates), mirroring
DirectGameRuntimeCommandAdapter's direct-session shape including the
identical Quit leader-hand-off rule read from RuntimeFellowshipState.
CurrentGameRuntimeAdapter (the graphical IGameRuntimeView/
IGameRuntimeCommands composite) exposes the two new views/command
groups. Headless's DirectGameRuntimeCommandAdapter needed no changes --
it already implements both new interfaces from the Runtime-layer
commit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-12 01:32:18 +02:00
parent 369729f06a
commit cced83b483
8 changed files with 363 additions and 3 deletions

View file

@ -50,6 +50,21 @@ internal sealed record LiveSessionCommandBindings(
// research §2.3-§2.7. No-ops when the batched module is clean, matching // research §2.3-§2.7. No-ops when the batched module is clean, matching
// retail's CPlayerModule::SaveToServer(force: 0). // retail's CPlayerModule::SaveToServer(force: 0).
Action SaveCharacterOptions, Action SaveCharacterOptions,
// Campaign FA slice FA2 (2026-08-12): fellowship + allegiance send
// wrappers, the App-bus twin of DirectGameRuntimeCommandAdapter's
// direct session.SendXxx calls.
Action<string, bool> SendFellowshipCreate,
Action<uint> SendFellowshipRecruit,
Action<uint> SendFellowshipDismiss,
Action<bool> SendFellowshipQuit,
Action<uint> SendFellowshipAssignNewLeader,
Action<bool> SendFellowshipChangeOpenness,
Action<bool> SendFellowshipUpdateRequest,
Action<uint> SendAllegianceSwear,
Action<uint> SendAllegianceBreak,
Action<uint> SendAllegianceKick,
Action<string> SendAllegianceInfoRequest,
Action<bool> SendAllegianceUpdateRequest,
Action<string>? Log = null); Action<string>? Log = null);
internal readonly record struct AddShortcutRuntimeCmd(ShortcutEntry Entry); internal readonly record struct AddShortcutRuntimeCmd(ShortcutEntry Entry);
@ -91,6 +106,22 @@ internal readonly record struct ModifyGlobalSquelchRuntimeCmd(
bool Add, bool Add,
uint MessageType); uint MessageType);
// ── Fellowship / Allegiance (Campaign FA slice FA2, 2026-08-12) ────────────
internal readonly record struct FellowshipCreateRuntimeCmd(
string FellowshipName,
bool ShareXp);
internal readonly record struct FellowshipRecruitRuntimeCmd(uint TargetGuid);
internal readonly record struct FellowshipDismissRuntimeCmd(uint TargetGuid);
internal readonly record struct FellowshipQuitRuntimeCmd(bool Disband);
internal readonly record struct FellowshipAssignNewLeaderRuntimeCmd(uint NewLeaderGuid);
internal readonly record struct FellowshipChangeOpennessRuntimeCmd(bool IsOpen);
internal readonly record struct FellowshipUpdateRequestRuntimeCmd(bool PanelOpen);
internal readonly record struct AllegianceSwearRuntimeCmd(uint PatronGuid);
internal readonly record struct AllegianceBreakRuntimeCmd(uint TargetGuid);
internal readonly record struct AllegianceKickRuntimeCmd(uint VassalGuid);
internal readonly record struct AllegianceInfoRequestRuntimeCmd(string PlayerName);
internal readonly record struct AllegianceUpdateRequestRuntimeCmd(bool On);
/// <summary> /// <summary>
/// Owns the command surface for one exact live-session generation. The router /// Owns the command surface for one exact live-session generation. The router
/// itself is the published bus, so a retained reference becomes inert before /// itself is the published bus, so a retained reference becomes inert before
@ -200,6 +231,43 @@ internal sealed class LiveSessionCommandRouter : ILiveSessionCommandRouting
command => SendIfActive(() => bindings.ModifyGlobalSquelch( command => SendIfActive(() => bindings.ModifyGlobalSquelch(
command.Add, command.Add,
command.MessageType))); command.MessageType)));
commands.Register<FellowshipCreateRuntimeCmd>(
command => SendIfActive(() => bindings.SendFellowshipCreate(
command.FellowshipName,
command.ShareXp)));
commands.Register<FellowshipRecruitRuntimeCmd>(
command => SendIfActive(() =>
bindings.SendFellowshipRecruit(command.TargetGuid)));
commands.Register<FellowshipDismissRuntimeCmd>(
command => SendIfActive(() =>
bindings.SendFellowshipDismiss(command.TargetGuid)));
commands.Register<FellowshipQuitRuntimeCmd>(
command => SendIfActive(() =>
bindings.SendFellowshipQuit(command.Disband)));
commands.Register<FellowshipAssignNewLeaderRuntimeCmd>(
command => SendIfActive(() =>
bindings.SendFellowshipAssignNewLeader(command.NewLeaderGuid)));
commands.Register<FellowshipChangeOpennessRuntimeCmd>(
command => SendIfActive(() =>
bindings.SendFellowshipChangeOpenness(command.IsOpen)));
commands.Register<FellowshipUpdateRequestRuntimeCmd>(
command => SendIfActive(() =>
bindings.SendFellowshipUpdateRequest(command.PanelOpen)));
commands.Register<AllegianceSwearRuntimeCmd>(
command => SendIfActive(() =>
bindings.SendAllegianceSwear(command.PatronGuid)));
commands.Register<AllegianceBreakRuntimeCmd>(
command => SendIfActive(() =>
bindings.SendAllegianceBreak(command.TargetGuid)));
commands.Register<AllegianceKickRuntimeCmd>(
command => SendIfActive(() =>
bindings.SendAllegianceKick(command.VassalGuid)));
commands.Register<AllegianceInfoRequestRuntimeCmd>(
command => SendIfActive(() =>
bindings.SendAllegianceInfoRequest(command.PlayerName)));
commands.Register<AllegianceUpdateRequestRuntimeCmd>(
command => SendIfActive(() =>
bindings.SendAllegianceUpdateRequest(command.On)));
_commands = commands; _commands = commands;
} }

View file

@ -258,7 +258,9 @@ internal sealed class LiveSessionRuntimeFactory
_domain.Communication.TurbineChat, _domain.Communication.TurbineChat,
_domain.Communication.Friends, _domain.Communication.Friends,
_domain.Communication.Squelch, _domain.Communication.Squelch,
(text, type) => _domain.Communication.AddText(text, type))); (text, type) => _domain.Communication.AddText(text, type),
Fellowship: _domain.Runtime.FellowshipOwner,
Allegiance: _domain.Runtime.AllegianceOwner));
return new GraphicalSessionEventRoute( return new GraphicalSessionEventRoute(
route, route,
_domain.Runtime, _domain.Runtime,
@ -591,6 +593,20 @@ internal sealed class LiveSessionRuntimeFactory
CharacterState: _domain.Character, CharacterState: _domain.Character,
SendSingleCharacterOption: SendSingleCharacterOption, SendSingleCharacterOption: SendSingleCharacterOption,
SaveCharacterOptions: SaveCharacterOptionsIfDirty, SaveCharacterOptions: SaveCharacterOptionsIfDirty,
// Campaign FA slice FA2 (2026-08-12): fellowship + allegiance send
// wrappers, matching the WorldSession.SendXxx methods FA2 added.
SendFellowshipCreate: session.SendFellowshipCreate,
SendFellowshipRecruit: session.SendFellowshipRecruit,
SendFellowshipDismiss: session.SendFellowshipDismiss,
SendFellowshipQuit: session.SendFellowshipQuit,
SendFellowshipAssignNewLeader: session.SendFellowshipAssignNewLeader,
SendFellowshipChangeOpenness: session.SendFellowshipChangeOpenness,
SendFellowshipUpdateRequest: session.SendFellowshipUpdateRequest,
SendAllegianceSwear: session.SendAllegianceSwear,
SendAllegianceBreak: session.SendAllegianceBreak,
SendAllegianceKick: session.SendAllegianceKick,
SendAllegianceInfoRequest: session.SendAllegianceInfoRequest,
SendAllegianceUpdateRequest: session.SendAllegianceUpdateRequest,
Log: _log); Log: _log);
} }

View file

@ -49,6 +49,7 @@ internal sealed class CurrentGameRuntimeAdapter
runtime.CharacterOwner, runtime.CharacterOwner,
runtime.ActionOwner, runtime.ActionOwner,
runtime.MovementOwner, runtime.MovementOwner,
runtime.FellowshipOwner,
selection, selection,
runtime.EventSink); runtime.EventSink);
} }
@ -88,6 +89,8 @@ internal sealed class CurrentGameRuntimeAdapter
public IRuntimeCharacterView Character => _runtime.Character; public IRuntimeCharacterView Character => _runtime.Character;
public IRuntimeSocialView Social => _runtime.Social; public IRuntimeSocialView Social => _runtime.Social;
public IRuntimeChatView Chat => _runtime.Chat; public IRuntimeChatView Chat => _runtime.Chat;
public IRuntimeFellowshipView Fellowship => _runtime.Fellowship;
public IRuntimeAllegianceView Allegiance => _runtime.Allegiance;
public IRuntimeActionView Actions => _runtime.Actions; public IRuntimeActionView Actions => _runtime.Actions;
public IRuntimeMovementView Movement => _runtime.Movement; public IRuntimeMovementView Movement => _runtime.Movement;
public IRuntimeWorldEnvironmentView Environment => _runtime.Environment; public IRuntimeWorldEnvironmentView Environment => _runtime.Environment;
@ -112,6 +115,10 @@ internal sealed class CurrentGameRuntimeAdapter
IRuntimeCharacterCommands IGameRuntimeCommands.Character => _commands; IRuntimeCharacterCommands IGameRuntimeCommands.Character => _commands;
public IRuntimeSocialCommands SocialCommands => _commands; public IRuntimeSocialCommands SocialCommands => _commands;
IRuntimeSocialCommands IGameRuntimeCommands.Social => _commands; IRuntimeSocialCommands IGameRuntimeCommands.Social => _commands;
public IRuntimeFellowshipCommands FellowshipCommands => _commands;
IRuntimeFellowshipCommands IGameRuntimeCommands.Fellowship => _commands;
public IRuntimeAllegianceCommands AllegianceCommands => _commands;
IRuntimeAllegianceCommands IGameRuntimeCommands.Allegiance => _commands;
public RuntimeStateCheckpoint CaptureCheckpoint() public RuntimeStateCheckpoint CaptureCheckpoint()
{ {

View file

@ -26,7 +26,9 @@ internal sealed class CurrentGameRuntimeCommandAdapter
IRuntimeInventoryStateCommands, IRuntimeInventoryStateCommands,
IRuntimeSpellbookCommands, IRuntimeSpellbookCommands,
IRuntimeCharacterCommands, IRuntimeCharacterCommands,
IRuntimeSocialCommands IRuntimeSocialCommands,
IRuntimeFellowshipCommands,
IRuntimeAllegianceCommands
{ {
private readonly LiveSessionController _session; private readonly LiveSessionController _session;
private readonly LiveSessionHost _sessionHost; private readonly LiveSessionHost _sessionHost;
@ -36,6 +38,7 @@ internal sealed class CurrentGameRuntimeCommandAdapter
private readonly RuntimeCharacterState _character; private readonly RuntimeCharacterState _character;
private readonly RuntimeActionState _actions; private readonly RuntimeActionState _actions;
private readonly RuntimeLocalPlayerMovementState _movement; private readonly RuntimeLocalPlayerMovementState _movement;
private readonly RuntimeFellowshipState _fellowship;
private readonly SelectionInteractionController _selection; private readonly SelectionInteractionController _selection;
private readonly IGameRuntimeEventSink _events; private readonly IGameRuntimeEventSink _events;
@ -48,6 +51,7 @@ internal sealed class CurrentGameRuntimeCommandAdapter
RuntimeCharacterState character, RuntimeCharacterState character,
RuntimeActionState actions, RuntimeActionState actions,
RuntimeLocalPlayerMovementState movement, RuntimeLocalPlayerMovementState movement,
RuntimeFellowshipState fellowship,
SelectionInteractionController selection, SelectionInteractionController selection,
IGameRuntimeEventSink events) IGameRuntimeEventSink events)
{ {
@ -61,6 +65,8 @@ internal sealed class CurrentGameRuntimeCommandAdapter
?? throw new ArgumentNullException(nameof(actions)); ?? throw new ArgumentNullException(nameof(actions));
_movement = movement _movement = movement
?? throw new ArgumentNullException(nameof(movement)); ?? throw new ArgumentNullException(nameof(movement));
_fellowship = fellowship
?? throw new ArgumentNullException(nameof(fellowship));
_selection = selection ?? throw new ArgumentNullException(nameof(selection)); _selection = selection ?? throw new ArgumentNullException(nameof(selection));
_events = events ?? throw new ArgumentNullException(nameof(events)); _events = events ?? throw new ArgumentNullException(nameof(events));
} }
@ -793,6 +799,249 @@ internal sealed class CurrentGameRuntimeCommandAdapter
command.Name); command.Name);
} }
// ── Fellowship / Allegiance (Campaign FA slice FA2, 2026-08-12) ────────
public RuntimeCommandResult Create(
RuntimeGenerationToken expectedGeneration,
string fellowshipName,
bool shareXp)
{
RuntimeCommandStatus gate = Validate(expectedGeneration, requireWorld: true);
if (gate != RuntimeCommandStatus.Accepted)
return Result(gate);
if (string.IsNullOrWhiteSpace(fellowshipName))
{
return EmitResult(
RuntimeCommandDomain.Fellowship,
operation: 0,
RuntimeCommandStatus.Rejected);
}
_commands.Publish(new FellowshipCreateRuntimeCmd(fellowshipName, shareXp));
return EmitResult(
RuntimeCommandDomain.Fellowship,
operation: 0,
RuntimeCommandStatus.Accepted);
}
public RuntimeCommandResult Recruit(
RuntimeGenerationToken expectedGeneration,
uint targetGuid)
{
RuntimeCommandStatus gate = Validate(expectedGeneration, requireWorld: true);
if (gate != RuntimeCommandStatus.Accepted)
return Result(gate);
if (targetGuid == 0u)
{
return EmitResult(
RuntimeCommandDomain.Fellowship,
operation: 1,
RuntimeCommandStatus.Rejected,
targetGuid);
}
_commands.Publish(new FellowshipRecruitRuntimeCmd(targetGuid));
return EmitResult(
RuntimeCommandDomain.Fellowship,
operation: 1,
RuntimeCommandStatus.Accepted,
targetGuid);
}
public RuntimeCommandResult Dismiss(
RuntimeGenerationToken expectedGeneration,
uint targetGuid)
{
RuntimeCommandStatus gate = Validate(expectedGeneration, requireWorld: true);
if (gate != RuntimeCommandStatus.Accepted)
return Result(gate);
if (targetGuid == 0u)
{
return EmitResult(
RuntimeCommandDomain.Fellowship,
operation: 2,
RuntimeCommandStatus.Rejected,
targetGuid);
}
_commands.Publish(new FellowshipDismissRuntimeCmd(targetGuid));
return EmitResult(
RuntimeCommandDomain.Fellowship,
operation: 2,
RuntimeCommandStatus.Accepted,
targetGuid);
}
/// <summary>
/// Retail's Quit-button leader hand-off (lane B §2.5/§3.6) — see
/// <see cref="DirectGameRuntimeCommandAdapter.Quit"/>'s identical rule.
/// </summary>
public RuntimeCommandResult Quit(
RuntimeGenerationToken expectedGeneration,
bool disband)
{
RuntimeCommandStatus gate = Validate(expectedGeneration, requireWorld: true);
if (gate != RuntimeCommandStatus.Accepted)
return Result(gate);
if (_fellowship.RequiresLeaderHandoffBeforeQuit(
_view.Lifecycle.PlayerGuid,
disband,
out uint newLeaderGuid))
{
_commands.Publish(new FellowshipAssignNewLeaderRuntimeCmd(newLeaderGuid));
}
_commands.Publish(new FellowshipQuitRuntimeCmd(disband));
return EmitResult(
RuntimeCommandDomain.Fellowship,
operation: 3,
RuntimeCommandStatus.Accepted);
}
public RuntimeCommandResult AssignLeader(
RuntimeGenerationToken expectedGeneration,
uint newLeaderGuid)
{
RuntimeCommandStatus gate = Validate(expectedGeneration, requireWorld: true);
if (gate != RuntimeCommandStatus.Accepted)
return Result(gate);
if (newLeaderGuid == 0u)
{
return EmitResult(
RuntimeCommandDomain.Fellowship,
operation: 4,
RuntimeCommandStatus.Rejected,
newLeaderGuid);
}
_commands.Publish(new FellowshipAssignNewLeaderRuntimeCmd(newLeaderGuid));
return EmitResult(
RuntimeCommandDomain.Fellowship,
operation: 4,
RuntimeCommandStatus.Accepted,
newLeaderGuid);
}
public RuntimeCommandResult SetOpen(
RuntimeGenerationToken expectedGeneration,
bool isOpen)
{
RuntimeCommandStatus gate = Validate(expectedGeneration, requireWorld: true);
if (gate != RuntimeCommandStatus.Accepted)
return Result(gate);
_commands.Publish(new FellowshipChangeOpennessRuntimeCmd(isOpen));
return EmitResult(
RuntimeCommandDomain.Fellowship,
operation: 5,
RuntimeCommandStatus.Accepted);
}
public RuntimeCommandResult SetPanelOpen(
RuntimeGenerationToken expectedGeneration,
bool panelOpen)
{
RuntimeCommandStatus gate = Validate(expectedGeneration, requireWorld: true);
if (gate != RuntimeCommandStatus.Accepted)
return Result(gate);
_commands.Publish(new FellowshipUpdateRequestRuntimeCmd(panelOpen));
return EmitResult(
RuntimeCommandDomain.Fellowship,
operation: 6,
RuntimeCommandStatus.Accepted);
}
public RuntimeCommandResult Swear(
RuntimeGenerationToken expectedGeneration,
uint patronGuid)
{
RuntimeCommandStatus gate = Validate(expectedGeneration, requireWorld: true);
if (gate != RuntimeCommandStatus.Accepted)
return Result(gate);
if (patronGuid == 0u)
{
return EmitResult(
RuntimeCommandDomain.Allegiance,
operation: 0,
RuntimeCommandStatus.Rejected,
patronGuid);
}
_commands.Publish(new AllegianceSwearRuntimeCmd(patronGuid));
return EmitResult(
RuntimeCommandDomain.Allegiance,
operation: 0,
RuntimeCommandStatus.Accepted,
patronGuid);
}
public RuntimeCommandResult Break(
RuntimeGenerationToken expectedGeneration,
uint targetGuid)
{
RuntimeCommandStatus gate = Validate(expectedGeneration, requireWorld: true);
if (gate != RuntimeCommandStatus.Accepted)
return Result(gate);
if (targetGuid == 0u)
{
return EmitResult(
RuntimeCommandDomain.Allegiance,
operation: 1,
RuntimeCommandStatus.Rejected,
targetGuid);
}
_commands.Publish(new AllegianceBreakRuntimeCmd(targetGuid));
return EmitResult(
RuntimeCommandDomain.Allegiance,
operation: 1,
RuntimeCommandStatus.Accepted,
targetGuid);
}
public RuntimeCommandResult Kick(
RuntimeGenerationToken expectedGeneration,
uint vassalGuid)
{
RuntimeCommandStatus gate = Validate(expectedGeneration, requireWorld: true);
if (gate != RuntimeCommandStatus.Accepted)
return Result(gate);
if (vassalGuid == 0u)
{
return EmitResult(
RuntimeCommandDomain.Allegiance,
operation: 2,
RuntimeCommandStatus.Rejected,
vassalGuid);
}
_commands.Publish(new AllegianceKickRuntimeCmd(vassalGuid));
return EmitResult(
RuntimeCommandDomain.Allegiance,
operation: 2,
RuntimeCommandStatus.Accepted,
vassalGuid);
}
public RuntimeCommandResult RequestInfo(
RuntimeGenerationToken expectedGeneration,
string playerName)
{
RuntimeCommandStatus gate = Validate(expectedGeneration, requireWorld: true);
if (gate != RuntimeCommandStatus.Accepted)
return Result(gate);
_commands.Publish(new AllegianceInfoRequestRuntimeCmd(playerName ?? string.Empty));
return EmitResult(
RuntimeCommandDomain.Allegiance,
operation: 3,
RuntimeCommandStatus.Accepted);
}
public RuntimeCommandResult SetUpdateSubscription(
RuntimeGenerationToken expectedGeneration,
bool on)
{
RuntimeCommandStatus gate = Validate(expectedGeneration, requireWorld: true);
if (gate != RuntimeCommandStatus.Accepted)
return Result(gate);
_commands.Publish(new AllegianceUpdateRequestRuntimeCmd(on));
return EmitResult(
RuntimeCommandDomain.Allegiance,
operation: 4,
RuntimeCommandStatus.Accepted);
}
private RuntimeCommandStatus Validate( private RuntimeCommandStatus Validate(
RuntimeGenerationToken expectedGeneration, RuntimeGenerationToken expectedGeneration,
bool requireWorld) bool requireWorld)

View file

@ -782,7 +782,9 @@ internal sealed class HeadlessSessionHost : IDisposable
Runtime.CommunicationOwner.TurbineChat, Runtime.CommunicationOwner.TurbineChat,
Runtime.CommunicationOwner.Friends, Runtime.CommunicationOwner.Friends,
Runtime.CommunicationOwner.Squelch, Runtime.CommunicationOwner.Squelch,
(text, type) => Runtime.CommunicationOwner.AddText(text, type))); (text, type) => Runtime.CommunicationOwner.AddText(text, type),
Fellowship: Runtime.FellowshipOwner,
Allegiance: Runtime.AllegianceOwner));
var eventRoute = new HeadlessSessionEventRoute( var eventRoute = new HeadlessSessionEventRoute(
route, route,
Runtime, Runtime,

View file

@ -234,6 +234,8 @@ public sealed class InteractionUiRuntimeSourcesTests
public IRuntimeCharacterView Character => null!; public IRuntimeCharacterView Character => null!;
public IRuntimeSocialView Social => null!; public IRuntimeSocialView Social => null!;
public IRuntimeChatView Chat => null!; public IRuntimeChatView Chat => null!;
public IRuntimeFellowshipView Fellowship => null!;
public IRuntimeAllegianceView Allegiance => null!;
public IRuntimeActionView Actions => null!; public IRuntimeActionView Actions => null!;
public IRuntimeMovementView Movement => null!; public IRuntimeMovementView Movement => null!;
public AcDream.Runtime.World.IRuntimeWorldEnvironmentView Environment => public AcDream.Runtime.World.IRuntimeWorldEnvironmentView Environment =>
@ -250,6 +252,8 @@ public sealed class InteractionUiRuntimeSourcesTests
IRuntimeSpellbookCommands IGameRuntimeCommands.Spellbook => this; IRuntimeSpellbookCommands IGameRuntimeCommands.Spellbook => this;
IRuntimeCharacterCommands IGameRuntimeCommands.Character => this; IRuntimeCharacterCommands IGameRuntimeCommands.Character => this;
IRuntimeSocialCommands IGameRuntimeCommands.Social => null!; IRuntimeSocialCommands IGameRuntimeCommands.Social => null!;
IRuntimeFellowshipCommands IGameRuntimeCommands.Fellowship => null!;
IRuntimeAllegianceCommands IGameRuntimeCommands.Allegiance => null!;
public RuntimeStateCheckpoint CaptureCheckpoint() => default; public RuntimeStateCheckpoint CaptureCheckpoint() => default;

View file

@ -227,6 +227,8 @@ public sealed class GameplayInputCommandControllerTests
throw new NotSupportedException(); throw new NotSupportedException();
public IRuntimeSocialView Social => throw new NotSupportedException(); public IRuntimeSocialView Social => throw new NotSupportedException();
public IRuntimeChatView Chat => throw new NotSupportedException(); public IRuntimeChatView Chat => throw new NotSupportedException();
public IRuntimeFellowshipView Fellowship => throw new NotSupportedException();
public IRuntimeAllegianceView Allegiance => throw new NotSupportedException();
public IRuntimeActionView Actions => throw new NotSupportedException(); public IRuntimeActionView Actions => throw new NotSupportedException();
public IRuntimeMovementView Movement => throw new NotSupportedException(); public IRuntimeMovementView Movement => throw new NotSupportedException();
public AcDream.Runtime.World.IRuntimeWorldEnvironmentView Environment => public AcDream.Runtime.World.IRuntimeWorldEnvironmentView Environment =>

View file

@ -617,6 +617,18 @@ public sealed class LiveSessionCommandRouterTests
CharacterState: characterState ?? new RuntimeCharacterState(), CharacterState: characterState ?? new RuntimeCharacterState(),
SendSingleCharacterOption: sendSingleCharacterOption ?? ((_, _) => { }), SendSingleCharacterOption: sendSingleCharacterOption ?? ((_, _) => { }),
SaveCharacterOptions: saveCharacterOptions ?? (() => { }), SaveCharacterOptions: saveCharacterOptions ?? (() => { }),
SendFellowshipCreate: (_, _) => { },
SendFellowshipRecruit: _ => { },
SendFellowshipDismiss: _ => { },
SendFellowshipQuit: _ => { },
SendFellowshipAssignNewLeader: _ => { },
SendFellowshipChangeOpenness: _ => { },
SendFellowshipUpdateRequest: _ => { },
SendAllegianceSwear: _ => { },
SendAllegianceBreak: _ => { },
SendAllegianceKick: _ => { },
SendAllegianceInfoRequest: _ => { },
SendAllegianceUpdateRequest: _ => { },
Log: log)); Log: log));
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]