From 8033023a1f62e87717da4a2bf63d75833fad3611 Mon Sep 17 00:00:00 2001 From: "soroush.asadi" Date: Thu, 11 Jun 2026 18:27:46 +0330 Subject: [PATCH] matchmaking: deterministic 15s wait before bots fill empty seats Both the mock and the .NET server already waited then bot-filled, but used a random 12-18s window. Make it exactly 15s on both sides so the rule is clear: wait 15s for real online players to join, then replace any unfilled seats with bots and start. - client: new MATCH_QUEUE_WAIT_MS = 15000 in gamification.ts; mock beginSearch uses it instead of randInt(12000,18000). - server: GameManager QueueWaitMs = 15000 (was randomized 12-18s per ticket). Co-Authored-By: Claude Opus 4.8 --- server/src/Hokm.Server/Game/GameManager.cs | 11 +++++------ src/lib/online/gamification.ts | 7 +++++++ src/lib/online/mock-service.ts | 8 ++++---- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/server/src/Hokm.Server/Game/GameManager.cs b/server/src/Hokm.Server/Game/GameManager.cs index f00ab63..cfa3f58 100644 --- a/server/src/Hokm.Server/Game/GameManager.cs +++ b/server/src/Hokm.Server/Game/GameManager.cs @@ -17,12 +17,11 @@ public sealed class Player /// In-memory matchmaking + room registry. (EF/Postgres persistence is a TODO.) public sealed class GameManager { - // Real players get priority: wait ~15s for humans before bots fill in. The - // exact wait is randomized per ticket (12–18s) so the queue doesn't feel - // robotically identical every time. - private const int QueueWaitMinMs = 12000; - private const int QueueWaitMaxMs = 18000; - private int NextQueueWaitMs() => _rng.Next(QueueWaitMinMs, QueueWaitMaxMs + 1); + // Real players get priority: wait exactly 15s for humans to join; whoever + // hasn't joined the table by then is replaced with a bot when the match forms. + // (Mirror of MATCH_QUEUE_WAIT_MS on the client — keep both in sync.) + private const int QueueWaitMs = 15000; + private int NextQueueWaitMs() => QueueWaitMs; private static readonly string[] BotNames = { "آرش", "کیان", "نیلوفر", "سارا", "رضا", "مهسا", "امیر", "پارسا", "الناز", "بابک" }; diff --git a/src/lib/online/gamification.ts b/src/lib/online/gamification.ts index d2465b7..fb237c4 100644 --- a/src/lib/online/gamification.ts +++ b/src/lib/online/gamification.ts @@ -178,6 +178,13 @@ export const SPEED_TURN_MS = 5000; /** Speed mode races to fewer points so a match is over fast. */ export const SPEED_TARGET_SCORE = 5; +/** + * How long matchmaking waits for real online players before filling the + * remaining seats with bots and starting the match. (Mirror of the server's + * QueueWaitMs in GameManager.cs — keep both in sync.) + */ +export const MATCH_QUEUE_WAIT_MS = 15000; + export function turnMsForStake(stake: number, speed = false): number { if (speed) return SPEED_TURN_MS; if (stake >= 1000) return 7000; diff --git a/src/lib/online/mock-service.ts b/src/lib/online/mock-service.ts index 03b8f28..4a61139 100644 --- a/src/lib/online/mock-service.ts +++ b/src/lib/online/mock-service.ts @@ -7,6 +7,7 @@ import { CARD_BACKS, CARD_FRONTS, CITY_REWARD, + MATCH_QUEUE_WAIT_MS, REACTION_PACKS, STICKER_PACKS, TITLES, @@ -890,10 +891,9 @@ export class MockOnlineService implements OnlineService { }; this.emitMM(); - // Wait ~15s (randomized 12–18s) for "online" players to show up; whoever - // hasn't joined by then is filled with a bot when the match forms. The exact - // wait varies so it never feels robotically identical. - const searchMs = randInt(12000, 18000); + // Wait 15s for "online" players to show up; whoever hasn't joined by then is + // filled with a bot when the match forms. + const searchMs = MATCH_QUEUE_WAIT_MS; // 0–3 humans actually appear; the rest of the table fills with bots. const humansFound = randInt(0, 3);