mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 06:16:04 +00:00
parent
37f9f1c6fe
commit
06068377bd
11 changed files with 163 additions and 26 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
@ -101,6 +101,11 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "azalea"
|
name = "azalea"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"env_logger",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "azalea-auth"
|
name = "azalea-auth"
|
||||||
|
@ -890,9 +895,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.8.3"
|
version = "0.8.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "713d550d9b44d89174e066b7a6217ae06234c10cb47819a88290d2b353c31799"
|
checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
|
@ -1432,10 +1437,11 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.19.2"
|
version = "1.21.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439"
|
checksum = "0020c875007ad96677dcc890298f4b942882c5d4eb7cc8f439fc3bf813dc9c95"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
"bytes",
|
"bytes",
|
||||||
"libc",
|
"libc",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
|
|
@ -66,7 +66,10 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_from_blockstate() {
|
fn test_from_blockstate() {
|
||||||
let box_block: Box<dyn Block> = Box::<dyn Block>::from(BlockState::Air);
|
let block: Box<dyn Block> = Box::<dyn Block>::from(BlockState::Air);
|
||||||
assert_eq!(box_block.id(), "air");
|
assert_eq!(block.id(), "air");
|
||||||
|
|
||||||
|
let block: Box<dyn Block> = Box::<dyn Block>::from(BlockState::FloweringAzalea);
|
||||||
|
assert_eq!(block.id(), "flowering_azalea");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,3 +9,9 @@ version = "0.1.0"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tokio = "^1.21.1"
|
||||||
|
env_logger = "^0.9.1"
|
||||||
|
anyhow = "^1.0.65"
|
||||||
|
|
|
@ -30,12 +30,11 @@ async fn handle_event(event: &Event, bot: &Bot, ctx: Arc<Context>) {
|
||||||
ctx_lock.started = true;
|
ctx_lock.started = true;
|
||||||
drop(ctx_lock);
|
drop(ctx_lock);
|
||||||
|
|
||||||
bot.goto_goal(
|
bot.goto(
|
||||||
pathfinder::Goals::NearXZ(5, azalea::BlockXZ(0, 0))
|
pathfinder::Goals::NearXZ(5, azalea::BlockXZ(0, 0))
|
||||||
).await;
|
).await;
|
||||||
let chest = bot.open_container(&bot.world.find_one_block(|b| b.id == "minecraft:chest")).await.unwrap();
|
let chest = bot.open_container(&bot.world.find_one_block(|b| b.id == "minecraft:chest")).await.unwrap();
|
||||||
bot.take_amount(&chest, 5, |i| i.id == "#minecraft:planks").await;
|
bot.take_amount(&chest, 5, |i| i.id == "#minecraft:planks").await;
|
||||||
// when rust adds async drop this won't be necessary
|
|
||||||
chest.close().await;
|
chest.close().await;
|
||||||
|
|
||||||
let crafting_table = bot.open_crafting_table(&bot.world.find_one_block(|b| b.id == "minecraft:crafting_table")).await.unwrap();
|
let crafting_table = bot.open_crafting_table(&bot.world.find_one_block(|b| b.id == "minecraft:crafting_table")).await.unwrap();
|
|
@ -12,15 +12,15 @@ async fn main() {
|
||||||
|
|
||||||
let bots = accounts.join("localhost".try_into().unwrap()).await.unwrap();
|
let bots = accounts.join("localhost".try_into().unwrap()).await.unwrap();
|
||||||
|
|
||||||
bots.goto(azalea::BlockCoord(0, 70, 0)).await;
|
bots.goto(azalea::BlockPos::new(0, 70, 0)).await;
|
||||||
// or bots.goto_goal(pathfinder::Goals::Goto(azalea::BlockCoord(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
|
// destroy the blocks in this area and then leave
|
||||||
|
|
||||||
bots.fill(
|
bots.fill(
|
||||||
azalea::Selection::Range(
|
azalea::Selection::Range(
|
||||||
azalea::BlockCoord(0, 0, 0),
|
azalea::BlockPos::new(0, 0, 0),
|
||||||
azalea::BlockCoord(16, 255, 16)
|
azalea::BlockPos::new(16, 255, 16)
|
||||||
),
|
),
|
||||||
azalea::block::Air
|
azalea::block::Air
|
||||||
).await;
|
).await;
|
24
azalea/examples/potatobot/README.md
Normal file
24
azalea/examples/potatobot/README.md
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
A relatively complex bot for farming potatoes.
|
||||||
|
|
||||||
|
Note: At the moment, all of the code here is only hypothetical. I decided to write this to help me decide how I want some the APIs to look.
|
||||||
|
|
||||||
|
## Attempted
|
||||||
|
- Sync: a sync function is called with the state and bot every time we get an event, and the function can queue events to execute at the end of the tick
|
||||||
|
|
||||||
|
Pros: No .lock().unwrap() necessary, and theoretically pausable by saving the state.
|
||||||
|
|
||||||
|
Cons: Async functions like opening containers and pathfinding are annoying because you have to keep state for them, and the code generally ends up being more confusing.
|
||||||
|
|
||||||
|
- Async non-blocking: an async function is called in a new task with the state mutex and bot every time we get an event
|
||||||
|
|
||||||
|
Pros: Easier to do async stuff like interacting with containers, code is somewhat easier to understand
|
||||||
|
|
||||||
|
Cons: Lock spam everywhere is annoying, and you have to make sure stuff doesn't accidentally run in parallel.
|
||||||
|
|
||||||
|
## Considered:
|
||||||
|
(I didn't actually try this because the problems were apparent)
|
||||||
|
- Async blocking: an async function is called with the state and bot every time we get an event, and only handles the next event when this one finishes running
|
||||||
|
|
||||||
|
Pros: No lock spam
|
||||||
|
|
||||||
|
Cons: Sometimes you want to handle multiple events at once like eating if you get hungry while pathfinding, this makes it harder without increasing complexity
|
20
azalea/examples/potatobot/autoeat.rs
Normal file
20
azalea/examples/potatobot/autoeat.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
//! Automatically eat when we get hungry.
|
||||||
|
|
||||||
|
use azalea::{Client, Event};
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct State {}
|
||||||
|
|
||||||
|
pub async fn handle(bot: &mut Client, event: Event, state: Arc<Mutex<State>>) {
|
||||||
|
match event {
|
||||||
|
Event::UpdateHunger => {
|
||||||
|
if !bot.using_held_item() && bot.food_level() <= 17 {
|
||||||
|
if bot.hold(azalea::ItemGroup::Food).await {
|
||||||
|
bot.use_held_item().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
91
azalea/examples/potatobot/main.rs
Normal file
91
azalea/examples/potatobot/main.rs
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
mod autoeat;
|
||||||
|
|
||||||
|
use azalea::{pathfinder, Account, BlockPos, Client, Event, ItemKind, MoveDirection, Vec3};
|
||||||
|
use std::{
|
||||||
|
convert::TryInto,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct State {
|
||||||
|
pub eating: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
env_logger::init();
|
||||||
|
|
||||||
|
let account = Account::offline("bot");
|
||||||
|
let (bot, mut rx) = account
|
||||||
|
.join(&"localhost".try_into().unwrap())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Maybe all this could be turned into a macro in the future?
|
||||||
|
let state = Arc::new(Mutex::new(State::default()));
|
||||||
|
let autoeat_state = Arc::new(Mutex::new(autoeat::State::default()));
|
||||||
|
let pathfinder_state = Arc::new(Mutex::new(pathfinder::State::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);
|
||||||
|
|
||||||
|
tokio::spawn(autoeat::handle(
|
||||||
|
bot.clone(),
|
||||||
|
event.clone(),
|
||||||
|
autoeat_state.clone(),
|
||||||
|
));
|
||||||
|
tokio::spawn(pathfinder::handle(
|
||||||
|
bot.clone(),
|
||||||
|
event.clone(),
|
||||||
|
pathfinder_state.clone(),
|
||||||
|
));
|
||||||
|
tokio::spawn(handle(bot.clone(), event.clone(), state.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle(bot: Client, event: Event, state: Arc<Mutex<State>>) -> anyhow::Result<()> {
|
||||||
|
match event {
|
||||||
|
Event::Login => {
|
||||||
|
goto_farm(bot, state).await?;
|
||||||
|
// after we get to the farm, start farming
|
||||||
|
farm(bot, state).await?;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// go to the place where we start farming
|
||||||
|
async fn goto_farm(bot: Client, state: Arc<Mutex<State>>) -> anyhow::Result<()> {
|
||||||
|
bot.state
|
||||||
|
.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<()> {
|
||||||
|
// first throw away any garbage we might have
|
||||||
|
bot.toss(|item| item.kind != ItemKind::Potato && item.kind != ItemKind::DiamondHoe);
|
||||||
|
|
||||||
|
bot.state.goto(Vec3::new(0, 70, 0)).await?;
|
||||||
|
let chest = bot
|
||||||
|
.open_container(&bot.dimension.block_at(BlockPos::new(0, 70, 0)))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let inventory_potato_count: usize = bot
|
||||||
|
.inventory()
|
||||||
|
.count_total(|item| item.kind == ItemKind::Potato);
|
||||||
|
if inventory_potato_count > 64 {
|
||||||
|
chest
|
||||||
|
.deposit_total_count(
|
||||||
|
|item| item.kind == azalea::ItemKind::Potato,
|
||||||
|
inventory_potato_count - 64,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
chest.close().await;
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -1,14 +1,2 @@
|
||||||
pub fn add(left: usize, right: usize) -> usize {
|
//! This is currently an advertisement crate for
|
||||||
left + right
|
//! [Azalea](https://github.com/mat-1/azalea). More stuff will be here soon!
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn it_works() {
|
|
||||||
let result = add(2, 2);
|
|
||||||
assert_eq!(result, 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue