fix: chunk leak
This commit is contained in:
parent
c13c515081
commit
a72531a7c2
283
Cargo.lock
generated
283
Cargo.lock
generated
@ -544,9 +544,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.4.2"
|
version = "1.4.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5d262e149917187838d5b42777c8253bcb64500067342904e7d429499a6f277e"
|
checksum = "509591b7bcd67f4ef775afad7662703b4935daaa6ec0e5605cfb1090b32a2b6d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"find-msvc-tools",
|
"find-msvc-tools",
|
||||||
"jobserver",
|
"jobserver",
|
||||||
@ -1602,9 +1602,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "error-code"
|
name = "error-code"
|
||||||
version = "3.3.2"
|
version = "3.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59"
|
checksum = "0b5343afd4a8365a643ac588dab4cf234a190c7f6c88c9f6dd6ffe00837661b7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "event-listener"
|
name = "event-listener"
|
||||||
@ -1675,9 +1675,9 @@ checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "find-msvc-tools"
|
name = "find-msvc-tools"
|
||||||
version = "0.1.10"
|
version = "0.1.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "26b73573e6edcd2af0cdf47bd6cb58f0b3839491263c314eaad1ccf24430e1de"
|
checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
@ -1732,9 +1732,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures"
|
name = "futures"
|
||||||
version = "0.3.33"
|
version = "0.3.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a88cf1f829d945f548cf8fec32c61b1f202b6d93b45848602fc02af4b12ad218"
|
checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
@ -1747,9 +1747,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-channel"
|
name = "futures-channel"
|
||||||
version = "0.3.33"
|
version = "0.3.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "262590f4fe6afeb0bc83be1daa64e52657fe185690a958af7f3ad0e92085c5ae"
|
checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
@ -1757,15 +1757,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-core"
|
name = "futures-core"
|
||||||
version = "0.3.33"
|
version = "0.3.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7"
|
checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-executor"
|
name = "futures-executor"
|
||||||
version = "0.3.33"
|
version = "0.3.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6754879cc9f2c66f88c6e5c35344bb0bdb0708b0352b1201815667c7eabc7458"
|
checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-task",
|
"futures-task",
|
||||||
@ -1774,38 +1774,38 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-io"
|
name = "futures-io"
|
||||||
version = "0.3.33"
|
version = "0.3.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4577ecaa3c4f96589d473f679a71b596316f6641bc350038b962a5daf0085d7a"
|
checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-macro"
|
name = "futures-macro"
|
||||||
version = "0.3.33"
|
version = "0.3.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2d6d3cde68c518367be28956066ddfef33813991b77a55005a69dae04bf3b10b"
|
checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.119",
|
"syn 3.0.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-sink"
|
name = "futures-sink"
|
||||||
version = "0.3.33"
|
version = "0.3.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e34418ac499d6305c2fb5ad0ed2f6ac998c5f8ca209b4510f7f94242c647e307"
|
checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-task"
|
name = "futures-task"
|
||||||
version = "0.3.33"
|
version = "0.3.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109"
|
checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-util"
|
name = "futures-util"
|
||||||
version = "0.3.33"
|
version = "0.3.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa"
|
checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
@ -1840,18 +1840,6 @@ dependencies = [
|
|||||||
"wasi",
|
"wasi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "getrandom"
|
|
||||||
version = "0.3.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"r-efi 5.3.0",
|
|
||||||
"wasip2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
@ -1860,7 +1848,7 @@ checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"r-efi 6.0.0",
|
"r-efi",
|
||||||
"rand_core 0.10.1",
|
"rand_core 0.10.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2058,9 +2046,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http-body-util"
|
name = "http-body-util"
|
||||||
version = "0.1.4"
|
version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e9f41fd6a08e4d4ec69df65976da761afd5ad5e58a9d4acb46bd1c953a9e3ff2"
|
checksum = "23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
@ -2155,9 +2143,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_collections"
|
name = "icu_collections"
|
||||||
version = "2.2.0"
|
version = "2.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c"
|
checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"potential_utf",
|
"potential_utf",
|
||||||
@ -2169,9 +2157,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_locale_core"
|
name = "icu_locale_core"
|
||||||
version = "2.2.0"
|
version = "2.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29"
|
checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"litemap",
|
"litemap",
|
||||||
@ -2182,9 +2170,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_normalizer"
|
name = "icu_normalizer"
|
||||||
version = "2.2.0"
|
version = "2.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4"
|
checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"icu_collections",
|
"icu_collections",
|
||||||
"icu_normalizer_data",
|
"icu_normalizer_data",
|
||||||
@ -2196,16 +2184,17 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_normalizer_data"
|
name = "icu_normalizer_data"
|
||||||
version = "2.2.0"
|
version = "2.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38"
|
checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_properties"
|
name = "icu_properties"
|
||||||
version = "2.2.0"
|
version = "2.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de"
|
checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"displaydoc",
|
||||||
"icu_collections",
|
"icu_collections",
|
||||||
"icu_locale_core",
|
"icu_locale_core",
|
||||||
"icu_properties_data",
|
"icu_properties_data",
|
||||||
@ -2216,15 +2205,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_properties_data"
|
name = "icu_properties_data"
|
||||||
version = "2.2.0"
|
version = "2.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14"
|
checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_provider"
|
name = "icu_provider"
|
||||||
version = "2.2.0"
|
version = "2.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421"
|
checksum = "92a7ed671a6aad807a8651a2e1782a6598fda9ce5185dd8158549e95a91c6428"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"icu_locale_core",
|
"icu_locale_core",
|
||||||
@ -2289,9 +2278,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "inotify"
|
name = "inotify"
|
||||||
version = "0.11.4"
|
version = "0.11.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "153be1941a183ec9ccd095ddbe17a8b8d435ef6c76e9e02451b933c3999af2c8"
|
checksum = "4cc00ea907cab49550b7da656f80ebb97be1b997d931fbcd28d39734e17ce592"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.13.1",
|
"bitflags 2.13.1",
|
||||||
"inotify-sys",
|
"inotify-sys",
|
||||||
@ -2470,9 +2459,9 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libredox"
|
name = "libredox"
|
||||||
version = "0.1.19"
|
version = "0.1.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2026a5056764a10b2bf5d56488cba40da507f5493a6a429340e2004d9ed085fa"
|
checksum = "28d0a00925a9f930d679b6789b721e3a7f9ed110f41b86d2497caa780c3a070a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@ -2485,9 +2474,9 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "litemap"
|
name = "litemap"
|
||||||
version = "0.8.2"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
|
checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "litrs"
|
name = "litrs"
|
||||||
@ -2773,9 +2762,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-integer"
|
name = "num-integer"
|
||||||
version = "0.1.46"
|
version = "0.1.47"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
@ -2993,9 +2982,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pest"
|
name = "pest"
|
||||||
version = "2.8.8"
|
version = "2.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7df728be843c7070fab6ab7c328c4e9e9d78e23bf749c0669c86ee7ebfa050a2"
|
checksum = "5a07a60cc7a4d00c91f95c685609d1d2f79050e6804b70ebedd7650f0b839bcf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
"ucd-trie",
|
"ucd-trie",
|
||||||
@ -3003,9 +2992,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pest_derive"
|
name = "pest_derive"
|
||||||
version = "2.8.8"
|
version = "2.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9e2dd6fc3b26b3462ee188aac870f5a41d398f1cd5e2408d16531bd71c9591fd"
|
checksum = "b3a83744a5c8455b8b3e0dc5031362780a347c878bdd11584d1a8984228cc88d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pest",
|
"pest",
|
||||||
"pest_generator",
|
"pest_generator",
|
||||||
@ -3013,9 +3002,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pest_generator"
|
name = "pest_generator"
|
||||||
version = "2.8.8"
|
version = "2.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a7a9205cfb6f596a9e8b689c0a15f9ceb7a1aafae7aaf788150ac65b29975b6"
|
checksum = "e0cd3451aa3de60d4b9a1e736885e4dea6b31617598026f12256ad566d63304a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pest",
|
"pest",
|
||||||
"pest_meta",
|
"pest_meta",
|
||||||
@ -3026,9 +3015,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pest_meta"
|
name = "pest_meta"
|
||||||
version = "2.8.8"
|
version = "2.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "85abd351c0de1e8384fc791a0737111a350394937e92b956b743dac12429f57c"
|
checksum = "e04d3a0849e241d7dfce834c83b1c5edc8622009e8dd51a12ba1927c32f05496"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pest",
|
"pest",
|
||||||
]
|
]
|
||||||
@ -3134,9 +3123,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pkg-config"
|
name = "pkg-config"
|
||||||
version = "0.3.33"
|
version = "0.3.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"
|
checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "png"
|
name = "png"
|
||||||
@ -3194,9 +3183,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "potential_utf"
|
name = "potential_utf"
|
||||||
version = "0.1.5"
|
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 = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564"
|
checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerovec",
|
"zerovec",
|
||||||
]
|
]
|
||||||
@ -3207,15 +3196,6 @@ version = "0.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ppv-lite86"
|
|
||||||
version = "0.2.21"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
|
||||||
dependencies = [
|
|
||||||
"zerocopy",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pretty_assertions"
|
name = "pretty_assertions"
|
||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
@ -3414,7 +3394,7 @@ dependencies = [
|
|||||||
"pumpkin-protocol",
|
"pumpkin-protocol",
|
||||||
"pumpkin-util",
|
"pumpkin-util",
|
||||||
"pumpkin-world",
|
"pumpkin-world",
|
||||||
"rand 0.10.2",
|
"rand",
|
||||||
"rayon",
|
"rayon",
|
||||||
"rsa",
|
"rsa",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
@ -3503,7 +3483,7 @@ dependencies = [
|
|||||||
"phf",
|
"phf",
|
||||||
"pumpkin-nbt",
|
"pumpkin-nbt",
|
||||||
"pumpkin-util",
|
"pumpkin-util",
|
||||||
"rand 0.10.2",
|
"rand",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3513,7 +3493,7 @@ version = "0.1.0-dev+26.2-26.40"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"colored",
|
"colored",
|
||||||
"rand 0.9.5",
|
"rand",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3525,7 +3505,7 @@ dependencies = [
|
|||||||
"pumpkin-protocol",
|
"pumpkin-protocol",
|
||||||
"pumpkin-util",
|
"pumpkin-util",
|
||||||
"pumpkin-world",
|
"pumpkin-world",
|
||||||
"rand 0.10.2",
|
"rand",
|
||||||
"thiserror 2.0.20",
|
"thiserror 2.0.20",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
@ -3566,7 +3546,7 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-serde-structured",
|
"tracing-serde-structured",
|
||||||
"wit-bindgen 0.60.0",
|
"wit-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3640,7 +3620,7 @@ dependencies = [
|
|||||||
"pumpkin-data",
|
"pumpkin-data",
|
||||||
"pumpkin-nbt",
|
"pumpkin-nbt",
|
||||||
"pumpkin-util",
|
"pumpkin-util",
|
||||||
"rand 0.10.2",
|
"rand",
|
||||||
"rayon",
|
"rayon",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"ruzstd",
|
"ruzstd",
|
||||||
@ -3686,12 +3666,6 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "r-efi"
|
|
||||||
version = "5.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "r-efi"
|
name = "r-efi"
|
||||||
version = "6.0.0"
|
version = "6.0.0"
|
||||||
@ -3707,16 +3681,6 @@ dependencies = [
|
|||||||
"ptr_meta",
|
"ptr_meta",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand"
|
|
||||||
version = "0.9.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41"
|
|
||||||
dependencies = [
|
|
||||||
"rand_chacha",
|
|
||||||
"rand_core 0.9.5",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.10.2"
|
version = "0.10.2"
|
||||||
@ -3728,16 +3692,6 @@ dependencies = [
|
|||||||
"rand_core 0.10.1",
|
"rand_core 0.10.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_chacha"
|
|
||||||
version = "0.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
|
||||||
dependencies = [
|
|
||||||
"ppv-lite86",
|
|
||||||
"rand_core 0.9.5",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_core"
|
name = "rand_core"
|
||||||
version = "0.6.4"
|
version = "0.6.4"
|
||||||
@ -3747,15 +3701,6 @@ dependencies = [
|
|||||||
"getrandom 0.2.17",
|
"getrandom 0.2.17",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_core"
|
|
||||||
version = "0.9.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom 0.3.4",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_core"
|
name = "rand_core"
|
||||||
version = "0.10.1"
|
version = "0.10.1"
|
||||||
@ -3960,7 +3905,7 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"hex",
|
"hex",
|
||||||
"log",
|
"log",
|
||||||
"rand 0.10.2",
|
"rand",
|
||||||
"rcgen",
|
"rcgen",
|
||||||
"ring",
|
"ring",
|
||||||
"rtc-datachannel",
|
"rtc-datachannel",
|
||||||
@ -4017,7 +3962,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"p256",
|
"p256",
|
||||||
"p384 0.13.1",
|
"p384 0.13.1",
|
||||||
"rand 0.10.2",
|
"rand",
|
||||||
"rand_core 0.6.4",
|
"rand_core 0.6.4",
|
||||||
"rcgen",
|
"rcgen",
|
||||||
"ring",
|
"ring",
|
||||||
@ -4041,7 +3986,7 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"crc",
|
"crc",
|
||||||
"log",
|
"log",
|
||||||
"rand 0.10.2",
|
"rand",
|
||||||
"rtc-mdns",
|
"rtc-mdns",
|
||||||
"rtc-shared",
|
"rtc-shared",
|
||||||
"rtc-stun",
|
"rtc-stun",
|
||||||
@ -4058,7 +4003,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "f66ea5650a91773d10e4d98729f6fe256681ec1314c7ded5839fa34867305f79"
|
checksum = "f66ea5650a91773d10e4d98729f6fe256681ec1314c7ded5839fa34867305f79"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"rand 0.10.2",
|
"rand",
|
||||||
"rtc-interceptor-derive",
|
"rtc-interceptor-derive",
|
||||||
"rtc-rtcp",
|
"rtc-rtcp",
|
||||||
"rtc-rtp",
|
"rtc-rtp",
|
||||||
@ -4098,7 +4043,7 @@ checksum = "4fbc2f460a321eccdc0907819f8fc7027036edcbd94620c3328c1aefb070dfe5"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"bytes",
|
"bytes",
|
||||||
"rand 0.10.2",
|
"rand",
|
||||||
"rtc-rtp",
|
"rtc-rtp",
|
||||||
"rtc-shared",
|
"rtc-shared",
|
||||||
"thiserror 2.0.20",
|
"thiserror 2.0.20",
|
||||||
@ -4122,7 +4067,7 @@ checksum = "aac1a05add837d45d562f48bc769c9b264440741aab319fed48ce6a696e6aa0c"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"memchr",
|
"memchr",
|
||||||
"rand 0.10.2",
|
"rand",
|
||||||
"rtc-shared",
|
"rtc-shared",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
@ -4136,7 +4081,7 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"crc32c",
|
"crc32c",
|
||||||
"log",
|
"log",
|
||||||
"rand 0.10.2",
|
"rand",
|
||||||
"rtc-shared",
|
"rtc-shared",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"slab",
|
"slab",
|
||||||
@ -4149,7 +4094,7 @@ version = "0.20.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a0379bb552d4813e042d376db99f2005038017fc7864676fc835334b810db015"
|
checksum = "a0379bb552d4813e042d376db99f2005038017fc7864676fc835334b810db015"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand 0.10.2",
|
"rand",
|
||||||
"rtc-shared",
|
"rtc-shared",
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
@ -4166,7 +4111,7 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"nix",
|
"nix",
|
||||||
"p256",
|
"p256",
|
||||||
"rand 0.10.2",
|
"rand",
|
||||||
"rcgen",
|
"rcgen",
|
||||||
"sec1 0.7.3",
|
"sec1 0.7.3",
|
||||||
"serde",
|
"serde",
|
||||||
@ -4206,7 +4151,7 @@ dependencies = [
|
|||||||
"crc",
|
"crc",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"md-5",
|
"md-5",
|
||||||
"rand 0.10.2",
|
"rand",
|
||||||
"ring",
|
"ring",
|
||||||
"rtc-shared",
|
"rtc-shared",
|
||||||
"sansio",
|
"sansio",
|
||||||
@ -4316,9 +4261,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-webpki"
|
name = "rustls-webpki"
|
||||||
version = "0.103.13"
|
version = "0.103.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e"
|
checksum = "0527518605e68109d875e248ea259b6758801cf165e4b2c2733ae3b51f12535a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ring",
|
"ring",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
@ -4872,9 +4817,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinystr"
|
name = "tinystr"
|
||||||
version = "0.8.3"
|
version = "0.8.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
|
checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"zerovec",
|
"zerovec",
|
||||||
@ -5295,9 +5240,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.24.0"
|
version = "1.24.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239"
|
checksum = "2cefc03fd367c0c6d4305de1b312cf00248c4114f4a0418ce6a6af769e3b0bd9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.4.3",
|
"getrandom 0.4.3",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
@ -5343,15 +5288,6 @@ version = "0.11.1+wasi-snapshot-preview1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasip2"
|
|
||||||
version = "1.0.4+wasi-0.2.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487"
|
|
||||||
dependencies = [
|
|
||||||
"wit-bindgen 0.57.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.127"
|
version = "0.2.127"
|
||||||
@ -5464,17 +5400,6 @@ dependencies = [
|
|||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasmparser"
|
|
||||||
version = "0.255.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e8e329ef4b5d46e73b91d3ac6924417cad55a8cbbf869c199283383427c3320b"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.13.1",
|
|
||||||
"indexmap",
|
|
||||||
"semver",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasmparser"
|
name = "wasmparser"
|
||||||
version = "0.256.0"
|
version = "0.256.0"
|
||||||
@ -5740,7 +5665,7 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
"futures",
|
"futures",
|
||||||
"io-lifetimes 3.0.1",
|
"io-lifetimes 3.0.1",
|
||||||
"rand 0.10.2",
|
"rand",
|
||||||
"rustix",
|
"rustix",
|
||||||
"thiserror 2.0.20",
|
"thiserror 2.0.20",
|
||||||
"tokio",
|
"tokio",
|
||||||
@ -6142,12 +6067,6 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wit-bindgen"
|
|
||||||
version = "0.57.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wit-bindgen"
|
name = "wit-bindgen"
|
||||||
version = "0.60.0"
|
version = "0.60.0"
|
||||||
@ -6220,15 +6139,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wit-encoder"
|
name = "wit-encoder"
|
||||||
version = "0.255.0"
|
version = "0.256.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7cebd2d14c3296dada506c67c1ee5c9440811a2fe88a83367a606ccbd30ebfde"
|
checksum = "b8085a1e724fa8c48f9f5489b9d8f121eb9fc2554ebcdaf6936256d854b24390"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"id-arena",
|
"id-arena",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"semver",
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
"wit-parser 0.255.0",
|
"wit-parser 0.256.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -6271,9 +6190,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wit-parser"
|
name = "wit-parser"
|
||||||
version = "0.255.0"
|
version = "0.256.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ab5f6371fc71f15730b756c1dea3562a67adab1a7e519c4ca010173d883695bb"
|
checksum = "fa073dadefba859cb03f689a0c2e3efc51f883bf86b907eaa9709bfd9e3a00a9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"hashbrown 0.17.1",
|
"hashbrown 0.17.1",
|
||||||
@ -6285,7 +6204,7 @@ dependencies = [
|
|||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
"wasmparser 0.255.0",
|
"wasmparser 0.256.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -6301,9 +6220,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "writeable"
|
name = "writeable"
|
||||||
version = "0.6.3"
|
version = "0.6.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
|
checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "x25519-dalek"
|
name = "x25519-dalek"
|
||||||
@ -6460,9 +6379,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerotrie"
|
name = "zerotrie"
|
||||||
version = "0.2.4"
|
version = "0.2.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf"
|
checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"yoke",
|
"yoke",
|
||||||
@ -6471,9 +6390,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerovec"
|
name = "zerovec"
|
||||||
version = "0.11.6"
|
version = "0.11.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
|
checksum = "94b5c6b5976d66c1d703c4fd17d3f5e43c8cedaacf604961b171adc7130896d8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"yoke",
|
"yoke",
|
||||||
"zerofrom",
|
"zerofrom",
|
||||||
@ -6482,13 +6401,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerovec-derive"
|
name = "zerovec-derive"
|
||||||
version = "0.11.3"
|
version = "0.11.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
|
checksum = "47402523226a02bfe5230160dc3ccc089aa6f6f19e7fcbb4e6f824bbb1b4aa62"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.119",
|
"syn 3.0.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@ -12,7 +12,7 @@ use recipe::RecipeConfig;
|
|||||||
use serde::{Deserialize, Serialize, de::DeserializeOwned};
|
use serde::{Deserialize, Serialize, de::DeserializeOwned};
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::{fs, num::NonZeroU8, path::Path};
|
use std::{fs, num::NonZero, path::Path};
|
||||||
use tracing::{debug, error, warn};
|
use tracing::{debug, error, warn};
|
||||||
|
|
||||||
/// Fun and experimental configuration options.
|
/// Fun and experimental configuration options.
|
||||||
@ -87,8 +87,8 @@ impl LoadConfiguration for PumpkinConfig {
|
|||||||
self.basic.validate();
|
self.basic.validate();
|
||||||
self.advanced.validate();
|
self.advanced.validate();
|
||||||
|
|
||||||
let min_vd = NonZeroU8::MIN;
|
let min_vd = NonZero::<u8>::MIN;
|
||||||
let Some(max_vd) = NonZeroU8::new(64) else {
|
let Some(max_vd) = NonZero::new(64) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use crate::CompressionConfig;
|
use crate::CompressionConfig;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::net::{IpAddr, SocketAddr};
|
use std::net::{IpAddr, SocketAddr};
|
||||||
use std::num::NonZeroU8;
|
use std::num::NonZero;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
/// Configuration for Bedrock authentication.
|
/// Configuration for Bedrock authentication.
|
||||||
@ -71,9 +71,9 @@ pub struct BedrockConfig {
|
|||||||
/// The maximum number of players allowed on the server. Specifying `0` disables the limit.
|
/// The maximum number of players allowed on the server. Specifying `0` disables the limit.
|
||||||
pub max_players: u32,
|
pub max_players: u32,
|
||||||
/// The maximum view distance for players.
|
/// The maximum view distance for players.
|
||||||
pub view_distance: NonZeroU8,
|
pub view_distance: NonZero<u8>,
|
||||||
/// The maximum simulated view distance.
|
/// The maximum simulated view distance.
|
||||||
pub simulation_distance: NonZeroU8,
|
pub simulation_distance: NonZero<u8>,
|
||||||
/// Bedrock Edition packet compression settings.
|
/// Bedrock Edition packet compression settings.
|
||||||
pub compression: CompressionConfig,
|
pub compression: CompressionConfig,
|
||||||
/// Message of the Day; the server's description displayed on the status screen.
|
/// Message of the Day; the server's description displayed on the status screen.
|
||||||
@ -88,8 +88,8 @@ pub struct BedrockConfig {
|
|||||||
|
|
||||||
impl Default for BedrockConfig {
|
impl Default for BedrockConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let view_distance = NonZeroU8::new(16).unwrap_or(NonZeroU8::MIN);
|
let view_distance = NonZero::new(16).unwrap_or(NonZero::<u8>::MIN);
|
||||||
let simulation_distance = NonZeroU8::new(10).unwrap_or(NonZeroU8::MIN);
|
let simulation_distance = NonZero::new(10).unwrap_or(NonZero::<u8>::MIN);
|
||||||
Self {
|
Self {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
online_mode: true,
|
online_mode: true,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use crate::{AuthenticationConfig, CompressionConfig};
|
use crate::{AuthenticationConfig, CompressionConfig};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::num::NonZeroU8;
|
use std::num::NonZero;
|
||||||
|
|
||||||
/// Configuration for Java Edition client connections.
|
/// Configuration for Java Edition client connections.
|
||||||
#[derive(Deserialize, Serialize, Clone)]
|
#[derive(Deserialize, Serialize, Clone)]
|
||||||
@ -18,9 +18,9 @@ pub struct JavaConfig {
|
|||||||
/// The maximum number of players allowed on the server. Specifying `0` disables the limit.
|
/// The maximum number of players allowed on the server. Specifying `0` disables the limit.
|
||||||
pub max_players: u32,
|
pub max_players: u32,
|
||||||
/// The maximum view distance for players.
|
/// The maximum view distance for players.
|
||||||
pub view_distance: NonZeroU8,
|
pub view_distance: NonZero<u8>,
|
||||||
/// The maximum simulated view distance.
|
/// The maximum simulated view distance.
|
||||||
pub simulation_distance: NonZeroU8,
|
pub simulation_distance: NonZero<u8>,
|
||||||
/// Java Edition packet compression settings.
|
/// Java Edition packet compression settings.
|
||||||
pub compression: CompressionConfig,
|
pub compression: CompressionConfig,
|
||||||
/// Message of the Day; the server's description displayed on the status screen.
|
/// Message of the Day; the server's description displayed on the status screen.
|
||||||
@ -34,8 +34,8 @@ impl Default for JavaConfig {
|
|||||||
let address = "0.0.0.0:25565"
|
let address = "0.0.0.0:25565"
|
||||||
.parse()
|
.parse()
|
||||||
.unwrap_or_else(|_| std::net::SocketAddr::from(([0, 0, 0, 0], 25565)));
|
.unwrap_or_else(|_| std::net::SocketAddr::from(([0, 0, 0, 0], 25565)));
|
||||||
let view_distance = NonZeroU8::new(16).unwrap_or(NonZeroU8::MIN);
|
let view_distance = NonZero::new(16).unwrap_or(NonZero::<u8>::MIN);
|
||||||
let simulation_distance = NonZeroU8::new(10).unwrap_or(NonZeroU8::MIN);
|
let simulation_distance = NonZero::new(10).unwrap_or(NonZero::<u8>::MIN);
|
||||||
Self {
|
Self {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
address,
|
address,
|
||||||
|
|||||||
@ -21,7 +21,7 @@ pub struct TrapezoidHeightProvider {
|
|||||||
pub struct VeryBiasedToBottomHeightProvider {
|
pub struct VeryBiasedToBottomHeightProvider {
|
||||||
pub min_inclusive: YOffset,
|
pub min_inclusive: YOffset,
|
||||||
pub max_inclusive: YOffset,
|
pub max_inclusive: YOffset,
|
||||||
pub inner: Option<std::num::NonZeroU32>,
|
pub inner: Option<std::num::NonZero<u32>>,
|
||||||
}
|
}
|
||||||
pub struct CaveCarverConfig {
|
pub struct CaveCarverConfig {
|
||||||
pub horizontal_radius_multiplier: FloatProvider,
|
pub horizontal_radius_multiplier: FloatProvider,
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use crate::dimension::Dimension;
|
|||||||
use pumpkin_util::random::RandomDeriver;
|
use pumpkin_util::random::RandomDeriver;
|
||||||
use pumpkin_util::y_offset::Absolute;
|
use pumpkin_util::y_offset::Absolute;
|
||||||
use pumpkin_util::y_offset::YOffset;
|
use pumpkin_util::y_offset::YOffset;
|
||||||
use std::{cell::RefCell, num::NonZeroUsize};
|
use std::cell::RefCell;
|
||||||
pub struct GenerationSettings {
|
pub struct GenerationSettings {
|
||||||
pub aquifers_enabled: bool,
|
pub aquifers_enabled: bool,
|
||||||
pub ore_veins_enabled: bool,
|
pub ore_veins_enabled: bool,
|
||||||
|
|||||||
@ -6359,7 +6359,7 @@ fn build_placed_features()
|
|||||||
height: HeightProvider::VeryBiasedToBottom(VeryBiasedToBottomHeightProvider {
|
height: HeightProvider::VeryBiasedToBottom(VeryBiasedToBottomHeightProvider {
|
||||||
min_inclusive: YOffset::AboveBottom(AboveBottom { above_bottom: 0i8 }),
|
min_inclusive: YOffset::AboveBottom(AboveBottom { above_bottom: 0i8 }),
|
||||||
max_inclusive: YOffset::BelowTop(BelowTop { below_top: 8i8 }),
|
max_inclusive: YOffset::BelowTop(BelowTop { below_top: 8i8 }),
|
||||||
inner: std::num::NonZeroU32::new(8u32),
|
inner: std::num::NonZero::new(8u32),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
PlacementModifier::Biome(BiomePlacementModifier),
|
PlacementModifier::Biome(BiomePlacementModifier),
|
||||||
@ -6381,7 +6381,7 @@ fn build_placed_features()
|
|||||||
height: HeightProvider::VeryBiasedToBottom(VeryBiasedToBottomHeightProvider {
|
height: HeightProvider::VeryBiasedToBottom(VeryBiasedToBottomHeightProvider {
|
||||||
min_inclusive: YOffset::AboveBottom(AboveBottom { above_bottom: 0i8 }),
|
min_inclusive: YOffset::AboveBottom(AboveBottom { above_bottom: 0i8 }),
|
||||||
max_inclusive: YOffset::BelowTop(BelowTop { below_top: 8i8 }),
|
max_inclusive: YOffset::BelowTop(BelowTop { below_top: 8i8 }),
|
||||||
inner: std::num::NonZeroU32::new(8u32),
|
inner: std::num::NonZero::new(8u32),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
PlacementModifier::Biome(BiomePlacementModifier),
|
PlacementModifier::Biome(BiomePlacementModifier),
|
||||||
|
|||||||
@ -552,6 +552,42 @@ impl TrackedData {
|
|||||||
v26_1: 16u8,
|
v26_1: 16u8,
|
||||||
v26_2: 16u8,
|
v26_2: 16u8,
|
||||||
};
|
};
|
||||||
|
pub const CAT_COLLAR_COLOR: TrackedId = TrackedId {
|
||||||
|
v1_21: 22u8,
|
||||||
|
v1_21_2: 22u8,
|
||||||
|
v1_21_4: 22u8,
|
||||||
|
v1_21_5: 22u8,
|
||||||
|
v1_21_6: 22u8,
|
||||||
|
v1_21_7: 22u8,
|
||||||
|
v1_21_9: 22u8,
|
||||||
|
v1_21_11: 22u8,
|
||||||
|
v26_1: 23u8,
|
||||||
|
v26_2: 23u8,
|
||||||
|
};
|
||||||
|
pub const CAT_COLLAR_COLOR_ID: TrackedId = TrackedId {
|
||||||
|
v1_21: 22u8,
|
||||||
|
v1_21_2: 22u8,
|
||||||
|
v1_21_4: 22u8,
|
||||||
|
v1_21_5: 22u8,
|
||||||
|
v1_21_6: 22u8,
|
||||||
|
v1_21_7: 22u8,
|
||||||
|
v1_21_9: 22u8,
|
||||||
|
v1_21_11: 22u8,
|
||||||
|
v26_1: 23u8,
|
||||||
|
v26_2: 23u8,
|
||||||
|
};
|
||||||
|
pub const CAT_SOUND_VARIANT_ID: TrackedId = TrackedId {
|
||||||
|
v1_21: 255u8,
|
||||||
|
v1_21_2: 255u8,
|
||||||
|
v1_21_4: 255u8,
|
||||||
|
v1_21_5: 23u8,
|
||||||
|
v1_21_6: 23u8,
|
||||||
|
v1_21_7: 23u8,
|
||||||
|
v1_21_9: 23u8,
|
||||||
|
v1_21_11: 23u8,
|
||||||
|
v26_1: 24u8,
|
||||||
|
v26_2: 24u8,
|
||||||
|
};
|
||||||
pub const CAT_VARIANT: TrackedId = TrackedId {
|
pub const CAT_VARIANT: TrackedId = TrackedId {
|
||||||
v1_21: 19u8,
|
v1_21: 19u8,
|
||||||
v1_21_2: 19u8,
|
v1_21_2: 19u8,
|
||||||
@ -561,8 +597,20 @@ impl TrackedData {
|
|||||||
v1_21_7: 19u8,
|
v1_21_7: 19u8,
|
||||||
v1_21_9: 19u8,
|
v1_21_9: 19u8,
|
||||||
v1_21_11: 19u8,
|
v1_21_11: 19u8,
|
||||||
v26_1: 255u8,
|
v26_1: 20u8,
|
||||||
v26_2: 255u8,
|
v26_2: 20u8,
|
||||||
|
};
|
||||||
|
pub const CAT_VARIANT_ID: TrackedId = TrackedId {
|
||||||
|
v1_21: 19u8,
|
||||||
|
v1_21_2: 19u8,
|
||||||
|
v1_21_4: 19u8,
|
||||||
|
v1_21_5: 19u8,
|
||||||
|
v1_21_6: 19u8,
|
||||||
|
v1_21_7: 19u8,
|
||||||
|
v1_21_9: 19u8,
|
||||||
|
v1_21_11: 19u8,
|
||||||
|
v26_1: 20u8,
|
||||||
|
v26_2: 20u8,
|
||||||
};
|
};
|
||||||
pub const CAUGHT_FISH: TrackedId = TrackedId {
|
pub const CAUGHT_FISH: TrackedId = TrackedId {
|
||||||
v1_21: 9u8,
|
v1_21: 9u8,
|
||||||
@ -1326,11 +1374,11 @@ impl TrackedData {
|
|||||||
v1_21_4: 21u8,
|
v1_21_4: 21u8,
|
||||||
v1_21_5: 21u8,
|
v1_21_5: 21u8,
|
||||||
v1_21_6: 21u8,
|
v1_21_6: 21u8,
|
||||||
v1_21_7: 255u8,
|
v1_21_7: 21u8,
|
||||||
v1_21_9: 21u8,
|
v1_21_9: 21u8,
|
||||||
v1_21_11: 21u8,
|
v1_21_11: 21u8,
|
||||||
v26_1: 255u8,
|
v26_1: 22u8,
|
||||||
v26_2: 255u8,
|
v26_2: 22u8,
|
||||||
};
|
};
|
||||||
pub const HEAD_POSE: TrackedId = TrackedId {
|
pub const HEAD_POSE: TrackedId = TrackedId {
|
||||||
v1_21: 255u8,
|
v1_21: 255u8,
|
||||||
@ -1830,11 +1878,11 @@ impl TrackedData {
|
|||||||
v1_21_4: 20u8,
|
v1_21_4: 20u8,
|
||||||
v1_21_5: 20u8,
|
v1_21_5: 20u8,
|
||||||
v1_21_6: 20u8,
|
v1_21_6: 20u8,
|
||||||
v1_21_7: 255u8,
|
v1_21_7: 20u8,
|
||||||
v1_21_9: 20u8,
|
v1_21_9: 20u8,
|
||||||
v1_21_11: 20u8,
|
v1_21_11: 20u8,
|
||||||
v26_1: 255u8,
|
v26_1: 21u8,
|
||||||
v26_2: 255u8,
|
v26_2: 21u8,
|
||||||
};
|
};
|
||||||
pub const IRON_GOLEM_FLAGS: TrackedId = TrackedId {
|
pub const IRON_GOLEM_FLAGS: TrackedId = TrackedId {
|
||||||
v1_21: 16u8,
|
v1_21: 16u8,
|
||||||
@ -1933,14 +1981,14 @@ impl TrackedData {
|
|||||||
v26_2: 18u8,
|
v26_2: 18u8,
|
||||||
};
|
};
|
||||||
pub const IS_LYING: TrackedId = TrackedId {
|
pub const IS_LYING: TrackedId = TrackedId {
|
||||||
v1_21: 255u8,
|
v1_21: 20u8,
|
||||||
v1_21_2: 255u8,
|
v1_21_2: 20u8,
|
||||||
v1_21_4: 255u8,
|
v1_21_4: 20u8,
|
||||||
v1_21_5: 255u8,
|
v1_21_5: 20u8,
|
||||||
v1_21_6: 255u8,
|
v1_21_6: 20u8,
|
||||||
v1_21_7: 255u8,
|
v1_21_7: 20u8,
|
||||||
v1_21_9: 255u8,
|
v1_21_9: 20u8,
|
||||||
v1_21_11: 255u8,
|
v1_21_11: 20u8,
|
||||||
v26_1: 21u8,
|
v26_1: 21u8,
|
||||||
v26_2: 21u8,
|
v26_2: 21u8,
|
||||||
};
|
};
|
||||||
@ -2701,14 +2749,14 @@ impl TrackedData {
|
|||||||
v26_2: 8u8,
|
v26_2: 8u8,
|
||||||
};
|
};
|
||||||
pub const RELAX_STATE_ONE: TrackedId = TrackedId {
|
pub const RELAX_STATE_ONE: TrackedId = TrackedId {
|
||||||
v1_21: 255u8,
|
v1_21: 21u8,
|
||||||
v1_21_2: 255u8,
|
v1_21_2: 21u8,
|
||||||
v1_21_4: 255u8,
|
v1_21_4: 21u8,
|
||||||
v1_21_5: 255u8,
|
v1_21_5: 21u8,
|
||||||
v1_21_6: 255u8,
|
v1_21_6: 21u8,
|
||||||
v1_21_7: 255u8,
|
v1_21_7: 21u8,
|
||||||
v1_21_9: 255u8,
|
v1_21_9: 21u8,
|
||||||
v1_21_11: 255u8,
|
v1_21_11: 21u8,
|
||||||
v26_1: 22u8,
|
v26_1: 22u8,
|
||||||
v26_2: 22u8,
|
v26_2: 22u8,
|
||||||
};
|
};
|
||||||
@ -3090,21 +3138,21 @@ impl TrackedData {
|
|||||||
v1_21_4: 255u8,
|
v1_21_4: 255u8,
|
||||||
v1_21_5: 23u8,
|
v1_21_5: 23u8,
|
||||||
v1_21_6: 23u8,
|
v1_21_6: 23u8,
|
||||||
v1_21_7: 255u8,
|
v1_21_7: 23u8,
|
||||||
v1_21_9: 23u8,
|
v1_21_9: 23u8,
|
||||||
v1_21_11: 23u8,
|
v1_21_11: 23u8,
|
||||||
v26_1: 255u8,
|
v26_1: 24u8,
|
||||||
v26_2: 255u8,
|
v26_2: 24u8,
|
||||||
};
|
};
|
||||||
pub const SOUND_VARIANT_ID: TrackedId = TrackedId {
|
pub const SOUND_VARIANT_ID: TrackedId = TrackedId {
|
||||||
v1_21: 255u8,
|
v1_21: 255u8,
|
||||||
v1_21_2: 255u8,
|
v1_21_2: 255u8,
|
||||||
v1_21_4: 255u8,
|
v1_21_4: 255u8,
|
||||||
v1_21_5: 255u8,
|
v1_21_5: 23u8,
|
||||||
v1_21_6: 255u8,
|
v1_21_6: 23u8,
|
||||||
v1_21_7: 255u8,
|
v1_21_7: 23u8,
|
||||||
v1_21_9: 255u8,
|
v1_21_9: 23u8,
|
||||||
v1_21_11: 255u8,
|
v1_21_11: 23u8,
|
||||||
v26_1: 24u8,
|
v26_1: 24u8,
|
||||||
v26_2: 24u8,
|
v26_2: 24u8,
|
||||||
};
|
};
|
||||||
@ -3960,6 +4008,42 @@ impl TrackedData {
|
|||||||
v26_1: 20u8,
|
v26_1: 20u8,
|
||||||
v26_2: 20u8,
|
v26_2: 20u8,
|
||||||
};
|
};
|
||||||
|
pub const WOLF_COLLAR_COLOR: TrackedId = TrackedId {
|
||||||
|
v1_21: 20u8,
|
||||||
|
v1_21_2: 20u8,
|
||||||
|
v1_21_4: 20u8,
|
||||||
|
v1_21_5: 20u8,
|
||||||
|
v1_21_6: 20u8,
|
||||||
|
v1_21_7: 20u8,
|
||||||
|
v1_21_9: 20u8,
|
||||||
|
v1_21_11: 20u8,
|
||||||
|
v26_1: 21u8,
|
||||||
|
v26_2: 21u8,
|
||||||
|
};
|
||||||
|
pub const WOLF_COLLAR_COLOR_ID: TrackedId = TrackedId {
|
||||||
|
v1_21: 20u8,
|
||||||
|
v1_21_2: 20u8,
|
||||||
|
v1_21_4: 20u8,
|
||||||
|
v1_21_5: 20u8,
|
||||||
|
v1_21_6: 20u8,
|
||||||
|
v1_21_7: 20u8,
|
||||||
|
v1_21_9: 20u8,
|
||||||
|
v1_21_11: 20u8,
|
||||||
|
v26_1: 21u8,
|
||||||
|
v26_2: 21u8,
|
||||||
|
};
|
||||||
|
pub const WOLF_SOUND_VARIANT_ID: TrackedId = TrackedId {
|
||||||
|
v1_21: 255u8,
|
||||||
|
v1_21_2: 255u8,
|
||||||
|
v1_21_4: 255u8,
|
||||||
|
v1_21_5: 23u8,
|
||||||
|
v1_21_6: 23u8,
|
||||||
|
v1_21_7: 23u8,
|
||||||
|
v1_21_9: 23u8,
|
||||||
|
v1_21_11: 23u8,
|
||||||
|
v26_1: 24u8,
|
||||||
|
v26_2: 24u8,
|
||||||
|
};
|
||||||
pub const WOLF_VARIANT_ID: TrackedId = TrackedId {
|
pub const WOLF_VARIANT_ID: TrackedId = TrackedId {
|
||||||
v1_21: 22u8,
|
v1_21: 22u8,
|
||||||
v1_21_2: 22u8,
|
v1_21_2: 22u8,
|
||||||
|
|||||||
@ -15,7 +15,7 @@ use pumpkin_util::GameMode;
|
|||||||
use rand;
|
use rand;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
use std::num::NonZeroI32;
|
use std::num::NonZero;
|
||||||
use std::sync::atomic::{AtomicU32, Ordering};
|
use std::sync::atomic::{AtomicU32, Ordering};
|
||||||
|
|
||||||
mod categories;
|
mod categories;
|
||||||
@ -42,7 +42,7 @@ pub struct ItemStack {
|
|||||||
|
|
||||||
// unique ID for Bedrock network; don't serialize
|
// unique ID for Bedrock network; don't serialize
|
||||||
// Should always be a positive value for non-empty stacks
|
// Should always be a positive value for non-empty stacks
|
||||||
pub uid: NonZeroI32,
|
pub uid: NonZero<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl Hash for ItemStack {
|
// impl Hash for ItemStack {
|
||||||
@ -71,14 +71,14 @@ impl ItemStackIdGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next_id(&self) -> NonZeroI32 {
|
pub fn next_id(&self) -> NonZero<i32> {
|
||||||
// Wraps on overflow, which is what we want.
|
// Wraps on overflow, which is what we want.
|
||||||
let value = self.counter.fetch_add(1, Ordering::Relaxed);
|
let value = self.counter.fetch_add(1, Ordering::Relaxed);
|
||||||
|
|
||||||
// Negative values are invalid; cycle through the positives
|
// Negative values are invalid; cycle through the positives
|
||||||
let masked = value & 0x7FFFFFFF;
|
let masked = value & 0x7FFFFFFF;
|
||||||
|
|
||||||
if let Some(id) = NonZeroI32::new(masked as i32) {
|
if let Some(id) = NonZero::new(masked as i32) {
|
||||||
id
|
id
|
||||||
} else {
|
} else {
|
||||||
// If we fetched 0 or 0x80000000, that's masked out as 0
|
// If we fetched 0 or 0x80000000, that's masked out as 0
|
||||||
@ -133,7 +133,7 @@ impl ItemStack {
|
|||||||
item,
|
item,
|
||||||
patch: Vec::new(),
|
patch: Vec::new(),
|
||||||
|
|
||||||
uid: match NonZeroI32::new(1) {
|
uid: match NonZero::new(1) {
|
||||||
Some(v) => v,
|
Some(v) => v,
|
||||||
None => panic!("1 is non-zero"),
|
None => panic!("1 is non-zero"),
|
||||||
},
|
},
|
||||||
@ -211,7 +211,7 @@ impl ItemStack {
|
|||||||
item: &Item::AIR,
|
item: &Item::AIR,
|
||||||
patch: Vec::new(),
|
patch: Vec::new(),
|
||||||
|
|
||||||
uid: NonZeroI32::MIN, // white lie - Bedrock `uid` is never sent if the stack is empty
|
uid: NonZero::<i32>::MIN, // white lie - Bedrock `uid` is never sent if the stack is empty
|
||||||
};
|
};
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use std::io::{Error, ErrorKind, Read, Write};
|
use std::io::{Error, ErrorKind, Read, Write};
|
||||||
use std::num::NonZeroI32;
|
use std::num::NonZero;
|
||||||
|
|
||||||
use pumpkin_data::item::{BedrockItem, JavaToBedrockItemMapping};
|
use pumpkin_data::item::{BedrockItem, JavaToBedrockItemMapping};
|
||||||
use pumpkin_data::item_stack::ItemStack;
|
use pumpkin_data::item_stack::ItemStack;
|
||||||
@ -155,7 +155,7 @@ pub struct ItemStackWrapper {
|
|||||||
pub place_on_blocks: Vec<String>,
|
pub place_on_blocks: Vec<String>,
|
||||||
pub destroy_blocks: Vec<String>,
|
pub destroy_blocks: Vec<String>,
|
||||||
pub shield_blocking_tick: i64,
|
pub shield_blocking_tick: i64,
|
||||||
pub net_id: Option<NonZeroI32>,
|
pub net_id: Option<NonZero<i32>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketWrite for ItemStackWrapper {
|
impl PacketWrite for ItemStackWrapper {
|
||||||
@ -192,7 +192,7 @@ impl PacketRead for ItemStackWrapper {
|
|||||||
let has_net_id = bool::read(buf)?;
|
let has_net_id = bool::read(buf)?;
|
||||||
let net_id = if has_net_id {
|
let net_id = if has_net_id {
|
||||||
let stack_id = VarInt::read(buf)?;
|
let stack_id = VarInt::read(buf)?;
|
||||||
NonZeroI32::new(stack_id.0)
|
NonZero::new(stack_id.0)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
@ -256,7 +256,7 @@ pub struct NetworkItemStackDescriptor {
|
|||||||
pub aux_value: VarUInt,
|
pub aux_value: VarUInt,
|
||||||
pub block_runtime_id: VarUInt,
|
pub block_runtime_id: VarUInt,
|
||||||
pub extra_data: Vec<u8>,
|
pub extra_data: Vec<u8>,
|
||||||
pub net_id: Option<NonZeroI32>,
|
pub net_id: Option<NonZero<i32>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketWrite for NetworkItemStackDescriptor {
|
impl PacketWrite for NetworkItemStackDescriptor {
|
||||||
@ -290,7 +290,7 @@ impl PacketRead for NetworkItemStackDescriptor {
|
|||||||
let has_net_id = bool::read(buf)?;
|
let has_net_id = bool::read(buf)?;
|
||||||
let net_id = if has_net_id {
|
let net_id = if has_net_id {
|
||||||
let stack_id = VarInt::read(buf)?;
|
let stack_id = VarInt::read(buf)?;
|
||||||
NonZeroI32::new(stack_id.0)
|
NonZero::new(stack_id.0)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use std::{
|
use std::{
|
||||||
io::{Error, ErrorKind, Read, Write},
|
io::{Error, ErrorKind, Read, Write},
|
||||||
num::NonZeroUsize,
|
num::NonZero,
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -20,9 +20,7 @@ pub type VarIntType = i32;
|
|||||||
pub struct VarInt(pub VarIntType);
|
pub struct VarInt(pub VarIntType);
|
||||||
|
|
||||||
impl VarInt {
|
impl VarInt {
|
||||||
/// The maximum number of bytes a `VarInt` can occupy.
|
pub const MAX_SIZE: NonZero<usize> = NonZero::new(5).expect("5 is non-zero");
|
||||||
#[allow(clippy::unwrap_used)]
|
|
||||||
pub const MAX_SIZE: NonZeroUsize = NonZeroUsize::new(5).unwrap();
|
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use std::{
|
use std::{
|
||||||
io::{Error, Read, Write},
|
io::{Error, Read, Write},
|
||||||
num::NonZeroUsize,
|
num::NonZero,
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -19,9 +19,7 @@ pub type VarLongType = i64;
|
|||||||
pub struct VarLong(pub VarLongType);
|
pub struct VarLong(pub VarLongType);
|
||||||
|
|
||||||
impl VarLong {
|
impl VarLong {
|
||||||
/// The maximum number of bytes a `VarLong` can occupy.
|
pub const MAX_SIZE: NonZero<usize> = NonZero::new(10).expect("10 is non-zero");
|
||||||
#[allow(clippy::unwrap_used)]
|
|
||||||
pub const MAX_SIZE: NonZeroUsize = NonZeroUsize::new(10).unwrap();
|
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use std::{
|
use std::{
|
||||||
io::{Error, ErrorKind, Read, Write},
|
io::{Error, ErrorKind, Read, Write},
|
||||||
num::NonZeroUsize,
|
num::NonZero,
|
||||||
};
|
};
|
||||||
|
|
||||||
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
||||||
@ -19,9 +19,7 @@ pub type VarUIntType = u32;
|
|||||||
pub struct VarUInt(pub VarUIntType);
|
pub struct VarUInt(pub VarUIntType);
|
||||||
|
|
||||||
impl VarUInt {
|
impl VarUInt {
|
||||||
/// The maximum number of bytes a `VarUInt` can occupy.
|
pub const MAX_SIZE: NonZero<usize> = NonZero::new(5).expect("5 is non-zero");
|
||||||
#[allow(clippy::unwrap_used)]
|
|
||||||
pub const MAX_SIZE: NonZeroUsize = NonZeroUsize::new(5).unwrap();
|
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use std::{
|
use std::{
|
||||||
io::{Error, Read, Write},
|
io::{Error, Read, Write},
|
||||||
num::NonZeroUsize,
|
num::NonZero,
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -19,9 +19,7 @@ pub type VarULongType = u64;
|
|||||||
pub struct VarULong(pub VarULongType);
|
pub struct VarULong(pub VarULongType);
|
||||||
|
|
||||||
impl VarULong {
|
impl VarULong {
|
||||||
/// The maximum number of bytes a `VarULong` can occupy.
|
pub const MAX_SIZE: NonZero<usize> = NonZero::new(10).expect("10 is non-zero");
|
||||||
#[allow(clippy::unwrap_used)]
|
|
||||||
pub const MAX_SIZE: NonZeroUsize = NonZeroUsize::new(10).unwrap();
|
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|||||||
@ -225,22 +225,40 @@ where
|
|||||||
.map(|c| P::file_path(folder, &S::get_chunk_key(c)))
|
.map(|c| P::file_path(folder, &S::get_chunk_key(c)))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut watchers = self.watchers.write().await;
|
let mut paths_to_evict = Vec::new();
|
||||||
for path in paths {
|
{
|
||||||
if let std::collections::btree_map::Entry::Occupied(mut e) = watchers.entry(path) {
|
let mut watchers = self.watchers.write().await;
|
||||||
let count = e.get_mut();
|
for path in paths {
|
||||||
*count = count.saturating_sub(1);
|
if let std::collections::btree_map::Entry::Occupied(mut e) =
|
||||||
if *count == 0 {
|
watchers.entry(path)
|
||||||
e.remove();
|
{
|
||||||
|
let count = e.get_mut();
|
||||||
|
*count = count.saturating_sub(1);
|
||||||
|
if *count == 0 {
|
||||||
|
let (path, _) = e.remove_entry();
|
||||||
|
paths_to_evict.push(path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for path in paths_to_evict {
|
||||||
|
self.maybe_evict(&path).await;
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_watched_chunks(&self) -> BoxFuture<'_, ()> {
|
fn clear_watched_chunks(&self) -> BoxFuture<'_, ()> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
self.watchers.write().await.clear();
|
let paths: Vec<PathBuf> = {
|
||||||
|
let mut watchers = self.watchers.write().await;
|
||||||
|
let keys: Vec<_> = watchers.keys().cloned().collect();
|
||||||
|
watchers.clear();
|
||||||
|
keys
|
||||||
|
};
|
||||||
|
for path in paths {
|
||||||
|
self.maybe_evict(&path).await;
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,6 +319,9 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
join!(forward, read);
|
join!(forward, read);
|
||||||
|
|
||||||
|
// Evict if not watched and references are dropped
|
||||||
|
self.maybe_evict(&path).await;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -132,10 +132,14 @@ impl LevelChannel {
|
|||||||
&& !level.should_save.load(SeqCst)
|
&& !level.should_save.load(SeqCst)
|
||||||
&& !level.shut_down_chunk_system.load(SeqCst)
|
&& !level.shut_down_chunk_system.load(SeqCst)
|
||||||
{
|
{
|
||||||
lock = self
|
let (new_lock, timeout_res) = self
|
||||||
.notify
|
.notify
|
||||||
.wait(lock)
|
.wait_timeout(lock, std::time::Duration::from_secs(1))
|
||||||
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||||
|
lock = new_lock;
|
||||||
|
if timeout_res.timed_out() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let mut ret = (None, None);
|
let mut ret = (None, None);
|
||||||
swap(&mut ret, &mut *lock);
|
swap(&mut ret, &mut *lock);
|
||||||
|
|||||||
@ -74,4 +74,46 @@ impl DAG {
|
|||||||
*edge = self.edges.insert(Edge::new(to, *edge));
|
*edge = self.edges.insert(Edge::new(to, *edge));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn drop_edge_chain(&mut self, mut head: EdgeKey) {
|
||||||
|
while !head.is_null() {
|
||||||
|
if let Some(edge) = self.edges.remove(head) {
|
||||||
|
head = edge.next;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prune_edge_chain(&mut self, head: &mut EdgeKey) -> bool {
|
||||||
|
let mut cur_edge = *head;
|
||||||
|
let mut prev_edge = EdgeKey::null();
|
||||||
|
let mut change_head = None;
|
||||||
|
let mut has_valid_target = false;
|
||||||
|
|
||||||
|
while !cur_edge.is_null() {
|
||||||
|
let Some(edge) = self.edges.get(cur_edge) else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
if self.nodes.contains_key(edge.to) {
|
||||||
|
prev_edge = cur_edge;
|
||||||
|
cur_edge = edge.next;
|
||||||
|
has_valid_target = true;
|
||||||
|
} else {
|
||||||
|
let next = edge.next;
|
||||||
|
self.edges.remove(cur_edge);
|
||||||
|
cur_edge = next;
|
||||||
|
if prev_edge.is_null() {
|
||||||
|
change_head = Some(next);
|
||||||
|
} else if let Some(prev) = self.edges.get_mut(prev_edge) {
|
||||||
|
prev.next = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(next) = change_head {
|
||||||
|
*head = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
has_valid_target
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -508,10 +508,16 @@ impl GenerationSchedule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if new_stage == StagedChunkEnum::None
|
if new_stage == StagedChunkEnum::None {
|
||||||
&& holder.dependency_stage == StagedChunkEnum::None
|
if holder.dependency_stage != StagedChunkEnum::None {
|
||||||
{
|
let has_valid_task = self.graph.prune_edge_chain(&mut holder.occupied_by);
|
||||||
self.unload_chunks.insert(pos);
|
if !has_valid_task {
|
||||||
|
holder.dependency_stage = StagedChunkEnum::None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if holder.dependency_stage == StagedChunkEnum::None {
|
||||||
|
self.unload_chunks.insert(pos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if old_stage == StagedChunkEnum::None {
|
if old_stage == StagedChunkEnum::None {
|
||||||
@ -588,14 +594,120 @@ impl GenerationSchedule {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn garbage_collect_dependencies(&mut self) {
|
fn recompute_dependency_stages(&mut self) {
|
||||||
// Garbage collect stranded dependencies
|
let mut required: HashMapType<ChunkPos, StagedChunkEnum> = HashMapType::default();
|
||||||
let mut stranded = Vec::new();
|
let mut worklist: Vec<(ChunkPos, StagedChunkEnum)> = self
|
||||||
for (pos, holder) in &self.chunk_map {
|
.chunk_map
|
||||||
if holder.target_stage == StagedChunkEnum::None
|
.iter()
|
||||||
&& holder.dependency_stage != StagedChunkEnum::None
|
.filter(|(_, holder)| holder.target_stage != StagedChunkEnum::None)
|
||||||
|
.map(|(pos, holder)| (*pos, holder.target_stage))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
while let Some((pos, req)) = worklist.pop() {
|
||||||
|
let entry = required.entry(pos).or_insert(StagedChunkEnum::None);
|
||||||
|
if *entry >= req {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let start = *entry as u8 + 1;
|
||||||
|
*entry = req;
|
||||||
|
|
||||||
|
// Only expand the stages that were not already accounted for.
|
||||||
|
for i in start..=(req as u8) {
|
||||||
|
let stage = StagedChunkEnum::from(i);
|
||||||
|
let radius = stage.get_direct_radius();
|
||||||
|
if radius == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let dependencies = stage.get_direct_dependencies();
|
||||||
|
for dx in -radius..=radius {
|
||||||
|
for dz in -radius..=radius {
|
||||||
|
if dx == 0 && dz == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let neighbor = pos.add_raw(dx, dz);
|
||||||
|
worklist.push((neighbor, dependencies[dx.abs().max(dz.abs()) as usize]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut nodes_to_drop = Vec::new();
|
||||||
|
let mut newly_unused = Vec::new();
|
||||||
|
for (pos, holder) in &mut self.chunk_map {
|
||||||
|
let new_dependency = required.get(pos).copied().unwrap_or(StagedChunkEnum::None);
|
||||||
|
if new_dependency >= holder.dependency_stage {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
holder.dependency_stage = new_dependency;
|
||||||
|
|
||||||
|
let effective_target = holder.target_stage.max(new_dependency);
|
||||||
|
for i in (effective_target as usize + 1)..StagedChunkEnum::COUNT {
|
||||||
|
let task = holder.tasks[i];
|
||||||
|
if !task.is_null() {
|
||||||
|
nodes_to_drop.push((*pos, i, task));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if effective_target == StagedChunkEnum::None {
|
||||||
|
newly_unused.push(*pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.unload_chunks.extend(newly_unused);
|
||||||
|
|
||||||
|
for (pos, index, task) in nodes_to_drop {
|
||||||
|
if self
|
||||||
|
.graph
|
||||||
|
.nodes
|
||||||
|
.get(task)
|
||||||
|
.is_some_and(|node| node.in_flight)
|
||||||
{
|
{
|
||||||
stranded.push(*pos);
|
continue;
|
||||||
|
}
|
||||||
|
self.waiting_for_chunks.remove(&task);
|
||||||
|
self.drop_node(task);
|
||||||
|
if let Some(holder) = self.chunk_map.get_mut(&pos) {
|
||||||
|
holder.tasks[index] = NodeKey::null();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.purge_dropped_queue_entries();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Drop heap entries whose node has been cancelled. They are skipped when popped,
|
||||||
|
/// but a saturated queue is never drained, so without this the heap keeps every
|
||||||
|
/// cancelled task of every chunk the player has flown past and `sort_queue` gets
|
||||||
|
/// slower on each level change.
|
||||||
|
fn purge_dropped_queue_entries(&mut self) {
|
||||||
|
if self.queue.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let graph = &self.graph;
|
||||||
|
let tasks: Vec<_> = self
|
||||||
|
.queue
|
||||||
|
.drain()
|
||||||
|
.filter(|task| graph.nodes.contains_key(task.1))
|
||||||
|
.collect();
|
||||||
|
self.queue = BinaryHeap::from(tasks);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn garbage_collect_dependencies(&mut self) {
|
||||||
|
self.recompute_dependency_stages();
|
||||||
|
|
||||||
|
// Garbage collect stranded dependencies and empty holders
|
||||||
|
let mut stranded = Vec::new();
|
||||||
|
let mut empty_holders = Vec::new();
|
||||||
|
|
||||||
|
for (pos, holder) in &self.chunk_map {
|
||||||
|
if holder.target_stage == StagedChunkEnum::None {
|
||||||
|
if holder.dependency_stage != StagedChunkEnum::None {
|
||||||
|
stranded.push(*pos);
|
||||||
|
} else if holder.current_stage == StagedChunkEnum::None
|
||||||
|
&& holder.chunk.is_none()
|
||||||
|
&& holder.occupied.is_null()
|
||||||
|
&& holder.tasks.iter().all(Key::is_null)
|
||||||
|
&& !holder.public
|
||||||
|
{
|
||||||
|
empty_holders.push(*pos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -605,41 +717,19 @@ impl GenerationSchedule {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut cur_edge = holder.occupied_by;
|
let has_valid_task = self.graph.prune_edge_chain(&mut holder.occupied_by);
|
||||||
let mut prev_edge = EdgeKey::null();
|
|
||||||
let mut change_head = None;
|
|
||||||
let mut has_valid_task = false;
|
|
||||||
|
|
||||||
while !cur_edge.is_null() {
|
|
||||||
let edge = self.graph.edges.get(cur_edge).expect("edge exists");
|
|
||||||
if self.graph.nodes.contains_key(edge.to) {
|
|
||||||
prev_edge = cur_edge;
|
|
||||||
cur_edge = edge.next;
|
|
||||||
has_valid_task = true;
|
|
||||||
} else {
|
|
||||||
let next = edge.next;
|
|
||||||
self.graph.edges.remove(cur_edge);
|
|
||||||
cur_edge = next;
|
|
||||||
if prev_edge.is_null() {
|
|
||||||
change_head = Some(next);
|
|
||||||
} else {
|
|
||||||
self.graph
|
|
||||||
.edges
|
|
||||||
.get_mut(prev_edge)
|
|
||||||
.expect("edge exists")
|
|
||||||
.next = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(next) = change_head {
|
|
||||||
holder.occupied_by = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !has_valid_task {
|
if !has_valid_task {
|
||||||
holder.dependency_stage = StagedChunkEnum::None;
|
holder.dependency_stage = StagedChunkEnum::None;
|
||||||
self.unload_chunks.insert(pos);
|
self.unload_chunks.insert(pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for pos in empty_holders {
|
||||||
|
if let Some(mut holder) = self.chunk_map.remove(&pos) {
|
||||||
|
self.graph.drop_edge_chain(holder.occupied_by);
|
||||||
|
holder.occupied_by = EdgeKey::null();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_unload_queue(&mut self) {
|
fn process_unload_queue(&mut self) {
|
||||||
@ -671,6 +761,9 @@ impl GenerationSchedule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.graph.drop_edge_chain(holder.occupied_by);
|
||||||
|
holder.occupied_by = EdgeKey::null();
|
||||||
|
|
||||||
if holder.public {
|
if holder.public {
|
||||||
self.public_chunk_map.remove(&pos);
|
self.public_chunk_map.remove(&pos);
|
||||||
holder.public = false;
|
holder.public = false;
|
||||||
@ -854,6 +947,15 @@ impl GenerationSchedule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// If this chunk was only loaded for a dependency or cancelled
|
||||||
|
// and is no longer needed, clear dependency_stage and queue unload.
|
||||||
|
if holder.target_stage == StagedChunkEnum::None
|
||||||
|
&& holder.current_stage >= holder.dependency_stage
|
||||||
|
{
|
||||||
|
holder.dependency_stage = StagedChunkEnum::None;
|
||||||
|
self.unload_chunks.insert(pos);
|
||||||
|
}
|
||||||
|
|
||||||
holder.chunk = Some(chunk);
|
holder.chunk = Some(chunk);
|
||||||
self.chunk_map.insert(pos, holder);
|
self.chunk_map.insert(pos, holder);
|
||||||
|
|
||||||
@ -1087,13 +1189,15 @@ impl GenerationSchedule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 1. Get latest world state (player moves, etc)
|
// 1. Get latest world state (player moves, etc)
|
||||||
self.resort_work(self.send_level.get());
|
if self.resort_work(self.send_level.get()) {
|
||||||
|
self.garbage_collect_dependencies();
|
||||||
|
}
|
||||||
|
|
||||||
// Process unload queue periodically (every 1 second) to batch writes together
|
// Process unload queue periodically (every 1 second) to batch writes together
|
||||||
// and act as a brief memory cache if a player walks back into the chunk.
|
// and act as a brief memory cache if a player walks back into the chunk.
|
||||||
if !self.unload_chunks.is_empty()
|
// This must run even when the queue is empty: `garbage_collect_dependencies`
|
||||||
&& self.last_unload.elapsed() >= std::time::Duration::from_secs(1)
|
// is what puts stale dependency holders into the queue in the first place.
|
||||||
{
|
if self.last_unload.elapsed() >= std::time::Duration::from_secs(1) {
|
||||||
self.garbage_collect_dependencies();
|
self.garbage_collect_dependencies();
|
||||||
self.process_unload_queue();
|
self.process_unload_queue();
|
||||||
self.last_unload = std::time::Instant::now();
|
self.last_unload = std::time::Instant::now();
|
||||||
@ -1130,6 +1234,7 @@ impl GenerationSchedule {
|
|||||||
self.receive_chunk(pos, data);
|
self.receive_chunk(pos, data);
|
||||||
if self.resort_work(self.send_level.get()) {
|
if self.resort_work(self.send_level.get()) {
|
||||||
// If world state changed, we MUST re-sort before continuing
|
// If world state changed, we MUST re-sort before continuing
|
||||||
|
self.garbage_collect_dependencies();
|
||||||
self.queue.push(task);
|
self.queue.push(task);
|
||||||
self.queue_dirty = true;
|
self.queue_dirty = true;
|
||||||
break 'out2;
|
break 'out2;
|
||||||
@ -1357,11 +1462,15 @@ impl GenerationSchedule {
|
|||||||
match self.recv_chunk.recv_timeout(Duration::from_millis(5)) {
|
match self.recv_chunk.recv_timeout(Duration::from_millis(5)) {
|
||||||
Ok((pos, data)) => {
|
Ok((pos, data)) => {
|
||||||
self.receive_chunk(pos, data);
|
self.receive_chunk(pos, data);
|
||||||
self.resort_work(self.send_level.get());
|
if self.resort_work(self.send_level.get()) {
|
||||||
|
self.garbage_collect_dependencies();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(crossfire::compat::RecvTimeoutError::Timeout) => {
|
Err(crossfire::compat::RecvTimeoutError::Timeout) => {
|
||||||
// Periodically check LevelChannel for new requests
|
// Periodically check LevelChannel for new requests
|
||||||
self.resort_work(self.send_level.get());
|
if self.resort_work(self.send_level.get()) {
|
||||||
|
self.garbage_collect_dependencies();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(crossfire::compat::RecvTimeoutError::Disconnected) => break,
|
Err(crossfire::compat::RecvTimeoutError::Disconnected) => break,
|
||||||
}
|
}
|
||||||
@ -1381,7 +1490,9 @@ impl GenerationSchedule {
|
|||||||
}
|
}
|
||||||
debug_assert!(self.debug_check());
|
debug_assert!(self.debug_check());
|
||||||
debug_assert_eq!(self.running_task_count, 0);
|
debug_assert_eq!(self.running_task_count, 0);
|
||||||
self.resort_work(self.send_level.wait_and_get(level));
|
if self.resort_work(self.send_level.wait_and_get(level)) {
|
||||||
|
self.garbage_collect_dependencies();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if self.queue_dirty {
|
if self.queue_dirty {
|
||||||
self.sort_queue();
|
self.sort_queue();
|
||||||
@ -1436,6 +1547,9 @@ impl GenerationSchedule {
|
|||||||
nodes_to_drop.push(holder.occupied);
|
nodes_to_drop.push(holder.occupied);
|
||||||
holder.occupied = NodeKey::null();
|
holder.occupied = NodeKey::null();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.graph.drop_edge_chain(holder.occupied_by);
|
||||||
|
holder.occupied_by = EdgeKey::null();
|
||||||
}
|
}
|
||||||
|
|
||||||
for node_key in nodes_to_drop {
|
for node_key in nodes_to_drop {
|
||||||
|
|||||||
@ -355,3 +355,64 @@ fn cancellation_path_decrements_in_degree() {
|
|||||||
"The waiting task should have been dropped during cancellation"
|
"The waiting task should have been dropped during cancellation"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dag_drop_edge_chain_removes_all_edges() {
|
||||||
|
let mut graph = DAG::default();
|
||||||
|
let node1 = graph
|
||||||
|
.nodes
|
||||||
|
.insert(Node::new(ChunkPos::new(0, 0), StagedChunkEnum::Empty));
|
||||||
|
let node2 = graph
|
||||||
|
.nodes
|
||||||
|
.insert(Node::new(ChunkPos::new(1, 0), StagedChunkEnum::Empty));
|
||||||
|
|
||||||
|
let edge1 = graph.edges.insert(crate::chunk_system::dag::Edge::new(
|
||||||
|
node1,
|
||||||
|
crate::chunk_system::dag::EdgeKey::null(),
|
||||||
|
));
|
||||||
|
let edge2 = graph
|
||||||
|
.edges
|
||||||
|
.insert(crate::chunk_system::dag::Edge::new(node2, edge1));
|
||||||
|
|
||||||
|
assert_eq!(graph.edges.len(), 2);
|
||||||
|
graph.drop_edge_chain(edge2);
|
||||||
|
assert_eq!(graph.edges.len(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dag_prune_edge_chain_removes_dead_target_edges() {
|
||||||
|
let mut graph = DAG::default();
|
||||||
|
let node_alive = graph
|
||||||
|
.nodes
|
||||||
|
.insert(Node::new(ChunkPos::new(0, 0), StagedChunkEnum::Empty));
|
||||||
|
let node_dead = graph
|
||||||
|
.nodes
|
||||||
|
.insert(Node::new(ChunkPos::new(1, 0), StagedChunkEnum::Empty));
|
||||||
|
|
||||||
|
let edge_alive = graph.edges.insert(crate::chunk_system::dag::Edge::new(
|
||||||
|
node_alive,
|
||||||
|
crate::chunk_system::dag::EdgeKey::null(),
|
||||||
|
));
|
||||||
|
let edge_dead = graph
|
||||||
|
.edges
|
||||||
|
.insert(crate::chunk_system::dag::Edge::new(node_dead, edge_alive));
|
||||||
|
|
||||||
|
// Remove node_dead from graph.nodes to simulate completed/dropped task
|
||||||
|
graph.nodes.remove(node_dead);
|
||||||
|
|
||||||
|
let mut head = edge_dead;
|
||||||
|
let has_valid_task = graph.prune_edge_chain(&mut head);
|
||||||
|
|
||||||
|
assert!(has_valid_task);
|
||||||
|
assert_eq!(head, edge_alive);
|
||||||
|
assert_eq!(graph.edges.len(), 1);
|
||||||
|
assert!(graph.edges.contains_key(edge_alive));
|
||||||
|
assert!(!graph.edges.contains_key(edge_dead));
|
||||||
|
|
||||||
|
// Now remove node_alive as well
|
||||||
|
graph.nodes.remove(node_alive);
|
||||||
|
let has_valid_task = graph.prune_edge_chain(&mut head);
|
||||||
|
assert!(!has_valid_task);
|
||||||
|
assert!(head.is_null());
|
||||||
|
assert_eq!(graph.edges.len(), 0);
|
||||||
|
}
|
||||||
|
|||||||
@ -38,7 +38,10 @@ fn needs_relighting(chunk: &crate::chunk::ChunkData, config: LightingEngineConfi
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let engine = chunk.light_engine.lock().expect("Mutex poisoned");
|
let engine = chunk
|
||||||
|
.light_engine
|
||||||
|
.lock()
|
||||||
|
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||||
|
|
||||||
// Scan for any complex lighting data
|
// Scan for any complex lighting data
|
||||||
let has_complex_light = engine.sky_light.iter().any(|lc| match lc {
|
let has_complex_light = engine.sky_light.iter().any(|lc| match lc {
|
||||||
@ -237,7 +240,14 @@ pub fn run_generation(
|
|||||||
_settings: &GenerationSettings,
|
_settings: &GenerationSettings,
|
||||||
) -> RecvChunk {
|
) -> RecvChunk {
|
||||||
let portal = level.world_portal.load_full();
|
let portal = level.world_portal.load_full();
|
||||||
let portal_ref = portal.as_deref().expect("Portal should be initialized");
|
let Some(portal_ref) = portal.as_deref() else {
|
||||||
|
error!("Chunk generation FAILED at {pos:?} ({stage:?}): World portal is not initialized");
|
||||||
|
return RecvChunk::GenerationFailure {
|
||||||
|
pos,
|
||||||
|
stage,
|
||||||
|
error: "World portal is not initialized".to_string(),
|
||||||
|
};
|
||||||
|
};
|
||||||
// Run generation with panic catching
|
// Run generation with panic catching
|
||||||
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
||||||
cache.advance(stage, &level.world_gen, portal_ref, &level.lighting_config);
|
cache.advance(stage, &level.world_gen, portal_ref, &level.lighting_config);
|
||||||
|
|||||||
@ -1,16 +1,16 @@
|
|||||||
use std::num::NonZeroU8;
|
use std::num::NonZero;
|
||||||
|
|
||||||
use pumpkin_util::math::vector2::Vector2;
|
use pumpkin_util::math::vector2::Vector2;
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct Cylindrical {
|
pub struct Cylindrical {
|
||||||
pub center: Vector2<i32>,
|
pub center: Vector2<i32>,
|
||||||
pub view_distance: NonZeroU8,
|
pub view_distance: NonZero<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cylindrical {
|
impl Cylindrical {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn new(center: Vector2<i32>, view_distance: NonZeroU8) -> Self {
|
pub const fn new(center: Vector2<i32>, view_distance: NonZero<u8>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
center,
|
center,
|
||||||
view_distance,
|
view_distance,
|
||||||
@ -100,17 +100,17 @@ impl Cylindrical {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
||||||
use std::num::NonZeroU8;
|
use std::num::NonZero;
|
||||||
|
|
||||||
use super::Cylindrical;
|
use super::Cylindrical;
|
||||||
use pumpkin_util::math::vector2::Vector2;
|
use pumpkin_util::math::vector2::Vector2;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bounds() {
|
fn bounds() {
|
||||||
let mut cylinder = Cylindrical::new(Vector2::new(0, 0), NonZeroU8::new(1).unwrap());
|
let mut cylinder = Cylindrical::new(Vector2::new(0, 0), NonZero::new(1).unwrap());
|
||||||
|
|
||||||
for view_distance in 1..=32 {
|
for view_distance in 1..=32 {
|
||||||
cylinder.view_distance = NonZeroU8::new(view_distance).unwrap();
|
cylinder.view_distance = NonZero::new(view_distance).unwrap();
|
||||||
|
|
||||||
for chunk in cylinder.all_chunks_within() {
|
for chunk in cylinder.all_chunks_within() {
|
||||||
assert!(chunk.x >= cylinder.left() && chunk.x <= cylinder.right());
|
assert!(chunk.x >= cylinder.left() && chunk.x <= cylinder.right());
|
||||||
@ -130,10 +130,10 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn all_chunks_within_capacity_estimation() {
|
fn all_chunks_within_capacity_estimation() {
|
||||||
let mut cylinder = Cylindrical::new(Vector2::new(0, 0), NonZeroU8::new(1).unwrap());
|
let mut cylinder = Cylindrical::new(Vector2::new(0, 0), NonZero::new(1).unwrap());
|
||||||
|
|
||||||
for distance in 1..=64 {
|
for distance in 1..=64 {
|
||||||
cylinder.view_distance = NonZeroU8::new(distance).unwrap();
|
cylinder.view_distance = NonZero::new(distance).unwrap();
|
||||||
let chunks = cylinder.all_chunks_within();
|
let chunks = cylinder.all_chunks_within();
|
||||||
let estimated_capacity = ((distance as usize + 3).pow(2) * 3167) >> 10;
|
let estimated_capacity = ((distance as usize + 3).pow(2) * 3167) >> 10;
|
||||||
|
|
||||||
|
|||||||
@ -29,7 +29,10 @@ impl RandomBooleanFeature {
|
|||||||
} else {
|
} else {
|
||||||
&self.feature_false
|
&self.feature_false
|
||||||
};
|
};
|
||||||
feature.get().generate(
|
let Some(feature) = feature.get() else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
feature.generate(
|
||||||
chunk,
|
chunk,
|
||||||
block_registry,
|
block_registry,
|
||||||
min_y,
|
min_y,
|
||||||
|
|||||||
@ -32,7 +32,20 @@ impl RandomFeature {
|
|||||||
if random.next_f32() >= feature.chance {
|
if random.next_f32() >= feature.chance {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return feature.feature.get().generate(
|
if let Some(f) = feature.feature.get() {
|
||||||
|
return f.generate(
|
||||||
|
chunk,
|
||||||
|
block_registry,
|
||||||
|
min_y,
|
||||||
|
height,
|
||||||
|
feature_name,
|
||||||
|
random,
|
||||||
|
pos,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.default.get().is_some_and(|default_feature| {
|
||||||
|
default_feature.generate(
|
||||||
chunk,
|
chunk,
|
||||||
block_registry,
|
block_registry,
|
||||||
min_y,
|
min_y,
|
||||||
@ -40,16 +53,7 @@ impl RandomFeature {
|
|||||||
feature_name,
|
feature_name,
|
||||||
random,
|
random,
|
||||||
pos,
|
pos,
|
||||||
);
|
)
|
||||||
}
|
})
|
||||||
self.default.get().generate(
|
|
||||||
chunk,
|
|
||||||
block_registry,
|
|
||||||
min_y,
|
|
||||||
height,
|
|
||||||
feature_name,
|
|
||||||
random,
|
|
||||||
pos,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,11 +28,11 @@ pub enum PlacedFeatureWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PlacedFeatureWrapper {
|
impl PlacedFeatureWrapper {
|
||||||
#[allow(clippy::expect_used)]
|
#[must_use]
|
||||||
pub fn get(&self) -> &PlacedFeature {
|
pub fn get(&self) -> Option<&PlacedFeature> {
|
||||||
match self {
|
match self {
|
||||||
Self::Named(name) => PLACED_FEATURES.get(name).expect("Unknown placed feature"),
|
Self::Named(name) => PLACED_FEATURES.get(name),
|
||||||
Self::Direct(feature) => feature,
|
Self::Direct(feature) => Some(feature),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use std::num::NonZeroU32;
|
use std::num::NonZero;
|
||||||
|
|
||||||
use pumpkin_util::{
|
use pumpkin_util::{
|
||||||
random::{RandomGenerator, RandomImpl},
|
random::{RandomGenerator, RandomImpl},
|
||||||
@ -25,7 +25,7 @@ impl HeightProvider {
|
|||||||
pub struct VeryBiasedToBottomHeightProvider {
|
pub struct VeryBiasedToBottomHeightProvider {
|
||||||
pub min_inclusive: YOffset,
|
pub min_inclusive: YOffset,
|
||||||
pub max_inclusive: YOffset,
|
pub max_inclusive: YOffset,
|
||||||
pub inner: Option<NonZeroU32>,
|
pub inner: Option<NonZero<u32>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VeryBiasedToBottomHeightProvider {
|
impl VeryBiasedToBottomHeightProvider {
|
||||||
|
|||||||
@ -628,6 +628,10 @@ impl Level {
|
|||||||
self.chunk_watchers.shrink_to_fit();
|
self.chunk_watchers.shrink_to_fit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.loaded_chunks.capacity() - self.loaded_chunks.len() >= 4096 {
|
||||||
|
self.loaded_chunks.shrink_to_fit();
|
||||||
|
}
|
||||||
|
|
||||||
if self.loaded_entity_chunks.capacity() - self.loaded_entity_chunks.len() >= 4096 {
|
if self.loaded_entity_chunks.capacity() - self.loaded_entity_chunks.len() >= 4096 {
|
||||||
self.loaded_entity_chunks.shrink_to_fit();
|
self.loaded_entity_chunks.shrink_to_fit();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -118,12 +118,12 @@ macro_rules! impl_block_entity_for_chest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn take_loot_table(&self) -> Option<(String, i64)> {
|
fn take_loot_table(&self) -> Option<(String, i64)> {
|
||||||
let mut guard = self.loot_table.lock().expect("Loot table mutex should not be poisoned");
|
let mut guard = self.loot_table.lock().unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||||
guard.take().map(|key| (key, self.loot_table_seed))
|
guard.take().map(|key| (key, self.loot_table_seed))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_loot_table(&self) -> bool {
|
fn has_loot_table(&self) -> bool {
|
||||||
self.loot_table.lock().expect("Loot table mutex should not be poisoned").is_some()
|
self.loot_table.lock().unwrap_or_else(std::sync::PoisonError::into_inner).is_some()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -147,7 +147,7 @@ macro_rules! impl_cooking_block_entity_base {
|
|||||||
.result
|
.result
|
||||||
.id
|
.id
|
||||||
.strip_prefix("minecraft:")
|
.strip_prefix("minecraft:")
|
||||||
.expect("Recipe ID should have minecraft: prefix"),
|
.unwrap_or(&recipe.result.id),
|
||||||
) && !is_top_items_empty
|
) && !is_top_items_empty
|
||||||
&& recipe_output_item.id == side_item_stack.item.id
|
&& recipe_output_item.id == side_item_stack.item.id
|
||||||
&& side_item_stack.item_count < max_count
|
&& side_item_stack.item_count < max_count
|
||||||
@ -172,7 +172,7 @@ macro_rules! impl_cooking_block_entity_base {
|
|||||||
.result
|
.result
|
||||||
.id
|
.id
|
||||||
.strip_prefix("minecraft:")
|
.strip_prefix("minecraft:")
|
||||||
.expect("Recipe ID should have minecraft: prefix"),
|
.unwrap_or(&recipe.result.id),
|
||||||
) else {
|
) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -186,7 +186,7 @@ impl TargetSelector {
|
|||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn includes_entities(&self) -> bool {
|
pub fn includes_entities(&self) -> bool {
|
||||||
let player_type = EntityType::from_name("player").expect("entity type player must exist");
|
let player_type = &EntityType::PLAYER;
|
||||||
let mut includes_entities = self.base_includes_entities();
|
let mut includes_entities = self.base_includes_entities();
|
||||||
|
|
||||||
for condition in &self.conditions {
|
for condition in &self.conditions {
|
||||||
|
|||||||
@ -3,11 +3,14 @@ use pumpkin_protocol::java::client::play::{ArgumentType, SuggestionProviders};
|
|||||||
use crate::command::{
|
use crate::command::{
|
||||||
CommandSender,
|
CommandSender,
|
||||||
args::{
|
args::{
|
||||||
Arg, ArgumentConsumer, ConsumeResult, DefaultNameArgConsumer, FindArg,
|
Arg, ArgumentConsumer, ConsumeResult, ConsumeResultWithSyntax, DefaultNameArgConsumer,
|
||||||
GetClientSideArgParser,
|
FindArg, GetClientSideArgParser,
|
||||||
},
|
},
|
||||||
|
argument_types::{argument_type::ArgumentType as _, time::TimeArgumentType},
|
||||||
dispatcher::CommandError,
|
dispatcher::CommandError,
|
||||||
tree::RawArgs,
|
errors::command_syntax_error::{CommandSyntaxError, CommandSyntaxErrorContext},
|
||||||
|
string_reader::StringReader,
|
||||||
|
tree::{RawArg, RawArgs},
|
||||||
};
|
};
|
||||||
use crate::server::Server;
|
use crate::server::Server;
|
||||||
|
|
||||||
@ -34,6 +37,23 @@ impl TimeArgumentConsumer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn map_local_syntax_error(error: CommandSyntaxError, raw_arg: RawArg<'_>) -> CommandSyntaxError {
|
||||||
|
let local_cursor = error.context.map_or(0, |context| context.cursor);
|
||||||
|
let mut clamped_local_cursor = local_cursor.min(raw_arg.value.len());
|
||||||
|
while clamped_local_cursor > 0 && !raw_arg.value.is_char_boundary(clamped_local_cursor) {
|
||||||
|
clamped_local_cursor -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandSyntaxError {
|
||||||
|
error_type: error.error_type,
|
||||||
|
message: error.message,
|
||||||
|
context: Some(CommandSyntaxErrorContext {
|
||||||
|
input: raw_arg.input.to_string(),
|
||||||
|
cursor: raw_arg.start + clamped_local_cursor,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl GetClientSideArgParser for TimeArgumentConsumer {
|
impl GetClientSideArgParser for TimeArgumentConsumer {
|
||||||
fn get_client_side_parser(&self) -> ArgumentType {
|
fn get_client_side_parser(&self) -> ArgumentType {
|
||||||
ArgumentType::Time { min: self.min }
|
ArgumentType::Time { min: self.min }
|
||||||
@ -54,30 +74,33 @@ impl ArgumentConsumer for TimeArgumentConsumer {
|
|||||||
let s_opt: Option<&'a str> = args.pop().map(|arg| arg.value);
|
let s_opt: Option<&'a str> = args.pop().map(|arg| arg.value);
|
||||||
|
|
||||||
let result: Option<Arg<'a>> = s_opt.and_then(|s| {
|
let result: Option<Arg<'a>> = s_opt.and_then(|s| {
|
||||||
let (num_str, unit) = s
|
let mut reader = StringReader::new(s);
|
||||||
.find(|c: char| c.is_alphabetic() && c != '-')
|
let parser = TimeArgumentType::new(self.min);
|
||||||
.map_or((s, "t"), |pos| (&s[..pos], &s[pos..]));
|
parser.parse(&mut reader).ok().map(Arg::Time)
|
||||||
|
|
||||||
let number = num_str.parse::<f32>().ok()?;
|
|
||||||
|
|
||||||
let factor = match unit {
|
|
||||||
"d" => 24000.0,
|
|
||||||
"s" => 20.0,
|
|
||||||
"t" | "" => 1.0,
|
|
||||||
_ => return None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let ticks = (number * factor).round() as i32;
|
|
||||||
|
|
||||||
if ticks < self.min {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(Arg::Time(ticks))
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Box::pin(async move { result })
|
Box::pin(async move { result })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn consume_with_syntax<'a>(
|
||||||
|
&'a self,
|
||||||
|
_sender: &'a CommandSender,
|
||||||
|
_server: &'a Server,
|
||||||
|
args: &mut RawArgs<'a>,
|
||||||
|
) -> ConsumeResultWithSyntax<'a> {
|
||||||
|
let Some(raw_arg) = args.pop() else {
|
||||||
|
return Box::pin(async { Ok(None) });
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut reader = StringReader::new(raw_arg.value);
|
||||||
|
let parser = TimeArgumentType::new(self.min);
|
||||||
|
let result = parser
|
||||||
|
.parse(&mut reader)
|
||||||
|
.map(|ticks| Some(Arg::Time(ticks)))
|
||||||
|
.map_err(|error| map_local_syntax_error(error, raw_arg));
|
||||||
|
|
||||||
|
Box::pin(async move { result })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DefaultNameArgConsumer for TimeArgumentConsumer {
|
impl DefaultNameArgConsumer for TimeArgumentConsumer {
|
||||||
|
|||||||
@ -42,7 +42,7 @@ impl ArgumentType for AttributeArgumentType {
|
|||||||
|
|
||||||
fn client_side_parser(&'_ self) -> JavaClientArgumentType {
|
fn client_side_parser(&'_ self) -> JavaClientArgumentType {
|
||||||
JavaClientArgumentType::Resource {
|
JavaClientArgumentType::Resource {
|
||||||
identifier: Identifier::vanilla("attribute").expect("valid identifier"),
|
identifier: Identifier::vanilla_static("attribute"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -82,14 +82,13 @@ pub async fn send_c_commands_packet(
|
|||||||
.values()
|
.values()
|
||||||
.copied()
|
.copied()
|
||||||
.map(|id| resolve_node_id(id, node_id_offset, root_node_index))
|
.map(|id| resolve_node_id(id, node_id_offset, root_node_index))
|
||||||
.map(|i| i.try_into().expect("i32 limit reached for ids"))
|
.map(|i| VarInt(i as i32))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let redirect_target = node
|
let redirect_target = node
|
||||||
.redirect()
|
.redirect()
|
||||||
.and_then(|redirection| dispatcher.tree.resolve(redirection))
|
.and_then(|redirection| dispatcher.tree.resolve(redirection))
|
||||||
.map(|id| resolve_node_id(id, node_id_offset, root_node_index))
|
.map(|id| resolve_node_id(id, node_id_offset, root_node_index) as i32);
|
||||||
.map(|i| i.try_into().expect("i32 limit reached for ids"));
|
|
||||||
|
|
||||||
let satisfies_requirements = true;
|
let satisfies_requirements = true;
|
||||||
|
|
||||||
@ -117,7 +116,7 @@ pub async fn send_c_commands_packet(
|
|||||||
!disabled
|
!disabled
|
||||||
})
|
})
|
||||||
.map(|id| resolve_node_id(id, node_id_offset, root_node_index))
|
.map(|id| resolve_node_id(id, node_id_offset, root_node_index))
|
||||||
.map(|i| i.try_into().expect("i32 limit reached for ids"))
|
.map(|i| VarInt(i as i32))
|
||||||
.collect();
|
.collect();
|
||||||
}
|
}
|
||||||
AttachedNode::Literal(literal_attached_node) => {
|
AttachedNode::Literal(literal_attached_node) => {
|
||||||
@ -205,11 +204,7 @@ impl<'a> ProtoNodeBuilder<'a> {
|
|||||||
let children: Box<[VarInt]> = self
|
let children: Box<[VarInt]> = self
|
||||||
.child_nodes
|
.child_nodes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|node| {
|
.map(|node| VarInt(node.build(buffer) as i32))
|
||||||
node.build(buffer)
|
|
||||||
.try_into()
|
|
||||||
.expect("Buffer index exceeded i32 bounds")
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let i = buffer.len();
|
let i = buffer.len();
|
||||||
@ -589,15 +584,14 @@ fn collect_overloads_from_attached(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn ensure_enum_value(enum_values: &mut Vec<String>, value: &str) -> u32 {
|
fn ensure_enum_value(enum_values: &mut Vec<String>, value: &str) -> u32 {
|
||||||
enum_values
|
let index = enum_values
|
||||||
.iter()
|
.iter()
|
||||||
.position(|v| v == value)
|
.position(|v| v == value)
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
enum_values.push(value.to_string());
|
enum_values.push(value.to_string());
|
||||||
enum_values.len() - 1
|
enum_values.len() - 1
|
||||||
})
|
});
|
||||||
.try_into()
|
index as u32
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ensure_command_enum(
|
fn ensure_command_enum(
|
||||||
|
|||||||
@ -67,12 +67,7 @@ impl CommandExecutor for LocationExecutor {
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let target = EntityArgumentConsumer::find_arg(args, ARG_TARGET)?;
|
let target = EntityArgumentConsumer::find_arg(args, ARG_TARGET)?;
|
||||||
|
|
||||||
let Ok(Ok(amount)) = BoundedNumArgumentConsumer::<f32>::find_arg(args, ARG_AMOUNT)
|
let amount = BoundedNumArgumentConsumer::<f32>::find_arg(args, ARG_AMOUNT)??;
|
||||||
else {
|
|
||||||
return Err(CommandError::CommandFailed(TextComponent::text(
|
|
||||||
"Invalid damage amount",
|
|
||||||
)));
|
|
||||||
};
|
|
||||||
|
|
||||||
let damage_type =
|
let damage_type =
|
||||||
args.get(ARG_DAMAGE_TYPE)
|
args.get(ARG_DAMAGE_TYPE)
|
||||||
@ -102,12 +97,7 @@ impl CommandExecutor for EntityExecutor {
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let target = EntityArgumentConsumer::find_arg(args, ARG_TARGET)?;
|
let target = EntityArgumentConsumer::find_arg(args, ARG_TARGET)?;
|
||||||
|
|
||||||
let Ok(Ok(amount)) = BoundedNumArgumentConsumer::<f32>::find_arg(args, ARG_AMOUNT)
|
let amount = BoundedNumArgumentConsumer::<f32>::find_arg(args, ARG_AMOUNT)??;
|
||||||
else {
|
|
||||||
return Err(CommandError::CommandFailed(TextComponent::text(
|
|
||||||
"Invalid damage amount",
|
|
||||||
)));
|
|
||||||
};
|
|
||||||
|
|
||||||
let damage_type =
|
let damage_type =
|
||||||
args.get(ARG_DAMAGE_TYPE)
|
args.get(ARG_DAMAGE_TYPE)
|
||||||
|
|||||||
@ -88,16 +88,13 @@ impl CommandExecutor for GiveExecutor {
|
|||||||
let mut successes = 0;
|
let mut successes = 0;
|
||||||
|
|
||||||
for target in targets {
|
for target in targets {
|
||||||
if target.living_entity.has_effect(effect).await
|
let should_skip = target
|
||||||
&& target
|
.living_entity
|
||||||
.living_entity
|
.get_effect(effect)
|
||||||
.get_effect(effect)
|
.await
|
||||||
.await
|
.is_some_and(|existing| existing.amplifier >= amplifier);
|
||||||
.expect("Effect should exist because has_effect returned true")
|
|
||||||
.amplifier
|
if !should_skip {
|
||||||
>= amplifier
|
|
||||||
{
|
|
||||||
} else {
|
|
||||||
target
|
target
|
||||||
.add_effect(Effect {
|
.add_effect(Effect {
|
||||||
effect_type: effect,
|
effect_type: effect,
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
use pumpkin_data::data_component::DataComponent::MaxStackSize;
|
|
||||||
use pumpkin_data::data_component_impl::{MaxStackSizeImpl, get};
|
|
||||||
use pumpkin_util::text::TextComponent;
|
use pumpkin_util::text::TextComponent;
|
||||||
use pumpkin_util::text::hover::HoverEvent;
|
use pumpkin_util::text::hover::HoverEvent;
|
||||||
|
|
||||||
@ -47,14 +45,7 @@ impl CommandExecutor for Executor {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for target in targets {
|
for target in targets {
|
||||||
let max_stack = i32::from(
|
let max_stack = i32::from(parsed_stack.get_max_stack_size());
|
||||||
item.components
|
|
||||||
.iter()
|
|
||||||
.find_map(|(id, component)| {
|
|
||||||
(id == &MaxStackSize).then(|| get::<MaxStackSizeImpl>(*component).size)
|
|
||||||
})
|
|
||||||
.expect("Item should have MaxStackSize component"),
|
|
||||||
);
|
|
||||||
let mut remaining = item_count;
|
let mut remaining = item_count;
|
||||||
|
|
||||||
while remaining > 0 {
|
while remaining > 0 {
|
||||||
|
|||||||
@ -333,7 +333,7 @@ fn register_permissions(registry: &mut PermissionRegistry) {
|
|||||||
"Allows a player to use selector variables",
|
"Allows a player to use selector variables",
|
||||||
PermissionDefault::Allow,
|
PermissionDefault::Allow,
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_level_0_permissions(registry: &mut PermissionRegistry) {
|
fn register_level_0_permissions(registry: &mut PermissionRegistry) {
|
||||||
@ -344,21 +344,21 @@ fn register_level_0_permissions(registry: &mut PermissionRegistry) {
|
|||||||
"Shows information about the Pumpkin server",
|
"Shows information about the Pumpkin server",
|
||||||
PermissionDefault::Allow,
|
PermissionDefault::Allow,
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.me",
|
"minecraft:command.me",
|
||||||
"Broadcasts a narrative message about the player",
|
"Broadcasts a narrative message about the player",
|
||||||
PermissionDefault::Allow,
|
PermissionDefault::Allow,
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.msg",
|
"minecraft:command.msg",
|
||||||
"Sends a private message to another player",
|
"Sends a private message to another player",
|
||||||
PermissionDefault::Allow,
|
PermissionDefault::Allow,
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(clippy::too_many_lines)]
|
#[expect(clippy::too_many_lines)]
|
||||||
@ -370,210 +370,210 @@ fn register_level_2_permissions(registry: &mut PermissionRegistry) {
|
|||||||
"Manages the world border",
|
"Manages the world border",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.effect",
|
"minecraft:command.effect",
|
||||||
"Adds or removes status effects",
|
"Adds or removes status effects",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.teleport",
|
"minecraft:command.teleport",
|
||||||
"Teleports entities to other locations",
|
"Teleports entities to other locations",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.time",
|
"minecraft:command.time",
|
||||||
"Changes or queries the world's game time",
|
"Changes or queries the world's game time",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.waypoint",
|
"minecraft:command.waypoint",
|
||||||
"List or modify waypoints",
|
"List or modify waypoints",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.give",
|
"minecraft:command.give",
|
||||||
"Gives an item to a player",
|
"Gives an item to a player",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.item",
|
"minecraft:command.item",
|
||||||
"Replace items in inventories",
|
"Replace items in inventories",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.clear",
|
"minecraft:command.clear",
|
||||||
"Clears items from player inventory",
|
"Clears items from player inventory",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.setblock",
|
"minecraft:command.setblock",
|
||||||
"Changes a block to another block",
|
"Changes a block to another block",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.fill",
|
"minecraft:command.fill",
|
||||||
"Fills a region with a specific block",
|
"Fills a region with a specific block",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.playsound",
|
"minecraft:command.playsound",
|
||||||
"Plays a sound to players",
|
"Plays a sound to players",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.tellraw",
|
"minecraft:command.tellraw",
|
||||||
"Displays a JSON message to players",
|
"Displays a JSON message to players",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.title",
|
"minecraft:command.title",
|
||||||
"Controls screen titles displayed to players",
|
"Controls screen titles displayed to players",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.summon",
|
"minecraft:command.summon",
|
||||||
"Summons an entity",
|
"Summons an entity",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.experience",
|
"minecraft:command.experience",
|
||||||
"Adds, removes or queries player experience",
|
"Adds, removes or queries player experience",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.weather",
|
"minecraft:command.weather",
|
||||||
"Sets the weather in the server",
|
"Sets the weather in the server",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.particle",
|
"minecraft:command.particle",
|
||||||
"Creates particles in the world",
|
"Creates particles in the world",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.rotate",
|
"minecraft:command.rotate",
|
||||||
"Changes the rotation of an entity",
|
"Changes the rotation of an entity",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.damage",
|
"minecraft:command.damage",
|
||||||
"Damages entities",
|
"Damages entities",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.bossbar",
|
"minecraft:command.bossbar",
|
||||||
"Creates and manages boss bars",
|
"Creates and manages boss bars",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.say",
|
"minecraft:command.say",
|
||||||
"Broadcasts a message to multiple players",
|
"Broadcasts a message to multiple players",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.gamemode",
|
"minecraft:command.gamemode",
|
||||||
"Sets a player's game mode",
|
"Sets a player's game mode",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.gamerule",
|
"minecraft:command.gamerule",
|
||||||
"Sets a player's game mode",
|
"Sets a player's game mode",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.stopsound",
|
"minecraft:command.stopsound",
|
||||||
"Stops sounds from playing",
|
"Stops sounds from playing",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.defaultgamemode",
|
"minecraft:command.defaultgamemode",
|
||||||
"Sets the default game mode for new players",
|
"Sets the default game mode for new players",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.data",
|
"minecraft:command.data",
|
||||||
"Query and modify data of entities and blocks",
|
"Query and modify data of entities and blocks",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.enchant",
|
"minecraft:command.enchant",
|
||||||
"Adds an enchantment to a player's selected item, subject to the same restrictions as an anvil. Also works on any mob or entity holding a weapon/tool/armor in its main hand.",
|
"Adds an enchantment to a player's selected item, subject to the same restrictions as an anvil. Also works on any mob or entity holding a weapon/tool/armor in its main hand.",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.spawnpoint",
|
"minecraft:command.spawnpoint",
|
||||||
"Sets the spawn point for a player",
|
"Sets the spawn point for a player",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.spectate",
|
"minecraft:command.spectate",
|
||||||
"Allows a player to spectate another entity",
|
"Allows a player to spectate another entity",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"pumpkin:command.tps",
|
"pumpkin:command.tps",
|
||||||
"Displays the server TPS and MSPT",
|
"Displays the server TPS and MSPT",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_level_3_permissions(registry: &mut PermissionRegistry) {
|
fn register_level_3_permissions(registry: &mut PermissionRegistry) {
|
||||||
@ -584,77 +584,77 @@ fn register_level_3_permissions(registry: &mut PermissionRegistry) {
|
|||||||
"Sets the world spawn point",
|
"Sets the world spawn point",
|
||||||
PermissionDefault::Op(PermissionLvl::Three),
|
PermissionDefault::Op(PermissionLvl::Three),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.deop",
|
"minecraft:command.deop",
|
||||||
"Revokes operator status from a player",
|
"Revokes operator status from a player",
|
||||||
PermissionDefault::Op(PermissionLvl::Three),
|
PermissionDefault::Op(PermissionLvl::Three),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.kick",
|
"minecraft:command.kick",
|
||||||
"Removes players from the server",
|
"Removes players from the server",
|
||||||
PermissionDefault::Op(PermissionLvl::Three),
|
PermissionDefault::Op(PermissionLvl::Three),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"pumpkin:command.plugin",
|
"pumpkin:command.plugin",
|
||||||
"Manages server plugins",
|
"Manages server plugins",
|
||||||
PermissionDefault::Op(PermissionLvl::Three),
|
PermissionDefault::Op(PermissionLvl::Three),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"pumpkin:command.plugins",
|
"pumpkin:command.plugins",
|
||||||
"Lists all plugins loaded on the server",
|
"Lists all plugins loaded on the server",
|
||||||
PermissionDefault::Op(PermissionLvl::Three),
|
PermissionDefault::Op(PermissionLvl::Three),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.ban",
|
"minecraft:command.ban",
|
||||||
"Adds players to banlist",
|
"Adds players to banlist",
|
||||||
PermissionDefault::Op(PermissionLvl::Three),
|
PermissionDefault::Op(PermissionLvl::Three),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.banip",
|
"minecraft:command.banip",
|
||||||
"Adds IP addresses to banlist",
|
"Adds IP addresses to banlist",
|
||||||
PermissionDefault::Op(PermissionLvl::Three),
|
PermissionDefault::Op(PermissionLvl::Three),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.pardon",
|
"minecraft:command.pardon",
|
||||||
"Removes entries from the player banlist",
|
"Removes entries from the player banlist",
|
||||||
PermissionDefault::Op(PermissionLvl::Three),
|
PermissionDefault::Op(PermissionLvl::Three),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.pardonip",
|
"minecraft:command.pardonip",
|
||||||
"Removes entries from the IP banlist",
|
"Removes entries from the IP banlist",
|
||||||
PermissionDefault::Op(PermissionLvl::Three),
|
PermissionDefault::Op(PermissionLvl::Three),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.whitelist",
|
"minecraft:command.whitelist",
|
||||||
"Manages server whitelist",
|
"Manages server whitelist",
|
||||||
PermissionDefault::Op(PermissionLvl::Three),
|
PermissionDefault::Op(PermissionLvl::Three),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.transfer",
|
"minecraft:command.transfer",
|
||||||
"Transfers the player to another server",
|
"Transfers the player to another server",
|
||||||
PermissionDefault::Op(PermissionLvl::Three),
|
PermissionDefault::Op(PermissionLvl::Three),
|
||||||
))
|
))
|
||||||
.expect("Permission already registered");
|
.unwrap_or_else(|e| tracing::warn!("{e}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
use pumpkin_data::translation;
|
use pumpkin_data::translation;
|
||||||
use pumpkin_util::text::TextComponent;
|
use pumpkin_util::text::TextComponent;
|
||||||
|
|
||||||
use crate::command::CommandResult;
|
|
||||||
use crate::command::args::{
|
use crate::command::args::{
|
||||||
FindArg, bounded_num::BoundedNumArgumentConsumer,
|
FindArg, bounded_num::BoundedNumArgumentConsumer,
|
||||||
resource_location::ResourceLocationArgumentConsumer, time::TimeArgumentConsumer,
|
resource_location::ResourceLocationArgumentConsumer, time::TimeArgumentConsumer,
|
||||||
};
|
};
|
||||||
use crate::command::dispatcher::CommandError;
|
|
||||||
use crate::command::tree::builder::{argument, literal};
|
use crate::command::tree::builder::{argument, literal};
|
||||||
use crate::command::{CommandExecutor, CommandSender, ConsumedArgs, tree::CommandTree};
|
use crate::command::{
|
||||||
|
CommandError, CommandExecutor, CommandResult, CommandSender, ConsumedArgs, tree::CommandTree,
|
||||||
|
};
|
||||||
|
|
||||||
const NAMES: [&str; 1] = ["time"];
|
const NAMES: [&str; 1] = ["time"];
|
||||||
const DESCRIPTION: &str = "Query or modify the world time and clocks.";
|
const DESCRIPTION: &str = "Query or modify the world time and clocks.";
|
||||||
@ -72,9 +72,7 @@ impl CommandExecutor for QueryExecutor {
|
|||||||
.unwrap_or(DEFAULT_CLOCK);
|
.unwrap_or(DEFAULT_CLOCK);
|
||||||
let mode = self.0;
|
let mode = self.0;
|
||||||
let worlds = server.worlds.load();
|
let worlds = server.worlds.load();
|
||||||
let world = worlds
|
let world = worlds.first().ok_or(CommandError::InvalidRequirement)?;
|
||||||
.first()
|
|
||||||
.expect("There should always be at least one world");
|
|
||||||
let level_time = world.level_time.lock().await;
|
let level_time = world.level_time.lock().await;
|
||||||
|
|
||||||
match mode {
|
match mode {
|
||||||
@ -142,21 +140,15 @@ impl CommandExecutor for ActionExecutor {
|
|||||||
.unwrap_or(DEFAULT_CLOCK);
|
.unwrap_or(DEFAULT_CLOCK);
|
||||||
let action = self.0;
|
let action = self.0;
|
||||||
let worlds = server.worlds.load();
|
let worlds = server.worlds.load();
|
||||||
let world = worlds
|
let world = worlds.first().ok_or(CommandError::InvalidRequirement)?;
|
||||||
.first()
|
|
||||||
.expect("There should always be at least one world");
|
|
||||||
let mut level_time = world.level_time.lock().await;
|
let mut level_time = world.level_time.lock().await;
|
||||||
|
|
||||||
match action {
|
match action {
|
||||||
Action::Set(preset) => {
|
Action::Set(preset) => {
|
||||||
let time_count = if let Some(p) = preset {
|
let time_count = if let Some(p) = preset {
|
||||||
p.to_ticks()
|
p.to_ticks()
|
||||||
} else if let Ok(ticks) = TimeArgumentConsumer::find_arg(args, ARG_TIME) {
|
|
||||||
ticks
|
|
||||||
} else {
|
} else {
|
||||||
return Err(CommandError::CommandFailed(TextComponent::text(
|
TimeArgumentConsumer::find_arg(args, ARG_TIME)?
|
||||||
"Invalid time specified.",
|
|
||||||
)));
|
|
||||||
};
|
};
|
||||||
level_time.set_time(time_count.into());
|
level_time.set_time(time_count.into());
|
||||||
level_time.send_time(world).await;
|
level_time.send_time(world).await;
|
||||||
|
|||||||
@ -9,7 +9,7 @@ use crate::command::args::{
|
|||||||
};
|
};
|
||||||
use crate::command::tree::builder::{argument, literal};
|
use crate::command::tree::builder::{argument, literal};
|
||||||
use crate::command::{
|
use crate::command::{
|
||||||
CommandExecutor, CommandResult, CommandSender, ConsumedArgs, tree::CommandTree,
|
CommandError, CommandExecutor, CommandResult, CommandSender, ConsumedArgs, tree::CommandTree,
|
||||||
};
|
};
|
||||||
|
|
||||||
const NAMES: [&str; 1] = ["waypoint"];
|
const NAMES: [&str; 1] = ["waypoint"];
|
||||||
@ -29,9 +29,7 @@ impl CommandExecutor for ListExecutor {
|
|||||||
) -> CommandResult<'a> {
|
) -> CommandResult<'a> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let worlds = server.worlds.load();
|
let worlds = server.worlds.load();
|
||||||
let world = worlds
|
let world = worlds.first().ok_or(CommandError::InvalidRequirement)?;
|
||||||
.first()
|
|
||||||
.expect("There should always be at least one world");
|
|
||||||
let dimension = world.dimension.minecraft_name.to_string();
|
let dimension = world.dimension.minecraft_name.to_string();
|
||||||
|
|
||||||
sender
|
sender
|
||||||
|
|||||||
@ -4,8 +4,8 @@ use pumpkin_util::{math::vector2::Vector2, text::TextComponent};
|
|||||||
use crate::command::{
|
use crate::command::{
|
||||||
CommandError, CommandExecutor, CommandResult, CommandSender,
|
CommandError, CommandExecutor, CommandResult, CommandSender,
|
||||||
args::{
|
args::{
|
||||||
ConsumedArgs, DefaultNameArgConsumer, FindArgDefaultName,
|
ConsumedArgs, FindArgDefaultName, bounded_num::BoundedNumArgumentConsumer,
|
||||||
bounded_num::BoundedNumArgumentConsumer, position_2d::Position2DArgumentConsumer,
|
position_2d::Position2DArgumentConsumer,
|
||||||
},
|
},
|
||||||
tree::{
|
tree::{
|
||||||
CommandTree,
|
CommandTree,
|
||||||
@ -51,9 +51,7 @@ impl CommandExecutor for GetExecutor {
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
// TODO: Maybe ask player for world, or get the current world
|
// TODO: Maybe ask player for world, or get the current world
|
||||||
let worlds = server.worlds.load();
|
let worlds = server.worlds.load();
|
||||||
let world = worlds
|
let world = worlds.first().ok_or(CommandError::InvalidRequirement)?;
|
||||||
.first()
|
|
||||||
.expect("There should always be at least one world");
|
|
||||||
let border = world.worldborder.lock().await;
|
let border = world.worldborder.lock().await;
|
||||||
|
|
||||||
let diameter = border.new_diameter.round() as i32;
|
let diameter = border.new_diameter.round() as i32;
|
||||||
@ -82,17 +80,10 @@ impl CommandExecutor for SetExecutor {
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
// TODO: Maybe ask player for world, or get the current world
|
// TODO: Maybe ask player for world, or get the current world
|
||||||
let worlds = server.worlds.load();
|
let worlds = server.worlds.load();
|
||||||
let world = worlds
|
let world = worlds.first().ok_or(CommandError::InvalidRequirement)?;
|
||||||
.first()
|
|
||||||
.expect("There should always be at least one world");
|
|
||||||
let mut border = world.worldborder.lock().await;
|
let mut border = world.worldborder.lock().await;
|
||||||
|
|
||||||
let Ok(distance) = distance_consumer().find_arg_default_name(args)? else {
|
let distance = distance_consumer().find_arg_default_name(args)??;
|
||||||
return Err(CommandError::CommandFailed(TextComponent::text(format!(
|
|
||||||
"{} is out of bounds.",
|
|
||||||
distance_consumer().default_name()
|
|
||||||
))));
|
|
||||||
};
|
|
||||||
|
|
||||||
if (distance - border.new_diameter).abs() < f64::EPSILON {
|
if (distance - border.new_diameter).abs() < f64::EPSILON {
|
||||||
return Err(CommandError::CommandFailed(
|
return Err(CommandError::CommandFailed(
|
||||||
@ -132,23 +123,11 @@ impl CommandExecutor for SetTimeExecutor {
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
// TODO: Maybe ask player for world, or get the current world
|
// TODO: Maybe ask player for world, or get the current world
|
||||||
let worlds = server.worlds.load();
|
let worlds = server.worlds.load();
|
||||||
let world = worlds
|
let world = worlds.first().ok_or(CommandError::InvalidRequirement)?;
|
||||||
.first()
|
|
||||||
.expect("There should always be at least one world");
|
|
||||||
let mut border = world.worldborder.lock().await;
|
let mut border = world.worldborder.lock().await;
|
||||||
|
|
||||||
let Ok(distance) = distance_consumer().find_arg_default_name(args)? else {
|
let distance = distance_consumer().find_arg_default_name(args)??;
|
||||||
return Err(CommandError::CommandFailed(TextComponent::text(format!(
|
let time = time_consumer().find_arg_default_name(args)??;
|
||||||
"{} is out of bounds.",
|
|
||||||
distance_consumer().default_name()
|
|
||||||
))));
|
|
||||||
};
|
|
||||||
let Ok(time) = time_consumer().find_arg_default_name(args)? else {
|
|
||||||
return Err(CommandError::CommandFailed(TextComponent::text(format!(
|
|
||||||
"{} is out of bounds.",
|
|
||||||
distance_consumer().default_name()
|
|
||||||
))));
|
|
||||||
};
|
|
||||||
|
|
||||||
let old_dist = format!("{:.1}", border.new_diameter);
|
let old_dist = format!("{:.1}", border.new_diameter);
|
||||||
match distance.total_cmp(&border.new_diameter) {
|
match distance.total_cmp(&border.new_diameter) {
|
||||||
@ -206,17 +185,10 @@ impl CommandExecutor for AddExecutor {
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
// TODO: Maybe ask player for world, or get the current world
|
// TODO: Maybe ask player for world, or get the current world
|
||||||
let worlds = server.worlds.load();
|
let worlds = server.worlds.load();
|
||||||
let world = worlds
|
let world = worlds.first().ok_or(CommandError::InvalidRequirement)?;
|
||||||
.first()
|
|
||||||
.expect("There should always be at least one world");
|
|
||||||
let mut border = world.worldborder.lock().await;
|
let mut border = world.worldborder.lock().await;
|
||||||
|
|
||||||
let Ok(distance_add) = distance_consumer().find_arg_default_name(args)? else {
|
let distance_add = distance_consumer().find_arg_default_name(args)??;
|
||||||
return Err(CommandError::CommandFailed(TextComponent::text(format!(
|
|
||||||
"{} is out of bounds.",
|
|
||||||
distance_consumer().default_name()
|
|
||||||
))));
|
|
||||||
};
|
|
||||||
|
|
||||||
if distance_add == 0.0 {
|
if distance_add == 0.0 {
|
||||||
return Err(CommandError::CommandFailed(
|
return Err(CommandError::CommandFailed(
|
||||||
@ -257,33 +229,23 @@ impl CommandExecutor for AddTimeExecutor {
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
// TODO: Maybe ask player for world, or get the current world
|
// TODO: Maybe ask player for world, or get the current world
|
||||||
let worlds = server.worlds.load();
|
let worlds = server.worlds.load();
|
||||||
let world = worlds
|
let world = worlds.first().ok_or(CommandError::InvalidRequirement)?;
|
||||||
.first()
|
|
||||||
.expect("There should always be at least one world");
|
|
||||||
let mut border = world.worldborder.lock().await;
|
let mut border = world.worldborder.lock().await;
|
||||||
|
|
||||||
let Ok(distance_add) = distance_consumer().find_arg_default_name(args)? else {
|
let distance_add = distance_consumer().find_arg_default_name(args)??;
|
||||||
return Err(CommandError::CommandFailed(TextComponent::text(format!(
|
let time = time_consumer().find_arg_default_name(args)??;
|
||||||
"{} is out of bounds.",
|
|
||||||
distance_consumer().default_name()
|
|
||||||
))));
|
|
||||||
};
|
|
||||||
let Ok(time) = time_consumer().find_arg_default_name(args)? else {
|
|
||||||
return Err(CommandError::CommandFailed(TextComponent::text(format!(
|
|
||||||
"{} is out of bounds.",
|
|
||||||
distance_consumer().default_name()
|
|
||||||
))));
|
|
||||||
};
|
|
||||||
|
|
||||||
let distance = distance_add + border.new_diameter;
|
let distance = distance_add + border.new_diameter;
|
||||||
|
|
||||||
let old_dist = format!("{:.1}", border.new_diameter);
|
let old_dist = format!("{:.1}", border.new_diameter);
|
||||||
match distance.total_cmp(&border.new_diameter) {
|
match distance.total_cmp(&border.new_diameter) {
|
||||||
std::cmp::Ordering::Equal => {
|
std::cmp::Ordering::Equal => {
|
||||||
return Err(CommandError::CommandFailed(TextComponent::text(format!(
|
return Err(CommandError::CommandFailed(
|
||||||
"{} is out of bounds.",
|
pumpkin_macros::translate_cross!(
|
||||||
distance_consumer().default_name()
|
translation::java::COMMANDS_WORLDBORDER_SET_FAILED_NOCHANGE,
|
||||||
))));
|
translation::bedrock::COMMANDS_WORLDBORDER_SET_SUCCESS
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
std::cmp::Ordering::Less => {
|
std::cmp::Ordering::Less => {
|
||||||
let dist = format!("{distance:.1}");
|
let dist = format!("{distance:.1}");
|
||||||
@ -330,9 +292,7 @@ impl CommandExecutor for CenterExecutor {
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
// TODO: Maybe ask player for world, or get the current world
|
// TODO: Maybe ask player for world, or get the current world
|
||||||
let worlds = server.worlds.load();
|
let worlds = server.worlds.load();
|
||||||
let world = worlds
|
let world = worlds.first().ok_or(CommandError::InvalidRequirement)?;
|
||||||
.first()
|
|
||||||
.expect("There should always be at least one world");
|
|
||||||
let mut border = world.worldborder.lock().await;
|
let mut border = world.worldborder.lock().await;
|
||||||
|
|
||||||
let Vector2 { x, y } = Position2DArgumentConsumer.find_arg_default_name(args)?;
|
let Vector2 { x, y } = Position2DArgumentConsumer.find_arg_default_name(args)?;
|
||||||
@ -363,18 +323,10 @@ impl CommandExecutor for DamageAmountExecutor {
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
// TODO: Maybe ask player for world, or get the current world
|
// TODO: Maybe ask player for world, or get the current world
|
||||||
let worlds = server.worlds.load();
|
let worlds = server.worlds.load();
|
||||||
let world = worlds
|
let world = worlds.first().ok_or(CommandError::InvalidRequirement)?;
|
||||||
.first()
|
|
||||||
.expect("There should always be at least one world");
|
|
||||||
let mut border = world.worldborder.lock().await;
|
let mut border = world.worldborder.lock().await;
|
||||||
|
|
||||||
let Ok(damage_per_block) = damage_per_block_consumer().find_arg_default_name(args)?
|
let damage_per_block = damage_per_block_consumer().find_arg_default_name(args)??;
|
||||||
else {
|
|
||||||
return Err(CommandError::CommandFailed(TextComponent::text(format!(
|
|
||||||
"{} is out of bounds.",
|
|
||||||
distance_consumer().default_name()
|
|
||||||
))));
|
|
||||||
};
|
|
||||||
|
|
||||||
if (damage_per_block - border.damage_per_block).abs() < f32::EPSILON {
|
if (damage_per_block - border.damage_per_block).abs() < f32::EPSILON {
|
||||||
return Err(CommandError::CommandFailed(
|
return Err(CommandError::CommandFailed(
|
||||||
@ -413,17 +365,10 @@ impl CommandExecutor for DamageBufferExecutor {
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
// TODO: Maybe ask player for world, or get the current world
|
// TODO: Maybe ask player for world, or get the current world
|
||||||
let worlds = server.worlds.load();
|
let worlds = server.worlds.load();
|
||||||
let world = worlds
|
let world = worlds.first().ok_or(CommandError::InvalidRequirement)?;
|
||||||
.first()
|
|
||||||
.expect("There should always be at least one world");
|
|
||||||
let mut border = world.worldborder.lock().await;
|
let mut border = world.worldborder.lock().await;
|
||||||
|
|
||||||
let Ok(buffer) = damage_buffer_consumer().find_arg_default_name(args)? else {
|
let buffer = damage_buffer_consumer().find_arg_default_name(args)??;
|
||||||
return Err(CommandError::CommandFailed(TextComponent::text(format!(
|
|
||||||
"{} is out of bounds.",
|
|
||||||
distance_consumer().default_name()
|
|
||||||
))));
|
|
||||||
};
|
|
||||||
|
|
||||||
if (buffer - border.buffer).abs() < f32::EPSILON {
|
if (buffer - border.buffer).abs() < f32::EPSILON {
|
||||||
return Err(CommandError::CommandFailed(
|
return Err(CommandError::CommandFailed(
|
||||||
@ -462,17 +407,10 @@ impl CommandExecutor for WarningDistanceExecutor {
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
// TODO: Maybe ask player for world, or get the current world
|
// TODO: Maybe ask player for world, or get the current world
|
||||||
let worlds = server.worlds.load();
|
let worlds = server.worlds.load();
|
||||||
let world = worlds
|
let world = worlds.first().ok_or(CommandError::InvalidRequirement)?;
|
||||||
.first()
|
|
||||||
.expect("There should always be at least one world");
|
|
||||||
let mut border = world.worldborder.lock().await;
|
let mut border = world.worldborder.lock().await;
|
||||||
|
|
||||||
let Ok(distance) = warning_distance_consumer().find_arg_default_name(args)? else {
|
let distance = warning_distance_consumer().find_arg_default_name(args)??;
|
||||||
return Err(CommandError::CommandFailed(TextComponent::text(format!(
|
|
||||||
"{} is out of bounds.",
|
|
||||||
distance_consumer().default_name()
|
|
||||||
))));
|
|
||||||
};
|
|
||||||
|
|
||||||
if distance == border.warning_blocks {
|
if distance == border.warning_blocks {
|
||||||
return Err(CommandError::CommandFailed(
|
return Err(CommandError::CommandFailed(
|
||||||
@ -509,17 +447,10 @@ impl CommandExecutor for WarningTimeExecutor {
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
// TODO: Maybe ask player for world, or get the current world
|
// TODO: Maybe ask player for world, or get the current world
|
||||||
let worlds = server.worlds.load();
|
let worlds = server.worlds.load();
|
||||||
let world = worlds
|
let world = worlds.first().ok_or(CommandError::InvalidRequirement)?;
|
||||||
.first()
|
|
||||||
.expect("There should always be at least one world");
|
|
||||||
let mut border = world.worldborder.lock().await;
|
let mut border = world.worldborder.lock().await;
|
||||||
|
|
||||||
let Ok(time) = time_consumer().find_arg_default_name(args)? else {
|
let time = time_consumer().find_arg_default_name(args)??;
|
||||||
return Err(CommandError::CommandFailed(TextComponent::text(format!(
|
|
||||||
"{} is out of bounds.",
|
|
||||||
distance_consumer().default_name()
|
|
||||||
))));
|
|
||||||
};
|
|
||||||
|
|
||||||
if time == border.warning_time {
|
if time == border.warning_time {
|
||||||
return Err(CommandError::CommandFailed(
|
return Err(CommandError::CommandFailed(
|
||||||
|
|||||||
@ -666,7 +666,10 @@ impl CommandDispatcher {
|
|||||||
let mut names = tree.names.iter();
|
let mut names = tree.names.iter();
|
||||||
let permission = permission.into();
|
let permission = permission.into();
|
||||||
|
|
||||||
let primary_name = names.next().expect("at least one name must be provided");
|
let Some(primary_name) = names.next() else {
|
||||||
|
tracing::warn!("Command registration skipped: command tree has no names");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
for name in names {
|
for name in names {
|
||||||
self.commands
|
self.commands
|
||||||
|
|||||||
@ -117,7 +117,7 @@ impl CommandSender {
|
|||||||
let format = time::macros::format_description!("[hour]:[minute]:[second]");
|
let format = time::macros::format_description!("[hour]:[minute]:[second]");
|
||||||
let timestamp = now
|
let timestamp = now
|
||||||
.format(&format)
|
.format(&format)
|
||||||
.expect("Failed to format timestamp for command block output");
|
.unwrap_or_else(|_| "00:00:00".to_string());
|
||||||
|
|
||||||
*last_output = format!("[{}] {}", timestamp, text.get_text());
|
*last_output = format!("[{}] {}", timestamp, text.get_text());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -196,7 +196,7 @@ impl CatEntity {
|
|||||||
let entity = self.get_entity();
|
let entity = self.get_entity();
|
||||||
entity.send_meta_data(
|
entity.send_meta_data(
|
||||||
&[Metadata::new(
|
&[Metadata::new(
|
||||||
TrackedData::COLLAR_COLOR,
|
TrackedData::CAT_COLLAR_COLOR,
|
||||||
MetaDataType::INT,
|
MetaDataType::INT,
|
||||||
VarInt(color as i32),
|
VarInt(color as i32),
|
||||||
)],
|
)],
|
||||||
@ -443,7 +443,7 @@ impl Mob for CatEntity {
|
|||||||
);
|
);
|
||||||
entity.send_meta_data(
|
entity.send_meta_data(
|
||||||
&[Metadata::new(
|
&[Metadata::new(
|
||||||
TrackedData::COLLAR_COLOR,
|
TrackedData::CAT_COLLAR_COLOR,
|
||||||
MetaDataType::INT,
|
MetaDataType::INT,
|
||||||
VarInt(self.collar_color.load(Ordering::Relaxed) as i32),
|
VarInt(self.collar_color.load(Ordering::Relaxed) as i32),
|
||||||
)],
|
)],
|
||||||
|
|||||||
@ -4,7 +4,7 @@ pub mod statistics;
|
|||||||
use core::f32;
|
use core::f32;
|
||||||
use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque};
|
use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque};
|
||||||
use std::f64::consts::TAU;
|
use std::f64::consts::TAU;
|
||||||
use std::num::NonZeroU8;
|
use std::num::NonZero;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::atomic::{AtomicBool, AtomicI8, AtomicI32, AtomicU8, AtomicU32, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicI8, AtomicI32, AtomicU8, AtomicU32, Ordering};
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
@ -374,6 +374,8 @@ pub struct ChunkManager {
|
|||||||
entity_chunk_queue: VecDeque<(Vector2<i32>, Weak<ChunkEntityData>)>,
|
entity_chunk_queue: VecDeque<(Vector2<i32>, Weak<ChunkEntityData>)>,
|
||||||
batches_sent_since_ack: u8,
|
batches_sent_since_ack: u8,
|
||||||
last_chunk_batch_sent_at: Instant,
|
last_chunk_batch_sent_at: Instant,
|
||||||
|
/// The (view, simulation) chunk loading ticket levels currently held at `center`.
|
||||||
|
held_tickets: Option<(i8, i8)>,
|
||||||
/// The current world for chunk loading. Updated on dimension change.
|
/// The current world for chunk loading. Updated on dimension change.
|
||||||
world: Arc<World>,
|
world: Arc<World>,
|
||||||
}
|
}
|
||||||
@ -398,6 +400,7 @@ impl ChunkManager {
|
|||||||
entity_chunk_queue: VecDeque::new(),
|
entity_chunk_queue: VecDeque::new(),
|
||||||
batches_sent_since_ack: 0,
|
batches_sent_since_ack: 0,
|
||||||
last_chunk_batch_sent_at: Instant::now(),
|
last_chunk_batch_sent_at: Instant::now(),
|
||||||
|
held_tickets: None,
|
||||||
world,
|
world,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -413,6 +416,25 @@ impl ChunkManager {
|
|||||||
self.chunk_sent.len()
|
self.chunk_sent.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reset_sent_chunks(&mut self) {
|
||||||
|
self.chunk_sent.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn set_view_distance(&mut self, view_distance: u8) {
|
||||||
|
self.view_distance = view_distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clean(&mut self) {
|
||||||
|
let (_rx, tx) = crossbeam::channel::unbounded();
|
||||||
|
// drop old channel
|
||||||
|
self.chunk_listener = tx;
|
||||||
|
|
||||||
|
// Drop any held chunk references to allow chunks to be unloaded.
|
||||||
|
self.chunk_sent.clear();
|
||||||
|
self.chunk_queue.clear();
|
||||||
|
self.entity_chunk_queue.clear();
|
||||||
|
}
|
||||||
|
|
||||||
fn should_enqueue_chunk(&mut self, position: Vector2<i32>, chunk: &SyncChunk) -> bool {
|
fn should_enqueue_chunk(&mut self, position: Vector2<i32>, chunk: &SyncChunk) -> bool {
|
||||||
self.chunk_sent
|
self.chunk_sent
|
||||||
.insert(position, Arc::downgrade(chunk))
|
.insert(position, Arc::downgrade(chunk))
|
||||||
@ -459,7 +481,6 @@ impl ChunkManager {
|
|||||||
) {
|
) {
|
||||||
view_distance += 1; // Margin for loading
|
view_distance += 1; // Margin for loading
|
||||||
let old_center = self.center;
|
let old_center = self.center;
|
||||||
let old_view_distance = self.view_distance;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut lock = level
|
let mut lock = level
|
||||||
@ -475,11 +496,13 @@ impl ChunkManager {
|
|||||||
let sim_level = ChunkLoading::get_level_from_simulation_distance(sim_dist);
|
let sim_level = ChunkLoading::get_level_from_simulation_distance(sim_dist);
|
||||||
lock.add_ticket(center, sim_level);
|
lock.add_ticket(center, sim_level);
|
||||||
|
|
||||||
if (old_center != center || old_view_distance != view_distance) && old_view_distance > 0
|
// Drop exactly the pair we last added rather than recomputing it. The
|
||||||
{
|
// simulation level is derived from live config and the view level from the
|
||||||
let old_level = ChunkLoading::get_level_from_view_distance(old_view_distance);
|
// previous view distance, so recomputing them can release a ticket we never
|
||||||
lock.remove_ticket(old_center, old_level);
|
// took and strand the one we did.
|
||||||
lock.remove_ticket(old_center, sim_level);
|
if let Some((held_view, held_sim)) = self.held_tickets.replace((new_level, sim_level)) {
|
||||||
|
lock.remove_ticket(old_center, held_view);
|
||||||
|
lock.remove_ticket(old_center, held_sim);
|
||||||
}
|
}
|
||||||
lock.send_change();
|
lock.send_change();
|
||||||
};
|
};
|
||||||
@ -528,11 +551,13 @@ impl ChunkManager {
|
|||||||
.chunk_loading
|
.chunk_loading
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||||
lock.remove_ticket(
|
if let Some((view_level, sim_level)) = self.held_tickets.take() {
|
||||||
self.center,
|
lock.remove_ticket(self.center, view_level);
|
||||||
ChunkLoading::get_level_from_view_distance(self.view_distance),
|
lock.remove_ticket(self.center, sim_level);
|
||||||
);
|
}
|
||||||
lock.send_change();
|
lock.send_change();
|
||||||
|
level.should_unload.store(true, Ordering::Relaxed);
|
||||||
|
level.level_channel.notify();
|
||||||
let (_rx, tx) = crossbeam::channel::unbounded();
|
let (_rx, tx) = crossbeam::channel::unbounded();
|
||||||
// drop old channel
|
// drop old channel
|
||||||
self.chunk_listener = tx;
|
self.chunk_listener = tx;
|
||||||
@ -543,6 +568,7 @@ impl ChunkManager {
|
|||||||
self.entity_chunk_queue.clear();
|
self.entity_chunk_queue.clear();
|
||||||
self.batches_sent_since_ack = 0;
|
self.batches_sent_since_ack = 0;
|
||||||
self.last_chunk_batch_sent_at = Instant::now();
|
self.last_chunk_batch_sent_at = Instant::now();
|
||||||
|
self.view_distance = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn change_world(&mut self, old_level: &Arc<Level>, new_world: Arc<World>) {
|
pub fn change_world(&mut self, old_level: &Arc<Level>, new_world: Arc<World>) {
|
||||||
@ -550,15 +576,19 @@ impl ChunkManager {
|
|||||||
.chunk_loading
|
.chunk_loading
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||||
lock.remove_ticket(
|
if let Some((view_level, sim_level)) = self.held_tickets.take() {
|
||||||
self.center,
|
lock.remove_ticket(self.center, view_level);
|
||||||
ChunkLoading::get_level_from_view_distance(self.view_distance),
|
lock.remove_ticket(self.center, sim_level);
|
||||||
);
|
}
|
||||||
lock.send_change();
|
lock.send_change();
|
||||||
|
old_level.should_unload.store(true, Ordering::Relaxed);
|
||||||
|
old_level.level_channel.notify();
|
||||||
drop(lock);
|
drop(lock);
|
||||||
self.chunk_listener = new_world.level.chunk_listener.add_global_chunk_listener();
|
self.chunk_listener = new_world.level.chunk_listener.add_global_chunk_listener();
|
||||||
self.chunk_sent.clear();
|
self.chunk_sent.clear();
|
||||||
self.chunk_queue.clear();
|
self.chunk_queue.clear();
|
||||||
|
self.entity_chunk_queue.clear();
|
||||||
|
self.view_distance = 0;
|
||||||
self.world = new_world;
|
self.world = new_world;
|
||||||
// Reset batch state so chunks can be sent immediately in the new dimension
|
// Reset batch state so chunks can be sent immediately in the new dimension
|
||||||
self.batches_sent_since_ack = 0;
|
self.batches_sent_since_ack = 0;
|
||||||
@ -953,7 +983,7 @@ impl Player {
|
|||||||
watched_section: AtomicCell::new(Cylindrical::new(
|
watched_section: AtomicCell::new(Cylindrical::new(
|
||||||
Vector2::new(0, 0),
|
Vector2::new(0, 0),
|
||||||
// Since 1 is not possible in vanilla it is used as uninit
|
// Since 1 is not possible in vanilla it is used as uninit
|
||||||
NonZeroU8::new(1).unwrap_or(NonZeroU8::MIN),
|
NonZero::new(1).unwrap_or(NonZero::<u8>::MIN),
|
||||||
)),
|
)),
|
||||||
last_action_time: AtomicCell::new(std::time::Instant::now()),
|
last_action_time: AtomicCell::new(std::time::Instant::now()),
|
||||||
ping: AtomicU32::new(0),
|
ping: AtomicU32::new(0),
|
||||||
@ -3165,7 +3195,7 @@ impl Player {
|
|||||||
|
|
||||||
self.watched_section.store(Cylindrical::new(
|
self.watched_section.store(Cylindrical::new(
|
||||||
Vector2::new(0, 0),
|
Vector2::new(0, 0),
|
||||||
NonZeroU8::new(1).unwrap_or(NonZeroU8::MIN),
|
NonZero::new(1).unwrap_or(NonZero::<u8>::MIN),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use std::{
|
use std::{
|
||||||
num::{NonZero, NonZeroI32},
|
num::NonZero,
|
||||||
sync::{Arc, atomic::Ordering},
|
sync::{Arc, atomic::Ordering},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,7 @@ impl BedrockClient {
|
|||||||
|
|
||||||
let view_distance = chunk_radius.clamp(
|
let view_distance = chunk_radius.clamp(
|
||||||
2,
|
2,
|
||||||
NonZeroI32::from(server.advanced_config.networking.bedrock.view_distance).get(),
|
NonZero::<i32>::from(server.advanced_config.networking.bedrock.view_distance).get(),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.enqueue_packet(&CChunkRadiusUpdate {
|
self.enqueue_packet(&CChunkRadiusUpdate {
|
||||||
|
|||||||
@ -22,8 +22,8 @@ impl JavaClient {
|
|||||||
self.config.store(Arc::new(PlayerConfig {
|
self.config.store(Arc::new(PlayerConfig {
|
||||||
locale: client_information.locale.to_string(),
|
locale: client_information.locale.to_string(),
|
||||||
// client_information.view_distance was checked above to be > 0 so compiler should optimize this out.
|
// client_information.view_distance was checked above to be > 0 so compiler should optimize this out.
|
||||||
view_distance: NonZeroU8::new(client_information.view_distance as u8)
|
view_distance: NonZero::new(client_information.view_distance as u8)
|
||||||
.unwrap_or(NonZeroU8::MIN),
|
.unwrap_or(NonZero::<u8>::MIN),
|
||||||
chat_mode,
|
chat_mode,
|
||||||
chat_colors: client_information.chat_colors,
|
chat_colors: client_information.chat_colors,
|
||||||
skin_parts: client_information.skin_parts,
|
skin_parts: client_information.skin_parts,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use std::{num::NonZeroU8, sync::Arc, sync::atomic::Ordering};
|
use std::{num::NonZero, sync::Arc, sync::atomic::Ordering};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
entity::player::ChatMode,
|
entity::player::ChatMode,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use std::{net::SocketAddr, num::NonZeroU8, sync::Arc};
|
use std::{net::SocketAddr, num::NonZero, sync::Arc};
|
||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use crossbeam::atomic::AtomicCell;
|
use crossbeam::atomic::AtomicCell;
|
||||||
@ -423,8 +423,8 @@ impl PendingConnection {
|
|||||||
) {
|
) {
|
||||||
self.config = Some(PlayerConfig {
|
self.config = Some(PlayerConfig {
|
||||||
locale: client_information.locale.to_string(),
|
locale: client_information.locale.to_string(),
|
||||||
view_distance: NonZeroU8::new(client_information.view_distance as u8)
|
view_distance: NonZero::new(client_information.view_distance as u8)
|
||||||
.unwrap_or(NonZeroU8::MIN),
|
.unwrap_or(NonZero::<u8>::MIN),
|
||||||
chat_mode,
|
chat_mode,
|
||||||
chat_colors: client_information.chat_colors,
|
chat_colors: client_information.chat_colors,
|
||||||
skin_parts: client_information.skin_parts,
|
skin_parts: client_information.skin_parts,
|
||||||
|
|||||||
@ -45,7 +45,7 @@ impl JavaClient {
|
|||||||
|
|
||||||
// 3. Construct the new config
|
// 3. Construct the new config
|
||||||
// If view_distance is 0, we exit early (safe guard)
|
// If view_distance is 0, we exit early (safe guard)
|
||||||
let Some(new_view_distance) = NonZeroU8::new(new_view_distance_raw) else {
|
let Some(new_view_distance) = NonZero::new(new_view_distance_raw) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ use pumpkin_util::{Hand, PermissionLvl};
|
|||||||
use rsa::pkcs1v15::{Signature as RsaPkcs1v15Signature, VerifyingKey};
|
use rsa::pkcs1v15::{Signature as RsaPkcs1v15Signature, VerifyingKey};
|
||||||
use rsa::signature::Verifier;
|
use rsa::signature::Verifier;
|
||||||
use sha1::Sha1;
|
use sha1::Sha1;
|
||||||
use std::num::NonZeroU8;
|
use std::num::NonZero;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicU32, Ordering};
|
use std::sync::atomic::{AtomicU32, Ordering};
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|||||||
@ -8,7 +8,7 @@ use bytes::Bytes;
|
|||||||
use pumpkin_world::level::SyncChunk;
|
use pumpkin_world::level::SyncChunk;
|
||||||
use std::{
|
use std::{
|
||||||
net::SocketAddr,
|
net::SocketAddr,
|
||||||
num::NonZeroU8,
|
num::NonZero,
|
||||||
sync::{Arc, atomic::Ordering},
|
sync::{Arc, atomic::Ordering},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ pub struct PlayerConfig {
|
|||||||
/// The player's preferred language.
|
/// The player's preferred language.
|
||||||
pub locale: String, // 16
|
pub locale: String, // 16
|
||||||
/// The maximum distance at which chunks are rendered.
|
/// The maximum distance at which chunks are rendered.
|
||||||
pub view_distance: NonZeroU8,
|
pub view_distance: NonZero<u8>,
|
||||||
/// The player's chat mode settings
|
/// The player's chat mode settings
|
||||||
pub chat_mode: ChatMode,
|
pub chat_mode: ChatMode,
|
||||||
/// Whether chat colors are enabled.
|
/// Whether chat colors are enabled.
|
||||||
@ -98,7 +98,7 @@ impl Default for PlayerConfig {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
locale: "en_us".to_string(),
|
locale: "en_us".to_string(),
|
||||||
view_distance: NonZeroU8::new(8).unwrap_or(NonZeroU8::MIN),
|
view_distance: NonZero::new(8).unwrap_or(NonZero::<u8>::MIN),
|
||||||
chat_mode: ChatMode::Enabled,
|
chat_mode: ChatMode::Enabled,
|
||||||
chat_colors: true,
|
chat_colors: true,
|
||||||
skin_parts: 0x7F,
|
skin_parts: 0x7F,
|
||||||
|
|||||||
@ -133,7 +133,11 @@ impl boss_bar::HostBossBar for PluginHostState {
|
|||||||
bossbar.color = from_wit_color(color);
|
bossbar.color = from_wit_color(color);
|
||||||
bossbar.division = from_wit_division(division);
|
bossbar.division = from_wit_division(division);
|
||||||
|
|
||||||
let server = self.server.as_ref().expect("server not available").clone();
|
let server = self
|
||||||
|
.server
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| wasmtime::Error::msg("server not available"))?
|
||||||
|
.clone();
|
||||||
let plugin_bossbar = Arc::new(Mutex::new(PluginBossBar::new(
|
let plugin_bossbar = Arc::new(Mutex::new(PluginBossBar::new(
|
||||||
bossbar,
|
bossbar,
|
||||||
Arc::downgrade(&server),
|
Arc::downgrade(&server),
|
||||||
|
|||||||
@ -666,7 +666,10 @@ impl HostEntity for PluginHostState {
|
|||||||
let entity = entity_from_resource(self, &entity)?;
|
let entity = entity_from_resource(self, &entity)?;
|
||||||
let attribute = from_wit_attribute(attr);
|
let attribute = from_wit_attribute(attr);
|
||||||
if let Some(living) = entity.get_living_entity() {
|
if let Some(living) = entity.get_living_entity() {
|
||||||
let map = living.attributes.read().unwrap();
|
let map = living
|
||||||
|
.attributes
|
||||||
|
.read()
|
||||||
|
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||||
if let Some(inst) = map.get(&attribute.id) {
|
if let Some(inst) = map.get(&attribute.id) {
|
||||||
return Ok(inst
|
return Ok(inst
|
||||||
.modifiers
|
.modifiers
|
||||||
@ -691,7 +694,10 @@ impl HostEntity for PluginHostState {
|
|||||||
let attribute = from_wit_attribute(attr);
|
let attribute = from_wit_attribute(attr);
|
||||||
if let Some(living) = entity.get_living_entity() {
|
if let Some(living) = entity.get_living_entity() {
|
||||||
{
|
{
|
||||||
let mut map = living.attributes.write().unwrap();
|
let mut map = living
|
||||||
|
.attributes
|
||||||
|
.write()
|
||||||
|
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||||
map.remove(&attribute.id);
|
map.remove(&attribute.id);
|
||||||
};
|
};
|
||||||
crate::entity::attributes::send_attribute_updates_for_living(
|
crate::entity::attributes::send_attribute_updates_for_living(
|
||||||
|
|||||||
@ -95,7 +95,7 @@ pub(super) fn to_wasm_block_name(block: &'static Block) -> String {
|
|||||||
|
|
||||||
pub(super) fn from_wasm_block_name(block_name: &str) -> &'static Block {
|
pub(super) fn from_wasm_block_name(block_name: &str) -> &'static Block {
|
||||||
Block::from_registry_key(block_name.strip_prefix("minecraft:").unwrap_or(block_name))
|
Block::from_registry_key(block_name.strip_prefix("minecraft:").unwrap_or(block_name))
|
||||||
.expect("invalid block name")
|
.unwrap_or(&Block::AIR)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn to_wasm_entity_type(entity_type: &'static EntityType) -> String {
|
pub(super) fn to_wasm_entity_type(entity_type: &'static EntityType) -> String {
|
||||||
@ -103,7 +103,12 @@ pub(super) fn to_wasm_entity_type(entity_type: &'static EntityType) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn from_wasm_entity_type(entity_type: &str) -> &'static EntityType {
|
pub(super) fn from_wasm_entity_type(entity_type: &str) -> &'static EntityType {
|
||||||
EntityType::from_name(entity_type).expect("invalid entity type")
|
EntityType::from_name(
|
||||||
|
entity_type
|
||||||
|
.strip_prefix("minecraft:")
|
||||||
|
.unwrap_or(entity_type),
|
||||||
|
)
|
||||||
|
.unwrap_or(&EntityType::PLAYER)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) const fn to_wasm_hand(hand: Hand) -> pumpkin::plugin::common::Hand {
|
pub(super) const fn to_wasm_hand(hand: Hand) -> pumpkin::plugin::common::Hand {
|
||||||
@ -228,10 +233,9 @@ impl<E: Payload + ToFromWasmEvent> EventHandler<E> for WasmPluginEventHandler {
|
|||||||
let event = event.to_wasm_event(store.data_mut());
|
let event = event.to_wasm_event(store.data_mut());
|
||||||
match self.plugin.plugin_instance {
|
match self.plugin.plugin_instance {
|
||||||
PluginInstance::V0_1(ref plugin) => {
|
PluginInstance::V0_1(ref plugin) => {
|
||||||
let server = store
|
let Ok(server) = store.data_mut().add_server(server.clone()) else {
|
||||||
.data_mut()
|
return;
|
||||||
.add_server(server.clone())
|
};
|
||||||
.expect("valid server");
|
|
||||||
let _ = plugin
|
let _ = plugin
|
||||||
.call_handle_event(&mut *store, self.handler_id, server, &event)
|
.call_handle_event(&mut *store, self.handler_id, server, &event)
|
||||||
.await;
|
.await;
|
||||||
@ -250,10 +254,9 @@ impl<E: Payload + ToFromWasmEvent> EventHandler<E> for WasmPluginEventHandler {
|
|||||||
let wasm_event = event.to_wasm_event(store.data_mut());
|
let wasm_event = event.to_wasm_event(store.data_mut());
|
||||||
match self.plugin.plugin_instance {
|
match self.plugin.plugin_instance {
|
||||||
PluginInstance::V0_1(ref plugin) => {
|
PluginInstance::V0_1(ref plugin) => {
|
||||||
let server = store
|
let Ok(server) = store.data_mut().add_server(server.clone()) else {
|
||||||
.data_mut()
|
return;
|
||||||
.add_server(server.clone())
|
};
|
||||||
.expect("valid server");
|
|
||||||
if let Ok(returned_event) = plugin
|
if let Ok(returned_event) = plugin
|
||||||
.call_handle_event(&mut *store, self.handler_id, server, &wasm_event)
|
.call_handle_event(&mut *store, self.handler_id, server, &wasm_event)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@ -1199,10 +1199,12 @@ impl ToFromWasmEvent for AsyncPlayerPreLoginEvent {
|
|||||||
Event::AsyncPlayerPreLoginEvent(data) => Self {
|
Event::AsyncPlayerPreLoginEvent(data) => Self {
|
||||||
player_name: data.player_name,
|
player_name: data.player_name,
|
||||||
player_uuid: data.player_uuid.parse().unwrap_or_default(),
|
player_uuid: data.player_uuid.parse().unwrap_or_default(),
|
||||||
ip_address: data
|
ip_address: data.ip_address.parse().unwrap_or_else(|_| {
|
||||||
.ip_address
|
std::net::SocketAddr::new(
|
||||||
.parse()
|
std::net::IpAddr::V4(std::net::Ipv4Addr::LOCALHOST),
|
||||||
.unwrap_or_else(|_| "127.0.0.1:0".parse().unwrap()),
|
0,
|
||||||
|
)
|
||||||
|
}),
|
||||||
kick_message: consume_text_component(state, &data.kick_message),
|
kick_message: consume_text_component(state, &data.kick_message),
|
||||||
cancelled: data.cancelled,
|
cancelled: data.cancelled,
|
||||||
},
|
},
|
||||||
@ -1912,10 +1914,12 @@ impl ToFromWasmEvent for PlayerPreLoginEvent {
|
|||||||
Event::PlayerPreLoginEvent(data) => Self {
|
Event::PlayerPreLoginEvent(data) => Self {
|
||||||
player_name: data.player_name,
|
player_name: data.player_name,
|
||||||
player_uuid: data.player_uuid.parse().unwrap_or_default(),
|
player_uuid: data.player_uuid.parse().unwrap_or_default(),
|
||||||
ip_address: data
|
ip_address: data.ip_address.parse().unwrap_or_else(|_| {
|
||||||
.ip_address
|
std::net::SocketAddr::new(
|
||||||
.parse()
|
std::net::IpAddr::V4(std::net::Ipv4Addr::LOCALHOST),
|
||||||
.unwrap_or_else(|_| "127.0.0.1:0".parse().unwrap()),
|
0,
|
||||||
|
)
|
||||||
|
}),
|
||||||
kick_message: consume_text_component(state, &data.kick_message),
|
kick_message: consume_text_component(state, &data.kick_message),
|
||||||
cancelled: data.cancelled,
|
cancelled: data.cancelled,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -12,12 +12,15 @@ impl pumpkin::plugin::ipc::Host for PluginHostState {
|
|||||||
recipient: PluginId,
|
recipient: PluginId,
|
||||||
message: IpcMessage,
|
message: IpcMessage,
|
||||||
) -> wasmtime::Result<Result<Result<IpcMessage, String>, ()>> {
|
) -> wasmtime::Result<Result<Result<IpcMessage, String>, ()>> {
|
||||||
Ok(self
|
let Some(server) = &self.server else {
|
||||||
.server
|
return Err(wasmtime::Error::msg("Server not available"));
|
||||||
.as_ref()
|
};
|
||||||
.unwrap()
|
let Some(name) = &self.name else {
|
||||||
|
return Err(wasmtime::Error::msg("Plugin name not available"));
|
||||||
|
};
|
||||||
|
Ok(server
|
||||||
.plugin_manager
|
.plugin_manager
|
||||||
.send_message(self.name.as_ref().unwrap(), &recipient, &message)
|
.send_message(name, &recipient, &message)
|
||||||
.await)
|
.await)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1047,9 +1047,7 @@ impl Server {
|
|||||||
.map_or_else(Vec::new, |player| vec![player]),
|
.map_or_else(Vec::new, |player| vec![player]),
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(player_type) = EntityType::from_name("player") else {
|
let player_type = &EntityType::PLAYER;
|
||||||
return Vec::new();
|
|
||||||
};
|
|
||||||
let type_included = target_selector
|
let type_included = target_selector
|
||||||
.conditions
|
.conditions
|
||||||
.iter()
|
.iter()
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use pumpkin_util::math::vector2::Vector2;
|
use pumpkin_util::math::vector2::Vector2;
|
||||||
use std::{num::NonZeroU8, sync::Arc};
|
use std::{num::NonZero, sync::Arc};
|
||||||
|
|
||||||
use pumpkin_protocol::{
|
use pumpkin_protocol::{
|
||||||
bedrock::client::network_chunk_publisher_update::CNetworkChunkPublisherUpdate,
|
bedrock::client::network_chunk_publisher_update::CNetworkChunkPublisherUpdate,
|
||||||
@ -12,8 +12,8 @@ use crate::{
|
|||||||
net::ClientPlatform,
|
net::ClientPlatform,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn get_view_distance(player: &Player) -> NonZeroU8 {
|
pub fn get_view_distance(player: &Player) -> NonZero<u8> {
|
||||||
let fallback = NonZeroU8::new(2).unwrap_or(NonZeroU8::MIN);
|
let fallback = NonZero::new(2).unwrap_or(NonZero::<u8>::MIN);
|
||||||
let Some(server) = player.world().server.upgrade() else {
|
let Some(server) = player.world().server.upgrade() else {
|
||||||
return fallback;
|
return fallback;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -16,7 +16,7 @@ serde_repr = { version = "0.1" }
|
|||||||
serde_json = { version = "1.0", features = ["preserve_order"] }
|
serde_json = { version = "1.0", features = ["preserve_order"] }
|
||||||
serde_json5 = "0.2"
|
serde_json5 = "0.2"
|
||||||
|
|
||||||
wit-encoder = "0.255.0"
|
wit-encoder = "0.256.0"
|
||||||
semver = "1.0"
|
semver = "1.0"
|
||||||
rayon = "1.12.0"
|
rayon = "1.12.0"
|
||||||
|
|
||||||
|
|||||||
@ -128,7 +128,7 @@ pub fn build() -> TokenStream {
|
|||||||
pub struct VeryBiasedToBottomHeightProvider {
|
pub struct VeryBiasedToBottomHeightProvider {
|
||||||
pub min_inclusive: YOffset,
|
pub min_inclusive: YOffset,
|
||||||
pub max_inclusive: YOffset,
|
pub max_inclusive: YOffset,
|
||||||
pub inner: Option<std::num::NonZeroU32>,
|
pub inner: Option<std::num::NonZero<u32>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CaveCarverConfig {
|
pub struct CaveCarverConfig {
|
||||||
|
|||||||
@ -486,7 +486,7 @@ pub fn build() -> TokenStream {
|
|||||||
use crate::chunk::DoublePerlinNoiseParameters;
|
use crate::chunk::DoublePerlinNoiseParameters;
|
||||||
use crate::BlockState;
|
use crate::BlockState;
|
||||||
|
|
||||||
use std::{cell::RefCell, num::NonZeroUsize};
|
use std::cell::RefCell;
|
||||||
use pumpkin_util::random::RandomDeriver;
|
use pumpkin_util::random::RandomDeriver;
|
||||||
use pumpkin_util::y_offset::YOffset;
|
use pumpkin_util::y_offset::YOffset;
|
||||||
use crate::biome::Biome;
|
use crate::biome::Biome;
|
||||||
|
|||||||
@ -506,7 +506,7 @@ pub fn value_to_height_provider(v: &Value) -> TokenStream {
|
|||||||
quote! { None }
|
quote! { None }
|
||||||
} else {
|
} else {
|
||||||
let n = v["inner"].as_u64().unwrap_or(1) as u32;
|
let n = v["inner"].as_u64().unwrap_or(1) as u32;
|
||||||
quote! { std::num::NonZeroU32::new(#n) }
|
quote! { std::num::NonZero::new(#n) }
|
||||||
};
|
};
|
||||||
quote! {
|
quote! {
|
||||||
HeightProvider::VeryBiasedToBottom(VeryBiasedToBottomHeightProvider {
|
HeightProvider::VeryBiasedToBottom(VeryBiasedToBottomHeightProvider {
|
||||||
|
|||||||
@ -44,6 +44,67 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
parsed.insert("WOLF_VARIANT_ID".to_owned(), id);
|
parsed.insert("WOLF_VARIANT_ID".to_owned(), id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let cat_variant_id = match ver {
|
||||||
|
JavaMinecraftVersion::V_26_1 | JavaMinecraftVersion::V_26_2 => Some(20),
|
||||||
|
_ => parsed.get("CAT_VARIANT").copied().or(Some(19)),
|
||||||
|
};
|
||||||
|
if let Some(id) = cat_variant_id {
|
||||||
|
parsed.insert("CAT_VARIANT".to_owned(), id);
|
||||||
|
parsed.insert("CAT_VARIANT_ID".to_owned(), id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let cat_collar_color_id = match ver {
|
||||||
|
JavaMinecraftVersion::V_26_1 | JavaMinecraftVersion::V_26_2 => Some(23),
|
||||||
|
_ => Some(22),
|
||||||
|
};
|
||||||
|
if let Some(id) = cat_collar_color_id {
|
||||||
|
parsed.insert("CAT_COLLAR_COLOR".to_owned(), id);
|
||||||
|
parsed.insert("CAT_COLLAR_COLOR_ID".to_owned(), id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let wolf_collar_color_id = match ver {
|
||||||
|
JavaMinecraftVersion::V_26_1 | JavaMinecraftVersion::V_26_2 => Some(21),
|
||||||
|
_ => Some(20),
|
||||||
|
};
|
||||||
|
if let Some(id) = wolf_collar_color_id {
|
||||||
|
parsed.insert("WOLF_COLLAR_COLOR".to_owned(), id);
|
||||||
|
parsed.insert("WOLF_COLLAR_COLOR_ID".to_owned(), id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let sound_variant_id = match ver {
|
||||||
|
JavaMinecraftVersion::V_26_1 | JavaMinecraftVersion::V_26_2 => Some(24),
|
||||||
|
JavaMinecraftVersion::V_1_21_5
|
||||||
|
| JavaMinecraftVersion::V_1_21_6
|
||||||
|
| JavaMinecraftVersion::V_1_21_7
|
||||||
|
| JavaMinecraftVersion::V_1_21_9
|
||||||
|
| JavaMinecraftVersion::V_1_21_11 => Some(23),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
if let Some(id) = sound_variant_id {
|
||||||
|
parsed.insert("SOUND_VARIANT".to_owned(), id);
|
||||||
|
parsed.insert("SOUND_VARIANT_ID".to_owned(), id);
|
||||||
|
parsed.insert("CAT_SOUND_VARIANT_ID".to_owned(), id);
|
||||||
|
parsed.insert("WOLF_SOUND_VARIANT_ID".to_owned(), id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let is_lying_id = match ver {
|
||||||
|
JavaMinecraftVersion::V_26_1 | JavaMinecraftVersion::V_26_2 => Some(21),
|
||||||
|
_ => Some(20),
|
||||||
|
};
|
||||||
|
if let Some(id) = is_lying_id {
|
||||||
|
parsed.insert("IS_LYING".to_owned(), id);
|
||||||
|
parsed.insert("IN_SLEEPING_POSE".to_owned(), id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let relax_state_one_id = match ver {
|
||||||
|
JavaMinecraftVersion::V_26_1 | JavaMinecraftVersion::V_26_2 => Some(22),
|
||||||
|
_ => Some(21),
|
||||||
|
};
|
||||||
|
if let Some(id) = relax_state_one_id {
|
||||||
|
parsed.insert("RELAX_STATE_ONE".to_owned(), id);
|
||||||
|
parsed.insert("HEAD_DOWN".to_owned(), id);
|
||||||
|
}
|
||||||
|
|
||||||
versions.insert(ver, parsed);
|
versions.insert(ver, parsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,10 +183,15 @@ fn generate_consts(versions: &BTreeMap<JavaMinecraftVersion, BTreeMap<String, u8
|
|||||||
// Some versions prefix keys with DATA_ (Bedrock), others don't (Java)
|
// Some versions prefix keys with DATA_ (Bedrock), others don't (Java)
|
||||||
// Try both forms so every version resolves correctly
|
// Try both forms so every version resolves correctly
|
||||||
let prefixed = format!("DATA_{final_name}");
|
let prefixed = format!("DATA_{final_name}");
|
||||||
let aliases: &[&str] = if final_name == "CUSTOM_NAME_VISIBLE" {
|
let aliases: &[&str] = match final_name.as_str() {
|
||||||
&["NAME_VISIBLE"]
|
"CUSTOM_NAME_VISIBLE" => &["NAME_VISIBLE"],
|
||||||
} else {
|
"IS_LYING" => &["IN_SLEEPING_POSE"],
|
||||||
&[]
|
"IN_SLEEPING_POSE" => &["IS_LYING"],
|
||||||
|
"RELAX_STATE_ONE" => &["HEAD_DOWN"],
|
||||||
|
"HEAD_DOWN" => &["RELAX_STATE_ONE"],
|
||||||
|
"SOUND_VARIANT" => &["SOUND_VARIANT_ID", "DATA_SOUND_VARIANT_ID"],
|
||||||
|
"SOUND_VARIANT_ID" => &["SOUND_VARIANT", "DATA_SOUND_VARIANT_ID"],
|
||||||
|
_ => &[],
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut fields = TokenStream::new();
|
let mut fields = TokenStream::new();
|
||||||
@ -184,6 +250,51 @@ mod tests {
|
|||||||
assert!(wolf.contains("v26_2 : 23u8"));
|
assert!(wolf.contains("v26_2 : 23u8"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cat_trackers_keep_their_entity_specific_tracker_ids() {
|
||||||
|
let generated = build().to_string();
|
||||||
|
|
||||||
|
assert!(generated.contains("CAT_VARIANT"));
|
||||||
|
let cat_variant = generated
|
||||||
|
.split("CAT_VARIANT")
|
||||||
|
.nth(1)
|
||||||
|
.expect("cat variant constant");
|
||||||
|
assert!(cat_variant.contains("v1_21_11 : 19u8"));
|
||||||
|
assert!(cat_variant.contains("v26_2 : 20u8"));
|
||||||
|
|
||||||
|
assert!(generated.contains("IS_LYING"));
|
||||||
|
let is_lying = generated
|
||||||
|
.split("IS_LYING")
|
||||||
|
.nth(1)
|
||||||
|
.expect("is lying constant");
|
||||||
|
assert!(is_lying.contains("v1_21_11 : 20u8"));
|
||||||
|
assert!(is_lying.contains("v26_2 : 21u8"));
|
||||||
|
|
||||||
|
assert!(generated.contains("RELAX_STATE_ONE"));
|
||||||
|
let relax = generated
|
||||||
|
.split("RELAX_STATE_ONE")
|
||||||
|
.nth(1)
|
||||||
|
.expect("relax state one constant");
|
||||||
|
assert!(relax.contains("v1_21_11 : 21u8"));
|
||||||
|
assert!(relax.contains("v26_2 : 22u8"));
|
||||||
|
|
||||||
|
assert!(generated.contains("CAT_COLLAR_COLOR"));
|
||||||
|
let collar = generated
|
||||||
|
.split("CAT_COLLAR_COLOR")
|
||||||
|
.nth(1)
|
||||||
|
.expect("cat collar color constant");
|
||||||
|
assert!(collar.contains("v1_21_11 : 22u8"));
|
||||||
|
assert!(collar.contains("v26_2 : 23u8"));
|
||||||
|
|
||||||
|
assert!(generated.contains("SOUND_VARIANT"));
|
||||||
|
let sound = generated
|
||||||
|
.split("SOUND_VARIANT")
|
||||||
|
.nth(1)
|
||||||
|
.expect("sound variant constant");
|
||||||
|
assert!(sound.contains("v1_21_11 : 23u8"));
|
||||||
|
assert!(sound.contains("v26_2 : 24u8"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn checked_in_tracker_table_matches_codegen() {
|
fn checked_in_tracker_table_matches_codegen() {
|
||||||
let checked_in =
|
let checked_in =
|
||||||
|
|||||||
@ -9,7 +9,7 @@ license.workspace = true
|
|||||||
tokio = { workspace = true, features = ["full"] }
|
tokio = { workspace = true, features = ["full"] }
|
||||||
clap = { version = "4", features = ["derive"] }
|
clap = { version = "4", features = ["derive"] }
|
||||||
colored.workspace = true
|
colored.workspace = true
|
||||||
rand = "0.9"
|
rand.workspace = true
|
||||||
|
|
||||||
[lints.clippy]
|
[lints.clippy]
|
||||||
expect_used = "allow"
|
expect_used = "allow"
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use clap::{Parser, ValueEnum};
|
use clap::{Parser, ValueEnum};
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use rand::Rng;
|
use rand::RngExt;
|
||||||
use std::{
|
use std::{
|
||||||
net::SocketAddr,
|
net::SocketAddr,
|
||||||
sync::{
|
sync::{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user