pub struct EntityRef { /* private fields */ }Expand description
A reference to an entity in a world.
This is different from [Entity], since you can perform actions with just
an EntityRef instead of it only being an identifier.
Most functions on EntityRef that return a value will result in a panic if
the client has despawned, so if your code involves waiting, you should check
Self::is_alive or Self::exists before calling those functions.
Also, since EntityRef stores the Client alongside the entity, this
means that it supports interactions such as Self::attack.
Not to be confused with Bevy’s EntityRef.
Implementations§
Source§impl EntityRef
impl EntityRef
Sourcepub fn position(&self) -> Vec3
pub fn position(&self) -> Vec3
Get the entity’s position in the world, which is the same as its feet position.
To get the client’s eye position, use Self::eye_position.
Also see Client::position.
Examples found in repository?
14pub fn register(commands: &mut CommandDispatcher<Mutex<CommandSource>>) {
15 commands.register(
16 literal("goto")
17 .executes(|ctx: &Ctx| {
18 let source = ctx.source.lock();
19 println!("got goto");
20 // look for the sender
21 let Some(entity) = source.entity() else {
22 source.reply("I can't see you!");
23 return 0;
24 };
25 let position = entity.position();
26 source.reply("ok");
27 source
28 .bot
29 .start_goto(BlockPosGoal(BlockPos::from(position.up(0.5))));
30 1
31 })
32 .then(literal("xz").then(argument("x", integer()).then(
33 argument("z", integer()).executes(|ctx: &Ctx| {
34 let source = ctx.source.lock();
35 let x = get_integer(ctx, "x").unwrap();
36 let z = get_integer(ctx, "z").unwrap();
37 println!("goto xz {x} {z}");
38 source.reply("ok");
39 source.bot.start_goto(XZGoal { x, z });
40 1
41 }),
42 )))
43 .then(literal("radius").then(argument("radius", float()).then(
44 argument("x", integer()).then(argument("y", integer()).then(
45 argument("z", integer()).executes(|ctx: &Ctx| {
46 let source = ctx.source.lock();
47 let radius = get_float(ctx, "radius").unwrap();
48 let x = get_integer(ctx, "x").unwrap();
49 let y = get_integer(ctx, "y").unwrap();
50 let z = get_integer(ctx, "z").unwrap();
51 println!("goto radius {radius}, position: {x} {y} {z}");
52 source.reply("ok");
53 source.bot.start_goto(RadiusGoal {
54 pos: BlockPos::new(x, y, z).center(),
55 radius,
56 });
57 1
58 }),
59 )),
60 )))
61 .then(argument("x", integer()).then(argument("y", integer()).then(
62 argument("z", integer()).executes(|ctx: &Ctx| {
63 let source = ctx.source.lock();
64 let x = get_integer(ctx, "x").unwrap();
65 let y = get_integer(ctx, "y").unwrap();
66 let z = get_integer(ctx, "z").unwrap();
67 println!("goto xyz {x} {y} {z}");
68 source.reply("ok");
69 source.bot.start_goto(BlockPosGoal(BlockPos::new(x, y, z)));
70 1
71 }),
72 ))),
73 );
74
75 commands.register(literal("down").executes(|ctx: &Ctx| {
76 let source = ctx.source.clone();
77 tokio::spawn(async move {
78 let bot = source.lock().bot.clone();
79 let position = BlockPos::from(bot.position());
80 source.lock().reply("mining...");
81 bot.mine(position.down(1)).await;
82 source.lock().reply("done");
83 });
84 1
85 }));
86
87 commands.register(
88 literal("look")
89 .executes(|ctx: &Ctx| {
90 // look for the sender
91 let source = ctx.source.lock();
92 let Some(entity) = source.entity() else {
93 source.reply("I can't see you!");
94 return 0;
95 };
96 let eye_position = entity.eye_position();
97 source.bot.look_at(eye_position);
98 1
99 })
100 .then(argument("x", integer()).then(argument("y", integer()).then(
101 argument("z", integer()).executes(|ctx: &Ctx| {
102 let pos = BlockPos::new(
103 get_integer(ctx, "x").unwrap(),
104 get_integer(ctx, "y").unwrap(),
105 get_integer(ctx, "z").unwrap(),
106 );
107 println!("{pos:?}");
108 let source = ctx.source.lock();
109 source.bot.look_at(pos.center());
110 1
111 }),
112 ))),
113 );
114
115 commands.register(
116 literal("walk").then(argument("seconds", float()).executes(|ctx: &Ctx| {
117 let mut seconds = get_float(ctx, "seconds").unwrap();
118 let source = ctx.source.lock();
119 let bot = source.bot.clone();
120
121 if seconds < 0. {
122 bot.walk(WalkDirection::Backward);
123 seconds = -seconds;
124 } else {
125 bot.walk(WalkDirection::Forward);
126 }
127
128 tokio::spawn(async move {
129 tokio::time::sleep(Duration::from_secs_f32(seconds)).await;
130 bot.walk(WalkDirection::None);
131 });
132 source.reply(format!("ok, walking for {seconds} seconds"));
133 1
134 })),
135 );
136 commands.register(
137 literal("sprint").then(argument("seconds", float()).executes(|ctx: &Ctx| {
138 let seconds = get_float(ctx, "seconds").unwrap();
139 let source = ctx.source.lock();
140 let bot = source.bot.clone();
141 bot.sprint(SprintDirection::Forward);
142 tokio::spawn(async move {
143 tokio::time::sleep(Duration::from_secs_f32(seconds)).await;
144 bot.walk(WalkDirection::None);
145 });
146 source.reply(format!("ok, sprinting for {seconds} seconds"));
147 1
148 })),
149 );
150
151 commands.register(literal("north").executes(|ctx: &Ctx| {
152 let source = ctx.source.lock();
153 source.bot.set_direction(180., 0.);
154 source.reply("ok");
155 1
156 }));
157 commands.register(literal("south").executes(|ctx: &Ctx| {
158 let source = ctx.source.lock();
159 source.bot.set_direction(0., 0.);
160 source.reply("ok");
161 1
162 }));
163 commands.register(literal("east").executes(|ctx: &Ctx| {
164 let source = ctx.source.lock();
165 source.bot.set_direction(-90., 0.);
166 source.reply("ok");
167 1
168 }));
169 commands.register(literal("west").executes(|ctx: &Ctx| {
170 let source = ctx.source.lock();
171 source.bot.set_direction(90., 0.);
172 source.reply("ok");
173 1
174 }));
175 commands.register(
176 literal("jump")
177 .executes(|ctx: &Ctx| {
178 let source = ctx.source.lock();
179 source.bot.jump();
180 source.reply("ok");
181 1
182 })
183 .then(argument("enabled", bool()).executes(|ctx: &Ctx| {
184 let jumping = get_bool(ctx, "enabled").unwrap();
185 let source = ctx.source.lock();
186 source.bot.set_jumping(jumping);
187 1
188 })),
189 );
190
191 let sneak = |ctx: &Ctx| {
192 let source = ctx.source.lock();
193 source.bot.set_crouching(!source.bot.crouching());
194 source.reply("ok");
195 1
196 };
197 let sneak_enabled = argument("enabled", bool()).executes(|ctx: &Ctx| {
198 let sneaking = get_bool(ctx, "enabled").unwrap();
199 let source = ctx.source.lock();
200 source.bot.set_crouching(sneaking);
201 1
202 });
203 commands.register(literal("sneak").executes(sneak).then(sneak_enabled.clone()));
204 commands.register(literal("crouch").executes(sneak).then(sneak_enabled));
205
206 commands.register(literal("stop").executes(|ctx: &Ctx| {
207 let source = ctx.source.lock();
208 source.bot.stop_pathfinding();
209 source.reply("ok");
210 *source.state.task.lock() = BotTask::None;
211 1
212 }));
213 commands.register(literal("forcestop").executes(|ctx: &Ctx| {
214 let source = ctx.source.lock();
215 source.bot.force_stop_pathfinding();
216 source.reply("ok");
217 *source.state.task.lock() = BotTask::None;
218 1
219 }));
220}More examples
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 chunks = &world.chunks;
353 let chunks = (chunks as &dyn Any).downcast_ref::<WeakChunkStorage>();
354 if let Some(chunks) = chunks {
355 let strong_chunks = chunks
356 .map
357 .iter()
358 .filter(|(_, v)| v.strong_count() > 0)
359 .count();
360 writeln!(
361 report,
362 "- Chunks: {} strongly referenced, {} in map",
363 strong_chunks,
364 chunks.map.len()
365 )
366 .unwrap();
367 }
368 writeln!(
369 report,
370 "- Entities: {}",
371 world.entities_by_chunk.len()
372 )
373 .unwrap();
374 }
375 }
376 }
377 "bevy_ecs::message::Messages<azalea_client::packet::game::ReceivePacketEvent>" => {
378 let events = ecs.resource::<Messages<game::ReceiveGamePacketEvent>>();
379 writeln!(report, "- Event count: {}", events.len()).unwrap();
380 }
381 "bevy_ecs::message::Messages<azalea_client::chunks::ReceiveChunkEvent>" => {
382 let events = ecs.resource::<Messages<ReceiveChunkEvent>>();
383 writeln!(report, "- Event count: {}", events.len()).unwrap();
384 }
385
386 _ => {}
387 }
388 }
389
390 println!("\x1b[1mWrote report to {}\x1b[m", report_path.display());
391 });
392
393 1
394 }));
395
396 commands.register(literal("exit").executes(|ctx: &Ctx| {
397 let source = ctx.source.lock();
398 source.reply("bye!");
399
400 source.bot.disconnect();
401
402 let source = ctx.source.clone();
403 thread::spawn(move || {
404 thread::sleep(Duration::from_secs(1));
405
406 source
407 .lock()
408 .bot
409 .ecs
410 .write()
411 .write_message(AppExit::Success);
412 });
413
414 1
415 }));
416}Source§impl EntityRef
impl EntityRef
Sourcepub fn dimensions(&self) -> EntityDimensions
pub fn dimensions(&self) -> EntityDimensions
Get the bounding box dimensions for the entity, which contains its width, height, and eye height.
Also see Client::dimensions
Source§impl EntityRef
impl EntityRef
Sourcepub fn eye_position(&self) -> Vec3
pub fn eye_position(&self) -> Vec3
Get the position of this entity’s eyes.
Also see Client::eye_position.
Examples found in repository?
14pub fn register(commands: &mut CommandDispatcher<Mutex<CommandSource>>) {
15 commands.register(
16 literal("goto")
17 .executes(|ctx: &Ctx| {
18 let source = ctx.source.lock();
19 println!("got goto");
20 // look for the sender
21 let Some(entity) = source.entity() else {
22 source.reply("I can't see you!");
23 return 0;
24 };
25 let position = entity.position();
26 source.reply("ok");
27 source
28 .bot
29 .start_goto(BlockPosGoal(BlockPos::from(position.up(0.5))));
30 1
31 })
32 .then(literal("xz").then(argument("x", integer()).then(
33 argument("z", integer()).executes(|ctx: &Ctx| {
34 let source = ctx.source.lock();
35 let x = get_integer(ctx, "x").unwrap();
36 let z = get_integer(ctx, "z").unwrap();
37 println!("goto xz {x} {z}");
38 source.reply("ok");
39 source.bot.start_goto(XZGoal { x, z });
40 1
41 }),
42 )))
43 .then(literal("radius").then(argument("radius", float()).then(
44 argument("x", integer()).then(argument("y", integer()).then(
45 argument("z", integer()).executes(|ctx: &Ctx| {
46 let source = ctx.source.lock();
47 let radius = get_float(ctx, "radius").unwrap();
48 let x = get_integer(ctx, "x").unwrap();
49 let y = get_integer(ctx, "y").unwrap();
50 let z = get_integer(ctx, "z").unwrap();
51 println!("goto radius {radius}, position: {x} {y} {z}");
52 source.reply("ok");
53 source.bot.start_goto(RadiusGoal {
54 pos: BlockPos::new(x, y, z).center(),
55 radius,
56 });
57 1
58 }),
59 )),
60 )))
61 .then(argument("x", integer()).then(argument("y", integer()).then(
62 argument("z", integer()).executes(|ctx: &Ctx| {
63 let source = ctx.source.lock();
64 let x = get_integer(ctx, "x").unwrap();
65 let y = get_integer(ctx, "y").unwrap();
66 let z = get_integer(ctx, "z").unwrap();
67 println!("goto xyz {x} {y} {z}");
68 source.reply("ok");
69 source.bot.start_goto(BlockPosGoal(BlockPos::new(x, y, z)));
70 1
71 }),
72 ))),
73 );
74
75 commands.register(literal("down").executes(|ctx: &Ctx| {
76 let source = ctx.source.clone();
77 tokio::spawn(async move {
78 let bot = source.lock().bot.clone();
79 let position = BlockPos::from(bot.position());
80 source.lock().reply("mining...");
81 bot.mine(position.down(1)).await;
82 source.lock().reply("done");
83 });
84 1
85 }));
86
87 commands.register(
88 literal("look")
89 .executes(|ctx: &Ctx| {
90 // look for the sender
91 let source = ctx.source.lock();
92 let Some(entity) = source.entity() else {
93 source.reply("I can't see you!");
94 return 0;
95 };
96 let eye_position = entity.eye_position();
97 source.bot.look_at(eye_position);
98 1
99 })
100 .then(argument("x", integer()).then(argument("y", integer()).then(
101 argument("z", integer()).executes(|ctx: &Ctx| {
102 let pos = BlockPos::new(
103 get_integer(ctx, "x").unwrap(),
104 get_integer(ctx, "y").unwrap(),
105 get_integer(ctx, "z").unwrap(),
106 );
107 println!("{pos:?}");
108 let source = ctx.source.lock();
109 source.bot.look_at(pos.center());
110 1
111 }),
112 ))),
113 );
114
115 commands.register(
116 literal("walk").then(argument("seconds", float()).executes(|ctx: &Ctx| {
117 let mut seconds = get_float(ctx, "seconds").unwrap();
118 let source = ctx.source.lock();
119 let bot = source.bot.clone();
120
121 if seconds < 0. {
122 bot.walk(WalkDirection::Backward);
123 seconds = -seconds;
124 } else {
125 bot.walk(WalkDirection::Forward);
126 }
127
128 tokio::spawn(async move {
129 tokio::time::sleep(Duration::from_secs_f32(seconds)).await;
130 bot.walk(WalkDirection::None);
131 });
132 source.reply(format!("ok, walking for {seconds} seconds"));
133 1
134 })),
135 );
136 commands.register(
137 literal("sprint").then(argument("seconds", float()).executes(|ctx: &Ctx| {
138 let seconds = get_float(ctx, "seconds").unwrap();
139 let source = ctx.source.lock();
140 let bot = source.bot.clone();
141 bot.sprint(SprintDirection::Forward);
142 tokio::spawn(async move {
143 tokio::time::sleep(Duration::from_secs_f32(seconds)).await;
144 bot.walk(WalkDirection::None);
145 });
146 source.reply(format!("ok, sprinting for {seconds} seconds"));
147 1
148 })),
149 );
150
151 commands.register(literal("north").executes(|ctx: &Ctx| {
152 let source = ctx.source.lock();
153 source.bot.set_direction(180., 0.);
154 source.reply("ok");
155 1
156 }));
157 commands.register(literal("south").executes(|ctx: &Ctx| {
158 let source = ctx.source.lock();
159 source.bot.set_direction(0., 0.);
160 source.reply("ok");
161 1
162 }));
163 commands.register(literal("east").executes(|ctx: &Ctx| {
164 let source = ctx.source.lock();
165 source.bot.set_direction(-90., 0.);
166 source.reply("ok");
167 1
168 }));
169 commands.register(literal("west").executes(|ctx: &Ctx| {
170 let source = ctx.source.lock();
171 source.bot.set_direction(90., 0.);
172 source.reply("ok");
173 1
174 }));
175 commands.register(
176 literal("jump")
177 .executes(|ctx: &Ctx| {
178 let source = ctx.source.lock();
179 source.bot.jump();
180 source.reply("ok");
181 1
182 })
183 .then(argument("enabled", bool()).executes(|ctx: &Ctx| {
184 let jumping = get_bool(ctx, "enabled").unwrap();
185 let source = ctx.source.lock();
186 source.bot.set_jumping(jumping);
187 1
188 })),
189 );
190
191 let sneak = |ctx: &Ctx| {
192 let source = ctx.source.lock();
193 source.bot.set_crouching(!source.bot.crouching());
194 source.reply("ok");
195 1
196 };
197 let sneak_enabled = argument("enabled", bool()).executes(|ctx: &Ctx| {
198 let sneaking = get_bool(ctx, "enabled").unwrap();
199 let source = ctx.source.lock();
200 source.bot.set_crouching(sneaking);
201 1
202 });
203 commands.register(literal("sneak").executes(sneak).then(sneak_enabled.clone()));
204 commands.register(literal("crouch").executes(sneak).then(sneak_enabled));
205
206 commands.register(literal("stop").executes(|ctx: &Ctx| {
207 let source = ctx.source.lock();
208 source.bot.stop_pathfinding();
209 source.reply("ok");
210 *source.state.task.lock() = BotTask::None;
211 1
212 }));
213 commands.register(literal("forcestop").executes(|ctx: &Ctx| {
214 let source = ctx.source.lock();
215 source.bot.force_stop_pathfinding();
216 source.reply("ok");
217 *source.state.task.lock() = BotTask::None;
218 1
219 }));
220}Source§impl EntityRef
impl EntityRef
Sourcepub fn health(&self) -> f32
pub fn health(&self) -> f32
Get the health of this entity, typically in the range 0..=20.
Also see Client::health.
Source§impl EntityRef
impl EntityRef
Sourcepub fn uuid(&self) -> Uuid
pub fn uuid(&self) -> Uuid
Get the Minecraft UUID of this entity.
Also see Client::uuid.
Examples found in repository?
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 chunks = &world.chunks;
353 let chunks = (chunks as &dyn Any).downcast_ref::<WeakChunkStorage>();
354 if let Some(chunks) = chunks {
355 let strong_chunks = chunks
356 .map
357 .iter()
358 .filter(|(_, v)| v.strong_count() > 0)
359 .count();
360 writeln!(
361 report,
362 "- Chunks: {} strongly referenced, {} in map",
363 strong_chunks,
364 chunks.map.len()
365 )
366 .unwrap();
367 }
368 writeln!(
369 report,
370 "- Entities: {}",
371 world.entities_by_chunk.len()
372 )
373 .unwrap();
374 }
375 }
376 }
377 "bevy_ecs::message::Messages<azalea_client::packet::game::ReceivePacketEvent>" => {
378 let events = ecs.resource::<Messages<game::ReceiveGamePacketEvent>>();
379 writeln!(report, "- Event count: {}", events.len()).unwrap();
380 }
381 "bevy_ecs::message::Messages<azalea_client::chunks::ReceiveChunkEvent>" => {
382 let events = ecs.resource::<Messages<ReceiveChunkEvent>>();
383 writeln!(report, "- Event count: {}", events.len()).unwrap();
384 }
385
386 _ => {}
387 }
388 }
389
390 println!("\x1b[1mWrote report to {}\x1b[m", report_path.display());
391 });
392
393 1
394 }));
395
396 commands.register(literal("exit").executes(|ctx: &Ctx| {
397 let source = ctx.source.lock();
398 source.reply("bye!");
399
400 source.bot.disconnect();
401
402 let source = ctx.source.clone();
403 thread::spawn(move || {
404 thread::sleep(Duration::from_secs(1));
405
406 source
407 .lock()
408 .bot
409 .ecs
410 .write()
411 .write_message(AppExit::Success);
412 });
413
414 1
415 }));
416}Source§impl EntityRef
impl EntityRef
Sourcepub fn minecraft_id(&self) -> MinecraftEntityId
pub fn minecraft_id(&self) -> MinecraftEntityId
Get the Minecraft UUID of this entity.
See MinecraftEntityId for more details. For persistent identifiers,
consider using Self::uuid instead.
Also see Client::minecraft_id.
Examples found in repository?
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 chunks = &world.chunks;
353 let chunks = (chunks as &dyn Any).downcast_ref::<WeakChunkStorage>();
354 if let Some(chunks) = chunks {
355 let strong_chunks = chunks
356 .map
357 .iter()
358 .filter(|(_, v)| v.strong_count() > 0)
359 .count();
360 writeln!(
361 report,
362 "- Chunks: {} strongly referenced, {} in map",
363 strong_chunks,
364 chunks.map.len()
365 )
366 .unwrap();
367 }
368 writeln!(
369 report,
370 "- Entities: {}",
371 world.entities_by_chunk.len()
372 )
373 .unwrap();
374 }
375 }
376 }
377 "bevy_ecs::message::Messages<azalea_client::packet::game::ReceivePacketEvent>" => {
378 let events = ecs.resource::<Messages<game::ReceiveGamePacketEvent>>();
379 writeln!(report, "- Event count: {}", events.len()).unwrap();
380 }
381 "bevy_ecs::message::Messages<azalea_client::chunks::ReceiveChunkEvent>" => {
382 let events = ecs.resource::<Messages<ReceiveChunkEvent>>();
383 writeln!(report, "- Event count: {}", events.len()).unwrap();
384 }
385
386 _ => {}
387 }
388 }
389
390 println!("\x1b[1mWrote report to {}\x1b[m", report_path.display());
391 });
392
393 1
394 }));
395
396 commands.register(literal("exit").executes(|ctx: &Ctx| {
397 let source = ctx.source.lock();
398 source.reply("bye!");
399
400 source.bot.disconnect();
401
402 let source = ctx.source.clone();
403 thread::spawn(move || {
404 thread::sleep(Duration::from_secs(1));
405
406 source
407 .lock()
408 .bot
409 .ecs
410 .write()
411 .write_message(AppExit::Success);
412 });
413
414 1
415 }));
416}Source§impl EntityRef
impl EntityRef
Sourcepub fn attributes(&self) -> Attributes
pub fn attributes(&self) -> Attributes
Returns the attribute values of the entity, which can be used to determine things like its movement speed.
Source§impl EntityRef
impl EntityRef
pub fn instance_name(&self) -> WorldName
renamed to world_name.
Source§impl EntityRef
impl EntityRef
Sourcepub fn world_name(&self) -> WorldName
pub fn world_name(&self) -> WorldName
Get the name of the world that the entity is in.
This can be used to check if the entity is in the same world as another entity.
Also see Client::world_name,
Source§impl EntityRef
impl EntityRef
Sourcepub fn is_alive(&self) -> bool
pub fn is_alive(&self) -> bool
Returns whether the entity is alive and hasn’t despawned.
Unlike most functions in EntityRef, this one will not panic if the
entity is despawned. Because of this, it may be useful to check is_alive
before calling functions that request data from the world.
Also see Client::is_alive and Self::exists.
Source§impl EntityRef
impl EntityRef
Sourcepub fn exists(&self) -> bool
pub fn exists(&self) -> bool
Returns whether the entity is in the world and hasn’t despawned.
Like Self::is_alive, this will not panic.
Also see Client::exists.
Source§impl EntityRef
impl EntityRef
Sourcepub fn physics(&self) -> Physics
pub fn physics(&self) -> Physics
Returns the complete Physics data for this entity, including velocity, bounding box,
collisions, etc.
Also see Client::physics.
Source§impl EntityRef
impl EntityRef
pub fn new(client: Client, entity: Entity) -> Self
Sourcepub fn id(&self) -> Entity
pub fn id(&self) -> Entity
Returns the ECS identifier for the entity.
Examples found in repository?
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 chunks = &world.chunks;
353 let chunks = (chunks as &dyn Any).downcast_ref::<WeakChunkStorage>();
354 if let Some(chunks) = chunks {
355 let strong_chunks = chunks
356 .map
357 .iter()
358 .filter(|(_, v)| v.strong_count() > 0)
359 .count();
360 writeln!(
361 report,
362 "- Chunks: {} strongly referenced, {} in map",
363 strong_chunks,
364 chunks.map.len()
365 )
366 .unwrap();
367 }
368 writeln!(
369 report,
370 "- Entities: {}",
371 world.entities_by_chunk.len()
372 )
373 .unwrap();
374 }
375 }
376 }
377 "bevy_ecs::message::Messages<azalea_client::packet::game::ReceivePacketEvent>" => {
378 let events = ecs.resource::<Messages<game::ReceiveGamePacketEvent>>();
379 writeln!(report, "- Event count: {}", events.len()).unwrap();
380 }
381 "bevy_ecs::message::Messages<azalea_client::chunks::ReceiveChunkEvent>" => {
382 let events = ecs.resource::<Messages<ReceiveChunkEvent>>();
383 writeln!(report, "- Event count: {}", events.len()).unwrap();
384 }
385
386 _ => {}
387 }
388 }
389
390 println!("\x1b[1mWrote report to {}\x1b[m", report_path.display());
391 });
392
393 1
394 }));
395
396 commands.register(literal("exit").executes(|ctx: &Ctx| {
397 let source = ctx.source.lock();
398 source.reply("bye!");
399
400 source.bot.disconnect();
401
402 let source = ctx.source.clone();
403 thread::spawn(move || {
404 thread::sleep(Duration::from_secs(1));
405
406 source
407 .lock()
408 .bot
409 .ecs
410 .write()
411 .write_message(AppExit::Success);
412 });
413
414 1
415 }));
416}Sourcepub fn component<T: Component>(&self) -> MappedRwLockReadGuard<'_, T>
pub fn component<T: Component>(&self) -> MappedRwLockReadGuard<'_, T>
Get a component on the entity.
This allows you to access certain data stored about the entity that isn’t accessible in a simpler way.
See Client::component for more details.
§Panics
This will panic if the component doesn’t exist on the client. Use
Self::get_component to avoid this.
§Examples
let world_name = client.component::<WorldName>();Sourcepub fn get_component<T: Component>(
&self,
) -> Option<MappedRwLockReadGuard<'_, T>>
pub fn get_component<T: Component>( &self, ) -> Option<MappedRwLockReadGuard<'_, T>>
Get a component on this client, or None if it doesn’t exist.
If the component is guaranteed to be present, consider using
Self::component.
See Client::component for more details.
Sourcepub fn query_self<D: QueryData, R>(
&self,
f: impl FnOnce(QueryItem<'_, '_, D>) -> R,
) -> R
pub fn query_self<D: QueryData, R>( &self, f: impl FnOnce(QueryItem<'_, '_, D>) -> R, ) -> R
Query the ECS for data from the entity.
You can use this to mutate data on the entity.
Also see Client::query_self and Client::query_entity.
§Panics
This will panic if the entity doesn’t exist or is missing a component
required by the query. Consider using Self::try_query_self to
avoid this.
Sourcepub fn try_query_self<D: QueryData, R>(
&self,
f: impl FnOnce(QueryItem<'_, '_, D>) -> R,
) -> Result<R, QueryEntityError>
pub fn try_query_self<D: QueryData, R>( &self, f: impl FnOnce(QueryItem<'_, '_, D>) -> R, ) -> Result<R, QueryEntityError>
Query the ECS for data from the entity, or return an error if the query fails.
Also see Self::query_self.
Source§impl EntityRef
impl EntityRef
Sourcepub fn attack(&self)
pub fn attack(&self)
Attack this entity from the client that created this EntityRef.
Also see Client::attack.
Examples found in repository?
9pub fn tick(bot: Client, state: State) -> eyre::Result<()> {
10 if !state.killaura {
11 return Ok(());
12 }
13 if bot.has_attack_cooldown() {
14 return Ok(());
15 }
16 let bot_position = bot.eye_position();
17
18 let nearest_entity = bot.nearest_entity_by::<&Position, (
19 With<AbstractMonster>,
20 Without<LocalEntity>,
21 Without<Dead>,
22 )>(|position: &Position| {
23 let distance = bot_position.distance_to(**position);
24 distance < 4.
25 });
26
27 if let Some(nearest_entity) = nearest_entity {
28 println!("attacking {nearest_entity:?}");
29 nearest_entity.attack();
30 }
31
32 Ok(())
33}Sourcepub fn interact(&self)
pub fn interact(&self)
Right-click this entity from the client that created this EntityRef.
See Client::entity_interact for more information.
Sourcepub fn distance_to_client(&self) -> f64
pub fn distance_to_client(&self) -> f64
Returns the distance between the client’s feet position and this entity’s feet position.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for EntityRef
impl !RefUnwindSafe for EntityRef
impl Send for EntityRef
impl Sync for EntityRef
impl Unpin for EntityRef
impl UnsafeUnpin for EntityRef
impl !UnwindSafe for EntityRef
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> CompatExt for T
impl<T> CompatExt for T
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
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>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
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)
fn as_any(&self) -> &(dyn Any + 'static)
&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)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.