diff --git a/server/src/Hokm.Server/Game/GameManager.cs b/server/src/Hokm.Server/Game/GameManager.cs index c779c7e..164e84c 100644 --- a/server/src/Hokm.Server/Game/GameManager.cs +++ b/server/src/Hokm.Server/Game/GameManager.cs @@ -17,14 +17,15 @@ public sealed class Player /// In-memory matchmaking + room registry. (EF/Postgres persistence is a TODO.) public sealed partial class GameManager { - // Real players get priority. We re-check the queue every QueueWaitMs; the - // moment a second human is waiting they're matched together (+ bots for any - // empty seats), and a full group of 4 forms instantly. A player left ALONE - // keeps waiting up to MaxAloneWaitMs so an online opponent has a genuine - // chance to join before we fall back to a bot table. (QueueWaitMs mirrors - // MATCH_QUEUE_WAIT_MS on the client — keep both in sync.) + // Real players get priority: + // • a full table of 4 humans forms instantly, at any time; + // • at the 15s checkpoint, if ≥2 humans are waiting they start together + // (bots fill any empty seats); + // • a player left ALONE keeps waiting until the 25s hard deadline, then we + // fill the seats with AI and start. + // (QueueWaitMs mirrors MATCH_QUEUE_WAIT_MS on the client — keep both in sync.) private const int QueueWaitMs = 15000; - private const int MaxAloneWaitMs = 75000; + private const int MaxAloneWaitMs = 25000; private static readonly string[] BotNames = { "آرش", "کیان", "نیلوفر", "سارا", "رضا", "مهسا", "امیر", "پارسا", "الناز", "بابک" }; @@ -102,12 +103,14 @@ public sealed partial class GameManager // bots fill any empty chairs (real players matched immediately). if (_waiting.Count >= 2) { FormGroupLocked(_waiting.Count); return; } - // Alone: keep the table open for an online opponent until the max wait - // elapses, then fall back to a bot table. Re-arm the re-check timer. + // Alone: keep the table open for an online opponent until the 25s + // deadline, then fill the seats with AI. Re-arm the timer to land + // exactly on the deadline rather than overshooting by a full window. var waited = (DateTime.UtcNow - _waiting[idx].since).TotalMilliseconds; - if (waited < MaxAloneWaitMs) + var remaining = MaxAloneWaitMs - waited; + if (remaining > 250) { - _waiting[idx].timer.Change(QueueWaitMs, Timeout.Infinite); + _waiting[idx].timer.Change((int)remaining, Timeout.Infinite); return; } FormGroupLocked(1); diff --git a/src/components/screens/MatchmakingScreen.tsx b/src/components/screens/MatchmakingScreen.tsx index 44db9cf..29752f9 100644 --- a/src/components/screens/MatchmakingScreen.tsx +++ b/src/components/screens/MatchmakingScreen.tsx @@ -140,7 +140,7 @@ export function MatchmakingScreen() { {searching && ( <>
{elapsed}s
- {elapsed >= 90 ? ( + {elapsed >= 40 ? (

{t("mm.stuck")}

) : (

{t("mm.fillHint")}