Show fail percent

This commit is contained in:
Natsu Kagami 2021-02-17 04:51:12 +09:00
parent 68e893a45e
commit 6af2bf967f
Signed by: nki
GPG key ID: 7306B3D3C3AD6E51
3 changed files with 81 additions and 26 deletions

View file

@ -204,15 +204,27 @@ impl<'a> ScoreEmbedBuilder<'a> {
let content = self.content; let content = self.content;
let u = self.u; let u = self.u;
let accuracy = s.accuracy(mode); let accuracy = s.accuracy(mode);
let stars = mode let info = mode
.to_oppai_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) .map(|info| info.stars as f64)
.unwrap_or(b.difficulty.stars); .unwrap_or(b.difficulty.stars);
let score_line = match &s.rank { let score_line = match &s.rank {
Rank::SS | Rank::SSH => format!("SS"), Rank::SS | Rank::SSH => format!("SS"),
_ if s.perfect => format!("{:.2}% FC", accuracy), _ 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!( v => format!(
"{:.2}% {}x {} miss {} rank", "{:.2}% {}x {} miss {} rank",
accuracy, s.max_combo, s.count_miss, v accuracy, s.max_combo, s.count_miss, v
@ -287,17 +299,22 @@ impl<'a> ScoreEmbedBuilder<'a> {
.map(|v| format!("| #{} on Global Rankings!", v)) .map(|v| format!("| #{} on Global Rankings!", v))
.unwrap_or("".to_owned()); .unwrap_or("".to_owned());
let diff = b.difficulty.apply_mods(s.mods, Some(stars)); 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())) m.author(|f| f.name(&u.username).url(u.link()).icon_url(u.avatar_url()))
.color(0xffb6c1) .color(0xffb6c1)
.title(format!( .title(format!(
"{} | {} - {} [{}] {} ({:.2}\\*) by {} | {} {} {}", "{} | {} - {} [{}] {} ({:.2}\\*) {}| {} {} {}",
u.username, u.username,
b.artist, b.artist,
b.title, b.title,
b.difficulty_name, b.difficulty_name,
s.mods, s.mods,
stars, stars,
b.creator, creator,
score_line, score_line,
top_record, top_record,
world_record, world_record,

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
discord::beatmap_cache::BeatmapMetaCache, discord::beatmap_cache::BeatmapMetaCache,
discord::oppai_cache::{BeatmapCache, OppaiAccuracy}, discord::oppai_cache::{BeatmapCache, BeatmapInfo, OppaiAccuracy},
models::{Beatmap, Mode, Mods, Score, User}, models::{Beatmap, Mode, Mods, Score, User},
request::UserID, request::UserID,
Client as OsuHttpClient, Client as OsuHttpClient,
@ -331,7 +331,7 @@ async fn list_plays<'a>(
const ITEMS_PER_PAGE: usize = 5; const ITEMS_PER_PAGE: usize = 5;
let total_pages = (plays.len() + ITEMS_PER_PAGE - 1) / ITEMS_PER_PAGE; let total_pages = (plays.len() + ITEMS_PER_PAGE - 1) / ITEMS_PER_PAGE;
paginate_reply_fn( paginate_reply_fn(
move |page, ctx, msg| { move |page, ctx: &Context, msg| {
let plays = plays.clone(); let plays = plays.clone();
Box::pin(async move { Box::pin(async move {
let data = ctx.data.read().await; let data = ctx.data.read().await;
@ -350,26 +350,16 @@ async fn list_plays<'a>(
.iter() .iter()
.map(|play| async move { .map(|play| async move {
let beatmap = osu.get_beatmap(play.beatmap_id, mode).await?; let beatmap = osu.get_beatmap(play.beatmap_id, mode).await?;
let stars = { let info = {
let b = beatmap_cache.get_beatmap(beatmap.beatmap_id).await?; let b = beatmap_cache.get_beatmap(beatmap.beatmap_id).await?;
mode.to_oppai_mode() mode.to_oppai_mode()
.and_then(|mode| b.get_info_with(Some(mode), play.mods).ok()) .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!( Ok((beatmap, info)) as Result<(Beatmap, Option<BeatmapInfo>)>
"[{:.1}*] {} - {} [{}] ({})",
stars,
beatmap.artist,
beatmap.title,
beatmap.difficulty_name,
beatmap.short_link(Some(mode), Some(play.mods)),
));
r
}) })
.collect::<stream::FuturesOrdered<_>>() .collect::<stream::FuturesOrdered<_>>()
.map(|v| v.unwrap_or("FETCH_FAILED".to_owned())) .map(|v| v.ok())
.collect::<Vec<String>>(); .collect::<Vec<_>>();
let pp = plays let pp = plays
.iter() .iter()
.map(|p| async move { .map(|p| async move {
@ -404,6 +394,45 @@ async fn list_plays<'a>(
.map(|v| v.unwrap_or("-".to_owned())) .map(|v| v.unwrap_or("-".to_owned()))
.collect::<Vec<String>>(); .collect::<Vec<String>>();
let (beatmaps, pp) = future::join(beatmaps, pp).await; 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::<Vec<_>>();
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::<Vec<_>>();
let pw = pp.iter().map(|v| v.len()).max().unwrap_or(2); let pw = pp.iter().map(|v| v.len()).max().unwrap_or(2);
/*mods width*/ /*mods width*/
let mw = plays let mw = plays
@ -414,23 +443,29 @@ async fn list_plays<'a>(
.max(4); .max(4);
/*beatmap names*/ /*beatmap names*/
let bw = beatmaps.iter().map(|v| v.len()).max().unwrap().max(7); 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(); let mut m = MessageBuilder::new();
// Table header // Table header
m.push_line(format!( m.push_line(format!(
" # | {:pw$} | accuracy | rank | {:mw$} | {:bw$}", " # | {:pw$} | accuracy | {:rw$} | {:mw$} | {:bw$}",
"pp", "pp",
"ranks",
"mods", "mods",
"beatmap", "beatmap",
rw = rw,
pw = pw, pw = pw,
mw = mw, mw = mw,
bw = bw bw = bw
)); ));
m.push_line(format!( m.push_line(format!(
"------{:-<pw$}---------------------{:-<mw$}---{:-<bw$}", "------{:-<pw$}--------------{:-<rw$}---{:-<mw$}---{:-<bw$}",
"", "",
"", "",
"", "",
"",
rw = rw,
pw = pw, pw = pw,
mw = mw, mw = mw,
bw = bw bw = bw
@ -438,13 +473,14 @@ async fn list_plays<'a>(
// Each row // Each row
for (id, (play, beatmap)) in plays.iter().zip(beatmaps.iter()).enumerate() { for (id, (play, beatmap)) in plays.iter().zip(beatmaps.iter()).enumerate() {
m.push_line(format!( m.push_line(format!(
"{:>3} | {:>pw$} | {:>8} | {:^4} | {:mw$} | {:bw$}", "{:>3} | {:>pw$} | {:>8} | {:^rw$} | {:mw$} | {:bw$}",
id + start + 1, id + start + 1,
pp[id], pp[id],
format!("{:.2}%", play.accuracy(mode)), format!("{:.2}%", play.accuracy(mode)),
play.rank.to_string(), ranks[id],
play.mods.to_string(), play.mods.to_string(),
beatmap, beatmap,
rw = rw,
pw = pw, pw = pw,
mw = mw, mw = mw,
bw = bw bw = bw

View file

@ -13,6 +13,7 @@ pub struct BeatmapContent {
/// the output of "one" oppai run. /// the output of "one" oppai run.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct BeatmapInfo { pub struct BeatmapInfo {
pub objects: u32,
pub stars: f32, pub stars: f32,
pub pp: [f32; 4], // 95, 98, 99, 100 pub pp: [f32; 4], // 95, 98, 99, 100
} }
@ -51,8 +52,9 @@ impl BeatmapContent {
oppai.accuracy(99.0)?.pp(), oppai.accuracy(99.0)?.pp(),
oppai.accuracy(100.0)?.pp(), oppai.accuracy(100.0)?.pp(),
]; ];
let objects = oppai.num_objects();
let stars = oppai.stars(); let stars = oppai.stars();
Ok(BeatmapInfo { stars, pp }) Ok(BeatmapInfo { stars, pp, objects })
} }
} }