added different format for high repeat counts

This commit is contained in:
Lilith Schier 2026-08-20 19:21:38 +02:00
parent 3db5d719d2
commit 0843c77473
2 changed files with 53 additions and 44 deletions

View file

@ -1,4 +1,4 @@
pub const MAX_DICE_COUNT_PER_ROLL: usize = 20_000; pub const MAX_DICE_COUNT_PER_ROLL: usize = 20_000;
pub const RESULT_CULL_CHARACTER_THRESHOLD: usize = 3000; pub const RESULT_CULL_CHARACTER_THRESHOLD: usize = 3000;
pub const MAX_DISPLAYED_DICE_PER_MESSAGE: usize = 100; pub const MAX_DISPLAYED_DICE_PER_MESSAGE: usize = 100;
pub const MAX_ROLL_REPEATS: usize = 35; pub const MAX_ROLL_REPEATS: usize = 100;

View file

@ -1,3 +1,4 @@
use std::fmt::Write as FmtWrite;
mod dice; mod dice;
mod limits; mod limits;
mod parsing; mod parsing;
@ -12,7 +13,8 @@ use serenity::all::{
FullEvent, Interaction, InteractionContext, MessageFlags, ResolvedOption, ResolvedValue, FullEvent, Interaction, InteractionContext, MessageFlags, ResolvedOption, ResolvedValue,
}; };
use serenity::builder::{ use serenity::builder::{
CreateCommand, CreateContainer, CreateContainerComponent, CreateInteractionResponse, CreateInteractionResponseMessage, CreateTextDisplay, CreateCommand, CreateContainer, CreateContainerComponent, CreateInteractionResponse,
CreateInteractionResponseMessage, CreateTextDisplay,
}; };
use serenity::{async_trait, prelude::*}; use serenity::{async_trait, prelude::*};
use std::sync::Arc; use std::sync::Arc;
@ -135,7 +137,8 @@ pub async fn roll(ctx: &Context, command: &CommandInteraction) -> anyhow::Result
} }
}) })
.unwrap_or(1) .unwrap_or(1)
.min(MAX_ROLL_REPEATS as i64); .min(MAX_ROLL_REPEATS as i64)
.max(1) as usize;
let private = options let private = options
.iter() .iter()
.find(|option| option.name == "private") .find(|option| option.name == "private")
@ -177,46 +180,59 @@ pub async fn roll(ctx: &Context, command: &CommandInteraction) -> anyhow::Result
let average = expression.average(&mut rng)?; let average = expression.average(&mut rng)?;
let ev = (average * 10.0).round() / 10.0; let ev = (average * 10.0).round() / 10.0;
let mut pre_paragraphs = Vec::new();
if let Some(description) = description {
pre_paragraphs.insert(0, format!(">>> {description}\n"));
}
let mut post_paragraphs = Vec::new();
if fixed_seed.is_some() {
post_paragraphs.push("***⚠️ This is not a fair roll. The result was generated based on a fixed seed and is thus fully reproducible.***".to_string());
}
post_paragraphs.push(format!("-# Expected value: {ev} | Seed: {seed}"));
let surrounding_par_count = pre_paragraphs.len() + post_paragraphs.len();
let paragraphs = if repeat <= 40 - surrounding_par_count {
let discord_md = Arc::new(std::sync::RwLock::new(DiscordMd { let discord_md = Arc::new(std::sync::RwLock::new(DiscordMd {
buffers: vec![], buffers: Vec::with_capacity(repeat),
dice_written: 0, dice_written: 0,
})); }));
if let Some(description) = description {
discord_md
.write()
.unwrap()
.buffers
.push(format!(">>> {description}\n"));
}
for _ in 0..repeat { for _ in 0..repeat {
let mut witness = DiscordMd::create_witness(&discord_md); let mut witness = DiscordMd::create_witness(&discord_md);
let result = expression.evaluate(&mut rng, &mut witness, i64::MAX)?; let result = expression.evaluate(&mut rng, &mut witness, i64::MAX)?;
witness.witness_total_result(result)?; witness.witness_total_result(result)?;
witness.end(); witness.end();
} }
if fixed_seed.is_some() { let discord_md = Arc::into_inner(discord_md).unwrap().into_inner()?;
discord_md
.write() discord_md.buffers
.unwrap() } else {
.buffers let mut par = String::new();
.push("***⚠️ This is not a fair roll. The result was generated based on a fixed seed and is thus fully reproducible.***".to_string()); for i in 0..repeat {
if i > 0 {
write!(par, ", ")?;
} }
discord_md write!(
.write() par,
.unwrap() "**{}**",
.buffers expression.evaluate(&mut rng, &mut std::io::sink(), i64::MAX)?
.push(format!("-# Expected value: {ev} | Seed: {seed}")); )?;
}
vec![par]
};
let discord_md = Arc::into_inner(discord_md) pre_paragraphs.extend(paragraphs);
.unwrap() pre_paragraphs.extend(post_paragraphs);
.into_inner()?; let paragraphs = pre_paragraphs;
if discord_md.character_count() > 4000 { if paragraphs.iter().map(|s| s.chars().count()).sum::<usize>() > 4000
|| paragraphs.len() > 40
{
bail!("Resulting message was too long, please roll fewer dice!"); bail!("Resulting message was too long, please roll fewer dice!");
} };
let text_components = discord_md let text_components = paragraphs
.buffers
.into_iter() .into_iter()
.map(|text| CreateContainerComponent::TextDisplay(CreateTextDisplay::new(text))) .map(|text| CreateContainerComponent::TextDisplay(CreateTextDisplay::new(text)))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -227,20 +243,13 @@ pub async fn roll(ctx: &Context, command: &CommandInteraction) -> anyhow::Result
text_components, text_components,
))]) ))])
// flags needs to be called before ephemeral for correct ordering // flags needs to be called before ephemeral for correct ordering
.flags( .flags(MessageFlags::IS_COMPONENTS_V2 | MessageFlags::SUPPRESS_NOTIFICATIONS)
MessageFlags::IS_COMPONENTS_V2 | MessageFlags::SUPPRESS_NOTIFICATIONS,
)
.ephemeral(private), .ephemeral(private),
); );
debug!("Returning response: {response:#?}"); debug!("Returning response: {response:#?}");
command command.create_response(&ctx.http, response).await?;
.create_response(
&ctx.http,
response,
)
.await?;
Ok(()) Ok(())
} }