Compare commits

..

1 Commits

Author SHA1 Message Date
copygirl 13f296d33f WIP 2 weeks ago
  1. 50
      .vscode/launch.json
  2. 531
      Cargo.lock
  3. 16
      Cargo.toml
  4. 6
      client/Cargo.toml
  5. 144
      client/src/connection_ui.rs
  6. 76
      client/src/main.rs
  7. 236
      client/src/server_address.rs
  8. 3
      common/Cargo.toml
  9. 2
      server/Cargo.toml
  10. 6
      server/src/main.rs

@ -6,13 +6,27 @@
"request": "launch", "request": "launch",
"name": "Debug client", "name": "Debug client",
"cargo": { "cargo": {
"args": [ "build", "--bin=gaemstone-client", "--package=gaemstone-client" ], "args": [
"filter": { "name": "gaemstone-client", "kind": "bin" }, "build",
"--bin", "gaemstone-client",
"--package", "gaemstone-client",
// "--features", "bevy/dynamic_linking",
],
"filter": {
"name": "gaemstone-client",
"kind": "bin",
}, },
},
"env": {
// When Bevy looks for assets, it checks BEVY_ASSET_ROOT, CARGO_MANIFEST_DIR, and // When Bevy looks for assets, it checks BEVY_ASSET_ROOT, CARGO_MANIFEST_DIR, and
// then falls back to the executable directory. When debugging, the cargo manifest // then falls back to the executable directory. When debugging, the cargo manifest
// directory is not set, so we need to specify this environment variable. // directory is not set, so we need to specify this environment variable.
"env": { "BEVY_ASSET_ROOT": "${workspaceFolder}" }, "BEVY_ASSET_ROOT": "${workspaceFolder}",
// When debugging with the dynamic_linking feature enabled, we need to add
// the right directories to LD_LIBRARY_PATH, for the libraries to be found.
// NOTE: Currently disabled. Find a way to do this in a portable way.
// "LD_LIBRARY_PATH": "${workspaceFolder}/target/debug/deps:${userHome}/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib:${env:LD_LIBRARY_PATH}",
},
"args": [], "args": [],
}, },
{ {
@ -20,10 +34,34 @@
"request": "launch", "request": "launch",
"name": "Debug server", "name": "Debug server",
"cargo": { "cargo": {
"args": [ "build", "--bin=gaemstone-server", "--package=gaemstone-server" ], "args": [
"filter": { "name": "gaemstone-server", "kind": "bin" }, "build",
"--bin", "gaemstone-server",
"--package", "gaemstone-server",
// "--features", "bevy/dynamic_linking",
],
"filter": {
"name": "gaemstone-server",
"kind": "bin",
},
},
"args": [],
},
{
"type": "lldb",
"request": "launch",
"name": "Debug client unit tests",
"cargo": {
"args": [
"test",
"--no-run",
],
"filter": {
"name": "gaemstone-client",
"kind": "bin",
},
}, },
"args": [], "args": [],
} }
] ],
} }

531
Cargo.lock generated

