This commit is contained in:
API runner
2026-09-04 19:11:49 +00:00
parent b933f09187
commit 3d063af9ae
130 changed files with 4876 additions and 53 deletions
+74 -8
View File
@@ -14,8 +14,11 @@ import {
getSettingsTableDict,
MATCH_ENTRY_FEE_RC,
registerMatchRoutes,
getAdminMmrLeaderboard,
updateMatchUserBlue,
type CreateRematchRoomFn,
type OnMatchSettledFn,
type OnBothPlayersConnectedFn,
type MatchRoomSuccessEnvelope,
} from './matches';
import {
@@ -97,6 +100,38 @@ function removeUserFromQueue(userId: number): void {
}
}
function removeRoomByMatchId(matchId: number): void {
const index = Rooms.findIndex((room) => room.match_id === matchId);
if (index < 0) return;
const room = Rooms[index]!;
const names = room.Players.map((p) => p.Name).join(', ');
Rooms.splice(index, 1);
logInfo('Room removed after match settled', { match_id: matchId, port: room.Port });
recordHistory(
`Room on port ${room.Port} removed (match ${matchId} settled) — had: ${names || 'nobody'}`
);
}
const onMatchSettled: OnMatchSettledFn = async (matchId) => {
await runMatchmakerExclusive(async () => {
removeRoomByMatchId(matchId);
});
};
function markRoomBothConnected(matchId: number): void {
const room = Rooms.find((r) => r.match_id === matchId);
if (!room || room.both_connected) return;
room.both_connected = true;
logInfo('Both players connected to match', { match_id: matchId, port: room.Port });
recordHistory(`Both players connected on port ${room.Port} (match ${matchId})`);
}
const onBothPlayersConnected: OnBothPlayersConnectedFn = async (matchId) => {
await runMatchmakerExclusive(async () => {
markRoomBothConnected(matchId);
});
};
/** GET / JSON only: same order as match DB — first joined = red, second = blue. Always includes `entry_fee`. */
function roomResponseForViewer(room: Room, viewerUserId: number, betFeePercent: number): Room {
const idx = room.Players.findIndex((p) => p.UserId === viewerUserId);
@@ -176,7 +211,7 @@ const createRematchRoom: CreateRematchRoomFn = async ({ userRedId, userBlueId, e
});
};
registerMatchRoutes(app, typedSettings, { createRematchRoom });
registerMatchRoutes(app, typedSettings, { createRematchRoom, onMatchSettled, onBothPlayersConnected });
app.get('/settings', async (req: Request, res: Response) => {
if (req.query.password !== typedSettings.password) {
@@ -242,6 +277,21 @@ app.get('/admin/history', (req: Request, res: Response) => {
res.json({ ok: true, entries });
});
/** Hidden MMR leaderboard (not shown to players). */
app.get('/admin/mmr', async (req: Request, res: Response) => {
if (req.query.password !== typedSettings.password) {
res.status(403).send('403 Unauthorized');
return;
}
const limit = parseAdminLinesParam(req.query.limit, 100, 500);
const result = await getAdminMmrLeaderboard(typedSettings, limit);
if (!result.ok) {
res.status(503).json({ ok: false, error: result.error });
return;
}
res.json({ ok: true, players: result.players });
});
app.get('/', async (req: Request, res: Response) => {
const auth = await authenticateMatchmakingRequest(req, typedSettings);
if (!auth.ok) {
@@ -306,12 +356,26 @@ app.get('/', async (req: Request, res: Response) => {
return !expired;
});
}
element.Players.forEach(player => {
if (player.UserId === userId) {
player.LastSeen = Date.now();
joinedRoom = element;
if (element.both_connected) {
const seated = element.Players.find((player) => player.UserId === userId);
if (seated) {
element.Players = element.Players.filter((player) => player.UserId !== userId);
logInfo(`${username} left connected match to matchmake again`, {
port: element.Port,
match_id: element.match_id ?? null,
});
recordHistory(
`${username} left connected match on port ${element.Port} (match id ${element.match_id ?? '—'}) — matchmaking again`
);
}
});
} else {
element.Players.forEach((player) => {
if (player.UserId === userId) {
player.LastSeen = Date.now();
joinedRoom = element;
}
});
}
if (element.Players.length === 0) {
// This room is empty, remove it
@@ -426,8 +490,10 @@ app.get('/cancel', async (req: Request, res: Response) => {
const { userId } = auth.user;
await runMatchmakerExclusive(async () => {
const isInRoom = Rooms.some((room) => room.Players.some((player) => player.UserId === userId));
if (isInRoom) {
const isInWaitingRoom = Rooms.some(
(room) => !room.instance_started && room.Players.some((player) => player.UserId === userId)
);
if (isInWaitingRoom) {
res.status(409).send("Can't cancel while already in a room");
return;
}