diff --git a/Cargo.lock b/Cargo.lock index 1c5a7b86b..16fd6b7fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -281,9 +281,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.53" +version = "1.2.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "755d2fce177175ffca841e9a06afdb2c4ab0f593d53b4dee48147dfaade85932" +checksum = "6354c81bbfd62d9cfa9cb3c773c2b7b2a3a482d569de977fd0e961f6e7c00583" dependencies = [ "find-msvc-tools", "shlex", @@ -318,13 +318,13 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chacha20" -version = "0.10.0-rc.8" +version = "0.10.0-rc.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31cd65b2ca03198c223cd9a8fa1152c4ec251cd79049f6dc584152ad3fb5ba9d" +checksum = "c81d916c6ae06736ec667b51f95ee5ff660a75f4ea6ce1bd932c942365c0ea43" dependencies = [ "cfg-if", "cpufeatures", - "rand_core 0.10.0-rc-5", + "rand_core 0.10.0-rc-6", ] [[package]] @@ -366,18 +366,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.54" +version = "4.5.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" +checksum = "3e34525d5bbbd55da2bb745d34b36121baac88d07619a9a09cfcf4a6c0832785" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.54" +version = "4.5.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" +checksum = "59a20016a20a3da95bef50ec7238dbd09baeef4311dcdd38ec15aba69812fb61" dependencies = [ "anstyle", "clap_lex", @@ -636,15 +636,14 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crossfire" -version = "2.1.10" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd901251b9b46c1752c85edfee0aee718c03a85a065f4126d32e5d6d419edf48" +checksum = "7e1ff29ef3add47897a4dab381889ccf8dedcedec4e2c8feed37efcf22a6392b" dependencies = [ - "crossbeam-queue", "crossbeam-utils", - "enum_dispatch", "futures-core", "parking_lot", + "smallvec", ] [[package]] @@ -667,13 +666,13 @@ dependencies = [ [[package]] name = "crypto-bigint" -version = "0.7.0-rc.21" +version = "0.7.0-rc.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9f9a78b88bb8255ec59a81423aa92ada22f96883f9ae59dcb68613907636ae5" +checksum = "053c3561863ce55e3226ecc48b08679f4b66cb1b92b9afb42c2c402dfe8b9b51" dependencies = [ "ctutils", "num-traits", - "rand_core 0.10.0-rc-5", + "rand_core 0.10.0-rc-6", "serdect", "zeroize", ] @@ -699,13 +698,13 @@ dependencies = [ [[package]] name = "crypto-primes" -version = "0.7.0-pre.7" +version = "0.7.0-pre.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6372ba15f988d7cd77e9cfbc42b269601c006f2f16a21a72b886136caf04bfb" +checksum = "334a79c97c0b7fa536716dc132fd417d0afbf471440a41fc25a5d9f66d8771cd" dependencies = [ - "crypto-bigint 0.7.0-rc.21", + "crypto-bigint 0.7.0-rc.22", "libm", - "rand_core 0.10.0-rc-5", + "rand_core 0.10.0-rc-6", ] [[package]] @@ -776,9 +775,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.11.0-rc.8" +version = "0.11.0-rc.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fc1408b7a9f59a7b933faff3e9e7fc15a05a524effd3b3d1601156944c8077f" +checksum = "bff8de092798697546237a3a701e4174fe021579faec9b854379af9bf1e31962" dependencies = [ "block-buffer 0.11.0", "const-oid 0.10.2", @@ -959,6 +958,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "foldhash" version = "0.2.0" @@ -1099,15 +1104,16 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.4.0-rc.0" +version = "0.4.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b99f0d993a2b9b97b9a201193aa8ad21305cde06a3be9a7e1f8f4201e5cc27e" +checksum = "74f70a332ddf75e5e5e43284304179ba02f391f82f692f030b08a8378adf3c99" dependencies = [ "cfg-if", "libc", "r-efi", - "rand_core 0.10.0-rc-5", + "rand_core 0.10.0-rc-6", "wasip2", + "wasip3", ] [[package]] @@ -1157,6 +1163,15 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] + [[package]] name = "hashbrown" version = "0.16.1" @@ -1165,7 +1180,7 @@ checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.2.0", ] [[package]] @@ -1213,11 +1228,11 @@ dependencies = [ [[package]] name = "hmac" -version = "0.13.0-rc.3" +version = "0.13.0-rc.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1c597ac7d6cc8143e30e83ef70915e7f883b18d8bec2e2b2bce47f5bbb06d57" +checksum = "d9956e202a691c5c86c60303a421f66f93f44b29433407b7c43cf2bebadc750e" dependencies = [ - "digest 0.11.0-rc.8", + "digest 0.11.0-rc.9", ] [[package]] @@ -1282,9 +1297,9 @@ checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" [[package]] name = "hybrid-array" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f471e0a81b2f90ffc0cb2f951ae04da57de8baa46fa99112b062a5173a5088d0" +checksum = "b41fb3dc24fe72c2e3a4685eed55917c2fb228851257f4a8f2d985da9443c3e5" dependencies = [ "typenum", ] @@ -1427,6 +1442,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "idna" version = "1.1.0" @@ -1539,6 +1560,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" version = "0.2.180" @@ -1557,9 +1584,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "linux-raw-sys" @@ -1723,9 +1750,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" [[package]] name = "num-derive" @@ -2002,9 +2029,9 @@ dependencies = [ [[package]] name = "pkcs8" -version = "0.11.0-rc.9" +version = "0.11.0-rc.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f8fa6196ede5a9f9ee95b44ca134bddc9b70e8913f9297bd58c909f5889a09" +checksum = "b226d2cc389763951db8869584fd800cbbe2962bf454e2edeb5172b31ee99774" dependencies = [ "der 0.8.0-rc.10", "spki 0.8.0-rc.4", @@ -2040,6 +2067,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "primeorder" version = "0.13.6" @@ -2121,13 +2158,14 @@ dependencies = [ "bytes", "console-subscriber", "crossbeam", + "dashmap", "flate2", "futures", - "hmac 0.13.0-rc.3", + "hmac 0.13.0-rc.4", "libloading", "log", "num-bigint", - "pkcs8 0.11.0-rc.9", + "pkcs8 0.11.0-rc.10", "pumpkin-config", "pumpkin-data", "pumpkin-inventory", @@ -2347,12 +2385,12 @@ dependencies = [ [[package]] name = "rand" -version = "0.10.0-rc.7" -source = "git+https://github.com/rust-random/rand#7a81944044f3f1d2dc5c85a8ca9bd30429f46bd0" +version = "0.10.0-rc.8" +source = "git+https://github.com/rust-random/rand#47455a0b004d5992d2a3d23ecf244f1edea27f40" dependencies = [ "chacha20", - "getrandom 0.4.0-rc.0", - "rand_core 0.10.0-rc-5", + "getrandom 0.4.0-rc.1", + "rand_core 0.10.0-rc-6", ] [[package]] @@ -2366,9 +2404,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.10.0-rc-5" +version = "0.10.0-rc-6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05a06e03bd1f2ae861ab9e7498b6c64ed3dadb9ce175c0464a2522a5f23c0045" +checksum = "70765ff7112b0fb2d272d24d9a2f907fc206211304328fe58b2db15a5649ef28" [[package]] name = "rayon" @@ -2454,19 +2492,19 @@ dependencies = [ [[package]] name = "rsa" -version = "0.10.0-rc.13" +version = "0.10.0-rc.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ff85dd219e338d42a2eada54ad71fe515717e08d53f728a8803de33b83f80b8" +checksum = "6ef381dd6f207f81aff2ee3a8264eddd68ba475bbfcdb44ca445e5906bce381b" dependencies = [ "const-oid 0.10.2", - "crypto-bigint 0.7.0-rc.21", + "crypto-bigint 0.7.0-rc.22", "crypto-primes", - "digest 0.11.0-rc.8", + "digest 0.11.0-rc.9", "pkcs1", - "pkcs8 0.11.0-rc.9", - "rand_core 0.10.0-rc-5", + "pkcs8 0.11.0-rc.10", + "rand_core 0.10.0-rc-6", "sha1", - "signature 3.0.0-rc.8", + "signature 3.0.0-rc.9", "spki 0.8.0-rc.4", "zeroize", ] @@ -2591,6 +2629,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" version = "1.0.228" @@ -2672,7 +2716,7 @@ checksum = "9c777f0a122a53fddb0beb6e706771197000b8eb5c9f42b5b850f450ef48c788" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.11.0-rc.8", + "digest 0.11.0-rc.9", ] [[package]] @@ -2694,7 +2738,7 @@ checksum = "7535f94fa3339fe9e5e9be6260a909e62af97f6e14b32345ccf79b92b8b81233" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.11.0-rc.8", + "digest 0.11.0-rc.9", ] [[package]] @@ -2734,12 +2778,12 @@ dependencies = [ [[package]] name = "signature" -version = "3.0.0-rc.8" +version = "3.0.0-rc.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c04b70a14ee5f15e2e0c785a5fdb2e9a51138dfe13ba3cf8eab037a9e60b1879" +checksum = "0ad0ce3b3f8efd7406f22e2ca5d02be21cdf3b3d1d53ab141f784de8965c7c7e" dependencies = [ - "digest 0.11.0-rc.8", - "rand_core 0.10.0-rc-5", + "digest 0.11.0-rc.9", + "rand_core 0.10.0-rc-6", ] [[package]] @@ -2762,9 +2806,9 @@ dependencies = [ [[package]] name = "siphasher" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" [[package]] name = "slab" @@ -2789,9 +2833,9 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" dependencies = [ "libc", "windows-sys 0.60.2", @@ -2904,18 +2948,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", @@ -2933,9 +2977,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.45" +version = "0.3.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" +checksum = "9da98b7d9b7dad93488a84b8248efc35352b0b2657397d4167e7ad67e5d535e5" dependencies = [ "deranged", "itoa", @@ -2950,15 +2994,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.25" +version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd" +checksum = "78cc610bac2dcee56805c99642447d4c5dbde4d01f752ffea0199aee1f601dc4" dependencies = [ "num-conv", "time-core", @@ -3242,6 +3286,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "untrusted" version = "0.9.0" @@ -3366,7 +3416,16 @@ version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.51.0", +] + +[[package]] +name = "wasip3" +version = "0.3.1+wasi-0.3.0-rc-2025-09-16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba4be47b1d11244670d11857eee0758a8f2c39aea64d80b78c1ce29b4642cd" +dependencies = [ + "wit-bindgen 0.48.1", ] [[package]] @@ -3414,6 +3473,40 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.241.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01164c9dda68301e34fdae536c23ed6fe90ce6d97213ccc171eebbd3d02d6b8" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.241.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876fe286f2fa416386deedebe8407e6f19e0b5aeaef3d03161e77a15fa80f167" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.241.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46d90019b1afd4b808c263e428de644f3003691f243387d30d673211ee0cb8e8" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + [[package]] name = "webpki-roots" version = "1.0.5" @@ -3631,12 +3724,100 @@ version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +[[package]] +name = "wit-bindgen" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f8c2adb5f74ac9395bc3121c99a1254bf9310482c27b13f97167aedb5887138" +dependencies = [ + "wit-bindgen-rust-macro", +] + [[package]] name = "wit-bindgen" version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +[[package]] +name = "wit-bindgen-core" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b881a098cae03686d7a0587f8f306f8a58102ad8da8b5599100fbe0e7f5800b" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69667efa439a453e1d50dac939c6cab6d2c3ac724a9d232b6631dad2472a5b70" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae2e22cceb5d105d52326c07e3e67603a861cc7add70fc467f7cc7ec5265017" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.241.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0c57df25e7ee612d946d3b7646c1ddb2310f8280aa2c17e543b66e0812241" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.241.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ef1c6ad67f35c831abd4039c02894de97034100899614d1c44e2268ad01c91" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + [[package]] name = "writeable" version = "0.6.2" @@ -3668,18 +3849,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.33" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" +checksum = "fdea86ddd5568519879b8187e1cf04e24fce28f7fe046ceecbce472ff19a2572" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.33" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" +checksum = "0c15e1b46eff7c6c91195752e0eeed8ef040e391cdece7c25376957d5f15df22" dependencies = [ "proc-macro2", "quote", @@ -3748,6 +3929,6 @@ dependencies = [ [[package]] name = "zmij" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea" +checksum = "02aae0f83f69aafc94776e879363e9771d7ecbffe2c7fbb6c14c5e00dfe88439" diff --git a/Cargo.toml b/Cargo.toml index 5dbc023c9..5f1b844be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ members = [ [workspace.lints.clippy] # Groups all = { level = "deny", priority = -1 } -# nursery = { level = "deny", priority = -1 } +nursery = { level = "deny", priority = -1 } pedantic = { level = "deny", priority = -1 } cargo = { level = "deny", priority = -1 } @@ -25,6 +25,7 @@ empty_enum_variants_with_brackets = "deny" empty_structs_with_brackets = "deny" separated_literal_suffix = "deny" semicolon_outside_block = "deny" +redundant_test_prefix = "deny" non_zero_suggestions = "deny" string_lit_chars_any = "deny" use_self = "deny" @@ -46,7 +47,15 @@ cast_precision_loss = "allow" multiple_crate_versions = "allow" single_call_fn = "allow" unreadable_literal = "allow" +many_single_char_names = "allow" +suboptimal_flops = "allow" cast_lossless = "allow" +while_float = "allow" +or_fun_call = "allow" +significant_drop_tightening = "allow" +suspicious_operation_groupings = "allow" +literal_string_with_formatting_args = "allow" +future_not_send = "allow" cast_sign_loss = "allow" float_cmp = "allow" cast_possible_truncation = "allow" @@ -106,14 +115,14 @@ console-subscriber = { version = "0.5.0", default-features = false } crc-fast = "1.10.0" criterion = { version = "0.8", default-features = false } crossbeam-utils = "0.8.21" -crossfire = "2.1.10" +crossfire = { version= "3.0.2", features = ["compat"]} dashmap = "6.1" ecdsa = "0.16.9" enum_dispatch = "0.3.13" env_logger = "0.11.8" flate2 = "1.1.8" heck = "0.5" -hmac = "=0.13.0-rc.3" +hmac = "=0.13.0-rc.4" indexmap = "2.13" itertools = "0.14.0" libloading = "0.9" @@ -126,7 +135,7 @@ num-traits = "0.2" num_cpus = "1.17.0" p384 = "0.13.1" phf = "0.13.1" -pkcs8 = "=0.11.0-rc.9" +pkcs8 = "=0.11.0-rc.10" proc-macro2 = "1.0" pumpkin-config = { path = "pumpkin-config" } pumpkin-data = { path = "pumpkin-data" } @@ -138,7 +147,7 @@ pumpkin-util = { path = "pumpkin-util" } pumpkin-world = { path = "pumpkin-world" } quote = "1.0" rand = { git = "https://github.com/rust-random/rand"} -rsa = "=0.10.0-rc.13" +rsa = "=0.10.0-rc.14" rustc-hash = "2.1.1" rustyline = "17.0.2" ruzstd = "0.8.2" diff --git a/pumpkin-config/src/networking/auth.rs b/pumpkin-config/src/networking/auth.rs index 51c1c4e45..1bc3598cd 100644 --- a/pumpkin-config/src/networking/auth.rs +++ b/pumpkin-config/src/networking/auth.rs @@ -1,7 +1,7 @@ use pumpkin_util::ProfileAction; use serde::{Deserialize, Serialize}; -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, Serialize, Clone)] #[serde(default)] pub struct AuthenticationConfig { /// Whether to use Mojang authentication. @@ -35,7 +35,7 @@ impl Default for AuthenticationConfig { } } -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, Serialize, Clone)] #[serde(default)] pub struct PlayerProfileConfig { /// Allow players flagged by Mojang (e.g. banned, forced name change). @@ -56,7 +56,7 @@ impl Default for PlayerProfileConfig { } } -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, Serialize, Clone)] #[serde(default)] pub struct TextureConfig { /// Whether to use player textures. @@ -80,7 +80,7 @@ impl Default for TextureConfig { } } -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, Serialize, Clone)] #[serde(default)] pub struct TextureTypes { /// Use player skins. diff --git a/pumpkin-config/src/op.rs b/pumpkin-config/src/op.rs index 5e60c61d0..dc13e7472 100644 --- a/pumpkin-config/src/op.rs +++ b/pumpkin-config/src/op.rs @@ -12,7 +12,7 @@ pub struct Op { impl Op { #[must_use] - pub fn new( + pub const fn new( uuid: Uuid, name: String, level: PermissionLvl, diff --git a/pumpkin-config/src/whitelist.rs b/pumpkin-config/src/whitelist.rs index 5d47c1410..56f53ca34 100644 --- a/pumpkin-config/src/whitelist.rs +++ b/pumpkin-config/src/whitelist.rs @@ -9,7 +9,7 @@ pub struct WhitelistEntry { impl WhitelistEntry { #[must_use] - pub fn new(uuid: Uuid, name: String) -> Self { + pub const fn new(uuid: Uuid, name: String) -> Self { Self { uuid, name } } } diff --git a/pumpkin-data/src/data_component_impl.rs b/pumpkin-data/src/data_component_impl.rs index 289879ae6..d609a7780 100644 --- a/pumpkin-data/src/data_component_impl.rs +++ b/pumpkin-data/src/data_component_impl.rs @@ -228,7 +228,7 @@ fn get_i32_hash(val: i32) -> u32 { } #[test] -fn test_hash() { +fn hash() { assert_eq!(get_str_hash("minecraft:sharpness"), 2734053906u32); assert_eq!(get_i32_hash(3), 3795317917u32); assert_eq!( diff --git a/pumpkin-inventory/src/container_click.rs b/pumpkin-inventory/src/container_click.rs index 6730c1b31..3ef3e8c08 100644 --- a/pumpkin-inventory/src/container_click.rs +++ b/pumpkin-inventory/src/container_click.rs @@ -145,7 +145,7 @@ pub enum DropType { } impl DropType { - fn from_i8(value: i8) -> Result { + const fn from_i8(value: i8) -> Result { Ok(match value { 0 => Self::SingleItem, 1 => Self::FullStack, @@ -154,13 +154,13 @@ impl DropType { } } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq)] pub enum MouseDragType { Left, Right, Middle, } -#[derive(PartialEq, Debug)] +#[derive(PartialEq, Eq, Debug)] pub enum MouseDragState { Start(MouseDragType), AddSlot(usize), diff --git a/pumpkin-inventory/src/player/player_inventory.rs b/pumpkin-inventory/src/player/player_inventory.rs index 41804717b..c34e891bf 100644 --- a/pumpkin-inventory/src/player/player_inventory.rs +++ b/pumpkin-inventory/src/player/player_inventory.rs @@ -73,7 +73,7 @@ impl PlayerInventory { } #[must_use] - pub fn is_valid_hotbar_index(slot: usize) -> bool { + pub const fn is_valid_hotbar_index(slot: usize) -> bool { slot < Self::HOTBAR_SIZE } diff --git a/pumpkin-inventory/src/slot.rs b/pumpkin-inventory/src/slot.rs index cca5e470d..8de8223eb 100644 --- a/pumpkin-inventory/src/slot.rs +++ b/pumpkin-inventory/src/slot.rs @@ -210,7 +210,7 @@ pub trait Slot: Send + Sync { self.on_take_item(player, stack).await; } - stack.unwrap_or(ItemStack::EMPTY.clone()) + stack.unwrap_or_else(|| ItemStack::EMPTY.clone()) }) } diff --git a/pumpkin-inventory/src/window_property.rs b/pumpkin-inventory/src/window_property.rs index 5996ecf25..2b1a3912f 100644 --- a/pumpkin-inventory/src/window_property.rs +++ b/pumpkin-inventory/src/window_property.rs @@ -8,7 +8,7 @@ pub struct WindowProperty { } impl WindowProperty { - pub fn new(window_property: T, value: i16) -> Self { + pub const fn new(window_property: T, value: i16) -> Self { Self { window_property, value, diff --git a/pumpkin-nbt/src/compound.rs b/pumpkin-nbt/src/compound.rs index be3050baa..1658d1b89 100644 --- a/pumpkin-nbt/src/compound.rs +++ b/pumpkin-nbt/src/compound.rs @@ -21,7 +21,7 @@ pub struct NbtCompound { impl NbtCompound { #[must_use] - pub fn new() -> Self { + pub const fn new() -> Self { Self { child_tags: Vec::new(), } @@ -85,7 +85,7 @@ impl NbtCompound { } #[must_use] - pub fn is_empty(&self) -> bool { + pub const fn is_empty(&self) -> bool { self.child_tags.is_empty() } diff --git a/pumpkin-nbt/src/deserializer.rs b/pumpkin-nbt/src/deserializer.rs index f1d927ca4..dedae7083 100644 --- a/pumpkin-nbt/src/deserializer.rs +++ b/pumpkin-nbt/src/deserializer.rs @@ -30,7 +30,7 @@ pub struct NbtReadHelper { } impl NbtReadHelper { - pub fn new(r: R) -> Self { + pub const fn new(r: R) -> Self { Self { reader: r } } } @@ -87,7 +87,7 @@ pub struct Deserializer { } impl Deserializer { - pub fn new(input: R, is_named: bool) -> Self { + pub const fn new(input: R, is_named: bool) -> Self { Self { input: NbtReadHelper { reader: input }, tag_to_deserialize_stack: None, diff --git a/pumpkin-nbt/src/lib.rs b/pumpkin-nbt/src/lib.rs index 7e011c0eb..a5d8bfb38 100644 --- a/pumpkin-nbt/src/lib.rs +++ b/pumpkin-nbt/src/lib.rs @@ -77,7 +77,7 @@ pub struct Nbt { impl Nbt { #[must_use] - pub fn new(name: String, tag: NbtCompound) -> Self { + pub const fn new(name: String, tag: NbtCompound) -> Self { Self { name, root_tag: tag, @@ -231,7 +231,7 @@ mod test { } #[test] - fn test_simple_ser_de_unnamed() { + fn simple_ser_de_unnamed() { let test = Test { byte: 123, short: 1342, @@ -260,7 +260,7 @@ mod test { } #[test] - fn test_simple_ser_de_array() { + fn simple_ser_de_array() { let test = TestArray { byte_array: vec![0, 3, 2], int_array: vec![13, 1321, 2], @@ -275,7 +275,7 @@ mod test { } #[test] - fn test_simple_ser_de_named() { + fn simple_ser_de_named() { let name = String::from("Test"); let test = Test { byte: 123, @@ -294,7 +294,7 @@ mod test { } #[test] - fn test_simple_ser_de_array_named() { + fn simple_ser_de_array_named() { let name = String::from("Test"); let test = TestArray { byte_array: vec![0, 3, 2], @@ -329,7 +329,7 @@ mod test { } #[test] - fn test_list() { + fn list() { let test1 = Test { byte: 123, short: 1342, @@ -369,7 +369,7 @@ mod test { } #[test] - fn test_list_named() { + fn list_named() { let test1 = Test { byte: 123, short: 1342, @@ -407,7 +407,7 @@ mod test { } #[test] - fn test_nbt_arrays() { + fn nbt_arrays() { #[derive(Serialize)] struct Tagged { #[serde(serialize_with = "nbt_long_array")] @@ -489,7 +489,7 @@ mod test { } #[test] - fn test_tuple_fail() { + fn tuple_fail() { #[derive(Serialize)] struct BadData { x: (i32, i64), @@ -506,7 +506,7 @@ mod test { } #[test] - fn test_tuple_ok() { + fn tuple_ok() { #[derive(Serialize, Deserialize, PartialEq, Debug)] struct GoodData { x: (i32, i32), diff --git a/pumpkin-nbt/src/nbt_compress.rs b/pumpkin-nbt/src/nbt_compress.rs index 42907c1b5..c37c02eb1 100644 --- a/pumpkin-nbt/src/nbt_compress.rs +++ b/pumpkin-nbt/src/nbt_compress.rs @@ -116,7 +116,7 @@ mod tests { use std::io::Cursor; #[test] - fn test_gzip_read_write_compound() { + fn gzip_read_write_compound() { // Create a test compound let mut compound = NbtCompound::new(); compound.put_byte("byte_value", 123); @@ -163,7 +163,7 @@ mod tests { } #[test] - fn test_gzip_convenience_methods() { + fn gzip_convenience_methods() { // Create a test compound let mut compound = NbtCompound::new(); compound.put_int("test_value", 12345); @@ -180,7 +180,7 @@ mod tests { } #[test] - fn test_gzip_empty_compound() { + fn gzip_empty_compound() { let compound = NbtCompound::new(); let mut buffer = Vec::new(); write_gzip_compound_tag(compound, &mut buffer).expect("Failed to compress empty compound"); @@ -191,7 +191,7 @@ mod tests { } #[test] - fn test_gzip_large_compound() { + fn gzip_large_compound() { let mut compound = NbtCompound::new(); // Add 1000 integer entries @@ -229,7 +229,7 @@ mod tests { } #[test] - fn test_gzip_serialize_deserialize() { + fn gzip_serialize_deserialize() { let test_struct = TestStruct { string_field: "test string".to_string(), int_field: 12345, @@ -263,7 +263,7 @@ mod tests { #[test] #[expect(clippy::print_stdout)] - fn test_gzip_compression_ratio() { + fn gzip_compression_ratio() { let mut compound = NbtCompound::new(); // Create a compound with repetitive data (should compress well) @@ -287,7 +287,7 @@ mod tests { } #[test] - fn test_gzip_invalid_data() { + fn gzip_invalid_data() { // Try to read from invalid data let invalid_data = vec![1, 2, 3, 4, 5]; // Not valid GZip data let result = read_gzip_compound_tag(Cursor::new(invalid_data)); @@ -296,7 +296,7 @@ mod tests { #[test] #[expect(clippy::struct_field_names)] - fn test_roundtrip_with_arrays() { + fn roundtrip_with_arrays() { #[derive(Serialize, Deserialize, Debug, PartialEq)] struct ArrayTest { byte_array: Vec, @@ -319,7 +319,7 @@ mod tests { } #[test] - fn test_roundtrip_with_map() { + fn roundtrip_with_map() { #[derive(Serialize, Deserialize, Debug, PartialEq)] struct MapTest { string_map: HashMap, @@ -348,7 +348,7 @@ mod tests { } #[test] - fn test_direct_file_io() { + fn direct_file_io() { use tempfile::tempdir; let temp_dir = tempdir().expect("Failed to create temporary directory"); diff --git a/pumpkin-nbt/src/serializer.rs b/pumpkin-nbt/src/serializer.rs index af5ff9173..dffb6ad55 100644 --- a/pumpkin-nbt/src/serializer.rs +++ b/pumpkin-nbt/src/serializer.rs @@ -16,7 +16,7 @@ pub struct WriteAdaptor { } impl WriteAdaptor { - pub fn new(w: W) -> Self { + pub const fn new(w: W) -> Self { Self { writer: w } } } @@ -57,7 +57,7 @@ pub struct Serializer { } impl Serializer { - pub fn new(output: W, name: Option) -> Self { + pub const fn new(output: W, name: Option) -> Self { Self { output: WriteAdaptor::new(output), state: State::Root(name), diff --git a/pumpkin-nbt/src/tag.rs b/pumpkin-nbt/src/tag.rs index 2741f28a0..16d298d66 100644 --- a/pumpkin-nbt/src/tag.rs +++ b/pumpkin-nbt/src/tag.rs @@ -267,7 +267,7 @@ impl NbtTag { } #[must_use] - pub fn extract_byte(&self) -> Option { + pub const fn extract_byte(&self) -> Option { match self { Self::Byte(byte) => Some(*byte), _ => None, @@ -275,7 +275,7 @@ impl NbtTag { } #[must_use] - pub fn extract_short(&self) -> Option { + pub const fn extract_short(&self) -> Option { match self { Self::Short(short) => Some(*short), _ => None, @@ -283,7 +283,7 @@ impl NbtTag { } #[must_use] - pub fn extract_int(&self) -> Option { + pub const fn extract_int(&self) -> Option { match self { Self::Int(int) => Some(*int), _ => None, @@ -291,7 +291,7 @@ impl NbtTag { } #[must_use] - pub fn extract_long(&self) -> Option { + pub const fn extract_long(&self) -> Option { match self { Self::Long(long) => Some(*long), _ => None, @@ -299,7 +299,7 @@ impl NbtTag { } #[must_use] - pub fn extract_float(&self) -> Option { + pub const fn extract_float(&self) -> Option { match self { Self::Float(float) => Some(*float), _ => None, @@ -307,7 +307,7 @@ impl NbtTag { } #[must_use] - pub fn extract_double(&self) -> Option { + pub const fn extract_double(&self) -> Option { match self { Self::Double(double) => Some(*double), _ => None, @@ -347,7 +347,7 @@ impl NbtTag { } #[must_use] - pub fn extract_compound(&self) -> Option<&NbtCompound> { + pub const fn extract_compound(&self) -> Option<&NbtCompound> { match self { Self::Compound(compound) => Some(compound), _ => None, diff --git a/pumpkin-protocol/src/bedrock/ack.rs b/pumpkin-protocol/src/bedrock/ack.rs index 6fe2f0643..3769a8e29 100644 --- a/pumpkin-protocol/src/bedrock/ack.rs +++ b/pumpkin-protocol/src/bedrock/ack.rs @@ -16,7 +16,7 @@ pub struct Ack { impl Ack { #[must_use] - pub fn new(sequences: Vec) -> Self { + pub const fn new(sequences: Vec) -> Self { Self { sequences } } diff --git a/pumpkin-protocol/src/bedrock/client/disconnect_player.rs b/pumpkin-protocol/src/bedrock/client/disconnect_player.rs index 79e5a0a3d..bb26bd04e 100644 --- a/pumpkin-protocol/src/bedrock/client/disconnect_player.rs +++ b/pumpkin-protocol/src/bedrock/client/disconnect_player.rs @@ -14,7 +14,7 @@ pub struct CDisconnectPlayer { impl CDisconnectPlayer { #[must_use] - pub fn new(reason: i32, message: String) -> Self { + pub const fn new(reason: i32, message: String) -> Self { Self { reason: VarInt(reason), skip_message: message.is_empty(), diff --git a/pumpkin-protocol/src/bedrock/client/handshake.rs b/pumpkin-protocol/src/bedrock/client/handshake.rs index 116a4b30c..fa7c365d0 100644 --- a/pumpkin-protocol/src/bedrock/client/handshake.rs +++ b/pumpkin-protocol/src/bedrock/client/handshake.rs @@ -9,7 +9,7 @@ pub struct CHandshake { impl CHandshake { #[must_use] - pub fn new(jwt_data: String) -> Self { + pub const fn new(jwt_data: String) -> Self { Self { jwt_data } } } diff --git a/pumpkin-protocol/src/bedrock/client/network_chunk_publisher_update.rs b/pumpkin-protocol/src/bedrock/client/network_chunk_publisher_update.rs index 629e60fa6..80f04f47d 100644 --- a/pumpkin-protocol/src/bedrock/client/network_chunk_publisher_update.rs +++ b/pumpkin-protocol/src/bedrock/client/network_chunk_publisher_update.rs @@ -20,7 +20,7 @@ pub struct CNetworkChunkPublisherUpdate { impl CNetworkChunkPublisherUpdate { #[must_use] - pub fn new(pos_for_view: BlockPos, new_radius: u32) -> Self { + pub const fn new(pos_for_view: BlockPos, new_radius: u32) -> Self { Self { pos_for_view: NetworkPos(pos_for_view), new_radius: VarUInt(new_radius), diff --git a/pumpkin-protocol/src/bedrock/client/network_settings.rs b/pumpkin-protocol/src/bedrock/client/network_settings.rs index 215d6d94a..ce53b42e6 100644 --- a/pumpkin-protocol/src/bedrock/client/network_settings.rs +++ b/pumpkin-protocol/src/bedrock/client/network_settings.rs @@ -14,7 +14,7 @@ pub struct CNetworkSettings { impl CNetworkSettings { #[must_use] - pub fn new( + pub const fn new( compression_threshold: u16, compression_method: u16, client_throttle_enabled: bool, diff --git a/pumpkin-protocol/src/bedrock/client/raknet/connection.rs b/pumpkin-protocol/src/bedrock/client/raknet/connection.rs index 17b0b9330..03357ddc1 100644 --- a/pumpkin-protocol/src/bedrock/client/raknet/connection.rs +++ b/pumpkin-protocol/src/bedrock/client/raknet/connection.rs @@ -13,7 +13,7 @@ pub struct CConnectedPong { impl CConnectedPong { #[must_use] #[expect(clippy::similar_names)] - pub fn new(ping: u64, pong: u64) -> Self { + pub const fn new(ping: u64, pong: u64) -> Self { Self { ping, pong } } } @@ -30,7 +30,7 @@ pub struct CConnectionRequestAccepted { impl CConnectionRequestAccepted { #[must_use] - pub fn new( + pub const fn new( client_address: SocketAddr, system_index: u16, system_addresses: [SocketAddr; 10], diff --git a/pumpkin-protocol/src/bedrock/client/raknet/open_connection.rs b/pumpkin-protocol/src/bedrock/client/raknet/open_connection.rs index e8ad7c26e..cd4c6ee36 100644 --- a/pumpkin-protocol/src/bedrock/client/raknet/open_connection.rs +++ b/pumpkin-protocol/src/bedrock/client/raknet/open_connection.rs @@ -17,7 +17,7 @@ pub struct COpenConnectionReply1 { impl COpenConnectionReply1 { #[must_use] - pub fn new(server_guid: u64, has_server_security: bool, mtu: u16) -> Self { + pub const fn new(server_guid: u64, has_server_security: bool, mtu: u16) -> Self { Self { magic: RAKNET_MAGIC, server_guid, @@ -40,7 +40,12 @@ pub struct COpenConnectionReply2 { impl COpenConnectionReply2 { #[must_use] - pub fn new(server_guid: u64, client_address: SocketAddr, mtu: u16, security: bool) -> Self { + pub const fn new( + server_guid: u64, + client_address: SocketAddr, + mtu: u16, + security: bool, + ) -> Self { Self { magic: RAKNET_MAGIC, server_guid, diff --git a/pumpkin-protocol/src/bedrock/client/raknet/unconnected_pong.rs b/pumpkin-protocol/src/bedrock/client/raknet/unconnected_pong.rs index 86278aa99..ae88063dd 100644 --- a/pumpkin-protocol/src/bedrock/client/raknet/unconnected_pong.rs +++ b/pumpkin-protocol/src/bedrock/client/raknet/unconnected_pong.rs @@ -62,7 +62,7 @@ impl fmt::Display for ServerInfo { impl CUnconnectedPong { #[must_use] - pub fn new(time: u64, server_guid: u64, magic: [u8; 16], server_id: String) -> Self { + pub const fn new(time: u64, server_guid: u64, magic: [u8; 16], server_id: String) -> Self { Self { time, server_guid, diff --git a/pumpkin-protocol/src/bedrock/client/resource_pack_stack.rs b/pumpkin-protocol/src/bedrock/client/resource_pack_stack.rs index c926fc731..224f5fe5a 100644 --- a/pumpkin-protocol/src/bedrock/client/resource_pack_stack.rs +++ b/pumpkin-protocol/src/bedrock/client/resource_pack_stack.rs @@ -18,7 +18,7 @@ pub struct CResourcePackStackPacket { impl CResourcePackStackPacket { #[must_use] - pub fn new( + pub const fn new( resource_pack_required: bool, texture_pack_list_size: VarUInt, game_version: String, diff --git a/pumpkin-protocol/src/bedrock/client/resource_packs_info.rs b/pumpkin-protocol/src/bedrock/client/resource_packs_info.rs index 2b635ed19..099a9288c 100644 --- a/pumpkin-protocol/src/bedrock/client/resource_packs_info.rs +++ b/pumpkin-protocol/src/bedrock/client/resource_packs_info.rs @@ -17,7 +17,7 @@ pub struct CResourcePacksInfo { impl CResourcePacksInfo { #[must_use] #[expect(clippy::fn_params_excessive_bools)] - pub fn new( + pub const fn new( resource_pack_required: bool, has_addon_packs: bool, has_scripts: bool, diff --git a/pumpkin-protocol/src/bedrock/client/set_actor_data.rs b/pumpkin-protocol/src/bedrock/client/set_actor_data.rs index 36752b27d..fd6c72901 100644 --- a/pumpkin-protocol/src/bedrock/client/set_actor_data.rs +++ b/pumpkin-protocol/src/bedrock/client/set_actor_data.rs @@ -72,7 +72,7 @@ pub enum MetadataValue { impl MetadataValue { #[must_use] - pub fn type_id(&self) -> u32 { + pub const fn type_id(&self) -> u32 { match self { Self::Byte(_) => 0, Self::Short(_) => 1, diff --git a/pumpkin-protocol/src/bedrock/frame_set.rs b/pumpkin-protocol/src/bedrock/frame_set.rs index a41a58ca2..3d5d62fea 100644 --- a/pumpkin-protocol/src/bedrock/frame_set.rs +++ b/pumpkin-protocol/src/bedrock/frame_set.rs @@ -52,7 +52,7 @@ pub struct Frame { impl Frame { #[must_use] - pub fn new_unreliable(payload: Vec) -> Self { + pub const fn new_unreliable(payload: Vec) -> Self { Self { reliability: RakReliability::Unreliable, payload, diff --git a/pumpkin-protocol/src/bedrock/mod.rs b/pumpkin-protocol/src/bedrock/mod.rs index cd45ec545..94fb96cf1 100644 --- a/pumpkin-protocol/src/bedrock/mod.rs +++ b/pumpkin-protocol/src/bedrock/mod.rs @@ -36,7 +36,7 @@ pub enum RakReliability { impl RakReliability { #[must_use] - pub fn is_reliable(&self) -> bool { + pub const fn is_reliable(&self) -> bool { matches!( self, Self::Reliable @@ -48,12 +48,12 @@ impl RakReliability { } #[must_use] - pub fn is_sequenced(&self) -> bool { + pub const fn is_sequenced(&self) -> bool { matches!(self, Self::ReliableSequenced | Self::UnreliableSequenced) } #[must_use] - pub fn is_ordered(&self) -> bool { + pub const fn is_ordered(&self) -> bool { matches!( self, Self::UnreliableSequenced @@ -64,7 +64,7 @@ impl RakReliability { } #[must_use] - pub fn is_order_exclusive(&self) -> bool { + pub const fn is_order_exclusive(&self) -> bool { matches!( self, Self::ReliableOrdered | Self::ReliableOrderedWithAckReceipt @@ -72,7 +72,7 @@ impl RakReliability { } #[must_use] - pub fn from_id(id: u8) -> Option { + pub const fn from_id(id: u8) -> Option { match id { 0 => Some(Self::Unreliable), 1 => Some(Self::UnreliableSequenced), @@ -87,7 +87,7 @@ impl RakReliability { } #[must_use] - pub fn to_id(&self) -> u8 { + pub const fn to_id(&self) -> u8 { match self { Self::Unreliable => 0, Self::UnreliableSequenced => 1, diff --git a/pumpkin-protocol/src/bedrock/packet_decoder.rs b/pumpkin-protocol/src/bedrock/packet_decoder.rs index cacaeeadc..81124ce22 100644 --- a/pumpkin-protocol/src/bedrock/packet_decoder.rs +++ b/pumpkin-protocol/src/bedrock/packet_decoder.rs @@ -90,16 +90,16 @@ impl Default for UDPNetworkDecoder { impl UDPNetworkDecoder { #[must_use] - pub fn new() -> Self { + pub const fn new() -> Self { Self { compression: None } } - pub fn set_compression(&mut self, threshold: CompressionThreshold) { + pub const fn set_compression(&mut self, threshold: CompressionThreshold) { self.compression = Some(threshold); } /// NOTE: Encryption can only be set; a minecraft stream cannot go back to being unencrypted - pub fn set_encryption(&mut self, _key: &[u8; 16]) { + pub const fn set_encryption(&mut self, _key: &[u8; 16]) { // if matches!(self.reader, DecryptionReader::Decrypt(_)) { // panic!("Cannot upgrade a stream that already has a cipher!"); // } diff --git a/pumpkin-protocol/src/bedrock/packet_encoder.rs b/pumpkin-protocol/src/bedrock/packet_encoder.rs index 6dad989d0..7438a03e6 100644 --- a/pumpkin-protocol/src/bedrock/packet_encoder.rs +++ b/pumpkin-protocol/src/bedrock/packet_encoder.rs @@ -91,16 +91,19 @@ impl Default for UDPNetworkEncoder { impl UDPNetworkEncoder { #[must_use] - pub fn new() -> Self { + pub const fn new() -> Self { Self { compression: None } } - pub fn set_compression(&mut self, compression_info: (CompressionThreshold, CompressionLevel)) { + pub const fn set_compression( + &mut self, + compression_info: (CompressionThreshold, CompressionLevel), + ) { self.compression = Some(compression_info); } /// NOTE: Encryption can only be set; a minecraft stream cannot go back to being unencrypted - pub fn set_encryption(&mut self, _key: &[u8; 16]) { + pub const fn set_encryption(&mut self, _key: &[u8; 16]) { // if matches!(self.writer, EncryptionWriter::Encrypt(_)) { // panic!("Cannot upgrade a stream that already has a cipher!"); // } diff --git a/pumpkin-protocol/src/bedrock/server/loading_screen.rs b/pumpkin-protocol/src/bedrock/server/loading_screen.rs index aaafebea5..05722db59 100644 --- a/pumpkin-protocol/src/bedrock/server/loading_screen.rs +++ b/pumpkin-protocol/src/bedrock/server/loading_screen.rs @@ -14,7 +14,7 @@ pub struct SLoadingScreen { impl SLoadingScreen { #[must_use] - pub fn is_loading_done(&self) -> bool { + pub const fn is_loading_done(&self) -> bool { self.status.0 == 2 } } diff --git a/pumpkin-protocol/src/bedrock/server/text.rs b/pumpkin-protocol/src/bedrock/server/text.rs index c70ae46ed..cc88e8101 100644 --- a/pumpkin-protocol/src/bedrock/server/text.rs +++ b/pumpkin-protocol/src/bedrock/server/text.rs @@ -55,7 +55,7 @@ impl SText { } } - fn get_dummy_strings(category: u8) -> &'static [&'static str] { + const fn get_dummy_strings(category: u8) -> &'static [&'static str] { match category { 0 => &[ "raw", @@ -71,7 +71,7 @@ impl SText { } } - fn get_category(&self) -> u8 { + const fn get_category(&self) -> u8 { match self.r#type { TextPacketType::Raw | TextPacketType::Tip @@ -205,7 +205,7 @@ impl PacketWrite for SText { } } -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] pub enum TextPacketType { Raw = 0, diff --git a/pumpkin-protocol/src/codec/var_int.rs b/pumpkin-protocol/src/codec/var_int.rs index 77376b292..081db4f2c 100644 --- a/pumpkin-protocol/src/codec/var_int.rs +++ b/pumpkin-protocol/src/codec/var_int.rs @@ -31,7 +31,7 @@ impl VarInt { /// Returns the exact number of bytes this `VarInt` will write when /// [`Encode::encode`] is called, assuming no error occurs. #[must_use] - pub fn written_size(&self) -> usize { + pub const fn written_size(&self) -> usize { match self.0 { 0 => 1, n => (31 - n.leading_zeros() as usize) / 7 + 1, diff --git a/pumpkin-protocol/src/codec/var_ulong.rs b/pumpkin-protocol/src/codec/var_ulong.rs index caeea916a..1a1ccbddf 100644 --- a/pumpkin-protocol/src/codec/var_ulong.rs +++ b/pumpkin-protocol/src/codec/var_ulong.rs @@ -30,7 +30,7 @@ impl VarULong { /// Returns the exact number of bytes this `VarLong` will write when /// [`Encode::encode`] is called, assuming no error occurs. #[must_use] - pub fn written_size(&self) -> usize { + pub const fn written_size(&self) -> usize { match self.0 { 0 => 1, n => (31 - n.leading_zeros() as usize) / 7 + 1, diff --git a/pumpkin-protocol/src/codec/velocity.rs b/pumpkin-protocol/src/codec/velocity.rs index 3aa2e85ee..a7160094b 100644 --- a/pumpkin-protocol/src/codec/velocity.rs +++ b/pumpkin-protocol/src/codec/velocity.rs @@ -71,12 +71,12 @@ fn clamp_value(value: f64) -> f64 { value.clamp(-MAX_VELOCITY_CLAMP, MAX_VELOCITY_CLAMP) } -fn abs_max(a: f64, b: f64) -> f64 { +const fn abs_max(a: f64, b: f64) -> f64 { a.abs().max(b.abs()) } fn to_long(value: f64) -> i64 { - (((value * 0.5 + 0.5) * MAX_15_BIT_VALUE).round() as i64).clamp(0, 32766) + ((value.mul_add(0.5, 0.5) * MAX_15_BIT_VALUE).round() as i64).clamp(0, 32766) } impl Serialize for Velocity { diff --git a/pumpkin-protocol/src/java/client/config/add_resource_pack.rs b/pumpkin-protocol/src/java/client/config/add_resource_pack.rs index 5c727474d..9afa28365 100644 --- a/pumpkin-protocol/src/java/client/config/add_resource_pack.rs +++ b/pumpkin-protocol/src/java/client/config/add_resource_pack.rs @@ -18,7 +18,7 @@ pub struct CConfigAddResourcePack<'a> { impl<'a> CConfigAddResourcePack<'a> { #[must_use] - pub fn new( + pub const fn new( uuid: &'a uuid::Uuid, url: &'a str, hash: &'a str, diff --git a/pumpkin-protocol/src/java/client/config/config_disconnect.rs b/pumpkin-protocol/src/java/client/config/config_disconnect.rs index 64920e82b..4b7e4531c 100644 --- a/pumpkin-protocol/src/java/client/config/config_disconnect.rs +++ b/pumpkin-protocol/src/java/client/config/config_disconnect.rs @@ -10,7 +10,7 @@ pub struct CConfigDisconnect<'a> { impl<'a> CConfigDisconnect<'a> { #[must_use] - pub fn new(reason: &'a str) -> Self { + pub const fn new(reason: &'a str) -> Self { Self { reason } } } diff --git a/pumpkin-protocol/src/java/client/config/cookie_request.rs b/pumpkin-protocol/src/java/client/config/cookie_request.rs index e8bb56b10..f39de054e 100644 --- a/pumpkin-protocol/src/java/client/config/cookie_request.rs +++ b/pumpkin-protocol/src/java/client/config/cookie_request.rs @@ -11,7 +11,7 @@ pub struct CCookieRequest<'a> { impl<'a> CCookieRequest<'a> { #[must_use] - pub fn new(key: &'a ResourceLocation) -> Self { + pub const fn new(key: &'a ResourceLocation) -> Self { Self { key } } } diff --git a/pumpkin-protocol/src/java/client/config/known_packs.rs b/pumpkin-protocol/src/java/client/config/known_packs.rs index a5e6fd95c..af8f6483e 100644 --- a/pumpkin-protocol/src/java/client/config/known_packs.rs +++ b/pumpkin-protocol/src/java/client/config/known_packs.rs @@ -12,7 +12,7 @@ pub struct CKnownPacks<'a> { impl<'a> CKnownPacks<'a> { #[must_use] - pub fn new(known_packs: &'a [KnownPack]) -> Self { + pub const fn new(known_packs: &'a [KnownPack]) -> Self { Self { known_packs } } } diff --git a/pumpkin-protocol/src/java/client/config/plugin_message.rs b/pumpkin-protocol/src/java/client/config/plugin_message.rs index fae75b8f2..92c4d136a 100644 --- a/pumpkin-protocol/src/java/client/config/plugin_message.rs +++ b/pumpkin-protocol/src/java/client/config/plugin_message.rs @@ -14,7 +14,7 @@ pub struct CPluginMessage<'a> { impl<'a> CPluginMessage<'a> { #[must_use] - pub fn new(channel: &'a str, data: &'a [u8]) -> Self { + pub const fn new(channel: &'a str, data: &'a [u8]) -> Self { Self { channel, data } } } diff --git a/pumpkin-protocol/src/java/client/config/registry_data.rs b/pumpkin-protocol/src/java/client/config/registry_data.rs index d7bda7ba1..5764fa29e 100644 --- a/pumpkin-protocol/src/java/client/config/registry_data.rs +++ b/pumpkin-protocol/src/java/client/config/registry_data.rs @@ -13,7 +13,7 @@ pub struct CRegistryData<'a> { impl<'a> CRegistryData<'a> { #[must_use] - pub fn new(registry_id: &'a ResourceLocation, entries: &'a [RegistryEntry]) -> Self { + pub const fn new(registry_id: &'a ResourceLocation, entries: &'a [RegistryEntry]) -> Self { Self { registry_id, entries, @@ -31,7 +31,7 @@ pub struct RegistryEntry { // TODO: No unwraps impl RegistryEntry { #[must_use] - pub fn new(entry_id: ResourceLocation, data: Option>) -> Self { + pub const fn new(entry_id: ResourceLocation, data: Option>) -> Self { Self { entry_id, data } } diff --git a/pumpkin-protocol/src/java/client/config/server_links.rs b/pumpkin-protocol/src/java/client/config/server_links.rs index 24dad3fdb..13ecc8259 100644 --- a/pumpkin-protocol/src/java/client/config/server_links.rs +++ b/pumpkin-protocol/src/java/client/config/server_links.rs @@ -11,7 +11,7 @@ pub struct CConfigServerLinks<'a> { impl<'a> CConfigServerLinks<'a> { #[must_use] - pub fn new(links: &'a [Link<'a>]) -> Self { + pub const fn new(links: &'a [Link<'a>]) -> Self { Self { links } } } diff --git a/pumpkin-protocol/src/java/client/config/store_cookie.rs b/pumpkin-protocol/src/java/client/config/store_cookie.rs index 74e697216..11a6791aa 100644 --- a/pumpkin-protocol/src/java/client/config/store_cookie.rs +++ b/pumpkin-protocol/src/java/client/config/store_cookie.rs @@ -13,7 +13,7 @@ pub struct CStoreCookie<'a> { impl<'a> CStoreCookie<'a> { #[must_use] - pub fn new(key: &'a ResourceLocation, payload: &'a [u8]) -> Self { + pub const fn new(key: &'a ResourceLocation, payload: &'a [u8]) -> Self { Self { key, payload } } } diff --git a/pumpkin-protocol/src/java/client/config/transfer.rs b/pumpkin-protocol/src/java/client/config/transfer.rs index 2685c54f2..2e0ba0a8d 100644 --- a/pumpkin-protocol/src/java/client/config/transfer.rs +++ b/pumpkin-protocol/src/java/client/config/transfer.rs @@ -12,7 +12,7 @@ pub struct CTransfer<'a> { impl<'a> CTransfer<'a> { #[must_use] - pub fn new(host: &'a str, port: &'a VarInt) -> Self { + pub const fn new(host: &'a str, port: &'a VarInt) -> Self { Self { host, port } } } diff --git a/pumpkin-protocol/src/java/client/config/update_tags.rs b/pumpkin-protocol/src/java/client/config/update_tags.rs index 015aedfe1..967000c5a 100644 --- a/pumpkin-protocol/src/java/client/config/update_tags.rs +++ b/pumpkin-protocol/src/java/client/config/update_tags.rs @@ -18,7 +18,7 @@ pub struct CUpdateTags<'a> { impl<'a> CUpdateTags<'a> { #[must_use] - pub fn new(tags: &'a [RegistryKey]) -> Self { + pub const fn new(tags: &'a [RegistryKey]) -> Self { Self { tags } } } diff --git a/pumpkin-protocol/src/java/client/login/cookie_request.rs b/pumpkin-protocol/src/java/client/login/cookie_request.rs index 59a16b75c..0ea4e0adf 100644 --- a/pumpkin-protocol/src/java/client/login/cookie_request.rs +++ b/pumpkin-protocol/src/java/client/login/cookie_request.rs @@ -16,7 +16,7 @@ pub struct CLoginCookieRequest<'a> { impl<'a> CLoginCookieRequest<'a> { #[must_use] - pub fn new(key: &'a ResourceLocation) -> Self { + pub const fn new(key: &'a ResourceLocation) -> Self { Self { key } } } diff --git a/pumpkin-protocol/src/java/client/login/encryption_request.rs b/pumpkin-protocol/src/java/client/login/encryption_request.rs index 818269b4c..4af8401bd 100644 --- a/pumpkin-protocol/src/java/client/login/encryption_request.rs +++ b/pumpkin-protocol/src/java/client/login/encryption_request.rs @@ -25,7 +25,7 @@ pub struct CEncryptionRequest<'a> { impl<'a> CEncryptionRequest<'a> { #[must_use] - pub fn new( + pub const fn new( server_id: &'a str, public_key: &'a [u8], verify_token: &'a [u8], diff --git a/pumpkin-protocol/src/java/client/login/login_disconnect.rs b/pumpkin-protocol/src/java/client/login/login_disconnect.rs index f7b03a8cc..cd0b12ba3 100644 --- a/pumpkin-protocol/src/java/client/login/login_disconnect.rs +++ b/pumpkin-protocol/src/java/client/login/login_disconnect.rs @@ -15,7 +15,7 @@ pub struct CLoginDisconnect { impl CLoginDisconnect { #[must_use] - pub fn new(json_reason: String) -> Self { + pub const fn new(json_reason: String) -> Self { Self { json_reason } } } diff --git a/pumpkin-protocol/src/java/client/login/login_success.rs b/pumpkin-protocol/src/java/client/login/login_success.rs index c4ddcbb46..f4d8248cc 100644 --- a/pumpkin-protocol/src/java/client/login/login_success.rs +++ b/pumpkin-protocol/src/java/client/login/login_success.rs @@ -22,7 +22,7 @@ pub struct CLoginSuccess<'a> { impl<'a> CLoginSuccess<'a> { #[must_use] - pub fn new(uuid: &'a uuid::Uuid, username: &'a str, properties: &'a [Property]) -> Self { + pub const fn new(uuid: &'a uuid::Uuid, username: &'a str, properties: &'a [Property]) -> Self { Self { uuid, username, diff --git a/pumpkin-protocol/src/java/client/login/plugin_request.rs b/pumpkin-protocol/src/java/client/login/plugin_request.rs index d4b8aaf89..b698a1b16 100644 --- a/pumpkin-protocol/src/java/client/login/plugin_request.rs +++ b/pumpkin-protocol/src/java/client/login/plugin_request.rs @@ -24,7 +24,7 @@ pub struct CLoginPluginRequest<'a> { impl<'a> CLoginPluginRequest<'a> { #[must_use] - pub fn new(message_id: VarInt, channel: &'a str, data: &'a [u8]) -> Self { + pub const fn new(message_id: VarInt, channel: &'a str, data: &'a [u8]) -> Self { Self { message_id, channel, diff --git a/pumpkin-protocol/src/java/client/login/set_compression.rs b/pumpkin-protocol/src/java/client/login/set_compression.rs index 9ebc5f242..6f15f6162 100644 --- a/pumpkin-protocol/src/java/client/login/set_compression.rs +++ b/pumpkin-protocol/src/java/client/login/set_compression.rs @@ -20,7 +20,7 @@ pub struct CSetCompression { impl CSetCompression { #[must_use] - pub fn new(threshold: VarInt) -> Self { + pub const fn new(threshold: VarInt) -> Self { Self { threshold } } } diff --git a/pumpkin-protocol/src/java/client/play/acknowledge_block.rs b/pumpkin-protocol/src/java/client/play/acknowledge_block.rs index 279202a1c..c847026ec 100644 --- a/pumpkin-protocol/src/java/client/play/acknowledge_block.rs +++ b/pumpkin-protocol/src/java/client/play/acknowledge_block.rs @@ -21,7 +21,7 @@ pub struct CAcknowledgeBlockChange { impl CAcknowledgeBlockChange { #[must_use] - pub fn new(sequence_id: VarInt) -> Self { + pub const fn new(sequence_id: VarInt) -> Self { Self { sequence_id } } } diff --git a/pumpkin-protocol/src/java/client/play/actionbar.rs b/pumpkin-protocol/src/java/client/play/actionbar.rs index 3a3bd9602..fcb7404db 100644 --- a/pumpkin-protocol/src/java/client/play/actionbar.rs +++ b/pumpkin-protocol/src/java/client/play/actionbar.rs @@ -18,7 +18,7 @@ pub struct CActionBar<'a> { impl<'a> CActionBar<'a> { #[must_use] - pub fn new(action_bar: &'a TextComponent) -> Self { + pub const fn new(action_bar: &'a TextComponent) -> Self { Self { action_bar } } } diff --git a/pumpkin-protocol/src/java/client/play/block_destroy_stage.rs b/pumpkin-protocol/src/java/client/play/block_destroy_stage.rs index ede9021fb..e3059b52a 100644 --- a/pumpkin-protocol/src/java/client/play/block_destroy_stage.rs +++ b/pumpkin-protocol/src/java/client/play/block_destroy_stage.rs @@ -25,7 +25,7 @@ pub struct CSetBlockDestroyStage { impl CSetBlockDestroyStage { #[must_use] - pub fn new(entity_id: VarInt, location: BlockPos, destroy_stage: i8) -> Self { + pub const fn new(entity_id: VarInt, location: BlockPos, destroy_stage: i8) -> Self { Self { entity_id, location, diff --git a/pumpkin-protocol/src/java/client/play/block_entity_data.rs b/pumpkin-protocol/src/java/client/play/block_entity_data.rs index 910e343c2..602995fe2 100644 --- a/pumpkin-protocol/src/java/client/play/block_entity_data.rs +++ b/pumpkin-protocol/src/java/client/play/block_entity_data.rs @@ -23,7 +23,7 @@ pub struct CBlockEntityData { impl CBlockEntityData { #[must_use] - pub fn new(location: BlockPos, r#type: VarInt, nbt_data: Box<[u8]>) -> Self { + pub const fn new(location: BlockPos, r#type: VarInt, nbt_data: Box<[u8]>) -> Self { Self { location, r#type, diff --git a/pumpkin-protocol/src/java/client/play/block_event.rs b/pumpkin-protocol/src/java/client/play/block_event.rs index a98a607e7..d4fab5df8 100644 --- a/pumpkin-protocol/src/java/client/play/block_event.rs +++ b/pumpkin-protocol/src/java/client/play/block_event.rs @@ -26,7 +26,7 @@ pub struct CBlockEvent { impl CBlockEvent { #[must_use] - pub fn new( + pub const fn new( location: BlockPos, action_id: u8, action_parameter: u8, diff --git a/pumpkin-protocol/src/java/client/play/block_update.rs b/pumpkin-protocol/src/java/client/play/block_update.rs index 6877b0c67..1f4c92232 100644 --- a/pumpkin-protocol/src/java/client/play/block_update.rs +++ b/pumpkin-protocol/src/java/client/play/block_update.rs @@ -21,7 +21,7 @@ pub struct CBlockUpdate { impl CBlockUpdate { #[must_use] - pub fn new(location: BlockPos, state_id: VarInt) -> Self { + pub const fn new(location: BlockPos, state_id: VarInt) -> Self { Self { location, state_id } } } diff --git a/pumpkin-protocol/src/java/client/play/boss_event.rs b/pumpkin-protocol/src/java/client/play/boss_event.rs index 51aa18826..fa8acc6f2 100644 --- a/pumpkin-protocol/src/java/client/play/boss_event.rs +++ b/pumpkin-protocol/src/java/client/play/boss_event.rs @@ -21,7 +21,7 @@ pub struct CBossEvent<'a> { impl<'a> CBossEvent<'a> { #[must_use] - pub fn new(uuid: &'a uuid::Uuid, action: BosseventAction) -> Self { + pub const fn new(uuid: &'a uuid::Uuid, action: BosseventAction) -> Self { Self { uuid, action } } } diff --git a/pumpkin-protocol/src/java/client/play/change_difficulty.rs b/pumpkin-protocol/src/java/client/play/change_difficulty.rs index d4711a859..580604561 100644 --- a/pumpkin-protocol/src/java/client/play/change_difficulty.rs +++ b/pumpkin-protocol/src/java/client/play/change_difficulty.rs @@ -24,7 +24,7 @@ pub struct CChangeDifficulty { impl CChangeDifficulty { #[must_use] - pub fn new(difficulty: u8, locked: bool) -> Self { + pub const fn new(difficulty: u8, locked: bool) -> Self { Self { difficulty, locked } } } diff --git a/pumpkin-protocol/src/java/client/play/combat_death.rs b/pumpkin-protocol/src/java/client/play/combat_death.rs index bf9f30df8..10560bdd1 100644 --- a/pumpkin-protocol/src/java/client/play/combat_death.rs +++ b/pumpkin-protocol/src/java/client/play/combat_death.rs @@ -20,7 +20,7 @@ pub struct CCombatDeath<'a> { impl<'a> CCombatDeath<'a> { #[must_use] - pub fn new(player_id: VarInt, message: &'a TextComponent) -> Self { + pub const fn new(player_id: VarInt, message: &'a TextComponent) -> Self { Self { player_id, message } } } diff --git a/pumpkin-protocol/src/java/client/play/command_suggestions.rs b/pumpkin-protocol/src/java/client/play/command_suggestions.rs index c61946920..365aea5e2 100644 --- a/pumpkin-protocol/src/java/client/play/command_suggestions.rs +++ b/pumpkin-protocol/src/java/client/play/command_suggestions.rs @@ -29,7 +29,7 @@ pub struct CCommandSuggestions { impl CCommandSuggestions { #[must_use] - pub fn new( + pub const fn new( id: VarInt, start: VarInt, length: VarInt, @@ -52,7 +52,7 @@ pub struct CommandSuggestion { impl CommandSuggestion { #[must_use] - pub fn new(suggestion: String, tooltip: Option) -> Self { + pub const fn new(suggestion: String, tooltip: Option) -> Self { Self { suggestion, tooltip, diff --git a/pumpkin-protocol/src/java/client/play/commands.rs b/pumpkin-protocol/src/java/client/play/commands.rs index 37a3dd146..250f54be9 100644 --- a/pumpkin-protocol/src/java/client/play/commands.rs +++ b/pumpkin-protocol/src/java/client/play/commands.rs @@ -23,7 +23,7 @@ pub struct CCommands<'a> { impl<'a> CCommands<'a> { #[must_use] - pub fn new(nodes: Box<[ProtoNode<'a>]>, root_node_index: VarInt) -> Self { + pub const fn new(nodes: Box<[ProtoNode<'a>]>, root_node_index: VarInt) -> Self { Self { nodes, root_node_index, @@ -331,7 +331,7 @@ pub enum SuggestionProviders { } impl SuggestionProviders { - fn resource_location(self) -> &'static str { + const fn resource_location(self) -> &'static str { match self { Self::AskServer => "minecraft:ask_server", Self::AllRecipes => "minecraft:all_recipes", diff --git a/pumpkin-protocol/src/java/client/play/cookie_request.rs b/pumpkin-protocol/src/java/client/play/cookie_request.rs index 950cab94f..be945d9be 100644 --- a/pumpkin-protocol/src/java/client/play/cookie_request.rs +++ b/pumpkin-protocol/src/java/client/play/cookie_request.rs @@ -17,7 +17,7 @@ pub struct CPlayCookieRequest<'a> { impl<'a> CPlayCookieRequest<'a> { #[must_use] - pub fn new(key: &'a ResourceLocation) -> Self { + pub const fn new(key: &'a ResourceLocation) -> Self { Self { key } } } diff --git a/pumpkin-protocol/src/java/client/play/disconnect.rs b/pumpkin-protocol/src/java/client/play/disconnect.rs index 748789738..8261d323a 100644 --- a/pumpkin-protocol/src/java/client/play/disconnect.rs +++ b/pumpkin-protocol/src/java/client/play/disconnect.rs @@ -19,7 +19,7 @@ pub struct CPlayDisconnect<'a> { impl<'a> CPlayDisconnect<'a> { #[must_use] - pub fn new(reason: &'a TextComponent) -> Self { + pub const fn new(reason: &'a TextComponent) -> Self { Self { reason } } } diff --git a/pumpkin-protocol/src/java/client/play/disguised_chat_message.rs b/pumpkin-protocol/src/java/client/play/disguised_chat_message.rs index 65e699d14..b2a7dca58 100644 --- a/pumpkin-protocol/src/java/client/play/disguised_chat_message.rs +++ b/pumpkin-protocol/src/java/client/play/disguised_chat_message.rs @@ -27,7 +27,7 @@ pub struct CDisguisedChatMessage<'a> { impl<'a> CDisguisedChatMessage<'a> { #[must_use] - pub fn new( + pub const fn new( message: &'a TextComponent, chat_type: VarInt, sender_name: &'a TextComponent, diff --git a/pumpkin-protocol/src/java/client/play/display_objective.rs b/pumpkin-protocol/src/java/client/play/display_objective.rs index 74fc7f7ae..8aa2885cf 100644 --- a/pumpkin-protocol/src/java/client/play/display_objective.rs +++ b/pumpkin-protocol/src/java/client/play/display_objective.rs @@ -23,7 +23,7 @@ pub struct CDisplayObjective { impl CDisplayObjective { #[must_use] - pub fn new(position: ScoreboardDisplaySlot, score_name: String) -> Self { + pub const fn new(position: ScoreboardDisplaySlot, score_name: String) -> Self { Self { position: VarInt(position as i32), score_name, diff --git a/pumpkin-protocol/src/java/client/play/entity_animation.rs b/pumpkin-protocol/src/java/client/play/entity_animation.rs index 27207a517..97e188140 100644 --- a/pumpkin-protocol/src/java/client/play/entity_animation.rs +++ b/pumpkin-protocol/src/java/client/play/entity_animation.rs @@ -20,7 +20,7 @@ pub struct CEntityAnimation { impl CEntityAnimation { #[must_use] - pub fn new(entity_id: VarInt, animation: Animation) -> Self { + pub const fn new(entity_id: VarInt, animation: Animation) -> Self { Self { entity_id, animation: animation as u8, diff --git a/pumpkin-protocol/src/java/client/play/entity_metadata.rs b/pumpkin-protocol/src/java/client/play/entity_metadata.rs index 8b674b47b..6c2302337 100644 --- a/pumpkin-protocol/src/java/client/play/entity_metadata.rs +++ b/pumpkin-protocol/src/java/client/play/entity_metadata.rs @@ -28,7 +28,7 @@ pub struct CSetEntityMetadata { impl CSetEntityMetadata { #[must_use] - pub fn new(entity_id: VarInt, metadata: Box<[u8]>) -> Self { + pub const fn new(entity_id: VarInt, metadata: Box<[u8]>) -> Self { Self { entity_id, metadata, @@ -43,7 +43,7 @@ pub struct Metadata { } impl Metadata { - pub fn new(index: TrackedId, r#type: MetaDataType, value: T) -> Self { + pub const fn new(index: TrackedId, r#type: MetaDataType, value: T) -> Self { Self { index, r#type: VarInt(r#type as i32), diff --git a/pumpkin-protocol/src/java/client/play/entity_position_sync.rs b/pumpkin-protocol/src/java/client/play/entity_position_sync.rs index 83806f58b..51e44b486 100644 --- a/pumpkin-protocol/src/java/client/play/entity_position_sync.rs +++ b/pumpkin-protocol/src/java/client/play/entity_position_sync.rs @@ -33,7 +33,7 @@ pub struct CEntityPositionSync { impl CEntityPositionSync { #[must_use] - pub fn new( + pub const fn new( entity_id: VarInt, position: Vector3, delta: Vector3, diff --git a/pumpkin-protocol/src/java/client/play/entity_sound_effect.rs b/pumpkin-protocol/src/java/client/play/entity_sound_effect.rs index 21f02ba55..1909a6f11 100644 --- a/pumpkin-protocol/src/java/client/play/entity_sound_effect.rs +++ b/pumpkin-protocol/src/java/client/play/entity_sound_effect.rs @@ -31,7 +31,7 @@ pub struct CEntitySoundEffect { impl CEntitySoundEffect { #[must_use] - pub fn new( + pub const fn new( sound_event: IdOr, sound_category: SoundCategory, entity_id: VarInt, diff --git a/pumpkin-protocol/src/java/client/play/entity_status.rs b/pumpkin-protocol/src/java/client/play/entity_status.rs index 4ccd280fe..240eb632e 100644 --- a/pumpkin-protocol/src/java/client/play/entity_status.rs +++ b/pumpkin-protocol/src/java/client/play/entity_status.rs @@ -20,7 +20,7 @@ pub struct CEntityStatus { impl CEntityStatus { #[must_use] - pub fn new(entity_id: i32, entity_status: i8) -> Self { + pub const fn new(entity_id: i32, entity_status: i8) -> Self { Self { entity_id, entity_status, diff --git a/pumpkin-protocol/src/java/client/play/entity_velocity.rs b/pumpkin-protocol/src/java/client/play/entity_velocity.rs index b0606412d..a3d175645 100644 --- a/pumpkin-protocol/src/java/client/play/entity_velocity.rs +++ b/pumpkin-protocol/src/java/client/play/entity_velocity.rs @@ -20,7 +20,7 @@ pub struct CEntityVelocity { impl CEntityVelocity { #[must_use] - pub fn new(entity_id: VarInt, velocity: Vector3) -> Self { + pub const fn new(entity_id: VarInt, velocity: Vector3) -> Self { Self { entity_id, velocity: Velocity(velocity), diff --git a/pumpkin-protocol/src/java/client/play/explode.rs b/pumpkin-protocol/src/java/client/play/explode.rs index 2cbc7d793..61aac0cb0 100644 --- a/pumpkin-protocol/src/java/client/play/explode.rs +++ b/pumpkin-protocol/src/java/client/play/explode.rs @@ -35,7 +35,7 @@ pub struct CExplosion { impl CExplosion { #[must_use] - pub fn new( + pub const fn new( center: Vector3, radius: f32, block_count: i32, diff --git a/pumpkin-protocol/src/java/client/play/game_event.rs b/pumpkin-protocol/src/java/client/play/game_event.rs index 10835079d..e99fdad54 100644 --- a/pumpkin-protocol/src/java/client/play/game_event.rs +++ b/pumpkin-protocol/src/java/client/play/game_event.rs @@ -19,7 +19,7 @@ pub struct CGameEvent { /// You need to implement all the random stuff somewhere, right? impl CGameEvent { #[must_use] - pub fn new(event: GameEvent, value: f32) -> Self { + pub const fn new(event: GameEvent, value: f32) -> Self { Self { event: event as u8, value, diff --git a/pumpkin-protocol/src/java/client/play/head_rot.rs b/pumpkin-protocol/src/java/client/play/head_rot.rs index 93590d0bf..04fe4b7aa 100644 --- a/pumpkin-protocol/src/java/client/play/head_rot.rs +++ b/pumpkin-protocol/src/java/client/play/head_rot.rs @@ -21,7 +21,7 @@ pub struct CHeadRot { impl CHeadRot { #[must_use] - pub fn new(entity_id: VarInt, head_yaw: u8) -> Self { + pub const fn new(entity_id: VarInt, head_yaw: u8) -> Self { Self { entity_id, head_yaw, diff --git a/pumpkin-protocol/src/java/client/play/hurt_animation.rs b/pumpkin-protocol/src/java/client/play/hurt_animation.rs index 786be9fc3..4b19fa7cd 100644 --- a/pumpkin-protocol/src/java/client/play/hurt_animation.rs +++ b/pumpkin-protocol/src/java/client/play/hurt_animation.rs @@ -21,7 +21,7 @@ pub struct CHurtAnimation { impl CHurtAnimation { #[must_use] - pub fn new(entity_id: VarInt, yaw: f32) -> Self { + pub const fn new(entity_id: VarInt, yaw: f32) -> Self { Self { entity_id, yaw } } } diff --git a/pumpkin-protocol/src/java/client/play/initialize_world_border.rs b/pumpkin-protocol/src/java/client/play/initialize_world_border.rs index 692199413..e58274b4e 100644 --- a/pumpkin-protocol/src/java/client/play/initialize_world_border.rs +++ b/pumpkin-protocol/src/java/client/play/initialize_world_border.rs @@ -35,7 +35,7 @@ pub struct CInitializeWorldBorder { impl CInitializeWorldBorder { #[expect(clippy::too_many_arguments)] #[must_use] - pub fn new( + pub const fn new( x: f64, z: f64, old_diameter: f64, diff --git a/pumpkin-protocol/src/java/client/play/keep_alive.rs b/pumpkin-protocol/src/java/client/play/keep_alive.rs index 18048bd93..16569b6d0 100644 --- a/pumpkin-protocol/src/java/client/play/keep_alive.rs +++ b/pumpkin-protocol/src/java/client/play/keep_alive.rs @@ -18,7 +18,7 @@ pub struct CKeepAlive { impl CKeepAlive { #[must_use] - pub fn new(keep_alive_id: i64) -> Self { + pub const fn new(keep_alive_id: i64) -> Self { Self { keep_alive_id } } } diff --git a/pumpkin-protocol/src/java/client/play/level_event.rs b/pumpkin-protocol/src/java/client/play/level_event.rs index 079d4c4b0..0a06db80f 100644 --- a/pumpkin-protocol/src/java/client/play/level_event.rs +++ b/pumpkin-protocol/src/java/client/play/level_event.rs @@ -27,7 +27,12 @@ pub struct CLevelEvent { impl CLevelEvent { #[must_use] - pub fn new(event: i32, location: BlockPos, data: i32, disable_relative_volume: bool) -> Self { + pub const fn new( + event: i32, + location: BlockPos, + data: i32, + disable_relative_volume: bool, + ) -> Self { Self { event, location, diff --git a/pumpkin-protocol/src/java/client/play/login.rs b/pumpkin-protocol/src/java/client/play/login.rs index cb514dfc1..0b4a3d4cf 100644 --- a/pumpkin-protocol/src/java/client/play/login.rs +++ b/pumpkin-protocol/src/java/client/play/login.rs @@ -56,7 +56,7 @@ impl<'a> CLogin<'a> { #[expect(clippy::too_many_arguments)] #[expect(clippy::fn_params_excessive_bools)] #[must_use] - pub fn new( + pub const fn new( entity_id: i32, is_hardcore: bool, dimension_names: &'a [ResourceLocation], diff --git a/pumpkin-protocol/src/java/client/play/open_screen.rs b/pumpkin-protocol/src/java/client/play/open_screen.rs index 9c9d62e2f..8915422a4 100644 --- a/pumpkin-protocol/src/java/client/play/open_screen.rs +++ b/pumpkin-protocol/src/java/client/play/open_screen.rs @@ -28,7 +28,11 @@ pub struct COpenScreen<'a> { impl<'a> COpenScreen<'a> { #[must_use] - pub fn new(window_id: VarInt, window_type: VarInt, window_title: &'a TextComponent) -> Self { + pub const fn new( + window_id: VarInt, + window_type: VarInt, + window_title: &'a TextComponent, + ) -> Self { Self { sync_id: window_id, window_type, diff --git a/pumpkin-protocol/src/java/client/play/open_sign_editor.rs b/pumpkin-protocol/src/java/client/play/open_sign_editor.rs index dd9920b3e..1c5452c51 100644 --- a/pumpkin-protocol/src/java/client/play/open_sign_editor.rs +++ b/pumpkin-protocol/src/java/client/play/open_sign_editor.rs @@ -20,7 +20,7 @@ pub struct COpenSignEditor { impl COpenSignEditor { #[must_use] - pub fn new(location: BlockPos, is_front_text: bool) -> Self { + pub const fn new(location: BlockPos, is_front_text: bool) -> Self { Self { location, is_front_text, diff --git a/pumpkin-protocol/src/java/client/play/particle.rs b/pumpkin-protocol/src/java/client/play/particle.rs index aff45607e..0a0c1eb81 100644 --- a/pumpkin-protocol/src/java/client/play/particle.rs +++ b/pumpkin-protocol/src/java/client/play/particle.rs @@ -39,7 +39,7 @@ pub struct CParticle<'a> { impl<'a> CParticle<'a> { #[expect(clippy::too_many_arguments)] #[must_use] - pub fn new( + pub const fn new( force_spawn: bool, important: bool, position: Vector3, diff --git a/pumpkin-protocol/src/java/client/play/ping_response.rs b/pumpkin-protocol/src/java/client/play/ping_response.rs index a89be8794..4a502ff2b 100644 --- a/pumpkin-protocol/src/java/client/play/ping_response.rs +++ b/pumpkin-protocol/src/java/client/play/ping_response.rs @@ -13,7 +13,7 @@ pub struct CPingResponse { impl CPingResponse { #[must_use] - pub fn new(payload: i64) -> Self { + pub const fn new(payload: i64) -> Self { Self { payload } } } diff --git a/pumpkin-protocol/src/java/client/play/player_abilities.rs b/pumpkin-protocol/src/java/client/play/player_abilities.rs index 2782dbd4d..72fcbd5b2 100644 --- a/pumpkin-protocol/src/java/client/play/player_abilities.rs +++ b/pumpkin-protocol/src/java/client/play/player_abilities.rs @@ -26,7 +26,7 @@ pub struct CPlayerAbilities { impl CPlayerAbilities { #[must_use] - pub fn new(flags: i8, flying_speed: f32, field_of_view: f32) -> Self { + pub const fn new(flags: i8, flying_speed: f32, field_of_view: f32) -> Self { Self { flags, flying_speed, diff --git a/pumpkin-protocol/src/java/client/play/player_chat_message.rs b/pumpkin-protocol/src/java/client/play/player_chat_message.rs index 05ad038d6..c94a61ccc 100644 --- a/pumpkin-protocol/src/java/client/play/player_chat_message.rs +++ b/pumpkin-protocol/src/java/client/play/player_chat_message.rs @@ -53,7 +53,7 @@ pub struct CPlayerChatMessage { impl CPlayerChatMessage { #[expect(clippy::too_many_arguments)] #[must_use] - pub fn new( + pub const fn new( global_index: VarInt, sender: uuid::Uuid, index: VarInt, diff --git a/pumpkin-protocol/src/java/client/play/player_info_update.rs b/pumpkin-protocol/src/java/client/play/player_info_update.rs index 0952e0d4b..90f40e931 100644 --- a/pumpkin-protocol/src/java/client/play/player_info_update.rs +++ b/pumpkin-protocol/src/java/client/play/player_info_update.rs @@ -56,7 +56,7 @@ pub struct Player<'a> { impl<'a> CPlayerInfoUpdate<'a> { #[must_use] - pub fn new(actions: u8, players: &'a [Player<'a>]) -> Self { + pub const fn new(actions: u8, players: &'a [Player<'a>]) -> Self { Self { actions, players } } } diff --git a/pumpkin-protocol/src/java/client/play/player_position.rs b/pumpkin-protocol/src/java/client/play/player_position.rs index 11c8412f7..c1d25cc6a 100644 --- a/pumpkin-protocol/src/java/client/play/player_position.rs +++ b/pumpkin-protocol/src/java/client/play/player_position.rs @@ -33,7 +33,7 @@ pub struct CPlayerPosition { impl CPlayerPosition { #[must_use] - pub fn new( + pub const fn new( teleport_id: VarInt, position: Vector3, delta: Vector3, diff --git a/pumpkin-protocol/src/java/client/play/player_remove.rs b/pumpkin-protocol/src/java/client/play/player_remove.rs index 3f2ddedcd..91dd0d75b 100644 --- a/pumpkin-protocol/src/java/client/play/player_remove.rs +++ b/pumpkin-protocol/src/java/client/play/player_remove.rs @@ -19,7 +19,7 @@ pub struct CRemovePlayerInfo<'a> { impl<'a> CRemovePlayerInfo<'a> { #[must_use] - pub fn new(players: &'a [uuid::Uuid]) -> Self { + pub const fn new(players: &'a [uuid::Uuid]) -> Self { Self { players } } } diff --git a/pumpkin-protocol/src/java/client/play/player_spawn_position.rs b/pumpkin-protocol/src/java/client/play/player_spawn_position.rs index 3d766bbc7..a98f30509 100644 --- a/pumpkin-protocol/src/java/client/play/player_spawn_position.rs +++ b/pumpkin-protocol/src/java/client/play/player_spawn_position.rs @@ -28,7 +28,7 @@ pub struct CPlayerSpawnPosition { impl CPlayerSpawnPosition { #[must_use] - pub fn new(location: BlockPos, yaw: f32, pitch: f32, dimension_name: String) -> Self { + pub const fn new(location: BlockPos, yaw: f32, pitch: f32, dimension_name: String) -> Self { Self { dimension_name, location, diff --git a/pumpkin-protocol/src/java/client/play/remove_entities.rs b/pumpkin-protocol/src/java/client/play/remove_entities.rs index 568b93e12..9bd02eb0e 100644 --- a/pumpkin-protocol/src/java/client/play/remove_entities.rs +++ b/pumpkin-protocol/src/java/client/play/remove_entities.rs @@ -17,7 +17,7 @@ pub struct CRemoveEntities<'a> { impl<'a> CRemoveEntities<'a> { #[must_use] - pub fn new(entity_ids: &'a [VarInt]) -> Self { + pub const fn new(entity_ids: &'a [VarInt]) -> Self { Self { entity_ids } } } diff --git a/pumpkin-protocol/src/java/client/play/remove_mob_effect.rs b/pumpkin-protocol/src/java/client/play/remove_mob_effect.rs index a4f83b04a..82df113d5 100644 --- a/pumpkin-protocol/src/java/client/play/remove_mob_effect.rs +++ b/pumpkin-protocol/src/java/client/play/remove_mob_effect.rs @@ -12,7 +12,7 @@ pub struct CRemoveMobEffect { impl CRemoveMobEffect { #[must_use] - pub fn new(entity_id: VarInt, effect_id: VarInt) -> Self { + pub const fn new(entity_id: VarInt, effect_id: VarInt) -> Self { Self { entity_id, effect_id, diff --git a/pumpkin-protocol/src/java/client/play/reset_score.rs b/pumpkin-protocol/src/java/client/play/reset_score.rs index f9ad4cc29..26611b3cd 100644 --- a/pumpkin-protocol/src/java/client/play/reset_score.rs +++ b/pumpkin-protocol/src/java/client/play/reset_score.rs @@ -11,7 +11,7 @@ pub struct CResetScore { impl CResetScore { #[must_use] - pub fn new(entity_name: String, objective_name: Option) -> Self { + pub const fn new(entity_name: String, objective_name: Option) -> Self { Self { entity_name, objective_name, diff --git a/pumpkin-protocol/src/java/client/play/respawn.rs b/pumpkin-protocol/src/java/client/play/respawn.rs index 1aebfe1c8..30e65ba47 100644 --- a/pumpkin-protocol/src/java/client/play/respawn.rs +++ b/pumpkin-protocol/src/java/client/play/respawn.rs @@ -24,7 +24,7 @@ pub struct CRespawn { impl CRespawn { #[expect(clippy::too_many_arguments)] #[must_use] - pub fn new( + pub const fn new( dimension_type: VarInt, dimension_name: ResourceLocation, hashed_seed: i64, diff --git a/pumpkin-protocol/src/java/client/play/server_links.rs b/pumpkin-protocol/src/java/client/play/server_links.rs index afc0f8690..b761e9da8 100644 --- a/pumpkin-protocol/src/java/client/play/server_links.rs +++ b/pumpkin-protocol/src/java/client/play/server_links.rs @@ -11,7 +11,7 @@ pub struct CPlayServerLinks<'a> { impl<'a> CPlayServerLinks<'a> { #[must_use] - pub fn new(links: &'a [Link<'a>]) -> Self { + pub const fn new(links: &'a [Link<'a>]) -> Self { Self { links } } } diff --git a/pumpkin-protocol/src/java/client/play/set_border_center.rs b/pumpkin-protocol/src/java/client/play/set_border_center.rs index 6190a3649..0efd24ddd 100644 --- a/pumpkin-protocol/src/java/client/play/set_border_center.rs +++ b/pumpkin-protocol/src/java/client/play/set_border_center.rs @@ -11,7 +11,7 @@ pub struct CSetBorderCenter { impl CSetBorderCenter { #[must_use] - pub fn new(x: f64, z: f64) -> Self { + pub const fn new(x: f64, z: f64) -> Self { Self { x, z } } } diff --git a/pumpkin-protocol/src/java/client/play/set_border_lerp_size.rs b/pumpkin-protocol/src/java/client/play/set_border_lerp_size.rs index f998f874c..d5f48817c 100644 --- a/pumpkin-protocol/src/java/client/play/set_border_lerp_size.rs +++ b/pumpkin-protocol/src/java/client/play/set_border_lerp_size.rs @@ -14,7 +14,7 @@ pub struct CSetBorderLerpSize { impl CSetBorderLerpSize { #[must_use] - pub fn new(old_diameter: f64, new_diameter: f64, speed: VarLong) -> Self { + pub const fn new(old_diameter: f64, new_diameter: f64, speed: VarLong) -> Self { Self { old_diameter, new_diameter, diff --git a/pumpkin-protocol/src/java/client/play/set_border_size.rs b/pumpkin-protocol/src/java/client/play/set_border_size.rs index 8b1ff4d0e..e6f3bb2bb 100644 --- a/pumpkin-protocol/src/java/client/play/set_border_size.rs +++ b/pumpkin-protocol/src/java/client/play/set_border_size.rs @@ -10,7 +10,7 @@ pub struct CSetBorderSize { impl CSetBorderSize { #[must_use] - pub fn new(diameter: f64) -> Self { + pub const fn new(diameter: f64) -> Self { Self { diameter } } } diff --git a/pumpkin-protocol/src/java/client/play/set_border_warning_delay.rs b/pumpkin-protocol/src/java/client/play/set_border_warning_delay.rs index 4fd1616f0..ffc38ac7e 100644 --- a/pumpkin-protocol/src/java/client/play/set_border_warning_delay.rs +++ b/pumpkin-protocol/src/java/client/play/set_border_warning_delay.rs @@ -12,7 +12,7 @@ pub struct CSetBorderWarningDelay { impl CSetBorderWarningDelay { #[must_use] - pub fn new(warning_time: VarInt) -> Self { + pub const fn new(warning_time: VarInt) -> Self { Self { warning_time } } } diff --git a/pumpkin-protocol/src/java/client/play/set_border_warning_distance.rs b/pumpkin-protocol/src/java/client/play/set_border_warning_distance.rs index f24b4785e..981aeeb5e 100644 --- a/pumpkin-protocol/src/java/client/play/set_border_warning_distance.rs +++ b/pumpkin-protocol/src/java/client/play/set_border_warning_distance.rs @@ -12,7 +12,7 @@ pub struct CSetBorderWarningDistance { impl CSetBorderWarningDistance { #[must_use] - pub fn new(warning_blocks: VarInt) -> Self { + pub const fn new(warning_blocks: VarInt) -> Self { Self { warning_blocks } } } diff --git a/pumpkin-protocol/src/java/client/play/set_container_content.rs b/pumpkin-protocol/src/java/client/play/set_container_content.rs index 91f8c1e3d..3e8192651 100644 --- a/pumpkin-protocol/src/java/client/play/set_container_content.rs +++ b/pumpkin-protocol/src/java/client/play/set_container_content.rs @@ -16,7 +16,7 @@ pub struct CSetContainerContent<'a> { impl<'a> CSetContainerContent<'a> { #[must_use] - pub fn new( + pub const fn new( window_id: VarInt, state_id: VarInt, slots: &'a [ItemStackSerializer], diff --git a/pumpkin-protocol/src/java/client/play/set_cursor_slot.rs b/pumpkin-protocol/src/java/client/play/set_cursor_slot.rs index cffac2ce6..d1b7a8c57 100644 --- a/pumpkin-protocol/src/java/client/play/set_cursor_slot.rs +++ b/pumpkin-protocol/src/java/client/play/set_cursor_slot.rs @@ -12,7 +12,7 @@ pub struct CSetCursorItem<'a> { impl<'a> CSetCursorItem<'a> { #[must_use] - pub fn new(stack: &'a ItemStackSerializer<'a>) -> Self { + pub const fn new(stack: &'a ItemStackSerializer<'a>) -> Self { Self { stack } } } diff --git a/pumpkin-protocol/src/java/client/play/set_equipment.rs b/pumpkin-protocol/src/java/client/play/set_equipment.rs index 740bda74f..7f4fb1836 100644 --- a/pumpkin-protocol/src/java/client/play/set_equipment.rs +++ b/pumpkin-protocol/src/java/client/play/set_equipment.rs @@ -22,7 +22,10 @@ pub struct CSetEquipment { impl CSetEquipment { #[must_use] - pub fn new(entity_id: VarInt, equipment: Vec<(i8, ItemStackSerializer<'static>)>) -> Self { + pub const fn new( + entity_id: VarInt, + equipment: Vec<(i8, ItemStackSerializer<'static>)>, + ) -> Self { Self { entity_id, equipment, diff --git a/pumpkin-protocol/src/java/client/play/set_experience.rs b/pumpkin-protocol/src/java/client/play/set_experience.rs index a2ca5d0b0..251ba6419 100644 --- a/pumpkin-protocol/src/java/client/play/set_experience.rs +++ b/pumpkin-protocol/src/java/client/play/set_experience.rs @@ -14,7 +14,7 @@ pub struct CSetExperience { impl CSetExperience { #[must_use] - pub fn new(progress: f32, level: VarInt, total_experience: VarInt) -> Self { + pub const fn new(progress: f32, level: VarInt, total_experience: VarInt) -> Self { Self { progress, total_experience, diff --git a/pumpkin-protocol/src/java/client/play/set_health.rs b/pumpkin-protocol/src/java/client/play/set_health.rs index 6f96aed0d..f377b2a98 100644 --- a/pumpkin-protocol/src/java/client/play/set_health.rs +++ b/pumpkin-protocol/src/java/client/play/set_health.rs @@ -14,7 +14,7 @@ pub struct CSetHealth { impl CSetHealth { #[must_use] - pub fn new(health: f32, food: VarInt, food_saturation: f32) -> Self { + pub const fn new(health: f32, food: VarInt, food_saturation: f32) -> Self { Self { health, food, diff --git a/pumpkin-protocol/src/java/client/play/set_held_item.rs b/pumpkin-protocol/src/java/client/play/set_held_item.rs index 6a359d848..488c01328 100644 --- a/pumpkin-protocol/src/java/client/play/set_held_item.rs +++ b/pumpkin-protocol/src/java/client/play/set_held_item.rs @@ -10,7 +10,7 @@ pub struct CSetSelectedSlot { impl CSetSelectedSlot { #[must_use] - pub fn new(slot: i8) -> Self { + pub const fn new(slot: i8) -> Self { Self { slot } } } diff --git a/pumpkin-protocol/src/java/client/play/set_player_inventory.rs b/pumpkin-protocol/src/java/client/play/set_player_inventory.rs index c73793352..6bbcf340f 100644 --- a/pumpkin-protocol/src/java/client/play/set_player_inventory.rs +++ b/pumpkin-protocol/src/java/client/play/set_player_inventory.rs @@ -14,7 +14,7 @@ pub struct CSetPlayerInventory<'a> { impl<'a> CSetPlayerInventory<'a> { #[must_use] - pub fn new(slot: VarInt, item: &'a ItemStackSerializer<'a>) -> Self { + pub const fn new(slot: VarInt, item: &'a ItemStackSerializer<'a>) -> Self { Self { slot, item } } } diff --git a/pumpkin-protocol/src/java/client/play/set_time.rs b/pumpkin-protocol/src/java/client/play/set_time.rs index 21b57a9a6..fc4a29786 100644 --- a/pumpkin-protocol/src/java/client/play/set_time.rs +++ b/pumpkin-protocol/src/java/client/play/set_time.rs @@ -12,7 +12,7 @@ pub struct CUpdateTime { impl CUpdateTime { #[must_use] - pub fn new(world_age: i64, time_of_day: i64, time_of_day_increasing: bool) -> Self { + pub const fn new(world_age: i64, time_of_day: i64, time_of_day_increasing: bool) -> Self { Self { world_age, time_of_day, diff --git a/pumpkin-protocol/src/java/client/play/set_title.rs b/pumpkin-protocol/src/java/client/play/set_title.rs index 61d33398f..45b3da258 100644 --- a/pumpkin-protocol/src/java/client/play/set_title.rs +++ b/pumpkin-protocol/src/java/client/play/set_title.rs @@ -12,7 +12,7 @@ pub struct CTitleText<'a> { impl<'a> CTitleText<'a> { #[must_use] - pub fn new(title: &'a TextComponent) -> Self { + pub const fn new(title: &'a TextComponent) -> Self { Self { title } } } diff --git a/pumpkin-protocol/src/java/client/play/set_title_animation.rs b/pumpkin-protocol/src/java/client/play/set_title_animation.rs index 07f85bb7c..d2fce2144 100644 --- a/pumpkin-protocol/src/java/client/play/set_title_animation.rs +++ b/pumpkin-protocol/src/java/client/play/set_title_animation.rs @@ -13,7 +13,7 @@ pub struct CTitleAnimation { impl CTitleAnimation { #[must_use] - pub fn new(fade_in_ticks: i32, stay_ticks: i32, fade_out_ticks: i32) -> Self { + pub const fn new(fade_in_ticks: i32, stay_ticks: i32, fade_out_ticks: i32) -> Self { Self { fade_in_ticks, stay_ticks, diff --git a/pumpkin-protocol/src/java/client/play/stop_sound.rs b/pumpkin-protocol/src/java/client/play/stop_sound.rs index cade760f5..d822de77c 100644 --- a/pumpkin-protocol/src/java/client/play/stop_sound.rs +++ b/pumpkin-protocol/src/java/client/play/stop_sound.rs @@ -16,7 +16,7 @@ pub struct CStopSound { impl CStopSound { #[must_use] - pub fn new(sound_id: Option, category: Option) -> Self { + pub const fn new(sound_id: Option, category: Option) -> Self { Self { sound_id, category } } } diff --git a/pumpkin-protocol/src/java/client/play/store_cookie.rs b/pumpkin-protocol/src/java/client/play/store_cookie.rs index 27d30799c..4f503e55d 100644 --- a/pumpkin-protocol/src/java/client/play/store_cookie.rs +++ b/pumpkin-protocol/src/java/client/play/store_cookie.rs @@ -14,7 +14,7 @@ pub struct CStoreCookie<'a> { impl<'a> CStoreCookie<'a> { #[must_use] - pub fn new(key: &'a ResourceLocation, payload: &'a [u8]) -> Self { + pub const fn new(key: &'a ResourceLocation, payload: &'a [u8]) -> Self { Self { key, payload } } } diff --git a/pumpkin-protocol/src/java/client/play/subtitle.rs b/pumpkin-protocol/src/java/client/play/subtitle.rs index 2a830a2f9..f810bca94 100644 --- a/pumpkin-protocol/src/java/client/play/subtitle.rs +++ b/pumpkin-protocol/src/java/client/play/subtitle.rs @@ -12,7 +12,7 @@ pub struct CSubtitle<'a> { impl<'a> CSubtitle<'a> { #[must_use] - pub fn new(subtitle: &'a TextComponent) -> Self { + pub const fn new(subtitle: &'a TextComponent) -> Self { Self { subtitle } } } diff --git a/pumpkin-protocol/src/java/client/play/system_chat_message.rs b/pumpkin-protocol/src/java/client/play/system_chat_message.rs index 480c30101..e0ae64b88 100644 --- a/pumpkin-protocol/src/java/client/play/system_chat_message.rs +++ b/pumpkin-protocol/src/java/client/play/system_chat_message.rs @@ -13,7 +13,7 @@ pub struct CSystemChatMessage<'a> { impl<'a> CSystemChatMessage<'a> { #[must_use] - pub fn new(content: &'a TextComponent, overlay: bool) -> Self { + pub const fn new(content: &'a TextComponent, overlay: bool) -> Self { Self { content, overlay } } } diff --git a/pumpkin-protocol/src/java/client/play/take_item.rs b/pumpkin-protocol/src/java/client/play/take_item.rs index 0c27e7cb3..9a5f4a263 100644 --- a/pumpkin-protocol/src/java/client/play/take_item.rs +++ b/pumpkin-protocol/src/java/client/play/take_item.rs @@ -16,7 +16,7 @@ pub struct CTakeItemEntity { impl CTakeItemEntity { #[must_use] - pub fn new(entity_id: VarInt, collector_entity_id: VarInt, stack_amount: VarInt) -> Self { + pub const fn new(entity_id: VarInt, collector_entity_id: VarInt, stack_amount: VarInt) -> Self { Self { entity_id, collector_entity_id, diff --git a/pumpkin-protocol/src/java/client/play/teleport_entity.rs b/pumpkin-protocol/src/java/client/play/teleport_entity.rs index 659778d06..dab42a2db 100644 --- a/pumpkin-protocol/src/java/client/play/teleport_entity.rs +++ b/pumpkin-protocol/src/java/client/play/teleport_entity.rs @@ -20,7 +20,7 @@ pub struct CTeleportEntity<'a> { impl<'a> CTeleportEntity<'a> { #[must_use] - pub fn new( + pub const fn new( entity_id: VarInt, position: Vector3, delta: Vector3, diff --git a/pumpkin-protocol/src/java/client/play/ticking_state.rs b/pumpkin-protocol/src/java/client/play/ticking_state.rs index 23986533f..89b37c298 100644 --- a/pumpkin-protocol/src/java/client/play/ticking_state.rs +++ b/pumpkin-protocol/src/java/client/play/ticking_state.rs @@ -11,7 +11,7 @@ pub struct CTickingState { impl CTickingState { #[must_use] - pub fn new(tick_rate: f32, is_frozen: bool) -> Self { + pub const fn new(tick_rate: f32, is_frozen: bool) -> Self { Self { tick_rate, is_frozen, diff --git a/pumpkin-protocol/src/java/client/play/ticking_step.rs b/pumpkin-protocol/src/java/client/play/ticking_step.rs index fe527da17..a5faf98b3 100644 --- a/pumpkin-protocol/src/java/client/play/ticking_step.rs +++ b/pumpkin-protocol/src/java/client/play/ticking_step.rs @@ -12,7 +12,7 @@ pub struct CTickingStep { impl CTickingStep { #[must_use] - pub fn new(tick_steps: VarInt) -> Self { + pub const fn new(tick_steps: VarInt) -> Self { Self { tick_steps } } } diff --git a/pumpkin-protocol/src/java/client/play/transfer.rs b/pumpkin-protocol/src/java/client/play/transfer.rs index d44c45c12..5a690f4f3 100644 --- a/pumpkin-protocol/src/java/client/play/transfer.rs +++ b/pumpkin-protocol/src/java/client/play/transfer.rs @@ -12,7 +12,7 @@ pub struct CTransfer<'a> { impl<'a> CTransfer<'a> { #[must_use] - pub fn new(host: &'a str, port: VarInt) -> Self { + pub const fn new(host: &'a str, port: VarInt) -> Self { Self { host, port } } } diff --git a/pumpkin-protocol/src/java/client/play/unload_chunk.rs b/pumpkin-protocol/src/java/client/play/unload_chunk.rs index 7adb98a60..5e88fde33 100644 --- a/pumpkin-protocol/src/java/client/play/unload_chunk.rs +++ b/pumpkin-protocol/src/java/client/play/unload_chunk.rs @@ -11,7 +11,7 @@ pub struct CUnloadChunk { impl CUnloadChunk { #[must_use] - pub fn new(x: i32, z: i32) -> Self { + pub const fn new(x: i32, z: i32) -> Self { Self { z, x } } } diff --git a/pumpkin-protocol/src/java/client/play/update_entity_pos.rs b/pumpkin-protocol/src/java/client/play/update_entity_pos.rs index 1f327ad75..0b7916bf5 100644 --- a/pumpkin-protocol/src/java/client/play/update_entity_pos.rs +++ b/pumpkin-protocol/src/java/client/play/update_entity_pos.rs @@ -15,7 +15,7 @@ pub struct CUpdateEntityPos { impl CUpdateEntityPos { #[must_use] - pub fn new(entity_id: VarInt, delta: Vector3, on_ground: bool) -> Self { + pub const fn new(entity_id: VarInt, delta: Vector3, on_ground: bool) -> Self { Self { entity_id, delta, diff --git a/pumpkin-protocol/src/java/client/play/update_entity_pos_rot.rs b/pumpkin-protocol/src/java/client/play/update_entity_pos_rot.rs index 7a63c1ae6..258e1a8cc 100644 --- a/pumpkin-protocol/src/java/client/play/update_entity_pos_rot.rs +++ b/pumpkin-protocol/src/java/client/play/update_entity_pos_rot.rs @@ -17,7 +17,7 @@ pub struct CUpdateEntityPosRot { impl CUpdateEntityPosRot { #[must_use] - pub fn new( + pub const fn new( entity_id: VarInt, delta: Vector3, yaw: u8, diff --git a/pumpkin-protocol/src/java/client/play/update_entity_rot.rs b/pumpkin-protocol/src/java/client/play/update_entity_rot.rs index 374cde5dd..321609557 100644 --- a/pumpkin-protocol/src/java/client/play/update_entity_rot.rs +++ b/pumpkin-protocol/src/java/client/play/update_entity_rot.rs @@ -15,7 +15,7 @@ pub struct CUpdateEntityRot { impl CUpdateEntityRot { #[must_use] - pub fn new(entity_id: VarInt, yaw: u8, pitch: u8, on_ground: bool) -> Self { + pub const fn new(entity_id: VarInt, yaw: u8, pitch: u8, on_ground: bool) -> Self { Self { entity_id, yaw, diff --git a/pumpkin-protocol/src/java/client/play/update_mob_effect.rs b/pumpkin-protocol/src/java/client/play/update_mob_effect.rs index 3630e2cd1..98239a133 100644 --- a/pumpkin-protocol/src/java/client/play/update_mob_effect.rs +++ b/pumpkin-protocol/src/java/client/play/update_mob_effect.rs @@ -16,7 +16,7 @@ pub struct CUpdateMobEffect { impl CUpdateMobEffect { #[must_use] - pub fn new( + pub const fn new( entity_id: VarInt, effect_id: VarInt, amplifier: VarInt, diff --git a/pumpkin-protocol/src/java/client/play/update_objectives.rs b/pumpkin-protocol/src/java/client/play/update_objectives.rs index 7ad9f0cf9..2a6054858 100644 --- a/pumpkin-protocol/src/java/client/play/update_objectives.rs +++ b/pumpkin-protocol/src/java/client/play/update_objectives.rs @@ -17,7 +17,7 @@ pub struct CUpdateObjectives { impl CUpdateObjectives { #[must_use] - pub fn new( + pub const fn new( objective_name: String, mode: Mode, display_name: TextComponent, diff --git a/pumpkin-protocol/src/java/client/play/update_score.rs b/pumpkin-protocol/src/java/client/play/update_score.rs index 01a987be5..f7f5b279c 100644 --- a/pumpkin-protocol/src/java/client/play/update_score.rs +++ b/pumpkin-protocol/src/java/client/play/update_score.rs @@ -30,7 +30,7 @@ pub struct CUpdateScore { impl CUpdateScore { #[must_use] - pub fn new( + pub const fn new( entity_name: String, objective_name: String, value: VarInt, diff --git a/pumpkin-protocol/src/java/client/play/worldevent.rs b/pumpkin-protocol/src/java/client/play/worldevent.rs index d67069bb8..1aee184fe 100644 --- a/pumpkin-protocol/src/java/client/play/worldevent.rs +++ b/pumpkin-protocol/src/java/client/play/worldevent.rs @@ -28,7 +28,12 @@ pub struct CWorldEvent { impl CWorldEvent { #[must_use] - pub fn new(event: i32, location: BlockPos, data: i32, disable_relative_volume: bool) -> Self { + pub const fn new( + event: i32, + location: BlockPos, + data: i32, + disable_relative_volume: bool, + ) -> Self { Self { event, location, diff --git a/pumpkin-protocol/src/java/client/status/ping_response.rs b/pumpkin-protocol/src/java/client/status/ping_response.rs index 0db8ea37f..d8e772de9 100644 --- a/pumpkin-protocol/src/java/client/status/ping_response.rs +++ b/pumpkin-protocol/src/java/client/status/ping_response.rs @@ -18,7 +18,7 @@ pub struct CPingResponse { impl CPingResponse { #[must_use] - pub fn new(payload: i64) -> Self { + pub const fn new(payload: i64) -> Self { Self { payload } } } diff --git a/pumpkin-protocol/src/java/client/status/status_response.rs b/pumpkin-protocol/src/java/client/status/status_response.rs index 6c3101445..b54de8f5c 100644 --- a/pumpkin-protocol/src/java/client/status/status_response.rs +++ b/pumpkin-protocol/src/java/client/status/status_response.rs @@ -17,7 +17,7 @@ pub struct CStatusResponse { } impl CStatusResponse { #[must_use] - pub fn new(json_response: String) -> Self { + pub const fn new(json_response: String) -> Self { Self { json_response } } } diff --git a/pumpkin-protocol/src/java/packet_decoder.rs b/pumpkin-protocol/src/java/packet_decoder.rs index 62a6a07c6..3285fa365 100644 --- a/pumpkin-protocol/src/java/packet_decoder.rs +++ b/pumpkin-protocol/src/java/packet_decoder.rs @@ -77,14 +77,14 @@ pub struct TCPNetworkDecoder { } impl TCPNetworkDecoder { - pub fn new(reader: R) -> Self { + pub const fn new(reader: R) -> Self { Self { reader: DecryptionReader::None(reader), compression: None, } } - pub fn set_compression(&mut self, threshold: CompressionThreshold) { + pub const fn set_compression(&mut self, threshold: CompressionThreshold) { self.compression = Some(threshold); } @@ -238,7 +238,7 @@ mod tests { /// Test decoding without compression and encryption #[tokio::test] - async fn test_decode_without_compression_and_encryption() { + async fn decode_without_compression_and_encryption() { // Sample packet data: packet_id = 1, payload = "Hello" let packet_id = 1; let payload = b"Hello"; @@ -258,7 +258,7 @@ mod tests { /// Test decoding with compression #[tokio::test] - async fn test_decode_with_compression() { + async fn decode_with_compression() { // Sample packet data: packet_id = 2, payload = "Hello, compressed world!" let packet_id = 2; let payload = b"Hello, compressed world!"; @@ -280,7 +280,7 @@ mod tests { /// Test decoding with encryption #[tokio::test] - async fn test_decode_with_encryption() { + async fn decode_with_encryption() { // Sample packet data: packet_id = 3, payload = "Hello, encrypted world!" let packet_id = 3; let payload = b"Hello, encrypted world!"; @@ -304,7 +304,7 @@ mod tests { /// Test decoding with both compression and encryption #[tokio::test] - async fn test_decode_with_compression_and_encryption() { + async fn decode_with_compression_and_encryption() { // Sample packet data: packet_id = 4, payload = "Hello, compressed and encrypted world!" let packet_id = 4; let payload = b"Hello, compressed and encrypted world!"; @@ -330,7 +330,7 @@ mod tests { /// Test decoding with invalid compressed data #[tokio::test] - async fn test_decode_with_invalid_compressed_data() { + async fn decode_with_invalid_compressed_data() { // Sample packet data: packet_id = 5, payload_len = 10, but compressed data is invalid let data_len = 10; // Expected decompressed size let invalid_compressed_data = vec![0xFF, 0xFF, 0xFF]; // Invalid Zlib data @@ -364,7 +364,7 @@ mod tests { /// Test decoding with a zero-length packet #[tokio::test] - async fn test_decode_with_zero_length_packet() { + async fn decode_with_zero_length_packet() { // Sample packet data: packet_id = 7, payload = "" (empty) let packet_id = 7; let payload = b""; @@ -384,7 +384,7 @@ mod tests { /// Test decoding with maximum length packet #[tokio::test] #[expect(clippy::print_stdout)] - async fn test_decode_with_maximum_length_packet() { + async fn decode_with_maximum_length_packet() { // Sample packet data: packet_id = 8, payload = "A" repeated MAX_PACKET_SIZE times // Sample packet data: packet_id = 8, payload = "A" repeated (MAX_PACKET_SIZE - 1) times let packet_id = 8; diff --git a/pumpkin-protocol/src/java/packet_encoder.rs b/pumpkin-protocol/src/java/packet_encoder.rs index e1e6f1cd0..da6e27818 100644 --- a/pumpkin-protocol/src/java/packet_encoder.rs +++ b/pumpkin-protocol/src/java/packet_encoder.rs @@ -87,14 +87,17 @@ pub struct TCPNetworkEncoder { } impl TCPNetworkEncoder { - pub fn new(writer: W) -> Self { + pub const fn new(writer: W) -> Self { Self { writer: EncryptionWriter::None(writer), compression: None, } } - pub fn set_compression(&mut self, compression_info: (CompressionThreshold, CompressionLevel)) { + pub const fn set_compression( + &mut self, + compression_info: (CompressionThreshold, CompressionLevel), + ) { self.compression = Some(compression_info); } @@ -354,7 +357,7 @@ mod tests { /// Test encoding without compression and encryption #[tokio::test] - async fn test_encode_without_compression_and_encryption() { + async fn encode_without_compression_and_encryption() { // Create a CStatusResponse packet let packet = CStatusResponse::new(String::from("{\"description\": \"A Minecraft Server\"}")); @@ -389,7 +392,7 @@ mod tests { /// Test encoding with compression #[tokio::test] - async fn test_encode_with_compression() { + async fn encode_with_compression() { // Create a CStatusResponse packet let packet = CStatusResponse::new("{\"description\": \"A Minecraft Server\"}".to_string()); @@ -438,7 +441,7 @@ mod tests { /// Test encoding with encryption #[tokio::test] - async fn test_encode_with_encryption() { + async fn encode_with_encryption() { // Create a CStatusResponse packet let packet = CStatusResponse::new("{\"description\": \"A Minecraft Server\"}".to_string()); @@ -476,7 +479,7 @@ mod tests { /// Test encoding with both compression and encryption #[tokio::test] - async fn test_encode_with_compression_and_encryption() { + async fn encode_with_compression_and_encryption() { // Create a CStatusResponse packet let packet = CStatusResponse::new("{\"description\": \"A Minecraft Server\"}".to_string()); @@ -532,7 +535,7 @@ mod tests { /// Test encoding with zero-length payload #[tokio::test] - async fn test_encode_with_zero_length_payload() { + async fn encode_with_zero_length_payload() { // Create a CStatusResponse packet with empty payload let packet = CStatusResponse::new(String::new()); @@ -570,7 +573,7 @@ mod tests { /// Test encoding with maximum length payload #[tokio::test] - async fn test_encode_with_maximum_string_length() { + async fn encode_with_maximum_string_length() { // Maximum allowed string length is 32767 bytes let max_string_length = 32767; let payload_str = "A".repeat(max_string_length); @@ -613,7 +616,7 @@ mod tests { /// Test encoding a packet that exceeds `MAX_PACKET_SIZE` as usize #[tokio::test] #[should_panic(expected = "TooLong")] - async fn test_encode_packet_exceeding_maximum_size() { + async fn encode_packet_exceeding_maximum_size() { // Create a custom packet with data exceeding MAX_PACKET_SIZE as usize let data_size = MAX_PACKET_SIZE as usize + 1; // Exceed by 1 byte let packet = MaxSizePacket::new(data_size); @@ -625,7 +628,7 @@ mod tests { /// Test encoding with a small payload that should not be compressed #[tokio::test] - async fn test_encode_small_payload_no_compression() { + async fn encode_small_payload_no_compression() { // Create a CStatusResponse packet with small payload let packet = CStatusResponse::new(String::from("Hi")); diff --git a/pumpkin-protocol/src/java/server/config/resource_pack_response.rs b/pumpkin-protocol/src/java/server/config/resource_pack_response.rs index d9f846b41..6ac230562 100644 --- a/pumpkin-protocol/src/java/server/config/resource_pack_response.rs +++ b/pumpkin-protocol/src/java/server/config/resource_pack_response.rs @@ -32,7 +32,7 @@ pub struct SConfigResourcePack { impl SConfigResourcePack { #[must_use] - pub fn response_result(&self) -> ResourcePackResponseResult { + pub const fn response_result(&self) -> ResourcePackResponseResult { match self.result.0 { 0 => ResourcePackResponseResult::DownloadSuccess, 1 => ResourcePackResponseResult::Declined, diff --git a/pumpkin-protocol/src/java/server/play/click_container.rs b/pumpkin-protocol/src/java/server/play/click_container.rs index 9ba3f5f59..5ad059c24 100644 --- a/pumpkin-protocol/src/java/server/play/click_container.rs +++ b/pumpkin-protocol/src/java/server/play/click_container.rs @@ -83,7 +83,7 @@ impl<'de> Deserialize<'de> for SClickSlot { } } -#[derive(Deserialize, Debug, PartialEq, Clone)] +#[derive(Deserialize, Debug, PartialEq, Eq, Clone)] pub enum SlotActionType { /// Performs a normal slot click. This can pick up or place items in the slot, possibly merging the cursor stack into the slot, or swapping the slot stack with the cursor stack if they can't be merged. Pickup, diff --git a/pumpkin-protocol/src/lib.rs b/pumpkin-protocol/src/lib.rs index 63226daa4..b56f7085c 100644 --- a/pumpkin-protocol/src/lib.rs +++ b/pumpkin-protocol/src/lib.rs @@ -50,7 +50,7 @@ pub type CompressionThreshold = usize; /// increase CPU usage. pub type CompressionLevel = u32; -#[derive(Debug, PartialEq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum ConnectionState { HandShake, Status, @@ -143,7 +143,7 @@ impl<'de, T: Deserialize<'de>> Visitor<'de> for IdOrVisitor { } } -#[derive(PartialEq, Clone)] +#[derive(PartialEq, Eq, Clone)] pub enum IdOr { Id(u16), Value(T), @@ -155,6 +155,7 @@ impl<'de, T: Deserialize<'de>> Deserialize<'de> for IdOr { } } +#[expect(clippy::trait_duplication_in_bounds)] impl Serialize for IdOr { fn serialize(&self, serializer: S) -> Result { match self { @@ -189,7 +190,7 @@ pub struct StreamDecryptor { } impl StreamDecryptor { - pub fn new(cipher: Aes128Cfb8Dec, stream: R) -> Self { + pub const fn new(cipher: Aes128Cfb8Dec, stream: R) -> Self { Self { cipher, read: stream, @@ -447,7 +448,7 @@ pub enum PositionFlag { } impl PositionFlag { - fn get_mask(&self) -> i32 { + const fn get_mask(&self) -> i32 { match self { Self::X => 1 << 0, Self::Y => 1 << 1, @@ -490,7 +491,7 @@ pub struct Link<'a> { impl<'a> Link<'a> { #[must_use] - pub fn new(label: Label, url: &'a String) -> Self { + pub const fn new(label: Label, url: &'a String) -> Self { Self { is_built_in: match label { Label::BuiltIn(_) => true, @@ -534,7 +535,7 @@ mod test { }; #[test] - fn test_serde_id_or_id() { + fn serde_id_or_id() { let mut buf = Vec::new(); let id = IdOr::::Id(0); @@ -547,7 +548,7 @@ mod test { } #[test] - fn test_serde_id_or_value() { + fn serde_id_or_value() { let mut buf = Vec::new(); let event = SoundEvent { sound_name: ResourceLocation::vanilla("test"), diff --git a/pumpkin-protocol/src/query.rs b/pumpkin-protocol/src/query.rs index df4bbf02e..4dcebd4b0 100644 --- a/pumpkin-protocol/src/query.rs +++ b/pumpkin-protocol/src/query.rs @@ -53,7 +53,7 @@ impl RawQueryPacket { } } -#[derive(PartialEq, Debug)] +#[derive(PartialEq, Eq, Debug)] pub struct SHandshake { pub session_id: i32, } @@ -66,7 +66,7 @@ impl SHandshake { } } -#[derive(PartialEq, Debug)] +#[derive(PartialEq, Eq, Debug)] pub struct SStatusRequest { pub session_id: i32, pub challenge_token: i32, @@ -242,7 +242,7 @@ impl CFullStatus { // All test bytes/packets are from protocol documentation #[tokio::test] -async fn test_handshake_request() { +async fn handshake_request() { let bytes = vec![0xFE, 0xFD, 0x09, 0x00, 0x00, 0x00, 0x01]; let mut raw_packet = RawQueryPacket::decode(bytes).await.unwrap(); let packet = SHandshake::decode(&mut raw_packet).await.unwrap(); @@ -254,7 +254,7 @@ async fn test_handshake_request() { } #[tokio::test] -async fn test_handshake_response() { +async fn handshake_response() { let bytes = vec![ 0x09, 0x00, 0x00, 0x00, 0x01, 0x39, 0x35, 0x31, 0x33, 0x33, 0x30, 0x37, 0x00, ]; @@ -268,7 +268,7 @@ async fn test_handshake_response() { } #[tokio::test] -async fn test_basic_stat_request() { +async fn basic_stat_request() { let bytes = vec![ 0xFE, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x91, 0x29, 0x5B, ]; @@ -285,7 +285,7 @@ async fn test_basic_stat_request() { } #[tokio::test] -async fn test_basic_stat_response() { +async fn basic_stat_response() { let bytes = vec![ 0x00, 0x00, 0x00, 0x00, 0x01, 0x41, 0x20, 0x4D, 0x69, 0x6E, 0x65, 0x63, 0x72, 0x61, 0x66, 0x74, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x00, 0x53, 0x4D, 0x50, 0x00, 0x77, 0x6F, @@ -307,7 +307,7 @@ async fn test_basic_stat_response() { } #[tokio::test] -async fn test_full_stat_request() { +async fn full_stat_request() { let bytes = vec![ 0xFE, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x91, 0x29, 0x5B, 0x00, 0x00, 0x00, 0x00, ]; @@ -323,7 +323,7 @@ async fn test_full_stat_request() { assert_eq!(packet, actual_packet); } #[tokio::test] -async fn test_full_stat_response() { +async fn full_stat_response() { let bytes = vec![ 0x00, 0x00, 0x00, 0x00, 0x01, 0x73, 0x70, 0x6C, 0x69, 0x74, 0x6E, 0x75, 0x6D, 0x00, 0x80, 0x00, 0x68, 0x6F, 0x73, 0x74, 0x6E, 0x61, 0x6D, 0x65, 0x00, 0x41, 0x20, 0x4D, 0x69, 0x6E, diff --git a/pumpkin-protocol/src/ser/deserializer.rs b/pumpkin-protocol/src/ser/deserializer.rs index 413c665f4..d79afd1ab 100644 --- a/pumpkin-protocol/src/ser/deserializer.rs +++ b/pumpkin-protocol/src/ser/deserializer.rs @@ -17,7 +17,7 @@ impl de::Error for ReadingError { } impl Deserializer { - pub fn new(read: R) -> Self { + pub const fn new(read: R) -> Self { Self { inner: read } } } diff --git a/pumpkin-protocol/src/ser/mod.rs b/pumpkin-protocol/src/ser/mod.rs index 2c4d73c89..fe7c09f7d 100644 --- a/pumpkin-protocol/src/ser/mod.rs +++ b/pumpkin-protocol/src/ser/mod.rs @@ -421,7 +421,7 @@ mod test { }; #[test] - fn test_i32_reserialize() { + fn i32_reserialize() { #[derive(serde::Serialize, serde::Deserialize, PartialEq, Eq, Debug)] struct Foo { bar: i32, @@ -439,7 +439,7 @@ mod test { } #[test] - fn test_varint_reserialize() { + fn varint_reserialize() { #[derive(serde::Serialize, serde::Deserialize, PartialEq, Eq, Debug)] struct Foo { bar: VarInt, @@ -457,7 +457,7 @@ mod test { } #[test] - fn test_char_reserialize() { + fn char_reserialize() { #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] struct CharStruct { c: char, @@ -502,7 +502,7 @@ mod test { } #[test] - fn test_i128_reserialize() { + fn i128_reserialize() { #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] struct I128Struct { val: i128, @@ -536,7 +536,7 @@ mod test { } #[test] - fn test_u128_reserialize() { + fn u128_reserialize() { #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] struct U128Struct { val: u128, @@ -557,7 +557,7 @@ mod test { } #[test] - fn test_unit_reserialize() { + fn unit_reserialize() { #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] struct UnitStruct; #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] @@ -600,7 +600,7 @@ mod test { } #[test] - fn test_enum_reserialize() { + fn enum_reserialize() { #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] enum MyEnum { A, @@ -643,7 +643,7 @@ mod test { let mut expected_bytes_c = vec![0x02]; expected_bytes_c.extend_from_slice(&456i32.to_be_bytes()); expected_bytes_c.push(0x05); // VarInt for string length 5 - expected_bytes_c.extend_from_slice("hello".as_bytes()); + expected_bytes_c.extend_from_slice(b"hello"); assert_eq!(bytes_c, expected_bytes_c); let de_cursor_c = Cursor::new(bytes_c); let deserialized_c: MyEnum = @@ -652,7 +652,7 @@ mod test { } #[test] - fn test_tuple_struct_reserialize() { + fn tuple_struct_reserialize() { #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] struct MyTupleStruct(i32, String); @@ -664,7 +664,7 @@ mod test { let mut expected_bytes = Vec::new(); expected_bytes.extend_from_slice(&789i32.to_be_bytes()); expected_bytes.push(0x05); // VarInt for string length 5 - expected_bytes.extend_from_slice("world".as_bytes()); + expected_bytes.extend_from_slice(b"world"); assert_eq!(bytes, expected_bytes); let de_cursor = Cursor::new(bytes); @@ -674,7 +674,7 @@ mod test { } #[test] - fn test_map_reserialize() { + fn map_reserialize() { use std::collections::HashMap; #[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] diff --git a/pumpkin-protocol/src/ser/serializer.rs b/pumpkin-protocol/src/ser/serializer.rs index f611a4da2..ec357010c 100644 --- a/pumpkin-protocol/src/ser/serializer.rs +++ b/pumpkin-protocol/src/ser/serializer.rs @@ -12,7 +12,7 @@ pub struct Serializer { } impl Serializer { - pub fn new(w: W) -> Self { + pub const fn new(w: W) -> Self { Self { write: w } } } diff --git a/pumpkin-protocol/src/serial/deserializer.rs b/pumpkin-protocol/src/serial/deserializer.rs index 62edeee5a..f72ee0348 100644 --- a/pumpkin-protocol/src/serial/deserializer.rs +++ b/pumpkin-protocol/src/serial/deserializer.rs @@ -139,6 +139,7 @@ impl PacketRead for String { } impl PacketRead for Vec { + #[expect(clippy::read_zero_byte_vec)] fn read(reader: &mut R) -> Result { #[expect(clippy::uninit_vec)] { diff --git a/pumpkin-util/src/difficulty.rs b/pumpkin-util/src/difficulty.rs index c019c244a..97482c573 100644 --- a/pumpkin-util/src/difficulty.rs +++ b/pumpkin-util/src/difficulty.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; pub struct ParseDifficultyError; -#[derive(Serialize, Deserialize, FromPrimitive, ToPrimitive, PartialEq, Clone, Copy, Debug)] +#[derive(Serialize, Deserialize, FromPrimitive, ToPrimitive, PartialEq, Eq, Clone, Copy, Debug)] pub enum Difficulty { Peaceful = 0, Easy = 1, diff --git a/pumpkin-util/src/gamemode.rs b/pumpkin-util/src/gamemode.rs index bd6ba91b1..10da5c6fc 100644 --- a/pumpkin-util/src/gamemode.rs +++ b/pumpkin-util/src/gamemode.rs @@ -4,7 +4,7 @@ use std::str::FromStr; #[derive(Debug, PartialEq, Eq)] pub struct ParseGameModeError; -#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum GameMode { Survival = 0, Creative = 1, @@ -14,7 +14,7 @@ pub enum GameMode { impl GameMode { #[must_use] - pub fn to_str(&self) -> &'static str { + pub const fn to_str(&self) -> &'static str { match self { Self::Survival => "Survival", Self::Creative => "Creative", diff --git a/pumpkin-util/src/lib.rs b/pumpkin-util/src/lib.rs index c2447f283..8f980904e 100644 --- a/pumpkin-util/src/lib.rs +++ b/pumpkin-util/src/lib.rs @@ -25,7 +25,7 @@ pub mod world_seed; pub mod jwt; -#[derive(Deserialize, Clone, Copy, Debug, PartialEq)] +#[derive(Deserialize, Clone, Copy, Debug, PartialEq, Eq)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub enum HeightMap { WorldSurfaceWg, @@ -99,7 +99,7 @@ pub enum BlockDirection { impl BlockDirection { #[must_use] - pub fn get_axis(&self) -> Axis { + pub const fn get_axis(&self) -> Axis { match self { Self::Up | Self::Down => Axis::Y, Self::North | Self::South => Axis::Z, @@ -116,7 +116,7 @@ pub struct MutableSplitSlice<'a, T> { } impl<'a, T> MutableSplitSlice<'a, T> { - pub fn extract_ith(base: &'a mut [T], index: usize) -> (&'a mut T, Self) { + pub const fn extract_ith(base: &'a mut [T], index: usize) -> (&'a mut T, Self) { let (start, end_inclusive) = base.split_at_mut(index); let (value, end) = end_inclusive .split_first_mut() @@ -126,12 +126,12 @@ impl<'a, T> MutableSplitSlice<'a, T> { } #[must_use] - pub fn len(&self) -> usize { + pub const fn len(&self) -> usize { self.start.len() + self.end.len() + 1 } #[must_use] - pub fn is_empty(&self) -> bool { + pub const fn is_empty(&self) -> bool { false } } @@ -191,7 +191,7 @@ pub enum Hand { impl Hand { #[must_use] - pub fn all() -> [Self; 2] { + pub const fn all() -> [Self; 2] { [Self::Right, Self::Left] } } diff --git a/pumpkin-util/src/loot_table.rs b/pumpkin-util/src/loot_table.rs index c12432146..6464464eb 100644 --- a/pumpkin-util/src/loot_table.rs +++ b/pumpkin-util/src/loot_table.rs @@ -20,7 +20,7 @@ pub struct LootPool { pub functions: Option<&'static [LootFunction]>, } -#[derive(Clone, PartialEq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] pub struct ItemEntry { pub name: &'static str, } @@ -42,7 +42,7 @@ pub enum LootPoolEntryTypes { Group, } -#[derive(Clone, PartialEq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] pub enum LootCondition { Inverted, AnyOf, @@ -124,7 +124,7 @@ pub struct LootPoolEntry { pub functions: Option<&'static [LootFunction]>, } -#[derive(Clone, Copy, PartialEq, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum LootTableType { Empty, Entity, @@ -169,7 +169,7 @@ impl ToTokens for UniformLootNumberProvider { impl UniformLootNumberProvider { pub fn get(&self, random: &mut impl RandomImpl) -> f32 { - random.next_f32() * (self.max - self.min) + self.min + random.next_f32().mul_add(self.max - self.min, self.min) } } diff --git a/pumpkin-util/src/math/block_box.rs b/pumpkin-util/src/math/block_box.rs index 5cf80d2e4..5cf7efdbb 100644 --- a/pumpkin-util/src/math/block_box.rs +++ b/pumpkin-util/src/math/block_box.rs @@ -14,7 +14,14 @@ pub struct BlockBox { impl BlockBox { #[must_use] - pub fn new(min_x: i32, min_y: i32, min_z: i32, max_x: i32, max_y: i32, max_z: i32) -> Self { + pub const fn new( + min_x: i32, + min_y: i32, + min_z: i32, + max_x: i32, + max_y: i32, + max_z: i32, + ) -> Self { Self { min: Vector3 { x: min_x, @@ -47,7 +54,7 @@ impl BlockBox { #[expect(clippy::too_many_arguments)] #[must_use] - pub fn rotated( + pub const fn rotated( x: i32, y: i32, z: i32, @@ -97,7 +104,7 @@ impl BlockBox { } #[must_use] - pub fn from_pos(pos: BlockPos) -> Self { + pub const fn from_pos(pos: BlockPos) -> Self { Self { min: pos.0, max: pos.0, @@ -105,14 +112,14 @@ impl BlockBox { } #[must_use] - pub fn expand(&self, x: i32, y: i32, z: i32) -> Self { + pub const fn expand(&self, x: i32, y: i32, z: i32) -> Self { Self { min: Vector3::new(self.min.x - x, self.min.y - y, self.min.z - z), max: Vector3::new(self.max.x + x, self.max.y + y, self.max.z + z), } } - pub fn move_pos(&mut self, dx: i32, dy: i32, dz: i32) { + pub const fn move_pos(&mut self, dx: i32, dy: i32, dz: i32) { self.min.x += dx; self.min.y += dy; self.min.z += dz; @@ -122,12 +129,12 @@ impl BlockBox { } #[must_use] - pub fn contains_pos(&self, pos: &Vector3) -> bool { + pub const fn contains_pos(&self, pos: &Vector3) -> bool { self.contains(pos.x, pos.y, pos.z) } #[must_use] - pub fn contains(&self, x: i32, y: i32, z: i32) -> bool { + pub const fn contains(&self, x: i32, y: i32, z: i32) -> bool { x >= self.min.x && x <= self.max.x && y >= self.min.y @@ -137,7 +144,7 @@ impl BlockBox { } #[must_use] - pub fn intersects(&self, other: &Self) -> bool { + pub const fn intersects(&self, other: &Self) -> bool { self.min.x < other.max.x && self.max.x > other.min.x && self.min.y < other.max.y @@ -145,7 +152,7 @@ impl BlockBox { } #[must_use] - pub fn intersects_xz(&self, other: &Self) -> bool { + pub const fn intersects_xz(&self, other: &Self) -> bool { self.max.x >= other.min.x && self.min.x <= other.max.x && self.max.z >= other.min.z @@ -153,12 +160,12 @@ impl BlockBox { } #[must_use] - pub fn intersects_raw_xz(&self, min_x: i32, min_z: i32, max_x: i32, max_z: i32) -> bool { + pub const fn intersects_raw_xz(&self, min_x: i32, min_z: i32, max_x: i32, max_z: i32) -> bool { self.max.x >= min_x && self.min.x <= max_x && self.max.z >= min_z && self.min.z <= max_z } #[must_use] - pub fn get_block_count_y(&self) -> i32 { + pub const fn get_block_count_y(&self) -> i32 { self.max.y - self.min.y + 1 } diff --git a/pumpkin-util/src/math/boundingbox.rs b/pumpkin-util/src/math/boundingbox.rs index a68eae85a..8d505615d 100644 --- a/pumpkin-util/src/math/boundingbox.rs +++ b/pumpkin-util/src/math/boundingbox.rs @@ -24,7 +24,7 @@ impl BoundingPlane { } // Projecting a 3D box into 2D - pub fn from_box(bounding_box: &BoundingBox, excluded: Axis) -> Self { + pub const fn from_box(bounding_box: &BoundingBox, excluded: Axis) -> Self { let [axis1, axis2] = Axis::excluding(excluded); Self { @@ -83,12 +83,12 @@ impl BoundingBox { } #[must_use] - pub fn new(min: Vector3, max: Vector3) -> Self { + pub const fn new(min: Vector3, max: Vector3) -> Self { Self { min, max } } #[must_use] - pub fn new_array(min: [f64; 3], max: [f64; 3]) -> Self { + pub const fn new_array(min: [f64; 3], max: [f64; 3]) -> Self { Self { min: Vector3::new(min[0], min[1], min[2]), max: Vector3::new(max[0], max[1], max[2]), @@ -113,7 +113,7 @@ impl BoundingBox { } #[must_use] - pub fn get_side(&self, max: bool) -> Vector3 { + pub const fn get_side(&self, max: bool) -> Vector3 { if max { self.max } else { self.min } } @@ -251,7 +251,7 @@ pub struct EntityDimensions { impl EntityDimensions { #[must_use] - pub fn new(width: f32, height: f32, eye_height: f32) -> Self { + pub const fn new(width: f32, height: f32, eye_height: f32) -> Self { Self { width, height, diff --git a/pumpkin-util/src/math/experience.rs b/pumpkin-util/src/math/experience.rs index 9e4124a4e..cca3e5eba 100644 --- a/pumpkin-util/src/math/experience.rs +++ b/pumpkin-util/src/math/experience.rs @@ -21,7 +21,7 @@ impl ToTokens for Experience { /// Get the number of points in a level. #[must_use] -pub fn points_in_level(level: i32) -> i32 { +pub const fn points_in_level(level: i32) -> i32 { match level { 0..=15 => 2 * level + 7, 16..=30 => 5 * level - 38, @@ -34,8 +34,12 @@ pub fn points_in_level(level: i32) -> i32 { pub fn points_to_level(level: i32) -> i32 { match level { 0..=16 => level * level + 6 * level, - 17..=31 => (2.5 * f64::from(level * level) - (40.5 * f64::from(level)) + 360.0) as i32, - _ => ((4.5 * f64::from(level * level)) - (162.5 * f64::from(level)) + 2220.0) as i32, + 17..=31 => { + (2.5f64.mul_add(f64::from(level * level), -(40.5 * f64::from(level))) + 360.0) as i32 + } + _ => { + (4.5f64.mul_add(f64::from(level * level), -(162.5 * f64::from(level))) + 2220.0) as i32 + } } } diff --git a/pumpkin-util/src/math/float_provider.rs b/pumpkin-util/src/math/float_provider.rs index c02a85df5..086e1d364 100644 --- a/pumpkin-util/src/math/float_provider.rs +++ b/pumpkin-util/src/math/float_provider.rs @@ -68,7 +68,7 @@ impl ToTokens for FloatProvider { impl FloatProvider { #[must_use] - pub fn get_min(&self) -> f32 { + pub const fn get_min(&self) -> f32 { match self { Self::Object(inv_provider) => match inv_provider { NormalFloatProvider::Constant(constant) => constant.get_min(), @@ -93,7 +93,7 @@ impl FloatProvider { } #[must_use] - pub fn get_max(&self) -> f32 { + pub const fn get_max(&self) -> f32 { match self { Self::Object(inv_provider) => match inv_provider { NormalFloatProvider::Constant(constant) => constant.get_max(), @@ -122,21 +122,21 @@ impl ToTokens for ConstantFloatProvider { impl ConstantFloatProvider { #[must_use] - pub fn new(value: f32) -> Self { + pub const fn new(value: f32) -> Self { Self { value } } #[must_use] - pub fn get_min(&self) -> f32 { + pub const fn get_min(&self) -> f32 { self.value } - pub fn get(&self, _random: &mut impl RandomImpl) -> f32 { + pub const fn get(&self, _random: &mut impl RandomImpl) -> f32 { self.value } #[must_use] - pub fn get_max(&self) -> f32 { + pub const fn get_max(&self) -> f32 { self.value } } @@ -159,7 +159,7 @@ impl ToTokens for UniformFloatProvider { impl UniformFloatProvider { #[must_use] - pub fn new(min_inclusive: f32, max_exclusive: f32) -> Self { + pub const fn new(min_inclusive: f32, max_exclusive: f32) -> Self { Self { min_inclusive, max_exclusive, @@ -167,18 +167,18 @@ impl UniformFloatProvider { } #[must_use] - pub fn get_min(&self) -> f32 { + pub const fn get_min(&self) -> f32 { self.min_inclusive } pub fn get(&self, random: &mut impl RandomImpl) -> f32 { // Use the random range in [min_inclusive, max_exclusive) let range = self.max_exclusive - self.min_inclusive; - self.min_inclusive + random.next_f32() * range + random.next_f32().mul_add(range, self.min_inclusive) } #[must_use] - pub fn get_max(&self) -> f32 { + pub const fn get_max(&self) -> f32 { self.max_exclusive } } @@ -210,7 +210,7 @@ impl ToTokens for ClampedNormalFloatProvider { impl ClampedNormalFloatProvider { #[must_use] - pub fn new(mean: f32, deviation: f32, min: f32, max: f32) -> Self { + pub const fn new(mean: f32, deviation: f32, min: f32, max: f32) -> Self { Self { mean, deviation, @@ -220,21 +220,21 @@ impl ClampedNormalFloatProvider { } #[must_use] - pub fn get_min(&self) -> f32 { + pub const fn get_min(&self) -> f32 { self.min } pub fn get(&self, random: &mut impl RandomImpl) -> f32 { // Generate normal distribution value let gaussian = random.next_gaussian() as f32; - let value = self.mean + gaussian * self.deviation; + let value = gaussian.mul_add(self.deviation, self.mean); // Clamp to min/max range value.clamp(self.min, self.max) } #[must_use] - pub fn get_max(&self) -> f32 { + pub const fn get_max(&self) -> f32 { self.max } } @@ -263,12 +263,12 @@ impl ToTokens for TrapezoidFloatProvider { impl TrapezoidFloatProvider { #[must_use] - pub fn new(min: f32, max: f32, plateau: f32) -> Self { + pub const fn new(min: f32, max: f32, plateau: f32) -> Self { Self { min, max, plateau } } #[must_use] - pub fn get_min(&self) -> f32 { + pub const fn get_min(&self) -> f32 { self.min } @@ -280,25 +280,26 @@ impl TrapezoidFloatProvider { let random_value = random.next_f32(); - if random_value < 0.5 - self.plateau * 0.5 { + if random_value < self.plateau.mul_add(-0.5, 0.5) { // Left ramp: quadratic distribution biased toward plateau - let scaled = random_value / (0.5 - self.plateau * 0.5); + let scaled = random_value / self.plateau.mul_add(-0.5, 0.5); let sqrt_scaled = scaled.sqrt(); self.min + ramp_range * sqrt_scaled - } else if random_value > 0.5 + self.plateau * 0.5 { + } else if random_value > self.plateau.mul_add(0.5, 0.5) { // Right ramp: quadratic distribution biased toward plateau - let scaled = (random_value - (0.5 + self.plateau * 0.5)) / (0.5 - self.plateau * 0.5); + let scaled = + (random_value - self.plateau.mul_add(0.5, 0.5)) / self.plateau.mul_add(-0.5, 0.5); let sqrt_scaled = (1.0 - scaled).sqrt(); self.max - ramp_range * sqrt_scaled } else { // Plateau: uniform distribution - let plateau_pos = (random_value - (0.5 - self.plateau * 0.5)) / self.plateau; + let plateau_pos = (random_value - self.plateau.mul_add(-0.5, 0.5)) / self.plateau; self.min + ramp_range + plateau_pos * plateau_range } } #[must_use] - pub fn get_max(&self) -> f32 { + pub const fn get_max(&self) -> f32 { self.max } } @@ -309,7 +310,7 @@ mod tests { use crate::random::{RandomGenerator, get_seed}; #[test] - fn test_constant_float_provider() { + fn constant_float_provider() { let mut random = RandomGenerator::Xoroshiro( crate::random::xoroshiro128::Xoroshiro::from_seed(get_seed()), ); @@ -322,7 +323,7 @@ mod tests { } #[test] - fn test_uniform_float_provider() { + fn uniform_float_provider() { let mut random = RandomGenerator::Xoroshiro( crate::random::xoroshiro128::Xoroshiro::from_seed(get_seed()), ); @@ -342,7 +343,7 @@ mod tests { } #[test] - fn test_clamped_normal_float_provider() { + fn clamped_normal_float_provider() { let mut random = RandomGenerator::Xoroshiro( crate::random::xoroshiro128::Xoroshiro::from_seed(get_seed()), ); @@ -362,7 +363,7 @@ mod tests { } #[test] - fn test_trapezoid_float_provider() { + fn trapezoid_float_provider() { let mut random = RandomGenerator::Xoroshiro( crate::random::xoroshiro128::Xoroshiro::from_seed(get_seed()), ); @@ -382,7 +383,7 @@ mod tests { } #[test] - fn test_float_provider_enum_constant() { + fn float_provider_enum_constant() { let mut random = RandomGenerator::Xoroshiro( crate::random::xoroshiro128::Xoroshiro::from_seed(get_seed()), ); @@ -394,7 +395,7 @@ mod tests { } #[test] - fn test_float_provider_enum_object() { + fn float_provider_enum_object() { let mut random = RandomGenerator::Xoroshiro( crate::random::xoroshiro128::Xoroshiro::from_seed(get_seed()), ); diff --git a/pumpkin-util/src/math/int_provider.rs b/pumpkin-util/src/math/int_provider.rs index 76ae95a30..96f350bc8 100644 --- a/pumpkin-util/src/math/int_provider.rs +++ b/pumpkin-util/src/math/int_provider.rs @@ -142,21 +142,21 @@ impl ToTokens for ConstantIntProvider { impl ConstantIntProvider { #[must_use] - pub fn new(value: i32) -> Self { + pub const fn new(value: i32) -> Self { Self { value } } #[must_use] - pub fn get_min(&self) -> i32 { + pub const fn get_min(&self) -> i32 { self.value } - pub fn get(&self, _random: &mut impl RandomImpl) -> i32 { + pub const fn get(&self, _random: &mut impl RandomImpl) -> i32 { self.value } #[must_use] - pub fn get_max(&self) -> i32 { + pub const fn get_max(&self) -> i32 { self.value } } @@ -179,7 +179,7 @@ impl ToTokens for BiasedToBottomIntProvider { impl BiasedToBottomIntProvider { #[must_use] - pub fn new(min_inclusive: i32, max_inclusive: i32) -> Self { + pub const fn new(min_inclusive: i32, max_inclusive: i32) -> Self { Self { min_inclusive, max_inclusive, @@ -187,7 +187,7 @@ impl BiasedToBottomIntProvider { } #[must_use] - pub fn get_min(&self) -> i32 { + pub const fn get_min(&self) -> i32 { self.min_inclusive } @@ -200,7 +200,7 @@ impl BiasedToBottomIntProvider { } #[must_use] - pub fn get_max(&self) -> i32 { + pub const fn get_max(&self) -> i32 { self.max_inclusive } } @@ -281,7 +281,7 @@ impl ToTokens for ClampedNormalIntProvider { impl ClampedNormalIntProvider { #[must_use] - pub fn new(mean: f32, deviation: f32, min_inclusive: i32, max_inclusive: i32) -> Self { + pub const fn new(mean: f32, deviation: f32, min_inclusive: i32, max_inclusive: i32) -> Self { Self { mean, deviation, @@ -291,19 +291,19 @@ impl ClampedNormalIntProvider { } #[must_use] - pub fn get_min(&self) -> i32 { + pub const fn get_min(&self) -> i32 { self.min_inclusive } pub fn get(&self, random: &mut impl RandomImpl) -> i32 { // Generate normal distribution value and clamp to range let gaussian = random.next_gaussian() as f32; - let value = (self.mean + gaussian * self.deviation).round() as i32; + let value = gaussian.mul_add(self.deviation, self.mean).round() as i32; value.clamp(self.min_inclusive, self.max_inclusive) } #[must_use] - pub fn get_max(&self) -> i32 { + pub const fn get_max(&self) -> i32 { self.max_inclusive } } @@ -340,7 +340,7 @@ impl ToTokens for WeightedListIntProvider { impl WeightedListIntProvider { #[must_use] - pub fn new(distribution: Vec) -> Self { + pub const fn new(distribution: Vec) -> Self { Self { distribution } } @@ -410,7 +410,7 @@ impl ToTokens for UniformIntProvider { impl UniformIntProvider { #[must_use] - pub fn new(min_inclusive: i32, max_inclusive: i32) -> Self { + pub const fn new(min_inclusive: i32, max_inclusive: i32) -> Self { Self { min_inclusive, max_inclusive, @@ -418,7 +418,7 @@ impl UniformIntProvider { } #[must_use] - pub fn get_min(&self) -> i32 { + pub const fn get_min(&self) -> i32 { self.min_inclusive } @@ -427,7 +427,7 @@ impl UniformIntProvider { } #[must_use] - pub fn get_max(&self) -> i32 { + pub const fn get_max(&self) -> i32 { self.max_inclusive } } @@ -438,7 +438,7 @@ mod tests { use crate::random::{RandomGenerator, get_seed}; #[test] - fn test_constant_int_provider() { + fn constant_int_provider() { let mut random = RandomGenerator::Xoroshiro( crate::random::xoroshiro128::Xoroshiro::from_seed(get_seed()), ); @@ -451,7 +451,7 @@ mod tests { } #[test] - fn test_uniform_int_provider() { + fn uniform_int_provider() { let mut random = RandomGenerator::Xoroshiro( crate::random::xoroshiro128::Xoroshiro::from_seed(get_seed()), ); @@ -471,7 +471,7 @@ mod tests { } #[test] - fn test_biased_to_bottom_int_provider() { + fn biased_to_bottom_int_provider() { let mut random = RandomGenerator::Xoroshiro( crate::random::xoroshiro128::Xoroshiro::from_seed(get_seed()), ); @@ -491,7 +491,7 @@ mod tests { } #[test] - fn test_clamped_normal_int_provider() { + fn clamped_normal_int_provider() { let mut random = RandomGenerator::Xoroshiro( crate::random::xoroshiro128::Xoroshiro::from_seed(get_seed()), ); @@ -511,7 +511,7 @@ mod tests { } #[test] - fn test_clamped_int_provider() { + fn clamped_int_provider() { let mut random = RandomGenerator::Xoroshiro( crate::random::xoroshiro128::Xoroshiro::from_seed(get_seed()), ); @@ -533,7 +533,7 @@ mod tests { } #[test] - fn test_weighted_list_int_provider() { + fn weighted_list_int_provider() { let mut random = RandomGenerator::Xoroshiro( crate::random::xoroshiro128::Xoroshiro::from_seed(get_seed()), ); @@ -569,7 +569,7 @@ mod tests { } #[test] - fn test_int_provider_enum_constant() { + fn int_provider_enum_constant() { let mut random = RandomGenerator::Xoroshiro( crate::random::xoroshiro128::Xoroshiro::from_seed(get_seed()), ); @@ -581,7 +581,7 @@ mod tests { } #[test] - fn test_int_provider_enum_object() { + fn int_provider_enum_object() { let mut random = RandomGenerator::Xoroshiro( crate::random::xoroshiro128::Xoroshiro::from_seed(get_seed()), ); diff --git a/pumpkin-util/src/math/mod.rs b/pumpkin-util/src/math/mod.rs index 938b9cf48..adb0c8375 100644 --- a/pumpkin-util/src/math/mod.rs +++ b/pumpkin-util/src/math/mod.rs @@ -210,7 +210,7 @@ pub fn java_string_hash(string: &str) -> i32 { #[test] #[expect(clippy::unicode_not_nfc)] -fn test_java_hash() { +fn java_hash() { let values = [ ("", 0, 1), ("1", 49, 80), diff --git a/pumpkin-util/src/math/position.rs b/pumpkin-util/src/math/position.rs index 1c57c1b52..9e27333de 100644 --- a/pumpkin-util/src/math/position.rs +++ b/pumpkin-util/src/math/position.rs @@ -21,7 +21,7 @@ pub struct BlockPosIterator { impl BlockPosIterator { #[must_use] - pub fn new( + pub const fn new( start_x: i32, start_y: i32, start_z: i32, @@ -89,7 +89,7 @@ pub struct OutwardIterator { impl OutwardIterator { #[must_use] - pub fn new(center: BlockPos, range_x: i32, range_y: i32, range_z: i32) -> Self { + pub const fn new(center: BlockPos, range_x: i32, range_y: i32, range_z: i32) -> Self { let max_manhattan_distance = range_x + range_y + range_z; Self { center_x: center.0.x, @@ -210,7 +210,7 @@ impl BlockPos { /// /// An `OutwardIterator` that yields `BlockPos` instances in the described outward order. #[must_use] - pub fn iterate_outwards( + pub const fn iterate_outwards( center: Self, range_x: i32, range_y: i32, @@ -220,7 +220,7 @@ impl BlockPos { } #[must_use] - pub fn iterate_block_pos( + pub const fn iterate_block_pos( start_x: i32, start_y: i32, start_z: i32, @@ -232,12 +232,12 @@ impl BlockPos { } #[must_use] - pub fn chunk_and_chunk_relative_position(&self) -> (Vector2, Vector3) { + pub const fn chunk_and_chunk_relative_position(&self) -> (Vector2, Vector3) { (self.chunk_position(), self.chunk_relative_position()) } #[must_use] - pub fn chunk_position(&self) -> Vector2 { + pub const fn chunk_position(&self) -> Vector2 { let z_chunk = self.0.z.div_euclid(16); let x_chunk = self.0.x.div_euclid(16); Vector2 { @@ -247,7 +247,7 @@ impl BlockPos { } #[must_use] - pub fn chunk_relative_position(&self) -> Vector3 { + pub const fn chunk_relative_position(&self) -> Vector3 { let z_chunk = self.0.z.rem_euclid(16); let x_chunk = self.0.x.rem_euclid(16); Vector3 { @@ -271,7 +271,7 @@ impl BlockPos { } } #[must_use] - pub fn from_i64(encoded_position: i64) -> Self { + pub const fn from_i64(encoded_position: i64) -> Self { Self(Vector3 { x: (encoded_position >> 38) as i32, y: (encoded_position << 52 >> 52) as i32, @@ -330,12 +330,12 @@ impl BlockPos { } #[must_use] - pub fn add(&self, x: i32, y: i32, z: i32) -> Self { + pub const fn add(&self, x: i32, y: i32, z: i32) -> Self { Self::new(self.0.x + x, self.0.y + y, self.0.z + z) } #[must_use] - pub fn offset_dir(&self, offset: Vector3, direction: i32) -> Self { + pub const fn offset_dir(&self, offset: Vector3, direction: i32) -> Self { Self(Vector3::new( self.0.x + offset.x * direction, self.0.y + offset.y * direction, @@ -384,7 +384,7 @@ impl BlockPos { } #[must_use] - pub fn manhattan_distance(&self, other: Self) -> i32 { + pub const fn manhattan_distance(&self, other: Self) -> i32 { let x = (other.0.x - self.0.x).abs(); let y = (other.0.y - self.0.y).abs(); let z = (other.0.z - self.0.z).abs(); @@ -452,7 +452,7 @@ pub const fn get_local_cord(cord: i32) -> i32 { } #[must_use] -pub fn pack_local_chunk_section(block_pos: &BlockPos) -> i16 { +pub const fn pack_local_chunk_section(block_pos: &BlockPos) -> i16 { let x = get_local_cord(block_pos.0.x); let z = get_local_cord(block_pos.0.z); let y = get_local_cord(block_pos.0.y); diff --git a/pumpkin-util/src/math/vector3.rs b/pumpkin-util/src/math/vector3.rs index 7cdad6166..16bc51601 100644 --- a/pumpkin-util/src/math/vector3.rs +++ b/pumpkin-util/src/math/vector3.rs @@ -25,17 +25,17 @@ pub enum Axis { impl Axis { #[must_use] - pub fn all() -> [Self; 3] { + pub const fn all() -> [Self; 3] { [Self::Y, Self::X, Self::Z] } #[must_use] - pub fn horizontal() -> [Self; 2] { + pub const fn horizontal() -> [Self; 2] { [Self::X, Self::Z] } #[must_use] - pub fn excluding(axis: Self) -> [Self; 2] { + pub const fn excluding(axis: Self) -> [Self; 2] { match axis { Self::X => [Self::Y, Self::Z], @@ -47,7 +47,7 @@ impl Axis { } impl Vector3 { - pub fn get_axis(&self, a: Axis) -> T { + pub const fn get_axis(&self, a: Axis) -> T { match a { Axis::X => self.x, Axis::Y => self.y, @@ -55,7 +55,7 @@ impl Vector3 { } } - pub fn set_axis(&mut self, a: Axis, value: T) { + pub const fn set_axis(&mut self, a: Axis, value: T) { match a { Axis::X => self.x = value, Axis::Y => self.y = value, diff --git a/pumpkin-util/src/noise/mod.rs b/pumpkin-util/src/noise/mod.rs index a3893c779..81ed37f5d 100644 --- a/pumpkin-util/src/noise/mod.rs +++ b/pumpkin-util/src/noise/mod.rs @@ -94,6 +94,6 @@ impl Gradient { #[inline] #[must_use] pub fn dot(&self, x: f64, y: f64, z: f64) -> f64 { - self.x * x + self.y * y + self.z * z + self.z.mul_add(z, self.x.mul_add(x, self.y * y)) } } diff --git a/pumpkin-util/src/noise/perlin.rs b/pumpkin-util/src/noise/perlin.rs index a2217de3b..542833890 100644 --- a/pumpkin-util/src/noise/perlin.rs +++ b/pumpkin-util/src/noise/perlin.rs @@ -87,6 +87,7 @@ impl PerlinNoiseSampler { } #[inline] + #[expect(clippy::suboptimal_flops)] fn perlin_fade(value: f64) -> f64 { value * value * value * (value * (value * 6.0 - 15.0) + 10.0) } @@ -151,7 +152,7 @@ pub struct OctavePerlinNoiseSampler { impl OctavePerlinNoiseSampler { #[must_use] - pub fn max_value(&self) -> f64 { + pub const fn max_value(&self) -> f64 { self.max_value } @@ -171,6 +172,7 @@ impl OctavePerlinNoiseSampler { #[inline] #[must_use] + #[expect(clippy::suboptimal_flops)] pub fn maintain_precision(value: f64) -> f64 { value - (value / 3.355_443_2E7 + 0.5).floor() * 3.355_443_2E7 } @@ -315,7 +317,7 @@ mod tests { }; #[test] - fn test_create_xoroshiro() { + fn create_xoroshiro() { let mut rand = Xoroshiro::from_seed(513513513); assert_eq!(rand.next_i32(), 404174895); @@ -344,7 +346,7 @@ mod tests { } #[test] - fn test_create_legacy() { + fn create_legacy() { let mut rand = LegacyRand::from_seed(513513513); assert_eq!(rand.next_i32(), -1302745855); @@ -368,7 +370,7 @@ mod tests { } #[test] - fn test_create() { + fn create() { let mut rand = Xoroshiro::from_seed(111); assert_eq!(rand.next_i32(), -1467508761); @@ -398,7 +400,7 @@ mod tests { #[test] #[expect(clippy::too_many_lines)] - fn test_no_y() { + fn no_y() { let mut rand = Xoroshiro::from_seed(111); assert_eq!(rand.next_i32(), -1467508761); let sampler = PerlinNoiseSampler::new(&mut rand); @@ -568,7 +570,7 @@ mod tests { } #[test] - fn test_no_y_chunk() { + fn no_y_chunk() { let expected_data: Vec<(i32, i32, i32, f64)> = read_data_from_file!("../../assets/perlin2_7_4.json"); @@ -597,7 +599,7 @@ mod tests { #[test] #[expect(clippy::too_many_lines)] - fn test_no_fade() { + fn no_fade() { let mut rand = Xoroshiro::from_seed(111); assert_eq!(rand.next_i32(), -1467508761); let sampler = PerlinNoiseSampler::new(&mut rand); @@ -811,7 +813,7 @@ mod tests { } #[test] - fn test_no_fade_chunk() { + fn no_fade_chunk() { let expected_data: Vec<(i32, i32, i32, f64)> = read_data_from_file!("../../assets/perlin_7_4.json"); @@ -845,7 +847,7 @@ mod tests { } #[test] - fn test_map() { + fn map() { let expected_data: Vec = read_data_from_file!("../../assets/perlin_map.json"); let mut expected_iter = expected_data.iter(); diff --git a/pumpkin-util/src/noise/simplex.rs b/pumpkin-util/src/noise/simplex.rs index e08312950..478d4cc13 100644 --- a/pumpkin-util/src/noise/simplex.rs +++ b/pumpkin-util/src/noise/simplex.rs @@ -69,6 +69,7 @@ impl SimplexNoiseSampler { i32::from(self.permutation[(input & 0xFF) as usize]) } + #[expect(clippy::suboptimal_flops)] fn grad(gradient_index: usize, x: f64, y: f64, z: f64, distance: f64) -> f64 { let d = distance - x * x - y * y - z * z; if d < 0f64 { @@ -81,6 +82,7 @@ impl SimplexNoiseSampler { #[must_use] #[expect(clippy::many_single_char_names)] + #[expect(clippy::suboptimal_flops)] pub fn sample_2d(&self, x: f64, y: f64) -> f64 { let d = (x + y) * Self::SKEW_FACTOR_2D; let i = (x + d).floor() as i32; @@ -259,6 +261,7 @@ impl OctaveSimplexNoiseSampler { #[must_use] #[expect(clippy::many_single_char_names)] + #[expect(clippy::suboptimal_flops)] pub fn sample(&self, x: f64, y: f64, use_origin: bool) -> f64 { let mut d = 0.0; let mut e = self.lacunarity; @@ -288,7 +291,7 @@ mod octave_simplex_noise_sampler_test { }; #[test] - fn test_new() { + fn new() { let mut rand = Xoroshiro::from_seed(450); assert_eq!(rand.next_i32(), 1394613419); let sampler = OctaveSimplexNoiseSampler::new(&mut rand, &[-1, 1, 0]); @@ -316,7 +319,7 @@ mod octave_simplex_noise_sampler_test { } #[test] - fn test_sample() { + fn sample() { let mut rand = Xoroshiro::from_seed(450); assert_eq!(rand.next_i32(), 1394613419); let sampler = OctaveSimplexNoiseSampler::new(&mut rand, &[-1, 1, 0]); @@ -424,7 +427,7 @@ mod simplex_noise_sampler_test { }; #[test] - fn test_create() { + fn create() { let mut rand = Xoroshiro::from_seed(111); assert_eq!(rand.next_i32(), -1467508761); let sampler = SimplexNoiseSampler::new(&mut rand); @@ -453,7 +456,7 @@ mod simplex_noise_sampler_test { #[test] #[expect(clippy::too_many_lines)] - fn test_sample_2d() { + fn sample_2d() { let data1 = [ ((-50000, 0), -0.013008608535752102), ((-49999, 1000), 0.0), @@ -565,7 +568,7 @@ mod simplex_noise_sampler_test { #[test] #[expect(clippy::too_many_lines)] - fn test_sample_3d() { + fn sample_3d() { let data = [ ( ( diff --git a/pumpkin-util/src/permission.rs b/pumpkin-util/src/permission.rs index a4193f73e..422415484 100644 --- a/pumpkin-util/src/permission.rs +++ b/pumpkin-util/src/permission.rs @@ -118,7 +118,7 @@ impl PermissionAttachment { /// Get all directly set permissions #[must_use] - pub fn get_permissions(&self) -> &HashMap { + pub const fn get_permissions(&self) -> &HashMap { &self.permissions } } diff --git a/pumpkin-util/src/random/gaussian.rs b/pumpkin-util/src/random/gaussian.rs index c1d22f1e8..fc333f8eb 100644 --- a/pumpkin-util/src/random/gaussian.rs +++ b/pumpkin-util/src/random/gaussian.rs @@ -11,8 +11,8 @@ pub trait GaussianGenerator: RandomImpl { gaussian } else { loop { - let d = self.next_f64() * 2.0 - 1.0; - let e = self.next_f64() * 2.0 - 1.0; + let d = self.next_f64().mul_add(2.0, -1.0); + let e = self.next_f64().mul_add(2.0, -1.0); let f = d * d + e * e; if f < 1f64 && f != 0f64 { diff --git a/pumpkin-util/src/random/legacy_rand.rs b/pumpkin-util/src/random/legacy_rand.rs index d4e662d79..12e2201a0 100644 --- a/pumpkin-util/src/random/legacy_rand.rs +++ b/pumpkin-util/src/random/legacy_rand.rs @@ -14,21 +14,21 @@ impl LegacyRand { population_seed_fn!(); #[must_use] - pub fn from_seed(seed: u64) -> Self { + pub const fn from_seed(seed: u64) -> Self { Self { seed: (seed ^ 0x0005_DEEC_E66D) & 0xFFFF_FFFF_FFFF, internal_next_gaussian: None, } } - fn next_random(&mut self) -> i64 { + const fn next_random(&mut self) -> i64 { let l = self.seed as i64; let m = l.wrapping_mul(0x0005_DEEC_E66D).wrapping_add(11) & 0xFFFFFFFFFFFF; self.seed = m as u64; m } - fn next(&mut self, bits: u64) -> i32 { + const fn next(&mut self, bits: u64) -> i32 { (self.next_random() >> (48 - bits)) as i32 } } @@ -102,7 +102,7 @@ pub struct LegacySplitter { } impl LegacySplitter { - fn new(seed: u64) -> Self { + const fn new(seed: u64) -> Self { Self { seed } } } @@ -132,7 +132,7 @@ mod test { use super::LegacyRand; #[test] - fn test_next_i32() { + fn next_i32() { let mut rand = LegacyRand::from_seed(0); let values = [ @@ -154,7 +154,7 @@ mod test { } #[test] - fn test_next_bounded_i32() { + fn next_bounded_i32() { let mut rand = LegacyRand::from_seed(0); let values = [0, 13, 4, 2, 5, 8, 11, 6, 9, 14]; @@ -176,7 +176,7 @@ mod test { } #[test] - fn test_next_inbetween_i32() { + fn next_inbetween_i32() { let mut rand = LegacyRand::from_seed(0); let values = [1, 5, 2, 12, 12, 6, 12, 10, 4, 3]; @@ -187,7 +187,7 @@ mod test { } #[test] - fn test_next_inbetween_exclusive_i32() { + fn next_inbetween_exclusive_i32() { let mut rand = LegacyRand::from_seed(0); let values = [1, 7, 9, 6, 7, 3, 3, 7, 3, 1]; @@ -198,7 +198,7 @@ mod test { } #[test] - fn test_next_f64() { + fn next_f64() { let mut rand = LegacyRand::from_seed(0); let values = [ @@ -220,7 +220,7 @@ mod test { } #[test] - fn test_next_f32() { + fn next_f32() { let mut rand = LegacyRand::from_seed(0); let values: [f32; 10] = [ @@ -234,7 +234,7 @@ mod test { } #[test] - fn test_next_i64() { + fn next_i64() { let mut rand = LegacyRand::from_seed(0); let values: [i64; 10] = [ @@ -256,7 +256,7 @@ mod test { } #[test] - fn test_next_bool() { + fn next_bool() { let mut rand = LegacyRand::from_seed(0); let values = [ @@ -269,7 +269,7 @@ mod test { } #[test] - fn test_next_gaussian() { + fn next_gaussian() { let mut rand = LegacyRand::from_seed(0); let values = [ @@ -291,7 +291,7 @@ mod test { } #[test] - fn test_next_triangular() { + fn next_triangular() { let mut rand = LegacyRand::from_seed(0); let values = [ @@ -313,7 +313,7 @@ mod test { } #[test] - fn test_split() { + fn split() { let mut original_rand = LegacyRand::from_seed(0); assert_eq!(original_rand.next_i64(), -4962768465676381896i64); diff --git a/pumpkin-util/src/random/mod.rs b/pumpkin-util/src/random/mod.rs index 13e7f1452..02165d86d 100644 --- a/pumpkin-util/src/random/mod.rs +++ b/pumpkin-util/src/random/mod.rs @@ -63,7 +63,7 @@ macro_rules! population_seed_fn { // TODO: Write unit test for this #[inline] #[must_use] -pub fn get_decorator_seed(population_seed: u64, index: u64, step: u64) -> u64 { +pub const fn get_decorator_seed(population_seed: u64, index: u64, step: u64) -> u64 { population_seed .wrapping_add(index) .wrapping_add(10_000u64.wrapping_mul(step)) @@ -117,6 +117,7 @@ pub trait RandomImpl { fn next_gaussian(&mut self) -> f64; + #[allow(clippy::suboptimal_flops)] fn next_triangular(&mut self, mode: f64, deviation: f64) -> f64 { mode + deviation * (self.next_f64() - self.next_f64()) } diff --git a/pumpkin-util/src/random/xoroshiro128.rs b/pumpkin-util/src/random/xoroshiro128.rs index 5e353cc09..d8bd4d359 100644 --- a/pumpkin-util/src/random/xoroshiro128.rs +++ b/pumpkin-util/src/random/xoroshiro128.rs @@ -15,14 +15,14 @@ impl Xoroshiro { population_seed_fn!(); #[must_use] - pub fn from_seed(seed: u64) -> Self { + pub const fn from_seed(seed: u64) -> Self { let (lo, hi) = Self::mix_u64(seed); let lo = mix_stafford_13(lo); let hi = mix_stafford_13(hi); Self::new(lo, hi) } - fn new(lo: u64, hi: u64) -> Self { + const fn new(lo: u64, hi: u64) -> Self { let (lo, hi) = if (lo | hi) == 0 { (0x9E3779B97F4A7C15, 0x6A09E667F3BCC909) } else { @@ -35,23 +35,23 @@ impl Xoroshiro { } } - fn mix_u64(seed: u64) -> (u64, u64) { + const fn mix_u64(seed: u64) -> (u64, u64) { let l = seed ^ 0x6A09E667F3BCC909; let m = l.wrapping_add(0x9E3779B97F4A7C15); (l, m) } #[must_use] - pub fn from_seed_unmixed(seed: u64) -> Self { + pub const fn from_seed_unmixed(seed: u64) -> Self { let (lo, hi) = Self::mix_u64(seed); Self::new(lo, hi) } - fn next(&mut self, bits: u64) -> u64 { + const fn next(&mut self, bits: u64) -> u64 { self.next_random() >> (64 - bits) } - fn next_random(&mut self) -> u64 { + const fn next_random(&mut self) -> u64 { let l = self.lo; let m = self.hi; let n = (l.wrapping_add(m)).rotate_left(17).wrapping_add(l); @@ -72,7 +72,7 @@ impl GaussianGenerator for Xoroshiro { } } -fn mix_stafford_13(z: u64) -> u64 { +const fn mix_stafford_13(z: u64) -> u64 { let z = (z ^ (z >> 30)).wrapping_mul(0xBF58476D1CE4E5B9); let z = (z ^ (z >> 27)).wrapping_mul(0x94D049BB133111EB); z ^ (z >> 31) @@ -168,7 +168,7 @@ mod tests { // Values checked against results from the equivalent Java source #[test] - fn test_mix_stafford_13() { + fn mix_stafford_13_test() { let values: [(u64, i64); 31] = [ (0, 0), (1, 6238072747940578789), @@ -208,7 +208,7 @@ mod tests { } #[test] - fn test_next_i32() { + fn next_i32() { let values = [ -160476802, 781697906, @@ -229,7 +229,7 @@ mod tests { } #[test] - fn test_next_bounded_i32() { + fn next_bounded_i32() { let mut xoroshiro = Xoroshiro::from_seed(0); let values = [9, 1, 1, 3, 8, 9, 0, 3, 6, 3]; @@ -247,7 +247,7 @@ mod tests { } #[test] - fn test_next_between_i32() { + fn next_between_i32() { let mut xoroshiro = Xoroshiro::from_seed(0); let values = [99, 59, 57, 65, 94, 100, 54, 66, 83, 68]; @@ -257,7 +257,7 @@ mod tests { } #[test] - fn test_next_inbetween_exclusive() { + fn next_inbetween_exclusive() { let mut xoroshiro = Xoroshiro::from_seed(0); let values = [98, 59, 57, 65, 94, 99, 53, 66, 82, 68]; @@ -267,7 +267,7 @@ mod tests { } #[test] - fn test_next_f64() { + fn next_f64() { let mut xoroshiro = Xoroshiro::from_seed(0); let values: [f64; 10] = [ @@ -288,7 +288,7 @@ mod tests { } #[test] - fn test_next_f32() { + fn next_f32() { let mut xoroshiro = Xoroshiro::from_seed(0); let values: [f32; 10] = [ @@ -309,7 +309,7 @@ mod tests { } #[test] - fn test_next_i64() { + fn next_i64() { let mut xoroshiro = Xoroshiro::from_seed(0); let values: [i64; 10] = [ @@ -330,7 +330,7 @@ mod tests { } #[test] - fn test_next_bool() { + fn next_bool() { let mut xoroshiro = Xoroshiro::from_seed(0); let values: [bool; 10] = [ @@ -342,7 +342,7 @@ mod tests { } #[test] - fn test_next_gaussian() { + fn next_gaussian() { let mut xoroshiro = Xoroshiro::from_seed(0); let values: [f64; 10] = [ @@ -363,7 +363,7 @@ mod tests { } #[test] - fn test_next_triangular() { + fn next_triangular() { let mut xoroshiro = Xoroshiro::from_seed(0); let values: [f64; 10] = [ @@ -384,7 +384,7 @@ mod tests { } #[test] - fn test_split() { + fn split() { let mut xoroshiro = Xoroshiro::from_seed(0); let mut new_generator = xoroshiro.split(); @@ -408,7 +408,7 @@ mod tests { } #[test] - fn test_intersection() { + fn intersection() { let mut xoroshiro = Xoroshiro::new(0, 0); assert_eq!(xoroshiro.next_i64(), 6807859099481836695); } diff --git a/pumpkin-util/src/text/color.rs b/pumpkin-util/src/text/color.rs index bd6a87188..0382acc8a 100644 --- a/pumpkin-util/src/text/color.rs +++ b/pumpkin-util/src/text/color.rs @@ -103,7 +103,7 @@ pub struct RGBColor { impl RGBColor { #[must_use] - pub fn new(red: u8, green: u8, blue: u8) -> Self { + pub const fn new(red: u8, green: u8, blue: u8) -> Self { Self { red, green, blue } } } @@ -127,7 +127,7 @@ pub struct ARGBColor { impl ARGBColor { #[must_use] - pub fn new(alpha: u8, red: u8, green: u8, blue: u8) -> Self { + pub const fn new(alpha: u8, red: u8, green: u8, blue: u8) -> Self { Self { alpha, red, @@ -167,7 +167,7 @@ pub enum NamedColor { impl NamedColor { #[must_use] - pub fn to_rgb(&self) -> RGBColor { + pub const fn to_rgb(&self) -> RGBColor { match self { Self::Black => RGBColor::new(0, 0, 0), Self::DarkBlue => RGBColor::new(0, 0, 170), diff --git a/pumpkin-util/src/text/mod.rs b/pumpkin-util/src/text/mod.rs index e30c402b3..7996e7d4e 100644 --- a/pumpkin-util/src/text/mod.rs +++ b/pumpkin-util/src/text/mod.rs @@ -402,12 +402,12 @@ impl TextComponent { // LERP logic color::RGBColor::new( - (f32::from(start.red) + (f32::from(end.red) - f32::from(start.red)) * local_t) - as u8, - (f32::from(start.green) + (f32::from(end.green) - f32::from(start.green)) * local_t) - as u8, - (f32::from(start.blue) + (f32::from(end.blue) - f32::from(start.blue)) * local_t) + (f32::from(end.red) - f32::from(start.red)).mul_add(local_t, f32::from(start.red)) as u8, + (f32::from(end.green) - f32::from(start.green)) + .mul_add(local_t, f32::from(start.green)) as u8, + (f32::from(end.blue) - f32::from(start.blue)) + .mul_add(local_t, f32::from(start.blue)) as u8, ) }) } @@ -563,7 +563,7 @@ mod test { use crate::text::{TextComponent, color::NamedColor}; #[test] - fn test_serialize_text_component() { + fn serialize_text_component() { let msg_comp = TextComponent::translate( "multiplayer.player.joined", [TextComponent::text("NAME".to_string())], diff --git a/pumpkin-util/src/text/style.rs b/pumpkin-util/src/text/style.rs index 869befd00..5165a3f3c 100644 --- a/pumpkin-util/src/text/style.rs +++ b/pumpkin-util/src/text/style.rs @@ -47,48 +47,48 @@ pub struct Style { impl Style { #[must_use] - pub fn color(mut self, color: Color) -> Self { + pub const fn color(mut self, color: Color) -> Self { self.color = Some(color); self } #[must_use] - pub fn color_named(mut self, color: color::NamedColor) -> Self { + pub const fn color_named(mut self, color: color::NamedColor) -> Self { self.color = Some(Color::Named(color)); self } /// Makes the text bold #[must_use] - pub fn bold(mut self) -> Self { + pub const fn bold(mut self) -> Self { self.bold = Some(true); self } /// Makes the text italic #[must_use] - pub fn italic(mut self) -> Self { + pub const fn italic(mut self) -> Self { self.italic = Some(true); self } /// Makes the text underlined #[must_use] - pub fn underlined(mut self) -> Self { + pub const fn underlined(mut self) -> Self { self.underlined = Some(true); self } /// Makes the text strikethrough #[must_use] - pub fn strikethrough(mut self) -> Self { + pub const fn strikethrough(mut self) -> Self { self.strikethrough = Some(true); self } /// Makes the text obfuscated #[must_use] - pub fn obfuscated(mut self) -> Self { + pub const fn obfuscated(mut self) -> Self { self.obfuscated = Some(true); self } @@ -124,7 +124,7 @@ impl Style { /// Overrides the shadow properties of text. #[must_use] - pub fn shadow_color(mut self, color: ARGBColor) -> Self { + pub const fn shadow_color(mut self, color: ARGBColor) -> Self { self.shadow_color = Some(color); self } diff --git a/pumpkin-util/src/translation.rs b/pumpkin-util/src/translation.rs index 7d526997f..05d88533b 100644 --- a/pumpkin-util/src/translation.rs +++ b/pumpkin-util/src/translation.rs @@ -28,11 +28,11 @@ pub struct SubstitutionRange { } impl SubstitutionRange { #[must_use] - pub fn len(&self) -> usize { + pub const fn len(&self) -> usize { (self.end - self.start) + 1 } #[must_use] - pub fn is_empty(&self) -> bool { + pub const fn is_empty(&self) -> bool { self.start == self.end } } diff --git a/pumpkin-util/src/version.rs b/pumpkin-util/src/version.rs index 71397b181..e4682f547 100644 --- a/pumpkin-util/src/version.rs +++ b/pumpkin-util/src/version.rs @@ -74,7 +74,7 @@ pub enum MinecraftVersion { impl MinecraftVersion { #[must_use] - pub fn protocol_version(&self) -> i32 { + pub const fn protocol_version(&self) -> i32 { match self { Self::V_1_7_2 => 4, Self::V_1_7_6 => 5, @@ -130,7 +130,7 @@ impl MinecraftVersion { } #[must_use] - pub fn from_protocol(protocol: u32) -> Self { + pub const fn from_protocol(protocol: u32) -> Self { match protocol { 4 => Self::V_1_7_2, 5 => Self::V_1_7_6, diff --git a/pumpkin-world/Cargo.toml b/pumpkin-world/Cargo.toml index b5136fec1..5f763c64e 100644 --- a/pumpkin-world/Cargo.toml +++ b/pumpkin-world/Cargo.toml @@ -85,3 +85,6 @@ harness = false [features] tokio_taskdump = [] + +# [lints] +# workspace = true diff --git a/pumpkin-world/benches/chunk.rs b/pumpkin-world/benches/chunk.rs index f33fef1cf..b85f6f12e 100644 --- a/pumpkin-world/benches/chunk.rs +++ b/pumpkin-world/benches/chunk.rs @@ -24,7 +24,7 @@ fn bench_terrain_gen(c: &mut Criterion) { surface_config, &terrain_cache, default_block, - ) + ); }); }); @@ -36,7 +36,7 @@ fn bench_terrain_gen(c: &mut Criterion) { surface_config, &terrain_cache, default_block, - ) + ); }); }); @@ -48,7 +48,7 @@ fn bench_terrain_gen(c: &mut Criterion) { surface_config, &terrain_cache, default_block, - ) + ); }); }); } diff --git a/pumpkin-world/benches/chunk_io.rs b/pumpkin-world/benches/chunk_io.rs index 46e8f2893..4fa548bb2 100644 --- a/pumpkin-world/benches/chunk_io.rs +++ b/pumpkin-world/benches/chunk_io.rs @@ -14,7 +14,7 @@ // use tokio::{runtime::Runtime, sync::RwLock}; // // #[ignore] -// async fn test_reads(level: &Arc, positions: Vec>) { +// async fn reads(level: &Arc, positions: Vec>) { // // let level = level.clone(); // // let mut receiver = level.receive_chunks(positions); // // @@ -25,7 +25,7 @@ // } // // /* -// async fn test_reads_parallel(level: &Arc, positions: Vec>, threads: usize) { +// async fn reads_parallel(level: &Arc, positions: Vec>, threads: usize) { // let mut tasks = JoinSet::new(); // // // we write non overlapping chunks to avoid conflicts or level cache @@ -43,12 +43,12 @@ // } // */ // -// async fn test_writes(level: &Arc, chunks: Vec<(Vector2, Arc>)>) { +// async fn writes(level: &Arc, chunks: Vec<(Vector2, Arc>)>) { // level.write_chunks(chunks).await; // } // // /* -// async fn test_writes_parallel( +// async fn writes_parallel( // level: &Arc, // chunks: Vec<(Vector2, Arc>)>, // threads: usize, diff --git a/pumpkin-world/benches/noise_router.rs b/pumpkin-world/benches/noise_router.rs index ad50437e3..15f22731d 100644 --- a/pumpkin-world/benches/noise_router.rs +++ b/pumpkin-world/benches/noise_router.rs @@ -26,7 +26,7 @@ fn bench_noise_router_creation(c: &mut Criterion) { black_box(&builder_options), ); black_box(router); - }) + }); }); } diff --git a/pumpkin-world/src/biome/mod.rs b/pumpkin-world/src/biome/mod.rs index 5a093ae68..377269bf2 100644 --- a/pumpkin-world/src/biome/mod.rs +++ b/pumpkin-world/src/biome/mod.rs @@ -49,6 +49,7 @@ impl BiomeSupplier for MultiNoiseBiomeSupplier { } } +#[must_use] pub fn hash_seed(seed: u64) -> i64 { let mut hasher = Sha256::new(); hasher.update(seed.to_le_bytes()); @@ -76,7 +77,7 @@ mod test { use super::{BiomeSupplier, MultiNoiseBiomeSupplier, hash_seed}; #[test] - fn test_biome_desert() { + fn biome_desert() { let seed = 13579; let random_config = GlobalRandomConfig::new(seed, false); let noise_router = @@ -85,11 +86,16 @@ mod test { let mut sampler = MultiNoiseSampler::generate(&noise_router.multi_noise, &multi_noise_config); let biome = MultiNoiseBiomeSupplier::biome(-24, 1, 8, &mut sampler, Dimension::OVERWORLD); - assert_eq!(biome, &Biome::DESERT) + assert_eq!(biome, &Biome::DESERT); } #[test] - fn test_wide_area_surface() { + fn wide_area_surface() { + use crate::biome::hash_seed; + use crate::generation::noise::router::multi_noise_sampler::{ + MultiNoiseSampler, MultiNoiseSamplerBuilderOptions, + }; + use crate::generation::{biome_coords, positions::chunk_pos}; #[derive(Deserialize)] struct BiomeData { x: i32, @@ -110,12 +116,11 @@ mod test { //let _terrain_cache = TerrainCache::from_random(&random_config); let default_block = surface_settings.default_block.get_state(); - for data in expected_data.into_iter() { + for data in expected_data { let chunk_x = data.x; let chunk_z = data.z; // Calculate biome mixer seed - use crate::biome::hash_seed; let biome_mixer_seed = hash_seed(random_config.seed); let mut chunk = ProtoChunk::new( @@ -127,10 +132,6 @@ mod test { ); // Create MultiNoiseSampler for populate_biomes - use crate::generation::noise::router::multi_noise_sampler::{ - MultiNoiseSampler, MultiNoiseSamplerBuilderOptions, - }; - use crate::generation::{biome_coords, positions::chunk_pos}; let start_x = chunk_pos::start_block_x(chunk_x); let start_z = chunk_pos::start_block_z(chunk_z); @@ -166,7 +167,7 @@ mod test { } #[test] - fn test_hash_seed() { + fn hash_seed_test() { let hashed_seed = hash_seed(0); assert_eq!(8794265229978523055, hashed_seed); @@ -175,10 +176,11 @@ mod test { } #[test] - fn test_proper_network_bits_per_entry() { + fn proper_network_bits_per_entry() { let id_to_test = 1 << BIOME_NETWORK_MAX_BITS; - if Biome::from_id(id_to_test).is_some() { - panic!("We need to update our constants!"); - } + assert!( + Biome::from_id(id_to_test).is_none(), + "We need to update our constants!" + ); } } diff --git a/pumpkin-world/src/biome/multi_noise.rs b/pumpkin-world/src/biome/multi_noise.rs index c80417898..c6ab95862 100644 --- a/pumpkin-world/src/biome/multi_noise.rs +++ b/pumpkin-world/src/biome/multi_noise.rs @@ -1,5 +1,6 @@ use serde::{Deserialize, Serialize}; +#[must_use] pub fn to_long(float: f32) -> i64 { (float * 10000f32) as i64 } @@ -15,7 +16,8 @@ pub struct NoiseValuePoint { } impl NoiseValuePoint { - pub fn convert_to_list(&self) -> [i64; 7] { + #[must_use] + pub const fn convert_to_list(&self) -> [i64; 7] { [ self.temperature, self.humidity, @@ -48,7 +50,12 @@ mod test { }; #[test] - fn test_sample_value() { + fn sample_value() { + use crate::biome::hash_seed; + use crate::generation::noise::router::multi_noise_sampler::{ + MultiNoiseSampler, MultiNoiseSamplerBuilderOptions, + }; + use crate::generation::{biome_coords, positions::chunk_pos}; type PosToPoint = (i32, i32, i32, i64, i64, i64, i64, i64, i64); let expected_data: Vec = read_data_from_file!("../../assets/multi_noise_sample_no_blend_no_beard_0_0_0.json"); @@ -66,7 +73,6 @@ mod test { .unwrap(); let _terrain_cache = TerrainCache::from_random(&random_config); // Calculate biome mixer seed - use crate::biome::hash_seed; let biome_mixer_seed = hash_seed(random_config.seed); let _chunk = ProtoChunk::new( @@ -77,12 +83,6 @@ mod test { biome_mixer_seed, ); - // Create MultiNoiseSampler for testing - use crate::generation::noise::router::multi_noise_sampler::{ - MultiNoiseSampler, MultiNoiseSamplerBuilderOptions, - }; - use crate::generation::{biome_coords, positions::chunk_pos}; - let start_x = chunk_pos::start_block_x(chunk_x); let start_z = chunk_pos::start_block_z(chunk_z); let horizontal_biome_end = biome_coords::from_block(16); @@ -94,7 +94,7 @@ mod test { let mut multi_noise_sampler = MultiNoiseSampler::generate(&noise_router.multi_noise, &multi_noise_config); - for (x, y, z, tem, hum, con, ero, dep, wei) in expected_data.into_iter() { + for (x, y, z, tem, hum, con, ero, dep, wei) in expected_data { let point = multi_noise_sampler.sample(x, y, z); assert_eq!(point.temperature, tem); assert_eq!(point.humidity, hum); @@ -106,7 +106,7 @@ mod test { } #[test] - fn test_sample_multinoise_biome() { + fn sample_multinoise_biome() { let expected_data: Vec<(i32, i32, i32, u8)> = read_data_from_file!("../../assets/multi_noise_biome_source_test.json"); diff --git a/pumpkin-world/src/block/entities/barrel.rs b/pumpkin-world/src/block/entities/barrel.rs index 107a7babc..af56ce9ea 100644 --- a/pumpkin-world/src/block/entities/barrel.rs +++ b/pumpkin-world/src/block/entities/barrel.rs @@ -80,7 +80,7 @@ impl BlockEntity for BarrelBlockEntity { ) -> Pin + Send + 'a>> { Box::pin(async move { self.viewers - .update_viewer_count::(self, world, &self.position) + .update_viewer_count::(self, world, &self.position) .await; }) } @@ -126,6 +126,7 @@ impl BarrelBlockEntity { pub const INVENTORY_SIZE: usize = 27; pub const ID: &'static str = "minecraft:barrel"; + #[must_use] pub fn new(position: BlockPos) -> Self { Self { position, @@ -181,7 +182,7 @@ impl Inventory for BarrelBlockEntity { fn is_empty(&self) -> InventoryFuture<'_, bool> { Box::pin(async move { - for slot in self.items.iter() { + for slot in &self.items { if !slot.lock().await.is_empty() { return false; } @@ -238,7 +239,7 @@ impl Inventory for BarrelBlockEntity { impl Clearable for BarrelBlockEntity { fn clear(&self) -> Pin + Send + '_>> { Box::pin(async move { - for slot in self.items.iter() { + for slot in &self.items { *slot.lock().await = ItemStack::EMPTY.clone(); } }) diff --git a/pumpkin-world/src/block/entities/bed.rs b/pumpkin-world/src/block/entities/bed.rs index 54ed74de2..646a0dba5 100644 --- a/pumpkin-world/src/block/entities/bed.rs +++ b/pumpkin-world/src/block/entities/bed.rs @@ -39,7 +39,8 @@ impl BlockEntity for BedBlockEntity { impl BedBlockEntity { pub const ID: &'static str = "minecraft:bed"; - pub fn new(position: BlockPos) -> Self { + #[must_use] + pub const fn new(position: BlockPos) -> Self { Self { position } } } diff --git a/pumpkin-world/src/block/entities/blasting_furnace.rs b/pumpkin-world/src/block/entities/blasting_furnace.rs index 24b98d5dc..81cc5d0a6 100644 --- a/pumpkin-world/src/block/entities/blasting_furnace.rs +++ b/pumpkin-world/src/block/entities/blasting_furnace.rs @@ -35,6 +35,7 @@ impl BlastingFurnaceBlockEntity { pub const INVENTORY_SIZE: usize = 3; pub const ID: &'static str = "minecraft:blast_furnace"; + #[must_use] pub fn new(position: BlockPos) -> Self { Self { position, diff --git a/pumpkin-world/src/block/entities/chest.rs b/pumpkin-world/src/block/entities/chest.rs index deb11c516..60ed32429 100644 --- a/pumpkin-world/src/block/entities/chest.rs +++ b/pumpkin-world/src/block/entities/chest.rs @@ -80,7 +80,7 @@ impl BlockEntity for ChestBlockEntity { ) -> Pin + Send + 'a>> { Box::pin(async move { self.viewers - .update_viewer_count::(self, world, &self.position) + .update_viewer_count::(self, world, &self.position) .await; }) } @@ -129,7 +129,7 @@ impl ViewerCountListener for ChestBlockEntity { Box::pin(async move { world .add_synced_block_event(*position, Self::LID_ANIMATION_EVENT_TYPE, new as u8) - .await + .await; }) } } @@ -138,6 +138,7 @@ impl ChestBlockEntity { pub const LID_ANIMATION_EVENT_TYPE: u8 = 1; pub const ID: &'static str = "minecraft:chest"; + #[must_use] pub fn new(position: BlockPos) -> Self { Self { position, @@ -188,7 +189,7 @@ impl Inventory for ChestBlockEntity { fn is_empty(&self) -> InventoryFuture<'_, bool> { Box::pin(async move { - for slot in self.items.iter() { + for slot in &self.items { if !slot.lock().await.is_empty() { return false; } @@ -245,7 +246,7 @@ impl Inventory for ChestBlockEntity { impl Clearable for ChestBlockEntity { fn clear(&self) -> Pin + Send + '_>> { Box::pin(async move { - for slot in self.items.iter() { + for slot in &self.items { *slot.lock().await = ItemStack::EMPTY.clone(); } }) diff --git a/pumpkin-world/src/block/entities/chiseled_bookshelf.rs b/pumpkin-world/src/block/entities/chiseled_bookshelf.rs index 5c1990f50..d7f09d9d8 100644 --- a/pumpkin-world/src/block/entities/chiseled_bookshelf.rs +++ b/pumpkin-world/src/block/entities/chiseled_bookshelf.rs @@ -88,6 +88,7 @@ impl ChiseledBookshelfBlockEntity { pub const INVENTORY_SIZE: usize = 6; pub const ID: &'static str = "minecraft:chiseled_bookshelf"; + #[must_use] pub fn new(position: BlockPos) -> Self { Self { position, @@ -136,7 +137,7 @@ impl Inventory for ChiseledBookshelfBlockEntity { fn is_empty(&self) -> InventoryFuture<'_, bool> { Box::pin(async move { - for slot in self.items.iter() { + for slot in &self.items { if !slot.lock().await.is_empty() { return false; } @@ -181,7 +182,7 @@ impl Inventory for ChiseledBookshelfBlockEntity { impl Clearable for ChiseledBookshelfBlockEntity { fn clear(&self) -> Pin + Send + '_>> { Box::pin(async move { - for slot in self.items.iter() { + for slot in &self.items { *slot.lock().await = ItemStack::EMPTY.clone(); } }) diff --git a/pumpkin-world/src/block/entities/command_block.rs b/pumpkin-world/src/block/entities/command_block.rs index 7592ed973..e12aea917 100644 --- a/pumpkin-world/src/block/entities/command_block.rs +++ b/pumpkin-world/src/block/entities/command_block.rs @@ -25,6 +25,7 @@ pub struct CommandBlockEntity { impl CommandBlockEntity { pub const ID: &'static str = "minecraft:command_block"; + #[must_use] pub fn new(position: BlockPos, track_output: bool, is_chain: bool) -> Self { Self { position, diff --git a/pumpkin-world/src/block/entities/comparator.rs b/pumpkin-world/src/block/entities/comparator.rs index f793754c0..743443e5a 100644 --- a/pumpkin-world/src/block/entities/comparator.rs +++ b/pumpkin-world/src/block/entities/comparator.rs @@ -15,7 +15,8 @@ pub struct ComparatorBlockEntity { impl ComparatorBlockEntity { pub const ID: &'static str = "minecraft:comparator"; - pub fn new(position: BlockPos) -> Self { + #[must_use] + pub const fn new(position: BlockPos) -> Self { Self { position, output_signal: AtomicU8::new(0), diff --git a/pumpkin-world/src/block/entities/dropper.rs b/pumpkin-world/src/block/entities/dropper.rs index 0a1c17804..42ae66495 100644 --- a/pumpkin-world/src/block/entities/dropper.rs +++ b/pumpkin-world/src/block/entities/dropper.rs @@ -3,7 +3,7 @@ use crate::inventory::{Clearable, Inventory, InventoryFuture, split_stack}; use crate::item::ItemStack; use pumpkin_nbt::compound::NbtCompound; use pumpkin_util::math::position::BlockPos; -use rand::{Rng, rng}; +use rand::{RngExt, rng}; use std::any::Any; use std::array::from_fn; use std::pin::Pin; @@ -69,6 +69,7 @@ impl DropperBlockEntity { pub const INVENTORY_SIZE: usize = 9; pub const ID: &'static str = "minecraft:dropper"; + #[must_use] pub fn new(position: BlockPos) -> Self { Self { position, @@ -100,7 +101,7 @@ impl Inventory for DropperBlockEntity { fn is_empty(&self) -> InventoryFuture<'_, bool> { Box::pin(async move { - for slot in self.items.iter() { + for slot in &self.items { if !slot.lock().await.is_empty() { return false; } @@ -145,7 +146,7 @@ impl Inventory for DropperBlockEntity { impl Clearable for DropperBlockEntity { fn clear(&self) -> Pin + Send + '_>> { Box::pin(async move { - for slot in self.items.iter() { + for slot in &self.items { *slot.lock().await = ItemStack::EMPTY.clone(); } }) diff --git a/pumpkin-world/src/block/entities/end_portal.rs b/pumpkin-world/src/block/entities/end_portal.rs index dff237b28..8965aad31 100644 --- a/pumpkin-world/src/block/entities/end_portal.rs +++ b/pumpkin-world/src/block/entities/end_portal.rs @@ -11,7 +11,8 @@ pub struct EndPortalBlockEntity { impl EndPortalBlockEntity { pub const ID: &'static str = "minecraft:end_portal"; - pub fn new(position: BlockPos) -> Self { + #[must_use] + pub const fn new(position: BlockPos) -> Self { Self { position } } } diff --git a/pumpkin-world/src/block/entities/ender_chest.rs b/pumpkin-world/src/block/entities/ender_chest.rs index 6c4d8dd77..57ac8bff8 100644 --- a/pumpkin-world/src/block/entities/ender_chest.rs +++ b/pumpkin-world/src/block/entities/ender_chest.rs @@ -51,7 +51,7 @@ impl BlockEntity for EnderChestBlockEntity { ) -> Pin + Send + 'a>> { Box::pin(async move { self.viewers - .update_viewer_count::(self, world, &self.position) + .update_viewer_count::(self, world, &self.position) .await; }) } @@ -92,7 +92,7 @@ impl ViewerCountListener for EnderChestBlockEntity { Box::pin(async move { world .add_synced_block_event(*position, Self::LID_ANIMATION_EVENT_TYPE, new as u8) - .await + .await; }) } } @@ -101,6 +101,7 @@ impl EnderChestBlockEntity { pub const LID_ANIMATION_EVENT_TYPE: u8 = 1; pub const ID: &'static str = "minecraft:ender_chest"; + #[must_use] pub fn new(position: BlockPos) -> Self { Self { position, @@ -108,6 +109,7 @@ impl EnderChestBlockEntity { } } + #[must_use] pub fn get_tracker(&self) -> Arc { self.viewers.clone() } diff --git a/pumpkin-world/src/block/entities/furnace.rs b/pumpkin-world/src/block/entities/furnace.rs index 35ceac5e6..19c14ae1a 100644 --- a/pumpkin-world/src/block/entities/furnace.rs +++ b/pumpkin-world/src/block/entities/furnace.rs @@ -35,6 +35,7 @@ impl FurnaceBlockEntity { pub const INVENTORY_SIZE: usize = 3; pub const ID: &'static str = "minecraft:furnace"; + #[must_use] pub fn new(position: BlockPos) -> Self { Self { position, diff --git a/pumpkin-world/src/block/entities/hopper.rs b/pumpkin-world/src/block/entities/hopper.rs index 6e7957ddf..666e4d035 100644 --- a/pumpkin-world/src/block/entities/hopper.rs +++ b/pumpkin-world/src/block/entities/hopper.rs @@ -26,6 +26,7 @@ pub struct HopperBlockEntity { pub ticked_game_time: AtomicI64, } +#[must_use] pub fn to_offset(facing: &HopperFacing) -> Vector3 { match facing { HopperFacing::Down => (0, -1, 0), @@ -129,6 +130,7 @@ impl HopperBlockEntity { pub const INVENTORY_SIZE: usize = 5; pub const ID: &'static str = "minecraft:hopper"; + #[must_use] pub fn new(position: BlockPos, facing: HopperFacing) -> Self { Self { position, @@ -254,14 +256,13 @@ impl HopperBlockEntity { } if success { if to_empty - && let Some(hopper) = to.as_any().downcast_ref::() + && let Some(hopper) = to.as_any().downcast_ref::() && hopper .cooldown_time .load(std::sync::atomic::Ordering::Relaxed) <= 8 { - if let Some(from_hopper) = from.as_any().downcast_ref::() - { + if let Some(from_hopper) = from.as_any().downcast_ref::() { if from_hopper .cooldown_time .load(std::sync::atomic::Ordering::Relaxed) @@ -299,7 +300,7 @@ impl Inventory for HopperBlockEntity { fn is_empty(&self) -> InventoryFuture<'_, bool> { Box::pin(async move { - for slot in self.items.iter() { + for slot in &self.items { if !slot.lock().await.is_empty() { return false; } @@ -344,7 +345,7 @@ impl Inventory for HopperBlockEntity { impl Clearable for HopperBlockEntity { fn clear(&self) -> Pin + Send + '_>> { Box::pin(async move { - for slot in self.items.iter() { + for slot in &self.items { *slot.lock().await = ItemStack::EMPTY.clone(); } }) diff --git a/pumpkin-world/src/block/entities/mob_spawner.rs b/pumpkin-world/src/block/entities/mob_spawner.rs index 5022f66a7..324d8c4db 100644 --- a/pumpkin-world/src/block/entities/mob_spawner.rs +++ b/pumpkin-world/src/block/entities/mob_spawner.rs @@ -35,7 +35,8 @@ impl MobSpawnerBlockEntity { pub const DEFAULT_SPAWN_COUNT: i32 = 4; pub const DEFAULT_SPAWN_RANGE: i32 = 4; - pub fn new(position: BlockPos) -> Self { + #[must_use] + pub const fn new(position: BlockPos) -> Self { Self { position, delay: AtomicI32::new(Self::DEFAULT_DELAY), @@ -61,7 +62,7 @@ impl MobSpawnerBlockEntity { }, Ordering::Relaxed, ); - world.add_synced_block_event(self.position, 1, 0).await + world.add_synced_block_event(self.position, 1, 0).await; } pub fn set_entity_type(&self, entity_type: &'static EntityType) { diff --git a/pumpkin-world/src/block/entities/mod.rs b/pumpkin-world/src/block/entities/mod.rs index 8ff466bb1..fff62ec93 100644 --- a/pumpkin-world/src/block/entities/mod.rs +++ b/pumpkin-world/src/block/entities/mod.rs @@ -78,12 +78,12 @@ pub trait BlockEntity: Send + Sync { pumpkin_data::block_properties::BLOCK_ENTITY_TYPES .iter() .position(|block_entity_name| { - *block_entity_name == self.resource_location().split(":").last().unwrap() + *block_entity_name == self.resource_location().split(':').next_back().unwrap() }) .unwrap() as u32 } - /// Obtain NBT data for sending to the client in [ChunkData](crate::chunk::ChunkData) + /// Obtain NBT data for sending to the client in [`ChunkData`](crate::chunk::ChunkData) fn chunk_data_nbt(&self) -> Option { None } @@ -117,6 +117,7 @@ pub trait BlockEntity: Send + Sync { } } +#[must_use] pub fn block_entity_from_generic(nbt: &NbtCompound) -> T { let x = nbt.get_int("x").unwrap(); let y = nbt.get_int("y").unwrap(); @@ -124,6 +125,7 @@ pub fn block_entity_from_generic(nbt: &NbtCompound) -> T { T::from_nbt(nbt, BlockPos::new(x, y, z)) } +#[must_use] pub fn block_entity_from_nbt(nbt: &NbtCompound) -> Option> { Some(match nbt.get_string("id").unwrap() { ChestBlockEntity::ID => Arc::new(block_entity_from_generic::(nbt)), @@ -161,6 +163,7 @@ pub fn block_entity_from_nbt(nbt: &NbtCompound) -> Option> }) } +#[must_use] pub fn has_block_block_entity(block: &Block) -> bool { BLOCK_ENTITY_TYPES.contains(&block.name) } diff --git a/pumpkin-world/src/block/entities/shulker_box.rs b/pumpkin-world/src/block/entities/shulker_box.rs index 38bdac5f5..d5ec4d56f 100644 --- a/pumpkin-world/src/block/entities/shulker_box.rs +++ b/pumpkin-world/src/block/entities/shulker_box.rs @@ -75,7 +75,7 @@ impl BlockEntity for ShulkerBoxBlockEntity { ) -> Pin + Send + 'a>> { Box::pin(async move { self.viewers - .update_viewer_count::(self, world, &self.position) + .update_viewer_count::(self, world, &self.position) .await; }) } @@ -141,7 +141,7 @@ impl ViewerCountListener for ShulkerBoxBlockEntity { Box::pin(async move { world .add_synced_block_event(*position, Self::OPEN_ANIMATION_EVENT_TYPE, new as u8) - .await + .await; }) } } @@ -151,6 +151,7 @@ impl ShulkerBoxBlockEntity { pub const OPEN_ANIMATION_EVENT_TYPE: u8 = 1; pub const ID: &'static str = "minecraft:shulker_box"; // TODO support multi IDs + #[must_use] pub fn new(position: BlockPos) -> Self { Self { position, @@ -182,7 +183,7 @@ impl Inventory for ShulkerBoxBlockEntity { fn is_empty(&self) -> InventoryFuture<'_, bool> { Box::pin(async move { - for slot in self.items.iter() { + for slot in &self.items { if !slot.lock().await.is_empty() { return false; } @@ -239,7 +240,7 @@ impl Inventory for ShulkerBoxBlockEntity { impl Clearable for ShulkerBoxBlockEntity { fn clear(&self) -> Pin + Send + '_>> { Box::pin(async move { - for slot in self.items.iter() { + for slot in &self.items { *slot.lock().await = ItemStack::EMPTY.clone(); } }) diff --git a/pumpkin-world/src/block/entities/sign.rs b/pumpkin-world/src/block/entities/sign.rs index 74ca88227..3e77907e2 100644 --- a/pumpkin-world/src/block/entities/sign.rs +++ b/pumpkin-world/src/block/entities/sign.rs @@ -60,23 +60,23 @@ impl From for String { impl From<&str> for DyeColor { fn from(s: &str) -> Self { match s { - "white" => DyeColor::White, - "orange" => DyeColor::Orange, - "magenta" => DyeColor::Magenta, - "light_blue" => DyeColor::LightBlue, - "yellow" => DyeColor::Yellow, - "lime" => DyeColor::Lime, - "pink" => DyeColor::Pink, - "gray" => DyeColor::Gray, - "light_gray" => DyeColor::LightGray, - "cyan" => DyeColor::Cyan, - "purple" => DyeColor::Purple, - "blue" => DyeColor::Blue, - "brown" => DyeColor::Brown, - "green" => DyeColor::Green, - "red" => DyeColor::Red, - "black" => DyeColor::Black, - _ => DyeColor::default(), + "white" => Self::White, + "orange" => Self::Orange, + "magenta" => Self::Magenta, + "light_blue" => Self::LightBlue, + "yellow" => Self::Yellow, + "lime" => Self::Lime, + "pink" => Self::Pink, + "gray" => Self::Gray, + "light_gray" => Self::LightGray, + "cyan" => Self::Cyan, + "purple" => Self::Purple, + "blue" => Self::Blue, + "brown" => Self::Brown, + "green" => Self::Green, + "red" => Self::Red, + "black" => Self::Black, + _ => Self::default(), } } } @@ -84,30 +84,30 @@ impl From<&str> for DyeColor { impl From for DyeColor { fn from(s: i8) -> Self { match s { - 0 => DyeColor::White, - 1 => DyeColor::Orange, - 2 => DyeColor::Magenta, - 3 => DyeColor::LightBlue, - 4 => DyeColor::Yellow, - 5 => DyeColor::Lime, - 6 => DyeColor::Pink, - 7 => DyeColor::Gray, - 8 => DyeColor::LightGray, - 9 => DyeColor::Cyan, - 10 => DyeColor::Purple, - 11 => DyeColor::Blue, - 12 => DyeColor::Brown, - 13 => DyeColor::Green, - 14 => DyeColor::Red, - 15 => DyeColor::Black, - _ => DyeColor::default(), + 0 => Self::White, + 1 => Self::Orange, + 2 => Self::Magenta, + 3 => Self::LightBlue, + 4 => Self::Yellow, + 5 => Self::Lime, + 6 => Self::Pink, + 7 => Self::Gray, + 8 => Self::LightGray, + 9 => Self::Cyan, + 10 => Self::Purple, + 11 => Self::Blue, + 12 => Self::Brown, + 13 => Self::Green, + 14 => Self::Red, + 15 => Self::Black, + _ => Self::default(), } } } impl From for NbtTag { fn from(value: DyeColor) -> Self { - NbtTag::Byte(value as i8) + Self::Byte(value as i8) } } @@ -160,10 +160,10 @@ impl From for NbtTag { .lock() .unwrap() .iter() - .map(|s| NbtTag::String(s.clone())) + .map(|s| Self::String(s.clone())) .collect(), ); - NbtTag::Compound(nbt) + Self::Compound(nbt) } } @@ -176,17 +176,17 @@ impl From for Text { .get_list("messages") .unwrap() .iter() - .filter_map(|tag| tag.extract_string().map(|s| s.to_string())) + .filter_map(|tag| tag.extract_string().map(std::string::ToString::to_string)) .collect(); Self { has_glowing_text: AtomicBool::new(has_glowing_text), color: AtomicI8::new(DyeColor::from(color) as i8), messages: Arc::new(std::sync::Mutex::new([ // its important that we use unwrap_or since otherwise we may crash on older versions - messages.first().unwrap_or(&"".to_string()).clone(), - messages.get(1).unwrap_or(&"".to_string()).clone(), - messages.get(2).unwrap_or(&"".to_string()).clone(), - messages.get(3).unwrap_or(&"".to_string()).clone(), + messages.first().unwrap_or(&String::new()).clone(), + messages.get(1).unwrap_or(&String::new()).clone(), + messages.get(2).unwrap_or(&String::new()).clone(), + messages.get(3).unwrap_or(&String::new()).clone(), ])), } } @@ -261,6 +261,7 @@ impl BlockEntity for SignBlockEntity { impl SignBlockEntity { pub const ID: &'static str = "minecraft:sign"; + #[must_use] pub fn new(position: BlockPos, is_front: bool, messages: [String; 4]) -> Self { Self { position, @@ -270,14 +271,15 @@ impl SignBlockEntity { } else { Text::default() }, - back_text: if !is_front { - Text::new(messages) - } else { + back_text: if is_front { Text::default() + } else { + Text::new(messages) }, currently_editing_player: Arc::new(Mutex::new(None)), } } + #[must_use] pub fn empty(position: BlockPos) -> Self { Self { position, diff --git a/pumpkin-world/src/block/entities/smoker.rs b/pumpkin-world/src/block/entities/smoker.rs index 76d8baabe..8d2d826d8 100644 --- a/pumpkin-world/src/block/entities/smoker.rs +++ b/pumpkin-world/src/block/entities/smoker.rs @@ -35,6 +35,7 @@ impl SmokerBlockEntity { pub const INVENTORY_SIZE: usize = 3; pub const ID: &'static str = "minecraft:smoker"; + #[must_use] pub fn new(position: BlockPos) -> Self { Self { position, diff --git a/pumpkin-world/src/block/mod.rs b/pumpkin-world/src/block/mod.rs index 98ec32048..db08eaf30 100644 --- a/pumpkin-world/src/block/mod.rs +++ b/pumpkin-world/src/block/mod.rs @@ -38,16 +38,19 @@ fn block_to_string(block: &'static Block, serializer: S) -> Resul } impl BlockStateCodec { + #[must_use] pub fn get_state(&self) -> &'static BlockState { let state_id = self.get_state_id(); BlockState::from_id(state_id) } - pub fn get_block(&self) -> &'static Block { + #[must_use] + pub const fn get_block(&self) -> &'static Block { self.name } /// Prefer this over `get_state` when the only the state ID is needed + #[must_use] pub fn get_state_id(&self) -> BlockStateId { let block = self.name; @@ -73,10 +76,11 @@ mod test { use crate::chunk::palette::BLOCK_NETWORK_MAX_BITS; #[test] - fn test_proper_network_bits_per_entry() { + fn proper_network_bits_per_entry() { let id_to_test = 1 << BLOCK_NETWORK_MAX_BITS; - if Block::from_state_id(id_to_test) != &Block::AIR { - panic!("We need to update our constants!"); - } + assert!( + Block::from_state_id(id_to_test) == &Block::AIR, + "We need to update our constants!" + ); } } diff --git a/pumpkin-world/src/block/state.rs b/pumpkin-world/src/block/state.rs index 823d145dc..603023f77 100644 --- a/pumpkin-world/src/block/state.rs +++ b/pumpkin-world/src/block/state.rs @@ -2,25 +2,28 @@ use pumpkin_data::{Block, BlockState}; use crate::BlockStateId; -/// Instead of using a memory heavy normal BlockState This is used for internal representation in chunks to save memory +/// Instead of using a memory heavy normal `BlockState` This is used for internal representation in chunks to save memory #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct RawBlockState(pub BlockStateId); impl RawBlockState { - pub const AIR: RawBlockState = RawBlockState(0); + pub const AIR: Self = Self(0); #[inline] + #[must_use] pub fn to_state(&self) -> &'static BlockState { BlockState::from_id(self.0) } #[inline] - pub fn to_block(&self) -> &'static Block { + #[must_use] + pub const fn to_block(&self) -> &'static Block { Block::from_state_id(self.0) } #[inline] - pub fn to_block_id(&self) -> u16 { + #[must_use] + pub const fn to_block_id(&self) -> u16 { Block::get_raw_id_from_state_id(self.0) } } diff --git a/pumpkin-world/src/block/viewer.rs b/pumpkin-world/src/block/viewer.rs index 139101bf7..bbf8360a5 100644 --- a/pumpkin-world/src/block/viewer.rs +++ b/pumpkin-world/src/block/viewer.rs @@ -23,7 +23,8 @@ impl Default for ViewerCountTracker { } impl ViewerCountTracker { - pub fn new() -> Self { + #[must_use] + pub const fn new() -> Self { Self { old: AtomicU16::new(0), current: AtomicU16::new(0), diff --git a/pumpkin-world/src/chunk/format/anvil.rs b/pumpkin-world/src/chunk/format/anvil.rs index 6a46f19e2..d9747c081 100644 --- a/pumpkin-world/src/chunk/format/anvil.rs +++ b/pumpkin-world/src/chunk/format/anvil.rs @@ -1,4 +1,4 @@ -use bytes::*; +use bytes::{Buf, Bytes}; use flate2::read::{GzDecoder, GzEncoder, ZlibDecoder, ZlibEncoder}; use itertools::Itertools; use lz4_java_wrc::Context; @@ -43,9 +43,9 @@ pub const WORLD_DATA_VERSION: i32 = 4671; #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] pub enum Compression { - /// GZip Compression + /// `GZip` Compression GZip = Self::GZIP_ID, - /// ZLib Compression + /// `ZLib` Compression ZLib = Self::ZLIB_ID, /// LZ4 Compression (since 24w04a) LZ4 = Self::LZ4_ID, @@ -123,25 +123,25 @@ impl Compression { const CUSTOM_ID: u8 = 127; fn decompress_data(&self, compressed_data: &[u8]) -> Result, CompressionError> { - let initial_capacity = compressed_data.len(); - fn decode(mut reader: R, capacity: usize) -> std::io::Result> { let mut buf = Vec::with_capacity(capacity); reader.read_to_end(&mut buf)?; Ok(buf.into_boxed_slice()) } + let initial_capacity = compressed_data.len(); + match self { - Compression::GZip => decode(GzDecoder::new(compressed_data), initial_capacity) + Self::GZip => decode(GzDecoder::new(compressed_data), initial_capacity) .map_err(CompressionError::GZipError), - Compression::ZLib => decode(ZlibDecoder::new(compressed_data), initial_capacity) + Self::ZLib => decode(ZlibDecoder::new(compressed_data), initial_capacity) .map_err(CompressionError::ZlibError), - Compression::LZ4 => decode( + Self::LZ4 => decode( lz4_java_wrc::Lz4BlockInput::new(compressed_data), initial_capacity, ) .map_err(CompressionError::LZ4Error), - Compression::Custom => todo!(), + Self::Custom => todo!(), } } @@ -152,7 +152,7 @@ impl Compression { compression_level: u32, ) -> Result, CompressionError> { match self { - Compression::GZip => { + Self::GZip => { let mut encoder = GzEncoder::new( uncompressed_data, flate2::Compression::new(compression_level), @@ -163,7 +163,7 @@ impl Compression { .map_err(CompressionError::GZipError)?; Ok(chunk_data) } - Compression::ZLib => { + Self::ZLib => { let mut encoder = ZlibEncoder::new( uncompressed_data, flate2::Compression::new(compression_level), @@ -174,7 +174,7 @@ impl Compression { .map_err(CompressionError::ZlibError)?; Ok(chunk_data) } - Compression::LZ4 => { + Self::LZ4 => { let mut compressed_data = Vec::new(); let block_size = 1 << (Self::LZ4_COMPRESSION_LEVEL_BASE + compression_level); let mut encoder = lz4_java_wrc::Lz4BlockOutput::with_context( @@ -189,13 +189,13 @@ impl Compression { drop(encoder); Ok(compressed_data) } - Compression::Custom => todo!(), + Self::Custom => todo!(), } } /// Returns Ok when a compression is found otherwise an Err #[expect(clippy::result_unit_err)] - pub fn from_byte(byte: u8) -> Result, ()> { + pub const fn from_byte(byte: u8) -> Result, ()> { match byte { Self::GZIP_ID => Ok(Some(Self::GZip)), Self::ZLIB_ID => Ok(Some(Self::ZLib)), @@ -224,20 +224,20 @@ impl From for Compression { impl AnvilChunkData { /// Raw size of serialized chunk #[inline] - fn raw_write_size(&self) -> usize { + const fn raw_write_size(&self) -> usize { // 4 bytes for the *length* and 1 byte for the *compression* method self.compressed_data.len() + 4 + 1 } /// Size of serialized chunk with padding #[inline] - fn padded_size(&self) -> usize { + const fn padded_size(&self) -> usize { let sector_count = self.sector_count() as usize; sector_count * SECTOR_BYTES } #[inline] - fn sector_count(&self) -> u32 { + const fn sector_count(&self) -> u32 { let total_size = self.raw_write_size(); total_size.div_ceil(SECTOR_BYTES) as u32 } @@ -259,9 +259,9 @@ impl AnvilChunkData { let compression_method = bytes.get_u8(); let compression = Compression::from_byte(compression_method) - .map_err(|_| ChunkReadingError::Compression(CompressionError::UnknownCompression))?; + .map_err(|()| ChunkReadingError::Compression(CompressionError::UnknownCompression))?; - Ok(AnvilChunkData { + Ok(Self { compression, // If this has padding, we need to trim it compressed_data: bytes.slice(..length), @@ -322,7 +322,7 @@ impl AnvilChunkData { .compress_data(&raw_bytes, chunk_config.compression.level) .map_err(ChunkWritingError::Compression)?; - Ok(AnvilChunkData { + Ok(Self { compression: Some(compression), compressed_data: compressed_data.into(), }) @@ -330,11 +330,13 @@ impl AnvilChunkData { } impl AnvilChunkFile { + #[must_use] pub const fn get_region_coords(at: &Vector2) -> (i32, i32) { // Divide by 32 for the region coordinates (at.x >> SUBREGION_BITS, at.y >> SUBREGION_BITS) } + #[must_use] pub const fn get_chunk_index(x: i32, z: i32) -> usize { let local_x = x & SUBREGION_AND; let local_z = z & SUBREGION_AND; @@ -375,7 +377,7 @@ impl AnvilChunkFile { } else { // If the chunk is not present, we write 0 to the location and timestamp tables write.write_u32(0).await?; - }; + } } for metadata in &self.chunks_data { @@ -407,7 +409,7 @@ impl AnvilChunkFile { // Verify we are actually two sectors into the file let current_pos = write.stream_position().await?; assert!(current_pos as usize == 2 * SECTOR_BYTES); - } + }; let mut current_sector = 2; for (index, chunk) in chunks { @@ -471,7 +473,7 @@ impl AnvilChunkFile { } else { // If the chunk is not present, we write 0 to the location and timestamp tables write.write_u32(0).await?; - }; + } } for metadata in &self.chunks_data { @@ -561,7 +563,7 @@ impl ChunkSerializer for AnvilChunkFile { let headers = raw_file_bytes.split_to(SECTOR_BYTES * 2); let (mut location_bytes, mut timestamp_bytes) = headers.split_at(SECTOR_BYTES); - let mut chunk_file = AnvilChunkFile::default(); + let mut chunk_file = Self::default(); let mut last_offset = 2; for i in 0..CHUNK_COUNT { @@ -622,7 +624,7 @@ impl ChunkSerializer for AnvilChunkFile { .unwrap() .as_secs() as u32; - let index = AnvilChunkFile::::get_chunk_index(chunk.position().0, chunk.position().1); + let index = Self::get_chunk_index(chunk.position().0, chunk.position().1); // Default to the compression type read from the file let compression_type = self.chunks_data[index] .as_ref() @@ -795,8 +797,8 @@ impl ChunkSerializer for AnvilChunkFile { ) { // Don't par iter here so we can prevent backpressure with the await in the async // runtime - for chunk in chunks.into_iter() { - let index = AnvilChunkFile::::get_chunk_index(chunk.x, chunk.y); + for chunk in chunks { + let index = Self::get_chunk_index(chunk.x, chunk.y); let is_ok = match &self.chunks_data[index] { None => stream.send(LoadedData::Missing(chunk)).await.is_ok(), Some(chunk_metadata) => { @@ -918,7 +920,7 @@ mod tests { } #[tokio::test(flavor = "multi_thread")] - async fn test_write_in_place() { + async fn write_in_place() { let mut config = AdvancedConfiguration::default(); config.chunk.write_in_place = true; override_config_for_testing(config); @@ -1194,7 +1196,7 @@ mod tests { } #[tokio::test(flavor = "multi_thread")] - async fn test_write_bulk() { + async fn write_bulk() { let mut config = AdvancedConfiguration::default(); config.chunk.write_in_place = false; override_config_for_testing(config); @@ -1286,7 +1288,7 @@ mod tests { // TODO /* #[test] - fn test_load_java_chunk() { + fn load_java_chunk() { let temp_dir = TempDir::new().unwrap(); let level_folder = LevelFolder { root_folder: temp_dir.path().to_path_buf(), diff --git a/pumpkin-world/src/chunk/format/linear.rs b/pumpkin-world/src/chunk/format/linear.rs index 8522a7b09..4ca330e68 100644 --- a/pumpkin-world/src/chunk/format/linear.rs +++ b/pumpkin-world/src/chunk/format/linear.rs @@ -17,7 +17,7 @@ use tokio::io::{AsyncWriteExt, BufWriter}; use super::anvil::CHUNK_COUNT; /// The signature of the linear file format -/// used as a header and footer described in https://gist.github.com/Aaron2550/5701519671253d4c6190bde6706f9f98 +/// used as a header and footer described in const SIGNATURE: [u8; 8] = u64::to_be_bytes(0xc3ff13183cca9d9a); #[derive(Default, Copy, Clone)] @@ -33,11 +33,11 @@ pub enum LinearVersion { None = 0x00, /// Version 1 of the Linear Region File Format. (Default) /// - /// Described in: https://github.com/xymb-endcrystalme/LinearRegionFileFormatTools/blob/linearv2/LINEAR.md + /// Described in: V1 = 0x01, /// Version 2 of the Linear Region File Format (currently unsupported). /// - /// Described in: https://github.com/xymb-endcrystalme/LinearRegionFileFormatTools/blob/linearv2/LINEARv2.md + /// Described in: V2 = 0x02, } struct LinearFileHeader { @@ -65,14 +65,14 @@ impl LinearChunkHeader { const CHUNK_HEADER_SIZE: usize = 8; fn from_bytes(bytes: &[u8]) -> Self { let mut bytes = bytes; - LinearChunkHeader { + Self { size: bytes.get_u32(), timestamp: bytes.get_u32(), } } - pub fn to_bytes(self) -> [u8; LinearChunkHeader::CHUNK_HEADER_SIZE] { - let mut bytes = [0u8; LinearChunkHeader::CHUNK_HEADER_SIZE]; + pub fn to_bytes(self) -> [u8; Self::CHUNK_HEADER_SIZE] { + let mut bytes = [0u8; Self::CHUNK_HEADER_SIZE]; bytes[0..4].copy_from_slice(&self.size.to_be_bytes()); bytes[4..8].copy_from_slice(&self.timestamp.to_be_bytes()); @@ -83,9 +83,9 @@ impl LinearChunkHeader { impl From for LinearVersion { fn from(value: u8) -> Self { match value { - 0x01 => LinearVersion::V1, - 0x02 => LinearVersion::V2, - _ => LinearVersion::None, + 0x01 => Self::V1, + 0x02 => Self::V2, + _ => Self::None, } } } @@ -109,7 +109,7 @@ impl LinearFileHeader { fn from_bytes(bytes: &[u8]) -> Self { let mut buf = bytes; - LinearFileHeader { + Self { version: buf.get_u8().into(), newest_timestamp: buf.get_u64(), compression_level: buf.get_u8(), @@ -120,7 +120,7 @@ impl LinearFileHeader { } fn to_bytes(&self) -> Box<[u8]> { - let mut bytes: Vec = Vec::with_capacity(LinearFileHeader::FILE_HEADER_SIZE); + let mut bytes: Vec = Vec::with_capacity(Self::FILE_HEADER_SIZE); bytes.put_u8(self.version as u8); bytes.put_u64(self.newest_timestamp); @@ -141,18 +141,18 @@ impl LinearFile { } fn check_signature(bytes: &[u8]) -> Result<(), ChunkReadingError> { - if bytes != SIGNATURE { + if bytes == SIGNATURE { + Ok(()) + } else { error!("Linear signature is invalid!"); Err(ChunkReadingError::InvalidHeader) - } else { - Ok(()) } } } impl Default for LinearFile { fn default() -> Self { - LinearFile { + Self { chunks_headers: [LinearChunkHeader::default(); CHUNK_COUNT], chunks_data: [const { None }; CHUNK_COUNT], _dummy: Default::default(), @@ -312,7 +312,7 @@ impl ChunkSerializer for LinearFile { } } - Ok(LinearFile { + Ok(Self { chunks_headers: chunk_headers, chunks_data: chunks, _dummy: Default::default(), @@ -324,7 +324,7 @@ impl ChunkSerializer for LinearFile { chunk: &Self::Data, _chunk_config: &Self::ChunkConfig, ) -> Result<(), ChunkWritingError> { - let index = LinearFile::::get_chunk_index(chunk.position().0, chunk.position().1); + let index = Self::get_chunk_index(chunk.position().0, chunk.position().1); let chunk_raw: Bytes = chunk .to_bytes() .await @@ -350,8 +350,8 @@ impl ChunkSerializer for LinearFile { ) { // Don't par iter here so we can prevent backpressure with the await in the async // runtime - for chunk in chunks.into_iter() { - let index = LinearFile::::get_chunk_index(chunk.x, chunk.y); + for chunk in chunks { + let index = Self::get_chunk_index(chunk.x, chunk.y); let linear_chunk_data = &self.chunks_data[index]; let result = if let Some(data) = linear_chunk_data { @@ -436,7 +436,7 @@ mod tests { } #[tokio::test(flavor = "multi_thread")] - async fn test_writing() { + async fn writing() { let _ = env_logger::try_init(); let generator = get_world_gen(Seed(0), Dimension::Overworld); diff --git a/pumpkin-world/src/chunk/format/mod.rs b/pumpkin-world/src/chunk/format/mod.rs index 39793a5cc..b17d39af8 100644 --- a/pumpkin-world/src/chunk/format/mod.rs +++ b/pumpkin-world/src/chunk/format/mod.rs @@ -105,7 +105,7 @@ impl ChunkData { block_sum, sky, sky_sum, - ) + ); } } } @@ -160,7 +160,7 @@ impl ChunkData { let min_y = section_coords::section_to_block(chunk_data.min_y_section); let section = ChunkSections::new(sub_chunks.into_boxed_slice(), min_y); - Ok(ChunkData { + Ok(Self { section, heightmap: chunk_data.heightmaps, x: position.x, @@ -291,28 +291,27 @@ impl ChunkEntityData { } let mut map = HashMap::new(); for entity_nbt in chunk_entity_data.entities { - let uuid = match entity_nbt.get_int_array("UUID") { - Some(uuid) => Uuid::from_u128( + let uuid = if let Some(uuid) = entity_nbt.get_int_array("UUID") { + Uuid::from_u128( (uuid[0] as u128) << 96 | (uuid[1] as u128) << 64 | (uuid[2] as u128) << 32 | (uuid[3] as u128), - ), - None => { - log::debug!( - "Entity in chunk {},{} is missing UUID: {:?}", - position.x, - position.y, - entity_nbt - ); - continue; - } + ) + } else { + log::debug!( + "Entity in chunk {},{} is missing UUID: {:?}", + position.x, + position.y, + entity_nbt + ); + continue; }; map.insert(uuid, entity_nbt); } - Ok(ChunkEntityData { + Ok(Self { x: position.x, z: position.y, data: map, @@ -386,11 +385,13 @@ impl LightContainer { pub const DIM: usize = 16; pub const ARRAY_SIZE: usize = Self::DIM * Self::DIM * Self::DIM / 2; + #[must_use] pub fn new_empty(default: u8) -> Self { assert!(default <= 15, "Default value must be between 0 and 15"); Self::Empty(default) } + #[must_use] pub fn new(data: Box<[u8]>) -> Self { assert!( data.len() == Self::ARRAY_SIZE, @@ -400,20 +401,23 @@ impl LightContainer { Self::Full(data) } + #[must_use] pub fn new_filled(default: u8) -> Self { assert!(default <= 15, "Default value must be between 0 and 15"); let value = default << 4 | default; Self::Full([value; Self::ARRAY_SIZE].into()) } - pub fn is_empty(&self) -> bool { + #[must_use] + pub const fn is_empty(&self) -> bool { matches!(self, Self::Empty(_)) } - fn index(x: usize, y: usize, z: usize) -> usize { + const fn index(x: usize, y: usize, z: usize) -> usize { y * 16 * 16 + z * 16 + x } + #[must_use] pub fn get(&self, x: usize, y: usize, z: usize) -> u8 { match self { Self::Full(data) => { diff --git a/pumpkin-world/src/chunk/io/file_manager.rs b/pumpkin-world/src/chunk/io/file_manager.rs index 3e922bf6a..e47a5c7f9 100644 --- a/pumpkin-world/src/chunk/io/file_manager.rs +++ b/pumpkin-world/src/chunk/io/file_manager.rs @@ -7,7 +7,6 @@ use std::{ use futures::future::join_all; use log::{error, trace}; -use num_traits::Zero; use pumpkin_util::math::vector2::Vector2; use tokio::{ io::AsyncReadExt, @@ -25,12 +24,12 @@ use crate::{ use super::{ChunkSerializer, FileIO, LoadedData}; -/// A simple implementation of the ChunkSerializer trait +/// A simple implementation of the `ChunkSerializer` trait /// that load and save the data from a file in the disk /// using parallelism and a cache for the files with ongoing IO operations. /// /// It also avoid IO operations that could produce dataraces thanks to the -/// custom *DashMap*-like implementation. +/// custom *`DashMap`*-like implementation. pub struct ChunkFileManager> { // Dashmap has rw-locks on shards, but we want per-serializer. // @@ -65,7 +64,7 @@ impl> ChunkSerializerLazyLoader { /// We can only remove this entry from the map if we are the only ones with a reference to it /// IMPORTANT: This must be called within the write lock of the parent map - async fn can_remove(&self) -> bool { + fn can_remove(&self) -> bool { match self.internal.get() { Some(arc) => { // A strong count of 1 means it's only in the map @@ -349,7 +348,7 @@ where .read() .await .get(&path) - .is_some_and(|count| !count.is_zero()); + .is_some_and(|count| count != &0); if !is_watched { // With the modification done, we can drop the write lock but keep the read lock @@ -373,12 +372,12 @@ where .read() .await .get(&path) - .is_none_or(|count| count.is_zero()) + .is_none_or(|count| count == &0) { let mut locks = self.file_locks.write().await; let can_remove = if let Some(loader) = locks.get(&path) { - loader.can_remove().await + loader.can_remove() } else { true }; @@ -416,13 +415,14 @@ where let serializer_cache = self.file_locks.read().await; // Acquire a write lock on all entries to verify they are complete - let tasks = serializer_cache + let _tasks = serializer_cache .values() - .map(|serializer| serializer.can_remove()); + .map(ChunkSerializerLazyLoader::can_remove); // We need to wait to ensure that all the locks are acquired // so there is no **operation** ongoing - let _ = join_all(tasks).await; + // TODO + // let _ = join_all(tasks); }) } } diff --git a/pumpkin-world/src/chunk/io/mod.rs b/pumpkin-world/src/chunk/io/mod.rs index 401ce3c7a..c780804bd 100644 --- a/pumpkin-world/src/chunk/io/mod.rs +++ b/pumpkin-world/src/chunk/io/mod.rs @@ -46,7 +46,7 @@ type BoxFuture<'a, T> = Pin + Send + 'a>>; /// or with different optimizations /// /// The `R` type is the type of the data that will be loaded/saved -/// like ChunkData or EntityData +/// like `ChunkData` or `EntityData` pub trait FileIO where Self: Send + Sync, @@ -94,7 +94,7 @@ where /// Trait to serialize and deserialize the chunk data to and from bytes. /// /// The `Data` type is the type of the data that will be updated or serialized/deserialized -/// like ChunkData or EntityData +/// like `ChunkData` or `EntityData` pub trait ChunkSerializer: Send + Sync + Default { type Data: Send + Sync + Sized + Dirtiable; type WriteBackend; diff --git a/pumpkin-world/src/chunk/mod.rs b/pumpkin-world/src/chunk/mod.rs index ed1aea53a..8b4d87f71 100644 --- a/pumpkin-world/src/chunk/mod.rs +++ b/pumpkin-world/src/chunk/mod.rs @@ -13,6 +13,7 @@ use pumpkin_nbt::compound::NbtCompound; use pumpkin_nbt::nbt_long_array; use pumpkin_util::math::position::BlockPos; use serde::{Deserialize, Serialize}; +use std::fmt::Write; use std::ops::{BitAnd, BitOr}; use std::{collections::HashMap, sync::Arc}; use thiserror::Error; @@ -107,10 +108,11 @@ pub struct ChunkSections { impl ChunkSections { #[cfg(test)] + #[must_use] pub fn dump_blocks(&self) -> Vec { // TODO: this is not optimal, we could use rust iters let mut dump = Vec::new(); - for section in self.sections.iter() { + for section in &self.sections { section.block_states.for_each(|raw_id| { dump.push(raw_id); }); @@ -119,10 +121,11 @@ impl ChunkSections { } #[cfg(test)] + #[must_use] pub fn dump_biomes(&self) -> Vec { // TODO: this is not optimal, we could use rust iters let mut dump = Vec::new(); - for section in self.sections.iter() { + for section in &self.sections { section.biomes.for_each(|raw_id| { dump.push(raw_id); }); @@ -154,9 +157,9 @@ impl TryFrom for ChunkHeightmapType { fn try_from(value: usize) -> Result { match value { - 0 => Ok(ChunkHeightmapType::WorldSurface), - 1 => Ok(ChunkHeightmapType::MotionBlocking), - 2 => Ok(ChunkHeightmapType::MotionBlockingNoLeaves), + 0 => Ok(Self::WorldSurface), + 1 => Ok(Self::MotionBlocking), + 2 => Ok(Self::MotionBlockingNoLeaves), _ => Err("Invalid usize value for ChunkHeightmapType. The value should be 0~2."), } } @@ -174,8 +177,8 @@ pub struct ChunkHeightmaps { } impl ChunkHeightmaps { - pub fn set(&mut self, _type: ChunkHeightmapType, pos: BlockPos, min_y: i32) { - let data = match _type { + pub fn set(&mut self, heightmap: ChunkHeightmapType, pos: BlockPos, min_y: i32) { + let data = match heightmap { ChunkHeightmapType::WorldSurface => &mut self.world_surface, ChunkHeightmapType::MotionBlocking => &mut self.motion_blocking, ChunkHeightmapType::MotionBlockingNoLeaves => &mut self.motion_blocking_no_leaves, @@ -218,6 +221,7 @@ impl ChunkHeightmaps { data[packed_array_idx] = data[packed_array_idx].bitand(mask).bitor(height); } + #[must_use] pub fn get(&self, heightmap: ChunkHeightmapType, x: i32, z: i32, min_y: i32) -> i32 { let local_x = (x & 15) as usize; let local_z = (z & 15) as usize; @@ -253,7 +257,7 @@ impl ChunkHeightmaps { pub fn log_heightmap(&self, _type: ChunkHeightmapType, min_y: i32) { let mut header = "Z/X".to_string(); for x in 0..16 { - header.push_str(&format!("{x:4}")); + let _ = write!(header, "{x:4}"); } let grid: String = (0..16) @@ -287,10 +291,12 @@ impl Default for ChunkHeightmaps { } impl ChunkSections { - pub fn new(sections: Box<[SubChunk]>, min_y: i32) -> Self { + #[must_use] + pub const fn new(sections: Box<[SubChunk]>, min_y: i32) -> Self { Self { sections, min_y } } + #[must_use] pub fn get_block_absolute_y( &self, relative_x: usize, @@ -306,6 +312,7 @@ impl ChunkSections { } } + #[must_use] pub fn get_rough_biome_absolute_y( &self, relative_x: usize, @@ -417,6 +424,7 @@ impl ChunkSections { } } + #[must_use] pub fn get_noise_biome( &self, index: usize, @@ -431,6 +439,7 @@ impl ChunkSections { .map(|section| section.biomes.get(scale_x, scale_y, scale_z)) } + #[must_use] pub fn get_top_y(&self, relative_x: usize, relative_z: usize, first_y: i32) -> Option { debug_assert!(relative_x < BlockPalette::SIZE); debug_assert!(relative_z < BlockPalette::SIZE); @@ -451,6 +460,7 @@ impl ChunkSections { impl ChunkData { /// Gets the given block in the chunk #[inline] + #[must_use] pub fn get_relative_block( &self, relative_x: usize, @@ -567,6 +577,7 @@ impl ChunkData { } } + #[must_use] pub fn get_highest_non_empty_subchunk(&self) -> usize { self.section .sections @@ -574,8 +585,7 @@ impl ChunkData { .enumerate() .rev() .position(|(_, sub)| !sub.block_states.has_only_air()) - .map(|p| self.section.sections.len() - 1 - p) - .unwrap_or(0) + .map_or(0, |p| self.section.sections.len() - 1 - p) } } diff --git a/pumpkin-world/src/chunk/palette.rs b/pumpkin-world/src/chunk/palette.rs index e539f6a8f..fee6c0755 100644 --- a/pumpkin-world/src/chunk/palette.rs +++ b/pumpkin-world/src/chunk/palette.rs @@ -74,7 +74,7 @@ impl PalettedContainer let mut counts: Vec = Vec::new(); // Iterate over the flattened cube to populate the palette and counts - for val in cube.as_flattened().as_flattened().iter() { + for val in cube.as_flattened().as_flattened() { if let Some(index) = palette.iter().position(|v| v == val) { // Value already exists, increment its count counts[index] += 1; @@ -137,6 +137,7 @@ impl PalettedContainer } } + #[must_use] pub fn from_palette_and_packed_data( palette: Vec, packed_data: &[i64], @@ -280,6 +281,7 @@ impl Default for PalettedContai } impl BiomePalette { + #[must_use] pub fn convert_network(&self) -> NetworkSerialization { match self { Self::Homogeneous(registry_id) => NetworkSerialization { @@ -326,6 +328,7 @@ impl BiomePalette { } } + #[must_use] pub fn from_disk_nbt(nbt: ChunkSectionBiomes) -> Self { let palette = nbt .palette @@ -340,6 +343,7 @@ impl BiomePalette { ) } + #[must_use] pub fn to_disk_nbt(&self) -> ChunkSectionBiomes { #[expect(clippy::unnecessary_min_or_max)] let bits_per_entry = self.bits_per_entry().max(BIOME_DISK_MIN_BITS); @@ -361,6 +365,7 @@ impl BiomePalette { } impl BlockPalette { + #[must_use] pub fn convert_network(&self) -> NetworkSerialization { match self { Self::Homogeneous(registry_id) => NetworkSerialization { @@ -408,6 +413,7 @@ impl BlockPalette { } } + #[must_use] pub fn convert_be_network(&self) -> BeNetworkSerialization { match self { Self::Homogeneous(registry_id) => BeNetworkSerialization { @@ -474,6 +480,7 @@ impl BlockPalette { } /// Check if the entire chunk is filled with only air + #[must_use] pub fn has_only_air(&self) -> bool { match self { Self::Homogeneous(id) => is_air(*id), @@ -481,30 +488,26 @@ impl BlockPalette { } } + #[must_use] pub fn non_air_block_count(&self) -> u16 { match self { Self::Homogeneous(registry_id) => { - if !is_air(*registry_id) { - Self::VOLUME as u16 - } else { + if is_air(*registry_id) { 0 + } else { + Self::VOLUME as u16 } } Self::Heterogeneous(data) => data .palette .iter() .zip(data.counts.iter()) - .filter_map(|(registry_id, count)| { - if !is_air(*registry_id) { - Some(*count) - } else { - None - } - }) + .filter_map(|(registry_id, count)| (!is_air(*registry_id)).then_some(*count)) .sum(), } } + #[must_use] pub fn from_disk_nbt(nbt: ChunkSectionBlockStates) -> Self { let palette = nbt .palette @@ -553,7 +556,7 @@ impl BlockPalette { /// Represents the different types of data encoding used in Minecraft's bit-packed chunk sections. /// /// Minecraft uses a "Palette" system to compress chunk data. Instead of sending a full -/// 15-bit BlockState ID for every block, it sends a smaller index (e.g., 4 bits) that +/// 15-bit `BlockState` ID for every block, it sends a smaller index (e.g., 4 bits) that /// points to a value in these palettes. pub enum NetworkPalette { /// **Single Value Palette (Bits per entry: 0)** diff --git a/pumpkin-world/src/chunk_system.rs b/pumpkin-world/src/chunk_system.rs index caa1b7d37..e114504ba 100644 --- a/pumpkin-world/src/chunk_system.rs +++ b/pumpkin-world/src/chunk_system.rs @@ -40,20 +40,18 @@ use std::cmp::{Ordering, PartialEq, max, min}; use std::collections::hash_map::Entry; use std::collections::{BinaryHeap, HashMap}; use std::mem::swap; -use std::ops::Deref; use std::sync::{Arc, Condvar, Mutex}; use crate::chunk::format::LightContainer; use crate::chunk::io::LoadedData; use crate::chunk_system::Chunk::Proto; use crate::chunk_system::StagedChunkEnum::{Biomes, Empty, Features, Full, Noise, Surface}; -use crossfire::AsyncRx; +use crossfire::compat::AsyncRx; use pumpkin_data::chunk::ChunkStatus; use rustc_hash::{FxHashMap, FxHashSet}; use slotmap::{Key, SlotMap, new_key_type}; use std::sync::atomic::Ordering::{Relaxed, SeqCst}; use std::thread; -use std::thread::JoinHandle; use tokio::sync::{RwLock, oneshot}; type HashMapType = FxHashMap; @@ -93,7 +91,7 @@ impl From for (ChunkPos, i8) { struct LevelCache(i32, i32, usize, [(i8, i8); 256 * 256]); impl LevelCache { - fn new() -> Self { + const fn new() -> Self { Self(0, 0, 0, [(0, 0); 256 * 256]) } } @@ -127,7 +125,7 @@ impl LevelCache { value.1 = level; } fn write( - &mut self, + &self, map: &mut ChunkLevel, change: &mut HashMapType, ) { @@ -302,8 +300,7 @@ impl ChunkLoading { .map(|y| { format!( "{:4}", - map.get(&ChunkPos::new(x, y)) - .unwrap_or(&ChunkLoading::MAX_LEVEL) + map.get(&ChunkPos::new(x, y)).unwrap_or(&Self::MAX_LEVEL) ) }) .collect::(), @@ -317,6 +314,7 @@ impl ChunkLoading { } #[inline] + #[must_use] pub const fn get_level_from_view_distance(view_distance: u8) -> i8 { Self::FULL_CHUNK_LEVEL - (view_distance as i8) } @@ -434,7 +432,7 @@ impl ChunkLoading { // log::debug!("add force ticket at {pos:?}"); self.high_priority.push(pos); self.is_priority_dirty = true; - self.add_ticket(pos, ChunkLoading::FULL_CHUNK_LEVEL); + self.add_ticket(pos, Self::FULL_CHUNK_LEVEL); } pub fn remove_force_ticket(&mut self, pos: ChunkPos) { // log::debug!("remove force ticket at {pos:?}"); @@ -446,7 +444,7 @@ impl ChunkLoading { .0; self.high_priority.remove(index); self.is_priority_dirty = true; - self.remove_ticket(pos, ChunkLoading::FULL_CHUNK_LEVEL); + self.remove_ticket(pos, Self::FULL_CHUNK_LEVEL); } pub fn add_ticket(&mut self, pos: ChunkPos, level: i8) { // log::debug!("add ticket at {pos:?} level {level}"); @@ -460,7 +458,7 @@ impl ChunkLoading { } } - let old = *self.pos_level.get(&pos).unwrap_or(&ChunkLoading::MAX_LEVEL); + let old = *self.pos_level.get(&pos).unwrap_or(&Self::MAX_LEVEL); if old <= level { return; } @@ -547,8 +545,8 @@ impl From for StagedChunkEnum { fn from(status: ChunkStatus) -> Self { match status { ChunkStatus::Empty => Empty, - ChunkStatus::StructureStarts => StagedChunkEnum::StructureStart, - ChunkStatus::StructureReferences => StagedChunkEnum::StructureReferences, + ChunkStatus::StructureStarts => Self::StructureStart, + ChunkStatus::StructureReferences => Self::StructureReferences, ChunkStatus::Biomes => Biomes, ChunkStatus::Noise => Noise, ChunkStatus::Surface => Surface, @@ -565,14 +563,14 @@ impl From for StagedChunkEnum { impl From for ChunkStatus { fn from(status: StagedChunkEnum) -> Self { match status { - StagedChunkEnum::Empty => ChunkStatus::Empty, - StagedChunkEnum::StructureStart => ChunkStatus::StructureStarts, - StagedChunkEnum::StructureReferences => ChunkStatus::StructureReferences, - StagedChunkEnum::Biomes => ChunkStatus::Biomes, - StagedChunkEnum::Noise => ChunkStatus::Noise, - StagedChunkEnum::Surface => ChunkStatus::Surface, - StagedChunkEnum::Features => ChunkStatus::Features, - StagedChunkEnum::Full => ChunkStatus::Full, + StagedChunkEnum::Empty => Self::Empty, + StagedChunkEnum::StructureStart => Self::StructureStarts, + StagedChunkEnum::StructureReferences => Self::StructureReferences, + StagedChunkEnum::Biomes => Self::Biomes, + StagedChunkEnum::Noise => Self::Noise, + StagedChunkEnum::Surface => Self::Surface, + StagedChunkEnum::Features => Self::Features, + StagedChunkEnum::Full => Self::Full, _ => panic!(), } } @@ -620,7 +618,7 @@ impl StagedChunkEnum { _ => panic!(), } } - const fn get_direct_dependencies(self) -> &'static [StagedChunkEnum] { + const fn get_direct_dependencies(self) -> &'static [Self] { match self { // In vanilla StructureStart is first, but since it needs the biome in Vanilla it gets computed in StructureStart and // the Biome Step, this should be more efficient @@ -653,7 +651,8 @@ impl Default for LevelChannel { } impl LevelChannel { - pub fn new() -> Self { + #[must_use] + pub const fn new() -> Self { Self { value: Mutex::new((None, None)), notify: Condvar::new(), @@ -767,19 +766,19 @@ pub enum Chunk { impl Chunk { fn get_stage_id(&self) -> u8 { match self { - Chunk::Proto(data) => data.stage_id(), - Chunk::Level(_) => 8, + Self::Proto(data) => data.stage_id(), + Self::Level(_) => 8, } } fn get_proto_chunk_mut(&mut self) -> &mut ProtoChunk { match self { - Chunk::Level(_) => panic!("chunk isn't a ProtoChunk"), + Self::Level(_) => panic!("chunk isn't a ProtoChunk"), Proto(chunk) => chunk, } } fn get_proto_chunk(&self) -> &ProtoChunk { match self { - Chunk::Level(_) => panic!("chunk isn't a ProtoChunk"), + Self::Level(_) => panic!("chunk isn't a ProtoChunk"), Proto(chunk) => chunk, } } @@ -857,7 +856,7 @@ impl Chunk { }; chunk.heightmap = chunk.calculate_heightmap(); - *self = Chunk::Level(Arc::new(RwLock::new(chunk))); + *self = Self::Level(Arc::new(RwLock::new(chunk))); } } @@ -924,22 +923,16 @@ impl GenerationCache for Cache { let dx = chunk_x - self.x; let dz = chunk_z - self.z; - if dx >= 0 && dx < self.size && dz >= 0 && dz < self.size { - Some(self.chunks[(dx * self.size + dz) as usize].get_proto_chunk_mut()) - } else { - None - } + (dx >= 0 && dx < self.size && dz >= 0 && dz < self.size) + .then(|| self.chunks[(dx * self.size + dz) as usize].get_proto_chunk_mut()) } fn get_chunk(&self, chunk_x: i32, chunk_z: i32) -> Option<&ProtoChunk> { let dx = chunk_x - self.x; let dz = chunk_z - self.z; - if dx >= 0 && dx < self.size && dz >= 0 && dz < self.size { - Some(self.chunks[(dx * self.size + dz) as usize].get_proto_chunk()) - } else { - None - } + (dx >= 0 && dx < self.size && dz >= 0 && dz < self.size) + .then(|| self.chunks[(dx * self.size + dz) as usize].get_proto_chunk()) } fn get_center_chunk(&self) -> &ProtoChunk { @@ -1148,8 +1141,8 @@ impl GenerationCache for Cache { } impl Cache { - fn new(x: i32, z: i32, size: i32) -> Cache { - Cache { + fn new(x: i32, z: i32, size: i32) -> Self { + Self { x, z, size, @@ -1189,7 +1182,7 @@ impl Cache { noise_router, ), Features => { - ProtoChunk::generate_features_and_structure(self, block_registry, random_config) + ProtoChunk::generate_features_and_structure(self, block_registry, random_config); } Full => { let chunk = self.chunks[mid].get_proto_chunk_mut(); @@ -1217,7 +1210,8 @@ impl Default for ChunkListener { } } impl ChunkListener { - pub fn new() -> Self { + #[must_use] + pub const fn new() -> Self { Self { single: Mutex::new(Vec::new()), global: Mutex::new(Vec::new()), @@ -1261,16 +1255,13 @@ impl ChunkListener { let mut i = 0; let mut len = global.len(); while i < len { - match global[i].send((pos, chunk.clone())) { - Ok(_) => { - // log::debug!("global listener {i} send {pos:?}"); - } - Err(_) => { - // log::debug!("one global listener dropped"); - global.remove(i); - len -= 1; - continue; - } + if matches!(global[i].send((pos, chunk.clone())), Ok(())) { + // log::debug!("global listener {i} send {pos:?}"); + } else { + // log::debug!("one global listener dropped"); + global.remove(i); + len -= 1; + continue; } i += 1; } @@ -1330,7 +1321,7 @@ struct Edge { } impl Edge { - fn new(to: NodeKey, next: EdgeKey) -> Self { + const fn new(to: NodeKey, next: EdgeKey) -> Self { Self { to, next } } } @@ -1392,82 +1383,89 @@ pub struct GenerationSchedule { io_lock: IOLock, running_task_count: u16, - recv_chunk: crossfire::MRx<(ChunkPos, RecvChunk)>, - io_read: crossfire::MTx, - io_write: crossfire::Tx>, - generate: crossfire::MTx<(ChunkPos, Cache, StagedChunkEnum)>, + recv_chunk: crossfire::compat::MRx<(ChunkPos, RecvChunk)>, + io_read: crossfire::compat::MTx, + io_write: crossfire::compat::Tx>, + generate: crossfire::compat::MTx<(ChunkPos, Cache, StagedChunkEnum)>, listener: Arc, } impl GenerationSchedule { pub fn create( - oi_read_thread_count: usize, + io_read_thread_count: usize, gen_thread_count: usize, level: Arc, level_channel: Arc, listener: Arc, - thread_tracker: &mut Vec>, + thread_tracker: &mut Vec>, ) { - let tracker = &level.chunk_system_tasks; - let (send_chunk, recv_chunk) = crossfire::mpmc::unbounded_blocking(); + let (send_chunk, recv_chunk) = crossfire::compat::mpmc::unbounded_blocking(); + let (send_read_io, recv_read_io) = - crossfire::mpmc::bounded_tx_blocking_rx_async(oi_read_thread_count + 2); - let (send_write_io, recv_write_io) = crossfire::spsc::unbounded_async(); - let (send_gen, recv_gen) = crossfire::mpmc::bounded_blocking(gen_thread_count + 5); + crossfire::compat::mpmc::bounded_tx_blocking_rx_async(io_read_thread_count + 5); + + let (send_write_io, recv_write_io) = crossfire::compat::spsc::unbounded_async(); + + let (send_gen, recv_gen) = crossfire::compat::mpmc::bounded_blocking(gen_thread_count + 5); + let io_lock = Arc::new((Mutex::new(HashMapType::default()), Condvar::new())); - for _ in 0..oi_read_thread_count { - tracker.spawn(Self::io_read_work( + + for _ in 0..io_read_thread_count { + level.chunk_system_tasks.spawn(Self::io_read_work( recv_read_io.clone(), send_chunk.clone(), level.clone(), io_lock.clone(), )); } - for i in 0..gen_thread_count { - let recv_gen = recv_gen.clone(); - let send_chunk = send_chunk.clone(); - let level = level.clone(); - let builder = thread::Builder::new().name(format!("Generation Thread {i}")); - thread_tracker.push( - builder - .spawn(move || { - Self::generation_work(recv_gen, send_chunk, level); - }) - .unwrap(), - ); - } - tracker.spawn(Self::io_write_work( + level.chunk_system_tasks.spawn(Self::io_write_work( recv_write_io, level.clone(), io_lock.clone(), )); - let builder = thread::Builder::new().name("Schedule Thread".to_string()); - thread_tracker.push( - builder + for i in 0..gen_thread_count { + let recv_gen = recv_gen.clone(); + let send_chunk = send_chunk.clone(); + let level_clone = level.clone(); + + let handle = thread::Builder::new() + .name(format!("Gen-{}", i)) // Identifying dim helps debugging .spawn(move || { - Self { - queue: BinaryHeap::new(), - graph: DAG::default(), - last_level: ChunkLevel::default(), - last_high_priority: Vec::new(), - send_level: level_channel, - public_chunk_map: level.loaded_chunks.clone(), - unload_chunks: HashSetType::default(), - io_lock, - running_task_count: 0, - recv_chunk, - io_read: send_read_io, - io_write: send_write_io, - generate: send_gen, - listener, - chunk_map: Default::default(), - } - .work(level); + Self::generation_work(recv_gen, send_chunk, level_clone); }) - .unwrap(), - ) + .expect("Failed to spawn Generation Thread"); + + thread_tracker.push(handle); + } + + let level_sched = level.clone(); + let handle = thread::Builder::new() + .name("Schedule".to_string()) + .spawn(move || { + let scheduler = Self { + queue: BinaryHeap::new(), + graph: DAG::default(), + last_level: ChunkLevel::default(), + last_high_priority: Vec::new(), + send_level: level_channel, + public_chunk_map: level_sched.loaded_chunks.clone(), + unload_chunks: HashSetType::default(), + io_lock, + running_task_count: 0, + recv_chunk, + io_read: send_read_io, + io_write: send_write_io, + generate: send_gen, + listener, + chunk_map: Default::default(), + }; + scheduler.work(level_sched); + }) + .expect("Failed to spawn Scheduler Thread"); + + thread_tracker.push(handle); } fn calc_priority( @@ -1627,29 +1625,31 @@ impl GenerationSchedule { } async fn io_read_work( - recv: crossfire::MAsyncRx, - send: crossfire::MTx<(ChunkPos, RecvChunk)>, + recv: crossfire::compat::MAsyncRx, + send: crossfire::compat::MTx<(ChunkPos, RecvChunk)>, level: Arc, lock: IOLock, ) { - log::debug!("io read thread start"); use crate::biome::hash_seed; + log::debug!("io read thread start"); let biome_mixer_seed = hash_seed(level.world_gen.random_config.seed); let dimension = &level.world_gen.dimension; - let (t_send, mut t_recv) = tokio::sync::mpsc::channel(2); + let (t_send, mut t_recv) = tokio::sync::mpsc::channel(1); while let Ok(pos) = recv.recv().await { - // debug!("io read thread receive chunk pos {pos:?}"); - { + tokio::task::block_in_place(|| { let mut data = lock.0.lock().unwrap(); while data.contains_key(&pos) { - data = tokio::task::block_in_place(|| lock.1.wait(data).unwrap()); + data = lock.1.wait(data).unwrap(); } - } + }); level .chunk_saver .fetch_chunks(&level.level_folder, &[pos], t_send.clone()) .await; - let data = t_recv.recv().await.unwrap(); + let data = match t_recv.recv().await { + Some(res) => res, + None => break, + }; match data { Loaded(chunk) => { if chunk.read().await.status == ChunkStatus::Full { @@ -1663,7 +1663,7 @@ impl GenerationSchedule { // debug!("io read thread receive proto chunk {pos:?}",); let val = RecvChunk::IO(Chunk::Proto(Box::new(ProtoChunk::from_chunk_data( - chunk.read().await.deref(), + &*chunk.read().await, dimension, level.world_gen.default_block, biome_mixer_seed, @@ -1745,8 +1745,8 @@ impl GenerationSchedule { } fn generation_work( - recv: crossfire::MRx<(ChunkPos, Cache, StagedChunkEnum)>, - send: crossfire::MTx<(ChunkPos, RecvChunk)>, + recv: crossfire::compat::MRx<(ChunkPos, Cache, StagedChunkEnum)>, + send: crossfire::compat::MTx<(ChunkPos, RecvChunk)>, level: Arc, ) { log::debug!( @@ -1797,16 +1797,16 @@ impl GenerationSchedule { self.public_chunk_map.remove(&pos); holder.public = false; } - if Arc::strong_count(&chunk) != 1 { + if Arc::strong_count(&chunk) == 1 { + // log::debug!("unload chunk {pos:?} to file"); + chunks.push((pos, Chunk::Level(chunk))); + self.chunk_map.remove(&pos); + } else { // log::debug!( // "chunk {pos:?} is still used somewhere. it can't be unloaded" // ); self.unload_chunks.insert(pos); holder.chunk = Some(Chunk::Level(chunk)); - } else { - // log::debug!("unload chunk {pos:?} to file"); - chunks.push((pos, Chunk::Level(chunk))); - self.chunk_map.remove(&pos); } } Chunk::Proto(chunk) => { diff --git a/pumpkin-world/src/cylindrical_chunk_iterator.rs b/pumpkin-world/src/cylindrical_chunk_iterator.rs index 307dd0ded..bdf37fcac 100644 --- a/pumpkin-world/src/cylindrical_chunk_iterator.rs +++ b/pumpkin-world/src/cylindrical_chunk_iterator.rs @@ -2,14 +2,15 @@ use std::num::NonZeroU8; use pumpkin_util::math::vector2::Vector2; -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, PartialEq, Eq)] pub struct Cylindrical { pub center: Vector2, pub view_distance: NonZeroU8, } impl Cylindrical { - pub fn new(center: Vector2, view_distance: NonZeroU8) -> Self { + #[must_use] + pub const fn new(center: Vector2, view_distance: NonZeroU8) -> Self { Self { center, view_distance, @@ -17,8 +18,8 @@ impl Cylindrical { } pub fn for_each_changed_chunk( - old_cylindrical: Cylindrical, - new_cylindrical: Cylindrical, + old_cylindrical: Self, + new_cylindrical: Self, newly_included: &mut Vec>, just_removed: &mut Vec>, ) { @@ -37,22 +38,23 @@ impl Cylindrical { } } - fn left(&self) -> i32 { + const fn left(&self) -> i32 { self.center.x - self.view_distance.get() as i32 - 1 } - fn bottom(&self) -> i32 { + const fn bottom(&self) -> i32 { self.center.y - self.view_distance.get() as i32 - 1 } - fn right(&self) -> i32 { + const fn right(&self) -> i32 { self.center.x + self.view_distance.get() as i32 + 1 } - fn top(&self) -> i32 { + const fn top(&self) -> i32 { self.center.y + self.view_distance.get() as i32 + 1 } + #[must_use] pub fn is_within_distance(&self, x: i32, z: i32) -> bool { if self.view_distance.get() == 1 { return false; @@ -66,6 +68,7 @@ impl Cylindrical { } /// Returns an iterator of all chunks within this cylinder + #[must_use] pub fn all_chunks_within(&self) -> Vec> { if self.view_distance.get() == 1 { return Vec::new(); @@ -102,7 +105,7 @@ mod test { use pumpkin_util::math::vector2::Vector2; #[test] - fn test_bounds() { + fn bounds() { let mut cylinder = Cylindrical::new(Vector2::new(0, 0), NonZeroU8::new(1).unwrap()); for view_distance in 1..=32 { @@ -133,9 +136,7 @@ mod test { let chunks = cylinder.all_chunks_within(); let estimated_capacity = ((distance as usize + 3).pow(2) * 3167) >> 10; - if estimated_capacity < chunks.len() { - panic!() - } + assert!(estimated_capacity >= chunks.len(),); } } } diff --git a/pumpkin-world/src/data/player_data.rs b/pumpkin-world/src/data/player_data.rs index b8ac33ebe..2b5c3c7d1 100644 --- a/pumpkin-world/src/data/player_data.rs +++ b/pumpkin-world/src/data/player_data.rs @@ -43,20 +43,21 @@ impl PlayerDataStorage { } #[must_use] - pub fn get_data_path(&self) -> &PathBuf { + pub const fn get_data_path(&self) -> &PathBuf { &self.data_path } #[must_use] - pub fn is_save_enabled(&self) -> bool { + pub const fn is_save_enabled(&self) -> bool { self.save_enabled } - pub fn set_save_enabled(&mut self, enabled: bool) { + pub const fn set_save_enabled(&mut self, enabled: bool) { self.save_enabled = enabled; } /// Returns the path for a player's data file based on their UUID. + #[must_use] pub fn get_player_data_path(&self, uuid: &Uuid) -> PathBuf { self.get_data_path().join(format!("{uuid}.dat")) } diff --git a/pumpkin-world/src/dimension.rs b/pumpkin-world/src/dimension.rs index d6c3af4f0..5d5c786ef 100644 --- a/pumpkin-world/src/dimension.rs +++ b/pumpkin-world/src/dimension.rs @@ -14,10 +14,10 @@ pub fn into_level( ) -> Arc { if dimension == Dimension::OVERWORLD { } else if dimension == Dimension::THE_NETHER { - base_directory.push("DIM-1") + base_directory.push("DIM-1"); } else if dimension == Dimension::THE_END { - base_directory.push("DIM1") - }; + base_directory.push("DIM1"); + } Level::from_root_folder( level_config, base_directory, diff --git a/pumpkin-world/src/generation/biome.rs b/pumpkin-world/src/generation/biome.rs index 013c25293..b5fcb4823 100644 --- a/pumpkin-world/src/generation/biome.rs +++ b/pumpkin-world/src/generation/biome.rs @@ -142,7 +142,7 @@ fn scale_mix(l: i64) -> f64 { } #[inline] -fn salt_mix(seed: i64, salt: i64) -> i64 { +const fn salt_mix(seed: i64, salt: i64) -> i64 { let mixed_seed = seed.wrapping_mul( seed.wrapping_mul(6364136223846793005) .wrapping_add(1442695040888963407), @@ -162,32 +162,32 @@ mod test { use super::salt_mix; #[test] - fn test_mix_seed() { + fn mix_seed() { let seed = salt_mix(12345678, 12345678); assert_eq!(seed, 2937271135939595220); } #[test] - fn test_permutation() { + fn permutation() { let seed = hash_seed(0); let score = score_permutation(seed, 123, 456, 456, 0.25, 0.5, 0.75); assert_eq!(score, 1.276986312866211); } #[test] - fn test_biome_blend() { + fn biome_blend() { let biome_pos = get_biome_blend(-64, 384, 1234567890, 123, 123, 123); assert_eq!(biome_pos, Vector3::new(31, 30, 30)); } #[test] - fn test_scale() { + fn scale() { let seed = scale_mix(12345678); assert_eq!(seed, -0.45); } #[test] - fn test_chunk_wide_blend() { + fn chunk_wide_blend() { let data: Vec<(i32, i32, i32, i32, i32, i32)> = read_data_from_file!("../../assets/biome_mixer.json"); diff --git a/pumpkin-world/src/generation/blender/mod.rs b/pumpkin-world/src/generation/blender/mod.rs index e2215cb85..e7ed84628 100644 --- a/pumpkin-world/src/generation/blender/mod.rs +++ b/pumpkin-world/src/generation/blender/mod.rs @@ -8,7 +8,7 @@ pub struct BlendResult { } impl BlendResult { - pub fn new(alpha: f64, offset: f64) -> Self { + pub const fn new(alpha: f64, offset: f64) -> Self { Self { alpha, offset } } } diff --git a/pumpkin-world/src/generation/block_predicate.rs b/pumpkin-world/src/generation/block_predicate.rs index c0e039f7e..7a3c96c05 100644 --- a/pumpkin-world/src/generation/block_predicate.rs +++ b/pumpkin-world/src/generation/block_predicate.rs @@ -47,18 +47,18 @@ impl BlockPredicate { pos: &BlockPos, ) -> bool { match self { - BlockPredicate::MatchingBlocks(predicate) => predicate.test(chunk, pos), - BlockPredicate::MatchingBlockTag(predicate) => predicate.test(chunk, pos), - BlockPredicate::MatchingFluids(predicate) => predicate.test(chunk, pos), - BlockPredicate::HasSturdyFace(predicate) => predicate.test(chunk, pos), - BlockPredicate::Solid(predicate) => predicate.test(chunk, pos), - BlockPredicate::Replaceable(predicate) => predicate.test(chunk, pos), - BlockPredicate::WouldSurvive(predicate) => predicate.test(block_registry, chunk, pos), - BlockPredicate::InsideWorldBounds(predicate) => predicate.test(chunk, pos), - BlockPredicate::AnyOf(predicate) => predicate.test(block_registry, chunk, pos), - BlockPredicate::AllOf(predicate) => predicate.test(block_registry, chunk, pos), - BlockPredicate::Not(predicate) => predicate.test(block_registry, chunk, pos), - BlockPredicate::AlwaysTrue => true, + Self::MatchingBlocks(predicate) => predicate.test(chunk, pos), + Self::MatchingBlockTag(predicate) => predicate.test(chunk, pos), + Self::MatchingFluids(predicate) => predicate.test(chunk, pos), + Self::HasSturdyFace(predicate) => predicate.test(chunk, pos), + Self::Solid(predicate) => predicate.test(chunk, pos), + Self::Replaceable(predicate) => predicate.test(chunk, pos), + Self::WouldSurvive(predicate) => predicate.test(block_registry, chunk, pos), + Self::InsideWorldBounds(predicate) => predicate.test(chunk, pos), + Self::AnyOf(predicate) => predicate.test(block_registry, chunk, pos), + Self::AllOf(predicate) => predicate.test(block_registry, chunk, pos), + Self::Not(predicate) => predicate.test(block_registry, chunk, pos), + Self::AlwaysTrue => true, } } } diff --git a/pumpkin-world/src/generation/block_state_provider.rs b/pumpkin-world/src/generation/block_state_provider.rs index 90855893d..962554d71 100644 --- a/pumpkin-world/src/generation/block_state_provider.rs +++ b/pumpkin-world/src/generation/block_state_provider.rs @@ -37,13 +37,13 @@ pub enum BlockStateProvider { impl BlockStateProvider { pub fn get(&self, random: &mut RandomGenerator, pos: BlockPos) -> &'static BlockState { match self { - BlockStateProvider::NoiseThreshold(provider) => provider.get(random, pos), - BlockStateProvider::NoiseProvider(provider) => provider.get(pos), - BlockStateProvider::Simple(provider) => provider.get(pos), - BlockStateProvider::Weighted(provider) => provider.get(random), - BlockStateProvider::DualNoise(provider) => provider.get(pos), - BlockStateProvider::Pillar(provider) => provider.get(pos), - BlockStateProvider::RandomizedInt(provider) => provider.get(random, pos), + Self::NoiseThreshold(provider) => provider.get(random, pos), + Self::NoiseProvider(provider) => provider.get(pos), + Self::Simple(provider) => provider.get(pos), + Self::Weighted(provider) => provider.get(random), + Self::DualNoise(provider) => provider.get(pos), + Self::Pillar(provider) => provider.get(pos), + Self::RandomizedInt(provider) => provider.get(random, pos), } } } @@ -190,7 +190,7 @@ impl NoiseBlockStateProvider { states: &'a [BlockStateCodec], value: f64, ) -> &'a BlockStateCodec { - let val = ((1.0 + value) / 2.0).clamp(0.0, 0.9999); + let val = f64::midpoint(1.0, value).clamp(0.0, 0.9999); &states[(val * states.len() as f64) as usize] } } diff --git a/pumpkin-world/src/generation/feature/features/desert_well.rs b/pumpkin-world/src/generation/feature/features/desert_well.rs index f1449ef34..36b704406 100644 --- a/pumpkin-world/src/generation/feature/features/desert_well.rs +++ b/pumpkin-world/src/generation/feature/features/desert_well.rs @@ -59,7 +59,7 @@ impl DesertWellFeature { chunk.set_block_state(&block_pos.0, WATER_BLOCK.default_state); - for direction in BlockDirection::horizontal().iter() { + for direction in &BlockDirection::horizontal() { chunk.set_block_state( &block_pos.0.add(&direction.to_offset()), WATER_BLOCK.default_state, @@ -69,7 +69,7 @@ impl DesertWellFeature { let block_pos2 = &block_pos.0.add(&Vector3::new(0, -1, 0)); chunk.set_block_state(block_pos2, Self::SAND.default_state); - for direction2 in BlockDirection::horizontal().iter() { + for direction2 in &BlockDirection::horizontal() { chunk.set_block_state( &block_pos2.add(&direction2.to_offset()), Self::SAND.default_state, diff --git a/pumpkin-world/src/generation/feature/features/drip_stone/small.rs b/pumpkin-world/src/generation/feature/features/drip_stone/small.rs index 24aca2f0c..c9bdfb51c 100644 --- a/pumpkin-world/src/generation/feature/features/drip_stone/small.rs +++ b/pumpkin-world/src/generation/feature/features/drip_stone/small.rs @@ -31,7 +31,7 @@ impl SmallDripstoneFeature { } fn get_direction( - chunk: &mut T, + chunk: &T, pos: BlockPos, random: &mut RandomGenerator, ) -> Option { diff --git a/pumpkin-world/src/generation/feature/features/fallen_tree.rs b/pumpkin-world/src/generation/feature/features/fallen_tree.rs index 696c86b6f..b532625ed 100644 --- a/pumpkin-world/src/generation/feature/features/fallen_tree.rs +++ b/pumpkin-world/src/generation/feature/features/fallen_tree.rs @@ -9,7 +9,7 @@ pub struct FallenTreeFeature { } impl FallenTreeFeature { - pub fn generate( + pub const fn generate( &self, _chunk: &mut ProtoChunk, _min_y: i8, diff --git a/pumpkin-world/src/generation/feature/features/netherrack_replace_blobs.rs b/pumpkin-world/src/generation/feature/features/netherrack_replace_blobs.rs index 31d9061e2..459a1cd80 100644 --- a/pumpkin-world/src/generation/feature/features/netherrack_replace_blobs.rs +++ b/pumpkin-world/src/generation/feature/features/netherrack_replace_blobs.rs @@ -56,7 +56,7 @@ impl ReplaceBlobsFeature { fn move_down_to_target( mut pos: BlockPos, - chunk: &mut T, + chunk: &T, target: &'static Block, ) -> Option { while pos.0.y > chunk.bottom_y() as i32 + 1 { diff --git a/pumpkin-world/src/generation/feature/features/ore.rs b/pumpkin-world/src/generation/feature/features/ore.rs index 1f997acb4..47fd83aa2 100644 --- a/pumpkin-world/src/generation/feature/features/ore.rs +++ b/pumpkin-world/src/generation/feature/features/ore.rs @@ -37,7 +37,7 @@ impl OreFeature { ) -> bool { let f = random.next_f32() * f32::consts::PI; let g = self.size as f32 / 8.0f32; - let i = ((self.size as f32 / 16.0f32 * 2.0 + 1.0) / 2.0).ceil() as i32; + let i = f32::midpoint(self.size as f32 / 16.0f32 * 2.0, 1.0).ceil() as i32; let d = pos.0.x as f64 + f.sin() as f64 * g as f64; let e = pos.0.x as f64 - f.sin() as f64 * g as f64; @@ -94,7 +94,7 @@ impl OreFeature { let e = lerp(f as f64, start_y, end_y); let g = lerp(f as f64, start_z, end_z); let h = random.next_f64() * j as f64 / 16.0; - let l = (((f32::consts::PI * f).sin() + 1.0) * h as f32 + 1.0) / 2.0; + let l = f32::midpoint(((f32::consts::PI * f).sin() + 1.0) * h as f32, 1.0); ds[k as usize * 4] = d; ds[k as usize * 4 + 1] = e; @@ -192,7 +192,7 @@ impl OreFeature { block_state.to_state(), random, target, - &mut mutable_pos, + &mutable_pos, ) { chunk.set_block_state(&pos_vec, target.state.get_state()); placed_blocks_count += 1; @@ -208,11 +208,11 @@ impl OreFeature { fn should_place( &self, - chunk: &mut T, + chunk: &T, state: &'static BlockState, random: &mut RandomGenerator, target: &OreTarget, - pos: &mut BlockPos, + pos: &BlockPos, ) -> bool { if !target.target.test(state, random) { return false; @@ -233,7 +233,7 @@ impl OreFeature { random.next_f32() >= chance } - fn is_exposed_to_air(chunk: &mut T, pos: &BlockPos) -> bool { + fn is_exposed_to_air(chunk: &T, pos: &BlockPos) -> bool { for dir in BlockDirection::all() { if GenerationCache::get_block_state(chunk, &pos.offset(dir.to_offset()).0) .to_state() diff --git a/pumpkin-world/src/generation/feature/features/random_patch.rs b/pumpkin-world/src/generation/feature/features/random_patch.rs index b9edb9b84..8d3ec9ca2 100644 --- a/pumpkin-world/src/generation/feature/features/random_patch.rs +++ b/pumpkin-world/src/generation/feature/features/random_patch.rs @@ -47,7 +47,7 @@ impl RandomPatchFeature { ) { continue; } - is_some = true + is_some = true; } is_some } diff --git a/pumpkin-world/src/generation/feature/features/tree/decorator/mod.rs b/pumpkin-world/src/generation/feature/features/tree/decorator/mod.rs index 992a30fc4..3d38c9f27 100644 --- a/pumpkin-world/src/generation/feature/features/tree/decorator/mod.rs +++ b/pumpkin-world/src/generation/feature/features/tree/decorator/mod.rs @@ -57,19 +57,19 @@ impl TreeDecorator { log_positions: &[BlockPos], ) { match self { - TreeDecorator::TrunkVine(decorator) => decorator.generate(chunk, random, log_positions), - TreeDecorator::LeaveVine(_decorator) => {} - TreeDecorator::PaleMoss(_decorator) => {} - TreeDecorator::CreakingHeart(_decorator) => {} - TreeDecorator::Cocoa(_decorator) => {} - TreeDecorator::Beehive(_decorator) => {} - TreeDecorator::AlterGround(_decorator) => {} - TreeDecorator::PlaceOnGround(decorator) => { - decorator.generate(chunk, random, root_positions, log_positions) + Self::TrunkVine(decorator) => decorator.generate(chunk, random, log_positions), + Self::LeaveVine(_decorator) => {} + Self::PaleMoss(_decorator) => {} + Self::CreakingHeart(_decorator) => {} + Self::Cocoa(_decorator) => {} + Self::Beehive(_decorator) => {} + Self::AlterGround(_decorator) => {} + Self::PlaceOnGround(decorator) => { + decorator.generate(chunk, random, root_positions, log_positions); } - TreeDecorator::AttachedToLeaves(_decorator) => {} - TreeDecorator::AttachedToLogs(decorator) => { - decorator.generate(chunk, random, log_positions) + Self::AttachedToLeaves(_decorator) => {} + Self::AttachedToLogs(decorator) => { + decorator.generate(chunk, random, log_positions); } } } diff --git a/pumpkin-world/src/generation/feature/features/tree/foliage/acacia.rs b/pumpkin-world/src/generation/feature/features/tree/foliage/acacia.rs index a28877a25..e1e890896 100644 --- a/pumpkin-world/src/generation/feature/features/tree/foliage/acacia.rs +++ b/pumpkin-world/src/generation/feature/features/tree/foliage/acacia.rs @@ -53,7 +53,7 @@ impl AcaciaFoliagePlacer { ); } - pub fn get_random_height(&self, _random: &mut RandomGenerator) -> i32 { + pub const fn get_random_height(&self, _random: &mut RandomGenerator) -> i32 { 0 } } diff --git a/pumpkin-world/src/generation/feature/features/tree/foliage/blob.rs b/pumpkin-world/src/generation/feature/features/tree/foliage/blob.rs index 0e761444e..4ab982d70 100644 --- a/pumpkin-world/src/generation/feature/features/tree/foliage/blob.rs +++ b/pumpkin-world/src/generation/feature/features/tree/foliage/blob.rs @@ -38,7 +38,7 @@ impl BlobFoliagePlacer { } } - pub fn get_random_height(&self, _random: &mut RandomGenerator) -> i32 { + pub const fn get_random_height(&self, _random: &mut RandomGenerator) -> i32 { self.height } } diff --git a/pumpkin-world/src/generation/feature/features/tree/foliage/bush.rs b/pumpkin-world/src/generation/feature/features/tree/foliage/bush.rs index c60649b43..f82e23689 100644 --- a/pumpkin-world/src/generation/feature/features/tree/foliage/bush.rs +++ b/pumpkin-world/src/generation/feature/features/tree/foliage/bush.rs @@ -38,7 +38,7 @@ impl BushFoliagePlacer { } } - pub fn get_random_height(&self, _random: &mut RandomGenerator) -> i32 { + pub const fn get_random_height(&self, _random: &mut RandomGenerator) -> i32 { self.height } } diff --git a/pumpkin-world/src/generation/feature/features/tree/foliage/dark_oak.rs b/pumpkin-world/src/generation/feature/features/tree/foliage/dark_oak.rs index 16684df97..56f0c7d8e 100644 --- a/pumpkin-world/src/generation/feature/features/tree/foliage/dark_oak.rs +++ b/pumpkin-world/src/generation/feature/features/tree/foliage/dark_oak.rs @@ -90,7 +90,7 @@ impl DarkOakFoliagePlacer { } } - pub fn get_random_height(&self, _random: &mut RandomGenerator) -> i32 { + pub const fn get_random_height(&self, _random: &mut RandomGenerator) -> i32 { 4 } } diff --git a/pumpkin-world/src/generation/feature/features/tree/foliage/fancy.rs b/pumpkin-world/src/generation/feature/features/tree/foliage/fancy.rs index 6a2775076..b95583bde 100644 --- a/pumpkin-world/src/generation/feature/features/tree/foliage/fancy.rs +++ b/pumpkin-world/src/generation/feature/features/tree/foliage/fancy.rs @@ -24,12 +24,7 @@ impl LargeOakFoliagePlacer { foliage_provider: &BlockState, ) { for y in (offset - foliage_height..=offset).rev() { - let radius = radius - + if y == offset || y == offset - foliage_height { - 0 - } else { - 1 - }; + let radius = radius + i32::from(!(y == offset || y == offset - foliage_height)); FoliagePlacer::generate_square( self, chunk, @@ -43,7 +38,7 @@ impl LargeOakFoliagePlacer { } } - pub fn get_random_height(&self, _random: &mut RandomGenerator) -> i32 { + pub const fn get_random_height(&self, _random: &mut RandomGenerator) -> i32 { self.height } } diff --git a/pumpkin-world/src/generation/feature/features/tree/foliage/jungle.rs b/pumpkin-world/src/generation/feature/features/tree/foliage/jungle.rs index b288332e2..9154c1894 100644 --- a/pumpkin-world/src/generation/feature/features/tree/foliage/jungle.rs +++ b/pumpkin-world/src/generation/feature/features/tree/foliage/jungle.rs @@ -42,7 +42,11 @@ impl JungleFoliagePlacer { ); } } - pub fn get_random_height(&self, _random: &mut RandomGenerator, _trunk_height: i32) -> i32 { + pub const fn get_random_height( + &self, + _random: &mut RandomGenerator, + _trunk_height: i32, + ) -> i32 { self.height } } diff --git a/pumpkin-world/src/generation/feature/features/tree/foliage/mod.rs b/pumpkin-world/src/generation/feature/features/tree/foliage/mod.rs index 2ff359d8e..a6750487e 100644 --- a/pumpkin-world/src/generation/feature/features/tree/foliage/mod.rs +++ b/pumpkin-world/src/generation/feature/features/tree/foliage/mod.rs @@ -85,7 +85,7 @@ impl FoliagePlacer { giant_trunk: bool, foliage_provider: &BlockState, ) { - let i = if giant_trunk { 1 } else { 0 }; + let i = i32::from(giant_trunk); for x in -radius..=(radius + i) { for z in -radius..=(radius + i) { @@ -179,7 +179,7 @@ impl FoliageType { foliage_provider: &BlockState, ) { match self { - FoliageType::Blob(blob) => blob.generate( + Self::Blob(blob) => blob.generate( chunk, random, node, @@ -188,7 +188,7 @@ impl FoliageType { offset, foliage_provider, ), - FoliageType::Spruce(spruce) => spruce.generate( + Self::Spruce(spruce) => spruce.generate( chunk, random, node, @@ -197,7 +197,7 @@ impl FoliageType { offset, foliage_provider, ), - FoliageType::Pine(pine) => pine.generate( + Self::Pine(pine) => pine.generate( chunk, random, node, @@ -206,7 +206,7 @@ impl FoliageType { offset, foliage_provider, ), - FoliageType::Acacia(acacia) => acacia.generate( + Self::Acacia(acacia) => acacia.generate( chunk, random, node, @@ -215,7 +215,7 @@ impl FoliageType { offset, foliage_provider, ), - FoliageType::Bush(bush) => bush.generate( + Self::Bush(bush) => bush.generate( chunk, random, node, @@ -224,7 +224,7 @@ impl FoliageType { offset, foliage_provider, ), - FoliageType::Fancy(fancy) => fancy.generate( + Self::Fancy(fancy) => fancy.generate( chunk, random, node, @@ -233,7 +233,7 @@ impl FoliageType { offset, foliage_provider, ), - FoliageType::Jungle(jungle) => jungle.generate( + Self::Jungle(jungle) => jungle.generate( chunk, random, node, @@ -242,7 +242,7 @@ impl FoliageType { offset, foliage_provider, ), - FoliageType::MegaPine(mega_pine) => mega_pine.generate( + Self::MegaPine(mega_pine) => mega_pine.generate( chunk, random, node, @@ -251,7 +251,7 @@ impl FoliageType { offset, foliage_provider, ), - FoliageType::DarkOak(dark_oak) => dark_oak.generate( + Self::DarkOak(dark_oak) => dark_oak.generate( chunk, random, node, @@ -260,7 +260,7 @@ impl FoliageType { offset, foliage_provider, ), - FoliageType::RandomSpread(random_spread) => random_spread.generate( + Self::RandomSpread(random_spread) => random_spread.generate( chunk, random, node, @@ -269,7 +269,7 @@ impl FoliageType { offset, foliage_provider, ), - FoliageType::Cherry(cherry) => cherry.generate( + Self::Cherry(cherry) => cherry.generate( chunk, random, node, @@ -283,19 +283,19 @@ impl FoliageType { pub fn get_random_height(&self, random: &mut RandomGenerator, trunk_height: i32) -> i32 { match self { - FoliageType::Blob(blob) => blob.get_random_height(random), - FoliageType::Spruce(spruce) => spruce.get_random_height(random, trunk_height), - FoliageType::Pine(pine) => pine.get_random_height(random, trunk_height), - FoliageType::Acacia(acacia) => acacia.get_random_height(random), - FoliageType::Bush(bush) => bush.get_random_height(random), - FoliageType::Fancy(fancy) => fancy.get_random_height(random), - FoliageType::Jungle(jungle) => jungle.get_random_height(random, trunk_height), - FoliageType::MegaPine(mega_pine) => mega_pine.get_random_height(random, trunk_height), - FoliageType::DarkOak(dark_oak) => dark_oak.get_random_height(random), - FoliageType::RandomSpread(random_spread) => { + Self::Blob(blob) => blob.get_random_height(random), + Self::Spruce(spruce) => spruce.get_random_height(random, trunk_height), + Self::Pine(pine) => pine.get_random_height(random, trunk_height), + Self::Acacia(acacia) => acacia.get_random_height(random), + Self::Bush(bush) => bush.get_random_height(random), + Self::Fancy(fancy) => fancy.get_random_height(random), + Self::Jungle(jungle) => jungle.get_random_height(random, trunk_height), + Self::MegaPine(mega_pine) => mega_pine.get_random_height(random, trunk_height), + Self::DarkOak(dark_oak) => dark_oak.get_random_height(random), + Self::RandomSpread(random_spread) => { random_spread.get_random_height(random, trunk_height) } - FoliageType::Cherry(cherry) => cherry.get_random_height(random), + Self::Cherry(cherry) => cherry.get_random_height(random), } } } diff --git a/pumpkin-world/src/generation/feature/features/tree/trunk/fancy.rs b/pumpkin-world/src/generation/feature/features/tree/trunk/fancy.rs index 42ef1b799..36fce2207 100644 --- a/pumpkin-world/src/generation/feature/features/tree/trunk/fancy.rs +++ b/pumpkin-world/src/generation/feature/features/tree/trunk/fancy.rs @@ -245,8 +245,8 @@ pub struct BranchPosition { } impl BranchPosition { - pub fn new(pos: BlockPos, end_y: i32) -> Self { - BranchPosition { + pub const fn new(pos: BlockPos, end_y: i32) -> Self { + Self { node: TreeNode { center: pos, foliage_radius: 0, @@ -256,7 +256,7 @@ impl BranchPosition { } } - pub fn get_end_y(&self) -> i32 { + pub const fn get_end_y(&self) -> i32 { self.end_y } } diff --git a/pumpkin-world/src/generation/feature/features/tree/trunk/mod.rs b/pumpkin-world/src/generation/feature/features/tree/trunk/mod.rs index 73f70e468..8ce3ee867 100644 --- a/pumpkin-world/src/generation/feature/features/tree/trunk/mod.rs +++ b/pumpkin-world/src/generation/feature/features/tree/trunk/mod.rs @@ -156,8 +156,8 @@ impl TrunkType { dirt_state, trunk_state, ), - TrunkType::Forking(_) => (vec![], vec![]), // TODO - TrunkType::Giant(_) => GiantTrunkPlacer::generate( + Self::Forking(_) => (vec![], vec![]), // TODO + Self::Giant(_) => GiantTrunkPlacer::generate( placer, height, start_pos, @@ -167,7 +167,7 @@ impl TrunkType { dirt_state, trunk_state, ), - TrunkType::MegaJungle(_) => MegaJungleTrunkPlacer::generate( + Self::MegaJungle(_) => MegaJungleTrunkPlacer::generate( placer, height, start_pos, @@ -177,7 +177,7 @@ impl TrunkType { dirt_state, trunk_state, ), - TrunkType::DarkOak(_) => DarkOakTrunkPlacer::generate( + Self::DarkOak(_) => DarkOakTrunkPlacer::generate( placer, height, start_pos, @@ -187,7 +187,7 @@ impl TrunkType { dirt_state, trunk_state, ), - TrunkType::Fancy(_) => FancyTrunkPlacer::generate( + Self::Fancy(_) => FancyTrunkPlacer::generate( placer, height, start_pos, @@ -197,7 +197,7 @@ impl TrunkType { dirt_state, trunk_state, ), - TrunkType::Bending(bending) => bending.generate( + Self::Bending(bending) => bending.generate( placer, height, start_pos, @@ -207,8 +207,8 @@ impl TrunkType { dirt_state, trunk_state, ), - TrunkType::UpwardsBranching(_) => (vec![], vec![]), // TODO - TrunkType::Cherry(_) => (vec![], vec![]), // TODO + Self::UpwardsBranching(_) => (vec![], vec![]), // TODO + Self::Cherry(_) => (vec![], vec![]), // TODO } } } diff --git a/pumpkin-world/src/generation/feature/placed_features.rs b/pumpkin-world/src/generation/feature/placed_features.rs index 705e83f9b..92fffb4e6 100644 --- a/pumpkin-world/src/generation/feature/placed_features.rs +++ b/pumpkin-world/src/generation/feature/placed_features.rs @@ -4,7 +4,6 @@ use pumpkin_util::{HeightMap, include_json_static}; use serde::Deserialize; use std::collections::HashMap; use std::iter; -use std::ops::Deref; use std::sync::LazyLock; use pumpkin_util::biome::FOLIAGE_NOISE; @@ -162,41 +161,31 @@ impl PlacementModifier { pos: BlockPos, ) -> Box> { match self { - PlacementModifier::BlockPredicateFilter(modifier) => { + Self::BlockPredicateFilter(modifier) => { modifier.get_positions(block_registry, chunk, feature, random, pos) } - PlacementModifier::RarityFilter(modifier) => { + Self::RarityFilter(modifier) => { modifier.get_positions(block_registry, chunk, feature, random, pos) } - PlacementModifier::SurfaceRelativeThresholdFilter(modifier) => { + Self::SurfaceRelativeThresholdFilter(modifier) => { modifier.get_positions(block_registry, chunk, feature, random, pos) } - PlacementModifier::SurfaceWaterDepthFilter(modifier) => { + Self::SurfaceWaterDepthFilter(modifier) => { modifier.get_positions(block_registry, chunk, feature, random, pos) } - PlacementModifier::Biome(modifier) => { + Self::Biome(modifier) => { modifier.get_positions(block_registry, chunk, feature, random, pos) } - PlacementModifier::Count(modifier) => modifier.get_positions(random, pos), - PlacementModifier::NoiseBasedCount(modifier) => { - Box::new(modifier.get_positions(random, pos)) - } - PlacementModifier::NoiseThresholdCount(modifier) => modifier.get_positions(random, pos), - PlacementModifier::CountOnEveryLayer(modifier) => { - modifier.get_positions(random, chunk, pos) - } - PlacementModifier::EnvironmentScan(modifier) => { - modifier.get_positions(chunk, block_registry, pos) - } - PlacementModifier::Heightmap(modifier) => { - modifier.get_positions(chunk, min_y, height, random, pos) - } - PlacementModifier::HeightRange(modifier) => { - modifier.get_positions(min_y, height, random, pos) - } - PlacementModifier::InSquare(_) => SquarePlacementModifier::get_positions(random, pos), - PlacementModifier::RandomOffset(modifier) => modifier.get_positions(random, pos), - PlacementModifier::FixedPlacement => Box::new(iter::empty()), + Self::Count(modifier) => modifier.get_positions(random, pos), + Self::NoiseBasedCount(modifier) => Box::new(modifier.get_positions(random, pos)), + Self::NoiseThresholdCount(modifier) => modifier.get_positions(random, pos), + Self::CountOnEveryLayer(modifier) => modifier.get_positions(random, chunk, pos), + Self::EnvironmentScan(modifier) => modifier.get_positions(chunk, block_registry, pos), + Self::Heightmap(modifier) => modifier.get_positions(chunk, min_y, height, random, pos), + Self::HeightRange(modifier) => modifier.get_positions(min_y, height, random, pos), + Self::InSquare(_) => SquarePlacementModifier::get_positions(random, pos), + Self::RandomOffset(modifier) => modifier.get_positions(random, pos), + Self::FixedPlacement => Box::new(iter::empty()), } } } @@ -493,7 +482,7 @@ impl ConditionalPlacementModifier for BiomePlacementModifier { let biome = chunk.get_biome_for_terrain_gen(pos.0.x, pos.0.y, pos.0.z); for feature in biome.features { - if feature.contains(&name.deref()) { + if feature.contains(&&*name) { return true; } } diff --git a/pumpkin-world/src/generation/feature/size.rs b/pumpkin-world/src/generation/feature/size.rs index 52d6d9dbc..879aebd04 100644 --- a/pumpkin-world/src/generation/feature/size.rs +++ b/pumpkin-world/src/generation/feature/size.rs @@ -17,10 +17,10 @@ pub enum FeatureSizeType { } impl FeatureSizeType { - pub fn get_radius(&self, height: u32, y: i32) -> i32 { + pub const fn get_radius(&self, height: u32, y: i32) -> i32 { match self { - FeatureSizeType::ThreeLayersFeatureSize(three) => three.get_radius(height, y), - FeatureSizeType::TwoLayersFeatureSize(two) => two.get_radius(y), + Self::ThreeLayersFeatureSize(three) => three.get_radius(height, y), + Self::TwoLayersFeatureSize(two) => two.get_radius(y), } } } @@ -33,7 +33,7 @@ pub struct TwoLayersFeatureSize { } impl TwoLayersFeatureSize { - pub fn get_radius(&self, y: i32) -> i32 { + pub const fn get_radius(&self, y: i32) -> i32 { if y < self.limit as i32 { self.lower_size as i32 } else { @@ -52,7 +52,7 @@ pub struct ThreeLayersFeatureSize { } impl ThreeLayersFeatureSize { - pub fn get_radius(&self, height: u32, y: i32) -> i32 { + pub const fn get_radius(&self, height: u32, y: i32) -> i32 { if y < self.limit as i32 { self.lower_size as i32 } else if y >= height as i32 - self.upper_limit as i32 { diff --git a/pumpkin-world/src/generation/height_provider.rs b/pumpkin-world/src/generation/height_provider.rs index 2fb0c53c0..329cffe19 100644 --- a/pumpkin-world/src/generation/height_provider.rs +++ b/pumpkin-world/src/generation/height_provider.rs @@ -19,9 +19,9 @@ pub enum HeightProvider { impl HeightProvider { pub fn get(&self, random: &mut RandomGenerator, min_y: i8, height: u16) -> i32 { match self { - HeightProvider::Uniform(provider) => provider.get(random, min_y, height), - HeightProvider::Trapezoid(provider) => provider.get(random, min_y, height), - HeightProvider::VeryBiasedToBottom(provider) => provider.get(random, min_y, height), + Self::Uniform(provider) => provider.get(random, min_y, height), + Self::Trapezoid(provider) => provider.get(random, min_y, height), + Self::VeryBiasedToBottom(provider) => provider.get(random, min_y, height), } } } @@ -37,7 +37,7 @@ impl VeryBiasedToBottomHeightProvider { pub fn get(&self, random: &mut RandomGenerator, min_y: i8, height: u16) -> i32 { let min = self.min_inclusive.get_y(min_y as i16, height); let max = self.max_inclusive.get_y(min_y as i16, height); - let inner = self.inner.map(|i| i.get()).unwrap_or(1) as i32; + let inner = self.inner.map_or(1, std::num::NonZero::get) as i32; let min_rnd = random.next_inbetween_i32(min + inner, max); let max_rnd = random.next_inbetween_i32(min, min_rnd - 1); diff --git a/pumpkin-world/src/generation/mod.rs b/pumpkin-world/src/generation/mod.rs index 09cc4e200..119329814 100644 --- a/pumpkin-world/src/generation/mod.rs +++ b/pumpkin-world/src/generation/mod.rs @@ -30,6 +30,7 @@ use pumpkin_util::{ world_seed::Seed, }; +#[must_use] pub fn get_world_gen(seed: Seed, dimension: Dimension) -> Box { // TODO decide which WorldGenerator to pick based on config. Box::new(VanillaGenerator::new(seed, dimension)) @@ -43,6 +44,7 @@ pub struct GlobalRandomConfig { } impl GlobalRandomConfig { + #[must_use] pub fn new(seed: u64, legacy: bool) -> Self { let random_deriver = if legacy { LegacyRand::from_seed(seed).next_splitter() @@ -62,7 +64,8 @@ impl GlobalRandomConfig { } } - pub fn seed(&self) -> u64 { + #[must_use] + pub const fn seed(&self) -> u64 { self.seed } } @@ -75,6 +78,7 @@ pub mod section_coords { coord >> 4 } + #[must_use] pub fn get_offset_pos(chunk_coord: i32, offset: i32) -> i32 { section_to_block(chunk_coord) + offset } @@ -109,7 +113,7 @@ pub mod biome_coords { } } -#[derive(PartialEq)] +#[derive(PartialEq, Eq)] pub enum Direction { North, NorthEast, diff --git a/pumpkin-world/src/generation/noise/aquifer_sampler.rs b/pumpkin-world/src/generation/noise/aquifer_sampler.rs index b9bad9e9f..af1ad111e 100644 --- a/pumpkin-world/src/generation/noise/aquifer_sampler.rs +++ b/pumpkin-world/src/generation/noise/aquifer_sampler.rs @@ -27,15 +27,17 @@ pub struct FluidLevel { } impl FluidLevel { - pub fn new(max_y: i32, block: &'static Block) -> Self { + #[must_use] + pub const fn new(max_y: i32, block: &'static Block) -> Self { Self { max_y, block } } - pub fn max_y_exclusive(&self) -> i32 { + #[must_use] + pub const fn max_y_exclusive(&self) -> i32 { self.max_y } - fn get_block(&self, y: i32) -> &'static Block { + const fn get_block(&self, y: i32) -> &'static Block { if y < self.max_y { self.block } else { @@ -53,8 +55,8 @@ pub enum FluidLevelSampler { impl FluidLevelSamplerImpl for FluidLevelSampler { fn get_fluid_level(&self, x: i32, y: i32, z: i32) -> &FluidLevel { match self { - FluidLevelSampler::Static(sampler) => sampler.get_fluid_level(x, y, z), - FluidLevelSampler::Chunk(sampler) => sampler.get_fluid_level(x, y, z), + Self::Static(sampler) => sampler.get_fluid_level(x, y, z), + Self::Chunk(sampler) => sampler.get_fluid_level(x, y, z), } } } @@ -64,7 +66,8 @@ pub struct StaticFluidLevelSampler { } impl StaticFluidLevelSampler { - pub fn new(y: i32, block: &'static Block) -> Self { + #[must_use] + pub const fn new(y: i32, block: &'static Block) -> Self { Self { fluid_level: FluidLevel::new(y, block), } @@ -133,6 +136,7 @@ impl WorldAquiferSampler { (1, 1), ]; + #[must_use] pub fn new( chunk_x: i32, chunk_z: i32, @@ -189,7 +193,7 @@ impl WorldAquiferSampler { } } - fn packed_position_index(&self, x: i32, y: i32, z: i32) -> usize { + const fn packed_position_index(&self, x: i32, y: i32, z: i32) -> usize { let local_x = (x - self.start_x) as usize; let local_y = (y - self.start_y) as usize; let local_z = (z - self.start_z) as usize; @@ -365,7 +369,7 @@ impl WorldAquiferSampler { ); FluidLevel::new( p, - WorldAquiferSampler::get_fluid_block_state( + Self::get_fluid_block_state( block_x, block_y, block_z, @@ -649,7 +653,8 @@ pub struct SeaLevelAquiferSampler { } impl SeaLevelAquiferSampler { - pub fn new(level_sampler: FluidLevelSampler) -> Self { + #[must_use] + pub const fn new(level_sampler: FluidLevelSampler) -> Self { Self { level_sampler } } } @@ -762,14 +767,12 @@ mod random_positions_and_hypot { let mut samplers_vec = noise.state_sampler.samplers.into_vec(); let first_sampler = samplers_vec.remove(0); - let sampler = match first_sampler { - BlockStateSampler::Aquifer(a) => a, - _ => panic!("Expected Aquifer"), + let BlockStateSampler::Aquifer(sampler) = first_sampler else { + panic!("Expected Aquifer") }; - let aquifer = match sampler { - AquiferSampler::Aquifer(aquifer) => aquifer, - _ => unreachable!(), + let AquiferSampler::Aquifer(aquifer) = sampler else { + unreachable!() }; let horizontal_cell_count = CHUNK_WIDTH / shape.horizontal_cell_block_count() as usize; @@ -795,7 +798,7 @@ mod random_positions_and_hypot { } #[test] - fn test_get_fluid_block_state() { + fn get_fluid_block_state() { let (_, mut router, _, options) = create_aquifer(&PROTO_ROUTER); let level = FluidLevel::new(0, &WATER_BLOCK); @@ -944,7 +947,7 @@ mod random_positions_and_hypot { } #[test] - fn test_get_noise_based_fluid_level() { + fn get_noise_based_fluid_level() { let (_, mut router, _, options) = create_aquifer(&PROTO_ROUTER); let values = [ @@ -1091,7 +1094,7 @@ mod random_positions_and_hypot { } #[test] - fn test_get_fluid_block_y() { + fn get_fluid_block_y() { let (_, mut router, _, env) = create_aquifer(&PROTO_ROUTER); let level = FluidLevel::new(0, &WATER_BLOCK); let values = [ @@ -1384,7 +1387,7 @@ mod random_positions_and_hypot { } #[test] - fn test_get_fluid_level() { + fn get_fluid_level() { let (aquifer, mut router, mut height_estimator, env) = create_aquifer(&PROTO_ROUTER); let values = [ ((-100, -100, -100), (-32512, LAVA_BLOCK)), @@ -1531,7 +1534,7 @@ mod random_positions_and_hypot { } #[test] - fn test_calculate_density() { + fn calculate_density() { let (_, mut router, _, env) = create_aquifer(&PROTO_ROUTER); let values = [ @@ -1683,7 +1686,8 @@ mod random_positions_and_hypot { } #[test] - fn test_apply() { + #[expect(clippy::large_stack_arrays)] + fn apply() { let (mut aquifer, mut router, mut height_estimator, env) = create_aquifer(&PROTO_ROUTER); let values = [ ((112, -100, 64, 0.037482421875), None), diff --git a/pumpkin-world/src/generation/noise/mod.rs b/pumpkin-world/src/generation/noise/mod.rs index ce14d77f6..046a838a1 100644 --- a/pumpkin-world/src/generation/noise/mod.rs +++ b/pumpkin-world/src/generation/noise/mod.rs @@ -62,7 +62,8 @@ pub struct ChainedBlockStateSampler { } impl ChainedBlockStateSampler { - pub fn new(samplers: Box<[BlockStateSampler]>) -> Self { + #[must_use] + pub const fn new(samplers: Box<[BlockStateSampler]>) -> Self { Self { samplers } } @@ -73,7 +74,7 @@ impl ChainedBlockStateSampler { sample_options: &ChunkNoiseFunctionSampleOptions, height_estimator: &mut SurfaceHeightEstimateSampler, ) -> Option<&'static BlockState> { - for sampler in self.samplers.iter_mut() { + for sampler in &mut self.samplers { if let Some(state) = sampler.sample(router, pos, sample_options, height_estimator) { return Some(state); } @@ -163,6 +164,7 @@ pub struct ChunkNoiseGenerator<'a> { impl<'a> ChunkNoiseGenerator<'a> { #[expect(clippy::too_many_arguments)] + #[must_use] pub fn new( noise_router_base: &'a ProtoNoiseRouter, random_config: &GlobalRandomConfig, @@ -397,23 +399,27 @@ impl<'a> ChunkNoiseGenerator<'a> { } #[inline] + #[must_use] pub fn horizontal_cell_block_count(&self) -> u8 { self.generation_shape.horizontal_cell_block_count() } #[inline] + #[must_use] pub fn vertical_cell_block_count(&self) -> u8 { self.generation_shape.vertical_cell_block_count() } - /// Aka bottom_y + /// Aka `bottom_y` #[inline] - pub fn min_y(&self) -> i8 { + #[must_use] + pub const fn min_y(&self) -> i8 { self.generation_shape.min_y } #[inline] - pub fn height(&self) -> u16 { + #[must_use] + pub const fn height(&self) -> u16 { self.generation_shape.height } } diff --git a/pumpkin-world/src/generation/noise/ore_sampler.rs b/pumpkin-world/src/generation/noise/ore_sampler.rs index 7c41a5c6c..d1e112da3 100644 --- a/pumpkin-world/src/generation/noise/ore_sampler.rs +++ b/pumpkin-world/src/generation/noise/ore_sampler.rs @@ -14,7 +14,8 @@ pub struct OreVeinSampler { } impl OreVeinSampler { - pub fn new(random_deriver: RandomDeriver) -> Self { + #[must_use] + pub const fn new(random_deriver: RandomDeriver) -> Self { Self { random_deriver } } @@ -82,7 +83,7 @@ pub struct VeinType { pub mod vein_type { use pumpkin_data::Block; - use super::*; + use super::VeinType; pub const COPPER: VeinType = VeinType { ore: Block::COPPER_ORE, raw_ore: Block::RAW_COPPER_BLOCK, diff --git a/pumpkin-world/src/generation/noise/perlin.rs b/pumpkin-world/src/generation/noise/perlin.rs index 459a6e094..8e8c3d2d2 100644 --- a/pumpkin-world/src/generation/noise/perlin.rs +++ b/pumpkin-world/src/generation/noise/perlin.rs @@ -13,7 +13,8 @@ impl DoublePerlinNoiseSampler { 0.1f64 * (1f64 + 1f64 / (octaves + 1) as f64) } - pub fn max_value(&self) -> f64 { + #[must_use] + pub const fn max_value(&self) -> f64 { self.max_value } @@ -49,6 +50,7 @@ impl DoublePerlinNoiseSampler { } } + #[must_use] pub fn sample(&self, x: f64, y: f64, z: f64) -> f64 { let d = x * 1.0181268882175227f64; let e = y * 1.0181268882175227f64; @@ -159,7 +161,7 @@ mod double_perlin_noise_sampler_test { ]; for ((x, y, z), sample) in values { - assert_eq!(sampler.sample(x, y, z), sample) + assert_eq!(sampler.sample(x, y, z), sample); } } @@ -258,7 +260,7 @@ mod double_perlin_noise_sampler_test { ]; for ((x, y, z), sample) in values { - assert_eq!(sampler.sample(x, y, z), sample) + assert_eq!(sampler.sample(x, y, z), sample); } } } @@ -270,7 +272,7 @@ mod octave_perline_noise_sampler_test { use super::OctavePerlinNoiseSampler; #[test] - fn test_sample() { + fn sample() { let mut rand = Xoroshiro::from_seed(513513513); assert_eq!(rand.next_i32(), 404174895); @@ -373,7 +375,7 @@ mod perlin_noise_sampler_test { use pumpkin_util::noise::perlin::OctavePerlinNoiseSampler; #[test] - fn test_precision() { + fn precision() { let values = [ 2.5E-4, 1.25E-4, @@ -418,7 +420,7 @@ mod perlin_noise_sampler_test { } #[test] - fn test_calculate_amplitudes() { + fn calculate_amplitudes() { let (first, amplitudes) = OctavePerlinNoiseSampler::calculate_amplitudes(&(-15..=0).collect::>()); diff --git a/pumpkin-world/src/generation/noise/router/chunk_density_function.rs b/pumpkin-world/src/generation/noise/router/chunk_density_function.rs index a02e15640..f847860f2 100644 --- a/pumpkin-world/src/generation/noise/router/chunk_density_function.rs +++ b/pumpkin-world/src/generation/noise/router/chunk_density_function.rs @@ -20,16 +20,17 @@ thread_local! { fn get_buffer(len: usize) -> Box<[f64]> { F64_BUFFER_POOL.with(|pool| { let mut buffers = pool.borrow_mut(); - if let Some(mut buf) = buffers.pop() { - if buf.len() != len { - buf.resize(len, 0.0); - } else { - buf.fill(0.0); - } - buf.into_boxed_slice() - } else { - vec![0.0; len].into_boxed_slice() - } + buffers.pop().map_or_else( + || vec![0.0; len].into_boxed_slice(), + |mut buf| { + if buf.len() == len { + buf.fill(0.0); + } else { + buf.resize(len, 0.0); + } + buf.into_boxed_slice() + }, + ) }) } @@ -56,6 +57,7 @@ pub struct WrapperData { } impl WrapperData { + #[must_use] pub fn new( cell_x_block_position: usize, cell_y_block_position: usize, @@ -116,6 +118,7 @@ pub struct ChunkNoiseFunctionSampleOptions { } impl ChunkNoiseFunctionSampleOptions { + #[must_use] pub const fn new( populating_caches: bool, action: SampleAction, @@ -151,6 +154,7 @@ pub struct ChunkNoiseFunctionBuilderOptions { } impl ChunkNoiseFunctionBuilderOptions { + #[must_use] pub const fn new( horizontal_cell_block_count: usize, vertical_cell_block_count: usize, @@ -205,6 +209,7 @@ impl NoiseFunctionComponentRange for DensityInterpolator { } impl DensityInterpolator { + #[must_use] pub fn new( input_index: usize, min_value: f64, @@ -233,7 +238,11 @@ impl DensityInterpolator { } #[inline] - pub(crate) fn yz_to_buf_index(&self, cell_y_position: usize, cell_z_position: usize) -> usize { + pub(crate) const fn yz_to_buf_index( + &self, + cell_y_position: usize, + cell_z_position: usize, + ) -> usize { cell_z_position * (self.vertical_cell_count + 1) + cell_y_position } @@ -432,6 +441,7 @@ impl Drop for FlatCache { } impl FlatCache { + #[must_use] pub fn new( input_index: usize, min_value: f64, @@ -452,7 +462,12 @@ impl FlatCache { } #[inline] - pub fn xz_to_index_const(&self, biome_x_position: usize, biome_z_position: usize) -> usize { + #[must_use] + pub const fn xz_to_index_const( + &self, + biome_x_position: usize, + biome_z_position: usize, + ) -> usize { biome_x_position * (self.horizontal_biome_end + 1) + biome_z_position } } @@ -504,6 +519,7 @@ impl MutableChunkNoiseFunctionComponentImpl for Cache2D { } impl Cache2D { + #[must_use] pub fn new(input_index: usize, min_value: f64, max_value: f64) -> Self { Self { input_index, @@ -608,6 +624,7 @@ impl MutableChunkNoiseFunctionComponentImpl for CacheOnce { } impl CacheOnce { + #[must_use] pub fn new(input_index: usize, min_value: f64, max_value: f64) -> Self { Self { input_index, @@ -676,6 +693,7 @@ impl MutableChunkNoiseFunctionComponentImpl for CellCache { } impl CellCache { + #[must_use] pub fn new( input_index: usize, min_value: f64, diff --git a/pumpkin-world/src/generation/noise/router/chunk_noise_router.rs b/pumpkin-world/src/generation/noise/router/chunk_noise_router.rs index ead45c96f..0e19c72fa 100644 --- a/pumpkin-world/src/generation/noise/router/chunk_noise_router.rs +++ b/pumpkin-world/src/generation/noise/router/chunk_noise_router.rs @@ -216,7 +216,7 @@ impl MutableChunkNoiseFunctionComponentImpl for ChunkNoiseFunctionComponent<'_> match self { Self::Independent(independent) => independent.fill(array, mapper), Self::Dependent(dependent) => { - dependent.fill(component_stack, array, mapper, sample_options) + dependent.fill(component_stack, array, mapper, sample_options); } Self::Chunk(chunk) => chunk.fill(component_stack, array, mapper, sample_options), Self::PassThrough(pass_through) => ChunkNoiseFunctionComponent::fill_from_stack( @@ -328,6 +328,7 @@ impl ChunkNoiseRouter<'_> { } impl<'a> ChunkNoiseRouter<'a> { + #[must_use] pub fn generate( base: &'a ProtoNoiseRouter, build_options: &ChunkNoiseFunctionBuilderOptions, diff --git a/pumpkin-world/src/generation/noise/router/density_function/math.rs b/pumpkin-world/src/generation/noise/router/density_function/math.rs index 49aacc165..2ce53a8aa 100644 --- a/pumpkin-world/src/generation/noise/router/density_function/math.rs +++ b/pumpkin-world/src/generation/noise/router/density_function/math.rs @@ -16,7 +16,7 @@ pub struct Constant { } impl Constant { - pub fn new(value: f64) -> Self { + pub const fn new(value: f64) -> Self { Self { value } } } @@ -80,7 +80,7 @@ impl StaticChunkNoiseFunctionComponentImpl for Linear { } impl Linear { - pub fn new( + pub const fn new( input_index: usize, min_value: f64, max_value: f64, @@ -255,7 +255,7 @@ impl StaticChunkNoiseFunctionComponentImpl for Binary { } impl Binary { - pub fn new( + pub const fn new( input1_index: usize, input2_index: usize, min_value: f64, @@ -320,14 +320,14 @@ impl StaticChunkNoiseFunctionComponentImpl for Unary { mapper, sample_options, ); - array.iter_mut().for_each(|value| { + for value in array.iter_mut() { *value = self.data.apply_density(*value); - }); + } } } impl Unary { - pub fn new( + pub const fn new( input_index: usize, min_value: f64, max_value: f64, @@ -349,7 +349,7 @@ pub struct Clamp { } impl Clamp { - pub fn new(input_index: usize, data: &'static ClampData) -> Self { + pub const fn new(input_index: usize, data: &'static ClampData) -> Self { Self { input_index, data } } } diff --git a/pumpkin-world/src/generation/noise/router/density_function/misc.rs b/pumpkin-world/src/generation/noise/router/density_function/misc.rs index 29c4a8f8c..db0c101dc 100644 --- a/pumpkin-world/src/generation/noise/router/density_function/misc.rs +++ b/pumpkin-world/src/generation/noise/router/density_function/misc.rs @@ -92,7 +92,7 @@ pub struct WeirdScaled { } impl WeirdScaled { - pub fn new( + pub const fn new( input_index: usize, sampler: DoublePerlinNoiseSampler, data: &WeirdScaledData, @@ -177,7 +177,7 @@ pub struct ClampedYGradient { } impl ClampedYGradient { - pub fn new(data: &'static ClampedYGradientData) -> Self { + pub const fn new(data: &'static ClampedYGradientData) -> Self { Self { data } } } @@ -217,7 +217,7 @@ pub struct RangeChoice { } impl RangeChoice { - pub fn new( + pub const fn new( input_index: usize, when_in_index: usize, when_out_index: usize, @@ -229,9 +229,9 @@ impl RangeChoice { input_index, when_in_index, when_out_index, + data, min_value, max_value, - data, } } } diff --git a/pumpkin-world/src/generation/noise/router/density_function/mod.rs b/pumpkin-world/src/generation/noise/router/density_function/mod.rs index 3ad8bc681..51b00d5ac 100644 --- a/pumpkin-world/src/generation/noise/router/density_function/mod.rs +++ b/pumpkin-world/src/generation/noise/router/density_function/mod.rs @@ -31,7 +31,8 @@ pub struct UnblendedNoisePos { } impl UnblendedNoisePos { - pub fn new(x: i32, y: i32, z: i32) -> Self { + #[must_use] + pub const fn new(x: i32, y: i32, z: i32) -> Self { Self { x, y, z } } } @@ -87,6 +88,7 @@ pub struct Wrapper { } impl Wrapper { + #[must_use] pub const fn new( input_index: usize, wrapper_type: WrapperType, @@ -122,7 +124,8 @@ pub struct PassThrough { } impl PassThrough { - pub fn new(input_index: usize, min_value: f64, max_value: f64) -> Self { + #[must_use] + pub const fn new(input_index: usize, min_value: f64, max_value: f64) -> Self { Self { input_index, min_value, @@ -130,7 +133,8 @@ impl PassThrough { } } - pub fn input_index(&self) -> usize { + #[must_use] + pub const fn input_index(&self) -> usize { self.input_index } } diff --git a/pumpkin-world/src/generation/noise/router/density_function/noise.rs b/pumpkin-world/src/generation/noise/router/density_function/noise.rs index 8bcff7f30..043794669 100644 --- a/pumpkin-world/src/generation/noise/router/density_function/noise.rs +++ b/pumpkin-world/src/generation/noise/router/density_function/noise.rs @@ -23,7 +23,7 @@ pub struct Noise { } impl Noise { - pub fn new(sampler: DoublePerlinNoiseSampler, data: &'static NoiseData) -> Self { + pub const fn new(sampler: DoublePerlinNoiseSampler, data: &'static NoiseData) -> Self { Self { sampler, data } } } @@ -60,7 +60,7 @@ pub struct ShiftA { } impl ShiftA { - pub fn new(sampler: DoublePerlinNoiseSampler) -> Self { + pub const fn new(sampler: DoublePerlinNoiseSampler) -> Self { Self { sampler } } } @@ -88,7 +88,7 @@ pub struct ShiftB { } impl ShiftB { - pub fn new(sampler: DoublePerlinNoiseSampler) -> Self { + pub const fn new(sampler: DoublePerlinNoiseSampler) -> Self { Self { sampler } } } @@ -163,7 +163,7 @@ impl StaticChunkNoiseFunctionComponentImpl for ShiftedNoise { } impl ShiftedNoise { - pub fn new( + pub const fn new( input_x_index: usize, input_y_index: usize, input_z_index: usize, @@ -269,11 +269,13 @@ impl StaticIndependentChunkNoiseFunctionComponentImpl for InterpolatedNoiseSampl }) .sum(); - let q = (n / 10f64 + 1f64) / 2f64; + let q = f64::midpoint(n / 10f64, 1f64); let bl2 = q >= 1f64; let bl3 = q <= 0f64; - let l = if !bl2 { + let l = if bl2 { + 0.0 + } else { self.lower_noise .samplers .iter() @@ -293,11 +295,11 @@ impl StaticIndependentChunkNoiseFunctionComponentImpl for InterpolatedNoiseSampl ) / fraction }) .sum() - } else { - 0.0 }; - let m = if !bl3 { + let m = if bl3 { + 0.0 + } else { self.upper_noise .samplers .iter() @@ -317,8 +319,6 @@ impl StaticIndependentChunkNoiseFunctionComponentImpl for InterpolatedNoiseSampl ) / fraction }) .sum() - } else { - 0.0 }; clamped_lerp(l / 512f64, m / 512f64, q) / 128f64 diff --git a/pumpkin-world/src/generation/noise/router/density_function/spline.rs b/pumpkin-world/src/generation/noise/router/density_function/spline.rs index af843175c..2150f1079 100644 --- a/pumpkin-world/src/generation/noise/router/density_function/spline.rs +++ b/pumpkin-world/src/generation/noise/router/density_function/spline.rs @@ -45,7 +45,7 @@ pub struct SplinePoint { } impl SplinePoint { - pub fn new(location: f32, value: SplineValue, derivative: f32) -> Self { + pub const fn new(location: f32, value: SplineValue, derivative: f32) -> Self { Self { location, value, @@ -74,7 +74,7 @@ pub struct Spline { } impl Spline { - pub fn new(input_index: usize, points: Box<[SplinePoint]>) -> Self { + pub const fn new(input_index: usize, points: Box<[SplinePoint]>) -> Self { Self { input_index, points, diff --git a/pumpkin-world/src/generation/noise/router/density_function/test.rs b/pumpkin-world/src/generation/noise/router/density_function/test.rs index dd9c8946e..1778f465b 100644 --- a/pumpkin-world/src/generation/noise/router/density_function/test.rs +++ b/pumpkin-world/src/generation/noise/router/density_function/test.rs @@ -130,7 +130,7 @@ macro_rules! sample_surface_router_function { // // This is equivalent to a Java `NoiseRouter` after being passed into `NoiseConfig` but before being // passed into `ChunkNoiseGenerator` -fn test_normal_surface_noisified() { +fn normal_surface_noisified() { let pos = TestNoisePos { x: 0, y: 0, z: 0 }; // TODO: Move these values to a file and create an extractor for them assert_eq!( @@ -577,7 +577,7 @@ fn test_normal_surface_noisified() { } #[test] -fn test_config_final_density() { +fn config_final_density() { let expected_data: Vec<(i32, i32, i32, f64)> = read_data_from_file!("../../../../../assets/final_density_dump_7_4.json"); @@ -650,7 +650,7 @@ static DENSITY_FUNCTION_REPRS: LazyLock = LazyLock::new(|| }); #[test] -fn test_base_sloped_cheese() { +fn base_sloped_cheese() { let base_stack = DENSITY_FUNCTION_REPRS.sloped_cheese.base_component_stack(); let proto_stack = ProtoNoiseRouters::generate_proto_stack(&base_stack, &RANDOM_CONFIG); let mut stack = build_function_stack!(proto_stack); @@ -669,7 +669,7 @@ fn test_base_sloped_cheese() { } #[test] -fn test_base_factor() { +fn base_factor() { let base_stack = DENSITY_FUNCTION_REPRS.factor.base_component_stack(); let proto_stack = ProtoNoiseRouters::generate_proto_stack(&base_stack, &RANDOM_CONFIG); let mut stack = build_function_stack!(proto_stack); @@ -688,7 +688,7 @@ fn test_base_factor() { } #[test] -fn test_base_depth() { +fn base_depth() { let base_stack = DENSITY_FUNCTION_REPRS.depth.base_component_stack(); let proto_stack = ProtoNoiseRouters::generate_proto_stack(&base_stack, &RANDOM_CONFIG); let mut function_stack = build_function_stack!(proto_stack); @@ -707,7 +707,7 @@ fn test_base_depth() { } #[test] -fn test_base_offset() { +fn base_offset() { let base_stack = DENSITY_FUNCTION_REPRS.offset.base_component_stack(); let proto_stack = ProtoNoiseRouters::generate_proto_stack(&base_stack, &RANDOM_CONFIG); let mut function_stack = build_function_stack!(proto_stack); @@ -726,7 +726,7 @@ fn test_base_offset() { } #[test] -fn test_base_cave_entrances() { +fn base_cave_entrances() { let base_stack = DENSITY_FUNCTION_REPRS.cave_entrances.base_component_stack(); let proto_stack = ProtoNoiseRouters::generate_proto_stack(&base_stack, &RANDOM_CONFIG); let mut function_stack = build_function_stack!(proto_stack); @@ -745,7 +745,7 @@ fn test_base_cave_entrances() { } #[test] -fn test_base_3d_noise() { +fn base_3d_noise() { let base_stack = DENSITY_FUNCTION_REPRS.base_3d_noise.base_component_stack(); let proto_stack = ProtoNoiseRouters::generate_proto_stack(&base_stack, &RANDOM_CONFIG); let mut function_stack = build_function_stack!(proto_stack); @@ -764,7 +764,7 @@ fn test_base_3d_noise() { } #[test] -fn test_base_spahetti_roughness() { +fn base_spahetti_roughness() { let base_stack = DENSITY_FUNCTION_REPRS .spaghetti_roughness .base_component_stack(); @@ -786,7 +786,7 @@ fn test_base_spahetti_roughness() { } #[test] -fn test_base_cave_noodle() { +fn base_cave_noodle() { let base_stack = DENSITY_FUNCTION_REPRS.cave_noodle.base_component_stack(); let proto_stack = ProtoNoiseRouters::generate_proto_stack(&base_stack, &RANDOM_CONFIG); let mut function_stack = build_function_stack!(proto_stack); @@ -805,7 +805,7 @@ fn test_base_cave_noodle() { } #[test] -fn test_base_cave_pillars() { +fn base_cave_pillars() { let base_stack = DENSITY_FUNCTION_REPRS.cave_pillars.base_component_stack(); let proto_stack = ProtoNoiseRouters::generate_proto_stack(&base_stack, &RANDOM_CONFIG); let mut function_stack = build_function_stack!(proto_stack); @@ -824,7 +824,7 @@ fn test_base_cave_pillars() { } #[test] -fn test_base_spaghetti_2d_thickness() { +fn base_spaghetti_2d_thickness() { let base_stack = DENSITY_FUNCTION_REPRS .spaghetti_2d_thickness .base_component_stack(); diff --git a/pumpkin-world/src/generation/noise/router/density_function/test_deserializer.rs b/pumpkin-world/src/generation/noise/router/density_function/test_deserializer.rs index b4629bd2b..c9958c324 100644 --- a/pumpkin-world/src/generation/noise/router/density_function/test_deserializer.rs +++ b/pumpkin-world/src/generation/noise/router/density_function/test_deserializer.rs @@ -51,7 +51,7 @@ pub enum SplineRepr { #[serde(rename(deserialize = "locationFunction"))] location_function: Box, locations: Box<[HashableF32]>, - values: Box<[SplineRepr]>, + values: Box<[Self]>, derivatives: Box<[HashableF32]>, }, #[serde(rename(deserialize = "fixed"))] @@ -65,7 +65,7 @@ impl SplineRepr { map: &mut HashMap, ) -> &'static noise_router::SplineRepr { let value = match self { - SplineRepr::Standard { + Self::Standard { location_function, locations, values, @@ -90,7 +90,7 @@ impl SplineRepr { points: Box::leak(points), } } - SplineRepr::Fixed { value } => noise_router::SplineRepr::Fixed { value: value.0 }, + Self::Fixed { value } => noise_router::SplineRepr::Fixed { value: value.0 }, }; Box::leak(Box::new(value)) @@ -110,7 +110,7 @@ pub enum BinaryOperation { } impl BinaryOperation { - fn as_base_component(&self) -> noise_router::BinaryOperation { + fn as_base_component(self) -> noise_router::BinaryOperation { match self { Self::Add => noise_router::BinaryOperation::Add, Self::Mul => noise_router::BinaryOperation::Mul, @@ -129,7 +129,7 @@ pub enum LinearOperation { } impl LinearOperation { - fn as_base_component(&self) -> noise_router::LinearOperation { + fn as_base_component(self) -> noise_router::LinearOperation { match self { Self::Add => noise_router::LinearOperation::Add, Self::Mul => noise_router::LinearOperation::Mul, @@ -154,7 +154,7 @@ pub enum UnaryOperation { } impl UnaryOperation { - fn as_base_component(&self) -> noise_router::UnaryOperation { + fn as_base_component(self) -> noise_router::UnaryOperation { match self { Self::Abs => noise_router::UnaryOperation::Abs, Self::Square => noise_router::UnaryOperation::Square, @@ -175,7 +175,7 @@ pub enum WeirdScaledMapper { } impl WeirdScaledMapper { - fn as_base_component(&self) -> noise_router::WeirdScaledMapper { + fn as_base_component(self) -> noise_router::WeirdScaledMapper { match self { Self::Caves => noise_router::WeirdScaledMapper::Caves, Self::Tunnels => noise_router::WeirdScaledMapper::Tunnels, @@ -194,7 +194,7 @@ pub enum WrapperType { } impl WrapperType { - fn as_base_component(&self) -> noise_router::WrapperType { + fn as_base_component(self) -> noise_router::WrapperType { match self { Self::Interpolated => noise_router::WrapperType::Interpolated, Self::CacheFlat => noise_router::WrapperType::CacheFlat, @@ -445,7 +445,7 @@ pub enum DensityFunctionRepr { BlendAlpha, BlendOffset, BlendDensity { - input: Box, + input: Box, }, EndIslands, Noise { @@ -462,11 +462,11 @@ pub enum DensityFunctionRepr { }, ShiftedNoise { #[serde(rename(deserialize = "shiftX"))] - shift_x: Box, + shift_x: Box, #[serde(rename(deserialize = "shiftY"))] - shift_y: Box, + shift_y: Box, #[serde(rename(deserialize = "shiftZ"))] - shift_z: Box, + shift_z: Box, #[serde(flatten)] data: ShiftedNoiseData, }, @@ -476,7 +476,7 @@ pub enum DensityFunctionRepr { }, #[serde(rename(deserialize = "WeirdScaledSampler"))] WeirdScaled { - input: Box, + input: Box, #[serde(flatten)] data: WeirdScaledData, }, @@ -484,7 +484,7 @@ pub enum DensityFunctionRepr { #[serde(rename(deserialize = "Wrapping"))] Wrapper { #[serde(rename(deserialize = "wrapped"))] - input: Box, + input: Box, #[serde(rename(deserialize = "type"))] wrapper: WrapperType, }, @@ -499,34 +499,34 @@ pub enum DensityFunctionRepr { }, #[serde(rename(deserialize = "BinaryOperation"))] Binary { - argument1: Box, - argument2: Box, + argument1: Box, + argument2: Box, #[serde(flatten)] data: BinaryData, }, #[serde(rename(deserialize = "LinearOperation"))] Linear { - input: Box, + input: Box, #[serde(flatten)] data: LinearData, }, #[serde(rename(deserialize = "UnaryOperation"))] Unary { - input: Box, + input: Box, #[serde(flatten)] data: UnaryData, }, Clamp { - input: Box, + input: Box, #[serde(flatten)] data: ClampData, }, RangeChoice { - input: Box, + input: Box, #[serde(rename(deserialize = "whenInRange"))] - when_in_range: Box, + when_in_range: Box, #[serde(rename(deserialize = "whenOutOfRange"))] - when_out_range: Box, + when_out_range: Box, #[serde(flatten)] data: RangeChoiceData, }, @@ -538,6 +538,7 @@ pub enum DensityFunctionRepr { } impl DensityFunctionRepr { + #[expect(clippy::too_many_lines)] fn as_base_component( &self, stack: &mut Vec, @@ -673,7 +674,6 @@ impl DensityFunctionRepr { let mut hasher = DefaultHasher::new(); self.hash(&mut hasher); let hash = hasher.finish(); - if let Some(index) = hash_to_index_map.get(&hash) { *index } else { diff --git a/pumpkin-world/src/generation/noise/router/multi_noise_sampler.rs b/pumpkin-world/src/generation/noise/router/multi_noise_sampler.rs index bef6807a1..fc402115a 100644 --- a/pumpkin-world/src/generation/noise/router/multi_noise_sampler.rs +++ b/pumpkin-world/src/generation/noise/router/multi_noise_sampler.rs @@ -25,7 +25,8 @@ pub struct MultiNoiseSamplerBuilderOptions { } impl MultiNoiseSamplerBuilderOptions { - pub fn new(start_biome_x: i32, start_biome_z: i32, horizontal_biome_end: usize) -> Self { + #[must_use] + pub const fn new(start_biome_x: i32, start_biome_z: i32, horizontal_biome_end: usize) -> Self { Self { start_biome_x, start_biome_z, @@ -113,6 +114,7 @@ impl<'a> MultiNoiseSampler<'a> { ) } + #[must_use] pub fn generate( base: &'a ProtoMultiNoiseRouter, build_options: &MultiNoiseSamplerBuilderOptions, @@ -122,7 +124,7 @@ impl<'a> MultiNoiseSampler<'a> { // (Should we traverse the functions and update the indices?) let mut component_stack = Vec::::with_capacity(base.full_component_stack.len()); - for base_component in base.full_component_stack.iter() { + for base_component in &base.full_component_stack { let chunk_component = match base_component { ProtoNoiseFunctionComponent::Dependent(dependent) => { ChunkNoiseFunctionComponent::Dependent(dependent) @@ -237,7 +239,7 @@ mod test { use super::{MultiNoiseSampler, MultiNoiseSamplerBuilderOptions}; #[test] - fn test_sample() { + fn sample() { let seed = 123; let random_config = GlobalRandomConfig::new(seed, false); let noise_router = @@ -253,11 +255,11 @@ mod test { depth: -19774, weirdness: 4421, }; - assert_eq!(sampler.sample(123, 123, 123), expected) + assert_eq!(sampler.sample(123, 123, 123), expected); } #[test] - fn test_sample_2() { + fn sample_2() { // we use a different seed let seed = 13579; let random_config = GlobalRandomConfig::new(seed, false); @@ -274,6 +276,6 @@ mod test { depth: -21237, weirdness: -5222, }; - assert_eq!(sampler.sample(123, 123, 123), expected) + assert_eq!(sampler.sample(123, 123, 123), expected); } } diff --git a/pumpkin-world/src/generation/noise/router/proto_noise_router.rs b/pumpkin-world/src/generation/noise/router/proto_noise_router.rs index 56c7738c7..689a62e6d 100644 --- a/pumpkin-world/src/generation/noise/router/proto_noise_router.rs +++ b/pumpkin-world/src/generation/noise/router/proto_noise_router.rs @@ -62,12 +62,14 @@ pub struct DoublePerlinNoiseBuilder<'a> { } impl<'a> DoublePerlinNoiseBuilder<'a> { - pub fn new(rand: &'a GlobalRandomConfig) -> Self { + #[must_use] + pub const fn new(rand: &'a GlobalRandomConfig) -> Self { Self { random_config: rand, } } + #[must_use] pub fn get_noise_sampler_for_id(&self, id: &str) -> DoublePerlinNoiseSampler { let parameters = DoublePerlinNoiseParameters::id_to_parameters(id) .unwrap_or_else(|| panic!("Unknown noise id: {id}")); @@ -136,6 +138,7 @@ fn build_spline_recursive(spline_repr: &SplineRepr) -> SplineValue { } impl ProtoNoiseRouters { + #[must_use] pub fn generate_proto_stack( base_stack: &[BaseNoiseFunctionComponent], random_config: &GlobalRandomConfig, @@ -424,6 +427,7 @@ impl ProtoNoiseRouters { stack.into() } + #[must_use] pub fn generate(base: &BaseNoiseRouters, random_config: &GlobalRandomConfig) -> Self { let noise_stack = Self::generate_proto_stack(base.noise.full_component_stack, random_config); diff --git a/pumpkin-world/src/generation/noise/router/surface_height_sampler.rs b/pumpkin-world/src/generation/noise/router/surface_height_sampler.rs index 284a53543..10dbf4748 100644 --- a/pumpkin-world/src/generation/noise/router/surface_height_sampler.rs +++ b/pumpkin-world/src/generation/noise/router/surface_height_sampler.rs @@ -30,7 +30,8 @@ pub struct SurfaceHeightSamplerBuilderOptions { } impl SurfaceHeightSamplerBuilderOptions { - pub fn new( + #[must_use] + pub const fn new( start_biome_x: i32, start_biome_z: i32, horizontal_biome_end: usize, @@ -107,6 +108,7 @@ impl<'a> SurfaceHeightEstimateSampler<'a> { result } + #[must_use] pub fn generate( base: &'a ProtoSurfaceEstimator, build_options: &SurfaceHeightSamplerBuilderOptions, @@ -116,7 +118,7 @@ impl<'a> SurfaceHeightEstimateSampler<'a> { // (Should we traverse the functions and update the indices?) let mut component_stack = Vec::::with_capacity(base.full_component_stack.len()); - for base_component in base.full_component_stack.iter() { + for base_component in &base.full_component_stack { let chunk_component = match base_component { ProtoNoiseFunctionComponent::Dependent(dependent) => { ChunkNoiseFunctionComponent::Dependent(dependent) diff --git a/pumpkin-world/src/generation/positions.rs b/pumpkin-world/src/generation/positions.rs index 97cd356e3..66731bf5b 100644 --- a/pumpkin-world/src/generation/positions.rs +++ b/pumpkin-world/src/generation/positions.rs @@ -6,21 +6,25 @@ pub mod block_pos { }; #[inline] + #[must_use] pub const fn unpack_x(packed: i64) -> i32 { ((packed << (64 - BIT_SHIFT_X - SIZE_BITS_X)) >> (64 - SIZE_BITS_X)) as i32 } #[inline] + #[must_use] pub const fn unpack_y(packed: i64) -> i32 { ((packed << (64 - SIZE_BITS_Y)) >> (64 - SIZE_BITS_Y)) as i32 } #[inline] + #[must_use] pub const fn unpack_z(packed: i64) -> i32 { ((packed << (64 - BIT_SHIFT_Z - SIZE_BITS_Z)) >> (64 - SIZE_BITS_Z)) as i32 } #[inline] + #[must_use] pub const fn packed(x: i64, y: i64, z: i64) -> i64 { let mut result = 0i64; // Need to go to i64 first to conserve sign @@ -39,50 +43,62 @@ pub mod chunk_pos { // A chunk outside of normal bounds pub const MARKER: u64 = packed(1875066, 1875066); + #[must_use] pub const fn packed(x: u64, y: u64) -> u64 { (x & 4294967295u64) | ((y & 4294967295u64) << 32) } + #[must_use] pub const fn unpack_x(packed: u64) -> i32 { (packed & 4294967295u64) as i32 } + #[must_use] pub const fn unpack_z(packed: u64) -> i32 { ((packed >> 32) & 4294967295u64) as i32 } + #[must_use] pub fn get_offset_x(coord: i32, offset: i32) -> i32 { get_offset_pos(coord, offset) } + #[must_use] pub fn get_center_x(coord: i32) -> i32 { get_offset_x(coord, 8) } + #[must_use] pub fn get_center_z(coord: i32) -> i32 { get_offset_z(coord, 8) } + #[must_use] pub fn get_offset_z(coord: i32, offset: i32) -> i32 { get_offset_pos(coord, offset) } + #[must_use] pub const fn start_block_x(x: i32) -> i32 { x << 4 } + #[must_use] pub const fn end_block_x(x: i32) -> i32 { start_block_x(x) + 15 } + #[must_use] pub const fn start_block_z(z: i32) -> i32 { z << 4 } + #[must_use] pub const fn end_block_z(z: i32) -> i32 { start_block_z(z) + 15 } + #[must_use] pub const fn to_chunk_pos(vec: &Vector2) -> Vector2 { Vector2::new(vec.x >> 4, vec.y >> 4) } @@ -108,9 +124,9 @@ mod test { use super::{block_pos, chunk_pos}; #[test] - fn test_chunk_packing() { - let x = 305135135_i32; - let y = -1351513511_i32; + fn chunk_packing() { + let x = 305135135i32; + let y = -1351513511i32; let packed = chunk_pos::packed(x as u64, y as u64); assert_eq!(packed as i64, -5804706329542001121i64); assert_eq!(x, chunk_pos::unpack_x(packed)); @@ -118,7 +134,7 @@ mod test { } #[test] - fn test_block_packing() { + fn block_packing() { let packed = block_pos::packed(-30000000, 120, 30000000); assert_eq!(packed, -8246337085439999880i64); assert_eq!(-30000000, block_pos::unpack_x(packed)); diff --git a/pumpkin-world/src/generation/proto_chunk.rs b/pumpkin-world/src/generation/proto_chunk.rs index 2e1f5f6e0..744cb84e6 100644 --- a/pumpkin-world/src/generation/proto_chunk.rs +++ b/pumpkin-world/src/generation/proto_chunk.rs @@ -76,6 +76,7 @@ pub struct StandardChunkFluidLevelSampler { } impl StandardChunkFluidLevelSampler { + #[must_use] pub fn new(top_fluid: FluidLevel, bottom_fluid: FluidLevel) -> Self { let bottom_y = top_fluid .max_y_exclusive() @@ -102,9 +103,9 @@ impl FluidLevelSamplerImpl for StandardChunkFluidLevelSampler { /// /// 1. empty: The chunk is not yet loaded or generated. /// -/// 2. structures_starts: This step calculates the starting points for structure pieces. For structures that are the starting in this chunk, the position of all pieces are generated and stored. +/// 2. `structures_starts`: This step calculates the starting points for structure pieces. For structures that are the starting in this chunk, the position of all pieces are generated and stored. /// -/// 3. structures_references: A reference to nearby chunks that have a structures' starting point are stored. +/// 3. `structures_references`: A reference to nearby chunks that have a structures' starting point are stored. /// /// 4. biomes: Biomes are determined and stored. No terrain is generated at this stage. /// @@ -116,7 +117,7 @@ impl FluidLevelSamplerImpl for StandardChunkFluidLevelSampler { /// /// 8. features: Features and structure pieces are placed and heightmaps are generated. /// -/// 9. initialize_light: The lighting engine is initialized and light sources are identified. +/// 9. `initialize_light`: The lighting engine is initialized and light sources are identified. /// /// 10. light: The lighting engine calculates the light level for blocks. /// @@ -155,6 +156,7 @@ pub struct TerrainCache { } impl TerrainCache { + #[must_use] pub fn from_random(random_config: &GlobalRandomConfig) -> Self { let random = &random_config.base_random_deriver; let noise_builder = DoublePerlinNoiseBuilder::new(random_config); @@ -170,6 +172,7 @@ impl TerrainCache { } impl ProtoChunk { + #[must_use] pub fn new( x: i32, z: i32, @@ -204,13 +207,14 @@ impl ProtoChunk { } } + #[must_use] pub fn from_chunk_data( chunk_data: &ChunkData, dimension: &Dimension, default_block: &'static BlockState, biome_mixer_seed: i64, ) -> Self { - let mut proto_chunk = ProtoChunk::new( + let mut proto_chunk = Self::new( chunk_data.x, chunk_data.z, dimension, @@ -293,15 +297,18 @@ impl ProtoChunk { proto_chunk } #[inline] - pub fn stage_id(&self) -> u8 { + #[must_use] + pub const fn stage_id(&self) -> u8 { self.stage as u8 } - pub fn height(&self) -> u16 { + #[must_use] + pub const fn height(&self) -> u16 { self.height } - pub fn bottom_y(&self) -> i8 { + #[must_use] + pub const fn bottom_y(&self) -> i8 { self.bottom_y } @@ -346,6 +353,7 @@ impl ProtoChunk { } } + #[must_use] pub fn get_top_y(&self, heightmap: &HeightMap, x: i32, z: i32) -> i32 { match heightmap { HeightMap::WorldSurfaceWg => self.top_block_height_exclusive(x, z), @@ -359,6 +367,7 @@ impl ProtoChunk { } } + #[must_use] pub fn top_block_height_exclusive(&self, x: i32, z: i32) -> i32 { let local_x = x & 15; let local_z = z & 15; @@ -366,6 +375,7 @@ impl ProtoChunk { self.flat_surface_height_map[index] as i32 + 1 } + #[must_use] pub fn ocean_floor_height_exclusive(&self, x: i32, z: i32) -> i32 { let local_x = x & 15; let local_z = z & 15; @@ -373,6 +383,7 @@ impl ProtoChunk { self.flat_ocean_floor_height_map[index] as i32 + 1 } + #[must_use] pub fn top_motion_blocking_block_height_exclusive(&self, x: i32, z: i32) -> i32 { let local_x = x & 15; let local_z = z & 15; @@ -380,6 +391,7 @@ impl ProtoChunk { self.flat_motion_blocking_height_map[index] as i32 + 1 } + #[must_use] pub fn top_motion_blocking_block_no_leaves_height_exclusive(&self, x: i32, z: i32) -> i32 { let local_x = x & 15; let local_z = z & 15; @@ -388,7 +400,7 @@ impl ProtoChunk { } #[inline] - fn local_position_to_height_map_index(x: i32, z: i32) -> usize { + const fn local_position_to_height_map_index(x: i32, z: i32) -> usize { x as usize * CHUNK_DIM as usize + z as usize } @@ -400,13 +412,14 @@ impl ProtoChunk { assert!(y < self.height() as i32); assert!(y >= 0); assert!((0..=15).contains(&z)); - } + }; self.height() as usize * CHUNK_DIM as usize * x as usize + CHUNK_DIM as usize * y as usize + z as usize } #[inline] + #[must_use] pub fn local_biome_pos_to_biome_index(&self, x: i32, y: i32, z: i32) -> usize { #[cfg(debug_assertions)] { @@ -419,7 +432,7 @@ impl ProtoChunk { y ); assert!((0..=3).contains(&z)); - } + }; biome_coords::from_block(self.height() as usize) * biome_coords::from_block(CHUNK_DIM as usize) @@ -429,17 +442,20 @@ impl ProtoChunk { } #[inline] + #[must_use] pub fn is_air(&self, local_pos: &Vector3) -> bool { is_air(self.get_block_state(local_pos).0) } #[inline] + #[must_use] pub fn get_block_state_raw(&self, x: i32, y: i32, z: i32) -> u16 { let index = self.local_pos_to_block_index(x, y, z); self.flat_block_map[index] } #[inline] + #[must_use] pub fn get_block_state(&self, local_pos: &Vector3) -> RawBlockState { let local_y = local_pos.y - self.bottom_y() as i32; if local_y < 0 || local_y >= self.height() as i32 { @@ -479,11 +495,13 @@ impl ProtoChunk { } #[inline] + #[must_use] pub fn get_biome(&self, x: i32, y: i32, z: i32) -> &'static Biome { Biome::from_id(self.get_biome_id(x, y, z)).unwrap() } #[inline] + #[must_use] pub fn get_biome_id(&self, x: i32, y: i32, z: i32) -> u8 { let index = self.local_biome_pos_to_biome_index( x & biome_coords::from_block(15), @@ -651,6 +669,7 @@ impl ProtoChunk { } } + #[expect(clippy::similar_names)] pub fn populate_noise( &mut self, noise_sampler: &mut ChunkNoiseGenerator, @@ -724,6 +743,7 @@ impl ProtoChunk { } } + #[must_use] pub fn get_biome_for_terrain_gen(&self, x: i32, y: i32, z: i32) -> &'static Biome { // TODO: See if we can cache this value let seed_biome_pos = biome::get_biome_blend( @@ -811,7 +831,7 @@ impl ProtoChunk { let shift = min_y << 4; min = shift as i32; - for search_y in (min_y as i32 - 1..=y - 1).rev() { + for search_y in ((min_y as i32 - 1)..y).rev() { if search_y < min_y as i32 { min = search_y + 1; break; @@ -889,7 +909,7 @@ impl ProtoChunk { let (center_x, center_z, min_y, height, biomes_in_chunk) = { let chunk = cache.get_center_chunk(); let mut unique_biomes = Vec::with_capacity(4); // Usually few biomes per chunk - for &biome_id in chunk.flat_biome_map.iter() { + for &biome_id in &chunk.flat_biome_map { if !unique_biomes.contains(&biome_id) { unique_biomes.push(biome_id); } @@ -1115,19 +1135,19 @@ impl ProtoChunk { center_chunk.stage = StagedChunkEnum::StructureReferences; } - fn start_cell_x(&self, horizontal_cell_block_count: i32) -> i32 { + const fn start_cell_x(&self, horizontal_cell_block_count: i32) -> i32 { self.start_block_x() / horizontal_cell_block_count } - fn start_cell_z(&self, horizontal_cell_block_count: i32) -> i32 { + const fn start_cell_z(&self, horizontal_cell_block_count: i32) -> i32 { self.start_block_z() / horizontal_cell_block_count } - fn start_block_x(&self) -> i32 { + const fn start_block_x(&self) -> i32 { start_block_x(self.x) } - fn start_block_z(&self) -> i32 { + const fn start_block_z(&self) -> i32 { start_block_z(self.z) } } diff --git a/pumpkin-world/src/generation/proto_chunk_test.rs b/pumpkin-world/src/generation/proto_chunk_test.rs index 6f9cb9dfb..5c21f1ad1 100644 --- a/pumpkin-world/src/generation/proto_chunk_test.rs +++ b/pumpkin-world/src/generation/proto_chunk_test.rs @@ -22,7 +22,7 @@ mod test { #[test] #[ignore] // TODO: Update this test to work with new API - fn test_no_blend_no_beard_only_cell_cache() { + fn no_blend_no_beard_only_cell_cache() { // We say no wrapper, but it technically has a top-level cell cache let expected_data: Vec = read_data_from_file!("../../assets/no_blend_no_beard_only_cell_cache_0_0.chunk"); @@ -80,7 +80,7 @@ mod test { #[test] #[ignore] // TODO: Update this test to work with new API - fn test_no_blend_no_beard_only_cell_2d_cache() { + fn no_blend_no_beard_only_cell_2d_cache() { // it technically has a top-level cell cache // should be the same as only cell_cache let expected_data: Vec = @@ -140,7 +140,7 @@ mod test { #[test] #[ignore] // TODO: Update this test to work with new API - fn test_no_blend_no_beard_only_cell_flat_cache() { + fn no_blend_no_beard_only_cell_flat_cache() { // it technically has a top-level cell cache let expected_data: Vec = read_data_from_file!( "../../assets/no_blend_no_beard_only_cell_cache_flat_cache_0_0.chunk" @@ -200,7 +200,7 @@ mod test { #[test] #[ignore] // TODO: Update this test to work with new API - fn test_no_blend_no_beard_only_cell_once_cache() { + fn no_blend_no_beard_only_cell_once_cache() { // it technically has a top-level cell cache let expected_data: Vec = read_data_from_file!( "../../assets/no_blend_no_beard_only_cell_cache_once_cache_0_0.chunk" @@ -260,7 +260,7 @@ mod test { #[test] #[ignore] // TODO: Update this test to work with new API - fn test_no_blend_no_beard_only_cell_interpolated() { + fn no_blend_no_beard_only_cell_interpolated() { // it technically has a top-level cell cache let expected_data: Vec = read_data_from_file!( "../../assets/no_blend_no_beard_only_cell_cache_interpolated_0_0.chunk" @@ -320,7 +320,7 @@ mod test { #[test] #[ignore] // TODO: Update this test to work with new API - fn test_no_blend_no_beard() { + fn no_blend_no_beard() { let _expected_data: Vec = read_data_from_file!("../../assets/no_blend_no_beard_0_0.chunk"); let surface_config = GENERATION_SETTINGS @@ -342,7 +342,7 @@ mod test { #[test] #[ignore] // TODO: Update this test to work with new API - fn test_no_blend_no_beard_aquifer() { + fn no_blend_no_beard_aquifer() { let expected_data: Vec = read_data_from_file!("../../assets/no_blend_no_beard_7_4.chunk"); let surface_config = GENERATION_SETTINGS @@ -366,7 +366,7 @@ mod test { #[test] #[ignore] // TODO: Update this test to work with new API - fn test_no_blend_no_beard_badlands() { + fn no_blend_no_beard_badlands() { let expected_data: Vec = read_data_from_file!("../../assets/no_blend_no_beard_-595_544.chunk"); let surface_config = GENERATION_SETTINGS @@ -395,7 +395,7 @@ mod test { #[test] #[ignore] // TODO: Update this test to work with new API - fn test_no_blend_no_beard_frozen_ocean() { + fn no_blend_no_beard_frozen_ocean() { let expected_data: Vec = read_data_from_file!("../../assets/no_blend_no_beard_-119_183.chunk"); let surface_config = GENERATION_SETTINGS @@ -424,7 +424,7 @@ mod test { #[test] #[ignore] // TODO: Update this test to work with new API - fn test_no_blend_no_beard_badlands2() { + fn no_blend_no_beard_badlands2() { let expected_data: Vec = read_data_from_file!("../../assets/no_blend_no_beard_13579_-6_11.chunk"); let surface_config = GENERATION_SETTINGS @@ -453,7 +453,7 @@ mod test { #[test] #[ignore] // TODO: Update this test to work with new API - fn test_no_blend_no_beard_badlands3() { + fn no_blend_no_beard_badlands3() { let expected_data: Vec = read_data_from_file!("../../assets/no_blend_no_beard_13579_-2_15.chunk"); let surface_config = GENERATION_SETTINGS @@ -482,7 +482,7 @@ mod test { #[test] #[ignore] // TODO: Update this test to work with new API - fn test_no_blend_no_beard_surface() { + fn no_blend_no_beard_surface() { let expected_data: Vec = read_data_from_file!("../../assets/no_blend_no_beard_surface_0_0.chunk"); let surface_config = GENERATION_SETTINGS @@ -514,7 +514,7 @@ mod test { #[test] #[ignore] // TODO: Update this test to work with new API - fn test_no_blend_no_beard_surface_badlands() { + fn no_blend_no_beard_surface_badlands() { let expected_data: Vec = read_data_from_file!("../../assets/no_blend_no_beard_surface_badlands_-595_544.chunk"); let surface_config = GENERATION_SETTINGS @@ -546,7 +546,7 @@ mod test { #[test] #[ignore] // TODO: Update this test to work with new API - fn test_no_blend_no_beard_surface_badlands2() { + fn no_blend_no_beard_surface_badlands2() { let expected_data: Vec = read_data_from_file!("../../assets/no_blend_no_beard_surface_13579_-6_11.chunk"); let surface_config = GENERATION_SETTINGS @@ -579,7 +579,7 @@ mod test { #[test] #[ignore] // TODO: Update this test to work with new API - fn test_no_blend_no_beard_surface_badlands3() { + fn no_blend_no_beard_surface_badlands3() { let expected_data: Vec = read_data_from_file!("../../assets/no_blend_no_beard_surface_13579_-7_9.chunk"); let surface_config = GENERATION_SETTINGS @@ -613,7 +613,7 @@ mod test { #[test] #[ignore] // TODO: Update this test to work with new API - fn test_no_blend_no_beard_surface_biome_blend() { + fn no_blend_no_beard_surface_biome_blend() { let expected_data: Vec = read_data_from_file!("../../assets/no_blend_no_beard_surface_13579_-2_15.chunk"); let surface_config = GENERATION_SETTINGS @@ -647,7 +647,7 @@ mod test { #[test] #[ignore] // TODO: Update this test to work with new API - fn test_no_blend_no_beard_surface_frozen_ocean() { + fn no_blend_no_beard_surface_frozen_ocean() { let expected_data: Vec = read_data_from_file!( "../../assets/no_blend_no_beard_surface_frozen_ocean_-119_183.chunk" ); diff --git a/pumpkin-world/src/generation/rule/mod.rs b/pumpkin-world/src/generation/rule/mod.rs index 7e7f78ba3..bc73b0af2 100644 --- a/pumpkin-world/src/generation/rule/mod.rs +++ b/pumpkin-world/src/generation/rule/mod.rs @@ -33,12 +33,12 @@ pub enum RuleTest { impl RuleTest { pub fn test(&self, state: &BlockState, random: &mut RandomGenerator) -> bool { match self { - RuleTest::AlwaysTrue => true, - RuleTest::BlockMatch(rule) => rule.test(state), - RuleTest::BlockStateMatch(rule) => rule.test(state), - RuleTest::TagMatch(rule) => rule.test(state), - RuleTest::RandomBlockMatch(rule) => rule.test(state, random), - RuleTest::RandomBlockStateMatch(rule) => rule.test(state, random), + Self::AlwaysTrue => true, + Self::BlockMatch(rule) => rule.test(state), + Self::BlockStateMatch(rule) => rule.test(state), + Self::TagMatch(rule) => rule.test(state), + Self::RandomBlockMatch(rule) => rule.test(state, random), + Self::RandomBlockStateMatch(rule) => rule.test(state, random), } } } diff --git a/pumpkin-world/src/generation/rule_test.rs b/pumpkin-world/src/generation/rule_test.rs index 9d0331e50..3769a2676 100644 --- a/pumpkin-world/src/generation/rule_test.rs +++ b/pumpkin-world/src/generation/rule_test.rs @@ -12,7 +12,7 @@ pub enum RuleTest { pub struct AlwaysTrueRuleTest; impl AlwaysTrueRuleTest { - pub fn test(&self, _block: &'static Block) -> bool { + pub const fn test() -> bool { true } } diff --git a/pumpkin-world/src/generation/settings.rs b/pumpkin-world/src/generation/settings.rs index f5789b59f..7a4828340 100644 --- a/pumpkin-world/src/generation/settings.rs +++ b/pumpkin-world/src/generation/settings.rs @@ -57,16 +57,19 @@ pub struct GenerationShapeConfig { impl GenerationShapeConfig { #[inline] + #[must_use] pub fn vertical_cell_block_count(&self) -> u8 { to_block(self.size_vertical) } #[inline] + #[must_use] pub fn horizontal_cell_block_count(&self) -> u8 { to_block(self.size_horizontal) } - pub fn max_y(&self) -> u16 { + #[must_use] + pub const fn max_y(&self) -> u16 { if self.min_y >= 0 { self.height + self.min_y as u16 } else { diff --git a/pumpkin-world/src/generation/structure/mod.rs b/pumpkin-world/src/generation/structure/mod.rs index 6615a24d2..429a55001 100644 --- a/pumpkin-world/src/generation/structure/mod.rs +++ b/pumpkin-world/src/generation/structure/mod.rs @@ -144,10 +144,8 @@ pub enum StructureKeys { TrialChambers, } -#[derive(Deserialize, Clone)] -pub struct EmptyStruct {} - impl StructureKeys { + #[must_use] pub fn try_generate( &self, structure: &Structure, @@ -165,16 +163,16 @@ impl StructureKeys { min_y: chunk.bottom_y() as i32, }; let structure_pos = match self { - StructureKeys::BuriedTreasure => { + Self::BuriedTreasure => { BuriedTreasureGenerator::get_structure_position(&BuriedTreasureGenerator, context) } // StructureKeys::Fortress => { // NetherFortressGenerator::get_structure_position(&NetherFortressGenerator, context) // } - StructureKeys::SwampHut => { + Self::SwampHut => { SwampHutGenerator::get_structure_position(&SwampHutGenerator, context) } - StructureKeys::Stronghold => { + Self::Stronghold => { StrongholdGenerator::get_structure_position(&StrongholdGenerator, context) } // StructureKeys::DesertPyramid => DesertTempleGenerator::get_structure_position( @@ -226,7 +224,8 @@ pub enum GenerationStep { } impl GenerationStep { - pub fn ordinal(&self) -> usize { + #[must_use] + pub const fn ordinal(&self) -> usize { *self as usize } } diff --git a/pumpkin-world/src/generation/structure/placement.rs b/pumpkin-world/src/generation/structure/placement.rs index b8485c4d6..793da5d3b 100644 --- a/pumpkin-world/src/generation/structure/placement.rs +++ b/pumpkin-world/src/generation/structure/placement.rs @@ -17,6 +17,7 @@ pub struct StructurePlacement { } impl StructurePlacement { + #[must_use] pub fn should_generate( &self, calculator: &StructurePlacementCalculator, @@ -53,6 +54,7 @@ pub enum FrequencyReductionMethod { } impl FrequencyReductionMethod { + #[must_use] pub fn should_generate( &self, seed: i64, @@ -62,12 +64,12 @@ impl FrequencyReductionMethod { frequency: f32, ) -> bool { match self { - FrequencyReductionMethod::Default => { + Self::Default => { let region_seed = get_region_seed(seed as u64, chunk_x, chunk_z, salt); let mut random = RandomGenerator::Xoroshiro(Xoroshiro::from_seed(region_seed)); random.next_f32() < frequency } - FrequencyReductionMethod::LegacyType1 => { + Self::LegacyType1 => { let x = chunk_x >> 4; let z = chunk_z >> 4; let mut random = RandomGenerator::Xoroshiro(Xoroshiro::from_seed( @@ -76,12 +78,12 @@ impl FrequencyReductionMethod { random.next_i32(); // yeah mojang just does that and does not use the value random.next_bounded_i32((1.0 / frequency) as i32) == 0 } - FrequencyReductionMethod::LegacyType2 => { + Self::LegacyType2 => { let region_seed = get_region_seed(seed as u64, chunk_x, chunk_z, 10387320); let mut random = RandomGenerator::Xoroshiro(Xoroshiro::from_seed(region_seed)); random.next_f32() < frequency } - FrequencyReductionMethod::LegacyType3 => { + Self::LegacyType3 => { let mut random: RandomGenerator = RandomGenerator::Xoroshiro(Xoroshiro::from_seed(seed as u64)); let carver_seed = get_carver_seed(&mut random, seed as u64, chunk_x, chunk_z); @@ -104,6 +106,7 @@ pub enum StructurePlacementType { } impl StructurePlacementType { + #[must_use] pub fn is_start_chunk( &self, calculator: &StructurePlacementCalculator, @@ -112,11 +115,11 @@ impl StructurePlacementType { salt: u32, ) -> bool { match self { - StructurePlacementType::RandomSpread(placement) => { + Self::RandomSpread(placement) => { placement.is_start_chunk(calculator, chunk_x, chunk_z, salt) } // This is needed for Stronghold, since it is placed in rings - StructurePlacementType::ConcentricRings(placement) => { + Self::ConcentricRings(placement) => { placement.is_start_chunk(calculator, chunk_x, chunk_z, salt) } } @@ -139,6 +142,7 @@ pub struct ConcentricRingsStructurePlacement { } impl ConcentricRingsStructurePlacement { + #[must_use] pub fn is_start_chunk( &self, _calculator: &StructurePlacementCalculator, @@ -180,10 +184,11 @@ pub enum SpreadType { impl SpreadType { pub fn get(&self, random: &mut RandomGenerator, bound: i32) -> i32 { match self { - SpreadType::Linear => random.next_bounded_i32(bound), - SpreadType::Triangular => { - (random.next_bounded_i32(bound) + random.next_bounded_i32(bound)) / 2 - } + Self::Linear => random.next_bounded_i32(bound), + Self::Triangular => i32::midpoint( + random.next_bounded_i32(bound), + random.next_bounded_i32(bound), + ), } } } @@ -201,6 +206,7 @@ impl RandomSpreadStructurePlacement { (x * self.spacing + rand_x, z * self.spacing + rand_z) } + #[must_use] pub fn is_start_chunk( &self, calculator: &StructurePlacementCalculator, @@ -218,7 +224,8 @@ pub struct StructurePlacementCalculator { } impl StructurePlacementCalculator { - pub fn new(seed: i64) -> Self { + #[must_use] + pub const fn new(seed: i64) -> Self { Self { seed } } } @@ -232,14 +239,14 @@ mod tests { use crate::generation::structure::placement::RandomSpreadStructurePlacement; #[test] - fn test_get_start_chunk_random() { + fn get_start_chunk_random() { let region_seed = get_region_seed(123, 1, 1, 14357620); let mut random = RandomGenerator::Legacy(LegacyRand::from_seed(region_seed)); - assert_eq!(random.next_bounded_i32(32 - 8), 8) + assert_eq!(random.next_bounded_i32(32 - 8), 8); } #[test] - fn test_get_start_chunk() { + fn get_start_chunk() { let random = RandomSpreadStructurePlacement { spacing: 32, separation: 8, diff --git a/pumpkin-world/src/generation/structure/shiftable_piece.rs b/pumpkin-world/src/generation/structure/shiftable_piece.rs index cabcd1dda..95f752c8c 100644 --- a/pumpkin-world/src/generation/structure/shiftable_piece.rs +++ b/pumpkin-world/src/generation/structure/shiftable_piece.rs @@ -20,6 +20,7 @@ pub struct ShiftableStructurePiece { impl ShiftableStructurePiece { #[expect(clippy::too_many_arguments)] + #[must_use] pub fn new( r#type: StructurePieceType, x: i32, diff --git a/pumpkin-world/src/generation/structure/structures/mod.rs b/pumpkin-world/src/generation/structure/structures/mod.rs index 7267aa4a7..ac8625997 100644 --- a/pumpkin-world/src/generation/structure/structures/mod.rs +++ b/pumpkin-world/src/generation/structure/structures/mod.rs @@ -65,7 +65,12 @@ pub struct StructurePiece { } impl StructurePiece { - pub fn new(r#type: StructurePieceType, bounding_box: BlockBox, chain_length: u32) -> Self { + #[must_use] + pub const fn new( + r#type: StructurePieceType, + bounding_box: BlockBox, + chain_length: u32, + ) -> Self { Self { r#type, bounding_box, @@ -74,11 +79,11 @@ impl StructurePiece { } } - pub fn set_facing(&mut self, facing: Option) { + pub const fn set_facing(&mut self, facing: Option) { self.facing = facing; } - fn offset_pos(&self, x: i32, y: i32, z: i32) -> Vector3 { + const fn offset_pos(&self, x: i32, y: i32, z: i32) -> Vector3 { Vector3::new( self.apply_x_transform(x, z), self.apply_y_transform(y), @@ -86,31 +91,29 @@ impl StructurePiece { ) } - fn apply_x_transform(&self, x: i32, z: i32) -> i32 { + const fn apply_x_transform(&self, x: i32, z: i32) -> i32 { match self.facing { None => x, - Some(BlockDirection::North) | Some(BlockDirection::South) => { - self.bounding_box.min.x + x - } + Some(BlockDirection::North | BlockDirection::South) => self.bounding_box.min.x + x, Some(BlockDirection::West) => self.bounding_box.max.x - z, Some(BlockDirection::East) => self.bounding_box.min.x + z, _ => x, } } - fn apply_y_transform(&self, y: i32) -> i32 { + const fn apply_y_transform(&self, y: i32) -> i32 { match self.facing { None => y, Some(_) => y + self.bounding_box.min.y, } } - fn apply_z_transform(&self, x: i32, z: i32) -> i32 { + const fn apply_z_transform(&self, x: i32, z: i32) -> i32 { match self.facing { None => z, Some(BlockDirection::North) => self.bounding_box.max.z - z, Some(BlockDirection::South) => self.bounding_box.min.z + z, - Some(BlockDirection::West) | Some(BlockDirection::East) => self.bounding_box.min.z + x, + Some(BlockDirection::West | BlockDirection::East) => self.bounding_box.min.z + x, _ => z, } } @@ -298,6 +301,7 @@ impl StructurePiece { block_pos.y < sea_level_at_pos } + #[must_use] pub fn get_block_at( &self, chunk: &ProtoChunk, @@ -392,6 +396,7 @@ pub struct StructurePiecesCollector { } impl StructurePiecesCollector { + #[must_use] pub fn new() -> Self { Self { pieces: Vec::new(), @@ -405,6 +410,7 @@ impl StructurePiecesCollector { } #[expect(clippy::borrowed_box)] + #[must_use] pub fn get_intersecting( &self, box_to_check: &BlockBox, @@ -438,7 +444,7 @@ impl StructurePiecesCollector { chunk_z + 15, ); - for piece in self.pieces.iter_mut() { + for piece in &mut self.pieces { if piece.bounding_box().intersects(&chunk_box) { piece.place(chunk, random, seed); } @@ -446,7 +452,7 @@ impl StructurePiecesCollector { } pub fn shift(&mut self, y_offset: i32) { - for piece in self.pieces.iter_mut() { + for piece in &mut self.pieces { piece.translate(0, y_offset, 0); } self.cached_box = None; @@ -489,12 +495,13 @@ impl StructurePiecesCollector { bbox } + #[must_use] pub fn is_empty(&self) -> bool { self.pieces.is_empty() } pub fn clear(&mut self) { - self.pieces.clear() + self.pieces.clear(); } } @@ -505,6 +512,7 @@ pub struct StructurePosition { } impl StructurePosition { + #[must_use] pub fn get_bounding_box(&self) -> BlockBox { self.collector.lock().unwrap().get_bounding_box() } @@ -526,6 +534,7 @@ pub struct StructureGeneratorContext { pub min_y: i32, } +#[must_use] pub fn create_chunk_random(seed: i64, chunk_x: i32, chunk_z: i32) -> RandomGenerator { let mut random: RandomGenerator = RandomGenerator::Xoroshiro(Xoroshiro::from_seed(seed as u64)); let carver_seed = get_carver_seed(&mut random, seed as u64, chunk_x, chunk_z); @@ -537,6 +546,6 @@ pub enum StructureInstance { /// This chunk is the "owner" of the structure. Start(StructurePosition), /// This chunk just contains a piece of a structure starting elsewhere. - /// Stores the BlockPos of the 'Start' so you can look it up. + /// Stores the `BlockPos` of the 'Start' so you can look it up. Reference(BlockPos), } diff --git a/pumpkin-world/src/generation/structure/structures/stronghold/corridor.rs b/pumpkin-world/src/generation/structure/structures/stronghold/corridor.rs index b7037a9b5..241f072b4 100644 --- a/pumpkin-world/src/generation/structure/structures/stronghold/corridor.rs +++ b/pumpkin-world/src/generation/structure/structures/stronghold/corridor.rs @@ -139,7 +139,8 @@ pub struct SmallCorridorPiece { } impl SmallCorridorPiece { - pub fn new(chain_length: u32, bbox: BlockBox, orientation: BlockDirection) -> Self { + #[must_use] + pub const fn new(chain_length: u32, bbox: BlockBox, orientation: BlockDirection) -> Self { let length = match orientation { BlockDirection::North | BlockDirection::South => bbox.max.z - bbox.min.z + 1, _ => bbox.max.x - bbox.min.x + 1, diff --git a/pumpkin-world/src/generation/structure/structures/stronghold/mod.rs b/pumpkin-world/src/generation/structure/structures/stronghold/mod.rs index 4e74a980a..f8d87976f 100644 --- a/pumpkin-world/src/generation/structure/structures/stronghold/mod.rs +++ b/pumpkin-world/src/generation/structure/structures/stronghold/mod.rs @@ -130,7 +130,7 @@ impl StructureGenerator for StrongholdGenerator { } } -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum EntranceType { Opening = 0, WoodDoor = 1, @@ -141,10 +141,10 @@ pub enum EntranceType { impl EntranceType { pub fn get_random(random: &mut impl RandomImpl) -> Self { match random.next_bounded_i32(5) { - 2 => EntranceType::WoodDoor, - 3 => EntranceType::Grates, - 4 => EntranceType::IronDoor, - _ => EntranceType::Opening, + 2 => Self::WoodDoor, + 3 => Self::Grates, + 4 => Self::IronDoor, + _ => Self::Opening, } } } @@ -183,7 +183,8 @@ pub enum StrongholdPieceType { PortalRoom, } impl StrongholdPieceType { - pub fn as_structure_type(&self) -> StructurePieceType { + #[must_use] + pub const fn as_structure_type(&self) -> StructurePieceType { match self { Self::Corridor => StructurePieceType::StrongholdCorridor, Self::PrisonHall => StructurePieceType::StrongholdPrisonHall, @@ -208,7 +209,7 @@ pub struct PieceWeight { } impl PieceWeight { - fn new(piece_type: StrongholdPieceType, weight: i32, limit: i32) -> Self { + const fn new(piece_type: StrongholdPieceType, weight: i32, limit: i32) -> Self { Self { piece_type, weight, @@ -216,7 +217,7 @@ impl PieceWeight { } } - fn can_generate(&self, _chain_length: u32) -> bool { + const fn can_generate(&self, _chain_length: u32) -> bool { self.limit == 0 //|| self.generated_count < self.limit } } @@ -297,13 +298,14 @@ pub struct StrongholdPiece { } impl StrongholdPiece { - pub fn new(r#type: StructurePieceType, chain_length: u32, bbox: BlockBox) -> Self { + #[must_use] + pub const fn new(r#type: StructurePieceType, chain_length: u32, bbox: BlockBox) -> Self { Self { piece: StructurePiece::new(r#type, bbox, chain_length), entry_door: EntranceType::Opening, } } - fn is_in_bounds(bb: &BlockBox) -> bool { + const fn is_in_bounds(bb: &BlockBox) -> bool { bb.min.y > 10 } @@ -435,7 +437,7 @@ impl StrongholdPiece { pieces_to_process: &mut Vec>, piece: Option, ) { - if let Some(facing) = &self.piece.facing { + if let Some(facing) = self.piece.facing { let bounding_box = self.piece.bounding_box; let (nx, ny, nz) = match facing { BlockDirection::North => ( @@ -514,7 +516,7 @@ impl StrongholdPiece { nx, ny, nz, - &next_facing, + next_facing, self.piece.chain_length, None, // Dynamic piece selection ) { @@ -558,7 +560,7 @@ impl StrongholdPiece { nx, ny, nz, - &next_facing, + next_facing, self.piece.chain_length, None, ) { @@ -575,7 +577,7 @@ impl StrongholdPiece { x: i32, y: i32, z: i32, - orientation: &BlockDirection, + orientation: BlockDirection, chain_length: u32, piece_type: Option, ) -> Option> { @@ -592,7 +594,7 @@ impl StrongholdPiece { let next_piece = if let Some(p_type) = piece_type { Self::create_piece( - &p_type, + p_type, collector, random, x, @@ -619,7 +621,7 @@ impl StrongholdPiece { x: i32, y: i32, z: i32, - orientation: &BlockDirection, + orientation: BlockDirection, chain_length: u32, ) -> Option> { let mut attempt = 0; @@ -627,7 +629,7 @@ impl StrongholdPiece { attempt += 1; let mut j = random.next_bounded_i32(TOTAL_WEIGHT); - for piece_data in POSSIBLE_PIECES.iter() { + for piece_data in POSSIBLE_PIECES { j -= piece_data.weight; if j >= 0 { continue; @@ -648,7 +650,7 @@ impl StrongholdPiece { } let piece = Self::create_piece( - &piece_data.piece_type, + piece_data.piece_type, collector, random, x, @@ -665,11 +667,11 @@ impl StrongholdPiece { } // Fallback: Small Corridor - if let Some(bbox) = SmallCorridorPiece::create_box(collector, x, y, z, orientation) { + if let Some(bbox) = SmallCorridorPiece::create_box(collector, x, y, z, &orientation) { return Some(Box::new(SmallCorridorPiece::new( chain_length, bbox, - *orientation, + orientation, ))); } @@ -678,48 +680,48 @@ impl StrongholdPiece { #[expect(clippy::too_many_arguments)] fn create_piece( - piece_type: &StrongholdPieceType, + piece_type: StrongholdPieceType, collector: &mut StructurePiecesCollector, random: &mut impl RandomImpl, x: i32, y: i32, z: i32, - orientation: &BlockDirection, + orientation: BlockDirection, chain_length: u32, ) -> Option> { match piece_type { StrongholdPieceType::FiveWayCrossing => { - FiveWayCrossingPiece::create(collector, random, x, y, z, *orientation, chain_length) + FiveWayCrossingPiece::create(collector, random, x, y, z, orientation, chain_length) } StrongholdPieceType::Corridor => { - CorridorPiece::create(collector, random, x, y, z, *orientation, chain_length) + CorridorPiece::create(collector, random, x, y, z, orientation, chain_length) } StrongholdPieceType::SquareRoom => { - SquareRoomPiece::create(collector, random, x, y, z, *orientation, chain_length) + SquareRoomPiece::create(collector, random, x, y, z, orientation, chain_length) } StrongholdPieceType::PortalRoom => { - PortalRoomPiece::create(collector, random, x, y, z, *orientation, chain_length) + PortalRoomPiece::create(collector, random, x, y, z, orientation, chain_length) } StrongholdPieceType::SpiralStaircase => { - SpiralStaircasePiece::create(collector, random, x, y, z, *orientation, chain_length) + SpiralStaircasePiece::create(collector, random, x, y, z, orientation, chain_length) } StrongholdPieceType::PrisonHall => { - PrisonHallPiece::create(collector, random, x, y, z, *orientation, chain_length) + PrisonHallPiece::create(collector, random, x, y, z, orientation, chain_length) } StrongholdPieceType::LeftTurn => { - LeftTurnPiece::create(collector, random, x, y, z, *orientation, chain_length) + LeftTurnPiece::create(collector, random, x, y, z, orientation, chain_length) } StrongholdPieceType::RightTurn => { - RightTurnPiece::create(collector, random, x, y, z, *orientation, chain_length) + RightTurnPiece::create(collector, random, x, y, z, orientation, chain_length) } StrongholdPieceType::Stairs => { - StairsPiece::create(collector, random, x, y, z, *orientation, chain_length) + StairsPiece::create(collector, random, x, y, z, orientation, chain_length) } StrongholdPieceType::ChestCorridor => { - ChestCorridorPiece::create(collector, random, x, y, z, *orientation, chain_length) + ChestCorridorPiece::create(collector, random, x, y, z, orientation, chain_length) } StrongholdPieceType::Library => { - LibraryPiece::create(collector, random, x, y, z, *orientation, chain_length) + LibraryPiece::create(collector, random, x, y, z, orientation, chain_length) } } } diff --git a/pumpkin-world/src/generation/structure/structures/stronghold/spiral_staircase.rs b/pumpkin-world/src/generation/structure/structures/stronghold/spiral_staircase.rs index 5e8b8f258..11e560b96 100644 --- a/pumpkin-world/src/generation/structure/structures/stronghold/spiral_staircase.rs +++ b/pumpkin-world/src/generation/structure/structures/stronghold/spiral_staircase.rs @@ -98,7 +98,8 @@ impl SpiralStaircasePiece { })) } - pub fn has_portal_room(&self) -> bool { + #[must_use] + pub const fn has_portal_room(&self) -> bool { self.portal_room_exists } } @@ -129,11 +130,8 @@ impl StructurePieceBase for SpiralStaircasePiece { 1, 1, pieces_to_process, - if self.is_structure_start { - Some(StrongholdPieceType::FiveWayCrossing) - } else { - None - }, + self.is_structure_start + .then_some(StrongholdPieceType::FiveWayCrossing), ); } diff --git a/pumpkin-world/src/generation/surface/mod.rs b/pumpkin-world/src/generation/surface/mod.rs index e40d328f9..819934395 100644 --- a/pumpkin-world/src/generation/surface/mod.rs +++ b/pumpkin-world/src/generation/surface/mod.rs @@ -56,7 +56,7 @@ pub struct MaterialRuleContext<'a> { impl<'a> MaterialRuleContext<'a> { #[expect(clippy::too_many_arguments)] - pub fn new( + pub const fn new( min_y: i8, height: u16, noise_builder: DoublePerlinNoiseBuilder<'a>, @@ -114,7 +114,7 @@ impl<'a> MaterialRuleContext<'a> { self.run_depth = self.sample_run_depth(); } - pub fn init_vertical( + pub const fn init_vertical( &mut self, stone_depth_above: i32, stone_depth_below: i32, @@ -132,7 +132,7 @@ impl<'a> MaterialRuleContext<'a> { self.last_unique_horizontal_pos_value = self.unique_horizontal_pos_value; self.secondary_depth = self.secondary_noise - .sample(self.block_pos_x as f64, 0.0, self.block_pos_z as f64) + .sample(self.block_pos_x as f64, 0.0, self.block_pos_z as f64); } self.secondary_depth } @@ -167,6 +167,7 @@ pub enum MaterialCondition { } impl MaterialCondition { + #[expect(clippy::similar_names)] pub fn test( &self, chunk: &mut ProtoChunk, @@ -174,14 +175,12 @@ impl MaterialCondition { surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler, ) -> bool { match self { - MaterialCondition::Biome(biome) => biome.test(context), - MaterialCondition::NoiseThreshold(noise_threshold) => noise_threshold.test(context), - MaterialCondition::VerticalGradient(vertical_gradient) => { - vertical_gradient.test(context) - } - MaterialCondition::YAbove(above_y) => above_y.test(context), - MaterialCondition::Water(water) => water.test(context), - MaterialCondition::Temperature => { + Self::Biome(biome) => biome.test(context), + Self::NoiseThreshold(noise_threshold) => noise_threshold.test(context), + Self::VerticalGradient(vertical_gradient) => vertical_gradient.test(context), + Self::YAbove(above_y) => above_y.test(context), + Self::Water(water) => water.test(context), + Self::Temperature => { let temperature = context.biome.weather.compute_temperature( context.block_pos_x as f64, context.block_pos_y, @@ -190,7 +189,7 @@ impl MaterialCondition { ); temperature < 0.15f32 } - MaterialCondition::Steep => { + Self::Steep => { let local_x = context.block_pos_x & 15; let local_z = context.block_pos_z & 15; @@ -212,14 +211,12 @@ impl MaterialCondition { sub_height >= add_height + 4 } } - MaterialCondition::Not(not) => { - not.test(chunk, context, surface_height_estimate_sampler) + Self::Not(not) => not.test(chunk, context, surface_height_estimate_sampler), + Self::Hole(_hole) => HoleMaterialCondition::test(context), + Self::AbovePreliminarySurface(_above) => { + SurfaceMaterialCondition::test(context, surface_height_estimate_sampler) } - MaterialCondition::Hole(hole) => hole.test(context), - MaterialCondition::AbovePreliminarySurface(above) => { - above.test(context, surface_height_estimate_sampler) - } - MaterialCondition::StoneDepth(stone_depth) => stone_depth.test(context), + Self::StoneDepth(stone_depth) => stone_depth.test(context), } } } @@ -228,7 +225,7 @@ impl MaterialCondition { pub struct HoleMaterialCondition; impl HoleMaterialCondition { - pub fn test(&self, context: &MaterialRuleContext) -> bool { + pub const fn test(context: &MaterialRuleContext) -> bool { context.run_depth <= 0 } } @@ -241,7 +238,7 @@ pub struct AboveYMaterialCondition { } impl AboveYMaterialCondition { - pub fn test(&self, context: &MaterialRuleContext) -> bool { + pub const fn test(&self, context: &MaterialRuleContext) -> bool { context.block_pos_y + if self.add_stone_depth { context.stone_depth_above @@ -276,7 +273,6 @@ pub struct SurfaceMaterialCondition; impl SurfaceMaterialCondition { pub fn test( - &self, context: &mut MaterialRuleContext, surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler, ) -> bool { @@ -398,7 +394,7 @@ pub struct WaterMaterialCondition { } impl WaterMaterialCondition { - pub fn test(&self, context: &MaterialRuleContext) -> bool { + pub const fn test(&self, context: &MaterialRuleContext) -> bool { context.fluid_height == i32::MIN || context.block_pos_y + (if self.add_stone_depth { diff --git a/pumpkin-world/src/generation/surface/rule.rs b/pumpkin-world/src/generation/surface/rule.rs index bb8d9a35c..69112aaa1 100644 --- a/pumpkin-world/src/generation/surface/rule.rs +++ b/pumpkin-world/src/generation/surface/rule.rs @@ -28,12 +28,12 @@ impl MaterialRule { surface_height_estimate_sampler: &mut SurfaceHeightEstimateSampler, ) -> Option<&'static BlockState> { match self { - MaterialRule::Badlands(badlands) => badlands.try_apply(context), - MaterialRule::Block(block) => Some(block.try_apply()), - MaterialRule::Sequence(sequence) => { + Self::Badlands(_badlands) => Some(BadLandsMaterialRule::try_apply(context)), + Self::Block(block) => Some(block.try_apply()), + Self::Sequence(sequence) => { sequence.try_apply(chunk, context, surface_height_estimate_sampler) } - MaterialRule::Condition(condition) => { + Self::Condition(condition) => { condition.try_apply(chunk, context, surface_height_estimate_sampler) } } @@ -44,12 +44,12 @@ impl MaterialRule { pub struct BadLandsMaterialRule; impl BadLandsMaterialRule { - pub fn try_apply(&self, context: &mut MaterialRuleContext) -> Option<&'static BlockState> { - Some(context.terrain_builder.get_terracotta_block( + pub fn try_apply(context: &mut MaterialRuleContext) -> &'static BlockState { + context.terrain_builder.get_terracotta_block( context.block_pos_x, context.block_pos_y, context.block_pos_z, - )) + ) } } diff --git a/pumpkin-world/src/generation/y_offset.rs b/pumpkin-world/src/generation/y_offset.rs index 701365a1a..11e1cc386 100644 --- a/pumpkin-world/src/generation/y_offset.rs +++ b/pumpkin-world/src/generation/y_offset.rs @@ -9,13 +9,14 @@ pub enum YOffset { } impl YOffset { - pub fn get_y(&self, min_y: i16, height: u16) -> i32 { + #[must_use] + pub const fn get_y(&self, min_y: i16, height: u16) -> i32 { match self { - YOffset::AboveBottom(above_bottom) => min_y as i32 + above_bottom.above_bottom as i32, - YOffset::BelowTop(below_top) => { + Self::AboveBottom(above_bottom) => min_y as i32 + above_bottom.above_bottom as i32, + Self::BelowTop(below_top) => { height as i32 - 1 + min_y as i32 - below_top.below_top as i32 } - YOffset::Absolute(absolute) => absolute.absolute as i32, + Self::Absolute(absolute) => absolute.absolute as i32, } } } diff --git a/pumpkin-world/src/item/categories.rs b/pumpkin-world/src/item/categories.rs index e15279af5..6d414317c 100644 --- a/pumpkin-world/src/item/categories.rs +++ b/pumpkin-world/src/item/categories.rs @@ -5,31 +5,37 @@ use crate::item::ItemStack; impl ItemStack { #[inline] + #[must_use] pub fn is_sword(&self) -> bool { self.item.has_tag(&tag::Item::MINECRAFT_SWORDS) } #[inline] + #[must_use] pub fn is_helmet(&self) -> bool { self.item.has_tag(&tag::Item::MINECRAFT_HEAD_ARMOR) } #[inline] + #[must_use] pub fn is_skull(&self) -> bool { self.item.has_tag(&tag::Item::MINECRAFT_SKULLS) } #[inline] + #[must_use] pub fn is_chestplate(&self) -> bool { self.item.has_tag(&tag::Item::MINECRAFT_CHEST_ARMOR) } #[inline] + #[must_use] pub fn is_leggings(&self) -> bool { self.item.has_tag(&tag::Item::MINECRAFT_LEG_ARMOR) } #[inline] + #[must_use] pub fn is_boots(&self) -> bool { self.item.has_tag(&tag::Item::MINECRAFT_FOOT_ARMOR) } diff --git a/pumpkin-world/src/item/mod.rs b/pumpkin-world/src/item/mod.rs index 70902c568..6b50cde49 100644 --- a/pumpkin-world/src/item/mod.rs +++ b/pumpkin-world/src/item/mod.rs @@ -38,6 +38,7 @@ impl PartialEq for ItemStack { } */ impl ItemStack { + #[must_use] pub fn new(item_count: u8, item: &'static Item) -> Self { Self { item_count, @@ -46,6 +47,7 @@ impl ItemStack { } } + #[must_use] pub fn new_with_component( item_count: u8, item: &'static Item, @@ -58,15 +60,14 @@ impl ItemStack { } } + #[must_use] pub fn get_data_component(&self) -> Option<&T> { let to_get_id = &T::get_enum(); for (id, component) in &self.patch { if id == to_get_id { - return if let Some(component) = component { - Some(get::(component.as_ref())) - } else { - None - }; + return component + .as_ref() + .map(|component| get::(component.as_ref())); } } for (id, component) in self.item.components { @@ -78,43 +79,41 @@ impl ItemStack { } pub fn get_data_component_mut(&mut self) -> Option<&mut T> { let to_get_id = &T::get_enum(); - for (id, component) in self.patch.iter_mut() { + for (id, component) in &mut self.patch { if id == to_get_id { - return if let Some(component) = component { - Some(get_mut::(component.as_mut())) - } else { - None - }; + return component + .as_mut() + .map(|component| get_mut::(component.as_mut())); } } None } - pub const EMPTY: &'static ItemStack = &ItemStack { + pub const EMPTY: &'static Self = &Self { item_count: 0, item: &Item::AIR, patch: Vec::new(), }; + #[must_use] pub fn get_max_stack_size(&self) -> u8 { - if let Some(value) = self.get_data_component::() { - value.size - } else { - 1 - } + self.get_data_component::() + .map_or(1, |value| value.size) } + #[must_use] pub fn get_max_damage(&self) -> Option { self.get_data_component::() .map(|value| value.max_damage) } + #[must_use] pub fn get_damage(&self) -> i32 { self.get_data_component::() - .map(|value| value.damage) - .unwrap_or(0) + .map_or(0, |value| value.damage) } + #[must_use] pub fn get_enchantment_level(&self, enchantment: &'static Enchantment) -> i32 { let Some(data) = self.get_data_component::() else { return 0; @@ -127,6 +126,7 @@ impl ItemStack { 0 } + #[must_use] pub fn is_unbreakable(&self) -> bool { self.get_data_component::().is_some() } @@ -138,7 +138,7 @@ impl ItemStack { return; } - for (id, component) in self.patch.iter_mut() { + for (id, component) in &mut self.patch { if *id == DataComponent::Damage { *component = Some(DamageImpl { damage }.to_dyn()); return; @@ -149,6 +149,7 @@ impl ItemStack { .push((DataComponent::Damage, Some(DamageImpl { damage }.to_dyn()))); } + #[must_use] pub fn is_damageable(&self) -> bool { self.get_max_damage().unwrap_or(0) > 0 } @@ -207,7 +208,7 @@ impl ItemStack { self.item_count = self.item_count.saturating_sub(1); self.set_damage(0); } else { - *self = ItemStack::EMPTY.clone(); + *self = Self::EMPTY.clone(); } return true; } @@ -220,6 +221,7 @@ impl ItemStack { self.damage_item_with_context(amount, false) } + #[must_use] pub fn get_max_use_time(&self) -> i32 { if let Some(value) = self.get_data_component::() { return value.consume_ticks(); @@ -230,7 +232,8 @@ impl ItemStack { 0 } - pub fn get_item(&self) -> &Item { + #[must_use] + pub const fn get_item(&self) -> &Item { if self.is_empty() { &Item::AIR } else { @@ -238,14 +241,17 @@ impl ItemStack { } } + #[must_use] pub fn is_stackable(&self) -> bool { self.get_max_stack_size() > 1 // TODO: && (!this.isDamageable() || !this.isDamaged()); } - pub fn is_empty(&self) -> bool { + #[must_use] + pub const fn is_empty(&self) -> bool { self.item_count == 0 || self.item.id == Item::AIR.id } + #[must_use] pub fn split(&mut self, amount: u8) -> Self { let min = amount.min(self.item_count); let stack = self.copy_with_count(min); @@ -253,6 +259,7 @@ impl ItemStack { stack } + #[must_use] pub fn split_unless_creative(&mut self, gamemode: GameMode, amount: u8) -> Self { let min = amount.min(self.item_count); let stack = self.copy_with_count(min); @@ -262,13 +269,14 @@ impl ItemStack { stack } + #[must_use] pub fn copy_with_count(&self, count: u8) -> Self { let mut stack = self.clone(); stack.item_count = count; stack } - pub fn set_count(&mut self, count: u8) { + pub const fn set_count(&mut self, count: u8) { self.item_count = count; } @@ -278,11 +286,11 @@ impl ItemStack { } } - pub fn decrement(&mut self, amount: u8) { + pub const fn decrement(&mut self, amount: u8) { self.item_count = self.item_count.saturating_sub(amount); } - pub fn increment(&mut self, amount: u8) { + pub const fn increment(&mut self, amount: u8) { self.item_count = self.item_count.saturating_add(amount); } @@ -312,6 +320,8 @@ impl ItemStack { )); } } + + #[must_use] pub fn are_items_and_components_equal(&self, other: &Self) -> bool { if self.item != other.item || self.patch.len() != other.patch.len() { return false; @@ -323,16 +333,14 @@ impl ItemStack { if let (Some(data), Some(other_data)) = (data, other_data) { if data.equal(other_data.as_ref()) { return false; - } else { - not_find = false; - break 'out; } + not_find = false; + break 'out; } else if data.is_none() && other_data.is_none() { not_find = false; break 'out; - } else { - return false; } + return false; } } if not_find { @@ -342,6 +350,7 @@ impl ItemStack { true } + #[must_use] pub fn are_equal(&self, other: &Self) -> bool { self.item_count == other.item_count && self.are_items_and_components_equal(other) } @@ -349,6 +358,7 @@ impl ItemStack { /// Determines the mining speed for a block based on tool rules. /// Direct matches return immediately, tagged blocks are checked separately. /// If no match is found, returns the tool's default mining speed or `1.0`. + #[must_use] pub fn get_speed(&self, block: &'static Block) -> f32 { // No tool? Use default speed if let Some(tool) = self.get_data_component::() { @@ -378,6 +388,7 @@ impl ItemStack { /// Determines if a tool is valid for block drops based on tool rules. /// Direct matches return immediately, while tagged blocks are checked separately. + #[must_use] pub fn is_correct_for_drops(&self, block: &'static Block) -> bool { if let Some(tool) = self.get_data_component::() { for rule in tool.rules.iter() { @@ -398,10 +409,8 @@ impl ItemStack { } } } - false - } else { - false } + false } pub fn write_item_stack(&self, compound: &mut NbtCompound) { @@ -425,6 +434,7 @@ impl ItemStack { compound.put_component("components", tag); } + #[must_use] pub fn read_item_stack(compound: &NbtCompound) -> Option { // Get ID, which is a string like "minecraft:diamond_sword" let full_id = compound.get_string("id")?; diff --git a/pumpkin-world/src/level.rs b/pumpkin-world/src/level.rs index 87a1bc89f..26c647264 100644 --- a/pumpkin-world/src/level.rs +++ b/pumpkin-world/src/level.rs @@ -22,7 +22,7 @@ use pumpkin_data::dimension::Dimension; use pumpkin_data::{Block, block_properties::has_random_ticks, fluid::Fluid}; use pumpkin_util::math::{position::BlockPos, vector2::Vector2}; use pumpkin_util::world_seed::Seed; -use rand::{Rng, SeedableRng, rngs::SmallRng}; +use rand::{RngExt, SeedableRng, rngs::SmallRng}; use std::sync::Mutex; use tokio_util::sync::CancellationToken; // use std::time::Duration; @@ -196,53 +196,65 @@ impl Level { chunk_listener: listener.clone(), }); - let num_threads = num_cpus::get().saturating_sub(2).max(1); + // TODO + let total_cores = num_cpus::get().saturating_sub(2).max(1); + let threads_per_dimension = (total_cores / 2).max(1); + let entity_threads = (threads_per_dimension / 2).max(1); GenerationSchedule::create( - 4, - num_threads, + 2, + threads_per_dimension, level_ref.clone(), level_channel, listener, level_ref.thread_tracker.lock().unwrap().as_mut(), ); - for thread_id in 0..(num_threads / 2).max(1) { + let mut tracker_lock = level_ref.thread_tracker.lock().unwrap(); + + for thread_id in 0..entity_threads { let level_clone = level_ref.clone(); let pending_clone = pending_entity_generations.clone(); let rx = gen_entity_request_rx.clone(); - let builder = - thread::Builder::new().name(format!("Entity Chunk Generation Thread {thread_id}")); - - builder + let handle = thread::Builder::new() + .name(format!("Entity Chunk Generation Thread {thread_id}")) .spawn(move || { - while let Ok(pos) = rx.recv() { + loop { if level_clone.cancel_token.is_cancelled() { break; } - let chunk = ChunkEntityData { - x: pos.x, - z: pos.y, - data: HashMap::new(), - dirty: true, - }; - let arc_chunk = Arc::new(RwLock::new(chunk)); + match rx.recv_timeout(std::time::Duration::from_millis(500)) { + Ok(pos) => { + let arc_chunk = Arc::new(RwLock::new(ChunkEntityData { + x: pos.x, + z: pos.y, + data: HashMap::new(), + dirty: true, + })); - level_clone - .loaded_entity_chunks - .insert(pos, arc_chunk.clone()); + level_clone + .loaded_entity_chunks + .insert(pos, arc_chunk.clone()); - if let Some((_, waiters)) = pending_clone.remove(&pos) { - for tx in waiters { - let _ = tx.send(arc_chunk.clone()); + if let Some((_, waiters)) = pending_clone.remove(&pos) { + for tx in waiters { + let _ = tx.send(arc_chunk.clone()); + } + } } + Err(crossbeam::channel::RecvTimeoutError::Timeout) => continue, + Err(crossbeam::channel::RecvTimeoutError::Disconnected) => break, } } }) - .unwrap(); + .expect("Failed to spawn Entity Generation Thread"); + + tracker_lock.push(handle); } + + drop(tracker_lock); level_ref } @@ -334,13 +346,7 @@ impl Level { for chunk in chunks { self.chunk_watchers .entry(*chunk) - .and_modify(|value| { - if let Some(new_value) = value.checked_add(1) { - *value = new_value; - } else { - log::error!("Watching overflow on chunk {:?}", chunk); - } - }) + .and_modify(|count| *count = count.saturating_add(1)) .or_insert(1); } @@ -358,17 +364,21 @@ impl Level { let mut chunks_to_clean = Vec::new(); for chunk in chunks { - if let Some(mut count) = self.chunk_watchers.get_mut(chunk) { - let value = count.value_mut(); - *value = value.saturating_sub(1); + let mut should_remove = false; - if *value == 0 { - drop(count); - self.chunk_watchers.remove(chunk); - chunks_to_clean.push(*chunk); + if let Some(mut count) = self.chunk_watchers.get_mut(chunk) { + *count = count.saturating_sub(1); + if *count == 0 { + should_remove = true; } } + + if should_remove { + self.chunk_watchers.remove(chunk); + chunks_to_clean.push(*chunk); + } } + self.entity_saver .unwatch_chunks(&self.level_folder, chunks) .await; @@ -381,7 +391,7 @@ impl Level { !self.mark_chunks_as_not_watched(&[chunk]).await.is_empty() } - pub async fn clean_entity_chunks(self: &Arc, chunks: &[Vector2]) { + pub fn clean_entity_chunks(self: &Arc, chunks: &[Vector2]) { // Care needs to be take here because of interweaving case: // 1) Remove chunk from cache // 2) Another player wants same chunk @@ -430,7 +440,7 @@ impl Level { let mut ticks = TickData { block_ticks: Vec::new(), fluid_ticks: Vec::new(), - random_ticks: Vec::with_capacity(self.loaded_chunks.len() * 3 * 16 * 16), + random_ticks: Vec::with_capacity(self.loaded_chunks.len() * 3), block_entities: Vec::new(), }; @@ -476,16 +486,12 @@ impl Level { section_data .into_iter() .filter_map(|(random_pos, block_state_id)| { - if has_random_ticks(block_state_id) { - Some(ScheduledTick { - position: random_pos, - delay: 0, - priority: TickPriority::Normal, - value: (), - }) - } else { - None - } + has_random_ticks(block_state_id).then_some(ScheduledTick { + position: random_pos, + delay: 0, + priority: TickPriority::Normal, + value: (), + }) }), ); } @@ -510,8 +516,8 @@ impl Level { ticks } - pub async fn clean_entity_chunk(self: &Arc, chunk: &Vector2) { - self.clean_entity_chunks(&[*chunk]).await; + pub fn clean_entity_chunk(self: &Arc, chunk: &Vector2) { + self.clean_entity_chunks(&[*chunk]); } pub fn is_chunk_watched(&self, chunk: &Vector2) -> bool { @@ -552,7 +558,7 @@ impl Level { let mut lock = self.chunk_loading.lock().unwrap(); lock.add_ticket(pos, 31); lock.send_change(); - } + }; if let Some(chunk) = self.loaded_chunks.get(&pos) { chunk.clone() @@ -573,9 +579,8 @@ impl Level { match rx.recv().await { Some(LoadedData::Loaded(chunk)) => Ok((chunk, false)), - Some(LoadedData::Missing(_)) => Err(ChunkReadingError::ChunkNotExist), Some(LoadedData::Error((_, err))) => Err(err), - None => Err(ChunkReadingError::ChunkNotExist), + _ => Err(ChunkReadingError::ChunkNotExist), } } @@ -593,12 +598,10 @@ impl Level { let to_fetch: Vec<_> = chunks .iter() .filter(|pos| { - if let Some(chunk) = level.loaded_entity_chunks.get(pos) { + level.loaded_entity_chunks.get(pos).is_none_or(|chunk| { let _ = sender.send((chunk.clone(), false)); false // Don't fetch - } else { - true // Needs fetch - } + }) }) .copied() .collect(); @@ -661,24 +664,21 @@ impl Level { return chunk.clone(); } - match self.load_single_entity_chunk(pos).await { - Ok((chunk, _)) => { - self.loaded_entity_chunks.insert(pos, chunk.clone()); - chunk - } - Err(_) => { - let (tx, rx) = oneshot::channel(); - match self.pending_entity_generations.entry(pos) { - dashmap::mapref::entry::Entry::Occupied(mut entry) => { - entry.get_mut().push(tx); - } - dashmap::mapref::entry::Entry::Vacant(entry) => { - entry.insert(vec![tx]); - let _ = self.gen_entity_request_tx.send(pos); - } + if let Ok((chunk, _)) = self.load_single_entity_chunk(pos).await { + self.loaded_entity_chunks.insert(pos, chunk.clone()); + chunk + } else { + let (tx, rx) = oneshot::channel(); + match self.pending_entity_generations.entry(pos) { + dashmap::mapref::entry::Entry::Occupied(mut entry) => { + entry.get_mut().push(tx); + } + dashmap::mapref::entry::Entry::Vacant(entry) => { + entry.insert(vec![tx]); + let _ = self.gen_entity_request_tx.send(pos); } - rx.await.expect("Entity generation worker dropped") } + rx.await.expect("Entity generation worker dropped") } } @@ -794,7 +794,7 @@ impl Level { delay, position: block_pos, priority, - value: unsafe { &*(block as *const Block) }, + value: unsafe { &*std::ptr::from_ref::(block) }, }, tick_order, ); @@ -815,7 +815,7 @@ impl Level { delay, position: block_pos, priority, - value: unsafe { &*(fluid as *const Fluid) }, + value: unsafe { &*std::ptr::from_ref::(fluid) }, }, tick_order, ); diff --git a/pumpkin-world/src/poi/mod.rs b/pumpkin-world/src/poi/mod.rs index b6f79297d..66a8adb72 100644 --- a/pumpkin-world/src/poi/mod.rs +++ b/pumpkin-world/src/poi/mod.rs @@ -36,6 +36,7 @@ pub struct PoiEntry { } impl PoiEntry { + #[must_use] pub fn new_portal(pos: BlockPos) -> Self { Self { x: pos.0.x, @@ -46,7 +47,8 @@ impl PoiEntry { } } - pub fn pos(&self) -> BlockPos { + #[must_use] + pub const fn pos(&self) -> BlockPos { BlockPos(Vector3::new(self.x, self.y, self.z)) } } @@ -81,16 +83,17 @@ pub struct PoiRegion { } impl PoiRegion { + #[must_use] pub fn new() -> Self { Self::default() } - fn pos_key(pos: &BlockPos) -> (i32, i32, i32) { + const fn pos_key(pos: &BlockPos) -> (i32, i32, i32) { (pos.0.x, pos.0.y, pos.0.z) } /// Get chunk index in MCA file (0-1023) - fn chunk_index(chunk_x: i32, chunk_z: i32) -> usize { + const fn chunk_index(chunk_x: i32, chunk_z: i32) -> usize { let local_x = chunk_x & 31; let local_z = chunk_z & 31; ((local_z << 5) | local_x) as usize @@ -123,11 +126,13 @@ impl PoiRegion { false } + #[must_use] pub fn get_all(&self) -> Vec<&PoiEntry> { self.entries.values().collect() } - pub fn is_dirty(&self) -> bool { + #[must_use] + pub const fn is_dirty(&self) -> bool { self.dirty } @@ -351,7 +356,7 @@ impl PoiRegion { } } Err(e) => { - log::warn!("Failed to parse POI chunk at index {}: {}", index, e); + log::warn!("Failed to parse POI chunk at index {index}: {e}"); } } } @@ -365,11 +370,12 @@ impl PoiRegion { pub struct PoiStorage { /// Path to the poi folder folder: PathBuf, - /// Loaded regions, keyed by (region_x, region_z) + /// Loaded regions, keyed by (`region_x`, `region_z`) regions: HashMap<(i32, i32), PoiRegion>, } impl PoiStorage { + #[must_use] pub fn new(world_folder: &Path) -> Self { Self { folder: world_folder.join("poi"), @@ -377,14 +383,14 @@ impl PoiStorage { } } - fn region_coords(pos: &BlockPos) -> (i32, i32) { + const fn region_coords(pos: &BlockPos) -> (i32, i32) { let chunk_x = pos.0.x >> 4; let chunk_z = pos.0.z >> 4; (chunk_x >> 5, chunk_z >> 5) } fn region_path(&self, rx: i32, rz: i32) -> PathBuf { - self.folder.join(format!("r.{}.{}.mca", rx, rz)) + self.folder.join(format!("r.{rx}.{rz}.mca")) } fn get_or_load_region(&mut self, rx: i32, rz: i32) -> &mut PoiRegion { @@ -392,7 +398,7 @@ impl PoiStorage { let path = self.region_path(rx, rz); let region = PoiRegion::load(&path).unwrap_or_else(|e| { if path.exists() { - log::warn!("Failed to load POI region {:?}: {}", path, e); + log::warn!("Failed to load POI region {}: {}", path.display(), e); } PoiRegion::new() }); @@ -424,6 +430,7 @@ impl PoiStorage { } /// Get all POI positions within a square radius (for portal search) + #[expect(clippy::similar_names)] pub fn get_in_square( &mut self, center: BlockPos, @@ -471,14 +478,14 @@ impl PoiStorage { let mut saved = 0; for ((rx, rz), region) in &mut self.regions { if region.is_dirty() { - let path = self.folder.join(format!("r.{}.{}.mca", rx, rz)); + let path = self.folder.join(format!("r.{rx}.{rz}.mca")); region.save(&path)?; saved += 1; } } if saved > 0 { - log::info!("Saved {} POI region(s)", saved); + log::info!("Saved {saved} POI region(s)"); } Ok(()) } @@ -501,7 +508,7 @@ mod tests { use super::*; #[test] - fn test_poi_entry() { + fn poi_entry() { let entry = PoiEntry::new_portal(BlockPos(Vector3::new(100, 64, 200))); assert_eq!(entry.x, 100); assert_eq!(entry.y, 64); @@ -510,7 +517,7 @@ mod tests { } #[test] - fn test_poi_region() { + fn poi_region() { let mut region = PoiRegion::new(); region.add(PoiEntry::new_portal(BlockPos(Vector3::new(100, 64, 200)))); region.add(PoiEntry::new_portal(BlockPos(Vector3::new(101, 64, 200)))); @@ -523,7 +530,7 @@ mod tests { } #[test] - fn test_poi_storage_mca() { + fn poi_storage_mca() { let dir = std::env::temp_dir().join("pumpkin_poi_mca_test"); let _ = std::fs::remove_dir_all(&dir); diff --git a/pumpkin-world/src/tick/mod.rs b/pumpkin-world/src/tick/mod.rs index 2f148b3ea..fb3104b06 100644 --- a/pumpkin-world/src/tick/mod.rs +++ b/pumpkin-world/src/tick/mod.rs @@ -24,30 +24,35 @@ pub enum TickPriority { } impl TickPriority { - pub fn values() -> [TickPriority; 7] { + #[must_use] + pub const fn values() -> [Self; 7] { [ - TickPriority::ExtremelyHigh, - TickPriority::VeryHigh, - TickPriority::High, - TickPriority::Normal, - TickPriority::Low, - TickPriority::VeryLow, - TickPriority::ExtremelyLow, + Self::ExtremelyHigh, + Self::VeryHigh, + Self::High, + Self::Normal, + Self::Low, + Self::VeryLow, + Self::ExtremelyLow, ] } } -impl From for TickPriority { - fn from(value: i32) -> Self { +#[derive(Debug)] +pub struct TickPriorityNotFound; + +impl TryFrom for TickPriority { + type Error = TickPriorityNotFound; + fn try_from(value: i32) -> Result { match value { - -3 => TickPriority::ExtremelyHigh, - -2 => TickPriority::VeryHigh, - -1 => TickPriority::High, - 0 => TickPriority::Normal, - 1 => TickPriority::Low, - 2 => TickPriority::VeryLow, - 3 => TickPriority::ExtremelyLow, - _ => panic!("Invalid tick priority: {value}"), + -3 => Ok(Self::ExtremelyHigh), + -2 => Ok(Self::VeryHigh), + -1 => Ok(Self::High), + 0 => Ok(Self::Normal), + 1 => Ok(Self::Low), + 2 => Ok(Self::VeryLow), + 3 => Ok(Self::ExtremelyLow), + _ => Err(TickPriorityNotFound), } } } @@ -70,7 +75,7 @@ pub struct OrderedTick { } impl OrderedTick { - pub fn new(position: BlockPos, value: T) -> Self { + pub const fn new(position: BlockPos, value: T) -> Self { Self { priority: TickPriority::Normal, sub_tick_order: 0, @@ -134,13 +139,13 @@ where let y = nbt.get_int("y").unwrap(); let z = nbt.get_int("z").unwrap(); let delay = nbt.get_int("t").unwrap() as u8; - let priority = TickPriority::from(nbt.get_int("p").unwrap()); + let priority = TickPriority::try_from(nbt.get_int("p").unwrap()).unwrap(); let value = T::from_resource_location( &ResourceLocation::from_str(nbt.get_string("i").unwrap()).unwrap(), ) .unwrap(); - ScheduledTick { + Self { delay, priority, position: BlockPos::new(x, y, z), diff --git a/pumpkin-world/src/tick/scheduler.rs b/pumpkin-world/src/tick/scheduler.rs index b250c3934..0825ff1b8 100644 --- a/pumpkin-world/src/tick/scheduler.rs +++ b/pumpkin-world/src/tick/scheduler.rs @@ -40,6 +40,7 @@ impl<'a, T: std::hash::Hash + Eq> ChunkTickScheduler<&'a T> { self.queued_ticks.contains(&(pos, value)) } + #[must_use] pub fn to_vec(&self) -> Vec> { let mut res = Vec::new(); for i in 0..MAX_TICK_DELAY { diff --git a/pumpkin-world/src/world.rs b/pumpkin-world/src/world.rs index 2ef656c42..bc7b58631 100644 --- a/pumpkin-world/src/world.rs +++ b/pumpkin-world/src/world.rs @@ -63,12 +63,12 @@ impl std::fmt::Display for GetBlockError { pub type WorldFuture<'a, T> = Pin + Send + 'a>>; pub trait SimpleWorld: BlockAccessor + Send + Sync { - fn set_block_state<'a>( + fn set_block_state( self: Arc, - position: &'a BlockPos, + position: &BlockPos, block_state_id: BlockStateId, flags: BlockFlags, - ) -> WorldFuture<'a, BlockStateId>; + ) -> WorldFuture<'_, BlockStateId>; fn update_neighbor<'a>( self: Arc, @@ -76,13 +76,13 @@ pub trait SimpleWorld: BlockAccessor + Send + Sync { source_block: &'a pumpkin_data::Block, ) -> WorldFuture<'a, ()>; - fn update_neighbors<'a>( + fn update_neighbors( self: Arc, - block_pos: &'a BlockPos, + block_pos: &BlockPos, except: Option, - ) -> WorldFuture<'a, ()>; + ) -> WorldFuture<'_, ()>; - fn is_space_empty<'a>(&'a self, bounding_box: BoundingBox) -> WorldFuture<'a, bool>; + fn is_space_empty(&self, bounding_box: BoundingBox) -> WorldFuture<'_, bool>; fn spawn_from_type( self: Arc, @@ -90,19 +90,14 @@ pub trait SimpleWorld: BlockAccessor + Send + Sync { position: Vector3, ) -> WorldFuture<'static, ()>; - fn add_synced_block_event<'a>( - &'a self, - pos: BlockPos, - r#type: u8, - data: u8, - ) -> WorldFuture<'a, ()>; + fn add_synced_block_event(&self, pos: BlockPos, r#type: u8, data: u8) -> WorldFuture<'_, ()>; - fn sync_world_event<'a>( - &'a self, + fn sync_world_event( + &self, world_event: WorldEvent, position: BlockPos, data: i32, - ) -> WorldFuture<'a, ()>; + ) -> WorldFuture<'_, ()>; fn remove_block_entity<'a>(&'a self, block_pos: &'a BlockPos) -> WorldFuture<'a, ()>; @@ -111,7 +106,7 @@ pub trait SimpleWorld: BlockAccessor + Send + Sync { block_pos: &'a BlockPos, ) -> WorldFuture<'a, Option>>; - fn get_world_age<'a>(&'a self) -> WorldFuture<'a, i64>; + fn get_world_age(&self) -> WorldFuture<'_, i64>; fn play_sound<'a>( &'a self, diff --git a/pumpkin-world/src/world_info/anvil.rs b/pumpkin-world/src/world_info/anvil.rs index 5caa3d243..462cefe3c 100644 --- a/pumpkin-world/src/world_info/anvil.rs +++ b/pumpkin-world/src/world_info/anvil.rs @@ -43,12 +43,12 @@ fn check_file_data_version(raw_nbt: &[u8]) -> Result<(), WorldInfoError> { let data_version = info.data.data_version; - if !(MINIMUM_SUPPORTED_WORLD_DATA_VERSION..=MAXIMUM_SUPPORTED_WORLD_DATA_VERSION) + if (MINIMUM_SUPPORTED_WORLD_DATA_VERSION..=MAXIMUM_SUPPORTED_WORLD_DATA_VERSION) .contains(&data_version) { - Err(WorldInfoError::UnsupportedDataVersion(data_version)) - } else { Ok(()) + } else { + Err(WorldInfoError::UnsupportedDataVersion(data_version)) } } @@ -70,11 +70,11 @@ fn check_file_level_version(raw_nbt: &[u8]) -> Result<(), WorldInfoError> { let level_version = info.data.version; - if !(MINIMUM_SUPPORTED_LEVEL_VERSION..=MAXIMUM_SUPPORTED_LEVEL_VERSION).contains(&level_version) + if (MINIMUM_SUPPORTED_LEVEL_VERSION..=MAXIMUM_SUPPORTED_LEVEL_VERSION).contains(&level_version) { - Err(WorldInfoError::UnsupportedLevelVersion(level_version)) - } else { Ok(()) + } else { + Err(WorldInfoError::UnsupportedLevelVersion(level_version)) } } @@ -159,7 +159,7 @@ mod test { use super::{AnvilLevelInfo, LEVEL_DAT_FILE_NAME, LevelDat, WorldInfoReader, WorldInfoWriter}; #[test] - fn test_preserve_level_dat_seed() { + fn preserve_level_dat_seed() { let seed = 1337; let data = LevelData::default(Seed(1337)); @@ -249,7 +249,7 @@ mod test { }); #[test] - fn test_deserialize_level_dat() { + fn deserialize_level_dat() { let raw_compressed_nbt = fs::read("assets/level_1_21_4.dat").unwrap(); assert!(!raw_compressed_nbt.is_empty()); @@ -262,7 +262,7 @@ mod test { } #[test] - fn test_serialize_level_dat() { + fn serialize_level_dat() { let mut serialized = Vec::new(); to_bytes(&*LEVEL_DAT, &mut serialized).expect("Failed to encode to bytes"); diff --git a/pumpkin-world/src/world_info/mod.rs b/pumpkin-world/src/world_info/mod.rs index 5b3221ed5..ef42a85ca 100644 --- a/pumpkin-world/src/world_info/mod.rs +++ b/pumpkin-world/src/world_info/mod.rs @@ -94,7 +94,7 @@ pub struct LevelData { pub level_version: i32, // TODO: Implement the rest of the fields } -#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)] +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)] pub struct WorldGenSettings { // the numerical seed of the world pub seed: i64, @@ -102,14 +102,14 @@ pub struct WorldGenSettings { } pub type Dimensions = HashMap; -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] pub struct Dimension { pub generator: Generator, #[serde(rename = "type")] pub dimension_type: String, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] pub struct Generator { pub settings: String, pub biome_source: BiomeSource, @@ -117,7 +117,7 @@ pub struct Generator { pub generator_type: String, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(untagged)] pub enum BiomeSource { WithPreset { @@ -131,7 +131,7 @@ pub enum BiomeSource { }, } -#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)] +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)] #[serde(rename_all = "PascalCase")] pub struct DataPacks { // List of disabled data packs. @@ -194,7 +194,7 @@ impl WorldGenSettings { } } -#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)] +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)] #[serde(rename_all = "PascalCase")] pub struct WorldVersion { // The version name as a string, e.g. "15w32b". @@ -219,6 +219,7 @@ impl Default for WorldVersion { } impl LevelData { + #[must_use] pub fn default(seed: Seed) -> Self { Self { allow_commands: true, @@ -249,12 +250,12 @@ impl LevelData { spawn_z: 0, spawn_yaw: 0.0, spawn_pitch: 0.0, - world_version: Default::default(), + world_version: WorldVersion::default(), level_version: MAXIMUM_SUPPORTED_LEVEL_VERSION, } } - pub fn set_pos(&mut self, x: i32, z: i32) { + pub const fn set_pos(&mut self, x: i32, z: i32) { self.spawn_x = x; self.spawn_z = z; } diff --git a/pumpkin/Cargo.toml b/pumpkin/Cargo.toml index 35e0d25c0..90fa2b118 100644 --- a/pumpkin/Cargo.toml +++ b/pumpkin/Cargo.toml @@ -53,6 +53,7 @@ bytes.workspace = true rand.workspace = true num-bigint.workspace = true +dashmap.workspace = true # Console line reading rustyline.workspace = true diff --git a/pumpkin/src/block/blocks/bed.rs b/pumpkin/src/block/blocks/bed.rs index ff843b711..ec016f16b 100644 --- a/pumpkin/src/block/blocks/bed.rs +++ b/pumpkin/src/block/blocks/bed.rs @@ -310,7 +310,7 @@ impl BlockBehaviour for BedBlock { } // Make sure there are no monsters nearby - for entity in args.world.entities.read().await.values() { + for entity in args.world.entities.load().iter() { if !entity_prevents_sleep(entity.get_entity()) { continue; } diff --git a/pumpkin/src/block/blocks/cake.rs b/pumpkin/src/block/blocks/cake.rs index b6b1db200..a84e534a9 100644 --- a/pumpkin/src/block/blocks/cake.rs +++ b/pumpkin/src/block/blocks/cake.rs @@ -22,7 +22,7 @@ use pumpkin_world::{ tick::TickPriority, world::{BlockAccessor, BlockFlags}, }; -use rand::{Rng, rng}; +use rand::{RngExt, rng}; #[pumpkin_block("minecraft:cake")] pub struct CakeBlock; diff --git a/pumpkin/src/block/blocks/chiseled_bookshelf.rs b/pumpkin/src/block/blocks/chiseled_bookshelf.rs index b8d4afb85..564933dd7 100644 --- a/pumpkin/src/block/blocks/chiseled_bookshelf.rs +++ b/pumpkin/src/block/blocks/chiseled_bookshelf.rs @@ -240,7 +240,7 @@ impl ChiseledBookshelfBlock { } } - fn is_slot_used(properties: ChiseledBookshelfLikeProperties, slot: i8) -> bool { + const fn is_slot_used(properties: ChiseledBookshelfLikeProperties, slot: i8) -> bool { match slot { 0 => properties.slot_0_occupied, 1 => properties.slot_1_occupied, diff --git a/pumpkin/src/block/blocks/command.rs b/pumpkin/src/block/blocks/command.rs index cb3c5dcde..e90cb9689 100644 --- a/pumpkin/src/block/blocks/command.rs +++ b/pumpkin/src/block/blocks/command.rs @@ -127,7 +127,7 @@ impl CommandBlock { block_entity: Arc, command: &str, ) { - let command_blocks_work = { world.level_info.read().await.game_rules.command_blocks_work }; + let command_blocks_work = { world.level_info.load().game_rules.command_blocks_work }; if !command_blocks_work { return; } @@ -158,8 +158,7 @@ impl CommandBlock { let mut pos = start; while i > 0 { - let command_blocks_work = - { world.level_info.read().await.game_rules.command_blocks_work }; + let command_blocks_work = { world.level_info.load().game_rules.command_blocks_work }; if !command_blocks_work { return; } @@ -238,14 +237,8 @@ impl BlockBehaviour for CommandBlock { fn on_neighbor_update<'a>(&'a self, args: OnNeighborUpdateArgs<'a>) -> BlockFuture<'a, ()> { Box::pin(async move { - let command_blocks_work = { - args.world - .level_info - .read() - .await - .game_rules - .command_blocks_work - }; + let command_blocks_work = + { args.world.level_info.load().game_rules.command_blocks_work }; if !command_blocks_work { return; } @@ -272,14 +265,8 @@ impl BlockBehaviour for CommandBlock { fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> { Box::pin(async move { - let command_blocks_work = { - args.world - .level_info - .read() - .await - .game_rules - .command_blocks_work - }; + let command_blocks_work = + { args.world.level_info.load().game_rules.command_blocks_work }; if !command_blocks_work { return; } @@ -342,7 +329,7 @@ impl BlockBehaviour for CommandBlock { fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> { Box::pin(async move { let send_command_feedback = { - let game_rules = &args.world.level_info.read().await.game_rules; + let game_rules = &args.world.level_info.load().game_rules; game_rules.send_command_feedback }; diff --git a/pumpkin/src/block/blocks/composter.rs b/pumpkin/src/block/blocks/composter.rs index 9383f978c..c46c58243 100644 --- a/pumpkin/src/block/blocks/composter.rs +++ b/pumpkin/src/block/blocks/composter.rs @@ -20,7 +20,7 @@ use pumpkin_inventory::screen_handler::InventoryPlayer; use pumpkin_macros::pumpkin_block; use pumpkin_util::math::position::BlockPos; use pumpkin_world::{BlockStateId, item::ItemStack, tick::TickPriority, world::BlockFlags}; -use rand::Rng; +use rand::RngExt; #[pumpkin_block("minecraft:composter")] pub struct ComposterBlock; diff --git a/pumpkin/src/block/blocks/end_portal.rs b/pumpkin/src/block/blocks/end_portal.rs index e8a0b5f3f..8d249a8f5 100644 --- a/pumpkin/src/block/blocks/end_portal.rs +++ b/pumpkin/src/block/blocks/end_portal.rs @@ -15,13 +15,9 @@ impl BlockBehaviour for EndPortalBlock { fn on_entity_collision<'a>(&'a self, args: OnEntityCollisionArgs<'a>) -> BlockFuture<'a, ()> { Box::pin(async move { let world = if args.world.dimension == Dimension::THE_END { - args.server - .get_world_from_dimension(&Dimension::OVERWORLD) - .await + args.server.get_world_from_dimension(&Dimension::OVERWORLD) } else { - args.server - .get_world_from_dimension(&Dimension::THE_END) - .await + args.server.get_world_from_dimension(&Dimension::THE_END) }; args.entity .get_entity() diff --git a/pumpkin/src/block/blocks/fire/fire.rs b/pumpkin/src/block/blocks/fire/fire.rs index a6983735d..528cbf397 100644 --- a/pumpkin/src/block/blocks/fire/fire.rs +++ b/pumpkin/src/block/blocks/fire/fire.rs @@ -4,7 +4,7 @@ use pumpkin_data::entity::EntityType; use pumpkin_data::fluid::Fluid; use pumpkin_util::math::vector3::Vector3; use pumpkin_world::world::{BlockAccessor, BlockFlags}; -use rand::Rng; +use rand::RngExt; use std::sync::Arc; use std::sync::atomic::Ordering; @@ -374,6 +374,7 @@ impl BlockBehaviour for FireBlock { ) .await; + let difficulty = world.level_info.load().difficulty as i32; for l in -1..=1 { for m in -1..=1 { for n in -1..=4 { @@ -382,10 +383,8 @@ impl BlockBehaviour for FireBlock { let burn_chance = Self.get_burn_chance(world, &offset_pos).await; if burn_chance > 0 { let o = 100 + if n > 1 { (n - 1) * 100 } else { 0 }; - let p: i32 = burn_chance - + 40 - + (world.level_info.read().await.difficulty as i32) * 7 - / i32::from(age + 30); + let p: i32 = + burn_chance + 40 + (difficulty) * 7 / i32::from(age + 30); if p > 0 && rand::rng().random_range(0..o) <= p { let new_age = diff --git a/pumpkin/src/block/blocks/fire/mod.rs b/pumpkin/src/block/blocks/fire/mod.rs index c01f61d53..28530f19e 100644 --- a/pumpkin/src/block/blocks/fire/mod.rs +++ b/pumpkin/src/block/blocks/fire/mod.rs @@ -7,7 +7,7 @@ use pumpkin_data::{Block, BlockDirection, tag}; use pumpkin_util::math::position::BlockPos; use pumpkin_util::random::RandomGenerator; use pumpkin_util::random::xoroshiro128::Xoroshiro; -use rand::Rng; +use rand::RngExt; use soul_fire::SoulFireBlock; use crate::block::blocks::fire::fire::FireBlock; diff --git a/pumpkin/src/block/blocks/nether_portal.rs b/pumpkin/src/block/blocks/nether_portal.rs index c046571f4..9b286978b 100644 --- a/pumpkin/src/block/blocks/nether_portal.rs +++ b/pumpkin/src/block/blocks/nether_portal.rs @@ -22,19 +22,18 @@ pub struct NetherPortalBlock; impl NetherPortalBlock { /// Gets the portal delay time based on entity type and gamemode - async fn get_portal_time(world: &Arc, entity: &dyn EntityBase) -> u32 { + fn get_portal_time(world: &Arc, entity: &dyn EntityBase) -> u32 { let entity_type = entity.get_entity().entity_type; - let level_info = world.level_info.read().await; + let level_info = world.level_info.load(); match entity_type.id { id if id == EntityType::PLAYER.id => (world - .get_player_by_id(entity.get_entity().entity_id) - .await) - .map_or(80, |player| match player.gamemode.load() { - GameMode::Creative => { - level_info.game_rules.players_nether_portal_creative_delay as u32 - } - _ => level_info.game_rules.players_nether_portal_default_delay as u32, - }), + .get_player_by_id(entity.get_entity().entity_id)) + .map_or(80, |player| match player.gamemode.load() { + GameMode::Creative => { + level_info.game_rules.players_nether_portal_creative_delay as u32 + } + _ => level_info.game_rules.players_nether_portal_default_delay as u32, + }), _ => 0, } } @@ -73,16 +72,12 @@ impl BlockBehaviour for NetherPortalBlock { fn on_entity_collision<'a>(&'a self, args: OnEntityCollisionArgs<'a>) -> BlockFuture<'a, ()> { Box::pin(async move { let target_world = if args.world.dimension == Dimension::THE_NETHER { - args.server - .get_world_from_dimension(&Dimension::OVERWORLD) - .await + args.server.get_world_from_dimension(&Dimension::OVERWORLD) } else { - args.server - .get_world_from_dimension(&Dimension::THE_NETHER) - .await + args.server.get_world_from_dimension(&Dimension::THE_NETHER) }; - let portal_delay = Self::get_portal_time(args.world, args.entity).await; + let portal_delay = Self::get_portal_time(args.world, args.entity); args.entity .get_entity() diff --git a/pumpkin/src/block/blocks/note.rs b/pumpkin/src/block/blocks/note.rs index 855b74775..d7f94da91 100644 --- a/pumpkin/src/block/blocks/note.rs +++ b/pumpkin/src/block/blocks/note.rs @@ -33,7 +33,7 @@ impl NoteBlock { } } fn get_note_pitch(note: u16) -> f32 { - 2.0f32.powf((f32::from(note) - 12.0) / 12.0) + ((f32::from(note) - 12.0) / 12.0).exp2() } async fn get_state_with_instrument( @@ -176,7 +176,7 @@ impl BlockBehaviour for NoteBlock { } } -fn convert_instrument_to_sound(instrument: Instrument) -> Sound { +const fn convert_instrument_to_sound(instrument: Instrument) -> Sound { match instrument { Instrument::Harp => Sound::BlockNoteBlockHarp, Instrument::Basedrum => Sound::BlockNoteBlockBasedrum, @@ -204,7 +204,7 @@ fn convert_instrument_to_sound(instrument: Instrument) -> Sound { } } -fn is_base_block(instrument: Instrument) -> bool { +const fn is_base_block(instrument: Instrument) -> bool { matches!( instrument, Instrument::Harp diff --git a/pumpkin/src/block/blocks/piston/piston.rs b/pumpkin/src/block/blocks/piston/piston.rs index 11f255c83..7dc90ab42 100644 --- a/pumpkin/src/block/blocks/piston/piston.rs +++ b/pumpkin/src/block/blocks/piston/piston.rs @@ -14,7 +14,7 @@ use pumpkin_world::{ block::entities::{has_block_block_entity, piston::PistonBlockEntity}, world::BlockFlags, }; -use rand::Rng; +use rand::RngExt; use crate::{ block::{ diff --git a/pumpkin/src/block/blocks/plant/bamboo.rs b/pumpkin/src/block/blocks/plant/bamboo.rs index b6f8b10c4..cb76d1064 100644 --- a/pumpkin/src/block/blocks/plant/bamboo.rs +++ b/pumpkin/src/block/blocks/plant/bamboo.rs @@ -13,7 +13,7 @@ use pumpkin_util::math::position::BlockPos; use pumpkin_world::BlockStateId; use pumpkin_world::tick::TickPriority; use pumpkin_world::world::{BlockAccessor, BlockFlags}; -use rand::Rng; +use rand::RngExt; use crate::block::registry::BlockActionResult; use crate::block::{BlockBehaviour, BlockFuture, CanPlaceAtArgs, blocks::plant::PlantBlockBase}; diff --git a/pumpkin/src/block/blocks/plant/bamboo_sapling.rs b/pumpkin/src/block/blocks/plant/bamboo_sapling.rs index 62ebbd09c..40b2a5447 100644 --- a/pumpkin/src/block/blocks/plant/bamboo_sapling.rs +++ b/pumpkin/src/block/blocks/plant/bamboo_sapling.rs @@ -10,7 +10,7 @@ use pumpkin_world::{ BlockStateId, world::{BlockAccessor, BlockFlags}, }; -use rand::Rng; +use rand::RngExt; use crate::block::{ BlockBehaviour, BlockFuture, CanPlaceAtArgs, GetStateForNeighborUpdateArgs, diff --git a/pumpkin/src/block/blocks/plant/cactus.rs b/pumpkin/src/block/blocks/plant/cactus.rs index 87380cb08..1f35aaf69 100644 --- a/pumpkin/src/block/blocks/plant/cactus.rs +++ b/pumpkin/src/block/blocks/plant/cactus.rs @@ -9,7 +9,7 @@ use pumpkin_util::math::position::BlockPos; use pumpkin_world::BlockStateId; use pumpkin_world::tick::TickPriority; use pumpkin_world::world::{BlockAccessor, BlockFlags}; -use rand::Rng; +use rand::RngExt; use crate::block::{ BlockBehaviour, BlockFuture, CanPlaceAtArgs, GetStateForNeighborUpdateArgs, diff --git a/pumpkin/src/block/blocks/plant/crop/beetroot.rs b/pumpkin/src/block/blocks/plant/crop/beetroot.rs index 34ba58caa..fed58be93 100644 --- a/pumpkin/src/block/blocks/plant/crop/beetroot.rs +++ b/pumpkin/src/block/blocks/plant/crop/beetroot.rs @@ -4,7 +4,7 @@ use pumpkin_data::block_properties::{ }; use pumpkin_macros::pumpkin_block; use pumpkin_world::BlockStateId; -use rand::Rng; +use rand::RngExt; use crate::block::blocks::plant::PlantBlockBase; use crate::block::blocks::plant::crop::CropBlockBase; diff --git a/pumpkin/src/block/blocks/plant/crop/gourds/stem.rs b/pumpkin/src/block/blocks/plant/crop/gourds/stem.rs index 139c827d7..677b98add 100644 --- a/pumpkin/src/block/blocks/plant/crop/gourds/stem.rs +++ b/pumpkin/src/block/blocks/plant/crop/gourds/stem.rs @@ -19,7 +19,7 @@ use pumpkin_world::{ BlockStateId, world::{BlockAccessor, BlockFlags}, }; -use rand::Rng; +use rand::RngExt; type StemProperties = WheatLikeProperties; type AttachedStemProperties = WallTorchLikeProperties; diff --git a/pumpkin/src/block/blocks/plant/crop/mod.rs b/pumpkin/src/block/blocks/plant/crop/mod.rs index 0b43d67b7..6cd29840d 100644 --- a/pumpkin/src/block/blocks/plant/crop/mod.rs +++ b/pumpkin/src/block/blocks/plant/crop/mod.rs @@ -12,7 +12,7 @@ use pumpkin_world::{ BlockStateId, world::{BlockAccessor, BlockFlags}, }; -use rand::Rng; +use rand::RngExt; use crate::{block::blocks::plant::PlantBlockBase, world::World}; diff --git a/pumpkin/src/block/blocks/plant/crop/nether_wart.rs b/pumpkin/src/block/blocks/plant/crop/nether_wart.rs index b6d76d44d..4c73c0484 100644 --- a/pumpkin/src/block/blocks/plant/crop/nether_wart.rs +++ b/pumpkin/src/block/blocks/plant/crop/nether_wart.rs @@ -10,7 +10,7 @@ use pumpkin_world::{ BlockStateId, world::{BlockAccessor, BlockFlags}, }; -use rand::Rng; +use rand::RngExt; use crate::{ block::{ diff --git a/pumpkin/src/block/blocks/plant/crop/sweet_berry_bush.rs b/pumpkin/src/block/blocks/plant/crop/sweet_berry_bush.rs index 78c9a22c7..d709989d4 100644 --- a/pumpkin/src/block/blocks/plant/crop/sweet_berry_bush.rs +++ b/pumpkin/src/block/blocks/plant/crop/sweet_berry_bush.rs @@ -15,7 +15,7 @@ use pumpkin_world::{ item::ItemStack, world::{BlockAccessor, BlockFlags}, }; -use rand::Rng; +use rand::RngExt; use crate::{ block::{ diff --git a/pumpkin/src/block/blocks/plant/crop/torch_flower.rs b/pumpkin/src/block/blocks/plant/crop/torch_flower.rs index 13fd89333..eb5815fc3 100644 --- a/pumpkin/src/block/blocks/plant/crop/torch_flower.rs +++ b/pumpkin/src/block/blocks/plant/crop/torch_flower.rs @@ -4,7 +4,7 @@ use pumpkin_data::block_properties::{ }; use pumpkin_macros::pumpkin_block; use pumpkin_world::BlockStateId; -use rand::Rng; +use rand::RngExt; use crate::block::blocks::plant::PlantBlockBase; use crate::block::blocks::plant::crop::CropBlockBase; diff --git a/pumpkin/src/block/blocks/plant/sea_pickles.rs b/pumpkin/src/block/blocks/plant/sea_pickles.rs index 1f0672b33..b35c1ea25 100644 --- a/pumpkin/src/block/blocks/plant/sea_pickles.rs +++ b/pumpkin/src/block/blocks/plant/sea_pickles.rs @@ -15,7 +15,7 @@ use pumpkin_macros::pumpkin_block; use pumpkin_util::math::position::BlockPos; use pumpkin_world::BlockStateId; use pumpkin_world::world::BlockFlags; -use rand::Rng; +use rand::RngExt; type SeaPickleProperties = pumpkin_data::block_properties::SeaPickleLikeProperties; diff --git a/pumpkin/src/block/blocks/redstone/comparator.rs b/pumpkin/src/block/blocks/redstone/comparator.rs index fc077a28a..b025edcba 100644 --- a/pumpkin/src/block/blocks/redstone/comparator.rs +++ b/pumpkin/src/block/blocks/redstone/comparator.rs @@ -272,9 +272,7 @@ impl RedstoneGateBlock for ComparatorBlock { let (source_block, source_state) = world.get_block_and_state(&source_pos).await; // Note: self.get_attached_itemframe_level is assumed to be an async method - let itemframe_level = self - .get_attached_itemframe_level(world, facing, source_pos) - .await; + let itemframe_level = Self::get_attached_itemframe_level(world, facing, source_pos); let block_level = if let Some(pumpkin_block) = world.block_registry.get_pumpkin_block(source_block.id) { @@ -345,15 +343,13 @@ impl ComparatorBlock { } } - async fn get_attached_itemframe_level( - &self, + fn get_attached_itemframe_level( world: &World, facing: HorizontalFacing, pos: BlockPos, ) -> Option { let mut itemframes = world .get_entities_at_box(&BoundingBox::from_block(&pos)) - .await .into_iter() .filter(|entity| { entity.get_entity().entity_type == &EntityType::ITEM_FRAME diff --git a/pumpkin/src/block/blocks/redstone/dropper.rs b/pumpkin/src/block/blocks/redstone/dropper.rs index c4c822a06..68ba8ea70 100644 --- a/pumpkin/src/block/blocks/redstone/dropper.rs +++ b/pumpkin/src/block/blocks/redstone/dropper.rs @@ -25,7 +25,7 @@ use pumpkin_world::block::entities::hopper::HopperBlockEntity; use pumpkin_world::inventory::Inventory; use pumpkin_world::tick::TickPriority; use pumpkin_world::world::BlockFlags; -use rand::{Rng, rng}; +use rand::{Rng, RngExt, rng}; use std::sync::Arc; use tokio::sync::Mutex; @@ -57,7 +57,7 @@ pub struct DropperBlock; type DispenserLikeProperties = pumpkin_data::block_properties::DispenserLikeProperties; fn triangle(rng: &mut R, min: f64, max: f64) -> f64 { - min + (rng.random::() - rng.random::()) * max + (rng.random::() - rng.random::()).mul_add(max, min) } const fn to_normal(facing: Facing) -> Vector3 { @@ -200,7 +200,7 @@ impl BlockBehaviour for DropperBlock { _ => 0.15625, }; let entity = Entity::new(args.world.clone(), position, &EntityType::ITEM); - let rd = rng().random::() * 0.1 + 0.2; + let rd = rng().random::().mul_add(0.1, 0.2); let velocity = Vector3::new( triangle(&mut rng(), facing.x * rd, 0.017_227_5 * 6.), triangle(&mut rng(), 0.2, 0.017_227_5 * 6.), diff --git a/pumpkin/src/block/blocks/redstone/pressure_plate/plate.rs b/pumpkin/src/block/blocks/redstone/pressure_plate/plate.rs index 7ad73fb2b..625fbdd84 100644 --- a/pumpkin/src/block/blocks/redstone/pressure_plate/plate.rs +++ b/pumpkin/src/block/blocks/redstone/pressure_plate/plate.rs @@ -102,8 +102,8 @@ impl PressurePlate for PressurePlateBlock { async fn calculate_redstone_output(&self, world: &World, _block: &Block, pos: &BlockPos) -> u8 { // TODO: this is bad use real box let aabb = BoundingBox::from_block(pos); - if !world.get_entities_at_box(&aabb).await.is_empty() - || !world.get_players_at_box(&aabb).await.is_empty() + if !world.get_entities_at_box(&aabb).is_empty() + || !world.get_players_at_box(&aabb).is_empty() { return 15; } diff --git a/pumpkin/src/block/blocks/redstone/pressure_plate/weighted.rs b/pumpkin/src/block/blocks/redstone/pressure_plate/weighted.rs index 61fb12042..350b5ce6f 100644 --- a/pumpkin/src/block/blocks/redstone/pressure_plate/weighted.rs +++ b/pumpkin/src/block/blocks/redstone/pressure_plate/weighted.rs @@ -113,8 +113,7 @@ impl PressurePlate for WeightedPressurePlateBlock { }; // TODO: this is bad use real box let aabb = BoundingBox::from_block(pos); - let len = world.get_entities_at_box(&aabb).await.len() - + world.get_players_at_box(&aabb).await.len(); + let len = world.get_entities_at_box(&aabb).len() + world.get_players_at_box(&aabb).len(); let len = len.min(weight); if len > 0 { let f = (weight.min(len) / weight) as f32; diff --git a/pumpkin/src/block/blocks/redstone/rails/mod.rs b/pumpkin/src/block/blocks/redstone/rails/mod.rs index 364071222..9bf4b07a3 100644 --- a/pumpkin/src/block/blocks/redstone/rails/mod.rs +++ b/pumpkin/src/block/blocks/redstone/rails/mod.rs @@ -182,14 +182,14 @@ impl RailProperties { } } - fn can_curve(&self) -> bool { + const fn can_curve(&self) -> bool { match self { Self::Rail(_) => true, Self::StraightRail(_) => false, } } - fn shape(&self) -> RailShape { + const fn shape(&self) -> RailShape { match self { Self::Rail(props) => props.shape, Self::StraightRail(props) => match props.shape { @@ -203,7 +203,7 @@ impl RailProperties { } } - fn directions(&self) -> [HorizontalFacing; 2] { + const fn directions(&self) -> [HorizontalFacing; 2] { match self { Self::Rail(props) => match props.shape { RailShape::EastWest | RailShape::AscendingEast | RailShape::AscendingWest => { @@ -241,7 +241,7 @@ impl RailProperties { } } - fn set_waterlogged(&mut self, waterlogged: bool) { + const fn set_waterlogged(&mut self, waterlogged: bool) { match self { Self::Rail(props) => props.waterlogged = waterlogged, Self::StraightRail(props) => props.waterlogged = waterlogged, @@ -272,14 +272,14 @@ impl RailProperties { } } - fn is_powered(&self) -> bool { + const fn is_powered(&self) -> bool { match self { Self::Rail(_) => false, Self::StraightRail(props) => props.powered, } } - fn set_powered(&mut self, powered: bool) { + const fn set_powered(&mut self, powered: bool) { match self { Self::Rail(_) => {} Self::StraightRail(props) => props.powered = powered, diff --git a/pumpkin/src/block/blocks/redstone/redstone_wire.rs b/pumpkin/src/block/blocks/redstone/redstone_wire.rs index e0056276d..8237a3028 100644 --- a/pumpkin/src/block/blocks/redstone/redstone_wire.rs +++ b/pumpkin/src/block/blocks/redstone/redstone_wire.rs @@ -252,7 +252,7 @@ async fn on_use(wire: RedstoneWireProperties, world: &Arc, block_pos: &Bl } #[must_use] -pub fn make_cross(power: Integer0To15) -> RedstoneWireProperties { +pub const fn make_cross(power: Integer0To15) -> RedstoneWireProperties { RedstoneWireProperties { north: NorthWireConnection::Side, south: SouthWireConnection::Side, @@ -428,7 +428,7 @@ impl WireConnection { self == Self::None } - fn to_north(self) -> NorthWireConnection { + const fn to_north(self) -> NorthWireConnection { match self { Self::Up => NorthWireConnection::Up, Self::Side => NorthWireConnection::Side, @@ -436,7 +436,7 @@ impl WireConnection { } } - fn to_south(self) -> SouthWireConnection { + const fn to_south(self) -> SouthWireConnection { match self { Self::Up => SouthWireConnection::Up, Self::Side => SouthWireConnection::Side, @@ -444,7 +444,7 @@ impl WireConnection { } } - fn to_east(self) -> EastWireConnection { + const fn to_east(self) -> EastWireConnection { match self { Self::Up => EastWireConnection::Up, Self::Side => EastWireConnection::Side, @@ -452,7 +452,7 @@ impl WireConnection { } } - fn to_west(self) -> WestWireConnection { + const fn to_west(self) -> WestWireConnection { match self { Self::Up => WestWireConnection::Up, Self::Side => WestWireConnection::Side, diff --git a/pumpkin/src/block/blocks/redstone/tripwire.rs b/pumpkin/src/block/blocks/redstone/tripwire.rs index 6acbecc19..6c74679e1 100644 --- a/pumpkin/src/block/blocks/redstone/tripwire.rs +++ b/pumpkin/src/block/blocks/redstone/tripwire.rs @@ -140,8 +140,8 @@ impl BlockBehaviour for TripwireBlock { let aabb = BoundingBox::from_block(args.position); // TODO entity.canAvoidTraps() - if args.world.get_entities_at_box(&aabb).await.is_empty() - && args.world.get_players_at_box(&aabb).await.is_empty() + if args.world.get_entities_at_box(&aabb).is_empty() + && args.world.get_players_at_box(&aabb).is_empty() { props.powered = false; let state_id = props.to_state_id(args.block); diff --git a/pumpkin/src/block/blocks/redstone/tripwire_hook.rs b/pumpkin/src/block/blocks/redstone/tripwire_hook.rs index 336d2a05e..301de6b15 100644 --- a/pumpkin/src/block/blocks/redstone/tripwire_hook.rs +++ b/pumpkin/src/block/blocks/redstone/tripwire_hook.rs @@ -12,7 +12,7 @@ use pumpkin_world::{ tick::TickPriority, world::{BlockAccessor, BlockFlags}, }; -use rand::{Rng, rng}; +use rand::{RngExt, rng}; use crate::{ block::{ @@ -349,7 +349,7 @@ impl TripwireHookBlock { .await; // TODO world.emitGameEvent((Entity)null, GameEvent.BLOCK_ATTACH, pos); } else if !attached && detached { - let pitch = 1.2 / (rng().random::() * 0.2 + 0.9); + let pitch = 1.2 / rng().random::().mul_add(0.2, 0.9); world .play_sound_raw(Sound::BlockTripwireDetach as u16, cat, &pos, 0.4, pitch) .await; diff --git a/pumpkin/src/block/blocks/redstone/turbo.rs b/pumpkin/src/block/blocks/redstone/turbo.rs index a51a74e9b..f23968e6d 100644 --- a/pumpkin/src/block/blocks/redstone/turbo.rs +++ b/pumpkin/src/block/blocks/redstone/turbo.rs @@ -79,7 +79,7 @@ impl RedstoneWireTurbo { &self.nodes[node_id.index] } - fn compute_all_neighbors(pos: BlockPos) -> [BlockPos; 24] { + const fn compute_all_neighbors(pos: BlockPos) -> [BlockPos; 24] { let Vector3 { x, y, z } = pos.0; [ BlockPos::new(x - 1, y, z), diff --git a/pumpkin/src/block/blocks/signs.rs b/pumpkin/src/block/blocks/signs.rs index 8b0673c6a..97e5fb524 100644 --- a/pumpkin/src/block/blocks/signs.rs +++ b/pumpkin/src/block/blocks/signs.rs @@ -100,9 +100,7 @@ impl BlockBehaviour for SignBlock { &args.player.gameprofile.id, args.world, args.position, - ) - .await - { + ) { return BlockActionResult::Pass; } @@ -142,9 +140,7 @@ impl BlockBehaviour for SignBlock { &args.player.gameprofile.id, args.world, args.position, - ) - .await - { + ) { // I don't think that makes sense, since it will also just return in normal_use, but vanilla does it like this return BlockActionResult::PassToDefaultBlockAction; } @@ -223,7 +219,7 @@ fn get_yaw_from_rotation_16(rotation: Integer0To15) -> f32 { f32::from(index) * 22.5 } -async fn try_claim_sign( +fn try_claim_sign( currently_editing: &mut Option, uuid: &Uuid, world: &World, @@ -231,7 +227,7 @@ async fn try_claim_sign( ) -> bool { if let Some(editing_player_id) = *currently_editing && editing_player_id != *uuid - && let Some(editing_player) = world.get_player_by_uuid(editing_player_id).await + && let Some(editing_player) = world.get_player_by_uuid(editing_player_id) && editing_player.can_interact_with_block_at(position, 4.0) { return false; diff --git a/pumpkin/src/block/blocks/tnt.rs b/pumpkin/src/block/blocks/tnt.rs index 728960898..75f32f10c 100644 --- a/pumpkin/src/block/blocks/tnt.rs +++ b/pumpkin/src/block/blocks/tnt.rs @@ -14,7 +14,7 @@ use pumpkin_macros::pumpkin_block; use pumpkin_util::math::position::BlockPos; use pumpkin_util::math::vector3::Vector3; use pumpkin_world::world::BlockFlags; -use rand::Rng; +use rand::RngExt; use super::redstone::block_receives_redstone_power; diff --git a/pumpkin/src/block/mod.rs b/pumpkin/src/block/mod.rs index bf113eb94..0dba95c45 100644 --- a/pumpkin/src/block/mod.rs +++ b/pumpkin/src/block/mod.rs @@ -392,7 +392,7 @@ pub async fn calc_block_breaking( player.get_mining_speed(block).await / hardness / i } -#[derive(PartialEq, Debug)] +#[derive(PartialEq, Eq, Debug)] pub enum BlockIsReplacing { Itself(BlockStateId), Water(Integer0To15), diff --git a/pumpkin/src/block/registry.rs b/pumpkin/src/block/registry.rs index 88f449764..352e47065 100644 --- a/pumpkin/src/block/registry.rs +++ b/pumpkin/src/block/registry.rs @@ -282,7 +282,7 @@ pub fn default_registry() -> Arc { } // ActionResult.java -#[derive(PartialEq)] +#[derive(PartialEq, Eq)] pub enum BlockActionResult { /// Action was successful | Same as SUCCESS in vanilla Success, @@ -300,7 +300,7 @@ pub enum BlockActionResult { impl BlockActionResult { #[must_use] - pub fn consumes_action(&self) -> bool { + pub const fn consumes_action(&self) -> bool { matches!(self, Self::Consume | Self::Success | Self::SuccessServer) } } diff --git a/pumpkin/src/command/args/bounded_num.rs b/pumpkin/src/command/args/bounded_num.rs index 9754a0f56..fceafa33b 100644 --- a/pumpkin/src/command/args/bounded_num.rs +++ b/pumpkin/src/command/args/bounded_num.rs @@ -116,7 +116,7 @@ pub enum Number { impl Number { #[must_use] - pub fn qualifier(&self) -> &'static str { + pub const fn qualifier(&self) -> &'static str { match self { Self::F64(_) | Self::F32(_) => "Float", Self::I32(_) | Self::I64(_) => "Integer", diff --git a/pumpkin/src/command/args/entities.rs b/pumpkin/src/command/args/entities.rs index 13b35e019..9e27f35d2 100644 --- a/pumpkin/src/command/args/entities.rs +++ b/pumpkin/src/command/args/entities.rs @@ -43,7 +43,7 @@ pub enum ComparableValueCondition { Between(T, T), } -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, Clone, PartialEq, Eq)] pub enum EntityFilterSort { Arbitrary, Nearest, @@ -272,7 +272,7 @@ impl ArgumentConsumer for EntitiesArgumentConsumer { Box::pin(async move { // todo: command context // This is the required asynchronous operation. - let entities = server.select_entities(&entity_selector, Some(sender)).await; + let entities = server.select_entities(&entity_selector, Some(sender)); Some(Arg::Entities(entities)) }) diff --git a/pumpkin/src/command/args/entity.rs b/pumpkin/src/command/args/entity.rs index bebac0fe6..c865d3dcb 100644 --- a/pumpkin/src/command/args/entity.rs +++ b/pumpkin/src/command/args/entity.rs @@ -60,7 +60,7 @@ impl ArgumentConsumer for EntityArgumentConsumer { Box::pin(async move { // todo: command context - let entities = server.select_entities(&entity_selector, Some(sender)).await; + let entities = server.select_entities(&entity_selector, Some(sender)); entities.into_iter().next().map(Arg::Entity) }) diff --git a/pumpkin/src/command/args/entity_anchor.rs b/pumpkin/src/command/args/entity_anchor.rs index 512c230c8..06852e543 100644 --- a/pumpkin/src/command/args/entity_anchor.rs +++ b/pumpkin/src/command/args/entity_anchor.rs @@ -19,7 +19,7 @@ pub enum EntityAnchor { impl EntityAnchor { /// Returns the name used in commands. #[must_use] - pub fn as_str(&self) -> &'static str { + pub const fn as_str(&self) -> &'static str { match self { Self::Feet => "feet", Self::Eyes => "eyes", diff --git a/pumpkin/src/command/args/players.rs b/pumpkin/src/command/args/players.rs index ec8f13cc9..7a4bfd8b2 100644 --- a/pumpkin/src/command/args/players.rs +++ b/pumpkin/src/command/args/players.rs @@ -63,10 +63,9 @@ impl ArgumentConsumer for PlayersArgumentConsumer { let players = match s { "@r" => server .get_random_player() - .await .map_or_else(|| Some(vec![]), |p| Some(vec![p])), - "@a" | "@e" => Some(server.get_all_players().await), - name => server.get_player_by_name(name).await.map(|p| vec![p]), + "@a" | "@e" => Some(server.get_all_players()), + name => server.get_player_by_name(name).map(|p| vec![p]), }; players.map(Arg::Players) diff --git a/pumpkin/src/command/commands/banip.rs b/pumpkin/src/command/commands/banip.rs index c5e81fb59..5e748bce2 100644 --- a/pumpkin/src/command/commands/banip.rs +++ b/pumpkin/src/command/commands/banip.rs @@ -23,8 +23,7 @@ async fn parse_ip(target: &str, server: &Server) -> Option { Some(match IpAddr::from_str(target) { Ok(ip) => ip, Err(_) => server - .get_player_by_name(target) - .await? + .get_player_by_name(target)? .client .address() .await diff --git a/pumpkin/src/command/commands/bossbar.rs b/pumpkin/src/command/commands/bossbar.rs index ab7068767..90fc6db75 100644 --- a/pumpkin/src/command/commands/bossbar.rs +++ b/pumpkin/src/command/commands/bossbar.rs @@ -458,10 +458,11 @@ impl CommandExecutor for SetExecuter { } } - let player_names: Vec = targets + let player_names = targets .iter() - .map(|player| player.gameprofile.name.clone()) - .collect(); + .map(|p| p.gameprofile.name.as_str()) + .collect::>() + .join(", "); sender .send_message(TextComponent::translate( @@ -472,7 +473,7 @@ impl CommandExecutor for SetExecuter { namespace.to_string(), ), TextComponent::text(count.to_string()), - TextComponent::text(player_names.join(", ").clone()), + TextComponent::text(player_names), ], )) .await; @@ -584,11 +585,11 @@ impl CommandExecutor for SetExecuter { } } -fn max_value_consumer() -> BoundedNumArgumentConsumer { +const fn max_value_consumer() -> BoundedNumArgumentConsumer { BoundedNumArgumentConsumer::new().min(0).name("max") } -fn value_consumer() -> BoundedNumArgumentConsumer { +const fn value_consumer() -> BoundedNumArgumentConsumer { BoundedNumArgumentConsumer::new().min(0).name("value") } diff --git a/pumpkin/src/command/commands/damage.rs b/pumpkin/src/command/commands/damage.rs index 752449115..5b917156a 100644 --- a/pumpkin/src/command/commands/damage.rs +++ b/pumpkin/src/command/commands/damage.rs @@ -27,7 +27,7 @@ const ARG_LOCATION: &str = "location"; const ARG_ENTITY: &str = "entity"; const ARG_CAUSE: &str = "cause"; -fn amount_consumer() -> BoundedNumArgumentConsumer { +const fn amount_consumer() -> BoundedNumArgumentConsumer { BoundedNumArgumentConsumer::new().name(ARG_AMOUNT).min(0.0) } diff --git a/pumpkin/src/command/commands/defaultgamemode.rs b/pumpkin/src/command/commands/defaultgamemode.rs index e04dd4090..74d18934f 100644 --- a/pumpkin/src/command/commands/defaultgamemode.rs +++ b/pumpkin/src/command/commands/defaultgamemode.rs @@ -32,7 +32,7 @@ impl CommandExecutor for DefaultGamemodeExecutor { }; if server.basic_config.force_gamemode { - for player in server.get_all_players().await { + for player in server.get_all_players() { player.set_gamemode(gamemode).await; } } diff --git a/pumpkin/src/command/commands/difficulty.rs b/pumpkin/src/command/commands/difficulty.rs index 78c66b752..52c1de9af 100644 --- a/pumpkin/src/command/commands/difficulty.rs +++ b/pumpkin/src/command/commands/difficulty.rs @@ -30,7 +30,7 @@ impl CommandExecutor for DifficultyExecutor { let translation_key = format!("options.difficulty.{difficulty_string}"); { - let level_info = server.level_info.read().await; + let level_info = server.level_info.load(); if level_info.difficulty == difficulty { sender diff --git a/pumpkin/src/command/commands/enchant.rs b/pumpkin/src/command/commands/enchant.rs index 435672596..bf54a3561 100644 --- a/pumpkin/src/command/commands/enchant.rs +++ b/pumpkin/src/command/commands/enchant.rs @@ -146,7 +146,7 @@ impl CommandExecutor for Executor { } } -fn enchantment_level_consumer() -> BoundedNumArgumentConsumer { +const fn enchantment_level_consumer() -> BoundedNumArgumentConsumer { BoundedNumArgumentConsumer::new() .name("level") .min(0) diff --git a/pumpkin/src/command/commands/experience.rs b/pumpkin/src/command/commands/experience.rs index e7f15ad84..a82b1a45a 100644 --- a/pumpkin/src/command/commands/experience.rs +++ b/pumpkin/src/command/commands/experience.rs @@ -18,7 +18,7 @@ const DESCRIPTION: &str = "Add, set or query player experience."; const ARG_TARGETS: &str = "targets"; const ARG_AMOUNT: &str = "amount"; -fn xp_amount() -> BoundedNumArgumentConsumer { +const fn xp_amount() -> BoundedNumArgumentConsumer { BoundedNumArgumentConsumer::new() .name(ARG_AMOUNT) .min(0) diff --git a/pumpkin/src/command/commands/gamerule.rs b/pumpkin/src/command/commands/gamerule.rs index e0d7b890f..874e82a57 100644 --- a/pumpkin/src/command/commands/gamerule.rs +++ b/pumpkin/src/command/commands/gamerule.rs @@ -28,7 +28,7 @@ impl CommandExecutor for QueryExecutor { ) -> CommandResult<'a> { Box::pin(async move { let key = TextComponent::text(self.0.to_string()); - let level_info = server.level_info.read().await; + let level_info = server.level_info.load(); let value = TextComponent::text(level_info.game_rules.get(&self.0).to_string()); drop(level_info); @@ -46,6 +46,7 @@ impl CommandExecutor for QueryExecutor { struct SetExecutor(GameRule); impl CommandExecutor for SetExecutor { + #[expect(unused)] fn execute<'a>( &'a self, sender: &'a CommandSender, @@ -54,29 +55,37 @@ impl CommandExecutor for SetExecutor { ) -> CommandResult<'a> { Box::pin(async move { let key = TextComponent::text(self.0.to_string()); - let mut level_info = server.level_info.write().await; - let raw_value = level_info.game_rules.get_mut(&self.0); + let current_info = server.level_info.load(); - let value = TextComponent::text(match raw_value { + let mut new_info = (**current_info).clone(); + + let mut output_value = String::new(); + + let raw_value = new_info.game_rules.get_mut(&self.0); + + match raw_value { GameRuleValue::Int(value) => { let arg_value = BoundedNumArgumentConsumer::::find_arg(args, ARG_NAME)??; *value = arg_value; - arg_value.to_string() + output_value = arg_value.to_string(); } GameRuleValue::Bool(value) => { let arg_value = BoolArgConsumer::find_arg(args, ARG_NAME)?; *value = arg_value; - arg_value.to_string() + output_value = arg_value.to_string(); } - }); - drop(level_info); + } + server.level_info.store(std::sync::Arc::new(new_info)); + + let value_component = TextComponent::text(output_value); sender .send_message(TextComponent::translate( "commands.gamerule.set", - [key, value], + [key, value_component], )) .await; + Ok(()) }) } diff --git a/pumpkin/src/command/commands/give.rs b/pumpkin/src/command/commands/give.rs index 904e47523..9ac4f3e2a 100644 --- a/pumpkin/src/command/commands/give.rs +++ b/pumpkin/src/command/commands/give.rs @@ -20,7 +20,7 @@ const DESCRIPTION: &str = "Give items to player(s)."; const ARG_ITEM: &str = "item"; -fn item_count_consumer() -> BoundedNumArgumentConsumer { +const fn item_count_consumer() -> BoundedNumArgumentConsumer { BoundedNumArgumentConsumer::new() .name("count") .min(1) diff --git a/pumpkin/src/command/commands/help.rs b/pumpkin/src/command/commands/help.rs index d0ed22df9..6244533d2 100644 --- a/pumpkin/src/command/commands/help.rs +++ b/pumpkin/src/command/commands/help.rs @@ -19,7 +19,7 @@ const ARG_COMMAND: &str = "command"; const COMMANDS_PER_PAGE: i32 = 7; -fn page_number_consumer() -> BoundedNumArgumentConsumer { +const fn page_number_consumer() -> BoundedNumArgumentConsumer { BoundedNumArgumentConsumer::new().name("page").min(1) } diff --git a/pumpkin/src/command/commands/list.rs b/pumpkin/src/command/commands/list.rs index 4f89aed68..be84d20f8 100644 --- a/pumpkin/src/command/commands/list.rs +++ b/pumpkin/src/command/commands/list.rs @@ -23,7 +23,7 @@ impl CommandExecutor for Executor { _args: &'a ConsumedArgs<'a>, ) -> CommandResult<'a> { Box::pin(async move { - let players: Vec> = server.get_all_players().await; + let players: Vec> = server.get_all_players(); sender .send_message(TextComponent::translate( "commands.list.players", diff --git a/pumpkin/src/command/commands/particle.rs b/pumpkin/src/command/commands/particle.rs index 22282fa55..b79abee2c 100644 --- a/pumpkin/src/command/commands/particle.rs +++ b/pumpkin/src/command/commands/particle.rs @@ -41,14 +41,14 @@ impl CommandExecutor for Executor { let count = count.unwrap_or(Ok(0))?; let (world, pos) = match sender { CommandSender::Console | CommandSender::Rcon(_) => { - let guard = server.worlds.read().await; + let guard = server.worlds.load(); let world = guard .first() .cloned() .ok_or(CommandError::InvalidRequirement)?; // default position for spawning a player, in this case for particle let pos = { - let info = &world.level_info.read().await; + let info = &world.level_info.load(); // default position for spawning a player, in this case for mob pos.unwrap_or(Vector3::new( f64::from(info.spawn_x) + 0.5, diff --git a/pumpkin/src/command/commands/playsound.rs b/pumpkin/src/command/commands/playsound.rs index e2da843df..8718865e2 100644 --- a/pumpkin/src/command/commands/playsound.rs +++ b/pumpkin/src/command/commands/playsound.rs @@ -1,6 +1,6 @@ use pumpkin_data::sound::SoundCategory; use pumpkin_util::text::TextComponent; -use rand::{Rng, rng}; +use rand::{RngExt, rng}; use crate::command::{ CommandExecutor, CommandResult, CommandSender, @@ -34,13 +34,13 @@ const ARG_PITCH: &str = "pitch"; const ARG_MIN_VOLUME: &str = "minVolume"; // Volume must be >= 0, no upper limit -fn volume_consumer() -> BoundedNumArgumentConsumer { +const fn volume_consumer() -> BoundedNumArgumentConsumer { BoundedNumArgumentConsumer::new().name(ARG_VOLUME).min(0.0) } // Pitch must be between 0.0 and 2.0 // Values below 0.5 are treated as 0.5 -fn pitch_consumer() -> BoundedNumArgumentConsumer { +const fn pitch_consumer() -> BoundedNumArgumentConsumer { BoundedNumArgumentConsumer::new() .name(ARG_PITCH) .min(0.0) @@ -49,7 +49,7 @@ fn pitch_consumer() -> BoundedNumArgumentConsumer { // Minimum volume must be between 0.0 and 1.0 // Controls the volume for players outside normal hearing range -fn min_volume_consumer() -> BoundedNumArgumentConsumer { +const fn min_volume_consumer() -> BoundedNumArgumentConsumer { BoundedNumArgumentConsumer::new() .name(ARG_MIN_VOLUME) .min(0.0) diff --git a/pumpkin/src/command/commands/pumpkin.rs b/pumpkin/src/command/commands/pumpkin.rs index 15ca56897..050656c9d 100644 --- a/pumpkin/src/command/commands/pumpkin.rs +++ b/pumpkin/src/command/commands/pumpkin.rs @@ -82,7 +82,7 @@ impl CommandExecutor for Executor { .map(|c| c.login.as_str()) .collect::>() .join(", "); - let locale = sender.get_locale().await; + let locale = sender.get_locale(); let version_string = format!( "{} (Commit: {}) - {} Contributors", CARGO_PKG_VERSION, diff --git a/pumpkin/src/command/commands/seed.rs b/pumpkin/src/command/commands/seed.rs index 9ea7f8d35..01b1c9bc4 100644 --- a/pumpkin/src/command/commands/seed.rs +++ b/pumpkin/src/command/commands/seed.rs @@ -26,7 +26,7 @@ impl CommandExecutor for Executor { player.living_entity.entity.world.load().level.seed.0 } // TODO: Maybe ask player for world, or get the current world - _ => match server.worlds.read().await.first() { + _ => match server.worlds.load().first() { Some(world) => world.level.seed.0, None => { return Err(CommandError::CommandFailed(TextComponent::text( diff --git a/pumpkin/src/command/commands/setblock.rs b/pumpkin/src/command/commands/setblock.rs index 27ef5d7cb..dcc944bba 100644 --- a/pumpkin/src/command/commands/setblock.rs +++ b/pumpkin/src/command/commands/setblock.rs @@ -43,7 +43,7 @@ impl CommandExecutor for Executor { let mode = self.0; let world = match sender { CommandSender::Console | CommandSender::Rcon(_) => { - let guard = server.worlds.read().await; + let guard = server.worlds.load(); guard .first() diff --git a/pumpkin/src/command/commands/setidletimeout.rs b/pumpkin/src/command/commands/setidletimeout.rs index 28250a7f3..8d23d4cd2 100644 --- a/pumpkin/src/command/commands/setidletimeout.rs +++ b/pumpkin/src/command/commands/setidletimeout.rs @@ -15,7 +15,7 @@ const DESCRIPTION: &str = "Sets the time before idle players are kicked from the const ARG_MINUTES: &str = "minutes"; -fn minutes_consumer() -> BoundedNumArgumentConsumer { +const fn minutes_consumer() -> BoundedNumArgumentConsumer { BoundedNumArgumentConsumer::new().min(0).name(ARG_MINUTES) } diff --git a/pumpkin/src/command/commands/setworldspawn.rs b/pumpkin/src/command/commands/setworldspawn.rs index 0247925e5..e45544eaf 100644 --- a/pumpkin/src/command/commands/setworldspawn.rs +++ b/pumpkin/src/command/commands/setworldspawn.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use crate::command::CommandResult; use crate::command::dispatcher::CommandError::InvalidConsumption; use crate::command::{ @@ -113,15 +115,17 @@ async fn setworldspawn( return Ok(()); } - let mut level_info_guard = server.level_info.write().await; - level_info_guard.spawn_x = block_pos.0.x; - level_info_guard.spawn_y = block_pos.0.y; - level_info_guard.spawn_z = block_pos.0.z; + let current_info = server.level_info.load(); - level_info_guard.spawn_yaw = yaw; - level_info_guard.spawn_pitch = pitch; + let mut new_info = (**current_info).clone(); - drop(level_info_guard); + new_info.spawn_x = block_pos.0.x; + new_info.spawn_y = block_pos.0.y; + new_info.spawn_z = block_pos.0.z; + new_info.spawn_yaw = yaw; + new_info.spawn_pitch = pitch; + + server.level_info.store(Arc::new(new_info)); sender .send_message(TextComponent::translate( diff --git a/pumpkin/src/command/commands/summon.rs b/pumpkin/src/command/commands/summon.rs index 3463f27e4..d806c9b17 100644 --- a/pumpkin/src/command/commands/summon.rs +++ b/pumpkin/src/command/commands/summon.rs @@ -34,13 +34,13 @@ impl CommandExecutor for Executor { let pos = Position3DArgumentConsumer::find_arg(args, ARG_POS); let (world, pos) = match sender { CommandSender::Console | CommandSender::Rcon(_) => { - let guard = server.worlds.read().await; + let guard = server.worlds.load(); let world = guard .first() .cloned() .ok_or(CommandError::InvalidRequirement)?; let pos = { - let info = &world.level_info.read().await; + let info = &world.level_info.load(); // default position for spawning a player, in this case for mob pos.unwrap_or(Vector3::new( f64::from(info.spawn_x) + 0.5, diff --git a/pumpkin/src/command/commands/teleport.rs b/pumpkin/src/command/commands/teleport.rs index b31c7510c..9ce9c87d6 100644 --- a/pumpkin/src/command/commands/teleport.rs +++ b/pumpkin/src/command/commands/teleport.rs @@ -111,7 +111,7 @@ impl CommandExecutor for EntitiesToPosFacingPosExecutor { //todo let world = match sender { CommandSender::Rcon(_) | CommandSender::Console => { - server.worlds.read().await.first().unwrap().clone() + server.worlds.load().first().unwrap().clone() } CommandSender::Player(player) => player.world().clone(), CommandSender::CommandBlock(_, w) => w.clone(), @@ -193,7 +193,7 @@ impl CommandExecutor for EntitiesToPosWithRotationExecutor { let (yaw, _, pitch, _) = RotationArgumentConsumer::find_arg(args, ARG_ROTATION)?; // todo command context - let world = server.worlds.read().await.first().unwrap().clone(); + let world = server.worlds.load().first().unwrap().clone(); for target in targets { target .clone() @@ -228,7 +228,7 @@ impl CommandExecutor for EntitiesToPosExecutor { // todo command context let world = match sender { CommandSender::Rcon(_) | CommandSender::Console => { - server.worlds.read().await.first().unwrap().clone() + server.worlds.load().first().unwrap().clone() } CommandSender::Player(player) => player.world().clone(), CommandSender::CommandBlock(_, w) => w.clone(), diff --git a/pumpkin/src/command/commands/tick.rs b/pumpkin/src/command/commands/tick.rs index b46f9ef99..d222953f6 100644 --- a/pumpkin/src/command/commands/tick.rs +++ b/pumpkin/src/command/commands/tick.rs @@ -24,14 +24,14 @@ fn nanos_to_millis_string(nanos: i64) -> String { format!("{:.2}", nanos as f64 / 1_000_000.0) } -fn rate_consumer() -> BoundedNumArgumentConsumer { +const fn rate_consumer() -> BoundedNumArgumentConsumer { BoundedNumArgumentConsumer::new() .name("rate") .min(1.0) .max(10000.0) } -fn time_consumer() -> TimeArgumentConsumer { +const fn time_consumer() -> TimeArgumentConsumer { TimeArgumentConsumer } diff --git a/pumpkin/src/command/commands/time.rs b/pumpkin/src/command/commands/time.rs index 68f1c7543..bafd411eb 100644 --- a/pumpkin/src/command/commands/time.rs +++ b/pumpkin/src/command/commands/time.rs @@ -19,7 +19,7 @@ enum PresetTime { } impl PresetTime { - fn to_ticks(self) -> i32 { + const fn to_ticks(self) -> i32 { match self { Self::Day => 1000, Self::Noon => 6000, @@ -54,7 +54,7 @@ impl CommandExecutor for QueryExecutor { Box::pin(async move { let mode = self.0; // TODO: Maybe ask player for world, or get the current world - let worlds = server.worlds.read().await; + let worlds = server.worlds.load(); let world = worlds .first() .expect("There should always be at least one world"); @@ -116,7 +116,7 @@ impl CommandExecutor for ChangeExecutor { let mode = self.0; // TODO: Maybe ask player for world, or get the current world - let worlds = server.worlds.read().await; + let worlds = server.worlds.load(); let world = worlds .first() .expect("There should always be at least one world"); diff --git a/pumpkin/src/command/commands/transfer.rs b/pumpkin/src/command/commands/transfer.rs index db2b62f94..6bb5ecf26 100644 --- a/pumpkin/src/command/commands/transfer.rs +++ b/pumpkin/src/command/commands/transfer.rs @@ -20,7 +20,7 @@ const ARG_HOSTNAME: &str = "hostname"; const ARG_PLAYERS: &str = "players"; -fn port_consumer() -> BoundedNumArgumentConsumer { +const fn port_consumer() -> BoundedNumArgumentConsumer { BoundedNumArgumentConsumer::new() .name("port") .min(1) diff --git a/pumpkin/src/command/commands/weather.rs b/pumpkin/src/command/commands/weather.rs index 41f383be7..f57933dcc 100644 --- a/pumpkin/src/command/commands/weather.rs +++ b/pumpkin/src/command/commands/weather.rs @@ -33,7 +33,7 @@ impl CommandExecutor for Executor { Box::pin(async move { let duration = TimeArgumentConsumer::find_arg(args, ARG_DURATION).unwrap_or(6000); let world = { - let guard = server.worlds.read().await; + let guard = server.worlds.load(); guard .first() diff --git a/pumpkin/src/command/commands/whitelist.rs b/pumpkin/src/command/commands/whitelist.rs index 2f114b7e0..836743ccd 100644 --- a/pumpkin/src/command/commands/whitelist.rs +++ b/pumpkin/src/command/commands/whitelist.rs @@ -27,7 +27,7 @@ const ARG_TARGETS: &str = "targets"; async fn kick_non_whitelisted_players(server: &Server) { let whitelist = server.data.whitelist_config.read().await; if server.basic_config.enforce_whitelist && server.white_list.load(Ordering::Relaxed) { - for player in server.get_all_players().await { + for player in server.get_all_players() { if whitelist.is_whitelisted(&player.gameprofile) { continue; } diff --git a/pumpkin/src/command/commands/worldborder.rs b/pumpkin/src/command/commands/worldborder.rs index 8d52f9695..5bd03b0e8 100644 --- a/pumpkin/src/command/commands/worldborder.rs +++ b/pumpkin/src/command/commands/worldborder.rs @@ -24,25 +24,25 @@ const DESCRIPTION: &str = "Worldborder command."; const NOTHING_CHANGED_EXCEPTION: &str = "commands.worldborder.set.failed.nochange"; -fn distance_consumer() -> BoundedNumArgumentConsumer { +const fn distance_consumer() -> BoundedNumArgumentConsumer { BoundedNumArgumentConsumer::new().min(0.0).name("distance") } -fn time_consumer() -> BoundedNumArgumentConsumer { +const fn time_consumer() -> BoundedNumArgumentConsumer { BoundedNumArgumentConsumer::new().min(0).name("time") } -fn damage_per_block_consumer() -> BoundedNumArgumentConsumer { +const fn damage_per_block_consumer() -> BoundedNumArgumentConsumer { BoundedNumArgumentConsumer::new() .min(0.0) .name("damage_per_block") } -fn damage_buffer_consumer() -> BoundedNumArgumentConsumer { +const fn damage_buffer_consumer() -> BoundedNumArgumentConsumer { BoundedNumArgumentConsumer::new().min(0.0).name("buffer") } -fn warning_distance_consumer() -> BoundedNumArgumentConsumer { +const fn warning_distance_consumer() -> BoundedNumArgumentConsumer { BoundedNumArgumentConsumer::new().min(0).name("distance") } @@ -57,7 +57,7 @@ impl CommandExecutor for GetExecutor { ) -> CommandResult<'a> { Box::pin(async move { // TODO: Maybe ask player for world, or get the current world - let worlds = server.worlds.read().await; + let worlds = server.worlds.load(); let world = worlds .first() .expect("There should always be at least one world"); @@ -86,7 +86,7 @@ impl CommandExecutor for SetExecutor { ) -> CommandResult<'a> { Box::pin(async move { // TODO: Maybe ask player for world, or get the current world - let worlds = server.worlds.read().await; + let worlds = server.worlds.load(); let world = worlds .first() .expect("There should always be at least one world"); @@ -139,7 +139,7 @@ impl CommandExecutor for SetTimeExecutor { ) -> CommandResult<'a> { Box::pin(async move { // TODO: Maybe ask player for world, or get the current world - let worlds = server.worlds.read().await; + let worlds = server.worlds.load(); let world = worlds .first() .expect("There should always be at least one world"); @@ -225,7 +225,7 @@ impl CommandExecutor for AddExecutor { ) -> CommandResult<'a> { Box::pin(async move { // TODO: Maybe ask player for world, or get the current world - let worlds = server.worlds.read().await; + let worlds = server.worlds.load(); let world = worlds .first() .expect("There should always be at least one world"); @@ -280,7 +280,7 @@ impl CommandExecutor for AddTimeExecutor { ) -> CommandResult<'a> { Box::pin(async move { // TODO: Maybe ask player for world, or get the current world - let worlds = server.worlds.read().await; + let worlds = server.worlds.load(); let world = worlds .first() .expect("There should always be at least one world"); @@ -368,7 +368,7 @@ impl CommandExecutor for CenterExecutor { ) -> CommandResult<'a> { Box::pin(async move { // TODO: Maybe ask player for world, or get the current world - let worlds = server.worlds.read().await; + let worlds = server.worlds.load(); let world = worlds .first() .expect("There should always be at least one world"); @@ -402,7 +402,7 @@ impl CommandExecutor for DamageAmountExecutor { ) -> CommandResult<'a> { Box::pin(async move { // TODO: Maybe ask player for world, or get the current world - let worlds = server.worlds.read().await; + let worlds = server.worlds.load(); let world = worlds .first() .expect("There should always be at least one world"); @@ -456,7 +456,7 @@ impl CommandExecutor for DamageBufferExecutor { ) -> CommandResult<'a> { Box::pin(async move { // TODO: Maybe ask player for world, or get the current world - let worlds = server.worlds.read().await; + let worlds = server.worlds.load(); let world = worlds .first() .expect("There should always be at least one world"); @@ -509,7 +509,7 @@ impl CommandExecutor for WarningDistanceExecutor { ) -> CommandResult<'a> { Box::pin(async move { // TODO: Maybe ask player for world, or get the current world - let worlds = server.worlds.read().await; + let worlds = server.worlds.load(); let world = worlds .first() .expect("There should always be at least one world"); @@ -564,7 +564,7 @@ impl CommandExecutor for WarningTimeExecutor { ) -> CommandResult<'a> { Box::pin(async move { // TODO: Maybe ask player for world, or get the current world - let worlds = server.worlds.read().await; + let worlds = server.worlds.load(); let world = worlds .first() .expect("There should always be at least one world"); diff --git a/pumpkin/src/command/dispatcher.rs b/pumpkin/src/command/dispatcher.rs index 80fd86d2b..d823619ea 100644 --- a/pumpkin/src/command/dispatcher.rs +++ b/pumpkin/src/command/dispatcher.rs @@ -360,7 +360,7 @@ impl CommandDispatcher { raw_args: &mut RawArgs<'a>, input: &'a str, ) -> Result>, CommandError> { - let mut parsed_args: ConsumedArgs = HashMap::new(); + //let mut parsed_args: ConsumedArgs = HashMap::new(); for node in path.iter().map(|&i| &tree.nodes[i]) { match &node.node_type { @@ -372,10 +372,10 @@ impl CommandDispatcher { return Ok(None); } } - NodeType::Argument { consumer, name } => { + NodeType::Argument { consumer, name: _ } => { match consumer.consume(src, server, raw_args).await { - Some(consumed) => { - parsed_args.insert(name, consumed); + Some(_consumed) => { + //parsed_args.insert(name, consumed); } None => { return if raw_args.is_empty() { @@ -444,7 +444,7 @@ mod test { use crate::command::{commands::default_dispatcher, tree::CommandTree}; #[tokio::test] - async fn test_dynamic_command() { + async fn dynamic_command() { let config = BasicConfiguration::default(); let registry = RwLock::new(PermissionRegistry::new()); let mut dispatcher = default_dispatcher(®istry, &config).await; diff --git a/pumpkin/src/command/mod.rs b/pumpkin/src/command/mod.rs index 22b1e94c4..a21034044 100644 --- a/pumpkin/src/command/mod.rs +++ b/pumpkin/src/command/mod.rs @@ -168,11 +168,12 @@ impl CommandSender { } } - pub async fn get_locale(&self) -> Locale { + #[must_use] + pub fn get_locale(&self) -> Locale { match self { Self::CommandBlock(..) | Self::Console | Self::Rcon(..) => Locale::EnUs, // Default locale for console and RCON Self::Player(player) => { - Locale::from_str(&player.config.read().await.locale).unwrap_or(Locale::EnUs) + Locale::from_str(&player.config.load().locale).unwrap_or(Locale::EnUs) } } } diff --git a/pumpkin/src/data/player_server.rs b/pumpkin/src/data/player_server.rs index 19803d856..123acc78d 100644 --- a/pumpkin/src/data/player_server.rs +++ b/pumpkin/src/data/player_server.rs @@ -74,8 +74,8 @@ impl ServerPlayerData { if should_save && self.storage.is_save_enabled() { self.last_save.store(now); // Save all online players periodically across all worlds - for world in server.worlds.read().await.iter() { - for player in world.players.read().await.values() { + for world in server.worlds.load().iter() { + for player in world.players.load().iter() { let mut nbt = NbtCompound::new(); player.write_nbt(&mut nbt).await; @@ -103,8 +103,8 @@ impl ServerPlayerData { let mut total_players = 0; // Save players from all worlds - for world in server.worlds.read().await.iter() { - for player in world.players.read().await.values() { + for world in server.worlds.load().iter() { + for player in world.players.load().iter() { self.extract_data_and_save_player(player).await?; total_players += 1; } @@ -186,7 +186,7 @@ mod test { use uuid::Uuid; #[tokio::test] - async fn test_player_data_storage_new() { + async fn player_data_storage_new() { // Create a temporary directory for testing let temp_dir = tempdir().unwrap(); let path = temp_dir.path().to_path_buf(); @@ -198,7 +198,7 @@ mod test { } #[tokio::test] - async fn test_player_data_storage_get_player_data_path() { + async fn player_data_storage_get_player_data_path() { let temp_dir = tempdir().unwrap(); let path = temp_dir.path().to_path_buf(); @@ -211,7 +211,7 @@ mod test { } #[tokio::test] - async fn test_player_data_storage_save_and_load() { + async fn player_data_storage_save_and_load() { let temp_dir = tempdir().unwrap(); let path = temp_dir.path().to_path_buf(); @@ -236,7 +236,7 @@ mod test { } #[tokio::test] - async fn test_player_data_storage_load_nonexistent() { + async fn player_data_storage_load_nonexistent() { let temp_dir = tempdir().unwrap(); let path = temp_dir.path().to_path_buf(); @@ -252,7 +252,7 @@ mod test { } #[tokio::test] - async fn test_player_data_storage_disabled() { + async fn player_data_storage_disabled() { let temp_dir = tempdir().unwrap(); let path = temp_dir.path().to_path_buf(); @@ -273,7 +273,7 @@ mod test { } #[tokio::test] - async fn test_server_player_data_new() { + async fn server_player_data_new() { let temp_dir = tempdir().unwrap(); let path = temp_dir.path().to_path_buf(); let save_interval = Duration::from_secs(300); @@ -287,7 +287,7 @@ mod test { } #[tokio::test] - async fn test_player_data_file_structure() { + async fn player_data_file_structure() { let temp_dir = tempdir().unwrap(); let path = temp_dir.path().to_path_buf(); diff --git a/pumpkin/src/entity/ai/control/look_control.rs b/pumpkin/src/entity/ai/control/look_control.rs index 7e7124970..71eac8c04 100644 --- a/pumpkin/src/entity/ai/control/look_control.rs +++ b/pumpkin/src/entity/ai/control/look_control.rs @@ -3,7 +3,6 @@ use crate::entity::ai::control::Control; use crate::entity::mob::{Mob, MobEntity}; use pumpkin_util::math::clamp_angle; use pumpkin_util::math::vector3::Vector3; -use std::f32::consts::PI; use std::sync::Arc; // Please keep the atomic values out of here!!! @@ -49,7 +48,7 @@ impl LookControl { ); } - pub fn look_at_with_range( + pub const fn look_at_with_range( &mut self, x: f64, y: f64, @@ -96,7 +95,7 @@ impl LookControl { self.clamp_head_yaw(mob).await; } - fn should_stay_horizontal() -> bool { + const fn should_stay_horizontal() -> bool { true } @@ -120,11 +119,11 @@ impl LookControl { let d = position.x - mob_position.x; let e = position.y - mob.living_entity.entity.get_eye_y(); let f = position.z - mob_position.z; - let g = (d * d + f * f).sqrt(); + let g = d.hypot(f); if e.abs() <= 1.0E-5 && g.abs() <= 1.0E-5 { None } else { - Some(-(e.atan2(g) as f32 * 180.0 / PI)) + Some(-(e.atan2(g) as f32).to_degrees()) } } @@ -136,7 +135,7 @@ impl LookControl { if e.abs() <= 1.0E-5 && d.abs() <= 1.0E-5 { None } else { - Some(e.atan2(d) as f32 * 180.0 / PI - 90.0) + Some((e.atan2(d) as f32).to_degrees() - 90.0) } } } diff --git a/pumpkin/src/entity/ai/goal/active_target.rs b/pumpkin/src/entity/ai/goal/active_target.rs index dbcc39ffe..aa6a5a30c 100644 --- a/pumpkin/src/entity/ai/goal/active_target.rs +++ b/pumpkin/src/entity/ai/goal/active_target.rs @@ -7,7 +7,7 @@ use crate::entity::mob::Mob; use crate::entity::{EntityBase, mob::MobEntity, player::Player}; use crate::world::World; use pumpkin_data::entity::EntityType; -use rand::Rng; +use rand::RngExt; use std::sync::Arc; const DEFAULT_RECIPROCAL_CHANCE: i32 = 10; @@ -67,7 +67,7 @@ impl ActiveTargetGoal { }) } - async fn find_closest_target(&mut self, mob: &MobEntity) { + fn find_closest_target(&mut self, mob: &MobEntity) { let world = mob.living_entity.entity.world.load(); if self.target_type == &EntityType::PLAYER { self.target = world @@ -75,16 +75,13 @@ impl ActiveTargetGoal { mob.living_entity.entity.pos.load(), TrackTargetGoal::get_follow_range(mob).into(), ) - .await .map(|p: Arc| p as Arc); } else { - self.target = world - .get_closest_entity( - mob.living_entity.entity.pos.load(), - TrackTargetGoal::get_follow_range(mob).into(), - Some(&[self.target_type]), - ) - .await; + self.target = world.get_closest_entity( + mob.living_entity.entity.pos.load(), + TrackTargetGoal::get_follow_range(mob).into(), + Some(&[self.target_type]), + ); } } } @@ -97,7 +94,7 @@ impl Goal for ActiveTargetGoal { { return false; } - self.find_closest_target(mob.get_mob_entity()).await; + self.find_closest_target(mob.get_mob_entity()); self.target.is_some() }) } diff --git a/pumpkin/src/entity/ai/goal/ambient_stand.rs b/pumpkin/src/entity/ai/goal/ambient_stand.rs index 60e983bef..183ae2732 100644 --- a/pumpkin/src/entity/ai/goal/ambient_stand.rs +++ b/pumpkin/src/entity/ai/goal/ambient_stand.rs @@ -1,6 +1,6 @@ use super::{Controls, Goal}; use crate::entity::{ai::goal::GoalFuture, mob::Mob}; -use rand::Rng; +use rand::RngExt; pub struct AmbientStandGoal { goal_control: Controls, @@ -8,7 +8,7 @@ pub struct AmbientStandGoal { } impl AmbientStandGoal { - fn reset_cooldown(&mut self) { + const fn reset_cooldown(&mut self) { // TODO: should be: this.cooldown = -entity.getMinAmbientStandDelay(); // TODO: implement when Horses are implemented self.cooldown = 0; diff --git a/pumpkin/src/entity/ai/goal/creeper_ignite.rs b/pumpkin/src/entity/ai/goal/creeper_ignite.rs index e090eeb7f..a80c69225 100644 --- a/pumpkin/src/entity/ai/goal/creeper_ignite.rs +++ b/pumpkin/src/entity/ai/goal/creeper_ignite.rs @@ -13,7 +13,7 @@ pub struct CreeperIgniteGoal { impl CreeperIgniteGoal { #[must_use] - pub fn new(creeper: Arc) -> Self { + pub const fn new(creeper: Arc) -> Self { Self { goal_control: Controls::MOVE, creeper, diff --git a/pumpkin/src/entity/ai/goal/goal_selector.rs b/pumpkin/src/entity/ai/goal/goal_selector.rs index d9333dcc4..39b022799 100644 --- a/pumpkin/src/entity/ai/goal/goal_selector.rs +++ b/pumpkin/src/entity/ai/goal/goal_selector.rs @@ -122,15 +122,15 @@ impl GoalSelector { } } - pub fn disable_control(&mut self, control: Controls) { + pub const fn disable_control(&mut self, control: Controls) { self.disabled_controls.set(control, true); } - pub fn enable_control(&mut self, control: Controls) { + pub const fn enable_control(&mut self, control: Controls) { self.disabled_controls.set(control, false); } - pub fn set_control_enabled(&mut self, control: Controls, enabled: bool) { + pub const fn set_control_enabled(&mut self, control: Controls, enabled: bool) { self.disabled_controls.set(control, !enabled); } diff --git a/pumpkin/src/entity/ai/goal/look_around.rs b/pumpkin/src/entity/ai/goal/look_around.rs index 2db0f3d57..99c56ffc3 100644 --- a/pumpkin/src/entity/ai/goal/look_around.rs +++ b/pumpkin/src/entity/ai/goal/look_around.rs @@ -2,7 +2,7 @@ use std::f64::consts::TAU; use super::{Controls, Goal}; use crate::entity::{ai::goal::GoalFuture, mob::Mob}; -use rand::Rng; +use rand::RngExt; pub struct LookAroundGoal { goal_control: Controls, diff --git a/pumpkin/src/entity/ai/goal/look_at_entity.rs b/pumpkin/src/entity/ai/goal/look_at_entity.rs index 79fdd9898..a5705541e 100644 --- a/pumpkin/src/entity/ai/goal/look_at_entity.rs +++ b/pumpkin/src/entity/ai/goal/look_at_entity.rs @@ -5,7 +5,7 @@ use crate::entity::mob::Mob; use crate::entity::predicate::EntityPredicate; use crate::entity::{EntityBase, player::Player}; use pumpkin_data::entity::EntityType; -use rand::Rng; +use rand::RngExt; use std::sync::{Arc, Weak}; #[expect(dead_code)] @@ -98,12 +98,10 @@ impl Goal for LookAtEntityGoal { if *self.target_type == EntityType::PLAYER { self.target = world .get_closest_player(mob_pos, self.range.into()) - .await .map(|p: Arc| p as Arc); } else { - self.target = world - .get_closest_entity(mob_pos, self.range.into(), Some(&[self.target_type])) - .await; + self.target = + world.get_closest_entity(mob_pos, self.range.into(), Some(&[self.target_type])); } self.target.is_some() diff --git a/pumpkin/src/entity/ai/goal/mod.rs b/pumpkin/src/entity/ai/goal/mod.rs index 130bdf9e0..64220f034 100644 --- a/pumpkin/src/entity/ai/goal/mod.rs +++ b/pumpkin/src/entity/ai/goal/mod.rs @@ -14,7 +14,7 @@ mod track_target; pub mod zombie_attack; #[must_use] -pub fn to_goal_ticks(server_ticks: i32) -> i32 { +pub const fn to_goal_ticks(server_ticks: i32) -> i32 { -(-server_ticks).div_euclid(2) } @@ -84,7 +84,7 @@ impl Controls { Self::default() } - pub fn set(&mut self, control: Self, val: bool) { + pub const fn set(&mut self, control: Self, val: bool) { if val { self.0 |= control.0; } else { @@ -93,7 +93,7 @@ impl Controls { } #[must_use] - pub fn get(&self, control: Self) -> bool { + pub const fn get(&self, control: Self) -> bool { self.0 & control.0 != 0 } diff --git a/pumpkin/src/entity/ai/goal/move_to_target_pos.rs b/pumpkin/src/entity/ai/goal/move_to_target_pos.rs index 1a05e8264..86e4ff91a 100644 --- a/pumpkin/src/entity/ai/goal/move_to_target_pos.rs +++ b/pumpkin/src/entity/ai/goal/move_to_target_pos.rs @@ -4,7 +4,7 @@ use crate::entity::{ai::goal::ParentHandle, mob::Mob}; use crate::world::World; use pumpkin_util::math::position::BlockPos; use pumpkin_util::math::vector3::Vector3; -use rand::Rng; +use rand::RngExt; use std::pin::Pin; use std::sync::Arc; @@ -108,7 +108,7 @@ impl MoveToTargetPosGoal { self.target_pos.up() } - fn should_reset_path(&self) -> bool { + const fn should_reset_path(&self) -> bool { self.trying_time % 40 == 0 } diff --git a/pumpkin/src/entity/ai/goal/step_and_destroy_block.rs b/pumpkin/src/entity/ai/goal/step_and_destroy_block.rs index 08f125439..7ba7de18f 100644 --- a/pumpkin/src/entity/ai/goal/step_and_destroy_block.rs +++ b/pumpkin/src/entity/ai/goal/step_and_destroy_block.rs @@ -90,7 +90,7 @@ impl Goal fn can_start<'a>(&'a mut self, mob: &'a dyn Mob) -> GoalFuture<'a, bool> { Box::pin(async { let world = mob.get_entity().world.load(); - let level_info = world.level_info.read().await; + let level_info = world.level_info.load(); if !level_info.game_rules.mob_griefing { false } else if self.move_to_target_pos_goal.cooldown > 0 { diff --git a/pumpkin/src/entity/ai/goal/track_target.rs b/pumpkin/src/entity/ai/goal/track_target.rs index bad6d4aa7..2d8db238b 100644 --- a/pumpkin/src/entity/ai/goal/track_target.rs +++ b/pumpkin/src/entity/ai/goal/track_target.rs @@ -4,7 +4,7 @@ use crate::entity::ai::target_predicate::TargetPredicate; use crate::entity::living::LivingEntity; use crate::entity::mob::Mob; use crate::entity::{EntityBase, mob::MobEntity}; -use rand::Rng; +use rand::RngExt; use std::sync::Arc; const UNSET: i32 = 0; @@ -44,7 +44,7 @@ impl TrackTargetGoal { } // TODO: get from entity attribute - pub fn get_follow_range(_mob: &MobEntity) -> f32 { + pub const fn get_follow_range(_mob: &MobEntity) -> f32 { 32.0 } diff --git a/pumpkin/src/entity/ai/path/mod.rs b/pumpkin/src/entity/ai/path/mod.rs index eae499f35..896266b37 100644 --- a/pumpkin/src/entity/ai/path/mod.rs +++ b/pumpkin/src/entity/ai/path/mod.rs @@ -14,11 +14,11 @@ pub struct NavigatorGoal { } impl Navigator { - pub fn set_progress(&mut self, goal: NavigatorGoal) { + pub const fn set_progress(&mut self, goal: NavigatorGoal) { self.current_goal = Some(goal); } - pub fn cancel(&mut self) { + pub const fn cancel(&mut self) { self.current_goal = None; } @@ -79,7 +79,7 @@ impl Navigator { } #[must_use] - pub fn is_idle(&self) -> bool { + pub const fn is_idle(&self) -> bool { // TODO: implement false } @@ -91,7 +91,7 @@ pub struct Node { impl Node { #[must_use] - pub fn new(location: Vector3) -> Self { + pub const fn new(location: Vector3) -> Self { Self { location } } /// How expensive is it to go to a location? diff --git a/pumpkin/src/entity/ai/target_predicate.rs b/pumpkin/src/entity/ai/target_predicate.rs index b36f600d3..4ca5558af 100644 --- a/pumpkin/src/entity/ai/target_predicate.rs +++ b/pumpkin/src/entity/ai/target_predicate.rs @@ -63,11 +63,11 @@ impl TargetPredicate { instance } - pub fn ignore_visibility(&mut self) { + pub const fn ignore_visibility(&mut self) { self.respects_visibility = false; } - pub fn ignore_distance_scaling(&mut self) { + pub const fn ignore_distance_scaling(&mut self) { self.use_distance_scaling_factor = false; } diff --git a/pumpkin/src/entity/breath.rs b/pumpkin/src/entity/breath.rs index 14f886369..f4b8db80a 100644 --- a/pumpkin/src/entity/breath.rs +++ b/pumpkin/src/entity/breath.rs @@ -42,14 +42,7 @@ impl BreathManager { return; } - if !player - .world() - .level_info - .read() - .await - .game_rules - .drowning_damage - { + if !player.world().level_info.load().game_rules.drowning_damage { return; } diff --git a/pumpkin/src/entity/combat.rs b/pumpkin/src/entity/combat.rs index d3dd33725..1db2b67e2 100644 --- a/pumpkin/src/entity/combat.rs +++ b/pumpkin/src/entity/combat.rs @@ -68,7 +68,7 @@ pub async fn spawn_sweep_particle(attacker_entity: &Entity, world: &World, pos: let e = f64::from((yaw.to_radians()).cos()); let scale = 0.5; - let body_y = pos.y + f64::from(attacker_entity.height()) * scale; + let body_y = f64::from(attacker_entity.height()).mul_add(scale, pos.y); world .spawn_particle( diff --git a/pumpkin/src/entity/decoration/armor_stand.rs b/pumpkin/src/entity/decoration/armor_stand.rs index 68f5c37f0..3fe0f88f3 100644 --- a/pumpkin/src/entity/decoration/armor_stand.rs +++ b/pumpkin/src/entity/decoration/armor_stand.rs @@ -314,7 +314,7 @@ impl EntityBase for ArmorStandEntity { let world = entity.world.load(); let mob_griefing_gamerule = { - let game_rules = &world.level_info.read().await.game_rules; + let game_rules = &world.level_info.load().game_rules; game_rules.mob_griefing }; diff --git a/pumpkin/src/entity/decoration/end_crystal.rs b/pumpkin/src/entity/decoration/end_crystal.rs index 4711209bc..0d77e7530 100644 --- a/pumpkin/src/entity/decoration/end_crystal.rs +++ b/pumpkin/src/entity/decoration/end_crystal.rs @@ -10,7 +10,7 @@ pub struct EndCrystalEntity { } impl EndCrystalEntity { - pub fn new(entity: Entity) -> Self { + pub const fn new(entity: Entity) -> Self { Self { entity } } } diff --git a/pumpkin/src/entity/decoration/painting.rs b/pumpkin/src/entity/decoration/painting.rs index 26f0b874a..d69b0256e 100644 --- a/pumpkin/src/entity/decoration/painting.rs +++ b/pumpkin/src/entity/decoration/painting.rs @@ -13,7 +13,7 @@ pub struct PaintingEntity { } impl PaintingEntity { - pub fn new(entity: Entity) -> Self { + pub const fn new(entity: Entity) -> Self { Self { entity } } } diff --git a/pumpkin/src/entity/experience_orb.rs b/pumpkin/src/entity/experience_orb.rs index d7914c847..c0648f4bc 100644 --- a/pumpkin/src/entity/experience_orb.rs +++ b/pumpkin/src/entity/experience_orb.rs @@ -38,7 +38,7 @@ impl ExperienceOrbEntity { } } - fn round_to_orb_size(value: u32) -> u32 { + const fn round_to_orb_size(value: u32) -> u32 { if value >= 2477 { 2477 } else if value >= 1237 { diff --git a/pumpkin/src/entity/falling.rs b/pumpkin/src/entity/falling.rs index bcba8d1d4..7657ad4f6 100644 --- a/pumpkin/src/entity/falling.rs +++ b/pumpkin/src/entity/falling.rs @@ -18,7 +18,7 @@ pub struct FallingEntity { } impl FallingEntity { - pub fn new(entity: Entity, block_state_id: BlockStateId) -> Self { + pub const fn new(entity: Entity, block_state_id: BlockStateId) -> Self { Self { entity, block_state_id, diff --git a/pumpkin/src/entity/hunger.rs b/pumpkin/src/entity/hunger.rs index d9ece69f6..aa26a0d52 100644 --- a/pumpkin/src/entity/hunger.rs +++ b/pumpkin/src/entity/hunger.rs @@ -36,7 +36,7 @@ impl HungerManager { let mut exhaustion = self.exhaustion.load(); let mut timer = self.tick_timer.load(); - let difficulty = player.world().level_info.read().await.difficulty; + let difficulty = player.world().level_info.load().difficulty; let health = player.living_entity.health.load(); let can_heal = player.can_food_heal(); diff --git a/pumpkin/src/entity/item.rs b/pumpkin/src/entity/item.rs index 030c9a6fe..c2ed0e766 100644 --- a/pumpkin/src/entity/item.rs +++ b/pumpkin/src/entity/item.rs @@ -37,9 +37,9 @@ impl ItemEntity { pub async fn new(entity: Entity, item_stack: ItemStack) -> Self { entity .set_velocity(Vector3::new( - rand::random::() * 0.2 - 0.1, + rand::random::().mul_add(0.2, -0.1), 0.2, - rand::random::() * 0.2 - 0.1, + rand::random::().mul_add(0.2, -0.1), )) .await; entity.yaw.store(rand::random::() * 360.0); @@ -88,19 +88,14 @@ impl ItemEntity { let bounding_box = self.entity.bounding_box.load().expand(0.5, 0.0, 0.5); let world = self.entity.world.load(); - let items: Vec<_> = world - .entities - .read() - .await - .values() - .filter_map(|entity: &Arc| { - entity.clone().get_item_entity().filter(|item| { - item.entity.entity_id != self.entity.entity_id - && !item.never_despawn.load(Ordering::Relaxed) - && item.entity.bounding_box.load().intersects(&bounding_box) - }) + let entities = world.entities.load(); + let items = entities.iter().filter_map(|entity: &Arc| { + entity.clone().get_item_entity().filter(|item| { + item.entity.entity_id != self.entity.entity_id + && !item.never_despawn.load(Ordering::Relaxed) + && item.entity.bounding_box.load().intersects(&bounding_box) }) - .collect(); + }); for item in items { if item.can_merge().await { diff --git a/pumpkin/src/entity/living.rs b/pumpkin/src/entity/living.rs index 2bee68a5f..f1ed0cde1 100644 --- a/pumpkin/src/entity/living.rs +++ b/pumpkin/src/entity/living.rs @@ -289,7 +289,7 @@ impl LivingEntity { if block == &Block::NETHER_PORTAL { let world = self.entity.world.load(); - let level_info = world.level_info.read().await; + let level_info = world.level_info.load(); return level_info.game_rules.players_nether_portal_default_delay == 0; } @@ -491,7 +491,7 @@ impl LivingEntity { let levitation = self.get_effect(&StatusEffect::LEVITATION).await; if let Some(lev) = levitation { - velo.y += (0.05 * f64::from(lev.amplifier + 1) - velo.y) * 0.2; + velo.y += 0.05f64.mul_add(f64::from(lev.amplifier + 1), -velo.y) * 0.2; } else { velo.y -= self.get_effective_gravity(&caller).await; @@ -846,7 +846,7 @@ impl LivingEntity { } } - fn get_fall_sound(distance: i32) -> Sound { + const fn get_fall_sound(distance: i32) -> Sound { if distance > 4 { Sound::EntityGenericBigFall } else { @@ -904,7 +904,6 @@ impl LivingEntity { let world = self.entity.world.load(); let dyn_self = world .get_entity_by_id(self.entity.entity_id) - .await .expect("Entity not found in world"); if self .dead @@ -938,14 +937,13 @@ impl LivingEntity { world.drop_stack(&block_pos, item).await; } - let show_death_messages = - { world.level_info.read().await.game_rules.show_death_messages }; + let show_death_messages = { world.level_info.load().game_rules.show_death_messages }; if self.entity.entity_type == &EntityType::PLAYER && show_death_messages { //TODO: KillCredit let death_message = Self::get_death_message(&*dyn_self, damage_type, source, cause).await; if let Some(server) = world.server.upgrade() { - for player in server.get_all_players().await { + for player in server.get_all_players() { player.send_system_message(&death_message).await; } } diff --git a/pumpkin/src/entity/mob/zombie.rs b/pumpkin/src/entity/mob/zombie.rs index 52b9a6301..31bb102e5 100644 --- a/pumpkin/src/entity/mob/zombie.rs +++ b/pumpkin/src/entity/mob/zombie.rs @@ -15,7 +15,7 @@ use pumpkin_data::Block; use pumpkin_data::entity::EntityType; use pumpkin_data::sound::{Sound, SoundCategory}; use pumpkin_util::math::position::BlockPos; -use rand::{Rng, rng}; +use rand::{RngExt, rng}; use std::pin::Pin; use std::sync::{Arc, Weak}; @@ -139,7 +139,7 @@ impl Stepping for DestroyEggGoal { SoundCategory::Hostile, &pos_f64, 0.7, - 0.9 + random * 0.2, + random.mul_add(0.2, 0.9), ) .await; }) @@ -158,7 +158,7 @@ impl Stepping for DestroyEggGoal { SoundCategory::Blocks, &pos_f64, 0.7, - 0.9 + random * 0.2, + random.mul_add(0.2, 0.9), ) .await; }) diff --git a/pumpkin/src/entity/mod.rs b/pumpkin/src/entity/mod.rs index 74eb7f8d9..1769e1d92 100644 --- a/pumpkin/src/entity/mod.rs +++ b/pumpkin/src/entity/mod.rs @@ -46,7 +46,6 @@ use pumpkin_util::text::hover::HoverEvent; use pumpkin_util::version::MinecraftVersion; use serde::Serialize; use std::collections::BTreeMap; -use std::f32::consts::PI; use std::pin::Pin; use std::sync::{ Arc, @@ -264,7 +263,7 @@ pub enum RemovalReason { impl RemovalReason { #[must_use] - pub fn should_destroy(&self) -> bool { + pub const fn should_destroy(&self) -> bool { match self { Self::Killed | Self::Discarded => true, Self::UnloadedToChunk | Self::UnloadedWithPlayer | Self::ChangedDimension => false, @@ -272,7 +271,7 @@ impl RemovalReason { } #[must_use] - pub fn should_save(&self) -> bool { + pub const fn should_save(&self) -> bool { match self { Self::Killed | Self::Discarded | Self::UnloadedWithPlayer | Self::ChangedDimension => { false @@ -487,7 +486,7 @@ impl Entity { } #[must_use] - pub fn get_entity_dimensions(pose: EntityPose) -> EntityDimensions { + pub const fn get_entity_dimensions(pose: EntityPose) -> EntityDimensions { match pose { EntityPose::Sleeping => EntityDimensions::new(0.2, 0.2, 0.2), EntityPose::FallFlying | EntityPose::Swimming | EntityPose::SpinAttack => { @@ -557,8 +556,8 @@ impl Entity { let position = self.pos.load(); let delta = target.sub(&position); let root = delta.x.hypot(delta.z); - let pitch = wrap_degrees(-delta.y.atan2(root) as f32 * 180.0 / PI); - let yaw = wrap_degrees((delta.z.atan2(delta.x) as f32 * 180.0 / PI) - 90.0); + let pitch = wrap_degrees((-delta.y.atan2(root) as f32).to_degrees()); + let yaw = wrap_degrees((delta.z.atan2(delta.x) as f32).to_degrees() - 90.0); self.pitch.store(pitch); self.yaw.store(yaw); } @@ -1188,9 +1187,9 @@ impl Entity { let cos = yaw.cos(); Vector3::new( - input.x * cos - input.z * sin, + input.x.mul_add(cos, -(input.z * sin)), input.y, - input.z * cos + input.x * sin, + input.z.mul_add(cos, input.x * sin), ) } @@ -1318,7 +1317,7 @@ impl Entity { } } - let amplitude = rand::random::() * 0.2 + 0.1; + let amplitude = rand::random::().mul_add(0.2, 0.1); let axis = direction.to_axis().into(); @@ -1812,8 +1811,7 @@ impl Entity { } buf.put_u8(255); let world = self.world.load(); - let current_players = world.players.read().await; - for player in current_players.values() { + for player in world.players.load().iter() { if let ClientPlatform::Java(client) = &player.client { let mut buf = Vec::new(); for meta in meta { diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index e83c1ef5d..d801baa82 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -8,6 +8,7 @@ use std::sync::Arc; use std::sync::atomic::{AtomicBool, AtomicI32, AtomicI64, AtomicU8, AtomicU32, Ordering}; use std::time::{Duration, Instant}; +use arc_swap::ArcSwap; use crossbeam::atomic::AtomicCell; use crossbeam::channel::Receiver; use log::warn; @@ -166,7 +167,7 @@ impl ChunkManager { /// Gets the current world for chunk loading. #[must_use] - pub fn world(&self) -> &Arc { + pub const fn world(&self) -> &Arc { &self.world } @@ -193,8 +194,10 @@ impl ChunkManager { center: Vector2, mut view_distance: u8, level: &Arc, + loading_chunks: &[Vector2], + unloading_chunks: &[Vector2], ) { - view_distance += 1; + view_distance += 1; // Margin for loading let old_center = self.center; let old_view_distance = self.view_distance; @@ -214,32 +217,27 @@ impl ChunkManager { lock.send_change(); }; - let view_distance_i32 = i32::from(view_distance); - - self.chunk_sent.retain(|pos| { - (pos.x - center.x).abs().max((pos.y - center.y).abs()) <= view_distance_i32 - }); - - let mut new_queue = BinaryHeap::with_capacity(self.chunk_queue.len()); - for node in &self.chunk_queue { - let dst = (node.1.x - center.x).abs().max((node.1.y - center.y).abs()); - if dst <= view_distance_i32 { - new_queue.push(HeapNode(dst, node.1, node.2.clone())); - } - } - - self.chunk_queue = new_queue; self.center = center; self.view_distance = view_distance; + let view_distance_i32 = i32::from(view_distance); - for dx in (-view_distance_i32)..=view_distance_i32 { - for dy in (-view_distance_i32)..=view_distance_i32 { - let new_pos = center.add_raw(dx, dy); - if !self.chunk_sent.contains(&new_pos) - && let Some(chunk) = level.loaded_chunks.get(&new_pos) - { - self.push_chunk(new_pos, chunk.value().clone()); - } + self.chunk_sent + .retain(|pos| !unloading_chunks.contains(pos)); + + let mut new_queue = BinaryHeap::with_capacity(self.chunk_queue.len()); + for node in self.chunk_queue.drain() { + let dst = (node.1.x - center.x).abs().max((node.1.y - center.y).abs()); + if dst <= view_distance_i32 { + new_queue.push(HeapNode(dst, node.1, node.2)); + } + } + self.chunk_queue = new_queue; + + for pos in loading_chunks { + if !self.chunk_sent.contains(pos) + && let Some(chunk) = level.loaded_chunks.get(pos) + { + self.push_chunk(*pos, chunk.value().clone()); } } } @@ -318,9 +316,10 @@ impl ChunkManager { pub fn next_entity(&mut self) -> Box<[SyncEntityChunk]> { let chunk_size = self.entity_chunk_queue.len().min(self.chunks_per_tick); - let chunks: Vec>> = self + + let chunks: Box<[Arc>]> = self .entity_chunk_queue - .drain(0..chunk_size) + .drain(..chunk_size) .map(|(_, chunk)| chunk) .collect(); @@ -332,7 +331,7 @@ impl ChunkManager { BatchState::Waiting => unreachable!(), } - chunks.into_boxed_slice() + chunks } } @@ -351,7 +350,7 @@ pub struct Player { /// The player's `EnderChest` inventory. pub ender_chest_inventory: Arc, /// The player's configuration settings. Changes when the player changes their settings. - pub config: RwLock, + pub config: ArcSwap, /// The player's current gamemode (e.g., Survival, Creative, Adventure). pub gamemode: AtomicCell, /// The player's previous gamemode @@ -473,7 +472,7 @@ impl Player { Self { living_entity, - config: RwLock::new(config), + config: ArcSwap::new(Arc::new(config)), gameprofile, client, awaiting_teleport: Mutex::new(None), @@ -563,11 +562,11 @@ impl Player { self.client.spawn_task(task) } - pub fn inventory(&self) -> &Arc { + pub const fn inventory(&self) -> &Arc { &self.inventory } - pub fn ender_chest_inventory(&self) -> &Arc { + pub const fn ender_chest_inventory(&self) -> &Arc { &self.ender_chest_inventory } @@ -594,7 +593,7 @@ impl Player { // Decrement the value of watched chunks let chunks_to_clean = level.mark_chunks_as_not_watched(&radial_chunks).await; // Remove chunks with no watchers from the cache - level.clean_entity_chunks(&chunks_to_clean).await; + level.clean_entity_chunks(&chunks_to_clean); // Remove left over entries from all possiblily loaded chunks level.clean_memory(); @@ -657,7 +656,7 @@ impl Player { // Only reduce attack damage if in cooldown // TODO: Enchantments are reduced in the same way, just without the square. if attack_cooldown_progress < 1.0 { - damage_multiplier = 0.2 + attack_cooldown_progress.powi(2) * 0.8; + damage_multiplier = attack_cooldown_progress.powi(2).mul_add(0.8, 0.2); } // Modify the added damage based on the multiplier. let mut damage = base_damage + add_damage * damage_multiplier; @@ -1550,8 +1549,6 @@ impl Player { ability_value |= 1 << (ability as u32); } }; - dbg!(abilities.allow_flying); - dbg!(abilities.flying); // Base Permissions set_ability(Ability::MayFly, abilities.allow_flying); @@ -1629,7 +1626,7 @@ impl Player { /// Sets the player's difficulty level. pub async fn send_difficulty_update(&self) { let world = self.world(); - let level_info = world.level_info.read().await; + let level_info = world.level_info.load(); self.client .enqueue_packet(&CChangeDifficulty::new( level_info.difficulty as u8, @@ -1699,8 +1696,8 @@ impl Player { pitch: Option, ) { let current_world = self.living_entity.entity.world.load_full(); - let yaw = yaw.unwrap_or(new_world.level_info.read().await.spawn_yaw); - let pitch = pitch.unwrap_or(new_world.level_info.read().await.spawn_pitch); + let yaw = yaw.unwrap_or(new_world.level_info.load().spawn_yaw); + let pitch = pitch.unwrap_or(new_world.level_info.load().spawn_pitch); let server = new_world.server.upgrade().unwrap(); @@ -1724,9 +1721,12 @@ impl Player { let new_world = event.new_world; self.set_client_loaded(false); - let uuid = self.gameprofile.id; let player = current_world.remove_player(self, false).await.unwrap(); - new_world.players.write().await.insert(uuid, player.clone()); + new_world.players.rcu(|current_list| { + let mut new_list = (**current_list).clone(); + new_list.push(player.clone()); + new_list + }); self.unload_watched_chunks(¤t_world).await; self.chunk_manager.lock().await.change_world(¤t_world.level, new_world.clone()); @@ -1908,14 +1908,7 @@ impl Player { self.set_client_loaded(false); let block_pos = self.position().to_block_pos(); - let keep_inventory = { - self.world() - .level_info - .read() - .await - .game_rules - .keep_inventory - }; + let keep_inventory = { self.world().level_info.load().game_rules.keep_inventory }; if !keep_inventory { for item in &self.inventory().main_inventory { @@ -2000,7 +1993,7 @@ impl Player { /// Send the player's skin layers and used hand to all players. pub async fn send_client_information(&self) { - let config = self.config.read().await; + let config = self.config.load(); self.living_entity .entity .send_meta_data(&[ @@ -2037,7 +2030,7 @@ impl Player { .has_effect(&StatusEffect::CONDUIT_POWER) .await { - speed *= 1.0 + (self.get_haste_amplifier().await + 1) as f32 * 0.2; + speed *= ((self.get_haste_amplifier().await + 1) as f32).mul_add(0.2, 1.0); } // Fatigue if let Some(fatigue) = self @@ -2108,9 +2101,10 @@ impl Player { let l = 0.02 * rand::random::(); let velocity = Vector3::new( - -yaw_sin * pitch_cos * 0.3 + horizontal_offset.cos() * l, - -pitch_sin * 0.3 + 0.1 + (rand::random::() - rand::random::()) * 0.1, - yaw_cos * pitch_cos * 0.3 + horizontal_offset.sin() * l, + (-yaw_sin * pitch_cos).mul_add(0.3, horizontal_offset.cos() * l), + (rand::random::() - rand::random::()) + .mul_add(0.1, (-pitch_sin).mul_add(0.3, 0.1)), + (yaw_cos * pitch_cos).mul_add(0.3, horizontal_offset.sin() * l), ); // TODO: Merge stacks together @@ -3043,7 +3037,7 @@ impl Default for Abilities { } impl Abilities { - pub fn set_for_gamemode(&mut self, gamemode: GameMode) { + pub const fn set_for_gamemode(&mut self, gamemode: GameMode) { match gamemode { GameMode::Creative => { // self.flying = false; // Start not flying @@ -3135,7 +3129,7 @@ impl Default for ChatSession { impl ChatSession { #[must_use] - pub fn new( + pub const fn new( session_id: Uuid, expires_at: i64, public_key: Box<[u8]>, diff --git a/pumpkin/src/entity/projectile/firework_rocket.rs b/pumpkin/src/entity/projectile/firework_rocket.rs index 82dcf44f2..888a51cec 100644 --- a/pumpkin/src/entity/projectile/firework_rocket.rs +++ b/pumpkin/src/entity/projectile/firework_rocket.rs @@ -87,7 +87,7 @@ impl EntityBase for FireworkRocketEntity { let mut velocity = entity.velocity.load(); if let Some(shooter_id) = self.shooter_id { - if let Some(shooter) = world.get_entity_by_id(shooter_id).await { + if let Some(shooter) = world.get_entity_by_id(shooter_id) { let shooter = shooter.get_entity(); if shooter.fall_flying.load(Ordering::Relaxed) { let rotation = shooter.rotation().to_f64(); diff --git a/pumpkin/src/entity/projectile/mod.rs b/pumpkin/src/entity/projectile/mod.rs index 64a9ffd97..198b0676d 100644 --- a/pumpkin/src/entity/projectile/mod.rs +++ b/pumpkin/src/entity/projectile/mod.rs @@ -59,7 +59,7 @@ impl ThrownItemEntity { /// The velocity and rotation will be set to the same direction. pub fn set_velocity(&self, x: f64, y: f64, z: f64, power: f64, uncertainty: f64) { fn next_triangular(mode: f64, deviation: f64) -> f64 { - mode + deviation * (rand::random::() - rand::random::()) + deviation.mul_add(rand::random::() - rand::random::(), mode) } let velocity = Vector3::new(x, y, z) .normalize() diff --git a/pumpkin/src/entity/projectile/wind_charge.rs b/pumpkin/src/entity/projectile/wind_charge.rs index 6d8aa187f..9fb435163 100644 --- a/pumpkin/src/entity/projectile/wind_charge.rs +++ b/pumpkin/src/entity/projectile/wind_charge.rs @@ -27,7 +27,7 @@ pub struct WindChargeEntity { impl WindChargeEntity { #[must_use] - pub fn new(thrown_item_entity: ThrownItemEntity) -> Self { + pub const fn new(thrown_item_entity: ThrownItemEntity) -> Self { Self { deflect_cooldown: AtomicU8::new(DEFAULT_DEFLECT_COOLDOWN), thrown_item_entity, diff --git a/pumpkin/src/entity/projectile_deflection.rs b/pumpkin/src/entity/projectile_deflection.rs index 56bda31c9..78edf7bde 100644 --- a/pumpkin/src/entity/projectile_deflection.rs +++ b/pumpkin/src/entity/projectile_deflection.rs @@ -14,7 +14,7 @@ impl ProjectileDeflectionType { match self { Self::None => {} Self::Simple => { - let vel = 170.0 + rand::random::() * 20.0; + let vel = rand::random::().mul_add(20.0, 170.0); let current_velocity = projectile .get_entity() diff --git a/pumpkin/src/entity/tnt.rs b/pumpkin/src/entity/tnt.rs index 7d968ff67..bde4937da 100644 --- a/pumpkin/src/entity/tnt.rs +++ b/pumpkin/src/entity/tnt.rs @@ -22,7 +22,7 @@ pub struct TNTEntity { } impl TNTEntity { - pub fn new(entity: Entity, power: f32, fuse: u32) -> Self { + pub const fn new(entity: Entity, power: f32, fuse: u32) -> Self { Self { entity, power, diff --git a/pumpkin/src/item/items/armor_stand.rs b/pumpkin/src/item/items/armor_stand.rs index 0436ff5f3..75a238ec7 100644 --- a/pumpkin/src/item/items/armor_stand.rs +++ b/pumpkin/src/item/items/armor_stand.rs @@ -72,7 +72,7 @@ impl ItemBehaviour for ArmorStandItem { ); if world.is_space_empty(bounding_box).await - && world.get_entities_at_box(&bounding_box).await.is_empty() + && world.get_entities_at_box(&bounding_box).is_empty() { let (player_yaw, _) = player.rotation(); let rotation = ((wrap_degrees(player_yaw - 180.0) + 22.5) / 45.0).floor() * 45.0; diff --git a/pumpkin/src/item/items/bucket.rs b/pumpkin/src/item/items/bucket.rs index ef9c3e685..23f0aff76 100644 --- a/pumpkin/src/item/items/bucket.rs +++ b/pumpkin/src/item/items/bucket.rs @@ -243,7 +243,7 @@ impl ItemBehaviour for FilledBucketItem { SoundCategory::Blocks, &player.position(), 0.5, - 2.6 + (rand::random::() - rand::random::()) * 0.8, + (rand::random::() - rand::random::()).mul_add(0.8, 2.6), ) .await; return; diff --git a/pumpkin/src/item/items/shovel.rs b/pumpkin/src/item/items/shovel.rs index f881f361b..6ce36344e 100644 --- a/pumpkin/src/item/items/shovel.rs +++ b/pumpkin/src/item/items/shovel.rs @@ -13,7 +13,7 @@ use pumpkin_util::math::position::BlockPos; use pumpkin_util::math::vector3::Vector3; use pumpkin_world::item::ItemStack; use pumpkin_world::world::BlockFlags; -use rand::{Rng, rng}; +use rand::{RngExt, rng}; pub struct ShovelItem; diff --git a/pumpkin/src/lib.rs b/pumpkin/src/lib.rs index c61e1e463..e4021b799 100644 --- a/pumpkin/src/lib.rs +++ b/pumpkin/src/lib.rs @@ -205,9 +205,7 @@ impl PumpkinServer { }); } - let mut tcp_listener = None; - - if server.basic_config.java_edition { + let tcp_listener = if server.basic_config.java_edition { let address = server.basic_config.java_edition_address; // Setup the TCP server socket. let listener = match TcpListener::bind(address).await { @@ -260,8 +258,10 @@ impl PumpkinServer { server.spawn_task(lan_broadcast.start(addr)); } - tcp_listener = Some(listener); - } + Some(listener) + } else { + None + }; // Ticker { @@ -282,7 +282,7 @@ impl PumpkinServer { }; Self { - server: server.clone(), + server, tcp_listener, udp_socket, } @@ -336,7 +336,7 @@ impl PumpkinServer { } let kick_message = TextComponent::text("Server stopped"); - for player in self.server.get_all_players().await { + for player in self.server.get_all_players() { player .kick(DisconnectReason::Shutdown, kick_message.clone()) .await; @@ -522,8 +522,7 @@ fn setup_stdin_console(server: Arc) { ServerCommandEvent::new(command.clone()); 'after: { - let dispatcher = &server.command_dispatcher.read().await; - dispatcher + server.command_dispatcher.read().await .handle_command(&command::CommandSender::Console, &server, command.as_str()) .await; }; @@ -590,9 +589,7 @@ fn setup_console(mut rl: Editor, server: A ServerCommandEvent::new(line.clone()); 'after: { - let dispatcher = server.command_dispatcher.read().await; - - dispatcher + server.command_dispatcher.read().await .handle_command(&command::CommandSender::Console, &server, &line) .await; } diff --git a/pumpkin/src/net/bedrock/connection.rs b/pumpkin/src/net/bedrock/connection.rs index 258281d35..812cd229c 100644 --- a/pumpkin/src/net/bedrock/connection.rs +++ b/pumpkin/src/net/bedrock/connection.rs @@ -40,7 +40,7 @@ impl BedrockClient { .await; } - pub fn handle_new_incoming_connection(&self, _packet: &SNewIncomingConnection) { + pub const fn handle_new_incoming_connection(&self, _packet: &SNewIncomingConnection) { // self.connection_state.store(ConnectionState::Login); } diff --git a/pumpkin/src/net/bedrock/mod.rs b/pumpkin/src/net/bedrock/mod.rs index cf7a90293..b78803c65 100644 --- a/pumpkin/src/net/bedrock/mod.rs +++ b/pumpkin/src/net/bedrock/mod.rs @@ -414,7 +414,7 @@ impl BedrockClient { Ok(()) } - fn handle_ack(_ack: &Ack) {} + const fn handle_ack(_ack: &Ack) {} async fn handle_frame_set(self: &Arc, server: &Arc, frame_set: FrameSet) { // TODO: Send all ACKs in short intervals in batches diff --git a/pumpkin/src/net/bedrock/play.rs b/pumpkin/src/net/bedrock/play.rs index 9d8337381..309634a83 100644 --- a/pumpkin/src/net/bedrock/play.rs +++ b/pumpkin/src/net/bedrock/play.rs @@ -56,10 +56,15 @@ impl BedrockClient { .await; let old_view_distance = { - let mut config = player.config.write().await; - let old_view_distance = config.view_distance; - config.view_distance = NonZero::new(view_distance as u8).unwrap(); - old_view_distance + let current_config = player.config.load(); + let old_vd = current_config.view_distance; + let mut new_config = (**current_config).clone(); + + new_config.view_distance = + NonZero::new(view_distance as u8).expect("View distance must be > 0"); + player.config.store(std::sync::Arc::new(new_config)); + + old_vd }; if old_view_distance.get() != view_distance as u8 { diff --git a/pumpkin/src/net/java/login.rs b/pumpkin/src/net/java/login.rs index 1ea4fba39..a6180cad6 100644 --- a/pumpkin/src/net/java/login.rs +++ b/pumpkin/src/net/java/login.rs @@ -31,7 +31,7 @@ impl JavaClient { // If `max_players` is set to zero, then there is no max player count enforced. // TODO: If client is an operator or has otherwise suitable elevated permissions, allow the client to bypass this requirement. let max_players = server.basic_config.max_players; - if max_players > 0 && server.get_player_count().await >= max_players as usize { + if max_players > 0 && server.get_player_count() >= max_players as usize { self.kick(TextComponent::translate( "multiplayer.disconnect.server_full", [], @@ -150,7 +150,7 @@ impl JavaClient { } // Don't allow duplicate UUIDs - if let Some(online_player) = &server.get_player_by_uuid(profile.id).await { + if let Some(online_player) = &server.get_player_by_uuid(profile.id) { log::debug!( "Player (IP '{}', username '{}') tried to log in with the same UUID ('{}') as an online player (username '{}')", &self.address.lock().await, @@ -167,7 +167,7 @@ impl JavaClient { } // Don't allow a duplicate username - if let Some(online_player) = &server.get_player_by_name(&profile.name).await { + if let Some(online_player) = &server.get_player_by_name(&profile.name) { log::debug!( "A player (IP '{}', attempted username '{}') tried to log in with the same username as an online player (UUID '{}', username '{}')", &self.address.lock().await, diff --git a/pumpkin/src/net/java/play.rs b/pumpkin/src/net/java/play.rs index bcebb32d3..021489ebb 100644 --- a/pumpkin/src/net/java/play.rs +++ b/pumpkin/src/net/java/play.rs @@ -213,11 +213,11 @@ impl JavaClient { } } - fn clamp_horizontal(pos: f64) -> f64 { + const fn clamp_horizontal(pos: f64) -> f64 { pos.clamp(-3.0E7, 3.0E7) } - fn clamp_vertical(pos: f64) -> f64 { + const fn clamp_vertical(pos: f64) -> f64 { pos.clamp(-2.0E7, 2.0E7) } @@ -976,7 +976,7 @@ impl JavaClient { return; } - if let Err(err) = self.validate_chat_session(player, server, &session).await { + if let Err(err) = self.validate_chat_session(player, server, &session) { log::log!( err.severity(), "{} (uuid {}) {}", @@ -1017,7 +1017,7 @@ impl JavaClient { } /// Runs vanilla checks for a valid player session - pub async fn validate_chat_session( + pub fn validate_chat_session( &self, player: &Player, server: &Server, @@ -1040,7 +1040,7 @@ impl JavaClient { signable.extend_from_slice(&session.expires_at.to_be_bytes()); signable.extend_from_slice(&session.public_key); - let public_keys_guard = server.mojang_public_keys.lock().await; + let public_keys_guard = server.mojang_public_keys.load(); // Verify signature with RSA-SHA1 let is_valid = public_keys_guard.iter().any(|key| { @@ -1074,38 +1074,38 @@ impl JavaClient { } let (update_settings, update_watched) = { - let mut config = player.config.write().await; - let update_settings = config.main_hand != main_hand - || config.skin_parts != client_information.skin_parts; + // 1. Load current snapshot + let current_config = player.config.load(); - let old_view_distance = config.view_distance; + // 2. Calculate if settings changed before we overwrite + let update_settings = current_config.main_hand != main_hand + || current_config.skin_parts != client_information.skin_parts; - let update_watched = - if old_view_distance.get() == client_information.view_distance as u8 { - false - } else { - log::debug!( - "Player {} ({}) updated their render distance: {} -> {}.", - player.gameprofile.name, - self.id, - old_view_distance, - client_information.view_distance - ); + let old_view_distance = current_config.view_distance; + let new_view_distance_raw = client_information.view_distance as u8; - true - }; + let update_watched = if old_view_distance.get() == new_view_distance_raw { + false + } else { + log::debug!( + "Player {} ({}) updated their render distance: {} -> {}.", + player.gameprofile.name, + self.id, + old_view_distance, + new_view_distance_raw + ); + true + }; - *config = PlayerConfig { + // 3. Construct the new config + // If view_distance is 0, we exit early (safe guard) + let Some(new_view_distance) = NonZeroU8::new(new_view_distance_raw) else { + return; + }; + + let new_config = PlayerConfig { locale: client_information.locale, - // A negative view distance would be impossible and makes no sense, right? Mojang: Let's make it signed :D - // client_information.view_distance was checked above to be > 0, so compiler should optimize this out. - view_distance: match NonZeroU8::new(client_information.view_distance as u8) { - Some(dist) => dist, - None => { - // Unreachable branch - return; - } - }, + view_distance: new_view_distance, chat_mode, chat_colors: client_information.chat_colors, skin_parts: client_information.skin_parts, @@ -1113,6 +1113,10 @@ impl JavaClient { text_filtering: client_information.text_filtering, server_listing: client_information.server_listing, }; + + // 4. Atomically swap the new config into the player + player.config.store(std::sync::Arc::new(new_config)); + (update_settings, update_watched) }; @@ -1199,7 +1203,7 @@ impl JavaClient { // TODO: set as camera entity when spectator let world = player_entity.world.load_full(); - let player_victim = world.get_player_by_id(entity_id.0).await; + let player_victim = world.get_player_by_id(entity_id.0); if entity_id.0 == player.entity_id() { // This can't be triggered from a non-modded client. self.kick(TextComponent::translate( @@ -1228,7 +1232,7 @@ impl JavaClient { return; } player.attack(player_victim).await; - } else if let Some(entity_victim) = world.get_entity_by_id(entity_id.0).await { + } else if let Some(entity_victim) = world.get_entity_by_id(entity_id.0) { player.attack(entity_victim).await; } else { log::error!( @@ -1245,7 +1249,7 @@ impl JavaClient { } ActionType::Interact | ActionType::InteractAt => { // TODO: split this up - let entity = player.world().get_player_by_id(entity_id.0).await; + let entity = player.world().get_player_by_id(entity_id.0); if let Some(entity) = entity { let held = player.inventory.held_item(); let mut stack = held.lock().await; @@ -2082,8 +2086,8 @@ impl JavaClient { // Check if there is a player in the way of the block being placed let state = BlockState::from_id(new_state); - for player in world.get_nearby_players(location.0.to_f64(), 3.0).await { - let player_box = player.1.living_entity.entity.bounding_box.load(); + for player in world.get_nearby_players(location.0.to_f64(), 3.0) { + let player_box = player.living_entity.entity.bounding_box.load(); for shape in state.get_block_collision_shapes() { if shape.at_pos(final_block_pos).intersects(&player_box) { return Ok(false); diff --git a/pumpkin/src/net/mod.rs b/pumpkin/src/net/mod.rs index 5a0643e2b..80f6e29b7 100644 --- a/pumpkin/src/net/mod.rs +++ b/pumpkin/src/net/mod.rs @@ -376,7 +376,7 @@ mod tests { /// Test case for a standard, valid English name at max length. #[test] - fn test_valid_max_length_ascii() { + fn valid_max_length_ascii() { let name = "player_name_1234"; // 16 characters (16 bytes) assert!( is_valid_player_name(name), @@ -386,7 +386,7 @@ mod tests { /// Test case for a short, valid ASCII name. #[test] - fn test_valid_short_ascii() { + fn valid_short_ascii() { let name = "GamerX"; assert!( is_valid_player_name(name), @@ -396,7 +396,7 @@ mod tests { /// Test case for a name containing allowed punctuation (codepoints 33-126). #[test] - fn test_valid_with_punctuation() { + fn valid_with_punctuation() { let name = "!-@#$%.^&*_+-="; assert!( is_valid_player_name(name), @@ -406,7 +406,7 @@ mod tests { /// Test case for allowed high-codepoint Unicode characters (like Chinese/CJK). #[test] - fn test_valid_unicode_chinese() { + fn valid_unicode_chinese() { let name = "玩家一号"; // 4 characters, 12 bytes assert!( is_valid_player_name(name), @@ -416,7 +416,7 @@ mod tests { /// Test case for a mix of valid ASCII and Unicode characters. #[test] - fn test_valid_mixed_chars() { + fn valid_mixed_chars() { let name = "Player_玩家"; // 9 characters assert!( is_valid_player_name(name), @@ -426,7 +426,7 @@ mod tests { /// Test case for a name that exceeds the 16-byte limit (ASCII). #[test] - fn test_invalid_length_ascii_over() { + fn invalid_length_ascii_over() { let name = "this_name_is_too_long"; // 21 characters (21 bytes) assert!( !is_valid_player_name(name), @@ -436,7 +436,7 @@ mod tests { /// Test case for a name that exceeds the 16-byte limit (Unicode). #[test] - fn test_invalid_length_unicode_over() { + fn invalid_length_unicode_over() { let name = "超长玩家名称哈哈"; // 8 Chinese characters * 3 bytes/char = 24 bytes assert!( !is_valid_player_name(name), @@ -446,7 +446,7 @@ mod tests { /// Test case for a name containing a standard space (codepoint 32). #[test] - fn test_invalid_contains_space() { + fn invalid_contains_space() { let name = "Player Name"; assert!( !is_valid_player_name(name), @@ -456,7 +456,7 @@ mod tests { /// Test case for an empty string (length 0, but included for completeness). #[test] - fn test_invalid_empty_string() { + fn invalid_empty_string() { let name = ""; assert!( is_valid_player_name(name), @@ -466,7 +466,7 @@ mod tests { /// Test case for a name containing a control character (e.g., Null, codepoint 0). #[test] - fn test_invalid_contains_null() { + fn invalid_contains_null() { let name = "Player\0Name"; assert!( !is_valid_player_name(name), @@ -476,7 +476,7 @@ mod tests { /// Test case for a name containing a newline character (codepoint 10). #[test] - fn test_invalid_contains_newline() { + fn invalid_contains_newline() { let name = "Player\nName"; assert!( !is_valid_player_name(name), @@ -486,7 +486,7 @@ mod tests { /// Test case for a name containing the DEL control character (codepoint 127). #[test] - fn test_invalid_contains_del() { + fn invalid_contains_del() { // DEL character is char::from_u32(127).unwrap() let name = format!("Player{}Name", 127u8 as char); assert!( diff --git a/pumpkin/src/net/proxy/velocity.rs b/pumpkin/src/net/proxy/velocity.rs index e8c175a97..7133c6512 100644 --- a/pumpkin/src/net/proxy/velocity.rs +++ b/pumpkin/src/net/proxy/velocity.rs @@ -13,7 +13,7 @@ use pumpkin_protocol::{ Property, java::client::login::CLoginPluginRequest, java::server::login::SLoginPluginResponse, ser::NetworkReadExt, }; -use rand::Rng; +use rand::RngExt; use sha2::Sha256; use thiserror::Error; diff --git a/pumpkin/src/net/query.rs b/pumpkin/src/net/query.rs index 2ee7bc0bb..555de6ec0 100644 --- a/pumpkin/src/net/query.rs +++ b/pumpkin/src/net/query.rs @@ -10,7 +10,7 @@ use pumpkin_protocol::query::{ CBasicStatus, CFullStatus, CHandshake, PacketType, RawQueryPacket, SHandshake, SStatusRequest, }; use pumpkin_world::CURRENT_MC_VERSION; -use rand::Rng; +use rand::RngExt; use tokio::{net::UdpSocket, sync::RwLock, time}; use crate::{SHOULD_STOP, STOP_INTERRUPT, server::Server}; @@ -117,13 +117,12 @@ async fn handle_packet( if packet.is_full_request { // Get 4 players let mut players: Vec = Vec::new(); - for world in server.worlds.read().await.iter() { + for world in server.worlds.load().iter() { let mut world_players = world .players - .read() - .await + .load() // Although there is no documented limit, we will limit to 4 players - .values() + .iter() .take(4 - players.len()) .map(|player| { CString::new(player.gameprofile.name.as_str()).unwrap() @@ -152,7 +151,7 @@ async fn handle_packet( version: CString::new(CURRENT_MC_VERSION)?, plugins: CString::new(plugins)?, map: CString::new("world")?, // TODO: Get actual world name - num_players: server.get_player_count().await, + num_players: server.get_player_count(), max_players: server.basic_config.max_players as usize, host_port: bound_addr.port(), host_ip: CString::new(bound_addr.ip().to_string())?, @@ -167,7 +166,7 @@ async fn handle_packet( session_id: packet.session_id, motd: CString::new(server.basic_config.motd.as_str())?, map: CString::new("world")?, - num_players: server.get_player_count().await, + num_players: server.get_player_count(), max_players: server.basic_config.max_players as usize, host_port: bound_addr.port(), host_ip: CString::new(bound_addr.ip().to_string())?, diff --git a/pumpkin/src/plugin/api/context.rs b/pumpkin/src/plugin/api/context.rs index db4b4e367..0f5f54a20 100644 --- a/pumpkin/src/plugin/api/context.rs +++ b/pumpkin/src/plugin/api/context.rs @@ -83,8 +83,9 @@ impl Context { /// /// # Returns /// An optional reference to the player if found, or `None` if not. - pub async fn get_player_by_name(&self, player_name: String) -> Option> { - self.server.get_player_by_name(&player_name).await + #[must_use] + pub fn get_player_by_name(&self, player_name: &str) -> Option> { + self.server.get_player_by_name(player_name) } /// Registers a service with the plugin context. @@ -166,8 +167,8 @@ impl Context { dispatcher_lock.register(tree, full_permission_node); }; - for world in self.server.worlds.read().await.iter() { - for player in world.players.read().await.values() { + for world in self.server.worlds.load().iter() { + for player in world.players.load().iter() { let command_dispatcher = self.server.command_dispatcher.read().await; client_suggestions::send_c_commands_packet( player, @@ -189,8 +190,8 @@ impl Context { dispatcher_lock.unregister(name); }; - for world in self.server.worlds.read().await.iter() { - for player in world.players.read().await.values() { + for world in self.server.worlds.load().iter() { + for player in world.players.load().iter() { let command_dispatcher = self.server.command_dispatcher.read().await; client_suggestions::send_c_commands_packet( player, @@ -223,7 +224,7 @@ impl Context { let permission_manager = self.permission_manager.read().await; // If the player isn't online, we need to find their op level - let player_op_level = (self.server.get_player_by_uuid(*player_uuid).await) + let player_op_level = (self.server.get_player_by_uuid(*player_uuid)) .map_or(PermissionLvl::Zero, |player| player.permission_lvl.load()); permission_manager diff --git a/pumpkin/src/plugin/api/events/block/block_break.rs b/pumpkin/src/plugin/api/events/block/block_break.rs index 94aaabb1a..fe2338195 100644 --- a/pumpkin/src/plugin/api/events/block/block_break.rs +++ b/pumpkin/src/plugin/api/events/block/block_break.rs @@ -43,7 +43,7 @@ impl BlockBreakEvent { /// # Returns /// A new instance of `BlockBreakEvent`. #[must_use] - pub fn new( + pub const fn new( player: Option>, block: &'static Block, block_position: BlockPos, diff --git a/pumpkin/src/plugin/api/events/player/player_change_world.rs b/pumpkin/src/plugin/api/events/player/player_change_world.rs index ffdc00163..15a9e5b20 100644 --- a/pumpkin/src/plugin/api/events/player/player_change_world.rs +++ b/pumpkin/src/plugin/api/events/player/player_change_world.rs @@ -44,7 +44,7 @@ impl PlayerChangeWorldEvent { /// /// # Returns /// A new instance of `PlayerChangeWorldEvent`. - pub fn new( + pub const fn new( player: Arc, previous_world: Arc, new_world: Arc, diff --git a/pumpkin/src/plugin/api/events/player/player_chat.rs b/pumpkin/src/plugin/api/events/player/player_chat.rs index 4453f2e9d..66930a2a0 100644 --- a/pumpkin/src/plugin/api/events/player/player_chat.rs +++ b/pumpkin/src/plugin/api/events/player/player_chat.rs @@ -31,7 +31,7 @@ impl PlayerChatEvent { /// /// # Returns /// A new instance of `PlayerChatEvent`. - pub fn new(player: Arc, message: String, recipients: Vec>) -> Self { + pub const fn new(player: Arc, message: String, recipients: Vec>) -> Self { Self { player, message, diff --git a/pumpkin/src/plugin/api/events/player/player_command_send.rs b/pumpkin/src/plugin/api/events/player/player_command_send.rs index 168cf061f..bc90eb4dd 100644 --- a/pumpkin/src/plugin/api/events/player/player_command_send.rs +++ b/pumpkin/src/plugin/api/events/player/player_command_send.rs @@ -29,7 +29,7 @@ impl PlayerCommandSendEvent { /// /// # Returns /// A new instance of `PlayerCommandSendEvent`. - pub fn new(player: Arc, command: String) -> Self { + pub const fn new(player: Arc, command: String) -> Self { Self { player, command, diff --git a/pumpkin/src/plugin/api/events/player/player_gamemode_change.rs b/pumpkin/src/plugin/api/events/player/player_gamemode_change.rs index 361fa4461..0ed498656 100644 --- a/pumpkin/src/plugin/api/events/player/player_gamemode_change.rs +++ b/pumpkin/src/plugin/api/events/player/player_gamemode_change.rs @@ -32,7 +32,11 @@ impl PlayerGamemodeChangeEvent { /// /// # Returns /// A new instance of `PlayerGamemodeChangeEvent`. - pub fn new(player: Arc, previous_gamemode: GameMode, new_gamemode: GameMode) -> Self { + pub const fn new( + player: Arc, + previous_gamemode: GameMode, + new_gamemode: GameMode, + ) -> Self { Self { player, previous_gamemode, diff --git a/pumpkin/src/plugin/api/events/player/player_join.rs b/pumpkin/src/plugin/api/events/player/player_join.rs index bcee2365a..3e9581574 100644 --- a/pumpkin/src/plugin/api/events/player/player_join.rs +++ b/pumpkin/src/plugin/api/events/player/player_join.rs @@ -28,7 +28,7 @@ impl PlayerJoinEvent { /// /// # Returns /// A new instance of `PlayerJoinEvent`. - pub fn new(player: Arc, join_message: TextComponent) -> Self { + pub const fn new(player: Arc, join_message: TextComponent) -> Self { Self { player, join_message, diff --git a/pumpkin/src/plugin/api/events/player/player_leave.rs b/pumpkin/src/plugin/api/events/player/player_leave.rs index c66683fd9..ca0cac6e6 100644 --- a/pumpkin/src/plugin/api/events/player/player_leave.rs +++ b/pumpkin/src/plugin/api/events/player/player_leave.rs @@ -28,7 +28,7 @@ impl PlayerLeaveEvent { /// /// # Returns /// A new instance of `PlayerLeaveEvent`. - pub fn new(player: Arc, leave_message: TextComponent) -> Self { + pub const fn new(player: Arc, leave_message: TextComponent) -> Self { Self { player, leave_message, diff --git a/pumpkin/src/plugin/api/events/player/player_login.rs b/pumpkin/src/plugin/api/events/player/player_login.rs index b408e0fba..511855690 100644 --- a/pumpkin/src/plugin/api/events/player/player_login.rs +++ b/pumpkin/src/plugin/api/events/player/player_login.rs @@ -30,7 +30,7 @@ impl PlayerLoginEvent { /// /// # Returns /// A new instance of `PlayerLoginEvent`. - pub fn new(player: Arc, kick_message: TextComponent) -> Self { + pub const fn new(player: Arc, kick_message: TextComponent) -> Self { Self { player, kick_message, diff --git a/pumpkin/src/plugin/api/events/player/player_move.rs b/pumpkin/src/plugin/api/events/player/player_move.rs index bdcde2a92..a08e0f230 100644 --- a/pumpkin/src/plugin/api/events/player/player_move.rs +++ b/pumpkin/src/plugin/api/events/player/player_move.rs @@ -34,7 +34,7 @@ impl PlayerMoveEvent { /// /// # Returns /// A new instance of `PlayerMoveEvent`. - pub fn new(player: Arc, from: Vector3, to: Vector3) -> Self { + pub const fn new(player: Arc, from: Vector3, to: Vector3) -> Self { Self { player, from, diff --git a/pumpkin/src/plugin/api/events/player/player_teleport.rs b/pumpkin/src/plugin/api/events/player/player_teleport.rs index 640797a37..3fc7ee4da 100644 --- a/pumpkin/src/plugin/api/events/player/player_teleport.rs +++ b/pumpkin/src/plugin/api/events/player/player_teleport.rs @@ -34,7 +34,7 @@ impl PlayerTeleportEvent { /// /// # Returns /// A new instance of `PlayerTeleportEvent`. - pub fn new(player: Arc, from: Vector3, to: Vector3) -> Self { + pub const fn new(player: Arc, from: Vector3, to: Vector3) -> Self { Self { player, from, diff --git a/pumpkin/src/plugin/api/events/server/server_broadcast.rs b/pumpkin/src/plugin/api/events/server/server_broadcast.rs index 123a478de..02a4d452a 100644 --- a/pumpkin/src/plugin/api/events/server/server_broadcast.rs +++ b/pumpkin/src/plugin/api/events/server/server_broadcast.rs @@ -23,7 +23,7 @@ impl ServerBroadcastEvent { /// # Returns /// A new instance of `ServerBroadcastEvent`. #[must_use] - pub fn new(message: TextComponent, sender: TextComponent) -> Self { + pub const fn new(message: TextComponent, sender: TextComponent) -> Self { Self { message, sender, diff --git a/pumpkin/src/plugin/api/events/server/server_command.rs b/pumpkin/src/plugin/api/events/server/server_command.rs index adeb8a952..c77f0361d 100644 --- a/pumpkin/src/plugin/api/events/server/server_command.rs +++ b/pumpkin/src/plugin/api/events/server/server_command.rs @@ -19,7 +19,7 @@ impl ServerCommandEvent { /// # Returns /// A new instance of `ServerCommandEvent`. #[must_use] - pub fn new(command: String) -> Self { + pub const fn new(command: String) -> Self { Self { command, cancelled: false, diff --git a/pumpkin/src/plugin/mod.rs b/pumpkin/src/plugin/mod.rs index 5562f58e1..dda57d975 100644 --- a/pumpkin/src/plugin/mod.rs +++ b/pumpkin/src/plugin/mod.rs @@ -147,7 +147,7 @@ where type HandlerMap = HashMap<&'static str, Vec>>; /// Plugin loading state -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum PluginState { Loading, Loaded, diff --git a/pumpkin/src/server/mod.rs b/pumpkin/src/server/mod.rs index dcf604e76..e542b89be 100644 --- a/pumpkin/src/server/mod.rs +++ b/pumpkin/src/server/mod.rs @@ -13,6 +13,7 @@ use crate::plugin::server::server_broadcast::ServerBroadcastEvent; use crate::server::tick_rate_manager::ServerTickRateManager; use crate::world::custom_bossbar::CustomBossbars; use crate::{command::dispatcher::CommandDispatcher, entity::player::Player, world::World}; +use arc_swap::ArcSwap; use connection_cache::{CachedBranding, CachedStatus}; use key_store::KeyStore; use pumpkin_config::{AdvancedConfiguration, BasicConfiguration}; @@ -84,14 +85,14 @@ pub struct Server { /// Item behaviour. pub item_registry: Arc, /// Manages multiple worlds within the server. - pub worlds: RwLock>>, + pub worlds: ArcSwap>>, /// All the dimensions that exist on the server. pub dimensions: Vec, /// Assigns unique IDs to containers. container_id: AtomicU32, /// Mojang's public keys, used for chat session signing /// Pulled from Mojang API on startup - pub mojang_public_keys: Mutex>, + pub mojang_public_keys: ArcSwap>, /// The server's custom bossbars pub bossbars: Mutex, /// The default gamemode when a player joins the server (reset every restart) @@ -115,7 +116,7 @@ pub struct Server { tasks: TaskTracker, // world stuff which maybe should be put into a struct - pub level_info: Arc>, + pub level_info: Arc>, world_info_writer: Arc, // Gets unlocked when dropped // TODO: Make this a trait @@ -176,7 +177,7 @@ impl Server { }); let seed = level_info.world_gen_settings.seed; - let level_info = Arc::new(RwLock::new(level_info)); + let level_info = Arc::new(ArcSwap::new(Arc::new(level_info))); let listing = Mutex::new(CachedStatus::new(&basic_config)); let defaultgamemode = Mutex::new(DefaultGamemode { @@ -191,11 +192,20 @@ impl Server { let tick_rate_manager = Arc::new(ServerTickRateManager::new(basic_config.tps)); - let mojang_public_keys = if basic_config.allow_chat_reports { - fetch_mojang_public_keys(&advanced_config.networking.authentication).unwrap() - } else { - Vec::new() - }; + let mojang_keys_task = tokio::spawn({ + let auth_config = advanced_config.networking.authentication.clone(); + let allow_chat = basic_config.allow_chat_reports; + async move { + if allow_chat { + fetch_mojang_public_keys(&auth_config).unwrap_or_else(|e| { + log::error!("Failed to fetch Mojang keys: {e}"); + Vec::new() + }) + } else { + Vec::new() + } + } + }); let server = Self { basic_config, @@ -207,7 +217,7 @@ impl Server { ))), permission_registry, container_id: 0.into(), - worlds: RwLock::new(vec![]), + worlds: ArcSwap::from_pointee(vec![]), dimensions: vec![ Dimension::OVERWORLD, Dimension::THE_NETHER, @@ -230,13 +240,12 @@ impl Server { tasks: TaskTracker::new(), server_guid: rand::random(), player_idle_timeout: AtomicI32::new(0), - mojang_public_keys: Mutex::new(mojang_public_keys), + mojang_public_keys: ArcSwap::from_pointee(Vec::new()), world_info_writer: Arc::new(AnvilLevelInfo), - level_info: level_info.clone(), + level_info, _locker: Arc::new(locker), }; let server = Arc::new(server); - let level_config = Arc::new(server.advanced_config.world.clone()); let server_clone = server.clone(); tokio::spawn(async move { @@ -246,74 +255,43 @@ impl Server { .await; }); - let weak_server = Arc::downgrade(&server); - - log::info!("Loading Overworld: {seed}"); - let overworld_task = tokio::task::spawn_blocking({ + let world_loader = |dim: Dimension| { let path = world_path.clone(); let registry = block_registry.clone(); - let level_info = level_info.clone(); - let weak = weak_server.clone(); - let config = level_config.clone(); - move || { + let l_info = server.level_info.clone(); // Access from struct + let weak = Arc::downgrade(&server); + let config = Arc::new(server.advanced_config.world.clone()); + + tokio::task::spawn_blocking(move || { + log::info!("Loading {}", dim.minecraft_name); World::load( - into_level(Dimension::OVERWORLD, &config, path, registry.clone(), seed), - level_info, - Dimension::OVERWORLD, + into_level(dim, &config, path, registry.clone(), seed), + l_info, + dim, registry, weak, ) - } - }); - - let nether_task = tokio::task::spawn_blocking({ - let path = world_path.clone(); - let registry = block_registry.clone(); - let level_info = level_info.clone(); - let weak = weak_server.clone(); - let config = level_config.clone(); - move || { - World::load( - into_level(Dimension::THE_NETHER, &config, path, registry.clone(), seed), - level_info, - Dimension::THE_NETHER, - registry, - weak, - ) - } - }); - - let end_task = tokio::task::spawn_blocking({ - let path = world_path.clone(); - let registry = block_registry.clone(); - let level_info = level_info.clone(); - let weak = weak_server.clone(); - let config = level_config.clone(); - move || { - World::load( - into_level(Dimension::THE_END, &config, path, registry.clone(), seed), - level_info, - Dimension::THE_END, - registry, - weak, - ) - } - }); - - let (overworld_res, nether_res, end_res) = - tokio::join!(overworld_task, nether_task, end_task); - - let overworld = overworld_res.expect("Overworld load panicked"); - let nether = nether_res.expect("Nether load panicked"); - let end = end_res.expect("End load panicked"); - - { - let mut worlds = server.worlds.write().await; - worlds.push(overworld.into()); - worlds.push(nether.into()); - worlds.push(end.into()); + }) }; + log::info!("Starting parallel world load..."); + let (overworld, nether, end, keys) = tokio::join!( + world_loader(Dimension::OVERWORLD), + world_loader(Dimension::THE_NETHER), + world_loader(Dimension::THE_END), + mojang_keys_task + ); + + let worlds_vec = vec![ + Arc::new(overworld.expect("Overworld panicked")), + Arc::new(nether.expect("Nether panicked")), + Arc::new(end.expect("End panicked")), + ]; + server.worlds.store(Arc::new(worlds_vec)); + if let Ok(k) = keys { + server.mojang_public_keys.store(Arc::new(k)); + } + log::info!("All worlds loaded successfully."); server } @@ -328,9 +306,9 @@ impl Server { self.tasks.spawn(task) } - pub async fn get_world_from_dimension(&self, dimension: &Dimension) -> Arc { + pub fn get_world_from_dimension(&self, dimension: &Dimension) -> Arc { // TODO: this is really bad - let world_guard = self.worlds.read().await; + let world_guard = self.worlds.load(); if dimension == &Dimension::OVERWORLD { world_guard.first() } else if dimension == &Dimension::THE_NETHER { @@ -378,14 +356,13 @@ impl Server { let (world, nbt) = if let Ok(Some(data)) = self.player_data_storage.load_data(&profile.id) { if let Some(dimension_key) = data.get_string("Dimension") { if let Some(dimension) = Dimension::from_name(dimension_key) { - let world = self.get_world_from_dimension(dimension).await; + let world = self.get_world_from_dimension(dimension); (world, Some(data)) } else { log::warn!("Invalid dimension key in player data: {dimension_key}"); let default_world = self .worlds - .read() - .await + .load() .first() .expect("Default world should exist") .clone(); @@ -395,8 +372,7 @@ impl Server { // Player data exists but doesn't have a "Dimension" key. let default_world = self .worlds - .read() - .await + .load() .first() .expect("Default world should exist") .clone(); @@ -406,8 +382,7 @@ impl Server { // No player data found or an error occurred, default to the Overworld. let default_world = self .worlds - .read() - .await + .load() .first() .expect("Default world should exist") .clone(); @@ -437,8 +412,8 @@ impl Server { player.screen_handler_sync_handler.store_player(player.clone()).await; #[expect(clippy::if_then_some_else_none)] if world - .add_player(player.gameprofile.id, player.clone()) - .await.is_ok() { + .add_player(player.clone()) + .is_ok() { // TODO: Config if we want increase online if let Some(config) = config { // TODO: Config so we can also just ignore this hehe @@ -472,10 +447,10 @@ impl Server { log::debug!("Done awaiting tasks for server"); log::info!("Starting worlds"); - for world in self.worlds.read().await.iter() { + for world in self.worlds.load().iter() { world.shutdown().await; } - let level_data = self.level_info.read().await; + let level_data = self.level_info.load(); // then lets save the world info if let Err(err) = self @@ -495,9 +470,8 @@ impl Server { /// /// * `packet`: A reference to the packet to be broadcast. The packet must implement the `ClientPacket` trait. pub async fn broadcast_packet_all(&self, packet: &P) { - for world in self.worlds.read().await.iter() { - let current_players = world.players.read().await; - for player in current_players.values() { + for world in self.worlds.load().iter() { + for player in world.players.load().iter() { player.client.enqueue_packet(packet).await; } } @@ -515,7 +489,7 @@ impl Server { ServerBroadcastEvent::new(message.clone(), sender_name.clone()); 'after: { - for world in self.worlds.read().await.iter() { + for world in self.worlds.load().iter() { world .broadcast_message(&event.message, &event.sender, chat_type, target_name) .await; @@ -540,23 +514,25 @@ impl Server { /// /// This function does not handle the actual mob spawn options update, which is a TODO item for future implementation. pub async fn set_difficulty(&self, difficulty: Difficulty, force_update: Option) { - let mut level_info = self.level_info.write().await; - if level_info.difficulty_locked && !force_update.unwrap_or_default() { + let current_info = self.level_info.load(); + if current_info.difficulty_locked && !force_update.unwrap_or_default() { return; } - let difficulty = if self.basic_config.hardcore { + let new_difficulty = if self.basic_config.hardcore { Difficulty::Hard } else { difficulty }; - level_info.difficulty = difficulty; - let locked = level_info.difficulty_locked; - drop(level_info); + let mut new_info = (**current_info).clone(); - for world in &*self.worlds.read().await { - world.level_info.write().await.difficulty = difficulty; + new_info.difficulty = new_difficulty; + let locked = new_info.difficulty_locked; + self.level_info.store(Arc::new(new_info)); + + for world in self.worlds.load().iter() { + world.set_difficulty(difficulty); } self.broadcast_packet_all(&CChangeDifficulty::new(difficulty as u8, locked)) @@ -575,9 +551,9 @@ impl Server { /// # Returns /// /// An `Option>` containing the player if found, or `None` if not found. - pub async fn get_player_by_name(&self, name: &str) -> Option> { - for world in self.worlds.read().await.iter() { - if let Some(player) = world.get_player_by_name(name).await { + pub fn get_player_by_name(&self, name: &str) -> Option> { + for world in self.worlds.load().iter() { + if let Some(player) = world.get_player_by_name(name) { return Some(player); } } @@ -587,8 +563,8 @@ impl Server { pub async fn get_players_by_ip(&self, ip: IpAddr) -> Vec> { let mut players = Vec::>::new(); - for world in self.worlds.read().await.iter() { - for player in world.players.read().await.values() { + for world in self.worlds.load().iter() { + for player in world.players.load().iter() { if player.client.address().await.ip() == ip { players.push(player.clone()); } @@ -599,20 +575,19 @@ impl Server { } /// Returns all players from all worlds. - pub async fn get_all_players(&self) -> Vec> { + pub fn get_all_players(&self) -> Vec> { let mut players = Vec::>::new(); - for world in self.worlds.read().await.iter() { - players.extend(world.players.read().await.values().cloned()); + for world in self.worlds.load().iter() { + players.extend(world.players.load().iter().cloned()); } players } /// Returns a random player from any of the worlds, or `None` if all worlds are empty. - pub async fn get_random_player(&self) -> Option> { - let players = self.get_all_players().await; - + pub fn get_random_player(&self) -> Option> { + let players = self.get_all_players(); players.choose(&mut rand::rng()).map(Arc::<_>::clone) } @@ -628,9 +603,9 @@ impl Server { /// # Returns /// /// An `Option>` containing the player if found, or `None` if not found. - pub async fn get_player_by_uuid(&self, id: uuid::Uuid) -> Option> { - for world in self.worlds.read().await.iter() { - if let Some(player) = world.get_player_by_uuid(id).await { + pub fn get_player_by_uuid(&self, id: uuid::Uuid) -> Option> { + for world in self.worlds.load().iter() { + if let Some(player) = world.get_player_by_uuid(id) { return Some(player); } } @@ -644,19 +619,19 @@ impl Server { /// # Returns /// /// The total number of players connected to the server. - pub async fn get_player_count(&self) -> usize { + pub fn get_player_count(&self) -> usize { let mut count = 0; - for world in self.worlds.read().await.iter() { - count += world.players.read().await.len(); + for world in self.worlds.load().iter() { + count += world.players.load().len(); } count } /// Similar to [`Server::get_player_count`] >= n, but may be more efficient since it stops its iteration through all worlds as soon as n players were found. - pub async fn has_n_players(&self, n: usize) -> bool { + pub fn has_n_players(&self, n: usize) -> bool { let mut count = 0; - for world in self.worlds.read().await.iter() { - count += world.players.read().await.len(); + for world in self.worlds.load().iter() { + count += world.players.load().len(); if count >= n { return true; } @@ -673,7 +648,7 @@ impl Server { self.branding.get_branding() } - pub fn get_status(&self) -> &Mutex { + pub const fn get_status(&self) -> &Mutex { &self.listing } @@ -717,22 +692,21 @@ impl Server { /// This includes player ticking (network, keep-alives) and flushing world updates to clients. pub async fn tick_players_and_network(&self) { // First, flush pending block updates and synced block events to clients - for world in self.worlds.read().await.iter() { + for world in self.worlds.load().iter() { world.flush_block_updates().await; world.flush_synced_block_events().await; } - let players_to_tick: Vec<_> = self.get_all_players().await; + let players_to_tick: Vec<_> = self.get_all_players(); for player in players_to_tick { player.tick(self).await; } } /// Ticks the game logic for all worlds. This is the part that is affected by `/tick freeze`. pub async fn tick_worlds(self: &Arc) { - let worlds = self.worlds.read().await; let mut set = JoinSet::new(); - for world in worlds.iter() { + for world in self.worlds.load().iter() { let world = world.clone(); let server = self.clone(); @@ -796,7 +770,7 @@ impl Server { #[expect(clippy::too_many_lines)] #[expect(clippy::option_if_let_else)] - pub async fn select_entities( + pub fn select_entities( &self, target_selector: &TargetSelector, source: Option<&CommandSender>, @@ -817,7 +791,7 @@ impl Server { } } EntitySelectorType::RandomPlayer => { - if let Some(player) = self.get_random_player().await { + if let Some(player) = self.get_random_player() { vec![player as Arc].into_iter() } else { vec![].into_iter() @@ -825,21 +799,19 @@ impl Server { } EntitySelectorType::AllPlayers => self .get_all_players() - .await .into_iter() .map(|p| p as Arc) .collect::>() .into_iter(), EntitySelectorType::AllEntities => { let mut entities = Vec::new(); - for world in self.worlds.read().await.iter() { - entities.extend(world.entities.read().await.values().cloned()); + for world in self.worlds.load().iter() { + entities.extend(world.entities.load().iter().cloned()); entities.extend( world .players - .read() - .await - .values() + .load() + .iter() .cloned() .map(|p| p as Arc), ); @@ -847,14 +819,14 @@ impl Server { entities.into_iter() } EntitySelectorType::NamedPlayer(name) => { - if let Some(player) = self.get_player_by_name(name).await { + if let Some(player) = self.get_player_by_name(name) { vec![player as Arc].into_iter() } else { vec![].into_iter() } } EntitySelectorType::Uuid(uuid) => { - if let Some(player) = self.get_player_by_uuid(*uuid).await { + if let Some(player) = self.get_player_by_uuid(*uuid) { vec![player as Arc].into_iter() } else { vec![].into_iter() diff --git a/pumpkin/src/world/border.rs b/pumpkin/src/world/border.rs index 2d2193205..18d2fbf8b 100644 --- a/pumpkin/src/world/border.rs +++ b/pumpkin/src/world/border.rs @@ -22,7 +22,7 @@ pub struct Worldborder { impl Worldborder { #[must_use] - pub fn new( + pub const fn new( x: f64, z: f64, diameter: f64, diff --git a/pumpkin/src/world/bossbar.rs b/pumpkin/src/world/bossbar.rs index 154881f6b..29b94461c 100644 --- a/pumpkin/src/world/bossbar.rs +++ b/pumpkin/src/world/bossbar.rs @@ -3,7 +3,7 @@ use pumpkin_protocol::java::client::play::{BosseventAction, CBossEvent}; use pumpkin_util::text::TextComponent; use uuid::Uuid; -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Eq)] pub enum BossbarColor { Pink, Blue, @@ -14,7 +14,7 @@ pub enum BossbarColor { White, } -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Eq)] pub enum BossbarDivisions { NoDivision, Notches6, diff --git a/pumpkin/src/world/chunker.rs b/pumpkin/src/world/chunker.rs index 7f2f95beb..2bb4830ae 100644 --- a/pumpkin/src/world/chunker.rs +++ b/pumpkin/src/world/chunker.rs @@ -11,10 +11,9 @@ use crate::{ net::ClientPlatform, }; -pub async fn get_view_distance(player: &Player) -> NonZeroU8 { +pub fn get_view_distance(player: &Player) -> NonZeroU8 { let server = player.world().server.upgrade().unwrap(); - - player.config.read().await.view_distance.clamp( + player.config.load().view_distance.clamp( NonZeroU8::new(2).unwrap(), server.basic_config.view_distance, ) @@ -30,7 +29,7 @@ pub async fn update_position(player: &Arc) { // return; // } - let view_distance = get_view_distance(player).await; + let view_distance = get_view_distance(player); let new_cylindrical = Cylindrical::new(new_chunk_center, view_distance); if old_cylindrical == new_cylindrical { @@ -73,12 +72,23 @@ pub async fn update_position(player: &Arc) { new_chunk_center, view_distance.into(), &world.level, + &loading_chunks, + &unloading_chunks, ); world }; player.watched_section.store(new_cylindrical); + if let ClientPlatform::Java(_) = &player.client { + for chunk in &unloading_chunks { + player + .client + .enqueue_packet(&CUnloadChunk::new(chunk.x, chunk.y)) + .await; + } + } + // Make sure the watched section and the chunk watcher updates are async atomic. We want to // ensure what we unload when the player disconnects is correct. world @@ -90,15 +100,6 @@ pub async fn update_position(player: &Arc) { .mark_chunks_as_not_watched(&unloading_chunks) .await; - if let ClientPlatform::Java(_) = &player.client { - for chunk in &unloading_chunks { - player - .client - .enqueue_packet(&CUnloadChunk::new(chunk.x, chunk.y)) - .await; - } - } - if !loading_chunks.is_empty() { world.spawn_world_entity_chunks(player.clone(), loading_chunks, new_chunk_center); } diff --git a/pumpkin/src/world/custom_bossbar.rs b/pumpkin/src/world/custom_bossbar.rs index ce1204ea4..3b3f6269b 100644 --- a/pumpkin/src/world/custom_bossbar.rs +++ b/pumpkin/src/world/custom_bossbar.rs @@ -30,7 +30,7 @@ pub struct CustomBossbar { impl CustomBossbar { #[deny(clippy::new_without_default)] #[must_use] - pub fn new(namespace: String, bossbar_data: Bossbar) -> Self { + pub const fn new(namespace: String, bossbar_data: Bossbar) -> Self { Self { namespace, bossbar_data, @@ -112,7 +112,7 @@ impl CustomBossbars { if let Some(bossbar) = bossbar { self.custom_bossbars.remove(&resource_location); - let players: Vec> = server.get_all_players().await; + let players: Vec> = server.get_all_players(); let online_players = players .iter() @@ -168,7 +168,7 @@ impl CustomBossbars { return Ok(()); } - let players: Vec> = server.get_all_players().await; + let players: Vec> = server.get_all_players(); let matching_players = players .iter() .filter(|player| bossbar.player.contains(&player.gameprofile.id)); @@ -203,7 +203,7 @@ impl CustomBossbars { bossbar.visible = new_visibility; - let players: Vec> = server.get_all_players().await; + let players: Vec> = server.get_all_players(); let online_players = players .iter() .filter(|player| bossbar.player.contains(&player.gameprofile.id)); @@ -241,7 +241,7 @@ impl CustomBossbars { return Ok(()); } - let players: Vec> = server.get_all_players().await; + let players: Vec> = server.get_all_players(); let matching_players = players .iter() .filter(|player| bossbar.player.contains(&player.gameprofile.id)); @@ -279,7 +279,7 @@ impl CustomBossbars { return Ok(()); } - let players: Vec> = server.get_all_players().await; + let players: Vec> = server.get_all_players(); let matching_players = players .iter() .filter(|player| bossbar.player.contains(&player.gameprofile.id)); @@ -318,7 +318,7 @@ impl CustomBossbars { return Ok(()); } - let players: Vec> = server.get_all_players().await; + let players: Vec> = server.get_all_players(); let matching_players = players .iter() .filter(|player| bossbar.player.contains(&player.gameprofile.id)); @@ -367,7 +367,7 @@ impl CustomBossbars { if bossbar.visible { for uuid in removed_players { - let Some(player) = server.get_player_by_uuid(uuid).await else { + let Some(player) = server.get_player_by_uuid(uuid) else { continue; }; @@ -382,7 +382,7 @@ impl CustomBossbars { } for uuid in added_players { - let Some(player) = server.get_player_by_uuid(uuid).await else { + let Some(player) = server.get_player_by_uuid(uuid) else { continue; }; diff --git a/pumpkin/src/world/explosion.rs b/pumpkin/src/world/explosion.rs index 504c0161c..fe295ae29 100644 --- a/pumpkin/src/world/explosion.rs +++ b/pumpkin/src/world/explosion.rs @@ -17,7 +17,7 @@ pub struct Explosion { } impl Explosion { #[must_use] - pub fn new(power: f32, pos: Vector3) -> Self { + pub const fn new(power: f32, pos: Vector3) -> Self { Self { power, pos } } async fn get_blocks_to_destroy( @@ -46,7 +46,7 @@ impl Explosion { let mut pos_y = self.pos.y + 0.0625; let mut pos_z = self.pos.z; - let mut h = self.power * (0.7 + rand::random::() * 0.6); + let mut h = self.power * rand::random::().mul_add(0.6, 0.7); while h > 0.0 { let block_pos = BlockPos::floored(pos_x, pos_y, pos_z); let (block, state) = world.get_block_and_state(&block_pos).await; diff --git a/pumpkin/src/world/loot.rs b/pumpkin/src/world/loot.rs index 5cfc0b8c3..e4a022954 100644 --- a/pumpkin/src/world/loot.rs +++ b/pumpkin/src/world/loot.rs @@ -7,7 +7,7 @@ use pumpkin_util::{ random::{RandomGenerator, RandomImpl, get_seed, xoroshiro128::Xoroshiro}, }; use pumpkin_world::item::ItemStack; -use rand::Rng; +use rand::RngExt; #[derive(Default)] pub struct LootContextParameters { diff --git a/pumpkin/src/world/mod.rs b/pumpkin/src/world/mod.rs index 89b9fb64a..782e8de34 100644 --- a/pumpkin/src/world/mod.rs +++ b/pumpkin/src/world/mod.rs @@ -1,11 +1,7 @@ use std::pin::Pin; -use std::sync::Weak; use std::sync::atomic::Ordering::Relaxed; -use std::time::Duration; -use std::{ - collections::HashMap, - sync::{Arc, atomic::Ordering}, -}; +use std::sync::{Arc, Weak}; +use std::{collections::HashMap, sync::atomic::Ordering}; pub mod chunker; pub mod explosion; @@ -32,6 +28,7 @@ use crate::{ }, server::Server, }; +use arc_swap::ArcSwap; use border::Worldborder; use bytes::BufMut; use crossbeam::queue::SegQueue; @@ -122,7 +119,7 @@ use pumpkin_world::{chunk::ChunkData, world::BlockAccessor}; use pumpkin_world::{level::Level, tick::TickPriority}; use pumpkin_world::{world::BlockFlags, world_info::LevelData}; use rand::seq::SliceRandom; -use rand::{Rng, rng}; +use rand::{RngExt, rng}; use scoreboard::Scoreboard; use time::LevelTime; use tokio::sync::Mutex; @@ -170,12 +167,12 @@ impl PumpkinError for GetBlockError { pub struct World { /// The underlying level, responsible for chunk management and terrain generation. pub level: Arc, - pub level_info: Arc>, + pub level_info: Arc>, /// A map of active players within the world, keyed by their unique UUID. - pub players: Arc>>>, + pub players: ArcSwap>>, /// A map of active entities within the world, keyed by their unique UUID. /// This does not include players. - pub entities: Arc>>>, + pub entities: ArcSwap>>, /// The world's scoreboard, used for tracking scores, objectives, and display information. pub scoreboard: Mutex, /// The world's worldborder, defining the playable area and controlling its expansion or contraction. @@ -204,7 +201,7 @@ impl World { #[must_use] pub fn load( level: Arc, - level_info: Arc>, + level_info: Arc>, dimension: Dimension, block_registry: Arc, server: Weak, @@ -218,8 +215,8 @@ impl World { Self { level, level_info, - players: Arc::new(RwLock::new(HashMap::new())), - entities: Arc::new(RwLock::new(HashMap::new())), + players: ArcSwap::new(Arc::new(Vec::new())), + entities: ArcSwap::new(Arc::new(Vec::new())), scoreboard: Mutex::new(Scoreboard::default()), worldborder: Mutex::new(Worldborder::new(0.0, 0.0, 5.999_996_8E7, 0, 5, 300)), level_time: Mutex::new(LevelTime::new()), @@ -238,8 +235,8 @@ impl World { } pub async fn shutdown(&self) { - for (uuid, entity) in self.entities.read().await.iter() { - self.save_entity(uuid, entity).await; + for entity in self.entities.load().iter() { + self.save_entity(entity).await; } // Save portal POI to disk @@ -251,10 +248,11 @@ impl World { self.level.shutdown().await; } - async fn save_entity(&self, uuid: &uuid::Uuid, entity: &Arc) { + async fn save_entity(&self, entity: &Arc) { // First lets see if the entity was saved on an other chunk, and if the current chunk does not match we remove it // Otherwise we just update the nbt data let base_entity = entity.get_entity(); + let uuid = base_entity.entity_uuid; let current_chunk_coordinate = base_entity.block_pos.load().chunk_position(); let mut nbt = NbtCompound::new(); entity.write_nbt(&mut nbt).await; @@ -264,17 +262,17 @@ impl World { let mut chunk = chunk.write().await; chunk.mark_dirty(true); if old_chunk == current_chunk_coordinate { - chunk.data.insert(*uuid, nbt); + chunk.data.insert(uuid, nbt); return; } // The chunk has changed, lets remove the entity from the old chunk - chunk.data.remove(uuid); + chunk.data.remove(&uuid); } // We did not continue, so lets save data in a new chunk let chunk = self.level.get_entity_chunk(current_chunk_coordinate).await; let mut chunk = chunk.write().await; - chunk.data.insert(*uuid, nbt); + chunk.data.insert(uuid, nbt); chunk.mark_dirty(true); } @@ -317,10 +315,11 @@ impl World { .await; } - pub async fn set_difficulty(&self, difficulty: Difficulty) { - let mut level_info = self.level_info.write().await; - - level_info.difficulty = difficulty; + pub fn set_difficulty(&self, difficulty: Difficulty) { + let current_info = self.level_info.load(); + let mut new_info = (**current_info).clone(); + new_info.difficulty = difficulty; + self.level_info.store(Arc::new(new_info)); } pub async fn add_synced_block_event(&self, pos: BlockPos, r#type: u8, data: u8) { @@ -364,9 +363,7 @@ impl World { /// /// **Note:** This function acquires a lock on the `current_players` map, ensuring thread safety. pub async fn broadcast_packet_all(&self, packet: &P) { - let current_players = self.players.read().await; - - for player in current_players.values() { + for player in self.players.load().iter() { player.client.enqueue_packet(packet).await; } } @@ -391,9 +388,7 @@ impl World { je_packet: &J, be_packet: &B, ) { - let current_players = self.players.read().await; - - for player in current_players.values() { + for player in self.players.load().iter() { match &player.client { ClientPlatform::Java(client) => client.enqueue_packet(je_packet).await, ClientPlatform::Bedrock(client) => client.send_game_packet(be_packet).await, @@ -413,7 +408,7 @@ impl World { cache.last_seen.clone() }; - for recipient in self.players.read().await.values() { + for recipient in self.players.load().iter() { let messages_received: i32 = recipient.chat_session.lock().await.messages_received; let packet = &CPlayerChatMessage::new( VarInt(messages_received), @@ -462,9 +457,12 @@ impl World { except: &[uuid::Uuid], packet: &P, ) { - let current_players = self.players.read().await; - - for (_, player) in current_players.iter().filter(|c| !except.contains(c.0)) { + for player in self + .players + .load() + .iter() + .filter(|c| !except.contains(&c.gameprofile.id)) + { player.client.enqueue_packet(packet).await; } } @@ -477,8 +475,7 @@ impl World { particle_count: i32, particle: Particle, ) { - let players = self.players.read().await; - for player in players.values() { + for player in self.players.load().iter() { player .spawn_particle(position, offset, max_speed, particle_count, particle) .await; @@ -575,34 +572,30 @@ impl World { let start = tokio::time::Instant::now(); // 1. Block & Environment - self.flush_block_updates().await; self.flush_synced_block_events().await; self.tick_environment().await; - // 2. Chunks let chunk_start = tokio::time::Instant::now(); self.tick_chunks().await; let chunk_elapsed = chunk_start.elapsed(); - // 3. Players let player_start = tokio::time::Instant::now(); - let players_to_tick: Vec<_> = self.players.read().await.values().cloned().collect(); - let player_count = players_to_tick.len(); - for player in &players_to_tick { + let players = self.players.load(); + let player_count = players.len(); + for player in players.iter() { player.tick(server).await; } let player_elapsed = player_start.elapsed(); - // 4. Entities & Collision let entity_start = tokio::time::Instant::now(); - let entities_to_tick: Vec<_> = self.entities.read().await.values().cloned().collect(); + let entities_to_tick = self.entities.load(); let entity_count = entities_to_tick.len(); - for entity in entities_to_tick { + for entity in entities_to_tick.iter() { entity.get_entity().age.fetch_add(1, Relaxed); entity.tick(entity.clone(), server).await; - for player in &players_to_tick { + for player in players.iter() { if player .living_entity .entity @@ -618,9 +611,9 @@ impl World { } let entity_elapsed = entity_start.elapsed(); - self.level.chunk_loading.lock().unwrap().send_change(); + self.flush_block_updates().await; + //self.level.chunk_loading.lock().unwrap().send_change(); - // 5. Detailed Slow Tick Logging let total_elapsed = start.elapsed(); if total_elapsed.as_millis() > 50 { log::debug!( @@ -668,7 +661,7 @@ impl World { async fn tick_environment(&self) { let mut level_time = self.level_time.lock().await; let (advance_time, advance_weather) = { - let lock = self.level_info.read().await; + let lock = self.level_info.load(); ( lock.game_rules.advance_time, lock.game_rules.advance_weather, @@ -691,12 +684,12 @@ impl World { let mut weather = self.weather.lock().await; weather.tick_weather(self).await; - if self.should_skip_night().await && level_time.is_night() { + if self.should_skip_night() && level_time.is_night() { let time = level_time.time_of_day + 24000; level_time.set_time(time - time % 24000); level_time.send_time(self).await; - for player in self.players.read().await.values() { + for player in self.players.load().iter() { player.wake_up().await; } @@ -731,8 +724,6 @@ impl World { } } - // TODO: Fix this deadlock - // TODO: ^ find this deadlock ^ for scheduled_tick in tick_data.random_ticks { let block = self.get_block(&scheduled_tick.position).await; if let Some(pumpkin_block) = self.block_registry.get_pumpkin_block(block.id) { @@ -746,12 +737,10 @@ impl World { } } - let spawn_entity_clock_start = tokio::time::Instant::now(); - let mut spawning_chunks_map = HashMap::new(); // TODO use FixedPlayerDistanceChunkTracker - for i in self.players.read().await.values() { + for i in self.players.load().iter() { let center = i.living_entity.entity.chunk_pos.load(); for dx in -8..=8 { for dy in -8..=8 { @@ -771,9 +760,6 @@ impl World { let mut spawning_chunks: Vec<(Vector2, Arc>)> = spawning_chunks_map.into_iter().collect(); - let get_chunks_clock = spawn_entity_clock_start.elapsed(); - // log::debug!("spawning chunks size {}", spawning_chunks.len()); - let mut spawn_state = SpawnState::new(spawning_chunks.len() as i32, &self.entities, self).await; // TODO store it @@ -792,20 +778,10 @@ impl World { spawning_chunks.shuffle(&mut rng()); // TODO i think it can be multithread - for (pos, chunk) in &spawning_chunks { - self.tick_spawning_chunk(pos, chunk, &spawn_list, &mut spawn_state) + for (pos, chunk) in spawning_chunks { + self.tick_spawning_chunk(pos, &chunk, &spawn_list, &mut spawn_state) .await; } - log::trace!( - "Spawning entity took {:?}, getting chunks {:?}, spawning chunks: {}, avg {:?} per chunk", - spawn_entity_clock_start.elapsed(), - get_chunks_clock, - spawning_chunks.len(), - spawn_entity_clock_start - .elapsed() - .checked_div(spawning_chunks.len() as u32) - .unwrap_or(Duration::new(0, 0)) - ); for block_entity in tick_data.block_entities { let world: Arc = self.clone(); @@ -1103,7 +1079,7 @@ impl World { pub async fn tick_spawning_chunk( self: &Arc, - chunk_pos: &Vector2, + chunk_pos: Vector2, chunk: &Arc>, spawn_list: &Vec<&'static MobCategory>, spawn_state: &mut SpawnState, @@ -1152,6 +1128,7 @@ impl World { self.spawn_entity(Arc::new(entity)).await; } } + drop(weather); if spawn_list.is_empty() { return; @@ -1191,7 +1168,7 @@ impl World { player: Arc, server: &Server, ) { - let level_info = server.level_info.read().await; + let level_info = server.level_info.load(); let weather = self.weather.lock().await; let runtime_id = player.entity_id() as u64; let (position, yaw, pitch) = if player.has_played_before.load(Ordering::Relaxed) { @@ -1201,16 +1178,15 @@ impl World { (position, yaw, pitch) } else { - let info = &self.level_info.read().await; - let spawn_position = Vector2::new(info.spawn_x, info.spawn_z); + let spawn_position = Vector2::new(level_info.spawn_x, level_info.spawn_z); let pos_y = self.get_top_block(spawn_position).await + 1; // +1 to spawn on top of the block let position = Vector3::new( - f64::from(info.spawn_x) + 0.5, + f64::from(level_info.spawn_x) + 0.5, f64::from(pos_y), - f64::from(info.spawn_z) + 0.5, + f64::from(level_info.spawn_z) + 0.5, ); - (position, info.spawn_yaw, info.spawn_pitch) + (position, level_info.spawn_yaw, level_info.spawn_pitch) }; // Todo make the data less spread let level_settings = LevelSettings { @@ -1521,7 +1497,7 @@ impl World { (position, yaw, pitch) } else { - let info = &self.level_info.read().await; + let info = &self.level_info.load(); let spawn_position = Vector2::new(info.spawn_x, info.spawn_z); let pos_y = self.get_top_block(spawn_position).await + 1; // +1 to spawn on top of the block @@ -1562,14 +1538,13 @@ impl World { }], )) .await; - let current_players = self.players.read().await; // Here, we send all the infos of players who already joined. { let mut current_player_data = Vec::new(); - - for (_, player) in current_players + let players = self.players.load(); + for player in players .iter() - .filter(|(c, _)| **c != player.gameprofile.id) + .filter(|p| p.gameprofile.id != player.gameprofile.id) { let chat_session = player.chat_session.lock().await; @@ -1635,7 +1610,12 @@ impl World { // Spawn players for our client. let id = player.gameprofile.id; - for (_, existing_player) in current_players.iter().filter(|c| c.0 != &id) { + for existing_player in self + .players + .load() + .iter() + .filter(|c| c.gameprofile.id != id) + { let entity = &existing_player.living_entity.entity; let pos = entity.pos.load(); let gameprofile = &existing_player.gameprofile; @@ -1655,7 +1635,7 @@ impl World { )) .await; { - let config = existing_player.config.read().await; + let config = existing_player.config.load(); let mut buf = Vec::new(); { let meta = Metadata::new( @@ -1731,7 +1711,7 @@ impl World { player.send_time(self).await; let (spawn_block_pos, yaw, pitch) = { - let level_info_lock = self.level_info.read().await; + let level_info_lock = self.level_info.load(); ( BlockPos::new( level_info_lock.spawn_x, @@ -1868,7 +1848,7 @@ impl World { Particle::ExplosionEmitter }; let sound = IdOr::::Id(Sound::EntityGenericExplode as u16); - for player in self.players.read().await.values() { + for player in self.players.load().iter() { if player.position().squared_distance_to_vec(&position) > 4096.0 { continue; } @@ -1900,7 +1880,7 @@ impl World { // Copy spawn info from level_info to avoid holding lock across await let (spawn_x, spawn_z, spawn_yaw, spawn_pitch, keep_inventory) = { - let info = self.level_info.read().await; + let info = self.level_info.load(); ( info.spawn_x, info.spawn_z, @@ -1948,16 +1928,19 @@ impl World { None } else { // Cross-dimension respawn: get target world from server - if let Some(server) = self.server.upgrade() { - let worlds = server.worlds.read().await; - worlds - .iter() - .find(|w| w.dimension == respawn_dimension) - .cloned() - } else { - log::warn!("Could not get server for cross-dimension respawn"); - None - } + self.server.upgrade().map_or_else( + || { + log::warn!("Could not get server for cross-dimension respawn"); + None + }, + |server| { + let worlds = server.worlds.load(); + worlds + .iter() + .find(|w| w.dimension == respawn_dimension) + .cloned() + }, + ) }; // Handle cross-dimension transfer if we found a different target world @@ -1969,11 +1952,12 @@ impl World { ); // Remove player from current world - let uuid = player.gameprofile.id; - if let Some(p) = self.remove_player(player, false).await { - // Add player to target world - new_world.players.write().await.insert(uuid, p); - } + self.remove_player(player, false).await; + new_world.players.rcu(|current_list| { + let mut new_list = (**current_list).clone(); + new_list.push(player.clone()); + new_list + }); // Update chunk manager to target world player @@ -2053,12 +2037,12 @@ impl World { } /// Returns true if enough players are sleeping and we should skip the night. - pub async fn should_skip_night(&self) -> bool { - let players = self.players.read().await; + pub fn should_skip_night(&self) -> bool { + let players = self.players.load(); let player_count = players.len(); let sleeping_player_count = players - .values() + .iter() .filter(|player| { player .sleeping_since @@ -2121,9 +2105,7 @@ impl World { "Received chunk {:?}, but it is no longer watched... cleaning", &position ); - let mut ids = Vec::new(); - // Remove all the entities from the world - let mut entities = world.entities.write().await; + let mut ids_to_remove = Vec::new(); for (uuid, entity_nbt) in &chunk.read().await.data { let Some(id) = entity_nbt.get_string("id") else { @@ -2143,8 +2125,7 @@ impl World { entity.read_nbt_non_mut(entity_nbt).await; let base_entity = entity.get_entity(); - entities.remove(&base_entity.entity_uuid); - ids.push(VarInt(base_entity.entity_id)); + ids_to_remove.push(VarInt(base_entity.entity_id)); let mut nbt = NbtCompound::new(); entity.write_nbt(&mut nbt).await; @@ -2170,20 +2151,27 @@ impl World { chunk.mark_dirty(true); } - if !ids.is_empty() { + if !ids_to_remove.is_empty() { + world.entities.rcu(|current_entities| { + let mut new_entities = (**current_entities).clone(); + new_entities.retain(|e| { + !ids_to_remove.contains(&VarInt(e.get_entity().entity_id)) + }); + new_entities + }); player .client - .enqueue_packet(&CRemoveEntities::new(&ids)) + .enqueue_packet(&CRemoveEntities::new(&ids_to_remove)) .await; } - level.clean_entity_chunk(&position).await; + level.clean_entity_chunk(&position); continue 'main; }; let entity_chunk = chunk.read().await; // Add all new Entities to the world - let mut current_entities = world.entities.write().await; + let mut entities_to_add: Vec> = Vec::new(); for (uuid, entity_nbt) in &entity_chunk.data { let Some(id) = entity_nbt.get_string("id") else { @@ -2206,7 +2194,15 @@ impl World { .enqueue_packet(&base_entity.create_spawn_packet()) .await; entity.init_data_tracker().await; - current_entities.insert(base_entity.entity_uuid, entity); + + entities_to_add.push(entity); + } + if !entities_to_add.is_empty() { + world.entities.rcu(|current_entities| { + let mut new_entities = (**current_entities).clone(); + new_entities.extend(entities_to_add.iter().cloned()); + new_entities + }); } } @@ -2216,8 +2212,8 @@ impl World { } /// Gets a `Player` by an entity id - pub async fn get_player_by_id(&self, id: i32) -> Option> { - for player in self.players.read().await.values() { + pub fn get_player_by_id(&self, id: i32) -> Option> { + for player in self.players.load().iter() { if player.entity_id() == id { return Some(player.clone()); } @@ -2226,13 +2222,13 @@ impl World { } /// Gets an entity by an entity id - pub async fn get_entity_by_id(&self, id: i32) -> Option> { - for entity in self.entities.read().await.values() { + pub fn get_entity_by_id(&self, id: i32) -> Option> { + for entity in self.entities.load().iter() { if entity.get_entity().entity_id == id { return Some(entity.clone()); } } - for player in self.players.read().await.values() { + for player in self.players.load().iter() { if player.get_entity().entity_id == id { return Some(player.clone() as Arc); } @@ -2241,8 +2237,8 @@ impl World { } /// Gets a `Player` by a username - pub async fn get_player_by_name(&self, name: &str) -> Option> { - for player in self.players.read().await.values() { + pub fn get_player_by_name(&self, name: &str) -> Option> { + for player in self.players.load().iter() { if player.gameprofile.name.eq_ignore_ascii_case(name) { return Some(player.clone()); } @@ -2250,18 +2246,18 @@ impl World { None } - pub async fn get_entities_at_box(&self, aabb: &BoundingBox) -> Vec> { - let entities_guard = self.entities.read().await; - entities_guard - .values() + pub fn get_entities_at_box(&self, aabb: &BoundingBox) -> Vec> { + self.entities + .load() + .iter() .filter(|entity| entity.get_entity().bounding_box.load().intersects(aabb)) .cloned() .collect() } - pub async fn get_players_at_box(&self, aabb: &BoundingBox) -> Vec> { - let players_guard = self.players.read().await; + pub fn get_players_at_box(&self, aabb: &BoundingBox) -> Vec> { + let players_guard = self.players.load(); players_guard - .values() + .iter() .filter(|player| player.get_entity().bounding_box.load().intersects(aabb)) .cloned() .collect() @@ -2279,8 +2275,12 @@ impl World { /// # Returns /// /// An `Option>` containing the player if found, or `None` if not. - pub async fn get_player_by_uuid(&self, id: uuid::Uuid) -> Option> { - self.players.read().await.get(&id).cloned() + pub fn get_player_by_uuid(&self, id: uuid::Uuid) -> Option> { + self.players + .load() + .iter() + .find(|p| p.gameprofile.id == id) + .cloned() } /// Gets a list of players whose location equals the given position in the world. @@ -2292,19 +2292,18 @@ impl World { /// # Arguments /// /// * `position`: The position the function will check. - pub async fn get_players_by_pos(&self, position: BlockPos) -> HashMap> { + pub fn get_players_by_pos(&self, position: BlockPos) -> Vec> { self.players - .read() - .await + .load() .iter() - .filter_map(|(uuid, player)| { + .filter_map(|player| { let player_block_pos = player.living_entity.entity.block_pos.load().0; (position.0.x == player_block_pos.x && position.0.y == player_block_pos.y && position.0.z == player_block_pos.z) - .then(|| (*uuid, Arc::clone(player))) + .then(|| Arc::clone(player)) }) - .collect::>>() + .collect::<_>() } /// Gets the nearby players around a given world position. @@ -2315,26 +2314,20 @@ impl World { /// # Arguments /// * `pos`: The center of the sphere. /// * `radius`: The radius of the sphere. The higher the radius, the more area will be checked (in every direction). - pub async fn get_nearby_players( - &self, - pos: Vector3, - radius: f64, - ) -> HashMap> { + pub fn get_nearby_players(&self, pos: Vector3, radius: f64) -> Vec> { let radius_squared = radius.powi(2); self.players - .read() - .await + .load() .iter() - .filter_map(|(id, player)| { + .filter_map(|player| { let player_pos = player.living_entity.entity.pos.load(); - (player_pos.squared_distance_to_vec(&pos) <= radius_squared) - .then(|| (*id, player.clone())) + (player_pos.squared_distance_to_vec(&pos) <= radius_squared).then(|| player.clone()) }) .collect() } - pub async fn get_nearby_entities( + pub fn get_nearby_entities( &self, pos: Vector3, radius: f64, @@ -2342,29 +2335,28 @@ impl World { let radius_squared = radius.powi(2); self.entities - .read() - .await + .load() .iter() - .filter_map(|(id, entity)| { + .filter_map(|entity| { let entity_pos = entity.get_entity().pos.load(); (entity_pos.squared_distance_to_vec(&pos) <= radius_squared) - .then(|| (*id, entity.clone())) + .then(|| (entity.get_entity().entity_uuid, entity.clone())) }) .collect() } - pub async fn get_closest_player(&self, pos: Vector3, radius: f64) -> Option> { - let players = self.get_nearby_players(pos, radius).await; + pub fn get_closest_player(&self, pos: Vector3, radius: f64) -> Option> { + let players = self.get_nearby_players(pos, radius); players .iter() .min_by(|a, b| { - a.1.living_entity + a.living_entity .entity .pos .load() .squared_distance_to_vec(&pos) .partial_cmp( - &b.1.living_entity + &b.living_entity .entity .pos .load() @@ -2372,7 +2364,7 @@ impl World { ) .unwrap() }) - .map(|p| p.1.clone()) + .cloned() } /// Gets the closest entity to a position, with optional filtering by entity type. @@ -2386,14 +2378,14 @@ impl World { /// # Returns /// /// The closest entity that matches the filter criteria, or None if no entities are found. - pub async fn get_closest_entity( + pub fn get_closest_entity( &self, pos: Vector3, radius: f64, entity_types: Option<&[&'static EntityType]>, ) -> Option> { // Get regular entities - let entities = self.get_nearby_entities(pos, radius).await; + let entities = self.get_nearby_entities(pos, radius); // Filter by entity type if specified let filtered_entities = if let Some(types) = entity_types { @@ -2432,11 +2424,15 @@ impl World { /// /// * `uuid`: The unique UUID of the player to add. /// * `player`: An `Arc` reference to the player object. - pub async fn add_player(&self, uuid: uuid::Uuid, player: Arc) -> Result<(), String> { - self.players.write().await.insert(uuid, player.clone()); + pub fn add_player(&self, player: Arc) -> Result<(), String> { + self.players.rcu(|current_list| { + let mut new_list = (**current_list).clone(); + new_list.push(player.clone()); + new_list + }); let server = self.server.upgrade().unwrap(); - let current_players = self.players.clone(); + let current_players = self.players.load(); player.clone().spawn_task(async move { let msg_comp = TextComponent::translate( "multiplayer.player.joined", @@ -2448,7 +2444,7 @@ impl World { let event = server.plugin_manager.fire(event).await; if !event.cancelled { - for player in current_players.read().await.values() { + for player in current_players.iter() { player.send_system_message(&event.join_message).await; } log::info!("{}", event.join_message.to_pretty_console()); @@ -2481,7 +2477,19 @@ impl World { player: &Arc, fire_event: bool, ) -> Option> { - let removed_player = self.players.write().await.remove(&player.gameprofile.id); + let mut removed_player: Option> = None; + + self.players.rcu(|current_list| { + let mut new_list = (**current_list).clone(); + // Find the player before we filter them out + if let Some(pos) = new_list + .iter() + .position(|p| p.gameprofile.id == player.gameprofile.id) + { + removed_player = Some(new_list.remove(pos)); + } + new_list + }); if let Some(ref player) = removed_player { let uuid = player.gameprofile.id; self.broadcast_packet_all(&CRemovePlayerInfo::new(&[uuid])) @@ -2506,11 +2514,9 @@ impl World { .await; if !event.cancelled { - let players = self.players.read().await; - for player in players.values() { + for player in self.players.load().iter() { player.send_system_message(&event.leave_message).await; } - drop(players); log::info!("{}", event.leave_message.to_pretty_console()); } } @@ -2518,7 +2524,6 @@ impl World { removed_player } - /// Adds an entity to the world. pub async fn spawn_entity(&self, entity: Arc) { let base_entity = entity.get_entity(); self.broadcast_packet_all(&base_entity.create_spawn_packet()) @@ -2535,12 +2540,20 @@ impl World { chunk.mark_dirty(true); }; - let mut current_entities = self.entities.write().await; - current_entities.insert(base_entity.entity_uuid, entity); + self.entities.rcu(|current_entities| { + let mut new_entities = (**current_entities).clone(); + new_entities.push(entity.clone()); + new_entities + }); } pub async fn remove_entity(&self, entity: &Entity) { - self.entities.write().await.remove(&entity.entity_uuid); + self.entities.rcu(|current_entities| { + let mut new_entities = (**current_entities).clone(); + new_entities.retain(|e| e.get_entity().entity_uuid != entity.entity_uuid); + new_entities + }); + self.broadcast_packet_all(&CRemoveEntities::new(&[entity.entity_id.into()])) .await; @@ -3017,9 +3030,9 @@ impl World { let mut rng = Xoroshiro::from_seed(get_seed()); // TODO: Use world random here: world.random.nextDouble() - let x = x.floor() + rng.next_f64() * spawn_area + half_width; - let y = y.floor() + rng.next_f64() * spawn_area; - let z = z.floor() + rng.next_f64() * spawn_area + half_width; + let x = rng.next_f64().mul_add(spawn_area, x.floor()) + half_width; + let y = rng.next_f64().mul_add(spawn_area, y.floor()); + let z = rng.next_f64().mul_add(spawn_area, z.floor()) + half_width; while !stack.is_empty() { let item = stack.split((rng.next_bounded_i32(21) + 10) as u8); diff --git a/pumpkin/src/world/natural_spawner.rs b/pumpkin/src/world/natural_spawner.rs index ab1d7c76f..1190fcac0 100644 --- a/pumpkin/src/world/natural_spawner.rs +++ b/pumpkin/src/world/natural_spawner.rs @@ -1,6 +1,7 @@ use crate::entity::EntityBase; use crate::entity::r#type::from_type; use crate::world::World; +use arc_swap::ArcSwap; use pumpkin_data::biome::Spawner; use pumpkin_data::entity::{EntityType, MobCategory, SpawnLocation}; use pumpkin_data::tag::Block::MINECRAFT_PREVENT_MOB_SPAWNING_INSIDE; @@ -20,7 +21,7 @@ use pumpkin_util::random::{RandomImpl, get_seed}; use pumpkin_world::chunk::io::Dirtiable; use pumpkin_world::chunk::{ChunkData, ChunkHeightmapType}; use rand::seq::IndexedRandom; -use rand::{Rng, rng}; +use rand::{RngExt, rng}; use std::collections::HashMap; use std::collections::hash_map::Entry; use std::fmt; @@ -67,20 +68,20 @@ impl LocalMobCapCalculator { dx * dx + dy * dy } - async fn get_players_near<'b>( + fn get_players_near<'b>( players_near_chunk: &'b mut HashMap, Vec>, world: &Arc, - chunk_pos: &Vector2, + chunk_pos: Vector2, ) -> &'b Vec { - match players_near_chunk.entry(*chunk_pos) { + match players_near_chunk.entry(chunk_pos) { Entry::Occupied(value) => value.into_mut(), Entry::Vacant(entry) => { let mut players = Vec::new(); - for (_uuid, player) in world.players.read().await.iter() { + for player in world.players.load().iter() { if player.gamemode.load() == GameMode::Spectator { continue; } - if Self::calc_distance(*chunk_pos, &player.position()) < 16384. { + if Self::calc_distance(chunk_pos, &player.position()) < 16384. { players.push(player.entity_id()); } } @@ -88,13 +89,13 @@ impl LocalMobCapCalculator { } } } - pub async fn add_mob( + pub fn add_mob( &mut self, - chunk_pos: &Vector2, + chunk_pos: Vector2, world: &Arc, category: &'static MobCategory, ) { - let players = Self::get_players_near(&mut self.players_near_chunk, world, chunk_pos).await; + let players = Self::get_players_near(&mut self.players_near_chunk, world, chunk_pos); for player in players { self.player_mob_counts .entry(*player) @@ -106,13 +107,13 @@ impl LocalMobCapCalculator { // debug!("chunk_pos {:?}", chunk_pos); // debug!("players {:?}", players); } - pub async fn can_spawn( + pub fn can_spawn( &mut self, category: &'static MobCategory, world: &Arc, - chunk_pos: &Vector2, + chunk_pos: Vector2, ) -> bool { - let players = Self::get_players_near(&mut self.players_near_chunk, world, chunk_pos).await; + let players = Self::get_players_near(&mut self.players_near_chunk, world, chunk_pos); for player in players { if let Some(count) = self.player_mob_counts.get(player) { if count.can_spawn(category) { @@ -185,13 +186,13 @@ impl fmt::Debug for SpawnState { impl SpawnState { pub async fn new( chunk_count: i32, - entities: &Arc>>>, + entities: &ArcSwap>>, world: &Arc, ) -> Self { let mut potential = PotentialCalculator::default(); let mut local_mob_cap = LocalMobCapCalculator::default(); let mut counter = MobCounts::default(); - for entity in entities.read().await.values() { + for entity in entities.load().iter() { let entity = entity.get_entity(); let entity_type = entity.entity_type; if !entity_type.mob || entity_type.category == &MobCategory::MISC { @@ -204,9 +205,7 @@ impl SpawnState { potential.add_charge(&entity_pos, cost.charge); } if entity_type.mob { - local_mob_cap - .add_mob(&entity.chunk_pos.load(), world, entity_type.category) - .await; + local_mob_cap.add_mob(entity.chunk_pos.load(), world, entity_type.category); } counter.add(entity_type.category); } @@ -222,19 +221,18 @@ impl SpawnState { } } #[inline] - fn can_spawn_for_category_global(&self, category: &'static MobCategory) -> bool { + const fn can_spawn_for_category_global(&self, category: &'static MobCategory) -> bool { self.mob_category_counts.0[category.id] < category.max * self.spawnable_chunk_count / MAGIC_NUMBER } - async fn can_spawn_for_category_local( + fn can_spawn_for_category_local( &mut self, world: &Arc, category: &'static MobCategory, - chunk_pos: &Vector2, + chunk_pos: Vector2, ) -> bool { self.local_mob_cap_calculator .can_spawn(category, world, chunk_pos) - .await } async fn can_spawn( &mut self, @@ -277,13 +275,11 @@ impl SpawnState { self.spawn_potential.add_charge(pos, charge); self.mob_category_counts.add(entity_type.category); - self.local_mob_cap_calculator - .add_mob( - &Vector2::::new(get_section_cord(pos.0.x), get_section_cord(pos.0.z)), - world, - entity_type.category, - ) - .await; + self.local_mob_cap_calculator.add_mob( + Vector2::::new(get_section_cord(pos.0.x), get_section_cord(pos.0.z)), + world, + entity_type.category, + ); } } @@ -319,20 +315,17 @@ pub fn get_filtered_spawning_categories( pub async fn spawn_for_chunk( world: &Arc, - chunk_pos: &Vector2, + chunk_pos: Vector2, chunk: &Arc>, spawn_state: &mut SpawnState, spawn_list: &Vec<&'static MobCategory>, ) { // debug!("spawn for chunk {:?}", chunk_pos); for category in spawn_list { - if spawn_state - .can_spawn_for_category_local(world, category, chunk_pos) - .await - { - let random_pos = get_random_pos_within(world.min_y, chunk_pos, chunk).await; + if spawn_state.can_spawn_for_category_local(world, category, chunk_pos) { + let random_pos = get_random_pos_within(world.min_y, &chunk_pos, chunk).await; if random_pos.0.y > world.min_y { - spawn_category_for_position(category, world, random_pos, chunk_pos, spawn_state) + spawn_category_for_position(category, world, random_pos, &chunk_pos, spawn_state) .await; } } @@ -369,13 +362,7 @@ pub async fn spawn_category_for_position( let mut batch_buffer = vec![]; let mut spawn_cluster_size = 0; let mut new_pos = pos; - let player_positions: Vec<_> = world - .players - .read() - .await - .values() - .map(|p| p.position()) - .collect(); + let player_positions: Vec<_> = world.players.load().iter().map(|p| p.position()).collect(); for _ in 0..3 { let mut new_x = new_pos.0.x; let mut new_z = new_pos.0.z; @@ -444,26 +431,35 @@ pub async fn spawn_category_for_position( let packet = base_entity.create_spawn_packet(); let mut nbt = NbtCompound::new(); entity.write_nbt(&mut nbt).await; - prepared_data.push((base_entity.entity_uuid, nbt, packet)); + // Keep the entity reference here so we don't have to "find" it later + prepared_data.push((base_entity.entity_uuid, nbt, packet, entity.clone())); } + { let chunk_handle = world.level.get_entity_chunk(*chunk_pos).await; let mut chunk_lock = chunk_handle.write().await; - let mut entities_lock = world.entities.write().await; - for (uuid, nbt, _) in &prepared_data { - let entity_ref = batch_buffer - .iter() - .find(|e| e.get_entity().entity_uuid == *uuid) - .unwrap(); - - entities_lock.insert(*uuid, entity_ref.clone()); + for (uuid, nbt, _, _) in &prepared_data { chunk_lock.data.insert(*uuid, nbt.clone()); } chunk_lock.mark_dirty(true); + + world.entities.rcu(|current_entities| { + let mut new_entities = (**current_entities).clone(); + + for (uuid, _, _, entity_ref) in &prepared_data { + if !new_entities + .iter() + .any(|e| e.get_entity().entity_uuid == *uuid) + { + new_entities.push(entity_ref.clone()); + } + } + new_entities + }); }; - for (_, _, packet) in prepared_data { + for (_, _, packet, _) in prepared_data { world.broadcast_packet_all(&packet).await; } } diff --git a/pumpkin/src/world/portal/mod.rs b/pumpkin/src/world/portal/mod.rs index dd87bfab7..69f19ae8d 100644 --- a/pumpkin/src/world/portal/mod.rs +++ b/pumpkin/src/world/portal/mod.rs @@ -41,7 +41,7 @@ pub struct PortalManager { } impl PortalManager { - pub fn new(portal_delay: u32, portal_world: Arc, pos: BlockPos) -> Self { + pub const fn new(portal_delay: u32, portal_world: Arc, pos: BlockPos) -> Self { Self { portal_delay, portal_world, @@ -52,11 +52,11 @@ impl PortalManager { } } - pub fn set_source_portal(&mut self, info: SourcePortalInfo) { + pub const fn set_source_portal(&mut self, info: SourcePortalInfo) { self.source_portal = Some(info); } - pub fn tick(&mut self) -> bool { + pub const fn tick(&mut self) -> bool { if self.in_portal { self.in_portal = false; self.ticks_in_portal += 1; diff --git a/pumpkin/src/world/portal/nether.rs b/pumpkin/src/world/portal/nether.rs index de3bf6365..e59bd97e7 100644 --- a/pumpkin/src/world/portal/nether.rs +++ b/pumpkin/src/world/portal/nether.rs @@ -115,7 +115,9 @@ impl PortalSearchResult { let lower = self.lower_corner.0; let axis_offset = if portal_width > 0.0 { - relative_pos.x * portal_width + f64::from(dimensions.width) / 2.0 + relative_pos + .x + .mul_add(portal_width, f64::from(dimensions.width) / 2.0) } else { f64::from(self.width) / 2.0 }; @@ -228,7 +230,7 @@ impl NetherPortal { const FRAME_BLOCK: Block = Block::OBSIDIAN; #[must_use] - pub fn is_valid(&self) -> bool { + pub const fn is_valid(&self) -> bool { self.width >= Self::MIN_WIDTH && self.width <= Self::MAX_WIDTH && self.height >= Self::MIN_HEIGHT @@ -236,27 +238,27 @@ impl NetherPortal { } #[must_use] - pub fn was_already_valid(&self) -> bool { + pub const fn was_already_valid(&self) -> bool { self.is_valid() && self.found_portal_blocks == self.width * self.height } #[must_use] - pub fn lower_corner(&self) -> BlockPos { + pub const fn lower_corner(&self) -> BlockPos { self.lower_conor } #[must_use] - pub fn axis(&self) -> HorizontalAxis { + pub const fn axis(&self) -> HorizontalAxis { self.axis } #[must_use] - pub fn width(&self) -> u32 { + pub const fn width(&self) -> u32 { self.width } #[must_use] - pub fn height(&self) -> u32 { + pub const fn height(&self) -> u32 { self.height } @@ -264,13 +266,12 @@ impl NetherPortal { let mut props = NetherPortalLikeProperties::default(&Block::NETHER_PORTAL); props.axis = self.axis; let state = props.to_state_id(&Block::NETHER_PORTAL); - let blocks: Vec = BlockPos::iterate( + let blocks = BlockPos::iterate( self.lower_conor, self.lower_conor .offset_dir(BlockDirection::Up.to_offset(), self.height as i32 - 1) .offset_dir(self.negative_direction.to_offset(), self.width as i32 - 1), - ) - .collect(); + ); let mut poi_storage = world.portal_poi.lock().await; for pos in blocks { @@ -667,7 +668,7 @@ impl NetherPortal { )) } - fn is_valid_portal_air(state: &BlockState) -> bool { + const fn is_valid_portal_air(state: &BlockState) -> bool { state.replaceable() && !state.is_liquid() } diff --git a/pumpkin/src/world/time.rs b/pumpkin/src/world/time.rs index 5ed16d424..d3afa5d38 100644 --- a/pumpkin/src/world/time.rs +++ b/pumpkin/src/world/time.rs @@ -16,7 +16,7 @@ impl Default for LevelTime { impl LevelTime { #[must_use] - pub fn new() -> Self { + pub const fn new() -> Self { Self { world_age: 0, time_of_day: 0, @@ -24,7 +24,7 @@ impl LevelTime { } } - pub fn tick_time(&mut self, advance_time: bool, advance_weather: bool) { + pub const fn tick_time(&mut self, advance_time: bool, advance_weather: bool) { self.world_age += 1; if advance_weather { self.rain_time += 1; @@ -43,11 +43,11 @@ impl LevelTime { .await; } - pub fn add_time(&mut self, time: i64) { + pub const fn add_time(&mut self, time: i64) { self.time_of_day += time; } - pub fn set_time(&mut self, time: i64) { + pub const fn set_time(&mut self, time: i64) { self.time_of_day = time; } @@ -67,7 +67,7 @@ impl LevelTime { } #[must_use] - pub fn is_night(&self) -> bool { + pub const fn is_night(&self) -> bool { (self.time_of_day % 24000) >= 12000 && (self.time_of_day % 24000) <= 23999 } } diff --git a/pumpkin/src/world/weather.rs b/pumpkin/src/world/weather.rs index 0e450df22..f68c2a0d3 100644 --- a/pumpkin/src/world/weather.rs +++ b/pumpkin/src/world/weather.rs @@ -1,6 +1,6 @@ use super::World; use pumpkin_protocol::java::client::play::{CGameEvent, GameEvent}; -use rand::Rng; +use rand::RngExt; // Weather timing constants const RAIN_DELAY_MIN: i32 = 12_000; @@ -37,7 +37,7 @@ impl Default for Weather { impl Weather { #[must_use] - pub fn new() -> Self { + pub const fn new() -> Self { Self { clear_weather_time: 0, raining: false,