Skip to main content

kojacoord_protocol/versions/v1_21/play/
mod.rs

1use bytes::{Buf, BufMut, Bytes, BytesMut};
2
3use crate::codec::{Decode, Encode, PacketId};
4use crate::error::ProtocolError;
5use crate::types::VarInt;
6
7fn need(src: &Bytes, n: usize) -> Result<(), ProtocolError> {
8    if src.remaining() < n {
9        Err(ProtocolError::Io(std::io::Error::new(
10            std::io::ErrorKind::UnexpectedEof,
11            format!("need {} bytes, only {} remaining", n, src.remaining()),
12        )))
13    } else {
14        Ok(())
15    }
16}
17
18fn encode_string(s: &str, dst: &mut BytesMut) -> Result<(), ProtocolError> {
19    VarInt(s.len() as i32).encode(dst)?;
20    dst.extend_from_slice(s.as_bytes());
21    Ok(())
22}
23
24fn decode_string(src: &mut Bytes) -> Result<String, ProtocolError> {
25    let len = VarInt::decode(src)?.0 as usize;
26    need(src, len)?;
27    let bytes = src.copy_to_bytes(len);
28    String::from_utf8(bytes.to_vec()).map_err(|_| {
29        ProtocolError::Io(std::io::Error::new(
30            std::io::ErrorKind::InvalidData,
31            "invalid utf-8 string",
32        ))
33    })
34}
35
36pub use packets::{
37    ClientboundAcknowledgeBlockChange, ClientboundAwardStats, ClientboundBlockAction,
38    ClientboundBlockDestroyStage, ClientboundBlockEntityData, ClientboundBlockUpdate,
39    ClientboundBossBar, ClientboundBundle, ClientboundChangeDifficulty,
40    ClientboundChunkBatchFinished, ClientboundChunkBatchStart, ClientboundChunkBiomes,
41    ClientboundClearTitles, ClientboundCommandSuggestions, ClientboundCommands,
42    ClientboundContainerClose, ClientboundContainerSetContent, ClientboundContainerSetProperty,
43    ClientboundContainerSetSlot, ClientboundCookieRequest, ClientboundCooldown,
44    ClientboundCustomChatCompletions, ClientboundDamageEvent, ClientboundDebugSample,
45    ClientboundDeleteChat, ClientboundDisconnect, ClientboundDisguisedChat,
46    ClientboundEntityAnimation, ClientboundEntityEvent, ClientboundExplosion,
47    ClientboundForgetLevelChunk, ClientboundGameEvent, ClientboundHorseScreenOpen,
48    ClientboundHurtAnimation, ClientboundInitializeBorder, ClientboundKeepAlive,
49    ClientboundLevelChunkWithLight, ClientboundLevelEvent, ClientboundLevelParticles,
50    ClientboundLightUpdate, ClientboundLogin, ClientboundMapItemData, ClientboundMerchantOffers,
51    ClientboundMoveEntityPos, ClientboundMoveEntityPosRot, ClientboundMoveEntityRot,
52    ClientboundMoveVehicle, ClientboundOpenBook, ClientboundOpenScreen, ClientboundOpenSignEditor,
53    ClientboundPing, ClientboundPlaceGhostRecipe, ClientboundPlayerAbilities,
54    ClientboundPlayerChat, ClientboundPlayerCombatEnd, ClientboundPlayerCombatEnter,
55    ClientboundPlayerCombatKill, ClientboundPlayerInfoRemove, ClientboundPlayerInfoUpdate,
56    ClientboundPlayerLookAt, ClientboundPlayerPosition, ClientboundPluginMessage,
57    ClientboundRecipeBookSettings, ClientboundRecipes, ClientboundRemoveEntities,
58    ClientboundRemoveEntityEffect, ClientboundResetScore, ClientboundResourcePackPop,
59    ClientboundResourcePackPush, ClientboundRespawn, ClientboundRotateHead,
60    ClientboundSectionBlocksUpdate, ClientboundSelectAdvancementsTab, ClientboundServerData,
61    ClientboundSetActionBarText, ClientboundSetBorderCenter, ClientboundSetBorderLerpSize,
62    ClientboundSetBorderSize, ClientboundSetBorderWarningDelay,
63    ClientboundSetBorderWarningDistance, ClientboundSetCamera, ClientboundSetCarriedItem,
64    ClientboundSetCursorItem, ClientboundSetEntityLink, ClientboundSetEntityMotion,
65    ClientboundSetEquipment, ClientboundSetExperience, ClientboundSetHealth,
66    ClientboundSetPlayerInventory, ClientboundSetScoreboardObjective,
67    ClientboundSetScoreboardScore, ClientboundSetSimulationDistance, ClientboundSetSubtitleText,
68    ClientboundSetTime, ClientboundSetTitleAnimationTimes, ClientboundSetTitleText,
69    ClientboundSound, ClientboundSoundEntity, ClientboundSpawnEntity,
70    ClientboundSpawnExperienceOrb, ClientboundSpawnPlayer, ClientboundStartConfiguration,
71    ClientboundStopSound, ClientboundStoreCookie, ClientboundSystemChat, ClientboundTabList,
72    ClientboundTagQuery, ClientboundTakeItemEntity, ClientboundTeleportEntity,
73    ClientboundTickingState, ClientboundTickingStep, ClientboundTransfer,
74    ClientboundUpdateAdvancements, ClientboundUpdateAttributes, ClientboundUpdateEffects,
75    ClientboundUpdateRecipes, ClientboundUpdateTags, InteractAction,
76    ServerboundAcceptTeleportation, ServerboundButtonPressed, ServerboundChatCommand,
77    ServerboundChatMessage, ServerboundChatSessionUpdate, ServerboundClickWindow,
78    ServerboundClickWindowButton, ServerboundClientInformation, ServerboundClientStatus,
79    ServerboundCloseWindow, ServerboundCommandSuggestion, ServerboundConfigurationAcknowledged,
80    ServerboundCreativeInventoryAction, ServerboundDifficultyChange, ServerboundDifficultyLock,
81    ServerboundEditBook, ServerboundEntityAction, ServerboundEntityTagQuery,
82    ServerboundHeldItemChange, ServerboundInteract, ServerboundJigsawGenerate,
83    ServerboundKeepAlive, ServerboundMovePlayerPos, ServerboundMovePlayerPosRot,
84    ServerboundMovePlayerRot, ServerboundMovePlayerStatusOnly, ServerboundPaddleBoat,
85    ServerboundPickItem, ServerboundPlaceRecipe, ServerboundPlayerAbilities,
86    ServerboundPlayerAction, ServerboundPlayerWeaponAttack, ServerboundPluginMessage,
87    ServerboundPong, ServerboundRecipeBookChangeSettings, ServerboundRecipeBookSeenRecipe,
88    ServerboundRenameItem, ServerboundResourcePackStatus, ServerboundSelectTrade,
89    ServerboundSetBeaconEffect, ServerboundSetCreativeModeSlot, ServerboundSetMerchantTrade,
90    ServerboundSetStructureBlock, ServerboundSpectate, ServerboundSteerBoat,
91    ServerboundSteerVehicle, ServerboundSwingArm, ServerboundUpdateCommandBlock,
92    ServerboundUpdateCommandBlockMinecart, ServerboundUpdateSign, ServerboundUseItem,
93    ServerboundUseItemOn, ServerboundVehicleMove,
94};
95
96mod packets {
97    use super::*;
98
99    macro_rules! passthrough {
100        ($(#[$meta:meta])* $name:ident, $id:expr) => {
101            $(#[$meta])*
102            #[derive(Debug, Clone, PartialEq)]
103            pub struct $name { pub raw: Vec<u8> }
104
105            impl PacketId for $name {
106                fn packet_id(_ver: u32) -> u8 { $id }
107            }
108
109            impl Encode for $name {
110                fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
111                    dst.extend_from_slice(&self.raw);
112                    Ok(())
113                }
114            }
115
116            impl Decode for $name {
117                fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
118                    let raw = src.copy_to_bytes(src.remaining()).to_vec();
119                    Ok(Self { raw })
120                }
121            }
122        };
123    }
124
125    #[derive(Debug, Clone, PartialEq)]
126    pub struct ClientboundKeepAlive {
127        pub keep_alive_id: i64,
128    }
129
130    impl PacketId for ClientboundKeepAlive {
131        fn packet_id(_ver: u32) -> u8 {
132            0x29
133        }
134    }
135
136    impl Encode for ClientboundKeepAlive {
137        fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
138            self.keep_alive_id.encode(dst)
139        }
140    }
141
142    impl Decode for ClientboundKeepAlive {
143        fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
144            Ok(Self {
145                keep_alive_id: i64::decode(src)?,
146            })
147        }
148    }
149
150    #[derive(Debug, Clone, PartialEq)]
151    pub struct ClientboundPlayerPosition {
152        pub x: f64,
153        pub y: f64,
154        pub z: f64,
155        pub yaw: f32,
156        pub pitch: f32,
157        pub flags: u8,
158        pub teleport_id: VarInt,
159    }
160
161    impl PacketId for ClientboundPlayerPosition {
162        fn packet_id(_ver: u32) -> u8 {
163            0x43
164        }
165    }
166
167    impl Encode for ClientboundPlayerPosition {
168        fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
169            dst.put_f64(self.x);
170            dst.put_f64(self.y);
171            dst.put_f64(self.z);
172            dst.put_f32(self.yaw);
173            dst.put_f32(self.pitch);
174            dst.put_u8(self.flags);
175            self.teleport_id.encode(dst)
176        }
177    }
178
179    impl Decode for ClientboundPlayerPosition {
180        fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
181            need(src, 8 + 8 + 8 + 4 + 4 + 1)?;
182            Ok(Self {
183                x: src.get_f64(),
184                y: src.get_f64(),
185                z: src.get_f64(),
186                yaw: src.get_f32(),
187                pitch: src.get_f32(),
188                flags: src.get_u8(),
189                teleport_id: VarInt::decode(src)?,
190            })
191        }
192    }
193
194    #[derive(Debug, Clone, PartialEq)]
195    pub struct ClientboundPluginMessage {
196        pub channel: String,
197        pub data: Vec<u8>,
198    }
199
200    impl PacketId for ClientboundPluginMessage {
201        fn packet_id(_ver: u32) -> u8 {
202            0x1A
203        }
204    }
205
206    impl Encode for ClientboundPluginMessage {
207        fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
208            encode_string(&self.channel, dst)?;
209            dst.extend_from_slice(&self.data);
210            Ok(())
211        }
212    }
213
214    impl Decode for ClientboundPluginMessage {
215        fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
216            let channel = decode_string(src)?;
217            let data = src.copy_to_bytes(src.remaining()).to_vec();
218            Ok(Self { channel, data })
219        }
220    }
221
222    #[derive(Debug, Clone, PartialEq)]
223    pub struct ClientboundSystemChat {
224        pub json_message: String,
225        pub overlay: bool,
226    }
227
228    impl PacketId for ClientboundSystemChat {
229        fn packet_id(_ver: u32) -> u8 {
230            0x6B
231        }
232    }
233
234    impl Encode for ClientboundSystemChat {
235        fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
236            encode_string(&self.json_message, dst)?;
237            dst.put_u8(self.overlay as u8);
238            Ok(())
239        }
240    }
241
242    impl Decode for ClientboundSystemChat {
243        fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
244            let json_message = decode_string(src)?;
245            need(src, 1)?;
246            let overlay = src.get_u8() != 0;
247            Ok(Self {
248                json_message,
249                overlay,
250            })
251        }
252    }
253
254    #[derive(Debug, Clone, PartialEq)]
255    pub struct ClientboundLogin {
256        pub entity_id: i32,
257        pub is_hardcore: bool,
258        pub dimension_names: Vec<String>,
259        pub max_players: VarInt,
260        pub view_distance: VarInt,
261        pub simulation_distance: VarInt,
262        pub reduced_debug_info: bool,
263        pub enable_respawn_screen: bool,
264        pub do_limited_crafting: bool,
265        pub dimension_type: VarInt,
266        pub dimension_name: String,
267        pub hashed_seed: i64,
268        pub game_mode: u8,
269        pub previous_game_mode: i8,
270        pub is_debug: bool,
271        pub is_flat: bool,
272        pub death_location: Option<(String, i64)>,
273        pub portal_cooldown: VarInt,
274        pub sea_level: VarInt,
275    }
276
277    impl PacketId for ClientboundLogin {
278        fn packet_id(_ver: u32) -> u8 {
279            0x2E
280        }
281    }
282
283    impl Encode for ClientboundLogin {
284        fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
285            dst.put_i32(self.entity_id);
286            dst.put_u8(self.is_hardcore as u8);
287            self.dimension_names.encode(dst)?;
288            self.max_players.encode(dst)?;
289            self.view_distance.encode(dst)?;
290            self.simulation_distance.encode(dst)?;
291            dst.put_u8(self.reduced_debug_info as u8);
292            dst.put_u8(self.enable_respawn_screen as u8);
293            dst.put_u8(self.do_limited_crafting as u8);
294            self.dimension_type.encode(dst)?;
295            encode_string(&self.dimension_name, dst)?;
296            dst.put_i64(self.hashed_seed);
297            dst.put_u8(self.game_mode);
298            dst.put_i8(self.previous_game_mode);
299            dst.put_u8(self.is_debug as u8);
300            dst.put_u8(self.is_flat as u8);
301            match &self.death_location {
302                Some((dim, pos)) => {
303                    dst.put_u8(1);
304                    encode_string(dim, dst)?;
305                    dst.put_i64(*pos);
306                },
307                None => dst.put_u8(0),
308            }
309            self.portal_cooldown.encode(dst)?;
310            self.sea_level.encode(dst)?;
311            Ok(())
312        }
313    }
314
315    impl Decode for ClientboundLogin {
316        fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
317            need(src, 4)?;
318            let entity_id = src.get_i32();
319            need(src, 1)?;
320            let is_hardcore = src.get_u8() != 0;
321            let dimension_names = Vec::<String>::decode(src)?;
322            let max_players = VarInt::decode(src)?;
323            let view_distance = VarInt::decode(src)?;
324            let simulation_distance = VarInt::decode(src)?;
325            need(src, 3)?;
326            let reduced_debug_info = src.get_u8() != 0;
327            let enable_respawn_screen = src.get_u8() != 0;
328            let do_limited_crafting = src.get_u8() != 0;
329            let dimension_type = VarInt::decode(src)?;
330            let dimension_name = decode_string(src)?;
331            need(src, 8)?;
332            let hashed_seed = src.get_i64();
333            need(src, 4)?;
334            let game_mode = src.get_u8();
335            let previous_game_mode = src.get_i8();
336            let is_debug = src.get_u8() != 0;
337            let is_flat = src.get_u8() != 0;
338            need(src, 1)?;
339            let death_location = if src.get_u8() != 0 {
340                let dim = decode_string(src)?;
341                need(src, 8)?;
342                let pos = src.get_i64();
343                Some((dim, pos))
344            } else {
345                None
346            };
347            let portal_cooldown = VarInt::decode(src)?;
348            let sea_level = VarInt::decode(src)?;
349            Ok(Self {
350                entity_id,
351                is_hardcore,
352                dimension_names,
353                max_players,
354                view_distance,
355                simulation_distance,
356                reduced_debug_info,
357                enable_respawn_screen,
358                do_limited_crafting,
359                dimension_type,
360                dimension_name,
361                hashed_seed,
362                game_mode,
363                previous_game_mode,
364                is_debug,
365                is_flat,
366                death_location,
367                portal_cooldown,
368                sea_level,
369            })
370        }
371    }
372
373    #[derive(Debug, Clone, PartialEq)]
374    pub struct ClientboundRespawn {
375        pub dimension_type: VarInt,
376        pub dimension_name: String,
377        pub hashed_seed: i64,
378        pub game_mode: u8,
379        pub previous_game_mode: i8,
380        pub is_debug: bool,
381        pub is_flat: bool,
382        pub data_kept: u8,
383        pub death_location: Option<(String, i64)>,
384        pub portal_cooldown: VarInt,
385        pub sea_level: VarInt,
386    }
387
388    impl PacketId for ClientboundRespawn {
389        fn packet_id(_ver: u32) -> u8 {
390            0x4B
391        }
392    }
393
394    impl Encode for ClientboundRespawn {
395        fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
396            self.dimension_type.encode(dst)?;
397            encode_string(&self.dimension_name, dst)?;
398            dst.put_i64(self.hashed_seed);
399            dst.put_u8(self.game_mode);
400            dst.put_i8(self.previous_game_mode);
401            dst.put_u8(self.is_debug as u8);
402            dst.put_u8(self.is_flat as u8);
403            dst.put_u8(self.data_kept);
404            match &self.death_location {
405                Some((dim, pos)) => {
406                    dst.put_u8(1);
407                    encode_string(dim, dst)?;
408                    dst.put_i64(*pos);
409                },
410                None => dst.put_u8(0),
411            }
412            self.portal_cooldown.encode(dst)?;
413            self.sea_level.encode(dst)?;
414            Ok(())
415        }
416    }
417
418    impl Decode for ClientboundRespawn {
419        fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
420            let dimension_type = VarInt::decode(src)?;
421            let dimension_name = decode_string(src)?;
422            need(src, 8)?;
423            let hashed_seed = src.get_i64();
424            need(src, 4)?;
425            let game_mode = src.get_u8();
426            let previous_game_mode = src.get_i8();
427            let is_debug = src.get_u8() != 0;
428            let is_flat = src.get_u8() != 0;
429            need(src, 1)?;
430            let data_kept = src.get_u8();
431            need(src, 1)?;
432            let death_location = if src.get_u8() != 0 {
433                let dim = decode_string(src)?;
434                need(src, 8)?;
435                let pos = src.get_i64();
436                Some((dim, pos))
437            } else {
438                None
439            };
440            let portal_cooldown = VarInt::decode(src)?;
441            let sea_level = VarInt::decode(src)?;
442            Ok(Self {
443                dimension_type,
444                dimension_name,
445                hashed_seed,
446                game_mode,
447                previous_game_mode,
448                is_debug,
449                is_flat,
450                data_kept,
451                death_location,
452                portal_cooldown,
453                sea_level,
454            })
455        }
456    }
457
458    #[derive(Debug, Clone, PartialEq)]
459    pub struct ClientboundSound {
460        pub sound_type: VarInt,
461        pub sound_name: String,
462        pub sound_category: VarInt,
463        pub effect_pos_x: i32,
464        pub effect_pos_y: i32,
465        pub effect_pos_z: i32,
466        pub volume: f32,
467        pub pitch: f32,
468        pub seed: i64,
469    }
470
471    impl PacketId for ClientboundSound {
472        fn packet_id(_ver: u32) -> u8 {
473            0x67
474        }
475    }
476
477    impl Encode for ClientboundSound {
478        fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
479            self.sound_type.encode(dst)?;
480            encode_string(&self.sound_name, dst)?;
481            self.sound_category.encode(dst)?;
482            dst.put_i32(self.effect_pos_x);
483            dst.put_i32(self.effect_pos_y);
484            dst.put_i32(self.effect_pos_z);
485            dst.put_f32(self.volume);
486            dst.put_f32(self.pitch);
487            dst.put_i64(self.seed);
488            Ok(())
489        }
490    }
491
492    impl Decode for ClientboundSound {
493        fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
494            let sound_type = VarInt::decode(src)?;
495            let sound_name = decode_string(src)?;
496            let sound_category = VarInt::decode(src)?;
497            need(src, 4 + 4 + 4 + 4 + 4 + 8)?;
498            let effect_pos_x = src.get_i32();
499            let effect_pos_y = src.get_i32();
500            let effect_pos_z = src.get_i32();
501            let volume = src.get_f32();
502            let pitch = src.get_f32();
503            let seed = src.get_i64();
504            Ok(Self {
505                sound_type,
506                sound_name,
507                sound_category,
508                effect_pos_x,
509                effect_pos_y,
510                effect_pos_z,
511                volume,
512                pitch,
513                seed,
514            })
515        }
516    }
517
518    #[derive(Debug, Clone, PartialEq)]
519    pub struct ClientboundDisconnect {
520        pub reason: String,
521    }
522
523    impl PacketId for ClientboundDisconnect {
524        fn packet_id(_ver: u32) -> u8 {
525            0x1E
526        }
527    }
528
529    impl Encode for ClientboundDisconnect {
530        fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
531            encode_string(&self.reason, dst)
532        }
533    }
534
535    impl Decode for ClientboundDisconnect {
536        fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
537            Ok(Self {
538                reason: decode_string(src)?,
539            })
540        }
541    }
542
543    passthrough!(ClientboundBundle, 0x00);
544    passthrough!(ClientboundSpawnEntity, 0x01);
545    passthrough!(ClientboundSpawnExperienceOrb, 0x02);
546    passthrough!(ClientboundSpawnPlayer, 0x03);
547    passthrough!(ClientboundEntityAnimation, 0x04);
548    passthrough!(ClientboundAwardStats, 0x05);
549    passthrough!(ClientboundAcknowledgeBlockChange, 0x06);
550    passthrough!(ClientboundBlockDestroyStage, 0x07);
551    passthrough!(ClientboundBlockEntityData, 0x08);
552    passthrough!(ClientboundBlockAction, 0x09);
553    passthrough!(ClientboundBlockUpdate, 0x0A);
554    passthrough!(ClientboundBossBar, 0x0B);
555    passthrough!(ClientboundChangeDifficulty, 0x0C);
556    passthrough!(ClientboundChunkBatchFinished, 0x0D);
557    passthrough!(ClientboundChunkBatchStart, 0x0E);
558    passthrough!(ClientboundChunkBiomes, 0x0F);
559    passthrough!(ClientboundClearTitles, 0x10);
560    passthrough!(ClientboundCommandSuggestions, 0x11);
561    passthrough!(ClientboundCommands, 0x12);
562    passthrough!(ClientboundContainerClose, 0x13);
563    passthrough!(ClientboundContainerSetProperty, 0x15);
564
565    #[derive(Debug, Clone, PartialEq)]
566    pub struct ClientboundContainerSetContent {
567        pub window_id: u8,
568        pub slots: Vec<crate::types::Slot>,
569        pub carried_item: crate::types::Slot,
570    }
571
572    impl PacketId for ClientboundContainerSetContent {
573        fn packet_id(_ver: u32) -> u8 {
574            0x14
575        }
576    }
577
578    impl Encode for ClientboundContainerSetContent {
579        fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
580            dst.put_u8(self.window_id);
581            VarInt(self.slots.len() as i32).encode(dst)?;
582            for slot in &self.slots {
583                slot.encode(dst)?;
584            }
585            self.carried_item.encode(dst)?;
586            Ok(())
587        }
588    }
589
590    impl Decode for ClientboundContainerSetContent {
591        fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
592            need(src, 1)?;
593            let window_id = src.get_u8();
594            let count = VarInt::decode(src)?.0 as usize;
595            let mut slots = Vec::with_capacity(count);
596            for _ in 0..count {
597                slots.push(crate::types::Slot::decode(src)?);
598            }
599            let carried_item = crate::types::Slot::decode(src)?;
600            Ok(Self {
601                window_id,
602                slots,
603                carried_item,
604            })
605        }
606    }
607
608    #[derive(Debug, Clone, PartialEq)]
609    pub struct ClientboundContainerSetSlot {
610        pub window_id: i8,
611        pub slot: i16,
612        pub slot_data: crate::types::Slot,
613    }
614
615    impl PacketId for ClientboundContainerSetSlot {
616        fn packet_id(_ver: u32) -> u8 {
617            0x16
618        }
619    }
620
621    impl Encode for ClientboundContainerSetSlot {
622        fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
623            dst.put_i8(self.window_id);
624            dst.put_i16(self.slot);
625            self.slot_data.encode(dst)?;
626            Ok(())
627        }
628    }
629
630    impl Decode for ClientboundContainerSetSlot {
631        fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
632            need(src, 1 + 2)?;
633            let window_id = src.get_i8();
634            let slot = src.get_i16();
635            let slot_data = crate::types::Slot::decode(src)?;
636            Ok(Self {
637                window_id,
638                slot,
639                slot_data,
640            })
641        }
642    }
643
644    passthrough!(ClientboundCookieRequest, 0x17);
645    passthrough!(ClientboundCooldown, 0x18);
646    passthrough!(ClientboundCustomChatCompletions, 0x19);
647    passthrough!(ClientboundDamageEvent, 0x1B);
648    passthrough!(ClientboundDebugSample, 0x1C);
649    passthrough!(ClientboundDeleteChat, 0x1D);
650    passthrough!(ClientboundDisguisedChat, 0x1F);
651    passthrough!(ClientboundEntityEvent, 0x20);
652    passthrough!(ClientboundExplosion, 0x21);
653    passthrough!(ClientboundForgetLevelChunk, 0x22);
654    passthrough!(ClientboundGameEvent, 0x23);
655    passthrough!(ClientboundHorseScreenOpen, 0x24);
656    passthrough!(ClientboundHurtAnimation, 0x25);
657    passthrough!(ClientboundInitializeBorder, 0x26);
658    passthrough!(ClientboundLevelChunkWithLight, 0x2A);
659    passthrough!(ClientboundLevelEvent, 0x2B);
660    passthrough!(ClientboundLevelParticles, 0x2C);
661    passthrough!(ClientboundLightUpdate, 0x2D);
662    passthrough!(ClientboundMapItemData, 0x2F);
663    passthrough!(ClientboundMerchantOffers, 0x30);
664    passthrough!(ClientboundMoveEntityPos, 0x31);
665    passthrough!(ClientboundMoveEntityPosRot, 0x32);
666    passthrough!(ClientboundMoveEntityRot, 0x33);
667    passthrough!(ClientboundMoveVehicle, 0x34);
668    passthrough!(ClientboundOpenBook, 0x35);
669    passthrough!(ClientboundOpenScreen, 0x36);
670    passthrough!(ClientboundOpenSignEditor, 0x37);
671    passthrough!(ClientboundPing, 0x38);
672    passthrough!(ClientboundPlaceGhostRecipe, 0x3A);
673    passthrough!(ClientboundPlayerAbilities, 0x3B);
674    passthrough!(ClientboundPlayerChat, 0x3C);
675    passthrough!(ClientboundPlayerCombatEnd, 0x3D);
676    passthrough!(ClientboundPlayerCombatEnter, 0x3E);
677    passthrough!(ClientboundPlayerCombatKill, 0x3F);
678    passthrough!(ClientboundPlayerInfoRemove, 0x40);
679    passthrough!(ClientboundPlayerInfoUpdate, 0x41);
680    passthrough!(ClientboundPlayerLookAt, 0x42);
681    passthrough!(ClientboundRecipeBookSettings, 0x44);
682    passthrough!(ClientboundRecipes, 0x45);
683    passthrough!(ClientboundRemoveEntities, 0x46);
684    passthrough!(ClientboundRemoveEntityEffect, 0x47);
685    passthrough!(ClientboundResetScore, 0x48);
686    passthrough!(ClientboundResourcePackPop, 0x49);
687    passthrough!(ClientboundResourcePackPush, 0x4A);
688    passthrough!(ClientboundRotateHead, 0x4C);
689    passthrough!(ClientboundSectionBlocksUpdate, 0x4D);
690    passthrough!(ClientboundSelectAdvancementsTab, 0x4E);
691    passthrough!(ClientboundServerData, 0x4F);
692    passthrough!(ClientboundSetActionBarText, 0x50);
693    passthrough!(ClientboundSetBorderCenter, 0x51);
694    passthrough!(ClientboundSetBorderLerpSize, 0x52);
695    passthrough!(ClientboundSetBorderSize, 0x53);
696    passthrough!(ClientboundSetBorderWarningDelay, 0x54);
697    passthrough!(ClientboundSetBorderWarningDistance, 0x55);
698    passthrough!(ClientboundSetCamera, 0x56);
699    passthrough!(ClientboundSetCursorItem, 0x57);
700    passthrough!(ClientboundSetEntityLink, 0x58);
701    passthrough!(ClientboundSetEntityMotion, 0x59);
702    passthrough!(ClientboundSetEquipment, 0x5A);
703    passthrough!(ClientboundSetExperience, 0x5B);
704    passthrough!(ClientboundSetHealth, 0x5C);
705    passthrough!(ClientboundSetCarriedItem, 0x5D);
706    passthrough!(ClientboundSetPlayerInventory, 0x5E);
707    passthrough!(ClientboundSetScoreboardObjective, 0x5F);
708    passthrough!(ClientboundSetScoreboardScore, 0x60);
709    passthrough!(ClientboundSetSimulationDistance, 0x61);
710    passthrough!(ClientboundSetSubtitleText, 0x62);
711    passthrough!(ClientboundSetTime, 0x63);
712    passthrough!(ClientboundSetTitleText, 0x64);
713    passthrough!(ClientboundSetTitleAnimationTimes, 0x65);
714    passthrough!(ClientboundSoundEntity, 0x66);
715    passthrough!(ClientboundStartConfiguration, 0x68);
716    passthrough!(ClientboundStopSound, 0x69);
717    passthrough!(ClientboundStoreCookie, 0x6A);
718    passthrough!(ClientboundTabList, 0x6C);
719    passthrough!(ClientboundTagQuery, 0x6D);
720    passthrough!(ClientboundTakeItemEntity, 0x6E);
721    passthrough!(ClientboundTeleportEntity, 0x6F);
722    passthrough!(ClientboundTickingState, 0x70);
723    passthrough!(ClientboundTickingStep, 0x71);
724    passthrough!(ClientboundTransfer, 0x72);
725    passthrough!(ClientboundUpdateAdvancements, 0x73);
726    passthrough!(ClientboundUpdateAttributes, 0x74);
727    passthrough!(ClientboundUpdateEffects, 0x75);
728    passthrough!(ClientboundUpdateRecipes, 0x76);
729    passthrough!(ClientboundUpdateTags, 0x77);
730
731    #[derive(Debug, Clone, PartialEq)]
732    pub struct ServerboundKeepAlive {
733        pub keep_alive_id: i64,
734    }
735
736    impl PacketId for ServerboundKeepAlive {
737        fn packet_id(_ver: u32) -> u8 {
738            0x15
739        }
740    }
741
742    impl Encode for ServerboundKeepAlive {
743        fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
744            self.keep_alive_id.encode(dst)
745        }
746    }
747
748    impl Decode for ServerboundKeepAlive {
749        fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
750            Ok(Self {
751                keep_alive_id: i64::decode(src)?,
752            })
753        }
754    }
755
756    #[derive(Debug, Clone, PartialEq)]
757    pub struct ServerboundMovePlayerPos {
758        pub x: f64,
759        pub feet_y: f64,
760        pub z: f64,
761        pub on_ground: bool,
762    }
763
764    impl PacketId for ServerboundMovePlayerPos {
765        fn packet_id(_ver: u32) -> u8 {
766            0x17
767        }
768    }
769
770    impl Encode for ServerboundMovePlayerPos {
771        fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
772            dst.put_f64(self.x);
773            dst.put_f64(self.feet_y);
774            dst.put_f64(self.z);
775            dst.put_u8(self.on_ground as u8);
776            Ok(())
777        }
778    }
779
780    impl Decode for ServerboundMovePlayerPos {
781        fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
782            need(src, 8 + 8 + 8 + 1)?;
783            Ok(Self {
784                x: src.get_f64(),
785                feet_y: src.get_f64(),
786                z: src.get_f64(),
787                on_ground: src.get_u8() != 0,
788            })
789        }
790    }
791
792    #[derive(Debug, Clone, PartialEq)]
793    pub struct ServerboundMovePlayerPosRot {
794        pub x: f64,
795        pub feet_y: f64,
796        pub z: f64,
797        pub yaw: f32,
798        pub pitch: f32,
799        pub on_ground: bool,
800    }
801
802    impl PacketId for ServerboundMovePlayerPosRot {
803        fn packet_id(_ver: u32) -> u8 {
804            0x19
805        }
806    }
807
808    impl Encode for ServerboundMovePlayerPosRot {
809        fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
810            dst.put_f64(self.x);
811            dst.put_f64(self.feet_y);
812            dst.put_f64(self.z);
813            dst.put_f32(self.yaw);
814            dst.put_f32(self.pitch);
815            dst.put_u8(self.on_ground as u8);
816            Ok(())
817        }
818    }
819
820    impl Decode for ServerboundMovePlayerPosRot {
821        fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
822            need(src, 8 + 8 + 8 + 4 + 4 + 1)?;
823            Ok(Self {
824                x: src.get_f64(),
825                feet_y: src.get_f64(),
826                z: src.get_f64(),
827                yaw: src.get_f32(),
828                pitch: src.get_f32(),
829                on_ground: src.get_u8() != 0,
830            })
831        }
832    }
833
834    #[derive(Debug, Clone, PartialEq)]
835    pub struct ServerboundMovePlayerRot {
836        pub yaw: f32,
837        pub pitch: f32,
838        pub on_ground: bool,
839    }
840
841    impl PacketId for ServerboundMovePlayerRot {
842        fn packet_id(_ver: u32) -> u8 {
843            0x18
844        }
845    }
846
847    impl Encode for ServerboundMovePlayerRot {
848        fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
849            dst.put_f32(self.yaw);
850            dst.put_f32(self.pitch);
851            dst.put_u8(self.on_ground as u8);
852            Ok(())
853        }
854    }
855
856    impl Decode for ServerboundMovePlayerRot {
857        fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
858            need(src, 4 + 4 + 1)?;
859            Ok(Self {
860                yaw: src.get_f32(),
861                pitch: src.get_f32(),
862                on_ground: src.get_u8() != 0,
863            })
864        }
865    }
866
867    #[derive(Debug, Clone, PartialEq)]
868    pub enum InteractAction {
869        Interact {
870            hand: VarInt,
871        },
872        Attack,
873        InteractAt {
874            target_x: f32,
875            target_y: f32,
876            target_z: f32,
877            hand: VarInt,
878        },
879    }
880
881    #[derive(Debug, Clone, PartialEq)]
882    pub struct ServerboundInteract {
883        pub entity_id: VarInt,
884        pub action: InteractAction,
885        pub sneaking: bool,
886    }
887
888    impl PacketId for ServerboundInteract {
889        fn packet_id(_ver: u32) -> u8 {
890            0x14
891        }
892    }
893
894    impl Encode for ServerboundInteract {
895        fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
896            self.entity_id.encode(dst)?;
897            match &self.action {
898                InteractAction::Interact { hand } => {
899                    VarInt(0).encode(dst)?;
900                    hand.encode(dst)?;
901                },
902                InteractAction::Attack => {
903                    VarInt(1).encode(dst)?;
904                },
905                InteractAction::InteractAt {
906                    target_x,
907                    target_y,
908                    target_z,
909                    hand,
910                } => {
911                    VarInt(2).encode(dst)?;
912                    dst.put_f32(*target_x);
913                    dst.put_f32(*target_y);
914                    dst.put_f32(*target_z);
915                    hand.encode(dst)?;
916                },
917            }
918            dst.put_u8(self.sneaking as u8);
919            Ok(())
920        }
921    }
922
923    impl Decode for ServerboundInteract {
924        fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
925            let entity_id = VarInt::decode(src)?;
926            let action = match VarInt::decode(src)?.0 {
927                0 => InteractAction::Interact {
928                    hand: VarInt::decode(src)?,
929                },
930                1 => InteractAction::Attack,
931                2 => {
932                    need(src, 4 + 4 + 4)?;
933                    let target_x = src.get_f32();
934                    let target_y = src.get_f32();
935                    let target_z = src.get_f32();
936                    let hand = VarInt::decode(src)?;
937                    InteractAction::InteractAt {
938                        target_x,
939                        target_y,
940                        target_z,
941                        hand,
942                    }
943                },
944                _ => return Err(ProtocolError::UnexpectedEof),
945            };
946            need(src, 1)?;
947            let sneaking = src.get_u8() != 0;
948            Ok(Self {
949                entity_id,
950                action,
951                sneaking,
952            })
953        }
954    }
955
956    #[derive(Debug, Clone, PartialEq)]
957    pub struct ServerboundPluginMessage {
958        pub channel: String,
959        pub data: Vec<u8>,
960    }
961
962    impl PacketId for ServerboundPluginMessage {
963        fn packet_id(_ver: u32) -> u8 {
964            0x0F
965        }
966    }
967
968    impl Encode for ServerboundPluginMessage {
969        fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
970            encode_string(&self.channel, dst)?;
971            dst.extend_from_slice(&self.data);
972            Ok(())
973        }
974    }
975
976    impl Decode for ServerboundPluginMessage {
977        fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
978            let channel = decode_string(src)?;
979            let data = src.copy_to_bytes(src.remaining()).to_vec();
980            Ok(Self { channel, data })
981        }
982    }
983
984    passthrough!(ServerboundAcceptTeleportation, 0x00);
985    passthrough!(ServerboundMovePlayerStatusOnly, 0x16);
986    passthrough!(ServerboundVehicleMove, 0x1A);
987    passthrough!(ServerboundSteerBoat, 0x1B);
988    passthrough!(ServerboundPaddleBoat, 0x1B);
989    passthrough!(ServerboundPlayerAbilities, 0x1E);
990    passthrough!(ServerboundPlayerAction, 0x1F);
991    passthrough!(ServerboundEntityAction, 0x20);
992    passthrough!(ServerboundSteerVehicle, 0x21);
993    passthrough!(ServerboundPlayerWeaponAttack, 0x22);
994    passthrough!(ServerboundSwingArm, 0x32);
995    passthrough!(ServerboundSpectate, 0x33);
996    passthrough!(ServerboundUseItemOn, 0x34);
997    passthrough!(ServerboundUseItem, 0x35);
998    passthrough!(ServerboundCloseWindow, 0x0E);
999    passthrough!(ServerboundClickWindow, 0x0D);
1000    passthrough!(ServerboundClickWindowButton, 0x0C);
1001    passthrough!(ServerboundCreativeInventoryAction, 0x2E);
1002    passthrough!(ServerboundHeldItemChange, 0x2B);
1003    passthrough!(ServerboundSetCreativeModeSlot, 0x2C);
1004    passthrough!(ServerboundChatMessage, 0x06);
1005    passthrough!(ServerboundChatCommand, 0x05);
1006    passthrough!(ServerboundChatSessionUpdate, 0x07);
1007    passthrough!(ServerboundClientStatus, 0x08);
1008    passthrough!(ServerboundClientInformation, 0x09);
1009    passthrough!(ServerboundResourcePackStatus, 0x2A);
1010    passthrough!(ServerboundPong, 0x24);
1011    passthrough!(ServerboundConfigurationAcknowledged, 0x0B);
1012    passthrough!(ServerboundButtonPressed, 0x0C);
1013    passthrough!(ServerboundCommandSuggestion, 0x0A);
1014    passthrough!(ServerboundDifficultyChange, 0x02);
1015    passthrough!(ServerboundDifficultyLock, 0x12);
1016    passthrough!(ServerboundEditBook, 0x10);
1017    passthrough!(ServerboundEntityTagQuery, 0x11);
1018    passthrough!(ServerboundJigsawGenerate, 0x13);
1019    passthrough!(ServerboundPickItem, 0x1C);
1020    passthrough!(ServerboundPlaceRecipe, 0x1D);
1021    passthrough!(ServerboundRecipeBookChangeSettings, 0x26);
1022    passthrough!(ServerboundRecipeBookSeenRecipe, 0x27);
1023    passthrough!(ServerboundRenameItem, 0x29);
1024    passthrough!(ServerboundSelectTrade, 0x2D);
1025    passthrough!(ServerboundSetMerchantTrade, 0x2D);
1026    passthrough!(ServerboundSetBeaconEffect, 0x2F);
1027    passthrough!(ServerboundSetStructureBlock, 0x36);
1028    passthrough!(ServerboundUpdateCommandBlock, 0x30);
1029    passthrough!(ServerboundUpdateCommandBlockMinecart, 0x31);
1030    passthrough!(ServerboundUpdateSign, 0x37);
1031}
1032
1033#[cfg(test)]
1034mod tests {
1035    use super::*;
1036
1037    macro_rules! roundtrip {
1038        ($T:ty, $val:expr) => {{
1039            let v = $val;
1040            let mut buf = BytesMut::new();
1041            v.encode(&mut buf).unwrap();
1042            let mut b = buf.freeze();
1043            assert_eq!(<$T>::decode(&mut b).unwrap(), v);
1044        }};
1045    }
1046
1047    #[test]
1048    fn keepalive_roundtrip() {
1049        roundtrip!(
1050            ClientboundKeepAlive,
1051            ClientboundKeepAlive {
1052                keep_alive_id: 123456789_i64
1053            }
1054        );
1055        roundtrip!(
1056            ServerboundKeepAlive,
1057            ServerboundKeepAlive {
1058                keep_alive_id: 987654321_i64
1059            }
1060        );
1061    }
1062
1063    #[test]
1064    fn player_position_roundtrip() {
1065        roundtrip!(
1066            ClientboundPlayerPosition,
1067            ClientboundPlayerPosition {
1068                x: -100.0,
1069                y: 70.0,
1070                z: 200.0,
1071                yaw: 90.0,
1072                pitch: -45.0,
1073                flags: 0,
1074                teleport_id: VarInt(5),
1075            }
1076        );
1077    }
1078
1079    #[test]
1080    fn plugin_message_roundtrip() {
1081        roundtrip!(
1082            ClientboundPluginMessage,
1083            ClientboundPluginMessage {
1084                channel: "minecraft:brand".to_string(),
1085                data: b"paper".to_vec(),
1086            }
1087        );
1088        roundtrip!(
1089            ServerboundPluginMessage,
1090            ServerboundPluginMessage {
1091                channel: "minecraft:brand".to_string(),
1092                data: b"vanilla".to_vec(),
1093            }
1094        );
1095    }
1096
1097    #[test]
1098    fn system_chat_roundtrip() {
1099        roundtrip!(
1100            ClientboundSystemChat,
1101            ClientboundSystemChat {
1102                json_message: r#"{"text":"hello"}"#.to_string(),
1103                overlay: false,
1104            }
1105        );
1106    }
1107
1108    #[test]
1109    fn disconnect_roundtrip() {
1110        roundtrip!(
1111            ClientboundDisconnect,
1112            ClientboundDisconnect {
1113                reason: r#"{"text":"bye"}"#.to_string(),
1114            }
1115        );
1116    }
1117
1118    #[test]
1119    fn respawn_roundtrip() {
1120        roundtrip!(
1121            ClientboundRespawn,
1122            ClientboundRespawn {
1123                dimension_type: VarInt(0),
1124                dimension_name: "minecraft:overworld".to_string(),
1125                hashed_seed: 0,
1126                game_mode: 0,
1127                previous_game_mode: -1,
1128                is_debug: false,
1129                is_flat: true,
1130                data_kept: 0,
1131                death_location: None,
1132                portal_cooldown: VarInt(0),
1133                sea_level: VarInt(63),
1134            }
1135        );
1136    }
1137
1138    #[test]
1139    fn sound_roundtrip() {
1140        roundtrip!(
1141            ClientboundSound,
1142            ClientboundSound {
1143                sound_type: VarInt(0),
1144                sound_name: "block.note_block.harp".to_string(),
1145                sound_category: VarInt(2),
1146                effect_pos_x: 0,
1147                effect_pos_y: 2048,
1148                effect_pos_z: 0,
1149                volume: 1.0,
1150                pitch: 1.0,
1151                seed: 0,
1152            }
1153        );
1154    }
1155
1156    #[test]
1157    fn login_roundtrip() {
1158        roundtrip!(
1159            ClientboundLogin,
1160            ClientboundLogin {
1161                entity_id: 0,
1162                is_hardcore: false,
1163                dimension_names: vec!["minecraft:overworld".to_string()],
1164                max_players: VarInt(20),
1165                view_distance: VarInt(8),
1166                simulation_distance: VarInt(8),
1167                reduced_debug_info: false,
1168                enable_respawn_screen: true,
1169                do_limited_crafting: false,
1170                dimension_type: VarInt(0),
1171                dimension_name: "minecraft:overworld".to_string(),
1172                hashed_seed: 0,
1173                game_mode: 3,
1174                previous_game_mode: -1,
1175                is_debug: false,
1176                is_flat: true,
1177                death_location: None,
1178                portal_cooldown: VarInt(0),
1179                sea_level: VarInt(63),
1180            }
1181        );
1182    }
1183
1184    #[test]
1185    fn move_pos_roundtrip() {
1186        roundtrip!(
1187            ServerboundMovePlayerPos,
1188            ServerboundMovePlayerPos {
1189                x: 5.0,
1190                feet_y: 64.0,
1191                z: -2.0,
1192                on_ground: true,
1193            }
1194        );
1195    }
1196
1197    #[test]
1198    fn move_rot_roundtrip() {
1199        roundtrip!(
1200            ServerboundMovePlayerRot,
1201            ServerboundMovePlayerRot {
1202                yaw: 90.0,
1203                pitch: -10.0,
1204                on_ground: true,
1205            }
1206        );
1207    }
1208
1209    #[test]
1210    fn move_pos_rot_roundtrip() {
1211        roundtrip!(
1212            ServerboundMovePlayerPosRot,
1213            ServerboundMovePlayerPosRot {
1214                x: 1.0,
1215                feet_y: 65.0,
1216                z: 2.0,
1217                yaw: 180.0,
1218                pitch: 45.0,
1219                on_ground: false,
1220            }
1221        );
1222    }
1223
1224    #[test]
1225    fn interact_roundtrip() {
1226        roundtrip!(
1227            ServerboundInteract,
1228            ServerboundInteract {
1229                entity_id: VarInt(1),
1230                action: InteractAction::Attack,
1231                sneaking: false,
1232            }
1233        );
1234        roundtrip!(
1235            ServerboundInteract,
1236            ServerboundInteract {
1237                entity_id: VarInt(2),
1238                action: InteractAction::Interact { hand: VarInt(0) },
1239                sneaking: true,
1240            }
1241        );
1242        roundtrip!(
1243            ServerboundInteract,
1244            ServerboundInteract {
1245                entity_id: VarInt(3),
1246                action: InteractAction::InteractAt {
1247                    target_x: 0.5,
1248                    target_y: 1.0,
1249                    target_z: 0.5,
1250                    hand: VarInt(0),
1251                },
1252                sneaking: false,
1253            }
1254        );
1255    }
1256
1257    #[test]
1258    fn packet_ids() {
1259        assert_eq!(ClientboundKeepAlive::packet_id(767), 0x29);
1260        assert_eq!(ClientboundPlayerPosition::packet_id(767), 0x43);
1261        assert_eq!(ClientboundPluginMessage::packet_id(767), 0x1A);
1262        assert_eq!(ClientboundSystemChat::packet_id(767), 0x6B);
1263        assert_eq!(ClientboundLogin::packet_id(767), 0x2E);
1264        assert_eq!(ClientboundRespawn::packet_id(767), 0x4B);
1265        assert_eq!(ClientboundSound::packet_id(767), 0x67);
1266        assert_eq!(ClientboundDisconnect::packet_id(767), 0x1E);
1267        assert_eq!(ServerboundKeepAlive::packet_id(767), 0x15);
1268        assert_eq!(ServerboundMovePlayerPos::packet_id(767), 0x17);
1269        assert_eq!(ServerboundMovePlayerPosRot::packet_id(767), 0x19);
1270        assert_eq!(ServerboundMovePlayerRot::packet_id(767), 0x18);
1271        assert_eq!(ServerboundInteract::packet_id(767), 0x14);
1272        assert_eq!(ServerboundPluginMessage::packet_id(767), 0x0F);
1273        assert_eq!(ClientboundBundle::packet_id(767), 0x00);
1274        assert_eq!(ClientboundUpdateTags::packet_id(767), 0x77);
1275        assert_eq!(ServerboundAcceptTeleportation::packet_id(767), 0x00);
1276        assert_eq!(ServerboundUpdateSign::packet_id(767), 0x37);
1277    }
1278}