From ff7d9ab82fc5c75672fa3222039e0115be3ab063 Mon Sep 17 00:00:00 2001 From: zkldi <20380519+zkldi@users.noreply.github.com> Date: Tue, 29 Mar 2022 16:14:20 +0100 Subject: [PATCH] Untested Milestone Functionality --- server/src/lib/targets/goals.ts | 1 - server/src/lib/targets/milestones.ts | 78 +++++++++++++++++-- .../_playtype/targets/milestones/router.ts | 6 +- 3 files changed, 78 insertions(+), 7 deletions(-) diff --git a/server/src/lib/targets/goals.ts b/server/src/lib/targets/goals.ts index 0f4ba6673..d5c10098a 100644 --- a/server/src/lib/targets/goals.ts +++ b/server/src/lib/targets/goals.ts @@ -332,7 +332,6 @@ export async function SubscribeToGoal( game: goalDocument.game, playtype: goalDocument.playtype, goalID: goalDocument.goalID, - achieved: result.achieved, wasInstantlyAchieved: result.achieved, }; diff --git a/server/src/lib/targets/milestones.ts b/server/src/lib/targets/milestones.ts index 9794b4eae..1eb4b52da 100644 --- a/server/src/lib/targets/milestones.ts +++ b/server/src/lib/targets/milestones.ts @@ -1,7 +1,12 @@ import db from "external/mongo/db"; import CreateLogCtx from "lib/logger/logger"; -import { GoalSubscriptionDocument, integer, MilestoneDocument } from "tachi-common"; -import { EvaluatedGoalReturn, EvaluateGoalForUser } from "./goals"; +import { + GoalSubscriptionDocument, + integer, + MilestoneDocument, + MilestoneSubscriptionDocument, +} from "tachi-common"; +import { EvaluatedGoalReturn, EvaluateGoalForUser, SubscribeToGoal } from "./goals"; const logger = CreateLogCtx(__filename); @@ -107,7 +112,7 @@ export async function EvaluateMilestoneProgress(userID: integer, milestone: Mile } } - const results: EvaluatedGoalResult[] = await Promise.all( + const goalResults: EvaluatedGoalResult[] = await Promise.all( goals.map(async (goal) => { if (isSubscribedToMilestone) { const goalSub = goalSubMap.get(goal.goalID); @@ -154,16 +159,79 @@ export async function EvaluateMilestoneProgress(userID: integer, milestone: Mile }) ); - const progress = results.filter((e) => e.achieved).length; + const progress = goalResults.filter((e) => e.achieved).length; const outOf = CalculateMilestoneOutOf(milestone); const achieved = progress >= outOf; return { goals, - results, + goalResults, achieved, progress, outOf, }; } + +/** + * Subscribes the given user to a provided milestone. If the user is already subscribed, + * null is returned. + * + * @param cancelIfAchieved - Don't subscribe to the milestone if subscribing would cause + * the user to immediately achieve it. + */ +export async function SubscribeToMilestone( + userID: integer, + milestone: MilestoneDocument, + cancelIfAchieved = true +) { + const isSubscribedToMilestone = await db["milestone-subs"].findOne({ + userID, + milestoneID: milestone.milestoneID, + }); + + if (isSubscribedToMilestone) { + return null; + } + + const result = await EvaluateMilestoneProgress(userID, milestone); + + if (result.achieved && cancelIfAchieved) { + return null; + } + + // @ts-expect-error TS can't resolve this. + // because it can't explode out the types. + const milestoneSub: MilestoneSubscriptionDocument = { + progress: result.progress, + userID, + milestoneID: milestone.milestoneID, + wasInstantlyAchieved: result.achieved, + timeSet: Date.now(), + game: milestone.game, + playtype: milestone.playtype, + achieved: result.achieved, + timeAchieved: result.achieved ? Date.now() : null, + }; + + // @optimisable, EvaluateMilestoneProgress calculates the users progress + // on each goal. We could probably shorten this by directly inserting the records + // from result.goalResults ourselves. + // evaluating goals is fairly cheap though. + await Promise.all( + result.goals.map((goal) => + SubscribeToGoal( + userID, + goal, + { milestoneID: milestone.milestoneID, origin: "milestone" }, + false + ) + ) + ); + + await db["milestone-subs"].insert(milestoneSub); + + logger.info(`User ${userID} subscribed to '${milestone.name}'.`); + + return { milestoneSub, goals: result.goals, goalResults: result.goalResults }; +} diff --git a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/milestones/router.ts b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/milestones/router.ts index ae62f7193..b06b56d0f 100644 --- a/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/milestones/router.ts +++ b/server/src/server/router/api/v1/users/_userID/games/_game/_playtype/targets/milestones/router.ts @@ -80,7 +80,11 @@ router.get("/:milestoneID", GetMilestoneSubscription, async (req, res) => { const milestone = await GetMilestoneForIDGuaranteed(milestoneSub.milestoneID); - const { progress, results, goals } = await EvaluateMilestoneProgress(user.id, milestone); + const { + progress, + goalResults: results, + goals, + } = await EvaluateMilestoneProgress(user.id, milestone); return res.status(200).json({ success: true,