mirror of
https://github.com/djdevin/recflare.git
synced 2026-10-25 23:18:51 -07:00
[api] votekick and uniform dorm kicks
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { deletePresence, getPresences, refreshInstanceFullness } from '@repo/domain'
|
||||
import { getPresences, movePlayerToDorm } from '@repo/domain'
|
||||
import { logger } from '@repo/hono-helpers'
|
||||
import { validateAndGetAccountId, validateAndGetRoles } from '@repo/jwt'
|
||||
|
||||
@@ -173,8 +173,11 @@ function banExpiry(
|
||||
* none. EPHEMERAL, because an offline player needs no frame — they meet the same screen at
|
||||
* `moderationBlockDetails` when they next sign in — and a queued one would fire again then.
|
||||
*
|
||||
* Their presence row is deleted (they read offline at once), and the instance they were in,
|
||||
* if any, has its fullness recomputed so a full room frees a slot.
|
||||
* They are moved into their own DORM rather than having their presence deleted — the same move
|
||||
* every kick makes, and the one place a banned player is still allowed to be: `match` lets them
|
||||
* matchmake there and nowhere else, which is how they reach this screen at all. Deleting the row
|
||||
* instead left the client arriving at the dorm not knowing where it was, loading it a second
|
||||
* time. The instance they were in, if any, frees a slot.
|
||||
*
|
||||
* Entirely best-effort. The ban row is already committed by the time this runs; a hub hiccup
|
||||
* or a missing presence must not fail a ban that has been handed down.
|
||||
@@ -188,9 +191,10 @@ async function kickBannedPlayer(c: Context<App>, report: ReportRow, moderatorId:
|
||||
// Offline: nothing to eject and nobody to tell. The sign-in check has them.
|
||||
if (!presence) return
|
||||
|
||||
await deletePresence(c.env.DB, playerId)
|
||||
// Read before the move, so the frame names the session they were thrown out of rather
|
||||
// than the dorm they landed in. `movePlayerToDorm` recomputes that instance's fullness.
|
||||
const gameSessionId = presence.roomInstance?.roomInstanceId
|
||||
if (gameSessionId !== undefined) await refreshInstanceFullness(c.env.DB, gameSessionId)
|
||||
await movePlayerToDorm(c.env.DB, playerId)
|
||||
|
||||
const block = banBlockDetails(report)
|
||||
const frame: ModerationKickPayload = {
|
||||
|
||||
@@ -9,6 +9,9 @@ import {
|
||||
setPresence,
|
||||
} from '@repo/domain/src/presence-db'
|
||||
import { ROOM_INSTANCE_SCHEMA_DDL } from '@repo/domain/src/room-instance-db'
|
||||
// Banning a player moves them into their own dorm, which is a room (created on demand) with
|
||||
// a subroom — so those tables have to be here, as they are on the shared database.
|
||||
import { ROOM_SCHEMA_DDL, SUBROOM_SCHEMA_DDL } from '@repo/domain/src/rooms-db'
|
||||
import { generateToken } from '@repo/jwt'
|
||||
|
||||
import {
|
||||
@@ -87,6 +90,8 @@ beforeAll(async () => {
|
||||
for (const stmt of REPORT_SCHEMA_DDL) await env.DB.prepare(stmt).run()
|
||||
for (const stmt of WARNING_SCHEMA_DDL) await env.DB.prepare(stmt).run()
|
||||
for (const stmt of ROOM_INSTANCE_SCHEMA_DDL) await env.DB.prepare(stmt).run()
|
||||
for (const stmt of ROOM_SCHEMA_DDL) await env.DB.prepare(stmt).run()
|
||||
for (const stmt of SUBROOM_SCHEMA_DDL) await env.DB.prepare(stmt).run()
|
||||
})
|
||||
|
||||
// Web signup is open, but only behind the Turnstile check. These pin the closed door:
|
||||
@@ -947,12 +952,15 @@ it('throws a banned player out of the instance they are standing in', async () =
|
||||
Duration: 3 * 86_400,
|
||||
})
|
||||
|
||||
// And their presence row is gone, so they read offline at once and the instance frees
|
||||
// a slot.
|
||||
// And they are out of that instance — moved into their own DORM, not deleted: `match`
|
||||
// lets a banned player matchmake there and nowhere else, so it is where they read the
|
||||
// block screen, and with no presence at all the client loads the dorm a second time.
|
||||
const presence = await env.DB.prepare(
|
||||
"SELECT COUNT(*) AS n FROM presence WHERE json_extract(data, '$.accountId') = 8190"
|
||||
).first<{ n: number }>()
|
||||
expect(presence?.n).toBe(0)
|
||||
"SELECT json_extract(data, '$.roomInstance.roomInstanceId') AS instance FROM presence WHERE json_extract(data, '$.accountId') = 8190"
|
||||
).first<{ instance: number | null }>()
|
||||
expect(presence).not.toBeNull()
|
||||
// The OFFLINE dorm sentinel — a room the client loads locally, with no session behind it.
|
||||
expect(presence?.instance).toBe(-2)
|
||||
})
|
||||
|
||||
// Online but not standing in any room — in a menu — is still banned from the game, and is
|
||||
|
||||
Reference in New Issue
Block a user