BREAKING: make batch-manual classes take strings instead of ints

This commit is contained in:
zkldi
2022-04-22 21:13:26 +01:00
parent ed149f6fa8
commit ea7d36e2ae
4 changed files with 89 additions and 10 deletions
@@ -0,0 +1,70 @@
import ScoreImportFatalError from "lib/score-import/framework/score-importing/score-import-error";
import { ClassHandler } from "lib/score-import/framework/user-game-stats/types";
import { GamePTConfig, GetGamePTConfig, IDStrings } from "tachi-common";
import { GameClasses, GameClassSets } from "tachi-common/js/game-classes";
// Note: This is tested by batch-manuals parser.test.ts.
export function CreateBatchManualClassHandler(
classes: Record<GameClassSets[IDStrings], string>
): ClassHandler {
return (game, playtype, userID, ratings, logger) => {
const gptConfig = GetGamePTConfig(game, playtype);
const newObj: Partial<GameClasses<IDStrings>> = {};
for (const [s, classID] of Object.entries(classes)) {
const set = s as GameClassSets[IDStrings];
const index = ClassIDToIndex(gptConfig, set, classID);
if (index === null) {
logger.warn(
`User passed invalid class of ${classID} for set ${set}. Expected any of ${gptConfig.classHumanisedFormat[
set
]
.map((e) => e.id)
.join(", ")}`
);
throw new ScoreImportFatalError(
400,
`Invalid class of ${classID} for set ${set}. Expected any of ${gptConfig.classHumanisedFormat[
set
]
.map((e) => e.id)
.join(", ")}`
);
}
newObj[set] = index;
}
return newObj;
};
}
/**
* Given a gpt classes ID, return its index value.
*
* Returns null if the classID doesn't exist.
* @returns
*/
function ClassIDToIndex(
gptConfig: GamePTConfig,
classSet: GameClassSets[IDStrings],
classID: string
) {
const classes = gptConfig.classHumanisedFormat[classSet];
for (let i = 0; i < classes.length; i++) {
const classInfo = classes[i];
// Object.entries on an array returns [string, T], counterintuitively.
// Ah well. We'll just iterate over it like this.
if (classInfo.id === classID) {
return i;
}
}
return null;
}
@@ -1,5 +1,4 @@
import deepmerge from "deepmerge";
import { IIDXDans, SDVXDans, WACCA_STAGEUPS } from "lib/constants/classes";
import { KtLogger } from "lib/logger/logger";
import { TachiConfig } from "lib/setup/config";
import p, { PrudenceSchema, ValidSchemaValue } from "prudence";
@@ -15,6 +14,7 @@ import {
import { FormatPrError } from "utils/prudence";
import ScoreImportFatalError from "../../../framework/score-importing/score-import-error";
import { ParserFunctionReturns } from "../types";
import { CreateBatchManualClassHandler } from "./class-handler";
import { BatchManualContext } from "./types";
const optNull = (v: ValidSchemaValue) => p.optional(p.nullable(v));
@@ -201,20 +201,27 @@ const PR_BatchManualScore = (game: Game, playtype: Playtypes[Game]): PrudenceSch
};
};
// both iidx sp and dp share dans.
const IIDXStringDans = GetGamePTConfig("iidx", "SP").classHumanisedFormat.dan.map((e) => e.id);
const SDVXStringDans = GetGamePTConfig("sdvx", "Single").classHumanisedFormat.dan.map((e) => e.id);
const WaccaStringStageUps = GetGamePTConfig("wacca", "Single").classHumanisedFormat.stageUp.map(
(e) => e.id
);
const PR_BatchManualClasses = (game: Game): PrudenceSchema => {
switch (game) {
// This can be implemented for any non-static class (i.e. dans).
case "iidx":
return {
dan: optNull(p.isBoundedInteger(IIDXDans.KYU_7, IIDXDans.KAIDEN)),
dan: optNull(p.isIn(IIDXStringDans)),
};
case "sdvx":
return {
dan: optNull(p.isBoundedInteger(SDVXDans.DAN_1, SDVXDans.INF)),
dan: optNull(p.isIn(SDVXStringDans)),
};
case "wacca":
return {
stageUp: optNull(p.isBoundedInteger(WACCA_STAGEUPS.I, WACCA_STAGEUPS.XIV)),
stageUp: optNull(p.isIn(WaccaStringStageUps)),
};
default:
return {};
@@ -321,6 +328,8 @@ export function ParseBatchManualFromObject(
iterable: batchManual.scores,
// if classes are provided, use those as a class handler. Otherwise, we
// don't care.
classHandler: batchManual.classes ? () => batchManual.classes! : null,
classHandler: batchManual.classes
? CreateBatchManualClassHandler(batchManual.classes!)
: null,
};
}