M Cargo.lock => Cargo.lock +1131 -12
@@ 86,6 86,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[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.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 226,6 236,45 @@ dependencies = [
]
[[package]]
+name = "asn1-rs"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7f43a50ac4fdca5df8e885c21b835997f0a1cdee65494a6847694a98652d9d8"
+dependencies = [
+ "asn1-rs-derive",
+ "asn1-rs-impl",
+ "displaydoc",
+ "nom",
+ "num-traits",
+ "rusticata-macros",
+ "thiserror 2.0.18",
+ "time",
+]
+
+[[package]]
+name = "asn1-rs-derive"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+ "synstructure",
+]
+
+[[package]]
+name = "asn1-rs-impl"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
name = "assert_type_match"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 389,6 438,34 @@ dependencies = [
]
[[package]]
+name = "aws-lc-rs"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ec2f1fc3ec205783a5da9a7e6c1509cc69dedf09a1949e412c1e18469326d00"
+dependencies = [
+ "aws-lc-sys",
+ "zeroize",
+]
+
+[[package]]
+name = "aws-lc-sys"
+version = "0.41.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a2f9779ce85b93ab6170dd940ad0169b5766ff848247aff13bb788b832fe3f4"
+dependencies = [
+ "cc",
+ "cmake",
+ "dunce",
+ "fs_extra",
+]
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
name = "bevy"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 463,7 540,7 @@ dependencies = [
"downcast-rs 2.0.2",
"log",
"thiserror 2.0.18",
- "variadics_please",
+ "variadics_please 1.1.0",
"wasm-bindgen",
"web-sys",
]
@@ 703,7 780,7 @@ dependencies = [
"smallvec",
"subsecond",
"thiserror 2.0.18",
- "variadics_please",
+ "variadics_please 1.1.0",
]
[[package]]
@@ 1023,7 1100,7 @@ dependencies = [
"rand_distr",
"serde",
"thiserror 2.0.18",
- "variadics_please",
+ "variadics_please 1.1.0",
]
[[package]]
@@ 1199,7 1276,7 @@ dependencies = [
"smol_str",
"thiserror 2.0.18",
"uuid",
- "variadics_please",
+ "variadics_please 1.1.0",
"wgpu-types",
]
@@ 1261,7 1338,7 @@ dependencies = [
"smallvec",
"thiserror 2.0.18",
"tracing",
- "variadics_please",
+ "variadics_please 1.1.0",
"wasm-bindgen",
"web-sys",
"wgpu",
@@ 1280,10 1357,23 @@ dependencies = [
]
[[package]]
+name = "bevy_renet2"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76cbba6aff2d461ccce2bb3a62fa328a2f39aeb6d61a37750c098396b7a6c242"
+dependencies = [
+ "bevy_app",
+ "bevy_ecs",
+ "bevy_time",
+ "renet2",
+ "renet2_netcode",
+]
+
+[[package]]
name = "bevy_replicon"
-version = "0.39.5"
+version = "0.40.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a0d6f7d37938f1f6797950774a41adc189a459d73cffb1941804a5d9d8fd059"
+checksum = "6112b46715b14666a32ed1e39fb8074f2126936c77e829c9d24c2199dd12a8d0"
dependencies = [
"bevy",
"bitflags 2.11.1",
@@ 1296,11 1386,22 @@ dependencies = [
"serde",
"smallbitvec",
"typeid",
- "variadics_please",
+ "variadics_please 2.0.0",
"xxhash-rust",
]
[[package]]
+name = "bevy_replicon_renet2"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddc45af0d5e0d365b1600b0ba2a3e57c9b2180618915afb74a7f1c7524ce90e6"
+dependencies = [
+ "bevy",
+ "bevy_renet2",
+ "bevy_replicon",
+]
+
+[[package]]
name = "bevy_scene"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 1409,7 1510,7 @@ dependencies = [
"bevy_state_macros",
"bevy_utils",
"log",
- "variadics_please",
+ "variadics_please 1.1.0",
]
[[package]]
@@ 1861,6 1962,17 @@ 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 0.2.17",
+]
+
+[[package]]
+name = "chacha20"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601"
@@ 1871,6 1983,19 @@ dependencies = [
]
[[package]]
+name = "chacha20poly1305"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
+dependencies = [
+ "aead",
+ "chacha20 0.9.1",
+ "cipher",
+ "poly1305",
+ "zeroize",
+]
+
+[[package]]
name = "chiapos-chacha8"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 1907,6 2032,17 @@ dependencies = [
]
[[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 = "clap"
version = "4.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 1952,6 2088,15 @@ dependencies = [
]
[[package]]
+name = "cmake"
+version = "0.1.58"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678"
+dependencies = [
+ "cc",
+]
+
+[[package]]
name = "cobs"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 2240,6 2385,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
[[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.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 2295,6 2453,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
dependencies = [
"generic-array",
+ "rand_core 0.6.4",
"typenum",
]
@@ 2357,6 2516,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8"
[[package]]
+name = "der-parser"
+version = "10.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6"
+dependencies = [
+ "asn1-rs",
+ "displaydoc",
+ "nom",
+ "num-bigint",
+ "num-traits",
+ "rusticata-macros",
+]
+
+[[package]]
+name = "deranged"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
+dependencies = [
+ "powerfmt",
+]
+
+[[package]]
name = "derive_builder"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 2524,6 2706,17 @@ dependencies = [
]
[[package]]
+name = "displaydoc"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
name = "disqualified"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 2566,6 2759,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
[[package]]
+name = "dunce"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
+
+[[package]]
name = "dyn-clone"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 2842,6 3041,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
[[package]]
+name = "form_urlencoded"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "fragile"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8878864ba14bb86e818a412bfd6f18f9eabd4ec0f008a28e8f7eb61db532fcf9"
+dependencies = [
+ "futures-core",
+]
+
+[[package]]
+name = "fs_extra"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
+
+[[package]]
name = "fsevent-sys"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 2851,12 3074,28 @@ dependencies = [
]
[[package]]
+name = "futures"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
name = "futures-channel"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
dependencies = [
"futures-core",
+ "futures-sink",
]
[[package]]
@@ 2866,6 3105,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
[[package]]
+name = "futures-executor"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
name = "futures-io"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 2896,6 3146,12 @@ dependencies = [
]
[[package]]
+name = "futures-sink"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
+
+[[package]]
name = "futures-task"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 2907,9 3163,13 @@ version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
dependencies = [
+ "futures-channel",
"futures-core",
+ "futures-io",
"futures-macro",
+ "futures-sink",
"futures-task",
+ "memchr",
"pin-project-lite",
"slab",
]
@@ 2946,14 3206,29 @@ dependencies = [
[[package]]
name = "getrandom"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "wasi",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "getrandom"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
dependencies = [
"cfg-if",
+ "js-sys",
"libc",
"r-efi 5.3.0",
"wasip2",
+ "wasm-bindgen",
]
[[package]]
@@ 3266,6 3541,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
[[package]]
+name = "hmac-sha256"
+version = "1.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec9d92d097f4749b64e8cc33d924d9f40a2d4eb91402b458014b781f5733d60f"
+
+[[package]]
+name = "httlib-huffman"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a9fcbcc408c5526c3ab80d534e5c86e7967c1fb7aa0a8c76abd1edc27deb877"
+
+[[package]]
name = "http"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 3282,6 3569,88 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
[[package]]
+name = "icu_collections"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c"
+dependencies = [
+ "displaydoc",
+ "potential_utf",
+ "utf8_iter",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locale_core"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4"
+dependencies = [
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38"
+
+[[package]]
+name = "icu_properties"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de"
+dependencies = [
+ "icu_collections",
+ "icu_locale_core",
+ "icu_properties_data",
+ "icu_provider",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14"
+
+[[package]]
+name = "icu_provider"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421"
+dependencies = [
+ "displaydoc",
+ "icu_locale_core",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
name = "id-arena"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 3294,6 3663,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
+name = "idna"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
+dependencies = [
+ "idna_adapter",
+ "smallvec",
+ "utf8_iter",
+]
+
+[[package]]
+name = "idna_adapter"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714"
+dependencies = [
+ "icu_normalizer",
+ "icu_properties",
+]
+
+[[package]]
name = "image"
version = "0.25.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 3339,6 3729,15 @@ dependencies = [
]
[[package]]
+name = "inout"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
name = "inventory"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 3642,6 4041,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
[[package]]
+name = "litemap"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
+
+[[package]]
name = "litrs"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 3669,8 4074,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3bd0dd2cd90571056fdb71f6275fada10131182f84899f4b2a916e565d81d86"
[[package]]
-name = "malloc_buf"
-version = "0.0.6"
+name = "lru-slab"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
+
+[[package]]
+name = "malloc_buf"
+version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
dependencies = [
@@ 3726,6 4137,12 @@ dependencies = [
]
[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
name = "miniz_oxide"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 3758,6 4175,12 @@ dependencies = [
]
[[package]]
+name = "mutants"
+version = "0.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc0287524726960e07b119cebd01678f852f147742ae0d925e6a520dca956126"
+
+[[package]]
name = "naga"
version = "27.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 3862,6 4285,16 @@ dependencies = [
]
[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
name = "nonmax"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 3917,6 4350,16 @@ dependencies = [
]
[[package]]
+name = "num-bigint"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
+dependencies = [
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
name = "num-complex"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 3926,6 4369,12 @@ dependencies = [
]
[[package]]
+name = "num-conv"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
+
+[[package]]
name = "num-derive"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 3937,6 4386,15 @@ dependencies = [
]
[[package]]
+name = "num-integer"
+version = "0.1.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 4224,6 4682,12 @@ dependencies = [
]
[[package]]
+name = "octets"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8311fa8ab7a57759b4ff1f851a3048d9ef0effaa0130726426b742d26d8a88e7"
+
+[[package]]
name = "offset-allocator"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 4234,6 4698,15 @@ dependencies = [
]
[[package]]
+name = "oid-registry"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7"
+dependencies = [
+ "asn1-rs",
+]
+
+[[package]]
name = "once_cell"
version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 4246,6 4719,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
[[package]]
+name = "opaque-debug"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
+
+[[package]]
+name = "openssl-probe"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
+
+[[package]]
name = "orbclient"
version = "0.3.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 4375,6 4860,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
+name = "pem"
+version = "3.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be"
+dependencies = [
+ "base64",
+ "serde_core",
+]
+
+[[package]]
name = "percent-encoding"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 4503,6 4998,17 @@ dependencies = [
]
[[package]]
+name = "poly1305"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
+dependencies = [
+ "cpufeatures 0.2.17",
+ "opaque-debug",
+ "universal-hash",
+]
+
+[[package]]
name = "portable-atomic"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 4540,6 5046,21 @@ dependencies = [
]
[[package]]
+name = "potential_utf"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564"
+dependencies = [
+ "zerovec",
+]
+
+[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 4644,6 5165,61 @@ dependencies = [
]
[[package]]
+name = "quinn"
+version = "0.11.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20"
+dependencies = [
+ "bytes",
+ "cfg_aliases",
+ "pin-project-lite",
+ "quinn-proto",
+ "quinn-udp",
+ "rustc-hash 2.1.2",
+ "rustls",
+ "socket2 0.6.4",
+ "thiserror 2.0.18",
+ "tokio",
+ "tracing",
+ "web-time 1.1.0",
+]
+
+[[package]]
+name = "quinn-proto"
+version = "0.11.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098"
+dependencies = [
+ "bytes",
+ "getrandom 0.3.4",
+ "lru-slab",
+ "rand 0.9.4",
+ "ring",
+ "rustc-hash 2.1.2",
+ "rustls",
+ "rustls-pki-types",
+ "slab",
+ "thiserror 2.0.18",
+ "tinyvec",
+ "tracing",
+ "web-time 1.1.0",
+]
+
+[[package]]
+name = "quinn-udp"
+version = "0.5.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd"
+dependencies = [
+ "cfg_aliases",
+ "libc",
+ "once_cell",
+ "socket2 0.6.4",
+ "tracing",
+ "windows-sys 0.60.2",
+]
+
+[[package]]
name = "quote"
version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 4686,7 5262,7 @@ version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207"
dependencies = [
- "chacha20",
+ "chacha20 0.10.0",
"getrandom 0.4.2",
"rand_core 0.10.1",
]
@@ 4703,6 5279,15 @@ dependencies = [
[[package]]
name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom 0.2.17",
+]
+
+[[package]]
+name = "rand_core"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
@@ 4765,6 5350,19 @@ dependencies = [
]
[[package]]
+name = "rcgen"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2"
+dependencies = [
+ "pem",
+ "ring",
+ "rustls-pki-types",
+ "time",
+ "yasna",
+]
+
+[[package]]
name = "rdst"
version = "0.20.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 4868,6 5466,77 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
[[package]]
+name = "renet2"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "689381686b0760f174e973d038df220eec2834d64345c2b609212d40679dc274"
+dependencies = [
+ "bevy_ecs",
+ "bytes",
+ "log",
+ "octets",
+]
+
+[[package]]
+name = "renet2_netcode"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4bda5b3ebbfacba2976a9825dac8cd57efadc2a55a98fc334fb504fa714d1200"
+dependencies = [
+ "anyhow",
+ "async-channel",
+ "bevy_ecs",
+ "bytes",
+ "crossbeam",
+ "fragile",
+ "futures",
+ "hmac-sha256",
+ "http",
+ "js-sys",
+ "log",
+ "octets",
+ "quinn",
+ "rcgen",
+ "renet2",
+ "renetcode2",
+ "rustls",
+ "rustls-pki-types",
+ "send_wrapper",
+ "time",
+ "tokio",
+ "url",
+ "urlencoding",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "wtransport",
+]
+
+[[package]]
+name = "renetcode2"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b908e79c2c22d075bf4307a36f96bff3ebfedaba40b377d70b2c2e899e6a53c"
+dependencies = [
+ "chacha20poly1305",
+ "log",
+]
+
+[[package]]
+name = "ring"
+version = "0.17.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
+dependencies = [
+ "cc",
+ "cfg-if",
+ "getrandom 0.2.17",
+ "libc",
+ "untrusted",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
name = "robust"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 4915,6 5584,15 @@ dependencies = [
]
[[package]]
+name = "rusticata-macros"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632"
+dependencies = [
+ "nom",
+]
+
+[[package]]
name = "rustix"
version = "0.38.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 4941,6 5619,65 @@ dependencies = [
]
[[package]]
+name = "rustls"
+version = "0.23.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b"
+dependencies = [
+ "aws-lc-rs",
+ "log",
+ "once_cell",
+ "ring",
+ "rustls-pki-types",
+ "rustls-webpki",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-native-certs"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d"
+dependencies = [
+ "openssl-probe",
+ "rustls-pki-types",
+ "schannel",
+ "security-framework",
+]
+
+[[package]]
+name = "rustls-pemfile"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
+dependencies = [
+ "rustls-pki-types",
+]
+
+[[package]]
+name = "rustls-pki-types"
+version = "1.14.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9"
+dependencies = [
+ "web-time 1.1.0",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-webpki"
+version = "0.103.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e"
+dependencies = [
+ "aws-lc-rs",
+ "ring",
+ "rustls-pki-types",
+ "untrusted",
+]
+
+[[package]]
name = "rustversion"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 4974,6 5711,15 @@ dependencies = [
]
[[package]]
+name = "schannel"
+version = "0.1.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
name = "scoped-tls"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 4999,6 5745,29 @@ dependencies = [
]
[[package]]
+name = "security-framework"
+version = "3.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
+dependencies = [
+ "bitflags 2.11.1",
+ "core-foundation 0.10.1",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "2.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
name = "self_cell"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 5015,6 5784,9 @@ name = "send_wrapper"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
+dependencies = [
+ "futures-core",
+]
[[package]]
name = "serde"
@@ 5108,6 5880,17 @@ dependencies = [
]
[[package]]
+name = "sha2"
+version = "0.10.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
+dependencies = [
+ "cfg-if",
+ "cpufeatures 0.2.17",
+ "digest",
+]
+
+[[package]]
name = "sharded-slab"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 5123,6 5906,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
+name = "signal-hook-registry"
+version = "1.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
+dependencies = [
+ "errno",
+ "libc",
+]
+
+[[package]]
name = "simba"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 5244,6 6037,26 @@ dependencies = [
]
[[package]]
+name = "socket2"
+version = "0.5.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "socket2"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51"
+dependencies = [
+ "libc",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
name = "spade"
version = "2.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 5297,17 6110,24 @@ dependencies = [
"bevy",
"bevy_common_assets",
"bevy_replicon",
+ "bevy_replicon_renet2",
"console_error_panic_hook",
"ctrlc",
+ "getrandom 0.2.17",
"getrandom 0.4.2",
"good_lp",
"leafwing-input-manager",
"pico-args",
"rand 0.10.1",
"serde",
+ "serde_json",
+ "tokio",
"tracing-subscriber",
"tracing-web",
+ "url",
"wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
"web-time 1.1.0",
]
@@ 5358,6 6178,12 @@ dependencies = [
]
[[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.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 5397,6 6223,17 @@ dependencies = [
]
[[package]]
+name = "synstructure"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
name = "sys-locale"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 5508,6 6345,37 @@ dependencies = [
]
[[package]]
+name = "time"
+version = "0.3.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c"
+dependencies = [
+ "deranged",
+ "itoa",
+ "num-conv",
+ "powerfmt",
+ "serde_core",
+ "time-core",
+ "time-macros",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
+
+[[package]]
+name = "time-macros"
+version = "0.2.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215"
+dependencies = [
+ "num-conv",
+ "time-core",
+]
+
+[[package]]
name = "tiny-skia"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 5533,6 6401,16 @@ dependencies = [
]
[[package]]
+name = "tinystr"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
+dependencies = [
+ "displaydoc",
+ "zerovec",
+]
+
+[[package]]
name = "tinytemplate"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 5558,6 6436,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
+name = "tokio"
+version = "1.52.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe"
+dependencies = [
+ "bytes",
+ "libc",
+ "mio",
+ "parking_lot",
+ "pin-project-lite",
+ "signal-hook-registry",
+ "socket2 0.6.4",
+ "tokio-macros",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "2.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
name = "toml"
version = "0.9.12+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 5819,12 6725,63 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[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 = "unsynn"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "501a7adf1a4bd9951501e5c66621e972ef8874d787628b7f90e64f936ef7ec0a"
+dependencies = [
+ "mutants",
+ "proc-macro2",
+ "rustc-hash 2.1.2",
+]
+
+[[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.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+ "serde",
+]
+
+[[package]]
+name = "urlencoding"
+version = "2.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
+
+[[package]]
name = "utf-8"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
+name = "utf8_iter"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+
+[[package]]
name = "uuid"
version = "1.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 5854,6 6811,16 @@ dependencies = [
]
[[package]]
+name = "variadics_please"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b53d0f7f2d0182759a549f1f313ce16b07d8f9ba93098157b5fa10ee3e61117f"
+dependencies = [
+ "quote",
+ "unsynn",
+]
+
+[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 6919,6 7886,49 @@ dependencies = [
]
[[package]]
+name = "writeable"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
+
+[[package]]
+name = "wtransport"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e5e745c8789c20095c9061d292098d4106660efe2d172efd8ae7a369fe28e3e"
+dependencies = [
+ "bytes",
+ "pem",
+ "quinn",
+ "rcgen",
+ "rustls",
+ "rustls-native-certs",
+ "rustls-pemfile",
+ "rustls-pki-types",
+ "sha2",
+ "socket2 0.5.10",
+ "thiserror 2.0.18",
+ "time",
+ "tokio",
+ "tracing",
+ "url",
+ "wtransport-proto",
+ "x509-parser",
+]
+
+[[package]]
+name = "wtransport-proto"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a09d89a8dba201c2439d9d5eca55a0faa08909d69da50decdb5ec00be0ac504"
+dependencies = [
+ "httlib-huffman",
+ "octets",
+ "thiserror 2.0.18",
+ "url",
+]
+
+[[package]]
name = "x11-dl"
version = "2.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 6951,6 7961,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd"
[[package]]
+name = "x509-parser"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4569f339c0c402346d4a75a9e39cf8dad310e287eef1ff56d4c68e5067f53460"
+dependencies = [
+ "asn1-rs",
+ "data-encoding",
+ "der-parser",
+ "lazy_static",
+ "nom",
+ "oid-registry",
+ "rusticata-macros",
+ "thiserror 2.0.18",
+ "time",
+]
+
+[[package]]
name = "xcursor"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 6996,12 8023,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3"
[[package]]
+name = "yasna"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd"
+dependencies = [
+ "time",
+]
+
+[[package]]
name = "yazi"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e01738255b5a16e78bbb83e7fbba0a1e7dd506905cfc53f4622d89015a03fbb5"
[[package]]
+name = "yoke"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5"
+dependencies = [
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+ "synstructure",
+]
+
+[[package]]
name = "zeno"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 7028,6 8087,66 @@ dependencies = [
]
[[package]]
+name = "zerofrom"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+ "synstructure",
+]
+
+[[package]]
+name = "zeroize"
+version = "1.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
+
+[[package]]
+name = "zerotrie"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+]
+
+[[package]]
+name = "zerovec"
+version = "0.11.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
+dependencies = [
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
name = "zmij"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
M Cargo.toml => Cargo.toml +6 -5
@@ 62,11 62,12 @@ console_error_panic_hook = "0.1"
test_each_file = "0.3.7"
colored = "3"
qsv-tabwriter = "2"
-aeronet = { version = "0.20" }
-aeronet_websocket = { version = "0.20" }
-aeronet_transport = { version = "0.20" }
-aeronet_replicon = { version = "0.20" }
-bevy_replicon = { version = "0.39"}
+bevy_replicon = { version = "0.40" }
+bevy_replicon_renet2 = { version = "0.17", default-features = false }
+url = "2"
+serde_json = "1"
+web-sys = "0.3"
+wasm-bindgen-futures = "0.4"
[profile.dev]
opt-level = 1
M crates/unified/Cargo.toml => crates/unified/Cargo.toml +12 -2
@@ 18,14 18,21 @@ leafwing-input-manager = { workspace = true }
good_lp = { workspace = true }
web-time = { workspace = true }
bevy_replicon = { workspace = true, features = ["client"] }
+bevy_replicon_renet2 = { workspace = true, features = ["client", "netcode"] }
+url = { workspace = true }
+serde_json = { workspace = true }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
ctrlc = { workspace = true }
+tokio = { version = "1", features = ["rt-multi-thread"] }
[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = { workspace = true }
+wasm-bindgen-futures = { workspace = true }
tracing-web = { workspace = true }
console_error_panic_hook = { workspace = true }
+getrandom02 = { package = "getrandom", version = "0.2", features = ["js"] }
+web-sys = { workspace = true, features = ["Window", "Response"] }
[features]
native_dev = [
@@ 37,6 44,9 @@ native_dev = [
native = [
"bevy/x11",
"bevy/wayland",
- "bevy_replicon/server"
+ "bevy_replicon/server",
+ "bevy_replicon_renet2/server",
+ "bevy_replicon_renet2/native_transport",
+ "bevy_replicon_renet2/wt_server_transport"
]
-wasm = ["getrandom/wasm_js", "bevy/webgl2"]
+wasm = ["getrandom/wasm_js", "bevy/webgl2", "bevy_replicon_renet2/wt_client_transport"]
M crates/unified/assets/config/world.wc.toml => crates/unified/assets/config/world.wc.toml +1 -0
@@ 4,6 4,7 @@ gravity = 500.0
gravity_iterations = 8
spawn_parts_at = "Earth"
spawn_parts_interval_secs = 1
+orbit_scale_factor = 4.0
[part]
default_height = 50
M crates/unified/src/cli.rs => crates/unified/src/cli.rs +11 -5
@@ 9,7 9,9 @@ pub enum StkArgs {
},
#[cfg(not(target_arch = "wasm32"))]
Server {
- bind_to: std::net::SocketAddr,
+ management_bind: std::net::SocketAddr,
+ native_bind: std::net::SocketAddr,
+ wt_bind: std::net::SocketAddr,
with_client: bool
},
}
@@ 43,7 45,9 @@ pub fn parse_args() -> StkArgs {
#[cfg(not(target_arch = "wasm32"))]
"server" => {
StkArgs::Server {
- bind_to: pargs.value_from_str(["-b", "--bind-to"]).unwrap(),
+ management_bind: pargs.value_from_str("--management-bind").unwrap(),
+ native_bind: pargs.value_from_str("--native-bind").unwrap(),
+ wt_bind: pargs.value_from_str("--wt-bind").unwrap(),
with_client: pargs.contains("--with-client"),
}
},
@@ 77,13 81,15 @@ SUBCOMMANDS:
println!("\
CLIENT:
- -s, --server <URL> WebSocket URL to connect to
+ -s, --server <URL> Connection string of the server's management port (e.g. http://127.0.0.1:5150/)
");
if cfg!(not(target_arch = "wasm32")) {
print!("\
SERVER:
- -b, --bind-to <IP:PORT> Socket address to bind to
- --with-client Start a client connected to this server
+ --management-bind <IP:PORT> Socket address to bind the management port to
+ --native-bind <IP:PORT> Socket address to bind the native (UDP) port to
+ --wt-bind <IP:PORT> Socket address to bind the WebTransport port to
+ --with-client Start a client connected to this server
\n");
}
}=
\ No newline at end of file
A crates/unified/src/client/interpolation.rs => crates/unified/src/client/interpolation.rs +69 -0
@@ 0,0 1,69 @@
+use std::time::Duration;
+use bevy_replicon::client::confirm_history::ConfirmHistory;
+use bevy_replicon::prelude::RepliconTick;
+use web_time::Instant;
+use crate::prelude::*;
+use crate::shared::plugins::TICK_RATE;
+
+const MAX_INTERPOLATION_DURATION: Duration = Duration::from_millis(500);
+
+#[derive(Component)]
+pub struct TransformInterpolation {
+ start: Transform,
+ end: Transform,
+ end_tick: RepliconTick,
+ duration: Duration,
+ end_received_at: Instant,
+}
+
+impl TransformInterpolation {
+ pub fn new(transform: Transform, tick: RepliconTick) -> Self {
+ Self {
+ start: transform,
+ end: transform,
+ end_tick: tick,
+ duration: Duration::ZERO,
+ end_received_at: Instant::now(),
+ }
+ }
+}
+
+pub fn transform_interpolation_plugin(app: &mut App) {
+ app.add_systems(Update, (record_transform_changes, apply_transform_interpolation).chain());
+}
+
+// must run before `apply_transform_interpolation`
+fn record_transform_changes(
+ mut entities: Query<(&Transform, &ConfirmHistory, &mut TransformInterpolation), Changed<Transform>>,
+) {
+ let now = Instant::now();
+ for (transform, confirm_history, mut interpolation) in &mut entities {
+ let tick = confirm_history.last_tick();
+ let tick_delta = tick - interpolation.end_tick;
+ let duration = Duration::from_secs_f64(tick_delta as f64 / TICK_RATE).min(MAX_INTERPOLATION_DURATION);
+
+ interpolation.start = interpolation.end;
+ interpolation.end = *transform;
+ interpolation.end_tick = tick;
+ interpolation.duration = duration;
+ interpolation.end_received_at = now;
+ }
+}
+
+fn apply_transform_interpolation(mut entities: Query<(&mut Transform, &TransformInterpolation)>) {
+ let now = Instant::now();
+ for (mut transform, interpolation) in &mut entities {
+ let t = if interpolation.duration > Duration::ZERO {
+ (now.duration_since(interpolation.end_received_at).as_secs_f64() / interpolation.duration.as_secs_f64())
+ .clamp(0.0, 1.0) as f32
+ } else {
+ 1.0
+ };
+
+ *transform.bypass_change_detection() = Transform {
+ translation: interpolation.start.translation.lerp(interpolation.end.translation, t),
+ rotation: interpolation.start.rotation.slerp(interpolation.end.rotation, t),
+ scale: interpolation.start.scale.lerp(interpolation.end.scale, t),
+ };
+ }
+}
M crates/unified/src/client/mod.rs => crates/unified/src/client/mod.rs +162 -48
@@ 15,11 15,37 @@ use planet::incoming_planets::incoming_planets_plugin;
use crate::client::components::Me;
use crate::client::ship::attachment::client_attachment_plugin;
use crate::shared::ecs::{GameplayState, TimeOffset};
-use crate::shared::gravity::update_gravity;
-use crate::shared::net::Hi;
-use crate::shared::orbit::OrbitPlugin;
+use crate::shared::net::{parse_management_address, ManagementInfo, Hi, STARKINGDOMS_PROTOCOL_MAGIC};
+use bevy_replicon::prelude::RepliconChannels;
+use bevy_replicon_renet2::RenetChannelsExt;
+use bevy_replicon_renet2::netcode::{ClientAuthentication, NetcodeClientTransport};
+use bevy_replicon_renet2::renet2::{ConnectionConfig, RenetClient};
+use std::net::{IpAddr, SocketAddr};
+use web_time::SystemTime;
+
+#[cfg(not(target_arch = "wasm32"))]
+use bevy_replicon_renet2::netcode::NativeSocket;
+#[cfg(not(target_arch = "wasm32"))]
+use std::io::{Read, Write};
+#[cfg(not(target_arch = "wasm32"))]
+use std::net::{TcpStream, UdpSocket};
+
+#[cfg(target_arch = "wasm32")]
+use bevy_replicon_renet2::netcode::{ServerCertHash, WebServerDestination, WebTransportClient, WebTransportClientConfig};
+#[cfg(target_arch = "wasm32")]
+use crate::shared::net::decode_cert_hash;
+#[cfg(target_arch = "wasm32")]
+use std::cell::RefCell;
+#[cfg(target_arch = "wasm32")]
+use std::rc::Rc;
+#[cfg(target_arch = "wasm32")]
+use wasm_bindgen::JsCast;
+#[cfg(target_arch = "wasm32")]
+use wasm_bindgen_futures::JsFuture;
+use crate::shared::config::planet::Planet;
pub mod colors;
+pub mod interpolation;
pub mod key_input;
pub mod parts;
pub mod planet;
@@ 43,12 69,11 @@ impl Plugin for ClientPlugin {
app
.init_gizmo_group::<StarguideGizmos>()
.add_plugins(rendering::render_plugin)
- .add_plugins(OrbitPlugin)
- .add_systems(FixedUpdate, update_gravity.before(PhysicsSystems::Prepare))
.add_plugins(input::input_plugin)
.add_plugins(ship::thrusters::client_thrusters_plugin)
.add_plugins((incoming_planets_plugin, indicators_plugin))
.add_plugins(parts_plugin)
+ .add_plugins(interpolation::transform_interpolation_plugin)
.add_plugins(key_input_plugin)
.add_plugins(starfield_plugin)
.add_plugins(ui_plugin)
@@ 56,7 81,7 @@ impl Plugin for ClientPlugin {
.add_plugins(client_attachment_plugin)
.add_plugins(starguide_init_plugin)
.add_plugins(starguide_input_plugin)
- .add_plugins(starguide_orbit_plugin)
+ //.add_plugins(starguide_orbit_plugin)
.add_plugins(crafting_ui_plugin)
.add_systems(Update, find_me)
.insert_state(GameplayState::Main)
@@ 64,56 89,145 @@ impl Plugin for ClientPlugin {
.insert_resource(TimeOffset::default());
let server = self.server.clone();
- app.add_systems(PostStartup, move |mut commands: Commands| {
- /*#[cfg(target_arch = "wasm32")]
- let config = ClientConfig {};
- #[cfg(not(target_arch = "wasm32"))]
- let config = ClientConfig::builder().with_no_cert_validation();
+
+ #[cfg(not(target_arch = "wasm32"))]
+ app.add_systems(PostStartup, move |mut commands: Commands, channels: Res<RepliconChannels>| {
let Some(server) = server.as_ref() else { return };
- commands.spawn((Name::new("default-session"), TransportConfig { max_memory_usage: 536_870_912, ..default() }, AeronetRepliconClient))
- .queue(
- WebSocketClient::connect(config, server.clone()));*/
+ let management_addr = parse_management_address(server).expect("invalid server connection string");
+ let info = fetch_management_info(management_addr);
+
+ let (client, transport) = build_client(&channels, management_addr.ip(), &info);
+ commands.insert_resource(client);
+ commands.insert_resource(transport);
});
- /*
- if self.server.is_some() {
- app.add_observer(on_connecting);
- app.add_observer(on_connected);
- app.add_observer(on_disconnected);
- }*/
+
+ #[cfg(target_arch = "wasm32")]
+ {
+ app.add_systems(PostStartup, move || {
+ let Some(server) = server.as_ref() else { return };
+ let management_addr = parse_management_address(server).expect("invalid server connection string");
+
+ let info = Rc::new(RefCell::new(None));
+ let info_handle = info.clone();
+ wasm_bindgen_futures::spawn_local(async move {
+ *info_handle.borrow_mut() = Some(fetch_management_info(management_addr).await);
+ });
+
+ PENDING_SERVER_INFO.with(|pending| {
+ *pending.borrow_mut() = Some(PendingServerInfo { addr: management_addr, info });
+ });
+ });
+ app.add_systems(Update, connect_when_ready);
+ }
}
}
-/*
-pub fn on_connecting(
- trigger: On<Add, SessionEndpoint>,
- names: Query<&Name>,
- mut commands: Commands,
-) {
- let entity = trigger.event_target();
- let name = names.get(entity).unwrap();
- info!("{name} is connecting");
+
+fn build_client(channels: &RepliconChannels, host: IpAddr, info: &ManagementInfo) -> (RenetClient, NetcodeClientTransport) {
+ let connection_config = ConnectionConfig::from_channels(channels.server_configs(), channels.client_configs());
+ let client = RenetClient::new(connection_config, false);
+
+ let client_id = rand::random::<u64>();
+ let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
+
+ #[cfg(not(target_arch = "wasm32"))]
+ let (socket_id, server_addr, transport) = {
+ let bind_addr = if host.is_ipv6() { "[::]:0" } else { "0.0.0.0:0" };
+ let socket = NativeSocket::new(UdpSocket::bind(bind_addr).expect("failed to bind client UDP socket"))
+ .expect("failed to create native socket");
+ let socket_id = 0;
+ let server_addr = SocketAddr::new(host, info.native_port);
+ let authentication = ClientAuthentication::Unsecure {
+ protocol_id: STARKINGDOMS_PROTOCOL_MAGIC,
+ client_id,
+ socket_id,
+ server_addr,
+ user_data: None,
+ };
+ let transport = NetcodeClientTransport::new(current_time, authentication, socket)
+ .expect("failed to create client transport");
+ (socket_id, server_addr, transport)
+ };
+
+ #[cfg(target_arch = "wasm32")]
+ let (socket_id, server_addr, transport) = {
+ let server_addr = SocketAddr::new(host, info.wt_port);
+ let cert_hash = ServerCertHash { hash: decode_cert_hash(&info.cert_hash).expect("invalid cert_hash") };
+ let socket = WebTransportClient::new(WebTransportClientConfig::new_with_certs(
+ WebServerDestination::Addr(server_addr),
+ vec![cert_hash],
+ ));
+ let socket_id = 1;
+ let authentication = ClientAuthentication::Unsecure {
+ protocol_id: STARKINGDOMS_PROTOCOL_MAGIC,
+ client_id,
+ socket_id,
+ server_addr,
+ user_data: None,
+ };
+ let transport = NetcodeClientTransport::new(current_time, authentication, socket)
+ .expect("failed to create client transport");
+ (socket_id, server_addr, transport)
+ };
+
+ info!(?socket_id, ?server_addr, "connecting to server");
+ (client, transport)
}
-pub fn on_connected(trigger: On<Add, Session>, names: Query<&Name>) {
- let entity = trigger.event_target();
- let name = names.get(entity).unwrap();
- info!("{name} is connected");
+
+#[cfg(not(target_arch = "wasm32"))]
+fn fetch_management_info(addr: SocketAddr) -> ManagementInfo {
+ let mut stream = TcpStream::connect(addr).expect("failed to connect to management port");
+ stream.write_all(format!("GET / HTTP/1.1\r\nHost: {addr}\r\nConnection: close\r\n\r\n").as_bytes())
+ .expect("failed to send management request");
+
+ let mut response = Vec::new();
+ stream.read_to_end(&mut response).expect("failed to read management response");
+
+ let body_start = response.windows(4).position(|w| w == b"\r\n\r\n")
+ .map(|i| i + 4)
+ .expect("malformed management response");
+ serde_json::from_slice(&response[body_start..]).expect("invalid management response body")
}
-pub fn on_disconnected(trigger: On<Disconnected>, names: Query<&Name>) {
- let session = trigger.event_target();
- let name = names.get(session).unwrap();
- match &trigger.reason {
- DisconnectReason::ByUser(reason) => {
- info!(?name, ?reason, "session disconnected by user");
- }
- DisconnectReason::ByPeer(reason) => {
- info!(?name, ?reason, "session disconnected by peer");
- }
- DisconnectReason::ByError(err) => {
- warn!(?name, "session disconnected due to error: {err:?}");
- }
- }
-}*/
+#[cfg(target_arch = "wasm32")]
+async fn fetch_management_info(addr: SocketAddr) -> ManagementInfo {
+ let window = web_sys::window().expect("no window");
+ let response = JsFuture::from(window.fetch_with_str(&format!("http://{addr}/")))
+ .await
+ .expect("management fetch failed");
+ let response: web_sys::Response = response.dyn_into().expect("fetch did not return a Response");
+ let text = JsFuture::from(response.text().expect("failed to read response body"))
+ .await
+ .expect("failed to read response body");
+ let text = text.as_string().expect("response body was not a string");
+ serde_json::from_str(&text).expect("invalid management response body")
+}
+
+#[cfg(target_arch = "wasm32")]
+struct PendingServerInfo {
+ addr: SocketAddr,
+ info: Rc<RefCell<Option<ManagementInfo>>>,
+}
+
+#[cfg(target_arch = "wasm32")]
+thread_local! {
+ static PENDING_SERVER_INFO: RefCell<Option<PendingServerInfo>> = RefCell::new(None);
+}
+
+#[cfg(target_arch = "wasm32")]
+fn connect_when_ready(mut commands: Commands, channels: Res<RepliconChannels>) {
+ let ready = PENDING_SERVER_INFO.with(|pending| {
+ let mut pending = pending.borrow_mut();
+ let info = pending.as_ref()?.info.borrow_mut().take()?;
+ let addr = pending.take().unwrap().addr;
+ Some((addr, info))
+ });
+ let Some((addr, info)) = ready else { return };
+
+ let (client, transport) = build_client(&channels, addr.ip(), &info);
+ commands.insert_resource(client);
+ commands.insert_resource(transport);
+}
pub fn find_me(
mut msgs: MessageReader<Hi>,
M crates/unified/src/client/parts.rs => crates/unified/src/client/parts.rs +5 -2
@@ 8,8 8,10 @@ use crate::shared::ecs::{DragAction, DragRequestEvent, Part, MAIN_LAYER};
use crate::client::input::CursorWorldCoordinates;
use bevy::color::palettes::css::{ORANGE, PURPLE, RED, YELLOW};
use crate::client::components::Me;
+use crate::client::interpolation::TransformInterpolation;
use crate::client::ship::attachment::AttachmentDebugRes;
use crate::prelude::*;
+use bevy_replicon::client::confirm_history::ConfirmHistory;
pub fn parts_plugin(app: &mut App) {
app.insert_resource(DragResource { dragged: None });
@@ 48,16 50,17 @@ fn build_part_sprite(part: &Part, temperature: &Temperature, is_connected: bool,
fn handle_incoming_parts(
mut commands: Commands,
- new_parts: Query<(Entity, &Part, &Temperature, Option<&PartInShip>), Added<Part>>,
+ new_parts: Query<(Entity, &Part, &Temperature, Option<&PartInShip>, &Transform, &ConfirmHistory), Added<Part>>,
asset_server: Res<AssetServer>,
) {
- for (new_entity, new_part, temperature, is_connected) in new_parts.iter() {
+ for (new_entity, new_part, temperature, is_connected, transform, confirm_history) in new_parts.iter() {
let sprite = build_part_sprite(new_part, temperature, is_connected.is_some(), &asset_server);
commands
.entity(new_entity)
.insert(MAIN_LAYER)
.insert(sprite)
.insert(Pickable::default())
+ .insert(TransformInterpolation::new(*transform, confirm_history.last_tick()))
.observe(on_part_click)
.observe(open_crafting_ui);
}
M crates/unified/src/client/planet/incoming_planets.rs => crates/unified/src/client/planet/incoming_planets.rs +8 -34
@@ 1,12 1,11 @@
-use crate::shared::config::planet::{Planet, PlanetSpring, PlanetSpringJoint, SpecialSpriteProperties};
+use crate::client::interpolation::TransformInterpolation;
+use crate::shared::config::planet::{Planet, SpecialSpriteProperties};
use crate::prelude::*;
use crate::shared::ecs::{MAIN_STAR_LAYERS};
-
-const PLANET_SPRING_COMPLIANCE: f64 = 0.01;
-const PLANET_SPRING_DAMPING: f64 = 0.1;
+use bevy_replicon::client::confirm_history::ConfirmHistory;
pub fn incoming_planets_plugin(app: &mut App) {
- app.add_systems(Update, (handle_incoming_planets, handle_updated_planets, setup_planet_spring_joints));
+ app.add_systems(Update, (handle_incoming_planets, handle_updated_planets));
}
fn build_planet_sprite(planet: &Planet, asset_server: &AssetServer) -> Sprite {
@@ 20,13 19,14 @@ fn build_planet_sprite(planet: &Planet, asset_server: &AssetServer) -> Sprite {
fn handle_incoming_planets(
mut commands: Commands,
- new_planets: Query<(Entity, &Planet), Added<Planet>>,
+ new_planets: Query<(Entity, &Planet, &Transform, &ConfirmHistory), Added<Planet>>,
asset_server: Res<AssetServer>,
) {
- for (new_entity, new_planet) in new_planets.iter() {
+ for (new_entity, new_planet, transform, confirm_history) in new_planets.iter() {
commands.entity(new_entity)
.insert(MAIN_STAR_LAYERS.clone())
- .insert(build_planet_sprite(new_planet, &asset_server));
+ .insert(build_planet_sprite(new_planet, &asset_server))
+ .insert(TransformInterpolation::new(*transform, confirm_history.last_tick()));
trace!(?new_planet, "prepared new planet");
}
}
@@ 43,29 43,3 @@ fn handle_updated_planets(
trace!(?updated_planet, "updated planet");
}
}
-
-#[derive(Component)]
-struct SpringJointReady;
-
-fn setup_planet_spring_joints(
- unmatched_springs: Query<(Entity, &PlanetSpring), Without<SpringJointReady>>,
- planets: Query<(Entity, &Planet)>,
- mut commands: Commands,
-) {
- for (spring_entity, spring) in unmatched_springs.iter() {
- let Some((planet_entity, _)) = planets.iter().find(|(_, p)| p.name == spring.name) else {
- continue;
- };
- commands.entity(spring_entity).insert((
- RigidBody::Kinematic,
- LinearVelocity::default(),
- SpringJointReady,
- ));
- commands.spawn((
- PlanetSpringJoint { name: spring.name.clone() },
- FixedJoint::new(planet_entity, spring_entity)
- .with_point_compliance(PLANET_SPRING_COMPLIANCE),
- JointDamping { linear: PLANET_SPRING_DAMPING, angular: 1.0 },
- ));
- }
-}
M crates/unified/src/client/plugins.rs => crates/unified/src/client/plugins.rs +1 -0
@@ 33,6 33,7 @@ impl PluginGroup for ClientPluginGroup {
.add(InputManagerPlugin::<crate::client::input::ClientAction>::default())
.add(bevy_replicon::client::ClientPlugin)
.add(bevy_replicon::client::message::ClientMessagePlugin)
+ .add(bevy_replicon_renet2::client::RepliconRenetClientPlugin)
}
}
M crates/unified/src/server/gravity.rs => crates/unified/src/server/gravity.rs +50 -1
@@ 1,7 1,56 @@
use crate::prelude::*;
use crate::server::system_sets::WorldUpdateSet;
-use crate::shared::gravity::update_gravity;
+use crate::shared::config::planet::Planet;
+use crate::shared::ecs::Part;
+use crate::shared::world_config::WorldConfigResource;
pub fn newtonian_gravity_plugin(app: &mut App) {
app.add_systems(Update, update_gravity.in_set(WorldUpdateSet));
}
+
+fn update_gravity(
+ mut part_query: Query<(&Position, &LinearVelocity, &Mass, &mut ConstantForce), With<Part>>,
+ planet_query: Query<(&Position, &Mass), With<Planet>>,
+ world_config: Res<WorldConfigResource>,
+ time: Res<Time>,
+) {
+ let Some(world_config) = &world_config.config else {
+ return;
+ };
+
+ for (part_position, part_velocity, part_mass, mut forces) in &mut part_query {
+ *forces = ConstantForce::new(0.0, 0.0);
+
+ let part_mass = part_mass.0 as f64;
+ let part_pos = part_position.0;
+
+ for (planet_position, planet_mass) in &planet_query {
+ let planet_mass = planet_mass.0 as f64;
+ let planet_pos = planet_position.0;
+
+ let distance = planet_pos.distance(part_pos);
+
+ let mut x = 0.0;
+ let mut total_f = 0.0;
+ let mut v = part_velocity.0;
+ let dt = time.delta_secs() as f64 / world_config.world.gravity_iterations as f64;
+ for i in 0..world_config.world.gravity_iterations {
+ let f =
+ world_config.world.gravity * ((part_mass * planet_mass) / ((distance - x)*(distance - x)));
+ let dx = dt*(v.project_onto(planet_pos - part_pos)).length()
+ - 1.0/2.0*(f/part_mass)*(dt*dt);
+ x += dx;
+ v += f/part_mass*dt;
+ if i == 0 || i == world_config.world.gravity_iterations-1 {
+ total_f += f;
+ } else {
+ total_f += 2.0*f;
+ }
+ }
+ let force = (dt/2.0*(total_f))/time.delta_secs() as f64;
+ let direction = (planet_pos - part_pos).normalize() * force;
+ forces.x += direction.x;
+ forces.y += direction.y;
+ }
+ }
+}
A crates/unified/src/server/management.rs => crates/unified/src/server/management.rs +32 -0
@@ 0,0 1,32 @@
+use std::io::{Read, Write};
+use std::net::{SocketAddr, TcpListener};
+
+use crate::shared::net::ManagementInfo;
+
+pub fn spawn_management_server(bind: SocketAddr, info: ManagementInfo) {
+ let listener = TcpListener::bind(bind).expect("failed to bind management TCP socket");
+ let body = serde_json::to_string(&info).expect("failed to serialize management info");
+
+ std::thread::spawn(move || {
+ for stream in listener.incoming() {
+ let Ok(mut stream) = stream else { continue };
+ let body = body.clone();
+ std::thread::spawn(move || {
+ let mut buf = [0u8; 1024];
+ let _ = stream.read(&mut buf);
+
+ let response = format!(
+ "HTTP/1.1 200 OK\r\n\
+ Content-Type: application/json\r\n\
+ Access-Control-Allow-Origin: *\r\n\
+ Content-Length: {}\r\n\
+ Connection: close\r\n\
+ \r\n\
+ {body}",
+ body.len(),
+ );
+ let _ = stream.write_all(response.as_bytes());
+ });
+ }
+ });
+}
M crates/unified/src/server/mod.rs => crates/unified/src/server/mod.rs +72 -50
@@ 5,37 5,52 @@ mod heat;
mod drill;
mod craft;
mod damping;
+mod management;
pub mod planets;
pub mod player;
mod system_sets;
+mod priority;
pub mod orbit;
pub mod plugins;
pub mod components;
pub mod visibility;
-use std::net::SocketAddr;
-use bevy_replicon::prelude::Replicated;
+use std::net::{SocketAddr, UdpSocket};
+use bevy_replicon::prelude::{ConnectedClient, Replicated, RepliconChannels};
use bevy_replicon::server::AuthorizedClient;
+use bevy_replicon_renet2::RenetChannelsExt;
+use bevy_replicon_renet2::netcode::{
+ BoxedSocket, NativeSocket, NetcodeServerTransport, ServerAuthentication, ServerSetupConfig,
+ WebTransportServer, WebTransportServerConfig,
+};
+use bevy_replicon_renet2::renet2::{ConnectionConfig, RenetServer};
+use web_time::SystemTime;
use crate::server::craft::craft_plugin;
use crate::server::damping::damping_plugin;
use crate::server::drill::drill_plugin;
use crate::server::earth_parts::spawn_parts_plugin;
use crate::server::gravity::newtonian_gravity_plugin;
+use crate::server::management::spawn_management_server;
use crate::server::part::part_management_plugin;
+use crate::server::priority::replication_priority_plugin;
use crate::server::planets::planets_plugin;
use crate::server::player::player_management_plugin;
use crate::server::system_sets::{PlayerInputSet, WorldUpdateSet};
use crate::prelude::*;
use crate::server::orbit::OrbitPlugin;
use crate::server::player::thrust::server_thrust_plugin;
+use crate::shared::net::{encode_cert_hash, ManagementInfo, STARKINGDOMS_PROTOCOL_MAGIC};
+
+const MAX_CLIENTS: usize = 32;
pub struct ServerPlugin {
- pub bind: SocketAddr
+ pub management_bind: SocketAddr,
+ pub native_bind: SocketAddr,
+ pub wt_bind: SocketAddr,
}
impl Plugin for ServerPlugin {
fn build(&self, app: &mut App) {
- let bind = self.bind;
app
.add_plugins(planets_plugin)
.add_plugins(newtonian_gravity_plugin)
@@ 50,11 65,56 @@ impl Plugin for ServerPlugin {
.add_plugins(craft_plugin)
.add_plugins(OrbitPlugin)
.add_plugins(damping_plugin)
+ .add_plugins(replication_priority_plugin)
.configure_sets(Update, WorldUpdateSet.before(PlayerInputSet))
- .add_systems(Update, handle_authorized);
+ .add_systems(Update, handle_authorized)
+ .add_observer(on_client_disconnected);
+
+ let management_bind = self.management_bind;
+ let native_bind = self.native_bind;
+ let wt_bind = self.wt_bind;
+ app.add_systems(Startup, move |mut commands: Commands, channels: Res<RepliconChannels>| {
+ let connection_config = ConnectionConfig::from_channels(channels.server_configs(), channels.client_configs());
+ let server = RenetServer::new(connection_config);
+
+ let native_socket = NativeSocket::new(UdpSocket::bind(native_bind).expect("failed to bind server UDP socket"))
+ .expect("failed to create native socket");
+
+ let (wt_config, cert_hash) = WebTransportServerConfig::new_selfsigned(wt_bind, MAX_CLIENTS)
+ .expect("failed to create self-signed WebTransport server config");
+ let runtime = tokio::runtime::Runtime::new().expect("failed to create tokio runtime");
+ let wt_socket = WebTransportServer::new(wt_config, runtime.handle().clone())
+ .expect("failed to create WebTransport server socket");
+
+ let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
+ let server_config = ServerSetupConfig {
+ current_time,
+ max_clients: MAX_CLIENTS,
+ protocol_id: STARKINGDOMS_PROTOCOL_MAGIC,
+ socket_addresses: vec![vec![native_bind], vec![wt_bind]],
+ authentication: ServerAuthentication::Unsecure,
+ };
+ let transport = NetcodeServerTransport::new_with_sockets(server_config, vec![
+ BoxedSocket::new(native_socket),
+ BoxedSocket::new(wt_socket),
+ ]).expect("failed to create server transport");
+
+ spawn_management_server(management_bind, ManagementInfo {
+ native_port: native_bind.port(),
+ wt_port: wt_bind.port(),
+ cert_hash: encode_cert_hash(&cert_hash.hash),
+ });
+
+ commands.insert_resource(server);
+ commands.insert_resource(transport);
+ commands.insert_resource(TokioRuntime(runtime));
+ });
}
}
+#[derive(Resource)]
+struct TokioRuntime(tokio::runtime::Runtime);
+
#[derive(Component, Debug)]
pub struct ConnectedGameEntity {
pub network_entity: Entity,
@@ 64,27 124,6 @@ pub struct ConnectedNetworkEntity {
pub game_entity: Entity,
}
-/*
-fn on_opened(trigger: On<Add, Server>, servers: Query<&LocalAddr>) {
- let server = trigger.event_target();
- let local_addr = servers.get(server).unwrap();
- info!(server_entity=?server, "websocket server opened on {:?}", *local_addr);
-}
-
-fn on_connected(
- trigger: On<Add, Session>,
- clients: Query<&ChildOf>,
- sessions: Query<&Session>,
- mut commands: Commands,
-) {
- let client = trigger.event_target();
- let Ok(&ChildOf(server)) = clients.get(client) else {
- return;
- };
- info!(?client, ?server, "client connected");
-}
-*/
-
fn handle_authorized(
newly_authorized_clients: Query<Entity, Added<AuthorizedClient>>,
mut commands: Commands
@@ 104,34 143,17 @@ fn handle_authorized(
));
}
}
-/*
-fn on_disconnected(
- trigger: On<Disconnected>,
- clients: Query<&ChildOf>,
- player_entity: Query<&ConnectedNetworkEntity>,
+
+fn on_client_disconnected(
+ trigger: On<Remove, ConnectedClient>,
+ network_entities: Query<&ConnectedNetworkEntity>,
mut commands: Commands,
) {
let client = trigger.event_target();
- let Ok(&ChildOf(server)) = clients.get(client) else {
+ let Ok(connected) = network_entities.get(client) else {
return;
};
- match &trigger.reason {
- DisconnectReason::ByUser(reason) => {
- info!(?client, ?server, ?reason, "client disconnected by user");
- }
- DisconnectReason::ByPeer(reason) => {
- info!(?client, ?server, ?reason, "client disconnected by peer");
- }
- DisconnectReason::ByError(err) => {
- warn!(?client, ?server, "client disconnected with error: {err:?}");
- }
+ if let Ok(mut entity) = commands.get_entity(connected.game_entity) {
+ entity.despawn();
}
- let Ok(other_entity) = player_entity.get(client) else {
- return;
- };
- let Ok(mut commands) = commands.get_entity(other_entity.game_entity) else {
- return;
- };
- commands.despawn();
}
-*/>
\ No newline at end of file
M crates/unified/src/server/orbit/mod.rs => crates/unified/src/server/orbit/mod.rs +77 -1
@@ 1,1 1,77 @@
-pub use crate::shared::orbit::OrbitPlugin;
+use std::collections::HashMap;
+use std::f64::consts::PI;
+use avian2d::math::TAU;
+use avian2d::prelude::{LinearVelocity, Mass};
+use bevy::prelude::{App, Plugin, Transform, Update};
+use bevy::time::Time;
+use crate::shared::config::planet::{Planet, PlanetSpring};
+use crate::prelude::{Query, Res, Without};
+use crate::shared::ecs::TimeOffset;
+use crate::shared::world_config::WorldConfigResource;
+
+pub struct OrbitPlugin;
+impl Plugin for OrbitPlugin {
+ fn build(&self, app: &mut App) {
+ app.add_systems(Update, update_orbits);
+ }
+}
+
+fn update_orbits(
+ mut planets: Query<(&Planet, &Transform, &mut LinearVelocity), Without<PlanetSpring>>,
+ planets_2: Query<(&Planet, &Transform, &Mass), Without<PlanetSpring>>,
+ mut planet_springs: Query<(&PlanetSpring, &mut Transform, &mut LinearVelocity), Without<Planet>>,
+ world_config: Res<WorldConfigResource>,
+ time: Res<Time>,
+ time_offset: Res<TimeOffset>,
+) {
+ let Some(ref world_config) = world_config.config else {
+ return;
+ };
+ let parent_velocities = planets.iter().map(|u| (u.0.name.clone(), u.2.clone())).collect::<HashMap<String, LinearVelocity>>();
+ for (planet, _, _vel) in planets.iter_mut() {
+ let Some(orbit_data) = &planet.orbit else { continue; };
+ let Some(parent) = planets_2.iter().find(|u| u.0.name == orbit_data.orbiting) else { continue; };
+
+ let (parent_data, parent_transform, parent_mass) = parent;
+ let a = (planet.default_position.x as f64 - parent_data.default_position.x as f64) / (1.0 - orbit_data.eccentricity);
+ let e = orbit_data.eccentricity;
+ let t = world_config.world.orbit_scale_factor * 2.0*PI*((a*a*a)/(world_config.world.gravity*(**parent_mass as f64))).sqrt();
+
+ let time = time.elapsed_secs_f64() + time_offset.0;
+
+ let m = (TAU / t) * time;
+ let e_k = iterative_kepler(m, e);
+ let nu = 2.0_f64 * ((1.0 + e).sqrt() * (e_k / 2.0).sin())
+ .atan2((1.0 - e).sqrt() * (e_k / 2.0).cos());
+ let r = a * (1.0 - e * e_k.cos());
+
+ let x = r * nu.cos();
+ let y = r * nu.sin();
+
+ let Some(mut planet_spring) = planet_springs.iter_mut().find(|u| u.0.name == planet.name) else { continue; };
+ planet_spring.1.translation.x = x as f32 + parent_transform.translation.x;
+ planet_spring.1.translation.y = y as f32 + parent_transform.translation.y;
+
+ let Some(parent_velocity) = parent_velocities.get(&orbit_data.orbiting) else { continue; };
+ let de_dt = (TAU / t) / (1.0 - e * e_k.cos());
+ let b_factor = (1.0 - e * e).sqrt();
+ let vx = -a * e_k.sin() * de_dt;
+ let vy = a * b_factor * e_k.cos() * de_dt;
+ planet_spring.2.x = vx + parent_velocity.x;
+ planet_spring.2.y = vy + parent_velocity.y;
+ }
+}
+
+fn iterative_kepler(m: f64, e: f64) -> f64 {
+ const MAX_ITERATIONS: u32 = 100;
+ const CONVERGENCE_THRESHOLD: f64 = 1e-10;
+ let mut output = m;
+ for _ in 0..MAX_ITERATIONS {
+ let d = (m - output + e * output.sin()) / (1.0 - e * output.cos());
+ output += d;
+ if d.abs() < CONVERGENCE_THRESHOLD {
+ break;
+ }
+ }
+ output
+}
M crates/unified/src/server/planets.rs => crates/unified/src/server/planets.rs +1 -1
@@ 80,7 80,7 @@ pub fn update_planets(
let g = world_config.world.gravity * parent_planet.mass as f64
/ r.length_squared();
// tangential velocity
- let v = (g*r.length() as f64).sqrt();
+ let v = (1.0/world_config.world.orbit_scale_factor) * (g*r.length() as f64).sqrt();
let v_dir = DVec3::Z.cross(r).truncate().normalize();
let v = v_dir * v;
planet_entity.insert(LinearVelocity(v));
M crates/unified/src/server/player/join.rs => crates/unified/src/server/player/join.rs +2 -2
@@ 1,4 1,4 @@
-use bevy_replicon::prelude::{ClientId, SendMode, ToClients};
+use bevy_replicon::prelude::{ClientId, SendTargets, ToClients};
use crate::client::components::Me;
use crate::shared::config::planet::Planet;
use crate::shared::config::world::GlobalWorldConfig;
@@ 83,7 83,7 @@ pub fn handle_new_players(
for joined_player in &q_new_clients {
debug!(?joined_player, "new player!");
welcome_messages.write(ToClients {
- mode: SendMode::Direct(ClientId::Client(joined_player.1.network_entity)),
+ targets: SendTargets::Single(ClientId::Client(joined_player.1.network_entity)),
message: Hi {
you_are: joined_player.0,
time_offset: time.elapsed_secs_f64(),
M crates/unified/src/server/plugins.rs => crates/unified/src/server/plugins.rs +17 -1
@@ 1,7 1,10 @@
use std::time::Duration;
-use bevy::app::{PluginGroup, PluginGroupBuilder, ScheduleRunnerPlugin};
+use bevy::app::{App, PluginGroup, PluginGroupBuilder, ScheduleRunnerPlugin};
+use crate::prelude::*;
use crate::shared::plugins::TICK_RATE;
+const PHYSICS_LENGTH_UNIT: f64 = 100.0;
+
pub struct ServerPluginGroup;
impl PluginGroup for ServerPluginGroup {
@@ 10,5 13,18 @@ impl PluginGroup for ServerPluginGroup {
.add(ScheduleRunnerPlugin::run_loop(Duration::from_secs_f64(1.0 / TICK_RATE)))
.add(bevy_replicon::server::ServerPlugin::default())
.add(bevy_replicon::server::message::ServerMessagePlugin)
+ .add(bevy_replicon_renet2::server::RepliconRenetServerPlugin)
+ .add_group(
+ PhysicsPlugins::default()
+ .with_length_unit(PHYSICS_LENGTH_UNIT)
+ .set(PhysicsInterpolationPlugin::interpolate_all())
+ .build()
+ .disable::<IslandPlugin>()
+ )
+ .add(physics_setup_plugin)
}
}
+
+fn physics_setup_plugin(app: &mut App) {
+ app.insert_resource(Gravity::ZERO);
+}
A crates/unified/src/server/priority.rs => crates/unified/src/server/priority.rs +32 -0
@@ 0,0 1,32 @@
+use bevy_replicon::prelude::{AuthorizedClient, PriorityMap};
+use crate::prelude::*;
+use crate::server::ConnectedNetworkEntity;
+use crate::shared::attachment::Parts;
+use crate::shared::ecs::{Part, Player};
+
+const OTHER_SHIP_PART_PRIORITY: f32 = 0.25;
+
+pub fn replication_priority_plugin(app: &mut App) {
+ app.add_systems(Update, prioritize_own_ship_parts);
+}
+
+fn prioritize_own_ship_parts(
+ mut clients: Query<(&ConnectedNetworkEntity, &mut PriorityMap), With<AuthorizedClient>>,
+ hearties: Query<Option<&Parts>, With<Player>>,
+ parts: Query<Entity, With<Part>>,
+) {
+ for (connected, mut priority) in &mut clients {
+ let own_parts = hearties.get(connected.game_entity).ok().flatten();
+
+ for part in &parts {
+ let is_own = part == connected.game_entity
+ || own_parts.is_some_and(|owned| owned.contains(&part));
+
+ if is_own {
+ priority.remove(&part);
+ } else {
+ priority.insert(part, OTHER_SHIP_PART_PRIORITY);
+ }
+ }
+ }
+}
M crates/unified/src/shared/config/world.rs => crates/unified/src/shared/config/world.rs +1 -0
@@ 15,6 15,7 @@ pub struct WorldConfig {
pub gravity_iterations: usize,
pub spawn_parts_at: String,
pub spawn_parts_interval_secs: f32,
+ pub orbit_scale_factor: f64
}
#[derive(Deserialize, Asset, TypePath, Clone, Debug)]
D crates/unified/src/shared/gravity.rs => crates/unified/src/shared/gravity.rs +0 -51
@@ 1,51 0,0 @@
-use crate::shared::config::planet::Planet;
-use crate::shared::ecs::Part;
-use crate::prelude::*;
-use crate::shared::world_config::WorldConfigResource;
-
-pub fn update_gravity(
- mut part_query: Query<(&Position, &LinearVelocity, &Mass, &mut ConstantForce), With<Part>>,
- planet_query: Query<(&Position, &Mass), With<Planet>>,
- world_config: Res<WorldConfigResource>,
- time: Res<Time>,
-) {
- let Some(world_config) = &world_config.config else {
- return;
- };
-
- for (part_position, part_velocity, part_mass, mut forces) in &mut part_query {
- *forces = ConstantForce::new(0.0, 0.0);
-
- let part_mass = part_mass.0 as f64;
- let part_pos = part_position.0;
-
- for (planet_position, planet_mass) in &planet_query {
- let planet_mass = planet_mass.0 as f64;
- let planet_pos = planet_position.0;
-
- let distance = planet_pos.distance(part_pos);
-
- let mut x = 0.0;
- let mut total_f = 0.0;
- let mut v = part_velocity.0;
- let dt = time.delta_secs() as f64 / world_config.world.gravity_iterations as f64;
- for i in 0..world_config.world.gravity_iterations {
- let f =
- world_config.world.gravity * ((part_mass * planet_mass) / ((distance - x)*(distance - x)));
- let dx = dt*(v.project_onto(planet_pos - part_pos)).length()
- - 1.0/2.0*(f/part_mass)*(dt*dt);
- x += dx;
- v += f/part_mass*dt;
- if i == 0 || i == world_config.world.gravity_iterations-1 {
- total_f += f;
- } else {
- total_f += 2.0*f;
- }
- }
- let force = (dt/2.0*(total_f))/time.delta_secs() as f64;
- let direction = (planet_pos - part_pos).normalize() * force;
- forces.x += direction.x;
- forces.y += direction.y;
- }
- }
-}
M crates/unified/src/shared/mod.rs => crates/unified/src/shared/mod.rs +0 -2
@@ 1,7 1,5 @@
pub mod attachment;
pub mod config;
-pub mod gravity;
-pub mod orbit;
pub mod physics;
pub mod thrust;
pub mod world_config;
M crates/unified/src/shared/net.rs => crates/unified/src/shared/net.rs +44 -0
@@ 4,11 4,15 @@ use bevy::prelude::*;
use crate::prelude::{App, Message};
use bevy_replicon::prelude::*;
use serde::{Deserialize, Serialize};
+use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
+use url::{Host, Url};
use crate::shared::attachment::{Joint, JointOf, PartInShip, Peer, Ship, SnapOf, SnapOfJoint};
use crate::shared::config::planet::{Planet, PlanetSpring, PlanetSpringJoint};
use crate::shared::ecs::{CanCraft, Drill, Part, Player, PlayerStorage, SingleStorage, Temperature};
use crate::shared::ecs::thruster::{Thruster, ThrusterOfPart};
+pub const STARKINGDOMS_PROTOCOL_MAGIC: u64 = 0x5a5a_e37e_4aaa;
+
pub fn register_replication(app: &mut App) {
app
.add_mapped_server_message::<Hi>(Channel::Ordered)
@@ 53,3 57,43 @@ pub struct Hi {
pub you_are: Entity,
pub time_offset: f64,
}
+
+#[derive(Serialize, Deserialize)]
+pub struct ManagementInfo {
+ pub native_port: u16,
+ pub wt_port: u16,
+ pub cert_hash: String,
+}
+
+/// wasm is hard
+pub fn parse_management_address(s: &str) -> Result<SocketAddr, String> {
+ let url = Url::parse(s).map_err(|err| format!("invalid server URL: {err}"))?;
+
+ let ip = match url.host() {
+ Some(Host::Ipv4(ip)) => IpAddr::V4(ip),
+ Some(Host::Ipv6(ip)) => IpAddr::V6(ip),
+ Some(Host::Domain(domain)) => domain.parse::<IpAddr>()
+ .map_err(|_| format!("server host must be an IP address, got `{domain}`"))?,
+ None => return Err("server URL is missing a host".to_string()),
+ };
+ let port = url.port().ok_or("server URL is missing a port")?;
+
+ Ok(SocketAddr::new(ip, port))
+}
+
+pub fn encode_cert_hash(hash: &[u8; 32]) -> String {
+ hash.iter().map(|byte| format!("{byte:02x}")).collect()
+}
+
+pub fn decode_cert_hash(s: &str) -> Result<[u8; 32], String> {
+ if s.len() != 64 {
+ return Err(format!("cert_hash must be 64 hex chars, got {}", s.len()));
+ }
+
+ let mut hash = [0u8; 32];
+ for (byte, chunk) in hash.iter_mut().zip(s.as_bytes().chunks_exact(2)) {
+ let chunk = std::str::from_utf8(chunk).unwrap();
+ *byte = u8::from_str_radix(chunk, 16).map_err(|err| format!("invalid cert_hash: {err}"))?;
+ }
+ Ok(hash)
+}
D crates/unified/src/shared/orbit.rs => crates/unified/src/shared/orbit.rs +0 -78
@@ 1,78 0,0 @@
-use std::collections::HashMap;
-use std::f64::consts::PI;
-use avian2d::math::TAU;
-use avian2d::prelude::{LinearVelocity, Mass};
-use bevy::log::debug;
-use bevy::prelude::{App, Plugin, Transform, Update};
-use bevy::time::Time;
-use crate::shared::config::planet::{Planet, PlanetSpring};
-use crate::prelude::{Query, Res, Without};
-use crate::shared::ecs::TimeOffset;
-use crate::shared::world_config::WorldConfigResource;
-
-pub struct OrbitPlugin;
-impl Plugin for OrbitPlugin {
- fn build(&self, app: &mut App) {
- app.add_systems(Update, update_orbits);
- }
-}
-
-pub fn update_orbits(
- mut planets: Query<(&Planet, &Transform, &mut LinearVelocity), Without<PlanetSpring>>,
- planets_2: Query<(&Planet, &Transform, &Mass), Without<PlanetSpring>>,
- mut planet_springs: Query<(&PlanetSpring, &mut Transform, &mut LinearVelocity), Without<Planet>>,
- world_config: Res<WorldConfigResource>,
- time: Res<Time>,
- time_offset: Res<TimeOffset>,
-) {
- let Some(ref world_config) = world_config.config else {
- return;
- };
- let parent_velocities = planets.iter().map(|u| (u.0.name.clone(), u.2.clone())).collect::<HashMap<String, LinearVelocity>>();
- for (planet, _, _vel) in planets.iter_mut() {
- let Some(orbit_data) = &planet.orbit else { continue; };
- let Some(parent) = planets_2.iter().find(|u| u.0.name == orbit_data.orbiting) else { continue; };
-
- let (parent_data, parent_transform, parent_mass) = parent;
- let a = (planet.default_position.x as f64 - parent_data.default_position.x as f64) / (1.0 - orbit_data.eccentricity);
- let e = orbit_data.eccentricity;
- let t = 2.0*PI*((a*a*a)/(world_config.world.gravity*(**parent_mass as f64))).sqrt();
-
- let time = time.elapsed_secs_f64() + time_offset.0;
-
- let m = (TAU / t) * time;
- let e_k = iterative_kepler(m, e);
- let nu = 2.0_f64 * ((1.0 + e).sqrt() * (e_k / 2.0).sin())
- .atan2((1.0 - e).sqrt() * (e_k / 2.0).cos());
- let r = a * (1.0 - e * e_k.cos());
-
- let x = r * nu.cos();
- let y = r * nu.sin();
-
- let Some(mut planet_spring) = planet_springs.iter_mut().find(|u| u.0.name == planet.name) else { continue; };
- planet_spring.1.translation.x = x as f32 + parent_transform.translation.x;
- planet_spring.1.translation.y = y as f32 + parent_transform.translation.y;
-
- let Some(parent_velocity) = parent_velocities.get(&orbit_data.orbiting) else { continue; };
- let de_dt = (TAU / t) / (1.0 - e * e_k.cos());
- let b_factor = (1.0 - e * e).sqrt();
- let vx = -a * e_k.sin() * de_dt;
- let vy = a * b_factor * e_k.cos() * de_dt;
- planet_spring.2.x = vx + parent_velocity.x;
- planet_spring.2.y = vy + parent_velocity.y;
- }
-}
-
-fn iterative_kepler(m: f64, e: f64) -> f64 {
- const MAX_ITERATIONS: u32 = 100;
- const CONVERGENCE_THRESHOLD: f64 = 1e-10;
- let mut output = m;
- for _ in 0..MAX_ITERATIONS {
- let d = (m - output + e * output.sin()) / (1.0 - e * output.cos());
- output += d;
- if d.abs() < CONVERGENCE_THRESHOLD {
- break;
- }
- }
- output
-}
M crates/unified/src/shared/plugins.rs => crates/unified/src/shared/plugins.rs +0 -16
@@ 14,7 14,6 @@ use crate::shared::net::register_replication;
use crate::shared::world_config::world_config_plugin;
pub const TICK_RATE: f64 = 20.0;
-const PHYSICS_LENGTH_UNIT: f64 = 100.0;
pub struct SharedPluginGroup;
@@ 30,14 29,6 @@ impl PluginGroup for SharedPluginGroup {
app.insert_resource(Time::from_hz(TICK_RATE));
app.insert_resource(TimeOffset::default());
})
- .add_group(
- PhysicsPlugins::default()
- .with_length_unit(PHYSICS_LENGTH_UNIT)
- .set(PhysicsInterpolationPlugin::interpolate_all())
- .build()
- .disable::<IslandPlugin>()
- )
- .add(physics_setup_plugin)
.add(register_replication)
.add(register_everything)
.add(world_config_plugin)
@@ 56,10 47,3 @@ pub fn register_everything(app: &mut App) {
app.add_message::<CraftPartRequest>();
app.add_message::<ThrustSolution>();
}
-
-fn physics_setup_plugin(app: &mut App) {
- app.insert_resource(Gravity::ZERO);
- app.add_systems(Startup, setup_physics);
-}
-
-fn setup_physics() {}
M crates/unified/src/universal_entrypoint.rs => crates/unified/src/universal_entrypoint.rs +2 -2
@@ 24,9 24,9 @@ pub fn run(cli: StkArgs) -> AppExit {
app.add_plugins(ClientPlugin { server: Some(server) });
},
#[cfg(not(target_arch = "wasm32"))]
- StkArgs::Server { bind_to, with_client } => {
+ StkArgs::Server { management_bind, native_bind, wt_bind, with_client } => {
app.add_plugins(ServerPluginGroup);
- app.add_plugins(ServerPlugin { bind: bind_to });
+ app.add_plugins(ServerPlugin { management_bind, native_bind, wt_bind });
if with_client {
app.add_plugins(ClientPluginGroup);
app.add_plugins(ClientPlugin { server: None });