Skip to main content

LookDirection

Struct LookDirection 

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

The direction that an entity is looking, in degrees.

To avoid flagging anticheats, consider using Self::update when updating the values of this struct.

Implementations§

Source§

impl LookDirection

Source

pub fn new(y_rot: f32, x_rot: f32) -> Self

Create a new look direction and clamp the x_rot to the allowed values.

Source

pub fn y_rot(&self) -> f32

Returns yaw (left and right) in degrees.

Minecraft allows this to go outside of ±360°, so it won’t necessarily be in any range.

Examples found in repository?
azalea/examples/testbot/commands/debug.rs (line 103)
26pub fn register(commands: &mut CommandDispatcher<Mutex<CommandSource>>) {
27    commands.register(literal("ping").executes(|ctx: &Ctx| {
28        let source = ctx.source.lock();
29        source.reply("pong!");
30        1
31    }));
32    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            1
38        })),
39    );
40
41    commands.register(literal("disconnect").executes(|ctx: &Ctx| {
42        let source = ctx.source.lock();
43        source.bot.disconnect();
44        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 0;
52        };
53        let position = entity.position();
54        source.reply(format!(
55            "You are at {}, {}, {}",
56            position.x, position.y, position.z
57        ));
58        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 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        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        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        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        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        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 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_component::<EntityKindComponent>(r.entity);
134                source.reply(format!(
135                    "I'm looking at {entity_kind} ({:?}) at {}",
136                    r.entity, r.location
137                ));
138            }
139        }
140
141        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            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            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        1
185    }));
186
187    commands.register(literal("pathfinderstate").executes(|ctx: &Ctx| {
188        let source = ctx.source.lock();
189        let pathfinder = source.bot.get_component::<Pathfinder>();
190        let Some(pathfinder) = pathfinder else {
191            source.reply("I don't have the Pathfinder component");
192            return 1;
193        };
194        source.reply(format!(
195            "pathfinder.is_calculating: {}",
196            pathfinder.is_calculating
197        ));
198
199        let executing_path = source.bot.get_component::<ExecutingPath>();
200        let Some(executing_path) = executing_path else {
201            source.reply("I'm not executing a path");
202            return 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        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 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        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        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        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        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        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        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        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        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        1
431    }));
432}
Source

pub fn x_rot(&self) -> f32

Returns pitch (up and down) in degrees.

Clamped to ±90°.

Examples found in repository?
azalea/examples/testbot/commands/debug.rs (line 104)
26pub fn register(commands: &mut CommandDispatcher<Mutex<CommandSource>>) {
27    commands.register(literal("ping").executes(|ctx: &Ctx| {
28        let source = ctx.source.lock();
29        source.reply("pong!");
30        1
31    }));
32    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            1
38        })),
39    );
40
41    commands.register(literal("disconnect").executes(|ctx: &Ctx| {
42        let source = ctx.source.lock();
43        source.bot.disconnect();
44        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 0;
52        };
53        let position = entity.position();
54        source.reply(format!(
55            "You are at {}, {}, {}",
56            position.x, position.y, position.z
57        ));
58        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 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        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        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        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        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        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 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_component::<EntityKindComponent>(r.entity);
134                source.reply(format!(
135                    "I'm looking at {entity_kind} ({:?}) at {}",
136                    r.entity, r.location
137                ));
138            }
139        }
140
141        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            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            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        1
185    }));
186
187    commands.register(literal("pathfinderstate").executes(|ctx: &Ctx| {
188        let source = ctx.source.lock();
189        let pathfinder = source.bot.get_component::<Pathfinder>();
190        let Some(pathfinder) = pathfinder else {
191            source.reply("I don't have the Pathfinder component");
192            return 1;
193        };
194        source.reply(format!(
195            "pathfinder.is_calculating: {}",
196            pathfinder.is_calculating
197        ));
198
199        let executing_path = source.bot.get_component::<ExecutingPath>();
200        let Some(executing_path) = executing_path else {
201            source.reply("I'm not executing a path");
202            return 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        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 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        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        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        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        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        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        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        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        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        1
431    }));
432}
Source

pub fn update(&mut self, new: LookDirection)

Update this look direction to the new value.

This handles relative rotations correctly and with the default Minecraft sensitivity to avoid triggering anticheats.

Source

pub fn update_y_rot(&mut self, new_y_rot: f32)

Update the y_rot (yaw) to the given value, in degrees.

This is a shortcut for Self::update while keeping the x_rot the same.

Source

pub fn update_x_rot(&mut self, new_x_rot: f32)

Update the x_rot (pitch) to the given value, in degrees.

This is a shortcut for Self::update while keeping the y_rot the same.

Source

pub fn update_with_sensitivity(&mut self, new: LookDirection, sensitivity: f32)

Update this look direction to the new value, using the given sensitivity value.

Consider using Self::update instead, which uses 1.0 as the sensitivity (equivalent to 100% sensitivity in Minecraft).

Source

pub fn clamped(self) -> Self

