Add account based multiplayer hosting and bug report retention

This commit is contained in:
2026-10-10 16:24:34 +05:00
parent 9af71c85c2
commit fc6da6756d
33 changed files with 1538 additions and 102 deletions

View File

@@ -61,30 +61,22 @@ export async function multiplayerApi(
return response;
};
if (request.method === "POST" && path.length === 1) {
const account = await user();
if (!account)
throw new ServiceError("Log in to create a multiplayer room", 401);
const body = createRoomSchema.parse(await jsonBody(request));
await limit("multiplayer:create:" + accessHash, 20, 3600);
const account = await user();
if (account) await accountProfile(account);
const profile = await accountProfile(account);
const id = required(
await client.rpc("create_map_room", {
p_dataset: body.datasetId,
p_difficulty: body.difficulty,
p_name: body.displayName,
p_name: profile.display_name,
p_limit: body.playerLimit,
p_access_hash: accessHash,
p_owner: account?.id ?? null,
p_owner: account.id,
}),
);
if (account)
required(
await client
.from("multiplayer_players")
.update({ account_id: account.id })
.eq("room_id", id)
.eq("access_hash", accessHash)
.is("account_id", null)
.select("id"),
);
return respond({ id });
}
const id = z.string().uuid().parse(path[1]);
@@ -151,11 +143,18 @@ export async function multiplayerApi(
});
}
let payload: Record<string, string | number> = {};
let joiningAccount: string | null = null;
if (request.method === "POST" && path.length === 3) {
const input = await jsonBody(request);
if (action === "join") {
payload = { name: joinRoomSchema.parse(input).displayName };
await limit("multiplayer:join:" + accessHash, 40, 3600);
const account = await user();
if (account) {
const profile = await accountProfile(account);
payload.name = profile.display_name;
joiningAccount = account.id;
}
} else if (action === "guess") payload = roomGuessSchema.parse(input);
else if (action === "ready" || action === "next")
payload = roomRoundSchema.parse(input);
@@ -172,12 +171,19 @@ export async function multiplayerApi(
return NextResponse.json({ error: "Not found" }, { status: 404 });
const room = required(
await client.rpc("multiplayer_action", {
p_room: id,
p_access_hash: accessHash,
p_action: request.method === "GET" ? "view" : action,
p_payload: payload,
}),
action === "join"
? await client.rpc("join_multiplayer_room", {
p_room: id,
p_access_hash: accessHash,
p_owner: joiningAccount,
p_name: String(payload.name),
})
: await client.rpc("multiplayer_action", {
p_room: id,
p_access_hash: accessHash,
p_action: request.method === "GET" ? "view" : action,
p_payload: payload,
}),
) as unknown as RoomView;
if (room.status === "closed") {
try {
@@ -186,22 +192,6 @@ export async function multiplayerApi(
console.error("Closed Discord party remains queued for cleanup.");
}
}
if (action === "join" && room.you) {
const account = await user();
if (account) {
await accountProfile(account);
required(
await client
.from("multiplayer_players")
.update({ account_id: account.id })
.eq("id", room.you)
.eq("room_id", id)
.eq("access_hash", accessHash)
.is("account_id", null)
.select("id"),
);
}
}
if (action !== "media") {
const appearances = await multiplayerAppearance(
id,