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 @@ -403,6 +403,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 @@ -557,6 +567,7 @@ export async function updateRank(uuid, db) {
plusColor: null,
socials: {},
achievements: {},
achievementsOneTime: {},
claimed_items: {},
};

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

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

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

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

return hypixelPlayer;
}
Expand Down
49 changes: 49 additions & 0 deletions src/lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -2384,6 +2384,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 @@ -2396,6 +2397,54 @@ export const getStats = async (
misc.claimed_items = hypixelProfile.claimed_items;
}

const response = await axios("https://api.hypixel.net/resources/achievements");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't really like this, it gets called every time a profile loads... we should fetch it and cache it in db maybe like... every hour or so

Copy link
Contributor Author

@doej1367 doej1367 Apr 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. But where should I cache it? New table, one value and put the whole list in there? How does that work? I've never used db.collcetion so far...

I guess the code should look something like the following, but neither do I know how to do this, nor do I know how and where you want it cached.

let list = await db.collection("achievements")... // get list from db
if (!list || +new Date() - list.last_updated > 3600 * 1000) {
  const response = await axios("https://api.hypixel.net/resources/achievements");
  list = response;
  await db.collection("achievements")... // put updated list into db
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Me neither honestly, I would look at how we store bazaar data (that gets refreshed every 30min or so I think) and do it in the same way

Copy link
Contributor Author

@doej1367 doej1367 Apr 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tried but the query stays empty. There has to be some place where these are properly initialized - but the lines I set in init-collections.js seem not to work properly either:

db.collection("achievements_tiered").createIndex({ key: "text" }, { unique: true }),
db.collection("achievements_one_time").createIndex({ key: "text" }, { unique: true }),
let tieredAchievements = await db.collection("achievements_tiered").find().toArray();
  let oneTimeAchievements = await db.collection("achievements_one_time").find().toArray();
  console.log(tieredAchievements);
  console.log(oneTimeAchievements);
  if (!tieredAchievements || tieredAchievements == [] || !oneTimeAchievements || oneTimeAchievements == []) {
    //||
    //+new Date() - tieredAchievements?.last_updated > 3600 * 1000 ||
    //+new Date() - oneTimeAchievements?.last_updated > 3600 * 1000
    const response = await axios("https://api.hypixel.net/resources/achievements");
    let skyblock_achievements = response.data.achievements.skyblock;
    let tieredList = skyblock_achievements.tiered;
    let oneTimeList = skyblock_achievements.one_time;

    for (const key in tieredList) {
      const tmp = tieredList[key];
      await db
        .collection("achievements_tiered")
        .updateOne(
          { key },
          { $set: { name: tmp.name, description: tmp.description, tiers: tmp.tiers } },
          { upsert: true }
        );
    }
    for (const key in oneTimeList) {
      const tmp = oneTimeList[key];
      await db
        .collection("achievements_one_time")
        .updateOne(
          { key },
          { $set: { name: tmp.name, description: tmp.description, points: tmp.points, amount: tmp.amount } },
          { upsert: true }
        );
    }
    tieredAchievements = await db.collection("achievements_tiered").find().toArray();
    oneTimeAchievements = await db.collection("achievements_one_time").find().toArray();
    console.log(tieredAchievements);
    console.log(oneTimeAchievements);
  }

I think I leave that caching part to someone else... (reset my working copy to the last working version)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for directly commiting it to your repo, but I hope this is what you wanted.

Copy link
Contributor Author

@doej1367 doej1367 Apr 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for directly commiting it to your repo, but I hope this is what you wanted.

On the contrary - one of the reasons I allow "edits by mantainers". It was a little bit out of my reach considdering my current knowledge about this project, javascript and mongodb. Thank you for your commit to my repo.

let _tiered = { sum: 0, total: 0, completed: {}, uncompleted: {} };
let _oneTime = { sum: 0, total: 0, completed: {}, uncompleted: {} };
if (response?.data?.achievements?.skyblock) {
let skyblock_achievements = response.data.achievements.skyblock;
let tieredAchievements = skyblock_achievements.tiered;
let oneTimeAchievements = skyblock_achievements.one_time;

for (const key in tieredAchievements) {
const tmp = tieredAchievements[key];
_tiered.total += tmp.tiers.map((a) => a.points).reduce((a, b) => a + b, 0);
let tier = 0;
for (const req in tmp.tiers) {
if (tmp.tiers[req].amount <= hypixelProfile.achievements["skyblock_" + key.toLowerCase()]) {
tier++;
_tiered.sum += Number(tmp.tiers[req].points);
}
}
let achievement = {
name: tmp.name,
description: tmp.description.replaceAll("%s", "x"),
level: hypixelProfile.achievements["skyblock_" + key.toLowerCase()] || 0,
tier: tier,
};
if (tier >= 5) {
_tiered.completed["skyblock_" + key.toLowerCase()] = achievement;
} else {
_tiered.uncompleted["skyblock_" + key.toLowerCase()] = achievement;
}
}
for (const key in oneTimeAchievements) {
const tmp = oneTimeAchievements[key];
_oneTime.total += tmp.points;
let achievement = { name: tmp.name, description: tmp.description, reward: tmp.points };
if (
hypixelProfile.achievementsOneTime &&
hypixelProfile.achievementsOneTime.includes("skyblock_" + key.toLowerCase())
) {
_oneTime.completed["skyblock_" + key.toLowerCase()] = achievement;
_oneTime.sum += Number(tmp.points);
} else {
_oneTime.uncompleted["skyblock_" + key.toLowerCase()] = achievement;
}
}
}
misc.achievements.tiered = _tiered;
misc.achievements.oneTime = _oneTime;

const burrows = [
"mythos_burrows_dug_next",
"mythos_burrows_dug_combat",
Expand Down
53 changes: 53 additions & 0 deletions views/stats.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -2721,6 +2721,59 @@ const metaDescription = getMetaDescription()
<% } %>
</p>
<% } %>
<% if('achievements' in calculated.misc){ %>
<% let list = calculated.misc.achievements; %>
<div class="category-header"><div class="category-icon"><div class="item-icon icon-267_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 Achievement Points: </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 Achievement Points: </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>
<% } %>

<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>
</p>
<% } %>
</div>
</div>
<% } %>
Expand Down