diff --git a/Cargo.lock b/Cargo.lock index 1e4f790..9277ad3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,6 +75,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + [[package]] name = "async-compression" version = "0.4.37" @@ -137,7 +143,7 @@ dependencies = [ [[package]] name = "botmark" -version = "0.1.0" +version = "0.1.1" dependencies = [ "clap", "crossbeam", @@ -186,13 +192,13 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[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]] @@ -207,9 +213,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.54" +version = "4.5.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" +checksum = "a75ca66430e33a14957acc24c5077b503e7d374151b2b4b3a10c83b4ceb4be0e" dependencies = [ "clap_builder", "clap_derive", @@ -217,9 +223,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.54" +version = "4.5.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" +checksum = "793207c7fa6300a0608d1080b858e5fdbe713cdc1c8db9fb17777d8a13e63df0" dependencies = [ "anstream", "anstyle", @@ -229,9 +235,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.49" +version = "4.5.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" dependencies = [ "heck", "proc-macro2", @@ -374,15 +380,14 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crossfire" -version = "2.1.10" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd901251b9b46c1752c85edfee0aee718c03a85a065f4126d32e5d6d419edf48" +checksum = "cf9c756fd351d7bc1f95698a33a90ce39c8f7458335cc7e95132d3d36124902a" dependencies = [ - "crossbeam-queue", "crossbeam-utils", - "enum_dispatch", "futures-core", "parking_lot", + "smallvec", ] [[package]] @@ -409,9 +414,9 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.2.0-rc.12" +version = "0.2.0-rc.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6dcdb44f2c3ee25689ca12a4c19e664fd09f97aeae0bc5043b2dbab6389e308" +checksum = "c7722afd27468475c9b6063dc03a57ef2ca833816981619f8ebe64d38d207eef" dependencies = [ "hybrid-array", ] @@ -464,13 +469,13 @@ dependencies = [ [[package]] name = "digest" -version = "0.11.0-rc.7" +version = "0.11.0-rc.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca14c221bd9052fd2da7c34a2eeb5ae54732db28be47c35937be71793d675422" +checksum = "bff8de092798697546237a3a701e4174fe021579faec9b854379af9bf1e31962" dependencies = [ "block-buffer 0.11.0", "const-oid 0.10.2", - "crypto-common 0.2.0-rc.12", + "crypto-common 0.2.0-rc.13", ] [[package]] @@ -568,6 +573,12 @@ dependencies = [ "miniz_oxide", ] +[[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" @@ -699,15 +710,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]] @@ -727,6 +739,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" @@ -735,7 +756,7 @@ checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.2.0", ] [[package]] @@ -770,13 +791,19 @@ dependencies = [ [[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", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "indexmap" version = "2.13.0" @@ -829,6 +856,12 @@ dependencies = [ "wasm-bindgen", ] +[[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" @@ -920,9 +953,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" @@ -1133,6 +1166,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" @@ -1176,7 +1219,7 @@ dependencies = [ [[package]] name = "pumpkin-config" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin#91813d4cac41f3e6ab76950a20927dda62f832ea" +source = "git+https://github.com/Pumpkin-MC/Pumpkin#452d8c413b0e54a1b29eeda73fd0fdbddddebaf2" dependencies = [ "log", "pumpkin-util", @@ -1188,7 +1231,7 @@ dependencies = [ [[package]] name = "pumpkin-data" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin#91813d4cac41f3e6ab76950a20927dda62f832ea" +source = "git+https://github.com/Pumpkin-MC/Pumpkin#452d8c413b0e54a1b29eeda73fd0fdbddddebaf2" dependencies = [ "crc-fast", "heck", @@ -1208,10 +1251,11 @@ dependencies = [ [[package]] name = "pumpkin-macros" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin#91813d4cac41f3e6ab76950a20927dda62f832ea" +source = "git+https://github.com/Pumpkin-MC/Pumpkin#452d8c413b0e54a1b29eeda73fd0fdbddddebaf2" dependencies = [ "proc-macro-error2", "proc-macro2", + "pumpkin-data", "quote", "syn", ] @@ -1219,7 +1263,7 @@ dependencies = [ [[package]] name = "pumpkin-nbt" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin#91813d4cac41f3e6ab76950a20927dda62f832ea" +source = "git+https://github.com/Pumpkin-MC/Pumpkin#452d8c413b0e54a1b29eeda73fd0fdbddddebaf2" dependencies = [ "bytes", "cesu8", @@ -1231,7 +1275,7 @@ dependencies = [ [[package]] name = "pumpkin-protocol" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin#91813d4cac41f3e6ab76950a20927dda62f832ea" +source = "git+https://github.com/Pumpkin-MC/Pumpkin#452d8c413b0e54a1b29eeda73fd0fdbddddebaf2" dependencies = [ "aes", "async-compression", @@ -1253,7 +1297,7 @@ dependencies = [ [[package]] name = "pumpkin-util" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin#91813d4cac41f3e6ab76950a20927dda62f832ea" +source = "git+https://github.com/Pumpkin-MC/Pumpkin#452d8c413b0e54a1b29eeda73fd0fdbddddebaf2" dependencies = [ "base64", "bytes", @@ -1278,7 +1322,7 @@ dependencies = [ [[package]] name = "pumpkin-world" version = "0.1.0-dev+1.21.11" -source = "git+https://github.com/Pumpkin-MC/Pumpkin#91813d4cac41f3e6ab76950a20927dda62f832ea" +source = "git+https://github.com/Pumpkin-MC/Pumpkin#452d8c413b0e54a1b29eeda73fd0fdbddddebaf2" dependencies = [ "bitflags", "bytes", @@ -1304,7 +1348,7 @@ dependencies = [ "ruzstd", "serde", "serde_json", - "sha2 0.11.0-rc.3", + "sha2 0.11.0-rc.4", "slotmap", "thiserror", "thread_local", @@ -1315,9 +1359,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] @@ -1330,12 +1374,12 @@ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" -version = "0.10.0-rc.7" -source = "git+https://github.com/rust-random/rand#6e80534233d4bb09ed0abc086edeacaae6f54dc0" +version = "0.10.0-rc.8" +source = "git+https://github.com/rust-random/rand#a4c9a8e565fa310de423e3ba89593b647b721e8c" 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]] @@ -1349,9 +1393,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" @@ -1433,6 +1477,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" @@ -1509,13 +1559,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.11.0-rc.3" +version = "0.11.0-rc.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d43dc0354d88b791216bb5c1bfbb60c0814460cc653ae0ebd71f286d0bd927" +checksum = "7535f94fa3339fe9e5e9be6260a909e62af97f6e14b32345ccf79b92b8b81233" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.11.0-rc.7", + "digest 0.11.0-rc.9", ] [[package]] @@ -1558,15 +1608,15 @@ 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" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "slotmap" @@ -1585,9 +1635,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", @@ -1675,9 +1725,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", @@ -1692,15 +1742,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", @@ -1820,6 +1870,12 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "utf8parse" version = "0.2.2" @@ -1828,9 +1884,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" +checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f" dependencies = [ "getrandom 0.3.4", "js-sys", @@ -1857,7 +1913,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]] @@ -1905,6 +1970,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 = "windows-link" version = "0.2.1" @@ -2000,12 +2099,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 = "zeroize" version = "1.8.2" @@ -2014,6 +2201,6 @@ checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zmij" -version = "1.0.16" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfcd145825aace48cff44a8844de64bf75feec3080e0aa5cdbde72961ae51a65" +checksum = "1966f8ac2c1f76987d69a74d0e0f929241c10e78136434e3be70ff7f58f64214" diff --git a/Cargo.toml b/Cargo.toml index 6687c2c..423d9d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "botmark" -version = "0.1.0" +version = "0.1.1" edition = "2024" [profile.release] @@ -12,7 +12,7 @@ codegen-units = 1 log = "0.4" simple_logger = "5.1.0" # CLI -clap = { version = "4.5.54", features = ["derive"] } +clap = { version = "4.5.56", features = ["derive"] } # Networking tokio = { version = "1.49.0", features = ["net", "io-util"] } pumpkin-protocol = { git = "https://github.com/Pumpkin-MC/Pumpkin", package = "pumpkin-protocol", default-features = false, features = ["serverbound", "clientbound"]} @@ -20,5 +20,5 @@ pumpkin-util = { git = "https://github.com/Pumpkin-MC/Pumpkin", package = "pumpk pumpkin-data = { git = "https://github.com/Pumpkin-MC/Pumpkin", package = "pumpkin-data"} crossbeam = "0.8.4" -uuid = "1.19.0" +uuid = "1.20.0" rand = { git = "https://github.com/rust-random/rand"} diff --git a/README.md b/README.md index 4a306d2..0381869 100644 --- a/README.md +++ b/README.md @@ -39,10 +39,22 @@ Here's a detailed breakdown of all available command-line arguments: - The timeout (in milliseconds) for each bot connection. - Example: `--delay 500` (500 milliseconds delay) -- **`--spam_message ""` (Optional):** +- **`--spam_message ""` (Optional, Default: `Please do not spam!`):** - Will send a Chat message with the specified `spam_message_delay`. - Example: `--spam_message "Hello, I'm a Robot"` -- **`--spam_message_delay ` (Optional, Default: `210`):** - - The delay (in milliseconds) between spam message. - - Example: `--spam_message_delay 100` (100 milliseconds delay) \ No newline at end of file +- **`--spam_message_delay_min ` (Optional, Default: `150`):** + - The minimal delay (in milliseconds) between spam message. + - Example: `--spam_message_delay_min 100` (100 milliseconds delay) +- **`--spam_message_delay_max ` (Optional, Default: `350`):** + - The maximal delay (in milliseconds) between spam message. + - Example: `--spam_message_delay_max 100` (100 milliseconds delay) +- **`--spam_message_delay_max ` (Optional, Default: `350`):** + - The maximal delay (in milliseconds) between spam message. + - Example: `--spam_message_delay_max 100` (100 milliseconds delay) +- **`--enable_rotation ` (Optional, Default: `true`):** + - Enable random head rotations. + - Example: `--enable_rotation true` +- **`--enable_swing ` (Optional, Default: `true`):** + - Enable random arm swings. + - Example: `--enable_swing true` \ No newline at end of file diff --git a/src/client.rs b/src/client.rs index bd5f765..5ce1f09 100644 --- a/src/client.rs +++ b/src/client.rs @@ -5,24 +5,28 @@ use pumpkin_protocol::java::client::config::{CConfigDisconnect, CFinishConfig}; use pumpkin_protocol::java::client::login::{ CEncryptionRequest, CLoginDisconnect, CLoginSuccess, CSetCompression, }; -use pumpkin_protocol::java::client::play::{CKeepAlive, CPlayDisconnect, CPlayerPosition}; +use pumpkin_protocol::java::client::play::{CKeepAlive, CLogin, CPlayDisconnect, CPlayerPosition}; use pumpkin_protocol::java::packet_decoder::TCPNetworkDecoder; use pumpkin_protocol::java::packet_encoder::TCPNetworkEncoder; use pumpkin_protocol::java::server::config::{SAcknowledgeFinishConfig, SKnownPacks}; use pumpkin_protocol::java::server::handshake::SHandShake; use pumpkin_protocol::java::server::login::{SLoginAcknowledged, SLoginStart}; -use pumpkin_protocol::java::server::play::{SChatMessage, SConfirmTeleport, SKeepAlive}; -use pumpkin_protocol::packet::Packet; +use pumpkin_protocol::java::server::play::{ + SChatMessage, SConfirmTeleport, SKeepAlive, SPlayerLoaded, SPlayerPosition, SPlayerRotation, + SSwingArm, +}; +use pumpkin_protocol::packet::MultiVersionJavaPacket; use pumpkin_protocol::ser::NetworkWriteExt; use pumpkin_protocol::ser::{ReadingError, WritingError}; use pumpkin_protocol::{ ClientPacket, CompressionLevel, CompressionThreshold, ConnectionState, PacketDecodeError, RawPacket, ServerPacket, }; +use pumpkin_util::math::vector3::Vector3; use pumpkin_util::version::MinecraftVersion; use std::io::Write; use std::net::SocketAddr; -use std::sync::atomic::{AtomicU32, Ordering}; +use std::sync::atomic::{AtomicI32, AtomicU32, Ordering}; use std::sync::{Arc, atomic::AtomicBool}; use std::time::{SystemTime, UNIX_EPOCH}; use tokio::io::{BufReader, BufWriter}; @@ -36,7 +40,10 @@ use tokio::{ }; use uuid::Uuid; +use crate::Args; + /// Everything which makes a Connection with our Server is a `Client`. +#[expect(dead_code)] pub struct Client { /// The current connection state of the client (e.g., Handshaking, Status, Play). pub connection_state: AtomicCell, @@ -48,7 +55,41 @@ pub struct Client { pub network_reader: Arc>>>, close_interrupt: Arc, + entity_id: AtomicI32, + message_spam_cooldown: AtomicU32, + message_count: AtomicU32, + is_loaded: AtomicBool, + swing_cooldown: AtomicU32, + // Position + current_x: AtomicCell, + current_y: AtomicCell, + current_z: AtomicCell, + + velocity_x: AtomicCell, + velocity_y: AtomicCell, + velocity_z: AtomicCell, + + start_x: AtomicCell, + start_z: AtomicCell, + target_x: AtomicCell, + target_z: AtomicCell, + + move_progress: AtomicCell, + move_cooldown: AtomicU32, + + // Rotation + current_yaw: AtomicCell, + current_pitch: AtomicCell, + // Starting point of the movement + start_yaw: AtomicCell, + start_pitch: AtomicCell, + // Goal point + target_yaw: AtomicCell, + target_pitch: AtomicCell, + // Progress: 0.0 (start) to 1.0 (end) + rotation_progress: AtomicCell, + rotation_cooldown: AtomicU32, } impl Client { @@ -62,9 +103,35 @@ impl Client { network_reader: Arc::new(Mutex::new(TCPNetworkDecoder::new(BufReader::new( connection_reader, )))), + entity_id: AtomicI32::new(0), + velocity_x: AtomicCell::new(0.0), + velocity_y: AtomicCell::new(0.0), + velocity_z: AtomicCell::new(0.0), + closed: AtomicBool::new(false), + swing_cooldown: AtomicU32::new(0), close_interrupt: Arc::new(Notify::new()), message_spam_cooldown: AtomicU32::new(1), + message_count: AtomicU32::new(0), + is_loaded: AtomicBool::new(false), + rotation_cooldown: AtomicU32::new(0), + rotation_progress: AtomicCell::new(1.0), + current_yaw: AtomicCell::new(0.0), + current_pitch: AtomicCell::new(0.0), + start_yaw: AtomicCell::new(0.0), + start_pitch: AtomicCell::new(0.0), + target_yaw: AtomicCell::new(0.0), + target_pitch: AtomicCell::new(0.0), + + current_x: AtomicCell::new(0.0), + current_y: AtomicCell::new(0.0), + current_z: AtomicCell::new(0.0), + start_x: AtomicCell::new(0.0), + start_z: AtomicCell::new(0.0), + target_x: AtomicCell::new(0.0), + target_z: AtomicCell::new(0.0), + move_progress: AtomicCell::new(1.0), + move_cooldown: AtomicU32::new(0), } } @@ -108,7 +175,7 @@ impl Client { Ok(packet) => Some(packet), Err(err) => { if !matches!(err, PacketDecodeError::ConnectionClosed) { - log::warn!("Failed to decode packet from client: {err}"); + log::warn!("Failed to decode packet from server: {err}"); self.close().await; } None @@ -136,23 +203,169 @@ impl Client { } // TODO: make this less ugly ig - pub async fn tick(&self, spam_message: Arc>, spam_message_delay: u32) { + pub async fn tick(&self, args: &Args) { if self.connection_state.load() != ConnectionState::Play { return; } - if let Some(spam_message) = spam_message.as_ref() - && self - .message_spam_cooldown - .fetch_sub(1, std::sync::atomic::Ordering::Relaxed) - == 0 - { - self.message_spam_cooldown - .store(spam_message_delay, std::sync::atomic::Ordering::Relaxed); - self.send_message(spam_message.clone()).await + if !self.is_loaded.load(Ordering::Relaxed) { + return; + } + + if let Some(spam_message) = &args.spam_message { + let result = self.message_spam_cooldown.fetch_update( + Ordering::SeqCst, + Ordering::Relaxed, + |curr| { + if curr == 0 { + let delay = rand::random_range( + args.spam_message_delay_min..args.spam_message_delay_max, + ); + Some(delay) + } else { + Some(curr - 1) + } + }, + ); + if let Ok(0) = result { + self.send_message(spam_message.clone()).await; + } + } + + if args.enable_rotation { + self.tick_rotation().await; + } + if args.enable_swing { + self.tick_swing().await; + } + //self.tick_movement().await + } + + async fn tick_rotation(&self) { + let progress = self.rotation_progress.load(); + let cooldown = self.rotation_cooldown.load(Ordering::Relaxed); + + if progress >= 1.0 { + // We have finished the movement. Wait for the cooldown. + if cooldown == 0 { + // Pick a new target and reset + let current_y = self.current_yaw.load(); + let current_p = self.current_pitch.load(); + + self.start_yaw.store(current_y); + self.start_pitch.store(current_p); + self.target_yaw.store(rand::random_range(-180.0..180.0)); + self.target_pitch.store(rand::random_range(-90.0..90.0)); + + self.rotation_progress.store(0.0); + // Wait for 2-5 seconds (40-100 ticks) before moving again + self.rotation_cooldown + .store(rand::random_range(40..100), Ordering::Relaxed); + } else { + self.rotation_cooldown.fetch_sub(1, Ordering::Relaxed); + } + } else { + // Increment progress (e.g., 0.02 means it takes 50 ticks/2.5s to complete turn) + let new_progress = (progress + 0.02).min(1.0); + self.rotation_progress.store(new_progress); + + // Calculate the "Smooth" T value using the S-Curve formula + // t = 3p^2 - 2p^3 + let t = 3.0 * new_progress.powi(2) - 2.0 * new_progress.powi(3); + + // Interpolate: start + (target - start) * t + let start_y = self.start_yaw.load(); + let target_y = self.target_yaw.load(); + let interpolated_yaw = start_y + (target_y - start_y) * t; + + let start_p = self.start_pitch.load(); + let target_p = self.target_pitch.load(); + let interpolated_pitch = start_p + (target_p - start_p) * t; + + self.current_yaw.store(interpolated_yaw); + self.current_pitch.store(interpolated_pitch); + + // Send rotation packet + self.send_packet(&SPlayerRotation { + yaw: interpolated_yaw, + pitch: interpolated_pitch, + ground: true, + }) + .await; + } + } + + #[expect(dead_code)] + async fn tick_movement(&self) { + let progress = self.move_progress.load(); + let cooldown = self.move_cooldown.load(Ordering::Relaxed); + + if progress >= 1.0 { + if cooldown == 0 { + // Start a new walk + let cur_x = self.current_x.load(); + let cur_z = self.current_z.load(); + + self.start_x.store(cur_x); + self.start_z.store(cur_z); + + // Small random walk (0.5 to 1.5 blocks) + let offset_x = rand::random_range(-1.5..1.5); + let offset_z = rand::random_range(-1.5..1.5); + + self.target_x.store(cur_x + offset_x); + self.target_z.store(cur_z + offset_z); + + self.move_progress.store(0.0); + // Wait 2-5 seconds between moves + self.move_cooldown + .store(rand::random_range(40..100), Ordering::Relaxed); + } else { + self.move_cooldown.fetch_sub(1, Ordering::Relaxed); + } + } else { + // Increase this to 0.05 for a normal human walking pace (20 ticks to finish) + let new_progress = (progress + 0.05).min(1.0); + self.move_progress.store(new_progress); + + // Cubic easing for a natural start/stop + let t = 3.0 * new_progress.powi(2) - 2.0 * new_progress.powi(3); + + let start_x = self.start_x.load(); + let target_x = self.target_x.load(); + let start_z = self.start_z.load(); + let target_z = self.target_z.load(); + + let interp_x = start_x + (target_x - start_x) * t as f64; + let interp_z = start_z + (target_z - start_z) * t as f64; + + self.current_x.store(interp_x); + self.current_z.store(interp_z); + + self.send_packet(&SPlayerPosition { + position: Vector3::new(interp_x, self.current_y.load(), interp_z), + collision: 1, // on_ground + }) + .await; + } + } + + async fn tick_swing(&self) { + let cooldown = self.swing_cooldown.load(Ordering::Relaxed); + + if cooldown == 0 { + if rand::random_bool(0.01) { + self.send_packet(&SSwingArm { hand: VarInt(0) }).await; + + self.swing_cooldown + .store(rand::random_range(20..40), Ordering::Relaxed); + } + } else { + self.swing_cooldown.fetch_sub(1, Ordering::Relaxed); } } pub async fn send_message(&self, message: String) { + let count = self.message_count.fetch_add(1, Ordering::SeqCst); let start = SystemTime::now(); let since_the_epoch = start .duration_since(UNIX_EPOCH) @@ -162,7 +375,7 @@ impl Client { timestamp: since_the_epoch.as_millis() as i64, salt: rand::random(), signature: None, - message_count: VarInt(1), + message_count: VarInt(count as i32), acknowledged: vec![0; 20].into_boxed_slice(), checksum: 0, }) @@ -174,7 +387,7 @@ impl Client { write: impl Write, ) -> Result<(), WritingError> { let mut write = write; - write.write_var_int(&VarInt(P::PACKET_ID))?; + write.write_var_int(&VarInt(P::PACKET_ID.latest_id))?; packet.write_packet_data(write, &MinecraftVersion::V_1_21_11) } @@ -205,7 +418,6 @@ impl Client { } pub async fn join_server(&self, address: SocketAddr, name: String) { - dbg!(address.ip().to_string()); self.send_packet(&SHandShake { protocol_version: VarInt(CURRENT_MC_PROTOCOL as i32), server_address: address.ip().to_string(), @@ -236,20 +448,20 @@ impl Client { async fn handle_login_packet(&self, packet: &mut RawPacket) -> Result<(), ReadingError> { let bytebuf = &packet.payload[..]; match packet.id { - CEncryptionRequest::PACKET_ID => { - log::debug!("Got Encryption Request") + id if id == CEncryptionRequest::PACKET_ID => { + todo!("Encryption is currently not implemented, please disable it at server level") } - CSetCompression::PACKET_ID => { + id if id == CSetCompression::PACKET_ID => { log::trace!("Set Compression"); let packet = CSetCompression::read(bytebuf)?; self.set_compression(Some((packet.threshold.0 as usize, 6))) .await } - CLoginDisconnect::PACKET_ID => { + id if id == CLoginDisconnect::PACKET_ID => { log::error!("Kicking in Login State"); self.close().await; } - CLoginSuccess::PACKET_ID => { + id if id == CLoginSuccess::PACKET_ID => { log::trace!("Login -> Config"); self.send_packet(&SLoginAcknowledged).await; self.connection_state.store(ConnectionState::Config); @@ -266,11 +478,11 @@ impl Client { async fn handle_config_packet(&self, packet: &mut RawPacket) -> Result<(), ReadingError> { match packet.id { - CConfigDisconnect::PACKET_ID => { + id if id == CConfigDisconnect::PACKET_ID => { log::error!("Kicking in Config State"); self.close().await; } - CFinishConfig::PACKET_ID => { + id if id == CFinishConfig::PACKET_ID => { log::trace!("Config -> Play"); self.send_packet(&SAcknowledgeFinishConfig).await; self.connection_state.store(ConnectionState::Play); @@ -283,21 +495,58 @@ impl Client { async fn handle_play_packet(&self, packet: &mut RawPacket) -> Result<(), ReadingError> { let bytebuf = &packet.payload[..]; match packet.id { - CKeepAlive::PACKET_ID => { + id if id == CKeepAlive::PACKET_ID => { let packet = CKeepAlive::read(bytebuf)?; self.send_packet(&SKeepAlive { keep_alive_id: packet.keep_alive_id, }) .await; } - CPlayerPosition::PACKET_ID => { + // TODO + // id if id == CEntityVelocity::PACKET_ID => { + // let packet = CEntityVelocity::read(bytebuf)?; + + // if packet.entity_id.0 == self.entity_id.load(Ordering::Relaxed) as i32 { + // self.velocity_x.store(packet.velocity.0.x as f64 / 8000.0); + // self.velocity_y.store(packet.velocity.0.y as f64 / 8000.0); + // self.velocity_z.store(packet.velocity.0.z as f64 / 8000.0); + // } + // } + id if id == CPlayerPosition::PACKET_ID => { let packet = CPlayerPosition::read(bytebuf)?; + self.current_yaw.store(packet.yaw); + self.current_pitch.store(packet.pitch); + + let x = packet.position.x; + let y = packet.position.y; + let z = packet.position.z; + + self.current_x.store(x); + self.current_y.store(y); + self.current_z.store(z); + + self.start_x.store(x); + self.start_z.store(z); + self.target_x.store(x); + self.target_z.store(z); + + self.move_progress.store(1.0); + self.move_cooldown + .store(rand::random_range(40..100), Ordering::Relaxed); self.send_packet(&SConfirmTeleport { teleport_id: packet.teleport_id, }) .await; + self.is_loaded.store(true, Ordering::Relaxed); } - CPlayDisconnect::PACKET_ID => { + id if id == CLogin::PACKET_ID => { + // TODO + // let packet = CLogin::read(bytebuf)?; + // self.entity_id.store(packet.entity_id, Ordering::Relaxed); + + self.send_packet(&SPlayerLoaded).await; + } + id if id == CPlayDisconnect::PACKET_ID => { log::error!("Kicking in Play State"); self.close().await; } diff --git a/src/main.rs b/src/main.rs index a1c3feb..f1aca0a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,4 @@ -use std::{net::SocketAddr, sync::Arc, thread::sleep, time::Duration}; +use std::{net::SocketAddr, sync::Arc, time::Duration}; use clap::Parser; use client::Client; @@ -17,31 +17,39 @@ pub struct Args { pub delay: u64, #[arg(short, long, default_value_t = 5000)] pub timeout: u64, - #[arg(long)] + + #[arg(long, default_value = "Please do not spam!")] pub spam_message: Option, - #[arg(long, default_value_t = 210)] - pub spam_message_delay: u32, + #[arg(long, default_value_t = 150)] + pub spam_message_delay_min: u32, + #[arg(long, default_value_t = 250)] + pub spam_message_delay_max: u32, + + #[arg(long, default_value_t = true)] + pub enable_rotation: bool, + #[arg(long, default_value_t = true)] + pub enable_swing: bool, } #[tokio::main] async fn main() { simple_logger::init_with_level(log::Level::Info).unwrap(); - let args = Args::parse(); + let args = Arc::new(Args::parse()); let address = args.ip.parse::().unwrap(); + let bot_count = args.count; log::info!( "{} Bots will Join {} with a delay of {}ms", - args.count, + bot_count, address, args.delay ); - let mut join_handles = Vec::with_capacity(args.count as usize); - for i in 0..args.count { - sleep(Duration::from_millis(args.delay)); - let stream_result = timeout( - Duration::from_millis(args.timeout), - TcpStream::connect(address), - ) - .await; + let timeout_dur = Duration::from_millis(args.timeout); + let timeout_delay = Duration::from_millis(args.delay); + + let mut join_handles = Vec::with_capacity(bot_count as usize); + for i in 0..bot_count { + tokio::time::sleep(timeout_delay).await; + let stream_result = timeout(timeout_dur, TcpStream::connect(address)).await; let stream = match stream_result { Ok(Ok(s)) => s, @@ -54,25 +62,31 @@ async fn main() { "Bot {} connection to {} timed out after {}ms", i + 1, address, - args.timeout + bot_count ); continue; } }; let client = Arc::new(Client::new(stream)); - let message = Arc::new(args.spam_message.clone()); client.join_server(address, format!("BOT_{i}")).await; + let cloned_args = args.clone(); let join_handle = tokio::spawn(async move { + let mut tick_interval = tokio::time::interval(Duration::from_millis(5)); + tick_interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); loop { - if !client.process_packets().await { - break; + tokio::select! { + res = client.process_packets() => { + if !res { break; } + } + _ = tick_interval.tick() => { + client.tick(&cloned_args).await; + } } - client.tick(message.clone(), args.spam_message_delay).await; } }); join_handles.push(join_handle); - log::info!("{}/{} Bots Joined", i + 1, args.count); + log::info!("{}/{} Bots Joined", i + 1, bot_count); } // Graceful shutdown on Ctrl+C tokio::signal::ctrl_c().await.unwrap();