/* Galvanic Corrosion - Rec Room custom server for communities. Copyright (C) 2025 @zombieb (Discord / proxnet Gitea) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ import Logging from "@proxnet/undead-logging"; import { APIUtils, NoBody } from "../../apiutils.ts"; import Matchmaking from "../../data/live/base.ts"; import { MatchmakingErrorCode } from "../../data/live/types.ts"; import { AuthType } from "../../data/users.ts"; import express from "express"; import { z } from "zod"; const log = new Logging("MatchGotoRoute"); export const route = APIUtils.createRouter('/goto'); interface MatchmakingParams { roomName?: string, subRoomName?: string } const ProperCaseBooleanSchema = z.preprocess((val) => { if (val === "True") return true; if (val === "False") return false; if (typeof val === "boolean") return val; // allow raw booleans too return val; // will fail validation }, z.boolean()); interface MatchmakingOptions { CreatePrivateInstance?: string, BypassMovementModeRestriction?: string } route.router.post('/room/:roomName', APIUtils.Authentication, APIUtils.AuthenticationType(AuthType.Game), APIUtils.startTimer, express.urlencoded({ extended: true }), APIUtils.validateRequestBody(z.object({ CreatePrivateInstance: ProperCaseBooleanSchema.optional(), BypassMovementModeRestriction: ProperCaseBooleanSchema.optional() })), async (rq: express.Request, rs: express.Response, nxt: express.NextFunction) => { log.d(`Player ${rs.locals.profile.getId()} is requesting to matchmake\n Room: '${rq.params.roomName}'\n Body: ${JSON.stringify(rq.body)}`); if (!rq.params.roomName) { log.d('Matchmake failed: No room specified'); rs.json({ errorCode: MatchmakingErrorCode.NoSuchRoom }); return; } rs.json(await Matchmaking.matchmake({ profile: rs.locals.profile, roomName: rq.params.roomName, private: rq.body.CreatePrivateInstance ? rq.body.CreatePrivateInstance == 'True' : undefined })); nxt(); }, APIUtils.stopTimer ); route.router.post('/room/:roomName/:subRoomName', APIUtils.Authentication, APIUtils.AuthenticationType(AuthType.Game), APIUtils.startTimer, express.urlencoded({ extended: true }), async (rq: express.Request, rs: express.Response, nxt: express.NextFunction) => { log.d(`Player ${rs.locals.profile.getId()} is requesting to matchmake\n Room: '${rq.params.roomName}'\n Subroom: '${rq.params.subRoomName}'\n Body: ${JSON.stringify(rq.body)}`); if (!rq.params.roomName) { log.d('Matchmake failed: No room specified'); rs.json({ errorCode: MatchmakingErrorCode.NoSuchRoom }); return; } rs.json(await Matchmaking.matchmake({ profile: rs.locals.profile, roomName: rq.params.roomName, subRoomName: rq.params.subRoomName, private: rq.body.CreatePrivateInstance ? rq.body.CreatePrivateInstance == 'True' : undefined })); nxt(); }, APIUtils.stopTimer );