aboutsummaryrefslogtreecommitdiff
path: root/azalea/src
diff options
context:
space:
mode:
Diffstat (limited to 'azalea/src')
-rw-r--r--azalea/src/bot.rs19
-rw-r--r--azalea/src/lib.rs58
2 files changed, 52 insertions, 25 deletions
diff --git a/azalea/src/bot.rs b/azalea/src/bot.rs
index 26e35fda..566ab1e7 100644
--- a/azalea/src/bot.rs
+++ b/azalea/src/bot.rs
@@ -3,14 +3,14 @@ use async_trait::async_trait;
use parking_lot::Mutex;
use std::sync::Arc;
-#[derive(Default)]
+#[derive(Default, Clone)]
pub struct Plugin {
- pub state: Arc<Mutex<State>>,
+ pub state: State,
}
-#[derive(Default)]
+#[derive(Default, Clone)]
pub struct State {
- jumping_once: bool,
+ jumping_once: Arc<Mutex<bool>>,
}
pub trait BotTrait {
@@ -18,7 +18,7 @@ pub trait BotTrait {
}
impl BotTrait for azalea_client::Client {
- /// Try to jump next tick.
+ /// Queue a jump for the next tick.
fn jump(&self) {
let player_lock = self.player.lock();
let mut dimension_lock = self.dimension.lock();
@@ -33,12 +33,11 @@ impl BotTrait for azalea_client::Client {
#[async_trait]
impl crate::Plugin for Plugin {
- async fn handle(self: Arc<Self>, event: Arc<Event>, mut bot: Client) {
- if let Event::Tick = *event {
- let mut state = self.state.lock();
- if state.jumping_once {
+ async fn handle(self: Box<Self>, event: Event, mut bot: Client) {
+ if let Event::Tick = event {
+ if *self.state.jumping_once.lock() {
if bot.jumping() {
- state.jumping_once = false;
+ *self.state.jumping_once.lock() = false;
} else {
bot.set_jumping(true);
}
diff --git a/azalea/src/lib.rs b/azalea/src/lib.rs
index 19384761..6a000e6d 100644
--- a/azalea/src/lib.rs
+++ b/azalea/src/lib.rs
@@ -30,6 +30,7 @@
//! .unwrap();
//! }
//!
+//! #[derive(Default, Clone)]
//! pub struct State {}
//!
//! async fn handle(bot: Client, event: Arc<Event>, state: Arc<Mutex<State>>) -> anyhow::Result<()> {
@@ -52,17 +53,35 @@ pub mod prelude;
use async_trait::async_trait;
pub use azalea_client::*;
use azalea_protocol::ServerAddress;
-use parking_lot::Mutex;
-use std::{future::Future, sync::Arc};
+use std::future::Future;
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>, event: Arc<Event>, bot: Client);
+pub trait Plugin: Send + Sync + PluginClone + 'static {
+ async fn handle(self: Box<Self>, event: Event, bot: Client);
}
-pub type HandleFn<Fut, S> = fn(Client, Arc<Event>, Arc<Mutex<S>>) -> Fut;
+/// An internal trait that allows Plugin to be cloned.
+#[doc(hidden)]
+pub trait PluginClone {
+ fn clone_box(&self) -> Box<dyn Plugin>;
+}
+impl<T> PluginClone for T
+where
+ T: 'static + Plugin + Clone,
+{
+ fn clone_box(&self) -> Box<dyn Plugin> {
+ Box::new(self.clone())
+ }
+}
+impl Clone for Box<dyn Plugin> {
+ fn clone(&self) -> Self {
+ self.clone_box()
+ }
+}
+
+pub type HandleFn<Fut, S> = fn(Client, Event, S) -> Fut;
/// The options that are passed to [`azalea::start`].
///
@@ -80,10 +99,22 @@ where
pub account: Account,
/// A list of plugins that are going to be used. Plugins are external
/// crates that add extra functionality to Azalea.
- pub plugins: Vec<Arc<dyn Plugin>>,
+ pub plugins: Vec<Box<dyn Plugin>>,
/// A struct that contains the data that you want your bot to remember
/// across events.
- pub state: Arc<Mutex<S>>,
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use parking_lot::Mutex;
+ /// use std::sync::Arc;
+ ///
+ /// #[derive(Default, Clone)]
+ /// struct State {
+ /// farming: Arc<Mutex<bool>>,
+ /// }
+ /// ```
+ pub state: S,
/// The function that's called whenever we get an event.
pub handle: HandleFn<Fut, S>,
}
@@ -107,7 +138,7 @@ pub enum Error {
/// }).await.unwrap();
/// ```
pub async fn start<
- S: Send + 'static,
+ S: Send + Sync + Clone + 'static,
A: Send + TryInto<ServerAddress>,
Fut: Future<Output = Result<(), anyhow::Error>> + Send + 'static,
>(
@@ -121,19 +152,16 @@ pub async fn start<
let (bot, mut rx) = Client::join(&options.account, address).await.unwrap();
let state = options.state;
- let bot_plugin = Arc::new(bot::Plugin::default());
+ let bot_plugin = 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(event.clone(), bot.clone()));
+ let plugin = plugin.clone();
+ tokio::spawn(plugin.handle(event.clone(), bot.clone()));
}
tokio::spawn(bot::Plugin::handle(
- bot_plugin.clone(),
+ Box::new(bot_plugin.clone()),
event.clone(),
bot.clone(),
));