snapshot migration phase 4
This commit is contained in:
+938
-96
File diff suppressed because it is too large
Load Diff
+320
-11
@@ -986,15 +986,11 @@ async function evaluateAchievements(
|
||||
continue;
|
||||
}
|
||||
|
||||
const currentValue =
|
||||
readStatValue(
|
||||
if (
|
||||
!achievementRequirementsMet(
|
||||
statsDocument,
|
||||
definition
|
||||
);
|
||||
|
||||
if (
|
||||
currentValue <
|
||||
Number(definition.target)
|
||||
)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
@@ -1033,9 +1029,9 @@ async function evaluateAchievements(
|
||||
const collectibleDefinitions =
|
||||
definitions.filter(
|
||||
definition =>
|
||||
definition.measure !==
|
||||
"achievementPercentage" &&
|
||||
Boolean(definition.stat)
|
||||
isStatBackfillableAchievement(
|
||||
definition
|
||||
)
|
||||
);
|
||||
|
||||
const totalCollectible =
|
||||
@@ -2133,7 +2129,23 @@ async function buildAchievementsEmbed(
|
||||
progressText =
|
||||
` • **${Math.min(100, currentValue * 100).toFixed(0)}% / ${Math.min(100, targetValue * 100).toFixed(0)}%**`;
|
||||
}
|
||||
else if (
|
||||
achievement.measure === "all" ||
|
||||
achievement.measure === "any"
|
||||
) {
|
||||
const {
|
||||
completed,
|
||||
total
|
||||
} =
|
||||
getCompositeProgress(
|
||||
statsDocument,
|
||||
achievement
|
||||
);
|
||||
|
||||
|
||||
progressText =
|
||||
` • **${completed} / ${total}**`;
|
||||
}
|
||||
else if (achievement.stat) {
|
||||
currentValue =
|
||||
readStatValue(
|
||||
@@ -2145,6 +2157,8 @@ async function buildAchievementsEmbed(
|
||||
` • **${Number(currentValue).toLocaleString()} / ${targetValue.toLocaleString()}**`;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const requirement =
|
||||
achievement.requirement ??
|
||||
achievement.description ??
|
||||
@@ -2590,7 +2604,9 @@ function formatCategoryName(
|
||||
collector:
|
||||
"🏆 Collector",
|
||||
other:
|
||||
"🏅 Other"
|
||||
"🏅 Other",
|
||||
activity:
|
||||
"📅 Activity",
|
||||
};
|
||||
|
||||
return labels[category] ??
|
||||
@@ -2637,6 +2653,291 @@ function formatBadgeLine(
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
function readStatPath(
|
||||
document,
|
||||
stat
|
||||
) {
|
||||
if (!stat) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return String(stat)
|
||||
.split(".")
|
||||
.reduce(
|
||||
(current, key) =>
|
||||
current?.[key],
|
||||
document
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function evaluateCondition(
|
||||
document,
|
||||
condition
|
||||
) {
|
||||
if (
|
||||
!condition ||
|
||||
!condition.stat
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const actual =
|
||||
readStatPath(
|
||||
document,
|
||||
condition.stat
|
||||
);
|
||||
|
||||
const expected =
|
||||
condition.value;
|
||||
|
||||
const operator =
|
||||
String(
|
||||
condition.operator ??
|
||||
"gte"
|
||||
).toLowerCase();
|
||||
|
||||
|
||||
switch (operator) {
|
||||
case "eq":
|
||||
return (
|
||||
actual ===
|
||||
expected
|
||||
);
|
||||
|
||||
|
||||
case "neq":
|
||||
return (
|
||||
actual !==
|
||||
expected
|
||||
);
|
||||
|
||||
|
||||
case "gt":
|
||||
return (
|
||||
Number(actual ?? 0) >
|
||||
Number(expected ?? 0)
|
||||
);
|
||||
|
||||
|
||||
case "gte":
|
||||
return (
|
||||
Number(actual ?? 0) >=
|
||||
Number(expected ?? 0)
|
||||
);
|
||||
|
||||
|
||||
case "lt":
|
||||
return (
|
||||
Number(actual ?? 0) <
|
||||
Number(expected ?? 0)
|
||||
);
|
||||
|
||||
|
||||
case "lte":
|
||||
return (
|
||||
Number(actual ?? 0) <=
|
||||
Number(expected ?? 0)
|
||||
);
|
||||
|
||||
|
||||
case "includes":
|
||||
return (
|
||||
Array.isArray(actual) &&
|
||||
actual.includes(
|
||||
expected
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
case "not_includes":
|
||||
return (
|
||||
Array.isArray(actual) &&
|
||||
!actual.includes(
|
||||
expected
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
case "truthy":
|
||||
return Boolean(
|
||||
actual
|
||||
);
|
||||
|
||||
|
||||
case "falsy":
|
||||
return !Boolean(
|
||||
actual
|
||||
);
|
||||
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function evaluateCompositeAchievement(
|
||||
document,
|
||||
definition
|
||||
) {
|
||||
const conditions =
|
||||
Array.isArray(
|
||||
definition.conditions
|
||||
)
|
||||
? definition.conditions
|
||||
: [];
|
||||
|
||||
|
||||
if (!conditions.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
definition.measure ===
|
||||
"all"
|
||||
) {
|
||||
return conditions.every(
|
||||
condition =>
|
||||
evaluateCondition(
|
||||
document,
|
||||
condition
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
definition.measure ===
|
||||
"any"
|
||||
) {
|
||||
return conditions.some(
|
||||
condition =>
|
||||
evaluateCondition(
|
||||
document,
|
||||
condition
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function isStatBackfillableAchievement(
|
||||
definition
|
||||
) {
|
||||
if (!definition) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
definition.measure ===
|
||||
"achievementPercentage"
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
definition.measure === "all" ||
|
||||
definition.measure === "any"
|
||||
) {
|
||||
return (
|
||||
Array.isArray(
|
||||
definition.conditions
|
||||
) &&
|
||||
definition.conditions.length > 0
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return Boolean(
|
||||
definition.stat
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function achievementRequirementsMet(
|
||||
document,
|
||||
definition
|
||||
) {
|
||||
if (!definition) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
definition.measure === "all" ||
|
||||
definition.measure === "any"
|
||||
) {
|
||||
return evaluateCompositeAchievement(
|
||||
document,
|
||||
definition
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if (!definition.stat) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const currentValue =
|
||||
readStatValue(
|
||||
document,
|
||||
definition
|
||||
);
|
||||
|
||||
|
||||
return (
|
||||
currentValue >=
|
||||
Number(
|
||||
definition.target ?? 0
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function getCompositeProgress(
|
||||
statsDocument,
|
||||
definition
|
||||
) {
|
||||
const conditions =
|
||||
Array.isArray(
|
||||
definition.conditions
|
||||
)
|
||||
? definition.conditions
|
||||
: [];
|
||||
|
||||
|
||||
if (!conditions.length) {
|
||||
return {
|
||||
completed: 0,
|
||||
total: 0
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
const completed =
|
||||
conditions.filter(
|
||||
condition =>
|
||||
evaluateCondition(
|
||||
statsDocument,
|
||||
condition
|
||||
)
|
||||
).length;
|
||||
|
||||
|
||||
return {
|
||||
completed,
|
||||
total:
|
||||
conditions.length
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
ensureProfileSystem,
|
||||
trackProfileEvent,
|
||||
@@ -2644,7 +2945,15 @@ module.exports = {
|
||||
getProfileStats,
|
||||
getProfileCollections,
|
||||
getDefaultStats,
|
||||
getCompositeProgress,
|
||||
|
||||
readStatValue,
|
||||
readStatPath,
|
||||
|
||||
evaluateCondition,
|
||||
evaluateCompositeAchievement,
|
||||
achievementRequirementsMet,
|
||||
isStatBackfillableAchievement,
|
||||
|
||||
getActivityDateContext,
|
||||
trackGameActivity,
|
||||
|
||||
Reference in New Issue
Block a user