The host clears seats and closes rooms
Two lobby-lifecycle gaps from tonight's duels (a token lost to a client bug left an unkickable ghost seat holding a chair in VQJW). kickSeat: the host removes any other seat from an unstarted room — the kick is a ledger line so restarts replay it, and a kicked live socket is set adrift with notice. abandonRoom: the host dissolves a lobby or a finished game; every member is notified and detached, and the ledger is archived to rooms-abandoned/ — moved, never deleted. The lobby shows hosts a ✕ per seat and an abandon-room control. Proven live: kick with notice, kick surviving a server restart, and abandonment archiving its ledger. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
This commit is contained in:
co-authored by
Claude Fable 5
parent
4c7633097b
commit
9af7bd80ce
@@ -1812,6 +1812,10 @@
|
||||
<span class="dot" style:background="#b3a687"></span>
|
||||
{/if}
|
||||
{p}{p === net.hostId ? " — host" : ""}{net.roomBots[p] ? ` ⚙ ${net.roomBots[p]}` : chosen === undefined ? " — choosing…" : ""}
|
||||
{#if net.you === net.hostId && p !== net.hostId}
|
||||
<button class="stamp tiny kick" title="clear this seat"
|
||||
onclick={() => net.kickSeat(p)}>✕</button>
|
||||
{/if}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
@@ -1835,6 +1839,8 @@
|
||||
{/each}
|
||||
</div>
|
||||
{#if net.you === net.hostId}
|
||||
<button class="stamp tiny abandon" title="dissolve this room for everyone"
|
||||
onclick={() => net.abandonRoom()}>abandon room</button>
|
||||
{#if net.players.length < 6}
|
||||
<span class="bot-row">
|
||||
<span class="bot-label">⚙ seat a</span>
|
||||
@@ -2462,6 +2468,8 @@
|
||||
text-transform: uppercase;
|
||||
color: #8d8672;
|
||||
}
|
||||
.kick { margin-left: 0.4rem; color: #a04545; }
|
||||
.abandon { margin: 0.4rem 0; color: #a04545; border-color: #a04545; }
|
||||
.mast-version {
|
||||
font-family: "Courier Prime", monospace;
|
||||
font-size: 0.65rem;
|
||||
|
||||
@@ -447,6 +447,14 @@ class Net {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "kicked":
|
||||
this.log = [...this.log, { text: `— the host cleared your seat in ${msg.roomId} —`, turn: null, notable: false }];
|
||||
this.leaveLocal();
|
||||
break;
|
||||
case "roomAbandoned":
|
||||
this.log = [...this.log, { text: `— the host closed room ${msg.roomId} —`, turn: null, notable: false }];
|
||||
this.leaveLocal();
|
||||
break;
|
||||
case "transferCode":
|
||||
this.transferCode = { code: msg.code, expiresAt: msg.expiresAt };
|
||||
break;
|
||||
@@ -565,6 +573,14 @@ class Net {
|
||||
this.send({ type: "addBot", ...(style ? { style } : {}), ...(tier ? { tier } : {}) });
|
||||
}
|
||||
|
||||
kickSeat(name: string): void {
|
||||
this.send({ type: "kickSeat", name });
|
||||
}
|
||||
|
||||
abandonRoom(): void {
|
||||
this.send({ type: "abandonRoom" });
|
||||
}
|
||||
|
||||
rollTableDie(): void {
|
||||
this.send({ type: "rollDie" });
|
||||
}
|
||||
@@ -636,6 +652,19 @@ class Net {
|
||||
}
|
||||
|
||||
/** Forget the remembered seat and return to the lobby. */
|
||||
/** Client-side teardown when the SERVER detached us (kick, abandon). */
|
||||
leaveLocal(): void {
|
||||
localStorage.removeItem(SEAT_KEY);
|
||||
this.roomId = null;
|
||||
this.roomIdPending = null;
|
||||
this.view = null;
|
||||
this.started = false;
|
||||
this.players = [];
|
||||
this.token = null;
|
||||
this.spectating = false;
|
||||
this.audience = 0;
|
||||
}
|
||||
|
||||
leave(): void {
|
||||
this.send({ type: "leave" }); // detach server-side too (frees a gallery seat)
|
||||
localStorage.removeItem(SEAT_KEY);
|
||||
|
||||
Reference in New Issue
Block a user