1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 14:26:04 +00:00
* start updating to 22w42a

* work a bit more on 22w42a

* player chat packet

* serverbound hello packet

* Update mod.rs

* add more stuff to clientbound player chat packet

* ClientboundPlayerInfoUpdatePacket

* features enabled and container closed

* serverbound chat packets

* make it compile

* 22w43a

* ServerboundChatSessionUpdatePacket

* profile_public_key isn't Option anymore

* Update bitset.rs

* joining a server works

* fix entitydatavalue

* backtraces + fix clientbound chat message

* fix some warnings and add more ecomments

* 22w44a

* generate en_us.json

* add updating guide to codegen/readme

* fix some markdown

* update list of generated things

* metadata stuff

* Replace PJS generator mod with PixLyzer (#38)

* pixlizer extractor

* start working on shape extraction

* fix generating language

* fix pixlyzer shape generation

* use empty_shape

* generate blocks and shapes

* update pixlyzer dir

* Revert "update pixlyzer dir"

This reverts commit ee9a0e7a49.

* fix

* fix

* Revert "fix"

This reverts commit ad12ddcb00.

* fix

* detect pixlyzer fail

* fix pixlyzer

* 22w45a

* gen entities

* add async-trait dep

* update codegen/readme.md

* explain when rust_log should be used

* remove some unused code

* start fixing pixlyzer issues

* fix a thing in codegen

* almost fixed

* more progress towards 1.19.3

* 1.19.3-pre2

* fixes

* revert some hardcoded property names

* Delete clientbound_player_info_packet.rs

* handle 1.19.3 player info packets

* handle playerinforemove

* start updating to 1.19.3-rc1

* optional registries work

* fix some issues with 1.19.3

chat doesn't work yet

* aaaaaaaaaaaaaaaaa

* oh

* ignore unused shapes

* uncomment generate_blocks

* fix migrate

* 1.19.3-rc2

* fix clippy warnings

* 1.19.3-rc3

* split the azalea-buf macro into separate modules

* improve Recipe in protocol

* 1.19.3
This commit is contained in:
mat 2022-12-07 21:09:58 -06:00 committed by GitHub
parent 9f5e5c092b
commit 7d901e39bc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
73 changed files with 22289 additions and 15350 deletions

112
Cargo.lock generated
View file

@ -43,9 +43,9 @@ dependencies = [
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "0.7.19" version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@ -82,9 +82,9 @@ dependencies = [
[[package]] [[package]]
name = "async-trait" name = "async-trait"
version = "0.1.58" version = "0.1.59"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -182,6 +182,7 @@ version = "0.4.0"
dependencies = [ dependencies = [
"azalea-buf-macros", "azalea-buf-macros",
"byteorder", "byteorder",
"log",
"serde_json", "serde_json",
"thiserror", "thiserror",
"tokio", "tokio",
@ -203,6 +204,7 @@ version = "0.4.0"
dependencies = [ dependencies = [
"azalea-buf", "azalea-buf",
"azalea-language", "azalea-language",
"log",
"once_cell", "once_cell",
"serde", "serde",
"serde_json", "serde_json",
@ -380,7 +382,7 @@ dependencies = [
"cc", "cc",
"cfg-if", "cfg-if",
"libc", "libc",
"miniz_oxide", "miniz_oxide 0.5.4",
"object", "object",
"rustc-demangle", "rustc-demangle",
] ]
@ -446,9 +448,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.2.1" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
[[package]] [[package]]
name = "cast" name = "cast"
@ -458,9 +460,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.76" version = "1.0.77"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f" checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
[[package]] [[package]]
name = "cfb8" name = "cfb8"
@ -601,9 +603,9 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-epoch" name = "crossbeam-epoch"
version = "0.9.11" version = "0.9.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f916dfc5d356b0ed9dae65f1db9fc9770aa2851d2662b988ccf4fe3516e86348" checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"cfg-if", "cfg-if",
@ -614,9 +616,9 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.8.12" version = "0.8.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac" checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
] ]
@ -661,9 +663,9 @@ checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57"
[[package]] [[package]]
name = "digest" name = "digest"
version = "0.10.5" version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c" checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
dependencies = [ dependencies = [
"block-buffer", "block-buffer",
"crypto-common", "crypto-common",
@ -726,12 +728,12 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
[[package]] [[package]]
name = "flate2" name = "flate2"
version = "1.0.24" version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"miniz_oxide", "miniz_oxide 0.6.2",
] ]
[[package]] [[package]]
@ -1026,9 +1028,9 @@ dependencies = [
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.9.1" version = "1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"hashbrown", "hashbrown",
@ -1096,9 +1098,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.137" version = "0.2.138"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
[[package]] [[package]]
name = "linked-hash-map" name = "linked-hash-map"
@ -1148,9 +1150,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]] [[package]]
name = "memoffset" name = "memoffset"
version = "0.6.5" version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
dependencies = [ dependencies = [
"autocfg", "autocfg",
] ]
@ -1170,6 +1172,15 @@ dependencies = [
"adler", "adler",
] ]
[[package]]
name = "miniz_oxide"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
dependencies = [
"adler",
]
[[package]] [[package]]
name = "mio" name = "mio"
version = "0.8.5" version = "0.8.5"
@ -1326,9 +1337,9 @@ checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]] [[package]]
name = "openssl" name = "openssl"
version = "0.10.42" version = "0.10.43"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12fc0523e3bd51a692c8850d075d74dc062ccf251c0110668cbd921917118a13" checksum = "020433887e44c27ff16365eaa2d380547a94544ad509aff6eb5b6e3e0b27b376"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cfg-if", "cfg-if",
@ -1358,9 +1369,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]] [[package]]
name = "openssl-sys" name = "openssl-sys"
version = "0.9.77" version = "0.9.78"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b03b84c3b2d099b81f0953422b4d4ad58761589d0229b5506356afca05a3670a" checksum = "07d5c8cb6e57b3a3612064d7b18b117912b4ce70955c2504d4b741c9e244b132"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"cc", "cc",
@ -1381,9 +1392,9 @@ dependencies = [
[[package]] [[package]]
name = "parking_lot_core" name = "parking_lot_core"
version = "0.9.4" version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"cfg-if", "cfg-if",
@ -1523,11 +1534,10 @@ dependencies = [
[[package]] [[package]]
name = "rayon" name = "rayon"
version = "1.5.3" version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" checksum = "1e060280438193c554f654141c9ea9417886713b7acd75974c85b18a69a88e0b"
dependencies = [ dependencies = [
"autocfg",
"crossbeam-deque", "crossbeam-deque",
"either", "either",
"rayon-core", "rayon-core",
@ -1535,9 +1545,9 @@ dependencies = [
[[package]] [[package]]
name = "rayon-core" name = "rayon-core"
version = "1.9.3" version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3"
dependencies = [ dependencies = [
"crossbeam-channel", "crossbeam-channel",
"crossbeam-deque", "crossbeam-deque",
@ -1588,9 +1598,9 @@ dependencies = [
[[package]] [[package]]
name = "reqwest" name = "reqwest"
version = "0.11.12" version = "0.11.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "431949c384f4e2ae07605ccaa56d1d9d2ecdb5cadd4f9577ccfab29f2e5149fc" checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c"
dependencies = [ dependencies = [
"base64", "base64",
"bytes", "bytes",
@ -1696,9 +1706,9 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.148" version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc" checksum = "256b9932320c590e707b94576e3cc1f7c9024d0ee6612dfbcf1cb106cbe8e055"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
@ -1715,9 +1725,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.148" version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c" checksum = "b4eae9b04cbffdfd550eb462ed33bc6a1b68c935127d008b27444d08380f94e4"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1726,9 +1736,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.87" version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db"
dependencies = [ dependencies = [
"itoa 1.0.4", "itoa 1.0.4",
"ryu", "ryu",
@ -1749,9 +1759,9 @@ dependencies = [
[[package]] [[package]]
name = "sha-1" name = "sha-1"
version = "0.10.0" version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"cpufeatures", "cpufeatures",
@ -1905,9 +1915,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.21.2" version = "1.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"bytes", "bytes",
@ -1925,9 +1935,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio-macros" name = "tokio-macros"
version = "1.8.0" version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2053,9 +2063,9 @@ checksum = "4fc45e9608894c9fefd9792d880560280086d73a4d8c8cb7436f27ca98550fb5"
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.15.0" version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]] [[package]]
name = "unicode-bidi" name = "unicode-bidi"

View file

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

View file

@ -2,7 +2,7 @@ use azalea_buf::McBuf;
use std::collections::HashMap; use std::collections::HashMap;
use uuid::Uuid; use uuid::Uuid;
#[derive(McBuf, Debug, Clone)] #[derive(McBuf, Debug, Clone, Default)]
pub struct GameProfile { pub struct GameProfile {
pub uuid: Uuid, pub uuid: Uuid,
pub name: String, pub name: String,

View file

@ -178,7 +178,7 @@ make_block_states! {
Down, Down,
}, },
"triggered" => bool, "triggered" => bool,
"instrument" => Instrument { "instrument" => Sound {
Harp, Harp,
Basedrum, Basedrum,
Snare, Snare,
@ -195,6 +195,13 @@ make_block_states! {
Bit, Bit,
Banjo, Banjo,
Pling, Pling,
Zombie,
Skeleton,
Creeper,
Dragon,
WitherSkeleton,
Piglin,
CustomHead,
}, },
"note" => NoteBlockNote { "note" => NoteBlockNote {
_0, _0,
@ -254,6 +261,12 @@ make_block_states! {
}, },
"short" => bool, "short" => bool,
"unstable" => bool, "unstable" => bool,
"slot_0_occupied" => bool,
"slot_1_occupied" => bool,
"slot_2_occupied" => bool,
"slot_3_occupied" => bool,
"slot_4_occupied" => bool,
"slot_5_occupied" => bool,
"age" => FireAge { "age" => FireAge {
_0, _0,
_1, _1,
@ -478,6 +491,24 @@ make_block_states! {
_14, _14,
_15, _15,
}, },
"rotation" => BambooSignRotation {
_0,
_1,
_2,
_3,
_4,
_5,
_6,
_7,
_8,
_9,
_10,
_11,
_12,
_13,
_14,
_15,
},
"hinge" => Hinge { "hinge" => Hinge {
Left, Left,
Right, Right,
@ -495,6 +526,187 @@ make_block_states! {
NorthWest, NorthWest,
NorthEast, NorthEast,
}, },
"attached" => bool,
"rotation" => OakHangingSignRotation {
_0,
_1,
_2,
_3,
_4,
_5,
_6,
_7,
_8,
_9,
_10,
_11,
_12,
_13,
_14,
_15,
},
"rotation" => SpruceHangingSignRotation {
_0,
_1,
_2,
_3,
_4,
_5,
_6,
_7,
_8,
_9,
_10,
_11,
_12,
_13,
_14,
_15,
},
"rotation" => BirchHangingSignRotation {
_0,
_1,
_2,
_3,
_4,
_5,
_6,
_7,
_8,
_9,
_10,
_11,
_12,
_13,
_14,
_15,
},
"rotation" => AcaciaHangingSignRotation {
_0,
_1,
_2,
_3,
_4,
_5,
_6,
_7,
_8,
_9,
_10,
_11,
_12,
_13,
_14,
_15,
},
"rotation" => JungleHangingSignRotation {
_0,
_1,
_2,
_3,
_4,
_5,
_6,
_7,
_8,
_9,
_10,
_11,
_12,
_13,
_14,
_15,
},
"rotation" => DarkOakHangingSignRotation {
_0,
_1,
_2,
_3,
_4,
_5,
_6,
_7,
_8,
_9,
_10,
_11,
_12,
_13,
_14,
_15,
},
"rotation" => CrimsonHangingSignRotation {
_0,
_1,
_2,
_3,
_4,
_5,
_6,
_7,
_8,
_9,
_10,
_11,
_12,
_13,
_14,
_15,
},
"rotation" => WarpedHangingSignRotation {
_0,
_1,
_2,
_3,
_4,
_5,
_6,
_7,
_8,
_9,
_10,
_11,
_12,
_13,
_14,
_15,
},
"rotation" => MangroveHangingSignRotation {
_0,
_1,
_2,
_3,
_4,
_5,
_6,
_7,
_8,
_9,
_10,
_11,
_12,
_13,
_14,
_15,
},
"rotation" => BambooHangingSignRotation {
_0,
_1,
_2,
_3,
_4,
_5,
_6,
_7,
_8,
_9,
_10,
_11,
_12,
_13,
_14,
_15,
},
"face" => Face { "face" => Face {
Floor, Floor,
Wall, Wall,
@ -588,7 +800,11 @@ make_block_states! {
_6, _6,
_7, _7,
}, },
"berries" => bool, "down" => bool,
"north" => bool,
"south" => bool,
"up" => bool,
"west" => bool,
"in_wall" => bool, "in_wall" => bool,
"age" => NetherWartAge { "age" => NetherWartAge {
_0, _0,
@ -613,7 +829,6 @@ make_block_states! {
_1, _1,
_2, _2,
}, },
"attached" => bool,
"disarmed" => bool, "disarmed" => bool,
"conditional" => bool, "conditional" => bool,
"east" => EastWall { "east" => EastWall {
@ -764,6 +979,24 @@ make_block_states! {
_14, _14,
_15, _15,
}, },
"rotation" => PiglinHeadRotation {
_0,
_1,
_2,
_3,
_4,
_5,
_6,
_7,
_8,
_9,
_10,
_11,
_12,
_13,
_14,
_15,
},
"power" => LightWeightedPressurePlatePower { "power" => LightWeightedPressurePlatePower {
_0, _0,
_1, _1,
@ -1535,6 +1768,8 @@ make_block_states! {
Active, Active,
Cooldown, Cooldown,
}, },
"south" => bool,
"west" => bool,
"bloom" => bool, "bloom" => bool,
"can_summon" => bool, "can_summon" => bool,
"shrieking" => bool, "shrieking" => bool,
@ -1549,7 +1784,7 @@ make_block_states! {
Up, Up,
Down, Down,
}, },
"age" => _0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24_25 { "age" => CaveVinesAge {
_0, _0,
_1, _1,
_2, _2,
@ -1577,13 +1812,14 @@ make_block_states! {
_24, _24,
_25, _25,
}, },
"berries" => bool,
"tilt" => Tilt { "tilt" => Tilt {
None, None,
Unstable, Unstable,
Partial, Partial,
Full, Full,
}, },
"axis" => XYZ { "axis" => CacheSize {
X, X,
Y, Y,
Z, Z,
@ -1614,6 +1850,8 @@ make_block_states! {
acacia_planks => BlockBehavior::default(), {}, acacia_planks => BlockBehavior::default(), {},
dark_oak_planks => BlockBehavior::default(), {}, dark_oak_planks => BlockBehavior::default(), {},
mangrove_planks => BlockBehavior::default(), {}, mangrove_planks => BlockBehavior::default(), {},
bamboo_planks => BlockBehavior::default(), {},
bamboo_mosaic => BlockBehavior::default(), {},
oak_sapling => BlockBehavior::default(), { oak_sapling => BlockBehavior::default(), {
stage: OakSaplingStage::_0, stage: OakSaplingStage::_0,
}, },
@ -1682,6 +1920,9 @@ make_block_states! {
muddy_mangrove_roots => BlockBehavior::default(), { muddy_mangrove_roots => BlockBehavior::default(), {
axis: Axis::Y, axis: Axis::Y,
}, },
bamboo_block => BlockBehavior::default(), {
axis: Axis::Y,
},
stripped_spruce_log => BlockBehavior::default(), { stripped_spruce_log => BlockBehavior::default(), {
axis: Axis::Y, axis: Axis::Y,
}, },
@ -1703,6 +1944,9 @@ make_block_states! {
stripped_mangrove_log => BlockBehavior::default(), { stripped_mangrove_log => BlockBehavior::default(), {
axis: Axis::Y, axis: Axis::Y,
}, },
stripped_bamboo_block => BlockBehavior::default(), {
axis: Axis::Y,
},
oak_wood => BlockBehavior::default(), { oak_wood => BlockBehavior::default(), {
axis: Axis::Y, axis: Axis::Y,
}, },
@ -1804,7 +2048,7 @@ make_block_states! {
chiseled_sandstone => BlockBehavior::default(), {}, chiseled_sandstone => BlockBehavior::default(), {},
cut_sandstone => BlockBehavior::default(), {}, cut_sandstone => BlockBehavior::default(), {},
note_block => BlockBehavior::default(), { note_block => BlockBehavior::default(), {
instrument: Instrument::Harp, instrument: Sound::Harp,
note: NoteBlockNote::_0, note: NoteBlockNote::_0,
powered: false, powered: false,
}, },
@ -1961,6 +2205,15 @@ make_block_states! {
unstable: false, unstable: false,
}, },
bookshelf => BlockBehavior::default(), {}, bookshelf => BlockBehavior::default(), {},
chiseled_bookshelf => BlockBehavior::default(), {
facing: FacingCardinal::North,
slot_0_occupied: false,
slot_1_occupied: false,
slot_2_occupied: false,
slot_3_occupied: false,
slot_4_occupied: false,
slot_5_occupied: false,
},
mossy_cobblestone => BlockBehavior::default(), {}, mossy_cobblestone => BlockBehavior::default(), {},
obsidian => BlockBehavior::default(), {}, obsidian => BlockBehavior::default(), {},
torch => BlockBehavior::default(), {}, torch => BlockBehavior::default(), {},
@ -2037,6 +2290,10 @@ make_block_states! {
rotation: MangroveSignRotation::_0, rotation: MangroveSignRotation::_0,
waterlogged: false, waterlogged: false,
}, },
bamboo_sign => BlockBehavior::default(), {
rotation: BambooSignRotation::_0,
waterlogged: false,
},
oak_door => BlockBehavior::default(), { oak_door => BlockBehavior::default(), {
facing: FacingCardinal::North, facing: FacingCardinal::North,
half: Half::Lower, half: Half::Lower,
@ -2086,6 +2343,100 @@ make_block_states! {
facing: FacingCardinal::North, facing: FacingCardinal::North,
waterlogged: false, waterlogged: false,
}, },
bamboo_wall_sign => BlockBehavior::default(), {
facing: FacingCardinal::North,
waterlogged: false,
},
oak_hanging_sign => BlockBehavior::default(), {
attached: false,
rotation: OakHangingSignRotation::_0,
waterlogged: false,
},
spruce_hanging_sign => BlockBehavior::default(), {
attached: false,
rotation: SpruceHangingSignRotation::_0,
waterlogged: false,
},
birch_hanging_sign => BlockBehavior::default(), {
attached: false,
rotation: BirchHangingSignRotation::_0,
waterlogged: false,
},
acacia_hanging_sign => BlockBehavior::default(), {
attached: false,
rotation: AcaciaHangingSignRotation::_0,
waterlogged: false,
},
jungle_hanging_sign => BlockBehavior::default(), {
attached: false,
rotation: JungleHangingSignRotation::_0,
waterlogged: false,
},
dark_oak_hanging_sign => BlockBehavior::default(), {
attached: false,
rotation: DarkOakHangingSignRotation::_0,
waterlogged: false,
},
crimson_hanging_sign => BlockBehavior::default(), {
attached: false,
rotation: CrimsonHangingSignRotation::_0,
waterlogged: false,
},
warped_hanging_sign => BlockBehavior::default(), {
attached: false,
rotation: WarpedHangingSignRotation::_0,
waterlogged: false,
},
mangrove_hanging_sign => BlockBehavior::default(), {
attached: false,
rotation: MangroveHangingSignRotation::_0,
waterlogged: false,
},
bamboo_hanging_sign => BlockBehavior::default(), {
attached: false,
rotation: BambooHangingSignRotation::_0,
waterlogged: false,
},
oak_wall_hanging_sign => BlockBehavior::default(), {
facing: FacingCardinal::North,
waterlogged: false,
},
spruce_wall_hanging_sign => BlockBehavior::default(), {
facing: FacingCardinal::North,
waterlogged: false,
},
birch_wall_hanging_sign => BlockBehavior::default(), {
facing: FacingCardinal::North,
waterlogged: false,
},
acacia_wall_hanging_sign => BlockBehavior::default(), {
facing: FacingCardinal::North,
waterlogged: false,
},
jungle_wall_hanging_sign => BlockBehavior::default(), {
facing: FacingCardinal::North,
waterlogged: false,
},
dark_oak_wall_hanging_sign => BlockBehavior::default(), {
facing: FacingCardinal::North,
waterlogged: false,
},
mangrove_wall_hanging_sign => BlockBehavior::default(), {
facing: FacingCardinal::North,
waterlogged: false,
},
crimson_wall_hanging_sign => BlockBehavior::default(), {
facing: FacingCardinal::North,
waterlogged: false,
},
warped_wall_hanging_sign => BlockBehavior::default(), {
facing: FacingCardinal::North,
waterlogged: false,
},
bamboo_wall_hanging_sign => BlockBehavior::default(), {
facing: FacingCardinal::North,
waterlogged: false,
},
lever => BlockBehavior::default(), { lever => BlockBehavior::default(), {
face: Face::Wall, face: Face::Wall,
facing: FacingCardinal::North, facing: FacingCardinal::North,
@ -2122,6 +2473,9 @@ make_block_states! {
mangrove_pressure_plate => BlockBehavior::default(), { mangrove_pressure_plate => BlockBehavior::default(), {
powered: false, powered: false,
}, },
bamboo_pressure_plate => BlockBehavior::default(), {
powered: false,
},
redstone_ore => BlockBehavior::default(), { redstone_ore => BlockBehavior::default(), {
lit: false, lit: false,
}, },
@ -2260,6 +2614,13 @@ make_block_states! {
powered: false, powered: false,
waterlogged: false, waterlogged: false,
}, },
bamboo_trapdoor => BlockBehavior::default(), {
facing: FacingCardinal::North,
half: TopBottom::Bottom,
open: false,
powered: false,
waterlogged: false,
},
stone_bricks => BlockBehavior::default(), {}, stone_bricks => BlockBehavior::default(), {},
mossy_stone_bricks => BlockBehavior::default(), {}, mossy_stone_bricks => BlockBehavior::default(), {},
cracked_stone_bricks => BlockBehavior::default(), {}, cracked_stone_bricks => BlockBehavior::default(), {},
@ -2549,6 +2910,11 @@ make_block_states! {
facing: FacingCardinal::North, facing: FacingCardinal::North,
powered: false, powered: false,
}, },
bamboo_button => BlockBehavior::default(), {
face: Face::Wall,
facing: FacingCardinal::North,
powered: false,
},
skeleton_skull => BlockBehavior::default(), { skeleton_skull => BlockBehavior::default(), {
rotation: SkeletonSkullRotation::_0, rotation: SkeletonSkullRotation::_0,
}, },
@ -2585,6 +2951,12 @@ make_block_states! {
dragon_wall_head => BlockBehavior::default(), { dragon_wall_head => BlockBehavior::default(), {
facing: FacingCardinal::North, facing: FacingCardinal::North,
}, },
piglin_head => BlockBehavior::default(), {
rotation: PiglinHeadRotation::_0,
},
piglin_wall_head => BlockBehavior::default(), {
facing: FacingCardinal::North,
},
anvil => BlockBehavior::default(), { anvil => BlockBehavior::default(), {
facing: FacingCardinal::North, facing: FacingCardinal::North,
}, },
@ -2786,6 +3158,18 @@ make_block_states! {
shape: StairShape::Straight, shape: StairShape::Straight,
waterlogged: false, waterlogged: false,
}, },
bamboo_stairs => BlockBehavior::default(), {
facing: FacingCardinal::North,
half: TopBottom::Bottom,
shape: StairShape::Straight,
waterlogged: false,
},
bamboo_mosaic_stairs => BlockBehavior::default(), {
facing: FacingCardinal::North,
half: TopBottom::Bottom,
shape: StairShape::Straight,
waterlogged: false,
},
slime_block => BlockBehavior::default(), {}, slime_block => BlockBehavior::default(), {},
barrier => BlockBehavior::default(), {}, barrier => BlockBehavior::default(), {},
light => BlockBehavior::default(), { light => BlockBehavior::default(), {
@ -3006,6 +3390,14 @@ make_block_states! {
kind: Type::Bottom, kind: Type::Bottom,
waterlogged: false, waterlogged: false,
}, },
bamboo_slab => BlockBehavior::default(), {
kind: Type::Bottom,
waterlogged: false,
},
bamboo_mosaic_slab => BlockBehavior::default(), {
kind: Type::Bottom,
waterlogged: false,
},
stone_slab => BlockBehavior::default(), { stone_slab => BlockBehavior::default(), {
kind: Type::Bottom, kind: Type::Bottom,
waterlogged: false, waterlogged: false,
@ -3102,6 +3494,12 @@ make_block_states! {
open: false, open: false,
powered: false, powered: false,
}, },
bamboo_fence_gate => BlockBehavior::default(), {
facing: FacingCardinal::North,
in_wall: false,
open: false,
powered: false,
},
spruce_fence => BlockBehavior::default(), { spruce_fence => BlockBehavior::default(), {
east: false, east: false,
north: false, north: false,
@ -3144,6 +3542,13 @@ make_block_states! {
waterlogged: false, waterlogged: false,
west: false, west: false,
}, },
bamboo_fence => BlockBehavior::default(), {
east: false,
north: false,
south: false,
waterlogged: false,
west: false,
},
spruce_door => BlockBehavior::default(), { spruce_door => BlockBehavior::default(), {
facing: FacingCardinal::North, facing: FacingCardinal::North,
half: Half::Lower, half: Half::Lower,
@ -3186,6 +3591,13 @@ make_block_states! {
open: false, open: false,
powered: false, powered: false,
}, },
bamboo_door => BlockBehavior::default(), {
facing: FacingCardinal::North,
half: Half::Lower,
hinge: Hinge::Left,
open: false,
powered: false,
},
end_rod => BlockBehavior::default(), { end_rod => BlockBehavior::default(), {
facing: FacingCubic::Up, facing: FacingCubic::Up,
}, },
@ -4355,7 +4767,7 @@ make_block_states! {
}, },
dripstone_block => BlockBehavior::default(), {}, dripstone_block => BlockBehavior::default(), {},
cave_vines => BlockBehavior::default(), { cave_vines => BlockBehavior::default(), {
age: _0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24_25::_0, age: CaveVinesAge::_0,
berries: false, berries: false,
}, },
cave_vines_plant => BlockBehavior::default(), { cave_vines_plant => BlockBehavior::default(), {
@ -4468,7 +4880,7 @@ make_block_states! {
cracked_deepslate_bricks => BlockBehavior::default(), {}, cracked_deepslate_bricks => BlockBehavior::default(), {},
cracked_deepslate_tiles => BlockBehavior::default(), {}, cracked_deepslate_tiles => BlockBehavior::default(), {},
infested_deepslate => BlockBehavior::default(), { infested_deepslate => BlockBehavior::default(), {
axis: XYZ::Y, axis: CacheSize::Y,
}, },
smooth_basalt => BlockBehavior::default(), {}, smooth_basalt => BlockBehavior::default(), {},
raw_iron_block => BlockBehavior::default(), {}, raw_iron_block => BlockBehavior::default(), {},

3
azalea-buf/Cargo.toml Executable file → Normal file
View file

@ -11,8 +11,9 @@ version = "0.4.0"
[dependencies] [dependencies]
azalea-buf-macros = {path = "./azalea-buf-macros", version = "^0.4.0"} azalea-buf-macros = {path = "./azalea-buf-macros", version = "^0.4.0"}
byteorder = "^1.4.3" byteorder = "^1.4.3"
log = "0.4.17"
serde_json = {version = "^1.0", optional = true} serde_json = {version = "^1.0", optional = true}
thiserror = "^1.0.34" thiserror = "1.0.37"
tokio = {version = "^1.21.2", features = ["io-util", "net", "macros"]} tokio = {version = "^1.21.2", features = ["io-util", "net", "macros"]}
uuid = "^1.1.2" uuid = "^1.1.2"

View file

@ -1,294 +1,30 @@
mod read;
mod write;
use proc_macro::TokenStream; use proc_macro::TokenStream;
use quote::{quote, ToTokens}; use quote::quote;
use syn::{self, parse_macro_input, Data, DeriveInput, FieldsNamed, Ident}; use syn::{self, parse_macro_input, DeriveInput};
fn create_impl_mcbufreadable(ident: &Ident, data: &Data) -> proc_macro2::TokenStream {
match data {
syn::Data::Struct(syn::DataStruct { fields, .. }) => {
let FieldsNamed { named, .. } = match fields {
syn::Fields::Named(f) => f,
_ => panic!("#[derive(McBuf)] can only be used on structs with named fields"),
};
let read_fields = named
.iter()
.map(|f| {
let field_name = &f.ident;
let field_type = &f.ty;
// do a different buf.write_* for each field depending on the type
// if it's a string, use buf.write_string
match field_type {
syn::Type::Path(_) | syn::Type::Array(_) => {
if f.attrs.iter().any(|a| a.path.is_ident("var")) {
quote! {
let #field_name = azalea_buf::McBufVarReadable::var_read_from(buf)?;
}
} else {
quote! {
let #field_name = azalea_buf::McBufReadable::read_from(buf)?;
}
}
}
_ => panic!(
"Error reading field {}: {}",
field_name.clone().unwrap(),
field_type.to_token_stream()
),
}
})
.collect::<Vec<_>>();
let read_field_names = named.iter().map(|f| &f.ident).collect::<Vec<_>>();
quote! {
impl azalea_buf::McBufReadable for #ident {
fn read_from(buf: &mut std::io::Cursor<&[u8]>) -> Result<Self, azalea_buf::BufReadError> {
#(#read_fields)*
Ok(#ident {
#(#read_field_names: #read_field_names),*
})
}
}
}
}
syn::Data::Enum(syn::DataEnum { variants, .. }) => {
let mut match_contents = quote!();
let mut variant_discrim: u32 = 0;
let mut first = true;
let mut first_reader = None;
for variant in variants {
let variant_name = &variant.ident;
match &variant.discriminant.as_ref() {
Some(d) => {
variant_discrim = match &d.1 {
syn::Expr::Lit(e) => match &e.lit {
syn::Lit::Int(i) => i.base10_parse().unwrap(),
_ => panic!("Error parsing enum discriminant as int"),
},
syn::Expr::Unary(_) => {
panic!("Negative enum discriminants are not supported")
}
_ => {
panic!("Error parsing enum discriminant as literal (is {:?})", d.1)
}
}
}
None => {
if !first {
variant_discrim += 1;
}
}
}
let reader = match variant.fields {
syn::Fields::Named(_) => {
panic!("writing named fields in enums is not supported")
}
syn::Fields::Unnamed(_) => quote! {
Ok(Self::#variant_name(azalea_buf::McBufReadable::read_from(buf)?))
},
syn::Fields::Unit => quote! {
Ok(Self::#variant_name)
},
};
if first {
first_reader = Some(reader.clone());
first = false;
};
match_contents.extend(quote! {
#variant_discrim => {
#reader
},
});
}
let first_reader = first_reader.expect("There should be at least one variant");
quote! {
impl azalea_buf::McBufReadable for #ident {
fn read_from(buf: &mut std::io::Cursor<&[u8]>) -> Result<Self, azalea_buf::BufReadError> {
let id = azalea_buf::McBufVarReadable::var_read_from(buf)?;
Self::read_from_id(buf, id)
}
}
impl #ident {
pub fn read_from_id(buf: &mut std::io::Cursor<&[u8]>, id: u32) -> Result<Self, azalea_buf::BufReadError> {
match id {
#match_contents
// you'd THINK this throws an error, but mojang decided to make it default for some reason
_ => #first_reader
}
}
}
}
}
_ => panic!("#[derive(McBuf)] can only be used on structs"),
}
}
fn create_impl_mcbufwritable(ident: &Ident, data: &Data) -> proc_macro2::TokenStream {
match data {
syn::Data::Struct(syn::DataStruct { fields, .. }) => {
let FieldsNamed { named, .. } = match fields {
syn::Fields::Named(f) => f,
_ => panic!("#[derive(McBuf)] can only be used on structs with named fields"),
};
let write_fields = named
.iter()
.map(|f| {
let field_name = &f.ident;
let field_type = &f.ty;
// do a different buf.write_* for each field depending on the type
// if it's a string, use buf.write_string
match field_type {
syn::Type::Path(_) | syn::Type::Array(_) => {
if f.attrs.iter().any(|attr| attr.path.is_ident("var")) {
quote! {
azalea_buf::McBufVarWritable::var_write_into(&self.#field_name, buf)?;
}
} else {
quote! {
azalea_buf::McBufWritable::write_into(&self.#field_name, buf)?;
}
}
}
_ => panic!(
"Error writing field {}: {}",
field_name.clone().unwrap(),
field_type.to_token_stream()
),
}
})
.collect::<Vec<_>>();
quote! {
impl azalea_buf::McBufWritable for #ident {
fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
#(#write_fields)*
Ok(())
}
}
}
}
syn::Data::Enum(syn::DataEnum { variants, .. }) => {
// remember whether it's a data variant so we can do an optimization later
let mut is_data_enum = false;
let mut match_arms = quote!();
let mut match_arms_without_id = quote!();
let mut variant_discrim: u32 = 0;
let mut first = true;
for variant in variants {
match &variant.discriminant.as_ref() {
Some(d) => {
variant_discrim = match &d.1 {
syn::Expr::Lit(e) => match &e.lit {
syn::Lit::Int(i) => i.base10_parse().unwrap(),
_ => panic!("Error parsing enum discriminant as int"),
},
syn::Expr::Unary(_) => {
panic!("Negative enum discriminants are not supported")
}
_ => {
panic!("Error parsing enum discriminant as literal (is {:?})", d.1)
}
}
}
None => {
if first {
first = false;
} else {
variant_discrim += 1;
}
}
}
match &variant.fields {
syn::Fields::Named(_) => {
panic!("Enum variants with named fields are not supported yet");
}
syn::Fields::Unit => {
let variant_name = &variant.ident;
match_arms.extend(quote! {
Self::#variant_name => {
azalea_buf::McBufVarWritable::var_write_into(&#variant_discrim, buf)?;
}
});
match_arms_without_id.extend(quote! {
Self::#variant_name => {}
});
}
syn::Fields::Unnamed(_) => {
is_data_enum = true;
let variant_name = &variant.ident;
match_arms.extend(quote! {
Self::#variant_name(data) => {
azalea_buf::McBufVarWritable::var_write_into(&#variant_discrim, buf)?;
azalea_buf::McBufWritable::write_into(data, buf)?;
}
});
match_arms_without_id.extend(quote! {
Self::#variant_name(data) => {
azalea_buf::McBufWritable::write_into(data, buf)?;
}
});
}
}
}
if is_data_enum {
quote! {
impl azalea_buf::McBufWritable for #ident {
fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
match self {
#match_arms
}
Ok(())
}
}
impl #ident {
pub fn write_without_id(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
match self {
#match_arms_without_id
}
Ok(())
}
}
}
} else {
// optimization: if it doesn't have data we can just do `as u32`
quote! {
impl azalea_buf::McBufWritable for #ident {
fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
azalea_buf::McBufVarWritable::var_write_into(&(*self as u32), buf)
}
}
}
}
}
_ => panic!("#[derive(McBuf)] can only be used on structs"),
}
}
#[proc_macro_derive(McBufReadable, attributes(var))] #[proc_macro_derive(McBufReadable, attributes(var))]
pub fn derive_mcbufreadable(input: TokenStream) -> TokenStream { pub fn derive_mcbufreadable(input: TokenStream) -> TokenStream {
let DeriveInput { ident, data, .. } = parse_macro_input!(input); let DeriveInput { ident, data, .. } = parse_macro_input!(input);
create_impl_mcbufreadable(&ident, &data).into() read::create_impl_mcbufreadable(&ident, &data).into()
} }
#[proc_macro_derive(McBufWritable, attributes(var))] #[proc_macro_derive(McBufWritable, attributes(var))]
pub fn derive_mcbufwritable(input: TokenStream) -> TokenStream { pub fn derive_mcbufwritable(input: TokenStream) -> TokenStream {
let DeriveInput { ident, data, .. } = parse_macro_input!(input); let DeriveInput { ident, data, .. } = parse_macro_input!(input);
create_impl_mcbufwritable(&ident, &data).into() write::create_impl_mcbufwritable(&ident, &data).into()
} }
#[proc_macro_derive(McBuf, attributes(var))] #[proc_macro_derive(McBuf, attributes(var))]
pub fn derive_mcbuf(input: TokenStream) -> TokenStream { pub fn derive_mcbuf(input: TokenStream) -> TokenStream {
let DeriveInput { ident, data, .. } = parse_macro_input!(input); let DeriveInput { ident, data, .. } = parse_macro_input!(input);
let writable = create_impl_mcbufwritable(&ident, &data); let writable = write::create_impl_mcbufwritable(&ident, &data);
let readable = create_impl_mcbufreadable(&ident, &data); let readable = read::create_impl_mcbufreadable(&ident, &data);
quote! { quote! {
#writable #writable
#readable #readable

View file

@ -0,0 +1,158 @@
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::{quote, ToTokens};
use syn::{
self, parse_macro_input, punctuated::Punctuated, token::Comma, Data, DeriveInput, Field,
FieldsNamed, Ident,
};
fn read_named_fields(
named: &Punctuated<Field, Comma>,
) -> (Vec<proc_macro2::TokenStream>, Vec<&Option<Ident>>) {
let read_fields = named
.iter()
.map(|f| {
let field_name = &f.ident;
let field_type = &f.ty;
// do a different buf.write_* for each field depending on the type
// if it's a string, use buf.write_string
match field_type {
syn::Type::Path(_) | syn::Type::Array(_) => {
if f.attrs.iter().any(|a| a.path.is_ident("var")) {
quote! {
let #field_name = azalea_buf::McBufVarReadable::var_read_from(buf)?;
}
} else {
quote! {
let #field_name = azalea_buf::McBufReadable::read_from(buf)?;
}
}
}
_ => panic!(
"Error reading field {}: {}",
field_name.clone().unwrap(),
field_type.to_token_stream()
),
}
})
.collect::<Vec<_>>();
let read_field_names = named.iter().map(|f| &f.ident).collect::<Vec<_>>();
(read_fields, read_field_names)
}
pub fn create_impl_mcbufreadable(ident: &Ident, data: &Data) -> proc_macro2::TokenStream {
match data {
syn::Data::Struct(syn::DataStruct { fields, .. }) => {
let FieldsNamed { named, .. } = match fields {
syn::Fields::Named(f) => f,
_ => panic!("#[derive(McBuf)] can only be used on structs with named fields"),
};
let (read_fields, read_field_names) = read_named_fields(named);
quote! {
impl azalea_buf::McBufReadable for #ident {
fn read_from(buf: &mut std::io::Cursor<&[u8]>) -> Result<Self, azalea_buf::BufReadError> {
#(#read_fields)*
Ok(#ident {
#(#read_field_names: #read_field_names),*
})
}
}
}
}
syn::Data::Enum(syn::DataEnum { variants, .. }) => {
let mut match_contents = quote!();
let mut variant_discrim: u32 = 0;
let mut first = true;
let mut first_reader = None;
for variant in variants {
let variant_name = &variant.ident;
match &variant.discriminant.as_ref() {
Some(d) => {
variant_discrim = match &d.1 {
syn::Expr::Lit(e) => match &e.lit {
syn::Lit::Int(i) => i.base10_parse().unwrap(),
_ => panic!("Error parsing enum discriminant as int (is {:?})", e),
},
syn::Expr::Unary(_) => {
panic!("Negative enum discriminants are not supported")
}
_ => {
panic!("Error parsing enum discriminant as literal (is {:?})", d.1)
}
}
}
None => {
if !first {
variant_discrim += 1;
}
}
}
let reader = match &variant.fields {
syn::Fields::Named(f) => {
let (read_fields, read_field_names) = read_named_fields(&f.named);
quote! {
#(#read_fields)*
Ok(#ident::#variant_name {
#(#read_field_names: #read_field_names),*
})
}
}
syn::Fields::Unnamed(fields) => {
let mut reader_code = quote! {};
for f in &fields.unnamed {
if f.attrs.iter().any(|attr| attr.path.is_ident("var")) {
reader_code.extend(quote! {
Self::#variant_name(azalea_buf::McBufVarReadable::var_read_from(buf)?),
})
} else {
reader_code.extend(quote! {
Self::#variant_name(azalea_buf::McBufReadable::read_from(buf)?),
})
}
}
quote! { Ok(#reader_code) }
}
syn::Fields::Unit => quote! {
Ok(Self::#variant_name)
},
};
if first {
first_reader = Some(reader.clone());
first = false;
};
match_contents.extend(quote! {
#variant_discrim => {
#reader
},
});
}
let first_reader = first_reader.expect("There should be at least one variant");
quote! {
impl azalea_buf::McBufReadable for #ident {
fn read_from(buf: &mut std::io::Cursor<&[u8]>) -> Result<Self, azalea_buf::BufReadError> {
let id = azalea_buf::McBufVarReadable::var_read_from(buf)?;
Self::read_from_id(buf, id)
}
}
impl #ident {
pub fn read_from_id(buf: &mut std::io::Cursor<&[u8]>, id: u32) -> Result<Self, azalea_buf::BufReadError> {
match id {
#match_contents
// you'd THINK this throws an error, but mojang decided to make it default for some reason
_ => {#first_reader}
}
}
}
}
}
_ => panic!("#[derive(McBuf)] can only be used on structs"),
}
}

View file

@ -0,0 +1,193 @@
use proc_macro2::Span;
use quote::{quote, ToTokens};
use syn::{self, punctuated::Punctuated, token::Comma, Data, Field, FieldsNamed, Ident};
fn write_named_fields(
named: &Punctuated<Field, Comma>,
ident_name: Option<&Ident>,
) -> proc_macro2::TokenStream {
let write_fields = named.iter().map(|f| {
let field_name = &f.ident;
let field_type = &f.ty;
let ident_dot_field = match ident_name {
Some(ident) => quote! { &#ident.#field_name },
None => quote! { #field_name },
};
// do a different buf.write_* for each field depending on the type
// if it's a string, use buf.write_string
match field_type {
syn::Type::Path(_) | syn::Type::Array(_) => {
if f.attrs.iter().any(|attr| attr.path.is_ident("var")) {
quote! {
azalea_buf::McBufVarWritable::var_write_into(#ident_dot_field, buf)?;
}
} else {
quote! {
azalea_buf::McBufWritable::write_into(#ident_dot_field, buf)?;
}
}
}
_ => panic!(
"Error writing field {}: {}",
field_name.clone().unwrap(),
field_type.to_token_stream()
),
}
});
quote! { #(#write_fields)* }
}
pub fn create_impl_mcbufwritable(ident: &Ident, data: &Data) -> proc_macro2::TokenStream {
match data {
syn::Data::Struct(syn::DataStruct { fields, .. }) => {
let FieldsNamed { named, .. } = match fields {
syn::Fields::Named(f) => f,
_ => panic!("#[derive(McBuf)] can only be used on structs with named fields"),
};
let write_fields =
write_named_fields(named, Some(&Ident::new("self", Span::call_site())));
quote! {
impl azalea_buf::McBufWritable for #ident {
fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
#write_fields
Ok(())
}
}
}
}
syn::Data::Enum(syn::DataEnum { variants, .. }) => {
// remember whether it's a data variant so we can do an optimization later
let mut is_data_enum = false;
let mut match_arms = quote!();
let mut match_arms_without_id = quote!();
let mut variant_discrim: u32 = 0;
let mut first = true;
for variant in variants {
match &variant.discriminant.as_ref() {
Some(d) => {
variant_discrim = match &d.1 {
syn::Expr::Lit(e) => match &e.lit {
syn::Lit::Int(i) => i.base10_parse().unwrap(),
// syn::Lit::Str(s) => s.value(),
_ => panic!("Error parsing enum discriminant as int (is {:?})", e),
},
syn::Expr::Unary(_) => {
panic!("Negative enum discriminants are not supported")
}
_ => {
panic!("Error parsing enum discriminant as literal (is {:?})", d.1)
}
}
}
None => {
if first {
first = false;
} else {
variant_discrim += 1;
}
}
}
let variant_name = &variant.ident;
// the variant number that we're going to write
let write_the_variant = quote! {
azalea_buf::McBufVarWritable::var_write_into(&#variant_discrim, buf)?;
};
match &variant.fields {
syn::Fields::Named(f) => {
is_data_enum = true;
let field_names = f
.named
.iter()
.map(|f| f.ident.clone().unwrap())
.collect::<Vec<_>>();
let write_fields = write_named_fields(&f.named, None);
match_arms.extend(quote! {
Self::#variant_name { #(#field_names),* } => {
#write_the_variant
#write_fields
}
});
match_arms_without_id.extend(quote! {
Self::#variant_name { #(#field_names),* } => {
#write_fields
}
});
}
syn::Fields::Unit => {
match_arms.extend(quote! {
Self::#variant_name => {
#write_the_variant
}
});
match_arms_without_id.extend(quote! {
Self::#variant_name => {}
});
}
syn::Fields::Unnamed(fields) => {
is_data_enum = true;
let mut writers_code = quote! {};
let mut params_code = quote! {};
for (i, f) in fields.unnamed.iter().enumerate() {
let param_ident = Ident::new(&format!("data{i}"), Span::call_site());
params_code.extend(quote! { #param_ident, });
if f.attrs.iter().any(|attr| attr.path.is_ident("var")) {
writers_code.extend(quote! {
azalea_buf::McBufVarWritable::var_write_into(#param_ident, buf)?;
})
} else {
writers_code.extend(quote! {
azalea_buf::McBufWritable::write_into(#param_ident, buf)?;
})
}
}
match_arms.extend(quote! {
Self::#variant_name(#params_code) => {
#write_the_variant
#writers_code
}
});
match_arms_without_id.extend(quote! {
Self::#variant_name(data) => {
azalea_buf::McBufWritable::write_into(data, buf)?;
}
});
}
}
}
if is_data_enum {
quote! {
impl azalea_buf::McBufWritable for #ident {
fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
match self {
#match_arms
}
Ok(())
}
}
impl #ident {
pub fn write_without_id(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
match self {
#match_arms_without_id
}
Ok(())
}
}
}
} else {
// optimization: if it doesn't have data we can just do `as u32`
quote! {
impl azalea_buf::McBufWritable for #ident {
fn write_into(&self, buf: &mut impl std::io::Write) -> Result<(), std::io::Error> {
azalea_buf::McBufVarWritable::var_write_into(&(*self as u32), buf)
}
}
}
}
}
_ => panic!("#[derive(McBuf)] can only be used on structs"),
}
}

View file

@ -1,6 +1,8 @@
use super::{UnsizedByteArray, MAX_STRING_LENGTH}; use super::{UnsizedByteArray, MAX_STRING_LENGTH};
use byteorder::{ReadBytesExt, BE}; use byteorder::{ReadBytesExt, BE};
use log::warn;
use std::{ use std::{
backtrace::Backtrace,
collections::HashMap, collections::HashMap,
hash::Hash, hash::Hash,
io::{Cursor, Read}, io::{Cursor, Read},
@ -17,14 +19,18 @@ pub enum BufReadError {
CouldNotReadBytes, CouldNotReadBytes,
#[error("The received encoded string buffer length is longer than maximum allowed ({length} > {max_length})")] #[error("The received encoded string buffer length is longer than maximum allowed ({length} > {max_length})")]
StringLengthTooLong { length: u32, max_length: u32 }, StringLengthTooLong { length: u32, max_length: u32 },
#[error("{0}")] #[error("{source}")]
Io( Io {
#[from] #[from]
#[backtrace] #[backtrace]
std::io::Error, source: std::io::Error,
), },
#[error("Invalid UTF-8")] #[error("Invalid UTF-8: {bytes:?} (lossy: {lossy:?})")]
InvalidUtf8, InvalidUtf8 {
bytes: Vec<u8>,
lossy: String,
// backtrace: Backtrace,
},
#[error("Unexpected enum variant {id}")] #[error("Unexpected enum variant {id}")]
UnexpectedEnumVariant { id: i32 }, UnexpectedEnumVariant { id: i32 },
#[error("Unexpected enum variant {id}")] #[error("Unexpected enum variant {id}")]
@ -33,12 +39,17 @@ pub enum BufReadError {
UnexpectedEof { UnexpectedEof {
attempted_read: usize, attempted_read: usize,
actual_read: usize, actual_read: usize,
backtrace: Backtrace,
}, },
#[error("{0}")] #[error("{0}")]
Custom(String), Custom(String),
#[cfg(feature = "serde_json")] #[cfg(feature = "serde_json")]
#[error("{0}")] #[error("{source}")]
Deserialization(#[from] serde_json::Error), Deserialization {
#[from]
#[backtrace]
source: serde_json::Error,
},
} }
fn read_bytes<'a>(buf: &'a mut Cursor<&[u8]>, length: usize) -> Result<&'a [u8], BufReadError> { fn read_bytes<'a>(buf: &'a mut Cursor<&[u8]>, length: usize) -> Result<&'a [u8], BufReadError> {
@ -46,6 +57,7 @@ fn read_bytes<'a>(buf: &'a mut Cursor<&[u8]>, length: usize) -> Result<&'a [u8],
return Err(BufReadError::UnexpectedEof { return Err(BufReadError::UnexpectedEof {
attempted_read: length, attempted_read: length,
actual_read: buf.get_ref().len() - buf.position() as usize, actual_read: buf.get_ref().len() - buf.position() as usize,
backtrace: Backtrace::capture(),
}); });
} }
let initial_position = buf.position() as usize; let initial_position = buf.position() as usize;
@ -66,7 +78,11 @@ fn read_utf_with_len(buf: &mut Cursor<&[u8]>, max_length: u32) -> Result<String,
let buffer = read_bytes(buf, length as usize)?; let buffer = read_bytes(buf, length as usize)?;
let string = std::str::from_utf8(buffer) let string = std::str::from_utf8(buffer)
.map_err(|_| BufReadError::InvalidUtf8)? .map_err(|_| BufReadError::InvalidUtf8 {
bytes: buffer.to_vec(),
lossy: String::from_utf8_lossy(buffer).to_string(),
// backtrace: Backtrace::capture(),
})?
.to_string(); .to_string();
if string.len() > length as usize { if string.len() > length as usize {
return Err(BufReadError::StringLengthTooLong { length, max_length }); return Err(BufReadError::StringLengthTooLong { length, max_length });
@ -265,7 +281,11 @@ impl McBufReadable for u64 {
impl McBufReadable for bool { impl McBufReadable for bool {
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> { fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
Ok(u8::read_from(buf)? != 0) let byte = u8::read_from(buf)?;
if byte > 1 {
warn!("Boolean value was not 0 or 1, but {}", byte);
}
Ok(byte != 0)
} }
} }

View file

@ -9,8 +9,11 @@ version = "0.4.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
azalea-buf = {path = "../azalea-buf", features = ["serde_json"], version = "^0.4.0"} azalea-buf = { path = "../azalea-buf", features = [
"serde_json",
], version = "^0.4.0" }
azalea-language = { path = "../azalea-language", version = "^0.4.0" } azalea-language = { path = "../azalea-language", version = "^0.4.0" }
log = "0.4.17"
once_cell = "1.16.0" once_cell = "1.16.0"
serde = { version = "^1.0.148", features = ["derive"] } serde = { version = "^1.0.148", features = ["derive"] }
serde_json = "^1.0.72" serde_json = "^1.0.72"

View file

@ -5,6 +5,7 @@ use crate::{
translatable_component::{StringOrComponent, TranslatableComponent}, translatable_component::{StringOrComponent, TranslatableComponent},
}; };
use azalea_buf::{BufReadError, McBufReadable, McBufWritable}; use azalea_buf::{BufReadError, McBufReadable, McBufWritable};
use log::debug;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use serde::{de, Deserialize, Deserializer, Serialize}; use serde::{de, Deserialize, Deserializer, Serialize};
use std::{ use std::{
@ -266,6 +267,7 @@ impl<'de> Deserialize<'de> for Component {
impl McBufReadable for Component { impl McBufReadable for Component {
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> { fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
let string = String::read_from(buf)?; let string = String::read_from(buf)?;
debug!("Component string: {}", string);
let json: serde_json::Value = serde_json::from_str(string.as_str())?; let json: serde_json::Value = serde_json::from_str(string.as_str())?;
let component = Component::deserialize(json)?; let component = Component::deserialize(json)?;
Ok(component) Ok(component)

View file

@ -2,12 +2,11 @@
use crate::Client; use crate::Client;
use azalea_chat::Component; use azalea_chat::Component;
use azalea_crypto::MessageSignature;
use azalea_protocol::packets::game::{ use azalea_protocol::packets::game::{
clientbound_player_chat_packet::{ClientboundPlayerChatPacket, LastSeenMessagesUpdate}, clientbound_player_chat_packet::ClientboundPlayerChatPacket,
clientbound_system_chat_packet::ClientboundSystemChatPacket, clientbound_system_chat_packet::ClientboundSystemChatPacket,
serverbound_chat_command_packet::ServerboundChatCommandPacket, serverbound_chat_command_packet::ServerboundChatCommandPacket,
serverbound_chat_packet::ServerboundChatPacket, serverbound_chat_packet::{LastSeenMessagesUpdate, ServerboundChatPacket},
}; };
use std::{ use std::{
sync::Arc, sync::Arc,
@ -33,7 +32,7 @@ impl ChatPacket {
pub fn message(&self) -> Component { pub fn message(&self) -> Component {
match self { match self {
ChatPacket::System(p) => p.content.clone(), ChatPacket::System(p) => p.content.clone(),
ChatPacket::Player(p) => p.message(false), ChatPacket::Player(p) => p.message(),
} }
} }
@ -47,7 +46,7 @@ impl ChatPacket {
// If it's a player chat packet, then the sender and content // If it's a player chat packet, then the sender and content
// are already split for us. // are already split for us.
Some(p.chat_type.name.to_string()), Some(p.chat_type.name.to_string()),
p.message.content(false).to_string(), p.body.content.clone(),
), ),
ChatPacket::System(p) => { ChatPacket::System(p) => {
let message = p.content.to_string(); let message = p.content.to_string();
@ -88,7 +87,7 @@ impl Client {
/// so you should use that instead. /// so you should use that instead.
pub async fn send_chat_packet(&self, message: &str) -> Result<(), std::io::Error> { pub async fn send_chat_packet(&self, message: &str) -> Result<(), std::io::Error> {
// TODO: chat signing // TODO: chat signing
let signature = sign_message(); // let signature = sign_message();
let packet = ServerboundChatPacket { let packet = ServerboundChatPacket {
message: message.to_string(), message: message.to_string(),
timestamp: SystemTime::now() timestamp: SystemTime::now()
@ -98,8 +97,7 @@ impl Client {
.try_into() .try_into()
.expect("Instant should fit into a u64"), .expect("Instant should fit into a u64"),
salt: azalea_crypto::make_salt(), salt: azalea_crypto::make_salt(),
signature, signature: None,
signed_preview: false,
last_seen_messages: LastSeenMessagesUpdate::default(), last_seen_messages: LastSeenMessagesUpdate::default(),
} }
.get(); .get();
@ -120,7 +118,6 @@ impl Client {
.expect("Instant should fit into a u64"), .expect("Instant should fit into a u64"),
salt: azalea_crypto::make_salt(), salt: azalea_crypto::make_salt(),
argument_signatures: vec![], argument_signatures: vec![],
signed_preview: false,
last_seen_messages: LastSeenMessagesUpdate::default(), last_seen_messages: LastSeenMessagesUpdate::default(),
} }
.get(); .get();
@ -143,14 +140,10 @@ impl Client {
self.send_chat_packet(message).await self.send_chat_packet(message).await
} }
} }
// will be used for when the server tells the client about a chat preview
// with custom formatting
// pub fn acknowledge_preview(&self, message: &str) {}
} }
// TODO // TODO
// MessageSigner, ChatMessageContent, LastSeenMessages // MessageSigner, ChatMessageContent, LastSeenMessages
fn sign_message() -> MessageSignature { // fn sign_message() -> MessageSignature {
MessageSignature::default() // MessageSignature::default()
} // }

View file

@ -1,8 +1,7 @@
pub use crate::chat::ChatPacket; pub use crate::chat::ChatPacket;
use crate::{movement::WalkDirection, plugins::PluginStates, Account, PlayerInfo}; use crate::{movement::WalkDirection, plugins::PluginStates, Account, PlayerInfo};
use azalea_auth::game_profile::GameProfile; use azalea_auth::game_profile::GameProfile;
use azalea_chat::Component; use azalea_core::{ChunkPos, ResourceLocation, Vec3};
use azalea_core::{ChunkPos, GameType, ResourceLocation, Vec3};
use azalea_protocol::{ use azalea_protocol::{
connect::{Connection, ConnectionError, ReadConnection, WriteConnection}, connect::{Connection, ConnectionError, ReadConnection, WriteConnection},
packets::{ packets::{
@ -22,8 +21,7 @@ use azalea_protocol::{
login::{ login::{
serverbound_custom_query_packet::ServerboundCustomQueryPacket, serverbound_custom_query_packet::ServerboundCustomQueryPacket,
serverbound_hello_packet::ServerboundHelloPacket, serverbound_hello_packet::ServerboundHelloPacket,
serverbound_key_packet::{NonceOrSaltSignature, ServerboundKeyPacket}, serverbound_key_packet::ServerboundKeyPacket, ClientboundLoginPacket,
ClientboundLoginPacket,
}, },
ConnectionProtocol, PROTOCOL_VERSION, ConnectionProtocol, PROTOCOL_VERSION,
}, },
@ -37,6 +35,8 @@ use azalea_world::{
use log::{debug, error, info, trace, warn}; use log::{debug, error, info, trace, warn};
use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard}; use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};
use std::{ use std::{
any,
backtrace::Backtrace,
collections::HashMap, collections::HashMap,
fmt::Debug, fmt::Debug,
io::{self, Cursor}, io::{self, Cursor},
@ -52,8 +52,11 @@ use uuid::Uuid;
pub type ClientInformation = ServerboundClientInformationPacket; pub type ClientInformation = ServerboundClientInformationPacket;
/// Events are sent before they're processed, so for example game ticks happen /// Something that happened in-game, such as a tick passing or chat message
/// at the beginning of a tick before anything has happened. /// being sent.
///
/// Note: Events are sent before they're processed, so for example game ticks
/// happen at the beginning of a tick before anything has happened.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Event { pub enum Event {
/// Happens right after the bot switches into the Game state, but before /// Happens right after the bot switches into the Game state, but before
@ -61,43 +64,26 @@ pub enum Event {
/// information with `Client::set_client_information`, so the packet /// information with `Client::set_client_information`, so the packet
/// doesn't have to be sent twice. /// doesn't have to be sent twice.
Init, Init,
/// The client is now in the world. Fired when we receive a login packet.
Login, Login,
/// A chat message was sent in the game chat.
Chat(ChatPacket), Chat(ChatPacket),
/// Happens 20 times per second, but only when the world is loaded. /// Happens 20 times per second, but only when the world is loaded.
Tick, Tick,
Packet(Arc<ClientboundGamePacket>), Packet(Arc<ClientboundGamePacket>),
/// Happens when a player is added, removed, or updated in the tab list. /// A player joined the game (or more specifically, was added to the tab
UpdatePlayers(UpdatePlayersEvent), /// list).
/// Emits when the player dies. AddPlayer(PlayerInfo),
/// A player left the game (or maybe is still in the game and was just
/// removed from the tab list).
RemovePlayer(PlayerInfo),
/// A player was updated in the tab list (gamemode, display
/// name, or latency changed).
UpdatePlayer(PlayerInfo),
/// The client player died in-game.
Death(Option<Arc<ClientboundPlayerCombatKillPacket>>), Death(Option<Arc<ClientboundPlayerCombatKillPacket>>),
} }
/// Happens when a player is added, removed, or updated in the tab list.
#[derive(Debug, Clone)]
pub enum UpdatePlayersEvent {
/// A player with the given info was added to the tab list (usually means
/// they joined the server).
Add(PlayerInfo),
/// A player with the given UUID was removed from the tab list (usually
/// means they left the server)
Remove { uuid: Uuid },
/// The latency of the player with the given UUID was updated in the tab
/// list. Note that this can be spoofed by the player and may not represent
/// their actual latency.
Latency {
uuid: Uuid,
/// The time it took in milliseconds for this player to reply to the ping packet.
latency: i32,
},
/// The played switched to a different gamemode (i.e. survival, creative, spectator)
GameMode { uuid: Uuid, game_mode: GameType },
/// The name of the player with the given UUID in the tab list was changed or reset.
DisplayName {
uuid: Uuid,
display_name: Option<Component>,
},
}
/// A player that you control that is currently in a Minecraft server. /// A player that you control that is currently in a Minecraft server.
#[derive(Clone)] #[derive(Clone)]
pub struct Client { pub struct Client {
@ -141,6 +127,7 @@ pub struct PhysicsState {
/// Whether we should ignore errors when decoding packets. /// Whether we should ignore errors when decoding packets.
const IGNORE_ERRORS: bool = !cfg!(debug_assertions); const IGNORE_ERRORS: bool = !cfg!(debug_assertions);
/// An error that happened while joining the server.
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum JoinError { pub enum JoinError {
#[error("{0}")] #[error("{0}")]
@ -148,7 +135,7 @@ pub enum JoinError {
#[error("{0}")] #[error("{0}")]
Connection(#[from] ConnectionError), Connection(#[from] ConnectionError),
#[error("{0}")] #[error("{0}")]
ReadPacket(#[from] azalea_protocol::read::ReadPacketError), ReadPacket(#[from] Box<azalea_protocol::read::ReadPacketError>),
#[error("{0}")] #[error("{0}")]
Io(#[from] io::Error), Io(#[from] io::Error),
#[error("{0}")] #[error("{0}")]
@ -280,8 +267,7 @@ impl Client {
// login // login
conn.write( conn.write(
ServerboundHelloPacket { ServerboundHelloPacket {
username: account.username.clone(), name: account.username.clone(),
public_key: None,
profile_id: None, profile_id: None,
} }
.get(), .get(),
@ -309,8 +295,8 @@ impl Client {
conn.write( conn.write(
ServerboundKeyPacket { ServerboundKeyPacket {
nonce_or_salt_signature: NonceOrSaltSignature::Nonce(e.encrypted_nonce),
key_bytes: e.encrypted_public_key, key_bytes: e.encrypted_public_key,
encrypted_challenge: e.encrypted_nonce,
} }
.get(), .get(),
) )
@ -396,6 +382,7 @@ impl Client {
} }
}, },
Err(e) => { Err(e) => {
let e = *e;
if let ReadPacketError::ConnectionClosed = e { if let ReadPacketError::ConnectionClosed = e {
info!("Connection closed"); info!("Connection closed");
if let Err(e) = client.disconnect().await { if let Err(e) = client.disconnect().await {
@ -403,13 +390,19 @@ impl Client {
} }
break; break;
} }
let default_backtrace = Backtrace::capture();
if IGNORE_ERRORS { if IGNORE_ERRORS {
warn!("{}", e); let backtrace =
if let ReadPacketError::FrameSplitter { .. } = e { any::request_ref::<Backtrace>(&e).unwrap_or(&default_backtrace);
panic!("Error: {e:?}"); warn!("{e}\n{backtrace}");
match e {
ReadPacketError::FrameSplitter { .. } => panic!("Error: {e:?}"),
_ => continue,
} }
} else { } else {
panic!("{}", e); let backtrace =
any::request_ref::<Backtrace>(&e).unwrap_or(&default_backtrace);
panic!("{e}\n{backtrace}")
} }
} }
}; };
@ -657,100 +650,56 @@ impl Client {
) )
.await?; .await?;
} }
ClientboundGamePacket::PlayerInfo(p) => { ClientboundGamePacket::PlayerInfoUpdate(p) => {
use azalea_protocol::packets::game::clientbound_player_info_packet::Action;
debug!("Got player info packet {:?}", p); debug!("Got player info packet {:?}", p);
let mut events = Vec::new(); let mut events = Vec::new();
{ {
let mut players_lock = client.players.write(); let mut players_lock = client.players.write();
match &p.action { for updated_info in &p.entries {
Action::AddPlayer(players) => { // add the new player maybe
for player in players { if p.actions.add_player {
let player_info = PlayerInfo { let player_info = PlayerInfo {
profile: GameProfile { profile: updated_info.profile.clone(),
uuid: player.uuid, uuid: updated_info.profile.uuid,
name: player.name.clone(), gamemode: updated_info.game_mode,
properties: player.properties.clone(), latency: updated_info.latency,
}, display_name: updated_info.display_name.clone(),
uuid: player.uuid,
gamemode: player.gamemode,
latency: player.latency,
display_name: player.display_name.clone(),
}; };
players_lock.insert(player.uuid, player_info.clone()); players_lock.insert(updated_info.profile.uuid, player_info.clone());
events.push(Event::UpdatePlayers(UpdatePlayersEvent::Add( events.push(Event::AddPlayer(player_info));
player_info, } else if let Some(info) = players_lock.get_mut(&updated_info.profile.uuid)
))); {
// `else if` because the block for add_player above
// already sets all the fields
if p.actions.update_game_mode {
info.gamemode = updated_info.game_mode;
} }
if p.actions.update_latency {
info.latency = updated_info.latency;
} }
Action::UpdateGameMode(players) => { if p.actions.update_display_name {
for player in players { info.display_name = updated_info.display_name.clone();
if let Some(p) = players_lock.get_mut(&player.uuid) { }
p.gamemode = player.gamemode; events.push(Event::UpdatePlayer(info.clone()));
events.push(Event::UpdatePlayers(
UpdatePlayersEvent::GameMode {
uuid: player.uuid,
game_mode: player.gamemode,
},
));
} else { } else {
warn!( warn!(
"Ignoring PlayerInfo (UpdateGameMode) for unknown player {}", "Ignoring PlayerInfoUpdate for unknown player {}",
player.uuid updated_info.profile.uuid
); );
} }
} }
} }
Action::UpdateLatency(players) => { for event in events {
for player in players { tx.send(event).await?;
if let Some(p) = players_lock.get_mut(&player.uuid) {
p.latency = player.latency;
events.push(Event::UpdatePlayers(
UpdatePlayersEvent::Latency {
uuid: player.uuid,
latency: player.latency,
},
));
} else {
warn!(
"Ignoring PlayerInfo (UpdateLatency) for unknown player {}",
player.uuid
);
}
}
}
Action::UpdateDisplayName(players) => {
for player in players {
if let Some(p) = players_lock.get_mut(&player.uuid) {
p.display_name = player.display_name.clone();
events.push(Event::UpdatePlayers(
UpdatePlayersEvent::DisplayName {
uuid: player.uuid,
display_name: player.display_name.clone(),
},
));
} else {
warn!(
"Ignoring PlayerInfo (UpdateDisplayName) for unknown player {}",
player.uuid
);
}
}
}
Action::RemovePlayer(players) => {
for player in players {
if players_lock.remove(&player.uuid).is_some() {
events.push(Event::UpdatePlayers(UpdatePlayersEvent::Remove {
uuid: player.uuid,
}));
} else {
warn!(
"Ignoring PlayerInfo (RemovePlayer) for unknown player {}",
player.uuid
);
} }
} }
ClientboundGamePacket::PlayerInfoRemove(p) => {
let mut events = Vec::new();
{
let mut players_lock = client.players.write();
for uuid in &p.profile_ids {
if let Some(info) = players_lock.remove(uuid) {
events.push(Event::RemovePlayer(info));
} }
} }
} }
@ -948,13 +897,11 @@ impl Client {
ClientboundGamePacket::BlockEntityData(_) => {} ClientboundGamePacket::BlockEntityData(_) => {}
ClientboundGamePacket::BlockEvent(_) => {} ClientboundGamePacket::BlockEvent(_) => {}
ClientboundGamePacket::BossEvent(_) => {} ClientboundGamePacket::BossEvent(_) => {}
ClientboundGamePacket::ChatPreview(_) => {}
ClientboundGamePacket::CommandSuggestions(_) => {} ClientboundGamePacket::CommandSuggestions(_) => {}
ClientboundGamePacket::ContainerSetData(_) => {} ClientboundGamePacket::ContainerSetData(_) => {}
ClientboundGamePacket::ContainerSetSlot(_) => {} ClientboundGamePacket::ContainerSetSlot(_) => {}
ClientboundGamePacket::Cooldown(_) => {} ClientboundGamePacket::Cooldown(_) => {}
ClientboundGamePacket::CustomChatCompletions(_) => {} ClientboundGamePacket::CustomChatCompletions(_) => {}
ClientboundGamePacket::CustomSound(_) => {}
ClientboundGamePacket::DeleteChat(_) => {} ClientboundGamePacket::DeleteChat(_) => {}
ClientboundGamePacket::Explode(_) => {} ClientboundGamePacket::Explode(_) => {}
ClientboundGamePacket::ForgetLevelChunk(_) => {} ClientboundGamePacket::ForgetLevelChunk(_) => {}
@ -967,7 +914,6 @@ impl Client {
ClientboundGamePacket::OpenSignEditor(_) => {} ClientboundGamePacket::OpenSignEditor(_) => {}
ClientboundGamePacket::Ping(_) => {} ClientboundGamePacket::Ping(_) => {}
ClientboundGamePacket::PlaceGhostRecipe(_) => {} ClientboundGamePacket::PlaceGhostRecipe(_) => {}
ClientboundGamePacket::PlayerChatHeader(_) => {}
ClientboundGamePacket::PlayerCombatEnd(_) => {} ClientboundGamePacket::PlayerCombatEnd(_) => {}
ClientboundGamePacket::PlayerCombatEnter(_) => {} ClientboundGamePacket::PlayerCombatEnter(_) => {}
ClientboundGamePacket::PlayerCombatKill(p) => { ClientboundGamePacket::PlayerCombatKill(p) => {
@ -998,7 +944,6 @@ impl Client {
ClientboundGamePacket::SetBorderWarningDelay(_) => {} ClientboundGamePacket::SetBorderWarningDelay(_) => {}
ClientboundGamePacket::SetBorderWarningDistance(_) => {} ClientboundGamePacket::SetBorderWarningDistance(_) => {}
ClientboundGamePacket::SetCamera(_) => {} ClientboundGamePacket::SetCamera(_) => {}
ClientboundGamePacket::SetDisplayChatPreview(_) => {}
ClientboundGamePacket::SetDisplayObjective(_) => {} ClientboundGamePacket::SetDisplayObjective(_) => {}
ClientboundGamePacket::SetObjective(_) => {} ClientboundGamePacket::SetObjective(_) => {}
ClientboundGamePacket::SetPassengers(_) => {} ClientboundGamePacket::SetPassengers(_) => {}
@ -1013,6 +958,8 @@ impl Client {
ClientboundGamePacket::TabList(_) => {} ClientboundGamePacket::TabList(_) => {}
ClientboundGamePacket::TagQuery(_) => {} ClientboundGamePacket::TagQuery(_) => {}
ClientboundGamePacket::TakeItemEntity(_) => {} ClientboundGamePacket::TakeItemEntity(_) => {}
ClientboundGamePacket::DisguisedChat(_) => {}
ClientboundGamePacket::UpdateEnabledFeatures(_) => {}
ClientboundGamePacket::ContainerClose(_) => {} ClientboundGamePacket::ContainerClose(_) => {}
} }

View file

@ -2,13 +2,13 @@
//! real clients. If you want to make bots, you should use the //! real clients. If you want to make bots, you should use the
//! [`azalea`] crate instead. //! [`azalea`] crate instead.
//! //!
//! [`azalea_protocol`]: https://crates.io/crates/azalea-protocol //! [`azalea_protocol`]: https://docs.rs/azalea-protocol
//! [`azalea`]: https://crates.io/crates/azalea //! [`azalea`]: https://docs.rs/azalea
#![feature(provide_any)]
#![allow(incomplete_features)] #![allow(incomplete_features)]
#![feature(trait_upcasting)] #![feature(trait_upcasting)]
#![feature(error_generic_member_access)] #![feature(error_generic_member_access)]
#![feature(provide_any)]
mod account; mod account;
mod chat; mod chat;

View file

@ -23,7 +23,7 @@ pub enum PingError {
#[error("{0}")] #[error("{0}")]
Connection(#[from] ConnectionError), Connection(#[from] ConnectionError),
#[error("{0}")] #[error("{0}")]
ReadPacket(#[from] azalea_protocol::read::ReadPacketError), ReadPacket(#[from] Box<azalea_protocol::read::ReadPacketError>),
#[error("{0}")] #[error("{0}")]
WritePacket(#[from] io::Error), WritePacket(#[from] io::Error),
#[error("The given address could not be parsed into a ServerAddress")] #[error("The given address could not be parsed into a ServerAddress")]

View file

@ -1,4 +1,6 @@
use azalea_buf::McBuf; use std::io::{Cursor, Read, Write};
use azalea_buf::{BufReadError, McBuf, McBufReadable, McBufWritable};
/// Represents Java's BitSet, a list of bits. /// Represents Java's BitSet, a list of bits.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, McBuf)] #[derive(Debug, Clone, PartialEq, Eq, Hash, Default, McBuf)]
@ -105,6 +107,89 @@ impl BitSet {
pub fn set(&mut self, bit_index: usize) { pub fn set(&mut self, bit_index: usize) {
self.data[bit_index / 64] |= 1u64 << (bit_index % 64); self.data[bit_index / 64] |= 1u64 << (bit_index % 64);
} }
/// Read a BitSet with a known length.
pub fn read_fixed(buf: &mut Cursor<&[u8]>, length: usize) -> Result<Self, BufReadError> {
let mut data = vec![0; length.div_ceil(8)];
buf.read_exact(&mut data)?;
Ok(BitSet::from(data))
}
}
impl From<Vec<u64>> for BitSet {
fn from(data: Vec<u64>) -> Self {
BitSet { data }
}
}
impl From<Vec<u8>> for BitSet {
fn from(data: Vec<u8>) -> Self {
let mut words = vec![0; data.len().div_ceil(8)];
for (i, byte) in data.iter().enumerate() {
words[i / 8] |= (*byte as u64) << ((i % 8) * 8);
}
BitSet { data: words }
}
}
/// A list of bits with a known fixed size.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FixedBitSet<const N: usize>
where
[(); N.div_ceil(8)]: Sized,
{
data: [u8; N.div_ceil(8)],
}
impl<const N: usize> FixedBitSet<N>
where
[u8; N.div_ceil(8)]: Sized,
{
pub fn new() -> Self {
FixedBitSet {
data: [0; N.div_ceil(8)],
}
}
pub fn index(&self, index: usize) -> bool {
(self.data[index / 8] & (1u8 << (index % 8))) != 0
}
pub fn set(&mut self, bit_index: usize) {
self.data[bit_index / 8] |= 1u8 << (bit_index % 8);
}
}
impl<const N: usize> McBufReadable for FixedBitSet<N>
where
[u8; N.div_ceil(8)]: Sized,
{
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
let mut data = [0; N.div_ceil(8)];
for item in data.iter_mut().take(N.div_ceil(8)) {
*item = u8::read_from(buf)?;
}
Ok(FixedBitSet { data })
}
}
impl<const N: usize> McBufWritable for FixedBitSet<N>
where
[u8; N.div_ceil(8)]: Sized,
{
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
for i in 0..N.div_ceil(8) {
self.data[i].write_into(buf)?;
}
Ok(())
}
}
impl<const N: usize> Default for FixedBitSet<N>
where
[u8; N.div_ceil(8)]: Sized,
{
fn default() -> Self {
Self::new()
}
} }
#[cfg(test)] #[cfg(test)]

3
azalea-core/src/game_type.rs Executable file → Normal file
View file

@ -1,8 +1,9 @@
use azalea_buf::{BufReadError, McBufReadable, McBufWritable}; use azalea_buf::{BufReadError, McBufReadable, McBufWritable};
use std::io::{Cursor, Write}; use std::io::{Cursor, Write};
#[derive(Hash, Copy, Clone, Debug)] #[derive(Hash, Copy, Clone, Debug, Default)]
pub enum GameType { pub enum GameType {
#[default]
Survival, Survival,
Creative, Creative,
Adventure, Adventure,

View file

@ -1,6 +1,8 @@
//! Random miscellaneous things like UUIDs that don't deserve their own crate. //! Random miscellaneous things like UUIDs that don't deserve their own crate.
#![feature(int_roundings)] #![feature(int_roundings)]
#![allow(incomplete_features)]
#![feature(generic_const_exprs)]
mod difficulty; mod difficulty;
pub use difficulty::*; pub use difficulty::*;

View file

@ -7,9 +7,9 @@ pub struct SaltSignaturePair {
pub signature: Vec<u8>, pub signature: Vec<u8>,
} }
#[derive(Clone, Debug, Default, McBuf, PartialEq)] #[derive(Clone, Debug, PartialEq, McBuf)]
pub struct MessageSignature { pub struct MessageSignature {
pub bytes: Vec<u8>, pub bytes: [u8; 256],
} }
#[derive(Clone, Debug, McBuf, PartialEq)] #[derive(Clone, Debug, McBuf, PartialEq)]

File diff suppressed because it is too large Load diff

32466
azalea-physics/src/collision/blocks.rs Executable file → Normal file

File diff suppressed because it is too large Load diff

View file

@ -244,7 +244,7 @@ mod tests {
world.add_entity( world.add_entity(
0, 0,
EntityData::new( EntityData::new(
Uuid::from_u128(0), Uuid::nil(),
Vec3 { Vec3 {
x: 0., x: 0.,
y: 70., y: 70.,
@ -277,7 +277,7 @@ mod tests {
world.add_entity( world.add_entity(
0, 0,
EntityData::new( EntityData::new(
Uuid::from_u128(0), Uuid::nil(),
Vec3 { Vec3 {
x: 0.5, x: 0.5,
y: 70., y: 70.,
@ -310,7 +310,7 @@ mod tests {
world.add_entity( world.add_entity(
0, 0,
EntityData::new( EntityData::new(
Uuid::from_u128(0), Uuid::nil(),
Vec3 { Vec3 {
x: 0.5, x: 0.5,
y: 71., y: 71.,
@ -344,7 +344,7 @@ mod tests {
world.add_entity( world.add_entity(
0, 0,
EntityData::new( EntityData::new(
Uuid::from_u128(0), Uuid::nil(),
Vec3 { Vec3 {
x: 0.5, x: 0.5,
y: 71., y: 71.,
@ -378,7 +378,7 @@ mod tests {
world.add_entity( world.add_entity(
0, 0,
EntityData::new( EntityData::new(
Uuid::from_u128(0), Uuid::nil(),
Vec3 { Vec3 {
x: 0.5, x: 0.5,
y: 73., y: 73.,

View file

@ -30,7 +30,7 @@ futures-util = "0.3.24"
log = "0.4.17" log = "0.4.17"
serde = {version = "1.0.130", features = ["serde_derive"]} serde = {version = "1.0.130", features = ["serde_derive"]}
serde_json = "^1.0.72" serde_json = "^1.0.72"
thiserror = "^1.0.34" thiserror = "1.0.37"
tokio = {version = "^1.21.2", features = ["io-util", "net", "macros"]} tokio = {version = "^1.21.2", features = ["io-util", "net", "macros"]}
tokio-util = {version = "0.7.4", features = ["codec"]} tokio-util = {version = "0.7.4", features = ["codec"]}
trust-dns-resolver = {version = "^0.22.0", default-features = false, features = ["tokio-runtime"]} trust-dns-resolver = {version = "^0.22.0", default-features = false, features = ["tokio-runtime"]}

View file

@ -24,4 +24,3 @@ Adding new packets is usually pretty easy, but you'll want to have Minecraft's d
You can manually implement reading and writing functionality for a packet by implementing McBufReadable and McBufWritable, but you can also have this automatically generated for a struct or enum by deriving McBuf. You can manually implement reading and writing functionality for a packet by implementing McBufReadable and McBufWritable, but you can also have this automatically generated for a struct or enum by deriving McBuf.
Look at other packets as an example. Look at other packets as an example.

View file

@ -221,11 +221,19 @@ pub fn declare_state_packets(input: TokenStream) -> TokenStream {
}); });
serverbound_read_match_contents.extend(quote! { serverbound_read_match_contents.extend(quote! {
#id => { #id => {
let data = #module::#name::read(buf).map_err(|e| crate::read::ReadPacketError::Parse { source: e, packet_id: #id, packet_name: #name_litstr.to_string() })?; let data = #module::#name::read(buf).map_err(|e| crate::read::ReadPacketError::Parse {
source: e,
packet_id: #id,
backtrace: Box::new(std::backtrace::Backtrace::capture()),
packet_name: #name_litstr.to_string(),
})?;
#[cfg(debug_assertions)]
{
let mut leftover = Vec::new(); let mut leftover = Vec::new();
let _ = std::io::Read::read_to_end(buf, &mut leftover); let _ = std::io::Read::read_to_end(buf, &mut leftover);
if !leftover.is_empty() { if !leftover.is_empty() {
return Err(crate::read::ReadPacketError::LeftoverData { packet_name: #name_litstr.to_string(), data: leftover }); return Err(Box::new(crate::read::ReadPacketError::LeftoverData { packet_name: #name_litstr.to_string(), data: leftover }));
}
} }
data data
}, },
@ -246,14 +254,25 @@ pub fn declare_state_packets(input: TokenStream) -> TokenStream {
}); });
clientbound_read_match_contents.extend(quote! { clientbound_read_match_contents.extend(quote! {
#id => { #id => {
let data = #module::#name::read(buf).map_err(|e| crate::read::ReadPacketError::Parse { source: e, packet_id: #id, packet_name: #name_litstr.to_string() })?; let data = #module::#name::read(buf).map_err(|e| crate::read::ReadPacketError::Parse {
source: e,
packet_id: #id,
backtrace: Box::new(std::backtrace::Backtrace::capture()),
packet_name: #name_litstr.to_string(),
})?;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
let mut leftover = Vec::new(); let mut leftover = Vec::new();
let _ = std::io::Read::read_to_end(buf, &mut leftover); let _ = std::io::Read::read_to_end(buf, &mut leftover);
if !leftover.is_empty() { if !leftover.is_empty() {
return Err(crate::read::ReadPacketError::LeftoverData { packet_name: #name_litstr.to_string(), data: leftover }); return Err(
Box::new(
crate::read::ReadPacketError::LeftoverData {
packet_name: #name_litstr.to_string(),
data: leftover
}
)
);
} }
} }
data data
@ -314,13 +333,13 @@ pub fn declare_state_packets(input: TokenStream) -> TokenStream {
fn read( fn read(
id: u32, id: u32,
buf: &mut std::io::Cursor<&[u8]>, buf: &mut std::io::Cursor<&[u8]>,
) -> Result<#serverbound_state_name, crate::read::ReadPacketError> ) -> Result<#serverbound_state_name, Box<crate::read::ReadPacketError>>
where where
Self: Sized, Self: Sized,
{ {
Ok(match id { Ok(match id {
#serverbound_read_match_contents #serverbound_read_match_contents
_ => return Err(crate::read::ReadPacketError::UnknownPacketId { state_name: #state_name_litstr.to_string(), id }), _ => return Err(Box::new(crate::read::ReadPacketError::UnknownPacketId { state_name: #state_name_litstr.to_string(), id })),
}) })
} }
} }
@ -345,13 +364,13 @@ pub fn declare_state_packets(input: TokenStream) -> TokenStream {
fn read( fn read(
id: u32, id: u32,
buf: &mut std::io::Cursor<&[u8]>, buf: &mut std::io::Cursor<&[u8]>,
) -> Result<#clientbound_state_name, crate::read::ReadPacketError> ) -> Result<#clientbound_state_name, Box<crate::read::ReadPacketError>>
where where
Self: Sized, Self: Sized,
{ {
Ok(match id { Ok(match id {
#clientbound_read_match_contents #clientbound_read_match_contents
_ => return Err(crate::read::ReadPacketError::UnknownPacketId { state_name: #state_name_litstr.to_string(), id }), _ => return Err(Box::new(crate::read::ReadPacketError::UnknownPacketId { state_name: #state_name_litstr.to_string(), id })),
}) })
} }
} }

View file

@ -52,7 +52,7 @@ pub struct WriteConnection<W: ProtocolPacket> {
/// login::{ /// login::{
/// ClientboundLoginPacket, /// ClientboundLoginPacket,
/// serverbound_hello_packet::ServerboundHelloPacket, /// serverbound_hello_packet::ServerboundHelloPacket,
/// serverbound_key_packet::{ServerboundKeyPacket, NonceOrSaltSignature} /// serverbound_key_packet::ServerboundKeyPacket
/// }, /// },
/// handshake::client_intention_packet::ClientIntentionPacket /// handshake::client_intention_packet::ClientIntentionPacket
/// } /// }
@ -80,8 +80,7 @@ pub struct WriteConnection<W: ProtocolPacket> {
/// // login /// // login
/// conn.write( /// conn.write(
/// ServerboundHelloPacket { /// ServerboundHelloPacket {
/// username: "bot".to_string(), /// name: "bot".to_string(),
/// public_key: None,
/// profile_id: None, /// profile_id: None,
/// } /// }
/// .get(), /// .get(),
@ -96,8 +95,8 @@ pub struct WriteConnection<W: ProtocolPacket> {
/// ///
/// conn.write( /// conn.write(
/// ServerboundKeyPacket { /// ServerboundKeyPacket {
/// nonce_or_salt_signature: NonceOrSaltSignature::Nonce(e.encrypted_nonce),
/// key_bytes: e.encrypted_public_key, /// key_bytes: e.encrypted_public_key,
/// encrypted_challenge: e.encrypted_nonce,
/// } /// }
/// .get(), /// .get(),
/// ) /// )
@ -131,7 +130,7 @@ where
R: ProtocolPacket + Debug, R: ProtocolPacket + Debug,
{ {
/// Read a packet from the stream. /// Read a packet from the stream.
pub async fn read(&mut self) -> Result<R, ReadPacketError> { pub async fn read(&mut self) -> Result<R, Box<ReadPacketError>> {
read_packet::<R, _>( read_packet::<R, _>(
&mut self.read_stream, &mut self.read_stream,
&mut self.buffer, &mut self.buffer,
@ -179,7 +178,7 @@ where
W: ProtocolPacket + Debug, W: ProtocolPacket + Debug,
{ {
/// Read a packet from the other side of the connection. /// Read a packet from the other side of the connection.
pub async fn read(&mut self) -> Result<R, ReadPacketError> { pub async fn read(&mut self) -> Result<R, Box<ReadPacketError>> {
self.reader.read().await self.reader.read().await
} }
@ -276,7 +275,7 @@ impl Connection<ClientboundLoginPacket, ServerboundLoginPacket> {
/// use azalea_protocol::connect::Connection; /// use azalea_protocol::connect::Connection;
/// use azalea_protocol::packets::login::{ /// use azalea_protocol::packets::login::{
/// ClientboundLoginPacket, /// ClientboundLoginPacket,
/// serverbound_key_packet::{ServerboundKeyPacket, NonceOrSaltSignature} /// serverbound_key_packet::ServerboundKeyPacket
/// }; /// };
/// use uuid::Uuid; /// use uuid::Uuid;
/// # use azalea_protocol::ServerAddress; /// # use azalea_protocol::ServerAddress;
@ -307,8 +306,8 @@ impl Connection<ClientboundLoginPacket, ServerboundLoginPacket> {
/// ).await?; /// ).await?;
/// conn.write( /// conn.write(
/// ServerboundKeyPacket { /// ServerboundKeyPacket {
/// nonce_or_salt_signature: NonceOrSaltSignature::Nonce(e.encrypted_nonce),
/// key_bytes: e.encrypted_public_key, /// key_bytes: e.encrypted_public_key,
/// encrypted_challenge: e.encrypted_nonce,
/// }.get() /// }.get()
/// ).await?; /// ).await?;
/// conn.set_encryption_key(e.secret_key); /// conn.set_encryption_key(e.secret_key);

View file

@ -76,8 +76,7 @@ mod tests {
use crate::{ use crate::{
packets::login::{ packets::login::{
serverbound_hello_packet::{ProfilePublicKeyData, ServerboundHelloPacket}, serverbound_hello_packet::ServerboundHelloPacket, ServerboundLoginPacket,
ServerboundLoginPacket,
}, },
read::read_packet, read::read_packet,
write::write_packet, write::write_packet,
@ -88,13 +87,8 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn test_hello_packet() { async fn test_hello_packet() {
let packet = ServerboundHelloPacket { let packet = ServerboundHelloPacket {
username: "test".to_string(), name: "test".to_string(),
public_key: Some(ProfilePublicKeyData { profile_id: Some(Uuid::nil()),
expires_at: 0,
key: b"idontthinkthisreallymattersijustwantittobelongforthetest".to_vec(),
key_signature: b"idontthinkthisreallymattersijustwantittobelongforthetest".to_vec(),
}),
profile_id: Some(Uuid::from_u128(0)),
} }
.get(); .get();
let mut stream = Vec::new(); let mut stream = Vec::new();
@ -117,13 +111,8 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn test_double_hello_packet() { async fn test_double_hello_packet() {
let packet = ServerboundHelloPacket { let packet = ServerboundHelloPacket {
username: "test".to_string(), name: "test".to_string(),
public_key: Some(ProfilePublicKeyData { profile_id: Some(Uuid::nil()),
expires_at: 0,
key: b"idontthinkthisreallymattersijustwantittobelongforthetest".to_vec(),
key_signature: b"idontthinkthisreallymattersijustwantittobelongforthetest".to_vec(),
}),
profile_id: Some(Uuid::from_u128(0)),
} }
.get(); .get();
let mut stream = Vec::new(); let mut stream = Vec::new();

View file

@ -79,15 +79,15 @@ pub enum BrigadierString {
GreedyPhrase = 2, GreedyPhrase = 2,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, McBuf)]
pub enum BrigadierParser { pub enum BrigadierParser {
Bool, Bool,
Double(BrigadierNumber<f64>),
Float(BrigadierNumber<f32>), Float(BrigadierNumber<f32>),
Double(BrigadierNumber<f64>),
Integer(BrigadierNumber<i32>), Integer(BrigadierNumber<i32>),
Long(BrigadierNumber<i64>), Long(BrigadierNumber<i64>),
String(BrigadierString), String(BrigadierString),
Entity { single: bool, players_only: bool }, Entity(EntityParser),
GameProfile, GameProfile,
BlockPos, BlockPos,
ColumnPos, ColumnPos,
@ -100,283 +100,61 @@ pub enum BrigadierParser {
Color, Color,
Component, Component,
Message, Message,
Nbt, NbtCompoundTag,
NbtTag,
NbtPath, NbtPath,
Objective, Objective,
ObjectiveCriteira, ObjectiveCriteria,
Operation, Operation,
Particle, Particle,
Rotation,
Angle, Angle,
Rotation,
ScoreboardSlot, ScoreboardSlot,
ScoreHolder { allows_multiple: bool }, ScoreHolder { allows_multiple: bool },
Swizzle, Swizzle,
Team, Team,
ItemSlot, ItemSlot,
ResourceLocation, ResourceLocation,
MobEffect,
Function, Function,
EntityAnchor, EntityAnchor,
IntRange, IntRange,
FloatRange, FloatRange,
ItemEnchantment,
EntitySummon,
Dimension, Dimension,
Uuid, GameMode,
NbtTag,
Time, Time,
ResourceOrTag { registry_key: ResourceLocation }, ResourceOrTag { registry_key: ResourceLocation },
ResourceOrTagKey { registry_key: ResourceLocation },
Resource { registry_key: ResourceLocation }, Resource { registry_key: ResourceLocation },
ResourceKey { registry_key: ResourceLocation },
TemplateMirror, TemplateMirror,
TemplateRotation, TemplateRotation,
Uuid,
} }
impl McBufReadable for BrigadierParser { #[derive(Debug, Clone)]
pub struct EntityParser {
pub single: bool,
pub players_only: bool,
}
impl McBufReadable for EntityParser {
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> { fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
let parser_type = u32::var_read_from(buf)?;
match parser_type {
0 => Ok(BrigadierParser::Bool),
1 => Ok(BrigadierParser::Float(BrigadierNumber::read_from(buf)?)),
2 => Ok(BrigadierParser::Double(BrigadierNumber::read_from(buf)?)),
3 => Ok(BrigadierParser::Integer(BrigadierNumber::read_from(buf)?)),
4 => Ok(BrigadierParser::Long(BrigadierNumber::read_from(buf)?)),
5 => Ok(BrigadierParser::String(BrigadierString::read_from(buf)?)),
6 => {
let flags = u8::read_from(buf)?; let flags = u8::read_from(buf)?;
Ok(BrigadierParser::Entity { Ok(EntityParser {
single: flags & 0x01 != 0, single: flags & 0x01 != 0,
players_only: flags & 0x02 != 0, players_only: flags & 0x02 != 0,
}) })
} }
7 => Ok(BrigadierParser::GameProfile),
8 => Ok(BrigadierParser::BlockPos),
9 => Ok(BrigadierParser::ColumnPos),
10 => Ok(BrigadierParser::Vec3),
11 => Ok(BrigadierParser::Vec2),
12 => Ok(BrigadierParser::BlockState),
13 => Ok(BrigadierParser::BlockPredicate),
14 => Ok(BrigadierParser::ItemStack),
15 => Ok(BrigadierParser::ItemPredicate),
16 => Ok(BrigadierParser::Color),
17 => Ok(BrigadierParser::Component),
18 => Ok(BrigadierParser::Message),
19 => Ok(BrigadierParser::Nbt),
20 => Ok(BrigadierParser::NbtTag),
21 => Ok(BrigadierParser::NbtPath),
22 => Ok(BrigadierParser::Objective),
23 => Ok(BrigadierParser::ObjectiveCriteira),
24 => Ok(BrigadierParser::Operation),
25 => Ok(BrigadierParser::Particle),
26 => Ok(BrigadierParser::Angle),
27 => Ok(BrigadierParser::Rotation),
28 => Ok(BrigadierParser::ScoreboardSlot),
29 => {
let flags = u8::read_from(buf)?;
Ok(BrigadierParser::ScoreHolder {
allows_multiple: flags & 0x01 != 0,
})
} }
30 => Ok(BrigadierParser::Swizzle), impl McBufWritable for EntityParser {
31 => Ok(BrigadierParser::Team),
32 => Ok(BrigadierParser::ItemSlot),
33 => Ok(BrigadierParser::ResourceLocation),
34 => Ok(BrigadierParser::MobEffect),
35 => Ok(BrigadierParser::Function),
36 => Ok(BrigadierParser::EntityAnchor),
37 => Ok(BrigadierParser::IntRange),
38 => Ok(BrigadierParser::FloatRange),
39 => Ok(BrigadierParser::ItemEnchantment),
40 => Ok(BrigadierParser::EntitySummon),
41 => Ok(BrigadierParser::Dimension),
42 => Ok(BrigadierParser::Time),
43 => Ok(BrigadierParser::ResourceOrTag {
registry_key: ResourceLocation::read_from(buf)?,
}),
44 => Ok(BrigadierParser::Resource {
registry_key: ResourceLocation::read_from(buf)?,
}),
45 => Ok(BrigadierParser::TemplateMirror),
46 => Ok(BrigadierParser::TemplateRotation),
47 => Ok(BrigadierParser::Uuid),
_ => Err(BufReadError::UnexpectedEnumVariant {
id: parser_type as i32,
}),
}
}
}
impl McBufWritable for BrigadierParser {
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
match &self { let mut flags: u8 = 0;
BrigadierParser::Bool => { if self.single {
u32::var_write_into(&0, buf)?; flags |= 0x01;
}
BrigadierParser::Float(f) => {
u32::var_write_into(&1, buf)?;
f.write_into(buf)?;
}
BrigadierParser::Double(d) => {
u32::var_write_into(&2, buf)?;
d.write_into(buf)?;
}
BrigadierParser::Integer(i) => {
u32::var_write_into(&3, buf)?;
i.write_into(buf)?;
}
BrigadierParser::Long(l) => {
u32::var_write_into(&4, buf)?;
l.write_into(buf)?;
}
BrigadierParser::String(s) => {
u32::var_write_into(&5, buf)?;
s.write_into(buf)?;
}
BrigadierParser::Entity {
single,
players_only,
} => {
u32::var_write_into(&6, buf)?;
let mut bitmask: u8 = 0x00;
if *single {
bitmask |= 0x01;
}
if *players_only {
bitmask |= 0x02;
}
bitmask.write_into(buf)?;
}
BrigadierParser::GameProfile => {
u32::var_write_into(&7, buf)?;
}
BrigadierParser::BlockPos => {
u32::var_write_into(&8, buf)?;
}
BrigadierParser::ColumnPos => {
u32::var_write_into(&9, buf)?;
}
BrigadierParser::Vec3 => {
u32::var_write_into(&10, buf)?;
}
BrigadierParser::Vec2 => {
u32::var_write_into(&11, buf)?;
}
BrigadierParser::BlockState => {
u32::var_write_into(&12, buf)?;
}
BrigadierParser::BlockPredicate => {
u32::var_write_into(&13, buf)?;
}
BrigadierParser::ItemStack => {
u32::var_write_into(&14, buf)?;
}
BrigadierParser::ItemPredicate => {
u32::var_write_into(&15, buf)?;
}
BrigadierParser::Color => {
u32::var_write_into(&16, buf)?;
}
BrigadierParser::Component => {
u32::var_write_into(&17, buf)?;
}
BrigadierParser::Message => {
u32::var_write_into(&18, buf)?;
}
BrigadierParser::Nbt => {
u32::var_write_into(&19, buf)?;
}
BrigadierParser::NbtTag => {
u32::var_write_into(&20, buf)?;
}
BrigadierParser::NbtPath => {
u32::var_write_into(&21, buf)?;
}
BrigadierParser::Objective => {
u32::var_write_into(&22, buf)?;
}
BrigadierParser::ObjectiveCriteira => {
u32::var_write_into(&23, buf)?;
}
BrigadierParser::Operation => {
u32::var_write_into(&24, buf)?;
}
BrigadierParser::Particle => {
u32::var_write_into(&25, buf)?;
}
BrigadierParser::Angle => {
u32::var_write_into(&26, buf)?;
}
BrigadierParser::Rotation => {
u32::var_write_into(&27, buf)?;
}
BrigadierParser::ScoreboardSlot => {
u32::var_write_into(&28, buf)?;
}
BrigadierParser::ScoreHolder { allows_multiple } => {
u32::var_write_into(&29, buf)?;
if *allows_multiple {
buf.write_all(&[0x01])?;
} else {
buf.write_all(&[0x00])?;
}
}
BrigadierParser::Swizzle => {
u32::var_write_into(&30, buf)?;
}
BrigadierParser::Team => {
u32::var_write_into(&31, buf)?;
}
BrigadierParser::ItemSlot => {
u32::var_write_into(&32, buf)?;
}
BrigadierParser::ResourceLocation => {
u32::var_write_into(&33, buf)?;
}
BrigadierParser::MobEffect => {
u32::var_write_into(&34, buf)?;
}
BrigadierParser::Function => {
u32::var_write_into(&35, buf)?;
}
BrigadierParser::EntityAnchor => {
u32::var_write_into(&36, buf)?;
}
BrigadierParser::IntRange => {
u32::var_write_into(&37, buf)?;
}
BrigadierParser::FloatRange => {
u32::var_write_into(&38, buf)?;
}
BrigadierParser::ItemEnchantment => {
u32::var_write_into(&39, buf)?;
}
BrigadierParser::EntitySummon => {
u32::var_write_into(&40, buf)?;
}
BrigadierParser::Dimension => {
u32::var_write_into(&41, buf)?;
}
BrigadierParser::Time => {
u32::var_write_into(&42, buf)?;
}
BrigadierParser::ResourceOrTag { registry_key } => {
u32::var_write_into(&43, buf)?;
registry_key.write_into(buf)?;
}
BrigadierParser::Resource { registry_key } => {
u32::var_write_into(&44, buf)?;
registry_key.write_into(buf)?;
}
BrigadierParser::TemplateMirror => {
u32::var_write_into(&45, buf)?;
}
BrigadierParser::TemplateRotation => {
u32::var_write_into(&46, buf)?;
}
BrigadierParser::Uuid => {
u32::var_write_into(&47, buf)?;
} }
if self.players_only {
flags |= 0x02;
} }
flags.write_into(buf)?;
Ok(()) Ok(())
} }
} }
@ -412,7 +190,7 @@ impl McBufReadable for BrigadierNodeStub {
} else { } else {
None None
}; };
return Ok(BrigadierNodeStub { let node = BrigadierNodeStub {
is_executable, is_executable,
children, children,
redirect_node, redirect_node,
@ -421,10 +199,11 @@ impl McBufReadable for BrigadierNodeStub {
parser, parser,
suggestions_type, suggestions_type,
}, },
}); };
return Ok(node);
} }
// literal node // literal node
if node_type == 1 { else if node_type == 1 {
let name = String::read_from(buf)?; let name = String::read_from(buf)?;
return Ok(BrigadierNodeStub { return Ok(BrigadierNodeStub {
is_executable, is_executable,

View file

@ -1,20 +0,0 @@
use azalea_buf::McBuf;
use azalea_core::ResourceLocation;
use azalea_protocol_macros::ClientboundGamePacket;
use super::clientbound_sound_packet::SoundSource;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
pub struct ClientboundCustomSoundPacket {
pub name: ResourceLocation,
pub source: SoundSource,
/// x position multiplied by 8
pub x: i32,
/// y position multiplied by 8
pub y: i32,
/// z position multiplied by 8
pub z: i32,
pub volume: f32,
pub pitch: f32,
pub seed: u64,
}

View file

@ -1,8 +1,8 @@
use super::clientbound_player_chat_packet::PackedMessageSignature;
use azalea_buf::McBuf; use azalea_buf::McBuf;
use azalea_crypto::MessageSignature;
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] #[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
pub struct ClientboundDeleteChatPacket { pub struct ClientboundDeleteChatPacket {
pub message_signature: MessageSignature, pub signature: PackedMessageSignature,
} }

View file

@ -0,0 +1,10 @@
use super::clientbound_player_chat_packet::ChatTypeBound;
use azalea_buf::McBuf;
use azalea_chat::Component;
use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
pub struct ClientboundDisguisedChatPacket {
pub message: Component,
pub chat_type: ChatTypeBound,
}

View file

@ -1,13 +1,14 @@
use std::io::{Cursor, Write};
use azalea_buf::{BufReadError, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable}; use azalea_buf::{BufReadError, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable};
use azalea_core::BlockPos; use azalea_core::BlockPos;
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
use std::io::{Cursor, Write};
#[derive(Clone, Debug, PartialEq, ClientboundGamePacket)] #[derive(Clone, Debug, PartialEq, ClientboundGamePacket)]
pub struct ClientboundExplodePacket { pub struct ClientboundExplodePacket {
pub x: f32, pub x: f64,
pub y: f32, pub y: f64,
pub z: f32, pub z: f64,
pub power: f32, pub power: f32,
pub to_blow: Vec<BlockPos>, pub to_blow: Vec<BlockPos>,
pub knockback_x: f32, pub knockback_x: f32,
@ -17,9 +18,9 @@ pub struct ClientboundExplodePacket {
impl McBufReadable for ClientboundExplodePacket { impl McBufReadable for ClientboundExplodePacket {
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> { fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
let x = f32::read_from(buf)?; let x = f64::read_from(buf)?;
let y = f32::read_from(buf)?; let y = f64::read_from(buf)?;
let z = f32::read_from(buf)?; let z = f64::read_from(buf)?;
let power = f32::read_from(buf)?; let power = f32::read_from(buf)?;
let x_floor = x.floor() as i32; let x_floor = x.floor() as i32;

View file

@ -1,19 +1,57 @@
use azalea_buf::McBuf; use azalea_buf::{
BufReadError, McBuf, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable,
};
use azalea_chat::{ use azalea_chat::{
translatable_component::{StringOrComponent, TranslatableComponent}, translatable_component::{StringOrComponent, TranslatableComponent},
Component, Component,
}; };
use azalea_core::BitSet; use azalea_core::BitSet;
use azalea_crypto::{MessageSignature, SignedMessageHeader}; use azalea_crypto::MessageSignature;
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
use std::io::{Cursor, Write};
use uuid::Uuid; use uuid::Uuid;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket, PartialEq)] #[derive(Clone, Debug, McBuf, ClientboundGamePacket, PartialEq)]
pub struct ClientboundPlayerChatPacket { pub struct ClientboundPlayerChatPacket {
pub message: PlayerChatMessage, pub sender: Uuid,
#[var]
pub index: u32,
pub signature: Option<MessageSignature>,
pub body: PackedSignedMessageBody,
pub unsigned_content: Option<Component>,
pub filter_mask: FilterMask,
pub chat_type: ChatTypeBound, pub chat_type: ChatTypeBound,
} }
#[derive(Clone, Debug, PartialEq, McBuf)]
pub struct PackedSignedMessageBody {
// the error is here, for some reason it skipped a byte earlier and here
// it's reading `0` when it should be `11`
pub content: String,
pub timestamp: u64,
pub salt: u64,
pub last_seen: PackedLastSeenMessages,
}
#[derive(Clone, Debug, PartialEq, McBuf)]
pub struct PackedLastSeenMessages {
pub entries: Vec<PackedMessageSignature>,
}
/// Messages can be deleted by either their signature or message id.
#[derive(Clone, Debug, PartialEq)]
pub enum PackedMessageSignature {
Signature(Box<MessageSignature>),
Id(u32),
}
#[derive(Clone, Debug, PartialEq, McBuf)]
pub enum FilterMask {
PassThrough,
FullyFiltered,
PartiallyFiltered(BitSet),
}
#[derive(Copy, Clone, Debug, McBuf, PartialEq, Eq)] #[derive(Copy, Clone, Debug, McBuf, PartialEq, Eq)]
pub enum ChatType { pub enum ChatType {
Chat = 0, Chat = 0,
@ -32,47 +70,36 @@ pub struct ChatTypeBound {
pub target_name: Option<Component>, pub target_name: Option<Component>,
} }
#[derive(Clone, Debug, McBuf, PartialEq)] // must be in Client
pub struct PlayerChatMessage { #[derive(Clone, Debug, PartialEq)]
pub signed_header: SignedMessageHeader, pub struct MessageSignatureCache {
pub header_signature: MessageSignature, pub entries: Vec<Option<MessageSignature>>,
pub signed_body: SignedMessageBody,
pub unsigned_content: Option<Component>,
pub filter_mask: FilterMask,
} }
#[derive(Clone, Debug, PartialEq, McBuf)] // impl MessageSignatureCache {
pub struct SignedMessageBody { // pub fn unpacker(&self) -> impl Fn(u32) -> Option<SignedMessageBody> {
pub content: ChatMessageContent,
pub timestamp: u64,
pub salt: u64,
pub last_seen: Vec<LastSeenMessagesEntry>,
}
impl PlayerChatMessage { // }
// }
// impl PackedSignedMessageBody {
// pub fn unpack(&self, unpacker: impl Fn(u32) -> Option<SignedMessageBody>) {}
// }
impl ClientboundPlayerChatPacket {
/// Returns the content of the message. If you want to get the Component /// Returns the content of the message. If you want to get the Component
/// for the whole message including the sender part, use /// for the whole message including the sender part, use
/// [`ClientboundPlayerChatPacket::message`]. /// [`ClientboundPlayerChatPacket::message`].
pub fn content(&self, only_secure_chat: bool) -> Component { pub fn content(&self) -> Component {
if only_secure_chat {
return self
.signed_body
.content
.decorated
.clone()
.unwrap_or_else(|| Component::from(self.signed_body.content.plain.clone()));
}
self.unsigned_content self.unsigned_content
.clone() .clone()
.unwrap_or_else(|| self.content(true)) .unwrap_or_else(|| Component::from(self.body.content.clone()))
}
} }
impl ClientboundPlayerChatPacket {
/// Get the full message, including the sender part. /// Get the full message, including the sender part.
pub fn message(&self, only_secure_chat: bool) -> Component { pub fn message(&self) -> Component {
let sender = self.chat_type.name.clone(); let sender = self.chat_type.name.clone();
let content = self.message.content(only_secure_chat); let content = self.content();
let target = self.chat_type.target_name.clone(); let target = self.chat_type.target_name.clone();
let translation_key = self.chat_type.chat_type.chat_translation_key(); let translation_key = self.chat_type.chat_type.chat_translation_key();
@ -117,45 +144,66 @@ impl ChatType {
} }
} }
#[derive(Clone, Debug, McBuf, PartialEq)] impl McBufReadable for PackedMessageSignature {
pub struct LastSeenMessagesEntry { fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
pub profile_id: Uuid, let id = u32::var_read_from(buf)?;
pub last_signature: MessageSignature, if id == 0 {
} let full_signature = MessageSignature::read_from(buf)?;
#[derive(Clone, Debug, McBuf, Default)] Ok(PackedMessageSignature::Signature(Box::new(full_signature)))
pub struct LastSeenMessagesUpdate { } else {
pub last_seen: Vec<LastSeenMessagesEntry>, Ok(PackedMessageSignature::Id(id - 1))
pub last_received: Option<LastSeenMessagesEntry>,
} }
#[derive(Clone, Debug, McBuf, PartialEq)]
pub struct ChatMessageContent {
pub plain: String,
/// Only sent if the decorated message is different than the plain.
pub decorated: Option<Component>,
} }
}
#[derive(Clone, Debug, McBuf, PartialEq)] impl McBufWritable for PackedMessageSignature {
pub enum FilterMask { fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
PassThrough, match self {
FullyFiltered, PackedMessageSignature::Signature(full_signature) => {
PartiallyFiltered(BitSet), 0u32.var_write_into(buf)?;
full_signature.write_into(buf)?;
}
PackedMessageSignature::Id(id) => {
(id + 1).var_write_into(buf)?;
}
}
Ok(())
}
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use azalea_buf::McBufReadable; use std::backtrace::Backtrace;
use std::io::Cursor;
// you can remove or update this test if it breaks because mojang changed the structure of the packet again
#[test] #[test]
fn test_chat_type() { fn test_player_chat_packet() {
let chat_type_enum = ChatType::read_from(&mut Cursor::new(&[0x06])).unwrap(); let data: [u8; 295] = [
assert_eq!(chat_type_enum, ChatType::EmoteCommand); 47, 247, 69, 164, 160, 108, 63, 217, 178, 34, 4, 161, 47, 115, 192, 126, 0, 0, 11, 72,
assert_eq!( 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 0, 0, 1, 132, 209, 9, 72, 139, 0, 0,
ChatType::read_from(&mut Cursor::new(&[0x07])).unwrap(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 242, 1, 123, 34, 105, 110, 115, 101, 114, 116, 105, 111,
ChatType::Chat 110, 34, 58, 34, 98, 111, 116, 48, 34, 44, 34, 99, 108, 105, 99, 107, 69, 118, 101,
); 110, 116, 34, 58, 123, 34, 97, 99, 116, 105, 111, 110, 34, 58, 34, 115, 117, 103, 103,
101, 115, 116, 95, 99, 111, 109, 109, 97, 110, 100, 34, 44, 34, 118, 97, 108, 117, 101,
34, 58, 34, 47, 116, 101, 108, 108, 32, 98, 111, 116, 48, 32, 34, 125, 44, 34, 104,
111, 118, 101, 114, 69, 118, 101, 110, 116, 34, 58, 123, 34, 97, 99, 116, 105, 111,
110, 34, 58, 34, 115, 104, 111, 119, 95, 101, 110, 116, 105, 116, 121, 34, 44, 34, 99,
111, 110, 116, 101, 110, 116, 115, 34, 58, 123, 34, 116, 121, 112, 101, 34, 58, 34,
109, 105, 110, 101, 99, 114, 97, 102, 116, 58, 112, 108, 97, 121, 101, 114, 34, 44, 34,
105, 100, 34, 58, 34, 50, 102, 102, 55, 52, 53, 97, 52, 45, 97, 48, 54, 99, 45, 51,
102, 100, 57, 45, 98, 50, 50, 50, 45, 48, 52, 97, 49, 50, 102, 55, 51, 99, 48, 55, 101,
34, 44, 34, 110, 97, 109, 101, 34, 58, 123, 34, 116, 101, 120, 116, 34, 58, 34, 98,
111, 116, 48, 34, 125, 125, 125, 44, 34, 116, 101, 120, 116, 34, 58, 34, 98, 111, 116,
48, 34, 125, 0,
];
// just make sure it doesn't panic
if let Err(e) = ClientboundPlayerChatPacket::read_from(&mut Cursor::new(&data)) {
let default_backtrace = Backtrace::capture();
let backtrace = std::any::request_ref::<Backtrace>(&e).unwrap_or(&default_backtrace);
eprintln!("{e}\n{backtrace}");
panic!("failed to read player chat packet");
}
} }
} }

View file

@ -1,93 +0,0 @@
use crate::packets::login::serverbound_hello_packet::ProfilePublicKeyData;
use azalea_auth::game_profile::ProfilePropertyValue;
use azalea_buf::{BufReadError, McBuf};
use azalea_buf::{McBufReadable, McBufWritable};
use azalea_chat::Component;
use azalea_core::GameType;
use azalea_protocol_macros::ClientboundGamePacket;
use std::collections::HashMap;
use std::io::{Cursor, Write};
use uuid::Uuid;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
pub struct ClientboundPlayerInfoPacket {
pub action: Action,
}
#[derive(Clone, Debug)]
pub enum Action {
AddPlayer(Vec<AddPlayer>),
UpdateGameMode(Vec<UpdateGameMode>),
UpdateLatency(Vec<UpdateLatency>),
UpdateDisplayName(Vec<UpdateDisplayName>),
RemovePlayer(Vec<RemovePlayer>),
}
#[derive(Clone, Debug, McBuf)]
pub struct AddPlayer {
pub uuid: Uuid,
pub name: String,
pub properties: HashMap<String, ProfilePropertyValue>,
pub gamemode: GameType,
#[var]
pub latency: i32,
pub display_name: Option<Component>,
pub profile_public_key: Option<ProfilePublicKeyData>,
}
#[derive(Clone, Debug, McBuf)]
pub struct UpdateGameMode {
pub uuid: Uuid,
pub gamemode: GameType,
}
#[derive(Clone, Debug, McBuf)]
pub struct UpdateLatency {
pub uuid: Uuid,
#[var]
pub latency: i32,
}
#[derive(Clone, Debug, McBuf)]
pub struct UpdateDisplayName {
pub uuid: Uuid,
pub display_name: Option<Component>,
}
#[derive(Clone, Debug, McBuf)]
pub struct RemovePlayer {
pub uuid: Uuid,
}
impl McBufReadable for Action {
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
let id = u8::read_from(buf)?;
Ok(match id {
0 => Action::AddPlayer(Vec::<AddPlayer>::read_from(buf)?),
1 => Action::UpdateGameMode(Vec::<UpdateGameMode>::read_from(buf)?),
2 => Action::UpdateLatency(Vec::<UpdateLatency>::read_from(buf)?),
3 => Action::UpdateDisplayName(Vec::<UpdateDisplayName>::read_from(buf)?),
4 => Action::RemovePlayer(Vec::<RemovePlayer>::read_from(buf)?),
_ => return Err(BufReadError::UnexpectedEnumVariant { id: id.into() }),
})
}
}
impl McBufWritable for Action {
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
let id: u8 = match self {
Action::AddPlayer(_) => 0,
Action::UpdateGameMode(_) => 1,
Action::UpdateLatency(_) => 2,
Action::UpdateDisplayName(_) => 3,
Action::RemovePlayer(_) => 4,
};
id.write_into(buf)?;
match self {
Action::AddPlayer(players) => players.write_into(buf)?,
Action::UpdateGameMode(players) => players.write_into(buf)?,
Action::UpdateLatency(players) => players.write_into(buf)?,
Action::UpdateDisplayName(players) => players.write_into(buf)?,
Action::RemovePlayer(players) => players.write_into(buf)?,
}
Ok(())
}
}

View file

@ -0,0 +1,8 @@
use azalea_buf::McBuf;
use azalea_protocol_macros::ClientboundGamePacket;
use uuid::Uuid;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
pub struct ClientboundPlayerInfoRemovePacket {
pub profile_ids: Vec<Uuid>,
}

View file

@ -0,0 +1,201 @@
use azalea_auth::game_profile::{GameProfile, ProfilePropertyValue};
use azalea_buf::{
BufReadError, McBuf, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable,
};
use azalea_chat::Component;
use azalea_core::{BitSet, GameType};
use azalea_protocol_macros::ClientboundGamePacket;
use std::{
collections::HashMap,
io::{Cursor, Write},
};
use uuid::Uuid;
use super::serverbound_chat_session_update_packet::RemoteChatSessionData;
#[derive(Clone, Debug, ClientboundGamePacket)]
pub struct ClientboundPlayerInfoUpdatePacket {
pub actions: ActionEnumSet,
pub entries: Vec<PlayerInfoEntry>,
}
#[derive(Clone, Debug, Default)]
pub struct PlayerInfoEntry {
pub profile: GameProfile,
pub listed: bool,
pub latency: i32,
pub game_mode: GameType,
pub display_name: Option<Component>,
pub chat_session: Option<RemoteChatSessionData>,
}
#[derive(Clone, Debug, McBuf)]
pub struct AddPlayerAction {
pub name: String,
pub properties: HashMap<String, ProfilePropertyValue>,
}
#[derive(Clone, Debug, McBuf)]
pub struct InitializeChatAction {
pub chat_session: Option<RemoteChatSessionData>,
}
#[derive(Clone, Debug, McBuf)]
pub struct UpdateGameModeAction {
pub game_mode: GameType,
}
#[derive(Clone, Debug, McBuf)]
pub struct UpdateListedAction {
pub listed: bool,
}
#[derive(Clone, Debug, McBuf)]
pub struct UpdateLatencyAction {
#[var]
pub latency: i32,
}
#[derive(Clone, Debug, McBuf)]
pub struct UpdateDisplayNameAction {
pub display_name: Option<Component>,
}
impl McBufReadable for ClientboundPlayerInfoUpdatePacket {
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
let actions = ActionEnumSet::read_from(buf)?;
let mut entries = vec![];
let entry_count = u32::var_read_from(buf)?;
for _ in 0..entry_count {
let profile_id = Uuid::read_from(buf)?;
let mut entry = PlayerInfoEntry::default();
entry.profile.uuid = profile_id;
if actions.add_player {
let action = AddPlayerAction::read_from(buf)?;
entry.profile.name = action.name;
entry.profile.properties = action.properties;
}
if actions.initialize_chat {
let action = InitializeChatAction::read_from(buf)?;
entry.chat_session = action.chat_session;
}
if actions.update_game_mode {
let action = UpdateGameModeAction::read_from(buf)?;
entry.game_mode = action.game_mode;
}
if actions.update_listed {
let action = UpdateListedAction::read_from(buf)?;
entry.listed = action.listed;
}
if actions.update_latency {
let action = UpdateLatencyAction::read_from(buf)?;
entry.latency = action.latency;
}
if actions.update_display_name {
let action = UpdateDisplayNameAction::read_from(buf)?;
entry.display_name = action.display_name;
}
entries.push(entry);
}
Ok(ClientboundPlayerInfoUpdatePacket { actions, entries })
}
}
impl McBufWritable for ClientboundPlayerInfoUpdatePacket {
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
self.actions.write_into(buf)?;
(self.entries.len() as u32).var_write_into(buf)?;
for entry in &self.entries {
entry.profile.uuid.write_into(buf)?;
if self.actions.add_player {
AddPlayerAction {
name: entry.profile.name.clone(),
properties: entry.profile.properties.clone(),
}
.write_into(buf)?;
}
if self.actions.initialize_chat {
InitializeChatAction {
chat_session: entry.chat_session.clone(),
}
.write_into(buf)?;
}
if self.actions.update_game_mode {
UpdateGameModeAction {
game_mode: entry.game_mode,
}
.write_into(buf)?;
}
if self.actions.update_listed {
UpdateListedAction {
listed: entry.listed,
}
.write_into(buf)?;
}
if self.actions.update_latency {
UpdateLatencyAction {
latency: entry.latency,
}
.write_into(buf)?;
}
if self.actions.update_display_name {
UpdateDisplayNameAction {
display_name: entry.display_name.clone(),
}
.write_into(buf)?;
}
}
Ok(())
}
}
#[derive(Clone, Debug)]
pub struct ActionEnumSet {
pub add_player: bool,
pub initialize_chat: bool,
pub update_game_mode: bool,
pub update_listed: bool,
pub update_latency: bool,
pub update_display_name: bool,
}
impl McBufReadable for ActionEnumSet {
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
let set = BitSet::read_fixed(buf, 6)?;
Ok(ActionEnumSet {
add_player: set.index(0),
initialize_chat: set.index(1),
update_game_mode: set.index(2),
update_listed: set.index(3),
update_latency: set.index(4),
update_display_name: set.index(5),
})
}
}
impl McBufWritable for ActionEnumSet {
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
let mut set = BitSet::new(6);
if self.add_player {
set.set(0);
}
if self.initialize_chat {
set.set(1);
}
if self.update_game_mode {
set.set(2);
}
if self.update_listed {
set.set(3);
}
if self.update_latency {
set.set(4);
}
if self.update_display_name {
set.set(5);
}
set.write_into(buf)
}
}

View file

@ -11,6 +11,6 @@ pub struct ClientboundRespawnPacket {
pub previous_player_game_type: OptionalGameType, pub previous_player_game_type: OptionalGameType,
pub is_debug: bool, pub is_debug: bool,
pub is_flat: bool, pub is_flat: bool,
pub keep_all_player_data: bool, pub data_to_keep: u8,
pub last_death_location: Option<GlobalPos>, pub last_death_location: Option<GlobalPos>,
} }

View file

@ -6,6 +6,5 @@ use azalea_protocol_macros::ClientboundGamePacket;
pub struct ClientboundServerDataPacket { pub struct ClientboundServerDataPacket {
pub motd: Option<Component>, pub motd: Option<Component>,
pub icon_base64: Option<String>, pub icon_base64: Option<String>,
pub previews_chat: bool,
pub enforces_secure_chat: bool, pub enforces_secure_chat: bool,
} }

View file

@ -1,10 +1,11 @@
use super::clientbound_sound_packet::SoundSource; use super::clientbound_sound_packet::SoundSource;
use azalea_buf::McBuf; use azalea_buf::McBuf;
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
use azalea_registry::OptionalRegistry;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] #[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
pub struct ClientboundSoundEntityPacket { pub struct ClientboundSoundEntityPacket {
pub sound: azalea_registry::SoundEvent, pub sound: OptionalRegistry<azalea_registry::SoundEvent>,
pub source: SoundSource, pub source: SoundSource,
#[var] #[var]
pub id: u32, pub id: u32,

View file

@ -1,9 +1,10 @@
use azalea_buf::McBuf; use azalea_buf::McBuf;
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
use azalea_registry::OptionalRegistry;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)] #[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
pub struct ClientboundSoundPacket { pub struct ClientboundSoundPacket {
pub sound: azalea_registry::SoundEvent, pub sound: OptionalRegistry<azalea_registry::SoundEvent>,
pub source: SoundSource, pub source: SoundSource,
pub x: i32, pub x: i32,
pub y: i32, pub y: i32,

View file

@ -0,0 +1,8 @@
use azalea_buf::McBuf;
use azalea_core::ResourceLocation;
use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
pub struct ClientboundUpdateEnabledFeaturesPacket {
pub features: Vec<ResourceLocation>,
}

View file

@ -20,17 +20,27 @@ pub struct Recipe {
pub struct ShapelessRecipe { pub struct ShapelessRecipe {
/// Used to group similar recipes together in the recipe book. /// Used to group similar recipes together in the recipe book.
/// Tag is present in recipe JSON /// Tag is present in recipe JSON
group: String, pub group: String,
ingredients: Vec<Ingredient>, pub category: CraftingBookCategory,
result: Slot, pub ingredients: Vec<Ingredient>,
pub result: Slot,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ShapedRecipe { pub struct ShapedRecipe {
width: usize, pub width: usize,
height: usize, pub height: usize,
group: String, pub group: String,
ingredients: Vec<Ingredient>, pub category: CraftingBookCategory,
result: Slot, pub ingredients: Vec<Ingredient>,
pub result: Slot,
}
#[derive(Clone, Debug, Copy, McBuf)]
pub enum CraftingBookCategory {
Building = 0,
Redstone,
Equipment,
Misc,
} }
impl McBufWritable for ShapedRecipe { impl McBufWritable for ShapedRecipe {
@ -38,6 +48,7 @@ impl McBufWritable for ShapedRecipe {
(self.width as u32).var_write_into(buf)?; (self.width as u32).var_write_into(buf)?;
(self.height as u32).var_write_into(buf)?; (self.height as u32).var_write_into(buf)?;
self.group.write_into(buf)?; self.group.write_into(buf)?;
self.category.write_into(buf)?;
for ingredient in &self.ingredients { for ingredient in &self.ingredients {
ingredient.write_into(buf)?; ingredient.write_into(buf)?;
} }
@ -51,6 +62,7 @@ impl McBufReadable for ShapedRecipe {
let width = u32::var_read_from(buf)?.try_into().unwrap(); let width = u32::var_read_from(buf)?.try_into().unwrap();
let height = u32::var_read_from(buf)?.try_into().unwrap(); let height = u32::var_read_from(buf)?.try_into().unwrap();
let group = String::read_from(buf)?; let group = String::read_from(buf)?;
let category = CraftingBookCategory::read_from(buf)?;
let mut ingredients = Vec::with_capacity(width * height); let mut ingredients = Vec::with_capacity(width * height);
for _ in 0..width * height { for _ in 0..width * height {
ingredients.push(Ingredient::read_from(buf)?); ingredients.push(Ingredient::read_from(buf)?);
@ -61,6 +73,7 @@ impl McBufReadable for ShapedRecipe {
width, width,
height, height,
group, group,
category,
ingredients, ingredients,
result, result,
}) })
@ -69,49 +82,55 @@ impl McBufReadable for ShapedRecipe {
#[derive(Clone, Debug, McBuf)] #[derive(Clone, Debug, McBuf)]
pub struct CookingRecipe { pub struct CookingRecipe {
group: String, pub group: String,
ingredient: Ingredient, pub category: CraftingBookCategory,
result: Slot, pub ingredient: Ingredient,
experience: f32, pub result: Slot,
pub experience: f32,
#[var] #[var]
cooking_time: u32, pub cooking_time: u32,
} }
#[derive(Clone, Debug, McBuf)] #[derive(Clone, Debug, McBuf)]
pub struct StoneCuttingRecipe { pub struct StoneCutterRecipe {
group: String, pub group: String,
ingredient: Ingredient, pub ingredient: Ingredient,
result: Slot, pub result: Slot,
} }
#[derive(Clone, Debug, McBuf)] #[derive(Clone, Debug, McBuf)]
pub struct SmithingRecipe { pub struct SmithingRecipe {
base: Ingredient, pub base: Ingredient,
addition: Ingredient, pub addition: Ingredient,
result: Slot, pub result: Slot,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug, McBuf)]
pub struct SimpleRecipe {
pub category: CraftingBookCategory,
}
#[derive(Clone, Debug, McBuf)]
pub enum RecipeData { pub enum RecipeData {
CraftingShapeless(ShapelessRecipe), CraftingShapeless(ShapelessRecipe),
CraftingShaped(ShapedRecipe), CraftingShaped(ShapedRecipe),
CraftingSpecialArmorDye, CraftingSpecialArmorDye(SimpleRecipe),
CraftingSpecialBookCloning, CraftingSpecialBookCloning(SimpleRecipe),
CraftingSpecialMapCloning, CraftingSpecialMapCloning(SimpleRecipe),
CraftingSpecialMapExtending, CraftingSpecialMapExtending(SimpleRecipe),
CraftingSpecialFireworkRocket, CraftingSpecialFireworkRocket(SimpleRecipe),
CraftingSpecialFireworkStar, CraftingSpecialFireworkStar(SimpleRecipe),
CraftingSpecialFireworkStarFade, CraftingSpecialFireworkStarFade(SimpleRecipe),
CraftingSpecialRepairItem, CraftingSpecialRepairItem(SimpleRecipe),
CraftingSpecialTippedArrow, CraftingSpecialTippedArrow(SimpleRecipe),
CraftingSpecialBannerDuplicate, CraftingSpecialBannerDuplicate(SimpleRecipe),
CraftingSpecialBannerAddPattern, CraftingSpecialBannerAddPattern(SimpleRecipe),
CraftingSpecialShieldDecoration, CraftingSpecialShieldDecoration(SimpleRecipe),
CraftingSpecialShulkerBoxColoring, CraftingSpecialShulkerBoxColoring(SimpleRecipe),
CraftingSpecialSuspiciousStew, CraftingSpecialSuspiciousStew(SimpleRecipe),
Smelting(CookingRecipe), Smelting(CookingRecipe),
Blasting(CookingRecipe), Blasting(CookingRecipe),
Smoking(CookingRecipe), Smoking(CookingRecipe),
CampfireCooking(CookingRecipe), CampfireCooking(CookingRecipe),
Stonecutting(StoneCuttingRecipe), Stonecutting(StoneCutterRecipe),
Smithing(SmithingRecipe), Smithing(SmithingRecipe),
} }
@ -122,148 +141,52 @@ pub struct Ingredient {
impl McBufWritable for Recipe { impl McBufWritable for Recipe {
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> { fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
match &self.data { let resource_location = match &self.data {
RecipeData::CraftingShapeless(recipe) => { RecipeData::CraftingShapeless(_) => "minecraft:crafting_shapeless",
ResourceLocation::new("minecraft:crafting_shapeless") RecipeData::CraftingShaped(_) => "minecraft:crafting_shaped",
.unwrap() RecipeData::CraftingSpecialArmorDye(_) => "minecraft:crafting_special_armordye",
.write_into(buf)?; RecipeData::CraftingSpecialBookCloning(_) => "minecraft:crafting_special_bookcloning",
self.identifier.write_into(buf)?; RecipeData::CraftingSpecialMapCloning(_) => "minecraft:crafting_special_mapcloning",
recipe.write_into(buf)?; RecipeData::CraftingSpecialMapExtending(_) => "minecraft:crafting_special_mapextending",
RecipeData::CraftingSpecialFireworkRocket(_) => {
"minecraft:crafting_special_firework_rocket"
} }
RecipeData::CraftingShaped(recipe) => { RecipeData::CraftingSpecialFireworkStar(_) => {
ResourceLocation::new("minecraft:crafting_shaped") "minecraft:crafting_special_firework_star"
.unwrap()
.write_into(buf)?;
self.identifier.write_into(buf)?;
recipe.write_into(buf)?;
} }
RecipeData::CraftingSpecialArmorDye => {
ResourceLocation::new("minecraft:crafting_special_armordye") RecipeData::CraftingSpecialFireworkStarFade(_) => {
.unwrap() "minecraft:crafting_special_firework_star_fade"
.write_into(buf)?;
self.identifier.write_into(buf)?;
} }
RecipeData::CraftingSpecialBookCloning => { RecipeData::CraftingSpecialRepairItem(_) => "minecraft:crafting_special_repairitem",
ResourceLocation::new("minecraft:crafting_special_bookcloning") RecipeData::CraftingSpecialTippedArrow(_) => "minecraft:crafting_special_tippedarrow",
.unwrap() RecipeData::CraftingSpecialBannerDuplicate(_) => {
.write_into(buf)?; "minecraft:crafting_special_bannerduplicate"
self.identifier.write_into(buf)?;
} }
RecipeData::CraftingSpecialMapCloning => { RecipeData::CraftingSpecialBannerAddPattern(_) => {
ResourceLocation::new("minecraft:crafting_special_mapcloning") "minecraft:crafting_special_banneraddpattern"
.unwrap()
.write_into(buf)?;
self.identifier.write_into(buf)?;
} }
RecipeData::CraftingSpecialMapExtending => { RecipeData::CraftingSpecialShieldDecoration(_) => {
ResourceLocation::new("minecraft:crafting_special_mapextending") "minecraft:crafting_special_shielddecoration"
.unwrap()
.write_into(buf)?;
self.identifier.write_into(buf)?;
} }
RecipeData::CraftingSpecialFireworkRocket => { RecipeData::CraftingSpecialShulkerBoxColoring(_) => {
ResourceLocation::new("minecraft:crafting_special_firework_rocket") "minecraft:crafting_special_shulkerboxcoloring"
.unwrap()
.write_into(buf)?;
self.identifier.write_into(buf)?;
} }
RecipeData::CraftingSpecialFireworkStar => { RecipeData::CraftingSpecialSuspiciousStew(_) => {
ResourceLocation::new("minecraft:crafting_special_firework_star") "minecraft:crafting_special_suspiciousstew"
.unwrap()
.write_into(buf)?;
self.identifier.write_into(buf)?;
}
RecipeData::CraftingSpecialFireworkStarFade => {
ResourceLocation::new("minecraft:crafting_special_firework_star_fade")
.unwrap()
.write_into(buf)?;
self.identifier.write_into(buf)?;
}
RecipeData::CraftingSpecialRepairItem => {
ResourceLocation::new("minecraft:crafting_special_repairitem")
.unwrap()
.write_into(buf)?;
self.identifier.write_into(buf)?;
}
RecipeData::CraftingSpecialTippedArrow => {
ResourceLocation::new("minecraft:crafting_special_tippedarrow")
.unwrap()
.write_into(buf)?;
self.identifier.write_into(buf)?;
}
RecipeData::CraftingSpecialBannerDuplicate => {
ResourceLocation::new("minecraft:crafting_special_bannerduplicate")
.unwrap()
.write_into(buf)?;
self.identifier.write_into(buf)?;
}
RecipeData::CraftingSpecialBannerAddPattern => {
ResourceLocation::new("minecraft:crafting_special_banneraddpattern")
.unwrap()
.write_into(buf)?;
self.identifier.write_into(buf)?;
}
RecipeData::CraftingSpecialShieldDecoration => {
ResourceLocation::new("minecraft:crafting_special_shielddecoration")
.unwrap()
.write_into(buf)?;
self.identifier.write_into(buf)?;
}
RecipeData::CraftingSpecialShulkerBoxColoring => {
ResourceLocation::new("minecraft:crafting_special_shulkerboxcoloring")
.unwrap()
.write_into(buf)?;
self.identifier.write_into(buf)?;
}
RecipeData::CraftingSpecialSuspiciousStew => {
ResourceLocation::new("minecraft:crafting_special_suspiciousstew")
.unwrap()
.write_into(buf)?;
self.identifier.write_into(buf)?;
}
RecipeData::Smelting(recipe) => {
ResourceLocation::new("minecraft:smelting")
.unwrap()
.write_into(buf)?;
self.identifier.write_into(buf)?;
recipe.write_into(buf)?;
}
RecipeData::Blasting(recipe) => {
ResourceLocation::new("minecraft:blasting")
.unwrap()
.write_into(buf)?;
self.identifier.write_into(buf)?;
recipe.write_into(buf)?;
}
RecipeData::Smoking(recipe) => {
ResourceLocation::new("minecraft:smoking")
.unwrap()
.write_into(buf)?;
self.identifier.write_into(buf)?;
recipe.write_into(buf)?;
}
RecipeData::CampfireCooking(recipe) => {
ResourceLocation::new("minecraft:campfire_cooking")
.unwrap()
.write_into(buf)?;
self.identifier.write_into(buf)?;
recipe.write_into(buf)?;
}
RecipeData::Stonecutting(recipe) => {
ResourceLocation::new("minecraft:stonecutting")
.unwrap()
.write_into(buf)?;
self.identifier.write_into(buf)?;
recipe.write_into(buf)?;
}
RecipeData::Smithing(recipe) => {
ResourceLocation::new("minecraft:smithing")
.unwrap()
.write_into(buf)?;
self.identifier.write_into(buf)?;
recipe.write_into(buf)?;
} }
RecipeData::Smelting(_) => "minecraft:smelting",
RecipeData::Blasting(_) => "minecraft:blasting",
RecipeData::Smoking(_) => "minecraft:smoking",
RecipeData::CampfireCooking(_) => "minecraft:campfire_cooking",
RecipeData::Stonecutting(_) => "minecraft:stonecutting",
RecipeData::Smithing(_) => "minecraft:smithing",
}; };
ResourceLocation::new(resource_location)
.unwrap()
.write_into(buf)?;
self.identifier.write_into(buf)?;
self.data.write_without_id(buf)?;
Ok(()) Ok(())
} }
} }
@ -275,83 +198,70 @@ impl McBufReadable for Recipe {
// rust doesn't let us match ResourceLocation so we have to do a big // rust doesn't let us match ResourceLocation so we have to do a big
// if-else chain :( // if-else chain :(
let data = if recipe_type == ResourceLocation::new("minecraft:crafting_shapeless").unwrap() let data = match recipe_type.to_string().as_str() {
{ "minecraft:crafting_shapeless" => {
RecipeData::CraftingShapeless(ShapelessRecipe::read_from(buf)?) RecipeData::CraftingShapeless(ShapelessRecipe::read_from(buf)?)
} else if recipe_type == ResourceLocation::new("minecraft:crafting_shaped").unwrap() { }
"minecraft:crafting_shaped" => {
RecipeData::CraftingShaped(ShapedRecipe::read_from(buf)?) RecipeData::CraftingShaped(ShapedRecipe::read_from(buf)?)
} else if recipe_type }
== ResourceLocation::new("minecraft:crafting_special_armordye").unwrap() "minecraft:crafting_special_armordye" => {
{ RecipeData::CraftingSpecialArmorDye(SimpleRecipe::read_from(buf)?)
RecipeData::CraftingSpecialArmorDye }
} else if recipe_type "minecraft:crafting_special_bookcloning" => {
== ResourceLocation::new("minecraft:crafting_special_bookcloning").unwrap() RecipeData::CraftingSpecialBookCloning(SimpleRecipe::read_from(buf)?)
{ }
RecipeData::CraftingSpecialBookCloning "minecraft:crafting_special_mapcloning" => {
} else if recipe_type RecipeData::CraftingSpecialMapCloning(SimpleRecipe::read_from(buf)?)
== ResourceLocation::new("minecraft:crafting_special_mapcloning").unwrap() }
{ "minecraft:crafting_special_mapextending" => {
RecipeData::CraftingSpecialMapCloning RecipeData::CraftingSpecialMapExtending(SimpleRecipe::read_from(buf)?)
} else if recipe_type }
== ResourceLocation::new("minecraft:crafting_special_mapextending").unwrap() "minecraft:crafting_special_firework_rocket" => {
{ RecipeData::CraftingSpecialFireworkRocket(SimpleRecipe::read_from(buf)?)
RecipeData::CraftingSpecialMapExtending }
} else if recipe_type "minecraft:crafting_special_firework_star" => {
== ResourceLocation::new("minecraft:crafting_special_firework_rocket").unwrap() RecipeData::CraftingSpecialFireworkStar(SimpleRecipe::read_from(buf)?)
{ }
RecipeData::CraftingSpecialFireworkRocket "minecraft:crafting_special_firework_star_fade" => {
} else if recipe_type RecipeData::CraftingSpecialFireworkStarFade(SimpleRecipe::read_from(buf)?)
== ResourceLocation::new("minecraft:crafting_special_firework_star").unwrap() }
{ "minecraft:crafting_special_repairitem" => {
RecipeData::CraftingSpecialFireworkStar RecipeData::CraftingSpecialRepairItem(SimpleRecipe::read_from(buf)?)
} else if recipe_type }
== ResourceLocation::new("minecraft:crafting_special_firework_star_fade").unwrap() "minecraft:crafting_special_tippedarrow" => {
{ RecipeData::CraftingSpecialTippedArrow(SimpleRecipe::read_from(buf)?)
RecipeData::CraftingSpecialFireworkStarFade }
} else if recipe_type "minecraft:crafting_special_bannerduplicate" => {
== ResourceLocation::new("minecraft:crafting_special_repairitem").unwrap() RecipeData::CraftingSpecialBannerDuplicate(SimpleRecipe::read_from(buf)?)
{ }
RecipeData::CraftingSpecialRepairItem "minecraft:crafting_special_banneraddpattern" => {
} else if recipe_type RecipeData::CraftingSpecialBannerAddPattern(SimpleRecipe::read_from(buf)?)
== ResourceLocation::new("minecraft:crafting_special_tippedarrow").unwrap() }
{ "minecraft:crafting_special_shielddecoration" => {
RecipeData::CraftingSpecialTippedArrow RecipeData::CraftingSpecialShieldDecoration(SimpleRecipe::read_from(buf)?)
} else if recipe_type }
== ResourceLocation::new("minecraft:crafting_special_bannerduplicate").unwrap() "minecraft:crafting_special_shulkerboxcoloring" => {
{ RecipeData::CraftingSpecialShulkerBoxColoring(SimpleRecipe::read_from(buf)?)
RecipeData::CraftingSpecialBannerDuplicate }
} else if recipe_type "minecraft:crafting_special_suspiciousstew" => {
== ResourceLocation::new("minecraft:crafting_special_banneraddpattern").unwrap() RecipeData::CraftingSpecialSuspiciousStew(SimpleRecipe::read_from(buf)?)
{ }
RecipeData::CraftingSpecialBannerAddPattern "minecraft:smelting" => RecipeData::Smelting(CookingRecipe::read_from(buf)?),
} else if recipe_type "minecraft:blasting" => RecipeData::Blasting(CookingRecipe::read_from(buf)?),
== ResourceLocation::new("minecraft:crafting_special_shielddecoration").unwrap() "minecraft:smoking" => RecipeData::Smoking(CookingRecipe::read_from(buf)?),
{ "minecraft:campfire_cooking" => {
RecipeData::CraftingSpecialShieldDecoration
} else if recipe_type
== ResourceLocation::new("minecraft:crafting_special_shulkerboxcoloring").unwrap()
{
RecipeData::CraftingSpecialShulkerBoxColoring
} else if recipe_type
== ResourceLocation::new("minecraft:crafting_special_suspiciousstew").unwrap()
{
RecipeData::CraftingSpecialSuspiciousStew
} else if recipe_type == ResourceLocation::new("minecraft:smelting").unwrap() {
RecipeData::Smelting(CookingRecipe::read_from(buf)?)
} else if recipe_type == ResourceLocation::new("minecraft:blasting").unwrap() {
RecipeData::Blasting(CookingRecipe::read_from(buf)?)
} else if recipe_type == ResourceLocation::new("minecraft:smoking").unwrap() {
RecipeData::Smoking(CookingRecipe::read_from(buf)?)
} else if recipe_type == ResourceLocation::new("minecraft:campfire_cooking").unwrap() {
RecipeData::CampfireCooking(CookingRecipe::read_from(buf)?) RecipeData::CampfireCooking(CookingRecipe::read_from(buf)?)
} else if recipe_type == ResourceLocation::new("minecraft:stonecutting").unwrap() { }
RecipeData::Stonecutting(StoneCuttingRecipe::read_from(buf)?) "minecraft:stonecutting" => {
} else if recipe_type == ResourceLocation::new("minecraft:smithing").unwrap() { RecipeData::Stonecutting(StoneCutterRecipe::read_from(buf)?)
RecipeData::Smithing(SmithingRecipe::read_from(buf)?) }
} else { "minecraft:smithing" => RecipeData::Smithing(SmithingRecipe::read_from(buf)?),
_ => {
return Err(BufReadError::UnexpectedStringEnumVariant { return Err(BufReadError::UnexpectedStringEnumVariant {
id: recipe_type.to_string(), id: recipe_type.to_string(),
}); });
}
}; };
let recipe = Recipe { identifier, data }; let recipe = Recipe { identifier, data };

View file

@ -10,7 +10,6 @@ pub mod clientbound_block_event_packet;
pub mod clientbound_block_update_packet; pub mod clientbound_block_update_packet;
pub mod clientbound_boss_event_packet; pub mod clientbound_boss_event_packet;
pub mod clientbound_change_difficulty_packet; pub mod clientbound_change_difficulty_packet;
pub mod clientbound_chat_preview_packet;
pub mod clientbound_command_suggestions_packet; pub mod clientbound_command_suggestions_packet;
pub mod clientbound_commands_packet; pub mod clientbound_commands_packet;
pub mod clientbound_container_close_packet; pub mod clientbound_container_close_packet;
@ -20,9 +19,9 @@ pub mod clientbound_container_set_slot_packet;
pub mod clientbound_cooldown_packet; pub mod clientbound_cooldown_packet;
pub mod clientbound_custom_chat_completions_packet; pub mod clientbound_custom_chat_completions_packet;
pub mod clientbound_custom_payload_packet; pub mod clientbound_custom_payload_packet;
pub mod clientbound_custom_sound_packet;
pub mod clientbound_delete_chat_packet; pub mod clientbound_delete_chat_packet;
pub mod clientbound_disconnect_packet; pub mod clientbound_disconnect_packet;
pub mod clientbound_disguised_chat_packet;
pub mod clientbound_entity_event_packet; pub mod clientbound_entity_event_packet;
pub mod clientbound_explode_packet; pub mod clientbound_explode_packet;
pub mod clientbound_forget_level_chunk_packet; pub mod clientbound_forget_level_chunk_packet;
@ -47,12 +46,12 @@ pub mod clientbound_open_sign_editor_packet;
pub mod clientbound_ping_packet; pub mod clientbound_ping_packet;
pub mod clientbound_place_ghost_recipe_packet; pub mod clientbound_place_ghost_recipe_packet;
pub mod clientbound_player_abilities_packet; pub mod clientbound_player_abilities_packet;
pub mod clientbound_player_chat_header_packet;
pub mod clientbound_player_chat_packet; pub mod clientbound_player_chat_packet;
pub mod clientbound_player_combat_end_packet; pub mod clientbound_player_combat_end_packet;
pub mod clientbound_player_combat_enter_packet; pub mod clientbound_player_combat_enter_packet;
pub mod clientbound_player_combat_kill_packet; pub mod clientbound_player_combat_kill_packet;
pub mod clientbound_player_info_packet; pub mod clientbound_player_info_remove_packet;
pub mod clientbound_player_info_update_packet;
pub mod clientbound_player_look_at_packet; pub mod clientbound_player_look_at_packet;
pub mod clientbound_player_position_packet; pub mod clientbound_player_position_packet;
pub mod clientbound_recipe_packet; pub mod clientbound_recipe_packet;
@ -75,7 +74,6 @@ pub mod clientbound_set_carried_item_packet;
pub mod clientbound_set_chunk_cache_center_packet; pub mod clientbound_set_chunk_cache_center_packet;
pub mod clientbound_set_chunk_cache_radius_packet; pub mod clientbound_set_chunk_cache_radius_packet;
pub mod clientbound_set_default_spawn_position_packet; pub mod clientbound_set_default_spawn_position_packet;
pub mod clientbound_set_display_chat_preview_packet;
pub mod clientbound_set_display_objective_packet; pub mod clientbound_set_display_objective_packet;
pub mod clientbound_set_entity_data_packet; pub mod clientbound_set_entity_data_packet;
pub mod clientbound_set_entity_link_packet; pub mod clientbound_set_entity_link_packet;
@ -102,6 +100,7 @@ pub mod clientbound_take_item_entity_packet;
pub mod clientbound_teleport_entity_packet; pub mod clientbound_teleport_entity_packet;
pub mod clientbound_update_advancements_packet; pub mod clientbound_update_advancements_packet;
pub mod clientbound_update_attributes_packet; pub mod clientbound_update_attributes_packet;
pub mod clientbound_update_enabled_features_packet;
pub mod clientbound_update_mob_effect_packet; pub mod clientbound_update_mob_effect_packet;
pub mod clientbound_update_recipes_packet; pub mod clientbound_update_recipes_packet;
pub mod clientbound_update_tags_packet; pub mod clientbound_update_tags_packet;
@ -111,7 +110,7 @@ pub mod serverbound_change_difficulty_packet;
pub mod serverbound_chat_ack_packet; pub mod serverbound_chat_ack_packet;
pub mod serverbound_chat_command_packet; pub mod serverbound_chat_command_packet;
pub mod serverbound_chat_packet; pub mod serverbound_chat_packet;
pub mod serverbound_chat_preview_packet; pub mod serverbound_chat_session_update_packet;
pub mod serverbound_client_command_packet; pub mod serverbound_client_command_packet;
pub mod serverbound_client_information_packet; pub mod serverbound_client_information_packet;
pub mod serverbound_command_suggestion_packet; pub mod serverbound_command_suggestion_packet;
@ -168,33 +167,33 @@ declare_state_packets!(
0x03: serverbound_chat_ack_packet::ServerboundChatAckPacket, 0x03: serverbound_chat_ack_packet::ServerboundChatAckPacket,
0x04: serverbound_chat_command_packet::ServerboundChatCommandPacket, 0x04: serverbound_chat_command_packet::ServerboundChatCommandPacket,
0x05: serverbound_chat_packet::ServerboundChatPacket, 0x05: serverbound_chat_packet::ServerboundChatPacket,
0x06: serverbound_chat_preview_packet::ServerboundChatPreviewPacket, 0x06: serverbound_client_command_packet::ServerboundClientCommandPacket,
0x07: serverbound_client_command_packet::ServerboundClientCommandPacket, 0x07: serverbound_client_information_packet::ServerboundClientInformationPacket,
0x08: serverbound_client_information_packet::ServerboundClientInformationPacket, 0x08: serverbound_command_suggestion_packet::ServerboundCommandSuggestionPacket,
0x09: serverbound_command_suggestion_packet::ServerboundCommandSuggestionPacket, 0x09: serverbound_container_button_click_packet::ServerboundContainerButtonClickPacket,
0x0a: serverbound_container_button_click_packet::ServerboundContainerButtonClickPacket, 0x0a: serverbound_container_click_packet::ServerboundContainerClickPacket,
0x0b: serverbound_container_click_packet::ServerboundContainerClickPacket, 0x0b: serverbound_container_close_packet::ServerboundContainerClosePacket,
0x0c: serverbound_container_close_packet::ServerboundContainerClosePacket, 0x0c: serverbound_custom_payload_packet::ServerboundCustomPayloadPacket,
0x0d: serverbound_custom_payload_packet::ServerboundCustomPayloadPacket, 0x0d: serverbound_edit_book_packet::ServerboundEditBookPacket,
0x0e: serverbound_edit_book_packet::ServerboundEditBookPacket, 0x0e: serverbound_entity_tag_query::ServerboundEntityTagQuery,
0x0f: serverbound_entity_tag_query::ServerboundEntityTagQuery, 0x0f: serverbound_interact_packet::ServerboundInteractPacket,
0x10: serverbound_interact_packet::ServerboundInteractPacket, 0x10: serverbound_jigsaw_generate_packet::ServerboundJigsawGeneratePacket,
0x11: serverbound_jigsaw_generate_packet::ServerboundJigsawGeneratePacket, 0x11: serverbound_keep_alive_packet::ServerboundKeepAlivePacket,
0x12: serverbound_keep_alive_packet::ServerboundKeepAlivePacket, 0x12: serverbound_lock_difficulty_packet::ServerboundLockDifficultyPacket,
0x13: serverbound_lock_difficulty_packet::ServerboundLockDifficultyPacket, 0x13: serverbound_move_player_pos_packet::ServerboundMovePlayerPosPacket,
0x14: serverbound_move_player_pos_packet::ServerboundMovePlayerPosPacket, 0x14: serverbound_move_player_pos_rot_packet::ServerboundMovePlayerPosRotPacket,
0x15: serverbound_move_player_pos_rot_packet::ServerboundMovePlayerPosRotPacket, 0x15: serverbound_move_player_rot_packet::ServerboundMovePlayerRotPacket,
0x16: serverbound_move_player_rot_packet::ServerboundMovePlayerRotPacket, 0x16: serverbound_move_player_status_only_packet::ServerboundMovePlayerStatusOnlyPacket,
0x17: serverbound_move_player_status_only_packet::ServerboundMovePlayerStatusOnlyPacket, 0x17: serverbound_move_vehicle_packet::ServerboundMoveVehiclePacket,
0x18: serverbound_move_vehicle_packet::ServerboundMoveVehiclePacket, 0x18: serverbound_paddle_boat_packet::ServerboundPaddleBoatPacket,
0x19: serverbound_paddle_boat_packet::ServerboundPaddleBoatPacket, 0x19: serverbound_pick_item_packet::ServerboundPickItemPacket,
0x1a: serverbound_pick_item_packet::ServerboundPickItemPacket, 0x1a: serverbound_place_recipe_packet::ServerboundPlaceRecipePacket,
0x1b: serverbound_place_recipe_packet::ServerboundPlaceRecipePacket, 0x1b: serverbound_player_abilities_packet::ServerboundPlayerAbilitiesPacket,
0x1c: serverbound_player_abilities_packet::ServerboundPlayerAbilitiesPacket, 0x1c: serverbound_player_action_packet::ServerboundPlayerActionPacket,
0x1d: serverbound_player_action_packet::ServerboundPlayerActionPacket, 0x1d: serverbound_player_command_packet::ServerboundPlayerCommandPacket,
0x1e: serverbound_player_command_packet::ServerboundPlayerCommandPacket, 0x1e: serverbound_player_input_packet::ServerboundPlayerInputPacket,
0x1f: serverbound_player_input_packet::ServerboundPlayerInputPacket, 0x1f: serverbound_pong_packet::ServerboundPongPacket,
0x20: serverbound_pong_packet::ServerboundPongPacket, 0x20: serverbound_chat_session_update_packet::ServerboundChatSessionUpdatePacket,
0x21: serverbound_recipe_book_change_settings_packet::ServerboundRecipeBookChangeSettingsPacket, 0x21: serverbound_recipe_book_change_settings_packet::ServerboundRecipeBookChangeSettingsPacket,
0x22: serverbound_recipe_book_seen_recipe_packet::ServerboundRecipeBookSeenRecipePacket, 0x22: serverbound_recipe_book_seen_recipe_packet::ServerboundRecipeBookSeenRecipePacket,
0x23: serverbound_rename_item_packet::ServerboundRenameItemPacket, 0x23: serverbound_rename_item_packet::ServerboundRenameItemPacket,
@ -227,100 +226,99 @@ declare_state_packets!(
0x09: clientbound_block_update_packet::ClientboundBlockUpdatePacket, 0x09: clientbound_block_update_packet::ClientboundBlockUpdatePacket,
0x0a: clientbound_boss_event_packet::ClientboundBossEventPacket, 0x0a: clientbound_boss_event_packet::ClientboundBossEventPacket,
0x0b: clientbound_change_difficulty_packet::ClientboundChangeDifficultyPacket, 0x0b: clientbound_change_difficulty_packet::ClientboundChangeDifficultyPacket,
0x0c: clientbound_chat_preview_packet::ClientboundChatPreviewPacket, 0x0d: clientbound_command_suggestions_packet::ClientboundCommandSuggestionsPacket,
0x0e: clientbound_command_suggestions_packet::ClientboundCommandSuggestionsPacket, 0x0e: clientbound_commands_packet::ClientboundCommandsPacket,
0x0f: clientbound_commands_packet::ClientboundCommandsPacket, 0x0f: clientbound_container_close_packet::ClientboundContainerClosePacket,
0x10: clientbound_container_close_packet::ClientboundContainerClosePacket, 0x10: clientbound_container_set_content_packet::ClientboundContainerSetContentPacket,
0x11: clientbound_container_set_content_packet::ClientboundContainerSetContentPacket, 0x11: clientbound_container_set_data_packet::ClientboundContainerSetDataPacket,
0x12: clientbound_container_set_data_packet::ClientboundContainerSetDataPacket, 0x12: clientbound_container_set_slot_packet::ClientboundContainerSetSlotPacket,
0x13: clientbound_container_set_slot_packet::ClientboundContainerSetSlotPacket, 0x13: clientbound_cooldown_packet::ClientboundCooldownPacket,
0x14: clientbound_cooldown_packet::ClientboundCooldownPacket, 0x14: clientbound_custom_chat_completions_packet::ClientboundCustomChatCompletionsPacket,
0x15: clientbound_custom_chat_completions_packet::ClientboundCustomChatCompletionsPacket, 0x15: clientbound_custom_payload_packet::ClientboundCustomPayloadPacket,
0x16: clientbound_custom_payload_packet::ClientboundCustomPayloadPacket, 0x16: clientbound_delete_chat_packet::ClientboundDeleteChatPacket,
0x17: clientbound_custom_sound_packet::ClientboundCustomSoundPacket, 0x17: clientbound_disconnect_packet::ClientboundDisconnectPacket,
0x18: clientbound_delete_chat_packet::ClientboundDeleteChatPacket, 0x18: clientbound_disguised_chat_packet::ClientboundDisguisedChatPacket,
0x19: clientbound_disconnect_packet::ClientboundDisconnectPacket, 0x19: clientbound_entity_event_packet::ClientboundEntityEventPacket,
0x1a: clientbound_entity_event_packet::ClientboundEntityEventPacket, 0x1a: clientbound_explode_packet::ClientboundExplodePacket,
0x1b: clientbound_explode_packet::ClientboundExplodePacket, 0x1b: clientbound_forget_level_chunk_packet::ClientboundForgetLevelChunkPacket,
0x1c: clientbound_forget_level_chunk_packet::ClientboundForgetLevelChunkPacket, 0x1c: clientbound_game_event_packet::ClientboundGameEventPacket,
0x1d: clientbound_game_event_packet::ClientboundGameEventPacket, 0x1d: clientbound_horse_screen_open_packet::ClientboundHorseScreenOpenPacket,
0x1e: clientbound_horse_screen_open_packet::ClientboundHorseScreenOpenPacket, 0x1e: clientbound_initialize_border_packet::ClientboundInitializeBorderPacket,
0x1f: clientbound_initialize_border_packet::ClientboundInitializeBorderPacket, 0x1f: clientbound_keep_alive_packet::ClientboundKeepAlivePacket,
0x20: clientbound_keep_alive_packet::ClientboundKeepAlivePacket, 0x20: clientbound_level_chunk_with_light_packet::ClientboundLevelChunkWithLightPacket,
0x21: clientbound_level_chunk_with_light_packet::ClientboundLevelChunkWithLightPacket, 0x21: clientbound_level_event_packet::ClientboundLevelEventPacket,
0x22: clientbound_level_event_packet::ClientboundLevelEventPacket, 0x22: clientbound_level_particles_packet::ClientboundLevelParticlesPacket,
0x23: clientbound_level_particles_packet::ClientboundLevelParticlesPacket, 0x23: clientbound_light_update_packet::ClientboundLightUpdatePacket,
0x24: clientbound_light_update_packet::ClientboundLightUpdatePacket, 0x24: clientbound_login_packet::ClientboundLoginPacket,
0x25: clientbound_login_packet::ClientboundLoginPacket, 0x25: clientbound_map_item_data_packet::ClientboundMapItemDataPacket,
0x26: clientbound_map_item_data_packet::ClientboundMapItemDataPacket, 0x26: clientbound_merchant_offers_packet::ClientboundMerchantOffersPacket,
0x27: clientbound_merchant_offers_packet::ClientboundMerchantOffersPacket, 0x27: clientbound_move_entity_pos_packet::ClientboundMoveEntityPosPacket,
0x28: clientbound_move_entity_pos_packet::ClientboundMoveEntityPosPacket, 0x28: clientbound_move_entity_pos_rot_packet::ClientboundMoveEntityPosRotPacket,
0x29: clientbound_move_entity_pos_rot_packet::ClientboundMoveEntityPosRotPacket, 0x29: clientbound_move_entity_rot_packet::ClientboundMoveEntityRotPacket,
0x2a: clientbound_move_entity_rot_packet::ClientboundMoveEntityRotPacket, 0x2a: clientbound_move_vehicle_packet::ClientboundMoveVehiclePacket,
0x2b: clientbound_move_vehicle_packet::ClientboundMoveVehiclePacket, 0x2b: clientbound_open_book_packet::ClientboundOpenBookPacket,
0x2c: clientbound_open_book_packet::ClientboundOpenBookPacket, 0x2c: clientbound_open_screen_packet::ClientboundOpenScreenPacket,
0x2d: clientbound_open_screen_packet::ClientboundOpenScreenPacket, 0x2d: clientbound_open_sign_editor_packet::ClientboundOpenSignEditorPacket,
0x2e: clientbound_open_sign_editor_packet::ClientboundOpenSignEditorPacket, 0x2e: clientbound_ping_packet::ClientboundPingPacket,
0x2f: clientbound_ping_packet::ClientboundPingPacket, 0x2f: clientbound_place_ghost_recipe_packet::ClientboundPlaceGhostRecipePacket,
0x30: clientbound_place_ghost_recipe_packet::ClientboundPlaceGhostRecipePacket, 0x30: clientbound_player_abilities_packet::ClientboundPlayerAbilitiesPacket,
0x31: clientbound_player_abilities_packet::ClientboundPlayerAbilitiesPacket, 0x31: clientbound_player_chat_packet::ClientboundPlayerChatPacket,
0x32: clientbound_player_chat_header_packet::ClientboundPlayerChatHeaderPacket, 0x32: clientbound_player_combat_end_packet::ClientboundPlayerCombatEndPacket,
0x33: clientbound_player_chat_packet::ClientboundPlayerChatPacket, 0x33: clientbound_player_combat_enter_packet::ClientboundPlayerCombatEnterPacket,
0x34: clientbound_player_combat_end_packet::ClientboundPlayerCombatEndPacket, 0x34: clientbound_player_combat_kill_packet::ClientboundPlayerCombatKillPacket,
0x35: clientbound_player_combat_enter_packet::ClientboundPlayerCombatEnterPacket, 0x35: clientbound_player_info_remove_packet::ClientboundPlayerInfoRemovePacket,
0x36: clientbound_player_combat_kill_packet::ClientboundPlayerCombatKillPacket, 0x36: clientbound_player_info_update_packet::ClientboundPlayerInfoUpdatePacket,
0x37: clientbound_player_info_packet::ClientboundPlayerInfoPacket, 0x37: clientbound_player_look_at_packet::ClientboundPlayerLookAtPacket,
0x38: clientbound_player_look_at_packet::ClientboundPlayerLookAtPacket, 0x38: clientbound_player_position_packet::ClientboundPlayerPositionPacket,
0x39: clientbound_player_position_packet::ClientboundPlayerPositionPacket, 0x39: clientbound_recipe_packet::ClientboundRecipePacket,
0x3a: clientbound_recipe_packet::ClientboundRecipePacket, 0x3a: clientbound_remove_entities_packet::ClientboundRemoveEntitiesPacket,
0x3b: clientbound_remove_entities_packet::ClientboundRemoveEntitiesPacket, 0x3b: clientbound_remove_mob_effect_packet::ClientboundRemoveMobEffectPacket,
0x3c: clientbound_remove_mob_effect_packet::ClientboundRemoveMobEffectPacket, 0x3c: clientbound_resource_pack_packet::ClientboundResourcePackPacket,
0x3d: clientbound_resource_pack_packet::ClientboundResourcePackPacket, 0x3d: clientbound_respawn_packet::ClientboundRespawnPacket,
0x3e: clientbound_respawn_packet::ClientboundRespawnPacket, 0x3e: clientbound_rotate_head_packet::ClientboundRotateHeadPacket,
0x3f: clientbound_rotate_head_packet::ClientboundRotateHeadPacket, 0x3f: clientbound_section_blocks_update_packet::ClientboundSectionBlocksUpdatePacket,
0x40: clientbound_section_blocks_update_packet::ClientboundSectionBlocksUpdatePacket, 0x40: clientbound_select_advancements_tab_packet::ClientboundSelectAdvancementsTabPacket,
0x41: clientbound_select_advancements_tab_packet::ClientboundSelectAdvancementsTabPacket, 0x41: clientbound_server_data_packet::ClientboundServerDataPacket,
0x42: clientbound_server_data_packet::ClientboundServerDataPacket, 0x42: clientbound_set_action_bar_text_packet::ClientboundSetActionBarTextPacket,
0x43: clientbound_set_action_bar_text_packet::ClientboundSetActionBarTextPacket, 0x43: clientbound_set_border_center_packet::ClientboundSetBorderCenterPacket,
0x44: clientbound_set_border_center_packet::ClientboundSetBorderCenterPacket, 0x44: clientbound_set_border_lerp_size_packet::ClientboundSetBorderLerpSizePacket,
0x45: clientbound_set_border_lerp_size_packet::ClientboundSetBorderLerpSizePacket, 0x45: clientbound_set_border_size_packet::ClientboundSetBorderSizePacket,
0x46: clientbound_set_border_size_packet::ClientboundSetBorderSizePacket, 0x46: clientbound_set_border_warning_delay_packet::ClientboundSetBorderWarningDelayPacket,
0x47: clientbound_set_border_warning_delay_packet::ClientboundSetBorderWarningDelayPacket, 0x47: clientbound_set_border_warning_distance_packet::ClientboundSetBorderWarningDistancePacket,
0x48: clientbound_set_border_warning_distance_packet::ClientboundSetBorderWarningDistancePacket, 0x48: clientbound_set_camera_packet::ClientboundSetCameraPacket,
0x49: clientbound_set_camera_packet::ClientboundSetCameraPacket, 0x49: clientbound_set_carried_item_packet::ClientboundSetCarriedItemPacket,
0x4a: clientbound_set_carried_item_packet::ClientboundSetCarriedItemPacket, 0x4a: clientbound_set_chunk_cache_center_packet::ClientboundSetChunkCacheCenterPacket,
0x4b: clientbound_set_chunk_cache_center_packet::ClientboundSetChunkCacheCenterPacket, 0x4b: clientbound_set_chunk_cache_radius_packet::ClientboundSetChunkCacheRadiusPacket,
0x4c: clientbound_set_chunk_cache_radius_packet::ClientboundSetChunkCacheRadiusPacket, 0x4c: clientbound_set_default_spawn_position_packet::ClientboundSetDefaultSpawnPositionPacket,
0x4d: clientbound_set_default_spawn_position_packet::ClientboundSetDefaultSpawnPositionPacket, 0x4d: clientbound_set_display_objective_packet::ClientboundSetDisplayObjectivePacket,
0x4e: clientbound_set_display_chat_preview_packet::ClientboundSetDisplayChatPreviewPacket, 0x4e: clientbound_set_entity_data_packet::ClientboundSetEntityDataPacket,
0x4f: clientbound_set_display_objective_packet::ClientboundSetDisplayObjectivePacket, 0x4f: clientbound_set_entity_link_packet::ClientboundSetEntityLinkPacket,
0x50: clientbound_set_entity_data_packet::ClientboundSetEntityDataPacket, 0x50: clientbound_set_entity_motion_packet::ClientboundSetEntityMotionPacket,
0x51: clientbound_set_entity_link_packet::ClientboundSetEntityLinkPacket, 0x51: clientbound_set_equipment_packet::ClientboundSetEquipmentPacket,
0x52: clientbound_set_entity_motion_packet::ClientboundSetEntityMotionPacket, 0x52: clientbound_set_experience_packet::ClientboundSetExperiencePacket,
0x53: clientbound_set_equipment_packet::ClientboundSetEquipmentPacket, 0x53: clientbound_set_health_packet::ClientboundSetHealthPacket,
0x54: clientbound_set_experience_packet::ClientboundSetExperiencePacket, 0x54: clientbound_set_objective_packet::ClientboundSetObjectivePacket,
0x55: clientbound_set_health_packet::ClientboundSetHealthPacket, 0x55: clientbound_set_passengers_packet::ClientboundSetPassengersPacket,
0x56: clientbound_set_objective_packet::ClientboundSetObjectivePacket, 0x56: clientbound_set_player_team_packet::ClientboundSetPlayerTeamPacket,
0x57: clientbound_set_passengers_packet::ClientboundSetPassengersPacket, 0x57: clientbound_set_score_packet::ClientboundSetScorePacket,
0x58: clientbound_set_player_team_packet::ClientboundSetPlayerTeamPacket, 0x58: clientbound_set_simulation_distance_packet::ClientboundSetSimulationDistancePacket,
0x59: clientbound_set_score_packet::ClientboundSetScorePacket, 0x59: clientbound_set_subtitle_text_packet::ClientboundSetSubtitleTextPacket,
0x5a: clientbound_set_simulation_distance_packet::ClientboundSetSimulationDistancePacket, 0x5a: clientbound_set_time_packet::ClientboundSetTimePacket,
0x5b: clientbound_set_subtitle_text_packet::ClientboundSetSubtitleTextPacket, 0x5b: clientbound_set_title_text_packet::ClientboundSetTitleTextPacket,
0x5c: clientbound_set_time_packet::ClientboundSetTimePacket, 0x5c: clientbound_set_titles_animation_packet::ClientboundSetTitlesAnimationPacket,
0x5d: clientbound_set_title_text_packet::ClientboundSetTitleTextPacket, 0x5d: clientbound_sound_entity_packet::ClientboundSoundEntityPacket,
0x5e: clientbound_set_titles_animation_packet::ClientboundSetTitlesAnimationPacket, 0x5e: clientbound_sound_packet::ClientboundSoundPacket,
0x5f: clientbound_sound_entity_packet::ClientboundSoundEntityPacket, 0x5f: clientbound_stop_sound_packet::ClientboundStopSoundPacket,
0x60: clientbound_sound_packet::ClientboundSoundPacket, 0x60: clientbound_system_chat_packet::ClientboundSystemChatPacket,
0x61: clientbound_stop_sound_packet::ClientboundStopSoundPacket, 0x61: clientbound_tab_list_packet::ClientboundTabListPacket,
0x62: clientbound_system_chat_packet::ClientboundSystemChatPacket, 0x62: clientbound_tag_query_packet::ClientboundTagQueryPacket,
0x63: clientbound_tab_list_packet::ClientboundTabListPacket, 0x63: clientbound_take_item_entity_packet::ClientboundTakeItemEntityPacket,
0x64: clientbound_tag_query_packet::ClientboundTagQueryPacket, 0x64: clientbound_teleport_entity_packet::ClientboundTeleportEntityPacket,
0x65: clientbound_take_item_entity_packet::ClientboundTakeItemEntityPacket, 0x65: clientbound_update_advancements_packet::ClientboundUpdateAdvancementsPacket,
0x66: clientbound_teleport_entity_packet::ClientboundTeleportEntityPacket, 0x66: clientbound_update_attributes_packet::ClientboundUpdateAttributesPacket,
0x67: clientbound_update_advancements_packet::ClientboundUpdateAdvancementsPacket, 0x67: clientbound_update_enabled_features_packet::ClientboundUpdateEnabledFeaturesPacket,
0x68: clientbound_update_attributes_packet::ClientboundUpdateAttributesPacket, 0x68: clientbound_update_mob_effect_packet::ClientboundUpdateMobEffectPacket,
0x69: clientbound_update_mob_effect_packet::ClientboundUpdateMobEffectPacket, 0x69: clientbound_update_recipes_packet::ClientboundUpdateRecipesPacket,
0x6a: clientbound_update_recipes_packet::ClientboundUpdateRecipesPacket, 0x6a: clientbound_update_tags_packet::ClientboundUpdateTagsPacket,
0x6b: clientbound_update_tags_packet::ClientboundUpdateTagsPacket,
} }
); );

View file

@ -1,8 +1,8 @@
use crate::packets::game::clientbound_player_chat_packet::LastSeenMessagesUpdate;
use azalea_buf::McBuf; use azalea_buf::McBuf;
use azalea_protocol_macros::ServerboundGamePacket; use azalea_protocol_macros::ServerboundGamePacket;
#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] #[derive(Clone, Debug, McBuf, ServerboundGamePacket)]
pub struct ServerboundChatAckPacket { pub struct ServerboundChatAckPacket {
pub last_seen_messages: LastSeenMessagesUpdate, #[var]
pub offset: u32,
} }

View file

@ -1,17 +1,14 @@
use super::serverbound_chat_packet::LastSeenMessagesUpdate;
use azalea_buf::McBuf; use azalea_buf::McBuf;
use azalea_crypto::MessageSignature; use azalea_crypto::MessageSignature;
use azalea_protocol_macros::ServerboundGamePacket; use azalea_protocol_macros::ServerboundGamePacket;
use super::clientbound_player_chat_packet::LastSeenMessagesUpdate;
#[derive(Clone, Debug, McBuf, ServerboundGamePacket)] #[derive(Clone, Debug, McBuf, ServerboundGamePacket)]
pub struct ServerboundChatCommandPacket { pub struct ServerboundChatCommandPacket {
pub command: String, pub command: String,
// TODO: Choose a real timestamp type
pub timestamp: u64, pub timestamp: u64,
pub salt: u64, pub salt: u64,
pub argument_signatures: Vec<ArgumentSignature>, pub argument_signatures: Vec<ArgumentSignature>,
pub signed_preview: bool,
pub last_seen_messages: LastSeenMessagesUpdate, pub last_seen_messages: LastSeenMessagesUpdate,
} }

View file

@ -1,5 +1,5 @@
use crate::packets::game::clientbound_player_chat_packet::LastSeenMessagesUpdate;
use azalea_buf::McBuf; use azalea_buf::McBuf;
use azalea_core::FixedBitSet;
use azalea_crypto::MessageSignature; use azalea_crypto::MessageSignature;
use azalea_protocol_macros::ServerboundGamePacket; use azalea_protocol_macros::ServerboundGamePacket;
@ -8,7 +8,13 @@ pub struct ServerboundChatPacket {
pub message: String, pub message: String,
pub timestamp: u64, pub timestamp: u64,
pub salt: u64, pub salt: u64,
pub signature: MessageSignature, pub signature: Option<MessageSignature>,
pub signed_preview: bool,
pub last_seen_messages: LastSeenMessagesUpdate, pub last_seen_messages: LastSeenMessagesUpdate,
} }
#[derive(Clone, Debug, McBuf, Default)]
pub struct LastSeenMessagesUpdate {
#[var]
pub offset: u32,
pub acknowledged: FixedBitSet<20>,
}

View file

@ -0,0 +1,21 @@
use azalea_buf::McBuf;
use azalea_protocol_macros::ServerboundGamePacket;
use uuid::Uuid;
#[derive(Clone, Debug, McBuf, ServerboundGamePacket)]
pub struct ServerboundChatSessionUpdatePacket {
pub chat_session: RemoteChatSessionData,
}
#[derive(Clone, Debug, PartialEq, Eq, McBuf)]
pub struct RemoteChatSessionData {
pub session_id: Uuid,
pub profile_public_key: ProfilePublicKeyData,
}
#[derive(Clone, Debug, McBuf, PartialEq, Eq)]
pub struct ProfilePublicKeyData {
pub expires_at: u64,
pub key: Vec<u8>,
pub key_signature: Vec<u8>,
}

View file

@ -2,20 +2,12 @@ use azalea_buf::McBuf;
use azalea_protocol_macros::ServerboundLoginPacket; use azalea_protocol_macros::ServerboundLoginPacket;
use uuid::Uuid; use uuid::Uuid;
#[derive(Clone, Debug, ServerboundLoginPacket, McBuf, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq, McBuf, ServerboundLoginPacket)]
pub struct ServerboundHelloPacket { pub struct ServerboundHelloPacket {
pub username: String, pub name: String,
pub public_key: Option<ProfilePublicKeyData>,
pub profile_id: Option<Uuid>, pub profile_id: Option<Uuid>,
} }
#[derive(Clone, Debug, McBuf, PartialEq, Eq)]
pub struct ProfilePublicKeyData {
pub expires_at: u64,
pub key: Vec<u8>,
pub key_signature: Vec<u8>,
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::io::Cursor; use std::io::Cursor;
@ -26,9 +18,8 @@ mod tests {
#[test] #[test]
fn test_read_write() { fn test_read_write() {
let packet = ServerboundHelloPacket { let packet = ServerboundHelloPacket {
username: "test".to_string(), name: "test".to_string(),
public_key: None, profile_id: Some(Uuid::nil()),
profile_id: Some(Uuid::from_u128(0)),
}; };
let mut buf: Vec<u8> = Vec::new(); let mut buf: Vec<u8> = Vec::new();
packet.write_into(&mut buf).unwrap(); packet.write_into(&mut buf).unwrap();

View file

@ -1,47 +1,8 @@
use azalea_buf::{BufReadError, McBuf}; use azalea_buf::McBuf;
use azalea_crypto::SaltSignaturePair;
use azalea_protocol_macros::ServerboundLoginPacket; use azalea_protocol_macros::ServerboundLoginPacket;
use std::io::{Cursor, Write};
use azalea_buf::{McBufReadable, McBufWritable};
#[derive(Clone, Debug, McBuf, ServerboundLoginPacket)] #[derive(Clone, Debug, McBuf, ServerboundLoginPacket)]
pub struct ServerboundKeyPacket { pub struct ServerboundKeyPacket {
pub key_bytes: Vec<u8>, pub key_bytes: Vec<u8>,
pub nonce_or_salt_signature: NonceOrSaltSignature, pub encrypted_challenge: Vec<u8>,
}
#[derive(Clone, Debug)]
pub enum NonceOrSaltSignature {
Nonce(Vec<u8>),
SaltSignature(SaltSignaturePair),
}
impl McBufReadable for NonceOrSaltSignature {
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
let is_nonce = bool::read_from(buf)?;
if is_nonce {
Ok(NonceOrSaltSignature::Nonce(Vec::<u8>::read_from(buf)?))
} else {
Ok(NonceOrSaltSignature::SaltSignature(
SaltSignaturePair::read_from(buf)?,
))
}
}
}
impl McBufWritable for NonceOrSaltSignature {
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
match self {
NonceOrSaltSignature::Nonce(nonce) => {
bool::write_into(&true, buf)?;
nonce.write_into(buf)?;
}
NonceOrSaltSignature::SaltSignature(salt_signature) => {
bool::write_into(&false, buf)?;
salt_signature.write_into(buf)?;
}
}
Ok(())
}
} }

View file

@ -9,7 +9,7 @@ use std::io::{Cursor, Write};
// TODO: rename the packet files to just like clientbound_add_entity instead of clientbound_add_entity_packet // TODO: rename the packet files to just like clientbound_add_entity instead of clientbound_add_entity_packet
pub const PROTOCOL_VERSION: u32 = 760; pub const PROTOCOL_VERSION: u32 = 761;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ConnectionProtocol { pub enum ConnectionProtocol {
@ -39,7 +39,7 @@ where
fn id(&self) -> u32; fn id(&self) -> u32;
/// Read a packet by its id, ConnectionProtocol, and flow /// Read a packet by its id, ConnectionProtocol, and flow
fn read(id: u32, buf: &mut Cursor<&[u8]>) -> Result<Self, ReadPacketError>; fn read(id: u32, buf: &mut Cursor<&[u8]>) -> Result<Self, Box<ReadPacketError>>;
fn write(&self, buf: &mut impl Write) -> Result<(), std::io::Error>; fn write(&self, buf: &mut impl Write) -> Result<(), std::io::Error>;
} }

View file

@ -9,6 +9,7 @@ use bytes::BytesMut;
use flate2::read::ZlibDecoder; use flate2::read::ZlibDecoder;
use futures::StreamExt; use futures::StreamExt;
use log::{log_enabled, trace}; use log::{log_enabled, trace};
use std::backtrace::Backtrace;
use std::{ use std::{
fmt::Debug, fmt::Debug,
io::{Cursor, Read}, io::{Cursor, Read},
@ -19,10 +20,11 @@ use tokio_util::codec::{BytesCodec, FramedRead};
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum ReadPacketError { pub enum ReadPacketError {
#[error("Error reading packet {packet_name} ({packet_id}): {source}")] #[error("Error reading packet {packet_name} (id {packet_id}): {source}")]
Parse { Parse {
packet_id: u32, packet_id: u32,
packet_name: String, packet_name: String,
backtrace: Box<Backtrace>,
source: BufReadError, source: BufReadError,
}, },
#[error("Unknown packet id {id} in state {state_name}")] #[error("Unknown packet id {id} in state {state_name}")]
@ -84,7 +86,7 @@ fn parse_frame(buffer: &mut BytesMut) -> Result<BytesMut, FrameSplitterError> {
let length = match u32::var_read_from(&mut buffer_copy) { let length = match u32::var_read_from(&mut buffer_copy) {
Ok(length) => length as usize, Ok(length) => length as usize,
Err(err) => match err { Err(err) => match err {
BufReadError::Io(io_err) => return Err(FrameSplitterError::Io { source: io_err }), BufReadError::Io { source } => return Err(FrameSplitterError::Io { source }),
_ => return Err(err.into()), _ => return Err(err.into()),
}, },
}; };
@ -126,7 +128,7 @@ fn frame_splitter(buffer: &mut BytesMut) -> Result<Option<Vec<u8>>, FrameSplitte
fn packet_decoder<P: ProtocolPacket + Debug>( fn packet_decoder<P: ProtocolPacket + Debug>(
stream: &mut Cursor<&[u8]>, stream: &mut Cursor<&[u8]>,
) -> Result<P, ReadPacketError> { ) -> Result<P, Box<ReadPacketError>> {
// Packet ID // Packet ID
let packet_id = let packet_id =
u32::var_read_from(stream).map_err(|e| ReadPacketError::ReadPacketId { source: e })?; u32::var_read_from(stream).map_err(|e| ReadPacketError::ReadPacketId { source: e })?;
@ -207,13 +209,13 @@ pub async fn read_packet<'a, P: ProtocolPacket + Debug, R>(
buffer: &mut BytesMut, buffer: &mut BytesMut,
compression_threshold: Option<u32>, compression_threshold: Option<u32>,
cipher: &mut Option<Aes128CfbDec>, cipher: &mut Option<Aes128CfbDec>,
) -> Result<P, ReadPacketError> ) -> Result<P, Box<ReadPacketError>>
where where
R: AsyncRead + std::marker::Unpin + std::marker::Send + std::marker::Sync, R: AsyncRead + std::marker::Unpin + std::marker::Send + std::marker::Sync,
{ {
let mut framed = FramedRead::new(stream, BytesCodec::new()); let mut framed = FramedRead::new(stream, BytesCodec::new());
let mut buf = loop { let mut buf = loop {
if let Some(buf) = frame_splitter(buffer)? { if let Some(buf) = frame_splitter(buffer).map_err(ReadPacketError::from)? {
// we got a full packet!! // we got a full packet!!
break buf; break buf;
} else { } else {
@ -222,7 +224,7 @@ where
// if we were given a cipher, decrypt the packet // if we were given a cipher, decrypt the packet
if let Some(message) = framed.next().await { if let Some(message) = framed.next().await {
let mut bytes = message?; let mut bytes = message.map_err(ReadPacketError::from)?;
if let Some(cipher) = cipher { if let Some(cipher) = cipher {
azalea_crypto::decrypt_packet(cipher, &mut bytes); azalea_crypto::decrypt_packet(cipher, &mut bytes);
@ -230,12 +232,13 @@ where
buffer.extend_from_slice(&bytes); buffer.extend_from_slice(&bytes);
} else { } else {
return Err(ReadPacketError::ConnectionClosed); return Err(Box::new(ReadPacketError::ConnectionClosed));
}; };
}; };
if let Some(compression_threshold) = compression_threshold { if let Some(compression_threshold) = compression_threshold {
buf = compression_decoder(&mut Cursor::new(&buf[..]), compression_threshold)?; buf = compression_decoder(&mut Cursor::new(&buf[..]), compression_threshold)
.map_err(ReadPacketError::from)?;
} }
if log_enabled!(log::Level::Trace) { if log_enabled!(log::Level::Trace) {
@ -255,38 +258,38 @@ where
Ok(packet) Ok(packet)
} }
#[cfg(test)] // #[cfg(test)]
mod tests { // mod tests {
use super::*; // use super::*;
use crate::packets::game::{clientbound_player_chat_packet::ChatType, ClientboundGamePacket}; // use crate::packets::game::{clientbound_player_chat_packet::ChatType, ClientboundGamePacket};
use std::io::Cursor; // use std::io::Cursor;
#[tokio::test] // #[tokio::test]
async fn test_read_packet() { // async fn test_read_packet() {
let mut buf: Cursor<&[u8]> = Cursor::new(&[ // let mut buf: Cursor<&[u8]> = Cursor::new(&[
51, 0, 12, 177, 250, 155, 132, 106, 60, 218, 161, 217, 90, 157, 105, 57, 206, 20, 0, 5, // 51, 0, 12, 177, 250, 155, 132, 106, 60, 218, 161, 217, 90, 157, 105, 57, 206, 20, 0, 5,
104, 101, 108, 108, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 116, // 104, 101, 108, 108, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 116,
123, 34, 101, 120, 116, 114, 97, 34, 58, 91, 123, 34, 99, 111, 108, 111, 114, 34, 58, // 123, 34, 101, 120, 116, 114, 97, 34, 58, 91, 123, 34, 99, 111, 108, 111, 114, 34, 58,
34, 103, 114, 97, 121, 34, 44, 34, 116, 101, 120, 116, 34, 58, 34, 91, 77, 69, 77, 66, // 34, 103, 114, 97, 121, 34, 44, 34, 116, 101, 120, 116, 34, 58, 34, 91, 77, 69, 77, 66,
69, 82, 93, 32, 112, 108, 97, 121, 101, 114, 49, 34, 125, 44, 123, 34, 116, 101, 120, // 69, 82, 93, 32, 112, 108, 97, 121, 101, 114, 49, 34, 125, 44, 123, 34, 116, 101, 120,
116, 34, 58, 34, 32, 34, 125, 44, 123, 34, 99, 111, 108, 111, 114, 34, 58, 34, 103, // 116, 34, 58, 34, 32, 34, 125, 44, 123, 34, 99, 111, 108, 111, 114, 34, 58, 34, 103,
114, 97, 121, 34, 44, 34, 116, 101, 120, 116, 34, 58, 34, 92, 117, 48, 48, 51, 101, 32, // 114, 97, 121, 34, 44, 34, 116, 101, 120, 116, 34, 58, 34, 92, 117, 48, 48, 51, 101, 32,
104, 101, 108, 108, 111, 34, 125, 93, 44, 34, 116, 101, 120, 116, 34, 58, 34, 34, 125, // 104, 101, 108, 108, 111, 34, 125, 93, 44, 34, 116, 101, 120, 116, 34, 58, 34, 34, 125,
0, 7, 64, 123, 34, 101, 120, 116, 114, 97, 34, 58, 91, 123, 34, 99, 111, 108, 111, 114, // 0, 7, 64, 123, 34, 101, 120, 116, 114, 97, 34, 58, 91, 123, 34, 99, 111, 108, 111, 114,
34, 58, 34, 103, 114, 97, 121, 34, 44, 34, 116, 101, 120, 116, 34, 58, 34, 91, 77, 69, // 34, 58, 34, 103, 114, 97, 121, 34, 44, 34, 116, 101, 120, 116, 34, 58, 34, 91, 77, 69,
77, 66, 69, 82, 93, 32, 112, 108, 97, 121, 101, 114, 49, 34, 125, 93, 44, 34, 116, 101, // 77, 66, 69, 82, 93, 32, 112, 108, 97, 121, 101, 114, 49, 34, 125, 93, 44, 34, 116, 101,
120, 116, 34, 58, 34, 34, 125, 0, // 120, 116, 34, 58, 34, 34, 125, 0,
]); // ]);
let packet = packet_decoder::<ClientboundGamePacket>(&mut buf).unwrap(); // let packet = packet_decoder::<ClientboundGamePacket>(&mut buf).unwrap();
match &packet { // match &packet {
ClientboundGamePacket::PlayerChat(m) => { // ClientboundGamePacket::PlayerChat(m) => {
assert_eq!( // assert_eq!(
m.chat_type.chat_type, // m.chat_type.chat_type,
ChatType::Chat, // ChatType::Chat,
"Enums should default if they're invalid" // "Enums should default if they're invalid"
); // );
} // }
_ => panic!("Wrong packet type"), // _ => panic!("Wrong packet type"),
} // }
} // }
} // }

View file

@ -4,6 +4,7 @@ use crate::{packets::ProtocolPacket, read::MAXIMUM_UNCOMPRESSED_LENGTH};
use async_compression::tokio::bufread::ZlibEncoder; use async_compression::tokio::bufread::ZlibEncoder;
use azalea_buf::McBufVarWritable; use azalea_buf::McBufVarWritable;
use azalea_crypto::Aes128CfbEnc; use azalea_crypto::Aes128CfbEnc;
use log::trace;
use std::fmt::Debug; use std::fmt::Debug;
use thiserror::Error; use thiserror::Error;
use tokio::io::{AsyncReadExt, AsyncWrite, AsyncWriteExt}; use tokio::io::{AsyncReadExt, AsyncWrite, AsyncWriteExt};
@ -81,6 +82,7 @@ where
P: ProtocolPacket + Debug, P: ProtocolPacket + Debug,
W: AsyncWrite + Unpin + Send, W: AsyncWrite + Unpin + Send,
{ {
trace!("Sending packet: {:?}", packet);
let mut buf = packet_encoder(packet).unwrap(); let mut buf = packet_encoder(packet).unwrap();
if let Some(threshold) = compression_threshold { if let Some(threshold) = compression_threshold {
buf = compression_encoder(&buf, threshold).await.unwrap(); buf = compression_encoder(&buf, threshold).await.unwrap();

View file

@ -95,6 +95,18 @@ pub fn registry(input: TokenStream) -> TokenStream {
id <= #max_id id <= #max_id
} }
} }
impl Registry for #name {
fn from_u32(value: u32) -> Option<Self> {
if Self::is_valid_id(value) {
Some(unsafe { Self::from_u32_unchecked(value) })
} else {
None
}
}
fn to_u32(&self) -> u32 {
*self as u32
}
}
}); });
let doc_0 = format!("Safely transmutes a u32 to a {name}."); let doc_0 = format!("Safely transmutes a u32 to a {name}.");
@ -105,8 +117,8 @@ pub fn registry(input: TokenStream) -> TokenStream {
#[doc = #doc_0] #[doc = #doc_0]
fn try_from(id: u32) -> Result<Self, Self::Error> { fn try_from(id: u32) -> Result<Self, Self::Error> {
if Self::is_valid_id(id) { if let Some(value) = Self::from_u32(id) {
Ok(unsafe { Self::from_u32_unchecked(id) }) Ok(value)
} else { } else {
Err(()) Err(())
} }

View file

@ -1,4 +1,41 @@
// This file is automatically generated in codegen/lib/code/registry.py
use azalea_buf::{BufReadError, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable};
use azalea_registry_macros::registry; use azalea_registry_macros::registry;
use std::io::{Cursor, Write};
pub trait Registry
where
Self: Sized,
{
fn from_u32(value: u32) -> Option<Self>;
fn to_u32(&self) -> u32;
}
/// A registry that might not be present. This is transmitted as a single
/// varint in the protocol.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct OptionalRegistry<T: Registry>(Option<T>);
impl<T: Registry> McBufReadable for OptionalRegistry<T> {
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
Ok(OptionalRegistry(match u32::var_read_from(buf)? {
0 => None,
value => Some(
T::from_u32(value - 1)
.ok_or(BufReadError::UnexpectedEnumVariant { id: value as i32 })?,
),
}))
}
}
impl<T: Registry> McBufWritable for OptionalRegistry<T> {
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
match &self.0 {
None => 0u32.var_write_into(buf),
Some(value) => (value.to_u32() + 1).var_write_into(buf),
}
}
}
registry!(Activity, { registry!(Activity, {
Core => "minecraft:core", Core => "minecraft:core",
@ -110,6 +147,8 @@ registry!(Block, {
AcaciaPlanks => "minecraft:acacia_planks", AcaciaPlanks => "minecraft:acacia_planks",
DarkOakPlanks => "minecraft:dark_oak_planks", DarkOakPlanks => "minecraft:dark_oak_planks",
MangrovePlanks => "minecraft:mangrove_planks", MangrovePlanks => "minecraft:mangrove_planks",
BambooPlanks => "minecraft:bamboo_planks",
BambooMosaic => "minecraft:bamboo_mosaic",
OakSapling => "minecraft:oak_sapling", OakSapling => "minecraft:oak_sapling",
SpruceSapling => "minecraft:spruce_sapling", SpruceSapling => "minecraft:spruce_sapling",
BirchSapling => "minecraft:birch_sapling", BirchSapling => "minecraft:birch_sapling",
@ -139,6 +178,7 @@ registry!(Block, {
MangroveLog => "minecraft:mangrove_log", MangroveLog => "minecraft:mangrove_log",
MangroveRoots => "minecraft:mangrove_roots", MangroveRoots => "minecraft:mangrove_roots",
MuddyMangroveRoots => "minecraft:muddy_mangrove_roots", MuddyMangroveRoots => "minecraft:muddy_mangrove_roots",
BambooBlock => "minecraft:bamboo_block",
StrippedSpruceLog => "minecraft:stripped_spruce_log", StrippedSpruceLog => "minecraft:stripped_spruce_log",
StrippedBirchLog => "minecraft:stripped_birch_log", StrippedBirchLog => "minecraft:stripped_birch_log",
StrippedJungleLog => "minecraft:stripped_jungle_log", StrippedJungleLog => "minecraft:stripped_jungle_log",
@ -146,6 +186,7 @@ registry!(Block, {
StrippedDarkOakLog => "minecraft:stripped_dark_oak_log", StrippedDarkOakLog => "minecraft:stripped_dark_oak_log",
StrippedOakLog => "minecraft:stripped_oak_log", StrippedOakLog => "minecraft:stripped_oak_log",
StrippedMangroveLog => "minecraft:stripped_mangrove_log", StrippedMangroveLog => "minecraft:stripped_mangrove_log",
StrippedBambooBlock => "minecraft:stripped_bamboo_block",
OakWood => "minecraft:oak_wood", OakWood => "minecraft:oak_wood",
SpruceWood => "minecraft:spruce_wood", SpruceWood => "minecraft:spruce_wood",
BirchWood => "minecraft:birch_wood", BirchWood => "minecraft:birch_wood",
@ -244,6 +285,7 @@ registry!(Block, {
Bricks => "minecraft:bricks", Bricks => "minecraft:bricks",
Tnt => "minecraft:tnt", Tnt => "minecraft:tnt",
Bookshelf => "minecraft:bookshelf", Bookshelf => "minecraft:bookshelf",
ChiseledBookshelf => "minecraft:chiseled_bookshelf",
MossyCobblestone => "minecraft:mossy_cobblestone", MossyCobblestone => "minecraft:mossy_cobblestone",
Obsidian => "minecraft:obsidian", Obsidian => "minecraft:obsidian",
Torch => "minecraft:torch", Torch => "minecraft:torch",
@ -268,6 +310,7 @@ registry!(Block, {
JungleSign => "minecraft:jungle_sign", JungleSign => "minecraft:jungle_sign",
DarkOakSign => "minecraft:dark_oak_sign", DarkOakSign => "minecraft:dark_oak_sign",
MangroveSign => "minecraft:mangrove_sign", MangroveSign => "minecraft:mangrove_sign",
BambooSign => "minecraft:bamboo_sign",
OakDoor => "minecraft:oak_door", OakDoor => "minecraft:oak_door",
Ladder => "minecraft:ladder", Ladder => "minecraft:ladder",
Rail => "minecraft:rail", Rail => "minecraft:rail",
@ -279,6 +322,27 @@ registry!(Block, {
JungleWallSign => "minecraft:jungle_wall_sign", JungleWallSign => "minecraft:jungle_wall_sign",
DarkOakWallSign => "minecraft:dark_oak_wall_sign", DarkOakWallSign => "minecraft:dark_oak_wall_sign",
MangroveWallSign => "minecraft:mangrove_wall_sign", MangroveWallSign => "minecraft:mangrove_wall_sign",
BambooWallSign => "minecraft:bamboo_wall_sign",
OakHangingSign => "minecraft:oak_hanging_sign",
SpruceHangingSign => "minecraft:spruce_hanging_sign",
BirchHangingSign => "minecraft:birch_hanging_sign",
AcaciaHangingSign => "minecraft:acacia_hanging_sign",
JungleHangingSign => "minecraft:jungle_hanging_sign",
DarkOakHangingSign => "minecraft:dark_oak_hanging_sign",
CrimsonHangingSign => "minecraft:crimson_hanging_sign",
WarpedHangingSign => "minecraft:warped_hanging_sign",
MangroveHangingSign => "minecraft:mangrove_hanging_sign",
BambooHangingSign => "minecraft:bamboo_hanging_sign",
OakWallHangingSign => "minecraft:oak_wall_hanging_sign",
SpruceWallHangingSign => "minecraft:spruce_wall_hanging_sign",
BirchWallHangingSign => "minecraft:birch_wall_hanging_sign",
AcaciaWallHangingSign => "minecraft:acacia_wall_hanging_sign",
JungleWallHangingSign => "minecraft:jungle_wall_hanging_sign",
DarkOakWallHangingSign => "minecraft:dark_oak_wall_hanging_sign",
MangroveWallHangingSign => "minecraft:mangrove_wall_hanging_sign",
CrimsonWallHangingSign => "minecraft:crimson_wall_hanging_sign",
WarpedWallHangingSign => "minecraft:warped_wall_hanging_sign",
BambooWallHangingSign => "minecraft:bamboo_wall_hanging_sign",
Lever => "minecraft:lever", Lever => "minecraft:lever",
StonePressurePlate => "minecraft:stone_pressure_plate", StonePressurePlate => "minecraft:stone_pressure_plate",
IronDoor => "minecraft:iron_door", IronDoor => "minecraft:iron_door",
@ -289,6 +353,7 @@ registry!(Block, {
AcaciaPressurePlate => "minecraft:acacia_pressure_plate", AcaciaPressurePlate => "minecraft:acacia_pressure_plate",
DarkOakPressurePlate => "minecraft:dark_oak_pressure_plate", DarkOakPressurePlate => "minecraft:dark_oak_pressure_plate",
MangrovePressurePlate => "minecraft:mangrove_pressure_plate", MangrovePressurePlate => "minecraft:mangrove_pressure_plate",
BambooPressurePlate => "minecraft:bamboo_pressure_plate",
RedstoneOre => "minecraft:redstone_ore", RedstoneOre => "minecraft:redstone_ore",
DeepslateRedstoneOre => "minecraft:deepslate_redstone_ore", DeepslateRedstoneOre => "minecraft:deepslate_redstone_ore",
RedstoneTorch => "minecraft:redstone_torch", RedstoneTorch => "minecraft:redstone_torch",
@ -339,6 +404,7 @@ registry!(Block, {
AcaciaTrapdoor => "minecraft:acacia_trapdoor", AcaciaTrapdoor => "minecraft:acacia_trapdoor",
DarkOakTrapdoor => "minecraft:dark_oak_trapdoor", DarkOakTrapdoor => "minecraft:dark_oak_trapdoor",
MangroveTrapdoor => "minecraft:mangrove_trapdoor", MangroveTrapdoor => "minecraft:mangrove_trapdoor",
BambooTrapdoor => "minecraft:bamboo_trapdoor",
StoneBricks => "minecraft:stone_bricks", StoneBricks => "minecraft:stone_bricks",
MossyStoneBricks => "minecraft:mossy_stone_bricks", MossyStoneBricks => "minecraft:mossy_stone_bricks",
CrackedStoneBricks => "minecraft:cracked_stone_bricks", CrackedStoneBricks => "minecraft:cracked_stone_bricks",
@ -435,6 +501,7 @@ registry!(Block, {
AcaciaButton => "minecraft:acacia_button", AcaciaButton => "minecraft:acacia_button",
DarkOakButton => "minecraft:dark_oak_button", DarkOakButton => "minecraft:dark_oak_button",
MangroveButton => "minecraft:mangrove_button", MangroveButton => "minecraft:mangrove_button",
BambooButton => "minecraft:bamboo_button",
SkeletonSkull => "minecraft:skeleton_skull", SkeletonSkull => "minecraft:skeleton_skull",
SkeletonWallSkull => "minecraft:skeleton_wall_skull", SkeletonWallSkull => "minecraft:skeleton_wall_skull",
WitherSkeletonSkull => "minecraft:wither_skeleton_skull", WitherSkeletonSkull => "minecraft:wither_skeleton_skull",
@ -447,6 +514,8 @@ registry!(Block, {
CreeperWallHead => "minecraft:creeper_wall_head", CreeperWallHead => "minecraft:creeper_wall_head",
DragonHead => "minecraft:dragon_head", DragonHead => "minecraft:dragon_head",
DragonWallHead => "minecraft:dragon_wall_head", DragonWallHead => "minecraft:dragon_wall_head",
PiglinHead => "minecraft:piglin_head",
PiglinWallHead => "minecraft:piglin_wall_head",
Anvil => "minecraft:anvil", Anvil => "minecraft:anvil",
ChippedAnvil => "minecraft:chipped_anvil", ChippedAnvil => "minecraft:chipped_anvil",
DamagedAnvil => "minecraft:damaged_anvil", DamagedAnvil => "minecraft:damaged_anvil",
@ -499,6 +568,8 @@ registry!(Block, {
AcaciaStairs => "minecraft:acacia_stairs", AcaciaStairs => "minecraft:acacia_stairs",
DarkOakStairs => "minecraft:dark_oak_stairs", DarkOakStairs => "minecraft:dark_oak_stairs",
MangroveStairs => "minecraft:mangrove_stairs", MangroveStairs => "minecraft:mangrove_stairs",
BambooStairs => "minecraft:bamboo_stairs",
BambooMosaicStairs => "minecraft:bamboo_mosaic_stairs",
SlimeBlock => "minecraft:slime_block", SlimeBlock => "minecraft:slime_block",
Barrier => "minecraft:barrier", Barrier => "minecraft:barrier",
Light => "minecraft:light", Light => "minecraft:light",
@ -582,6 +653,8 @@ registry!(Block, {
AcaciaSlab => "minecraft:acacia_slab", AcaciaSlab => "minecraft:acacia_slab",
DarkOakSlab => "minecraft:dark_oak_slab", DarkOakSlab => "minecraft:dark_oak_slab",
MangroveSlab => "minecraft:mangrove_slab", MangroveSlab => "minecraft:mangrove_slab",
BambooSlab => "minecraft:bamboo_slab",
BambooMosaicSlab => "minecraft:bamboo_mosaic_slab",
StoneSlab => "minecraft:stone_slab", StoneSlab => "minecraft:stone_slab",
SmoothStoneSlab => "minecraft:smooth_stone_slab", SmoothStoneSlab => "minecraft:smooth_stone_slab",
SandstoneSlab => "minecraft:sandstone_slab", SandstoneSlab => "minecraft:sandstone_slab",
@ -606,18 +679,21 @@ registry!(Block, {
AcaciaFenceGate => "minecraft:acacia_fence_gate", AcaciaFenceGate => "minecraft:acacia_fence_gate",
DarkOakFenceGate => "minecraft:dark_oak_fence_gate", DarkOakFenceGate => "minecraft:dark_oak_fence_gate",
MangroveFenceGate => "minecraft:mangrove_fence_gate", MangroveFenceGate => "minecraft:mangrove_fence_gate",
BambooFenceGate => "minecraft:bamboo_fence_gate",
SpruceFence => "minecraft:spruce_fence", SpruceFence => "minecraft:spruce_fence",
BirchFence => "minecraft:birch_fence", BirchFence => "minecraft:birch_fence",
JungleFence => "minecraft:jungle_fence", JungleFence => "minecraft:jungle_fence",
AcaciaFence => "minecraft:acacia_fence", AcaciaFence => "minecraft:acacia_fence",
DarkOakFence => "minecraft:dark_oak_fence", DarkOakFence => "minecraft:dark_oak_fence",
MangroveFence => "minecraft:mangrove_fence", MangroveFence => "minecraft:mangrove_fence",
BambooFence => "minecraft:bamboo_fence",
SpruceDoor => "minecraft:spruce_door", SpruceDoor => "minecraft:spruce_door",
BirchDoor => "minecraft:birch_door", BirchDoor => "minecraft:birch_door",
JungleDoor => "minecraft:jungle_door", JungleDoor => "minecraft:jungle_door",
AcaciaDoor => "minecraft:acacia_door", AcaciaDoor => "minecraft:acacia_door",
DarkOakDoor => "minecraft:dark_oak_door", DarkOakDoor => "minecraft:dark_oak_door",
MangroveDoor => "minecraft:mangrove_door", MangroveDoor => "minecraft:mangrove_door",
BambooDoor => "minecraft:bamboo_door",
EndRod => "minecraft:end_rod", EndRod => "minecraft:end_rod",
ChorusPlant => "minecraft:chorus_plant", ChorusPlant => "minecraft:chorus_plant",
ChorusFlower => "minecraft:chorus_flower", ChorusFlower => "minecraft:chorus_flower",
@ -1034,6 +1110,7 @@ registry!(BlockEntityType, {
Dispenser => "minecraft:dispenser", Dispenser => "minecraft:dispenser",
Dropper => "minecraft:dropper", Dropper => "minecraft:dropper",
Sign => "minecraft:sign", Sign => "minecraft:sign",
HangingSign => "minecraft:hanging_sign",
MobSpawner => "minecraft:mob_spawner", MobSpawner => "minecraft:mob_spawner",
Piston => "minecraft:piston", Piston => "minecraft:piston",
BrewingStand => "minecraft:brewing_stand", BrewingStand => "minecraft:brewing_stand",
@ -1062,6 +1139,7 @@ registry!(BlockEntityType, {
SculkSensor => "minecraft:sculk_sensor", SculkSensor => "minecraft:sculk_sensor",
SculkCatalyst => "minecraft:sculk_catalyst", SculkCatalyst => "minecraft:sculk_catalyst",
SculkShrieker => "minecraft:sculk_shrieker", SculkShrieker => "minecraft:sculk_shrieker",
ChiseledBookshelf => "minecraft:chiseled_bookshelf",
}); });
registry!(BlockPredicateType, { registry!(BlockPredicateType, {
@ -1144,17 +1222,17 @@ registry!(CommandArgumentType, {
Team => "minecraft:team", Team => "minecraft:team",
ItemSlot => "minecraft:item_slot", ItemSlot => "minecraft:item_slot",
ResourceLocation => "minecraft:resource_location", ResourceLocation => "minecraft:resource_location",
MobEffect => "minecraft:mob_effect",
Function => "minecraft:function", Function => "minecraft:function",
EntityAnchor => "minecraft:entity_anchor", EntityAnchor => "minecraft:entity_anchor",
IntRange => "minecraft:int_range", IntRange => "minecraft:int_range",
FloatRange => "minecraft:float_range", FloatRange => "minecraft:float_range",
ItemEnchantment => "minecraft:item_enchantment",
EntitySummon => "minecraft:entity_summon",
Dimension => "minecraft:dimension", Dimension => "minecraft:dimension",
Gamemode => "minecraft:gamemode",
Time => "minecraft:time", Time => "minecraft:time",
ResourceOrTag => "minecraft:resource_or_tag", ResourceOrTag => "minecraft:resource_or_tag",
ResourceOrTagKey => "minecraft:resource_or_tag_key",
Resource => "minecraft:resource", Resource => "minecraft:resource",
ResourceKey => "minecraft:resource_key",
TemplateMirror => "minecraft:template_mirror", TemplateMirror => "minecraft:template_mirror",
TemplateRotation => "minecraft:template_rotation", TemplateRotation => "minecraft:template_rotation",
Uuid => "minecraft:uuid", Uuid => "minecraft:uuid",
@ -1292,6 +1370,7 @@ registry!(EntityType, {
Boat => "minecraft:boat", Boat => "minecraft:boat",
ChestBoat => "minecraft:chest_boat", ChestBoat => "minecraft:chest_boat",
Cat => "minecraft:cat", Cat => "minecraft:cat",
Camel => "minecraft:camel",
CaveSpider => "minecraft:cave_spider", CaveSpider => "minecraft:cave_spider",
Chicken => "minecraft:chicken", Chicken => "minecraft:chicken",
Cod => "minecraft:cod", Cod => "minecraft:cod",
@ -1531,8 +1610,10 @@ registry!(Item, {
AcaciaPlanks => "minecraft:acacia_planks", AcaciaPlanks => "minecraft:acacia_planks",
DarkOakPlanks => "minecraft:dark_oak_planks", DarkOakPlanks => "minecraft:dark_oak_planks",
MangrovePlanks => "minecraft:mangrove_planks", MangrovePlanks => "minecraft:mangrove_planks",
BambooPlanks => "minecraft:bamboo_planks",
CrimsonPlanks => "minecraft:crimson_planks", CrimsonPlanks => "minecraft:crimson_planks",
WarpedPlanks => "minecraft:warped_planks", WarpedPlanks => "minecraft:warped_planks",
BambooMosaic => "minecraft:bamboo_mosaic",
OakSapling => "minecraft:oak_sapling", OakSapling => "minecraft:oak_sapling",
SpruceSapling => "minecraft:spruce_sapling", SpruceSapling => "minecraft:spruce_sapling",
BirchSapling => "minecraft:birch_sapling", BirchSapling => "minecraft:birch_sapling",
@ -1616,6 +1697,7 @@ registry!(Item, {
MuddyMangroveRoots => "minecraft:muddy_mangrove_roots", MuddyMangroveRoots => "minecraft:muddy_mangrove_roots",
CrimsonStem => "minecraft:crimson_stem", CrimsonStem => "minecraft:crimson_stem",
WarpedStem => "minecraft:warped_stem", WarpedStem => "minecraft:warped_stem",
BambooBlock => "minecraft:bamboo_block",
StrippedOakLog => "minecraft:stripped_oak_log", StrippedOakLog => "minecraft:stripped_oak_log",
StrippedSpruceLog => "minecraft:stripped_spruce_log", StrippedSpruceLog => "minecraft:stripped_spruce_log",
StrippedBirchLog => "minecraft:stripped_birch_log", StrippedBirchLog => "minecraft:stripped_birch_log",
@ -1634,6 +1716,7 @@ registry!(Item, {
StrippedMangroveWood => "minecraft:stripped_mangrove_wood", StrippedMangroveWood => "minecraft:stripped_mangrove_wood",
StrippedCrimsonHyphae => "minecraft:stripped_crimson_hyphae", StrippedCrimsonHyphae => "minecraft:stripped_crimson_hyphae",
StrippedWarpedHyphae => "minecraft:stripped_warped_hyphae", StrippedWarpedHyphae => "minecraft:stripped_warped_hyphae",
StrippedBambooBlock => "minecraft:stripped_bamboo_block",
OakWood => "minecraft:oak_wood", OakWood => "minecraft:oak_wood",
SpruceWood => "minecraft:spruce_wood", SpruceWood => "minecraft:spruce_wood",
BirchWood => "minecraft:birch_wood", BirchWood => "minecraft:birch_wood",
@ -1722,6 +1805,8 @@ registry!(Item, {
AcaciaSlab => "minecraft:acacia_slab", AcaciaSlab => "minecraft:acacia_slab",
DarkOakSlab => "minecraft:dark_oak_slab", DarkOakSlab => "minecraft:dark_oak_slab",
MangroveSlab => "minecraft:mangrove_slab", MangroveSlab => "minecraft:mangrove_slab",
BambooSlab => "minecraft:bamboo_slab",
BambooMosaicSlab => "minecraft:bamboo_mosaic_slab",
CrimsonSlab => "minecraft:crimson_slab", CrimsonSlab => "minecraft:crimson_slab",
WarpedSlab => "minecraft:warped_slab", WarpedSlab => "minecraft:warped_slab",
StoneSlab => "minecraft:stone_slab", StoneSlab => "minecraft:stone_slab",
@ -1747,6 +1832,7 @@ registry!(Item, {
SmoothStone => "minecraft:smooth_stone", SmoothStone => "minecraft:smooth_stone",
Bricks => "minecraft:bricks", Bricks => "minecraft:bricks",
Bookshelf => "minecraft:bookshelf", Bookshelf => "minecraft:bookshelf",
ChiseledBookshelf => "minecraft:chiseled_bookshelf",
MossyCobblestone => "minecraft:mossy_cobblestone", MossyCobblestone => "minecraft:mossy_cobblestone",
Obsidian => "minecraft:obsidian", Obsidian => "minecraft:obsidian",
Torch => "minecraft:torch", Torch => "minecraft:torch",
@ -1776,6 +1862,7 @@ registry!(Item, {
AcaciaFence => "minecraft:acacia_fence", AcaciaFence => "minecraft:acacia_fence",
DarkOakFence => "minecraft:dark_oak_fence", DarkOakFence => "minecraft:dark_oak_fence",
MangroveFence => "minecraft:mangrove_fence", MangroveFence => "minecraft:mangrove_fence",
BambooFence => "minecraft:bamboo_fence",
CrimsonFence => "minecraft:crimson_fence", CrimsonFence => "minecraft:crimson_fence",
WarpedFence => "minecraft:warped_fence", WarpedFence => "minecraft:warped_fence",
Pumpkin => "minecraft:pumpkin", Pumpkin => "minecraft:pumpkin",
@ -1846,6 +1933,8 @@ registry!(Item, {
AcaciaStairs => "minecraft:acacia_stairs", AcaciaStairs => "minecraft:acacia_stairs",
DarkOakStairs => "minecraft:dark_oak_stairs", DarkOakStairs => "minecraft:dark_oak_stairs",
MangroveStairs => "minecraft:mangrove_stairs", MangroveStairs => "minecraft:mangrove_stairs",
BambooStairs => "minecraft:bamboo_stairs",
BambooMosaicStairs => "minecraft:bamboo_mosaic_stairs",
CrimsonStairs => "minecraft:crimson_stairs", CrimsonStairs => "minecraft:crimson_stairs",
WarpedStairs => "minecraft:warped_stairs", WarpedStairs => "minecraft:warped_stairs",
CommandBlock => "minecraft:command_block", CommandBlock => "minecraft:command_block",
@ -2142,6 +2231,7 @@ registry!(Item, {
AcaciaButton => "minecraft:acacia_button", AcaciaButton => "minecraft:acacia_button",
DarkOakButton => "minecraft:dark_oak_button", DarkOakButton => "minecraft:dark_oak_button",
MangroveButton => "minecraft:mangrove_button", MangroveButton => "minecraft:mangrove_button",
BambooButton => "minecraft:bamboo_button",
CrimsonButton => "minecraft:crimson_button", CrimsonButton => "minecraft:crimson_button",
WarpedButton => "minecraft:warped_button", WarpedButton => "minecraft:warped_button",
StonePressurePlate => "minecraft:stone_pressure_plate", StonePressurePlate => "minecraft:stone_pressure_plate",
@ -2155,6 +2245,7 @@ registry!(Item, {
AcaciaPressurePlate => "minecraft:acacia_pressure_plate", AcaciaPressurePlate => "minecraft:acacia_pressure_plate",
DarkOakPressurePlate => "minecraft:dark_oak_pressure_plate", DarkOakPressurePlate => "minecraft:dark_oak_pressure_plate",
MangrovePressurePlate => "minecraft:mangrove_pressure_plate", MangrovePressurePlate => "minecraft:mangrove_pressure_plate",
BambooPressurePlate => "minecraft:bamboo_pressure_plate",
CrimsonPressurePlate => "minecraft:crimson_pressure_plate", CrimsonPressurePlate => "minecraft:crimson_pressure_plate",
WarpedPressurePlate => "minecraft:warped_pressure_plate", WarpedPressurePlate => "minecraft:warped_pressure_plate",
IronDoor => "minecraft:iron_door", IronDoor => "minecraft:iron_door",
@ -2165,6 +2256,7 @@ registry!(Item, {
AcaciaDoor => "minecraft:acacia_door", AcaciaDoor => "minecraft:acacia_door",
DarkOakDoor => "minecraft:dark_oak_door", DarkOakDoor => "minecraft:dark_oak_door",
MangroveDoor => "minecraft:mangrove_door", MangroveDoor => "minecraft:mangrove_door",
BambooDoor => "minecraft:bamboo_door",
CrimsonDoor => "minecraft:crimson_door", CrimsonDoor => "minecraft:crimson_door",
WarpedDoor => "minecraft:warped_door", WarpedDoor => "minecraft:warped_door",
IronTrapdoor => "minecraft:iron_trapdoor", IronTrapdoor => "minecraft:iron_trapdoor",
@ -2175,6 +2267,7 @@ registry!(Item, {
AcaciaTrapdoor => "minecraft:acacia_trapdoor", AcaciaTrapdoor => "minecraft:acacia_trapdoor",
DarkOakTrapdoor => "minecraft:dark_oak_trapdoor", DarkOakTrapdoor => "minecraft:dark_oak_trapdoor",
MangroveTrapdoor => "minecraft:mangrove_trapdoor", MangroveTrapdoor => "minecraft:mangrove_trapdoor",
BambooTrapdoor => "minecraft:bamboo_trapdoor",
CrimsonTrapdoor => "minecraft:crimson_trapdoor", CrimsonTrapdoor => "minecraft:crimson_trapdoor",
WarpedTrapdoor => "minecraft:warped_trapdoor", WarpedTrapdoor => "minecraft:warped_trapdoor",
OakFenceGate => "minecraft:oak_fence_gate", OakFenceGate => "minecraft:oak_fence_gate",
@ -2184,6 +2277,7 @@ registry!(Item, {
AcaciaFenceGate => "minecraft:acacia_fence_gate", AcaciaFenceGate => "minecraft:acacia_fence_gate",
DarkOakFenceGate => "minecraft:dark_oak_fence_gate", DarkOakFenceGate => "minecraft:dark_oak_fence_gate",
MangroveFenceGate => "minecraft:mangrove_fence_gate", MangroveFenceGate => "minecraft:mangrove_fence_gate",
BambooFenceGate => "minecraft:bamboo_fence_gate",
CrimsonFenceGate => "minecraft:crimson_fence_gate", CrimsonFenceGate => "minecraft:crimson_fence_gate",
WarpedFenceGate => "minecraft:warped_fence_gate", WarpedFenceGate => "minecraft:warped_fence_gate",
PoweredRail => "minecraft:powered_rail", PoweredRail => "minecraft:powered_rail",
@ -2213,6 +2307,8 @@ registry!(Item, {
DarkOakChestBoat => "minecraft:dark_oak_chest_boat", DarkOakChestBoat => "minecraft:dark_oak_chest_boat",
MangroveBoat => "minecraft:mangrove_boat", MangroveBoat => "minecraft:mangrove_boat",
MangroveChestBoat => "minecraft:mangrove_chest_boat", MangroveChestBoat => "minecraft:mangrove_chest_boat",
BambooRaft => "minecraft:bamboo_raft",
BambooChestRaft => "minecraft:bamboo_chest_raft",
StructureBlock => "minecraft:structure_block", StructureBlock => "minecraft:structure_block",
Jigsaw => "minecraft:jigsaw", Jigsaw => "minecraft:jigsaw",
TurtleHelmet => "minecraft:turtle_helmet", TurtleHelmet => "minecraft:turtle_helmet",
@ -2312,8 +2408,19 @@ registry!(Item, {
AcaciaSign => "minecraft:acacia_sign", AcaciaSign => "minecraft:acacia_sign",
DarkOakSign => "minecraft:dark_oak_sign", DarkOakSign => "minecraft:dark_oak_sign",
MangroveSign => "minecraft:mangrove_sign", MangroveSign => "minecraft:mangrove_sign",
BambooSign => "minecraft:bamboo_sign",
CrimsonSign => "minecraft:crimson_sign", CrimsonSign => "minecraft:crimson_sign",
WarpedSign => "minecraft:warped_sign", WarpedSign => "minecraft:warped_sign",
OakHangingSign => "minecraft:oak_hanging_sign",
SpruceHangingSign => "minecraft:spruce_hanging_sign",
BirchHangingSign => "minecraft:birch_hanging_sign",
JungleHangingSign => "minecraft:jungle_hanging_sign",
AcaciaHangingSign => "minecraft:acacia_hanging_sign",
DarkOakHangingSign => "minecraft:dark_oak_hanging_sign",
MangroveHangingSign => "minecraft:mangrove_hanging_sign",
BambooHangingSign => "minecraft:bamboo_hanging_sign",
CrimsonHangingSign => "minecraft:crimson_hanging_sign",
WarpedHangingSign => "minecraft:warped_hanging_sign",
Bucket => "minecraft:bucket", Bucket => "minecraft:bucket",
WaterBucket => "minecraft:water_bucket", WaterBucket => "minecraft:water_bucket",
LavaBucket => "minecraft:lava_bucket", LavaBucket => "minecraft:lava_bucket",
@ -2419,6 +2526,7 @@ registry!(Item, {
BeeSpawnEgg => "minecraft:bee_spawn_egg", BeeSpawnEgg => "minecraft:bee_spawn_egg",
BlazeSpawnEgg => "minecraft:blaze_spawn_egg", BlazeSpawnEgg => "minecraft:blaze_spawn_egg",
CatSpawnEgg => "minecraft:cat_spawn_egg", CatSpawnEgg => "minecraft:cat_spawn_egg",
CamelSpawnEgg => "minecraft:camel_spawn_egg",
CaveSpiderSpawnEgg => "minecraft:cave_spider_spawn_egg", CaveSpiderSpawnEgg => "minecraft:cave_spider_spawn_egg",
ChickenSpawnEgg => "minecraft:chicken_spawn_egg", ChickenSpawnEgg => "minecraft:chicken_spawn_egg",
CodSpawnEgg => "minecraft:cod_spawn_egg", CodSpawnEgg => "minecraft:cod_spawn_egg",
@ -2428,6 +2536,7 @@ registry!(Item, {
DonkeySpawnEgg => "minecraft:donkey_spawn_egg", DonkeySpawnEgg => "minecraft:donkey_spawn_egg",
DrownedSpawnEgg => "minecraft:drowned_spawn_egg", DrownedSpawnEgg => "minecraft:drowned_spawn_egg",
ElderGuardianSpawnEgg => "minecraft:elder_guardian_spawn_egg", ElderGuardianSpawnEgg => "minecraft:elder_guardian_spawn_egg",
EnderDragonSpawnEgg => "minecraft:ender_dragon_spawn_egg",
EndermanSpawnEgg => "minecraft:enderman_spawn_egg", EndermanSpawnEgg => "minecraft:enderman_spawn_egg",
EndermiteSpawnEgg => "minecraft:endermite_spawn_egg", EndermiteSpawnEgg => "minecraft:endermite_spawn_egg",
EvokerSpawnEgg => "minecraft:evoker_spawn_egg", EvokerSpawnEgg => "minecraft:evoker_spawn_egg",
@ -2440,6 +2549,7 @@ registry!(Item, {
HoglinSpawnEgg => "minecraft:hoglin_spawn_egg", HoglinSpawnEgg => "minecraft:hoglin_spawn_egg",
HorseSpawnEgg => "minecraft:horse_spawn_egg", HorseSpawnEgg => "minecraft:horse_spawn_egg",
HuskSpawnEgg => "minecraft:husk_spawn_egg", HuskSpawnEgg => "minecraft:husk_spawn_egg",
IronGolemSpawnEgg => "minecraft:iron_golem_spawn_egg",
LlamaSpawnEgg => "minecraft:llama_spawn_egg", LlamaSpawnEgg => "minecraft:llama_spawn_egg",
MagmaCubeSpawnEgg => "minecraft:magma_cube_spawn_egg", MagmaCubeSpawnEgg => "minecraft:magma_cube_spawn_egg",
MooshroomSpawnEgg => "minecraft:mooshroom_spawn_egg", MooshroomSpawnEgg => "minecraft:mooshroom_spawn_egg",
@ -2463,6 +2573,7 @@ registry!(Item, {
SkeletonSpawnEgg => "minecraft:skeleton_spawn_egg", SkeletonSpawnEgg => "minecraft:skeleton_spawn_egg",
SkeletonHorseSpawnEgg => "minecraft:skeleton_horse_spawn_egg", SkeletonHorseSpawnEgg => "minecraft:skeleton_horse_spawn_egg",
SlimeSpawnEgg => "minecraft:slime_spawn_egg", SlimeSpawnEgg => "minecraft:slime_spawn_egg",
SnowGolemSpawnEgg => "minecraft:snow_golem_spawn_egg",
SpiderSpawnEgg => "minecraft:spider_spawn_egg", SpiderSpawnEgg => "minecraft:spider_spawn_egg",
SquidSpawnEgg => "minecraft:squid_spawn_egg", SquidSpawnEgg => "minecraft:squid_spawn_egg",
StraySpawnEgg => "minecraft:stray_spawn_egg", StraySpawnEgg => "minecraft:stray_spawn_egg",
@ -2477,6 +2588,7 @@ registry!(Item, {
WanderingTraderSpawnEgg => "minecraft:wandering_trader_spawn_egg", WanderingTraderSpawnEgg => "minecraft:wandering_trader_spawn_egg",
WardenSpawnEgg => "minecraft:warden_spawn_egg", WardenSpawnEgg => "minecraft:warden_spawn_egg",
WitchSpawnEgg => "minecraft:witch_spawn_egg", WitchSpawnEgg => "minecraft:witch_spawn_egg",
WitherSpawnEgg => "minecraft:wither_spawn_egg",
WitherSkeletonSpawnEgg => "minecraft:wither_skeleton_spawn_egg", WitherSkeletonSpawnEgg => "minecraft:wither_skeleton_spawn_egg",
WolfSpawnEgg => "minecraft:wolf_spawn_egg", WolfSpawnEgg => "minecraft:wolf_spawn_egg",
ZoglinSpawnEgg => "minecraft:zoglin_spawn_egg", ZoglinSpawnEgg => "minecraft:zoglin_spawn_egg",
@ -2503,6 +2615,7 @@ registry!(Item, {
ZombieHead => "minecraft:zombie_head", ZombieHead => "minecraft:zombie_head",
CreeperHead => "minecraft:creeper_head", CreeperHead => "minecraft:creeper_head",
DragonHead => "minecraft:dragon_head", DragonHead => "minecraft:dragon_head",
PiglinHead => "minecraft:piglin_head",
NetherStar => "minecraft:nether_star", NetherStar => "minecraft:nether_star",
PumpkinPie => "minecraft:pumpkin_pie", PumpkinPie => "minecraft:pumpkin_pie",
FireworkRocket => "minecraft:firework_rocket", FireworkRocket => "minecraft:firework_rocket",
@ -2773,6 +2886,7 @@ registry!(MemoryModuleType, {
PlayDeadTicks => "minecraft:play_dead_ticks", PlayDeadTicks => "minecraft:play_dead_ticks",
TemptingPlayer => "minecraft:tempting_player", TemptingPlayer => "minecraft:tempting_player",
TemptationCooldownTicks => "minecraft:temptation_cooldown_ticks", TemptationCooldownTicks => "minecraft:temptation_cooldown_ticks",
GazeCooldownTicks => "minecraft:gaze_cooldown_ticks",
IsTempted => "minecraft:is_tempted", IsTempted => "minecraft:is_tempted",
LongJumpCoolingDown => "minecraft:long_jump_cooling_down", LongJumpCoolingDown => "minecraft:long_jump_cooling_down",
LongJumpMidJump => "minecraft:long_jump_mid_jump", LongJumpMidJump => "minecraft:long_jump_mid_jump",
@ -3167,6 +3281,7 @@ registry!(SensorType, {
AxolotlTemptations => "minecraft:axolotl_temptations", AxolotlTemptations => "minecraft:axolotl_temptations",
GoatTemptations => "minecraft:goat_temptations", GoatTemptations => "minecraft:goat_temptations",
FrogTemptations => "minecraft:frog_temptations", FrogTemptations => "minecraft:frog_temptations",
CamelTemptations => "minecraft:camel_temptations",
FrogAttackables => "minecraft:frog_attackables", FrogAttackables => "minecraft:frog_attackables",
IsInWater => "minecraft:is_in_water", IsInWater => "minecraft:is_in_water",
WardenEntitySensor => "minecraft:warden_entity_sensor", WardenEntitySensor => "minecraft:warden_entity_sensor",
@ -3270,6 +3385,21 @@ registry!(SoundEvent, {
BlockBambooSaplingBreak => "minecraft:block.bamboo_sapling.break", BlockBambooSaplingBreak => "minecraft:block.bamboo_sapling.break",
BlockBambooSaplingHit => "minecraft:block.bamboo_sapling.hit", BlockBambooSaplingHit => "minecraft:block.bamboo_sapling.hit",
BlockBambooSaplingPlace => "minecraft:block.bamboo_sapling.place", BlockBambooSaplingPlace => "minecraft:block.bamboo_sapling.place",
BlockBambooWoodBreak => "minecraft:block.bamboo_wood.break",
BlockBambooWoodFall => "minecraft:block.bamboo_wood.fall",
BlockBambooWoodHit => "minecraft:block.bamboo_wood.hit",
BlockBambooWoodPlace => "minecraft:block.bamboo_wood.place",
BlockBambooWoodStep => "minecraft:block.bamboo_wood.step",
BlockBambooWoodDoorClose => "minecraft:block.bamboo_wood_door.close",
BlockBambooWoodDoorOpen => "minecraft:block.bamboo_wood_door.open",
BlockBambooWoodTrapdoorClose => "minecraft:block.bamboo_wood_trapdoor.close",
BlockBambooWoodTrapdoorOpen => "minecraft:block.bamboo_wood_trapdoor.open",
BlockBambooWoodButtonClickOff => "minecraft:block.bamboo_wood_button.click_off",
BlockBambooWoodButtonClickOn => "minecraft:block.bamboo_wood_button.click_on",
BlockBambooWoodPressurePlateClickOff => "minecraft:block.bamboo_wood_pressure_plate.click_off",
BlockBambooWoodPressurePlateClickOn => "minecraft:block.bamboo_wood_pressure_plate.click_on",
BlockBambooWoodFenceGateClose => "minecraft:block.bamboo_wood_fence_gate.close",
BlockBambooWoodFenceGateOpen => "minecraft:block.bamboo_wood_fence_gate.open",
BlockBarrelClose => "minecraft:block.barrel.close", BlockBarrelClose => "minecraft:block.barrel.close",
BlockBarrelOpen => "minecraft:block.barrel.open", BlockBarrelOpen => "minecraft:block.barrel.open",
BlockBasaltBreak => "minecraft:block.basalt.break", BlockBasaltBreak => "minecraft:block.basalt.break",
@ -3350,6 +3480,17 @@ registry!(SoundEvent, {
BlockCalcitePlace => "minecraft:block.calcite.place", BlockCalcitePlace => "minecraft:block.calcite.place",
BlockCalciteHit => "minecraft:block.calcite.hit", BlockCalciteHit => "minecraft:block.calcite.hit",
BlockCalciteFall => "minecraft:block.calcite.fall", BlockCalciteFall => "minecraft:block.calcite.fall",
EntityCamelAmbient => "minecraft:entity.camel.ambient",
EntityCamelDash => "minecraft:entity.camel.dash",
EntityCamelDashReady => "minecraft:entity.camel.dash_ready",
EntityCamelDeath => "minecraft:entity.camel.death",
EntityCamelEat => "minecraft:entity.camel.eat",
EntityCamelHurt => "minecraft:entity.camel.hurt",
EntityCamelSaddle => "minecraft:entity.camel.saddle",
EntityCamelSit => "minecraft:entity.camel.sit",
EntityCamelStand => "minecraft:entity.camel.stand",
EntityCamelStep => "minecraft:entity.camel.step",
EntityCamelStepSand => "minecraft:entity.camel.step_sand",
BlockCampfireCrackle => "minecraft:block.campfire.crackle", BlockCampfireCrackle => "minecraft:block.campfire.crackle",
BlockCandleAmbient => "minecraft:block.candle.ambient", BlockCandleAmbient => "minecraft:block.candle.ambient",
BlockCandleBreak => "minecraft:block.candle.break", BlockCandleBreak => "minecraft:block.candle.break",
@ -3386,6 +3527,15 @@ registry!(SoundEvent, {
EntityChickenEgg => "minecraft:entity.chicken.egg", EntityChickenEgg => "minecraft:entity.chicken.egg",
EntityChickenHurt => "minecraft:entity.chicken.hurt", EntityChickenHurt => "minecraft:entity.chicken.hurt",
EntityChickenStep => "minecraft:entity.chicken.step", EntityChickenStep => "minecraft:entity.chicken.step",
BlockChiseledBookshelfBreak => "minecraft:block.chiseled_bookshelf.break",
BlockChiseledBookshelfFall => "minecraft:block.chiseled_bookshelf.fall",
BlockChiseledBookshelfHit => "minecraft:block.chiseled_bookshelf.hit",
BlockChiseledBookshelfInsert => "minecraft:block.chiseled_bookshelf.insert",
BlockChiseledBookshelfInsertEnchanted => "minecraft:block.chiseled_bookshelf.insert.enchanted",
BlockChiseledBookshelfStep => "minecraft:block.chiseled_bookshelf.step",
BlockChiseledBookshelfPickup => "minecraft:block.chiseled_bookshelf.pickup",
BlockChiseledBookshelfPickupEnchanted => "minecraft:block.chiseled_bookshelf.pickup.enchanted",
BlockChiseledBookshelfPlace => "minecraft:block.chiseled_bookshelf.place",
BlockChorusFlowerDeath => "minecraft:block.chorus_flower.death", BlockChorusFlowerDeath => "minecraft:block.chorus_flower.death",
BlockChorusFlowerGrow => "minecraft:block.chorus_flower.grow", BlockChorusFlowerGrow => "minecraft:block.chorus_flower.grow",
ItemChorusFruitTeleport => "minecraft:item.chorus_fruit.teleport", ItemChorusFruitTeleport => "minecraft:item.chorus_fruit.teleport",
@ -3680,6 +3830,21 @@ registry!(SoundEvent, {
BlockHangingRootsHit => "minecraft:block.hanging_roots.hit", BlockHangingRootsHit => "minecraft:block.hanging_roots.hit",
BlockHangingRootsPlace => "minecraft:block.hanging_roots.place", BlockHangingRootsPlace => "minecraft:block.hanging_roots.place",
BlockHangingRootsStep => "minecraft:block.hanging_roots.step", BlockHangingRootsStep => "minecraft:block.hanging_roots.step",
BlockHangingSignStep => "minecraft:block.hanging_sign.step",
BlockHangingSignBreak => "minecraft:block.hanging_sign.break",
BlockHangingSignFall => "minecraft:block.hanging_sign.fall",
BlockHangingSignHit => "minecraft:block.hanging_sign.hit",
BlockHangingSignPlace => "minecraft:block.hanging_sign.place",
BlockNetherWoodHangingSignStep => "minecraft:block.nether_wood_hanging_sign.step",
BlockNetherWoodHangingSignBreak => "minecraft:block.nether_wood_hanging_sign.break",
BlockNetherWoodHangingSignFall => "minecraft:block.nether_wood_hanging_sign.fall",
BlockNetherWoodHangingSignHit => "minecraft:block.nether_wood_hanging_sign.hit",
BlockNetherWoodHangingSignPlace => "minecraft:block.nether_wood_hanging_sign.place",
BlockBambooWoodHangingSignStep => "minecraft:block.bamboo_wood_hanging_sign.step",
BlockBambooWoodHangingSignBreak => "minecraft:block.bamboo_wood_hanging_sign.break",
BlockBambooWoodHangingSignFall => "minecraft:block.bamboo_wood_hanging_sign.fall",
BlockBambooWoodHangingSignHit => "minecraft:block.bamboo_wood_hanging_sign.hit",
BlockBambooWoodHangingSignPlace => "minecraft:block.bamboo_wood_hanging_sign.place",
ItemHoeTill => "minecraft:item.hoe.till", ItemHoeTill => "minecraft:item.hoe.till",
EntityHoglinAmbient => "minecraft:entity.hoglin.ambient", EntityHoglinAmbient => "minecraft:entity.hoglin.ambient",
EntityHoglinAngry => "minecraft:entity.hoglin.angry", EntityHoglinAngry => "minecraft:entity.hoglin.angry",
@ -3896,6 +4061,21 @@ registry!(SoundEvent, {
BlockNetherBricksFall => "minecraft:block.nether_bricks.fall", BlockNetherBricksFall => "minecraft:block.nether_bricks.fall",
BlockNetherWartBreak => "minecraft:block.nether_wart.break", BlockNetherWartBreak => "minecraft:block.nether_wart.break",
ItemNetherWartPlant => "minecraft:item.nether_wart.plant", ItemNetherWartPlant => "minecraft:item.nether_wart.plant",
BlockNetherWoodBreak => "minecraft:block.nether_wood.break",
BlockNetherWoodFall => "minecraft:block.nether_wood.fall",
BlockNetherWoodHit => "minecraft:block.nether_wood.hit",
BlockNetherWoodPlace => "minecraft:block.nether_wood.place",
BlockNetherWoodStep => "minecraft:block.nether_wood.step",
BlockNetherWoodDoorClose => "minecraft:block.nether_wood_door.close",
BlockNetherWoodDoorOpen => "minecraft:block.nether_wood_door.open",
BlockNetherWoodTrapdoorClose => "minecraft:block.nether_wood_trapdoor.close",
BlockNetherWoodTrapdoorOpen => "minecraft:block.nether_wood_trapdoor.open",
BlockNetherWoodButtonClickOff => "minecraft:block.nether_wood_button.click_off",
BlockNetherWoodButtonClickOn => "minecraft:block.nether_wood_button.click_on",
BlockNetherWoodPressurePlateClickOff => "minecraft:block.nether_wood_pressure_plate.click_off",
BlockNetherWoodPressurePlateClickOn => "minecraft:block.nether_wood_pressure_plate.click_on",
BlockNetherWoodFenceGateClose => "minecraft:block.nether_wood_fence_gate.close",
BlockNetherWoodFenceGateOpen => "minecraft:block.nether_wood_fence_gate.open",
BlockPackedMudBreak => "minecraft:block.packed_mud.break", BlockPackedMudBreak => "minecraft:block.packed_mud.break",
BlockPackedMudFall => "minecraft:block.packed_mud.fall", BlockPackedMudFall => "minecraft:block.packed_mud.fall",
BlockPackedMudHit => "minecraft:block.packed_mud.hit", BlockPackedMudHit => "minecraft:block.packed_mud.hit",
@ -3957,6 +4137,12 @@ registry!(SoundEvent, {
BlockNoteBlockDidgeridoo => "minecraft:block.note_block.didgeridoo", BlockNoteBlockDidgeridoo => "minecraft:block.note_block.didgeridoo",
BlockNoteBlockBit => "minecraft:block.note_block.bit", BlockNoteBlockBit => "minecraft:block.note_block.bit",
BlockNoteBlockBanjo => "minecraft:block.note_block.banjo", BlockNoteBlockBanjo => "minecraft:block.note_block.banjo",
BlockNoteBlockImitateZombie => "minecraft:block.note_block.imitate.zombie",
BlockNoteBlockImitateSkeleton => "minecraft:block.note_block.imitate.skeleton",
BlockNoteBlockImitateCreeper => "minecraft:block.note_block.imitate.creeper",
BlockNoteBlockImitateEnderDragon => "minecraft:block.note_block.imitate.ender_dragon",
BlockNoteBlockImitateWitherSkeleton => "minecraft:block.note_block.imitate.wither_skeleton",
BlockNoteBlockImitatePiglin => "minecraft:block.note_block.imitate.piglin",
EntityOcelotHurt => "minecraft:entity.ocelot.hurt", EntityOcelotHurt => "minecraft:entity.ocelot.hurt",
EntityOcelotAmbient => "minecraft:entity.ocelot.ambient", EntityOcelotAmbient => "minecraft:entity.ocelot.ambient",
EntityOcelotDeath => "minecraft:entity.ocelot.death", EntityOcelotDeath => "minecraft:entity.ocelot.death",

View file

@ -1,10 +1,9 @@
use azalea_block::BlockState; use azalea_block::BlockState;
use azalea_buf::{BufReadError, McBufVarReadable}; use azalea_buf::{BufReadError, McBufVarReadable, McBufVarWritable};
use azalea_buf::{McBuf, McBufReadable, McBufWritable}; use azalea_buf::{McBuf, McBufReadable, McBufWritable};
use azalea_chat::Component; use azalea_chat::Component;
use azalea_core::{BlockPos, Direction, GlobalPos, Particle, Slot}; use azalea_core::{BlockPos, Direction, GlobalPos, Particle, Slot};
use enum_as_inner::EnumAsInner; use enum_as_inner::EnumAsInner;
use log::warn;
use nohash_hasher::IntSet; use nohash_hasher::IntSet;
use std::io::{Cursor, Write}; use std::io::{Cursor, Write};
use uuid::Uuid; use uuid::Uuid;
@ -24,12 +23,12 @@ impl McBufReadable for EntityMetadataItems {
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> { fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
let mut metadata = Vec::new(); let mut metadata = Vec::new();
loop { loop {
let index = u8::read_from(buf)?; let id = u8::read_from(buf)?;
if index == 0xff { if id == 0xff {
break; break;
} }
let value = EntityDataValue::read_from(buf)?; let value = EntityDataValue::read_from(buf)?;
metadata.push(EntityDataItem { index, value }); metadata.push(EntityDataItem { index: id, value });
} }
Ok(EntityMetadataItems(metadata)) Ok(EntityMetadataItems(metadata))
} }
@ -46,10 +45,11 @@ impl McBufWritable for EntityMetadataItems {
} }
} }
#[derive(Clone, Debug, EnumAsInner)] #[derive(Clone, Debug, EnumAsInner, McBuf)]
pub enum EntityDataValue { pub enum EntityDataValue {
Byte(u8), Byte(u8),
Int(i32), Int(#[var] i32),
Long(i64),
Float(f32), Float(f32),
String(String), String(String),
Component(Component), Component(Component),
@ -63,19 +63,41 @@ pub enum EntityDataValue {
OptionalUuid(Option<Uuid>), OptionalUuid(Option<Uuid>),
// 0 for absent (implies air); otherwise, a block state ID as per the global palette // 0 for absent (implies air); otherwise, a block state ID as per the global palette
// this is a varint // this is a varint
OptionalBlockState(Option<BlockState>), BlockState(BlockState),
CompoundTag(azalea_nbt::Tag), CompoundTag(azalea_nbt::Tag),
Particle(Particle), Particle(Particle),
VillagerData(VillagerData), VillagerData(VillagerData),
// 0 for absent; 1 + actual value otherwise. Used for entity IDs. // 0 for absent; 1 + actual value otherwise. Used for entity IDs.
OptionalUnsignedInt(Option<u32>), OptionalUnsignedInt(OptionalUnsignedInt),
Pose(Pose), Pose(Pose),
CatVariant(azalea_registry::CatVariant), CatVariant(azalea_registry::CatVariant),
FrogVariant(azalea_registry::FrogVariant), FrogVariant(azalea_registry::FrogVariant),
GlobalPos(GlobalPos), OptionalGlobalPos(Option<GlobalPos>),
PaintingVariant(azalea_registry::PaintingVariant), PaintingVariant(azalea_registry::PaintingVariant),
} }
#[derive(Clone, Debug)]
pub struct OptionalUnsignedInt(pub Option<u32>);
impl McBufReadable for OptionalUnsignedInt {
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
let val = u32::var_read_from(buf)?;
Ok(OptionalUnsignedInt(if val == 0 {
None
} else {
Some(val - 1)
}))
}
}
impl McBufWritable for OptionalUnsignedInt {
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
match self.0 {
Some(val) => (val + 1).var_write_into(buf),
None => 0u32.var_write_into(buf),
}
}
}
#[derive(Clone, Debug, McBuf, Default)] #[derive(Clone, Debug, McBuf, Default)]
pub struct Rotations { pub struct Rotations {
pub x: f32, pub x: f32,
@ -83,67 +105,6 @@ pub struct Rotations {
pub z: f32, pub z: f32,
} }
impl McBufReadable for EntityDataValue {
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
let data_type = u32::var_read_from(buf)?;
Ok(match data_type {
0 => EntityDataValue::Byte(u8::read_from(buf)?),
1 => EntityDataValue::Int(i32::var_read_from(buf)?),
2 => EntityDataValue::Float(f32::read_from(buf)?),
3 => EntityDataValue::String(String::read_from(buf)?),
4 => EntityDataValue::Component(Component::read_from(buf)?),
5 => EntityDataValue::OptionalComponent(Option::<Component>::read_from(buf)?),
6 => EntityDataValue::ItemStack(Slot::read_from(buf)?),
7 => EntityDataValue::Boolean(bool::read_from(buf)?),
8 => EntityDataValue::Rotations(Rotations::read_from(buf)?),
9 => EntityDataValue::BlockPos(BlockPos::read_from(buf)?),
10 => EntityDataValue::OptionalBlockPos(Option::<BlockPos>::read_from(buf)?),
11 => EntityDataValue::Direction(Direction::read_from(buf)?),
12 => EntityDataValue::OptionalUuid(Option::<Uuid>::read_from(buf)?),
13 => EntityDataValue::OptionalBlockState({
let val = u32::var_read_from(buf)?;
if val == 0 {
None
} else {
Some(BlockState::try_from(val - 1).unwrap_or_else(|_| {
warn!("Invalid block state ID {} in entity metadata", val - 1);
BlockState::Air
}))
}
}),
14 => EntityDataValue::CompoundTag(azalea_nbt::Tag::read_from(buf)?),
15 => EntityDataValue::Particle(Particle::read_from(buf)?),
16 => EntityDataValue::VillagerData(VillagerData::read_from(buf)?),
17 => EntityDataValue::OptionalUnsignedInt({
let val = u32::var_read_from(buf)?;
if val == 0 {
None
} else {
Some(val - 1)
}
}),
18 => EntityDataValue::Pose(Pose::read_from(buf)?),
19 => EntityDataValue::CatVariant(azalea_registry::CatVariant::read_from(buf)?),
20 => EntityDataValue::FrogVariant(azalea_registry::FrogVariant::read_from(buf)?),
21 => EntityDataValue::GlobalPos(GlobalPos::read_from(buf)?),
22 => {
EntityDataValue::PaintingVariant(azalea_registry::PaintingVariant::read_from(buf)?)
}
_ => {
return Err(BufReadError::UnexpectedEnumVariant {
id: data_type as i32,
})
}
})
}
}
impl McBufWritable for EntityDataValue {
fn write_into(&self, _buf: &mut impl Write) -> Result<(), std::io::Error> {
todo!();
}
}
#[derive(Clone, Debug, Copy, McBuf, Default)] #[derive(Clone, Debug, Copy, McBuf, Default)]
pub enum Pose { pub enum Pose {
#[default] #[default]
@ -157,14 +118,12 @@ pub enum Pose {
Dying, Dying,
} }
#[derive(Debug, Clone, McBuf, Default)] #[derive(Debug, Clone, McBuf)]
pub struct VillagerData { pub struct VillagerData {
pub kind: azalea_registry::VillagerType,
pub profession: azalea_registry::VillagerProfession,
#[var] #[var]
type_: u32, pub level: u32,
#[var]
profession: u32,
#[var]
level: u32,
} }
impl TryFrom<EntityMetadataItems> for Vec<EntityDataValue> { impl TryFrom<EntityMetadataItems> for Vec<EntityDataValue> {

View file

@ -2,7 +2,7 @@
// Don't change it manually! // Don't change it manually!
#![allow(clippy::clone_on_copy, clippy::derivable_impls)] #![allow(clippy::clone_on_copy, clippy::derivable_impls)]
use super::{EntityDataValue, Pose, Rotations, VillagerData}; use super::{EntityDataValue, OptionalUnsignedInt, Pose, Rotations, VillagerData};
use azalea_block::BlockState; use azalea_block::BlockState;
use azalea_chat::Component; use azalea_chat::Component;
use azalea_core::{BlockPos, Direction, Particle, Slot}; use azalea_core::{BlockPos, Direction, Particle, Slot};
@ -114,7 +114,7 @@ impl Default for AreaEffectCloud {
fn default() -> Self { fn default() -> Self {
Self { Self {
abstract_entity: Default::default(), abstract_entity: Default::default(),
radius: 0.5, radius: 3.0,
color: 0, color: 0,
waiting: false, waiting: false,
particle: Default::default(), particle: Default::default(),
@ -730,6 +730,119 @@ impl DerefMut for Boat {
} }
} }
#[derive(Debug, Clone)]
pub struct Camel {
pub abstract_animal: AbstractAnimal,
pub tamed: bool,
pub eating: bool,
pub standing: bool,
pub bred: bool,
pub saddled: bool,
pub owner_uuid: Option<Uuid>,
pub dash: bool,
pub last_pose_change_tick: i64,
}
impl Camel {
pub fn read(metadata: &mut VecDeque<EntityDataValue>) -> Option<Self> {
let abstract_animal = AbstractAnimal::read(metadata)?;
let bitfield = metadata.pop_front()?.into_byte().ok()?;
let tamed = bitfield & 0x2 != 0;
let eating = bitfield & 0x10 != 0;
let standing = bitfield & 0x20 != 0;
let bred = bitfield & 0x8 != 0;
let saddled = bitfield & 0x4 != 0;
let owner_uuid = metadata.pop_front()?.into_optional_uuid().ok()?;
let dash = metadata.pop_front()?.into_boolean().ok()?;
let last_pose_change_tick = metadata.pop_front()?.into_long().ok()?;
Some(Self {
abstract_animal,
tamed,
eating,
standing,
bred,
saddled,
owner_uuid,
dash,
last_pose_change_tick,
})
}
pub fn write(&self) -> Vec<EntityDataValue> {
let mut metadata = Vec::new();
metadata.extend(self.abstract_animal.write());
let mut bitfield = 0u8;
if self.tamed {
bitfield &= 0x2;
}
if self.eating {
bitfield &= 0x10;
}
if self.standing {
bitfield &= 0x20;
}
if self.bred {
bitfield &= 0x8;
}
if self.saddled {
bitfield &= 0x4;
}
metadata.push(EntityDataValue::Byte(bitfield));
metadata.push(EntityDataValue::OptionalUuid(self.owner_uuid.clone()));
metadata.push(EntityDataValue::Boolean(self.dash.clone()));
metadata.push(EntityDataValue::Long(self.last_pose_change_tick.clone()));
metadata
}
}
impl Default for Camel {
fn default() -> Self {
Self {
abstract_animal: Default::default(),
tamed: false,
eating: false,
standing: false,
bred: false,
saddled: false,
owner_uuid: None,
dash: false,
last_pose_change_tick: -52,
}
}
}
impl Camel {
pub fn set_index(&mut self, index: u8, value: EntityDataValue) -> Option<()> {
match index {
0..=16 => self.abstract_animal.set_index(index, value)?,
17 => {
let bitfield = value.into_byte().ok()?;
self.tamed = bitfield & 0x2 != 0;
self.eating = bitfield & 0x10 != 0;
self.standing = bitfield & 0x20 != 0;
self.bred = bitfield & 0x8 != 0;
self.saddled = bitfield & 0x4 != 0;
}
18 => self.owner_uuid = value.into_optional_uuid().ok()?,
19 => self.dash = value.into_boolean().ok()?,
20 => self.last_pose_change_tick = value.into_long().ok()?,
_ => {}
}
Some(())
}
}
impl Deref for Camel {
type Target = AbstractAnimal;
fn deref(&self) -> &Self::Target {
&self.abstract_animal
}
}
impl DerefMut for Camel {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.abstract_animal
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Cat { pub struct Cat {
pub abstract_tameable: AbstractTameable, pub abstract_tameable: AbstractTameable,
@ -1733,7 +1846,7 @@ impl DerefMut for EnderPearl {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Enderman { pub struct Enderman {
pub abstract_monster: AbstractMonster, pub abstract_monster: AbstractMonster,
pub carry_state: Option<BlockState>, pub carry_state: BlockState,
pub creepy: bool, pub creepy: bool,
pub stared_at: bool, pub stared_at: bool,
} }
@ -1741,7 +1854,7 @@ pub struct Enderman {
impl Enderman { impl Enderman {
pub fn read(metadata: &mut VecDeque<EntityDataValue>) -> Option<Self> { pub fn read(metadata: &mut VecDeque<EntityDataValue>) -> Option<Self> {
let abstract_monster = AbstractMonster::read(metadata)?; let abstract_monster = AbstractMonster::read(metadata)?;
let carry_state = metadata.pop_front()?.into_optional_block_state().ok()?; let carry_state = metadata.pop_front()?.into_block_state().ok()?;
let creepy = metadata.pop_front()?.into_boolean().ok()?; let creepy = metadata.pop_front()?.into_boolean().ok()?;
let stared_at = metadata.pop_front()?.into_boolean().ok()?; let stared_at = metadata.pop_front()?.into_boolean().ok()?;
Some(Self { Some(Self {
@ -1755,9 +1868,7 @@ impl Enderman {
pub fn write(&self) -> Vec<EntityDataValue> { pub fn write(&self) -> Vec<EntityDataValue> {
let mut metadata = Vec::new(); let mut metadata = Vec::new();
metadata.extend(self.abstract_monster.write()); metadata.extend(self.abstract_monster.write());
metadata.push(EntityDataValue::OptionalBlockState( metadata.push(EntityDataValue::BlockState(self.carry_state.clone()));
self.carry_state.clone(),
));
metadata.push(EntityDataValue::Boolean(self.creepy.clone())); metadata.push(EntityDataValue::Boolean(self.creepy.clone()));
metadata.push(EntityDataValue::Boolean(self.stared_at.clone())); metadata.push(EntityDataValue::Boolean(self.stared_at.clone()));
metadata metadata
@ -1768,7 +1879,7 @@ impl Default for Enderman {
fn default() -> Self { fn default() -> Self {
Self { Self {
abstract_monster: Default::default(), abstract_monster: Default::default(),
carry_state: None, carry_state: BlockState::Air,
creepy: false, creepy: false,
stared_at: false, stared_at: false,
} }
@ -1779,7 +1890,7 @@ impl Enderman {
pub fn set_index(&mut self, index: u8, value: EntityDataValue) -> Option<()> { pub fn set_index(&mut self, index: u8, value: EntityDataValue) -> Option<()> {
match index { match index {
0..=15 => self.abstract_monster.set_index(index, value)?, 0..=15 => self.abstract_monster.set_index(index, value)?,
16 => self.carry_state = value.into_optional_block_state().ok()?, 16 => self.carry_state = value.into_block_state().ok()?,
17 => self.creepy = value.into_boolean().ok()?, 17 => self.creepy = value.into_boolean().ok()?,
18 => self.stared_at = value.into_boolean().ok()?, 18 => self.stared_at = value.into_boolean().ok()?,
_ => {} _ => {}
@ -2213,7 +2324,7 @@ impl DerefMut for Fireball {
pub struct FireworkRocket { pub struct FireworkRocket {
pub abstract_entity: AbstractEntity, pub abstract_entity: AbstractEntity,
pub fireworks_item: Slot, pub fireworks_item: Slot,
pub attached_to_target: Option<u32>, pub attached_to_target: OptionalUnsignedInt,
pub shot_at_angle: bool, pub shot_at_angle: bool,
} }
@ -2248,7 +2359,7 @@ impl Default for FireworkRocket {
Self { Self {
abstract_entity: Default::default(), abstract_entity: Default::default(),
fireworks_item: Slot::Empty, fireworks_item: Slot::Empty,
attached_to_target: None, attached_to_target: OptionalUnsignedInt(None),
shot_at_angle: false, shot_at_angle: false,
} }
} }
@ -2464,7 +2575,7 @@ impl DerefMut for Fox {
pub struct Frog { pub struct Frog {
pub abstract_animal: AbstractAnimal, pub abstract_animal: AbstractAnimal,
pub variant: azalea_registry::FrogVariant, pub variant: azalea_registry::FrogVariant,
pub tongue_target: Option<u32>, pub tongue_target: OptionalUnsignedInt,
} }
impl Frog { impl Frog {
@ -2495,7 +2606,7 @@ impl Default for Frog {
Self { Self {
abstract_animal: Default::default(), abstract_animal: Default::default(),
variant: azalea_registry::FrogVariant::Temperate, variant: azalea_registry::FrogVariant::Temperate,
tongue_target: None, tongue_target: OptionalUnsignedInt(None),
} }
} }
} }
@ -6421,7 +6532,11 @@ impl Default for Villager {
Self { Self {
abstract_ageable: Default::default(), abstract_ageable: Default::default(),
unhappy_counter: 0, unhappy_counter: 0,
villager_data: Default::default(), villager_data: VillagerData {
kind: azalea_registry::VillagerType::Plains,
profession: azalea_registry::VillagerProfession::None,
level: 0,
},
} }
} }
} }
@ -7169,7 +7284,11 @@ impl Default for ZombieVillager {
Self { Self {
zombie: Default::default(), zombie: Default::default(),
converting: false, converting: false,
villager_data: Default::default(), villager_data: VillagerData {
kind: azalea_registry::VillagerType::Plains,
profession: azalea_registry::VillagerProfession::None,
level: 0,
},
} }
} }
} }
@ -7920,6 +8039,7 @@ pub enum EntityMetadata {
Bee(Bee), Bee(Bee),
Blaze(Blaze), Blaze(Blaze),
Boat(Boat), Boat(Boat),
Camel(Camel),
Cat(Cat), Cat(Cat),
CaveSpider(CaveSpider), CaveSpider(CaveSpider),
ChestBoat(ChestBoat), ChestBoat(ChestBoat),
@ -8047,6 +8167,7 @@ impl From<azalea_registry::EntityType> for EntityMetadata {
azalea_registry::EntityType::Bee => EntityMetadata::Bee(Bee::default()), azalea_registry::EntityType::Bee => EntityMetadata::Bee(Bee::default()),
azalea_registry::EntityType::Blaze => EntityMetadata::Blaze(Blaze::default()), azalea_registry::EntityType::Blaze => EntityMetadata::Blaze(Blaze::default()),
azalea_registry::EntityType::Boat => EntityMetadata::Boat(Boat::default()), azalea_registry::EntityType::Boat => EntityMetadata::Boat(Boat::default()),
azalea_registry::EntityType::Camel => EntityMetadata::Camel(Camel::default()),
azalea_registry::EntityType::Cat => EntityMetadata::Cat(Cat::default()), azalea_registry::EntityType::Cat => EntityMetadata::Cat(Cat::default()),
azalea_registry::EntityType::CaveSpider => { azalea_registry::EntityType::CaveSpider => {
EntityMetadata::CaveSpider(CaveSpider::default()) EntityMetadata::CaveSpider(CaveSpider::default())
@ -8270,6 +8391,7 @@ impl EntityMetadata {
EntityMetadata::Bee(entity) => entity.set_index(index, value), EntityMetadata::Bee(entity) => entity.set_index(index, value),
EntityMetadata::Blaze(entity) => entity.set_index(index, value), EntityMetadata::Blaze(entity) => entity.set_index(index, value),
EntityMetadata::Boat(entity) => entity.set_index(index, value), EntityMetadata::Boat(entity) => entity.set_index(index, value),
EntityMetadata::Camel(entity) => entity.set_index(index, value),
EntityMetadata::Cat(entity) => entity.set_index(index, value), EntityMetadata::Cat(entity) => entity.set_index(index, value),
EntityMetadata::CaveSpider(entity) => entity.set_index(index, value), EntityMetadata::CaveSpider(entity) => entity.set_index(index, value),
EntityMetadata::ChestBoat(entity) => entity.set_index(index, value), EntityMetadata::ChestBoat(entity) => entity.set_index(index, value),
@ -8396,6 +8518,7 @@ impl Deref for EntityMetadata {
EntityMetadata::Bee(entity) => entity, EntityMetadata::Bee(entity) => entity,
EntityMetadata::Blaze(entity) => entity, EntityMetadata::Blaze(entity) => entity,
EntityMetadata::Boat(entity) => entity, EntityMetadata::Boat(entity) => entity,
EntityMetadata::Camel(entity) => entity,
EntityMetadata::Cat(entity) => entity, EntityMetadata::Cat(entity) => entity,
EntityMetadata::CaveSpider(entity) => entity, EntityMetadata::CaveSpider(entity) => entity,
EntityMetadata::ChestBoat(entity) => entity, EntityMetadata::ChestBoat(entity) => entity,
@ -8520,6 +8643,7 @@ impl DerefMut for EntityMetadata {
EntityMetadata::Bee(entity) => entity, EntityMetadata::Bee(entity) => entity,
EntityMetadata::Blaze(entity) => entity, EntityMetadata::Blaze(entity) => entity,
EntityMetadata::Boat(entity) => entity, EntityMetadata::Boat(entity) => entity,
EntityMetadata::Camel(entity) => entity,
EntityMetadata::Cat(entity) => entity, EntityMetadata::Cat(entity) => entity,
EntityMetadata::CaveSpider(entity) => entity, EntityMetadata::CaveSpider(entity) => entity,
EntityMetadata::ChestBoat(entity) => entity, EntityMetadata::ChestBoat(entity) => entity,

View file

@ -73,7 +73,7 @@
//! } //! }
//! ``` //! ```
//! //!
//! [`azalea_client`]: https://crates.io/crates/azalea-client //! [`azalea_client`]: https://docs.rs/azalea-client
#![feature(trait_upcasting)] #![feature(trait_upcasting)]
#![feature(async_closure)] #![feature(async_closure)]

View file

@ -42,7 +42,7 @@ async fn main() -> anyhow::Result<()> {
let mut accounts = Vec::new(); let mut accounts = Vec::new();
let mut states = Vec::new(); let mut states = Vec::new();
for i in 0..7 { for i in 0..1 {
accounts.push(Account::offline(&format!("bot{}", i))); accounts.push(Account::offline(&format!("bot{}", i)));
states.push(State::default()); states.push(State::default());
} }

View file

@ -6,14 +6,42 @@ The directory name doesn't start with `azalea-` because it's not a Rust crate.
- Python 3.8+ - Python 3.8+
- Java 17+ - Java 17+
- Gradle - Maven
## Usage ## Usage
Generate packet:\ Generate packet:\
`python newpacket.py [packet id] [clientbound or serverbound] \[game/handshake/login/status\]`\ `python newpacket.py [packet id] [clientbound or serverbound] [game/handshake/login/status]`\
This will create a new file in the `azalea-protocol/src/packets/\[state\] directory`. You will probably have to manually fix up the auto generated code. This will create a new file in the `azalea-protocol/src/packets/[state] directory`. You will probably have to manually fix up the auto generated code.
## Updating to a new Minecraft version
First, run `python migrate.py [new version]`. This will run a script that automatically updates as much as it can, including:
- Adding, removing, and updating packets in azalea-protocol (limited)
- Updating supported version in README.md
- Updating the `PROTOCOL_VERSION` variable in azalea-protocol
- Generating blocks in azalea-block
- Generating block shapes in azalea-physics
- Generating registries in azalea-registries
- Updating en_us.json in azalea-language
- Generating entity metadata structs and parsers in azalea-world
If you're lucky, that's all you're going to have to do.
Look at the diff (`git diff`) and type-check the code (`cargo check`) to make sure everything is right. In the diff, specifically look for new comments that have "TODO".
If a packet is incorrect, you'll want to find it in the Minecraft source. The name of the struct should be the same or similar as the class in the vanilla source. Now, you'll have to manually write the struct for the packet. If the packet existed in the version before and it's just being updated, you can compare against that to see what was updated. Note that if a packet is particularly complicated, you may have to implement McBufReadable and McBufWritable, but most of the time the `#[derive(McBuf)]` macro will be able to generate the impls correctly. Look at other existing packets as reference if you're confused.
Finally, test by making a bot join a world. Specifically, you'll want to test the things that were updated in the version. Setting the RUST_LOG environment variable to `debug` or `trace` may help you find the source of crashes (trace shows the first few hundred bytes for every packet received so it's typically more useful, but it may log more than you want).
If it all works, make a pull request. If the version you updated to is a snapshot, make it a draft PR (the main branch is for release versions).
## Extracting new data
At the time of writing, the following data generators are used:
- [Vanilla data generator](https://wiki.vg/Data_Generators)
- [Burger](https://github.com/Pokechu22/Burger)
- [PixLyzer](https://gitlab.bixilon.de/bixilon/pixlyzer)
Some things can be obtained from multiple generators. You should prefer them by the order above (the vanilla generator is the most reliable).
Migrate to a new Minecraft version:\
`python migrate.py [new version]`\
This updates all the packet ids in `azalea-protocol/src/packets/mod.rs` and creates all the new packets.

View file

@ -9,8 +9,10 @@ import lib.utils
version_id = lib.code.version.get_version_id() version_id = lib.code.version.get_version_id()
shape_datas = lib.extract.get_generator_mod_data( shape_datas = lib.extract.get_pixlyzer_data(
version_id, 'blockCollisionShapes') version_id, 'shapes')
pixlyzer_block_datas = lib.extract.get_pixlyzer_data(
version_id, 'blocks')
mappings = lib.download.get_mappings_for_version(version_id) mappings = lib.download.get_mappings_for_version(version_id)
block_states_burger = lib.extract.get_block_states_burger(version_id) block_states_burger = lib.extract.get_block_states_burger(version_id)
@ -21,7 +23,7 @@ lib.code.blocks.generate_blocks(
block_states_burger, block_states_report, ordered_blocks, mappings) block_states_burger, block_states_report, ordered_blocks, mappings)
lib.code.shapes.generate_block_shapes( lib.code.shapes.generate_block_shapes(
shape_datas['blocks'], shape_datas['shapes'], block_states_report, block_states_burger, mappings) pixlyzer_block_datas, shape_datas['shapes'], shape_datas['aabbs'], block_states_report, block_states_burger, mappings)
lib.code.utils.fmt() lib.code.utils.fmt()

View file

@ -3,7 +3,6 @@ import lib.code.entity
import lib.code.utils import lib.code.utils
import lib.download import lib.download
import lib.extract import lib.extract
import sys
version_id = lib.code.version.get_version_id() version_id = lib.code.version.get_version_id()

13
codegen/genlanguage.py Normal file
View file

@ -0,0 +1,13 @@
import lib.code.language
import lib.code.version
import lib.code.utils
import lib.download
import lib.extract
import lib.utils
version_id = lib.code.version.get_version_id()
language = lib.extract.get_en_us_lang(version_id)
lib.code.language.write_language(language)
print('Done!')

View file

@ -20,7 +20,6 @@ def generate_blocks(blocks_burger: dict, blocks_report: dict, ordered_blocks: li
new_make_block_states_macro_code = [] new_make_block_states_macro_code = []
new_make_block_states_macro_code.append('make_block_states! {') new_make_block_states_macro_code.append('make_block_states! {')
# Find properties # Find properties
properties = {} properties = {}
@ -84,7 +83,6 @@ def generate_blocks(blocks_burger: dict, blocks_report: dict, ordered_blocks: li
new_make_block_states_macro_code.append( new_make_block_states_macro_code.append(
f' "{property_name}" => {property_shape_code},') f' "{property_name}" => {property_shape_code},')
new_make_block_states_macro_code.append(' },') new_make_block_states_macro_code.append(' },')
# Block codegen # Block codegen
@ -101,7 +99,6 @@ def generate_blocks(blocks_burger: dict, blocks_report: dict, ordered_blocks: li
if state.get('default'): if state.get('default'):
default_property_variants = state.get('properties', {}) default_property_variants = state.get('properties', {})
properties_code = '{' properties_code = '{'
for property_name in list(block_data_report.get('properties', {}).keys()): for property_name in list(block_data_report.get('properties', {}).keys()):
property_burger = None property_burger = None
@ -163,6 +160,7 @@ def generate_blocks(blocks_burger: dict, blocks_report: dict, ordered_blocks: li
with open(BLOCKS_RS_DIR, 'w') as f: with open(BLOCKS_RS_DIR, 'w') as f:
f.write('\n'.join(new_code)) f.write('\n'.join(new_code))
def get_property_struct_name(property: Optional[dict], block_data_burger: dict, property_variants: list[str], mappings: Mappings) -> str: def get_property_struct_name(property: Optional[dict], block_data_burger: dict, property_variants: list[str], mappings: Mappings) -> str:
# these are hardcoded because otherwise they cause conflicts # these are hardcoded because otherwise they cause conflicts
# some names inspired by https://github.com/feather-rs/feather/blob/main/feather/blocks/src/generated/table.rs # some names inspired by https://github.com/feather-rs/feather/blob/main/feather/blocks/src/generated/table.rs
@ -184,16 +182,23 @@ def get_property_struct_name(property: Optional[dict], block_data_burger: dict,
return 'ChestType' return 'ChestType'
if property_variants == ['compare', 'subtract']: if property_variants == ['compare', 'subtract']:
return 'ComparatorType' return 'ComparatorType'
if 'harp' in property_variants and 'didgeridoo' in property_variants:
return 'Sound'
if property is None: if property is None:
return ''.join(map(to_camel_case, property_variants)) return ''.join(map(to_camel_case, property_variants))
property_name = None
for class_name in [block_data_burger['class']] + block_data_burger['super']: for class_name in [block_data_burger['class']] + block_data_burger['super']:
property_name = mappings.get_field( property_name = mappings.get_field(
class_name, property['field_name']) class_name, property['field_name'])
if property_name: if property_name:
break break
if property_name is None:
if 'declared_in' in property:
property_name = mappings.get_field(
property['declared_in'], property['field_name'])
if property_name is None:
property_name = property['name']
assert property_name assert property_name
property_name = to_camel_case(property_name.lower()) property_name = to_camel_case(property_name.lower())
if property['type'] == 'int': if property['type'] == 'int':

View file

@ -11,7 +11,8 @@ def generate_entity_metadata(burger_entity_data: dict, mappings: Mappings):
# TODO: auto generate this and use it for generating the EntityDataValue enum # TODO: auto generate this and use it for generating the EntityDataValue enum
metadata_types = [ metadata_types = [
{'name': 'Byte', 'type': 'u8'}, {'name': 'Byte', 'type': 'u8'},
{'name': 'Int', 'type': 'i32'}, {'name': 'Int', 'type': 'i32', 'var': True},
{'name': 'Long', 'type': 'i64'},
{'name': 'Float', 'type': 'f32'}, {'name': 'Float', 'type': 'f32'},
{'name': 'String', 'type': 'String'}, {'name': 'String', 'type': 'String'},
{'name': 'Component', 'type': 'Component'}, {'name': 'Component', 'type': 'Component'},
@ -23,11 +24,11 @@ def generate_entity_metadata(burger_entity_data: dict, mappings: Mappings):
{'name': 'OptionalBlockPos', 'type': 'Option<BlockPos>'}, {'name': 'OptionalBlockPos', 'type': 'Option<BlockPos>'},
{'name': 'Direction', 'type': 'Direction'}, {'name': 'Direction', 'type': 'Direction'},
{'name': 'OptionalUuid', 'type': 'Option<Uuid>'}, {'name': 'OptionalUuid', 'type': 'Option<Uuid>'},
{'name': 'OptionalBlockState', 'type': 'Option<BlockState>'}, {'name': 'BlockState', 'type': 'BlockState'},
{'name': 'CompoundTag', 'type': 'azalea_nbt::Tag'}, {'name': 'CompoundTag', 'type': 'azalea_nbt::Tag'},
{'name': 'Particle', 'type': 'Particle'}, {'name': 'Particle', 'type': 'Particle'},
{'name': 'VillagerData', 'type': 'VillagerData'}, {'name': 'VillagerData', 'type': 'VillagerData'},
{'name': 'OptionalUnsignedInt', 'type': 'Option<u32>'}, {'name': 'OptionalUnsignedInt', 'type': 'OptionalUnsignedInt'},
{'name': 'Pose', 'type': 'Pose'}, {'name': 'Pose', 'type': 'Pose'},
{'name': 'CatVariant', 'type': 'azalea_registry::CatVariant'}, {'name': 'CatVariant', 'type': 'azalea_registry::CatVariant'},
{'name': 'FrogVariant', 'type': 'azalea_registry::FrogVariant'}, {'name': 'FrogVariant', 'type': 'azalea_registry::FrogVariant'},
@ -40,7 +41,8 @@ def generate_entity_metadata(burger_entity_data: dict, mappings: Mappings):
code.append("// Don't change it manually!") code.append("// Don't change it manually!")
code.append('') code.append('')
code.append('#![allow(clippy::clone_on_copy, clippy::derivable_impls)]') code.append('#![allow(clippy::clone_on_copy, clippy::derivable_impls)]')
code.append('use super::{EntityDataValue, Rotations, VillagerData, Pose};') code.append(
'use super::{EntityDataValue, Rotations, VillagerData, OptionalUnsignedInt, Pose};')
code.append('use azalea_block::BlockState;') code.append('use azalea_block::BlockState;')
code.append('use azalea_chat::Component;') code.append('use azalea_chat::Component;')
code.append('use azalea_core::{BlockPos, Direction, Particle, Slot};') code.append('use azalea_core::{BlockPos, Direction, Particle, Slot};')
@ -185,6 +187,8 @@ def generate_entity_metadata(burger_entity_data: dict, mappings: Mappings):
default = 'azalea_registry::PaintingVariant::Kebab' default = 'azalea_registry::PaintingVariant::Kebab'
elif type_name == 'FrogVariant': elif type_name == 'FrogVariant':
default = 'azalea_registry::FrogVariant::Temperate' default = 'azalea_registry::FrogVariant::Temperate'
elif type_name == 'VillagerData':
default = 'VillagerData { kind: azalea_registry::VillagerType::Plains, profession: azalea_registry::VillagerProfession::None, level: 0 }'
else: else:
default = 'Default::default()' default = 'Default::default()'
else: else:
@ -200,11 +204,11 @@ def generate_entity_metadata(burger_entity_data: dict, mappings: Mappings):
elif type_name == 'OptionalUuid': elif type_name == 'OptionalUuid':
default = f'Some(uuid::uuid!({default}))' if default != 'Empty' else 'None' default = f'Some(uuid::uuid!({default}))' if default != 'Empty' else 'None'
elif type_name == 'OptionalUnsignedInt': elif type_name == 'OptionalUnsignedInt':
default = f'Some({default})' if default != 'Empty' else 'None' default = f'OptionalUnsignedInt(Some({default}))' if default != 'Empty' else 'OptionalUnsignedInt(None)'
elif type_name == 'ItemStack': elif type_name == 'ItemStack':
default = f'Slot::Present({default})' if default != 'Empty' else 'Slot::Empty' default = f'Slot::Present({default})' if default != 'Empty' else 'Slot::Empty'
elif type_name == 'OptionalBlockState': elif type_name == 'BlockState':
default = f'Some({default})' if default != 'Empty' else 'None' default = f'{default}' if default != 'Empty' else 'BlockState::Air'
elif type_name == 'OptionalComponent': elif type_name == 'OptionalComponent':
default = f'Some({default})' if default != 'Empty' else 'None' default = f'Some({default})' if default != 'Empty' else 'None'
elif type_name == 'CompoundTag': elif type_name == 'CompoundTag':

View file

@ -0,0 +1,8 @@
from lib.utils import get_dir_location
import json
LANGUAGE_DIR = get_dir_location('../azalea-language/src/en_us.json')
def write_language(contents: dict):
with open(LANGUAGE_DIR, 'w') as f:
f.write(json.dumps(contents, indent=' '))

View file

@ -247,9 +247,10 @@ def burger_instruction_to_code(instructions: list[dict], index: int, generated_p
# figure out what kind of iterator it is # figure out what kind of iterator it is
loop_instructions = next_next_instruction['instructions'] loop_instructions = next_next_instruction['instructions']
if len(loop_instructions) == 2: if len(loop_instructions) == 2:
entry_type_rs, is_var, uses, extra_code = burger_type_to_rust_type( entry_type_rs, is_var, value_uses, extra_code = burger_type_to_rust_type(
loop_instructions[1]['type'], None, loop_instructions[1], mappings, obfuscated_class_name) loop_instructions[1]['type'], None, loop_instructions[1], mappings, obfuscated_class_name)
field_type_rs = f'Vec<{entry_type_rs}>' field_type_rs = f'Vec<{entry_type_rs}>'
uses.update(value_uses)
elif len(loop_instructions) == 3: elif len(loop_instructions) == 3:
is_map = loop_instructions[0]['type'].startswith( is_map = loop_instructions[0]['type'].startswith(
'Map.Entry<') 'Map.Entry<')

View file

@ -9,8 +9,45 @@ REGISTRIES_DIR = get_dir_location('../azalea-registry/src/lib.rs')
def generate_registries(registries: dict): def generate_registries(registries: dict):
code = [] code = []
code.append('use azalea_registry_macros::registry;') code.append('''// This file is automatically generated in codegen/lib/code/registry.py
code.append('')
use azalea_buf::{BufReadError, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable};
use azalea_registry_macros::registry;
use std::io::{Cursor, Write};
pub trait Registry
where
Self: Sized,
{
fn from_u32(value: u32) -> Option<Self>;
fn to_u32(&self) -> u32;
}
/// A registry that might not be present. This is transmitted as a single
/// varint in the protocol.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct OptionalRegistry<T: Registry>(Option<T>);
impl<T: Registry> McBufReadable for OptionalRegistry<T> {
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
Ok(OptionalRegistry(match u32::var_read_from(buf)? {
0 => None,
value => Some(
T::from_u32(value - 1)
.ok_or(BufReadError::UnexpectedEnumVariant { id: value as i32 })?,
),
}))
}
}
impl<T: Registry> McBufWritable for OptionalRegistry<T> {
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
match &self.0 {
None => 0u32.var_write_into(buf),
Some(value) => (value.to_u32() + 1).var_write_into(buf),
}
}
}
''')
for registry_name, registry in registries.items(): for registry_name, registry in registries.items():
# registry!(Block, { # registry!(Block, {

View file

@ -7,8 +7,8 @@ COLLISION_BLOCKS_RS_DIR = get_dir_location(
'../azalea-physics/src/collision/blocks.rs') '../azalea-physics/src/collision/blocks.rs')
def generate_block_shapes(blocks: dict, shapes: dict, block_states_report, block_datas_burger, mappings: Mappings): def generate_block_shapes(blocks: dict, shapes: dict, aabbs: dict, block_states_report, block_datas_burger, mappings: Mappings):
blocks, shapes = simplify_shapes(blocks, shapes) blocks, shapes = simplify_shapes(blocks, shapes, aabbs)
code = generate_block_shapes_code( code = generate_block_shapes_code(
blocks, shapes, block_states_report, block_datas_burger, mappings) blocks, shapes, block_states_report, block_datas_burger, mappings)
@ -16,33 +16,54 @@ def generate_block_shapes(blocks: dict, shapes: dict, block_states_report, block
f.write(code) f.write(code)
def simplify_shapes(blocks: dict, shapes: dict): def simplify_shapes(blocks: dict, shapes: dict, aabbs: dict):
shape_to_new_id = {}
new_id_increment = 0 new_id_increment = 0
new_shapes = {} new_shapes = {}
old_id_to_new_id = {} old_id_to_new_id = {}
for shape_id, shape in sorted(shapes.items(), key=lambda shape: int(shape[0])): old_id_to_new_id[None] = 0
# tuples are hashable new_shapes[0] = ()
shape_as_tuple = tuple(map(tuple, shape)) new_id_increment += 1
if shape_as_tuple not in shape_to_new_id:
shape_to_new_id[shape_as_tuple] = new_id_increment used_shape_ids = set()
# determine the used shape ids
for block_id, block_data in blocks.items():
block_id = block_id.split(':')[-1]
block_shapes = [state.get('collision_shape')
for state in block_data['states'].values()]
for s in block_shapes:
used_shape_ids.add(s)
for shape_id, shape in enumerate(shapes):
if shape_id not in used_shape_ids: continue
# pixlyzer gives us shapes as an index or list of indexes into the
# aabbs list
# and aabbs look like { "from": number or [x, y, z], "to": (number or vec3) }
# convert them to [x1, y1, z1, x2, y2, z2]
shape = [shape] if isinstance(shape, int) else shape
shape = [aabbs[shape_aabb] for shape_aabb in shape]
shape = tuple([(
(tuple(part['from']) if isinstance(
part['from'], list) else ((part['from'],)*3))
+ (tuple(part['to']) if isinstance(part['to'], list)
else ((part['to'],)*3))
) for part in shape])
old_id_to_new_id[shape_id] = new_id_increment old_id_to_new_id[shape_id] = new_id_increment
new_shapes[new_id_increment] = shape new_shapes[new_id_increment] = shape
new_id_increment += 1 new_id_increment += 1
else:
old_id_to_new_id[shape_id] = shape_to_new_id[shape_as_tuple]
# now map the blocks to the new shape ids # now map the blocks to the new shape ids
for block_id, shape_ids in blocks.items(): new_blocks = {}
if isinstance(shape_ids, int): for block_id, block_data in blocks.items():
blocks[block_id] = old_id_to_new_id[str(shape_ids)] block_id = block_id.split(':')[-1]
else: block_shapes = [state.get('collision_shape')
blocks[block_id] = [old_id_to_new_id[str(shape_id)] for state in block_data['states'].values()]
for shape_id in shape_ids] new_blocks[block_id] = [old_id_to_new_id[shape_id]
for shape_id in block_shapes]
return blocks, new_shapes return new_blocks, new_shapes
def generate_block_shapes_code(blocks: dict, shapes: dict, block_states_report, block_datas_burger, mappings: Mappings): def generate_block_shapes_code(blocks: dict, shapes: dict, block_states_report, block_datas_burger, mappings: Mappings):
@ -116,7 +137,7 @@ def generate_code_for_shape(shape_id: str, parts: list[list[float]]):
code = '' code = ''
code += f'static SHAPE{shape_id}: Lazy<VoxelShape> = Lazy::new(|| {{' code += f'static SHAPE{shape_id}: Lazy<VoxelShape> = Lazy::new(|| {{'
steps = [] steps = []
if parts == []: if parts == ():
steps.append('collision::empty_shape()') steps.append('collision::empty_shape()')
else: else:
steps.append(f'collision::box_shape({make_arguments(parts[0])})') steps.append(f'collision::box_shape({make_arguments(parts[0])})')

View file

@ -63,6 +63,12 @@ def burger_type_to_rust_type(burger_type, field_name: Optional[str] = None, inst
elif burger_type == 'metadata': elif burger_type == 'metadata':
field_type_rs = 'EntityMetadata' field_type_rs = 'EntityMetadata'
uses.add('azalea_entity::EntityMetadata') uses.add('azalea_entity::EntityMetadata')
elif burger_type == 'bitset':
if instruction:
length = instruction['length']
field_type_rs = f'todo!("fixed bitset of length {length}")'
else:
field_type_rs = 'todo!("fixed bitset")'
elif burger_type == 'abstract': elif burger_type == 'abstract':
field_type_rs = 'todo!()' field_type_rs = 'todo!()'
elif burger_type == 'enum': elif burger_type == 'enum':

View file

@ -19,15 +19,15 @@ def get_burger():
f'cd {get_dir_location("downloads")} && git clone https://github.com/pokechu22/Burger && cd Burger && git pull') f'cd {get_dir_location("downloads")} && git clone https://github.com/pokechu22/Burger && cd Burger && git pull')
print('\033[92mInstalling dependencies...\033[m') print('\033[92mInstalling dependencies...\033[m')
os.system('cd downloads/Burger && pip install six jawa') os.system(f'cd {get_dir_location("downloads")}/Burger && pip install six jawa')
def get_generator_mod(): def get_pixlyzer():
if not os.path.exists(get_dir_location('downloads/minecraft-data-generator-server')): if not os.path.exists(get_dir_location('downloads/pixlyzer')):
print('\033[92mDownloading u9g/minecraft-data-generator-server...\033[m') print('\033[92mDownloading bixilon/pixlyzer...\033[m')
os.system( os.system(
f'cd {get_dir_location("downloads")} && git clone https://github.com/u9g/minecraft-data-generator-server && cd minecraft-data-generator-server && git pull') f'cd {get_dir_location("downloads")} && git clone https://gitlab.bixilon.de/bixilon/pixlyzer.git && cd pixlyzer && git pull')
return get_dir_location('downloads/minecraft-data-generator-server') return get_dir_location('downloads/pixlyzer')
def get_version_manifest(): def get_version_manifest():
@ -180,4 +180,4 @@ def clear_version_cache():
os.system( os.system(
f'cd {get_dir_location("downloads/Burger")} && git pull') f'cd {get_dir_location("downloads/Burger")} && git pull')
os.system( os.system(
f'cd {get_dir_location("downloads/minecraft-data-generator-server")} && git pull') f'cd {get_dir_location("downloads/pixlyzer")} && git pull')

View file

@ -1,9 +1,11 @@
# Extracting data from the Minecraft jars # Extracting data from the Minecraft jars
from lib.download import get_server_jar, get_burger, get_client_jar, get_generator_mod, get_yarn_data, get_fabric_api_versions, get_fabric_loader_versions from lib.download import get_server_jar, get_burger, get_client_jar, get_pixlyzer, get_yarn_data, get_fabric_api_versions, get_fabric_loader_versions
from lib.utils import get_dir_location from lib.utils import get_dir_location
from zipfile import ZipFile
import subprocess import subprocess
import json import json
import sys
import re import re
import os import os
@ -59,103 +61,185 @@ def determine_python_command():
'Couldn\'t determine python command to use to run burger with!') 'Couldn\'t determine python command to use to run burger with!')
def run_python_command_and_download_deps(command):
print('>', command)
for _ in range(10):
p = subprocess.Popen(
command,
stderr=subprocess.PIPE,
shell=True
)
stderr = b''
while True:
data = p.stderr.read()
if data == b'':
break
print(data.decode(), end='', flush=True)
stderr += data
regex_match = re.search(
r'ModuleNotFoundError: No module named \'(\w+?)\'', stderr.decode())
if not regex_match:
out, err = p.communicate()
if out:
print(out)
if err:
print(err)
break
missing_lib = regex_match.group(1)
print('Missing required lib:', missing_lib)
os.system(
f'{determine_python_command()} -m pip install {missing_lib}')
print('ok')
def get_burger_data_for_version(version_id: str): def get_burger_data_for_version(version_id: str):
if not os.path.exists(get_dir_location(f'downloads/burger-{version_id}.json')): if not os.path.exists(get_dir_location(f'downloads/burger-{version_id}.json')):
get_burger() get_burger()
get_client_jar(version_id) get_client_jar(version_id)
for _ in range(10): print('\033[92mRunning Burger...\033[m')
r = subprocess.run( run_python_command_and_download_deps(
f'cd {get_dir_location("downloads/Burger")} && {determine_python_command()} munch.py ../client-{version_id}.jar --output ../burger-{version_id}.json', f'cd {get_dir_location("downloads/Burger")} && {determine_python_command()} munch.py {get_dir_location("downloads")}/client-{version_id}.jar --output {get_dir_location("downloads")}/burger-{version_id}.json'
capture_output=True,
shell=True
) )
regex_match = re.search(
r'ModuleNotFoundError: No module named \'(\w+?)\'', r.stderr.decode())
if not regex_match:
break
missing_lib = regex_match.group(1)
print('Missing required lib for Burger:', missing_lib)
os.system(
f'{determine_python_command()} -m pip install {missing_lib}')
with open(get_dir_location(f'downloads/burger-{version_id}.json'), 'r') as f: with open(get_dir_location(f'downloads/burger-{version_id}.json'), 'r') as f:
return json.load(f) return json.load(f)
def get_generator_mod_data(version_id: str, category: str): def get_pixlyzer_data(version_id: str, category: str):
''' '''
Gets data from u9g's data generator mod. Note that this is not very stable, and it requires Yarn to release updates first. Gets data from Pixlyzer. Note that this requires Yarn to release updates first.
''' '''
target_dir = get_dir_location(f'downloads/generator-mod-{version_id}') target_dir = get_dir_location(f'downloads/pixlyzer-{version_id}')
if not os.path.exists(get_dir_location(target_dir)): if not os.path.exists(get_dir_location(target_dir)):
generator_mod_dir = get_generator_mod() pixlyzer_dir = get_pixlyzer()
yarn_data = get_yarn_data(version_id) # for some reason pixlyzer doesn't work right unless the mvn clean
if not yarn_data: # instruction looks like that
raise Exception( # and pixlyzer.py doesn't do it right
'Fabric/Yarn hasn\'t been updated to this version yet.')
# looks like 1.19+build.1
yarn_version = yarn_data['version']
fabric_api_version = get_fabric_api_versions()[-1] # map jar + download dependencies
fabric_loader_version = get_fabric_loader_versions()[0] run_python_command_and_download_deps(
f'cd {pixlyzer_dir}/wrapper && {determine_python_command()} PixLyzer.py --only-version={version_id} --dont-compile --only-map'
# the mod has the minecraft version hard-coded by default, so we just change the gradle.properties and fabric.mod.json
with open(get_dir_location(f'{generator_mod_dir}/gradle.properties'), 'r') as f:
lines = f.readlines()
with open(get_dir_location(f'{generator_mod_dir}/gradle.properties'), 'w') as f:
for line in lines:
if line.startswith('minecraft_version='):
line = f'minecraft_version={version_id}\n'
if line.startswith('yarn_mappings='):
line = f'yarn_mappings={yarn_version}\n'
if line.startswith('fabric_version='):
line = f'fabric_version={fabric_api_version}\n'
if line.startswith('loader_version='):
line = f'loader_version={fabric_loader_version}\n'
f.write(line)
# edit the fabric.mod.json to support this version
with open(get_dir_location(f'{generator_mod_dir}/src/main/resources/fabric.mod.json'), 'r') as f:
fabric_mod_json = json.load(f)
fabric_mod_json['depends']['minecraft'] = '*'
with open(get_dir_location(f'{generator_mod_dir}/src/main/resources/fabric.mod.json'), 'w') as f:
json.dump(fabric_mod_json, f, indent=2)
try:
os.system(f'cd {generator_mod_dir} && chmod u+x ./gradlew')
except:
pass
# set the server port to something other than 25565 so it doesn't
# conflict with anything else that's running
try:
os.makedirs(get_dir_location(f'{generator_mod_dir}/run'))
except:
pass
with open(get_dir_location(f'{generator_mod_dir}/run/server.properties'), 'w') as f:
f.write('server-port=56553')
# make sure we have perms to run this file
# (on windows it fails but keeps running)
os.system(f'cd {generator_mod_dir} && chmod u+x ./gradlew')
try:
subprocess.run(
[f'cd {generator_mod_dir} && ./gradlew runServer'],
check=True,
shell=True
) )
except Exception as e: # update the pom.xml <dependencies>
os.system(f'cd {generator_mod_dir} && gradlew runServer') # list directories in pixlyzer/wrapper/data/data/dependencies/libraries
pom_xml_dependencies = '''<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test-junit</artifactId>
<version>1.7.21</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>net.minecraft</groupId>
<artifactId>client</artifactId>
<version>${minecraft.version}</version>
<scope>system</scope>
<systemPath>${project.basedir}/wrapper/data/data/${minecraft.version}_yarn/${minecraft.version}-exhibitionism.jar</systemPath>
</dependency>
<dependency>
<groupId>de.bixilon</groupId>
<artifactId>mbf-kotlin</artifactId>
<version>0.2.1</version>
</dependency>
<dependency>
<groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId>
<version>3.3</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.0</version>
</dependency>
<dependency>
<groupId>de.bixilon</groupId>
<artifactId>kutil</artifactId>
<version>1.17.1</version>
</dependency>'''
# walk dir f'{pixlyzer_dir}/wrapper/data/data/dependencies/libraries'
for root, dirs, files in os.walk(f'{pixlyzer_dir}/wrapper/data/data/dependencies/libraries'):
for file in files:
full_path = os.path.join(
root.replace('\\', '/').replace(
f'{pixlyzer_dir}/wrapper/data/data/dependencies/libraries/'.replace('\\', '/'), ''),
file
).replace('\\', '/')
print(full_path)
if not full_path.endswith('.jar'):
continue
split_path = full_path.split('/')
group = ''
for group_index in range(0, len(split_path) - 3):
group += split_path[group_index] + '.'
if group.endswith('.'):
group = group[:-1]
artifact = split_path[-3]
version = split_path[-2]
path = '${project.basedir}/wrapper/data/data/dependencies/libraries/' + full_path
pom_xml_dependencies += """
<dependency>
<groupId>""" + group + """</groupId>
<artifactId>""" + artifact + """</artifactId>
<version>""" + version + """</version>
<scope>system</scope>
<systemPath>""" + path + """</systemPath>
</dependency>
"""
print('pom_xml_dependencies', pom_xml_dependencies)
assert pom_xml_dependencies != ''
pom_xml = open(f'{pixlyzer_dir}/pom.xml', 'r').read()
pom_xml = re.sub(
'<dependencies>.*?</dependencies>', f'<dependencies>{pom_xml_dependencies}</dependencies>', pom_xml, flags=re.DOTALL)
open(f'{pixlyzer_dir}/pom.xml', 'w').write(pom_xml)
# compile
os.system(
f'cd {pixlyzer_dir} && mvn clean -Dmaven.repo.local=. verify')
# run pixlyzer.py again lol
run_python_command_and_download_deps(
f'cd {pixlyzer_dir}/wrapper && {determine_python_command()} PixLyzer.py --only-version={version_id} --no-compile'
)
source_dir = get_dir_location(
f'{pixlyzer_dir}/wrapper/data/version/{version_id}')
if not os.path.exists(source_dir):
print('PixLyzer failed, no output!')
exit()
if os.path.exists(target_dir): if os.path.exists(target_dir):
os.unlink(target_dir) os.unlink(target_dir)
os.rename( os.rename(
get_dir_location( source_dir,
f'{generator_mod_dir}/run/minecraft-data/{version_id}'),
target_dir target_dir
) )
with open(f'{target_dir}/{category}.json', 'r') as f: with open(f'{target_dir}/{category}.min.json', 'r') as f:
return json.load(f) return json.load(f)
def get_file_from_jar(version_id: str, file_dir: str):
get_client_jar(version_id)
with ZipFile(get_dir_location(f'downloads/client-{version_id}.jar')) as z:
with z.open(file_dir) as f:
return f.read()
def get_en_us_lang(version_id: str):
return json.loads(
get_file_from_jar(version_id, 'assets/minecraft/lang/en_us.json')
)

View file

@ -1,8 +1,11 @@
from lib.code.packet import fix_state from lib.code.packet import fix_state
from lib.utils import PacketIdentifier, group_packets from lib.utils import PacketIdentifier, group_packets
import lib.code.language
import lib.code.registry
import lib.code.version import lib.code.version
import lib.code.blocks import lib.code.blocks
import lib.code.packet import lib.code.packet
import lib.code.shapes
import lib.code.utils import lib.code.utils
import lib.download import lib.download
import lib.extract import lib.extract
@ -101,7 +104,6 @@ for packet in added_or_changed_packets:
lib.code.version.set_protocol_version( lib.code.version.set_protocol_version(
new_burger_data[0]['version']['protocol']) new_burger_data[0]['version']['protocol'])
lib.code.version.set_version_id(new_version_id)
print('Updated protocol!') print('Updated protocol!')
@ -110,13 +112,33 @@ old_ordered_blocks = lib.extract.get_ordered_blocks_burger(old_version_id)
new_ordered_blocks = lib.extract.get_ordered_blocks_burger(new_version_id) new_ordered_blocks = lib.extract.get_ordered_blocks_burger(new_version_id)
if old_ordered_blocks != new_ordered_blocks: if old_ordered_blocks != new_ordered_blocks:
print('Blocks changed, updating...') print('Blocks changed, updating...')
block_states_burger = lib.extract.get_block_states_burger(new_version_id) block_states_burger = lib.extract.get_block_states_burger(new_version_id)
block_states_report = lib.extract.get_block_states_report(new_version_id) block_states_report = lib.extract.get_block_states_report(new_version_id)
shape_datas = lib.extract.get_pixlyzer_data(
new_version_id, 'shapes')
pixlyzer_block_datas = lib.extract.get_pixlyzer_data(
new_version_id, 'blocks')
lib.code.blocks.generate_blocks( lib.code.blocks.generate_blocks(
block_states_burger, block_states_report, old_ordered_blocks, new_mappings) block_states_burger, block_states_report, new_ordered_blocks, new_mappings)
lib.code.shapes.generate_block_shapes(
pixlyzer_block_datas, shape_datas['shapes'], shape_datas['aabbs'], block_states_report, block_states_burger, new_mappings)
print('Getting en_us.json...')
language = lib.extract.get_en_us_lang(new_version_id)
lib.code.language.write_language(language)
print('Generating registries...')
registries = lib.extract.get_registries_report(new_version_id)
lib.code.registry.generate_registries(registries)
print('Finishing touches, setting version in README and formatting code...')
lib.code.version.set_version_id(new_version_id)
lib.code.utils.fmt() lib.code.utils.fmt()
print('Done!') print('Done!')
print('Make sure to `cargo check` and look for the generated `TODO`s to make sure everything is correct!')

View file

@ -11,7 +11,7 @@ mappings = lib.download.get_mappings_for_version(version_id)
burger_data = lib.extract.get_burger_data_for_version(version_id) burger_data = lib.extract.get_burger_data_for_version(version_id)
burger_packets_data = burger_data[0]['packets']['packet'] burger_packets_data = burger_data[0]['packets']['packet']
packet_id, direction, state = int(sys.argv[1]), sys.argv[2], sys.argv[3] packet_id, direction, state = int(sys.argv[1], 0), sys.argv[2], sys.argv[3]
print( print(
f'Generating code for packet id: {packet_id} with direction {direction} and state {state}') f'Generating code for packet id: {packet_id} with direction {direction} and state {state}')
lib.code.packet.generate_packet(burger_packets_data, mappings, lib.code.packet.generate_packet(burger_packets_data, mappings,