1#![doc = include_str!("../README.md")]
2
3#[doc(hidden)]
5pub mod __private {
6 pub use anyhow::{anyhow, bail, ensure, Context, Result};
7
8 pub use crate::var_int::VarInt;
9 pub use crate::{Decode, Encode, Packet};
10}
11
12extern crate self as valence_protocol;
14
15mod array;
16mod biome_pos;
17mod bit_set;
18pub mod block_pos;
19mod bounded;
20mod byte_angle;
21pub mod chunk_pos;
22pub mod chunk_section_pos;
23pub mod decode;
24mod difficulty;
25mod direction;
26pub mod encode;
27pub mod game_mode;
28mod global_pos;
29mod hand;
30mod impls;
31pub mod item;
32pub mod packets;
33pub mod profile;
34mod raw;
35pub mod sound;
36pub mod var_int;
37mod var_long;
38mod velocity;
39
40use std::io::Write;
41
42use anyhow::Context;
43pub use array::FixedArray;
44pub use biome_pos::BiomePos;
45pub use bit_set::FixedBitSet;
46pub use block::{BlockKind, BlockState};
47pub use block_pos::BlockPos;
48pub use bounded::Bounded;
49pub use byte_angle::ByteAngle;
50pub use chunk_pos::ChunkPos;
51pub use chunk_section_pos::ChunkSectionPos;
52pub use decode::PacketDecoder;
53use derive_more::{From, Into};
54pub use difficulty::Difficulty;
55pub use direction::Direction;
56pub use encode::{PacketEncoder, WritePacket};
57pub use game_mode::GameMode;
58pub use global_pos::GlobalPos;
59pub use hand::Hand;
60pub use ident::ident;
61pub use item::{ItemKind, ItemStack};
62pub use packets::play::particle_s2c::Particle;
63pub use raw::RawBytes;
64use serde::{Deserialize, Serialize};
65pub use sound::Sound;
66pub use text::Text;
67pub use valence_generated::{block, packet_id, status_effects};
68pub use valence_ident::Ident;
69pub use valence_protocol_macros::{Decode, Encode, Packet};
70pub use var_int::VarInt;
71pub use var_long::VarLong;
72pub use velocity::Velocity;
73pub use {
74 anyhow, bytes, uuid, valence_ident as ident, valence_math as math, valence_nbt as nbt,
75 valence_text as text,
76};
77
78pub const MAX_PACKET_SIZE: i32 = 2097152;
80
81pub const PROTOCOL_VERSION: i32 = 763;
83
84pub const MINECRAFT_VERSION: &str = "1.20.1";
87
88#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, From, Into)]
94pub struct CompressionThreshold(pub i32);
95
96impl CompressionThreshold {
97 pub const DEFAULT: Self = Self(-1);
99}
100
101impl Default for CompressionThreshold {
103 fn default() -> Self {
104 Self::DEFAULT
105 }
106}
107
108pub trait Encode {
158 fn encode(&self, w: impl Write) -> anyhow::Result<()>;
167
168 fn encode_slice(slice: &[Self], mut w: impl Write) -> anyhow::Result<()>
182 where
183 Self: Sized,
184 {
185 for value in slice {
186 value.encode(&mut w)?;
187 }
188
189 Ok(())
190 }
191}
192
193pub trait Decode<'a>: Sized {
245 fn decode(r: &mut &'a [u8]) -> anyhow::Result<Self>;
250}
251
252pub trait Packet: std::fmt::Debug {
259 const ID: i32;
261 const NAME: &'static str;
263 const SIDE: PacketSide;
265 const STATE: PacketState;
267
268 fn encode_with_id(&self, mut w: impl Write) -> anyhow::Result<()>
270 where
271 Self: Encode,
272 {
273 VarInt(Self::ID)
274 .encode(&mut w)
275 .context("failed to encode packet ID")?;
276
277 self.encode(w)
278 }
279}
280
281#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
283pub enum PacketSide {
284 Clientbound,
286 Serverbound,
288}
289
290#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
292pub enum PacketState {
293 Handshaking,
294 Status,
295 Login,
296 Play,
297}
298
299#[allow(dead_code)]
300#[cfg(test)]
301mod tests {
302 use std::borrow::Cow;
303
304 use bytes::BytesMut;
305
306 use super::*;
307 use crate::block_pos::BlockPos;
308 use crate::decode::PacketDecoder;
309 use crate::encode::PacketEncoder;
310 use crate::hand::Hand;
311 use crate::item::{ItemKind, ItemStack};
312 use crate::text::{IntoText, Text};
313 use crate::var_int::VarInt;
314 use crate::var_long::VarLong;
315 use crate::Ident;
316
317 #[derive(Encode, Decode, Packet, Debug)]
318 #[packet(id = 1, side = PacketSide::Clientbound)]
319 struct RegularStruct {
320 foo: i32,
321 bar: bool,
322 baz: f64,
323 }
324
325 #[derive(Encode, Decode, Packet, Debug)]
326 #[packet(id = 2, side = PacketSide::Clientbound)]
327 struct UnitStruct;
328
329 #[derive(Encode, Decode, Packet, Debug)]
330 #[packet(id = 3, side = PacketSide::Clientbound)]
331 struct EmptyStruct;
332
333 #[derive(Encode, Decode, Packet, Debug)]
334 #[packet(id = 4, side = PacketSide::Clientbound)]
335 struct TupleStruct(i32, bool, f64);
336
337 #[derive(Encode, Decode, Packet, Debug)]
338 #[packet(id = 5, side = PacketSide::Clientbound)]
339 struct StructWithGenerics<'z, T = ()> {
340 foo: &'z str,
341 bar: T,
342 }
343
344 #[derive(Encode, Decode, Packet, Debug)]
345 #[packet(id = 6, side = PacketSide::Clientbound)]
346 struct TupleStructWithGenerics<'z, T = ()>(&'z str, i32, T);
347
348 #[allow(unconditional_recursion, clippy::extra_unused_type_parameters)]
349 fn assert_has_impls<'a, T>()
350 where
351 T: Encode + Decode<'a> + Packet,
352 {
353 assert_has_impls::<RegularStruct>();
354 assert_has_impls::<UnitStruct>();
355 assert_has_impls::<EmptyStruct>();
356 assert_has_impls::<TupleStruct>();
357 assert_has_impls::<StructWithGenerics>();
358 assert_has_impls::<TupleStructWithGenerics>();
359 }
360
361 #[test]
362 fn packet_name() {
363 assert_eq!(RegularStruct::NAME, "RegularStruct");
364 assert_eq!(UnitStruct::NAME, "UnitStruct");
365 assert_eq!(StructWithGenerics::<()>::NAME, "StructWithGenerics");
366 }
367
368 #[cfg(feature = "encryption")]
369 const CRYPT_KEY: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
370
371 #[derive(PartialEq, Debug, Encode, Decode, Packet)]
372 #[packet(id = 42, side = PacketSide::Clientbound)]
373 struct TestPacket<'a> {
374 a: bool,
375 b: u8,
376 c: i32,
377 d: f32,
378 e: f64,
379 f: BlockPos,
380 g: Hand,
381 h: Ident<Cow<'a, str>>,
382 i: ItemStack,
383 j: Text,
384 k: VarInt,
385 l: VarLong,
386 m: &'a str,
387 n: &'a [u8; 10],
388 o: [u128; 3],
389 }
390
391 impl<'a> TestPacket<'a> {
392 fn new(string: &'a str) -> Self {
393 Self {
394 a: true,
395 b: 12,
396 c: -999,
397 d: 5.001,
398 e: 1e10,
399 f: BlockPos::new(1, 2, 3),
400 g: Hand::Off,
401 h: Ident::new("minecraft:whatever").unwrap(),
402 i: ItemStack::new(ItemKind::WoodenSword, 12, None),
403 j: "my ".into_text() + "fancy".italic() + " text",
404 k: VarInt(123),
405 l: VarLong(456),
406 m: string,
407 n: &[7; 10],
408 o: [123456789; 3],
409 }
410 }
411 }
412
413 fn check_test_packet(dec: &mut PacketDecoder, string: &str) {
414 let frame = dec.try_next_packet().unwrap().unwrap();
415
416 let pkt = frame.decode::<TestPacket>().unwrap();
417
418 assert_eq!(&pkt, &TestPacket::new(string));
419 }
420
421 #[test]
422 fn packets_round_trip() {
423 let mut buf = BytesMut::new();
424
425 let mut enc = PacketEncoder::new();
426
427 enc.append_packet(&TestPacket::new("first")).unwrap();
428 #[cfg(feature = "compression")]
429 enc.set_compression(0.into());
430 enc.append_packet(&TestPacket::new("second")).unwrap();
431 buf.unsplit(enc.take());
432 #[cfg(feature = "encryption")]
433 enc.enable_encryption(&CRYPT_KEY);
434 enc.append_packet(&TestPacket::new("third")).unwrap();
435 enc.prepend_packet(&TestPacket::new("fourth")).unwrap();
436
437 buf.unsplit(enc.take());
438
439 let mut dec = PacketDecoder::new();
440
441 dec.queue_bytes(buf);
442
443 check_test_packet(&mut dec, "first");
444
445 #[cfg(feature = "compression")]
446 dec.set_compression(0.into());
447
448 check_test_packet(&mut dec, "second");
449
450 #[cfg(feature = "encryption")]
451 dec.enable_encryption(&CRYPT_KEY);
452
453 check_test_packet(&mut dec, "fourth");
454 check_test_packet(&mut dec, "third");
455 }
456}