pub struct ArgumentBuilder<S> { /* private fields */ }Expand description
A node that hasn’t yet been built.
Implementations§
Source§impl<S> ArgumentBuilder<S>
A node that isn’t yet built.
impl<S> ArgumentBuilder<S>
A node that isn’t yet built.
pub fn new(value: ArgumentBuilderType<S>) -> Self
Sourcepub fn then(self, argument: ArgumentBuilder<S>) -> Self
pub fn then(self, argument: ArgumentBuilder<S>) -> Self
Continue building this node with a child node.
literal("foo").then(literal("bar").executes(|ctx: &CommandContext<()>| 42))Examples found in repository?
azalea/examples/testbot/commands/combat.rs (lines 9-20)
7pub fn register(commands: &mut CommandDispatcher<Mutex<CommandSource>>) {
8 commands.register(
9 literal("killaura").then(argument("enabled", bool()).executes(|ctx: &Ctx| {
10 let enabled = get_bool(ctx, "enabled").unwrap();
11 let source = ctx.source.lock();
12 let bot = source.bot.clone();
13 bot.query_self::<&mut State, _>(|mut state| state.killaura = enabled);
14 source.reply(if enabled {
15 "Enabled killaura"
16 } else {
17 "Disabled killaura"
18 });
19 1
20 })),
21 );
22}More examples
azalea/examples/testbot/commands/movement.rs (lines 32-42)
14pub fn register(commands: &mut CommandDispatcher<Mutex<CommandSource>>) {
15 commands.register(
16 literal("goto")
17 .executes(|ctx: &Ctx| {
18 let mut source = ctx.source.lock();
19 println!("got goto");
20 // look for the sender
21 let Some(entity) = source.entity() else {
22 source.reply("I can't see you!");
23 return 0;
24 };
25 let position = entity.position();
26 source.reply("ok");
27 source
28 .bot
29 .start_goto(BlockPosGoal(BlockPos::from(position)));
30 1
31 })
32 .then(literal("xz").then(argument("x", integer()).then(
33 argument("z", integer()).executes(|ctx: &Ctx| {
34 let source = ctx.source.lock();
35 let x = get_integer(ctx, "x").unwrap();
36 let z = get_integer(ctx, "z").unwrap();
37 println!("goto xz {x} {z}");
38 source.reply("ok");
39 source.bot.start_goto(XZGoal { x, z });
40 1
41 }),
42 )))
43 .then(literal("radius").then(argument("radius", float()).then(
44 argument("x", integer()).then(argument("y", integer()).then(
45 argument("z", integer()).executes(|ctx: &Ctx| {
46 let source = ctx.source.lock();
47 let radius = get_float(ctx, "radius").unwrap();
48 let x = get_integer(ctx, "x").unwrap();
49 let y = get_integer(ctx, "y").unwrap();
50 let z = get_integer(ctx, "z").unwrap();
51 println!("goto radius {radius}, position: {x} {y} {z}");
52 source.reply("ok");
53 source.bot.start_goto(RadiusGoal {
54 pos: BlockPos::new(x, y, z).center(),
55 radius,
56 });
57 1
58 }),
59 )),
60 )))
61 .then(argument("x", integer()).then(argument("y", integer()).then(
62 argument("z", integer()).executes(|ctx: &Ctx| {
63 let source = ctx.source.lock();
64 let x = get_integer(ctx, "x").unwrap();
65 let y = get_integer(ctx, "y").unwrap();
66 let z = get_integer(ctx, "z").unwrap();
67 println!("goto xyz {x} {y} {z}");
68 source.reply("ok");
69 source.bot.start_goto(BlockPosGoal(BlockPos::new(x, y, z)));
70 1
71 }),
72 ))),
73 );
74
75 commands.register(literal("down").executes(|ctx: &Ctx| {
76 let source = ctx.source.clone();
77 tokio::spawn(async move {
78 let bot = source.lock().bot.clone();
79 let position = BlockPos::from(bot.position());
80 source.lock().reply("mining...");
81 bot.mine(position.down(1)).await;
82 source.lock().reply("done");
83 });
84 1
85 }));
86
87 commands.register(
88 literal("look")
89 .executes(|ctx: &Ctx| {
90 // look for the sender
91 let mut source = ctx.source.lock();
92 let Some(entity) = source.entity() else {
93 source.reply("I can't see you!");
94 return 0;
95 };
96 let eye_position = entity.eye_position();
97 source.bot.look_at(eye_position);
98 1
99 })
100 .then(argument("x", integer()).then(argument("y", integer()).then(
101 argument("z", integer()).executes(|ctx: &Ctx| {
102 let pos = BlockPos::new(
103 get_integer(ctx, "x").unwrap(),
104 get_integer(ctx, "y").unwrap(),
105 get_integer(ctx, "z").unwrap(),
106 );
107 println!("{pos:?}");
108 let source = ctx.source.lock();
109 source.bot.look_at(pos.center());
110 1
111 }),
112 ))),
113 );
114
115 commands.register(
116 literal("walk").then(argument("seconds", float()).executes(|ctx: &Ctx| {
117 let mut seconds = get_float(ctx, "seconds").unwrap();
118 let source = ctx.source.lock();
119 let bot = source.bot.clone();
120
121 if seconds < 0. {
122 bot.walk(WalkDirection::Backward);
123 seconds = -seconds;
124 } else {
125 bot.walk(WalkDirection::Forward);
126 }
127
128 tokio::spawn(async move {
129 tokio::time::sleep(Duration::from_secs_f32(seconds)).await;
130 bot.walk(WalkDirection::None);
131 });
132 source.reply(format!("ok, walking for {seconds} seconds"));
133 1
134 })),
135 );
136 commands.register(
137 literal("sprint").then(argument("seconds", float()).executes(|ctx: &Ctx| {
138 let seconds = get_float(ctx, "seconds").unwrap();
139 let source = ctx.source.lock();
140 let bot = source.bot.clone();
141 bot.sprint(SprintDirection::Forward);
142 tokio::spawn(async move {
143 tokio::time::sleep(Duration::from_secs_f32(seconds)).await;
144 bot.walk(WalkDirection::None);
145 });
146 source.reply(format!("ok, sprinting for {seconds} seconds"));
147 1
148 })),
149 );
150
151 commands.register(literal("north").executes(|ctx: &Ctx| {
152 let source = ctx.source.lock();
153 source.bot.set_direction(180., 0.);
154 source.reply("ok");
155 1
156 }));
157 commands.register(literal("south").executes(|ctx: &Ctx| {
158 let source = ctx.source.lock();
159 source.bot.set_direction(0., 0.);
160 source.reply("ok");
161 1
162 }));
163 commands.register(literal("east").executes(|ctx: &Ctx| {
164 let source = ctx.source.lock();
165 source.bot.set_direction(-90., 0.);
166 source.reply("ok");
167 1
168 }));
169 commands.register(literal("west").executes(|ctx: &Ctx| {
170 let source = ctx.source.lock();
171 source.bot.set_direction(90., 0.);
172 source.reply("ok");
173 1
174 }));
175 commands.register(
176 literal("jump")
177 .executes(|ctx: &Ctx| {
178 let source = ctx.source.lock();
179 source.bot.jump();
180 source.reply("ok");
181 1
182 })
183 .then(argument("enabled", bool()).executes(|ctx: &Ctx| {
184 let jumping = get_bool(ctx, "enabled").unwrap();
185 let source = ctx.source.lock();
186 source.bot.set_jumping(jumping);
187 1
188 })),
189 );
190
191 let sneak = |ctx: &Ctx| {
192 let source = ctx.source.lock();
193 source.bot.set_crouching(!source.bot.crouching());
194 source.reply("ok");
195 1
196 };
197 let sneak_enabled = argument("enabled", bool()).executes(|ctx: &Ctx| {
198 let sneaking = get_bool(ctx, "enabled").unwrap();
199 let source = ctx.source.lock();
200 source.bot.set_crouching(sneaking);
201 1
202 });
203 commands.register(literal("sneak").executes(sneak).then(sneak_enabled.clone()));
204 commands.register(literal("crouch").executes(sneak).then(sneak_enabled));
205
206 commands.register(literal("stop").executes(|ctx: &Ctx| {
207 let source = ctx.source.lock();
208 source.bot.stop_pathfinding();
209 source.reply("ok");
210 *source.state.task.lock() = BotTask::None;
211 1
212 }));
213}azalea/examples/testbot/commands/debug.rs (lines 132-144)
22pub fn register(commands: &mut CommandDispatcher<Mutex<CommandSource>>) {
23 commands.register(literal("ping").executes(|ctx: &Ctx| {
24 let source = ctx.source.lock();
25 source.reply("pong!");
26 1
27 }));
28
29 commands.register(literal("disconnect").executes(|ctx: &Ctx| {
30 let source = ctx.source.lock();
31 source.bot.disconnect();
32 1
33 }));
34
35 commands.register(literal("whereami").executes(|ctx: &Ctx| {
36 let mut source = ctx.source.lock();
37 let Some(entity) = source.entity() else {
38 source.reply("You aren't in render distance!");
39 return 0;
40 };
41 let position = entity.position();
42 source.reply(format!(
43 "You are at {}, {}, {}",
44 position.x, position.y, position.z
45 ));
46 1
47 }));
48
49 commands.register(literal("entityid").executes(|ctx: &Ctx| {
50 let mut source = ctx.source.lock();
51 let Some(entity) = source.entity() else {
52 source.reply("You aren't in render distance!");
53 return 0;
54 };
55 let entity_id = entity.minecraft_id();
56 source.reply(format!(
57 "Your Minecraft ID is {} and your ECS ID is {entity:?}",
58 *entity_id
59 ));
60 1
61 }));
62
63 let whereareyou = |ctx: &Ctx| {
64 let source = ctx.source.lock();
65 let position = source.bot.position();
66 source.reply(format!(
67 "I'm at {}, {}, {}",
68 position.x, position.y, position.z
69 ));
70 1
71 };
72 commands.register(literal("whereareyou").executes(whereareyou));
73 commands.register(literal("pos").executes(whereareyou));
74
75 commands.register(literal("whoareyou").executes(|ctx: &Ctx| {
76 let source = ctx.source.lock();
77 source.reply(format!(
78 "I am {} ({}, {})",
79 source.bot.username(),
80 source.bot.uuid(),
81 source.bot.entity
82 ));
83 1
84 }));
85
86 commands.register(literal("getdirection").executes(|ctx: &Ctx| {
87 let source = ctx.source.lock();
88 let direction = source.bot.direction();
89 source.reply(format!(
90 "I'm looking at {}, {}",
91 direction.y_rot(),
92 direction.x_rot()
93 ));
94 1
95 }));
96
97 commands.register(literal("health").executes(|ctx: &Ctx| {
98 let source = ctx.source.lock();
99
100 let health = source.bot.health();
101 source.reply(format!("I have {health} health"));
102 1
103 }));
104
105 commands.register(literal("lookingat").executes(|ctx: &Ctx| {
106 let source = ctx.source.lock();
107
108 let hit_result = source.bot.hit_result();
109
110 match &hit_result {
111 HitResult::Block(r) => {
112 if r.miss {
113 source.reply("I'm not looking at anything");
114 return 0;
115 }
116 let block_pos = r.block_pos;
117 let block = source.bot.world().read().get_block_state(block_pos);
118 source.reply(format!("I'm looking at {block:?} at {block_pos:?}"));
119 }
120 HitResult::Entity(r) => {
121 let entity_kind = **source.bot.entity_component::<EntityKindComponent>(r.entity);
122 source.reply(format!(
123 "I'm looking at {entity_kind} ({:?}) at {}",
124 r.entity, r.location
125 ));
126 }
127 }
128
129 1
130 }));
131
132 commands.register(literal("getblock").then(argument("x", integer()).then(
133 argument("y", integer()).then(argument("z", integer()).executes(|ctx: &Ctx| {
134 let source = ctx.source.lock();
135 let x = get_integer(ctx, "x").unwrap();
136 let y = get_integer(ctx, "y").unwrap();
137 let z = get_integer(ctx, "z").unwrap();
138 println!("getblock xyz {x} {y} {z}");
139 let block_pos = BlockPos::new(x, y, z);
140 let block = source.bot.world().read().get_block_state(block_pos);
141 source.reply(format!("BlockKind at {block_pos} is {block:?}"));
142 1
143 })),
144 )));
145 commands.register(literal("getfluid").then(argument("x", integer()).then(
146 argument("y", integer()).then(argument("z", integer()).executes(|ctx: &Ctx| {
147 let source = ctx.source.lock();
148 let x = get_integer(ctx, "x").unwrap();
149 let y = get_integer(ctx, "y").unwrap();
150 let z = get_integer(ctx, "z").unwrap();
151 println!("getfluid xyz {x} {y} {z}");
152 let block_pos = BlockPos::new(x, y, z);
153 let block = source.bot.world().read().get_fluid_state(block_pos);
154 source.reply(format!("Fluid at {block_pos} is {block:?}"));
155 1
156 })),
157 )));
158
159 commands.register(literal("pathfinderstate").executes(|ctx: &Ctx| {
160 let source = ctx.source.lock();
161 let pathfinder = source.bot.get_component::<Pathfinder>();
162 let Some(pathfinder) = pathfinder else {
163 source.reply("I don't have the Pathfinder ocmponent");
164 return 1;
165 };
166 source.reply(format!(
167 "pathfinder.is_calculating: {}",
168 pathfinder.is_calculating
169 ));
170
171 let executing_path = source.bot.get_component::<ExecutingPath>();
172 let Some(executing_path) = executing_path else {
173 source.reply("I'm not executing a path");
174 return 1;
175 };
176 source.reply(format!(
177 "is_path_partial: {}, path.len: {}, queued_path.len: {}",
178 executing_path.is_path_partial,
179 executing_path.path.len(),
180 if let Some(queued) = &executing_path.queued_path {
181 queued.len().to_string()
182 } else {
183 "n/a".to_owned()
184 },
185 ));
186 1
187 }));
188
189 commands.register(literal("startuseitem").executes(|ctx: &Ctx| {
190 let source = ctx.source.lock();
191 source.bot.start_use_item();
192 source.reply("Ok!");
193 1
194 }));
195 commands.register(literal("maxstacksize").executes(|ctx: &Ctx| {
196 let source = ctx.source.lock();
197 let max_stack_size = source
198 .bot
199 .get_held_item()
200 .get_component::<MaxStackSize>()
201 .map_or(-1, |s| s.count);
202 source.reply(format!("{max_stack_size}"));
203 1
204 }));
205
206 commands.register(literal("dimensions").executes(|ctx: &Ctx| {
207 let source = ctx.source.lock();
208 let bot_dimensions = source.bot.dimensions();
209 source.reply(format!("{bot_dimensions:?}"));
210 1
211 }));
212
213 commands.register(literal("players").executes(|ctx: &Ctx| {
214 let source = ctx.source.lock();
215 let player_entities = source
216 .bot
217 .nearest_entities_by::<(), With<metadata::Player>>(|_: ()| true);
218 let tab_list = source.bot.tab_list();
219 for player_entity in player_entities {
220 let uuid = player_entity.uuid();
221 source.reply(format!(
222 "{} - {} ({:?})",
223 player_entity.id(),
224 tab_list.get(&uuid).map_or("?", |p| p.profile.name.as_str()),
225 uuid
226 ));
227 }
228 1
229 }));
230
231 commands.register(literal("enchants").executes(|ctx: &Ctx| {
232 let source = ctx.source.lock();
233 source.bot.with_registry_holder(|r| {
234 let enchants = &r.enchantment;
235 println!("enchants: {enchants:?}");
236 });
237 1
238 }));
239
240 commands.register(literal("attributes").executes(|ctx: &Ctx| {
241 let source = ctx.source.lock();
242 let attributes = source.bot.attributes();
243 println!("attributes: {attributes:?}");
244 1
245 }));
246
247 commands.register(literal("debugecsleak").executes(|ctx: &Ctx| {
248 let source = ctx.source.lock();
249
250 source.reply("Ok!");
251
252
253
254 source.bot.disconnect();
255
256 let ecs = source.bot.ecs.clone();
257 thread::spawn(move || {
258 thread::sleep(Duration::from_secs(1));
259 // dump the ecs
260
261 let mut ecs = ecs.write();
262
263 let report_path = env::temp_dir().join("azalea-ecs-leak-report.txt");
264 let mut report = File::create(&report_path).unwrap();
265
266 let mut query = ecs.query::<EntityRef>();
267 for entity in query.iter(& ecs) {
268 writeln!(report, "Entity: {}", entity.id()).unwrap();
269 let archetype = entity.archetype();
270 let component_count = archetype.component_count();
271
272 let component_names = archetype
273 .components()
274 .iter()
275 .map(|c| ecs.components().get_info(*c).unwrap().name().to_string())
276 .collect::<Vec<_>>();
277 writeln!(
278 report,
279 "- {component_count} components: {}",
280 component_names.join(", ")
281 )
282 .unwrap();
283 }
284
285 writeln!(report).unwrap();
286
287
288 for (info, _) in ecs.iter_resources() {
289 let name = info.name().to_string();
290 writeln!(report, "Resource: {name}").unwrap();
291 // writeln!(report, "- Size: {} bytes",
292 // info.layout().size()).unwrap();
293
294 match name.as_ref() {
295 "azalea_world::container::InstanceContainer" => {
296 let instance_container = ecs.resource::<InstanceContainer>();
297
298 for (instance_name, instance) in &instance_container.instances {
299 writeln!(report, "- Name: {instance_name}").unwrap();
300 writeln!(report, "- Reference count: {}", instance.strong_count())
301 .unwrap();
302 if let Some(instance) = instance.upgrade() {
303 let instance = instance.read();
304 let strong_chunks = instance
305 .chunks
306 .map
307 .iter()
308 .filter(|(_, v)| v.strong_count() > 0)
309 .count();
310 writeln!(
311 report,
312 "- Chunks: {} strongly referenced, {} in map",
313 strong_chunks,
314 instance.chunks.map.len()
315 )
316 .unwrap();
317 writeln!(
318 report,
319 "- Entities: {}",
320 instance.entities_by_chunk.len()
321 )
322 .unwrap();
323 }
324 }
325 }
326 "bevy_ecs::message::Messages<azalea_client::packet::game::ReceivePacketEvent>" => {
327 let events = ecs.resource::<Messages<game::ReceiveGamePacketEvent>>();
328 writeln!(report, "- Event count: {}", events.len()).unwrap();
329 }
330 "bevy_ecs::message::Messages<azalea_client::chunks::ReceiveChunkEvent>" => {
331 let events = ecs.resource::<Messages<ReceiveChunkEvent>>();
332 writeln!(report, "- Event count: {}", events.len()).unwrap();
333 }
334
335 _ => {}
336 }
337 }
338
339 println!("\x1b[1mWrote report to {}\x1b[m", report_path.display());
340 });
341
342 1
343 }));
344
345 commands.register(literal("exit").executes(|ctx: &Ctx| {
346 let source = ctx.source.lock();
347 source.reply("bye!");
348
349 source.bot.disconnect();
350
351 let source = ctx.source.clone();
352 thread::spawn(move || {
353 thread::sleep(Duration::from_secs(1));
354
355 source
356 .lock()
357 .bot
358 .ecs
359 .write()
360 .write_message(AppExit::Success);
361 });
362
363 1
364 }));
365}Sourcepub fn then_built(self, argument: CommandNode<S>) -> Self
pub fn then_built(self, argument: CommandNode<S>) -> Self
Add an already built child node to this node.
You should usually use Self::then instead.
Sourcepub fn executes<F>(self, f: F) -> Self
pub fn executes<F>(self, f: F) -> Self
Set the command to be executed when this node is reached.
If this is not present on a node, it is not a valid command.
literal("foo").executes(|ctx: &CommandContext<()>| 42)Examples found in repository?
azalea/examples/testbot/commands/combat.rs (lines 9-20)
7pub fn register(commands: &mut CommandDispatcher<Mutex<CommandSource>>) {
8 commands.register(
9 literal("killaura").then(argument("enabled", bool()).executes(|ctx: &Ctx| {
10 let enabled = get_bool(ctx, "enabled").unwrap();
11 let source = ctx.source.lock();
12 let bot = source.bot.clone();
13 bot.query_self::<&mut State, _>(|mut state| state.killaura = enabled);
14 source.reply(if enabled {
15 "Enabled killaura"
16 } else {
17 "Disabled killaura"
18 });
19 1
20 })),
21 );
22}More examples
azalea/examples/testbot/commands/movement.rs (lines 17-31)
14pub fn register(commands: &mut CommandDispatcher<Mutex<CommandSource>>) {
15 commands.register(
16 literal("goto")
17 .executes(|ctx: &Ctx| {
18 let mut source = ctx.source.lock();
19 println!("got goto");
20 // look for the sender
21 let Some(entity) = source.entity() else {
22 source.reply("I can't see you!");
23 return 0;
24 };
25 let position = entity.position();
26 source.reply("ok");
27 source
28 .bot
29 .start_goto(BlockPosGoal(BlockPos::from(position)));
30 1
31 })
32 .then(literal("xz").then(argument("x", integer()).then(
33 argument("z", integer()).executes(|ctx: &Ctx| {
34 let source = ctx.source.lock();
35 let x = get_integer(ctx, "x").unwrap();
36 let z = get_integer(ctx, "z").unwrap();
37 println!("goto xz {x} {z}");
38 source.reply("ok");
39 source.bot.start_goto(XZGoal { x, z });
40 1
41 }),
42 )))
43 .then(literal("radius").then(argument("radius", float()).then(
44 argument("x", integer()).then(argument("y", integer()).then(
45 argument("z", integer()).executes(|ctx: &Ctx| {
46 let source = ctx.source.lock();
47 let radius = get_float(ctx, "radius").unwrap();
48 let x = get_integer(ctx, "x").unwrap();
49 let y = get_integer(ctx, "y").unwrap();
50 let z = get_integer(ctx, "z").unwrap();
51 println!("goto radius {radius}, position: {x} {y} {z}");
52 source.reply("ok");
53 source.bot.start_goto(RadiusGoal {
54 pos: BlockPos::new(x, y, z).center(),
55 radius,
56 });
57 1
58 }),
59 )),
60 )))
61 .then(argument("x", integer()).then(argument("y", integer()).then(
62 argument("z", integer()).executes(|ctx: &Ctx| {
63 let source = ctx.source.lock();
64 let x = get_integer(ctx, "x").unwrap();
65 let y = get_integer(ctx, "y").unwrap();
66 let z = get_integer(ctx, "z").unwrap();
67 println!("goto xyz {x} {y} {z}");
68 source.reply("ok");
69 source.bot.start_goto(BlockPosGoal(BlockPos::new(x, y, z)));
70 1
71 }),
72 ))),
73 );
74
75 commands.register(literal("down").executes(|ctx: &Ctx| {
76 let source = ctx.source.clone();
77 tokio::spawn(async move {
78 let bot = source.lock().bot.clone();
79 let position = BlockPos::from(bot.position());
80 source.lock().reply("mining...");
81 bot.mine(position.down(1)).await;
82 source.lock().reply("done");
83 });
84 1
85 }));
86
87 commands.register(
88 literal("look")
89 .executes(|ctx: &Ctx| {
90 // look for the sender
91 let mut source = ctx.source.lock();
92 let Some(entity) = source.entity() else {
93 source.reply("I can't see you!");
94 return 0;
95 };
96 let eye_position = entity.eye_position();
97 source.bot.look_at(eye_position);
98 1
99 })
100 .then(argument("x", integer()).then(argument("y", integer()).then(
101 argument("z", integer()).executes(|ctx: &Ctx| {
102 let pos = BlockPos::new(
103 get_integer(ctx, "x").unwrap(),
104 get_integer(ctx, "y").unwrap(),
105 get_integer(ctx, "z").unwrap(),
106 );
107 println!("{pos:?}");
108 let source = ctx.source.lock();
109 source.bot.look_at(pos.center());
110 1
111 }),
112 ))),
113 );
114
115 commands.register(
116 literal("walk").then(argument("seconds", float()).executes(|ctx: &Ctx| {
117 let mut seconds = get_float(ctx, "seconds").unwrap();
118 let source = ctx.source.lock();
119 let bot = source.bot.clone();
120
121 if seconds < 0. {
122 bot.walk(WalkDirection::Backward);
123 seconds = -seconds;
124 } else {
125 bot.walk(WalkDirection::Forward);
126 }
127
128 tokio::spawn(async move {
129 tokio::time::sleep(Duration::from_secs_f32(seconds)).await;
130 bot.walk(WalkDirection::None);
131 });
132 source.reply(format!("ok, walking for {seconds} seconds"));
133 1
134 })),
135 );
136 commands.register(
137 literal("sprint").then(argument("seconds", float()).executes(|ctx: &Ctx| {
138 let seconds = get_float(ctx, "seconds").unwrap();
139 let source = ctx.source.lock();
140 let bot = source.bot.clone();
141 bot.sprint(SprintDirection::Forward);
142 tokio::spawn(async move {
143 tokio::time::sleep(Duration::from_secs_f32(seconds)).await;
144 bot.walk(WalkDirection::None);
145 });
146 source.reply(format!("ok, sprinting for {seconds} seconds"));
147 1
148 })),
149 );
150
151 commands.register(literal("north").executes(|ctx: &Ctx| {
152 let source = ctx.source.lock();
153 source.bot.set_direction(180., 0.);
154 source.reply("ok");
155 1
156 }));
157 commands.register(literal("south").executes(|ctx: &Ctx| {
158 let source = ctx.source.lock();
159 source.bot.set_direction(0., 0.);
160 source.reply("ok");
161 1
162 }));
163 commands.register(literal("east").executes(|ctx: &Ctx| {
164 let source = ctx.source.lock();
165 source.bot.set_direction(-90., 0.);
166 source.reply("ok");
167 1
168 }));
169 commands.register(literal("west").executes(|ctx: &Ctx| {
170 let source = ctx.source.lock();
171 source.bot.set_direction(90., 0.);
172 source.reply("ok");
173 1
174 }));
175 commands.register(
176 literal("jump")
177 .executes(|ctx: &Ctx| {
178 let source = ctx.source.lock();
179 source.bot.jump();
180 source.reply("ok");
181 1
182 })
183 .then(argument("enabled", bool()).executes(|ctx: &Ctx| {
184 let jumping = get_bool(ctx, "enabled").unwrap();
185 let source = ctx.source.lock();
186 source.bot.set_jumping(jumping);
187 1
188 })),
189 );
190
191 let sneak = |ctx: &Ctx| {
192 let source = ctx.source.lock();
193 source.bot.set_crouching(!source.bot.crouching());
194 source.reply("ok");
195 1
196 };
197 let sneak_enabled = argument("enabled", bool()).executes(|ctx: &Ctx| {
198 let sneaking = get_bool(ctx, "enabled").unwrap();
199 let source = ctx.source.lock();
200 source.bot.set_crouching(sneaking);
201 1
202 });
203 commands.register(literal("sneak").executes(sneak).then(sneak_enabled.clone()));
204 commands.register(literal("crouch").executes(sneak).then(sneak_enabled));
205
206 commands.register(literal("stop").executes(|ctx: &Ctx| {
207 let source = ctx.source.lock();
208 source.bot.stop_pathfinding();
209 source.reply("ok");
210 *source.state.task.lock() = BotTask::None;
211 1
212 }));
213}azalea/examples/testbot/commands/debug.rs (lines 23-27)
22pub fn register(commands: &mut CommandDispatcher<Mutex<CommandSource>>) {
23 commands.register(literal("ping").executes(|ctx: &Ctx| {
24 let source = ctx.source.lock();
25 source.reply("pong!");
26 1
27 }));
28
29 commands.register(literal("disconnect").executes(|ctx: &Ctx| {
30 let source = ctx.source.lock();
31 source.bot.disconnect();
32 1
33 }));
34
35 commands.register(literal("whereami").executes(|ctx: &Ctx| {
36 let mut source = ctx.source.lock();
37 let Some(entity) = source.entity() else {
38 source.reply("You aren't in render distance!");
39 return 0;
40 };
41 let position = entity.position();
42 source.reply(format!(
43 "You are at {}, {}, {}",
44 position.x, position.y, position.z
45 ));
46 1
47 }));
48
49 commands.register(literal("entityid").executes(|ctx: &Ctx| {
50 let mut source = ctx.source.lock();
51 let Some(entity) = source.entity() else {
52 source.reply("You aren't in render distance!");
53 return 0;
54 };
55 let entity_id = entity.minecraft_id();
56 source.reply(format!(
57 "Your Minecraft ID is {} and your ECS ID is {entity:?}",
58 *entity_id
59 ));
60 1
61 }));
62
63 let whereareyou = |ctx: &Ctx| {
64 let source = ctx.source.lock();
65 let position = source.bot.position();
66 source.reply(format!(
67 "I'm at {}, {}, {}",
68 position.x, position.y, position.z
69 ));
70 1
71 };
72 commands.register(literal("whereareyou").executes(whereareyou));
73 commands.register(literal("pos").executes(whereareyou));
74
75 commands.register(literal("whoareyou").executes(|ctx: &Ctx| {
76 let source = ctx.source.lock();
77 source.reply(format!(
78 "I am {} ({}, {})",
79 source.bot.username(),
80 source.bot.uuid(),
81 source.bot.entity
82 ));
83 1
84 }));
85
86 commands.register(literal("getdirection").executes(|ctx: &Ctx| {
87 let source = ctx.source.lock();
88 let direction = source.bot.direction();
89 source.reply(format!(
90 "I'm looking at {}, {}",
91 direction.y_rot(),
92 direction.x_rot()
93 ));
94 1
95 }));
96
97 commands.register(literal("health").executes(|ctx: &Ctx| {
98 let source = ctx.source.lock();
99
100 let health = source.bot.health();
101 source.reply(format!("I have {health} health"));
102 1
103 }));
104
105 commands.register(literal("lookingat").executes(|ctx: &Ctx| {
106 let source = ctx.source.lock();
107
108 let hit_result = source.bot.hit_result();
109
110 match &hit_result {
111 HitResult::Block(r) => {
112 if r.miss {
113 source.reply("I'm not looking at anything");
114 return 0;
115 }
116 let block_pos = r.block_pos;
117 let block = source.bot.world().read().get_block_state(block_pos);
118 source.reply(format!("I'm looking at {block:?} at {block_pos:?}"));
119 }
120 HitResult::Entity(r) => {
121 let entity_kind = **source.bot.entity_component::<EntityKindComponent>(r.entity);
122 source.reply(format!(
123 "I'm looking at {entity_kind} ({:?}) at {}",
124 r.entity, r.location
125 ));
126 }
127 }
128
129 1
130 }));
131
132 commands.register(literal("getblock").then(argument("x", integer()).then(
133 argument("y", integer()).then(argument("z", integer()).executes(|ctx: &Ctx| {
134 let source = ctx.source.lock();
135 let x = get_integer(ctx, "x").unwrap();
136 let y = get_integer(ctx, "y").unwrap();
137 let z = get_integer(ctx, "z").unwrap();
138 println!("getblock xyz {x} {y} {z}");
139 let block_pos = BlockPos::new(x, y, z);
140 let block = source.bot.world().read().get_block_state(block_pos);
141 source.reply(format!("BlockKind at {block_pos} is {block:?}"));
142 1
143 })),
144 )));
145 commands.register(literal("getfluid").then(argument("x", integer()).then(
146 argument("y", integer()).then(argument("z", integer()).executes(|ctx: &Ctx| {
147 let source = ctx.source.lock();
148 let x = get_integer(ctx, "x").unwrap();
149 let y = get_integer(ctx, "y").unwrap();
150 let z = get_integer(ctx, "z").unwrap();
151 println!("getfluid xyz {x} {y} {z}");
152 let block_pos = BlockPos::new(x, y, z);
153 let block = source.bot.world().read().get_fluid_state(block_pos);
154 source.reply(format!("Fluid at {block_pos} is {block:?}"));
155 1
156 })),
157 )));
158
159 commands.register(literal("pathfinderstate").executes(|ctx: &Ctx| {
160 let source = ctx.source.lock();
161 let pathfinder = source.bot.get_component::<Pathfinder>();
162 let Some(pathfinder) = pathfinder else {
163 source.reply("I don't have the Pathfinder ocmponent");
164 return 1;
165 };
166 source.reply(format!(
167 "pathfinder.is_calculating: {}",
168 pathfinder.is_calculating
169 ));
170
171 let executing_path = source.bot.get_component::<ExecutingPath>();
172 let Some(executing_path) = executing_path else {
173 source.reply("I'm not executing a path");
174 return 1;
175 };
176 source.reply(format!(
177 "is_path_partial: {}, path.len: {}, queued_path.len: {}",
178 executing_path.is_path_partial,
179 executing_path.path.len(),
180 if let Some(queued) = &executing_path.queued_path {
181 queued.len().to_string()
182 } else {
183 "n/a".to_owned()
184 },
185 ));
186 1
187 }));
188
189 commands.register(literal("startuseitem").executes(|ctx: &Ctx| {
190 let source = ctx.source.lock();
191 source.bot.start_use_item();
192 source.reply("Ok!");
193 1
194 }));
195 commands.register(literal("maxstacksize").executes(|ctx: &Ctx| {
196 let source = ctx.source.lock();
197 let max_stack_size = source
198 .bot
199 .get_held_item()
200 .get_component::<MaxStackSize>()
201 .map_or(-1, |s| s.count);
202 source.reply(format!("{max_stack_size}"));
203 1
204 }));
205
206 commands.register(literal("dimensions").executes(|ctx: &Ctx| {
207 let source = ctx.source.lock();
208 let bot_dimensions = source.bot.dimensions();
209 source.reply(format!("{bot_dimensions:?}"));
210 1
211 }));
212
213 commands.register(literal("players").executes(|ctx: &Ctx| {
214 let source = ctx.source.lock();
215 let player_entities = source
216 .bot
217 .nearest_entities_by::<(), With<metadata::Player>>(|_: ()| true);
218 let tab_list = source.bot.tab_list();
219 for player_entity in player_entities {
220 let uuid = player_entity.uuid();
221 source.reply(format!(
222 "{} - {} ({:?})",
223 player_entity.id(),
224 tab_list.get(&uuid).map_or("?", |p| p.profile.name.as_str()),
225 uuid
226 ));
227 }
228 1
229 }));
230
231 commands.register(literal("enchants").executes(|ctx: &Ctx| {
232 let source = ctx.source.lock();
233 source.bot.with_registry_holder(|r| {
234 let enchants = &r.enchantment;
235 println!("enchants: {enchants:?}");
236 });
237 1
238 }));
239
240 commands.register(literal("attributes").executes(|ctx: &Ctx| {
241 let source = ctx.source.lock();
242 let attributes = source.bot.attributes();
243 println!("attributes: {attributes:?}");
244 1
245 }));
246
247 commands.register(literal("debugecsleak").executes(|ctx: &Ctx| {
248 let source = ctx.source.lock();
249
250 source.reply("Ok!");
251
252
253
254 source.bot.disconnect();
255
256 let ecs = source.bot.ecs.clone();
257 thread::spawn(move || {
258 thread::sleep(Duration::from_secs(1));
259 // dump the ecs
260
261 let mut ecs = ecs.write();
262
263 let report_path = env::temp_dir().join("azalea-ecs-leak-report.txt");
264 let mut report = File::create(&report_path).unwrap();
265
266 let mut query = ecs.query::<EntityRef>();
267 for entity in query.iter(& ecs) {
268 writeln!(report, "Entity: {}", entity.id()).unwrap();
269 let archetype = entity.archetype();
270 let component_count = archetype.component_count();
271
272 let component_names = archetype
273 .components()
274 .iter()
275 .map(|c| ecs.components().get_info(*c).unwrap().name().to_string())
276 .collect::<Vec<_>>();
277 writeln!(
278 report,
279 "- {component_count} components: {}",
280 component_names.join(", ")
281 )
282 .unwrap();
283 }
284
285 writeln!(report).unwrap();
286
287
288 for (info, _) in ecs.iter_resources() {
289 let name = info.name().to_string();
290 writeln!(report, "Resource: {name}").unwrap();
291 // writeln!(report, "- Size: {} bytes",
292 // info.layout().size()).unwrap();
293
294 match name.as_ref() {
295 "azalea_world::container::InstanceContainer" => {
296 let instance_container = ecs.resource::<InstanceContainer>();
297
298 for (instance_name, instance) in &instance_container.instances {
299 writeln!(report, "- Name: {instance_name}").unwrap();
300 writeln!(report, "- Reference count: {}", instance.strong_count())
301 .unwrap();
302 if let Some(instance) = instance.upgrade() {
303 let instance = instance.read();
304 let strong_chunks = instance
305 .chunks
306 .map
307 .iter()
308 .filter(|(_, v)| v.strong_count() > 0)
309 .count();
310 writeln!(
311 report,
312 "- Chunks: {} strongly referenced, {} in map",
313 strong_chunks,
314 instance.chunks.map.len()
315 )
316 .unwrap();
317 writeln!(
318 report,
319 "- Entities: {}",
320 instance.entities_by_chunk.len()
321 )
322 .unwrap();
323 }
324 }
325 }
326 "bevy_ecs::message::Messages<azalea_client::packet::game::ReceivePacketEvent>" => {
327 let events = ecs.resource::<Messages<game::ReceiveGamePacketEvent>>();
328 writeln!(report, "- Event count: {}", events.len()).unwrap();
329 }
330 "bevy_ecs::message::Messages<azalea_client::chunks::ReceiveChunkEvent>" => {
331 let events = ecs.resource::<Messages<ReceiveChunkEvent>>();
332 writeln!(report, "- Event count: {}", events.len()).unwrap();
333 }
334
335 _ => {}
336 }
337 }
338
339 println!("\x1b[1mWrote report to {}\x1b[m", report_path.display());
340 });
341
342 1
343 }));
344
345 commands.register(literal("exit").executes(|ctx: &Ctx| {
346 let source = ctx.source.lock();
347 source.reply("bye!");
348
349 source.bot.disconnect();
350
351 let source = ctx.source.clone();
352 thread::spawn(move || {
353 thread::sleep(Duration::from_secs(1));
354
355 source
356 .lock()
357 .bot
358 .ecs
359 .write()
360 .write_message(AppExit::Success);
361 });
362
363 1
364 }));
365}Sourcepub fn executes_result<F>(self, f: F) -> Self
pub fn executes_result<F>(self, f: F) -> Self
Same as Self::executes but returns a Result<i32, CommandSyntaxError>.
Sourcepub fn requires<F>(self, requirement: F) -> Self
pub fn requires<F>(self, requirement: F) -> Self
Set the requirement for this node to be considered.
If this is not present on a node, it is considered to always pass.
literal("foo")
.requires(|s: &CommandSource| s.opped)
// ...pub fn redirect(self, target: Arc<RwLock<CommandNode<S>>>) -> Self
pub fn fork( self, target: Arc<RwLock<CommandNode<S>>>, modifier: Arc<RedirectModifier<S>>, ) -> Self
pub fn forward( self, target: Arc<RwLock<CommandNode<S>>>, modifier: Option<Arc<RedirectModifier<S>>>, fork: bool, ) -> Self
pub fn arguments(&self) -> &CommandNode<S>
Sourcepub fn build(self) -> CommandNode<S>
pub fn build(self) -> CommandNode<S>
Manually build this node into a CommandNode. You probably don’t need
to do this yourself.
Trait Implementations§
Source§impl<S> Clone for ArgumentBuilder<S>
impl<S> Clone for ArgumentBuilder<S>
Auto Trait Implementations§
impl<S> Freeze for ArgumentBuilder<S>
impl<S> !RefUnwindSafe for ArgumentBuilder<S>
impl<S> Send for ArgumentBuilder<S>
impl<S> Sync for ArgumentBuilder<S>
impl<S> Unpin for ArgumentBuilder<S>
impl<S> !UnwindSafe for ArgumentBuilder<S>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more