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