From 90f16ab9779cd59a94f67381db892ac2ebb8ee21 Mon Sep 17 00:00:00 2001 From: Snowiiii Date: Wed, 31 Jul 2024 16:31:09 +0200 Subject: [PATCH] move to tokio's bytes crate --- Cargo.lock | 43 +- README.md | 11 +- pumpkin/Cargo.toml | 3 +- pumpkin/src/client/client_packet.rs | 47 +- pumpkin/src/client/mod.rs | 5 +- pumpkin/src/client/packet_decoder.rs | 4 +- pumpkin/src/client/packet_encoder.rs | 6 +- pumpkin/src/network/connection.rs | 168 ---- pumpkin/src/protocol/bytebuf/buffer.rs | 877 ------------------- pumpkin/src/protocol/bytebuf/mod.rs | 282 +++++- pumpkin/src/protocol/bytebuf/reader.rs | 368 -------- pumpkin/src/protocol/client/config/mod.rs | 78 +- pumpkin/src/protocol/client/login/mod.rs | 34 +- pumpkin/src/protocol/client/play/mod.rs | 66 +- pumpkin/src/protocol/client/status/mod.rs | 10 +- pumpkin/src/protocol/mod.rs | 10 +- pumpkin/src/protocol/nbt/deserialize.rs | 132 --- pumpkin/src/protocol/nbt/error.rs | 56 -- pumpkin/src/protocol/nbt/mod.rs | 445 ---------- pumpkin/src/protocol/nbt/nbt.rs | 283 ------ pumpkin/src/protocol/nbt/serialize.rs | 96 -- pumpkin/src/protocol/registry/biomes.rs | 90 +- pumpkin/src/protocol/registry/chat_type.rs | 13 +- pumpkin/src/protocol/registry/damage_type.rs | 64 +- pumpkin/src/protocol/registry/dimensions.rs | 35 +- pumpkin/src/protocol/registry/mod.rs | 15 +- pumpkin/src/protocol/server/config/mod.rs | 37 +- pumpkin/src/protocol/server/handshake/mod.rs | 12 +- pumpkin/src/protocol/server/login/mod.rs | 30 +- pumpkin/src/protocol/server/status/mod.rs | 8 +- pumpkin/src/server.rs | 33 +- 31 files changed, 685 insertions(+), 2676 deletions(-) delete mode 100644 pumpkin/src/network/connection.rs delete mode 100644 pumpkin/src/protocol/bytebuf/buffer.rs delete mode 100644 pumpkin/src/protocol/bytebuf/reader.rs delete mode 100644 pumpkin/src/protocol/nbt/deserialize.rs delete mode 100644 pumpkin/src/protocol/nbt/error.rs delete mode 100644 pumpkin/src/protocol/nbt/mod.rs delete mode 100644 pumpkin/src/protocol/nbt/nbt.rs delete mode 100644 pumpkin/src/protocol/nbt/serialize.rs diff --git a/Cargo.lock b/Cargo.lock index 98ab0397a..e145db112 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -69,9 +69,15 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" +checksum = "fca2be1d5c43812bae364ee3f30b3afcb7877cf59f4aeb94c66f313a41d2fac9" + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] name = "cfb8" @@ -123,6 +129,18 @@ dependencies = [ "libc", ] +[[package]] +name = "crab_nbt" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469a8a59b4898974c623174c52d1c47b2e21a19e1f6f849a8046aa9ba03af5cf" +dependencies = [ + "bytes", + "cesu8", + "derive_more", + "thiserror", +] + [[package]] name = "crc32fast" version = "1.4.2" @@ -177,6 +195,26 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "derive_more" +version = "1.0.0-beta.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7abbfc297053be59290e3152f8cbcd52c8642e0728b69ee187d991d4c1af08d" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0-beta.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bba3e9872d7c58ce7ef0fcf1844fcc3e23ef2a58377b50df35dd98e42a5726e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "digest" version = "0.10.7" @@ -484,6 +522,7 @@ dependencies = [ "byteorder", "bytes", "cfb8", + "crab_nbt", "crossbeam-channel", "flate2", "image", diff --git a/README.md b/README.md index 188b2ad50..cf3011ee6 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,16 @@ A Minecraft server written in pure Rust ### Features -- [x] Server Status/Ping -- [x] Encryption -- [ ] Compression - States - [x] Handshake - [x] Status - [x] Login - [x] Config - [ ] Play - \ No newline at end of file +- [x] Server Status/Ping +- [x] Encryption +- [ ] Compression +- [x] Configuration + +### Thanks +Big thanks to https://wiki.vg/ for providing all the Information we need for create this Project \ No newline at end of file diff --git a/pumpkin/Cargo.toml b/pumpkin/Cargo.toml index 55be3b759..b3cc7365c 100644 --- a/pumpkin/Cargo.toml +++ b/pumpkin/Cargo.toml @@ -16,7 +16,7 @@ rsa-der = "0.3.0" aes = "0.8.4" cfb8 = "0.8.1" flate2 = "1.0.30" -bytes = "1.6.1" +bytes = "1.7" anyhow = "1.0.86" @@ -30,5 +30,6 @@ mio = { version = "1.0.1", features = ["os-poll", "net"]} crossbeam-channel = "0.5.13" uuid = "1.10" toml = "0.8.17" +crab_nbt = "0.1.2" diff --git a/pumpkin/src/client/client_packet.rs b/pumpkin/src/client/client_packet.rs index 3928713a5..747ec1587 100644 --- a/pumpkin/src/client/client_packet.rs +++ b/pumpkin/src/client/client_packet.rs @@ -1,17 +1,17 @@ use crate::{ protocol::{ client::{ - config::CFinishConfig, + config::{CFinishConfig, CKnownPacks, CPluginMessage, CRegistryData, Entry}, login::{CEncryptionRequest, CLoginSuccess}, status::{CPingResponse, CStatusResponse}, }, server::{ - config::{SAcknowledgeFinishConfig, SClientInformation}, + config::{SAcknowledgeFinishConfig, SClientInformation, SKnownPacks}, handshake::SHandShake, login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart}, status::{SPingRequest, SStatusRequest}, }, - ConnectionState, + ConnectionState, KnownPack, }, server::Server, }; @@ -47,6 +47,7 @@ pub trait ClientPacketProcessor { server: &mut Server, client_information: SClientInformation, ); + fn handle_known_packs(&mut self, server: &mut Server, config_acknowledged: SKnownPacks); fn handle_config_acknowledged( &mut self, server: &mut Server, @@ -120,10 +121,19 @@ impl ClientPacketProcessor for Client { fn handle_login_acknowledged( &mut self, _server: &mut Server, - login_acknowledged: SLoginAcknowledged, + _login_acknowledged: SLoginAcknowledged, ) { - let _ = login_acknowledged; self.connection_state = ConnectionState::Config; + Server::send_brand(self); + // known data packs + self.send_packet(CKnownPacks::new( + 1, + &[KnownPack { + namespace: "minecraft".to_string(), + id: "core".to_string(), + version: "1.21".to_string(), + }], + )); dbg!("login achnowlaged"); } fn handle_client_information( @@ -141,7 +151,34 @@ impl ClientPacketProcessor for Client { text_filtering: client_information.text_filtering, server_listing: client_information.server_listing, }); + } + + fn handle_known_packs(&mut self, server: &mut Server, config_acknowledged: SKnownPacks) { + self.send_packet(CRegistryData::new( + "0".into(), + 1, + vec![ + Entry { + entry_id: "minecraft:dimension_type".into(), + has_data: true, + }, + /* Entry { + entry_id: "minecraft:worldgen/biome".into(), + has_data: true, + }, + Entry { + entry_id: "minecraft:chat_type".into(), + has_data: true, + }, + Entry { + entry_id: "minecraft:damage_type".into(), + has_data: true, + }, */ + ], + )); + // We are done with configuring + dbg!("finish config"); self.send_packet(CFinishConfig::new()); } diff --git a/pumpkin/src/client/mod.rs b/pumpkin/src/client/mod.rs index 21f1b72d3..4e928093d 100644 --- a/pumpkin/src/client/mod.rs +++ b/pumpkin/src/client/mod.rs @@ -9,7 +9,7 @@ use crate::{ protocol::{ client::{config::CConfigDisconnect, login::CLoginDisconnect}, server::{ - config::{SAcknowledgeFinishConfig, SClientInformation}, + config::{SAcknowledgeFinishConfig, SClientInformation, SKnownPacks}, handshake::SHandShake, login::{SEncryptionResponse, SLoginAcknowledged, SLoginPluginResponse, SLoginStart}, status::{SPingRequest, SStatusRequest}, @@ -168,6 +168,9 @@ impl Client { SAcknowledgeFinishConfig::PACKET_ID => { self.handle_config_acknowledged(server, SAcknowledgeFinishConfig::read(bytebuf)) } + SKnownPacks::PACKET_ID => { + self.handle_known_packs(server, SKnownPacks::read(bytebuf)) + } _ => log::error!( "Failed to handle packet id {} while in Config state", packet.id diff --git a/pumpkin/src/client/packet_decoder.rs b/pumpkin/src/client/packet_decoder.rs index 3c75198c8..4792d1495 100644 --- a/pumpkin/src/client/packet_decoder.rs +++ b/pumpkin/src/client/packet_decoder.rs @@ -4,7 +4,7 @@ use bytes::{Buf, BytesMut}; use crate::{ client::MAX_PACKET_SIZE, - protocol::{bytebuf::buffer::ByteBuffer, RawPacket, VarInt32, VarIntDecodeError}, + protocol::{bytebuf::ByteBuffer, RawPacket, VarInt32, VarIntDecodeError}, }; type Cipher = cfb8::Decryptor; @@ -56,7 +56,7 @@ impl PacketDecoder { Ok(Some(RawPacket { len: packet_len, id: packet_id, - bytebuf: ByteBuffer::from_bytes(&data), + bytebuf: ByteBuffer::new(BytesMut::from(data)), })) } diff --git a/pumpkin/src/client/packet_encoder.rs b/pumpkin/src/client/packet_encoder.rs index 74821b4e0..0fef5da51 100644 --- a/pumpkin/src/client/packet_encoder.rs +++ b/pumpkin/src/client/packet_encoder.rs @@ -6,7 +6,7 @@ use bytes::{BufMut, BytesMut}; use crate::{ client::MAX_PACKET_SIZE, - protocol::{bytebuf::buffer::ByteBuffer, ClientPacket, VarInt32}, + protocol::{bytebuf::ByteBuffer, ClientPacket, VarInt32}, }; type Cipher = cfb8::Encryptor; @@ -25,13 +25,13 @@ impl PacketEncoder { let mut writer = (&mut self.buf).writer(); - let mut packet_buf = ByteBuffer::new(); + let mut packet_buf = ByteBuffer::empty(); VarInt32(P::PACKET_ID) .encode(&mut writer) .context("failed to encode packet ID")?; packet.write(&mut packet_buf); - writer.write(packet_buf.as_bytes()).unwrap(); + writer.write(packet_buf.buf()).unwrap(); let data_len = self.buf.len() - start_len; diff --git a/pumpkin/src/network/connection.rs b/pumpkin/src/network/connection.rs deleted file mode 100644 index c6ace2882..000000000 --- a/pumpkin/src/network/connection.rs +++ /dev/null @@ -1,168 +0,0 @@ -use std::{ - io::{self, Read}, - string::FromUtf8Error, - sync::Arc, -}; - -use crossbeam_channel::{Receiver, Sender}; -use mio::{net::TcpStream, Token, Waker}; - -use crate::player::JoinInfo; - -use super::{ - protocol::{clientbound, read::MessageReader, serverbound}, - ProtocolVersion, -}; - -pub struct Connection { - stream: TcpStream, - ver: Option, - - tx: Sender, - rx: Receiver, - - token: Token, - - incoming: Vec, - outgoing: Vec, - garbage: Vec, -} - -#[derive(Debug, Clone)] -pub struct ConnSender { - tx: Sender, - wake: Sender, - waker: Arc, - tok: Token, -} - -pub struct NewConn { - pub sender: ConnSender, - pub info: JoinInfo, -} - -#[derive(Debug)] -enum ParseError { - InvalidType(i32), - CannotHandleOutput, - InvalidLength, - NotLoggedIn, - AlreadyLoggedIn, - InvalidPassword, - IO(io::Error), - InvalidMessage(FromUtf8Error), -} - -impl Connection { - fn new(stream: TcpStream, token: Token) -> Self { - // For a 10 chunk render distance, we need to send 441 packets at once. So a - // limit of 512 means we don't block very much. - let (tx, rx) = crossbeam_channel::bounded(512); - Self { - stream, - rx, - tx, - token, - incoming: Vec::with_capacity(1024), - outgoing: Vec::with_capacity(1024), - garbage: vec![0; 256 * 1024], - } - } - pub fn send(&self, p: clientbound::Packet) { - if let Ok(()) = self.tx.send(p) {} - } - - pub fn read(&mut self) -> io::Result<(bool, Option, Vec)> { - let mut out = vec![]; - loop { - let n = match self.stream.read(&mut self.garbage) { - Ok(0) => return Ok((true, None, out)), - Ok(n) => n, - Err(e) if e.kind() == io::ErrorKind::WouldBlock => return Ok((false, None, out)), - Err(e) => return Err(e), - }; - self.incoming.extend_from_slice(&self.garbage[..n]); - let (new_conn, packets) = self.read_incoming()?; - if new_conn.is_some() { - return Ok((false, new_conn, packets)); - } - out.extend(packets); - } - } - - fn read_incoming(&mut self) -> io::Result<(Option, Vec)> { - let mut out = vec![]; - while !self.incoming.is_empty() { - let mut m = MessageReader::new(&self.incoming); - match m.read_u32() { - Ok(len) => { - let len = len as usize; - if len + m.index() <= self.incoming.len() { - // Remove the length varint at the start - let idx = m.index(); - self.incoming.drain(0..idx); - // We already handshaked - if self.ver.is_some() { - let mut m = MessageReader::new(&self.incoming[..len]); - let p = serverbound::Packet::read(&mut m).map_err(|err| { - io::Error::new( - io::ErrorKind::InvalidData, - format!("while reading packet got err: {err}"), - ) - })?; - let n = m.index(); - self.incoming.drain(0..n); - if n != len { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - format!("packet did not parse enough bytes (expected {len}, only parsed {n})"), - )); - } - out.push(p); - } else { - // This is the first packet, so it must be a login packet. - let mut m = MessageReader::new(&self.incoming[..len]); - let info: JoinInfo = m.read().map_err(|e| { - io::Error::new( - io::ErrorKind::InvalidData, - format!("error reading handshake: {e}"), - ) - })?; - let n = m.index(); - self.incoming.drain(0..n); - if n != len { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - format!("handshake did not parse enough bytes (expected {len}, only parsed {n})"), - )); - } - self.ver = Some(ProtocolVersion::from(info.ver as i32)); - // We rely on the caller to set the player using this value. - return Ok(( - Some(NewConn { - sender: self.sender(), - info, - }), - out, - )); - } - } else { - break; - } - } - // If this is an EOF, then we have a partial varint, so we are done reading. - Err(e) => { - if matches!(e, ReadError::Invalid(InvalidReadError::EOF)) { - return Ok((None, out)); - } else { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - format!("error reading packet id: {e}"), - )); - } - } - } - } - Ok((None, out)) - } -} diff --git a/pumpkin/src/protocol/bytebuf/buffer.rs b/pumpkin/src/protocol/bytebuf/buffer.rs deleted file mode 100644 index 1b8d1d27b..000000000 --- a/pumpkin/src/protocol/bytebuf/buffer.rs +++ /dev/null @@ -1,877 +0,0 @@ -use crate::protocol::{nbt::nbt::NBT, VarInt, VarLong}; - -use super::{Endian, CONTINUE_BIT, SEGMENT_BITS}; -use byteorder::{BigEndian, ByteOrder, LittleEndian}; -use std::{ - fmt::Debug, - io::{Error, ErrorKind, Read, Result, Write}, -}; - -/// A byte buffer object specifically turned to easily read and write binary values -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct ByteBuffer { - data: Vec, - wpos: usize, - rpos: usize, - wbit: usize, - rbit: usize, - endian: Endian, -} - -impl From<&[u8]> for ByteBuffer { - fn from(val: &[u8]) -> Self { - ByteBuffer::from_bytes(val) - } -} - -impl From> for ByteBuffer { - fn from(val: Vec) -> Self { - ByteBuffer::from_vec(val) - } -} - -impl From for Vec { - fn from(val: ByteBuffer) -> Self { - val.into_vec() - } -} - -impl Default for ByteBuffer { - fn default() -> Self { - Self::new() - } -} - -impl Read for ByteBuffer { - fn read(&mut self, buf: &mut [u8]) -> Result { - self.flush_bits(); - let read_len = std::cmp::min(self.data.len() - self.rpos, buf.len()); - let range = self.rpos..self.rpos + read_len; - for (i, val) in self.data[range].iter().enumerate() { - buf[i] = *val; - } - self.rpos += read_len; - Ok(read_len) - } -} - -impl Write for ByteBuffer { - fn write(&mut self, buf: &[u8]) -> Result { - self.write_bytes(buf); - Ok(buf.len()) - } - - fn flush(&mut self) -> Result<()> { - Ok(()) - } -} - -impl Debug for ByteBuffer { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - let rpos = if self.rbit > 0 { - self.rpos + 1 - } else { - self.rpos - }; - - let read_len = self.data.len() - rpos; - let mut remaining_data = vec![0; read_len]; - let range = rpos..rpos + read_len; - for (i, val) in self.data[range].iter().enumerate() { - remaining_data[i] = *val; - } - - write!( - f, - "ByteBuffer {{ remaining_data: {:?}, total_data: {:?}, wpos: {:?}, rpos: {:?}, endian: {:?} }}", - remaining_data, self.data, self.wpos, self.rpos, self.endian - ) - } -} - -macro_rules! read_number { - ($self:ident, $name:ident, $offset:expr) => {{ - $self.flush_bits(); - if $self.rpos + $offset > $self.data.len() { - return Err(Error::new( - ErrorKind::UnexpectedEof, - "could not read enough bits from buffer", - )); - } - let range = $self.rpos..$self.rpos + $offset; - $self.rpos += $offset; - - Ok(match $self.endian { - Endian::BigEndian => BigEndian::$name(&$self.data[range]), - Endian::LittleEndian => LittleEndian::$name(&$self.data[range]), - }) - }}; -} - -impl ByteBuffer { - /// Construct a new, empty, ByteBuffer - pub fn new() -> ByteBuffer { - ByteBuffer { - data: vec![], - wpos: 0, - rpos: 0, - rbit: 0, - wbit: 0, - endian: Endian::BigEndian, - } - } - - /// Construct a new ByteBuffer filled with the data array. - pub fn from_bytes(bytes: &[u8]) -> ByteBuffer { - let mut buffer = ByteBuffer::new(); - buffer.write_bytes(bytes); - buffer - } - - /// Constructs a new ByteBuffer from an existing vector. This - /// function takes ownership of the vector - pub fn from_vec(vec: Vec) -> ByteBuffer { - let len = vec.len(); - ByteBuffer { - data: vec, - wpos: len, - rpos: 0, - rbit: 0, - wbit: 0, - endian: Endian::BigEndian, - } - } - - /// Return the buffer size - pub fn len(&self) -> usize { - self.data.len() - } - - pub fn is_empty(&self) -> bool { - self.data.is_empty() - } - - /// Clear the buffer and reinitialize the reading and writing cursors - pub fn clear(&mut self) { - self.data.clear(); - self.reset_cursors(); - self.reset_bits_cursors(); - } - - /// Reinitialize the reading and writing cursor - pub fn reset_cursors(&mut self) { - self.wpos = 0; - self.rpos = 0; - } - - /// Reinitialize the bit reading and bit writing cursor - pub fn reset_bits_cursors(&mut self) { - self.rbit = 0; - self.wbit = 0; - } - - /// Change the buffer size to size. - /// - /// _Note_: You cannot shrink a buffer with this method - pub fn resize(&mut self, size: usize) { - let diff = size - self.data.len(); - if diff > 0 { - self.data.extend(std::iter::repeat(0).take(diff)) - } - } - - /// Set the byte order of the buffer - /// - /// _Note_: By default the buffer uses big endian order - pub fn set_endian(&mut self, endian: Endian) { - self.endian = endian; - } - - /// Returns the current byte order of the buffer - pub fn endian(&self) -> Endian { - self.endian - } - - // Write operations - - /// Append a byte array to the buffer. The buffer is automatically extended if needed - /// _Note_: This method resets the read and write cursor for bitwise reading. - /// - /// #Example - /// - /// ``` - /// # use bytebuffer::*; - /// let mut buffer = ByteBuffer::new(); - /// buffer.write_bytes(&vec![0x1, 0xFF, 0x45]); // buffer contains [0x1, 0xFF, 0x45] - /// ``` - pub fn write_bytes(&mut self, bytes: &[u8]) { - self.flush_bits(); - - let size = bytes.len() + self.wpos; - - if size > self.data.len() { - self.resize(size); - } - - for v in bytes { - self.data[self.wpos] = *v; - self.wpos += 1; - } - } - - pub fn write_bool(&mut self, v: bool) { - if v { - self.write_u8(1); - } else { - self.write_u8(0); - } - } - - pub fn write_bytes_len(&mut self, bytes: &[u8], max_len: usize) { - self.flush_bits(); - - let size = bytes.len() + self.wpos; - if size > max_len { - eprintln!("Write: size > max size"); - return; - } - - if size > self.data.len() { - self.resize(size); - } - - for v in bytes { - self.data[self.wpos] = *v; - self.wpos += 1; - } - } - - /// Append a byte (8 bits value) to the buffer - /// _Note_: This method resets the read and write cursor for bitwise reading. - /// - /// #Example - /// - /// ``` - /// # use bytebuffer::*; - /// let mut buffer = ByteBuffer::new(); - /// buffer.write_u8(1) // buffer contains [0x1] - /// ``` - pub fn write_u8(&mut self, val: u8) { - self.write_bytes(&[val]); - } - - /// Same as `write_u8()` but for signed values - /// _Note_: This method resets the read and write cursor for bitwise reading. - pub fn write_i8(&mut self, val: i8) { - self.write_u8(val as u8); - } - - /// Append a word (16 bits value) to the buffer - /// _Note_: This method resets the read and write cursor for bitwise reading. - /// - /// #Example - /// - /// ``` - /// # use bytebuffer::*; - /// let mut buffer = ByteBuffer::new(); - /// buffer.write_u16(1) // buffer contains [0x00, 0x1] if little endian - /// ``` - pub fn write_u16(&mut self, val: u16) { - let mut buf = [0; 2]; - - match self.endian { - Endian::BigEndian => BigEndian::write_u16(&mut buf, val), - Endian::LittleEndian => LittleEndian::write_u16(&mut buf, val), - }; - - self.write_bytes(&buf); - } - - /// Same as `write_u16()` but for signed values - /// _Note_: This method resets the read and write cursor for bitwise reading. - pub fn write_i16(&mut self, val: i16) { - self.write_u16(val as u16); - } - - /// Append a double word (32 bits value) to the buffer - /// _Note_: This method resets the read and write cursor for bitwise reading. - /// - /// #Example - /// - /// ``` - /// # use bytebuffer::*; - /// let mut buffer = ByteBuffer::new(); - /// buffer.write_u32(1) // buffer contains [0x00, 0x00, 0x00, 0x1] if little endian - /// ``` - pub fn write_u32(&mut self, val: u32) { - let mut buf = [0; 4]; - - match self.endian { - Endian::BigEndian => BigEndian::write_u32(&mut buf, val), - Endian::LittleEndian => LittleEndian::write_u32(&mut buf, val), - }; - - self.write_bytes(&buf); - } - - /// Same as `write_u32()` but for signed values - /// _Note_: This method resets the read and write cursor for bitwise reading. - pub fn write_i32(&mut self, val: i32) { - self.write_u32(val as u32); - } - - pub fn write_var_int(&mut self, value: VarInt) { - let mut val = value as u32; - for _ in 0..5 { - let mut b: u8 = val as u8 & 0b01111111; - val >>= 7; - if val != 0 { - b |= 0b10000000; - } - self.write_u8(b); - if val == 0 { - break; - } - } - } - - /// Append a quaddruple word (64 bits value) to the buffer - /// _Note_: This method resets the read and write cursor for bitwise reading. - /// - /// #Example - /// - /// ``` - /// # use bytebuffer::*; - /// let mut buffer = ByteBuffer::new(); - /// buffer.write_u64(1) // buffer contains [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1] if little endian - /// ``` - pub fn write_u64(&mut self, val: u64) { - let mut buf = [0; 8]; - match self.endian { - Endian::BigEndian => BigEndian::write_u64(&mut buf, val), - Endian::LittleEndian => LittleEndian::write_u64(&mut buf, val), - }; - - self.write_bytes(&buf); - } - - /// Same as `write_u64()` but for signed values - /// _Note_: This method resets the read and write cursor for bitwise reading. - pub fn write_i64(&mut self, val: i64) { - self.write_u64(val as u64); - } - - /// Append a 32 bits floating point number to the buffer. - /// _Note_: This method resets the read and write cursor for bitwise reading. - /// - /// #Example - /// - /// ``` - /// # use bytebuffer::*; - /// let mut buffer = ByteBuffer::new(); - /// buffer.write_f32(0.1) - /// ``` - pub fn write_f32(&mut self, val: f32) { - let mut buf = [0; 4]; - - match self.endian { - Endian::BigEndian => BigEndian::write_f32(&mut buf, val), - Endian::LittleEndian => LittleEndian::write_f32(&mut buf, val), - }; - - self.write_bytes(&buf); - } - - /// Append a 64 bits floating point number to the buffer. - /// _Note_: This method resets the read and write cursor for bitwise reading. - /// - /// #Example - /// - /// ``` - /// # use bytebuffer::*; - /// let mut buffer = ByteBuffer::new(); - /// buffer.write_f64(0.1) - /// ``` - pub fn write_f64(&mut self, val: f64) { - let mut buf = [0; 8]; - - match self.endian { - Endian::BigEndian => BigEndian::write_f64(&mut buf, val), - Endian::LittleEndian => LittleEndian::write_f64(&mut buf, val), - }; - self.write_bytes(&buf); - } - - /// Append a string to the buffer. - /// _Note_: This method resets the read and write cursor for bitwise reading. - /// - /// *Format* The format is `(u32)size + size * (u8)characters` - /// - /// #Example - /// - /// ``` - /// # use bytebuffer::*; - /// let mut buffer = ByteBuffer::new(); - /// buffer.write_string("Hello") - /// ``` - pub fn write_string(&mut self, val: &str) { - self.write_string_len(val, 32767) - } - - pub fn write_string_len(&mut self, val: &str, max_len: usize) { - self.write_var_int(val.len() as VarInt); - self.write_bytes_len(val.as_bytes(), max_len); - } - - pub fn write_string_array(&mut self, array: &[String]) { - for string in array { - self.write_string(string) - } - } - - // Read operations - - /// Read a defined amount of raw bytes, or return an IO error if not enough bytes are - /// available. - /// _Note_: This method resets the read and write cursor for bitwise reading. - pub fn read_bytes(&mut self, size: usize) -> Result> { - self.flush_bits(); - if self.rpos + size > self.data.len() { - return Err(Error::new( - ErrorKind::UnexpectedEof, - "could not read enough bytes from buffer", - )); - } - let range = self.rpos..self.rpos + size; - let mut res = Vec::::new(); - res.write_all(&self.data[range])?; - self.rpos += size; - Ok(res) - } - - /// Read one byte, or return an IO error if not enough bytes are available. - /// _Note_: This method resets the read and write cursor for bitwise reading. - /// - /// #Example - /// - /// ``` - /// # use bytebuffer::*; - /// let mut buffer = ByteBuffer::from_bytes(&vec![0x1]); - /// let value = buffer.read_u8().unwrap(); //Value contains 1 - /// ``` - pub fn read_u8(&mut self) -> Result { - self.flush_bits(); - if self.rpos >= self.data.len() { - return Err(Error::new( - ErrorKind::UnexpectedEof, - "could not read enough bits from buffer", - )); - } - let pos = self.rpos; - self.rpos += 1; - Ok(self.data[pos]) - } - - pub fn read_bool(&mut self) -> Result { - Ok(self.read_u8()? != 0) - } - - /// Same as `read_u8()` but for signed values - pub fn read_i8(&mut self) -> Result { - Ok(self.read_u8()? as i8) - } - - /// Read a 2-bytes long value, or return an IO error if not enough bytes are available. - /// _Note_: This method resets the read and write cursor for bitwise reading. - /// - /// #Example - /// - /// ``` - /// # use bytebuffer::*; - /// let mut buffer = ByteBuffer::from_bytes(&vec![0x0, 0x1]); - /// let value = buffer.read_u16().unwrap(); //Value contains 1 - /// ``` - pub fn read_u16(&mut self) -> Result { - read_number!(self, read_u16, 2) - } - - /// Same as `read_u16()` but for signed values - /// _Note_: This method resets the read and write cursor for bitwise reading. - pub fn read_i16(&mut self) -> Result { - Ok(self.read_u16()? as i16) - } - - /// Read a four-bytes long value, or return an IO error if not enough bytes are available. - /// _Note_: This method resets the read and write cursor for bitwise reading. - /// - /// #Example - /// - /// ``` - /// # use bytebuffer::*; - /// let mut buffer = ByteBuffer::from_bytes(&vec![0x0, 0x0, 0x0, 0x1]); - /// let value = buffer.read_u32().unwrap(); // Value contains 1 - /// ``` - pub fn read_u32(&mut self) -> Result { - read_number!(self, read_u32, 4) - } - - /// Same as `read_u32()` but for signed values - /// _Note_: This method resets the read and write cursor for bitwise reading. - pub fn read_i32(&mut self) -> Result { - Ok(self.read_u32()? as i32) - } - - /// Read an eight bytes long value, or return an IO error if not enough bytes are available. - /// _Note_: This method resets the read and write cursor for bitwise reading. - /// - /// #Example - /// - /// ``` - /// # use bytebuffer::*; - /// let mut buffer = ByteBuffer::from_bytes(&vec![0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1]); - /// let value = buffer.read_u64().unwrap(); //Value contains 1 - /// ``` - pub fn read_u64(&mut self) -> Result { - read_number!(self, read_u64, 8) - } - - /// Reads a boolean. If true, the closure is called, and the returned value is - /// wrapped in Some. Otherwise, this returns None. - pub fn read_option(&mut self, val: impl FnOnce(&mut ByteBuffer) -> T) -> Result> { - if self.read_bool()? { - Ok(Some(val(self))) - } else { - Ok(None) - } - } - /// Writes `true` if the option is Some, or `false` if None. If the option is - /// some, then it also calls the `write` closure. - pub fn write_option(&mut self, val: &Option, write: impl FnOnce(&mut ByteBuffer, &T)) { - self.write_bool(val.is_some()); - match val { - Some(v) => write(self, v), - None => {} - } - } - - pub fn read_var_int(&mut self) -> Result { - let mut value: i32 = 0; - let mut position: i32 = 0; - - loop { - let read = self.read_u8()?; - - value |= ((read & SEGMENT_BITS) as i32) << position; - - if read & CONTINUE_BIT == 0 { - break; - } - - position += 7; - - if position >= 32 { - return Err(Error::new(ErrorKind::InvalidData, "VarInt is too big")); - } - } - - Ok(value) - } - - pub fn read_var_long(&mut self) -> Result { - let mut value: i64 = 0; - let mut position: i64 = 0; - - loop { - let read = self.read_u8()?; - - value |= ((read & SEGMENT_BITS) as i64) << position; - - if read & CONTINUE_BIT == 0 { - break; - } - - position += 7; - - if position >= 64 { - return Err(Error::new(ErrorKind::InvalidData, "VarLong is too big")); - } - } - - Ok(value) - } - - /// Same as `read_u64()` but for signed values - /// _Note_: This method resets the read and write cursor for bitwise reading. - pub fn read_i64(&mut self) -> Result { - Ok(self.read_u64()? as i64) - } - - /// Read a 32 bits floating point value, or return an IO error if not enough bytes are available. - /// _Note_: This method resets the read and write cursor for bitwise reading. - pub fn read_f32(&mut self) -> Result { - read_number!(self, read_f32, 4) - } - - /// Read a 64 bits floating point value, or return an IO error if not enough bytes are available. - /// _Note_: This method resets the read and write cursor for bitwise reading. - pub fn read_f64(&mut self) -> Result { - read_number!(self, read_f64, 8) - } - - pub fn read_list(&mut self, val: impl Fn(&mut ByteBuffer) -> Result) -> Result> { - let len = self.read_var_int()?.try_into().unwrap(); - let mut list = Vec::with_capacity(len); - for _ in 0..len { - list.push(val(self)?); - } - Ok(list) - } - /// Writes a list to the buffer. - pub fn write_list(&mut self, list: &[T], write: impl Fn(&mut ByteBuffer, &T)) { - self.write_var_int(list.len().try_into().unwrap()); - for v in list { - write(self, v); - } - } - - pub fn read_varint_arr(&mut self) -> Result> { - self.read_list(|buf| buf.read_var_int()) - } - pub fn write_varint_arr(&mut self, v: &[i32]) { - self.write_list(v, |p, &v| p.write_var_int(v)) - } - - pub fn read_nbt(&mut self) -> Result { - match NBT::deserialize_buf(self) { - Ok(v) => Ok(v), - Err(err) => { - return Err(Error::new(ErrorKind::InvalidData, "Failed read nbt")); - } - } - } - - /// Read a string. - /// - /// _Note_: First it reads a 32 bits value representing the size, then 'size' raw bytes - /// that must be encoded as UTF8. - /// _Note_: This method resets the read and write cursor for bitwise reading. - pub fn read_string(&mut self) -> Result { - self.read_string_len(32767) - } - - pub fn read_string_len(&mut self, max_size: usize) -> Result { - let size = self.read_var_int()?; - if size as usize > max_size { - return Err(Error::new( - ErrorKind::InvalidData, - "String length is bigger than max size", - )); - } - let data = self.read_bytes(size as usize)?; - if data.len() > max_size { - return Err(Error::new( - ErrorKind::InvalidData, - "String is bigger than max size", - )); - } - match String::from_utf8(data) { - Ok(string_result) => Ok(string_result), - Err(e) => Err(Error::new(ErrorKind::InvalidData, e)), - } - } - - /// Reads 16 bytes from the buffer, and returns that as a big endian UUID. - pub fn read_uuid(&mut self) -> Result { - let mut bytes = [0u8; 16]; - self.read_exact(&mut bytes)?; - uuid::Uuid::from_slice(&bytes).map_err(|e| Error::new(ErrorKind::InvalidData, e)) - } - - /// This writes a UUID into the buffer (in big endian format). - pub fn write_uuid(&mut self, v: uuid::Uuid) { - self.write_bytes(v.as_bytes()); - } - - // Other - - /// Dump the byte buffer to a string. - pub fn to_hex_dump(&self) -> String { - let mut str = String::new(); - for b in &self.data { - str = str + &format!("0x{:01$x} ", b, 2); - } - str.pop(); - str - } - - /// Return the position of the reading cursor - pub fn get_rpos(&self) -> usize { - self.rpos - } - - /// Set the reading cursor position. - /// _Note_: Sets the reading cursor to `min(newPosition, self.len())` to prevent overflow - pub fn set_rpos(&mut self, rpos: usize) { - self.rpos = std::cmp::min(rpos, self.data.len()); - } - - /// Return the writing cursor position - pub fn get_wpos(&self) -> usize { - self.wpos - } - - /// Set the writing cursor position. - /// _Note_: Sets the writing cursor to `min(newPosition, self.len())` to prevent overflow - pub fn set_wpos(&mut self, wpos: usize) { - self.wpos = std::cmp::min(wpos, self.data.len()); - } - - /// Return the raw byte buffer bytes. - pub fn as_bytes(&self) -> &[u8] { - &self.data - } - - /// Return the raw byte buffer as a Vec. - #[deprecated( - since = "2.1.0", - note = "use `as_bytes().to_vec()` or `into_vec()` instead" - )] - pub fn into_bytes(&self) -> Vec { - self.data.to_vec() - } - - /// Return the raw byte buffer as a Vec. - pub fn into_vec(self) -> Vec { - self.data - } - - //Bit manipulation functions - - /// Read 1 bit. Return true if the bit is set to 1, otherwhise, return false. - /// - /// _Note_: Bits are read from left to right - /// - /// #Example - /// - /// ``` - /// # use bytebuffer::*; - /// let mut buffer = ByteBuffer::from_bytes(&vec![128]); // 10000000b - /// let value1 = buffer.read_bit().unwrap(); //value1 contains true (eg: bit is 1) - /// let value2 = buffer.read_bit().unwrap(); //value2 contains false (eg: bit is 0) - /// ``` - pub fn read_bit(&mut self) -> Result { - if self.rpos >= self.data.len() { - return Err(Error::new( - ErrorKind::UnexpectedEof, - "could not read enough bits from buffer", - )); - } - let bit = self.data[self.rpos] & (1 << (7 - self.rbit)) != 0; - self.rbit += 1; - if self.rbit > 7 { - self.flush_rbits(); - } - Ok(bit) - } - - /// Read n bits. an return the corresponding value an u64. - /// - /// _Note_: We cannot read more than 64 bits - /// - /// _Note_: Bits are read from left to right - /// - /// #Example - /// - /// ``` - /// # use bytebuffer::*; - /// let mut buffer = ByteBuffer::from_bytes(&vec![128]); // 10000000b - /// let value = buffer.read_bits(3).unwrap(); // value contains 4 (eg: 100b) - /// ``` - pub fn read_bits(&mut self, n: u8) -> Result { - if n > 64 { - return Err(Error::new( - ErrorKind::InvalidInput, - "cannot read more than 64 bits", - )); - } - - if n == 0 { - Ok(0) - } else { - Ok((u64::from(self.read_bit()?) << (n - 1)) | self.read_bits(n - 1)?) - } - } - - /// Discard all the pending bits available for reading or writing and place the corresponding cursor to the next byte. - /// - /// _Note_: If no bits are currently read or written, this function does nothing. - /// - /// #Example - /// - /// ```text - /// 10010010 | 00000001 - /// ^ - /// 10010010 | 00000001 // read_bit called - /// ^ - /// 10010010 | 00000001 // flush_bit() called - /// ^ - /// ``` - pub fn flush_bits(&mut self) { - if self.rbit > 0 { - self.flush_rbits(); - } - if self.wbit > 0 { - self.flush_wbits(); - } - } - - fn flush_rbits(&mut self) { - self.rpos += 1; - self.rbit = 0 - } - - fn flush_wbits(&mut self) { - self.wpos += 1; - self.wbit = 0 - } - - /// Append 1 bit value to the buffer. - /// The bit is appended like this : - /// - /// ```text - /// ...| XXXXXXXX | 10000000 |.... - /// ``` - pub fn write_bit(&mut self, bit: bool) { - let size = self.wpos + 1; - if size > self.data.len() { - self.resize(size); - } - - if bit { - self.data[self.wpos] |= 1 << (7 - self.wbit); - } - - self.wbit += 1; - - if self.wbit > 7 { - self.wbit = 0; - self.wpos += 1; - } - } - - /// Write the given value as a sequence of n bits - /// - /// #Example - /// - /// ``` - /// # use bytebuffer::*; - /// let mut buffer = ByteBuffer::new(); - /// buffer.write_bits(4, 3); // append 100b - /// ``` - pub fn write_bits(&mut self, value: u64, n: u8) { - if n > 0 { - self.write_bit((value >> (n - 1)) & 1 != 0); - self.write_bits(value, n - 1); - } - } -} diff --git a/pumpkin/src/protocol/bytebuf/mod.rs b/pumpkin/src/protocol/bytebuf/mod.rs index 93f65a020..e391070f8 100644 --- a/pumpkin/src/protocol/bytebuf/mod.rs +++ b/pumpkin/src/protocol/bytebuf/mod.rs @@ -1,11 +1,279 @@ -pub mod buffer; -pub mod reader; +use core::str; +use std::io::{self, Error, ErrorKind, Read}; + +use bytes::{Buf, BufMut, BytesMut}; + +use crate::protocol::{VarInt, VarLong}; const SEGMENT_BITS: u8 = 0x7F; const CONTINUE_BIT: u8 = 0x80; -/// An enum to represent the byte order of the ByteBuffer object -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum Endian { - BigEndian, - LittleEndian, + +pub struct ByteBuffer { + buffer: BytesMut, +} + +impl ByteBuffer { + pub fn empty() -> Self { + Self { + buffer: BytesMut::new(), + } + } + pub fn new(buffer: BytesMut) -> Self { + Self { buffer } + } + + pub fn get_var_int(&mut self) -> VarInt { + let mut value: i32 = 0; + let mut position: i32 = 0; + + loop { + let read = self.buffer.get_u8(); + + value |= ((read & SEGMENT_BITS) as i32) << position; + + if read & CONTINUE_BIT == 0 { + break; + } + + position += 7; + + if position >= 32 { + panic!("VarInt is too big"); + } + } + + value + } + + pub fn get_var_long(&mut self) -> VarLong { + let mut value: i64 = 0; + let mut position: i64 = 0; + + loop { + let read = self.buffer.get_u8(); + + value |= ((read & SEGMENT_BITS) as i64) << position; + + if read & CONTINUE_BIT == 0 { + break; + } + + position += 7; + + if position >= 64 { + panic!("VarInt is too big"); + } + } + + value + } + + pub fn get_string(&mut self) -> Result { + self.get_string_len(32767) + } + + pub fn get_string_len(&mut self, max_size: usize) -> Result { + let size = self.get_var_int(); + if size as usize > max_size { + return Err(Error::new( + ErrorKind::InvalidData, + "String length is bigger than max size", + )); + } + let data = self.buffer.copy_to_bytes(size as usize); + if data.len() > max_size { + return Err(Error::new( + ErrorKind::InvalidData, + "String is bigger than max size", + )); + } + match str::from_utf8(&data) { + Ok(string_result) => Ok(string_result.to_string()), + Err(e) => Err(Error::new(ErrorKind::InvalidData, e)), + } + } + + pub fn get_bool(&mut self) -> bool { + self.buffer.get_u8() != 0 + } + + pub fn get_uuid(&mut self) -> uuid::Uuid { + let mut bytes = [0u8; 16]; + self.buffer.copy_to_slice(&mut bytes); + uuid::Uuid::from_slice(&bytes).expect("Failed to parse UUID") + } + + pub fn put_bool(&mut self, v: bool) { + if v { + self.buffer.put_u8(1); + } else { + self.buffer.put_u8(0); + } + } + + pub fn put_uuid(&mut self, v: uuid::Uuid) { + self.buffer.put_slice(v.as_bytes()); + } + + pub fn put_string(&mut self, val: &str) { + self.put_var_int(val.len() as VarInt); + self.buffer.put(val.as_bytes()); + } + + pub fn put_string_array(&mut self, array: &[String]) { + for string in array { + self.put_string(string) + } + } + + pub fn put_var_int(&mut self, value: VarInt) { + let mut val = value as u32; + for _ in 0..5 { + let mut b: u8 = val as u8 & 0b01111111; + val >>= 7; + if val != 0 { + b |= 0b10000000; + } + self.buffer.put_u8(b); + if val == 0 { + break; + } + } + } + + /// Reads a boolean. If true, the closure is called, and the returned value is + /// wrapped in Some. Otherwise, this returns None. + pub fn get_option(&mut self, val: impl FnOnce(&mut Self) -> T) -> Option { + if self.get_bool() { + Some(val(self)) + } else { + None + } + } + /// Writes `true` if the option is Some, or `false` if None. If the option is + /// some, then it also calls the `write` closure. + pub fn put_option(&mut self, val: &Option, write: impl FnOnce(&mut Self, &T)) { + self.put_bool(val.is_some()); + match val { + Some(v) => write(self, v), + None => {} + } + } + + pub fn get_list(&mut self, val: impl Fn(&mut Self) -> T) -> Vec { + let len = self.get_var_int().try_into().unwrap(); + let mut list = Vec::with_capacity(len); + for _ in 0..len { + list.push(val(self)); + } + list + } + /// Writes a list to the buffer. + pub fn put_list(&mut self, list: &[T], write: impl Fn(&mut Self, &T)) { + self.put_var_int(list.len().try_into().unwrap()); + for v in list { + write(self, v); + } + } + + pub fn put_varint_arr(&mut self, v: &[i32]) { + self.put_list(v, |p, &v| p.put_var_int(v)) + } + + pub fn get_nbt(&mut self) -> Option { + match crab_nbt::NbtTag::deserialize(self.buf()) { + Ok(v) => Some(v), + Err(err) => None, + } + } + + pub fn buf(&mut self) -> &mut BytesMut { + &mut self.buffer + } +} + +// trait +impl ByteBuffer { + pub fn get_u8(&mut self) -> u8 { + self.buffer.get_u8() + } + + pub fn get_i8(&mut self) -> i8 { + self.buffer.get_i8() + } + + pub fn get_u16(&mut self) -> u16 { + self.buffer.get_u16() + } + + pub fn get_i16(&mut self) -> i16 { + self.buffer.get_i16() + } + + pub fn get_u32(&mut self) -> u32 { + self.buffer.get_u32() + } + + pub fn get_i32(&mut self) -> i32 { + self.buffer.get_i32() + } + + pub fn get_u64(&mut self) -> u64 { + self.buffer.get_u64() + } + + pub fn get_i64(&mut self) -> i64 { + self.buffer.get_i64() + } + + pub fn get_f32(&mut self) -> f32 { + self.buffer.get_f32() + } + + pub fn get_f64(&mut self) -> f64 { + self.buffer.get_f64() + } + + pub fn put_u8(&mut self, n: u8) { + self.buffer.put_u8(n) + } + + pub fn put_i8(&mut self, n: i8) { + self.buffer.put_i8(n) + } + + pub fn put_u16(&mut self, n: u16) { + self.buffer.put_u16(n) + } + + pub fn put_i16(&mut self, n: i16) { + self.buffer.put_i16(n) + } + + pub fn put_u32(&mut self, n: u32) { + self.buffer.put_u32(n) + } + + pub fn put_i32(&mut self, n: i32) { + self.buffer.put_i32(n) + } + + pub fn put_u64(&mut self, n: u64) { + self.buffer.put_u64(n) + } + + pub fn put_i64(&mut self, n: i64) { + self.buffer.put_i64(n) + } + + pub fn put_f32(&mut self, n: f32) { + self.buffer.put_f32(n) + } + + pub fn copy_to_bytes(&mut self, len: usize) -> bytes::Bytes { + self.buffer.copy_to_bytes(len) + } + pub fn put_slice(&mut self, src: &[u8]) { + self.buffer.put_slice(src) + } } diff --git a/pumpkin/src/protocol/bytebuf/reader.rs b/pumpkin/src/protocol/bytebuf/reader.rs deleted file mode 100644 index 461df7a39..000000000 --- a/pumpkin/src/protocol/bytebuf/reader.rs +++ /dev/null @@ -1,368 +0,0 @@ -use super::Endian; -use byteorder::{BigEndian, ByteOrder, LittleEndian}; -use std::{ - fmt::Debug, - io::{Error, ErrorKind, Read, Result, Write}, -}; - -/// A byte buffer object specifically turned to easily read and write binary values -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct ByteReader<'a> { - data: &'a [u8], - rpos: usize, - rbit: usize, - endian: Endian, -} - -impl<'a> From<&'a [u8]> for ByteReader<'a> { - fn from(val: &'a [u8]) -> Self { - ByteReader::from_bytes(val) - } -} - -impl<'a> Read for ByteReader<'a> { - fn read(&mut self, buf: &mut [u8]) -> Result { - self.flush_bits(); - let read_len = std::cmp::min(self.data.len() - self.rpos, buf.len()); - let range = self.rpos..self.rpos + read_len; - for (i, val) in self.data[range].iter().enumerate() { - buf[i] = *val; - } - self.rpos += read_len; - Ok(read_len) - } -} - -impl<'a> Debug for ByteReader<'a> { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - let rpos = if self.rbit > 0 { - self.rpos + 1 - } else { - self.rpos - }; - - let read_len = self.data.len() - rpos; - let mut remaining_data = vec![0; read_len]; - let range = rpos..rpos + read_len; - for (i, val) in self.data[range].iter().enumerate() { - remaining_data[i] = *val; - } - - write!( - f, - "ByteReader {{ remaining_data: {:?}, total_data: {:?}, rpos: {:?}, endian: {:?} }}", - remaining_data, self.data, self.rpos, self.endian - ) - } -} - -macro_rules! read_number { - ($self:ident, $name:ident, $offset:expr) => {{ - $self.flush_bits(); - if $self.rpos + $offset > $self.data.len() { - return Err(Error::new( - ErrorKind::UnexpectedEof, - "could not read enough bits from buffer", - )); - } - let range = $self.rpos..$self.rpos + $offset; - $self.rpos += $offset; - - Ok(match $self.endian { - Endian::BigEndian => BigEndian::$name(&$self.data[range]), - Endian::LittleEndian => LittleEndian::$name(&$self.data[range]), - }) - }}; -} - -impl<'a> ByteReader<'a> { - /// Construct a new ByteReader filled with the data array. - pub fn from_bytes(bytes: &[u8]) -> ByteReader { - ByteReader { - data: bytes, - rpos: 0, - rbit: 0, - endian: Endian::BigEndian, - } - } - - /// Return the buffer size - pub fn len(&self) -> usize { - self.data.len() - } - - pub fn is_empty(&self) -> bool { - self.data.is_empty() - } - - /// Reinitialize the reading cursor - pub fn reset_cursors(&mut self) { - self.rpos = 0; - } - - /// Reinitialize the bit reading cursor - pub fn reset_bits_cursors(&mut self) { - self.rbit = 0; - } - - /// Set the byte order of the buffer - /// - /// _Note_: By default the buffer uses big endian order - pub fn set_endian(&mut self, endian: Endian) { - self.endian = endian; - } - - /// Returns the current byte order of the buffer - pub fn endian(&self) -> Endian { - self.endian - } - - // Read operations - - /// Read a defined amount of raw bytes, or return an IO error if not enough bytes are - /// available. - /// _Note_: This method resets the read and write cursor for bitwise reading. - pub fn read_bytes(&mut self, size: usize) -> Result> { - self.flush_bits(); - if self.rpos + size > self.data.len() { - return Err(Error::new( - ErrorKind::UnexpectedEof, - "could not read enough bytes from buffer", - )); - } - let range = self.rpos..self.rpos + size; - let mut res = Vec::::new(); - res.write_all(&self.data[range])?; - self.rpos += size; - Ok(res) - } - - /// Read one byte, or return an IO error if not enough bytes are available. - /// _Note_: This method resets the read and write cursor for bitwise reading. - /// - /// #Example - /// - /// ``` - /// # use bytebuffer::*; - /// let data = vec![0x1]; - /// let mut buffer = ByteReader::from_bytes(&data); - /// let value = buffer.read_u8().unwrap(); //Value contains 1 - /// ``` - pub fn read_u8(&mut self) -> Result { - self.flush_bits(); - if self.rpos >= self.data.len() { - return Err(Error::new( - ErrorKind::UnexpectedEof, - "could not read enough bits from buffer", - )); - } - let pos = self.rpos; - self.rpos += 1; - Ok(self.data[pos]) - } - - /// Same as `read_u8()` but for signed values - pub fn read_i8(&mut self) -> Result { - Ok(self.read_u8()? as i8) - } - - /// Read a 2-bytes long value, or return an IO error if not enough bytes are available. - /// _Note_: This method resets the read and write cursor for bitwise reading. - /// - /// #Example - /// - /// ``` - /// # use bytebuffer::*; - /// let data = vec![0x0, 0x1]; - /// let mut buffer = ByteReader::from_bytes(&data); - /// let value = buffer.read_u16().unwrap(); //Value contains 1 - /// ``` - pub fn read_u16(&mut self) -> Result { - read_number!(self, read_u16, 2) - } - - /// Same as `read_u16()` but for signed values - /// _Note_: This method resets the read and write cursor for bitwise reading. - pub fn read_i16(&mut self) -> Result { - Ok(self.read_u16()? as i16) - } - - /// Read a four-bytes long value, or return an IO error if not enough bytes are available. - /// _Note_: This method resets the read and write cursor for bitwise reading. - /// - /// #Example - /// - /// ``` - /// # use bytebuffer::*; - /// let data = vec![0x0, 0x0, 0x0, 0x1]; - /// let mut buffer = ByteReader::from_bytes(&data); - /// let value = buffer.read_u32().unwrap(); // Value contains 1 - /// ``` - pub fn read_u32(&mut self) -> Result { - read_number!(self, read_u32, 4) - } - - /// Same as `read_u32()` but for signed values - /// _Note_: This method resets the read and write cursor for bitwise reading. - pub fn read_i32(&mut self) -> Result { - Ok(self.read_u32()? as i32) - } - - /// Read an eight bytes long value, or return an IO error if not enough bytes are available. - /// _Note_: This method resets the read and write cursor for bitwise reading. - /// - /// #Example - /// - /// ``` - /// # use bytebuffer::*; - /// let data = vec![0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1]; - /// let mut buffer = ByteReader::from_bytes(&data); - /// let value = buffer.read_u64().unwrap(); //Value contains 1 - /// ``` - pub fn read_u64(&mut self) -> Result { - read_number!(self, read_u64, 8) - } - - /// Same as `read_u64()` but for signed values - /// _Note_: This method resets the read and write cursor for bitwise reading. - pub fn read_i64(&mut self) -> Result { - Ok(self.read_u64()? as i64) - } - - /// Read a 32 bits floating point value, or return an IO error if not enough bytes are available. - /// _Note_: This method resets the read and write cursor for bitwise reading. - pub fn read_f32(&mut self) -> Result { - read_number!(self, read_f32, 4) - } - - /// Read a 64 bits floating point value, or return an IO error if not enough bytes are available. - /// _Note_: This method resets the read and write cursor for bitwise reading. - pub fn read_f64(&mut self) -> Result { - read_number!(self, read_f64, 8) - } - - /// Read a string. - /// - /// _Note_: First it reads a 32 bits value representing the size, then 'size' raw bytes - /// that must be encoded as UTF8. - /// _Note_: This method resets the read and write cursor for bitwise reading. - pub fn read_string(&mut self) -> Result { - let size = self.read_u32()?; - match String::from_utf8(self.read_bytes(size as usize)?) { - Ok(string_result) => Ok(string_result), - Err(e) => Err(Error::new(ErrorKind::InvalidData, e)), - } - } - - // Other - - /// Dump the byte buffer to a string. - pub fn to_hex_dump(&self) -> String { - let mut str = String::new(); - for b in self.data { - str = str + &format!("0x{:01$x} ", b, 2); - } - str.pop(); - str - } - - /// Return the position of the reading cursor - pub fn get_rpos(&self) -> usize { - self.rpos - } - - /// Set the reading cursor position. - /// _Note_: Sets the reading cursor to `min(newPosition, self.len())` to prevent overflow - pub fn set_rpos(&mut self, rpos: usize) { - self.rpos = std::cmp::min(rpos, self.data.len()); - } - - /// Return the raw byte buffer bytes. - pub fn as_bytes(&self) -> &[u8] { - self.data - } - - //Bit manipulation functions - - /// Read 1 bit. Return true if the bit is set to 1, otherwhise, return false. - /// - /// _Note_: Bits are read from left to right - /// - /// #Example - /// - /// ``` - /// # use bytebuffer::*; - /// let data = vec![128]; - /// let mut buffer = ByteReader::from_bytes(&data); // 10000000b - /// let value1 = buffer.read_bit().unwrap(); //value1 contains true (eg: bit is 1) - /// let value2 = buffer.read_bit().unwrap(); //value2 contains false (eg: bit is 0) - /// ``` - pub fn read_bit(&mut self) -> Result { - if self.rpos >= self.data.len() { - return Err(Error::new( - ErrorKind::UnexpectedEof, - "could not read enough bits from buffer", - )); - } - let bit = self.data[self.rpos] & (1 << (7 - self.rbit)) != 0; - self.rbit += 1; - if self.rbit > 7 { - self.flush_rbits(); - } - Ok(bit) - } - - /// Read n bits. an return the corresponding value an u64. - /// - /// _Note_: We cannot read more than 64 bits - /// - /// _Note_: Bits are read from left to right - /// - /// #Example - /// - /// ``` - /// # use bytebuffer::*; - /// let data = vec![128]; - /// let mut buffer = ByteReader::from_bytes(&data); // 10000000b - /// let value = buffer.read_bits(3).unwrap(); // value contains 4 (eg: 100b) - /// ``` - pub fn read_bits(&mut self, n: u8) -> Result { - if n > 64 { - return Err(Error::new( - ErrorKind::InvalidInput, - "cannot read more than 64 bits", - )); - } - - if n == 0 { - Ok(0) - } else { - Ok((u64::from(self.read_bit()?) << (n - 1)) | self.read_bits(n - 1)?) - } - } - - /// Discard all the pending bits available for reading and place the corresponding cursor to the next byte. - /// - /// _Note_: If no bits are currently read, this function does nothing. - /// - /// #Example - /// - /// ```text - /// 10010010 | 00000001 - /// ^ - /// 10010010 | 00000001 // read_bit called - /// ^ - /// 10010010 | 00000001 // flush_bit() called - /// ^ - /// ``` - pub fn flush_bits(&mut self) { - if self.rbit > 0 { - self.flush_rbits(); - } - } - - fn flush_rbits(&mut self) { - self.rpos += 1; - self.rbit = 0 - } -} diff --git a/pumpkin/src/protocol/client/config/mod.rs b/pumpkin/src/protocol/client/config/mod.rs index f273a221b..a4f6799b2 100644 --- a/pumpkin/src/protocol/client/config/mod.rs +++ b/pumpkin/src/protocol/client/config/mod.rs @@ -1,13 +1,33 @@ -use crate::protocol::{registry, ClientPacket, VarInt}; +use crate::protocol::{bytebuf::ByteBuffer, registry, ClientPacket, KnownPack, VarInt}; pub struct CCookieRequest { // TODO } impl ClientPacket for CCookieRequest { - const PACKET_ID: crate::protocol::VarInt = 0; + const PACKET_ID: crate::protocol::VarInt = 0x00; - fn write(&self, bytebuf: &mut crate::protocol::bytebuf::buffer::ByteBuffer) {} + fn write(&self, bytebuf: &mut ByteBuffer) {} +} + +pub struct CPluginMessage<'a> { + channel: String, + data: &'a [u8], +} + +impl<'a> CPluginMessage<'a> { + pub fn new(channel: String, data: &'a [u8]) -> Self { + Self { channel, data } + } +} + +impl<'a> ClientPacket for CPluginMessage<'a> { + const PACKET_ID: VarInt = 0x01; + + fn write(&self, bytebuf: &mut ByteBuffer) { + bytebuf.put_string(&self.channel); + bytebuf.put_slice(&self.data); + } } pub struct CConfigDisconnect { @@ -21,10 +41,10 @@ impl CConfigDisconnect { } impl ClientPacket for CConfigDisconnect { - const PACKET_ID: crate::protocol::VarInt = 2; + const PACKET_ID: crate::protocol::VarInt = 0x02; - fn write(&self, bytebuf: &mut crate::protocol::bytebuf::buffer::ByteBuffer) { - bytebuf.write_string(&self.reason); + fn write(&self, bytebuf: &mut ByteBuffer) { + bytebuf.put_string(&self.reason); } } @@ -43,37 +63,31 @@ impl CFinishConfig { } impl ClientPacket for CFinishConfig { - const PACKET_ID: crate::protocol::VarInt = 3; + const PACKET_ID: crate::protocol::VarInt = 0x03; - fn write(&self, _bytebuf: &mut crate::protocol::bytebuf::buffer::ByteBuffer) {} + fn write(&self, _bytebuf: &mut ByteBuffer) {} } -pub struct CKnownPacks { +pub struct CKnownPacks<'a> { count: VarInt, - known_packs: Vec, + known_packs: &'a [KnownPack], } -impl CKnownPacks { - pub fn new(count: VarInt, known_packs: Vec) -> Self { +impl<'a> CKnownPacks<'a> { + pub fn new(count: VarInt, known_packs: &'a [KnownPack]) -> Self { Self { count, known_packs } } } -pub struct KnownPack { - pub namespace: String, - pub id: String, - pub version: String, -} - -impl ClientPacket for CKnownPacks { +impl<'a> ClientPacket for CKnownPacks<'a> { const PACKET_ID: VarInt = 0x0E; - fn write(&self, bytebuf: &mut crate::protocol::bytebuf::buffer::ByteBuffer) { - bytebuf.write_var_int(self.count); - bytebuf.write_list::(&self.known_packs, |p, v| { - p.write_string(&v.namespace); - p.write_string(&v.id); - p.write_string(&v.version); + fn write(&self, bytebuf: &mut ByteBuffer) { + // bytebuf.write_var_int(self.count); + bytebuf.put_list::(&self.known_packs, |p, v| { + p.put_string(&v.namespace); + p.put_string(&v.id); + p.put_string(&v.version); }); } } @@ -103,13 +117,13 @@ pub struct Entry { impl ClientPacket for CRegistryData { const PACKET_ID: VarInt = 0x07; - fn write(&self, bytebuf: &mut crate::protocol::bytebuf::buffer::ByteBuffer) { - bytebuf.write_string(&self.registry_id); - bytebuf.write_var_int(self.entry_count); - bytebuf.write_list::(&self.entries, |p, v| { - p.write_string(&v.entry_id); - p.write_bool(v.has_data); - registry::write_codec(p, -64, 320); + fn write(&self, bytebuf: &mut ByteBuffer) { + bytebuf.put_string(&self.registry_id); + bytebuf.put_var_int(self.entry_count); + bytebuf.put_list::(&self.entries, |p, v| { + p.put_string(&v.entry_id); + p.put_bool(v.has_data); + registry::write_single_dimension(p, -64, 320); }); } } diff --git a/pumpkin/src/protocol/client/login/mod.rs b/pumpkin/src/protocol/client/login/mod.rs index b028425b3..1a80fd819 100644 --- a/pumpkin/src/protocol/client/login/mod.rs +++ b/pumpkin/src/protocol/client/login/mod.rs @@ -1,4 +1,4 @@ -use crate::protocol::{bytebuf::buffer::ByteBuffer, ClientPacket, VarInt}; +use crate::protocol::{bytebuf::ByteBuffer, ClientPacket, VarInt}; pub struct CLoginDisconnect { reason: String, @@ -11,10 +11,10 @@ impl CLoginDisconnect { } impl ClientPacket for CLoginDisconnect { - const PACKET_ID: VarInt = 0; + const PACKET_ID: VarInt = 0x00; fn write(&self, bytebuf: &mut ByteBuffer) { - bytebuf.write_string(&serde_json::to_string_pretty(&self.reason).unwrap()); + bytebuf.put_string(&serde_json::to_string_pretty(&self.reason).unwrap()); } } @@ -48,15 +48,15 @@ impl<'a> CEncryptionRequest<'a> { } impl<'a> ClientPacket for CEncryptionRequest<'a> { - const PACKET_ID: VarInt = 1; + const PACKET_ID: VarInt = 0x01; fn write(&self, bytebuf: &mut ByteBuffer) { - bytebuf.write_string_len(self.server_id.as_str(), 20); - bytebuf.write_var_int(self.public_key_length); - bytebuf.write_bytes(self.public_key); - bytebuf.write_var_int(self.verify_token_length); - bytebuf.write_bytes(self.verify_token); - bytebuf.write_bool(self.should_authenticate); + bytebuf.put_string(self.server_id.as_str()); + bytebuf.put_var_int(self.public_key_length); + bytebuf.put_slice(self.public_key); + bytebuf.put_var_int(self.verify_token_length); + bytebuf.put_slice(self.verify_token); + bytebuf.put_bool(self.should_authenticate); } } @@ -96,14 +96,14 @@ pub struct Property { } impl ClientPacket for CLoginSuccess { - const PACKET_ID: VarInt = 2; + const PACKET_ID: VarInt = 0x02; fn write(&self, bytebuf: &mut ByteBuffer) { - bytebuf.write_uuid(self.uuid); - bytebuf.write_string(&self.username); - bytebuf.write_var_int(self.num_of_props); + bytebuf.put_uuid(self.uuid); + bytebuf.put_string(&self.username); + bytebuf.put_var_int(self.num_of_props); // Todo - bytebuf.write_bool(self.strict_error_handling); + bytebuf.put_bool(self.strict_error_handling); } } @@ -114,9 +114,9 @@ impl CSetCompression { } impl ClientPacket for CSetCompression { - const PACKET_ID: VarInt = 3; + const PACKET_ID: VarInt = 0x03; fn write(&self, bytebuf: &mut ByteBuffer) { - bytebuf.write_var_int(self.threshold); + bytebuf.put_var_int(self.threshold); } } diff --git a/pumpkin/src/protocol/client/play/mod.rs b/pumpkin/src/protocol/client/play/mod.rs index 47835ce94..49f11101e 100644 --- a/pumpkin/src/protocol/client/play/mod.rs +++ b/pumpkin/src/protocol/client/play/mod.rs @@ -1,6 +1,6 @@ use crate::{ entity::player::GameMode, - protocol::{ClientPacket, VarInt}, + protocol::{bytebuf::ByteBuffer, ClientPacket, VarInt}, }; pub struct SetHeldItem { @@ -16,8 +16,8 @@ impl SetHeldItem { impl ClientPacket for SetHeldItem { const PACKET_ID: VarInt = 0x53; - fn write(&self, bytebuf: &mut crate::protocol::bytebuf::buffer::ByteBuffer) { - bytebuf.write_i8(self.slot); + fn write(&self, bytebuf: &mut ByteBuffer) { + bytebuf.put_i8(self.slot); } } @@ -40,10 +40,10 @@ impl CPlayerAbilities { impl ClientPacket for CPlayerAbilities { const PACKET_ID: VarInt = 0x38; - fn write(&self, bytebuf: &mut crate::protocol::bytebuf::buffer::ByteBuffer) { - bytebuf.write_i8(self.flags); - bytebuf.write_f32(self.flying_speed); - bytebuf.write_f32(self.field_of_view); + fn write(&self, bytebuf: &mut ByteBuffer) { + bytebuf.put_i8(self.flags); + bytebuf.put_f32(self.flying_speed); + bytebuf.put_f32(self.field_of_view); } } @@ -61,9 +61,9 @@ impl CChangeDifficulty { impl ClientPacket for CChangeDifficulty { const PACKET_ID: VarInt = 0x0B; - fn write(&self, bytebuf: &mut crate::protocol::bytebuf::buffer::ByteBuffer) { - bytebuf.write_u8(self.difficulty); - bytebuf.write_bool(self.locked); + fn write(&self, bytebuf: &mut ByteBuffer) { + bytebuf.put_u8(self.difficulty); + bytebuf.put_bool(self.locked); } } pub struct CLogin { @@ -147,28 +147,28 @@ impl CLogin { impl ClientPacket for CLogin { const PACKET_ID: VarInt = 0x2B; - fn write(&self, bytebuf: &mut crate::protocol::bytebuf::buffer::ByteBuffer) { - bytebuf.write_i32(self.entity_id); - bytebuf.write_bool(self.is_hardcore); - bytebuf.write_var_int(self.dimension_count); - bytebuf.write_string_array(self.dimension_names.as_slice()); - bytebuf.write_var_int(self.max_players); - bytebuf.write_var_int(self.view_distance); - bytebuf.write_var_int(self.simulated_distance); - bytebuf.write_bool(self.reduced_debug_info); - bytebuf.write_bool(self.enabled_respawn_screen); - bytebuf.write_bool(self.limited_crafting); - bytebuf.write_var_int(self.dimension_type); - bytebuf.write_string(&self.dimension_name); - bytebuf.write_i64(self.hashed_seed); - bytebuf.write_u8(self.game_mode.to_byte() as u8); - bytebuf.write_i8(self.previous_gamemode.to_byte()); - bytebuf.write_bool(self.debug); - bytebuf.write_bool(self.is_flat); - bytebuf.write_bool(self.has_death_loc); - bytebuf.write_option(&self.death_dimension_name, |buf, v| buf.write_string(v)); - bytebuf.write_option(&self.death_loc, |buf, v| buf.write_string(v)); - bytebuf.write_var_int(self.portal_cooldown); - bytebuf.write_bool(self.enforce_secure_chat); + fn write(&self, bytebuf: &mut ByteBuffer) { + bytebuf.put_i32(self.entity_id); + bytebuf.put_bool(self.is_hardcore); + bytebuf.put_var_int(self.dimension_count); + bytebuf.put_string_array(self.dimension_names.as_slice()); + bytebuf.put_var_int(self.max_players); + bytebuf.put_var_int(self.view_distance); + bytebuf.put_var_int(self.simulated_distance); + bytebuf.put_bool(self.reduced_debug_info); + bytebuf.put_bool(self.enabled_respawn_screen); + bytebuf.put_bool(self.limited_crafting); + bytebuf.put_var_int(self.dimension_type); + bytebuf.put_string(&self.dimension_name); + bytebuf.put_i64(self.hashed_seed); + bytebuf.put_u8(self.game_mode.to_byte() as u8); + bytebuf.put_i8(self.previous_gamemode.to_byte()); + bytebuf.put_bool(self.debug); + bytebuf.put_bool(self.is_flat); + bytebuf.put_bool(self.has_death_loc); + bytebuf.put_option(&self.death_dimension_name, |buf, v| buf.put_string(v)); + bytebuf.put_option(&self.death_loc, |buf, v| buf.put_string(v)); + bytebuf.put_var_int(self.portal_cooldown); + bytebuf.put_bool(self.enforce_secure_chat); } } diff --git a/pumpkin/src/protocol/client/status/mod.rs b/pumpkin/src/protocol/client/status/mod.rs index 1d531b6e8..32a5eb9a7 100644 --- a/pumpkin/src/protocol/client/status/mod.rs +++ b/pumpkin/src/protocol/client/status/mod.rs @@ -1,4 +1,4 @@ -use crate::protocol::{bytebuf::buffer::ByteBuffer, ClientPacket, VarInt}; +use crate::protocol::{bytebuf::ByteBuffer, ClientPacket, VarInt}; pub struct CPingResponse { payload: i64, // must responde with the same as in `SPingRequest` @@ -11,10 +11,10 @@ impl CPingResponse { } impl ClientPacket for CPingResponse { - const PACKET_ID: VarInt = 1; + const PACKET_ID: VarInt = 0x01; fn write(&self, bytebuf: &mut ByteBuffer) { - bytebuf.write_i64(self.payload); + bytebuf.put_i64(self.payload); } } @@ -29,9 +29,9 @@ impl CStatusResponse { } impl ClientPacket for CStatusResponse { - const PACKET_ID: VarInt = 0; + const PACKET_ID: VarInt = 0x00; fn write(&self, bytebuf: &mut ByteBuffer) { - bytebuf.write_string(self.json_response.as_str()); + bytebuf.put_string(self.json_response.as_str()); } } diff --git a/pumpkin/src/protocol/mod.rs b/pumpkin/src/protocol/mod.rs index f26d50d13..5bfeb5cbc 100644 --- a/pumpkin/src/protocol/mod.rs +++ b/pumpkin/src/protocol/mod.rs @@ -1,12 +1,11 @@ use std::io::{Read, Write}; use anyhow::bail; -use bytebuf::buffer::ByteBuffer; +use bytebuf::ByteBuffer; use byteorder::ReadBytesExt; use serde::{Deserialize, Serialize}; pub mod bytebuf; -pub mod nbt; mod registry; pub mod client; @@ -113,7 +112,6 @@ impl ConnectionState { } } -#[derive(Debug)] pub struct RawPacket { pub len: VarInt, pub id: VarInt, @@ -152,3 +150,9 @@ pub struct Sample { pub name: String, pub id: String, // uuid } + +pub struct KnownPack { + pub namespace: String, + pub id: String, + pub version: String, +} diff --git a/pumpkin/src/protocol/nbt/deserialize.rs b/pumpkin/src/protocol/nbt/deserialize.rs deleted file mode 100644 index 32538537f..000000000 --- a/pumpkin/src/protocol/nbt/deserialize.rs +++ /dev/null @@ -1,132 +0,0 @@ -use flate2::read::{GzDecoder, ZlibDecoder}; -use std::{collections::HashMap, error::Error, fmt, io, io::Read, string::FromUtf8Error}; - -use crate::protocol::bytebuf::buffer::ByteBuffer; - -use super::{nbt::ParseError, Tag, NBT}; - -impl fmt::Display for ParseError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::InvalidType(ty) => write!(f, "invalid tag type: {ty}"), - Self::InvalidString(e) => write!(f, "invalid string: {e}"), - Self::IO(e) => write!(f, "io error: {e}"), - } - } -} - -impl From for ParseError { - fn from(e: FromUtf8Error) -> ParseError { - ParseError::InvalidString(e) - } -} -impl From for ParseError { - fn from(e: io::Error) -> ParseError { - ParseError::IO(e) - } -} -impl Error for ParseError {} - -impl NBT { - pub fn deserialize_file(buf: Vec) -> Result { - if buf.len() >= 2 && buf[0] == 0x1f && buf[1] == 0x8b { - // This means its gzipped - let mut d: GzDecoder<&[u8]> = GzDecoder::new(buf.as_ref()); - let mut buf = vec![]; - d.read_to_end(&mut buf)?; - Self::deserialize(buf) - } else { - // It could be zlib compressed or not compressed - let mut d: ZlibDecoder<&[u8]> = ZlibDecoder::new(buf.as_ref()); - let mut decompressed = vec![]; - match d.read_to_end(&mut decompressed) { - Ok(_) => Self::deserialize(decompressed), - Err(_) => Self::deserialize(buf), - } - } - } - /// Deserializes the given byte array as nbt data. - pub fn deserialize(mut buf: Vec) -> Result { - Self::deserialize_buf(&mut ByteBuffer::from_vec(buf)) - } - /// Deserializes the given buffer as nbt data. This will continue reading - /// where this buffer is currently placed, and will advance the reader to be - /// right after the nbt data. If this function returns an error, then the - /// buffer will be in an undefined state (it will still be safe, but there are - /// no guarantees as too how far ahead the buffer will have been advanced). - pub fn deserialize_buf(buf: &mut ByteBuffer) -> Result { - let ty = buf.read_u8()?; - if ty == 0 { - Ok(NBT::empty()) - } else { - let len = buf.read_u16()?; - let name = String::from_utf8(buf.read_bytes(len as usize)?)?; - Ok(NBT::new(&name, Tag::deserialize(ty, buf)?)) - } - } -} - -impl Tag { - fn deserialize(ty: u8, buf: &mut ByteBuffer) -> Result { - match ty { - 0 => Ok(Self::End), - 1 => Ok(Self::Byte(buf.read_i8()?)), - 2 => Ok(Self::Short(buf.read_i16()?)), - 3 => Ok(Self::Int(buf.read_i32()?)), - 4 => Ok(Self::Long(buf.read_i64()?)), - 5 => Ok(Self::Float(buf.read_f32()?)), - 6 => Ok(Self::Double(buf.read_f64()?)), - 7 => { - let len = buf.read_i32()?; - Ok(Self::ByteArr(buf.read_bytes(len as usize)?)) - } - 8 => { - let len = buf.read_u16()?; - match String::from_utf8(buf.read_bytes(len as usize)?) { - Ok(v) => Ok(Self::String(v)), - Err(e) => Err(ParseError::InvalidString(e)), - } - } - 9 => { - let inner_ty = buf.read_u8()?; - let len = buf.read_i32()?; - let mut inner = Vec::with_capacity(len as usize); - for _ in 0..len { - inner.push(Tag::deserialize(inner_ty, buf)?); - } - Ok(Self::List(inner)) - } - 10 => { - let mut inner = HashMap::new(); - loop { - let ty = buf.read_u8()?; - if ty == Self::End.ty() { - break; - } - let len = buf.read_u16()?; - let name = String::from_utf8(buf.read_bytes(len as usize)?).unwrap(); - let tag = Tag::deserialize(ty, buf)?; - inner.insert(name, tag); - } - Ok(inner.into()) - } - 11 => { - let len = buf.read_i32()?; - let mut inner = Vec::with_capacity(len as usize); - for _ in 0..len { - inner.push(buf.read_i32()?); - } - Ok(Self::IntArray(inner)) - } - 12 => { - let len = buf.read_i32()?; - let mut inner = Vec::with_capacity(len as usize); - for _ in 0..len { - inner.push(buf.read_i64()?); - } - Ok(Self::LongArray(inner)) - } - _ => Err(ParseError::InvalidType(ty)), - } - } -} diff --git a/pumpkin/src/protocol/nbt/error.rs b/pumpkin/src/protocol/nbt/error.rs deleted file mode 100644 index 4963758a7..000000000 --- a/pumpkin/src/protocol/nbt/error.rs +++ /dev/null @@ -1,56 +0,0 @@ -use super::Tag; -use serde::{de, ser}; -use std::{fmt, fmt::Display, num::TryFromIntError}; - -#[derive(Debug, Clone, PartialEq)] -pub enum Error { - Message(String), - Eof, - - TryFromInt(TryFromIntError), - ListType(Tag, Tag), - MapKey(Tag), - CannotSerializeNone, - Enum, -} - -pub type Result = std::result::Result; - -impl ser::Error for Error { - fn custom(msg: T) -> Self { - Error::Message(msg.to_string()) - } -} - -impl de::Error for Error { - fn custom(msg: T) -> Self { - Error::Message(msg.to_string()) - } -} - -impl Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Error::Message(msg) => write!(f, "{msg}"), - Error::Eof => write!(f, "unexpected end of input"), - Error::TryFromInt(e) => write!(f, "invalid integer: {e}"), - Error::ListType(expected, got) => { - write!(f, "expected type in list: {expected:?}, got: {got:?}") - } - Error::MapKey(got) => { - write!(f, "expected a string for map key, got: {got:?}") - } - Error::CannotSerializeNone => { - write!( - f, - "cannot serialize `None` or `()` (use `#[serde(skip_serializing_if = \"Option::is_none\")]`)" - ) - } - Error::Enum => { - write!(f, "enums are not supported") - } - } - } -} - -impl std::error::Error for Error {} diff --git a/pumpkin/src/protocol/nbt/mod.rs b/pumpkin/src/protocol/nbt/mod.rs deleted file mode 100644 index 0f47c3129..000000000 --- a/pumpkin/src/protocol/nbt/mod.rs +++ /dev/null @@ -1,445 +0,0 @@ -use std::collections::HashMap; - -use error::Error; -use error::Result; -use nbt::Tag; -use nbt::NBT; -use serde::{ser, Serialize}; - -mod deserialize; -mod error; -pub mod nbt; -mod serialize; - -pub fn to_nbt(name: &str, value: &T) -> anyhow::Result -where - T: Serialize, -{ - Ok(NBT::new(name, to_tag(value)?)) -} - -pub fn to_tag(value: &T) -> anyhow::Result -where - T: Serialize, -{ - let mut serializer = Serializer { tag: Tag::End }; - value.serialize(&mut serializer)?; - Ok(serializer.tag) -} - -pub struct Serializer { - tag: Tag, -} - -pub struct SeqSerializer<'a> { - ser: &'a mut Serializer, - items: Vec, -} -pub struct MapSerializer<'a> { - ser: &'a mut Serializer, - key: Option, - items: HashMap, -} - -impl<'a> ser::Serializer for &'a mut Serializer { - // The output type produced by this `Serializer` during successful - // serialization. Most serializers that produce text or binary output should - // set `Ok = ()` and serialize into an `io::Write` or buffer contained - // within the `Serializer` instance, as happens here. Serializers that build - // in-memory data structures may be simplified by using `Ok` to propagate - // the data structure around. - type Ok = (); - type Error = Error; - - // Associated types for keeping track of additional state while serializing - // compound data structures like sequences and maps. In this case no - // additional state is required beyond what is already stored in the - // Serializer struct. - type SerializeSeq = SeqSerializer<'a>; - type SerializeTuple = SeqSerializer<'a>; - type SerializeTupleStruct = SeqSerializer<'a>; - type SerializeTupleVariant = SeqSerializer<'a>; - type SerializeMap = MapSerializer<'a>; - type SerializeStruct = MapSerializer<'a>; - type SerializeStructVariant = MapSerializer<'a>; - - // Here we go with the simple methods. The following 12 methods receive one - // of the primitive types of the data model and map it to JSON by appending - // into the output string. - fn serialize_bool(self, v: bool) -> Result<()> { - self.tag = Tag::Byte(v as i8); - Ok(()) - } - - // JSON does not distinguish between different sizes of integers, so all - // signed integers will be serialized the same and all unsigned integers - // will be serialized the same. Other formats, especially compact binary - // formats, may need independent logic for the different sizes. - fn serialize_i8(self, v: i8) -> Result<()> { - self.tag = Tag::Byte(v); - Ok(()) - } - fn serialize_i16(self, v: i16) -> Result<()> { - self.tag = Tag::Short(v); - Ok(()) - } - fn serialize_i32(self, v: i32) -> Result<()> { - self.tag = Tag::Int(v); - Ok(()) - } - fn serialize_i64(self, v: i64) -> Result<()> { - self.tag = Tag::Long(v); - Ok(()) - } - - fn serialize_u8(self, v: u8) -> Result<()> { - self.serialize_i8(v as i8) - } - fn serialize_u16(self, v: u16) -> Result<()> { - self.serialize_i16(v as i16) - } - fn serialize_u32(self, v: u32) -> Result<()> { - self.serialize_i32(v as i32) - } - fn serialize_u64(self, v: u64) -> Result<()> { - self.serialize_i64(v as i64) - } - - fn serialize_f32(self, v: f32) -> Result<()> { - self.tag = Tag::Float(v); - Ok(()) - } - fn serialize_f64(self, v: f64) -> Result<()> { - self.tag = Tag::Double(v); - Ok(()) - } - - fn serialize_char(self, v: char) -> Result<()> { - self.serialize_str(&v.to_string()) - } - fn serialize_str(self, v: &str) -> Result<()> { - self.tag = Tag::String(v.into()); - Ok(()) - } - - fn serialize_bytes(self, v: &[u8]) -> Result<()> { - self.tag = Tag::ByteArr(v.into()); - Ok(()) - } - - // There isn't really a `None` in NBT. There is `Tag::End`, which could be - // searched and removed if this was in a struct or map, which would essentially - // skip this value if it's `None`. However, I don't care enough, so I'm just - // going to produce an error. - fn serialize_none(self) -> Result<()> { - Err(Error::CannotSerializeNone) - } - fn serialize_some(self, value: &T) -> Result<()> - where - T: ?Sized + Serialize, - { - value.serialize(self) - } - - fn serialize_unit(self) -> Result<()> { - Err(Error::CannotSerializeNone) - } - - // Unit struct means a named value containing no data. Again, since there is - // no data, map this to JSON as `null`. There is no need to serialize the - // name in most formats. - fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { - self.serialize_unit() - } - - // As is done here, serializers are encouraged to treat newtype structs as - // insignificant wrappers around the data they contain. - fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result<()> - where - T: ?Sized + Serialize, - { - value.serialize(self) - } - - // Now we get to the serialization of compound types. - // - // The start of the sequence, each value, and the end are three separate - // method calls. This one is responsible only for serializing the start, - // which in JSON is `[`. - // - // The length of the sequence may or may not be known ahead of time. This - // doesn't make a difference in JSON because the length is not represented - // explicitly in the serialized form. Some serializers may only be able to - // support sequences for which the length is known up front. - fn serialize_seq(self, _len: Option) -> Result { - Ok(SeqSerializer { - ser: self, - items: vec![], - }) - } - - // Tuples look just like sequences in JSON. Some formats may be able to - // represent tuples more efficiently by omitting the length, since tuple - // means that the corresponding `Deserialize implementation will know the - // length without needing to look at the serialized data. - fn serialize_tuple(self, len: usize) -> Result { - self.serialize_seq(Some(len)) - } - - // Tuple structs look just like sequences in JSON. - fn serialize_tuple_struct( - self, - _name: &'static str, - len: usize, - ) -> Result { - self.serialize_seq(Some(len)) - } - - // Maps are represented in JSON as `{ K: V, K: V, ... }`. - fn serialize_map(self, _len: Option) -> Result { - Ok(MapSerializer { - ser: self, - key: None, - items: HashMap::new(), - }) - } - - // Structs look just like maps in JSON. In particular, JSON requires that we - // serialize the field names of the struct. Other formats may be able to - // omit the field names when serializing structs because the corresponding - // Deserialize implementation is required to know what the keys are without - // looking at the serialized data. - fn serialize_struct(self, _name: &'static str, len: usize) -> Result { - self.serialize_map(Some(len)) - } - - // We don't support enums (they don't really make sense) - fn serialize_unit_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - ) -> Result<()> { - Err(Error::Enum) - } - fn serialize_newtype_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _value: &T, - ) -> Result<()> - where - T: ?Sized + Serialize, - { - Err(Error::Enum) - } - fn serialize_tuple_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize, - ) -> Result { - Err(Error::Enum) - } - fn serialize_struct_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize, - ) -> Result { - Err(Error::Enum) - } -} - -// The following 7 impls deal with the serialization of compound types like -// sequences and maps. Serialization of such types is begun by a Serializer -// method and followed by zero or more calls to serialize individual elements of -// the compound type and one call to end the compound type. -// -// This impl is SerializeSeq so these methods are called after `serialize_seq` -// is called on the Serializer. -impl<'a> ser::SerializeSeq for SeqSerializer<'a> { - type Ok = (); - type Error = Error; - - // Serialize a single element of the sequence. - fn serialize_element(&mut self, value: &T) -> Result<()> - where - T: ?Sized + Serialize, - { - value.serialize(&mut *self.ser)?; - let tag = std::mem::replace(&mut self.ser.tag, Tag::End); - if let Some(first) = self.items.first() { - let expected_ty = first.ty(); - let actual_ty = tag.ty(); - if expected_ty != actual_ty { - return Err(Error::ListType(first.clone(), tag)); - } - } - self.items.push(tag); - Ok(()) - } - - fn end(self) -> Result<()> { - self.ser.tag = Tag::List(self.items); - Ok(()) - } -} - -// Same thing but for tuples. -impl<'a> ser::SerializeTuple for SeqSerializer<'a> { - type Ok = (); - type Error = Error; - - fn serialize_element(&mut self, value: &T) -> Result<()> - where - T: ?Sized + Serialize, - { - ::serialize_element(self, value) - } - - fn end(self) -> Result<()> { - ::end(self) - } -} - -// Same thing but for tuple structs. -impl<'a> ser::SerializeTupleStruct for SeqSerializer<'a> { - type Ok = (); - type Error = Error; - - fn serialize_field(&mut self, value: &T) -> Result<()> - where - T: ?Sized + Serialize, - { - ::serialize_element(self, value) - } - - fn end(self) -> Result<()> { - ::end(self) - } -} - -// Tuple variants are a little different. Refer back to the -// `serialize_tuple_variant` method above: -// -// self.output += "{"; -// variant.serialize(&mut *self)?; -// self.output += ":["; -// -// So the `end` method in this impl is responsible for closing both the `]` and -// the `}`. -impl<'a> ser::SerializeTupleVariant for SeqSerializer<'a> { - type Ok = (); - type Error = Error; - - fn serialize_field(&mut self, value: &T) -> Result<()> - where - T: ?Sized + Serialize, - { - ::serialize_element(self, value) - } - - fn end(self) -> Result<()> { - ::end(self) - } -} - -// Some `Serialize` types are not able to hold a key and value in memory at the -// same time so `SerializeMap` implementations are required to support -// `serialize_key` and `serialize_value` individually. -// -// There is a third optional method on the `SerializeMap` trait. The -// `serialize_entry` method allows serializers to optimize for the case where -// key and value are both available simultaneously. In JSON it doesn't make a -// difference so the default behavior for `serialize_entry` is fine. -impl<'a> ser::SerializeMap for MapSerializer<'a> { - type Ok = (); - type Error = Error; - - // The Serde data model allows map keys to be any serializable type. JSON - // only allows string keys so the implementation below will produce invalid - // JSON if the key serializes as something other than a string. - // - // A real JSON serializer would need to validate that map keys are strings. - // This can be done by using a different Serializer to serialize the key - // (instead of `&mut **self`) and having that other serializer only - // implement `serialize_str` and return an error on any other data type. - fn serialize_key(&mut self, key: &T) -> Result<()> - where - T: ?Sized + Serialize, - { - key.serialize(&mut *self.ser)?; - let tag = std::mem::replace(&mut self.ser.tag, Tag::End); - self.key = match tag { - Tag::String(key) => Some(key), - other => return Err(Error::MapKey(other)), - }; - Ok(()) - } - - // It doesn't make a difference whether the colon is printed at the end of - // `serialize_key` or at the beginning of `serialize_value`. In this case - // the code is a bit simpler having it here. - fn serialize_value(&mut self, value: &T) -> Result<()> - where - T: ?Sized + Serialize, - { - value.serialize(&mut *self.ser)?; - let tag = std::mem::replace(&mut self.ser.tag, Tag::End); - self.items.insert(self.key.take().unwrap(), tag); - Ok(()) - } - - fn end(self) -> Result<()> { - self.ser.tag = self.items.into(); - Ok(()) - } -} - -// Structs are like maps in which the keys are constrained to be compile-time -// constant strings. -impl<'a> ser::SerializeStruct for MapSerializer<'a> { - type Ok = (); - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> - where - T: ?Sized + Serialize, - { - value.serialize(&mut *self.ser)?; - let tag = std::mem::replace(&mut self.ser.tag, Tag::End); - self.items.insert(key.into(), tag); - Ok(()) - } - - fn end(self) -> Result<()> { - self.ser.tag = self.items.into(); - Ok(()) - } -} - -// Similar to `SerializeTupleVariant`, here the `end` method is responsible for -// closing both of the curly braces opened by `serialize_struct_variant`. -impl<'a> ser::SerializeStructVariant for MapSerializer<'a> { - type Ok = (); - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> - where - T: ?Sized + Serialize, - { - value.serialize(&mut *self.ser)?; - let tag = std::mem::replace(&mut self.ser.tag, Tag::End); - self.items.insert(key.into(), tag); - Ok(()) - } - - fn end(self) -> Result<()> { - self.ser.tag = self.items.into(); - Ok(()) - } -} diff --git a/pumpkin/src/protocol/nbt/nbt.rs b/pumpkin/src/protocol/nbt/nbt.rs deleted file mode 100644 index 7a134c970..000000000 --- a/pumpkin/src/protocol/nbt/nbt.rs +++ /dev/null @@ -1,283 +0,0 @@ -use std::{collections::HashMap, fmt, io, ops::Index, string::FromUtf8Error}; - -#[derive(Debug)] -pub enum ParseError { - InvalidType(u8), - InvalidString(FromUtf8Error), - IO(io::Error), -} - -#[derive(Debug, Clone, PartialEq)] -pub struct WrongTag(Tag); - -impl fmt::Display for WrongTag { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "wrong tag: {:?}", self.0) - } -} - -impl std::error::Error for WrongTag {} - -/// This is an nbt tag. It has a name, and any amount of data. This can be used -/// to store item data, entity data, level data, and more. -#[derive(Debug, Clone, PartialEq)] -pub struct NBT { - pub tag: Tag, - pub name: String, -} - -impl Default for NBT { - fn default() -> Self { - NBT::new("", Tag::new_compound(&[])) - } -} - -/// This is a single tag. It does not contain a name, but has the actual data -/// for any of the nbt tags. -#[derive(Debug, Clone, PartialEq)] -pub enum Tag { - End, - Byte(i8), - Short(i16), - Int(i32), - Long(i64), - Float(f32), - Double(f64), - ByteArr(Vec), - String(String), - List(Vec), // All elements must be the same type, and un-named. - Compound(Compound), // Types can be any kind, and are named. Order is not defined. - IntArray(Vec), - LongArray(Vec), -} - -/// An NBT Compound tag. This is essentially a map, with some extra helper -/// functions. -#[derive(Debug, Clone, PartialEq)] -pub struct Compound { - pub inner: HashMap, -} - -impl Compound { - pub fn new() -> Self { - Compound { - inner: HashMap::new(), - } - } - pub fn insert(&mut self, key: impl Into, value: impl Into) { - self.inner.insert(key.into(), value.into()); - } - pub fn get_or_create_compound(&mut self, key: impl Into) -> &mut Compound { - self.inner - .entry(key.into()) - .or_insert_with(|| Tag::Compound(Compound::new())) - .compound_mut() - .unwrap() - } - - pub fn contains_key(&self, key: impl AsRef) -> bool { - self.inner.contains_key(key.as_ref()) - } - - pub fn iter(&self) -> std::collections::hash_map::Iter { - self.inner.iter() - } - pub fn iter_mut(&mut self) -> std::collections::hash_map::IterMut { - self.inner.iter_mut() - } -} -impl IntoIterator for Compound { - type Item = (String, Tag); - type IntoIter = std::collections::hash_map::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.inner.into_iter() - } -} -impl<'a> IntoIterator for &'a Compound { - type Item = (&'a String, &'a Tag); - type IntoIter = std::collections::hash_map::Iter<'a, String, Tag>; - - fn into_iter(self) -> Self::IntoIter { - self.inner.iter() - } -} -impl<'a> IntoIterator for &'a mut Compound { - type Item = (&'a String, &'a mut Tag); - type IntoIter = std::collections::hash_map::IterMut<'a, String, Tag>; - - fn into_iter(self) -> Self::IntoIter { - self.inner.iter_mut() - } -} -impl From> for Compound { - fn from(v: HashMap) -> Self { - Compound { inner: v } - } -} - -impl Index<&str> for Compound { - type Output = Tag; - fn index(&self, index: &str) -> &Tag { - &self.inner[index] - } -} - -impl From for Tag { - fn from(v: bool) -> Self { - Tag::Byte(v as i8) - } -} -impl From<&str> for Tag { - fn from(s: &str) -> Self { - Tag::String(s.into()) - } -} -impl From for Tag { - fn from(s: String) -> Self { - Tag::String(s) - } -} -impl From> for Tag { - fn from(v: HashMap) -> Self { - Tag::Compound(Compound::from(v)) - } -} - -impl From> for Tag -where - Tag: From, -{ - fn from(list: Vec) -> Self { - Tag::List(list.into_iter().map(|it| it.into()).collect()) - } -} - -impl NBT { - /// Creates a new nbt tag. The tag value can be anything. - /// - /// # Panics - /// This will panic if the tag is a list, and the values within that list - /// contain multiple types. This is a limitation with the nbt data format: - /// lists can only contain one type of data. - pub fn new(name: &str, tag: Tag) -> Self { - if let Tag::List(inner) = &tag { - if let Some(v) = inner.get(0) { - let ty = v.ty(); - for v in inner { - if v.ty() != ty { - panic!("the given list contains multiple types: {inner:?}"); - } - } - } - } - NBT { - tag, - name: name.into(), - } - } - - /// Creates an empty nbt tag. - pub const fn empty() -> Self { - NBT { - tag: Tag::End, - name: String::new(), - } - } - - /// Appends the given element to the list. This will panic if self is not a - /// list, or if tag does not match the type of the existing elements. - pub fn list_add(&mut self, tag: Tag) { - if let Tag::List(inner) = &mut self.tag { - if let Some(v) = inner.get(0) { - if tag.ty() != v.ty() { - panic!("cannot add different types to list. current: {inner:?}, new: {tag:?}"); - } else { - inner.push(tag); - } - } else { - // No elements yet, so we add this no matter what type it is. - inner.push(tag); - } - } else { - panic!("called list_add on non-list type: {self:?}"); - } - } - - /// Appends the given element to the compound. This will panic if self is not - /// a compound tag. - pub fn compound_add(&mut self, name: String, value: Tag) { - if let Tag::Compound(inner) = &mut self.tag { - inner.insert(name, value); - } else { - panic!("called compound_add on non-compound type: {self:?}"); - } - } - - /// If this is a compound tag, this returns the inner data of the tag. - /// Otherwise, this panics. - pub fn compound(&self) -> Option<&Compound> { - if let Tag::Compound(inner) = &self.tag { - Some(inner) - } else { - None - } - } - /// If this is a compound tag, this returns the inner data of the tag. - /// Otherwise, this panics. - pub fn compound_mut(&mut self) -> Option<&mut Compound> { - if let Tag::Compound(inner) = &mut self.tag { - Some(inner) - } else { - None - } - } - - pub fn tag(&self) -> &Tag { - &self.tag - } - pub fn into_tag(self) -> Tag { - self.tag - } -} - -macro_rules! getter { - ( $(: $conv:tt)? $name:ident -> $variant:ident ( $ty:ty ) ) => { - pub fn $name(&self) -> Result<$ty, WrongTag> { - match self { - Self::$variant(v) => Ok($($conv)? v), - _ => Err(WrongTag(self.clone())), - } - } - }; -} - -impl Tag { - /// A simpler way to construct compound tags inline. - pub fn new_compound(value: &[(&str, Tag)]) -> Self { - let mut inner = HashMap::new(); - for (name, tag) in value { - inner.insert(name.to_string(), tag.clone()); - } - inner.into() - } - - getter!(:*byte -> Byte(i8)); - getter!(:*short -> Short(i16)); - getter!(:*int -> Int(i32)); - getter!(:*long -> Long(i64)); - getter!(:*float -> Float(f32)); - getter!(:*double -> Double(f64)); - getter!(string -> String(&str)); - getter!(byte_arr -> ByteArr(&[u8])); - getter!(list -> List(&Vec)); - getter!(compound -> Compound(&Compound)); - getter!(long_arr -> LongArray(&Vec)); - - pub fn compound_mut(&mut self) -> Result<&mut Compound, WrongTag> { - match self { - Self::Compound(v) => Ok(v), - _ => Err(WrongTag(self.clone())), - } - } -} diff --git a/pumpkin/src/protocol/nbt/serialize.rs b/pumpkin/src/protocol/nbt/serialize.rs deleted file mode 100644 index 068b654bc..000000000 --- a/pumpkin/src/protocol/nbt/serialize.rs +++ /dev/null @@ -1,96 +0,0 @@ -use crate::protocol::bytebuf::buffer::ByteBuffer; - -use super::{Tag, NBT}; - -impl NBT { - pub fn serialize_buf(&self, out: &mut ByteBuffer) { - out.write_u8(self.tag.ty()); - if matches!(self.tag, Tag::End) { - return; - } - out.write_u16(self.name.len() as u16); - out.write_bytes(self.name.as_bytes()); - self.tag.serialize(out); - } - pub fn serialize(&self) -> Vec { - let mut out = ByteBuffer::new(); - self.serialize_buf(&mut out); - out.into_vec() - } -} - -impl Tag { - /// Returns the type of the tag. - pub fn ty(&self) -> u8 { - match self { - Self::End => 0, - Self::Byte(_) => 1, - Self::Short(_) => 2, - Self::Int(_) => 3, - Self::Long(_) => 4, - Self::Float(_) => 5, - Self::Double(_) => 6, - Self::ByteArr(_) => 7, - Self::String(_) => 8, - Self::List(_) => 9, - Self::Compound(_) => 10, - Self::IntArray(_) => 11, - Self::LongArray(_) => 12, - } - } - - /// Serializes the data of the tag. Does not add type byte. - fn serialize(&self, out: &mut ByteBuffer) { - match self { - Self::End => (), - Self::Byte(v) => out.write_i8(*v), - Self::Short(v) => out.write_i16(*v), - Self::Int(v) => out.write_i32(*v), - Self::Long(v) => out.write_i64(*v), - Self::Float(v) => out.write_f32(*v), - Self::Double(v) => out.write_f64(*v), - Self::ByteArr(v) => { - out.write_i32(v.len() as i32); - out.write_bytes(v); - } - Self::String(v) => { - out.write_u16(v.len() as u16); - out.write_bytes(v.as_bytes()); - } - Self::List(v) => { - out.write_u8(v.get(0).unwrap_or(&Self::End).ty()); - out.write_i32(v.len() as i32); - for tag in v { - tag.serialize(out); - } - } - Self::Compound(v) => { - for (name, tag) in &v.inner { - // Each element in the HashMap is essentially a NBT, but we store it in a - // separated form, so we have a manual implementation of serialize() here. - out.write_u8(tag.ty()); - if tag.ty() == Self::End.ty() { - // End tags don't have a name, so we stop early. - break; - } - out.write_u16(name.len() as u16); - out.write_bytes(name.as_bytes()); - tag.serialize(out); - } - out.write_u8(Self::End.ty()); - } - Self::IntArray(v) => { - out.write_i32(v.len() as i32); - for elem in v { - out.write_i32(*elem); - } - } - Self::LongArray(v) => { - out.write_i32(v.len() as i32); - for elem in v { - out.write_i64(*elem); - } - } - } - } -} diff --git a/pumpkin/src/protocol/registry/biomes.rs b/pumpkin/src/protocol/registry/biomes.rs index da1581023..fa1fbd79a 100644 --- a/pumpkin/src/protocol/registry/biomes.rs +++ b/pumpkin/src/protocol/registry/biomes.rs @@ -1,30 +1,54 @@ +use crate::protocol::VarInt; + use super::CodecItem; use serde::Serialize; #[derive(Debug, Clone, Serialize)] pub struct Biome { - category: String, - depth: f32, + has_precipitation: bool, + temperature: f32, + #[serde(skip_serializing_if = "Option::is_none")] + temperature_modifier: Option, downfall: f32, effects: BiomeEffects, - precipitation: String, - scale: f32, - temperature: f32, - has_precipitation: bool, } #[derive(Debug, Clone, Serialize)] struct BiomeEffects { - sky_color: i32, fog_color: i32, - water_fog_color: i32, water_color: i32, + water_fog_color: i32, + sky_color: i32, #[serde(skip_serializing_if = "Option::is_none")] foliage_color: Option, #[serde(skip_serializing_if = "Option::is_none")] grass_color: Option, #[serde(skip_serializing_if = "Option::is_none")] - mood_sound: Option, // 1.18.2+ + grass_color_modifier: Option, + #[serde(skip_serializing_if = "Option::is_none")] + particle: Option, + #[serde(skip_serializing_if = "Option::is_none")] + ambient_sound: Option, + #[serde(skip_serializing_if = "Option::is_none")] + mood_sound: Option, + #[serde(skip_serializing_if = "Option::is_none")] + additions_sound: Option, + #[serde(skip_serializing_if = "Option::is_none")] + music: Option, } + +#[derive(Debug, Clone, Serialize)] +struct Particle { + options: ParticleOptions, + probability: f32, +} + +#[derive(Debug, Clone, Serialize)] +struct ParticleOptions { + typee: String, + #[serde(skip_serializing_if = "Option::is_none")] + value: Option, +} + #[derive(Debug, Clone, Serialize)] struct MoodSound { block_search_extent: i32, @@ -33,35 +57,45 @@ struct MoodSound { tick_delay: i32, } +#[derive(Debug, Clone, Serialize)] +struct AdditionsSound { + sound: String, + tick_chance: f64, +} + +#[derive(Debug, Clone, Serialize)] +struct Music { + sound: String, + min_delay: i32, + max_delay: i32, + replace_current_music: bool, +} + +// 1.20.6 default https://gist.github.com/WinX64/ab8c7a8df797c273b32d3a3b66522906 pub(super) fn all() -> Vec> { let biome = Biome { - precipitation: "rain".into(), - depth: 1.0, + has_precipitation: false, temperature: 1.0, - scale: 1.0, - downfall: 1.0, - category: "none".into(), - has_precipitation: true, + temperature_modifier: None, + downfall: 0.0, effects: BiomeEffects { - sky_color: 0x78a7ff, - fog_color: 0xc0d8ff, - water_fog_color: 0x050533, - water_color: 0x3f76e4, - foliage_color: None, - grass_color: None, + fog_color: 0x7FA1FF, + water_color: 0x7FA1FF, + water_fog_color: 0x7FA1FF, + sky_color: 0x7FA1FF, + foliage_color: Some(0x7FA1FF), + grass_color: Some(0x7FA1FF), + grass_color_modifier: None, + particle: None, + ambient_sound: None, mood_sound: Some(MoodSound { block_search_extent: 8, offset: 2.0, sound: "minecraft:ambient.cave".into(), tick_delay: 6000, }), - // sky_color: 0xff00ff, - // water_color: 0xff00ff, - // fog_color: 0xff00ff, - // water_fog_color: 0xff00ff, - // grass_color: 0xff00ff, - // foliage_color: 0x00ffe5, - // grass_color: 0xff5900, + additions_sound: None, + music: None, }, }; diff --git a/pumpkin/src/protocol/registry/chat_type.rs b/pumpkin/src/protocol/registry/chat_type.rs index 3dbf3a434..66bc22792 100644 --- a/pumpkin/src/protocol/registry/chat_type.rs +++ b/pumpkin/src/protocol/registry/chat_type.rs @@ -3,13 +3,14 @@ use serde::Serialize; #[derive(Debug, Clone, Serialize)] pub struct ChatType { - chat: ChatParams, - narration: ChatParams, + chat: Decoration, + narration: Decoration, } #[derive(Debug, Clone, Serialize)] -struct ChatParams { - parameters: Vec, +struct Decoration { translation_key: String, + // style: Option<> + parameters: Vec, } pub(super) fn all() -> Vec> { @@ -17,11 +18,11 @@ pub(super) fn all() -> Vec> { name: "minecraft:chat".into(), id: 0, element: ChatType { - chat: ChatParams { + chat: Decoration { parameters: vec!["sender".into(), "content".into()], translation_key: "chat.type.text".into(), }, - narration: ChatParams { + narration: Decoration { parameters: vec!["sender".into(), "content".into()], translation_key: "chat.type.text.narrate".into(), }, diff --git a/pumpkin/src/protocol/registry/damage_type.rs b/pumpkin/src/protocol/registry/damage_type.rs index 35e6d6431..669bc41de 100644 --- a/pumpkin/src/protocol/registry/damage_type.rs +++ b/pumpkin/src/protocol/registry/damage_type.rs @@ -3,38 +3,61 @@ use serde::Serialize; #[derive(Debug, Clone, Serialize)] pub struct DamageType { - exhaustion: f32, message_id: String, scaling: String, + exhaustion: f32, #[serde(skip_serializing_if = "Option::is_none")] effects: Option, + #[serde(skip_serializing_if = "Option::is_none")] + death_message_type: Option, } const NAMES: &[&str] = &[ - "in_fire", - "lightning_bolt", - "on_fire", - "lava", - "hot_floor", - "in_wall", - "cramming", - "drown", - "starve", + "arrow", + "bad_respawn_point", "cactus", - "fall", - "fly_into_wall", - "out_of_world", - "generic", - "magic", - "wither", + "cramming", "dragon_breath", + "drown", "dry_out", - "sweet_berry_bush", + "explosion", + "fall", + "falling_anvil", + "falling_block", + "falling_stalactite", + "fireball", + "fireworks", + "fly_into_wall", "freeze", - "stalagmite", - // 1.20+ - "outside_border", + "generic", "generic_kill", + "hot_floor", + "in_fire", + "in_wall", + "indirect_magic", + "lava", + "lightning_bolt", + "magic", + "mob_attack", + "mob_attack_no_aggro", + "mob_projectile", + "on_fire", + "out_of_world", + "outside_border", + "player_attack", + "player_explosion", + "sonic_boom", + "spit", + "stalagmite", + "starve", + "sting", + "sweet_berry_bush", + "thorns", + "thrown", + "trident", + "unattributed_fireball", + "wither", + "wither_skull", ]; pub(super) fn all() -> Vec> { @@ -48,6 +71,7 @@ pub(super) fn all() -> Vec> { message_id: "inFire".into(), scaling: "when_caused_by_living_non_player".into(), effects: None, + death_message_type: Some("default".into()), }, }) .collect(); diff --git a/pumpkin/src/protocol/registry/dimensions.rs b/pumpkin/src/protocol/registry/dimensions.rs index db4cf2208..fd9782c04 100644 --- a/pumpkin/src/protocol/registry/dimensions.rs +++ b/pumpkin/src/protocol/registry/dimensions.rs @@ -2,24 +2,23 @@ use serde::Serialize; #[derive(Debug, Clone, Serialize)] pub struct Dimension { - ambient_light: f32, - bed_works: bool, - coordinate_scale: f32, - effects: String, - has_ceiling: bool, - has_raids: bool, + #[serde(skip_serializing_if = "Option::is_none")] + fixed_time: Option, has_skylight: bool, - height: i32, // 1.17+ - infiniburn: String, - logical_height: i32, - min_y: i32, // 1.17+ - natural: bool, - piglin_safe: bool, - fixed_time: i64, - respawn_anchor_works: bool, + has_ceiling: bool, ultrawarm: bool, - - // 1.19+ + natural: bool, + coordinate_scale: f64, + bed_works: bool, + respawn_anchor_works: bool, + min_y: i32, + height: i32, + logical_height: i32, + infiniburn: String, + effects: String, + ambient_light: f32, + piglin_safe: bool, + has_raids: bool, monster_spawn_light_level: i32, monster_spawn_block_light_limit: i32, } @@ -29,14 +28,14 @@ pub fn overworld(world_min_y: i32, world_height: u32) -> Dimension { piglin_safe: false, natural: true, ambient_light: 0.0, - fixed_time: 6000, + fixed_time: Some(6000.0), infiniburn: "#minecraft:infiniburn_overworld".into(), respawn_anchor_works: false, has_skylight: true, bed_works: true, effects: "minecraft:overworld".into(), has_raids: false, - logical_height: 128, + logical_height: 384, coordinate_scale: 1.0, ultrawarm: false, has_ceiling: false, diff --git a/pumpkin/src/protocol/registry/mod.rs b/pumpkin/src/protocol/registry/mod.rs index e21b4f21e..bca0f5a3f 100644 --- a/pumpkin/src/protocol/registry/mod.rs +++ b/pumpkin/src/protocol/registry/mod.rs @@ -1,6 +1,6 @@ use serde::Serialize; -use super::{bytebuf::buffer::ByteBuffer, nbt}; +use super::bytebuf::ByteBuffer; mod biomes; mod chat_type; @@ -32,12 +32,9 @@ struct CodecItem { element: T, } -pub fn write_single_dimension(out: &mut ByteBuffer, world_min_y: i32, world_height: u32) -where - std::io::Cursor: std::io::Write, -{ +pub fn write_single_dimension(out: &mut ByteBuffer, world_min_y: i32, world_height: u32) { let dimension = dimensions::overworld(world_min_y, world_height); - out.write_bytes(&nbt::to_nbt("", &dimension).unwrap().serialize()); + // out.put_slice(&crab_nbt::nbt!("", &dimension).unwrap().serialize()); } pub fn write_codec(out: &mut ByteBuffer, world_min_y: i32, world_height: u32) { @@ -67,9 +64,9 @@ pub fn write_codec(out: &mut ByteBuffer, world_min_y: i32, world_height: u32) { }; // Dimension codec - out.write_bytes(&nbt::to_nbt("", &info).unwrap().serialize()); + // out.put_slice(&nbt::to_nbt("", &info).unwrap().serialize()); // Current dimension type (key in dimension codec) - out.write_string("minecraft:overworld"); + out.put_string("minecraft:overworld"); // Current world - out.write_string("minecraft:overworld"); + out.put_string("minecraft:overworld"); } diff --git a/pumpkin/src/protocol/server/config/mod.rs b/pumpkin/src/protocol/server/config/mod.rs index b3a537a97..a42986825 100644 --- a/pumpkin/src/protocol/server/config/mod.rs +++ b/pumpkin/src/protocol/server/config/mod.rs @@ -1,6 +1,6 @@ use crate::{ entity::player::{ChatMode, Hand}, - protocol::{bytebuf::buffer::ByteBuffer, VarInt}, + protocol::{bytebuf::ByteBuffer, VarInt}, }; pub struct SClientInformation { @@ -15,18 +15,18 @@ pub struct SClientInformation { } impl SClientInformation { - pub const PACKET_ID: VarInt = 0; + pub const PACKET_ID: VarInt = 0x00; pub fn read(bytebuf: &mut ByteBuffer) -> Self { Self { - locale: bytebuf.read_string_len(16).unwrap(), - view_distance: bytebuf.read_i8().unwrap(), - chat_mode: ChatMode::from_varint(bytebuf.read_var_int().unwrap()), - chat_colors: bytebuf.read_bool().unwrap(), - skin_parts: bytebuf.read_u8().unwrap(), - main_hand: Hand::from_varint(bytebuf.read_var_int().unwrap()), - text_filtering: bytebuf.read_bool().unwrap(), - server_listing: bytebuf.read_bool().unwrap(), + locale: bytebuf.get_string_len(16).unwrap(), + view_distance: bytebuf.get_i8(), + chat_mode: ChatMode::from_varint(bytebuf.get_var_int()), + chat_colors: bytebuf.get_bool(), + skin_parts: bytebuf.get_u8(), + main_hand: Hand::from_varint(bytebuf.get_var_int()), + text_filtering: bytebuf.get_bool(), + server_listing: bytebuf.get_bool(), } } } @@ -34,9 +34,24 @@ impl SClientInformation { pub struct SAcknowledgeFinishConfig {} impl SAcknowledgeFinishConfig { - pub const PACKET_ID: VarInt = 3; + pub const PACKET_ID: VarInt = 0x03; pub fn read(_bytebuf: &mut ByteBuffer) -> Self { Self {} } } + +pub struct SKnownPacks { + known_pack_count: VarInt, + // known_packs: &'a [KnownPack] +} + +impl SKnownPacks { + pub const PACKET_ID: VarInt = 0x07; + + pub fn read(bytebuf: &mut ByteBuffer) -> Self { + Self { + known_pack_count: bytebuf.get_var_int(), + } + } +} diff --git a/pumpkin/src/protocol/server/handshake/mod.rs b/pumpkin/src/protocol/server/handshake/mod.rs index eaa9a6e98..b5e0049bc 100644 --- a/pumpkin/src/protocol/server/handshake/mod.rs +++ b/pumpkin/src/protocol/server/handshake/mod.rs @@ -1,4 +1,4 @@ -use crate::protocol::{bytebuf::buffer::ByteBuffer, ConnectionState, VarInt}; +use crate::protocol::{bytebuf::ByteBuffer, ConnectionState, VarInt}; pub struct SHandShake { pub protocol_version: VarInt, @@ -8,14 +8,14 @@ pub struct SHandShake { } impl SHandShake { - pub const PACKET_ID: VarInt = 0; + pub const PACKET_ID: VarInt = 0x00; pub fn read(bytebuf: &mut ByteBuffer) -> Self { Self { - protocol_version: bytebuf.read_var_int().unwrap(), - server_address: bytebuf.read_string_len(255).unwrap(), - server_port: bytebuf.read_u16().unwrap(), - next_state: ConnectionState::from_varint(bytebuf.read_var_int().unwrap()), + protocol_version: bytebuf.get_var_int(), + server_address: bytebuf.get_string_len(255).unwrap(), + server_port: bytebuf.get_u16(), + next_state: ConnectionState::from_varint(bytebuf.get_var_int()), } } } diff --git a/pumpkin/src/protocol/server/login/mod.rs b/pumpkin/src/protocol/server/login/mod.rs index 3ef70b46f..561420327 100644 --- a/pumpkin/src/protocol/server/login/mod.rs +++ b/pumpkin/src/protocol/server/login/mod.rs @@ -1,4 +1,4 @@ -use crate::protocol::{bytebuf::buffer::ByteBuffer, VarInt}; +use crate::protocol::{bytebuf::ByteBuffer, VarInt}; pub struct SLoginStart { pub name: String, // 16 @@ -6,12 +6,12 @@ pub struct SLoginStart { } impl SLoginStart { - pub const PACKET_ID: VarInt = 0; + pub const PACKET_ID: VarInt = 0x00; pub fn read(bytebuf: &mut ByteBuffer) -> Self { Self { - name: bytebuf.read_string_len(16).unwrap(), - uuid: bytebuf.read_uuid().unwrap(), + name: bytebuf.get_string_len(16).unwrap(), + uuid: bytebuf.get_uuid(), } } } @@ -24,18 +24,18 @@ pub struct SEncryptionResponse { } impl SEncryptionResponse { - pub const PACKET_ID: VarInt = 1; + pub const PACKET_ID: VarInt = 0x01; pub fn read(bytebuf: &mut ByteBuffer) -> Self { - let shared_secret_length = bytebuf.read_var_int().unwrap(); - let shared_secret = bytebuf.read_bytes(shared_secret_length as usize).unwrap(); - let verify_token_length = bytebuf.read_var_int().unwrap(); - let verify_token = bytebuf.read_bytes(shared_secret_length as usize).unwrap(); + let shared_secret_length = bytebuf.get_var_int(); + let shared_secret = bytebuf.copy_to_bytes(shared_secret_length as usize); + let verify_token_length = bytebuf.get_var_int(); + let verify_token = bytebuf.copy_to_bytes(shared_secret_length as usize); Self { shared_secret_length, - shared_secret, + shared_secret: shared_secret.to_vec(), verify_token_length, - verify_token, + verify_token: verify_token.to_vec(), } } } @@ -47,12 +47,12 @@ pub struct SLoginPluginResponse<'a> { } impl<'a> SLoginPluginResponse<'a> { - pub const PACKET_ID: VarInt = 2; + pub const PACKET_ID: VarInt = 0x02; pub fn read(bytebuf: &mut ByteBuffer) -> Self { Self { - message_id: bytebuf.read_var_int().unwrap(), - successful: bytebuf.read_bool().unwrap(), + message_id: bytebuf.get_var_int(), + successful: bytebuf.get_bool(), data: None, // TODO } } @@ -64,7 +64,7 @@ pub struct SLoginAcknowledged { } impl SLoginAcknowledged { - pub const PACKET_ID: VarInt = 3; + pub const PACKET_ID: VarInt = 0x03; pub fn read(_bytebuf: &mut ByteBuffer) -> Self { Self {} diff --git a/pumpkin/src/protocol/server/status/mod.rs b/pumpkin/src/protocol/server/status/mod.rs index 925a88634..fa10dcad3 100644 --- a/pumpkin/src/protocol/server/status/mod.rs +++ b/pumpkin/src/protocol/server/status/mod.rs @@ -1,11 +1,11 @@ -use crate::protocol::{bytebuf::buffer::ByteBuffer, VarInt}; +use crate::protocol::{bytebuf::ByteBuffer, VarInt}; pub struct SStatusRequest { // empty } impl SStatusRequest { - pub const PACKET_ID: VarInt = 0; + pub const PACKET_ID: VarInt = 0x00; pub fn read(_bytebuf: &mut ByteBuffer) -> Self { Self {} @@ -17,11 +17,11 @@ pub struct SPingRequest { } impl SPingRequest { - pub const PACKET_ID: VarInt = 1; + pub const PACKET_ID: VarInt = 0x01; pub fn read(bytebuf: &mut ByteBuffer) -> Self { Self { - payload: bytebuf.read_i64().unwrap(), + payload: bytebuf.get_i64(), } } } diff --git a/pumpkin/src/server.rs b/pumpkin/src/server.rs index d0eaab6bd..3ff33afb1 100644 --- a/pumpkin/src/server.rs +++ b/pumpkin/src/server.rs @@ -17,10 +17,10 @@ use crate::{ }, protocol::{ client::{ - config::{CKnownPacks, CRegistryData, Entry, KnownPack}, + config::{CFinishConfig, CKnownPacks, CPluginMessage, CRegistryData, Entry}, play::CLogin, }, - Players, Sample, StatusResponse, VarInt, Version, + Players, Sample, StatusResponse, VarInt, VarInt32, Version, }, world::World, }; @@ -94,23 +94,6 @@ impl Server { entity_id: self.new_entity_id(), }, }; - // known data packs - client.send_packet(CKnownPacks::new( - 1, - vec![KnownPack { - namespace: "minecraft".to_string(), - id: "core".to_string(), - version: "1.21".to_string(), - }], - )); - client.send_packet(CRegistryData::new( - "0".into(), - 1, - vec![Entry { - entry_id: "minecraft:dimension_type".into(), - has_data: true, - }], - )); client.send_packet(CLogin::new( player.entity_id(), @@ -145,6 +128,18 @@ impl Server { self.entity_id.fetch_add(1, Ordering::SeqCst) } + pub fn send_brand(client: &mut Client) { + // send server brand + let brand = "pumpkin"; + let mut buf = vec![]; + let _ = VarInt32(brand.len() as i32).encode(&mut buf); + buf.extend_from_slice(brand.as_bytes()); + client.send_packet(CPluginMessage::new( + "minecraft:brand".to_string(), + buf.as_slice(), + )) + } + pub fn default_response( config: &(BasicConfiguration, AdvancedConfiguration), ) -> StatusResponse {