aboutsummaryrefslogtreecommitdiff
path: root/README.md
blob: e214fb0997732f71d1efe788ed5210a6c21bf244 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# Azalea

<p align="center">
    <img src="https://cdn.matdoes.dev/images/flowering_azalea.webp" alt="Azalea" height="200">
</p>

A Rust crate for creating Minecraft bots.

I named this Azalea because it sounds like a cool word and this is a cool library. This project was heavily inspired by PrismarineJS.

## Why

I wanted a fun excuse to do something cool with Rust, and I also felt like I could do better than [Mineflayer](https://github.com/prismarinejs/mineflayer) in some areas.

## Goals

- Do everything a vanilla client can do.
- Be easy to use.
- Bypass most/all anticheats.
- Support the latest Minecraft version.
- Be fast and memory efficient.

## Example code

Note that these don't work yet, it's just how I want the API to look.

```rs
use azalea::{Account, Event};

let account = Account::offline("bot");
// or let account = azalea::Account::microsoft("access token").await;

let bot = account.join("localhost".try_into().unwrap()).await.unwrap();

loop {
    match bot.next().await {
        Event::Message(m) {
            if m.username == bot.username { return };
            bot.chat(m.message).await;
        },
        Event::Kicked(m) {
            println!(m);
            bot.reconnect().await.unwrap();
        },
        Event::Hunger(h) {
            if !h.using_held_item() && h.hunger <= 17 {
                match bot.hold(azalea::ItemGroup::Food).await {
                    Ok(_) => {},
                    Err(e) => {
                        println!("{}", e);
                        break;
                    }
                }
                match bot.use_held_item().await {
                    Ok(_) => {},
                    Err(e) => {
                        println!("{}", e);
                        break;
                    }
                }
            }
        }
        _ => {}
    }
}
```

```rs
use azalea::{Bot, Event};

let bot = Bot::offline("bot");
// or let bot = azalea::Bot::microsoft("access token").await;

bot.join("localhost".try_into().unwrap()).await.unwrap();

loop {
    match bot.next().await {
        Event::Message(m) {
            if m.username == bot.username { return };
            if m.message = "go" {
                bot.goto_goal(
                    pathfinder::Goals::NearXZ(5, azalea::BlockXZ(0, 0))
                ).await;
                let chest = bot.open_chest(&bot.world.find_one_block(|b| b.id == "minecraft:chest")).await.unwrap();
                bot.take_amount(&chest, 3, |i| i.id == "#minecraft:planks").await;
                // when rust adds async drop this won't be necessary
                chest.close().await;

                let crafting_table = bot.open_crafting_table(&bot.world.find_one_block(|b| b.id == "minecraft:crafting_table")).await.unwrap();
                bot.craft(&crafting_table, &bot.recipe_for("minecraft:sticks")).await?;
                let pickaxe = bot.craft(&crafting_table, &bot.recipe_for("minecraft:wooden_pickaxe")).await?;
                crafting_table.close().await;

                bot.hold(&pickaxe);
                loop {
                    if let Err(e) = bot.dig(bot.feet_coords().down(1)).await {
                        println!("{:?}", e);
                        break;
                    }
                }
            }
        },
        _ => {}
    }
}
```

You can use the `azalea::Bots` struct to control many bots as one unit.

```rs
use azalea::{Account, Accounts, Event, pathfinder};

#[tokio::main]
async fn main() {
    let accounts = Accounts::new();

    for i in 0..10 {
        accounts.add(Account::offline(format!("bot{}", i)));
    }

    let bots = accounts.join("localhost".try_into().unwrap()).await.unwrap();

    bots.goto(azalea::BlockCoord(0, 70, 0)).await;
    // or bots.goto_goal(pathfinder::Goals::Goto(azalea::BlockCoord(0, 70, 0))).await;

    // destroy the blocks in this area and then leave

    bots.fill(
        azalea::Selection::Range(
            azalea::BlockCoord(0, 0, 0),
            azalea::BlockCoord(16, 255, 16)
        ),
        azalea::block::Air
    ).await;
}
```