chore: add encoder fuzzing

ofc nothing more :wink
This commit is contained in:
Alexander Medvedev 2026-04-16 20:32:19 +02:00
parent e2089531ee
commit e9423dcb9c
22 changed files with 532 additions and 558 deletions

26
Cargo.lock generated
View File

@ -411,19 +411,6 @@ dependencies = [
"rand_core 0.10.1", "rand_core 0.10.1",
] ]
[[package]]
name = "chrono"
version = "0.4.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
dependencies = [
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-link",
]
[[package]] [[package]]
name = "ciborium" name = "ciborium"
version = "0.2.2" version = "0.2.2"
@ -463,9 +450,9 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.6.0" version = "4.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
] ]
@ -2840,7 +2827,6 @@ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"bitflags 2.11.1", "bitflags 2.11.1",
"bytes", "bytes",
"chrono",
"console-subscriber", "console-subscriber",
"crossbeam", "crossbeam",
"flate2", "flate2",
@ -4326,9 +4312,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.23.0" version = "1.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76"
dependencies = [ dependencies = [
"getrandom 0.4.2", "getrandom 0.4.2",
"js-sys", "js-sys",
@ -4894,9 +4880,9 @@ dependencies = [
[[package]] [[package]]
name = "webpki-roots" name = "webpki-roots"
version = "1.0.6" version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d"
dependencies = [ dependencies = [
"rustls-pki-types", "rustls-pki-types",
] ]

View File

@ -101,7 +101,6 @@ bytes = "1.11"
futures = { version = "0.3", default-features = false, features = ["executor"] } futures = { version = "0.3", default-features = false, features = ["executor"] }
rayon = "1.12" rayon = "1.12"
crossbeam = "0.8" crossbeam = "0.8"
chrono = "0.4"
uuid = { version = "1.23", features = ["serde", "v3", "v4"] } uuid = { version = "1.23", features = ["serde", "v3", "v4"] }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }

View File

@ -906,9 +906,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.51.0" version = "1.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bd1c4c0fc4a7ab90fc15ef6daaa3ec3b893f004f915f2392557ed23237820cd" checksum = "a91135f59b1cbf38c91e73cf3386fca9bb77915c45ce2771460c9d92f0f3d776"
dependencies = [ dependencies = [
"pin-project-lite", "pin-project-lite",
] ]

View File

@ -21,7 +21,7 @@ pumpkin-util.workspace = true
uuid.workspace = true uuid.workspace = true
serde.workspace = true serde.workspace = true
thiserror.workspace = true thiserror.workspace = true
tokio.workspace = true tokio = { workspace = true, features = ["net"] }
bytes.workspace = true bytes.workspace = true
# encryption # encryption

View File

@ -10,13 +10,13 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]] [[package]]
name = "aes" name = "aes"
version = "0.8.4" version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" checksum = "66bd29a732b644c0431c6140f370d097879203d79b80c94a6747ba0872adaef8"
dependencies = [ dependencies = [
"cfg-if",
"cipher", "cipher",
"cpufeatures 0.2.17", "cpubits",
"cpufeatures 0.3.0",
] ]
[[package]] [[package]]
@ -69,9 +69,9 @@ checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.11.0" version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
[[package]] [[package]]
name = "block-buffer" name = "block-buffer"
@ -84,9 +84,9 @@ dependencies = [
[[package]] [[package]]
name = "block-buffer" name = "block-buffer"
version = "0.11.0" version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96eb4cdd6cf1b31d671e9efe75c5d1ec614776856cefbe109ca373554a6d514f" checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be"
dependencies = [ dependencies = [
"hybrid-array", "hybrid-array",
] ]
@ -105,9 +105,9 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.56" version = "1.2.60"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20"
dependencies = [ dependencies = [
"find-msvc-tools", "find-msvc-tools",
"jobserver", "jobserver",
@ -123,9 +123,9 @@ checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
[[package]] [[package]]
name = "cfb8" name = "cfb8"
version = "0.8.1" version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "014c0a0e1ad0dae6a86c082db2f9bd7fe8c2c734227047d0d8b4d4a3a094a1e1" checksum = "c22e6368a74b7dd7039e10da9f0300ab4520584f2960048a5a4a4e51f8e4e183"
dependencies = [ dependencies = [
"cipher", "cipher",
] ]
@ -144,16 +144,16 @@ checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"cpufeatures 0.3.0", "cpufeatures 0.3.0",
"rand_core 0.10.0", "rand_core 0.10.1",
] ]
[[package]] [[package]]
name = "cipher" name = "cipher"
version = "0.4.4" version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" checksum = "e34d8227fe1ba289043aeb13792056ff80fd6de1a9f49137a5f499de8e8c78ea"
dependencies = [ dependencies = [
"crypto-common 0.1.7", "crypto-common 0.2.1",
"inout", "inout",
] ]
@ -163,7 +163,7 @@ version = "3.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34"
dependencies = [ dependencies = [
"windows-sys 0.61.2", "windows-sys",
] ]
[[package]] [[package]]
@ -194,6 +194,12 @@ version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c"
[[package]]
name = "cpubits"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ef0c543070d296ea414df2dd7625d1b24866ce206709d8a4a424f28377f5861"
[[package]] [[package]]
name = "cpufeatures" name = "cpufeatures"
version = "0.2.17" version = "0.2.17"
@ -313,9 +319,9 @@ dependencies = [
[[package]] [[package]]
name = "crypto-common" name = "crypto-common"
version = "0.1.7" version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [ dependencies = [
"generic-array", "generic-array",
"typenum", "typenum",
@ -323,9 +329,9 @@ dependencies = [
[[package]] [[package]]
name = "crypto-common" name = "crypto-common"
version = "0.2.0" version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "211f05e03c7d03754740fd9e585de910a095d6b99f8bcfffdef8319fa02a8331" checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710"
dependencies = [ dependencies = [
"hybrid-array", "hybrid-array",
] ]
@ -363,19 +369,19 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [ dependencies = [
"block-buffer 0.10.4", "block-buffer 0.10.4",
"const-oid 0.9.6", "const-oid 0.9.6",
"crypto-common 0.1.7", "crypto-common 0.1.6",
"subtle", "subtle",
] ]
[[package]] [[package]]
name = "digest" name = "digest"
version = "0.11.0" version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8bf3682cdec91817be507e4aa104314898b95b84d74f3d43882210101a545b6" checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c"
dependencies = [ dependencies = [
"block-buffer 0.11.0", "block-buffer 0.12.0",
"const-oid 0.10.2", "const-oid 0.10.2",
"crypto-common 0.2.0", "crypto-common 0.2.1",
] ]
[[package]] [[package]]
@ -444,14 +450,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys 0.61.2", "windows-sys",
] ]
[[package]] [[package]]
name = "fastrand" name = "fastrand"
version = "2.3.0" version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
[[package]] [[package]]
name = "ff" name = "ff"
@ -575,9 +581,9 @@ dependencies = [
[[package]] [[package]]
name = "generic-array" name = "generic-array"
version = "0.14.7" version = "0.14.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2"
dependencies = [ dependencies = [
"typenum", "typenum",
"version_check", "version_check",
@ -603,20 +609,20 @@ checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"r-efi", "r-efi 5.3.0",
"wasip2", "wasip2",
] ]
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.4.1" version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
"r-efi", "r-efi 6.0.0",
"rand_core 0.10.0", "rand_core 0.10.1",
"wasip2", "wasip2",
"wasip3", "wasip3",
] ]
@ -649,9 +655,9 @@ dependencies = [
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.16.1" version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51"
[[package]] [[package]]
name = "heck" name = "heck"
@ -685,9 +691,9 @@ dependencies = [
[[package]] [[package]]
name = "hybrid-array" name = "hybrid-array"
version = "0.4.7" version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1b229d73f5803b562cc26e4da0396c8610a4ee209f4fac8fa4f8d709166dc45" checksum = "3944cf8cf766b40e2a1a333ee5e9b563f854d5fa49d6a8ca2764e97c6eddb214"
dependencies = [ dependencies = [
"typenum", "typenum",
] ]
@ -700,23 +706,23 @@ checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.13.0" version = "2.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown 0.16.1", "hashbrown 0.17.0",
"serde", "serde",
"serde_core", "serde_core",
] ]
[[package]] [[package]]
name = "inout" name = "inout"
version = "0.1.4" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7"
dependencies = [ dependencies = [
"generic-array", "hybrid-array",
] ]
[[package]] [[package]]
@ -730,9 +736,9 @@ dependencies = [
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.17" version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]] [[package]]
name = "jobserver" name = "jobserver"
@ -746,9 +752,9 @@ dependencies = [
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.88" version = "0.3.95"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7e709f3e3d22866f9c25b3aff01af289b18422cc8b4262fb19103ee80fe513d" checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"wasm-bindgen", "wasm-bindgen",
@ -762,9 +768,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.182" version = "0.2.185"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f"
[[package]] [[package]]
name = "libfuzzer-sys" name = "libfuzzer-sys"
@ -803,9 +809,9 @@ dependencies = [
[[package]] [[package]]
name = "lz4_flex" name = "lz4_flex"
version = "0.11.5" version = "0.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08ab2867e3eeeca90e844d1940eab391c9dc5228783db2ed999acbc0a9ed375a" checksum = "373f5eceeeab7925e0c1098212f2fbc4d416adec9d35051a6ab251e824c1854a"
[[package]] [[package]]
name = "md-5" name = "md-5"
@ -841,13 +847,13 @@ dependencies = [
[[package]] [[package]]
name = "mio" name = "mio"
version = "1.1.1" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
dependencies = [ dependencies = [
"libc", "libc",
"wasi", "wasi",
"windows-sys 0.61.2", "windows-sys",
] ]
[[package]] [[package]]
@ -882,9 +888,9 @@ dependencies = [
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.21.3" version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
[[package]] [[package]]
name = "p384" name = "p384"
@ -975,9 +981,9 @@ dependencies = [
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.16" version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
[[package]] [[package]]
name = "pkcs8" name = "pkcs8"
@ -1105,6 +1111,7 @@ dependencies = [
"bytes", "bytes",
"cfb8", "cfb8",
"flate2", "flate2",
"hybrid-array",
"pumpkin-data", "pumpkin-data",
"pumpkin-macros", "pumpkin-macros",
"pumpkin-nbt", "pumpkin-nbt",
@ -1171,6 +1178,7 @@ dependencies = [
"pumpkin-nbt", "pumpkin-nbt",
"pumpkin-util", "pumpkin-util",
"rand", "rand",
"rayon",
"rustc-hash", "rustc-hash",
"ruzstd", "ruzstd",
"serde", "serde",
@ -1185,9 +1193,9 @@ dependencies = [
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.44" version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@ -1199,14 +1207,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
[[package]] [[package]]
name = "rand" name = "r-efi"
version = "0.10.0" version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
[[package]]
name = "rand"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207"
dependencies = [ dependencies = [
"chacha20", "chacha20",
"getrandom 0.4.1", "getrandom 0.4.2",
"rand_core 0.10.0", "rand_core 0.10.1",
] ]
[[package]] [[package]]
@ -1220,9 +1234,29 @@ dependencies = [
[[package]] [[package]]
name = "rand_core" name = "rand_core"
version = "0.10.0" version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
[[package]]
name = "rayon"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
]
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
@ -1286,9 +1320,9 @@ dependencies = [
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.27" version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
[[package]] [[package]]
name = "serde" name = "serde"
@ -1361,7 +1395,7 @@ checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"cpufeatures 0.3.0", "cpufeatures 0.3.0",
"digest 0.11.0", "digest 0.11.2",
] ]
[[package]] [[package]]
@ -1392,9 +1426,9 @@ dependencies = [
[[package]] [[package]]
name = "simd-adler32" name = "simd-adler32"
version = "0.3.8" version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
[[package]] [[package]]
name = "siphasher" name = "siphasher"
@ -1425,12 +1459,12 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.6.2" version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys 0.60.2", "windows-sys",
] ]
[[package]] [[package]]
@ -1500,9 +1534,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.50.0" version = "1.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" checksum = "a91135f59b1cbf38c91e73cf3386fca9bb77915c45ce2771460c9d92f0f3d776"
dependencies = [ dependencies = [
"bytes", "bytes",
"libc", "libc",
@ -1512,14 +1546,14 @@ dependencies = [
"signal-hook-registry", "signal-hook-registry",
"socket2", "socket2",
"tokio-macros", "tokio-macros",
"windows-sys 0.61.2", "windows-sys",
] ]
[[package]] [[package]]
name = "tokio-macros" name = "tokio-macros"
version = "2.6.0" version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1542,9 +1576,9 @@ dependencies = [
[[package]] [[package]]
name = "toml" name = "toml"
version = "1.1.1+spec-1.1.0" version = "1.1.2+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "994b95d9e7bae62b34bab0e2a4510b801fa466066a6a8b2b57361fa1eba068ee" checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"serde_core", "serde_core",
@ -1566,9 +1600,9 @@ dependencies = [
[[package]] [[package]]
name = "toml_parser" name = "toml_parser"
version = "1.1.1+spec-1.1.0" version = "1.1.2+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39ca317ebc49f06bd748bfba29533eac9485569dc9bf80b849024b025e814fb9" checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
dependencies = [ dependencies = [
"winnow", "winnow",
] ]
@ -1646,11 +1680,11 @@ checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.23.0" version = "1.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76"
dependencies = [ dependencies = [
"getrandom 0.4.1", "getrandom 0.4.2",
"js-sys", "js-sys",
"md-5", "md-5",
"serde_core", "serde_core",
@ -1689,9 +1723,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.111" version = "0.2.118"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec1adf1535672f5b7824f817792b1afd731d7e843d2d04ec8f27e8cb51edd8ac" checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"once_cell", "once_cell",
@ -1702,9 +1736,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.111" version = "0.2.118"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19e638317c08b21663aed4d2b9a2091450548954695ff4efa75bff5fa546b3b1" checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed"
dependencies = [ dependencies = [
"quote", "quote",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
@ -1712,9 +1746,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.111" version = "0.2.118"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c64760850114d03d5f65457e96fc988f11f01d38fbaa51b254e4ab5809102af" checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"proc-macro2", "proc-macro2",
@ -1725,9 +1759,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.111" version = "0.2.118"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60eecd4fe26177cfa3339eb00b4a36445889ba3ad37080c2429879718e20ca41" checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -1772,15 +1806,6 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.61.2" version = "0.61.2"
@ -1790,71 +1815,6 @@ dependencies = [
"windows-link", "windows-link",
] ]
[[package]]
name = "windows-targets"
version = "0.53.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
dependencies = [
"windows-link",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
[[package]]
name = "windows_i686_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
[[package]]
name = "windows_i686_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "1.0.1" version = "1.0.1"

View File

@ -35,3 +35,17 @@ path = "fuzz_targets/decoder_bedrock.rs"
test = false test = false
doc = false doc = false
bench = false bench = false
[[bin]]
name = "encoder_java"
path = "fuzz_targets/encoder_java.rs"
test = false
doc = false
bench = false
[[bin]]
name = "encoder_bedrock"
path = "fuzz_targets/encoder_bedrock.rs"
test = false
doc = false
bench = false

View File

@ -0,0 +1,43 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
use pumpkin_protocol::bedrock::packet_encoder::UDPNetworkEncoder;
use pumpkin_protocol::bedrock::SubClient;
fuzz_target!(|data: &[u8]| {
if data.len() < 10 {
return;
}
let compression_threshold = data[0] as usize;
let compression_level = (data[1] % 10) as u32;
let packet_id = u16::from_be_bytes([data[2], data[3]]);
let sender = match data[4] % 4 {
0 => SubClient::Main,
1 => SubClient::SubClient0,
2 => SubClient::SubClient1,
_ => SubClient::SubClietn2,
};
let target = match data[5] % 4 {
0 => SubClient::Main,
1 => SubClient::SubClient0,
2 => SubClient::SubClient1,
_ => SubClient::SubClietn2,
};
let use_compression = data[6] % 2 == 0;
let packet_payload = &data[7..];
let mut encoder = UDPNetworkEncoder::new();
if use_compression {
encoder.set_compression((compression_threshold, compression_level));
}
let mut out = Vec::new();
let _ = encoder.write_game_packet(
packet_id,
sender,
target,
packet_payload,
&mut out
);
});

View File

@ -0,0 +1,59 @@
#![no_main]
use libfuzzer_sys::fuzz_target;
use pumpkin_protocol::java::packet_encoder::TCPNetworkEncoder;
use pumpkin_protocol::codec::var_int::VarInt;
use pumpkin_protocol::ser::NetworkWriteExt;
use pumpkin_protocol::ServerPacket;
use pumpkin_protocol::java::client::play::CPlayerPosition;
use pumpkin_protocol::packet::MultiVersionJavaPacket;
use pumpkin_protocol::ClientPacket;
use pumpkin_util::version::MinecraftVersion;
use std::io::Cursor;
use tokio::runtime::Runtime;
const TARGET_VERSION: MinecraftVersion = MinecraftVersion::V_1_21_4;
fuzz_target!(|data: &[u8]| {
if data.len() < 20 {
return;
}
let compression_threshold = data[0] as usize;
let compression_level = (data[1] % 10) as u32;
let encryption_key: [u8; 16] = data[2..18].try_into().unwrap();
let use_compression = data[18] % 2 == 0;
let use_encryption = data[19] % 2 == 0;
let packet_data = &data[20..];
let rt = Runtime::new().unwrap();
rt.block_on(async {
let mut out = Vec::new();
let mut encoder = TCPNetworkEncoder::new(&mut out);
if use_compression {
encoder.set_compression((compression_threshold, compression_level));
}
if use_encryption {
encoder.set_encryption(&encryption_key);
}
// 1. Fuzz with raw bytes (simulating various packet payloads)
let mut buf = Vec::new();
let packet_id = if packet_data.is_empty() { 0 } else { packet_data[0] as i32 };
let _ = buf.write_var_int(&VarInt(packet_id));
buf.extend_from_slice(packet_data);
let _ = encoder.write_packet(buf.into()).await;
// 2. Fuzz with actual packets if they can be partially read
let mut cursor = Cursor::new(packet_data);
if let Ok(packet) = CPlayerPosition::read(&mut cursor, &TARGET_VERSION) {
let mut packet_buf = Vec::new();
let id = CPlayerPosition::to_id(TARGET_VERSION);
let _ = packet_buf.write_var_int(&VarInt(id));
let _ = packet.write_packet_data(&mut packet_buf, &TARGET_VERSION);
let _ = encoder.write_packet(packet_buf.into()).await;
}
let _ = encoder.flush().await;
});
});

View File

@ -157,7 +157,9 @@ impl<R: AsyncRead + Unpin> TCPNetworkDecoder<R> {
let payload_len_hint = expected_packet_data_len.saturating_sub(packet_id_len); let payload_len_hint = expected_packet_data_len.saturating_sub(packet_id_len);
self.payload_scratch.clear(); self.payload_scratch.clear();
self.payload_scratch.reserve(payload_len_hint); self.payload_scratch.reserve(payload_len_hint);
loop {
let mut total_read = 0;
while total_read < payload_len_hint {
let bytes_read = reader let bytes_read = reader
.read_buf(&mut self.payload_scratch) .read_buf(&mut self.payload_scratch)
.await .await
@ -165,6 +167,7 @@ impl<R: AsyncRead + Unpin> TCPNetworkDecoder<R> {
if bytes_read == 0 { if bytes_read == 0 {
break; break;
} }
total_read += bytes_read;
} }
if let Some(expected_uncompressed_packet_data_len) = expected_uncompressed_packet_data_len { if let Some(expected_uncompressed_packet_data_len) = expected_uncompressed_packet_data_len {

View File

@ -103,8 +103,7 @@ impl DaylightDetectorBlockEntity {
let sky_light_level = level let sky_light_level = level
.light_engine .light_engine
.get_sky_light_level(level, block_pos) .get_sky_light_level(level, block_pos)
.await .await;
.unwrap();
let mut power = sky_light_level - ambient_darkness; let mut power = sky_light_level - ambient_darkness;

View File

@ -38,8 +38,8 @@ pub const CHUNK_COUNT: usize = REGION_SIZE * REGION_SIZE;
/// The number of bytes in a sector (4 KiB) /// The number of bytes in a sector (4 KiB)
const SECTOR_BYTES: usize = 4096; const SECTOR_BYTES: usize = 4096;
// 26.1 // 26.1.2
pub const WORLD_DATA_VERSION: i32 = 4786; pub const WORLD_DATA_VERSION: i32 = 4790;
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)] #[repr(u8)]

View File

@ -136,14 +136,14 @@ impl DynamicLightEngine {
let new_light = light_level.saturating_sub(opacity); let new_light = light_level.saturating_sub(opacity);
// Only propagate if new light is brighter than current light // Only propagate if new light is brighter than current light
if new_light > neighbor_light { if new_light > neighbor_light
self.set_block_light_level(level, &neighbor_pos, new_light) && self
.set_block_light_level(level, &neighbor_pos, new_light)
.await .await
.unwrap(); .is_ok()
&& new_light > 1
if new_light > 1 { {
self.queue_block_light_increase(neighbor_pos, new_light); self.queue_block_light_increase(neighbor_pos, new_light);
}
} }
} }
} }
@ -301,29 +301,27 @@ impl DynamicLightEngine {
for dir in BlockDirection::all() { for dir in BlockDirection::all() {
let neighbor_pos = pos.offset(dir.to_offset()); let neighbor_pos = pos.offset(dir.to_offset());
if let Some(neighbor_light) = self.get_sky_light_level(level, &neighbor_pos).await { let neighbor_light = self.get_sky_light_level(level, &neighbor_pos).await;
let neighbor_state = level.get_block_state(&neighbor_pos).await.to_state(); let neighbor_state = level.get_block_state(&neighbor_pos).await.to_state();
let opacity = neighbor_state.opacity; let opacity = neighbor_state.opacity;
// Calculate new light level for neighbor // Calculate new light level for neighbor
let new_light = if light_level == 15 && dir == BlockDirection::Down && opacity == 0 let new_light = if light_level == 15 && dir == BlockDirection::Down && opacity == 0 {
{ // Special case: Sky light at 15 propagates down as 15 through transparent blocks
// Special case: Sky light at 15 propagates down as 15 through transparent blocks 15
15 } else {
} else { // Normal propagation: reduce by 1 for distance, then by opacity
// Normal propagation: reduce by 1 for distance, then by opacity light_level.saturating_sub(1).saturating_sub(opacity)
light_level.saturating_sub(1).saturating_sub(opacity) };
};
// Only propagate if new light is brighter than current light // Only propagate if new light is brighter than current light
if new_light > neighbor_light { if new_light > neighbor_light {
self.set_sky_light_level(level, &neighbor_pos, new_light) self.set_sky_light_level(level, &neighbor_pos, new_light)
.await .await
.unwrap(); .unwrap();
if new_light > 0 { if new_light > 0 {
self.queue_sky_light_increase(neighbor_pos, new_light); self.queue_sky_light_increase(neighbor_pos, new_light);
}
} }
} }
} }
@ -338,33 +336,31 @@ impl DynamicLightEngine {
for dir in BlockDirection::all() { for dir in BlockDirection::all() {
let neighbor_pos = pos.offset(dir.to_offset()); let neighbor_pos = pos.offset(dir.to_offset());
if let Some(neighbor_light) = self.get_sky_light_level(level, &neighbor_pos).await { let neighbor_light = self.get_sky_light_level(level, &neighbor_pos).await;
if neighbor_light == 0 { if neighbor_light == 0 {
continue; // Already dark continue; // Already dark
} }
let neighbor_state = level.get_block_state(&neighbor_pos).await.to_state(); let neighbor_state = level.get_block_state(&neighbor_pos).await.to_state();
let opacity = neighbor_state.opacity; let opacity = neighbor_state.opacity;
// Calculate what we would have given this neighbor // Calculate what we would have given this neighbor
let expected = if removed_light == 15 && dir == BlockDirection::Down && opacity == 0 let expected = if removed_light == 15 && dir == BlockDirection::Down && opacity == 0 {
{ 15
15 } else {
} else { removed_light.saturating_sub(1).saturating_sub(opacity)
removed_light.saturating_sub(1).saturating_sub(opacity) };
};
if neighbor_light == expected || neighbor_light < removed_light { if neighbor_light == expected || neighbor_light < removed_light {
// This neighbor was lit by us, darken it // This neighbor was lit by us, darken it
self.set_sky_light_level(level, &neighbor_pos, 0) self.set_sky_light_level(level, &neighbor_pos, 0)
.await .await
.unwrap(); .unwrap();
self.queue_sky_light_decrease(neighbor_pos, neighbor_light); self.queue_sky_light_decrease(neighbor_pos, neighbor_light);
} else if neighbor_light > removed_light { } else if neighbor_light > removed_light {
// Neighbor has brighter light from another source // Neighbor has brighter light from another source
// Re-propagate from it to fill in the gap we left // Re-propagate from it to fill in the gap we left
self.queue_sky_light_increase(neighbor_pos, neighbor_light); self.queue_sky_light_increase(neighbor_pos, neighbor_light);
}
} }
} }
} }
@ -382,7 +378,7 @@ impl DynamicLightEngine {
LightingEngineConfig::Default => {} LightingEngineConfig::Default => {}
} }
let current_light = self.get_sky_light_level(level, &pos).await.unwrap_or(0); let current_light = self.get_sky_light_level(level, &pos).await;
let block_state = level.get_block_state(&pos).await.to_state(); let block_state = level.get_block_state(&pos).await.to_state();
let opacity = block_state.opacity; let opacity = block_state.opacity;
@ -404,20 +400,17 @@ impl DynamicLightEngine {
for dir in BlockDirection::all() { for dir in BlockDirection::all() {
let neighbor_pos = pos.offset(dir.to_offset()); let neighbor_pos = pos.offset(dir.to_offset());
if let Some(neighbor_light) = let neighbor_light = self.get_sky_light_level(level, &neighbor_pos).await;
self.get_sky_light_level(level, &neighbor_pos).await // Calculate potential light from this neighbor
{ let potential = if neighbor_light == 15 && dir == BlockDirection::Up {
// Calculate potential light from this neighbor // Sky light at 15 from above stays 15
let potential = if neighbor_light == 15 && dir == BlockDirection::Up { 15
// Sky light at 15 from above stays 15 } else {
15 // Normal decay
} else { neighbor_light.saturating_sub(1)
// Normal decay };
neighbor_light.saturating_sub(1)
};
best_light = best_light.max(potential); best_light = best_light.max(potential);
}
} }
// Apply opacity to the best incoming light // Apply opacity to the best incoming light
@ -459,20 +452,22 @@ impl DynamicLightEngine {
level: &Arc<Level>, level: &Arc<Level>,
position: &BlockPos, position: &BlockPos,
) -> Option<u8> { ) -> Option<u8> {
let (chunk_coordinate, relative) = position.chunk_and_chunk_relative_position(); let (chunk_pos, relative) = position.chunk_and_chunk_relative_position();
let chunk = level.get_chunk(chunk_coordinate).await;
let section_index = (relative.y - chunk.section.min_y) as usize / BlockPalette::SIZE; let chunk = level.get_chunk(chunk_pos).await;
// Bounds check for section index (lock the light engine)
let light_engine = chunk.light_engine.lock().unwrap(); let section_idx = (relative.y - chunk.section.min_y) as usize / 16;
if section_index >= light_engine.block_light.len() { let light_engine = chunk.light_engine.lock().ok()?;
return None;
} light_engine
Some(light_engine.block_light[section_index].get( .block_light
relative.x as usize, .get(section_idx)?
(relative.y - chunk.section.min_y) as usize % BlockPalette::SIZE, .get(
relative.z as usize, relative.x as usize,
)) (relative.y - chunk.section.min_y) as usize % 16,
relative.z as usize,
)
.into()
} }
pub async fn set_block_light_level( pub async fn set_block_light_level(
@ -503,20 +498,22 @@ impl DynamicLightEngine {
Ok(()) Ok(())
} }
pub async fn get_sky_light_level(&self, level: &Arc<Level>, position: &BlockPos) -> Option<u8> { pub async fn get_sky_light_level(&self, level: &Arc<Level>, position: &BlockPos) -> u8 {
let (chunk_coordinate, relative) = position.chunk_and_chunk_relative_position(); let (chunk_coordinate, relative) = position.chunk_and_chunk_relative_position();
let chunk = level.get_chunk(chunk_coordinate).await; let chunk = level.get_chunk(chunk_coordinate).await;
let section_index = (relative.y - chunk.section.min_y) as usize / BlockPalette::SIZE; let section_index = (relative.y - chunk.section.min_y) as usize / BlockPalette::SIZE;
// Bounds check for section index (lock the light engine)
let light_engine = chunk.light_engine.lock().unwrap(); let light_engine = chunk.light_engine.lock().unwrap();
// Bounds check for section index (lock the light engine)
if section_index >= light_engine.sky_light.len() { if section_index >= light_engine.sky_light.len() {
return None; return 15;
} }
Some(light_engine.sky_light[section_index].get(
light_engine.sky_light[section_index].get(
relative.x as usize, relative.x as usize,
(relative.y - chunk.section.min_y) as usize % BlockPalette::SIZE, (relative.y - chunk.section.min_y) as usize % BlockPalette::SIZE,
relative.z as usize, relative.z as usize,
)) )
} }
pub async fn set_sky_light_level( pub async fn set_sky_light_level(

View File

@ -5,6 +5,7 @@ use pumpkin_util::{
math::position::BlockPos, math::position::BlockPos,
resource_location::{FromResourceLocation, ResourceLocation, ToResourceLocation}, resource_location::{FromResourceLocation, ResourceLocation, ToResourceLocation},
}; };
use serde::de::Error;
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub mod scheduler; pub mod scheduler;
@ -134,23 +135,36 @@ where
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
NbtCompound::deserialize(deserializer).map(|nbt| { let nbt = NbtCompound::deserialize(deserializer)?;
let x = nbt.get_int("x").unwrap();
let y = nbt.get_int("y").unwrap();
let z = nbt.get_int("z").unwrap();
let delay = nbt.get_int("t").unwrap() as u8;
let priority = TickPriority::try_from(nbt.get_int("p").unwrap()).unwrap();
let value = T::from_resource_location(
&ResourceLocation::from_str(nbt.get_string("i").unwrap()).unwrap(),
)
.unwrap();
Self { let get_int = |key| nbt.get_int(key).ok_or_else(|| D::Error::missing_field(key));
delay, let get_str = |key| {
priority, nbt.get_string(key)
position: BlockPos::new(x, y, z), .ok_or_else(|| D::Error::missing_field(key))
value, };
}
let x = get_int("x")?;
let y = get_int("y")?;
let z = get_int("z")?;
let delay = get_int("t")? as u8;
let priority = TickPriority::try_from(get_int("p")?)
.map_err(|_| D::Error::custom("Invalid tick priority"))?;
let res_loc_str = get_str("i")?;
let res_loc = ResourceLocation::from_str(res_loc_str).map_err(|e| {
D::Error::custom(format!("Invalid ResourceLocation '{res_loc_str}': {e}"))
})?;
let value = T::from_resource_location(&res_loc)
.ok_or_else(|| D::Error::custom(format!("Unknown tick type: {res_loc_str}")))?;
Ok(Self {
delay,
priority,
position: BlockPos::new(x, y, z),
value,
}) })
} }
} }

View File

@ -11,7 +11,7 @@ pub mod anvil;
// Constraint: disk biome palette serialization changed in 1.21.5 // Constraint: disk biome palette serialization changed in 1.21.5
pub const MINIMUM_SUPPORTED_WORLD_DATA_VERSION: i32 = 4435; // 1.21.9 pub const MINIMUM_SUPPORTED_WORLD_DATA_VERSION: i32 = 4435; // 1.21.9
pub const MAXIMUM_SUPPORTED_WORLD_DATA_VERSION: i32 = 4786; // 26.1 pub const MAXIMUM_SUPPORTED_WORLD_DATA_VERSION: i32 = 4790; // 26.1.2
pub const MINIMUM_SUPPORTED_LEVEL_VERSION: i32 = 19132; // 1.21.9 pub const MINIMUM_SUPPORTED_LEVEL_VERSION: i32 = 19132; // 1.21.9
pub const MAXIMUM_SUPPORTED_LEVEL_VERSION: i32 = 19133; // 1.21.9 pub const MAXIMUM_SUPPORTED_LEVEL_VERSION: i32 = 19133; // 1.21.9

View File

@ -79,7 +79,6 @@ base64.workspace = true
tracing.workspace = true tracing.workspace = true
tracing-subscriber.workspace = true tracing-subscriber.workspace = true
chrono.workspace = true
time = { workspace = true, features = ["parsing", "macros", "local-offset"] } time = { workspace = true, features = ["parsing", "macros", "local-offset"] }
# plugins # plugins

View File

@ -174,7 +174,7 @@ pub async fn send_c_commands_packet(
root_node.children = first.into_boxed_slice(); root_node.children = first.into_boxed_slice();
} }
let packet = CCommands::new(proto_nodes.into(), root_node_index.try_into().unwrap()); let packet = CCommands::new(proto_nodes.into(), VarInt(root_node_index as i32));
player.client.enqueue_packet(&packet).await; player.client.enqueue_packet(&packet).await;
} }
@ -207,15 +207,19 @@ struct ProtoNodeBuilder<'a> {
impl<'a> ProtoNodeBuilder<'a> { impl<'a> ProtoNodeBuilder<'a> {
fn build(self, buffer: &mut Vec<ProtoNode<'a>>) -> usize { fn build(self, buffer: &mut Vec<ProtoNode<'a>>) -> usize {
let mut children = Vec::with_capacity(self.child_nodes.len()); let children: Box<[VarInt]> = self
for node in self.child_nodes { .child_nodes
let i = node.build(buffer); .into_iter()
children.push(i.try_into().unwrap()); .map(|node| {
} node.build(buffer)
.try_into()
.expect("Buffer index exceeded i32 bounds")
})
.collect();
let i = buffer.len(); let i = buffer.len();
buffer.push(ProtoNode { buffer.push(ProtoNode {
children: children.into(), children,
node_type: self.node_type, node_type: self.node_type,
}); });
i i

View File

@ -17,7 +17,6 @@ use crate::world::custom_bossbar::BossbarUpdateError;
use pumpkin_data::translation; use pumpkin_data::translation;
use pumpkin_util::text::TextComponent; use pumpkin_util::text::TextComponent;
use pumpkin_util::text::hover::HoverEvent; use pumpkin_util::text::hover::HoverEvent;
use std::fmt::Write as _;
use uuid::Uuid; use uuid::Uuid;
const NAMES: [&str; 1] = ["bossbar"]; const NAMES: [&str; 1] = ["bossbar"];
@ -642,12 +641,10 @@ fn handle_bossbar_error(error: BossbarUpdateError) -> CommandError {
)) ))
} }
BossbarUpdateError::NoChanges(value, variation) => { BossbarUpdateError::NoChanges(value, variation) => {
let mut key = "commands.bossbar.set.".to_string(); let key = variation.map_or_else(
key.push_str(value); || format!("commands.bossbar.set.{value}.unchanged"),
key.push_str(".unchanged"); |var| format!("commands.bossbar.set.{value}.unchanged.{var}"),
if let Some(variation) = variation { );
write!(key, ".{variation}").unwrap();
}
CommandError::CommandFailed(TextComponent::translate(key, [])) CommandError::CommandFailed(TextComponent::translate(key, []))
} }

View File

@ -41,161 +41,85 @@ enum ExpType {
struct Executor { struct Executor {
mode: Mode, mode: Mode,
exp_type: Option<ExpType>, exp_type: ExpType,
} }
impl Executor { impl Executor {
async fn handle_query( async fn handle_query(&self, sender: &CommandSender, target: &Player) -> i32 {
&self, let (val, translation_key) = match self.exp_type {
sender: &CommandSender, ExpType::Levels => (
target: &Player, target.experience_level.load(Ordering::Relaxed),
exp_type: ExpType, "commands.experience.query.levels",
) -> i32 { ),
match exp_type { ExpType::Points => (
ExpType::Levels => { target.experience_points.load(Ordering::Relaxed),
let level = target.experience_level.load(Ordering::Relaxed); "commands.experience.query.points",
sender ),
.send_message(TextComponent::translate( };
"commands.experience.query.levels",
[ sender
target.get_display_name().await, .send_message(TextComponent::translate(
TextComponent::text(level.to_string()), translation_key,
], [
)) target.get_display_name().await,
.await; TextComponent::text(val.to_string()),
level ],
} ))
ExpType::Points => { .await;
let points = target.experience_points.load(Ordering::Relaxed);
sender val
.send_message(TextComponent::translate(
"commands.experience.query.points",
[
target.get_display_name().await,
TextComponent::text(points.to_string()),
],
))
.await;
points
}
}
} }
fn get_success_message( fn get_success_message(
mode: Mode, &self,
exp_type: ExpType,
amount: i32, amount: i32,
targets_len: usize, targets: &[Arc<Player>],
target_name: Option<TextComponent>, first_target_name: TextComponent,
) -> TextComponent { ) -> TextComponent {
match (mode, exp_type) { let type_str = match self.exp_type {
(Mode::Add, ExpType::Points) => { ExpType::Points => "points",
if targets_len > 1 { ExpType::Levels => "levels",
TextComponent::translate( };
"commands.experience.add.points.success.multiple", let mode_str = match self.mode {
[ Mode::Add => "add",
TextComponent::text(amount.to_string()), Mode::Set => "set",
TextComponent::text(targets_len.to_string()), Mode::Query => "query",
], };
)
} else { if targets.len() > 1 {
TextComponent::translate( TextComponent::translate(
"commands.experience.add.points.success.single", format!("commands.experience.{mode_str}.{type_str}.success.multiple"),
[ [
TextComponent::text(amount.to_string()), TextComponent::text(amount.to_string()),
target_name.unwrap(), TextComponent::text(targets.len().to_string()),
], ],
) )
} } else {
} TextComponent::translate(
(Mode::Add, ExpType::Levels) => { format!("commands.experience.{mode_str}.{type_str}.success.single"),
if targets_len > 1 { [TextComponent::text(amount.to_string()), first_target_name],
TextComponent::translate( )
"commands.experience.add.levels.success.multiple",
[
TextComponent::text(amount.to_string()),
TextComponent::text(targets_len.to_string()),
],
)
} else {
TextComponent::translate(
"commands.experience.add.levels.success.single",
[
TextComponent::text(amount.to_string()),
target_name.unwrap(),
],
)
}
}
(Mode::Set, ExpType::Points) => {
if targets_len > 1 {
TextComponent::translate(
"commands.experience.set.points.success.multiple",
[
TextComponent::text(amount.to_string()),
TextComponent::text(targets_len.to_string()),
],
)
} else {
TextComponent::translate(
"commands.experience.set.points.success.single",
[
TextComponent::text(amount.to_string()),
target_name.unwrap(),
],
)
}
}
(Mode::Set, ExpType::Levels) => {
if targets_len > 1 {
TextComponent::translate(
"commands.experience.set.levels.success.multiple",
[
TextComponent::text(amount.to_string()),
TextComponent::text(targets_len.to_string()),
],
)
} else {
TextComponent::translate(
"commands.experience.set.levels.success.single",
[
TextComponent::text(amount.to_string()),
target_name.unwrap(),
],
)
}
}
(Mode::Query, _) => unreachable!("Query mode doesn't use success messages"),
} }
} }
/// Returns `true` if successful. Otherwise, there was a problem setting the points of a player. /// Returns `true` if successful. Otherwise, there was a problem setting the points of a player.
async fn handle_modify( async fn handle_modify(&self, target: &Arc<Player>, amount: i32) -> bool {
&self, match self.exp_type {
target: &Arc<Player>,
amount: i32,
exp_type: ExpType,
mode: Mode,
) -> bool {
match exp_type {
ExpType::Levels => { ExpType::Levels => {
if mode == Mode::Add { if self.mode == Mode::Add {
target.add_experience_levels(amount).await; target.add_experience_levels(amount).await;
} else { } else {
target.set_experience_level(amount, true).await; target.set_experience_level(amount, true).await;
} }
} }
ExpType::Points => { ExpType::Points => {
if mode == Mode::Add { if self.mode == Mode::Add {
target.add_experience_points(amount).await; target.add_experience_points(amount).await;
} else { } else {
let current_level = target.experience_level.load(Ordering::Relaxed); let current_lvl = target.experience_level.load(Ordering::Relaxed);
let current_max_points = experience::points_in_level(current_level); if amount > experience::points_in_level(current_lvl) {
if amount > current_max_points {
return false; return false;
} }
target.set_experience_points(amount).await; target.set_experience_points(amount).await;
} }
} }
@ -214,72 +138,46 @@ impl CommandExecutor for Executor {
Box::pin(async move { Box::pin(async move {
let targets = PlayersArgumentConsumer::find_arg(args, ARG_TARGETS)?; let targets = PlayersArgumentConsumer::find_arg(args, ARG_TARGETS)?;
match self.mode { if self.mode == Mode::Query {
Mode::Query => { let target = targets.first().ok_or_else(|| {
if targets.len() != 1 { CommandError::CommandFailed(TextComponent::translate(
// TODO: Add proper error message for multiple players in query mode during parsing itself and not here "argument.player.unknown",
return Err(CommandError::CommandFailed(TextComponent::translate( [],
"argument.player.toomany", ))
[], })?;
)));
} if targets.len() > 1 {
Ok(self return Err(CommandError::CommandFailed(TextComponent::translate(
.handle_query(sender, &targets[0], self.exp_type.unwrap()) "argument.player.toomany",
.await) [],
)));
} }
Mode::Add | Mode::Set => { return Ok(self.handle_query(sender, target).await);
let Ok(amount) = BoundedNumArgumentConsumer::<i32>::find_arg(args, ARG_AMOUNT)? }
else {
return Err(CommandError::CommandFailed(TextComponent::translate(
"commands.experience.set.points.invalid",
[],
)));
};
if self.mode == Mode::Set && amount < 0 { // Handle Add/Set
return Err(CommandError::CommandFailed(TextComponent::translate( let amount = BoundedNumArgumentConsumer::<i32>::find_arg(args, ARG_AMOUNT)??;
"commands.experience.set.points.invalid",
[],
)));
}
let mut successes: i32 = 0; let mut successes = 0;
for target in targets { for target in targets {
let succeeded = self if self.handle_modify(target, amount).await {
.handle_modify(target, amount, self.exp_type.unwrap(), self.mode) successes += 1;
.await;
if succeeded {
successes += 1;
}
}
if successes == 0 {
Err(CommandError::CommandFailed(TextComponent::translate(
"commands.experience.set.points.invalid",
[],
)))
} else {
// This should not panic as we already check the number of successes to not be equal to `0`.
let target = targets
.first()
.expect("expected at least one player in targets")
.get_display_name()
.await;
let msg = Self::get_success_message(
self.mode,
self.exp_type.unwrap(),
amount,
targets.len(),
Some(target),
);
sender.send_message(msg).await;
Ok(successes)
}
} }
} }
if successes == 0 {
return Err(CommandError::CommandFailed(TextComponent::translate(
"commands.experience.set.points.invalid",
[],
)));
}
// Safe to access first() because successes > 0
let first_name = targets[0].get_display_name().await;
let msg = self.get_success_message(amount, targets, first_name);
sender.send_message(msg).await;
Ok(successes)
}) })
} }
} }
@ -292,15 +190,15 @@ pub fn init_command_tree() -> CommandTree {
argument(ARG_AMOUNT, xp_amount()) argument(ARG_AMOUNT, xp_amount())
.then(literal("levels").execute(Executor { .then(literal("levels").execute(Executor {
mode: Mode::Add, mode: Mode::Add,
exp_type: Some(ExpType::Levels), exp_type: ExpType::Levels,
})) }))
.then(literal("points").execute(Executor { .then(literal("points").execute(Executor {
mode: Mode::Add, mode: Mode::Add,
exp_type: Some(ExpType::Points), exp_type: ExpType::Points,
})) }))
.execute(Executor { .execute(Executor {
mode: Mode::Add, mode: Mode::Add,
exp_type: Some(ExpType::Points), exp_type: ExpType::Points,
}), }),
), ),
), ),
@ -311,15 +209,15 @@ pub fn init_command_tree() -> CommandTree {
argument(ARG_AMOUNT, xp_amount()) argument(ARG_AMOUNT, xp_amount())
.then(literal("levels").execute(Executor { .then(literal("levels").execute(Executor {
mode: Mode::Set, mode: Mode::Set,
exp_type: Some(ExpType::Levels), exp_type: ExpType::Levels,
})) }))
.then(literal("points").execute(Executor { .then(literal("points").execute(Executor {
mode: Mode::Set, mode: Mode::Set,
exp_type: Some(ExpType::Points), exp_type: ExpType::Points,
})) }))
.execute(Executor { .execute(Executor {
mode: Mode::Set, mode: Mode::Set,
exp_type: Some(ExpType::Points), exp_type: ExpType::Points,
}), }),
), ),
), ),
@ -329,11 +227,11 @@ pub fn init_command_tree() -> CommandTree {
argument(ARG_TARGETS, PlayersArgumentConsumer) argument(ARG_TARGETS, PlayersArgumentConsumer)
.then(literal("levels").execute(Executor { .then(literal("levels").execute(Executor {
mode: Mode::Query, mode: Mode::Query,
exp_type: Some(ExpType::Levels), exp_type: ExpType::Levels,
})) }))
.then(literal("points").execute(Executor { .then(literal("points").execute(Executor {
mode: Mode::Query, mode: Mode::Query,
exp_type: Some(ExpType::Points), exp_type: ExpType::Points,
})), })),
), ),
) )

View File

@ -2,20 +2,20 @@ use std::cmp::Reverse;
use std::collections::HashMap; use std::collections::HashMap;
use std::{env, fs}; use std::{env, fs};
use chrono::{DateTime, FixedOffset, Local, Months, TimeDelta, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use time::format_description::well_known::Rfc3339;
use time::{Duration, OffsetDateTime};
use tracing::warn; use tracing::warn;
use uuid::Uuid; use uuid::Uuid;
const USER_CACHE_PATH: &str = "usercache.json"; const USER_CACHE_PATH: &str = "usercache.json";
const USER_CACHE_MRU_LIMIT: usize = 1000; const USER_CACHE_MRU_LIMIT: usize = 1000;
const USER_CACHE_DATE_FORMAT: &str = "%Y-%m-%d %H:%M:%S %z";
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct UserCacheEntry { pub struct UserCacheEntry {
pub uuid: Uuid, pub uuid: Uuid,
pub name: String, pub name: String,
expiration_date: DateTime<FixedOffset>, expiration_date: OffsetDateTime,
last_access: u64, last_access: u64,
} }
@ -192,8 +192,8 @@ impl UserCache {
let Ok(uuid) = Uuid::parse_str(uuid_raw) else { let Ok(uuid) = Uuid::parse_str(uuid_raw) else {
continue; continue;
}; };
let Ok(expiration_date) = DateTime::parse_from_str(expires_on, USER_CACHE_DATE_FORMAT)
else { let Ok(expiration_date) = OffsetDateTime::parse(expires_on, &Rfc3339) else {
continue; continue;
}; };
@ -209,16 +209,14 @@ impl UserCache {
} }
} }
fn format_cache_date(date: DateTime<FixedOffset>) -> String { fn format_cache_date(date: OffsetDateTime) -> String {
date.format(USER_CACHE_DATE_FORMAT).to_string() date.format(&Rfc3339).unwrap_or_default()
} }
fn is_expired(expiration_date: DateTime<FixedOffset>) -> bool { fn is_expired(expiration_date: OffsetDateTime) -> bool {
Utc::now() >= expiration_date.with_timezone(&Utc) OffsetDateTime::now_utc() >= expiration_date
} }
fn one_month_from_now() -> DateTime<FixedOffset> { fn one_month_from_now() -> OffsetDateTime {
let now = Local::now().fixed_offset(); OffsetDateTime::now_utc() + Duration::days(30)
now.checked_add_months(Months::new(1))
.unwrap_or(now + TimeDelta::days(30))
} }

View File

@ -561,8 +561,7 @@ pub trait SunSensitive: Mob + Send + Sync {
.level .level
.light_engine .light_engine
.get_sky_light_level(&world.level, &pos.to_block_pos()) .get_sky_light_level(&world.level, &pos.to_block_pos())
.await .await as f32
.unwrap_or(0) as f32
/ 15.0; / 15.0;
if brightness < 0.5 { if brightness < 0.5 {

View File

@ -106,7 +106,7 @@ use pumpkin_world::chunk_system::ChunkLoading;
const MAX_CACHED_SIGNATURES: u8 = 128; // Vanilla: 128 const MAX_CACHED_SIGNATURES: u8 = 128; // Vanilla: 128
const MAX_PREVIOUS_MESSAGES: u8 = 20; // Vanilla: 20 const MAX_PREVIOUS_MESSAGES: u8 = 20; // Vanilla: 20
pub const DATA_VERSION: i32 = 4786; // 26.1 pub const DATA_VERSION: i32 = 4790; // 26.1.2
enum BatchState { enum BatchState {
Count(u8), Count(u8),

View File

@ -449,6 +449,13 @@ impl BedrockClient {
vec vec
}); });
if fragment_index >= entry.len() {
return Err(Error::other(format!(
"Fragment index {fragment_index} out of bounds for size {}",
entry.len()
)));
}
entry[fragment_index] = Some(frame); entry[fragment_index] = Some(frame);
// Check if all fragments are received // Check if all fragments are received
@ -456,21 +463,21 @@ impl BedrockClient {
return Ok(()); return Ok(());
} }
let mut frames = compounds.remove(&compound_id).unwrap(); let mut frames_opt = compounds
.remove(&compound_id)
.ok_or_else(|| Error::other("Compound ID vanished"))?;
// Safety: We already checked that all frames are Some at this point let total_len: usize = frames_opt.iter().flatten().map(|f| f.payload.len()).sum();
let len = frames
.iter()
.map(|frame| unsafe { frame.as_ref().unwrap_unchecked().payload.len() })
.sum();
let mut merged = Vec::with_capacity(len); let mut merged = Vec::with_capacity(total_len);
for frame in &frames { for f in frames_opt.iter().flatten() {
merged.extend_from_slice(unsafe { &frame.as_ref().unwrap_unchecked().payload }); merged.extend_from_slice(&f.payload);
} }
frame = unsafe { frames[0].take().unwrap_unchecked() }; frame = frames_opt[0]
.take()
.ok_or_else(|| Error::other("Failed to retrieve primary frame"))?;
frame.payload = merged; frame.payload = merged;
frame.split_size = 0; frame.split_size = 0;
@ -504,7 +511,8 @@ impl BedrockClient {
.await; .await;
} }
_ => { _ => {
self.handle_play_packet(self.player.lock().await.as_ref().unwrap(), server, packet) return self
.handle_play_packet(self.player.lock().await.as_ref().unwrap(), server, packet)
.await; .await;
} }
} }
@ -516,46 +524,43 @@ impl BedrockClient {
player: &Arc<Player>, player: &Arc<Player>,
server: &Arc<Server>, server: &Arc<Server>,
packet: RawPacket, packet: RawPacket,
) { ) -> Result<(), Error> {
let reader = &mut &packet.payload[..]; let reader = &mut &packet.payload[..];
match packet.id { match packet.id {
SPlayerAuthInput::PACKET_ID => { SPlayerAuthInput::PACKET_ID => {
if let Ok(input_packet) = SPlayerAuthInput::read(reader) { self.player_pos_update(player, SPlayerAuthInput::read(reader)?, server)
self.player_pos_update(player, input_packet, server).await; .await;
}
} }
SLoadingScreen::PACKET_ID => { SLoadingScreen::PACKET_ID => {
if SLoadingScreen::read(reader).unwrap().is_loading_done() { if SLoadingScreen::read(reader)?.is_loading_done() {
player.set_client_loaded(true); player.set_client_loaded(true);
} }
} }
SRequestChunkRadius::PACKET_ID => { SRequestChunkRadius::PACKET_ID => {
self.handle_request_chunk_radius( self.handle_request_chunk_radius(player, SRequestChunkRadius::read(reader)?)
player, .await;
SRequestChunkRadius::read(reader).unwrap(),
)
.await;
} }
SInteraction::PACKET_ID => { SInteraction::PACKET_ID => {
self.handle_interaction(player, SInteraction::read(reader).unwrap()) self.handle_interaction(player, SInteraction::read(reader)?)
.await; .await;
} }
SContainerClose::PACKET_ID => { SContainerClose::PACKET_ID => {
self.handle_container_close(player, SContainerClose::read(reader).unwrap()) self.handle_container_close(player, SContainerClose::read(reader)?)
.await; .await;
} }
SText::PACKET_ID => { SText::PACKET_ID => {
self.handle_chat_message(server, player, SText::read(reader).unwrap()) self.handle_chat_message(server, player, SText::read(reader)?)
.await; .await;
} }
SCommandRequest::PACKET_ID => { SCommandRequest::PACKET_ID => {
self.handle_chat_command(player, server, SCommandRequest::read(reader).unwrap()) self.handle_chat_command(player, server, SCommandRequest::read(reader)?)
.await; .await;
} }
_ => { _ => {
warn!("Bedrock: Received Unknown Game packet: {}", packet.id); warn!("Bedrock: Received Unknown Game packet: {}", packet.id);
} }
} }
Ok(())
} }
async fn handle_raknet_packet( async fn handle_raknet_packet(