This repository has been archived on 2026-03-19. You can view files and clone it, but cannot push or open issues or pull requests.
Files
galvanic-corrosion/src/routes/match/player.ts
zombieb 27b3754330 Rooms and matchmaking
* Added missing config (route) data
* Fetch room class, database hash
* Basic room querying
* Built-in room generation during first runtime
* Matchmaking response base and notes for myself, later today
* Instance fixes
* Challenge and quick play routes
(unused for now)
* Rooms route (untested)
* Matchmaking goto route
* Avatar route addition
* Settings/set route
2025-04-02 00:27:10 -04:00

107 lines
3.3 KiB
TypeScript

/* Galvanic Corrosion - Rec Room custom server for communities.
<https://gitea.proxnet.dev/zombieb-galvanic-corrosion>
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 <https://www.gnu.org/licenses/>. */
import { z } from "zod";
import { APIUtils, NoBody } from "../../apiutils.ts";
import express from "express";
import Matchmaking from "../../data/live/base.ts";
import Presence, { PresenceExport } from "../../data/live/presence.ts";
import { AuthType } from "../../data/users.ts";
import Logging from "@proxnet/undead-logging";
import UnifiedProfile from "../../data/profiles.ts";
const log = new Logging("MatchPlayerRoute");
export const route = APIUtils.createRouter('/player');
interface BaseLoginLock {
LoginLock: string
}
const LoginSchema = z.object({
LoginLock: z.string().uuid("LoginLock must be a UUIDv4")
});
route.router.get('/',
APIUtils.Authentication,
APIUtils.AuthenticationType(AuthType.Game),
APIUtils.validateQuery(z.object({ id: z.union([z.string(), z.array(z.string())]) })),
async (rq: express.Request<NoBody, PresenceExport[], NoBody, { id: string[] | string }>, rs) => {
let ids: number[] = [];
if (typeof rq.query.id == 'object') ids = rq.query.id.map(val => parseInt(val));
else ids.push(parseInt(rq.query.id));
ids = ids.filter(val => !isNaN(val));
const presExport: PresenceExport[] = [];
for (const id of ids) {
const pres = await Presence.get(UnifiedProfile.get(id));
await pres.update();
presExport.push(await pres.export());
}
rs.json(presExport);
log.d(JSON.stringify(presExport));
}
)
route.router.post('/login',
APIUtils.Authentication,
APIUtils.AuthenticationType(AuthType.Game),
express.urlencoded({extended: true}),
APIUtils.validateRequestBody(LoginSchema),
(rq: express.Request<NoBody, NoBody, BaseLoginLock>, rs: express.Response) => {
Matchmaking.createLoginLock(rs.locals.profile, rq.body.LoginLock);
Presence.create(rs.locals.profile);
rs.sendStatus(200);
},
);
route.router.post('/logout',
APIUtils.Authentication,
APIUtils.AuthenticationType(AuthType.Game),
express.urlencoded({extended: true}),
APIUtils.validateRequestBody(LoginSchema),
(_rq, rs) => {
Matchmaking.deleteLoginLock(rs.locals.profile);
rs.sendStatus(200);
}
)
route.router.post('/heartbeat',
APIUtils.Authentication,
APIUtils.AuthenticationType(AuthType.Game),
express.urlencoded({extended: true}),
APIUtils.validateRequestBody(LoginSchema),
APIUtils.LoginLock,
async (_rq, rs) => {
const pres = await Presence.get(rs.locals.profile);
await pres.update();
rs.json(await pres.export());
}
);