feat: migrate old scoreDerivers

This commit is contained in:
zk
2026-03-28 22:18:25 +00:00
parent 4cff1fd5d5
commit 9aa3aee2a7
35 changed files with 70 additions and 219 deletions
+9 -7
View File
@@ -36,16 +36,18 @@ return p.isBetween(0, 100)(rate);
},
```
## `derivers`
## `scoreDeriver`
Any derived metrics you declared need derivers implemented here. This is a function
that takes in the provided metrics and the chart for this score and should return
the metric value we expect.
Any derived metrics you declared are produced by a single function
`(scoreData, chart) => derivedMetrics` that returns all derived fields at once.
!!! example
`ts
percent: (metrics, chart) => (100 * metrics.score) / (chart.data.notecount * 2);
`
```ts
(scoreData, chart) => ({
percent: (100 * scoreData.score) / (chart.data.notecount * 2),
grade: GetGrade(G, scoreData.score),
});
```
## `scoreCalcs`, `sessionCalcs`, `profileCalcs`
@@ -1,12 +1,11 @@
import type {
__OLD_KILL_GPTDerivers,
ChartSpecificMetricValidator,
GPTChartSpecificMetricValidators,
GPTClassDerivers,
GPTGoalFormatters,
GPTGoalProgressFormatters,
GPTNewCalcs,
GPTNewDeriver,
GPTScoreDeriver,
GPTNewProfileCalcs,
GPTNewSessionCalcs,
GPTProfileCalculators,
@@ -58,21 +57,7 @@ function calculateIIDXLikePercent(exScore: integer, notecount: integer) {
type IIDXLikes = GPTStrings["bms" | "iidx" | "pms"];
/**
* Derivers for both IIDX SP and DP.
*
* and BMS. and PMS. They use the same things.
*/
export const IIDXLIKE_DERIVERS: __OLD_KILL_GPTDerivers<IIDXLikes> = {
percent: ({ score }, chart) => calculateIIDXLikePercent(score, chart.data.notecount),
grade: ({ score }, chart) => {
const percent = calculateIIDXLikePercent(score, chart.data.notecount);
return GetGrade(IIDXLIKE_GBOUNDARIES, percent);
},
};
export const IIDXLIKE_NEW_DERIVER: GPTNewDeriver<IIDXLikes> = (scoreData, chart) => ({
export const IIDXLIKE_SCORE_DERIVER: GPTScoreDeriver<IIDXLikes> = (scoreData, chart) => ({
percent: calculateIIDXLikePercent(scoreData.score, chart.data.notecount),
grade: IIDXLikeGetGrade(scoreData.score, chart.data.notecount),
});
@@ -97,11 +82,7 @@ export const IIDXLIKE_SCORE_VALIDATORS: Array<ScoreValidator<IIDXLikes>> = [
type SDVXLikes = GPTStrings["sdvx" | "usc"];
export const SDVXLIKE_DERIVERS: __OLD_KILL_GPTDerivers<SDVXLikes> = {
grade: ({ score }) => GetGrade(SDVXLIKE_GBOUNDARIES, score),
};
export const SDVXLIKE_NEW_DERIVER: GPTNewDeriver<SDVXLikes> = (scoreData, _chart) => ({
export const SDVXLIKE_SCORE_DERIVER: GPTScoreDeriver<SDVXLikes> = (scoreData, _chart) => ({
grade: GetGrade(SDVXLIKE_GBOUNDARIES, scoreData.score),
});
@@ -48,7 +48,8 @@ t.test("Arcaea Implementation", (t) => {
t.test("Grade Deriver", (t) => {
const f = (score: number, expected: string) =>
t.equal(
ARCAEA_IMPL.derivers.grade(dmf(baseMetrics, { score }), TestingArcaeaSheriruthFTR),
ARCAEA_IMPL.scoreDeriver(dmf(baseMetrics, { score }) as any, TestingArcaeaSheriruthFTR)
.grade,
expected,
`A score of ${score.toLocaleString()} should result in grade=${expected}.`,
);
@@ -23,10 +23,7 @@ export const ARCAEA_IMPL: GPTServerImplementation<GPTStrings["arcaea"]> = {
return true;
},
},
derivers: {
grade: ({ score }) => GetGrade(ARCAEA_GBOUNDARIES, score),
},
newDeriver: (scoreData, _chart) => ({
scoreDeriver: (scoreData, _chart) => ({
grade: GetGrade(ARCAEA_GBOUNDARIES, scoreData.score),
}),
newCalcs: (scoreData, _derivedData, chart) => ({
@@ -84,7 +84,7 @@ for (const [game, playtype, impl] of [
t.test("Percent", (t) => {
const f = (modifant: Partial<typeof baseMetrics>, expected: any, msg: string) =>
t.equal(
impl.derivers.percent(dmf(baseMetrics, modifant), chart as any),
impl.scoreDeriver(dmf(baseMetrics, modifant) as any, chart as any).percent,
expected,
msg,
);
@@ -105,10 +105,10 @@ for (const [game, playtype, impl] of [
t.test("Grade", (t) => {
const f = (percent: number, expected: any) =>
t.equal(
impl.derivers.grade(
dmf(baseMetrics, { score: percentToScore(percent) }),
impl.scoreDeriver(
dmf(baseMetrics, { score: percentToScore(percent) }) as any,
chart as any,
),
).grade,
expected,
`A percent of ${percent}% should result in grade=${expected}.`,
);
@@ -9,8 +9,7 @@ import {
GoalFmtPercent,
GoalOutOfFmtPercent,
GradeGoalFormatter,
IIDXLIKE_DERIVERS,
IIDXLIKE_NEW_DERIVER,
IIDXLIKE_SCORE_DERIVER,
IIDXLIKE_PB_RANKING_VALUES,
IIDXLIKE_SCORE_VALIDATORS,
IIDXLIKE_VALIDATORS,
@@ -41,8 +40,7 @@ const BMS_PMS_MERGERS: Array<PBMergeFunction<GPTStrings["bms" | "pms"]>> = [
// implementations. Nice.
const BMS_IMPL: GPTServerImplementation<GPTStrings["bms" | "pms"]> = {
derivers: IIDXLIKE_DERIVERS,
newDeriver: IIDXLIKE_NEW_DERIVER,
scoreDeriver: IIDXLIKE_SCORE_DERIVER,
newCalcs: SGL_NEW_CALCS,
newSessionCalcs: SGL_NEW_SESSION_CALCS,
newProfileCalcs: SGL_NEW_PROFILE_CALCS,
@@ -42,7 +42,7 @@ t.test("CHUNITHM Implementation", (t) => {
t.test("Grade Deriver", (t) => {
const f = (score: number, expected: any) =>
t.equal(
CHUNITHM_IMPL.derivers.grade(dmf(baseMetrics, { score }), CHUNITHMBBKKChart),
CHUNITHM_IMPL.scoreDeriver(dmf(baseMetrics, { score }) as any, CHUNITHMBBKKChart).grade,
expected,
`A score of ${score.toLocaleString()} should result in grade=${expected}.`,
);
@@ -11,10 +11,7 @@ import { GoalFmtScore, GoalOutOfFmtScore, GradeGoalFormatter } from "./_common";
export const CHUNITHM_IMPL: GPTServerImplementation<"chunithm:Single"> = {
chartSpecificValidators: {},
derivers: {
grade: ({ score }) => GetGrade(CHUNITHM_GBOUNDARIES, score),
},
newDeriver: (scoreData, _chart) => ({
scoreDeriver: (scoreData, _chart) => ({
grade: GetGrade(CHUNITHM_GBOUNDARIES, scoreData.score),
}),
newCalcs: (scoreData, _derivedData, chart) => ({
@@ -25,7 +25,7 @@ t.test("DDR Implementation", (t) => {
t.test("Grade", (t) => {
const f = (score: number, expected: any) =>
t.equal(
impl.derivers.grade(dmf(baseMetrics, { score }), TestingDDRSP as any),
impl.scoreDeriver(dmf(baseMetrics, { score }) as any, TestingDDRSP as any).grade,
expected,
`A score of ${score} should result in grade=${expected}.`,
);
@@ -312,16 +312,7 @@ export const DDR_IMPL: GPTServerImplementation<"ddr:DP" | "ddr:SP"> = {
return { flare: IsNullish(flarePoints) ? null : DeriveFlareClass(flarePoints) };
},
defaultMergeRefName: "Best Score",
derivers: {
grade: ({ score, lamp }) => {
if (lamp === "FAILED") {
return "E";
}
return GetGrade(DDR_GBOUNDARIES, score);
},
},
newDeriver: (scoreData, _chart) => ({
scoreDeriver: (scoreData, _chart) => ({
grade: scoreData.lamp === "FAILED" ? "E" : GetGrade(DDR_GBOUNDARIES, scoreData.score),
}),
newCalcs: (scoreData, _derivedData, chart) => {
@@ -46,7 +46,8 @@ for (const [playtype, impl] of [
t.test("Grade Deriver", (t) => {
const f = (percent: number, expected: any) =>
t.equal(
impl.derivers.grade(dmf(baseMetrics, { percent }), TestingGitadoraChart as any),
impl.scoreDeriver(dmf(baseMetrics, { percent }) as any, TestingGitadoraChart as any)
.grade,
expected,
`A percent of ${percent}% should result in grade=${expected}.`,
);
@@ -11,10 +11,7 @@ import { GoalFmtPercent, GoalOutOfFmtPercent, GradeGoalFormatter } from "./_comm
const GITADORA_IMPL: GPTServerImplementation<"gitadora:Dora" | "gitadora:Gita"> = {
chartSpecificValidators: {},
derivers: {
grade: ({ percent }) => GetGrade(GITADORA_GBOUNDARIES, percent),
},
newDeriver: (scoreData, _chart) => ({
scoreDeriver: (scoreData, _chart) => ({
grade: GetGrade(GITADORA_GBOUNDARIES, scoreData.percent),
}),
newCalcs: (scoreData, _derivedData, chart) => ({
@@ -39,7 +39,7 @@ t.test("IIDX Implementation", (t) => {
t.test("Percent", (t) => {
const f = (modifant: Partial<typeof baseMetrics>, expected: any, msg: string) =>
t.equal(
impl.derivers.percent(dmf(baseMetrics, modifant), Testing511SPA as any),
impl.scoreDeriver(dmf(baseMetrics, modifant) as any, Testing511SPA as any).percent,
expected,
msg,
);
@@ -64,10 +64,10 @@ t.test("IIDX Implementation", (t) => {
t.test("Grade", (t) => {
const f = (percent: number, expected: any) =>
t.equal(
impl.derivers.grade(
dmf(baseMetrics, { score: percentToScore(percent) }),
impl.scoreDeriver(
dmf(baseMetrics, { score: percentToScore(percent) }) as any,
Testing511SPA as any,
),
).grade,
expected,
`A percent of ${percent}% should result in grade=${expected}.`,
);
@@ -20,8 +20,7 @@ import {
GoalFmtPercent,
GoalOutOfFmtPercent,
GradeGoalFormatter,
IIDXLIKE_DERIVERS,
IIDXLIKE_NEW_DERIVER,
IIDXLIKE_SCORE_DERIVER,
IIDXLIKE_PB_RANKING_VALUES,
IIDXLIKE_SCORE_VALIDATORS,
IIDXLIKE_VALIDATORS,
@@ -135,8 +134,7 @@ const IIDX_GOAL_PG_FMT: GPTGoalProgressFormatters<"iidx:DP" | "iidx:SP"> = {
};
export const IIDX_SP_IMPL: GPTServerImplementation<"iidx:SP"> = {
derivers: IIDXLIKE_DERIVERS,
newDeriver: IIDXLIKE_NEW_DERIVER,
scoreDeriver: IIDXLIKE_SCORE_DERIVER,
chartSpecificValidators: IIDXLIKE_VALIDATORS,
pbRankingValues: IIDXLIKE_PB_RANKING_VALUES,
newCalcs: (scoreData, _derivedData, chart) => {
@@ -219,8 +217,7 @@ export const IIDX_SP_IMPL: GPTServerImplementation<"iidx:SP"> = {
};
export const IIDX_DP_IMPL: GPTServerImplementation<"iidx:DP"> = {
derivers: IIDXLIKE_DERIVERS,
newDeriver: IIDXLIKE_NEW_DERIVER,
scoreDeriver: IIDXLIKE_SCORE_DERIVER,
chartSpecificValidators: IIDXLIKE_VALIDATORS,
pbRankingValues: IIDXLIKE_PB_RANKING_VALUES,
newCalcs: (scoreData, _derivedData, chart) => {
@@ -11,27 +11,7 @@ import { GoalFmtPercent, GradeGoalFormatter } from "./_common";
export const ITG_STAMINA_IMPL: GPTServerImplementation<"itg:Stamina"> = {
chartSpecificValidators: {},
derivers: {
finalPercent: (metrics) => {
// *important*
// don't check if metrics.survivedPercent === 100, as due to floating
// point inaccuracies, it's possible to have a 100% fail
// (on extremely long charts, for example)
if (metrics.lamp === "FAILED") {
return metrics.survivedPercent;
}
return 100 + metrics.scorePercent;
},
grade: ({ scorePercent, lamp }) => {
if (lamp === "FAILED") {
return "F";
}
return GetGrade(ITG_GBOUNDARIES, scorePercent);
},
},
newDeriver: (scoreData, _chart) => ({
scoreDeriver: (scoreData, _chart) => ({
// *important*: don't check survivedPercent === 100 — floating point can
// produce a 100% survived-percent on a fail for very long charts.
finalPercent:
@@ -41,7 +41,7 @@ t.test("Jubeat Implementation", (t) => {
t.test("Grade Deriver", (t) => {
const f = (score: number, expected: any) =>
t.equal(
JUBEAT_IMPL.derivers.grade(dmf(baseMetrics, { score }), TestingJubeatChart),
JUBEAT_IMPL.scoreDeriver(dmf(baseMetrics, { score }) as any, TestingJubeatChart).grade,
expected,
`A score of ${score.toLocaleString()} should result in grade=${expected}.`,
);
@@ -162,10 +162,7 @@ export const JUBEAT_IMPL: GPTServerImplementation<"jubeat:Single"> = {
}
},
},
derivers: {
grade: ({ score }) => GetGrade(JUBEAT_GBOUNDARIES, score),
},
newDeriver: (scoreData, _chart) => ({
scoreDeriver: (scoreData, _chart) => ({
grade: GetGrade(JUBEAT_GBOUNDARIES, scoreData.score),
}),
newCalcs: (scoreData, _derivedData, chart) => ({
@@ -58,7 +58,7 @@ t.test("maimai Implementation", (t) => {
t.test("Grade Deriver", (t) => {
const f = (percent: number, expected: string) =>
t.equal(
MAIMAI_IMPL.derivers.grade(dmf(baseMetrics, { percent }), TestingMaimaiChart),
MAIMAI_IMPL.scoreDeriver(dmf(baseMetrics, { percent }) as any, TestingMaimaiChart).grade,
expected,
`A percent of ${percent} should result in grade=${expected}.`,
);
@@ -23,16 +23,7 @@ export const MAIMAI_IMPL: GPTServerImplementation<"maimai:Single"> = {
return true;
},
},
derivers: {
grade: ({ percent }, chart) => {
if (percent === chart.data.maxPercent) {
return "SSS+";
}
return GetGrade(MAIMAI_GBOUNDARIES, percent);
},
},
newDeriver: (scoreData, chart) => ({
scoreDeriver: (scoreData, chart) => ({
grade:
scoreData.percent === chart.data.maxPercent
? "SSS+"
@@ -38,7 +38,8 @@ t.test("Maimai DX Implementation", (t) => {
t.test("Grade Deriver", (t) => {
const f = (percent: number, expected: any) =>
t.equal(
MAIMAIDX_IMPL.derivers.grade(dmf(baseMetrics, { percent }), TestingMaimaiDXChart),
MAIMAIDX_IMPL.scoreDeriver(dmf(baseMetrics, { percent }) as any, TestingMaimaiDXChart)
.grade,
expected,
`A percent of ${percent} should result in grade=${expected}.`,
);
@@ -11,10 +11,7 @@ import { GoalFmtPercent, GoalOutOfFmtPercent, GradeGoalFormatter } from "./_comm
export const MAIMAIDX_IMPL: GPTServerImplementation<"maimaidx:Single"> = {
chartSpecificValidators: {},
derivers: {
grade: ({ percent }) => GetGrade(MAIMAIDX_GBOUNDARIES, percent),
},
newDeriver: (scoreData, _chart) => ({
scoreDeriver: (scoreData, _chart) => ({
grade: GetGrade(MAIMAIDX_GBOUNDARIES, scoreData.percent),
}),
newCalcs: (scoreData, _derivedData, chart) => ({
@@ -33,7 +33,7 @@ t.test("MUSECA Implementation", (t) => {
t.test("Grade Deriver", (t) => {
const f = (score: number, expected: any) =>
t.equal(
MUSECA_IMPL.derivers.grade(dmf(baseMetrics, { score }), TestingMusecaChart),
MUSECA_IMPL.scoreDeriver(dmf(baseMetrics, { score }) as any, TestingMusecaChart).grade,
expected,
`A score of ${score.toLocaleString()} should result in grade=${expected}.`,
);
@@ -10,10 +10,7 @@ import { GoalFmtScore, GoalOutOfFmtScore, GradeGoalFormatter } from "./_common";
export const MUSECA_IMPL: GPTServerImplementation<"museca:Single"> = {
chartSpecificValidators: {},
derivers: {
grade: ({ score }) => GetGrade(MUSECA_GBOUNDARIES, score),
},
newDeriver: (scoreData, _chart) => ({
scoreDeriver: (scoreData, _chart) => ({
grade: GetGrade(MUSECA_GBOUNDARIES, scoreData.score),
}),
newCalcs: (scoreData, _derivedData, chart) => ({
@@ -48,7 +48,7 @@ t.test("ONGEKI Implementation", (t: any) => {
t.test("Grade Deriver", (t: any) => {
const f = (score: number, expected: string) =>
t.equal(
ONGEKI_IMPL.derivers.grade(dmf(baseMetrics, { score }), TestingOngekiChart),
ONGEKI_IMPL.scoreDeriver(dmf(baseMetrics, { score }) as any, TestingOngekiChart).grade,
expected,
`A score of ${score.toLocaleString()} should result in grade=${expected}.`,
);
@@ -73,10 +73,10 @@ t.test("ONGEKI Implementation", (t: any) => {
t.test("Star Deriver", (t: any) => {
const f = (platinumScore: number, expected: number) =>
t.equal(
ONGEKI_IMPL.derivers.platinumStars(
dmf(baseMetrics, { platinumScore }),
ONGEKI_IMPL.scoreDeriver(
dmf(baseMetrics, { platinumScore }) as any,
TestingOngekiChart,
),
).platinumStars,
expected,
`A score of ${platinumScore.toLocaleString()} should result in stars=${expected}.`,
);
@@ -63,12 +63,7 @@ export const ONGEKI_IMPL: GPTServerImplementation<"ongeki:Single"> = {
return true;
},
},
derivers: {
grade: ({ score }) => GetGrade(ONGEKI_GBOUNDARIES, score),
platinumStars: ({ platinumScore }, chart) =>
starCount(platinumScore, chart.data.maxPlatScore),
},
newDeriver: (scoreData, chart) => ({
scoreDeriver: (scoreData, chart) => ({
grade: GetGrade(ONGEKI_GBOUNDARIES, scoreData.score),
platinumStars: starCount(scoreData.platinumScore, chart.data.maxPlatScore),
}),
@@ -41,7 +41,7 @@ t.test("Pop'n Implementation", (t) => {
t.test("Grade Deriver", (t) => {
const f = (score: number, expected: any) =>
t.equal(
POPN_9B_IMPL.derivers.grade(dmf(baseMetrics, { score }), TestingPopnChart),
POPN_9B_IMPL.scoreDeriver(dmf(baseMetrics, { score }) as any, TestingPopnChart).grade,
expected,
`A score of ${score.toLocaleString()} should result in grade=${expected}.`,
);
@@ -61,7 +61,8 @@ t.test("Pop'n Implementation", (t) => {
t.test("Lamp Deriver", (t) => {
const f = (clearMedal: ProvidedMetrics["popn:9B"]["clearMedal"], expected: any) =>
t.equal(
POPN_9B_IMPL.derivers.lamp(dmf(baseMetrics, { clearMedal }), TestingPopnChart),
POPN_9B_IMPL.scoreDeriver(dmf(baseMetrics, { clearMedal }) as any, TestingPopnChart)
.lamp,
expected,
`A clear medal of ${clearMedal} should result in lamp=${expected}.`,
);
@@ -35,23 +35,7 @@ export function PopnClearMedalToLamp(
export const POPN_9B_IMPL: GPTServerImplementation<"popn:9B"> = {
chartSpecificValidators: {},
derivers: {
lamp: ({ clearMedal }) => PopnClearMedalToLamp(clearMedal),
grade: ({ score, clearMedal }) => {
const gradeString = GetGrade(POPN_GBOUNDARIES, score);
// lol double-calc
const lamp = PopnClearMedalToLamp(clearMedal);
// grades are kneecapped at "A" if you failed.
if (score >= 90_000 && lamp === "FAILED") {
return "A";
}
return gradeString;
},
},
newDeriver: (scoreData, _chart) => {
scoreDeriver: (scoreData, _chart) => {
const lamp = PopnClearMedalToLamp(scoreData.clearMedal);
return {
@@ -49,7 +49,7 @@ t.test("SDVX Implementation", (t) => {
t.test("Grade Deriver", (t) => {
const f = (score: number, expected: any) =>
t.equal(
SDVX_IMPL.derivers.grade(dmf(baseMetrics, { score }), TestingSDVXAlbidaChart),
SDVX_IMPL.scoreDeriver(dmf(baseMetrics, { score }) as any, TestingSDVXAlbidaChart).grade,
expected,
`A score of ${score.toLocaleString()} should result in grade=${expected}.`,
);
@@ -5,12 +5,11 @@ import { CreatePBMergeFor } from "#game-implementations/utils/pb-merge";
import {
SDVXLIKE_CLASS_DERIVERS,
SDVXLIKE_DEFAULT_MERGE_NAME,
SDVXLIKE_DERIVERS,
SDVXLIKE_GOAL_FMT,
SDVXLIKE_GOAL_OO_FMT,
SDVXLIKE_GOAL_PG_FMT,
SDVXLIKE_NEW_CALCS,
SDVXLIKE_NEW_DERIVER,
SDVXLIKE_SCORE_DERIVER,
SDVXLIKE_NEW_PROFILE_CALCS,
SDVXLIKE_NEW_SESSION_CALCS,
SDVXLIKE_PROFILE_CALCS,
@@ -20,8 +19,7 @@ import {
} from "./_common";
export const SDVX_IMPL: GPTServerImplementation<"sdvx:Single"> = {
derivers: SDVXLIKE_DERIVERS,
newDeriver: SDVXLIKE_NEW_DERIVER,
scoreDeriver: SDVXLIKE_SCORE_DERIVER,
newCalcs: SDVXLIKE_NEW_CALCS,
newSessionCalcs: SDVXLIKE_NEW_SESSION_CALCS,
newProfileCalcs: SDVXLIKE_NEW_PROFILE_CALCS,
@@ -44,7 +44,7 @@ for (const [playtype, impl] of [
t.test("Grade Deriver", (t) => {
const f = (score: number, expected: any) =>
t.equal(
impl.derivers.grade(dmf(baseMetrics, { score }), TestingUSCChart as any),
impl.scoreDeriver(dmf(baseMetrics, { score }) as any, TestingUSCChart as any).grade,
expected,
`A score of ${score.toLocaleString()} should result in grade=${expected}.`,
);
@@ -4,12 +4,11 @@ import type { GPTStrings } from "tachi-common";
import {
SDVXLIKE_CLASS_DERIVERS,
SDVXLIKE_DEFAULT_MERGE_NAME,
SDVXLIKE_DERIVERS,
SDVXLIKE_GOAL_FMT,
SDVXLIKE_GOAL_OO_FMT,
SDVXLIKE_GOAL_PG_FMT,
SDVXLIKE_NEW_CALCS,
SDVXLIKE_NEW_DERIVER,
SDVXLIKE_SCORE_DERIVER,
SDVXLIKE_NEW_PROFILE_CALCS,
SDVXLIKE_NEW_SESSION_CALCS,
SDVXLIKE_PB_MERGERS,
@@ -20,8 +19,7 @@ import {
} from "./_common";
const USC_IMPL: GPTServerImplementation<GPTStrings["usc"]> = {
derivers: SDVXLIKE_DERIVERS,
newDeriver: SDVXLIKE_NEW_DERIVER,
scoreDeriver: SDVXLIKE_SCORE_DERIVER,
newCalcs: SDVXLIKE_NEW_CALCS,
newSessionCalcs: SDVXLIKE_NEW_SESSION_CALCS,
newProfileCalcs: SDVXLIKE_NEW_PROFILE_CALCS,
@@ -41,7 +41,7 @@ t.test("WACCA Implementation", (t) => {
t.test("Grade Deriver", (t) => {
const f = (score: number, expected: any) =>
t.equal(
WACCA_IMPL.derivers.grade(dmf(baseMetrics, { score }), TestingWaccaPupaExp),
WACCA_IMPL.scoreDeriver(dmf(baseMetrics, { score }) as any, TestingWaccaPupaExp).grade,
expected,
`A score of ${score.toLocaleString()} should result in grade=${expected}.`,
);
@@ -11,10 +11,7 @@ import { GoalFmtScore, GoalOutOfFmtScore, GradeGoalFormatter } from "./_common";
export const WACCA_IMPL: GPTServerImplementation<"wacca:Single"> = {
chartSpecificValidators: {},
derivers: {
grade: ({ score }) => GetGrade(WACCA_GBOUNDARIES, score),
},
newDeriver: (scoreData, _chart) => ({
scoreDeriver: (scoreData, _chart) => ({
grade: GetGrade(WACCA_GBOUNDARIES, scoreData.score),
}),
newCalcs: (scoreData, _derivedData, chart) => ({
@@ -2,7 +2,6 @@ import type { DryScoreData } from "#lib/score-import/framework/common/types";
import type { MONGO_PBScoreDocumentNoRank } from "#lib/score-import/framework/pb/create-pb-doc";
import type {
ClassConfigs,
ConfDerivedMetrics,
ConfScoreMetrics,
GPTString,
GPTStringToGame,
@@ -20,11 +19,7 @@ import type {
SessionRatingAlgorithms,
} from "tachi-common";
import type { DerivedClassConfig } from "tachi-common/types/game-config-utils";
import type {
__OLD_KILL_ScoreMetricDeriver,
AllConfMetrics,
ConfEnumScoreMetric,
} from "tachi-common/types/metrics";
import type { AllConfMetrics, ConfEnumScoreMetric } from "tachi-common/types/metrics";
/**
* Validate this chart-specific metric. This should return a string representing an
@@ -117,22 +112,8 @@ export type GPTChartSpecificMetricValidators<GPT extends GPTString> = {
: never]: ChartSpecificMetricValidator<GPT>;
};
export type __OLD_KILL_GPTDerivers<GPT extends GPTString> = {
[K in keyof ConfDerivedMetrics[GPT]]: __OLD_KILL_ScoreMetricDeriver<
// @ts-expect-error This *might* be a bug in the typescript compiler
// as this works for all GPT inputs normally.
// Possibly some generic nonsense but like...
// can you really blame them for this not working?
// can you? LOOK at what we're doing.
ConfDerivedMetrics[GPT][K],
GPT
>;
};
// New-style deriver; just f(scoreData, chart) -> derivedMetrics
// instead of the overly complex shit above.
export type GPTNewDeriver<GPT extends GPTString> = (
/** Derives chart-dependent score metrics (grade, percent, …) from provided score data. */
export type GPTScoreDeriver<GPT extends GPTString> = (
scoreData: MONGO_ScoreData<GPT>,
chart: MONGO_ChartDocument<GPT>,
) => MongoDerivedMetrics[GPT];
@@ -241,14 +222,7 @@ export interface GPTServerImplementation<GPT extends GPTString> {
/**
* How should we derive the derived metrics for this game?
*/
derivers: __OLD_KILL_GPTDerivers<GPT>;
/**
* How should we derive the derived metrics for this game?
*
* New style, simpler function.
*/
newDeriver: GPTNewDeriver<GPT>;
scoreDeriver: GPTScoreDeriver<GPT>;
/**
* How should we compute the score rating algorithms for this game?
@@ -1,7 +1,4 @@
import type { __OLD_KILL_GPTDerivers } from "#game-implementations/types";
import type { KtLogger } from "#lib/log/log";
import type { MetricValue } from "tachi-common/types/metrics";
import { GPT_SERVER_IMPLEMENTATIONS } from "#game-implementations/game-implementations";
import {
GetGPTConfig,
@@ -27,28 +24,10 @@ function DeriveMetrics<GPT extends GPTString>(
metrics: DryScoreData<GPT>,
chart: MONGO_ChartDocument<GPT>,
) {
const deriverImplementation: __OLD_KILL_GPTDerivers<GPT> =
GPT_SERVER_IMPLEMENTATIONS[gpt].derivers;
const derivedMetrics: Record<string, MetricValue> = {};
const gptConfig = GetGPTConfig(gpt);
for (const [key, fn] of Object.entries(deriverImplementation)) {
const metricConfig = gptConfig.derivedMetrics[key];
if (!metricConfig) {
throw new InternalFailure(
`${gpt} has a deriver defined for '${key}', but no such field exists in the config?`,
);
}
const value = fn(metrics, chart);
derivedMetrics[key] = value;
}
return derivedMetrics as MongoDerivedMetrics[GPT];
return GPT_SERVER_IMPLEMENTATIONS[gpt].scoreDeriver(
metrics as MONGO_ScoreData<GPT>,
chart,
) as MongoDerivedMetrics[GPT];
}
export function CreateEnumIndexes<GPT extends GPTString>(gpt: GPT, metrics: any, log: KtLogger) {