snapshot migration phase 4

This commit is contained in:
DeSqBlocki
2026-08-27 19:19:58 +02:00
parent c2ac7737c0
commit 42fc848f8c
2 changed files with 1260 additions and 109 deletions
File diff suppressed because it is too large Load Diff
+320 -11
View File
@@ -986,15 +986,11 @@ async function evaluateAchievements(
continue; continue;
} }
const currentValue = if (
readStatValue( !achievementRequirementsMet(
statsDocument, statsDocument,
definition definition
); )
if (
currentValue <
Number(definition.target)
) { ) {
continue; continue;
} }
@@ -1033,9 +1029,9 @@ async function evaluateAchievements(
const collectibleDefinitions = const collectibleDefinitions =
definitions.filter( definitions.filter(
definition => definition =>
definition.measure !== isStatBackfillableAchievement(
"achievementPercentage" && definition
Boolean(definition.stat) )
); );
const totalCollectible = const totalCollectible =
@@ -2133,7 +2129,23 @@ async function buildAchievementsEmbed(
progressText = progressText =
` • **${Math.min(100, currentValue * 100).toFixed(0)}% / ${Math.min(100, targetValue * 100).toFixed(0)}%**`; ` • **${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) { else if (achievement.stat) {
currentValue = currentValue =
readStatValue( readStatValue(
@@ -2145,6 +2157,8 @@ async function buildAchievementsEmbed(
` • **${Number(currentValue).toLocaleString()} / ${targetValue.toLocaleString()}**`; ` • **${Number(currentValue).toLocaleString()} / ${targetValue.toLocaleString()}**`;
} }
const requirement = const requirement =
achievement.requirement ?? achievement.requirement ??
achievement.description ?? achievement.description ??
@@ -2590,7 +2604,9 @@ function formatCategoryName(
collector: collector:
"🏆 Collector", "🏆 Collector",
other: other:
"🏅 Other" "🏅 Other",
activity:
"📅 Activity",
}; };
return labels[category] ?? return labels[category] ??
@@ -2637,6 +2653,291 @@ function formatBadgeLine(
].join("\n"); ].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 = { module.exports = {
ensureProfileSystem, ensureProfileSystem,
trackProfileEvent, trackProfileEvent,
@@ -2644,7 +2945,15 @@ module.exports = {
getProfileStats, getProfileStats,
getProfileCollections, getProfileCollections,
getDefaultStats, getDefaultStats,
getCompositeProgress,
readStatValue, readStatValue,
readStatPath,
evaluateCondition,
evaluateCompositeAchievement,
achievementRequirementsMet,
isStatBackfillableAchievement,
getActivityDateContext, getActivityDateContext,
trackGameActivity, trackGameActivity,