diff options
| author | mat <27899617+mat-1@users.noreply.github.com> | 2022-10-07 19:57:42 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-10-07 19:57:42 -0500 |
| commit | ba4cfaafaec97a3c5b9405fe542035ebe9039edd (patch) | |
| tree | 5fc7340a49f96d84f86ed6adf400ad461c47d1b6 /azalea/src/lib.rs | |
| parent | e0bcab53b8a3721a008e47062c6b5972fa64b8ad (diff) | |
| download | azalea-drasl-ba4cfaafaec97a3c5b9405fe542035ebe9039edd.tar.xz | |
Bot API (#27)
Basically make the `azalea` crate have stuff
Diffstat (limited to 'azalea/src/lib.rs')
| -rw-r--r-- | azalea/src/lib.rs | 82 |
1 files changed, 81 insertions, 1 deletions
diff --git a/azalea/src/lib.rs b/azalea/src/lib.rs index fe8a3740..8ef02e7c 100644 --- a/azalea/src/lib.rs +++ b/azalea/src/lib.rs @@ -1,4 +1,84 @@ mod bot; pub mod prelude; -pub use azalea_client::Client; +use async_trait::async_trait; +pub use azalea_client::*; +use azalea_protocol::ServerAddress; +use parking_lot::Mutex; +use std::{future::Future, sync::Arc}; +use thiserror::Error; + +/// Plugins can keep their own personal state, listen to events, and add new functions to Client. +#[async_trait] +pub trait Plugin: Send + Sync { + async fn handle(self: Arc<Self>, bot: Client, event: Arc<Event>); +} + +// pub type HeuristicFn<N, W> = fn(start: &Vertex<N, W>, current: &Vertex<N, W>) -> W; +pub type HandleFn<Fut, S> = fn(Client, Arc<Event>, Arc<Mutex<S>>) -> Fut; + +pub struct Options<S, A, Fut> +where + A: TryInto<ServerAddress>, + Fut: Future<Output = Result<(), anyhow::Error>>, +{ + pub address: A, + pub account: Account, + pub plugins: Vec<Arc<dyn Plugin>>, + pub state: Arc<Mutex<S>>, + pub handle: HandleFn<Fut, S>, +} + +#[derive(Error, Debug)] +pub enum Error { + #[error("Invalid address")] + InvalidAddress, +} + +/// Join a Minecraft server. +/// +/// ```no_run +/// azalea::start(azalea::Options { +/// account, +/// address: "localhost", +/// state: Arc::new(Mutex::new(State::default())), +/// plugins: vec![&autoeat::Plugin::default()], +/// handle: Box::new(handle), +/// }).await.unwrap(); +/// ``` +pub async fn start< + S: Send + 'static, + A: Send + TryInto<ServerAddress>, + Fut: Future<Output = Result<(), anyhow::Error>> + Send + 'static, +>( + options: Options<S, A, Fut>, +) -> Result<(), Error> { + let address = match options.address.try_into() { + Ok(address) => address, + Err(_) => return Err(Error::InvalidAddress), + }; + + let (bot, mut rx) = options.account.join(&address).await.unwrap(); + + let state = options.state; + let bot_plugin = Arc::new(bot::Plugin::default()); + + while let Some(event) = rx.recv().await { + // we put it into an Arc so it's cheaper to clone + let event = Arc::new(event); + + for plugin in &options.plugins { + tokio::spawn(plugin.clone().handle(bot.clone(), event.clone())); + } + + { + let bot_plugin = bot_plugin.clone(); + let bot = bot.clone(); + let event = event.clone(); + tokio::spawn(bot::Plugin::handle(bot_plugin, bot, event)); + }; + tokio::spawn((options.handle)(bot.clone(), event.clone(), state.clone())); + } + + Ok(()) +} |
