1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 14:26:04 +00:00

Merge branch 'main' into autoreconnect

This commit is contained in:
mat 2025-05-02 02:21:24 +00:00
commit b96e1a77bc
54 changed files with 942 additions and 594 deletions

495
Cargo.lock generated
View file

@ -28,20 +28,6 @@ dependencies = [
"cpufeatures",
]
[[package]]
name = "ahash"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [
"cfg-if",
"const-random",
"getrandom 0.2.15",
"once_cell",
"version_check",
"zerocopy 0.7.35",
]
[[package]]
name = "aho-corasick"
version = "1.1.3"
@ -51,12 +37,6 @@ dependencies = [
"memchr",
]
[[package]]
name = "allocator-api2"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "android_log-sys"
version = "0.3.2"
@ -121,9 +101,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.97"
version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
[[package]]
name = "arrayvec"
@ -202,6 +182,9 @@ name = "async-task"
version = "4.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
dependencies = [
"portable-atomic",
]
[[package]]
name = "async-trait"
@ -214,6 +197,15 @@ dependencies = [
"syn",
]
[[package]]
name = "atomic-waker"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
dependencies = [
"portable-atomic",
]
[[package]]
name = "autocfg"
version = "1.4.0"
@ -600,28 +592,32 @@ checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3"
[[package]]
name = "bevy_app"
version = "0.15.3"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0ac033a388b8699d241499a43783a09e6a3bab2430f1297c6bd4974095efb3f"
checksum = "a2b6267ac23a9947d5b2725ff047a1e1add70076d85fa9fb73d044ab9bea1f3c"
dependencies = [
"bevy_derive",
"bevy_ecs",
"bevy_platform",
"bevy_reflect",
"bevy_tasks",
"bevy_utils",
"cfg-if",
"console_error_panic_hook",
"ctrlc",
"derive_more 1.0.0",
"downcast-rs",
"log",
"thiserror 2.0.12",
"variadics_please",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "bevy_derive"
version = "0.15.3"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57d94761ce947b0a2402fd949fe1e7a5b1535293130ba4cd9893be6295d4680a"
checksum = "f626531b9c05c25a758ede228727bd11c2c2c8498ecbed9925044386d525a2a3"
dependencies = [
"bevy_macro_utils",
"quote",
@ -630,30 +626,37 @@ dependencies = [
[[package]]
name = "bevy_ecs"
version = "0.15.3"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1597106cc01e62e6217ccb662e0748b2ce330893f27c7dc17bac33e0bb99bca9"
checksum = "d9e807b5d9aab3bb8dfe47e7a44c9ff088bad2ceefe299b80ac77609a87fe9d4"
dependencies = [
"arrayvec",
"bevy_ecs_macros",
"bevy_platform",
"bevy_ptr",
"bevy_reflect",
"bevy_tasks",
"bevy_utils",
"bitflags",
"bumpalo",
"concurrent-queue",
"derive_more 1.0.0",
"disqualified",
"fixedbitset 0.5.7",
"indexmap",
"log",
"nonmax",
"petgraph",
"serde",
"smallvec",
"thiserror 2.0.12",
"variadics_please",
]
[[package]]
name = "bevy_ecs_macros"
version = "0.15.3"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f453adf07712b39826bc5845e5b0887ce03204ee8359bbe6b40a9afda60564a1"
checksum = "467d7bb98aeb8dd30f36e6a773000c12a891d4f1bee2adc3841ec89cc8eaf54e"
dependencies = [
"bevy_macro_utils",
"proc-macro2",
@ -663,14 +666,15 @@ dependencies = [
[[package]]
name = "bevy_log"
version = "0.15.3"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b381a22e01f24af51536ef1eace94298dd555d06ffcf368125d16317f5f179cb"
checksum = "7156df8d2f11135cf71c03eb4c11132b65201fd4f51648571e59e39c9c9ee2f6"
dependencies = [
"android_log-sys",
"bevy_app",
"bevy_ecs",
"bevy_utils",
"tracing",
"tracing-log",
"tracing-oslog",
"tracing-subscriber",
@ -679,10 +683,11 @@ dependencies = [
[[package]]
name = "bevy_macro_utils"
version = "0.15.3"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bb6ded1ddc124ea214f6a2140e47a78d1fe79b0638dad39419cdeef2e1133f1"
checksum = "7a2473db70d8785b5c75d6dd951a2e51e9be2c2311122db9692c79c9d887517b"
dependencies = [
"parking_lot",
"proc-macro2",
"quote",
"syn",
@ -690,18 +695,37 @@ dependencies = [
]
[[package]]
name = "bevy_ptr"
version = "0.15.3"
name = "bevy_platform"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89fe0b0b919146939481a3a7c38864face2c6d0fd2c73ab3d430dc693ecd9b11"
checksum = "704db2c11b7bc31093df4fbbdd3769f9606a6a5287149f4b51f2680f25834ebc"
dependencies = [
"cfg-if",
"critical-section",
"foldhash",
"getrandom 0.2.16",
"hashbrown",
"portable-atomic",
"portable-atomic-util",
"serde",
"spin",
"web-time",
]
[[package]]
name = "bevy_ptr"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f1275dfb4cfef4ffc90c3fa75408964864facf833acc932413d52aa5364ba4"
[[package]]
name = "bevy_reflect"
version = "0.15.3"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ddbca0a39e88eff2c301dc794ee9d73a53f4b08d47b2c9b5a6aac182fae6217"
checksum = "607ebacc31029cf2f39ac330eabf1d4bc411b159528ec08dbe6b0593eaccfd41"
dependencies = [
"assert_type_match",
"bevy_platform",
"bevy_ptr",
"bevy_reflect_derive",
"bevy_utils",
@ -709,16 +733,22 @@ dependencies = [
"disqualified",
"downcast-rs",
"erased-serde",
"foldhash",
"glam",
"serde",
"smallvec",
"smol_str",
"thiserror 2.0.12",
"uuid",
"variadics_please",
"wgpu-types",
]
[[package]]
name = "bevy_reflect_derive"
version = "0.15.3"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d62affb769db17d34ad0b75ff27eca94867e2acc8ea350c5eca97d102bd98709"
checksum = "cf35e45e4eb239018369f63f2adc2107a54c329f9276d020e01eee1625b0238b"
dependencies = [
"bevy_macro_utils",
"proc-macro2",
@ -729,56 +759,49 @@ dependencies = [
[[package]]
name = "bevy_tasks"
version = "0.15.3"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "028630ddc355563bd567df1076db3515858aa26715ddf7467d2086f9b40e5ab1"
checksum = "444c450b65e108855f42ecb6db0c041a56ea7d7f10cc6222f0ca95e9536a7d19"
dependencies = [
"async-channel",
"async-executor",
"async-task",
"atomic-waker",
"bevy_platform",
"cfg-if",
"concurrent-queue",
"crossbeam-queue",
"derive_more 1.0.0",
"futures-channel",
"futures-lite",
"heapless",
"pin-project",
"wasm-bindgen-futures",
]
[[package]]
name = "bevy_time"
version = "0.15.3"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b2051ec56301b994f7c182a2a6eb1490038149ad46d95eee715e1a922acdfd9"
checksum = "456369ca10f8e039aaf273332744674844827854833ee29e28f9e161702f2f55"
dependencies = [
"bevy_app",
"bevy_ecs",
"bevy_platform",
"bevy_reflect",
"bevy_utils",
"crossbeam-channel",
"log",
"serde",
]
[[package]]
name = "bevy_utils"
version = "0.15.3"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63c2174d43a0de99f863c98a472370047a2bfa7d1e5cec8d9d647fb500905d9d"
checksum = "ac2da3b3c1f94dadefcbe837aaa4aa119fcea37f7bdc5307eb05b4ede1921e24"
dependencies = [
"ahash",
"bevy_utils_proc_macros",
"getrandom 0.2.15",
"hashbrown 0.14.5",
"bevy_platform",
"thread_local",
"tracing",
"web-time",
]
[[package]]
name = "bevy_utils_proc_macros"
version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94847541f6dd2e28f54a9c2b0e857da5f2631e2201ebc25ce68781cdcb721391"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
@ -806,6 +829,9 @@ name = "bitflags"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
dependencies = [
"serde",
]
[[package]]
name = "block-buffer"
@ -948,18 +974,18 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.36"
version = "4.5.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04"
checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.5.36"
version = "4.5.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5"
checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2"
dependencies = [
"anstyle",
"clap_lex",
@ -999,6 +1025,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
dependencies = [
"crossbeam-utils",
"portable-atomic",
]
[[package]]
@ -1017,26 +1044,6 @@ version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
[[package]]
name = "const-random"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359"
dependencies = [
"const-random-macro",
]
[[package]]
name = "const-random-macro"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
dependencies = [
"getrandom 0.2.15",
"once_cell",
"tiny-keccak",
]
[[package]]
name = "cpufeatures"
version = "0.2.17"
@ -1125,6 +1132,15 @@ dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-queue"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.21"
@ -1165,9 +1181,9 @@ checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476"
[[package]]
name = "der"
version = "0.7.9"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0"
checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
dependencies = [
"const-oid",
"pem-rfc7468",
@ -1245,9 +1261,9 @@ checksum = "c9c272297e804878a2a4b707cfcfc6d2328b5bb936944613b4fdf2b9269afdfd"
[[package]]
name = "downcast-rs"
version = "1.2.1"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
checksum = "ea8a8b81cacc08888170eef4d13b775126db426d0b348bee9d18c2c1eaf123cf"
[[package]]
name = "either"
@ -1362,6 +1378,12 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foldhash"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "form_urlencoded"
version = "1.2.1"
@ -1498,9 +1520,9 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.15"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
dependencies = [
"cfg-if",
"js-sys",
@ -1529,6 +1551,15 @@ version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "glam"
version = "0.29.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8babf46d4c1c9d92deac9f7be466f76dfc4482b6452fc5024b5e8daf6ffeb3ee"
dependencies = [
"serde",
]
[[package]]
name = "glob"
version = "0.3.2"
@ -1546,14 +1577,12 @@ dependencies = [
]
[[package]]
name = "hashbrown"
version = "0.14.5"
name = "hash32"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
dependencies = [
"ahash",
"allocator-api2",
"serde",
"byteorder",
]
[[package]]
@ -1561,6 +1590,21 @@ name = "hashbrown"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
dependencies = [
"equivalent",
"serde",
]
[[package]]
name = "heapless"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
dependencies = [
"hash32",
"portable-atomic",
"stable_deref_trait",
]
[[package]]
name = "heck"
@ -1577,13 +1621,10 @@ checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e"
[[package]]
name = "hickory-proto"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d844af74f7b799e41c78221be863bade11c430d46042c3b49ca8ae0c6d27287"
source = "git+https://github.com/hickory-dns/hickory-dns#2f7f6825b3a2d205b3f7526b4fd7aca839739c95"
dependencies = [
"async-recursion",
"async-trait",
"cfg-if",
"critical-section",
"data-encoding",
"enum-as-inner",
"futures-channel",
@ -1592,7 +1633,7 @@ dependencies = [
"idna",
"ipnet",
"once_cell",
"rand 0.9.0",
"rand 0.9.1",
"ring",
"thiserror 2.0.12",
"tinyvec",
@ -1604,22 +1645,34 @@ dependencies = [
[[package]]
name = "hickory-resolver"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a128410b38d6f931fcc6ca5c107a3b02cabd6c05967841269a4ad65d23c44331"
source = "git+https://github.com/hickory-dns/hickory-dns#2f7f6825b3a2d205b3f7526b4fd7aca839739c95"
dependencies = [
"cfg-if",
"futures-util",
"hickory-proto",
"ipconfig",
"moka",
"once_cell",
"parking_lot",
"rand 0.9.0",
"rand 0.9.1",
"resolv-conf",
"smallvec",
"thiserror 2.0.12",
"tokio",
"tracing",
]
[[package]]
name = "hostname"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a56f203cd1c76362b69e3863fd987520ac36cf70a8c92627449b2f64a8cf7d65"
dependencies = [
"cfg-if",
"libc",
"windows-link",
]
[[package]]
name = "http"
version = "1.3.1"
@ -1863,7 +1916,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
dependencies = [
"equivalent",
"hashbrown 0.15.2",
"hashbrown",
]
[[package]]
@ -1875,6 +1928,18 @@ dependencies = [
"generic-array",
]
[[package]]
name = "ipconfig"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f"
dependencies = [
"socket2",
"widestring",
"windows-sys 0.48.0",
"winreg",
]
[[package]]
name = "ipnet"
version = "2.11.0"
@ -1924,9 +1989,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "jiff"
version = "0.2.6"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f33145a5cbea837164362c7bd596106eb7c5198f97d1ba6f6ebb3223952e488"
checksum = "5a064218214dc6a10fbae5ec5fa888d80c45d611aba169222fc272072bf7aef6"
dependencies = [
"jiff-static",
"log",
@ -1937,9 +2002,9 @@ dependencies = [
[[package]]
name = "jiff-static"
version = "0.2.6"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43ce13c40ec6956157a3635d97a1ee2df323b263f09ea14165131289cb0f5c19"
checksum = "199b7932d97e325aff3a7030e141eafe7f2c6268e1d1b24859b753a627f45254"
dependencies = [
"proc-macro2",
"quote",
@ -1967,9 +2032,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.171"
version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]]
name = "libloading"
@ -1983,9 +2048,9 @@ dependencies = [
[[package]]
name = "libm"
version = "0.2.11"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa"
checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72"
[[package]]
name = "libz-rs-sys"
@ -2454,7 +2519,7 @@ version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
dependencies = [
"zerocopy 0.8.24",
"zerocopy",
]
[[package]]
@ -2469,9 +2534,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.94"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
@ -2498,13 +2563,13 @@ dependencies = [
[[package]]
name = "quinn-proto"
version = "0.11.10"
version = "0.11.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b820744eb4dc9b57a3398183639c511b5a26d2ed702cedd3febaa1393caa22cc"
checksum = "bcbafbbdbb0f638fe3f35f3c56739f77a8a1d070cb25603226c83339b391472b"
dependencies = [
"bytes",
"getrandom 0.3.2",
"rand 0.9.0",
"rand 0.9.1",
"ring",
"rustc-hash 2.1.1",
"rustls",
@ -2558,13 +2623,12 @@ dependencies = [
[[package]]
name = "rand"
version = "0.9.0"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
dependencies = [
"rand_chacha 0.9.0",
"rand_core 0.9.3",
"zerocopy 0.8.24",
]
[[package]]
@ -2593,7 +2657,7 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom 0.2.15",
"getrandom 0.2.16",
]
[[package]]
@ -2721,6 +2785,15 @@ dependencies = [
"windows-registry",
]
[[package]]
name = "resolv-conf"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48375394603e3dd4b2d64371f7148fd8c7baa2680e28741f2cb8d23b59e3d4c4"
dependencies = [
"hostname",
]
[[package]]
name = "ring"
version = "0.17.14"
@ -2729,7 +2802,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
dependencies = [
"cc",
"cfg-if",
"getrandom 0.2.15",
"getrandom 0.2.16",
"libc",
"untrusted",
"windows-sys 0.52.0",
@ -2959,9 +3032,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "signal-hook-registry"
version = "1.4.2"
version = "1.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410"
dependencies = [
"libc",
]
@ -3082,6 +3155,9 @@ name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
dependencies = [
"portable-atomic",
]
[[package]]
name = "spki"
@ -3208,15 +3284,6 @@ dependencies = [
"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"
@ -3293,9 +3360,9 @@ dependencies = [
[[package]]
name = "tokio-util"
version = "0.7.14"
version = "0.7.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034"
checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df"
dependencies = [
"bytes",
"futures-core",
@ -3502,13 +3569,15 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
version = "1.12.1"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b"
checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
dependencies = [
"getrandom 0.2.15",
"getrandom 0.3.2",
"js-sys",
"md-5",
"serde",
"wasm-bindgen",
]
[[package]]
@ -3517,6 +3586,17 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
[[package]]
name = "variadics_please"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41b6d82be61465f97d42bd1d15bf20f3b0a3a0905018f38f9d6f6962055b0b5c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "version_check"
version = "0.9.5"
@ -3657,6 +3737,25 @@ dependencies = [
"rustls-pki-types",
]
[[package]]
name = "wgpu-types"
version = "24.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50ac044c0e76c03a0378e7786ac505d010a873665e2d51383dcff8dd227dc69c"
dependencies = [
"bitflags",
"js-sys",
"log",
"serde",
"web-sys",
]
[[package]]
name = "widestring"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd7cf3379ca1aac9eea11fba24fd7e315d621f8dfe35c8d7d2be8b793726e07d"
[[package]]
name = "winapi"
version = "0.3.9"
@ -3787,6 +3886,15 @@ dependencies = [
"windows-link",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
@ -3805,6 +3913,21 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
@ -3837,6 +3960,12 @@ dependencies = [
"windows_x86_64_msvc 0.53.0",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
@ -3849,6 +3978,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
@ -3861,6 +3996,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
@ -3885,6 +4026,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
@ -3897,6 +4044,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
@ -3909,6 +4062,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
@ -3921,6 +4080,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
@ -3935,13 +4100,23 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
[[package]]
name = "winnow"
version = "0.7.6"
version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10"
checksum = "6cb8234a863ea0e8cd7284fcdd4f145233eb00fee02bbdd9861aec44e6477bc5"
dependencies = [
"memchr",
]
[[package]]
name = "winreg"
version = "0.50.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
dependencies = [
"cfg-if",
"windows-sys 0.48.0",
]
[[package]]
name = "wit-bindgen-rt"
version = "0.39.0"
@ -3987,33 +4162,13 @@ dependencies = [
"synstructure",
]
[[package]]
name = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"zerocopy-derive 0.7.35",
]
[[package]]
name = "zerocopy"
version = "0.8.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879"
dependencies = [
"zerocopy-derive 0.8.24",
]
[[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",
"zerocopy-derive",
]
[[package]]

View file

@ -30,14 +30,14 @@ repository = "https://github.com/azalea-rs/azalea"
[workspace.dependencies]
aes = "0.8.4"
anyhow = "1.0.97"
anyhow = "1.0.98"
async-recursion = "1.1.1"
base64 = "0.22.1"
bevy_app = "0.15.3"
bevy_ecs = { version = "0.15.3", default-features = false }
bevy_log = "0.15.3"
bevy_tasks = "0.15.3"
bevy_time = "0.15.3"
bevy_app = "0.16.0"
bevy_ecs = { version = "0.16.0", default-features = false }
bevy_log = "0.16.0"
bevy_tasks = "0.16.0"
bevy_time = "0.16.0"
byteorder = "1.5.0"
cfb8 = "0.8.1"
chrono = { version = "0.4.40", default-features = false }
@ -54,7 +54,7 @@ nohash-hasher = "0.2.0"
num-bigint = "0.4.6"
num-traits = "0.2.19"
parking_lot = "0.12.3"
proc-macro2 = "1.0.94"
proc-macro2 = "1.0.95"
quote = "1.0.40"
rand = "0.8.4"
regex = "1.11.1"
@ -71,11 +71,11 @@ socks5-impl = "0.6.2"
syn = "2.0.100"
thiserror = "2.0.12"
tokio = "1.44.2"
tokio-util = "0.7.14"
tokio-util = "0.7.15"
tracing = "0.1.41"
tracing-subscriber = "0.3.19"
hickory-resolver = { version = "0.25.1", default-features = false }
uuid = "1.12"
hickory-resolver = { version = "0.25.1", default-features = false, git = "https://github.com/hickory-dns/hickory-dns" }
uuid = "1.16"
num-format = "0.4.4"
indexmap = "2.9.0"
paste = "1.0.15"

View file

@ -7,12 +7,7 @@ use azalea_brigadier::{
context::CommandContext,
};
use bevy_app::App;
use bevy_ecs::{
component::Component,
query::With,
system::{Query, Resource, RunSystemOnce},
world::{FromWorld, World},
};
use bevy_ecs::{prelude::*, system::RunSystemOnce};
use parking_lot::Mutex;
#[test]

View file

@ -67,6 +67,105 @@ impl FormattedText {
}
}
/// Render all components into a single `String`, using your custom
/// closures to drive styling, text transformation, and final cleanup.
///
/// # Type params
/// - `F`: `(running, component, default) -> (prefix, suffix)` for
/// per-component styling
/// - `S`: `&str -> String` for text tweaks (escaping, mapping, etc.)
/// - `C`: `&final_running_style -> String` for any trailing cleanup
///
/// # Args
/// - `style_formatter`: how to open/close each components style
/// - `text_formatter`: how to turn raw text into output text
/// - `cleanup_formatter`: emit after all components (e.g. reset codes)
/// - `default_style`: where to reset when a components `reset` is true
///
/// # Example
/// ```rust
/// use azalea_chat::{FormattedText, DEFAULT_STYLE};
/// use serde::de::Deserialize;
///
/// let component = FormattedText::deserialize(&serde_json::json!({
/// "text": "Hello, world!",
/// "color": "red",
/// })).unwrap();
///
/// let ansi = component.to_custom_format(
/// |running, new, default| (running.compare_ansi(new, default), String::new()),
/// |text| text.to_string(),
/// |style| {
/// if !style.is_empty() {
/// "\u{1b}[m".to_string()
/// } else {
/// String::new()
/// }
/// },
/// &DEFAULT_STYLE,
/// );
/// println!("{}", ansi);
/// ```
pub fn to_custom_format<F, S, C>(
&self,
mut style_formatter: F,
mut text_formatter: S,
mut cleanup_formatter: C,
default_style: &Style,
) -> String
where
F: FnMut(&Style, &Style, &Style) -> (String, String),
S: FnMut(&str) -> String,
C: FnMut(&Style) -> String,
{
let mut output = String::new();
let mut running_style = Style::default();
for component in self.clone().into_iter() {
let component_text = match &component {
Self::Text(c) => c.text.to_string(),
Self::Translatable(c) => match c.read() {
Ok(c) => c.to_string(),
Err(_) => c.key.to_string(),
},
};
let component_style = &component.get_base().style;
let formatted_style = style_formatter(&running_style, component_style, default_style);
let formatted_text = text_formatter(&component_text);
output.push_str(&formatted_style.0);
output.push_str(&formatted_text);
output.push_str(&formatted_style.1);
// Reset running style if required
if component_style.reset {
running_style = default_style.clone();
} else {
running_style.apply(component_style);
}
}
output.push_str(&cleanup_formatter(&running_style));
output
}
/// Convert this component into an
/// [ANSI string](https://en.wikipedia.org/wiki/ANSI_escape_code).
///
/// This is the same as [`FormattedText::to_ansi`], but you can specify a
/// default [`Style`] to use.
pub fn to_ansi_with_custom_style(&self, default_style: &Style) -> String {
self.to_custom_format(
|running, new, default| (running.compare_ansi(new, default), "".to_owned()),
|text| text.to_string(),
|style| if !style.is_empty() { "\u{1b}[m" } else { "" }.to_string(),
default_style,
)
}
/// Convert this component into an
/// [ANSI string](https://en.wikipedia.org/wiki/ANSI_escape_code), so you
/// can print it to your terminal and get styling.
@ -89,41 +188,30 @@ impl FormattedText {
/// println!("{}", component.to_ansi());
/// ```
pub fn to_ansi(&self) -> String {
// default the default_style to white if it's not set
self.to_ansi_with_custom_style(&DEFAULT_STYLE)
}
/// Convert this component into an
/// [ANSI string](https://en.wikipedia.org/wiki/ANSI_escape_code).
///
/// This is the same as [`FormattedText::to_ansi`], but you can specify a
/// default [`Style`] to use.
pub fn to_ansi_with_custom_style(&self, default_style: &Style) -> String {
// this contains the final string will all the ansi escape codes
let mut built_string = String::new();
// this style will update as we visit components
let mut running_style = Style::default();
for component in self.clone().into_iter() {
let component_text = match &component {
Self::Text(c) => c.text.to_string(),
Self::Translatable(c) => c.to_string(),
};
let component_style = &component.get_base().style;
let ansi_text = running_style.compare_ansi(component_style, default_style);
built_string.push_str(&ansi_text);
built_string.push_str(&component_text);
running_style.apply(component_style);
}
if !running_style.is_empty() {
built_string.push_str("\u{1b}[m");
}
built_string
pub fn to_html(&self) -> String {
self.to_custom_format(
|running, new, _| {
(
format!(
"<span style=\"{}\">",
running.merged_with(new).get_html_style()
),
"</span>".to_owned(),
)
},
|text| {
text.replace("&", "&amp;")
.replace("<", "&lt;")
// usually unnecessary but good for compatibility
.replace(">", "&gt;")
.replace("\n", "<br>")
},
|_| "".to_string(),
&DEFAULT_STYLE,
)
}
}

View file

@ -8,4 +8,4 @@ pub mod style;
pub mod text_component;
pub mod translatable_component;
pub use component::FormattedText;
pub use component::{FormattedText, DEFAULT_STYLE};

View file

@ -559,6 +559,21 @@ impl Style {
}
}
/// Returns a new style that is a merge of self and other.
/// For any field that `other` does not specify (is None), selfs value is
/// used.
pub fn merged_with(&self, other: &Style) -> Style {
Style {
color: other.color.clone().or(self.color.clone()),
bold: other.bold.or(self.bold),
italic: other.italic.or(self.italic),
underlined: other.underlined.or(self.underlined),
strikethrough: other.strikethrough.or(self.strikethrough),
obfuscated: other.obfuscated.or(self.obfuscated),
reset: other.reset, // if reset is true in the new style, that takes precedence
}
}
/// Apply a ChatFormatting to this style
pub fn apply_formatting(&mut self, formatting: &ChatFormatting) {
match *formatting {
@ -576,6 +591,48 @@ impl Style {
}
}
}
pub fn get_html_style(&self) -> String {
let mut style = String::new();
if let Some(color) = &self.color {
style.push_str(&format!("color: {};", color.format_value()));
}
if let Some(bold) = self.bold {
style.push_str(&format!(
"font-weight: {};",
if bold { "bold" } else { "normal" }
));
}
if let Some(italic) = self.italic {
style.push_str(&format!(
"font-style: {};",
if italic { "italic" } else { "normal" }
));
}
if let Some(underlined) = self.underlined {
style.push_str(&format!(
"text-decoration: {};",
if underlined { "underline" } else { "none" }
));
}
if let Some(strikethrough) = self.strikethrough {
style.push_str(&format!(
"text-decoration: {};",
if strikethrough {
"line-through"
} else {
"none"
}
));
}
if let Some(obfuscated) = self.obfuscated {
if obfuscated {
style.push_str("filter: blur(2px);");
}
}
style
}
}
#[cfg(feature = "simdnbt")]

View file

@ -146,7 +146,7 @@ mod tests {
use crate::style::Ansi;
#[test]
fn test_hypixel_motd() {
fn test_hypixel_motd_ansi() {
let component =
TextComponent::new("§aHypixel Network §c[1.8-1.18]\n§b§lHAPPY HOLIDAYS".to_string())
.get();
@ -163,6 +163,39 @@ mod tests {
);
}
#[test]
fn test_hypixel_motd_html() {
let component =
TextComponent::new("§aHypixel Network §c[1.8-1.18]\n§b§lHAPPY HOLIDAYS".to_string())
.get();
assert_eq!(
component.to_html(),
format!(
"{GREEN}Hypixel Network {END_SPAN}{RED}[1.8-1.18]<br>{END_SPAN}{BOLD_AQUA}HAPPY HOLIDAYS{END_SPAN}",
END_SPAN = "</span>",
GREEN = "<span style=\"color: #55FF55;\">",
RED = "<span style=\"color: #FF5555;\">",
BOLD_AQUA = "<span style=\"color: #55FFFF;font-weight: bold;\">",
)
);
}
#[test]
fn test_xss_html() {
let component = TextComponent::new("§a<b>&\n§b</b>".to_string()).get();
assert_eq!(
component.to_html(),
format!(
"{GREEN}&lt;b&gt;&amp;<br>{END_SPAN}{AQUA}&lt;/b&gt;{END_SPAN}",
END_SPAN = "</span>",
GREEN = "<span style=\"color: #55FF55;\">",
AQUA = "<span style=\"color: #55FFFF;\">",
)
);
}
#[test]
fn test_legacy_color_code_to_component() {
let component = TextComponent::new("§lHello §r§1w§2o§3r§4l§5d".to_string()).get();

View file

@ -1,7 +1,7 @@
use std::{
collections::HashMap,
fmt::Debug,
io,
io, mem,
net::SocketAddr,
sync::Arc,
thread,
@ -32,12 +32,8 @@ use azalea_protocol::{
use azalea_world::{Instance, InstanceContainer, InstanceName, MinecraftEntityId, PartialInstance};
use bevy_app::{App, Plugin, PluginsState, Update};
use bevy_ecs::{
bundle::Bundle,
component::Component,
entity::Entity,
schedule::{InternedScheduleLabel, IntoSystemConfigs, LogLevel, ScheduleBuildSettings},
system::Resource,
world::World,
prelude::*,
schedule::{InternedScheduleLabel, LogLevel, ScheduleBuildSettings},
};
use parking_lot::{Mutex, RwLock};
use simdnbt::owned::NbtCompound;
@ -128,7 +124,8 @@ impl<'a> StartClientOpts<'a> {
let mut app = App::new();
app.add_plugins(DefaultPlugins);
let ecs_lock = start_ecs_runner(app);
let (ecs_lock, start_running_systems) = start_ecs_runner(app);
start_running_systems();
Self {
ecs_lock,
@ -659,12 +656,14 @@ impl Plugin for AzaleaPlugin {
}
}
/// Start running the ECS loop!
/// Create the ECS world, and return a function that begins running systems.
/// This exists to allow you to make last-millisecond updates to the world
/// before any systems start running.
///
/// You can create your app with `App::new()`, but don't forget to add
/// [`DefaultPlugins`].
#[doc(hidden)]
pub fn start_ecs_runner(mut app: App) -> Arc<Mutex<World>> {
pub fn start_ecs_runner(mut app: App) -> (Arc<Mutex<World>>, impl FnOnce()) {
// this block is based on Bevy's default runner:
// https://github.com/bevyengine/bevy/blob/390877cdae7a17095a75c8f9f1b4241fe5047e83/crates/bevy_app/src/schedule_runner.rs#L77-L85
if app.plugins_state() != PluginsState::Cleaned {
@ -682,14 +681,15 @@ pub fn start_ecs_runner(mut app: App) -> Arc<Mutex<World>> {
// all resources should have been added by now so we can take the ecs from the
// app
let ecs = Arc::new(Mutex::new(std::mem::take(app.world_mut())));
let ecs = Arc::new(Mutex::new(mem::take(app.world_mut())));
tokio::spawn(run_schedule_loop(
ecs.clone(),
*app.main().update_schedule.as_ref().unwrap(),
));
let ecs_clone = ecs.clone();
let outer_schedule_label = *app.main().update_schedule.as_ref().unwrap();
let start_running_systems = move || {
tokio::spawn(run_schedule_loop(ecs_clone, outer_schedule_label));
};
ecs
(ecs, start_running_systems)
}
async fn run_schedule_loop(ecs: Arc<Mutex<World>>, outer_schedule_label: InternedScheduleLabel) {

View file

@ -35,7 +35,8 @@ impl Plugin for AttackPlugin {
update_attack_strength_scale.after(PhysicsSet),
handle_attack_queued
.before(super::tick_end::game_tick_packet)
.after(super::movement::send_sprinting_if_needed),
.after(super::movement::send_sprinting_if_needed)
.before(super::movement::send_position),
)
.chain(),
);

View file

@ -10,12 +10,7 @@ use azalea_protocol::packets::game::{
c_system_chat::ClientboundSystemChat,
};
use bevy_app::{App, Plugin, Update};
use bevy_ecs::{
entity::Entity,
event::{EventReader, EventWriter},
prelude::Event,
schedule::IntoSystemConfigs,
};
use bevy_ecs::prelude::*;
use handler::{SendChatKindEvent, handle_send_chat_kind_event};
use uuid::Uuid;
@ -204,13 +199,13 @@ pub fn handle_send_chat_event(
) {
for event in events.read() {
if event.content.starts_with('/') {
send_chat_kind_events.send(SendChatKindEvent {
send_chat_kind_events.write(SendChatKindEvent {
entity: event.entity,
content: event.content[1..].to_string(),
kind: ChatKind::Command,
});
} else {
send_chat_kind_events.send(SendChatKindEvent {
send_chat_kind_events.write(SendChatKindEvent {
entity: event.entity,
content: event.content.clone(),
kind: ChatKind::Message,

View file

@ -67,7 +67,7 @@ pub struct ChunkBatchFinishedEvent {
pub fn handle_receive_chunk_events(
mut events: EventReader<ReceiveChunkEvent>,
mut query: Query<&mut InstanceHolder>,
mut query: Query<&InstanceHolder>,
) {
for event in events.read() {
let pos = ChunkPos::new(event.packet.x, event.packet.z);

View file

@ -34,7 +34,6 @@ impl Plugin for ConnectionPlugin {
}
pub fn read_packets(ecs: &mut World) {
// receive_game_packet_events: EventWriter<ReceiveGamePacketEvent>,
let mut entity_and_conn_query = ecs.query::<(Entity, &mut RawConnection)>();
let mut conn_query = ecs.query::<&mut RawConnection>();

View file

@ -3,17 +3,9 @@
use azalea_chat::FormattedText;
use azalea_entity::{EntityBundle, InLoadedChunk, LocalEntity, metadata::PlayerMetadataBundle};
use bevy_app::{App, Plugin, PostUpdate};
use bevy_ecs::{
component::Component,
entity::Entity,
event::{EventReader, EventWriter},
prelude::Event,
query::{Changed, With},
schedule::IntoSystemConfigs,
system::{Commands, Query},
};
use bevy_ecs::prelude::*;
use derive_more::Deref;
use tracing::trace;
use tracing::info;
use crate::{InstanceHolder, client::JoinedClientBundle, connection::RawConnection};
@ -55,8 +47,15 @@ pub fn remove_components_from_disconnected_players(
mut events: EventReader<DisconnectEvent>,
mut loaded_by_query: Query<&mut azalea_entity::LoadedBy>,
) {
for DisconnectEvent { entity, .. } in events.read() {
trace!("Got DisconnectEvent for {entity:?}");
for DisconnectEvent { entity, reason } in events.read() {
info!(
"A client {entity:?} was disconnected{}",
if let Some(reason) = reason {
format!(": {reason}")
} else {
"".to_string()
}
);
commands
.entity(*entity)
.remove::<JoinedClientBundle>()
@ -98,7 +97,7 @@ fn disconnect_on_connection_dead(
) {
for (entity, &is_connection_alive) in &query {
if !*is_connection_alive {
disconnect_events.send(DisconnectEvent {
disconnect_events.write(DisconnectEvent {
entity,
reason: None,
});

View file

@ -9,14 +9,7 @@ use azalea_entity::{Dead, InLoadedChunk};
use azalea_protocol::packets::game::c_player_combat_kill::ClientboundPlayerCombatKill;
use azalea_world::{InstanceName, MinecraftEntityId};
use bevy_app::{App, Plugin, PreUpdate, Update};
use bevy_ecs::{
component::Component,
entity::Entity,
event::EventReader,
query::{Added, With, Without},
schedule::IntoSystemConfigs,
system::{Commands, Query},
};
use bevy_ecs::prelude::*;
use derive_more::{Deref, DerefMut};
use tokio::sync::mpsc;

View file

@ -19,15 +19,7 @@ use azalea_protocol::packets::game::{
};
use azalea_world::{Instance, InstanceContainer, InstanceName};
use bevy_app::{App, Plugin, Update};
use bevy_ecs::{
component::Component,
entity::Entity,
event::{Event, EventReader},
observer::Trigger,
query::{Changed, With},
schedule::IntoSystemConfigs,
system::{Commands, Query, Res},
};
use bevy_ecs::prelude::*;
use derive_more::{Deref, DerefMut};
use tracing::warn;

View file

@ -16,14 +16,7 @@ use azalea_protocol::packets::game::{
};
use azalea_registry::MenuKind;
use bevy_app::{App, Plugin, Update};
use bevy_ecs::{
component::Component,
entity::Entity,
event::EventReader,
prelude::{Event, EventWriter},
schedule::{IntoSystemConfigs, SystemSet},
system::{Commands, Query},
};
use bevy_ecs::prelude::*;
use tracing::{error, warn};
use crate::{
@ -628,7 +621,7 @@ fn handle_container_close_event(
container_id: inventory.id,
},
));
client_side_events.send(ClientSideCloseContainerEvent {
client_side_events.write(ClientSideCloseContainerEvent {
entity: event.entity,
});
}

View file

@ -27,7 +27,7 @@ fn handle_receive_hello_event(trigger: Trigger<ReceiveHelloEvent>, mut commands:
let account = trigger.account.clone();
let packet = trigger.packet.clone();
let player = trigger.entity();
let player = trigger.target();
let task = task_pool.spawn(auth_with_account(account, packet));
commands.entity(player).insert(AuthTask(task));

View file

@ -127,12 +127,12 @@ fn handle_auto_mine(
))
&& !hit_result_component.miss
{
start_mining_block_event.send(StartMiningBlockEvent {
start_mining_block_event.write(StartMiningBlockEvent {
entity,
position: block_pos,
});
} else if mining.is_some() && hit_result_component.miss {
stop_mining_block_event.send(StopMiningBlockEvent { entity });
stop_mining_block_event.write(StopMiningBlockEvent { entity });
}
}
}
@ -168,7 +168,7 @@ fn handle_start_mining_block_event(
// we're not looking at the block, arbitrary direction
Direction::Down
};
start_mining_events.send(StartMiningBlockWithDirectionEvent {
start_mining_events.write(StartMiningBlockWithDirectionEvent {
entity: event.entity,
position: event.position,
direction,
@ -236,7 +236,7 @@ fn handle_start_mining_block_with_direction_event(
if game_mode.current == GameMode::Creative {
*sequence_number += 1;
finish_mining_events.send(FinishMiningBlockEvent {
finish_mining_events.write(FinishMiningBlockEvent {
entity: event.entity,
position: event.position,
});
@ -283,7 +283,7 @@ fn handle_start_mining_block_with_direction_event(
if block_is_solid && **mine_progress == 0. {
// interact with the block (like note block left click) here
attack_block_events.send(AttackBlockEvent {
attack_block_events.write(AttackBlockEvent {
entity: event.entity,
position: event.position,
});
@ -303,7 +303,7 @@ fn handle_start_mining_block_with_direction_event(
) >= 1.
{
// block was broken instantly
finish_mining_events.send(FinishMiningBlockEvent {
finish_mining_events.write(FinishMiningBlockEvent {
entity: event.entity,
position: event.position,
});
@ -316,7 +316,7 @@ fn handle_start_mining_block_with_direction_event(
**current_mining_item = held_item;
**mine_progress = 0.;
**mine_ticks = 0.;
mine_block_progress_events.send(MineBlockProgressEvent {
mine_block_progress_events.write(MineBlockProgressEvent {
entity: event.entity,
position: event.position,
destroy_stage: mine_progress.destroy_stage(),
@ -502,7 +502,7 @@ pub fn handle_stop_mining_block_event(
));
commands.entity(event.entity).remove::<Mining>();
**mine_progress = 0.;
mine_block_progress_events.send(MineBlockProgressEvent {
mine_block_progress_events.write(MineBlockProgressEvent {
entity: event.entity,
position: mine_block_pos,
destroy_stage: None,
@ -558,7 +558,7 @@ pub fn continue_mining_block(
if game_mode.current == GameMode::Creative {
// TODO: worldborder check
**mine_delay = 5;
finish_mining_events.send(FinishMiningBlockEvent {
finish_mining_events.write(FinishMiningBlockEvent {
entity,
position: mining.pos,
});
@ -572,7 +572,7 @@ pub fn continue_mining_block(
sequence: **sequence_number,
},
));
swing_arm_events.send(SwingArmEvent { entity });
swing_arm_events.write(SwingArmEvent { entity });
} else if is_same_mining_target(
mining.pos,
inventory,
@ -604,7 +604,7 @@ pub fn continue_mining_block(
if **mine_progress >= 1. {
commands.entity(entity).remove::<Mining>();
*sequence_number += 1;
finish_mining_events.send(FinishMiningBlockEvent {
finish_mining_events.write(FinishMiningBlockEvent {
entity,
position: mining.pos,
});
@ -622,20 +622,20 @@ pub fn continue_mining_block(
**mine_delay = 0;
}
mine_block_progress_events.send(MineBlockProgressEvent {
mine_block_progress_events.write(MineBlockProgressEvent {
entity,
position: mining.pos,
destroy_stage: mine_progress.destroy_stage(),
});
swing_arm_events.send(SwingArmEvent { entity });
swing_arm_events.write(SwingArmEvent { entity });
} else {
start_mining_events.send(StartMiningBlockWithDirectionEvent {
start_mining_events.write(StartMiningBlockWithDirectionEvent {
entity,
position: mining.pos,
direction: mining.dir,
});
}
swing_arm_events.send(SwingArmEvent { entity });
swing_arm_events.write(SwingArmEvent { entity });
}
}

View file

@ -17,13 +17,7 @@ use azalea_protocol::packets::{
};
use azalea_world::{MinecraftEntityId, MoveEntityError};
use bevy_app::{App, Plugin, Update};
use bevy_ecs::prelude::Event;
use bevy_ecs::schedule::SystemSet;
use bevy_ecs::system::Commands;
use bevy_ecs::{
component::Component, entity::Entity, event::EventReader, query::With,
schedule::IntoSystemConfigs, system::Query,
};
use bevy_ecs::prelude::*;
use thiserror::Error;
use crate::client::Client;

View file

@ -64,7 +64,7 @@ pub struct ConfigPacketHandler<'a> {
}
impl ConfigPacketHandler<'_> {
pub fn registry_data(&mut self, p: &ClientboundRegistryData) {
as_system::<Query<&mut InstanceHolder>>(self.ecs, |mut query| {
as_system::<Query<&InstanceHolder>>(self.ecs, |mut query| {
let instance_holder = query.get_mut(self.player).unwrap();
let mut instance = instance_holder.instance.write();
@ -82,7 +82,7 @@ impl ConfigPacketHandler<'_> {
pub fn disconnect(&mut self, p: &ClientboundDisconnect) {
warn!("Got disconnect packet {p:?}");
as_system::<EventWriter<_>>(self.ecs, |mut events| {
events.send(DisconnectEvent {
events.write(DisconnectEvent {
entity: self.player,
reason: Some(p.reason.clone()),
});
@ -96,12 +96,12 @@ impl ConfigPacketHandler<'_> {
self.ecs,
|(mut commands, mut query)| {
let mut raw_conn = query.get_mut(self.player).unwrap();
raw_conn.state = ConnectionProtocol::Game;
commands.trigger(SendConfigPacketEvent::new(
self.player,
ServerboundFinishConfiguration,
));
raw_conn.state = ConnectionProtocol::Game;
// these components are added now that we're going to be in the Game state
commands
@ -124,7 +124,7 @@ impl ConfigPacketHandler<'_> {
);
as_system::<(Commands, EventWriter<_>)>(self.ecs, |(mut commands, mut events)| {
events.send(KeepAliveEvent {
events.write(KeepAliveEvent {
entity: self.player,
id: p.id,
});
@ -147,7 +147,7 @@ impl ConfigPacketHandler<'_> {
debug!("Got resource pack push packet {p:?}");
as_system::<EventWriter<_>>(self.ecs, |mut events| {
events.send(ResourcePackEvent {
events.write(ResourcePackEvent {
entity: self.player,
id: p.id,
url: p.url.to_owned(),

View file

@ -13,7 +13,7 @@ use azalea_entity::{
indexing::{EntityIdIndex, EntityUuidIndex},
metadata::{Health, apply_metadata},
};
use azalea_protocol::packets::game::*;
use azalea_protocol::packets::{ConnectionProtocol, game::*};
use azalea_world::{InstanceContainer, InstanceName, MinecraftEntityId, PartialInstance};
use bevy_ecs::{prelude::*, system::SystemState};
pub use events::*;
@ -22,7 +22,9 @@ use tracing::{debug, error, trace, warn};
use crate::{
ClientInformation, PlayerInfo,
chat::{ChatPacket, ChatReceivedEvent},
chunks, declare_packet_handlers,
chunks,
connection::RawConnection,
declare_packet_handlers,
disconnect::DisconnectEvent,
inventory::{
ClientSideCloseContainerEvent, Inventory, MenuOpenedEvent, SetContainerContentEvent,
@ -225,7 +227,7 @@ impl GamePacketHandler<'_> {
let new_instance_name = p.common.dimension.clone();
if let Some(mut instance_name) = instance_name {
*instance_name = instance_name.clone();
**instance_name = new_instance_name.clone();
} else {
commands
.entity(self.player)
@ -241,13 +243,13 @@ impl GamePacketHandler<'_> {
// add this world to the instance_container (or don't if it's already
// there)
let weak_instance = instance_container.insert(
let weak_instance = instance_container.get_or_insert(
new_instance_name.clone(),
dimension_data.height,
dimension_data.min_y,
&instance_holder.instance.read().registries,
);
instance_loaded_events.send(InstanceLoadedEvent {
instance_loaded_events.write(InstanceLoadedEvent {
entity: self.player,
name: new_instance_name.clone(),
instance: Arc::downgrade(&weak_instance),
@ -337,7 +339,7 @@ impl GamePacketHandler<'_> {
debug!("Got chunk batch start");
as_system::<EventWriter<_>>(self.ecs, |mut events| {
events.send(chunks::ChunkBatchStartEvent {
events.write(chunks::ChunkBatchStartEvent {
entity: self.player,
});
});
@ -347,7 +349,7 @@ impl GamePacketHandler<'_> {
debug!("Got chunk batch finished {p:?}");
as_system::<EventWriter<_>>(self.ecs, |mut events| {
events.send(chunks::ChunkBatchFinishedEvent {
events.write(chunks::ChunkBatchFinishedEvent {
entity: self.player,
batch_size: p.batch_size,
});
@ -388,7 +390,7 @@ impl GamePacketHandler<'_> {
warn!("Got disconnect packet {p:?}");
as_system::<EventWriter<_>>(self.ecs, |mut events| {
events.send(DisconnectEvent {
events.write(DisconnectEvent {
entity: self.player,
reason: Some(p.reason.clone()),
});
@ -530,7 +532,7 @@ impl GamePacketHandler<'_> {
display_name: updated_info.display_name.clone(),
};
tab_list.insert(updated_info.profile.uuid, info.clone());
add_player_events.send(AddPlayerEvent {
add_player_events.write(AddPlayerEvent {
entity: self.player,
info,
});
@ -546,7 +548,7 @@ impl GamePacketHandler<'_> {
if p.actions.update_display_name {
info.display_name.clone_from(&updated_info.display_name);
}
update_player_events.send(UpdatePlayerEvent {
update_player_events.write(UpdatePlayerEvent {
entity: self.player,
info: info.clone(),
});
@ -575,7 +577,7 @@ impl GamePacketHandler<'_> {
for uuid in &p.profile_ids {
if let Some(info) = tab_list.remove(uuid) {
remove_player_events.send(RemovePlayerEvent {
remove_player_events.write(RemovePlayerEvent {
entity: self.player,
info,
});
@ -589,7 +591,7 @@ impl GamePacketHandler<'_> {
pub fn set_chunk_cache_center(&mut self, p: &ClientboundSetChunkCacheCenter) {
debug!("Got chunk cache center packet {p:?}");
as_system::<Query<&mut InstanceHolder>>(self.ecs, |mut query| {
as_system::<Query<&InstanceHolder>>(self.ecs, |mut query| {
let instance_holder = query.get_mut(self.player).unwrap();
let mut partial_world = instance_holder.partial_instance.write();
@ -609,7 +611,7 @@ impl GamePacketHandler<'_> {
debug!("Got chunk with light packet {} {}", p.x, p.z);
as_system::<EventWriter<_>>(self.ecs, |mut events| {
events.send(chunks::ReceiveChunkEvent {
events.write(chunks::ReceiveChunkEvent {
entity: self.player,
packet: p.clone(),
});
@ -1030,7 +1032,7 @@ impl GamePacketHandler<'_> {
as_system::<(EventWriter<KeepAliveEvent>, Commands)>(
self.ecs,
|(mut keepalive_events, mut commands)| {
keepalive_events.send(KeepAliveEvent {
keepalive_events.write(KeepAliveEvent {
entity: self.player,
id: p.id,
});
@ -1082,7 +1084,7 @@ impl GamePacketHandler<'_> {
debug!("Got player chat packet {p:?}");
as_system::<EventWriter<_>>(self.ecs, |mut events| {
events.send(ChatReceivedEvent {
events.write(ChatReceivedEvent {
entity: self.player,
packet: ChatPacket::Player(Arc::new(p.clone())),
});
@ -1093,7 +1095,7 @@ impl GamePacketHandler<'_> {
debug!("Got system chat packet {p:?}");
as_system::<EventWriter<_>>(self.ecs, |mut events| {
events.send(ChatReceivedEvent {
events.write(ChatReceivedEvent {
entity: self.player,
packet: ChatPacket::System(Arc::new(p.clone())),
});
@ -1104,7 +1106,7 @@ impl GamePacketHandler<'_> {
debug!("Got disguised chat packet {p:?}");
as_system::<EventWriter<_>>(self.ecs, |mut events| {
events.send(ChatReceivedEvent {
events.write(ChatReceivedEvent {
entity: self.player,
packet: ChatPacket::Disguised(Arc::new(p.clone())),
});
@ -1120,7 +1122,7 @@ impl GamePacketHandler<'_> {
pub fn block_update(&mut self, p: &ClientboundBlockUpdate) {
debug!("Got block update packet {p:?}");
as_system::<Query<&mut InstanceHolder>>(self.ecs, |mut query| {
as_system::<Query<&InstanceHolder>>(self.ecs, |mut query| {
let local_player = query.get_mut(self.player).unwrap();
let world = local_player.instance.write();
@ -1136,7 +1138,7 @@ impl GamePacketHandler<'_> {
pub fn section_blocks_update(&mut self, p: &ClientboundSectionBlocksUpdate) {
debug!("Got section blocks update packet {p:?}");
as_system::<Query<&mut InstanceHolder>>(self.ecs, |mut query| {
as_system::<Query<&InstanceHolder>>(self.ecs, |mut query| {
let local_player = query.get_mut(self.player).unwrap();
let world = local_player.instance.write();
for state in &p.states {
@ -1215,7 +1217,7 @@ impl GamePacketHandler<'_> {
}
}
} else {
events.send(SetContainerContentEvent {
events.write(SetContainerContentEvent {
entity: self.player,
slots: p.items.clone(),
container_id: p.container_id,
@ -1281,7 +1283,7 @@ impl GamePacketHandler<'_> {
debug!("Got container close packet {p:?}");
as_system::<EventWriter<_>>(self.ecs, |mut events| {
events.send(ClientSideCloseContainerEvent {
events.write(ClientSideCloseContainerEvent {
entity: self.player,
});
});
@ -1298,7 +1300,7 @@ impl GamePacketHandler<'_> {
as_system::<EventWriter<_>>(self.ecs, |mut knockback_events| {
if let Some(knockback) = p.knockback {
knockback_events.send(KnockbackEvent {
knockback_events.write(KnockbackEvent {
entity: self.player,
knockback: KnockbackType::Set(knockback),
});
@ -1309,7 +1311,7 @@ impl GamePacketHandler<'_> {
pub fn forget_level_chunk(&mut self, p: &ClientboundForgetLevelChunk) {
debug!("Got forget level chunk packet {p:?}");
as_system::<Query<&mut InstanceHolder>>(self.ecs, |mut query| {
as_system::<Query<&InstanceHolder>>(self.ecs, |mut query| {
let local_player = query.get_mut(self.player).unwrap();
let mut partial_instance = local_player.partial_instance.write();
@ -1332,7 +1334,7 @@ impl GamePacketHandler<'_> {
debug!("Got open screen packet {p:?}");
as_system::<EventWriter<_>>(self.ecs, |mut events| {
events.send(MenuOpenedEvent {
events.write(MenuOpenedEvent {
entity: self.player,
window_id: p.container_id,
menu_type: p.menu_type,
@ -1369,7 +1371,7 @@ impl GamePacketHandler<'_> {
if *entity_id == p.player_id && dead.is_none() {
commands.entity(self.player).insert(Dead);
events.send(DeathEvent {
events.write(DeathEvent {
entity: self.player,
packet: Some(p.clone()),
});
@ -1385,7 +1387,7 @@ impl GamePacketHandler<'_> {
debug!("Got resource pack packet {p:?}");
as_system::<EventWriter<_>>(self.ecs, |mut events| {
events.send(ResourcePackEvent {
events.write(ResourcePackEvent {
entity: self.player,
id: p.id,
url: p.url.to_owned(),
@ -1408,6 +1410,7 @@ impl GamePacketHandler<'_> {
&mut InstanceHolder,
&GameProfileComponent,
&ClientInformation,
Option<&mut InstanceName>,
),
With<LocalEntity>,
>,
@ -1417,11 +1420,19 @@ impl GamePacketHandler<'_> {
)>(
self.ecs,
|(mut commands, mut query, mut events, mut instance_container, mut loaded_by_query)| {
let (mut instance_holder, game_profile, client_information) =
let (mut instance_holder, game_profile, client_information, instance_name) =
query.get_mut(self.player).unwrap();
let new_instance_name = p.common.dimension.clone();
if let Some(mut instance_name) = instance_name {
**instance_name = new_instance_name.clone();
} else {
commands
.entity(self.player)
.insert(InstanceName(new_instance_name.clone()));
}
let Some((_dimension_type, dimension_data)) = p
.common
.dimension_type(&instance_holder.instance.read().registries)
@ -1431,13 +1442,13 @@ impl GamePacketHandler<'_> {
// add this world to the instance_container (or don't if it's already
// there)
let weak_instance = instance_container.insert(
let weak_instance = instance_container.get_or_insert(
new_instance_name.clone(),
dimension_data.height,
dimension_data.min_y,
&instance_holder.instance.read().registries,
);
events.send(InstanceLoadedEvent {
events.write(InstanceLoadedEvent {
entity: self.player,
name: new_instance_name.clone(),
instance: Arc::downgrade(&weak_instance),
@ -1485,18 +1496,27 @@ impl GamePacketHandler<'_> {
pub fn start_configuration(&mut self, _p: &ClientboundStartConfiguration) {
debug!("Got start configuration packet");
as_system::<Commands>(self.ecs, |mut commands| {
commands.trigger(SendPacketEvent::new(
self.player,
ServerboundConfigurationAcknowledged,
));
as_system::<(Commands, Query<&mut RawConnection>)>(
self.ecs,
|(mut commands, mut query)| {
let Some(mut raw_conn) = query.get_mut(self.player).ok() else {
warn!("Got start configuration packet but player doesn't have a RawConnection");
return;
};
raw_conn.state = ConnectionProtocol::Configuration;
commands
.entity(self.player)
.insert(crate::client::InConfigState)
.remove::<crate::JoinedClientBundle>()
.remove::<EntityBundle>();
});
commands.trigger(SendPacketEvent::new(
self.player,
ServerboundConfigurationAcknowledged,
));
commands
.entity(self.player)
.insert(crate::client::InConfigState)
.remove::<crate::JoinedClientBundle>()
.remove::<EntityBundle>();
},
);
}
pub fn entity_position_sync(&mut self, p: &ClientboundEntityPositionSync) {
@ -1554,7 +1574,9 @@ impl GamePacketHandler<'_> {
pub fn set_display_objective(&mut self, _p: &ClientboundSetDisplayObjective) {}
pub fn set_objective(&mut self, _p: &ClientboundSetObjective) {}
pub fn set_passengers(&mut self, _p: &ClientboundSetPassengers) {}
pub fn set_player_team(&mut self, _p: &ClientboundSetPlayerTeam) {}
pub fn set_player_team(&mut self, p: &ClientboundSetPlayerTeam) {
debug!("Got set player team packet {p:?}");
}
pub fn set_score(&mut self, _p: &ClientboundSetScore) {}
pub fn set_simulation_distance(&mut self, _p: &ClientboundSetSimulationDistance) {}
pub fn set_subtitle_text(&mut self, _p: &ClientboundSetSubtitleText) {}

View file

@ -72,7 +72,7 @@ impl LoginPacketHandler<'_> {
debug!("Got disconnect {:?}", p);
as_system::<EventWriter<_>>(self.ecs, |mut events| {
events.send(DisconnectEvent {
events.write(DisconnectEvent {
entity: self.player,
reason: Some(p.reason.clone()),
});
@ -121,7 +121,7 @@ impl LoginPacketHandler<'_> {
debug!("Got custom query {p:?}");
as_system::<EventWriter<ReceiveCustomQueryEvent>>(self.ecs, |mut events| {
events.send(ReceiveCustomQueryEvent {
events.write(ReceiveCustomQueryEvent {
entity: self.player,
packet: p.clone(),
disabled: false,

View file

@ -20,7 +20,7 @@ pub fn death_event_on_0_health(
) {
for (entity, health) in query.iter() {
if **health == 0. {
death_events.send(DeathEvent {
death_events.write(DeathEvent {
entity,
packet: None,
});

View file

@ -24,14 +24,14 @@ impl Plugin for PongPlugin {
pub fn reply_to_game_ping(trigger: Trigger<PingEvent>, mut commands: Commands) {
commands.trigger(SendPacketEvent::new(
trigger.entity(),
trigger.target(),
azalea_protocol::packets::game::ServerboundPong { id: trigger.0.id },
));
}
pub fn reply_to_config_ping(trigger: Trigger<ConfigPingEvent>, mut commands: Commands) {
commands.trigger(SendConfigPacketEvent::new(
trigger.entity(),
trigger.target(),
azalea_protocol::packets::config::ServerboundPong { id: trigger.0.id },
));
}

View file

@ -3,7 +3,7 @@
use std::marker::PhantomData;
use bevy_app::{App, Last, Plugin};
use bevy_ecs::system::{NonSend, Resource};
use bevy_ecs::prelude::*;
use bevy_tasks::{
AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool, TaskPoolBuilder,
tick_global_task_pools_on_main_thread,

View file

@ -20,6 +20,7 @@ use azalea_registry::{DimensionType, EntityKind};
use azalea_world::palette::{PalettedContainer, PalettedContainerKind};
use azalea_world::{Chunk, Instance, MinecraftEntityId, Section};
use bevy_app::App;
use bevy_ecs::component::Mutable;
use bevy_ecs::{prelude::*, schedule::ExecutorKind};
use parking_lot::RwLock;
use simdnbt::owned::{NbtCompound, NbtTag};
@ -100,6 +101,11 @@ impl Simulation {
pub fn tick(&mut self) {
tick_app(&mut self.app);
}
pub fn minecraft_entity_id(&self) -> MinecraftEntityId {
self.component::<MinecraftEntityId>()
}
pub fn component<T: Component + Clone>(&self) -> T {
self.app.world().get::<T>(self.entity).unwrap().clone()
}
@ -109,7 +115,10 @@ impl Simulation {
pub fn has_component<T: Component>(&self) -> bool {
self.app.world().get::<T>(self.entity).is_some()
}
pub fn with_component_mut<T: Component>(&mut self, f: impl FnOnce(&mut T)) {
pub fn with_component_mut<T: Component<Mutability = Mutable>>(
&mut self,
f: impl FnOnce(&mut T),
) {
f(&mut self
.app
.world_mut()

View file

@ -7,12 +7,7 @@ use std::{
use azalea_core::position::ChunkPos;
use azalea_world::{Instance, InstanceContainer, InstanceName, MinecraftEntityId};
use bevy_ecs::{
component::Component,
entity::Entity,
query::{Added, Changed, Without},
system::{Commands, Query, Res, ResMut, Resource},
};
use bevy_ecs::prelude::*;
use derive_more::{Deref, DerefMut};
use nohash_hasher::IntMap;
use tracing::{debug, trace, warn};
@ -136,8 +131,9 @@ pub fn update_entity_chunk_positions(
mut query: Query<(Entity, &Position, &InstanceName, &mut EntityChunkPos), Changed<Position>>,
instance_container: Res<InstanceContainer>,
) {
for (entity, pos, world_name, mut entity_chunk_pos) in query.iter_mut() {
let instance_lock = instance_container.get(world_name).unwrap();
for (entity, pos, instance_name, mut entity_chunk_pos) in query.iter_mut() {
// TODO: move this inside of the if statement so it's not called as often
let instance_lock = instance_container.get(instance_name).unwrap();
let mut instance = instance_lock.write();
let old_chunk = **entity_chunk_pos;

View file

@ -18,12 +18,7 @@
use std::sync::Arc;
use azalea_world::{MinecraftEntityId, PartialInstance};
use bevy_ecs::{
prelude::{Component, Entity},
query::With,
system::{EntityCommand, Query},
world::{EntityWorldMut, World},
};
use bevy_ecs::prelude::*;
use derive_more::{Deref, DerefMut};
use parking_lot::RwLock;
use tracing::warn;
@ -68,19 +63,17 @@ impl RelativeEntityUpdate {
pub struct UpdatesReceived(u32);
impl EntityCommand for RelativeEntityUpdate {
fn apply(self, entity: Entity, world: &mut World) {
fn apply(self, mut entity: EntityWorldMut) {
let partial_entity_infos = &mut self.partial_world.write().entity_infos;
let mut entity_mut = world.entity_mut(entity);
if Some(entity) == partial_entity_infos.owner_entity {
if Some(entity.id()) == partial_entity_infos.owner_entity {
// if the entity owns this partial world, it's always allowed to update itself
(self.update)(&mut entity_mut);
(self.update)(&mut entity);
return;
};
let entity_id = *entity_mut.get::<MinecraftEntityId>().unwrap();
if entity_mut.contains::<LocalEntity>() {
let entity_id = *entity.get::<MinecraftEntityId>().unwrap();
if entity.contains::<LocalEntity>() {
// a client tried to update another client, which isn't allowed
return;
}
@ -90,7 +83,7 @@ impl EntityCommand for RelativeEntityUpdate {
.get(&entity_id)
.copied();
let can_update = if let Some(updates_received) = entity_mut.get::<UpdatesReceived>() {
let can_update = if let Some(updates_received) = entity.get::<UpdatesReceived>() {
this_client_updates_received.unwrap_or(1) == **updates_received
} else {
// no UpdatesReceived means the entity was just spawned
@ -102,9 +95,8 @@ impl EntityCommand for RelativeEntityUpdate {
.updates_received
.insert(entity_id, new_updates_received);
entity_mut.insert(UpdatesReceived(new_updates_received));
entity.insert(UpdatesReceived(new_updates_received));
let mut entity = world.entity_mut(entity);
(self.update)(&mut entity);
}
}

View file

@ -809,7 +809,7 @@ impl DataComponent for ContainerLoot {
#[derive(Clone, PartialEq, AzBuf)]
pub enum JukeboxPlayable {
Registry(registry::JukeboxSong),
Referenced(ResourceLocation),
Direct(Holder<registry::JukeboxSong, JukeboxSongData>),
}
impl DataComponent for JukeboxPlayable {
@ -1206,8 +1206,8 @@ pub struct ItemDamageFunction {
#[derive(Clone, PartialEq, AzBuf)]
pub enum ProvidesTrimMaterial {
Holder(Holder<TrimMaterial, DirectTrimMaterial>),
Registry(TrimMaterial),
Referenced(ResourceLocation),
Direct(Holder<TrimMaterial, DirectTrimMaterial>),
}
impl DataComponent for ProvidesTrimMaterial {
const KIND: DataComponentKind = DataComponentKind::ProvidesTrimMaterial;
@ -1263,7 +1263,7 @@ impl DataComponent for CowVariant {
#[derive(Clone, PartialEq, AzBuf)]
pub enum ChickenVariant {
Registry(azalea_registry::ChickenVariant),
Referenced(ResourceLocation),
Direct(ChickenVariantData),
}
impl DataComponent for ChickenVariant {
@ -1271,6 +1271,5 @@ impl DataComponent for ChickenVariant {
}
#[derive(Clone, PartialEq, AzBuf)]
pub struct ChickenVariantData {
// not a typo, as of 1.21.5 chicken variants do actually seem to be encoded like this
pub registry: azalea_registry::ChickenVariant,
}

View file

@ -20,13 +20,7 @@ use azalea_entity::{
};
use azalea_world::{Instance, InstanceContainer, InstanceName};
use bevy_app::{App, Plugin};
use bevy_ecs::{
entity::Entity,
query::With,
schedule::{IntoSystemConfigs, SystemSet},
system::{Query, Res},
world::Mut,
};
use bevy_ecs::prelude::*;
use clip::box_traverse_blocks;
use collision::{
BLOCK_SHAPE, BlockWithShape, MoverType, VoxelShape,

View file

@ -26,12 +26,14 @@ fn make_test_app() -> App {
}
pub fn insert_overworld(app: &mut App) -> Arc<RwLock<Instance>> {
app.world_mut().resource_mut::<InstanceContainer>().insert(
ResourceLocation::new("minecraft:overworld"),
384,
-64,
&RegistryHolder::default(),
)
app.world_mut()
.resource_mut::<InstanceContainer>()
.get_or_insert(
ResourceLocation::new("minecraft:overworld"),
384,
-64,
&RegistryHolder::default(),
)
}
#[test]
@ -248,12 +250,15 @@ fn test_top_slab_collision() {
#[test]
fn test_weird_wall_collision() {
let mut app = make_test_app();
let world_lock = app.world_mut().resource_mut::<InstanceContainer>().insert(
ResourceLocation::new("minecraft:overworld"),
384,
-64,
&RegistryHolder::default(),
);
let world_lock = app
.world_mut()
.resource_mut::<InstanceContainer>()
.get_or_insert(
ResourceLocation::new("minecraft:overworld"),
384,
-64,
&RegistryHolder::default(),
);
let mut partial_world = PartialInstance::default();
partial_world.chunks.set(
@ -307,12 +312,15 @@ fn test_weird_wall_collision() {
#[test]
fn test_negative_coordinates_weird_wall_collision() {
let mut app = make_test_app();
let world_lock = app.world_mut().resource_mut::<InstanceContainer>().insert(
ResourceLocation::new("minecraft:overworld"),
384,
-64,
&RegistryHolder::default(),
);
let world_lock = app
.world_mut()
.resource_mut::<InstanceContainer>()
.get_or_insert(
ResourceLocation::new("minecraft:overworld"),
384,
-64,
&RegistryHolder::default(),
);
let mut partial_world = PartialInstance::default();
partial_world.chunks.set(
@ -370,12 +378,15 @@ fn test_negative_coordinates_weird_wall_collision() {
#[test]
fn spawn_and_unload_world() {
let mut app = make_test_app();
let world_lock = app.world_mut().resource_mut::<InstanceContainer>().insert(
ResourceLocation::new("minecraft:overworld"),
384,
-64,
&RegistryHolder::default(),
);
let world_lock = app
.world_mut()
.resource_mut::<InstanceContainer>()
.get_or_insert(
ResourceLocation::new("minecraft:overworld"),
384,
-64,
&RegistryHolder::default(),
);
let mut partial_world = PartialInstance::default();
partial_world.chunks.set(

View file

@ -46,7 +46,7 @@ thiserror.workspace = true
tokio = { workspace = true, features = ["io-util", "net", "macros"] }
tokio-util = { workspace = true, features = ["codec"] }
tracing.workspace = true
hickory-resolver = { workspace = true, features = ["tokio"] }
hickory-resolver = { workspace = true, features = ["tokio", "system-config"] }
uuid.workspace = true
crc32fast = { workspace = true, optional = true }

View file

@ -16,7 +16,7 @@ pub struct PositionMoveRotation {
pub look_direction: LookDirection,
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Default)]
pub struct RelativeMovements {
pub x: bool,
pub y: bool,

View file

@ -1,9 +0,0 @@
use azalea_buf::AzBuf;
use azalea_chat::FormattedText;
use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, AzBuf, ClientboundGamePacket)]
pub struct ClientboundChatPreview {
pub query_id: i32,
pub preview: Option<FormattedText>,
}

View file

@ -1,28 +0,0 @@
use azalea_buf::AzBuf;
use azalea_core::resource_location::ResourceLocation;
use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, AzBuf, ClientboundGamePacket)]
pub struct ClientboundCustomSound {
pub name: ResourceLocation,
pub source: SoundSource,
pub x: i32,
pub y: i32,
pub z: i32,
pub volume: f32,
pub pitch: f32,
}
#[derive(AzBuf, Clone, Copy, Debug)]
pub enum SoundSource {
Master = 0,
Music = 1,
Records = 2,
Weather = 3,
Blocks = 4,
Hostile = 5,
Neutral = 6,
Players = 7,
Ambient = 8,
Voice = 9,
}

View file

@ -1,10 +0,0 @@
use azalea_buf::AzBuf;
use azalea_crypto::{MessageSignature, SignedMessageHeader};
use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, AzBuf, ClientboundGamePacket)]
pub struct ClientboundPlayerChatHeader {
pub header: SignedMessageHeader,
pub header_signature: MessageSignature,
pub body_digest: Vec<u8>,
}

View file

@ -1,7 +0,0 @@
use azalea_buf::AzBuf;
use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, AzBuf, ClientboundGamePacket)]
pub struct ClientboundSetDisplayChatPreview {
pub enabled: bool,
}

View file

@ -1,7 +1,5 @@
use std::io::{Cursor, Write};
use azalea_buf::{AzBuf, AzaleaRead, AzaleaWrite, BufReadError};
use azalea_chat::{style::ChatFormatting, FormattedText};
use azalea_buf::AzBuf;
use azalea_chat::{FormattedText, style::ChatFormatting};
use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, AzBuf, ClientboundGamePacket)]
@ -10,7 +8,7 @@ pub struct ClientboundSetPlayerTeam {
pub method: Method,
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, AzBuf)]
pub enum Method {
Add((Parameters, PlayerList)),
Remove,
@ -19,56 +17,54 @@ pub enum Method {
Leave(PlayerList),
}
impl AzaleaRead for Method {
fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
Ok(match u8::azalea_read(buf)? {
0 => Method::Add((Parameters::azalea_read(buf)?, PlayerList::azalea_read(buf)?)),
1 => Method::Remove,
2 => Method::Change(Parameters::azalea_read(buf)?),
3 => Method::Join(PlayerList::azalea_read(buf)?),
4 => Method::Leave(PlayerList::azalea_read(buf)?),
id => return Err(BufReadError::UnexpectedEnumVariant { id: i32::from(id) }),
})
}
}
impl AzaleaWrite for Method {
fn azalea_write(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
match self {
Method::Add((parameters, playerlist)) => {
0u8.azalea_write(buf)?;
parameters.azalea_write(buf)?;
playerlist.azalea_write(buf)?;
}
Method::Remove => {
1u8.azalea_write(buf)?;
}
Method::Change(parameters) => {
2u8.azalea_write(buf)?;
parameters.azalea_write(buf)?;
}
Method::Join(playerlist) => {
3u8.azalea_write(buf)?;
playerlist.azalea_write(buf)?;
}
Method::Leave(playerlist) => {
4u8.azalea_write(buf)?;
playerlist.azalea_write(buf)?;
}
}
Ok(())
}
}
#[derive(AzBuf, Clone, Debug)]
#[derive(Clone, Debug, AzBuf)]
pub struct Parameters {
pub display_name: FormattedText,
pub options: u8,
pub nametag_visibility: String,
pub collision_rule: String,
pub nametag_visibility: NameTagVisibility,
pub collision_rule: CollisionRule,
pub color: ChatFormatting,
pub player_prefix: FormattedText,
pub player_suffix: FormattedText,
}
#[derive(Clone, Copy, Debug, AzBuf)]
pub enum CollisionRule {
Always,
Never,
PushOtherTeams,
PushOwnTeam,
}
#[derive(Clone, Copy, Debug, AzBuf)]
pub enum NameTagVisibility {
Always,
Never,
HideForOtherTeams,
HideForOwnTeam,
}
type PlayerList = Vec<String>;
#[cfg(test)]
mod tests {
use std::io::Cursor;
use azalea_buf::AzaleaRead;
use crate::packets::game::ClientboundSetPlayerTeam;
#[test]
fn test_read_set_player_team() {
let contents = [
16, 99, 111, 108, 108, 105, 100, 101, 82, 117, 108, 101, 95, 57, 52, 53, 54, 0, 8, 0,
16, 99, 111, 108, 108, 105, 100, 101, 82, 117, 108, 101, 95, 57, 52, 53, 54, 1, 0, 1,
21, 8, 0, 0, 8, 0, 0, 0,
];
let mut buf = Cursor::new(contents.as_slice());
let packet = ClientboundSetPlayerTeam::azalea_read(&mut buf).unwrap();
println!("{:?}", packet);
assert_eq!(buf.position(), contents.len() as u64);
}
}

View file

@ -1,8 +0,0 @@
use azalea_buf::AzBuf;
use azalea_core::resource_location::ResourceLocation;
use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, AzBuf, ClientboundGamePacket)]
pub struct ClientboundUpdateEnabledFeatures {
pub features: Vec<ResourceLocation>,
}

View file

@ -3,9 +3,7 @@
use std::net::{IpAddr, SocketAddr};
use async_recursion::async_recursion;
use hickory_resolver::{
Name, TokioResolver, config::ResolverConfig, name_server::TokioConnectionProvider,
};
use hickory_resolver::{Name, TokioResolver, name_server::TokioConnectionProvider};
use thiserror::Error;
use crate::ServerAddress;
@ -31,11 +29,9 @@ pub async fn resolve_address(address: &ServerAddress) -> Result<SocketAddr, Reso
// we specify Cloudflare instead of the default resolver because
// hickory_resolver has an issue on Windows where it's really slow using the
// default resolver
let resolver = TokioResolver::builder_with_config(
ResolverConfig::cloudflare(),
TokioConnectionProvider::default(),
)
.build();
let resolver = TokioResolver::builder(TokioConnectionProvider::default())
.unwrap()
.build();
// first, we do a srv lookup for _minecraft._tcp.<host>
let srv_redirect_result = resolver

View file

@ -4,7 +4,7 @@ use std::{
};
use azalea_core::{registry_holder::RegistryHolder, resource_location::ResourceLocation};
use bevy_ecs::{component::Component, system::Resource};
use bevy_ecs::{component::Component, resource::Resource};
use derive_more::{Deref, DerefMut};
use nohash_hasher::IntMap;
use parking_lot::RwLock;
@ -46,7 +46,7 @@ impl InstanceContainer {
/// Add an empty world to the container (unless it already exists) and
/// returns a strong reference to the world.
#[must_use = "the world will be immediately forgotten if unused"]
pub fn insert(
pub fn get_or_insert(
&mut self,
name: ResourceLocation,
height: u32,

View file

@ -3,7 +3,7 @@ use std::{hint::black_box, sync::Arc, time::Duration};
use azalea::{
BlockPos,
pathfinder::{
astar::{self, PathfinderTimeout, a_star},
astar::{self, PathfinderTimeout, WeightedNode, a_star},
goals::{BlockPosGoal, Goal},
mining::MiningCache,
rel_block_pos::RelBlockPos,
@ -165,6 +165,55 @@ fn bench_pathfinder(c: &mut Criterion) {
run_pathfinder_benchmark(b, generate_mining_world);
});
slow_group.finish();
c.bench_function("weighted_node_le g_score", |b| {
b.iter(|| {
WeightedNode::le(
&black_box(WeightedNode {
index: 0,
g_score: 1.,
f_score: 0.,
}),
&black_box(WeightedNode {
index: 0,
g_score: 0.,
f_score: 0.,
}),
)
});
});
c.bench_function("weighted_node_le f_score", |b| {
b.iter(|| {
WeightedNode::le(
&black_box(WeightedNode {
index: 0,
g_score: 0.,
f_score: 1.,
}),
&black_box(WeightedNode {
index: 0,
g_score: 0.,
f_score: 0.,
}),
)
});
});
c.bench_function("weighted_node_le eq", |b| {
b.iter(|| {
WeightedNode::le(
&black_box(WeightedNode {
index: 0,
g_score: 0.,
f_score: 0.,
}),
&black_box(WeightedNode {
index: 0,
g_score: 0.,
f_score: 0.,
}),
)
});
});
}
criterion_group!(benches, bench_pathfinder);

View file

@ -48,7 +48,7 @@ fn look_at_everything(
look_target.y += **eye_height as f64;
}
look_at_event.send(LookAtEvent {
look_at_event.write(LookAtEvent {
entity: bot_id,
position: look_target,
});

View file

@ -26,7 +26,7 @@ fn auto_respawn(
mut perform_respawn_events: EventWriter<PerformRespawnEvent>,
) {
for event in events.read() {
perform_respawn_events.send(PerformRespawnEvent {
perform_respawn_events.write(PerformRespawnEvent {
entity: event.entity,
});
}

View file

@ -11,8 +11,7 @@ use azalea_entity::{
};
use azalea_physics::PhysicsSet;
use bevy_app::Update;
use bevy_ecs::prelude::Event;
use bevy_ecs::schedule::IntoSystemConfigs;
use bevy_ecs::prelude::*;
use futures_lite::Future;
use tracing::trace;

View file

@ -34,7 +34,7 @@ use bevy_ecs::{
/// continue;
/// };
///
/// chat_events.send(SendChatEvent {
/// chat_events.write(SendChatEvent {
/// entity: bot_id,
/// content: String::from("Ahhh!"),
/// });

View file

@ -66,6 +66,7 @@ where
let mut best_path_scores: [f32; 7] = [heuristic(start); 7];
let mut num_nodes = 0;
let mut num_movements = 0;
while let Some(WeightedNode { index, g_score, .. }) = open_set.pop() {
num_nodes += 1;
@ -94,6 +95,7 @@ where
if tentative_g_score - g_score < MIN_IMPROVEMENT {
continue;
}
num_movements += 1;
match nodes.entry(neighbor.movement.target) {
indexmap::map::Entry::Occupied(mut e) => {
@ -166,10 +168,13 @@ where
let best_path = determine_best_path(best_paths, 0);
let elapsed_seconds = start_time.elapsed().as_secs_f64();
let nodes_per_second = (num_nodes as f64 / elapsed_seconds) as u64;
let num_movements_per_second = (num_movements as f64 / elapsed_seconds) as u64;
debug!(
"A* ran at {} nodes per second",
((num_nodes as f64 / start_time.elapsed().as_secs_f64()) as u64)
.to_formatted_string(&num_format::Locale::en)
"A* ran at {} nodes per second and {} movements per second",
nodes_per_second.to_formatted_string(&num_format::Locale::en),
num_movements_per_second.to_formatted_string(&num_format::Locale::en),
);
Path {
@ -262,22 +267,38 @@ impl<P: Hash + Copy + Clone, M: Clone> Clone for Movement<P, M> {
}
#[derive(PartialEq)]
#[repr(C)]
pub struct WeightedNode {
index: usize,
/// The actual cost to get to this node
g_score: f32,
/// Sum of the g_score and heuristic
f_score: f32,
pub f_score: f32,
/// The actual cost to get to this node
pub g_score: f32,
pub index: usize,
}
impl Ord for WeightedNode {
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering {
// intentionally inverted to make the BinaryHeap a min-heap
match other.f_score.total_cmp(&self.f_score) {
cmp::Ordering::Equal => self.g_score.total_cmp(&other.g_score),
s => s,
// we compare bits instead of floats because it's faster. this is the same as
// f32::total_cmp as long as the numbers aren't negative
debug_assert!(self.f_score >= 0.0);
debug_assert!(other.f_score >= 0.0);
debug_assert!(self.g_score >= 0.0);
debug_assert!(other.g_score >= 0.0);
let self_f_score = self.f_score.to_bits() as i32;
let other_f_score = other.f_score.to_bits() as i32;
if self_f_score == other_f_score {
let self_g_score = self.g_score.to_bits() as i32;
let other_g_score = other.g_score.to_bits() as i32;
return self_g_score.cmp(&other_g_score);
}
// intentionally inverted to make the BinaryHeap a min-heap
other_f_score.cmp(&self_f_score)
}
}
impl Eq for WeightedNode {}
@ -305,3 +326,37 @@ impl Default for PathfinderTimeout {
Self::Time(Duration::from_secs(1))
}
}
#[cfg(test)]
mod tests {
use super::*;
fn weighted_node(f: f32, g: f32) -> WeightedNode {
WeightedNode {
f_score: f,
g_score: g,
index: 0,
}
}
#[test]
fn test_weighted_node_eq() {
let a = weighted_node(0., 0.);
let b = weighted_node(0., 0.);
assert!(a == b);
}
#[test]
fn test_weighted_node_le() {
let a = weighted_node(1., 0.);
let b = weighted_node(0., 0.);
assert_eq!(a.cmp(&b), cmp::Ordering::Less);
assert!(a.le(&b));
}
#[test]
fn test_weighted_node_le_g() {
let a = weighted_node(0., 1.);
let b = weighted_node(0., 0.);
assert_eq!(a.cmp(&b), cmp::Ordering::Greater);
assert!(!a.le(&b));
}
}

View file

@ -32,9 +32,7 @@ use azalea_entity::{Physics, Position};
use azalea_physics::PhysicsSet;
use azalea_world::{InstanceContainer, InstanceName};
use bevy_app::{PreUpdate, Update};
use bevy_ecs::prelude::Event;
use bevy_ecs::query::Changed;
use bevy_ecs::schedule::IntoSystemConfigs;
use bevy_ecs::prelude::*;
use bevy_tasks::{AsyncComputeTaskPool, Task};
use futures_lite::future;
use goals::BlockPosGoal;
@ -477,7 +475,7 @@ pub fn handle_tasks(
for (entity, mut task) in &mut transform_tasks {
if let Some(optional_path_found_event) = future::block_on(future::poll_once(&mut task.0)) {
if let Some(path_found_event) = optional_path_found_event {
path_found_events.send(path_found_event);
path_found_events.write(path_found_event);
}
// Task is complete, so remove task component from entity
@ -698,7 +696,7 @@ pub fn check_node_reached(
if executing_path.path.is_empty() {
info!("the path we just swapped to was empty, so reached end of path");
walk_events.send(StartWalkEvent {
walk_events.write(StartWalkEvent {
entity,
direction: WalkDirection::None,
});
@ -712,7 +710,7 @@ pub fn check_node_reached(
if executing_path.path.is_empty() {
debug!("pathfinder path is now empty");
walk_events.send(StartWalkEvent {
walk_events.write(StartWalkEvent {
entity,
direction: WalkDirection::None,
});
@ -923,7 +921,7 @@ pub fn recalculate_near_end_of_path(
"recalculate_near_end_of_path executing_path.is_path_partial: {}",
executing_path.is_path_partial
);
goto_events.send(GotoEvent {
goto_events.write(GotoEvent {
entity,
goal,
successors_fn,
@ -947,7 +945,7 @@ pub fn recalculate_near_end_of_path(
info!(
"the path we just swapped to was empty, so reached end of path"
);
walk_events.send(StartWalkEvent {
walk_events.write(StartWalkEvent {
entity,
direction: WalkDirection::None,
});
@ -955,7 +953,7 @@ pub fn recalculate_near_end_of_path(
break;
}
} else {
walk_events.send(StartWalkEvent {
walk_events.write(StartWalkEvent {
entity,
direction: WalkDirection::None,
});
@ -966,7 +964,7 @@ pub fn recalculate_near_end_of_path(
_ => {
if executing_path.path.is_empty() {
// idk when this can happen but stop moving just in case
walk_events.send(StartWalkEvent {
walk_events.write(StartWalkEvent {
entity,
direction: WalkDirection::None,
});
@ -1033,7 +1031,7 @@ pub fn recalculate_if_has_goal_but_no_path(
if pathfinder.goal.is_some() && !pathfinder.is_calculating {
if let Some(goal) = pathfinder.goal.as_ref().cloned() {
debug!("Recalculating path because it has a goal but no ExecutingPath");
goto_events.send(GotoEvent {
goto_events.write(GotoEvent {
entity,
goal,
successors_fn: pathfinder.successors_fn.unwrap(),
@ -1081,7 +1079,7 @@ pub fn handle_stop_pathfinding_event(
}
if executing_path.path.is_empty() {
walk_events.send(StartWalkEvent {
walk_events.write(StartWalkEvent {
entity: event.entity,
direction: WalkDirection::None,
});
@ -1098,7 +1096,7 @@ pub fn stop_pathfinding_on_instance_change(
if !executing_path.path.is_empty() {
debug!("instance changed, clearing path");
executing_path.path.clear();
stop_pathfinding_events.send(StopPathfindingEvent {
stop_pathfinding_events.write(StopPathfindingEvent {
entity,
force: true,
});

View file

@ -68,7 +68,7 @@ pub struct ExecuteCtx<'w1, 'w2, 'w3, 'w4, 'w5, 'w6, 'a> {
impl ExecuteCtx<'_, '_, '_, '_, '_, '_, '_> {
pub fn look_at(&mut self, position: Vec3) {
self.look_at_events.send(LookAtEvent {
self.look_at_events.write(LookAtEvent {
entity: self.entity,
position: Vec3 {
x: position.x,
@ -80,28 +80,28 @@ impl ExecuteCtx<'_, '_, '_, '_, '_, '_, '_> {
}
pub fn look_at_exact(&mut self, position: Vec3) {
self.look_at_events.send(LookAtEvent {
self.look_at_events.write(LookAtEvent {
entity: self.entity,
position,
});
}
pub fn sprint(&mut self, direction: SprintDirection) {
self.sprint_events.send(StartSprintEvent {
self.sprint_events.write(StartSprintEvent {
entity: self.entity,
direction,
});
}
pub fn walk(&mut self, direction: WalkDirection) {
self.walk_events.send(StartWalkEvent {
self.walk_events.write(StartWalkEvent {
entity: self.entity,
direction,
});
}
pub fn jump(&mut self) {
self.jump_events.send(JumpEvent {
self.jump_events.write(JumpEvent {
entity: self.entity,
});
}
@ -137,7 +137,7 @@ impl ExecuteCtx<'_, '_, '_, '_, '_, '_, '_> {
let best_tool_result = best_tool_in_hotbar_for_block(block_state, &self.menu);
self.set_selected_hotbar_slot_events
.send(SetSelectedHotbarSlotEvent {
.write(SetSelectedHotbarSlotEvent {
entity: self.entity,
slot: best_tool_result.index as u8,
});
@ -146,7 +146,7 @@ impl ExecuteCtx<'_, '_, '_, '_, '_, '_, '_> {
self.walk(WalkDirection::None);
self.look_at_exact(block.center());
self.start_mining_events.send(StartMiningBlockEvent {
self.start_mining_events.write(StartMiningBlockEvent {
entity: self.entity,
position: block,
});

View file

@ -8,11 +8,12 @@ use azalea_core::position::BlockPos;
///
/// The X and Z are limited to ±32k.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
#[repr(C)]
pub struct RelBlockPos {
pub x: i16,
pub z: i16,
/// Note that the y isn't relative.
pub y: i32,
pub z: i16,
}
impl RelBlockPos {

View file

@ -6,7 +6,7 @@ pub use azalea_core::tick::GameTick;
// this is necessary to make the macros that reference bevy_ecs work
pub use crate::ecs as bevy_ecs;
pub use crate::ecs::{component::Component, system::Resource};
pub use crate::ecs::{component::Component, resource::Resource};
pub use crate::{
ClientBuilder, bot::BotClientExt, container::ContainerClientExt,
pathfinder::PathfinderClientExt,

View file

@ -20,12 +20,7 @@ use bevy_app::{App, Plugin, Update};
use bevy_ecs::prelude::Event;
use super::{Swarm, SwarmEvent};
use crate::ecs::{
component::Component,
event::{EventReader, EventWriter},
schedule::IntoSystemConfigs,
system::{Commands, Query, Res, ResMut, Resource},
};
use crate::ecs::prelude::*;
#[derive(Clone)]
pub struct SwarmChatPlugin;
@ -99,7 +94,7 @@ fn chat_listener(
if !found {
// didn't find the message, so fire the swarm event and add to the queue
new_chat_messages_events.send(NewChatMessageEvent(event.packet.clone()));
new_chat_messages_events.write(NewChatMessageEvent(event.packet.clone()));
global_chat_state.chat_queue.push_back(event.packet.clone());
client_chat_index =
global_chat_state.chat_queue.len() + global_chat_state.chat_min_index;

View file

@ -38,5 +38,5 @@ fn check_ready(
// all the players are in the world, so we're ready
**is_swarm_ready = true;
ready_events.send(SwarmReadyEvent);
ready_events.write(SwarmReadyEvent);
}

View file

@ -24,7 +24,7 @@ use azalea_client::{
use azalea_protocol::{ServerAddress, resolver};
use azalea_world::InstanceContainer;
use bevy_app::{App, PluginGroup, PluginGroupBuilder, Plugins};
use bevy_ecs::{component::Component, entity::Entity, system::Resource, world::World};
use bevy_ecs::prelude::*;
use futures::future::{BoxFuture, join_all};
use parking_lot::{Mutex, RwLock};
use tokio::sync::mpsc;
@ -396,7 +396,7 @@ where
let main_schedule_label = self.app.main().update_schedule.unwrap();
let ecs_lock = start_ecs_runner(self.app);
let (ecs_lock, start_running_systems) = start_ecs_runner(self.app);
let swarm = Swarm {
ecs_lock: ecs_lock.clone(),
@ -420,6 +420,10 @@ where
ecs.clear_trackers();
}
// only do this after we inserted the Swarm and state resources to avoid errors
// where Res<Swarm> is inaccessible
start_running_systems();
// SwarmBuilder (self) isn't Send so we have to take all the things we need out
// of it
let swarm_clone = swarm.clone();