uno YAAAY
This commit is contained in:
parent
803289d754
commit
0778aaab3d
6 changed files with 562 additions and 20 deletions
|
@ -6,5 +6,6 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
rand = "0.9.0-alpha.1"
|
||||
twitch-irc = "5.0.1"
|
||||
tokio = { version = "1.33.0", features = ["full"] }
|
||||
|
|
37
src/bot.rs
37
src/bot.rs
|
@ -32,6 +32,21 @@ pub struct Bot<'a, P> {
|
|||
impl<'a, P> Bot<'a, P>
|
||||
where P: Send + 'static
|
||||
{
|
||||
/// Creates a `Bot` instance using the given username and oauth-token.
|
||||
/// `payload` can be any type and will be wrapped to `Arc<Mutex<P>>` and passed to any command executed,
|
||||
/// where the user can access the contents mutable.
|
||||
pub fn new<'b>(username: &'b str, oauth_token: &'b str, payload: P) -> Bot<'a, P>
|
||||
where
|
||||
'b : 'a
|
||||
{
|
||||
Bot {
|
||||
username,
|
||||
oauth_token,
|
||||
payload: Arc::new(StdMutex::new(payload)),
|
||||
commands: Arc::new(Mutex::new(HashMap::new())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a message stream and a client wrapped in `Arc<Mutex<...>>`
|
||||
fn incoming_messages_and_client(&self) -> (IncomingMessages, ClientAM) {
|
||||
let login = self.username.to_owned();
|
||||
|
@ -48,21 +63,6 @@ impl<'a, P> Bot<'a, P>
|
|||
return (incoming_messages, client_am);
|
||||
}
|
||||
|
||||
/// Creates a `Bot` instance using the given username and oauth-token.
|
||||
/// `payload` can be any type and will be wrapped to `Arc<Mutex<P>>` and passed to any command executed,
|
||||
/// where the user can access the contents mutable.
|
||||
pub fn new<'b>(username: &'b str, oauth_token: &'b str, payload: P) -> Bot<'a, P>
|
||||
where
|
||||
'b : 'a
|
||||
{
|
||||
Bot {
|
||||
username,
|
||||
oauth_token,
|
||||
payload: Arc::new(StdMutex::new(payload)),
|
||||
commands: Arc::new(Mutex::new(HashMap::new())),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn add_command(&mut self, identifier: String, command: Box<dyn Command<CommandPayLoad=P>>) {
|
||||
let mut commands = self.commands.lock().await;
|
||||
commands.insert(identifier, command);
|
||||
|
@ -73,7 +73,7 @@ impl<'a, P> Bot<'a, P>
|
|||
let (mut incoming_messages, client_am) = self.incoming_messages_and_client();
|
||||
let commands = Arc::clone(&self.commands);
|
||||
let payload = Arc::clone(&self.payload);
|
||||
let initial_channel = self.username.to_owned();
|
||||
let initial_channel = "daph".to_string();
|
||||
|
||||
let msg_processor = tokio::spawn(async move {
|
||||
{
|
||||
|
@ -95,7 +95,10 @@ impl<'a, P> Bot<'a, P>
|
|||
ServerMessage::Pong(_) => {}
|
||||
ServerMessage::Privmsg(msg) => {
|
||||
let mut cmd = commands.lock().await;
|
||||
if let Some(command) = cmd.get_mut(&msg.message_text) {
|
||||
|
||||
let args: Vec<String> = msg.message_text.split(' ').map(|s| s.to_string()).collect();
|
||||
|
||||
if let Some(command) = cmd.get_mut(args.get(0).unwrap()) {
|
||||
let mut queue = command.execute(Arc::clone(&payload), msg);
|
||||
queue.execute(Arc::clone(&client_am)).await;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,10 @@ pub trait Command: Send {
|
|||
type CommandPayLoad;
|
||||
|
||||
fn execute(&self, pl_am: Arc<StdMutex<Self::CommandPayLoad>>, ctx: PrivmsgMessage) -> ClientQueue;
|
||||
fn help(&self) -> String;
|
||||
fn info(&self) -> String;
|
||||
fn help(&self) -> String {
|
||||
"help".to_string()
|
||||
}
|
||||
fn info(&self) -> String {
|
||||
"info".to_string()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,8 @@ impl Command for PingCommand {
|
|||
let mut queue = ClientQueue::new();
|
||||
|
||||
let pl = pl_am.lock().unwrap();
|
||||
queue.say("mzntori".to_string(), format!("Pong! {} {}", pl.content, ctx.sender.name));
|
||||
queue.say(ctx.channel_login.to_owned(), format!("Pong! {} {}", pl.content, ctx.sender.name));
|
||||
queue.say("gaygebot".to_string(), format!("Ponged in {}", ctx.channel_login));
|
||||
println!("Pong executed! {}", pl.content);
|
||||
|
||||
queue
|
||||
|
|
277
tests/uno.rs
Normal file
277
tests/uno.rs
Normal file
|
@ -0,0 +1,277 @@
|
|||
use rand::prelude::*;
|
||||
|
||||
|
||||
use std::fmt::{Display, Formatter, write};
|
||||
use std::mem;
|
||||
use crate::uno::UnoState::NotStarted;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Color {
|
||||
Wild,
|
||||
Blue,
|
||||
Green,
|
||||
Red,
|
||||
Yellow,
|
||||
}
|
||||
|
||||
|
||||
impl Display for Color {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Color::Wild => { write!(f, "Wild") }
|
||||
Color::Blue => { write!(f, "Blue") }
|
||||
Color::Green => { write!(f, "Green") }
|
||||
Color::Red => { write!(f, "Red") }
|
||||
Color::Yellow => { write!(f, "Yellow") }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Type {
|
||||
Number(usize),
|
||||
DrawTwo,
|
||||
DrawFour,
|
||||
ChooseColor,
|
||||
Reverse,
|
||||
Skip,
|
||||
}
|
||||
|
||||
|
||||
impl Display for Type {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Type::Number(n) => { write!(f, "{}", n) }
|
||||
Type::DrawTwo => { write!(f, "+2") }
|
||||
Type::DrawFour => { write!(f, "+4") }
|
||||
Type::ChooseColor => { write!(f, "Choose Color") }
|
||||
Type::Reverse => { write!(f, "Reverse") }
|
||||
Type::Skip => { write!(f, "Skip") }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct UnoCard {
|
||||
typ: Type,
|
||||
col: Color,
|
||||
}
|
||||
|
||||
|
||||
impl UnoCard {
|
||||
pub fn new(typ: Type, col: Color) -> UnoCard {
|
||||
UnoCard { typ, col }
|
||||
}
|
||||
|
||||
pub fn can_stack(&self, other: &UnoCard) -> bool {
|
||||
return if self.typ == other.typ || self.col == other.col || self.col == Color::Wild || other.col == Color::Wild {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for UnoCard {
|
||||
fn default() -> Self {
|
||||
UnoCard::new(Type::Number(0), Color::Wild)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for UnoCard {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{} {}", self.col, self.typ)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UnoPlayer {
|
||||
pub name: String,
|
||||
pub hand: Vec<UnoCard>,
|
||||
}
|
||||
|
||||
|
||||
impl UnoPlayer {
|
||||
pub fn new(name: String) -> Self {
|
||||
UnoPlayer { name, hand: vec![] }
|
||||
}
|
||||
|
||||
pub fn take_hand(&mut self) -> Vec<UnoCard> {
|
||||
mem::take(&mut self.hand)
|
||||
}
|
||||
|
||||
pub fn give_hand(&mut self, hand: Vec<UnoCard>) {
|
||||
self.hand = hand;
|
||||
}
|
||||
|
||||
pub fn take_card(&mut self, idx: usize) -> UnoCard {
|
||||
let mut hand = self.take_hand();
|
||||
let result = hand.remove(idx);
|
||||
self.give_hand(hand);
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum UnoState {
|
||||
NotStarted,
|
||||
Started,
|
||||
Ended,
|
||||
}
|
||||
|
||||
|
||||
fn new_uno_stack() -> Vec<UnoCard> {
|
||||
let mut deck: Vec<UnoCard> = vec![];
|
||||
|
||||
for col in [Color::Blue, Color::Red, Color::Green, Color::Yellow] {
|
||||
deck.push(UnoCard::new(Type::Number(0), col));
|
||||
|
||||
for n in 1..=9 {
|
||||
deck.push(UnoCard::new(Type::Number(n), col));
|
||||
deck.push(UnoCard::new(Type::Number(n), col));
|
||||
}
|
||||
|
||||
for typ in [Type::Reverse, Type::Skip, Type::DrawTwo] {
|
||||
deck.push(UnoCard::new(typ, col));
|
||||
}
|
||||
|
||||
for _ in 0..4 {
|
||||
deck.push(UnoCard::new(Type::DrawFour, Color::Wild));
|
||||
deck.push(UnoCard::new(Type::ChooseColor, Color::Wild));
|
||||
}
|
||||
}
|
||||
|
||||
deck
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Uno {
|
||||
card_stack: Vec<UnoCard>,
|
||||
pub players: Vec<UnoPlayer>,
|
||||
pub admin: String,
|
||||
pub active_player: usize,
|
||||
pub direction: i32,
|
||||
pub draw_amount: u32,
|
||||
pub state: UnoState,
|
||||
pub top: UnoCard,
|
||||
}
|
||||
|
||||
impl Uno {
|
||||
pub fn new(admin: String) -> Self {
|
||||
Uno {
|
||||
card_stack: new_uno_stack(),
|
||||
players: vec![],
|
||||
admin,
|
||||
active_player: 0,
|
||||
direction: 1,
|
||||
draw_amount: 0,
|
||||
state: UnoState::Ended,
|
||||
top: UnoCard::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw(&mut self) -> UnoCard {
|
||||
self.card_stack.pop().unwrap()
|
||||
}
|
||||
|
||||
pub fn end(&mut self) {
|
||||
self.state = UnoState::Ended;
|
||||
}
|
||||
|
||||
pub fn init(&mut self) {
|
||||
self.state = UnoState::Started;
|
||||
self.shuffle();
|
||||
|
||||
let mut card_buf: Vec<UnoCard> = vec![];
|
||||
|
||||
for _ in 0..(7 * self.players.len()) {
|
||||
card_buf.push(self.draw());
|
||||
}
|
||||
|
||||
for player in self.players.iter_mut() {
|
||||
for _ in 0..7 {
|
||||
player.hand.push(card_buf.pop().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
self.top = self.draw();
|
||||
}
|
||||
|
||||
pub fn join(&mut self, name: String) {
|
||||
if self.state == UnoState::NotStarted {
|
||||
self.players.push(UnoPlayer::new(name));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn kick(&mut self, name: String) {
|
||||
let mut kick_idx: usize = usize::MAX;
|
||||
|
||||
for (i, p) in self.players.iter_mut().enumerate() {
|
||||
if p.name == name {
|
||||
let mut hand = p.take_hand();
|
||||
self.card_stack.append(&mut hand);
|
||||
kick_idx = i;
|
||||
|
||||
if i < self.active_player {
|
||||
self.active_player -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if kick_idx < self.players.len() {
|
||||
self.players.remove(kick_idx);
|
||||
}
|
||||
self.shuffle();
|
||||
}
|
||||
|
||||
pub fn next_player(&mut self) {
|
||||
let mult: i32 = match self.top.typ {
|
||||
Type::Skip => { 2 }
|
||||
_ => { 1 }
|
||||
};
|
||||
|
||||
self.active_player = (self.active_player + self.players.len() + (self.direction * mult) as usize) % self.players.len();
|
||||
}
|
||||
|
||||
pub fn place(&mut self, card: UnoCard) {
|
||||
self.card_stack.push(mem::take(&mut self.top));
|
||||
self.top = card;
|
||||
self.shuffle();
|
||||
|
||||
match self.top.typ {
|
||||
Type::Number(_) => { self.draw_amount = 0; }
|
||||
Type::DrawTwo => { self.draw_amount += 2; }
|
||||
Type::DrawFour => { self.draw_amount += 4; }
|
||||
Type::ChooseColor => { self.draw_amount = 0; }
|
||||
Type::Reverse => {
|
||||
self.direction *= -1;
|
||||
self.draw_amount = 0;
|
||||
}
|
||||
Type::Skip => { self.draw_amount = 0; }
|
||||
}
|
||||
|
||||
self.next_player();
|
||||
}
|
||||
|
||||
pub fn shuffle(&mut self) {
|
||||
let mut rng = thread_rng();
|
||||
self.card_stack.shuffle(&mut rng);
|
||||
}
|
||||
|
||||
pub fn reset(&mut self, admin: String) {
|
||||
self.admin = admin;
|
||||
self.players = vec![];
|
||||
self.card_stack = new_uno_stack();
|
||||
self.active_player = 0;
|
||||
self.direction = 1;
|
||||
self.draw_amount = 0;
|
||||
self.state = NotStarted;
|
||||
self.top = UnoCard::default();
|
||||
}
|
||||
}
|
||||
|
256
tests/uno_test.rs
Normal file
256
tests/uno_test.rs
Normal file
|
@ -0,0 +1,256 @@
|
|||
pub mod uno;
|
||||
|
||||
use std::sync::{Arc, Mutex as StdMutex};
|
||||
use twitch_irc::message::PrivmsgMessage;
|
||||
|
||||
use twitchbot_rs::{Bot, ClientQueue, Command, Context};
|
||||
use crate::uno::{Uno, UnoPlayer, UnoState};
|
||||
use crate::uno::UnoState::Ended;
|
||||
|
||||
|
||||
pub struct PingCommand;
|
||||
|
||||
impl Command for PingCommand {
|
||||
type CommandPayLoad = Uno;
|
||||
|
||||
fn execute(&self, pl_am: Arc<StdMutex<Self::CommandPayLoad>>, ctx: Context) -> ClientQueue {
|
||||
let mut queue = ClientQueue::new();
|
||||
|
||||
let pl = pl_am.lock().unwrap();
|
||||
queue.say(ctx.channel_login.to_owned(), format!("@{} Pong!", ctx.sender.name));
|
||||
|
||||
queue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct UnoCommand;
|
||||
|
||||
impl Command for UnoCommand {
|
||||
type CommandPayLoad = Uno;
|
||||
|
||||
fn execute(&self, pl_am: Arc<StdMutex<Self::CommandPayLoad>>, ctx: PrivmsgMessage) -> ClientQueue {
|
||||
let mut queue = ClientQueue::new();
|
||||
|
||||
let mut pl = pl_am.lock().unwrap();
|
||||
if pl.state == Ended {
|
||||
pl.reset(ctx.sender.name.clone());
|
||||
queue.me(ctx.channel_login, format!("{} started a new uno game, type !join to join.", ctx.sender.name));
|
||||
} else {
|
||||
queue.me(ctx.channel_login, "Another game going on rn".to_string());
|
||||
}
|
||||
|
||||
queue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct DrawCommand;
|
||||
|
||||
impl Command for DrawCommand {
|
||||
type CommandPayLoad = Uno;
|
||||
|
||||
fn execute(&self, pl_am: Arc<StdMutex<Self::CommandPayLoad>>, ctx: PrivmsgMessage) -> ClientQueue {
|
||||
let mut queue = ClientQueue::new();
|
||||
let args: Vec<String> = ctx.message_text.split(' ').map(|s| s.to_string()).collect();
|
||||
|
||||
let mut pl = pl_am.lock().unwrap();
|
||||
|
||||
let idx = pl.active_player;
|
||||
if pl.players.get_mut(idx).unwrap().name == ctx.sender.name && args.len() > 1 {
|
||||
let amount = args
|
||||
.get(1)
|
||||
.unwrap()
|
||||
.parse::<u32>()
|
||||
.unwrap_or(0);
|
||||
|
||||
for _ in 0..amount {
|
||||
let card = pl.draw();
|
||||
pl.players.get_mut(idx).unwrap().hand.push(card);
|
||||
}
|
||||
|
||||
queue.me(ctx.channel_login, format!("{} drew {} cards.", ctx.sender.name, amount));
|
||||
} else {
|
||||
queue.me(ctx.channel_login, "Sender probably not active player.".to_string())
|
||||
}
|
||||
|
||||
queue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct PlaceCommand;
|
||||
|
||||
impl Command for PlaceCommand {
|
||||
type CommandPayLoad = Uno;
|
||||
|
||||
fn execute(&self, pl_am: Arc<StdMutex<Self::CommandPayLoad>>, ctx: PrivmsgMessage) -> ClientQueue {
|
||||
let mut queue = ClientQueue::new();
|
||||
let args: Vec<String> = ctx.message_text.split(' ').map(|s| s.to_string()).collect();
|
||||
|
||||
let mut pl = pl_am.lock().unwrap();
|
||||
|
||||
let idx = pl.active_player;
|
||||
if pl.players.get_mut(idx).unwrap().name == ctx.sender.name && args.len() > 1 {
|
||||
let hand_idx = args
|
||||
.get(1)
|
||||
.unwrap()
|
||||
.parse::<usize>()
|
||||
.unwrap_or(0);
|
||||
|
||||
if hand_idx < pl.players.get_mut(idx).unwrap().hand.len() {
|
||||
let card = pl.players.get_mut(idx).unwrap().take_card(hand_idx);
|
||||
|
||||
if card.can_stack(&pl.top) {
|
||||
queue.me(ctx.channel_login, format!("{} placed {}", pl.players.get_mut(idx).unwrap().name, &card));
|
||||
pl.place(card);
|
||||
} else {
|
||||
queue.me(ctx.channel_login, "Cant stack on that card.".to_string())
|
||||
}
|
||||
|
||||
} else {
|
||||
queue.me(ctx.channel_login, "Hand index out of range".to_string());
|
||||
}
|
||||
} else {
|
||||
queue.me(ctx.channel_login, "Sender probably not active player.".to_string())
|
||||
}
|
||||
|
||||
queue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct JoinCommand;
|
||||
|
||||
impl Command for JoinCommand {
|
||||
type CommandPayLoad = Uno;
|
||||
|
||||
fn execute(&self, pl_am: Arc<StdMutex<Self::CommandPayLoad>>, ctx: PrivmsgMessage) -> ClientQueue {
|
||||
let mut queue = ClientQueue::new();
|
||||
|
||||
let mut pl = pl_am.lock().unwrap();
|
||||
|
||||
if pl.state == UnoState::NotStarted {
|
||||
pl.players.push(UnoPlayer::new(ctx.sender.name.clone()));
|
||||
queue.me(ctx.channel_login, format!("{} Joined the game.", ctx.sender.name));
|
||||
}
|
||||
|
||||
queue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct StartCommand;
|
||||
|
||||
impl Command for StartCommand {
|
||||
type CommandPayLoad = Uno;
|
||||
|
||||
fn execute(&self, pl_am: Arc<StdMutex<Self::CommandPayLoad>>, ctx: PrivmsgMessage) -> ClientQueue {
|
||||
let mut queue = ClientQueue::new();
|
||||
|
||||
let mut pl = pl_am.lock().unwrap();
|
||||
if pl.admin == ctx.sender.name {
|
||||
pl.init();
|
||||
queue.me(ctx.channel_login, "Game started!".to_string());
|
||||
}
|
||||
|
||||
queue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct EndCommand;
|
||||
|
||||
impl Command for EndCommand {
|
||||
type CommandPayLoad = Uno;
|
||||
|
||||
fn execute(&self, pl_am: Arc<StdMutex<Self::CommandPayLoad>>, ctx: PrivmsgMessage) -> ClientQueue {
|
||||
let mut queue = ClientQueue::new();
|
||||
|
||||
let mut pl = pl_am.lock().unwrap();
|
||||
if pl.admin == ctx.sender.name {
|
||||
pl.end();
|
||||
queue.me(ctx.channel_login, "Game ended!".to_string());
|
||||
}
|
||||
|
||||
queue
|
||||
}
|
||||
}
|
||||
|
||||
pub struct HandCommand;
|
||||
|
||||
impl Command for HandCommand {
|
||||
type CommandPayLoad = Uno;
|
||||
|
||||
fn execute(&self, pl_am: Arc<StdMutex<Self::CommandPayLoad>>, ctx: PrivmsgMessage) -> ClientQueue {
|
||||
let mut queue = ClientQueue::new();
|
||||
let args: Vec<String> = ctx.message_text.split(' ').map(|s| s.to_string()).collect();
|
||||
|
||||
let mut pl = pl_am.lock().unwrap();
|
||||
|
||||
let mut index = usize::MAX;
|
||||
|
||||
for (i, player) in pl.players.iter().enumerate() {
|
||||
if player.name == ctx.sender.name {
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
let mut card_list = String::new();
|
||||
for card in pl.players.get(index).unwrap().hand.iter().enumerate() {
|
||||
card_list.push_str(format!("{}: {}, ", card.0, card.1).as_str());
|
||||
}
|
||||
|
||||
let channel: String = if ctx.sender.name == "daph" {
|
||||
"daphbot".to_string()
|
||||
} else {
|
||||
ctx.sender.name
|
||||
};
|
||||
|
||||
queue.say(channel, card_list);
|
||||
|
||||
queue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct TopCommand;
|
||||
|
||||
impl Command for TopCommand {
|
||||
type CommandPayLoad = Uno;
|
||||
|
||||
fn execute(&self, pl_am: Arc<StdMutex<Self::CommandPayLoad>>, ctx: PrivmsgMessage) -> ClientQueue {
|
||||
let mut queue = ClientQueue::new();
|
||||
|
||||
let mut pl = pl_am.lock().unwrap();
|
||||
|
||||
queue.me(ctx.channel_login, format!("Top: {}", &pl.top));
|
||||
|
||||
queue
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn main() {
|
||||
let mut u = Uno::new("mzntori".to_string());
|
||||
|
||||
let login = std::env::var("LOGIN").unwrap();
|
||||
let oauth = std::env::var("OAUTH").unwrap();
|
||||
let mut bot = Bot::new(
|
||||
login.as_str(),
|
||||
oauth.as_str(),
|
||||
u,
|
||||
);
|
||||
|
||||
bot.add_command("!ping".to_owned(), Box::new(PingCommand {})).await;
|
||||
bot.add_command("!uno".to_owned(), Box::new(UnoCommand {})).await;
|
||||
bot.add_command("!join".to_owned(), Box::new(JoinCommand {})).await;
|
||||
bot.add_command("!draw".to_owned(), Box::new(DrawCommand {})).await;
|
||||
bot.add_command("!start".to_owned(), Box::new(StartCommand {})).await;
|
||||
bot.add_command("!end".to_owned(), Box::new(EndCommand {})).await;
|
||||
bot.add_command("!place".to_owned(), Box::new(PlaceCommand {})).await;
|
||||
bot.add_command("!hand".to_owned(), Box::new(HandCommand {})).await;
|
||||
bot.add_command("!top".to_owned(), Box::new(TopCommand {})).await;
|
||||
|
||||
bot.run().await;
|
||||
}
|
Loading…
Reference in a new issue