Add MineGeo gameplay systems and interface

This commit is contained in:
2026-10-10 10:27:47 +05:00
parent bf01d9801d
commit 9af71c85c2
47 changed files with 9954 additions and 93 deletions

View File

@@ -8,6 +8,12 @@ import { multiplayerAppearance } from "./multiplayer-appearance";
import { mediaUrls } from "./catalog";
import { requestOrigin } from "./request-origin";
import { ServiceError } from "./service-error";
import { scheduleDiscordCleanup } from "./discord-cleanup-scheduler";
import {
discordPartyReady,
discordAfterResponse,
partyAnnouncement,
} from "./discord-announcements";
import {
createRoomSchema,
joinRoomSchema,
@@ -83,6 +89,35 @@ export async function multiplayerApi(
}
const id = z.string().uuid().parse(path[1]);
const action = path[2] ?? "view";
if (action === "discord" && path.length === 3 && request.method === "POST") {
const view = required(
await client.rpc("multiplayer_action", {
p_room: id,
p_access_hash: accessHash,
p_action: "view",
p_payload: {},
}),
) as unknown as RoomView;
if (!savedSecret || !view.you || view.you !== view.hostId)
throw new ServiceError("Only the room owner can publish this party", 403);
z.object({})
.strict()
.parse(await jsonBody(request));
if (!discordPartyReady())
throw new ServiceError(
"Discord party sharing is not configured yet",
503,
);
await limit("multiplayer:discord:" + accessHash, 5, 3600);
required(
await client.rpc("publish_discord_party", {
p_room: id,
p_access_hash: accessHash,
}),
);
discordAfterResponse(id);
return respond({ ok: true });
}
if (
action === "chat" &&
path.length === 3 &&
@@ -144,6 +179,13 @@ export async function multiplayerApi(
p_payload: payload,
}),
) as unknown as RoomView;
if (room.status === "closed") {
try {
await scheduleDiscordCleanup(room.id);
} catch {
console.error("Closed Discord party remains queued for cleanup.");
}
}
if (action === "join" && room.you) {
const account = await user();
if (account) {
@@ -170,7 +212,10 @@ export async function multiplayerApi(
...appearances.get(player.id),
}));
}
if (action !== "media") return respond(room);
if (action !== "media") {
room.discord = await partyAnnouncement(room);
return respond(room);
}
if (!room.you) throw new ServiceError("Join this room to play", 403);
if (["lobby", "closed"].includes(room.status))
throw new ServiceError("This round is not available yet", 409);