aboutsummaryrefslogtreecommitdiff
path: root/azalea-nbt/src/encode.rs
diff options
context:
space:
mode:
Diffstat (limited to 'azalea-nbt/src/encode.rs')
-rwxr-xr-x[-rw-r--r--]azalea-nbt/src/encode.rs231
1 files changed, 164 insertions, 67 deletions
diff --git a/azalea-nbt/src/encode.rs b/azalea-nbt/src/encode.rs
index 9ce4faf4..20d13793 100644..100755
--- a/azalea-nbt/src/encode.rs
+++ b/azalea-nbt/src/encode.rs
@@ -2,96 +2,197 @@ use crate::Error;
use crate::Tag;
use byteorder::{WriteBytesExt, BE};
use flate2::write::{GzEncoder, ZlibEncoder};
+use std::collections::HashMap;
use std::io::Write;
+// who needs friends when you've got code that runs in nanoseconds?
+
#[inline]
fn write_string(writer: &mut dyn Write, string: &str) -> Result<(), Error> {
- writer
- .write_i16::<BE>(string.len() as i16)
- .map_err(|_| Error::WriteError)?;
- writer
- .write_all(string.as_bytes())
- .map_err(|_| Error::WriteError)?;
+ writer.write_i16::<BE>(string.len() as i16)?;
+ writer.write_all(string.as_bytes())?;
Ok(())
}
-impl Tag {
- pub fn write_without_end(&self, writer: &mut dyn Write) -> Result<(), Error> {
- match self {
+#[inline]
+fn write_compound(
+ writer: &mut dyn Write,
+ value: &HashMap<String, Tag>,
+ end_tag: bool,
+) -> Result<(), Error> {
+ for (key, tag) in value {
+ match tag {
Tag::End => {}
- Tag::Byte(value) => writer.write_i8(*value).map_err(|_| Error::WriteError)?,
- Tag::Short(value) => writer
- .write_i16::<BE>(*value)
- .map_err(|_| Error::WriteError)?,
- Tag::Int(value) => writer
- .write_i32::<BE>(*value)
- .map_err(|_| Error::WriteError)?,
- Tag::Long(value) => writer
- .write_i64::<BE>(*value)
- .map_err(|_| Error::WriteError)?,
- Tag::Float(value) => writer
- .write_f32::<BE>(*value)
- .map_err(|_| Error::WriteError)?,
- Tag::Double(value) => writer
- .write_f64::<BE>(*value)
- .map_err(|_| Error::WriteError)?,
+ Tag::Byte(value) => {
+ writer.write_u8(1)?;
+ write_string(writer, key)?;
+ writer.write_i8(*value)?
+ }
+ Tag::Short(value) => {
+ writer.write_u8(2)?;
+ write_string(writer, key)?;
+ writer.write_i16::<BE>(*value)?
+ }
+ Tag::Int(value) => {
+ writer.write_u8(3)?;
+ write_string(writer, key)?;
+ writer.write_i32::<BE>(*value)?
+ }
+ Tag::Long(value) => {
+ writer.write_u8(4)?;
+ write_string(writer, key)?;
+ writer.write_i64::<BE>(*value)?
+ }
+ Tag::Float(value) => {
+ writer.write_u8(5)?;
+ write_string(writer, key)?;
+ writer.write_f32::<BE>(*value)?
+ }
+ Tag::Double(value) => {
+ writer.write_u8(6)?;
+ write_string(writer, key)?;
+ writer.write_f64::<BE>(*value)?
+ }
Tag::ByteArray(value) => {
- writer
- .write_i32::<BE>(value.len() as i32)
- .map_err(|_| Error::WriteError)?;
+ writer.write_u8(7)?;
+ write_string(writer, key)?;
+ writer.write_i32::<BE>(value.len() as i32)?;
for &byte in value {
- writer.write_i8(byte).map_err(|_| Error::WriteError)?;
+ writer.write_i8(byte)?;
}
}
Tag::String(value) => {
- write_string(writer, value)?;
+ writer.write_u8(8)?;
+ write_string(writer, key)?;
+ write_string(writer, value)?
}
Tag::List(value) => {
- // we just get the type from the first item, or default the type to END
- if value.is_empty() {
- writer.write_i8(0).map_err(|_| Error::WriteError)?;
- writer.write_i32::<BE>(0).map_err(|_| Error::WriteError)?;
- } else {
- let type_id = value[0].id();
- writer.write_u8(type_id).map_err(|_| Error::WriteError)?;
- writer
- .write_i32::<BE>(value.len() as i32)
- .map_err(|_| Error::WriteError)?;
- for tag in value {
- tag.write_without_end(writer)?;
- }
- }
+ writer.write_u8(9)?;
+ write_string(writer, key)?;
+ write_list(writer, value)?
}
Tag::Compound(value) => {
- for (key, tag) in value {
- writer.write_u8(tag.id()).map_err(|_| Error::WriteError)?;
- write_string(writer, key)?;
- tag.write_without_end(writer)?;
- }
- writer
- .write_u8(Tag::End.id())
- .map_err(|_| Error::WriteError)?;
+ writer.write_u8(10)?;
+ write_string(writer, key)?;
+ write_compound(writer, value, true)?
}
Tag::IntArray(value) => {
- writer
- .write_i32::<BE>(value.len() as i32)
- .map_err(|_| Error::WriteError)?;
+ writer.write_u8(11)?;
+ write_string(writer, key)?;
+ writer.write_i32::<BE>(value.len() as i32)?;
for &int in value {
- writer.write_i32::<BE>(int).map_err(|_| Error::WriteError)?;
+ writer.write_i32::<BE>(int)?;
}
}
Tag::LongArray(value) => {
- writer
- .write_i32::<BE>(value.len() as i32)
- .map_err(|_| Error::WriteError)?;
+ writer.write_u8(12)?;
+ write_string(writer, key)?;
+ writer.write_i32::<BE>(value.len() as i32)?;
for &long in value {
- writer
- .write_i64::<BE>(long)
- .map_err(|_| Error::WriteError)?;
+ writer.write_i64::<BE>(long)?;
+ }
+ }
+ }
+ }
+ if end_tag {
+ writer.write_u8(Tag::End.id())?;
+ }
+ return Ok(());
+}
+
+#[inline]
+fn write_list(writer: &mut dyn Write, value: &[Tag]) -> Result<(), Error> {
+ // we just get the type from the first item, or default the type to END
+ if value.is_empty() {
+ writer.write_all(&[0; 5])?;
+ } else {
+ let first_tag = &value[0];
+ writer.write_u8(first_tag.id())?;
+ writer.write_i32::<BE>(value.len() as i32)?;
+ match first_tag {
+ Tag::Int(_) => {
+ for tag in value {
+ writer.write_i32::<BE>(
+ *tag.as_int().expect("List of Int should only contains Int"),
+ )?;
+ }
+ }
+ Tag::String(_) => {
+ for tag in value {
+ write_string(
+ writer,
+ tag.as_string()
+ .expect("List of String should only contain String"),
+ )?;
+ }
+ }
+ Tag::Compound(_) => {
+ for tag in value {
+ write_compound(
+ writer,
+ tag.as_compound()
+ .expect("List of Compound should only contain Compound"),
+ true,
+ )?;
+ }
+ }
+ _ => {
+ for tag in value {
+ tag.write_without_end(writer)?;
}
}
}
+ }
+
+ Ok(())
+}
+
+#[inline]
+fn write_bytearray(writer: &mut dyn Write, value: &Vec<i8>) -> Result<(), Error> {
+ writer.write_i32::<BE>(value.len() as i32)?;
+ for &byte in value {
+ writer.write_i8(byte)?;
+ }
+ Ok(())
+}
+
+#[inline]
+fn write_intarray(writer: &mut dyn Write, value: &Vec<i32>) -> Result<(), Error> {
+ writer.write_i32::<BE>(value.len() as i32)?;
+ for &int in value {
+ writer.write_i32::<BE>(int)?;
+ }
+ Ok(())
+}
+
+#[inline]
+fn write_longarray(writer: &mut dyn Write, value: &Vec<i64>) -> Result<(), Error> {
+ writer.write_i32::<BE>(value.len() as i32)?;
+ for &long in value {
+ writer.write_i64::<BE>(long)?;
+ }
+ Ok(())
+}
+
+impl Tag {
+ #[inline]
+ pub fn write_without_end(&self, writer: &mut dyn Write) -> Result<(), Error> {
+ match self {
+ Tag::End => {}
+ Tag::Byte(value) => writer.write_i8(*value)?,
+ Tag::Short(value) => writer.write_i16::<BE>(*value)?,
+ Tag::Int(value) => writer.write_i32::<BE>(*value)?,
+ Tag::Long(value) => writer.write_i64::<BE>(*value)?,
+ Tag::Float(value) => writer.write_f32::<BE>(*value)?,
+ Tag::Double(value) => writer.write_f64::<BE>(*value)?,
+ Tag::ByteArray(value) => write_bytearray(writer, value)?,
+ Tag::String(value) => write_string(writer, value)?,
+ Tag::List(value) => write_list(writer, value)?,
+ Tag::Compound(value) => write_compound(writer, value, true)?,
+ Tag::IntArray(value) => write_intarray(writer, value)?,
+ Tag::LongArray(value) => write_longarray(writer, value)?,
+ }
Ok(())
}
@@ -99,11 +200,7 @@ impl Tag {
pub fn write(&self, writer: &mut impl Write) -> Result<(), Error> {
match self {
Tag::Compound(value) => {
- for (key, tag) in value {
- writer.write_u8(tag.id()).map_err(|_| Error::WriteError)?;
- write_string(writer, key)?;
- tag.write_without_end(writer)?;
- }
+ write_compound(writer, value, false)?;
Ok(())
}
_ => Err(Error::InvalidTag),