Files
zkldi_Tachi/server/src/utils/class.ts
T
2023-01-19 16:39:38 +00:00

161 lines
4.1 KiB
TypeScript

import db from "external/mongo/db";
import { CreateGameSettings } from "lib/game-settings/create-game-settings";
import CreateLogCtx from "lib/logger/logger";
import { EmitWebhookEvent } from "lib/webhooks/webhooks";
import { GetGPTConfig, GetGPTString } from "tachi-common";
import type { Game, GPTString, integer, Playtype, UserGameStats, Classes } from "tachi-common";
const logger = CreateLogCtx(__filename);
/**
* Returns the provided class if it is greater than the one in userGameStats
* @returns The provided class if it is greater, NULL if there is nothing
* to compare to, and FALSE if it is worse or equal.
*/
export function ReturnClassIfGreater(
gptString: GPTString,
classSet: Classes[GPTString],
classVal: string,
userGameStats?: UserGameStats | null
): boolean | null {
const gptConfig = GetGPTConfig(gptString);
const classInfo = gptConfig.classes[classSet];
if (!classInfo) {
logger.warn(
`Invalid ReturnClassIfGreater call. Attempted to index set '${classSet}' on ${gptString}. No such class is defined for this game.`
);
return null;
}
if (!userGameStats) {
return null;
}
const prevClass: string | null | undefined = userGameStats.classes[classSet];
if (prevClass === null || prevClass === undefined) {
return null;
}
const previousClassIndex = ClassToIndex(gptString, classSet, prevClass);
const newClassIndex = ClassToIndex(gptString, classSet, classVal);
if (previousClassIndex === null && newClassIndex === null) {
return null;
} else if (newClassIndex === null) {
return null;
} else if (previousClassIndex === null) {
return true;
}
return newClassIndex > previousClassIndex;
}
export function ClassToIndex(gptString: GPTString, classSet: Classes[GPTString], classVal: string) {
const gptConfig = GetGPTConfig(gptString);
const classInfo = gptConfig.classes[classSet];
if (!classInfo) {
logger.warn(
`Invalid ClassToIndex call. Attempted to index set '${classSet}' on ${gptString}. No such class is defined for this game. Returning null.`
);
return null;
}
const v = classInfo.values.map((e) => e.id).indexOf(classVal);
if (v === -1) {
logger.warn(
`Attempted to index a class that doesn't exist: ${classVal} on ${classSet} (${gptString}). Returning null.`
);
return null;
}
return v;
}
/**
* Updates a user's class value if it is greater than the one in their
* UserGameStats.
* @returns False if nothing was updated.
* Null if it was updated because there was nothing in UserGameStats to
* compare to.
* True if it was updated because it was better than UserGameStats.
*/
export async function UpdateClassIfGreater(
userID: integer,
game: Game,
playtype: Playtype,
classSet: Classes[GPTString],
classVal: string
) {
const gptString = GetGPTString(game, playtype);
const userGameStats = await db["game-stats"].findOne({ userID, game, playtype });
const isGreater = ReturnClassIfGreater(gptString, classSet, classVal, userGameStats);
if (isGreater === false) {
return false;
}
if (userGameStats) {
await db["game-stats"].update(
{ userID, game, playtype },
{ $set: { [`classes.${classSet}`]: classVal } }
);
} else {
// insert new game stats for this user - this is an awkward place
// to call this - maybe we should call it elsewhere.
await db["game-stats"].insert({
userID,
game,
playtype,
ratings: {},
classes: {
[classSet]: classVal,
},
});
logger.info(`Created new player gamestats for ${userID} (${game} ${playtype})`);
await CreateGameSettings(userID, game, playtype);
}
await db["class-achievements"].insert({
game,
playtype,
userID,
classOldValue: isGreater === null ? null : userGameStats!.classes[classSet]!,
classSet,
classValue: classVal,
timeAchieved: Date.now(),
});
if (isGreater === null) {
void EmitWebhookEvent({
type: "class-update/v1",
content: { userID, new: classVal, old: null, set: classSet, game, playtype },
});
return null;
}
void EmitWebhookEvent({
type: "class-update/v1",
content: {
userID,
new: classVal,
old: userGameStats!.classes[classSet]!,
set: classSet,
game,
playtype,
},
});
return true;
}