rematch
This commit is contained in:
@@ -6,8 +6,13 @@ import { authenticateMatchmakingRequest, registerAuthRoutes } from './auth_bridg
|
||||
import {
|
||||
getPlayerLast10MatchRecord,
|
||||
insertMatchForNewRoom,
|
||||
insertRematchMatch,
|
||||
loadUsernamesForUserPair,
|
||||
MATCH_ENTRY_FEE_RC,
|
||||
registerMatchRoutes,
|
||||
updateMatchUserBlue,
|
||||
type CreateRematchRoomFn,
|
||||
type MatchRoomSuccessEnvelope,
|
||||
} from './matches';
|
||||
import {
|
||||
initServerLog,
|
||||
@@ -66,7 +71,6 @@ const gameName = configuredGame.name || "game";
|
||||
logVerbose(logLevel, typedSettings);
|
||||
|
||||
registerAuthRoutes(app, typedSettings);
|
||||
registerMatchRoutes(app, typedSettings);
|
||||
|
||||
let Rooms: Room[] = [];
|
||||
let Queue: QueueEntry[] = [];
|
||||
@@ -89,6 +93,83 @@ function removeUserFromQueue(userId: number): void {
|
||||
}
|
||||
}
|
||||
|
||||
/** GET / JSON only: same order as match DB — first joined = red, second = blue. Always includes `entry_fee`. */
|
||||
function roomResponseForViewer(room: Room, viewerUserId: number): Room {
|
||||
const idx = room.Players.findIndex((p) => p.UserId === viewerUserId);
|
||||
const your_team: 'red' | 'blue' | null = idx === 0 ? 'red' : idx === 1 ? 'blue' : null;
|
||||
const entry_fee = room.entry_fee ?? MATCH_ENTRY_FEE_RC;
|
||||
return { ...room, entry_fee, your_team };
|
||||
}
|
||||
|
||||
/** Same envelope as `POST /internal/rematch` success: both sides when seated, else `null` for open slot. */
|
||||
function roomMatchSuccessEnvelope(room: Room): MatchRoomSuccessEnvelope {
|
||||
const entry_fee = room.entry_fee ?? MATCH_ENTRY_FEE_RC;
|
||||
const redId = room.Players[0]?.UserId;
|
||||
const blueId = room.Players[1]?.UserId;
|
||||
return {
|
||||
ok: true,
|
||||
entry_fee,
|
||||
for_red: redId != null ? roomResponseForViewer(room, redId) : null,
|
||||
for_blue: blueId != null ? roomResponseForViewer(room, blueId) : null,
|
||||
};
|
||||
}
|
||||
|
||||
const createRematchRoom: CreateRematchRoomFn = async ({ userRedId, userBlueId, entryFee }) => {
|
||||
return runMatchmakerExclusive(async () => {
|
||||
const names = await loadUsernamesForUserPair(typedSettings, userRedId, userBlueId);
|
||||
if (!names) {
|
||||
return { ok: false, status: 404, error: 'One or both players not found' };
|
||||
}
|
||||
|
||||
for (const room of Rooms) {
|
||||
room.Players = room.Players.filter((p) => p.UserId !== userRedId && p.UserId !== userBlueId);
|
||||
}
|
||||
for (let i = Rooms.length - 1; i >= 0; i--) {
|
||||
if (Rooms[i]!.Players.length === 0) {
|
||||
Rooms.splice(i, 1);
|
||||
}
|
||||
}
|
||||
removeUserFromQueue(userRedId);
|
||||
removeUserFromQueue(userBlueId);
|
||||
|
||||
const matchId = await insertRematchMatch(typedSettings, userRedId, userBlueId, entryFee);
|
||||
if (matchId == null) {
|
||||
return { ok: false, status: 500, error: 'Failed to create match row' };
|
||||
}
|
||||
|
||||
const newPort = GetRandomPort(typedSettings.port_range_min, typedSettings.port_range_max);
|
||||
const [l10Red, l10Blue] = await Promise.all([
|
||||
getPlayerLast10MatchRecord(typedSettings, userRedId),
|
||||
getPlayerLast10MatchRecord(typedSettings, userBlueId),
|
||||
]);
|
||||
|
||||
const redName = names.nameById.get(userRedId)!;
|
||||
const blueName = names.nameById.get(userBlueId)!;
|
||||
|
||||
const newRoom: Room = {
|
||||
Players: [
|
||||
{ Name: redName, LastSeen: Date.now(), UserId: userRedId, ...l10Red },
|
||||
{ Name: blueName, LastSeen: Date.now(), UserId: userBlueId, ...l10Blue },
|
||||
],
|
||||
GameName: gameName,
|
||||
Port: newPort,
|
||||
InitTime: Date.now(),
|
||||
entry_fee: entryFee,
|
||||
match_id: matchId,
|
||||
instance_started: true,
|
||||
};
|
||||
Rooms.push(newRoom);
|
||||
OpenGameInstance(configuredGame.exe, newRoom.Port, newRoom.match_id);
|
||||
recordHistory(
|
||||
`Rematch room port ${newPort} match ${matchId} — ${redName} vs ${blueName} (entry_fee ${entryFee})`
|
||||
);
|
||||
|
||||
return roomMatchSuccessEnvelope(newRoom);
|
||||
});
|
||||
};
|
||||
|
||||
registerMatchRoutes(app, typedSettings, { createRematchRoom });
|
||||
|
||||
app.get('/settings', (req: Request, res: Response) => {
|
||||
if (req.query.password !== typedSettings.password) {
|
||||
res.send("403 Unauthorized");
|
||||
@@ -221,7 +302,7 @@ app.get('/', async (req: Request, res: Response) => {
|
||||
|
||||
if (joinedRoom !== null) { // Already in a room. Stopping here
|
||||
removeUserFromQueue(userId);
|
||||
res.send(roomResponseForViewer(joinedRoom, userId));
|
||||
res.json(roomMatchSuccessEnvelope(joinedRoom));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -234,7 +315,8 @@ app.get('/', async (req: Request, res: Response) => {
|
||||
Players: [{ Name: username, LastSeen: Date.now(), UserId: userId, ...l10 }],
|
||||
GameName: gameName,
|
||||
Port: newPort,
|
||||
InitTime: Date.now()
|
||||
InitTime: Date.now(),
|
||||
entry_fee: MATCH_ENTRY_FEE_RC,
|
||||
};
|
||||
const matchId = await insertMatchForNewRoom(typedSettings, userId);
|
||||
if (matchId != null) {
|
||||
@@ -245,7 +327,7 @@ app.get('/', async (req: Request, res: Response) => {
|
||||
recordHistory(
|
||||
`${username} created a room on port ${newPort} (match id ${newRoom.match_id ?? '—'}) — waiting for opponent`
|
||||
);
|
||||
res.send(roomResponseForViewer(newRoom, userId));
|
||||
res.json(roomMatchSuccessEnvelope(newRoom));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -267,7 +349,7 @@ app.get('/', async (req: Request, res: Response) => {
|
||||
`new room created with port ${room.Port} and matchId ${room.match_id ?? '—'} for ${p0.Name} and ${p1.Name}`
|
||||
);
|
||||
}
|
||||
res.send(roomResponseForViewer(room, userId));
|
||||
res.json(roomMatchSuccessEnvelope(room));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -362,6 +444,7 @@ app.get('/reopen', async (req: Request, res: Response) => {
|
||||
GameName: gameName,
|
||||
Port: port,
|
||||
InitTime: Date.now(),
|
||||
entry_fee: MATCH_ENTRY_FEE_RC,
|
||||
instance_started: true,
|
||||
};
|
||||
const matchId = await insertMatchForNewRoom(typedSettings);
|
||||
@@ -384,13 +467,6 @@ app.get('/reopen', async (req: Request, res: Response) => {
|
||||
}
|
||||
});
|
||||
|
||||
/** GET / JSON only: same order as match DB — first joined = red, second = blue. */
|
||||
function roomResponseForViewer(room: Room, viewerUserId: number): Room {
|
||||
const idx = room.Players.findIndex((p) => p.UserId === viewerUserId);
|
||||
const your_team: 'red' | 'blue' | null = idx === 0 ? 'red' : idx === 1 ? 'blue' : null;
|
||||
return { ...room, your_team };
|
||||
}
|
||||
|
||||
app.use((err: unknown, _req: Request, res: Response, next: express.NextFunction) => {
|
||||
const e = err as { status?: number; type?: string };
|
||||
if (e.status === 400 && e.type === 'entity.parse.failed') {
|
||||
|
||||
Reference in New Issue
Block a user