From 6af2bf967f2f9d47c8947b3806ea01cd12d0badf Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Wed, 17 Feb 2021 04:51:12 +0900 Subject: [PATCH] Show fail percent --- youmubot-osu/src/discord/embeds.rs | 27 +++++++-- youmubot-osu/src/discord/mod.rs | 76 ++++++++++++++++++------- youmubot-osu/src/discord/oppai_cache.rs | 4 +- 3 files changed, 81 insertions(+), 26 deletions(-) diff --git a/youmubot-osu/src/discord/embeds.rs b/youmubot-osu/src/discord/embeds.rs index b8ff7a2..2491f7e 100644 --- a/youmubot-osu/src/discord/embeds.rs +++ b/youmubot-osu/src/discord/embeds.rs @@ -204,15 +204,27 @@ impl<'a> ScoreEmbedBuilder<'a> { let content = self.content; let u = self.u; let accuracy = s.accuracy(mode); - let stars = mode + let info = mode .to_oppai_mode() - .and_then(|mode| content.get_info_with(Some(mode), s.mods).ok()) + .and_then(|mode| content.get_info_with(Some(mode), s.mods).ok()); + let stars = info + .as_ref() .map(|info| info.stars as f64) .unwrap_or(b.difficulty.stars); let score_line = match &s.rank { Rank::SS | Rank::SSH => format!("SS"), _ if s.perfect => format!("{:.2}% FC", accuracy), - Rank::F => format!("{:.2}% {} combo [FAILED]", accuracy, s.max_combo), + Rank::F => { + let display = info + .map(|info| { + ((s.count_300 + s.count_100 + s.count_50 + s.count_miss) as f64) + / (info.objects as f64) + * 100.0 + }) + .map(|p| format!("FAILED @ {:.2}%", p)) + .unwrap_or("FAILED".to_owned()); + format!("{:.2}% {} combo [{}]", accuracy, s.max_combo, display) + } v => format!( "{:.2}% {}x {} miss {} rank", accuracy, s.max_combo, s.count_miss, v @@ -287,17 +299,22 @@ impl<'a> ScoreEmbedBuilder<'a> { .map(|v| format!("| #{} on Global Rankings!", v)) .unwrap_or("".to_owned()); let diff = b.difficulty.apply_mods(s.mods, Some(stars)); + let creator = if b.difficulty_name.contains("'s") { + "".to_owned() + } else { + format!("by {} ", b.creator) + }; m.author(|f| f.name(&u.username).url(u.link()).icon_url(u.avatar_url())) .color(0xffb6c1) .title(format!( - "{} | {} - {} [{}] {} ({:.2}\\*) by {} | {} {} {}", + "{} | {} - {} [{}] {} ({:.2}\\*) {}| {} {} {}", u.username, b.artist, b.title, b.difficulty_name, s.mods, stars, - b.creator, + creator, score_line, top_record, world_record, diff --git a/youmubot-osu/src/discord/mod.rs b/youmubot-osu/src/discord/mod.rs index 47360f7..db42722 100644 --- a/youmubot-osu/src/discord/mod.rs +++ b/youmubot-osu/src/discord/mod.rs @@ -1,6 +1,6 @@ use crate::{ discord::beatmap_cache::BeatmapMetaCache, - discord::oppai_cache::{BeatmapCache, OppaiAccuracy}, + discord::oppai_cache::{BeatmapCache, BeatmapInfo, OppaiAccuracy}, models::{Beatmap, Mode, Mods, Score, User}, request::UserID, Client as OsuHttpClient, @@ -331,7 +331,7 @@ async fn list_plays<'a>( const ITEMS_PER_PAGE: usize = 5; let total_pages = (plays.len() + ITEMS_PER_PAGE - 1) / ITEMS_PER_PAGE; paginate_reply_fn( - move |page, ctx, msg| { + move |page, ctx: &Context, msg| { let plays = plays.clone(); Box::pin(async move { let data = ctx.data.read().await; @@ -350,26 +350,16 @@ async fn list_plays<'a>( .iter() .map(|play| async move { let beatmap = osu.get_beatmap(play.beatmap_id, mode).await?; - let stars = { + let info = { let b = beatmap_cache.get_beatmap(beatmap.beatmap_id).await?; mode.to_oppai_mode() .and_then(|mode| b.get_info_with(Some(mode), play.mods).ok()) - .map(|info| info.stars as f64) - .unwrap_or(beatmap.difficulty.stars) }; - let r: Result<_> = Ok(format!( - "[{:.1}*] {} - {} [{}] ({})", - stars, - beatmap.artist, - beatmap.title, - beatmap.difficulty_name, - beatmap.short_link(Some(mode), Some(play.mods)), - )); - r + Ok((beatmap, info)) as Result<(Beatmap, Option)> }) .collect::>() - .map(|v| v.unwrap_or("FETCH_FAILED".to_owned())) - .collect::>(); + .map(|v| v.ok()) + .collect::>(); let pp = plays .iter() .map(|p| async move { @@ -404,6 +394,45 @@ async fn list_plays<'a>( .map(|v| v.unwrap_or("-".to_owned())) .collect::>(); let (beatmaps, pp) = future::join(beatmaps, pp).await; + + let ranks = plays + .iter() + .enumerate() + .map(|(i, p)| match p.rank { + crate::models::Rank::F => beatmaps[i] + .as_ref() + .and_then(|(_, i)| i.map(|i| i.objects)) + .map(|total| { + (p.count_300 + p.count_100 + p.count_50 + p.count_miss) as f64 + / (total as f64) + * 100.0 + }) + .map(|p| format!("F [{:.0}%]", p)) + .unwrap_or_else(|| "F".to_owned()), + v => v.to_string(), + }) + .collect::>(); + + let beatmaps = beatmaps + .into_iter() + .enumerate() + .map(|(i, b)| { + let play = &plays[i]; + b.map(|(beatmap, info)| { + format!( + "[{:.1}*] {} - {} [{}] ({})", + info.map(|i| i.stars as f64) + .unwrap_or(beatmap.difficulty.stars), + beatmap.artist, + beatmap.title, + beatmap.difficulty_name, + beatmap.short_link(Some(mode), Some(play.mods)), + ) + }) + .unwrap_or_else(|| "FETCH_FAILED".to_owned()) + }) + .collect::>(); + let pw = pp.iter().map(|v| v.len()).max().unwrap_or(2); /*mods width*/ let mw = plays @@ -414,23 +443,29 @@ async fn list_plays<'a>( .max(4); /*beatmap names*/ let bw = beatmaps.iter().map(|v| v.len()).max().unwrap().max(7); + /* ranks width */ + let rw = ranks.iter().map(|v| v.len()).max().unwrap().max(5); let mut m = MessageBuilder::new(); // Table header m.push_line(format!( - " # | {:pw$} | accuracy | rank | {:mw$} | {:bw$}", + " # | {:pw$} | accuracy | {:rw$} | {:mw$} | {:bw$}", "pp", + "ranks", "mods", "beatmap", + rw = rw, pw = pw, mw = mw, bw = bw )); m.push_line(format!( - "------{:-( // Each row for (id, (play, beatmap)) in plays.iter().zip(beatmaps.iter()).enumerate() { m.push_line(format!( - "{:>3} | {:>pw$} | {:>8} | {:^4} | {:mw$} | {:bw$}", + "{:>3} | {:>pw$} | {:>8} | {:^rw$} | {:mw$} | {:bw$}", id + start + 1, pp[id], format!("{:.2}%", play.accuracy(mode)), - play.rank.to_string(), + ranks[id], play.mods.to_string(), beatmap, + rw = rw, pw = pw, mw = mw, bw = bw diff --git a/youmubot-osu/src/discord/oppai_cache.rs b/youmubot-osu/src/discord/oppai_cache.rs index 94ba773..47c1fb3 100644 --- a/youmubot-osu/src/discord/oppai_cache.rs +++ b/youmubot-osu/src/discord/oppai_cache.rs @@ -13,6 +13,7 @@ pub struct BeatmapContent { /// the output of "one" oppai run. #[derive(Clone, Copy, Debug)] pub struct BeatmapInfo { + pub objects: u32, pub stars: f32, pub pp: [f32; 4], // 95, 98, 99, 100 } @@ -51,8 +52,9 @@ impl BeatmapContent { oppai.accuracy(99.0)?.pp(), oppai.accuracy(100.0)?.pp(), ]; + let objects = oppai.num_objects(); let stars = oppai.stars(); - Ok(BeatmapInfo { stars, pp }) + Ok(BeatmapInfo { stars, pp, objects }) } }