1#![doc = include_str!("../README.md")]
2#![allow(deprecated)] #[doc(hidden)]
6pub mod __private {
7 pub use anyhow::{anyhow, bail, ensure, Context, Result};
8
9 pub use crate::Packet;
10}
11
12extern crate self as chunkedge_protocol;
13
14mod biome_pos;
15pub mod block_pos;
16pub mod chunk_pos;
17pub mod chunk_section_pos;
18pub mod decode;
19mod difficulty;
20mod direction;
21pub mod encode;
22pub mod game_mode;
23mod global_pos;
24mod hand;
25pub mod movement_flags;
26pub mod packets;
27pub mod profile;
28pub mod sound;
29mod velocity;
30
31use std::io::Write;
32
33use anyhow::Context;
34pub use biome_pos::BiomePos;
35pub use block::{BlockKind, BlockState};
36pub use block_pos::BlockPos;
37pub use chunk_pos::ChunkPos;
38pub use chunk_section_pos::ChunkSectionPos;
39pub use chunkedge_binary::array::FixedArray;
40pub use chunkedge_binary::bit_set::{FixedBitSet, VariableBitSet};
41pub use chunkedge_binary::byte_angle::ByteAngle;
42use chunkedge_binary::Encode;
43pub use chunkedge_binary::{
44 IDSet, IdOr, IntoTextComponent, TextComponent, VarInt, VarIntDecodeError, VarLong,
45};
46pub use chunkedge_generated::registry_id::RegistryId;
47pub use chunkedge_generated::{block, packet_id, status_effects};
48pub use chunkedge_ident::Ident;
49pub use chunkedge_item::{ItemKind, ItemStack};
50use chunkedge_protocol_macros::Packet;
51pub use decode::PacketDecoder;
52use derive_more::{From, Into};
53pub use difficulty::Difficulty;
54pub use direction::Direction;
55pub use encode::{PacketEncoder, WritePacket};
56pub use game_mode::GameMode;
57pub use global_pos::GlobalPos;
58pub use hand::Hand;
59pub use ident::ident;
60pub use packets::play::level_particles_s2c::Particle;
61use serde::{Deserialize, Serialize};
62pub use sound::Sound;
63pub use text::{JsonText, Text};
64pub use velocity::Velocity;
65pub use {
66 anyhow, bytes, chunkedge_ident as ident, chunkedge_math as math, chunkedge_nbt as nbt,
67 chunkedge_text as text, uuid,
68};
69
70pub const MAX_PACKET_SIZE: i32 = 2_i32.pow(21) - 1; pub const PROTOCOL_VERSION: i32 = 770;
75
76pub const MINECRAFT_VERSION: &str = "1.21.5";
79
80#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, From, Into)]
86pub struct CompressionThreshold(pub i32);
87
88impl CompressionThreshold {
89 pub const DEFAULT: Self = Self(-1);
91}
92
93impl Default for CompressionThreshold {
95 fn default() -> Self {
96 Self::DEFAULT
97 }
98}
99
100pub trait Packet: std::fmt::Debug {
107 const ID: i32;
109 const NAME: &'static str;
111 const SIDE: PacketSide;
113 const STATE: PacketState;
115
116 fn encode_with_id(&self, mut w: impl Write) -> anyhow::Result<()>
118 where
119 Self: Encode,
120 {
121 VarInt(Self::ID)
122 .encode(&mut w)
123 .context("failed to encode packet ID")?;
124
125 self.encode(w)
126 }
127}
128
129#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
131pub enum PacketSide {
132 Clientbound,
134 Serverbound,
136}
137
138#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
140pub enum PacketState {
141 Handshake,
142 Status,
143 Login,
144 Configuration,
145 Play,
146}
147
148#[allow(dead_code)]
149#[cfg(test)]
150mod tests {
151 use std::borrow::Cow;
152
153 use bytes::BytesMut;
154 use chunkedge_binary::{Decode, Encode, VarInt, VarLong};
156 use chunkedge_item::{ItemKind, ItemStack};
157 use chunkedge_protocol_macros::Packet;
158
159 use super::*;
160 use crate::block_pos::BlockPos;
161 use crate::decode::PacketDecoder;
162 use crate::encode::PacketEncoder;
163 use crate::hand::Hand;
164 use crate::text::{IntoText, Text};
165 use crate::Ident;
166
167 #[derive(Encode, Decode, Packet, Debug)]
168 #[packet(id = 1, side = PacketSide::Clientbound)]
169 struct RegularStruct {
170 foo: i32,
171 bar: bool,
172 baz: f64,
173 }
174
175 #[derive(Encode, Decode, Packet, Debug)]
176 #[packet(id = 2, side = PacketSide::Clientbound)]
177 struct UnitStruct;
178
179 #[derive(Encode, Decode, Packet, Debug)]
180 #[packet(id = 3, side = PacketSide::Clientbound)]
181 struct EmptyStruct;
182
183 #[derive(Encode, Decode, Packet, Debug)]
184 #[packet(id = 4, side = PacketSide::Clientbound)]
185 struct TupleStruct(i32, bool, f64);
186
187 #[derive(Encode, Decode, Packet, Debug)]
188 #[packet(id = 5, side = PacketSide::Clientbound)]
189 struct StructWithGenerics<'z, T = ()> {
190 foo: &'z str,
191 bar: T,
192 }
193
194 #[derive(Encode, Decode, Packet, Debug)]
195 #[packet(id = 6, side = PacketSide::Clientbound)]
196 struct TupleStructWithGenerics<'z, T = ()>(&'z str, i32, T);
197
198 #[allow(unconditional_recursion, clippy::extra_unused_type_parameters)]
199 fn assert_has_impls<'a, T>()
200 where
201 T: Encode + Decode<'a> + Packet,
202 {
203 assert_has_impls::<RegularStruct>();
204 assert_has_impls::<UnitStruct>();
205 assert_has_impls::<EmptyStruct>();
206 assert_has_impls::<TupleStruct>();
207 assert_has_impls::<StructWithGenerics>();
208 assert_has_impls::<TupleStructWithGenerics>();
209 }
210
211 #[test]
212 fn packet_name() {
213 assert_eq!(RegularStruct::NAME, "RegularStruct");
214 assert_eq!(UnitStruct::NAME, "UnitStruct");
215 assert_eq!(StructWithGenerics::<()>::NAME, "StructWithGenerics");
216 }
217
218 #[cfg(feature = "encryption")]
219 const CRYPT_KEY: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
220
221 #[derive(PartialEq, Debug, Encode, Decode, Packet)]
222 #[packet(id = 42, side = PacketSide::Clientbound)]
223 struct TestPacket<'a> {
224 a: bool,
225 b: u8,
226 c: i32,
227 d: f32,
228 e: f64,
229 f: BlockPos,
230 g: Hand,
231 h: Ident<Cow<'a, str>>,
232 i: ItemStack,
233 j: Text,
234 k: VarInt,
235 l: VarLong,
236 m: &'a str,
237 n: &'a [u8; 10],
238 o: [u128; 3],
239 }
240
241 impl<'a> TestPacket<'a> {
242 fn new(string: &'a str) -> Self {
243 Self {
244 a: true,
245 b: 12,
246 c: -999,
247 d: 5.001,
248 e: 1e10,
249 f: BlockPos::new(1, 2, 3),
250 g: Hand::Off,
251 h: Ident::new("minecraft:whatever").unwrap(),
252 i: ItemStack::new(ItemKind::WoodenSword, 12),
253 j: "my ".into_text() + "fancy".italic() + " text",
254 k: VarInt(123),
255 l: VarLong(456),
256 m: string,
257 n: &[7; 10],
258 o: [123456789; 3],
259 }
260 }
261 }
262
263 fn check_test_packet(dec: &mut PacketDecoder, string: &str) {
264 let frame = dec.try_next_packet().unwrap().unwrap();
265
266 let pkt = frame.decode::<TestPacket>().unwrap();
267
268 assert_eq!(&pkt, &TestPacket::new(string));
269 }
270
271 #[test]
272 fn packets_round_trip() {
273 let mut buf = BytesMut::new();
274
275 let mut enc = PacketEncoder::new();
276
277 enc.append_packet(&TestPacket::new("first")).unwrap();
278 #[cfg(feature = "compression")]
279 enc.set_compression(0.into());
280 enc.append_packet(&TestPacket::new("second")).unwrap();
281 buf.unsplit(enc.take());
282 #[cfg(feature = "encryption")]
283 enc.enable_encryption(&CRYPT_KEY);
284 enc.append_packet(&TestPacket::new("third")).unwrap();
285 enc.prepend_packet(&TestPacket::new("fourth")).unwrap();
286
287 buf.unsplit(enc.take());
288
289 let mut dec = PacketDecoder::new();
290
291 dec.queue_bytes(buf);
292
293 check_test_packet(&mut dec, "first");
294
295 #[cfg(feature = "compression")]
296 dec.set_compression(0.into());
297
298 check_test_packet(&mut dec, "second");
299
300 #[cfg(feature = "encryption")]
301 dec.enable_encryption(&CRYPT_KEY);
302
303 check_test_packet(&mut dec, "fourth");
304 check_test_packet(&mut dec, "third");
305 }
306}