Skip to main content

testbot/commands/
movement.rs

1use std::time::Duration;
2
3use azalea::{
4    BlockPos, SprintDirection, WalkDirection,
5    brigadier::prelude::*,
6    pathfinder::goals::{BlockPosGoal, RadiusGoal, XZGoal},
7    prelude::*,
8};
9
10use super::Ctx;
11use crate::commands::Dispatcher;
12
13pub fn register(commands: &mut Dispatcher) {
14    commands.register(
15        literal("goto")
16            .executes(|ctx: &Ctx| {
17                let source = ctx.source.lock();
18                println!("got goto");
19                // look for the sender
20                let Some(entity) = source.entity() else {
21                    source.reply("I can't see you!");
22                    return Ok(0);
23                };
24                let position = entity.position()?;
25                source.reply("ok");
26                source
27                    .bot
28                    .start_goto(BlockPosGoal(BlockPos::from(position.up(0.5))));
29                Ok(1)
30            })
31            .then(literal("xz").then(argument("x", integer()).then(
32                argument("z", integer()).executes(|ctx: &Ctx| {
33                    let source = ctx.source.lock();
34                    let x = get_integer(ctx, "x").unwrap();
35                    let z = get_integer(ctx, "z").unwrap();
36                    println!("goto xz {x} {z}");
37                    source.reply("ok");
38                    source.bot.start_goto(XZGoal { x, z });
39                    Ok(1)
40                }),
41            )))
42            .then(literal("radius").then(argument("radius", float()).then(
43                argument("x", integer()).then(argument("y", integer()).then(
44                    argument("z", integer()).executes(|ctx: &Ctx| {
45                        let source = ctx.source.lock();
46                        let radius = get_float(ctx, "radius").unwrap();
47                        let x = get_integer(ctx, "x").unwrap();
48                        let y = get_integer(ctx, "y").unwrap();
49                        let z = get_integer(ctx, "z").unwrap();
50                        println!("goto radius {radius}, position: {x} {y} {z}");
51                        source.reply("ok");
52                        source.bot.start_goto(RadiusGoal {
53                            pos: BlockPos::new(x, y, z).center(),
54                            radius,
55                        });
56                        Ok(1)
57                    }),
58                )),
59            )))
60            .then(argument("x", integer()).then(argument("y", integer()).then(
61                argument("z", integer()).executes(|ctx: &Ctx| {
62                    let source = ctx.source.lock();
63                    let x = get_integer(ctx, "x").unwrap();
64                    let y = get_integer(ctx, "y").unwrap();
65                    let z = get_integer(ctx, "z").unwrap();
66                    println!("goto xyz {x} {y} {z}");
67                    source.reply("ok");
68                    source.bot.start_goto(BlockPosGoal(BlockPos::new(x, y, z)));
69                    Ok(1)
70                }),
71            ))),
72    );
73
74    commands.register(literal("follow").executes(|ctx: &Ctx| {
75        let source = ctx.source.lock();
76        println!("got follow");
77        // look for the sender
78        let Some(entity) = source.entity() else {
79            source.reply("I can't see you!");
80            return Ok(0);
81        };
82        source.reply("ok");
83        *source.state.following_entity.lock() = Some(entity);
84        Ok(1)
85    }));
86
87    commands.register(literal("down").executes(|ctx: &Ctx| {
88        let source = ctx.source.clone();
89        let bot = source.lock().bot.clone();
90        let position = BlockPos::from(bot.position()?);
91        tokio::spawn(async move {
92            source.lock().reply("mining...");
93            bot.mine(position.down(1)).await;
94            source.lock().reply("done");
95        });
96        Ok(1)
97    }));
98
99    commands.register(
100        literal("look")
101            .executes(|ctx: &Ctx| {
102                // look for the sender
103                let source = ctx.source.lock();
104                let Some(entity) = source.entity() else {
105                    source.reply("I can't see you!");
106                    return Ok(0);
107                };
108                let eye_position = entity.eye_position()?;
109                source.bot.look_at(eye_position);
110                Ok(1)
111            })
112            .then(argument("x", integer()).then(argument("y", integer()).then(
113                argument("z", integer()).executes(|ctx: &Ctx| {
114                    let pos = BlockPos::new(
115                        get_integer(ctx, "x").unwrap(),
116                        get_integer(ctx, "y").unwrap(),
117                        get_integer(ctx, "z").unwrap(),
118                    );
119                    println!("{pos:?}");
120                    let source = ctx.source.lock();
121                    source.bot.look_at(pos.center());
122                    Ok(1)
123                }),
124            ))),
125    );
126
127    fn walk_command(ctx: &Ctx, direction: WalkDirection) -> eyre::Result<i32> {
128        let mut seconds = get_float(ctx, "seconds").unwrap();
129        let source = ctx.source.lock();
130        let bot = source.bot.clone();
131
132        if seconds < 0. {
133            bot.walk(direction.opposite());
134            seconds = -seconds;
135        } else {
136            bot.walk(direction);
137        }
138
139        tokio::spawn(async move {
140            tokio::time::sleep(Duration::from_secs_f32(seconds)).await;
141            bot.walk(WalkDirection::None);
142        });
143        source.reply(format!("ok, walking {direction:?} for {seconds} seconds"));
144        Ok(1)
145    }
146
147    commands.register(
148        literal("walk").then(
149            argument("seconds", float())
150                .executes(|ctx: &Ctx| walk_command(ctx, WalkDirection::Forward)),
151        ),
152    );
153    commands.register(literal("left").then(
154        argument("seconds", float()).executes(|ctx: &Ctx| walk_command(ctx, WalkDirection::Left)),
155    ));
156    commands.register(literal("right").then(
157        argument("seconds", float()).executes(|ctx: &Ctx| walk_command(ctx, WalkDirection::Left)),
158    ));
159    commands.register(
160        literal("sprint").then(argument("seconds", float()).executes(|ctx: &Ctx| {
161            let seconds = get_float(ctx, "seconds").unwrap();
162            let source = ctx.source.lock();
163            let bot = source.bot.clone();
164            bot.sprint(SprintDirection::Forward);
165            tokio::spawn(async move {
166                tokio::time::sleep(Duration::from_secs_f32(seconds)).await;
167                bot.walk(WalkDirection::None);
168            });
169            source.reply(format!("ok, sprinting for {seconds} seconds"));
170            Ok(1)
171        })),
172    );
173
174    commands.register(literal("north").executes(|ctx: &Ctx| {
175        let source = ctx.source.lock();
176        source.bot.set_direction(180., 0.)?;
177        source.reply("ok");
178        Ok(1)
179    }));
180    commands.register(literal("south").executes(|ctx: &Ctx| {
181        let source = ctx.source.lock();
182        source.bot.set_direction(0., 0.)?;
183        source.reply("ok");
184        Ok(1)
185    }));
186    commands.register(literal("east").executes(|ctx: &Ctx| {
187        let source = ctx.source.lock();
188        source.bot.set_direction(-90., 0.)?;
189        source.reply("ok");
190        Ok(1)
191    }));
192    commands.register(literal("west").executes(|ctx: &Ctx| {
193        let source = ctx.source.lock();
194        source.bot.set_direction(90., 0.)?;
195        source.reply("ok");
196        Ok(1)
197    }));
198    commands.register(
199        literal("jump")
200            .executes(|ctx: &Ctx| {
201                let source = ctx.source.lock();
202                source.bot.jump();
203                source.reply("ok");
204                Ok(1)
205            })
206            .then(argument("enabled", bool()).executes(|ctx: &Ctx| {
207                let jumping = get_bool(ctx, "enabled").unwrap();
208                let source = ctx.source.lock();
209                source.bot.set_jumping(jumping)?;
210                Ok(1)
211            })),
212    );
213
214    let sneak = |ctx: &Ctx| {
215        let source = ctx.source.lock();
216        source.bot.set_crouching(!source.bot.crouching())?;
217        source.reply("ok");
218        Ok(1)
219    };
220    let sneak_enabled = argument("enabled", bool()).executes(|ctx: &Ctx| {
221        let sneaking = get_bool(ctx, "enabled").unwrap();
222        let source = ctx.source.lock();
223        source.bot.set_crouching(sneaking)?;
224        Ok(1)
225    });
226    commands.register(literal("sneak").executes(sneak).then(sneak_enabled.clone()));
227    commands.register(literal("crouch").executes(sneak).then(sneak_enabled));
228
229    commands.register(literal("stop").executes(|ctx: &Ctx| {
230        let source = ctx.source.lock();
231        source.bot.stop_pathfinding();
232        source.reply("ok");
233        *source.state.following_entity.lock() = None;
234        Ok(1)
235    }));
236    commands.register(literal("forcestop").executes(|ctx: &Ctx| {
237        let source = ctx.source.lock();
238        source.bot.force_stop_pathfinding();
239        source.reply("ok");
240        *source.state.following_entity.lock() = None;
241        Ok(1)
242    }));
243}