mejorando leaderboard

This commit is contained in:
2025-08-29 10:49:54 -06:00
parent 90eb4aae2b
commit 4dc3d40123
2 changed files with 439 additions and 261 deletions

View File

@@ -909,6 +909,7 @@ async function sendPlayersActionsUpdate(client?: Response) {
const round = (entry as any)?.round;
const gameVariant = (entry as any)?.gameVariant || (entry as any)?.variant;
const role = (entry as any)?.role;
const timestamp = (entry as any)?.timestamp;
if (!ACTION_EVENTS.includes(kind)) continue;
if (!isActionMade(kind, role)) continue;
@@ -919,7 +920,8 @@ async function sendPlayersActionsUpdate(client?: Response) {
kind,
round,
gameVariant,
roomId
roomId,
timestamp
});
}
@@ -947,7 +949,136 @@ async function sendPlayersActionsUpdate(client?: Response) {
};
}).filter((p: any) => p.total > 0 || p.name);
const payload = { players };
// Build aggregated data across all players
const aggregatedCounts: Record<string, number> = Object.fromEntries(ACTION_EVENTS.map(k => [k, 0])) as any;
const aggregatedDetailedEvents: Array<{ kind: string; round?: number; gameVariant?: string; roomId?: string; playerUuid?: string; timestamp?: number }>[] = [] as any;
const roomsIndex: Record<string, { roomId: string; lastSeenIndex: number; lastEventAt?: number; messageCount: number }> = {};
let idxCounter = 0;
players.forEach((p: any) => {
// Sum counts
ACTION_EVENTS.forEach(k => {
const c = Number(p?.counts?.[k] || 0);
aggregatedCounts[k] = (aggregatedCounts[k] || 0) + c;
});
// Flatten detailed history and build rooms index
(Array.isArray(p?.detailedHistory) ? p.detailedHistory : []).forEach((ev: any) => {
const e = {
kind: String(ev?.kind || ''),
round: ev?.round != null ? Number(ev.round) : undefined,
gameVariant: (ev?.gameVariant || ev?.variant) ? String(ev.gameVariant || ev.variant) : undefined,
roomId: ev?.roomId ? String(ev.roomId) : undefined,
playerUuid: p.uuid,
timestamp: ev?.timestamp != null ? Number(ev.timestamp) : undefined
};
aggregatedDetailedEvents.push(e as any);
const rid = e.roomId || '';
if (rid) {
if (!roomsIndex[rid]) {
roomsIndex[rid] = { roomId: rid, lastSeenIndex: idxCounter, messageCount: 0 };
}
roomsIndex[rid].lastSeenIndex = idxCounter; // newer index wins
roomsIndex[rid].messageCount += 1;
if (e.timestamp) {
roomsIndex[rid].lastEventAt = Math.max(roomsIndex[rid].lastEventAt || 0, e.timestamp);
}
idxCounter += 1;
}
});
});
// Optionally include snapshot of active rooms similar to /dashboard-stream
let activeRoomsPayload: any | undefined = undefined;
try {
const rooms = await matchMaker.query({});
const activeRoomDetails: any[] = [];
const activeCounts: Record<string, number> = Object.fromEntries(ACTION_EVENTS.map(k => [k, 0]));
for (const room of rooms) {
if (room.name === 'game') {
try {
const detailData: any = await matchMaker.remoteRoomCall(room.roomId, "getState");
// Map systemMessages to detailed events
const msgs = Array.isArray(detailData?.systemMessages) ? detailData.systemMessages : [];
const systemMessages = msgs.map((m: any) => ({
kind: String(m?.kind || ''),
round: m?.round != null ? Number(m.round) : undefined,
gameVariant: (m?.gameVariant || m?.variant) ? String(m.gameVariant || m.variant) : undefined,
roomId: String(m?.roomId || room.roomId),
timestamp: m?.timestamp != null ? Number(m.timestamp) : undefined
}));
// Count events present in ACTION_EVENTS
systemMessages.forEach((m: any) => {
if (ACTION_EVENTS.includes(m.kind)) {
activeCounts[m.kind] = (activeCounts[m.kind] || 0) + 1;
}
});
activeRoomDetails.push({
roomId: room.roomId,
name: room.name,
metadata: {
gameStatus: room.metadata?.gameStatus || 'unknown',
currentVariant: room.metadata?.currentVariant || detailData?.variant || undefined,
currentRound: room.metadata?.currentRound || detailData?.round || undefined
},
players: (Array.isArray(detailData?.players) ? detailData.players : []).map((p: any) => ({
uuid: String(p?.uuid || p?.sessionId || ''),
name: p?.name || null,
color: p?.color || null
})),
systemMessages
});
} catch (error) {
// Ignore errors per room to not break the stream
}
}
}
activeRoomsPayload = {
rooms: activeRoomDetails,
counts: activeCounts
};
} catch (e) {
// If querying active rooms fails, omit activeRooms in payload
activeRoomsPayload = undefined;
}
// Build summary metrics
const playersWithNames = players.filter((p: any) => !!p.name).length;
let totalP1 = 0, cntP1 = 0;
let totalP2 = 0, cntP2 = 0;
players.forEach((p: any) => {
(Array.isArray(p?.roomScoreHistory) ? p.roomScoreHistory : []).forEach((rs: any) => {
(Array.isArray(rs?.scores) ? rs.scores : []).forEach((s: any) => {
if (s?.role === 'P1') { totalP1 += Number(s.score || 0); cntP1 += 1; }
else if (s?.role === 'P2') { totalP2 += Number(s.score || 0); cntP2 += 1; }
});
});
});
const avgP1 = cntP1 > 0 ? totalP1 / cntP1 : 0;
const avgP2 = cntP2 > 0 ? totalP2 / cntP2 : 0;
const overallCnt = cntP1 + cntP2;
const overallAvg = overallCnt > 0 ? (totalP1 + totalP2) / overallCnt : 0;
const payload = {
version: '1.0',
timestamp: Date.now(),
players,
aggregated: {
detailedEvents: aggregatedDetailedEvents,
counts: aggregatedCounts,
rooms: Object.values(roomsIndex)
},
activeRooms: activeRoomsPayload,
summary: {
totalPlayers: playersWithNames,
playersWithShame: players.filter((p: any) => Number(p?.shameTokens || 0) > 0).length,
playersWithoutShame: Math.max(0, playersWithNames - players.filter((p: any) => Number(p?.shameTokens || 0) > 0).length),
averageScore: {
p1: Number(avgP1.toFixed(2)),
p2: Number(avgP2.toFixed(2)),
overall: Number(overallAvg.toFixed(2))
}
}
};
const message = `data: ${JSON.stringify(payload)}\n\n`;
if (client) {
if (!(client as any).destroyed) client.write(message);