mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2025-12-29 03:20:46 +08:00
Add xp reward overrides (#3525) Bruception, Miodec
* Add xp reward overrides * edge case * switched to defined brackets instead of just min and max * foreach * moved type to its own interface * updated spec Co-authored-by: Miodec <bartnikjack@gmail.com>
This commit is contained in:
parent
2fa5dd0fef
commit
c894a862e4
6 changed files with 91 additions and 44 deletions
|
|
@ -23,6 +23,7 @@ const dailyLeaderboardsConfig = {
|
|||
topResultsToAnnounce: 3,
|
||||
maxXpReward: 0,
|
||||
minXpReward: 0,
|
||||
xpRewardBrackets: [],
|
||||
};
|
||||
|
||||
describe("Daily Leaderboards", () => {
|
||||
|
|
|
|||
|
|
@ -72,8 +72,7 @@ export const BASE_CONFIGURATION: MonkeyTypes.Configuration = {
|
|||
// GOTCHA! MUST ATLEAST BE 1, LRUCache module will make process crash and die
|
||||
dailyLeaderboardCacheSize: 1,
|
||||
topResultsToAnnounce: 1, // This should never be 0. Setting to zero will announce all results.
|
||||
minXpReward: 0,
|
||||
maxXpReward: 0,
|
||||
xpRewardBrackets: [],
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -391,15 +390,35 @@ export const CONFIGURATION_FORM_SCHEMA: ObjectSchema = {
|
|||
label: "Top Results To Announce",
|
||||
min: 1,
|
||||
},
|
||||
minXpReward: {
|
||||
type: "number",
|
||||
label: "Minimum XP Reward",
|
||||
min: 0,
|
||||
},
|
||||
maxXpReward: {
|
||||
type: "number",
|
||||
label: "Maximum XP Reward",
|
||||
min: 0,
|
||||
xpRewardBrackets: {
|
||||
type: "array",
|
||||
label: "XP Reward Brackets",
|
||||
items: {
|
||||
type: "object",
|
||||
label: "Bracket",
|
||||
fields: {
|
||||
minRank: {
|
||||
type: "number",
|
||||
label: "Min Rank",
|
||||
min: 1,
|
||||
},
|
||||
maxRank: {
|
||||
type: "number",
|
||||
label: "Max Rank",
|
||||
min: 1,
|
||||
},
|
||||
minReward: {
|
||||
type: "number",
|
||||
label: "Min Reward",
|
||||
min: 0,
|
||||
},
|
||||
maxReward: {
|
||||
type: "number",
|
||||
label: "Max Reward",
|
||||
min: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -828,11 +828,15 @@ function buildRewardUpdates(
|
|||
}
|
||||
});
|
||||
|
||||
const baseUpdate = {
|
||||
$inc: {
|
||||
xp: _.isNumber(totalXp) ? totalXp : 0,
|
||||
},
|
||||
};
|
||||
|
||||
if (inventoryIsNull) {
|
||||
return {
|
||||
$inc: {
|
||||
xp: totalXp,
|
||||
},
|
||||
...baseUpdate,
|
||||
$set: {
|
||||
inventory: {
|
||||
badges: newBadges,
|
||||
|
|
@ -841,9 +845,7 @@ function buildRewardUpdates(
|
|||
};
|
||||
} else {
|
||||
return {
|
||||
$inc: {
|
||||
xp: totalXp,
|
||||
},
|
||||
...baseUpdate,
|
||||
$push: {
|
||||
"inventory.badges": { $each: newBadges },
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import _ from "lodash";
|
||||
import { CronJob } from "cron";
|
||||
import {
|
||||
getCurrentDayTimestamp,
|
||||
|
|
@ -50,38 +51,52 @@ async function announceDailyLeaderboard(
|
|||
if (allResults.length === 0) {
|
||||
return;
|
||||
}
|
||||
const { maxResults, xpRewardBrackets } = dailyLeaderboardsConfig;
|
||||
|
||||
if (inboxConfig.enabled) {
|
||||
const { maxXpReward, minXpReward, maxResults } = dailyLeaderboardsConfig;
|
||||
if (inboxConfig.enabled && xpRewardBrackets.length > 0) {
|
||||
const mailEntries: {
|
||||
uid: string;
|
||||
mail: MonkeyTypes.MonkeyMail[];
|
||||
}[] = [];
|
||||
|
||||
if (maxXpReward > 0) {
|
||||
const mailEntries = allResults.map((entry) => {
|
||||
const rank = entry.rank ?? maxResults;
|
||||
allResults.forEach((entry) => {
|
||||
const rank = entry.rank ?? maxResults;
|
||||
|
||||
const placementString = getOrdinalNumberString(rank);
|
||||
const xpReward = Math.floor(
|
||||
mapRange(rank, 1, maxResults, maxXpReward, minXpReward)
|
||||
);
|
||||
const placementString = getOrdinalNumberString(rank);
|
||||
|
||||
const rewardMail = buildMonkeyMail({
|
||||
subject: "Daily leaderboard placement",
|
||||
body: `Congratulations ${entry.name} on placing ${placementString} in the ${language} ${mode} ${mode2} daily leaderboard!`,
|
||||
rewards: [
|
||||
{
|
||||
type: "xp",
|
||||
item: xpReward,
|
||||
},
|
||||
],
|
||||
});
|
||||
const xpReward = _(xpRewardBrackets)
|
||||
.filter((bracket) => rank >= bracket.minRank && rank <= bracket.maxRank)
|
||||
.map((bracket) =>
|
||||
mapRange(
|
||||
rank,
|
||||
bracket.minRank,
|
||||
bracket.maxRank,
|
||||
bracket.maxReward,
|
||||
bracket.minReward
|
||||
)
|
||||
)
|
||||
.max();
|
||||
|
||||
return {
|
||||
uid: entry.uid,
|
||||
mail: [rewardMail],
|
||||
};
|
||||
if (!xpReward) return;
|
||||
|
||||
const rewardMail = buildMonkeyMail({
|
||||
subject: "Daily leaderboard placement",
|
||||
body: `Congratulations ${entry.name} on placing ${placementString} in the ${language} ${mode} ${mode2} daily leaderboard!`,
|
||||
rewards: [
|
||||
{
|
||||
type: "xp",
|
||||
item: xpReward,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await addToInboxBulk(mailEntries, inboxConfig);
|
||||
}
|
||||
mailEntries.push({
|
||||
uid: entry.uid,
|
||||
mail: [rewardMail],
|
||||
});
|
||||
});
|
||||
|
||||
await addToInboxBulk(mailEntries, inboxConfig);
|
||||
}
|
||||
|
||||
const topResults = allResults.slice(
|
||||
|
|
|
|||
10
backend/src/types/types.d.ts
vendored
10
backend/src/types/types.d.ts
vendored
|
|
@ -77,11 +77,17 @@ declare namespace MonkeyTypes {
|
|||
validModeRules: ValidModeRule[];
|
||||
dailyLeaderboardCacheSize: number;
|
||||
topResultsToAnnounce: number;
|
||||
maxXpReward: number;
|
||||
minXpReward: number;
|
||||
xpRewardBrackets: RewardBracket[];
|
||||
};
|
||||
}
|
||||
|
||||
interface RewardBracket {
|
||||
minRank: number;
|
||||
maxRank: number;
|
||||
minReward: number;
|
||||
maxReward: number;
|
||||
}
|
||||
|
||||
interface DecodedToken {
|
||||
type: "Bearer" | "ApeKey" | "None";
|
||||
uid: string;
|
||||
|
|
|
|||
|
|
@ -187,6 +187,10 @@ export function mapRange(
|
|||
outMax: number,
|
||||
clamp = false
|
||||
): number {
|
||||
if (inMin === inMax) {
|
||||
return outMin;
|
||||
}
|
||||
|
||||
const result =
|
||||
((value - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue