From 4fa508ec8146d09887ff3605655929f910fd4063 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Sun, 19 Jan 2025 05:13:25 -0500 Subject: [PATCH 01/35] feat: start work on 0.2.0 --- .cargo/config.toml | 9 +- .gitignore | 6 +- Cargo.lock | 3948 +++++++++++++++++++------------------ Cargo.toml | 36 +- README.md | 71 - images/icon.png | Bin 6697 -> 0 bytes src/arguments.rs | 10 + src/bot.rs | 1104 ----------- src/commands.rs | 101 + src/events.rs | 48 + src/logging.rs | 75 - src/main.rs | 727 +------ src/matrix.rs | 150 -- src/scripting/client.rs | 109 + src/scripting/mod.rs | 2 + src/scripting/position.rs | 13 + 16 files changed, 2363 insertions(+), 4046 deletions(-) delete mode 100644 README.md delete mode 100644 images/icon.png create mode 100644 src/arguments.rs delete mode 100644 src/bot.rs create mode 100644 src/commands.rs create mode 100644 src/events.rs delete mode 100644 src/logging.rs delete mode 100644 src/matrix.rs create mode 100644 src/scripting/client.rs create mode 100644 src/scripting/mod.rs create mode 100644 src/scripting/position.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index e21bd8a..5909338 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,10 +1,3 @@ [target.x86_64-unknown-linux-gnu] -linker = "/usr/bin/clang" +linker = "clang" rustflags = ["-Clink-arg=-fuse-ld=mold"] - -[target.x86_64-apple-darwin] -rustflags = ["-C", "link-arg=-fuse-ld=/usr/local/bin/zld"] - -[target.x86_64-pc-windows-msvc] -linker = "rust-lld.exe" -rustflags = ["-Zshare-generics=y"] diff --git a/.gitignore b/.gitignore index ae8d42c..45560fd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ -/target -/scripts -/bot_configuration.toml +*.lua +.luarc.json +target diff --git a/Cargo.lock b/Cargo.lock index ae95020..2bb087c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,152 +1,177 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" -version = "0.19.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aead" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" -dependencies = [ - "generic-array", - "rand_core 0.6.4", -] +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aes" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433cfd6710c9986c576a25ca913c39d66a6474107b406f34f91d4a8923395241" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", - "cipher 0.4.3", + "cipher", "cpufeatures", ] [[package]] name = "ahash" -version = "0.7.6" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom 0.2.8", - "once_cell", - "version_check", -] - -[[package]] -name = "ahash" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom 0.2.8", + "const-random", + "getrandom", "once_cell", - "serde", "version_check", + "zerocopy", ] [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] -name = "android_system_properties" -version = "0.1.5" +name = "allocator-api2" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android_log-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ecc8056bf6ab9892dcd53216c83d1597487d7dacac16c8df6b877d127df9937" + +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ - "libc", + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +dependencies = [ + "anstyle", + "once_cell", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.68" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" - -[[package]] -name = "anymap2" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c" - -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "as-any" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0f477b951e452a0b6b4a10b53ccd569042d1d01729b519e02074a9c0958a063" + +[[package]] +name = "assert_type_match" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f548ad2c4031f2902e3edc1f29c29e835829437de49562d8eb5dc5584d3a1043" dependencies = [ - "serde", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "assign" -version = "1.1.1" +name = "async-channel" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f093eed78becd229346bf859eec0aa4dd7ddde0757287b2b4107a1f09c80002" - -[[package]] -name = "async-compression" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942c7cd7ae39e91bde4820d74132e9862e62c2f386c3aa90ccf55949f5bad63a" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" dependencies = [ - "flate2", + "concurrent-queue", + "event-listener-strategy", "futures-core", - "memchr", "pin-project-lite", - "tokio", ] [[package]] -name = "async-lock" -version = "2.6.0" +name = "async-executor" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8101efe8695a6c17e02911402145357e718ac92d3ff88ae8419e84b1707b685" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" dependencies = [ - "event-listener", + "async-task", + "concurrent-queue", + "fastrand", "futures-lite", + "slab", ] -[[package]] -name = "async-once-cell" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72faff1fdc615a0199d7bf71e6f389af54d46a66e9beb5d76c39e48eda93ecce" - [[package]] name = "async-recursion" -version = "1.0.2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b015a331cc64ebd1774ba119538573603427eaace0a1950c423ab971f903796" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", @@ -154,123 +179,100 @@ dependencies = [ ] [[package]] -name = "async-stream" -version = "0.3.3" +name = "async-task" +version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dad5c83079eae9969be7fadefe640a1c566901f05ff91ab221de4b6f68d9507e" -dependencies = [ - "async-stream-impl", - "futures-core", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.64" +version = "0.1.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2" +checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "atomic" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b88d82667eca772c4aa12f0f1348b3ae643424c8876448f3f7bd5787032e234c" -dependencies = [ - "autocfg", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "autocfg" -version = "1.1.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "azalea" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c47c8a728a5073e5efdb6a199f948e89f3fc2081f2b256232f30f0d65e4e75" +version = "0.11.0+mc1.21.4" +source = "git+https://github.com/azalea-rs/azalea.git#4fb6b077464e14f816e4c4fe54ff648e8c3d0ede" dependencies = [ - "anyhow", - "async-trait", + "azalea-auth", "azalea-block", + "azalea-brigadier", + "azalea-buf", "azalea-chat", "azalea-client", "azalea-core", + "azalea-entity", + "azalea-inventory", "azalea-physics", "azalea-protocol", + "azalea-registry", "azalea-world", + "bevy_app", + "bevy_ecs", + "bevy_log", + "bevy_tasks", + "derive_more 2.0.1", "futures", - "log", + "futures-lite", + "indexmap", "nohash-hasher", + "num-format", "num-traits", - "parking_lot 0.12.1", - "priority-queue", - "thiserror", + "parking_lot", + "rustc-hash 2.1.1", + "serde", + "thiserror 2.0.11", "tokio", - "uuid 1.3.0", + "tracing", + "uuid", ] [[package]] name = "azalea-auth" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a630316c79925fbbc4e18ad2e763add12532e719c2fe9c95d3d906da0762f45b" +version = "0.11.0+mc1.21.4" +source = "git+https://github.com/azalea-rs/azalea.git#4fb6b077464e14f816e4c4fe54ff648e8c3d0ede" dependencies = [ "azalea-buf", "azalea-crypto", + "base64", "chrono", - "log", - "num-bigint", + "md-5", "reqwest", + "rsa", "serde", "serde_json", - "thiserror", + "thiserror 2.0.11", "tokio", - "uuid 1.3.0", + "tracing", + "uuid", ] [[package]] name = "azalea-block" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f648b01c7290b817c3aad3f725f4a88df06e2c0c7f598ecf29bc9fbc2be2f925" +version = "0.11.0+mc1.21.4" +source = "git+https://github.com/azalea-rs/azalea.git#4fb6b077464e14f816e4c4fe54ff648e8c3d0ede" dependencies = [ "azalea-block-macros", "azalea-buf", + "azalea-registry", ] [[package]] name = "azalea-block-macros" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12c21c01e312abf920f210b14cc34c18863efe3c3fac2aa774e6077854eee86d" +version = "0.11.0+mc1.21.4" +source = "git+https://github.com/azalea-rs/azalea.git#4fb6b077464e14f816e4c4fe54ff648e8c3d0ede" dependencies = [ "proc-macro2", "quote", @@ -279,34 +281,32 @@ dependencies = [ [[package]] name = "azalea-brigadier" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854f255baa6b740dc6f440f4a34bcf75e7cd71168fb8fd828d1f98d5a341ef95" +version = "0.11.0+mc1.21.4" +source = "git+https://github.com/azalea-rs/azalea.git#4fb6b077464e14f816e4c4fe54ff648e8c3d0ede" dependencies = [ "azalea-buf", "azalea-chat", + "parking_lot", ] [[package]] name = "azalea-buf" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec6031972c401255a5ae9038608dacf1eae6b46787433767cd26d7ccf9e93b97" +version = "0.11.0+mc1.21.4" +source = "git+https://github.com/azalea-rs/azalea.git#4fb6b077464e14f816e4c4fe54ff648e8c3d0ede" dependencies = [ "azalea-buf-macros", "byteorder", - "log", "serde_json", - "thiserror", - "tokio", - "uuid 1.3.0", + "simdnbt", + "thiserror 2.0.11", + "tracing", + "uuid", ] [[package]] name = "azalea-buf-macros" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c002b742e4810daeb4eb30970f2c081fc604b3f0a46a2258021dddaaa7e13951" +version = "0.11.0+mc1.21.4" +source = "git+https://github.com/azalea-rs/azalea.git#4fb6b077464e14f816e4c4fe54ff648e8c3d0ede" dependencies = [ "proc-macro2", "quote", @@ -315,120 +315,166 @@ dependencies = [ [[package]] name = "azalea-chat" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723855de866bd8d0d2630973c9dda8b36fd038c69f18ddfe9d1788640409e376" +version = "0.11.0+mc1.21.4" +source = "git+https://github.com/azalea-rs/azalea.git#4fb6b077464e14f816e4c4fe54ff648e8c3d0ede" dependencies = [ "azalea-buf", "azalea-language", - "log", - "once_cell", + "azalea-registry", "serde", "serde_json", + "simdnbt", + "tracing", ] [[package]] name = "azalea-client" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07403c4372b5fd50f01aecee0b1c2d7e9acf745750804380261f41c1beb20c12" +version = "0.11.0+mc1.21.4" +source = "git+https://github.com/azalea-rs/azalea.git#4fb6b077464e14f816e4c4fe54ff648e8c3d0ede" dependencies = [ - "anyhow", - "async-trait", "azalea-auth", "azalea-block", + "azalea-buf", "azalea-chat", "azalea-core", "azalea-crypto", + "azalea-entity", + "azalea-inventory", "azalea-physics", "azalea-protocol", + "azalea-registry", "azalea-world", - "log", - "nohash-hasher", - "once_cell", - "parking_lot 0.12.1", + "bevy_app", + "bevy_ecs", + "bevy_log", + "bevy_tasks", + "bevy_time", + "derive_more 2.0.1", + "minecraft_folder_path", + "parking_lot", "regex", - "thiserror", + "reqwest", + "simdnbt", + "thiserror 2.0.11", "tokio", - "typemap_rev", - "uuid 1.3.0", + "tracing", + "uuid", ] [[package]] name = "azalea-core" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49bb5d57f3186c1d6a10a9959c98bb5697e8bb41dbef0d922bff233c55cad4f" +version = "0.11.0+mc1.21.4" +source = "git+https://github.com/azalea-rs/azalea.git#4fb6b077464e14f816e4c4fe54ff648e8c3d0ede" dependencies = [ "azalea-buf", "azalea-chat", - "azalea-nbt", - "uuid 1.3.0", + "azalea-registry", + "bevy_ecs", + "indexmap", + "nohash-hasher", + "num-traits", + "serde", + "simdnbt", + "tracing", ] [[package]] name = "azalea-crypto" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b606a93c9d5bd648a48608168f832254db6a1f60e42fb599eab07db9a8d944a0" +version = "0.11.0+mc1.21.4" +source = "git+https://github.com/azalea-rs/azalea.git#4fb6b077464e14f816e4c4fe54ff648e8c3d0ede" dependencies = [ "aes", "azalea-buf", "cfb8", "num-bigint", - "rand 0.8.5", + "rand", + "rsa", "rsa_public_encrypt_pkcs1", "sha-1", - "uuid 1.3.0", + "sha2", + "uuid", +] + +[[package]] +name = "azalea-entity" +version = "0.11.0+mc1.21.4" +source = "git+https://github.com/azalea-rs/azalea.git#4fb6b077464e14f816e4c4fe54ff648e8c3d0ede" +dependencies = [ + "azalea-block", + "azalea-buf", + "azalea-chat", + "azalea-core", + "azalea-inventory", + "azalea-registry", + "azalea-world", + "bevy_app", + "bevy_ecs", + "derive_more 2.0.1", + "enum-as-inner", + "nohash-hasher", + "parking_lot", + "simdnbt", + "thiserror 2.0.11", + "tracing", + "uuid", +] + +[[package]] +name = "azalea-inventory" +version = "0.11.0+mc1.21.4" +source = "git+https://github.com/azalea-rs/azalea.git#4fb6b077464e14f816e4c4fe54ff648e8c3d0ede" +dependencies = [ + "azalea-buf", + "azalea-chat", + "azalea-core", + "azalea-inventory-macros", + "azalea-registry", + "indexmap", + "simdnbt", + "uuid", +] + +[[package]] +name = "azalea-inventory-macros" +version = "0.11.0+mc1.21.4" +source = "git+https://github.com/azalea-rs/azalea.git#4fb6b077464e14f816e4c4fe54ff648e8c3d0ede" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] name = "azalea-language" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2746c21432330995acb0bdbd3528bcc35d023784c5769eef3d1a7fc95095ef07" +version = "0.11.0+mc1.21.4" +source = "git+https://github.com/azalea-rs/azalea.git#4fb6b077464e14f816e4c4fe54ff648e8c3d0ede" dependencies = [ - "once_cell", "serde", "serde_json", ] -[[package]] -name = "azalea-nbt" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45ff939a8c7a8dffdee8c3ad8eb1a881c5d32c248e1dea2bef27b46879523e4a" -dependencies = [ - "ahash 0.8.3", - "azalea-buf", - "byteorder", - "flate2", - "log", - "num-derive", - "num-traits", - "serde", -] - [[package]] name = "azalea-physics" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca89e08fde6d0f18d46e94ee807f2fde308c66f07c37d1e9d1fe6ba198f2187" +version = "0.11.0+mc1.21.4" +source = "git+https://github.com/azalea-rs/azalea.git#4fb6b077464e14f816e4c4fe54ff648e8c3d0ede" dependencies = [ "azalea-block", "azalea-core", + "azalea-entity", + "azalea-inventory", + "azalea-registry", "azalea-world", - "once_cell", - "parking_lot 0.12.1", + "bevy_app", + "bevy_ecs", + "parking_lot", + "tracing", ] [[package]] name = "azalea-protocol" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cec3b56d9b43e19dbfda9cb2424e130d3d75dbc794abd327baf085a5ce8bd951" +version = "0.11.0+mc1.21.4" +source = "git+https://github.com/azalea-rs/azalea.git#4fb6b077464e14f816e4c4fe54ff648e8c3d0ede" dependencies = [ - "async-compression", "async-recursion", "azalea-auth", "azalea-block", @@ -437,30 +483,31 @@ dependencies = [ "azalea-chat", "azalea-core", "azalea-crypto", - "azalea-nbt", + "azalea-entity", + "azalea-inventory", "azalea-protocol-macros", "azalea-registry", "azalea-world", - "byteorder", - "bytes", + "bevy_ecs", "flate2", "futures", - "futures-util", - "log", + "futures-lite", + "hickory-resolver", "serde", "serde_json", - "thiserror", + "simdnbt", + "socks5-impl", + "thiserror 2.0.11", "tokio", "tokio-util", - "trust-dns-resolver", - "uuid 1.3.0", + "tracing", + "uuid", ] [[package]] name = "azalea-protocol-macros" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b41027e2f8fa3167cd744e967a313e04f4c74176042fe6be8daa9bbf525137bb" +version = "0.11.0+mc1.21.4" +source = "git+https://github.com/azalea-rs/azalea.git#4fb6b077464e14f816e4c4fe54ff648e8c3d0ede" dependencies = [ "proc-macro2", "quote", @@ -469,19 +516,247 @@ dependencies = [ [[package]] name = "azalea-registry" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd5b62480c354646b40786d1ecea9d1f8e6eb09fe8e613b692feb2d28ab8fc4c" +version = "0.11.0+mc1.21.4" +source = "git+https://github.com/azalea-rs/azalea.git#4fb6b077464e14f816e4c4fe54ff648e8c3d0ede" dependencies = [ "azalea-buf", "azalea-registry-macros", + "serde", + "simdnbt", ] [[package]] name = "azalea-registry-macros" -version = "0.5.0" +version = "0.11.0+mc1.21.4" +source = "git+https://github.com/azalea-rs/azalea.git#4fb6b077464e14f816e4c4fe54ff648e8c3d0ede" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "azalea-world" +version = "0.11.0+mc1.21.4" +source = "git+https://github.com/azalea-rs/azalea.git#4fb6b077464e14f816e4c4fe54ff648e8c3d0ede" +dependencies = [ + "azalea-block", + "azalea-buf", + "azalea-core", + "azalea-registry", + "bevy_ecs", + "derive_more 2.0.1", + "nohash-hasher", + "parking_lot", + "rustc-hash 2.1.1", + "simdnbt", + "thiserror 2.0.11", + "tracing", +] + +[[package]] +name = "backtrace" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c1b2f732449c8d01100ea3df7efe8234832d3b3423059477a7e5797ae9f25d8" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bevy_app" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47983196daf9290ac97023de67d9364182c4a9a88ce400039e2d79aaf342dcb2" +dependencies = [ + "bevy_derive", + "bevy_ecs", + "bevy_reflect", + "bevy_tasks", + "bevy_utils", + "console_error_panic_hook", + "ctrlc", + "derive_more 1.0.0", + "downcast-rs", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "bevy_derive" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa901a443b9ee433823f0d1a4e6db78440ff27572a98e7fa7f2a614bf8d6e475" +dependencies = [ + "bevy_macro_utils", + "quote", + "syn", +] + +[[package]] +name = "bevy_ecs" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40e6d5ad061f750f710a9a4e2f9e7d65f86c0061fc9ffcf3a430b3c003bc0088" +dependencies = [ + "bevy_ecs_macros", + "bevy_ptr", + "bevy_reflect", + "bevy_tasks", + "bevy_utils", + "bitflags", + "concurrent-queue", + "derive_more 1.0.0", + "disqualified", + "fixedbitset 0.5.7", + "nonmax", + "petgraph", + "smallvec", +] + +[[package]] +name = "bevy_ecs_macros" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea80917f2d11e8928d0b7cd41efa55b814355e6a3544a1bf68e6b73871d332c" +dependencies = [ + "bevy_macro_utils", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "bevy_log" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8530cc17503ccfe86c8496136fca222bfa389c9cc70267be7d377d0f6621aa29" +dependencies = [ + "android_log-sys", + "bevy_app", + "bevy_ecs", + "bevy_utils", + "tracing-log", + "tracing-oslog", + "tracing-subscriber", + "tracing-wasm", +] + +[[package]] +name = "bevy_macro_utils" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090371a2cd85574989febff6063a21d1fbbc2939e80f00fe075f62aa8e616136" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "toml_edit", +] + +[[package]] +name = "bevy_ptr" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4da2111eefa2000ea8c9dc1beee2eb7283b29b5ef90a29fe43c748df549f84ad" + +[[package]] +name = "bevy_reflect" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82af24a68fd8feff476d9672ff34d220d3f45e95ef2f2324e7cb674614d18138" +dependencies = [ + "assert_type_match", + "bevy_ptr", + "bevy_reflect_derive", + "bevy_utils", + "derive_more 1.0.0", + "disqualified", + "downcast-rs", + "erased-serde", + "serde", + "smallvec", + "smol_str", +] + +[[package]] +name = "bevy_reflect_derive" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8369e6e779ab3540f9dcd93d062139f62551b3d2fe1ab451c6ddf74757e22ccd" +dependencies = [ + "bevy_macro_utils", + "proc-macro2", + "quote", + "syn", + "uuid", +] + +[[package]] +name = "bevy_tasks" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e085e93374b8dd2559968bcc1bc66d059387ef3128e59e9af92dcde03f10b7" +dependencies = [ + "async-channel", + "async-executor", + "concurrent-queue", + "futures-channel", + "futures-lite", + "pin-project", + "wasm-bindgen-futures", +] + +[[package]] +name = "bevy_time" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02b14d56c04a372725dacc656e2e5f134ff239e72cd73431a065b32b296db31" +dependencies = [ + "bevy_app", + "bevy_ecs", + "bevy_reflect", + "bevy_utils", + "crossbeam-channel", +] + +[[package]] +name = "bevy_utils" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2993cac374b3f88cfaf59506c71f8e3e7ad8b4961f4e9864bc76e1c9e1e4400c" +dependencies = [ + "ahash", + "bevy_utils_proc_macros", + "getrandom", + "hashbrown 0.14.5", + "thread_local", + "tracing", + "web-time", +] + +[[package]] +name = "bevy_utils_proc_macros" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2606f79dfe359a88e2a59bb6cd632cd42e9d4bcd250ac8bc3a4e7657e82f4f39" dependencies = [ "proc-macro2", "quote", @@ -489,151 +764,85 @@ dependencies = [ ] [[package]] -name = "azalea-world" -version = "0.5.0" +name = "bindgen" +version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1c163aa1fbe0d73fc1f81730af5b6e59054fa60339352634107ce38653ec8f2" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" dependencies = [ - "azalea-block", - "azalea-buf", - "azalea-chat", - "azalea-core", - "azalea-nbt", - "azalea-registry", - "enum-as-inner", + "bitflags", + "cexpr", + "clang-sys", + "itertools", "log", - "nohash-hasher", - "parking_lot 0.12.1", - "thiserror", - "uuid 1.3.0", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex", + "syn", ] -[[package]] -name = "backoff" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" -dependencies = [ - "futures-core", - "getrandom 0.2.8", - "instant", - "pin-project-lite", - "rand 0.8.5", - "tokio", -] - -[[package]] -name = "backtrace" -version = "0.3.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" - -[[package]] -name = "base64ct" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" - [[package]] name = "bitflags" -version = "1.3.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "blake3" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ae2468a89544a466886840aa467a25b766499f4f04bf7d9fcd10ecee9fccef" -dependencies = [ - "arrayref", - "arrayvec", - "cc", - "cfg-if", - "constant_time_eq", - "digest 0.10.6", -] +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] name = "block-buffer" -version = "0.9.0" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] [[package]] -name = "block-buffer" -version = "0.10.3" +name = "bstr" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" dependencies = [ - "generic-array", -] - -[[package]] -name = "block-padding" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a90ec2df9600c28a01c56c4784c9207a96d2451833aeceb8cc97e4c9548bb78" -dependencies = [ - "generic-array", + "memchr", + "serde", ] [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.4.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" - -[[package]] -name = "cbc" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" -dependencies = [ - "cipher 0.4.3", -] +checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" [[package]] name = "cc" -version = "1.0.79" +version = "1.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9" +dependencies = [ + "shlex", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] [[package]] name = "cfb8" @@ -641,7 +850,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "014c0a0e1ad0dae6a86c082db2f9bd7fe8c2c734227047d0d8b4d4a3a094a1e1" dependencies = [ - "cipher 0.4.3", + "cipher", ] [[package]] @@ -651,152 +860,171 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "chacha20" -version = "0.8.2" +name = "cfg_aliases" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6" -dependencies = [ - "cfg-if", - "cipher 0.3.0", - "cpufeatures", - "zeroize", -] - -[[package]] -name = "chacha20poly1305" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5" -dependencies = [ - "aead", - "chacha20", - "cipher 0.3.0", - "poly1305", - "zeroize", -] +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.23" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ - "iana-time-zone", - "js-sys", - "num-integer", "num-traits", - "time", - "wasm-bindgen", - "winapi", + "serde", ] [[package]] name = "cipher" -version = "0.3.0" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" -dependencies = [ - "generic-array", -] - -[[package]] -name = "cipher" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common", "inout", ] [[package]] -name = "codespan-reporting" -version = "0.11.1" +name = "clang-sys" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ - "termcolor", - "unicode-width", + "glob", + "libc", + "libloading", ] [[package]] -name = "colored" -version = "2.0.0" +name = "clap" +version = "4.5.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +checksum = "8acebd8ad879283633b343856142139f2da2317c96b05b4dd6181c61e2480184" dependencies = [ - "atty", - "lazy_static", - "winapi", + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ba32cbda51c7e1dfd49acc1457ba1a7dec5b64fe360e828acb13ca8dc9c2f9" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", ] [[package]] name = "const-oid" -version = "0.7.1" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] -name = "constant_time_eq" -version = "0.2.4" +name = "const-random" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3ad85c1f65dc7b37604eb0e89748faf0b9653065f2a8ef69f96a687ec1e9279" - -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" dependencies = [ - "core-foundation-sys", - "libc", + "const-random-macro", ] [[package]] -name = "core-foundation-sys" -version = "0.8.3" +name = "const-random-macro" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom", + "once_cell", + "tiny-keccak", +] [[package]] name = "cpufeatures" -version = "0.2.5" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] [[package]] -name = "crossbeam-epoch" -version = "0.9.13" +name = "crossbeam-channel" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", - "memoffset", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.14" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" -dependencies = [ - "cfg-if", -] +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "crypto-common" @@ -809,248 +1037,118 @@ dependencies = [ ] [[package]] -name = "ctr" -version = "0.9.2" +name = "ctrlc" +version = "3.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" dependencies = [ - "cipher 0.4.3", -] - -[[package]] -name = "curve25519-dalek" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" -dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", - "serde", - "subtle", - "zeroize", -] - -[[package]] -name = "cxx" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc831ee6a32dd495436e317595e639a587aa9907bef96fe6e6abc290ab6204e9" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94331d54f1b1a8895cd81049f7eaaaef9d05a7dcb4d1fd08bf3ff0806246789d" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48dcd35ba14ca9b40d6e4b4b39961f23d835dbb8eed74565ded361d93e1feb8a" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bbeb29798b407ccd82a3324ade1a7286e0d29851475990b612670f6f5124d2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "darling" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e" -dependencies = [ - "darling_core", - "quote", - "syn", -] - -[[package]] -name = "dashmap" -version = "5.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" -dependencies = [ - "cfg-if", - "hashbrown", - "lock_api", - "once_cell", - "parking_lot_core 0.9.7", + "nix", + "windows-sys 0.59.0", ] [[package]] name = "data-encoding" -version = "2.3.3" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" +checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" [[package]] name = "der" -version = "0.5.1" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", -] - -[[package]] -name = "derive_builder" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07adf7be193b71cc36b193d0f5fe60b918a3a9db4dad0449f57bcfd519704a3" -dependencies = [ - "derive_builder_macro", -] - -[[package]] -name = "derive_builder_core" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f91d4cfa921f1c05904dc3c57b4a32c38aed3340cce209f3a6fd1478babafc4" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "derive_builder_macro" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f0314b72bed045f3a68671b3c86328386762c93f82d98c65c3cb5e5f573dd68" -dependencies = [ - "derive_builder_core", - "syn", -] - -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - -[[package]] -name = "digest" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" -dependencies = [ - "block-buffer 0.10.3", - "crypto-common", - "subtle", -] - -[[package]] -name = "discard" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" - -[[package]] -name = "displaydoc" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "ed25519" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" -dependencies = [ - "serde", - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" -dependencies = [ - "curve25519-dalek", - "ed25519", - "rand 0.7.3", - "serde", - "serde_bytes", - "sha2 0.9.9", + "pem-rfc7468", "zeroize", ] [[package]] -name = "either" -version = "1.8.1" +name = "derive_more" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" - -[[package]] -name = "encoding_rs" -version = "0.8.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" dependencies = [ - "cfg-if", + "derive_more-impl 1.0.0", ] [[package]] -name = "enum-as-inner" -version = "0.5.1" +name = "derive_more" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl 2.0.1", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "disqualified" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9c272297e804878a2a4b707cfcfc6d2328b5bb936944613b4fdf2b9269afdfd" + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ "heck", "proc-macro2", @@ -1058,41 +1156,61 @@ dependencies = [ "syn", ] +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erased-serde" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" +dependencies = [ + "serde", + "typeid", +] + [[package]] name = "errornowatcher" -version = "0.1.0" +version = "0.2.0" dependencies = [ "anyhow", - "async-recursion", "azalea", - "azalea-block", - "azalea-core", - "azalea-protocol", - "chrono", - "colored", - "matrix-sdk", - "rand 0.8.5", - "serde", - "strum", - "strum_macros", + "clap", + "futures", + "mlua", + "parking_lot", "tokio", - "toml", ] [[package]] name = "event-listener" -version = "2.5.3" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" +dependencies = [ + "event-listener", + "pin-project-lite", +] [[package]] name = "fastrand" -version = "1.8.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" -dependencies = [ - "instant", -] +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fixedbitset" @@ -1101,10 +1219,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] -name = "flate2" -version = "1.0.25" +name = "fixedbitset" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "flate2" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", "miniz_oxide", @@ -1116,51 +1240,20 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] -[[package]] -name = "fs2" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - [[package]] name = "futures" -version = "0.3.26" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -1173,9 +1266,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.26" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -1183,15 +1276,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.26" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.26" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -1200,30 +1293,28 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.26" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "1.12.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" +checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" dependencies = [ "fastrand", "futures-core", "futures-io", - "memchr", "parking", "pin-project-lite", - "waker-fn", ] [[package]] name = "futures-macro" -version = "0.3.26" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", @@ -1231,35 +1322,22 @@ dependencies = [ ] [[package]] -name = "futures-signals" +name = "futures-sink" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3acc659ba666cff13fdf65242d16428f2f11935b688f82e4024ad39667a5132" -dependencies = [ - "discard", - "futures-channel", - "futures-core", - "futures-util", - "pin-project", -] - -[[package]] -name = "futures-sink" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.26" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.26" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -1273,20 +1351,11 @@ dependencies = [ "slab", ] -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - [[package]] name = "generic-array" -version = "0.14.6" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -1294,111 +1363,100 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.16" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.9.0+wasi-snapshot-preview1", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] [[package]] name = "gimli" -version = "0.27.1" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] -name = "h2" -version = "0.3.15" +name = "glob" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", + "ahash", + "allocator-api2", + "serde", ] [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash 0.7.6", -] +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] -name = "hermit-abi" -version = "0.1.19" +name = "hickory-proto" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +checksum = "2ad3d6d98c648ed628df039541a5577bee1a7c83e9e16fe3dbedeea4cdfeb971" dependencies = [ - "libc", + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna", + "ipnet", + "once_cell", + "rand", + "thiserror 1.0.69", + "tinyvec", + "tokio", + "tracing", + "url", ] [[package]] -name = "hermit-abi" -version = "0.2.6" +name = "hickory-resolver" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +checksum = "dcf287bde7b776e85d7188e6e5db7cf410a2f9531fe82817eb87feed034c8d14" dependencies = [ - "libc", -] - -[[package]] -name = "hkdf" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" -dependencies = [ - "hmac", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest 0.10.6", + "cfg-if", + "futures-util", + "hickory-proto", + "lru-cache", + "once_cell", + "parking_lot", + "rand", + "smallvec", + "thiserror 1.0.69", + "tokio", + "tracing", ] [[package]] name = "http" -version = "0.2.8" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", @@ -1407,138 +1465,236 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", "pin-project-lite", ] [[package]] name = "httparse" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" [[package]] name = "hyper" -version = "0.14.24" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e011372fa0b68db8350aa7a248930ecc7839bf46d8485577d69f117a75f164c" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" dependencies = [ "bytes", "futures-channel", - "futures-core", "futures-util", - "h2", "http", "http-body", "httparse", - "httpdate", "itoa", "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" +dependencies = [ + "futures-util", + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-util" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", "socket2", "tokio", "tower-service", "tracing", - "want", ] [[package]] -name = "hyper-tls" -version = "0.5.0" +name = "icu_collections" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", + "displaydoc", + "yoke", + "zerofrom", + "zerovec", ] [[package]] -name = "iana-time-zone" -version = "0.1.53" +name = "icu_locid" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "winapi", + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", ] [[package]] -name = "iana-time-zone-haiku" -version = "0.1.1" +name = "icu_locid_transform" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" dependencies = [ - "cxx", - "cxx-build", + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", ] [[package]] -name = "ident_case" -version = "1.0.1" +name = "icu_locid_transform_data" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" [[package]] -name = "idna" -version = "0.2.3" +name = "icu_normalizer" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] name = "idna" -version = "0.3.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", ] [[package]] -name = "indexed_db_futures" -version = "0.2.3" +name = "idna_adapter" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26ac735f676c52305becf53264b91cea9866a8de61ccbf464405b377b9cbca9" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" dependencies = [ - "cfg-if", - "js-sys", - "uuid 0.8.2", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", + "icu_normalizer", + "icu_properties", ] [[package]] name = "indexmap" -version = "1.9.2" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ - "autocfg", - "hashbrown", - "serde", + "equivalent", + "hashbrown 0.15.2", ] [[package]] @@ -1547,91 +1703,77 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" dependencies = [ - "block-padding", "generic-array", ] [[package]] -name = "instant" -version = "0.1.12" +name = "ipnet" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] -name = "ipnet" -version = "2.7.1" +name = "is_terminal_polyfill" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" -version = "0.10.5" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.5" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "js-sys" -version = "0.3.61" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] -[[package]] -name = "js_int" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d937f95470b270ce8b8950207715d71aa8e153c0d44c6684d59397ed4949160a" -dependencies = [ - "serde", -] - -[[package]] -name = "js_option" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68421373957a1593a767013698dbf206e2b221eefe97a44d98d18672ff38423c" -dependencies = [ - "serde", -] - [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "libc" -version = "0.2.139" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] -name = "link-cplusplus" -version = "1.0.8" +name = "libloading" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ - "cc", + "cfg-if", + "windows-targets", ] +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -1639,10 +1781,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] -name = "lock_api" -version = "0.4.9" +name = "litemap" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -1650,21 +1798,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "lru" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6e8aaa3f231bb4bd57b84b2d5dc3ae7f350265df8aa96492e0bc394a1571909" -dependencies = [ - "hashbrown", -] +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" [[package]] name = "lru-cache" @@ -1676,254 +1812,115 @@ dependencies = [ ] [[package]] -name = "maplit" -version = "1.0.2" +name = "luau0-src" +version = "0.12.2+luau660" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" - -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - -[[package]] -name = "matrix-sdk" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbeafb4809f33f377165f2fbcf10e0613053ad206762194c3050a727fd3abcb2" +checksum = "d62e6fe44400150a045b8f2a6721a268437d45dc67600f8ca716e2fa3a3cc2fe" dependencies = [ - "anymap2", - "async-once-cell", - "async-stream", - "async-trait", - "backoff", - "bytes", - "dashmap", - "derive_builder", - "event-listener", - "futures-core", - "futures-signals", - "futures-util", - "http", - "matrix-sdk-base", - "matrix-sdk-common", - "matrix-sdk-indexeddb", - "matrix-sdk-sled", - "mime", - "reqwest", - "ruma", - "serde", - "serde_json", - "thiserror", - "tokio", - "tracing", - "url", - "wasm-timer", - "zeroize", + "cc", ] [[package]] -name = "matrix-sdk-base" -version = "0.6.1" +name = "matchers" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b944f6d1fc8779ba790dd0b942ceff45c626c1f5da847f01122d355ad06511bd" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "async-stream", - "async-trait", - "dashmap", - "futures-channel", - "futures-core", - "futures-signals", - "futures-util", - "lru", - "matrix-sdk-common", - "matrix-sdk-crypto", - "once_cell", - "ruma", - "serde", - "serde_json", - "thiserror", - "tracing", - "zeroize", + "regex-automata 0.1.10", ] [[package]] -name = "matrix-sdk-common" -version = "0.6.0" +name = "md-5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b85a6a743cc9dcf9385e61a26db78276078beddd27f3762d9d82baa2030695f1" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ - "async-lock", - "futures-core", - "futures-util", - "instant", - "ruma", - "serde", - "tokio", - "wasm-bindgen-futures", - "wasm-timer", -] - -[[package]] -name = "matrix-sdk-crypto" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68fa699e8dd54578a4b92e3fcd18a50da8e415a0c042da1706b0330fc2d8f949" -dependencies = [ - "aes", - "async-trait", - "atomic", - "base64 0.13.1", - "byteorder", - "ctr", - "dashmap", - "event-listener", - "futures-util", - "hmac", - "matrix-sdk-common", - "pbkdf2", - "rand 0.8.5", - "ruma", - "serde", - "serde_json", - "sha2 0.10.6", - "thiserror", - "tokio", - "tracing", - "vodozemac", - "zeroize", -] - -[[package]] -name = "matrix-sdk-indexeddb" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7847d36bba832bc787214323bc042b71dca7fdf2aee9f0e3eb573b64f2f7eb7f" -dependencies = [ - "anyhow", - "async-trait", - "base64 0.13.1", - "dashmap", - "derive_builder", - "getrandom 0.2.8", - "indexed_db_futures", - "js-sys", - "matrix-sdk-base", - "matrix-sdk-crypto", - "matrix-sdk-store-encryption", - "ruma", - "serde", - "serde_json", - "thiserror", - "tracing", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "matrix-sdk-sled" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ded5a703ad8a82b8edfde808228711315c8761a5fbf7ac2b98ab4951dadd066" -dependencies = [ - "async-stream", - "async-trait", - "dashmap", - "derive_builder", - "fs_extra", - "futures-core", - "futures-util", - "matrix-sdk-base", - "matrix-sdk-common", - "matrix-sdk-crypto", - "matrix-sdk-store-encryption", - "ruma", - "serde", - "serde_json", - "sled", - "thiserror", - "tokio", - "tracing", -] - -[[package]] -name = "matrix-sdk-store-encryption" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ddee75c3cca58f3a323283dc4e849d19d52988903f907ed0fb53dcad5d6fd25" -dependencies = [ - "blake3", - "chacha20poly1305", - "displaydoc", - "hmac", - "pbkdf2", - "rand 0.8.5", - "serde", - "serde_json", - "sha2 0.10.6", - "thiserror", - "zeroize", + "cfg-if", + "digest", ] [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" -dependencies = [ - "autocfg", -] +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "mime" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minecraft_folder_path" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d60a6352e005f1f86008644a9fe336a66f74c94428182162cc69eb8c6fff458d" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.6.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b" dependencies = [ - "adler", + "adler2", ] [[package]] name = "mio" -version = "0.8.5" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", - "log", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.42.0", + "wasi", + "windows-sys 0.52.0", ] [[package]] -name = "native-tls" -version = "0.2.11" +name = "mlua" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +checksum = "d3f763c1041eff92ffb5d7169968a327e1ed2ebfe425dac0ee5a35f29082534b" dependencies = [ - "lazy_static", + "bstr", + "either", + "futures-util", + "libloading", + "mlua-sys", + "num-traits", + "parking_lot", + "rustc-hash 2.1.1", +] + +[[package]] +name = "mlua-sys" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1901c1a635a22fe9250ffcc4fcc937c16b47c2e9e71adba8784af8bca1f69594" +dependencies = [ + "cc", + "cfg-if", + "luau0-src", + "pkg-config", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", ] [[package]] @@ -1933,19 +1930,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" [[package]] -name = "nom8" -version = "0.2.0" +name = "nom" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", + "minimal-lexical", +] + +[[package]] +name = "nonmax" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51" + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", ] [[package]] name = "num" -version = "0.4.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ "num-bigint", "num-complex", @@ -1957,50 +1971,64 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.3" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "autocfg", "num-integer", "num-traits", ] [[package]] -name = "num-complex" -version = "0.4.3" +name = "num-bigint-dig" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ "num-traits", ] [[package]] -name = "num-derive" -version = "0.3.3" +name = "num-format" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" dependencies = [ - "proc-macro2", - "quote", - "syn", + "arrayvec", + "itoa", ] [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", @@ -2009,11 +2037,10 @@ dependencies = [ [[package]] name = "num-rational" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "autocfg", "num-bigint", "num-integer", "num-traits", @@ -2021,199 +2048,103 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" -dependencies = [ - "hermit-abi 0.2.6", - "libc", + "libm", ] [[package]] name = "object" -version = "0.30.3" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.17.0" +version = "1.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" [[package]] -name = "opaque-debug" -version = "0.3.0" +name = "overload" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "openssl" -version = "0.10.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7" -dependencies = [ - "autocfg", - "cc", - "libc", - "pkg-config", - "vcpkg", -] +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "parking" -version = "2.0.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core 0.9.7", + "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.8.6" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", - "instant", "libc", "redox_syscall", "smallvec", - "winapi", + "windows-targets", ] [[package]] -name = "parking_lot_core" -version = "0.9.7" +name = "pem-rfc7468" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" -dependencies = [ - "backtrace", - "cfg-if", - "libc", - "petgraph", - "redox_syscall", - "smallvec", - "thread-id", - "windows-sys 0.45.0", -] - -[[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" dependencies = [ "base64ct", - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest 0.10.6", - "hmac", - "password-hash", - "sha2 0.10.6", ] [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "petgraph" -version = "0.6.2" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ - "fixedbitset", + "fixedbitset 0.4.2", "indexmap", ] [[package]] name = "pin-project" -version = "1.0.12" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +checksum = "dfe2e71e1471fe07709406bf725f710b02927c9c54b2b5b2ec0e8087d97c327d" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.12" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +checksum = "f6e859e6e5bd50440ab63c47e3ebabc90f26251f7c73c3d3e837b74a1cc3fa67" dependencies = [ "proc-macro2", "quote", @@ -2222,9 +2153,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -2233,10 +2164,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] -name = "pkcs7" -version = "0.3.0" +name = "pkcs1" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f7364e6d0e236473de91e042395d71e0e64715f99a60620b014a4a4c7d1619b" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ "der", "spki", @@ -2244,101 +2186,99 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.26" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" - -[[package]] -name = "poly1305" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede" -dependencies = [ - "cpufeatures", - "opaque-debug", - "universal-hash", -] +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "priority-queue" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca9c6be70d989d21a136eb86c2d83e4b328447fac4a88dace2143c179c86267" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "autocfg", - "indexmap", + "zerocopy", ] [[package]] -name = "proc-macro-crate" -version = "1.3.0" +name = "prettyplease" +version = "0.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34" +checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" dependencies = [ - "once_cell", - "toml_edit", + "proc-macro2", + "syn", ] [[package]] name = "proc-macro2" -version = "1.0.50" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] [[package]] -name = "prost" +name = "quinn" version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21dc42e00223fc37204bd4aa177e69420c604ca4a183209a8f9de30c6d934698" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" dependencies = [ "bytes", - "prost-derive", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.1.1", + "rustls", + "socket2", + "thiserror 2.0.11", + "tokio", + "tracing", ] [[package]] -name = "prost-derive" -version = "0.11.6" +name = "quinn-proto" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda8c0881ea9f722eb9629376db3d0b903b462477c1aafcb0566610ac28ac5d" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn", + "bytes", + "getrandom", + "rand", + "ring", + "rustc-hash 2.1.1", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.11", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e46f3055866785f6b92bc6164b76be02ca8f2eb4b002c0354b28cf4c119e5944" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", ] [[package]] name = "quote" -version = "1.0.23" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", -] - [[package]] name = "rand" version = "0.8.5" @@ -2346,18 +2286,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", + "rand_chacha", + "rand_core", ] [[package]] @@ -2367,16 +2297,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", + "rand_core", ] [[package]] @@ -2385,88 +2306,138 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.8", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", + "getrandom", ] [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.7.1" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.5", ] [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] -name = "remove_dir_all" -version = "0.5.3" +name = "regex-syntax" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.11.14" +version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9" +checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" dependencies = [ - "base64 0.21.0", + "base64", "bytes", - "encoding_rs", "futures-core", "futures-util", - "h2", "http", "http-body", + "http-body-util", "hyper", - "hyper-tls", + "hyper-rustls", + "hyper-util", "ipnet", "js-sys", "log", "mime", - "native-tls", "once_cell", "percent-encoding", "pin-project-lite", + "quinn", + "rustls", + "rustls-pemfile", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", "tokio", - "tokio-native-tls", + "tokio-rustls", + "tower", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "winreg", + "webpki-roots", + "windows-registry", +] + +[[package]] +name = "ring" +version = "0.17.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e75ec5e92c4d8aede845126adc388046234541629e76029599ed35a003c7ed24" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rsa" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47c75d7c5c6b673e58bf54d8544a9f432e3a925b0e80f7cd3602ab5c50c55519" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "sha2", + "signature", + "spki", + "subtle", + "zeroize", ] [[package]] @@ -2476,194 +2447,118 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3e9243a1f8b312c5535c09de102cc061416515201b194ee4f0a9a76da20ebf4" dependencies = [ "num", - "rand 0.8.5", + "rand", "simple_asn1", ] [[package]] -name = "ruma" -version = "0.7.4" +name = "rustc-demangle" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dc348e3a4a18abc4e97fffa5e2e623f6edd50ba3a1dd5f47eb249fea713b69f" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "assign", - "js_int", - "js_option", - "ruma-client-api", - "ruma-common", - "ruma-federation-api", + "semver", ] [[package]] -name = "ruma-client-api" -version = "0.15.3" +name = "rustls" +version = "0.23.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1e72bc731b4dc8b569aa83915f13e419144b67110d858c65bb74aa05e2dc4b7" -dependencies = [ - "assign", - "bytes", - "http", - "js_int", - "maplit", - "percent-encoding", - "ruma-common", - "serde", - "serde_json", -] - -[[package]] -name = "ruma-common" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "716889595f4edc3cfeb94d9f122e413f73e37d7d80ea1c14196e1004241a3889" -dependencies = [ - "base64 0.13.1", - "bytes", - "form_urlencoded", - "getrandom 0.2.8", - "http", - "indexmap", - "itoa", - "js-sys", - "js_int", - "js_option", - "percent-encoding", - "rand 0.8.5", - "regex", - "ruma-identifiers-validation", - "ruma-macros", - "serde", - "serde_json", - "thiserror", - "tracing", - "url", - "uuid 1.3.0", - "wildmatch", -] - -[[package]] -name = "ruma-federation-api" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f905d12f6144c7a754bd0339fa6893698c03d03a908abb20cc6eeb4ec7f9466" -dependencies = [ - "js_int", - "ruma-common", - "serde", - "serde_json", -] - -[[package]] -name = "ruma-identifiers-validation" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabac62d16465a87435579c779d74dceabb93b09e44c766af6085050f3cc4275" -dependencies = [ - "js_int", - "thiserror", -] - -[[package]] -name = "ruma-macros" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f82e91eb61cd86d9287303133ee55b54618eccb75a522cc22a42c15f5bda340" +checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395" dependencies = [ "once_cell", - "proc-macro-crate", - "proc-macro2", - "quote", - "ruma-identifiers-validation", - "serde", - "syn", - "toml", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", ] [[package]] -name = "rustc-demangle" -version = "0.1.21" +name = "rustls-pemfile" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +dependencies = [ + "web-time", +] + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] [[package]] name = "rustversion" -version = "1.0.11" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "ryu" -version = "1.0.12" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" - -[[package]] -name = "schannel" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" -dependencies = [ - "windows-sys 0.42.0", -] +checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "scratch" -version = "1.0.3" +name = "semver" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" - -[[package]] -name = "security-framework" -version = "2.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" -dependencies = [ - "core-foundation-sys", - "libc", -] +checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" [[package]] name = "serde" -version = "1.0.152" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] -[[package]] -name = "serde_bytes" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718dc5fff5b36f99093fc49b280cfc96ce6fc824317783bff5a1fed0c7a64819" -dependencies = [ - "serde", -] - [[package]] name = "serde_derive" -version = "1.0.152" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", @@ -2672,11 +2567,12 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.91" +version = "1.0.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -2701,38 +2597,84 @@ checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.6", + "digest", ] [[package]] name = "sha2" -version = "0.9.9" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ - "block-buffer 0.9.0", "cfg-if", "cpufeatures", - "digest 0.9.0", - "opaque-debug", + "digest", ] [[package]] -name = "sha2" -version = "0.10.6" +name = "sharded-slab" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.6", + "lazy_static", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signature" -version = "1.6.4" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "simd_cesu8" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c14f02c32cc4ef5068b0e15bee4513942f59165add7778a518b4d507b3b97ab" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdnbt" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960b88bb7ea0984fbba94e53f1a2181ba6654e68a0eb53e45843e0eed402f10e" +dependencies = [ + "byteorder", + "flate2", + "simd_cesu8", + "simdnbt-derive", + "thiserror 2.0.11", +] + +[[package]] +name = "simdnbt-derive" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd1fe91ba0e4ee5cd6e565153b363fe06b19357ce9af07cc54371c450275d26e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "simple_asn1" @@ -2743,95 +2685,97 @@ dependencies = [ "chrono", "num-bigint", "num-traits", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "slab" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] -name = "sled" -version = "0.34.7" +name = "smallvec" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f96b4737c2ce5987354855aed3797279def4ebf734436c6aa4552cf8e169935" -dependencies = [ - "crc32fast", - "crossbeam-epoch", - "crossbeam-utils", - "fs2", - "fxhash", - "libc", - "log", - "parking_lot 0.11.2", -] +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" [[package]] -name = "smallvec" -version = "1.10.0" +name = "smol_str" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +dependencies = [ + "serde", +] [[package]] name = "socket2" -version = "0.4.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", - "winapi", + "windows-sys 0.52.0", ] [[package]] -name = "spki" -version = "0.5.4" +name = "socks5-impl" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" +checksum = "16c081d915d229c8e86edd9bfc784fbbee0e9ae6f2a338d791b22c5ec45dc00f" dependencies = [ + "as-any", + "async-trait", + "byteorder", + "bytes", + "percent-encoding", + "thiserror 2.0.11", + "tokio", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", "der", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "strum" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" - -[[package]] -name = "strum_macros" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn", -] +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" -version = "2.4.1" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "1.0.107" +version = "2.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" dependencies = [ "proc-macro2", "quote", @@ -2839,54 +2783,48 @@ dependencies = [ ] [[package]] -name = "synstructure" -version = "0.12.6" +name = "sync_wrapper" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", "syn", - "unicode-xid", -] - -[[package]] -name = "tempfile" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" -dependencies = [ - "cfg-if", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", -] - -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", ] [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +dependencies = [ + "thiserror-impl 2.0.11", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", @@ -2894,32 +2832,50 @@ dependencies = [ ] [[package]] -name = "thread-id" -version = "4.0.0" +name = "thiserror-impl" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fdfe0627923f7411a43ec9ec9c39c3a9b4151be313e0922042581fb6c9b717f" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" dependencies = [ - "libc", - "redox_syscall", - "winapi", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "time" -version = "0.1.45" +name = "thread_local" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", + "cfg-if", + "once_cell", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", ] [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" dependencies = [ "tinyvec_macros", ] @@ -2932,27 +2888,25 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.25.0" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" +checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" dependencies = [ - "autocfg", + "backtrace", "bytes", "libc", - "memchr", "mio", - "num_cpus", "pin-project-lite", "socket2", "tokio-macros", - "windows-sys 0.42.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "1.8.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", @@ -2960,68 +2914,78 @@ dependencies = [ ] [[package]] -name = "tokio-native-tls" -version = "0.3.0" +name = "tokio-rustls" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" dependencies = [ - "native-tls", + "rustls", "tokio", ] [[package]] name = "tokio-util" -version = "0.7.4" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", - "tracing", -] - -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", ] [[package]] name = "toml_datetime" -version = "0.5.1" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" -version = "0.18.1" +version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ "indexmap", - "nom8", "toml_datetime", + "winnow", ] [[package]] -name = "tower-service" -version = "0.3.2" +name = "tower" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -3029,9 +2993,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", @@ -3040,212 +3004,166 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", + "valuable", ] [[package]] -name = "trust-dns-proto" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f7f83d1e4a0e4358ac54c5c3681e5d7da5efc5a7a632c90bb6d6669ddd9bc26" -dependencies = [ - "async-trait", - "cfg-if", - "data-encoding", - "enum-as-inner", - "futures-channel", - "futures-io", - "futures-util", - "idna 0.2.3", - "ipnet", - "lazy_static", - "rand 0.8.5", - "smallvec", - "thiserror", - "tinyvec", - "tokio", - "tracing", - "url", -] - -[[package]] -name = "trust-dns-resolver" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aff21aa4dcefb0a1afbfac26deb0adc93888c7d295fb63ab273ef276ba2b7cfe" -dependencies = [ - "cfg-if", - "futures-util", - "lazy_static", - "lru-cache", - "parking_lot 0.12.1", - "smallvec", - "thiserror", - "tokio", - "tracing", - "trust-dns-proto", -] - -[[package]] -name = "try-lock" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" - -[[package]] -name = "typemap_rev" +name = "tracing-log" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fc45e9608894c9fefd9792d880560280086d73a4d8c8cb7436f27ca98550fb5" - -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "unicode-bidi" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58" - -[[package]] -name = "unicode-ident" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ - "tinyvec", + "log", + "once_cell", + "tracing-core", ] [[package]] -name = "unicode-width" -version = "0.1.10" +name = "tracing-oslog" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "universal-hash" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +checksum = "528bdd1f0e27b5dd9a4ededf154e824b0532731e4af73bb531de46276e0aab1e" dependencies = [ - "generic-array", - "subtle", + "bindgen", + "cc", + "cfg-if", + "once_cell", + "parking_lot", + "tracing-core", + "tracing-subscriber", ] [[package]] -name = "url" -version = "2.3.1" +name = "tracing-subscriber" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ - "form_urlencoded", - "idna 0.3.0", - "percent-encoding", + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", ] [[package]] -name = "uuid" -version = "0.8.2" +name = "tracing-wasm" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +checksum = "4575c663a174420fa2d78f4108ff68f65bf2fbb7dd89f33749b6e826b3626e07" dependencies = [ - "getrandom 0.2.8", -] - -[[package]] -name = "uuid" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79" -dependencies = [ - "getrandom 0.2.8", + "tracing", + "tracing-subscriber", "wasm-bindgen", ] [[package]] -name = "vcpkg" -version = "0.2.15" +name = "try-lock" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typeid" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" +dependencies = [ + "getrandom", + "md-5", + "serde", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "vodozemac" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f20153a1c82ac5f1243b62e80f067ae608facc415c6ef82f88426a61c79886" -dependencies = [ - "aes", - "arrayvec", - "base64 0.13.1", - "cbc", - "ed25519-dalek", - "hkdf", - "hmac", - "pkcs7", - "prost", - "rand 0.7.3", - "serde", - "serde_json", - "sha2 0.10.6", - "subtle", - "thiserror", - "x25519-dalek", - "zeroize", -] - -[[package]] -name = "waker-fn" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -3254,25 +3172,24 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", - "serde", - "serde_json", + "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", "syn", @@ -3281,21 +3198,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.34" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3303,9 +3221,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", @@ -3316,40 +3234,41 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" - -[[package]] -name = "wasm-timer" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" dependencies = [ - "futures", - "js-sys", - "parking_lot 0.11.2", - "pin-utils", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", + "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.61" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] -name = "wildmatch" -version = "2.1.1" +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee583bdc5ff1cf9db20e9db5bb3ff4c3089a8f6b8b31aff265c9aba85812db86" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.26.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" +dependencies = [ + "rustls-pki-types", +] [[package]] name = "winapi" @@ -3367,15 +3286,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -3383,38 +3293,63 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows-sys" -version = "0.42.0" +name = "windows-registry" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows-result", + "windows-strings", + "windows-targets", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets", ] [[package]] name = "windows-sys" -version = "0.45.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", + "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", @@ -3423,84 +3358,163 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "winreg" -version = "0.10.1" +name = "winnow" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "59690dea168f2198d1a3b0cac23b8063efcd11012f10ae4698f284808c8ef603" dependencies = [ - "winapi", + "memchr", ] [[package]] -name = "x25519-dalek" -version = "1.2.0" +name = "write16" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2392b6b94a576b4e2bf3c5b2757d63f10ada8020a2e4d08ac849ebcf6ea8e077" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ - "curve25519-dalek", - "rand_core 0.5.1", "serde", - "zeroize", + "stable_deref_trait", + "yoke-derive", + "zerofrom", ] [[package]] -name = "zeroize" -version = "1.3.0" +name = "yoke-derive" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", "syn", "synstructure", ] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index 641d81b..5b731f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,27 +1,25 @@ [package] name = "errornowatcher" -version = "0.1.0" -edition = "2021" - -[dependencies] -azalea = "0.5.0" -azalea-protocol = "0.5.0" -azalea-block = "0.5.0" -azalea-core = "0.5.0" -toml = "0.5.10" -serde = { version = "1.0", features = ["derive"] } -tokio = { version = "1.24.2", features = ["macros", "rt-multi-thread"] } -anyhow = "1.0.68" -colored = "2.0.0" -chrono = "0.4.23" -strum = "0.24.1" -strum_macros = "0.24.1" -async-recursion = "1.0.0" -rand = "0.8.5" -matrix-sdk = "0.6.2" +version = "0.2.0" +edition = "2024" [profile.dev] opt-level = 1 [profile.dev.package."*"] opt-level = 3 + +[profile.release] +codegen-units = 1 +lto = true +panic = "abort" +strip = true + +[dependencies] +anyhow = "1" +azalea = { git = "https://github.com/azalea-rs/azalea.git" } +clap = { version = "4", features = ["derive"] } +futures = "0" +mlua = { version = "0", features = ["async", "luau", "send"] } +parking_lot = { version = "0" } +tokio = { version = "1", features = ["macros"] } diff --git a/README.md b/README.md deleted file mode 100644 index 240e800..0000000 --- a/README.md +++ /dev/null @@ -1,71 +0,0 @@ -

- -

ErrorNoWatcher

-

- ErrorNoWatcher is a Minecraft bot (written in Rust with azalea) that alerts you when players are near your base. You can customize the size and location of your base, change the players that will receive a private message in-game, and even run custom shell commands! It also has other features such as an entity finder, a pathfinder that can follow players and go to coordinates, the ability to interact with blocks, a scripting system to run commands from a file, the ability to accept and respond to commands from Matrix, and much more. -

-

- -## Compiling -```sh -git clone https://github.com/ErrorNoInternet/ErrorNoWatcher -cd ErrorNoWatcher -cargo build --release -``` -The compiled executable can be found at `./target/release/errornowatcher` - -## Usage -### Configuration -Running the bot will create the `bot_configuration.toml` file, where you can change several options: -```toml -username = "" # offline username -server_address = "" -register_keyword = "Register using" -register_command = "register MyPassword MyPassword" -login_keyword = "Login using" -login_command = "login MyPassword" -bot_owners = ["ErrorNoInternet", ""] -whitelist = [ - "ErrorNoInternet", - "" -] -alert_players = ["ErrorNoInternet", ""] -alert_location = [0, 0] # coordinates of your base (X and Y position) -alert_radius = 192 # the radius of your base (-192, -192 to 192, 192) -alert_command = [ - "curl", - "-s", - "-m 5", - "-HTitle: Intruder Alert", - "-HPriority: urgent", - "-HTags: warning", - "-d{player_name} is near your base! Their coordinates are {x} {y} {z}.", - "" -] -alert_pause_time = 5 # the amount of seconds to wait between alert messages -cleanup_interval = 300 # the amount of seconds to wait before checking for idle entities -mob_expiry_time = 300 # the maximum amount of time a mob can stay idle before getting cleared -mob_packet_drop_level = 5 # the amount of mob packets to drop (0 = 0%, 5 = 50%, 10 = 100%) - -[matrix] -enabled = false -homeserver_url = "https://matrix.example.com" -username = "errornowatcher" -password = "MyMatrixPassword" -bot_owners = ["@zenderking:envs.net", ""] -``` -### Example commands -- `/msg ErrorNoWatcher help 1` - list the first page of usable commands -- `/msg ErrorNoWatcher bot_status` - display the bot's health, food & saturation levels, etc -- `/msg ErrorNoWatcher goto 20 64 10` - go to X20 Y64 Z10 (using the pathfinder) -- `/msg ErrorNoWatcher script sleep.txt` - run all commands in the file `sleep.txt` -- `/msg ErrorNoWatcher attack ErrorNoInternet` - attack the player named ErrorNoInternet -- `/msg ErrorNoWatcher look 180 0` - rotate the bot's head to 180 (yaw) 0 (pitch) -- `/msg ErrorNoWatcher whitelist_add Notch` - temporarily add Notch to the whitelist -- `/msg ErrorNoWatcher sprint forward 5000` - sprint forward for 5 seconds -- `/msg ErrorNoWatcher drop_item` - drop the currently held item (or `drop_stack`) -- `/msg ErrorNoWatcher last_location 1` - show the first page of players sorted by join time -- `/msg ErrorNoWatcher last_location ErrorNoInternet` - display the last seen location -- `/msg ErrorNoWatcher follow_player ErrorNoInternet` - start following ErrorNoInternet -- `/msg ErrorNoWatcher slot 1` - switch to the first inventory slot (hold the item) -- `/msg ErrorNoWatcher place_block 0 64 2 top` - places a block on top of the block at 0 64 2 diff --git a/images/icon.png b/images/icon.png deleted file mode 100644 index 7f9044cfe56e6f56b552268c8e3ced99dfcb124d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6697 zcmeHLc{r5)*S|-UP(n%@(@1$__Awiy7-Gnhl$4&#a*xI`!^~iWLW>p^DwW4t`XQyP z*$Qb#BE9Ic zrLbLJWz<76Pu|wtB(Ca1LQ|#TE+zJ{J!yirX8flEl||7u28N3tjt`gqRql(?Sd?X2 z)b%vHYRw`_s>YF^v=26sv`d|StFDjL6uGKu(IYly&wO*etvz3*c6n-g{l2>c@N(1r zpK^7G^pm;^qO=lsEI4>_>GR<*)HL2c|01nXkz#ROVQb8uVSGDcJpXD`@8DzI;0;*) zT0866Zk7`D=yw{rGnZUHq4&Pa_2cari&yt%s=xokp=ZB)!;B3hY9G(s?f$#dFE0xm zj;M~~T#+7a-}f=kz@t0aq}g|1$ltBy`HHj1k@hFSv&NzptXtL-?HQ<0kV~XifJIu_ zyI}>)hs;?D`R!5UX&e2+JqPryZn^5K)3fd44D`Ai?iD)1ENkj6TSXRMPS|Z`VuivD zR522-T4buHcu~MB*AFQt^4r(dzD8Dv^j4pCkHWmVoj&|}PwVZh)#5!TR=#Cv-}+IvUOO9m^WjVoR9O^t_LSL7%@x{G3&xz9 z%{M>4Bf8Jh(=0gO-QaaUROuabgVjIh`jO@<~JuhUg zt8(%za%iw*sgKdHB<0~I#od5gW!epCSDcjC78%CPt4-3!G z@rwJl?nx=qQFk}{aKBfPgH(OBk85QytN}(hq`IC<)tZ}sc$0C9bV1U=*{{Zr@ozQH zZy9npfv1<~7z}1NuXxnmxbJReV~DbqlWJwNOYnp+E{6F0EKdOF6T6W~E_U;z;b{;MuyNq+aOr9EQrSzOQ zcQDPXb=WU{pSEs5p#|Mya|7Dr|RTF<&kLn-BO|V;gUj)bfaP2 z3z;2{Zsk5Y-O3OS3Jk zdt)C1VC$LZ5k?9=rCsxbcO# zbBR@^vLLOFv`O_r`8n^MHN$@$za5c=QSg_9Ya5PU@M<-Cxy^5DS8QE@KH_>Fsyw>N z^xf&Fk*}I-(=Y5~oqD>N@FwR$Vr#ygYh!u?l5<|;lp$GAP%7#wIUmQv_1G%E&xqxl z+h!b9KPyr-+v;|CM?H9_BRroJJ0Djocj8@UnXgeDHY5_cm@;?Q$1J2*vL~3!8``l0 z<4vm4REm2^IOVfwah>sy_GcG;Ux@S-;KJi5|j$nM#rJ;4FbDwjSx3H`(q`tb;p7p5mrmM>g7qdB|Fh74k zCvl8=zpWCIRrXe*)7c`D^qa2Ue*84o|0ZB}DL&J}t(N0*vtnh4mZj>gIVVnowG1cq zqyc}27Uw{|*dxAVHTh&mrrZ@-=v{V!KNLD+7(`l4^c<_9D zCwD<)|70oVaet8YQ*1KLWI9s=fwq6g{mJ@U?vuulm7N{cLcsQyg~zaJyVCAhl0vve@Q{a3;;QkaY9&MRP60cz6S_RkFV|eP0srdtpIY^Yzhl% z1r~`#L=x~s43b5};gMXBMPPHd93v7L|1-Ksz!e8Fg`k-S#3RHN)Si=E!SyE#^~cZF zf!je@6(GWp7%cJ&VOSCsNBT+_`kzk`PaqRPJP`*qCf*21pg?`f#NhErCJE{rBMOTI zGMPUI{eMqU))UyDQ#3)##^Sf4nxOw%*}oV}nWGRjUu4jHhQ>Ym`@H|knQXHDgFj!} z?H}|2LH~C0OZ@((>o;A$#K12Z|L(5ebo~+ozhwNoyZ+zkQu^`62=bvn^a7#x!3^&N z73f`ZI?L9|0+^7kl&k5-AjwQ$YgZ8fC~L?*Fd#lb3lh!{Gwdv9bi$TQUy2u4pwZBO zO-mRSX3i36U!vLexh`5^xFsEy_H1&tjX`OFtrtQJy7yP5p^>K-^=WlBPP_Mo!0w zy>d-3zJH>8*rTJaxk<&C!zr9liEe9b?1GhqYgDMgJ{eb0Edd*_^?wt{eKl-J=W*3dF^MO`y4I6{>>U-t~)X#6m>Ey)J={L ztZxs+4+d-qi)k9?rzonxnp#xC5DIBB<&rC0RSF>ENJJ~#QA5n6V-)(xKFJwsAyTx1#5SWQ^xH^61f{luwbW zI`|KhH9d*766R;-_b zG!<2Ly)3r3MyF~#XZMH0<@~{tvA(2}&N6MEpjK6!hs<|Ze=j^}nz}O3DRz+_% zP=yUT;UG|7Wj#ln%Gop5C} zOn-Rv=8m)GnIVfd;pSzsGaU`uvg@Wj#b{@?ukq0a+?5&$%QKnydqEq*AS2aN1XLyy zcW-#n`pWi-+#H5UjbC;U9a5DkMlDRffnV4e|5<5us&kV3t*CXZ1&2hnadJ1@vbMsl z&zw3avZce6&b=2sJFmVBHSE&<>S7&UGU2bI=g!V?#!spfAHbP+v0~6a14;J=j|2$ z$ZJUBbwUGL-nGqCi%*d%@6gcXr_QL17{b% li;i1sa)8>~sso!l1oLM)@<9Qf4l$y diff --git a/src/arguments.rs b/src/arguments.rs new file mode 100644 index 0000000..eb075ab --- /dev/null +++ b/src/arguments.rs @@ -0,0 +1,10 @@ +use clap::Parser; +use std::path::PathBuf; + +/// A Minecraft utility bot +#[derive(Parser)] +pub struct Arguments { + /// Path to main Lua file + #[arg(short, long)] + pub script: Option, +} diff --git a/src/bot.rs b/src/bot.rs deleted file mode 100644 index b23c53c..0000000 --- a/src/bot.rs +++ /dev/null @@ -1,1104 +0,0 @@ -use crate::{logging::log_error, PlayerTimeData, State}; -use async_recursion::async_recursion; -use azalea::{ - pathfinder::BlockPosGoal, prelude::*, BlockPos, SprintDirection, Vec3, WalkDirection, -}; -use azalea_core::Direction; -use azalea_protocol::packets::game::{ - self, serverbound_interact_packet::InteractionHand, ServerboundGamePacket, -}; -use chrono::{Local, TimeZone}; -use std::{ - sync::Arc, - time::{SystemTime, UNIX_EPOCH}, -}; -use strum::IntoEnumIterator; -use strum_macros::EnumIter; - -#[derive(Debug, Clone, PartialEq, PartialOrd, EnumIter)] -pub enum Command { - Help, - Wait, - Online, - Location, - BotStatus, - Whitelist, - WhitelistAdd, - WhitelistRemove, - LastLocation, - LastOnline, - FollowPlayer, - StopFollowPlayer, - LookPlayer, - StopLookPlayer, - Goto, - StopGoto, - Say, - Slot, - UseItem, - Look, - Sneak, - Unsneak, - PlaceBlock, - InteractBlock, - InteractEntity, - Attack, - Jump, - Walk, - Sprint, - DropItem, - DropStack, - LeaveBed, - Script, - StopScript, - Latency, - MobLocations, - ToggleBotStatusMessages, - ToggleAlertMessages, - Unknown, -} - -#[async_recursion] -pub async fn process_command( - command: &String, - executor: &String, - client: &mut Client, - state: Arc, -) -> String { - let mut segments: Vec = command - .split(" ") - .map(|segment| segment.to_string()) - .collect(); - if segments.len() <= 0 { - return "Hmm... I was unable to parse your command!".to_string(); - }; - - let mut command = Command::Unknown; - match segments[0].to_lowercase().as_str() { - "help" => command = Command::Help, - "wait" | "sleep" | "pause" => command = Command::Wait, - "online" | "players" => command = Command::Online, - "location" | "position" | "coordinates" => command = Command::Location, - "bot_status" | "health" | "food" | "saturation" => command = Command::BotStatus, - "whitelist" => command = Command::Whitelist, - "whitelist_add" => command = Command::WhitelistAdd, - "whitelist_remove" => command = Command::WhitelistRemove, - "last_location" | "last_position" => command = Command::LastLocation, - "last_online" => command = Command::LastOnline, - "follow_player" => command = Command::FollowPlayer, - "stop_follow_player" => command = Command::StopFollowPlayer, - "look_player" => command = Command::LookPlayer, - "stop_look_player" => command = Command::StopLookPlayer, - "goto" => command = Command::Goto, - "stop_goto" => command = Command::StopGoto, - "say" => command = Command::Say, - "slot" => command = Command::Slot, - "use_item" => command = Command::UseItem, - "look" => command = Command::Look, - "sneak" | "shift" | "crouch" => command = Command::Sneak, - "unsneak" | "unshift" | "uncrouch" => command = Command::Unsneak, - "place_block" | "place" => command = Command::PlaceBlock, - "interact_block" => command = Command::InteractBlock, - "interact_entity" => command = Command::InteractEntity, - "attack" | "hit" => command = Command::Attack, - "jump" => command = Command::Jump, - "walk" => command = Command::Walk, - "sprint" => command = Command::Sprint, - "drop_item" | "throw_item" => command = Command::DropItem, - "drop_stack" | "throw_stack" => command = Command::DropStack, - "leave_bed" => command = Command::LeaveBed, - "script" | "run" => command = Command::Script, - "stop_script" | "stop_scripts" | "stop_run" => command = Command::StopScript, - "latency" | "ping" => command = Command::Latency, - "mob_locations" => command = Command::MobLocations, - "toggle_alert_messages" => command = Command::ToggleAlertMessages, - "toggle_bot_status_messages" => command = Command::ToggleBotStatusMessages, - _ => (), - }; - segments.remove(0); - let return_value = match command { - Command::Help => { - let mut page = 1; - if segments.len() > 0 { - page = segments[0].parse().unwrap_or(1) - } - if page < 1 { - page = 1 - } - - let mut commands = Vec::new(); - for command in Command::iter() { - if command != Command::Unknown { - commands.push(format!("{:?}", command)); - } - } - - let mut start_index = (page - 1) * 10; - let mut end_index = page * 10; - while start_index > commands.len() { - start_index -= 1 - } - while end_index > commands.len() { - end_index -= 1 - } - let paged_commands = &commands[start_index..end_index]; - return format!("Commands (page {}): {}", page, paged_commands.join(", ")); - } - Command::Wait => { - if segments.len() < 1 { - return "Please tell me how long to wait!".to_string(); - } - - let duration = match segments[0].parse() { - Ok(duration) => duration, - Err(error) => return format!("Unable to parse duration: {}", error), - }; - tokio::time::sleep(std::time::Duration::from_millis(duration)).await; - return format!("I have successfully slept for {} ms!", duration); - } - Command::Online => { - let mut page = 1; - if segments.len() > 0 { - page = segments[0].parse().unwrap_or(1) - } - if page < 1 { - page = 1 - } - - let players: Vec = client - .players - .read() - .values() - .map(|item| item.profile.name.to_owned()) - .collect(); - - let mut start_index = (page - 1) * 10; - let mut end_index = page * 10; - while start_index > players.len() { - start_index -= 1 - } - while end_index > players.len() { - end_index -= 1 - } - let paged_players = &players[start_index..end_index]; - return format!( - "Online players (page {}): {}", - page, - paged_players.join(", ") - ); - } - Command::Location => { - let world = client.world.read(); - let entity = match world.entity(client.entity_id.read().to_owned()) { - Some(entity) => entity, - None => return "Uh oh! An unknown error occurred!".to_string(), - }; - return format!( - "I am currently at {} {} {}!", - entity.last_pos.x as i32, entity.last_pos.y as i32, entity.last_pos.z as i32 - ); - } - Command::BotStatus => { - let bot_status = state.bot_status.lock().unwrap().to_owned(); - let metadata = client.metadata(); - return format!( - "Health: {:.1}/20.0, Food: {}/20, Saturation: {:.1}/20.0, Score: {}, Air Supply: {}", - bot_status.health, - bot_status.food, - bot_status.saturation, - metadata.score, - metadata.air_supply - ); - } - Command::Whitelist => { - let mut page = 1; - if segments.len() > 0 { - page = segments[0].parse().unwrap_or(1) - } - if page < 1 { - page = 1 - } - - let whitelist = state.whitelist.lock().unwrap(); - - let mut start_index = (page - 1) * 10; - let mut end_index = page * 10; - while start_index > whitelist.len() { - start_index -= 1 - } - while end_index > whitelist.len() { - end_index -= 1 - } - let paged_whitelist = &whitelist[start_index..end_index]; - return format!( - "Whitelisted players (page {}): {}", - page, - paged_whitelist.join(", ") - ); - } - Command::WhitelistAdd => { - if segments.len() < 1 { - return "Please tell me the name of a player!".to_string(); - } - - let mut whitelist = state.whitelist.lock().unwrap().to_vec(); - if whitelist.contains(&segments[0]) { - return format!("{} is already whitelisted!", segments[0]); - } - whitelist.push(segments[0].to_owned()); - *state.whitelist.lock().unwrap() = whitelist; - return format!( - "{} has been successfully added to the whitelist!", - segments[0] - ); - } - Command::WhitelistRemove => { - if segments.len() < 1 { - return "Please tell me the name of a player!".to_string(); - } - - let mut whitelist = state.whitelist.lock().unwrap().to_vec(); - if !whitelist.contains(&segments[0]) { - return format!("{} is not whitelisted!", segments[0]); - } - whitelist.remove( - whitelist - .iter() - .position(|item| *item == segments[0]) - .unwrap(), - ); - *state.whitelist.lock().unwrap() = whitelist; - return format!( - "{} has been successfully removed from the whitelist!", - segments[0] - ); - } - Command::LastLocation => { - if segments.len() < 1 { - return "Please tell me the name of a player!".to_string(); - } - - let player_locations = state.player_locations.lock().unwrap().to_owned(); - for (player, position_time_data) in player_locations { - if player.username == segments[0] || player.uuid.to_string() == segments[0] { - return format!( - "{} was last seen at {} {} {} ({})", - segments[0], - position_time_data.position[0], - position_time_data.position[1], - position_time_data.position[2], - Local - .timestamp_opt(position_time_data.time as i64, 0) - .unwrap() - .format("%Y/%m/%d %H:%M:%S") - ); - } - } - format!("I haven't seen {} move anywhere near me...", segments[0]) - } - Command::LastOnline => { - let mut page = 1; - if segments.len() > 0 { - if segments[0].parse::().is_ok() { - page = segments[0].parse().unwrap(); - if page < 1 { - page = 1 - } - } else { - for (player, player_time_data) in state.player_timestamps.lock().unwrap().iter() - { - if player == &segments[0] { - return format!( - "{} - last join: {}, last chat message: {}, last leave: {}", - segments[0], - if player_time_data.join_time != 0 { - Local - .timestamp_opt(player_time_data.join_time as i64, 0) - .unwrap() - .format("%Y/%m/%d %H:%M:%S") - .to_string() - } else { - "never".to_string() - }, - if player_time_data.chat_message_time != 0 { - Local - .timestamp_opt(player_time_data.chat_message_time as i64, 0) - .unwrap() - .format("%Y/%m/%d %H:%M:%S") - .to_string() - } else { - "never".to_string() - }, - if player_time_data.leave_time != 0 { - Local - .timestamp_opt(player_time_data.leave_time as i64, 0) - .unwrap() - .format("%Y/%m/%d %H:%M:%S") - .to_string() - } else { - "never".to_string() - }, - ); - } - } - return format!("I haven't seen {} online yet...", segments[0]); - } - } - - let mut sorted_player_time_data: Vec = state - .player_timestamps - .lock() - .unwrap() - .to_owned() - .values() - .map(|item| item.to_owned()) - .collect(); - sorted_player_time_data.sort_by(|a, b| b.join_time.cmp(&a.join_time)); - let mut player_timestamps = state.player_timestamps.lock().unwrap().to_owned(); - let mut players = Vec::new(); - for player_time_data in sorted_player_time_data { - for (player, original_player_time_data) in player_timestamps.to_owned().iter() { - if player_time_data == original_player_time_data.to_owned() { - players.push(player.to_owned()); - player_timestamps.remove(player); - break; - } - } - } - - let mut start_index = (page - 1) * 10; - let mut end_index = page * 10; - while start_index > players.len() { - start_index -= 1 - } - while end_index > players.len() { - end_index -= 1 - } - let paged_players = &players[start_index..end_index]; - return format!( - "Sorted by join time (page {}): {}", - page, - paged_players.join(", ") - ); - } - Command::FollowPlayer => { - if segments.len() < 1 { - return "Please tell me the name of a player!".to_string(); - }; - - let mut found = true; - let player_locations = state.player_locations.lock().unwrap().to_owned(); - for (player, _) in player_locations { - if player.username == segments[0] || player.uuid.to_string() == segments[0] { - found = true; - *state.followed_player.lock().unwrap() = Some(player.to_owned()); - } - } - if found { - return format!("I am now following {}!", segments[0]); - } else { - return format!("I was unable to find {}!", segments[0]); - } - } - Command::StopFollowPlayer => { - *state.followed_player.lock().unwrap() = None; - let current_position = client.entity().pos().to_owned(); - client.goto(BlockPosGoal { - pos: BlockPos { - x: current_position.x.round() as i32, - y: current_position.y.round() as i32, - z: current_position.z.round() as i32, - }, - }); - "I am no longer following anyone!".to_string() - } - Command::LookPlayer => { - if segments.len() < 1 { - return "Please tell me the name of a player!".to_string(); - }; - - let mut found = true; - let player_locations = state.player_locations.lock().unwrap().to_owned(); - for (player, _) in player_locations { - if player.username == segments[0] || player.uuid.to_string() == segments[0] { - found = true; - *state.looked_player.lock().unwrap() = Some(player.to_owned()); - } - } - if found { - return format!("I am now looking at {}!", segments[0]); - } else { - return format!("I was unable to find {}!", segments[0]); - } - } - Command::StopLookPlayer => { - *state.looked_player.lock().unwrap() = None; - "I am no longer looking at anyone!".to_string() - } - Command::Goto => { - if segments.len() < 3 { - return "Please give me X, Y, and Z coordinates to go to!".to_string(); - } - - let mut coordinates: Vec = Vec::new(); - for segment in segments { - coordinates.push(match segment.parse() { - Ok(number) => number, - Err(error) => return format!("Unable to parse coordinates: {}", error), - }) - } - client.goto(BlockPosGoal { - pos: BlockPos { - x: coordinates[0], - y: coordinates[1], - z: coordinates[2], - }, - }); - format!( - "I have found the path to {} {} {}!", - coordinates[0], coordinates[1], coordinates[2] - ) - } - Command::StopGoto => { - let current_position = client.entity().pos().to_owned(); - client.goto(BlockPosGoal { - pos: BlockPos { - x: current_position.x.round() as i32, - y: current_position.y.round() as i32, - z: current_position.z.round() as i32, - }, - }); - "I am no longer going anywhere!".to_string() - } - Command::Say => { - if segments.len() < 1 { - return "Please give me something to say!".to_string(); - } - - log_error(client.chat(segments.join(" ").as_str()).await); - "Successfully sent message!".to_string() - } - Command::Slot => { - if segments.len() < 1 { - return "Please give me a slot to set!".to_string(); - } - - log_error( - client - .write_packet(ServerboundGamePacket::SetCarriedItem( - game::serverbound_set_carried_item_packet::ServerboundSetCarriedItemPacket { - slot: match segments[0].parse::() { - Ok(number) => (number-1) as u16, - Err(error) => return format!("Unable to parse slot: {}", error), - }, - }, - )) - .await - ); - "I have successfully switched slots!".to_string() - } - Command::UseItem => { - log_error( - client - .write_packet(ServerboundGamePacket::UseItem( - game::serverbound_use_item_packet::ServerboundUseItemPacket { - hand: InteractionHand::MainHand, - sequence: 0, - }, - )) - .await, - ); - "I have successfully used the item!".to_string() - } - Command::Look => { - if segments.len() < 2 { - return "Please give me rotation vectors to look at!".to_string(); - } - - let mut rotation: Vec = Vec::new(); - for segment in segments { - rotation.push(match segment.parse() { - Ok(number) => number, - Err(error) => return format!("Unable to parse rotation: {}", error), - }) - } - client.set_rotation(rotation[0], rotation[1]); - format!("I am now looking at {} {}!", rotation[0], rotation[1]) - } - Command::Sneak => { - let entity_id = client.entity_id.read().to_owned(); - log_error( - client - .write_packet(ServerboundGamePacket::PlayerCommand( - game::serverbound_player_command_packet::ServerboundPlayerCommandPacket { - id: entity_id, - action: game::serverbound_player_command_packet::Action::PressShiftKey, - data: 0, - }, - )) - .await, - ); - return "I am now sneaking!".to_string(); - } - Command::Unsneak => { - let entity_id = client.entity_id.read().to_owned(); - log_error( - client - .write_packet(ServerboundGamePacket::PlayerCommand( - game::serverbound_player_command_packet::ServerboundPlayerCommandPacket { - id: entity_id, - action: - game::serverbound_player_command_packet::Action::ReleaseShiftKey, - data: 0, - }, - )) - .await, - ); - return "I am no longer sneaking!".to_string(); - } - Command::PlaceBlock => { - if segments.len() < 4 { - return "Please give me block coordinates, block faces, and optionally cursor positions to interact with!" - .to_string(); - } - - let mut coordinates: Vec = Vec::new(); - for segment in &segments[0..3] { - coordinates.push(match segment.parse() { - Ok(number) => number, - Err(error) => return format!("Unable to parse coordinates: {}", error), - }) - } - let block_face = match segments[3].to_lowercase().as_str() { - "up" | "top" => Direction::Up, - "down" | "bottom" => Direction::Down, - "north" => Direction::North, - "east" => Direction::East, - "south" => Direction::South, - "west" => Direction::West, - _ => return "Please give me a valid block face!".to_string(), - }; - let mut cursor_positions: Vec = Vec::new(); - if segments.len() >= 7 { - for segment in &segments[4..7] { - cursor_positions.push(match segment.parse() { - Ok(number) => number, - Err(error) => { - return format!("Unable to parse cursor positions: {}", error) - } - }) - } - } - if cursor_positions.len() == 0 { - cursor_positions = vec![0.5, 1.0, 0.5]; - } - log_error( - client - .write_packet(ServerboundGamePacket::UseItemOn( - game::serverbound_use_item_on_packet::ServerboundUseItemOnPacket { - hand: InteractionHand::MainHand, - block_hit: game::serverbound_use_item_on_packet::BlockHitResult { - block_pos: BlockPos { - x: coordinates[0], - y: coordinates[1], - z: coordinates[2], - }, - direction: block_face, - location: Vec3 { - x: cursor_positions[0] + coordinates[0] as f64, - y: cursor_positions[1] + coordinates[1] as f64, - z: cursor_positions[2] + coordinates[2] as f64, - }, - inside: false, - }, - sequence: 0, - }, - )) - .await, - ); - return "I have successfully interacted with the block!".to_string(); - } - Command::InteractBlock => { - if segments.len() < 4 { - return "Please give me block coordinates (and block faces) to interact with!" - .to_string(); - } - - let mut coordinates: Vec = Vec::new(); - for segment in &segments[0..3] { - coordinates.push(match segment.parse() { - Ok(number) => number, - Err(error) => return format!("Unable to parse coordinates: {}", error), - }) - } - let block_face = match segments[3].to_lowercase().as_str() { - "up" | "top" => Direction::Up, - "down" | "bottom" => Direction::Down, - "north" => Direction::North, - "east" => Direction::East, - "south" => Direction::South, - "west" => Direction::West, - _ => return "Please give me a valid block face!".to_string(), - }; - log_error( - client - .write_packet(ServerboundGamePacket::UseItemOn( - game::serverbound_use_item_on_packet::ServerboundUseItemOnPacket { - hand: InteractionHand::MainHand, - block_hit: game::serverbound_use_item_on_packet::BlockHitResult { - block_pos: BlockPos { - x: coordinates[0], - y: coordinates[1], - z: coordinates[2], - }, - direction: block_face, - location: Vec3 { - x: coordinates[0] as f64, - y: coordinates[1] as f64, - z: coordinates[2] as f64, - }, - inside: false, - }, - sequence: 0, - }, - )) - .await, - ); - return "I have successfully interacted with the block!".to_string(); - } - Command::InteractEntity => { - if segments.len() < 1 { - return "Please give me IDs to interact with!".to_string(); - } - let mut range = 4; - if segments.len() > 1 { - range = match segments[1].parse() { - Ok(range) => range, - Err(error) => return format!("Unable to parse range: {error}"), - }; - } - let mut max_time = 30; - if segments.len() > 2 { - max_time = match segments[2].parse() { - Ok(max_time) => max_time, - Err(error) => return format!("Unable to parse max time: {error}"), - }; - } - let current_time = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs(); - let entity_position = - match (client.world.read()).entity(client.entity_id.read().to_owned()) { - Some(entity) => entity.last_pos, - None => return "Uh oh! An unknown error occurred!".to_string(), - }; - - let mob_locations = state.mob_locations.lock().unwrap().to_owned(); - for (mob, position_time_data) in mob_locations { - if mob.id.to_string() == segments[0] - || mob.uuid == segments[0] - || mob.entity_type == segments[0] - { - if current_time - position_time_data.time > max_time { - continue; - } - if !(((position_time_data.position[0] - range as i32) - ..(position_time_data.position[0] + range as i32)) - .contains(&(entity_position.x as i32)) - && ((position_time_data.position[1] - range as i32) - ..(position_time_data.position[1] + range as i32)) - .contains(&(entity_position.y as i32)) - && ((position_time_data.position[2] - range as i32) - ..(position_time_data.position[2] + range as i32)) - .contains(&(entity_position.z as i32))) - { - continue; - } - - log_error( - client - .write_packet(ServerboundGamePacket::Interact( - game::serverbound_interact_packet::ServerboundInteractPacket { - action: - game::serverbound_interact_packet::ActionType::Interact { - hand: InteractionHand::MainHand, - }, - entity_id: mob.id, - using_secondary_action: false, - }, - )) - .await, - ); - return format!("Successfully interacted with {}!", mob.uuid); - } - } - let player_locations = state.player_locations.lock().unwrap().to_owned(); - for (player, position_time_data) in player_locations { - if player.entity_id.to_string() == segments[0] - || player.uuid == segments[0] - || player.username == segments[0] - { - if current_time - position_time_data.time > max_time { - continue; - } - if !(((position_time_data.position[0] - range as i32) - ..(position_time_data.position[0] + range as i32)) - .contains(&(entity_position.x as i32)) - && ((position_time_data.position[1] - range as i32) - ..(position_time_data.position[1] + range as i32)) - .contains(&(entity_position.y as i32)) - && ((position_time_data.position[2] - range as i32) - ..(position_time_data.position[2] + range as i32)) - .contains(&(entity_position.z as i32))) - { - continue; - } - - log_error( - client - .write_packet(ServerboundGamePacket::Interact( - game::serverbound_interact_packet::ServerboundInteractPacket { - action: - game::serverbound_interact_packet::ActionType::Interact { - hand: InteractionHand::MainHand, - }, - entity_id: player.entity_id, - using_secondary_action: false, - }, - )) - .await, - ); - return format!("Successfully interacted with {}!", player.username); - } - } - return "Unable to find entity!".to_string(); - } - Command::Attack => { - if segments.len() < 1 { - return "Please give me IDs to attack!".to_string(); - } - let mut range = 4; - if segments.len() > 1 { - range = match segments[1].parse() { - Ok(range) => range, - Err(error) => return format!("Unable to parse range: {error}"), - }; - } - let mut max_time = 30; - if segments.len() > 2 { - max_time = match segments[2].parse() { - Ok(max_time) => max_time, - Err(error) => return format!("Unable to parse max time: {error}"), - }; - } - let current_time = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs(); - let entity_position = - match (client.world.read()).entity(client.entity_id.read().to_owned()) { - Some(entity) => entity.last_pos, - None => return "Uh oh! An unknown error occurred!".to_string(), - }; - - let mob_locations = state.mob_locations.lock().unwrap().to_owned(); - for (mob, position_time_data) in mob_locations { - if mob.id.to_string() == segments[0] - || mob.uuid == segments[0] - || mob.entity_type == segments[0] - { - if current_time - position_time_data.time > max_time { - continue; - } - if !(((position_time_data.position[0] - range as i32) - ..(position_time_data.position[0] + range as i32)) - .contains(&(entity_position.x as i32)) - && ((position_time_data.position[1] - range as i32) - ..(position_time_data.position[1] + range as i32)) - .contains(&(entity_position.y as i32)) - && ((position_time_data.position[2] - range as i32) - ..(position_time_data.position[2] + range as i32)) - .contains(&(entity_position.z as i32))) - { - continue; - } - - log_error( - client - .write_packet(ServerboundGamePacket::Interact( - game::serverbound_interact_packet::ServerboundInteractPacket { - action: game::serverbound_interact_packet::ActionType::Attack, - entity_id: mob.id, - using_secondary_action: false, - }, - )) - .await, - ); - return format!("Successfully attacked {}!", mob.uuid); - } - } - let player_locations = state.player_locations.lock().unwrap().to_owned(); - for (player, position_time_data) in player_locations { - if player.entity_id.to_string() == segments[0] - || player.uuid == segments[0] - || player.username == segments[0] - { - if current_time - position_time_data.time > max_time { - continue; - } - if !(((position_time_data.position[0] - range as i32) - ..(position_time_data.position[0] + range as i32)) - .contains(&(entity_position.x as i32)) - && ((position_time_data.position[1] - range as i32) - ..(position_time_data.position[1] + range as i32)) - .contains(&(entity_position.y as i32)) - && ((position_time_data.position[2] - range as i32) - ..(position_time_data.position[2] + range as i32)) - .contains(&(entity_position.z as i32))) - { - continue; - } - - log_error( - client - .write_packet(ServerboundGamePacket::Interact( - game::serverbound_interact_packet::ServerboundInteractPacket { - action: game::serverbound_interact_packet::ActionType::Attack, - entity_id: player.entity_id, - using_secondary_action: false, - }, - )) - .await, - ); - return format!("Successfully attacked {}!", player.username); - } - } - return "Unable to find entity!".to_string(); - } - Command::Jump => { - client.jump(); - return "I have successfully jumped!".to_string(); - } - Command::Walk => { - if segments.len() < 2 { - return "Please give me a direction (and duration) to walk in!".to_string(); - } - - let direction = match segments[0].to_lowercase().as_str() { - "forward" => WalkDirection::Forward, - "forward_left" => WalkDirection::ForwardLeft, - "forward_right" => WalkDirection::ForwardRight, - "backward" => WalkDirection::Backward, - "backward_left" => WalkDirection::BackwardLeft, - "backward_right" => WalkDirection::BackwardRight, - "left" => WalkDirection::Left, - "right" => WalkDirection::Right, - _ => WalkDirection::None, - }; - let duration = match segments[1].parse() { - Ok(duration) => duration, - Err(error) => return format!("Unable to parse duration: {}", error), - }; - - client.walk(direction); - tokio::time::sleep(std::time::Duration::from_millis(duration)).await; - client.walk(WalkDirection::None); - return "I have finished walking!".to_string(); - } - Command::Sprint => { - if segments.len() < 2 { - return "Please give me a direction (and duration) to sprint in!".to_string(); - } - - let direction = match segments[0].to_lowercase().as_str() { - "forward" => SprintDirection::Forward, - "forward_left" => SprintDirection::ForwardLeft, - "forward_right" => SprintDirection::ForwardRight, - _ => return "Please give me a valid direction to sprint in!".to_string(), - }; - let duration = match segments[1].parse() { - Ok(duration) => duration, - Err(error) => return format!("Unable to parse duration: {}", error), - }; - - client.sprint(direction); - tokio::time::sleep(std::time::Duration::from_millis(duration)).await; - client.walk(WalkDirection::None); - return "I have finished sprinting!".to_string(); - } - Command::DropItem => { - log_error( - client - .write_packet(ServerboundGamePacket::PlayerAction( - game::serverbound_player_action_packet::ServerboundPlayerActionPacket { - action: game::serverbound_player_action_packet::Action::DropItem, - pos: BlockPos { x: 0, y: 0, z: 0 }, - direction: Default::default(), - sequence: 0, - }, - )) - .await, - ); - return "I have successfully dropped 1 item!".to_string(); - } - Command::DropStack => { - log_error( - client - .write_packet(ServerboundGamePacket::PlayerAction( - game::serverbound_player_action_packet::ServerboundPlayerActionPacket { - action: game::serverbound_player_action_packet::Action::DropAllItems, - pos: BlockPos { x: 0, y: 0, z: 0 }, - direction: Default::default(), - sequence: 0, - }, - )) - .await, - ); - return "I have successfully dropped 1 stack!".to_string(); - } - Command::LeaveBed => { - let entity_id = client.entity_id.read().to_owned(); - log_error( - client - .write_packet(ServerboundGamePacket::PlayerCommand( - game::serverbound_player_command_packet::ServerboundPlayerCommandPacket { - id: entity_id, - action: game::serverbound_player_command_packet::Action::StopSleeping, - data: 0, - }, - )) - .await, - ); - return "I am no longer sleeping!".to_string(); - } - Command::Script => { - if segments.len() < 1 { - return "Please give me a script file to run!".to_string(); - } - - let script = match std::fs::read_to_string(segments[0].to_owned()) { - Ok(script) => script, - Err(error) => return format!("Unable to read script: {}", error), - }; - for line in script.split("\n") { - if *state.stop_scripts.lock().unwrap() == true { - *state.stop_scripts.lock().unwrap() = false; - break; - } - process_command(&line.to_string(), &executor, client, state.clone()).await; - } - - return "Finished executing script!".to_string(); - } - Command::StopScript => { - *state.stop_scripts.lock().unwrap() = true; - return "Successfully told all executing scripts to stop!".to_string(); - } - Command::Latency => { - let mut player = &state.bot_configuration.username; - if segments.len() > 0 { - player = &segments[0] - } - - let players = client.players.read().to_owned(); - for (uuid, online_player) in players.iter().map(|item| item.to_owned()) { - if &online_player.profile.name == player - || &uuid.as_hyphenated().to_string() == player - { - return format!( - "{} has a latency of {} ms!", - online_player.profile.name, online_player.latency - ); - } - } - - return format!("{} was not found!", player); - } - Command::MobLocations => { - if segments.len() < 1 { - return "Please give me the ID or type of a mob!".to_string(); - } - let mut page = 1; - if segments.len() > 1 { - page = segments[1].parse().unwrap_or(1) - } - if page < 1 { - page = 1 - } - - let mut locations = Vec::new(); - for (entity, position_time_data) in state.mob_locations.lock().unwrap().to_owned() { - if entity.id.to_string() == segments[0] - || entity.uuid == segments[0] - || entity.entity_type == segments[0] - { - locations.push(format!( - "{}: {} {} {}", - entity.entity_type, - position_time_data.position[0], - position_time_data.position[1], - position_time_data.position[2], - )) - } - } - - let mut start_index = (page - 1) * 5; - let mut end_index = page * 5; - while start_index > locations.len() { - start_index -= 1 - } - while end_index > locations.len() { - end_index -= 1 - } - let paged_locations = &locations[start_index..end_index]; - return format!( - "Mob locations (page {}): {}", - page, - paged_locations.join(", ") - ); - } - Command::ToggleAlertMessages => { - if state.alert_players.lock().unwrap().contains(executor) { - let mut players = state.alert_players.lock().unwrap().to_vec(); - players.remove( - players - .iter() - .position(|item| *item == executor.to_owned()) - .unwrap(), - ); - *state.alert_players.lock().unwrap() = players; - "You will no longer be receiving alert messages!".to_string() - } else { - let mut players = state.alert_players.lock().unwrap().to_vec(); - players.push(executor.to_owned()); - *state.alert_players.lock().unwrap() = players; - "You will now be receiving alert messages!".to_string() - } - } - Command::ToggleBotStatusMessages => { - if state.bot_status_players.lock().unwrap().contains(executor) { - let mut players = state.bot_status_players.lock().unwrap().to_vec(); - players.remove( - players - .iter() - .position(|item| *item == executor.to_owned()) - .unwrap(), - ); - *state.bot_status_players.lock().unwrap() = players; - "You will no longer be receiving bot status messages!".to_string() - } else { - let mut players = state.bot_status_players.lock().unwrap().to_vec(); - players.push(executor.to_owned()); - *state.bot_status_players.lock().unwrap() = players; - "You will now be receiving bot status messages!".to_string() - } - } - _ => "".to_string(), - }; - if !return_value.is_empty() { - return return_value; - } - - "Sorry, I don't know what you mean...".to_string() -} diff --git a/src/commands.rs b/src/commands.rs new file mode 100644 index 0000000..6586894 --- /dev/null +++ b/src/commands.rs @@ -0,0 +1,101 @@ +use crate::State; +use azalea::{ + GameProfileComponent, brigadier::prelude::*, chat::ChatPacket, entity::metadata::Player, + prelude::*, +}; +use bevy_ecs::{entity::Entity, query::With}; +use parking_lot::Mutex; + +pub type Ctx<'a> = CommandContext>; + +pub struct CommandSource { + pub client: Client, + pub message: ChatPacket, + pub state: State, +} + +impl CommandSource { + pub fn reply(&self, message: &str) { + if self.message.is_whisper() + && let Some(username) = self.message.username() + { + self.client.chat(&format!("/w {username} {message}")); + } else { + self.client.chat(message); + } + } + + pub fn _entity(&mut self) -> Option { + let username = self.message.username()?; + self.client + .entity_by::, &GameProfileComponent>(|profile: &&GameProfileComponent| { + profile.name == username + }) + } +} + +pub fn register(commands: &mut CommandDispatcher>) { + commands.register(literal("reload").executes(|ctx: &Ctx| { + let source = ctx.source.lock(); + let lua = source.state.lua.lock(); + let config_path = match lua.globals().get::("config_path") { + Ok(path) => path, + Err(error) => { + source.reply(&format!( + "failed to get config_path from lua globals: {error:?}" + )); + return 0; + } + }; + if let Err(error) = match &std::fs::read_to_string(&config_path) { + Ok(string) => lua.load(string).exec(), + Err(error) => { + source.reply(&format!("failed to read {config_path:?}: {error:?}")); + return 0; + } + } { + source.reply(&format!( + "failed to execute configuration as lua code: {error:?}" + )); + return 0; + } + 1 + })); + + commands.register( + literal("eval").then(argument("expr", string()).executes(|ctx: &Ctx| { + let source = ctx.source.lock(); + source.reply(&format!( + "{:?}", + source + .state + .lua + .lock() + .load(get_string(ctx, "expr").unwrap()) + .eval::() + )); + 1 + })), + ); + + commands.register( + literal("exec").then(argument("code", string()).executes(|ctx: &Ctx| { + let source = ctx.source.lock(); + source.reply(&format!( + "{:?}", + source + .state + .lua + .lock() + .load(get_string(ctx, "code").unwrap()) + .exec() + )); + 1 + })), + ); + + commands.register(literal("ping").executes(|ctx: &Ctx| { + ctx.source.lock().reply("pong!"); + 1 + })); +} diff --git a/src/events.rs b/src/events.rs new file mode 100644 index 0000000..5a43029 --- /dev/null +++ b/src/events.rs @@ -0,0 +1,48 @@ +use crate::{State, commands::CommandSource, scripting}; +use azalea::prelude::*; +use mlua::Function; + +pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow::Result<()> { + let globals = state.lua.lock().globals(); + + match event { + Event::Chat(message) => { + println!("{}", message.message().to_ansi()); + + let owners = globals.get::>("OWNERS")?; + if message.is_whisper() + && let (Some(sender), content) = message.split_sender_and_content() + && owners.contains(&sender) + { + if let Err(error) = state.commands.execute( + content, + CommandSource { + client: client.clone(), + message: message.clone(), + state: state.clone(), + } + .into(), + ) { + CommandSource { + client, + message, + state, + } + .reply(&format!("{error:?}")); + }; + } + } + Event::Init => { + globals.set( + "client", + scripting::client::Client { + inner: Some(client), + }, + )?; + globals.get::("Init")?.call::<()>(())? + } + _ => (), + }; + + Ok(()) +} diff --git a/src/logging.rs b/src/logging.rs deleted file mode 100644 index 35644eb..0000000 --- a/src/logging.rs +++ /dev/null @@ -1,75 +0,0 @@ -use chrono::Local; -use colored::*; - -pub enum LogMessageType { - Bot, - Chat, - Matrix, - Error, - MatrixError, -} - -pub fn log_error(result: Result) { - match result { - Ok(_) => (), - Err(error) => log_message(LogMessageType::Error, &error.to_string()), - } -} - -pub fn log_message(message_type: LogMessageType, message: &String) { - match message_type { - LogMessageType::Bot => { - println!( - "{} {} {}", - current_time(), - colored_brackets(&"BOT".bold().blue()), - message - ) - } - LogMessageType::Chat => { - println!( - "{} {} {}", - current_time(), - colored_brackets(&"CHAT".bold().blue()), - message - ) - } - LogMessageType::Matrix => { - println!( - "{} {} {}", - current_time(), - colored_brackets(&"MATRIX".bold().green()), - message - ) - } - LogMessageType::Error => println!( - "{} {} {}", - current_time(), - colored_brackets(&"ERROR".bold().red()), - message.red() - ), - LogMessageType::MatrixError => println!( - "{} {} {}", - current_time(), - colored_brackets(&"ERROR (Matrix)".bold().red()), - message.red() - ), - } -} - -fn current_time() -> String { - format!( - "{}{}{}", - "[".bold().white(), - Local::now() - .format("%Y/%m/%d %H:%M:%S") - .to_string() - .bold() - .white(), - "]".bold().white() - ) -} - -fn colored_brackets(text: &ColoredString) -> String { - format!("{}{}{}", "[".bold().yellow(), text, "]".bold().yellow()) -} diff --git a/src/main.rs b/src/main.rs index bcb1fc7..fcf5314 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,660 +1,89 @@ -mod bot; -mod logging; -mod matrix; +#![feature(let_chains)] -use azalea::pathfinder::BlockPosGoal; -use azalea::{prelude::*, BlockPos, ClientInformation, Vec3}; -use azalea_protocol::packets::game::serverbound_client_command_packet::{ - Action::PerformRespawn, ServerboundClientCommandPacket, -}; -use azalea_protocol::packets::game::ClientboundGamePacket; -use azalea_protocol::ServerAddress; -use logging::LogMessageType::*; -use logging::{log_error, log_message}; -use matrix::login_and_sync; -use rand::Rng; -use serde::{Deserialize, Serialize}; -use std::collections::HashMap; -use std::sync::{Arc, Mutex}; -use std::time::{SystemTime, UNIX_EPOCH}; +mod arguments; +mod commands; +mod events; +mod scripting; -#[derive(Debug, Clone, Deserialize, Serialize)] -struct BotConfiguration { - username: String, - server_address: String, - register_keyword: String, - register_command: String, - login_keyword: String, - login_command: String, - bot_owners: Vec, - whitelist: Vec, - alert_players: Vec, - alert_location: Vec, - alert_radius: u32, - alert_command: Vec, - alert_pause_time: u32, - cleanup_interval: u32, - mob_expiry_time: u64, - mob_packet_drop_level: u8, - matrix: MatrixConfiguration, -} +use azalea::{brigadier::prelude::CommandDispatcher, prelude::*}; +use clap::Parser; +use commands::{CommandSource, register}; +use events::handle_event; +use mlua::Lua; +use parking_lot::Mutex; +use std::{path::PathBuf, process::ExitCode, sync::Arc}; -#[derive(Default, Debug, Clone, Deserialize, Serialize)] -pub struct MatrixConfiguration { - enabled: bool, - homeserver_url: String, - username: String, - password: String, - bot_owners: Vec, -} - -impl Default for BotConfiguration { - fn default() -> BotConfiguration { - BotConfiguration { - username: "ErrorNoWatcher".to_string(), - server_address: "localhost".to_string(), - register_keyword: "/register".to_string(), - register_command: "register 1VerySafePassword!!! 1VerySafePassword!!!".to_string(), - login_keyword: "/login".to_string(), - login_command: "login 1VerySafePassword!!!".to_string(), - bot_owners: vec![], - whitelist: vec![], - alert_players: vec![], - alert_location: vec![0, 0], - alert_radius: 100, - alert_command: Vec::new(), - alert_pause_time: 5, - cleanup_interval: 300, - mob_expiry_time: 300, - mob_packet_drop_level: 5, - matrix: MatrixConfiguration { - enabled: false, - homeserver_url: "https://matrix.example.com".to_string(), - username: "errornowatcher".to_string(), - password: "MyMatrixPassword".to_string(), - bot_owners: vec!["@zenderking:envs.net".to_string()], - }, - } - } +#[derive(Default, Clone, Component)] +pub struct State { + lua: Arc>, + commands: Arc>>, } #[tokio::main] -async fn main() { - let bot_configuration: BotConfiguration = match toml::from_str( - &std::fs::read_to_string("bot_configuration.toml").unwrap_or_default(), - ) { - Ok(bot_configuration) => bot_configuration, - Err(_) => { - let default_configuration = BotConfiguration::default(); - std::fs::copy("bot_configuration.toml", "bot_configuration.toml.bak") - .unwrap_or_default(); - match std::fs::write( - "bot_configuration.toml", - toml::to_string(&default_configuration).unwrap(), - ) { - Ok(_) => (), - Err(error) => { - log_message( - Error, - &format!("Unable to save configuration file: {}", error), - ); - return; - } - }; - default_configuration +async fn main() -> ExitCode { + let args = arguments::Arguments::parse(); + let lua = Lua::new(); + + let config_path = args.script.unwrap_or(PathBuf::from("errornowatcher.lua")); + if let Err(error) = match &std::fs::read_to_string(&config_path) { + Ok(string) => lua.load(string).exec(), + Err(error) => { + eprintln!("failed to read {config_path:?}: {error:?}"); + return ExitCode::FAILURE; } - }; - - let original_state = State { - client: Arc::new(Mutex::new(None)), - bot_configuration: bot_configuration.clone(), - whitelist: Arc::new(Mutex::new(bot_configuration.clone().whitelist)), - bot_status: Arc::new(Mutex::new(BotStatus::default())), - stop_scripts: Arc::new(Mutex::new(false)), - tick_counter: Arc::new(Mutex::new(0)), - alert_second_counter: Arc::new(Mutex::new(0)), - cleanup_second_counter: Arc::new(Mutex::new(0)), - followed_player: Arc::new(Mutex::new(None)), - looked_player: Arc::new(Mutex::new(None)), - player_locations: Arc::new(Mutex::new(HashMap::new())), - mob_locations: Arc::new(Mutex::new(HashMap::new())), - player_timestamps: Arc::new(Mutex::new(HashMap::new())), - alert_players: Arc::new(Mutex::new(bot_configuration.clone().alert_players)), - alert_queue: Arc::new(Mutex::new(HashMap::new())), - bot_status_players: Arc::new(Mutex::new(Vec::new())), - }; - let state = Arc::new(original_state); - - let matrix_configuration = bot_configuration.matrix.to_owned(); - if matrix_configuration.enabled { - log_message(Matrix, &"Matrix is enabled! Logging in...".to_string()); - tokio::spawn(login_and_sync(matrix_configuration, state.clone())); + } { + eprintln!("failed to execute configuration as lua code: {error:?}"); + return ExitCode::FAILURE; } - loop { - match azalea::start(azalea::Options { - account: Account::offline(&bot_configuration.username), - address: { - let segments: Vec = bot_configuration - .server_address - .split(":") - .map(|item| item.to_string()) - .collect(); - if segments.len() == 1 { - ServerAddress { - host: segments[0].to_owned(), - port: 25565, - } - } else if segments.len() == 2 { - ServerAddress { - host: segments[0].to_owned(), - port: segments[1].to_owned().parse().unwrap_or(25565), - } - } else { - log_message( - Error, - &"Unable to parse server address! Quitting...".to_string(), - ); - return; - } - }, - state: state.clone(), - plugins: plugins![], - handle, + let globals = lua.globals(); + let Ok(server) = globals.get::("SERVER") else { + eprintln!("no server defined in lua globals!"); + return ExitCode::FAILURE; + }; + let Ok(username) = globals.get::("USERNAME") else { + eprintln!("no username defined in lua globals!"); + return ExitCode::FAILURE; + }; + + if let Err(error) = globals.set("config_path", config_path) { + eprintln!("failed to set config_path in lua globals: {error:?}"); + return ExitCode::FAILURE; + }; + + let Ok(server) = globals.get::("Server") else { + eprintln!("no server defined in lua globals!"); + return ExitCode::FAILURE; + }; + let Ok(username) = globals.get::("Username") else { + eprintln!("no username defined in lua globals!"); + return ExitCode::FAILURE; + }; + + let account = if username.contains('@') { + match Account::microsoft(&username).await { + Ok(a) => a, + Err(error) => { + eprintln!("failed to login using microsoft account: {error:?}"); + return ExitCode::FAILURE; + } + } + } else { + Account::offline(&username) + }; + + let mut commands = CommandDispatcher::new(); + register(&mut commands); + + let Err(error) = ClientBuilder::new() + .set_handler(handle_event) + .set_state(State { + lua: Arc::new(Mutex::new(lua)), + commands: Arc::new(commands), }) - .await - { - Ok(_) => (), - Err(error) => log_message(Error, &format!("An error occurred: {}", error)), - } - log_message( - Bot, - &"ErrorNoWatcher has lost connection, reconnecting in 5 seconds...".to_string(), - ); - std::thread::sleep(std::time::Duration::from_secs(5)); - } -} - -#[derive(Eq, Hash, PartialEq, PartialOrd, Default, Debug, Clone)] -pub struct Player { - uuid: String, - entity_id: u32, - username: String, -} - -#[derive(Eq, Hash, PartialEq, PartialOrd, Default, Debug, Clone)] -pub struct Entity { - id: u32, - uuid: String, - entity_type: String, -} - -#[derive(Default, Debug, Clone)] -pub struct PositionTimeData { - position: Vec, - time: u64, -} - -#[derive(Eq, Hash, PartialEq, PartialOrd, Default, Debug, Clone)] -pub struct PlayerTimeData { - join_time: u64, - chat_message_time: u64, - leave_time: u64, -} - -#[derive(Default, Debug, Clone)] -pub struct BotStatus { - health: f32, - food: u32, - saturation: f32, -} - -#[derive(Clone)] -pub struct State { - client: Arc>>, - bot_configuration: BotConfiguration, - whitelist: Arc>>, - bot_status: Arc>, - stop_scripts: Arc>, - tick_counter: Arc>, - alert_second_counter: Arc>, - cleanup_second_counter: Arc>, - followed_player: Arc>>, - looked_player: Arc>>, - player_locations: Arc>>, - mob_locations: Arc>>, - player_timestamps: Arc>>, - alert_players: Arc>>, - alert_queue: Arc>>>, - bot_status_players: Arc>>, -} - -async fn handle(mut client: Client, event: Event, state: Arc) -> anyhow::Result<()> { - match event { - Event::Login => { - *state.client.lock().unwrap() = Some(client.clone()); - log_message( - Bot, - &"Successfully joined server, receiving initial data...".to_string(), - ); - log_error( - client - .set_client_information(ClientInformation { - view_distance: (state.bot_configuration.alert_radius as f32 / 16.0).ceil() - as u8, - ..Default::default() - }) - .await, - ); - } - Event::Death(_) => { - log_message( - Bot, - &"Player has died! Automatically respawning...".to_string(), - ); - client - .write_packet( - ServerboundClientCommandPacket { - action: PerformRespawn, - } - .get(), - ) - .await? - } - Event::AddPlayer(player) => { - let mut player_timestamps = state.player_timestamps.lock().unwrap().to_owned(); - let mut current_player = player_timestamps - .get(&player.profile.name) - .unwrap_or(&PlayerTimeData { - join_time: 0, - chat_message_time: 0, - leave_time: 0, - }) - .to_owned(); - current_player.join_time = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs(); - player_timestamps.insert(player.profile.name, current_player); - *state.player_timestamps.lock().unwrap() = player_timestamps; - } - Event::RemovePlayer(player) => { - let mut player_timestamps = state.player_timestamps.lock().unwrap().to_owned(); - let mut current_player = player_timestamps - .get(&player.profile.name) - .unwrap_or(&PlayerTimeData { - join_time: 0, - chat_message_time: 0, - leave_time: 0, - }) - .to_owned(); - current_player.leave_time = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs(); - player_timestamps.insert(player.profile.name, current_player); - *state.player_timestamps.lock().unwrap() = player_timestamps; - } - Event::Tick => { - *state.tick_counter.lock().unwrap() += 1; - if *state.tick_counter.lock().unwrap() >= 20 { - *state.tick_counter.lock().unwrap() = 0; - *state.alert_second_counter.lock().unwrap() += 1; - *state.cleanup_second_counter.lock().unwrap() += 1; - - let followed_player = state.followed_player.lock().unwrap().to_owned(); - if followed_player.is_some() { - let player_locations = state.player_locations.lock().unwrap().to_owned(); - match player_locations.get(&followed_player.unwrap()) { - Some(position_time_data) => client.goto(BlockPosGoal { - pos: BlockPos { - x: position_time_data.position[0], - y: position_time_data.position[1], - z: position_time_data.position[2], - }, - }), - None => (), - } - } - - let looked_player = state.looked_player.lock().unwrap().to_owned(); - if looked_player.is_some() { - let player_locations = state.player_locations.lock().unwrap().to_owned(); - match player_locations.get(&looked_player.unwrap()) { - Some(position_time_data) => client.look_at(&Vec3 { - x: position_time_data.position[0] as f64, - y: position_time_data.position[1] as f64, - z: position_time_data.position[2] as f64, - }), - None => (), - } - } - } - - if *state.alert_second_counter.lock().unwrap() as u32 - >= state.bot_configuration.alert_pause_time - { - *state.alert_second_counter.lock().unwrap() = 0; - - let alert_queue = state.alert_queue.lock().unwrap().to_owned(); - for (intruder, position) in alert_queue { - log_message( - Bot, - &format!( - "{} is in the specified alert radius at {} {} {}!", - intruder, position[0], position[1], position[2] - ), - ); - let alert_players = state.alert_players.lock().unwrap().to_vec(); - for alert_player in alert_players { - log_error( - client - .send_command_packet(&format!( - "msg {} {}", - alert_player, - format!( - "{} is near our base at {} {} {}!", - intruder, position[0], position[1], position[2], - ) - )) - .await, - ); - } - let mut alert_command = state.bot_configuration.alert_command.to_vec(); - for argument in alert_command.iter_mut() { - *argument = argument.replace("{player_name}", &intruder); - *argument = argument.replace("{x}", &(position[0]).to_string()); - *argument = argument.replace("{y}", &(position[1]).to_string()); - *argument = argument.replace("{z}", &(position[2]).to_string()); - } - if alert_command.len() >= 1 { - log_message(Bot, &"Executing alert shell command...".to_string()); - let command_name = alert_command[0].to_owned(); - alert_command.remove(0); - log_error( - std::process::Command::new(command_name) - .args(alert_command) - .stdin(std::process::Stdio::null()) - .stdout(std::process::Stdio::null()) - .stderr(std::process::Stdio::null()) - .spawn(), - ); - } - } - *state.alert_queue.lock().unwrap() = HashMap::new(); - } - - if *state.cleanup_second_counter.lock().unwrap() as u32 - >= state.bot_configuration.cleanup_interval - { - *state.cleanup_second_counter.lock().unwrap() = 0; - - log_message(Bot, &"Cleaning up mob locations...".to_string()); - let mut mob_locations = state.mob_locations.lock().unwrap().to_owned(); - let before_count = mob_locations.len(); - let current_time = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs(); - for (mob, position_time_data) in mob_locations.to_owned() { - if current_time - position_time_data.time - > state.bot_configuration.mob_expiry_time - { - mob_locations.remove(&mob); - } - } - let after_count = mob_locations.len(); - *state.mob_locations.lock().unwrap() = mob_locations; - - let removed_count = before_count - after_count; - let mut label = "mobs"; - if removed_count == 1 { - label = "mob"; - } - log_message( - Bot, - &format!( - "Successfully removed {} {} ({} -> {})", - removed_count, label, before_count, after_count - ), - ); - } - } - Event::Packet(packet) => match packet.as_ref() { - ClientboundGamePacket::AddEntity(packet) => { - if packet.entity_type.to_string() != "Player" { - let entity = Entity { - id: packet.id, - uuid: packet.uuid.as_hyphenated().to_string(), - entity_type: packet.entity_type.to_string().to_lowercase(), - }; - - let mut mob_locations = state.mob_locations.lock().unwrap().to_owned(); - mob_locations.insert( - entity, - PositionTimeData { - position: vec![packet.x as i32, packet.y as i32, packet.z as i32], - time: SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs(), - }, - ); - *state.mob_locations.lock().unwrap() = mob_locations; - } - } - ClientboundGamePacket::MoveEntityPos(packet) => { - let world = client.world.read(); - let raw_entity = match world.entity(packet.entity_id) { - Some(raw_entity) => raw_entity, - None => return Ok(()), - }; - let entity_type = format!("{:?}", raw_entity.metadata) - .split("(") - .map(|item| item.to_owned()) - .collect::>()[0] - .to_lowercase(); - if entity_type != "player" { - if rand::thread_rng().gen_range(0..10) + 1 - > 10 - state.bot_configuration.mob_packet_drop_level - { - return Ok(()); - } - } - let entity = Entity { - id: raw_entity.id, - uuid: raw_entity.uuid.as_hyphenated().to_string(), - entity_type: entity_type.to_owned(), - }; - let entity_position = raw_entity.pos(); - - if entity_type == "player" { - let players = client.players.read().to_owned(); - for (uuid, player) in players.iter().map(|item| item.to_owned()) { - if uuid.as_hyphenated().to_string() == entity.uuid { - let mut player_locations = - state.player_locations.lock().unwrap().to_owned(); - let username = player.profile.name.to_owned(); - for (player, _) in player_locations.to_owned() { - if player.username == username { - player_locations.remove(&player); - } - } - player_locations.insert( - Player { - uuid: uuid.as_hyphenated().to_string(), - entity_id: entity.id, - username, - }, - PositionTimeData { - position: vec![ - entity_position.x as i32, - entity_position.y as i32, - entity_position.z as i32, - ], - time: SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs(), - }, - ); - *state.player_locations.lock().unwrap() = player_locations; - - if ((state.bot_configuration.alert_location[0] - - state.bot_configuration.alert_radius as i32) - ..(state.bot_configuration.alert_location[0] - + state.bot_configuration.alert_radius as i32)) - .contains(&(entity_position.x as i32)) - && ((state.bot_configuration.alert_location[1] - - state.bot_configuration.alert_radius as i32) - ..(state.bot_configuration.alert_location[1] - + state.bot_configuration.alert_radius as i32)) - .contains(&(entity_position.z as i32)) - { - if !state - .whitelist - .lock() - .unwrap() - .contains(&player.profile.name) - { - let mut alert_queue = - state.alert_queue.lock().unwrap().to_owned(); - alert_queue.insert( - player.profile.name.to_owned(), - vec![ - entity_position.x as i32, - entity_position.y as i32, - entity_position.z as i32, - ], - ); - *state.alert_queue.lock().unwrap() = alert_queue; - } - } - } - } - } else { - let mut mob_locations = state.mob_locations.lock().unwrap().to_owned(); - mob_locations.insert( - entity, - PositionTimeData { - position: vec![ - entity_position.x as i32, - entity_position.y as i32, - entity_position.z as i32, - ], - time: SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs(), - }, - ); - *state.mob_locations.lock().unwrap() = mob_locations; - } - } - ClientboundGamePacket::SetHealth(packet) => { - *state.bot_status.lock().unwrap() = BotStatus { - health: packet.health, - food: packet.food, - saturation: packet.saturation, - }; - let bot_status_players: Vec = state - .bot_status_players - .lock() - .unwrap() - .iter() - .map(|item| item.to_owned()) - .collect(); - for player in bot_status_players { - log_error( - client - .send_command_packet(&format!( - "msg {} {}", - player, - format!( - "Health: {:.1}/20.0, Food: {}/20, Saturation: {:.1}/20.0", - packet.health, packet.food, packet.saturation - ), - )) - .await, - ); - } - } - _ => (), - }, - Event::Chat(message) => { - log_message(Chat, &message.message().to_ansi()); - - if message.username().is_none() { - if message - .content() - .contains(&state.bot_configuration.register_keyword) - { - log_message( - Bot, - &"Detected register keyword! Registering...".to_string(), - ); - log_error( - client - .send_command_packet(&state.bot_configuration.register_command) - .await, - ) - } else if message - .content() - .contains(&state.bot_configuration.login_keyword) - { - log_message(Bot, &"Detected login keyword! Logging in...".to_string()); - log_error( - client - .send_command_packet(&state.bot_configuration.login_command) - .await, - ) - } - return Ok(()); - } - - for bot_owner in state.bot_configuration.bot_owners.to_owned() { - if message - .message() - .to_string() - .starts_with(&format!("{} whispers to you: ", bot_owner)) - { - let command = message - .message() - .to_string() - .split("whispers to you: ") - .nth(1) - .unwrap_or("") - .to_string(); - - let return_value = - &bot::process_command(&command, &bot_owner, &mut client, state.clone()) - .await; - log_error( - client - .send_command_packet(&format!("msg {} {}", bot_owner, return_value)) - .await, - ); - } - - let mut player_timestamps = state.player_timestamps.lock().unwrap().to_owned(); - let mut current_player = player_timestamps - .get(&message.username().unwrap()) - .unwrap_or(&PlayerTimeData { - join_time: 0, - chat_message_time: 0, - leave_time: 0, - }) - .to_owned(); - current_player.chat_message_time = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs(); - player_timestamps.insert(message.username().unwrap(), current_player); - *state.player_timestamps.lock().unwrap() = player_timestamps; - } - } - _ => {} - } - - Ok(()) + .start(account, server.as_ref()) + .await; + eprintln!("{error:?}"); + + ExitCode::SUCCESS } diff --git a/src/matrix.rs b/src/matrix.rs deleted file mode 100644 index e5f98b5..0000000 --- a/src/matrix.rs +++ /dev/null @@ -1,150 +0,0 @@ -use crate::logging::{log_error, LogMessageType::*}; -use crate::{log_message, MatrixConfiguration, State}; -use matrix_sdk::config::SyncSettings; -use matrix_sdk::event_handler::Ctx; -use matrix_sdk::room::Room; -use matrix_sdk::ruma::events::room::message::{ - MessageType, OriginalSyncRoomMessageEvent, RoomMessageEventContent, -}; -use std::sync::Arc; - -#[derive(Clone)] -struct MatrixState { - bot_state: Arc, - matrix_configuration: MatrixConfiguration, - display_name: String, -} - -pub async fn login_and_sync(matrix_configuration: MatrixConfiguration, bot_state: Arc) { - loop { - let client_builder = - matrix_sdk::Client::builder().homeserver_url(&matrix_configuration.homeserver_url); - let client = match client_builder.build().await { - Ok(client) => client, - Err(error) => { - log_message(MatrixError, &format!("Unable to build client: {}", error)); - return; - } - }; - match client - .login_username( - &matrix_configuration.username, - &matrix_configuration.password, - ) - .device_id("ERRORNOWATCHER") - .initial_device_display_name("ErrorNoWatcher") - .send() - .await - { - Ok(_) => (), - Err(error) => { - log_message(MatrixError, &format!("Unable to login: {}", error)); - return; - } - }; - let response = match client.sync_once(SyncSettings::default()).await { - Ok(response) => response, - Err(error) => { - log_message(MatrixError, &format!("Unable to synchronize: {}", error)); - return; - } - }; - let display_name = match client.account().get_display_name().await { - Ok(display_name) => display_name.unwrap_or(match client.user_id() { - Some(user_id) => user_id.to_string(), - None => matrix_configuration.username.to_owned(), - }), - Err(error) => { - log_message( - MatrixError, - &format!("Unable to get display name: {}", error), - ); - return; - } - }; - log_message( - Matrix, - &format!("Successfully logged in as {}!", display_name), - ); - let matrix_state = MatrixState { - bot_state: bot_state.clone(), - matrix_configuration: matrix_configuration.clone(), - display_name, - }; - client.add_event_handler_context(matrix_state); - client.add_event_handler(room_message_handler); - let settings = SyncSettings::default().token(response.next_batch); - match client.sync(settings).await { - Ok(_) => (), - Err(error) => log_message(MatrixError, &format!("Unable to synchronize: {}", error)), - }; - } -} - -async fn room_message_handler( - event: OriginalSyncRoomMessageEvent, - room: Room, - state: Ctx, -) { - if let Room::Joined(room) = room { - let MessageType::Text(text_content) = event.content.msgtype else { - return; - }; - - if state - .matrix_configuration - .bot_owners - .contains(&event.sender.to_string()) - && text_content.body.starts_with(&state.display_name) - { - let bot_state = state.bot_state.clone(); - let client = bot_state.client.lock().unwrap().to_owned(); - let mut client = match client { - Some(client) => client, - None => { - log_error( - room.send( - RoomMessageEventContent::text_plain( - "I am still joining the Minecraft server!", - ), - None, - ) - .await, - ); - return; - } - }; - let command = text_content - .body - .trim_start_matches(&state.display_name) - .trim_start_matches(":") - .trim() - .to_string(); - log_message( - Matrix, - &format!( - "Executing command from {}: {}", - event.sender.to_string(), - command - ), - ); - tokio::task::spawn(async move { - log_error( - room.send( - RoomMessageEventContent::text_plain( - &crate::bot::process_command( - &command, - &event.sender.to_string(), - &mut client, - bot_state.clone(), - ) - .await, - ), - None, - ) - .await, - ); - }); - } - } -} diff --git a/src/scripting/client.rs b/src/scripting/client.rs new file mode 100644 index 0000000..cbe99bc --- /dev/null +++ b/src/scripting/client.rs @@ -0,0 +1,109 @@ +use super::position::{from_table, to_table}; +use azalea::{ + BlockPos, Client as AzaleaClient, ClientInformation, + ecs::query::Without, + entity::{Dead, EntityKind, EntityUuid, Position, metadata::CustomName}, + pathfinder::goals::BlockPosGoal, + prelude::PathfinderClientExt, + world::MinecraftEntityId, +}; +use mlua::{Error, Function, Lua, Result, Table, UserData, UserDataRef}; + +pub struct Client { + pub inner: Option, +} + +impl UserData for Client { + fn add_fields>(fields: &mut F) { + fields.add_field_method_get("pos", |lua, this| { + let pos = this.inner.as_ref().unwrap().position(); + to_table(lua, pos.x, pos.y, pos.z) + }); + } + + fn add_methods>(methods: &mut M) { + methods.add_async_method("set_client_information", set_client_information); + methods.add_method("get_entity", get_entity); + methods.add_method_mut("get_entity_position", get_entity_position); + methods.add_method_mut("goto", goto); + methods.add_method_mut("stop", stop); + } +} + +async fn set_client_information( + _lua: Lua, + client: UserDataRef, + client_information: Table, +) -> Result<()> { + client + .inner + .as_ref() + .unwrap() + .set_client_information(ClientInformation { + view_distance: client_information.get("view_distance")?, + ..ClientInformation::default() + }) + .await + .unwrap(); + Ok(()) +} + +fn get_entity(lua: &Lua, client: &Client, filter_fn: Function) -> Result { + let mut ecs = client.inner.as_ref().unwrap().ecs.lock(); + let mut query = ecs.query_filtered::<( + &MinecraftEntityId, + &EntityUuid, + &EntityKind, + &Position, + &CustomName, + ), Without>(); + + for (&entity_id, entity_uuid, entity_kind, pos, custom_name) in query.iter(&ecs) { + let entity = lua.create_table()?; + + entity.set("id", entity_id.0)?; + entity.set("uuid", entity_uuid.to_string())?; + entity.set("kind", entity_kind.0.to_string())?; + entity.set("pos", to_table(lua, pos.x, pos.y, pos.z)?)?; + if let Some(n) = &**custom_name { + entity.set("custom_name", n.to_string())?; + } + + if filter_fn.call::(entity).unwrap() { + return Ok(entity_id.0); + }; + } + + Err(Error::RuntimeError("entity not found".to_string())) +} + +fn get_entity_position(lua: &Lua, client: &mut Client, entity_id: u32) -> Result { + let client = client.inner.as_mut().unwrap(); + let entity = client + .entity_by::, &MinecraftEntityId>(|query_entity_id: &&MinecraftEntityId| { + query_entity_id.0 == entity_id + }) + .unwrap(); + let pos = client.entity_component::(entity); + to_table(lua, pos.x, pos.y, pos.z) +} + +fn goto(_lua: &Lua, client: &mut Client, pos_table: Table) -> Result<()> { + let pos = from_table(&pos_table)?; + #[allow(clippy::cast_possible_truncation)] + client + .inner + .as_ref() + .unwrap() + .goto(BlockPosGoal(BlockPos::new( + pos.0 as i32, + pos.1 as i32, + pos.2 as i32, + ))); + Ok(()) +} + +fn stop(_lua: &Lua, client: &mut Client, _: ()) -> Result<()> { + client.inner.as_ref().unwrap().stop_pathfinding(); + Ok(()) +} diff --git a/src/scripting/mod.rs b/src/scripting/mod.rs new file mode 100644 index 0000000..a24d5d2 --- /dev/null +++ b/src/scripting/mod.rs @@ -0,0 +1,2 @@ +pub mod client; +pub mod position; diff --git a/src/scripting/position.rs b/src/scripting/position.rs new file mode 100644 index 0000000..89133ff --- /dev/null +++ b/src/scripting/position.rs @@ -0,0 +1,13 @@ +use mlua::{Lua, Result, Table}; + +pub fn to_table(lua: &Lua, x: f64, y: f64, z: f64) -> Result
{ + let table = lua.create_table()?; + table.set("x", x)?; + table.set("y", y)?; + table.set("z", z)?; + Ok(table) +} + +pub fn from_table(table: &Table) -> Result<(f64, f64, f64)> { + Ok((table.get("x")?, table.get("y")?, table.get("z")?)) +} From a937db0be6d64835f9e5952b5d3b0e4994965b04 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Sat, 15 Feb 2025 20:05:12 -0500 Subject: [PATCH 02/35] feat: add basic logging --- Cargo.lock | 1 + Cargo.toml | 1 + src/events.rs | 3 ++- src/main.rs | 9 ++------- src/scripting/logging.rs | 41 ++++++++++++++++++++++++++++++++++++++++ src/scripting/mod.rs | 1 + 6 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 src/scripting/logging.rs diff --git a/Cargo.lock b/Cargo.lock index 2bb087c..9e29f7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1180,6 +1180,7 @@ dependencies = [ "azalea", "clap", "futures", + "log", "mlua", "parking_lot", "tokio", diff --git a/Cargo.toml b/Cargo.toml index 5b731f3..7c1c862 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ anyhow = "1" azalea = { git = "https://github.com/azalea-rs/azalea.git" } clap = { version = "4", features = ["derive"] } futures = "0" +log = { version = "0" } mlua = { version = "0", features = ["async", "luau", "send"] } parking_lot = { version = "0" } tokio = { version = "1", features = ["macros"] } diff --git a/src/events.rs b/src/events.rs index 5a43029..e720349 100644 --- a/src/events.rs +++ b/src/events.rs @@ -1,5 +1,6 @@ use crate::{State, commands::CommandSource, scripting}; use azalea::prelude::*; +use log::info; use mlua::Function; pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow::Result<()> { @@ -7,7 +8,7 @@ pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow: match event { Event::Chat(message) => { - println!("{}", message.message().to_ansi()); + info!("{}", message.message().to_ansi()); let owners = globals.get::>("OWNERS")?; if message.is_whisper() diff --git a/src/main.rs b/src/main.rs index fcf5314..774efa7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -50,13 +50,8 @@ async fn main() -> ExitCode { eprintln!("failed to set config_path in lua globals: {error:?}"); return ExitCode::FAILURE; }; - - let Ok(server) = globals.get::("Server") else { - eprintln!("no server defined in lua globals!"); - return ExitCode::FAILURE; - }; - let Ok(username) = globals.get::("Username") else { - eprintln!("no username defined in lua globals!"); + if let Err(error) = scripting::logging::init(&lua, &globals) { + eprintln!("failed to set up logging wrappers: {error:?}"); return ExitCode::FAILURE; }; diff --git a/src/scripting/logging.rs b/src/scripting/logging.rs new file mode 100644 index 0000000..cb9bf7b --- /dev/null +++ b/src/scripting/logging.rs @@ -0,0 +1,41 @@ +use log::{debug, error, info, trace, warn}; +use mlua::{Lua, Result, Table}; + +pub fn init(lua: &Lua, globals: &Table) -> Result<()> { + globals.set( + "error", + lua.create_function(|_, message: String| { + error!("{message}"); + Ok(()) + })?, + )?; + globals.set( + "warn", + lua.create_function(|_, message: String| { + warn!("{message}"); + Ok(()) + })?, + )?; + globals.set( + "info", + lua.create_function(|_, message: String| { + info!("{message}"); + Ok(()) + })?, + )?; + globals.set( + "debug", + lua.create_function(|_, message: String| { + debug!("{message}"); + Ok(()) + })?, + )?; + globals.set( + "trace", + lua.create_function(|_, message: String| { + trace!("{message}"); + Ok(()) + })?, + )?; + Ok(()) +} diff --git a/src/scripting/mod.rs b/src/scripting/mod.rs index a24d5d2..70cc1ba 100644 --- a/src/scripting/mod.rs +++ b/src/scripting/mod.rs @@ -1,2 +1,3 @@ pub mod client; +pub mod logging; pub mod position; From 5752e94ad28ad0d4d5d0599f32e8f2ad795cdf77 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Sat, 15 Feb 2025 22:47:22 -0500 Subject: [PATCH 03/35] feat: run http server to receive commands --- Cargo.lock | 10 ++++++ Cargo.toml | 3 ++ src/arguments.rs | 6 +++- src/events.rs | 27 +++++++++++++-- src/http.rs | 90 ++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 9 +++-- 6 files changed, 138 insertions(+), 7 deletions(-) create mode 100644 src/http.rs diff --git a/Cargo.lock b/Cargo.lock index 9e29f7d..31d36a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1180,6 +1180,9 @@ dependencies = [ "azalea", "clap", "futures", + "http-body-util", + "hyper", + "hyper-util", "log", "mlua", "parking_lot", @@ -1493,6 +1496,12 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + [[package]] name = "hyper" version = "1.6.0" @@ -1505,6 +1514,7 @@ dependencies = [ "http", "http-body", "httparse", + "httpdate", "itoa", "pin-project-lite", "smallvec", diff --git a/Cargo.toml b/Cargo.toml index 7c1c862..e6f67b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,9 @@ anyhow = "1" azalea = { git = "https://github.com/azalea-rs/azalea.git" } clap = { version = "4", features = ["derive"] } futures = "0" +http-body-util = "0" +hyper = { version = "1", features = ["server"] } +hyper-util = "0" log = { version = "0" } mlua = { version = "0", features = ["async", "luau", "send"] } parking_lot = { version = "0" } diff --git a/src/arguments.rs b/src/arguments.rs index eb075ab..85de8e5 100644 --- a/src/arguments.rs +++ b/src/arguments.rs @@ -1,5 +1,5 @@ use clap::Parser; -use std::path::PathBuf; +use std::{net::SocketAddr, path::PathBuf}; /// A Minecraft utility bot #[derive(Parser)] @@ -7,4 +7,8 @@ pub struct Arguments { /// Path to main Lua file #[arg(short, long)] pub script: Option, + + /// Socket address to bind HTTP server to + #[arg(short, long)] + pub address: Option, } diff --git a/src/events.rs b/src/events.rs index e720349..69a6d43 100644 --- a/src/events.rs +++ b/src/events.rs @@ -1,7 +1,10 @@ -use crate::{State, commands::CommandSource, scripting}; +use crate::{State, commands::CommandSource, http::handle, scripting}; use azalea::prelude::*; -use log::info; +use hyper::{server::conn::http1, service::service_fn}; +use hyper_util::rt::TokioIo; +use log::{error, info}; use mlua::Function; +use tokio::net::TcpListener; pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow::Result<()> { let globals = state.lua.lock().globals(); @@ -40,7 +43,25 @@ pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow: inner: Some(client), }, )?; - globals.get::("Init")?.call::<()>(())? + globals.get::("Init")?.call::<()>(())?; + + if let Some(address) = state.address { + let listener = TcpListener::bind(address).await?; + loop { + let (stream, _) = listener.accept().await?; + let io = TokioIo::new(stream); + + let state = state.clone(); + let service = service_fn(move |request| { + let state = state.clone(); + async move { handle(request, state).await } + }); + + if let Err(error) = http1::Builder::new().serve_connection(io, service).await { + error!("failed to serve connection: {error:?}"); + } + } + } } _ => (), }; diff --git a/src/http.rs b/src/http.rs new file mode 100644 index 0000000..f795846 --- /dev/null +++ b/src/http.rs @@ -0,0 +1,90 @@ +use crate::State; +use http_body_util::{BodyExt, Empty, Full, combinators::BoxBody}; +use hyper::{Method, Request, Response, StatusCode, body::Bytes}; + +pub async fn handle( + request: Request, + state: State, +) -> Result>, hyper::Error> { + let path = request.uri().path().to_owned(); + + match (request.method(), path.as_str()) { + (&Method::POST, "/reload") => { + let lua = state.lua.lock(); + let config_path = match lua.globals().get::("config_path") { + Ok(path) => path, + Err(error) => { + return Ok(status_code_response( + StatusCode::INTERNAL_SERVER_ERROR, + Some(full(format!( + "failed to get config_path from lua globals: {error:?}" + ))), + )); + } + }; + if let Err(error) = match &std::fs::read_to_string(&config_path) { + Ok(string) => lua.load(string).exec(), + Err(error) => { + return Ok(status_code_response( + StatusCode::INTERNAL_SERVER_ERROR, + Some(full(format!("failed to read {config_path:?}: {error:?}"))), + )); + } + } { + return Ok(status_code_response( + StatusCode::INTERNAL_SERVER_ERROR, + Some(full(format!( + "failed to execute configuration as lua code: {error:?}" + ))), + )); + } + + Ok(Response::new(empty())) + } + + (&Method::POST, "/eval" | "/exec") => { + let bytes = request.into_body().collect().await?.to_bytes(); + let code = match std::str::from_utf8(&bytes) { + Ok(code) => code, + Err(error) => { + return Ok(status_code_response( + StatusCode::BAD_REQUEST, + Some(full(format!("invalid utf-8 data received: {error:?}"))), + )); + } + }; + let chunk = state.lua.lock().load(code); + + Ok(Response::new(full(match path.as_str() { + "/eval" => format!("{:?}", chunk.eval::()), + "/exec" => format!("{:?}", chunk.exec()), + _ => unreachable!(), + }))) + } + + (&Method::GET, "/ping") => Ok(Response::new(full("pong!"))), + + _ => Ok(status_code_response(StatusCode::NOT_FOUND, None)), + } +} + +fn status_code_response( + status_code: StatusCode, + bytes: Option>, +) -> Response> { + let mut response = Response::new(bytes.unwrap_or(empty())); + *response.status_mut() = status_code; + response +} + +fn full>(chunk: T) -> BoxBody { + Full::new(chunk.into()) + .map_err(|never| match never {}) + .boxed() +} + +fn empty() -> BoxBody { + Empty::::new() + .map_err(|never| match never {}) + .boxed() +} diff --git a/src/main.rs b/src/main.rs index 774efa7..fb1439c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ mod arguments; mod commands; mod events; +mod http; mod scripting; use azalea::{brigadier::prelude::CommandDispatcher, prelude::*}; @@ -11,12 +12,13 @@ use commands::{CommandSource, register}; use events::handle_event; use mlua::Lua; use parking_lot::Mutex; -use std::{path::PathBuf, process::ExitCode, sync::Arc}; +use std::{net::SocketAddr, path::PathBuf, process::ExitCode, sync::Arc}; #[derive(Default, Clone, Component)] pub struct State { - lua: Arc>, commands: Arc>>, + lua: Arc>, + address: Option, } #[tokio::main] @@ -73,8 +75,9 @@ async fn main() -> ExitCode { let Err(error) = ClientBuilder::new() .set_handler(handle_event) .set_state(State { - lua: Arc::new(Mutex::new(lua)), commands: Arc::new(commands), + lua: Arc::new(Mutex::new(lua)), + address: args.address, }) .start(account, server.as_ref()) .await; From c4702a74f281e372e47afe0ad86d4bb7b28956a1 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Sun, 16 Feb 2025 01:06:03 -0500 Subject: [PATCH 04/35] refactor: unify scripting commands --- src/commands.rs | 44 ++++++------------------------ src/http.rs | 64 +++++++++++++++----------------------------- src/scripting/mod.rs | 33 +++++++++++++++++++++++ 3 files changed, 62 insertions(+), 79 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index 6586894..aa7261c 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -1,4 +1,7 @@ -use crate::State; +use crate::{ + State, + scripting::{eval, exec, reload}, +}; use azalea::{ GameProfileComponent, brigadier::prelude::*, chat::ChatPacket, entity::metadata::Player, prelude::*, @@ -37,42 +40,16 @@ impl CommandSource { pub fn register(commands: &mut CommandDispatcher>) { commands.register(literal("reload").executes(|ctx: &Ctx| { let source = ctx.source.lock(); - let lua = source.state.lua.lock(); - let config_path = match lua.globals().get::("config_path") { - Ok(path) => path, - Err(error) => { - source.reply(&format!( - "failed to get config_path from lua globals: {error:?}" - )); - return 0; - } - }; - if let Err(error) = match &std::fs::read_to_string(&config_path) { - Ok(string) => lua.load(string).exec(), - Err(error) => { - source.reply(&format!("failed to read {config_path:?}: {error:?}")); - return 0; - } - } { - source.reply(&format!( - "failed to execute configuration as lua code: {error:?}" - )); - return 0; - } + source.reply(&format!("{:?}", reload(&source.state.lua.lock()))); 1 })); commands.register( - literal("eval").then(argument("expr", string()).executes(|ctx: &Ctx| { + literal("eval").then(argument("code", string()).executes(|ctx: &Ctx| { let source = ctx.source.lock(); source.reply(&format!( "{:?}", - source - .state - .lua - .lock() - .load(get_string(ctx, "expr").unwrap()) - .eval::() + eval(&source.state.lua.lock(), &get_string(ctx, "code").unwrap()) )); 1 })), @@ -83,12 +60,7 @@ pub fn register(commands: &mut CommandDispatcher>) { let source = ctx.source.lock(); source.reply(&format!( "{:?}", - source - .state - .lua - .lock() - .load(get_string(ctx, "code").unwrap()) - .exec() + exec(&source.state.lua.lock(), &get_string(ctx, "code").unwrap()) )); 1 })), diff --git a/src/http.rs b/src/http.rs index f795846..d774014 100644 --- a/src/http.rs +++ b/src/http.rs @@ -1,4 +1,7 @@ -use crate::State; +use crate::{ + State, + scripting::{eval, exec, reload}, +}; use http_body_util::{BodyExt, Empty, Full, combinators::BoxBody}; use hyper::{Method, Request, Response, StatusCode, body::Bytes}; @@ -9,57 +12,32 @@ pub async fn handle( let path = request.uri().path().to_owned(); match (request.method(), path.as_str()) { - (&Method::POST, "/reload") => { - let lua = state.lua.lock(); - let config_path = match lua.globals().get::("config_path") { - Ok(path) => path, - Err(error) => { - return Ok(status_code_response( - StatusCode::INTERNAL_SERVER_ERROR, - Some(full(format!( - "failed to get config_path from lua globals: {error:?}" - ))), - )); - } - }; - if let Err(error) = match &std::fs::read_to_string(&config_path) { - Ok(string) => lua.load(string).exec(), - Err(error) => { - return Ok(status_code_response( - StatusCode::INTERNAL_SERVER_ERROR, - Some(full(format!("failed to read {config_path:?}: {error:?}"))), - )); - } - } { - return Ok(status_code_response( - StatusCode::INTERNAL_SERVER_ERROR, - Some(full(format!( - "failed to execute configuration as lua code: {error:?}" - ))), - )); - } - - Ok(Response::new(empty())) - } + (&Method::POST, "/reload") => Ok(match reload(&state.lua.lock()) { + Ok(()) => Response::new(empty()), + Err(error) => status_code_response( + StatusCode::INTERNAL_SERVER_ERROR, + Some(full(format!("{error:?}"))), + ), + }), (&Method::POST, "/eval" | "/exec") => { let bytes = request.into_body().collect().await?.to_bytes(); - let code = match std::str::from_utf8(&bytes) { - Ok(code) => code, + Ok(match std::str::from_utf8(&bytes) { + Ok(code) => { + let lua = state.lua.lock(); + Response::new(full(match path.as_str() { + "/eval" => format!("{:?}", eval(&lua, code)), + "/exec" => format!("{:?}", exec(&lua, code)), + _ => unreachable!(), + })) + } Err(error) => { return Ok(status_code_response( StatusCode::BAD_REQUEST, Some(full(format!("invalid utf-8 data received: {error:?}"))), )); } - }; - let chunk = state.lua.lock().load(code); - - Ok(Response::new(full(match path.as_str() { - "/eval" => format!("{:?}", chunk.eval::()), - "/exec" => format!("{:?}", chunk.exec()), - _ => unreachable!(), - }))) + }) } (&Method::GET, "/ping") => Ok(Response::new(full("pong!"))), diff --git a/src/scripting/mod.rs b/src/scripting/mod.rs index 70cc1ba..498a20e 100644 --- a/src/scripting/mod.rs +++ b/src/scripting/mod.rs @@ -1,3 +1,36 @@ pub mod client; pub mod logging; pub mod position; + +use mlua::Lua; + +#[derive(Debug)] +#[allow(dead_code)] +pub enum Error { + MissingGlobal(mlua::Error), + ReadFile(std::io::Error), + LoadChunk(mlua::Error), + EvalChunk(mlua::Error), + ExecChunk(mlua::Error), +} + +pub fn reload(lua: &Lua) -> Result<(), Error> { + lua.load( + &std::fs::read_to_string( + lua.globals() + .get::("config_path") + .map_err(Error::MissingGlobal)?, + ) + .map_err(Error::ReadFile)?, + ) + .exec() + .map_err(Error::LoadChunk) +} + +pub fn eval(lua: &Lua, code: &str) -> Result { + lua.load(code).eval::().map_err(Error::EvalChunk) +} + +pub fn exec(lua: &Lua, code: &str) -> Result<(), Error> { + lua.load(code).exec().map_err(Error::ExecChunk) +} From 645483c98f2e44703e06b96b0b6187f9dc832e40 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Sun, 16 Feb 2025 01:10:48 -0500 Subject: [PATCH 05/35] refactor: clean up and restructure --- Cargo.lock | 1 - Cargo.toml | 1 - src/arguments.rs | 4 +- src/commands.rs | 9 ++- src/events.rs | 46 ++++++++---- src/http.rs | 34 ++++----- src/main.rs | 66 +++++------------ src/scripting/client.rs | 109 ---------------------------- src/scripting/client/mod.rs | 68 +++++++++++++++++ src/scripting/client/pathfinding.rs | 22 ++++++ src/scripting/client/state.rs | 21 ++++++ src/scripting/entity.rs | 43 +++++++++++ src/scripting/logging.rs | 2 +- src/scripting/mod.rs | 11 +-- src/scripting/position.rs | 41 ++++++++--- 15 files changed, 267 insertions(+), 211 deletions(-) delete mode 100644 src/scripting/client.rs create mode 100644 src/scripting/client/mod.rs create mode 100644 src/scripting/client/pathfinding.rs create mode 100644 src/scripting/client/state.rs create mode 100644 src/scripting/entity.rs diff --git a/Cargo.lock b/Cargo.lock index 31d36a9..23aae7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1179,7 +1179,6 @@ dependencies = [ "anyhow", "azalea", "clap", - "futures", "http-body-util", "hyper", "hyper-util", diff --git a/Cargo.toml b/Cargo.toml index e6f67b5..b5c811c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,6 @@ strip = true anyhow = "1" azalea = { git = "https://github.com/azalea-rs/azalea.git" } clap = { version = "4", features = ["derive"] } -futures = "0" http-body-util = "0" hyper = { version = "1", features = ["server"] } hyper-util = "0" diff --git a/src/arguments.rs b/src/arguments.rs index 85de8e5..626f85e 100644 --- a/src/arguments.rs +++ b/src/arguments.rs @@ -9,6 +9,6 @@ pub struct Arguments { pub script: Option, /// Socket address to bind HTTP server to - #[arg(short, long)] - pub address: Option, + #[arg(short = 'a', long)] + pub http_address: Option, } diff --git a/src/commands.rs b/src/commands.rs index aa7261c..4015952 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -19,13 +19,14 @@ pub struct CommandSource { impl CommandSource { pub fn reply(&self, message: &str) { - if self.message.is_whisper() + let response = if self.message.is_whisper() && let Some(username) = self.message.username() { - self.client.chat(&format!("/w {username} {message}")); + &format!("/w {username} {message}") } else { - self.client.chat(message); - } + message + }; + self.client.chat(response); } pub fn _entity(&mut self) -> Option { diff --git a/src/events.rs b/src/events.rs index 69a6d43..23c8856 100644 --- a/src/events.rs +++ b/src/events.rs @@ -1,9 +1,9 @@ -use crate::{State, commands::CommandSource, http::handle, scripting}; +use crate::{State, commands::CommandSource, http::serve, scripting}; use azalea::prelude::*; use hyper::{server::conn::http1, service::service_fn}; use hyper_util::rt::TokioIo; -use log::{error, info}; use mlua::Function; +use log::{debug, error, info, trace}; use tokio::net::TcpListener; pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow::Result<()> { @@ -33,38 +33,54 @@ pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow: state, } .reply(&format!("{error:?}")); - }; + } } } Event::Init => { + debug!("client initialized"); + globals.set( "client", scripting::client::Client { inner: Some(client), }, )?; - globals.get::("Init")?.call::<()>(())?; + if let Ok(on_init) = globals.get::("on_init") + && let Err(error) = on_init.call::<()>(()) + { + error!("failed to call lua on_init function: {error:?}"); + }; + + if let Some(address) = state.http_address { + let listener = TcpListener::bind(address).await.map_err(|error| { + error!("failed to listen on {address}: {error:?}"); + error + })?; + debug!("http server listening on {address}"); - if let Some(address) = state.address { - let listener = TcpListener::bind(address).await?; loop { - let (stream, _) = listener.accept().await?; - let io = TokioIo::new(stream); + let (stream, peer) = listener.accept().await?; + trace!("http server got connection from {peer}"); - let state = state.clone(); + let conn_state = state.clone(); let service = service_fn(move |request| { - let state = state.clone(); - async move { handle(request, state).await } + let request_state = conn_state.clone(); + async move { serve(request, request_state).await } }); - if let Err(error) = http1::Builder::new().serve_connection(io, service).await { - error!("failed to serve connection: {error:?}"); - } + tokio::task::spawn(async move { + if let Err(error) = http1::Builder::new() + .serve_connection(TokioIo::new(stream), service) + .await + { + error!("failed to serve connection: {error:?}"); + } + }); } } } _ => (), - }; + } Ok(()) } diff --git a/src/http.rs b/src/http.rs index d774014..a57a5ff 100644 --- a/src/http.rs +++ b/src/http.rs @@ -5,24 +5,24 @@ use crate::{ use http_body_util::{BodyExt, Empty, Full, combinators::BoxBody}; use hyper::{Method, Request, Response, StatusCode, body::Bytes}; -pub async fn handle( +pub async fn serve( request: Request, state: State, ) -> Result>, hyper::Error> { let path = request.uri().path().to_owned(); - match (request.method(), path.as_str()) { - (&Method::POST, "/reload") => Ok(match reload(&state.lua.lock()) { + Ok(match (request.method(), path.as_str()) { + (&Method::POST, "/reload") => match reload(&state.lua.lock()) { Ok(()) => Response::new(empty()), Err(error) => status_code_response( StatusCode::INTERNAL_SERVER_ERROR, - Some(full(format!("{error:?}"))), + full(format!("{error:?}")), ), - }), + }, (&Method::POST, "/eval" | "/exec") => { let bytes = request.into_body().collect().await?.to_bytes(); - Ok(match std::str::from_utf8(&bytes) { + match std::str::from_utf8(&bytes) { Ok(code) => { let lua = state.lua.lock(); Response::new(full(match path.as_str() { @@ -31,26 +31,24 @@ pub async fn handle( _ => unreachable!(), })) } - Err(error) => { - return Ok(status_code_response( - StatusCode::BAD_REQUEST, - Some(full(format!("invalid utf-8 data received: {error:?}"))), - )); - } - }) + Err(error) => status_code_response( + StatusCode::BAD_REQUEST, + full(format!("invalid utf-8 data received: {error:?}")), + ), + } } - (&Method::GET, "/ping") => Ok(Response::new(full("pong!"))), + (&Method::GET, "/ping") => Response::new(full("pong!")), - _ => Ok(status_code_response(StatusCode::NOT_FOUND, None)), - } + _ => status_code_response(StatusCode::NOT_FOUND, empty()), + }) } fn status_code_response( status_code: StatusCode, - bytes: Option>, + bytes: BoxBody, ) -> Response> { - let mut response = Response::new(bytes.unwrap_or(empty())); + let mut response = Response::new(bytes); *response.status_mut() = status_code; response } diff --git a/src/main.rs b/src/main.rs index fb1439c..28fa6b0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,62 +12,29 @@ use commands::{CommandSource, register}; use events::handle_event; use mlua::Lua; use parking_lot::Mutex; -use std::{net::SocketAddr, path::PathBuf, process::ExitCode, sync::Arc}; +use std::{net::SocketAddr, path::PathBuf, sync::Arc}; #[derive(Default, Clone, Component)] pub struct State { commands: Arc>>, lua: Arc>, - address: Option, + http_address: Option, } #[tokio::main] -async fn main() -> ExitCode { +async fn main() -> anyhow::Result<()> { let args = arguments::Arguments::parse(); - let lua = Lua::new(); + let script_path = args.script.unwrap_or(PathBuf::from("errornowatcher.lua")); - let config_path = args.script.unwrap_or(PathBuf::from("errornowatcher.lua")); - if let Err(error) = match &std::fs::read_to_string(&config_path) { - Ok(string) => lua.load(string).exec(), - Err(error) => { - eprintln!("failed to read {config_path:?}: {error:?}"); - return ExitCode::FAILURE; - } - } { - eprintln!("failed to execute configuration as lua code: {error:?}"); - return ExitCode::FAILURE; - } + let lua = Lua::new(); + lua.load(std::fs::read_to_string(&script_path)?).exec()?; let globals = lua.globals(); - let Ok(server) = globals.get::("SERVER") else { - eprintln!("no server defined in lua globals!"); - return ExitCode::FAILURE; - }; - let Ok(username) = globals.get::("USERNAME") else { - eprintln!("no username defined in lua globals!"); - return ExitCode::FAILURE; - }; + let server = globals.get::("SERVER")?; + let username = globals.get::("USERNAME")?; - if let Err(error) = globals.set("config_path", config_path) { - eprintln!("failed to set config_path in lua globals: {error:?}"); - return ExitCode::FAILURE; - }; - if let Err(error) = scripting::logging::init(&lua, &globals) { - eprintln!("failed to set up logging wrappers: {error:?}"); - return ExitCode::FAILURE; - }; - - let account = if username.contains('@') { - match Account::microsoft(&username).await { - Ok(a) => a, - Err(error) => { - eprintln!("failed to login using microsoft account: {error:?}"); - return ExitCode::FAILURE; - } - } - } else { - Account::offline(&username) - }; + globals.set("script_path", script_path)?; + scripting::logging::register(&lua, &globals)?; let mut commands = CommandDispatcher::new(); register(&mut commands); @@ -77,11 +44,18 @@ async fn main() -> ExitCode { .set_state(State { commands: Arc::new(commands), lua: Arc::new(Mutex::new(lua)), - address: args.address, + http_address: args.http_address, }) - .start(account, server.as_ref()) + .start( + if username.contains('@') { + Account::microsoft(&username).await? + } else { + Account::offline(&username) + }, + server.as_ref(), + ) .await; eprintln!("{error:?}"); - ExitCode::SUCCESS + Ok(()) } diff --git a/src/scripting/client.rs b/src/scripting/client.rs deleted file mode 100644 index cbe99bc..0000000 --- a/src/scripting/client.rs +++ /dev/null @@ -1,109 +0,0 @@ -use super::position::{from_table, to_table}; -use azalea::{ - BlockPos, Client as AzaleaClient, ClientInformation, - ecs::query::Without, - entity::{Dead, EntityKind, EntityUuid, Position, metadata::CustomName}, - pathfinder::goals::BlockPosGoal, - prelude::PathfinderClientExt, - world::MinecraftEntityId, -}; -use mlua::{Error, Function, Lua, Result, Table, UserData, UserDataRef}; - -pub struct Client { - pub inner: Option, -} - -impl UserData for Client { - fn add_fields>(fields: &mut F) { - fields.add_field_method_get("pos", |lua, this| { - let pos = this.inner.as_ref().unwrap().position(); - to_table(lua, pos.x, pos.y, pos.z) - }); - } - - fn add_methods>(methods: &mut M) { - methods.add_async_method("set_client_information", set_client_information); - methods.add_method("get_entity", get_entity); - methods.add_method_mut("get_entity_position", get_entity_position); - methods.add_method_mut("goto", goto); - methods.add_method_mut("stop", stop); - } -} - -async fn set_client_information( - _lua: Lua, - client: UserDataRef, - client_information: Table, -) -> Result<()> { - client - .inner - .as_ref() - .unwrap() - .set_client_information(ClientInformation { - view_distance: client_information.get("view_distance")?, - ..ClientInformation::default() - }) - .await - .unwrap(); - Ok(()) -} - -fn get_entity(lua: &Lua, client: &Client, filter_fn: Function) -> Result { - let mut ecs = client.inner.as_ref().unwrap().ecs.lock(); - let mut query = ecs.query_filtered::<( - &MinecraftEntityId, - &EntityUuid, - &EntityKind, - &Position, - &CustomName, - ), Without>(); - - for (&entity_id, entity_uuid, entity_kind, pos, custom_name) in query.iter(&ecs) { - let entity = lua.create_table()?; - - entity.set("id", entity_id.0)?; - entity.set("uuid", entity_uuid.to_string())?; - entity.set("kind", entity_kind.0.to_string())?; - entity.set("pos", to_table(lua, pos.x, pos.y, pos.z)?)?; - if let Some(n) = &**custom_name { - entity.set("custom_name", n.to_string())?; - } - - if filter_fn.call::(entity).unwrap() { - return Ok(entity_id.0); - }; - } - - Err(Error::RuntimeError("entity not found".to_string())) -} - -fn get_entity_position(lua: &Lua, client: &mut Client, entity_id: u32) -> Result
{ - let client = client.inner.as_mut().unwrap(); - let entity = client - .entity_by::, &MinecraftEntityId>(|query_entity_id: &&MinecraftEntityId| { - query_entity_id.0 == entity_id - }) - .unwrap(); - let pos = client.entity_component::(entity); - to_table(lua, pos.x, pos.y, pos.z) -} - -fn goto(_lua: &Lua, client: &mut Client, pos_table: Table) -> Result<()> { - let pos = from_table(&pos_table)?; - #[allow(clippy::cast_possible_truncation)] - client - .inner - .as_ref() - .unwrap() - .goto(BlockPosGoal(BlockPos::new( - pos.0 as i32, - pos.1 as i32, - pos.2 as i32, - ))); - Ok(()) -} - -fn stop(_lua: &Lua, client: &mut Client, _: ()) -> Result<()> { - client.inner.as_ref().unwrap().stop_pathfinding(); - Ok(()) -} diff --git a/src/scripting/client/mod.rs b/src/scripting/client/mod.rs new file mode 100644 index 0000000..ff3f7c9 --- /dev/null +++ b/src/scripting/client/mod.rs @@ -0,0 +1,68 @@ +mod pathfinding; +mod state; + +use super::{entity::Entity, position::Position}; +use azalea::{ + Client as AzaleaClient, + ecs::query::Without, + entity::{Dead, EntityKind, EntityUuid, Position as AzaleaPosition, metadata::CustomName}, + world::MinecraftEntityId, +}; +use mlua::{Function, Lua, Result, UserData}; + +pub struct Client { + pub inner: Option, +} + +impl UserData for Client { + fn add_fields>(fields: &mut F) { + fields.add_field_method_get("position", |_, this| { + let position = this.inner.as_ref().unwrap().position(); + Ok(Position { + x: position.x, + y: position.y, + z: position.z, + }) + }); + } + + fn add_methods>(methods: &mut M) { + methods.add_async_method("set_client_information", state::set_client_information); + methods.add_method("find_entities", find_entities); + methods.add_method("stop_pathfinding", pathfinding::stop_pathfinding); + methods.add_method_mut("goto", pathfinding::goto); + } +} + +fn find_entities(_lua: &Lua, client: &Client, filter_fn: Function) -> Result> { + let mut matched = Vec::new(); + + let mut ecs = client.inner.as_ref().unwrap().ecs.lock(); + let mut query = ecs.query_filtered::<( + &MinecraftEntityId, + &EntityUuid, + &EntityKind, + &AzaleaPosition, + &CustomName, + ), Without>(); + + for (&id, uuid, kind, position, custom_name) in query.iter(&ecs) { + let entity = Entity { + id: id.0, + uuid: uuid.to_string(), + kind: kind.to_string(), + position: Position { + x: position.x, + y: position.y, + z: position.z, + }, + custom_name: custom_name.as_ref().map(ToString::to_string), + }; + + if filter_fn.call::(entity.clone()).unwrap() { + matched.push(entity); + } + } + + Ok(matched) +} diff --git a/src/scripting/client/pathfinding.rs b/src/scripting/client/pathfinding.rs new file mode 100644 index 0000000..95fe164 --- /dev/null +++ b/src/scripting/client/pathfinding.rs @@ -0,0 +1,22 @@ +use super::{Client, Position}; +use azalea::{BlockPos, pathfinder::goals::BlockPosGoal, prelude::*}; +use mlua::{Lua, Result}; + +pub fn goto(_lua: &Lua, client: &mut Client, position: Position) -> Result<()> { + #[allow(clippy::cast_possible_truncation)] + client + .inner + .as_ref() + .unwrap() + .goto(BlockPosGoal(BlockPos::new( + position.x as i32, + position.y as i32, + position.z as i32, + ))); + Ok(()) +} + +pub fn stop_pathfinding(_lua: &Lua, client: &Client, _: ()) -> Result<()> { + client.inner.as_ref().unwrap().stop_pathfinding(); + Ok(()) +} diff --git a/src/scripting/client/state.rs b/src/scripting/client/state.rs new file mode 100644 index 0000000..cf7af8a --- /dev/null +++ b/src/scripting/client/state.rs @@ -0,0 +1,21 @@ +use super::Client; +use azalea::ClientInformation; +use mlua::{Lua, Result, Table, UserDataRef}; + +pub async fn set_client_information( + _lua: Lua, + client: UserDataRef, + client_information: Table, +) -> Result<()> { + client + .inner + .as_ref() + .unwrap() + .set_client_information(ClientInformation { + view_distance: client_information.get("view_distance")?, + ..ClientInformation::default() + }) + .await + .unwrap(); + Ok(()) +} diff --git a/src/scripting/entity.rs b/src/scripting/entity.rs new file mode 100644 index 0000000..d74a9e6 --- /dev/null +++ b/src/scripting/entity.rs @@ -0,0 +1,43 @@ +use super::position::Position; +use mlua::{FromLua, IntoLua, Lua, Result, Value}; + +#[derive(Clone)] +pub struct Entity { + pub id: u32, + pub uuid: String, + pub kind: String, + pub position: Position, + pub custom_name: Option, +} + +impl IntoLua for Entity { + fn into_lua(self, lua: &Lua) -> Result { + let entity = lua.create_table()?; + entity.set("id", self.id)?; + entity.set("uuid", self.uuid)?; + entity.set("kind", self.kind)?; + entity.set("position", self.position)?; + entity.set("custom_name", self.custom_name)?; + Ok(Value::Table(entity)) + } +} + +impl FromLua for Entity { + fn from_lua(value: Value, _lua: &Lua) -> Result { + if let Value::Table(table) = value { + Ok(Self { + id: table.get("id")?, + uuid: table.get("uuid")?, + kind: table.get("kind")?, + position: table.get("position")?, + custom_name: table.get("custom_name")?, + }) + } else { + Err(mlua::Error::FromLuaConversionError { + from: value.type_name(), + to: "Position".to_string(), + message: None, + }) + } + } +} diff --git a/src/scripting/logging.rs b/src/scripting/logging.rs index cb9bf7b..c0c78e9 100644 --- a/src/scripting/logging.rs +++ b/src/scripting/logging.rs @@ -1,7 +1,7 @@ use log::{debug, error, info, trace, warn}; use mlua::{Lua, Result, Table}; -pub fn init(lua: &Lua, globals: &Table) -> Result<()> { +pub fn register(lua: &Lua, globals: &Table) -> Result<()> { globals.set( "error", lua.create_function(|_, message: String| { diff --git a/src/scripting/mod.rs b/src/scripting/mod.rs index 498a20e..e4b1a84 100644 --- a/src/scripting/mod.rs +++ b/src/scripting/mod.rs @@ -1,4 +1,5 @@ pub mod client; +pub mod entity; pub mod logging; pub mod position; @@ -7,19 +8,19 @@ use mlua::Lua; #[derive(Debug)] #[allow(dead_code)] pub enum Error { - MissingGlobal(mlua::Error), - ReadFile(std::io::Error), - LoadChunk(mlua::Error), EvalChunk(mlua::Error), ExecChunk(mlua::Error), + LoadChunk(mlua::Error), + MissingPath(mlua::Error), + ReadFile(std::io::Error), } pub fn reload(lua: &Lua) -> Result<(), Error> { lua.load( &std::fs::read_to_string( lua.globals() - .get::("config_path") - .map_err(Error::MissingGlobal)?, + .get::("script_path") + .map_err(Error::MissingPath)?, ) .map_err(Error::ReadFile)?, ) diff --git a/src/scripting/position.rs b/src/scripting/position.rs index 89133ff..16df16e 100644 --- a/src/scripting/position.rs +++ b/src/scripting/position.rs @@ -1,13 +1,36 @@ -use mlua::{Lua, Result, Table}; +use mlua::{FromLua, IntoLua, Lua, Result, Value}; -pub fn to_table(lua: &Lua, x: f64, y: f64, z: f64) -> Result
{ - let table = lua.create_table()?; - table.set("x", x)?; - table.set("y", y)?; - table.set("z", z)?; - Ok(table) +#[derive(Clone)] +pub struct Position { + pub x: f64, + pub y: f64, + pub z: f64, } -pub fn from_table(table: &Table) -> Result<(f64, f64, f64)> { - Ok((table.get("x")?, table.get("y")?, table.get("z")?)) +impl IntoLua for Position { + fn into_lua(self, lua: &Lua) -> Result { + let table = lua.create_table()?; + table.set("x", self.x)?; + table.set("y", self.y)?; + table.set("z", self.z)?; + Ok(Value::Table(table)) + } +} + +impl FromLua for Position { + fn from_lua(value: Value, _lua: &Lua) -> Result { + if let Value::Table(table) = value { + Ok(Self { + x: table.get("x")?, + y: table.get("y")?, + z: table.get("z")?, + }) + } else { + Err(mlua::Error::FromLuaConversionError { + from: value.type_name(), + to: "Position".to_string(), + message: None, + }) + } + } } From 1c7a6fde09f4c064f4528ac8624c1644c096c994 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Sun, 16 Feb 2025 13:08:26 -0500 Subject: [PATCH 06/35] feat: add more lua event hooks --- src/events.rs | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/events.rs b/src/events.rs index 23c8856..8952ec7 100644 --- a/src/events.rs +++ b/src/events.rs @@ -2,8 +2,8 @@ use crate::{State, commands::CommandSource, http::serve, scripting}; use azalea::prelude::*; use hyper::{server::conn::http1, service::service_fn}; use hyper_util::rt::TokioIo; -use mlua::Function; use log::{debug, error, info, trace}; +use mlua::{Function, IntoLuaMulti, Table}; use tokio::net::TcpListener; pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow::Result<()> { @@ -11,7 +11,8 @@ pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow: match event { Event::Chat(message) => { - info!("{}", message.message().to_ansi()); + let formatted_message = message.message(); + info!("{}", formatted_message.to_ansi()); let owners = globals.get::>("OWNERS")?; if message.is_whisper() @@ -35,7 +36,18 @@ pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow: .reply(&format!("{error:?}")); } } + + call_lua_handler(&globals, "on_chat", ()); } + Event::Death(Some(packet)) => { + let death_data = state.lua.lock().create_table()?; + death_data.set("message", packet.message.to_string())?; + death_data.set("player_id", packet.player_id)?; + + call_lua_handler(&globals, "on_death", death_data); + } + Event::Tick => call_lua_handler(&globals, "on_tick", ()), + Event::Login => call_lua_handler(&globals, "on_login", ()), Event::Init => { debug!("client initialized"); @@ -45,11 +57,7 @@ pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow: inner: Some(client), }, )?; - if let Ok(on_init) = globals.get::("on_init") - && let Err(error) = on_init.call::<()>(()) - { - error!("failed to call lua on_init function: {error:?}"); - }; + call_lua_handler(&globals, "on_init", ()); if let Some(address) = state.http_address { let listener = TcpListener::bind(address).await.map_err(|error| { @@ -84,3 +92,11 @@ pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow: Ok(()) } + +fn call_lua_handler(globals: &Table, name: &str, data: T) { + if let Ok(handler) = globals.get::(name) + && let Err(error) = handler.call::<()>(data) + { + error!("failed to call lua {name} function: {error:?}"); + } +} From 2e1736af250d5cb0e6833f8ad39d186b8c9a9cb4 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Sun, 16 Feb 2025 14:21:29 -0500 Subject: [PATCH 07/35] refactor: clean up locking and convert to async --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/commands.rs | 36 ++++++++++++++++++++++-------------- src/events.rs | 4 ++-- src/http.rs | 15 ++++++--------- src/main.rs | 10 +++++----- src/scripting/mod.rs | 11 +++++++---- 7 files changed, 44 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 23aae7b..10416a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1179,12 +1179,12 @@ dependencies = [ "anyhow", "azalea", "clap", + "futures", "http-body-util", "hyper", "hyper-util", "log", "mlua", - "parking_lot", "tokio", ] diff --git a/Cargo.toml b/Cargo.toml index b5c811c..e17c9d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,5 +24,5 @@ hyper = { version = "1", features = ["server"] } hyper-util = "0" log = { version = "0" } mlua = { version = "0", features = ["async", "luau", "send"] } -parking_lot = { version = "0" } tokio = { version = "1", features = ["macros"] } +futures = "0" diff --git a/src/commands.rs b/src/commands.rs index 4015952..d6c68c5 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -7,7 +7,7 @@ use azalea::{ prelude::*, }; use bevy_ecs::{entity::Entity, query::With}; -use parking_lot::Mutex; +use futures::lock::Mutex; pub type Ctx<'a> = CommandContext>; @@ -40,35 +40,43 @@ impl CommandSource { pub fn register(commands: &mut CommandDispatcher>) { commands.register(literal("reload").executes(|ctx: &Ctx| { - let source = ctx.source.lock(); - source.reply(&format!("{:?}", reload(&source.state.lua.lock()))); + let source = ctx.source.clone(); + tokio::spawn(async move { + let source = source.lock().await; + source.reply(&format!("{:?}", reload(&source.state.lua))); + }); 1 })); commands.register( literal("eval").then(argument("code", string()).executes(|ctx: &Ctx| { - let source = ctx.source.lock(); - source.reply(&format!( - "{:?}", - eval(&source.state.lua.lock(), &get_string(ctx, "code").unwrap()) - )); + let source = ctx.source.clone(); + let code = get_string(ctx, "code").unwrap(); + tokio::spawn(async move { + let source = source.lock().await; + source.reply(&format!("{:?}", eval(&source.state.lua, &code).await)); + }); 1 })), ); commands.register( literal("exec").then(argument("code", string()).executes(|ctx: &Ctx| { - let source = ctx.source.lock(); - source.reply(&format!( - "{:?}", - exec(&source.state.lua.lock(), &get_string(ctx, "code").unwrap()) - )); + let source = ctx.source.clone(); + let code = get_string(ctx, "code").unwrap(); + tokio::spawn(async move { + let source = source.lock().await; + source.reply(&format!("{:?}", exec(&source.state.lua, &code).await)); + }); 1 })), ); commands.register(literal("ping").executes(|ctx: &Ctx| { - ctx.source.lock().reply("pong!"); + let source = ctx.source.clone(); + tokio::spawn(async move { + source.lock().await.reply("pong!"); + }); 1 })); } diff --git a/src/events.rs b/src/events.rs index 8952ec7..a0a31d2 100644 --- a/src/events.rs +++ b/src/events.rs @@ -7,7 +7,7 @@ use mlua::{Function, IntoLuaMulti, Table}; use tokio::net::TcpListener; pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow::Result<()> { - let globals = state.lua.lock().globals(); + let globals = state.lua.globals(); match event { Event::Chat(message) => { @@ -40,7 +40,7 @@ pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow: call_lua_handler(&globals, "on_chat", ()); } Event::Death(Some(packet)) => { - let death_data = state.lua.lock().create_table()?; + let death_data = state.lua.create_table()?; death_data.set("message", packet.message.to_string())?; death_data.set("player_id", packet.player_id)?; diff --git a/src/http.rs b/src/http.rs index a57a5ff..67953b6 100644 --- a/src/http.rs +++ b/src/http.rs @@ -12,7 +12,7 @@ pub async fn serve( let path = request.uri().path().to_owned(); Ok(match (request.method(), path.as_str()) { - (&Method::POST, "/reload") => match reload(&state.lua.lock()) { + (&Method::POST, "/reload") => match reload(&state.lua) { Ok(()) => Response::new(empty()), Err(error) => status_code_response( StatusCode::INTERNAL_SERVER_ERROR, @@ -23,14 +23,11 @@ pub async fn serve( (&Method::POST, "/eval" | "/exec") => { let bytes = request.into_body().collect().await?.to_bytes(); match std::str::from_utf8(&bytes) { - Ok(code) => { - let lua = state.lua.lock(); - Response::new(full(match path.as_str() { - "/eval" => format!("{:?}", eval(&lua, code)), - "/exec" => format!("{:?}", exec(&lua, code)), - _ => unreachable!(), - })) - } + Ok(code) => Response::new(full(match path.as_str() { + "/eval" => format!("{:?}", eval(&state.lua, code).await), + "/exec" => format!("{:?}", exec(&state.lua, code).await), + _ => unreachable!(), + })), Err(error) => status_code_response( StatusCode::BAD_REQUEST, full(format!("invalid utf-8 data received: {error:?}")), diff --git a/src/main.rs b/src/main.rs index 28fa6b0..791c852 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,15 +10,15 @@ use azalea::{brigadier::prelude::CommandDispatcher, prelude::*}; use clap::Parser; use commands::{CommandSource, register}; use events::handle_event; +use futures::lock::Mutex; use mlua::Lua; -use parking_lot::Mutex; use std::{net::SocketAddr, path::PathBuf, sync::Arc}; #[derive(Default, Clone, Component)] pub struct State { - commands: Arc>>, - lua: Arc>, + lua: Lua, http_address: Option, + commands: Arc>>, } #[tokio::main] @@ -42,9 +42,9 @@ async fn main() -> anyhow::Result<()> { let Err(error) = ClientBuilder::new() .set_handler(handle_event) .set_state(State { - commands: Arc::new(commands), - lua: Arc::new(Mutex::new(lua)), + lua, http_address: args.http_address, + commands: Arc::new(commands), }) .start( if username.contains('@') { diff --git a/src/scripting/mod.rs b/src/scripting/mod.rs index e4b1a84..c1b67f4 100644 --- a/src/scripting/mod.rs +++ b/src/scripting/mod.rs @@ -28,10 +28,13 @@ pub fn reload(lua: &Lua) -> Result<(), Error> { .map_err(Error::LoadChunk) } -pub fn eval(lua: &Lua, code: &str) -> Result { - lua.load(code).eval::().map_err(Error::EvalChunk) +pub async fn eval(lua: &Lua, code: &str) -> Result { + lua.load(code) + .eval_async::() + .await + .map_err(Error::EvalChunk) } -pub fn exec(lua: &Lua, code: &str) -> Result<(), Error> { - lua.load(code).exec().map_err(Error::ExecChunk) +pub async fn exec(lua: &Lua, code: &str) -> Result<(), Error> { + lua.load(code).exec_async().await.map_err(Error::ExecChunk) } From 8e89f8e9ea1d8ec7d7934a284f4a3570862c611a Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Sun, 16 Feb 2025 14:21:29 -0500 Subject: [PATCH 08/35] feat(client): add remaining miscellaneous fields and methods --- src/main.rs | 2 +- src/scripting/client/interaction.rs | 22 +++++ src/scripting/client/mod.rs | 107 +++++++++++++++++++++---- src/scripting/client/movement.rs | 90 +++++++++++++++++++++ src/scripting/client/pathfinding.rs | 22 ----- src/scripting/direction.rs | 33 ++++++++ src/scripting/entity.rs | 4 +- src/scripting/hunger.rs | 33 ++++++++ src/scripting/logging.rs | 3 +- src/scripting/mod.rs | 18 ++++- src/scripting/{position.rs => vec3.rs} | 6 +- 11 files changed, 292 insertions(+), 48 deletions(-) create mode 100644 src/scripting/client/interaction.rs create mode 100644 src/scripting/client/movement.rs delete mode 100644 src/scripting/client/pathfinding.rs create mode 100644 src/scripting/direction.rs create mode 100644 src/scripting/hunger.rs rename src/scripting/{position.rs => vec3.rs} (91%) diff --git a/src/main.rs b/src/main.rs index 791c852..b882784 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,7 +34,7 @@ async fn main() -> anyhow::Result<()> { let username = globals.get::("USERNAME")?; globals.set("script_path", script_path)?; - scripting::logging::register(&lua, &globals)?; + scripting::register_functions(&lua, &globals)?; let mut commands = CommandDispatcher::new(); register(&mut commands); diff --git a/src/scripting/client/interaction.rs b/src/scripting/client/interaction.rs new file mode 100644 index 0000000..3345242 --- /dev/null +++ b/src/scripting/client/interaction.rs @@ -0,0 +1,22 @@ +use super::{Client, Vec3}; +use azalea::{BlockPos, world::MinecraftEntityId}; +use mlua::{Lua, Result}; + +pub fn attack(_lua: &Lua, client: &mut Client, entity_id: u32) -> Result<()> { + client + .inner + .as_mut() + .unwrap() + .attack(MinecraftEntityId(entity_id)); + Ok(()) +} + +pub fn block_interact(_lua: &Lua, client: &mut Client, position: Vec3) -> Result<()> { + #[allow(clippy::cast_possible_truncation)] + client.inner.as_mut().unwrap().block_interact(BlockPos::new( + position.x as i32, + position.y as i32, + position.z as i32, + )); + Ok(()) +} diff --git a/src/scripting/client/mod.rs b/src/scripting/client/mod.rs index ff3f7c9..9c92473 100644 --- a/src/scripting/client/mod.rs +++ b/src/scripting/client/mod.rs @@ -1,36 +1,104 @@ -mod pathfinding; +mod interaction; +mod movement; mod state; -use super::{entity::Entity, position::Position}; +use super::{direction::Direction, entity::Entity, hunger::Hunger, vec3::Vec3}; use azalea::{ Client as AzaleaClient, ecs::query::Without, - entity::{Dead, EntityKind, EntityUuid, Position as AzaleaPosition, metadata::CustomName}, + entity::{ + Dead, EntityKind, EntityUuid, Position as AzaleaPosition, + metadata::{AirSupply, CustomName, Score}, + }, world::MinecraftEntityId, }; -use mlua::{Function, Lua, Result, UserData}; +use mlua::{Function, Lua, Result, UserData, UserDataFields, UserDataMethods}; pub struct Client { pub inner: Option, } impl UserData for Client { - fn add_fields>(fields: &mut F) { - fields.add_field_method_get("position", |_, this| { - let position = this.inner.as_ref().unwrap().position(); - Ok(Position { - x: position.x, - y: position.y, - z: position.z, + fn add_fields>(f: &mut F) { + f.add_field_method_get("air_supply", |_, this| { + Ok(this.inner.as_ref().unwrap().component::().0) + }); + + f.add_field_method_get("direction", |_, this| { + let d = this.inner.as_ref().unwrap().direction(); + Ok(Direction { x: d.0, y: d.1 }) + }); + + f.add_field_method_get("eye_position", |_, this| { + let p = this.inner.as_ref().unwrap().eye_position(); + Ok(Vec3 { + x: p.x, + y: p.y, + z: p.z, }) }); + + f.add_field_method_get("health", |_, this| { + Ok(this.inner.as_ref().unwrap().health()) + }); + + f.add_field_method_get("hunger", |_, this| { + let h = this.inner.as_ref().unwrap().hunger(); + Ok(Hunger { + food: h.food, + saturation: h.saturation, + }) + }); + + f.add_field_method_get("position", |_, this| { + let p = this.inner.as_ref().unwrap().position(); + Ok(Vec3 { + x: p.x, + y: p.y, + z: p.z, + }) + }); + + f.add_field_method_get("score", |_, this| { + Ok(this.inner.as_ref().unwrap().component::().0) + }); + + f.add_field_method_get("tab_list", |lua, this| { + let tab_list = lua.create_table()?; + for (uuid, player_info) in this.inner.as_ref().unwrap().tab_list() { + let player = lua.create_table()?; + player.set("gamemode", player_info.gamemode.name())?; + player.set("latency", player_info.latency)?; + player.set("name", player_info.profile.name)?; + player.set( + "display_name", + player_info.display_name.map(|n| n.to_string()), + )?; + tab_list.set(uuid.to_string(), player)?; + } + Ok(tab_list) + }); + + f.add_field_method_get("uuid", |_, this| { + Ok(this.inner.as_ref().unwrap().uuid().to_string()) + }); } - fn add_methods>(methods: &mut M) { - methods.add_async_method("set_client_information", state::set_client_information); - methods.add_method("find_entities", find_entities); - methods.add_method("stop_pathfinding", pathfinding::stop_pathfinding); - methods.add_method_mut("goto", pathfinding::goto); + fn add_methods>(m: &mut M) { + m.add_async_method("set_client_information", state::set_client_information); + m.add_method("chat", chat); + m.add_method("find_entities", find_entities); + m.add_method("stop_pathfinding", movement::stop_pathfinding); + m.add_method_mut("attack", interaction::attack); + m.add_method_mut("block_interact", interaction::block_interact); + m.add_method_mut("goto", movement::goto); + m.add_method_mut("goto_without_mining", movement::goto_without_mining); + m.add_method_mut("jump", movement::jump); + m.add_method_mut("look_at", movement::look_at); + m.add_method_mut("set_direction", movement::set_direction); + m.add_method_mut("set_jumping", movement::set_jumping); + m.add_method_mut("sprint", movement::sprint); + m.add_method_mut("walk", movement::walk); } } @@ -51,7 +119,7 @@ fn find_entities(_lua: &Lua, client: &Client, filter_fn: Function) -> Result Result Result<()> { + client.inner.as_ref().unwrap().chat(&message); + Ok(()) +} diff --git a/src/scripting/client/movement.rs b/src/scripting/client/movement.rs new file mode 100644 index 0000000..52616a8 --- /dev/null +++ b/src/scripting/client/movement.rs @@ -0,0 +1,90 @@ +use super::{Client, Vec3}; +use azalea::{ + BlockPos, SprintDirection, WalkDirection, pathfinder::goals::BlockPosGoal, prelude::*, +}; +use mlua::{Lua, Result}; + +pub fn stop_pathfinding(_lua: &Lua, client: &Client, _: ()) -> Result<()> { + client.inner.as_ref().unwrap().stop_pathfinding(); + Ok(()) +} + +pub fn goto(_lua: &Lua, client: &mut Client, position: Vec3) -> Result<()> { + #[allow(clippy::cast_possible_truncation)] + client + .inner + .as_ref() + .unwrap() + .goto(BlockPosGoal(BlockPos::new( + position.x as i32, + position.y as i32, + position.z as i32, + ))); + Ok(()) +} + +pub fn goto_without_mining(_lua: &Lua, client: &mut Client, position: Vec3) -> Result<()> { + #[allow(clippy::cast_possible_truncation)] + client + .inner + .as_ref() + .unwrap() + .goto_without_mining(BlockPosGoal(BlockPos::new( + position.x as i32, + position.y as i32, + position.z as i32, + ))); + Ok(()) +} + +pub fn jump(_lua: &Lua, client: &mut Client, _: ()) -> Result<()> { + client.inner.as_mut().unwrap().jump(); + Ok(()) +} + +pub fn look_at(_lua: &Lua, client: &mut Client, position: Vec3) -> Result<()> { + client + .inner + .as_mut() + .unwrap() + .look_at(azalea::Vec3::new(position.x, position.y, position.z)); + Ok(()) +} + +pub fn set_direction(_lua: &Lua, client: &mut Client, direction: (f32, f32)) -> Result<()> { + client + .inner + .as_mut() + .unwrap() + .set_direction(direction.0, direction.1); + Ok(()) +} + +pub fn set_jumping(_lua: &Lua, client: &mut Client, jumping: bool) -> Result<()> { + client.inner.as_mut().unwrap().set_jumping(jumping); + Ok(()) +} + +pub fn sprint(_lua: &Lua, client: &mut Client, direction: u8) -> Result<()> { + client.inner.as_mut().unwrap().sprint(match direction { + 5 => SprintDirection::ForwardRight, + 6 => SprintDirection::ForwardLeft, + _ => SprintDirection::Forward, + }); + Ok(()) +} + +pub fn walk(_lua: &Lua, client: &mut Client, direction: u8) -> Result<()> { + client.inner.as_mut().unwrap().walk(match direction { + 1 => WalkDirection::Forward, + 2 => WalkDirection::Backward, + 3 => WalkDirection::Left, + 4 => WalkDirection::Right, + 5 => WalkDirection::ForwardRight, + 6 => WalkDirection::ForwardLeft, + 7 => WalkDirection::BackwardRight, + 8 => WalkDirection::BackwardLeft, + _ => WalkDirection::None, + }); + Ok(()) +} diff --git a/src/scripting/client/pathfinding.rs b/src/scripting/client/pathfinding.rs deleted file mode 100644 index 95fe164..0000000 --- a/src/scripting/client/pathfinding.rs +++ /dev/null @@ -1,22 +0,0 @@ -use super::{Client, Position}; -use azalea::{BlockPos, pathfinder::goals::BlockPosGoal, prelude::*}; -use mlua::{Lua, Result}; - -pub fn goto(_lua: &Lua, client: &mut Client, position: Position) -> Result<()> { - #[allow(clippy::cast_possible_truncation)] - client - .inner - .as_ref() - .unwrap() - .goto(BlockPosGoal(BlockPos::new( - position.x as i32, - position.y as i32, - position.z as i32, - ))); - Ok(()) -} - -pub fn stop_pathfinding(_lua: &Lua, client: &Client, _: ()) -> Result<()> { - client.inner.as_ref().unwrap().stop_pathfinding(); - Ok(()) -} diff --git a/src/scripting/direction.rs b/src/scripting/direction.rs new file mode 100644 index 0000000..c58153e --- /dev/null +++ b/src/scripting/direction.rs @@ -0,0 +1,33 @@ +use mlua::{FromLua, IntoLua, Lua, Result, Value}; + +#[derive(Clone)] +pub struct Direction { + pub x: f32, + pub y: f32, +} + +impl IntoLua for Direction { + fn into_lua(self, lua: &Lua) -> Result { + let table = lua.create_table()?; + table.set("x", self.x)?; + table.set("y", self.y)?; + Ok(Value::Table(table)) + } +} + +impl FromLua for Direction { + fn from_lua(value: Value, _lua: &Lua) -> Result { + if let Value::Table(table) = value { + Ok(Self { + x: table.get("x")?, + y: table.get("y")?, + }) + } else { + Err(mlua::Error::FromLuaConversionError { + from: value.type_name(), + to: "Direction".to_string(), + message: None, + }) + } + } +} diff --git a/src/scripting/entity.rs b/src/scripting/entity.rs index d74a9e6..8d8a881 100644 --- a/src/scripting/entity.rs +++ b/src/scripting/entity.rs @@ -1,4 +1,4 @@ -use super::position::Position; +use super::vec3::Vec3; use mlua::{FromLua, IntoLua, Lua, Result, Value}; #[derive(Clone)] @@ -6,7 +6,7 @@ pub struct Entity { pub id: u32, pub uuid: String, pub kind: String, - pub position: Position, + pub position: Vec3, pub custom_name: Option, } diff --git a/src/scripting/hunger.rs b/src/scripting/hunger.rs new file mode 100644 index 0000000..fd74f59 --- /dev/null +++ b/src/scripting/hunger.rs @@ -0,0 +1,33 @@ +use mlua::{FromLua, IntoLua, Lua, Result, Value}; + +#[derive(Clone)] +pub struct Hunger { + pub food: u32, + pub saturation: f32, +} + +impl IntoLua for Hunger { + fn into_lua(self, lua: &Lua) -> Result { + let table = lua.create_table()?; + table.set("food", self.food)?; + table.set("saturation", self.saturation)?; + Ok(Value::Table(table)) + } +} + +impl FromLua for Hunger { + fn from_lua(value: Value, _lua: &Lua) -> Result { + if let Value::Table(table) = value { + Ok(Self { + food: table.get("food")?, + saturation: table.get("saturation")?, + }) + } else { + Err(mlua::Error::FromLuaConversionError { + from: value.type_name(), + to: "Hunger".to_string(), + message: None, + }) + } + } +} diff --git a/src/scripting/logging.rs b/src/scripting/logging.rs index c0c78e9..ed073a4 100644 --- a/src/scripting/logging.rs +++ b/src/scripting/logging.rs @@ -1,7 +1,7 @@ use log::{debug, error, info, trace, warn}; use mlua::{Lua, Result, Table}; -pub fn register(lua: &Lua, globals: &Table) -> Result<()> { +pub fn register_functions(lua: &Lua, globals: &Table) -> Result<()> { globals.set( "error", lua.create_function(|_, message: String| { @@ -37,5 +37,6 @@ pub fn register(lua: &Lua, globals: &Table) -> Result<()> { Ok(()) })?, )?; + Ok(()) } diff --git a/src/scripting/mod.rs b/src/scripting/mod.rs index c1b67f4..10f71b2 100644 --- a/src/scripting/mod.rs +++ b/src/scripting/mod.rs @@ -1,9 +1,11 @@ pub mod client; +pub mod direction; pub mod entity; +pub mod hunger; pub mod logging; -pub mod position; +pub mod vec3; -use mlua::Lua; +use mlua::{Lua, Table}; #[derive(Debug)] #[allow(dead_code)] @@ -15,6 +17,18 @@ pub enum Error { ReadFile(std::io::Error), } +pub fn register_functions(lua: &Lua, globals: &Table) -> mlua::Result<()> { + globals.set( + "sleep", + lua.create_async_function(async |_, duration: u64| { + tokio::time::sleep(std::time::Duration::from_millis(duration)).await; + Ok(()) + })?, + )?; + + logging::register_functions(lua, globals) +} + pub fn reload(lua: &Lua) -> Result<(), Error> { lua.load( &std::fs::read_to_string( diff --git a/src/scripting/position.rs b/src/scripting/vec3.rs similarity index 91% rename from src/scripting/position.rs rename to src/scripting/vec3.rs index 16df16e..45cdbe5 100644 --- a/src/scripting/position.rs +++ b/src/scripting/vec3.rs @@ -1,13 +1,13 @@ use mlua::{FromLua, IntoLua, Lua, Result, Value}; #[derive(Clone)] -pub struct Position { +pub struct Vec3 { pub x: f64, pub y: f64, pub z: f64, } -impl IntoLua for Position { +impl IntoLua for Vec3 { fn into_lua(self, lua: &Lua) -> Result { let table = lua.create_table()?; table.set("x", self.x)?; @@ -17,7 +17,7 @@ impl IntoLua for Position { } } -impl FromLua for Position { +impl FromLua for Vec3 { fn from_lua(value: Value, _lua: &Lua) -> Result { if let Value::Table(table) = value { Ok(Self { From 04b0bdd756ef5fcf0ef625038c91806c5e7cbb11 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Sun, 16 Feb 2025 18:21:06 -0500 Subject: [PATCH 09/35] feat(client): add world interaction methods --- src/scripting/block.rs | 48 +++++++++++++ src/scripting/client/mod.rs | 54 ++++---------- src/scripting/client/world.rs | 132 ++++++++++++++++++++++++++++++++++ src/scripting/fluid_state.rs | 36 ++++++++++ src/scripting/mod.rs | 2 + 5 files changed, 230 insertions(+), 42 deletions(-) create mode 100644 src/scripting/block.rs create mode 100644 src/scripting/client/world.rs create mode 100644 src/scripting/fluid_state.rs diff --git a/src/scripting/block.rs b/src/scripting/block.rs new file mode 100644 index 0000000..25c8cd0 --- /dev/null +++ b/src/scripting/block.rs @@ -0,0 +1,48 @@ +use mlua::{FromLua, IntoLua, Lua, Result, Value}; + +#[derive(Clone)] +pub struct Block { + pub id: String, + pub friction: f32, + pub jump_factor: f32, + pub destroy_time: f32, + pub explosion_resistance: f32, + pub requires_correct_tool_for_drops: bool, +} + +impl IntoLua for Block { + fn into_lua(self, lua: &Lua) -> Result { + let table = lua.create_table()?; + table.set("id", self.id)?; + table.set("friction", self.friction)?; + table.set("jump_factor", self.jump_factor)?; + table.set("destroy_time", self.destroy_time)?; + table.set("explosion_resistance", self.explosion_resistance)?; + table.set( + "requires_correct_tool_for_drops", + self.requires_correct_tool_for_drops, + )?; + Ok(Value::Table(table)) + } +} + +impl FromLua for Block { + fn from_lua(value: Value, _lua: &Lua) -> Result { + if let Value::Table(table) = value { + Ok(Self { + id: table.get("id")?, + friction: table.get("friction")?, + jump_factor: table.get("jump_factor")?, + destroy_time: table.get("destroy_time")?, + explosion_resistance: table.get("explosion_resistance")?, + requires_correct_tool_for_drops: table.get("requires_correct_tool_for_drops")?, + }) + } else { + Err(mlua::Error::FromLuaConversionError { + from: value.type_name(), + to: "Block".to_string(), + message: None, + }) + } + } +} diff --git a/src/scripting/client/mod.rs b/src/scripting/client/mod.rs index 9c92473..bce4b44 100644 --- a/src/scripting/client/mod.rs +++ b/src/scripting/client/mod.rs @@ -1,18 +1,17 @@ mod interaction; mod movement; mod state; +mod world; -use super::{direction::Direction, entity::Entity, hunger::Hunger, vec3::Vec3}; +use super::{ + block::Block, direction::Direction, entity::Entity, fluid_state::FluidState, hunger::Hunger, + vec3::Vec3, +}; use azalea::{ Client as AzaleaClient, - ecs::query::Without, - entity::{ - Dead, EntityKind, EntityUuid, Position as AzaleaPosition, - metadata::{AirSupply, CustomName, Score}, - }, - world::MinecraftEntityId, + entity::metadata::{AirSupply, Score}, }; -use mlua::{Function, Lua, Result, UserData, UserDataFields, UserDataMethods}; +use mlua::{Lua, Result, UserData, UserDataFields, UserDataMethods}; pub struct Client { pub inner: Option, @@ -87,7 +86,11 @@ impl UserData for Client { fn add_methods>(m: &mut M) { m.add_async_method("set_client_information", state::set_client_information); m.add_method("chat", chat); - m.add_method("find_entities", find_entities); + m.add_method("find_blocks", world::find_blocks); + m.add_method("find_entities", world::find_entities); + m.add_method("get_block_from_state", world::get_block_from_state); + m.add_method("get_block_state", world::get_block_state); + m.add_method("get_fluid_state", world::get_fluid_state); m.add_method("stop_pathfinding", movement::stop_pathfinding); m.add_method_mut("attack", interaction::attack); m.add_method_mut("block_interact", interaction::block_interact); @@ -102,39 +105,6 @@ impl UserData for Client { } } -fn find_entities(_lua: &Lua, client: &Client, filter_fn: Function) -> Result> { - let mut matched = Vec::new(); - - let mut ecs = client.inner.as_ref().unwrap().ecs.lock(); - let mut query = ecs.query_filtered::<( - &MinecraftEntityId, - &EntityUuid, - &EntityKind, - &AzaleaPosition, - &CustomName, - ), Without>(); - - for (&id, uuid, kind, position, custom_name) in query.iter(&ecs) { - let entity = Entity { - id: id.0, - uuid: uuid.to_string(), - kind: kind.to_string(), - position: Vec3 { - x: position.x, - y: position.y, - z: position.z, - }, - custom_name: custom_name.as_ref().map(ToString::to_string), - }; - - if filter_fn.call::(entity.clone()).unwrap() { - matched.push(entity); - } - } - - Ok(matched) -} - fn chat(_lua: &Lua, client: &Client, message: String) -> Result<()> { client.inner.as_ref().unwrap().chat(&message); Ok(()) diff --git a/src/scripting/client/world.rs b/src/scripting/client/world.rs new file mode 100644 index 0000000..53d0135 --- /dev/null +++ b/src/scripting/client/world.rs @@ -0,0 +1,132 @@ +use super::{Block, Client, Entity, FluidState, Vec3}; +use azalea::{ + BlockPos, + blocks::{Block as AzaleaBlock, BlockState, BlockStates}, + ecs::query::Without, + entity::{Dead, EntityKind, EntityUuid, Position as AzaleaPosition, metadata::CustomName}, + world::MinecraftEntityId, +}; +use mlua::{Function, Lua, Result}; + +pub fn find_blocks( + _lua: &Lua, + client: &Client, + (nearest_to, block_names): (Vec3, Vec), +) -> Result> { + #[allow(clippy::cast_possible_truncation)] + Ok(client + .inner + .as_ref() + .unwrap() + .world() + .read() + .find_blocks( + BlockPos::new( + nearest_to.x as i32, + nearest_to.y as i32, + nearest_to.z as i32, + ), + &BlockStates { + set: block_names + .iter() + .flat_map(|n| { + (u32::MIN..u32::MAX) + .map_while(|i| BlockState::try_from(i).ok()) + .filter(move |&b| n == Into::>::into(b).id()) + }) + .collect(), + }, + ) + .map(|p| Vec3 { + x: f64::from(p.x), + y: f64::from(p.y), + z: f64::from(p.z), + }) + .collect()) +} + +pub fn find_entities(_lua: &Lua, client: &Client, filter_fn: Function) -> Result> { + let mut matched = Vec::new(); + + let mut ecs = client.inner.as_ref().unwrap().ecs.lock(); + let mut query = ecs.query_filtered::<( + &MinecraftEntityId, + &EntityUuid, + &EntityKind, + &AzaleaPosition, + &CustomName, + ), Without>(); + + for (&id, uuid, kind, position, custom_name) in query.iter(&ecs) { + let entity = Entity { + id: id.0, + uuid: uuid.to_string(), + kind: kind.to_string(), + position: Vec3 { + x: position.x, + y: position.y, + z: position.z, + }, + custom_name: custom_name.as_ref().map(ToString::to_string), + }; + + if filter_fn.call::(entity.clone()).unwrap() { + matched.push(entity); + } + } + + Ok(matched) +} + +pub fn get_block_from_state(_lua: &Lua, _client: &Client, state: u32) -> Result> { + let Ok(state) = BlockState::try_from(state) else { + return Ok(None); + }; + let block: Box = state.into(); + let behavior = block.behavior(); + + Ok(Some(Block { + id: block.id().to_string(), + friction: behavior.friction, + jump_factor: behavior.jump_factor, + destroy_time: behavior.destroy_time, + explosion_resistance: behavior.explosion_resistance, + requires_correct_tool_for_drops: behavior.requires_correct_tool_for_drops, + })) +} + +pub fn get_block_state(_lua: &Lua, client: &Client, position: Vec3) -> Result> { + #[allow(clippy::cast_possible_truncation)] + Ok(client + .inner + .as_ref() + .unwrap() + .world() + .read() + .get_block_state(&BlockPos::new( + position.x as i32, + position.y as i32, + position.z as i32, + )) + .map(|b| b.id)) +} + +pub fn get_fluid_state(_lua: &Lua, client: &Client, position: Vec3) -> Result> { + #[allow(clippy::cast_possible_truncation)] + Ok(client + .inner + .as_ref() + .unwrap() + .world() + .read() + .get_fluid_state(&BlockPos::new( + position.x as i32, + position.y as i32, + position.z as i32, + )) + .map(|f| FluidState { + kind: f.kind as u8, + amount: f.amount, + falling: f.falling, + })) +} diff --git a/src/scripting/fluid_state.rs b/src/scripting/fluid_state.rs new file mode 100644 index 0000000..6233f75 --- /dev/null +++ b/src/scripting/fluid_state.rs @@ -0,0 +1,36 @@ +use mlua::{FromLua, IntoLua, Lua, Result, Value}; + +#[derive(Clone)] +pub struct FluidState { + pub kind: u8, + pub amount: u8, + pub falling: bool, +} + +impl IntoLua for FluidState { + fn into_lua(self, lua: &Lua) -> Result { + let table = lua.create_table()?; + table.set("kind", self.kind)?; + table.set("amount", self.amount)?; + table.set("falling", self.falling)?; + Ok(Value::Table(table)) + } +} + +impl FromLua for FluidState { + fn from_lua(value: Value, _lua: &Lua) -> Result { + if let Value::Table(table) = value { + Ok(Self { + kind: table.get("kind")?, + amount: table.get("amount")?, + falling: table.get("falling")?, + }) + } else { + Err(mlua::Error::FromLuaConversionError { + from: value.type_name(), + to: "FluidState".to_string(), + message: None, + }) + } + } +} diff --git a/src/scripting/mod.rs b/src/scripting/mod.rs index 10f71b2..6b7c54b 100644 --- a/src/scripting/mod.rs +++ b/src/scripting/mod.rs @@ -1,6 +1,8 @@ +pub mod block; pub mod client; pub mod direction; pub mod entity; +pub mod fluid_state; pub mod hunger; pub mod logging; pub mod vec3; From 083dd7f707f41a60da067cdfff7d03197cb788eb Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Sun, 16 Feb 2025 20:13:18 -0500 Subject: [PATCH 10/35] feat(client): add mining methods --- src/scripting/client/interaction.rs | 34 +++++++++++++++++++++++++++-- src/scripting/client/mod.rs | 3 +++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/scripting/client/interaction.rs b/src/scripting/client/interaction.rs index 3345242..7ce34d9 100644 --- a/src/scripting/client/interaction.rs +++ b/src/scripting/client/interaction.rs @@ -1,6 +1,36 @@ use super::{Client, Vec3}; -use azalea::{BlockPos, world::MinecraftEntityId}; -use mlua::{Lua, Result}; +use azalea::{BlockPos, BotClientExt, world::MinecraftEntityId}; +use mlua::{Lua, Result, UserDataRefMut}; + +pub async fn mine(_lua: Lua, mut client: UserDataRefMut, position: Vec3) -> Result<()> { + #[allow(clippy::cast_possible_truncation)] + client + .inner + .as_mut() + .unwrap() + .mine(BlockPos::new( + position.x as i32, + position.y as i32, + position.z as i32, + )) + .await; + Ok(()) +} + +pub fn start_mining(_lua: &Lua, client: &mut Client, position: Vec3) -> Result<()> { + #[allow(clippy::cast_possible_truncation)] + client.inner.as_mut().unwrap().start_mining(BlockPos::new( + position.x as i32, + position.y as i32, + position.z as i32, + )); + Ok(()) +} + +pub fn set_mining(_lua: &Lua, client: &Client, mining: bool) -> Result<()> { + client.inner.as_ref().unwrap().left_click_mine(mining); + Ok(()) +} pub fn attack(_lua: &Lua, client: &mut Client, entity_id: u32) -> Result<()> { client diff --git a/src/scripting/client/mod.rs b/src/scripting/client/mod.rs index bce4b44..64752b5 100644 --- a/src/scripting/client/mod.rs +++ b/src/scripting/client/mod.rs @@ -85,12 +85,14 @@ impl UserData for Client { fn add_methods>(m: &mut M) { m.add_async_method("set_client_information", state::set_client_information); + m.add_async_method_mut("mine", interaction::mine); m.add_method("chat", chat); m.add_method("find_blocks", world::find_blocks); m.add_method("find_entities", world::find_entities); m.add_method("get_block_from_state", world::get_block_from_state); m.add_method("get_block_state", world::get_block_state); m.add_method("get_fluid_state", world::get_fluid_state); + m.add_method("set_mining", interaction::set_mining); m.add_method("stop_pathfinding", movement::stop_pathfinding); m.add_method_mut("attack", interaction::attack); m.add_method_mut("block_interact", interaction::block_interact); @@ -101,6 +103,7 @@ impl UserData for Client { m.add_method_mut("set_direction", movement::set_direction); m.add_method_mut("set_jumping", movement::set_jumping); m.add_method_mut("sprint", movement::sprint); + m.add_method_mut("start_mining", interaction::start_mining); m.add_method_mut("walk", movement::walk); } } From d6abd3fd06d02141fcaff471d4e2787eb970dcf9 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Sun, 16 Feb 2025 20:19:01 -0500 Subject: [PATCH 11/35] feat(client): add looking_at field --- src/scripting/client/mod.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/scripting/client/mod.rs b/src/scripting/client/mod.rs index 64752b5..9f06dd8 100644 --- a/src/scripting/client/mod.rs +++ b/src/scripting/client/mod.rs @@ -10,6 +10,7 @@ use super::{ use azalea::{ Client as AzaleaClient, entity::metadata::{AirSupply, Score}, + interact::HitResultComponent, }; use mlua::{Lua, Result, UserData, UserDataFields, UserDataMethods}; @@ -49,6 +50,30 @@ impl UserData for Client { }) }); + f.add_field_method_get("looking_at", |lua, this| { + let hr = this + .inner + .as_ref() + .unwrap() + .component::(); + Ok(if hr.miss { + None + } else { + let result = lua.create_table()?; + result.set( + "position", + Vec3 { + x: f64::from(hr.block_pos.x), + y: f64::from(hr.block_pos.y), + z: f64::from(hr.block_pos.z), + }, + )?; + result.set("inside", hr.inside)?; + result.set("world_border", hr.world_border)?; + Some(result) + }) + }); + f.add_field_method_get("position", |_, this| { let p = this.inner.as_ref().unwrap().position(); Ok(Vec3 { From 54c6b8c88fcb9627a22ba233ffedd89d725043af Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Sun, 16 Feb 2025 21:26:54 -0500 Subject: [PATCH 12/35] refactor(client/movement): wrap common pathfinder goals --- src/scripting/client/mod.rs | 1 - src/scripting/client/movement.rs | 110 ++++++++++++++++++++++++------- 2 files changed, 85 insertions(+), 26 deletions(-) diff --git a/src/scripting/client/mod.rs b/src/scripting/client/mod.rs index 9f06dd8..8ba98ee 100644 --- a/src/scripting/client/mod.rs +++ b/src/scripting/client/mod.rs @@ -122,7 +122,6 @@ impl UserData for Client { m.add_method_mut("attack", interaction::attack); m.add_method_mut("block_interact", interaction::block_interact); m.add_method_mut("goto", movement::goto); - m.add_method_mut("goto_without_mining", movement::goto_without_mining); m.add_method_mut("jump", movement::jump); m.add_method_mut("look_at", movement::look_at); m.add_method_mut("set_direction", movement::set_direction); diff --git a/src/scripting/client/movement.rs b/src/scripting/client/movement.rs index 52616a8..f1b40f1 100644 --- a/src/scripting/client/movement.rs +++ b/src/scripting/client/movement.rs @@ -1,39 +1,99 @@ use super::{Client, Vec3}; use azalea::{ - BlockPos, SprintDirection, WalkDirection, pathfinder::goals::BlockPosGoal, prelude::*, + BlockPos, BotClientExt, Client as AzaleaClient, SprintDirection, WalkDirection, + pathfinder::{ + PathfinderClientExt, + goals::{BlockPosGoal, Goal, RadiusGoal, ReachBlockPosGoal, XZGoal, YGoal}, + }, }; -use mlua::{Lua, Result}; +use mlua::{FromLua, Lua, Result, Table, Value}; pub fn stop_pathfinding(_lua: &Lua, client: &Client, _: ()) -> Result<()> { client.inner.as_ref().unwrap().stop_pathfinding(); Ok(()) } -pub fn goto(_lua: &Lua, client: &mut Client, position: Vec3) -> Result<()> { - #[allow(clippy::cast_possible_truncation)] - client - .inner - .as_ref() - .unwrap() - .goto(BlockPosGoal(BlockPos::new( - position.x as i32, - position.y as i32, - position.z as i32, - ))); - Ok(()) -} +pub fn goto( + lua: &Lua, + client: &mut Client, + (data, metadata): (Value, Option
), +) -> Result<()> { + fn g(client: &AzaleaClient, without_mining: bool, goal: impl Goal + Send + Sync + 'static) { + if without_mining { + client.goto_without_mining(goal); + } else { + client.goto(goal); + } + } + + let error = mlua::Error::FromLuaConversionError { + from: data.type_name(), + to: "Table".to_string(), + message: None, + }; + let client = client.inner.as_ref().unwrap(); + let (goal_type, without_mining) = metadata + .map(|t| { + ( + t.get("type").unwrap_or_default(), + t.get("without_mining").unwrap_or_default(), + ) + }) + .unwrap_or_default(); -pub fn goto_without_mining(_lua: &Lua, client: &mut Client, position: Vec3) -> Result<()> { #[allow(clippy::cast_possible_truncation)] - client - .inner - .as_ref() - .unwrap() - .goto_without_mining(BlockPosGoal(BlockPos::new( - position.x as i32, - position.y as i32, - position.z as i32, - ))); + match goal_type { + 1 => { + let t = data.as_table().ok_or(error)?; + let p = Vec3::from_lua(t.get("position")?, lua)?; + g( + client, + without_mining, + RadiusGoal { + pos: azalea::Vec3::new(p.x, p.y, p.z), + radius: t.get("radius")?, + }, + ); + } + 2 => { + let p = Vec3::from_lua(data, lua)?; + g( + client, + without_mining, + ReachBlockPosGoal { + pos: BlockPos::new(p.x as i32, p.y as i32, p.z as i32), + chunk_storage: client.world().read().chunks.clone(), + }, + ); + } + 3 => { + let t = data.as_table().ok_or(error)?; + g( + client, + without_mining, + XZGoal { + x: t.get("x")?, + z: t.get("z")?, + }, + ); + } + 4 => g( + client, + without_mining, + YGoal { + y: data.as_integer().ok_or(error)?, + }, + ), + _ => { + let p = Vec3::from_lua(data, lua)?; + g( + client, + without_mining, + BlockPosGoal(BlockPos::new(p.x as i32, p.y as i32, p.z as i32)), + ); + } + } + Ok(()) } From c65682d273298a26d25f7ced56801610a3f32873 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Sun, 16 Feb 2025 22:22:44 -0500 Subject: [PATCH 13/35] feat(client): add pathfinder field --- src/scripting/client/mod.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/scripting/client/mod.rs b/src/scripting/client/mod.rs index 8ba98ee..94b54d9 100644 --- a/src/scripting/client/mod.rs +++ b/src/scripting/client/mod.rs @@ -11,6 +11,7 @@ use azalea::{ Client as AzaleaClient, entity::metadata::{AirSupply, Score}, interact::HitResultComponent, + pathfinder::{ExecutingPath, Pathfinder}, }; use mlua::{Lua, Result, UserData, UserDataFields, UserDataMethods}; @@ -74,6 +75,37 @@ impl UserData for Client { }) }); + f.add_field_method_get("pathfinder", |lua, this| { + let client = this.inner.as_ref().unwrap(); + let pathfinder = lua.create_table()?; + pathfinder.set( + "is_calculating", + client.component::().is_calculating, + )?; + pathfinder.set( + "is_executing", + if let Some(p) = client.get_component::() { + pathfinder.set( + "last_reached_node", + Vec3 { + x: f64::from(p.last_reached_node.x), + y: f64::from(p.last_reached_node.y), + z: f64::from(p.last_reached_node.z), + }, + )?; + pathfinder.set( + "last_node_reach_elapsed", + p.last_node_reached_at.elapsed().as_millis(), + )?; + pathfinder.set("is_path_partial", p.is_path_partial)?; + true + } else { + false + }, + )?; + Ok(pathfinder) + }); + f.add_field_method_get("position", |_, this| { let p = this.inner.as_ref().unwrap().position(); Ok(Vec3 { From 8547ea04ab3fd5be452d6f06faa41fcfc4b4e2dd Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Sun, 16 Feb 2025 22:41:28 -0500 Subject: [PATCH 14/35] refactor(client): move fields into modules --- src/scripting/client/interaction.rs | 60 +++++------ src/scripting/client/mod.rs | 157 ++++++---------------------- src/scripting/client/movement.rs | 89 +++++++++++++++- src/scripting/client/state.rs | 27 ++++- 4 files changed, 172 insertions(+), 161 deletions(-) diff --git a/src/scripting/client/interaction.rs b/src/scripting/client/interaction.rs index 7ce34d9..a626340 100644 --- a/src/scripting/client/interaction.rs +++ b/src/scripting/client/interaction.rs @@ -2,36 +2,6 @@ use super::{Client, Vec3}; use azalea::{BlockPos, BotClientExt, world::MinecraftEntityId}; use mlua::{Lua, Result, UserDataRefMut}; -pub async fn mine(_lua: Lua, mut client: UserDataRefMut, position: Vec3) -> Result<()> { - #[allow(clippy::cast_possible_truncation)] - client - .inner - .as_mut() - .unwrap() - .mine(BlockPos::new( - position.x as i32, - position.y as i32, - position.z as i32, - )) - .await; - Ok(()) -} - -pub fn start_mining(_lua: &Lua, client: &mut Client, position: Vec3) -> Result<()> { - #[allow(clippy::cast_possible_truncation)] - client.inner.as_mut().unwrap().start_mining(BlockPos::new( - position.x as i32, - position.y as i32, - position.z as i32, - )); - Ok(()) -} - -pub fn set_mining(_lua: &Lua, client: &Client, mining: bool) -> Result<()> { - client.inner.as_ref().unwrap().left_click_mine(mining); - Ok(()) -} - pub fn attack(_lua: &Lua, client: &mut Client, entity_id: u32) -> Result<()> { client .inner @@ -50,3 +20,33 @@ pub fn block_interact(_lua: &Lua, client: &mut Client, position: Vec3) -> Result )); Ok(()) } + +pub async fn mine(_lua: Lua, mut client: UserDataRefMut, position: Vec3) -> Result<()> { + #[allow(clippy::cast_possible_truncation)] + client + .inner + .as_mut() + .unwrap() + .mine(BlockPos::new( + position.x as i32, + position.y as i32, + position.z as i32, + )) + .await; + Ok(()) +} + +pub fn set_mining(_lua: &Lua, client: &Client, mining: bool) -> Result<()> { + client.inner.as_ref().unwrap().left_click_mine(mining); + Ok(()) +} + +pub fn start_mining(_lua: &Lua, client: &mut Client, position: Vec3) -> Result<()> { + #[allow(clippy::cast_possible_truncation)] + client.inner.as_mut().unwrap().start_mining(BlockPos::new( + position.x as i32, + position.y as i32, + position.z as i32, + )); + Ok(()) +} diff --git a/src/scripting/client/mod.rs b/src/scripting/client/mod.rs index 94b54d9..f52c09d 100644 --- a/src/scripting/client/mod.rs +++ b/src/scripting/client/mod.rs @@ -7,13 +7,8 @@ use super::{ block::Block, direction::Direction, entity::Entity, fluid_state::FluidState, hunger::Hunger, vec3::Vec3, }; -use azalea::{ - Client as AzaleaClient, - entity::metadata::{AirSupply, Score}, - interact::HitResultComponent, - pathfinder::{ExecutingPath, Pathfinder}, -}; -use mlua::{Lua, Result, UserData, UserDataFields, UserDataMethods}; +use azalea::Client as AzaleaClient; +use mlua::{Lua, Result, Table, UserData, UserDataFields, UserDataMethods}; pub struct Client { pub inner: Option, @@ -21,123 +16,17 @@ pub struct Client { impl UserData for Client { fn add_fields>(f: &mut F) { - f.add_field_method_get("air_supply", |_, this| { - Ok(this.inner.as_ref().unwrap().component::().0) - }); - - f.add_field_method_get("direction", |_, this| { - let d = this.inner.as_ref().unwrap().direction(); - Ok(Direction { x: d.0, y: d.1 }) - }); - - f.add_field_method_get("eye_position", |_, this| { - let p = this.inner.as_ref().unwrap().eye_position(); - Ok(Vec3 { - x: p.x, - y: p.y, - z: p.z, - }) - }); - - f.add_field_method_get("health", |_, this| { - Ok(this.inner.as_ref().unwrap().health()) - }); - - f.add_field_method_get("hunger", |_, this| { - let h = this.inner.as_ref().unwrap().hunger(); - Ok(Hunger { - food: h.food, - saturation: h.saturation, - }) - }); - - f.add_field_method_get("looking_at", |lua, this| { - let hr = this - .inner - .as_ref() - .unwrap() - .component::(); - Ok(if hr.miss { - None - } else { - let result = lua.create_table()?; - result.set( - "position", - Vec3 { - x: f64::from(hr.block_pos.x), - y: f64::from(hr.block_pos.y), - z: f64::from(hr.block_pos.z), - }, - )?; - result.set("inside", hr.inside)?; - result.set("world_border", hr.world_border)?; - Some(result) - }) - }); - - f.add_field_method_get("pathfinder", |lua, this| { - let client = this.inner.as_ref().unwrap(); - let pathfinder = lua.create_table()?; - pathfinder.set( - "is_calculating", - client.component::().is_calculating, - )?; - pathfinder.set( - "is_executing", - if let Some(p) = client.get_component::() { - pathfinder.set( - "last_reached_node", - Vec3 { - x: f64::from(p.last_reached_node.x), - y: f64::from(p.last_reached_node.y), - z: f64::from(p.last_reached_node.z), - }, - )?; - pathfinder.set( - "last_node_reach_elapsed", - p.last_node_reached_at.elapsed().as_millis(), - )?; - pathfinder.set("is_path_partial", p.is_path_partial)?; - true - } else { - false - }, - )?; - Ok(pathfinder) - }); - - f.add_field_method_get("position", |_, this| { - let p = this.inner.as_ref().unwrap().position(); - Ok(Vec3 { - x: p.x, - y: p.y, - z: p.z, - }) - }); - - f.add_field_method_get("score", |_, this| { - Ok(this.inner.as_ref().unwrap().component::().0) - }); - - f.add_field_method_get("tab_list", |lua, this| { - let tab_list = lua.create_table()?; - for (uuid, player_info) in this.inner.as_ref().unwrap().tab_list() { - let player = lua.create_table()?; - player.set("gamemode", player_info.gamemode.name())?; - player.set("latency", player_info.latency)?; - player.set("name", player_info.profile.name)?; - player.set( - "display_name", - player_info.display_name.map(|n| n.to_string()), - )?; - tab_list.set(uuid.to_string(), player)?; - } - Ok(tab_list) - }); - - f.add_field_method_get("uuid", |_, this| { - Ok(this.inner.as_ref().unwrap().uuid().to_string()) - }); + f.add_field_method_get("air_supply", state::air_supply); + f.add_field_method_get("direction", movement::direction); + f.add_field_method_get("eye_position", movement::eye_position); + f.add_field_method_get("health", state::health); + f.add_field_method_get("hunger", state::hunger); + f.add_field_method_get("looking_at", movement::looking_at); + f.add_field_method_get("pathfinder", movement::pathfinder); + f.add_field_method_get("position", movement::position); + f.add_field_method_get("score", state::score); + f.add_field_method_get("tab_list", tab_list); + f.add_field_method_get("uuid", uuid); } fn add_methods>(m: &mut M) { @@ -164,6 +53,26 @@ impl UserData for Client { } } +fn tab_list(lua: &Lua, client: &Client) -> Result
{ + let tab_list = lua.create_table()?; + for (uuid, player_info) in client.inner.as_ref().unwrap().tab_list() { + let player = lua.create_table()?; + player.set("gamemode", player_info.gamemode.name())?; + player.set("latency", player_info.latency)?; + player.set("name", player_info.profile.name)?; + player.set( + "display_name", + player_info.display_name.map(|n| n.to_string()), + )?; + tab_list.set(uuid.to_string(), player)?; + } + Ok(tab_list) +} + +fn uuid(_lua: &Lua, client: &Client) -> Result { + Ok(client.inner.as_ref().unwrap().uuid().to_string()) +} + fn chat(_lua: &Lua, client: &Client, message: String) -> Result<()> { client.inner.as_ref().unwrap().chat(&message); Ok(()) diff --git a/src/scripting/client/movement.rs b/src/scripting/client/movement.rs index f1b40f1..6025add 100644 --- a/src/scripting/client/movement.rs +++ b/src/scripting/client/movement.rs @@ -1,16 +1,26 @@ -use super::{Client, Vec3}; +use super::{Client, Direction, Vec3}; use azalea::{ BlockPos, BotClientExt, Client as AzaleaClient, SprintDirection, WalkDirection, + interact::HitResultComponent, pathfinder::{ - PathfinderClientExt, + ExecutingPath, Pathfinder, PathfinderClientExt, goals::{BlockPosGoal, Goal, RadiusGoal, ReachBlockPosGoal, XZGoal, YGoal}, }, }; use mlua::{FromLua, Lua, Result, Table, Value}; -pub fn stop_pathfinding(_lua: &Lua, client: &Client, _: ()) -> Result<()> { - client.inner.as_ref().unwrap().stop_pathfinding(); - Ok(()) +pub fn direction(_lua: &Lua, client: &Client) -> Result { + let d = client.inner.as_ref().unwrap().direction(); + Ok(Direction { x: d.0, y: d.1 }) +} + +pub fn eye_position(_lua: &Lua, client: &Client) -> Result { + let p = client.inner.as_ref().unwrap().eye_position(); + Ok(Vec3 { + x: p.x, + y: p.y, + z: p.z, + }) } pub fn goto( @@ -102,6 +112,30 @@ pub fn jump(_lua: &Lua, client: &mut Client, _: ()) -> Result<()> { Ok(()) } +pub fn looking_at(lua: &Lua, client: &Client) -> Result> { + let hr = client + .inner + .as_ref() + .unwrap() + .component::(); + Ok(if hr.miss { + None + } else { + let result = lua.create_table()?; + result.set( + "position", + Vec3 { + x: f64::from(hr.block_pos.x), + y: f64::from(hr.block_pos.y), + z: f64::from(hr.block_pos.z), + }, + )?; + result.set("inside", hr.inside)?; + result.set("world_border", hr.world_border)?; + Some(result) + }) +} + pub fn look_at(_lua: &Lua, client: &mut Client, position: Vec3) -> Result<()> { client .inner @@ -111,6 +145,46 @@ pub fn look_at(_lua: &Lua, client: &mut Client, position: Vec3) -> Result<()> { Ok(()) } +pub fn pathfinder(lua: &Lua, client: &Client) -> Result
{ + let client = client.inner.as_ref().unwrap(); + let pathfinder = lua.create_table()?; + pathfinder.set( + "is_calculating", + client.component::().is_calculating, + )?; + pathfinder.set( + "is_executing", + if let Some(p) = client.get_component::() { + pathfinder.set( + "last_reached_node", + Vec3 { + x: f64::from(p.last_reached_node.x), + y: f64::from(p.last_reached_node.y), + z: f64::from(p.last_reached_node.z), + }, + )?; + pathfinder.set( + "last_node_reach_elapsed", + p.last_node_reached_at.elapsed().as_millis(), + )?; + pathfinder.set("is_path_partial", p.is_path_partial)?; + true + } else { + false + }, + )?; + Ok(pathfinder) +} + +pub fn position(_lua: &Lua, client: &Client) -> Result { + let p = client.inner.as_ref().unwrap().position(); + Ok(Vec3 { + x: p.x, + y: p.y, + z: p.z, + }) +} + pub fn set_direction(_lua: &Lua, client: &mut Client, direction: (f32, f32)) -> Result<()> { client .inner @@ -134,6 +208,11 @@ pub fn sprint(_lua: &Lua, client: &mut Client, direction: u8) -> Result<()> { Ok(()) } +pub fn stop_pathfinding(_lua: &Lua, client: &Client, _: ()) -> Result<()> { + client.inner.as_ref().unwrap().stop_pathfinding(); + Ok(()) +} + pub fn walk(_lua: &Lua, client: &mut Client, direction: u8) -> Result<()> { client.inner.as_mut().unwrap().walk(match direction { 1 => WalkDirection::Forward, diff --git a/src/scripting/client/state.rs b/src/scripting/client/state.rs index cf7af8a..1f7a34a 100644 --- a/src/scripting/client/state.rs +++ b/src/scripting/client/state.rs @@ -1,7 +1,30 @@ -use super::Client; -use azalea::ClientInformation; +use super::{Client, Hunger}; +use azalea::{ + ClientInformation, + entity::metadata::{AirSupply, Score}, +}; use mlua::{Lua, Result, Table, UserDataRef}; +pub fn air_supply(_lua: &Lua, client: &Client) -> Result { + Ok(client.inner.as_ref().unwrap().component::().0) +} + +pub fn health(_lua: &Lua, client: &Client) -> Result { + Ok(client.inner.as_ref().unwrap().health()) +} + +pub fn hunger(_lua: &Lua, client: &Client) -> Result { + let h = client.inner.as_ref().unwrap().hunger(); + Ok(Hunger { + food: h.food, + saturation: h.saturation, + }) +} + +pub fn score(_lua: &Lua, client: &Client) -> Result { + Ok(client.inner.as_ref().unwrap().component::().0) +} + pub async fn set_client_information( _lua: Lua, client: UserDataRef, From fc5ff582c6c7362a3b50152ee7b42d203cba9680 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Sun, 16 Feb 2025 23:54:04 -0500 Subject: [PATCH 15/35] fix(client): clone client in async mut functions --- src/scripting/client/interaction.rs | 6 +++--- src/scripting/client/mod.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/scripting/client/interaction.rs b/src/scripting/client/interaction.rs index a626340..0deb5bc 100644 --- a/src/scripting/client/interaction.rs +++ b/src/scripting/client/interaction.rs @@ -1,6 +1,6 @@ use super::{Client, Vec3}; use azalea::{BlockPos, BotClientExt, world::MinecraftEntityId}; -use mlua::{Lua, Result, UserDataRefMut}; +use mlua::{Lua, Result, UserDataRef}; pub fn attack(_lua: &Lua, client: &mut Client, entity_id: u32) -> Result<()> { client @@ -21,11 +21,11 @@ pub fn block_interact(_lua: &Lua, client: &mut Client, position: Vec3) -> Result Ok(()) } -pub async fn mine(_lua: Lua, mut client: UserDataRefMut, position: Vec3) -> Result<()> { +pub async fn mine(_lua: Lua, client: UserDataRef, position: Vec3) -> Result<()> { #[allow(clippy::cast_possible_truncation)] client .inner - .as_mut() + .clone() .unwrap() .mine(BlockPos::new( position.x as i32, diff --git a/src/scripting/client/mod.rs b/src/scripting/client/mod.rs index f52c09d..794d51f 100644 --- a/src/scripting/client/mod.rs +++ b/src/scripting/client/mod.rs @@ -30,8 +30,8 @@ impl UserData for Client { } fn add_methods>(m: &mut M) { + m.add_async_method("mine", interaction::mine); m.add_async_method("set_client_information", state::set_client_information); - m.add_async_method_mut("mine", interaction::mine); m.add_method("chat", chat); m.add_method("find_blocks", world::find_blocks); m.add_method("find_entities", world::find_entities); From 93348835ac36214f0d5ee2dfffa0c9022758e3f6 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Mon, 17 Feb 2025 01:24:57 -0500 Subject: [PATCH 16/35] chore(lua): add basic functions --- .gitignore | 1 - errornowatcher.lua | 15 +++++++++++++++ lua/enum.lua | 15 +++++++++++++++ lua/events.lua | 20 ++++++++++++++++++++ lua/utils.lua | 30 ++++++++++++++++++++++++++++++ 5 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 errornowatcher.lua create mode 100644 lua/enum.lua create mode 100644 lua/events.lua create mode 100644 lua/utils.lua diff --git a/.gitignore b/.gitignore index 45560fd..7bbd4af 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ -*.lua .luarc.json target diff --git a/errornowatcher.lua b/errornowatcher.lua new file mode 100644 index 0000000..95ef5c5 --- /dev/null +++ b/errornowatcher.lua @@ -0,0 +1,15 @@ +SERVER = "localhost" +USERNAME = "ErrorNoWatcher" +OWNERS = { "ErrorNoInternet" } + +for _, module in + { + "enum", + "events", + "utils", + } +do + module = "lua/" .. module + package.loaded[module] = nil + require(module) +end diff --git a/lua/enum.lua b/lua/enum.lua new file mode 100644 index 0000000..96aadee --- /dev/null +++ b/lua/enum.lua @@ -0,0 +1,15 @@ +NONE = 0 +FORWARD = 1 +BACKWARD = 2 +LEFT = 3 +RIGHT = 4 +FORWARD_LEFT = 5 +FORWARD_RIGHT = 6 +BACKWARD_LEFT = 7 +BACKWARD_RIGHT = 8 + +BLOCK_POS_GOAL = 0 +RADIUS_GOAL = 1 +REACH_BLOCK_POS_GOAL = 2 +XZ_GOAL = 3 +Y_GOAL = 4 diff --git a/lua/events.lua b/lua/events.lua new file mode 100644 index 0000000..a7f4c1f --- /dev/null +++ b/lua/events.lua @@ -0,0 +1,20 @@ +local center = { x = 0, z = 0 } +local radius = 50 + +function on_tick() + local entities = client:find_entities(function(e) + return e.kind == "minecraft:player" + and e.position.x > center.x - radius + 1 + and e.position.x < center.x + radius + and e.position.z > center.z - radius + and e.position.z < center.z + radius + end) + for _, e in entities do + client:chat(string.format("%s (%s) at %.1f %.1f %.1f", e.kind, e.id, e.position.x, e.position.y, e.position.z)) + end +end + +function on_init() + info("client initialized, setting client information") + client:set_client_information({ view_distance = 16 }) +end diff --git a/lua/utils.lua b/lua/utils.lua new file mode 100644 index 0000000..4ef5ba8 --- /dev/null +++ b/lua/utils.lua @@ -0,0 +1,30 @@ +function dump(object) + if type(object) == "table" then + local string = "{ " + local parts = {} + for key, value in pairs(object) do + table.insert(parts, key .. " = " .. dump(value)) + end + string = string .. table.concat(parts, ", ") + return string .. " " .. "}" + else + return tostring(object) + end +end + +function dump_pretty(object, level) + if not level then + level = 0 + end + if type(object) == "table" then + local string = "{\n" .. string.rep(" ", level + 1) + local parts = {} + for key, value in pairs(object) do + table.insert(parts, key .. " = " .. dump_pretty(value, level + 1)) + end + string = string .. table.concat(parts, ",\n" .. string.rep(" ", level + 1)) + return string .. "\n" .. string.rep(" ", level) .. "}" + else + return tostring(object) + end +end From 2373d6500ebf8ca8dfa58c730631484ebb9fe130 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Mon, 17 Feb 2025 11:53:24 -0500 Subject: [PATCH 17/35] refactor: rename a few things --- errornowatcher.lua | 2 +- {lua => lib}/enum.lua | 0 {lua => lib}/events.lua | 0 {lua => lib}/utils.lua | 0 src/commands.rs | 2 +- src/events.rs | 4 ++-- src/http.rs | 2 +- src/{scripting => lua}/block.rs | 0 src/{scripting => lua}/client/interaction.rs | 0 src/{scripting => lua}/client/mod.rs | 0 src/{scripting => lua}/client/movement.rs | 0 src/{scripting => lua}/client/state.rs | 0 src/{scripting => lua}/client/world.rs | 0 src/{scripting => lua}/direction.rs | 0 src/{scripting => lua}/entity.rs | 0 src/{scripting => lua}/fluid_state.rs | 0 src/{scripting => lua}/hunger.rs | 0 src/{scripting => lua}/logging.rs | 0 src/{scripting => lua}/mod.rs | 0 src/{scripting => lua}/vec3.rs | 0 src/main.rs | 4 ++-- 21 files changed, 7 insertions(+), 7 deletions(-) rename {lua => lib}/enum.lua (100%) rename {lua => lib}/events.lua (100%) rename {lua => lib}/utils.lua (100%) rename src/{scripting => lua}/block.rs (100%) rename src/{scripting => lua}/client/interaction.rs (100%) rename src/{scripting => lua}/client/mod.rs (100%) rename src/{scripting => lua}/client/movement.rs (100%) rename src/{scripting => lua}/client/state.rs (100%) rename src/{scripting => lua}/client/world.rs (100%) rename src/{scripting => lua}/direction.rs (100%) rename src/{scripting => lua}/entity.rs (100%) rename src/{scripting => lua}/fluid_state.rs (100%) rename src/{scripting => lua}/hunger.rs (100%) rename src/{scripting => lua}/logging.rs (100%) rename src/{scripting => lua}/mod.rs (100%) rename src/{scripting => lua}/vec3.rs (100%) diff --git a/errornowatcher.lua b/errornowatcher.lua index 95ef5c5..fc641ba 100644 --- a/errornowatcher.lua +++ b/errornowatcher.lua @@ -9,7 +9,7 @@ for _, module in "utils", } do - module = "lua/" .. module + module = "lib/" .. module package.loaded[module] = nil require(module) end diff --git a/lua/enum.lua b/lib/enum.lua similarity index 100% rename from lua/enum.lua rename to lib/enum.lua diff --git a/lua/events.lua b/lib/events.lua similarity index 100% rename from lua/events.lua rename to lib/events.lua diff --git a/lua/utils.lua b/lib/utils.lua similarity index 100% rename from lua/utils.lua rename to lib/utils.lua diff --git a/src/commands.rs b/src/commands.rs index d6c68c5..cb38b18 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -1,6 +1,6 @@ use crate::{ State, - scripting::{eval, exec, reload}, + lua::{eval, exec, reload}, }; use azalea::{ GameProfileComponent, brigadier::prelude::*, chat::ChatPacket, entity::metadata::Player, diff --git a/src/events.rs b/src/events.rs index a0a31d2..9569634 100644 --- a/src/events.rs +++ b/src/events.rs @@ -1,4 +1,4 @@ -use crate::{State, commands::CommandSource, http::serve, scripting}; +use crate::{State, commands::CommandSource, http::serve, lua}; use azalea::prelude::*; use hyper::{server::conn::http1, service::service_fn}; use hyper_util::rt::TokioIo; @@ -53,7 +53,7 @@ pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow: globals.set( "client", - scripting::client::Client { + lua::client::Client { inner: Some(client), }, )?; diff --git a/src/http.rs b/src/http.rs index 67953b6..acd8d97 100644 --- a/src/http.rs +++ b/src/http.rs @@ -1,6 +1,6 @@ use crate::{ State, - scripting::{eval, exec, reload}, + lua::{eval, exec, reload}, }; use http_body_util::{BodyExt, Empty, Full, combinators::BoxBody}; use hyper::{Method, Request, Response, StatusCode, body::Bytes}; diff --git a/src/scripting/block.rs b/src/lua/block.rs similarity index 100% rename from src/scripting/block.rs rename to src/lua/block.rs diff --git a/src/scripting/client/interaction.rs b/src/lua/client/interaction.rs similarity index 100% rename from src/scripting/client/interaction.rs rename to src/lua/client/interaction.rs diff --git a/src/scripting/client/mod.rs b/src/lua/client/mod.rs similarity index 100% rename from src/scripting/client/mod.rs rename to src/lua/client/mod.rs diff --git a/src/scripting/client/movement.rs b/src/lua/client/movement.rs similarity index 100% rename from src/scripting/client/movement.rs rename to src/lua/client/movement.rs diff --git a/src/scripting/client/state.rs b/src/lua/client/state.rs similarity index 100% rename from src/scripting/client/state.rs rename to src/lua/client/state.rs diff --git a/src/scripting/client/world.rs b/src/lua/client/world.rs similarity index 100% rename from src/scripting/client/world.rs rename to src/lua/client/world.rs diff --git a/src/scripting/direction.rs b/src/lua/direction.rs similarity index 100% rename from src/scripting/direction.rs rename to src/lua/direction.rs diff --git a/src/scripting/entity.rs b/src/lua/entity.rs similarity index 100% rename from src/scripting/entity.rs rename to src/lua/entity.rs diff --git a/src/scripting/fluid_state.rs b/src/lua/fluid_state.rs similarity index 100% rename from src/scripting/fluid_state.rs rename to src/lua/fluid_state.rs diff --git a/src/scripting/hunger.rs b/src/lua/hunger.rs similarity index 100% rename from src/scripting/hunger.rs rename to src/lua/hunger.rs diff --git a/src/scripting/logging.rs b/src/lua/logging.rs similarity index 100% rename from src/scripting/logging.rs rename to src/lua/logging.rs diff --git a/src/scripting/mod.rs b/src/lua/mod.rs similarity index 100% rename from src/scripting/mod.rs rename to src/lua/mod.rs diff --git a/src/scripting/vec3.rs b/src/lua/vec3.rs similarity index 100% rename from src/scripting/vec3.rs rename to src/lua/vec3.rs diff --git a/src/main.rs b/src/main.rs index b882784..c91d9ce 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,7 @@ mod arguments; mod commands; mod events; mod http; -mod scripting; +mod lua; use azalea::{brigadier::prelude::CommandDispatcher, prelude::*}; use clap::Parser; @@ -34,7 +34,7 @@ async fn main() -> anyhow::Result<()> { let username = globals.get::("USERNAME")?; globals.set("script_path", script_path)?; - scripting::register_functions(&lua, &globals)?; + lua::register_functions(&lua, &globals)?; let mut commands = CommandDispatcher::new(); register(&mut commands); From 21cc1a54882bba9b6475828bf91c51e9f64f883e Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Mon, 17 Feb 2025 13:38:20 -0500 Subject: [PATCH 18/35] feat(client): add inventory manipulation wrappers --- lib/enum.lua | 19 +++++ src/lua/client/container.rs | 88 +++++++++++++++++++++++ src/lua/client/mod.rs | 17 ++++- src/lua/client/world.rs | 43 ++++++++--- src/lua/container/item_stack.rs | 50 +++++++++++++ src/lua/container/mod.rs | 124 ++++++++++++++++++++++++++++++++ src/lua/mod.rs | 1 + 7 files changed, 331 insertions(+), 11 deletions(-) create mode 100644 src/lua/client/container.rs create mode 100644 src/lua/container/item_stack.rs create mode 100644 src/lua/container/mod.rs diff --git a/lib/enum.lua b/lib/enum.lua index 96aadee..e83500e 100644 --- a/lib/enum.lua +++ b/lib/enum.lua @@ -13,3 +13,22 @@ RADIUS_GOAL = 1 REACH_BLOCK_POS_GOAL = 2 XZ_GOAL = 3 Y_GOAL = 4 + +PICKUP_LEFT = 0 +PICKUP_RIGHT = 1 +PICKUP_LEFT_OUTSIDE = 2 +PICKUP_RIGHT_OUTSIDE = 3 +QUICK_MOVE_LEFT = 4 +QUICK_MOVE_RIGHT = 5 +SWAP = 6 +CLONE = 7 +THROW_SINGLE = 8 +THROW_ALL = 9 +QUICK_CRAFT = 10 +QUICK_CRAFT_LEFT = 0 +QUICK_CRAFT_RIGHT = 1 +QUICK_CRAFT_MIDDLE = 2 +QUICK_CRAFT_START = 0 +QUICK_CRAFT_ADD = 1 +QUICK_CRAFT_END = 2 +PICKUP_ALL = 11 diff --git a/src/lua/client/container.rs b/src/lua/client/container.rs new file mode 100644 index 0000000..d0d72ac --- /dev/null +++ b/src/lua/client/container.rs @@ -0,0 +1,88 @@ +use super::{Client, Container, ContainerRef, ItemStack, Vec3}; +use azalea::{ + BlockPos, inventory::Inventory, prelude::ContainerClientExt, + protocol::packets::game::ServerboundSetCarriedItem, +}; +use log::error; +use mlua::{Lua, Result, UserDataRef}; + +pub fn held_item(_lua: &Lua, client: &Client) -> Result { + Ok(ItemStack { + inner: client + .inner + .as_ref() + .unwrap() + .component::() + .held_item(), + }) +} + +pub fn held_slot(_lua: &Lua, client: &Client) -> Result { + Ok(client + .inner + .as_ref() + .unwrap() + .component::() + .selected_hotbar_slot) +} + +pub fn open_container(_lua: &Lua, client: &Client) -> Result> { + Ok(client + .inner + .as_ref() + .unwrap() + .get_open_container() + .map(|c| ContainerRef { inner: c })) +} + +pub async fn open_container_at( + _lua: Lua, + client: UserDataRef, + position: Vec3, +) -> Result> { + #[allow(clippy::cast_possible_truncation)] + Ok(client + .inner + .clone() + .unwrap() + .open_container_at(BlockPos::new( + position.x as i32, + position.y as i32, + position.z as i32, + )) + .await + .map(|c| Container { inner: c })) +} + +pub fn open_inventory(_lua: &Lua, client: &mut Client, _: ()) -> Result> { + Ok(client + .inner + .as_mut() + .unwrap() + .open_inventory() + .map(|c| Container { inner: c })) +} + +pub fn set_held_slot(_lua: &Lua, client: &Client, slot: u8) -> Result<()> { + if slot > 8 { + return Ok(()); + } + + let client = client.inner.as_ref().unwrap(); + { + let mut ecs = client.ecs.lock(); + let mut inventory = client.query::<&mut Inventory>(&mut ecs); + if inventory.selected_hotbar_slot == slot { + return Ok(()); + } + inventory.selected_hotbar_slot = slot; + }; + + if let Err(error) = client.write_packet(ServerboundSetCarriedItem { + slot: u16::from(slot), + }) { + error!("failed to send SetCarriedItem packet: {error:?}"); + } + + Ok(()) +} diff --git a/src/lua/client/mod.rs b/src/lua/client/mod.rs index 794d51f..46cf497 100644 --- a/src/lua/client/mod.rs +++ b/src/lua/client/mod.rs @@ -1,10 +1,17 @@ +mod container; mod interaction; mod movement; mod state; mod world; use super::{ - block::Block, direction::Direction, entity::Entity, fluid_state::FluidState, hunger::Hunger, + block::Block, + container::item_stack::ItemStack, + container::{Container, ContainerRef}, + direction::Direction, + entity::Entity, + fluid_state::FluidState, + hunger::Hunger, vec3::Vec3, }; use azalea::Client as AzaleaClient; @@ -20,8 +27,11 @@ impl UserData for Client { f.add_field_method_get("direction", movement::direction); f.add_field_method_get("eye_position", movement::eye_position); f.add_field_method_get("health", state::health); + f.add_field_method_get("held_item", container::held_item); + f.add_field_method_get("held_slot", container::held_slot); f.add_field_method_get("hunger", state::hunger); f.add_field_method_get("looking_at", movement::looking_at); + f.add_field_method_get("open_container", container::open_container); f.add_field_method_get("pathfinder", movement::pathfinder); f.add_field_method_get("position", movement::position); f.add_field_method_get("score", state::score); @@ -31,13 +41,17 @@ impl UserData for Client { fn add_methods>(m: &mut M) { m.add_async_method("mine", interaction::mine); + m.add_async_method("open_container_at", container::open_container_at); m.add_async_method("set_client_information", state::set_client_information); + m.add_method("best_tool_for_block", world::best_tool_for_block); + m.add_method("block_names_to_states", world::block_names_to_states); m.add_method("chat", chat); m.add_method("find_blocks", world::find_blocks); m.add_method("find_entities", world::find_entities); m.add_method("get_block_from_state", world::get_block_from_state); m.add_method("get_block_state", world::get_block_state); m.add_method("get_fluid_state", world::get_fluid_state); + m.add_method("set_held_slot", container::set_held_slot); m.add_method("set_mining", interaction::set_mining); m.add_method("stop_pathfinding", movement::stop_pathfinding); m.add_method_mut("attack", interaction::attack); @@ -45,6 +59,7 @@ impl UserData for Client { m.add_method_mut("goto", movement::goto); m.add_method_mut("jump", movement::jump); m.add_method_mut("look_at", movement::look_at); + m.add_method_mut("open_inventory", container::open_inventory); m.add_method_mut("set_direction", movement::set_direction); m.add_method_mut("set_jumping", movement::set_jumping); m.add_method_mut("sprint", movement::sprint); diff --git a/src/lua/client/world.rs b/src/lua/client/world.rs index 53d0135..5c92814 100644 --- a/src/lua/client/world.rs +++ b/src/lua/client/world.rs @@ -1,17 +1,47 @@ use super::{Block, Client, Entity, FluidState, Vec3}; use azalea::{ BlockPos, + auto_tool::AutoToolClientExt, blocks::{Block as AzaleaBlock, BlockState, BlockStates}, ecs::query::Without, entity::{Dead, EntityKind, EntityUuid, Position as AzaleaPosition, metadata::CustomName}, world::MinecraftEntityId, }; -use mlua::{Function, Lua, Result}; +use mlua::{Function, Lua, Result, Table}; + +pub fn best_tool_for_block(lua: &Lua, client: &Client, block_state: u16) -> Result
{ + let tr = client + .inner + .as_ref() + .unwrap() + .best_tool_in_hotbar_for_block(BlockState { id: block_state }); + + let tool_result = lua.create_table()?; + tool_result.set("index", tr.index)?; + tool_result.set("percentage_per_tick", tr.percentage_per_tick)?; + Ok(tool_result) +} + +pub fn block_names_to_states( + _lua: &Lua, + _client: &Client, + block_names: Vec, +) -> Result> { + Ok(block_names + .iter() + .flat_map(|n| { + (u32::MIN..u32::MAX) + .map_while(|i| BlockState::try_from(i).ok()) + .filter(move |&b| n == Into::>::into(b).id()) + .map(|b| b.id) + }) + .collect()) +} pub fn find_blocks( _lua: &Lua, client: &Client, - (nearest_to, block_names): (Vec3, Vec), + (nearest_to, block_states): (Vec3, Vec), ) -> Result> { #[allow(clippy::cast_possible_truncation)] Ok(client @@ -27,14 +57,7 @@ pub fn find_blocks( nearest_to.z as i32, ), &BlockStates { - set: block_names - .iter() - .flat_map(|n| { - (u32::MIN..u32::MAX) - .map_while(|i| BlockState::try_from(i).ok()) - .filter(move |&b| n == Into::>::into(b).id()) - }) - .collect(), + set: block_states.iter().map(|&id| BlockState { id }).collect(), }, ) .map(|p| Vec3 { diff --git a/src/lua/container/item_stack.rs b/src/lua/container/item_stack.rs new file mode 100644 index 0000000..0aef768 --- /dev/null +++ b/src/lua/container/item_stack.rs @@ -0,0 +1,50 @@ +use azalea::inventory::components::{CustomName, Damage, MaxDamage}; +use mlua::{UserData, UserDataFields, UserDataMethods}; + +pub struct ItemStack { + pub inner: azalea::inventory::ItemStack, +} + +impl UserData for ItemStack { + fn add_fields>(f: &mut F) { + f.add_field_method_get("is_empty", |_, this| Ok(this.inner.is_empty())); + f.add_field_method_get("is_present", |_, this| Ok(this.inner.is_present())); + f.add_field_method_get("count", |_, this| Ok(this.inner.count())); + f.add_field_method_get("kind", |_, this| Ok(this.inner.kind().to_string())); + f.add_field_method_get("custom_name", |_, this| { + Ok(if let Some(data) = this.inner.as_present() { + data.components + .get::() + .map(|n| n.name.to_string()) + } else { + None + }) + }); + f.add_field_method_get("damage", |_, this| { + Ok(if let Some(data) = this.inner.as_present() { + data.components.get::().map(|d| d.amount) + } else { + None + }) + }); + f.add_field_method_get("max_damage", |_, this| { + Ok(if let Some(data) = this.inner.as_present() { + data.components.get::().map(|d| d.amount) + } else { + None + }) + }); + } + + fn add_methods>(m: &mut M) { + m.add_method_mut("split", |_, this, count: u32| { + Ok(ItemStack { + inner: this.inner.split(count), + }) + }); + m.add_method_mut("update_empty", |_, this, (): ()| { + this.inner.update_empty(); + Ok(()) + }); + } +} diff --git a/src/lua/container/mod.rs b/src/lua/container/mod.rs new file mode 100644 index 0000000..a71076f --- /dev/null +++ b/src/lua/container/mod.rs @@ -0,0 +1,124 @@ +pub mod item_stack; + +use azalea::{ + container::{ContainerHandle, ContainerHandleRef}, + inventory::operations::{ + ClickOperation, CloneClick, PickupAllClick, PickupClick, QuickCraftClick, QuickCraftKind, + QuickCraftStatus, QuickMoveClick, SwapClick, ThrowClick, + }, +}; +use item_stack::ItemStack; +use mlua::{Result, Table, UserData, UserDataFields, UserDataMethods}; + +pub struct Container { + pub inner: ContainerHandle, +} + +impl UserData for Container { + fn add_fields>(f: &mut F) { + f.add_field_method_get("id", |_, this| Ok(this.inner.id())); + + f.add_field_method_get("menu", |_, this| { + Ok(this.inner.menu().map(|m| format!("{m:?}"))) + }); + + f.add_field_method_get("contents", |_, this| { + Ok(this.inner.contents().map(|v| { + v.iter() + .map(|i| ItemStack { inner: i.clone() }) + .collect::>() + })) + }); + } + + fn add_methods>(m: &mut M) { + m.add_method("click", |_, this, operation: Table| { + this.inner.click(click_operation_from_table(operation)?); + Ok(()) + }); + } +} + +pub struct ContainerRef { + pub inner: ContainerHandleRef, +} + +impl UserData for ContainerRef { + fn add_fields>(f: &mut F) { + f.add_field_method_get("id", |_, this| Ok(this.inner.id())); + + f.add_field_method_get("menu", |_, this| { + Ok(this.inner.menu().map(|m| format!("{m:?}"))) + }); + + f.add_field_method_get("contents", |_, this| { + Ok(this.inner.contents().map(|v| { + v.iter() + .map(|i| ItemStack { inner: i.clone() }) + .collect::>() + })) + }); + } + + fn add_methods>(m: &mut M) { + m.add_method("close", |_, this, (): ()| { + this.inner.close(); + Ok(()) + }); + + m.add_method("click", |_, this, operation: Table| { + this.inner.click(click_operation_from_table(operation)?); + Ok(()) + }); + } +} + +fn click_operation_from_table(o: Table) -> Result { + Ok(match o.get("type")? { + 0 => ClickOperation::Pickup(PickupClick::Left { + slot: o.get("slot")?, + }), + 1 => ClickOperation::Pickup(PickupClick::Right { + slot: o.get("slot")?, + }), + 2 => ClickOperation::Pickup(PickupClick::LeftOutside), + 3 => ClickOperation::Pickup(PickupClick::RightOutside), + 5 => ClickOperation::QuickMove(QuickMoveClick::Right { + slot: o.get("slot")?, + }), + 6 => ClickOperation::Swap(SwapClick { + source_slot: o.get("source_slot")?, + target_slot: o.get("target_slot")?, + }), + 7 => ClickOperation::Clone(CloneClick { + slot: o.get("slot")?, + }), + 8 => ClickOperation::Throw(ThrowClick::Single { + slot: o.get("slot")?, + }), + 9 => ClickOperation::Throw(ThrowClick::All { + slot: o.get("slot")?, + }), + 10 => ClickOperation::QuickCraft(QuickCraftClick { + kind: match o.get("kind").unwrap_or_default() { + 1 => QuickCraftKind::Right, + 2 => QuickCraftKind::Middle, + _ => QuickCraftKind::Left, + }, + status: match o.get("status").unwrap_or_default() { + 1 => QuickCraftStatus::Add { + slot: o.get("slot")?, + }, + 2 => QuickCraftStatus::End, + _ => QuickCraftStatus::Start, + }, + }), + 11 => ClickOperation::PickupAll(PickupAllClick { + slot: o.get("slot")?, + reversed: o.get("reversed").unwrap_or_default(), + }), + _ => ClickOperation::QuickMove(QuickMoveClick::Left { + slot: o.get("slot")?, + }), + }) +} diff --git a/src/lua/mod.rs b/src/lua/mod.rs index 6b7c54b..7e1fb77 100644 --- a/src/lua/mod.rs +++ b/src/lua/mod.rs @@ -1,5 +1,6 @@ pub mod block; pub mod client; +pub mod container; pub mod direction; pub mod entity; pub mod fluid_state; From 8f2fbf11da3df68815afe5371c0b067f4378577f Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Mon, 17 Feb 2025 15:07:31 -0500 Subject: [PATCH 19/35] feat(client): add last few fields and methods --- src/lua/client/interaction.rs | 4 ++++ src/lua/client/mod.rs | 17 ++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/lua/client/interaction.rs b/src/lua/client/interaction.rs index 0deb5bc..b68c795 100644 --- a/src/lua/client/interaction.rs +++ b/src/lua/client/interaction.rs @@ -21,6 +21,10 @@ pub fn block_interact(_lua: &Lua, client: &mut Client, position: Vec3) -> Result Ok(()) } +pub fn has_attack_cooldown(_lua: &Lua, client: &Client) -> Result { + Ok(client.inner.as_ref().unwrap().has_attack_cooldown()) +} + pub async fn mine(_lua: Lua, client: UserDataRef, position: Vec3) -> Result<()> { #[allow(clippy::cast_possible_truncation)] client diff --git a/src/lua/client/mod.rs b/src/lua/client/mod.rs index 46cf497..6b60d7a 100644 --- a/src/lua/client/mod.rs +++ b/src/lua/client/mod.rs @@ -26,6 +26,7 @@ impl UserData for Client { f.add_field_method_get("air_supply", state::air_supply); f.add_field_method_get("direction", movement::direction); f.add_field_method_get("eye_position", movement::eye_position); + f.add_field_method_get("has_attack_cooldown", interaction::has_attack_cooldown); f.add_field_method_get("health", state::health); f.add_field_method_get("held_item", container::held_item); f.add_field_method_get("held_slot", container::held_slot); @@ -46,6 +47,7 @@ impl UserData for Client { m.add_method("best_tool_for_block", world::best_tool_for_block); m.add_method("block_names_to_states", world::block_names_to_states); m.add_method("chat", chat); + m.add_method("disconnect", disconnect); m.add_method("find_blocks", world::find_blocks); m.add_method("find_entities", world::find_entities); m.add_method("get_block_from_state", world::get_block_from_state); @@ -68,6 +70,16 @@ impl UserData for Client { } } +fn chat(_lua: &Lua, client: &Client, message: String) -> Result<()> { + client.inner.as_ref().unwrap().chat(&message); + Ok(()) +} + +fn disconnect(_lua: &Lua, client: &Client, _: ()) -> Result<()> { + client.inner.as_ref().unwrap().disconnect(); + Ok(()) +} + fn tab_list(lua: &Lua, client: &Client) -> Result
{ let tab_list = lua.create_table()?; for (uuid, player_info) in client.inner.as_ref().unwrap().tab_list() { @@ -87,8 +99,3 @@ fn tab_list(lua: &Lua, client: &Client) -> Result
{ fn uuid(_lua: &Lua, client: &Client) -> Result { Ok(client.inner.as_ref().unwrap().uuid().to_string()) } - -fn chat(_lua: &Lua, client: &Client, message: String) -> Result<()> { - client.inner.as_ref().unwrap().chat(&message); - Ok(()) -} From dde489a8ed8e86e66bc3859d54d9f34c5e3aab6b Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Mon, 17 Feb 2025 17:01:23 -0500 Subject: [PATCH 20/35] refactor: random fixes and usage improvements --- Cargo.toml | 3 +- errornowatcher.lua | 2 ++ lib/events.lua | 8 +++-- lib/inventory.lua | 38 +++++++++++++++++++++++ lib/movement.lua | 18 +++++++++++ lib/utils.lua | 14 +++++++++ src/events.rs | 1 + src/http.rs | 4 +-- src/lua/block.rs | 60 ++++++++++++++++++++++++++++++++++++- src/lua/client/container.rs | 18 +++++------ src/lua/client/mod.rs | 7 ++--- src/lua/client/movement.rs | 22 +++++++++----- src/lua/client/world.rs | 39 ++---------------------- src/lua/container/mod.rs | 56 +++++++++++++++++++--------------- src/lua/mod.rs | 3 +- 15 files changed, 203 insertions(+), 90 deletions(-) create mode 100644 lib/inventory.lua create mode 100644 lib/movement.lua diff --git a/Cargo.toml b/Cargo.toml index e17c9d7..12e2746 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,17 +12,16 @@ opt-level = 3 [profile.release] codegen-units = 1 lto = true -panic = "abort" strip = true [dependencies] anyhow = "1" azalea = { git = "https://github.com/azalea-rs/azalea.git" } clap = { version = "4", features = ["derive"] } +futures = "0" http-body-util = "0" hyper = { version = "1", features = ["server"] } hyper-util = "0" log = { version = "0" } mlua = { version = "0", features = ["async", "luau", "send"] } tokio = { version = "1", features = ["macros"] } -futures = "0" diff --git a/errornowatcher.lua b/errornowatcher.lua index fc641ba..c55f286 100644 --- a/errornowatcher.lua +++ b/errornowatcher.lua @@ -6,6 +6,8 @@ for _, module in { "enum", "events", + "inventory", + "movement", "utils", } do diff --git a/lib/events.lua b/lib/events.lua index a7f4c1f..8a960c4 100644 --- a/lib/events.lua +++ b/lib/events.lua @@ -1,5 +1,5 @@ local center = { x = 0, z = 0 } -local radius = 50 +local radius = 100 function on_tick() local entities = client:find_entities(function(e) @@ -15,6 +15,10 @@ function on_tick() end function on_init() - info("client initialized, setting client information") + info("client initialized, setting information...") client:set_client_information({ view_distance = 16 }) end + +function on_login() + info("player successfully logged in!") +end diff --git a/lib/inventory.lua b/lib/inventory.lua new file mode 100644 index 0000000..d99e618 --- /dev/null +++ b/lib/inventory.lua @@ -0,0 +1,38 @@ +function steal(item_name) + for _, chest_pos in client:find_blocks(client.position, get_block_states({ "chest" })) do + client:chat(dump(chest_pos)) + + client:goto({ position = chest_pos, radius = 3 }, { type = RADIUS_GOAL }) + while client.pathfinder.is_calculating or client.pathfinder.is_executing do + sleep(50) + end + client:look_at(chest_pos) + + local container = client:open_container_at(chest_pos) + for index, item in container.contents do + if item.kind == item_name then + container:click({slot = index - 1}, THROW_ALL) + sleep(50) + end + end + + container = nil + while client.open_container do + sleep(50) + end + end +end + +function drop_all_hotbar() + local inventory = client:open_inventory() + for i = 0, 9 do + inventory:click({slot = 36 + i}, THROW_ALL) + end +end + +function drop_all_inventory() + local inventory = client:open_inventory() + for i = 0, 45 do + inventory:click({slot = i}, THROW_ALL) + end +end diff --git a/lib/movement.lua b/lib/movement.lua new file mode 100644 index 0000000..e885d92 --- /dev/null +++ b/lib/movement.lua @@ -0,0 +1,18 @@ +function look_at_player(name) + local player = get_player(name) + if player then + player.position.y = player.position.y + 1 + client:look_at(player.position) + else + client:chat("player not found!") + end +end + +function goto_player(name) + local player = get_player(name) + if player then + client:goto(player.position) + else + client:chat("player not found!") + end +end diff --git a/lib/utils.lua b/lib/utils.lua index 4ef5ba8..cf6023b 100644 --- a/lib/utils.lua +++ b/lib/utils.lua @@ -1,3 +1,17 @@ +function get_player(name) + local target_uuid = nil + for uuid, player in client.tab_list do + if player.name == name then + target_uuid = uuid + break + end + end + + return client:find_entities(function(e) + return e.kind == "minecraft:player" and e.uuid == target_uuid + end)[1] +end + function dump(object) if type(object) == "table" then local string = "{ " diff --git a/src/events.rs b/src/events.rs index 9569634..fec8620 100644 --- a/src/events.rs +++ b/src/events.rs @@ -7,6 +7,7 @@ use mlua::{Function, IntoLuaMulti, Table}; use tokio::net::TcpListener; pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow::Result<()> { + state.lua.gc_stop(); let globals = state.lua.globals(); match event { diff --git a/src/http.rs b/src/http.rs index acd8d97..3ac8bf5 100644 --- a/src/http.rs +++ b/src/http.rs @@ -24,8 +24,8 @@ pub async fn serve( let bytes = request.into_body().collect().await?.to_bytes(); match std::str::from_utf8(&bytes) { Ok(code) => Response::new(full(match path.as_str() { - "/eval" => format!("{:?}", eval(&state.lua, code).await), - "/exec" => format!("{:?}", exec(&state.lua, code).await), + "/eval" => format!("{:#?}", eval(&state.lua, code).await), + "/exec" => format!("{:#?}", exec(&state.lua, code).await), _ => unreachable!(), })), Err(error) => status_code_response( diff --git a/src/lua/block.rs b/src/lua/block.rs index 25c8cd0..747b442 100644 --- a/src/lua/block.rs +++ b/src/lua/block.rs @@ -1,4 +1,8 @@ -use mlua::{FromLua, IntoLua, Lua, Result, Value}; +use azalea::blocks::{ + Block as AzaleaBlock, BlockState, + properties::{ChestType, Facing, LightLevel}, +}; +use mlua::{FromLua, Function, IntoLua, Lua, Result, Table, Value}; #[derive(Clone)] pub struct Block { @@ -46,3 +50,57 @@ impl FromLua for Block { } } } + +pub fn register_functions(lua: &Lua, globals: &Table) -> Result<()> { + globals.set( + "get_block_from_state", + lua.create_function(get_block_from_state)?, + )?; + globals.set("get_block_states", lua.create_function(get_block_states)?)?; + + Ok(()) +} + +pub fn get_block_from_state(_lua: &Lua, state: u32) -> Result> { + let Ok(state) = BlockState::try_from(state) else { + return Ok(None); + }; + let block: Box = state.into(); + let behavior = block.behavior(); + + Ok(Some(Block { + id: block.id().to_string(), + friction: behavior.friction, + jump_factor: behavior.jump_factor, + destroy_time: behavior.destroy_time, + explosion_resistance: behavior.explosion_resistance, + requires_correct_tool_for_drops: behavior.requires_correct_tool_for_drops, + })) +} + +pub fn get_block_states( + lua: &Lua, + (block_names, filter_fn): (Vec, Option), +) -> Result> { + let mut matched = Vec::new(); + for block_name in block_names { + for b in + (u32::MIN..u32::MAX).map_while(|possible_id| BlockState::try_from(possible_id).ok()) + { + if block_name == Into::>::into(b).id() + && (if let Some(filter_fn) = &filter_fn { + let p = lua.create_table()?; + p.set("chest_type", b.property::().map(|v| v as u8))?; + p.set("facing", b.property::().map(|v| v as u8))?; + p.set("light_level", b.property::().map(|v| v as u8))?; + filter_fn.call::(p.clone())? + } else { + true + }) + { + matched.push(b.id); + } + } + } + Ok(matched) +} diff --git a/src/lua/client/container.rs b/src/lua/client/container.rs index d0d72ac..81d166b 100644 --- a/src/lua/client/container.rs +++ b/src/lua/client/container.rs @@ -6,6 +6,15 @@ use azalea::{ use log::error; use mlua::{Lua, Result, UserDataRef}; +pub fn container(_lua: &Lua, client: &Client) -> Result> { + Ok(client + .inner + .as_ref() + .unwrap() + .get_open_container() + .map(|c| ContainerRef { inner: c })) +} + pub fn held_item(_lua: &Lua, client: &Client) -> Result { Ok(ItemStack { inner: client @@ -26,15 +35,6 @@ pub fn held_slot(_lua: &Lua, client: &Client) -> Result { .selected_hotbar_slot) } -pub fn open_container(_lua: &Lua, client: &Client) -> Result> { - Ok(client - .inner - .as_ref() - .unwrap() - .get_open_container() - .map(|c| ContainerRef { inner: c })) -} - pub async fn open_container_at( _lua: Lua, client: UserDataRef, diff --git a/src/lua/client/mod.rs b/src/lua/client/mod.rs index 6b60d7a..bf25489 100644 --- a/src/lua/client/mod.rs +++ b/src/lua/client/mod.rs @@ -5,7 +5,6 @@ mod state; mod world; use super::{ - block::Block, container::item_stack::ItemStack, container::{Container, ContainerRef}, direction::Direction, @@ -24,6 +23,7 @@ pub struct Client { impl UserData for Client { fn add_fields>(f: &mut F) { f.add_field_method_get("air_supply", state::air_supply); + f.add_field_method_get("container", container::container); f.add_field_method_get("direction", movement::direction); f.add_field_method_get("eye_position", movement::eye_position); f.add_field_method_get("has_attack_cooldown", interaction::has_attack_cooldown); @@ -32,7 +32,6 @@ impl UserData for Client { f.add_field_method_get("held_slot", container::held_slot); f.add_field_method_get("hunger", state::hunger); f.add_field_method_get("looking_at", movement::looking_at); - f.add_field_method_get("open_container", container::open_container); f.add_field_method_get("pathfinder", movement::pathfinder); f.add_field_method_get("position", movement::position); f.add_field_method_get("score", state::score); @@ -41,16 +40,15 @@ impl UserData for Client { } fn add_methods>(m: &mut M) { + m.add_async_method("goto", movement::goto); m.add_async_method("mine", interaction::mine); m.add_async_method("open_container_at", container::open_container_at); m.add_async_method("set_client_information", state::set_client_information); m.add_method("best_tool_for_block", world::best_tool_for_block); - m.add_method("block_names_to_states", world::block_names_to_states); m.add_method("chat", chat); m.add_method("disconnect", disconnect); m.add_method("find_blocks", world::find_blocks); m.add_method("find_entities", world::find_entities); - m.add_method("get_block_from_state", world::get_block_from_state); m.add_method("get_block_state", world::get_block_state); m.add_method("get_fluid_state", world::get_fluid_state); m.add_method("set_held_slot", container::set_held_slot); @@ -58,7 +56,6 @@ impl UserData for Client { m.add_method("stop_pathfinding", movement::stop_pathfinding); m.add_method_mut("attack", interaction::attack); m.add_method_mut("block_interact", interaction::block_interact); - m.add_method_mut("goto", movement::goto); m.add_method_mut("jump", movement::jump); m.add_method_mut("look_at", movement::look_at); m.add_method_mut("open_inventory", container::open_inventory); diff --git a/src/lua/client/movement.rs b/src/lua/client/movement.rs index 6025add..5658912 100644 --- a/src/lua/client/movement.rs +++ b/src/lua/client/movement.rs @@ -3,11 +3,11 @@ use azalea::{ BlockPos, BotClientExt, Client as AzaleaClient, SprintDirection, WalkDirection, interact::HitResultComponent, pathfinder::{ - ExecutingPath, Pathfinder, PathfinderClientExt, + ExecutingPath, GotoEvent, Pathfinder, PathfinderClientExt, goals::{BlockPosGoal, Goal, RadiusGoal, ReachBlockPosGoal, XZGoal, YGoal}, }, }; -use mlua::{FromLua, Lua, Result, Table, Value}; +use mlua::{FromLua, Lua, Result, Table, UserDataRef, Value}; pub fn direction(_lua: &Lua, client: &Client) -> Result { let d = client.inner.as_ref().unwrap().direction(); @@ -23,9 +23,9 @@ pub fn eye_position(_lua: &Lua, client: &Client) -> Result { }) } -pub fn goto( - lua: &Lua, - client: &mut Client, +pub async fn goto( + lua: Lua, + client: UserDataRef, (data, metadata): (Value, Option
), ) -> Result<()> { fn g(client: &AzaleaClient, without_mining: bool, goal: impl Goal + Send + Sync + 'static) { @@ -55,7 +55,7 @@ pub fn goto( match goal_type { 1 => { let t = data.as_table().ok_or(error)?; - let p = Vec3::from_lua(t.get("position")?, lua)?; + let p = Vec3::from_lua(t.get("position")?, &lua)?; g( client, without_mining, @@ -66,7 +66,7 @@ pub fn goto( ); } 2 => { - let p = Vec3::from_lua(data, lua)?; + let p = Vec3::from_lua(data, &lua)?; g( client, without_mining, @@ -95,7 +95,7 @@ pub fn goto( }, ), _ => { - let p = Vec3::from_lua(data, lua)?; + let p = Vec3::from_lua(data, &lua)?; g( client, without_mining, @@ -104,6 +104,12 @@ pub fn goto( } } + while client.get_tick_broadcaster().recv().await.is_ok() { + if client.ecs.lock().get::(client.entity).is_none() { + break; + } + } + Ok(()) } diff --git a/src/lua/client/world.rs b/src/lua/client/world.rs index 5c92814..2049cb4 100644 --- a/src/lua/client/world.rs +++ b/src/lua/client/world.rs @@ -1,8 +1,8 @@ -use super::{Block, Client, Entity, FluidState, Vec3}; +use super::{Client, Entity, FluidState, Vec3}; use azalea::{ BlockPos, auto_tool::AutoToolClientExt, - blocks::{Block as AzaleaBlock, BlockState, BlockStates}, + blocks::{BlockState, BlockStates}, ecs::query::Without, entity::{Dead, EntityKind, EntityUuid, Position as AzaleaPosition, metadata::CustomName}, world::MinecraftEntityId, @@ -22,22 +22,6 @@ pub fn best_tool_for_block(lua: &Lua, client: &Client, block_state: u16) -> Resu Ok(tool_result) } -pub fn block_names_to_states( - _lua: &Lua, - _client: &Client, - block_names: Vec, -) -> Result> { - Ok(block_names - .iter() - .flat_map(|n| { - (u32::MIN..u32::MAX) - .map_while(|i| BlockState::try_from(i).ok()) - .filter(move |&b| n == Into::>::into(b).id()) - .map(|b| b.id) - }) - .collect()) -} - pub fn find_blocks( _lua: &Lua, client: &Client, @@ -93,7 +77,7 @@ pub fn find_entities(_lua: &Lua, client: &Client, filter_fn: Function) -> Result custom_name: custom_name.as_ref().map(ToString::to_string), }; - if filter_fn.call::(entity.clone()).unwrap() { + if filter_fn.call::(entity.clone())? { matched.push(entity); } } @@ -101,23 +85,6 @@ pub fn find_entities(_lua: &Lua, client: &Client, filter_fn: Function) -> Result Ok(matched) } -pub fn get_block_from_state(_lua: &Lua, _client: &Client, state: u32) -> Result> { - let Ok(state) = BlockState::try_from(state) else { - return Ok(None); - }; - let block: Box = state.into(); - let behavior = block.behavior(); - - Ok(Some(Block { - id: block.id().to_string(), - friction: behavior.friction, - jump_factor: behavior.jump_factor, - destroy_time: behavior.destroy_time, - explosion_resistance: behavior.explosion_resistance, - requires_correct_tool_for_drops: behavior.requires_correct_tool_for_drops, - })) -} - pub fn get_block_state(_lua: &Lua, client: &Client, position: Vec3) -> Result> { #[allow(clippy::cast_possible_truncation)] Ok(client diff --git a/src/lua/container/mod.rs b/src/lua/container/mod.rs index a71076f..8063982 100644 --- a/src/lua/container/mod.rs +++ b/src/lua/container/mod.rs @@ -32,10 +32,14 @@ impl UserData for Container { } fn add_methods>(m: &mut M) { - m.add_method("click", |_, this, operation: Table| { - this.inner.click(click_operation_from_table(operation)?); - Ok(()) - }); + m.add_method( + "click", + |_, this, (operation, operation_type): (Table, Option)| { + this.inner + .click(click_operation_from_table(operation, operation_type)?); + Ok(()) + }, + ); } } @@ -66,59 +70,63 @@ impl UserData for ContainerRef { Ok(()) }); - m.add_method("click", |_, this, operation: Table| { - this.inner.click(click_operation_from_table(operation)?); - Ok(()) - }); + m.add_method( + "click", + |_, this, (operation, operation_type): (Table, Option)| { + this.inner + .click(click_operation_from_table(operation, operation_type)?); + Ok(()) + }, + ); } } -fn click_operation_from_table(o: Table) -> Result { - Ok(match o.get("type")? { +fn click_operation_from_table(op: Table, op_type: Option) -> Result { + Ok(match op_type.unwrap_or_default() { 0 => ClickOperation::Pickup(PickupClick::Left { - slot: o.get("slot")?, + slot: op.get("slot")?, }), 1 => ClickOperation::Pickup(PickupClick::Right { - slot: o.get("slot")?, + slot: op.get("slot")?, }), 2 => ClickOperation::Pickup(PickupClick::LeftOutside), 3 => ClickOperation::Pickup(PickupClick::RightOutside), 5 => ClickOperation::QuickMove(QuickMoveClick::Right { - slot: o.get("slot")?, + slot: op.get("slot")?, }), 6 => ClickOperation::Swap(SwapClick { - source_slot: o.get("source_slot")?, - target_slot: o.get("target_slot")?, + source_slot: op.get("source_slot")?, + target_slot: op.get("target_slot")?, }), 7 => ClickOperation::Clone(CloneClick { - slot: o.get("slot")?, + slot: op.get("slot")?, }), 8 => ClickOperation::Throw(ThrowClick::Single { - slot: o.get("slot")?, + slot: op.get("slot")?, }), 9 => ClickOperation::Throw(ThrowClick::All { - slot: o.get("slot")?, + slot: op.get("slot")?, }), 10 => ClickOperation::QuickCraft(QuickCraftClick { - kind: match o.get("kind").unwrap_or_default() { + kind: match op.get("kind").unwrap_or_default() { 1 => QuickCraftKind::Right, 2 => QuickCraftKind::Middle, _ => QuickCraftKind::Left, }, - status: match o.get("status").unwrap_or_default() { + status: match op.get("status").unwrap_or_default() { 1 => QuickCraftStatus::Add { - slot: o.get("slot")?, + slot: op.get("slot")?, }, 2 => QuickCraftStatus::End, _ => QuickCraftStatus::Start, }, }), 11 => ClickOperation::PickupAll(PickupAllClick { - slot: o.get("slot")?, - reversed: o.get("reversed").unwrap_or_default(), + slot: op.get("slot")?, + reversed: op.get("reversed").unwrap_or_default(), }), _ => ClickOperation::QuickMove(QuickMoveClick::Left { - slot: o.get("slot")?, + slot: op.get("slot")?, }), }) } diff --git a/src/lua/mod.rs b/src/lua/mod.rs index 7e1fb77..827ec15 100644 --- a/src/lua/mod.rs +++ b/src/lua/mod.rs @@ -29,7 +29,8 @@ pub fn register_functions(lua: &Lua, globals: &Table) -> mlua::Result<()> { })?, )?; - logging::register_functions(lua, globals) + logging::register_functions(lua, globals)?; + block::register_functions(lua, globals) } pub fn reload(lua: &Lua) -> Result<(), Error> { From 2cba4d797f62b4c5958a94e765e0895eeb2d3a07 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Mon, 17 Feb 2025 22:18:59 -0500 Subject: [PATCH 21/35] fix(client): split long replies into multiple chunks --- src/commands.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index cb38b18..29d8f4a 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -19,14 +19,22 @@ pub struct CommandSource { impl CommandSource { pub fn reply(&self, message: &str) { - let response = if self.message.is_whisper() - && let Some(username) = self.message.username() + for chunk in message + .chars() + .collect::>() + .chunks(236) + .map(|chars| chars.iter().collect::()) { - &format!("/w {username} {message}") - } else { - message - }; - self.client.chat(response); + self.client.chat( + &(if self.message.is_whisper() + && let Some(username) = self.message.username() + { + format!("/w {username} {chunk}") + } else { + chunk + }), + ); + } } pub fn _entity(&mut self) -> Option { From 0303244897f76e319862cd3fe5e39454d75c3474 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Mon, 17 Feb 2025 23:09:44 -0500 Subject: [PATCH 22/35] refactor: remove redundant lua type wrappers --- src/lua/block.rs | 74 +++++++++-------------------------------- src/lua/client/mod.rs | 3 -- src/lua/client/state.rs | 13 ++++---- src/lua/client/world.rs | 62 +++++++++++++++++++--------------- src/lua/entity.rs | 43 ------------------------ src/lua/fluid_state.rs | 36 -------------------- src/lua/hunger.rs | 33 ------------------ src/lua/mod.rs | 3 -- src/lua/vec3.rs | 2 +- 9 files changed, 58 insertions(+), 211 deletions(-) delete mode 100644 src/lua/entity.rs delete mode 100644 src/lua/fluid_state.rs delete mode 100644 src/lua/hunger.rs diff --git a/src/lua/block.rs b/src/lua/block.rs index 747b442..a43c73b 100644 --- a/src/lua/block.rs +++ b/src/lua/block.rs @@ -2,54 +2,7 @@ use azalea::blocks::{ Block as AzaleaBlock, BlockState, properties::{ChestType, Facing, LightLevel}, }; -use mlua::{FromLua, Function, IntoLua, Lua, Result, Table, Value}; - -#[derive(Clone)] -pub struct Block { - pub id: String, - pub friction: f32, - pub jump_factor: f32, - pub destroy_time: f32, - pub explosion_resistance: f32, - pub requires_correct_tool_for_drops: bool, -} - -impl IntoLua for Block { - fn into_lua(self, lua: &Lua) -> Result { - let table = lua.create_table()?; - table.set("id", self.id)?; - table.set("friction", self.friction)?; - table.set("jump_factor", self.jump_factor)?; - table.set("destroy_time", self.destroy_time)?; - table.set("explosion_resistance", self.explosion_resistance)?; - table.set( - "requires_correct_tool_for_drops", - self.requires_correct_tool_for_drops, - )?; - Ok(Value::Table(table)) - } -} - -impl FromLua for Block { - fn from_lua(value: Value, _lua: &Lua) -> Result { - if let Value::Table(table) = value { - Ok(Self { - id: table.get("id")?, - friction: table.get("friction")?, - jump_factor: table.get("jump_factor")?, - destroy_time: table.get("destroy_time")?, - explosion_resistance: table.get("explosion_resistance")?, - requires_correct_tool_for_drops: table.get("requires_correct_tool_for_drops")?, - }) - } else { - Err(mlua::Error::FromLuaConversionError { - from: value.type_name(), - to: "Block".to_string(), - message: None, - }) - } - } -} +use mlua::{Function, Lua, Result, Table}; pub fn register_functions(lua: &Lua, globals: &Table) -> Result<()> { globals.set( @@ -61,21 +14,24 @@ pub fn register_functions(lua: &Lua, globals: &Table) -> Result<()> { Ok(()) } -pub fn get_block_from_state(_lua: &Lua, state: u32) -> Result> { +pub fn get_block_from_state(lua: &Lua, state: u32) -> Result> { let Ok(state) = BlockState::try_from(state) else { return Ok(None); }; - let block: Box = state.into(); - let behavior = block.behavior(); + let b: Box = state.into(); + let bh = b.behavior(); - Ok(Some(Block { - id: block.id().to_string(), - friction: behavior.friction, - jump_factor: behavior.jump_factor, - destroy_time: behavior.destroy_time, - explosion_resistance: behavior.explosion_resistance, - requires_correct_tool_for_drops: behavior.requires_correct_tool_for_drops, - })) + let block = lua.create_table()?; + block.set("id", b.id())?; + block.set("friction", bh.friction)?; + block.set("jump_factor", bh.jump_factor)?; + block.set("destroy_time", bh.destroy_time)?; + block.set("explosion_resistance", bh.explosion_resistance)?; + block.set( + "requires_correct_tool_for_drops", + bh.requires_correct_tool_for_drops, + )?; + Ok(Some(block)) } pub fn get_block_states( diff --git a/src/lua/client/mod.rs b/src/lua/client/mod.rs index bf25489..81a1c48 100644 --- a/src/lua/client/mod.rs +++ b/src/lua/client/mod.rs @@ -8,9 +8,6 @@ use super::{ container::item_stack::ItemStack, container::{Container, ContainerRef}, direction::Direction, - entity::Entity, - fluid_state::FluidState, - hunger::Hunger, vec3::Vec3, }; use azalea::Client as AzaleaClient; diff --git a/src/lua/client/state.rs b/src/lua/client/state.rs index 1f7a34a..1ed1c7e 100644 --- a/src/lua/client/state.rs +++ b/src/lua/client/state.rs @@ -1,4 +1,4 @@ -use super::{Client, Hunger}; +use super::Client; use azalea::{ ClientInformation, entity::metadata::{AirSupply, Score}, @@ -13,12 +13,13 @@ pub fn health(_lua: &Lua, client: &Client) -> Result { Ok(client.inner.as_ref().unwrap().health()) } -pub fn hunger(_lua: &Lua, client: &Client) -> Result { +pub fn hunger(lua: &Lua, client: &Client) -> Result
{ let h = client.inner.as_ref().unwrap().hunger(); - Ok(Hunger { - food: h.food, - saturation: h.saturation, - }) + + let hunger = lua.create_table()?; + hunger.set("food", h.food)?; + hunger.set("saturation", h.saturation)?; + Ok(hunger) } pub fn score(_lua: &Lua, client: &Client) -> Result { diff --git a/src/lua/client/world.rs b/src/lua/client/world.rs index 2049cb4..46c4f33 100644 --- a/src/lua/client/world.rs +++ b/src/lua/client/world.rs @@ -1,4 +1,4 @@ -use super::{Client, Entity, FluidState, Vec3}; +use super::{Client, Vec3}; use azalea::{ BlockPos, auto_tool::AutoToolClientExt, @@ -52,7 +52,7 @@ pub fn find_blocks( .collect()) } -pub fn find_entities(_lua: &Lua, client: &Client, filter_fn: Function) -> Result> { +pub fn find_entities(lua: &Lua, client: &Client, filter_fn: Function) -> Result> { let mut matched = Vec::new(); let mut ecs = client.inner.as_ref().unwrap().ecs.lock(); @@ -65,19 +65,21 @@ pub fn find_entities(_lua: &Lua, client: &Client, filter_fn: Function) -> Result ), Without>(); for (&id, uuid, kind, position, custom_name) in query.iter(&ecs) { - let entity = Entity { - id: id.0, - uuid: uuid.to_string(), - kind: kind.to_string(), - position: Vec3 { + let entity = lua.create_table()?; + entity.set("id", id.0)?; + entity.set("uuid", uuid.to_string())?; + entity.set("kind", kind.to_string())?; + entity.set( + "position", + Vec3 { x: position.x, y: position.y, z: position.z, }, - custom_name: custom_name.as_ref().map(ToString::to_string), - }; + )?; + entity.set("custom_name", custom_name.as_ref().map(ToString::to_string))?; - if filter_fn.call::(entity.clone())? { + if filter_fn.call::(&entity)? { matched.push(entity); } } @@ -101,22 +103,28 @@ pub fn get_block_state(_lua: &Lua, client: &Client, position: Vec3) -> Result Result> { +pub fn get_fluid_state(lua: &Lua, client: &Client, position: Vec3) -> Result> { #[allow(clippy::cast_possible_truncation)] - Ok(client - .inner - .as_ref() - .unwrap() - .world() - .read() - .get_fluid_state(&BlockPos::new( - position.x as i32, - position.y as i32, - position.z as i32, - )) - .map(|f| FluidState { - kind: f.kind as u8, - amount: f.amount, - falling: f.falling, - })) + Ok( + if let Some(fs) = client + .inner + .as_ref() + .unwrap() + .world() + .read() + .get_fluid_state(&BlockPos::new( + position.x as i32, + position.y as i32, + position.z as i32, + )) + { + let fluid_state = lua.create_table()?; + fluid_state.set("kind", fs.kind as u8)?; + fluid_state.set("amount", fs.amount)?; + fluid_state.set("falling", fs.falling)?; + Some(fluid_state) + } else { + None + }, + ) } diff --git a/src/lua/entity.rs b/src/lua/entity.rs deleted file mode 100644 index 8d8a881..0000000 --- a/src/lua/entity.rs +++ /dev/null @@ -1,43 +0,0 @@ -use super::vec3::Vec3; -use mlua::{FromLua, IntoLua, Lua, Result, Value}; - -#[derive(Clone)] -pub struct Entity { - pub id: u32, - pub uuid: String, - pub kind: String, - pub position: Vec3, - pub custom_name: Option, -} - -impl IntoLua for Entity { - fn into_lua(self, lua: &Lua) -> Result { - let entity = lua.create_table()?; - entity.set("id", self.id)?; - entity.set("uuid", self.uuid)?; - entity.set("kind", self.kind)?; - entity.set("position", self.position)?; - entity.set("custom_name", self.custom_name)?; - Ok(Value::Table(entity)) - } -} - -impl FromLua for Entity { - fn from_lua(value: Value, _lua: &Lua) -> Result { - if let Value::Table(table) = value { - Ok(Self { - id: table.get("id")?, - uuid: table.get("uuid")?, - kind: table.get("kind")?, - position: table.get("position")?, - custom_name: table.get("custom_name")?, - }) - } else { - Err(mlua::Error::FromLuaConversionError { - from: value.type_name(), - to: "Position".to_string(), - message: None, - }) - } - } -} diff --git a/src/lua/fluid_state.rs b/src/lua/fluid_state.rs deleted file mode 100644 index 6233f75..0000000 --- a/src/lua/fluid_state.rs +++ /dev/null @@ -1,36 +0,0 @@ -use mlua::{FromLua, IntoLua, Lua, Result, Value}; - -#[derive(Clone)] -pub struct FluidState { - pub kind: u8, - pub amount: u8, - pub falling: bool, -} - -impl IntoLua for FluidState { - fn into_lua(self, lua: &Lua) -> Result { - let table = lua.create_table()?; - table.set("kind", self.kind)?; - table.set("amount", self.amount)?; - table.set("falling", self.falling)?; - Ok(Value::Table(table)) - } -} - -impl FromLua for FluidState { - fn from_lua(value: Value, _lua: &Lua) -> Result { - if let Value::Table(table) = value { - Ok(Self { - kind: table.get("kind")?, - amount: table.get("amount")?, - falling: table.get("falling")?, - }) - } else { - Err(mlua::Error::FromLuaConversionError { - from: value.type_name(), - to: "FluidState".to_string(), - message: None, - }) - } - } -} diff --git a/src/lua/hunger.rs b/src/lua/hunger.rs deleted file mode 100644 index fd74f59..0000000 --- a/src/lua/hunger.rs +++ /dev/null @@ -1,33 +0,0 @@ -use mlua::{FromLua, IntoLua, Lua, Result, Value}; - -#[derive(Clone)] -pub struct Hunger { - pub food: u32, - pub saturation: f32, -} - -impl IntoLua for Hunger { - fn into_lua(self, lua: &Lua) -> Result { - let table = lua.create_table()?; - table.set("food", self.food)?; - table.set("saturation", self.saturation)?; - Ok(Value::Table(table)) - } -} - -impl FromLua for Hunger { - fn from_lua(value: Value, _lua: &Lua) -> Result { - if let Value::Table(table) = value { - Ok(Self { - food: table.get("food")?, - saturation: table.get("saturation")?, - }) - } else { - Err(mlua::Error::FromLuaConversionError { - from: value.type_name(), - to: "Hunger".to_string(), - message: None, - }) - } - } -} diff --git a/src/lua/mod.rs b/src/lua/mod.rs index 827ec15..59bfbfa 100644 --- a/src/lua/mod.rs +++ b/src/lua/mod.rs @@ -2,9 +2,6 @@ pub mod block; pub mod client; pub mod container; pub mod direction; -pub mod entity; -pub mod fluid_state; -pub mod hunger; pub mod logging; pub mod vec3; diff --git a/src/lua/vec3.rs b/src/lua/vec3.rs index 45cdbe5..4ac8385 100644 --- a/src/lua/vec3.rs +++ b/src/lua/vec3.rs @@ -28,7 +28,7 @@ impl FromLua for Vec3 { } else { Err(mlua::Error::FromLuaConversionError { from: value.type_name(), - to: "Position".to_string(), + to: "Vec3".to_string(), message: None, }) } From 93a2dda8c6ed1ddc3ad5c2ddaa0d966dc57b81e7 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Mon, 17 Feb 2025 23:09:44 -0500 Subject: [PATCH 23/35] feat: accept more lua types for Vec3 and Direction --- src/lua/direction.rs | 10 +++++++--- src/lua/vec3.rs | 28 +++++++++++++++++++--------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/lua/direction.rs b/src/lua/direction.rs index c58153e..6f18d51 100644 --- a/src/lua/direction.rs +++ b/src/lua/direction.rs @@ -18,9 +18,13 @@ impl IntoLua for Direction { impl FromLua for Direction { fn from_lua(value: Value, _lua: &Lua) -> Result { if let Value::Table(table) = value { - Ok(Self { - x: table.get("x")?, - y: table.get("y")?, + Ok(if let (Ok(x), Ok(y)) = (table.get(1), table.get(2)) { + Self { x, y } + } else { + Self { + x: table.get("x")?, + y: table.get("y")?, + } }) } else { Err(mlua::Error::FromLuaConversionError { diff --git a/src/lua/vec3.rs b/src/lua/vec3.rs index 4ac8385..5d8e50b 100644 --- a/src/lua/vec3.rs +++ b/src/lua/vec3.rs @@ -19,18 +19,28 @@ impl IntoLua for Vec3 { impl FromLua for Vec3 { fn from_lua(value: Value, _lua: &Lua) -> Result { - if let Value::Table(table) = value { - Ok(Self { - x: table.get("x")?, - y: table.get("y")?, - z: table.get("z")?, - }) - } else { - Err(mlua::Error::FromLuaConversionError { + match value { + Value::Table(table) => Ok( + if let (Ok(x), Ok(y), Ok(z)) = (table.get(1), table.get(2), table.get(3)) { + Self { x, y, z } + } else { + Self { + x: table.get("x")?, + y: table.get("y")?, + z: table.get("z")?, + } + }, + ), + Value::Vector(vector) => Ok(Self { + x: vector.x().into(), + y: vector.y().into(), + z: vector.z().into(), + }), + _ => Err(mlua::Error::FromLuaConversionError { from: value.type_name(), to: "Vec3".to_string(), message: None, - }) + }), } } } From 75d4a9c18385846a73004350b92bb7c94e340c15 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Tue, 18 Feb 2025 21:34:57 -0500 Subject: [PATCH 24/35] refactor(client): simplify usage with deref --- src/commands.rs | 4 +-- src/lua/client/container.rs | 27 +++---------------- src/lua/client/interaction.rs | 16 ++++------- src/lua/client/mod.rs | 30 ++++++++++++++++----- src/lua/client/movement.rs | 50 +++++++++++++---------------------- src/lua/client/state.rs | 18 ++++++------- src/lua/client/world.rs | 31 +++++----------------- 7 files changed, 68 insertions(+), 108 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index 29d8f4a..cd00c15 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -59,7 +59,7 @@ pub fn register(commands: &mut CommandDispatcher>) { commands.register( literal("eval").then(argument("code", string()).executes(|ctx: &Ctx| { let source = ctx.source.clone(); - let code = get_string(ctx, "code").unwrap(); + let code = get_string(ctx, "code").expect("argument should exist"); tokio::spawn(async move { let source = source.lock().await; source.reply(&format!("{:?}", eval(&source.state.lua, &code).await)); @@ -71,7 +71,7 @@ pub fn register(commands: &mut CommandDispatcher>) { commands.register( literal("exec").then(argument("code", string()).executes(|ctx: &Ctx| { let source = ctx.source.clone(); - let code = get_string(ctx, "code").unwrap(); + let code = get_string(ctx, "code").expect("argument should exist"); tokio::spawn(async move { let source = source.lock().await; source.reply(&format!("{:?}", exec(&source.state.lua, &code).await)); diff --git a/src/lua/client/container.rs b/src/lua/client/container.rs index 81d166b..5b0912d 100644 --- a/src/lua/client/container.rs +++ b/src/lua/client/container.rs @@ -8,31 +8,18 @@ use mlua::{Lua, Result, UserDataRef}; pub fn container(_lua: &Lua, client: &Client) -> Result> { Ok(client - .inner - .as_ref() - .unwrap() .get_open_container() .map(|c| ContainerRef { inner: c })) } pub fn held_item(_lua: &Lua, client: &Client) -> Result { Ok(ItemStack { - inner: client - .inner - .as_ref() - .unwrap() - .component::() - .held_item(), + inner: client.component::().held_item(), }) } pub fn held_slot(_lua: &Lua, client: &Client) -> Result { - Ok(client - .inner - .as_ref() - .unwrap() - .component::() - .selected_hotbar_slot) + Ok(client.component::().selected_hotbar_slot) } pub async fn open_container_at( @@ -42,9 +29,7 @@ pub async fn open_container_at( ) -> Result> { #[allow(clippy::cast_possible_truncation)] Ok(client - .inner .clone() - .unwrap() .open_container_at(BlockPos::new( position.x as i32, position.y as i32, @@ -55,12 +40,7 @@ pub async fn open_container_at( } pub fn open_inventory(_lua: &Lua, client: &mut Client, _: ()) -> Result> { - Ok(client - .inner - .as_mut() - .unwrap() - .open_inventory() - .map(|c| Container { inner: c })) + Ok(client.open_inventory().map(|c| Container { inner: c })) } pub fn set_held_slot(_lua: &Lua, client: &Client, slot: u8) -> Result<()> { @@ -68,7 +48,6 @@ pub fn set_held_slot(_lua: &Lua, client: &Client, slot: u8) -> Result<()> { return Ok(()); } - let client = client.inner.as_ref().unwrap(); { let mut ecs = client.ecs.lock(); let mut inventory = client.query::<&mut Inventory>(&mut ecs); diff --git a/src/lua/client/interaction.rs b/src/lua/client/interaction.rs index b68c795..bd0c024 100644 --- a/src/lua/client/interaction.rs +++ b/src/lua/client/interaction.rs @@ -3,17 +3,13 @@ use azalea::{BlockPos, BotClientExt, world::MinecraftEntityId}; use mlua::{Lua, Result, UserDataRef}; pub fn attack(_lua: &Lua, client: &mut Client, entity_id: u32) -> Result<()> { - client - .inner - .as_mut() - .unwrap() - .attack(MinecraftEntityId(entity_id)); + client.attack(MinecraftEntityId(entity_id)); Ok(()) } pub fn block_interact(_lua: &Lua, client: &mut Client, position: Vec3) -> Result<()> { #[allow(clippy::cast_possible_truncation)] - client.inner.as_mut().unwrap().block_interact(BlockPos::new( + client.block_interact(BlockPos::new( position.x as i32, position.y as i32, position.z as i32, @@ -22,15 +18,13 @@ pub fn block_interact(_lua: &Lua, client: &mut Client, position: Vec3) -> Result } pub fn has_attack_cooldown(_lua: &Lua, client: &Client) -> Result { - Ok(client.inner.as_ref().unwrap().has_attack_cooldown()) + Ok(client.has_attack_cooldown()) } pub async fn mine(_lua: Lua, client: UserDataRef, position: Vec3) -> Result<()> { #[allow(clippy::cast_possible_truncation)] client - .inner .clone() - .unwrap() .mine(BlockPos::new( position.x as i32, position.y as i32, @@ -41,13 +35,13 @@ pub async fn mine(_lua: Lua, client: UserDataRef, position: Vec3) -> Res } pub fn set_mining(_lua: &Lua, client: &Client, mining: bool) -> Result<()> { - client.inner.as_ref().unwrap().left_click_mine(mining); + client.left_click_mine(mining); Ok(()) } pub fn start_mining(_lua: &Lua, client: &mut Client, position: Vec3) -> Result<()> { #[allow(clippy::cast_possible_truncation)] - client.inner.as_mut().unwrap().start_mining(BlockPos::new( + client.start_mining(BlockPos::new( position.x as i32, position.y as i32, position.z as i32, diff --git a/src/lua/client/mod.rs b/src/lua/client/mod.rs index 81a1c48..9137832 100644 --- a/src/lua/client/mod.rs +++ b/src/lua/client/mod.rs @@ -5,18 +5,36 @@ mod state; mod world; use super::{ - container::item_stack::ItemStack, - container::{Container, ContainerRef}, + container::{Container, ContainerRef, item_stack::ItemStack}, direction::Direction, vec3::Vec3, }; use azalea::Client as AzaleaClient; use mlua::{Lua, Result, Table, UserData, UserDataFields, UserDataMethods}; +use std::ops::{Deref, DerefMut}; pub struct Client { pub inner: Option, } +impl Deref for Client { + type Target = AzaleaClient; + + fn deref(&self) -> &Self::Target { + self.inner + .as_ref() + .expect("should have received init event") + } +} + +impl DerefMut for Client { + fn deref_mut(&mut self) -> &mut Self::Target { + self.inner + .as_mut() + .expect("should have received init event") + } +} + impl UserData for Client { fn add_fields>(f: &mut F) { f.add_field_method_get("air_supply", state::air_supply); @@ -65,18 +83,18 @@ impl UserData for Client { } fn chat(_lua: &Lua, client: &Client, message: String) -> Result<()> { - client.inner.as_ref().unwrap().chat(&message); + client.chat(&message); Ok(()) } fn disconnect(_lua: &Lua, client: &Client, _: ()) -> Result<()> { - client.inner.as_ref().unwrap().disconnect(); + client.disconnect(); Ok(()) } fn tab_list(lua: &Lua, client: &Client) -> Result
{ let tab_list = lua.create_table()?; - for (uuid, player_info) in client.inner.as_ref().unwrap().tab_list() { + for (uuid, player_info) in client.tab_list() { let player = lua.create_table()?; player.set("gamemode", player_info.gamemode.name())?; player.set("latency", player_info.latency)?; @@ -91,5 +109,5 @@ fn tab_list(lua: &Lua, client: &Client) -> Result
{ } fn uuid(_lua: &Lua, client: &Client) -> Result { - Ok(client.inner.as_ref().unwrap().uuid().to_string()) + Ok(client.uuid().to_string()) } diff --git a/src/lua/client/movement.rs b/src/lua/client/movement.rs index 5658912..1c853b3 100644 --- a/src/lua/client/movement.rs +++ b/src/lua/client/movement.rs @@ -1,6 +1,6 @@ use super::{Client, Direction, Vec3}; use azalea::{ - BlockPos, BotClientExt, Client as AzaleaClient, SprintDirection, WalkDirection, + BlockPos, BotClientExt, SprintDirection, WalkDirection, interact::HitResultComponent, pathfinder::{ ExecutingPath, GotoEvent, Pathfinder, PathfinderClientExt, @@ -10,12 +10,12 @@ use azalea::{ use mlua::{FromLua, Lua, Result, Table, UserDataRef, Value}; pub fn direction(_lua: &Lua, client: &Client) -> Result { - let d = client.inner.as_ref().unwrap().direction(); + let d = client.direction(); Ok(Direction { x: d.0, y: d.1 }) } pub fn eye_position(_lua: &Lua, client: &Client) -> Result { - let p = client.inner.as_ref().unwrap().eye_position(); + let p = client.eye_position(); Ok(Vec3 { x: p.x, y: p.y, @@ -28,7 +28,7 @@ pub async fn goto( client: UserDataRef, (data, metadata): (Value, Option
), ) -> Result<()> { - fn g(client: &AzaleaClient, without_mining: bool, goal: impl Goal + Send + Sync + 'static) { + fn g(client: &Client, without_mining: bool, goal: impl Goal + Send + Sync + 'static) { if without_mining { client.goto_without_mining(goal); } else { @@ -41,7 +41,6 @@ pub async fn goto( to: "Table".to_string(), message: None, }; - let client = client.inner.as_ref().unwrap(); let (goal_type, without_mining) = metadata .map(|t| { ( @@ -57,7 +56,7 @@ pub async fn goto( let t = data.as_table().ok_or(error)?; let p = Vec3::from_lua(t.get("position")?, &lua)?; g( - client, + &client, without_mining, RadiusGoal { pos: azalea::Vec3::new(p.x, p.y, p.z), @@ -68,7 +67,7 @@ pub async fn goto( 2 => { let p = Vec3::from_lua(data, &lua)?; g( - client, + &client, without_mining, ReachBlockPosGoal { pos: BlockPos::new(p.x as i32, p.y as i32, p.z as i32), @@ -79,7 +78,7 @@ pub async fn goto( 3 => { let t = data.as_table().ok_or(error)?; g( - client, + &client, without_mining, XZGoal { x: t.get("x")?, @@ -88,7 +87,7 @@ pub async fn goto( ); } 4 => g( - client, + &client, without_mining, YGoal { y: data.as_integer().ok_or(error)?, @@ -97,7 +96,7 @@ pub async fn goto( _ => { let p = Vec3::from_lua(data, &lua)?; g( - client, + &client, without_mining, BlockPosGoal(BlockPos::new(p.x as i32, p.y as i32, p.z as i32)), ); @@ -114,16 +113,12 @@ pub async fn goto( } pub fn jump(_lua: &Lua, client: &mut Client, _: ()) -> Result<()> { - client.inner.as_mut().unwrap().jump(); + client.jump(); Ok(()) } pub fn looking_at(lua: &Lua, client: &Client) -> Result> { - let hr = client - .inner - .as_ref() - .unwrap() - .component::(); + let hr = client.component::(); Ok(if hr.miss { None } else { @@ -143,16 +138,11 @@ pub fn looking_at(lua: &Lua, client: &Client) -> Result> { } pub fn look_at(_lua: &Lua, client: &mut Client, position: Vec3) -> Result<()> { - client - .inner - .as_mut() - .unwrap() - .look_at(azalea::Vec3::new(position.x, position.y, position.z)); + client.look_at(azalea::Vec3::new(position.x, position.y, position.z)); Ok(()) } pub fn pathfinder(lua: &Lua, client: &Client) -> Result
{ - let client = client.inner.as_ref().unwrap(); let pathfinder = lua.create_table()?; pathfinder.set( "is_calculating", @@ -183,7 +173,7 @@ pub fn pathfinder(lua: &Lua, client: &Client) -> Result
{ } pub fn position(_lua: &Lua, client: &Client) -> Result { - let p = client.inner.as_ref().unwrap().position(); + let p = client.position(); Ok(Vec3 { x: p.x, y: p.y, @@ -192,21 +182,17 @@ pub fn position(_lua: &Lua, client: &Client) -> Result { } pub fn set_direction(_lua: &Lua, client: &mut Client, direction: (f32, f32)) -> Result<()> { - client - .inner - .as_mut() - .unwrap() - .set_direction(direction.0, direction.1); + client.set_direction(direction.0, direction.1); Ok(()) } pub fn set_jumping(_lua: &Lua, client: &mut Client, jumping: bool) -> Result<()> { - client.inner.as_mut().unwrap().set_jumping(jumping); + client.set_jumping(jumping); Ok(()) } pub fn sprint(_lua: &Lua, client: &mut Client, direction: u8) -> Result<()> { - client.inner.as_mut().unwrap().sprint(match direction { + client.sprint(match direction { 5 => SprintDirection::ForwardRight, 6 => SprintDirection::ForwardLeft, _ => SprintDirection::Forward, @@ -215,12 +201,12 @@ pub fn sprint(_lua: &Lua, client: &mut Client, direction: u8) -> Result<()> { } pub fn stop_pathfinding(_lua: &Lua, client: &Client, _: ()) -> Result<()> { - client.inner.as_ref().unwrap().stop_pathfinding(); + client.stop_pathfinding(); Ok(()) } pub fn walk(_lua: &Lua, client: &mut Client, direction: u8) -> Result<()> { - client.inner.as_mut().unwrap().walk(match direction { + client.walk(match direction { 1 => WalkDirection::Forward, 2 => WalkDirection::Backward, 3 => WalkDirection::Left, diff --git a/src/lua/client/state.rs b/src/lua/client/state.rs index 1ed1c7e..5c6e543 100644 --- a/src/lua/client/state.rs +++ b/src/lua/client/state.rs @@ -3,18 +3,19 @@ use azalea::{ ClientInformation, entity::metadata::{AirSupply, Score}, }; +use log::error; use mlua::{Lua, Result, Table, UserDataRef}; pub fn air_supply(_lua: &Lua, client: &Client) -> Result { - Ok(client.inner.as_ref().unwrap().component::().0) + Ok(client.component::().0) } pub fn health(_lua: &Lua, client: &Client) -> Result { - Ok(client.inner.as_ref().unwrap().health()) + Ok(client.health()) } pub fn hunger(lua: &Lua, client: &Client) -> Result
{ - let h = client.inner.as_ref().unwrap().hunger(); + let h = client.hunger(); let hunger = lua.create_table()?; hunger.set("food", h.food)?; @@ -23,7 +24,7 @@ pub fn hunger(lua: &Lua, client: &Client) -> Result
{ } pub fn score(_lua: &Lua, client: &Client) -> Result { - Ok(client.inner.as_ref().unwrap().component::().0) + Ok(client.component::().0) } pub async fn set_client_information( @@ -31,15 +32,14 @@ pub async fn set_client_information( client: UserDataRef, client_information: Table, ) -> Result<()> { - client - .inner - .as_ref() - .unwrap() + if let Err(error) = client .set_client_information(ClientInformation { view_distance: client_information.get("view_distance")?, ..ClientInformation::default() }) .await - .unwrap(); + { + error!("failed to set client client information: {error:?}"); + } Ok(()) } diff --git a/src/lua/client/world.rs b/src/lua/client/world.rs index 46c4f33..0000d76 100644 --- a/src/lua/client/world.rs +++ b/src/lua/client/world.rs @@ -10,11 +10,7 @@ use azalea::{ use mlua::{Function, Lua, Result, Table}; pub fn best_tool_for_block(lua: &Lua, client: &Client, block_state: u16) -> Result
{ - let tr = client - .inner - .as_ref() - .unwrap() - .best_tool_in_hotbar_for_block(BlockState { id: block_state }); + let tr = client.best_tool_in_hotbar_for_block(BlockState { id: block_state }); let tool_result = lua.create_table()?; tool_result.set("index", tr.index)?; @@ -29,9 +25,6 @@ pub fn find_blocks( ) -> Result> { #[allow(clippy::cast_possible_truncation)] Ok(client - .inner - .as_ref() - .unwrap() .world() .read() .find_blocks( @@ -55,7 +48,7 @@ pub fn find_blocks( pub fn find_entities(lua: &Lua, client: &Client, filter_fn: Function) -> Result> { let mut matched = Vec::new(); - let mut ecs = client.inner.as_ref().unwrap().ecs.lock(); + let mut ecs = client.ecs.lock(); let mut query = ecs.query_filtered::<( &MinecraftEntityId, &EntityUuid, @@ -90,9 +83,6 @@ pub fn find_entities(lua: &Lua, client: &Client, filter_fn: Function) -> Result< pub fn get_block_state(_lua: &Lua, client: &Client, position: Vec3) -> Result> { #[allow(clippy::cast_possible_truncation)] Ok(client - .inner - .as_ref() - .unwrap() .world() .read() .get_block_state(&BlockPos::new( @@ -106,18 +96,11 @@ pub fn get_block_state(_lua: &Lua, client: &Client, position: Vec3) -> Result Result> { #[allow(clippy::cast_possible_truncation)] Ok( - if let Some(fs) = client - .inner - .as_ref() - .unwrap() - .world() - .read() - .get_fluid_state(&BlockPos::new( - position.x as i32, - position.y as i32, - position.z as i32, - )) - { + if let Some(fs) = client.world().read().get_fluid_state(&BlockPos::new( + position.x as i32, + position.y as i32, + position.z as i32, + )) { let fluid_state = lua.create_table()?; fluid_state.set("kind", fs.kind as u8)?; fluid_state.set("amount", fs.amount)?; From 324cb2d6d86905137c5516074c059d48a864b110 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Tue, 18 Feb 2025 21:34:57 -0500 Subject: [PATCH 25/35] refactor(client): make more methods async --- src/lua/client/interaction.rs | 18 +++++++++++++++--- src/lua/client/mod.rs | 4 ++-- src/lua/client/movement.rs | 20 +++++++++++++++++--- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/lua/client/interaction.rs b/src/lua/client/interaction.rs index bd0c024..3090038 100644 --- a/src/lua/client/interaction.rs +++ b/src/lua/client/interaction.rs @@ -1,9 +1,21 @@ use super::{Client, Vec3}; -use azalea::{BlockPos, BotClientExt, world::MinecraftEntityId}; +use azalea::{BlockPos, BotClientExt, attack::AttackEvent, world::MinecraftEntityId}; use mlua::{Lua, Result, UserDataRef}; -pub fn attack(_lua: &Lua, client: &mut Client, entity_id: u32) -> Result<()> { - client.attack(MinecraftEntityId(entity_id)); +pub async fn attack(_lua: Lua, client: UserDataRef, entity_id: u32) -> Result<()> { + client.clone().attack(MinecraftEntityId(entity_id)); + + while client.get_tick_broadcaster().recv().await.is_ok() { + if client + .ecs + .lock() + .get::(client.entity) + .is_none() + { + break; + } + } + Ok(()) } diff --git a/src/lua/client/mod.rs b/src/lua/client/mod.rs index 9137832..717ad4f 100644 --- a/src/lua/client/mod.rs +++ b/src/lua/client/mod.rs @@ -55,7 +55,9 @@ impl UserData for Client { } fn add_methods>(m: &mut M) { + m.add_async_method("attack", interaction::attack); m.add_async_method("goto", movement::goto); + m.add_async_method("look_at", movement::look_at); m.add_async_method("mine", interaction::mine); m.add_async_method("open_container_at", container::open_container_at); m.add_async_method("set_client_information", state::set_client_information); @@ -69,10 +71,8 @@ impl UserData for Client { m.add_method("set_held_slot", container::set_held_slot); m.add_method("set_mining", interaction::set_mining); m.add_method("stop_pathfinding", movement::stop_pathfinding); - m.add_method_mut("attack", interaction::attack); m.add_method_mut("block_interact", interaction::block_interact); m.add_method_mut("jump", movement::jump); - m.add_method_mut("look_at", movement::look_at); m.add_method_mut("open_inventory", container::open_inventory); m.add_method_mut("set_direction", movement::set_direction); m.add_method_mut("set_jumping", movement::set_jumping); diff --git a/src/lua/client/movement.rs b/src/lua/client/movement.rs index 1c853b3..ad6de42 100644 --- a/src/lua/client/movement.rs +++ b/src/lua/client/movement.rs @@ -1,6 +1,6 @@ use super::{Client, Direction, Vec3}; use azalea::{ - BlockPos, BotClientExt, SprintDirection, WalkDirection, + BlockPos, BotClientExt, LookAtEvent, SprintDirection, WalkDirection, interact::HitResultComponent, pathfinder::{ ExecutingPath, GotoEvent, Pathfinder, PathfinderClientExt, @@ -137,8 +137,22 @@ pub fn looking_at(lua: &Lua, client: &Client) -> Result> { }) } -pub fn look_at(_lua: &Lua, client: &mut Client, position: Vec3) -> Result<()> { - client.look_at(azalea::Vec3::new(position.x, position.y, position.z)); +pub async fn look_at(_lua: Lua, client: UserDataRef, position: Vec3) -> Result<()> { + client + .clone() + .look_at(azalea::Vec3::new(position.x, position.y, position.z)); + + while client.get_tick_broadcaster().recv().await.is_ok() { + if client + .ecs + .lock() + .get::(client.entity) + .is_none() + { + break; + } + } + Ok(()) } From aa27d9fd365659b3139b922d12c365ae6569305b Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Tue, 18 Feb 2025 21:34:57 -0500 Subject: [PATCH 26/35] feat(lib): add distance function --- lib/utils.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/utils.lua b/lib/utils.lua index cf6023b..03a48bc 100644 --- a/lib/utils.lua +++ b/lib/utils.lua @@ -12,6 +12,10 @@ function get_player(name) end)[1] end +function distance(p1, p2) + return math.sqrt((p2.x - p1.x) ^ 2 + (p2.y - p1.y) ^ 2 + (p2.z - p1.z) ^ 2) +end + function dump(object) if type(object) == "table" then local string = "{ " From c2da997b719253dc504bfe5c47e393d7457396d5 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Wed, 19 Feb 2025 08:02:11 -0500 Subject: [PATCH 27/35] refactor: a few small efficiency improvements --- src/commands.rs | 2 +- src/lua/client/movement.rs | 3 ++- src/main.rs | 18 ++++++++++++++---- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index cd00c15..f800dd0 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -9,7 +9,7 @@ use azalea::{ use bevy_ecs::{entity::Entity, query::With}; use futures::lock::Mutex; -pub type Ctx<'a> = CommandContext>; +pub type Ctx = CommandContext>; pub struct CommandSource { pub client: Client, diff --git a/src/lua/client/movement.rs b/src/lua/client/movement.rs index ad6de42..06b9ee5 100644 --- a/src/lua/client/movement.rs +++ b/src/lua/client/movement.rs @@ -1,6 +1,7 @@ use super::{Client, Direction, Vec3}; use azalea::{ BlockPos, BotClientExt, LookAtEvent, SprintDirection, WalkDirection, + entity::Position, interact::HitResultComponent, pathfinder::{ ExecutingPath, GotoEvent, Pathfinder, PathfinderClientExt, @@ -187,7 +188,7 @@ pub fn pathfinder(lua: &Lua, client: &Client) -> Result
{ } pub fn position(_lua: &Lua, client: &Client) -> Result { - let p = client.position(); + let p = client.component::(); Ok(Vec3 { x: p.x, y: p.y, diff --git a/src/main.rs b/src/main.rs index c91d9ce..0bb76c9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,6 +14,8 @@ use futures::lock::Mutex; use mlua::Lua; use std::{net::SocketAddr, path::PathBuf, sync::Arc}; +const DEFAULT_SCRIPT_PATH: &str = "errornowatcher.lua"; + #[derive(Default, Clone, Component)] pub struct State { lua: Lua, @@ -24,14 +26,22 @@ pub struct State { #[tokio::main] async fn main() -> anyhow::Result<()> { let args = arguments::Arguments::parse(); - let script_path = args.script.unwrap_or(PathBuf::from("errornowatcher.lua")); + let script_path = args.script.unwrap_or(PathBuf::from(DEFAULT_SCRIPT_PATH)); let lua = Lua::new(); - lua.load(std::fs::read_to_string(&script_path)?).exec()?; + lua.load( + std::fs::read_to_string(&script_path) + .expect(&(DEFAULT_SCRIPT_PATH.to_owned() + " should be in current directory")), + ) + .exec()?; let globals = lua.globals(); - let server = globals.get::("SERVER")?; - let username = globals.get::("USERNAME")?; + let server = globals + .get::("SERVER") + .expect("SERVER should be in lua globals"); + let username = globals + .get::("USERNAME") + .expect("USERNAME should be in lua globals"); globals.set("script_path", script_path)?; lua::register_functions(&lua, &globals)?; From bd6698c4b4e011bb4d356b1a54482f3333961d71 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Thu, 20 Feb 2025 21:07:41 -0500 Subject: [PATCH 28/35] feat: add event listeners --- lib/events.lua | 14 ++++++--- src/events.rs | 41 +++++++++++++++--------- src/lua/events.rs | 79 +++++++++++++++++++++++++++++++++++++++++++++++ src/lua/mod.rs | 5 +-- src/main.rs | 12 ++++--- 5 files changed, 126 insertions(+), 25 deletions(-) create mode 100644 src/lua/events.rs diff --git a/lib/events.lua b/lib/events.lua index 8a960c4..7bd4c55 100644 --- a/lib/events.lua +++ b/lib/events.lua @@ -1,7 +1,7 @@ local center = { x = 0, z = 0 } local radius = 100 -function on_tick() +function log_player_positions() local entities = client:find_entities(function(e) return e.kind == "minecraft:player" and e.position.x > center.x - radius + 1 @@ -17,8 +17,14 @@ end function on_init() info("client initialized, setting information...") client:set_client_information({ view_distance = 16 }) -end -function on_login() - info("player successfully logged in!") + add_listener("login", function() + info("player successfully logged in!") + end) + + add_listener("death", function() + warn("player died!") + end, "warn_player_died") + + add_listener("tick", log_player_positions) end diff --git a/src/events.rs b/src/events.rs index fec8620..6dbd624 100644 --- a/src/events.rs +++ b/src/events.rs @@ -1,9 +1,14 @@ -use crate::{State, commands::CommandSource, http::serve, lua}; +use crate::{ + State, + commands::CommandSource, + http::serve, + lua::{self, events::register_functions}, +}; use azalea::prelude::*; use hyper::{server::conn::http1, service::service_fn}; use hyper_util::rt::TokioIo; use log::{debug, error, info, trace}; -use mlua::{Function, IntoLuaMulti, Table}; +use mlua::{Function, IntoLuaMulti}; use tokio::net::TcpListener; pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow::Result<()> { @@ -32,23 +37,22 @@ pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow: CommandSource { client, message, - state, + state: state.clone(), } .reply(&format!("{error:?}")); } } - call_lua_handler(&globals, "on_chat", ()); + call_listeners(&state, "chat", formatted_message.to_string()).await; } Event::Death(Some(packet)) => { let death_data = state.lua.create_table()?; death_data.set("message", packet.message.to_string())?; death_data.set("player_id", packet.player_id)?; - - call_lua_handler(&globals, "on_death", death_data); + call_listeners(&state, "death", death_data).await; } - Event::Tick => call_lua_handler(&globals, "on_tick", ()), - Event::Login => call_lua_handler(&globals, "on_login", ()), + Event::Login => call_listeners(&state, "login", ()).await, + Event::Tick => call_listeners(&state, "tick", ()).await, Event::Init => { debug!("client initialized"); @@ -58,7 +62,12 @@ pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow: inner: Some(client), }, )?; - call_lua_handler(&globals, "on_init", ()); + register_functions(&state.lua, &globals, state.clone()).await?; + if let Ok(on_init) = globals.get::("on_init") + && let Err(error) = on_init.call::<()>(()) + { + error!("failed to call lua on_init function: {error:?}"); + } if let Some(address) = state.http_address { let listener = TcpListener::bind(address).await.map_err(|error| { @@ -77,7 +86,7 @@ pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow: async move { serve(request, request_state).await } }); - tokio::task::spawn(async move { + tokio::spawn(async move { if let Err(error) = http1::Builder::new() .serve_connection(TokioIo::new(stream), service) .await @@ -94,10 +103,12 @@ pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow: Ok(()) } -fn call_lua_handler(globals: &Table, name: &str, data: T) { - if let Ok(handler) = globals.get::(name) - && let Err(error) = handler.call::<()>(data) - { - error!("failed to call lua {name} function: {error:?}"); +async fn call_listeners(state: &State, event_type: &str, data: T) { + if let Some(listeners) = state.event_listeners.lock().await.get(event_type) { + for (_, listener) in listeners { + if let Err(error) = listener.call_async::<()>(data.clone()).await { + error!("failed to call lua event listener for {event_type}: {error:?}"); + } + } } } diff --git a/src/lua/events.rs b/src/lua/events.rs new file mode 100644 index 0000000..5b0e1c3 --- /dev/null +++ b/src/lua/events.rs @@ -0,0 +1,79 @@ +use crate::State; +use futures::executor::block_on; +use mlua::{Function, Lua, Result, Table}; +use std::time::{SystemTime, UNIX_EPOCH}; + +pub async fn register_functions(lua: &Lua, globals: &Table, state: State) -> Result<()> { + let l = state.event_listeners.clone(); + globals.set( + "add_listener", + lua.create_function( + move |_, (event_type, callback, id): (String, Function, Option)| { + let mut l = block_on(l.lock()); + + l.entry(event_type).or_default().push(( + id.unwrap_or(callback.info().name.unwrap_or(format!( + "anonymous @ {}", + SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_millis() + ))), + callback, + )); + Ok(()) + }, + )?, + )?; + + let l = state.event_listeners.clone(); + globals.set( + "remove_listener", + lua.create_function(move |_, (event_type, target_id): (String, String)| { + let mut l = block_on(l.lock()); + + let empty = if let Some(listeners) = l.get_mut(&event_type) { + listeners.retain(|(id, _)| target_id != *id); + listeners.is_empty() + } else { + false + }; + if empty { + l.remove(&event_type); + } + + Ok(()) + })?, + )?; + + globals.set( + "get_listeners", + lua.create_function(move |lua, (): ()| { + let l = block_on(state.event_listeners.lock()); + + let listeners = lua.create_table()?; + for (event_type, callbacks) in l.iter() { + let type_listeners = lua.create_table()?; + for (id, callback) in callbacks { + let listener = lua.create_table()?; + let i = callback.info(); + if let Some(n) = i.name { + listener.set("name", n)?; + } + if let Some(l) = i.line_defined { + listener.set("line_defined", l)?; + } + if let Some(s) = i.source { + listener.set("source", s)?; + } + type_listeners.set(id.to_owned(), listener)?; + } + listeners.set(event_type.to_owned(), type_listeners)?; + } + + Ok(listeners) + })?, + )?; + + Ok(()) +} diff --git a/src/lua/mod.rs b/src/lua/mod.rs index 59bfbfa..c83b62d 100644 --- a/src/lua/mod.rs +++ b/src/lua/mod.rs @@ -2,6 +2,7 @@ pub mod block; pub mod client; pub mod container; pub mod direction; +pub mod events; pub mod logging; pub mod vec3; @@ -26,8 +27,8 @@ pub fn register_functions(lua: &Lua, globals: &Table) -> mlua::Result<()> { })?, )?; - logging::register_functions(lua, globals)?; - block::register_functions(lua, globals) + block::register_functions(lua, globals)?; + logging::register_functions(lua, globals) } pub fn reload(lua: &Lua) -> Result<(), Error> { diff --git a/src/main.rs b/src/main.rs index 0bb76c9..c2f336e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,16 +11,19 @@ use clap::Parser; use commands::{CommandSource, register}; use events::handle_event; use futures::lock::Mutex; -use mlua::Lua; -use std::{net::SocketAddr, path::PathBuf, sync::Arc}; +use mlua::{Function, Lua}; +use std::{collections::HashMap, net::SocketAddr, path::PathBuf, sync::Arc}; const DEFAULT_SCRIPT_PATH: &str = "errornowatcher.lua"; +type ListenerMap = HashMap>; + #[derive(Default, Clone, Component)] pub struct State { lua: Lua, - http_address: Option, + event_listeners: Arc>, commands: Arc>>, + http_address: Option, } #[tokio::main] @@ -53,8 +56,9 @@ async fn main() -> anyhow::Result<()> { .set_handler(handle_event) .set_state(State { lua, - http_address: args.http_address, + event_listeners: Arc::new(Mutex::new(HashMap::new())), commands: Arc::new(commands), + http_address: args.http_address, }) .start( if username.contains('@') { From 2f9e4f50cf519a19f2a7bdf9f474a327a3b6bc88 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Fri, 21 Feb 2025 21:36:24 -0500 Subject: [PATCH 29/35] refactor: convert to Player struct --- lib/utils.lua | 4 ++-- src/lua/client/mod.rs | 19 ++++++------------- src/lua/mod.rs | 1 + src/lua/player.rs | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 15 deletions(-) create mode 100644 src/lua/player.rs diff --git a/lib/utils.lua b/lib/utils.lua index 03a48bc..c0afebd 100644 --- a/lib/utils.lua +++ b/lib/utils.lua @@ -1,8 +1,8 @@ function get_player(name) local target_uuid = nil - for uuid, player in client.tab_list do + for _, player in client.tab_list do if player.name == name then - target_uuid = uuid + target_uuid = player.uuid break end end diff --git a/src/lua/client/mod.rs b/src/lua/client/mod.rs index 717ad4f..364d70b 100644 --- a/src/lua/client/mod.rs +++ b/src/lua/client/mod.rs @@ -7,10 +7,11 @@ mod world; use super::{ container::{Container, ContainerRef, item_stack::ItemStack}, direction::Direction, + player::Player, vec3::Vec3, }; use azalea::Client as AzaleaClient; -use mlua::{Lua, Result, Table, UserData, UserDataFields, UserDataMethods}; +use mlua::{Lua, Result, UserData, UserDataFields, UserDataMethods}; use std::ops::{Deref, DerefMut}; pub struct Client { @@ -92,18 +93,10 @@ fn disconnect(_lua: &Lua, client: &Client, _: ()) -> Result<()> { Ok(()) } -fn tab_list(lua: &Lua, client: &Client) -> Result
{ - let tab_list = lua.create_table()?; - for (uuid, player_info) in client.tab_list() { - let player = lua.create_table()?; - player.set("gamemode", player_info.gamemode.name())?; - player.set("latency", player_info.latency)?; - player.set("name", player_info.profile.name)?; - player.set( - "display_name", - player_info.display_name.map(|n| n.to_string()), - )?; - tab_list.set(uuid.to_string(), player)?; +fn tab_list(_lua: &Lua, client: &Client) -> Result> { + let mut tab_list = Vec::new(); + for (_, player_info) in client.tab_list() { + tab_list.push(Player::from(player_info)); } Ok(tab_list) } diff --git a/src/lua/mod.rs b/src/lua/mod.rs index c83b62d..b526ee7 100644 --- a/src/lua/mod.rs +++ b/src/lua/mod.rs @@ -4,6 +4,7 @@ pub mod container; pub mod direction; pub mod events; pub mod logging; +pub mod player; pub mod vec3; use mlua::{Lua, Table}; diff --git a/src/lua/player.rs b/src/lua/player.rs new file mode 100644 index 0000000..8981e00 --- /dev/null +++ b/src/lua/player.rs @@ -0,0 +1,35 @@ +use azalea::PlayerInfo; +use mlua::{IntoLua, Lua, Result, Value}; + +#[derive(Clone)] +pub struct Player { + pub display_name: Option, + pub gamemode: String, + pub latency: i32, + pub name: String, + pub uuid: String, +} + +impl From for Player { + fn from(p: PlayerInfo) -> Self { + Self { + display_name: p.display_name.map(|n| n.to_string()), + gamemode: p.gamemode.name().to_owned(), + latency: p.latency, + name: p.profile.name, + uuid: p.uuid.to_string(), + } + } +} + +impl IntoLua for Player { + fn into_lua(self, lua: &Lua) -> Result { + let table = lua.create_table()?; + table.set("display_name", self.display_name)?; + table.set("gamemode", self.gamemode)?; + table.set("latency", self.latency)?; + table.set("name", self.name)?; + table.set("uuid", self.uuid)?; + Ok(Value::Table(table)) + } +} From 6f0f3938a71895b032ad0e6fc7b01b2f8eb240fd Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Fri, 21 Feb 2025 21:41:17 -0500 Subject: [PATCH 30/35] feat: add last few wrapped events --- src/events.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/events.rs b/src/events.rs index 6dbd624..125ab20 100644 --- a/src/events.rs +++ b/src/events.rs @@ -2,7 +2,7 @@ use crate::{ State, commands::CommandSource, http::serve, - lua::{self, events::register_functions}, + lua::{self, events::register_functions, player::Player}, }; use azalea::prelude::*; use hyper::{server::conn::http1, service::service_fn}; @@ -16,6 +16,9 @@ pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow: let globals = state.lua.globals(); match event { + Event::AddPlayer(player_info) => { + call_listeners(&state, "add_player", Player::from(player_info)).await; + } Event::Chat(message) => { let formatted_message = message.message(); info!("{}", formatted_message.to_ansi()); @@ -51,8 +54,17 @@ pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow: death_data.set("player_id", packet.player_id)?; call_listeners(&state, "death", death_data).await; } + Event::Disconnect(message) => { + call_listeners(&state, "disconnect", message.map(|m| m.to_string())).await; + } Event::Login => call_listeners(&state, "login", ()).await, + Event::RemovePlayer(player_info) => { + call_listeners(&state, "remove_player", Player::from(player_info)).await; + } Event::Tick => call_listeners(&state, "tick", ()).await, + Event::UpdatePlayer(player_info) => { + call_listeners(&state, "update_player", Player::from(player_info)).await; + } Event::Init => { debug!("client initialized"); From ea7a3707150c5664aa73ac4c7de08fb606cda2f8 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Fri, 21 Feb 2025 22:09:58 -0500 Subject: [PATCH 31/35] refactor: impl From for Vec3 --- src/lua/client/movement.rs | 40 ++++++++------------------------------ src/lua/client/world.rs | 15 ++------------ src/lua/vec3.rs | 31 +++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 45 deletions(-) diff --git a/src/lua/client/movement.rs b/src/lua/client/movement.rs index 06b9ee5..7a208a6 100644 --- a/src/lua/client/movement.rs +++ b/src/lua/client/movement.rs @@ -16,12 +16,7 @@ pub fn direction(_lua: &Lua, client: &Client) -> Result { } pub fn eye_position(_lua: &Lua, client: &Client) -> Result { - let p = client.eye_position(); - Ok(Vec3 { - x: p.x, - y: p.y, - z: p.z, - }) + Ok(Vec3::from(client.eye_position())) } pub async fn goto( @@ -119,21 +114,14 @@ pub fn jump(_lua: &Lua, client: &mut Client, _: ()) -> Result<()> { } pub fn looking_at(lua: &Lua, client: &Client) -> Result> { - let hr = client.component::(); - Ok(if hr.miss { + let r = client.component::(); + Ok(if r.miss { None } else { let result = lua.create_table()?; - result.set( - "position", - Vec3 { - x: f64::from(hr.block_pos.x), - y: f64::from(hr.block_pos.y), - z: f64::from(hr.block_pos.z), - }, - )?; - result.set("inside", hr.inside)?; - result.set("world_border", hr.world_border)?; + result.set("position", Vec3::from(r.block_pos))?; + result.set("inside", r.inside)?; + result.set("world_border", r.world_border)?; Some(result) }) } @@ -166,14 +154,7 @@ pub fn pathfinder(lua: &Lua, client: &Client) -> Result
{ pathfinder.set( "is_executing", if let Some(p) = client.get_component::() { - pathfinder.set( - "last_reached_node", - Vec3 { - x: f64::from(p.last_reached_node.x), - y: f64::from(p.last_reached_node.y), - z: f64::from(p.last_reached_node.z), - }, - )?; + pathfinder.set("last_reached_node", Vec3::from(p.last_reached_node))?; pathfinder.set( "last_node_reach_elapsed", p.last_node_reached_at.elapsed().as_millis(), @@ -188,12 +169,7 @@ pub fn pathfinder(lua: &Lua, client: &Client) -> Result
{ } pub fn position(_lua: &Lua, client: &Client) -> Result { - let p = client.component::(); - Ok(Vec3 { - x: p.x, - y: p.y, - z: p.z, - }) + Ok(Vec3::from(&client.component::())) } pub fn set_direction(_lua: &Lua, client: &mut Client, direction: (f32, f32)) -> Result<()> { diff --git a/src/lua/client/world.rs b/src/lua/client/world.rs index 0000d76..83167c4 100644 --- a/src/lua/client/world.rs +++ b/src/lua/client/world.rs @@ -37,11 +37,7 @@ pub fn find_blocks( set: block_states.iter().map(|&id| BlockState { id }).collect(), }, ) - .map(|p| Vec3 { - x: f64::from(p.x), - y: f64::from(p.y), - z: f64::from(p.z), - }) + .map(Vec3::from) .collect()) } @@ -62,14 +58,7 @@ pub fn find_entities(lua: &Lua, client: &Client, filter_fn: Function) -> Result< entity.set("id", id.0)?; entity.set("uuid", uuid.to_string())?; entity.set("kind", kind.to_string())?; - entity.set( - "position", - Vec3 { - x: position.x, - y: position.y, - z: position.z, - }, - )?; + entity.set("position", Vec3::from(position))?; entity.set("custom_name", custom_name.as_ref().map(ToString::to_string))?; if filter_fn.call::(&entity)? { diff --git a/src/lua/vec3.rs b/src/lua/vec3.rs index 5d8e50b..e8f0e97 100644 --- a/src/lua/vec3.rs +++ b/src/lua/vec3.rs @@ -1,3 +1,4 @@ +use azalea::{BlockPos, entity::Position}; use mlua::{FromLua, IntoLua, Lua, Result, Value}; #[derive(Clone)] @@ -17,6 +18,36 @@ impl IntoLua for Vec3 { } } +impl From for Vec3 { + fn from(v: azalea::Vec3) -> Self { + Self { + x: v.x, + y: v.y, + z: v.z, + } + } +} + +impl From<&Position> for Vec3 { + fn from(p: &Position) -> Self { + Self { + x: p.x, + y: p.y, + z: p.z, + } + } +} + +impl From for Vec3 { + fn from(p: BlockPos) -> Self { + Vec3 { + x: f64::from(p.x), + y: f64::from(p.y), + z: f64::from(p.z), + } + } +} + impl FromLua for Vec3 { fn from_lua(value: Value, _lua: &Lua) -> Result { match value { From a4606e68e4129d5995ffbd821d8e315cba1a1da6 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Fri, 21 Feb 2025 22:13:38 -0500 Subject: [PATCH 32/35] feat(client): add dimension field --- src/lua/client/mod.rs | 1 + src/lua/client/world.rs | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/lua/client/mod.rs b/src/lua/client/mod.rs index 364d70b..8540b79 100644 --- a/src/lua/client/mod.rs +++ b/src/lua/client/mod.rs @@ -40,6 +40,7 @@ impl UserData for Client { fn add_fields>(f: &mut F) { f.add_field_method_get("air_supply", state::air_supply); f.add_field_method_get("container", container::container); + f.add_field_method_get("dimension", world::dimension); f.add_field_method_get("direction", movement::direction); f.add_field_method_get("eye_position", movement::eye_position); f.add_field_method_get("has_attack_cooldown", interaction::has_attack_cooldown); diff --git a/src/lua/client/world.rs b/src/lua/client/world.rs index 83167c4..3c07c60 100644 --- a/src/lua/client/world.rs +++ b/src/lua/client/world.rs @@ -5,7 +5,7 @@ use azalea::{ blocks::{BlockState, BlockStates}, ecs::query::Without, entity::{Dead, EntityKind, EntityUuid, Position as AzaleaPosition, metadata::CustomName}, - world::MinecraftEntityId, + world::{InstanceName, MinecraftEntityId}, }; use mlua::{Function, Lua, Result, Table}; @@ -18,6 +18,10 @@ pub fn best_tool_for_block(lua: &Lua, client: &Client, block_state: u16) -> Resu Ok(tool_result) } +pub fn dimension(_lua: &Lua, client: &Client) -> Result { + Ok(client.component::().to_string()) +} + pub fn find_blocks( _lua: &Lua, client: &Client, From 08b9fbbc1ee8529ac68a496ef2bc8dc4cdb5162b Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Fri, 21 Feb 2025 22:32:21 -0500 Subject: [PATCH 33/35] chore: add basic readme --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..e80c40b --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# ErrorNoWatcher + +A Minecraft bot with Lua scripting support, written in Rust with [azalea](https://github.com/azalea-rs/azalea). + +## Features + +- Running Lua from + - `errornowatcher.lua` + - in-game chat messages + - POST requests to HTTP server +- Listening to in-game events +- Pathfinding (from azalea) +- Entity and chest interaction + +## Usage + +```sh +$ git clone https://github.com/ErrorNoInternet/ErrorNoWatcher +$ cd ErrorNoWatcher +$ cargo build --release +$ # ./target/release/errornowatcher +``` + +Make sure the `SERVER` and `USERNAME` globals are defined in `errornowatcher.lua` before starting the bot. From 70c1a83eb2f65acd62e7059a02ba080edad4c72d Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Fri, 21 Feb 2025 23:00:29 -0500 Subject: [PATCH 34/35] feat(client): bring a few commands from v0.1.0 --- src/lua/client/interaction.rs | 24 +++++++++++++++++++++++- src/lua/client/mod.rs | 3 +++ src/lua/client/movement.rs | 28 ++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/lua/client/interaction.rs b/src/lua/client/interaction.rs index 3090038..5215c37 100644 --- a/src/lua/client/interaction.rs +++ b/src/lua/client/interaction.rs @@ -1,5 +1,11 @@ use super::{Client, Vec3}; -use azalea::{BlockPos, BotClientExt, attack::AttackEvent, world::MinecraftEntityId}; +use azalea::{ + BlockPos, BotClientExt, + attack::AttackEvent, + protocol::packets::game::{ServerboundUseItem, s_interact::InteractionHand}, + world::MinecraftEntityId, +}; +use log::error; use mlua::{Lua, Result, UserDataRef}; pub async fn attack(_lua: Lua, client: UserDataRef, entity_id: u32) -> Result<()> { @@ -60,3 +66,19 @@ pub fn start_mining(_lua: &Lua, client: &mut Client, position: Vec3) -> Result<( )); Ok(()) } + +pub fn use_item(_lua: &Lua, client: &Client, hand: Option) -> Result<()> { + let d = client.direction(); + if let Err(error) = client.write_packet(ServerboundUseItem { + hand: match hand { + Some(1) => InteractionHand::OffHand, + _ => InteractionHand::MainHand, + }, + sequence: 0, + yaw: d.0, + pitch: d.1, + }) { + error!("failed to send UseItem packet: {error:?}"); + } + Ok(()) +} diff --git a/src/lua/client/mod.rs b/src/lua/client/mod.rs index 8540b79..cae8fc1 100644 --- a/src/lua/client/mod.rs +++ b/src/lua/client/mod.rs @@ -72,7 +72,10 @@ impl UserData for Client { m.add_method("get_fluid_state", world::get_fluid_state); m.add_method("set_held_slot", container::set_held_slot); m.add_method("set_mining", interaction::set_mining); + m.add_method("set_sneaking", movement::set_sneaking); m.add_method("stop_pathfinding", movement::stop_pathfinding); + m.add_method("stop_sleeping", movement::stop_sleeping); + m.add_method("use_item", interaction::use_item); m.add_method_mut("block_interact", interaction::block_interact); m.add_method_mut("jump", movement::jump); m.add_method_mut("open_inventory", container::open_inventory); diff --git a/src/lua/client/movement.rs b/src/lua/client/movement.rs index 7a208a6..8d909ea 100644 --- a/src/lua/client/movement.rs +++ b/src/lua/client/movement.rs @@ -7,7 +7,9 @@ use azalea::{ ExecutingPath, GotoEvent, Pathfinder, PathfinderClientExt, goals::{BlockPosGoal, Goal, RadiusGoal, ReachBlockPosGoal, XZGoal, YGoal}, }, + protocol::packets::game::{ServerboundPlayerCommand, s_player_command::Action}, }; +use log::error; use mlua::{FromLua, Lua, Result, Table, UserDataRef, Value}; pub fn direction(_lua: &Lua, client: &Client) -> Result { @@ -182,6 +184,21 @@ pub fn set_jumping(_lua: &Lua, client: &mut Client, jumping: bool) -> Result<()> Ok(()) } +pub fn set_sneaking(_lua: &Lua, client: &Client, sneaking: bool) -> Result<()> { + if let Err(error) = client.write_packet(ServerboundPlayerCommand { + id: client.entity.index(), + action: if sneaking { + Action::PressShiftKey + } else { + Action::ReleaseShiftKey + }, + data: 0, + }) { + error!("failed to send PlayerCommand packet: {error:?}"); + } + Ok(()) +} + pub fn sprint(_lua: &Lua, client: &mut Client, direction: u8) -> Result<()> { client.sprint(match direction { 5 => SprintDirection::ForwardRight, @@ -196,6 +213,17 @@ pub fn stop_pathfinding(_lua: &Lua, client: &Client, _: ()) -> Result<()> { Ok(()) } +pub fn stop_sleeping(_lua: &Lua, client: &Client, _: ()) -> Result<()> { + if let Err(error) = client.write_packet(ServerboundPlayerCommand { + id: client.entity.index(), + action: Action::StopSleeping, + data: 0, + }) { + error!("failed to send PlayerCommand packet: {error:?}"); + } + Ok(()) +} + pub fn walk(_lua: &Lua, client: &mut Client, direction: u8) -> Result<()> { client.walk(match direction { 1 => WalkDirection::Forward, From 6fa586829c21d38353bb9cccc70b02af938e5e62 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Fri, 21 Feb 2025 23:14:58 -0500 Subject: [PATCH 35/35] fix: exit on server disconnect azalea currently seems to just block forever. --- src/events.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/events.rs b/src/events.rs index 125ab20..fb322b3 100644 --- a/src/events.rs +++ b/src/events.rs @@ -1,3 +1,5 @@ +use std::process::exit; + use crate::{ State, commands::CommandSource, @@ -56,6 +58,7 @@ pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow: } Event::Disconnect(message) => { call_listeners(&state, "disconnect", message.map(|m| m.to_string())).await; + exit(1) } Event::Login => call_listeners(&state, "login", ()).await, Event::RemovePlayer(player_info) => {