From b3a6a7eb255bb6d186e116d62ef410c5b8ed8688 Mon Sep 17 00:00:00 2001 From: ByteDice Date: Fri, 27 Feb 2026 13:00:11 +0100 Subject: [PATCH 1/6] removed french language & updated en-us --- data/lang/en.json | 8 ++--- data/lang/gpt_fr.json | 69 ------------------------------------------- 2 files changed, 4 insertions(+), 73 deletions(-) delete mode 100644 data/lang/gpt_fr.json diff --git a/data/lang/en.json b/data/lang/en.json index 722c00a..8f5bad2 100644 --- a/data/lang/en.json +++ b/data/lang/en.json @@ -7,10 +7,10 @@ "dc_btn_vote": "Vote", "dc_msg_8-ball_answer": "**8-ball Question:** {0}\n**Answer:** {1}", "dc_msg_add_to_data": "Added your server to my data! Thanks for letting me steal it! (/s)", - "dc_msg_bound_channel": "Successfully bound channel ID `{0}` as the \"where all collected Reddit data gets dumped\" channel!", + "dc_msg_bound_channel": "Successfully added channel ID `{0}` to the database!", "dc_msg_cmd_404": "No command \"{0}\" found!\nHint: Try `/help` without any arguments or `/help `", - "dc_msg_corrupted_data": "Oopsies `(。>\\\\<)`. It looks like my data i-is \\**sob*\\*... c-corrupted!\n[From Byte Dice]: I have no idea what I was thinking while writing this at 2am. I'm not removing it.", - "dc_msg_data_server_404": "This server is not in the data!\n Hint: Run the command `/add_server` inside of a Discord server (requires administrator permission).", + "dc_msg_corrupted_data": "Oopsies `(。>\\\\<)`. It looks like my data i-is \\**sob*\\*... c-corrupted!", + "dc_msg_data_server_404": "This server is not in the data!\n Hint: Run the command `/database AddServer` inside of a Discord server (requires administrator permission).", "dc_msg_dm_python_err_socket": "Unknown internal Python error occurred: Websocket response error", "dc_msg_dm_python_err": "Unknown internal Python Error:\n```\n{0}\n```", "dc_msg_embed_default_embed_desc": "Default english embed description.", @@ -38,7 +38,7 @@ "dc_msg_re_post_unremove_success": "Successfully restored post with URL \"<{0}>\"!", "dc_msg_re_post_update_success": "Updated post with URL \"<{0}>\"!", "dc_msg_re_post_vote_removed_post": "Couldn't [vote / un-vote] the post because it has been removed!", - "dc_msg_re_posts_channel_404": "Could not find `re_posts_channel` in data!\nHint: Run `/admin_re_bindchannel` in a (preferably read-only) channel (requires administrator permission).", + "dc_msg_re_posts_channel_404": "Could not find `re_posts_channel` in data!\nHint: Run `/database RedditChannel` in a (preferably read-only) channel (requires administrator permission).", "dc_msg_re_vote_err": "Failed to [vote / un-vote]: Unknown internal error.", "dc_msg_re_vote_mod_success": "Successfully voted (as moderator vote)!", "dc_msg_re_vote_remove_havent": "Couldn't remove your vote: You haven't voted on this post yet!", diff --git a/data/lang/gpt_fr.json b/data/lang/gpt_fr.json deleted file mode 100644 index d949ba2..0000000 --- a/data/lang/gpt_fr.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "dc_btn_approve": "Approuver", - "dc_btn_remove": "Supprimer", - "dc_btn_unapprove": "Désapprouver", - "dc_btn_unremove": "Restaurer", - "dc_btn_unvote": "Annuler le vote", - "dc_btn_vote": "Voter", - "dc_msg_8-ball_answer": "**Question de la boule magique :** {0}\n**Réponse :** {1}", - "dc_msg_add_to_data": "Serveur ajouté à mes données ! Merci de me laisser les voler ! (/s)", - "dc_msg_bound_channel": "Canal avec l’identifiant `{0}` lié avec succès comme canal \"où toutes les données Reddit collectées sont envoyées\" !", - "dc_msg_cmd_404": "Commande \"{0}\" introuvable !\nAstuce : Essayez `/help` sans arguments ou `/help `", - "dc_msg_corrupted_data": "Oups `(。>\\\\<)`. On dirait que mes données sont \\**snif*\\*... c-corrompues !\n[De Byte Dice] : Je n’ai aucune idée de ce que je faisais à 2h du matin. Je ne le supprime pas.", - "dc_msg_data_server_404": "Ce serveur n’est pas dans les données !\n Astuce : Exécutez la commande `/add_server` dans un serveur Discord (nécessite les droits administrateur).", - "dc_msg_dm_python_err_socket": "Erreur Python interne inconnue : erreur de réponse WebSocket", - "dc_msg_dm_python_err": "Erreur Python interne inconnue :\n```\n{0}\n```", - "dc_msg_embed_default_embed_desc": "Description par défaut de l'encart en anglais.", - "dc_msg_embed_re_post": "Spoilers et anonymiseur de durée des votes pour une évaluation équitable !\n## Données du post :\n**Subreddit :** {0}\n**Votes positifs du post :** ||`{1:>6}`||\n**Votes des modérateurs :** ||`{2:>6}`||\n**Type de média :** `{3}`\n## Données d'inscription :\n**Ajouté par :** humain : {4} | bot : {5}\n**Approuvé:** {6}", - "dc_msg_embed_re_removed": "## Supprimé par `{0}`\n**Raison :** {1}", - "dc_msg_err_trace": "Erreur inconnue !\nTrace de l’erreur : {0}", - "dc_msg_failed_shorturl_conversion": "Échec de la conversion en shortURL : format d’URL Reddit invalide.", - "dc_msg_mandatory_response": "Message de réponse obligatoire, merci d’ignorer.", - "dc_msg_no_perms": "Permission manquante sur ce serveur : {0}", - "dc_msg_not_in_guild": "Je ne fais pas partie de ce serveur.", - "dc_msg_owner_data_save_complete": "Sauvegarde des données... Terminé !\nFermeture...", - "dc_msg_owner_data_save": "Sauvegarde des données...", - "dc_msg_owner_shutdown_failed_confirmation": "Échec de l’arrêt : confirmation invalide.", - "dc_msg_re_already_voted": "Impossible de voter : vous avez déjà voté pour ce post !", - "dc_msg_re_also_approved": "Également approuvé !", - "dc_msg_re_data_corrupted": "URL du post \"<{0}>\" introuvable : données du post corrompues !\n Détails : clé \"posts\" introuvable dans le fichier \"re_data.json\"", - "dc_msg_re_help_removed": "Fichier d’aide Reddit introuvable, il a probablement été supprimé.\n Astuce : Vous pouvez trouver le fichier d’aide officiel à https://github.com/ByteDice/ByteDiceAssistant dans `re_help.md`.\n**ATTENTION :** Le fichier d’aide peut contenir des informations incorrectes si vous n’utilisez pas le bot officiel de Byte Dice.", - "dc_msg_re_permdeny_not_re_mod": "Permission refusée : vous n’êtes pas modérateur des subreddit(s) {0}", - "dc_msg_re_post_404": "URL du post \"<{0}>\" introuvable : le post n’existe pas dans les données !\n Astuce : Exécutez la commande `/re_addpost [URL]` dans un canal Discord ou `u/ByteDiceAssistant add_post` sur un post Reddit.", - "dc_msg_re_post_add_success": "Post ajouté avec succès à l’URL \"<{0}>\" !", - "dc_msg_re_post_approve_remove": "Impossible d’approuver le post car il a été supprimé !", - "dc_msg_re_post_approve_success": "Post approuvé avec succès !", - "dc_msg_re_post_disapprove_success": "Post désapprouvé avec succès !", - "dc_msg_re_post_remove_success": "Post supprimé avec succès à l’URL \"<{0}>\" !", - "dc_msg_re_post_unremove_success": "Post restauré avec succès à l’URL \"<{0}>\" !", - "dc_msg_re_post_update_success": "Post mis à jour avec succès à l’URL \"<{0}>\" !", - "dc_msg_re_post_vote_removed_post": "Impossible de [voter / annuler le vote] : le post a été supprimé !", - "dc_msg_re_posts_channel_404": "Impossible de trouver `re_posts_channel` dans les données !\nAstuce : Exécutez `/admin_re_bindchannel` dans un canal (de préférence en lecture seule) (nécessite les droits administrateur).", - "dc_msg_re_vote_err": "Échec du [vote / annulation du vote] : erreur interne inconnue.", - "dc_msg_re_vote_mod_success": "Vote enregistré avec succès (vote modérateur) !", - "dc_msg_re_vote_remove_havent": "Impossible de retirer le vote : vous n’avez pas encore voté pour ce post !", - "dc_msg_re_vote_remove_success": "Vote retiré avec succès !", - "dc_msg_re_vote_success": "Vote enregistré avec succès !", - "dc_msg_reload_cfg_python_fail": "Échec du rechargement des configurations : réponse invalide de Python.", - "dc_msg_reload_cfg_success": "Configurations rechargées avec succès !\nNouvelles configurations :\n```\n{0}\n```", - "dc_msg_removed_square_brackets": "[SUPPRIMÉ] {0}", - "dc_msg_shorturl": "ShortURL : <{0}>", - "dc_msg_update_add": "{0}Ajout de nouveaux posts...", - "dc_msg_update_done": "{0}Terminé !", - "dc_msg_update_editing": "{0}Modification des posts mis à jour...", - "dc_msg_update_fetch": "{0}Récupération des nouveaux posts et mise à jour du fichier de données...", - "dc_msg_update_parse": "{0}Analyse des messages vers JSON...", - "dc_msg_update_read": "{0}Lecture des messages dans <#{1}>...", - "dc_msg_update_removing_dupe": "{0}Suppression des posts en double...", - "dc_msg_update_removing_old": "{0}Suppression des anciens posts (seuil : {1}j)...", - "dc_msg_update_removing": "{0}Suppression des posts supprimés...", - "dc_msg_whoami": "**Propriétaire du bot :** {0}\n**Modérateur BK :** {1}", - "log_lang_load_success": "Fichier de langue français chargé avec succès !", - "none": "Aucun", - "py_re_response_suffix": "^(Je ne suis pas une IA, juste un bot. Cette action a été effectuée automatiquement. Vous pouvez signaler des bugs et consulter mon code source [ici](https://github.com/ByteDice/ByteDiceAssistant) !)", - "py_re_response_weekly_add": "Post ajouté avec succès aux soumissions hebdomadaires d'art ! Merci pour votre participation !", - "py_re_response_weekly_exists": "Impossible d’ajouter ce post, il est déjà présent ! Merci pour votre participation !", - "py_re_response_weekly_mod_add": "[ACTION MOD] Post ajouté avec succès aux soumissions hebdomadaires d’art !", - "py_re_response_weekly_mod_unremove": "[ACTION MOD] Post restauré avec succès dans les soumissions hebdomadaires d’art !", - "dc_msg_success": "succès !" -} \ No newline at end of file From 650cb98a3e67be2831717b4d91b621aa66db8f9f Mon Sep 17 00:00:00 2001 From: ByteDice Date: Fri, 27 Feb 2026 13:00:40 +0100 Subject: [PATCH 2/6] moved database-related commands into subcommands & added wwrps database entry --- data/defaults/dc_data_preset.json | 3 +- src/data.rs | 20 +++++++++++ src/{cmds => db_cmds}/add_server.rs | 10 ------ src/db_cmds/main_cmd.rs | 35 +++++++++++++++++++ .../reddit_channel.rs} | 10 ------ src/db_cmds/wwrps_channel.rs | 18 ++++++++++ src/gen.rs | 5 ++- src/main.rs | 8 +++-- 8 files changed, 83 insertions(+), 26 deletions(-) rename src/{cmds => db_cmds}/add_server.rs (55%) create mode 100644 src/db_cmds/main_cmd.rs rename src/{re_cmds/admin_bind.rs => db_cmds/reddit_channel.rs} (58%) create mode 100644 src/db_cmds/wwrps_channel.rs diff --git a/data/defaults/dc_data_preset.json b/data/defaults/dc_data_preset.json index 502a5b4..baecfa5 100644 --- a/data/defaults/dc_data_preset.json +++ b/data/defaults/dc_data_preset.json @@ -2,7 +2,8 @@ "servers": { "SERVER ID": { "re_posts_channel": 0, - "re_disabled": false + "re_disabled": false, + "wwrps_channel": 0 } } } \ No newline at end of file diff --git a/src/data.rs b/src/data.rs index b3c8b9c..0d5f95f 100644 --- a/src/data.rs +++ b/src/data.rs @@ -20,6 +20,7 @@ static PRESET_PATH_CFG: &str = "./data/defaults/cfg_default.toml"; static DATA_PATH_LANG: &str = "./data/lang/"; pub static DC_POSTS_CHANNEL_KEY: &str = "re_posts_channel"; +pub static DC_WWRPS_CHANNEL_KEY: &str = "wwrps_channel"; pub async fn read_dc_data(data: &Data, wipe: bool) { @@ -181,6 +182,25 @@ pub async fn dc_bind_bk(data: &Data, server_id: u64, channel_id: u64) -> Result< } +pub async fn bind_wwrps(data: &Data, server_id: u64, channel_id: u64) -> Result<(), ()> { + let mut dc_data_lock = data.discord_data.lock().await; + let dc_data = dc_data_lock.as_mut().unwrap(); + + if dc_data.get("servers").is_none() { return Err(()); } + + let servers = dc_data["servers"].as_object_mut().unwrap(); + + if !servers.contains_key(&server_id.to_string()) + { return Err(()); } + + let server = servers[&server_id.to_string()].as_object_mut().unwrap(); + + server.insert(DC_WWRPS_CHANNEL_KEY.to_string(), channel_id.into()); + + return Ok(()); +} + + pub async fn dc_contains_server(data: &Data, server_id: u64) -> bool { let dc_data_lock = data.discord_data.lock().await; let dc_data = dc_data_lock.as_ref().unwrap(); diff --git a/src/cmds/add_server.rs b/src/db_cmds/add_server.rs similarity index 55% rename from src/cmds/add_server.rs rename to src/db_cmds/add_server.rs index 21b0040..4d8658f 100644 --- a/src/cmds/add_server.rs +++ b/src/db_cmds/add_server.rs @@ -1,16 +1,6 @@ use crate::{data::dc_add_server, lang, messages::send_msg, Context, Error}; -#[poise::command( - slash_command, - prefix_command, - rename = "add_server", - category = "db", - default_member_permissions = "ADMINISTRATOR", - guild_only, - required_bot_permissions = "SEND_MESSAGES | VIEW_CHANNEL" -)] -/// Add your server to my database so I can sell it! (/s), I only store some minimal data the bot needs. pub async fn cmd( ctx: Context<'_> ) -> Result<(), Error> diff --git a/src/db_cmds/main_cmd.rs b/src/db_cmds/main_cmd.rs new file mode 100644 index 0000000..9235a8f --- /dev/null +++ b/src/db_cmds/main_cmd.rs @@ -0,0 +1,35 @@ +use crate::{Context, Error, db_cmds::{add_server, reddit_channel, wwrps_channel}}; + + +#[derive(poise::ChoiceParameter, PartialEq)] +pub enum Subcommands { + AddServer, + RedditChannel, + WWRPSChannel +} + + +#[poise::command( + slash_command, + prefix_command, + category = "db", + rename = "database", + owners_only, + default_member_permissions = "ADMINISTRATOR", + required_bot_permissions = "SEND_MESSAGES | VIEW_CHANNEL" +)] +/// Various debug utilities +pub async fn cmd( + ctx: Context<'_>, + #[description = "Subcommand"] subcommand: Subcommands, +) -> Result<(), Error> +{ + match subcommand { + Subcommands::AddServer => add_server::cmd(ctx).await?, + Subcommands::RedditChannel => reddit_channel::cmd(ctx).await?, + Subcommands::WWRPSChannel => wwrps_channel::cmd(ctx).await?, + //_ => return Ok(()) + } + + return Ok(()); +} diff --git a/src/re_cmds/admin_bind.rs b/src/db_cmds/reddit_channel.rs similarity index 58% rename from src/re_cmds/admin_bind.rs rename to src/db_cmds/reddit_channel.rs index 9205b2b..193c411 100644 --- a/src/re_cmds/admin_bind.rs +++ b/src/db_cmds/reddit_channel.rs @@ -1,15 +1,5 @@ use crate::{data::dc_bind_bk, lang, messages::send_msg, Context, Error}; -#[poise::command( - slash_command, - prefix_command, - rename = "admin_re_bindchannel", - category = "db", - default_member_permissions = "ADMINISTRATOR", - guild_only, - required_bot_permissions = "SEND_MESSAGES | VIEW_CHANNEL" -)] -/// Sets the channel where the bot will dump all Reddit data upon using /re_updateDiscord. pub async fn cmd( ctx: Context<'_> ) -> Result<(), Error> diff --git a/src/db_cmds/wwrps_channel.rs b/src/db_cmds/wwrps_channel.rs new file mode 100644 index 0000000..40b133e --- /dev/null +++ b/src/db_cmds/wwrps_channel.rs @@ -0,0 +1,18 @@ +use crate::{Context, Error, data::bind_wwrps, lang, messages::send_msg}; + +pub async fn cmd( + ctx: Context<'_> +) -> Result<(), Error> +{ + let c_id = ctx.channel_id().into(); + let r = bind_wwrps(ctx.data(), ctx.guild_id().unwrap().into(), c_id).await; + + if r.is_ok() { + send_msg(ctx, lang!("dc_msg_bound_channel", c_id), true, true).await; + } + else { + send_msg(ctx, lang!("dc_msg_data_server_404"), true, true).await; + } + + return Ok(()); +} \ No newline at end of file diff --git a/src/gen.rs b/src/gen.rs index 73e7f7e..a9315e2 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -6,7 +6,7 @@ use poise::serenity_prelude::Client; use toml::Value; use crate::data::get_toml_mutex; -use crate::{Args, Cmd, Data, cmds, data, debug_cmds, events, re_cmds, rs_println}; +use crate::{Args, Cmd, Data, cmds, data, db_cmds, debug_cmds, events, re_cmds, rs_println}; pub async fn gen_data(args: Args, owners: Vec) -> Data { @@ -100,8 +100,7 @@ async fn make_cmd_vec(data: &Data) -> Vec { cmds::send::cmd(), debug_cmds::main_cmd::cmd(), // DATABASE - re_cmds::admin_bind::cmd(), - cmds::add_server::cmd(), + db_cmds::main_cmd::cmd() ]; let cfg = get_toml_mutex(&data.cfg).await.unwrap(); diff --git a/src/main.rs b/src/main.rs index e1de758..d4b435e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,6 @@ #![allow(static_mut_refs)] mod cmds { - pub mod add_server; pub mod eight_ball; pub mod embed; pub mod help; @@ -11,7 +10,6 @@ mod cmds { } mod re_cmds { pub mod add; - pub mod admin_bind; pub mod approve; pub mod generic_fns; pub mod get; @@ -31,6 +29,12 @@ mod debug_cmds { pub mod view_guilds; pub mod whoami; } +mod db_cmds { + pub mod add_server; + pub mod reddit_channel; + pub mod main_cmd; + pub mod wwrps_channel; +} mod events; mod messages; mod python; From 4c4ff1379bd975d723ced6a3bf25c2b921a7ed72 Mon Sep 17 00:00:00 2001 From: ByteDice Date: Fri, 27 Feb 2026 16:44:40 +0100 Subject: [PATCH 3/6] started on wwrps (BROKEN, continuing on other device) --- src/cmds/wwrps.rs | 105 ++++++++++++++++++++++++++++++++++++++++++++++ src/data.rs | 2 +- src/gen.rs | 2 + src/main.rs | 3 ++ 4 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 src/cmds/wwrps.rs diff --git a/src/cmds/wwrps.rs b/src/cmds/wwrps.rs new file mode 100644 index 0000000..6f5ad52 --- /dev/null +++ b/src/cmds/wwrps.rs @@ -0,0 +1,105 @@ +use poise::serenity_prelude::User; + +use crate::{Context, Error, data::get_mutex_data, lang, messages::send_msg}; + + +#[derive(poise::ChoiceParameter, PartialEq, Clone)] +#[repr(u8)] +pub enum RPS { + Paper = 0, + Rock = 1, + Scissors = 2 +} + + +#[derive(Clone)] +pub struct RPSPlayer { + pub selection: RPS, + pub user: User, + pub anonymous: bool +} +pub struct RPSGame { + pub players: [Option; 2], +} + + +impl RPSGame { + pub fn new() -> Self { + return RPSGame { + players: [None, None], + } + } + + pub fn add_player(&mut self, player: RPSPlayer) -> Result<(), Error> { + if let Some(p1) = &self.players[0] + { if p1.user == player.user { return Err(Error::from("Cannot add player, it already exists!")); }} + + if self.players[0].is_none() { self.players[0] = Some(player); return Ok(()); } + else if self.players[1].is_none() { self.players[1] = Some(player); return Ok(()); } + else { return Err(Error::from("Cannot add player, list is full!")); } + } + + pub fn clear(&mut self) + { self.players = [None, None]; } + + + pub fn get_winner(&self) -> Option { + if self.players.iter().any(|i| i.is_none()) + { return None; } + + let Some(p1) = self.players[0].clone() else { return None; }; + let Some(p2) = self.players[1].clone() else { return None; }; + + let i1 = p1.selection as u8; + let i2 = p2.selection as u8; + + if i1 == i2 { return None; } + else if (i1 + 1) % 3 == i2 { return Some(0); } + else { return Some(1); } + } + + pub fn is_full_lobby(&self) -> bool + { return self.players.iter().all(|i| i.is_some()); } +} + + +#[poise::command( + slash_command, + prefix_command, + category = "fun", + rename = "wwrps", + required_bot_permissions = "SEND_MESSAGES | VIEW_CHANNEL" +)] +/// World-Wide Rock Paper Scissors. Play with a completely random person! +pub async fn cmd( + ctx: Context<'_>, + selection: RPS, + #[description = "If true, replaces your username with [Anonymous]."] anonymous: bool +) -> Result<(), Error> +{ + let c_o = get_wwrps_channel(ctx).await; + + if c_o.is_none() { send_msg(ctx, lang!("dc_msg_wwrps_not_in_data"), true, true).await; return Ok(()); } + let c = c_o.unwrap(); + + let mut game = &ctx.data().rps_game; + + if !game.is_full_lobby() { game.add_player(RPSPlayer { selection, user: ctx.author().clone(), anonymous }); } + + return Ok(()); +} + + +async fn get_wwrps_channel(ctx: Context<'_>) -> Option { + let d = get_mutex_data(&ctx.data().discord_data).await.unwrap(); + + let is_guild = ctx.guild_channel().await.is_some(); + + if !is_guild { return Some(ctx.channel_id().get()); } + + let Some(servers) = d.get("servers") else { return None; }; + let Some(s) = servers.get(ctx.guild_id().unwrap().get() as usize) else { return None; }; + let Some(c_id) = s.get("wwrps_channel") else { return None; }; + + return Some(c_id.as_u64().unwrap()); +} \ No newline at end of file diff --git a/src/data.rs b/src/data.rs index 0d5f95f..67f43b2 100644 --- a/src/data.rs +++ b/src/data.rs @@ -155,7 +155,7 @@ pub async fn dc_add_server(data: &Data, server_id: u64) -> Result<(), ()> { let servers = dc_data["servers"].as_object_mut().unwrap(); if !servers.contains_key(&server_id.to_string()) { - servers.insert(server_id.to_string(), json!({ DC_POSTS_CHANNEL_KEY: 0 })); + servers.insert(server_id.to_string(), json!({})); } return Ok(()); diff --git a/src/gen.rs b/src/gen.rs index a9315e2..4cff2c1 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -5,6 +5,7 @@ use poise::serenity_prelude as serenity; use poise::serenity_prelude::Client; use toml::Value; +use crate::cmds::wwrps::RPSGame; use crate::data::get_toml_mutex; use crate::{Args, Cmd, Data, cmds, data, db_cmds, debug_cmds, events, re_cmds, rs_println}; @@ -26,6 +27,7 @@ pub async fn gen_data(args: Args, owners: Vec) -> Data { let data = Data { owners, ball_prompts: [ball_classic, ball_quirk], + rps_game: RPSGame::new(), bk_mods: mods_vec_u64, reddit_data: None.into(), discord_data: None.into(), diff --git a/src/main.rs b/src/main.rs index d4b435e..d119a04 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ mod cmds { pub mod embed; pub mod help; pub mod send; + pub mod wwrps; } mod re_cmds { pub mod add; @@ -62,6 +63,7 @@ use tokio::runtime::Runtime; use tokio::sync::Mutex; use websocket::send_cmd_json; +use crate::cmds::wwrps::RPSGame; use crate::data::get_toml_mutex; use crate::schedule::Schedule; @@ -95,6 +97,7 @@ type Cmd = Command>; struct Data { owners: Vec, ball_prompts: [Vec; 2], + rps_game: RPSGame, reddit_data: Mutex>, discord_data: Mutex>, cfg: Mutex>, From fcf5ffad3a6ba7e330e9b85bf9d330c2acdcf210 Mon Sep 17 00:00:00 2001 From: ByteDice Date: Fri, 27 Feb 2026 16:51:04 +0100 Subject: [PATCH 4/6] converted tabs to spaces & updated gitignore --- .gitignore | 1 + data/defaults/dc_data_preset.json | 2 +- src/cmds/wwrps.rs | 126 +++++++++++++++--------------- src/data.rs | 4 +- src/db_cmds/main_cmd.rs | 12 +-- src/gen.rs | 4 +- src/main.rs | 8 +- 7 files changed, 79 insertions(+), 78 deletions(-) diff --git a/.gitignore b/.gitignore index 022b0e9..db58a6b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ Cargo.lock *.pdb **/__pycache__/ .vscode/ +!.vscode/settings.json # program-created data **/reddit_data.json diff --git a/data/defaults/dc_data_preset.json b/data/defaults/dc_data_preset.json index baecfa5..a69c92a 100644 --- a/data/defaults/dc_data_preset.json +++ b/data/defaults/dc_data_preset.json @@ -3,7 +3,7 @@ "SERVER ID": { "re_posts_channel": 0, "re_disabled": false, - "wwrps_channel": 0 + "wwrps_channel": 0 } } } \ No newline at end of file diff --git a/src/cmds/wwrps.rs b/src/cmds/wwrps.rs index 6f5ad52..cae1282 100644 --- a/src/cmds/wwrps.rs +++ b/src/cmds/wwrps.rs @@ -6,60 +6,60 @@ use crate::{Context, Error, data::get_mutex_data, lang, messages::send_msg}; #[derive(poise::ChoiceParameter, PartialEq, Clone)] #[repr(u8)] pub enum RPS { - Paper = 0, - Rock = 1, - Scissors = 2 + Paper = 0, + Rock = 1, + Scissors = 2 } #[derive(Clone)] pub struct RPSPlayer { - pub selection: RPS, - pub user: User, - pub anonymous: bool + pub selection: RPS, + pub user: User, + pub anonymous: bool } pub struct RPSGame { - pub players: [Option; 2], + pub players: [Option; 2], } impl RPSGame { - pub fn new() -> Self { - return RPSGame { - players: [None, None], - } - } + pub fn new() -> Self { + return RPSGame { + players: [None, None], + } + } - pub fn add_player(&mut self, player: RPSPlayer) -> Result<(), Error> { - if let Some(p1) = &self.players[0] - { if p1.user == player.user { return Err(Error::from("Cannot add player, it already exists!")); }} - - if self.players[0].is_none() { self.players[0] = Some(player); return Ok(()); } - else if self.players[1].is_none() { self.players[1] = Some(player); return Ok(()); } - else { return Err(Error::from("Cannot add player, list is full!")); } - } - - pub fn clear(&mut self) - { self.players = [None, None]; } - - - pub fn get_winner(&self) -> Option { - if self.players.iter().any(|i| i.is_none()) - { return None; } - - let Some(p1) = self.players[0].clone() else { return None; }; - let Some(p2) = self.players[1].clone() else { return None; }; - - let i1 = p1.selection as u8; - let i2 = p2.selection as u8; - - if i1 == i2 { return None; } - else if (i1 + 1) % 3 == i2 { return Some(0); } - else { return Some(1); } - } - - pub fn is_full_lobby(&self) -> bool - { return self.players.iter().all(|i| i.is_some()); } + pub fn add_player(&mut self, player: RPSPlayer) -> Result<(), Error> { + if let Some(p1) = &self.players[0] + { if p1.user == player.user { return Err(Error::from("Cannot add player, it already exists!")); }} + + if self.players[0].is_none() { self.players[0] = Some(player); return Ok(()); } + else if self.players[1].is_none() { self.players[1] = Some(player); return Ok(()); } + else { return Err(Error::from("Cannot add player, list is full!")); } + } + + pub fn clear(&mut self) + { self.players = [None, None]; } + + + pub fn get_winner(&self) -> Option { + if self.players.iter().any(|i| i.is_none()) + { return None; } + + let Some(p1) = self.players[0].clone() else { return None; }; + let Some(p2) = self.players[1].clone() else { return None; }; + + let i1 = p1.selection as u8; + let i2 = p2.selection as u8; + + if i1 == i2 { return None; } + else if (i1 + 1) % 3 == i2 { return Some(0); } + else { return Some(1); } + } + + pub fn is_full_lobby(&self) -> bool + { return self.players.iter().all(|i| i.is_some()); } } @@ -74,32 +74,32 @@ impl RPSGame { pub async fn cmd( ctx: Context<'_>, selection: RPS, - #[description = "If true, replaces your username with [Anonymous]."] anonymous: bool + #[description = "If true, replaces your username with [Anonymous]."] anonymous: bool ) -> Result<(), Error> { - let c_o = get_wwrps_channel(ctx).await; - - if c_o.is_none() { send_msg(ctx, lang!("dc_msg_wwrps_not_in_data"), true, true).await; return Ok(()); } - let c = c_o.unwrap(); - - let mut game = &ctx.data().rps_game; - - if !game.is_full_lobby() { game.add_player(RPSPlayer { selection, user: ctx.author().clone(), anonymous }); } - + let c_o = get_wwrps_channel(ctx).await; + + if c_o.is_none() { send_msg(ctx, lang!("dc_msg_wwrps_not_in_data"), true, true).await; return Ok(()); } + let c = c_o.unwrap(); + + let mut game = &ctx.data().rps_game; + + if !game.is_full_lobby() { game.add_player(RPSPlayer { selection, user: ctx.author().clone(), anonymous }); } + return Ok(()); } async fn get_wwrps_channel(ctx: Context<'_>) -> Option { - let d = get_mutex_data(&ctx.data().discord_data).await.unwrap(); - - let is_guild = ctx.guild_channel().await.is_some(); - - if !is_guild { return Some(ctx.channel_id().get()); } - - let Some(servers) = d.get("servers") else { return None; }; - let Some(s) = servers.get(ctx.guild_id().unwrap().get() as usize) else { return None; }; - let Some(c_id) = s.get("wwrps_channel") else { return None; }; - - return Some(c_id.as_u64().unwrap()); + let d = get_mutex_data(&ctx.data().discord_data).await.unwrap(); + + let is_guild = ctx.guild_channel().await.is_some(); + + if !is_guild { return Some(ctx.channel_id().get()); } + + let Some(servers) = d.get("servers") else { return None; }; + let Some(s) = servers.get(ctx.guild_id().unwrap().get() as usize) else { return None; }; + let Some(c_id) = s.get("wwrps_channel") else { return None; }; + + return Some(c_id.as_u64().unwrap()); } \ No newline at end of file diff --git a/src/data.rs b/src/data.rs index 67f43b2..63222bb 100644 --- a/src/data.rs +++ b/src/data.rs @@ -183,7 +183,7 @@ pub async fn dc_bind_bk(data: &Data, server_id: u64, channel_id: u64) -> Result< pub async fn bind_wwrps(data: &Data, server_id: u64, channel_id: u64) -> Result<(), ()> { - let mut dc_data_lock = data.discord_data.lock().await; + let mut dc_data_lock = data.discord_data.lock().await; let dc_data = dc_data_lock.as_mut().unwrap(); if dc_data.get("servers").is_none() { return Err(()); } @@ -191,7 +191,7 @@ pub async fn bind_wwrps(data: &Data, server_id: u64, channel_id: u64) -> Result< let servers = dc_data["servers"].as_object_mut().unwrap(); if !servers.contains_key(&server_id.to_string()) - { return Err(()); } + { return Err(()); } let server = servers[&server_id.to_string()].as_object_mut().unwrap(); diff --git a/src/db_cmds/main_cmd.rs b/src/db_cmds/main_cmd.rs index 9235a8f..92d49dd 100644 --- a/src/db_cmds/main_cmd.rs +++ b/src/db_cmds/main_cmd.rs @@ -3,9 +3,9 @@ use crate::{Context, Error, db_cmds::{add_server, reddit_channel, wwrps_channel} #[derive(poise::ChoiceParameter, PartialEq)] pub enum Subcommands { - AddServer, - RedditChannel, - WWRPSChannel + AddServer, + RedditChannel, + WWRPSChannel } @@ -15,7 +15,7 @@ pub enum Subcommands { category = "db", rename = "database", owners_only, - default_member_permissions = "ADMINISTRATOR", + default_member_permissions = "ADMINISTRATOR", required_bot_permissions = "SEND_MESSAGES | VIEW_CHANNEL" )] /// Various debug utilities @@ -26,8 +26,8 @@ pub async fn cmd( { match subcommand { Subcommands::AddServer => add_server::cmd(ctx).await?, - Subcommands::RedditChannel => reddit_channel::cmd(ctx).await?, - Subcommands::WWRPSChannel => wwrps_channel::cmd(ctx).await?, + Subcommands::RedditChannel => reddit_channel::cmd(ctx).await?, + Subcommands::WWRPSChannel => wwrps_channel::cmd(ctx).await?, //_ => return Ok(()) } diff --git a/src/gen.rs b/src/gen.rs index 4cff2c1..311c45a 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -27,7 +27,7 @@ pub async fn gen_data(args: Args, owners: Vec) -> Data { let data = Data { owners, ball_prompts: [ball_classic, ball_quirk], - rps_game: RPSGame::new(), + rps_game: RPSGame::new(), bk_mods: mods_vec_u64, reddit_data: None.into(), discord_data: None.into(), @@ -102,7 +102,7 @@ async fn make_cmd_vec(data: &Data) -> Vec { cmds::send::cmd(), debug_cmds::main_cmd::cmd(), // DATABASE - db_cmds::main_cmd::cmd() + db_cmds::main_cmd::cmd() ]; let cfg = get_toml_mutex(&data.cfg).await.unwrap(); diff --git a/src/main.rs b/src/main.rs index d119a04..b409755 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,7 @@ mod cmds { pub mod embed; pub mod help; pub mod send; - pub mod wwrps; + pub mod wwrps; } mod re_cmds { pub mod add; @@ -33,8 +33,8 @@ mod debug_cmds { mod db_cmds { pub mod add_server; pub mod reddit_channel; - pub mod main_cmd; - pub mod wwrps_channel; + pub mod main_cmd; + pub mod wwrps_channel; } mod events; mod messages; @@ -97,7 +97,7 @@ type Cmd = Command>; struct Data { owners: Vec, ball_prompts: [Vec; 2], - rps_game: RPSGame, + rps_game: RPSGame, reddit_data: Mutex>, discord_data: Mutex>, cfg: Mutex>, From f3faa727c654f98effa2c943f8702f93fe4b34c3 Mon Sep 17 00:00:00 2001 From: ByteDice Date: Fri, 27 Feb 2026 16:52:28 +0100 Subject: [PATCH 5/6] fixed .gitignore --- .gitignore | 2 +- .vscode/settings.json | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index db58a6b..2e745ad 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ Cargo.lock **/*.rs.bk *.pdb **/__pycache__/ -.vscode/ +.vscode/* !.vscode/settings.json # program-created data diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..67d749a --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "editor.tabSize": 2, + "editor.insertSpaces": true, + "editor.detectIndentation": false +} \ No newline at end of file From 486a204f1d0018fdf15af3287d7fa1735a13b4a6 Mon Sep 17 00:00:00 2001 From: ByteDice Date: Fri, 27 Feb 2026 18:11:15 +0100 Subject: [PATCH 6/6] the basis for wwrps is done (may add ranks) --- data/defaults/cfg_default.toml | 6 +-- data/lang/en.json | 8 ++++ src/cmds/wwrps.rs | 68 +++++++++++++++++++++++++++++----- src/gen.rs | 4 +- src/main.rs | 2 +- 5 files changed, 73 insertions(+), 15 deletions(-) diff --git a/data/defaults/cfg_default.toml b/data/defaults/cfg_default.toml index ec5ee70..1b6dd08 100644 --- a/data/defaults/cfg_default.toml +++ b/data/defaults/cfg_default.toml @@ -34,9 +34,9 @@ add_post = ["weekly_art", "weekly"] # Disabled selected command categories. All commands and their categories can be viewed in the README. disabled_categories = [ # "fun", - # "help" - # "re" - # "debug" + # "help", + # "re", + # "debug", # "db" ] diff --git a/data/lang/en.json b/data/lang/en.json index 8f5bad2..cd384e4 100644 --- a/data/lang/en.json +++ b/data/lang/en.json @@ -58,6 +58,14 @@ "dc_msg_update_removing_old": "{0}Removing old posts (threshold: {1}d)...", "dc_msg_update_removing": "{0}Removing removed posts...", "dc_msg_whoami": "**Bot \"owner\":** {0}\n**BK moderator:** {1}", + "dc_msg_wwrps_already_submitted": "You can't compete against yourself! Please wait until another player has submitted their RPS.", + "dc_msg_wwrps_anon": "[Anonymous]", + "dc_msg_wwrps_draw": "DRAW", + "dc_msg_wwrps_fight": "### {0} (P1) vs {1} (P2)...\n## {2}\n**P1:** {3}\n**P2:** {4}", + "dc_msg_wwrps_not_in_data": "Could not find `wwrps_channel` in data!\nHint: Run `/database WWRPSChannel` in a channel (requires administrator permission).", + "dc_msg_wwrps_p1_win": "P1 WINS", + "dc_msg_wwrps_p2_win": "P2 WINS", + "dc_msg_wwrps_submitting": "Submitting your RPS... Please wait for another contestant to compete against you.", "log_lang_load_success": "Successfully loaded the english language file!", "none": "None", "py_re_response_suffix": "^(I am not an AI, I am just a bot. This action was performed automatically by the way. You can report bugs and view my source code [here](https://github.com/ByteDice/ByteDiceAssistant)!)", diff --git a/src/cmds/wwrps.rs b/src/cmds/wwrps.rs index cae1282..2a41707 100644 --- a/src/cmds/wwrps.rs +++ b/src/cmds/wwrps.rs @@ -1,9 +1,12 @@ -use poise::serenity_prelude::User; +use std::fmt::Display; -use crate::{Context, Error, data::get_mutex_data, lang, messages::send_msg}; +use poise::serenity_prelude::{ChannelId, Mentionable, User}; +use tokio::sync::MutexGuard; + +use crate::{Context, Error, data::get_mutex_data, lang, messages::{http_send_msg, send_msg}}; -#[derive(poise::ChoiceParameter, PartialEq, Clone)] +#[derive(poise::ChoiceParameter, PartialEq, Clone, Debug)] #[repr(u8)] pub enum RPS { Paper = 0, @@ -23,6 +26,17 @@ pub struct RPSGame { } +impl Display for RPS { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + return match self { + Self::Paper => write!(f, "Paper"), + Self::Rock => write!(f, "Rock"), + Self::Scissors => write!(f, "Scissors") + }; + } +} + + impl RPSGame { pub fn new() -> Self { return RPSGame { @@ -30,12 +44,13 @@ impl RPSGame { } } - pub fn add_player(&mut self, player: RPSPlayer) -> Result<(), Error> { + /// Returns wether the lobby is filled or not + pub fn add_player(&mut self, player: RPSPlayer) -> Result { if let Some(p1) = &self.players[0] { if p1.user == player.user { return Err(Error::from("Cannot add player, it already exists!")); }} - if self.players[0].is_none() { self.players[0] = Some(player); return Ok(()); } - else if self.players[1].is_none() { self.players[1] = Some(player); return Ok(()); } + if self.players[0].is_none() { self.players[0] = Some(player); return Ok(false); } + else if self.players[1].is_none() { self.players[1] = Some(player); return Ok(true); } else { return Err(Error::from("Cannot add player, list is full!")); } } @@ -81,15 +96,48 @@ pub async fn cmd( if c_o.is_none() { send_msg(ctx, lang!("dc_msg_wwrps_not_in_data"), true, true).await; return Ok(()); } let c = c_o.unwrap(); + + send_msg(ctx, lang!("dc_msg_wwrps_submitting"), true, true).await; + + let mut game = ctx.data().rps_game.lock().await; - let mut game = &ctx.data().rps_game; - - if !game.is_full_lobby() { game.add_player(RPSPlayer { selection, user: ctx.author().clone(), anonymous }); } + if !game.is_full_lobby() { + let r = game.add_player( + RPSPlayer { selection, user: ctx.author().clone(), anonymous }); + + if let Err(_) = r + { send_msg(ctx, lang!("dc_msg_wwrps_already_submitted"), true, true).await; return Ok(()); } + + let full = r.unwrap(); + if !full { return Ok(()); } + + let r_text = results_text(&game); + game.clear(); + + http_send_msg(ctx.http(), ChannelId::new(c), r_text).await; + } return Ok(()); } +fn results_text(game: &MutexGuard<'_, RPSGame>) -> String { + let winner = game.get_winner(); + let winner_text: String; + + if let Some(w) = winner + { winner_text = if w == 0 { lang!("dc_msg_wwrps_p1_win") } else { lang!("dc_msg_wwrps_p2_win") }; } + else { winner_text = lang!("dc_msg_wwrps_draw"); } + + let p1 = game.players[0].as_ref().unwrap(); + let p2 = game.players[1].as_ref().unwrap(); + let p1_n = if !p1.anonymous { p1.user.mention().to_string() } else { lang!("dc_msg_wwrps_anon") }; + let p2_n = if !p2.anonymous { p2.user.mention().to_string() } else { lang!("dc_msg_wwrps_anon") }; + + return lang!("dc_msg_wwrps_fight", p1.selection.clone(), p2.selection.clone(), winner_text, p1_n, p2_n); +} + + async fn get_wwrps_channel(ctx: Context<'_>) -> Option { let d = get_mutex_data(&ctx.data().discord_data).await.unwrap(); @@ -98,7 +146,7 @@ async fn get_wwrps_channel(ctx: Context<'_>) -> Option { if !is_guild { return Some(ctx.channel_id().get()); } let Some(servers) = d.get("servers") else { return None; }; - let Some(s) = servers.get(ctx.guild_id().unwrap().get() as usize) else { return None; }; + let Some(s) = servers.get(ctx.guild_id().unwrap().get().to_string()) else { return None; }; let Some(c_id) = s.get("wwrps_channel") else { return None; }; return Some(c_id.as_u64().unwrap()); diff --git a/src/gen.rs b/src/gen.rs index 311c45a..de34e51 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -3,6 +3,7 @@ use std::{collections::HashSet, process}; use poise::serenity_prelude::{ActivityData, UserId}; use poise::serenity_prelude as serenity; use poise::serenity_prelude::Client; +use tokio::sync::Mutex; use toml::Value; use crate::cmds::wwrps::RPSGame; @@ -27,7 +28,7 @@ pub async fn gen_data(args: Args, owners: Vec) -> Data { let data = Data { owners, ball_prompts: [ball_classic, ball_quirk], - rps_game: RPSGame::new(), + rps_game: Mutex::new(RPSGame::new()), bk_mods: mods_vec_u64, reddit_data: None.into(), discord_data: None.into(), @@ -88,6 +89,7 @@ async fn make_cmd_vec(data: &Data) -> Vec { // GENERIC cmds::help::cmd(), cmds::eight_ball::cmd(), + cmds::wwrps::cmd(), // REDDIT re_cmds::add::cmd(), re_cmds::approve::cmd(), diff --git a/src/main.rs b/src/main.rs index b409755..5512535 100644 --- a/src/main.rs +++ b/src/main.rs @@ -97,7 +97,7 @@ type Cmd = Command>; struct Data { owners: Vec, ball_prompts: [Vec; 2], - rps_game: RPSGame, + rps_game: Mutex, reddit_data: Mutex>, discord_data: Mutex>, cfg: Mutex>,