Skip to content

Commit

Permalink
add nbt
Browse files Browse the repository at this point in the history
  • Loading branch information
Snowiiii committed Jul 30, 2024
1 parent a1b08a6 commit 5851ce5
Show file tree
Hide file tree
Showing 17 changed files with 1,236 additions and 176 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
/target
configuration.toml
features.toml
14 changes: 0 additions & 14 deletions configuration.toml

This file was deleted.

2 changes: 0 additions & 2 deletions features.toml

This file was deleted.

25 changes: 24 additions & 1 deletion pumpkin/src/protocol/bytebuf/buffer.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::protocol::{nbt::NBT, VarInt, VarLong};
use crate::protocol::{nbt::nbt::NBT, VarInt, VarLong};

use super::{Endian, CONTINUE_BIT, SEGMENT_BITS};
use byteorder::{BigEndian, ByteOrder, LittleEndian};
Expand Down Expand Up @@ -618,6 +618,29 @@ impl ByteBuffer {
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),
Expand Down
90 changes: 67 additions & 23 deletions pumpkin/src/protocol/client/config/mod.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,4 @@
use crate::protocol::{nbt::NBT, ClientPacket, VarInt};

pub struct CRegistryData {
registry_id: String,
entry_count: VarInt,
entries: NBT,
}

struct Entry {
entry_id: String,
has_data: bool,
data: NBT,
}

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_array(self.entries);
}
}
use crate::protocol::{registry, ClientPacket, VarInt};

pub struct CCookieRequest {
// TODO
Expand Down Expand Up @@ -69,3 +47,69 @@ impl ClientPacket for CFinishConfig {

fn write(&self, _bytebuf: &mut crate::protocol::bytebuf::buffer::ByteBuffer) {}
}

pub struct CKnownPacks {
count: VarInt,
known_packs: Vec<KnownPack>,
}

impl CKnownPacks {
pub fn new(count: VarInt, known_packs: Vec<KnownPack>) -> Self {
Self { count, known_packs }
}
}

pub struct KnownPack {
pub namespace: String,
pub id: String,
pub version: String,
}

impl ClientPacket for CKnownPacks {
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);
});
}
}

pub struct CRegistryData {
registry_id: String,
entry_count: VarInt,
entries: Vec<Entry>,
}

impl CRegistryData {
pub fn new(registry_id: String, entry_count: VarInt, entries: Vec<Entry>) -> Self {
Self {
registry_id,
entry_count,
entries,
}
}
}

pub struct Entry {
pub entry_id: String,
pub has_data: bool,
// data provided by registry::write_codec
}

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);
});
}
}
1 change: 0 additions & 1 deletion pumpkin/src/protocol/client/play/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

use crate::{
entity::player::GameMode,
protocol::{ClientPacket, VarInt},
Expand Down
97 changes: 62 additions & 35 deletions pumpkin/src/protocol/nbt/deserialize.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,52 @@
use std::{collections::HashMap, error::Error, fmt, string::FromUtf8Error};
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::{Tag, NBT};

#[derive(Debug)]
pub enum ParseError {
InvalidType(u8),
InvalidString(FromUtf8Error),
}
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::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(buf: Vec<u8>) -> Result<Self, ParseError> {
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
Expand All @@ -32,37 +55,41 @@ impl NBT {
/// 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().unwrap();
let len = buf.read_u16().unwrap();
let name = String::from_utf8(buf.read_bytes(len as usize).unwrap()).unwrap();
Ok(NBT::new(&name, Tag::deserialize(ty, buf)?))
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().unwrap())),
2 => Ok(Self::Short(buf.read_i16().unwrap())),
3 => Ok(Self::Int(buf.read_i32().unwrap())),
4 => Ok(Self::Long(buf.read_i64().unwrap())),
5 => Ok(Self::Float(buf.read_f32().unwrap())),
6 => Ok(Self::Double(buf.read_f64().unwrap())),
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().unwrap();
Ok(Self::ByteArr(buf.read_bytes(len as usize).unwrap()))
let len = buf.read_i32()?;
Ok(Self::ByteArr(buf.read_bytes(len as usize)?))
}
8 => {
let len = buf.read_u16().unwrap();
match String::from_utf8(buf.read_bytes(len as usize).unwrap()) {
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().unwrap();
let len = buf.read_i32().unwrap();
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)?);
Expand All @@ -72,30 +99,30 @@ impl Tag {
10 => {
let mut inner = HashMap::new();
loop {
let ty = buf.read_u8().unwrap();
let ty = buf.read_u8()?;
if ty == Self::End.ty() {
break;
}
let len = buf.read_u16().unwrap();
let name = String::from_utf8(buf.read_bytes(len as usize).unwrap()).unwrap();
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(Self::Compound(inner))
Ok(inner.into())
}
11 => {
let len = buf.read_i32().unwrap();
let len = buf.read_i32()?;
let mut inner = Vec::with_capacity(len as usize);
for _ in 0..len {
inner.push(buf.read_i32().unwrap());
inner.push(buf.read_i32()?);
}
Ok(Self::IntArray(inner))
}
12 => {
let len = buf.read_i32().unwrap();
let len = buf.read_i32()?;
let mut inner = Vec::with_capacity(len as usize);
for _ in 0..len {
inner.push(buf.read_i64().unwrap());
inner.push(buf.read_i64()?);
}
Ok(Self::LongArray(inner))
}
Expand Down
56 changes: 56 additions & 0 deletions pumpkin/src/protocol/nbt/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
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 {}
Loading

0 comments on commit 5851ce5

Please sign in to comment.