Skip to main content

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) -> AzaleaResult<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/main.rs (line 201)
132async fn handle(bot: Client, event: azalea::Event, state: State) -> eyre::Result<()> {
133    let swarm = bot.resource::<SwarmState>();
134
135    match event {
136        azalea::Event::Init => {
137            bot.set_client_information(ClientInformation {
138                view_distance: 32,
139                ..Default::default()
140            })?;
141            if swarm.args.pathfinder_debug_particles {
142                bot.ecs
143                    .write()
144                    .entity_mut(bot.entity)
145                    .insert(PathfinderDebugParticles);
146            }
147        }
148        azalea::Event::Chat(chat) => {
149            let (Some(username), content) = chat.split_sender_and_content() else {
150                return Ok(());
151            };
152            if username != swarm.args.owner_username {
153                return Ok(());
154            }
155
156            println!("{:?}", chat.message());
157
158            let command = if chat.is_whisper() {
159                Some(content)
160            } else {
161                content.strip_prefix('!').map(|s| s.to_owned())
162            };
163            if let Some(command) = command {
164                match swarm.commands.execute(
165                    command,
166                    Mutex::new(CommandSource {
167                        bot: bot.clone(),
168                        chat: chat.clone(),
169                        state: state.clone(),
170                    }),
171                ) {
172                    Ok(Ok(_)) => {}
173                    Ok(Err(err)) => {
174                        eprintln!("azalea error: {err:?}");
175                        let command_source = CommandSource {
176                            bot,
177                            chat: chat.clone(),
178                            state: state.clone(),
179                        };
180                        command_source.reply(format!("azalea error: {err:?}"));
181                    }
182                    Err(err) => {
183                        eprintln!("{err:?}");
184                        let command_source = CommandSource {
185                            bot,
186                            chat: chat.clone(),
187                            state: state.clone(),
188                        };
189                        command_source.reply(format!("{err:?}"));
190                    }
191                }
192            }
193        }
194        azalea::Event::Tick => {
195            killaura::tick(bot.clone(), state.clone())?;
196
197            if bot.ticks_connected().is_multiple_of(5) {
198                if let Some(following) = &*state.following_entity.lock()
199                    && following.is_alive()
200                {
201                    let goal = RadiusGoal::new(following.position()?, 3.);
202                    if bot.is_calculating_path() {
203                        // keep waiting
204                    } else if !goal.success(bot.position()?.into()) || bot.is_executing_path() {
205                        bot.start_goto_with_opts(
206                            goal,
207                            PathfinderOpts::new()
208                                .retry_on_no_path(false)
209                                .max_timeout(Duration::from_secs(1)),
210                        );
211                    } else {
212                        following.look_at()?;
213                    }
214                }
215            }
216        }
217        azalea::Event::Login => {
218            println!("Got login event")
219        }
220        _ => {}
221    }
222
223    Ok(())
224}
More examples
Hide additional examples
azalea/examples/testbot/commands/movement.rs (line 24)
13pub fn register(commands: &mut Dispatcher) {
14    commands.register(
15        literal("goto")
16            .executes(|ctx: &Ctx| {
17                let source = ctx.source.lock();
18                println!("got goto");
19                // look for the sender
20                let Some(entity) = source.entity() else {
21                    source.reply("I can't see you!");
22                    return Ok(0);
23                };
24                let position = entity.position()?;
25                source.reply("ok");
26                source
27                    .bot
28                    .start_goto(BlockPosGoal(BlockPos::from(position.up(0.5))));
29                Ok(1)
30            })
31            .then(literal("xz").then(argument("x", integer()).then(
32                argument("z", integer()).executes(|ctx: &Ctx| {
33                    let source = ctx.source.lock();
34                    let x = get_integer(ctx, "x").unwrap();
35                    let z = get_integer(ctx, "z").unwrap();
36                    println!("goto xz {x} {z}");
37                    source.reply("ok");
38                    source.bot.start_goto(XZGoal { x, z });
39                    Ok(1)
40                }),
41            )))
42            .then(literal("radius").then(argument("radius", float()).then(
43                argument("x", integer()).then(argument("y", integer()).then(
44                    argument("z", integer()).executes(|ctx: &Ctx| {
45                        let source = ctx.source.lock();
46                        let radius = get_float(ctx, "radius").unwrap();
47                        let x = get_integer(ctx, "x").unwrap();
48                        let y = get_integer(ctx, "y").unwrap();
49                        let z = get_integer(ctx, "z").unwrap();
50                        println!("goto radius {radius}, position: {x} {y} {z}");
51                        source.reply("ok");
52                        source.bot.start_goto(RadiusGoal {
53                            pos: BlockPos::new(x, y, z).center(),
54                            radius,
55                        });
56                        Ok(1)
57                    }),
58                )),
59            )))
60            .then(argument("x", integer()).then(argument("y", integer()).then(
61                argument("z", integer()).executes(|ctx: &Ctx| {
62                    let source = ctx.source.lock();
63                    let x = get_integer(ctx, "x").unwrap();
64                    let y = get_integer(ctx, "y").unwrap();
65                    let z = get_integer(ctx, "z").unwrap();
66                    println!("goto xyz {x} {y} {z}");
67                    source.reply("ok");
68                    source.bot.start_goto(BlockPosGoal(BlockPos::new(x, y, z)));
69                    Ok(1)
70                }),
71            ))),
72    );
73
74    commands.register(literal("follow").executes(|ctx: &Ctx| {
75        let source = ctx.source.lock();
76        println!("got follow");
77        // look for the sender
78        let Some(entity) = source.entity() else {
79            source.reply("I can't see you!");
80            return Ok(0);
81        };
82        source.reply("ok");
83        *source.state.following_entity.lock() = Some(entity);
84        Ok(1)
85    }));
86
87    commands.register(literal("down").executes(|ctx: &Ctx| {
88        let source = ctx.source.clone();
89        let bot = source.lock().bot.clone();
90        let position = BlockPos::from(bot.position()?);
91        tokio::spawn(async move {
92            source.lock().reply("mining...");
93            bot.mine(position.down(1)).await;
94            source.lock().reply("done");
95        });
96        Ok(1)
97    }));
98
99    commands.register(
100        literal("look")
101            .executes(|ctx: &Ctx| {
102                // look for the sender
103                let source = ctx.source.lock();
104                let Some(entity) = source.entity() else {
105                    source.reply("I can't see you!");
106                    return Ok(0);
107                };
108                let eye_position = entity.eye_position()?;
109                source.bot.look_at(eye_position);
110                Ok(1)
111            })
112            .then(argument("x", integer()).then(argument("y", integer()).then(
113                argument("z", integer()).executes(|ctx: &Ctx| {
114                    let pos = BlockPos::new(
115                        get_integer(ctx, "x").unwrap(),
116                        get_integer(ctx, "y").unwrap(),
117                        get_integer(ctx, "z").unwrap(),
118                    );
119                    println!("{pos:?}");
120                    let source = ctx.source.lock();
121                    source.bot.look_at(pos.center());
122                    Ok(1)
123                }),
124            ))),
125    );
126
127    commands.register(
128        literal("walk").then(argument("seconds", float()).executes(|ctx: &Ctx| {
129            let mut seconds = get_float(ctx, "seconds").unwrap();
130            let source = ctx.source.lock();
131            let bot = source.bot.clone();
132
133            if seconds < 0. {
134                bot.walk(WalkDirection::Backward);
135                seconds = -seconds;
136            } else {
137                bot.walk(WalkDirection::Forward);
138            }
139
140            tokio::spawn(async move {
141                tokio::time::sleep(Duration::from_secs_f32(seconds)).await;
142                bot.walk(WalkDirection::None);
143            });
144            source.reply(format!("ok, walking for {seconds} seconds"));
145            Ok(1)
146        })),
147    );
148    commands.register(
149        literal("sprint").then(argument("seconds", float()).executes(|ctx: &Ctx| {
150            let seconds = get_float(ctx, "seconds").unwrap();
151            let source = ctx.source.lock();
152            let bot = source.bot.clone();
153            bot.sprint(SprintDirection::Forward);
154            tokio::spawn(async move {
155                tokio::time::sleep(Duration::from_secs_f32(seconds)).await;
156                bot.walk(WalkDirection::None);
157            });
158            source.reply(format!("ok, sprinting for {seconds} seconds"));
159            Ok(1)
160        })),
161    );
162
163    commands.register(literal("north").executes(|ctx: &Ctx| {
164        let source = ctx.source.lock();
165        source.bot.set_direction(180., 0.)?;
166        source.reply("ok");
167        Ok(1)
168    }));
169    commands.register(literal("south").executes(|ctx: &Ctx| {
170        let source = ctx.source.lock();
171        source.bot.set_direction(0., 0.)?;
172        source.reply("ok");
173        Ok(1)
174    }));
175    commands.register(literal("east").executes(|ctx: &Ctx| {
176        let source = ctx.source.lock();
177        source.bot.set_direction(-90., 0.)?;
178        source.reply("ok");
179        Ok(1)
180    }));
181    commands.register(literal("west").executes(|ctx: &Ctx| {
182        let source = ctx.source.lock();
183        source.bot.set_direction(90., 0.)?;
184        source.reply("ok");
185        Ok(1)
186    }));
187    commands.register(
188        literal("jump")
189            .executes(|ctx: &Ctx| {
190                let source = ctx.source.lock();
191                source.bot.jump();
192                source.reply("ok");
193                Ok(1)
194            })
195            .then(argument("enabled", bool()).executes(|ctx: &Ctx| {
196                let jumping = get_bool(ctx, "enabled").unwrap();
197                let source = ctx.source.lock();
198                source.bot.set_jumping(jumping)?;
199                Ok(1)
200            })),
201    );
202
203    let sneak = |ctx: &Ctx| {
204        let source = ctx.source.lock();
205        source.bot.set_crouching(!source.bot.crouching())?;
206        source.reply("ok");
207        Ok(1)
208    };
209    let sneak_enabled = argument("enabled", bool()).executes(|ctx: &Ctx| {
210        let sneaking = get_bool(ctx, "enabled").unwrap();
211        let source = ctx.source.lock();
212        source.bot.set_crouching(sneaking)?;
213        Ok(1)
214    });
215    commands.register(literal("sneak").executes(sneak).then(sneak_enabled.clone()));
216    commands.register(literal("crouch").executes(sneak).then(sneak_enabled));
217
218    commands.register(literal("stop").executes(|ctx: &Ctx| {
219        let source = ctx.source.lock();
220        source.bot.stop_pathfinding();
221        source.reply("ok");
222        *source.state.following_entity.lock() = None;
223        Ok(1)
224    }));
225    commands.register(literal("forcestop").executes(|ctx: &Ctx| {
226        let source = ctx.source.lock();
227        source.bot.force_stop_pathfinding();
228        source.reply("ok");
229        *source.state.following_entity.lock() = None;
230        Ok(1)
231    }));
232}
azalea/examples/testbot/commands/debug.rs (line 53)
26pub fn register(commands: &mut Dispatcher) {
27    commands.register(literal("ping").executes(|ctx: &Ctx| {
28        let source = ctx.source.lock();
29        source.reply("pong!");
30        Ok(1)
31    }));
32    commands.register(
33        literal("say").then(argument("message", greedy_string()).executes(|ctx: &Ctx| {
34            let source = ctx.source.lock();
35            let message = get_string(ctx, "message").unwrap();
36            source.bot.chat(message);
37            Ok(1)
38        })),
39    );
40
41    commands.register(literal("disconnect").executes(|ctx: &Ctx| {
42        let source = ctx.source.lock();
43        source.bot.disconnect();
44        Ok(1)
45    }));
46
47    commands.register(literal("whereami").executes(|ctx: &Ctx| {
48        let source = ctx.source.lock();
49        let Some(entity) = source.entity() else {
50            source.reply("You aren't in render distance!");
51            return Ok(0);
52        };
53        let position = entity.position()?;
54        source.reply(format!(
55            "You are at {}, {}, {}",
56            position.x, position.y, position.z
57        ));
58        Ok(1)
59    }));
60
61    commands.register(literal("entityid").executes(|ctx: &Ctx| {
62        let source = ctx.source.lock();
63        let Some(entity) = source.entity() else {
64            source.reply("You aren't in render distance!");
65            return Ok(0);
66        };
67        let entity_id = entity.minecraft_id()?;
68        source.reply(format!(
69            "Your Minecraft ID is {} and your ECS ID is {entity:?}",
70            *entity_id
71        ));
72        Ok(1)
73    }));
74
75    let whereareyou = |ctx: &Ctx| {
76        let source = ctx.source.lock();
77        let position = source.bot.position()?;
78        source.reply(format!(
79            "I'm at {}, {}, {}",
80            position.x, position.y, position.z
81        ));
82        Ok(1)
83    };
84    commands.register(literal("whereareyou").executes(whereareyou));
85    commands.register(literal("pos").executes(whereareyou));
86
87    commands.register(literal("whoareyou").executes(|ctx: &Ctx| {
88        let source = ctx.source.lock();
89        source.reply(format!(
90            "I am {} ({}, {})",
91            source.bot.username(),
92            source.bot.uuid(),
93            source.bot.entity
94        ));
95        Ok(1)
96    }));
97
98    commands.register(literal("getdirection").executes(|ctx: &Ctx| {
99        let source = ctx.source.lock();
100        let direction = source.bot.direction()?;
101        source.reply(format!(
102            "I'm looking at {}, {}",
103            direction.y_rot(),
104            direction.x_rot()
105        ));
106        Ok(1)
107    }));
108
109    commands.register(literal("health").executes(|ctx: &Ctx| {
110        let source = ctx.source.lock();
111
112        let health = source.bot.health()?;
113        source.reply(format!("I have {health} health"));
114        Ok(1)
115    }));
116
117    commands.register(literal("lookingat").executes(|ctx: &Ctx| {
118        let source = ctx.source.lock();
119
120        let hit_result = source.bot.hit_result()?;
121
122        match &hit_result {
123            HitResult::Block(r) => {
124                if r.miss {
125                    source.reply("I'm not looking at anything");
126                    return Ok(0);
127                }
128                let block_pos = r.block_pos;
129                let block = source.bot.world()?.read().get_block_state(block_pos);
130                source.reply(format!("I'm looking at {block:?} at {block_pos:?}"));
131            }
132            HitResult::Entity(r) => {
133                let entity_kind = source.bot.entity_ref_for(r.entity).kind()?;
134                source.reply(format!(
135                    "I'm looking at {entity_kind} ({:?}) at {}",
136                    r.entity, r.location
137                ));
138            }
139        }
140
141        Ok(1)
142    }));
143
144    commands.register(literal("getblock").then(argument("x", integer()).then(
145        argument("y", integer()).then(argument("z", integer()).executes(|ctx: &Ctx| {
146            let source = ctx.source.lock();
147            let x = get_integer(ctx, "x").unwrap();
148            let y = get_integer(ctx, "y").unwrap();
149            let z = get_integer(ctx, "z").unwrap();
150            println!("getblock xyz {x} {y} {z}");
151            let block_pos = BlockPos::new(x, y, z);
152            let block = source.bot.world()?.read().get_block_state(block_pos);
153            source.reply(format!("BlockKind at {block_pos} is {block:?}"));
154            Ok(1)
155        })),
156    )));
157    commands.register(literal("getfluid").then(argument("x", integer()).then(
158        argument("y", integer()).then(argument("z", integer()).executes(|ctx: &Ctx| {
159            let source = ctx.source.lock();
160            let x = get_integer(ctx, "x").unwrap();
161            let y = get_integer(ctx, "y").unwrap();
162            let z = get_integer(ctx, "z").unwrap();
163            println!("getfluid xyz {x} {y} {z}");
164            let block_pos = BlockPos::new(x, y, z);
165            let block = source.bot.world()?.read().get_fluid_state(block_pos);
166            source.reply(format!("Fluid at {block_pos} is {block:?}"));
167            Ok(1)
168        })),
169    )));
170
171    commands.register(literal("inventory").executes(|ctx: &Ctx| {
172        let source = ctx.source.lock();
173        for item in source.bot.menu()?.slots() {
174            if item.is_empty() {
175                continue;
176            }
177            println!("{item:?}");
178            for (kind, data) in item.component_patch().iter() {
179                if let Some(data) = data {
180                    println!("- {kind} {data:?}");
181                }
182            }
183        }
184        Ok(1)
185    }));
186
187    commands.register(literal("pathfinderstate").executes(|ctx: &Ctx| {
188        let source = ctx.source.lock();
189        let pathfinder = source.bot.component::<Pathfinder>();
190        let Ok(pathfinder) = pathfinder else {
191            source.reply("I don't have the Pathfinder component");
192            return Ok(1);
193        };
194        source.reply(format!(
195            "pathfinder.is_calculating: {}",
196            pathfinder.is_calculating
197        ));
198
199        let executing_path = source.bot.component::<ExecutingPath>();
200        let Ok(executing_path) = executing_path else {
201            source.reply("I'm not executing a path");
202            return Ok(1);
203        };
204        source.reply(format!(
205            "is_path_partial: {}, path.len: {}, queued_path.len: {}",
206            executing_path.is_path_partial,
207            executing_path.path.len(),
208            if let Some(queued) = &executing_path.queued_path {
209                queued.len().to_string()
210            } else {
211                "n/a".to_owned()
212            },
213        ));
214        Ok(1)
215    }));
216    commands.register(literal("pathfindermoves").executes(|ctx: &Ctx| {
217        let source = ctx.source.lock();
218
219        let Some(entity) = source.entity() else {
220            source.reply("You aren't in render distance!");
221            return Ok(0);
222        };
223        let position = entity.position()?;
224        let position = BlockPos::from(position);
225
226        let mut edges = Vec::new();
227        let cached_world = CachedWorld::new(source.bot.world()?, position);
228        let mining_cache = MiningCache::new(Some(Menu::Player(inventory::Player::default())));
229        let custom_state = CustomPathfinderStateRef::default();
230
231        azalea::pathfinder::moves::default_move(
232            &mut MovesCtx {
233                edges: &mut edges,
234                world: &cached_world,
235                mining_cache: &mining_cache,
236                custom_state: &custom_state,
237            },
238            RelBlockPos::from_origin(position, position),
239        );
240
241        if edges.is_empty() {
242            source.reply("No possible moves.");
243        } else {
244            source.reply("Moves:");
245            for (i, edge) in edges.iter().enumerate() {
246                source.reply(format!("{}) {edge:?}", i + 1));
247            }
248        }
249
250        Ok(1)
251    }));
252
253    commands.register(literal("startuseitem").executes(|ctx: &Ctx| {
254        let source = ctx.source.lock();
255        source.bot.start_use_item();
256        source.reply("Ok!");
257        Ok(1)
258    }));
259    commands.register(literal("maxstacksize").executes(|ctx: &Ctx| {
260        let source = ctx.source.lock();
261        let max_stack_size = source
262            .bot
263            .get_held_item()?
264            .get_component::<MaxStackSize>()
265            .map_or(-1, |s| s.count);
266        source.reply(format!("{max_stack_size}"));
267        Ok(1)
268    }));
269
270    commands.register(literal("dimensions").executes(|ctx: &Ctx| {
271        let source = ctx.source.lock();
272        let bot_dimensions = source.bot.dimensions();
273        source.reply(format!("{bot_dimensions:?}"));
274        Ok(1)
275    }));
276
277    commands.register(literal("players").executes(|ctx: &Ctx| {
278        let source = ctx.source.lock();
279        let player_entities = source
280            .bot
281            .nearest_entities_by::<(), With<metadata::Player>>(|_: ()| true)?;
282        let tab_list = source.bot.tab_list()?;
283        for player_entity in player_entities {
284            let uuid = player_entity.uuid()?;
285            source.reply(format!(
286                "{} - {} ({:?})",
287                player_entity.id(),
288                tab_list.get(&uuid).map_or("?", |p| p.profile.name.as_str()),
289                uuid
290            ));
291        }
292        Ok(1)
293    }));
294
295    commands.register(literal("enchants").executes(|ctx: &Ctx| {
296        let source = ctx.source.lock();
297        source.bot.with_registry_holder(|r| {
298            let enchants = &r.enchantment;
299            println!("enchants: {enchants:?}");
300        })?;
301        Ok(1)
302    }));
303
304    commands.register(literal("attributes").executes(|ctx: &Ctx| {
305        let source = ctx.source.lock();
306        let attributes = source.bot.attributes();
307        println!("attributes: {attributes:?}");
308        Ok(1)
309    }));
310
311    commands.register(literal("debugecsleak").executes(|ctx: &Ctx| {
312        let source = ctx.source.lock();
313
314        source.reply("Ok!");
315
316
317
318        source.bot.disconnect();
319
320        let ecs = source.bot.ecs.clone();
321        thread::spawn(move || {
322            thread::sleep(Duration::from_secs(1));
323            // dump the ecs
324
325            let mut ecs = ecs.write();
326
327            let report_path = env::temp_dir().join("azalea-ecs-leak-report.txt");
328            let mut report = File::create(&report_path).unwrap();
329
330            let mut query = ecs.query::<EntityRef>();
331            for entity in query.iter(& ecs) {
332                writeln!(report, "Entity: {}", entity.id()).unwrap();
333                let archetype = entity.archetype();
334                let component_count = archetype.component_count();
335
336                let component_names = archetype
337                    .components()
338                    .iter()
339                    .map(|c| ecs.components().get_info(*c).unwrap().name().to_string())
340                    .collect::<Vec<_>>();
341                writeln!(
342                    report,
343                    "- {component_count} components: {}",
344                    component_names.join(", ")
345                )
346                .unwrap();
347            }
348
349            writeln!(report).unwrap();
350
351
352            for (info, _) in ecs.iter_resources() {
353                let name = info.name().to_string();
354                writeln!(report, "Resource: {name}").unwrap();
355                // writeln!(report, "- Size: {} bytes",
356                // info.layout().size()).unwrap();
357
358                match name.as_ref() {
359                    "azalea_world::container::Worlds" => {
360                        let worlds = ecs.resource::<Worlds>();
361
362                        for (world_name, world) in &worlds.map {
363                            writeln!(report, "- Name: {world_name}").unwrap();
364                            writeln!(report, "- Reference count: {}", world.strong_count())
365                                .unwrap();
366                            if let Some(world) = world.upgrade() {
367                                let world = world.read();
368                                let chunks = &world.chunks;
369                                let chunks = (chunks as &dyn Any).downcast_ref::<WeakChunkStorage>();
370                                if let Some(chunks) = chunks {
371                                    let strong_chunks = chunks
372                                        .map
373                                        .iter()
374                                        .filter(|(_, v)| v.strong_count() > 0)
375                                        .count();
376                                    writeln!(
377                                        report,
378                                        "- Chunks: {} strongly referenced, {} in map",
379                                        strong_chunks,
380                                        chunks.map.len()
381                                    )
382                                    .unwrap();
383                                }
384                                writeln!(
385                                    report,
386                                    "- Entities: {}",
387                                    world.entities_by_chunk.len()
388                                )
389                                .unwrap();
390                            }
391                        }
392                    }
393                    "bevy_ecs::message::Messages<azalea_client::packet::game::ReceivePacketEvent>" => {
394                        let events = ecs.resource::<Messages<game::ReceiveGamePacketEvent>>();
395                        writeln!(report, "- Event count: {}", events.len()).unwrap();
396                    }
397                    "bevy_ecs::message::Messages<azalea_client::chunks::ReceiveChunkEvent>" => {
398                        let events = ecs.resource::<Messages<ReceiveChunkEvent>>();
399                        writeln!(report, "- Event count: {}", events.len()).unwrap();
400                    }
401
402                    _ => {}
403                }
404            }
405
406            println!("\x1b[1mWrote report to {}\x1b[m", report_path.display());
407        });
408
409        Ok(1)
410    }));
411
412    commands.register(literal("exit").executes(|ctx: &Ctx| {
413        let source = ctx.source.lock();
414        source.reply("bye!");
415
416        source.bot.disconnect();
417
418        let source = ctx.source.clone();
419        thread::spawn(move || {
420            thread::sleep(Duration::from_secs(1));
421
422            source
423                .lock()
424                .bot
425                .ecs
426                .write()
427                .write_message(AppExit::Success);
428        });
429
430        Ok(1)
431    }));
432}
Source§

