pub fn default_move(ctx: &mut MovesCtx<'_>, node: RelBlockPos)Examples found in repository?
azalea/examples/testbot/commands/debug.rs (lines 207-215)
26pub fn register(commands: &mut CommandDispatcher<Mutex<CommandSource>>) {
27 commands.register(literal("ping").executes(|ctx: &Ctx| {
28 let source = ctx.source.lock();
29 source.reply("pong!");
30 1
31 }));
32
33 commands.register(literal("disconnect").executes(|ctx: &Ctx| {
34 let source = ctx.source.lock();
35 source.bot.disconnect();
36 1
37 }));
38
39 commands.register(literal("whereami").executes(|ctx: &Ctx| {
40 let source = ctx.source.lock();
41 let Some(entity) = source.entity() else {
42 source.reply("You aren't in render distance!");
43 return 0;
44 };
45 let position = entity.position();
46 source.reply(format!(
47 "You are at {}, {}, {}",
48 position.x, position.y, position.z
49 ));
50 1
51 }));
52
53 commands.register(literal("entityid").executes(|ctx: &Ctx| {
54 let source = ctx.source.lock();
55 let Some(entity) = source.entity() else {
56 source.reply("You aren't in render distance!");
57 return 0;
58 };
59 let entity_id = entity.minecraft_id();
60 source.reply(format!(
61 "Your Minecraft ID is {} and your ECS ID is {entity:?}",
62 *entity_id
63 ));
64 1
65 }));
66
67 let whereareyou = |ctx: &Ctx| {
68 let source = ctx.source.lock();
69 let position = source.bot.position();
70 source.reply(format!(
71 "I'm at {}, {}, {}",
72 position.x, position.y, position.z
73 ));
74 1
75 };
76 commands.register(literal("whereareyou").executes(whereareyou));
77 commands.register(literal("pos").executes(whereareyou));
78
79 commands.register(literal("whoareyou").executes(|ctx: &Ctx| {
80 let source = ctx.source.lock();
81 source.reply(format!(
82 "I am {} ({}, {})",
83 source.bot.username(),
84 source.bot.uuid(),
85 source.bot.entity
86 ));
87 1
88 }));
89
90 commands.register(literal("getdirection").executes(|ctx: &Ctx| {
91 let source = ctx.source.lock();
92 let direction = source.bot.direction();
93 source.reply(format!(
94 "I'm looking at {}, {}",
95 direction.y_rot(),
96 direction.x_rot()
97 ));
98 1
99 }));
100
101 commands.register(literal("health").executes(|ctx: &Ctx| {
102 let source = ctx.source.lock();
103
104 let health = source.bot.health();
105 source.reply(format!("I have {health} health"));
106 1
107 }));
108
109 commands.register(literal("lookingat").executes(|ctx: &Ctx| {
110 let source = ctx.source.lock();
111
112 let hit_result = source.bot.hit_result();
113
114 match &hit_result {
115 HitResult::Block(r) => {
116 if r.miss {
117 source.reply("I'm not looking at anything");
118 return 0;
119 }
120 let block_pos = r.block_pos;
121 let block = source.bot.world().read().get_block_state(block_pos);
122 source.reply(format!("I'm looking at {block:?} at {block_pos:?}"));
123 }
124 HitResult::Entity(r) => {
125 let entity_kind = **source.bot.entity_component::<EntityKindComponent>(r.entity);
126 source.reply(format!(
127 "I'm looking at {entity_kind} ({:?}) at {}",
128 r.entity, r.location
129 ));
130 }
131 }
132
133 1
134 }));
135
136 commands.register(literal("getblock").then(argument("x", integer()).then(
137 argument("y", integer()).then(argument("z", integer()).executes(|ctx: &Ctx| {
138 let source = ctx.source.lock();
139 let x = get_integer(ctx, "x").unwrap();
140 let y = get_integer(ctx, "y").unwrap();
141 let z = get_integer(ctx, "z").unwrap();
142 println!("getblock xyz {x} {y} {z}");
143 let block_pos = BlockPos::new(x, y, z);
144 let block = source.bot.world().read().get_block_state(block_pos);
145 source.reply(format!("BlockKind at {block_pos} is {block:?}"));
146 1
147 })),
148 )));
149 commands.register(literal("getfluid").then(argument("x", integer()).then(
150 argument("y", integer()).then(argument("z", integer()).executes(|ctx: &Ctx| {
151 let source = ctx.source.lock();
152 let x = get_integer(ctx, "x").unwrap();
153 let y = get_integer(ctx, "y").unwrap();
154 let z = get_integer(ctx, "z").unwrap();
155 println!("getfluid xyz {x} {y} {z}");
156 let block_pos = BlockPos::new(x, y, z);
157 let block = source.bot.world().read().get_fluid_state(block_pos);
158 source.reply(format!("Fluid at {block_pos} is {block:?}"));
159 1
160 })),
161 )));
162
163 commands.register(literal("pathfinderstate").executes(|ctx: &Ctx| {
164 let source = ctx.source.lock();
165 let pathfinder = source.bot.get_component::<Pathfinder>();
166 let Some(pathfinder) = pathfinder else {
167 source.reply("I don't have the Pathfinder component");
168 return 1;
169 };
170 source.reply(format!(
171 "pathfinder.is_calculating: {}",
172 pathfinder.is_calculating
173 ));
174
175 let executing_path = source.bot.get_component::<ExecutingPath>();
176 let Some(executing_path) = executing_path else {
177 source.reply("I'm not executing a path");
178 return 1;
179 };
180 source.reply(format!(
181 "is_path_partial: {}, path.len: {}, queued_path.len: {}",
182 executing_path.is_path_partial,
183 executing_path.path.len(),
184 if let Some(queued) = &executing_path.queued_path {
185 queued.len().to_string()
186 } else {
187 "n/a".to_owned()
188 },
189 ));
190 1
191 }));
192 commands.register(literal("pathfindermoves").executes(|ctx: &Ctx| {
193 let source = ctx.source.lock();
194
195 let Some(entity) = source.entity() else {
196 source.reply("You aren't in render distance!");
197 return 0;
198 };
199 let position = entity.position();
200 let position = BlockPos::from(position);
201
202 let mut edges = Vec::new();
203 let cached_world = CachedWorld::new(source.bot.world(), position);
204 let mining_cache = MiningCache::new(Some(Menu::Player(inventory::Player::default())));
205 let custom_state = CustomPathfinderStateRef::default();
206
207 azalea::pathfinder::moves::default_move(
208 &mut MovesCtx {
209 edges: &mut edges,
210 world: &cached_world,
211 mining_cache: &mining_cache,
212 custom_state: &custom_state,
213 },
214 RelBlockPos::from_origin(position, position),
215 );
216
217 if edges.is_empty() {
218 source.reply("No possible moves.");
219 } else {
220 source.reply("Moves:");
221 for (i, edge) in edges.iter().enumerate() {
222 source.reply(format!("{}) {edge:?}", i + 1));
223 }
224 }
225
226 1
227 }));
228
229 commands.register(literal("startuseitem").executes(|ctx: &Ctx| {
230 let source = ctx.source.lock();
231 source.bot.start_use_item();
232 source.reply("Ok!");
233 1
234 }));
235 commands.register(literal("maxstacksize").executes(|ctx: &Ctx| {
236 let source = ctx.source.lock();
237 let max_stack_size = source
238 .bot
239 .get_held_item()
240 .get_component::<MaxStackSize>()
241 .map_or(-1, |s| s.count);
242 source.reply(format!("{max_stack_size}"));
243 1
244 }));
245
246 commands.register(literal("dimensions").executes(|ctx: &Ctx| {
247 let source = ctx.source.lock();
248 let bot_dimensions = source.bot.dimensions();
249 source.reply(format!("{bot_dimensions:?}"));
250 1
251 }));
252
253 commands.register(literal("players").executes(|ctx: &Ctx| {
254 let source = ctx.source.lock();
255 let player_entities = source
256 .bot
257 .nearest_entities_by::<(), With<metadata::Player>>(|_: ()| true);
258 let tab_list = source.bot.tab_list();
259 for player_entity in player_entities {
260 let uuid = player_entity.uuid();
261 source.reply(format!(
262 "{} - {} ({:?})",
263 player_entity.id(),
264 tab_list.get(&uuid).map_or("?", |p| p.profile.name.as_str()),
265 uuid
266 ));
267 }
268 1
269 }));
270
271 commands.register(literal("enchants").executes(|ctx: &Ctx| {
272 let source = ctx.source.lock();
273 source.bot.with_registry_holder(|r| {
274 let enchants = &r.enchantment;
275 println!("enchants: {enchants:?}");
276 });
277 1
278 }));
279
280 commands.register(literal("attributes").executes(|ctx: &Ctx| {
281 let source = ctx.source.lock();
282 let attributes = source.bot.attributes();
283 println!("attributes: {attributes:?}");
284 1
285 }));
286
287 commands.register(literal("debugecsleak").executes(|ctx: &Ctx| {
288 let source = ctx.source.lock();
289
290 source.reply("Ok!");
291
292
293
294 source.bot.disconnect();
295
296 let ecs = source.bot.ecs.clone();
297 thread::spawn(move || {
298 thread::sleep(Duration::from_secs(1));
299 // dump the ecs
300
301 let mut ecs = ecs.write();
302
303 let report_path = env::temp_dir().join("azalea-ecs-leak-report.txt");
304 let mut report = File::create(&report_path).unwrap();
305
306 let mut query = ecs.query::<EntityRef>();
307 for entity in query.iter(& ecs) {
308 writeln!(report, "Entity: {}", entity.id()).unwrap();
309 let archetype = entity.archetype();
310 let component_count = archetype.component_count();
311
312 let component_names = archetype
313 .components()
314 .iter()
315 .map(|c| ecs.components().get_info(*c).unwrap().name().to_string())
316 .collect::<Vec<_>>();
317 writeln!(
318 report,
319 "- {component_count} components: {}",
320 component_names.join(", ")
321 )
322 .unwrap();
323 }
324
325 writeln!(report).unwrap();
326
327
328 for (info, _) in ecs.iter_resources() {
329 let name = info.name().to_string();
330 writeln!(report, "Resource: {name}").unwrap();
331 // writeln!(report, "- Size: {} bytes",
332 // info.layout().size()).unwrap();
333
334 match name.as_ref() {
335 "azalea_world::container::Worlds" => {
336 let worlds = ecs.resource::<Worlds>();
337
338 for (world_name, world) in &worlds.map {
339 writeln!(report, "- Name: {world_name}").unwrap();
340 writeln!(report, "- Reference count: {}", world.strong_count())
341 .unwrap();
342 if let Some(world) = world.upgrade() {
343 let world = world.read();
344 let strong_chunks = world
345 .chunks
346 .map
347 .iter()
348 .filter(|(_, v)| v.strong_count() > 0)
349 .count();
350 writeln!(
351 report,
352 "- Chunks: {} strongly referenced, {} in map",
353 strong_chunks,
354 world.chunks.map.len()
355 )
356 .unwrap();
357 writeln!(
358 report,
359 "- Entities: {}",
360 world.entities_by_chunk.len()
361 )
362 .unwrap();
363 }
364 }
365 }
366 "bevy_ecs::message::Messages<azalea_client::packet::game::ReceivePacketEvent>" => {
367 let events = ecs.resource::<Messages<game::ReceiveGamePacketEvent>>();
368 writeln!(report, "- Event count: {}", events.len()).unwrap();
369 }
370 "bevy_ecs::message::Messages<azalea_client::chunks::ReceiveChunkEvent>" => {
371 let events = ecs.resource::<Messages<ReceiveChunkEvent>>();
372 writeln!(report, "- Event count: {}", events.len()).unwrap();
373 }
374
375 _ => {}
376 }
377 }
378
379 println!("\x1b[1mWrote report to {}\x1b[m", report_path.display());
380 });
381
382 1
383 }));
384
385 commands.register(literal("exit").executes(|ctx: &Ctx| {
386 let source = ctx.source.lock();
387 source.reply("bye!");
388
389 source.bot.disconnect();
390
391 let source = ctx.source.clone();
392 thread::spawn(move || {
393 thread::sleep(Duration::from_secs(1));
394
395 source
396 .lock()
397 .bot
398 .ecs
399 .write()
400 .write_message(AppExit::Success);
401 });
402
403 1
404 }));
405}