From 0843c774731ae98927c12fbb6b30dfbb4ddf06bb Mon Sep 17 00:00:00 2001 From: Lilith Schier Date: Thu, 20 Aug 2026 19:21:38 +0200 Subject: [PATCH] added different format for high repeat counts --- src/limits.rs | 2 +- src/main.rs | 95 ++++++++++++++++++++++++++++----------------------- 2 files changed, 53 insertions(+), 44 deletions(-) diff --git a/src/limits.rs b/src/limits.rs index 41f855c..a9b8136 100644 --- a/src/limits.rs +++ b/src/limits.rs @@ -1,4 +1,4 @@ pub const MAX_DICE_COUNT_PER_ROLL: usize = 20_000; pub const RESULT_CULL_CHARACTER_THRESHOLD: usize = 3000; pub const MAX_DISPLAYED_DICE_PER_MESSAGE: usize = 100; -pub const MAX_ROLL_REPEATS: usize = 35; \ No newline at end of file +pub const MAX_ROLL_REPEATS: usize = 100; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index e2638a5..742b301 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +use std::fmt::Write as FmtWrite; mod dice; mod limits; mod parsing; @@ -12,7 +13,8 @@ use serenity::all::{ FullEvent, Interaction, InteractionContext, MessageFlags, ResolvedOption, ResolvedValue, }; use serenity::builder::{ - CreateCommand, CreateContainer, CreateContainerComponent, CreateInteractionResponse, CreateInteractionResponseMessage, CreateTextDisplay, + CreateCommand, CreateContainer, CreateContainerComponent, CreateInteractionResponse, + CreateInteractionResponseMessage, CreateTextDisplay, }; use serenity::{async_trait, prelude::*}; use std::sync::Arc; @@ -135,7 +137,8 @@ pub async fn roll(ctx: &Context, command: &CommandInteraction) -> anyhow::Result } }) .unwrap_or(1) - .min(MAX_ROLL_REPEATS as i64); + .min(MAX_ROLL_REPEATS as i64) + .max(1) as usize; let private = options .iter() .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 ev = (average * 10.0).round() / 10.0; - let discord_md = Arc::new(std::sync::RwLock::new(DiscordMd { - buffers: vec![], - dice_written: 0, - })); + let mut pre_paragraphs = Vec::new(); if let Some(description) = description { - discord_md - .write() - .unwrap() - .buffers - .push(format!(">>> {description}\n")); - } - for _ in 0..repeat { - let mut witness = DiscordMd::create_witness(&discord_md); - let result = expression.evaluate(&mut rng, &mut witness, i64::MAX)?; - witness.witness_total_result(result)?; - witness.end(); + pre_paragraphs.insert(0, format!(">>> {description}\n")); } + + let mut post_paragraphs = Vec::new(); if fixed_seed.is_some() { - discord_md - .write() - .unwrap() - .buffers - .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("***⚠️ This is not a fair roll. The result was generated based on a fixed seed and is thus fully reproducible.***".to_string()); } - discord_md - .write() - .unwrap() - .buffers - .push(format!("-# Expected value: {ev} | Seed: {seed}")); + post_paragraphs.push(format!("-# Expected value: {ev} | Seed: {seed}")); - let discord_md = Arc::into_inner(discord_md) - .unwrap() - .into_inner()?; + let surrounding_par_count = pre_paragraphs.len() + post_paragraphs.len(); - if discord_md.character_count() > 4000 { + let paragraphs = if repeat <= 40 - surrounding_par_count { + let discord_md = Arc::new(std::sync::RwLock::new(DiscordMd { + buffers: Vec::with_capacity(repeat), + dice_written: 0, + })); + for _ in 0..repeat { + let mut witness = DiscordMd::create_witness(&discord_md); + let result = expression.evaluate(&mut rng, &mut witness, i64::MAX)?; + witness.witness_total_result(result)?; + witness.end(); + } + let discord_md = Arc::into_inner(discord_md).unwrap().into_inner()?; + + discord_md.buffers + } else { + let mut par = String::new(); + for i in 0..repeat { + if i > 0 { + write!(par, ", ")?; + } + write!( + par, + "**{}**", + expression.evaluate(&mut rng, &mut std::io::sink(), i64::MAX)? + )?; + } + vec![par] + }; + + pre_paragraphs.extend(paragraphs); + pre_paragraphs.extend(post_paragraphs); + let paragraphs = pre_paragraphs; + + if paragraphs.iter().map(|s| s.chars().count()).sum::() > 4000 + || paragraphs.len() > 40 + { bail!("Resulting message was too long, please roll fewer dice!"); - } + }; - let text_components = discord_md - .buffers + let text_components = paragraphs .into_iter() .map(|text| CreateContainerComponent::TextDisplay(CreateTextDisplay::new(text))) .collect::>(); @@ -227,20 +243,13 @@ pub async fn roll(ctx: &Context, command: &CommandInteraction) -> anyhow::Result text_components, ))]) // flags needs to be called before ephemeral for correct ordering - .flags( - MessageFlags::IS_COMPONENTS_V2 | MessageFlags::SUPPRESS_NOTIFICATIONS, - ) + .flags(MessageFlags::IS_COMPONENTS_V2 | MessageFlags::SUPPRESS_NOTIFICATIONS) .ephemeral(private), ); debug!("Returning response: {response:#?}"); - command - .create_response( - &ctx.http, - response, - ) - .await?; + command.create_response(&ctx.http, response).await?; Ok(()) }