impl EntityRef

Source

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

impl EntityRef

Source

pub fn health(&self) -> AzaleaResult<f32>

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

Also see Client::health.

Source§

impl EntityRef

Source

pub fn minecraft_id(&self) -> AzaleaResult<MinecraftEntityId>

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

impl EntityRef

Source

pub fn attributes(&self) -> AzaleaResult<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 world_name(&self) -> AzaleaResult<WorldName>

Get the name of the 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::world_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.

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

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

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::<WorldName>();
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, ) -> AzaleaResult<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.

§Errors

This will return an error if the entity doesn’t exist or is missing a component required by the query.

Source§

impl EntityRef

Source

pub fn kind(&self) -> AzaleaResult<EntityKind>

Returns the type of entity that this is.

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

pub fn uuid(&self) -> AzaleaResult<Uuid>

Get the Minecraft UUID of this entity.

Also see Client::uuid.

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

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

Examples found in repository?
azalea/examples/testbot/main.rs (line 212)
132async fn handle(bot: Client, event: azalea::Event, state: State) -> eyre::Result<()> {
133    let swarm = bot.resource::<SwarmState>();
134
135    match event {
136        azalea::Event::Init => {
137            bot.set_client_information(ClientInformation {
138                view_distance: 32,
139                ..Default::default()
140            })?;
141            if swarm.args.pathfinder_debug_particles {
142                bot.ecs
143                    .write()
144                    .entity_mut(bot.entity)
145                    .insert(PathfinderDebugParticles);
146            }
147        }
148        azalea::Event::Chat(chat) => {
149            let (Some(username), content) = chat.split_sender_and_content() else {
150                return Ok(());
151            };
152            if username != swarm.args.owner_username {
153                return Ok(());
154            }
155
156            println!("{:?}", chat.message());
157
158            let command = if chat.is_whisper() {
159                Some(content)
160            } else {
161                content.strip_prefix('!').map(|s| s.to_owned())
162            };
163            if let Some(command) = command {
164                match swarm.commands.execute(
165                    command,
166                    Mutex::new(CommandSource {
167                        bot: bot.clone(),
168                        chat: chat.clone(),
169                        state: state.clone(),
170                    }),
171                ) {
172                    Ok(Ok(_)) => {}
173                    Ok(Err(err)) => {
174                        eprintln!("azalea error: {err:?}");
175                        let command_source = CommandSource {
176                            bot,
177                            chat: chat.clone(),
178                            state: state.clone(),
179                        };
180                        command_source.reply(format!("azalea error: {err:?}"));
181                    }
182                    Err(err) => {
183                        eprintln!("{err:?}");
184                        let command_source = CommandSource {
185                            bot,
186                            chat: chat.clone(),
187                            state: state.clone(),
188                        };
189                        command_source.reply(format!("{err:?}"));
190                    }
191                }
192            }
193        }
194        azalea::Event::Tick => {
195            killaura::tick(bot.clone(), state.clone())?;
196
197            if bot.ticks_connected().is_multiple_of(5) {
198                if let Some(following) = &*state.following_entity.lock()
199                    && following.is_alive()
200                {
201                    let goal = RadiusGoal::new(following.position()?, 3.);
202                    if bot.is_calculating_path() {
203                        // keep waiting
204                    } else if !goal.success(bot.position()?.into()) || bot.is_executing_path() {
205                        bot.start_goto_with_opts(
206                            goal,
207                            PathfinderOpts::new()
208                                .retry_on_no_path(false)
209                                .max_timeout(Duration::from_secs(1)),
210                        );
211                    } else {
212                        following.look_at()?;
213                    }
214                }
215            }
216        }
217        azalea::Event::Login => {
218            println!("Got login event")
219        }
220        _ => {}
221    }
222
223    Ok(())
224}
Source

pub fn distance_to_client(&self) -> AzaleaResult<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 (const: unstable) · 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.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

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,