Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion apps/realtime/src/pickup/match-stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ type MatchPlayerIndex = {
bySteamId: Map<string, PickupMatchPlayerRow>;
};

const latchedMatchGuidByMatchId = new Map<string, string>();

function asObject(value: unknown): Record<string, unknown> | null {
return value != null && typeof value === "object" && !Array.isArray(value)
? (value as Record<string, unknown>)
Expand Down Expand Up @@ -449,6 +451,27 @@ function parseSummaryUpdate(event: MatchStatsEvent) {
};
}

function isMatchGuidLockedEventType(eventType: string) {
return eventType === "PLAYER_STATS" || eventType === "MATCH_REPORT";
}

function readEventMatchGuid(event: MatchStatsEvent) {
return readString(
pickFirst(
event.data.MATCH_GUID,
event.data.matchGuid,
event.data.match_guid,
),
);
}

function isQuitPlayerStatsEvent(event: MatchStatsEvent) {
return (
event.type === "PLAYER_STATS" &&
(readBoolean(pickFirst(event.data.QUIT, event.data.quit)) ?? false)
);
}

async function insertRawEvent(
client: PoolClient,
matchId: string,
Expand Down Expand Up @@ -846,8 +869,21 @@ export async function applyPickupMatchStats(
const client = await pool.connect();
try {
await client.query("begin");
let latchedMatchGuid = latchedMatchGuidByMatchId.get(matchId) ?? null;

for (const event of parsed.events) {
if (isMatchGuidLockedEventType(event.type)) {
const eventMatchGuid = readEventMatchGuid(event);
if (latchedMatchGuid) {
if (eventMatchGuid !== latchedMatchGuid) {
continue;
}
} else if (eventMatchGuid) {
latchedMatchGuid = eventMatchGuid;
latchedMatchGuidByMatchId.set(matchId, eventMatchGuid);
}
}

await insertRawEvent(client, matchId, event);

if (
Expand All @@ -862,7 +898,7 @@ export async function applyPickupMatchStats(
await upsertStatsSummary(client, matchId, event);
}

if (event.type === "PLAYER_STATS") {
if (event.type === "PLAYER_STATS" && !isQuitPlayerStatsEvent(event)) {
await upsertPlayerStats(client, matchId, event, index);
}

Expand Down
25 changes: 22 additions & 3 deletions apps/web/components/pages/pickup-match-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ const weaponChartColors: Record<string, string> = {
GRENADE: "#029012",
NAILGUN: "#ec4899",
BFG: "#14b8a6",
GAUNTLET: "#f43f5e",
GAUNTLET: "#00FFFF",
CHAINGUN: "#64748b",
}

Expand Down Expand Up @@ -235,6 +235,14 @@ function formatNumber(value: number | null) {
return value == null ? "-" : value.toLocaleString()
}

function truncateLabel(value: string, maxLength: number) {
if (value.length <= maxLength) {
return value
}

return `${value.slice(0, Math.max(0, maxLength - 1))}\u2026`
}

function formatAccuracy(stat: PickupMatchWeaponStat) {
if (typeof stat.accuracy === "number") {
return `${Math.round(stat.accuracy)}%`
Expand Down Expand Up @@ -634,14 +642,24 @@ function PlayerAxisTick({
.toUpperCase()
: ""
const profileHref = player ? getPlayerProfileHref(player) : null
const displayLabel = truncateLabel(player?.label ?? payload?.value ?? "", 14)
const avatarClipId = player ? `weapon-chart-avatar-${player.id}` : null

if (typeof x !== "number" || typeof y !== "number") {
return null
}

return (
<g transform={`translate(${x},${y})`}>
{avatarClipId ? (
<defs>
<clipPath id={avatarClipId}>
<circle cx={-118} cy={0} r="14" />
</clipPath>
</defs>
) : null}
<a href={profileHref ?? undefined}>
<title>{player?.label ?? payload?.value ?? ""}</title>
<rect
fill="transparent"
height="34"
Expand All @@ -655,6 +673,7 @@ function PlayerAxisTick({
height="28"
href={player.avatarUrl}
preserveAspectRatio="xMidYMid slice"
clipPath={avatarClipId ? `url(#${avatarClipId})` : undefined}
width="28"
x="-132"
y="-14"
Expand Down Expand Up @@ -695,7 +714,7 @@ function PlayerAxisTick({
x={flagSrc ? -67 : -95}
y={5}
>
{player?.label ?? payload?.value ?? ""}
{displayLabel}
</text>
</a>
</g>
Expand Down Expand Up @@ -822,7 +841,7 @@ function WeaponDamageChart({ detail }: { detail: PickupMatchDetail }) {
dataKey="playerKey"
tick={<PlayerAxisTick players={chart.players} />}
tickLine={false}
tickMargin={10}
tickMargin={22}
type="category"
width={150}
/>
Expand Down
6 changes: 4 additions & 2 deletions devenv.nix
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,10 @@ in
fi

if [ ! -f .devenv/state/pnpm-install.stamp ] || [ pnpm-lock.yaml -nt .devenv/state/pnpm-install.stamp ]; then
echo "[devenv] installing workspace dependencies"
pnpm install --frozen-lockfile
echo "[devenv] installing web + realtime workspace dependencies"
pnpm install --frozen-lockfile \
--filter @qltracker/web... \
--filter @qltracker/realtime...
touch .devenv/state/pnpm-install.stamp
fi

Expand Down
Loading