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",
]
[[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]]
name = "ciborium"
version = "0.2.2"
@ -463,9 +450,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.6.0"
version = "4.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351"
checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51"
dependencies = [
"clap_builder",
]
@ -2840,7 +2827,6 @@ dependencies = [
"base64 0.22.1",
"bitflags 2.11.1",
"bytes",
"chrono",
"console-subscriber",
"crossbeam",
"flate2",
@ -4326,9 +4312,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
version = "1.23.0"
version = "1.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9"
checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76"
dependencies = [
"getrandom 0.4.2",
"js-sys",
@ -4894,9 +4880,9 @@ dependencies = [
[[package]]
name = "webpki-roots"
version = "1.0.6"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed"
checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d"
dependencies = [
"rustls-pki-types",
]

View File

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

View File

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

View File

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

View File

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

View File

@ -35,3 +35,17 @@ path = "fuzz_targets/decoder_bedrock.rs"
test = false
doc = 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);
self.payload_scratch.clear();
self.payload_scratch.reserve(payload_len_hint);
loop {
let mut total_read = 0;
while total_read < payload_len_hint {
let bytes_read = reader
.read_buf(&mut self.payload_scratch)
.await
@ -165,6 +167,7 @@ impl<R: AsyncRead + Unpin> TCPNetworkDecoder<R> {
if bytes_read == 0 {
break;
}
total_read += bytes_read;
}
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
.light_engine
.get_sky_light_level(level, block_pos)
.await
.unwrap();
.await;
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)
const SECTOR_BYTES: usize = 4096;
// 26.1
pub const WORLD_DATA_VERSION: i32 = 4786;
// 26.1.2
pub const WORLD_DATA_VERSION: i32 = 4790;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]

View File

@ -136,18 +136,18 @@ impl DynamicLightEngine {
let new_light = light_level.saturating_sub(opacity);
// Only propagate if new light is brighter than current light
if new_light > neighbor_light {
self.set_block_light_level(level, &neighbor_pos, new_light)
if new_light > neighbor_light
&& self
.set_block_light_level(level, &neighbor_pos, new_light)
.await
.unwrap();
if new_light > 1 {
.is_ok()
&& new_light > 1
{
self.queue_block_light_increase(neighbor_pos, new_light);
}
}
}
}
}
async fn propagate_block_light_decrease(
&self,
@ -301,13 +301,12 @@ impl DynamicLightEngine {
for dir in BlockDirection::all() {
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 opacity = neighbor_state.opacity;
// 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
15
} else {
@ -327,7 +326,6 @@ impl DynamicLightEngine {
}
}
}
}
async fn propagate_sky_light_decrease(
&self,
@ -338,7 +336,7 @@ impl DynamicLightEngine {
for dir in BlockDirection::all() {
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 {
continue; // Already dark
}
@ -347,8 +345,7 @@ impl DynamicLightEngine {
let opacity = neighbor_state.opacity;
// 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
} else {
removed_light.saturating_sub(1).saturating_sub(opacity)
@ -367,7 +364,6 @@ impl DynamicLightEngine {
}
}
}
}
pub async fn check_sky_light_updates(&self, level: &Arc<Level>, pos: BlockPos) {
match level.lighting_config {
@ -382,7 +378,7 @@ impl DynamicLightEngine {
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 opacity = block_state.opacity;
@ -404,9 +400,7 @@ impl DynamicLightEngine {
for dir in BlockDirection::all() {
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;
// Calculate potential light from this neighbor
let potential = if neighbor_light == 15 && dir == BlockDirection::Up {
// Sky light at 15 from above stays 15
@ -418,7 +412,6 @@ impl DynamicLightEngine {
best_light = best_light.max(potential);
}
}
// Apply opacity to the best incoming light
best_light.saturating_sub(opacity)
@ -459,20 +452,22 @@ impl DynamicLightEngine {
level: &Arc<Level>,
position: &BlockPos,
) -> Option<u8> {
let (chunk_coordinate, relative) = position.chunk_and_chunk_relative_position();
let chunk = level.get_chunk(chunk_coordinate).await;
let (chunk_pos, relative) = position.chunk_and_chunk_relative_position();
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();
if section_index >= light_engine.block_light.len() {
return None;
}
Some(light_engine.block_light[section_index].get(
let chunk = level.get_chunk(chunk_pos).await;
let section_idx = (relative.y - chunk.section.min_y) as usize / 16;
let light_engine = chunk.light_engine.lock().ok()?;
light_engine
.block_light
.get(section_idx)?
.get(
relative.x as usize,
(relative.y - chunk.section.min_y) as usize % BlockPalette::SIZE,
(relative.y - chunk.section.min_y) as usize % 16,
relative.z as usize,
))
)
.into()
}
pub async fn set_block_light_level(
@ -503,20 +498,22 @@ impl DynamicLightEngine {
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 = level.get_chunk(chunk_coordinate).await;
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();
// Bounds check for section index (lock the light engine)
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.y - chunk.section.min_y) as usize % BlockPalette::SIZE,
relative.z as usize,
))
)
}
pub async fn set_sky_light_level(

View File

@ -5,6 +5,7 @@ use pumpkin_util::{
math::position::BlockPos,
resource_location::{FromResourceLocation, ResourceLocation, ToResourceLocation},
};
use serde::de::Error;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub mod scheduler;
@ -134,23 +135,36 @@ where
where
D: Deserializer<'de>,
{
NbtCompound::deserialize(deserializer).map(|nbt| {
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();
let nbt = NbtCompound::deserialize(deserializer)?;
Self {
let get_int = |key| nbt.get_int(key).ok_or_else(|| D::Error::missing_field(key));
let get_str = |key| {
nbt.get_string(key)
.ok_or_else(|| D::Error::missing_field(key))
};
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
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 MAXIMUM_SUPPORTED_LEVEL_VERSION: i32 = 19133; // 1.21.9

View File

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

View File

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

View File

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

View File

@ -41,161 +41,85 @@ enum ExpType {
struct Executor {
mode: Mode,
exp_type: Option<ExpType>,
exp_type: ExpType,
}
impl Executor {
async fn handle_query(
&self,
sender: &CommandSender,
target: &Player,
exp_type: ExpType,
) -> i32 {
match exp_type {
ExpType::Levels => {
let level = target.experience_level.load(Ordering::Relaxed);
sender
.send_message(TextComponent::translate(
async fn handle_query(&self, sender: &CommandSender, target: &Player) -> i32 {
let (val, translation_key) = match self.exp_type {
ExpType::Levels => (
target.experience_level.load(Ordering::Relaxed),
"commands.experience.query.levels",
[
target.get_display_name().await,
TextComponent::text(level.to_string()),
],
))
.await;
level
}
ExpType::Points => {
let points = target.experience_points.load(Ordering::Relaxed);
),
ExpType::Points => (
target.experience_points.load(Ordering::Relaxed),
"commands.experience.query.points",
),
};
sender
.send_message(TextComponent::translate(
"commands.experience.query.points",
translation_key,
[
target.get_display_name().await,
TextComponent::text(points.to_string()),
TextComponent::text(val.to_string()),
],
))
.await;
points
}
}
val
}
fn get_success_message(
mode: Mode,
exp_type: ExpType,
&self,
amount: i32,
targets_len: usize,
target_name: Option<TextComponent>,
targets: &[Arc<Player>],
first_target_name: TextComponent,
) -> TextComponent {
match (mode, exp_type) {
(Mode::Add, ExpType::Points) => {
if targets_len > 1 {
let type_str = match self.exp_type {
ExpType::Points => "points",
ExpType::Levels => "levels",
};
let mode_str = match self.mode {
Mode::Add => "add",
Mode::Set => "set",
Mode::Query => "query",
};
if targets.len() > 1 {
TextComponent::translate(
"commands.experience.add.points.success.multiple",
format!("commands.experience.{mode_str}.{type_str}.success.multiple"),
[
TextComponent::text(amount.to_string()),
TextComponent::text(targets_len.to_string()),
TextComponent::text(targets.len().to_string()),
],
)
} else {
TextComponent::translate(
"commands.experience.add.points.success.single",
[
TextComponent::text(amount.to_string()),
target_name.unwrap(),
],
format!("commands.experience.{mode_str}.{type_str}.success.single"),
[TextComponent::text(amount.to_string()), first_target_name],
)
}
}
(Mode::Add, ExpType::Levels) => {
if targets_len > 1 {
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.
async fn handle_modify(
&self,
target: &Arc<Player>,
amount: i32,
exp_type: ExpType,
mode: Mode,
) -> bool {
match exp_type {
async fn handle_modify(&self, target: &Arc<Player>, amount: i32) -> bool {
match self.exp_type {
ExpType::Levels => {
if mode == Mode::Add {
if self.mode == Mode::Add {
target.add_experience_levels(amount).await;
} else {
target.set_experience_level(amount, true).await;
}
}
ExpType::Points => {
if mode == Mode::Add {
if self.mode == Mode::Add {
target.add_experience_points(amount).await;
} else {
let current_level = target.experience_level.load(Ordering::Relaxed);
let current_max_points = experience::points_in_level(current_level);
if amount > current_max_points {
let current_lvl = target.experience_level.load(Ordering::Relaxed);
if amount > experience::points_in_level(current_lvl) {
return false;
}
target.set_experience_points(amount).await;
}
}
@ -214,72 +138,46 @@ impl CommandExecutor for Executor {
Box::pin(async move {
let targets = PlayersArgumentConsumer::find_arg(args, ARG_TARGETS)?;
match self.mode {
Mode::Query => {
if targets.len() != 1 {
// TODO: Add proper error message for multiple players in query mode during parsing itself and not here
if self.mode == Mode::Query {
let target = targets.first().ok_or_else(|| {
CommandError::CommandFailed(TextComponent::translate(
"argument.player.unknown",
[],
))
})?;
if targets.len() > 1 {
return Err(CommandError::CommandFailed(TextComponent::translate(
"argument.player.toomany",
[],
)));
}
Ok(self
.handle_query(sender, &targets[0], self.exp_type.unwrap())
.await)
}
Mode::Add | Mode::Set => {
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 {
return Err(CommandError::CommandFailed(TextComponent::translate(
"commands.experience.set.points.invalid",
[],
)));
return Ok(self.handle_query(sender, target).await);
}
let mut successes: i32 = 0;
// Handle Add/Set
let amount = BoundedNumArgumentConsumer::<i32>::find_arg(args, ARG_AMOUNT)??;
let mut successes = 0;
for target in targets {
let succeeded = self
.handle_modify(target, amount, self.exp_type.unwrap(), self.mode)
.await;
if succeeded {
if self.handle_modify(target, amount).await {
successes += 1;
}
}
if successes == 0 {
Err(CommandError::CommandFailed(TextComponent::translate(
return 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),
);
// 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())
.then(literal("levels").execute(Executor {
mode: Mode::Add,
exp_type: Some(ExpType::Levels),
exp_type: ExpType::Levels,
}))
.then(literal("points").execute(Executor {
mode: Mode::Add,
exp_type: Some(ExpType::Points),
exp_type: ExpType::Points,
}))
.execute(Executor {
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())
.then(literal("levels").execute(Executor {
mode: Mode::Set,
exp_type: Some(ExpType::Levels),
exp_type: ExpType::Levels,
}))
.then(literal("points").execute(Executor {
mode: Mode::Set,
exp_type: Some(ExpType::Points),
exp_type: ExpType::Points,
}))
.execute(Executor {
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)
.then(literal("levels").execute(Executor {
mode: Mode::Query,
exp_type: Some(ExpType::Levels),
exp_type: ExpType::Levels,
}))
.then(literal("points").execute(Executor {
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::{env, fs};
use chrono::{DateTime, FixedOffset, Local, Months, TimeDelta, Utc};
use serde::{Deserialize, Serialize};
use time::format_description::well_known::Rfc3339;
use time::{Duration, OffsetDateTime};
use tracing::warn;
use uuid::Uuid;
const USER_CACHE_PATH: &str = "usercache.json";
const USER_CACHE_MRU_LIMIT: usize = 1000;
const USER_CACHE_DATE_FORMAT: &str = "%Y-%m-%d %H:%M:%S %z";
#[derive(Clone, Debug)]
pub struct UserCacheEntry {
pub uuid: Uuid,
pub name: String,
expiration_date: DateTime<FixedOffset>,
expiration_date: OffsetDateTime,
last_access: u64,
}
@ -192,8 +192,8 @@ impl UserCache {
let Ok(uuid) = Uuid::parse_str(uuid_raw) else {
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;
};
@ -209,16 +209,14 @@ impl UserCache {
}
}
fn format_cache_date(date: DateTime<FixedOffset>) -> String {
date.format(USER_CACHE_DATE_FORMAT).to_string()
fn format_cache_date(date: OffsetDateTime) -> String {
date.format(&Rfc3339).unwrap_or_default()
}
fn is_expired(expiration_date: DateTime<FixedOffset>) -> bool {
Utc::now() >= expiration_date.with_timezone(&Utc)
fn is_expired(expiration_date: OffsetDateTime) -> bool {
OffsetDateTime::now_utc() >= expiration_date
}
fn one_month_from_now() -> DateTime<FixedOffset> {
let now = Local::now().fixed_offset();
now.checked_add_months(Months::new(1))
.unwrap_or(now + TimeDelta::days(30))
fn one_month_from_now() -> OffsetDateTime {
OffsetDateTime::now_utc() + Duration::days(30)
}

View File

@ -561,8 +561,7 @@ pub trait SunSensitive: Mob + Send + Sync {
.level
.light_engine
.get_sky_light_level(&world.level, &pos.to_block_pos())
.await
.unwrap_or(0) as f32
.await as f32
/ 15.0;
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_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 {
Count(u8),

View File

@ -449,6 +449,13 @@ impl BedrockClient {
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);
// Check if all fragments are received
@ -456,21 +463,21 @@ impl BedrockClient {
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 len = frames
.iter()
.map(|frame| unsafe { frame.as_ref().unwrap_unchecked().payload.len() })
.sum();
let total_len: usize = frames_opt.iter().flatten().map(|f| f.payload.len()).sum();
let mut merged = Vec::with_capacity(len);
let mut merged = Vec::with_capacity(total_len);
for frame in &frames {
merged.extend_from_slice(unsafe { &frame.as_ref().unwrap_unchecked().payload });
for f in frames_opt.iter().flatten() {
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.split_size = 0;
@ -504,7 +511,8 @@ impl BedrockClient {
.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;
}
}
@ -516,46 +524,43 @@ impl BedrockClient {
player: &Arc<Player>,
server: &Arc<Server>,
packet: RawPacket,
) {
) -> Result<(), Error> {
let reader = &mut &packet.payload[..];
match packet.id {
SPlayerAuthInput::PACKET_ID => {
if let Ok(input_packet) = SPlayerAuthInput::read(reader) {
self.player_pos_update(player, input_packet, server).await;
}
self.player_pos_update(player, SPlayerAuthInput::read(reader)?, server)
.await;
}
SLoadingScreen::PACKET_ID => {
if SLoadingScreen::read(reader).unwrap().is_loading_done() {
if SLoadingScreen::read(reader)?.is_loading_done() {
player.set_client_loaded(true);
}
}
SRequestChunkRadius::PACKET_ID => {
self.handle_request_chunk_radius(
player,
SRequestChunkRadius::read(reader).unwrap(),
)
self.handle_request_chunk_radius(player, SRequestChunkRadius::read(reader)?)
.await;
}
SInteraction::PACKET_ID => {
self.handle_interaction(player, SInteraction::read(reader).unwrap())
self.handle_interaction(player, SInteraction::read(reader)?)
.await;
}
SContainerClose::PACKET_ID => {
self.handle_container_close(player, SContainerClose::read(reader).unwrap())
self.handle_container_close(player, SContainerClose::read(reader)?)
.await;
}
SText::PACKET_ID => {
self.handle_chat_message(server, player, SText::read(reader).unwrap())
self.handle_chat_message(server, player, SText::read(reader)?)
.await;
}
SCommandRequest::PACKET_ID => {
self.handle_chat_command(player, server, SCommandRequest::read(reader).unwrap())
self.handle_chat_command(player, server, SCommandRequest::read(reader)?)
.await;
}
_ => {
warn!("Bedrock: Received Unknown Game packet: {}", packet.id);
}
}
Ok(())
}
async fn handle_raknet_packet(