Skip to content

Commit

Permalink
replace everything with pumpkin_nbt
Browse files Browse the repository at this point in the history
  • Loading branch information
kralverde committed Feb 14, 2025
1 parent 99e61a0 commit f458072
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 73 deletions.
44 changes: 30 additions & 14 deletions pumpkin-nbt/src/deserializer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::*;
use io::Read;
use serde::de::{self, DeserializeSeed, MapAccess, SeqAccess, Visitor};
use serde::de::{self, DeserializeSeed, IntoDeserializer, MapAccess, SeqAccess, Visitor};
use serde::{forward_to_deserialize_any, Deserialize};

pub type Result<T> = std::result::Result<T, Error>;
Expand Down Expand Up @@ -54,15 +54,6 @@ impl<R: Read> ReadAdaptor<R> {
Ok(u16::from_be_bytes(buf))
}

pub fn get_u32_be(&mut self) -> Result<u32> {
let mut buf = [0u8; 4];
self.reader
.read_exact(&mut buf)
.map_err(Error::Incomplete)?;

Ok(u32::from_be_bytes(buf))
}

pub fn get_i32_be(&mut self) -> Result<i32> {
let mut buf = [0u8; 4];
self.reader
Expand Down Expand Up @@ -151,7 +142,7 @@ impl<'de, R: Read> de::Deserializer<'de> for &mut Deserializer<R> {

forward_to_deserialize_any! {
i8 i16 i32 i64 f32 f64 char str string unit unit_struct seq tuple tuple_struct
ignored_any bytes enum newtype_struct byte_buf option
ignored_any bytes newtype_struct byte_buf
}

fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
Expand All @@ -169,7 +160,11 @@ impl<'de, R: Read> de::Deserializer<'de> for &mut Deserializer<R> {
};

if let Some(list_type) = list_type {
let remaining_values = self.input.get_u32_be()?;
let remaining_values = self.input.get_i32_be()?;
if remaining_values < 0 {
return Err(Error::NegativeLength(remaining_values));
}

return visitor.visit_seq(ListAccess {
de: self,
list_type,
Expand Down Expand Up @@ -254,6 +249,27 @@ impl<'de, R: Read> de::Deserializer<'de> for &mut Deserializer<R> {
}
}

fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value>
where
V: Visitor<'de>,
{
let variant = get_nbt_string(&mut self.input)?;
visitor.visit_enum(variant.into_deserializer())
}

fn deserialize_option<V>(self, visitor: V) -> std::result::Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
// None is not encoded, so no need for it
visitor.visit_some(self)
}

fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
Expand Down Expand Up @@ -330,7 +346,7 @@ impl<'de, R: Read> MapAccess<'de> for CompoundAccess<'_, R> {

struct ListAccess<'a, R: Read> {
de: &'a mut Deserializer<R>,
remaining_values: u32,
remaining_values: i32,
list_type: u8,
}

Expand All @@ -341,7 +357,7 @@ impl<'de, R: Read> SeqAccess<'de> for ListAccess<'_, R> {
where
E: DeserializeSeed<'de>,
{
if self.remaining_values == 0 {
if self.remaining_values <= 0 {
return Ok(None);
}

Expand Down
2 changes: 2 additions & 0 deletions pumpkin-nbt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,8 @@ mod test {
let mut serialized = Vec::new();
to_bytes(&*LEVEL_DAT, &mut serialized).expect("Failed to encode to bytes");

assert!(!serialized.is_empty());

let level_dat_again: LevelDat =
from_bytes(&serialized[..]).expect("Failed to decode from bytes");

Expand Down
36 changes: 16 additions & 20 deletions pumpkin-nbt/src/serializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,12 +263,12 @@ impl<W: Write> ser::Serializer for &mut Serializer<W> {

fn serialize_str(self, v: &str) -> Result<()> {
self.parse_state(STRING_ID)?;

NbtTag::String(v.to_string()).serialize_data(&mut self.output)?;

if self.state == State::MapKey {
self.state = State::Named(v.to_string());
return Ok(());
}

NbtTag::String(v.to_string()).serialize_data(&mut self.output)?;
Ok(())
}

Expand Down Expand Up @@ -355,10 +355,13 @@ impl<W: Write> ser::Serializer for &mut Serializer<W> {
}

fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq> {
if len.is_none() {
let Some(len) = len else {
return Err(Error::SerdeError(
"Length of the sequence must be known first!".to_string(),
));
};
if len > i32::MAX as usize {
return Err(Error::LargeLength(len));
}

match &mut self.state {
Expand All @@ -375,19 +378,18 @@ impl<W: Write> ser::Serializer for &mut Serializer<W> {
};
self.parse_state(id)?;

let len = len.unwrap();
if len > i32::MAX as usize {
return Err(Error::LargeLength(len));
}

self.output.write_i32_be(len as i32)?;
self.state = State::ListElement;
}
_ => {
self.parse_state(LIST_ID)?;
self.state = State::FirstListElement {
len: len.unwrap() as i32,
};
self.state = State::FirstListElement { len: len as i32 };
if len == 0 {
// If we have no elements, FirstListElement state will never be invoked; so
// write the list type and length here.
self.output.write_u8_be(END_ID)?;
self.output.write_i32_be(0)?;
}
}
}

Expand Down Expand Up @@ -428,20 +430,14 @@ impl<W: Write> ser::Serializer for &mut Serializer<W> {
}

fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct> {
self.output.write_u8_be(COMPOUND_ID)?;

match &mut self.state {
State::Root(root_name) => {
self.output.write_u8_be(COMPOUND_ID)?;
if let Some(root_name) = root_name {
NbtTag::String(root_name.clone()).serialize_data(&mut self.output)?;
}
}
State::Named(string) => {
NbtTag::String(string.clone()).serialize_data(&mut self.output)?;
}
_ => {
unimplemented!()
}
_ => self.parse_state(COMPOUND_ID)?,
}

Ok(self)
Expand Down
1 change: 1 addition & 0 deletions pumpkin-registry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ impl Registry {
.iter()
.map(|(name, nbt)| RegistryEntry::from_nbt(name, nbt))
.collect();

let chat_type = Registry {
registry_id: Identifier::vanilla("chat_type"),
registry_entries,
Expand Down
3 changes: 1 addition & 2 deletions pumpkin-world/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ indexmap = "2.7"

enum_dispatch = "0.3"

fastnbt = { git = "https://github.com/owengage/fastnbt.git" }

noise = "0.9"
rand = "0.8"

Expand All @@ -49,6 +47,7 @@ serde_json5 = { git = "https://github.com/kralverde/serde_json5.git" }
derive-getters = "0.5.0"
[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports"] }
temp-dir = "0.1.14"

[[bench]]
name = "chunk_noise_populate"
Expand Down
8 changes: 5 additions & 3 deletions pumpkin-world/src/chunk/anvil.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use bytes::*;
use fastnbt::LongArray;
use flate2::bufread::{GzDecoder, GzEncoder, ZlibDecoder, ZlibEncoder};
use indexmap::IndexMap;
use pumpkin_config::ADVANCED_CONFIG;
use pumpkin_nbt::serializer::to_bytes;
use pumpkin_util::math::ceil_log2;
use std::time::{SystemTime, UNIX_EPOCH};
use std::{
Expand Down Expand Up @@ -425,7 +425,7 @@ impl AnvilChunkFormat {
sections.push(ChunkSection {
y: i as i8 - 4,
block_states: Some(ChunkSectionBlockStates {
data: Some(LongArray::new(section_longs)),
data: Some(section_longs.into_boxed_slice()),
palette: palette
.into_iter()
.map(|entry| PaletteEntry {
Expand All @@ -446,7 +446,9 @@ impl AnvilChunkFormat {
sections,
};

fastnbt::to_bytes(&nbt).map_err(ChunkSerializingError::ErrorSerializingChunk)
let mut result = Vec::new();
to_bytes(&nbt, &mut result).map_err(ChunkSerializingError::ErrorSerializingChunk)?;
Ok(result)
}

/// Returns the next free writable sector
Expand Down
24 changes: 12 additions & 12 deletions pumpkin-world/src/chunk/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use dashmap::{
mapref::one::{Ref, RefMut},
DashMap,
};
use fastnbt::LongArray;
use pumpkin_data::chunk::ChunkStatus;
use pumpkin_nbt::deserializer::from_bytes;
use pumpkin_util::math::{ceil_log2, vector2::Vector2};
use serde::{Deserialize, Serialize};
use std::{
Expand Down Expand Up @@ -168,9 +168,9 @@ struct PaletteEntry {
#[serde(rename_all = "UPPERCASE")]
pub struct ChunkHeightmaps {
// #[serde(with = "LongArray")]
motion_blocking: LongArray,
motion_blocking: Box<[i64]>,
// #[serde(with = "LongArray")]
world_surface: LongArray,
world_surface: Box<[i64]>,
}

#[derive(Serialize, Deserialize, Debug)]
Expand All @@ -183,7 +183,7 @@ struct ChunkSection {
#[derive(Serialize, Deserialize, Debug, Clone)]
struct ChunkSectionBlockStates {
// #[serde(with = "LongArray")]
data: Option<LongArray>,
data: Option<Box<[i64]>>,
palette: Vec<PaletteEntry>,
}

Expand Down Expand Up @@ -234,8 +234,8 @@ impl Default for ChunkHeightmaps {
fn default() -> Self {
Self {
// 0 packed into an i64 7 times.
motion_blocking: LongArray::new(vec![0; 37]),
world_surface: LongArray::new(vec![0; 37]),
motion_blocking: vec![0; 37].into_boxed_slice(),
world_surface: vec![0; 37].into_boxed_slice(),
}
}
}
Expand Down Expand Up @@ -402,15 +402,15 @@ impl ChunkData {
chunk_data: &[u8],
position: Vector2<i32>,
) -> Result<Self, ChunkParsingError> {
if fastnbt::from_bytes::<ChunkStatusWrapper>(chunk_data)
.map_err(|_| ChunkParsingError::FailedReadStatus)?
if from_bytes::<ChunkStatusWrapper>(chunk_data)
.map_err(ChunkParsingError::FailedReadStatus)?
.status
!= ChunkStatus::Full
{
return Err(ChunkParsingError::ChunkNotGenerated);
}

let chunk_data = fastnbt::from_bytes::<ChunkNbt>(chunk_data)
let chunk_data = from_bytes::<ChunkNbt>(chunk_data)
.map_err(|e| ChunkParsingError::ErrorDeserializingChunk(e.to_string()))?;

if chunk_data.x_pos != position.x || chunk_data.z_pos != position.z {
Expand Down Expand Up @@ -502,8 +502,8 @@ impl ChunkData {

#[derive(Error, Debug)]
pub enum ChunkParsingError {
#[error("Failed reading chunk status")]
FailedReadStatus,
#[error("Failed reading chunk status {0}")]
FailedReadStatus(pumpkin_nbt::Error),
#[error("The chunk isn't generated yet")]
ChunkNotGenerated,
#[error("Error deserializing chunk: {0}")]
Expand All @@ -517,5 +517,5 @@ fn convert_index(index: ChunkRelativeBlockCoordinates) -> usize {
#[derive(Error, Debug)]
pub enum ChunkSerializingError {
#[error("Error serializing chunk: {0}")]
ErrorSerializingChunk(fastnbt::error::Error),
ErrorSerializingChunk(pumpkin_nbt::Error),
}
Loading

0 comments on commit f458072

Please sign in to comment.