1use bytes::{Buf, BufMut, Bytes, BytesMut};
2
3use crate::codec::{Decode, Encode, PacketId};
4use crate::error::ProtocolError;
5use crate::types::VarInt;
6
7pub use packets::{
8 ClientboundAcknowledgePlayerDigging, ClientboundAdvancements, ClientboundAttachEntity,
9 ClientboundAwardStats, ClientboundBlockAction, ClientboundBlockBreakAnimation,
10 ClientboundBlockChange, ClientboundBlockEntityData, ClientboundBossBar, ClientboundCamera,
11 ClientboundChangeGameState, ClientboundChatMessage, ClientboundChunkData,
12 ClientboundCloseWindow, ClientboundCollectItem, ClientboundCombatEvent,
13 ClientboundCraftRecipeResponse, ClientboundDeclareCommands, ClientboundDeclareRecipes,
14 ClientboundDestroyEntities, ClientboundDisconnect, ClientboundDisplayScoreboard,
15 ClientboundEffect, ClientboundEntityAnimation, ClientboundEntityEffect,
16 ClientboundEntityEquipment, ClientboundEntityHeadLook, ClientboundEntityMetadata,
17 ClientboundEntityPosition, ClientboundEntityPositionAndRotation, ClientboundEntityProperties,
18 ClientboundEntityRotation, ClientboundEntitySoundEffect, ClientboundEntityStatus,
19 ClientboundEntityTeleport, ClientboundEntityVelocity, ClientboundExplosion,
20 ClientboundFacePlayer, ClientboundHeldItemChange, ClientboundInitializeWorldBorder,
21 ClientboundJoinGame, ClientboundKeepAlive, ClientboundMap, ClientboundMultiBlockChange,
22 ClientboundNamedSoundEffect, ClientboundNbtQueryResponse, ClientboundOpenBook,
23 ClientboundOpenHorseWindow, ClientboundOpenSignEditor, ClientboundOpenWindow,
24 ClientboundParticle, ClientboundPlayerAbilities, ClientboundPlayerInfo,
25 ClientboundPlayerListHeaderAndFooter, ClientboundPlayerPosition, ClientboundPluginMessage,
26 ClientboundRemoveEntityEffect, ClientboundResourcePackSend, ClientboundRespawn,
27 ClientboundScoreboardObjective, ClientboundSelectAdvancementsTab, ClientboundServerDifficulty,
28 ClientboundSetCooldown, ClientboundSetExperience, ClientboundSetPassengers, ClientboundSetSlot,
29 ClientboundSoundEffect, ClientboundSpawnEntity, ClientboundSpawnExperienceOrb,
30 ClientboundSpawnLivingEntity, ClientboundSpawnPainting, ClientboundSpawnPlayer,
31 ClientboundSpawnPosition, ClientboundStopSound, ClientboundTabComplete, ClientboundTags,
32 ClientboundTeams, ClientboundTimeUpdate, ClientboundTitle, ClientboundTradeList,
33 ClientboundUnloadChunk, ClientboundUpdateHealth, ClientboundUpdateLight,
34 ClientboundUpdateScore, ClientboundUpdateViewDistance, ClientboundUpdateViewPosition,
35 ClientboundVehicleMove, ClientboundWindowConfirmation, ClientboundWindowItems,
36 ClientboundWindowProperty, ClientboundWorldBorder, InteractAction, ServerboundChatMessage,
37 ServerboundClickWindow, ServerboundClickWindowButton, ServerboundCloseWindow,
38 ServerboundCraftRecipeRequest, ServerboundCreativeModeSlot, ServerboundEditBook,
39 ServerboundEntityAction, ServerboundGenerateStructure, ServerboundHeldItemChange,
40 ServerboundInteract, ServerboundKeepAlive, ServerboundLockDifficulty, ServerboundMovePlayerPos,
41 ServerboundMovePlayerPosRot, ServerboundMovePlayerPosRotSb, ServerboundMovePlayerRot,
42 ServerboundMovePlayerStatus, ServerboundPickItem, ServerboundPlaceRecipe,
43 ServerboundPlayerAbilities, ServerboundPlayerBlockPlacement, ServerboundPlayerDigging,
44 ServerboundPluginMessage, ServerboundQueryBlockNbt, ServerboundQueryEntityNbt,
45 ServerboundResourcePackStatus, ServerboundSelectTrade, ServerboundSetBeaconEffect,
46 ServerboundSetDifficulty, ServerboundSpectate, ServerboundSteerBoat, ServerboundSteerVehicle,
47 ServerboundSwingArm, ServerboundTabComplete, ServerboundTeleportConfirm,
48 ServerboundUpdateCommandBlock, ServerboundUpdateCommandBlockMinecart,
49 ServerboundUpdateJigsawBlock, ServerboundUpdateSign, ServerboundUpdateStructureBlock,
50 ServerboundUseEntity, ServerboundUseItem, ServerboundVehicleMove,
51};
52
53fn need(src: &Bytes, n: usize) -> Result<(), ProtocolError> {
54 if src.remaining() < n {
55 return Err(ProtocolError::Io(std::io::Error::new(
56 std::io::ErrorKind::UnexpectedEof,
57 "Not enough bytes",
58 )));
59 }
60 Ok(())
61}
62
63fn encode_string(s: &str, dst: &mut BytesMut) -> Result<(), ProtocolError> {
64 let bytes = s.as_bytes();
65 VarInt(bytes.len() as i32).encode(dst)?;
66 dst.put_slice(bytes);
67 Ok(())
68}
69
70fn decode_string(src: &mut Bytes) -> Result<String, ProtocolError> {
71 let len = VarInt::decode(src)?.0 as usize;
72 if src.remaining() < len {
73 return Err(ProtocolError::Io(std::io::Error::new(
74 std::io::ErrorKind::UnexpectedEof,
75 "Missing bytes for string",
76 )));
77 }
78 let mut buf = vec![0u8; len];
79 src.copy_to_slice(&mut buf);
80 String::from_utf8(buf).map_err(|_| {
81 ProtocolError::Io(std::io::Error::new(
82 std::io::ErrorKind::InvalidData,
83 "Invalid UTF-8 in string",
84 ))
85 })
86}
87
88mod packets {
89 use super::*;
90
91 macro_rules! raw_packet {
92 ($name:ident, $id:expr) => {
93 #[derive(Debug, Clone, PartialEq)]
94 pub struct $name {
95 pub raw: Vec<u8>,
96 }
97 impl PacketId for $name {
98 fn packet_id(_ver: u32) -> u8 {
99 $id
100 }
101 }
102 impl Encode for $name {
103 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
104 dst.put_slice(&self.raw);
105 Ok(())
106 }
107 }
108 impl Decode for $name {
109 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
110 let len = src.remaining();
111 let mut raw = vec![0u8; len];
112 src.copy_to_slice(&mut raw);
113 Ok(Self { raw })
114 }
115 }
116 };
117 }
118
119 #[derive(Debug, Clone, PartialEq)]
120 pub struct ClientboundSpawnEntity {
121 pub entity_id: VarInt,
122 pub entity_uuid: uuid::Uuid,
123 pub entity_type: VarInt,
124 pub x: f64,
125 pub y: f64,
126 pub z: f64,
127 pub pitch: i8,
128 pub yaw: i8,
129 pub head_pitch: i8,
130 pub data: VarInt,
131 pub velocity_x: i16,
132 pub velocity_y: i16,
133 pub velocity_z: i16,
134 }
135
136 impl PacketId for ClientboundSpawnEntity {
137 fn packet_id(_ver: u32) -> u8 {
138 0x00
139 }
140 }
141
142 impl Encode for ClientboundSpawnEntity {
143 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
144 self.entity_id.encode(dst)?;
145 let (hi, lo) = self.entity_uuid.as_u64_pair();
146 dst.put_i64(hi as i64);
147 dst.put_i64(lo as i64);
148 self.entity_type.encode(dst)?;
149 dst.put_f64(self.x);
150 dst.put_f64(self.y);
151 dst.put_f64(self.z);
152 dst.put_i8(self.pitch);
153 dst.put_i8(self.yaw);
154 dst.put_i8(self.head_pitch);
155 self.data.encode(dst)?;
156 dst.put_i16(self.velocity_x);
157 dst.put_i16(self.velocity_y);
158 dst.put_i16(self.velocity_z);
159 Ok(())
160 }
161 }
162
163 impl Decode for ClientboundSpawnEntity {
164 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
165 let entity_id = VarInt::decode(src)?;
166 let hi = src.get_i64();
167 let lo = src.get_i64();
168 let entity_uuid = uuid::Uuid::from_u64_pair(hi as u64, lo as u64);
169 let entity_type = VarInt::decode(src)?;
170 let x = src.get_f64();
171 let y = src.get_f64();
172 let z = src.get_f64();
173 let pitch = src.get_i8();
174 let yaw = src.get_i8();
175 let head_pitch = src.get_i8();
176 let data = VarInt::decode(src)?;
177 let velocity_x = src.get_i16();
178 let velocity_y = src.get_i16();
179 let velocity_z = src.get_i16();
180 Ok(Self {
181 entity_id,
182 entity_uuid,
183 entity_type,
184 x,
185 y,
186 z,
187 pitch,
188 yaw,
189 head_pitch,
190 data,
191 velocity_x,
192 velocity_y,
193 velocity_z,
194 })
195 }
196 }
197
198 raw_packet!(ClientboundSpawnExperienceOrb, 0x01);
199
200 #[derive(Debug, Clone, PartialEq)]
201 pub struct ClientboundSpawnLivingEntity {
202 pub entity_id: VarInt,
203 pub entity_uuid: uuid::Uuid,
204 pub entity_type: VarInt,
205 pub x: f64,
206 pub y: f64,
207 pub z: f64,
208 pub yaw: i8,
209 pub pitch: i8,
210 pub head_pitch: i8,
211 pub velocity_x: i16,
212 pub velocity_y: i16,
213 pub velocity_z: i16,
214 }
215
216 impl PacketId for ClientboundSpawnLivingEntity {
217 fn packet_id(_ver: u32) -> u8 {
218 0x02
219 }
220 }
221
222 impl Encode for ClientboundSpawnLivingEntity {
223 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
224 self.entity_id.encode(dst)?;
225 let (hi, lo) = self.entity_uuid.as_u64_pair();
226 dst.put_i64(hi as i64);
227 dst.put_i64(lo as i64);
228 self.entity_type.encode(dst)?;
229 dst.put_f64(self.x);
230 dst.put_f64(self.y);
231 dst.put_f64(self.z);
232 dst.put_i8(self.yaw);
233 dst.put_i8(self.pitch);
234 dst.put_i8(self.head_pitch);
235 dst.put_i16(self.velocity_x);
236 dst.put_i16(self.velocity_y);
237 dst.put_i16(self.velocity_z);
238 Ok(())
239 }
240 }
241
242 impl Decode for ClientboundSpawnLivingEntity {
243 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
244 let entity_id = VarInt::decode(src)?;
245 let hi = src.get_i64();
246 let lo = src.get_i64();
247 let entity_uuid = uuid::Uuid::from_u64_pair(hi as u64, lo as u64);
248 let entity_type = VarInt::decode(src)?;
249 let x = src.get_f64();
250 let y = src.get_f64();
251 let z = src.get_f64();
252 let yaw = src.get_i8();
253 let pitch = src.get_i8();
254 let head_pitch = src.get_i8();
255 let velocity_x = src.get_i16();
256 let velocity_y = src.get_i16();
257 let velocity_z = src.get_i16();
258 Ok(Self {
259 entity_id,
260 entity_uuid,
261 entity_type,
262 x,
263 y,
264 z,
265 yaw,
266 pitch,
267 head_pitch,
268 velocity_x,
269 velocity_y,
270 velocity_z,
271 })
272 }
273 }
274
275 raw_packet!(ClientboundSpawnPainting, 0x03);
276
277 #[derive(Debug, Clone, PartialEq)]
278 pub struct ClientboundSpawnPlayer {
279 pub entity_id: VarInt,
280 pub player_uuid: uuid::Uuid,
281 pub x: f64,
282 pub y: f64,
283 pub z: f64,
284 pub yaw: i8,
285 pub pitch: i8,
286 }
287
288 impl PacketId for ClientboundSpawnPlayer {
289 fn packet_id(_ver: u32) -> u8 {
290 0x04
291 }
292 }
293
294 impl Encode for ClientboundSpawnPlayer {
295 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
296 self.entity_id.encode(dst)?;
297 let (hi, lo) = self.player_uuid.as_u64_pair();
298 dst.put_i64(hi as i64);
299 dst.put_i64(lo as i64);
300 dst.put_f64(self.x);
301 dst.put_f64(self.y);
302 dst.put_f64(self.z);
303 dst.put_i8(self.yaw);
304 dst.put_i8(self.pitch);
305 Ok(())
306 }
307 }
308
309 impl Decode for ClientboundSpawnPlayer {
310 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
311 let entity_id = VarInt::decode(src)?;
312 let hi = src.get_i64();
313 let lo = src.get_i64();
314 let player_uuid = uuid::Uuid::from_u64_pair(hi as u64, lo as u64);
315 let x = src.get_f64();
316 let y = src.get_f64();
317 let z = src.get_f64();
318 let yaw = src.get_i8();
319 let pitch = src.get_i8();
320 Ok(Self {
321 entity_id,
322 player_uuid,
323 x,
324 y,
325 z,
326 yaw,
327 pitch,
328 })
329 }
330 }
331
332 raw_packet!(ClientboundEntityAnimation, 0x05);
333 raw_packet!(ClientboundAwardStats, 0x06);
334 raw_packet!(ClientboundAcknowledgePlayerDigging, 0x07);
335 raw_packet!(ClientboundBlockBreakAnimation, 0x08);
336 raw_packet!(ClientboundBlockEntityData, 0x09);
337 raw_packet!(ClientboundBlockAction, 0x0A);
338
339 #[derive(Debug, Clone, PartialEq)]
340 pub struct ClientboundBlockChange {
341 pub location: VarInt,
342 pub block_state: VarInt,
343 }
344
345 impl PacketId for ClientboundBlockChange {
346 fn packet_id(_ver: u32) -> u8 {
347 0x0B
348 }
349 }
350
351 impl Encode for ClientboundBlockChange {
352 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
353 self.location.encode(dst)?;
354 self.block_state.encode(dst)?;
355 Ok(())
356 }
357 }
358
359 impl Decode for ClientboundBlockChange {
360 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
361 let location = VarInt::decode(src)?;
362 let block_state = VarInt::decode(src)?;
363 Ok(Self {
364 location,
365 block_state,
366 })
367 }
368 }
369
370 raw_packet!(ClientboundBossBar, 0x0C);
371 raw_packet!(ClientboundServerDifficulty, 0x0D);
372
373 raw_packet!(ClientboundTabComplete, 0x0F);
374 raw_packet!(ClientboundDeclareCommands, 0x10);
375 raw_packet!(ClientboundWindowConfirmation, 0x11);
376
377 #[derive(Debug, Clone, PartialEq)]
378 pub struct ClientboundCloseWindow {
379 pub window_id: u8,
380 }
381
382 impl PacketId for ClientboundCloseWindow {
383 fn packet_id(_ver: u32) -> u8 {
384 0x12
385 }
386 }
387
388 impl Encode for ClientboundCloseWindow {
389 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
390 dst.put_u8(self.window_id);
391 Ok(())
392 }
393 }
394
395 impl Decode for ClientboundCloseWindow {
396 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
397 need(src, 1)?;
398 let window_id = src.get_u8();
399 Ok(Self { window_id })
400 }
401 }
402
403 raw_packet!(ClientboundWindowProperty, 0x14);
404 raw_packet!(ClientboundSetCooldown, 0x16);
405
406 #[derive(Debug, Clone, PartialEq)]
407 pub struct ClientboundWindowItems {
408 pub window_id: u8,
409 pub slots: Vec<crate::types::Slot>,
410 pub carried_item: crate::types::Slot,
411 }
412
413 impl PacketId for ClientboundWindowItems {
414 fn packet_id(_ver: u32) -> u8 {
415 0x13
416 }
417 }
418
419 impl Encode for ClientboundWindowItems {
420 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
421 dst.put_u8(self.window_id);
422 VarInt(self.slots.len() as i32).encode(dst)?;
423 for slot in &self.slots {
424 slot.encode(dst)?;
425 }
426 self.carried_item.encode(dst)?;
427 Ok(())
428 }
429 }
430
431 impl Decode for ClientboundWindowItems {
432 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
433 need(src, 1)?;
434 let window_id = src.get_u8();
435 let count = VarInt::decode(src)?.0 as usize;
436 let mut slots = Vec::with_capacity(count);
437 for _ in 0..count {
438 slots.push(crate::types::Slot::decode(src)?);
439 }
440 let carried_item = crate::types::Slot::decode(src)?;
441 Ok(Self {
442 window_id,
443 slots,
444 carried_item,
445 })
446 }
447 }
448
449 #[derive(Debug, Clone, PartialEq)]
450 pub struct ClientboundSetSlot {
451 pub window_id: u8,
452 pub slot: i16,
453 pub slot_data: crate::types::Slot,
454 }
455
456 impl PacketId for ClientboundSetSlot {
457 fn packet_id(_ver: u32) -> u8 {
458 0x15
459 }
460 }
461
462 impl Encode for ClientboundSetSlot {
463 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
464 dst.put_u8(self.window_id);
465 dst.put_i16(self.slot);
466 self.slot_data.encode(dst)?;
467 Ok(())
468 }
469 }
470
471 impl Decode for ClientboundSetSlot {
472 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
473 need(src, 1 + 2)?;
474 let window_id = src.get_u8();
475 let slot = src.get_i16();
476 let slot_data = crate::types::Slot::decode(src)?;
477 Ok(Self {
478 window_id,
479 slot,
480 slot_data,
481 })
482 }
483 }
484
485 raw_packet!(ClientboundEntityStatus, 0x1A);
486 raw_packet!(ClientboundExplosion, 0x1B);
487 raw_packet!(ClientboundUnloadChunk, 0x1C);
488 raw_packet!(ClientboundChangeGameState, 0x1D);
489 raw_packet!(ClientboundOpenHorseWindow, 0x1E);
490
491 raw_packet!(ClientboundInitializeWorldBorder, 0x20);
492 raw_packet!(ClientboundChunkData, 0x21);
493 raw_packet!(ClientboundEffect, 0x22);
494 raw_packet!(ClientboundParticle, 0x23);
495 raw_packet!(ClientboundUpdateLight, 0x24);
496
497 raw_packet!(ClientboundMap, 0x25);
498 raw_packet!(ClientboundTradeList, 0x26);
499
500 #[derive(Debug, Clone, PartialEq)]
501 pub struct ClientboundEntityPosition {
502 pub entity_id: VarInt,
503 pub delta_x: i16,
504 pub delta_y: i16,
505 pub delta_z: i16,
506 pub on_ground: bool,
507 }
508
509 impl PacketId for ClientboundEntityPosition {
510 fn packet_id(_ver: u32) -> u8 {
511 0x27
512 }
513 }
514
515 impl Encode for ClientboundEntityPosition {
516 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
517 self.entity_id.encode(dst)?;
518 dst.put_i16(self.delta_x);
519 dst.put_i16(self.delta_y);
520 dst.put_i16(self.delta_z);
521 dst.put_u8(if self.on_ground { 1 } else { 0 });
522 Ok(())
523 }
524 }
525
526 impl Decode for ClientboundEntityPosition {
527 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
528 let entity_id = VarInt::decode(src)?;
529 let delta_x = src.get_i16();
530 let delta_y = src.get_i16();
531 let delta_z = src.get_i16();
532 let on_ground = src.get_u8() != 0;
533 Ok(Self {
534 entity_id,
535 delta_x,
536 delta_y,
537 delta_z,
538 on_ground,
539 })
540 }
541 }
542
543 #[derive(Debug, Clone, PartialEq)]
544 pub struct ClientboundEntityPositionAndRotation {
545 pub entity_id: VarInt,
546 pub delta_x: i16,
547 pub delta_y: i16,
548 pub delta_z: i16,
549 pub yaw: i8,
550 pub pitch: i8,
551 pub on_ground: bool,
552 }
553
554 impl PacketId for ClientboundEntityPositionAndRotation {
555 fn packet_id(_ver: u32) -> u8 {
556 0x28
557 }
558 }
559
560 impl Encode for ClientboundEntityPositionAndRotation {
561 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
562 self.entity_id.encode(dst)?;
563 dst.put_i16(self.delta_x);
564 dst.put_i16(self.delta_y);
565 dst.put_i16(self.delta_z);
566 dst.put_i8(self.yaw);
567 dst.put_i8(self.pitch);
568 dst.put_u8(if self.on_ground { 1 } else { 0 });
569 Ok(())
570 }
571 }
572
573 impl Decode for ClientboundEntityPositionAndRotation {
574 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
575 let entity_id = VarInt::decode(src)?;
576 let delta_x = src.get_i16();
577 let delta_y = src.get_i16();
578 let delta_z = src.get_i16();
579 let yaw = src.get_i8();
580 let pitch = src.get_i8();
581 let on_ground = src.get_u8() != 0;
582 Ok(Self {
583 entity_id,
584 delta_x,
585 delta_y,
586 delta_z,
587 yaw,
588 pitch,
589 on_ground,
590 })
591 }
592 }
593
594 #[derive(Debug, Clone, PartialEq)]
595 pub struct ClientboundEntityRotation {
596 pub entity_id: VarInt,
597 pub yaw: i8,
598 pub pitch: i8,
599 pub on_ground: bool,
600 }
601
602 impl PacketId for ClientboundEntityRotation {
603 fn packet_id(_ver: u32) -> u8 {
604 0x29
605 }
606 }
607
608 impl Encode for ClientboundEntityRotation {
609 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
610 self.entity_id.encode(dst)?;
611 dst.put_i8(self.yaw);
612 dst.put_i8(self.pitch);
613 dst.put_u8(if self.on_ground { 1 } else { 0 });
614 Ok(())
615 }
616 }
617
618 impl Decode for ClientboundEntityRotation {
619 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
620 let entity_id = VarInt::decode(src)?;
621 let yaw = src.get_i8();
622 let pitch = src.get_i8();
623 let on_ground = src.get_u8() != 0;
624 Ok(Self {
625 entity_id,
626 yaw,
627 pitch,
628 on_ground,
629 })
630 }
631 }
632
633 raw_packet!(ClientboundVehicleMove, 0x2A);
634 raw_packet!(ClientboundOpenBook, 0x2B);
635
636 #[derive(Debug, Clone, PartialEq)]
637 pub struct ClientboundOpenWindow {
638 pub window_id: VarInt,
639 pub window_type: VarInt,
640 pub window_title: String,
641 }
642
643 impl PacketId for ClientboundOpenWindow {
644 fn packet_id(_ver: u32) -> u8 {
645 0x2C
646 }
647 }
648
649 impl Encode for ClientboundOpenWindow {
650 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
651 self.window_id.encode(dst)?;
652 self.window_type.encode(dst)?;
653 encode_string(&self.window_title, dst)?;
654 Ok(())
655 }
656 }
657
658 impl Decode for ClientboundOpenWindow {
659 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
660 let window_id = VarInt::decode(src)?;
661 let window_type = VarInt::decode(src)?;
662 let window_title = decode_string(src)?;
663 Ok(Self {
664 window_id,
665 window_type,
666 window_title,
667 })
668 }
669 }
670
671 raw_packet!(ClientboundOpenSignEditor, 0x2D);
672 raw_packet!(ClientboundCraftRecipeResponse, 0x2E);
673
674 #[derive(Debug, Clone, PartialEq)]
675 pub struct ClientboundPlayerAbilities {
676 pub flags: u8,
677 pub flying_speed: f32,
678 pub walking_speed: f32,
679 }
680
681 impl PacketId for ClientboundPlayerAbilities {
682 fn packet_id(_ver: u32) -> u8 {
683 0x2F
684 }
685 }
686
687 impl Encode for ClientboundPlayerAbilities {
688 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
689 dst.put_u8(self.flags);
690 dst.put_f32(self.flying_speed);
691 dst.put_f32(self.walking_speed);
692 Ok(())
693 }
694 }
695
696 impl Decode for ClientboundPlayerAbilities {
697 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
698 need(src, 1 + 4 + 4)?;
699 let flags = src.get_u8();
700 let flying_speed = src.get_f32();
701 let walking_speed = src.get_f32();
702 Ok(Self {
703 flags,
704 flying_speed,
705 walking_speed,
706 })
707 }
708 }
709
710 raw_packet!(ClientboundCombatEvent, 0x30);
711 raw_packet!(ClientboundPlayerInfo, 0x31);
712 raw_packet!(ClientboundFacePlayer, 0x31);
713
714 #[derive(Debug, Clone, PartialEq)]
715 pub struct ClientboundDestroyEntities {
716 pub entity_ids: VarInt,
717 pub count: VarInt,
718 pub entities: Vec<VarInt>,
719 }
720
721 impl PacketId for ClientboundDestroyEntities {
722 fn packet_id(_ver: u32) -> u8 {
723 0x36
724 }
725 }
726
727 impl Encode for ClientboundDestroyEntities {
728 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
729 self.entity_ids.encode(dst)?;
730 for entity in &self.entities {
731 entity.encode(dst)?;
732 }
733 Ok(())
734 }
735 }
736
737 impl Decode for ClientboundDestroyEntities {
738 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
739 let entity_ids = VarInt::decode(src)?;
740 let count = entity_ids.0 as usize;
741 let mut entities = Vec::with_capacity(count);
742 for _ in 0..count {
743 entities.push(VarInt::decode(src)?);
744 }
745 Ok(Self {
746 entity_ids,
747 count: entity_ids,
748 entities,
749 })
750 }
751 }
752
753 raw_packet!(ClientboundRemoveEntityEffect, 0x37);
754 raw_packet!(ClientboundResourcePackSend, 0x38);
755
756 #[derive(Debug, Clone, PartialEq)]
757 pub struct ClientboundEntityHeadLook {
758 pub entity_id: VarInt,
759 pub head_yaw: i8,
760 }
761
762 impl PacketId for ClientboundEntityHeadLook {
763 fn packet_id(_ver: u32) -> u8 {
764 0x3A
765 }
766 }
767
768 impl Encode for ClientboundEntityHeadLook {
769 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
770 self.entity_id.encode(dst)?;
771 dst.put_i8(self.head_yaw);
772 Ok(())
773 }
774 }
775
776 impl Decode for ClientboundEntityHeadLook {
777 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
778 let entity_id = VarInt::decode(src)?;
779 let head_yaw = src.get_i8();
780 Ok(Self {
781 entity_id,
782 head_yaw,
783 })
784 }
785 }
786
787 raw_packet!(ClientboundMultiBlockChange, 0x3B);
788 raw_packet!(ClientboundSelectAdvancementsTab, 0x3C);
789 raw_packet!(ClientboundWorldBorder, 0x3D);
790 raw_packet!(ClientboundCamera, 0x3E);
791
792 #[derive(Debug, Clone, PartialEq)]
793 pub struct ClientboundHeldItemChange {
794 pub slot: i8,
795 }
796
797 impl PacketId for ClientboundHeldItemChange {
798 fn packet_id(_ver: u32) -> u8 {
799 0x3F
800 }
801 }
802
803 impl Encode for ClientboundHeldItemChange {
804 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
805 dst.put_i8(self.slot);
806 Ok(())
807 }
808 }
809
810 impl Decode for ClientboundHeldItemChange {
811 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
812 need(src, 1)?;
813 let slot = src.get_i8();
814 Ok(Self { slot })
815 }
816 }
817
818 raw_packet!(ClientboundUpdateViewPosition, 0x40);
819 raw_packet!(ClientboundUpdateViewDistance, 0x41);
820
821 #[derive(Debug, Clone, PartialEq)]
822 pub struct ClientboundSpawnPosition {
823 pub location: VarInt,
824 }
825
826 impl PacketId for ClientboundSpawnPosition {
827 fn packet_id(_ver: u32) -> u8 {
828 0x42
829 }
830 }
831
832 impl Encode for ClientboundSpawnPosition {
833 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
834 self.location.encode(dst)?;
835 Ok(())
836 }
837 }
838
839 impl Decode for ClientboundSpawnPosition {
840 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
841 let location = VarInt::decode(src)?;
842 Ok(Self { location })
843 }
844 }
845
846 raw_packet!(ClientboundDisplayScoreboard, 0x43);
847 raw_packet!(ClientboundEntityMetadata, 0x44);
848 raw_packet!(ClientboundAttachEntity, 0x45);
849
850 #[derive(Debug, Clone, PartialEq)]
851 pub struct ClientboundEntityVelocity {
852 pub entity_id: VarInt,
853 pub velocity_x: i16,
854 pub velocity_y: i16,
855 pub velocity_z: i16,
856 }
857
858 impl PacketId for ClientboundEntityVelocity {
859 fn packet_id(_ver: u32) -> u8 {
860 0x46
861 }
862 }
863
864 impl Encode for ClientboundEntityVelocity {
865 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
866 self.entity_id.encode(dst)?;
867 dst.put_i16(self.velocity_x);
868 dst.put_i16(self.velocity_y);
869 dst.put_i16(self.velocity_z);
870 Ok(())
871 }
872 }
873
874 impl Decode for ClientboundEntityVelocity {
875 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
876 let entity_id = VarInt::decode(src)?;
877 let velocity_x = src.get_i16();
878 let velocity_y = src.get_i16();
879 let velocity_z = src.get_i16();
880 Ok(Self {
881 entity_id,
882 velocity_x,
883 velocity_y,
884 velocity_z,
885 })
886 }
887 }
888
889 #[derive(Debug, Clone, PartialEq)]
890 pub struct ClientboundEntityEquipment {
891 pub entity_id: i32,
892 pub slot: VarInt,
893 pub item: crate::types::Slot,
894 }
895
896 impl PacketId for ClientboundEntityEquipment {
897 fn packet_id(_ver: u32) -> u8 {
898 0x47
899 }
900 }
901
902 impl Encode for ClientboundEntityEquipment {
903 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
904 VarInt(self.entity_id).encode(dst)?;
905 self.slot.encode(dst)?;
906 self.item.encode(dst)?;
907 Ok(())
908 }
909 }
910
911 impl Decode for ClientboundEntityEquipment {
912 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
913 let entity_id = VarInt::decode(src)?.0;
914 let slot = VarInt::decode(src)?;
915 let item = crate::types::Slot::decode(src)?;
916 Ok(Self {
917 entity_id,
918 slot,
919 item,
920 })
921 }
922 }
923
924 #[derive(Debug, Clone, PartialEq)]
925 pub struct ClientboundSetExperience {
926 pub experience_bar: f32,
927 pub level: VarInt,
928 pub total_experience: VarInt,
929 }
930
931 impl PacketId for ClientboundSetExperience {
932 fn packet_id(_ver: u32) -> u8 {
933 0x48
934 }
935 }
936
937 impl Encode for ClientboundSetExperience {
938 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
939 dst.put_f32(self.experience_bar);
940 self.level.encode(dst)?;
941 self.total_experience.encode(dst)?;
942 Ok(())
943 }
944 }
945
946 impl Decode for ClientboundSetExperience {
947 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
948 need(src, 4)?;
949 let experience_bar = src.get_f32();
950 let level = VarInt::decode(src)?;
951 let total_experience = VarInt::decode(src)?;
952 Ok(Self {
953 experience_bar,
954 level,
955 total_experience,
956 })
957 }
958 }
959
960 #[derive(Debug, Clone, PartialEq)]
961 pub struct ClientboundUpdateHealth {
962 pub health: f32,
963 pub food: VarInt,
964 pub food_saturation: f32,
965 }
966
967 impl PacketId for ClientboundUpdateHealth {
968 fn packet_id(_ver: u32) -> u8 {
969 0x49
970 }
971 }
972
973 impl Encode for ClientboundUpdateHealth {
974 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
975 dst.put_f32(self.health);
976 self.food.encode(dst)?;
977 dst.put_f32(self.food_saturation);
978 Ok(())
979 }
980 }
981
982 impl Decode for ClientboundUpdateHealth {
983 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
984 need(src, 4)?;
985 let health = src.get_f32();
986 let food = VarInt::decode(src)?;
987 let food_saturation = src.get_f32();
988 Ok(Self {
989 health,
990 food,
991 food_saturation,
992 })
993 }
994 }
995
996 raw_packet!(ClientboundScoreboardObjective, 0x4A);
997 raw_packet!(ClientboundSetPassengers, 0x4B);
998 raw_packet!(ClientboundTeams, 0x4C);
999 raw_packet!(ClientboundUpdateScore, 0x4D);
1000
1001 #[derive(Debug, Clone, PartialEq)]
1002 pub struct ClientboundTimeUpdate {
1003 pub world_age: i64,
1004 pub time_of_day: i64,
1005 }
1006
1007 impl PacketId for ClientboundTimeUpdate {
1008 fn packet_id(_ver: u32) -> u8 {
1009 0x4E
1010 }
1011 }
1012
1013 impl Encode for ClientboundTimeUpdate {
1014 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
1015 dst.put_i64(self.world_age);
1016 dst.put_i64(self.time_of_day);
1017 Ok(())
1018 }
1019 }
1020
1021 impl Decode for ClientboundTimeUpdate {
1022 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
1023 need(src, 8 + 8)?;
1024 let world_age = src.get_i64();
1025 let time_of_day = src.get_i64();
1026 Ok(Self {
1027 world_age,
1028 time_of_day,
1029 })
1030 }
1031 }
1032
1033 #[derive(Debug, Clone, PartialEq)]
1034 pub struct ClientboundTitle {
1035 pub action: VarInt,
1036 pub title_text: Option<String>,
1037 pub fade_in: i32,
1038 pub stay: i32,
1039 pub fade_out: i32,
1040 }
1041
1042 impl PacketId for ClientboundTitle {
1043 fn packet_id(_ver: u32) -> u8 {
1044 0x4F
1045 }
1046 }
1047
1048 impl Encode for ClientboundTitle {
1049 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
1050 self.action.encode(dst)?;
1051 if let Some(ref text) = self.title_text {
1052 encode_string(text, dst)?;
1053 dst.put_i32(self.fade_in);
1054 dst.put_i32(self.stay);
1055 dst.put_i32(self.fade_out);
1056 }
1057 Ok(())
1058 }
1059 }
1060
1061 impl Decode for ClientboundTitle {
1062 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
1063 let action = VarInt::decode(src)?;
1064 let mut title_text = None;
1065 let mut fade_in = 0;
1066 let mut stay = 0;
1067 let mut fade_out = 0;
1068 if action.0 == 0 || action.0 == 2 {
1069 title_text = Some(decode_string(src)?);
1070 fade_in = src.get_i32();
1071 stay = src.get_i32();
1072 fade_out = src.get_i32();
1073 }
1074 Ok(Self {
1075 action,
1076 title_text,
1077 fade_in,
1078 stay,
1079 fade_out,
1080 })
1081 }
1082 }
1083
1084 raw_packet!(ClientboundEntitySoundEffect, 0x50);
1085 raw_packet!(ClientboundStopSound, 0x52);
1086 raw_packet!(ClientboundSoundEffect, 0x4D);
1087
1088 #[derive(Debug, Clone, PartialEq)]
1089 pub struct ClientboundPlayerListHeaderAndFooter {
1090 pub header: String,
1091 pub footer: String,
1092 }
1093
1094 impl PacketId for ClientboundPlayerListHeaderAndFooter {
1095 fn packet_id(_ver: u32) -> u8 {
1096 0x53
1097 }
1098 }
1099
1100 impl Encode for ClientboundPlayerListHeaderAndFooter {
1101 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
1102 encode_string(&self.header, dst)?;
1103 encode_string(&self.footer, dst)?;
1104 Ok(())
1105 }
1106 }
1107
1108 impl Decode for ClientboundPlayerListHeaderAndFooter {
1109 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
1110 let header = decode_string(src)?;
1111 let footer = decode_string(src)?;
1112 Ok(Self { header, footer })
1113 }
1114 }
1115
1116 raw_packet!(ClientboundNbtQueryResponse, 0x54);
1117 raw_packet!(ClientboundCollectItem, 0x55);
1118
1119 #[derive(Debug, Clone, PartialEq)]
1120 pub struct ClientboundEntityTeleport {
1121 pub entity_id: VarInt,
1122 pub x: f64,
1123 pub y: f64,
1124 pub z: f64,
1125 pub yaw: i8,
1126 pub pitch: i8,
1127 pub on_ground: bool,
1128 }
1129
1130 impl PacketId for ClientboundEntityTeleport {
1131 fn packet_id(_ver: u32) -> u8 {
1132 0x56
1133 }
1134 }
1135
1136 impl Encode for ClientboundEntityTeleport {
1137 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
1138 self.entity_id.encode(dst)?;
1139 dst.put_f64(self.x);
1140 dst.put_f64(self.y);
1141 dst.put_f64(self.z);
1142 dst.put_i8(self.yaw);
1143 dst.put_i8(self.pitch);
1144 dst.put_u8(if self.on_ground { 1 } else { 0 });
1145 Ok(())
1146 }
1147 }
1148
1149 impl Decode for ClientboundEntityTeleport {
1150 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
1151 let entity_id = VarInt::decode(src)?;
1152 let x = src.get_f64();
1153 let y = src.get_f64();
1154 let z = src.get_f64();
1155 let yaw = src.get_i8();
1156 let pitch = src.get_i8();
1157 let on_ground = src.get_u8() != 0;
1158 Ok(Self {
1159 entity_id,
1160 x,
1161 y,
1162 z,
1163 yaw,
1164 pitch,
1165 on_ground,
1166 })
1167 }
1168 }
1169
1170 raw_packet!(ClientboundAdvancements, 0x57);
1171 raw_packet!(ClientboundEntityProperties, 0x58);
1172 raw_packet!(ClientboundEntityEffect, 0x59);
1173 raw_packet!(ClientboundDeclareRecipes, 0x5A);
1174 raw_packet!(ClientboundTags, 0x5B);
1175
1176 #[derive(Debug, Clone, PartialEq)]
1177 pub struct ServerboundTeleportConfirm {
1178 pub teleport_id: VarInt,
1179 }
1180
1181 impl PacketId for ServerboundTeleportConfirm {
1182 fn packet_id(_ver: u32) -> u8 {
1183 0x00
1184 }
1185 }
1186
1187 impl Encode for ServerboundTeleportConfirm {
1188 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
1189 self.teleport_id.encode(dst)?;
1190 Ok(())
1191 }
1192 }
1193
1194 impl Decode for ServerboundTeleportConfirm {
1195 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
1196 let teleport_id = VarInt::decode(src)?;
1197 Ok(Self { teleport_id })
1198 }
1199 }
1200
1201 raw_packet!(ServerboundQueryBlockNbt, 0x01);
1202 raw_packet!(ServerboundSetDifficulty, 0x02);
1203
1204 raw_packet!(ServerboundTabComplete, 0x06);
1205 raw_packet!(ServerboundClickWindowButton, 0x08);
1206 raw_packet!(ServerboundClickWindow, 0x09);
1207 raw_packet!(ServerboundCloseWindow, 0x0A);
1208 raw_packet!(ServerboundEditBook, 0x0C);
1209 raw_packet!(ServerboundQueryEntityNbt, 0x0D);
1210
1211 raw_packet!(ServerboundGenerateStructure, 0x0F);
1212
1213 raw_packet!(ServerboundLockDifficulty, 0x11);
1214
1215 raw_packet!(ServerboundMovePlayerStatus, 0x15);
1216 raw_packet!(ServerboundVehicleMove, 0x16);
1217 raw_packet!(ServerboundSteerBoat, 0x17);
1218 raw_packet!(ServerboundPickItem, 0x18);
1219 raw_packet!(ServerboundCraftRecipeRequest, 0x19);
1220 raw_packet!(ServerboundPlayerAbilities, 0x1A);
1221 raw_packet!(ServerboundPlayerDigging, 0x1B);
1222 raw_packet!(ServerboundEntityAction, 0x1C);
1223 raw_packet!(ServerboundSteerVehicle, 0x1D);
1224 raw_packet!(ServerboundPlaceRecipe, 0x1F);
1225 raw_packet!(ServerboundMovePlayerPosRotSb, 0x20);
1226 raw_packet!(ServerboundResourcePackStatus, 0x21);
1227 raw_packet!(ServerboundSelectTrade, 0x22);
1228 raw_packet!(ServerboundSetBeaconEffect, 0x23);
1229 raw_packet!(ServerboundHeldItemChange, 0x25);
1230 raw_packet!(ServerboundUpdateCommandBlock, 0x26);
1231 raw_packet!(ServerboundUpdateCommandBlockMinecart, 0x27);
1232 raw_packet!(ServerboundCreativeModeSlot, 0x28);
1233 raw_packet!(ServerboundUpdateJigsawBlock, 0x29);
1234 raw_packet!(ServerboundUpdateStructureBlock, 0x2A);
1235 raw_packet!(ServerboundUpdateSign, 0x2B);
1236 raw_packet!(ServerboundSwingArm, 0x2C);
1237 raw_packet!(ServerboundSpectate, 0x2D);
1238 raw_packet!(ServerboundPlayerBlockPlacement, 0x2E);
1239 raw_packet!(ServerboundUseItem, 0x2F);
1240
1241 raw_packet!(ServerboundUseEntity, 0x0E);
1242
1243 #[derive(Debug, Clone, PartialEq)]
1244 pub struct ClientboundNamedSoundEffect {
1245 pub sound_name: String,
1246 pub sound_category: VarInt,
1247 pub effect_position_x: i32,
1248 pub effect_position_y: i32,
1249 pub effect_position_z: i32,
1250 pub volume: f32,
1251 pub pitch: f32,
1252 }
1253
1254 impl PacketId for ClientboundNamedSoundEffect {
1255 fn packet_id(_ver: u32) -> u8 {
1256 0x19
1257 }
1258 }
1259
1260 impl Encode for ClientboundNamedSoundEffect {
1261 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
1262 encode_string(&self.sound_name, dst)?;
1263 self.sound_category.encode(dst)?;
1264 dst.put_i32(self.effect_position_x);
1265 dst.put_i32(self.effect_position_y);
1266 dst.put_i32(self.effect_position_z);
1267 dst.put_f32(self.volume);
1268 dst.put_f32(self.pitch);
1269 Ok(())
1270 }
1271 }
1272
1273 impl Decode for ClientboundNamedSoundEffect {
1274 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
1275 let sound_name = decode_string(src)?;
1276 let sound_category = VarInt::decode(src)?;
1277 if src.remaining() < 20 {
1278 return Err(ProtocolError::Io(std::io::Error::new(
1279 std::io::ErrorKind::UnexpectedEof,
1280 "Missing bytes for ClientboundNamedSoundEffect position/volume/pitch",
1281 )));
1282 }
1283 let effect_position_x = src.get_i32();
1284 let effect_position_y = src.get_i32();
1285 let effect_position_z = src.get_i32();
1286 let volume = src.get_f32();
1287 let pitch = src.get_f32();
1288 Ok(Self {
1289 sound_name,
1290 sound_category,
1291 effect_position_x,
1292 effect_position_y,
1293 effect_position_z,
1294 volume,
1295 pitch,
1296 })
1297 }
1298 }
1299
1300 #[derive(Debug, Clone, PartialEq)]
1301 pub struct ClientboundJoinGame {
1302 pub entity_id: i32,
1303 pub is_hardcore: bool,
1304 pub game_mode: u8,
1305 pub previous_game_mode: i8,
1306 pub world_names: Vec<String>,
1307 pub dimension: String,
1308 pub world_name: String,
1309 pub hashed_seed: i64,
1310 pub max_players: VarInt,
1311 pub view_distance: VarInt,
1312 pub reduced_debug_info: bool,
1313 pub enable_respawn_screen: bool,
1314 pub is_debug: bool,
1315 pub is_flat: bool,
1316 }
1317
1318 impl PacketId for ClientboundJoinGame {
1319 fn packet_id(_ver: u32) -> u8 {
1320 0x24
1321 }
1322 }
1323
1324 impl Encode for ClientboundJoinGame {
1325 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
1326 dst.put_i32(self.entity_id);
1327 dst.put_u8(self.is_hardcore as u8);
1328 dst.put_u8(self.game_mode);
1329 dst.put_i8(self.previous_game_mode);
1330 VarInt(self.world_names.len() as i32).encode(dst)?;
1331 for name in &self.world_names {
1332 encode_string(name, dst)?;
1333 }
1334 encode_string(&self.dimension, dst)?;
1335 encode_string(&self.world_name, dst)?;
1336 dst.put_i64(self.hashed_seed);
1337 self.max_players.encode(dst)?;
1338 self.view_distance.encode(dst)?;
1339 dst.put_u8(self.reduced_debug_info as u8);
1340 dst.put_u8(self.enable_respawn_screen as u8);
1341 dst.put_u8(self.is_debug as u8);
1342 dst.put_u8(self.is_flat as u8);
1343 Ok(())
1344 }
1345 }
1346
1347 impl Decode for ClientboundJoinGame {
1348 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
1349 if src.remaining() < 4 {
1350 return Err(ProtocolError::Io(std::io::Error::new(
1351 std::io::ErrorKind::UnexpectedEof,
1352 "Missing bytes for ClientboundJoinGame entity_id",
1353 )));
1354 }
1355 let entity_id = src.get_i32();
1356 if src.remaining() < 3 {
1357 return Err(ProtocolError::Io(std::io::Error::new(
1358 std::io::ErrorKind::UnexpectedEof,
1359 "Missing bytes for ClientboundJoinGame flags",
1360 )));
1361 }
1362 let is_hardcore = src.get_u8() != 0;
1363 let game_mode = src.get_u8();
1364 let previous_game_mode = src.get_i8();
1365 let world_count = VarInt::decode(src)?.0 as usize;
1366 let mut world_names = Vec::with_capacity(world_count);
1367 for _ in 0..world_count {
1368 world_names.push(decode_string(src)?);
1369 }
1370 let dimension = decode_string(src)?;
1371 let world_name = decode_string(src)?;
1372 if src.remaining() < 8 {
1373 return Err(ProtocolError::Io(std::io::Error::new(
1374 std::io::ErrorKind::UnexpectedEof,
1375 "Missing bytes for ClientboundJoinGame hashed_seed",
1376 )));
1377 }
1378 let hashed_seed = src.get_i64();
1379 let max_players = VarInt::decode(src)?;
1380 let view_distance = VarInt::decode(src)?;
1381 if src.remaining() < 4 {
1382 return Err(ProtocolError::Io(std::io::Error::new(
1383 std::io::ErrorKind::UnexpectedEof,
1384 "Missing bytes for ClientboundJoinGame boolean flags",
1385 )));
1386 }
1387 let reduced_debug_info = src.get_u8() != 0;
1388 let enable_respawn_screen = src.get_u8() != 0;
1389 let is_debug = src.get_u8() != 0;
1390 let is_flat = src.get_u8() != 0;
1391 Ok(Self {
1392 entity_id,
1393 is_hardcore,
1394 game_mode,
1395 previous_game_mode,
1396 world_names,
1397 dimension,
1398 world_name,
1399 hashed_seed,
1400 max_players,
1401 view_distance,
1402 reduced_debug_info,
1403 enable_respawn_screen,
1404 is_debug,
1405 is_flat,
1406 })
1407 }
1408 }
1409
1410 #[derive(Debug, Clone, PartialEq)]
1411 pub struct ClientboundRespawn {
1412 pub dimension: String,
1413 pub world_name: String,
1414 pub hashed_seed: i64,
1415 pub game_mode: u8,
1416 pub previous_game_mode: i8,
1417 pub is_debug: bool,
1418 pub is_flat: bool,
1419 pub copy_metadata: bool,
1420 }
1421
1422 impl PacketId for ClientboundRespawn {
1423 fn packet_id(_ver: u32) -> u8 {
1424 0x39
1425 }
1426 }
1427
1428 impl Encode for ClientboundRespawn {
1429 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
1430 encode_string(&self.dimension, dst)?;
1431 encode_string(&self.world_name, dst)?;
1432 dst.put_i64(self.hashed_seed);
1433 dst.put_u8(self.game_mode);
1434 dst.put_i8(self.previous_game_mode);
1435 dst.put_u8(self.is_debug as u8);
1436 dst.put_u8(self.is_flat as u8);
1437 dst.put_u8(self.copy_metadata as u8);
1438 Ok(())
1439 }
1440 }
1441
1442 impl Decode for ClientboundRespawn {
1443 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
1444 let dimension = decode_string(src)?;
1445 let world_name = decode_string(src)?;
1446 if src.remaining() < 8 {
1447 return Err(ProtocolError::Io(std::io::Error::new(
1448 std::io::ErrorKind::UnexpectedEof,
1449 "Missing bytes for ClientboundRespawn hashed_seed",
1450 )));
1451 }
1452 let hashed_seed = src.get_i64();
1453 if src.remaining() < 3 {
1454 return Err(ProtocolError::Io(std::io::Error::new(
1455 std::io::ErrorKind::UnexpectedEof,
1456 "Missing bytes for ClientboundRespawn game modes",
1457 )));
1458 }
1459 let game_mode = src.get_u8();
1460 let previous_game_mode = src.get_i8();
1461 if src.remaining() < 3 {
1462 return Err(ProtocolError::Io(std::io::Error::new(
1463 std::io::ErrorKind::UnexpectedEof,
1464 "Missing bytes for ClientboundRespawn flags",
1465 )));
1466 }
1467 let is_debug = src.get_u8() != 0;
1468 let is_flat = src.get_u8() != 0;
1469 let copy_metadata = src.get_u8() != 0;
1470 Ok(Self {
1471 dimension,
1472 world_name,
1473 hashed_seed,
1474 game_mode,
1475 previous_game_mode,
1476 is_debug,
1477 is_flat,
1478 copy_metadata,
1479 })
1480 }
1481 }
1482
1483 #[derive(Debug, Clone, PartialEq)]
1484 pub struct ClientboundPlayerPosition {
1485 pub x: f64,
1486 pub y: f64,
1487 pub z: f64,
1488 pub yaw: f32,
1489 pub pitch: f32,
1490 pub flags: u8,
1491 pub teleport_id: VarInt,
1492 }
1493
1494 impl PacketId for ClientboundPlayerPosition {
1495 fn packet_id(_ver: u32) -> u8 {
1496 0x34
1497 }
1498 }
1499
1500 impl Encode for ClientboundPlayerPosition {
1501 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
1502 dst.put_f64(self.x);
1503 dst.put_f64(self.y);
1504 dst.put_f64(self.z);
1505 dst.put_f32(self.yaw);
1506 dst.put_f32(self.pitch);
1507 dst.put_u8(self.flags);
1508 self.teleport_id.encode(dst)
1509 }
1510 }
1511
1512 impl Decode for ClientboundPlayerPosition {
1513 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
1514 if src.remaining() < 8 * 3 + 4 * 2 + 1 {
1515 return Err(ProtocolError::Io(std::io::Error::new(
1516 std::io::ErrorKind::UnexpectedEof,
1517 "Missing bytes for ClientboundPlayerPosition",
1518 )));
1519 }
1520 let x = src.get_f64();
1521 let y = src.get_f64();
1522 let z = src.get_f64();
1523 let yaw = src.get_f32();
1524 let pitch = src.get_f32();
1525 let flags = src.get_u8();
1526 let teleport_id = VarInt::decode(src)?;
1527 Ok(Self {
1528 x,
1529 y,
1530 z,
1531 yaw,
1532 pitch,
1533 flags,
1534 teleport_id,
1535 })
1536 }
1537 }
1538
1539 #[derive(Debug, Clone, PartialEq)]
1540 pub struct ClientboundKeepAlive {
1541 pub keep_alive_id: i64,
1542 }
1543
1544 impl PacketId for ClientboundKeepAlive {
1545 fn packet_id(_ver: u32) -> u8 {
1546 0x1F
1547 }
1548 }
1549
1550 impl Encode for ClientboundKeepAlive {
1551 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
1552 dst.put_i64(self.keep_alive_id);
1553 Ok(())
1554 }
1555 }
1556
1557 impl Decode for ClientboundKeepAlive {
1558 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
1559 if src.remaining() < 8 {
1560 return Err(ProtocolError::Io(std::io::Error::new(
1561 std::io::ErrorKind::UnexpectedEof,
1562 "Missing bytes for ClientboundKeepAlive",
1563 )));
1564 }
1565 Ok(Self {
1566 keep_alive_id: src.get_i64(),
1567 })
1568 }
1569 }
1570
1571 #[derive(Debug, Clone, PartialEq)]
1572 pub struct ServerboundKeepAlive {
1573 pub keep_alive_id: i64,
1574 }
1575
1576 impl PacketId for ServerboundKeepAlive {
1577 fn packet_id(_ver: u32) -> u8 {
1578 0x10
1579 }
1580 }
1581
1582 impl Encode for ServerboundKeepAlive {
1583 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
1584 dst.put_i64(self.keep_alive_id);
1585 Ok(())
1586 }
1587 }
1588
1589 impl Decode for ServerboundKeepAlive {
1590 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
1591 if src.remaining() < 8 {
1592 return Err(ProtocolError::Io(std::io::Error::new(
1593 std::io::ErrorKind::UnexpectedEof,
1594 "Missing bytes for ServerboundKeepAlive",
1595 )));
1596 }
1597 Ok(Self {
1598 keep_alive_id: src.get_i64(),
1599 })
1600 }
1601 }
1602
1603 #[derive(Debug, Clone, PartialEq)]
1604 pub struct ClientboundChatMessage {
1605 pub json_message: String,
1606 pub position: u8,
1607 pub sender: uuid::Uuid,
1608 }
1609
1610 impl PacketId for ClientboundChatMessage {
1611 fn packet_id(_ver: u32) -> u8 {
1612 0x0E
1613 }
1614 }
1615
1616 impl Encode for ClientboundChatMessage {
1617 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
1618 encode_string(&self.json_message, dst)?;
1619 dst.put_u8(self.position);
1620 let (hi, lo) = self.sender.as_u64_pair();
1621 dst.put_i64(hi as i64);
1622 dst.put_i64(lo as i64);
1623 Ok(())
1624 }
1625 }
1626
1627 impl Decode for ClientboundChatMessage {
1628 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
1629 let json_message = decode_string(src)?;
1630 if src.remaining() < 1 + 16 {
1631 return Err(ProtocolError::Io(std::io::Error::new(
1632 std::io::ErrorKind::UnexpectedEof,
1633 "Missing bytes for ClientboundChatMessage position/sender",
1634 )));
1635 }
1636 let position = src.get_u8();
1637 let hi = src.get_i64() as u64;
1638 let lo = src.get_i64() as u64;
1639 let sender = uuid::Uuid::from_u64_pair(hi, lo);
1640 Ok(Self {
1641 json_message,
1642 position,
1643 sender,
1644 })
1645 }
1646 }
1647
1648 #[derive(Debug, Clone, PartialEq)]
1649 pub struct ServerboundChatMessage {
1650 pub message: String,
1651 }
1652
1653 impl PacketId for ServerboundChatMessage {
1654 fn packet_id(_ver: u32) -> u8 {
1655 0x03
1656 }
1657 }
1658
1659 impl Encode for ServerboundChatMessage {
1660 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
1661 encode_string(&self.message, dst)
1662 }
1663 }
1664
1665 impl Decode for ServerboundChatMessage {
1666 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
1667 Ok(Self {
1668 message: decode_string(src)?,
1669 })
1670 }
1671 }
1672
1673 #[derive(Debug, Clone, PartialEq)]
1674 pub struct ServerboundMovePlayerPos {
1675 pub x: f64,
1676 pub feet_y: f64,
1677 pub z: f64,
1678 pub on_ground: bool,
1679 }
1680
1681 impl PacketId for ServerboundMovePlayerPos {
1682 fn packet_id(_ver: u32) -> u8 {
1683 0x12
1684 }
1685 }
1686
1687 impl Encode for ServerboundMovePlayerPos {
1688 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
1689 dst.put_f64(self.x);
1690 dst.put_f64(self.feet_y);
1691 dst.put_f64(self.z);
1692 dst.put_u8(self.on_ground as u8);
1693 Ok(())
1694 }
1695 }
1696
1697 impl Decode for ServerboundMovePlayerPos {
1698 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
1699 if src.remaining() < 8 * 3 + 1 {
1700 return Err(ProtocolError::Io(std::io::Error::new(
1701 std::io::ErrorKind::UnexpectedEof,
1702 "Missing bytes for ServerboundMovePlayerPos",
1703 )));
1704 }
1705 Ok(Self {
1706 x: src.get_f64(),
1707 feet_y: src.get_f64(),
1708 z: src.get_f64(),
1709 on_ground: src.get_u8() != 0,
1710 })
1711 }
1712 }
1713
1714 #[derive(Debug, Clone, PartialEq)]
1715 pub struct ServerboundMovePlayerRot {
1716 pub yaw: f32,
1717 pub pitch: f32,
1718 pub on_ground: bool,
1719 }
1720
1721 impl PacketId for ServerboundMovePlayerRot {
1722 fn packet_id(_ver: u32) -> u8 {
1723 0x13
1724 }
1725 }
1726
1727 impl Encode for ServerboundMovePlayerRot {
1728 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
1729 dst.put_f32(self.yaw);
1730 dst.put_f32(self.pitch);
1731 dst.put_u8(self.on_ground as u8);
1732 Ok(())
1733 }
1734 }
1735
1736 impl Decode for ServerboundMovePlayerRot {
1737 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
1738 if src.remaining() < 4 * 2 + 1 {
1739 return Err(ProtocolError::Io(std::io::Error::new(
1740 std::io::ErrorKind::UnexpectedEof,
1741 "Missing bytes for ServerboundMovePlayerRot",
1742 )));
1743 }
1744 Ok(Self {
1745 yaw: src.get_f32(),
1746 pitch: src.get_f32(),
1747 on_ground: src.get_u8() != 0,
1748 })
1749 }
1750 }
1751
1752 #[derive(Debug, Clone, PartialEq)]
1753 pub struct ServerboundMovePlayerPosRot {
1754 pub x: f64,
1755 pub feet_y: f64,
1756 pub z: f64,
1757 pub yaw: f32,
1758 pub pitch: f32,
1759 pub on_ground: bool,
1760 }
1761
1762 impl PacketId for ServerboundMovePlayerPosRot {
1763 fn packet_id(_ver: u32) -> u8 {
1764 0x14
1765 }
1766 }
1767
1768 impl Encode for ServerboundMovePlayerPosRot {
1769 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
1770 dst.put_f64(self.x);
1771 dst.put_f64(self.feet_y);
1772 dst.put_f64(self.z);
1773 dst.put_f32(self.yaw);
1774 dst.put_f32(self.pitch);
1775 dst.put_u8(self.on_ground as u8);
1776 Ok(())
1777 }
1778 }
1779
1780 impl Decode for ServerboundMovePlayerPosRot {
1781 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
1782 if src.remaining() < 8 * 3 + 4 * 2 + 1 {
1783 return Err(ProtocolError::Io(std::io::Error::new(
1784 std::io::ErrorKind::UnexpectedEof,
1785 "Missing bytes for ServerboundMovePlayerPosRot",
1786 )));
1787 }
1788 Ok(Self {
1789 x: src.get_f64(),
1790 feet_y: src.get_f64(),
1791 z: src.get_f64(),
1792 yaw: src.get_f32(),
1793 pitch: src.get_f32(),
1794 on_ground: src.get_u8() != 0,
1795 })
1796 }
1797 }
1798
1799 #[derive(Debug, Clone, PartialEq)]
1800 pub enum InteractAction {
1801 Interact {
1802 hand: VarInt,
1803 },
1804 Attack,
1805 InteractAt {
1806 target_x: f32,
1807 target_y: f32,
1808 target_z: f32,
1809 hand: VarInt,
1810 },
1811 }
1812
1813 #[derive(Debug, Clone, PartialEq)]
1814 pub struct ServerboundInteract {
1815 pub entity_id: VarInt,
1816 pub action: InteractAction,
1817 pub sneaking: bool,
1818 }
1819
1820 impl PacketId for ServerboundInteract {
1821 fn packet_id(_ver: u32) -> u8 {
1822 0x0E
1823 }
1824 }
1825
1826 impl Encode for ServerboundInteract {
1827 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
1828 self.entity_id.encode(dst)?;
1829 match &self.action {
1830 InteractAction::Interact { hand } => {
1831 VarInt(0).encode(dst)?;
1832 hand.encode(dst)?;
1833 },
1834 InteractAction::Attack => {
1835 VarInt(1).encode(dst)?;
1836 },
1837 InteractAction::InteractAt {
1838 target_x,
1839 target_y,
1840 target_z,
1841 hand,
1842 } => {
1843 VarInt(2).encode(dst)?;
1844 dst.put_f32(*target_x);
1845 dst.put_f32(*target_y);
1846 dst.put_f32(*target_z);
1847 hand.encode(dst)?;
1848 },
1849 }
1850 dst.put_u8(self.sneaking as u8);
1851 Ok(())
1852 }
1853 }
1854
1855 impl Decode for ServerboundInteract {
1856 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
1857 let entity_id = VarInt::decode(src)?;
1858 let action = match VarInt::decode(src)?.0 {
1859 0 => InteractAction::Interact {
1860 hand: VarInt::decode(src)?,
1861 },
1862 1 => InteractAction::Attack,
1863 2 => {
1864 if src.remaining() < 12 {
1865 return Err(ProtocolError::Io(std::io::Error::new(
1866 std::io::ErrorKind::UnexpectedEof,
1867 "Missing bytes for InteractAt",
1868 )));
1869 }
1870 InteractAction::InteractAt {
1871 target_x: src.get_f32(),
1872 target_y: src.get_f32(),
1873 target_z: src.get_f32(),
1874 hand: VarInt::decode(src)?,
1875 }
1876 },
1877 _ => {
1878 return Err(ProtocolError::Io(std::io::Error::new(
1879 std::io::ErrorKind::InvalidData,
1880 "Unknown InteractAction type",
1881 )))
1882 },
1883 };
1884 if src.remaining() < 1 {
1885 return Err(ProtocolError::Io(std::io::Error::new(
1886 std::io::ErrorKind::UnexpectedEof,
1887 "Missing bytes for sneaking",
1888 )));
1889 }
1890 Ok(Self {
1891 entity_id,
1892 action,
1893 sneaking: src.get_u8() != 0,
1894 })
1895 }
1896 }
1897
1898 #[derive(Debug, Clone, PartialEq)]
1899 pub struct ClientboundPluginMessage {
1900 pub channel: String,
1901 pub data: Vec<u8>,
1902 }
1903
1904 impl PacketId for ClientboundPluginMessage {
1905 fn packet_id(_ver: u32) -> u8 {
1906 0x17
1907 }
1908 }
1909
1910 impl Encode for ClientboundPluginMessage {
1911 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
1912 encode_string(&self.channel, dst)?;
1913 dst.put_slice(&self.data);
1914 Ok(())
1915 }
1916 }
1917
1918 impl Decode for ClientboundPluginMessage {
1919 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
1920 let channel = decode_string(src)?;
1921 let data = src.copy_to_bytes(src.remaining()).to_vec();
1922 Ok(Self { channel, data })
1923 }
1924 }
1925
1926 #[derive(Debug, Clone, PartialEq)]
1927 pub struct ServerboundPluginMessage {
1928 pub channel: String,
1929 pub data: Vec<u8>,
1930 }
1931
1932 impl PacketId for ServerboundPluginMessage {
1933 fn packet_id(_ver: u32) -> u8 {
1934 0x0B
1935 }
1936 }
1937
1938 impl Encode for ServerboundPluginMessage {
1939 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
1940 encode_string(&self.channel, dst)?;
1941 dst.put_slice(&self.data);
1942 Ok(())
1943 }
1944 }
1945
1946 impl Decode for ServerboundPluginMessage {
1947 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
1948 let channel = decode_string(src)?;
1949 let data = src.copy_to_bytes(src.remaining()).to_vec();
1950 Ok(Self { channel, data })
1951 }
1952 }
1953
1954 #[derive(Debug, Clone, PartialEq)]
1955 pub struct ClientboundDisconnect {
1956 pub reason: String,
1957 }
1958
1959 impl PacketId for ClientboundDisconnect {
1960 fn packet_id(_ver: u32) -> u8 {
1961 0x19
1962 }
1963 }
1964
1965 impl Encode for ClientboundDisconnect {
1966 fn encode(&self, dst: &mut BytesMut) -> Result<(), ProtocolError> {
1967 encode_string(&self.reason, dst)
1968 }
1969 }
1970
1971 impl Decode for ClientboundDisconnect {
1972 fn decode(src: &mut Bytes) -> Result<Self, ProtocolError> {
1973 Ok(Self {
1974 reason: decode_string(src)?,
1975 })
1976 }
1977 }
1978}
1979
1980#[cfg(test)]
1981mod tests {
1982 use super::*;
1983
1984 macro_rules! roundtrip {
1985 ($T:ty, $val:expr) => {{
1986 let v = $val;
1987 let mut buf = BytesMut::new();
1988 v.encode(&mut buf).unwrap();
1989 let mut b = buf.freeze();
1990 assert_eq!(<$T>::decode(&mut b).unwrap(), v);
1991 }};
1992 }
1993
1994 #[test]
1995 fn join_game_roundtrip() {
1996 roundtrip!(
1997 ClientboundJoinGame,
1998 ClientboundJoinGame {
1999 entity_id: 1,
2000 is_hardcore: false,
2001 game_mode: 0,
2002 previous_game_mode: -1,
2003 world_names: vec!["minecraft:overworld".to_string()],
2004 dimension: "minecraft:overworld".to_string(),
2005 world_name: "minecraft:overworld".to_string(),
2006 hashed_seed: 12345678,
2007 max_players: VarInt(20),
2008 view_distance: VarInt(10),
2009 reduced_debug_info: false,
2010 enable_respawn_screen: true,
2011 is_debug: false,
2012 is_flat: false,
2013 }
2014 );
2015 }
2016
2017 #[test]
2018 fn respawn_roundtrip() {
2019 roundtrip!(
2020 ClientboundRespawn,
2021 ClientboundRespawn {
2022 dimension: "minecraft:the_nether".to_string(),
2023 world_name: "minecraft:the_nether".to_string(),
2024 hashed_seed: 0,
2025 game_mode: 0,
2026 previous_game_mode: -1,
2027 is_debug: false,
2028 is_flat: false,
2029 copy_metadata: true,
2030 }
2031 );
2032 }
2033
2034 #[test]
2035 fn player_position_roundtrip() {
2036 roundtrip!(
2037 ClientboundPlayerPosition,
2038 ClientboundPlayerPosition {
2039 x: 10.0,
2040 y: 64.0,
2041 z: -10.0,
2042 yaw: 0.0,
2043 pitch: 0.0,
2044 flags: 0,
2045 teleport_id: VarInt(1),
2046 }
2047 );
2048 }
2049
2050 #[test]
2051 fn keepalive_roundtrip() {
2052 roundtrip!(
2053 ClientboundKeepAlive,
2054 ClientboundKeepAlive {
2055 keep_alive_id: 111222333_i64
2056 }
2057 );
2058 roundtrip!(
2059 ServerboundKeepAlive,
2060 ServerboundKeepAlive {
2061 keep_alive_id: 111222333_i64
2062 }
2063 );
2064 }
2065
2066 #[test]
2067 fn chat_roundtrip() {
2068 roundtrip!(
2069 ClientboundChatMessage,
2070 ClientboundChatMessage {
2071 json_message: r#"{"text":"hi"}"#.to_string(),
2072 position: 1,
2073 sender: uuid::Uuid::nil(),
2074 }
2075 );
2076 roundtrip!(
2077 ServerboundChatMessage,
2078 ServerboundChatMessage {
2079 message: "hello".to_string()
2080 }
2081 );
2082 }
2083
2084 #[test]
2085 fn move_roundtrips() {
2086 roundtrip!(
2087 ServerboundMovePlayerPos,
2088 ServerboundMovePlayerPos {
2089 x: 0.0,
2090 feet_y: 64.0,
2091 z: 0.0,
2092 on_ground: true
2093 }
2094 );
2095 roundtrip!(
2096 ServerboundMovePlayerRot,
2097 ServerboundMovePlayerRot {
2098 yaw: 45.0,
2099 pitch: -20.0,
2100 on_ground: false
2101 }
2102 );
2103 roundtrip!(
2104 ServerboundMovePlayerPosRot,
2105 ServerboundMovePlayerPosRot {
2106 x: 5.0,
2107 feet_y: 65.0,
2108 z: -5.0,
2109 yaw: 90.0,
2110 pitch: 0.0,
2111 on_ground: true
2112 }
2113 );
2114 }
2115
2116 #[test]
2117 fn interact_roundtrips() {
2118 roundtrip!(
2119 ServerboundInteract,
2120 ServerboundInteract {
2121 entity_id: VarInt(3),
2122 action: InteractAction::Attack,
2123 sneaking: true
2124 }
2125 );
2126 roundtrip!(
2127 ServerboundInteract,
2128 ServerboundInteract {
2129 entity_id: VarInt(4),
2130 action: InteractAction::Interact { hand: VarInt(0) },
2131 sneaking: false
2132 }
2133 );
2134 roundtrip!(
2135 ServerboundInteract,
2136 ServerboundInteract {
2137 entity_id: VarInt(5),
2138 action: InteractAction::InteractAt {
2139 target_x: 0.5,
2140 target_y: 1.0,
2141 target_z: 0.5,
2142 hand: VarInt(1)
2143 },
2144 sneaking: false,
2145 }
2146 );
2147 }
2148
2149 #[test]
2150 fn plugin_message_roundtrip() {
2151 roundtrip!(
2152 ClientboundPluginMessage,
2153 ClientboundPluginMessage {
2154 channel: "minecraft:brand".to_string(),
2155 data: b"velocity".to_vec()
2156 }
2157 );
2158 roundtrip!(
2159 ServerboundPluginMessage,
2160 ServerboundPluginMessage {
2161 channel: "minecraft:brand".to_string(),
2162 data: b"vanilla".to_vec()
2163 }
2164 );
2165 }
2166
2167 #[test]
2168 fn disconnect_roundtrip() {
2169 roundtrip!(
2170 ClientboundDisconnect,
2171 ClientboundDisconnect {
2172 reason: r#"{"text":"cya"}"#.to_string()
2173 }
2174 );
2175 }
2176
2177 #[test]
2178 fn raw_stubs_roundtrip() {
2179 roundtrip!(
2180 ClientboundChunkData,
2181 ClientboundChunkData {
2182 raw: vec![0xFF; 32]
2183 }
2184 );
2185 roundtrip!(
2186 ClientboundEntityMetadata,
2187 ClientboundEntityMetadata { raw: vec![] }
2188 );
2189 roundtrip!(
2190 ServerboundPlayerDigging,
2191 ServerboundPlayerDigging { raw: vec![0x00; 8] }
2192 );
2193 roundtrip!(
2194 ServerboundPlayerBlockPlacement,
2195 ServerboundPlayerBlockPlacement {
2196 raw: vec![0xAB, 0xCD]
2197 }
2198 );
2199 }
2200
2201 #[test]
2202 fn packet_ids() {
2203 assert_eq!(ClientboundJoinGame::packet_id(754), 0x24);
2204 assert_eq!(ClientboundRespawn::packet_id(754), 0x39);
2205 assert_eq!(ClientboundPlayerPosition::packet_id(754), 0x34);
2206 assert_eq!(ClientboundKeepAlive::packet_id(754), 0x1F);
2207 assert_eq!(ServerboundKeepAlive::packet_id(754), 0x10);
2208 assert_eq!(ClientboundChatMessage::packet_id(754), 0x0E);
2209 assert_eq!(ServerboundChatMessage::packet_id(754), 0x03);
2210 assert_eq!(ServerboundMovePlayerPos::packet_id(754), 0x12);
2211 assert_eq!(ServerboundMovePlayerRot::packet_id(754), 0x13);
2212 assert_eq!(ServerboundMovePlayerPosRot::packet_id(754), 0x14);
2213 assert_eq!(ServerboundInteract::packet_id(754), 0x0E);
2214 assert_eq!(ClientboundPluginMessage::packet_id(754), 0x17);
2215 assert_eq!(ServerboundPluginMessage::packet_id(754), 0x0B);
2216 assert_eq!(ClientboundDisconnect::packet_id(754), 0x19);
2217
2218 assert_eq!(ClientboundSpawnEntity::packet_id(754), 0x00);
2219 assert_eq!(ClientboundSpawnPlayer::packet_id(754), 0x04);
2220 assert_eq!(ClientboundBlockChange::packet_id(754), 0x0B);
2221 assert_eq!(ClientboundChunkData::packet_id(754), 0x21);
2222 assert_eq!(ClientboundEntityVelocity::packet_id(754), 0x46);
2223 assert_eq!(ClientboundUpdateHealth::packet_id(754), 0x49);
2224 assert_eq!(ClientboundDeclareRecipes::packet_id(754), 0x5A);
2225 assert_eq!(ClientboundTags::packet_id(754), 0x5B);
2226 assert_eq!(ServerboundTeleportConfirm::packet_id(754), 0x00);
2227 assert_eq!(ServerboundPlayerDigging::packet_id(754), 0x1B);
2228 assert_eq!(ServerboundPlayerBlockPlacement::packet_id(754), 0x2E);
2229 assert_eq!(ServerboundUseItem::packet_id(754), 0x2F);
2230 }
2231}