diff --git a/Cargo.lock b/Cargo.lock index fcd91de42..8755d5a6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -37,12 +37,30 @@ dependencies = [ "memchr", ] +[[package]] +name = "aligned-vec" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] + [[package]] name = "android_log-sys" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84521a3cf562bc62942e294181d9eef17eb38ceb8c68677bc49f144e4c3d4f8d" +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anes" version = "0.1.6" @@ -105,6 +123,23 @@ version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "arrayvec" version = "0.7.6" @@ -207,6 +242,29 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "av1-grain" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47c8fbc0f831f4519fe8b810b6a7a91410ec83031b8233f730a0480029f6a23f" +dependencies = [ + "arrayvec", +] + [[package]] name = "azalea" version = "0.14.0+mc1.21.10" @@ -234,12 +292,14 @@ dependencies = [ "futures", "futures-lite", "indexmap", + "mcdata", "nohash-hasher", "num-format", "num-traits", "parking_lot", "rand 0.9.2", "rustc-hash", + "rustmatica", "serde", "thiserror 2.0.17", "tokio", @@ -701,7 +761,7 @@ dependencies = [ "proc-macro2", "quote", "syn", - "toml_edit", + "toml_edit 0.23.7", ] [[package]] @@ -816,6 +876,12 @@ dependencies = [ "thread_local", ] +[[package]] +name = "bit_field" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" + [[package]] name = "bitflags" version = "2.9.4" @@ -825,6 +891,12 @@ dependencies = [ "serde", ] +[[package]] +name = "bitstream-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" + [[package]] name = "block-buffer" version = "0.10.4" @@ -843,6 +915,21 @@ dependencies = [ "hybrid-array", ] +[[package]] +name = "bounded-integer" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "102dbef1187b1893e6dfe05a774e79fd52265f49f214f6879c8ff49f52c8188b" +dependencies = [ + "serde", +] + +[[package]] +name = "built" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" + [[package]] name = "bumpalo" version = "3.19.0" @@ -875,6 +962,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + [[package]] name = "bytes" version = "1.10.1" @@ -903,9 +996,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" dependencies = [ "find-msvc-tools", + "jobserver", + "libc", "shlex", ] +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cfb8" version = "0.8.1" @@ -915,6 +1016,16 @@ dependencies = [ "cipher", ] +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + [[package]] name = "cfg-if" version = "1.0.3" @@ -933,8 +1044,12 @@ version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ + "iana-time-zone", + "js-sys", "num-traits", "serde", + "wasm-bindgen", + "windows-link", ] [[package]] @@ -999,6 +1114,12 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + [[package]] name = "colorchoice" version = "1.0.4" @@ -1046,6 +1167,12 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dabb6555f92fb9ee4140454eb5dcd14c7960e1225c6d1a6cc361f032947713e" +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -1084,7 +1211,7 @@ dependencies = [ "ciborium", "clap", "criterion-plot", - "itertools", + "itertools 0.13.0", "num-traits", "oorandom", "plotters", @@ -1103,7 +1230,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b1bcc0dc7dfae599d84ad0b1a55f80cde8af3725da8313b528da95ef783e338" dependencies = [ "cast", - "itertools", + "itertools 0.13.0", ] [[package]] @@ -1308,6 +1435,9 @@ name = "either" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +dependencies = [ + "serde", +] [[package]] name = "enum-as-inner" @@ -1344,6 +1474,26 @@ dependencies = [ "log", ] +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -1382,12 +1532,68 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "exr" +version = "1.73.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" +dependencies = [ + "bit_field", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[package]] +name = "fastnbt" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29e3bb1f9ba8b6dbb35d89b415216041c2cad0c3e0b329db85ef5d4fc9e80cd6" +dependencies = [ + "byteorder", + "cesu8", + "serde", + "serde_bytes", +] + [[package]] name = "fastrand" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "fax" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab" +dependencies = [ + "fax_derive", +] + +[[package]] +name = "fax_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + [[package]] name = "find-msvc-tools" version = "0.1.4" @@ -1577,6 +1783,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gif" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b" +dependencies = [ + "color_quant", + "weezl", +] + [[package]] name = "gimli" version = "0.32.3" @@ -1796,6 +2012,30 @@ dependencies = [ "tracing", ] +[[package]] +name = "iana-time-zone" +version = "0.1.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "icu_collections" version = "2.0.0" @@ -1903,6 +2143,46 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "image" +version = "0.25.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "529feb3e6769d234375c4cf1ee2ce713682b8e76538cb13f9fc23e1400a591e7" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "exr", + "gif", + "image-webp", + "moxcms", + "num-traits", + "png", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3" +dependencies = [ + "byteorder-lite", + "quick-error", +] + +[[package]] +name = "imgref" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8" + [[package]] name = "indexmap" version = "2.11.4" @@ -1922,6 +2202,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "io-uring" version = "0.7.10" @@ -1967,6 +2258,15 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.13.0" @@ -2006,6 +2306,16 @@ dependencies = [ "syn", ] +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + [[package]] name = "js-sys" version = "0.3.81" @@ -2022,12 +2332,28 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "lebe" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" + [[package]] name = "libc" version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +[[package]] +name = "libfuzzer-sys" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404" +dependencies = [ + "arbitrary", + "cc", +] + [[package]] name = "libm" version = "0.2.15" @@ -2064,6 +2390,15 @@ version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + [[package]] name = "lru-slab" version = "0.1.2" @@ -2079,6 +2414,29 @@ dependencies = [ "regex-automata", ] +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + +[[package]] +name = "mcdata" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7d9308b6ccaae33eb8acf71b02edc136421f0d75ba1adbfc78003b6151fd82d" +dependencies = [ + "bounded-integer", + "either", + "fastnbt", + "serde", + "strum", +] + [[package]] name = "md-5" version = "0.10.6" @@ -2140,6 +2498,22 @@ dependencies = [ "uuid", ] +[[package]] +name = "moxcms" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fbdd3d7436f8b5e892b8b7ea114271ff0fa00bc5acae845d53b07d498616ef6" +dependencies = [ + "num-traits", + "pxfm", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + [[package]] name = "nix" version = "0.30.1" @@ -2158,12 +2532,27 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + [[package]] name = "nonmax" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51" +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + [[package]] name = "nu-ansi-term" version = "0.50.3" @@ -2206,6 +2595,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "num-format" version = "0.4.4" @@ -2318,6 +2718,12 @@ dependencies = [ "windows-link", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pastey" version = "0.1.1" @@ -2401,6 +2807,12 @@ dependencies = [ "spki", ] +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + [[package]] name = "plotters" version = "0.3.7" @@ -2429,6 +2841,19 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "png" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0" +dependencies = [ + "bitflags", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + [[package]] name = "portable-atomic" version = "1.11.1" @@ -2471,6 +2896,49 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "profiling" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "pxfm" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3cbdf373972bf78df4d3b518d07003938e2c7d1fb5891e55f9cb6df57009d84" +dependencies = [ + "num-traits", +] + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quinn" version = "0.11.9" @@ -2600,6 +3068,56 @@ dependencies = [ "getrandom 0.3.3", ] +[[package]] +name = "rav1e" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" +dependencies = [ + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools 0.12.1", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "once_cell", + "paste", + "profiling", + "rand 0.8.5", + "rand_chacha 0.3.1", + "simd_helpers", + "system-deps", + "thiserror 1.0.69", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.11.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5825c26fddd16ab9f515930d49028a630efec172e903483c94796cfe31893e6b" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] + [[package]] name = "rayon" version = "1.11.0" @@ -2702,6 +3220,12 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b3789b30bd25ba102de4beabd95d21ac45b69b1be7d14522bab988c526d6799" +[[package]] +name = "rgb" +version = "0.8.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6a884d2998352bb4daf0183589aec883f16a6da1f4dde84d8e2e9a5409a1ce" + [[package]] name = "ring" version = "0.17.14" @@ -2803,6 +3327,22 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustmatica" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3156b8b799e73cc20ecd5c04447cc4e5093a22434c1fb13ae058d91a8ba7776f" +dependencies = [ + "chrono", + "fastnbt", + "flate2", + "image", + "js-sys", + "mcdata", + "serde", + "thiserror 2.0.17", +] + [[package]] name = "rustversion" version = "1.0.22" @@ -2846,6 +3386,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde_bytes" +version = "0.11.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" +dependencies = [ + "serde", + "serde_core", +] + [[package]] name = "serde_core" version = "1.0.228" @@ -2879,6 +3429,15 @@ dependencies = [ "serde_core", ] +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -2973,6 +3532,15 @@ dependencies = [ "simdutf8", ] +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + [[package]] name = "simdnbt" version = "0.8.0" @@ -3108,6 +3676,28 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + [[package]] name = "subtle" version = "2.6.1" @@ -3145,12 +3735,31 @@ dependencies = [ "syn", ] +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml", + "version-compare", +] + [[package]] name = "tagptr" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + [[package]] name = "thiserror" version = "1.0.69" @@ -3200,6 +3809,20 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "tiff" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f" +dependencies = [ + "fax", + "flate2", + "half", + "quick-error", + "weezl", + "zune-jpeg", +] + [[package]] name = "tinystr" version = "0.8.1" @@ -3289,6 +3912,27 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + [[package]] name = "toml_datetime" version = "0.7.3" @@ -3298,6 +3942,19 @@ dependencies = [ "serde_core", ] +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "winnow", +] + [[package]] name = "toml_edit" version = "0.23.7" @@ -3305,7 +3962,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" dependencies = [ "indexmap", - "toml_datetime", + "toml_datetime 0.7.3", "toml_parser", "winnow", ] @@ -3521,6 +4178,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "v_frame" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + [[package]] name = "valuable" version = "0.1.1" @@ -3538,6 +4206,12 @@ dependencies = [ "syn", ] +[[package]] +name = "version-compare" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" + [[package]] name = "version_check" version = "0.9.5" @@ -3688,6 +4362,12 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "weezl" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" + [[package]] name = "wgpu-types" version = "26.0.0" @@ -3718,12 +4398,65 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -4095,3 +4828,27 @@ name = "zlib-rs" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f06ae92f42f5e5c42443fd094f245eb656abf56dd7cce9b8b263236565e00f2" + +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "zune-jpeg" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" +dependencies = [ + "zune-core", +] diff --git a/Cargo.toml b/Cargo.toml index b9e7bcbef..3c74af46a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,6 +83,8 @@ tokio-util = "0.7" tracing = "0.1" tracing-subscriber = "0.3" uuid = "1" +rustmatica = "0.5" +mcdata = { version = "0.4", features = ["latest"] } azalea-block-macros = { path = "azalea-block/azalea-block-macros", version = "0.14.0" } azalea-block = { path = "azalea-block", version = "0.14.0" } @@ -110,6 +112,9 @@ azalea-world = { path = "azalea-world", version = "0.14.0" } [profile.release] debug = true +[profile.bench] +lto = "thin" + # decoding packets takes forever if we don't do this [profile.dev.package.azalea-crypto] opt-level = 3 diff --git a/azalea/Cargo.toml b/azalea/Cargo.toml index ab6b83b2e..2e6a839f1 100644 --- a/azalea/Cargo.toml +++ b/azalea/Cargo.toml @@ -49,6 +49,8 @@ parking_lot = { workspace = true, features = ["deadlock_detection"] } rand.workspace = true anyhow.workspace = true bevy_log.workspace = true +rustmatica.workspace = true +mcdata.workspace = true [features] default = ["log", "serde", "packet-event"] @@ -57,6 +59,10 @@ log = ["azalea-client/log"] serde = ["dep:serde", "azalea-registry/serde", "azalea-world/serde"] packet-event = ["azalea-client/packet-event"] +[[bench]] +name = "checks" +harness = false + [[bench]] name = "pathfinder" harness = false @@ -66,5 +72,5 @@ name = "physics" harness = false [[bench]] -name = "checks" +name = "realistic_one" harness = false diff --git a/azalea/benches/assets/simple/Getting over it.litematic b/azalea/benches/assets/simple/Getting over it.litematic new file mode 100644 index 000000000..6ba42f882 Binary files /dev/null and b/azalea/benches/assets/simple/Getting over it.litematic differ diff --git a/azalea/benches/assets/simple/The Jumbo LABYRINTH (by TriscuitsAllDay).litematic b/azalea/benches/assets/simple/The Jumbo LABYRINTH (by TriscuitsAllDay).litematic new file mode 100644 index 000000000..e5a5c4e5b Binary files /dev/null and b/azalea/benches/assets/simple/The Jumbo LABYRINTH (by TriscuitsAllDay).litematic differ diff --git a/azalea/benches/assets/simple/Tiny.litematic b/azalea/benches/assets/simple/Tiny.litematic new file mode 100644 index 000000000..8e6571177 Binary files /dev/null and b/azalea/benches/assets/simple/Tiny.litematic differ diff --git a/azalea/benches/realistic_one.rs b/azalea/benches/realistic_one.rs new file mode 100644 index 000000000..70e43aac6 --- /dev/null +++ b/azalea/benches/realistic_one.rs @@ -0,0 +1,162 @@ +//! Realistic benchmark what can load custom maps (currently block params and +//! entities not supported) How use: +//! For pathfinder start point place command block, after this bot will spawn on +//! command block. For pathfinder end point place diamond block. + +use std::{fs, hint::black_box, path::Path, str::FromStr, sync::Arc, time::Duration}; + +use anyhow::{Result, anyhow}; +use azalea::{ + BlockPos, + pathfinder::{ + astar::{self, PathfinderTimeout, a_star}, + custom_state::CustomPathfinderStateRef, + goals::{BlockPosGoal, Goal}, + mining::MiningCache, + rel_block_pos::RelBlockPos, + world::CachedWorld, + }, +}; +use azalea_block::BlockState; +use azalea_core::position::ChunkPos; +use azalea_inventory::Menu; +use azalea_registry::{Block, Registry}; +use azalea_world::{Chunk, ChunkStorage, PartialChunkStorage}; +use criterion::{BatchSize, Criterion, criterion_group, criterion_main}; +use mcdata::GenericBlockState; +use parking_lot::RwLock; +use rustmatica::Litematic; + +fn load_litematic( + path: impl AsRef, + partial_chunks: &mut PartialChunkStorage, + size: u32, +) -> Result<(ChunkStorage, BlockPos, BlockPos)> { + let size = size as i32; + let mut chunks = ChunkStorage::default(); + + for chunk_x in -size..size { + for chunk_z in -size..size { + let chunk_pos = ChunkPos::new(chunk_x, chunk_z); + partial_chunks.set(&chunk_pos, Some(Chunk::default()), &mut chunks); + } + } + + let (mut start, mut end) = (BlockPos::new(0, 0, 0), BlockPos::new(0, 0, 0)); + let litematic: Litematic = Litematic::read_file(path)?; + + for region in litematic.regions { + for (p, state) in region.blocks() { + let p = BlockPos::new(p.x, p.y, p.z); + let block = Block::from_str(&state.name).map_err(|e| anyhow!("{e}"))?; + + match block { + Block::CommandBlock => start = p.up(1), + Block::DiamondBlock => end = p.up(1), + _ => {} + } + + chunks.set_block_state( + BlockPos::new(p.x, p.y, p.z), + BlockState::try_from(block.to_u32()).map_err(|_| anyhow!("BlockState invalid"))?, + ); + } + } + + Ok((chunks, start, end)) +} + +fn bench_pathfinder(c: &mut Criterion) { + bench_folder(c, "benches/assets/simple", false); + bench_folder(c, "benches/assets/mine", true); +} + +fn bench_folder(c: &mut Criterion, folder: &str, mine: bool) { + let mut g = c.benchmark_group("realistic benches"); + let c = g.measurement_time(Duration::from_secs(20)); + + let mut entries = vec![]; + for file in fs::read_dir(folder).unwrap() { + let path = file.unwrap().path(); + let name = path + .file_name() + .unwrap() + .to_str() + .unwrap() + .trim_end_matches(".litematic") + .to_string(); + entries.push((path, name)); + } + + for (path, name) in entries { + let mut partial_chunks = PartialChunkStorage::new(32); + let (world, start, end) = load_litematic(path, &mut partial_chunks, 16).unwrap(); + println!("Bench: {name}, Start: {start}, End: {end}"); + + let (cached_world, mining_cache) = setup(&world, start, mine); + if iteration(cached_world, mining_cache, start, end) { + println!( + "Partial path getted, its a bug. It maybe can works in non-test enviroment, but its must be fixed." + ); + continue; + } + + c.bench_function(&name, |b| { + b.iter_batched( + || setup(&world, start, mine), + |(cached_world, mining_cache)| { + iteration(cached_world, mining_cache, start, end); + }, + BatchSize::SmallInput, + ); + }); + } +} + +fn setup(world: &ChunkStorage, start: BlockPos, mine: bool) -> (CachedWorld, MiningCache) { + let cached_world = CachedWorld::new(Arc::new(RwLock::new(world.clone().into())), start); + let mining_cache = MiningCache::new(if mine { + Some(Menu::Player(azalea_inventory::Player::default())) + } else { + None + }); + (cached_world, mining_cache) +} + +fn iteration( + cached_world: CachedWorld, + mining_cache: MiningCache, + start: BlockPos, + end: BlockPos, +) -> bool { + let goal = BlockPosGoal(end); + + let successors = |pos: RelBlockPos| { + azalea::pathfinder::call_successors_fn( + &cached_world, + &mining_cache, + &CustomPathfinderStateRef::default(), + azalea::pathfinder::moves::default_move, + pos, + ) + }; + + let astar::Path { + movements, + is_partial: partial, + } = a_star( + RelBlockPos::get_origin(start), + |n| goal.heuristic(n.apply(start)), + successors, + |n| goal.success(n.apply(start)), + PathfinderTimeout::Time(Duration::MAX), + PathfinderTimeout::Time(Duration::MAX), + ); + + black_box((movements, partial)); + + partial +} + +criterion_group!(benches, bench_pathfinder); +criterion_main!(benches); diff --git a/azalea/src/pathfinder/moves/parkour.rs b/azalea/src/pathfinder/moves/parkour.rs index b4a037324..fd2180b64 100644 --- a/azalea/src/pathfinder/moves/parkour.rs +++ b/azalea/src/pathfinder/moves/parkour.rs @@ -1,257 +1,180 @@ use azalea_client::{SprintDirection, WalkDirection}; -use azalea_core::{direction::CardinalDirection, position::BlockPos}; -use tracing::trace; use super::{Edge, ExecuteCtx, IsReachedCtx, MoveData, PathfinderCtx}; use crate::pathfinder::{astar, costs::*, player_pos_to_block_pos, rel_block_pos::RelBlockPos}; pub fn parkour_move(ctx: &mut PathfinderCtx, node: RelBlockPos) { if !ctx.world.is_block_solid(node.down(1)) { - // we can only parkour from solid blocks (not just standable blocks like slabs) return; } - parkour_forward_1_move(ctx, node); - parkour_forward_2_move(ctx, node); - parkour_forward_3_move(ctx, node); -} - -fn parkour_forward_1_move(ctx: &mut PathfinderCtx, pos: RelBlockPos) { - for dir in CardinalDirection::iter() { - let gap_offset = RelBlockPos::new(dir.x(), 0, dir.z()); - let offset = RelBlockPos::new(dir.x() * 2, 0, dir.z() * 2); - - // make sure we actually have to jump - if ctx.world.is_block_solid((pos + gap_offset).down(1)) { - continue; - } - if !ctx.world.is_passable(pos + gap_offset) { - continue; - } + let distance = 5; - let ascend: i32 = if ctx.world.is_standable(pos + offset.up(1)) { - // ascend - 1 - } else if ctx.world.is_standable(pos + offset) { - // forward - 0 - } else { - continue; - }; - - // make sure we have space to jump - if !ctx.world.is_block_passable((pos + gap_offset).up(2)) { - continue; - } + for dx in -distance..=distance { + for dz in -distance..=distance { + if ((-1..=1).contains(&dx) && (-1..=1).contains(&dz)) + || dx * dx + dz * dz > distance * distance + { + continue; + } - // make sure there's not a block above us - if !ctx.world.is_block_passable(pos.up(2)) { - continue; - } - // make sure there's not a block above the target - if !ctx.world.is_block_passable((pos + offset).up(2)) { - continue; + parkour_direction_move(ctx, node, dx, dz, dx.abs().max(dz.abs())); } + } +} - let cost = JUMP_PENALTY + WALK_ONE_BLOCK_COST * 2. + CENTER_AFTER_FALL_COST; +fn parkour_direction_move( + ctx: &mut PathfinderCtx, + pos: RelBlockPos, + dx: i16, + dz: i16, + distance: i16, +) { + let target_offset = RelBlockPos::new(dx, 0, dz); + let target_pos = pos + target_offset; + + if !are_gaps_valid(ctx, pos, dx, dz) + || (!ctx.world.is_block_passable(pos.up(2)) + || !ctx.world.is_block_passable(target_pos.up(2))) + { + return; + } + if let Some((target, cost)) = find_landing_position(ctx, target_pos, distance - 1) { ctx.edges.push(Edge { movement: astar::Movement { - target: pos + offset.up(ascend), + target, data: MoveData { execute: &execute_parkour_move, is_reached: &parkour_is_reached, }, }, cost, - }) + }); } } -fn parkour_forward_2_move(ctx: &mut PathfinderCtx, pos: RelBlockPos) { - 'dir: for dir in CardinalDirection::iter() { - let gap_1_offset = RelBlockPos::new(dir.x(), 0, dir.z()); - let gap_2_offset = RelBlockPos::new(dir.x() * 2, 0, dir.z() * 2); - let offset = RelBlockPos::new(dir.x() * 3, 0, dir.z() * 3); - - // make sure we actually have to jump - if ctx.world.is_block_solid((pos + gap_1_offset).down(1)) - || ctx.world.is_block_solid((pos + gap_2_offset).down(1)) - { - continue; - } - - let mut cost = JUMP_PENALTY + WALK_ONE_BLOCK_COST * 3. + CENTER_AFTER_FALL_COST; - - let ascend: i32 = if ctx.world.is_standable(pos + offset.up(1)) { - 1 - } else if ctx.world.is_standable(pos + offset) { - cost += FALL_N_BLOCKS_COST[1]; - 0 - } else if ctx.world.is_standable(pos + offset.down(1)) { - cost += FALL_N_BLOCKS_COST[2]; - -1 - } else { - continue; - }; +fn are_gaps_valid(ctx: &mut PathfinderCtx, pos: RelBlockPos, dx: i16, dz: i16) -> bool { + let line = get_line_bresenham(0, 0, dx, dz); + + line.iter() + .enumerate() + .skip(1) + .take(line.len().saturating_sub(2)) + .all(|(_, &(x, z))| { + let gap_pos = pos + RelBlockPos::new(x, 0, z); + !ctx.world.is_block_solid(gap_pos.down(1)) + && ctx.world.is_passable(gap_pos) + && ctx.world.is_block_passable(gap_pos.up(2)) + }) +} - // make sure we have space to jump - for offset in [gap_1_offset, gap_2_offset] { - if !ctx.world.is_passable(pos + offset) { - continue 'dir; - } - if !ctx.world.is_block_passable((pos + offset).up(2)) { - continue 'dir; - } +fn get_line_bresenham(x0: i16, y0: i16, x1: i16, y1: i16) -> Vec<(i16, i16)> { + let mut points = Vec::new(); + let (dx, dy) = ((x1 - x0).abs(), (y1 - y0).abs()); + let (sx, sy) = (x0.cmp(&x1).reverse() as i16, y0.cmp(&y1).reverse() as i16); + let mut err = dx - dy; + let (mut x, mut y) = (x0, y0); + + loop { + points.push((x, y)); + if x == x1 && y == y1 { + break; } - // make sure there's not a block above us - if !ctx.world.is_block_passable(pos.up(2)) { - continue; + let e2 = 2 * err; + if e2 > -dy { + err -= dy; + x += sx; } - // make sure there's not a block above the target - if !ctx.world.is_block_passable((pos + offset).up(2)) { - continue; + if e2 < dx { + err += dx; + y += sy; } - - ctx.edges.push(Edge { - movement: astar::Movement { - target: pos + offset.up(ascend), - data: MoveData { - execute: &execute_parkour_move, - is_reached: &parkour_is_reached, - }, - }, - cost, - }) } + points } -fn parkour_forward_3_move(ctx: &mut PathfinderCtx, pos: RelBlockPos) { - 'dir: for dir in CardinalDirection::iter() { - let gap_1_offset = RelBlockPos::new(dir.x(), 0, dir.z()); - let gap_2_offset = RelBlockPos::new(dir.x() * 2, 0, dir.z() * 2); - let gap_3_offset = RelBlockPos::new(dir.x() * 3, 0, dir.z() * 3); - let offset = RelBlockPos::new(dir.x() * 4, 0, dir.z() * 4); - - // make sure we actually have to jump - if ctx.world.is_block_solid((pos + gap_1_offset).down(1)) - || ctx.world.is_block_solid((pos + gap_2_offset).down(1)) - || ctx.world.is_block_solid((pos + gap_3_offset).down(1)) - { - continue; - } - - if !ctx.world.is_standable(pos + offset) { - continue; - }; - - // make sure we have space to jump - for offset in [gap_1_offset, gap_2_offset, gap_3_offset] { - if !ctx.world.is_passable(pos + offset) { - continue 'dir; +fn find_landing_position( + ctx: &mut PathfinderCtx, + base_target: RelBlockPos, + distance: i16, +) -> Option<(RelBlockPos, f32)> { + generate_height_checks(distance) + .into_iter() + .find_map(|(height_offset, fall_cost)| { + let target = base_target.up(height_offset); + if ctx.world.is_standable(target) { + let movement_cost = if distance >= 4 { + SPRINT_ONE_BLOCK_COST + } else { + WALK_ONE_BLOCK_COST + }; + let actual_distance = + ((base_target.x as f32).powi(2) + (base_target.z as f32).powi(2)).sqrt(); + let cost = JUMP_PENALTY + + movement_cost * actual_distance + + fall_cost + + CENTER_AFTER_FALL_COST; + Some((target, cost)) + } else { + None } - if !ctx.world.is_block_passable((pos + offset).up(2)) { - continue 'dir; + }) +} + +fn generate_height_checks(distance: i16) -> Vec<(i32, f32)> { + match distance { + 2 => vec![(1, 0.0), (0, 0.0)], + 3 => vec![ + (1, 0.0), + (0, FALL_N_BLOCKS_COST[1]), + (-1, FALL_N_BLOCKS_COST[2]), + ], + _ => { + let mut checks = Vec::with_capacity(5); + if distance <= 3 { + checks.push((1, 0.0)); } + checks.push((0, FALL_N_BLOCKS_COST[1])); + checks.extend((1..=3).map(|h| (-(h as i32), FALL_N_BLOCKS_COST[h]))); + checks } - // make sure there's not a block above us - if !ctx.world.is_block_passable(pos.up(2)) { - continue; - } - // make sure there's not a block above the target - if !ctx.world.is_block_passable((pos + offset).up(2)) { - continue; - } - - let cost = JUMP_PENALTY + SPRINT_ONE_BLOCK_COST * 4. + CENTER_AFTER_FALL_COST; - - ctx.edges.push(Edge { - movement: astar::Movement { - target: pos + offset, - data: MoveData { - execute: &execute_parkour_move, - is_reached: &parkour_is_reached, - }, - }, - cost, - }) } } fn execute_parkour_move(mut ctx: ExecuteCtx) { - let ExecuteCtx { - position, - target, - start, - .. - } = ctx; + let delta = ctx.target - ctx.start; + let jump_distance = (delta.x as f64).hypot(delta.z as f64); - let start_center = start.center(); - let target_center = target.center(); - - let jump_distance = i32::max((target - start).x.abs(), (target - start).z.abs()); - - let ascend: i32 = target.y - start.y; - - if jump_distance >= 4 || (ascend > 0 && jump_distance >= 3) { - // 3 block gap OR 2 block gap with ascend + if jump_distance >= 3.0 { ctx.sprint(SprintDirection::Forward); } else { ctx.walk(WalkDirection::Forward); } - let x_dir = (target.x - start.x).clamp(-1, 1); - let z_dir = (target.z - start.z).clamp(-1, 1); - let dir = BlockPos::new(x_dir, 0, z_dir); - let jump_at_pos = start + dir; - - let is_at_start_block = player_pos_to_block_pos(position) == start; - let is_at_jump_block = player_pos_to_block_pos(position) == jump_at_pos; + let should_jump = [ + (delta.x, ctx.start.x, ctx.position.x), + (delta.z, ctx.start.z, ctx.position.z), + ] + .iter() + .any(|&(d, start, pos)| { + if d == 0 { + return false; + } - let required_distance_from_center = if jump_distance <= 2 { - // 1 block gap - 0.0 - } else { - 0.6 - }; - let distance_from_start = f64::max( - (position.x - start_center.x).abs(), - (position.z - start_center.z).abs(), - ); + let edge = if d > 0 { start + 1 } else { start } as f64; + (d > 0 && pos >= edge) || (d < 0 && pos <= edge) + }); - if !is_at_start_block - && !is_at_jump_block - && (position.y - start.y as f64) < 0.094 - && distance_from_start < 0.85 - { - // we have to be on the start block to jump - ctx.look_at(start_center); - trace!("looking at start_center"); - } else { - ctx.look_at(target_center); - trace!("looking at target_center"); - } + ctx.look_at(ctx.target.center()); - if !is_at_start_block && is_at_jump_block && distance_from_start > required_distance_from_center - { + if should_jump { ctx.jump(); } } #[must_use] -pub fn parkour_is_reached( - IsReachedCtx { - position, - target, - physics, - .. - }: IsReachedCtx, -) -> bool { - // 0.094 and not 0 for lilypads - if player_pos_to_block_pos(position) == target && (position.y - target.y as f64) < 0.094 { - return true; - } - - // this is to make it handle things like slabs correctly - player_pos_to_block_pos(position) == target && physics.on_ground() +pub fn parkour_is_reached(ctx: IsReachedCtx) -> bool { + player_pos_to_block_pos(ctx.position) == ctx.target + && (ctx.position.y - (ctx.target.y as f64) < 0.094 || ctx.physics.on_ground()) }