using SVSim.BattleNode.Bridge; using SVSim.BattleNode.Lifecycle; using SVSim.BattleNode.Protocol; namespace SVSim.BattleNode.Sessions.Participants; /// /// Silent participant — produces no frames, swallows everything pushed to it. /// Used as the "other" participant in sessions, where /// the real opponent runs in the client and the server has no opponent-side state /// to model. ViewerId is ; /// Context is a fixed stub (irrelevant — never read because no frames are pushed /// to the other side). /// public sealed class NoOpBotParticipant : IBattleParticipant { public long ViewerId => ServerBattleFrames.FakeOpponentViewerId; public MatchContext Context { get; } = new( SelfDeckCardIds: Array.Empty(), ClassId: "0", CharaId: "0", CardMasterName: "card_master_node_10015", CountryCode: "", UserName: "Bot", SleeveId: "0", EmblemId: "0", DegreeId: "0", FieldId: 0, IsOfficial: 0, BattleType: 0); public event Func? FrameEmitted; public Task PushAsync(MsgEnvelope envelope, bool noStock, CancellationToken ct) => Task.CompletedTask; public Task RunAsync(CancellationToken ct) => Task.CompletedTask; public Task TerminateAsync(BattleFinishReason reason) => Task.CompletedTask; public ValueTask DisposeAsync() => ValueTask.CompletedTask; // Suppress unused-event warning — FrameEmitted is declared by the interface contract; // intentionally never invoked. private void Touch() => FrameEmitted?.Invoke(null!, default); }