diff --git a/Cargo.lock b/Cargo.lock index b749344..49d4f55 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -82,12 +82,31 @@ dependencies = [ "game", ] +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + [[package]] name = "adler" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + [[package]] name = "ahash" version = "0.8.11" @@ -207,7 +226,7 @@ dependencies = [ "objc2", "objc2-app-kit", "objc2-foundation", - "parking_lot", + "parking_lot 0.12.3", "windows-sys 0.48.0", "x11rb", ] @@ -355,6 +374,21 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64" version = "0.21.7" @@ -502,7 +536,7 @@ dependencies = [ "futures-io", "futures-lite", "js-sys", - "parking_lot", + "parking_lot 0.12.3", "ron", "serde", "thiserror", @@ -1028,6 +1062,18 @@ dependencies = [ "syn 2.0.71", ] +[[package]] +name = "bevy_renet2" +version = "0.0.5" +source = "git+https://github.com/UkoeHB/renet2?rev=0.0.5#4dac070c66b13c49f87bb5224d0ea6f578d5e846" +dependencies = [ + "bevy_app", + "bevy_ecs", + "bevy_time", + "bevy_window", + "renet2", +] + [[package]] name = "bevy_replicon" version = "0.27.0" @@ -1042,6 +1088,16 @@ dependencies = [ "varint-rs", ] +[[package]] +name = "bevy_replicon_renet2" +version = "0.0.6" +source = "git+https://github.com/UkoeHB/renet2?rev=0.0.5#4dac070c66b13c49f87bb5224d0ea6f578d5e846" +dependencies = [ + "bevy", + "bevy_renet2", + "bevy_replicon", +] + [[package]] name = "bevy_scene" version = "0.14.0" @@ -1361,6 +1417,15 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "block2" version = "0.5.1" @@ -1496,6 +1561,30 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "chacha20poly1305" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +dependencies = [ + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", +] + [[package]] name = "ciborium" version = "0.2.2" @@ -1523,6 +1612,17 @@ dependencies = [ "half", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", + "zeroize", +] + [[package]] name = "clang-sys" version = "1.8.1" @@ -1534,6 +1634,23 @@ dependencies = [ "libloading 0.8.4", ] +[[package]] +name = "client" +version = "0.1.0" +dependencies = [ + "base64 0.22.1", + "bevy", + "bevy_renet2", + "bevy_replicon", + "bevy_replicon_renet2", + "bincode", + "game", + "renet2", + "serde", + "url", + "wasm-timer", +] + [[package]] name = "clipboard-win" version = "5.4.0" @@ -1814,6 +1931,15 @@ dependencies = [ "windows 0.54.0", ] +[[package]] +name = "cpufeatures" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" version = "1.4.2" @@ -1823,6 +1949,19 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + [[package]] name = "crossbeam-channel" version = "0.5.13" @@ -1832,6 +1971,34 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.20" @@ -1844,6 +2011,17 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core", + "typenum", +] + [[package]] name = "cursor-icon" version = "1.1.0" @@ -1871,7 +2049,7 @@ dependencies = [ "hashbrown", "lock_api", "once_cell", - "parking_lot_core", + "parking_lot_core 0.9.10", ] [[package]] @@ -1886,6 +2064,15 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + [[package]] name = "derive-where" version = "1.2.7" @@ -1897,6 +2084,16 @@ dependencies = [ "syn 2.0.71", ] +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -2029,7 +2226,7 @@ dependencies = [ "ecolor", "emath", "nohash-hasher", - "parking_lot", + "parking_lot 0.12.3", ] [[package]] @@ -2179,6 +2376,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fragile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" + [[package]] name = "futures" version = "0.3.30" @@ -2300,6 +2503,16 @@ dependencies = [ "thiserror", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "gethostname" version = "0.4.3" @@ -2357,6 +2570,12 @@ dependencies = [ "windows 0.54.0", ] +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + [[package]] name = "gl_generator" version = "0.14.0" @@ -2586,6 +2805,67 @@ dependencies = [ "svg_fmt", ] +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h3" +version = "0.0.4" +source = "git+https://github.com/hyperium/h3?tag=h3-v0.0.4#651ff5ebb56f3e5319bd96595dbbf71c1ac761b1" +dependencies = [ + "bytes", + "fastrand", + "futures-util", + "http 1.1.0", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "h3-quinn" +version = "0.0.4" +source = "git+https://github.com/hyperium/h3?tag=h3-v0.0.4#651ff5ebb56f3e5319bd96595dbbf71c1ac761b1" +dependencies = [ + "bytes", + "futures", + "h3", + "quinn", + "quinn-proto", + "tokio", + "tokio-util", +] + +[[package]] +name = "h3-webtransport" +version = "0.1.0" +source = "git+https://github.com/hyperium/h3?tag=h3-v0.0.4#651ff5ebb56f3e5319bd96595dbbf71c1ac761b1" +dependencies = [ + "bytes", + "futures-util", + "h3", + "http 1.1.0", + "pin-project-lite", + "tokio", + "tracing", +] + [[package]] name = "half" version = "2.4.1" @@ -2622,6 +2902,36 @@ dependencies = [ "winapi", ] +[[package]] +name = "headers" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" +dependencies = [ + "base64 0.21.7", + "bytes", + "headers-core", + "http 0.2.12", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http 0.2.12", +] + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "hermit-abi" version = "0.4.0" @@ -2644,6 +2954,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" +[[package]] +name = "hmac-sha256" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3688e69b38018fec1557254f64c8dc2cc8ec502890182f395dbb0aa997aa5735" + [[package]] name = "home" version = "0.5.9" @@ -2684,6 +3000,53 @@ dependencies = [ "itoa", ] +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http 0.2.12", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + [[package]] name = "idna" version = "0.5.0" @@ -2764,6 +3127,24 @@ dependencies = [ "libc", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + [[package]] name = "interpolator" version = "0.5.0" @@ -2957,7 +3338,7 @@ dependencies = [ "anyhow", "camino", "indexmap", - "parking_lot", + "parking_lot 0.12.3", "proc-macro2", "quote", "rstml", @@ -3198,6 +3579,22 @@ dependencies = [ "paste", ] +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -3215,13 +3612,25 @@ dependencies = [ ] [[package]] -name = "naga" -version = "0.20.0" +name = "mio" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e536ae46fcab0876853bd4a632ede5df4b1c2527a58f6c5a4150fe86be858231" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ - "arrayvec", - "bit-set", + "hermit-abi 0.3.9", + "libc", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] +name = "naga" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e536ae46fcab0876853bd4a632ede5df4b1c2527a58f6c5a4150fe86be858231" +dependencies = [ + "arrayvec", + "bit-set", "bitflags 2.6.0", "codespan-reporting", "hexf-parse", @@ -3362,6 +3771,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-derive" version = "0.4.2" @@ -3615,6 +4030,15 @@ dependencies = [ "objc2-foundation", ] +[[package]] +name = "object" +version = "0.36.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +dependencies = [ + "memchr", +] + [[package]] name = "oboe" version = "0.6.1" @@ -3648,6 +4072,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "octets" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109983a091271ee8916076731ba5fdc9ee22fea871bc7c6ceab9bfd423eb1d99" + [[package]] name = "ogg" version = "0.8.0" @@ -3663,6 +4093,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + [[package]] name = "orbclient" version = "0.3.47" @@ -3709,6 +4145,17 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -3716,7 +4163,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.9.10", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", ] [[package]] @@ -3744,6 +4205,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +[[package]] +name = "pem" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +dependencies = [ + "base64 0.22.1", + "serde", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -3843,13 +4314,30 @@ checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" dependencies = [ "cfg-if", "concurrent-queue", - "hermit-abi", + "hermit-abi 0.4.0", "pin-project-lite", "rustix", "tracing", "windows-sys 0.52.0", ] +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "pp-rs" version = "0.2.1" @@ -3859,6 +4347,15 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + [[package]] name = "presser" version = "0.3.1" @@ -3971,6 +4468,54 @@ dependencies = [ "memchr", ] +[[package]] +name = "quinn" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" +dependencies = [ + "bytes", + "futures-io", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" +dependencies = [ + "bytes", + "rand", + "ring 0.16.20", + "rustc-hash", + "rustls", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" +dependencies = [ + "bytes", + "libc", + "socket2", + "tracing", + "windows-sys 0.48.0", +] + [[package]] name = "quote" version = "1.0.36" @@ -4015,6 +4560,18 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", "rand_core", ] @@ -4023,6 +4580,9 @@ name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] [[package]] name = "range-alloc" @@ -4036,12 +4596,33 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" +[[package]] +name = "rcgen" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48406db8ac1f3cbc7dcdb56ec355343817958a356ff430259bb07baf7607e1e1" +dependencies = [ + "pem", + "ring 0.17.8", + "time", + "yasna", +] + [[package]] name = "rectangle-pack" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0d463f2884048e7153449a55166f91028d5b0ea53c79377099ce4e8cf0cf9bb" +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -4110,6 +4691,83 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" +[[package]] +name = "renet2" +version = "0.0.5" +source = "git+https://github.com/UkoeHB/renet2?rev=0.0.5#4dac070c66b13c49f87bb5224d0ea6f578d5e846" +dependencies = [ + "anyhow", + "async-channel", + "bevy_ecs", + "bevy_reflect", + "bytes", + "crossbeam", + "form_urlencoded", + "fragile", + "futures", + "getrandom", + "h3", + "h3-quinn", + "h3-webtransport", + "hmac-sha256", + "http 1.1.0", + "js-sys", + "log", + "octets", + "quinn", + "rcgen", + "renetcode2", + "rustls", + "send_wrapper", + "serde", + "serde_json", + "time", + "tokio", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "renetcode2" +version = "0.0.5" +source = "git+https://github.com/UkoeHB/renet2?rev=0.0.5#4dac070c66b13c49f87bb5224d0ea6f578d5e846" +dependencies = [ + "chacha20poly1305", + "log", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.52.0", +] + [[package]] name = "rodio" version = "0.18.1" @@ -4147,6 +4805,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + [[package]] name = "rustc-hash" version = "1.1.0" @@ -4166,6 +4830,28 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring 0.17.8", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring 0.17.8", + "untrusted 0.9.0", +] + [[package]] name = "rustversion" version = "1.0.17" @@ -4209,6 +4895,16 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring 0.17.8", + "untrusted 0.9.0", +] + [[package]] name = "sctk-adwaita" version = "0.10.1" @@ -4300,12 +4996,35 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "server" version = "0.1.0" dependencies = [ + "base64 0.22.1", "bevy", + "bevy_renet2", + "bevy_replicon", + "bevy_replicon_renet2", + "bincode", + "fastrand", "game", + "renet2", + "serde", + "tokio", + "url", + "warp", ] [[package]] @@ -4361,6 +5080,17 @@ dependencies = [ "syn 2.0.71", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -4425,6 +5155,15 @@ dependencies = [ "sickle_math", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + [[package]] name = "simd-adler32" version = "0.3.7" @@ -4493,6 +5232,28 @@ dependencies = [ "serde", ] +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "spirv" version = "0.3.0+sdk-1.3.268.0" @@ -4514,6 +5275,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "svg_fmt" version = "0.4.3" @@ -4631,6 +5398,25 @@ dependencies = [ "weezl", ] +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -4680,6 +5466,48 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "tokio" +version = "1.39.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot 0.12.3", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.71", +] + +[[package]] +name = "tokio-util" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + [[package]] name = "toml" version = "0.8.15" @@ -4736,12 +5564,19 @@ dependencies = [ "winnow 0.6.14", ] +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + [[package]] name = "tracing" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -4808,6 +5643,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "ttf-parser" version = "0.24.0" @@ -4850,6 +5691,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "059d83cc991e7a42fc37bd50941885db0888e34209f8cfd9aab07ddec03bc9cf" +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "ui" version = "0.1.0" @@ -4861,6 +5708,15 @@ dependencies = [ "sickle_ui", ] +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.15" @@ -4900,6 +5756,28 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.5.2" @@ -4909,6 +5787,7 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -4961,6 +5840,42 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "warp" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4378d202ff965b011c64817db11d5829506d3404edeadb61f190d111da3f231c" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "headers", + "http 0.2.12", + "hyper", + "log", + "mime", + "mime_guess", + "percent-encoding", + "pin-project", + "scoped-tls", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-util", + "tower-service", + "tracing", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -5046,6 +5961,21 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" +dependencies = [ + "futures", + "js-sys", + "parking_lot 0.11.2", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "wayland-backend" version = "0.3.6" @@ -5212,7 +6142,7 @@ dependencies = [ "js-sys", "log", "naga", - "parking_lot", + "parking_lot 0.12.3", "profiling", "raw-window-handle", "smallvec", @@ -5241,7 +6171,7 @@ dependencies = [ "log", "naga", "once_cell", - "parking_lot", + "parking_lot 0.12.3", "profiling", "raw-window-handle", "rustc-hash", @@ -5283,7 +6213,7 @@ dependencies = [ "ndk-sys 0.5.0+25.2.9519653", "objc", "once_cell", - "parking_lot", + "parking_lot 0.12.3", "profiling", "range-alloc", "raw-window-handle", @@ -5700,21 +6630,32 @@ dependencies = [ "bevy", "bevy-inspector-egui", "game", - "server", "ui", ] +[[package]] +name = "wordfight-server" +version = "0.1.0" +dependencies = [ + "bevy", + "server", + "wordfight", +] + [[package]] name = "wordfight-web" version = "0.1.0" dependencies = [ "bevy", + "client", "console_error_panic_hook", + "futures-lite", "gloo-worker", "js-sys", "leptos", "serde", "wasm-bindgen", + "wasm-bindgen-futures", "web-sys", "wordfight", ] @@ -5800,12 +6741,22 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] + [[package]] name = "zerocopy" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] @@ -5819,3 +6770,9 @@ dependencies = [ "quote", "syn 2.0.71", ] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/Cargo.toml b/Cargo.toml index 2b7622a..80bdec7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ members = ["apps/*", "plugins/*"] [workspace.dependencies] active_game = { path = "plugins/active_game" } +client = { path = "plugins/client" } game = { path = "plugins/game" } server = { path = "plugins/server" } ui = { path = "plugins/ui" } @@ -10,7 +11,13 @@ ui = { path = "plugins/ui" } bevy = { version = "0.14", default-features = false } bevy_mod_try_system = "0.2" bevy-inspector-egui = "0.25" +bevy_renet2 = { git = "https://github.com/UkoeHB/renet2", rev = "0.0.5" } bevy_replicon = "0.27" +bevy_replicon_renet2 = { git = "https://github.com/UkoeHB/renet2", rev = "0.0.5" } +renet2 = { git = "https://github.com/UkoeHB/renet2", rev = "0.0.5", default-features = false, features = [ + "bevy", + "serde", +] } sickle_ui = "0.2" anyhow = "1.0" @@ -50,14 +57,12 @@ strip = "none" [features] default = [] dev = ["dep:bevy-inspector-egui"] -server = ["dep:server"] ui = ["dep:ui"] [dependencies] # plugins active_game = { workspace = true } game = { workspace = true } -server = { workspace = true, optional = true } ui = { workspace = true, optional = true } # bevy diff --git a/README.md b/README.md index 60d817b..6cd9e60 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,22 @@ WORDFIGHT is a simple text-based "fighting" game. The only mechanic is spelling. +## How To Run + +To run the webserver (be sure to have [`trunk`](https://trunkrs.dev/) installed!): + +```sh +trunk serve --release +``` + +To run the game-server: + +```sh +cargo run -p wordfight-server --release +``` + +You can configure the server IP, port, and the port for accessing the server token using the environment variables `SERVER_IP`, `SERVER_PORT`, and `SERVER_TOKENS_PORT` respectively. + ## Gameplay Two players battle by typing any substring of a valid English word into the shared input space of a fixed size (for the time being, that size is 7 characters). Each player's word extends from one "side" of the input, and both perspectives are shown to both players. diff --git a/apps/server/Cargo.toml b/apps/server/Cargo.toml new file mode 100644 index 0000000..fdfa6db --- /dev/null +++ b/apps/server/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "wordfight-server" +version = "0.1.0" +authors = ["Sean Sullivan "] +edition = "2021" +license = "MIT OR Apache-2.0" +publish = false + +[dependencies] +wordfight = { path = "../../" } +server = { workspace = true } +bevy = { workspace = true } diff --git a/apps/server/src/main.rs b/apps/server/src/main.rs new file mode 100644 index 0000000..5fc9ab7 --- /dev/null +++ b/apps/server/src/main.rs @@ -0,0 +1,36 @@ +use bevy::{ + app::ScheduleRunnerPlugin, + log::{Level, LogPlugin}, + prelude::*, +}; + +use server::ServerPlugin; +use wordfight::WordFightPlugins; + +fn main() { + App::default() + .add_plugins(( + ScheduleRunnerPlugin::run_loop( + // need some wait duration so that async tasks are not entirely outcompeted by the main loop + std::time::Duration::from_millis(10), + ), + WordFightPlugins.build().set(LogPlugin { + filter: "wgpu=error,naga=warn,h3=error".to_string(), + level: Level::INFO, + ..Default::default() + }), + )) + .add_plugins(ServerPlugin { + port: option_env!("SERVER_PORT").unwrap_or("7636").to_string(), + wt_tokens_port: option_env!("SERVER_TOKENS_PORT") + .unwrap_or("7637") + .to_string(), + // native_host: option_env!("SERVER_IP") + // .unwrap_or("127.0.0.1") + // .to_string(), + // native_port: option_env!("SERVER_IP") + // .unwrap_or("127.0.0.1") + // .to_string(), + }) + .run(); +} diff --git a/apps/web/Cargo.toml b/apps/web/Cargo.toml index cbf8981..859b419 100644 --- a/apps/web/Cargo.toml +++ b/apps/web/Cargo.toml @@ -11,6 +11,7 @@ log = [] [dependencies] # plugins wordfight = { path = "../../" } +client = { workspace = true } # bevy bevy = { workspace = true } @@ -19,21 +20,29 @@ leptos = { version = "0.6", features = ["csr"] } console_error_panic_hook = "0.1" js-sys = "0.3" +futures-lite = "2.3" wasm-bindgen = "0.2" +wasm-bindgen-futures = "0.4" web-sys = { version = "0.3", features = [ "Blob", "BlobPropertyBag", "console", "DedicatedWorkerGlobalScope", "Document", + "Headers", "HtmlElement", "Location", "MessageEvent", "KeyboardEvent", "Node", + "RequestInit", + "RequestMode", + "Response", "Text", "Url", "Window", "Worker", + "WorkerGlobalScope", ] } -gloo-worker = "0.5" + +gloo-worker = { version = "0.5", features = ["futures"] } diff --git a/apps/web/src/bin/worker.rs b/apps/web/src/bin/worker.rs index 471ffc0..a9ff79c 100644 --- a/apps/web/src/bin/worker.rs +++ b/apps/web/src/bin/worker.rs @@ -4,5 +4,6 @@ use wordfight_web::BevyWorker; fn main() { console_error_panic_hook::set_once(); - BevyWorker::registrar().register(); + let registrar = BevyWorker::registrar(); + registrar.register(); } diff --git a/apps/web/src/lib.rs b/apps/web/src/lib.rs index 465f948..312147d 100644 --- a/apps/web/src/lib.rs +++ b/apps/web/src/lib.rs @@ -5,6 +5,15 @@ pub use wordfight::*; mod worker; pub use worker::*; +pub const SERVER_IP: Option<&'static str> = option_env!("SERVER_IP"); +pub const SERVER_DEFAULT_IP: &'static str = "127.0.0.1"; + +pub const SERVER_PORT: Option<&'static str> = option_env!("SERVER_PORT"); +pub const SERVER_DEFAULT_PORT: &'static str = "7636"; + +pub const SERVER_TOKENS_PORT: Option<&'static str> = option_env!("SERVER_TOKENS_PORT"); +pub const SERVER_DEFAULT_TOKENS_PORT: &'static str = "7637"; + #[derive(Debug)] #[derive(Deserialize, Serialize)] pub enum AppMessage { diff --git a/apps/web/src/worker.rs b/apps/web/src/worker.rs index c471bbe..48139df 100644 --- a/apps/web/src/worker.rs +++ b/apps/web/src/worker.rs @@ -1,11 +1,18 @@ use gloo_worker::{HandlerId, Worker, WorkerScope}; +use js_sys::Promise; use wasm_bindgen::prelude::*; +use wasm_bindgen_futures::JsFuture; +use web_sys::{Request, RequestInit, RequestMode, Response}; use bevy::{prelude::*, utils::HashSet}; -use wordfight::{ActiveGameUpdate, WordFightPlugins}; +use client::ClientPlugin; +use wordfight::{ActiveGameUpdate, PlayerSide, WordFightPlugins}; -use crate::{AppMessage, UpdateStateMessage, WorkerMessage}; +use crate::{ + AppMessage, UpdateStateMessage, WorkerMessage, SERVER_DEFAULT_IP, SERVER_DEFAULT_PORT, + SERVER_DEFAULT_TOKENS_PORT, SERVER_IP, SERVER_PORT, SERVER_TOKENS_PORT, +}; // Use this to enable console logging #[wasm_bindgen] @@ -19,10 +26,8 @@ extern "C" { fn setInterval(closure: &Closure, millis: u32) -> f64; fn clearInterval(token: f64); } - pub struct BevyWorker { - app: App, - my_player: Entity, + game: Option, subscriptions: HashSet, _trigger_update: Closure, _interval: Interval, @@ -31,71 +36,83 @@ pub struct BevyWorker { impl Worker for BevyWorker { type Input = AppMessage; type Output = WorkerMessage; - type Message = (); + type Message = WorkerUpdateMessage; fn create(scope: &WorkerScope) -> Self { - let mut app = App::new(); - app.add_plugins(WordFightPlugins); - app.update(); - app.update(); - - let events = app.world().resource::>(); - let mut reader = events.get_reader(); - let update = reader.read(&events).last().unwrap(); - let my_player = update.player_left; - + scope + .send_future(async { WorkerUpdateMessage::Token(fetch_server_token().await.unwrap()) }); let scope_clone = scope.clone(); let trigger_update = Closure::new(move || { - scope_clone.send_message(()); + scope_clone.send_message(WorkerUpdateMessage::Update); }); let interval = setInterval(&trigger_update, 10); Self { - app, - my_player, + game: None, subscriptions: HashSet::default(), _trigger_update: trigger_update, _interval: Interval(interval), } } - fn update(&mut self, scope: &WorkerScope, _: Self::Message) { + fn update(&mut self, scope: &WorkerScope, message: Self::Message) { #[cfg(feature = "log")] log("Update".to_string()); - self.app.update(); - let events = self.app.world().resource::>(); - let mut reader = events.get_reader(); - if let Some(update) = reader.read(&events).last() { - for id in &self.subscriptions { - scope.respond( - *id, - WorkerMessage::UpdateState(UpdateStateMessage { - left_word: update.left_word.to_string(), - left_score: *update.left_score, - right_word: update.right_word.to_string(), - right_score: *update.right_score, - arena_size: update.arena_size, - }), - ); + if let Some(app) = self.game.as_mut() { + let WorkerUpdateMessage::Update = message else { + return; + }; + app.update(); + let events = app.world().resource::>(); + let mut reader = events.get_reader(); + if let Some(update) = reader.read(&events).last() { + for id in &self.subscriptions { + scope.respond( + *id, + WorkerMessage::UpdateState(UpdateStateMessage { + left_word: update.left_word.to_string(), + left_score: *update.left_score, + right_word: update.right_word.to_string(), + right_score: *update.right_score, + arena_size: update.arena_size, + }), + ); + } } + } else if let WorkerUpdateMessage::Token(token) = message { + let app = build_app(token); + self.game = Some(app); } } fn received(&mut self, _: &WorkerScope, message: Self::Input, id: HandlerId) { #[cfg(feature = "log")] log(format!("Message received! {:?}", message)); - self.subscriptions.insert(id); - let action: wordfight::Action = match message { - AppMessage::AddLetter(letter) => wordfight::Action::Append(letter), - AppMessage::Backspace => wordfight::Action::Delete, - }; - self.app - .world_mut() - .send_event(action.made_by(self.my_player, wordfight::PlayerSide::Left)); - - self.app.update(); + if let Some(app) = self.game.as_mut() { + self.subscriptions.insert(id); + let action: wordfight::Action = match message { + AppMessage::AddLetter(letter) => wordfight::Action::Append(letter), + AppMessage::Backspace => wordfight::Action::Delete, + }; + let mut query = app.world_mut().query::<(Entity, &PlayerSide)>(); + let Some((my_player, _)) = query + .iter(app.world()) + .find(|(_, side)| **side == PlayerSide::Left) + else { + return; + }; + app.world_mut() + .send_event(action.made_by(my_player, wordfight::PlayerSide::Left)); + + app.update(); + } } } +pub enum WorkerUpdateMessage { + Token(String), + Update, +} + pub struct Interval(f64); impl Drop for Interval { @@ -103,3 +120,43 @@ impl Drop for Interval { clearInterval(self.0); } } + +fn build_app(server_token: String) -> App { + let mut app = App::new(); + let server_origin = SERVER_IP.unwrap_or(SERVER_DEFAULT_IP).to_string(); + let server_port = SERVER_PORT.unwrap_or(SERVER_DEFAULT_PORT).to_string(); + + app.add_plugins(WordFightPlugins); + app.add_plugins(ClientPlugin { + server_origin, + server_port, + server_token, + }); + app.update(); + app.update(); + app +} + +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen] + fn fetch(input: &Request) -> Promise; +} + +async fn fetch_server_token() -> Result { + let server_origin = SERVER_IP.unwrap_or(SERVER_DEFAULT_IP); + let server_token_port = SERVER_TOKENS_PORT.unwrap_or(SERVER_DEFAULT_TOKENS_PORT); + let server_url = format!("http://{server_origin}:{server_token_port}"); + let mut opts = RequestInit::new(); + opts.method("GET"); + opts.mode(RequestMode::Cors); + let request = Request::new_with_str_and_init(&server_url, &opts)?; + + let response = JsFuture::from(fetch(&request)).await?; + + assert!(response.is_instance_of::()); + let response: Response = response.dyn_into().unwrap(); + let text = JsFuture::from(response.text()?).await?; + + Ok(text.as_string().unwrap()) +} diff --git a/plugins/client/Cargo.toml b/plugins/client/Cargo.toml new file mode 100644 index 0000000..1e7888a --- /dev/null +++ b/plugins/client/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "client" +version = "0.1.0" +edition = "2021" +license = "MIT OR Apache-2.0" + + +[dependencies] +game = { workspace = true } + +bevy = { workspace = true } +bevy_replicon = { workspace = true, features = ["client"] } +bevy_replicon_renet2 = { workspace = true, features = ["wt_client_transport"] } +bevy_renet2 = { workspace = true } +renet2 = { workspace = true, features = ["wt_client_transport"] } + +serde = { workspace = true } +bincode = "1.3" +base64 = { version = "0.22" } +url = "2.5" +wasm-timer = { version = "0.2" } diff --git a/plugins/client/src/lib.rs b/plugins/client/src/lib.rs new file mode 100644 index 0000000..5951aa6 --- /dev/null +++ b/plugins/client/src/lib.rs @@ -0,0 +1,66 @@ +use bevy::{ + ecs::world::Command, + prelude::{App, Commands, Plugin, Startup, World}, +}; + +use bevy_replicon::prelude::RepliconChannels; +use bevy_replicon_renet2::{ + renet2::{ConnectionConfig, RenetClient}, + RenetChannelsExt, +}; + +mod transport; + +pub struct ClientPlugin { + pub server_origin: String, + pub server_port: String, + pub server_token: String, +} + +impl Plugin for ClientPlugin { + fn build(&self, app: &mut App) { + #[cfg(target_family = "wasm")] + app.add_plugins(transport::ClientTransportPlugin::new( + &self.server_origin, + &self.server_port, + &self.server_token, + )); + app.add_systems(Startup, |mut commands: Commands| { + commands.add(ClientCommand::Connect); + }); + } +} + +pub enum ClientCommand { + Connect, + Disconnect, +} + +impl Command for ClientCommand { + fn apply(self, world: &mut World) { + match self { + ClientCommand::Connect => { + connect_to_server(world); + } + ClientCommand::Disconnect => { + world.remove_resource::(); + } + } + } +} + +// TODO: turn this into a system once bevy_renet2 uses the run condition here +// https://github.com/UkoeHB/renet2/blob/main/bevy_renet2/src/lib.rs#L62 +fn connect_to_server(world: &mut World) { + let replicon_channels = world + .get_resource::() + .expect("replicon plugins to be added before transport plugins"); + let server_channels_config = replicon_channels.get_server_configs(); + let client_channels_config = replicon_channels.get_client_configs(); + let client = RenetClient::new(ConnectionConfig { + server_channels_config, + client_channels_config, + ..Default::default() + }); + world.insert_resource(client); +} diff --git a/plugins/client/src/transport.rs b/plugins/client/src/transport.rs new file mode 100644 index 0000000..977fd7c --- /dev/null +++ b/plugins/client/src/transport.rs @@ -0,0 +1,78 @@ +use std::net::SocketAddr; +use url::Url; + +use bevy::prelude::{App, Plugin}; +use renet2::transport::WebServerDestination; + +use game::PROTOCOL_ID; + +pub struct ClientTransportPlugin { + server_address: WebServerDestination, + server_token: String, +} + +impl ClientTransportPlugin { + pub fn new(host: &str, port: &str, server_token: &str) -> Self { + Self::ip(host, port, server_token) + // .or_else(|| Self::url(host, port, server_token)) + .unwrap() + } + + fn url(host: &str, port: &str, server_token: &str) -> Option { + format!("{host}:{port}") + .parse::() + .map(|url| Self { + server_address: WebServerDestination::Url(url), + server_token: server_token.to_string(), + }) + .ok() + } + + fn ip(ip: &str, port: &str, server_token: &str) -> Option { + format!("{ip}:{port}") + .parse::() + .map(|addr| Self { + server_address: WebServerDestination::Addr(addr), + server_token: server_token.to_string(), + }) + .ok() + } +} + +#[cfg(target_family = "wasm")] +impl Plugin for ClientTransportPlugin { + fn build(&self, app: &mut App) { + use renet2::transport::{ClientAuthentication, NetcodeClientTransport}; + use wasm_timer::SystemTime; + + let server_addr: SocketAddr = self.server_address.clone().into(); + let current_time = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap(); + let client_id = current_time.as_millis() as u64; + let authentication = ClientAuthentication::Unsecure { + client_id, + protocol_id: PROTOCOL_ID, + socket_id: 0, + server_addr, + user_data: None, + }; + + // TODO: to support this at this layer we would need to pass the client socket in from above + // #[cfg(feature = "memory_transport")] + // let socket = renet2::transport::MemorySocketClient::new(client_id as u16, client_memory_socket).unwrap(); + use base64::Engine; + use renet2::transport::{ServerCertHash, WebTransportClientConfig}; + + let hash = base64::engine::general_purpose::STANDARD + .decode(self.server_token.clone()) + .unwrap(); + let config = WebTransportClientConfig::new_with_certs( + server_addr, + Vec::from([ServerCertHash::try_from(hash).unwrap()]), + ); + let socket = renet2::transport::WebTransportClient::new(config); + let transport = NetcodeClientTransport::new(current_time, authentication, socket).unwrap(); + app.insert_resource(transport); + } +} diff --git a/plugins/game/src/letters.rs b/plugins/game/src/letters.rs index 24ccd99..e43d04b 100644 --- a/plugins/game/src/letters.rs +++ b/plugins/game/src/letters.rs @@ -1,9 +1,9 @@ use serde::{Deserialize, Serialize}; -use bevy::prelude::{Component, KeyCode, Reflect}; +use bevy::prelude::{KeyCode, Reflect}; #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[derive(Component, Reflect)] +#[derive(Reflect)] #[derive(Deserialize, Serialize)] #[rustfmt::skip] diff --git a/plugins/game/src/lib.rs b/plugins/game/src/lib.rs index b7a5d5b..e8eb94e 100644 --- a/plugins/game/src/lib.rs +++ b/plugins/game/src/lib.rs @@ -14,11 +14,16 @@ pub use player::*; mod wordlist; pub use wordlist::*; +pub const PROTOCOL_ID: u64 = 1; + pub struct WordFightGamePlugin; impl Plugin for WordFightGamePlugin { fn build(&self, app: &mut App) { - app.add_plugins(RepliconPlugins); + app.add_plugins(RepliconPlugins.build().set(ServerPlugin { + visibility_policy: VisibilityPolicy::Whitelist, + ..Default::default() + })); // TODO: perhaps we only want to include this on server. // check whether it is currently "optimistic", if so, maybe we keep it @@ -38,6 +43,7 @@ impl Plugin for WordFightGamePlugin { .replicate::() .replicate::() .replicate::() + .replicate_mapped::() .replicate::() .replicate::() .replicate_mapped::(); @@ -140,40 +146,60 @@ impl MapEntities for ActionEvent { } } +#[derive(Clone, Debug)] +#[derive(Component, Deref, DerefMut, Reflect)] +#[derive(Deserialize, Serialize)] +pub struct InGame(Entity); + +impl MapEntities for InGame { + fn map_entities(&mut self, mapper: &mut M) { + self.0 = mapper.map_entity(self.0); + } +} + #[derive(Debug)] #[derive(Event)] pub struct SpawnGame { arena_size: usize, + client1: Entity, + client2: Entity, } impl SpawnGame { - pub fn new(arena_size: usize) -> Self { - Self { arena_size } + pub fn new(arena_size: usize, client1: Entity, client2: Entity) -> Self { + Self { + arena_size, + client1, + client2, + } } fn observer(trigger: Trigger, mut commands: Commands) { - eprintln!("Hello!"); let player_one = commands - .spawn(PlayerBundle { - client: ClientId::SERVER.into(), + .entity(trigger.event().client1) + .insert(PlayerBundle { side: PlayerSide::Left, word: Word::default(), score: Score::default(), }) .id(); let player_two = commands - .spawn(PlayerBundle { - client: ClientId::SERVER.into(), + .entity(trigger.event().client2) + .insert(PlayerBundle { side: PlayerSide::Right, word: Word::default(), score: Score::default(), }) .id(); - commands.spawn(GameBundle::new( - player_one, - player_two, - trigger.event().arena_size, - )); + let game = commands + .spawn(GameBundle::new( + player_one, + player_two, + trigger.event().arena_size, + )) + .id(); + commands.entity(player_one).insert(InGame(game)); + commands.entity(player_two).insert(InGame(game)); } } @@ -428,7 +454,10 @@ mod tests { let mut app = app(); let size = 7; - app.world_mut().trigger(SpawnGame::new(size)); + let client1 = app.world_mut().spawn(Client::from(ClientId::SERVER)).id(); + let client2 = app.world_mut().spawn(Client::from(ClientId::SERVER)).id(); + app.world_mut() + .trigger(SpawnGame::new(size, client1, client2)); // update to let spawns / etc flush app.update(); diff --git a/plugins/game/src/player.rs b/plugins/game/src/player.rs index 5e7d57e..ccbddf4 100644 --- a/plugins/game/src/player.rs +++ b/plugins/game/src/player.rs @@ -70,7 +70,6 @@ impl std::fmt::Display for Word { #[derive(Bundle)] pub struct PlayerBundle { - pub client: Client, pub side: PlayerSide, pub score: Score, pub word: Word, diff --git a/plugins/server/Cargo.toml b/plugins/server/Cargo.toml index 8ed9dc0..d9dacfb 100644 --- a/plugins/server/Cargo.toml +++ b/plugins/server/Cargo.toml @@ -2,8 +2,21 @@ name = "server" version = "0.1.0" edition = "2021" -authors = ["Sean Sullivan "] +license = "MIT OR Apache-2.0" [dependencies] game = { workspace = true } + bevy = { workspace = true } +bevy_replicon = { workspace = true, features = ["server"] } +bevy_replicon_renet2 = { workspace = true, features = ["wt_server_transport"] } +bevy_renet2 = { workspace = true } +renet2 = { workspace = true, features = ["wt_server_transport"] } + +serde = { workspace = true, features = ["derive"] } +bincode = "1.3" +base64 = { version = "0.22" } +url = "2.5" +warp = { version = "0.3", default-features = false } +tokio = { version = "1.32" } +fastrand = { version = "2.0" } diff --git a/plugins/server/src/lib.rs b/plugins/server/src/lib.rs index 13fa2ff..d0fb574 100644 --- a/plugins/server/src/lib.rs +++ b/plugins/server/src/lib.rs @@ -1,9 +1,146 @@ -use bevy::prelude::*; +use bevy::prelude::{ + App, Commands, Entity, EventReader, IntoSystemConfigs, Name, Plugin, Query, Res, ResMut, + Startup, Update, With, Without, +}; -pub struct WordFightServerPlugin; +use bevy_replicon::prelude::{ConnectedClients, Replicated, RepliconChannels, ServerEvent}; +use bevy_replicon_renet2::{ + renet2::{ConnectionConfig, RenetServer}, + RenetChannelsExt, +}; -impl Plugin for WordFightServerPlugin { +use game::{Client, InGame, SpawnGame}; + +mod transport; +use transport::*; + +pub struct ServerPlugin { + pub port: String, + pub wt_tokens_port: String, +} + +impl Plugin for ServerPlugin { fn build(&self, app: &mut App) { - unimplemented!("") + app.add_plugins(ServerTransportPlugin { + port: self.port.clone(), + wt_tokens_port: self.wt_tokens_port.clone(), + }); + app.add_systems(Startup, Self::start_server).add_systems( + Update, + ( + Self::handle_connections, + Self::matchmake, + Self::handle_visibility, + ) + .chain(), + ); + } +} + +impl ServerPlugin { + fn start_server(mut commands: Commands, replicon_channels: Res) { + let server_channels_config = replicon_channels.get_server_configs(); + let client_channels_config = replicon_channels.get_client_configs(); + + let server = RenetServer::new(ConnectionConfig { + server_channels_config, + client_channels_config, + ..Default::default() + }); + commands.insert_resource(server); + } + + fn matchmake(mut commands: Commands, clients: Query, Without)>) { + for [client1, client2] in clients + .iter() + .collect::>() + .chunks(2) + .map(|chunk| [chunk[0], chunk[1]]) + { + commands.trigger(SpawnGame::new(7, client1, client2)); + } + } + + fn handle_connections( + mut commands: Commands, + mut server_events: EventReader, + clients: Query<(Entity, &Client)>, + ) { + for event in server_events.read() { + match event { + ServerEvent::ClientConnected { client_id } => { + #[cfg(feature = "log")] + bevy_log::info!("Player {} connected.", client_id.get()); + // Spawn new player entity + commands.spawn(( + Replicated, + Name::new(format!("Player {}", client_id.get())), + Client::from(*client_id), + )); + } + ServerEvent::ClientDisconnected { client_id, reason } => { + if let Some((player_entity, _)) = + clients.iter().find(|(_, id)| ***id == *client_id) + { + #[cfg(feature = "log")] + bevy_log::debug!("Player disconnected: {}", reason); + commands.entity(player_entity).despawn(); + } + } + } + } + } + + pub fn handle_visibility( + players: Query<(Entity, &Client, Option<&InGame>)>, + game_entities: Query<(Entity, &InGame), Without>, + mut connected_clients: ResMut, + ) { + // let players have visibility over all entities present in the same game + for (entity, player, player_game) in players + .iter() + .filter_map(|(entity, player, in_game)| in_game.map(|game| (entity, player, game))) + { + let client = connected_clients.client_mut(**player); + let visibility = client.visibility_mut(); + // player can see themselves + visibility.set_visibility(entity, true); + // and the game instance + // TODO: turning this off when switching / ending games? + visibility.set_visibility(**player_game, true); + + // player can see other game entities + for (entity, in_game) in game_entities.iter() { + if **in_game == **player_game { + visibility.set_visibility(entity, true); + } else { + visibility.set_visibility(entity, false); + } + } + } + + // players also need to be able to see each other when either both in lobby, or both in the same game + for [(entity1, player1, in_game1), (entity2, player2, in_game2)] in + players.iter_combinations() + { + let visible = match (in_game1, in_game2) { + (None, None) => true, + (None, Some(_)) | (Some(_), None) => false, + (Some(game1), Some(game2)) => { + if **game1 == **game2 { + true + } else { + false + } + } + }; + let client1 = connected_clients.client_mut(**player1); + let visibility1 = client1.visibility_mut(); + visibility1.set_visibility(entity2, visible); + + let client2 = connected_clients.client_mut(**player2); + let visibility2 = client2.visibility_mut(); + visibility2.set_visibility(entity1, visible); + } } } diff --git a/plugins/server/src/transport.rs b/plugins/server/src/transport.rs new file mode 100644 index 0000000..babb83c --- /dev/null +++ b/plugins/server/src/transport.rs @@ -0,0 +1,115 @@ +use std::net::SocketAddr; +use warp::Filter; + +use bevy::prelude::{App, Plugin, Resource}; + +use renet2::transport::WebServerDestination; + +use game::PROTOCOL_ID; + +pub struct ServerTransportPlugin { + pub port: String, + pub wt_tokens_port: String, +} + +impl Plugin for ServerTransportPlugin { + fn build(&self, app: &mut App) { + app.add_plugins(NativeServerTransportPlugin::ip( + "0.0.0.0", + self.port.as_str(), + self.wt_tokens_port.as_str(), + )); + } +} + +struct NativeServerTransportPlugin { + server_address: WebServerDestination, + tokens_address: WebServerDestination, +} + +impl NativeServerTransportPlugin { + fn url(host: &str, port: &str, tokens_port: &str) -> Self { + Self { + server_address: WebServerDestination::Url(format!("{host}:{port}").parse().unwrap()), + tokens_address: WebServerDestination::Url( + format!("{host}:{}", tokens_port.to_string()) + .parse() + .unwrap(), + ), + } + } + + fn ip(ip: &str, port: &str, tokens_port: &str) -> Self { + Self { + server_address: WebServerDestination::Addr(format!("{ip}:{port}").parse().unwrap()), + tokens_address: WebServerDestination::Addr( + format!("{ip}:{}", tokens_port.to_string()).parse().unwrap(), + ), + } + } +} + +impl Default for NativeServerTransportPlugin { + fn default() -> Self { + Self::ip("0.0.0.0", "7636", "7637") + } +} + +impl Plugin for NativeServerTransportPlugin { + fn build(&self, app: &mut App) { + use bevy_renet2::renet2::transport::{ + NetcodeServerTransport, ServerAuthentication, ServerSetupConfig, + }; + use std::time::SystemTime; + + let public_addr: SocketAddr = self.server_address.clone().into(); + + let current_time: std::time::Duration = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap(); + let server_config = ServerSetupConfig { + current_time, + max_clients: 64, + protocol_id: PROTOCOL_ID, + socket_addresses: vec![vec![public_addr]], + authentication: ServerAuthentication::Unsecure, + }; + + let socket = { + use base64::Engine; + + #[derive(Resource)] + pub struct TokioRuntime(#[allow(dead_code)] tokio::runtime::Runtime); + + println!("Opening WT Socket on {}", public_addr); + + let (config, cert_hash) = + renet2::transport::WebTransportServerConfig::new_selfsigned(public_addr, 4); + + let cert_hash_b64 = + base64::engine::general_purpose::STANDARD.encode(cert_hash.hash.as_ref()); + let certs_socket: SocketAddr = self.tokens_address.clone().into(); + + let runtime = tokio::runtime::Runtime::new().unwrap(); + runtime.spawn(async move { + let cors = warp::cors() + .allow_method("GET") + .allow_origin("http://localhost:8080") + .allow_origin("http://127.0.0.1:8080"); + let serve_certs = warp::path::end() + .map(move || cert_hash_b64.clone()) + .with(cors); + warp::serve(serve_certs).run(certs_socket).await; + }); + + let socket = + renet2::transport::WebTransportServer::new(config, runtime.handle().clone()) + .unwrap(); + app.insert_resource(TokioRuntime(runtime)); + socket + }; + + let transport = NetcodeServerTransport::new(server_config, socket).unwrap(); + app.insert_resource(transport); + } +} diff --git a/src/lib.rs b/src/lib.rs index 407c7d9..3af1d5c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,4 @@ -use bevy::{ - app::PluginGroupBuilder, - prelude::{App, Commands, Plugin, PluginGroup, Startup}, - DefaultPlugins, -}; +use bevy::{app::PluginGroupBuilder, prelude::PluginGroup, DefaultPlugins}; pub use active_game::*; pub use game::*; @@ -30,28 +26,28 @@ impl PluginGroup for WordFightPlugins { ..Default::default() }); let plugins = plugins.add_group(default_plugins); - let plugins = plugins - .add(WordFightGamePlugin) - .add(ActiveGamePlugin) - .add(StartupPlugin); - #[cfg(feature = "server")] - let plugins = plugins.add(WordFightServerPlugin); + let plugins = plugins.add(WordFightGamePlugin).add(ActiveGamePlugin); #[cfg(feature = "ui")] let plugins = plugins.add(WordFightUiPlugin); #[cfg(feature = "dev")] + let plugins = plugins.add(StartupPlugin); + #[cfg(feature = "dev")] let plugins = plugins.add(bevy_inspector_egui::quick::WorldInspectorPlugin::default()); plugins } } +#[cfg(feature = "dev")] pub struct StartupPlugin; +#[cfg(feature = "dev")] impl Plugin for StartupPlugin { fn build(&self, app: &mut App) { app.add_systems(Startup, Self::spawn_game); } } +#[cfg(feature = "dev")] impl StartupPlugin { fn spawn_game(mut commands: Commands) { commands.trigger(SpawnGame::new(7));