From e4a55d99586be8d0676ce03c3e91e33bef1bbeb4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Mar 2024 09:04:27 +0000 Subject: [PATCH 1/5] Bump mio from 0.8.10 to 0.8.11 (#36) Bumps [mio](https://github.com/tokio-rs/mio) from 0.8.10 to 0.8.11. - [Release notes](https://github.com/tokio-rs/mio/releases) - [Changelog](https://github.com/tokio-rs/mio/blob/master/CHANGELOG.md) - [Commits](https://github.com/tokio-rs/mio/compare/v0.8.10...v0.8.11) --- updated-dependencies: - dependency-name: mio dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 36f8772..d198d81 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1230,9 +1230,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "wasi", From a50f44ad90b2fd9b30168c6a89b5b5be39daaf72 Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Tue, 5 Mar 2024 22:18:08 +0100 Subject: [PATCH 2/5] Don't respond to the bot's pagination reaction --- youmubot-prelude/src/pagination.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/youmubot-prelude/src/pagination.rs b/youmubot-prelude/src/pagination.rs index fe5335a..c62dcc9 100644 --- a/youmubot-prelude/src/pagination.rs +++ b/youmubot-prelude/src/pagination.rs @@ -144,6 +144,7 @@ async fn paginate_with_first_message( let mut reaction_collector = { // message.await_reactions(ctx).removed(true).build(); let message_id = message.id; + let me = message.author.id; collector::collect(&ctx.shard, move |event| { match event { serenity::all::Event::ReactionAdd(r) => Some(r.reaction.clone()), @@ -151,6 +152,7 @@ async fn paginate_with_first_message( _ => None, } .filter(|r| r.message_id == message_id) + .filter(|r| r.user_id.is_some_and(|id| id != me)) }) }; let mut page = 0; From 11f32ccf046ba35196361575638a17d9eef8fe3a Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Wed, 6 Mar 2024 00:01:38 +0100 Subject: [PATCH 3/5] osu: Implement map length on server ranks --- README.md | 9 + ...20dfd7f9d3df62a35ba63c61efc5de70e750d.json | 12 -- ...58ec9de4802d90dbb2ab48de32c1a4ada601.json} | 12 +- ...6c0e59d61596cb609c4bb952edc2d64cec868.json | 12 ++ ...6b1a1cd2aeb89517b7ee09e7e6f8d6e0cd79.json} | 12 +- ...a90ec3137398e83b3d0c626209306804399a.json} | 12 +- ...0305211858_osu_add_weighted_map_length.sql | 5 + youmubot-db-sql/src/models/osu_user.rs | 23 ++- youmubot-osu/src/discord/announcer.rs | 32 ++++ youmubot-osu/src/discord/db.rs | 3 + youmubot-osu/src/discord/mod.rs | 1 + youmubot-osu/src/discord/server_rank.rs | 167 +++++++++++++----- 12 files changed, 229 insertions(+), 71 deletions(-) delete mode 100644 youmubot-db-sql/.sqlx/query-26a910506c0613936be169df13320dfd7f9d3df62a35ba63c61efc5de70e750d.json rename youmubot-db-sql/.sqlx/{query-5753fe315c9a55154d2d80e6d293dc8abffcf426b845624a42cd0bfefc75fb74.json => query-6ef67ca385287a4cef9fdd47bf4258ec9de4802d90dbb2ab48de32c1a4ada601.json} (81%) create mode 100644 youmubot-db-sql/.sqlx/query-a06efa1b12c2c7c9cf5b83bff796c0e59d61596cb609c4bb952edc2d64cec868.json rename youmubot-db-sql/.sqlx/{query-08f2568a69a14ae240a24264238d4abc7aea5eee67d6062d049f0d37031e4d7a.json => query-b098282e73cc6fd435330f6ecd446b1a1cd2aeb89517b7ee09e7e6f8d6e0cd79.json} (80%) rename youmubot-db-sql/.sqlx/{query-700ec95294d9a4f21e3d7ff53f15f5dc739bffe8fedc19e35cbb576b6dd2e948.json => query-df0aa5065268e59c68990ab46ab4a90ec3137398e83b3d0c626209306804399a.json} (80%) create mode 100644 youmubot-db-sql/migrations/20240305211858_osu_add_weighted_map_length.sql diff --git a/README.md b/README.md index 90c041e..356a591 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,15 @@ All PRs welcome. - `youmubot-core`: Core commands: admin, fun, community - `youmubot-osu`: osu!-related commands. +## Working with `sqlx` + +### Regenerate compiler information + +From within `./youmubot-db-sql` run +```bash +cargo sqlx prepare --database-url "sqlite:$(realpath ..)/youmubot.db" +``` + ## License Basically MIT. diff --git a/youmubot-db-sql/.sqlx/query-26a910506c0613936be169df13320dfd7f9d3df62a35ba63c61efc5de70e750d.json b/youmubot-db-sql/.sqlx/query-26a910506c0613936be169df13320dfd7f9d3df62a35ba63c61efc5de70e750d.json deleted file mode 100644 index cfd5f19..0000000 --- a/youmubot-db-sql/.sqlx/query-26a910506c0613936be169df13320dfd7f9d3df62a35ba63c61efc5de70e750d.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "INSERT\n INTO osu_users(user_id, username, id, last_update, pp_std, pp_taiko, pp_mania, pp_catch, failures)\n VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT (user_id) WHERE id = ? DO UPDATE\n SET\n last_update = excluded.last_update,\n username = excluded.username,\n pp_std = excluded.pp_std,\n pp_taiko = excluded.pp_taiko,\n pp_mania = excluded.pp_mania,\n pp_catch = excluded.pp_catch,\n failures = excluded.failures\n ", - "describe": { - "columns": [], - "parameters": { - "Right": 10 - }, - "nullable": [] - }, - "hash": "26a910506c0613936be169df13320dfd7f9d3df62a35ba63c61efc5de70e750d" -} diff --git a/youmubot-db-sql/.sqlx/query-5753fe315c9a55154d2d80e6d293dc8abffcf426b845624a42cd0bfefc75fb74.json b/youmubot-db-sql/.sqlx/query-6ef67ca385287a4cef9fdd47bf4258ec9de4802d90dbb2ab48de32c1a4ada601.json similarity index 81% rename from youmubot-db-sql/.sqlx/query-5753fe315c9a55154d2d80e6d293dc8abffcf426b845624a42cd0bfefc75fb74.json rename to youmubot-db-sql/.sqlx/query-6ef67ca385287a4cef9fdd47bf4258ec9de4802d90dbb2ab48de32c1a4ada601.json index 7d74007..9935fbd 100644 --- a/youmubot-db-sql/.sqlx/query-5753fe315c9a55154d2d80e6d293dc8abffcf426b845624a42cd0bfefc75fb74.json +++ b/youmubot-db-sql/.sqlx/query-6ef67ca385287a4cef9fdd47bf4258ec9de4802d90dbb2ab48de32c1a4ada601.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "SELECT\n user_id as \"user_id: i64\",\n username,\n id as \"id: i64\",\n last_update as \"last_update: DateTime\",\n pp_std, pp_taiko, pp_mania, pp_catch,\n failures as \"failures: u8\"\n FROM osu_users", + "query": "SELECT\n user_id as \"user_id: i64\",\n username,\n id as \"id: i64\",\n last_update as \"last_update: DateTime\",\n pp_std, pp_taiko, pp_mania, pp_catch,\n failures as \"failures: u8\",\n std_weighted_map_length\n FROM osu_users", "describe": { "columns": [ { @@ -47,6 +47,11 @@ "name": "failures: u8", "ordinal": 8, "type_info": "Int64" + }, + { + "name": "std_weighted_map_length", + "ordinal": 9, + "type_info": "Float" } ], "parameters": { @@ -61,8 +66,9 @@ true, true, true, - false + false, + true ] }, - "hash": "5753fe315c9a55154d2d80e6d293dc8abffcf426b845624a42cd0bfefc75fb74" + "hash": "6ef67ca385287a4cef9fdd47bf4258ec9de4802d90dbb2ab48de32c1a4ada601" } diff --git a/youmubot-db-sql/.sqlx/query-a06efa1b12c2c7c9cf5b83bff796c0e59d61596cb609c4bb952edc2d64cec868.json b/youmubot-db-sql/.sqlx/query-a06efa1b12c2c7c9cf5b83bff796c0e59d61596cb609c4bb952edc2d64cec868.json new file mode 100644 index 0000000..f69c8f9 --- /dev/null +++ b/youmubot-db-sql/.sqlx/query-a06efa1b12c2c7c9cf5b83bff796c0e59d61596cb609c4bb952edc2d64cec868.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT\n INTO osu_users(user_id, username, id, last_update, pp_std, pp_taiko, pp_mania, pp_catch, failures, std_weighted_map_length)\n VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT (user_id) WHERE id = ? DO UPDATE\n SET\n last_update = excluded.last_update,\n username = excluded.username,\n pp_std = excluded.pp_std,\n pp_taiko = excluded.pp_taiko,\n pp_mania = excluded.pp_mania,\n pp_catch = excluded.pp_catch,\n failures = excluded.failures,\n std_weighted_map_length = excluded.std_weighted_map_length\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 11 + }, + "nullable": [] + }, + "hash": "a06efa1b12c2c7c9cf5b83bff796c0e59d61596cb609c4bb952edc2d64cec868" +} diff --git a/youmubot-db-sql/.sqlx/query-08f2568a69a14ae240a24264238d4abc7aea5eee67d6062d049f0d37031e4d7a.json b/youmubot-db-sql/.sqlx/query-b098282e73cc6fd435330f6ecd446b1a1cd2aeb89517b7ee09e7e6f8d6e0cd79.json similarity index 80% rename from youmubot-db-sql/.sqlx/query-08f2568a69a14ae240a24264238d4abc7aea5eee67d6062d049f0d37031e4d7a.json rename to youmubot-db-sql/.sqlx/query-b098282e73cc6fd435330f6ecd446b1a1cd2aeb89517b7ee09e7e6f8d6e0cd79.json index 36adbd6..9d44a8a 100644 --- a/youmubot-db-sql/.sqlx/query-08f2568a69a14ae240a24264238d4abc7aea5eee67d6062d049f0d37031e4d7a.json +++ b/youmubot-db-sql/.sqlx/query-b098282e73cc6fd435330f6ecd446b1a1cd2aeb89517b7ee09e7e6f8d6e0cd79.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "SELECT\n user_id as \"user_id: i64\",\n username,\n id as \"id: i64\",\n last_update as \"last_update: DateTime\",\n pp_std, pp_taiko, pp_mania, pp_catch,\n failures as \"failures: u8\"\n FROM osu_users WHERE id = ?", + "query": "SELECT\n user_id as \"user_id: i64\",\n username,\n id as \"id: i64\",\n last_update as \"last_update: DateTime\",\n pp_std, pp_taiko, pp_mania, pp_catch,\n failures as \"failures: u8\",\n std_weighted_map_length\n FROM osu_users WHERE id = ?", "describe": { "columns": [ { @@ -47,6 +47,11 @@ "name": "failures: u8", "ordinal": 8, "type_info": "Int64" + }, + { + "name": "std_weighted_map_length", + "ordinal": 9, + "type_info": "Float" } ], "parameters": { @@ -61,8 +66,9 @@ true, true, true, - false + false, + true ] }, - "hash": "08f2568a69a14ae240a24264238d4abc7aea5eee67d6062d049f0d37031e4d7a" + "hash": "b098282e73cc6fd435330f6ecd446b1a1cd2aeb89517b7ee09e7e6f8d6e0cd79" } diff --git a/youmubot-db-sql/.sqlx/query-700ec95294d9a4f21e3d7ff53f15f5dc739bffe8fedc19e35cbb576b6dd2e948.json b/youmubot-db-sql/.sqlx/query-df0aa5065268e59c68990ab46ab4a90ec3137398e83b3d0c626209306804399a.json similarity index 80% rename from youmubot-db-sql/.sqlx/query-700ec95294d9a4f21e3d7ff53f15f5dc739bffe8fedc19e35cbb576b6dd2e948.json rename to youmubot-db-sql/.sqlx/query-df0aa5065268e59c68990ab46ab4a90ec3137398e83b3d0c626209306804399a.json index ec5b5f5..bbca50f 100644 --- a/youmubot-db-sql/.sqlx/query-700ec95294d9a4f21e3d7ff53f15f5dc739bffe8fedc19e35cbb576b6dd2e948.json +++ b/youmubot-db-sql/.sqlx/query-df0aa5065268e59c68990ab46ab4a90ec3137398e83b3d0c626209306804399a.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "SELECT\n user_id as \"user_id: i64\",\n username,\n id as \"id: i64\",\n last_update as \"last_update: DateTime\",\n pp_std, pp_taiko, pp_mania, pp_catch,\n failures as \"failures: u8\"\n FROM osu_users WHERE user_id = ?", + "query": "SELECT\n user_id as \"user_id: i64\",\n username,\n id as \"id: i64\",\n last_update as \"last_update: DateTime\",\n pp_std, pp_taiko, pp_mania, pp_catch,\n failures as \"failures: u8\",\n std_weighted_map_length\n FROM osu_users WHERE user_id = ?", "describe": { "columns": [ { @@ -47,6 +47,11 @@ "name": "failures: u8", "ordinal": 8, "type_info": "Int64" + }, + { + "name": "std_weighted_map_length", + "ordinal": 9, + "type_info": "Float" } ], "parameters": { @@ -61,8 +66,9 @@ true, true, true, - false + false, + true ] }, - "hash": "700ec95294d9a4f21e3d7ff53f15f5dc739bffe8fedc19e35cbb576b6dd2e948" + "hash": "df0aa5065268e59c68990ab46ab4a90ec3137398e83b3d0c626209306804399a" } diff --git a/youmubot-db-sql/migrations/20240305211858_osu_add_weighted_map_length.sql b/youmubot-db-sql/migrations/20240305211858_osu_add_weighted_map_length.sql new file mode 100644 index 0000000..b20439b --- /dev/null +++ b/youmubot-db-sql/migrations/20240305211858_osu_add_weighted_map_length.sql @@ -0,0 +1,5 @@ +-- Add migration script here + +ALTER TABLE osu_users + ADD COLUMN std_weighted_map_length DOUBLE NULL DEFAULT NULL; + diff --git a/youmubot-db-sql/src/models/osu_user.rs b/youmubot-db-sql/src/models/osu_user.rs index 3de2487..f743e19 100644 --- a/youmubot-db-sql/src/models/osu_user.rs +++ b/youmubot-db-sql/src/models/osu_user.rs @@ -14,6 +14,8 @@ pub struct OsuUser { pub pp_catch: Option, /// Number of consecutive update failures pub failures: u8, + + pub std_weighted_map_length: Option, } impl OsuUser { @@ -30,7 +32,8 @@ impl OsuUser { id as "id: i64", last_update as "last_update: DateTime", pp_std, pp_taiko, pp_mania, pp_catch, - failures as "failures: u8" + failures as "failures: u8", + std_weighted_map_length FROM osu_users WHERE user_id = ?"#, user_id ) @@ -52,7 +55,8 @@ impl OsuUser { id as "id: i64", last_update as "last_update: DateTime", pp_std, pp_taiko, pp_mania, pp_catch, - failures as "failures: u8" + failures as "failures: u8", + std_weighted_map_length FROM osu_users WHERE id = ?"#, osu_id ) @@ -74,7 +78,8 @@ impl OsuUser { id as "id: i64", last_update as "last_update: DateTime", pp_std, pp_taiko, pp_mania, pp_catch, - failures as "failures: u8" + failures as "failures: u8", + std_weighted_map_length FROM osu_users"#, ) .fetch_many(conn) @@ -90,8 +95,8 @@ impl OsuUser { { query!( r#"INSERT - INTO osu_users(user_id, username, id, last_update, pp_std, pp_taiko, pp_mania, pp_catch, failures) - VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?) + INTO osu_users(user_id, username, id, last_update, pp_std, pp_taiko, pp_mania, pp_catch, failures, std_weighted_map_length) + VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT (user_id) WHERE id = ? DO UPDATE SET last_update = excluded.last_update, @@ -100,7 +105,8 @@ impl OsuUser { pp_taiko = excluded.pp_taiko, pp_mania = excluded.pp_mania, pp_catch = excluded.pp_catch, - failures = excluded.failures + failures = excluded.failures, + std_weighted_map_length = excluded.std_weighted_map_length "#, self.user_id, self.username, @@ -111,7 +117,10 @@ impl OsuUser { self.pp_mania, self.pp_catch, self.failures, - self.user_id).execute(conn).await?; + self.std_weighted_map_length, + + self.user_id, + ).execute(conn).await?; Ok(()) } diff --git a/youmubot-osu/src/discord/announcer.rs b/youmubot-osu/src/discord/announcer.rs index e88f2bd..91836c7 100644 --- a/youmubot-osu/src/discord/announcer.rs +++ b/youmubot-osu/src/discord/announcer.rs @@ -1,4 +1,5 @@ use super::db::{OsuSavedUsers, OsuUser}; +use super::OsuClient; use super::{embeds::score_embed, BeatmapWithMode}; use crate::{ discord::beatmap_cache::BeatmapMetaCache, @@ -19,6 +20,7 @@ use serenity::{ }; use std::{convert::TryInto, sync::Arc}; use youmubot_prelude::announcer::CacheAndHttp; +use youmubot_prelude::stream::{FuturesUnordered, TryStreamExt}; use youmubot_prelude::*; /// osu! announcer's unique announcer key. @@ -83,7 +85,12 @@ impl youmubot_prelude::Announcer for Announcer { .unwrap(); osu_user.username = v.into_iter().next().unwrap().username.into(); osu_user.last_update = now; + osu_user.std_weighted_map_length = + Self::std_weighted_map_length(&ctx, &osu_user) + .await + .pls_ok(); let id = osu_user.id; + println!("{:?}", osu_user); ctx.data .read() .await @@ -185,6 +192,31 @@ impl Announcer { .collect(); Ok(scores) } + + async fn std_weighted_map_length(ctx: &Context, u: &OsuUser) -> Result { + let data = ctx.data.read().await; + let client = data.get::().unwrap().clone(); + let cache = data.get::().unwrap(); + let scores = client + .user_best(UserID::ID(u.id), |f| f.mode(Mode::Std).limit(100)) + .await?; + scores + .into_iter() + .enumerate() + .map(|(i, s)| async move { + let beatmap = cache.get_beatmap_default(s.beatmap_id).await?; + const SCALING_FACTOR: f64 = 0.975; + Ok(beatmap + .difficulty + .apply_mods(s.mods, 0.0 /* dont care */) + .drain_length + .as_secs_f64() + * (SCALING_FACTOR.powi(i as i32))) + }) + .collect::>() + .try_fold(0.0, |a, b| future::ready(Ok(a + b))) + .await + } } #[derive(Clone)] diff --git a/youmubot-osu/src/discord/db.rs b/youmubot-osu/src/discord/db.rs index 9f8c2cf..ad54c8d 100644 --- a/youmubot-osu/src/discord/db.rs +++ b/youmubot-osu/src/discord/db.rs @@ -145,6 +145,7 @@ pub struct OsuUser { pub id: u64, pub last_update: DateTime, pub pp: [Option; 4], + pub std_weighted_map_length: Option, /// More than 5 failures => gone pub failures: u8, } @@ -160,6 +161,7 @@ impl From for model::OsuUser { pp_taiko: u.pp[Mode::Taiko as usize], pp_catch: u.pp[Mode::Catch as usize], pp_mania: u.pp[Mode::Mania as usize], + std_weighted_map_length: u.std_weighted_map_length, failures: u.failures, } } @@ -178,6 +180,7 @@ impl From for OsuUser { Mode::Catch => u.pp_catch, Mode::Mania => u.pp_mania, }), + std_weighted_map_length: u.std_weighted_map_length, failures: u.failures, } } diff --git a/youmubot-osu/src/discord/mod.rs b/youmubot-osu/src/discord/mod.rs index 27c23fc..90f04ef 100644 --- a/youmubot-osu/src/discord/mod.rs +++ b/youmubot-osu/src/discord/mod.rs @@ -326,6 +326,7 @@ async fn add_user( failures: 0, last_update: chrono::Utc::now(), pp: [None, None, None, None], + std_weighted_map_length: None, }; data.get::().unwrap().new_user(u).await?; Ok(()) diff --git a/youmubot-osu/src/discord/server_rank.rs b/youmubot-osu/src/discord/server_rank.rs index dd639db..9982690 100644 --- a/youmubot-osu/src/discord/server_rank.rs +++ b/youmubot-osu/src/discord/server_rank.rs @@ -36,6 +36,75 @@ impl FromStr for ModeOrTotal { } } +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +enum Align { + Left, + Middle, + Right, +} + +impl Align { + fn pad(self, input: &str, len: usize) -> String { + match self { + Align::Left => format!("{: format!("{:^len$}", input), + Align::Right => format!("{:>len$}", input), + } + } +} + +fn table_formatting + std::fmt::Debug, Ts: AsRef<[[S; N]]>>( + headers: &[&'static str; N], + padding: &[Align; N], + table: Ts, +) -> String { + let table = table.as_ref(); + // get length for each column + let lens = headers + .iter() + .enumerate() + .map(|(i, header)| { + table + .iter() + .map(|r| r.as_ref()[i].as_ref().len()) + .max() + .unwrap_or(0) + .max(header.len()) + }) + .collect::>(); + // paint with message builder + let mut m = MessageBuilder::new(); + m.push_line("```"); + // headers first + for (i, header) in headers.iter().enumerate() { + if i > 0 { + m.push(" | "); + } + m.push(padding[i].pad(header, lens[i])); + } + m.push_line(""); + // separator + m.push_line(format!( + "{:-() + (lens.len() - 1) * 3 + )); + // table itself + for row in table { + let row = row.as_ref(); + for (i, cell) in row.iter().enumerate() { + if i > 0 { + m.push(" | "); + } + let cell = cell.as_ref(); + m.push(padding[i].pad(cell, lens[i])); + } + m.push_line(""); + } + m.push_line("```"); + m.build() +} + #[command("ranks")] #[description = "See the server's ranks"] #[usage = "[mode (Std, Taiko, Catch, Mania) = Std]"] @@ -89,6 +158,7 @@ pub async fn server_rank(ctx: &Context, m: &Message, mut args: Args) -> CommandR let last_update = last_update.unwrap(); paginate_reply_fn( move |page: u8, ctx: &Context, m: &mut Message| { + use Align::*; const ITEMS_PER_PAGE: usize = 10; let users = users.clone(); Box::pin(async move { @@ -99,51 +169,62 @@ pub async fn server_rank(ctx: &Context, m: &Message, mut args: Args) -> CommandR } let total_len = users.len(); let users = &users[start..end]; - let username_len = users - .iter() - .map(|(_, (_, u))| u.username.len()) - .max() - .unwrap_or(8) - .max(8); - let member_len = users - .iter() - .map(|(_, (mem, _))| mem.len()) - .max() - .unwrap_or(8) - .max(8); - let mut content = MessageBuilder::new(); - content - .push_line("```") + let table = if matches!(mode, ModeOrTotal::Mode(Mode::Std)) { + const HEADERS: [&'static str; 5] = + ["#", "pp", "Map length", "Username", "Member"]; + const ALIGNS: [Align; 5] = [Right, Right, Right, Left, Left]; + + let table = users + .iter() + .enumerate() + .map(|(i, (pp, (mem, ou)))| { + let map_length = match ou.std_weighted_map_length { + Some(len) => { + let trunc_secs = len.floor() as u64; + let minutes = trunc_secs / 60; + let seconds = len - (60 * minutes) as f64; + format!("{}m{:02.2}s", minutes, seconds) + } + None => "unknown".to_owned(), + }; + [ + format!("{}", 1 + i + start), + format!("{:.2}", pp), + map_length, + ou.username.clone().into_owned(), + mem.clone(), + ] + }) + .collect::>(); + table_formatting(&HEADERS, &ALIGNS, table) + } else { + const HEADERS: [&'static str; 4] = ["#", "pp", "Username", "Member"]; + const ALIGNS: [Align; 4] = [Right, Right, Left, Left]; + + let table = users + .iter() + .enumerate() + .map(|(i, (pp, (mem, ou)))| { + [ + format!("{}", 1 + i + start), + format!("{:.2}", pp), + ou.username.clone().into_owned(), + mem.clone(), + ] + }) + .collect::>(); + table_formatting(&HEADERS, &ALIGNS, table) + }; + let content = MessageBuilder::new() + .push_line(table) .push_line(format!( - "Rank | pp | {:uw$} | Member", - "Username", - uw = username_len + "Page **{}**/**{}**. Last updated: {}", + page + 1, + (total_len + ITEMS_PER_PAGE - 1) / ITEMS_PER_PAGE, + last_update.format(""), )) - .push_line(format!( - "------------------{:-4} | {:>8.2} | {:uw$} | {}", - format!("#{}", 1 + id + start), - pp, - u.username, - member, - uw = username_len - )); - } - content.push_line("```").push_line(format!( - "Page **{}**/**{}**. Last updated: {}", - page + 1, - (total_len + ITEMS_PER_PAGE - 1) / ITEMS_PER_PAGE, - last_update.format(""), - )); - m.edit(ctx, EditMessage::new().content(content.to_string())) - .await?; + .build(); + m.edit(ctx, EditMessage::new().content(content)).await?; Ok(true) }) }, From e1671ca510a47ab3e239f3fccaa28f82683893d2 Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Wed, 6 Mar 2024 00:19:02 +0100 Subject: [PATCH 4/5] Pad map length properly --- youmubot-osu/src/discord/server_rank.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/youmubot-osu/src/discord/server_rank.rs b/youmubot-osu/src/discord/server_rank.rs index 9982690..b6eb6c4 100644 --- a/youmubot-osu/src/discord/server_rank.rs +++ b/youmubot-osu/src/discord/server_rank.rs @@ -101,7 +101,7 @@ fn table_formatting + std::fmt::Debug, Ts: AsRef<[ } m.push_line(""); } - m.push_line("```"); + m.push("```"); m.build() } @@ -183,7 +183,7 @@ pub async fn server_rank(ctx: &Context, m: &Message, mut args: Args) -> CommandR let trunc_secs = len.floor() as u64; let minutes = trunc_secs / 60; let seconds = len - (60 * minutes) as f64; - format!("{}m{:02.2}s", minutes, seconds) + format!("{}m{:05.2}s", minutes, seconds) } None => "unknown".to_owned(), }; From 0f91c3a22a175d4095040f12316c70dee04d0b6d Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Wed, 6 Mar 2024 00:28:29 +0100 Subject: [PATCH 5/5] Allow server-ranks by map length --- youmubot-osu/src/discord/server_rank.rs | 34 ++++++++++++++++--------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/youmubot-osu/src/discord/server_rank.rs b/youmubot-osu/src/discord/server_rank.rs index b6eb6c4..a890f14 100644 --- a/youmubot-osu/src/discord/server_rank.rs +++ b/youmubot-osu/src/discord/server_rank.rs @@ -19,19 +19,20 @@ use serenity::{ use youmubot_prelude::{stream::FuturesUnordered, *}; #[derive(Debug, Clone, Copy)] -enum ModeOrTotal { +enum RankQuery { Total, + MapLength, Mode(Mode), } -impl FromStr for ModeOrTotal { +impl FromStr for RankQuery { type Err = ::Err; fn from_str(s: &str) -> Result { - if s == "total" { - Ok(ModeOrTotal::Total) - } else { - ModeArg::from_str(s).map(|ModeArg(m)| ModeOrTotal::Mode(m)) + match s { + "total" => Ok(RankQuery::Total), + "map-length" => Ok(RankQuery::MapLength), + _ => ModeArg::from_str(s).map(|ModeArg(m)| RankQuery::Mode(m)), } } } @@ -113,8 +114,8 @@ fn table_formatting + std::fmt::Debug, Ts: AsRef<[ pub async fn server_rank(ctx: &Context, m: &Message, mut args: Args) -> CommandResult { let data = ctx.data.read().await; let mode = args - .single::() - .unwrap_or(ModeOrTotal::Mode(Mode::Std)); + .single::() + .unwrap_or(RankQuery::Mode(Mode::Std)); let guild = m.guild_id.expect("Guild-only command"); let member_cache = data.get::().unwrap(); let osu_users = data @@ -132,10 +133,11 @@ pub async fn server_rank(ctx: &Context, m: &Message, mut args: Args) -> CommandR .filter_map(|m| osu_users.get(&m.user.id).map(|ou| (m, ou))) .filter_map(|(member, osu_user)| { let pp = match mode { - ModeOrTotal::Total if osu_user.pp.iter().any(|v| v.is_some_and(|v| v > 0.0)) => { + RankQuery::Total if osu_user.pp.iter().any(|v| v.is_some_and(|v| v > 0.0)) => { Some(osu_user.pp.iter().map(|v| v.unwrap_or(0.0)).sum()) } - ModeOrTotal::Mode(m) => osu_user.pp.get(m as usize).and_then(|v| *v), + RankQuery::MapLength => osu_user.pp.get(Mode::Std as usize).and_then(|v| *v), + RankQuery::Mode(m) => osu_user.pp.get(m as usize).and_then(|v| *v), _ => None, }?; Some((pp, member.user.name.clone(), osu_user)) @@ -146,7 +148,15 @@ pub async fn server_rank(ctx: &Context, m: &Message, mut args: Args) -> CommandR .into_iter() .map(|(a, b, u)| (a, (b, u.clone()))) .collect::>(); - users.sort_by(|(a, _), (b, _)| (*b).partial_cmp(a).unwrap_or(std::cmp::Ordering::Equal)); + if matches!(mode, RankQuery::MapLength) { + users.sort_by(|(_, (_, a)), (_, (_, b))| { + (b.std_weighted_map_length) + .partial_cmp(&a.std_weighted_map_length) + .unwrap_or(std::cmp::Ordering::Equal) + }); + } else { + users.sort_by(|(a, _), (b, _)| (*b).partial_cmp(a).unwrap_or(std::cmp::Ordering::Equal)); + } if users.is_empty() { m.reply(&ctx, "No saved users in the current server...") @@ -169,7 +179,7 @@ pub async fn server_rank(ctx: &Context, m: &Message, mut args: Args) -> CommandR } let total_len = users.len(); let users = &users[start..end]; - let table = if matches!(mode, ModeOrTotal::Mode(Mode::Std)) { + let table = if matches!(mode, RankQuery::Mode(Mode::Std) | RankQuery::MapLength) { const HEADERS: [&'static str; 5] = ["#", "pp", "Map length", "Username", "Member"]; const ALIGNS: [Align; 5] = [Right, Right, Right, Left, Left];