mirror of
https://github.com/natsukagami/youmubot.git
synced 2025-04-10 04:30:29 +00:00
Merge branch 'master' into osu-app-commands
This commit is contained in:
commit
4d68ba5941
14 changed files with 253 additions and 83 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -1282,9 +1282,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",
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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"
|
||||
}
|
|
@ -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"
|
||||
}
|
12
youmubot-db-sql/.sqlx/query-a06efa1b12c2c7c9cf5b83bff796c0e59d61596cb609c4bb952edc2d64cec868.json
generated
Normal file
12
youmubot-db-sql/.sqlx/query-a06efa1b12c2c7c9cf5b83bff796c0e59d61596cb609c4bb952edc2d64cec868.json
generated
Normal file
|
@ -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"
|
||||
}
|
|
@ -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"
|
||||
}
|
|
@ -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"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
-- Add migration script here
|
||||
|
||||
ALTER TABLE osu_users
|
||||
ADD COLUMN std_weighted_map_length DOUBLE NULL DEFAULT NULL;
|
||||
|
|
@ -14,6 +14,8 @@ pub struct OsuUser {
|
|||
pub pp_catch: Option<f64>,
|
||||
/// Number of consecutive update failures
|
||||
pub failures: u8,
|
||||
|
||||
pub std_weighted_map_length: Option<f64>,
|
||||
}
|
||||
|
||||
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(())
|
||||
}
|
||||
|
||||
|
|
|
@ -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<f64> {
|
||||
let data = ctx.data.read().await;
|
||||
let client = data.get::<OsuClient>().unwrap().clone();
|
||||
let cache = data.get::<BeatmapMetaCache>().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::<FuturesUnordered<_>>()
|
||||
.try_fold(0.0, |a, b| future::ready(Ok(a + b)))
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
|
@ -148,6 +148,7 @@ pub struct OsuUser {
|
|||
pub id: u64,
|
||||
pub last_update: DateTime<Utc>,
|
||||
pub pp: [Option<f64>; 4],
|
||||
pub std_weighted_map_length: Option<f64>,
|
||||
/// More than 5 failures => gone
|
||||
pub failures: u8,
|
||||
}
|
||||
|
@ -163,6 +164,7 @@ impl From<OsuUser> 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,
|
||||
}
|
||||
}
|
||||
|
@ -181,6 +183,7 @@ impl From<model::OsuUser> for OsuUser {
|
|||
Mode::Catch => u.pp_catch,
|
||||
Mode::Mania => u.pp_mania,
|
||||
}),
|
||||
std_weighted_map_length: u.std_weighted_map_length,
|
||||
failures: u.failures,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -366,6 +366,7 @@ async fn add_user(
|
|||
failures: 0,
|
||||
last_update: chrono::Utc::now(),
|
||||
pp: [None, None, None, None],
|
||||
std_weighted_map_length: None,
|
||||
};
|
||||
data.get::<OsuSavedUsers>().unwrap().new_user(u).await?;
|
||||
Ok(())
|
||||
|
|
|
@ -12,7 +12,6 @@ use crate::{
|
|||
|
||||
use poise::CreateReply;
|
||||
use serenity::{
|
||||
builder::EditMessage,
|
||||
framework::standard::{macros::command, Args, CommandResult},
|
||||
model::channel::Message,
|
||||
utils::MessageBuilder,
|
||||
|
@ -20,23 +19,93 @@ 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 = <ModeArg as FromStr>::Err;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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!("{:<len$}", input),
|
||||
Align::Middle => format!("{:^len$}", input),
|
||||
Align::Right => format!("{:>len$}", input),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn table_formatting<const N: usize, S: AsRef<str> + 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::<Vec<_>>();
|
||||
// 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!(
|
||||
"{:-<total$}",
|
||||
"",
|
||||
total = lens.iter().sum::<usize>() + (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("```");
|
||||
m.build()
|
||||
}
|
||||
|
||||
#[command("ranks")]
|
||||
#[description = "See the server's ranks"]
|
||||
#[usage = "[mode (Std, Taiko, Catch, Mania) = Std]"]
|
||||
|
@ -45,8 +114,8 @@ impl FromStr for ModeOrTotal {
|
|||
pub async fn server_rank(ctx: &Context, m: &Message, mut args: Args) -> CommandResult {
|
||||
let data = ctx.data.read().await;
|
||||
let mode = args
|
||||
.single::<ModeOrTotal>()
|
||||
.unwrap_or(ModeOrTotal::Mode(Mode::Std));
|
||||
.single::<RankQuery>()
|
||||
.unwrap_or(RankQuery::Mode(Mode::Std));
|
||||
let guild = m.guild_id.expect("Guild-only command");
|
||||
let member_cache = data.get::<MemberCache>().unwrap();
|
||||
let osu_users = data
|
||||
|
@ -64,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))
|
||||
|
@ -78,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::<Vec<_>>();
|
||||
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...")
|
||||
|
@ -90,6 +168,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, _| {
|
||||
use Align::*;
|
||||
const ITEMS_PER_PAGE: usize = 10;
|
||||
let users = users.clone();
|
||||
Box::pin(async move {
|
||||
|
@ -100,49 +179,61 @@ 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, 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];
|
||||
|
||||
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{:05.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::<Vec<_>>();
|
||||
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::<Vec<_>>();
|
||||
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("<t:%s:R>"),
|
||||
))
|
||||
.push_line(format!(
|
||||
"------------------{:-<uw$}---{:-<mw$}",
|
||||
"",
|
||||
"",
|
||||
uw = username_len,
|
||||
mw = member_len
|
||||
));
|
||||
for (id, (pp, (member, u))) in users.iter().enumerate() {
|
||||
content.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("<t:%s:R>"),
|
||||
));
|
||||
.build();
|
||||
Ok(Some(CreateReply::default().content(content.to_string())))
|
||||
})
|
||||
},
|
||||
|
|
|
@ -180,6 +180,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()),
|
||||
|
@ -187,6 +188,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;
|
||||
|
|
Loading…
Add table
Reference in a new issue