snapshot migration pre-phase 6, stable

This commit is contained in:
DeSqBlocki
2026-08-27 21:14:27 +02:00
parent 14a059034c
commit e3dbb11e12
7 changed files with 1089 additions and 43 deletions
+703 -25
View File
@@ -409,6 +409,145 @@ async function ensureProfileSystem() {
);
}
async function evaluateSocialRelationshipFlags(
userId,
guildId,
event
) {
const {
stats
} =
getProfileCollections();
const document =
await stats.findOne({
userId,
guildId
});
if (!document) {
return;
}
const social =
document.social ?? {};
const set = {};
/*
* ========================================================
* ET TU, CRUMB?
* ========================================================
*
* Successfully steal from somebody who has
* previously gifted Cookies to you.
*/
if (
event.type ===
"steal_success"
&&
event.targetUserId
&&
Array.isArray(
social.receivedFrom
)
&&
social.receivedFrom.includes(
event.targetUserId
)
) {
set[
"special.etTuCrumb"
] = 1;
}
/*
* ========================================================
* NO HARD FEELINGS
* ========================================================
*
* Give Cookies to somebody who has previously
* successfully stolen from you.
*/
if (
event.type ===
"cookies_given"
&&
event.targetUserId
&&
Array.isArray(
social.successfullyStolenBy
)
&&
social.successfullyStolenBy.includes(
event.targetUserId
)
) {
set[
"special.noHardFeelings"
] = 1;
}
/*
* ========================================================
* COOKIE LAUNDERING
* ========================================================
*
* Give Cookies to somebody you have previously
* successfully stolen from.
*/
if (
event.type ===
"cookies_given"
&&
event.targetUserId
&&
Array.isArray(
social.successfullyStolenFrom
)
&&
social.successfullyStolenFrom.includes(
event.targetUserId
)
) {
set[
"special.cookieLaundering"
] = 1;
}
if (
Object.keys(
set
).length ===
0
) {
return;
}
await stats.updateOne(
{
userId,
guildId
},
{
$set:
set
}
);
}
function getDefaultStats(userId, guildId) {
return {
userId,
@@ -486,8 +625,21 @@ function getDefaultStats(userId, guildId) {
bestLoss: 0
},
social: {
giftedTo: [],
receivedFrom: [],
successfullyStolenFrom: [],
successfullyStolenBy: []
},
special: {
allInRunItBack: 0
allInRunItBack: 0,
bankruptcyCount: 0,
bankruptcyRecoveryBest: 0,
etTuCrumb: 0,
noHardFeelings: 0,
cookieLaundering: 0
},
activity: {
@@ -517,6 +669,22 @@ function getDefaultStats(userId, guildId) {
evening: 0
}
},
daily: {
dateKey: null,
gamesPlayed: [],
gamesWon: [],
gamesLost: [],
collectedCookies: false,
gambledAfterCollect: false,
wonAnyGame: false,
lostAnyGame: false,
gaveCookies: false,
stoleCookies: false
},
profileSchemaVersion: 2
};
@@ -590,16 +758,54 @@ async function trackProfileEvent(
switch (event.type) {
case "cookie_gain":
await stats.updateOne(
{ userId, guildId },
{
userId,
guildId
},
{
$inc: {
"economy.cookiesObtainedTotal":
event.amount
},
...(
event.source === "give" &&
event.senderUserId
? {
$addToSet: {
"social.receivedFrom":
event.senderUserId
},
$set: {
"special.lastGiftSenderId":
event.senderUserId
}
}
: {}
)
}
);
break;
case "bankruptcy":
await stats.updateOne(
{
userId,
guildId
},
{
$inc: {
"special.bankruptcyCount":
1
},
$set: {
"special.bankruptcyRecoveryBest":
0
}
}
);
break;
case "cookie_loss":
await stats.updateOne(
{ userId, guildId },
@@ -614,48 +820,87 @@ async function trackProfileEvent(
case "cookies_given":
await stats.updateOne(
{ userId, guildId },
{
userId,
guildId
},
{
$inc: {
"economy.cookiesGivenTotal":
event.amount
}
},
...(event.targetUserId
? {
$addToSet: {
"social.giftedTo":
event.targetUserId
},
$set: {
"special.lastGiftTargetId":
event.targetUserId
}
}
: {})
}
);
break;
case "steal_success":
await stats.updateOne(
{ userId, guildId },
{
userId,
guildId
},
{
$inc: {
"economy.stolenTotal":
event.amount
},
$addToSet: {
"unique.playersStolenFrom":
event.targetUserId,
"social.successfullyStolenFrom":
event.targetUserId
},
$set: {
"special.lastSuccessfulStealTargetId":
event.targetUserId
}
}
);
break;
case "stolen_from_me":
await stats.updateOne(
{ userId, guildId },
{
userId,
guildId
},
{
$inc: {
"economy.stolenFromMeTotal":
event.amount
},
$addToSet: {
"unique.playersStolenBy":
event.thiefUserId,
"social.successfullyStolenBy":
event.thiefUserId
},
$set: {
"special.lastSuccessfulThiefId":
event.thiefUserId
}
}
);
break;
case "vault_steal":
await stats.updateOne(
{ userId, guildId },
@@ -694,6 +939,53 @@ async function trackProfileEvent(
return;
}
if (
[
"steal_success",
"cookies_given"
].includes(
event.type
)
) {
await evaluateSocialRelationshipFlags(
userId,
guildId,
event
);
}
if (
[
"cookie_gain",
"cookie_loss",
"game_result",
"bankruptcy"
].includes(
event.type
)
) {
await updateBankruptcyRecovery(
userId,
guildId
);
}
if (
event.type ===
"game_result"
) {
await trackDailyGameState(
userId,
guildId,
event
);
}
await trackDailyNarrativeState(
userId,
guildId,
event
);
const updatedStats =
await getProfileStats(
userId,
@@ -804,18 +1096,22 @@ async function trackGameStart(
const set = {};
const previousBet = Number(
event.previousBet ?? 0
const previousWager = Number(
event.previousWager ??
event.previousBet ??
0
);
const currentBet = Number(
event.bet ?? 0
const currentWager = Number(
event.wager ??
event.bet ??
0
);
const chainedAllIn =
event.previousAllIn === true &&
previousBet > 0 &&
currentBet === previousBet;
previousWager > 0 &&
currentWager === previousWager;
if (chainedAllIn) {
set["special.allInRunItBack"] = 1;
@@ -1401,8 +1697,21 @@ async function evaluateBadges(
event.type === "game_start" &&
event.source === "run_it_back" &&
event.previousAllIn === true &&
Number(event.previousBet) > 0 &&
Number(event.bet) === Number(event.previousBet)
Number(
event.previousWager ??
event.previousBet ??
0
) > 0 &&
Number(
event.wager ??
event.bet ??
0
) ===
Number(
event.previousWager ??
event.previousBet ??
0
)
) {
await tryClaimBadge(
interaction,
@@ -1434,15 +1743,14 @@ async function evaluateCollectorBadges(
.find({
active: {
$ne: false
},
measure: {
$ne:
"achievementPercentage"
}
})
.toArray()
).filter(achievement =>
Boolean(achievement.stat)
).filter(
achievement =>
isStatBackfillableAchievement(
achievement
)
);
if (
@@ -2070,8 +2378,9 @@ async function buildAchievementsEmbed(
const collectibleDefinitions =
definitions.filter(
definition =>
definition.measure !==
"achievementPercentage"
isStatBackfillableAchievement(
definition
)
);
const unlockedCollectible =
@@ -3279,6 +3588,371 @@ async function evaluateEventAchievements(
);
}
}
async function updateBankruptcyRecovery(
userId,
guildId
) {
const {
stats
} =
getProfileCollections();
const document =
await stats.findOne(
{
userId,
guildId
},
{
projection: {
"special.bankruptcyCount":
1
}
}
);
if (
Number(
document
?.special
?.bankruptcyCount ?? 0
) <= 0
) {
return;
}
const balance =
await getCookieBalance(
userId
);
await stats.updateOne(
{
userId,
guildId
},
{
$max: {
"special.bankruptcyRecoveryBest":
balance
}
}
);
}
async function trackDailyGameState(
userId,
guildId,
event
) {
if (
event.type !==
"game_result"
) {
return;
}
const game =
String(
event.game ?? ""
).toLowerCase();
const result =
String(
event.result ?? ""
).toLowerCase();
if (
![
"slots",
"blackjack",
"roulette",
"heist"
].includes(
game
)
) {
return;
}
const {
stats
} =
getProfileCollections();
const {
dateKey
} =
getActivityDateContext();
const document =
await stats.findOne(
{
userId,
guildId
},
{
projection: {
daily: 1
}
}
);
const currentDateKey =
document
?.daily
?.dateKey ?? null;
if (
currentDateKey !==
dateKey
) {
await stats.updateOne(
{
userId,
guildId
},
{
$set: {
"daily.dateKey":
dateKey,
"daily.gamesPlayed":
[game],
"daily.gamesWon":
result === "win"
? [game]
: [],
"daily.gamesLost":
result === "loss"
? [game]
: [],
"daily.collectedCookies":
false,
"daily.gambledAfterCollect":
false,
"daily.wonAnyGame":
result === "win",
"daily.lostAnyGame":
result === "loss",
"daily.gaveCookies":
false,
"daily.stoleCookies":
false
}
}
);
return;
}
const addToSet = {
"daily.gamesPlayed":
game
};
const set = {};
if (
result ===
"win"
) {
addToSet[
"daily.gamesWon"
] = game;
set[
"daily.wonAnyGame"
] = true;
}
if (
result ===
"loss"
) {
addToSet[
"daily.gamesLost"
] = game;
set[
"daily.lostAnyGame"
] = true;
}
await stats.updateOne(
{
userId,
guildId
},
{
$addToSet:
addToSet,
...(
Object.keys(
set
).length
? {
$set:
set
}
: {}
)
}
);
}
async function trackDailyNarrativeState(
userId,
guildId,
event
) {
const {
stats
} =
getProfileCollections();
const {
dateKey
} =
getActivityDateContext();
const document =
await stats.findOne(
{
userId,
guildId
},
{
projection: {
daily: 1
}
}
);
const currentDateKey =
document
?.daily
?.dateKey ?? null;
if (
currentDateKey !==
dateKey
) {
await stats.updateOne(
{
userId,
guildId
},
{
$set: {
"daily.dateKey":
dateKey,
"daily.gamesPlayed":
[],
"daily.gamesWon":
[],
"daily.gamesLost":
[],
"daily.collectedCookies":
false,
"daily.gambledAfterCollect":
false,
"daily.wonAnyGame":
false,
"daily.lostAnyGame":
false,
"daily.gaveCookies":
false,
"daily.stoleCookies":
false
}
}
);
}
const set = {};
if (
event.type ===
"cookie_gain"
&&
event.source ===
"collect"
) {
set[
"daily.collectedCookies"
] = true;
}
if (
event.type ===
"cookies_given"
) {
set[
"daily.gaveCookies"
] = true;
}
if (
event.type ===
"steal_success"
) {
set[
"daily.stoleCookies"
] = true;
}
if (
event.type ===
"game_start"
&&
document
?.daily
?.collectedCookies === true
) {
set[
"daily.gambledAfterCollect"
] = true;
}
if (
Object.keys(
set
).length === 0
) {
return;
}
await stats.updateOne(
{
userId,
guildId
},
{
$set:
set
}
);
}
module.exports = {
ensureProfileSystem,
@@ -3288,6 +3962,7 @@ module.exports = {
getProfileCollections,
getDefaultStats,
getCompositeProgress,
updateBankruptcyRecovery,
readStatValue,
readStatPath,
@@ -3316,4 +3991,7 @@ module.exports = {
evaluateEventCondition,
evaluateEventAchievement,
evaluateEventAchievements,
evaluateSocialRelationshipFlags,
trackDailyGameState,
trackDailyNarrativeState,
};