fix(mm): pro players also wait the 15s queue; compact post-match roster
CI/CD / CI - API (dotnet build + engine sim) (push) Successful in 4m45s
CI/CD / CI - Web (tsc + next build) (push) Successful in 1m10s
CI/CD / Deploy - local stack (db + server + web) (push) Successful in 1m33s

- server: remove pro instant-start so all players queue for up to 15s,
  giving real players a chance to seat together before bot-fill
- post-match: render the 4 seats as a horizontal strip so every player
  is visible at once without scrolling

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-16 21:31:18 +03:30
parent 60d44100a2
commit 6aa4f37642
2 changed files with 32 additions and 53 deletions
+3 -7
View File
@@ -54,13 +54,9 @@ public sealed partial class GameManager
return;
}
// Pro players skip the queue entirely.
if (p.Plan == "pro")
{
StartMatch(new List<Player> { p });
return;
}
// Everyone — including pro — waits in the queue so we always try to seat
// real players together first. The 15s timer (NextQueueWaitMs) then fills
// any empty seats with bots, and a full group of 4 forms instantly.
lock (_mmLock)
{
if (_waiting.Any(w => w.player.UserId == p.UserId)) return;
+24 -41
View File
@@ -32,64 +32,47 @@ export function MatchPlayersList() {
return (
<div className="mt-3 sm:mt-4 text-start">
<div className="text-[11px] font-bold text-cream/55 mb-1.5">{t("match.players")}</div>
<div className="space-y-1">
{/* Horizontal strip: all four seats are visible at once — no scrolling. */}
<div className="flex items-start justify-between gap-1.5">
{seatPlayers.map((p, i) => {
const isMe = p.id ? p.id === myId : !p.isBot;
const canAdd = !!p.id && !p.isBot && p.id !== myId;
const tag = isMe ? t("match.you") : p.isBot ? t("match.bot") : null;
return (
<div key={i} className="flex items-center gap-2.5 glass rounded-xl px-2.5 py-1">
{canAdd ? (
<button
onClick={() => viewProfile(p.id!)}
className="flex items-center gap-2.5 flex-1 min-w-0 text-start active:scale-[0.99] transition"
key={i}
onClick={() => canAdd && viewProfile(p.id!)}
className={
"flex-1 min-w-0 glass rounded-xl px-1 py-2 flex flex-col items-center gap-0.5 text-center " +
(canAdd ? "active:scale-[0.97] transition" : "cursor-default")
}
>
<span className="grid size-8 shrink-0 place-items-center rounded-lg bg-navy-900 text-lg">
<span className="grid size-9 shrink-0 place-items-center rounded-lg bg-navy-900 text-lg">
{p.avatar}
</span>
<span className="flex-1 min-w-0">
<span className="block text-sm font-semibold text-cream truncate">{p.name}</span>
{p.level > 0 && (
<span className="block text-[10px] text-cream/45">
{t("common.level")} {p.level}
<span className="w-full truncate text-[11px] font-semibold text-cream">{p.name}</span>
<span className="text-[9px] text-cream/45 leading-tight">
{tag ?? (p.level > 0 ? `${t("common.level")} ${p.level}` : "")}
</span>
)}
</span>
</button>
) : (
<>
<span className="grid size-8 shrink-0 place-items-center rounded-lg bg-navy-900 text-lg">
{p.avatar}
</span>
<span className="flex-1 min-w-0">
<span className="block text-sm font-semibold text-cream truncate">
{p.name}
{isMe && <span className="text-gold-300 font-normal"> ({t("match.you")})</span>}
{p.isBot && <span className="text-cream/35 font-normal"> ({t("match.bot")})</span>}
</span>
{p.level > 0 && (
<span className="block text-[10px] text-cream/45">
{t("common.level")} {p.level}
</span>
)}
</span>
</>
)}
{canAdd &&
(sent[p.id!] ? (
<span className="text-[11px] text-teal-300 flex items-center gap-1 shrink-0">
<Check className="size-3.5" />
<span className="mt-0.5 text-[10px] text-teal-300 flex items-center gap-0.5">
<Check className="size-3" />
{t("match.sent")}
</span>
) : (
<button
onClick={() => add(p.id!)}
className="press-3d btn-gold rounded-lg px-2.5 py-1.5 text-[11px] font-bold flex items-center gap-1 shrink-0"
<span
onClick={(e) => {
e.stopPropagation();
add(p.id!);
}}
className="press-3d btn-gold mt-0.5 rounded-md px-2 py-0.5 text-[10px] font-bold flex items-center gap-0.5"
>
<UserPlus className="size-3.5" />
<UserPlus className="size-3" />
{t("match.addFriend")}
</button>
</span>
))}
</div>
</button>
);
})}
</div>