hypixel-sdk 0.2.1

Async client for the Hypixel Public API with typed models and SkyBlock helpers
Documentation
use hypixel::HypixelClient;
use hypixel::util::skyblock;
use serde_json::Value;

#[tokio::main]
async fn main() -> hypixel::Result<()> {
    dotenvy::dotenv().ok();
    let key = std::env::var("HYPIXEL_API_KEY").expect("set HYPIXEL_API_KEY");
    let uuid = std::env::args()
        .nth(1)
        .unwrap_or_else(|| "be5c42d4ea454601a57b944c6413f3cd".to_string());
    let member_id = uuid.replace('-', "");
    let client = HypixelClient::new(key);

    let profiles = client.skyblock_profiles(&uuid).await?;
    let profile = profiles
        .iter()
        .find(|p| p.selected)
        .or_else(|| profiles.first())
        .expect("player has no SkyBlock profiles");

    println!(
        "Profile: {} [{}]",
        profile.cute_name.as_deref().unwrap_or("?"),
        profile.game_mode.as_deref().unwrap_or("normal")
    );
    if let Some(banking) = &profile.banking {
        println!("Bank balance: {:.0}", banking.balance);
    }

    let member = profile
        .members
        .get(&member_id)
        .expect("uuid is not a member of this profile");

    let skills = client.resource_skyblock_skills().await?;
    let summary = skyblock::member_summary(member, Some(&skills));

    if let Some(level) = &summary.skyblock {
        println!("SkyBlock level: {:.2}", level.fractional_level);
    }
    if let Some(purse) = summary.coin_purse {
        println!("Purse: {purse:.0}");
    }

    if !summary.skills.is_empty() {
        println!("\nSkills:");
        let mut entries: Vec<_> = summary.skills.iter().collect();
        entries.sort_by_key(|(name, _)| name.to_owned());
        for (name, progress) in entries {
            println!(
                "  {name:<14} level {:>2}  ({:.0} xp)",
                progress.level, progress.total_xp
            );
        }
        if let Some(average) = summary.skill_average {
            println!("  Skill average: {average:.2}");
        }
    }

    if let Some(catacombs) = &summary.catacombs {
        println!("\nCatacombs: level {:.2}", catacombs.fractional_level);
    }
    for (class, progress) in &summary.classes {
        println!("  {class:<10} level {}", progress.level);
    }
    for (boss, progress) in &summary.slayers {
        println!("  {boss:<10} slayer {}", progress.level);
    }
    if let Some(hotm) = &summary.hotm {
        println!("HOTM tier: {}", hotm.level);
    }

    if let Some(count) = member
        .extra
        .get("collection")
        .and_then(Value::as_object)
        .map(|c| c.len())
    {
        println!("Tracked collections: {count}");
    }

    Ok(())
}