testbot/commands/
movement.rs1use 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 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 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 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}