Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SkyBlock Achievements #1292

Open
wants to merge 12 commits into
base: development
Choose a base branch
from
17 changes: 16 additions & 1 deletion src/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,16 @@ export function renderRaceTier(completeTiers) {
return "●".repeat(completeTiers) + "○".repeat(incompleteTiers);
}

/**
* returns a string with 5 dots "●" for completed tiers and "○" for incomplete tiers
* @param {number} completeTiers
* @returns {string} 5 dots
*/
export function renderAchievementTier(completeTiers) {
const incompleteTiers = Math.max(0, 5 - completeTiers);
return "●".repeat(completeTiers) + "○".repeat(incompleteTiers);
}

/**
* checks whether a string should be proceeded by a or by an
* @param {string} string
Expand Down Expand Up @@ -533,6 +543,7 @@ export async function updateRank(uuid, db) {
plusColor: null,
socials: {},
achievements: {},
achievementsOneTime: {},
claimed_items: {},
};

Expand All @@ -558,6 +569,10 @@ export async function updateRank(uuid, db) {
rank.achievements = player.achievements;
}

if (player?.achievementsOneTime != undefined) {
rank.achievementsOneTime = player.achievementsOneTime;
}

const claimable = {
claimed_potato_talisman: "Potato Talisman",
claimed_potato_basket: "Potato Basket",
Expand Down Expand Up @@ -602,7 +617,7 @@ export async function getRank(uuid, db, cacheOnly = false) {
hypixelPlayer = await _updateRank;
}

hypixelPlayer ??= { achievements: {} };
hypixelPlayer ??= { achievements: {}, achievementsOneTime: {} };

return hypixelPlayer;
}
Expand Down
52 changes: 52 additions & 0 deletions src/lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -1931,6 +1931,7 @@ export const getStats = async (
misc.auctions_sell = {};
misc.auctions_buy = {};
misc.claimed_items = {};
misc.achievements = {};

if ("ender_crystals_destroyed" in userProfile.stats) {
misc.dragons["ender_crystals_destroyed"] = userProfile.stats["ender_crystals_destroyed"];
Expand All @@ -1943,6 +1944,57 @@ export const getStats = async (
misc.claimed_items = hypixelProfile.claimed_items;
}

const _tiered = { sum: 0, total: 0, completed: {}, uncompleted: {} };
const _oneTime = { sum: 0, total: 0, completed: {}, uncompleted: {} };
for await (const tmp of db.collection("achievements").find()) {
if (tmp?.tiered) {
_tiered.total += tmp.achievement.tiers.map((a) => a.points).reduce((a, b) => a + b, 0);

let tier = 0;
for (const req in tmp.achievement.tiers) {
if (tmp.achievement.tiers[req].amount <= hypixelProfile.achievements["skyblock_" + tmp.id.toLowerCase()]) {
tier++;
_tiered.sum += Number(tmp.achievement.tiers[req].points);
}
}

const achievement = {
name: tmp.achievement.name,
description: tmp.achievement.description.replaceAll("%s", "x"),
level: hypixelProfile.achievements["skyblock_" + tmp.id.toLowerCase()] || 0,
tier: tier,
};

if (tier >= 5) {
_tiered.completed["skyblock_" + tmp.id.toLowerCase()] = achievement;
} else {
_tiered.uncompleted["skyblock_" + tmp.id.toLowerCase()] = achievement;
}
}

if (tmp?.one_time) {
_oneTime.total += tmp.achievement.points;
const achievement = {
name: tmp.achievement.name,
description: tmp.achievement.description,
reward: tmp.achievement.points,
};

if (
hypixelProfile.achievementsOneTime &&
hypixelProfile.achievementsOneTime.includes("skyblock_" + tmp.id.toLowerCase())
) {
_oneTime.completed["skyblock_" + tmp.id.toLowerCase()] = achievement;
_oneTime.sum += Number(tmp.achievement.points);
} else {
_oneTime.uncompleted["skyblock_" + tmp.id.toLowerCase()] = achievement;
}
}
}

misc.achievements.tiered = _tiered;
misc.achievements.oneTime = _oneTime;

const burrows = [
"mythos_burrows_dug_next",
"mythos_burrows_dug_combat",
Expand Down
1 change: 1 addition & 0 deletions src/master.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ await import("./scripts/init-collections.js");
await Promise.all([
import("./scripts/cap-leaderboards.js"),
import("./scripts/clear-favorite-cache.js"),
import("./scripts/update-achievements.js"),
import("./scripts/update-bazaar.js"),
import("./scripts/update-items.js"),
import("./scripts/update-featured-profiles.js"),
Expand Down
2 changes: 2 additions & 0 deletions src/scripts/init-collections.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,6 @@ await Promise.all([
db.collection("profileCache").createIndex({ profile_id: 1 }, { unique: true }),

db.collection("featuredProfiles").createIndex({ total: -1 }),

db.collection("achievements").createIndex({ id: 1 }, { unique: true }),
]);
42 changes: 42 additions & 0 deletions src/scripts/update-achievements.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { db } from "../mongo.js";
import axios from "axios";
import "axios-debug-log";

const Hypixel = axios.create({
baseURL: "https://api.hypixel.net/",
});

async function updateAchievements() {
try {
const response = await Hypixel.get("resources/achievements");

const achievements = [];
const { one_time, tiered } = response.data.achievements.skyblock;

for (const achId in one_time) {
achievements.push({
id: achId,
one_time: true,
achievement: one_time[achId],
});
}

for (const achId in tiered) {
achievements.push({
id: achId,
tiered: true,
achievement: tiered[achId],
});
}

achievements.forEach(async (item) => {
await db.collection("achievements").updateOne({ id: item.id }, { $set: item }, { upsert: true });
});
} catch (e) {
console.error(e);
}

setTimeout(updateAchievements, 1000 * 60 * 60 * 6);
}

updateAchievements();
54 changes: 53 additions & 1 deletion views/stats.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -2478,7 +2478,6 @@ const metaDescription = getMetaDescription()
<% } %>
</p>
<% } %>

<% if ('uncategorized' in calculated.misc && Object.keys(calculated.misc.uncategorized).length > 0) { %>
<div class="category-header"><div class="category-icon"><div class="item-icon icon-421_0"></div></div><span>Uncategorized</span></div>
<p class="stat-raw-values">
Expand All @@ -2488,6 +2487,59 @@ const metaDescription = getMetaDescription()
<% } %>
</p>
<% } %>
<% if ('achievements' in calculated.misc) { %>
<% const list = calculated.misc.achievements; %>
<div class="category-header"><div class="category-icon"><div class="item-icon icon-340_0"></div></div><span>achievements</span></div>
<p class="stat-raw-values stat-achievements">
<% if('tiered' in list){ %>
<span class="stat-name<%= (list.tiered.sum >= list.tiered.total ?" golden-text":"") %>">Tiered <abbr title="Achievement Points">AP</abbr>: </span><span class="stat-value<%= (list.tiered.sum >= list.tiered.total ?" golden-text":"") %>"><%= list.tiered.sum %> / <%= list.tiered.total %></span><span class="grey-text"> (<%= Math.floor(list.tiered.sum / list.tiered.total * 100) %>%)</span><br>
<% } %>
<% if('oneTime' in list){ %>
<span class="stat-name<%= (list.oneTime.sum >= list.oneTime.total ?" golden-text":"") %>">One Time <abbr title="Achievement Points">AP</abbr>: </span><span class="stat-value<%= (list.oneTime.sum >= list.oneTime.total ?" golden-text":"") %>"><%= list.oneTime.sum %> / <%= list.oneTime.total %></span><span class="grey-text"> (<%= Math.floor(list.oneTime.sum / list.oneTime.total * 100) %>%)</span><br>
<% } %>
</p>

<div class="achievements-container narrow-info-container-wrapper">
<div class="narrow-info-container achievements-tiered">
<div class="narrow-info-header">Tiered</div>
<div class="narrow-info-content">
<% if('tiered' in list && 'uncompleted' in list.tiered && 'completed' in list.tiered){ %>
<% for(const key in list.tiered.uncompleted){ %>
<div class="narrow-info-flexsb">
<div class="achievements-stat" data-tippy-content='<%= list.tiered.uncompleted[key].description %>'><%= list.tiered.uncompleted[key].name %><span class="grey-text"> (<%= list.tiered.uncompleted[key].level %>)</span></div>
<div><span class="stat-value"><%= helper.renderAchievementTier(list.tiered.uncompleted[key].tier) %></span></div>
</div>
<% } %>
<% for(const key in list.tiered.completed){ %>
<div class="narrow-info-flexsb">
<div class="achievements-stat golden-text" data-tippy-content='<%= list.tiered.completed[key].description %>'><%= list.tiered.completed[key].name %><span class="grey-text"> (<%= list.tiered.completed[key].level %>)</span></div>
<div><span class="stat-value"><%= helper.renderAchievementTier(list.tiered.completed[key].tier) %></span></div>
</div>
<% } %>
<% } %>
</div>
</div>
<div class="narrow-info-container achievements-oneTime">
<div class="narrow-info-header">One Time</div>
<div class="narrow-info-content">
<% if('oneTime' in list && 'uncompleted' in list.oneTime && 'completed' in list.oneTime){ %>
<% for(const key in list.oneTime.uncompleted){ %>
<div class="narrow-info-flexsb">
<div class="achievements-stat" data-tippy-content='<%= list.oneTime.uncompleted[key].description %>'><%= list.oneTime.uncompleted[key].name %></div>
<div class="grey-text">&nbsp;<%= list.oneTime.uncompleted[key].reward %></div>
</div>
<% } %>
<% for(const key in list.oneTime.completed){ %>
<div class="narrow-info-flexsb">
<div class="achievements-stat golden-text" data-tippy-content='<%= list.oneTime.completed[key].description %>'><%= list.oneTime.completed[key].name %></div>
<div class="grey-text">&nbsp;<%= list.oneTime.completed[key].reward %></div>
</div>
<% } %>
<% } %>
</div>
</div>
</div>
<% } %>
</div>
</div>
<% } %>
Expand Down