1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 06:16:04 +00:00
This commit is contained in:
mat 2023-09-21 11:08:11 -05:00
parent fedf7802ff
commit dd152fd265
40 changed files with 121 additions and 1530 deletions

252
Cargo.lock generated
View file

@ -42,9 +42,9 @@ dependencies = [
[[package]]
name = "aho-corasick"
version = "1.0.5"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783"
checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab"
dependencies = [
"memchr",
]
@ -134,7 +134,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.33",
"syn 2.0.37",
]
[[package]]
@ -151,7 +151,7 @@ checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.33",
"syn 2.0.37",
]
[[package]]
@ -232,7 +232,7 @@ version = "0.8.0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.33",
"syn 2.0.37",
]
[[package]]
@ -252,6 +252,7 @@ dependencies = [
"byteorder",
"log",
"serde_json",
"simdnbt",
"thiserror",
"uuid",
]
@ -262,7 +263,7 @@ version = "0.8.0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.33",
"syn 2.0.37",
]
[[package]]
@ -291,7 +292,6 @@ dependencies = [
"azalea-crypto",
"azalea-entity",
"azalea-inventory",
"azalea-nbt",
"azalea-physics",
"azalea-protocol",
"azalea-registry",
@ -311,6 +311,7 @@ dependencies = [
"reqwest",
"serde",
"serde_json",
"simdnbt",
"thiserror",
"tokio",
"uuid",
@ -322,11 +323,11 @@ version = "0.8.0"
dependencies = [
"azalea-buf",
"azalea-inventory",
"azalea-nbt",
"azalea-registry",
"bevy_ecs",
"num-traits",
"serde",
"simdnbt",
"uuid",
]
@ -356,7 +357,6 @@ dependencies = [
"azalea-chat",
"azalea-core",
"azalea-inventory",
"azalea-nbt",
"azalea-registry",
"azalea-world",
"bevy_app",
@ -366,6 +366,7 @@ dependencies = [
"log",
"nohash-hasher",
"parking_lot",
"simdnbt",
"thiserror",
"uuid",
]
@ -376,8 +377,8 @@ version = "0.8.0"
dependencies = [
"azalea-buf",
"azalea-inventory-macros",
"azalea-nbt",
"azalea-registry",
"simdnbt",
]
[[package]]
@ -386,7 +387,7 @@ version = "0.8.0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.33",
"syn 2.0.37",
]
[[package]]
@ -398,24 +399,6 @@ dependencies = [
"serde_json",
]
[[package]]
name = "azalea-nbt"
version = "0.8.0"
dependencies = [
"azalea-buf",
"byteorder",
"compact_str",
"criterion",
"enum-as-inner",
"fastnbt",
"flate2",
"graphite_binary",
"log",
"serde",
"thiserror",
"valence_nbt",
]
[[package]]
name = "azalea-physics"
version = "0.8.0"
@ -451,7 +434,6 @@ dependencies = [
"azalea-crypto",
"azalea-entity",
"azalea-inventory",
"azalea-nbt",
"azalea-protocol-macros",
"azalea-registry",
"azalea-world",
@ -466,6 +448,7 @@ dependencies = [
"once_cell",
"serde",
"serde_json",
"simdnbt",
"thiserror",
"tokio",
"tokio-util",
@ -481,7 +464,7 @@ version = "0.8.0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.33",
"syn 2.0.37",
]
[[package]]
@ -500,7 +483,7 @@ version = "0.8.0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.33",
"syn 2.0.37",
]
[[package]]
@ -512,7 +495,6 @@ dependencies = [
"azalea-client",
"azalea-core",
"azalea-inventory",
"azalea-nbt",
"azalea-registry",
"bevy_ecs",
"derive_more",
@ -521,6 +503,7 @@ dependencies = [
"nohash-hasher",
"once_cell",
"parking_lot",
"simdnbt",
"thiserror",
"uuid",
]
@ -576,7 +559,7 @@ checksum = "c5cc78985f4d0ad1fd7b8ead06dcfaa192685775a7b1be158191c788c7d52298"
dependencies = [
"bevy_macro_utils",
"quote",
"syn 2.0.33",
"syn 2.0.37",
]
[[package]]
@ -609,7 +592,7 @@ dependencies = [
"bevy_macro_utils",
"proc-macro2",
"quote",
"syn 2.0.33",
"syn 2.0.37",
]
[[package]]
@ -636,7 +619,7 @@ checksum = "d1cd460205fe05634d58b32d9bb752b1b4eaf32b2d29cbd4161ba35eb44a2f8c"
dependencies = [
"quote",
"rustc-hash",
"syn 2.0.33",
"syn 2.0.37",
"toml_edit",
]
@ -687,7 +670,7 @@ dependencies = [
"bit-set",
"proc-macro2",
"quote",
"syn 2.0.33",
"syn 2.0.37",
"uuid",
]
@ -744,7 +727,7 @@ checksum = "0d104f29e231123c703e8b394e2341d2425c33c5a2e9ab8cc8d0a554bdb62a41"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.33",
"syn 2.0.37",
]
[[package]]
@ -785,9 +768,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.13.0"
version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
[[package]]
name = "bytemuck"
@ -813,15 +796,6 @@ version = "0.3.0"
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"
@ -831,12 +805,6 @@ dependencies = [
"libc",
]
[[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"
@ -854,9 +822,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.30"
version = "0.4.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "defd4e7873dbddba6c7c91e199c7fcb946abc4a6a4ac3195400bcfb01b5de877"
checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
dependencies = [
"num-traits",
"serde",
@ -901,18 +869,18 @@ dependencies = [
[[package]]
name = "clap"
version = "4.4.3"
version = "4.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84ed82781cea27b43c9b106a979fe450a13a31aab0500595fb3fc06616de08e6"
checksum = "b1d7b8d5ec32af0fadc644bf1fd509a688c2103b185644bb1e29d164e0703136"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.4.2"
version = "4.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08"
checksum = "5179bb514e4d7c2051749d8fcefa2ed6d06a9f4e6d69faf3805f5d80b8cf8d56"
dependencies = [
"anstyle",
"clap_lex",
@ -924,20 +892,6 @@ version = "0.5.1"
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.2.0"
@ -1147,7 +1101,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.33",
"syn 2.0.37",
]
[[package]]
@ -1205,18 +1159,6 @@ version = "2.5.3"
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"
@ -1328,7 +1270,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.33",
"syn 2.0.37",
]
[[package]]
@ -1400,31 +1342,6 @@ dependencies = [
"serde",
]
[[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"
@ -1475,9 +1392,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hermit-abi"
version = "0.3.2"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
[[package]]
name = "http"
@ -2088,9 +2005,9 @@ dependencies = [
[[package]]
name = "rayon"
version = "1.7.0"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
dependencies = [
"either",
"rayon-core",
@ -2098,14 +2015,12 @@ dependencies = [
[[package]]
name = "rayon-core"
version = "1.11.0"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"num_cpus",
]
[[package]]
@ -2209,6 +2124,21 @@ dependencies = [
"winreg",
]
[[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"
@ -2281,9 +2211,9 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.38.13"
version = "0.38.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662"
checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f"
dependencies = [
"bitflags 2.4.0",
"errno",
@ -2323,12 +2253,6 @@ dependencies = [
"untrusted",
]
[[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"
@ -2375,15 +2299,6 @@ dependencies = [
"serde_derive",
]
[[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.188"
@ -2392,7 +2307,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.33",
"syn 2.0.37",
]
[[package]]
@ -2468,6 +2383,17 @@ dependencies = [
"rand_core",
]
[[package]]
name = "simdnbt"
version = "0.1.2"
source = "git+https://github.com/mat-1/simdnbt#837b5990e7cd24fe990d434361075ec0d6f26045"
dependencies = [
"byteorder",
"flate2",
"residua-mutf8",
"thiserror",
]
[[package]]
name = "simple_asn1"
version = "0.5.4"
@ -2491,9 +2417,9 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.11.0"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
dependencies = [
"serde",
]
@ -2543,12 +2469,6 @@ dependencies = [
"der",
]
[[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"
@ -2568,9 +2488,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.33"
version = "2.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9caece70c63bfba29ec2fed841a09851b14a235c60010fa4de58089b6c025668"
checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8"
dependencies = [
"proc-macro2",
"quote",
@ -2579,9 +2499,9 @@ dependencies = [
[[package]]
name = "termcolor"
version = "1.2.0"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64"
dependencies = [
"winapi-util",
]
@ -2603,7 +2523,7 @@ checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.33",
"syn 2.0.37",
]
[[package]]
@ -2679,7 +2599,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.33",
"syn 2.0.37",
]
[[package]]
@ -2694,9 +2614,9 @@ dependencies = [
[[package]]
name = "tokio-util"
version = "0.7.8"
version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d"
checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d"
dependencies = [
"bytes",
"futures-core",
@ -2749,7 +2669,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.33",
"syn 2.0.37",
]
[[package]]
@ -2854,9 +2774,9 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
[[package]]
name = "typenum"
version = "1.16.0"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicode-bidi"
@ -2906,12 +2826,6 @@ dependencies = [
"serde",
]
[[package]]
name = "valence_nbt"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a438b23122288a8db833fb960b1858aba873bef2c14687a172b39464c7b8b2a1"
[[package]]
name = "valuable"
version = "0.1.0"
@ -2976,7 +2890,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.33",
"syn 2.0.37",
"wasm-bindgen-shared",
]
@ -3010,7 +2924,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.33",
"syn 2.0.37",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -3055,9 +2969,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
dependencies = [
"winapi",
]

View file

@ -6,7 +6,6 @@ members = [
"azalea-chat",
"azalea-core",
"azalea-auth",
"azalea-nbt",
"azalea-brigadier",
"azalea-crypto",
"azalea-world",

View file

@ -9,7 +9,7 @@ A collection of Rust crates for making Minecraft bots, clients, and tools.
</p>
<!-- The line below is automatically read and updated by the migrate script, so don't change it manually. -->
*Currently supported Minecraft version: `1.20.2-rc2`.*
*Currently supported Minecraft version: `1.20.2`.*
## ⚠️ Azalea is still very unfinished, though most crates are in a somewhat useable state

View file

@ -11,8 +11,8 @@ version = "0.8.0"
[dependencies]
azalea-buf = { path = "../azalea-buf", version = "0.8.0" }
azalea-crypto = { path = "../azalea-crypto", version = "0.8.0" }
base64 = "0.21.3"
chrono = { version = "0.4.30", default-features = false, features = ["serde"] }
base64 = "0.21.4"
chrono = { version = "0.4.31", default-features = false, features = ["serde"] }
log = "0.4.20"
num-bigint = "0.4.4"
once_cell = "1.18.0"
@ -22,7 +22,7 @@ reqwest = { version = "0.11.20", default-features = false, features = [
] }
rsa = "0.9.2"
serde = { version = "1.0.188", features = ["derive"] }
serde_json = "1.0.105"
serde_json = "1.0.107"
thiserror = "1.0.48"
tokio = { version = "1.32.0", features = ["fs"] }
uuid = { version = "1.4.1", features = ["serde"] }

View file

@ -12,6 +12,6 @@ proc-macro = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
proc-macro2 = "1.0.66"
proc-macro2 = "1.0.67"
quote = "1.0.33"
syn = "2.0.31"
syn = "2.0.37"

View file

@ -15,6 +15,8 @@ log = "0.4.20"
serde_json = { version = "^1.0", optional = true }
thiserror = "1.0.48"
uuid = "^1.4.1"
simdnbt = { git = "https://github.com/mat-1/simdnbt" }
[features]
serde_json = ["dep:serde_json"]

View file

@ -11,6 +11,6 @@ proc-macro = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
proc-macro2 = "^1.0.66"
proc-macro2 = "^1.0.67"
quote = "^1.0.33"
syn = { version = "^2.0.31", features = ["extra-traits"] }
syn = { version = "^2.0.37", features = ["extra-traits"] }

View file

@ -1,6 +1,7 @@
use super::{UnsizedByteArray, MAX_STRING_LENGTH};
use byteorder::{ReadBytesExt, BE};
use log::warn;
use simdnbt::owned::Nbt;
use std::{
backtrace::Backtrace,
collections::HashMap,
@ -341,3 +342,9 @@ impl<T: McBufReadable, const N: usize> McBufReadable for [T; N] {
})
}
}
impl McBufReadable for Nbt {
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
Ok(Nbt::new(buf)?)
}
}

View file

@ -19,4 +19,4 @@ azalea-language = { path = "../azalea-language", version = "0.8.0" }
log = "0.4.20"
once_cell = "1.18.0"
serde = { version = "^1.0", features = ["derive"] }
serde_json = "^1.0.105"
serde_json = "^1.0.107"

View file

@ -14,7 +14,7 @@ anyhow = "1.0.75"
async-trait = "0.1.73"
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 = { git = "https://github.com/mat-1/simdnbt" }
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" }
@ -40,8 +40,8 @@ thiserror = "^1.0.48"
tokio = { version = "^1.32.0", features = ["sync"] }
uuid = "^1.4.1"
azalea-entity = { version = "0.8.0", path = "../azalea-entity" }
serde_json = "1.0.104"
serde = "1.0.183"
serde_json = "1.0.107"
serde = "1.0.188"
[features]
default = ["log"]

View file

@ -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 = { git = "https://github.com/mat-1/simdnbt" }
azalea-registry = { path = "../azalea-registry", version = "0.8.0" }
bevy_ecs = { version = "0.11.2", default-features = false, optional = true }
num-traits = "0.2.16"

View file

@ -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 = { git = "https://github.com/mat-1/simdnbt" }
azalea-registry = { version = "0.8.0", path = "../azalea-registry" }
azalea-world = { version = "0.8.0", path = "../azalea-world" }
bevy_app = "0.11.2"

View file

@ -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 = { git = "https://github.com/mat-1/simdnbt" }
azalea-registry = { version = "0.8.0", path = "../azalea-registry" }

View file

@ -12,6 +12,6 @@ proc-macro = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
proc-macro2 = "1.0.66"
proc-macro2 = "1.0.67"
quote = "1.0.33"
syn = "2.0.31"
syn = "2.0.37"

View file

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

View file

@ -11,5 +11,5 @@ version = "0.8.0"
[dependencies]
once_cell = "1.18.0"
serde = "^1.0"
serde_json = "^1.0.105"
serde_json = "^1.0.107"
# tokio = {version = "^1.21.2", features = ["fs"]}

View file

@ -1,45 +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/mat-1/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.4.3"
compact_str = { version = "0.7.1", features = ["serde"] }
enum-as-inner = "0.6.0"
flate2 = "^1.0.27"
log = "0.4.20"
serde = { version = "^1.0", features = ["derive"], optional = true }
thiserror = "1.0.48"
[dev-dependencies]
criterion = { version = "^0.5.1", features = ["html_reports"] }
graphite_binary = "0.1.0"
valence_nbt = "0.7.0"
fastnbt = "2.4.4"
[features]
default = []
serde = ["dep:serde"]
[profile.release]
lto = true
debug = true
[profile.bench]
lto = true
debug = true
[[bench]]
harness = false
name = "nbt"
[[bench]]
harness = false
name = "compare"

View file

@ -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'`.

View file

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

View file

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

View file

@ -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 log::warn;
use std::io::{BufRead, Cursor, Read};
#[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())
}
}

View file

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

View file

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

View file

@ -1,47 +0,0 @@
#![doc = include_str!("../README.md")]
#![feature(min_specialization)]
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()),
)])),
)]))
);
}
}

View file

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

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

View file

@ -9,7 +9,7 @@ version = "0.8.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
async-compression = { version = "^0.4.2", features = [
async-compression = { version = "^0.4.3", features = [
"tokio",
"zlib",
], optional = true }
@ -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 = { git = "https://github.com/mat-1/simdnbt" }
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" }
@ -42,10 +40,10 @@ futures-lite = "1.13.0"
futures-util = "0.3.28"
log = "0.4.20"
serde = { version = "^1.0", features = ["serde_derive"] }
serde_json = "^1.0.105"
serde_json = "^1.0.107"
thiserror = "1.0.48"
tokio = { version = "^1.32.0", features = ["io-util", "net", "macros"] }
tokio-util = { version = "0.7.8", features = ["codec"] }
tokio-util = { version = "0.7.9", features = ["codec"] }
trust-dns-resolver = { version = "^0.23.0", default-features = false, features = [
"tokio-runtime",
] }

View file

@ -11,6 +11,6 @@ proc-macro = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
proc-macro2 = "^1.0.66"
proc-macro2 = "^1.0.67"
quote = "^1.0.33"
syn = "^2.0.31"
syn = "^2.0.37"

View file

@ -12,7 +12,7 @@ use std::io::{Cursor, Write};
// TODO: rename the packet files to just like clientbound_add_entity instead of
// clientbound_add_entity_packet
pub const PROTOCOL_VERSION: u32 = 1073741977;
pub const PROTOCOL_VERSION: u32 = 764;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ConnectionProtocol {

View file

@ -12,9 +12,9 @@ proc-macro = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
proc-macro2 = "1.0.66"
proc-macro2 = "1.0.67"
quote = "1.0.33"
syn = "2.0.31"
syn = "2.0.37"
[features]
serde = []

View file

@ -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 = { git = "https://github.com/mat-1/simdnbt" }
azalea-registry = { path = "../azalea-registry", version = "0.8.0" }
bevy_ecs = "0.11.2"
derive_more = { version = "0.99.17", features = ["deref", "deref_mut"] }