fix(mm): pro players also wait the 15s queue; compact post-match roster
- 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:
@@ -54,13 +54,9 @@ public sealed partial class GameManager
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pro players skip the queue entirely.
|
// Everyone — including pro — waits in the queue so we always try to seat
|
||||||
if (p.Plan == "pro")
|
// real players together first. The 15s timer (NextQueueWaitMs) then fills
|
||||||
{
|
// any empty seats with bots, and a full group of 4 forms instantly.
|
||||||
StartMatch(new List<Player> { p });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (_mmLock)
|
lock (_mmLock)
|
||||||
{
|
{
|
||||||
if (_waiting.Any(w => w.player.UserId == p.UserId)) return;
|
if (_waiting.Any(w => w.player.UserId == p.UserId)) return;
|
||||||
|
|||||||
@@ -32,64 +32,47 @@ export function MatchPlayersList() {
|
|||||||
return (
|
return (
|
||||||
<div className="mt-3 sm:mt-4 text-start">
|
<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="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) => {
|
{seatPlayers.map((p, i) => {
|
||||||
const isMe = p.id ? p.id === myId : !p.isBot;
|
const isMe = p.id ? p.id === myId : !p.isBot;
|
||||||
const canAdd = !!p.id && !p.isBot && p.id !== myId;
|
const canAdd = !!p.id && !p.isBot && p.id !== myId;
|
||||||
|
const tag = isMe ? t("match.you") : p.isBot ? t("match.bot") : null;
|
||||||
return (
|
return (
|
||||||
<div key={i} className="flex items-center gap-2.5 glass rounded-xl px-2.5 py-1">
|
<button
|
||||||
{canAdd ? (
|
key={i}
|
||||||
<button
|
onClick={() => canAdd && viewProfile(p.id!)}
|
||||||
onClick={() => viewProfile(p.id!)}
|
className={
|
||||||
className="flex items-center gap-2.5 flex-1 min-w-0 text-start active:scale-[0.99] transition"
|
"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">
|
}
|
||||||
{p.avatar}
|
>
|
||||||
</span>
|
<span className="grid size-9 shrink-0 place-items-center rounded-lg bg-navy-900 text-lg">
|
||||||
<span className="flex-1 min-w-0">
|
{p.avatar}
|
||||||
<span className="block text-sm font-semibold text-cream truncate">{p.name}</span>
|
</span>
|
||||||
{p.level > 0 && (
|
<span className="w-full truncate text-[11px] font-semibold text-cream">{p.name}</span>
|
||||||
<span className="block text-[10px] text-cream/45">
|
<span className="text-[9px] text-cream/45 leading-tight">
|
||||||
{t("common.level")} {p.level}
|
{tag ?? (p.level > 0 ? `${t("common.level")} ${p.level}` : "")}
|
||||||
</span>
|
</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 &&
|
{canAdd &&
|
||||||
(sent[p.id!] ? (
|
(sent[p.id!] ? (
|
||||||
<span className="text-[11px] text-teal-300 flex items-center gap-1 shrink-0">
|
<span className="mt-0.5 text-[10px] text-teal-300 flex items-center gap-0.5">
|
||||||
<Check className="size-3.5" />
|
<Check className="size-3" />
|
||||||
{t("match.sent")}
|
{t("match.sent")}
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<button
|
<span
|
||||||
onClick={() => add(p.id!)}
|
onClick={(e) => {
|
||||||
className="press-3d btn-gold rounded-lg px-2.5 py-1.5 text-[11px] font-bold flex items-center gap-1 shrink-0"
|
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")}
|
{t("match.addFriend")}
|
||||||
</button>
|
</span>
|
||||||
))}
|
))}
|
||||||
</div>
|
</button>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user