EntityRef

Struct EntityRef 

Source
pub struct EntityRef { /* private fields */ }
Expand description

A reference to an entity in a world.

This is different from [Entity], since you can perform actions with just an EntityRef instead of it only being an identifier.

Most functions on EntityRef that return a value will result in a panic if the client has despawned, so if your code involves waiting, you should check Self::is_alive or Self::exists before calling those functions.

Also, since EntityRef stores the Client alongside the entity, this means that it supports interactions such as Self::attack.

Not to be confused with Bevy’s EntityRef.

Implementations§

Source§

impl EntityRef

Source

pub fn position(&self) -> Vec3

Get the entity’s position in the world, which is the same as its feet position.

To get the client’s eye position, use Self::eye_position.

Also see Client::position.

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

impl EntityRef

Source

pub fn dimensions(&self) -> EntityDimensions

Get the bounding box dimensions for the entity, which contains its width, height, and eye height.

Also see Client::dimensions

Source§

impl EntityRef

Source

pub fn eye_position(&self) -> Vec3

Get the position of this entity’s eyes.

Also see Client::eye_position.

Examples found in repository?
azalea/examples/testbot/commands/movement.rs (line 96)
14pub fn register(commands: &mut CommandDispatcher<Mutex<CommandSource>>) {
15    commands.register(
16        literal("goto")
17            .executes(|ctx: &Ctx| {
18                let 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 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}
Source§

impl EntityRef

Source

pub fn health(&self) -> f32

Get the health of this entity, typically in the range 0..=20.

Also see Client::health.

Source§

impl EntityRef

Source

pub fn uuid(&self) -> Uuid

Get the Minecraft UUID of this entity.

Also see Client::uuid.

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

impl EntityRef

Source

pub fn minecraft_id(&self) -> MinecraftEntityId

Get the Minecraft UUID of this entity.

See MinecraftEntityId for more details. For persistent identifiers, consider using Self::uuid instead.

Also see Client::minecraft_id.

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

impl EntityRef

Source

pub fn attributes(&self) -> Attributes

Returns the attribute values of the entity, which can be used to determine things like its movement speed.

Source§

impl EntityRef

Source

pub fn instance_name(&self) -> InstanceName

Get the name of the instance (world) that the entity is in.

This can be used to check if the entity is in the same world as another entity.

Also see Client::instance_name,

Source§

impl EntityRef

Source

pub fn is_alive(&self) -> bool

Returns whether the entity is alive and hasn’t despawned.

Unlike most functions in EntityRef, this one will not panic if the entity is despawned. Because of this, it may be useful to check is_alive before calling functions that request data from the world.

Also see Client::is_alive and Self::exists.

Source§

impl EntityRef

Source

pub fn exists(&self) -> bool

Returns whether the entity is in the world and hasn’t despawned.

Like Self::is_alive, this will not panic.

Also see Client::exists.

Source§

impl EntityRef

Source

pub fn physics(&self) -> Physics

Returns the complete Physics data for this entity, including velocity, bounding box, collisions, etc.

Also see Client::physics.

Source§

impl EntityRef

Source

pub fn new(client: Client, entity: Entity) -> Self

Source

pub fn id(&self) -> Entity

Returns the ECS identifier for the entity.

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

pub fn component<T: Component>(&self) -> MappedRwLockReadGuard<'_, T>

Get a component on the entity.

This allows you to access certain data stored about the entity that isn’t accessible in a simpler way.

See Client::component for more details.

§Panics

This will panic if the component doesn’t exist on the client. Use Self::get_component to avoid this.

§Examples
let world_name = client.component::<InstanceName>();
Source

pub fn get_component<T: Component>( &self, ) -> Option<MappedRwLockReadGuard<'_, T>>

Get a component on this client, or None if it doesn’t exist.

If the component is guaranteed to be present, consider using Self::component.

See Client::component for more details.

Source

pub fn query_self<D: QueryData, R>( &self, f: impl FnOnce(QueryItem<'_, '_, D>) -> R, ) -> R

Query the ECS for data from the entity.

You can use this to mutate data on the entity.

Also see Client::query_self and Client::query_entity.

§Panics

This will panic if the entity doesn’t exist or is missing a component required by the query. Consider using Self::try_query_self to avoid this.

Source

pub fn try_query_self<D: QueryData, R>( &self, f: impl FnOnce(QueryItem<'_, '_, D>) -> R, ) -> Result<R, QueryEntityError>

Query the ECS for data from the entity, or return an error if the query fails.

Also see Self::query_self.

Source§

impl EntityRef

Source

pub fn kind(&self) -> EntityKind

Returns the type of entity that this is.

Source§

impl EntityRef

Source

pub fn attack(&self)

Attack this entity from the client that created this EntityRef.

Also see Client::attack.

Examples found in repository?
azalea/examples/testbot/killaura.rs (line 29)
9pub fn tick(bot: Client, state: State) -> anyhow::Result<()> {
10    if !state.killaura {
11        return Ok(());
12    }
13    if bot.has_attack_cooldown() {
14        return Ok(());
15    }
16    let bot_position = bot.eye_position();
17
18    let nearest_entity = bot.nearest_entity_by::<&Position, (
19        With<AbstractMonster>,
20        Without<LocalEntity>,
21        Without<Dead>,
22    )>(|position: &Position| {
23        let distance = bot_position.distance_to(**position);
24        distance < 4.
25    });
26
27    if let Some(nearest_entity) = nearest_entity {
28        println!("attacking {nearest_entity:?}");
29        nearest_entity.attack();
30    }
31
32    Ok(())
33}
Source

pub fn interact(&self)

Right-click this entity from the client that created this EntityRef.

See Client::entity_interact for more information.

Source

pub fn look_at(&self)

Look at this entity from the client that created the EntityRef.

Source

pub fn distance_to_client(&self) -> f64

Returns the distance between the client’s feet position and this entity’s feet position.

Trait Implementations§

Source§

impl Clone for EntityRef

Source§

fn clone(&self) -> EntityRef

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for EntityRef

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
§

impl<T> CompatExt for T

§

fn compat(self) -> Compat<T>

Applies the [Compat] adapter by value. Read more
§

fn compat_ref(&self) -> Compat<&T>

Applies the [Compat] adapter by shared reference. Read more
§

fn compat_mut(&mut self) -> Compat<&mut T>

Applies the [Compat] adapter by mutable reference. Read more
§

impl<T> Downcast for T
where T: Any,

§

fn into_any(self: Box<T>) -> Box<dyn Any>

Converts Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.
§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Converts Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
§

fn as_any(&self) -> &(dyn Any + 'static)

Converts &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Converts &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
§

impl<T> DowncastSend for T
where T: Any + Send,

§

fn into_any_send(self: Box<T>) -> Box<dyn Any + Send>

Converts Box<Trait> (where Trait: DowncastSend) to Box<dyn Any + Send>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> IntoResult<T> for T

§

fn into_result(self) -> Result<T, RunSystemError>

Converts this type into the system output type.
§

impl<A> Is for A
where A: Any,

§

fn is<T>() -> bool
where T: Any,

Checks if the current type “is” another type, using a TypeId equality comparison. This is most useful in the context of generic logic. Read more
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> TypeData for T
where T: 'static + Send + Sync + Clone,

§

fn clone_type_data(&self) -> Box<dyn TypeData>

Creates a type-erased clone of this value.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

impl<T> ConditionalSend for T
where T: Send,