From a33403be8685f291e71f9ccde13a2e81728a04ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9C=A8=20Audrey=20=E2=9C=A8?= Date: Wed, 12 Mar 2025 17:10:03 -0400 Subject: [PATCH] add duplicate progress emission detection --- .../achievements/achievement-processor.ts | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/libs/common/src/tools/achievements/achievement-processor.ts b/libs/common/src/tools/achievements/achievement-processor.ts index 0f2fc384c32..dde4a98463e 100644 --- a/libs/common/src/tools/achievements/achievement-processor.ts +++ b/libs/common/src/tools/achievements/achievement-processor.ts @@ -6,7 +6,14 @@ import { achievementsLocal$ as achievementsLog$, userActionIn$, } from "./inputs"; -import { AchievementEvent, AchievementValidator, UserActionEvent } from "./types"; +import { + AchievementEvent, + AchievementId, + AchievementProgressEvent, + AchievementValidator, + MetricId, + UserActionEvent, +} from "./types"; import { mapProgressByName } from "./util"; // the formal event processor @@ -25,16 +32,34 @@ function validate( concatMap(([[action, validators], captured]) => { const results: AchievementEvent[] = []; const progress = mapProgressByName(captured); + const measurements = new Map(); + // collect measurements for (const validator of validators) { const measured = validator.measure(action, progress); + measurements.set(validator.achievement, measured); results.push(...measured); + } - // update progress with the latest measurements - for (const m of measured) { - progress.set(m.achievement.name, m.achievement.value); + // update processor's internal progress values + const distinct = new Map(); + const entries = [...measurements.entries()].flatMap(([a, ms]) => + ms.map((m) => [a, m] as const), + ); + for (const [achievement, measured] of entries) { + const key = measured.achievement.name; + if (distinct.has(key)) { + const msg = `${achievement} failed to set set ${key} value already set by ${distinct.get(key)}`; + throw new Error(msg); } + distinct.set(key, achievement); + progress.set(measured.achievement.name, measured.achievement.value); + } + + // detect earned achievements + for (const validator of validators) { + const measured = measurements.get(validator.achievement) ?? []; const earned = validator.earn(measured, progress); results.push(...earned); }