aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2023-11-19 22:07:38 -0600
committerGitHub <noreply@github.com>2023-11-19 22:07:38 -0600
commit2c610826fc9f8e16897f52313faa8e0602d1dc3d (patch)
tree5aad79ecab3b68511a10ebd7eba07af0bd8a5905
parent84e036ce3752ecf57904b0f5aff1f33d43e95a32 (diff)
downloadazalea-drasl-2c610826fc9f8e16897f52313faa8e0602d1dc3d.tar.xz
Replace azalea-nbt with simdnbt (#111)
* delete azalea-nbt and replace with simdnbt * use simdnbt from crates.io * remove serde dependency on azalea-registry
-rw-r--r--Cargo.lock166
-rwxr-xr-xCargo.toml1
-rw-r--r--azalea-buf/Cargo.toml1
-rwxr-xr-xazalea-buf/src/read.rs33
-rwxr-xr-xazalea-buf/src/write.rs24
-rw-r--r--azalea-client/Cargo.toml2
-rw-r--r--azalea-client/src/chunks.rs9
-rw-r--r--azalea-client/src/interact.rs7
-rw-r--r--azalea-core/Cargo.toml3
-rw-r--r--azalea-core/src/registry_holder.rs287
-rwxr-xr-xazalea-core/src/resource_location.rs25
-rwxr-xr-xazalea-core/src/slot.rs40
-rw-r--r--azalea-entity/Cargo.toml2
-rwxr-xr-xazalea-entity/src/data.rs2
-rw-r--r--azalea-entity/src/metadata.rs8
-rw-r--r--azalea-inventory/Cargo.toml2
-rw-r--r--azalea-inventory/src/slot.rs2
-rw-r--r--azalea-nbt/Cargo.toml37
-rwxr-xr-xazalea-nbt/README.md35
-rwxr-xr-xazalea-nbt/benches/compare.rs91
-rwxr-xr-xazalea-nbt/benches/nbt.rs75
-rwxr-xr-xazalea-nbt/src/decode.rs314
-rwxr-xr-xazalea-nbt/src/encode.rs296
-rwxr-xr-xazalea-nbt/src/error.rs15
-rwxr-xr-xazalea-nbt/src/lib.rs46
-rwxr-xr-xazalea-nbt/src/tag.rs271
-rwxr-xr-xazalea-nbt/tests/bigtest.nbtbin507 -> 0 bytes
-rwxr-xr-xazalea-nbt/tests/complex_player.datbin1379 -> 0 bytes
-rwxr-xr-xazalea-nbt/tests/hello_world.nbtbin33 -> 0 bytes
-rw-r--r--azalea-nbt/tests/inttest1023.nbtbin4104 -> 0 bytes
-rwxr-xr-xazalea-nbt/tests/inttest16.nbtbin95 -> 0 bytes
-rw-r--r--azalea-nbt/tests/inttest3.nbtbin24 -> 0 bytes
-rwxr-xr-xazalea-nbt/tests/level.datbin1922 -> 0 bytes
-rwxr-xr-xazalea-nbt/tests/simple_player.datbin440 -> 0 bytes
-rwxr-xr-xazalea-nbt/tests/stringtest.nbtbin251 -> 0 bytes
-rwxr-xr-xazalea-nbt/tests/tests.rs140
-rw-r--r--azalea-protocol/Cargo.toml4
-rwxr-xr-xazalea-protocol/src/packets/game/clientbound_block_entity_data_packet.rs3
-rwxr-xr-xazalea-protocol/src/packets/game/clientbound_level_chunk_with_light_packet.rs2
-rwxr-xr-xazalea-protocol/src/packets/game/clientbound_tag_query_packet.rs3
-rwxr-xr-xazalea-protocol/src/packets/game/clientbound_update_mob_effect_packet.rs3
-rw-r--r--azalea-registry/Cargo.toml4
-rwxr-xr-xazalea-registry/azalea-registry-macros/src/lib.rs25
-rw-r--r--azalea-world/Cargo.toml2
-rwxr-xr-xazalea-world/src/chunk_storage.rs6
-rw-r--r--codegen/lib/code/entity.py4
-rwxr-xr-xcodegen/lib/code/utils.py2
47 files changed, 278 insertions, 1714 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 2331c5ee..67364af5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -255,6 +255,7 @@ dependencies = [
"azalea-buf-macros",
"byteorder",
"serde_json",
+ "simdnbt",
"thiserror",
"tracing",
"uuid",
@@ -295,7 +296,6 @@ dependencies = [
"azalea-crypto",
"azalea-entity",
"azalea-inventory",
- "azalea-nbt",
"azalea-physics",
"azalea-protocol",
"azalea-registry",
@@ -314,6 +314,7 @@ dependencies = [
"reqwest",
"serde",
"serde_json",
+ "simdnbt",
"thiserror",
"tokio",
"tracing",
@@ -326,13 +327,14 @@ version = "0.8.0"
dependencies = [
"azalea-buf",
"azalea-inventory",
- "azalea-nbt",
"azalea-registry",
"bevy_ecs",
"nohash-hasher",
"num-traits",
"serde",
"serde_json",
+ "simdnbt",
+ "tracing",
"uuid",
]
@@ -362,7 +364,6 @@ dependencies = [
"azalea-chat",
"azalea-core",
"azalea-inventory",
- "azalea-nbt",
"azalea-registry",
"azalea-world",
"bevy_app",
@@ -371,6 +372,7 @@ dependencies = [
"enum-as-inner",
"nohash-hasher",
"parking_lot",
+ "simdnbt",
"thiserror",
"tracing",
"uuid",
@@ -382,8 +384,8 @@ version = "0.8.0"
dependencies = [
"azalea-buf",
"azalea-inventory-macros",
- "azalea-nbt",
"azalea-registry",
+ "simdnbt",
]
[[package]]
@@ -405,24 +407,6 @@ dependencies = [
]
[[package]]
-name = "azalea-nbt"
-version = "0.8.0"
-dependencies = [
- "azalea-buf",
- "byteorder",
- "compact_str",
- "criterion",
- "enum-as-inner",
- "fastnbt",
- "flate2",
- "graphite_binary",
- "serde",
- "thiserror",
- "tracing",
- "valence_nbt",
-]
-
-[[package]]
name = "azalea-physics"
version = "0.8.0"
dependencies = [
@@ -457,7 +441,6 @@ dependencies = [
"azalea-crypto",
"azalea-entity",
"azalea-inventory",
- "azalea-nbt",
"azalea-protocol-macros",
"azalea-registry",
"azalea-world",
@@ -471,6 +454,7 @@ dependencies = [
"once_cell",
"serde",
"serde_json",
+ "simdnbt",
"thiserror",
"tokio",
"tokio-util",
@@ -496,7 +480,7 @@ dependencies = [
"azalea-buf",
"azalea-registry-macros",
"once_cell",
- "serde",
+ "simdnbt",
]
[[package]]
@@ -517,7 +501,6 @@ dependencies = [
"azalea-client",
"azalea-core",
"azalea-inventory",
- "azalea-nbt",
"azalea-registry",
"bevy_ecs",
"criterion",
@@ -528,6 +511,7 @@ dependencies = [
"parking_lot",
"serde",
"serde_json",
+ "simdnbt",
"thiserror",
"tracing",
"uuid",
@@ -806,15 +790,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
-name = "castaway"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a17ed5635fc8536268e5d4de1e22e81ac34419e5f052d4d51f4e01dcc263fcc"
-dependencies = [
- "rustversion",
-]
-
-[[package]]
name = "cc"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -824,12 +799,6 @@ dependencies = [
]
[[package]]
-name = "cesu8"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
-
-[[package]]
name = "cfb8"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -917,20 +886,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
[[package]]
-name = "compact_str"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f"
-dependencies = [
- "castaway",
- "cfg-if",
- "itoa",
- "ryu",
- "serde",
- "static_assertions",
-]
-
-[[package]]
name = "concurrent-queue"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1203,18 +1158,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]]
-name = "fastnbt"
-version = "2.4.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3369bd70629bccfda7e344883c9ae3ab7f3b10a357bcf8b0f69caa7256bcf188"
-dependencies = [
- "byteorder",
- "cesu8",
- "serde",
- "serde_bytes",
-]
-
-[[package]]
name = "fastrand"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1418,31 +1361,6 @@ dependencies = [
]
[[package]]
-name = "graphite_binary"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1dc8b44c673c50a2b3e6ec6652b8c8d26532254a3a182cc43b76d1b6e4cd1572"
-dependencies = [
- "anyhow",
- "bytes",
- "cesu8",
- "graphite_binary_macros",
- "thiserror",
-]
-
-[[package]]
-name = "graphite_binary_macros"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30667bf8d368a37fa37f4165d90ee84362e360d83d85924898c41cfe3d097521"
-dependencies = [
- "anyhow",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
name = "h2"
version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2234,6 +2152,21 @@ dependencies = [
]
[[package]]
+name = "residua-cesu8"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ca29b145d9861719b5505602d881afc46705200144153ca9dbc0802be2938ea"
+
+[[package]]
+name = "residua-mutf8"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2adba843a48e520e7dad6d1e9c367a4f818787eaccf4530c6b90dd1f035e630d"
+dependencies = [
+ "residua-cesu8",
+]
+
+[[package]]
name = "ring"
version = "0.16.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2346,12 +2279,6 @@ dependencies = [
]
[[package]]
-name = "rustversion"
-version = "1.0.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
-
-[[package]]
name = "ryu"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2398,15 +2325,6 @@ dependencies = [
]
[[package]]
-name = "serde_bytes"
-version = "0.11.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff"
-dependencies = [
- "serde",
-]
-
-[[package]]
name = "serde_derive"
version = "1.0.192"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2491,6 +2409,30 @@ dependencies = [
]
[[package]]
+name = "simdnbt"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89e3431666c99066308d860437da87ac1dfdf7225b80b551aa007cbd3a46a086"
+dependencies = [
+ "byteorder",
+ "flate2",
+ "residua-mutf8",
+ "simdnbt-derive",
+ "thiserror",
+]
+
+[[package]]
+name = "simdnbt-derive"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "840927b3f00258339cb4ccb4658a33f572409a1bf42e1b98a3f872a995894b4e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.39",
+]
+
+[[package]]
name = "simple_asn1"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2566,12 +2508,6 @@ dependencies = [
]
[[package]]
-name = "static_assertions"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
-
-[[package]]
name = "subtle"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2960,12 +2896,6 @@ dependencies = [
]
[[package]]
-name = "valence_nbt"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3cddc3222ed5ead4fa446881b3deeeee0dba60b0088b2bf12fedbac7eda2312"
-
-[[package]]
name = "valuable"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index c9bbddbb..9ce1fc84 100755
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,7 +6,6 @@ members = [
"azalea-chat",
"azalea-core",
"azalea-auth",
- "azalea-nbt",
"azalea-brigadier",
"azalea-crypto",
"azalea-world",
diff --git a/azalea-buf/Cargo.toml b/azalea-buf/Cargo.toml
index 95f3b4ac..dc25632b 100644
--- a/azalea-buf/Cargo.toml
+++ b/azalea-buf/Cargo.toml
@@ -15,6 +15,7 @@ tracing = "0.1.40"
serde_json = { version = "^1.0", optional = true }
thiserror = "1.0.50"
uuid = "^1.5.0"
+simdnbt = { version = "0.2.1" }
[features]
serde_json = ["dep:serde_json"]
diff --git a/azalea-buf/src/read.rs b/azalea-buf/src/read.rs
index 78db7357..d5c4d0a8 100755
--- a/azalea-buf/src/read.rs
+++ b/azalea-buf/src/read.rs
@@ -50,6 +50,18 @@ pub enum BufReadError {
#[backtrace]
source: serde_json::Error,
},
+ #[error("{source}")]
+ Nbt {
+ #[from]
+ #[backtrace]
+ source: simdnbt::Error,
+ },
+ #[error("{source}")]
+ DeserializeNbt {
+ #[from]
+ #[backtrace]
+ source: simdnbt::DeserializeError,
+ },
}
fn read_bytes<'a>(buf: &'a mut Cursor<&[u8]>, length: usize) -> Result<&'a [u8], BufReadError> {
@@ -340,3 +352,24 @@ impl<T: McBufReadable, const N: usize> McBufReadable for [T; N] {
})
}
}
+
+impl McBufReadable for simdnbt::owned::NbtTag {
+ fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
+ Ok(simdnbt::owned::NbtTag::read(buf)?)
+ }
+}
+
+impl McBufReadable for simdnbt::owned::NbtCompound {
+ fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
+ match simdnbt::owned::NbtTag::read(buf)? {
+ simdnbt::owned::NbtTag::Compound(compound) => Ok(compound),
+ _ => Err(BufReadError::Custom("Expected compound tag".to_string())),
+ }
+ }
+}
+
+impl McBufReadable for simdnbt::owned::Nbt {
+ fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
+ Ok(simdnbt::owned::Nbt::read_unnamed(buf)?)
+ }
+}
diff --git a/azalea-buf/src/write.rs b/azalea-buf/src/write.rs
index f48bf2ec..03d40d79 100755
--- a/azalea-buf/src/write.rs
+++ b/azalea-buf/src/write.rs
@@ -257,3 +257,27 @@ impl<T: McBufWritable, const N: usize> McBufWritable for [T; N] {
Ok(())
}
}
+
+impl McBufWritable for simdnbt::owned::NbtTag {
+ fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
+ let mut data = Vec::new();
+ self.write(&mut data);
+ data.write_into(buf)
+ }
+}
+
+impl McBufWritable for simdnbt::owned::NbtCompound {
+ fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
+ let mut data = Vec::new();
+ simdnbt::owned::NbtTag::Compound(self.clone()).write(&mut data);
+ data.write_into(buf)
+ }
+}
+
+impl McBufWritable for simdnbt::owned::Nbt {
+ fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
+ let mut data = Vec::new();
+ self.write_unnamed(&mut data);
+ data.write_into(buf)
+ }
+}
diff --git a/azalea-client/Cargo.toml b/azalea-client/Cargo.toml
index 71f117ed..4694fbd9 100644
--- a/azalea-client/Cargo.toml
+++ b/azalea-client/Cargo.toml
@@ -14,7 +14,7 @@ anyhow = "1.0.75"
async-trait = "0.1.74"
azalea-auth = { path = "../azalea-auth", version = "0.8.0" }
azalea-block = { path = "../azalea-block", version = "0.8.0" }
-azalea-nbt = { path = "../azalea-nbt", version = "0.8.0" }
+simdnbt = { version = "0.2.1" }
azalea-chat = { path = "../azalea-chat", version = "0.8.0" }
azalea-core = { path = "../azalea-core", version = "0.8.0" }
azalea-crypto = { path = "../azalea-crypto", version = "0.8.0" }
diff --git a/azalea-client/src/chunks.rs b/azalea-client/src/chunks.rs
index 4d2641f5..e91e6b01 100644
--- a/azalea-client/src/chunks.rs
+++ b/azalea-client/src/chunks.rs
@@ -4,17 +4,18 @@
use std::{
io::Cursor,
+ ops::Deref,
time::{Duration, Instant},
};
use azalea_core::position::ChunkPos;
-use azalea_nbt::NbtCompound;
use azalea_protocol::packets::game::{
clientbound_level_chunk_with_light_packet::ClientboundLevelChunkWithLightPacket,
serverbound_chunk_batch_received_packet::ServerboundChunkBatchReceivedPacket,
};
use bevy_app::{App, Plugin, Update};
use bevy_ecs::prelude::*;
+use simdnbt::owned::BaseNbt;
use tracing::{error, trace};
use crate::{
@@ -99,10 +100,10 @@ fn handle_receive_chunk_events(
}
}
- let heightmaps = event.packet.chunk_data.heightmaps.as_compound();
+ let heightmaps_nbt = &event.packet.chunk_data.heightmaps;
// necessary to make the unwrap_or work
- let empty_nbt_compound = NbtCompound::default();
- let heightmaps = heightmaps.unwrap_or(&empty_nbt_compound);
+ let empty_nbt = BaseNbt::default();
+ let heightmaps = heightmaps_nbt.unwrap_or(&empty_nbt).deref();
if let Err(e) = partial_instance.chunks.replace_with_packet_data(
&pos,
diff --git a/azalea-client/src/interact.rs b/azalea-client/src/interact.rs
index 64cbd7be..bdb17827 100644
--- a/azalea-client/src/interact.rs
+++ b/azalea-client/src/interact.rs
@@ -11,7 +11,6 @@ use azalea_entity::{
clamp_look_direction, view_vector, Attributes, EyeHeight, LocalEntity, LookDirection, Position,
};
use azalea_inventory::{ItemSlot, ItemSlotData};
-use azalea_nbt::NbtList;
use azalea_physics::clip::{BlockShapeType, ClipContext, FluidPickType};
use azalea_protocol::packets::game::{
serverbound_interact_packet::InteractionHand,
@@ -29,6 +28,7 @@ use bevy_ecs::{
system::{Commands, Query, Res},
};
use derive_more::{Deref, DerefMut};
+use simdnbt::owned::NbtList;
use tracing::warn;
use crate::{
@@ -272,9 +272,8 @@ pub fn check_block_can_be_broken_by_item_in_adventure_mode(
let Some(can_destroy) = item
.nbt
- .as_compound()
- .and_then(|nbt| nbt.get("tag").and_then(|nbt| nbt.as_compound()))
- .and_then(|nbt| nbt.get("CanDestroy").and_then(|nbt| nbt.as_list()))
+ .compound("tag")
+ .and_then(|nbt| nbt.list("CanDestroy"))
else {
// no CanDestroy tag
return false;
diff --git a/azalea-core/Cargo.toml b/azalea-core/Cargo.toml
index a25485a2..957eaaf5 100644
--- a/azalea-core/Cargo.toml
+++ b/azalea-core/Cargo.toml
@@ -11,7 +11,7 @@ version = "0.8.0"
[dependencies]
azalea-buf = { path = "../azalea-buf", version = "0.8.0" }
azalea-inventory = { version = "0.8.0", path = "../azalea-inventory" }
-azalea-nbt = { path = "../azalea-nbt", version = "0.8.0" }
+simdnbt = { version = "0.2.1" }
azalea-registry = { path = "../azalea-registry", version = "0.8.0" }
bevy_ecs = { version = "0.12.0", default-features = false, optional = true }
nohash-hasher = "0.2.0"
@@ -19,6 +19,7 @@ num-traits = "0.2.17"
serde = { version = "^1.0", optional = true }
uuid = "^1.5.0"
serde_json = "^1.0.108"
+tracing = "0.1.40"
[features]
bevy_ecs = ["dep:bevy_ecs"]
diff --git a/azalea-core/src/registry_holder.rs b/azalea-core/src/registry_holder.rs
index 7f811e23..6d58f77a 100644
--- a/azalea-core/src/registry_holder.rs
+++ b/azalea-core/src/registry_holder.rs
@@ -6,100 +6,103 @@
//! biomes.
use azalea_buf::{BufReadError, McBufReadable, McBufWritable};
-use azalea_nbt::Nbt;
-use serde::{
- de::{self, DeserializeOwned},
- Deserialize, Deserializer, Serialize, Serializer,
+use simdnbt::{
+ owned::{NbtCompound, NbtTag},
+ Deserialize, FromNbtTag, Serialize, ToNbtTag,
};
use std::{collections::HashMap, io::Cursor};
+use tracing::error;
use crate::resource_location::ResourceLocation;
/// The base of the registry.
///
/// This is the registry that is sent to the client upon login.
-#[derive(Default, Debug, Clone, Serialize, Deserialize)]
+#[derive(Default, Debug, Clone)]
pub struct RegistryHolder {
- pub map: HashMap<ResourceLocation, Nbt>,
+ pub map: HashMap<ResourceLocation, NbtCompound>,
}
impl RegistryHolder {
- fn get<T: DeserializeOwned>(&self, name: &ResourceLocation) -> Option<T> {
- let nbt = self.map.get(name)?;
- serde_json::from_value(serde_json::to_value(nbt).ok()?).ok()
+ fn get<T: Deserialize>(
+ &self,
+ name: &ResourceLocation,
+ ) -> Option<Result<T, simdnbt::DeserializeError>> {
+ self.map.get(name).map(|nbt| T::from_compound(nbt.clone()))
}
/// Get the dimension type registry, or `None` if it doesn't exist. You
/// should do some type of error handling if this returns `None`.
pub fn dimension_type(&self) -> Option<RegistryType<DimensionTypeElement>> {
- self.get(&ResourceLocation::new("minecraft:dimension_type"))
- }
-}
-
-impl TryFrom<Nbt> for RegistryHolder {
- type Error = serde_json::Error;
-
- fn try_from(value: Nbt) -> Result<Self, Self::Error> {
- Ok(RegistryHolder {
- map: serde_json::from_value(serde_json::to_value(value)?)?,
- })
- }
-}
-
-impl TryInto<Nbt> for RegistryHolder {
- type Error = serde_json::Error;
-
- fn try_into(self) -> Result<Nbt, Self::Error> {
- serde_json::from_value(serde_json::to_value(self.map)?)
+ let name = ResourceLocation::new("minecraft:dimension_type");
+ match self.get(&name) {
+ Some(Ok(registry)) => Some(registry),
+ Some(Err(err)) => {
+ error!(
+ "Error deserializing dimension type registry: {err:?}\n{:?}",
+ self.map.get(&name)
+ );
+ None
+ }
+ None => None,
+ }
}
}
impl McBufReadable for RegistryHolder {
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
- RegistryHolder::try_from(Nbt::read_from(buf)?)
- .map_err(|e| BufReadError::Deserialization { source: e })
+ let nbt_compound = NbtCompound::read_from(buf)?;
+ Ok(RegistryHolder {
+ map: simdnbt::Deserialize::from_compound(nbt_compound)?,
+ })
}
}
impl McBufWritable for RegistryHolder {
fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
- TryInto::<Nbt>::try_into(self.clone())?.write_into(buf)
+ let mut written = Vec::new();
+ self.map.clone().to_compound().write_into(&mut written)?;
+ buf.write_all(&written)
}
}
/// A collection of values for a certain type of registry data.
#[derive(Debug, Clone, Serialize, Deserialize)]
-#[cfg_attr(feature = "strict_registry", serde(deny_unknown_fields))]
-pub struct RegistryType<T> {
- #[serde(rename = "type")]
+#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
+pub struct RegistryType<T>
+where
+ T: Serialize + Deserialize,
+{
+ #[simdnbt(rename = "type")]
pub kind: ResourceLocation,
pub value: Vec<TypeValue<T>>,
}
/// A value for a certain type of registry data.
#[derive(Debug, Clone, Serialize, Deserialize)]
-#[cfg_attr(feature = "strict_registry", serde(deny_unknown_fields))]
-pub struct TypeValue<T> {
+#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
+pub struct TypeValue<T>
+where
+ T: Serialize + Deserialize,
+{
pub id: u32,
pub name: ResourceLocation,
pub element: T,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
-#[cfg_attr(feature = "strict_registry", serde(deny_unknown_fields))]
+#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
pub struct TrimMaterialElement {
pub asset_name: String,
pub ingredient: ResourceLocation,
pub item_model_index: f32,
pub override_armor_materials: HashMap<String, String>,
- #[serde(default)]
- #[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
}
/// Data about a kind of chat message
#[derive(Debug, Clone, Serialize, Deserialize)]
-#[cfg_attr(feature = "strict_registry", serde(deny_unknown_fields))]
+#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
pub struct ChatTypeElement {
pub chat: ChatTypeData,
pub narration: ChatTypeData,
@@ -107,48 +110,29 @@ pub struct ChatTypeElement {
/// Data about a chat message.
#[derive(Debug, Clone, Serialize, Deserialize)]
-#[cfg_attr(feature = "strict_registry", serde(deny_unknown_fields))]
+#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
pub struct ChatTypeData {
pub translation_key: String,
pub parameters: Vec<String>,
- #[serde(default)]
- #[serde(skip_serializing_if = "Option::is_none")]
pub style: Option<ChatTypeStyle>,
}
/// The style of a chat message.
#[derive(Debug, Clone, Serialize, Deserialize)]
-#[cfg_attr(feature = "strict_registry", serde(deny_unknown_fields))]
+#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
pub struct ChatTypeStyle {
- #[serde(default)]
- #[serde(skip_serializing_if = "Option::is_none")]
pub color: Option<String>,
- #[serde(default)]
- #[serde(skip_serializing_if = "Option::is_none")]
- #[serde(with = "Convert")]
pub bold: Option<bool>,
- #[serde(default)]
- #[serde(skip_serializing_if = "Option::is_none")]
- #[serde(with = "Convert")]
pub italic: Option<bool>,
- #[serde(default)]
- #[serde(skip_serializing_if = "Option::is_none")]
- #[serde(with = "Convert")]
pub underlined: Option<bool>,
- #[serde(default)]
- #[serde(skip_serializing_if = "Option::is_none")]
- #[serde(with = "Convert")]
pub strikethrough: Option<bool>,
- #[serde(default)]
- #[serde(skip_serializing_if = "Option::is_none")]
- #[serde(with = "Convert")]
pub obfuscated: Option<bool>,
}
/// Dimension attributes.
#[cfg(feature = "strict_registry")]
#[derive(Debug, Clone, Serialize, Deserialize)]
-#[serde(deny_unknown_fields)]
+#[simdnbt(deny_unknown_fields)]
pub struct DimensionTypeElement {
pub ambient_light: f32,
#[serde(with = "Convert")]
@@ -186,99 +170,124 @@ pub struct DimensionTypeElement {
pub struct DimensionTypeElement {
pub height: u32,
pub min_y: i32,
- #[serde(flatten)]
- pub _extra: HashMap<String, Nbt>,
+ #[simdnbt(flatten)]
+ pub _extra: HashMap<String, NbtTag>,
}
/// The light level at which monsters can spawn.
///
/// This can be either a single minimum value, or a formula with a min and
/// max.
-#[derive(Debug, Clone, Serialize, Deserialize)]
-#[serde(untagged)]
-#[cfg_attr(feature = "strict_registry", serde(deny_unknown_fields))]
+#[derive(Debug, Clone)]
+// #[serde(untagged)]
+#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
pub enum MonsterSpawnLightLevel {
/// A simple minimum value.
Simple(u32),
/// A complex value with a type, minimum, and maximum.
/// Vanilla minecraft only uses one type, "minecraft:uniform".
Complex {
- #[serde(rename = "type")]
kind: ResourceLocation,
value: MonsterSpawnLightLevelValues,
},
}
+impl FromNbtTag for MonsterSpawnLightLevel {
+ fn from_nbt_tag(tag: simdnbt::owned::NbtTag) -> Option<Self> {
+ if let Some(value) = tag.int() {
+ Some(Self::Simple(value as u32))
+ } else if let Some(value) = tag.compound() {
+ let kind = ResourceLocation::from_nbt_tag(value.get("type")?.clone())?;
+ let value = MonsterSpawnLightLevelValues::from_nbt_tag(value.get("value")?.clone())?;
+ Some(Self::Complex { kind, value })
+ } else {
+ None
+ }
+ }
+}
+
+impl ToNbtTag for MonsterSpawnLightLevel {
+ fn to_nbt_tag(self) -> simdnbt::owned::NbtTag {
+ match self {
+ Self::Simple(value) => value.to_nbt_tag(),
+ Self::Complex { kind, value } => {
+ let mut compound = NbtCompound::new();
+ compound.insert("type", kind.to_nbt_tag());
+ compound.insert("value", value.to_nbt_tag());
+ simdnbt::owned::NbtTag::Compound(compound)
+ }
+ }
+ }
+}
+
/// The min and max light levels at which monsters can spawn.
///
/// Values are inclusive.
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
-#[cfg_attr(feature = "strict_registry", serde(deny_unknown_fields))]
+#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
pub struct MonsterSpawnLightLevelValues {
- #[serde(rename = "min_inclusive")]
+ #[simdnbt(rename = "min_inclusive")]
pub min: u32,
- #[serde(rename = "max_inclusive")]
+ #[simdnbt(rename = "max_inclusive")]
pub max: u32,
}
/// Biome attributes.
#[derive(Debug, Clone, Serialize, Deserialize)]
-#[cfg_attr(feature = "strict_registry", serde(deny_unknown_fields))]
+#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
pub struct WorldTypeElement {
- #[serde(with = "Convert")]
pub has_precipitation: bool,
pub temperature: f32,
- #[serde(default)]
- #[serde(skip_serializing_if = "Option::is_none")]
pub temperature_modifier: Option<String>,
pub downfall: f32,
pub effects: BiomeEffects,
}
/// The precipitation of a biome.
-#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)]
-#[cfg_attr(feature = "strict_registry", serde(deny_unknown_fields))]
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum BiomePrecipitation {
- #[serde(rename = "none")]
None,
- #[serde(rename = "rain")]
Rain,
- #[serde(rename = "snow")]
Snow,
}
+impl FromNbtTag for BiomePrecipitation {
+ fn from_nbt_tag(tag: NbtTag) -> Option<Self> {
+ match tag.string()?.to_str().as_ref() {
+ "none" => Some(Self::None),
+ "rain" => Some(Self::Rain),
+ "snow" => Some(Self::Snow),
+ _ => None,
+ }
+ }
+}
+impl ToNbtTag for BiomePrecipitation {
+ fn to_nbt_tag(self) -> NbtTag {
+ match self {
+ Self::None => NbtTag::String("none".into()),
+ Self::Rain => NbtTag::String("rain".into()),
+ Self::Snow => NbtTag::String("snow".into()),
+ }
+ }
+}
/// The effects of a biome.
///
/// This includes the sky, fog, water, and grass color,
/// as well as music and other sound effects.
#[derive(Debug, Clone, Serialize, Deserialize)]
-#[cfg_attr(feature = "strict_registry", serde(deny_unknown_fields))]
+#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
pub struct BiomeEffects {
pub sky_color: u32,
pub fog_color: u32,
pub water_color: u32,
pub water_fog_color: u32,
- #[serde(default)]
- #[serde(skip_serializing_if = "Option::is_none")]
pub foliage_color: Option<u32>,
- #[serde(default)]
- #[serde(skip_serializing_if = "Option::is_none")]
pub grass_color: Option<u32>,
- #[serde(default)]
- #[serde(skip_serializing_if = "Option::is_none")]
pub grass_color_modifier: Option<String>,
- #[serde(default)]
- #[serde(skip_serializing_if = "Option::is_none")]
pub music: Option<BiomeMusic>,
pub mood_sound: BiomeMoodSound,
- #[serde(default)]
- #[serde(skip_serializing_if = "Option::is_none")]
pub additions_sound: Option<AdditionsSound>,
- #[serde(default)]
- #[serde(skip_serializing_if = "Option::is_none")]
pub ambient_sound: Option<ResourceLocation>,
- #[serde(default)]
- #[serde(skip_serializing_if = "Option::is_none")]
pub particle: Option<BiomeParticle>,
}
@@ -286,9 +295,8 @@ pub struct BiomeEffects {
///
/// Some biomes have unique music that only play when inside them.
#[derive(Debug, Clone, Serialize, Deserialize)]
-#[cfg_attr(feature = "strict_registry", serde(deny_unknown_fields))]
+#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
pub struct BiomeMusic {
- #[serde(with = "Convert")]
pub replace_current_music: bool,
pub max_delay: u32,
pub min_delay: u32,
@@ -296,7 +304,7 @@ pub struct BiomeMusic {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
-#[cfg_attr(feature = "strict_registry", serde(deny_unknown_fields))]
+#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
pub struct BiomeMoodSound {
pub tick_delay: u32,
pub block_search_extent: u32,
@@ -305,7 +313,7 @@ pub struct BiomeMoodSound {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
-#[cfg_attr(feature = "strict_registry", serde(deny_unknown_fields))]
+#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
pub struct AdditionsSound {
pub tick_chance: f32,
pub sound: azalea_registry::SoundEvent,
@@ -315,98 +323,25 @@ pub struct AdditionsSound {
///
/// Some biomes have particles that spawn in the air.
#[derive(Debug, Clone, Serialize, Deserialize)]
-#[cfg_attr(feature = "strict_registry", serde(deny_unknown_fields))]
+#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
pub struct BiomeParticle {
pub probability: f32,
pub options: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
-#[cfg_attr(feature = "strict_registry", serde(deny_unknown_fields))]
+#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
pub struct TrimPatternElement {
- #[serde(flatten)]
+ #[simdnbt(flatten)]
pub pattern: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
-#[cfg_attr(feature = "strict_registry", serde(deny_unknown_fields))]
+#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
pub struct DamageTypeElement {
pub message_id: String,
pub scaling: String,
pub exhaustion: f32,
- #[serde(default)]
- #[serde(skip_serializing_if = "Option::is_none")]
pub effects: Option<String>,
- #[serde(default)]
- #[serde(skip_serializing_if = "Option::is_none")]
pub death_message_type: Option<String>,
}
-
-// Using a trait because you can't implement methods for
-// types you don't own, in this case Option<bool> and bool.
-trait Convert: Sized {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: Serializer;
-
- fn deserialize<'de, D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: Deserializer<'de>;
-}
-
-// Convert between bool and u8
-impl Convert for bool {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: Serializer,
- {
- serializer.serialize_u8(if *self { 1 } else { 0 })
- }
-
- fn deserialize<'de, D>(deserializer: D) -> Result<bool, D::Error>
- where
- D: Deserializer<'de>,
- {
- convert::<D>(u8::deserialize(deserializer)?)
- }
-}
-
-// Convert between Option<bool> and u8
-impl Convert for Option<bool> {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: Serializer,
- {
- if let Some(value) = self {
- Convert::serialize(value, serializer)
- } else {
- serializer.serialize_none()
- }
- }
-
- fn deserialize<'de, D>(deserializer: D) -> Result<Option<bool>, D::Error>
- where
- D: Deserializer<'de>,
- {
- if let Some(value) = Option::<u8>::deserialize(deserializer)? {
- Ok(Some(convert::<D>(value)?))
- } else {
- Ok(None)
- }
- }
-}
-
-// Deserializing logic here to deduplicate code
-fn convert<'de, D>(value: u8) -> Result<bool, D::Error>
-where
- D: Deserializer<'de>,
-{
- match value {
- 0 => Ok(false),
- 1 => Ok(true),
- other => Err(de::Error::invalid_value(
- de::Unexpected::Unsigned(other as u64),
- &"zero or one",
- )),
- }
-}
diff --git a/azalea-core/src/resource_location.rs b/azalea-core/src/resource_location.rs
index cc669841..e6a70247 100755
--- a/azalea-core/src/resource_location.rs
+++ b/azalea-core/src/resource_location.rs
@@ -1,7 +1,11 @@
//! A resource, like minecraft:stone
use azalea_buf::{BufReadError, McBufReadable, McBufWritable};
-use std::io::{Cursor, Write};
+use simdnbt::{owned::NbtTag, FromNbtTag, ToNbtTag};
+use std::{
+ io::{Cursor, Write},
+ str::FromStr,
+};
#[cfg(feature = "serde")]
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
@@ -47,6 +51,13 @@ impl std::fmt::Debug for ResourceLocation {
write!(f, "{}:{}", self.namespace, self.path)
}
}
+impl FromStr for ResourceLocation {
+ type Err = &'static str;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ Ok(ResourceLocation::new(s))
+ }
+}
impl McBufReadable for ResourceLocation {
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
@@ -88,6 +99,18 @@ impl<'de> Deserialize<'de> for ResourceLocation {
}
}
+impl FromNbtTag for ResourceLocation {
+ fn from_nbt_tag(tag: NbtTag) -> Option<Self> {
+ tag.string().and_then(|s| s.to_str().parse().ok())
+ }
+}
+
+impl ToNbtTag for ResourceLocation {
+ fn to_nbt_tag(self) -> NbtTag {
+ NbtTag::String(self.to_string().into())
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/azalea-core/src/slot.rs b/azalea-core/src/slot.rs
deleted file mode 100755
index 22961437..00000000
--- a/azalea-core/src/slot.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-// TODO: have an azalea-inventory or azalea-container crate and put this there
-
-use azalea_buf::{BufReadError, McBuf, McBufReadable, McBufWritable};
-use azalea_nbt::Nbt;
-use std::io::{Cursor, Write};
-
-#[derive(Debug, Clone, Default)]
-pub enum Slot {
- #[default]
- Empty,
- Present(SlotData),
-}
-
-#[derive(Debug, Clone, McBuf)]
-pub struct SlotData {
- #[var]
- pub id: u32,
- pub count: u8,
- pub nbt: Nbt,
-}
-
-impl McBufReadable for Slot {
- fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
- let slot = Option::<SlotData>::read_from(buf)?;
- Ok(slot.map_or(Slot::Empty, Slot::Present))
- }
-}
-
-impl McBufWritable for Slot {
- fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
- match self {
- Slot::Empty => false.write_into(buf)?,
- Slot::Present(i) => {
- true.write_into(buf)?;
- i.write_into(buf)?;
- }
- };
- Ok(())
- }
-}
diff --git a/azalea-entity/Cargo.toml b/azalea-entity/Cargo.toml
index 4399ddf3..7cdf5343 100644
--- a/azalea-entity/Cargo.toml
+++ b/azalea-entity/Cargo.toml
@@ -14,7 +14,7 @@ azalea-buf = { version = "0.8.0", path = "../azalea-buf" }
azalea-chat = { version = "0.8.0", path = "../azalea-chat" }
azalea-core = { version = "0.8.0", path = "../azalea-core" }
azalea-inventory = { version = "0.8.0", path = "../azalea-inventory" }
-azalea-nbt = { version = "0.8.0", path = "../azalea-nbt" }
+simdnbt = { version = "0.2.1" }
azalea-registry = { version = "0.8.0", path = "../azalea-registry" }
azalea-world = { version = "0.8.0", path = "../azalea-world" }
bevy_app = "0.12.0"
diff --git a/azalea-entity/src/data.rs b/azalea-entity/src/data.rs
index 54487ef1..83779b21 100755
--- a/azalea-entity/src/data.rs
+++ b/azalea-entity/src/data.rs
@@ -81,7 +81,7 @@ pub enum EntityDataValue {
BlockState(azalea_block::BlockState),
/// If this is air, that means it's absent,
OptionalBlockState(azalea_block::BlockState),
- CompoundTag(azalea_nbt::Nbt),
+ CompoundTag(simdnbt::owned::NbtCompound),
Particle(Particle),
VillagerData(VillagerData),
// 0 for absent; 1 + actual value otherwise. Used for entity IDs.
diff --git a/azalea-entity/src/metadata.rs b/azalea-entity/src/metadata.rs
index 39ba9527..006020d1 100644
--- a/azalea-entity/src/metadata.rs
+++ b/azalea-entity/src/metadata.rs
@@ -6054,9 +6054,9 @@ pub struct PlayerModeCustomisation(pub u8);
#[derive(Component, Deref, DerefMut, Clone)]
pub struct PlayerMainHand(pub u8);
#[derive(Component, Deref, DerefMut, Clone)]
-pub struct ShoulderLeft(pub azalea_nbt::Nbt);
+pub struct ShoulderLeft(pub simdnbt::owned::NbtCompound);
#[derive(Component, Deref, DerefMut, Clone)]
-pub struct ShoulderRight(pub azalea_nbt::Nbt);
+pub struct ShoulderRight(pub simdnbt::owned::NbtCompound);
#[derive(Component)]
pub struct Player;
impl Player {
@@ -6137,8 +6137,8 @@ impl Default for PlayerMetadataBundle {
score: Score(0),
player_mode_customisation: PlayerModeCustomisation(0),
player_main_hand: PlayerMainHand(Default::default()),
- shoulder_left: ShoulderLeft(azalea_nbt::Nbt::Compound(Default::default())),
- shoulder_right: ShoulderRight(azalea_nbt::Nbt::Compound(Default::default())),
+ shoulder_left: ShoulderLeft(simdnbt::owned::NbtCompound::default()),
+ shoulder_right: ShoulderRight(simdnbt::owned::NbtCompound::default()),
}
}
}
diff --git a/azalea-inventory/Cargo.toml b/azalea-inventory/Cargo.toml
index 64db6423..994dbb2b 100644
--- a/azalea-inventory/Cargo.toml
+++ b/azalea-inventory/Cargo.toml
@@ -11,5 +11,5 @@ version = "0.8.0"
[dependencies]
azalea-buf = { version = "0.8.0", path = "../azalea-buf" }
azalea-inventory-macros = { version = "0.8.0", path = "./azalea-inventory-macros" }
-azalea-nbt = { version = "0.8.0", path = "../azalea-nbt" }
+simdnbt = { version = "0.2.1" }
azalea-registry = { version = "0.8.0", path = "../azalea-registry" }
diff --git a/azalea-inventory/src/slot.rs b/azalea-inventory/src/slot.rs
index cef555d7..814b6c37 100644
--- a/azalea-inventory/src/slot.rs
+++ b/azalea-inventory/src/slot.rs
@@ -1,5 +1,5 @@
use azalea_buf::{BufReadError, McBuf, McBufReadable, McBufWritable};
-use azalea_nbt::Nbt;
+use simdnbt::owned::Nbt;
use std::io::{Cursor, Write};
/// Either an item in an inventory or nothing.
diff --git a/azalea-nbt/Cargo.toml b/azalea-nbt/Cargo.toml
deleted file mode 100644
index 788d4a07..00000000
--- a/azalea-nbt/Cargo.toml
+++ /dev/null
@@ -1,37 +0,0 @@
-[package]
-description = "A fast NBT serializer and deserializer."
-edition = "2021"
-license = "MIT"
-name = "azalea-nbt"
-version = "0.8.0"
-repository = "https://github.com/azalea-rs/azalea/tree/main/azalea-nbt"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-azalea-buf = { path = "../azalea-buf", version = "0.8.0" }
-byteorder = "^1.5.0"
-compact_str = { version = "0.7.1", features = ["serde"] }
-enum-as-inner = "0.6.0"
-flate2 = "^1.0.28"
-tracing = "0.1.40"
-serde = { version = "^1.0", features = ["derive"], optional = true }
-thiserror = "1.0.50"
-
-[dev-dependencies]
-criterion = { version = "^0.5.1", features = ["html_reports"] }
-graphite_binary = "0.1.0"
-valence_nbt = "0.8.0"
-fastnbt = "2.4.4"
-
-[features]
-default = []
-serde = ["dep:serde"]
-
-[[bench]]
-harness = false
-name = "nbt"
-
-[[bench]]
-harness = false
-name = "compare"
diff --git a/azalea-nbt/README.md b/azalea-nbt/README.md
deleted file mode 100755
index e13bcf22..00000000
--- a/azalea-nbt/README.md
+++ /dev/null
@@ -1,35 +0,0 @@
-# Azalea NBT
-
-A fast NBT serializer and deserializer.
-
-- Gzip and Zlib compression
-- All data is owned for ease-of-use
-- Serde support with the `serde` feature.
-
-# Examples
-
-```
-use azalea_nbt::{Nbt, NbtCompound};
-use std::io::Cursor;
-
-let buf = include_bytes!("../tests/hello_world.nbt");
-let tag = Nbt::read(&mut Cursor::new(&buf[..])).unwrap();
-assert_eq!(
- tag,
- Nbt::Compound(NbtCompound::from_iter(vec![(
- "hello world".into(),
- Nbt::Compound(NbtCompound::from_iter(vec![(
- "name".into(),
- Nbt::String("Bananrama".into()),
- )]))
- )]))
-);
-```
-
-# Benchmarks
-
-At the time of writing, Azalea NBT is the fastest NBT decoder (approximately twice as fast as Graphite NBT, the second fastest) and on-par with the fastest NBT encoders (sometimes the fastest, depending on the data).
-
-You can run the benchmarks to compare against other NBT libraries with `cargo bench --bench compare` and the normal benchmarks with `cargo bench --bench nbt`.
-
-Note: For best performance, use `RUSTFLAGS='-C target-cpu=native'`.
diff --git a/azalea-nbt/benches/compare.rs b/azalea-nbt/benches/compare.rs
deleted file mode 100755
index 863e0b9a..00000000
--- a/azalea-nbt/benches/compare.rs
+++ /dev/null
@@ -1,91 +0,0 @@
-use std::{
- fs::File,
- io::{Cursor, Read},
-};
-
-use azalea_buf::McBufReadable;
-use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
-use flate2::read::GzDecoder;
-
-pub fn bench_read_file(filename: &str, c: &mut Criterion) {
- let mut file = File::open(filename).unwrap();
- let mut contents = Vec::new();
- file.read_to_end(&mut contents).unwrap();
- let mut src = &contents[..];
-
- // decode the original src so most of the time isn't spent on unzipping
- let mut decoded_src_decoder = GzDecoder::new(&mut src);
- let mut input = Vec::new();
- decoded_src_decoder.read_to_end(&mut input).unwrap();
- let input = input.as_slice();
-
- let mut group = c.benchmark_group(filename);
- group.throughput(Throughput::Bytes(input.len() as u64));
-
- group.bench_function("azalea_parse", |b| {
- b.iter(|| {
- let input = black_box(input);
- let nbt = azalea_nbt::Nbt::read(&mut Cursor::new(input)).unwrap();
- black_box(nbt);
- })
- });
-
- group.bench_function("graphite_parse", |b| {
- b.iter(|| {
- let input = black_box(input);
- let nbt = graphite_binary::nbt::decode::read(&mut &input[..]).unwrap();
- black_box(nbt);
- })
- });
-
- // group.bench_function("valence_parse", |b| {
- // b.iter(|| {
- // let input = black_box(input);
- // let nbt = valence_nbt::from_binary_slice(&mut &input[..]).unwrap();
- // black_box(nbt);
- // })
- // });
-
- // // writing
-
- let nbt = azalea_nbt::Nbt::read_from(&mut Cursor::new(input)).unwrap();
- group.bench_function("azalea_write", |b| {
- b.iter(|| {
- let nbt = black_box(&nbt);
- let mut written = Vec::new();
- nbt.write(&mut written);
- black_box(written);
- })
- });
-
- let nbt = graphite_binary::nbt::decode::read(&mut &input[..]).unwrap();
- group.bench_function("graphite_write", |b| {
- b.iter(|| {
- let nbt = black_box(&nbt);
- let written = graphite_binary::nbt::encode::write(nbt);
- black_box(written);
- })
- });
-
- // let nbt = valence_nbt::from_binary_slice(&mut &input[..]).unwrap();
- // group.bench_function("valence_write", |b| {
- // b.iter(|| {
- // let nbt = black_box(&nbt);
- // let mut written = Vec::new();
- // valence_nbt::to_binary_writer(&mut written, &nbt.0,
- // &nbt.1).unwrap(); black_box(written);
- // })
- // });
-}
-
-fn bench(c: &mut Criterion) {
- bench_read_file("tests/bigtest.nbt", c);
- // bench_read_file("tests/simple_player.dat", c);
- bench_read_file("tests/complex_player.dat", c);
- // bench_read_file("tests/level.dat", c);
- // bench_read_file("tests/stringtest.nbt", c);
- // bench_read_file("tests/inttest.nbt", c);
-}
-
-criterion_group!(benches, bench);
-criterion_main!(benches);
diff --git a/azalea-nbt/benches/nbt.rs b/azalea-nbt/benches/nbt.rs
deleted file mode 100755
index 60f620b5..00000000
--- a/azalea-nbt/benches/nbt.rs
+++ /dev/null
@@ -1,75 +0,0 @@
-use azalea_nbt::Nbt;
-use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
-use flate2::read::GzDecoder;
-use std::{
- fs::File,
- io::{Cursor, Read},
-};
-
-fn bench_file(filename: &str, c: &mut Criterion) {
- let mut file = File::open(filename).unwrap();
- let mut contents = Vec::new();
- file.read_to_end(&mut contents).unwrap();
- let mut src = &contents[..];
-
- // decode the original src so most of the time isn't spent on unzipping
- let mut decoded_src_decoder = GzDecoder::new(&mut src);
- let mut decoded_src = Vec::new();
- if decoded_src_decoder.read_to_end(&mut decoded_src).is_err() {
- // oh probably wasn't gzipped then
- decoded_src = contents;
- }
-
- let mut decoded_src_stream = Cursor::new(&decoded_src[..]);
-
- let nbt = Nbt::read(&mut decoded_src_stream).unwrap();
- decoded_src_stream.set_position(0);
-
- let mut group = c.benchmark_group(filename);
-
- group.throughput(Throughput::Bytes(decoded_src.len() as u64));
-
- group.bench_function("Decode", |b| {
- b.iter(|| {
- black_box(Nbt::read(&mut decoded_src_stream).unwrap());
- decoded_src_stream.set_position(0);
- })
- });
-
- group.bench_function("Encode", |b| {
- b.iter(|| {
- nbt.write(&mut black_box(Vec::new()));
- })
- });
-
- // group.bench_function("Get", |b| {
- // b.iter(|| {
- // let level = nbt
- // .as_compound()
- // .unwrap()
- // .get("Level")
- // .unwrap()
- // .as_compound()
- // .unwrap();
- // for (k, _) in level.iter() {
- // black_box(level.get(black_box(k)));
- // }
- // })
- // });
- group.finish();
-}
-
-fn bench(c: &mut Criterion) {
- bench_file("tests/bigtest.nbt", c);
- // bench_file("tests/simple_player.dat", c);
- // bench_file("tests/complex_player.dat", c);
- // bench_file("tests/level.dat", c);
- // bench_file("tests/stringtest.nbt", c);
- // bench_file("tests/inttest16.nbt", c);
-
- // bench_file("tests/inttest1023.nbt", c);
- // bench_file("tests/inttest3.nbt", c);
-}
-
-criterion_group!(benches, bench);
-criterion_main!(benches);
diff --git a/azalea-nbt/src/decode.rs b/azalea-nbt/src/decode.rs
deleted file mode 100755
index 23247b74..00000000
--- a/azalea-nbt/src/decode.rs
+++ /dev/null
@@ -1,314 +0,0 @@
-use crate::tag::*;
-use crate::Error;
-use azalea_buf::{BufReadError, McBufReadable};
-use byteorder::{ReadBytesExt, BE};
-use flate2::read::{GzDecoder, ZlibDecoder};
-use std::io::{BufRead, Cursor, Read};
-use tracing::warn;
-
-#[inline]
-fn read_bytes<'a>(buf: &'a mut Cursor<&[u8]>, length: usize) -> Result<&'a [u8], Error> {
- if length > (buf.get_ref().len() - buf.position() as usize) {
- return Err(Error::UnexpectedEof);
- }
- let initial_position = buf.position() as usize;
- buf.set_position(buf.position() + length as u64);
- let data = &buf.get_ref()[initial_position..initial_position + length];
- Ok(data)
-}
-
-#[inline]
-fn read_string(stream: &mut Cursor<&[u8]>) -> Result<NbtString, Error> {
- let length = stream.read_u16::<BE>()? as usize;
-
- let buf = read_bytes(stream, length)?;
-
- Ok(if let Ok(string) = std::str::from_utf8(buf) {
- string.into()
- } else {
- let lossy_string = String::from_utf8_lossy(buf).into_owned();
- warn!("Error decoding utf8 (bytes: {buf:?}, lossy: \"{lossy_string})\"");
- lossy_string.into()
- })
-}
-
-#[inline]
-fn read_byte_array(stream: &mut Cursor<&[u8]>) -> Result<NbtByteArray, Error> {
- let length = stream.read_u32::<BE>()? as usize;
- let bytes = read_bytes(stream, length)?.to_vec();
- Ok(bytes)
-}
-
-// https://stackoverflow.com/a/59707887
-fn vec_u8_into_i8(v: Vec<u8>) -> Vec<i8> {
- // ideally we'd use Vec::into_raw_parts, but it's unstable,
- // so we have to do it manually:
-
- // first, make sure v's destructor doesn't free the data
- // it thinks it owns when it goes out of scope
- let mut v = std::mem::ManuallyDrop::new(v);
-
- // then, pick apart the existing Vec
- let p = v.as_mut_ptr();
- let len = v.len();
- let cap = v.capacity();
-
- // finally, adopt the data into a new Vec
- unsafe { Vec::from_raw_parts(p as *mut i8, len, cap) }
-}
-
-#[inline]
-fn read_list(stream: &mut Cursor<&[u8]>) -> Result<NbtList, Error> {
- let type_id = stream.read_u8()?;
- let length = stream.read_u32::<BE>()?;
- let list = match type_id {
- END_ID => NbtList::Empty,
- BYTE_ID => NbtList::Byte(vec_u8_into_i8(
- read_bytes(stream, length as usize)?.to_vec(),
- )),
- SHORT_ID => NbtList::Short({
- if ((length * 2) as usize) > (stream.get_ref().len() - stream.position() as usize) {
- return Err(Error::UnexpectedEof);
- }
- (0..length)
- .map(|_| stream.read_i16::<BE>())
- .collect::<Result<Vec<_>, _>>()?
- }),
- INT_ID => NbtList::Int({
- if ((length * 4) as usize) > (stream.get_ref().len() - stream.position() as usize) {
- return Err(Error::UnexpectedEof);
- }
- (0..length)
- .map(|_| stream.read_i32::<BE>())
- .collect::<Result<Vec<_>, _>>()?
- }),
- LONG_ID => NbtList::Long({
- if ((length * 8) as usize) > (stream.get_ref().len() - stream.position() as usize) {
- return Err(Error::UnexpectedEof);
- }
- (0..length)
- .map(|_| stream.read_i64::<BE>())
- .collect::<Result<Vec<_>, _>>()?
- }),
- FLOAT_ID => NbtList::Float({
- if ((length * 4) as usize) > (stream.get_ref().len() - stream.position() as usize) {
- return Err(Error::UnexpectedEof);
- }
- (0..length)
- .map(|_| stream.read_f32::<BE>())
- .collect::<Result<Vec<_>, _>>()?
- }),
- DOUBLE_ID => NbtList::Double({
- if ((length * 8) as usize) > (stream.get_ref().len() - stream.position() as usize) {
- return Err(Error::UnexpectedEof);
- }
- (0..length)
- .map(|_| stream.read_f64::<BE>())
- .collect::<Result<Vec<_>, _>>()?
- }),
- BYTE_ARRAY_ID => NbtList::ByteArray({
- if ((length * 4) as usize) > (stream.get_ref().len() - stream.position() as usize) {
- return Err(Error::UnexpectedEof);
- }
- (0..length)
- .map(|_| read_byte_array(stream))
- .collect::<Result<Vec<_>, _>>()?
- }),
- STRING_ID => NbtList::String({
- if ((length * 4) as usize) > (stream.get_ref().len() - stream.position() as usize) {
- return Err(Error::UnexpectedEof);
- }
- (0..length)
- .map(|_| read_string(stream))
- .collect::<Result<Vec<_>, _>>()?
- }),
- LIST_ID => NbtList::List({
- if ((length * 4) as usize) > (stream.get_ref().len() - stream.position() as usize) {
- return Err(Error::UnexpectedEof);
- }
- (0..length)
- .map(|_| read_list(stream))
- .collect::<Result<Vec<_>, _>>()?
- }),
- COMPOUND_ID => NbtList::Compound({
- if ((length * 4) as usize) > (stream.get_ref().len() - stream.position() as usize) {
- return Err(Error::UnexpectedEof);
- }
- (0..length)
- .map(|_| read_compound(stream))
- .collect::<Result<Vec<_>, _>>()?
- }),
- INT_ARRAY_ID => NbtList::IntArray({
- if ((length * 4) as usize) > (stream.get_ref().len() - stream.position() as usize) {
- return Err(Error::UnexpectedEof);
- }
- (0..length)
- .map(|_| read_int_array(stream))
- .collect::<Result<Vec<_>, _>>()?
- }),
- LONG_ARRAY_ID => NbtList::LongArray({
- if ((length * 4) as usize) > (stream.get_ref().len() - stream.position() as usize) {
- return Err(Error::UnexpectedEof);
- }
- (0..length)
- .map(|_| read_long_array(stream))
- .collect::<Result<Vec<_>, _>>()?
- }),
- _ => return Err(Error::InvalidTagType(type_id)),
- };
- Ok(list)
-}
-
-#[inline]
-fn read_compound(stream: &mut Cursor<&[u8]>) -> Result<NbtCompound, Error> {
- // we default to capacity 4 because it'll probably not be empty
- let mut map = NbtCompound::with_capacity(4);
- loop {
- let tag_id = stream.read_u8().unwrap_or(0);
- if tag_id == 0 {
- break;
- }
- let name = read_string(stream)?;
- let tag = Nbt::read_known(stream, tag_id)?;
- map.insert_unsorted(name, tag);
- }
- map.sort();
- Ok(map)
-}
-
-#[inline]
-fn read_int_array(stream: &mut Cursor<&[u8]>) -> Result<NbtIntArray, Error> {
- let length = stream.read_u32::<BE>()? as usize;
- if length * 4 > (stream.get_ref().len() - stream.position() as usize) {
- return Err(Error::UnexpectedEof);
- }
- let mut ints = NbtIntArray::with_capacity(length);
- for _ in 0..length {
- ints.push(stream.read_i32::<BE>()?);
- }
- Ok(ints)
-}
-
-#[inline]
-fn read_long_array(stream: &mut Cursor<&[u8]>) -> Result<NbtLongArray, Error> {
- let length = stream.read_u32::<BE>()? as usize;
- if length * 8 > (stream.get_ref().len() - stream.position() as usize) {
- return Err(Error::UnexpectedEof);
- }
- let mut longs = NbtLongArray::with_capacity(length);
- for _ in 0..length {
- longs.push(stream.read_i64::<BE>()?);
- }
- Ok(longs)
-}
-
-impl Nbt {
- /// Read the NBT data when you already know the ID of the tag. You usually
- /// want [`Nbt::read`] if you're reading an NBT file.
- #[inline]
- fn read_known(stream: &mut Cursor<&[u8]>, id: u8) -> Result<Nbt, Error> {
- Ok(match id {
- // Signifies the end of a TAG_Compound. It is only ever used inside
- // a TAG_Compound, and is not named despite being in a TAG_Compound
- END_ID => Nbt::End,
- // A single signed byte
- BYTE_ID => Nbt::Byte(stream.read_i8()?),
- // A single signed, big endian 16 bit integer
- SHORT_ID => Nbt::Short(stream.read_i16::<BE>()?),
- // A single signed, big endian 32 bit integer
- INT_ID => Nbt::Int(stream.read_i32::<BE>()?),
- // A single signed, big endian 64 bit integer
- LONG_ID => Nbt::Long(stream.read_i64::<BE>()?),
- // A single, big endian IEEE-754 single-precision floating point
- // number (NaN possible)
- FLOAT_ID => Nbt::Float(stream.read_f32::<BE>()?),
- // A single, big endian IEEE-754 double-precision floating point
- // number (NaN possible)
- DOUBLE_ID => Nbt::Double(stream.read_f64::<BE>()?),
- // A length-prefixed array of signed bytes. The prefix is a signed
- // integer (thus 4 bytes)
- BYTE_ARRAY_ID => Nbt::ByteArray(read_byte_array(stream)?),
- // A length-prefixed modified UTF-8 string. The prefix is an
- // unsigned short (thus 2 bytes) signifying the length of the
- // string in bytes
- STRING_ID => Nbt::String(read_string(stream)?),
- // A list of nameless tags, all of the same type. The list is
- // prefixed with the Type ID of the items it contains (thus 1
- // byte), and the length of the list as a signed integer (a further
- // 4 bytes). If the length of the list is 0 or negative, the type
- // may be 0 (TAG_End) but otherwise it must be any other type. (The
- // notchian implementation uses TAG_End in that situation, but
- // another reference implementation by Mojang uses 1 instead;
- // parsers should accept any type if the length is <= 0).
- LIST_ID => Nbt::List(read_list(stream)?),
- // Effectively a list of a named tags. Order is not guaranteed.
- COMPOUND_ID => Nbt::Compound(read_compound(stream)?),
- // A length-prefixed array of signed integers. The prefix is a
- // signed integer (thus 4 bytes) and indicates the number of 4 byte
- // integers.
- INT_ARRAY_ID => Nbt::IntArray(read_int_array(stream)?),
- // A length-prefixed array of signed longs. The prefix is a signed
- // integer (thus 4 bytes) and indicates the number of 8 byte longs.
- LONG_ARRAY_ID => Nbt::LongArray(read_long_array(stream)?),
- _ => return Err(Error::InvalidTagType(id)),
- })
- }
-
- /// Read the NBT data. This will return a compound tag with a single item.
- ///
- /// Minecraft usually uses this function when reading from files.
- /// [`Nbt::read_any_tag`] is used when reading from the network.
- pub fn read(stream: &mut Cursor<&[u8]>) -> Result<Nbt, Error> {
- // default to compound tag
-
- // the parent compound only ever has one item
- let tag_id = stream.read_u8().unwrap_or(0);
- if tag_id == 0 {
- return Ok(Nbt::End);
- }
- let name = read_string(stream)?;
- let tag = Nbt::read_known(stream, tag_id)?;
- let mut map = NbtCompound::with_capacity(1);
- map.insert_unsorted(name, tag);
-
- Ok(Nbt::Compound(map))
- }
-
- /// Read the NBT data. There is no guarantee that the tag will be a compound
- /// with a single item.
- ///
- /// The Minecraft protocol uses this function when reading from the network.
- /// [`Nbt::read`] is usually used when reading from files.
- pub fn read_any_tag(stream: &mut Cursor<&[u8]>) -> Result<Nbt, Error> {
- let tag_id = stream.read_u8().unwrap_or(0);
- let tag = Nbt::read_known(stream, tag_id)?;
- Ok(tag)
- }
-
- /// Read the NBT data compressed wtih zlib.
- pub fn read_zlib(stream: &mut impl BufRead) -> Result<Nbt, Error> {
- let mut gz = ZlibDecoder::new(stream);
- let mut buf = Vec::new();
- gz.read_to_end(&mut buf)?;
- Nbt::read(&mut Cursor::new(&buf))
- }
-
- /// Read the NBT data compressed wtih gzip.
- pub fn read_gzip(stream: &mut Cursor<Vec<u8>>) -> Result<Nbt, Error> {
- let mut gz = GzDecoder::new(stream);
- let mut buf = Vec::new();
- gz.read_to_end(&mut buf)?;
- Nbt::read(&mut Cursor::new(&buf))
- }
-}
-
-impl McBufReadable for Nbt {
- fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
- Ok(Nbt::read_any_tag(buf)?)
- }
-}
-impl From<Error> for BufReadError {
- fn from(e: Error) -> Self {
- BufReadError::Custom(e.to_string())
- }
-}
diff --git a/azalea-nbt/src/encode.rs b/azalea-nbt/src/encode.rs
deleted file mode 100755
index 34c451d2..00000000
--- a/azalea-nbt/src/encode.rs
+++ /dev/null
@@ -1,296 +0,0 @@
-use crate::tag::*;
-use azalea_buf::McBufWritable;
-use byteorder::{WriteBytesExt, BE};
-use flate2::write::{GzEncoder, ZlibEncoder};
-// use packed_simd_2::{i32x16, i32x2, i32x4, i32x8, i64x2, i64x4, i64x8};
-use std::io::Write;
-
-#[inline]
-fn write_string(writer: &mut impl Write, string: &NbtString) {
- writer.write_u16::<BE>(string.len() as u16).unwrap();
- writer.write_all(string.as_bytes()).unwrap();
-}
-
-#[inline]
-fn write_compound(writer: &mut impl Write, value: &NbtCompound, end_tag: bool) {
- for (key, tag) in value.iter() {
- writer.write_u8(tag.id()).unwrap();
- write_string(writer, key);
- write_known(writer, tag);
- }
- if end_tag {
- writer.write_u8(END_ID).unwrap();
- }
-}
-
-fn write_known(writer: &mut impl Write, tag: &Nbt) {
- match tag {
- Nbt::End => {}
- Nbt::Byte(value) => {
- writer.write_i8(*value).unwrap();
- }
- Nbt::Short(value) => {
- writer.write_i16::<BE>(*value).unwrap();
- }
- Nbt::Int(value) => {
- writer.write_i32::<BE>(*value).unwrap();
- }
- Nbt::Long(value) => {
- writer.write_i64::<BE>(*value).unwrap();
- }
- Nbt::Float(value) => {
- writer.write_f32::<BE>(*value).unwrap();
- }
- Nbt::Double(value) => {
- writer.write_f64::<BE>(*value).unwrap();
- }
- Nbt::ByteArray(value) => {
- write_byte_array(writer, value);
- }
- Nbt::String(value) => {
- write_string(writer, value);
- }
- Nbt::List(value) => {
- write_list(writer, value);
- }
- Nbt::Compound(value) => {
- write_compound(writer, value, true);
- }
- Nbt::IntArray(value) => {
- write_int_array(writer, value);
- }
- Nbt::LongArray(value) => {
- write_long_array(writer, value);
- }
- }
-}
-
-#[inline]
-fn write_list(writer: &mut impl Write, value: &NbtList) {
- writer.write_u8(value.id()).unwrap();
- match value {
- NbtList::Empty => writer.write_all(&[0; 4]).unwrap(),
- NbtList::Byte(l) => {
- writer.write_i32::<BE>(l.len() as i32).unwrap();
- let l = l.as_slice();
- writer
- // convert [i8] into [u8]
- .write_all(unsafe { std::slice::from_raw_parts(l.as_ptr() as *const u8, l.len()) })
- .unwrap();
- }
- NbtList::Short(l) => {
- writer.write_i32::<BE>(l.len() as i32).unwrap();
- for &v in l {
- writer.write_i16::<BE>(v).unwrap();
- }
- }
- NbtList::Int(l) => write_int_array(writer, l),
- NbtList::Long(l) => write_long_array(writer, l),
- NbtList::Float(l) => {
- writer.write_i32::<BE>(l.len() as i32).unwrap();
- for &v in l {
- writer.write_f32::<BE>(v).unwrap();
- }
- }
- NbtList::Double(l) => {
- writer.write_i32::<BE>(l.len() as i32).unwrap();
- for &v in l {
- writer.write_f64::<BE>(v).unwrap();
- }
- }
- NbtList::ByteArray(l) => {
- writer.write_i32::<BE>(l.len() as i32).unwrap();
- for v in l {
- write_byte_array(writer, v);
- }
- }
- NbtList::String(l) => {
- writer.write_i32::<BE>(l.len() as i32).unwrap();
- for v in l {
- write_string(writer, v);
- }
- }
- NbtList::List(l) => {
- writer.write_i32::<BE>(l.len() as i32).unwrap();
- for v in l {
- write_list(writer, v);
- }
- }
- NbtList::Compound(l) => {
- writer.write_i32::<BE>(l.len() as i32).unwrap();
- for v in l {
- write_compound(writer, v, true);
- }
- }
- NbtList::IntArray(l) => {
- writer.write_i32::<BE>(l.len() as i32).unwrap();
- for v in l {
- write_int_array(writer, v);
- }
- }
- NbtList::LongArray(l) => {
- writer.write_i32::<BE>(l.len() as i32).unwrap();
- for v in l {
- write_long_array(writer, v);
- }
- }
- }
-}
-
-#[inline]
-fn write_byte_array(writer: &mut impl Write, value: &[u8]) {
- writer.write_u32::<BE>(value.len() as u32).unwrap();
- writer.write_all(value).unwrap();
-}
-
-#[inline]
-fn write_int_array(writer: &mut impl Write, array: &[i32]) {
- writer.write_i32::<BE>(array.len() as i32).unwrap();
-
- for &item in array {
- writer.write_i32::<BE>(item).unwrap();
- }
-
- // (disabled for now since i realized packed_simd to_be does not work as
- // expected) // flip the bits to big endian with simd
- // let mut position = 0;
- // // x16
- // while array.len() - position >= 16 {
- // let l = unsafe {
- // i32x16::from_slice_unaligned_unchecked(&array[position..]) }; let
- // l = l.to_be(); let l = unsafe { std::mem::transmute::<i32x16,
- // [u8; 64]>(l) }; writer.write_all(&l).unwrap();
- // position += 16;
- // }
- // // x8
- // if array.len() - position >= 8 {
- // let l = unsafe {
- // i32x8::from_slice_unaligned_unchecked(&array[position..]) };
- // let l = l.to_be();
- // let l = unsafe { std::mem::transmute::<i32x8, [u8; 32]>(l) };
- // writer.write_all(&l).unwrap();
- // position += 8;
- // }
- // // x4
- // if array.len() - position >= 4 {
- // let l = unsafe {
- // i32x4::from_slice_unaligned_unchecked(&array[position..]) };
- // let l = l.to_be();
- // let l = unsafe { std::mem::transmute::<i32x4, [u8; 16]>(l) };
- // writer.write_all(&l).unwrap();
- // position += 4;
- // }
- // // x2
- // if array.len() - position >= 2 {
- // let l = unsafe {
- // i32x2::from_slice_unaligned_unchecked(&array[position..]) };
- // let l = l.to_be();
- // let l = l.swap_bytes();
- // let l = unsafe { std::mem::transmute::<i32x2, [u8; 8]>(l) };
- // writer.write_all(&l).unwrap();
- // position += 2;
- // }
- // // x1 ... just a normal write_i32
- // if array.len() - position >= 1 {
- // writer.write_i32::<BE>(array[position]).unwrap();
- // }
-}
-
-#[inline]
-fn write_long_array(writer: &mut impl Write, l: &[i64]) {
- writer.write_i32::<BE>(l.len() as i32).unwrap();
-
- for &item in l {
- writer.write_i64::<BE>(item).unwrap();
- }
-
- // (disabled for now since i realized packed_simd to_be does not work as
- // expected)
-
- // // flip the bits to big endian with simd
- // let mut position = 0;
- // // x16
- // while l.len() - position >= 8 {
- // let l = unsafe {
- // i64x8::from_slice_unaligned_unchecked(&l[position..]) };
- // l.to_be();
- // let l = unsafe { std::mem::transmute::<i64x8, [u8; 64]>(l) };
- // writer.write_all(&l).unwrap();
- // position += 8;
- // }
- // // x4
- // if l.len() - position >= 4 {
- // let l = unsafe {
- // i64x4::from_slice_unaligned_unchecked(&l[position..]) };
- // l.to_be();
- // let l = unsafe { std::mem::transmute::<i64x4, [u8; 32]>(l) };
- // writer.write_all(&l).unwrap();
- // position += 4;
- // }
- // // x2
- // if l.len() - position >= 2 {
- // let l = unsafe {
- // i64x2::from_slice_unaligned_unchecked(&l[position..]) };
- // l.to_be();
- // let l = unsafe { std::mem::transmute::<i64x2, [u8; 16]>(l) };
- // writer.write_all(&l).unwrap();
- // position += 2;
- // }
- // // x1 ... just a normal write_i32
- // if l.len() - position >= 1 {
- // writer.write_i64::<BE>(l[position]).unwrap();
- // }
-}
-
-impl Nbt {
- /// Write the compound tag as NBT data.
- ///
- /// # Panics
- ///
- /// Will panic if the tag is not a Compound or End tag.
- pub fn write(&self, writer: &mut impl Write) {
- match self {
- Nbt::Compound(value) => {
- write_compound(writer, value, false);
- }
- Nbt::End => {
- END_ID.write_into(writer).unwrap();
- }
- _ => panic!("Not a compound tag"),
- }
- }
-
- /// Write any tag as NBT data. This is used by Minecraft when writing to the
- /// network, otherwise [`Nbt::write`] is usually used instead.
- pub fn write_any(&self, writer: &mut impl Write) {
- writer.write_u8(self.id()).unwrap();
- write_known(writer, self);
- }
-
- /// Write the compound tag as NBT data compressed wtih zlib.
- ///
- /// # Errors
- ///
- /// Returns an `Err` if it's not a Compound or End tag.
- pub fn write_zlib(&self, writer: &mut impl Write) {
- let mut encoder = ZlibEncoder::new(writer, flate2::Compression::default());
- self.write(&mut encoder)
- }
-
- /// Write the compound tag as NBT data compressed wtih gzip.
- ///
- /// # Errors
- ///
- /// Returns an `Err` if it's not a Compound or End tag.
- pub fn write_gzip(&self, writer: &mut impl Write) {
- let mut encoder = GzEncoder::new(writer, flate2::Compression::default());
- self.write(&mut encoder)
- }
-}
-
-impl McBufWritable for Nbt {
- fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
- self.write_any(buf);
- Ok(())
- }
-}
diff --git a/azalea-nbt/src/error.rs b/azalea-nbt/src/error.rs
deleted file mode 100755
index ace7fcd3..00000000
--- a/azalea-nbt/src/error.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-use thiserror::Error;
-
-#[derive(Debug, Error)]
-pub enum Error {
- #[error("Invalid tag type: {0}")]
- InvalidTagType(u8),
- #[error("Invalid tag")]
- InvalidTag,
- #[error("Write error: {0}")]
- WriteError(#[from] std::io::Error),
- #[error("Utf8 error: {0}")]
- Utf8Error(#[from] std::str::Utf8Error),
- #[error("Unexpected EOF")]
- UnexpectedEof,
-}
diff --git a/azalea-nbt/src/lib.rs b/azalea-nbt/src/lib.rs
deleted file mode 100755
index 1a636520..00000000
--- a/azalea-nbt/src/lib.rs
+++ /dev/null
@@ -1,46 +0,0 @@
-#![doc = include_str!("../README.md")]
-
-mod decode;
-mod encode;
-mod error;
-mod tag;
-
-pub use error::Error;
-pub use tag::*;
-
-#[cfg(test)]
-mod tests {
- use std::io::Cursor;
-
- use crate::tag::NbtCompound;
-
- use super::*;
- use azalea_buf::{McBufReadable, McBufWritable};
-
- #[test]
- fn mcbuf_nbt() {
- let mut buf = Vec::new();
- let tag = Nbt::Compound(NbtCompound::from_iter(vec![(
- "hello world".into(),
- Nbt::Compound(NbtCompound::from_iter(vec![(
- "name".into(),
- Nbt::String("Bananrama".into()),
- )])),
- )]));
- tag.write_into(&mut buf).unwrap();
-
- let mut buf = Cursor::new(&buf[..]);
-
- let result = Nbt::read_from(&mut buf).unwrap();
- assert_eq!(
- result,
- Nbt::Compound(NbtCompound::from_iter(vec![(
- "hello world".into(),
- Nbt::Compound(NbtCompound::from_iter(vec![(
- "name".into(),
- Nbt::String("Bananrama".into()),
- )])),
- )]))
- );
- }
-}
diff --git a/azalea-nbt/src/tag.rs b/azalea-nbt/src/tag.rs
deleted file mode 100755
index 224db2d3..00000000
--- a/azalea-nbt/src/tag.rs
+++ /dev/null
@@ -1,271 +0,0 @@
-use compact_str::CompactString;
-use enum_as_inner::EnumAsInner;
-#[cfg(feature = "serde")]
-use serde::{ser::SerializeMap, Deserialize, Serialize};
-
-pub type NbtByte = i8;
-pub type NbtShort = i16;
-pub type NbtInt = i32;
-pub type NbtLong = i64;
-pub type NbtFloat = f32;
-pub type NbtDouble = f64;
-pub type NbtByteArray = Vec<u8>;
-pub type NbtString = CompactString;
-pub type NbtIntArray = Vec<i32>;
-pub type NbtLongArray = Vec<i64>;
-
-pub const END_ID: u8 = 0;
-pub const BYTE_ID: u8 = 1;
-pub const SHORT_ID: u8 = 2;
-pub const INT_ID: u8 = 3;
-pub const LONG_ID: u8 = 4;
-pub const FLOAT_ID: u8 = 5;
-pub const DOUBLE_ID: u8 = 6;
-pub const BYTE_ARRAY_ID: u8 = 7;
-pub const STRING_ID: u8 = 8;
-pub const LIST_ID: u8 = 9;
-pub const COMPOUND_ID: u8 = 10;
-pub const INT_ARRAY_ID: u8 = 11;
-pub const LONG_ARRAY_ID: u8 = 12;
-
-/// An NBT value.
-#[derive(Clone, Debug, PartialEq, Default, EnumAsInner)]
-#[repr(u8)]
-#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(untagged))]
-pub enum Nbt {
- #[default]
- End = END_ID,
- Byte(NbtByte) = BYTE_ID,
- Short(NbtShort) = SHORT_ID,
- Int(NbtInt) = INT_ID,
- Long(NbtLong) = LONG_ID,
- Float(NbtFloat) = FLOAT_ID,
- Double(NbtDouble) = DOUBLE_ID,
- ByteArray(NbtByteArray) = BYTE_ARRAY_ID,
- String(NbtString) = STRING_ID,
- List(NbtList) = LIST_ID,
- Compound(NbtCompound) = COMPOUND_ID,
- IntArray(NbtIntArray) = INT_ARRAY_ID,
- LongArray(NbtLongArray) = LONG_ARRAY_ID,
-}
-impl Nbt {
- /// Get the numerical ID of the tag type.
- #[inline]
- pub fn id(&self) -> u8 {
- // SAFETY: Because `Self` is marked `repr(u8)`, its layout is a `repr(C)`
- // `union` between `repr(C)` structs, each of which has the `u8`
- // discriminant as its first field, so we can read the discriminant
- // without offsetting the pointer.
- unsafe { *<*const _>::from(self).cast::<u8>() }
- }
-}
-
-/// An NBT value.
-#[derive(Clone, Debug, PartialEq)]
-#[repr(u8)]
-#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(untagged))]
-pub enum NbtList {
- Empty = END_ID,
- Byte(Vec<NbtByte>) = BYTE_ID,
- Short(Vec<NbtShort>) = SHORT_ID,
- Int(Vec<NbtInt>) = INT_ID,
- Long(Vec<NbtLong>) = LONG_ID,
- Float(Vec<NbtFloat>) = FLOAT_ID,
- Double(Vec<NbtDouble>) = DOUBLE_ID,
- ByteArray(Vec<NbtByteArray>) = BYTE_ARRAY_ID,
- String(Vec<NbtString>) = STRING_ID,
- List(Vec<NbtList>) = LIST_ID,
- Compound(Vec<NbtCompound>) = COMPOUND_ID,
- IntArray(Vec<NbtIntArray>) = INT_ARRAY_ID,
- LongArray(Vec<NbtLongArray>) = LONG_ARRAY_ID,
-}
-
-impl NbtList {
- /// Get the numerical ID of the tag type.
- #[inline]
- pub fn id(&self) -> u8 {
- // SAFETY: Because `Self` is marked `repr(u8)`, its layout is a `repr(C)`
- // `union` between `repr(C)` structs, each of which has the `u8`
- // discriminant as its first field, so we can read the discriminant
- // without offsetting the pointer.
- unsafe { *<*const _>::from(self).cast::<u8>() }
- }
-}
-impl From<Vec<NbtByte>> for NbtList {
- fn from(v: Vec<NbtByte>) -> Self {
- Self::Byte(v)
- }
-}
-impl From<Vec<NbtShort>> for NbtList {
- fn from(v: Vec<NbtShort>) -> Self {
- Self::Short(v)
- }
-}
-impl From<Vec<NbtInt>> for NbtList {
- fn from(v: Vec<NbtInt>) -> Self {
- Self::Int(v)
- }
-}
-impl From<Vec<NbtLong>> for NbtList {
- fn from(v: Vec<NbtLong>) -> Self {
- Self::Long(v)
- }
-}
-impl From<Vec<NbtFloat>> for NbtList {
- fn from(v: Vec<NbtFloat>) -> Self {
- Self::Float(v)
- }
-}
-impl From<Vec<NbtDouble>> for NbtList {
- fn from(v: Vec<NbtDouble>) -> Self {
- Self::Double(v)
- }
-}
-impl From<Vec<NbtByteArray>> for NbtList {
- fn from(v: Vec<NbtByteArray>) -> Self {
- Self::ByteArray(v)
- }
-}
-impl From<Vec<NbtString>> for NbtList {
- fn from(v: Vec<NbtString>) -> Self {
- Self::String(v)
- }
-}
-impl From<Vec<NbtList>> for NbtList {
- fn from(v: Vec<NbtList>) -> Self {
- Self::List(v)
- }
-}
-impl From<Vec<NbtCompound>> for NbtList {
- fn from(v: Vec<NbtCompound>) -> Self {
- Self::Compound(v)
- }
-}
-impl From<Vec<NbtIntArray>> for NbtList {
- fn from(v: Vec<NbtIntArray>) -> Self {
- Self::IntArray(v)
- }
-}
-impl From<Vec<NbtLongArray>> for NbtList {
- fn from(v: Vec<NbtLongArray>) -> Self {
- Self::LongArray(v)
- }
-}
-
-// thanks to Moulberry/Graphite for the idea to use a vec and binary search
-#[derive(Debug, Clone, Default, PartialEq)]
-pub struct NbtCompound {
- inner: Vec<(NbtString, Nbt)>,
-}
-impl NbtCompound {
- #[inline]
- pub fn with_capacity(capacity: usize) -> Self {
- Self {
- inner: Vec::with_capacity(capacity),
- }
- }
-
- #[inline]
- fn binary_search(&self, key: &NbtString) -> Result<usize, usize> {
- self.inner.binary_search_by(|(k, _)| k.cmp(key))
- }
-
- /// Get a reference to the value corresponding to the key in this compound.
- ///
- /// If you previously used [`Self::insert_unsorted`] without [`Self::sort`],
- /// this function may return incorrect results.
- #[inline]
- pub fn get(&self, key: &str) -> Option<&Nbt> {
- if self.is_worth_sorting() {
- let key = NbtString::from(key);
- self.binary_search(&key).ok().map(|i| &self.inner[i].1)
- } else {
- for (k, v) in &self.inner {
- if &key == k {
- return Some(v);
- }
- }
- None
- }
- }
-
- #[inline]
- pub fn insert_unsorted(&mut self, key: NbtString, value: Nbt) {
- self.inner.push((key, value));
- }
-
- /// Insert an item into the compound, returning the previous value if it
- /// existed.
- ///
- /// If you're adding many items at once, it's more efficient to use
- /// [`Self::insert_unsorted`] and then [`Self::sort`] after everything is
- /// inserted.
- #[inline]
- pub fn insert(&mut self, key: NbtString, value: Nbt) {
- self.inner.push((key, value));
- self.sort()
- }
-
- #[inline]
- pub fn sort(&mut self) {
- if !self.is_worth_sorting() {
- return;
- }
- self.inner.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
- }
-
- #[inline]
- pub fn iter(&self) -> std::slice::Iter<'_, (CompactString, Nbt)> {
- self.inner.iter()
- }
-
- #[inline]
- fn is_worth_sorting(&self) -> bool {
- // i don't actually know when binary search starts being better, but it's at
- // least more than 12
- self.inner.len() >= 32
- }
-}
-
-impl IntoIterator for NbtCompound {
- type Item = (NbtString, Nbt);
- type IntoIter = std::vec::IntoIter<Self::Item>;
-
- fn into_iter(self) -> Self::IntoIter {
- self.inner.into_iter()
- }
-}
-
-#[cfg(feature = "serde")]
-impl Serialize for NbtCompound {
- fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
- let mut map = serializer.serialize_map(Some(self.inner.len()))?;
- for (key, value) in &self.inner {
- map.serialize_entry(key, value)?;
- }
- map.end()
- }
-}
-#[cfg(feature = "serde")]
-impl<'de> Deserialize<'de> for NbtCompound {
- fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
- use std::collections::BTreeMap;
- let map = <BTreeMap<NbtString, Nbt> as Deserialize>::deserialize(deserializer)?;
- Ok(Self {
- inner: map.into_iter().collect(),
- })
- }
-}
-
-impl FromIterator<(NbtString, Nbt)> for NbtCompound {
- fn from_iter<T: IntoIterator<Item = (NbtString, Nbt)>>(iter: T) -> Self {
- let inner = iter.into_iter().collect::<Vec<_>>();
- Self { inner }
- }
-}
-
-impl From<Vec<(NbtString, Nbt)>> for NbtCompound {
- fn from(inner: Vec<(NbtString, Nbt)>) -> Self {
- Self { inner }
- }
-}
diff --git a/azalea-nbt/tests/bigtest.nbt b/azalea-nbt/tests/bigtest.nbt
deleted file mode 100755
index dc3769bc..00000000
--- a/azalea-nbt/tests/bigtest.nbt
+++ /dev/null
Binary files differ
diff --git a/azalea-nbt/tests/complex_player.dat b/azalea-nbt/tests/complex_player.dat
deleted file mode 100755
index d7f3fcbd..00000000
--- a/azalea-nbt/tests/complex_player.dat
+++ /dev/null
Binary files differ
diff --git a/azalea-nbt/tests/hello_world.nbt b/azalea-nbt/tests/hello_world.nbt
deleted file mode 100755
index f3f5e21a..00000000
--- a/azalea-nbt/tests/hello_world.nbt
+++ /dev/null
Binary files differ
diff --git a/azalea-nbt/tests/inttest1023.nbt b/azalea-nbt/tests/inttest1023.nbt
deleted file mode 100644
index 481dde19..00000000
--- a/azalea-nbt/tests/inttest1023.nbt
+++ /dev/null
Binary files differ
diff --git a/azalea-nbt/tests/inttest16.nbt b/azalea-nbt/tests/inttest16.nbt
deleted file mode 100755
index ad9255f2..00000000
--- a/azalea-nbt/tests/inttest16.nbt
+++ /dev/null
Binary files differ
diff --git a/azalea-nbt/tests/inttest3.nbt b/azalea-nbt/tests/inttest3.nbt
deleted file mode 100644
index 2890f577..00000000
--- a/azalea-nbt/tests/inttest3.nbt
+++ /dev/null
Binary files differ
diff --git a/azalea-nbt/tests/level.dat b/azalea-nbt/tests/level.dat
deleted file mode 100755
index e5d11b8c..00000000
--- a/azalea-nbt/tests/level.dat
+++ /dev/null
Binary files differ
diff --git a/azalea-nbt/tests/simple_player.dat b/azalea-nbt/tests/simple_player.dat
deleted file mode 100755
index e5091b41..00000000
--- a/azalea-nbt/tests/simple_player.dat
+++ /dev/null
Binary files differ
diff --git a/azalea-nbt/tests/stringtest.nbt b/azalea-nbt/tests/stringtest.nbt
deleted file mode 100755
index ac111433..00000000
--- a/azalea-nbt/tests/stringtest.nbt
+++ /dev/null
Binary files differ
diff --git a/azalea-nbt/tests/tests.rs b/azalea-nbt/tests/tests.rs
deleted file mode 100755
index 5c82c3c7..00000000
--- a/azalea-nbt/tests/tests.rs
+++ /dev/null
@@ -1,140 +0,0 @@
-use azalea_nbt::{Nbt, NbtCompound, NbtList};
-use std::io::Cursor;
-
-#[test]
-fn test_decode_hello_world() {
- // read hello_world.nbt
- let buf = include_bytes!("hello_world.nbt").to_vec();
- let tag = Nbt::read(&mut Cursor::new(&buf[..])).unwrap();
- assert_eq!(
- tag,
- Nbt::Compound(NbtCompound::from_iter(vec![(
- "hello world".into(),
- Nbt::Compound(NbtCompound::from_iter(vec![(
- "name".into(),
- Nbt::String("Bananrama".into()),
- )]))
- )]))
- );
-}
-
-#[test]
-fn test_roundtrip_hello_world() {
- let original = include_bytes!("hello_world.nbt").to_vec();
-
- let mut original_stream = Cursor::new(&original[..]);
- let tag = Nbt::read(&mut original_stream).unwrap();
-
- // write hello_world.nbt
- let mut result = Vec::new();
- tag.write(&mut result);
-
- assert_eq!(result, original);
-}
-
-#[test]
-fn test_bigtest() {
- // read bigtest.nbt
- let original = include_bytes!("bigtest.nbt").to_vec();
-
- let mut original_stream = Cursor::new(original);
- let original_tag = Nbt::read_gzip(&mut original_stream).unwrap();
-
- let mut result = Vec::new();
- original_tag.write(&mut result);
-
- let decoded_tag = Nbt::read(&mut Cursor::new(&result)).unwrap();
-
- assert_eq!(decoded_tag, original_tag);
-}
-
-#[test]
-fn test_stringtest() {
- let correct_tag = Nbt::Compound(NbtCompound::from_iter(vec![(
- "😃".into(),
- Nbt::List(NbtList::String(vec![
- "asdfkghasfjgihsdfogjsndfg".into(),
- "jnabsfdgihsabguiqwrntgretqwejirhbiqw".into(),
- "asd".into(),
- "wqierjgt7wqy8u4rtbwreithwretiwerutbwenryq8uwervqwer9iuqwbrgyuqrbtwierotugqewrtqwropethert".into(),
- "asdf".into(),
- "alsdkjiqwoe".into(),
- "lmqi9hyqd".into(),
- "qwertyuiop".into(),
- "asdfghjkl".into(),
- "zxcvbnm".into(),
- " ".into(),
- "words words words words words words".into(),
- "aaaaaaaaaaaaaaaaaaaa".into(),
- "♥".into(),
- "a\nb\n\n\nc\r\rd".into(),
- "😁".into(),
- ]))
- )]));
- let original = include_bytes!("stringtest.nbt").to_vec();
-
- let mut original_stream = Cursor::new(original);
- let original_tag = Nbt::read_gzip(&mut original_stream).unwrap();
-
- assert_eq!(original_tag, correct_tag);
-}
-
-#[test]
-fn test_complex_player() {
- let original = include_bytes!("complex_player.dat").to_vec();
-
- let mut original_stream = Cursor::new(original);
- let original_tag = Nbt::read_gzip(&mut original_stream).unwrap();
-
- let mut result = Vec::new();
- original_tag.write(&mut result);
-
- let decoded_tag = Nbt::read(&mut Cursor::new(&result)).unwrap();
-
- assert_eq!(decoded_tag, original_tag);
-}
-
-#[test]
-fn test_simple_player() {
- let original = include_bytes!("simple_player.dat").to_vec();
-
- let mut original_stream = Cursor::new(original);
- let original_tag = Nbt::read_gzip(&mut original_stream).unwrap();
-
- let mut result = Vec::new();
- original_tag.write(&mut result);
-
- let decoded_tag = Nbt::read(&mut Cursor::new(&result)).unwrap();
-
- assert_eq!(decoded_tag, original_tag);
-}
-
-// #[test]
-// fn test_inttest() {
-// let original = include_bytes!("inttest.nbt").to_vec();
-
-// let mut original_stream = Cursor::new(original);
-// let original_tag = Nbt::read_gzip(&mut original_stream).unwrap();
-
-// let mut result = Vec::new();
-// original_tag.write(&mut result);
-
-// let decoded_tag = Nbt::read(&mut Cursor::new(&result)).unwrap();
-
-// assert_eq!(decoded_tag, original_tag);
-// }
-
-#[test]
-fn test_inttest1023() {
- let original = include_bytes!("inttest1023.nbt").to_vec();
-
- let mut original_stream = Cursor::new(original.as_slice());
- let original_tag = Nbt::read(&mut original_stream).unwrap();
-
- let mut result = Vec::new();
- original_tag.write(&mut result);
-
- let decoded_tag = Nbt::read(&mut Cursor::new(&result)).unwrap();
-
- assert_eq!(decoded_tag, original_tag);
-}
diff --git a/azalea-protocol/Cargo.toml b/azalea-protocol/Cargo.toml
index 9a143ed5..81a3dde1 100644
--- a/azalea-protocol/Cargo.toml
+++ b/azalea-protocol/Cargo.toml
@@ -27,9 +27,7 @@ azalea-core = { path = "../azalea-core", optional = true, version = "^0.8.0", fe
azalea-crypto = { path = "../azalea-crypto", version = "0.8.0" }
azalea-entity = { version = "0.8.0", path = "../azalea-entity" }
azalea-inventory = { version = "0.8.0", path = "../azalea-inventory" }
-azalea-nbt = { path = "../azalea-nbt", version = "^0.8.0", features = [
- "serde",
-] }
+simdnbt = { version = "0.2.1" }
azalea-protocol-macros = { path = "./azalea-protocol-macros", version = "0.8.0" }
azalea-registry = { path = "../azalea-registry", version = "0.8.0" }
azalea-world = { path = "../azalea-world", version = "0.8.0" }
diff --git a/azalea-protocol/src/packets/game/clientbound_block_entity_data_packet.rs b/azalea-protocol/src/packets/game/clientbound_block_entity_data_packet.rs
index f9c889f8..95e9c6c3 100755
--- a/azalea-protocol/src/packets/game/clientbound_block_entity_data_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_block_entity_data_packet.rs
@@ -1,10 +1,11 @@
use azalea_buf::McBuf;
use azalea_core::position::BlockPos;
use azalea_protocol_macros::ClientboundGamePacket;
+use simdnbt::owned::NbtTag;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
pub struct ClientboundBlockEntityDataPacket {
pub pos: BlockPos,
pub block_entity_type: azalea_registry::BlockEntityKind,
- pub tag: azalea_nbt::Nbt,
+ pub tag: NbtTag,
}
diff --git a/azalea-protocol/src/packets/game/clientbound_level_chunk_with_light_packet.rs b/azalea-protocol/src/packets/game/clientbound_level_chunk_with_light_packet.rs
index c10fa737..f8927ca4 100755
--- a/azalea-protocol/src/packets/game/clientbound_level_chunk_with_light_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_level_chunk_with_light_packet.rs
@@ -1,6 +1,6 @@
use azalea_buf::McBuf;
-use azalea_nbt::Nbt;
use azalea_protocol_macros::ClientboundGamePacket;
+use simdnbt::owned::Nbt;
use super::clientbound_light_update_packet::ClientboundLightUpdatePacketData;
diff --git a/azalea-protocol/src/packets/game/clientbound_tag_query_packet.rs b/azalea-protocol/src/packets/game/clientbound_tag_query_packet.rs
index db238f66..d1073cd5 100755
--- a/azalea-protocol/src/packets/game/clientbound_tag_query_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_tag_query_packet.rs
@@ -1,9 +1,10 @@
use azalea_buf::McBuf;
use azalea_protocol_macros::ClientboundGamePacket;
+use simdnbt::owned::NbtTag;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
pub struct ClientboundTagQueryPacket {
#[var]
pub transaction_id: u32,
- pub tag: azalea_nbt::Nbt,
+ pub tag: NbtTag,
}
diff --git a/azalea-protocol/src/packets/game/clientbound_update_mob_effect_packet.rs b/azalea-protocol/src/packets/game/clientbound_update_mob_effect_packet.rs
index c43d64bb..37ffd9ce 100755
--- a/azalea-protocol/src/packets/game/clientbound_update_mob_effect_packet.rs
+++ b/azalea-protocol/src/packets/game/clientbound_update_mob_effect_packet.rs
@@ -1,5 +1,6 @@
use azalea_buf::McBuf;
use azalea_protocol_macros::ClientboundGamePacket;
+use simdnbt::owned::NbtTag;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
pub struct ClientboundUpdateMobEffectPacket {
@@ -10,5 +11,5 @@ pub struct ClientboundUpdateMobEffectPacket {
#[var]
pub effect_duration_ticks: u32,
pub flags: u8,
- pub factor_data: Option<azalea_nbt::Nbt>,
+ pub factor_data: Option<NbtTag>,
}
diff --git a/azalea-registry/Cargo.toml b/azalea-registry/Cargo.toml
index b32c5759..ffd59035 100644
--- a/azalea-registry/Cargo.toml
+++ b/azalea-registry/Cargo.toml
@@ -12,8 +12,8 @@ version = "0.8.0"
azalea-buf = { path = "../azalea-buf", version = "0.8.0" }
azalea-registry-macros = { path = "./azalea-registry-macros", version = "0.8.0" }
once_cell = "1.18.0"
-serde = { version = "^1.0", optional = true }
+simdnbt = { version = "0.2.1" }
[features]
-serde = ["dep:serde", "azalea-registry-macros/serde"]
+serde = ["azalea-registry-macros/serde"]
default = ["serde"]
diff --git a/azalea-registry/azalea-registry-macros/src/lib.rs b/azalea-registry/azalea-registry-macros/src/lib.rs
index 3bf798a5..f3289d96 100755
--- a/azalea-registry/azalea-registry-macros/src/lib.rs
+++ b/azalea-registry/azalea-registry-macros/src/lib.rs
@@ -75,7 +75,7 @@ pub fn registry(input: TokenStream) -> TokenStream {
let attributes = input.attributes;
generated.extend(quote! {
#(#attributes)*
- #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, azalea_buf::McBuf)]
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, azalea_buf::McBuf, simdnbt::ToNbtTag, simdnbt::FromNbtTag)]
#[repr(u32)]
pub enum #name {
#enum_items
@@ -167,28 +167,5 @@ pub fn registry(input: TokenStream) -> TokenStream {
}
});
- #[cfg(feature = "serde")]
- {
- generated.extend(quote! {
- impl serde::Serialize for #name {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: serde::Serializer,
- {
- serializer.serialize_str(&self.to_string())
- }
- }
- impl<'de> serde::Deserialize<'de> for #name {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: serde::Deserializer<'de>,
- {
- let s = String::deserialize(deserializer)?;
- s.parse().map_err(serde::de::Error::custom)
- }
- }
- });
- }
-
generated.into()
}
diff --git a/azalea-world/Cargo.toml b/azalea-world/Cargo.toml
index 4e0b4efa..ef2d6517 100644
--- a/azalea-world/Cargo.toml
+++ b/azalea-world/Cargo.toml
@@ -15,7 +15,7 @@ azalea-core = { path = "../azalea-core", version = "^0.8.0", features = [
"bevy_ecs",
] }
azalea-inventory = { version = "0.8.0", path = "../azalea-inventory" }
-azalea-nbt = { path = "../azalea-nbt", version = "0.8.0" }
+simdnbt = { version = "0.2.1" }
azalea-registry = { path = "../azalea-registry", version = "0.8.0" }
bevy_ecs = "0.12.0"
derive_more = { version = "0.99.17", features = ["deref", "deref_mut"] }
diff --git a/azalea-world/src/chunk_storage.rs b/azalea-world/src/chunk_storage.rs
index 7301fdd1..ac81fd09 100755
--- a/azalea-world/src/chunk_storage.rs
+++ b/azalea-world/src/chunk_storage.rs
@@ -5,9 +5,9 @@ use crate::palette::PalettedContainerKind;
use azalea_block::BlockState;
use azalea_buf::{BufReadError, McBufReadable, McBufWritable};
use azalea_core::position::{BlockPos, ChunkBlockPos, ChunkPos, ChunkSectionBlockPos};
-use azalea_nbt::NbtCompound;
use nohash_hasher::IntMap;
use parking_lot::RwLock;
+use simdnbt::owned::NbtCompound;
use std::collections::hash_map::Entry;
use std::str::FromStr;
use std::{
@@ -323,11 +323,11 @@ impl Chunk {
let mut heightmaps = HashMap::new();
for (name, heightmap) in heightmaps_nbt.iter() {
- let Ok(kind) = HeightmapKind::from_str(name) else {
+ let Ok(kind) = HeightmapKind::from_str(&name.to_str()) else {
warn!("Unknown heightmap kind: {name}");
continue;
};
- let Some(data) = heightmap.as_long_array() else {
+ let Some(data) = heightmap.long_array() else {
warn!("Heightmap {name} is not a long array");
continue;
};
diff --git a/codegen/lib/code/entity.py b/codegen/lib/code/entity.py
index 7be6b01d..8fa11430 100644
--- a/codegen/lib/code/entity.py
+++ b/codegen/lib/code/entity.py
@@ -400,7 +400,7 @@ impl From<EntityDataValue> for UpdateMetadataError {
if default is None:
# some types don't have Default implemented
if type_name == 'CompoundTag':
- default = 'azalea_nbt::Nbt::Compound(Default::default())'
+ default = 'simdnbt::owned::NbtCompound::default()'
elif type_name == 'CatVariant':
default = 'azalea_registry::CatVariant::Tabby'
elif type_name == 'PaintingVariant':
@@ -434,7 +434,7 @@ impl From<EntityDataValue> for UpdateMetadataError {
elif type_name == 'OptionalFormattedText':
default = f'Some({default})' if default != 'Empty' else 'None'
elif type_name == 'CompoundTag':
- default = f'azalea_nbt::Nbt::Compound({default})' if default != 'Empty' else 'azalea_nbt::Nbt::Compound(Default::default())'
+ default = f'simdnbt::owned::NbtCompound({default})' if default != 'Empty' else 'simdnbt::owned::NbtCompound::default()'
elif type_name == 'Quaternion':
default = f'Quaternion {{ x: {float(default["x"])}, y: {float(default["y"])}, z: {float(default["z"])}, w: {float(default["w"])} }}'
elif type_name == 'Vector3':
diff --git a/codegen/lib/code/utils.py b/codegen/lib/code/utils.py
index 0050ce7b..cb835ecb 100755
--- a/codegen/lib/code/utils.py
+++ b/codegen/lib/code/utils.py
@@ -56,7 +56,7 @@ def burger_type_to_rust_type(burger_type, field_name: Optional[str] = None, inst
field_type_rs = 'BlockPos'
uses.add('azalea_core::position::BlockPos')
elif burger_type == 'nbtcompound':
- field_type_rs = 'azalea_nbt::Nbt'
+ field_type_rs = 'simdnbt::owned::NbtCompound'
elif burger_type == 'itemstack':
field_type_rs = 'Slot'
uses.add('azalea_core::slot::Slot')