From 830213b37d8f1aa46ed2a7307d56581d41cece13 Mon Sep 17 00:00:00 2001 From: Ruthenic Date: Sun, 23 Apr 2023 16:17:30 -0400 Subject: [PATCH] i have a serial designation N plushie coming in like a week or two Co-authored-by: Tymon --- Cargo.lock | 483 ++++++++++++++++++++++++-------------------- Cargo.toml | 7 +- README.md | 2 +- src/chat.rs | 31 ++- src/chests.rs | 9 +- src/combat.rs | 100 +++++++++ src/commands/mod.rs | 5 +- src/loot_tables.rs | 63 ++++++ src/main.rs | 64 +++--- src/player.rs | 123 +++++++---- src/utils.rs | 5 +- src/world.rs | 8 +- 12 files changed, 572 insertions(+), 328 deletions(-) create mode 100644 src/combat.rs create mode 100644 src/loot_tables.rs diff --git a/Cargo.lock b/Cargo.lock index 3b8f346..41b4356 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -100,6 +100,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[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" @@ -120,7 +126,6 @@ checksum = "01db46963eb9486f7884121527ec69751d0e448f9e1d5329e80ea3424118a31a" dependencies = [ "bevy_derive", "bevy_ecs", - "bevy_reflect", "bevy_utils", "downcast-rs", "wasm-bindgen", @@ -147,7 +152,6 @@ dependencies = [ "async-channel", "bevy_ecs_macros", "bevy_ptr", - "bevy_reflect", "bevy_tasks", "bevy_utils", "downcast-rs", @@ -187,37 +191,6 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b88451d4c5a353bff67dbaa937b6886efd26ae114769c17f2b35099c7a4de" -[[package]] -name = "bevy_reflect" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc3979471890e336f3ba87961ef3ecd45c331cf2cb2f582c885e541af228b48" -dependencies = [ - "bevy_ptr", - "bevy_reflect_derive", - "bevy_utils", - "downcast-rs", - "erased-serde", - "once_cell", - "parking_lot", - "serde", - "thiserror", -] - -[[package]] -name = "bevy_reflect_derive" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc7ea7c9bc2c531eb29ba5619976613d6680453ff5dd4a7fcd08848e8bec5ad" -dependencies = [ - "bevy_macro_utils", - "bit-set", - "proc-macro2", - "quote", - "syn 1.0.109", - "uuid", -] - [[package]] name = "bevy_tasks" version = "0.10.1" @@ -261,21 +234,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - [[package]] name = "bitfield-struct" version = "0.3.2" @@ -389,40 +347,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "memoffset", - "scopeguard", -] - [[package]] name = "crossbeam-utils" version = "0.8.15" @@ -471,12 +395,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" -[[package]] -name = "either" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" - [[package]] name = "encoding_rs" version = "0.8.32" @@ -486,15 +404,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "erased-serde" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2b0c2380453a92ea8b6c8e5f64ecaafccddde8ceab55ff7a8ac1029f894569" -dependencies = [ - "serde", -] - [[package]] name = "event-listener" version = "2.5.3" @@ -866,15 +775,6 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" -[[package]] -name = "memoffset" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" -dependencies = [ - "autocfg", -] - [[package]] name = "mime" version = "0.3.17" @@ -921,20 +821,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "num" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - [[package]] name = "num-bigint" version = "0.4.3" @@ -963,15 +849,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "num-complex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" -dependencies = [ - "num-traits", -] - [[package]] name = "num-integer" version = "0.1.45" @@ -993,18 +870,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-rational" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" -dependencies = [ - "autocfg", - "num-bigint", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.15" @@ -1165,9 +1030,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.54" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] @@ -1211,28 +1076,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rayon" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-utils", - "num_cpus", -] - [[package]] name = "redox_syscall" version = "0.2.16" @@ -1248,7 +1091,7 @@ version = "0.11.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27b71749df584b7f4cac2c426c127a7c785a5106cc98f7a8feb044115f0fa254" dependencies = [ - "base64", + "base64 0.21.0", "bytes", "encoding_rs", "futures-core", @@ -1296,6 +1139,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "ron" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300a51053b1cb55c80b7a9fde4120726ddf25ca241a1cbb926626f62fb136bff" +dependencies = [ + "base64 0.13.1", + "bitflags", + "serde", +] + [[package]] name = "rsa" version = "0.7.2" @@ -1350,7 +1204,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ - "base64", + "base64 0.21.0", ] [[package]] @@ -1377,18 +1231,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.159" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.159" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", @@ -1397,9 +1251,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.95" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ "itoa", "ryu", @@ -1819,9 +1673,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79" +checksum = "5b55a3fef2a1e3b3a00ce878640918820d3c51081576ac657d23af9fc7928fdb" dependencies = [ "getrandom", "serde", @@ -1829,43 +1683,26 @@ dependencies = [ [[package]] name = "valence" -version = "0.2.0+mc1.19.4" -source = "git+https://github.com/valence-rs/valence?rev=58a3fbf#58a3fbf6a3d179a3223d54e30d78538f005bbfa1" +version = "0.2.0-dev+mc.1.19.4" +source = "git+https://github.com/valence-rs/valence?rev=1da1a58#1da1a589f15e3b46e3b72368a7aa58e8553504ca" dependencies = [ - "anyhow", - "arrayvec", - "async-trait", - "base64", "bevy_app", "bevy_ecs", - "bitfield-struct", - "bytes", - "flume", "glam", - "heck", - "hmac", - "num", - "parking_lot", - "paste", - "proc-macro2", - "quote", - "rand", - "rayon", - "reqwest", - "rsa", - "rsa-der", - "rustc-hash", - "serde", - "serde_json", - "sha1", - "sha2", - "thiserror", - "tokio", - "tracing", - "url", "uuid", + "valence_anvil", + "valence_biome", + "valence_block", + "valence_client", + "valence_core", + "valence_dimension", + "valence_entity", + "valence_instance", + "valence_inventory", "valence_nbt", - "valence_protocol", + "valence_network", + "valence_player_list", + "valence_registry", ] [[package]] @@ -1875,44 +1712,101 @@ dependencies = [ "anyhow", "flume", "once_cell", + "proc-macro2", "rand", + "ron", + "serde", "tracing", "tracing-subscriber", "valence", - "valence_anvil", - "valence_protocol", ] [[package]] name = "valence_anvil" -version = "0.1.0" -source = "git+https://github.com/valence-rs/valence?rev=58a3fbf#58a3fbf6a3d179a3223d54e30d78538f005bbfa1" +version = "0.2.0-dev+mc.1.19.4" +source = "git+https://github.com/valence-rs/valence?rev=1da1a58#1da1a589f15e3b46e3b72368a7aa58e8553504ca" dependencies = [ "byteorder", "flate2", "num-integer", "thiserror", - "valence", + "valence_biome", + "valence_block", + "valence_core", + "valence_instance", "valence_nbt", ] [[package]] -name = "valence_nbt" -version = "0.5.0" -source = "git+https://github.com/valence-rs/valence?rev=58a3fbf#58a3fbf6a3d179a3223d54e30d78538f005bbfa1" +name = "valence_biome" +version = "0.2.0-dev+mc.1.19.4" +source = "git+https://github.com/valence-rs/valence?rev=1da1a58#1da1a589f15e3b46e3b72368a7aa58e8553504ca" dependencies = [ - "byteorder", - "cesu8", + "anyhow", + "bevy_app", + "bevy_ecs", + "tracing", + "valence_core", + "valence_nbt", + "valence_registry", +] + +[[package]] +name = "valence_block" +version = "0.2.0-dev+mc.1.19.4" +source = "git+https://github.com/valence-rs/valence?rev=1da1a58#1da1a589f15e3b46e3b72368a7aa58e8553504ca" +dependencies = [ + "anyhow", + "heck", + "proc-macro2", + "quote", + "serde", + "serde_json", + "valence_build_utils", + "valence_core", +] + +[[package]] +name = "valence_build_utils" +version = "0.2.0-dev+mc.1.19.4" +source = "git+https://github.com/valence-rs/valence?rev=1da1a58#1da1a589f15e3b46e3b72368a7aa58e8553504ca" +dependencies = [ + "anyhow", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "valence_client" +version = "0.2.0-dev+mc.1.19.4" +source = "git+https://github.com/valence-rs/valence?rev=1da1a58#1da1a589f15e3b46e3b72368a7aa58e8553504ca" +dependencies = [ + "anyhow", + "bevy_app", + "bevy_ecs", + "bytes", + "glam", + "rand", + "tracing", "uuid", + "valence_biome", + "valence_core", + "valence_dimension", + "valence_entity", + "valence_instance", + "valence_registry", ] [[package]] -name = "valence_protocol" -version = "0.1.0" -source = "git+https://github.com/valence-rs/valence?rev=58a3fbf#58a3fbf6a3d179a3223d54e30d78538f005bbfa1" +name = "valence_core" +version = "0.2.0-dev+mc.1.19.4" +source = "git+https://github.com/valence-rs/valence?rev=1da1a58#1da1a589f15e3b46e3b72368a7aa58e8553504ca" dependencies = [ "aes", "anyhow", + "base64 0.21.0", + "bevy_app", + "bevy_ecs", "bitfield-struct", "byteorder", "bytes", @@ -1922,25 +1816,168 @@ dependencies = [ "heck", "proc-macro2", "quote", + "rand", "serde", "serde_json", "thiserror", "tracing", + "url", "uuid", + "valence_build_utils", + "valence_core_macros", "valence_nbt", - "valence_protocol_macros", ] [[package]] -name = "valence_protocol_macros" -version = "0.1.0" -source = "git+https://github.com/valence-rs/valence?rev=58a3fbf#58a3fbf6a3d179a3223d54e30d78538f005bbfa1" +name = "valence_core_macros" +version = "0.2.0-dev+mc.1.19.4" +source = "git+https://github.com/valence-rs/valence?rev=1da1a58#1da1a589f15e3b46e3b72368a7aa58e8553504ca" dependencies = [ "proc-macro2", "quote", "syn 1.0.109", ] +[[package]] +name = "valence_dimension" +version = "0.2.0-dev+mc.1.19.4" +source = "git+https://github.com/valence-rs/valence?rev=1da1a58#1da1a589f15e3b46e3b72368a7aa58e8553504ca" +dependencies = [ + "anyhow", + "bevy_app", + "bevy_ecs", + "tracing", + "valence_core", + "valence_nbt", + "valence_registry", +] + +[[package]] +name = "valence_entity" +version = "0.2.0-dev+mc.1.19.4" +source = "git+https://github.com/valence-rs/valence?rev=1da1a58#1da1a589f15e3b46e3b72368a7aa58e8553504ca" +dependencies = [ + "anyhow", + "bevy_app", + "bevy_ecs", + "glam", + "heck", + "paste", + "proc-macro2", + "quote", + "rustc-hash", + "serde", + "serde_json", + "syn 1.0.109", + "tracing", + "uuid", + "valence_block", + "valence_build_utils", + "valence_core", + "valence_nbt", +] + +[[package]] +name = "valence_instance" +version = "0.2.0-dev+mc.1.19.4" +source = "git+https://github.com/valence-rs/valence?rev=1da1a58#1da1a589f15e3b46e3b72368a7aa58e8553504ca" +dependencies = [ + "anyhow", + "arrayvec", + "bevy_app", + "bevy_ecs", + "glam", + "num-integer", + "parking_lot", + "rand", + "rustc-hash", + "valence_biome", + "valence_block", + "valence_core", + "valence_dimension", + "valence_entity", + "valence_nbt", +] + +[[package]] +name = "valence_inventory" +version = "0.2.0-dev+mc.1.19.4" +source = "git+https://github.com/valence-rs/valence?rev=1da1a58#1da1a589f15e3b46e3b72368a7aa58e8553504ca" +dependencies = [ + "anyhow", + "bevy_app", + "bevy_ecs", + "tracing", + "valence_client", + "valence_core", +] + +[[package]] +name = "valence_nbt" +version = "0.5.0" +source = "git+https://github.com/valence-rs/valence?rev=1da1a58#1da1a589f15e3b46e3b72368a7aa58e8553504ca" +dependencies = [ + "byteorder", + "cesu8", + "uuid", +] + +[[package]] +name = "valence_network" +version = "0.2.0-dev+mc.1.19.4" +source = "git+https://github.com/valence-rs/valence?rev=1da1a58#1da1a589f15e3b46e3b72368a7aa58e8553504ca" +dependencies = [ + "anyhow", + "async-trait", + "base64 0.21.0", + "bevy_app", + "bevy_ecs", + "bytes", + "flume", + "hmac", + "num-bigint", + "rand", + "reqwest", + "rsa", + "rsa-der", + "serde", + "serde_json", + "sha1", + "sha2", + "thiserror", + "tokio", + "tracing", + "uuid", + "valence_client", + "valence_core", + "valence_entity", +] + +[[package]] +name = "valence_player_list" +version = "0.2.0-dev+mc.1.19.4" +source = "git+https://github.com/valence-rs/valence?rev=1da1a58#1da1a589f15e3b46e3b72368a7aa58e8553504ca" +dependencies = [ + "bevy_app", + "bevy_ecs", + "uuid", + "valence_client", + "valence_core", + "valence_instance", +] + +[[package]] +name = "valence_registry" +version = "0.2.0-dev+mc.1.19.4" +source = "git+https://github.com/valence-rs/valence?rev=1da1a58#1da1a589f15e3b46e3b72368a7aa58e8553504ca" +dependencies = [ + "bevy_app", + "bevy_ecs", + "tracing", + "valence_core", + "valence_nbt", +] + [[package]] name = "valuable" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 3e41cba..066a287 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,12 +6,13 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +proc-macro2 = "1.0.56" tracing = "0.1.37" tracing-subscriber = "0.3.16" -valence = { git = "https://github.com/valence-rs/valence", rev = "58a3fbf" } -valence_protocol = { git = "https://github.com/valence-rs/valence", rev = "58a3fbf" } -valence_anvil = { git = "https://github.com/valence-rs/valence", rev = "58a3fbf" } +valence = { git = "https://github.com/valence-rs/valence", rev = "1da1a58" } flume = "0.10.14" anyhow = "1.0.70" once_cell = "1.17.1" rand = "0.8.5" +ron = "0.8.0" +serde = { version = "1.0.160", features = ["derive"] } diff --git a/README.md b/README.md index d83a81c..2bd6fb7 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A (really bad) implementation of Minecraft: Console Edition's Battle minigame, u ## How to run? Don't. -### But what if I take away your Robo Fizz plushie instead? +### But what if I take away your Robo Fizz and/or N plushie instead? Okay, fine. 1. Clone repo 2. Get world (hosted [here](https://media.ruthenic.com/world.tar.zstd)) and extract it (other worlds aren't supported because there are too many hardcoded values) diff --git a/src/chat.rs b/src/chat.rs index 15874c9..d0d9556 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -1,7 +1,10 @@ use valence::{client::misc::ChatMessage, prelude::*}; -pub fn chat_handler( - mut clients: Query<(&mut Client, &Username)>, +use crate::MessageQueue; + +pub fn player_message_handler( + clients: Query<(&mut Client, &Username)>, + mut message_queue: ResMut, mut messages: EventReader, ) { for message in messages.iter() { @@ -13,25 +16,21 @@ pub fn chat_handler( let new_message = format!("[{}] ", username).not_bold().color(Color::GOLD) + message.message.to_string().not_bold().color(Color::WHITE); - for (mut client, _) in &mut clients { - client.send_message(new_message.clone()); - } + message_queue.0.push(new_message) } } -pub fn player_joined(mut clients: Query<(&mut Client, &Username)>) { - let mut messages: Vec = vec![]; +pub fn flush_message_queue( + mut clients: Query<&mut Client>, + mut message_queue: ResMut, +) { + message_queue.0.reverse(); + while message_queue.0.len() > 0 { + let message = message_queue.0.pop().unwrap(); - for (mut client, username) in &mut clients { - if client.is_added() { - messages.push( - format!("{} joined the game", username) - .italic() - .color(Color::GRAY), - ); - } + tracing::info!("{}", message.clone().to_string()); - for message in messages.iter() { + for mut client in &mut clients { client.send_message(message.clone()); } } diff --git a/src/chests.rs b/src/chests.rs index 65cdac2..d29c9c1 100644 --- a/src/chests.rs +++ b/src/chests.rs @@ -1,7 +1,5 @@ -use valence::bevy_ecs; -use valence::client::misc::InteractBlock; -use valence::prelude::*; -use valence_protocol::block::BlockEntityKind; +use crate::loot_tables::EARLY_GAME; +use valence::{block::BlockEntityKind, client::misc::InteractBlock, ecs as bevy_ecs, prelude::*}; #[derive(Component, Debug)] pub struct Chest { @@ -42,8 +40,7 @@ pub fn open_chests( event.position.y, event.position.z ); - let mut inventory = Inventory::new(InventoryKind::Generic9x3); - inventory.set_slot(0, ItemStack::new(ItemKind::IronSword, 1, None)); + let inventory = EARLY_GAME.get_random_inventory(5, 7); let chest_commands = commands.spawn((inventory, Pos(event.position))); diff --git a/src/combat.rs b/src/combat.rs new file mode 100644 index 0000000..e22e0f4 --- /dev/null +++ b/src/combat.rs @@ -0,0 +1,100 @@ +use valence::ecs::{self as bevy_ecs, prelude::*, query::WorldQuery}; +use valence::entity::living::Health; +use valence::entity::EntityStatuses; +use valence::glam::Vec3Swizzles; +use valence::inventory::ClientInventoryState; +use valence::prelude::*; + +#[derive(Component)] +pub struct CombatState { + /// The tick the client was last attacked. + pub last_attacked_tick: i64, + pub has_bonus_knockback: bool, +} + +#[derive(WorldQuery)] +#[world_query(mutable)] +pub struct CombatQuery { + client: &'static mut Client, + inventory: &'static mut Inventory, + inventory_state: &'static mut ClientInventoryState, + health: &'static mut Health, + pos: &'static Position, + state: &'static mut CombatState, + statuses: &'static mut EntityStatuses, +} + +pub fn handle_combat_events( + server: Res, + mut clients: Query, + mut sprinting: EventReader, + mut interact_entity: EventReader, +) { + for &Sprinting { client, state } in sprinting.iter() { + if let Ok(mut client) = clients.get_mut(client) { + client.state.has_bonus_knockback = state == SprintState::Start; + } + } + + for &InteractEntity { + client: attacker_client, + entity: victim_client, + .. + } in interact_entity.iter() + { + let Ok([mut attacker, mut victim]) = clients.get_many_mut([attacker_client, victim_client]) else { + continue + }; + + if server.current_tick() - victim.state.last_attacked_tick < 10 { + continue; + } + + victim.state.last_attacked_tick = server.current_tick(); + + let mut damage = 0.0; + + let slot_idx = attacker.inventory_state.held_item_slot(); + if let Some(stack) = attacker.inventory.slot(slot_idx) { + match stack.item { + ItemKind::WoodenSword => damage += 4.0, + ItemKind::WoodenAxe => damage += 7.0, + ItemKind::StoneSword => damage += 5.0, + ItemKind::StoneAxe => damage += 9.0, + ItemKind::IronSword => damage += 6.0, + ItemKind::IronAxe => damage += 9.0, + _ => damage += 1.0, + } + } else { + damage += 1.0 + } + + victim.health.0 -= damage; + + let victim_pos = victim.pos.0.xz(); + let attacker_pos = attacker.pos.0.xz(); + + let dir = (victim_pos - attacker_pos).normalize().as_vec2(); + + let knockback_xz = if attacker.state.has_bonus_knockback { + 18.0 + } else { + 8.0 + }; + let knockback_y = if attacker.state.has_bonus_knockback { + 8.432 + } else { + 6.432 + }; + + victim + .client + .set_velocity([dir.x * knockback_xz, knockback_y, dir.y * knockback_xz]); + + attacker.state.has_bonus_knockback = false; + + victim.client.trigger_status(EntityStatus::PlayAttackSound); + + victim.statuses.trigger(EntityStatus::PlayAttackSound); + } +} diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 6f4eb1b..a1371b0 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1,7 +1,8 @@ mod gamemode; -use valence::{event_loop::PacketEvent, prelude::*}; -use valence_protocol::packet::c2s::play::CommandExecutionC2s; +use valence::{ + client::event_loop::PacketEvent, packet::c2s::play::CommandExecutionC2s, prelude::*, +}; #[derive(Clone, Debug)] pub struct CommandExecution { diff --git a/src/loot_tables.rs b/src/loot_tables.rs new file mode 100644 index 0000000..8474d9b --- /dev/null +++ b/src/loot_tables.rs @@ -0,0 +1,63 @@ +use once_cell::sync::Lazy; +use rand::{distributions::WeightedIndex, prelude::Distribution, Rng}; +use valence::prelude::*; + +pub struct LootTable { + items: Vec, + index: WeightedIndex, +} + +impl LootTable { + pub fn new(table: Vec<(ItemKind, f64)>) -> LootTable { + let items = table.iter().map(|item| item.0); + let weights = table.iter().map(|item| item.1); + + LootTable { + items: items.collect(), + index: WeightedIndex::new(weights).unwrap(), + } + } + + pub fn get_random_item(&self) -> ItemKind { + let mut rng = rand::thread_rng(); + self.items[self.index.sample(&mut rng)] + } + + pub fn get_random_inventory(&self, min: i64, max: i64) -> Inventory { + let mut rng = rand::thread_rng(); + let mut inventory = Inventory::new(InventoryKind::Generic9x3); + + for _ in 0..rng.gen_range(min..max) { + let mut random_slot_idx = rng.gen_range(0..27); + while let Some(_) = inventory.slot(random_slot_idx) { + random_slot_idx = rng.gen_range(0..27) + } + + inventory.set_slot( + random_slot_idx, + ItemStack::new(self.get_random_item(), 1, None), + ) + } + + inventory + } +} + +pub static EARLY_GAME: Lazy = Lazy::new(|| { + let table = vec![ + // Armor + (ItemKind::LeatherHelmet, 20.0), + (ItemKind::LeatherChestplate, 16.5), + (ItemKind::LeatherLeggings, 16.0), + (ItemKind::LeatherBoots, 25.0), + // Attacking items (swords/axes) + (ItemKind::WoodenSword, 20.0), + (ItemKind::WoodenAxe, 10.0), + (ItemKind::StoneSword, 15.0), + (ItemKind::StoneAxe, 7.5), + (ItemKind::IronSword, 5.0), + (ItemKind::IronAxe, 2.5), + ]; + + LootTable::new(table) +}); diff --git a/src/main.rs b/src/main.rs index 8a16032..32055e0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,8 @@ mod chat; mod chests; +mod combat; mod commands; +mod loot_tables; mod player; mod special; mod utils; @@ -8,22 +10,24 @@ mod world; use std::net::SocketAddr; -use std::sync::atomic::AtomicI32; -use std::sync::atomic::Ordering; +use std::sync::atomic::{AtomicI32, Ordering}; -use commands::handle_command_execution; -use commands::CommandExecution; -use valence::prelude::*; +use commands::{handle_command_execution, CommandExecution}; +use valence::{ + ecs as bevy_ecs, + network::{async_trait, ServerListPing}, + prelude::*, +}; pub static PLAYER_COUNT: AtomicI32 = AtomicI32::new(0); struct MyCallbacks; #[async_trait] -impl AsyncCallbacks for MyCallbacks { +impl NetworkCallbacks for MyCallbacks { async fn server_list_ping( &self, - _shared: &SharedServer, + _shared: &SharedNetworkState, _remote_addr: SocketAddr, _protocol_version: i32, ) -> ServerListPing { @@ -37,37 +41,35 @@ impl AsyncCallbacks for MyCallbacks { } } +#[derive(Resource, Debug)] +pub struct MessageQueue(pub Vec); + fn main() { tracing_subscriber::fmt::init(); - let server = ServerPlugin::new(MyCallbacks); - App::new() - .add_plugin(server) + .insert_resource(NetworkSettings { + //connection_mode: valence::network::ConnectionMode::Offline, + callbacks: MyCallbacks.into(), + ..Default::default() + }) + .insert_resource(MessageQueue(vec![])) + .add_plugins(DefaultPlugins) .add_startup_system(world::setup) .add_event::() - .add_system( - handle_command_execution - .in_schedule(EventLoopSchedule) - .in_base_set(EventLoopSet::PreUpdate), - ) - .add_systems( - ( - //default_event_handler, - //special::tnt, - chat::chat_handler, - chests::open_chests, - commands::command_executor, - player::fall_damage, - player::death, - player::respawn, - ) - .in_schedule(EventLoopSchedule), - ) + .add_system(player::update_username_cache) + .add_system(handle_command_execution) .add_systems(( - player::init_clients, - chat::player_joined, - player::despawn_disconnected_clients, + chat::player_message_handler, + chests::open_chests, + commands::command_executor, + player::fall_damage, + combat::handle_combat_events, + player::death, + player::respawn, + chat::flush_message_queue, )) + .add_system(player::init_clients) + .add_system(player::despawn_disconnected_clients) .run(); } diff --git a/src/player.rs b/src/player.rs index 0ddad6a..1bc5f6d 100644 --- a/src/player.rs +++ b/src/player.rs @@ -3,16 +3,22 @@ use std::{ sync::{atomic::Ordering, Mutex}, }; -use crate::utils::get_death_message; -use valence::{bevy_ecs, client::misc::Respawn}; -use valence::{entity::living::Health, packet::WritePacket, prelude::*}; -use valence_protocol::{ - packet::s2c::play::{ - synchronize_tags::{Tag, TagGroup}, - ChunkRenderDistanceCenterS2c, DamageTiltS2c, SynchronizeTagsS2c, +use crate::{combat::CombatState, utils::get_death_message, MessageQueue}; +use once_cell::sync::Lazy; +use valence::{ + client::misc::Respawn, + ecs as bevy_ecs, + entity::{living::Health, OnGround}, + packet::{ + encode::WritePacket, + s2c::play::{ + synchronize_tags::{Tag, TagGroup}, + ChunkRenderDistanceCenterS2c, DamageTiltS2c, SynchronizeTagsS2c, + }, + var_int::VarInt, + Encode, }, - var_int::VarInt, - Encode, + prelude::*, }; use crate::PLAYER_COUNT; @@ -36,6 +42,7 @@ pub fn init_clients( ), Added, >, + mut message_queue: ResMut, instances: Query>, mut commands: Commands, ) { @@ -51,9 +58,14 @@ pub fn init_clients( y: 83.0, z: 276.0, }); - commands - .entity(entity) - .insert((OldHeight(-1.0), Alive(true))); + commands.entity(entity).insert(( + OldHeight(-1.0), + Alive(true), + CombatState { + last_attacked_tick: 0, + has_bonus_knockback: false, + }, + )); // send packet that magically fixes chunks // TODO: make this configurable as different maps will have different chunks we need to force load @@ -93,7 +105,46 @@ pub fn init_clients( // add player to count PLAYER_COUNT.fetch_add(1, Ordering::SeqCst); - tracing::info!("{username} joined the game"); + //tracing::info!("{username} joined the game"); + message_queue.0.push( + format!("{username} joined the game") + .italic() + .color(Color::GRAY), + ) + } +} + +// NOTE: this could be a resource but since it's only used here there isn't much of a point imo +static USERNAME_CACHE: Lazy>> = + Lazy::new(|| Mutex::new(HashMap::new())); + +pub fn update_username_cache(query: Query<(Entity, &Username)>) { + for (entity, username) in query.iter() { + let _ = USERNAME_CACHE + .lock() + .unwrap() + .insert(entity, username.0.clone()); + } +} + +pub fn despawn_disconnected_clients( + mut commands: Commands, + mut message_queue: ResMut, + mut disconnected_clients: RemovedComponents, +) { + let default_username = "[Unknown username]".to_string(); + let username_cache = USERNAME_CACHE.lock().unwrap(); + for entity in disconnected_clients.iter() { + if let Some(mut entity_commands) = commands.get_entity(entity) { + let username = username_cache.get(&entity).unwrap_or(&default_username); + message_queue.0.push( + format!("{username} left the game") + .italic() + .color(Color::GRAY), + ); + entity_commands.insert(Despawned); + PLAYER_COUNT.fetch_sub(1, Ordering::SeqCst); + } } } @@ -152,10 +203,11 @@ pub fn fall_damage( } } -pub fn death(mut clients: Query<(&mut Client, &UniqueId, &Health, &Username, &mut Alive)>) { - let mut messages: Vec = vec![]; - - for (mut client, id, health, username, mut is_alive) in &mut clients { +pub fn death( + mut clients: Query<(&mut Client, &Health, &Username, &mut Alive)>, + mut message_queue: ResMut, +) { + for (mut client, health, username, mut is_alive) in &mut clients { if health.0 <= 0.0 && is_alive.0 { tracing::debug!("Trying to kill player {}", username); @@ -164,25 +216,9 @@ pub fn death(mut clients: Query<(&mut Client, &UniqueId, &Health, &Username, &mu client.kill(None, death_message.clone()); is_alive.0 = false; - messages.push(death_message.italic().color(Color::GRAY)); - } - } - - for (mut client, _, _, _, _) in &mut clients { - for message in messages.iter() { - client.send_message(message.clone()); - } - } -} - -pub fn despawn_disconnected_clients( - mut commands: Commands, - mut disconnected_clients: RemovedComponents, -) { - for entity in disconnected_clients.iter() { - if let Some(mut entity) = commands.get_entity(entity) { - entity.insert(Despawned); - PLAYER_COUNT.fetch_sub(1, Ordering::SeqCst); + message_queue + .0 + .push(death_message.italic().color(Color::GRAY)); } } } @@ -191,28 +227,33 @@ pub fn respawn( mut clients: Query<( &mut Position, &mut Look, - &mut Location, - &UniqueId, &mut Health, &mut Alive, + &mut Location, + &mut HasRespawnScreen, )>, mut events: EventReader, instances: Query>, ) { for event in events.iter() { - if let Ok((mut pos, mut look, mut loc, uuid, mut health, mut is_alive)) = + if let Ok((mut pos, mut look, mut health, mut is_alive, mut loc, mut has_respawn_screen)) = clients.get_mut(event.client) { + tracing::debug!("Trying to respawn player..."); + pos.set(DVec3 { x: -214.0, y: 83.0, z: 276.0, }); + + loc.0 = instances.single(); + look.yaw = 0.0; look.pitch = 0.0; - loc.0 = instances.single(); - health.0 = 20.0; + health.0 = 20.0; + has_respawn_screen.0 = false; is_alive.0 = true; } } diff --git a/src/utils.rs b/src/utils.rs index 25cc9fa..ecec5f2 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,12 +1,13 @@ use rand::prelude::*; -static DEATH_MESSAGES: [&str; 21] = [ +static DEATH_MESSAGES: [&str; 22] = [ "{username} got fired by Mike Mood.", "{username} let the water drip on their springlocks.", - "{username} got stuck on a fetch quest.", + "{username} got stuck in a fetch quest.", "{username} SIGSEGVed.", "{username} was so engrossed in their xReader fanfic that they didn't notice the player sneaking up behind them.", "{username} thought the Ink Demon would not kill them and actually love them. They were wrong.", + "{username} thought the Ink Demon really just wanted a hug.", "{username} ignored all of the warning signs and went on to die an entirely avoidable death.", "{username} thought they could out-drink Husk. They were wrong.", "{username} tried to outfuck Angel Dust.", diff --git a/src/world.rs b/src/world.rs index 4eb5ddc..2438dff 100644 --- a/src/world.rs +++ b/src/world.rs @@ -1,5 +1,7 @@ -use valence::prelude::*; -use valence_anvil::{AnvilChunk, AnvilWorld}; +use valence::{ + anvil::{AnvilChunk, AnvilWorld}, + prelude::*, +}; pub fn setup( mut commands: Commands, @@ -21,7 +23,7 @@ pub fn setup( let mut chunk = Chunk::new(24); - let Ok(_) = valence_anvil::to_valence(&data, &mut chunk, 4, |_| BiomeId::default()) else { + let Ok(_) = valence::anvil::to_valence(&data, &mut chunk, 4, |_| BiomeId::default()) else { tracing::warn!("Failed to load chunk ({x}, {z}); could not convert Anvil chunk to Valence chunk"); continue };