mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 06:16:04 +00:00
1.19.3 (#34)
* 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 commitee9a0e7a49
. * fix * fix * Revert "fix" This reverts commitad12ddcb00
. * 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:
parent
9f5e5c092b
commit
7d901e39bc
73 changed files with 22289 additions and 15350 deletions
112
Cargo.lock
generated
112
Cargo.lock
generated
|
@ -43,9 +43,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.19"
|
||||
version = "0.7.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e"
|
||||
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
@ -82,9 +82,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.58"
|
||||
version = "0.1.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c"
|
||||
checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -182,6 +182,7 @@ version = "0.4.0"
|
|||
dependencies = [
|
||||
"azalea-buf-macros",
|
||||
"byteorder",
|
||||
"log",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
|
@ -203,6 +204,7 @@ version = "0.4.0"
|
|||
dependencies = [
|
||||
"azalea-buf",
|
||||
"azalea-language",
|
||||
"log",
|
||||
"once_cell",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
@ -380,7 +382,7 @@ dependencies = [
|
|||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"miniz_oxide 0.5.4",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
@ -446,9 +448,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
|||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.2.1"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db"
|
||||
checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
|
||||
|
||||
[[package]]
|
||||
name = "cast"
|
||||
|
@ -458,9 +460,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.76"
|
||||
version = "1.0.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f"
|
||||
checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
|
||||
|
||||
[[package]]
|
||||
name = "cfb8"
|
||||
|
@ -601,9 +603,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.11"
|
||||
version = "0.9.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f916dfc5d356b0ed9dae65f1db9fc9770aa2851d2662b988ccf4fe3516e86348"
|
||||
checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
|
@ -614,9 +616,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.12"
|
||||
version = "0.8.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac"
|
||||
checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
@ -661,9 +663,9 @@ checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57"
|
|||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.5"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c"
|
||||
checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
|
@ -726,12 +728,12 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
|||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.24"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6"
|
||||
checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
"miniz_oxide 0.6.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1026,9 +1028,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.1"
|
||||
version = "1.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
|
||||
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
|
@ -1096,9 +1098,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.137"
|
||||
version = "0.2.138"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
|
||||
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
|
@ -1148,9 +1150,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
|||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.5"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
|
||||
checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
@ -1170,6 +1172,15 @@ dependencies = [
|
|||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.5"
|
||||
|
@ -1326,9 +1337,9 @@ checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
|
|||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.42"
|
||||
version = "0.10.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12fc0523e3bd51a692c8850d075d74dc062ccf251c0110668cbd921917118a13"
|
||||
checksum = "020433887e44c27ff16365eaa2d380547a94544ad509aff6eb5b6e3e0b27b376"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
|
@ -1358,9 +1369,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
|||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.77"
|
||||
version = "0.9.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b03b84c3b2d099b81f0953422b4d4ad58761589d0229b5506356afca05a3670a"
|
||||
checksum = "07d5c8cb6e57b3a3612064d7b18b117912b4ce70955c2504d4b741c9e244b132"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cc",
|
||||
|
@ -1381,9 +1392,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.4"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0"
|
||||
checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"cfg-if",
|
||||
|
@ -1523,11 +1534,10 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.5.3"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d"
|
||||
checksum = "1e060280438193c554f654141c9ea9417886713b7acd75974c85b18a69a88e0b"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"crossbeam-deque",
|
||||
"either",
|
||||
"rayon-core",
|
||||
|
@ -1535,9 +1545,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.9.3"
|
||||
version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f"
|
||||
checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
|
@ -1588,9 +1598,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.12"
|
||||
version = "0.11.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "431949c384f4e2ae07605ccaa56d1d9d2ecdb5cadd4f9577ccfab29f2e5149fc"
|
||||
checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
|
@ -1696,9 +1706,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.148"
|
||||
version = "1.0.149"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc"
|
||||
checksum = "256b9932320c590e707b94576e3cc1f7c9024d0ee6612dfbcf1cb106cbe8e055"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
@ -1715,9 +1725,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.148"
|
||||
version = "1.0.149"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c"
|
||||
checksum = "b4eae9b04cbffdfd550eb462ed33bc6a1b68c935127d008b27444d08380f94e4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1726,9 +1736,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.87"
|
||||
version = "1.0.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45"
|
||||
checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db"
|
||||
dependencies = [
|
||||
"itoa 1.0.4",
|
||||
"ryu",
|
||||
|
@ -1749,9 +1759,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.10.0"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
|
||||
checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
|
@ -1905,9 +1915,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.21.2"
|
||||
version = "1.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099"
|
||||
checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bytes",
|
||||
|
@ -1925,9 +1935,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "1.8.0"
|
||||
version = "1.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484"
|
||||
checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -2053,9 +2063,9 @@ checksum = "4fc45e9608894c9fefd9792d880560280086d73a4d8c8cb7436f27ca98550fb5"
|
|||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.15.0"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
|
||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
|
|
|
@ -9,7 +9,7 @@ A collection of Rust crates for making Minecraft bots, clients, and tools.
|
|||
</p>
|
||||
|
||||
<!-- The line below is automatically read and updated by the migrate script, so don't change it manually. -->
|
||||
*Currently supported Minecraft version: `1.19.2`.*
|
||||
*Currently supported Minecraft version: `1.19.3`.*
|
||||
|
||||
## ⚠️ Azalea is still very unfinished, though most crates are in a somewhat useable state
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ use azalea_buf::McBuf;
|
|||
use std::collections::HashMap;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(McBuf, Debug, Clone)]
|
||||
#[derive(McBuf, Debug, Clone, Default)]
|
||||
pub struct GameProfile {
|
||||
pub uuid: Uuid,
|
||||
pub name: String,
|
||||
|
|
|
@ -178,7 +178,7 @@ make_block_states! {
|
|||
Down,
|
||||
},
|
||||
"triggered" => bool,
|
||||
"instrument" => Instrument {
|
||||
"instrument" => Sound {
|
||||
Harp,
|
||||
Basedrum,
|
||||
Snare,
|
||||
|
@ -195,6 +195,13 @@ make_block_states! {
|
|||
Bit,
|
||||
Banjo,
|
||||
Pling,
|
||||
Zombie,
|
||||
Skeleton,
|
||||
Creeper,
|
||||
Dragon,
|
||||
WitherSkeleton,
|
||||
Piglin,
|
||||
CustomHead,
|
||||
},
|
||||
"note" => NoteBlockNote {
|
||||
_0,
|
||||
|
@ -254,6 +261,12 @@ make_block_states! {
|
|||
},
|
||||
"short" => 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 {
|
||||
_0,
|
||||
_1,
|
||||
|
@ -478,6 +491,24 @@ make_block_states! {
|
|||
_14,
|
||||
_15,
|
||||
},
|
||||
"rotation" => BambooSignRotation {
|
||||
_0,
|
||||
_1,
|
||||
_2,
|
||||
_3,
|
||||
_4,
|
||||
_5,
|
||||
_6,
|
||||
_7,
|
||||
_8,
|
||||
_9,
|
||||
_10,
|
||||
_11,
|
||||
_12,
|
||||
_13,
|
||||
_14,
|
||||
_15,
|
||||
},
|
||||
"hinge" => Hinge {
|
||||
Left,
|
||||
Right,
|
||||
|
@ -495,6 +526,187 @@ make_block_states! {
|
|||
NorthWest,
|
||||
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 {
|
||||
Floor,
|
||||
Wall,
|
||||
|
@ -588,7 +800,11 @@ make_block_states! {
|
|||
_6,
|
||||
_7,
|
||||
},
|
||||
"berries" => bool,
|
||||
"down" => bool,
|
||||
"north" => bool,
|
||||
"south" => bool,
|
||||
"up" => bool,
|
||||
"west" => bool,
|
||||
"in_wall" => bool,
|
||||
"age" => NetherWartAge {
|
||||
_0,
|
||||
|
@ -613,7 +829,6 @@ make_block_states! {
|
|||
_1,
|
||||
_2,
|
||||
},
|
||||
"attached" => bool,
|
||||
"disarmed" => bool,
|
||||
"conditional" => bool,
|
||||
"east" => EastWall {
|
||||
|
@ -764,6 +979,24 @@ make_block_states! {
|
|||
_14,
|
||||
_15,
|
||||
},
|
||||
"rotation" => PiglinHeadRotation {
|
||||
_0,
|
||||
_1,
|
||||
_2,
|
||||
_3,
|
||||
_4,
|
||||
_5,
|
||||
_6,
|
||||
_7,
|
||||
_8,
|
||||
_9,
|
||||
_10,
|
||||
_11,
|
||||
_12,
|
||||
_13,
|
||||
_14,
|
||||
_15,
|
||||
},
|
||||
"power" => LightWeightedPressurePlatePower {
|
||||
_0,
|
||||
_1,
|
||||
|
@ -1535,6 +1768,8 @@ make_block_states! {
|
|||
Active,
|
||||
Cooldown,
|
||||
},
|
||||
"south" => bool,
|
||||
"west" => bool,
|
||||
"bloom" => bool,
|
||||
"can_summon" => bool,
|
||||
"shrieking" => bool,
|
||||
|
@ -1549,7 +1784,7 @@ make_block_states! {
|
|||
Up,
|
||||
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,
|
||||
_1,
|
||||
_2,
|
||||
|
@ -1577,13 +1812,14 @@ make_block_states! {
|
|||
_24,
|
||||
_25,
|
||||
},
|
||||
"berries" => bool,
|
||||
"tilt" => Tilt {
|
||||
None,
|
||||
Unstable,
|
||||
Partial,
|
||||
Full,
|
||||
},
|
||||
"axis" => XYZ {
|
||||
"axis" => CacheSize {
|
||||
X,
|
||||
Y,
|
||||
Z,
|
||||
|
@ -1614,6 +1850,8 @@ make_block_states! {
|
|||
acacia_planks => BlockBehavior::default(), {},
|
||||
dark_oak_planks => BlockBehavior::default(), {},
|
||||
mangrove_planks => BlockBehavior::default(), {},
|
||||
bamboo_planks => BlockBehavior::default(), {},
|
||||
bamboo_mosaic => BlockBehavior::default(), {},
|
||||
oak_sapling => BlockBehavior::default(), {
|
||||
stage: OakSaplingStage::_0,
|
||||
},
|
||||
|
@ -1682,6 +1920,9 @@ make_block_states! {
|
|||
muddy_mangrove_roots => BlockBehavior::default(), {
|
||||
axis: Axis::Y,
|
||||
},
|
||||
bamboo_block => BlockBehavior::default(), {
|
||||
axis: Axis::Y,
|
||||
},
|
||||
stripped_spruce_log => BlockBehavior::default(), {
|
||||
axis: Axis::Y,
|
||||
},
|
||||
|
@ -1703,6 +1944,9 @@ make_block_states! {
|
|||
stripped_mangrove_log => BlockBehavior::default(), {
|
||||
axis: Axis::Y,
|
||||
},
|
||||
stripped_bamboo_block => BlockBehavior::default(), {
|
||||
axis: Axis::Y,
|
||||
},
|
||||
oak_wood => BlockBehavior::default(), {
|
||||
axis: Axis::Y,
|
||||
},
|
||||
|
@ -1804,7 +2048,7 @@ make_block_states! {
|
|||
chiseled_sandstone => BlockBehavior::default(), {},
|
||||
cut_sandstone => BlockBehavior::default(), {},
|
||||
note_block => BlockBehavior::default(), {
|
||||
instrument: Instrument::Harp,
|
||||
instrument: Sound::Harp,
|
||||
note: NoteBlockNote::_0,
|
||||
powered: false,
|
||||
},
|
||||
|
@ -1961,6 +2205,15 @@ make_block_states! {
|
|||
unstable: false,
|
||||
},
|
||||
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(), {},
|
||||
obsidian => BlockBehavior::default(), {},
|
||||
torch => BlockBehavior::default(), {},
|
||||
|
@ -2037,6 +2290,10 @@ make_block_states! {
|
|||
rotation: MangroveSignRotation::_0,
|
||||
waterlogged: false,
|
||||
},
|
||||
bamboo_sign => BlockBehavior::default(), {
|
||||
rotation: BambooSignRotation::_0,
|
||||
waterlogged: false,
|
||||
},
|
||||
oak_door => BlockBehavior::default(), {
|
||||
facing: FacingCardinal::North,
|
||||
half: Half::Lower,
|
||||
|
@ -2086,6 +2343,100 @@ make_block_states! {
|
|||
facing: FacingCardinal::North,
|
||||
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(), {
|
||||
face: Face::Wall,
|
||||
facing: FacingCardinal::North,
|
||||
|
@ -2122,6 +2473,9 @@ make_block_states! {
|
|||
mangrove_pressure_plate => BlockBehavior::default(), {
|
||||
powered: false,
|
||||
},
|
||||
bamboo_pressure_plate => BlockBehavior::default(), {
|
||||
powered: false,
|
||||
},
|
||||
redstone_ore => BlockBehavior::default(), {
|
||||
lit: false,
|
||||
},
|
||||
|
@ -2260,6 +2614,13 @@ make_block_states! {
|
|||
powered: false,
|
||||
waterlogged: false,
|
||||
},
|
||||
bamboo_trapdoor => BlockBehavior::default(), {
|
||||
facing: FacingCardinal::North,
|
||||
half: TopBottom::Bottom,
|
||||
open: false,
|
||||
powered: false,
|
||||
waterlogged: false,
|
||||
},
|
||||
stone_bricks => BlockBehavior::default(), {},
|
||||
mossy_stone_bricks => BlockBehavior::default(), {},
|
||||
cracked_stone_bricks => BlockBehavior::default(), {},
|
||||
|
@ -2549,6 +2910,11 @@ make_block_states! {
|
|||
facing: FacingCardinal::North,
|
||||
powered: false,
|
||||
},
|
||||
bamboo_button => BlockBehavior::default(), {
|
||||
face: Face::Wall,
|
||||
facing: FacingCardinal::North,
|
||||
powered: false,
|
||||
},
|
||||
skeleton_skull => BlockBehavior::default(), {
|
||||
rotation: SkeletonSkullRotation::_0,
|
||||
},
|
||||
|
@ -2585,6 +2951,12 @@ make_block_states! {
|
|||
dragon_wall_head => BlockBehavior::default(), {
|
||||
facing: FacingCardinal::North,
|
||||
},
|
||||
piglin_head => BlockBehavior::default(), {
|
||||
rotation: PiglinHeadRotation::_0,
|
||||
},
|
||||
piglin_wall_head => BlockBehavior::default(), {
|
||||
facing: FacingCardinal::North,
|
||||
},
|
||||
anvil => BlockBehavior::default(), {
|
||||
facing: FacingCardinal::North,
|
||||
},
|
||||
|
@ -2786,6 +3158,18 @@ make_block_states! {
|
|||
shape: StairShape::Straight,
|
||||
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(), {},
|
||||
barrier => BlockBehavior::default(), {},
|
||||
light => BlockBehavior::default(), {
|
||||
|
@ -3006,6 +3390,14 @@ make_block_states! {
|
|||
kind: Type::Bottom,
|
||||
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(), {
|
||||
kind: Type::Bottom,
|
||||
waterlogged: false,
|
||||
|
@ -3102,6 +3494,12 @@ make_block_states! {
|
|||
open: false,
|
||||
powered: false,
|
||||
},
|
||||
bamboo_fence_gate => BlockBehavior::default(), {
|
||||
facing: FacingCardinal::North,
|
||||
in_wall: false,
|
||||
open: false,
|
||||
powered: false,
|
||||
},
|
||||
spruce_fence => BlockBehavior::default(), {
|
||||
east: false,
|
||||
north: false,
|
||||
|
@ -3144,6 +3542,13 @@ make_block_states! {
|
|||
waterlogged: false,
|
||||
west: false,
|
||||
},
|
||||
bamboo_fence => BlockBehavior::default(), {
|
||||
east: false,
|
||||
north: false,
|
||||
south: false,
|
||||
waterlogged: false,
|
||||
west: false,
|
||||
},
|
||||
spruce_door => BlockBehavior::default(), {
|
||||
facing: FacingCardinal::North,
|
||||
half: Half::Lower,
|
||||
|
@ -3186,6 +3591,13 @@ make_block_states! {
|
|||
open: false,
|
||||
powered: false,
|
||||
},
|
||||
bamboo_door => BlockBehavior::default(), {
|
||||
facing: FacingCardinal::North,
|
||||
half: Half::Lower,
|
||||
hinge: Hinge::Left,
|
||||
open: false,
|
||||
powered: false,
|
||||
},
|
||||
end_rod => BlockBehavior::default(), {
|
||||
facing: FacingCubic::Up,
|
||||
},
|
||||
|
@ -4355,7 +4767,7 @@ make_block_states! {
|
|||
},
|
||||
dripstone_block => 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,
|
||||
},
|
||||
cave_vines_plant => BlockBehavior::default(), {
|
||||
|
@ -4468,7 +4880,7 @@ make_block_states! {
|
|||
cracked_deepslate_bricks => BlockBehavior::default(), {},
|
||||
cracked_deepslate_tiles => BlockBehavior::default(), {},
|
||||
infested_deepslate => BlockBehavior::default(), {
|
||||
axis: XYZ::Y,
|
||||
axis: CacheSize::Y,
|
||||
},
|
||||
smooth_basalt => BlockBehavior::default(), {},
|
||||
raw_iron_block => BlockBehavior::default(), {},
|
||||
|
|
5
azalea-buf/Cargo.toml
Executable file → Normal file
5
azalea-buf/Cargo.toml
Executable file → Normal file
|
@ -9,10 +9,11 @@ version = "0.4.0"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[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"
|
||||
log = "0.4.17"
|
||||
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"]}
|
||||
uuid = "^1.1.2"
|
||||
|
||||
|
|
|
@ -1,294 +1,30 @@
|
|||
mod read;
|
||||
mod write;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::{quote, ToTokens};
|
||||
use syn::{self, parse_macro_input, Data, DeriveInput, FieldsNamed, Ident};
|
||||
|
||||
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"),
|
||||
}
|
||||
}
|
||||
use quote::quote;
|
||||
use syn::{self, parse_macro_input, DeriveInput};
|
||||
|
||||
#[proc_macro_derive(McBufReadable, attributes(var))]
|
||||
pub fn derive_mcbufreadable(input: TokenStream) -> TokenStream {
|
||||
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))]
|
||||
pub fn derive_mcbufwritable(input: TokenStream) -> TokenStream {
|
||||
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))]
|
||||
pub fn derive_mcbuf(input: TokenStream) -> TokenStream {
|
||||
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
|
||||
|
||||
let writable = create_impl_mcbufwritable(&ident, &data);
|
||||
let readable = create_impl_mcbufreadable(&ident, &data);
|
||||
let writable = write::create_impl_mcbufwritable(&ident, &data);
|
||||
let readable = read::create_impl_mcbufreadable(&ident, &data);
|
||||
quote! {
|
||||
#writable
|
||||
#readable
|
||||
|
|
158
azalea-buf/azalea-buf-macros/src/read.rs
Normal file
158
azalea-buf/azalea-buf-macros/src/read.rs
Normal 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"),
|
||||
}
|
||||
}
|
193
azalea-buf/azalea-buf-macros/src/write.rs
Normal file
193
azalea-buf/azalea-buf-macros/src/write.rs
Normal 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"),
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
use super::{UnsizedByteArray, MAX_STRING_LENGTH};
|
||||
use byteorder::{ReadBytesExt, BE};
|
||||
use log::warn;
|
||||
use std::{
|
||||
backtrace::Backtrace,
|
||||
collections::HashMap,
|
||||
hash::Hash,
|
||||
io::{Cursor, Read},
|
||||
|
@ -17,14 +19,18 @@ pub enum BufReadError {
|
|||
CouldNotReadBytes,
|
||||
#[error("The received encoded string buffer length is longer than maximum allowed ({length} > {max_length})")]
|
||||
StringLengthTooLong { length: u32, max_length: u32 },
|
||||
#[error("{0}")]
|
||||
Io(
|
||||
#[error("{source}")]
|
||||
Io {
|
||||
#[from]
|
||||
#[backtrace]
|
||||
std::io::Error,
|
||||
),
|
||||
#[error("Invalid UTF-8")]
|
||||
InvalidUtf8,
|
||||
source: std::io::Error,
|
||||
},
|
||||
#[error("Invalid UTF-8: {bytes:?} (lossy: {lossy:?})")]
|
||||
InvalidUtf8 {
|
||||
bytes: Vec<u8>,
|
||||
lossy: String,
|
||||
// backtrace: Backtrace,
|
||||
},
|
||||
#[error("Unexpected enum variant {id}")]
|
||||
UnexpectedEnumVariant { id: i32 },
|
||||
#[error("Unexpected enum variant {id}")]
|
||||
|
@ -33,12 +39,17 @@ pub enum BufReadError {
|
|||
UnexpectedEof {
|
||||
attempted_read: usize,
|
||||
actual_read: usize,
|
||||
backtrace: Backtrace,
|
||||
},
|
||||
#[error("{0}")]
|
||||
Custom(String),
|
||||
#[cfg(feature = "serde_json")]
|
||||
#[error("{0}")]
|
||||
Deserialization(#[from] serde_json::Error),
|
||||
#[error("{source}")]
|
||||
Deserialization {
|
||||
#[from]
|
||||
#[backtrace]
|
||||
source: serde_json::Error,
|
||||
},
|
||||
}
|
||||
|
||||
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 {
|
||||
attempted_read: length,
|
||||
actual_read: buf.get_ref().len() - buf.position() as usize,
|
||||
backtrace: Backtrace::capture(),
|
||||
});
|
||||
}
|
||||
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 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();
|
||||
if string.len() > length as usize {
|
||||
return Err(BufReadError::StringLengthTooLong { length, max_length });
|
||||
|
@ -265,7 +281,11 @@ impl McBufReadable for u64 {
|
|||
|
||||
impl McBufReadable for bool {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,11 @@ version = "0.4.0"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
azalea-buf = {path = "../azalea-buf", features = ["serde_json"], version = "^0.4.0"}
|
||||
azalea-language = {path = "../azalea-language", 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" }
|
||||
log = "0.4.17"
|
||||
once_cell = "1.16.0"
|
||||
serde = {version = "^1.0.148", features = ["derive"]}
|
||||
serde = { version = "^1.0.148", features = ["derive"] }
|
||||
serde_json = "^1.0.72"
|
||||
|
|
|
@ -5,6 +5,7 @@ use crate::{
|
|||
translatable_component::{StringOrComponent, TranslatableComponent},
|
||||
};
|
||||
use azalea_buf::{BufReadError, McBufReadable, McBufWritable};
|
||||
use log::debug;
|
||||
use once_cell::sync::Lazy;
|
||||
use serde::{de, Deserialize, Deserializer, Serialize};
|
||||
use std::{
|
||||
|
@ -266,6 +267,7 @@ impl<'de> Deserialize<'de> for Component {
|
|||
impl McBufReadable for Component {
|
||||
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
||||
let string = String::read_from(buf)?;
|
||||
debug!("Component string: {}", string);
|
||||
let json: serde_json::Value = serde_json::from_str(string.as_str())?;
|
||||
let component = Component::deserialize(json)?;
|
||||
Ok(component)
|
||||
|
|
|
@ -2,12 +2,11 @@
|
|||
|
||||
use crate::Client;
|
||||
use azalea_chat::Component;
|
||||
use azalea_crypto::MessageSignature;
|
||||
use azalea_protocol::packets::game::{
|
||||
clientbound_player_chat_packet::{ClientboundPlayerChatPacket, LastSeenMessagesUpdate},
|
||||
clientbound_player_chat_packet::ClientboundPlayerChatPacket,
|
||||
clientbound_system_chat_packet::ClientboundSystemChatPacket,
|
||||
serverbound_chat_command_packet::ServerboundChatCommandPacket,
|
||||
serverbound_chat_packet::ServerboundChatPacket,
|
||||
serverbound_chat_packet::{LastSeenMessagesUpdate, ServerboundChatPacket},
|
||||
};
|
||||
use std::{
|
||||
sync::Arc,
|
||||
|
@ -33,7 +32,7 @@ impl ChatPacket {
|
|||
pub fn message(&self) -> Component {
|
||||
match self {
|
||||
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
|
||||
// are already split for us.
|
||||
Some(p.chat_type.name.to_string()),
|
||||
p.message.content(false).to_string(),
|
||||
p.body.content.clone(),
|
||||
),
|
||||
ChatPacket::System(p) => {
|
||||
let message = p.content.to_string();
|
||||
|
@ -88,7 +87,7 @@ impl Client {
|
|||
/// so you should use that instead.
|
||||
pub async fn send_chat_packet(&self, message: &str) -> Result<(), std::io::Error> {
|
||||
// TODO: chat signing
|
||||
let signature = sign_message();
|
||||
// let signature = sign_message();
|
||||
let packet = ServerboundChatPacket {
|
||||
message: message.to_string(),
|
||||
timestamp: SystemTime::now()
|
||||
|
@ -98,8 +97,7 @@ impl Client {
|
|||
.try_into()
|
||||
.expect("Instant should fit into a u64"),
|
||||
salt: azalea_crypto::make_salt(),
|
||||
signature,
|
||||
signed_preview: false,
|
||||
signature: None,
|
||||
last_seen_messages: LastSeenMessagesUpdate::default(),
|
||||
}
|
||||
.get();
|
||||
|
@ -120,7 +118,6 @@ impl Client {
|
|||
.expect("Instant should fit into a u64"),
|
||||
salt: azalea_crypto::make_salt(),
|
||||
argument_signatures: vec![],
|
||||
signed_preview: false,
|
||||
last_seen_messages: LastSeenMessagesUpdate::default(),
|
||||
}
|
||||
.get();
|
||||
|
@ -143,14 +140,10 @@ impl Client {
|
|||
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
|
||||
// MessageSigner, ChatMessageContent, LastSeenMessages
|
||||
fn sign_message() -> MessageSignature {
|
||||
MessageSignature::default()
|
||||
}
|
||||
// fn sign_message() -> MessageSignature {
|
||||
// MessageSignature::default()
|
||||
// }
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
pub use crate::chat::ChatPacket;
|
||||
use crate::{movement::WalkDirection, plugins::PluginStates, Account, PlayerInfo};
|
||||
use azalea_auth::game_profile::GameProfile;
|
||||
use azalea_chat::Component;
|
||||
use azalea_core::{ChunkPos, GameType, ResourceLocation, Vec3};
|
||||
use azalea_core::{ChunkPos, ResourceLocation, Vec3};
|
||||
use azalea_protocol::{
|
||||
connect::{Connection, ConnectionError, ReadConnection, WriteConnection},
|
||||
packets::{
|
||||
|
@ -22,8 +21,7 @@ use azalea_protocol::{
|
|||
login::{
|
||||
serverbound_custom_query_packet::ServerboundCustomQueryPacket,
|
||||
serverbound_hello_packet::ServerboundHelloPacket,
|
||||
serverbound_key_packet::{NonceOrSaltSignature, ServerboundKeyPacket},
|
||||
ClientboundLoginPacket,
|
||||
serverbound_key_packet::ServerboundKeyPacket, ClientboundLoginPacket,
|
||||
},
|
||||
ConnectionProtocol, PROTOCOL_VERSION,
|
||||
},
|
||||
|
@ -37,6 +35,8 @@ use azalea_world::{
|
|||
use log::{debug, error, info, trace, warn};
|
||||
use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
use std::{
|
||||
any,
|
||||
backtrace::Backtrace,
|
||||
collections::HashMap,
|
||||
fmt::Debug,
|
||||
io::{self, Cursor},
|
||||
|
@ -52,8 +52,11 @@ use uuid::Uuid;
|
|||
|
||||
pub type ClientInformation = ServerboundClientInformationPacket;
|
||||
|
||||
/// Events are sent before they're processed, so for example game ticks happen
|
||||
/// at the beginning of a tick before anything has happened.
|
||||
/// Something that happened in-game, such as a tick passing or chat message
|
||||
/// 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)]
|
||||
pub enum Event {
|
||||
/// 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
|
||||
/// doesn't have to be sent twice.
|
||||
Init,
|
||||
/// The client is now in the world. Fired when we receive a login packet.
|
||||
Login,
|
||||
/// A chat message was sent in the game chat.
|
||||
Chat(ChatPacket),
|
||||
/// Happens 20 times per second, but only when the world is loaded.
|
||||
Tick,
|
||||
Packet(Arc<ClientboundGamePacket>),
|
||||
/// Happens when a player is added, removed, or updated in the tab list.
|
||||
UpdatePlayers(UpdatePlayersEvent),
|
||||
/// Emits when the player dies.
|
||||
/// A player joined the game (or more specifically, was added to the tab
|
||||
/// list).
|
||||
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>>),
|
||||
}
|
||||
|
||||
/// 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.
|
||||
#[derive(Clone)]
|
||||
pub struct Client {
|
||||
|
@ -141,6 +127,7 @@ pub struct PhysicsState {
|
|||
/// Whether we should ignore errors when decoding packets.
|
||||
const IGNORE_ERRORS: bool = !cfg!(debug_assertions);
|
||||
|
||||
/// An error that happened while joining the server.
|
||||
#[derive(Error, Debug)]
|
||||
pub enum JoinError {
|
||||
#[error("{0}")]
|
||||
|
@ -148,7 +135,7 @@ pub enum JoinError {
|
|||
#[error("{0}")]
|
||||
Connection(#[from] ConnectionError),
|
||||
#[error("{0}")]
|
||||
ReadPacket(#[from] azalea_protocol::read::ReadPacketError),
|
||||
ReadPacket(#[from] Box<azalea_protocol::read::ReadPacketError>),
|
||||
#[error("{0}")]
|
||||
Io(#[from] io::Error),
|
||||
#[error("{0}")]
|
||||
|
@ -280,8 +267,7 @@ impl Client {
|
|||
// login
|
||||
conn.write(
|
||||
ServerboundHelloPacket {
|
||||
username: account.username.clone(),
|
||||
public_key: None,
|
||||
name: account.username.clone(),
|
||||
profile_id: None,
|
||||
}
|
||||
.get(),
|
||||
|
@ -309,8 +295,8 @@ impl Client {
|
|||
|
||||
conn.write(
|
||||
ServerboundKeyPacket {
|
||||
nonce_or_salt_signature: NonceOrSaltSignature::Nonce(e.encrypted_nonce),
|
||||
key_bytes: e.encrypted_public_key,
|
||||
encrypted_challenge: e.encrypted_nonce,
|
||||
}
|
||||
.get(),
|
||||
)
|
||||
|
@ -396,6 +382,7 @@ impl Client {
|
|||
}
|
||||
},
|
||||
Err(e) => {
|
||||
let e = *e;
|
||||
if let ReadPacketError::ConnectionClosed = e {
|
||||
info!("Connection closed");
|
||||
if let Err(e) = client.disconnect().await {
|
||||
|
@ -403,13 +390,19 @@ impl Client {
|
|||
}
|
||||
break;
|
||||
}
|
||||
let default_backtrace = Backtrace::capture();
|
||||
if IGNORE_ERRORS {
|
||||
warn!("{}", e);
|
||||
if let ReadPacketError::FrameSplitter { .. } = e {
|
||||
panic!("Error: {e:?}");
|
||||
let backtrace =
|
||||
any::request_ref::<Backtrace>(&e).unwrap_or(&default_backtrace);
|
||||
warn!("{e}\n{backtrace}");
|
||||
match e {
|
||||
ReadPacketError::FrameSplitter { .. } => panic!("Error: {e:?}"),
|
||||
_ => continue,
|
||||
}
|
||||
} 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?;
|
||||
}
|
||||
ClientboundGamePacket::PlayerInfo(p) => {
|
||||
use azalea_protocol::packets::game::clientbound_player_info_packet::Action;
|
||||
|
||||
ClientboundGamePacket::PlayerInfoUpdate(p) => {
|
||||
debug!("Got player info packet {:?}", p);
|
||||
let mut events = Vec::new();
|
||||
{
|
||||
let mut players_lock = client.players.write();
|
||||
match &p.action {
|
||||
Action::AddPlayer(players) => {
|
||||
for player in players {
|
||||
for updated_info in &p.entries {
|
||||
// add the new player maybe
|
||||
if p.actions.add_player {
|
||||
let player_info = PlayerInfo {
|
||||
profile: GameProfile {
|
||||
uuid: player.uuid,
|
||||
name: player.name.clone(),
|
||||
properties: player.properties.clone(),
|
||||
},
|
||||
uuid: player.uuid,
|
||||
gamemode: player.gamemode,
|
||||
latency: player.latency,
|
||||
display_name: player.display_name.clone(),
|
||||
profile: updated_info.profile.clone(),
|
||||
uuid: updated_info.profile.uuid,
|
||||
gamemode: updated_info.game_mode,
|
||||
latency: updated_info.latency,
|
||||
display_name: updated_info.display_name.clone(),
|
||||
};
|
||||
players_lock.insert(player.uuid, player_info.clone());
|
||||
events.push(Event::UpdatePlayers(UpdatePlayersEvent::Add(
|
||||
player_info,
|
||||
)));
|
||||
players_lock.insert(updated_info.profile.uuid, player_info.clone());
|
||||
events.push(Event::AddPlayer(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) => {
|
||||
for player in players {
|
||||
if let Some(p) = players_lock.get_mut(&player.uuid) {
|
||||
p.gamemode = player.gamemode;
|
||||
events.push(Event::UpdatePlayers(
|
||||
UpdatePlayersEvent::GameMode {
|
||||
uuid: player.uuid,
|
||||
game_mode: player.gamemode,
|
||||
},
|
||||
));
|
||||
if p.actions.update_display_name {
|
||||
info.display_name = updated_info.display_name.clone();
|
||||
}
|
||||
events.push(Event::UpdatePlayer(info.clone()));
|
||||
} else {
|
||||
warn!(
|
||||
"Ignoring PlayerInfo (UpdateGameMode) for unknown player {}",
|
||||
player.uuid
|
||||
"Ignoring PlayerInfoUpdate for unknown player {}",
|
||||
updated_info.profile.uuid
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Action::UpdateLatency(players) => {
|
||||
for player in players {
|
||||
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
|
||||
);
|
||||
for event in events {
|
||||
tx.send(event).await?;
|
||||
}
|
||||
}
|
||||
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::BlockEvent(_) => {}
|
||||
ClientboundGamePacket::BossEvent(_) => {}
|
||||
ClientboundGamePacket::ChatPreview(_) => {}
|
||||
ClientboundGamePacket::CommandSuggestions(_) => {}
|
||||
ClientboundGamePacket::ContainerSetData(_) => {}
|
||||
ClientboundGamePacket::ContainerSetSlot(_) => {}
|
||||
ClientboundGamePacket::Cooldown(_) => {}
|
||||
ClientboundGamePacket::CustomChatCompletions(_) => {}
|
||||
ClientboundGamePacket::CustomSound(_) => {}
|
||||
ClientboundGamePacket::DeleteChat(_) => {}
|
||||
ClientboundGamePacket::Explode(_) => {}
|
||||
ClientboundGamePacket::ForgetLevelChunk(_) => {}
|
||||
|
@ -967,7 +914,6 @@ impl Client {
|
|||
ClientboundGamePacket::OpenSignEditor(_) => {}
|
||||
ClientboundGamePacket::Ping(_) => {}
|
||||
ClientboundGamePacket::PlaceGhostRecipe(_) => {}
|
||||
ClientboundGamePacket::PlayerChatHeader(_) => {}
|
||||
ClientboundGamePacket::PlayerCombatEnd(_) => {}
|
||||
ClientboundGamePacket::PlayerCombatEnter(_) => {}
|
||||
ClientboundGamePacket::PlayerCombatKill(p) => {
|
||||
|
@ -998,7 +944,6 @@ impl Client {
|
|||
ClientboundGamePacket::SetBorderWarningDelay(_) => {}
|
||||
ClientboundGamePacket::SetBorderWarningDistance(_) => {}
|
||||
ClientboundGamePacket::SetCamera(_) => {}
|
||||
ClientboundGamePacket::SetDisplayChatPreview(_) => {}
|
||||
ClientboundGamePacket::SetDisplayObjective(_) => {}
|
||||
ClientboundGamePacket::SetObjective(_) => {}
|
||||
ClientboundGamePacket::SetPassengers(_) => {}
|
||||
|
@ -1013,6 +958,8 @@ impl Client {
|
|||
ClientboundGamePacket::TabList(_) => {}
|
||||
ClientboundGamePacket::TagQuery(_) => {}
|
||||
ClientboundGamePacket::TakeItemEntity(_) => {}
|
||||
ClientboundGamePacket::DisguisedChat(_) => {}
|
||||
ClientboundGamePacket::UpdateEnabledFeatures(_) => {}
|
||||
ClientboundGamePacket::ContainerClose(_) => {}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
//! real clients. If you want to make bots, you should use the
|
||||
//! [`azalea`] crate instead.
|
||||
//!
|
||||
//! [`azalea_protocol`]: https://crates.io/crates/azalea-protocol
|
||||
//! [`azalea`]: https://crates.io/crates/azalea
|
||||
//! [`azalea_protocol`]: https://docs.rs/azalea-protocol
|
||||
//! [`azalea`]: https://docs.rs/azalea
|
||||
|
||||
#![feature(provide_any)]
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(trait_upcasting)]
|
||||
#![feature(error_generic_member_access)]
|
||||
#![feature(provide_any)]
|
||||
|
||||
mod account;
|
||||
mod chat;
|
||||
|
|
|
@ -23,7 +23,7 @@ pub enum PingError {
|
|||
#[error("{0}")]
|
||||
Connection(#[from] ConnectionError),
|
||||
#[error("{0}")]
|
||||
ReadPacket(#[from] azalea_protocol::read::ReadPacketError),
|
||||
ReadPacket(#[from] Box<azalea_protocol::read::ReadPacketError>),
|
||||
#[error("{0}")]
|
||||
WritePacket(#[from] io::Error),
|
||||
#[error("The given address could not be parsed into a ServerAddress")]
|
||||
|
|
|
@ -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.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, McBuf)]
|
||||
|
@ -105,6 +107,89 @@ impl BitSet {
|
|||
pub fn set(&mut self, bit_index: usize) {
|
||||
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)]
|
||||
|
|
3
azalea-core/src/game_type.rs
Executable file → Normal file
3
azalea-core/src/game_type.rs
Executable file → Normal file
|
@ -1,8 +1,9 @@
|
|||
use azalea_buf::{BufReadError, McBufReadable, McBufWritable};
|
||||
use std::io::{Cursor, Write};
|
||||
|
||||
#[derive(Hash, Copy, Clone, Debug)]
|
||||
#[derive(Hash, Copy, Clone, Debug, Default)]
|
||||
pub enum GameType {
|
||||
#[default]
|
||||
Survival,
|
||||
Creative,
|
||||
Adventure,
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
//! Random miscellaneous things like UUIDs that don't deserve their own crate.
|
||||
|
||||
#![feature(int_roundings)]
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(generic_const_exprs)]
|
||||
|
||||
mod difficulty;
|
||||
pub use difficulty::*;
|
||||
|
|
|
@ -7,9 +7,9 @@ pub struct SaltSignaturePair {
|
|||
pub signature: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, McBuf, PartialEq)]
|
||||
#[derive(Clone, Debug, PartialEq, McBuf)]
|
||||
pub struct MessageSignature {
|
||||
pub bytes: Vec<u8>,
|
||||
pub bytes: [u8; 256],
|
||||
}
|
||||
|
||||
#[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
32466
azalea-physics/src/collision/blocks.rs
Executable file → Normal file
File diff suppressed because it is too large
Load diff
|
@ -244,7 +244,7 @@ mod tests {
|
|||
world.add_entity(
|
||||
0,
|
||||
EntityData::new(
|
||||
Uuid::from_u128(0),
|
||||
Uuid::nil(),
|
||||
Vec3 {
|
||||
x: 0.,
|
||||
y: 70.,
|
||||
|
@ -277,7 +277,7 @@ mod tests {
|
|||
world.add_entity(
|
||||
0,
|
||||
EntityData::new(
|
||||
Uuid::from_u128(0),
|
||||
Uuid::nil(),
|
||||
Vec3 {
|
||||
x: 0.5,
|
||||
y: 70.,
|
||||
|
@ -310,7 +310,7 @@ mod tests {
|
|||
world.add_entity(
|
||||
0,
|
||||
EntityData::new(
|
||||
Uuid::from_u128(0),
|
||||
Uuid::nil(),
|
||||
Vec3 {
|
||||
x: 0.5,
|
||||
y: 71.,
|
||||
|
@ -344,7 +344,7 @@ mod tests {
|
|||
world.add_entity(
|
||||
0,
|
||||
EntityData::new(
|
||||
Uuid::from_u128(0),
|
||||
Uuid::nil(),
|
||||
Vec3 {
|
||||
x: 0.5,
|
||||
y: 71.,
|
||||
|
@ -378,7 +378,7 @@ mod tests {
|
|||
world.add_entity(
|
||||
0,
|
||||
EntityData::new(
|
||||
Uuid::from_u128(0),
|
||||
Uuid::nil(),
|
||||
Vec3 {
|
||||
x: 0.5,
|
||||
y: 73.,
|
||||
|
|
|
@ -30,7 +30,7 @@ futures-util = "0.3.24"
|
|||
log = "0.4.17"
|
||||
serde = {version = "1.0.130", features = ["serde_derive"]}
|
||||
serde_json = "^1.0.72"
|
||||
thiserror = "^1.0.34"
|
||||
thiserror = "1.0.37"
|
||||
tokio = {version = "^1.21.2", features = ["io-util", "net", "macros"]}
|
||||
tokio-util = {version = "0.7.4", features = ["codec"]}
|
||||
trust-dns-resolver = {version = "^0.22.0", default-features = false, features = ["tokio-runtime"]}
|
||||
|
|
|
@ -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.
|
||||
|
||||
Look at other packets as an example.
|
||||
|
||||
|
|
|
@ -221,11 +221,19 @@ pub fn declare_state_packets(input: TokenStream) -> TokenStream {
|
|||
});
|
||||
serverbound_read_match_contents.extend(quote! {
|
||||
#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 _ = std::io::Read::read_to_end(buf, &mut leftover);
|
||||
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
|
||||
},
|
||||
|
@ -246,14 +254,25 @@ pub fn declare_state_packets(input: TokenStream) -> TokenStream {
|
|||
});
|
||||
clientbound_read_match_contents.extend(quote! {
|
||||
#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 _ = std::io::Read::read_to_end(buf, &mut leftover);
|
||||
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
|
||||
|
@ -314,13 +333,13 @@ pub fn declare_state_packets(input: TokenStream) -> TokenStream {
|
|||
fn read(
|
||||
id: u32,
|
||||
buf: &mut std::io::Cursor<&[u8]>,
|
||||
) -> Result<#serverbound_state_name, crate::read::ReadPacketError>
|
||||
) -> Result<#serverbound_state_name, Box<crate::read::ReadPacketError>>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Ok(match id {
|
||||
#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(
|
||||
id: u32,
|
||||
buf: &mut std::io::Cursor<&[u8]>,
|
||||
) -> Result<#clientbound_state_name, crate::read::ReadPacketError>
|
||||
) -> Result<#clientbound_state_name, Box<crate::read::ReadPacketError>>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Ok(match id {
|
||||
#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 })),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ pub struct WriteConnection<W: ProtocolPacket> {
|
|||
/// login::{
|
||||
/// ClientboundLoginPacket,
|
||||
/// serverbound_hello_packet::ServerboundHelloPacket,
|
||||
/// serverbound_key_packet::{ServerboundKeyPacket, NonceOrSaltSignature}
|
||||
/// serverbound_key_packet::ServerboundKeyPacket
|
||||
/// },
|
||||
/// handshake::client_intention_packet::ClientIntentionPacket
|
||||
/// }
|
||||
|
@ -80,8 +80,7 @@ pub struct WriteConnection<W: ProtocolPacket> {
|
|||
/// // login
|
||||
/// conn.write(
|
||||
/// ServerboundHelloPacket {
|
||||
/// username: "bot".to_string(),
|
||||
/// public_key: None,
|
||||
/// name: "bot".to_string(),
|
||||
/// profile_id: None,
|
||||
/// }
|
||||
/// .get(),
|
||||
|
@ -96,8 +95,8 @@ pub struct WriteConnection<W: ProtocolPacket> {
|
|||
///
|
||||
/// conn.write(
|
||||
/// ServerboundKeyPacket {
|
||||
/// nonce_or_salt_signature: NonceOrSaltSignature::Nonce(e.encrypted_nonce),
|
||||
/// key_bytes: e.encrypted_public_key,
|
||||
/// encrypted_challenge: e.encrypted_nonce,
|
||||
/// }
|
||||
/// .get(),
|
||||
/// )
|
||||
|
@ -131,7 +130,7 @@ where
|
|||
R: ProtocolPacket + Debug,
|
||||
{
|
||||
/// 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, _>(
|
||||
&mut self.read_stream,
|
||||
&mut self.buffer,
|
||||
|
@ -179,7 +178,7 @@ where
|
|||
W: ProtocolPacket + Debug,
|
||||
{
|
||||
/// 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
|
||||
}
|
||||
|
||||
|
@ -276,7 +275,7 @@ impl Connection<ClientboundLoginPacket, ServerboundLoginPacket> {
|
|||
/// use azalea_protocol::connect::Connection;
|
||||
/// use azalea_protocol::packets::login::{
|
||||
/// ClientboundLoginPacket,
|
||||
/// serverbound_key_packet::{ServerboundKeyPacket, NonceOrSaltSignature}
|
||||
/// serverbound_key_packet::ServerboundKeyPacket
|
||||
/// };
|
||||
/// use uuid::Uuid;
|
||||
/// # use azalea_protocol::ServerAddress;
|
||||
|
@ -307,8 +306,8 @@ impl Connection<ClientboundLoginPacket, ServerboundLoginPacket> {
|
|||
/// ).await?;
|
||||
/// conn.write(
|
||||
/// ServerboundKeyPacket {
|
||||
/// nonce_or_salt_signature: NonceOrSaltSignature::Nonce(e.encrypted_nonce),
|
||||
/// key_bytes: e.encrypted_public_key,
|
||||
/// encrypted_challenge: e.encrypted_nonce,
|
||||
/// }.get()
|
||||
/// ).await?;
|
||||
/// conn.set_encryption_key(e.secret_key);
|
||||
|
|
|
@ -76,8 +76,7 @@ mod tests {
|
|||
|
||||
use crate::{
|
||||
packets::login::{
|
||||
serverbound_hello_packet::{ProfilePublicKeyData, ServerboundHelloPacket},
|
||||
ServerboundLoginPacket,
|
||||
serverbound_hello_packet::ServerboundHelloPacket, ServerboundLoginPacket,
|
||||
},
|
||||
read::read_packet,
|
||||
write::write_packet,
|
||||
|
@ -88,13 +87,8 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn test_hello_packet() {
|
||||
let packet = ServerboundHelloPacket {
|
||||
username: "test".to_string(),
|
||||
public_key: Some(ProfilePublicKeyData {
|
||||
expires_at: 0,
|
||||
key: b"idontthinkthisreallymattersijustwantittobelongforthetest".to_vec(),
|
||||
key_signature: b"idontthinkthisreallymattersijustwantittobelongforthetest".to_vec(),
|
||||
}),
|
||||
profile_id: Some(Uuid::from_u128(0)),
|
||||
name: "test".to_string(),
|
||||
profile_id: Some(Uuid::nil()),
|
||||
}
|
||||
.get();
|
||||
let mut stream = Vec::new();
|
||||
|
@ -117,13 +111,8 @@ mod tests {
|
|||
#[tokio::test]
|
||||
async fn test_double_hello_packet() {
|
||||
let packet = ServerboundHelloPacket {
|
||||
username: "test".to_string(),
|
||||
public_key: Some(ProfilePublicKeyData {
|
||||
expires_at: 0,
|
||||
key: b"idontthinkthisreallymattersijustwantittobelongforthetest".to_vec(),
|
||||
key_signature: b"idontthinkthisreallymattersijustwantittobelongforthetest".to_vec(),
|
||||
}),
|
||||
profile_id: Some(Uuid::from_u128(0)),
|
||||
name: "test".to_string(),
|
||||
profile_id: Some(Uuid::nil()),
|
||||
}
|
||||
.get();
|
||||
let mut stream = Vec::new();
|
||||
|
|
|
@ -79,15 +79,15 @@ pub enum BrigadierString {
|
|||
GreedyPhrase = 2,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, McBuf)]
|
||||
pub enum BrigadierParser {
|
||||
Bool,
|
||||
Double(BrigadierNumber<f64>),
|
||||
Float(BrigadierNumber<f32>),
|
||||
Double(BrigadierNumber<f64>),
|
||||
Integer(BrigadierNumber<i32>),
|
||||
Long(BrigadierNumber<i64>),
|
||||
String(BrigadierString),
|
||||
Entity { single: bool, players_only: bool },
|
||||
Entity(EntityParser),
|
||||
GameProfile,
|
||||
BlockPos,
|
||||
ColumnPos,
|
||||
|
@ -100,283 +100,61 @@ pub enum BrigadierParser {
|
|||
Color,
|
||||
Component,
|
||||
Message,
|
||||
Nbt,
|
||||
NbtCompoundTag,
|
||||
NbtTag,
|
||||
NbtPath,
|
||||
Objective,
|
||||
ObjectiveCriteira,
|
||||
ObjectiveCriteria,
|
||||
Operation,
|
||||
Particle,
|
||||
Rotation,
|
||||
Angle,
|
||||
Rotation,
|
||||
ScoreboardSlot,
|
||||
ScoreHolder { allows_multiple: bool },
|
||||
Swizzle,
|
||||
Team,
|
||||
ItemSlot,
|
||||
ResourceLocation,
|
||||
MobEffect,
|
||||
Function,
|
||||
EntityAnchor,
|
||||
IntRange,
|
||||
FloatRange,
|
||||
ItemEnchantment,
|
||||
EntitySummon,
|
||||
Dimension,
|
||||
Uuid,
|
||||
NbtTag,
|
||||
GameMode,
|
||||
Time,
|
||||
ResourceOrTag { registry_key: ResourceLocation },
|
||||
ResourceOrTagKey { registry_key: ResourceLocation },
|
||||
Resource { registry_key: ResourceLocation },
|
||||
ResourceKey { registry_key: ResourceLocation },
|
||||
TemplateMirror,
|
||||
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> {
|
||||
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)?;
|
||||
Ok(BrigadierParser::Entity {
|
||||
Ok(EntityParser {
|
||||
single: flags & 0x01 != 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),
|
||||
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 {
|
||||
impl McBufWritable for EntityParser {
|
||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||
match &self {
|
||||
BrigadierParser::Bool => {
|
||||
u32::var_write_into(&0, buf)?;
|
||||
}
|
||||
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)?;
|
||||
let mut flags: u8 = 0;
|
||||
if self.single {
|
||||
flags |= 0x01;
|
||||
}
|
||||
if self.players_only {
|
||||
flags |= 0x02;
|
||||
}
|
||||
flags.write_into(buf)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -412,7 +190,7 @@ impl McBufReadable for BrigadierNodeStub {
|
|||
} else {
|
||||
None
|
||||
};
|
||||
return Ok(BrigadierNodeStub {
|
||||
let node = BrigadierNodeStub {
|
||||
is_executable,
|
||||
children,
|
||||
redirect_node,
|
||||
|
@ -421,10 +199,11 @@ impl McBufReadable for BrigadierNodeStub {
|
|||
parser,
|
||||
suggestions_type,
|
||||
},
|
||||
});
|
||||
};
|
||||
return Ok(node);
|
||||
}
|
||||
// literal node
|
||||
if node_type == 1 {
|
||||
else if node_type == 1 {
|
||||
let name = String::read_from(buf)?;
|
||||
return Ok(BrigadierNodeStub {
|
||||
is_executable,
|
||||
|
|
|
@ -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,
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
use super::clientbound_player_chat_packet::PackedMessageSignature;
|
||||
use azalea_buf::McBuf;
|
||||
use azalea_crypto::MessageSignature;
|
||||
use azalea_protocol_macros::ClientboundGamePacket;
|
||||
|
||||
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
|
||||
pub struct ClientboundDeleteChatPacket {
|
||||
pub message_signature: MessageSignature,
|
||||
pub signature: PackedMessageSignature,
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
|
@ -1,13 +1,14 @@
|
|||
use std::io::{Cursor, Write};
|
||||
|
||||
use azalea_buf::{BufReadError, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable};
|
||||
use azalea_core::BlockPos;
|
||||
use azalea_protocol_macros::ClientboundGamePacket;
|
||||
use std::io::{Cursor, Write};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, ClientboundGamePacket)]
|
||||
pub struct ClientboundExplodePacket {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
pub z: f32,
|
||||
pub x: f64,
|
||||
pub y: f64,
|
||||
pub z: f64,
|
||||
pub power: f32,
|
||||
pub to_blow: Vec<BlockPos>,
|
||||
pub knockback_x: f32,
|
||||
|
@ -17,9 +18,9 @@ pub struct ClientboundExplodePacket {
|
|||
|
||||
impl McBufReadable for ClientboundExplodePacket {
|
||||
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
||||
let x = f32::read_from(buf)?;
|
||||
let y = f32::read_from(buf)?;
|
||||
let z = f32::read_from(buf)?;
|
||||
let x = f64::read_from(buf)?;
|
||||
let y = f64::read_from(buf)?;
|
||||
let z = f64::read_from(buf)?;
|
||||
let power = f32::read_from(buf)?;
|
||||
|
||||
let x_floor = x.floor() as i32;
|
||||
|
|
174
azalea-protocol/src/packets/game/clientbound_player_chat_packet.rs
Executable file → Normal file
174
azalea-protocol/src/packets/game/clientbound_player_chat_packet.rs
Executable file → Normal file
|
@ -1,19 +1,57 @@
|
|||
use azalea_buf::McBuf;
|
||||
use azalea_buf::{
|
||||
BufReadError, McBuf, McBufReadable, McBufVarReadable, McBufVarWritable, McBufWritable,
|
||||
};
|
||||
use azalea_chat::{
|
||||
translatable_component::{StringOrComponent, TranslatableComponent},
|
||||
Component,
|
||||
};
|
||||
use azalea_core::BitSet;
|
||||
use azalea_crypto::{MessageSignature, SignedMessageHeader};
|
||||
use azalea_crypto::MessageSignature;
|
||||
use azalea_protocol_macros::ClientboundGamePacket;
|
||||
use std::io::{Cursor, Write};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, McBuf, ClientboundGamePacket, PartialEq)]
|
||||
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,
|
||||
}
|
||||
|
||||
#[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)]
|
||||
pub enum ChatType {
|
||||
Chat = 0,
|
||||
|
@ -32,47 +70,36 @@ pub struct ChatTypeBound {
|
|||
pub target_name: Option<Component>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, McBuf, PartialEq)]
|
||||
pub struct PlayerChatMessage {
|
||||
pub signed_header: SignedMessageHeader,
|
||||
pub header_signature: MessageSignature,
|
||||
pub signed_body: SignedMessageBody,
|
||||
pub unsigned_content: Option<Component>,
|
||||
pub filter_mask: FilterMask,
|
||||
// must be in Client
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct MessageSignatureCache {
|
||||
pub entries: Vec<Option<MessageSignature>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, McBuf)]
|
||||
pub struct SignedMessageBody {
|
||||
pub content: ChatMessageContent,
|
||||
pub timestamp: u64,
|
||||
pub salt: u64,
|
||||
pub last_seen: Vec<LastSeenMessagesEntry>,
|
||||
}
|
||||
// impl MessageSignatureCache {
|
||||
// pub fn unpacker(&self) -> impl Fn(u32) -> Option<SignedMessageBody> {
|
||||
|
||||
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
|
||||
/// for the whole message including the sender part, use
|
||||
/// [`ClientboundPlayerChatPacket::message`].
|
||||
pub fn content(&self, only_secure_chat: bool) -> Component {
|
||||
if only_secure_chat {
|
||||
return self
|
||||
.signed_body
|
||||
.content
|
||||
.decorated
|
||||
.clone()
|
||||
.unwrap_or_else(|| Component::from(self.signed_body.content.plain.clone()));
|
||||
}
|
||||
pub fn content(&self) -> Component {
|
||||
self.unsigned_content
|
||||
.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.
|
||||
pub fn message(&self, only_secure_chat: bool) -> Component {
|
||||
pub fn message(&self) -> Component {
|
||||
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 translation_key = self.chat_type.chat_type.chat_translation_key();
|
||||
|
@ -117,45 +144,66 @@ impl ChatType {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, McBuf, PartialEq)]
|
||||
pub struct LastSeenMessagesEntry {
|
||||
pub profile_id: Uuid,
|
||||
pub last_signature: MessageSignature,
|
||||
}
|
||||
impl McBufReadable for PackedMessageSignature {
|
||||
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
||||
let id = u32::var_read_from(buf)?;
|
||||
if id == 0 {
|
||||
let full_signature = MessageSignature::read_from(buf)?;
|
||||
|
||||
#[derive(Clone, Debug, McBuf, Default)]
|
||||
pub struct LastSeenMessagesUpdate {
|
||||
pub last_seen: Vec<LastSeenMessagesEntry>,
|
||||
pub last_received: Option<LastSeenMessagesEntry>,
|
||||
Ok(PackedMessageSignature::Signature(Box::new(full_signature)))
|
||||
} else {
|
||||
Ok(PackedMessageSignature::Id(id - 1))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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)]
|
||||
pub enum FilterMask {
|
||||
PassThrough,
|
||||
FullyFiltered,
|
||||
PartiallyFiltered(BitSet),
|
||||
impl McBufWritable for PackedMessageSignature {
|
||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||
match self {
|
||||
PackedMessageSignature::Signature(full_signature) => {
|
||||
0u32.var_write_into(buf)?;
|
||||
full_signature.write_into(buf)?;
|
||||
}
|
||||
PackedMessageSignature::Id(id) => {
|
||||
(id + 1).var_write_into(buf)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use azalea_buf::McBufReadable;
|
||||
use std::io::Cursor;
|
||||
use std::backtrace::Backtrace;
|
||||
|
||||
// you can remove or update this test if it breaks because mojang changed the structure of the packet again
|
||||
#[test]
|
||||
fn test_chat_type() {
|
||||
let chat_type_enum = ChatType::read_from(&mut Cursor::new(&[0x06])).unwrap();
|
||||
assert_eq!(chat_type_enum, ChatType::EmoteCommand);
|
||||
assert_eq!(
|
||||
ChatType::read_from(&mut Cursor::new(&[0x07])).unwrap(),
|
||||
ChatType::Chat
|
||||
);
|
||||
fn test_player_chat_packet() {
|
||||
let data: [u8; 295] = [
|
||||
47, 247, 69, 164, 160, 108, 63, 217, 178, 34, 4, 161, 47, 115, 192, 126, 0, 0, 11, 72,
|
||||
101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 0, 0, 1, 132, 209, 9, 72, 139, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 242, 1, 123, 34, 105, 110, 115, 101, 114, 116, 105, 111,
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
}
|
|
@ -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>,
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -11,6 +11,6 @@ pub struct ClientboundRespawnPacket {
|
|||
pub previous_player_game_type: OptionalGameType,
|
||||
pub is_debug: bool,
|
||||
pub is_flat: bool,
|
||||
pub keep_all_player_data: bool,
|
||||
pub data_to_keep: u8,
|
||||
pub last_death_location: Option<GlobalPos>,
|
||||
}
|
||||
|
|
|
@ -6,6 +6,5 @@ use azalea_protocol_macros::ClientboundGamePacket;
|
|||
pub struct ClientboundServerDataPacket {
|
||||
pub motd: Option<Component>,
|
||||
pub icon_base64: Option<String>,
|
||||
pub previews_chat: bool,
|
||||
pub enforces_secure_chat: bool,
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use super::clientbound_sound_packet::SoundSource;
|
||||
use azalea_buf::McBuf;
|
||||
use azalea_protocol_macros::ClientboundGamePacket;
|
||||
use azalea_registry::OptionalRegistry;
|
||||
|
||||
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
|
||||
pub struct ClientboundSoundEntityPacket {
|
||||
pub sound: azalea_registry::SoundEvent,
|
||||
pub sound: OptionalRegistry<azalea_registry::SoundEvent>,
|
||||
pub source: SoundSource,
|
||||
#[var]
|
||||
pub id: u32,
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use azalea_buf::McBuf;
|
||||
use azalea_protocol_macros::ClientboundGamePacket;
|
||||
use azalea_registry::OptionalRegistry;
|
||||
|
||||
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
|
||||
pub struct ClientboundSoundPacket {
|
||||
pub sound: azalea_registry::SoundEvent,
|
||||
pub sound: OptionalRegistry<azalea_registry::SoundEvent>,
|
||||
pub source: SoundSource,
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
|
|
|
@ -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>,
|
||||
}
|
|
@ -20,17 +20,27 @@ pub struct Recipe {
|
|||
pub struct ShapelessRecipe {
|
||||
/// Used to group similar recipes together in the recipe book.
|
||||
/// Tag is present in recipe JSON
|
||||
group: String,
|
||||
ingredients: Vec<Ingredient>,
|
||||
result: Slot,
|
||||
pub group: String,
|
||||
pub category: CraftingBookCategory,
|
||||
pub ingredients: Vec<Ingredient>,
|
||||
pub result: Slot,
|
||||
}
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ShapedRecipe {
|
||||
width: usize,
|
||||
height: usize,
|
||||
group: String,
|
||||
ingredients: Vec<Ingredient>,
|
||||
result: Slot,
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
pub group: String,
|
||||
pub category: CraftingBookCategory,
|
||||
pub ingredients: Vec<Ingredient>,
|
||||
pub result: Slot,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Copy, McBuf)]
|
||||
pub enum CraftingBookCategory {
|
||||
Building = 0,
|
||||
Redstone,
|
||||
Equipment,
|
||||
Misc,
|
||||
}
|
||||
|
||||
impl McBufWritable for ShapedRecipe {
|
||||
|
@ -38,6 +48,7 @@ impl McBufWritable for ShapedRecipe {
|
|||
(self.width as u32).var_write_into(buf)?;
|
||||
(self.height as u32).var_write_into(buf)?;
|
||||
self.group.write_into(buf)?;
|
||||
self.category.write_into(buf)?;
|
||||
for ingredient in &self.ingredients {
|
||||
ingredient.write_into(buf)?;
|
||||
}
|
||||
|
@ -51,6 +62,7 @@ impl McBufReadable for ShapedRecipe {
|
|||
let width = 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 category = CraftingBookCategory::read_from(buf)?;
|
||||
let mut ingredients = Vec::with_capacity(width * height);
|
||||
for _ in 0..width * height {
|
||||
ingredients.push(Ingredient::read_from(buf)?);
|
||||
|
@ -61,6 +73,7 @@ impl McBufReadable for ShapedRecipe {
|
|||
width,
|
||||
height,
|
||||
group,
|
||||
category,
|
||||
ingredients,
|
||||
result,
|
||||
})
|
||||
|
@ -69,49 +82,55 @@ impl McBufReadable for ShapedRecipe {
|
|||
|
||||
#[derive(Clone, Debug, McBuf)]
|
||||
pub struct CookingRecipe {
|
||||
group: String,
|
||||
ingredient: Ingredient,
|
||||
result: Slot,
|
||||
experience: f32,
|
||||
pub group: String,
|
||||
pub category: CraftingBookCategory,
|
||||
pub ingredient: Ingredient,
|
||||
pub result: Slot,
|
||||
pub experience: f32,
|
||||
#[var]
|
||||
cooking_time: u32,
|
||||
pub cooking_time: u32,
|
||||
}
|
||||
#[derive(Clone, Debug, McBuf)]
|
||||
pub struct StoneCuttingRecipe {
|
||||
group: String,
|
||||
ingredient: Ingredient,
|
||||
result: Slot,
|
||||
pub struct StoneCutterRecipe {
|
||||
pub group: String,
|
||||
pub ingredient: Ingredient,
|
||||
pub result: Slot,
|
||||
}
|
||||
#[derive(Clone, Debug, McBuf)]
|
||||
pub struct SmithingRecipe {
|
||||
base: Ingredient,
|
||||
addition: Ingredient,
|
||||
result: Slot,
|
||||
pub base: Ingredient,
|
||||
pub addition: Ingredient,
|
||||
pub result: Slot,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, McBuf)]
|
||||
pub struct SimpleRecipe {
|
||||
pub category: CraftingBookCategory,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, McBuf)]
|
||||
pub enum RecipeData {
|
||||
CraftingShapeless(ShapelessRecipe),
|
||||
CraftingShaped(ShapedRecipe),
|
||||
CraftingSpecialArmorDye,
|
||||
CraftingSpecialBookCloning,
|
||||
CraftingSpecialMapCloning,
|
||||
CraftingSpecialMapExtending,
|
||||
CraftingSpecialFireworkRocket,
|
||||
CraftingSpecialFireworkStar,
|
||||
CraftingSpecialFireworkStarFade,
|
||||
CraftingSpecialRepairItem,
|
||||
CraftingSpecialTippedArrow,
|
||||
CraftingSpecialBannerDuplicate,
|
||||
CraftingSpecialBannerAddPattern,
|
||||
CraftingSpecialShieldDecoration,
|
||||
CraftingSpecialShulkerBoxColoring,
|
||||
CraftingSpecialSuspiciousStew,
|
||||
CraftingSpecialArmorDye(SimpleRecipe),
|
||||
CraftingSpecialBookCloning(SimpleRecipe),
|
||||
CraftingSpecialMapCloning(SimpleRecipe),
|
||||
CraftingSpecialMapExtending(SimpleRecipe),
|
||||
CraftingSpecialFireworkRocket(SimpleRecipe),
|
||||
CraftingSpecialFireworkStar(SimpleRecipe),
|
||||
CraftingSpecialFireworkStarFade(SimpleRecipe),
|
||||
CraftingSpecialRepairItem(SimpleRecipe),
|
||||
CraftingSpecialTippedArrow(SimpleRecipe),
|
||||
CraftingSpecialBannerDuplicate(SimpleRecipe),
|
||||
CraftingSpecialBannerAddPattern(SimpleRecipe),
|
||||
CraftingSpecialShieldDecoration(SimpleRecipe),
|
||||
CraftingSpecialShulkerBoxColoring(SimpleRecipe),
|
||||
CraftingSpecialSuspiciousStew(SimpleRecipe),
|
||||
Smelting(CookingRecipe),
|
||||
Blasting(CookingRecipe),
|
||||
Smoking(CookingRecipe),
|
||||
CampfireCooking(CookingRecipe),
|
||||
Stonecutting(StoneCuttingRecipe),
|
||||
Stonecutting(StoneCutterRecipe),
|
||||
Smithing(SmithingRecipe),
|
||||
}
|
||||
|
||||
|
@ -122,148 +141,52 @@ pub struct Ingredient {
|
|||
|
||||
impl McBufWritable for Recipe {
|
||||
fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
|
||||
match &self.data {
|
||||
RecipeData::CraftingShapeless(recipe) => {
|
||||
ResourceLocation::new("minecraft:crafting_shapeless")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
recipe.write_into(buf)?;
|
||||
let resource_location = match &self.data {
|
||||
RecipeData::CraftingShapeless(_) => "minecraft:crafting_shapeless",
|
||||
RecipeData::CraftingShaped(_) => "minecraft:crafting_shaped",
|
||||
RecipeData::CraftingSpecialArmorDye(_) => "minecraft:crafting_special_armordye",
|
||||
RecipeData::CraftingSpecialBookCloning(_) => "minecraft:crafting_special_bookcloning",
|
||||
RecipeData::CraftingSpecialMapCloning(_) => "minecraft:crafting_special_mapcloning",
|
||||
RecipeData::CraftingSpecialMapExtending(_) => "minecraft:crafting_special_mapextending",
|
||||
RecipeData::CraftingSpecialFireworkRocket(_) => {
|
||||
"minecraft:crafting_special_firework_rocket"
|
||||
}
|
||||
RecipeData::CraftingShaped(recipe) => {
|
||||
ResourceLocation::new("minecraft:crafting_shaped")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
recipe.write_into(buf)?;
|
||||
RecipeData::CraftingSpecialFireworkStar(_) => {
|
||||
"minecraft:crafting_special_firework_star"
|
||||
}
|
||||
RecipeData::CraftingSpecialArmorDye => {
|
||||
ResourceLocation::new("minecraft:crafting_special_armordye")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
|
||||
RecipeData::CraftingSpecialFireworkStarFade(_) => {
|
||||
"minecraft:crafting_special_firework_star_fade"
|
||||
}
|
||||
RecipeData::CraftingSpecialBookCloning => {
|
||||
ResourceLocation::new("minecraft:crafting_special_bookcloning")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
RecipeData::CraftingSpecialRepairItem(_) => "minecraft:crafting_special_repairitem",
|
||||
RecipeData::CraftingSpecialTippedArrow(_) => "minecraft:crafting_special_tippedarrow",
|
||||
RecipeData::CraftingSpecialBannerDuplicate(_) => {
|
||||
"minecraft:crafting_special_bannerduplicate"
|
||||
}
|
||||
RecipeData::CraftingSpecialMapCloning => {
|
||||
ResourceLocation::new("minecraft:crafting_special_mapcloning")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
RecipeData::CraftingSpecialBannerAddPattern(_) => {
|
||||
"minecraft:crafting_special_banneraddpattern"
|
||||
}
|
||||
RecipeData::CraftingSpecialMapExtending => {
|
||||
ResourceLocation::new("minecraft:crafting_special_mapextending")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
RecipeData::CraftingSpecialShieldDecoration(_) => {
|
||||
"minecraft:crafting_special_shielddecoration"
|
||||
}
|
||||
RecipeData::CraftingSpecialFireworkRocket => {
|
||||
ResourceLocation::new("minecraft:crafting_special_firework_rocket")
|
||||
.unwrap()
|
||||
.write_into(buf)?;
|
||||
self.identifier.write_into(buf)?;
|
||||
RecipeData::CraftingSpecialShulkerBoxColoring(_) => {
|
||||
"minecraft:crafting_special_shulkerboxcoloring"
|
||||
}
|
||||
RecipeData::CraftingSpecialFireworkStar => {
|
||||
ResourceLocation::new("minecraft:crafting_special_firework_star")
|
||||
.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::CraftingSpecialSuspiciousStew(_) => {
|
||||
"minecraft:crafting_special_suspiciousstew"
|
||||
}
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
@ -275,83 +198,70 @@ impl McBufReadable for Recipe {
|
|||
|
||||
// rust doesn't let us match ResourceLocation so we have to do a big
|
||||
// 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)?)
|
||||
} else if recipe_type == ResourceLocation::new("minecraft:crafting_shaped").unwrap() {
|
||||
}
|
||||
"minecraft:crafting_shaped" => {
|
||||
RecipeData::CraftingShaped(ShapedRecipe::read_from(buf)?)
|
||||
} else if recipe_type
|
||||
== ResourceLocation::new("minecraft:crafting_special_armordye").unwrap()
|
||||
{
|
||||
RecipeData::CraftingSpecialArmorDye
|
||||
} else if recipe_type
|
||||
== ResourceLocation::new("minecraft:crafting_special_bookcloning").unwrap()
|
||||
{
|
||||
RecipeData::CraftingSpecialBookCloning
|
||||
} else if recipe_type
|
||||
== ResourceLocation::new("minecraft:crafting_special_mapcloning").unwrap()
|
||||
{
|
||||
RecipeData::CraftingSpecialMapCloning
|
||||
} else if recipe_type
|
||||
== ResourceLocation::new("minecraft:crafting_special_mapextending").unwrap()
|
||||
{
|
||||
RecipeData::CraftingSpecialMapExtending
|
||||
} else if recipe_type
|
||||
== ResourceLocation::new("minecraft:crafting_special_firework_rocket").unwrap()
|
||||
{
|
||||
RecipeData::CraftingSpecialFireworkRocket
|
||||
} else if recipe_type
|
||||
== ResourceLocation::new("minecraft:crafting_special_firework_star").unwrap()
|
||||
{
|
||||
RecipeData::CraftingSpecialFireworkStar
|
||||
} else if recipe_type
|
||||
== ResourceLocation::new("minecraft:crafting_special_firework_star_fade").unwrap()
|
||||
{
|
||||
RecipeData::CraftingSpecialFireworkStarFade
|
||||
} else if recipe_type
|
||||
== ResourceLocation::new("minecraft:crafting_special_repairitem").unwrap()
|
||||
{
|
||||
RecipeData::CraftingSpecialRepairItem
|
||||
} else if recipe_type
|
||||
== ResourceLocation::new("minecraft:crafting_special_tippedarrow").unwrap()
|
||||
{
|
||||
RecipeData::CraftingSpecialTippedArrow
|
||||
} else if recipe_type
|
||||
== ResourceLocation::new("minecraft:crafting_special_bannerduplicate").unwrap()
|
||||
{
|
||||
RecipeData::CraftingSpecialBannerDuplicate
|
||||
} else if recipe_type
|
||||
== ResourceLocation::new("minecraft:crafting_special_banneraddpattern").unwrap()
|
||||
{
|
||||
RecipeData::CraftingSpecialBannerAddPattern
|
||||
} else if recipe_type
|
||||
== ResourceLocation::new("minecraft:crafting_special_shielddecoration").unwrap()
|
||||
{
|
||||
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() {
|
||||
}
|
||||
"minecraft:crafting_special_armordye" => {
|
||||
RecipeData::CraftingSpecialArmorDye(SimpleRecipe::read_from(buf)?)
|
||||
}
|
||||
"minecraft:crafting_special_bookcloning" => {
|
||||
RecipeData::CraftingSpecialBookCloning(SimpleRecipe::read_from(buf)?)
|
||||
}
|
||||
"minecraft:crafting_special_mapcloning" => {
|
||||
RecipeData::CraftingSpecialMapCloning(SimpleRecipe::read_from(buf)?)
|
||||
}
|
||||
"minecraft:crafting_special_mapextending" => {
|
||||
RecipeData::CraftingSpecialMapExtending(SimpleRecipe::read_from(buf)?)
|
||||
}
|
||||
"minecraft:crafting_special_firework_rocket" => {
|
||||
RecipeData::CraftingSpecialFireworkRocket(SimpleRecipe::read_from(buf)?)
|
||||
}
|
||||
"minecraft:crafting_special_firework_star" => {
|
||||
RecipeData::CraftingSpecialFireworkStar(SimpleRecipe::read_from(buf)?)
|
||||
}
|
||||
"minecraft:crafting_special_firework_star_fade" => {
|
||||
RecipeData::CraftingSpecialFireworkStarFade(SimpleRecipe::read_from(buf)?)
|
||||
}
|
||||
"minecraft:crafting_special_repairitem" => {
|
||||
RecipeData::CraftingSpecialRepairItem(SimpleRecipe::read_from(buf)?)
|
||||
}
|
||||
"minecraft:crafting_special_tippedarrow" => {
|
||||
RecipeData::CraftingSpecialTippedArrow(SimpleRecipe::read_from(buf)?)
|
||||
}
|
||||
"minecraft:crafting_special_bannerduplicate" => {
|
||||
RecipeData::CraftingSpecialBannerDuplicate(SimpleRecipe::read_from(buf)?)
|
||||
}
|
||||
"minecraft:crafting_special_banneraddpattern" => {
|
||||
RecipeData::CraftingSpecialBannerAddPattern(SimpleRecipe::read_from(buf)?)
|
||||
}
|
||||
"minecraft:crafting_special_shielddecoration" => {
|
||||
RecipeData::CraftingSpecialShieldDecoration(SimpleRecipe::read_from(buf)?)
|
||||
}
|
||||
"minecraft:crafting_special_shulkerboxcoloring" => {
|
||||
RecipeData::CraftingSpecialShulkerBoxColoring(SimpleRecipe::read_from(buf)?)
|
||||
}
|
||||
"minecraft:crafting_special_suspiciousstew" => {
|
||||
RecipeData::CraftingSpecialSuspiciousStew(SimpleRecipe::read_from(buf)?)
|
||||
}
|
||||
"minecraft:smelting" => RecipeData::Smelting(CookingRecipe::read_from(buf)?),
|
||||
"minecraft:blasting" => RecipeData::Blasting(CookingRecipe::read_from(buf)?),
|
||||
"minecraft:smoking" => RecipeData::Smoking(CookingRecipe::read_from(buf)?),
|
||||
"minecraft:campfire_cooking" => {
|
||||
RecipeData::CampfireCooking(CookingRecipe::read_from(buf)?)
|
||||
} else if recipe_type == ResourceLocation::new("minecraft:stonecutting").unwrap() {
|
||||
RecipeData::Stonecutting(StoneCuttingRecipe::read_from(buf)?)
|
||||
} else if recipe_type == ResourceLocation::new("minecraft:smithing").unwrap() {
|
||||
RecipeData::Smithing(SmithingRecipe::read_from(buf)?)
|
||||
} else {
|
||||
}
|
||||
"minecraft:stonecutting" => {
|
||||
RecipeData::Stonecutting(StoneCutterRecipe::read_from(buf)?)
|
||||
}
|
||||
"minecraft:smithing" => RecipeData::Smithing(SmithingRecipe::read_from(buf)?),
|
||||
_ => {
|
||||
return Err(BufReadError::UnexpectedStringEnumVariant {
|
||||
id: recipe_type.to_string(),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let recipe = Recipe { identifier, data };
|
||||
|
|
|
@ -10,7 +10,6 @@ pub mod clientbound_block_event_packet;
|
|||
pub mod clientbound_block_update_packet;
|
||||
pub mod clientbound_boss_event_packet;
|
||||
pub mod clientbound_change_difficulty_packet;
|
||||
pub mod clientbound_chat_preview_packet;
|
||||
pub mod clientbound_command_suggestions_packet;
|
||||
pub mod clientbound_commands_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_custom_chat_completions_packet;
|
||||
pub mod clientbound_custom_payload_packet;
|
||||
pub mod clientbound_custom_sound_packet;
|
||||
pub mod clientbound_delete_chat_packet;
|
||||
pub mod clientbound_disconnect_packet;
|
||||
pub mod clientbound_disguised_chat_packet;
|
||||
pub mod clientbound_entity_event_packet;
|
||||
pub mod clientbound_explode_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_place_ghost_recipe_packet;
|
||||
pub mod clientbound_player_abilities_packet;
|
||||
pub mod clientbound_player_chat_header_packet;
|
||||
pub mod clientbound_player_chat_packet;
|
||||
pub mod clientbound_player_combat_end_packet;
|
||||
pub mod clientbound_player_combat_enter_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_position_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_radius_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_entity_data_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_update_advancements_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_recipes_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_command_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_information_packet;
|
||||
pub mod serverbound_command_suggestion_packet;
|
||||
|
@ -168,33 +167,33 @@ declare_state_packets!(
|
|||
0x03: serverbound_chat_ack_packet::ServerboundChatAckPacket,
|
||||
0x04: serverbound_chat_command_packet::ServerboundChatCommandPacket,
|
||||
0x05: serverbound_chat_packet::ServerboundChatPacket,
|
||||
0x06: serverbound_chat_preview_packet::ServerboundChatPreviewPacket,
|
||||
0x07: serverbound_client_command_packet::ServerboundClientCommandPacket,
|
||||
0x08: serverbound_client_information_packet::ServerboundClientInformationPacket,
|
||||
0x09: serverbound_command_suggestion_packet::ServerboundCommandSuggestionPacket,
|
||||
0x0a: serverbound_container_button_click_packet::ServerboundContainerButtonClickPacket,
|
||||
0x0b: serverbound_container_click_packet::ServerboundContainerClickPacket,
|
||||
0x0c: serverbound_container_close_packet::ServerboundContainerClosePacket,
|
||||
0x0d: serverbound_custom_payload_packet::ServerboundCustomPayloadPacket,
|
||||
0x0e: serverbound_edit_book_packet::ServerboundEditBookPacket,
|
||||
0x0f: serverbound_entity_tag_query::ServerboundEntityTagQuery,
|
||||
0x10: serverbound_interact_packet::ServerboundInteractPacket,
|
||||
0x11: serverbound_jigsaw_generate_packet::ServerboundJigsawGeneratePacket,
|
||||
0x12: serverbound_keep_alive_packet::ServerboundKeepAlivePacket,
|
||||
0x13: serverbound_lock_difficulty_packet::ServerboundLockDifficultyPacket,
|
||||
0x14: serverbound_move_player_pos_packet::ServerboundMovePlayerPosPacket,
|
||||
0x15: serverbound_move_player_pos_rot_packet::ServerboundMovePlayerPosRotPacket,
|
||||
0x16: serverbound_move_player_rot_packet::ServerboundMovePlayerRotPacket,
|
||||
0x17: serverbound_move_player_status_only_packet::ServerboundMovePlayerStatusOnlyPacket,
|
||||
0x18: serverbound_move_vehicle_packet::ServerboundMoveVehiclePacket,
|
||||
0x19: serverbound_paddle_boat_packet::ServerboundPaddleBoatPacket,
|
||||
0x1a: serverbound_pick_item_packet::ServerboundPickItemPacket,
|
||||
0x1b: serverbound_place_recipe_packet::ServerboundPlaceRecipePacket,
|
||||
0x1c: serverbound_player_abilities_packet::ServerboundPlayerAbilitiesPacket,
|
||||
0x1d: serverbound_player_action_packet::ServerboundPlayerActionPacket,
|
||||
0x1e: serverbound_player_command_packet::ServerboundPlayerCommandPacket,
|
||||
0x1f: serverbound_player_input_packet::ServerboundPlayerInputPacket,
|
||||
0x20: serverbound_pong_packet::ServerboundPongPacket,
|
||||
0x06: serverbound_client_command_packet::ServerboundClientCommandPacket,
|
||||
0x07: serverbound_client_information_packet::ServerboundClientInformationPacket,
|
||||
0x08: serverbound_command_suggestion_packet::ServerboundCommandSuggestionPacket,
|
||||
0x09: serverbound_container_button_click_packet::ServerboundContainerButtonClickPacket,
|
||||
0x0a: serverbound_container_click_packet::ServerboundContainerClickPacket,
|
||||
0x0b: serverbound_container_close_packet::ServerboundContainerClosePacket,
|
||||
0x0c: serverbound_custom_payload_packet::ServerboundCustomPayloadPacket,
|
||||
0x0d: serverbound_edit_book_packet::ServerboundEditBookPacket,
|
||||
0x0e: serverbound_entity_tag_query::ServerboundEntityTagQuery,
|
||||
0x0f: serverbound_interact_packet::ServerboundInteractPacket,
|
||||
0x10: serverbound_jigsaw_generate_packet::ServerboundJigsawGeneratePacket,
|
||||
0x11: serverbound_keep_alive_packet::ServerboundKeepAlivePacket,
|
||||
0x12: serverbound_lock_difficulty_packet::ServerboundLockDifficultyPacket,
|
||||
0x13: serverbound_move_player_pos_packet::ServerboundMovePlayerPosPacket,
|
||||
0x14: serverbound_move_player_pos_rot_packet::ServerboundMovePlayerPosRotPacket,
|
||||
0x15: serverbound_move_player_rot_packet::ServerboundMovePlayerRotPacket,
|
||||
0x16: serverbound_move_player_status_only_packet::ServerboundMovePlayerStatusOnlyPacket,
|
||||
0x17: serverbound_move_vehicle_packet::ServerboundMoveVehiclePacket,
|
||||
0x18: serverbound_paddle_boat_packet::ServerboundPaddleBoatPacket,
|
||||
0x19: serverbound_pick_item_packet::ServerboundPickItemPacket,
|
||||
0x1a: serverbound_place_recipe_packet::ServerboundPlaceRecipePacket,
|
||||
0x1b: serverbound_player_abilities_packet::ServerboundPlayerAbilitiesPacket,
|
||||
0x1c: serverbound_player_action_packet::ServerboundPlayerActionPacket,
|
||||
0x1d: serverbound_player_command_packet::ServerboundPlayerCommandPacket,
|
||||
0x1e: serverbound_player_input_packet::ServerboundPlayerInputPacket,
|
||||
0x1f: serverbound_pong_packet::ServerboundPongPacket,
|
||||
0x20: serverbound_chat_session_update_packet::ServerboundChatSessionUpdatePacket,
|
||||
0x21: serverbound_recipe_book_change_settings_packet::ServerboundRecipeBookChangeSettingsPacket,
|
||||
0x22: serverbound_recipe_book_seen_recipe_packet::ServerboundRecipeBookSeenRecipePacket,
|
||||
0x23: serverbound_rename_item_packet::ServerboundRenameItemPacket,
|
||||
|
@ -227,100 +226,99 @@ declare_state_packets!(
|
|||
0x09: clientbound_block_update_packet::ClientboundBlockUpdatePacket,
|
||||
0x0a: clientbound_boss_event_packet::ClientboundBossEventPacket,
|
||||
0x0b: clientbound_change_difficulty_packet::ClientboundChangeDifficultyPacket,
|
||||
0x0c: clientbound_chat_preview_packet::ClientboundChatPreviewPacket,
|
||||
0x0e: clientbound_command_suggestions_packet::ClientboundCommandSuggestionsPacket,
|
||||
0x0f: clientbound_commands_packet::ClientboundCommandsPacket,
|
||||
0x10: clientbound_container_close_packet::ClientboundContainerClosePacket,
|
||||
0x11: clientbound_container_set_content_packet::ClientboundContainerSetContentPacket,
|
||||
0x12: clientbound_container_set_data_packet::ClientboundContainerSetDataPacket,
|
||||
0x13: clientbound_container_set_slot_packet::ClientboundContainerSetSlotPacket,
|
||||
0x14: clientbound_cooldown_packet::ClientboundCooldownPacket,
|
||||
0x15: clientbound_custom_chat_completions_packet::ClientboundCustomChatCompletionsPacket,
|
||||
0x16: clientbound_custom_payload_packet::ClientboundCustomPayloadPacket,
|
||||
0x17: clientbound_custom_sound_packet::ClientboundCustomSoundPacket,
|
||||
0x18: clientbound_delete_chat_packet::ClientboundDeleteChatPacket,
|
||||
0x19: clientbound_disconnect_packet::ClientboundDisconnectPacket,
|
||||
0x1a: clientbound_entity_event_packet::ClientboundEntityEventPacket,
|
||||
0x1b: clientbound_explode_packet::ClientboundExplodePacket,
|
||||
0x1c: clientbound_forget_level_chunk_packet::ClientboundForgetLevelChunkPacket,
|
||||
0x1d: clientbound_game_event_packet::ClientboundGameEventPacket,
|
||||
0x1e: clientbound_horse_screen_open_packet::ClientboundHorseScreenOpenPacket,
|
||||
0x1f: clientbound_initialize_border_packet::ClientboundInitializeBorderPacket,
|
||||
0x20: clientbound_keep_alive_packet::ClientboundKeepAlivePacket,
|
||||
0x21: clientbound_level_chunk_with_light_packet::ClientboundLevelChunkWithLightPacket,
|
||||
0x22: clientbound_level_event_packet::ClientboundLevelEventPacket,
|
||||
0x23: clientbound_level_particles_packet::ClientboundLevelParticlesPacket,
|
||||
0x24: clientbound_light_update_packet::ClientboundLightUpdatePacket,
|
||||
0x25: clientbound_login_packet::ClientboundLoginPacket,
|
||||
0x26: clientbound_map_item_data_packet::ClientboundMapItemDataPacket,
|
||||
0x27: clientbound_merchant_offers_packet::ClientboundMerchantOffersPacket,
|
||||
0x28: clientbound_move_entity_pos_packet::ClientboundMoveEntityPosPacket,
|
||||
0x29: clientbound_move_entity_pos_rot_packet::ClientboundMoveEntityPosRotPacket,
|
||||
0x2a: clientbound_move_entity_rot_packet::ClientboundMoveEntityRotPacket,
|
||||
0x2b: clientbound_move_vehicle_packet::ClientboundMoveVehiclePacket,
|
||||
0x2c: clientbound_open_book_packet::ClientboundOpenBookPacket,
|
||||
0x2d: clientbound_open_screen_packet::ClientboundOpenScreenPacket,
|
||||
0x2e: clientbound_open_sign_editor_packet::ClientboundOpenSignEditorPacket,
|
||||
0x2f: clientbound_ping_packet::ClientboundPingPacket,
|
||||
0x30: clientbound_place_ghost_recipe_packet::ClientboundPlaceGhostRecipePacket,
|
||||
0x31: clientbound_player_abilities_packet::ClientboundPlayerAbilitiesPacket,
|
||||
0x32: clientbound_player_chat_header_packet::ClientboundPlayerChatHeaderPacket,
|
||||
0x33: clientbound_player_chat_packet::ClientboundPlayerChatPacket,
|
||||
0x34: clientbound_player_combat_end_packet::ClientboundPlayerCombatEndPacket,
|
||||
0x35: clientbound_player_combat_enter_packet::ClientboundPlayerCombatEnterPacket,
|
||||
0x36: clientbound_player_combat_kill_packet::ClientboundPlayerCombatKillPacket,
|
||||
0x37: clientbound_player_info_packet::ClientboundPlayerInfoPacket,
|
||||
0x38: clientbound_player_look_at_packet::ClientboundPlayerLookAtPacket,
|
||||
0x39: clientbound_player_position_packet::ClientboundPlayerPositionPacket,
|
||||
0x3a: clientbound_recipe_packet::ClientboundRecipePacket,
|
||||
0x3b: clientbound_remove_entities_packet::ClientboundRemoveEntitiesPacket,
|
||||
0x3c: clientbound_remove_mob_effect_packet::ClientboundRemoveMobEffectPacket,
|
||||
0x3d: clientbound_resource_pack_packet::ClientboundResourcePackPacket,
|
||||
0x3e: clientbound_respawn_packet::ClientboundRespawnPacket,
|
||||
0x3f: clientbound_rotate_head_packet::ClientboundRotateHeadPacket,
|
||||
0x40: clientbound_section_blocks_update_packet::ClientboundSectionBlocksUpdatePacket,
|
||||
0x41: clientbound_select_advancements_tab_packet::ClientboundSelectAdvancementsTabPacket,
|
||||
0x42: clientbound_server_data_packet::ClientboundServerDataPacket,
|
||||
0x43: clientbound_set_action_bar_text_packet::ClientboundSetActionBarTextPacket,
|
||||
0x44: clientbound_set_border_center_packet::ClientboundSetBorderCenterPacket,
|
||||
0x45: clientbound_set_border_lerp_size_packet::ClientboundSetBorderLerpSizePacket,
|
||||
0x46: clientbound_set_border_size_packet::ClientboundSetBorderSizePacket,
|
||||
0x47: clientbound_set_border_warning_delay_packet::ClientboundSetBorderWarningDelayPacket,
|
||||
0x48: clientbound_set_border_warning_distance_packet::ClientboundSetBorderWarningDistancePacket,
|
||||
0x49: clientbound_set_camera_packet::ClientboundSetCameraPacket,
|
||||
0x4a: clientbound_set_carried_item_packet::ClientboundSetCarriedItemPacket,
|
||||
0x4b: clientbound_set_chunk_cache_center_packet::ClientboundSetChunkCacheCenterPacket,
|
||||
0x4c: clientbound_set_chunk_cache_radius_packet::ClientboundSetChunkCacheRadiusPacket,
|
||||
0x4d: clientbound_set_default_spawn_position_packet::ClientboundSetDefaultSpawnPositionPacket,
|
||||
0x4e: clientbound_set_display_chat_preview_packet::ClientboundSetDisplayChatPreviewPacket,
|
||||
0x4f: clientbound_set_display_objective_packet::ClientboundSetDisplayObjectivePacket,
|
||||
0x50: clientbound_set_entity_data_packet::ClientboundSetEntityDataPacket,
|
||||
0x51: clientbound_set_entity_link_packet::ClientboundSetEntityLinkPacket,
|
||||
0x52: clientbound_set_entity_motion_packet::ClientboundSetEntityMotionPacket,
|
||||
0x53: clientbound_set_equipment_packet::ClientboundSetEquipmentPacket,
|
||||
0x54: clientbound_set_experience_packet::ClientboundSetExperiencePacket,
|
||||
0x55: clientbound_set_health_packet::ClientboundSetHealthPacket,
|
||||
0x56: clientbound_set_objective_packet::ClientboundSetObjectivePacket,
|
||||
0x57: clientbound_set_passengers_packet::ClientboundSetPassengersPacket,
|
||||
0x58: clientbound_set_player_team_packet::ClientboundSetPlayerTeamPacket,
|
||||
0x59: clientbound_set_score_packet::ClientboundSetScorePacket,
|
||||
0x5a: clientbound_set_simulation_distance_packet::ClientboundSetSimulationDistancePacket,
|
||||
0x5b: clientbound_set_subtitle_text_packet::ClientboundSetSubtitleTextPacket,
|
||||
0x5c: clientbound_set_time_packet::ClientboundSetTimePacket,
|
||||
0x5d: clientbound_set_title_text_packet::ClientboundSetTitleTextPacket,
|
||||
0x5e: clientbound_set_titles_animation_packet::ClientboundSetTitlesAnimationPacket,
|
||||
0x5f: clientbound_sound_entity_packet::ClientboundSoundEntityPacket,
|
||||
0x60: clientbound_sound_packet::ClientboundSoundPacket,
|
||||
0x61: clientbound_stop_sound_packet::ClientboundStopSoundPacket,
|
||||
0x62: clientbound_system_chat_packet::ClientboundSystemChatPacket,
|
||||
0x63: clientbound_tab_list_packet::ClientboundTabListPacket,
|
||||
0x64: clientbound_tag_query_packet::ClientboundTagQueryPacket,
|
||||
0x65: clientbound_take_item_entity_packet::ClientboundTakeItemEntityPacket,
|
||||
0x66: clientbound_teleport_entity_packet::ClientboundTeleportEntityPacket,
|
||||
0x67: clientbound_update_advancements_packet::ClientboundUpdateAdvancementsPacket,
|
||||
0x68: clientbound_update_attributes_packet::ClientboundUpdateAttributesPacket,
|
||||
0x69: clientbound_update_mob_effect_packet::ClientboundUpdateMobEffectPacket,
|
||||
0x6a: clientbound_update_recipes_packet::ClientboundUpdateRecipesPacket,
|
||||
0x6b: clientbound_update_tags_packet::ClientboundUpdateTagsPacket,
|
||||
0x0d: clientbound_command_suggestions_packet::ClientboundCommandSuggestionsPacket,
|
||||
0x0e: clientbound_commands_packet::ClientboundCommandsPacket,
|
||||
0x0f: clientbound_container_close_packet::ClientboundContainerClosePacket,
|
||||
0x10: clientbound_container_set_content_packet::ClientboundContainerSetContentPacket,
|
||||
0x11: clientbound_container_set_data_packet::ClientboundContainerSetDataPacket,
|
||||
0x12: clientbound_container_set_slot_packet::ClientboundContainerSetSlotPacket,
|
||||
0x13: clientbound_cooldown_packet::ClientboundCooldownPacket,
|
||||
0x14: clientbound_custom_chat_completions_packet::ClientboundCustomChatCompletionsPacket,
|
||||
0x15: clientbound_custom_payload_packet::ClientboundCustomPayloadPacket,
|
||||
0x16: clientbound_delete_chat_packet::ClientboundDeleteChatPacket,
|
||||
0x17: clientbound_disconnect_packet::ClientboundDisconnectPacket,
|
||||
0x18: clientbound_disguised_chat_packet::ClientboundDisguisedChatPacket,
|
||||
0x19: clientbound_entity_event_packet::ClientboundEntityEventPacket,
|
||||
0x1a: clientbound_explode_packet::ClientboundExplodePacket,
|
||||
0x1b: clientbound_forget_level_chunk_packet::ClientboundForgetLevelChunkPacket,
|
||||
0x1c: clientbound_game_event_packet::ClientboundGameEventPacket,
|
||||
0x1d: clientbound_horse_screen_open_packet::ClientboundHorseScreenOpenPacket,
|
||||
0x1e: clientbound_initialize_border_packet::ClientboundInitializeBorderPacket,
|
||||
0x1f: clientbound_keep_alive_packet::ClientboundKeepAlivePacket,
|
||||
0x20: clientbound_level_chunk_with_light_packet::ClientboundLevelChunkWithLightPacket,
|
||||
0x21: clientbound_level_event_packet::ClientboundLevelEventPacket,
|
||||
0x22: clientbound_level_particles_packet::ClientboundLevelParticlesPacket,
|
||||
0x23: clientbound_light_update_packet::ClientboundLightUpdatePacket,
|
||||
0x24: clientbound_login_packet::ClientboundLoginPacket,
|
||||
0x25: clientbound_map_item_data_packet::ClientboundMapItemDataPacket,
|
||||
0x26: clientbound_merchant_offers_packet::ClientboundMerchantOffersPacket,
|
||||
0x27: clientbound_move_entity_pos_packet::ClientboundMoveEntityPosPacket,
|
||||
0x28: clientbound_move_entity_pos_rot_packet::ClientboundMoveEntityPosRotPacket,
|
||||
0x29: clientbound_move_entity_rot_packet::ClientboundMoveEntityRotPacket,
|
||||
0x2a: clientbound_move_vehicle_packet::ClientboundMoveVehiclePacket,
|
||||
0x2b: clientbound_open_book_packet::ClientboundOpenBookPacket,
|
||||
0x2c: clientbound_open_screen_packet::ClientboundOpenScreenPacket,
|
||||
0x2d: clientbound_open_sign_editor_packet::ClientboundOpenSignEditorPacket,
|
||||
0x2e: clientbound_ping_packet::ClientboundPingPacket,
|
||||
0x2f: clientbound_place_ghost_recipe_packet::ClientboundPlaceGhostRecipePacket,
|
||||
0x30: clientbound_player_abilities_packet::ClientboundPlayerAbilitiesPacket,
|
||||
0x31: clientbound_player_chat_packet::ClientboundPlayerChatPacket,
|
||||
0x32: clientbound_player_combat_end_packet::ClientboundPlayerCombatEndPacket,
|
||||
0x33: clientbound_player_combat_enter_packet::ClientboundPlayerCombatEnterPacket,
|
||||
0x34: clientbound_player_combat_kill_packet::ClientboundPlayerCombatKillPacket,
|
||||
0x35: clientbound_player_info_remove_packet::ClientboundPlayerInfoRemovePacket,
|
||||
0x36: clientbound_player_info_update_packet::ClientboundPlayerInfoUpdatePacket,
|
||||
0x37: clientbound_player_look_at_packet::ClientboundPlayerLookAtPacket,
|
||||
0x38: clientbound_player_position_packet::ClientboundPlayerPositionPacket,
|
||||
0x39: clientbound_recipe_packet::ClientboundRecipePacket,
|
||||
0x3a: clientbound_remove_entities_packet::ClientboundRemoveEntitiesPacket,
|
||||
0x3b: clientbound_remove_mob_effect_packet::ClientboundRemoveMobEffectPacket,
|
||||
0x3c: clientbound_resource_pack_packet::ClientboundResourcePackPacket,
|
||||
0x3d: clientbound_respawn_packet::ClientboundRespawnPacket,
|
||||
0x3e: clientbound_rotate_head_packet::ClientboundRotateHeadPacket,
|
||||
0x3f: clientbound_section_blocks_update_packet::ClientboundSectionBlocksUpdatePacket,
|
||||
0x40: clientbound_select_advancements_tab_packet::ClientboundSelectAdvancementsTabPacket,
|
||||
0x41: clientbound_server_data_packet::ClientboundServerDataPacket,
|
||||
0x42: clientbound_set_action_bar_text_packet::ClientboundSetActionBarTextPacket,
|
||||
0x43: clientbound_set_border_center_packet::ClientboundSetBorderCenterPacket,
|
||||
0x44: clientbound_set_border_lerp_size_packet::ClientboundSetBorderLerpSizePacket,
|
||||
0x45: clientbound_set_border_size_packet::ClientboundSetBorderSizePacket,
|
||||
0x46: clientbound_set_border_warning_delay_packet::ClientboundSetBorderWarningDelayPacket,
|
||||
0x47: clientbound_set_border_warning_distance_packet::ClientboundSetBorderWarningDistancePacket,
|
||||
0x48: clientbound_set_camera_packet::ClientboundSetCameraPacket,
|
||||
0x49: clientbound_set_carried_item_packet::ClientboundSetCarriedItemPacket,
|
||||
0x4a: clientbound_set_chunk_cache_center_packet::ClientboundSetChunkCacheCenterPacket,
|
||||
0x4b: clientbound_set_chunk_cache_radius_packet::ClientboundSetChunkCacheRadiusPacket,
|
||||
0x4c: clientbound_set_default_spawn_position_packet::ClientboundSetDefaultSpawnPositionPacket,
|
||||
0x4d: clientbound_set_display_objective_packet::ClientboundSetDisplayObjectivePacket,
|
||||
0x4e: clientbound_set_entity_data_packet::ClientboundSetEntityDataPacket,
|
||||
0x4f: clientbound_set_entity_link_packet::ClientboundSetEntityLinkPacket,
|
||||
0x50: clientbound_set_entity_motion_packet::ClientboundSetEntityMotionPacket,
|
||||
0x51: clientbound_set_equipment_packet::ClientboundSetEquipmentPacket,
|
||||
0x52: clientbound_set_experience_packet::ClientboundSetExperiencePacket,
|
||||
0x53: clientbound_set_health_packet::ClientboundSetHealthPacket,
|
||||
0x54: clientbound_set_objective_packet::ClientboundSetObjectivePacket,
|
||||
0x55: clientbound_set_passengers_packet::ClientboundSetPassengersPacket,
|
||||
0x56: clientbound_set_player_team_packet::ClientboundSetPlayerTeamPacket,
|
||||
0x57: clientbound_set_score_packet::ClientboundSetScorePacket,
|
||||
0x58: clientbound_set_simulation_distance_packet::ClientboundSetSimulationDistancePacket,
|
||||
0x59: clientbound_set_subtitle_text_packet::ClientboundSetSubtitleTextPacket,
|
||||
0x5a: clientbound_set_time_packet::ClientboundSetTimePacket,
|
||||
0x5b: clientbound_set_title_text_packet::ClientboundSetTitleTextPacket,
|
||||
0x5c: clientbound_set_titles_animation_packet::ClientboundSetTitlesAnimationPacket,
|
||||
0x5d: clientbound_sound_entity_packet::ClientboundSoundEntityPacket,
|
||||
0x5e: clientbound_sound_packet::ClientboundSoundPacket,
|
||||
0x5f: clientbound_stop_sound_packet::ClientboundStopSoundPacket,
|
||||
0x60: clientbound_system_chat_packet::ClientboundSystemChatPacket,
|
||||
0x61: clientbound_tab_list_packet::ClientboundTabListPacket,
|
||||
0x62: clientbound_tag_query_packet::ClientboundTagQueryPacket,
|
||||
0x63: clientbound_take_item_entity_packet::ClientboundTakeItemEntityPacket,
|
||||
0x64: clientbound_teleport_entity_packet::ClientboundTeleportEntityPacket,
|
||||
0x65: clientbound_update_advancements_packet::ClientboundUpdateAdvancementsPacket,
|
||||
0x66: clientbound_update_attributes_packet::ClientboundUpdateAttributesPacket,
|
||||
0x67: clientbound_update_enabled_features_packet::ClientboundUpdateEnabledFeaturesPacket,
|
||||
0x68: clientbound_update_mob_effect_packet::ClientboundUpdateMobEffectPacket,
|
||||
0x69: clientbound_update_recipes_packet::ClientboundUpdateRecipesPacket,
|
||||
0x6a: clientbound_update_tags_packet::ClientboundUpdateTagsPacket,
|
||||
}
|
||||
);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use crate::packets::game::clientbound_player_chat_packet::LastSeenMessagesUpdate;
|
||||
use azalea_buf::McBuf;
|
||||
use azalea_protocol_macros::ServerboundGamePacket;
|
||||
|
||||
#[derive(Clone, Debug, McBuf, ServerboundGamePacket)]
|
||||
pub struct ServerboundChatAckPacket {
|
||||
pub last_seen_messages: LastSeenMessagesUpdate,
|
||||
#[var]
|
||||
pub offset: u32,
|
||||
}
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
use super::serverbound_chat_packet::LastSeenMessagesUpdate;
|
||||
use azalea_buf::McBuf;
|
||||
use azalea_crypto::MessageSignature;
|
||||
use azalea_protocol_macros::ServerboundGamePacket;
|
||||
|
||||
use super::clientbound_player_chat_packet::LastSeenMessagesUpdate;
|
||||
|
||||
#[derive(Clone, Debug, McBuf, ServerboundGamePacket)]
|
||||
pub struct ServerboundChatCommandPacket {
|
||||
pub command: String,
|
||||
// TODO: Choose a real timestamp type
|
||||
pub timestamp: u64,
|
||||
pub salt: u64,
|
||||
pub argument_signatures: Vec<ArgumentSignature>,
|
||||
pub signed_preview: bool,
|
||||
pub last_seen_messages: LastSeenMessagesUpdate,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::packets::game::clientbound_player_chat_packet::LastSeenMessagesUpdate;
|
||||
use azalea_buf::McBuf;
|
||||
use azalea_core::FixedBitSet;
|
||||
use azalea_crypto::MessageSignature;
|
||||
use azalea_protocol_macros::ServerboundGamePacket;
|
||||
|
||||
|
@ -8,7 +8,13 @@ pub struct ServerboundChatPacket {
|
|||
pub message: String,
|
||||
pub timestamp: u64,
|
||||
pub salt: u64,
|
||||
pub signature: MessageSignature,
|
||||
pub signed_preview: bool,
|
||||
pub signature: Option<MessageSignature>,
|
||||
pub last_seen_messages: LastSeenMessagesUpdate,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, McBuf, Default)]
|
||||
pub struct LastSeenMessagesUpdate {
|
||||
#[var]
|
||||
pub offset: u32,
|
||||
pub acknowledged: FixedBitSet<20>,
|
||||
}
|
||||
|
|
|
@ -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>,
|
||||
}
|
|
@ -2,20 +2,12 @@ use azalea_buf::McBuf;
|
|||
use azalea_protocol_macros::ServerboundLoginPacket;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, ServerboundLoginPacket, McBuf, PartialEq, Eq)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, McBuf, ServerboundLoginPacket)]
|
||||
pub struct ServerboundHelloPacket {
|
||||
pub username: String,
|
||||
pub public_key: Option<ProfilePublicKeyData>,
|
||||
pub name: String,
|
||||
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)]
|
||||
mod tests {
|
||||
use std::io::Cursor;
|
||||
|
@ -26,9 +18,8 @@ mod tests {
|
|||
#[test]
|
||||
fn test_read_write() {
|
||||
let packet = ServerboundHelloPacket {
|
||||
username: "test".to_string(),
|
||||
public_key: None,
|
||||
profile_id: Some(Uuid::from_u128(0)),
|
||||
name: "test".to_string(),
|
||||
profile_id: Some(Uuid::nil()),
|
||||
};
|
||||
let mut buf: Vec<u8> = Vec::new();
|
||||
packet.write_into(&mut buf).unwrap();
|
||||
|
|
|
@ -1,47 +1,8 @@
|
|||
use azalea_buf::{BufReadError, McBuf};
|
||||
use azalea_crypto::SaltSignaturePair;
|
||||
use azalea_buf::McBuf;
|
||||
use azalea_protocol_macros::ServerboundLoginPacket;
|
||||
use std::io::{Cursor, Write};
|
||||
|
||||
use azalea_buf::{McBufReadable, McBufWritable};
|
||||
|
||||
#[derive(Clone, Debug, McBuf, ServerboundLoginPacket)]
|
||||
pub struct ServerboundKeyPacket {
|
||||
pub key_bytes: Vec<u8>,
|
||||
pub nonce_or_salt_signature: NonceOrSaltSignature,
|
||||
}
|
||||
|
||||
#[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(())
|
||||
}
|
||||
pub encrypted_challenge: Vec<u8>,
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
pub const PROTOCOL_VERSION: u32 = 760;
|
||||
pub const PROTOCOL_VERSION: u32 = 761;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum ConnectionProtocol {
|
||||
|
@ -39,7 +39,7 @@ where
|
|||
fn id(&self) -> u32;
|
||||
|
||||
/// 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>;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use bytes::BytesMut;
|
|||
use flate2::read::ZlibDecoder;
|
||||
use futures::StreamExt;
|
||||
use log::{log_enabled, trace};
|
||||
use std::backtrace::Backtrace;
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
io::{Cursor, Read},
|
||||
|
@ -19,10 +20,11 @@ use tokio_util::codec::{BytesCodec, FramedRead};
|
|||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum ReadPacketError {
|
||||
#[error("Error reading packet {packet_name} ({packet_id}): {source}")]
|
||||
#[error("Error reading packet {packet_name} (id {packet_id}): {source}")]
|
||||
Parse {
|
||||
packet_id: u32,
|
||||
packet_name: String,
|
||||
backtrace: Box<Backtrace>,
|
||||
source: BufReadError,
|
||||
},
|
||||
#[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) {
|
||||
Ok(length) => length as usize,
|
||||
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()),
|
||||
},
|
||||
};
|
||||
|
@ -126,7 +128,7 @@ fn frame_splitter(buffer: &mut BytesMut) -> Result<Option<Vec<u8>>, FrameSplitte
|
|||
|
||||
fn packet_decoder<P: ProtocolPacket + Debug>(
|
||||
stream: &mut Cursor<&[u8]>,
|
||||
) -> Result<P, ReadPacketError> {
|
||||
) -> Result<P, Box<ReadPacketError>> {
|
||||
// Packet ID
|
||||
let packet_id =
|
||||
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,
|
||||
compression_threshold: Option<u32>,
|
||||
cipher: &mut Option<Aes128CfbDec>,
|
||||
) -> Result<P, ReadPacketError>
|
||||
) -> Result<P, Box<ReadPacketError>>
|
||||
where
|
||||
R: AsyncRead + std::marker::Unpin + std::marker::Send + std::marker::Sync,
|
||||
{
|
||||
let mut framed = FramedRead::new(stream, BytesCodec::new());
|
||||
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!!
|
||||
break buf;
|
||||
} else {
|
||||
|
@ -222,7 +224,7 @@ where
|
|||
|
||||
// if we were given a cipher, decrypt the packet
|
||||
if let Some(message) = framed.next().await {
|
||||
let mut bytes = message?;
|
||||
let mut bytes = message.map_err(ReadPacketError::from)?;
|
||||
|
||||
if let Some(cipher) = cipher {
|
||||
azalea_crypto::decrypt_packet(cipher, &mut bytes);
|
||||
|
@ -230,12 +232,13 @@ where
|
|||
|
||||
buffer.extend_from_slice(&bytes);
|
||||
} else {
|
||||
return Err(ReadPacketError::ConnectionClosed);
|
||||
return Err(Box::new(ReadPacketError::ConnectionClosed));
|
||||
};
|
||||
};
|
||||
|
||||
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) {
|
||||
|
@ -255,38 +258,38 @@ where
|
|||
Ok(packet)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::packets::game::{clientbound_player_chat_packet::ChatType, ClientboundGamePacket};
|
||||
use std::io::Cursor;
|
||||
// #[cfg(test)]
|
||||
// mod tests {
|
||||
// use super::*;
|
||||
// use crate::packets::game::{clientbound_player_chat_packet::ChatType, ClientboundGamePacket};
|
||||
// use std::io::Cursor;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_read_packet() {
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
120, 116, 34, 58, 34, 34, 125, 0,
|
||||
]);
|
||||
let packet = packet_decoder::<ClientboundGamePacket>(&mut buf).unwrap();
|
||||
match &packet {
|
||||
ClientboundGamePacket::PlayerChat(m) => {
|
||||
assert_eq!(
|
||||
m.chat_type.chat_type,
|
||||
ChatType::Chat,
|
||||
"Enums should default if they're invalid"
|
||||
);
|
||||
}
|
||||
_ => panic!("Wrong packet type"),
|
||||
}
|
||||
}
|
||||
}
|
||||
// #[tokio::test]
|
||||
// async fn test_read_packet() {
|
||||
// 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,
|
||||
// 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,
|
||||
// 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,
|
||||
// 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,
|
||||
// 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,
|
||||
// 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,
|
||||
// 120, 116, 34, 58, 34, 34, 125, 0,
|
||||
// ]);
|
||||
// let packet = packet_decoder::<ClientboundGamePacket>(&mut buf).unwrap();
|
||||
// match &packet {
|
||||
// ClientboundGamePacket::PlayerChat(m) => {
|
||||
// assert_eq!(
|
||||
// m.chat_type.chat_type,
|
||||
// ChatType::Chat,
|
||||
// "Enums should default if they're invalid"
|
||||
// );
|
||||
// }
|
||||
// _ => panic!("Wrong packet type"),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -4,6 +4,7 @@ use crate::{packets::ProtocolPacket, read::MAXIMUM_UNCOMPRESSED_LENGTH};
|
|||
use async_compression::tokio::bufread::ZlibEncoder;
|
||||
use azalea_buf::McBufVarWritable;
|
||||
use azalea_crypto::Aes128CfbEnc;
|
||||
use log::trace;
|
||||
use std::fmt::Debug;
|
||||
use thiserror::Error;
|
||||
use tokio::io::{AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
||||
|
@ -81,6 +82,7 @@ where
|
|||
P: ProtocolPacket + Debug,
|
||||
W: AsyncWrite + Unpin + Send,
|
||||
{
|
||||
trace!("Sending packet: {:?}", packet);
|
||||
let mut buf = packet_encoder(packet).unwrap();
|
||||
if let Some(threshold) = compression_threshold {
|
||||
buf = compression_encoder(&buf, threshold).await.unwrap();
|
||||
|
|
|
@ -95,6 +95,18 @@ pub fn registry(input: TokenStream) -> TokenStream {
|
|||
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}.");
|
||||
|
@ -105,8 +117,8 @@ pub fn registry(input: TokenStream) -> TokenStream {
|
|||
|
||||
#[doc = #doc_0]
|
||||
fn try_from(id: u32) -> Result<Self, Self::Error> {
|
||||
if Self::is_valid_id(id) {
|
||||
Ok(unsafe { Self::from_u32_unchecked(id) })
|
||||
if let Some(value) = Self::from_u32(id) {
|
||||
Ok(value)
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
|
|
|
@ -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 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, {
|
||||
Core => "minecraft:core",
|
||||
|
@ -110,6 +147,8 @@ registry!(Block, {
|
|||
AcaciaPlanks => "minecraft:acacia_planks",
|
||||
DarkOakPlanks => "minecraft:dark_oak_planks",
|
||||
MangrovePlanks => "minecraft:mangrove_planks",
|
||||
BambooPlanks => "minecraft:bamboo_planks",
|
||||
BambooMosaic => "minecraft:bamboo_mosaic",
|
||||
OakSapling => "minecraft:oak_sapling",
|
||||
SpruceSapling => "minecraft:spruce_sapling",
|
||||
BirchSapling => "minecraft:birch_sapling",
|
||||
|
@ -139,6 +178,7 @@ registry!(Block, {
|
|||
MangroveLog => "minecraft:mangrove_log",
|
||||
MangroveRoots => "minecraft:mangrove_roots",
|
||||
MuddyMangroveRoots => "minecraft:muddy_mangrove_roots",
|
||||
BambooBlock => "minecraft:bamboo_block",
|
||||
StrippedSpruceLog => "minecraft:stripped_spruce_log",
|
||||
StrippedBirchLog => "minecraft:stripped_birch_log",
|
||||
StrippedJungleLog => "minecraft:stripped_jungle_log",
|
||||
|
@ -146,6 +186,7 @@ registry!(Block, {
|
|||
StrippedDarkOakLog => "minecraft:stripped_dark_oak_log",
|
||||
StrippedOakLog => "minecraft:stripped_oak_log",
|
||||
StrippedMangroveLog => "minecraft:stripped_mangrove_log",
|
||||
StrippedBambooBlock => "minecraft:stripped_bamboo_block",
|
||||
OakWood => "minecraft:oak_wood",
|
||||
SpruceWood => "minecraft:spruce_wood",
|
||||
BirchWood => "minecraft:birch_wood",
|
||||
|
@ -244,6 +285,7 @@ registry!(Block, {
|
|||
Bricks => "minecraft:bricks",
|
||||
Tnt => "minecraft:tnt",
|
||||
Bookshelf => "minecraft:bookshelf",
|
||||
ChiseledBookshelf => "minecraft:chiseled_bookshelf",
|
||||
MossyCobblestone => "minecraft:mossy_cobblestone",
|
||||
Obsidian => "minecraft:obsidian",
|
||||
Torch => "minecraft:torch",
|
||||
|
@ -268,6 +310,7 @@ registry!(Block, {
|
|||
JungleSign => "minecraft:jungle_sign",
|
||||
DarkOakSign => "minecraft:dark_oak_sign",
|
||||
MangroveSign => "minecraft:mangrove_sign",
|
||||
BambooSign => "minecraft:bamboo_sign",
|
||||
OakDoor => "minecraft:oak_door",
|
||||
Ladder => "minecraft:ladder",
|
||||
Rail => "minecraft:rail",
|
||||
|
@ -279,6 +322,27 @@ registry!(Block, {
|
|||
JungleWallSign => "minecraft:jungle_wall_sign",
|
||||
DarkOakWallSign => "minecraft:dark_oak_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",
|
||||
StonePressurePlate => "minecraft:stone_pressure_plate",
|
||||
IronDoor => "minecraft:iron_door",
|
||||
|
@ -289,6 +353,7 @@ registry!(Block, {
|
|||
AcaciaPressurePlate => "minecraft:acacia_pressure_plate",
|
||||
DarkOakPressurePlate => "minecraft:dark_oak_pressure_plate",
|
||||
MangrovePressurePlate => "minecraft:mangrove_pressure_plate",
|
||||
BambooPressurePlate => "minecraft:bamboo_pressure_plate",
|
||||
RedstoneOre => "minecraft:redstone_ore",
|
||||
DeepslateRedstoneOre => "minecraft:deepslate_redstone_ore",
|
||||
RedstoneTorch => "minecraft:redstone_torch",
|
||||
|
@ -339,6 +404,7 @@ registry!(Block, {
|
|||
AcaciaTrapdoor => "minecraft:acacia_trapdoor",
|
||||
DarkOakTrapdoor => "minecraft:dark_oak_trapdoor",
|
||||
MangroveTrapdoor => "minecraft:mangrove_trapdoor",
|
||||
BambooTrapdoor => "minecraft:bamboo_trapdoor",
|
||||
StoneBricks => "minecraft:stone_bricks",
|
||||
MossyStoneBricks => "minecraft:mossy_stone_bricks",
|
||||
CrackedStoneBricks => "minecraft:cracked_stone_bricks",
|
||||
|
@ -435,6 +501,7 @@ registry!(Block, {
|
|||
AcaciaButton => "minecraft:acacia_button",
|
||||
DarkOakButton => "minecraft:dark_oak_button",
|
||||
MangroveButton => "minecraft:mangrove_button",
|
||||
BambooButton => "minecraft:bamboo_button",
|
||||
SkeletonSkull => "minecraft:skeleton_skull",
|
||||
SkeletonWallSkull => "minecraft:skeleton_wall_skull",
|
||||
WitherSkeletonSkull => "minecraft:wither_skeleton_skull",
|
||||
|
@ -447,6 +514,8 @@ registry!(Block, {
|
|||
CreeperWallHead => "minecraft:creeper_wall_head",
|
||||
DragonHead => "minecraft:dragon_head",
|
||||
DragonWallHead => "minecraft:dragon_wall_head",
|
||||
PiglinHead => "minecraft:piglin_head",
|
||||
PiglinWallHead => "minecraft:piglin_wall_head",
|
||||
Anvil => "minecraft:anvil",
|
||||
ChippedAnvil => "minecraft:chipped_anvil",
|
||||
DamagedAnvil => "minecraft:damaged_anvil",
|
||||
|
@ -499,6 +568,8 @@ registry!(Block, {
|
|||
AcaciaStairs => "minecraft:acacia_stairs",
|
||||
DarkOakStairs => "minecraft:dark_oak_stairs",
|
||||
MangroveStairs => "minecraft:mangrove_stairs",
|
||||
BambooStairs => "minecraft:bamboo_stairs",
|
||||
BambooMosaicStairs => "minecraft:bamboo_mosaic_stairs",
|
||||
SlimeBlock => "minecraft:slime_block",
|
||||
Barrier => "minecraft:barrier",
|
||||
Light => "minecraft:light",
|
||||
|
@ -582,6 +653,8 @@ registry!(Block, {
|
|||
AcaciaSlab => "minecraft:acacia_slab",
|
||||
DarkOakSlab => "minecraft:dark_oak_slab",
|
||||
MangroveSlab => "minecraft:mangrove_slab",
|
||||
BambooSlab => "minecraft:bamboo_slab",
|
||||
BambooMosaicSlab => "minecraft:bamboo_mosaic_slab",
|
||||
StoneSlab => "minecraft:stone_slab",
|
||||
SmoothStoneSlab => "minecraft:smooth_stone_slab",
|
||||
SandstoneSlab => "minecraft:sandstone_slab",
|
||||
|
@ -606,18 +679,21 @@ registry!(Block, {
|
|||
AcaciaFenceGate => "minecraft:acacia_fence_gate",
|
||||
DarkOakFenceGate => "minecraft:dark_oak_fence_gate",
|
||||
MangroveFenceGate => "minecraft:mangrove_fence_gate",
|
||||
BambooFenceGate => "minecraft:bamboo_fence_gate",
|
||||
SpruceFence => "minecraft:spruce_fence",
|
||||
BirchFence => "minecraft:birch_fence",
|
||||
JungleFence => "minecraft:jungle_fence",
|
||||
AcaciaFence => "minecraft:acacia_fence",
|
||||
DarkOakFence => "minecraft:dark_oak_fence",
|
||||
MangroveFence => "minecraft:mangrove_fence",
|
||||
BambooFence => "minecraft:bamboo_fence",
|
||||
SpruceDoor => "minecraft:spruce_door",
|
||||
BirchDoor => "minecraft:birch_door",
|
||||
JungleDoor => "minecraft:jungle_door",
|
||||
AcaciaDoor => "minecraft:acacia_door",
|
||||
DarkOakDoor => "minecraft:dark_oak_door",
|
||||
MangroveDoor => "minecraft:mangrove_door",
|
||||
BambooDoor => "minecraft:bamboo_door",
|
||||
EndRod => "minecraft:end_rod",
|
||||
ChorusPlant => "minecraft:chorus_plant",
|
||||
ChorusFlower => "minecraft:chorus_flower",
|
||||
|
@ -1034,6 +1110,7 @@ registry!(BlockEntityType, {
|
|||
Dispenser => "minecraft:dispenser",
|
||||
Dropper => "minecraft:dropper",
|
||||
Sign => "minecraft:sign",
|
||||
HangingSign => "minecraft:hanging_sign",
|
||||
MobSpawner => "minecraft:mob_spawner",
|
||||
Piston => "minecraft:piston",
|
||||
BrewingStand => "minecraft:brewing_stand",
|
||||
|
@ -1062,6 +1139,7 @@ registry!(BlockEntityType, {
|
|||
SculkSensor => "minecraft:sculk_sensor",
|
||||
SculkCatalyst => "minecraft:sculk_catalyst",
|
||||
SculkShrieker => "minecraft:sculk_shrieker",
|
||||
ChiseledBookshelf => "minecraft:chiseled_bookshelf",
|
||||
});
|
||||
|
||||
registry!(BlockPredicateType, {
|
||||
|
@ -1144,17 +1222,17 @@ registry!(CommandArgumentType, {
|
|||
Team => "minecraft:team",
|
||||
ItemSlot => "minecraft:item_slot",
|
||||
ResourceLocation => "minecraft:resource_location",
|
||||
MobEffect => "minecraft:mob_effect",
|
||||
Function => "minecraft:function",
|
||||
EntityAnchor => "minecraft:entity_anchor",
|
||||
IntRange => "minecraft:int_range",
|
||||
FloatRange => "minecraft:float_range",
|
||||
ItemEnchantment => "minecraft:item_enchantment",
|
||||
EntitySummon => "minecraft:entity_summon",
|
||||
Dimension => "minecraft:dimension",
|
||||
Gamemode => "minecraft:gamemode",
|
||||
Time => "minecraft:time",
|
||||
ResourceOrTag => "minecraft:resource_or_tag",
|
||||
ResourceOrTagKey => "minecraft:resource_or_tag_key",
|
||||
Resource => "minecraft:resource",
|
||||
ResourceKey => "minecraft:resource_key",
|
||||
TemplateMirror => "minecraft:template_mirror",
|
||||
TemplateRotation => "minecraft:template_rotation",
|
||||
Uuid => "minecraft:uuid",
|
||||
|
@ -1292,6 +1370,7 @@ registry!(EntityType, {
|
|||
Boat => "minecraft:boat",
|
||||
ChestBoat => "minecraft:chest_boat",
|
||||
Cat => "minecraft:cat",
|
||||
Camel => "minecraft:camel",
|
||||
CaveSpider => "minecraft:cave_spider",
|
||||
Chicken => "minecraft:chicken",
|
||||
Cod => "minecraft:cod",
|
||||
|
@ -1531,8 +1610,10 @@ registry!(Item, {
|
|||
AcaciaPlanks => "minecraft:acacia_planks",
|
||||
DarkOakPlanks => "minecraft:dark_oak_planks",
|
||||
MangrovePlanks => "minecraft:mangrove_planks",
|
||||
BambooPlanks => "minecraft:bamboo_planks",
|
||||
CrimsonPlanks => "minecraft:crimson_planks",
|
||||
WarpedPlanks => "minecraft:warped_planks",
|
||||
BambooMosaic => "minecraft:bamboo_mosaic",
|
||||
OakSapling => "minecraft:oak_sapling",
|
||||
SpruceSapling => "minecraft:spruce_sapling",
|
||||
BirchSapling => "minecraft:birch_sapling",
|
||||
|
@ -1616,6 +1697,7 @@ registry!(Item, {
|
|||
MuddyMangroveRoots => "minecraft:muddy_mangrove_roots",
|
||||
CrimsonStem => "minecraft:crimson_stem",
|
||||
WarpedStem => "minecraft:warped_stem",
|
||||
BambooBlock => "minecraft:bamboo_block",
|
||||
StrippedOakLog => "minecraft:stripped_oak_log",
|
||||
StrippedSpruceLog => "minecraft:stripped_spruce_log",
|
||||
StrippedBirchLog => "minecraft:stripped_birch_log",
|
||||
|
@ -1634,6 +1716,7 @@ registry!(Item, {
|
|||
StrippedMangroveWood => "minecraft:stripped_mangrove_wood",
|
||||
StrippedCrimsonHyphae => "minecraft:stripped_crimson_hyphae",
|
||||
StrippedWarpedHyphae => "minecraft:stripped_warped_hyphae",
|
||||
StrippedBambooBlock => "minecraft:stripped_bamboo_block",
|
||||
OakWood => "minecraft:oak_wood",
|
||||
SpruceWood => "minecraft:spruce_wood",
|
||||
BirchWood => "minecraft:birch_wood",
|
||||
|
@ -1722,6 +1805,8 @@ registry!(Item, {
|
|||
AcaciaSlab => "minecraft:acacia_slab",
|
||||
DarkOakSlab => "minecraft:dark_oak_slab",
|
||||
MangroveSlab => "minecraft:mangrove_slab",
|
||||
BambooSlab => "minecraft:bamboo_slab",
|
||||
BambooMosaicSlab => "minecraft:bamboo_mosaic_slab",
|
||||
CrimsonSlab => "minecraft:crimson_slab",
|
||||
WarpedSlab => "minecraft:warped_slab",
|
||||
StoneSlab => "minecraft:stone_slab",
|
||||
|
@ -1747,6 +1832,7 @@ registry!(Item, {
|
|||
SmoothStone => "minecraft:smooth_stone",
|
||||
Bricks => "minecraft:bricks",
|
||||
Bookshelf => "minecraft:bookshelf",
|
||||
ChiseledBookshelf => "minecraft:chiseled_bookshelf",
|
||||
MossyCobblestone => "minecraft:mossy_cobblestone",
|
||||
Obsidian => "minecraft:obsidian",
|
||||
Torch => "minecraft:torch",
|
||||
|
@ -1776,6 +1862,7 @@ registry!(Item, {
|
|||
AcaciaFence => "minecraft:acacia_fence",
|
||||
DarkOakFence => "minecraft:dark_oak_fence",
|
||||
MangroveFence => "minecraft:mangrove_fence",
|
||||
BambooFence => "minecraft:bamboo_fence",
|
||||
CrimsonFence => "minecraft:crimson_fence",
|
||||
WarpedFence => "minecraft:warped_fence",
|
||||
Pumpkin => "minecraft:pumpkin",
|
||||
|
@ -1846,6 +1933,8 @@ registry!(Item, {
|
|||
AcaciaStairs => "minecraft:acacia_stairs",
|
||||
DarkOakStairs => "minecraft:dark_oak_stairs",
|
||||
MangroveStairs => "minecraft:mangrove_stairs",
|
||||
BambooStairs => "minecraft:bamboo_stairs",
|
||||
BambooMosaicStairs => "minecraft:bamboo_mosaic_stairs",
|
||||
CrimsonStairs => "minecraft:crimson_stairs",
|
||||
WarpedStairs => "minecraft:warped_stairs",
|
||||
CommandBlock => "minecraft:command_block",
|
||||
|
@ -2142,6 +2231,7 @@ registry!(Item, {
|
|||
AcaciaButton => "minecraft:acacia_button",
|
||||
DarkOakButton => "minecraft:dark_oak_button",
|
||||
MangroveButton => "minecraft:mangrove_button",
|
||||
BambooButton => "minecraft:bamboo_button",
|
||||
CrimsonButton => "minecraft:crimson_button",
|
||||
WarpedButton => "minecraft:warped_button",
|
||||
StonePressurePlate => "minecraft:stone_pressure_plate",
|
||||
|
@ -2155,6 +2245,7 @@ registry!(Item, {
|
|||
AcaciaPressurePlate => "minecraft:acacia_pressure_plate",
|
||||
DarkOakPressurePlate => "minecraft:dark_oak_pressure_plate",
|
||||
MangrovePressurePlate => "minecraft:mangrove_pressure_plate",
|
||||
BambooPressurePlate => "minecraft:bamboo_pressure_plate",
|
||||
CrimsonPressurePlate => "minecraft:crimson_pressure_plate",
|
||||
WarpedPressurePlate => "minecraft:warped_pressure_plate",
|
||||
IronDoor => "minecraft:iron_door",
|
||||
|
@ -2165,6 +2256,7 @@ registry!(Item, {
|
|||
AcaciaDoor => "minecraft:acacia_door",
|
||||
DarkOakDoor => "minecraft:dark_oak_door",
|
||||
MangroveDoor => "minecraft:mangrove_door",
|
||||
BambooDoor => "minecraft:bamboo_door",
|
||||
CrimsonDoor => "minecraft:crimson_door",
|
||||
WarpedDoor => "minecraft:warped_door",
|
||||
IronTrapdoor => "minecraft:iron_trapdoor",
|
||||
|
@ -2175,6 +2267,7 @@ registry!(Item, {
|
|||
AcaciaTrapdoor => "minecraft:acacia_trapdoor",
|
||||
DarkOakTrapdoor => "minecraft:dark_oak_trapdoor",
|
||||
MangroveTrapdoor => "minecraft:mangrove_trapdoor",
|
||||
BambooTrapdoor => "minecraft:bamboo_trapdoor",
|
||||
CrimsonTrapdoor => "minecraft:crimson_trapdoor",
|
||||
WarpedTrapdoor => "minecraft:warped_trapdoor",
|
||||
OakFenceGate => "minecraft:oak_fence_gate",
|
||||
|
@ -2184,6 +2277,7 @@ registry!(Item, {
|
|||
AcaciaFenceGate => "minecraft:acacia_fence_gate",
|
||||
DarkOakFenceGate => "minecraft:dark_oak_fence_gate",
|
||||
MangroveFenceGate => "minecraft:mangrove_fence_gate",
|
||||
BambooFenceGate => "minecraft:bamboo_fence_gate",
|
||||
CrimsonFenceGate => "minecraft:crimson_fence_gate",
|
||||
WarpedFenceGate => "minecraft:warped_fence_gate",
|
||||
PoweredRail => "minecraft:powered_rail",
|
||||
|
@ -2213,6 +2307,8 @@ registry!(Item, {
|
|||
DarkOakChestBoat => "minecraft:dark_oak_chest_boat",
|
||||
MangroveBoat => "minecraft:mangrove_boat",
|
||||
MangroveChestBoat => "minecraft:mangrove_chest_boat",
|
||||
BambooRaft => "minecraft:bamboo_raft",
|
||||
BambooChestRaft => "minecraft:bamboo_chest_raft",
|
||||
StructureBlock => "minecraft:structure_block",
|
||||
Jigsaw => "minecraft:jigsaw",
|
||||
TurtleHelmet => "minecraft:turtle_helmet",
|
||||
|
@ -2312,8 +2408,19 @@ registry!(Item, {
|
|||
AcaciaSign => "minecraft:acacia_sign",
|
||||
DarkOakSign => "minecraft:dark_oak_sign",
|
||||
MangroveSign => "minecraft:mangrove_sign",
|
||||
BambooSign => "minecraft:bamboo_sign",
|
||||
CrimsonSign => "minecraft:crimson_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",
|
||||
WaterBucket => "minecraft:water_bucket",
|
||||
LavaBucket => "minecraft:lava_bucket",
|
||||
|
@ -2419,6 +2526,7 @@ registry!(Item, {
|
|||
BeeSpawnEgg => "minecraft:bee_spawn_egg",
|
||||
BlazeSpawnEgg => "minecraft:blaze_spawn_egg",
|
||||
CatSpawnEgg => "minecraft:cat_spawn_egg",
|
||||
CamelSpawnEgg => "minecraft:camel_spawn_egg",
|
||||
CaveSpiderSpawnEgg => "minecraft:cave_spider_spawn_egg",
|
||||
ChickenSpawnEgg => "minecraft:chicken_spawn_egg",
|
||||
CodSpawnEgg => "minecraft:cod_spawn_egg",
|
||||
|
@ -2428,6 +2536,7 @@ registry!(Item, {
|
|||
DonkeySpawnEgg => "minecraft:donkey_spawn_egg",
|
||||
DrownedSpawnEgg => "minecraft:drowned_spawn_egg",
|
||||
ElderGuardianSpawnEgg => "minecraft:elder_guardian_spawn_egg",
|
||||
EnderDragonSpawnEgg => "minecraft:ender_dragon_spawn_egg",
|
||||
EndermanSpawnEgg => "minecraft:enderman_spawn_egg",
|
||||
EndermiteSpawnEgg => "minecraft:endermite_spawn_egg",
|
||||
EvokerSpawnEgg => "minecraft:evoker_spawn_egg",
|
||||
|
@ -2440,6 +2549,7 @@ registry!(Item, {
|
|||
HoglinSpawnEgg => "minecraft:hoglin_spawn_egg",
|
||||
HorseSpawnEgg => "minecraft:horse_spawn_egg",
|
||||
HuskSpawnEgg => "minecraft:husk_spawn_egg",
|
||||
IronGolemSpawnEgg => "minecraft:iron_golem_spawn_egg",
|
||||
LlamaSpawnEgg => "minecraft:llama_spawn_egg",
|
||||
MagmaCubeSpawnEgg => "minecraft:magma_cube_spawn_egg",
|
||||
MooshroomSpawnEgg => "minecraft:mooshroom_spawn_egg",
|
||||
|
@ -2463,6 +2573,7 @@ registry!(Item, {
|
|||
SkeletonSpawnEgg => "minecraft:skeleton_spawn_egg",
|
||||
SkeletonHorseSpawnEgg => "minecraft:skeleton_horse_spawn_egg",
|
||||
SlimeSpawnEgg => "minecraft:slime_spawn_egg",
|
||||
SnowGolemSpawnEgg => "minecraft:snow_golem_spawn_egg",
|
||||
SpiderSpawnEgg => "minecraft:spider_spawn_egg",
|
||||
SquidSpawnEgg => "minecraft:squid_spawn_egg",
|
||||
StraySpawnEgg => "minecraft:stray_spawn_egg",
|
||||
|
@ -2477,6 +2588,7 @@ registry!(Item, {
|
|||
WanderingTraderSpawnEgg => "minecraft:wandering_trader_spawn_egg",
|
||||
WardenSpawnEgg => "minecraft:warden_spawn_egg",
|
||||
WitchSpawnEgg => "minecraft:witch_spawn_egg",
|
||||
WitherSpawnEgg => "minecraft:wither_spawn_egg",
|
||||
WitherSkeletonSpawnEgg => "minecraft:wither_skeleton_spawn_egg",
|
||||
WolfSpawnEgg => "minecraft:wolf_spawn_egg",
|
||||
ZoglinSpawnEgg => "minecraft:zoglin_spawn_egg",
|
||||
|
@ -2503,6 +2615,7 @@ registry!(Item, {
|
|||
ZombieHead => "minecraft:zombie_head",
|
||||
CreeperHead => "minecraft:creeper_head",
|
||||
DragonHead => "minecraft:dragon_head",
|
||||
PiglinHead => "minecraft:piglin_head",
|
||||
NetherStar => "minecraft:nether_star",
|
||||
PumpkinPie => "minecraft:pumpkin_pie",
|
||||
FireworkRocket => "minecraft:firework_rocket",
|
||||
|
@ -2773,6 +2886,7 @@ registry!(MemoryModuleType, {
|
|||
PlayDeadTicks => "minecraft:play_dead_ticks",
|
||||
TemptingPlayer => "minecraft:tempting_player",
|
||||
TemptationCooldownTicks => "minecraft:temptation_cooldown_ticks",
|
||||
GazeCooldownTicks => "minecraft:gaze_cooldown_ticks",
|
||||
IsTempted => "minecraft:is_tempted",
|
||||
LongJumpCoolingDown => "minecraft:long_jump_cooling_down",
|
||||
LongJumpMidJump => "minecraft:long_jump_mid_jump",
|
||||
|
@ -3167,6 +3281,7 @@ registry!(SensorType, {
|
|||
AxolotlTemptations => "minecraft:axolotl_temptations",
|
||||
GoatTemptations => "minecraft:goat_temptations",
|
||||
FrogTemptations => "minecraft:frog_temptations",
|
||||
CamelTemptations => "minecraft:camel_temptations",
|
||||
FrogAttackables => "minecraft:frog_attackables",
|
||||
IsInWater => "minecraft:is_in_water",
|
||||
WardenEntitySensor => "minecraft:warden_entity_sensor",
|
||||
|
@ -3270,6 +3385,21 @@ registry!(SoundEvent, {
|
|||
BlockBambooSaplingBreak => "minecraft:block.bamboo_sapling.break",
|
||||
BlockBambooSaplingHit => "minecraft:block.bamboo_sapling.hit",
|
||||
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",
|
||||
BlockBarrelOpen => "minecraft:block.barrel.open",
|
||||
BlockBasaltBreak => "minecraft:block.basalt.break",
|
||||
|
@ -3350,6 +3480,17 @@ registry!(SoundEvent, {
|
|||
BlockCalcitePlace => "minecraft:block.calcite.place",
|
||||
BlockCalciteHit => "minecraft:block.calcite.hit",
|
||||
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",
|
||||
BlockCandleAmbient => "minecraft:block.candle.ambient",
|
||||
BlockCandleBreak => "minecraft:block.candle.break",
|
||||
|
@ -3386,6 +3527,15 @@ registry!(SoundEvent, {
|
|||
EntityChickenEgg => "minecraft:entity.chicken.egg",
|
||||
EntityChickenHurt => "minecraft:entity.chicken.hurt",
|
||||
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",
|
||||
BlockChorusFlowerGrow => "minecraft:block.chorus_flower.grow",
|
||||
ItemChorusFruitTeleport => "minecraft:item.chorus_fruit.teleport",
|
||||
|
@ -3680,6 +3830,21 @@ registry!(SoundEvent, {
|
|||
BlockHangingRootsHit => "minecraft:block.hanging_roots.hit",
|
||||
BlockHangingRootsPlace => "minecraft:block.hanging_roots.place",
|
||||
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",
|
||||
EntityHoglinAmbient => "minecraft:entity.hoglin.ambient",
|
||||
EntityHoglinAngry => "minecraft:entity.hoglin.angry",
|
||||
|
@ -3896,6 +4061,21 @@ registry!(SoundEvent, {
|
|||
BlockNetherBricksFall => "minecraft:block.nether_bricks.fall",
|
||||
BlockNetherWartBreak => "minecraft:block.nether_wart.break",
|
||||
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",
|
||||
BlockPackedMudFall => "minecraft:block.packed_mud.fall",
|
||||
BlockPackedMudHit => "minecraft:block.packed_mud.hit",
|
||||
|
@ -3957,6 +4137,12 @@ registry!(SoundEvent, {
|
|||
BlockNoteBlockDidgeridoo => "minecraft:block.note_block.didgeridoo",
|
||||
BlockNoteBlockBit => "minecraft:block.note_block.bit",
|
||||
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",
|
||||
EntityOcelotAmbient => "minecraft:entity.ocelot.ambient",
|
||||
EntityOcelotDeath => "minecraft:entity.ocelot.death",
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use azalea_block::BlockState;
|
||||
use azalea_buf::{BufReadError, McBufVarReadable};
|
||||
use azalea_buf::{BufReadError, McBufVarReadable, McBufVarWritable};
|
||||
use azalea_buf::{McBuf, McBufReadable, McBufWritable};
|
||||
use azalea_chat::Component;
|
||||
use azalea_core::{BlockPos, Direction, GlobalPos, Particle, Slot};
|
||||
use enum_as_inner::EnumAsInner;
|
||||
use log::warn;
|
||||
use nohash_hasher::IntSet;
|
||||
use std::io::{Cursor, Write};
|
||||
use uuid::Uuid;
|
||||
|
@ -24,12 +23,12 @@ impl McBufReadable for EntityMetadataItems {
|
|||
fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
||||
let mut metadata = Vec::new();
|
||||
loop {
|
||||
let index = u8::read_from(buf)?;
|
||||
if index == 0xff {
|
||||
let id = u8::read_from(buf)?;
|
||||
if id == 0xff {
|
||||
break;
|
||||
}
|
||||
let value = EntityDataValue::read_from(buf)?;
|
||||
metadata.push(EntityDataItem { index, value });
|
||||
metadata.push(EntityDataItem { index: id, value });
|
||||
}
|
||||
Ok(EntityMetadataItems(metadata))
|
||||
}
|
||||
|
@ -46,10 +45,11 @@ impl McBufWritable for EntityMetadataItems {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, EnumAsInner)]
|
||||
#[derive(Clone, Debug, EnumAsInner, McBuf)]
|
||||
pub enum EntityDataValue {
|
||||
Byte(u8),
|
||||
Int(i32),
|
||||
Int(#[var] i32),
|
||||
Long(i64),
|
||||
Float(f32),
|
||||
String(String),
|
||||
Component(Component),
|
||||
|
@ -63,19 +63,41 @@ pub enum EntityDataValue {
|
|||
OptionalUuid(Option<Uuid>),
|
||||
// 0 for absent (implies air); otherwise, a block state ID as per the global palette
|
||||
// this is a varint
|
||||
OptionalBlockState(Option<BlockState>),
|
||||
BlockState(BlockState),
|
||||
CompoundTag(azalea_nbt::Tag),
|
||||
Particle(Particle),
|
||||
VillagerData(VillagerData),
|
||||
// 0 for absent; 1 + actual value otherwise. Used for entity IDs.
|
||||
OptionalUnsignedInt(Option<u32>),
|
||||
OptionalUnsignedInt(OptionalUnsignedInt),
|
||||
Pose(Pose),
|
||||
CatVariant(azalea_registry::CatVariant),
|
||||
FrogVariant(azalea_registry::FrogVariant),
|
||||
GlobalPos(GlobalPos),
|
||||
OptionalGlobalPos(Option<GlobalPos>),
|
||||
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)]
|
||||
pub struct Rotations {
|
||||
pub x: f32,
|
||||
|
@ -83,67 +105,6 @@ pub struct Rotations {
|
|||
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)]
|
||||
pub enum Pose {
|
||||
#[default]
|
||||
|
@ -157,14 +118,12 @@ pub enum Pose {
|
|||
Dying,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, McBuf, Default)]
|
||||
#[derive(Debug, Clone, McBuf)]
|
||||
pub struct VillagerData {
|
||||
pub kind: azalea_registry::VillagerType,
|
||||
pub profession: azalea_registry::VillagerProfession,
|
||||
#[var]
|
||||
type_: u32,
|
||||
#[var]
|
||||
profession: u32,
|
||||
#[var]
|
||||
level: u32,
|
||||
pub level: u32,
|
||||
}
|
||||
|
||||
impl TryFrom<EntityMetadataItems> for Vec<EntityDataValue> {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// Don't change it manually!
|
||||
|
||||
#![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_chat::Component;
|
||||
use azalea_core::{BlockPos, Direction, Particle, Slot};
|
||||
|
@ -114,7 +114,7 @@ impl Default for AreaEffectCloud {
|
|||
fn default() -> Self {
|
||||
Self {
|
||||
abstract_entity: Default::default(),
|
||||
radius: 0.5,
|
||||
radius: 3.0,
|
||||
color: 0,
|
||||
waiting: false,
|
||||
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)]
|
||||
pub struct Cat {
|
||||
pub abstract_tameable: AbstractTameable,
|
||||
|
@ -1733,7 +1846,7 @@ impl DerefMut for EnderPearl {
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct Enderman {
|
||||
pub abstract_monster: AbstractMonster,
|
||||
pub carry_state: Option<BlockState>,
|
||||
pub carry_state: BlockState,
|
||||
pub creepy: bool,
|
||||
pub stared_at: bool,
|
||||
}
|
||||
|
@ -1741,7 +1854,7 @@ pub struct Enderman {
|
|||
impl Enderman {
|
||||
pub fn read(metadata: &mut VecDeque<EntityDataValue>) -> Option<Self> {
|
||||
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 stared_at = metadata.pop_front()?.into_boolean().ok()?;
|
||||
Some(Self {
|
||||
|
@ -1755,9 +1868,7 @@ impl Enderman {
|
|||
pub fn write(&self) -> Vec<EntityDataValue> {
|
||||
let mut metadata = Vec::new();
|
||||
metadata.extend(self.abstract_monster.write());
|
||||
metadata.push(EntityDataValue::OptionalBlockState(
|
||||
self.carry_state.clone(),
|
||||
));
|
||||
metadata.push(EntityDataValue::BlockState(self.carry_state.clone()));
|
||||
metadata.push(EntityDataValue::Boolean(self.creepy.clone()));
|
||||
metadata.push(EntityDataValue::Boolean(self.stared_at.clone()));
|
||||
metadata
|
||||
|
@ -1768,7 +1879,7 @@ impl Default for Enderman {
|
|||
fn default() -> Self {
|
||||
Self {
|
||||
abstract_monster: Default::default(),
|
||||
carry_state: None,
|
||||
carry_state: BlockState::Air,
|
||||
creepy: false,
|
||||
stared_at: false,
|
||||
}
|
||||
|
@ -1779,7 +1890,7 @@ impl Enderman {
|
|||
pub fn set_index(&mut self, index: u8, value: EntityDataValue) -> Option<()> {
|
||||
match index {
|
||||
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()?,
|
||||
18 => self.stared_at = value.into_boolean().ok()?,
|
||||
_ => {}
|
||||
|
@ -2213,7 +2324,7 @@ impl DerefMut for Fireball {
|
|||
pub struct FireworkRocket {
|
||||
pub abstract_entity: AbstractEntity,
|
||||
pub fireworks_item: Slot,
|
||||
pub attached_to_target: Option<u32>,
|
||||
pub attached_to_target: OptionalUnsignedInt,
|
||||
pub shot_at_angle: bool,
|
||||
}
|
||||
|
||||
|
@ -2248,7 +2359,7 @@ impl Default for FireworkRocket {
|
|||
Self {
|
||||
abstract_entity: Default::default(),
|
||||
fireworks_item: Slot::Empty,
|
||||
attached_to_target: None,
|
||||
attached_to_target: OptionalUnsignedInt(None),
|
||||
shot_at_angle: false,
|
||||
}
|
||||
}
|
||||
|
@ -2464,7 +2575,7 @@ impl DerefMut for Fox {
|
|||
pub struct Frog {
|
||||
pub abstract_animal: AbstractAnimal,
|
||||
pub variant: azalea_registry::FrogVariant,
|
||||
pub tongue_target: Option<u32>,
|
||||
pub tongue_target: OptionalUnsignedInt,
|
||||
}
|
||||
|
||||
impl Frog {
|
||||
|
@ -2495,7 +2606,7 @@ impl Default for Frog {
|
|||
Self {
|
||||
abstract_animal: Default::default(),
|
||||
variant: azalea_registry::FrogVariant::Temperate,
|
||||
tongue_target: None,
|
||||
tongue_target: OptionalUnsignedInt(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6421,7 +6532,11 @@ impl Default for Villager {
|
|||
Self {
|
||||
abstract_ageable: Default::default(),
|
||||
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 {
|
||||
zombie: Default::default(),
|
||||
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),
|
||||
Blaze(Blaze),
|
||||
Boat(Boat),
|
||||
Camel(Camel),
|
||||
Cat(Cat),
|
||||
CaveSpider(CaveSpider),
|
||||
ChestBoat(ChestBoat),
|
||||
|
@ -8047,6 +8167,7 @@ impl From<azalea_registry::EntityType> for EntityMetadata {
|
|||
azalea_registry::EntityType::Bee => EntityMetadata::Bee(Bee::default()),
|
||||
azalea_registry::EntityType::Blaze => EntityMetadata::Blaze(Blaze::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::CaveSpider => {
|
||||
EntityMetadata::CaveSpider(CaveSpider::default())
|
||||
|
@ -8270,6 +8391,7 @@ impl EntityMetadata {
|
|||
EntityMetadata::Bee(entity) => entity.set_index(index, value),
|
||||
EntityMetadata::Blaze(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::CaveSpider(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::Blaze(entity) => entity,
|
||||
EntityMetadata::Boat(entity) => entity,
|
||||
EntityMetadata::Camel(entity) => entity,
|
||||
EntityMetadata::Cat(entity) => entity,
|
||||
EntityMetadata::CaveSpider(entity) => entity,
|
||||
EntityMetadata::ChestBoat(entity) => entity,
|
||||
|
@ -8520,6 +8643,7 @@ impl DerefMut for EntityMetadata {
|
|||
EntityMetadata::Bee(entity) => entity,
|
||||
EntityMetadata::Blaze(entity) => entity,
|
||||
EntityMetadata::Boat(entity) => entity,
|
||||
EntityMetadata::Camel(entity) => entity,
|
||||
EntityMetadata::Cat(entity) => entity,
|
||||
EntityMetadata::CaveSpider(entity) => entity,
|
||||
EntityMetadata::ChestBoat(entity) => entity,
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! [`azalea_client`]: https://crates.io/crates/azalea-client
|
||||
//! [`azalea_client`]: https://docs.rs/azalea-client
|
||||
|
||||
#![feature(trait_upcasting)]
|
||||
#![feature(async_closure)]
|
||||
|
|
|
@ -42,7 +42,7 @@ async fn main() -> anyhow::Result<()> {
|
|||
let mut accounts = Vec::new();
|
||||
let mut states = Vec::new();
|
||||
|
||||
for i in 0..7 {
|
||||
for i in 0..1 {
|
||||
accounts.push(Account::offline(&format!("bot{}", i)));
|
||||
states.push(State::default());
|
||||
}
|
||||
|
|
|
@ -6,14 +6,42 @@ The directory name doesn't start with `azalea-` because it's not a Rust crate.
|
|||
|
||||
- Python 3.8+
|
||||
- Java 17+
|
||||
- Gradle
|
||||
- Maven
|
||||
|
||||
## Usage
|
||||
|
||||
Generate packet:\
|
||||
`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.
|
||||
`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.
|
||||
|
||||
## 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.
|
||||
|
|
|
@ -9,8 +9,10 @@ import lib.utils
|
|||
|
||||
version_id = lib.code.version.get_version_id()
|
||||
|
||||
shape_datas = lib.extract.get_generator_mod_data(
|
||||
version_id, 'blockCollisionShapes')
|
||||
shape_datas = lib.extract.get_pixlyzer_data(
|
||||
version_id, 'shapes')
|
||||
pixlyzer_block_datas = lib.extract.get_pixlyzer_data(
|
||||
version_id, 'blocks')
|
||||
|
||||
mappings = lib.download.get_mappings_for_version(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)
|
||||
|
||||
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()
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ import lib.code.entity
|
|||
import lib.code.utils
|
||||
import lib.download
|
||||
import lib.extract
|
||||
import sys
|
||||
|
||||
version_id = lib.code.version.get_version_id()
|
||||
|
||||
|
|
13
codegen/genlanguage.py
Normal file
13
codegen/genlanguage.py
Normal 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!')
|
|
@ -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.append('make_block_states! {')
|
||||
|
||||
|
||||
# Find 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(
|
||||
f' "{property_name}" => {property_shape_code},')
|
||||
|
||||
|
||||
new_make_block_states_macro_code.append(' },')
|
||||
|
||||
# Block codegen
|
||||
|
@ -101,7 +99,6 @@ def generate_blocks(blocks_burger: dict, blocks_report: dict, ordered_blocks: li
|
|||
if state.get('default'):
|
||||
default_property_variants = state.get('properties', {})
|
||||
|
||||
|
||||
properties_code = '{'
|
||||
for property_name in list(block_data_report.get('properties', {}).keys()):
|
||||
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:
|
||||
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:
|
||||
# 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
|
||||
|
@ -184,16 +182,23 @@ def get_property_struct_name(property: Optional[dict], block_data_burger: dict,
|
|||
return 'ChestType'
|
||||
if property_variants == ['compare', 'subtract']:
|
||||
return 'ComparatorType'
|
||||
if 'harp' in property_variants and 'didgeridoo' in property_variants:
|
||||
return 'Sound'
|
||||
|
||||
if property is None:
|
||||
return ''.join(map(to_camel_case, property_variants))
|
||||
|
||||
property_name = None
|
||||
for class_name in [block_data_burger['class']] + block_data_burger['super']:
|
||||
property_name = mappings.get_field(
|
||||
class_name, property['field_name'])
|
||||
if property_name:
|
||||
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
|
||||
property_name = to_camel_case(property_name.lower())
|
||||
if property['type'] == 'int':
|
||||
|
|
|
@ -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
|
||||
metadata_types = [
|
||||
{'name': 'Byte', 'type': 'u8'},
|
||||
{'name': 'Int', 'type': 'i32'},
|
||||
{'name': 'Int', 'type': 'i32', 'var': True},
|
||||
{'name': 'Long', 'type': 'i64'},
|
||||
{'name': 'Float', 'type': 'f32'},
|
||||
{'name': 'String', 'type': 'String'},
|
||||
{'name': 'Component', 'type': 'Component'},
|
||||
|
@ -23,11 +24,11 @@ def generate_entity_metadata(burger_entity_data: dict, mappings: Mappings):
|
|||
{'name': 'OptionalBlockPos', 'type': 'Option<BlockPos>'},
|
||||
{'name': 'Direction', 'type': 'Direction'},
|
||||
{'name': 'OptionalUuid', 'type': 'Option<Uuid>'},
|
||||
{'name': 'OptionalBlockState', 'type': 'Option<BlockState>'},
|
||||
{'name': 'BlockState', 'type': 'BlockState'},
|
||||
{'name': 'CompoundTag', 'type': 'azalea_nbt::Tag'},
|
||||
{'name': 'Particle', 'type': 'Particle'},
|
||||
{'name': 'VillagerData', 'type': 'VillagerData'},
|
||||
{'name': 'OptionalUnsignedInt', 'type': 'Option<u32>'},
|
||||
{'name': 'OptionalUnsignedInt', 'type': 'OptionalUnsignedInt'},
|
||||
{'name': 'Pose', 'type': 'Pose'},
|
||||
{'name': 'CatVariant', 'type': 'azalea_registry::CatVariant'},
|
||||
{'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('')
|
||||
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_chat::Component;')
|
||||
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'
|
||||
elif type_name == 'FrogVariant':
|
||||
default = 'azalea_registry::FrogVariant::Temperate'
|
||||
elif type_name == 'VillagerData':
|
||||
default = 'VillagerData { kind: azalea_registry::VillagerType::Plains, profession: azalea_registry::VillagerProfession::None, level: 0 }'
|
||||
else:
|
||||
default = 'Default::default()'
|
||||
else:
|
||||
|
@ -200,11 +204,11 @@ def generate_entity_metadata(burger_entity_data: dict, mappings: Mappings):
|
|||
elif type_name == 'OptionalUuid':
|
||||
default = f'Some(uuid::uuid!({default}))' if default != 'Empty' else 'None'
|
||||
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':
|
||||
default = f'Slot::Present({default})' if default != 'Empty' else 'Slot::Empty'
|
||||
elif type_name == 'OptionalBlockState':
|
||||
default = f'Some({default})' if default != 'Empty' else 'None'
|
||||
elif type_name == 'BlockState':
|
||||
default = f'{default}' if default != 'Empty' else 'BlockState::Air'
|
||||
elif type_name == 'OptionalComponent':
|
||||
default = f'Some({default})' if default != 'Empty' else 'None'
|
||||
elif type_name == 'CompoundTag':
|
||||
|
|
8
codegen/lib/code/language.py
Normal file
8
codegen/lib/code/language.py
Normal 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=' '))
|
|
@ -247,9 +247,10 @@ def burger_instruction_to_code(instructions: list[dict], index: int, generated_p
|
|||
# figure out what kind of iterator it is
|
||||
loop_instructions = next_next_instruction['instructions']
|
||||
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)
|
||||
field_type_rs = f'Vec<{entry_type_rs}>'
|
||||
uses.update(value_uses)
|
||||
elif len(loop_instructions) == 3:
|
||||
is_map = loop_instructions[0]['type'].startswith(
|
||||
'Map.Entry<')
|
||||
|
|
|
@ -9,8 +9,45 @@ REGISTRIES_DIR = get_dir_location('../azalea-registry/src/lib.rs')
|
|||
def generate_registries(registries: dict):
|
||||
code = []
|
||||
|
||||
code.append('use azalea_registry_macros::registry;')
|
||||
code.append('')
|
||||
code.append('''// 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 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():
|
||||
# registry!(Block, {
|
||||
|
|
|
@ -7,8 +7,8 @@ COLLISION_BLOCKS_RS_DIR = get_dir_location(
|
|||
'../azalea-physics/src/collision/blocks.rs')
|
||||
|
||||
|
||||
def generate_block_shapes(blocks: dict, shapes: dict, block_states_report, block_datas_burger, mappings: Mappings):
|
||||
blocks, shapes = simplify_shapes(blocks, shapes)
|
||||
def generate_block_shapes(blocks: dict, shapes: dict, aabbs: dict, block_states_report, block_datas_burger, mappings: Mappings):
|
||||
blocks, shapes = simplify_shapes(blocks, shapes, aabbs)
|
||||
|
||||
code = generate_block_shapes_code(
|
||||
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)
|
||||
|
||||
|
||||
def simplify_shapes(blocks: dict, shapes: dict):
|
||||
shape_to_new_id = {}
|
||||
def simplify_shapes(blocks: dict, shapes: dict, aabbs: dict):
|
||||
new_id_increment = 0
|
||||
|
||||
new_shapes = {}
|
||||
old_id_to_new_id = {}
|
||||
|
||||
for shape_id, shape in sorted(shapes.items(), key=lambda shape: int(shape[0])):
|
||||
# tuples are hashable
|
||||
shape_as_tuple = tuple(map(tuple, shape))
|
||||
if shape_as_tuple not in shape_to_new_id:
|
||||
shape_to_new_id[shape_as_tuple] = new_id_increment
|
||||
old_id_to_new_id[None] = 0
|
||||
new_shapes[0] = ()
|
||||
new_id_increment += 1
|
||||
|
||||
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
|
||||
new_shapes[new_id_increment] = shape
|
||||
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
|
||||
for block_id, shape_ids in blocks.items():
|
||||
if isinstance(shape_ids, int):
|
||||
blocks[block_id] = old_id_to_new_id[str(shape_ids)]
|
||||
else:
|
||||
blocks[block_id] = [old_id_to_new_id[str(shape_id)]
|
||||
for shape_id in shape_ids]
|
||||
new_blocks = {}
|
||||
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()]
|
||||
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):
|
||||
|
@ -116,7 +137,7 @@ def generate_code_for_shape(shape_id: str, parts: list[list[float]]):
|
|||
code = ''
|
||||
code += f'static SHAPE{shape_id}: Lazy<VoxelShape> = Lazy::new(|| {{'
|
||||
steps = []
|
||||
if parts == []:
|
||||
if parts == ():
|
||||
steps.append('collision::empty_shape()')
|
||||
else:
|
||||
steps.append(f'collision::box_shape({make_arguments(parts[0])})')
|
||||
|
|
|
@ -63,6 +63,12 @@ def burger_type_to_rust_type(burger_type, field_name: Optional[str] = None, inst
|
|||
elif burger_type == 'metadata':
|
||||
field_type_rs = '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':
|
||||
field_type_rs = 'todo!()'
|
||||
elif burger_type == 'enum':
|
||||
|
|
|
@ -19,15 +19,15 @@ def get_burger():
|
|||
f'cd {get_dir_location("downloads")} && git clone https://github.com/pokechu22/Burger && cd Burger && git pull')
|
||||
|
||||
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():
|
||||
if not os.path.exists(get_dir_location('downloads/minecraft-data-generator-server')):
|
||||
print('\033[92mDownloading u9g/minecraft-data-generator-server...\033[m')
|
||||
def get_pixlyzer():
|
||||
if not os.path.exists(get_dir_location('downloads/pixlyzer')):
|
||||
print('\033[92mDownloading bixilon/pixlyzer...\033[m')
|
||||
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')
|
||||
return get_dir_location('downloads/minecraft-data-generator-server')
|
||||
f'cd {get_dir_location("downloads")} && git clone https://gitlab.bixilon.de/bixilon/pixlyzer.git && cd pixlyzer && git pull')
|
||||
return get_dir_location('downloads/pixlyzer')
|
||||
|
||||
|
||||
def get_version_manifest():
|
||||
|
@ -180,4 +180,4 @@ def clear_version_cache():
|
|||
os.system(
|
||||
f'cd {get_dir_location("downloads/Burger")} && git pull')
|
||||
os.system(
|
||||
f'cd {get_dir_location("downloads/minecraft-data-generator-server")} && git pull')
|
||||
f'cd {get_dir_location("downloads/pixlyzer")} && git pull')
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
# 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 zipfile import ZipFile
|
||||
import subprocess
|
||||
import json
|
||||
import sys
|
||||
import re
|
||||
import os
|
||||
|
||||
|
@ -59,103 +61,185 @@ def determine_python_command():
|
|||
'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):
|
||||
if not os.path.exists(get_dir_location(f'downloads/burger-{version_id}.json')):
|
||||
get_burger()
|
||||
get_client_jar(version_id)
|
||||
|
||||
for _ in range(10):
|
||||
r = subprocess.run(
|
||||
f'cd {get_dir_location("downloads/Burger")} && {determine_python_command()} munch.py ../client-{version_id}.jar --output ../burger-{version_id}.json',
|
||||
capture_output=True,
|
||||
shell=True
|
||||
print('\033[92mRunning Burger...\033[m')
|
||||
run_python_command_and_download_deps(
|
||||
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'
|
||||
)
|
||||
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:
|
||||
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)):
|
||||
generator_mod_dir = get_generator_mod()
|
||||
pixlyzer_dir = get_pixlyzer()
|
||||
|
||||
yarn_data = get_yarn_data(version_id)
|
||||
if not yarn_data:
|
||||
raise Exception(
|
||||
'Fabric/Yarn hasn\'t been updated to this version yet.')
|
||||
# looks like 1.19+build.1
|
||||
yarn_version = yarn_data['version']
|
||||
# for some reason pixlyzer doesn't work right unless the mvn clean
|
||||
# instruction looks like that
|
||||
# and pixlyzer.py doesn't do it right
|
||||
|
||||
fabric_api_version = get_fabric_api_versions()[-1]
|
||||
fabric_loader_version = get_fabric_loader_versions()[0]
|
||||
|
||||
# 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
|
||||
# map jar + download dependencies
|
||||
run_python_command_and_download_deps(
|
||||
f'cd {pixlyzer_dir}/wrapper && {determine_python_command()} PixLyzer.py --only-version={version_id} --dont-compile --only-map'
|
||||
)
|
||||
except Exception as e:
|
||||
os.system(f'cd {generator_mod_dir} && gradlew runServer')
|
||||
# update the pom.xml <dependencies>
|
||||
# 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):
|
||||
os.unlink(target_dir)
|
||||
os.rename(
|
||||
get_dir_location(
|
||||
f'{generator_mod_dir}/run/minecraft-data/{version_id}'),
|
||||
source_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)
|
||||
|
||||
|
||||
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')
|
||||
)
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
from lib.code.packet import fix_state
|
||||
from lib.utils import PacketIdentifier, group_packets
|
||||
import lib.code.language
|
||||
import lib.code.registry
|
||||
import lib.code.version
|
||||
import lib.code.blocks
|
||||
import lib.code.packet
|
||||
import lib.code.shapes
|
||||
import lib.code.utils
|
||||
import lib.download
|
||||
import lib.extract
|
||||
|
@ -101,7 +104,6 @@ for packet in added_or_changed_packets:
|
|||
|
||||
lib.code.version.set_protocol_version(
|
||||
new_burger_data[0]['version']['protocol'])
|
||||
lib.code.version.set_version_id(new_version_id)
|
||||
|
||||
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)
|
||||
if old_ordered_blocks != new_ordered_blocks:
|
||||
print('Blocks changed, updating...')
|
||||
|
||||
block_states_burger = lib.extract.get_block_states_burger(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(
|
||||
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()
|
||||
|
||||
print('Done!')
|
||||
print('Make sure to `cargo check` and look for the generated `TODO`s to make sure everything is correct!')
|
||||
|
|
|
@ -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_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(
|
||||
f'Generating code for packet id: {packet_id} with direction {direction} and state {state}')
|
||||
lib.code.packet.generate_packet(burger_packets_data, mappings,
|
||||
|
|
Loading…
Add table
Reference in a new issue