aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormat <github@matdoes.dev>2022-10-23 16:51:49 -0500
committermat <github@matdoes.dev>2022-10-23 16:51:49 -0500
commit2eade86cf7a12a6ec64496aedbfc3d3a3bd44e1a (patch)
treec010d3f02beaec29741b723a1bc6e7eaad59e193
parenta9ff79a10553026b0fa32f0e31f1e0442467ca78 (diff)
downloadazalea-drasl-2eade86cf7a12a6ec64496aedbfc3d3a3bd44e1a.tar.xz
make `handle` cleaner
Arc<Event> -> Event, Arc<Mutex<State>> -> State Items in State now need to have interior mutability (i.e. Arc<Mutex<T>>), but it's a worthwhile tradeoff since it allows the user to customize it for each field
-rw-r--r--azalea-client/src/chat.rs2
-rw-r--r--azalea/examples/craft_dig_straight_down.rs16
-rw-r--r--azalea/examples/echo.rs13
-rw-r--r--azalea/examples/mine_a_chunk.rs43
-rw-r--r--azalea/examples/potatobot/autoeat.rs8
-rw-r--r--azalea/examples/potatobot/main.rs12
-rw-r--r--azalea/examples/pvp.rs18
-rw-r--r--azalea/src/bot.rs19
-rw-r--r--azalea/src/lib.rs58
-rw-r--r--bot/src/main.rs10
10 files changed, 114 insertions, 85 deletions
diff --git a/azalea-client/src/chat.rs b/azalea-client/src/chat.rs
index 9e3d58a0..fecd76ae 100644
--- a/azalea-client/src/chat.rs
+++ b/azalea-client/src/chat.rs
@@ -83,7 +83,7 @@ impl Client {
/// # }
/// ```
pub async fn chat(&self, message: &str) -> Result<(), std::io::Error> {
- if message.chars().next() == Some('/') {
+ if message.starts_with('/') {
self.send_command_packet(&message[1..]).await
} else {
self.send_chat_packet(message).await
diff --git a/azalea/examples/craft_dig_straight_down.rs b/azalea/examples/craft_dig_straight_down.rs
index 48e1fd22..9e675f28 100644
--- a/azalea/examples/craft_dig_straight_down.rs
+++ b/azalea/examples/craft_dig_straight_down.rs
@@ -3,9 +3,9 @@ use azalea::{Bot, Client, Event};
use parking_lot::Mutex;
use std::sync::Arc;
-#[derive(Default)]
+#[derive(Default, Clone)]
struct State {
- pub started: bool,
+ pub started: Arc<Mutex<bool>>,
}
#[tokio::main]
@@ -16,7 +16,7 @@ async fn main() {
azalea::start(azalea::Options {
account,
address: "localhost",
- state: Arc::new(Mutex::new(State::default())),
+ state: State::default(),
plugins: vec![],
handle,
})
@@ -24,13 +24,13 @@ async fn main() {
.unwrap();
}
-async fn handle(bot: Client, event: Arc<Event>, state: Arc<Mutex<State>>) {
+async fn handle(bot: Client, event: Event, state: State) -> anyhow::Result<()> {
match event {
- Event::Message(m) => {
+ Event::Chat(m) => {
if m.username == bot.player.username {
- return;
+ return Ok(());
};
- if m.message = "go" {
+ if m.content == "go" {
// make sure we only start once
let ctx_lock = ctx.lock().unwrap();
if ctx_lock.started {
@@ -74,4 +74,6 @@ async fn handle(bot: Client, event: Arc<Event>, state: Arc<Mutex<State>>) {
}
_ => {}
}
+
+ Ok(())
}
diff --git a/azalea/examples/echo.rs b/azalea/examples/echo.rs
index a5280d8b..07dd50c1 100644
--- a/azalea/examples/echo.rs
+++ b/azalea/examples/echo.rs
@@ -12,7 +12,7 @@ async fn main() {
azalea::start(azalea::Options {
account,
address: "localhost",
- state: Arc::new(Mutex::new(State::default())),
+ state: State::default(),
plugins: vec![],
handle,
})
@@ -20,19 +20,16 @@ async fn main() {
.unwrap();
}
+#[derive(Default, Clone)]
pub struct State {}
-async fn handle(bot: Client, event: Arc<Event>, state: Arc<Mutex<State>>) -> anyhow::Result<()> {
- match *event {
+async fn handle(bot: Client, event: Event, state: State) -> anyhow::Result<()> {
+ match event {
Event::Chat(m) => {
if m.username == bot.username {
return Ok(()); // ignore our own messages
};
- bot.chat(m.message).await;
- }
- Event::Kick(m) => {
- println!(m);
- bot.reconnect().await.unwrap();
+ bot.chat(m.content).await;
}
_ => {}
}
diff --git a/azalea/examples/mine_a_chunk.rs b/azalea/examples/mine_a_chunk.rs
index bc576513..5f1dabe1 100644
--- a/azalea/examples/mine_a_chunk.rs
+++ b/azalea/examples/mine_a_chunk.rs
@@ -1,4 +1,4 @@
-use azalea::{pathfinder, Account, Accounts, Client, Event};
+use azalea::{pathfinder, Account, Accounts, Client, Event, Swarm};
use parking_lot::Mutex;
use std::sync::Arc;
@@ -7,31 +7,31 @@ async fn main() {
let accounts = Accounts::new();
for i in 0..10 {
- accounts.add(Account::offline(format!("bot{}", i)));
+ accounts.add(Account::offline(&format!("bot{}", i)));
}
- azalea::start_group(azalea::GroupOptions {
+ azalea::start_swarm(azalea::SwarmOptions {
accounts,
address: "localhost",
- group_state: Arc::new(Mutex::new(State::default())),
+ swarm_state: Arc::new(Mutex::new(State::default())),
state: State::default(),
- group_plugins: vec![Arc::new(pathfinder::Plugin::default())],
+ swarm_plugins: vec![Arc::new(pathfinder::Plugin::default())],
plugins: vec![],
handle: Box::new(handle),
- group_handle: Box::new(handle),
+ swarm_handle: Box::new(swarm_handle),
})
.await
.unwrap();
}
-#[derive(Default)]
+#[derive(Default, Clone)]
struct State {}
-#[derive(Default)]
-struct GroupState {}
+#[derive(Default, Clone)]
+struct SwarmState {}
async fn handle(bot: Client, event: Arc<Event>, state: Arc<Mutex<State>>) -> anyhow::Result<()> {
match event {
@@ -41,26 +41,27 @@ async fn handle(bot: Client, event: Arc<Event>, state: Arc<Mutex<State>>) -> any
Ok(())
}
-async fn group_handle(
- bots: Swarm,
+async fn swarm_handle(
+ swarm: Swarm,
event: Arc<Event>,
- state: Arc<Mutex<GroupState>>,
+ state: Arc<Mutex<SwarmState>>,
) -> anyhow::Result<()> {
match *event {
Event::Login => {
- bots.goto(azalea::BlockPos::new(0, 70, 0)).await;
+ swarm.goto(azalea::BlockPos::new(0, 70, 0)).await;
// or bots.goto_goal(pathfinder::Goals::Goto(azalea::BlockPos(0, 70, 0))).await;
// destroy the blocks in this area and then leave
- bots.fill(
- azalea::Selection::Range(
- azalea::BlockPos::new(0, 0, 0),
- azalea::BlockPos::new(16, 255, 16),
- ),
- azalea::block::Air,
- )
- .await;
+ swarm
+ .fill(
+ azalea::Selection::Range(
+ azalea::BlockPos::new(0, 0, 0),
+ azalea::BlockPos::new(16, 255, 16),
+ ),
+ azalea::block::Air,
+ )
+ .await;
}
_ => {}
}
diff --git a/azalea/examples/potatobot/autoeat.rs b/azalea/examples/potatobot/autoeat.rs
index d1296c29..8042e2a2 100644
--- a/azalea/examples/potatobot/autoeat.rs
+++ b/azalea/examples/potatobot/autoeat.rs
@@ -4,17 +4,17 @@ use async_trait::async_trait;
use azalea::{Client, Event};
use std::sync::{Arc, Mutex};
-#[derive(Default)]
+#[derive(Default, Clone)]
pub struct Plugin {
- pub state: Arc<Mutex<State>>,
+ pub state: State,
}
-#[derive(Default)]
+#[derive(Default, Clone)]
pub struct State {}
#[async_trait]
impl azalea::Plugin for Plugin {
- async fn handle(self: Arc<Self>, bot: Client, event: Arc<Event>) {
+ async fn handle(self: Box<Self>, event: Event, bot: Client) {
match event {
Event::UpdateHunger => {
if !bot.using_held_item() && bot.food_level() <= 17 {
diff --git a/azalea/examples/potatobot/main.rs b/azalea/examples/potatobot/main.rs
index a04b199d..5398c68a 100644
--- a/azalea/examples/potatobot/main.rs
+++ b/azalea/examples/potatobot/main.rs
@@ -17,10 +17,10 @@ async fn main() {
azalea::start(azalea::Options {
account,
address: "localhost",
- state: Arc::new(Mutex::new(State::default())),
+ state: State::default(),
plugins: vec![
- Arc::new(autoeat::Plugin::default()),
- Arc::new(pathfinder::Plugin::default()),
+ Box::new(autoeat::Plugin::default()),
+ Box::new(pathfinder::Plugin::default()),
],
handle,
})
@@ -28,7 +28,7 @@ async fn main() {
.unwrap();
}
-async fn handle(bot: Client, event: Arc<Event>, state: Arc<Mutex<State>>) -> anyhow::Result<()> {
+async fn handle(bot: Client, event: Event, state: State) -> anyhow::Result<()> {
match event {
Event::Login => {
goto_farm(bot, state).await?;
@@ -42,14 +42,14 @@ async fn handle(bot: Client, event: Arc<Event>, state: Arc<Mutex<State>>) -> any
}
// go to the place where we start farming
-async fn goto_farm(bot: Client, state: Arc<Mutex<State>>) -> anyhow::Result<()> {
+async fn goto_farm(bot: Client, state: State) -> anyhow::Result<()> {
bot.goto(pathfinder::Goals::Near(5, BlockPos::new(0, 70, 0)))
.await?;
Ok(())
}
// go to the chest and deposit everything in our inventory.
-async fn deposit(bot: &mut Client, state: &mut Arc<Mutex<State>>) -> anyhow::Result<()> {
+async fn deposit(bot: &mut Client, state: State) -> anyhow::Result<()> {
// first throw away any garbage we might have
bot.toss(|item| item.kind != ItemKind::Potato && item.kind != ItemKind::DiamondHoe);
diff --git a/azalea/examples/pvp.rs b/azalea/examples/pvp.rs
index a2f070f0..8c133576 100644
--- a/azalea/examples/pvp.rs
+++ b/azalea/examples/pvp.rs
@@ -7,7 +7,7 @@ async fn main() {
let accounts = Accounts::new();
for i in 0..10 {
- accounts.add(Account::offline(format!("bot{}", i)));
+ accounts.add(Account::offline(&format!("bot{}", i)));
}
azalea::start_swarm(azalea::SwarmOptions {
@@ -21,24 +21,28 @@ async fn main() {
plugins: vec![],
handle: Box::new(handle),
- swarm_handle: Box::new(handle),
+ swarm_handle: Box::new(swarm_handle),
})
.await
.unwrap();
}
+#[derive(Default, Clone)]
struct State {}
+
+#[derive(Default, Clone)]
struct SwarmState {}
-async fn handle(bots: Client, event: Arc<Event>, state: Arc<Mutex<State>>) {
- match *event {
+async fn handle(bot: Client, event: Event, state: State) {}
+async fn swarm_handle(swarm: Swarm, event: Event, state: State) {
+ match event {
Event::Tick => {
// choose an arbitrary player within render distance to target
- if let Some(target) = bots
- .dimension()
+ if let Some(target) = swarm
+ .dimension
.find_one_entity(|e| e.id == "minecraft:player")
{
- for bot in bots {
+ for bot in swarm {
bot.tick_goto_goal(pathfinder::Goals::Reach(target.bounding_box));
// if target.bounding_box.distance(bot.eyes) < bot.reach_distance() {
if bot.entity.can_reach(target.bounding_box) {
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(),
));
diff --git a/bot/src/main.rs b/bot/src/main.rs
index beed4320..9f8bd0c8 100644
--- a/bot/src/main.rs
+++ b/bot/src/main.rs
@@ -1,9 +1,7 @@
use azalea::prelude::*;
use azalea::{Account, Client, Event};
-use parking_lot::Mutex;
-use std::sync::Arc;
-#[derive(Default)]
+#[derive(Default, Clone)]
struct State {}
#[tokio::main]
@@ -15,7 +13,7 @@ async fn main() -> anyhow::Result<()> {
azalea::start(azalea::Options {
account,
address: "localhost",
- state: Arc::new(Mutex::new(State::default())),
+ state: State::default(),
plugins: vec![],
handle,
})
@@ -25,8 +23,8 @@ async fn main() -> anyhow::Result<()> {
Ok(())
}
-async fn handle(bot: Client, event: Arc<Event>, _state: Arc<Mutex<State>>) -> anyhow::Result<()> {
- match *event {
+async fn handle(bot: Client, event: Event, _state: State) -> anyhow::Result<()> {
+ match event {
Event::Login => {
bot.chat("Hello world").await?;
}