move to tokio's bytes crate

This commit is contained in:
Snowiiii
2024-07-31 16:31:09 +02:00
parent d1e3c8eaac
commit 90f16ab977
31 changed files with 685 additions and 2676 deletions

43
Cargo.lock generated
View File

@@ -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",

View File

@@ -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
- [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

View File

@@ -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"

View File

@@ -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());
}

View File

@@ -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

View File

@@ -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<aes::Aes128>;
@@ -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)),
}))
}

View File

@@ -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<aes::Aes128>;
@@ -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;

View File

@@ -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<ProtocolVersion>,
tx: Sender<clientbound::Packet>,
rx: Receiver<clientbound::Packet>,
token: Token,
incoming: Vec<u8>,
outgoing: Vec<u8>,
garbage: Vec<u8>,
}
#[derive(Debug, Clone)]
pub struct ConnSender {
tx: Sender<cb::Packet>,
wake: Sender<WakeEvent>,
waker: Arc<Waker>,
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<NewConn>, Vec<serverbound::Packet>)> {
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<NewConn>, Vec<serverbound::Packet>)> {
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))
}
}

View File

@@ -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<u8>,
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<Vec<u8>> for ByteBuffer {
fn from(val: Vec<u8>) -> Self {
ByteBuffer::from_vec(val)
}
}
impl From<ByteBuffer> for Vec<u8> {
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<usize> {
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<usize> {
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<u8>) -> 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<Vec<u8>> {
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::<u8>::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<u8> {
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<bool> {
Ok(self.read_u8()? != 0)
}
/// Same as `read_u8()` but for signed values
pub fn read_i8(&mut self) -> Result<i8> {
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<u16> {
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<i16> {
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<u32> {
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<i32> {
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<u64> {
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<T>(&mut self, val: impl FnOnce(&mut ByteBuffer) -> T) -> Result<Option<T>> {
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<T>(&mut self, val: &Option<T>, 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<VarInt> {
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<VarLong> {
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<i64> {
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<f32> {
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<f64> {
read_number!(self, read_f64, 8)
}
pub fn read_list<T>(&mut self, val: impl Fn(&mut ByteBuffer) -> Result<T>) -> Result<Vec<T>> {
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<T>(&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<Vec<i32>> {
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<NBT> {
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<String> {
self.read_string_len(32767)
}
pub fn read_string_len(&mut self, max_size: usize) -> Result<String> {
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<uuid::Uuid> {
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<u8>.
#[deprecated(
since = "2.1.0",
note = "use `as_bytes().to_vec()` or `into_vec()` instead"
)]
pub fn into_bytes(&self) -> Vec<u8> {
self.data.to_vec()
}
/// Return the raw byte buffer as a Vec<u8>.
pub fn into_vec(self) -> Vec<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 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<bool> {
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<u64> {
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);
}
}
}

View File

@@ -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<String, io::Error> {
self.get_string_len(32767)
}
pub fn get_string_len(&mut self, max_size: usize) -> Result<String, io::Error> {
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<T>(&mut self, val: impl FnOnce(&mut Self) -> T) -> Option<T> {
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<T>(&mut self, val: &Option<T>, write: impl FnOnce(&mut Self, &T)) {
self.put_bool(val.is_some());
match val {
Some(v) => write(self, v),
None => {}
}
}
pub fn get_list<T>(&mut self, val: impl Fn(&mut Self) -> T) -> Vec<T> {
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<T>(&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<crab_nbt::NbtTag> {
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)
}
}

View File

@@ -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<usize> {
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<Vec<u8>> {
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::<u8>::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<u8> {
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<i8> {
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<u16> {
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<i16> {
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<u32> {
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<i32> {
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<u64> {
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<i64> {
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<f32> {
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<f64> {
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<String> {
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<bool> {
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<u64> {
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
}
}

View File

@@ -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<KnownPack>,
known_packs: &'a [KnownPack],
}
impl CKnownPacks {
pub fn new(count: VarInt, known_packs: Vec<KnownPack>) -> 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::<KnownPack>(&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::<KnownPack>(&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::<Entry>(&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::<Entry>(&self.entries, |p, v| {
p.put_string(&v.entry_id);
p.put_bool(v.has_data);
registry::write_single_dimension(p, -64, 320);
});
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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());
}
}

View File

@@ -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,
}

View File

@@ -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<FromUtf8Error> for ParseError {
fn from(e: FromUtf8Error) -> ParseError {
ParseError::InvalidString(e)
}
}
impl From<io::Error> for ParseError {
fn from(e: io::Error) -> ParseError {
ParseError::IO(e)
}
}
impl Error for ParseError {}
impl NBT {
pub fn deserialize_file(buf: Vec<u8>) -> Result<Self, ParseError> {
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<u8>) -> Result<Self, ParseError> {
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<Self, ParseError> {
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<Self, ParseError> {
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)),
}
}
}

View File

@@ -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<T> = std::result::Result<T, Error>;
impl ser::Error for Error {
fn custom<T: Display>(msg: T) -> Self {
Error::Message(msg.to_string())
}
}
impl de::Error for Error {
fn custom<T: Display>(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 {}

View File

@@ -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<T>(name: &str, value: &T) -> anyhow::Result<NBT>
where
T: Serialize,
{
Ok(NBT::new(name, to_tag(value)?))
}
pub fn to_tag<T>(value: &T) -> anyhow::Result<Tag>
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<Tag>,
}
pub struct MapSerializer<'a> {
ser: &'a mut Serializer,
key: Option<String>,
items: HashMap<String, Tag>,
}
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<T>(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<T>(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<usize>) -> Result<Self::SerializeSeq> {
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::SerializeTuple> {
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::SerializeTupleStruct> {
self.serialize_seq(Some(len))
}
// Maps are represented in JSON as `{ K: V, K: V, ... }`.
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
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::SerializeStruct> {
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<T>(
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<Self::SerializeTupleVariant> {
Err(Error::Enum)
}
fn serialize_struct_variant(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_len: usize,
) -> Result<Self::SerializeStructVariant> {
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<T>(&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<T>(&mut self, value: &T) -> Result<()>
where
T: ?Sized + Serialize,
{
<Self as ser::SerializeSeq>::serialize_element(self, value)
}
fn end(self) -> Result<()> {
<Self as ser::SerializeSeq>::end(self)
}
}
// Same thing but for tuple structs.
impl<'a> ser::SerializeTupleStruct for SeqSerializer<'a> {
type Ok = ();
type Error = Error;
fn serialize_field<T>(&mut self, value: &T) -> Result<()>
where
T: ?Sized + Serialize,
{
<Self as ser::SerializeSeq>::serialize_element(self, value)
}
fn end(self) -> Result<()> {
<Self as ser::SerializeSeq>::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<T>(&mut self, value: &T) -> Result<()>
where
T: ?Sized + Serialize,
{
<Self as ser::SerializeSeq>::serialize_element(self, value)
}
fn end(self) -> Result<()> {
<Self as ser::SerializeSeq>::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<T>(&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<T>(&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<T>(&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<T>(&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(())
}
}

View File

@@ -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<u8>),
String(String),
List(Vec<Tag>), // 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<i32>),
LongArray(Vec<i64>),
}
/// An NBT Compound tag. This is essentially a map, with some extra helper
/// functions.
#[derive(Debug, Clone, PartialEq)]
pub struct Compound {
pub inner: HashMap<String, Tag>,
}
impl Compound {
pub fn new() -> Self {
Compound {
inner: HashMap::new(),
}
}
pub fn insert(&mut self, key: impl Into<String>, value: impl Into<Tag>) {
self.inner.insert(key.into(), value.into());
}
pub fn get_or_create_compound(&mut self, key: impl Into<String>) -> &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<str>) -> bool {
self.inner.contains_key(key.as_ref())
}
pub fn iter(&self) -> std::collections::hash_map::Iter<String, Tag> {
self.inner.iter()
}
pub fn iter_mut(&mut self) -> std::collections::hash_map::IterMut<String, Tag> {
self.inner.iter_mut()
}
}
impl IntoIterator for Compound {
type Item = (String, Tag);
type IntoIter = std::collections::hash_map::IntoIter<String, Tag>;
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<HashMap<String, Tag>> for Compound {
fn from(v: HashMap<String, Tag>) -> Self {
Compound { inner: v }
}
}
impl Index<&str> for Compound {
type Output = Tag;
fn index(&self, index: &str) -> &Tag {
&self.inner[index]
}
}
impl From<bool> 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<String> for Tag {
fn from(s: String) -> Self {
Tag::String(s)
}
}
impl From<HashMap<String, Tag>> for Tag {
fn from(v: HashMap<String, Tag>) -> Self {
Tag::Compound(Compound::from(v))
}
}
impl<T> From<Vec<T>> for Tag
where
Tag: From<T>,
{
fn from(list: Vec<T>) -> 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<Tag>));
getter!(compound -> Compound(&Compound));
getter!(long_arr -> LongArray(&Vec<i64>));
pub fn compound_mut(&mut self) -> Result<&mut Compound, WrongTag> {
match self {
Self::Compound(v) => Ok(v),
_ => Err(WrongTag(self.clone())),
}
}
}

View File

@@ -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<u8> {
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);
}
}
}
}
}

View File

@@ -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<String>,
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<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
grass_color: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
mood_sound: Option<MoodSound>, // 1.18.2+
grass_color_modifier: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
particle: Option<Particle>,
#[serde(skip_serializing_if = "Option::is_none")]
ambient_sound: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
mood_sound: Option<MoodSound>,
#[serde(skip_serializing_if = "Option::is_none")]
additions_sound: Option<AdditionsSound>,
#[serde(skip_serializing_if = "Option::is_none")]
music: Option<Music>,
}
#[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<VarInt>,
}
#[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<CodecItem<Biome>> {
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,
},
};

View File

@@ -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<String>,
struct Decoration {
translation_key: String,
// style: Option<>
parameters: Vec<String>,
}
pub(super) fn all() -> Vec<CodecItem<ChatType>> {
@@ -17,11 +18,11 @@ pub(super) fn all() -> Vec<CodecItem<ChatType>> {
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(),
},

View File

@@ -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<String>,
#[serde(skip_serializing_if = "Option::is_none")]
death_message_type: Option<String>,
}
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<CodecItem<DamageType>> {
@@ -48,6 +71,7 @@ pub(super) fn all() -> Vec<CodecItem<DamageType>> {
message_id: "inFire".into(),
scaling: "when_caused_by_living_non_player".into(),
effects: None,
death_message_type: Some("default".into()),
},
})
.collect();

View File

@@ -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<f64>,
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,

View File

@@ -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<T> {
element: T,
}
pub fn write_single_dimension<T>(out: &mut ByteBuffer, world_min_y: i32, world_height: u32)
where
std::io::Cursor<T>: 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");
}

View File

@@ -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(),
}
}
}

View File

@@ -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()),
}
}
}

View File

@@ -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 {}

View File

@@ -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(),
}
}
}

View File

@@ -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 {