steal/
steal.rs

1//! Steal all the diamonds from all the nearby chests.
2
3use std::sync::Arc;
4
5use azalea::{BlockPos, pathfinder::goals::RadiusGoal, prelude::*};
6use azalea_inventory::{ItemStack, operations::QuickMoveClick};
7use azalea_registry::builtin::{BlockKind, ItemKind};
8use parking_lot::Mutex;
9
10#[tokio::main]
11async fn main() -> AppExit {
12    let account = Account::offline("bot");
13    // or let bot = Account::microsoft("email").await.unwrap();
14
15    ClientBuilder::new()
16        .set_handler(handle)
17        .start(account, "localhost")
18        .await
19}
20
21#[derive(Clone, Component, Default)]
22struct State {
23    pub is_stealing: Arc<Mutex<bool>>,
24    pub checked_chests: Arc<Mutex<Vec<BlockPos>>>,
25}
26
27async fn handle(bot: Client, event: Event, state: State) -> anyhow::Result<()> {
28    if let Event::Chat(m) = event {
29        if m.sender() == Some(bot.username()) {
30            return Ok(());
31        };
32        if m.content() != "go" {
33            return Ok(());
34        }
35
36        steal(bot, state).await?;
37    }
38
39    Ok(())
40}
41
42async fn steal(bot: Client, state: State) -> anyhow::Result<()> {
43    {
44        let mut is_stealing = state.is_stealing.lock();
45        if *is_stealing {
46            bot.chat("Already stealing");
47            return Ok(());
48        }
49        *is_stealing = true;
50    }
51
52    state.checked_chests.lock().clear();
53
54    loop {
55        let chest_block = bot
56            .world()
57            .read()
58            .find_blocks(bot.position(), &BlockKind::Chest.into())
59            .find(
60                // find the closest chest that hasn't been checked
61                |block_pos| !state.checked_chests.lock().contains(block_pos),
62            );
63        let Some(chest_block) = chest_block else {
64            break;
65        };
66
67        state.checked_chests.lock().push(chest_block);
68
69        bot.goto(RadiusGoal::new(chest_block.center(), 3.)).await;
70
71        let Some(chest) = bot.open_container_at(chest_block).await else {
72            println!("Couldn't open chest at {chest_block:?}");
73            continue;
74        };
75
76        println!("Getting contents of chest at {chest_block:?}");
77        for (index, slot) in chest.contents().unwrap_or_default().iter().enumerate() {
78            println!("Checking slot {index}: {slot:?}");
79            let ItemStack::Present(item) = slot else {
80                continue;
81            };
82            if item.kind == ItemKind::Diamond {
83                println!("clicking slot ^");
84                chest.click(QuickMoveClick::Left { slot: index as u16 });
85            }
86        }
87    }
88
89    bot.chat("Done");
90
91    *state.is_stealing.lock() = false;
92
93    Ok(())
94}