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("pathfinderstate").executes(|ctx: &Ctx| {
172        let source = ctx.source.lock();
173        let pathfinder = source.bot.get_component::<Pathfinder>();
174        let Some(pathfinder) = pathfinder else {
175            source.reply("I don't have the Pathfinder component");
176            return 1;
177        };
178        source.reply(format!(
179            "pathfinder.is_calculating: {}",
180            pathfinder.is_calculating
181        ));
182
183        let executing_path = source.bot.get_component::<ExecutingPath>();
184        let Some(executing_path) = executing_path else {
185            source.reply("I'm not executing a path");
186            return 1;
187        };
188        source.reply(format!(
189            "is_path_partial: {}, path.len: {}, queued_path.len: {}",
190            executing_path.is_path_partial,
191            executing_path.path.len(),
192            if let Some(queued) = &executing_path.queued_path {
193                queued.len().to_string()
194            } else {
195                "n/a".to_owned()
196            },
197        ));
198        1
199    }));
200    commands.register(literal("pathfindermoves").executes(|ctx: &Ctx| {
201        let source = ctx.source.lock();
202
203        let Some(entity) = source.entity() else {
204            source.reply("You aren't in render distance!");
205            return 0;
206        };
207        let position = entity.position();
208        let position = BlockPos::from(position);
209
210        let mut edges = Vec::new();
211        let cached_world = CachedWorld::new(source.bot.world(), position);
212        let mining_cache = MiningCache::new(Some(Menu::Player(inventory::Player::default())));
213        let custom_state = CustomPathfinderStateRef::default();
214
215        azalea::pathfinder::moves::default_move(
216            &mut MovesCtx {
217                edges: &mut edges,
218                world: &cached_world,
219                mining_cache: &mining_cache,
220                custom_state: &custom_state,
221            },
222            RelBlockPos::from_origin(position, position),
223        );
224
225        if edges.is_empty() {
226            source.reply("No possible moves.");
227        } else {
228            source.reply("Moves:");
229            for (i, edge) in edges.iter().enumerate() {
230                source.reply(format!("{}) {edge:?}", i + 1));
231            }
232        }
233
234        1
235    }));
236
237    commands.register(literal("startuseitem").executes(|ctx: &Ctx| {
238        let source = ctx.source.lock();
239        source.bot.start_use_item();
240        source.reply("Ok!");
241        1
242    }));
243    commands.register(literal("maxstacksize").executes(|ctx: &Ctx| {
244        let source = ctx.source.lock();
245        let max_stack_size = source
246            .bot
247            .get_held_item()
248            .get_component::<MaxStackSize>()
249            .map_or(-1, |s| s.count);
250        source.reply(format!("{max_stack_size}"));
251        1
252    }));
253
254    commands.register(literal("dimensions").executes(|ctx: &Ctx| {
255        let source = ctx.source.lock();
256        let bot_dimensions = source.bot.dimensions();
257        source.reply(format!("{bot_dimensions:?}"));
258        1
259    }));
260
261    commands.register(literal("players").executes(|ctx: &Ctx| {
262        let source = ctx.source.lock();
263        let player_entities = source
264            .bot
265            .nearest_entities_by::<(), With<metadata::Player>>(|_: ()| true);
266        let tab_list = source.bot.tab_list();
267        for player_entity in player_entities {
268            let uuid = player_entity.uuid();
269            source.reply(format!(
270                "{} - {} ({:?})",
271                player_entity.id(),
272                tab_list.get(&uuid).map_or("?", |p| p.profile.name.as_str()),
273                uuid
274            ));
275        }
276        1
277    }));
278
279    commands.register(literal("enchants").executes(|ctx: &Ctx| {
280        let source = ctx.source.lock();
281        source.bot.with_registry_holder(|r| {
282            let enchants = &r.enchantment;
283            println!("enchants: {enchants:?}");
284        });
285        1
286    }));
287
288    commands.register(literal("attributes").executes(|ctx: &Ctx| {
289        let source = ctx.source.lock();
290        let attributes = source.bot.attributes();
291        println!("attributes: {attributes:?}");
292        1
293    }));
294
295    commands.register(literal("debugecsleak").executes(|ctx: &Ctx| {
296        let source = ctx.source.lock();
297
298        source.reply("Ok!");
299
300
301
302        source.bot.disconnect();
303
304        let ecs = source.bot.ecs.clone();
305        thread::spawn(move || {
306            thread::sleep(Duration::from_secs(1));
307            // dump the ecs
308
309            let mut ecs = ecs.write();
310
311            let report_path = env::temp_dir().join("azalea-ecs-leak-report.txt");
312            let mut report = File::create(&report_path).unwrap();
313
314            let mut query = ecs.query::<EntityRef>();
315            for entity in query.iter(& ecs) {
316                writeln!(report, "Entity: {}", entity.id()).unwrap();
317                let archetype = entity.archetype();
318                let component_count = archetype.component_count();
319
320                let component_names = archetype
321                    .components()
322                    .iter()
323                    .map(|c| ecs.components().get_info(*c).unwrap().name().to_string())
324                    .collect::<Vec<_>>();
325                writeln!(
326                    report,
327                    "- {component_count} components: {}",
328                    component_names.join(", ")
329                )
330                .unwrap();
331            }
332
333            writeln!(report).unwrap();
334
335
336            for (info, _) in ecs.iter_resources() {
337                let name = info.name().to_string();
338                writeln!(report, "Resource: {name}").unwrap();
339                // writeln!(report, "- Size: {} bytes",
340                // info.layout().size()).unwrap();
341
342                match name.as_ref() {
343                    "azalea_world::container::Worlds" => {
344                        let worlds = ecs.resource::<Worlds>();
345
346                        for (world_name, world) in &worlds.map {
347                            writeln!(report, "- Name: {world_name}").unwrap();
348                            writeln!(report, "- Reference count: {}", world.strong_count())
349                                .unwrap();
350                            if let Some(world) = world.upgrade() {
351                                let world = world.read();
352                                let strong_chunks = world
353                                    .chunks
354                                    .map
355                                    .iter()
356                                    .filter(|(_, v)| v.strong_count() > 0)
357                                    .count();
358                                writeln!(
359                                    report,
360                                    "- Chunks: {} strongly referenced, {} in map",
361                                    strong_chunks,
362                                    world.chunks.map.len()
363                                )
364                                .unwrap();
365                                writeln!(
366                                    report,
367                                    "- Entities: {}",
368                                    world.entities_by_chunk.len()
369                                )
370                                .unwrap();
371                            }
372                        }
373                    }
374                    "bevy_ecs::message::Messages<azalea_client::packet::game::ReceivePacketEvent>" => {
375                        let events = ecs.resource::<Messages<game::ReceiveGamePacketEvent>>();
376                        writeln!(report, "- Event count: {}", events.len()).unwrap();
377                    }
378                    "bevy_ecs::message::Messages<azalea_client::chunks::ReceiveChunkEvent>" => {
379                        let events = ecs.resource::<Messages<ReceiveChunkEvent>>();
380                        writeln!(report, "- Event count: {}", events.len()).unwrap();
381                    }
382
383                    _ => {}
384                }
385            }
386
387            println!("\x1b[1mWrote report to {}\x1b[m", report_path.display());
388        });
389
390        1
391    }));
392
393    commands.register(literal("exit").executes(|ctx: &Ctx| {
394        let source = ctx.source.lock();
395        source.reply("bye!");
396
397        source.bot.disconnect();
398
399        let source = ctx.source.clone();
400        thread::spawn(move || {
401            thread::sleep(Duration::from_secs(1));
402
403            source
404                .lock()
405                .bot
406                .ecs
407                .write()
408                .write_message(AppExit::Success);
409        });
410
411        1
412    }));
413}
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("pathfinderstate").executes(|ctx: &Ctx| {
172        let source = ctx.source.lock();
173        let pathfinder = source.bot.get_component::<Pathfinder>();
174        let Some(pathfinder) = pathfinder else {
175            source.reply("I don't have the Pathfinder component");
176            return 1;
177        };
178        source.reply(format!(
179            "pathfinder.is_calculating: {}",
180            pathfinder.is_calculating
181        ));
182
183        let executing_path = source.bot.get_component::<ExecutingPath>();
184        let Some(executing_path) = executing_path else {
185            source.reply("I'm not executing a path");
186            return 1;
187        };
188        source.reply(format!(
189            "is_path_partial: {}, path.len: {}, queued_path.len: {}",
190            executing_path.is_path_partial,
191            executing_path.path.len(),
192            if let Some(queued) = &executing_path.queued_path {
193                queued.len().to_string()
194            } else {
195                "n/a".to_owned()
196            },
197        ));
198        1
199    }));
200    commands.register(literal("pathfindermoves").executes(|ctx: &Ctx| {
201        let source = ctx.source.lock();
202
203        let Some(entity) = source.entity() else {
204            source.reply("You aren't in render distance!");
205            return 0;
206        };
207        let position = entity.position();
208        let position = BlockPos::from(position);
209
210        let mut edges = Vec::new();
211        let cached_world = CachedWorld::new(source.bot.world(), position);
212        let mining_cache = MiningCache::new(Some(Menu::Player(inventory::Player::default())));
213        let custom_state = CustomPathfinderStateRef::default();
214
215        azalea::pathfinder::moves::default_move(
216            &mut MovesCtx {
217                edges: &mut edges,
218                world: &cached_world,
219                mining_cache: &mining_cache,
220                custom_state: &custom_state,
221            },
222            RelBlockPos::from_origin(position, position),
223        );
224
225        if edges.is_empty() {
226            source.reply("No possible moves.");
227        } else {
228            source.reply("Moves:");
229            for (i, edge) in edges.iter().enumerate() {
230                source.reply(format!("{}) {edge:?}", i + 1));
231            }
232        }
233
234        1
235    }));
236
237    commands.register(literal("startuseitem").executes(|ctx: &Ctx| {
238        let source = ctx.source.lock();
239        source.bot.start_use_item();
240        source.reply("Ok!");
241        1
242    }));
243    commands.register(literal("maxstacksize").executes(|ctx: &Ctx| {
244        let source = ctx.source.lock();
245        let max_stack_size = source
246            .bot
247            .get_held_item()
248            .get_component::<MaxStackSize>()
249            .map_or(-1, |s| s.count);
250        source.reply(format!("{max_stack_size}"));
251        1
252    }));
253
254    commands.register(literal("dimensions").executes(|ctx: &Ctx| {
255        let source = ctx.source.lock();
256        let bot_dimensions = source.bot.dimensions();
257        source.reply(format!("{bot_dimensions:?}"));
258        1
259    }));
260
261    commands.register(literal("players").executes(|ctx: &Ctx| {
262        let source = ctx.source.lock();
263        let player_entities = source
264            .bot
265            .nearest_entities_by::<(), With<metadata::Player>>(|_: ()| true);
266        let tab_list = source.bot.tab_list();
267        for player_entity in player_entities {
268            let uuid = player_entity.uuid();
269            source.reply(format!(
270                "{} - {} ({:?})",
271                player_entity.id(),
272                tab_list.get(&uuid).map_or("?", |p| p.profile.name.as_str()),
273                uuid
274            ));
275        }
276        1
277    }));
278
279    commands.register(literal("enchants").executes(|ctx: &Ctx| {
280        let source = ctx.source.lock();
281        source.bot.with_registry_holder(|r| {
282            let enchants = &r.enchantment;
283            println!("enchants: {enchants:?}");
284        });
285        1
286    }));
287
288    commands.register(literal("attributes").executes(|ctx: &Ctx| {
289        let source = ctx.source.lock();
290        let attributes = source.bot.attributes();
291        println!("attributes: {attributes:?}");
292        1
293    }));
294
295    commands.register(literal("debugecsleak").executes(|ctx: &Ctx| {
296        let source = ctx.source.lock();
297
298        source.reply("Ok!");
299
300
301
302        source.bot.disconnect();
303
304        let ecs = source.bot.ecs.clone();
305        thread::spawn(move || {
306            thread::sleep(Duration::from_secs(1));
307            // dump the ecs
308
309            let mut ecs = ecs.write();
310
311            let report_path = env::temp_dir().join("azalea-ecs-leak-report.txt");
312            let mut report = File::create(&report_path).unwrap();
313
314            let mut query = ecs.query::<EntityRef>();
315            for entity in query.iter(& ecs) {
316                writeln!(report, "Entity: {}", entity.id()).unwrap();
317                let archetype = entity.archetype();
318                let component_count = archetype.component_count();
319
320                let component_names = archetype
321                    .components()
322                    .iter()
323                    .map(|c| ecs.components().get_info(*c).unwrap().name().to_string())
324                    .collect::<Vec<_>>();
325                writeln!(
326                    report,
327                    "- {component_count} components: {}",
328                    component_names.join(", ")
329                )
330                .unwrap();
331            }
332
333            writeln!(report).unwrap();
334
335
336            for (info, _) in ecs.iter_resources() {
337                let name = info.name().to_string();
338                writeln!(report, "Resource: {name}").unwrap();
339                // writeln!(report, "- Size: {} bytes",
340                // info.layout().size()).unwrap();
341
342                match name.as_ref() {
343                    "azalea_world::container::Worlds" => {
344                        let worlds = ecs.resource::<Worlds>();
345
346                        for (world_name, world) in &worlds.map {
347                            writeln!(report, "- Name: {world_name}").unwrap();
348                            writeln!(report, "- Reference count: {}", world.strong_count())
349                                .unwrap();
350                            if let Some(world) = world.upgrade() {
351                                let world = world.read();
352                                let strong_chunks = world
353                                    .chunks
354                                    .map
355                                    .iter()
356                                    .filter(|(_, v)| v.strong_count() > 0)
357                                    .count();
358                                writeln!(
359                                    report,
360                                    "- Chunks: {} strongly referenced, {} in map",
361                                    strong_chunks,
362                                    world.chunks.map.len()
363                                )
364                                .unwrap();
365                                writeln!(
366                                    report,
367                                    "- Entities: {}",
368                                    world.entities_by_chunk.len()
369                                )
370                                .unwrap();
371                            }
372                        }
373                    }
374                    "bevy_ecs::message::Messages<azalea_client::packet::game::ReceivePacketEvent>" => {
375                        let events = ecs.resource::<Messages<game::ReceiveGamePacketEvent>>();
376                        writeln!(report, "- Event count: {}", events.len()).unwrap();
377                    }
378                    "bevy_ecs::message::Messages<azalea_client::chunks::ReceiveChunkEvent>" => {
379                        let events = ecs.resource::<Messages<ReceiveChunkEvent>>();
380                        writeln!(report, "- Event count: {}", events.len()).unwrap();
381                    }
382
383                    _ => {}
384                }
385            }
386
387            println!("\x1b[1mWrote report to {}\x1b[m", report_path.display());
388        });
389
390        1
391    }));
392
393    commands.register(literal("exit").executes(|ctx: &Ctx| {
394        let source = ctx.source.lock();
395        source.reply("bye!");
396
397        source.bot.disconnect();
398
399        let source = ctx.source.clone();
400        thread::spawn(move || {
401            thread::sleep(Duration::from_secs(1));
402
403            source
404                .lock()
405                .bot
406                .ecs
407                .write()
408                .write_message(AppExit::Success);
409        });
410
411        1
412    }));
413}
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,