Force the Self::x_rot to be between -90 and 90 degrees, and return the new look direction.

Trait Implementations§

Source§

impl AzBuf for LookDirection

Source§

fn azalea_write(&self, buf: &mut impl Write) -> Result<(), Error>

Source§

fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError>

Source§

impl Clone for LookDirection

Source§

fn clone(&self) -> LookDirection

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

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

Performs copy-assignment from source. Read more
Source§

impl Component for LookDirection
where Self: Send + Sync + 'static,

Source§

const STORAGE_TYPE: StorageType = bevy_ecs::component::StorageType::Table

A constant indicating the storage type used for this component.
Source§

type Mutability = Mutable

A marker type to assist Bevy with determining if this component is mutable, or immutable. Mutable components will have [Component<Mutability = Mutable>], while immutable components will instead have [Component<Mutability = Immutable>]. Read more
Source§

fn register_required_components( _requiree: ComponentId, required_components: &mut RequiredComponentsRegistrator<'_, '_>, )

Registers required components. Read more
Source§

fn clone_behavior() -> ComponentCloneBehavior

Called when registering this component, allowing to override clone function (or disable cloning altogether) for this component. Read more
Source§

fn relationship_accessor() -> Option<ComponentRelationshipAccessor<Self>>

Returns [ComponentRelationshipAccessor] required for working with relationships in dynamic contexts. Read more
§

fn on_add() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>

Gets the on_add [ComponentHook] for this [Component] if one is defined.
§

fn on_insert() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>

Gets the on_insert [ComponentHook] for this [Component] if one is defined.
§

fn on_replace() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>

Gets the on_replace [ComponentHook] for this [Component] if one is defined.
§

fn on_remove() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>

Gets the on_remove [ComponentHook] for this [Component] if one is defined.
§

fn on_despawn() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>

Gets the on_despawn [ComponentHook] for this [Component] if one is defined.
§

fn map_entities<E>(_this: &mut Self, _mapper: &mut E)
where E: EntityMapper,

Maps the entities on this component using the given [EntityMapper]. This is used to remap entities in contexts like scenes and entity cloning. When deriving [Component], this is populated by annotating fields containing entities with #[entities] Read more
Source§

impl Debug for LookDirection

Source§

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

Formats the value using the given formatter. Read more
Source§

impl Default for LookDirection

Source§

fn default() -> LookDirection

Returns the “default value” for a type. Read more
Source§

impl From<(f32, f32)> for LookDirection

Source§

fn from((y_rot, x_rot): (f32, f32)) -> Self

Converts to this type from the input type.
Source§

impl From<LookDirection> for (f32, f32)

Source§

fn from(value: LookDirection) -> Self

Converts to this type from the input type.
Source§

impl Hash for LookDirection

Source§

fn hash<H: Hasher>(&self, state: &mut H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl PartialEq for LookDirection

Source§

fn eq(&self, other: &LookDirection) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Copy for LookDirection

Source§

impl Eq for LookDirection

Source§

impl StructuralPartialEq for LookDirection

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
§

impl<C> Bundle for C
where C: Component,

§

fn component_ids( components: &mut ComponentsRegistrator<'_>, ) -> impl Iterator<Item = ComponentId> + use<C>

§

fn get_component_ids( components: &Components, ) -> impl Iterator<Item = Option<ComponentId>>

Return a iterator over this [Bundle]’s component ids. This will be None if the component has not been registered.
§

impl<C> BundleFromComponents for C
where C: Component,

§

unsafe fn from_components<T, F>(ctx: &mut T, func: &mut F) -> C
where F: for<'a> FnMut(&'a mut T) -> OwningPtr<'a>,

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> 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.
§

impl<T> DynEq for T
where T: Any + Eq,

§

fn dyn_eq(&self, other: &(dyn DynEq + 'static)) -> bool

This method tests for self and other values to be equal. Read more
§

impl<T> DynHash for T
where T: DynEq + Hash,

§

fn dyn_hash(&self, state: &mut dyn Hasher)

Feeds this value into the given Hasher.
§

impl<C> DynamicBundle for C
where C: Component,

§

type Effect = ()

An operation on the entity that happens after inserting this bundle.
§

unsafe fn get_components( ptr: MovingPtr<'_, C>, func: &mut impl FnMut(StorageType, OwningPtr<'_>), ) -> <C as DynamicBundle>::Effect

Moves the components out of the bundle. Read more
§

unsafe fn apply_effect( _ptr: MovingPtr<'_, MaybeUninit<C>>, _entity: &mut EntityWorldMut<'_>, )

Applies the after-effects of spawning this bundle. Read more
§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> FromWorld for T
where T: Default,

§

fn from_world(_world: &mut World) -> T

Creates Self using default().

§

impl<T> Instrument for T

§

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

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

fn in_current_span(self) -> Instrumented<Self>

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

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

Source§

fn into(self) -> U

Calls U::from(self).

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

§

impl<T> IntoResult<T> for T

§

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

Converts this type into the system output type.
§

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

§

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

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

impl<T> 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,