diff --git a/server/src/Hokm.Server/Game/Contracts.cs b/server/src/Hokm.Server/Game/Contracts.cs index 1bd8ef0..7f3658e 100644 --- a/server/src/Hokm.Server/Game/Contracts.cs +++ b/server/src/Hokm.Server/Game/Contracts.cs @@ -34,7 +34,8 @@ public record GameStateDto( bool Ranked, int Stake); -public record MatchmakingStateDto(string Phase, int Players, int? QueuePosition); +public record QueuePlayerDto(string Id, string Name, string Avatar, string? AvatarImage, int Level); +public record MatchmakingStateDto(string Phase, int Players, int? QueuePosition, QueuePlayerDto[]? Queue = null); public record ReactionDto(int Seat, string Reaction); public static class Map diff --git a/server/src/Hokm.Server/Game/GameManager.cs b/server/src/Hokm.Server/Game/GameManager.cs index ef39b66..15fa8f3 100644 --- a/server/src/Hokm.Server/Game/GameManager.cs +++ b/server/src/Hokm.Server/Game/GameManager.cs @@ -88,13 +88,16 @@ public sealed partial class GameManager } } - /// Push the current queue size to every waiting player (call inside _mmLock). + /// Push the current queue size + player list to every waiting player (call inside _mmLock). private void BroadcastQueueLocked() { - int n = _waiting.Count; + var queue = _waiting + .Select(w => new QueuePlayerDto(w.player.UserId, w.player.Name, w.player.Avatar, w.player.AvatarImage, w.player.Level)) + .ToArray(); + int n = queue.Length; foreach (var w in _waiting) _ = _hub.Clients.User(w.player.UserId).SendAsync("matchmaking", - new MatchmakingStateDto("searching", n, null)); + new MatchmakingStateDto("searching", n, null, queue)); } /// Client safety net: re-send the current game state to a player who diff --git a/src/lib/online/signalr-service.ts b/src/lib/online/signalr-service.ts index 663f649..1478a58 100644 --- a/src/lib/online/signalr-service.ts +++ b/src/lib/online/signalr-service.ts @@ -159,8 +159,9 @@ export class SignalrService implements OnlineService { .configureLogging(signalR.LogLevel.Warning) .build(); - conn.on("matchmaking", (s: { phase: string; players: number; queuePosition: number | null }) => - this.emitMM(s.phase, s.queuePosition ?? undefined, s.players)); + conn.on("matchmaking", (s: { phase: string; players: number; queuePosition: number | null; queue?: Array<{ id: string; name: string; avatar: string; avatarImage?: string; level: number }> }) => + this.emitMM(s.phase, s.queuePosition ?? undefined, s.players, + s.queue?.map(p => ({ id: p.id, displayName: p.name, avatar: p.avatar, avatarImage: p.avatarImage, level: p.level, rating: 0 })))); conn.on("matchFound", () => { this.emitMM("ready"); // Safety net: if the initial state never lands (dropped/raced), ask the @@ -226,10 +227,15 @@ export class SignalrService implements OnlineService { } } - private emitMM(phase: string, queuePosition?: number, waiting?: number) { + private emitMM( + phase: string, + queuePosition?: number, + waiting?: number, + queuePlayers?: Array<{ id: string; displayName: string; avatar: string; avatarImage?: string; level: number; rating: number }> + ) { const state: MatchmakingState = { phase: phase as MatchmakingState["phase"], - players: [], + players: queuePlayers ?? [], elapsedMs: 0, ranked: this.mmRanked, stake: this.mmStake,