LookDirection

Struct LookDirection 

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

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

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

pub fn 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 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 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).

Trait Implementations§

Source§

impl AzaleaRead for LookDirection

Source§

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

Source§

impl AzaleaWrite for LookDirection

Source§

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

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
§

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<'_>, ids: &mut impl FnMut(ComponentId), )

§

fn get_component_ids( components: &Components, ids: &mut impl FnMut(Option<ComponentId>), )

Gets 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,