@ -2,6 +2,22 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 4
[[package]]
name = "ab_glyph"
version = "0.2.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec3672c180e71eeaaac3a541fbbc5f5ad4def8b747c595ad30d674e43049f7b0"
dependencies = [
"ab_glyph_rasterizer",
"owned_ttf_parser",
]
[[package]]
name = "ab_glyph_rasterizer"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046"
[[package]] [[package]]
name = "accesskit" name = "accesskit"
version = "0.17.1" version = "0.17.1"
@ -105,6 +121,23 @@ dependencies = [
"web-time", "web-time",
] ]
[[package]]
name = "aeronet_replicon"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d27f508133f39a100fbf2192222790c875d0a77997952806582229095fc79893"
dependencies = [
"aeronet_io",
"aeronet_transport",
"anyhow",
"bevy_app",
"bevy_ecs",
"bevy_hierarchy",
"bevy_reflect",
"bevy_replicon",
"tracing",
]
[[package]] [[package]]
name = "aeronet_transport" name = "aeronet_transport"
version = "0.11.0" version = "0.11.0"
@ -282,6 +315,24 @@ dependencies = [
"derive_arbitrary", "derive_arbitrary",
] ]
[[package]]
name = "arboard"
version = "3.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df099ccb16cd014ff054ac1bf392c67feeef57164b05c42f037cd40f5d4357f4"
dependencies = [
"clipboard-win",
"core-graphics",
"image",
"log",
"objc2",
"objc2-app-kit",
"objc2-foundation",
"parking_lot",
"windows-sys 0.48.0",
"x11rb",
]
[[package]] [[package]]
name = "arrayref" name = "arrayref"
version = "0.3.9" version = "0.3.9"
@ -640,6 +691,7 @@ dependencies = [
"bevy_reflect", "bevy_reflect",
"bevy_tasks", "bevy_tasks",
"bevy_utils", "bevy_utils",
"serde",
"uuid", "uuid",
] ]
@ -732,6 +784,42 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "bevy_egui"
version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "954fbe8551af4b40767ea9390ec7d32fe1070a6ab55d524cf0868c17f8469a55"
dependencies = [
"arboard",
"bevy_app",
"bevy_asset",
"bevy_derive",
"bevy_ecs",
"bevy_image",
"bevy_input",
"bevy_log",
"bevy_math",
"bevy_reflect",
"bevy_render",
"bevy_time",
"bevy_utils",
"bevy_window",
"bevy_winit",
"bytemuck",
"crossbeam-channel",
"egui",
"encase",
"js-sys",
"log",
"thread_local",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"webbrowser",
"wgpu-types",
"winit",
]
[[package]] [[package]]
name = "bevy_encase_derive" name = "bevy_encase_derive"
version = "0.15.0" version = "0.15.0"
@ -875,6 +963,7 @@ dependencies = [
"bevy_reflect", "bevy_reflect",
"bevy_utils", "bevy_utils",
"derive_more", "derive_more",
"serde",
"smol_str", "smol_str",
] ]
@ -1150,6 +1239,21 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "bevy_replicon"
version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20e0a980e9483807ef5cf4f7f9a4f0073dc1f2146a6cc0a2f17b9236ae6d7b4d"
dependencies = [
"bevy",
"bincode",
"bitflags 2.6.0",
"bytes",
"integer-encoding",
"ordered-multimap",
"serde",
]
[[package]] [[package]]
name = "bevy_scene" name = "bevy_scene"
version = "0.15.0" version = "0.15.0"
@ -1198,6 +1302,7 @@ dependencies = [
"nonmax", "nonmax",
"radsort", "radsort",
"rectangle-pack", "rectangle-pack",
"serde",
] ]
[[package]] [[package]]
@ -1280,6 +1385,7 @@ dependencies = [
"bevy_reflect", "bevy_reflect",
"bevy_utils", "bevy_utils",
"crossbeam-channel", "crossbeam-channel",
"serde",
] ]
[[package]] [[package]]
@ -1294,6 +1400,7 @@ dependencies = [
"bevy_math", "bevy_math",
"bevy_reflect", "bevy_reflect",
"derive_more", "derive_more",
"serde",
] ]
[[package]] [[package]]
@ -1325,6 +1432,7 @@ dependencies = [
"bytemuck", "bytemuck",
"derive_more", "derive_more",
"nonmax", "nonmax",
"serde",
"smallvec", "smallvec",
"taffy", "taffy",
] ]
@ -1370,6 +1478,7 @@ dependencies = [
"bevy_reflect", "bevy_reflect",
"bevy_utils", "bevy_utils",
"raw-window-handle", "raw-window-handle",
"serde",
"smol_str", "smol_str",
] ]
@ -1400,12 +1509,22 @@ dependencies = [
"cfg-if", "cfg-if",
"crossbeam-channel", "crossbeam-channel",
"raw-window-handle", "raw-window-handle",
"serde",
"wasm-bindgen", "wasm-bindgen",
"web-sys", "web-sys",
"wgpu-types", "wgpu-types",
"winit", "winit",
] ]
[[package]]
name = "bincode"
version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "bindgen" name = "bindgen"
version = "0.70.1" version = "0.70.1"
@ -1591,6 +1710,18 @@ dependencies = [
"thiserror 1.0.69", "thiserror 1.0.69",
] ]
[[package]]
name = "calloop-wayland-source"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20"
dependencies = [
"calloop",
"rustix",
"wayland-backend",
"wayland-client",
]
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.2" version = "1.2.2"
@ -1646,6 +1777,15 @@ dependencies = [
"libloading", "libloading",
] ]
[[package]]
name = "clipboard-win"
version = "5.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892"
dependencies = [
"error-code",
]
[[package]] [[package]]
name = "codespan-reporting" name = "codespan-reporting"
version = "0.11.1" version = "0.11.1"
@ -2077,6 +2217,15 @@ dependencies = [
"libloading", "libloading",
] ]
[[package]]
name = "dlv-list"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f"
dependencies = [
"const-random",
]
[[package]] [[package]]
name = "document-features" name = "document-features"
version = "0.2.10" version = "0.2.10"
@ -2098,12 +2247,43 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53"
[[package]]
name = "ecolor"
version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "775cfde491852059e386c4e1deb4aef381c617dc364184c6f6afee99b87c402b"
dependencies = [
"bytemuck",
"emath",
]
[[package]]
name = "egui"
version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53eafabcce0cb2325a59a98736efe0bf060585b437763f8c476957fb274bb974"
dependencies = [
"ahash",
"emath",
"epaint",
"nohash-hasher",
]
[[package]] [[package]]
name = "either" name = "either"
version = "1.13.0" version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "emath"
version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1fe0049ce51d0fb414d029e668dd72eb30bc2b739bf34296ed97bd33df544f3"
dependencies = [
"bytemuck",
]
[[package]] [[package]]
name = "encase" name = "encase"
version = "0.10.0" version = "0.10.0"
@ -2136,6 +2316,28 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "epaint"
version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a32af8da821bd4f43f2c137e295459ee2e1661d87ca8779dfa0eaf45d870e20f"
dependencies = [
"ab_glyph",
"ahash",
"bytemuck",
"ecolor",
"emath",
"epaint_default_fonts",
"nohash-hasher",
"parking_lot",
]
[[package]]
name = "epaint_default_fonts"
version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "483440db0b7993cf77a20314f08311dbe95675092405518c0677aa08c151a3ea"
[[package]] [[package]]
name = "equivalent" name = "equivalent"
version = "1.0.1" version = "1.0.1"
@ -2162,6 +2364,12 @@ dependencies = [
"windows-sys 0.59.0", "windows-sys 0.59.0",
] ]
[[package]]
name = "error-code"
version = "3.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f"
[[package]] [[package]]
name = "euclid" name = "euclid"
version = "0.22.11" version = "0.22.11"
@ -2434,22 +2642,32 @@ name = "gaemstone-client"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"aeronet", "aeronet",
"aeronet_replicon",
"aeronet_webtransport", "aeronet_webtransport",
"bevy", "bevy",
"bevy_egui",
"bevy_replicon",
"gaemstone-common", "gaemstone-common",
"hostname-validator",
] ]
[[package]] [[package]]
name = "gaemstone-common" name = "gaemstone-common"
version = "0.1.0" version = "0.1.0"
dependencies = [
"bevy",
"disqualified",
]
[[package]] [[package]]
name = "gaemstone-server" name = "gaemstone-server"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"aeronet", "aeronet",
"aeronet_replicon",
"aeronet_webtransport", "aeronet_webtransport",
"bevy", "bevy",
"bevy_replicon",
"gaemstone-common", "gaemstone-common",
] ]
@ -2732,6 +2950,21 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
[[package]]
name = "home"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "hostname-validator"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f558a64ac9af88b5ba400d99b579451af0d39c6d360980045b91aac966d705e2"
[[package]] [[package]]
name = "httlib-huffman" name = "httlib-huffman"
version = "0.3.4" version = "0.3.4"
@ -2887,6 +3120,7 @@ dependencies = [
"byteorder-lite", "byteorder-lite",
"num-traits", "num-traits",
"png", "png",
"tiff",
] ]
[[package]] [[package]]
@ -2934,6 +3168,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "integer-encoding"
version = "4.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d762194228a2f1c11063e46e32e5acb96e66e906382b9eb5441f2e0504bbd5a"
[[package]] [[package]]
name = "io-kit-sys" name = "io-kit-sys"
version = "0.4.1" version = "0.4.1"
@ -2990,6 +3230,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "jpeg-decoder"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0"
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.74" version = "0.3.74"
@ -3311,6 +3557,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "nohash-hasher"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
[[package]] [[package]]
name = "nom" name = "nom"
version = "7.1.3" version = "7.1.3"
@ -3721,12 +3973,31 @@ dependencies = [
"libredox", "libredox",
] ]
[[package]]
name = "ordered-multimap"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79"
dependencies = [
"dlv-list",
"hashbrown 0.14.5",
]
[[package]] [[package]]
name = "overload" name = "overload"
version = "0.1.1" version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "owned_ttf_parser"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4"
dependencies = [
"ttf-parser 0.25.1",
]
[[package]] [[package]]
name = "parking" name = "parking"
version = "2.2.1" version = "2.2.1"
@ -3946,6 +4217,15 @@ version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d" checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d"
[[package]]
name = "quick-xml"
version = "0.36.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "quinn" name = "quinn"
version = "0.11.6" version = "0.11.6"
@ -4399,12 +4679,31 @@ dependencies = [
"windows-sys 0.59.0", "windows-sys 0.59.0",
] ]
[[package]]
name = "scoped-tls"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.2.0" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "sctk-adwaita"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6277f0217056f77f1d8f49f2950ac6c278c0d607c45f5ee99328d792ede24ec"
dependencies = [
"ab_glyph",
"log",
"memmap2",
"smithay-client-toolkit",
"tiny-skia",
]
[[package]] [[package]]
name = "security-framework" name = "security-framework"
version = "3.0.1" version = "3.0.1"
@ -4537,6 +4836,34 @@ name = "smallvec"
version = "1.13.2" version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
dependencies = [
"serde",
]
[[package]]
name = "smithay-client-toolkit"
version = "0.19.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016"
dependencies = [
"bitflags 2.6.0",
"calloop",
"calloop-wayland-source",
"cursor-icon",
"libc",
"log",
"memmap2",
"rustix",
"thiserror 1.0.69",
"wayland-backend",
"wayland-client",
"wayland-csd-frame",
"wayland-cursor",
"wayland-protocols",
"wayland-protocols-wlr",
"wayland-scanner",
"xkeysym",
]
[[package]] [[package]]
name = "smol_str" name = "smol_str"
@ -4601,6 +4928,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strict-num"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
[[package]] [[package]]
name = "subtle" name = "subtle"
version = "2.6.1" version = "2.6.1"
@ -4746,6 +5079,17 @@ dependencies = [
"once_cell", "once_cell",
] ]
[[package]]
name = "tiff"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e"
dependencies = [
"flate2",
"jpeg-decoder",
"weezl",
]
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.37" version = "0.3.37"
@ -4786,6 +5130,31 @@ dependencies = [
"crunchy", "crunchy",
] ]
[[package]]
name = "tiny-skia"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab"
dependencies = [
"arrayref",
"arrayvec",
"bytemuck",
"cfg-if",
"log",
"tiny-skia-path",
]
[[package]]
name = "tiny-skia-path"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93"
dependencies = [
"arrayref",
"bytemuck",
"strict-num",
]
[[package]] [[package]]
name = "tinystr" name = "tinystr"
version = "0.7.6" version = "0.7.6"
@ -4975,6 +5344,12 @@ version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8" checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8"
[[package]]
name = "ttf-parser"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
[[package]] [[package]]
name = "twox-hash" name = "twox-hash"
version = "1.6.3" version = "1.6.3"
@ -5220,6 +5595,115 @@ version = "0.2.97"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49"
[[package]]
name = "wayland-backend"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6"
dependencies = [
"cc",
"downcast-rs",
"rustix",
"scoped-tls",
"smallvec",
"wayland-sys",
]
[[package]]
name = "wayland-client"
version = "0.31.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280"
dependencies = [
"bitflags 2.6.0",
"rustix",
"wayland-backend",
"wayland-scanner",
]
[[package]]
name = "wayland-csd-frame"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e"
dependencies = [
"bitflags 2.6.0",
"cursor-icon",
"wayland-backend",
]
[[package]]
name = "wayland-cursor"
version = "0.31.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32b08bc3aafdb0035e7fe0fdf17ba0c09c268732707dca4ae098f60cb28c9e4c"
dependencies = [
"rustix",
"wayland-client",
"xcursor",
]
[[package]]
name = "wayland-protocols"
version = "0.32.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cd0ade57c4e6e9a8952741325c30bf82f4246885dca8bf561898b86d0c1f58e"
dependencies = [
"bitflags 2.6.0",
"wayland-backend",
"wayland-client",
"wayland-scanner",
]
[[package]]
name = "wayland-protocols-plasma"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b31cab548ee68c7eb155517f2212049dc151f7cd7910c2b66abfd31c3ee12bd"
dependencies = [
"bitflags 2.6.0",
"wayland-backend",
"wayland-client",
"wayland-protocols",
"wayland-scanner",
]
[[package]]
name = "wayland-protocols-wlr"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "782e12f6cd923c3c316130d56205ebab53f55d6666b7faddfad36cecaeeb4022"
dependencies = [
"bitflags 2.6.0",
"wayland-backend",
"wayland-client",
"wayland-protocols",
"wayland-scanner",
]
[[package]]
name = "wayland-scanner"
version = "0.31.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3"
dependencies = [
"proc-macro2",
"quick-xml",
"quote",
]
[[package]]
name = "wayland-sys"
version = "0.31.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09"
dependencies = [
"dlib",
"log",
"once_cell",
"pkg-config",
]
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.74" version = "0.3.74"
@ -5265,6 +5749,30 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "webbrowser"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea9fe1ebb156110ff855242c1101df158b822487e4957b0556d9ffce9db0f535"
dependencies = [
"block2",
"core-foundation 0.10.0",
"home",
"jni",
"log",
"ndk-context",
"objc2",
"objc2-foundation",
"url",
"web-sys",
]
[[package]]
name = "weezl"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082"
[[package]] [[package]]
name = "wgpu" name = "wgpu"
version = "23.0.1" version = "23.0.1"
@ -5548,6 +6056,15 @@ dependencies = [
"windows-targets 0.42.2", "windows-targets 0.42.2",
] ]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.5",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.52.0" version = "0.52.0"
@ -5750,6 +6267,7 @@ version = "0.30.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0be9e76a1f1077e04a411f0b989cbd3c93339e1771cb41e71ac4aee95bfd2c67" checksum = "0be9e76a1f1077e04a411f0b989cbd3c93339e1771cb41e71ac4aee95bfd2c67"
dependencies = [ dependencies = [
"ahash",
"android-activity", "android-activity",
"atomic-waker", "atomic-waker",
"bitflags 2.6.0", "bitflags 2.6.0",
@ -5764,6 +6282,7 @@ dependencies = [
"dpi", "dpi",
"js-sys", "js-sys",
"libc", "libc",
"memmap2",
"ndk 0.9.0", "ndk 0.9.0",
"objc2", "objc2",
"objc2-app-kit", "objc2-app-kit",
@ -5775,11 +6294,17 @@ dependencies = [
"raw-window-handle", "raw-window-handle",
"redox_syscall 0.4.1", "redox_syscall 0.4.1",
"rustix", "rustix",
"sctk-adwaita",
"smithay-client-toolkit",
"smol_str", "smol_str",
"tracing", "tracing",
"unicode-segmentation", "unicode-segmentation",
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures",
"wayland-backend",
"wayland-client",
"wayland-protocols",
"wayland-protocols-plasma",
"web-sys", "web-sys",
"web-time", "web-time",
"windows-sys 0.52.0", "windows-sys 0.52.0",
@ -5916,6 +6441,12 @@ dependencies = [
"time", "time",
] ]
[[package]]
name = "xcursor"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ef33da6b1660b4ddbfb3aef0ade110c8b8a781a3b6382fa5f2b5b040fd55f61"
[[package]] [[package]]
name = "xkbcommon-dl" name = "xkbcommon-dl"
version = "0.4.2" version = "0.4.2"

@ -1,14 +1,20 @@
[workspace] [workspace]
resolver = "2" resolver = "2"
members = [ members = ["client", "common", "server"]
"client",
"common", # Enable a small amount of optimization in the dev profile.
"server", [profile.dev]
] opt-level = 1
# Enable a large amount of optimization in the dev profile for dependencies.
[profile.dev.package."*"]
opt-level = 3
[workspace.dependencies] [workspace.dependencies]
# TODO: Disable default features and enable what's needed in specific crates. # TODO: Disable default features and enable what's needed in specific crates.
bevy = "0.15.*" bevy = "0.15.*"
bevy_replicon = "0.29.*"
aeronet = "0.11.*" aeronet = "0.11.*"
aeronet_webtransport = "0.11.*" aeronet_webtransport = "0.11.*"
aeronet_replicon = "0.11.*"

@ -7,6 +7,12 @@ edition = "2021"
common = { package = "gaemstone-common", path = "../common" } common = { package = "gaemstone-common", path = "../common" }
bevy = { workspace = true } bevy = { workspace = true }
bevy_replicon = { workspace = true }
aeronet = { workspace = true } aeronet = { workspace = true }
aeronet_webtransport = { workspace = true, features = ["client"] } aeronet_webtransport = { workspace = true, features = ["client"] }
aeronet_replicon = { workspace = true, features = ["client"] }
bevy_egui = "0.31.*"
hostname-validator = "1.1.1"

@ -0,0 +1,144 @@
use {
crate::server_address::ServerAddress,
aeronet_replicon::client::AeronetRepliconClient,
aeronet_webtransport::{
cert::{self, CertificateHash},
client::{ClientConfig, WebTransportClient},
},
bevy::prelude::*,
bevy_egui::{egui, EguiContexts},
bevy_replicon::prelude::*,
};
pub struct ConnectionUiPlugin;
impl Plugin for ConnectionUiPlugin {
fn build(&self, app: &mut App) {
app.init_resource::<ConnectionUiState>().add_systems(
Update,
display_connection_ui.run_if(not(client_connected.or(client_connecting))),
);
}
}
#[derive(Default, Resource)]
struct ConnectionUiState {
reveal: bool,
address: String,
cert_hash: String,
}
fn display_connection_ui(
commands: Commands,
mut contexts: EguiContexts,
mut ui_state: ResMut<ConnectionUiState>,
) {
let default_address_str = format!("[::1]:{}", common::WEB_TRANSPORT_PORT);
let default_address = default_address_str.parse().unwrap();
egui::Window::new("Connect to Server")
.anchor(egui::Align2::CENTER_CENTER, [0., 0.])
.collapsible(false)
.resizable(false)
.show(contexts.ctx_mut(), |ui| {
let password = !ui_state.reveal;
egui::Grid::new("connection_info_grid")
.num_columns(2)
.show(ui, |ui| {
ui.label("Server Address:");
egui::TextEdit::singleline(&mut ui_state.address)
.hint_text(&default_address_str)
.password(password)
.show(ui);
ui.end_row();
ui.label("Certificate Hash:");
egui::TextEdit::singleline(&mut ui_state.cert_hash)
.password(password)
.show(ui);
ui.end_row();
});
ui.horizontal(|ui| {
ui.checkbox(&mut ui_state.reveal, "Reveal Address / Hash");
let address = if ui_state.address.is_empty() {
Some(default_address)
} else if let Ok(address) = ui_state.address.parse::<ServerAddress>() {
Some(address.with_default_port(common::WEB_TRANSPORT_PORT))
} else {
None
};
let (cert_hash, cert_valid) = if ui_state.cert_hash.is_empty() {
(None, true)
} else if let Ok(cert_hash) = cert::hash_from_b64(&ui_state.cert_hash) {
(Some(cert_hash), true)
} else {
(None, false)
};
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
ui.horizontal(|ui| {
ui.add_enabled_ui(address.is_some() && cert_valid, |ui| {
if ui.button(" Connect ").clicked() {
connect_to_server(commands, &address.unwrap(), cert_hash);
}
});
});
});
});
});
}
fn connect_to_server(
mut commands: Commands,
address: &ServerAddress,
cert_hash: Option<CertificateHash>,
) {
// When using a self-signed cert from the server, its hash needs to be provided to the
// client for it to accept it. Works on native and WASM. On WASM we have the option to
// just accept the HTTPS server's certificate. On native we could theoretically disable
// cert checking entirely, but that kind of defeats the point.
// TODO: Add support for SRV records to `ServerAddress`.
// TODO: (WASM) Auto-connect to address of the server hosting the webpage.
// FIXME: (WASM) `serverCertificateHashes` not accepted in Firefox. https://github.com/BiagioFesta/wtransport/issues/241
let config = web_transport_config(cert_hash);
let target = format!("https://{address}");
commands
.spawn((Name::new(address.to_string()), AeronetRepliconClient))
.queue(WebTransportClient::connect(config, target));
}
#[cfg(not(target_family = "wasm"))]
fn web_transport_config(cert_hash: Option<CertificateHash>) -> ClientConfig {
use {aeronet_webtransport::wtransport::tls::Sha256Digest, core::time::Duration};
let server_certificate_hashes = cert_hash
.map(Sha256Digest::new)
.into_iter()
.collect::<Vec<_>>();
ClientConfig::builder()
.with_bind_default()
.with_server_certificate_hashes(server_certificate_hashes)
.keep_alive_interval(Some(Duration::from_secs(1)))
.max_idle_timeout(Some(Duration::from_secs(5)))
.unwrap()
.build()
}
#[cfg(target_family = "wasm")]
fn web_transport_config(cert_hash: Option<CertificateHash>) -> ClientConfig {
use aeronet_webtransport::xwt_web_sys::{CertificateHash, HashAlgorithm};
let server_certificate_hashes = cert_hash
.map(|hash| CertificateHash {
algorithm: HashAlgorithm::Sha256,
value: Vec::from(hash),
})
.into_iter()
.collect::<Vec<_>>();
ClientConfig {
server_certificate_hashes,
..Default::default()
}
}

@ -6,14 +6,16 @@ use {
}, },
transport::TransportConfig, transport::TransportConfig,
}, },
aeronet_webtransport::{ aeronet_replicon::client::AeronetRepliconClientPlugin,
cert, aeronet_webtransport::client::WebTransportClientPlugin,
cert::CertificateHash,
client::{ClientConfig, WebTransportClient, WebTransportClientPlugin},
},
bevy::{prelude::*, window::WindowResolution}, bevy::{prelude::*, window::WindowResolution},
bevy_egui::EguiPlugin,
bevy_replicon::RepliconPlugins,
}; };
mod connection_ui;
mod server_address;
fn main() -> AppExit { fn main() -> AppExit {
App::new() App::new()
.add_plugins(( .add_plugins((
@ -31,9 +33,13 @@ fn main() -> AppExit {
}), }),
..default() ..default()
}), }),
EguiPlugin,
RepliconPlugins,
WebTransportClientPlugin, WebTransportClientPlugin,
AeronetRepliconClientPlugin,
connection_ui::ConnectionUiPlugin,
)) ))
.add_systems(Startup, (setup, connect_to_server)) .add_systems(Startup, setup)
.add_observer(on_connecting) .add_observer(on_connecting)
.add_observer(on_connected) .add_observer(on_connected)
.add_observer(on_disconnected) .add_observer(on_disconnected)
@ -45,64 +51,6 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(Sprite::from_image(asset_server.load("heck.png"))); commands.spawn(Sprite::from_image(asset_server.load("heck.png")));
} }
fn connect_to_server(mut commands: Commands) {
// When using a self-signed cert, its hash needs to be provided to the
// client for it to accept it. Works on native and WASM. On WASM we have
// the option to just accept the HTTPS server's certificate. On native we
// could theoretically disable cert checking entirely, but that kind of
// defeats the point.
// TODO: Do not hardcode the server's certificate hash. Enter in a UI of some sort?
// For now, just manually replace the `todo!` with the hash that gets
// logged in the server output. It looks something like this:
// ************************
// SPKI FINGERPRINT
// 1YLqE3c3ZsRBos35nUrMETfZtCUVIxyIjcskEq0LFYE=
// CERTIFICATE HASH
// z3cWU+Pc209kffV440ksqcWxMcCTi9QO6qI7VjVOQfU=
// ************************
let target = format!("https://[::1]:{}", common::WEB_TRANSPORT_PORT);
let cert_hash = todo!();
let cert_hash = cert::hash_from_b64(cert_hash).unwrap();
let config = web_transport_config(Some(cert_hash));
commands
.spawn(Name::new(target.clone()))
.queue(WebTransportClient::connect(config, target));
}
#[cfg(target_family = "wasm")]
fn web_transport_config(cert_hash: Option<CertificateHash>) -> ClientConfig {
use aeronet_webtransport::xwt_web_sys::{CertificateHash, HashAlgorithm};
let server_certificate_hashes = cert_hash
.map(|hash| CertificateHash {
algorithm: HashAlgorithm::Sha256,
value: Vec::from(hash),
})
.into_iter()
.collect::<Vec<_>>();
ClientConfig {
server_certificate_hashes,
..Default::default()
}
}
#[cfg(not(target_family = "wasm"))]
fn web_transport_config(cert_hash: Option<CertificateHash>) -> ClientConfig {
use {aeronet_webtransport::wtransport::tls::Sha256Digest, core::time::Duration};
let server_certificate_hashes = cert_hash
.map(Sha256Digest::new)
.into_iter()
.collect::<Vec<_>>();
ClientConfig::builder()
.with_bind_default()
.with_server_certificate_hashes(server_certificate_hashes)
.keep_alive_interval(Some(Duration::from_secs(1)))
.max_idle_timeout(Some(Duration::from_secs(5)))
.unwrap()
.build()
}
fn on_connecting(trigger: Trigger<OnAdd, SessionEndpoint>, names: Query<&Name>) { fn on_connecting(trigger: Trigger<OnAdd, SessionEndpoint>, names: Query<&Name>) {
let session = trigger.entity(); let session = trigger.entity();
let name = names.get(session).unwrap(); let name = names.get(session).unwrap();

@ -0,0 +1,236 @@
use std::net::{Ipv4Addr, Ipv6Addr};
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ServerAddress {
host: ServerHost,
port: Option<u16>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum ServerHost {
Hostname(String),
Ipv4Addr(Ipv4Addr),
Ipv6Addr(Ipv6Addr),
}
impl ServerAddress {
pub fn host(&self) -> &ServerHost {
&self.host
}
pub fn port(&self) -> Option<u16> {
self.port
}
/// Returns a new `ServerAddress` with the specified port if
/// this instance did not already have an explicit port set.
pub fn with_default_port(self, default_port: u16) -> Self {
Self {
port: self.port.or(Some(default_port)),
..self
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum ParseError {
/// The given string (or its host or port) was empty.
Empty,
/// The given string was not a valid hostname.
Hostname,
/// The given string looked like an IPv4 address (`#.#.#.#`) but turned out to be invalid.
Ipv4,
/// The given string started with a '[' but did not contain a valid IPv6 address.
Ipv6,
/// The given port was invalid or out of range.
Port,
}
impl std::str::FromStr for ServerAddress {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let colon = match (s.rfind(':'), s.rfind(']')) {
// This doesn't match colons within IPv6 brackets (`[::1]:80`).
(Some(colon), Some(bracket)) if colon > bracket => Some(colon),
(Some(colon), None) => Some(colon),
_ => None,
};
let host_slice = colon.map(|i| &s[..i]).unwrap_or(s);
let host = host_slice.parse()?;
if colon == Some(s.len() - 1) {
return Err(ParseError::Empty);
}
let port_slice = colon.map(|i| &s[(i + 1)..]);
let port_result = port_slice.map(str::parse).transpose();
let port = port_result.map_err(|_| ParseError::Port)?;
Ok(Self { host, port })
}
}
impl std::str::FromStr for ServerHost {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.is_empty() {
Err(ParseError::Empty)
} else if s.chars().nth(0).unwrap() == '[' {
if s.chars().last().unwrap() == ']' {
let result = s[1..(s.len() - 1)].parse();
result.map(Self::Ipv6Addr).map_err(|_| ParseError::Ipv6)
} else {
Err(ParseError::Ipv6)
}
} else if looks_like_ipv4(s) {
s.parse().map(Self::Ipv4Addr).map_err(|_| ParseError::Ipv4)
} else if hostname_validator::is_valid(s) {
Ok(Self::Hostname(s.to_string()))
} else {
Err(ParseError::Hostname)
}
}
}
impl std::fmt::Display for ServerAddress {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(port) = self.port {
write!(f, "{}:{}", self.host, port)
} else {
write!(f, "{}", self.host)
}
}
}
impl std::fmt::Display for ServerHost {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ServerHost::Hostname(host) => write!(f, "{}", host),
ServerHost::Ipv4Addr(ipv4) => write!(f, "{}", ipv4),
ServerHost::Ipv6Addr(ipv6) => write!(f, "[{}]", ipv6),
}
}
}
/// Returns whether the supplied string is in the dotted-decimal (`#.#.#.#`)
/// form that IPv4 addresses are (has 4 digit-only sections seperated by dots).
/// Does not verify the individual values are within valid ranges (0-255).
fn looks_like_ipv4(s: &str) -> bool {
let mut num_dots = 0;
let mut previous_char = '.';
for c in s.chars() {
match c {
// Dot at beginning or after another dot is invalid.
'.' if previous_char == '.' => return false,
// More than 3 dots aren't valid, let's stop iterating.
'.' if num_dots == 3 => return false,
// More dots!
'.' => num_dots += 1,
// Digits are valid.
'0'..'9' => {}
// Anything else isn't.
_ => return false,
}
previous_char = c;
}
// Must contain 3 dots and not end with one.
(num_dots == 3) && (previous_char != '.')
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn valid_addresses() {
// No port.
assert!(parse("localhost").is_ok());
assert!(parse("0.1-example.net2").is_ok());
assert!(parse("127.0.0.1").is_ok());
assert!(parse("255.255.255.255").is_ok());
assert!(parse("[::]").is_ok());
assert!(parse("[2001:db8:85a3::8a2e:370:7334]").is_ok());
assert!(parse("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]").is_ok());
// Yes port.
assert!(parse("localhost:0").is_ok());
assert!(parse("0.1-example.net2:80").is_ok());
assert!(parse("127.0.0.1:420").is_ok());
assert!(parse("[::]:8080").is_ok());
assert!(parse("[2001:db8:85a3::8a2e:370:7334]:25565").is_ok());
assert!(parse("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:65535").is_ok());
assert_host_and_port("localhost:80", "localhost", 80);
assert_host_and_port("0.0.0.0:69", "0.0.0.0", 69);
assert_host_and_port("[::1]:1337", "[::1]", 1337);
// Sussy but technically valid hostnames??
assert_is_hostname("12.34.56");
assert_is_hostname("12.34.56.78.90:123");
}
#[test]
fn invalid_addresses() {
assert_eq!(parse(""), Err(ParseError::Empty));
assert_eq!(parse(":"), Err(ParseError::Empty));
assert_eq!(parse(":80"), Err(ParseError::Empty));
assert_eq!(parse("abc:"), Err(ParseError::Empty));
assert_eq!(parse("[::]:a"), Err(ParseError::Port));
assert_eq!(parse("[::]:20a"), Err(ParseError::Port));
assert_eq!(parse("[::]:65536"), Err(ParseError::Port));
assert_eq!(parse("example.net:42.0"), Err(ParseError::Port));
// Not necessary to verify many of these, as we don't parse them ourselves.
assert_eq!(parse("["), Err(ParseError::Ipv6));
assert_eq!(parse("[]"), Err(ParseError::Ipv6));
assert_eq!(parse("[localhost]"), Err(ParseError::Ipv6));
// Bare IPv6 values are not supported, they must be wrapped in brackets.
assert_eq!(parse("::"), Err(ParseError::Hostname));
assert_eq!(parse("::1:1337"), Err(ParseError::Hostname));
assert_eq!(parse("2001:4860:4860::8888"), Err(ParseError::Hostname));
// Anything that "looks like an IPv4 address" will attempt to parse as such.
assert_eq!(parse("253.254.255.256"), Err(ParseError::Ipv4));
assert_eq!(parse("1.22.333.4444"), Err(ParseError::Ipv4));
assert_eq!(parse("01.02.03.04"), Err(ParseError::Ipv4));
assert_eq!(parse("..."), Err(ParseError::Hostname));
assert_eq!(parse("a..b"), Err(ParseError::Hostname));
assert_eq!(parse("example.net]"), Err(ParseError::Hostname));
assert_eq!(parse("foo.-bar.example"), Err(ParseError::Hostname));
assert_eq!(parse("admin@example.net"), Err(ParseError::Hostname));
}
#[test]
fn address_with_default_port() {
assert_default_port("localhost", 12345, 12345);
assert_default_port("localhost:80", 12345, 80);
assert_default_port("[::1]", 12345, 12345);
assert_default_port("[::1]:80", 12345, 80);
assert_default_port("1.2.3.4", 12345, 12345);
assert_default_port("1.2.3.4:80", 12345, 80);
}
fn parse(s: &str) -> Result<ServerAddress, ParseError> {
s.parse::<ServerAddress>()
}
fn assert_host_and_port(s: &str, host: &str, port: u16) {
let address = parse(s).unwrap();
assert_eq!(address.host().to_string(), host);
assert_eq!(address.port(), Some(port));
}
fn assert_is_hostname(s: &str) {
let host = parse(s).unwrap().host().clone();
assert!(matches!(host, ServerHost::Hostname(_)));
}
fn assert_default_port(s: &str, default_port: u16, expected_port: u16) {
let address = parse(s).unwrap().with_default_port(default_port);
assert_eq!(address.port(), Some(expected_port));
}
}

@ -4,3 +4,6 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
disqualified = "1.0.0"
bevy = { workspace = true }

@ -7,6 +7,8 @@ edition = "2021"
common = { package = "gaemstone-common", path = "../common" } common = { package = "gaemstone-common", path = "../common" }
bevy = { workspace = true } bevy = { workspace = true }
bevy_replicon = { workspace = true }
aeronet = { workspace = true } aeronet = { workspace = true }
aeronet_webtransport = { workspace = true, features = ["server"] } aeronet_webtransport = { workspace = true, features = ["server"] }
aeronet_replicon = { workspace = true, features = ["server"] }

@ -4,12 +4,14 @@ use {
server::Server, server::Server,
Session, Session,
}, },
aeronet_replicon::server::{AeronetRepliconServer, AeronetRepliconServerPlugin},
aeronet_webtransport::{ aeronet_webtransport::{
cert, cert,
server::{SessionRequest, SessionResponse, WebTransportServer, WebTransportServerPlugin}, server::{SessionRequest, SessionResponse, WebTransportServer, WebTransportServerPlugin},
wtransport::{Identity, ServerConfig}, wtransport::{Identity, ServerConfig},
}, },
bevy::{log::LogPlugin, prelude::*}, bevy::{log::LogPlugin, prelude::*},
bevy_replicon::RepliconPlugins,
std::time::Duration, std::time::Duration,
}; };
@ -18,7 +20,9 @@ fn main() -> AppExit {
.add_plugins(( .add_plugins((
LogPlugin::default(), LogPlugin::default(),
MinimalPlugins, MinimalPlugins,
RepliconPlugins,
WebTransportServerPlugin, WebTransportServerPlugin,
AeronetRepliconServerPlugin,
)) ))
.add_systems(Startup, (setup, open_web_transport_server)) .add_systems(Startup, (setup, open_web_transport_server))
.add_observer(on_server_opened) .add_observer(on_server_opened)
@ -53,7 +57,7 @@ fn open_web_transport_server(mut commands: Commands) {
.build(); .build();
commands commands
.spawn_empty() .spawn(AeronetRepliconServer)
.queue(WebTransportServer::open(config)); .queue(WebTransportServer::open(config));
info!("Starting WebTransport server ..."); info!("Starting WebTransport server ...");
} }

Loading…
Cancel
Save