commit
4b7570b24c
File diff suppressed because it is too large
Load Diff
|
@ -6,7 +6,7 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
config = "0.12.0"
|
config = "0.13.3"
|
||||||
structopt = "0.3.26"
|
structopt = "0.3.26"
|
||||||
chrono = {version="0.4.19", features=["serde"]}
|
chrono = {version="0.4.19", features=["serde"]}
|
||||||
serde = "1.0.136"
|
serde = "1.0.136"
|
||||||
|
@ -16,9 +16,10 @@ regex = "1.5.5"
|
||||||
futures = "0.3.21"
|
futures = "0.3.21"
|
||||||
reqwest = "0.11.10"
|
reqwest = "0.11.10"
|
||||||
tera = "1.15.0"
|
tera = "1.15.0"
|
||||||
|
bitflags = "1.3.2"
|
||||||
|
|
||||||
[dependencies.serenity]
|
[dependencies.serenity]
|
||||||
version = "0.10.10"
|
version = "0.11.5"
|
||||||
features = ["framework", "standard_framework"]
|
features = ["framework", "standard_framework"]
|
||||||
|
|
||||||
[dependencies.tokio]
|
[dependencies.tokio]
|
||||||
|
|
|
@ -15,10 +15,12 @@ pub struct Args {
|
||||||
pub struct GameConfig {
|
pub struct GameConfig {
|
||||||
pub game_name: String,
|
pub game_name: String,
|
||||||
pub bot_name: String,
|
pub bot_name: String,
|
||||||
|
pub bot_profile_pic: String,
|
||||||
pub vote_phase_name: String,
|
pub vote_phase_name: String,
|
||||||
pub enemy_phase_name: String,
|
pub enemy_phase_name: String,
|
||||||
pub player_group_name: String,
|
pub player_group_name: String,
|
||||||
pub profile_album_hash: String,
|
pub profile_album_hash: String,
|
||||||
|
pub whispers_allowed: bool,
|
||||||
pub first_name: Vec<String>,
|
pub first_name: Vec<String>,
|
||||||
pub last_name: Vec<String>,
|
pub last_name: Vec<String>,
|
||||||
pub messages: MessageConfig,
|
pub messages: MessageConfig,
|
||||||
|
@ -43,6 +45,7 @@ pub struct DiscordConfig {
|
||||||
pub host_webhook_id: u64,
|
pub host_webhook_id: u64,
|
||||||
pub vote_channel: u64,
|
pub vote_channel: u64,
|
||||||
pub category: u64,
|
pub category: u64,
|
||||||
|
pub guild_id: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||||
|
|
|
@ -14,16 +14,20 @@ use serenity::model::prelude::{Message, UserId};
|
||||||
use serenity::prelude::Context;
|
use serenity::prelude::Context;
|
||||||
use serenity::utils::MessageBuilder;
|
use serenity::utils::MessageBuilder;
|
||||||
|
|
||||||
use crate::discord::helper::{add_user_to_game, parse_duration_arg, send_msg_to_player_channels};
|
use crate::discord::helper::{add_user_to_game, parse_duration_arg};
|
||||||
use crate::error::{Result, WoxlfError};
|
use crate::error::{Result, WoxlfError};
|
||||||
use crate::game::global_data::GlobalData;
|
use crate::game::global_data::GlobalData;
|
||||||
|
use crate::game::message_router::{
|
||||||
|
dispatch_message, Median, MessageDest, MessageSource, WoxlfMessage,
|
||||||
|
};
|
||||||
use crate::game::player_data::PlayerData;
|
use crate::game::player_data::PlayerData;
|
||||||
use crate::game::MessageSource;
|
|
||||||
use crate::game::Phase;
|
use crate::game::Phase;
|
||||||
use crate::messages::DiscordUser;
|
use crate::messages::DiscordUser;
|
||||||
|
|
||||||
#[group]
|
#[group]
|
||||||
#[commands(start, say, end, broadcast, next_phase, kill, add_time, test_theme)]
|
#[commands(
|
||||||
|
start, say, end, broadcast, next_phase, kill, add_time, test_theme, whisper
|
||||||
|
)]
|
||||||
struct Host;
|
struct Host;
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
|
@ -34,7 +38,7 @@ async fn start(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||||
|
|
||||||
let mut data = ctx.data.write().await;
|
let mut data = ctx.data.write().await;
|
||||||
let global_data = data.get_mut::<GlobalData>().unwrap();
|
let global_data = data.get_mut::<GlobalData>().unwrap();
|
||||||
let guild = msg.guild(&ctx.cache).await.unwrap();
|
let guild = msg.guild(&ctx.cache).unwrap();
|
||||||
let mut global_data = global_data.lock().await;
|
let mut global_data = global_data.lock().await;
|
||||||
|
|
||||||
let game_name = args.single::<String>()?;
|
let game_name = args.single::<String>()?;
|
||||||
|
@ -136,7 +140,7 @@ async fn start(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||||
async fn end(ctx: &Context, msg: &Message, mut _args: Args) -> CommandResult {
|
async fn end(ctx: &Context, msg: &Message, mut _args: Args) -> CommandResult {
|
||||||
let mut data = ctx.data.write().await;
|
let mut data = ctx.data.write().await;
|
||||||
let global_data = data.get_mut::<GlobalData>().unwrap();
|
let global_data = data.get_mut::<GlobalData>().unwrap();
|
||||||
let guild = msg.guild(&ctx.cache).await.unwrap();
|
let guild = msg.guild(&ctx.cache).unwrap();
|
||||||
|
|
||||||
let mut global_data = global_data.lock().await;
|
let mut global_data = global_data.lock().await;
|
||||||
|
|
||||||
|
@ -159,23 +163,20 @@ async fn end(ctx: &Context, msg: &Message, mut _args: Args) -> CommandResult {
|
||||||
#[command]
|
#[command]
|
||||||
#[only_in(guilds)]
|
#[only_in(guilds)]
|
||||||
#[allowed_roles("wolfx host")]
|
#[allowed_roles("wolfx host")]
|
||||||
async fn say(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
async fn say(ctx: &Context, _msg: &Message, args: Args) -> CommandResult {
|
||||||
let mut data = ctx.data.write().await;
|
let data = ctx.data.read().await;
|
||||||
let global_data = data.get_mut::<GlobalData>().unwrap();
|
let global_data = data.get::<GlobalData>().unwrap();
|
||||||
let guild = msg.guild(&ctx.cache).await.unwrap();
|
|
||||||
|
|
||||||
let mut global_data = global_data.lock().await;
|
let global_data = global_data.lock().await;
|
||||||
|
|
||||||
send_msg_to_player_channels(
|
let msg = WoxlfMessage::default()
|
||||||
ctx,
|
.source(MessageSource::Host)
|
||||||
&guild,
|
.dest(MessageDest::Broadcast)
|
||||||
&mut global_data,
|
.median(Median::Webhook)
|
||||||
MessageSource::Host,
|
.content(args.rest())
|
||||||
args.rest(),
|
.clone();
|
||||||
None,
|
|
||||||
false,
|
dispatch_message(ctx, &global_data, msg).await?;
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -183,27 +184,24 @@ async fn say(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||||
#[command]
|
#[command]
|
||||||
#[only_in(guilds)]
|
#[only_in(guilds)]
|
||||||
#[allowed_roles("wolfx host")]
|
#[allowed_roles("wolfx host")]
|
||||||
async fn broadcast(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
async fn broadcast(ctx: &Context, _msg: &Message, args: Args) -> CommandResult {
|
||||||
let mut data = ctx.data.write().await;
|
let data = ctx.data.read().await;
|
||||||
let global_data = data.get_mut::<GlobalData>().unwrap();
|
let global_data = data.get::<GlobalData>().unwrap();
|
||||||
let guild = msg.guild(&ctx.cache).await.unwrap();
|
|
||||||
|
|
||||||
let mut global_data = global_data.lock().await;
|
let global_data = global_data.lock().await;
|
||||||
|
|
||||||
let msg = global_data
|
let broadcast = global_data
|
||||||
.templates()?
|
.templates()?
|
||||||
.build_announcement(&global_data, args.rest())?;
|
.build_announcement(&global_data, args.rest())?;
|
||||||
|
|
||||||
send_msg_to_player_channels(
|
let woxlf_msg = WoxlfMessage::default()
|
||||||
ctx,
|
.source(MessageSource::Automated)
|
||||||
&guild,
|
.dest(MessageDest::Broadcast)
|
||||||
&mut global_data,
|
.content(&broadcast)
|
||||||
MessageSource::Automated,
|
.median(Median::Webhook)
|
||||||
&msg,
|
.clone();
|
||||||
None,
|
|
||||||
true,
|
dispatch_message(ctx, &global_data, woxlf_msg).await?;
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -214,7 +212,7 @@ async fn broadcast(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||||
async fn next_phase(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
async fn next_phase(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||||
let mut data = ctx.data.write().await;
|
let mut data = ctx.data.write().await;
|
||||||
let global_data = data.get_mut::<GlobalData>().unwrap();
|
let global_data = data.get_mut::<GlobalData>().unwrap();
|
||||||
let guild = msg.guild(&ctx.cache).await.unwrap();
|
let guild = msg.guild(&ctx.cache).unwrap();
|
||||||
|
|
||||||
let mut global_data = global_data.lock().await;
|
let mut global_data = global_data.lock().await;
|
||||||
|
|
||||||
|
@ -232,16 +230,14 @@ async fn next_phase(ctx: &Context, msg: &Message, mut args: Args) -> CommandResu
|
||||||
.templates()?
|
.templates()?
|
||||||
.build_announcement(&global_data, &broadcast)?;
|
.build_announcement(&global_data, &broadcast)?;
|
||||||
|
|
||||||
send_msg_to_player_channels(
|
let woxlf_msg = WoxlfMessage::default()
|
||||||
ctx,
|
.source(MessageSource::Automated)
|
||||||
&guild,
|
.dest(MessageDest::Broadcast)
|
||||||
&mut global_data,
|
.median(Median::Webhook)
|
||||||
MessageSource::Automated,
|
.content(&broadcast)
|
||||||
&broadcast,
|
.clone();
|
||||||
None,
|
|
||||||
true,
|
dispatch_message(ctx, &global_data, woxlf_msg).await?;
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
if global_data.game_state_mut()?.current_phase == Phase::Day {
|
if global_data.game_state_mut()?.current_phase == Phase::Day {
|
||||||
let vote_channel = guild
|
let vote_channel = guild
|
||||||
|
@ -251,6 +247,7 @@ async fn next_phase(ctx: &Context, msg: &Message, mut args: Args) -> CommandResu
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
vote_channel
|
vote_channel
|
||||||
|
.id()
|
||||||
.send_message(&ctx.http, |m| {
|
.send_message(&ctx.http, |m| {
|
||||||
m.content(format!(
|
m.content(format!(
|
||||||
"**{} {} Votes:**",
|
"**{} {} Votes:**",
|
||||||
|
@ -308,7 +305,6 @@ async fn kill(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||||
async fn add_time(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
async fn add_time(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||||
let mut data = ctx.data.write().await;
|
let mut data = ctx.data.write().await;
|
||||||
let global_data = data.get_mut::<GlobalData>().unwrap();
|
let global_data = data.get_mut::<GlobalData>().unwrap();
|
||||||
let guild = msg.guild(&ctx.cache).await.unwrap();
|
|
||||||
|
|
||||||
let mut global_data = global_data.lock().await;
|
let mut global_data = global_data.lock().await;
|
||||||
|
|
||||||
|
@ -332,16 +328,14 @@ async fn add_time(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult
|
||||||
.templates()?
|
.templates()?
|
||||||
.build_announcement(&global_data, &broadcast)?;
|
.build_announcement(&global_data, &broadcast)?;
|
||||||
|
|
||||||
send_msg_to_player_channels(
|
let woxlf_msg = WoxlfMessage::default()
|
||||||
ctx,
|
.source(MessageSource::Automated)
|
||||||
&guild,
|
.dest(MessageDest::Broadcast)
|
||||||
&mut global_data,
|
.median(Median::Webhook)
|
||||||
MessageSource::Automated,
|
.content(&broadcast)
|
||||||
&broadcast,
|
.clone();
|
||||||
None,
|
|
||||||
true,
|
dispatch_message(ctx, &global_data, woxlf_msg).await?;
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
msg.reply(&ctx.http, "Phase has been updated")
|
msg.reply(&ctx.http, "Phase has been updated")
|
||||||
.await
|
.await
|
||||||
|
@ -501,7 +495,7 @@ struct Player;
|
||||||
async fn vote(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
async fn vote(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||||
let mut data = ctx.data.write().await;
|
let mut data = ctx.data.write().await;
|
||||||
let global_data = data.get_mut::<GlobalData>().unwrap();
|
let global_data = data.get_mut::<GlobalData>().unwrap();
|
||||||
let guild = msg.guild(&ctx.cache).await.unwrap();
|
let guild = msg.guild(&ctx.cache).unwrap();
|
||||||
|
|
||||||
let mut global_data = global_data.lock().await;
|
let mut global_data = global_data.lock().await;
|
||||||
|
|
||||||
|
@ -555,6 +549,7 @@ async fn vote(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
vote_channel
|
vote_channel
|
||||||
|
.id()
|
||||||
.send_message(&ctx.http, |m| m.content(vote_msg))
|
.send_message(&ctx.http, |m| m.content(vote_msg))
|
||||||
.await?;
|
.await?;
|
||||||
} else {
|
} else {
|
||||||
|
@ -626,7 +621,7 @@ async fn players(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
|
||||||
.push(alive_status);
|
.push(alive_status);
|
||||||
|
|
||||||
if msg.channel_id.0 == global_data.cfg.discord_config.host_channel {
|
if msg.channel_id.0 == global_data.cfg.discord_config.host_channel {
|
||||||
let guild = msg.guild(&ctx.cache).await.unwrap();
|
let guild = msg.guild(&ctx.cache).unwrap();
|
||||||
let member = guild.members.get(&UserId::from(player.discord_id)).unwrap();
|
let member = guild.members.get(&UserId::from(player.discord_id)).unwrap();
|
||||||
msg_builder.push_line(format!(" ({})", member.display_name()));
|
msg_builder.push_line(format!(" ({})", member.display_name()));
|
||||||
} else {
|
} else {
|
||||||
|
@ -639,6 +634,59 @@ async fn players(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[command]
|
||||||
|
#[aliases("pm", "w")]
|
||||||
|
#[description = "Send a private message to another player."]
|
||||||
|
async fn whisper(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
||||||
|
if args.len() < 2 {
|
||||||
|
msg.reply(&ctx.http, "Need a recipient and message!")
|
||||||
|
.await?;
|
||||||
|
} else {
|
||||||
|
let data = ctx.data.read().await;
|
||||||
|
let global_data = data.get::<GlobalData>().unwrap();
|
||||||
|
let global_data = global_data.lock().await;
|
||||||
|
|
||||||
|
let target = args.single::<String>()?;
|
||||||
|
let pm = args.rest();
|
||||||
|
|
||||||
|
let src_player = match global_data
|
||||||
|
.game_state()?
|
||||||
|
.get_player_from_discord_id(msg.author.id.0)
|
||||||
|
{
|
||||||
|
None => {
|
||||||
|
msg.reply(&ctx.http, "You are not in the game!").await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
Some(player) => player,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(target_player) = global_data.game_state()?.get_player_by_codename(&target) {
|
||||||
|
if src_player.discord_id == target_player.discord_id {
|
||||||
|
msg.reply(&ctx.http, "You can't send messages to yourself!")
|
||||||
|
.await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let woxlf_msg = WoxlfMessage::default()
|
||||||
|
.source(MessageSource::Player(Box::new(src_player.clone())))
|
||||||
|
.dest(MessageDest::Player(Box::new(target_player.clone())))
|
||||||
|
.median(Median::DirectMessage)
|
||||||
|
.content(pm)
|
||||||
|
.clone();
|
||||||
|
|
||||||
|
dispatch_message(ctx, &global_data, woxlf_msg).await?;
|
||||||
|
} else {
|
||||||
|
msg.reply(
|
||||||
|
&ctx.http,
|
||||||
|
format!("Could not find a player with codename {}.", target),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[help]
|
#[help]
|
||||||
#[individual_command_tip = "If you want more information about a specific command, just pass the command as argument."]
|
#[individual_command_tip = "If you want more information about a specific command, just pass the command as argument."]
|
||||||
#[command_not_found_text = "Could not find: `{}`."]
|
#[command_not_found_text = "Could not find: `{}`."]
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
use serenity::async_trait;
|
use serenity::async_trait;
|
||||||
use serenity::client::{Context, EventHandler};
|
use serenity::client::{Context, EventHandler};
|
||||||
use serenity::http::AttachmentType;
|
|
||||||
use serenity::model::channel::Message;
|
use serenity::model::channel::Message;
|
||||||
use serenity::model::gateway::Ready;
|
use serenity::model::gateway::Ready;
|
||||||
|
use serenity::model::prelude::AttachmentType;
|
||||||
use serenity::utils::parse_emoji;
|
use serenity::utils::parse_emoji;
|
||||||
|
|
||||||
use crate::discord::helper::send_webhook_msg_to_player_channels;
|
|
||||||
use crate::game::global_data::GlobalData;
|
use crate::game::global_data::GlobalData;
|
||||||
use crate::game::MessageSource;
|
use crate::game::message_router::{dispatch_message, MessageDest};
|
||||||
|
use crate::game::message_router::{Median, MessageSource, WoxlfMessage};
|
||||||
|
|
||||||
pub struct Handler {}
|
pub struct Handler {}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ impl EventHandler for Handler {
|
||||||
|
|
||||||
let global_data = data.get::<GlobalData>().unwrap();
|
let global_data = data.get::<GlobalData>().unwrap();
|
||||||
|
|
||||||
let mut global_data = global_data.lock().await;
|
let global_data = global_data.lock().await;
|
||||||
|
|
||||||
if global_data.game_state.is_none() {
|
if global_data.game_state.is_none() {
|
||||||
// no game in progress
|
// no game in progress
|
||||||
|
@ -43,7 +43,6 @@ impl EventHandler for Handler {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let guild = msg.guild(&ctx.cache).await.unwrap();
|
|
||||||
let user_msg = msg.content.clone();
|
let user_msg = msg.content.clone();
|
||||||
|
|
||||||
let re = regex::Regex::new(r"<a?:.+:\d+>").unwrap();
|
let re = regex::Regex::new(r"<a?:.+:\d+>").unwrap();
|
||||||
|
@ -52,7 +51,6 @@ impl EventHandler for Handler {
|
||||||
if let Some(emoji) = parse_emoji(&emoji_cap[0]) {
|
if let Some(emoji) = parse_emoji(&emoji_cap[0]) {
|
||||||
if !msg
|
if !msg
|
||||||
.guild(&ctx.cache)
|
.guild(&ctx.cache)
|
||||||
.await
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.emojis
|
.emojis
|
||||||
.contains_key(&emoji.id)
|
.contains_key(&emoji.id)
|
||||||
|
@ -66,21 +64,20 @@ impl EventHandler for Handler {
|
||||||
let attachments: Vec<AttachmentType> = msg
|
let attachments: Vec<AttachmentType> = msg
|
||||||
.attachments
|
.attachments
|
||||||
.iter()
|
.iter()
|
||||||
.map(|a| AttachmentType::Image(&a.url))
|
.map(|a| AttachmentType::Image((a.url).parse().unwrap()))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let msg_source = MessageSource::Player(Box::new(player_data.clone()));
|
let woxlf_msg = WoxlfMessage::default()
|
||||||
|
.source(MessageSource::Player(Box::new(player_data.clone())))
|
||||||
|
.dest(MessageDest::Broadcast)
|
||||||
|
.median(Median::Webhook)
|
||||||
|
.content(&user_msg)
|
||||||
|
.attachments(attachments)
|
||||||
|
.clone();
|
||||||
|
|
||||||
send_webhook_msg_to_player_channels(
|
dispatch_message(&ctx, &global_data, woxlf_msg)
|
||||||
&ctx,
|
.await
|
||||||
&guild,
|
.expect("Unable to send message to players");
|
||||||
&mut global_data,
|
|
||||||
msg_source,
|
|
||||||
&user_msg,
|
|
||||||
Some(attachments),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.expect("Unable to send message to players");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
use serenity::client::Context;
|
use serenity::client::Context;
|
||||||
use serenity::framework::standard::Args;
|
use serenity::framework::standard::Args;
|
||||||
use serenity::http::{AttachmentType, Http};
|
use serenity::model::channel::{PermissionOverwrite, PermissionOverwriteType};
|
||||||
use serenity::model::channel::{Message, PermissionOverwrite, PermissionOverwriteType};
|
|
||||||
use serenity::model::guild::{Guild, Member};
|
use serenity::model::guild::{Guild, Member};
|
||||||
use serenity::model::id::{ChannelId, UserId};
|
use serenity::model::id::ChannelId;
|
||||||
use serenity::model::Permissions;
|
use serenity::model::Permissions;
|
||||||
|
|
||||||
use crate::error;
|
use crate::error;
|
||||||
|
@ -11,201 +10,7 @@ use crate::error::WoxlfError;
|
||||||
use crate::game::game_state::PhaseDuration;
|
use crate::game::game_state::PhaseDuration;
|
||||||
use crate::game::global_data::GlobalData;
|
use crate::game::global_data::GlobalData;
|
||||||
use crate::game::player_data::PlayerData;
|
use crate::game::player_data::PlayerData;
|
||||||
use crate::game::MessageSource;
|
|
||||||
use crate::imgur::Image;
|
use crate::imgur::Image;
|
||||||
use serenity::prelude::SerenityError;
|
|
||||||
|
|
||||||
fn filter_source_channel(player_data: &&PlayerData, msg_source: &MessageSource) -> bool {
|
|
||||||
if let MessageSource::Player(source_player) = &msg_source {
|
|
||||||
if source_player.channel == player_data.channel {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
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| filter_source_channel(player, &msg_source))
|
|
||||||
.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.discord_config.host_channel,
|
|
||||||
))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let source = match msg_source {
|
|
||||||
MessageSource::Player(player_data) => {
|
|
||||||
let name = guild
|
|
||||||
.members
|
|
||||||
.get(&UserId::from(player_data.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 send_webhook_msg(
|
|
||||||
http: &Http,
|
|
||||||
webhook_id: u64,
|
|
||||||
username: &str,
|
|
||||||
profile_pic_url: Option<String>,
|
|
||||||
msg: &str,
|
|
||||||
attachment: Option<Vec<AttachmentType<'_>>>,
|
|
||||||
) -> error::Result<()> {
|
|
||||||
let webhook = http.get_webhook(webhook_id).await?;
|
|
||||||
|
|
||||||
webhook
|
|
||||||
.execute(http, false, |w| {
|
|
||||||
w.content(&msg).username(username);
|
|
||||||
|
|
||||||
if let Some(profile_pic_url) = profile_pic_url {
|
|
||||||
w.avatar_url(profile_pic_url);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(attachment) = attachment.clone() {
|
|
||||||
w.add_files(attachment);
|
|
||||||
}
|
|
||||||
|
|
||||||
w
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn send_webhook_msg_to_player_channels(
|
|
||||||
ctx: &Context,
|
|
||||||
guild: &Guild,
|
|
||||||
global_data: &mut GlobalData,
|
|
||||||
msg_source: MessageSource,
|
|
||||||
msg: &str,
|
|
||||||
attachment: Option<Vec<AttachmentType<'_>>>,
|
|
||||||
) -> error::Result<()> {
|
|
||||||
let msg_username = match &msg_source {
|
|
||||||
MessageSource::Player(p) => p.codename.clone(),
|
|
||||||
MessageSource::Host => "Woxlf".to_string(),
|
|
||||||
MessageSource::Automated => "Woxlf System Message".to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let profile_pic = match &msg_source {
|
|
||||||
MessageSource::Player(p) => Some(p.profile_pic_url.clone()),
|
|
||||||
MessageSource::Host | MessageSource::Automated => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let msg_tasks = global_data
|
|
||||||
.game_state_mut()?
|
|
||||||
.player_data
|
|
||||||
.iter()
|
|
||||||
.filter(|player| filter_source_channel(player, &msg_source))
|
|
||||||
.map(|player_data| {
|
|
||||||
send_webhook_msg(
|
|
||||||
&ctx.http,
|
|
||||||
player_data.channel_webhook_id,
|
|
||||||
&msg_username,
|
|
||||||
profile_pic.clone(),
|
|
||||||
msg,
|
|
||||||
attachment.clone(),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let msgs: Result<(), WoxlfError> = futures::future::join_all(msg_tasks)
|
|
||||||
.await
|
|
||||||
.into_iter()
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
msgs?;
|
|
||||||
|
|
||||||
let source = match &msg_source {
|
|
||||||
MessageSource::Player(player_data) => {
|
|
||||||
let name = guild
|
|
||||||
.members
|
|
||||||
.get(&UserId::from(player_data.discord_id))
|
|
||||||
.unwrap()
|
|
||||||
.display_name();
|
|
||||||
|
|
||||||
name.to_string()
|
|
||||||
}
|
|
||||||
MessageSource::Host => "Host".to_string(),
|
|
||||||
MessageSource::Automated => "Automated".to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let host_channel_username = format!("{} ({})", msg_username, source);
|
|
||||||
|
|
||||||
send_webhook_msg(
|
|
||||||
&ctx.http,
|
|
||||||
global_data.cfg.discord_config.host_webhook_id,
|
|
||||||
&host_channel_username,
|
|
||||||
profile_pic,
|
|
||||||
msg,
|
|
||||||
attachment,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn add_user_to_game(
|
pub async fn add_user_to_game(
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
|
@ -237,7 +42,7 @@ pub async fn add_user_to_game(
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let allow =
|
let allow =
|
||||||
Permissions::SEND_MESSAGES | Permissions::READ_MESSAGE_HISTORY | Permissions::READ_MESSAGES;
|
Permissions::SEND_MESSAGES | Permissions::READ_MESSAGE_HISTORY | Permissions::VIEW_CHANNEL;
|
||||||
|
|
||||||
let overwrite = PermissionOverwrite {
|
let overwrite = PermissionOverwrite {
|
||||||
allow,
|
allow,
|
||||||
|
|
|
@ -19,6 +19,7 @@ pub enum WoxlfError {
|
||||||
RanOutOfCodenames,
|
RanOutOfCodenames,
|
||||||
TemplateError(tera::Error),
|
TemplateError(tera::Error),
|
||||||
RanOutOfProfilePics,
|
RanOutOfProfilePics,
|
||||||
|
UnsupportedMsgMedium,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for WoxlfError {}
|
impl std::error::Error for WoxlfError {}
|
||||||
|
@ -41,6 +42,9 @@ impl Display for WoxlfError {
|
||||||
}
|
}
|
||||||
WoxlfError::TemplateError(e) => format!("Template error: {}", e),
|
WoxlfError::TemplateError(e) => format!("Template error: {}", e),
|
||||||
WoxlfError::RanOutOfProfilePics => "Ran out of user profile pics".to_string(),
|
WoxlfError::RanOutOfProfilePics => "Ran out of user profile pics".to_string(),
|
||||||
|
WoxlfError::UnsupportedMsgMedium => {
|
||||||
|
"Tried to send a message over an unsupported medium".to_string()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
write!(f, "Woxlf Error: {}", msg)
|
write!(f, "Woxlf Error: {}", msg)
|
||||||
|
|
|
@ -0,0 +1,315 @@
|
||||||
|
use crate::error;
|
||||||
|
use crate::error::WoxlfError;
|
||||||
|
use crate::game::global_data::GlobalData;
|
||||||
|
use crate::game::player_data::PlayerData;
|
||||||
|
use bitflags::bitflags;
|
||||||
|
use serenity::client::Context;
|
||||||
|
use serenity::http::{CacheHttp, Http};
|
||||||
|
use serenity::model::guild::Guild;
|
||||||
|
use serenity::model::id::{ChannelId, UserId};
|
||||||
|
use serenity::model::prelude::{AttachmentType, GuildId, WebhookId};
|
||||||
|
use serenity::utils::MessageBuilder;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum MessageSource {
|
||||||
|
Player(Box<PlayerData>),
|
||||||
|
Host,
|
||||||
|
Automated,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MessageSource {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Automated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub enum MessageDest {
|
||||||
|
Player(Box<PlayerData>),
|
||||||
|
Host,
|
||||||
|
Broadcast,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MessageDest {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Broadcast
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub enum Median {
|
||||||
|
DirectMessage,
|
||||||
|
Webhook,
|
||||||
|
StandardMessage,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Median {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Webhook
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct MsgFlags: u32 {
|
||||||
|
const PIN_MSG = 0b00000001;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub struct WoxlfMessage<'a> {
|
||||||
|
pub source: MessageSource,
|
||||||
|
pub dest: MessageDest,
|
||||||
|
pub median: Median,
|
||||||
|
pub content: String,
|
||||||
|
pub attachments: Option<Vec<AttachmentType<'a>>>,
|
||||||
|
pub flags: MsgFlags,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
impl<'a> WoxlfMessage<'a> {
|
||||||
|
pub fn get_profile_pic(&self, global_data: &GlobalData) -> Result<String, WoxlfError> {
|
||||||
|
Ok(match &self.source {
|
||||||
|
MessageSource::Player(p) => p.profile_pic_url.clone(),
|
||||||
|
MessageSource::Host | MessageSource::Automated => {
|
||||||
|
global_data.game_cfg()?.bot_profile_pic.clone()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_message_username(&self, global_data: &GlobalData) -> Result<String, WoxlfError> {
|
||||||
|
Ok(match &self.source {
|
||||||
|
MessageSource::Player(p) => p.codename.clone(),
|
||||||
|
MessageSource::Host => global_data.game_cfg()?.bot_name.clone(),
|
||||||
|
MessageSource::Automated => "Woxlf System Message".to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn source(mut self, source: MessageSource) -> Self {
|
||||||
|
self.source = source;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dest(mut self, dest: MessageDest) -> Self {
|
||||||
|
self.dest = dest;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn median(mut self, median: Median) -> Self {
|
||||||
|
self.median = median;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn content(mut self, content: &str) -> Self {
|
||||||
|
self.content = content.to_string();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn attachments(mut self, attachments: Vec<AttachmentType<'a>>) -> Self {
|
||||||
|
self.attachments = Some(attachments);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn flags(mut self, flags: MsgFlags) -> Self {
|
||||||
|
self.flags = flags;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pin(mut self) -> Self {
|
||||||
|
self.flags |= MsgFlags::PIN_MSG;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn filter_source_channel(player_data: &&PlayerData, msg_source: &MessageSource) -> bool {
|
||||||
|
if let MessageSource::Player(source_player) = &msg_source {
|
||||||
|
if source_player.channel == player_data.channel {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_webhook_msg(
|
||||||
|
http: &Http,
|
||||||
|
webhook_id: WebhookId,
|
||||||
|
username: &str,
|
||||||
|
profile_pic_url: Option<String>,
|
||||||
|
msg: &str,
|
||||||
|
attachments: &Option<Vec<AttachmentType<'_>>>,
|
||||||
|
) -> error::Result<()> {
|
||||||
|
let webhook = http.get_webhook(webhook_id.0).await?;
|
||||||
|
|
||||||
|
webhook
|
||||||
|
.execute(http, false, move |w| {
|
||||||
|
w.content(&msg).username(username);
|
||||||
|
|
||||||
|
if let Some(profile_pic_url) = profile_pic_url {
|
||||||
|
w.avatar_url(profile_pic_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(attachments) = attachments {
|
||||||
|
w.add_files(attachments.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
w
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_private_message(
|
||||||
|
http: &Http,
|
||||||
|
src_username: &str,
|
||||||
|
dest: UserId,
|
||||||
|
msg: &str,
|
||||||
|
attachments: &Option<Vec<AttachmentType<'_>>>,
|
||||||
|
) -> error::Result<()> {
|
||||||
|
let dest_user = dest.to_user(http).await?;
|
||||||
|
|
||||||
|
let mut dm_message = MessageBuilder::new();
|
||||||
|
|
||||||
|
dm_message.push_bold_line_safe(format!("{} has sent you a DM:", src_username));
|
||||||
|
dm_message.push(msg);
|
||||||
|
|
||||||
|
dest_user
|
||||||
|
.dm(http, |msg| {
|
||||||
|
msg.content(dm_message);
|
||||||
|
|
||||||
|
if let Some(attachments) = attachments {
|
||||||
|
msg.add_files(attachments.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
msg
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_to_host_channel(
|
||||||
|
http: &Http,
|
||||||
|
guild: &Guild,
|
||||||
|
global_data: &GlobalData,
|
||||||
|
msg: WoxlfMessage<'_>,
|
||||||
|
) -> error::Result<()> {
|
||||||
|
let source = match &msg.source {
|
||||||
|
MessageSource::Player(player_data) => {
|
||||||
|
let name = guild
|
||||||
|
.members
|
||||||
|
.get(&UserId::from(player_data.discord_id))
|
||||||
|
.unwrap()
|
||||||
|
.display_name();
|
||||||
|
|
||||||
|
name.to_string()
|
||||||
|
}
|
||||||
|
MessageSource::Host => "Host".to_string(),
|
||||||
|
MessageSource::Automated => "Automated".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let dest = match &msg.median {
|
||||||
|
Median::DirectMessage => {
|
||||||
|
if let MessageDest::Player(dest_player) = &msg.dest {
|
||||||
|
let name = guild
|
||||||
|
.members
|
||||||
|
.get(&UserId::from(dest_player.discord_id))
|
||||||
|
.unwrap()
|
||||||
|
.display_name();
|
||||||
|
format!(" to {} ({})", dest_player.codename, name)
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => "".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let host_channel_username = format!(
|
||||||
|
"{} ({}){}",
|
||||||
|
msg.get_message_username(global_data)?,
|
||||||
|
source,
|
||||||
|
dest
|
||||||
|
);
|
||||||
|
|
||||||
|
send_webhook_msg(
|
||||||
|
http,
|
||||||
|
WebhookId::from(global_data.cfg.discord_config.host_webhook_id),
|
||||||
|
&host_channel_username,
|
||||||
|
Some(msg.get_profile_pic(global_data)?),
|
||||||
|
&msg.content,
|
||||||
|
&msg.attachments,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_message(
|
||||||
|
ctx: &Context,
|
||||||
|
global_data: &GlobalData,
|
||||||
|
msg: &WoxlfMessage<'_>,
|
||||||
|
dest_player: &PlayerData,
|
||||||
|
) -> Result<(), WoxlfError> {
|
||||||
|
match &msg.median {
|
||||||
|
Median::Webhook => {
|
||||||
|
send_webhook_msg(
|
||||||
|
&ctx.http,
|
||||||
|
WebhookId::from(dest_player.channel_webhook_id),
|
||||||
|
&msg.get_message_username(global_data)?,
|
||||||
|
Some(msg.get_profile_pic(global_data)?),
|
||||||
|
&msg.content,
|
||||||
|
&msg.attachments,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
Median::DirectMessage => {
|
||||||
|
send_private_message(
|
||||||
|
&ctx.http,
|
||||||
|
&msg.get_message_username(global_data)?,
|
||||||
|
UserId(dest_player.discord_id),
|
||||||
|
&msg.content,
|
||||||
|
&msg.attachments,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
Median::StandardMessage => {
|
||||||
|
let channel = ChannelId::from(dest_player.channel);
|
||||||
|
channel.say(&ctx.http(), &msg.content).await?;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn dispatch_message(
|
||||||
|
ctx: &Context,
|
||||||
|
global_data: &GlobalData,
|
||||||
|
msg: WoxlfMessage<'_>,
|
||||||
|
) -> error::Result<()> {
|
||||||
|
let guild_id = global_data.cfg.discord_config.guild_id;
|
||||||
|
let guild = GuildId::from(guild_id).to_guild_cached(&ctx.cache).unwrap();
|
||||||
|
|
||||||
|
let msg_tasks = global_data
|
||||||
|
.game_state()?
|
||||||
|
.player_data
|
||||||
|
.iter()
|
||||||
|
.filter(|player| filter_source_channel(player, &msg.source))
|
||||||
|
.filter(|player| match &msg.dest {
|
||||||
|
MessageDest::Player(dest_user) => dest_user.discord_id == player.discord_id,
|
||||||
|
MessageDest::Host => false,
|
||||||
|
MessageDest::Broadcast => true,
|
||||||
|
})
|
||||||
|
.map(|p| send_message(ctx, global_data, &msg, p));
|
||||||
|
|
||||||
|
let results: Result<(), WoxlfError> = futures::future::join_all(msg_tasks)
|
||||||
|
.await
|
||||||
|
.into_iter()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
results?;
|
||||||
|
|
||||||
|
send_to_host_channel(&ctx.http, &guild, global_data, msg).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -1,9 +1,8 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::game::player_data::PlayerData;
|
|
||||||
|
|
||||||
pub mod game_state;
|
pub mod game_state;
|
||||||
pub mod global_data;
|
pub mod global_data;
|
||||||
|
pub mod message_router;
|
||||||
pub mod player_data;
|
pub mod player_data;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialEq, Copy)]
|
#[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialEq, Copy)]
|
||||||
|
@ -17,10 +16,3 @@ impl Default for Phase {
|
||||||
Self::Night
|
Self::Night
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum MessageSource {
|
|
||||||
Player(Box<PlayerData>),
|
|
||||||
Host,
|
|
||||||
Automated,
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use serenity::client::bridge::gateway::GatewayIntents;
|
|
||||||
use serenity::prelude::*;
|
use serenity::prelude::*;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
|
@ -32,10 +31,9 @@ async fn main() {
|
||||||
.expect("Unable to open saved game state.");
|
.expect("Unable to open saved game state.");
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut client = Client::builder(&bot_cfg.discord_config.token)
|
let mut client = Client::builder(&bot_cfg.discord_config.token, GatewayIntents::all())
|
||||||
.event_handler(Handler {})
|
.event_handler(Handler {})
|
||||||
.framework(command_framework())
|
.framework(command_framework())
|
||||||
.intents(GatewayIntents::all())
|
|
||||||
.type_map_insert::<GlobalData>(Arc::new(Mutex::new(global_data)))
|
.type_map_insert::<GlobalData>(Arc::new(Mutex::new(global_data)))
|
||||||
.await
|
.await
|
||||||
.expect("Err creating client");
|
.expect("Err creating client");
|
||||||
|
|
|
@ -8,9 +8,9 @@ use serenity::prelude::Mentionable;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use tera::{Tera, Value};
|
use tera::{Tera, Value};
|
||||||
|
|
||||||
fn time_to_discord_time(
|
type TeraFnRet = Box<dyn Fn(&HashMap<String, Value>) -> tera::Result<Value> + Send + Sync>;
|
||||||
time_flag: &str,
|
|
||||||
) -> Box<dyn Fn(&HashMap<String, Value>) -> tera::Result<Value> + Send + Sync> {
|
fn time_to_discord_time(time_flag: &str) -> TeraFnRet {
|
||||||
let time_flag = time_flag.to_string();
|
let time_flag = time_flag.to_string();
|
||||||
|
|
||||||
Box::new(
|
Box::new(
|
||||||
|
|
Loading…
Reference in New Issue