1mod events;
2
3use std::{collections::HashSet, sync::Arc};
4
5use azalea_core::{
6 game_type::GameMode,
7 position::{ChunkPos, Vec3},
8};
9use azalea_entity::{
10 Dead, EntityBundle, EntityKindComponent, HasClientLoaded, LoadedBy, LocalEntity, LookDirection,
11 Physics, PlayerAbilities, Position, RelativeEntityUpdate,
12 indexing::{EntityIdIndex, EntityUuidIndex},
13 metadata::{Health, apply_metadata},
14};
15use azalea_protocol::{
16 common::movements::MoveFlags,
17 packets::{ConnectionProtocol, game::*},
18};
19use azalea_world::{InstanceContainer, InstanceName, MinecraftEntityId, PartialInstance};
20use bevy_ecs::{prelude::*, system::SystemState};
21pub use events::*;
22use tracing::{debug, error, trace, warn};
23
24use crate::{
25 ClientInformation,
26 block_update::QueuedServerBlockUpdates,
27 chat::{ChatPacket, ChatReceivedEvent},
28 chunks,
29 connection::RawConnection,
30 disconnect::DisconnectEvent,
31 interact::BlockStatePredictionHandler,
32 inventory::{
33 ClientsideCloseContainerEvent, Inventory, MenuOpenedEvent, SetContainerContentEvent,
34 },
35 local_player::{Hunger, InstanceHolder, LocalGameMode, TabList},
36 movement::{KnockbackEvent, KnockbackType},
37 packet::{as_system, declare_packet_handlers},
38 player::{GameProfileComponent, PlayerInfo},
39 tick_counter::TicksConnected,
40};
41
42pub fn process_packet(ecs: &mut World, player: Entity, packet: &ClientboundGamePacket) {
43 let mut handler = GamePacketHandler { player, ecs };
44
45 declare_packet_handlers!(
47 ClientboundGamePacket,
48 packet,
49 handler,
50 [
51 login,
52 set_chunk_cache_radius,
53 chunk_batch_start,
54 chunk_batch_finished,
55 custom_payload,
56 change_difficulty,
57 commands,
58 player_abilities,
59 set_cursor_item,
60 update_tags,
61 disconnect,
62 update_recipes,
63 entity_event,
64 player_position,
65 player_info_update,
66 player_info_remove,
67 set_chunk_cache_center,
68 chunks_biomes,
69 light_update,
70 level_chunk_with_light,
71 add_entity,
72 set_entity_data,
73 update_attributes,
74 set_entity_motion,
75 set_entity_link,
76 initialize_border,
77 set_time,
78 set_default_spawn_position,
79 set_health,
80 set_experience,
81 teleport_entity,
82 update_advancements,
83 rotate_head,
84 move_entity_pos,
85 move_entity_pos_rot,
86 move_entity_rot,
87 keep_alive,
88 remove_entities,
89 player_chat,
90 system_chat,
91 disguised_chat,
92 sound,
93 level_event,
94 block_update,
95 animate,
96 section_blocks_update,
97 game_event,
98 level_particles,
99 server_data,
100 set_equipment,
101 update_mob_effect,
102 award_stats,
103 block_changed_ack,
104 block_destruction,
105 block_entity_data,
106 block_event,
107 boss_event,
108 command_suggestions,
109 container_set_content,
110 container_set_data,
111 container_set_slot,
112 container_close,
113 cooldown,
114 custom_chat_completions,
115 delete_chat,
116 explode,
117 forget_level_chunk,
118 horse_screen_open,
119 map_item_data,
120 merchant_offers,
121 move_vehicle,
122 open_book,
123 open_screen,
124 open_sign_editor,
125 ping,
126 place_ghost_recipe,
127 player_combat_end,
128 player_combat_enter,
129 player_combat_kill,
130 player_look_at,
131 remove_mob_effect,
132 resource_pack_push,
133 resource_pack_pop,
134 respawn,
135 start_configuration,
136 entity_position_sync,
137 select_advancements_tab,
138 set_action_bar_text,
139 set_border_center,
140 set_border_lerp_size,
141 set_border_size,
142 set_border_warning_delay,
143 set_border_warning_distance,
144 set_camera,
145 set_display_objective,
146 set_objective,
147 set_passengers,
148 set_player_team,
149 set_score,
150 set_simulation_distance,
151 set_subtitle_text,
152 set_title_text,
153 set_titles_animation,
154 clear_titles,
155 sound_entity,
156 stop_sound,
157 tab_list,
158 tag_query,
159 take_item_entity,
160 bundle_delimiter,
161 damage_event,
162 hurt_animation,
163 ticking_state,
164 ticking_step,
165 reset_score,
166 cookie_request,
167 debug_sample,
168 pong_response,
169 store_cookie,
170 transfer,
171 move_minecart_along_track,
172 set_held_slot,
173 set_player_inventory,
174 projectile_power,
175 custom_report_details,
176 server_links,
177 player_rotation,
178 recipe_book_add,
179 recipe_book_remove,
180 recipe_book_settings,
181 test_instance_block_status,
182 waypoint,
183 clear_dialog,
184 show_dialog,
185 debug_block_value,
186 debug_chunk_value,
187 debug_entity_value,
188 debug_event,
189 game_test_highlight_pos,
190 ]
191 );
192}
193
194pub struct GamePacketHandler<'a> {
195 pub ecs: &'a mut World,
196 pub player: Entity,
197}
198impl GamePacketHandler<'_> {
199 pub fn login(&mut self, p: &ClientboundLogin) {
200 debug!("Got login packet");
201
202 as_system::<(
203 Commands,
204 Query<
205 (
206 &GameProfileComponent,
207 &ClientInformation,
208 Option<&mut InstanceName>,
209 Option<&mut LoadedBy>,
210 &mut EntityIdIndex,
211 &mut InstanceHolder,
212 ),
213 With<LocalEntity>,
214 >,
215 MessageWriter<InstanceLoadedEvent>,
216 ResMut<InstanceContainer>,
217 ResMut<EntityUuidIndex>,
218 Query<&mut LoadedBy, Without<LocalEntity>>,
219 )>(
220 self.ecs,
221 |(
222 mut commands,
223 mut query,
224 mut instance_loaded_events,
225 mut instance_container,
226 mut entity_uuid_index,
227 mut loaded_by_query,
228 )| {
229 let (
230 game_profile,
231 client_information,
232 instance_name,
233 loaded_by,
234 mut entity_id_index,
235 mut instance_holder,
236 ) = query.get_mut(self.player).unwrap();
237
238 let new_instance_name = p.common.dimension.clone();
239
240 if let Some(mut instance_name) = instance_name {
241 **instance_name = new_instance_name.clone();
242 } else {
243 commands
244 .entity(self.player)
245 .insert(InstanceName(new_instance_name.clone()));
246 }
247
248 let Some((_dimension_type, dimension_data)) = p
249 .common
250 .dimension_type(&instance_holder.instance.read().registries)
251 else {
252 return;
253 };
254
255 let weak_instance = instance_container.get_or_insert(
258 new_instance_name.clone(),
259 dimension_data.height,
260 dimension_data.min_y,
261 &instance_holder.instance.read().registries,
262 );
263 instance_loaded_events.write(InstanceLoadedEvent {
264 entity: self.player,
265 name: new_instance_name.clone(),
266 instance: Arc::downgrade(&weak_instance),
267 });
268
269 *instance_holder.partial_instance.write() = PartialInstance::new(
274 azalea_world::chunk_storage::calculate_chunk_storage_range(
275 client_information.view_distance.into(),
276 ),
277 Some(self.player),
280 );
281 {
282 let map = instance_holder.instance.read().registries.map.clone();
283 let new_registries = &mut weak_instance.write().registries;
284 for (registry_name, registry) in map {
286 new_registries.map.insert(registry_name, registry);
287 }
288 }
289 instance_holder.instance = weak_instance;
290
291 let entity_bundle = EntityBundle::new(
292 game_profile.uuid,
293 Vec3::ZERO,
294 azalea_registry::EntityKind::Player,
295 new_instance_name,
296 );
297 let entity_id = p.player_id;
298 commands.entity(self.player).insert((
300 entity_id,
301 LocalGameMode {
302 current: p.common.game_type,
303 previous: p.common.previous_game_type.into(),
304 },
305 entity_bundle,
306 TicksConnected(0),
307 ));
308
309 azalea_entity::indexing::add_entity_to_indexes(
310 entity_id,
311 self.player,
312 Some(game_profile.uuid),
313 &mut entity_id_index,
314 &mut entity_uuid_index,
315 &mut instance_holder.instance.write(),
316 );
317
318 for mut loaded_by in &mut loaded_by_query.iter_mut() {
320 loaded_by.remove(&self.player);
321 }
322
323 if let Some(mut loaded_by) = loaded_by {
325 loaded_by.insert(self.player);
326 } else {
327 commands
328 .entity(self.player)
329 .insert(LoadedBy(HashSet::from_iter(vec![self.player])));
330 }
331 },
332 );
333 }
334
335 pub fn set_chunk_cache_radius(&mut self, p: &ClientboundSetChunkCacheRadius) {
336 debug!("Got set chunk cache radius packet {p:?}");
337 }
338
339 pub fn chunk_batch_start(&mut self, _p: &ClientboundChunkBatchStart) {
340 debug!("Got chunk batch start");
343
344 as_system::<MessageWriter<_>>(self.ecs, |mut events| {
345 events.write(chunks::ChunkBatchStartEvent {
346 entity: self.player,
347 });
348 });
349 }
350
351 pub fn chunk_batch_finished(&mut self, p: &ClientboundChunkBatchFinished) {
352 debug!("Got chunk batch finished {p:?}");
353
354 as_system::<MessageWriter<_>>(self.ecs, |mut events| {
355 events.write(chunks::ChunkBatchFinishedEvent {
356 entity: self.player,
357 batch_size: p.batch_size,
358 });
359 });
360 }
361
362 pub fn custom_payload(&mut self, p: &ClientboundCustomPayload) {
363 debug!("Got custom payload packet {p:?}");
364 }
365
366 pub fn change_difficulty(&mut self, p: &ClientboundChangeDifficulty) {
367 debug!("Got difficulty packet {p:?}");
368 }
369
370 pub fn commands(&mut self, _p: &ClientboundCommands) {
371 debug!("Got declare commands packet");
372 }
373
374 pub fn player_abilities(&mut self, p: &ClientboundPlayerAbilities) {
375 debug!("Got player abilities packet {p:?}");
376
377 as_system::<Query<&mut PlayerAbilities>>(self.ecs, |mut query| {
378 let mut player_abilities = query.get_mut(self.player).unwrap();
379
380 *player_abilities = PlayerAbilities::from(p);
381 });
382 }
383
384 pub fn set_cursor_item(&mut self, p: &ClientboundSetCursorItem) {
385 debug!("Got set cursor item packet {p:?}");
386 }
387
388 pub fn update_tags(&mut self, _p: &ClientboundUpdateTags) {
389 debug!("Got update tags packet");
390 }
391
392 pub fn disconnect(&mut self, p: &ClientboundDisconnect) {
393 warn!("Got disconnect packet {p:?}");
394
395 as_system::<MessageWriter<_>>(self.ecs, |mut events| {
396 events.write(DisconnectEvent {
397 entity: self.player,
398 reason: Some(p.reason.clone()),
399 });
400 });
401 }
402
403 pub fn update_recipes(&mut self, _p: &ClientboundUpdateRecipes) {
404 debug!("Got update recipes packet");
405 }
406
407 pub fn entity_event(&mut self, _p: &ClientboundEntityEvent) {
408 }
410
411 pub fn player_position(&mut self, p: &ClientboundPlayerPosition) {
412 debug!("Got player position packet {p:?}");
413
414 as_system::<(
415 Query<(&mut Physics, &mut LookDirection, &mut Position)>,
416 Commands,
417 )>(self.ecs, |(mut query, mut commands)| {
418 let Ok((mut physics, mut direction, mut position)) = query.get_mut(self.player) else {
419 return;
420 };
421
422 p.relative
423 .apply(&p.change, &mut position, &mut direction, &mut physics);
424 physics.set_old_pos(*position);
426
427 commands.trigger(SendGamePacketEvent::new(
429 self.player,
430 ServerboundAcceptTeleportation { id: p.id },
431 ));
432 commands.trigger(SendGamePacketEvent::new(
433 self.player,
434 ServerboundMovePlayerPosRot {
435 pos: **position,
436 look_direction: *direction,
437 flags: MoveFlags::default(),
438 },
439 ));
440 });
441 }
442
443 pub fn player_info_update(&mut self, p: &ClientboundPlayerInfoUpdate) {
444 debug!("Got player info packet {p:?}");
445
446 as_system::<(
447 Query<&mut TabList>,
448 MessageWriter<AddPlayerEvent>,
449 MessageWriter<UpdatePlayerEvent>,
450 ResMut<TabList>,
451 )>(
452 self.ecs,
453 |(
454 mut query,
455 mut add_player_events,
456 mut update_player_events,
457 mut tab_list_resource,
458 )| {
459 let mut tab_list = query.get_mut(self.player).unwrap();
460
461 for updated_info in &p.entries {
462 if p.actions.add_player {
464 let info = PlayerInfo {
465 profile: updated_info.profile.clone(),
466 uuid: updated_info.profile.uuid,
467 gamemode: updated_info.game_mode,
468 latency: updated_info.latency,
469 display_name: updated_info.display_name.clone(),
470 };
471 tab_list.insert(updated_info.profile.uuid, info.clone());
472 add_player_events.write(AddPlayerEvent {
473 entity: self.player,
474 info,
475 });
476 } else if let Some(info) = tab_list.get_mut(&updated_info.profile.uuid) {
477 if p.actions.update_game_mode {
480 info.gamemode = updated_info.game_mode;
481 }
482 if p.actions.update_latency {
483 info.latency = updated_info.latency;
484 }
485 if p.actions.update_display_name {
486 info.display_name.clone_from(&updated_info.display_name);
487 }
488 update_player_events.write(UpdatePlayerEvent {
489 entity: self.player,
490 info: info.clone(),
491 });
492 } else {
493 let uuid = updated_info.profile.uuid;
494 debug!("Ignoring PlayerInfoUpdate for unknown player {uuid}");
495 }
496 }
497
498 *tab_list_resource = tab_list.clone();
499 },
500 );
501 }
502
503 pub fn player_info_remove(&mut self, p: &ClientboundPlayerInfoRemove) {
504 debug!("Got chunk cache center packet {p:?}");
505
506 as_system::<(
507 Query<&mut TabList>,
508 MessageWriter<RemovePlayerEvent>,
509 ResMut<TabList>,
510 )>(
511 self.ecs,
512 |(mut query, mut remove_player_events, mut tab_list_resource)| {
513 let mut tab_list = query.get_mut(self.player).unwrap();
514
515 for uuid in &p.profile_ids {
516 if let Some(info) = tab_list.remove(uuid) {
517 remove_player_events.write(RemovePlayerEvent {
518 entity: self.player,
519 info,
520 });
521 }
522 tab_list_resource.remove(uuid);
523 }
524 },
525 );
526 }
527
528 pub fn set_chunk_cache_center(&mut self, p: &ClientboundSetChunkCacheCenter) {
529 debug!("Got chunk cache center packet {p:?}");
530
531 as_system::<Query<&InstanceHolder>>(self.ecs, |mut query| {
532 let instance_holder = query.get_mut(self.player).unwrap();
533 let mut partial_world = instance_holder.partial_instance.write();
534
535 partial_world
536 .chunks
537 .update_view_center(ChunkPos::new(p.x, p.z));
538 });
539 }
540
541 pub fn chunks_biomes(&mut self, _p: &ClientboundChunksBiomes) {}
542
543 pub fn light_update(&mut self, _p: &ClientboundLightUpdate) {
544 }
546
547 pub fn level_chunk_with_light(&mut self, p: &ClientboundLevelChunkWithLight) {
548 debug!("Got chunk with light packet {} {}", p.x, p.z);
549
550 as_system::<MessageWriter<_>>(self.ecs, |mut events| {
551 events.write(chunks::ReceiveChunkEvent {
552 entity: self.player,
553 packet: p.clone(),
554 });
555 });
556 }
557
558 pub fn add_entity(&mut self, p: &ClientboundAddEntity) {
559 debug!("Got add entity packet {p:?}");
560
561 as_system::<(
562 Commands,
563 Query<(&mut EntityIdIndex, Option<&InstanceName>, Option<&TabList>)>,
564 Query<&mut LoadedBy>,
565 Query<Entity>,
566 Res<InstanceContainer>,
567 ResMut<EntityUuidIndex>,
568 )>(
569 self.ecs,
570 |(
571 mut commands,
572 mut query,
573 mut loaded_by_query,
574 entity_query,
575 instance_container,
576 mut entity_uuid_index,
577 )| {
578 let (mut entity_id_index, instance_name, tab_list) =
579 query.get_mut(self.player).unwrap();
580
581 let entity_id = p.id;
582
583 let Some(instance_name) = instance_name else {
584 warn!("got add player packet but we haven't gotten a login packet yet");
585 return;
586 };
587
588 let instance = instance_container.get(instance_name).unwrap();
590 if let Some(&ecs_entity) = instance.read().entity_by_id.get(&entity_id) {
591 let Ok(mut loaded_by) = loaded_by_query.get_mut(ecs_entity) else {
593 let entity_in_ecs = entity_query.get(ecs_entity).is_ok();
597
598 if entity_in_ecs {
599 error!(
600 "LoadedBy for entity {entity_id:?} ({ecs_entity:?}) isn't in the ecs, but the entity is in entity_by_id"
601 );
602 } else {
603 error!(
604 "Entity {entity_id:?} ({ecs_entity:?}) isn't in the ecs, but the entity is in entity_by_id"
605 );
606 }
607 return;
608 };
609 loaded_by.insert(self.player);
610
611 entity_id_index.insert(entity_id, ecs_entity);
613
614 debug!("added to LoadedBy of entity {ecs_entity:?} with id {entity_id:?}");
615 return;
616 };
617
618 let bundle = p.as_entity_bundle((**instance_name).clone());
621 let mut spawned =
622 commands.spawn((entity_id, LoadedBy(HashSet::from([self.player])), bundle));
623 let ecs_entity: Entity = spawned.id();
624 debug!(
625 "spawned entity {ecs_entity:?} with id {entity_id:?} at {pos:?}",
626 pos = p.position
627 );
628
629 azalea_entity::indexing::add_entity_to_indexes(
630 entity_id,
631 ecs_entity,
632 Some(p.uuid),
633 &mut entity_id_index,
634 &mut entity_uuid_index,
635 &mut instance.write(),
636 );
637
638 if let Some(tab_list) = tab_list {
640 if let Some(player_info) = tab_list.get(&p.uuid) {
644 spawned.insert(GameProfileComponent(player_info.profile.clone()));
645 }
646 }
647
648 p.apply_metadata(&mut spawned);
651 },
652 );
653 }
654
655 pub fn set_entity_data(&mut self, p: &ClientboundSetEntityData) {
656 as_system::<(
657 Commands,
658 Query<(&EntityIdIndex, &InstanceHolder)>,
659 Query<&EntityKindComponent>,
662 )>(self.ecs, |(mut commands, query, entity_kind_query)| {
663 let (entity_id_index, instance_holder) = query.get(self.player).unwrap();
664
665 let entity = entity_id_index.get_by_minecraft_entity(p.id);
666
667 let Some(entity) = entity else {
668 debug!(
670 "Server sent an entity data packet for an entity id ({}) that we don't know about",
671 p.id
672 );
673 return;
674 };
675
676 let Ok(entity_kind) = entity_kind_query.get(entity) else {
677 debug!(
678 "Server sent an entity data packet for an entity id ({}) that we have indexed as {entity} but they don't have EntityKind. Maybe a second local client that just disconnected?",
679 p.id
680 );
681 return;
682 };
683 let entity_kind = **entity_kind;
684
685 debug!("Got set entity data packet {p:?} for entity of kind {entity_kind:?}");
686
687 let packed_items = p.packed_items.clone().to_vec();
688
689 commands.entity(entity).queue(RelativeEntityUpdate::new(
692 instance_holder.partial_instance.clone(),
693 move |entity| {
694 let entity_id = entity.id();
695 entity.world_scope(|world| {
696 let mut commands_system_state = SystemState::<Commands>::new(world);
697 let mut commands = commands_system_state.get_mut(world);
698 let mut entity_commands = commands.entity(entity_id);
699 if let Err(e) =
700 apply_metadata(&mut entity_commands, entity_kind, packed_items)
701 {
702 warn!("{e}");
703 }
704 commands_system_state.apply(world);
705 });
706 },
707 ));
708 });
709 }
710
711 pub fn update_attributes(&mut self, _p: &ClientboundUpdateAttributes) {
712 }
714
715 pub fn set_entity_motion(&mut self, p: &ClientboundSetEntityMotion) {
716 as_system::<(Commands, Query<(&EntityIdIndex, &InstanceHolder)>)>(
720 self.ecs,
721 |(mut commands, query)| {
722 let (entity_id_index, instance_holder) = query.get(self.player).unwrap();
723
724 let Some(entity) = entity_id_index.get_by_minecraft_entity(p.id) else {
725 debug!(
729 "Got set entity motion packet for unknown entity id {}",
730 p.id
731 );
732 return;
733 };
734
735 let knockback = KnockbackType::Set(p.delta.to_vec3());
739
740 commands.entity(entity).queue(RelativeEntityUpdate::new(
741 instance_holder.partial_instance.clone(),
742 move |entity_mut| {
743 entity_mut.world_scope(|world| {
744 world.write_message(KnockbackEvent { entity, knockback })
745 });
746 },
747 ));
748 },
749 );
750 }
751
752 pub fn set_entity_link(&mut self, p: &ClientboundSetEntityLink) {
753 debug!("Got set entity link packet {p:?}");
754 }
755
756 pub fn initialize_border(&mut self, p: &ClientboundInitializeBorder) {
757 debug!("Got initialize border packet {p:?}");
758 }
759
760 pub fn set_time(&mut self, _p: &ClientboundSetTime) {
761 }
763
764 pub fn set_default_spawn_position(&mut self, p: &ClientboundSetDefaultSpawnPosition) {
765 debug!("Got set default spawn position packet {p:?}");
766 }
767
768 pub fn set_health(&mut self, p: &ClientboundSetHealth) {
769 debug!("Got set health packet {p:?}");
770
771 as_system::<Query<(&mut Health, &mut Hunger)>>(self.ecs, |mut query| {
772 let (mut health, mut hunger) = query.get_mut(self.player).unwrap();
773
774 **health = p.health;
775 (hunger.food, hunger.saturation) = (p.food, p.saturation);
776
777 });
781 }
782
783 pub fn set_experience(&mut self, p: &ClientboundSetExperience) {
784 debug!("Got set experience packet {p:?}");
785 }
786
787 pub fn teleport_entity(&mut self, p: &ClientboundTeleportEntity) {
788 debug!("Got teleport entity packet {p:?}");
789
790 as_system::<(Commands, Query<(&EntityIdIndex, &InstanceHolder)>)>(
791 self.ecs,
792 |(mut commands, mut query)| {
793 let (entity_id_index, instance_holder) = query.get_mut(self.player).unwrap();
794
795 let Some(entity) = entity_id_index.get_by_minecraft_entity(p.id) else {
796 warn!("Got teleport entity packet for unknown entity id {}", p.id);
797 return;
798 };
799
800 let relative = p.relative.clone();
801 let change = p.change.clone();
802
803 commands.entity(entity).queue(RelativeEntityUpdate::new(
804 instance_holder.partial_instance.clone(),
805 move |entity| {
806 let entity_id = entity.id();
807 entity.world_scope(move |world| {
808 let mut query =
809 world.query::<(&mut Physics, &mut LookDirection, &mut Position)>();
810 let (mut physics, mut look_direction, mut position) =
811 query.get_mut(world, entity_id).unwrap();
812 let old_position = *position;
813 relative.apply(
814 &change,
815 &mut position,
816 &mut look_direction,
817 &mut physics,
818 );
819 physics.set_old_pos(old_position);
821 });
822 },
823 ));
824 },
825 );
826 }
827
828 pub fn update_advancements(&mut self, p: &ClientboundUpdateAdvancements) {
829 debug!("Got update advancements packet {p:?}");
830 }
831
832 pub fn rotate_head(&mut self, _p: &ClientboundRotateHead) {}
833
834 pub fn move_entity_pos(&mut self, p: &ClientboundMoveEntityPos) {
835 as_system::<(Commands, Query<(&EntityIdIndex, &InstanceHolder)>)>(
836 self.ecs,
837 |(mut commands, mut query)| {
838 let (entity_id_index, instance_holder) = query.get_mut(self.player).unwrap();
839
840 debug!("Got move entity pos packet {p:?}");
841
842 let entity_id = p.entity_id;
843 let Some(entity) = entity_id_index.get_by_minecraft_entity(entity_id) else {
844 debug!("Got move entity pos packet for unknown entity id {entity_id}");
845 return;
846 };
847
848 let new_delta = p.delta.clone();
849 let new_on_ground = p.on_ground;
850 commands.entity(entity).queue(RelativeEntityUpdate::new(
851 instance_holder.partial_instance.clone(),
852 move |entity_mut| {
853 let mut physics = entity_mut.get_mut::<Physics>().unwrap();
854 let new_pos = physics.vec_delta_codec.decode(&new_delta);
855 physics.vec_delta_codec.set_base(new_pos);
856 physics.set_on_ground(new_on_ground);
857
858 let mut position = entity_mut.get_mut::<Position>().unwrap();
859 if new_pos != **position {
860 **position = new_pos;
861 }
862
863 trace!(
864 "Applied movement update for {entity_id} / {entity}",
865 entity = entity_mut.id()
866 );
867 },
868 ));
869 },
870 );
871 }
872
873 pub fn move_entity_pos_rot(&mut self, p: &ClientboundMoveEntityPosRot) {
874 as_system::<(Commands, Query<(&EntityIdIndex, &InstanceHolder)>)>(
875 self.ecs,
876 |(mut commands, mut query)| {
877 let (entity_id_index, instance_holder) = query.get_mut(self.player).unwrap();
878
879 debug!("Got move entity pos rot packet {p:?}");
880
881 let entity = entity_id_index.get_by_minecraft_entity(p.entity_id);
882
883 let Some(entity) = entity else {
884 debug!(
886 "Got move entity pos rot packet for unknown entity id {}",
887 p.entity_id
888 );
889 return;
890 };
891
892 let new_delta = p.delta.clone();
893 let new_look_direction = LookDirection::new(
894 (p.y_rot as i32 * 360) as f32 / 256.,
895 (p.x_rot as i32 * 360) as f32 / 256.,
896 );
897
898 let new_on_ground = p.on_ground;
899
900 commands.entity(entity).queue(RelativeEntityUpdate::new(
901 instance_holder.partial_instance.clone(),
902 move |entity_mut| {
903 let mut physics = entity_mut.get_mut::<Physics>().unwrap();
904 let new_position = physics.vec_delta_codec.decode(&new_delta);
905 physics.vec_delta_codec.set_base(new_position);
906 physics.set_on_ground(new_on_ground);
907
908 let mut position = entity_mut.get_mut::<Position>().unwrap();
909 if new_position != **position {
910 **position = new_position;
911 }
912
913 let mut look_direction = entity_mut.get_mut::<LookDirection>().unwrap();
914 if new_look_direction != *look_direction {
915 *look_direction = new_look_direction;
916 }
917 },
918 ));
919 },
920 );
921 }
922
923 pub fn move_entity_rot(&mut self, p: &ClientboundMoveEntityRot) {
924 as_system::<(Commands, Query<(&EntityIdIndex, &InstanceHolder)>)>(
925 self.ecs,
926 |(mut commands, mut query)| {
927 let (entity_id_index, instance_holder) = query.get_mut(self.player).unwrap();
928
929 let entity = entity_id_index.get_by_minecraft_entity(p.entity_id);
930 if let Some(entity) = entity {
931 let new_look_direction = LookDirection::new(
932 (p.y_rot as i32 * 360) as f32 / 256.,
933 (p.x_rot as i32 * 360) as f32 / 256.,
934 );
935 let new_on_ground = p.on_ground;
936
937 commands.entity(entity).queue(RelativeEntityUpdate::new(
938 instance_holder.partial_instance.clone(),
939 move |entity_mut| {
940 let mut physics = entity_mut.get_mut::<Physics>().unwrap();
941 physics.set_on_ground(new_on_ground);
942
943 let mut look_direction = entity_mut.get_mut::<LookDirection>().unwrap();
944 if new_look_direction != *look_direction {
945 *look_direction = new_look_direction;
946 }
947 },
948 ));
949 } else {
950 warn!(
951 "Got move entity rot packet for unknown entity id {}",
952 p.entity_id
953 );
954 }
955 },
956 );
957 }
958 pub fn keep_alive(&mut self, p: &ClientboundKeepAlive) {
959 debug!("Got keep alive packet {p:?} for {:?}", self.player);
960
961 as_system::<(MessageWriter<KeepAliveEvent>, Commands)>(
962 self.ecs,
963 |(mut keepalive_events, mut commands)| {
964 keepalive_events.write(KeepAliveEvent {
965 entity: self.player,
966 id: p.id,
967 });
968 commands.trigger(SendGamePacketEvent::new(
969 self.player,
970 ServerboundKeepAlive { id: p.id },
971 ));
972 },
973 );
974 }
975
976 pub fn remove_entities(&mut self, p: &ClientboundRemoveEntities) {
977 debug!("Got remove entities packet {p:?}");
978
979 as_system::<(Query<&mut EntityIdIndex>, Query<&mut LoadedBy>)>(
980 self.ecs,
981 |(mut query, mut entity_query)| {
982 let Ok(mut entity_id_index) = query.get_mut(self.player) else {
983 warn!("our local player doesn't have EntityIdIndex");
984 return;
985 };
986
987 for &id in &p.entity_ids {
988 let Some(entity) = entity_id_index.remove_by_minecraft_entity(id) else {
989 debug!(
990 "Tried to remove entity with id {id} but it wasn't in the EntityIdIndex. This may be expected on certain server setups (like if they're using VeryManyPlayers)."
991 );
992 continue;
993 };
994 let Ok(mut loaded_by) = entity_query.get_mut(entity) else {
995 warn!(
996 "tried to despawn entity {id} but it doesn't have a LoadedBy component",
997 );
998 continue;
999 };
1000
1001 loaded_by.remove(&self.player);
1008 }
1009 },
1010 );
1011 }
1012 pub fn player_chat(&mut self, p: &ClientboundPlayerChat) {
1013 debug!("Got player chat packet {p:?}");
1014
1015 as_system::<MessageWriter<_>>(self.ecs, |mut events| {
1016 events.write(ChatReceivedEvent {
1017 entity: self.player,
1018 packet: ChatPacket::Player(Arc::new(p.clone())),
1019 });
1020 });
1021 }
1022
1023 pub fn system_chat(&mut self, p: &ClientboundSystemChat) {
1024 debug!("Got system chat packet {p:?}");
1025
1026 as_system::<MessageWriter<_>>(self.ecs, |mut events| {
1027 events.write(ChatReceivedEvent {
1028 entity: self.player,
1029 packet: ChatPacket::System(Arc::new(p.clone())),
1030 });
1031 });
1032 }
1033
1034 pub fn disguised_chat(&mut self, p: &ClientboundDisguisedChat) {
1035 debug!("Got disguised chat packet {p:?}");
1036
1037 as_system::<MessageWriter<_>>(self.ecs, |mut events| {
1038 events.write(ChatReceivedEvent {
1039 entity: self.player,
1040 packet: ChatPacket::Disguised(Arc::new(p.clone())),
1041 });
1042 });
1043 }
1044
1045 pub fn sound(&mut self, _p: &ClientboundSound) {}
1046
1047 pub fn level_event(&mut self, p: &ClientboundLevelEvent) {
1048 debug!("Got level event packet {p:?}");
1049 }
1050
1051 pub fn block_update(&mut self, p: &ClientboundBlockUpdate) {
1052 debug!("Got block update packet {p:?}");
1053
1054 as_system::<Query<&mut QueuedServerBlockUpdates>>(self.ecs, |mut query| {
1055 let mut queued = query.get_mut(self.player).unwrap();
1056 queued.list.push((p.pos, p.block_state));
1057 });
1058 }
1059
1060 pub fn animate(&mut self, p: &ClientboundAnimate) {
1061 debug!("Got animate packet {p:?}");
1062 }
1063
1064 pub fn section_blocks_update(&mut self, p: &ClientboundSectionBlocksUpdate) {
1065 debug!("Got section blocks update packet {p:?}");
1066
1067 as_system::<Query<&mut QueuedServerBlockUpdates>>(self.ecs, |mut query| {
1068 let mut queued = query.get_mut(self.player).unwrap();
1069 for new_state in &p.states {
1070 let pos = p.section_pos + new_state.pos;
1071 queued.list.push((pos, new_state.state));
1072 }
1073 });
1074 }
1075
1076 pub fn game_event(&mut self, p: &ClientboundGameEvent) {
1077 use azalea_protocol::packets::game::c_game_event::EventType;
1078
1079 debug!("Got game event packet {p:?}");
1080
1081 #[allow(clippy::single_match)]
1082 match p.event {
1083 EventType::ChangeGameMode => {
1084 as_system::<Query<&mut LocalGameMode>>(self.ecs, |mut query| {
1085 let mut local_game_mode = query.get_mut(self.player).unwrap();
1086 if let Some(new_game_mode) = GameMode::from_id(p.param as u8) {
1087 local_game_mode.current = new_game_mode;
1088 }
1089 });
1090 }
1091 _ => {}
1092 }
1093 }
1094
1095 pub fn level_particles(&mut self, p: &ClientboundLevelParticles) {
1096 debug!("Got level particles packet {p:?}");
1097 }
1098
1099 pub fn server_data(&mut self, p: &ClientboundServerData) {
1100 debug!("Got server data packet {p:?}");
1101 }
1102
1103 pub fn set_equipment(&mut self, p: &ClientboundSetEquipment) {
1104 debug!("Got set equipment packet {p:?}");
1105 }
1106
1107 pub fn update_mob_effect(&mut self, p: &ClientboundUpdateMobEffect) {
1108 debug!("Got update mob effect packet {p:?}");
1109 }
1110
1111 pub fn award_stats(&mut self, _p: &ClientboundAwardStats) {}
1112
1113 pub fn block_changed_ack(&mut self, p: &ClientboundBlockChangedAck) {
1114 as_system::<Query<(&InstanceHolder, &mut BlockStatePredictionHandler)>>(
1115 self.ecs,
1116 |mut query| {
1117 let (local_player, mut prediction_handler) = query.get_mut(self.player).unwrap();
1118 let world = local_player.instance.read();
1119 prediction_handler.end_prediction_up_to(p.seq, &world);
1120 },
1121 );
1122 }
1123
1124 pub fn block_destruction(&mut self, _p: &ClientboundBlockDestruction) {}
1125
1126 pub fn block_entity_data(&mut self, _p: &ClientboundBlockEntityData) {}
1127
1128 pub fn block_event(&mut self, p: &ClientboundBlockEvent) {
1129 debug!("Got block event packet {p:?}");
1130 }
1131
1132 pub fn boss_event(&mut self, _p: &ClientboundBossEvent) {}
1133
1134 pub fn command_suggestions(&mut self, _p: &ClientboundCommandSuggestions) {}
1135
1136 pub fn container_set_content(&mut self, p: &ClientboundContainerSetContent) {
1137 debug!("Got container set content packet {p:?}");
1138
1139 as_system::<(Commands, Query<&mut Inventory>)>(self.ecs, |(mut commands, mut query)| {
1140 let mut inventory = query.get_mut(self.player).unwrap();
1141
1142 if p.container_id == 0 {
1144 for (i, slot) in p.items.iter().enumerate() {
1146 if let Some(slot_mut) = inventory.inventory_menu.slot_mut(i) {
1147 *slot_mut = slot.clone();
1148 }
1149 }
1150 } else {
1151 commands.trigger(SetContainerContentEvent {
1152 entity: self.player,
1153 slots: p.items.clone(),
1154 container_id: p.container_id,
1155 });
1156 }
1157 });
1158 }
1159
1160 pub fn container_set_data(&mut self, p: &ClientboundContainerSetData) {
1161 debug!("Got container set data packet {p:?}");
1162
1163 }
1172
1173 pub fn container_set_slot(&mut self, p: &ClientboundContainerSetSlot) {
1174 debug!("Got container set slot packet {p:?}");
1175
1176 as_system::<Query<&mut Inventory>>(self.ecs, |mut query| {
1177 let mut inventory = query.get_mut(self.player).unwrap();
1178
1179 if p.container_id == -1 {
1180 inventory.carried = p.item_stack.clone();
1182 } else if p.container_id == -2 {
1183 if let Some(slot) = inventory.inventory_menu.slot_mut(p.slot.into()) {
1184 *slot = p.item_stack.clone();
1185 }
1186 } else {
1187 let is_creative_mode_and_inventory_closed = false;
1188 if p.container_id == 0 && azalea_inventory::Player::is_hotbar_slot(p.slot.into()) {
1191 if let Some(slot) = inventory.inventory_menu.slot_mut(p.slot.into()) {
1194 *slot = p.item_stack.clone();
1195 }
1196 } else if p.container_id == inventory.id
1197 && (p.container_id != 0 || !is_creative_mode_and_inventory_closed)
1198 {
1199 if let Some(slot) = inventory.menu_mut().slot_mut(p.slot.into()) {
1201 *slot = p.item_stack.clone();
1202 inventory.state_id = p.state_id;
1203 }
1204 }
1205 }
1206 });
1207 }
1208
1209 pub fn container_close(&mut self, p: &ClientboundContainerClose) {
1210 debug!("Got container close packet {p:?}");
1214
1215 as_system::<Commands>(self.ecs, |mut commands| {
1216 commands.trigger(ClientsideCloseContainerEvent {
1217 entity: self.player,
1218 });
1219 });
1220 }
1221
1222 pub fn cooldown(&mut self, _p: &ClientboundCooldown) {}
1223
1224 pub fn custom_chat_completions(&mut self, _p: &ClientboundCustomChatCompletions) {}
1225
1226 pub fn delete_chat(&mut self, _p: &ClientboundDeleteChat) {}
1227
1228 pub fn explode(&mut self, p: &ClientboundExplode) {
1229 trace!("Got explode packet {p:?}");
1230
1231 as_system::<MessageWriter<_>>(self.ecs, |mut knockback_events| {
1232 if let Some(knockback) = p.player_knockback {
1233 knockback_events.write(KnockbackEvent {
1234 entity: self.player,
1235 knockback: KnockbackType::Set(knockback),
1236 });
1237 }
1238 });
1239 }
1240
1241 pub fn forget_level_chunk(&mut self, p: &ClientboundForgetLevelChunk) {
1242 debug!("Got forget level chunk packet {p:?}");
1243
1244 as_system::<Query<&InstanceHolder>>(self.ecs, |mut query| {
1245 let local_player = query.get_mut(self.player).unwrap();
1246
1247 let mut partial_instance = local_player.partial_instance.write();
1248
1249 partial_instance.chunks.limited_set(&p.pos, None);
1250 });
1251 }
1252
1253 pub fn horse_screen_open(&mut self, _p: &ClientboundHorseScreenOpen) {}
1254
1255 pub fn map_item_data(&mut self, _p: &ClientboundMapItemData) {}
1256
1257 pub fn merchant_offers(&mut self, _p: &ClientboundMerchantOffers) {}
1258
1259 pub fn move_vehicle(&mut self, _p: &ClientboundMoveVehicle) {}
1260
1261 pub fn open_book(&mut self, _p: &ClientboundOpenBook) {}
1262
1263 pub fn open_screen(&mut self, p: &ClientboundOpenScreen) {
1264 debug!("Got open screen packet {p:?}");
1265
1266 as_system::<Commands>(self.ecs, |mut commands| {
1267 commands.trigger(MenuOpenedEvent {
1268 entity: self.player,
1269 window_id: p.container_id,
1270 menu_type: p.menu_type,
1271 title: p.title.to_owned(),
1272 });
1273 });
1274 }
1275
1276 pub fn open_sign_editor(&mut self, _p: &ClientboundOpenSignEditor) {}
1277
1278 pub fn ping(&mut self, p: &ClientboundPing) {
1279 debug!("Got ping packet {p:?}");
1280
1281 as_system::<Commands>(self.ecs, |mut commands| {
1282 commands.trigger(GamePingEvent {
1283 entity: self.player,
1284 packet: p.clone(),
1285 });
1286 });
1287 }
1288
1289 pub fn place_ghost_recipe(&mut self, _p: &ClientboundPlaceGhostRecipe) {}
1290
1291 pub fn player_combat_end(&mut self, _p: &ClientboundPlayerCombatEnd) {}
1292
1293 pub fn player_combat_enter(&mut self, _p: &ClientboundPlayerCombatEnter) {}
1294
1295 pub fn player_combat_kill(&mut self, p: &ClientboundPlayerCombatKill) {
1296 debug!("Got player kill packet {p:?}");
1297
1298 as_system::<(
1299 Commands,
1300 Query<(&MinecraftEntityId, Option<&Dead>)>,
1301 MessageWriter<_>,
1302 )>(self.ecs, |(mut commands, mut query, mut events)| {
1303 let (entity_id, dead) = query.get_mut(self.player).unwrap();
1304
1305 if *entity_id == p.player_id && dead.is_none() {
1306 commands.entity(self.player).insert(Dead);
1307 events.write(DeathEvent {
1308 entity: self.player,
1309 packet: Some(p.clone()),
1310 });
1311 }
1312 });
1313 }
1314
1315 pub fn player_look_at(&mut self, _p: &ClientboundPlayerLookAt) {}
1316
1317 pub fn remove_mob_effect(&mut self, _p: &ClientboundRemoveMobEffect) {}
1318
1319 pub fn resource_pack_push(&mut self, p: &ClientboundResourcePackPush) {
1320 debug!("Got resource pack packet {p:?}");
1321
1322 as_system::<MessageWriter<_>>(self.ecs, |mut events| {
1323 events.write(ResourcePackEvent {
1324 entity: self.player,
1325 id: p.id,
1326 url: p.url.to_owned(),
1327 hash: p.hash.to_owned(),
1328 required: p.required,
1329 prompt: p.prompt.to_owned(),
1330 });
1331 });
1332 }
1333
1334 pub fn resource_pack_pop(&mut self, _p: &ClientboundResourcePackPop) {}
1335
1336 pub fn respawn(&mut self, p: &ClientboundRespawn) {
1337 debug!("Got respawn packet {p:?}");
1338
1339 as_system::<(
1340 Commands,
1341 Query<
1342 (
1343 &mut InstanceHolder,
1344 &GameProfileComponent,
1345 &ClientInformation,
1346 Option<&mut InstanceName>,
1347 ),
1348 With<LocalEntity>,
1349 >,
1350 MessageWriter<_>,
1351 ResMut<InstanceContainer>,
1352 Query<&mut LoadedBy, Without<LocalEntity>>,
1353 )>(
1354 self.ecs,
1355 |(mut commands, mut query, mut events, mut instance_container, mut loaded_by_query)| {
1356 let Ok((mut instance_holder, game_profile, client_information, instance_name)) =
1357 query.get_mut(self.player)
1358 else {
1359 warn!("Got respawn packet but player doesn't have the required components");
1360 return;
1361 };
1362
1363 let new_instance_name = p.common.dimension.clone();
1364
1365 if let Some(mut instance_name) = instance_name {
1366 **instance_name = new_instance_name.clone();
1367 } else {
1368 commands
1369 .entity(self.player)
1370 .insert(InstanceName(new_instance_name.clone()));
1371 }
1372
1373 let Some((_dimension_type, dimension_data)) = p
1374 .common
1375 .dimension_type(&instance_holder.instance.read().registries)
1376 else {
1377 return;
1378 };
1379
1380 let weak_instance = instance_container.get_or_insert(
1383 new_instance_name.clone(),
1384 dimension_data.height,
1385 dimension_data.min_y,
1386 &instance_holder.instance.read().registries,
1387 );
1388 events.write(InstanceLoadedEvent {
1389 entity: self.player,
1390 name: new_instance_name.clone(),
1391 instance: Arc::downgrade(&weak_instance),
1392 });
1393
1394 *instance_holder.partial_instance.write() = PartialInstance::new(
1399 azalea_world::chunk_storage::calculate_chunk_storage_range(
1400 client_information.view_distance.into(),
1401 ),
1402 Some(self.player),
1403 );
1404 instance_holder.instance = weak_instance;
1405
1406 for mut loaded_by in &mut loaded_by_query.iter_mut() {
1408 loaded_by.remove(&self.player);
1409 }
1410
1411 let entity_bundle = EntityBundle::new(
1413 game_profile.uuid,
1414 Vec3::ZERO,
1415 azalea_registry::EntityKind::Player,
1416 new_instance_name,
1417 );
1418 commands.entity(self.player).insert((
1420 LocalGameMode {
1421 current: p.common.game_type,
1422 previous: p.common.previous_game_type.into(),
1423 },
1424 entity_bundle,
1425 ));
1426
1427 commands
1428 .entity(self.player)
1429 .remove::<(Dead, HasClientLoaded)>();
1430 },
1431 )
1432 }
1433
1434 pub fn start_configuration(&mut self, _p: &ClientboundStartConfiguration) {
1435 debug!("Got start configuration packet");
1436
1437 as_system::<(Commands, Query<(&mut RawConnection, &mut InstanceHolder)>)>(
1438 self.ecs,
1439 |(mut commands, mut query)| {
1440 let Some((mut raw_conn, mut instance_holder)) = query.get_mut(self.player).ok()
1441 else {
1442 warn!("Got start configuration packet but player doesn't have a RawConnection");
1443 return;
1444 };
1445 raw_conn.state = ConnectionProtocol::Configuration;
1446
1447 commands.trigger(SendGamePacketEvent::new(
1448 self.player,
1449 ServerboundConfigurationAcknowledged,
1450 ));
1451
1452 commands
1453 .entity(self.player)
1454 .insert(crate::client::InConfigState)
1455 .remove::<crate::JoinedClientBundle>()
1456 .remove::<EntityBundle>();
1457
1458 instance_holder.reset();
1459 },
1460 );
1461 }
1462
1463 pub fn entity_position_sync(&mut self, p: &ClientboundEntityPositionSync) {
1464 as_system::<(Commands, Query<(&EntityIdIndex, &InstanceHolder)>)>(
1465 self.ecs,
1466 |(mut commands, mut query)| {
1467 let (entity_id_index, instance_holder) = query.get_mut(self.player).unwrap();
1468
1469 let Some(entity) = entity_id_index.get_by_minecraft_entity(p.id) else {
1470 debug!("Got teleport entity packet for unknown entity id {}", p.id);
1471 return;
1472 };
1473
1474 let new_position = p.values.pos;
1475 let new_on_ground = p.on_ground;
1476 let new_look_direction = p.values.look_direction;
1477
1478 commands.entity(entity).queue(RelativeEntityUpdate::new(
1479 instance_holder.partial_instance.clone(),
1480 move |entity_mut| {
1481 let is_local_entity = entity_mut.get::<LocalEntity>().is_some();
1482 let mut physics = entity_mut.get_mut::<Physics>().unwrap();
1483
1484 physics.vec_delta_codec.set_base(new_position);
1485
1486 if is_local_entity {
1487 debug!("Ignoring entity position sync packet for local player");
1488 return;
1489 }
1490
1491 physics.set_on_ground(new_on_ground);
1492
1493 let mut position = entity_mut.get_mut::<Position>().unwrap();
1494 **position = new_position;
1495
1496 let mut look_direction = entity_mut.get_mut::<LookDirection>().unwrap();
1497 *look_direction = new_look_direction;
1498 },
1499 ));
1500 },
1501 );
1502 }
1503
1504 pub fn select_advancements_tab(&mut self, _p: &ClientboundSelectAdvancementsTab) {}
1505 pub fn set_action_bar_text(&mut self, _p: &ClientboundSetActionBarText) {}
1506 pub fn set_border_center(&mut self, _p: &ClientboundSetBorderCenter) {}
1507 pub fn set_border_lerp_size(&mut self, _p: &ClientboundSetBorderLerpSize) {}
1508 pub fn set_border_size(&mut self, _p: &ClientboundSetBorderSize) {}
1509 pub fn set_border_warning_delay(&mut self, _p: &ClientboundSetBorderWarningDelay) {}
1510 pub fn set_border_warning_distance(&mut self, _p: &ClientboundSetBorderWarningDistance) {}
1511 pub fn set_camera(&mut self, _p: &ClientboundSetCamera) {}
1512 pub fn set_display_objective(&mut self, _p: &ClientboundSetDisplayObjective) {}
1513 pub fn set_objective(&mut self, _p: &ClientboundSetObjective) {}
1514 pub fn set_passengers(&mut self, _p: &ClientboundSetPassengers) {}
1515 pub fn set_player_team(&mut self, p: &ClientboundSetPlayerTeam) {
1516 debug!("Got set player team packet {p:?}");
1517 }
1518 pub fn set_score(&mut self, _p: &ClientboundSetScore) {}
1519 pub fn set_simulation_distance(&mut self, _p: &ClientboundSetSimulationDistance) {}
1520 pub fn set_subtitle_text(&mut self, _p: &ClientboundSetSubtitleText) {}
1521 pub fn set_title_text(&mut self, _p: &ClientboundSetTitleText) {}
1522 pub fn set_titles_animation(&mut self, _p: &ClientboundSetTitlesAnimation) {}
1523 pub fn clear_titles(&mut self, _p: &ClientboundClearTitles) {}
1524 pub fn sound_entity(&mut self, _p: &ClientboundSoundEntity) {}
1525 pub fn stop_sound(&mut self, _p: &ClientboundStopSound) {}
1526 pub fn tab_list(&mut self, _p: &ClientboundTabList) {}
1527 pub fn tag_query(&mut self, _p: &ClientboundTagQuery) {}
1528 pub fn take_item_entity(&mut self, _p: &ClientboundTakeItemEntity) {}
1529 pub fn bundle_delimiter(&mut self, _p: &ClientboundBundleDelimiter) {}
1530 pub fn damage_event(&mut self, _p: &ClientboundDamageEvent) {}
1531 pub fn hurt_animation(&mut self, _p: &ClientboundHurtAnimation) {}
1532 pub fn ticking_state(&mut self, _p: &ClientboundTickingState) {}
1533 pub fn ticking_step(&mut self, _p: &ClientboundTickingStep) {}
1534 pub fn reset_score(&mut self, _p: &ClientboundResetScore) {}
1535 pub fn cookie_request(&mut self, _p: &ClientboundCookieRequest) {}
1536 pub fn debug_sample(&mut self, _p: &ClientboundDebugSample) {}
1537 pub fn pong_response(&mut self, _p: &ClientboundPongResponse) {}
1538 pub fn store_cookie(&mut self, _p: &ClientboundStoreCookie) {}
1539 pub fn transfer(&mut self, _p: &ClientboundTransfer) {}
1540 pub fn move_minecart_along_track(&mut self, _p: &ClientboundMoveMinecartAlongTrack) {}
1541 pub fn set_held_slot(&mut self, p: &ClientboundSetHeldSlot) {
1542 debug!("Got set held slot packet {p:?}");
1543
1544 as_system::<Query<&mut Inventory>>(self.ecs, |mut query| {
1545 let mut inventory = query.get_mut(self.player).unwrap();
1546 if p.slot <= 8 {
1547 inventory.selected_hotbar_slot = p.slot as u8;
1548 }
1549 });
1550 }
1551 pub fn set_player_inventory(&mut self, _p: &ClientboundSetPlayerInventory) {}
1552 pub fn projectile_power(&mut self, _p: &ClientboundProjectilePower) {}
1553 pub fn custom_report_details(&mut self, _p: &ClientboundCustomReportDetails) {}
1554 pub fn server_links(&mut self, _p: &ClientboundServerLinks) {}
1555 pub fn player_rotation(&mut self, _p: &ClientboundPlayerRotation) {}
1556 pub fn recipe_book_add(&mut self, _p: &ClientboundRecipeBookAdd) {}
1557 pub fn recipe_book_remove(&mut self, _p: &ClientboundRecipeBookRemove) {}
1558 pub fn recipe_book_settings(&mut self, _p: &ClientboundRecipeBookSettings) {}
1559 pub fn test_instance_block_status(&mut self, _p: &ClientboundTestInstanceBlockStatus) {}
1560 pub fn waypoint(&mut self, _p: &ClientboundWaypoint) {}
1561
1562 pub fn clear_dialog(&mut self, p: &ClientboundClearDialog) {
1563 debug!("Got clear dialog packet {p:?}");
1564 }
1565 pub fn show_dialog(&mut self, p: &ClientboundShowDialog) {
1566 debug!("Got show dialog packet {p:?}");
1567 }
1568
1569 pub fn debug_block_value(&mut self, p: &ClientboundDebugBlockValue) {
1570 debug!("Got debug block value packet {p:?}");
1571 }
1572 pub fn debug_chunk_value(&mut self, p: &ClientboundDebugChunkValue) {
1573 debug!("Got debug chunk value packet {p:?}");
1574 }
1575 pub fn debug_entity_value(&mut self, p: &ClientboundDebugEntityValue) {
1576 debug!("Got debug entity value packet {p:?}");
1577 }
1578
1579 pub fn debug_event(&mut self, p: &ClientboundDebugEvent) {
1580 debug!("Got debug event packet {p:?}");
1581 }
1582 pub fn game_test_highlight_pos(&mut self, p: &ClientboundGameTestHighlightPos) {
1583 debug!("Got game test highlight pos packet {p:?}");
1584 }
1585}