+ Messages broadcast to all channels are now all started in "parallel" + This should improve message times to all channels, especially when there are many players + Start of the logic needed for having multiple deputy bots and one chief bot + clippy + fmt
188 lines
5.4 KiB
Rust
188 lines
5.4 KiB
Rust
use serenity::client::Context;
|
|
use serenity::framework::standard::Args;
|
|
use serenity::http::AttachmentType;
|
|
use serenity::model::channel::{Message, PermissionOverwrite, PermissionOverwriteType};
|
|
use serenity::model::guild::{Guild, Member};
|
|
use serenity::model::id::{ChannelId, UserId};
|
|
use serenity::model::Permissions;
|
|
use serenity::utils::MessageBuilder;
|
|
|
|
use crate::error::WoxlfError;
|
|
use crate::game::game_state::PhaseDuration;
|
|
use crate::game::global_data::GlobalData;
|
|
use crate::game::player_data::PlayerData;
|
|
use crate::game::MessageSource;
|
|
use crate::{error, game};
|
|
use serenity::prelude::SerenityError;
|
|
|
|
pub async fn send_msg_to_player_channels(
|
|
ctx: &Context,
|
|
guild: &Guild,
|
|
global_data: &mut GlobalData,
|
|
msg_source: MessageSource,
|
|
msg: &str,
|
|
attachment: Option<Vec<AttachmentType<'_>>>,
|
|
pin: bool,
|
|
) -> error::Result<()> {
|
|
let msg_tasks = global_data
|
|
.game_state_mut()?
|
|
.player_data
|
|
.iter()
|
|
.filter(|player_data| {
|
|
if let MessageSource::Player(channel_id) = msg_source {
|
|
if channel_id == player_data.channel {
|
|
return false;
|
|
}
|
|
}
|
|
true
|
|
})
|
|
.map(|player_data| {
|
|
let channel = guild
|
|
.channels
|
|
.get(&ChannelId::from(player_data.channel))
|
|
.unwrap();
|
|
|
|
channel.send_message(&ctx.http, |m| {
|
|
m.content(&msg);
|
|
|
|
if let Some(attachment) = attachment.clone() {
|
|
m.add_files(attachment);
|
|
}
|
|
|
|
m
|
|
})
|
|
});
|
|
|
|
let msgs: Result<Vec<Message>, SerenityError> = futures::future::join_all(msg_tasks)
|
|
.await
|
|
.into_iter()
|
|
.collect();
|
|
|
|
let msgs = msgs?;
|
|
|
|
if pin {
|
|
let pin_tasks = msgs.iter().map(|msg| msg.pin(&ctx.http));
|
|
|
|
let pins: Result<(), SerenityError> = futures::future::join_all(pin_tasks)
|
|
.await
|
|
.into_iter()
|
|
.collect();
|
|
|
|
pins?;
|
|
}
|
|
|
|
let host_channel = guild
|
|
.channels
|
|
.get(&ChannelId::from(global_data.cfg.host_channel))
|
|
.unwrap();
|
|
|
|
let source = match msg_source {
|
|
MessageSource::Player(channel_id) => {
|
|
let discord_id = global_data
|
|
.game_state_mut()?
|
|
.get_player_from_channel(channel_id)
|
|
.unwrap()
|
|
.discord_id;
|
|
let name = guild
|
|
.members
|
|
.get(&UserId::from(discord_id))
|
|
.unwrap()
|
|
.display_name();
|
|
|
|
name.to_string()
|
|
}
|
|
MessageSource::Host => "Host".to_string(),
|
|
MessageSource::Automated => "Automated".to_string(),
|
|
};
|
|
|
|
host_channel
|
|
.send_message(&ctx.http, |m| {
|
|
m.content(format!("({}): {}", source, msg));
|
|
if let Some(attachment) = attachment {
|
|
m.add_files(attachment);
|
|
}
|
|
|
|
m
|
|
})
|
|
.await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn add_user_to_game(
|
|
ctx: &Context,
|
|
guild: &Guild,
|
|
global_data: &mut GlobalData,
|
|
discord_user: &Member,
|
|
) -> error::Result<()> {
|
|
let mut codename = game::generate_codename(&global_data.cfg);
|
|
|
|
while global_data.game_state_mut()?.codename_exists(&codename) {
|
|
codename = game::generate_codename(&global_data.cfg);
|
|
}
|
|
|
|
let channel = guild
|
|
.create_channel(&ctx.http, |c| {
|
|
c.category(&ChannelId::from(global_data.cfg.category))
|
|
.name(format!("{}'s Channel", discord_user.display_name()))
|
|
})
|
|
.await?;
|
|
|
|
let allow =
|
|
Permissions::SEND_MESSAGES | Permissions::READ_MESSAGE_HISTORY | Permissions::READ_MESSAGES;
|
|
|
|
let overwrite = PermissionOverwrite {
|
|
allow,
|
|
deny: Default::default(),
|
|
kind: PermissionOverwriteType::Member(discord_user.user.id),
|
|
};
|
|
|
|
channel.create_permission(&ctx.http, &overwrite).await?;
|
|
|
|
let msg = channel.send_message(&ctx.http, |m| {
|
|
m.content(MessageBuilder::new()
|
|
.push("Welcome ")
|
|
.mention(discord_user)
|
|
.push_line(" to your WOxlf Terminal. You may use this terminal to communicate to other subjects.")
|
|
.push_line("You will also use this terminal for choosing one of your fellow subjects for termination.")
|
|
.push_line("Happy testing :)")
|
|
.push_line("")
|
|
.push_line("Do $help to see all commands.")
|
|
.push_line("")
|
|
.push("SUBJECT CODENAME: ")
|
|
.push_line(&codename)
|
|
.push(global_data.print_game_status())
|
|
)
|
|
}).await?;
|
|
|
|
channel.pin(&ctx.http, msg.id).await?;
|
|
|
|
let player_data = PlayerData {
|
|
channel: channel.id.0,
|
|
discord_id: discord_user.user.id.0,
|
|
vote_target: None,
|
|
codename,
|
|
};
|
|
|
|
global_data.game_state_mut()?.player_data.push(player_data);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn build_system_message(msg: &str) -> String {
|
|
MessageBuilder::new()
|
|
.push_bold_line("\\*\\*IMPORTANT wOxlf SYSTEM MESSAGE\\*\\*")
|
|
.push_line("")
|
|
.push_line(msg)
|
|
.push_line("")
|
|
.push_bold_line("\\*\\*END OF SYSTEM MESSAGE\\*\\*")
|
|
.build()
|
|
}
|
|
|
|
pub async fn parse_duration_arg(args: &mut Args) -> error::Result<PhaseDuration> {
|
|
match args.single::<PhaseDuration>() {
|
|
Ok(d) => Ok(d),
|
|
Err(_) => Err(WoxlfError::DurationParseError),
|
|
}
|
|
}
|