From 681f8670f59ed374e4bf74bac69a6140bb4a18c7 Mon Sep 17 00:00:00 2001 From: Logan McNaughton <848146+loganmc10@users.noreply.github.com> Date: Fri, 5 Jun 2026 09:43:31 +0200 Subject: [PATCH] GGRS netplay (#1004) * update netplay * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more * more --- Cargo.lock | 1850 +++++++++++++++-- Cargo.toml | 5 +- data/translations/de/LC_MESSAGES/gopher64.po | 138 +- data/translations/es/LC_MESSAGES/gopher64.po | 138 +- data/translations/fr/LC_MESSAGES/gopher64.po | 138 +- data/translations/gopher64.pot | 118 +- data/translations/ja/LC_MESSAGES/gopher64.po | 138 +- data/translations/nl/LC_MESSAGES/gopher64.po | 138 +- .../pt_BR/LC_MESSAGES/gopher64.po | 138 +- data/translations/ru/LC_MESSAGES/gopher64.po | 138 +- src/device.rs | 10 +- src/device/cart/rom.rs | 2 +- src/device/controller.rs | 10 +- src/device/controller/rumble.rs | 2 +- src/device/pif.rs | 4 +- src/device/vi.rs | 42 +- src/lib.rs | 28 +- src/netplay.rs | 622 +++--- src/savestates.rs | 56 +- src/ui/android.rs | 11 +- src/ui/audio.rs | 6 + src/ui/gui.rs | 14 +- src/ui/gui/appwindow.slint | 52 +- src/ui/gui/netplay_create.slint | 69 +- src/ui/gui/netplay_join.slint | 23 +- src/ui/gui/netplay_page.slint | 12 +- src/ui/gui/netplay_wait.slint | 28 +- src/ui/input.rs | 1 + src/ui/netplay.rs | 1276 ++++-------- src/ui/storage.rs | 18 +- 30 files changed, 3143 insertions(+), 2082 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ad1d7902..5c6159b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -69,7 +69,7 @@ checksum = "d5d552169ef018149966ed139bb0311c6947b3343e9140d1b9f88d69da9528fd" dependencies = [ "accesskit", "accesskit_atspi_common", - "async-channel", + "async-channel 2.5.0", "async-executor", "async-task", "atspi", @@ -113,17 +113,52 @@ version = "2.0.1" 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 0.1.7", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher 0.4.4", + "cpufeatures 0.2.17", +] + [[package]] name = "aes" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1fc76eaeac4c9164506c466d4ffdd8ec9d0c5bf57ee97177c4d8eceb3a0e138" dependencies = [ - "cipher", + "cipher 0.5.2", "cpubits", "cpufeatures 0.3.0", ] +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes 0.8.4", + "cipher 0.4.4", + "ctr", + "ghash", + "subtle", +] + [[package]] name = "ahash" version = "0.8.12" @@ -177,7 +212,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289" dependencies = [ "android-properties", - "bitflags 2.11.1", + "bitflags 2.12.1", "cc", "cesu8", "jni 0.21.1", @@ -198,7 +233,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f2a1bb052857d5dd49572219344a7332b31b76405648eabac5bc68978251bcd" dependencies = [ "android-properties", - "bitflags 2.11.1", + "bitflags 2.12.1", "cc", "jni 0.22.4", "libc", @@ -307,6 +342,15 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +[[package]] +name = "arc-swap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207" +dependencies = [ + "rustversion", +] + [[package]] name = "arg_enum_proc_macro" version = "0.3.4" @@ -354,18 +398,68 @@ dependencies = [ "libloading", ] +[[package]] +name = "asn1-rs" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom 7.1.3", + "num-traits", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "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", +] + [[package]] name = "async-broadcast" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" dependencies = [ - "event-listener", + "event-listener 5.4.1", "event-listener-strategy", "futures-core", "pin-project-lite", ] +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + [[package]] name = "async-channel" version = "2.5.0" @@ -378,6 +472,19 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-compat" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ba85bc55464dcbf728b56d97e119d673f4cf9062be330a9a26f3acf504a590" +dependencies = [ + "futures-core", + "futures-io", + "once_cell", + "pin-project-lite", + "tokio", +] + [[package]] name = "async-executor" version = "1.14.0" @@ -392,6 +499,21 @@ dependencies = [ "slab", ] +[[package]] +name = "async-global-executor" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" +dependencies = [ + "async-channel 2.5.0", + "async-executor", + "async-io", + "async-lock", + "blocking", + "futures-lite", + "once_cell", +] + [[package]] name = "async-io" version = "2.6.0" @@ -416,7 +538,7 @@ version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ - "event-listener", + "event-listener 5.4.1", "event-listener-strategy", "pin-project-lite", ] @@ -427,14 +549,14 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" dependencies = [ - "async-channel", + "async-channel 2.5.0", "async-io", "async-lock", "async-signal", "async-task", "blocking", "cfg-if", - "event-listener", + "event-listener 5.4.1", "futures-lite", "rustix 1.1.4", ] @@ -468,12 +590,51 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "async-std" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c8e079a4ab67ae52b7403632e4618815d6db36d2a010cfe41b02c1b1578f93b" +dependencies = [ + "async-channel 1.9.0", + "async-global-executor", + "async-io", + "async-lock", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite", + "gloo-timers 0.3.0", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + [[package]] name = "async-task" version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" +[[package]] +name = "async-tls" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ae3c9eba89d472a0e4fe1dea433df78fbbe63d2b764addaf2ba3a6bde89a5e" +dependencies = [ + "futures-core", + "futures-io", + "rustls 0.21.12", + "rustls-pemfile", + "webpki-roots", +] + [[package]] name = "async-trait" version = "0.1.89" @@ -485,6 +646,34 @@ dependencies = [ "syn", ] +[[package]] +name = "async-tungstenite" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc405d38be14342132609f06f02acaf825ddccfe76c4824a69281e0458ebd4" +dependencies = [ + "async-std", + "async-tls", + "atomic-waker", + "futures-core", + "futures-io", + "futures-task", + "log", + "pin-project-lite", + "tungstenite 0.28.0", +] + +[[package]] +name = "async_io_stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" +dependencies = [ + "futures", + "pharos", + "rustc_version", +] + [[package]] name = "atomic-polyfill" version = "1.0.3" @@ -598,12 +787,39 @@ dependencies = [ "arrayvec", ] +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bincode" version = "2.0.1" @@ -620,7 +836,7 @@ version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "cexpr", "clang-sys", "itertools 0.13.0", @@ -630,7 +846,7 @@ dependencies = [ "quote", "regex", "rustc-hash 2.1.2", - "shlex", + "shlex 1.3.0", "syn", ] @@ -655,6 +871,16 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" +[[package]] +name = "bitfield-rle" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "215d5574bfd0d6d9243a9c741690f0b7ee8a0f39d3195283779793ed46d984e1" +dependencies = [ + "anyhow", + "varinteger", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -663,9 +889,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.11.1" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +checksum = "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a" dependencies = [ "serde_core", ] @@ -704,6 +930,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] + [[package]] name = "block-padding" version = "0.4.2" @@ -737,7 +972,7 @@ version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" dependencies = [ - "async-channel", + "async-channel 2.5.0", "async-task", "futures-io", "futures-lite", @@ -772,6 +1007,29 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" +[[package]] +name = "bytecheck" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0caa33a2c0edca0419d15ac723dff03f1956f7978329b1e3b5fdaaaed9d3ca8b" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "rancor", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89385e82b5d1821d2219e0b095efa2cc1f246cbf99080f3be46a1a85c0d392d9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "bytemuck" version = "1.25.0" @@ -825,7 +1083,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "log", "polling", "rustix 0.38.44", @@ -839,7 +1097,7 @@ version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dbf9978365bac10f54d1d4b04f7ce4427e51f71d61f2fe15e3fed5166474df7" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "polling", "rustix 1.1.4", "slab", @@ -870,25 +1128,46 @@ dependencies = [ "wayland-client", ] +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher 0.4.4", +] + [[package]] name = "cbc" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce2dc9ee5f88d11e0beb842c88b33c8a5cf0d1329c4b19494af42b07dbfe8896" dependencies = [ - "cipher", + "cipher 0.5.2", ] [[package]] name = "cc" -version = "1.2.62" +version = "1.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" +checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" dependencies = [ "find-msvc-tools", "jobserver", "libc", - "shlex", + "shlex 2.0.1", +] + +[[package]] +name = "ccm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae3c82e4355234767756212c570e29833699ab63e6ffd161887314cc5b43847" +dependencies = [ + "aead", + "cipher 0.4.4", + "ctr", + "subtle", ] [[package]] @@ -927,6 +1206,17 @@ dependencies = [ "libc", ] +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher 0.4.4", + "cpufeatures 0.2.17", +] + [[package]] name = "chacha20" version = "0.10.0" @@ -939,10 +1229,23 @@ dependencies = [ ] [[package]] -name = "chrono" -version = "0.4.44" +name = "chacha20poly1305" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +dependencies = [ + "aead", + "chacha20 0.9.1", + "cipher 0.4.4", + "poly1305", + "zeroize", +] + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" dependencies = [ "iana-time-zone", "js-sys", @@ -951,6 +1254,17 @@ dependencies = [ "windows-link 0.2.1", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common 0.1.7", + "inout 0.1.4", + "zeroize", +] + [[package]] name = "cipher" version = "0.5.2" @@ -958,7 +1272,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c" dependencies = [ "crypto-common 0.2.2", - "inout", + "inout 0.2.2", ] [[package]] @@ -1041,9 +1355,9 @@ dependencies = [ [[package]] name = "cmov" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" [[package]] name = "cobs" @@ -1117,6 +1431,12 @@ dependencies = [ "syn", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "const-oid" version = "0.10.2" @@ -1208,7 +1528,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "core-foundation 0.10.1", "libc", ] @@ -1252,6 +1572,21 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" + [[package]] name = "crc32fast" version = "1.5.0" @@ -1307,6 +1642,18 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.7" @@ -1314,6 +1661,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", + "rand_core 0.6.4", "typenum", ] @@ -1335,6 +1683,15 @@ dependencies = [ "dtor", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher 0.4.4", +] + [[package]] name = "ctutils" version = "0.4.2" @@ -1350,6 +1707,32 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "curve25519-dalek-derive", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "data-encoding" version = "2.11.0" @@ -1368,6 +1751,31 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac6b926516df9c60bfa16e107b21086399f8285a44ca9711344b9e553c5146e2" +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid 0.9.6", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "der-parser" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom 7.1.3", + "num-bigint", + "num-traits", + "rusticata-macros", +] + [[package]] name = "deranged" version = "0.5.8" @@ -1418,7 +1826,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", + "const-oid 0.9.6", "crypto-common 0.1.7", + "subtle", ] [[package]] @@ -1428,7 +1838,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" dependencies = [ "block-buffer 0.12.0", - "const-oid", + "const-oid 0.10.2", "crypto-common 0.2.2", "ctutils", "zeroize", @@ -1482,7 +1892,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "block2 0.6.2", "libc", "objc2 0.6.4", @@ -1535,7 +1945,7 @@ version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80bc8c5c6c2941f70a55c15f8d9f00f9710ebda3ffda98075f996a0e6c92756f" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "bytemuck", "drm-ffi", "drm-fourcc", @@ -1569,18 +1979,89 @@ dependencies = [ "linux-raw-sys 0.9.4", ] +[[package]] +name = "dtls" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f016db07b91e9d79cc60a152c163d3f0ce2d4c0173cb3964de3526aab6e07fa" +dependencies = [ + "aes 0.8.4", + "aes-gcm", + "async-trait", + "bytecheck", + "byteorder", + "cbc 0.1.2", + "ccm", + "chacha20poly1305", + "der-parser", + "hmac 0.12.1", + "log", + "p256", + "p384", + "portable-atomic", + "rand 0.9.4", + "rand_core 0.6.4", + "rcgen", + "ring", + "rkyv", + "rustls 0.23.40", + "sec1", + "sha1 0.10.6", + "sha2 0.10.9", + "thiserror 1.0.69", + "tokio", + "webrtc-util", + "x25519-dalek", + "x509-parser", +] + [[package]] name = "dtor" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edf234dd1594d6dd434a8fb8cada51ddbbc593e40e4a01556a0b31c62da2775b" +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + [[package]] name = "either" version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "embedded-io" version = "0.4.0" @@ -1680,6 +2161,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + [[package]] name = "event-listener" version = "5.4.1" @@ -1697,7 +2184,7 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "event-listener", + "event-listener 5.4.1", "pin-project-lite", ] @@ -1755,7 +2242,7 @@ version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "727c5dd9d601f3f4ea133b8a6ba37d37ca67ed59781675dc1c9c9f1701e0d197" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "bytemuck", "fnv", "glow 0.17.0", @@ -1770,13 +2257,29 @@ dependencies = [ "wgpu", ] +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "field-offset" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" dependencies = [ - "memoffset", + "memoffset 0.9.1", "rustc_version", ] @@ -2009,6 +2512,16 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" +[[package]] +name = "futures-timer" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af43fadb8a98512d547e37b4e92e0ced13e205c061b87b4623eff01d918d6968" +dependencies = [ + "gloo-timers 0.4.0", + "send_wrapper", +] + [[package]] name = "futures-util" version = "0.3.32" @@ -2034,6 +2547,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -2094,6 +2608,32 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "ggrs" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777d9da4dfd802a272f1795a7a1887d6078fd31487e7e68d689596c4c5298046" +dependencies = [ + "bincode 1.3.3", + "bitfield-rle", + "instant", + "js-sys", + "parking_lot", + "rand 0.8.6", + "serde", + "tracing", +] + +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "gif" version = "0.14.2" @@ -2121,6 +2661,30 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "gloo-timers" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "482ce8a491a501da4cd806bd190275363d674f2845005c6ddbd5d3e1dd54495d" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "glow" version = "0.16.0" @@ -2151,7 +2715,7 @@ version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12124de845cacfebedff80e877bb37b5b75c34c5a4c89e47e1cdd67fb6041325" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "cfg_aliases", "cgl", "dispatch2", @@ -2224,7 +2788,9 @@ dependencies = [ "encoding_rs", "fatfs", "futures", + "ggrs", "jni 0.22.4", + "matchbox_socket", "mimalloc", "open", "postcard", @@ -2242,10 +2808,9 @@ dependencies = [ "serde-big-array", "serde_json", "sevenz-rust2", - "sha2", + "sha2 0.11.0", "slint", "slint-build", - "socket2", "spin_sleep", "tokio", "tokio-tungstenite", @@ -2273,7 +2838,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "gpu-descriptor-types", "hashbrown 0.15.5", ] @@ -2284,7 +2849,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", ] [[package]] @@ -2293,6 +2858,17 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b40ca9252762c466af32d0b1002e91e4e1bc5398f77455e55474deb466355ff5" +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "h2" version = "0.4.14" @@ -2330,7 +2906,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9da2e5ae821f6e96664977bf974d6d6a2d6682f9ccee23e62ec1d134246845f9" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "bytemuck", "core_maths", "read-fonts", @@ -2422,6 +2998,24 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac 0.12.1", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "hmac" version = "0.13.0" @@ -2487,9 +3081,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb92f162bf56536459fc83c79b974bb12837acfed43d6bc370a7916d0ae15ecc" +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" dependencies = [ "atomic-waker", "bytes", @@ -2515,7 +3109,7 @@ dependencies = [ "http", "hyper", "hyper-util", - "rustls", + "rustls 0.23.40", "tokio", "tokio-rustls", "tower-service", @@ -2543,7 +3137,7 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "futures-channel", "futures-util", @@ -2554,7 +3148,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2", + "socket2 0.6.4", "system-configuration", "tokio", "tower-service", @@ -2591,7 +3185,7 @@ dependencies = [ "i-slint-core", "i-slint-renderer-femtovg", "input", - "nix", + "nix 0.30.1", "xkbcommon", ] @@ -2707,7 +3301,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89e4a57afd78d8a1f599a78781dc1413af68545b2bc5ba5e143ecf022c75d5f3" dependencies = [ "auto_enums", - "bitflags 2.11.1", + "bitflags 2.12.1", "cfg-if", "chrono", "clru", @@ -3082,13 +3676,23 @@ dependencies = [ "serde_core", ] +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "block-padding 0.3.3", + "generic-array", +] + [[package]] name = "inout" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" dependencies = [ - "block-padding", + "block-padding 0.4.2", "hybrid-array", ] @@ -3098,7 +3702,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbdc09524a91f9cacd26f16734ff63d7dc650daffadd2b6f84d17a285bd875a9" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "input-sys", "libc", "log", @@ -3111,6 +3715,15 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "36eee07d8e02bd95bf52b2e642cf13d33701b94c6e4b04fbf1d1fb07e9cb19e7" +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + [[package]] name = "integer-sqrt" version = "0.1.5" @@ -3120,6 +3733,27 @@ dependencies = [ "num-traits", ] +[[package]] +name = "interceptor" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f73f4fdb971cab2d599cbdc2ccf0c6ea8fb27347b871ed14c65ce2353dbe75b" +dependencies = [ + "async-trait", + "bytes", + "futures", + "log", + "portable-atomic", + "rand 0.9.4", + "rtcp", + "rtp", + "thiserror 1.0.69", + "tokio", + "waitgroup", + "webrtc-srtp", + "webrtc-util", +] + [[package]] name = "interpolate_name" version = "0.2.4" @@ -3299,7 +3933,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "serde", "unicode-segmentation", ] @@ -3333,6 +3967,15 @@ dependencies = [ "smallvec", ] +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -3404,10 +4047,10 @@ version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "libc", "plain", - "redox_syscall 0.8.0", + "redox_syscall 0.8.1", ] [[package]] @@ -3482,9 +4125,12 @@ dependencies = [ [[package]] name = "log" -version = "0.4.30" +version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5" +checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a" +dependencies = [ + "value-bag", +] [[package]] name = "loop9" @@ -3538,11 +4184,11 @@ dependencies = [ [[package]] name = "lzma-rust2" -version = "0.16.3" +version = "0.16.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e9ceaec84b54518262de7cf06b8b43e83c808349960f1610b21b0bfc9640f20" +checksum = "ce716bf1a316f47a280fc76295f6495b5bea4752bca01c3b3885e101b1c23c02" dependencies = [ - "sha2", + "sha2 0.11.0", ] [[package]] @@ -3554,6 +4200,50 @@ dependencies = [ "libc", ] +[[package]] +name = "matchbox_protocol" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "867e83a984f369eabc682318eec2db410aef1dbb5399cb1890e6659dfa9b7449" +dependencies = [ + "cfg-if", + "derive_more", + "serde", + "uuid 1.23.2", +] + +[[package]] +name = "matchbox_socket" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ee21421327e145fab424cadb542bef9f745a8938b9eb8c81d3286e98f18be9" +dependencies = [ + "async-compat", + "async-trait", + "async-tungstenite", + "bytes", + "cfg-if", + "derive_more", + "futures", + "futures-channel", + "futures-timer", + "futures-util", + "js-sys", + "log", + "matchbox_protocol", + "once_cell", + "serde", + "serde-wasm-bindgen", + "serde_json", + "thiserror 2.0.18", + "tokio-util", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webrtc", + "ws_stream_wasm", +] + [[package]] name = "maybe-rayon" version = "0.1.1" @@ -3564,6 +4254,16 @@ dependencies = [ "rayon", ] +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest 0.10.7", +] + [[package]] name = "memchr" version = "2.8.1" @@ -3579,6 +4279,15 @@ dependencies = [ "libc", ] +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + [[package]] name = "memoffset" version = "0.9.1" @@ -3594,7 +4303,7 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f569fb946490b5743ad69813cb19629130ce9374034abe31614a36402d18f99e" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "block", "core-graphics-types 0.1.3", "foreign-types 0.5.0", @@ -3609,7 +4318,7 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7047791b5bc903b8cd963014b355f71dc9864a9a0b727057676c1dcae5cbc15" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "block", "core-graphics-types 0.2.0", "foreign-types 0.5.0", @@ -3689,6 +4398,26 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "munge" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c" +dependencies = [ + "munge_macro", +] + +[[package]] +name = "munge_macro" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "naga" version = "28.0.0" @@ -3697,7 +4426,7 @@ checksum = "618f667225063219ddfc61251087db8a9aec3c3f0950c916b614e403486f1135" dependencies = [ "arrayvec", "bit-set", - "bitflags 2.11.1", + "bitflags 2.12.1", "cfg-if", "cfg_aliases", "codespan-reporting", @@ -3744,7 +4473,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "jni-sys 0.3.1", "log", "ndk-sys 0.5.0+25.2.9519653", @@ -3758,7 +4487,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "jni-sys 0.3.1", "log", "ndk-sys 0.6.0+11769913", @@ -3797,13 +4526,26 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.7.1", + "pin-utils", +] + [[package]] name = "nix" version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "cfg-if", "cfg_aliases", "libc", @@ -3962,7 +4704,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "block2 0.5.1", "libc", "objc2 0.5.2", @@ -3978,7 +4720,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "block2 0.6.2", "libc", "objc2 0.6.4", @@ -3999,7 +4741,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "block2 0.5.1", "objc2 0.5.2", "objc2-core-location", @@ -4012,7 +4754,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "objc2 0.6.4", "objc2-foundation 0.3.2", ] @@ -4034,7 +4776,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -4046,7 +4788,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "objc2 0.6.4", "objc2-foundation 0.3.2", ] @@ -4057,7 +4799,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "dispatch2", "objc2 0.6.4", ] @@ -4068,7 +4810,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "dispatch2", "objc2 0.6.4", "objc2-core-foundation", @@ -4115,7 +4857,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "objc2 0.6.4", "objc2-core-foundation", "objc2-core-graphics", @@ -4127,7 +4869,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d425caf1df73233f29fd8a5c3e5edbc30d2d4307870f802d18f00d83dc5141a6" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "objc2 0.6.4", "objc2-core-foundation", "objc2-core-graphics", @@ -4146,7 +4888,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "block2 0.5.1", "dispatch", "libc", @@ -4159,7 +4901,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "block2 0.6.2", "objc2 0.6.4", "objc2-core-foundation", @@ -4171,7 +4913,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "objc2 0.6.4", "objc2-core-foundation", ] @@ -4194,7 +4936,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -4206,7 +4948,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0125f776a10d00af4152d74616409f0d4a2053a6f57fa5b7d6aa2854ac04794" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "objc2 0.6.4", "objc2-foundation 0.3.2", ] @@ -4217,7 +4959,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -4230,7 +4972,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "objc2 0.6.4", "objc2-core-foundation", "objc2-foundation 0.3.2", @@ -4253,7 +4995,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "block2 0.5.1", "objc2 0.5.2", "objc2-cloud-kit 0.2.2", @@ -4274,7 +5016,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "block2 0.6.2", "objc2 0.6.4", "objc2-core-foundation", @@ -4299,13 +5041,22 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "block2 0.5.1", "objc2 0.5.2", "objc2-core-location", "objc2-foundation 0.2.2", ] +[[package]] +name = "oid-registry" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" +dependencies = [ + "asn1-rs", +] + [[package]] name = "once_cell" version = "1.21.4" @@ -4322,6 +5073,12 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + [[package]] name = "open" version = "5.3.5" @@ -4339,7 +5096,7 @@ version = "0.10.80" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a45fa2aa886c42762255da344f0a0d313e254066c46aad76f300c3d3da62d967" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "cfg-if", "foreign-types 0.3.2", "libc", @@ -4430,6 +5187,30 @@ dependencies = [ "ttf-parser", ] +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2 0.10.9", +] + +[[package]] +name = "p384" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2 0.10.9", +] + [[package]] name = "parking" version = "2.2.1" @@ -4517,7 +5298,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112d82ceb8c5bf524d9af484d4e4970c9fd5a0cc15ba14ad93dccd28873b0629" dependencies = [ "digest 0.11.3", - "hmac", + "hmac 0.13.0", +] + +[[package]] +name = "pem" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +dependencies = [ + "base64 0.22.1", + "serde_core", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", ] [[package]] @@ -4526,6 +5326,16 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "pharos" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +dependencies = [ + "futures", + "rustc_version", +] + [[package]] name = "pico-args" version = "0.5.0" @@ -4581,6 +5391,16 @@ dependencies = [ "futures-io", ] +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.33" @@ -4612,7 +5432,7 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "crc32fast", "fdeflate", "flate2", @@ -4639,6 +5459,17 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" +[[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 = "polycool" version = "0.4.0" @@ -4648,6 +5479,18 @@ dependencies = [ "arrayvec", ] +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "opaque-debug", + "universal-hash", +] + [[package]] name = "portable-atomic" version = "1.13.1" @@ -4727,6 +5570,15 @@ dependencies = [ "syn", ] +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro-crate" version = "3.5.0" @@ -4764,13 +5616,33 @@ dependencies = [ "syn", ] +[[package]] +name = "ptr_meta" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9a0cf95a1196af61d4f1cbdab967179516d9a4a4312af1f31948f8f6224a79" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "pulldown-cmark" version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9f068eba8e7071c5f9511831b44f32c740d5adf574e990f946ddb53db2f314e" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "getopts", "memchr", "pulldown-cmark-escape", @@ -4835,13 +5707,33 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" +[[package]] +name = "rancor" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a063ea72381527c2a0561da9c80000ef822bdd7c3241b1cc1b12100e3df081ee" +dependencies = [ + "ptr_meta", +] + +[[package]] +name = "rand" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + [[package]] name = "rand" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ - "rand_chacha", + "rand_chacha 0.9.0", "rand_core 0.9.5", ] @@ -4851,9 +5743,20 @@ 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", + "serde", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", ] [[package]] @@ -4866,6 +5769,15 @@ dependencies = [ "rand_core 0.9.5", ] +[[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" @@ -4915,7 +5827,7 @@ dependencies = [ "paste", "profiling", "rand 0.9.4", - "rand_chacha", + "rand_chacha 0.9.0", "simd_helpers", "thiserror 2.0.18", "v_frame", @@ -4975,6 +5887,20 @@ dependencies = [ "crossbeam-utils", ] +[[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", + "x509-parser", + "yasna", +] + [[package]] name = "read-fonts" version = "0.37.0" @@ -5001,16 +5927,16 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", ] [[package]] name = "redox_syscall" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c7591fa2c6b601dfcfe5f043f65a1c39fcdf50efefcd7f1572e538c1f4b398d" +checksum = "5b44b894f2a6e36457d665d1e08c3866add6ed5e70050c1b4ba8a8ddedb02ce7" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", ] [[package]] @@ -5053,6 +5979,15 @@ version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +[[package]] +name = "rend" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6" +dependencies = [ + "bytecheck", +] + [[package]] name = "renderdoc-sys" version = "1.1.0" @@ -5065,7 +6000,7 @@ version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "encoding_rs", "futures-core", @@ -5116,6 +6051,16 @@ dependencies = [ "zune-jpeg", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle", +] + [[package]] name = "rfd" version = "0.17.2" @@ -5166,6 +6111,36 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rkyv" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73389e0c99e664f919275ab5b5b0471391fe9a8de61e1dff9b1eaf56a90f16e3" +dependencies = [ + "bytecheck", + "bytes", + "hashbrown 0.17.1", + "indexmap", + "munge", + "ptr_meta", + "rancor", + "rend", + "rkyv_derive", + "tinyvec", + "uuid 1.23.2", +] + +[[package]] +name = "rkyv_derive" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d2ed0b54125315fb36bd021e82d314d1c126548f871634b483f46b31d13cac6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "rowan" version = "0.16.1" @@ -5206,6 +6181,32 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "rtcp" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb22f1cc99aea8152fdae6a4bc52a9caddf4bd1ff083d897c1f9f279956177e8" +dependencies = [ + "bytes", + "thiserror 1.0.69", + "webrtc-util", +] + +[[package]] +name = "rtp" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8d41f3565d9add11caabe7c61745517f4ef511c168a6aa2b59ce4c701802cde" +dependencies = [ + "bytes", + "memchr", + "portable-atomic", + "rand 0.9.4", + "serde", + "thiserror 1.0.69", + "webrtc-util", +] + [[package]] name = "rustc-hash" version = "1.1.0" @@ -5227,13 +6228,22 @@ dependencies = [ "semver", ] +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom 7.1.3", +] + [[package]] name = "rustix" version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "errno", "libc", "linux-raw-sys 0.4.15", @@ -5246,13 +6256,25 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "errno", "libc", "linux-raw-sys 0.12.1", "windows-sys 0.61.2", ] +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + [[package]] name = "rustls" version = "0.23.40" @@ -5260,12 +6282,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" dependencies = [ "once_cell", + "ring", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.103.13", "subtle", "zeroize", ] +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + [[package]] name = "rustls-pki-types" version = "1.14.1" @@ -5275,6 +6307,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "rustls-webpki" version = "0.103.13" @@ -5298,7 +6340,7 @@ version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "bytemuck", "core_maths", "log", @@ -5352,6 +6394,16 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "sctk-adwaita" version = "0.10.1" @@ -5419,13 +6471,39 @@ dependencies = [ "sdl3-ttf-src", ] +[[package]] +name = "sdp" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22c3b0257608d7de4de4c4ea650ccc2e6e3e45e3cd80039fcdee768bcb449253" +dependencies = [ + "rand 0.9.4", + "substring", + "thiserror 1.0.69", + "url", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + [[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", + "bitflags 2.12.1", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -5448,6 +6526,12 @@ version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + [[package]] name = "serde" version = "1.0.228" @@ -5467,6 +6551,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + [[package]] name = "serde_core" version = "1.0.228" @@ -5538,15 +6633,15 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbbd24232798280d6bc896e3429a3469174de008ec8b1b591a96618b46664195" dependencies = [ - "aes", + "aes 0.9.1", "bzip2", - "cbc", + "cbc 0.2.1", "crc32fast", "getrandom 0.4.2", "js-sys", "lzma-rust2", "ppmd-rust", - "sha2", + "sha2 0.11.0", "wasm-bindgen", ] @@ -5572,6 +6667,17 @@ dependencies = [ "digest 0.11.3", ] +[[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 0.10.7", +] + [[package]] name = "sha2" version = "0.11.0" @@ -5589,6 +6695,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + [[package]] name = "signal-hook-registry" version = "1.4.8" @@ -5599,6 +6711,16 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + [[package]] name = "simd-adler32" version = "0.3.9" @@ -5668,7 +6790,7 @@ version = "0.90.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a71c01d325d40b1031dee67d251a5e0132e79e2a9ec272149a4f4a0d4b8b3be" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "skia-bindings", "windows 0.62.2", ] @@ -5758,7 +6880,7 @@ version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "calloop 0.13.0", "calloop-wayland-source 0.3.0", "cursor-icon", @@ -5783,7 +6905,7 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0512da38f5e2b31201a93524adb8d3136276fa4fe4aafab4e1f727a82b534cc0" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "calloop 0.14.4", "calloop-wayland-source 0.4.1", "cursor-icon", @@ -5855,6 +6977,16 @@ dependencies = [ "syn", ] +[[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" @@ -5929,7 +7061,17 @@ version = "0.3.0+sdk-1.3.268.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", ] [[package]] @@ -5980,6 +7122,34 @@ dependencies = [ "syn", ] +[[package]] +name = "stun" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e0fd33c04d4617df42c9c84c698511c59f59869629fb7a193067eec41bce347" +dependencies = [ + "base64 0.22.1", + "crc", + "lazy_static", + "md-5", + "rand 0.9.4", + "ring", + "subtle", + "thiserror 1.0.69", + "tokio", + "url", + "webrtc-util", +] + +[[package]] +name = "substring" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ee6433ecef213b2e72f587ef64a2f5943e7cd16fbd82dbe8bc07486c534c86" +dependencies = [ + "autocfg", +] + [[package]] name = "subtle" version = "2.6.1" @@ -6056,7 +7226,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -6183,11 +7353,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", + "itoa", "js-sys", "num-conv", "powerfmt", "serde_core", "time-core", + "time-macros", ] [[package]] @@ -6196,6 +7368,16 @@ 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" @@ -6295,9 +7477,10 @@ dependencies = [ "bytes", "libc", "mio", + "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.6.4", "tokio-macros", "windows-sys 0.61.2", ] @@ -6329,7 +7512,7 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls", + "rustls 0.23.40", "tokio", ] @@ -6342,7 +7525,7 @@ dependencies = [ "futures-util", "log", "tokio", - "tungstenite", + "tungstenite 0.29.0", ] [[package]] @@ -6353,6 +7536,7 @@ checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", + "futures-io", "futures-sink", "pin-project-lite", "tokio", @@ -6455,7 +7639,7 @@ version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "bytes", "futures-util", "http", @@ -6526,6 +7710,23 @@ dependencies = [ "core_maths", ] +[[package]] +name = "tungstenite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" +dependencies = [ + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.9.4", + "sha1 0.10.6", + "thiserror 2.0.18", + "utf-8", +] + [[package]] name = "tungstenite" version = "0.29.0" @@ -6542,13 +7743,34 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "turn" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6a8b8ac3543b2a8eb0b28c7ac3d5f2db6221e057f3b3ae47cf7637b1333a5c3" +dependencies = [ + "async-trait", + "base64 0.22.1", + "futures", + "log", + "md-5", + "portable-atomic", + "rand 0.9.4", + "ring", + "stun", + "thiserror 1.0.69", + "tokio", + "tokio-util", + "webrtc-util", +] + [[package]] name = "typed-index-collections" version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "898160f1dfd383b4e92e17f0512a7d62f3c51c44937b23b6ffc3a1614a8eaccd" dependencies = [ - "bincode", + "bincode 2.0.1", "serde", ] @@ -6560,9 +7782,9 @@ checksum = "8e28f89b80c87b8fb0cf04ab448d5dd0dd0ade2f8891bae878de66a75a28600e" [[package]] name = "typenum" -version = "1.20.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "udev" @@ -6582,7 +7804,7 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" dependencies = [ - "memoffset", + "memoffset 0.9.1", "tempfile", "windows-sys 0.61.2", ] @@ -6637,9 +7859,9 @@ checksum = "383ad40bb927465ec0ce7720e033cb4ca06912855fc35db31b5755d0de75b1ee" [[package]] name = "unicode-segmentation" -version = "1.13.2" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] name = "unicode-vo" @@ -6659,6 +7881,16 @@ version = "0.2.6" 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 0.1.7", + "subtle", +] + [[package]] name = "untrusted" version = "0.9.0" @@ -6689,7 +7921,7 @@ version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d46cf96c5f498d36b7a9693bc6a7075c0bb9303189d61b2249b0dc3d309c07de" dependencies = [ - "base64", + "base64 0.22.1", "data-url", "flate2", "fontdb", @@ -6711,6 +7943,12 @@ dependencies = [ "xmlwriter", ] +[[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" @@ -6734,10 +7972,11 @@ dependencies = [ [[package]] name = "uuid" -version = "1.23.1" +version = "1.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" +checksum = "d258b83ceec21034727ecee8c382cfa6c3e133699b0742c64571814fb420c9f7" dependencies = [ + "getrandom 0.4.2", "js-sys", "serde_core", "wasm-bindgen", @@ -6754,6 +7993,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "value-bag" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0" + +[[package]] +name = "varinteger" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ea29db9f94ff08bb619656b8120878f280526f71dc88b5262c958a510181812" + [[package]] name = "vcpkg" version = "0.2.15" @@ -6789,6 +8040,15 @@ dependencies = [ "syn", ] +[[package]] +name = "waitgroup" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1f50000a783467e6c0200f9d10642f4bc424e39efc1b770203e88b488f79292" +dependencies = [ + "atomic-waker", +] + [[package]] name = "walkdir" version = "2.5.0" @@ -6915,7 +8175,7 @@ version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "hashbrown 0.15.5", "indexmap", "semver", @@ -6941,7 +8201,7 @@ version = "0.31.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "645c7c96bb74690c3189b5c9cb4ca1627062bb23693a4fad9d8c3de958260144" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "rustix 1.1.4", "wayland-backend", "wayland-scanner", @@ -6953,7 +8213,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "cursor-icon", "wayland-backend", ] @@ -6975,7 +8235,7 @@ version = "0.32.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "563a85523cade2429938e790815fd7319062103b9f4a2dc806e9b53b95982d8f" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "wayland-backend", "wayland-client", "wayland-scanner", @@ -6987,7 +8247,7 @@ version = "20250721.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40a1f863128dcaaec790d7b4b396cc9b9a7a079e878e18c47e6c2d2c5a8dcbb1" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -7000,7 +8260,7 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e9567599ef23e09b8dad6e429e5738d4509dfc46b3b21f32841a304d16b29c8" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -7013,7 +8273,7 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b6d8cf1eb2c1c31ed1f5643c88a6e53538129d4af80030c8cabd1f9fa884d91" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -7026,7 +8286,7 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb04e52f7836d7c7976c78ca0250d61e33873c34156a2a1fc9474828ec268234" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -7092,6 +8352,194 @@ dependencies = [ "web-sys", ] +[[package]] +name = "webpki" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" +dependencies = [ + "webpki", +] + +[[package]] +name = "webrtc" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ba06986c4fcfbbb4b490abe4b88887b0ac9de0d3eb0aae36f3254e38d6ecdd1" +dependencies = [ + "arc-swap", + "async-trait", + "bytes", + "dtls", + "hex", + "interceptor", + "lazy_static", + "log", + "portable-atomic", + "rand 0.9.4", + "rcgen", + "regex", + "ring", + "rtcp", + "rtp", + "sdp", + "serde", + "serde_json", + "sha2 0.10.9", + "smol_str 0.2.2", + "stun", + "thiserror 1.0.69", + "tokio", + "turn", + "unicase", + "url", + "waitgroup", + "webrtc-data", + "webrtc-ice", + "webrtc-mdns", + "webrtc-media", + "webrtc-sctp", + "webrtc-srtp", + "webrtc-util", +] + +[[package]] +name = "webrtc-data" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7ca42127ee64bcb71da36d151e6f87b12488c5f14c4f379e73d2d52a8e54aa0" +dependencies = [ + "bytes", + "log", + "portable-atomic", + "thiserror 1.0.69", + "tokio", + "webrtc-sctp", + "webrtc-util", +] + +[[package]] +name = "webrtc-ice" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23ede72a36e5dda685814c389b2b34ac60b3ed000a81789e93626e27180eb785" +dependencies = [ + "arc-swap", + "async-trait", + "crc", + "log", + "portable-atomic", + "rand 0.9.4", + "serde", + "serde_json", + "stun", + "thiserror 1.0.69", + "tokio", + "turn", + "url", + "uuid 1.23.2", + "waitgroup", + "webrtc-mdns", + "webrtc-util", +] + +[[package]] +name = "webrtc-mdns" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b62bc8d3fb5024bc6ffde5f4aad2127ce17f8359dbc6f70208a324a12e44677" +dependencies = [ + "log", + "socket2 0.5.10", + "thiserror 1.0.69", + "tokio", + "webrtc-util", +] + +[[package]] +name = "webrtc-media" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9a28290bd0cdda196f8bf5c6f7dddaef18cc913ee0702cd1ea237bad203e337" +dependencies = [ + "byteorder", + "bytes", + "rand 0.9.4", + "rtp", + "thiserror 1.0.69", +] + +[[package]] +name = "webrtc-sctp" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ea6633bf951b3fd71eba3244731c8d0814f6a80300620a4370cad2983a5a42f" +dependencies = [ + "arc-swap", + "async-trait", + "bytes", + "crc", + "log", + "portable-atomic", + "rand 0.9.4", + "thiserror 1.0.69", + "tokio", + "webrtc-util", +] + +[[package]] +name = "webrtc-srtp" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e437f74b04f42049192e25cbb33c21c86be308875e6afe14cf8e28d1ffa35ac" +dependencies = [ + "aead", + "aes 0.8.4", + "aes-gcm", + "byteorder", + "bytes", + "ctr", + "hmac 0.12.1", + "log", + "rtcp", + "rtp", + "sha1 0.10.6", + "subtle", + "thiserror 1.0.69", + "tokio", + "webrtc-util", +] + +[[package]] +name = "webrtc-util" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b65c1e0143a43d40f69e1d8c2ffc8734e379b49c06d45892ea4104c388bf9ead" +dependencies = [ + "async-trait", + "bitflags 1.3.2", + "bytes", + "ipnet", + "lazy_static", + "log", + "nix 0.26.4", + "portable-atomic", + "rand 0.9.4", + "thiserror 1.0.69", + "tokio", + "winapi", +] + [[package]] name = "weezl" version = "0.1.12" @@ -7105,7 +8553,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9cb534d5ffd109c7d1135f34cdae29e60eab94855a625dcfe1705f8bc7ad79f" dependencies = [ "arrayvec", - "bitflags 2.11.1", + "bitflags 2.12.1", "bytemuck", "cfg-if", "cfg_aliases", @@ -7137,7 +8585,7 @@ dependencies = [ "arrayvec", "bit-set", "bit-vec", - "bitflags 2.11.1", + "bitflags 2.12.1", "bytemuck", "cfg_aliases", "document-features", @@ -7197,7 +8645,7 @@ dependencies = [ "arrayvec", "ash", "bit-set", - "bitflags 2.11.1", + "bitflags 2.12.1", "block", "bytemuck", "cfg-if", @@ -7241,13 +8689,29 @@ version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e18308757e594ed2cd27dddbb16a139c42a683819d32a2e0b1b0167552f5840c" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "bytemuck", "js-sys", "log", "web-sys", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + [[package]] name = "winapi-util" version = "0.1.11" @@ -7257,6 +8721,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows" version = "0.61.3" @@ -7773,7 +9243,7 @@ dependencies = [ "ahash", "android-activity 0.6.1", "atomic-waker", - "bitflags 2.11.1", + "bitflags 2.12.1", "block2 0.5.1", "bytemuck", "calloop 0.13.0", @@ -7905,7 +9375,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.11.1", + "bitflags 2.12.1", "indexmap", "log", "serde", @@ -7954,6 +9424,25 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" +[[package]] +name = "ws_stream_wasm" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c173014acad22e83f16403ee360115b38846fe754e735c5d9d3803fe70c6abc" +dependencies = [ + "async_io_stream", + "futures", + "js-sys", + "log", + "pharos", + "rustc_version", + "send_wrapper", + "thiserror 2.0.18", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "x11-clipboard" version = "0.9.3" @@ -7996,6 +9485,36 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" +[[package]] +name = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core 0.6.4", + "serde", + "zeroize", +] + +[[package]] +name = "x509-parser" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom 7.1.3", + "oid-registry", + "ring", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + [[package]] name = "xattr" version = "1.6.1" @@ -8029,7 +9548,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.12.1", "dlib", "log", "once_cell", @@ -8060,6 +9579,15 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448" +[[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" @@ -8079,9 +9607,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -8102,9 +9630,9 @@ dependencies = [ [[package]] name = "zbus" -version = "5.15.0" +version = "5.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3bcbf15c8708d7fc1be0c993622e0a5cbd5e8b52bfa40afa4c3e0cd8d724ac1" +checksum = "eee682d202a77e4a9f3b2c2bdf48a7b28af5c08c34ddf66f98c93e5e39464285" dependencies = [ "async-broadcast", "async-executor", @@ -8116,7 +9644,7 @@ dependencies = [ "async-trait", "blocking", "enumflags2", - "event-listener", + "event-listener 5.4.1", "futures-core", "futures-lite", "hex", @@ -8127,7 +9655,7 @@ dependencies = [ "serde_repr", "tracing", "uds_windows", - "uuid 1.23.1", + "uuid 1.23.2", "windows-sys 0.61.2", "winnow 1.0.3", "zbus_macros", @@ -8161,9 +9689,9 @@ dependencies = [ [[package]] name = "zbus_macros" -version = "5.15.0" +version = "5.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51fa5406ad9175a8c825a931f8cf347116b531b3634fcb0b627c290f1f2516ff" +checksum = "adf1bd45a81a103745b1757754762a26e8cd01e4532e4d6c8ec431624b80d1d6" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -8205,18 +9733,18 @@ checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524" [[package]] name = "zerocopy" -version = "0.8.49" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bce33a6288fa3f072a8c2c7d0f2fdbb90e28298f0135c1f99b96c3db2efcc60b" +checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.49" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd425244944f4ab65ccff928e7323354c5a018c75838362fdce749dfad2ee1e" +checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639" dependencies = [ "proc-macro2", "quote", @@ -8249,6 +9777,20 @@ name = "zeroize" version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "zerotrie" @@ -8291,14 +9833,14 @@ version = "8.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d04a6b5381502aa6087c94c669499eb1602eb9c5e8198e534de571f7154809b" dependencies = [ - "aes", + "aes 0.9.1", "bzip2", "constant_time_eq", "crc32fast", "deflate64", "flate2", "getrandom 0.4.2", - "hmac", + "hmac 0.13.0", "indexmap", "lzma-rust2", "memchr", @@ -8390,9 +9932,9 @@ dependencies = [ [[package]] name = "zvariant" -version = "5.11.0" +version = "5.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c1567a6ec68df868cbbfde844cfc6d81649fe5109a62b116b19fabd53e618ee" +checksum = "a192a0bde63360d77a7523c833d4b4ce6070a927e2c53246e4c540b1a3e27be0" dependencies = [ "endi", "enumflags2", @@ -8404,9 +9946,9 @@ dependencies = [ [[package]] name = "zvariant_derive" -version = "5.11.0" +version = "5.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d5b780599bbde114e39d9a0799577fad1ced5105d38515745f7b3099d8ceda" +checksum = "90bc6cde9c01c511074be97f7ccb6c19d0da89e3f8662e812e999dcfd4638737" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -8417,9 +9959,9 @@ dependencies = [ [[package]] name = "zvariant_utils" -version = "3.3.1" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d464f5733ffa07a3164d656f18533caace9d0638596721355d73256a410d691" +checksum = "1e8535915cfa75547e559d8c68e8139909a4aeee076831e4ef7fc59d8172c4d6" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index e44058bc..7a7ed7ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,10 +25,11 @@ encoding_rs = "0.8" mimalloc = "0.1" regex = "1.11" tokio-tungstenite = "0.29" +matchbox_socket = "0.14" +ggrs = { version = "0.12", features = ["sync-send"] } rustc-hash = "2.1" futures = "0.3" -socket2 = { version = "0.6", features = ["all"] } -rand = "0.10" +rand = { version = "0.10", features = ["serde"] } fatfs = "0.3" semver = "1.0" postcard = { version = "1.1", features = ["use-std"] } diff --git a/data/translations/de/LC_MESSAGES/gopher64.po b/data/translations/de/LC_MESSAGES/gopher64.po index 18c0e7f7..fcc6ed1e 100644 --- a/data/translations/de/LC_MESSAGES/gopher64.po +++ b/data/translations/de/LC_MESSAGES/gopher64.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: gopher64\n" -"POT-Creation-Date: 2026-05-30 16:03+0000\n" +"POT-Creation-Date: 2026-06-04 13:13+0000\n" "PO-Revision-Date: 2026-05-11 12:00+0000\n" "Last-Translator: \n" "Language-Team: German\n" @@ -47,37 +47,37 @@ msgctxt "About" msgid "Donate (via GitHub)" msgstr "Spenden (über GitHub)" -#: src/ui/gui/appwindow.slint:152 +#: src/ui/gui/appwindow.slint:145 msgctxt "Menu" msgid "Local Game" msgstr "Lokales Spiel" -#: src/ui/gui/appwindow.slint:156 +#: src/ui/gui/appwindow.slint:149 msgctxt "Menu" msgid "Controller Config" msgstr "Controller-Konfiguration" -#: src/ui/gui/appwindow.slint:160 +#: src/ui/gui/appwindow.slint:153 msgctxt "Menu" msgid "Netplay" msgstr "Netplay" -#: src/ui/gui/appwindow.slint:164 +#: src/ui/gui/appwindow.slint:157 msgctxt "Menu" msgid "Cheats" msgstr "Cheats" -#: src/ui/gui/appwindow.slint:168 +#: src/ui/gui/appwindow.slint:161 msgctxt "Menu" msgid "RetroAchievements" msgstr "RetroAchievements" -#: src/ui/gui/appwindow.slint:172 +#: src/ui/gui/appwindow.slint:165 msgctxt "Menu" msgid "Settings" msgstr "Einstellungen" -#: src/ui/gui/appwindow.slint:176 +#: src/ui/gui/appwindow.slint:169 msgctxt "Menu" msgid "About" msgstr "Über" @@ -192,47 +192,42 @@ msgctxt "NetplayCreate" msgid "Netplay: Create Session" msgstr "Netplay: Sitzung erstellen" -#: src/ui/gui/netplay_create.slint:23 +#: src/ui/gui/netplay_create.slint:22 msgctxt "NetplayCreate" msgid "Session Name:" msgstr "Sitzungsname:" -#: src/ui/gui/netplay_create.slint:27 +#: src/ui/gui/netplay_create.slint:26 msgctxt "NetplayCreate" msgid "Enter session name" msgstr "Sitzungsname eingeben" -#: src/ui/gui/netplay_create.slint:37 +#: src/ui/gui/netplay_create.slint:36 msgctxt "NetplayCreate" msgid "Password (Optional):" msgstr "Passwort (optional):" -#: src/ui/gui/netplay_create.slint:41 +#: src/ui/gui/netplay_create.slint:40 msgctxt "NetplayCreate" msgid "Enter session password" msgstr "Sitzungspasswort eingeben" -#: src/ui/gui/netplay_create.slint:52 +#: src/ui/gui/netplay_create.slint:51 msgctxt "NetplayCreate" msgid "Player Name:" msgstr "Spielername:" -#: src/ui/gui/netplay_create.slint:56 +#: src/ui/gui/netplay_create.slint:55 msgctxt "NetplayCreate" msgid "Enter player name" msgstr "Spielername eingeben" #: src/ui/gui/netplay_create.slint:66 msgctxt "NetplayCreate" -msgid "Server:" -msgstr "Server:" - -#: src/ui/gui/netplay_create.slint:86 -msgctxt "NetplayCreate" msgid "Select ROM" msgstr "ROM auswählen" -#: src/ui/gui/netplay_create.slint:102 +#: src/ui/gui/netplay_create.slint:82 msgctxt "NetplayCreate" msgid "" "This game has cheats enabled. Cheats will be synchronized with other players." @@ -240,21 +235,16 @@ msgstr "" "Für dieses Spiel sind Cheats aktiviert. Cheats werden mit anderen Spielern " "synchronisiert." -#: src/ui/gui/netplay_create.slint:112 +#: src/ui/gui/netplay_create.slint:91 msgctxt "NetplayCreate" msgid "Create Session" msgstr "Sitzung erstellen" -#: src/ui/gui/netplay_create.slint:132 +#: src/ui/gui/netplay_create.slint:105 msgctxt "NetplayCreate" msgid "Cancel" msgstr "Abbrechen" -#: src/ui/gui/netplay_create.slint:155 -msgctxt "CustomServerDialog" -msgid "Enter a custom server URL" -msgstr "Eigene Server-URL eingeben" - #: src/ui/gui/netplay_join.slint:7 msgctxt "NetplayJoin" msgid "Netplay: Join Session" @@ -275,152 +265,142 @@ msgctxt "NetplayJoin" msgid "Password (if required)" msgstr "Passwort (falls erforderlich)" -#: src/ui/gui/netplay_join.slint:41 -msgctxt "NetplayJoin" -msgid "Custom Server URL (optional):" -msgstr "Eigene Server-URL (optional):" - -#: src/ui/gui/netplay_join.slint:53 +#: src/ui/gui/netplay_join.slint:42 msgctxt "NetplayJoin" msgid "Select ROM" msgstr "ROM auswählen" -#: src/ui/gui/netplay_join.slint:68 +#: src/ui/gui/netplay_join.slint:57 msgctxt "NetplayJoin" msgid "Refreshing session list, please wait..." msgstr "Sitzungsliste wird aktualisiert, bitte warten …" -#: src/ui/gui/netplay_join.slint:73 +#: src/ui/gui/netplay_join.slint:62 msgctxt "NetplayJoin" msgid "Click on a session below to select it" msgstr "Auf eine Sitzung klicken um diese auszuwählen" -#: src/ui/gui/netplay_join.slint:78 +#: src/ui/gui/netplay_join.slint:67 msgctxt "NetplayJoin" msgid "No sessions available. Please refresh to check again." msgstr "Keine Sitzungen verfügbar. Bitte aktualisieren, um erneut zu prüfen." -#: src/ui/gui/netplay_join.slint:84 -msgctxt "NetplayJoin" -msgid "Server" -msgstr "Server" - -#: src/ui/gui/netplay_join.slint:85 +#: src/ui/gui/netplay_join.slint:73 msgctxt "NetplayJoin" msgid "Session Name" msgstr "Sitzungsname" -#: src/ui/gui/netplay_join.slint:86 +#: src/ui/gui/netplay_join.slint:74 msgctxt "NetplayJoin" msgid "Game Name" msgstr "Spielname" -#: src/ui/gui/netplay_join.slint:87 +#: src/ui/gui/netplay_join.slint:75 msgctxt "NetplayJoin" msgid "Password" msgstr "Passwort" -#: src/ui/gui/netplay_join.slint:88 +#: src/ui/gui/netplay_join.slint:76 msgctxt "NetplayJoin" msgid "Cheats" msgstr "Cheats" -#: src/ui/gui/netplay_join.slint:102 +#: src/ui/gui/netplay_join.slint:90 msgctxt "NetplayJoin" msgid "Refresh Session List" msgstr "Sitzungsliste aktualisieren" -#: src/ui/gui/netplay_join.slint:119 +#: src/ui/gui/netplay_join.slint:105 msgctxt "NetplayJoin" msgid "Join Session" msgstr "Sitzung beitreten" -#: src/ui/gui/netplay_join.slint:132 +#: src/ui/gui/netplay_join.slint:117 msgctxt "NetplayJoin" msgid "Cancel" msgstr "Abbrechen" -#: src/ui/gui/netplay_page.slint:37 +#: src/ui/gui/netplay_page.slint:31 msgctxt "Netplay" msgid "Netplay" msgstr "Netplay" -#: src/ui/gui/netplay_page.slint:45 +#: src/ui/gui/netplay_page.slint:39 msgctxt "Netplay" msgid "Create Session" msgstr "Sitzung erstellen" -#: src/ui/gui/netplay_page.slint:56 +#: src/ui/gui/netplay_page.slint:50 msgctxt "Netplay" msgid "Join Session" msgstr "Sitzung beitreten" -#: src/ui/gui/netplay_page.slint:70 +#: src/ui/gui/netplay_page.slint:64 msgctxt "Netplay" msgid "Netplay Discord Channel" msgstr "Netplay-Discord-Kanal" -#: src/ui/gui/netplay_page.slint:77 +#: src/ui/gui/netplay_page.slint:71 msgctxt "Netplay" msgid "Provide Feedback" msgstr "Feedback geben" -#: src/ui/gui/netplay_wait.slint:15 +#: src/ui/gui/netplay_wait.slint:14 msgctxt "NetplayWait" msgid "Netplay: Waiting Room" msgstr "Netplay: Warteraum" -#: src/ui/gui/netplay_wait.slint:27 +#: src/ui/gui/netplay_wait.slint:26 msgctxt "NetplayWait" msgid "Session Name:" msgstr "Sitzungsname:" -#: src/ui/gui/netplay_wait.slint:33 +#: src/ui/gui/netplay_wait.slint:32 msgctxt "NetplayWait" msgid "Game Name:" msgstr "Spielname:" -#: src/ui/gui/netplay_wait.slint:39 -msgctxt "NetplayWait" -msgid "Ping:" -msgstr "Ping:" - -#: src/ui/gui/netplay_wait.slint:48 +#: src/ui/gui/netplay_wait.slint:42 msgctxt "NetplayWait" msgid "Player 1:" msgstr "Spieler 1:" -#: src/ui/gui/netplay_wait.slint:52 +#: src/ui/gui/netplay_wait.slint:46 msgctxt "NetplayWait" msgid "Player 2:" msgstr "Spieler 2:" -#: src/ui/gui/netplay_wait.slint:58 +#: src/ui/gui/netplay_wait.slint:52 msgctxt "NetplayWait" msgid "Player 3:" msgstr "Spieler 3:" -#: src/ui/gui/netplay_wait.slint:62 +#: src/ui/gui/netplay_wait.slint:56 msgctxt "NetplayWait" msgid "Player 4:" msgstr "Spieler 4:" -#: src/ui/gui/netplay_wait.slint:76 +#: src/ui/gui/netplay_wait.slint:70 msgctxt "NetplayWait" msgid "Enter chat message" msgstr "Chatnachricht eingeben" -#: src/ui/gui/netplay_wait.slint:87 +#: src/ui/gui/netplay_wait.slint:81 msgctxt "NetplayWait" msgid "Send Message" msgstr "Nachricht senden" -#: src/ui/gui/netplay_wait.slint:105 +#: src/ui/gui/netplay_wait.slint:98 +msgctxt "NetplayWait" +msgid "Local Input Delay:" +msgstr "Lokale Eingabeverzögerung:" + +#: src/ui/gui/netplay_wait.slint:115 msgctxt "NetplayWait" msgid "Start Game" msgstr "Spiel starten" -#: src/ui/gui/netplay_wait.slint:113 +#: src/ui/gui/netplay_wait.slint:123 msgctxt "NetplayWait" msgid "Cancel" msgstr "Abbrechen" @@ -555,6 +535,26 @@ msgctxt "VruDialog" msgid "What Would You Like To Say?" msgstr "Was möchten Sie sagen?" +#~ msgctxt "NetplayCreate" +#~ msgid "Server:" +#~ msgstr "Server:" + +#~ msgctxt "CustomServerDialog" +#~ msgid "Enter a custom server URL" +#~ msgstr "Eigene Server-URL eingeben" + +#~ msgctxt "NetplayJoin" +#~ msgid "Custom Server URL (optional):" +#~ msgstr "Eigene Server-URL (optional):" + +#~ msgctxt "NetplayJoin" +#~ msgid "Server" +#~ msgstr "Server" + +#~ msgctxt "NetplayWait" +#~ msgid "Ping:" +#~ msgstr "Ping:" + #~ msgctxt "NetplayCreate" #~ msgid "Creating server, please wait...This may take about 30 seconds." #~ msgstr "" diff --git a/data/translations/es/LC_MESSAGES/gopher64.po b/data/translations/es/LC_MESSAGES/gopher64.po index c975dbd2..b8fb3bb8 100644 --- a/data/translations/es/LC_MESSAGES/gopher64.po +++ b/data/translations/es/LC_MESSAGES/gopher64.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: gopher64\n" -"POT-Creation-Date: 2026-05-30 16:03+0000\n" +"POT-Creation-Date: 2026-06-04 13:13+0000\n" "PO-Revision-Date: 2026-05-11 12:00+0000\n" "Last-Translator: Gemini\n" "Language-Team: Spanish (Spain)\n" @@ -47,37 +47,37 @@ msgctxt "About" msgid "Donate (via GitHub)" msgstr "Donar (a través de GitHub)" -#: src/ui/gui/appwindow.slint:152 +#: src/ui/gui/appwindow.slint:145 msgctxt "Menu" msgid "Local Game" msgstr "Juego local" -#: src/ui/gui/appwindow.slint:156 +#: src/ui/gui/appwindow.slint:149 msgctxt "Menu" msgid "Controller Config" msgstr "Config. del mando" -#: src/ui/gui/appwindow.slint:160 +#: src/ui/gui/appwindow.slint:153 msgctxt "Menu" msgid "Netplay" msgstr "Netplay" -#: src/ui/gui/appwindow.slint:164 +#: src/ui/gui/appwindow.slint:157 msgctxt "Menu" msgid "Cheats" msgstr "Trucos" -#: src/ui/gui/appwindow.slint:168 +#: src/ui/gui/appwindow.slint:161 msgctxt "Menu" msgid "RetroAchievements" msgstr "RetroAchievements" -#: src/ui/gui/appwindow.slint:172 +#: src/ui/gui/appwindow.slint:165 msgctxt "Menu" msgid "Settings" msgstr "Ajustes" -#: src/ui/gui/appwindow.slint:176 +#: src/ui/gui/appwindow.slint:169 msgctxt "Menu" msgid "About" msgstr "Acerca de" @@ -192,47 +192,42 @@ msgctxt "NetplayCreate" msgid "Netplay: Create Session" msgstr "Netplay: Crear sesión" -#: src/ui/gui/netplay_create.slint:23 +#: src/ui/gui/netplay_create.slint:22 msgctxt "NetplayCreate" msgid "Session Name:" msgstr "Nombre de la sesión:" -#: src/ui/gui/netplay_create.slint:27 +#: src/ui/gui/netplay_create.slint:26 msgctxt "NetplayCreate" msgid "Enter session name" msgstr "Introduce el nombre de la sesión" -#: src/ui/gui/netplay_create.slint:37 +#: src/ui/gui/netplay_create.slint:36 msgctxt "NetplayCreate" msgid "Password (Optional):" msgstr "Contraseña (Opcional):" -#: src/ui/gui/netplay_create.slint:41 +#: src/ui/gui/netplay_create.slint:40 msgctxt "NetplayCreate" msgid "Enter session password" msgstr "Introduce la contraseña" -#: src/ui/gui/netplay_create.slint:52 +#: src/ui/gui/netplay_create.slint:51 msgctxt "NetplayCreate" msgid "Player Name:" msgstr "Nombre del jugador:" -#: src/ui/gui/netplay_create.slint:56 +#: src/ui/gui/netplay_create.slint:55 msgctxt "NetplayCreate" msgid "Enter player name" msgstr "Introduce tu nombre" #: src/ui/gui/netplay_create.slint:66 msgctxt "NetplayCreate" -msgid "Server:" -msgstr "Servidor:" - -#: src/ui/gui/netplay_create.slint:86 -msgctxt "NetplayCreate" msgid "Select ROM" msgstr "Seleccionar ROM" -#: src/ui/gui/netplay_create.slint:102 +#: src/ui/gui/netplay_create.slint:82 msgctxt "NetplayCreate" msgid "" "This game has cheats enabled. Cheats will be synchronized with other players." @@ -240,21 +235,16 @@ msgstr "" "Este juego tiene trucos activados. Los trucos se sincronizarán con los otros " "jugadores." -#: src/ui/gui/netplay_create.slint:112 +#: src/ui/gui/netplay_create.slint:91 msgctxt "NetplayCreate" msgid "Create Session" msgstr "Crear sesión" -#: src/ui/gui/netplay_create.slint:132 +#: src/ui/gui/netplay_create.slint:105 msgctxt "NetplayCreate" msgid "Cancel" msgstr "Cancelar" -#: src/ui/gui/netplay_create.slint:155 -msgctxt "CustomServerDialog" -msgid "Enter a custom server URL" -msgstr "Introduce la URL de servidor personalizado" - #: src/ui/gui/netplay_join.slint:7 msgctxt "NetplayJoin" msgid "Netplay: Join Session" @@ -275,152 +265,142 @@ msgctxt "NetplayJoin" msgid "Password (if required)" msgstr "Contraseña (si es necesaria)" -#: src/ui/gui/netplay_join.slint:41 -msgctxt "NetplayJoin" -msgid "Custom Server URL (optional):" -msgstr "URL de servidor personalizado (opcional):" - -#: src/ui/gui/netplay_join.slint:53 +#: src/ui/gui/netplay_join.slint:42 msgctxt "NetplayJoin" msgid "Select ROM" msgstr "Seleccionar ROM" -#: src/ui/gui/netplay_join.slint:68 +#: src/ui/gui/netplay_join.slint:57 msgctxt "NetplayJoin" msgid "Refreshing session list, please wait..." msgstr "Actualizando lista de sesiones, espera..." -#: src/ui/gui/netplay_join.slint:73 +#: src/ui/gui/netplay_join.slint:62 msgctxt "NetplayJoin" msgid "Click on a session below to select it" msgstr "Pulsa una sesión para seleccionarla" -#: src/ui/gui/netplay_join.slint:78 +#: src/ui/gui/netplay_join.slint:67 msgctxt "NetplayJoin" msgid "No sessions available. Please refresh to check again." msgstr "No hay sesiones disponibles. Actualiza para comprobar de nuevo." -#: src/ui/gui/netplay_join.slint:84 -msgctxt "NetplayJoin" -msgid "Server" -msgstr "Servidor" - -#: src/ui/gui/netplay_join.slint:85 +#: src/ui/gui/netplay_join.slint:73 msgctxt "NetplayJoin" msgid "Session Name" msgstr "Nombre de la sesión" -#: src/ui/gui/netplay_join.slint:86 +#: src/ui/gui/netplay_join.slint:74 msgctxt "NetplayJoin" msgid "Game Name" msgstr "Nombre del juego" -#: src/ui/gui/netplay_join.slint:87 +#: src/ui/gui/netplay_join.slint:75 msgctxt "NetplayJoin" msgid "Password" msgstr "Contraseña" -#: src/ui/gui/netplay_join.slint:88 +#: src/ui/gui/netplay_join.slint:76 msgctxt "NetplayJoin" msgid "Cheats" msgstr "Trucos" -#: src/ui/gui/netplay_join.slint:102 +#: src/ui/gui/netplay_join.slint:90 msgctxt "NetplayJoin" msgid "Refresh Session List" msgstr "Actualizar lista" -#: src/ui/gui/netplay_join.slint:119 +#: src/ui/gui/netplay_join.slint:105 msgctxt "NetplayJoin" msgid "Join Session" msgstr "Unirse a la sesión" -#: src/ui/gui/netplay_join.slint:132 +#: src/ui/gui/netplay_join.slint:117 msgctxt "NetplayJoin" msgid "Cancel" msgstr "Cancelar" -#: src/ui/gui/netplay_page.slint:37 +#: src/ui/gui/netplay_page.slint:31 msgctxt "Netplay" msgid "Netplay" msgstr "Netplay" -#: src/ui/gui/netplay_page.slint:45 +#: src/ui/gui/netplay_page.slint:39 msgctxt "Netplay" msgid "Create Session" msgstr "Crear sesión" -#: src/ui/gui/netplay_page.slint:56 +#: src/ui/gui/netplay_page.slint:50 msgctxt "Netplay" msgid "Join Session" msgstr "Unirse a la sesión" -#: src/ui/gui/netplay_page.slint:70 +#: src/ui/gui/netplay_page.slint:64 msgctxt "Netplay" msgid "Netplay Discord Channel" msgstr "Canal de Discord de Netplay" -#: src/ui/gui/netplay_page.slint:77 +#: src/ui/gui/netplay_page.slint:71 msgctxt "Netplay" msgid "Provide Feedback" msgstr "Enviar comentarios" -#: src/ui/gui/netplay_wait.slint:15 +#: src/ui/gui/netplay_wait.slint:14 msgctxt "NetplayWait" msgid "Netplay: Waiting Room" msgstr "Netplay: Sala de espera" -#: src/ui/gui/netplay_wait.slint:27 +#: src/ui/gui/netplay_wait.slint:26 msgctxt "NetplayWait" msgid "Session Name:" msgstr "Nombre de la sesión:" -#: src/ui/gui/netplay_wait.slint:33 +#: src/ui/gui/netplay_wait.slint:32 msgctxt "NetplayWait" msgid "Game Name:" msgstr "Nombre del juego:" -#: src/ui/gui/netplay_wait.slint:39 -msgctxt "NetplayWait" -msgid "Ping:" -msgstr "Latencia (Ping):" - -#: src/ui/gui/netplay_wait.slint:48 +#: src/ui/gui/netplay_wait.slint:42 msgctxt "NetplayWait" msgid "Player 1:" msgstr "Jugador 1:" -#: src/ui/gui/netplay_wait.slint:52 +#: src/ui/gui/netplay_wait.slint:46 msgctxt "NetplayWait" msgid "Player 2:" msgstr "Jugador 2:" -#: src/ui/gui/netplay_wait.slint:58 +#: src/ui/gui/netplay_wait.slint:52 msgctxt "NetplayWait" msgid "Player 3:" msgstr "Jugador 3:" -#: src/ui/gui/netplay_wait.slint:62 +#: src/ui/gui/netplay_wait.slint:56 msgctxt "NetplayWait" msgid "Player 4:" msgstr "Jugador 4:" -#: src/ui/gui/netplay_wait.slint:76 +#: src/ui/gui/netplay_wait.slint:70 msgctxt "NetplayWait" msgid "Enter chat message" msgstr "Escribe un mensaje en el chat" -#: src/ui/gui/netplay_wait.slint:87 +#: src/ui/gui/netplay_wait.slint:81 msgctxt "NetplayWait" msgid "Send Message" msgstr "Enviar mensaje" -#: src/ui/gui/netplay_wait.slint:105 +#: src/ui/gui/netplay_wait.slint:98 +msgctxt "NetplayWait" +msgid "Local Input Delay:" +msgstr "Retardo de entrada local:" + +#: src/ui/gui/netplay_wait.slint:115 msgctxt "NetplayWait" msgid "Start Game" msgstr "Iniciar juego" -#: src/ui/gui/netplay_wait.slint:113 +#: src/ui/gui/netplay_wait.slint:123 msgctxt "NetplayWait" msgid "Cancel" msgstr "Cancelar" @@ -555,6 +535,26 @@ msgctxt "VruDialog" msgid "What Would You Like To Say?" msgstr "¿Qué te gustaría decir?" +#~ msgctxt "NetplayCreate" +#~ msgid "Server:" +#~ msgstr "Servidor:" + +#~ msgctxt "CustomServerDialog" +#~ msgid "Enter a custom server URL" +#~ msgstr "Introduce la URL de servidor personalizado" + +#~ msgctxt "NetplayJoin" +#~ msgid "Custom Server URL (optional):" +#~ msgstr "URL de servidor personalizado (opcional):" + +#~ msgctxt "NetplayJoin" +#~ msgid "Server" +#~ msgstr "Servidor" + +#~ msgctxt "NetplayWait" +#~ msgid "Ping:" +#~ msgstr "Latencia (Ping):" + #~ msgctxt "NetplayCreate" #~ msgid "Creating server, please wait...This may take about 30 seconds." #~ msgstr "Creando servidor, espera... Puede tardar unos 30 segundos." diff --git a/data/translations/fr/LC_MESSAGES/gopher64.po b/data/translations/fr/LC_MESSAGES/gopher64.po index 4952a37f..91a03e2d 100644 --- a/data/translations/fr/LC_MESSAGES/gopher64.po +++ b/data/translations/fr/LC_MESSAGES/gopher64.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: gopher64\n" -"POT-Creation-Date: 2026-05-30 16:03+0000\n" +"POT-Creation-Date: 2026-06-04 13:13+0000\n" "PO-Revision-Date: 2026-05-11 12:00+0000\n" "Last-Translator: \n" "Language-Team: French (France)\n" @@ -47,37 +47,37 @@ msgctxt "About" msgid "Donate (via GitHub)" msgstr "Faire un don (via GitHub)" -#: src/ui/gui/appwindow.slint:152 +#: src/ui/gui/appwindow.slint:145 msgctxt "Menu" msgid "Local Game" msgstr "Jeu local" -#: src/ui/gui/appwindow.slint:156 +#: src/ui/gui/appwindow.slint:149 msgctxt "Menu" msgid "Controller Config" msgstr "Configuration manette" -#: src/ui/gui/appwindow.slint:160 +#: src/ui/gui/appwindow.slint:153 msgctxt "Menu" msgid "Netplay" msgstr "Netplay" -#: src/ui/gui/appwindow.slint:164 +#: src/ui/gui/appwindow.slint:157 msgctxt "Menu" msgid "Cheats" msgstr "Triche" -#: src/ui/gui/appwindow.slint:168 +#: src/ui/gui/appwindow.slint:161 msgctxt "Menu" msgid "RetroAchievements" msgstr "RetroAchievements" -#: src/ui/gui/appwindow.slint:172 +#: src/ui/gui/appwindow.slint:165 msgctxt "Menu" msgid "Settings" msgstr "Paramètres" -#: src/ui/gui/appwindow.slint:176 +#: src/ui/gui/appwindow.slint:169 msgctxt "Menu" msgid "About" msgstr "À propos" @@ -192,47 +192,42 @@ msgctxt "NetplayCreate" msgid "Netplay: Create Session" msgstr "Netplay : créer une session" -#: src/ui/gui/netplay_create.slint:23 +#: src/ui/gui/netplay_create.slint:22 msgctxt "NetplayCreate" msgid "Session Name:" msgstr "Nom de la session :" -#: src/ui/gui/netplay_create.slint:27 +#: src/ui/gui/netplay_create.slint:26 msgctxt "NetplayCreate" msgid "Enter session name" msgstr "Saisir le nom de la session" -#: src/ui/gui/netplay_create.slint:37 +#: src/ui/gui/netplay_create.slint:36 msgctxt "NetplayCreate" msgid "Password (Optional):" msgstr "Mot de passe (facultatif) :" -#: src/ui/gui/netplay_create.slint:41 +#: src/ui/gui/netplay_create.slint:40 msgctxt "NetplayCreate" msgid "Enter session password" msgstr "Saisir le mot de passe de la session" -#: src/ui/gui/netplay_create.slint:52 +#: src/ui/gui/netplay_create.slint:51 msgctxt "NetplayCreate" msgid "Player Name:" msgstr "Nom du joueur :" -#: src/ui/gui/netplay_create.slint:56 +#: src/ui/gui/netplay_create.slint:55 msgctxt "NetplayCreate" msgid "Enter player name" msgstr "Saisir le nom du joueur" #: src/ui/gui/netplay_create.slint:66 msgctxt "NetplayCreate" -msgid "Server:" -msgstr "Serveur :" - -#: src/ui/gui/netplay_create.slint:86 -msgctxt "NetplayCreate" msgid "Select ROM" msgstr "Sélectionner une ROM" -#: src/ui/gui/netplay_create.slint:102 +#: src/ui/gui/netplay_create.slint:82 msgctxt "NetplayCreate" msgid "" "This game has cheats enabled. Cheats will be synchronized with other players." @@ -240,21 +235,16 @@ msgstr "" "La triche est activée pour ce jeu. Elle sera synchronisée avec les autres " "joueurs." -#: src/ui/gui/netplay_create.slint:112 +#: src/ui/gui/netplay_create.slint:91 msgctxt "NetplayCreate" msgid "Create Session" msgstr "Créer la session" -#: src/ui/gui/netplay_create.slint:132 +#: src/ui/gui/netplay_create.slint:105 msgctxt "NetplayCreate" msgid "Cancel" msgstr "Annuler" -#: src/ui/gui/netplay_create.slint:155 -msgctxt "CustomServerDialog" -msgid "Enter a custom server URL" -msgstr "Saisir l'URL personnalisée du serveur" - #: src/ui/gui/netplay_join.slint:7 msgctxt "NetplayJoin" msgid "Netplay: Join Session" @@ -275,153 +265,143 @@ msgctxt "NetplayJoin" msgid "Password (if required)" msgstr "Mot de passe (si requis)" -#: src/ui/gui/netplay_join.slint:41 -msgctxt "NetplayJoin" -msgid "Custom Server URL (optional):" -msgstr "URL personnalisée du serveur (facultatif) :" - -#: src/ui/gui/netplay_join.slint:53 +#: src/ui/gui/netplay_join.slint:42 msgctxt "NetplayJoin" msgid "Select ROM" msgstr "Sélectionner une ROM" -#: src/ui/gui/netplay_join.slint:68 +#: src/ui/gui/netplay_join.slint:57 msgctxt "NetplayJoin" msgid "Refreshing session list, please wait..." msgstr "Actualisation de la liste des sessions, veuillez patienter…" -#: src/ui/gui/netplay_join.slint:73 +#: src/ui/gui/netplay_join.slint:62 msgctxt "NetplayJoin" msgid "Click on a session below to select it" msgstr "Cliquez sur une session ci-dessous pour la sélectionner" -#: src/ui/gui/netplay_join.slint:78 +#: src/ui/gui/netplay_join.slint:67 msgctxt "NetplayJoin" msgid "No sessions available. Please refresh to check again." msgstr "" "Aucune session disponible. Veuillez actualiser pour vérifier à nouveau." -#: src/ui/gui/netplay_join.slint:84 -msgctxt "NetplayJoin" -msgid "Server" -msgstr "Serveur" - -#: src/ui/gui/netplay_join.slint:85 +#: src/ui/gui/netplay_join.slint:73 msgctxt "NetplayJoin" msgid "Session Name" msgstr "Nom de la session" -#: src/ui/gui/netplay_join.slint:86 +#: src/ui/gui/netplay_join.slint:74 msgctxt "NetplayJoin" msgid "Game Name" msgstr "Nom du jeu" -#: src/ui/gui/netplay_join.slint:87 +#: src/ui/gui/netplay_join.slint:75 msgctxt "NetplayJoin" msgid "Password" msgstr "Mot de passe" -#: src/ui/gui/netplay_join.slint:88 +#: src/ui/gui/netplay_join.slint:76 msgctxt "NetplayJoin" msgid "Cheats" msgstr "Triche" -#: src/ui/gui/netplay_join.slint:102 +#: src/ui/gui/netplay_join.slint:90 msgctxt "NetplayJoin" msgid "Refresh Session List" msgstr "Actualiser la liste" -#: src/ui/gui/netplay_join.slint:119 +#: src/ui/gui/netplay_join.slint:105 msgctxt "NetplayJoin" msgid "Join Session" msgstr "Rejoindre la session" -#: src/ui/gui/netplay_join.slint:132 +#: src/ui/gui/netplay_join.slint:117 msgctxt "NetplayJoin" msgid "Cancel" msgstr "Annuler" -#: src/ui/gui/netplay_page.slint:37 +#: src/ui/gui/netplay_page.slint:31 msgctxt "Netplay" msgid "Netplay" msgstr "Netplay" -#: src/ui/gui/netplay_page.slint:45 +#: src/ui/gui/netplay_page.slint:39 msgctxt "Netplay" msgid "Create Session" msgstr "Créer une session" -#: src/ui/gui/netplay_page.slint:56 +#: src/ui/gui/netplay_page.slint:50 msgctxt "Netplay" msgid "Join Session" msgstr "Rejoindre une session" -#: src/ui/gui/netplay_page.slint:70 +#: src/ui/gui/netplay_page.slint:64 msgctxt "Netplay" msgid "Netplay Discord Channel" msgstr "Salon Discord Netplay" -#: src/ui/gui/netplay_page.slint:77 +#: src/ui/gui/netplay_page.slint:71 msgctxt "Netplay" msgid "Provide Feedback" msgstr "Donner votre avis" -#: src/ui/gui/netplay_wait.slint:15 +#: src/ui/gui/netplay_wait.slint:14 msgctxt "NetplayWait" msgid "Netplay: Waiting Room" msgstr "Netplay : salle d'attente" -#: src/ui/gui/netplay_wait.slint:27 +#: src/ui/gui/netplay_wait.slint:26 msgctxt "NetplayWait" msgid "Session Name:" msgstr "Nom de la session :" -#: src/ui/gui/netplay_wait.slint:33 +#: src/ui/gui/netplay_wait.slint:32 msgctxt "NetplayWait" msgid "Game Name:" msgstr "Nom du jeu :" -#: src/ui/gui/netplay_wait.slint:39 -msgctxt "NetplayWait" -msgid "Ping:" -msgstr "Ping :" - -#: src/ui/gui/netplay_wait.slint:48 +#: src/ui/gui/netplay_wait.slint:42 msgctxt "NetplayWait" msgid "Player 1:" msgstr "Joueur 1 :" -#: src/ui/gui/netplay_wait.slint:52 +#: src/ui/gui/netplay_wait.slint:46 msgctxt "NetplayWait" msgid "Player 2:" msgstr "Joueur 2 :" -#: src/ui/gui/netplay_wait.slint:58 +#: src/ui/gui/netplay_wait.slint:52 msgctxt "NetplayWait" msgid "Player 3:" msgstr "Joueur 3 :" -#: src/ui/gui/netplay_wait.slint:62 +#: src/ui/gui/netplay_wait.slint:56 msgctxt "NetplayWait" msgid "Player 4:" msgstr "Joueur 4 :" -#: src/ui/gui/netplay_wait.slint:76 +#: src/ui/gui/netplay_wait.slint:70 msgctxt "NetplayWait" msgid "Enter chat message" msgstr "Saisir un message" -#: src/ui/gui/netplay_wait.slint:87 +#: src/ui/gui/netplay_wait.slint:81 msgctxt "NetplayWait" msgid "Send Message" msgstr "Envoyer" -#: src/ui/gui/netplay_wait.slint:105 +#: src/ui/gui/netplay_wait.slint:98 +msgctxt "NetplayWait" +msgid "Local Input Delay:" +msgstr "Délai d'entrée local :" + +#: src/ui/gui/netplay_wait.slint:115 msgctxt "NetplayWait" msgid "Start Game" msgstr "Lancer la partie" -#: src/ui/gui/netplay_wait.slint:113 +#: src/ui/gui/netplay_wait.slint:123 msgctxt "NetplayWait" msgid "Cancel" msgstr "Annuler" @@ -556,6 +536,26 @@ msgctxt "VruDialog" msgid "What Would You Like To Say?" msgstr "Que souhaitez-vous dire ?" +#~ msgctxt "NetplayCreate" +#~ msgid "Server:" +#~ msgstr "Serveur :" + +#~ msgctxt "CustomServerDialog" +#~ msgid "Enter a custom server URL" +#~ msgstr "Saisir l'URL personnalisée du serveur" + +#~ msgctxt "NetplayJoin" +#~ msgid "Custom Server URL (optional):" +#~ msgstr "URL personnalisée du serveur (facultatif) :" + +#~ msgctxt "NetplayJoin" +#~ msgid "Server" +#~ msgstr "Serveur" + +#~ msgctxt "NetplayWait" +#~ msgid "Ping:" +#~ msgstr "Ping :" + #~ msgctxt "NetplayCreate" #~ msgid "Creating server, please wait...This may take about 30 seconds." #~ msgstr "" diff --git a/data/translations/gopher64.pot b/data/translations/gopher64.pot index fc298e63..e261d474 100644 --- a/data/translations/gopher64.pot +++ b/data/translations/gopher64.pot @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2026-05-30 16:03+0000\n" +"POT-Creation-Date: 2026-06-04 13:13+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -47,37 +47,37 @@ msgctxt "About" msgid "Donate (via GitHub)" msgstr "" -#: src/ui/gui/appwindow.slint:152 +#: src/ui/gui/appwindow.slint:145 msgctxt "Menu" msgid "Local Game" msgstr "" -#: src/ui/gui/appwindow.slint:156 +#: src/ui/gui/appwindow.slint:149 msgctxt "Menu" msgid "Controller Config" msgstr "" -#: src/ui/gui/appwindow.slint:160 +#: src/ui/gui/appwindow.slint:153 msgctxt "Menu" msgid "Netplay" msgstr "" -#: src/ui/gui/appwindow.slint:164 +#: src/ui/gui/appwindow.slint:157 msgctxt "Menu" msgid "Cheats" msgstr "" -#: src/ui/gui/appwindow.slint:168 +#: src/ui/gui/appwindow.slint:161 msgctxt "Menu" msgid "RetroAchievements" msgstr "" -#: src/ui/gui/appwindow.slint:172 +#: src/ui/gui/appwindow.slint:165 msgctxt "Menu" msgid "Settings" msgstr "" -#: src/ui/gui/appwindow.slint:176 +#: src/ui/gui/appwindow.slint:169 msgctxt "Menu" msgid "About" msgstr "" @@ -192,67 +192,57 @@ msgctxt "NetplayCreate" msgid "Netplay: Create Session" msgstr "" -#: src/ui/gui/netplay_create.slint:23 +#: src/ui/gui/netplay_create.slint:22 msgctxt "NetplayCreate" msgid "Session Name:" msgstr "" -#: src/ui/gui/netplay_create.slint:27 +#: src/ui/gui/netplay_create.slint:26 msgctxt "NetplayCreate" msgid "Enter session name" msgstr "" -#: src/ui/gui/netplay_create.slint:37 +#: src/ui/gui/netplay_create.slint:36 msgctxt "NetplayCreate" msgid "Password (Optional):" msgstr "" -#: src/ui/gui/netplay_create.slint:41 +#: src/ui/gui/netplay_create.slint:40 msgctxt "NetplayCreate" msgid "Enter session password" msgstr "" -#: src/ui/gui/netplay_create.slint:52 +#: src/ui/gui/netplay_create.slint:51 msgctxt "NetplayCreate" msgid "Player Name:" msgstr "" -#: src/ui/gui/netplay_create.slint:56 +#: src/ui/gui/netplay_create.slint:55 msgctxt "NetplayCreate" msgid "Enter player name" msgstr "" #: src/ui/gui/netplay_create.slint:66 msgctxt "NetplayCreate" -msgid "Server:" -msgstr "" - -#: src/ui/gui/netplay_create.slint:86 -msgctxt "NetplayCreate" msgid "Select ROM" msgstr "" -#: src/ui/gui/netplay_create.slint:102 +#: src/ui/gui/netplay_create.slint:82 msgctxt "NetplayCreate" msgid "" "This game has cheats enabled. Cheats will be synchronized with other players." msgstr "" -#: src/ui/gui/netplay_create.slint:112 +#: src/ui/gui/netplay_create.slint:91 msgctxt "NetplayCreate" msgid "Create Session" msgstr "" -#: src/ui/gui/netplay_create.slint:132 +#: src/ui/gui/netplay_create.slint:105 msgctxt "NetplayCreate" msgid "Cancel" msgstr "" -#: src/ui/gui/netplay_create.slint:155 -msgctxt "CustomServerDialog" -msgid "Enter a custom server URL" -msgstr "" - #: src/ui/gui/netplay_join.slint:7 msgctxt "NetplayJoin" msgid "Netplay: Join Session" @@ -273,152 +263,142 @@ msgctxt "NetplayJoin" msgid "Password (if required)" msgstr "" -#: src/ui/gui/netplay_join.slint:41 -msgctxt "NetplayJoin" -msgid "Custom Server URL (optional):" -msgstr "" - -#: src/ui/gui/netplay_join.slint:53 +#: src/ui/gui/netplay_join.slint:42 msgctxt "NetplayJoin" msgid "Select ROM" msgstr "" -#: src/ui/gui/netplay_join.slint:68 +#: src/ui/gui/netplay_join.slint:57 msgctxt "NetplayJoin" msgid "Refreshing session list, please wait..." msgstr "" -#: src/ui/gui/netplay_join.slint:73 +#: src/ui/gui/netplay_join.slint:62 msgctxt "NetplayJoin" msgid "Click on a session below to select it" msgstr "" -#: src/ui/gui/netplay_join.slint:78 +#: src/ui/gui/netplay_join.slint:67 msgctxt "NetplayJoin" msgid "No sessions available. Please refresh to check again." msgstr "" -#: src/ui/gui/netplay_join.slint:84 -msgctxt "NetplayJoin" -msgid "Server" -msgstr "" - -#: src/ui/gui/netplay_join.slint:85 +#: src/ui/gui/netplay_join.slint:73 msgctxt "NetplayJoin" msgid "Session Name" msgstr "" -#: src/ui/gui/netplay_join.slint:86 +#: src/ui/gui/netplay_join.slint:74 msgctxt "NetplayJoin" msgid "Game Name" msgstr "" -#: src/ui/gui/netplay_join.slint:87 +#: src/ui/gui/netplay_join.slint:75 msgctxt "NetplayJoin" msgid "Password" msgstr "" -#: src/ui/gui/netplay_join.slint:88 +#: src/ui/gui/netplay_join.slint:76 msgctxt "NetplayJoin" msgid "Cheats" msgstr "" -#: src/ui/gui/netplay_join.slint:102 +#: src/ui/gui/netplay_join.slint:90 msgctxt "NetplayJoin" msgid "Refresh Session List" msgstr "" -#: src/ui/gui/netplay_join.slint:119 +#: src/ui/gui/netplay_join.slint:105 msgctxt "NetplayJoin" msgid "Join Session" msgstr "" -#: src/ui/gui/netplay_join.slint:132 +#: src/ui/gui/netplay_join.slint:117 msgctxt "NetplayJoin" msgid "Cancel" msgstr "" -#: src/ui/gui/netplay_page.slint:37 +#: src/ui/gui/netplay_page.slint:31 msgctxt "Netplay" msgid "Netplay" msgstr "" -#: src/ui/gui/netplay_page.slint:45 +#: src/ui/gui/netplay_page.slint:39 msgctxt "Netplay" msgid "Create Session" msgstr "" -#: src/ui/gui/netplay_page.slint:56 +#: src/ui/gui/netplay_page.slint:50 msgctxt "Netplay" msgid "Join Session" msgstr "" -#: src/ui/gui/netplay_page.slint:70 +#: src/ui/gui/netplay_page.slint:64 msgctxt "Netplay" msgid "Netplay Discord Channel" msgstr "" -#: src/ui/gui/netplay_page.slint:77 +#: src/ui/gui/netplay_page.slint:71 msgctxt "Netplay" msgid "Provide Feedback" msgstr "" -#: src/ui/gui/netplay_wait.slint:15 +#: src/ui/gui/netplay_wait.slint:14 msgctxt "NetplayWait" msgid "Netplay: Waiting Room" msgstr "" -#: src/ui/gui/netplay_wait.slint:27 +#: src/ui/gui/netplay_wait.slint:26 msgctxt "NetplayWait" msgid "Session Name:" msgstr "" -#: src/ui/gui/netplay_wait.slint:33 +#: src/ui/gui/netplay_wait.slint:32 msgctxt "NetplayWait" msgid "Game Name:" msgstr "" -#: src/ui/gui/netplay_wait.slint:39 -msgctxt "NetplayWait" -msgid "Ping:" -msgstr "" - -#: src/ui/gui/netplay_wait.slint:48 +#: src/ui/gui/netplay_wait.slint:42 msgctxt "NetplayWait" msgid "Player 1:" msgstr "" -#: src/ui/gui/netplay_wait.slint:52 +#: src/ui/gui/netplay_wait.slint:46 msgctxt "NetplayWait" msgid "Player 2:" msgstr "" -#: src/ui/gui/netplay_wait.slint:58 +#: src/ui/gui/netplay_wait.slint:52 msgctxt "NetplayWait" msgid "Player 3:" msgstr "" -#: src/ui/gui/netplay_wait.slint:62 +#: src/ui/gui/netplay_wait.slint:56 msgctxt "NetplayWait" msgid "Player 4:" msgstr "" -#: src/ui/gui/netplay_wait.slint:76 +#: src/ui/gui/netplay_wait.slint:70 msgctxt "NetplayWait" msgid "Enter chat message" msgstr "" -#: src/ui/gui/netplay_wait.slint:87 +#: src/ui/gui/netplay_wait.slint:81 msgctxt "NetplayWait" msgid "Send Message" msgstr "" -#: src/ui/gui/netplay_wait.slint:105 +#: src/ui/gui/netplay_wait.slint:98 +msgctxt "NetplayWait" +msgid "Local Input Delay:" +msgstr "" + +#: src/ui/gui/netplay_wait.slint:115 msgctxt "NetplayWait" msgid "Start Game" msgstr "" -#: src/ui/gui/netplay_wait.slint:113 +#: src/ui/gui/netplay_wait.slint:123 msgctxt "NetplayWait" msgid "Cancel" msgstr "" diff --git a/data/translations/ja/LC_MESSAGES/gopher64.po b/data/translations/ja/LC_MESSAGES/gopher64.po index 24c2075c..de66b357 100644 --- a/data/translations/ja/LC_MESSAGES/gopher64.po +++ b/data/translations/ja/LC_MESSAGES/gopher64.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: gopher64\n" -"POT-Creation-Date: 2026-05-30 16:03+0000\n" +"POT-Creation-Date: 2026-06-04 13:13+0000\n" "PO-Revision-Date: 2026-05-11 12:00+0000\n" "Last-Translator: \n" "Language-Team: Japanese\n" @@ -47,37 +47,37 @@ msgctxt "About" msgid "Donate (via GitHub)" msgstr "GitHubで寄付" -#: src/ui/gui/appwindow.slint:152 +#: src/ui/gui/appwindow.slint:145 msgctxt "Menu" msgid "Local Game" msgstr "ローカルゲーム" -#: src/ui/gui/appwindow.slint:156 +#: src/ui/gui/appwindow.slint:149 msgctxt "Menu" msgid "Controller Config" msgstr "コントローラー設定" -#: src/ui/gui/appwindow.slint:160 +#: src/ui/gui/appwindow.slint:153 msgctxt "Menu" msgid "Netplay" msgstr "ネットプレイ" -#: src/ui/gui/appwindow.slint:164 +#: src/ui/gui/appwindow.slint:157 msgctxt "Menu" msgid "Cheats" msgstr "チート" -#: src/ui/gui/appwindow.slint:168 +#: src/ui/gui/appwindow.slint:161 msgctxt "Menu" msgid "RetroAchievements" msgstr "RetroAchievements" -#: src/ui/gui/appwindow.slint:172 +#: src/ui/gui/appwindow.slint:165 msgctxt "Menu" msgid "Settings" msgstr "設定" -#: src/ui/gui/appwindow.slint:176 +#: src/ui/gui/appwindow.slint:169 msgctxt "Menu" msgid "About" msgstr "バージョン情報" @@ -192,67 +192,57 @@ msgctxt "NetplayCreate" msgid "Netplay: Create Session" msgstr "ネットプレイ:セッション作成" -#: src/ui/gui/netplay_create.slint:23 +#: src/ui/gui/netplay_create.slint:22 msgctxt "NetplayCreate" msgid "Session Name:" msgstr "セッション名:" -#: src/ui/gui/netplay_create.slint:27 +#: src/ui/gui/netplay_create.slint:26 msgctxt "NetplayCreate" msgid "Enter session name" msgstr "セッション名を入力" -#: src/ui/gui/netplay_create.slint:37 +#: src/ui/gui/netplay_create.slint:36 msgctxt "NetplayCreate" msgid "Password (Optional):" msgstr "パスワード(任意):" -#: src/ui/gui/netplay_create.slint:41 +#: src/ui/gui/netplay_create.slint:40 msgctxt "NetplayCreate" msgid "Enter session password" msgstr "セッションのパスワードを入力" -#: src/ui/gui/netplay_create.slint:52 +#: src/ui/gui/netplay_create.slint:51 msgctxt "NetplayCreate" msgid "Player Name:" msgstr "プレイヤー名:" -#: src/ui/gui/netplay_create.slint:56 +#: src/ui/gui/netplay_create.slint:55 msgctxt "NetplayCreate" msgid "Enter player name" msgstr "プレイヤー名を入力" #: src/ui/gui/netplay_create.slint:66 msgctxt "NetplayCreate" -msgid "Server:" -msgstr "サーバー:" - -#: src/ui/gui/netplay_create.slint:86 -msgctxt "NetplayCreate" msgid "Select ROM" msgstr "ROMを選択" -#: src/ui/gui/netplay_create.slint:102 +#: src/ui/gui/netplay_create.slint:82 msgctxt "NetplayCreate" msgid "" "This game has cheats enabled. Cheats will be synchronized with other players." msgstr "このゲームではチートが有効です。チートは他のプレイヤーと同期されます。" -#: src/ui/gui/netplay_create.slint:112 +#: src/ui/gui/netplay_create.slint:91 msgctxt "NetplayCreate" msgid "Create Session" msgstr "セッションを作成" -#: src/ui/gui/netplay_create.slint:132 +#: src/ui/gui/netplay_create.slint:105 msgctxt "NetplayCreate" msgid "Cancel" msgstr "キャンセル" -#: src/ui/gui/netplay_create.slint:155 -msgctxt "CustomServerDialog" -msgid "Enter a custom server URL" -msgstr "カスタムサーバーURLを入力" - #: src/ui/gui/netplay_join.slint:7 msgctxt "NetplayJoin" msgid "Netplay: Join Session" @@ -273,152 +263,142 @@ msgctxt "NetplayJoin" msgid "Password (if required)" msgstr "パスワード(必要な場合)" -#: src/ui/gui/netplay_join.slint:41 -msgctxt "NetplayJoin" -msgid "Custom Server URL (optional):" -msgstr "カスタムサーバーURL(任意):" - -#: src/ui/gui/netplay_join.slint:53 +#: src/ui/gui/netplay_join.slint:42 msgctxt "NetplayJoin" msgid "Select ROM" msgstr "ROMを選択" -#: src/ui/gui/netplay_join.slint:68 +#: src/ui/gui/netplay_join.slint:57 msgctxt "NetplayJoin" msgid "Refreshing session list, please wait..." msgstr "セッション一覧を更新しています。しばらくお待ちください…" -#: src/ui/gui/netplay_join.slint:73 +#: src/ui/gui/netplay_join.slint:62 msgctxt "NetplayJoin" msgid "Click on a session below to select it" msgstr "下の一覧からセッションをクリックして選択" -#: src/ui/gui/netplay_join.slint:78 +#: src/ui/gui/netplay_join.slint:67 msgctxt "NetplayJoin" msgid "No sessions available. Please refresh to check again." msgstr "利用できるセッションがありません。更新して再度確認してください。" -#: src/ui/gui/netplay_join.slint:84 -msgctxt "NetplayJoin" -msgid "Server" -msgstr "サーバー" - -#: src/ui/gui/netplay_join.slint:85 +#: src/ui/gui/netplay_join.slint:73 msgctxt "NetplayJoin" msgid "Session Name" msgstr "セッション名" -#: src/ui/gui/netplay_join.slint:86 +#: src/ui/gui/netplay_join.slint:74 msgctxt "NetplayJoin" msgid "Game Name" msgstr "ゲーム名" -#: src/ui/gui/netplay_join.slint:87 +#: src/ui/gui/netplay_join.slint:75 msgctxt "NetplayJoin" msgid "Password" msgstr "パスワード" -#: src/ui/gui/netplay_join.slint:88 +#: src/ui/gui/netplay_join.slint:76 msgctxt "NetplayJoin" msgid "Cheats" msgstr "チート" -#: src/ui/gui/netplay_join.slint:102 +#: src/ui/gui/netplay_join.slint:90 msgctxt "NetplayJoin" msgid "Refresh Session List" msgstr "セッション一覧を更新" -#: src/ui/gui/netplay_join.slint:119 +#: src/ui/gui/netplay_join.slint:105 msgctxt "NetplayJoin" msgid "Join Session" msgstr "セッションに参加" -#: src/ui/gui/netplay_join.slint:132 +#: src/ui/gui/netplay_join.slint:117 msgctxt "NetplayJoin" msgid "Cancel" msgstr "キャンセル" -#: src/ui/gui/netplay_page.slint:37 +#: src/ui/gui/netplay_page.slint:31 msgctxt "Netplay" msgid "Netplay" msgstr "ネットプレイ" -#: src/ui/gui/netplay_page.slint:45 +#: src/ui/gui/netplay_page.slint:39 msgctxt "Netplay" msgid "Create Session" msgstr "セッションを作成" -#: src/ui/gui/netplay_page.slint:56 +#: src/ui/gui/netplay_page.slint:50 msgctxt "Netplay" msgid "Join Session" msgstr "セッションに参加" -#: src/ui/gui/netplay_page.slint:70 +#: src/ui/gui/netplay_page.slint:64 msgctxt "Netplay" msgid "Netplay Discord Channel" msgstr "ネットプレイ用Discordチャンネル" -#: src/ui/gui/netplay_page.slint:77 +#: src/ui/gui/netplay_page.slint:71 msgctxt "Netplay" msgid "Provide Feedback" msgstr "フィードバックを送る" -#: src/ui/gui/netplay_wait.slint:15 +#: src/ui/gui/netplay_wait.slint:14 msgctxt "NetplayWait" msgid "Netplay: Waiting Room" msgstr "ネットプレイ:待機室" -#: src/ui/gui/netplay_wait.slint:27 +#: src/ui/gui/netplay_wait.slint:26 msgctxt "NetplayWait" msgid "Session Name:" msgstr "セッション名:" -#: src/ui/gui/netplay_wait.slint:33 +#: src/ui/gui/netplay_wait.slint:32 msgctxt "NetplayWait" msgid "Game Name:" msgstr "ゲーム名:" -#: src/ui/gui/netplay_wait.slint:39 -msgctxt "NetplayWait" -msgid "Ping:" -msgstr "Ping:" - -#: src/ui/gui/netplay_wait.slint:48 +#: src/ui/gui/netplay_wait.slint:42 msgctxt "NetplayWait" msgid "Player 1:" msgstr "プレイヤー1:" -#: src/ui/gui/netplay_wait.slint:52 +#: src/ui/gui/netplay_wait.slint:46 msgctxt "NetplayWait" msgid "Player 2:" msgstr "プレイヤー2:" -#: src/ui/gui/netplay_wait.slint:58 +#: src/ui/gui/netplay_wait.slint:52 msgctxt "NetplayWait" msgid "Player 3:" msgstr "プレイヤー3:" -#: src/ui/gui/netplay_wait.slint:62 +#: src/ui/gui/netplay_wait.slint:56 msgctxt "NetplayWait" msgid "Player 4:" msgstr "プレイヤー4:" -#: src/ui/gui/netplay_wait.slint:76 +#: src/ui/gui/netplay_wait.slint:70 msgctxt "NetplayWait" msgid "Enter chat message" msgstr "チャットメッセージを入力" -#: src/ui/gui/netplay_wait.slint:87 +#: src/ui/gui/netplay_wait.slint:81 msgctxt "NetplayWait" msgid "Send Message" msgstr "送信" -#: src/ui/gui/netplay_wait.slint:105 +#: src/ui/gui/netplay_wait.slint:98 +msgctxt "NetplayWait" +msgid "Local Input Delay:" +msgstr "ローカル入力遅延:" + +#: src/ui/gui/netplay_wait.slint:115 msgctxt "NetplayWait" msgid "Start Game" msgstr "ゲーム開始" -#: src/ui/gui/netplay_wait.slint:113 +#: src/ui/gui/netplay_wait.slint:123 msgctxt "NetplayWait" msgid "Cancel" msgstr "キャンセル" @@ -553,6 +533,26 @@ msgctxt "VruDialog" msgid "What Would You Like To Say?" msgstr "何と言いますか?" +#~ msgctxt "NetplayCreate" +#~ msgid "Server:" +#~ msgstr "サーバー:" + +#~ msgctxt "CustomServerDialog" +#~ msgid "Enter a custom server URL" +#~ msgstr "カスタムサーバーURLを入力" + +#~ msgctxt "NetplayJoin" +#~ msgid "Custom Server URL (optional):" +#~ msgstr "カスタムサーバーURL(任意):" + +#~ msgctxt "NetplayJoin" +#~ msgid "Server" +#~ msgstr "サーバー" + +#~ msgctxt "NetplayWait" +#~ msgid "Ping:" +#~ msgstr "Ping:" + #~ msgctxt "NetplayCreate" #~ msgid "Creating server, please wait...This may take about 30 seconds." #~ msgstr "" diff --git a/data/translations/nl/LC_MESSAGES/gopher64.po b/data/translations/nl/LC_MESSAGES/gopher64.po index 17ee82d6..3a1cffde 100644 --- a/data/translations/nl/LC_MESSAGES/gopher64.po +++ b/data/translations/nl/LC_MESSAGES/gopher64.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: gopher64\n" -"POT-Creation-Date: 2026-05-30 16:03+0000\n" +"POT-Creation-Date: 2026-06-04 13:13+0000\n" "PO-Revision-Date: 2026-05-11 12:00+0000\n" "Last-Translator: \n" "Language-Team: Dutch (Netherlands)\n" @@ -47,37 +47,37 @@ msgctxt "About" msgid "Donate (via GitHub)" msgstr "Doneren (via GitHub)" -#: src/ui/gui/appwindow.slint:152 +#: src/ui/gui/appwindow.slint:145 msgctxt "Menu" msgid "Local Game" msgstr "Lokaal spel" -#: src/ui/gui/appwindow.slint:156 +#: src/ui/gui/appwindow.slint:149 msgctxt "Menu" msgid "Controller Config" msgstr "Controllerconfiguratie" -#: src/ui/gui/appwindow.slint:160 +#: src/ui/gui/appwindow.slint:153 msgctxt "Menu" msgid "Netplay" msgstr "Netplay" -#: src/ui/gui/appwindow.slint:164 +#: src/ui/gui/appwindow.slint:157 msgctxt "Menu" msgid "Cheats" msgstr "Cheats" -#: src/ui/gui/appwindow.slint:168 +#: src/ui/gui/appwindow.slint:161 msgctxt "Menu" msgid "RetroAchievements" msgstr "RetroAchievements" -#: src/ui/gui/appwindow.slint:172 +#: src/ui/gui/appwindow.slint:165 msgctxt "Menu" msgid "Settings" msgstr "Instellingen" -#: src/ui/gui/appwindow.slint:176 +#: src/ui/gui/appwindow.slint:169 msgctxt "Menu" msgid "About" msgstr "Over" @@ -192,47 +192,42 @@ msgctxt "NetplayCreate" msgid "Netplay: Create Session" msgstr "Netplay: sessie aanmaken" -#: src/ui/gui/netplay_create.slint:23 +#: src/ui/gui/netplay_create.slint:22 msgctxt "NetplayCreate" msgid "Session Name:" msgstr "Sessienaam:" -#: src/ui/gui/netplay_create.slint:27 +#: src/ui/gui/netplay_create.slint:26 msgctxt "NetplayCreate" msgid "Enter session name" msgstr "Sessienaam invoeren" -#: src/ui/gui/netplay_create.slint:37 +#: src/ui/gui/netplay_create.slint:36 msgctxt "NetplayCreate" msgid "Password (Optional):" msgstr "Wachtwoord (optioneel):" -#: src/ui/gui/netplay_create.slint:41 +#: src/ui/gui/netplay_create.slint:40 msgctxt "NetplayCreate" msgid "Enter session password" msgstr "Sessiewachtwoord invoeren" -#: src/ui/gui/netplay_create.slint:52 +#: src/ui/gui/netplay_create.slint:51 msgctxt "NetplayCreate" msgid "Player Name:" msgstr "Spelernaam:" -#: src/ui/gui/netplay_create.slint:56 +#: src/ui/gui/netplay_create.slint:55 msgctxt "NetplayCreate" msgid "Enter player name" msgstr "Spelernaam invoeren" #: src/ui/gui/netplay_create.slint:66 msgctxt "NetplayCreate" -msgid "Server:" -msgstr "Server:" - -#: src/ui/gui/netplay_create.slint:86 -msgctxt "NetplayCreate" msgid "Select ROM" msgstr "ROM selecteren" -#: src/ui/gui/netplay_create.slint:102 +#: src/ui/gui/netplay_create.slint:82 msgctxt "NetplayCreate" msgid "" "This game has cheats enabled. Cheats will be synchronized with other players." @@ -240,21 +235,16 @@ msgstr "" "Voor dit spel zijn cheats ingeschakeld. Cheats worden gesynchroniseerd met " "andere spelers." -#: src/ui/gui/netplay_create.slint:112 +#: src/ui/gui/netplay_create.slint:91 msgctxt "NetplayCreate" msgid "Create Session" msgstr "Sessie aanmaken" -#: src/ui/gui/netplay_create.slint:132 +#: src/ui/gui/netplay_create.slint:105 msgctxt "NetplayCreate" msgid "Cancel" msgstr "Annuleren" -#: src/ui/gui/netplay_create.slint:155 -msgctxt "CustomServerDialog" -msgid "Enter a custom server URL" -msgstr "Aangepaste server-URL invoeren" - #: src/ui/gui/netplay_join.slint:7 msgctxt "NetplayJoin" msgid "Netplay: Join Session" @@ -275,152 +265,142 @@ msgctxt "NetplayJoin" msgid "Password (if required)" msgstr "Wachtwoord (indien vereist)" -#: src/ui/gui/netplay_join.slint:41 -msgctxt "NetplayJoin" -msgid "Custom Server URL (optional):" -msgstr "Aangepaste server-URL (optioneel):" - -#: src/ui/gui/netplay_join.slint:53 +#: src/ui/gui/netplay_join.slint:42 msgctxt "NetplayJoin" msgid "Select ROM" msgstr "ROM selecteren" -#: src/ui/gui/netplay_join.slint:68 +#: src/ui/gui/netplay_join.slint:57 msgctxt "NetplayJoin" msgid "Refreshing session list, please wait..." msgstr "Sessielijst wordt vernieuwd, even geduld…" -#: src/ui/gui/netplay_join.slint:73 +#: src/ui/gui/netplay_join.slint:62 msgctxt "NetplayJoin" msgid "Click on a session below to select it" msgstr "Klik hieronder op een sessie om die te selecteren" -#: src/ui/gui/netplay_join.slint:78 +#: src/ui/gui/netplay_join.slint:67 msgctxt "NetplayJoin" msgid "No sessions available. Please refresh to check again." msgstr "Geen sessies beschikbaar. Vernieuw om opnieuw te controleren." -#: src/ui/gui/netplay_join.slint:84 -msgctxt "NetplayJoin" -msgid "Server" -msgstr "Server" - -#: src/ui/gui/netplay_join.slint:85 +#: src/ui/gui/netplay_join.slint:73 msgctxt "NetplayJoin" msgid "Session Name" msgstr "Sessienaam" -#: src/ui/gui/netplay_join.slint:86 +#: src/ui/gui/netplay_join.slint:74 msgctxt "NetplayJoin" msgid "Game Name" msgstr "Spelnaam" -#: src/ui/gui/netplay_join.slint:87 +#: src/ui/gui/netplay_join.slint:75 msgctxt "NetplayJoin" msgid "Password" msgstr "Wachtwoord" -#: src/ui/gui/netplay_join.slint:88 +#: src/ui/gui/netplay_join.slint:76 msgctxt "NetplayJoin" msgid "Cheats" msgstr "Cheats" -#: src/ui/gui/netplay_join.slint:102 +#: src/ui/gui/netplay_join.slint:90 msgctxt "NetplayJoin" msgid "Refresh Session List" msgstr "Sessielijst vernieuwen" -#: src/ui/gui/netplay_join.slint:119 +#: src/ui/gui/netplay_join.slint:105 msgctxt "NetplayJoin" msgid "Join Session" msgstr "Deelnemen aan sessie" -#: src/ui/gui/netplay_join.slint:132 +#: src/ui/gui/netplay_join.slint:117 msgctxt "NetplayJoin" msgid "Cancel" msgstr "Annuleren" -#: src/ui/gui/netplay_page.slint:37 +#: src/ui/gui/netplay_page.slint:31 msgctxt "Netplay" msgid "Netplay" msgstr "Netplay" -#: src/ui/gui/netplay_page.slint:45 +#: src/ui/gui/netplay_page.slint:39 msgctxt "Netplay" msgid "Create Session" msgstr "Sessie aanmaken" -#: src/ui/gui/netplay_page.slint:56 +#: src/ui/gui/netplay_page.slint:50 msgctxt "Netplay" msgid "Join Session" msgstr "Deelnemen aan sessie" -#: src/ui/gui/netplay_page.slint:70 +#: src/ui/gui/netplay_page.slint:64 msgctxt "Netplay" msgid "Netplay Discord Channel" msgstr "Netplay-Discordkanaal" -#: src/ui/gui/netplay_page.slint:77 +#: src/ui/gui/netplay_page.slint:71 msgctxt "Netplay" msgid "Provide Feedback" msgstr "Feedback geven" -#: src/ui/gui/netplay_wait.slint:15 +#: src/ui/gui/netplay_wait.slint:14 msgctxt "NetplayWait" msgid "Netplay: Waiting Room" msgstr "Netplay: wachtruimte" -#: src/ui/gui/netplay_wait.slint:27 +#: src/ui/gui/netplay_wait.slint:26 msgctxt "NetplayWait" msgid "Session Name:" msgstr "Sessienaam:" -#: src/ui/gui/netplay_wait.slint:33 +#: src/ui/gui/netplay_wait.slint:32 msgctxt "NetplayWait" msgid "Game Name:" msgstr "Spelnaam:" -#: src/ui/gui/netplay_wait.slint:39 -msgctxt "NetplayWait" -msgid "Ping:" -msgstr "Ping:" - -#: src/ui/gui/netplay_wait.slint:48 +#: src/ui/gui/netplay_wait.slint:42 msgctxt "NetplayWait" msgid "Player 1:" msgstr "Speler 1:" -#: src/ui/gui/netplay_wait.slint:52 +#: src/ui/gui/netplay_wait.slint:46 msgctxt "NetplayWait" msgid "Player 2:" msgstr "Speler 2:" -#: src/ui/gui/netplay_wait.slint:58 +#: src/ui/gui/netplay_wait.slint:52 msgctxt "NetplayWait" msgid "Player 3:" msgstr "Speler 3:" -#: src/ui/gui/netplay_wait.slint:62 +#: src/ui/gui/netplay_wait.slint:56 msgctxt "NetplayWait" msgid "Player 4:" msgstr "Speler 4:" -#: src/ui/gui/netplay_wait.slint:76 +#: src/ui/gui/netplay_wait.slint:70 msgctxt "NetplayWait" msgid "Enter chat message" msgstr "Chatbericht invoeren" -#: src/ui/gui/netplay_wait.slint:87 +#: src/ui/gui/netplay_wait.slint:81 msgctxt "NetplayWait" msgid "Send Message" msgstr "Bericht verzenden" -#: src/ui/gui/netplay_wait.slint:105 +#: src/ui/gui/netplay_wait.slint:98 +msgctxt "NetplayWait" +msgid "Local Input Delay:" +msgstr "Lokale invoervertraging:" + +#: src/ui/gui/netplay_wait.slint:115 msgctxt "NetplayWait" msgid "Start Game" msgstr "Spel starten" -#: src/ui/gui/netplay_wait.slint:113 +#: src/ui/gui/netplay_wait.slint:123 msgctxt "NetplayWait" msgid "Cancel" msgstr "Annuleren" @@ -555,6 +535,26 @@ msgctxt "VruDialog" msgid "What Would You Like To Say?" msgstr "Wat wil je zeggen?" +#~ msgctxt "NetplayCreate" +#~ msgid "Server:" +#~ msgstr "Server:" + +#~ msgctxt "CustomServerDialog" +#~ msgid "Enter a custom server URL" +#~ msgstr "Aangepaste server-URL invoeren" + +#~ msgctxt "NetplayJoin" +#~ msgid "Custom Server URL (optional):" +#~ msgstr "Aangepaste server-URL (optioneel):" + +#~ msgctxt "NetplayJoin" +#~ msgid "Server" +#~ msgstr "Server" + +#~ msgctxt "NetplayWait" +#~ msgid "Ping:" +#~ msgstr "Ping:" + #~ msgctxt "NetplayCreate" #~ msgid "Creating server, please wait...This may take about 30 seconds." #~ msgstr "" diff --git a/data/translations/pt_BR/LC_MESSAGES/gopher64.po b/data/translations/pt_BR/LC_MESSAGES/gopher64.po index f4188d74..b9742821 100644 --- a/data/translations/pt_BR/LC_MESSAGES/gopher64.po +++ b/data/translations/pt_BR/LC_MESSAGES/gopher64.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2026-05-30 16:03+0000\n" +"POT-Creation-Date: 2026-06-04 13:13+0000\n" "PO-Revision-Date: 2026-05-11 18:11-3000\n" "Last-Translator: EDUARDO CARVALHO \n" "Language-Team: LANGUAGE \n" @@ -47,37 +47,37 @@ msgctxt "About" msgid "Donate (via GitHub)" msgstr "Doações (via GitHub)" -#: src/ui/gui/appwindow.slint:152 +#: src/ui/gui/appwindow.slint:145 msgctxt "Menu" msgid "Local Game" msgstr "Jogo Local" -#: src/ui/gui/appwindow.slint:156 +#: src/ui/gui/appwindow.slint:149 msgctxt "Menu" msgid "Controller Config" msgstr "Configurar Controle" -#: src/ui/gui/appwindow.slint:160 +#: src/ui/gui/appwindow.slint:153 msgctxt "Menu" msgid "Netplay" msgstr "Netplay" -#: src/ui/gui/appwindow.slint:164 +#: src/ui/gui/appwindow.slint:157 msgctxt "Menu" msgid "Cheats" msgstr "Trapaças" -#: src/ui/gui/appwindow.slint:168 +#: src/ui/gui/appwindow.slint:161 msgctxt "Menu" msgid "RetroAchievements" msgstr "RetroAchievements" -#: src/ui/gui/appwindow.slint:172 +#: src/ui/gui/appwindow.slint:165 msgctxt "Menu" msgid "Settings" msgstr "Configurações" -#: src/ui/gui/appwindow.slint:176 +#: src/ui/gui/appwindow.slint:169 msgctxt "Menu" msgid "About" msgstr "Sobre" @@ -192,47 +192,42 @@ msgctxt "NetplayCreate" msgid "Netplay: Create Session" msgstr "Netplay: Criar Sessão" -#: src/ui/gui/netplay_create.slint:23 +#: src/ui/gui/netplay_create.slint:22 msgctxt "NetplayCreate" msgid "Session Name:" msgstr "Nome da Sessão:" -#: src/ui/gui/netplay_create.slint:27 +#: src/ui/gui/netplay_create.slint:26 msgctxt "NetplayCreate" msgid "Enter session name" msgstr "Insira nome da sessão:" -#: src/ui/gui/netplay_create.slint:37 +#: src/ui/gui/netplay_create.slint:36 msgctxt "NetplayCreate" msgid "Password (Optional):" msgstr "Senha: (Opcional):" -#: src/ui/gui/netplay_create.slint:41 +#: src/ui/gui/netplay_create.slint:40 msgctxt "NetplayCreate" msgid "Enter session password" msgstr "Insira a senha da sessão" -#: src/ui/gui/netplay_create.slint:52 +#: src/ui/gui/netplay_create.slint:51 msgctxt "NetplayCreate" msgid "Player Name:" msgstr "Nome de Jogador:" -#: src/ui/gui/netplay_create.slint:56 +#: src/ui/gui/netplay_create.slint:55 msgctxt "NetplayCreate" msgid "Enter player name" msgstr "Insira nome de jogador" #: src/ui/gui/netplay_create.slint:66 msgctxt "NetplayCreate" -msgid "Server:" -msgstr "Servidor:" - -#: src/ui/gui/netplay_create.slint:86 -msgctxt "NetplayCreate" msgid "Select ROM" msgstr "Selecionar ROM" -#: src/ui/gui/netplay_create.slint:102 +#: src/ui/gui/netplay_create.slint:82 msgctxt "NetplayCreate" msgid "" "This game has cheats enabled. Cheats will be synchronized with other players." @@ -240,21 +235,16 @@ msgstr "" "Este jogo tem trapaças habilitadas. As trapaças serão sincronizadas com " "outros jogadores." -#: src/ui/gui/netplay_create.slint:112 +#: src/ui/gui/netplay_create.slint:91 msgctxt "NetplayCreate" msgid "Create Session" msgstr "Criar Sessão" -#: src/ui/gui/netplay_create.slint:132 +#: src/ui/gui/netplay_create.slint:105 msgctxt "NetplayCreate" msgid "Cancel" msgstr "Cancelar" -#: src/ui/gui/netplay_create.slint:155 -msgctxt "CustomServerDialog" -msgid "Enter a custom server URL" -msgstr "Insira a URL personalizada do servidor" - #: src/ui/gui/netplay_join.slint:7 msgctxt "NetplayJoin" msgid "Netplay: Join Session" @@ -275,153 +265,143 @@ msgctxt "NetplayJoin" msgid "Password (if required)" msgstr "Senha (caso obrigatória)" -#: src/ui/gui/netplay_join.slint:41 -msgctxt "NetplayJoin" -msgid "Custom Server URL (optional):" -msgstr "URL Personalizada de Servidor (opcional):" - -#: src/ui/gui/netplay_join.slint:53 +#: src/ui/gui/netplay_join.slint:42 msgctxt "NetplayJoin" msgid "Select ROM" msgstr "Selecionar ROM" -#: src/ui/gui/netplay_join.slint:68 +#: src/ui/gui/netplay_join.slint:57 msgctxt "NetplayJoin" msgid "Refreshing session list, please wait..." msgstr "Recarregando lista de sessões, por favor aguarde..." -#: src/ui/gui/netplay_join.slint:73 +#: src/ui/gui/netplay_join.slint:62 msgctxt "NetplayJoin" msgid "Click on a session below to select it" msgstr "Clique em uma sessão abaixo para selecionar" -#: src/ui/gui/netplay_join.slint:78 +#: src/ui/gui/netplay_join.slint:67 msgctxt "NetplayJoin" msgid "No sessions available. Please refresh to check again." msgstr "" "Sem sessões disponíveis. Por favor recarregue para verificar novamente." -#: src/ui/gui/netplay_join.slint:84 -msgctxt "NetplayJoin" -msgid "Server" -msgstr "Servidor" - -#: src/ui/gui/netplay_join.slint:85 +#: src/ui/gui/netplay_join.slint:73 msgctxt "NetplayJoin" msgid "Session Name" msgstr "Nome da Sessão" -#: src/ui/gui/netplay_join.slint:86 +#: src/ui/gui/netplay_join.slint:74 msgctxt "NetplayJoin" msgid "Game Name" msgstr "Nome do Jogo" -#: src/ui/gui/netplay_join.slint:87 +#: src/ui/gui/netplay_join.slint:75 msgctxt "NetplayJoin" msgid "Password" msgstr "Senha" -#: src/ui/gui/netplay_join.slint:88 +#: src/ui/gui/netplay_join.slint:76 msgctxt "NetplayJoin" msgid "Cheats" msgstr "Trapaças" -#: src/ui/gui/netplay_join.slint:102 +#: src/ui/gui/netplay_join.slint:90 msgctxt "NetplayJoin" msgid "Refresh Session List" msgstr "Recarregar Lista de Sessões" -#: src/ui/gui/netplay_join.slint:119 +#: src/ui/gui/netplay_join.slint:105 msgctxt "NetplayJoin" msgid "Join Session" msgstr "Entrar na Sessão" -#: src/ui/gui/netplay_join.slint:132 +#: src/ui/gui/netplay_join.slint:117 msgctxt "NetplayJoin" msgid "Cancel" msgstr "Cancelar" -#: src/ui/gui/netplay_page.slint:37 +#: src/ui/gui/netplay_page.slint:31 msgctxt "Netplay" msgid "Netplay" msgstr "Netplay" -#: src/ui/gui/netplay_page.slint:45 +#: src/ui/gui/netplay_page.slint:39 msgctxt "Netplay" msgid "Create Session" msgstr "Criar Sessão" -#: src/ui/gui/netplay_page.slint:56 +#: src/ui/gui/netplay_page.slint:50 msgctxt "Netplay" msgid "Join Session" msgstr "Entrar na Sessão" -#: src/ui/gui/netplay_page.slint:70 +#: src/ui/gui/netplay_page.slint:64 msgctxt "Netplay" msgid "Netplay Discord Channel" msgstr "Canal de Netplay do Discord" -#: src/ui/gui/netplay_page.slint:77 +#: src/ui/gui/netplay_page.slint:71 msgctxt "Netplay" msgid "Provide Feedback" msgstr "Fornecer Feedback" -#: src/ui/gui/netplay_wait.slint:15 +#: src/ui/gui/netplay_wait.slint:14 msgctxt "NetplayWait" msgid "Netplay: Waiting Room" msgstr "Netplay: Aguardando Sala" -#: src/ui/gui/netplay_wait.slint:27 +#: src/ui/gui/netplay_wait.slint:26 msgctxt "NetplayWait" msgid "Session Name:" msgstr "Nome da Sessão:" -#: src/ui/gui/netplay_wait.slint:33 +#: src/ui/gui/netplay_wait.slint:32 msgctxt "NetplayWait" msgid "Game Name:" msgstr "Nome do Jogo:" -#: src/ui/gui/netplay_wait.slint:39 -msgctxt "NetplayWait" -msgid "Ping:" -msgstr "Ping:" - -#: src/ui/gui/netplay_wait.slint:48 +#: src/ui/gui/netplay_wait.slint:42 msgctxt "NetplayWait" msgid "Player 1:" msgstr "Jogador 1" -#: src/ui/gui/netplay_wait.slint:52 +#: src/ui/gui/netplay_wait.slint:46 msgctxt "NetplayWait" msgid "Player 2:" msgstr "Jogador 2:" -#: src/ui/gui/netplay_wait.slint:58 +#: src/ui/gui/netplay_wait.slint:52 msgctxt "NetplayWait" msgid "Player 3:" msgstr "Jogador 3:" -#: src/ui/gui/netplay_wait.slint:62 +#: src/ui/gui/netplay_wait.slint:56 msgctxt "NetplayWait" msgid "Player 4:" msgstr "Jogador 4:" -#: src/ui/gui/netplay_wait.slint:76 +#: src/ui/gui/netplay_wait.slint:70 msgctxt "NetplayWait" msgid "Enter chat message" msgstr "Escrever mensagem no chat" -#: src/ui/gui/netplay_wait.slint:87 +#: src/ui/gui/netplay_wait.slint:81 msgctxt "NetplayWait" msgid "Send Message" msgstr "Enviar Mensagem" -#: src/ui/gui/netplay_wait.slint:105 +#: src/ui/gui/netplay_wait.slint:98 +msgctxt "NetplayWait" +msgid "Local Input Delay:" +msgstr "Atraso de entrada local:" + +#: src/ui/gui/netplay_wait.slint:115 msgctxt "NetplayWait" msgid "Start Game" msgstr "Iniciar jogo" -#: src/ui/gui/netplay_wait.slint:113 +#: src/ui/gui/netplay_wait.slint:123 msgctxt "NetplayWait" msgid "Cancel" msgstr "Cancelar" @@ -556,6 +536,26 @@ msgctxt "VruDialog" msgid "What Would You Like To Say?" msgstr "O que você quer falar?" +#~ msgctxt "NetplayCreate" +#~ msgid "Server:" +#~ msgstr "Servidor:" + +#~ msgctxt "CustomServerDialog" +#~ msgid "Enter a custom server URL" +#~ msgstr "Insira a URL personalizada do servidor" + +#~ msgctxt "NetplayJoin" +#~ msgid "Custom Server URL (optional):" +#~ msgstr "URL Personalizada de Servidor (opcional):" + +#~ msgctxt "NetplayJoin" +#~ msgid "Server" +#~ msgstr "Servidor" + +#~ msgctxt "NetplayWait" +#~ msgid "Ping:" +#~ msgstr "Ping:" + #~ msgctxt "NetplayCreate" #~ msgid "Creating server, please wait...This may take about 30 seconds." #~ msgstr "" diff --git a/data/translations/ru/LC_MESSAGES/gopher64.po b/data/translations/ru/LC_MESSAGES/gopher64.po index d7699169..7ddeba67 100644 --- a/data/translations/ru/LC_MESSAGES/gopher64.po +++ b/data/translations/ru/LC_MESSAGES/gopher64.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: gopher64\n" -"POT-Creation-Date: 2026-05-30 16:03+0000\n" +"POT-Creation-Date: 2026-06-04 13:13+0000\n" "PO-Revision-Date: 2026-05-11 12:00+0000\n" "Last-Translator: \n" "Language-Team: Russian\n" @@ -47,37 +47,37 @@ msgctxt "About" msgid "Donate (via GitHub)" msgstr "Пожертвовать (через GitHub)" -#: src/ui/gui/appwindow.slint:152 +#: src/ui/gui/appwindow.slint:145 msgctxt "Menu" msgid "Local Game" msgstr "Локальная игра" -#: src/ui/gui/appwindow.slint:156 +#: src/ui/gui/appwindow.slint:149 msgctxt "Menu" msgid "Controller Config" msgstr "Настройка контроллера" -#: src/ui/gui/appwindow.slint:160 +#: src/ui/gui/appwindow.slint:153 msgctxt "Menu" msgid "Netplay" msgstr "Сетевая игра" -#: src/ui/gui/appwindow.slint:164 +#: src/ui/gui/appwindow.slint:157 msgctxt "Menu" msgid "Cheats" msgstr "Читы" -#: src/ui/gui/appwindow.slint:168 +#: src/ui/gui/appwindow.slint:161 msgctxt "Menu" msgid "RetroAchievements" msgstr "RetroAchievements" -#: src/ui/gui/appwindow.slint:172 +#: src/ui/gui/appwindow.slint:165 msgctxt "Menu" msgid "Settings" msgstr "Настройки" -#: src/ui/gui/appwindow.slint:176 +#: src/ui/gui/appwindow.slint:169 msgctxt "Menu" msgid "About" msgstr "О программе" @@ -192,68 +192,58 @@ msgctxt "NetplayCreate" msgid "Netplay: Create Session" msgstr "Сетевая игра: Создать сессию" -#: src/ui/gui/netplay_create.slint:23 +#: src/ui/gui/netplay_create.slint:22 msgctxt "NetplayCreate" msgid "Session Name:" msgstr "Имя сессии:" -#: src/ui/gui/netplay_create.slint:27 +#: src/ui/gui/netplay_create.slint:26 msgctxt "NetplayCreate" msgid "Enter session name" msgstr "Введите имя сессии" -#: src/ui/gui/netplay_create.slint:37 +#: src/ui/gui/netplay_create.slint:36 msgctxt "NetplayCreate" msgid "Password (Optional):" msgstr "Пароль (необязательно):" -#: src/ui/gui/netplay_create.slint:41 +#: src/ui/gui/netplay_create.slint:40 msgctxt "NetplayCreate" msgid "Enter session password" msgstr "Введите пароль сессии" -#: src/ui/gui/netplay_create.slint:52 +#: src/ui/gui/netplay_create.slint:51 msgctxt "NetplayCreate" msgid "Player Name:" msgstr "Имя игрока:" -#: src/ui/gui/netplay_create.slint:56 +#: src/ui/gui/netplay_create.slint:55 msgctxt "NetplayCreate" msgid "Enter player name" msgstr "Введите имя игрока" #: src/ui/gui/netplay_create.slint:66 msgctxt "NetplayCreate" -msgid "Server:" -msgstr "Сервер:" - -#: src/ui/gui/netplay_create.slint:86 -msgctxt "NetplayCreate" msgid "Select ROM" msgstr "Выбрать ROM" -#: src/ui/gui/netplay_create.slint:102 +#: src/ui/gui/netplay_create.slint:82 msgctxt "NetplayCreate" msgid "" "This game has cheats enabled. Cheats will be synchronized with other players." msgstr "" "Для этой игры включены читы. Читы будут синхронизированы с другими игроками." -#: src/ui/gui/netplay_create.slint:112 +#: src/ui/gui/netplay_create.slint:91 msgctxt "NetplayCreate" msgid "Create Session" msgstr "Создать сессию" -#: src/ui/gui/netplay_create.slint:132 +#: src/ui/gui/netplay_create.slint:105 msgctxt "NetplayCreate" msgid "Cancel" msgstr "Отмена" -#: src/ui/gui/netplay_create.slint:155 -msgctxt "CustomServerDialog" -msgid "Enter a custom server URL" -msgstr "Введите URL пользовательского сервера" - #: src/ui/gui/netplay_join.slint:7 msgctxt "NetplayJoin" msgid "Netplay: Join Session" @@ -274,152 +264,142 @@ msgctxt "NetplayJoin" msgid "Password (if required)" msgstr "Пароль (если требуется)" -#: src/ui/gui/netplay_join.slint:41 -msgctxt "NetplayJoin" -msgid "Custom Server URL (optional):" -msgstr "URL пользовательского сервера (необязательно):" - -#: src/ui/gui/netplay_join.slint:53 +#: src/ui/gui/netplay_join.slint:42 msgctxt "NetplayJoin" msgid "Select ROM" msgstr "Выбрать ROM" -#: src/ui/gui/netplay_join.slint:68 +#: src/ui/gui/netplay_join.slint:57 msgctxt "NetplayJoin" msgid "Refreshing session list, please wait..." msgstr "Обновление списка сессий, пожалуйста, подождите..." -#: src/ui/gui/netplay_join.slint:73 +#: src/ui/gui/netplay_join.slint:62 msgctxt "NetplayJoin" msgid "Click on a session below to select it" msgstr "Нажмите на сессию ниже, чтобы выбрать её" -#: src/ui/gui/netplay_join.slint:78 +#: src/ui/gui/netplay_join.slint:67 msgctxt "NetplayJoin" msgid "No sessions available. Please refresh to check again." msgstr "Нет доступных сессий. Пожалуйста, обновите, чтобы проверить снова." -#: src/ui/gui/netplay_join.slint:84 -msgctxt "NetplayJoin" -msgid "Server" -msgstr "Сервер" - -#: src/ui/gui/netplay_join.slint:85 +#: src/ui/gui/netplay_join.slint:73 msgctxt "NetplayJoin" msgid "Session Name" msgstr "Имя сессии" -#: src/ui/gui/netplay_join.slint:86 +#: src/ui/gui/netplay_join.slint:74 msgctxt "NetplayJoin" msgid "Game Name" msgstr "Название игры" -#: src/ui/gui/netplay_join.slint:87 +#: src/ui/gui/netplay_join.slint:75 msgctxt "NetplayJoin" msgid "Password" msgstr "Пароль" -#: src/ui/gui/netplay_join.slint:88 +#: src/ui/gui/netplay_join.slint:76 msgctxt "NetplayJoin" msgid "Cheats" msgstr "Читы" -#: src/ui/gui/netplay_join.slint:102 +#: src/ui/gui/netplay_join.slint:90 msgctxt "NetplayJoin" msgid "Refresh Session List" msgstr "Обновить список сессий" -#: src/ui/gui/netplay_join.slint:119 +#: src/ui/gui/netplay_join.slint:105 msgctxt "NetplayJoin" msgid "Join Session" msgstr "Присоединиться к сессии" -#: src/ui/gui/netplay_join.slint:132 +#: src/ui/gui/netplay_join.slint:117 msgctxt "NetplayJoin" msgid "Cancel" msgstr "Отмена" -#: src/ui/gui/netplay_page.slint:37 +#: src/ui/gui/netplay_page.slint:31 msgctxt "Netplay" msgid "Netplay" msgstr "Сетевая игра" -#: src/ui/gui/netplay_page.slint:45 +#: src/ui/gui/netplay_page.slint:39 msgctxt "Netplay" msgid "Create Session" msgstr "Создать сессию" -#: src/ui/gui/netplay_page.slint:56 +#: src/ui/gui/netplay_page.slint:50 msgctxt "Netplay" msgid "Join Session" msgstr "Присоединиться к сессии" -#: src/ui/gui/netplay_page.slint:70 +#: src/ui/gui/netplay_page.slint:64 msgctxt "Netplay" msgid "Netplay Discord Channel" msgstr "Канал Discord для сетевой игры" -#: src/ui/gui/netplay_page.slint:77 +#: src/ui/gui/netplay_page.slint:71 msgctxt "Netplay" msgid "Provide Feedback" msgstr "Оставить отзыв" -#: src/ui/gui/netplay_wait.slint:15 +#: src/ui/gui/netplay_wait.slint:14 msgctxt "NetplayWait" msgid "Netplay: Waiting Room" msgstr "Сетевая игра: Комната ожидания" -#: src/ui/gui/netplay_wait.slint:27 +#: src/ui/gui/netplay_wait.slint:26 msgctxt "NetplayWait" msgid "Session Name:" msgstr "Имя сессии:" -#: src/ui/gui/netplay_wait.slint:33 +#: src/ui/gui/netplay_wait.slint:32 msgctxt "NetplayWait" msgid "Game Name:" msgstr "Название игры:" -#: src/ui/gui/netplay_wait.slint:39 -msgctxt "NetplayWait" -msgid "Ping:" -msgstr "Пинг:" - -#: src/ui/gui/netplay_wait.slint:48 +#: src/ui/gui/netplay_wait.slint:42 msgctxt "NetplayWait" msgid "Player 1:" msgstr "Игрок 1:" -#: src/ui/gui/netplay_wait.slint:52 +#: src/ui/gui/netplay_wait.slint:46 msgctxt "NetplayWait" msgid "Player 2:" msgstr "Игрок 2:" -#: src/ui/gui/netplay_wait.slint:58 +#: src/ui/gui/netplay_wait.slint:52 msgctxt "NetplayWait" msgid "Player 3:" msgstr "Игрок 3:" -#: src/ui/gui/netplay_wait.slint:62 +#: src/ui/gui/netplay_wait.slint:56 msgctxt "NetplayWait" msgid "Player 4:" msgstr "Игрок 4:" -#: src/ui/gui/netplay_wait.slint:76 +#: src/ui/gui/netplay_wait.slint:70 msgctxt "NetplayWait" msgid "Enter chat message" msgstr "Введите сообщение чата" -#: src/ui/gui/netplay_wait.slint:87 +#: src/ui/gui/netplay_wait.slint:81 msgctxt "NetplayWait" msgid "Send Message" msgstr "Отправить сообщение" -#: src/ui/gui/netplay_wait.slint:105 +#: src/ui/gui/netplay_wait.slint:98 +msgctxt "NetplayWait" +msgid "Local Input Delay:" +msgstr "Локальная задержка ввода:" + +#: src/ui/gui/netplay_wait.slint:115 msgctxt "NetplayWait" msgid "Start Game" msgstr "Начать игру" -#: src/ui/gui/netplay_wait.slint:113 +#: src/ui/gui/netplay_wait.slint:123 msgctxt "NetplayWait" msgid "Cancel" msgstr "Отмена" @@ -554,6 +534,26 @@ msgctxt "VruDialog" msgid "What Would You Like To Say?" msgstr "Что вы хотите сказать?" +#~ msgctxt "NetplayCreate" +#~ msgid "Server:" +#~ msgstr "Сервер:" + +#~ msgctxt "CustomServerDialog" +#~ msgid "Enter a custom server URL" +#~ msgstr "Введите URL пользовательского сервера" + +#~ msgctxt "NetplayJoin" +#~ msgid "Custom Server URL (optional):" +#~ msgstr "URL пользовательского сервера (необязательно):" + +#~ msgctxt "NetplayJoin" +#~ msgid "Server" +#~ msgstr "Сервер" + +#~ msgctxt "NetplayWait" +#~ msgid "Ping:" +#~ msgstr "Пинг:" + #~ msgctxt "NetplayCreate" #~ msgid "Creating server, please wait...This may take about 30 seconds." #~ msgstr "" diff --git a/src/device.rs b/src/device.rs index 2dcdcc0c..37f8b5a3 100644 --- a/src/device.rs +++ b/src/device.rs @@ -244,7 +244,6 @@ pub struct Device { pub ai: ai::Ai, pub si: si::Si, pub ri: ri::Ri, - #[serde(skip, default = "set_rng")] pub rng: rand::rngs::Xoshiro256PlusPlus, pub vru: controller::vru::Vru, pub transferpaks: [controller::transferpak::TransferPak; 4], @@ -257,6 +256,7 @@ pub fn zero_m128i() -> __m128i { impl Device { pub fn clone_state(&mut self, device: &Device) { + self.rng.clone_from(&device.rng); self.cpu.clone_from(&device.cpu); self.pif.clone_from(&device.pif); self.cart.clone_from(&device.cart); @@ -275,7 +275,7 @@ impl Device { self.cheats.clone_from(&device.cheats); } - pub fn new(with_ui: bool) -> Device { + pub fn new(with_ui: bool) -> Box { let mut byte_swap: usize = 0; let test: [u8; 4] = [1, 2, 3, 4]; // if the host computer is little endian, that means the RDRAM will be stored as little endian @@ -283,7 +283,7 @@ impl Device { if u32::from_le_bytes(test) == u32::from_ne_bytes(test) { byte_swap = 3; } - Device { + Box::new(Device { netplay: None, ui: if with_ui { ui::Ui::new() @@ -299,7 +299,7 @@ impl Device { load_rewind: false, last_rewind_saved: 0.0, rewind_pool: std::sync::Arc::new(std::sync::Mutex::new( - std::collections::VecDeque::new(), + std::collections::BTreeMap::new(), )), }, cpu: cpu::Cpu { @@ -559,6 +559,6 @@ impl Device { boot: true, enabled: false, }, - } + }) } } diff --git a/src/device/cart/rom.rs b/src/device/cart/rom.rs index 51389de8..73476d8d 100644 --- a/src/device/cart/rom.rs +++ b/src/device/cart/rom.rs @@ -148,7 +148,7 @@ pub fn init(device: &mut device::Device, rom_file: &[u8]) { } } -fn is_system_pal(country: u8) -> bool { +pub fn is_system_pal(country: u8) -> bool { let pal_codes: [u8; 8] = *b"DFIPSUXY"; for i in pal_codes { if country == i { diff --git a/src/device/controller.rs b/src/device/controller.rs index 78277896..1eda9e50 100644 --- a/src/device/controller.rs +++ b/src/device/controller.rs @@ -1,4 +1,4 @@ -use crate::{device, netplay, savestates, ui}; +use crate::{device, savestates, ui}; pub mod gbcart; pub mod mempak; @@ -57,11 +57,7 @@ pub fn process(device: &mut device::Device, channel: usize) { JCMD_CONTROLLER_READ => { let offset = device.pif.channels[channel].rx_buf.unwrap(); let input = if let Some(netplay) = &mut device.netplay { - if netplay.player_number as usize == channel { - let local_input = ui::input::get(&mut device.ui, 0, device.frame_counter); - netplay::send_input(netplay, local_input); - } - netplay::get_input(device, channel) + netplay.inputs[channel].0 } else { ui::input::get(&mut device.ui, channel, device.frame_counter) }; @@ -162,7 +158,7 @@ pub fn pak_switch_event(device: &mut device::Device) { if channel.change_pak != PakType::None { //stop rumble if it is on if let Some(netplay) = &device.netplay { - if netplay.player_number as usize == i { + if netplay.player_number == i { device::ui::input::set_rumble(&device.ui, 0, 0); } } else { diff --git a/src/device/controller/rumble.rs b/src/device/controller/rumble.rs index e3bc83cf..2d5092fb 100644 --- a/src/device/controller/rumble.rs +++ b/src/device/controller/rumble.rs @@ -17,7 +17,7 @@ pub fn write(device: &mut device::Device, channel: usize, address: u16, data: us let rumble = device.pif.ram[data + size - 1]; if let Some(netplay) = &device.netplay { - if netplay.player_number as usize == channel { + if netplay.player_number == channel { device::ui::input::set_rumble(&device.ui, 0, rumble); } } else { diff --git a/src/device/pif.rs b/src/device/pif.rs index cb04b10b..fbf1f476 100644 --- a/src/device/pif.rs +++ b/src/device/pif.rs @@ -219,7 +219,7 @@ pub fn process_ram(device: &mut device::Device) { pub fn connect_pif_channels(device: &mut device::Device) { for i in 0..4 { if let Some(netplay) = &device.netplay { - if netplay.player_data[i].reg_id != 0 { + if netplay.connected[i] { device.pif.channels[i].process = Some(device::controller::process); } } else if device.ui.config.input.controller_enabled[i] { @@ -278,7 +278,7 @@ pub fn init(device: &mut device::Device) { for i in 0..4 { if let Some(netplay) = &device.netplay { - if netplay.player_data[i].reg_id != 0 { + if netplay.connected[i] { device.pif.channels[i].pak_handler = Some(default_handler); } } else if device.ui.config.input.controller_enabled[i] { diff --git a/src/device/vi.rs b/src/device/vi.rs index f33c30dc..5475a957 100644 --- a/src/device/vi.rs +++ b/src/device/vi.rs @@ -110,7 +110,15 @@ pub fn write_regs(device: &mut device::Device, address: u64, value: u32, mask: u let current_origin = device.vi.regs[reg as usize]; device::memory::masked_write_32(&mut device.vi.regs[reg as usize], value, mask); if current_origin != device.vi.regs[reg as usize] { - savestates::process_savestates(device); + if let Some(netplay) = &device.netplay { + device.netplay.as_mut().unwrap().inputs = if netplay.requests.is_empty() { + netplay::process_netplay(device) + } else { + netplay::process_requests(device) + }; + } else { + savestates::process_savestates(device); + } let _ = device.ui.video.fps_tx.as_ref().unwrap().try_send(true); } } @@ -133,15 +141,10 @@ pub fn vertical_interrupt_event(device: &mut device::Device) { retroachievements::do_frame(); - let (mut speed_limiter_toggled, paused) = ui::video::check_callback(device); + let (speed_limiter_toggled, paused) = ui::video::check_callback(device); - if let Some(netplay) = &mut device.netplay { - netplay::send_sync_check(netplay, device.cpu.cop0.regs.as_ref()); - if device.vi.enable_speed_limiter == netplay.fast_forward { - speed_limiter_toggled = true; - device.vi.enable_speed_limiter = !netplay.fast_forward; - } - } else if device.ui.config.emulation.rewind + if device.netplay.is_none() + && device.ui.config.emulation.rewind && device.vi.elapsed_time - device.savestate.last_rewind_saved > 1.0 { device.savestate.save_rewind = true; @@ -152,13 +155,17 @@ pub fn vertical_interrupt_event(device: &mut device::Device) { reset_pace_deadline(device); } - if device.frame_counter.is_multiple_of(device.vi.limit_freq) && device.vi.enable_speed_limiter { + if (device.netplay.is_none() || netplay::pending_frames(device.netplay.as_ref().unwrap()) == 0) + && device.frame_counter.is_multiple_of(device.vi.limit_freq) + && device.vi.enable_speed_limiter + { speed_limiter(device); } unsafe { sdl3_sys::events::SDL_PumpEvents() }; - - ui::video::update_screen(); + if device.netplay.is_none() || netplay::pending_frames(device.netplay.as_ref().unwrap()) == 0 { + ui::video::update_screen(); + } device.frame_counter += 1; if device.netplay.is_none() && paused { @@ -194,9 +201,18 @@ pub fn init(device: &mut device::Device) { fn speed_limiter(device: &mut device::Device) { let mut speed_limiter_toggled = false; - let interval = + let mut interval = std::time::Duration::from_secs_f64(device.vi.frame_time * device.vi.limit_freq as f64); + if let Some(netplay) = &device.netplay { + let ahead = netplay.session.frames_ahead(); + if ahead > 0 { + interval = interval.mul_f64(1.0 + 0.05 * ahead.min(2) as f64); + } else if ahead < 0 { + interval = interval.mul_f64(1.0 - 0.05 * (-ahead).min(2) as f64); + } + } + let now = std::time::Instant::now(); match device.vi.next_pace_deadline { None => { diff --git a/src/lib.rs b/src/lib.rs index e19d7f8f..fe0c6d91 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,10 +27,14 @@ pub struct Args { pub disable_expansion_pak: Option, #[arg(long, value_name = "CHEATS_FILE", hide = true)] pub cheats: Option, - #[arg(long, value_name = "NETPLAY_PEER_ADDR", hide = true)] - pub netplay_peer_addr: Option, + #[arg(long, value_name = "NETPLAY_SERVER_ADDR", hide = true)] + pub netplay_server_addr: Option, #[arg(long, value_name = "NETPLAY_PLAYER_NUMBER", hide = true)] - pub netplay_player_number: Option, + pub netplay_player_number: Option, + #[arg(long, value_name = "NETPLAY_NUMBER_OF_PLAYERS", hide = true)] + pub netplay_number_of_players: Option, + #[arg(long, value_name = "NETPLAY_INPUT_DELAY", hide = true)] + pub netplay_input_delay: Option, #[arg( long, value_name = "PROFILE_NAME", @@ -165,10 +169,18 @@ pub async fn run(args: Args, arg_count: usize) -> std::io::Result<()> { let mut shutdown_tx = None; let mut usb_handle = None; - if let Some(peer_addr) = args.netplay_peer_addr + if let Some(server_addr) = args.netplay_server_addr && let Some(player_number) = args.netplay_player_number + && let Some(number_of_players) = args.netplay_number_of_players + && let Some(input_delay) = args.netplay_input_delay { - device.netplay = Some(netplay::init(peer_addr.parse().unwrap(), player_number)); + device.netplay = Some(netplay::init( + server_addr, + player_number, + number_of_players, + input_delay, + device::cart::rom::is_system_pal(rom_contents[0x3E]), + )); } else { for i in 0..4 { if device.ui.config.input.transfer_pak[i] @@ -195,7 +207,7 @@ pub async fn run(args: Args, arg_count: usize) -> std::io::Result<()> { { let username = args.ra_username.unwrap_or(ra_config.username.clone()); retroachievements::init_client( - if cfg!(ra_hardcore_enabled) { + if cfg!(ra_hardcore_enabled) && device.netplay.is_none() { ra_config.hardcore } else { false @@ -236,9 +248,7 @@ pub async fn run(args: Args, arg_count: usize) -> std::io::Result<()> { #[cfg(not(target_os = "android"))] retroachievements::shutdown_client(); - if device.netplay.is_some() { - netplay::close(&mut device); - } else { + if device.netplay.is_none() { for i in 0..4 { if device.ui.config.input.transfer_pak[i] && !device.ui.config.input.gb_ram_path[i].is_empty() diff --git a/src/netplay.rs b/src/netplay.rs index 63e1b0df..f4970f83 100644 --- a/src/netplay.rs +++ b/src/netplay.rs @@ -1,349 +1,331 @@ -use crate::{device, ui}; -use std::io::{Read, Write}; -//UDP packet formats -const UDP_SEND_KEY_INFO: u8 = 0; -const UDP_RECEIVE_KEY_INFO: u8 = 1; -const UDP_REQUEST_KEY_INFO: u8 = 2; -const UDP_RECEIVE_KEY_INFO_GRATUITOUS: u8 = 3; -const UDP_SYNC_DATA: u8 = 4; +use crate::device; +use crate::savestates; +use crate::ui; +use sha2::digest::Digest; -//TCP packet formats -const TCP_SEND_SAVE: u8 = 1; -//const TCP_RECEIVE_SAVE: u8 = 2; -//const TCP_SEND_SETTINGS: u8 = 3; -//const TCP_RECEIVE_SETTINGS: u8 = 4; -const TCP_REGISTER_PLAYER: u8 = 5; -const TCP_GET_REGISTRATION: u8 = 6; -const TCP_DISCONNECT_NOTICE: u8 = 7; -const TCP_RECEIVE_SAVE_WITH_SIZE: u8 = 8; -const TCP_SEND_RTC: u8 = 64; -const TCP_RECEIVE_RTC: u8 = 128; -const TCP_SEND_RNG: u8 = 65; -const TCP_RECEIVE_RNG: u8 = 129; +pub struct GgrsConfig; +impl ggrs::Config for GgrsConfig { + type Input = ui::input::InputData; + type InputPredictor = ggrs::PredictRepeatLast; + type State = i32; + type Address = matchbox_socket::PeerId; +} -const CS4: u32 = 32; +pub struct MatchboxSocket(matchbox_socket::WebRtcSocket); + +impl ggrs::NonBlockingSocket for MatchboxSocket { + fn send_to(&mut self, msg: &ggrs::Message, addr: &matchbox_socket::PeerId) { + let encoded = postcard::to_stdvec(msg).expect("serialization failed"); + let channel = self.0.get_channel_mut(0).unwrap(); + if channel.config().max_retransmits != Some(0) || channel.config().ordered { + eprintln!("Sending GGRS traffic over reliable channel"); + } + channel.send(encoded.into(), *addr); + } + + fn receive_all_messages(&mut self) -> Vec<(matchbox_socket::PeerId, ggrs::Message)> { + let channel = self.0.get_channel_mut(0).unwrap(); + channel + .receive() + .iter() + .filter_map(|(peer, packet)| { + let msg = postcard::from_bytes::(packet).ok()?; + Some((*peer, msg)) + }) + .collect() + } +} pub struct Netplay { - udp_socket: std::net::UdpSocket, - tcp_stream: std::net::TcpStream, - pub player_number: u8, - pub player_data: [PlayerData; 4], - vi_counter: u32, - status: u8, - buffer_target: u8, - pub fast_forward: bool, + pub session: ggrs::P2PSession, + pub reliable_channel: matchbox_socket::WebRtcChannel, + pub peers: Vec, + pub player_number: usize, + pub connected: [bool; 4], + pub data: std::collections::HashMap>, + pub inputs: Vec<(ui::input::InputData, ggrs::InputStatus)>, + pub requests: std::collections::VecDeque>, } -pub struct PlayerData { - lag: u8, - count: u32, - pub reg_id: u32, - input_events: rustc_hash::FxHashMap, +#[derive(serde::Serialize, serde::Deserialize)] +struct NetplayMessage { + name: String, + data: Vec, } -struct InputEvent { - input: u32, - plugin: u8, +fn send_message(netplay: &mut Netplay, message: NetplayMessage) { + let data = postcard::to_stdvec(&message).unwrap(); + for peer in netplay.peers.iter() { + netplay.reliable_channel.send(data.clone().into(), *peer); + } +} + +fn receive_message(netplay: &mut Netplay, name: &str) -> Vec { + while !netplay.data.contains_key(name) { + let messages = netplay.reliable_channel.receive(); + for (_, data) in messages { + let message = postcard::from_bytes::(&data).unwrap(); + netplay.data.insert(message.name, message.data); + } + std::thread::sleep(std::time::Duration::from_millis(1)); + } + netplay.data.remove(name).unwrap() +} + +fn send_player_number( + channel: &mut matchbox_socket::WebRtcChannel, + peers: Vec, + player_number: usize, +) { + let message = NetplayMessage { + name: "player_number".to_string(), + data: player_number.to_be_bytes().to_vec(), + }; + let data = postcard::to_stdvec(&message).unwrap(); + for peer in peers { + channel.send(data.clone().into(), peer); + } +} + +fn get_player_numbers( + channel: &mut matchbox_socket::WebRtcChannel, + local_player_number: usize, + number_of_peers: usize, +) -> std::collections::BTreeMap> { + let mut player_numbers = std::collections::BTreeMap::new(); + player_numbers.insert(local_player_number, None); + while player_numbers.len() < number_of_peers + 1 { + for (peer, data) in channel.receive() { + let message = postcard::from_bytes::(&data).unwrap(); + if message.name == "player_number" { + player_numbers.insert( + usize::from_be_bytes(message.data.try_into().unwrap()), + Some(peer), + ); + } + } + std::thread::sleep(std::time::Duration::from_millis(1)); + } + player_numbers } pub fn send_rtc(netplay: &mut Netplay, rtc: i64) { - let mut request: Vec = [TCP_SEND_RTC].to_vec(); - let size: u32 = 8; - request.extend_from_slice(&size.to_be_bytes()); - request.extend_from_slice(&rtc.to_be_bytes()); - netplay.tcp_stream.write_all(&request).unwrap(); + let message = NetplayMessage { + name: "rtc".to_string(), + data: rtc.to_be_bytes().to_vec(), + }; + send_message(netplay, message); } pub fn receive_rtc(netplay: &mut Netplay) -> i64 { - let request: Vec = [TCP_RECEIVE_RTC].to_vec(); - netplay.tcp_stream.write_all(&request).unwrap(); - let mut rtc: [u8; 8] = [0; 8]; - netplay.tcp_stream.read_exact(&mut rtc).unwrap(); - i64::from_be_bytes(rtc) + let message = receive_message(netplay, "rtc"); + + i64::from_be_bytes(message.try_into().unwrap()) } pub fn send_rng(netplay: &mut Netplay, seed: u64) { - let mut request: Vec = [TCP_SEND_RNG].to_vec(); - let size: u32 = 8; - request.extend_from_slice(&size.to_be_bytes()); - request.extend_from_slice(&seed.to_be_bytes()); - netplay.tcp_stream.write_all(&request).unwrap(); + let message = NetplayMessage { + name: "rng".to_string(), + data: seed.to_be_bytes().to_vec(), + }; + send_message(netplay, message); } pub fn receive_rng(netplay: &mut Netplay) -> u64 { - let request: Vec = [TCP_RECEIVE_RNG].to_vec(); - netplay.tcp_stream.write_all(&request).unwrap(); - let mut seed: [u8; 8] = [0; 8]; - netplay.tcp_stream.read_exact(&mut seed).unwrap(); - u64::from_be_bytes(seed) + let message = receive_message(netplay, "rng"); + u64::from_be_bytes(message.try_into().unwrap()) } -pub fn send_save(netplay: &mut Netplay, save_type: &str, save_data: &[u8], size: usize) { - let mut request: Vec = [TCP_SEND_SAVE].to_vec(); - request.extend_from_slice(save_type.as_bytes()); - request.push(0); // null terminate string - request.extend_from_slice(&(size as u32).to_be_bytes()); - - if size > 0 { - request.extend_from_slice(save_data); - } - netplay.tcp_stream.write_all(&request).unwrap(); +pub fn send_save(netplay: &mut Netplay, save_type: &str, save_data: &[u8]) { + let message = NetplayMessage { + name: save_type.to_string(), + data: save_data.to_vec(), + }; + send_message(netplay, message); } pub fn receive_save(netplay: &mut Netplay, save_type: &str, save_data: &mut Vec) { - let mut request: Vec = [TCP_RECEIVE_SAVE_WITH_SIZE].to_vec(); - request.extend_from_slice(save_type.as_bytes()); - request.push(0); // null terminate string - netplay.tcp_stream.write_all(&request).unwrap(); - - let mut size: [u8; 4] = [0; 4]; - netplay.tcp_stream.read_exact(&mut size).unwrap(); - let mut response: Vec = vec![0; u32::from_be_bytes(size) as usize]; - netplay.tcp_stream.read_exact(&mut response).unwrap(); - *save_data = response; + let message = receive_message(netplay, save_type); + *save_data = message; } -pub fn send_sync_check(netplay: &mut Netplay, regs: &[u64]) { - if netplay.vi_counter.is_multiple_of(600) { - let mut request: Vec = [UDP_SYNC_DATA].to_vec(); - request.extend_from_slice(&(netplay.vi_counter).to_be_bytes()); - - for item in regs.iter() { - request.extend_from_slice(&(*item as u32).to_be_bytes()); - } - - netplay.udp_socket.send(&request).unwrap(); - } - netplay.vi_counter = netplay.vi_counter.wrapping_add(1); -} - -pub fn send_input(netplay: &Netplay, input: ui::input::InputData) { - let mut request: Vec = [UDP_SEND_KEY_INFO].to_vec(); - request.push(netplay.player_number); - request.extend_from_slice( - &(netplay.player_data[netplay.player_number as usize].count).to_be_bytes(), - ); - request.extend_from_slice(&(input.data).to_be_bytes()); - request.push(input.pak_change_pressed as u8); - netplay.udp_socket.send(&request).unwrap(); -} - -pub fn get_input(device: &mut device::Device, channel: usize) -> ui::input::InputData { - let netplay = device.netplay.as_mut().unwrap(); - let mut input = None; - - let timeout = std::time::Instant::now() + std::time::Duration::from_secs(10); - let mut request_timer = std::time::Instant::now() - std::time::Duration::from_millis(5); - while input.is_none() { - process_incoming(netplay); // we execute process_incoming before request_input so that we send an accurate buffer count - if std::time::Instant::now() > request_timer { - // sends a request packet every 5ms - request_input(netplay, channel); - request_timer = std::time::Instant::now() + std::time::Duration::from_millis(5); - } - input = netplay.player_data[channel] - .input_events - .remove(&netplay.player_data[channel].count); - - if std::time::Instant::now() > timeout { - ui::video::onscreen_message( - "Lost connection to netplay server", - ui::video::MESSAGE_LENGTH_MESSAGE_SHORT, - ); - input = Some(InputEvent { - input: 0, - plugin: 0, - }); - device.cpu.running = false; - } - } - - netplay.fast_forward = netplay.player_data[channel].lag > 0 - && netplay.player_data[channel].input_events.len() as u8 > netplay.buffer_target; - - netplay.player_data[channel].count = netplay.player_data[channel].count.wrapping_add(1); - ui::input::InputData { - data: input.as_ref().unwrap().input, - pak_change_pressed: input.as_ref().unwrap().plugin != 0, - } -} - -fn request_input(netplay: &Netplay, channel: usize) { - let mut request: Vec = [UDP_REQUEST_KEY_INFO].to_vec(); - request.push(channel as u8); //The player we need input for - request.extend_from_slice( - &(netplay.player_data[netplay.player_number as usize].reg_id).to_be_bytes(), - ); - request.extend_from_slice(&(netplay.player_data[channel].count).to_be_bytes()); - request.push(0); //spectator mode - request.push(netplay.player_data[channel].input_events.len() as u8); - netplay.udp_socket.send(&request).unwrap(); -} - -fn process_incoming(netplay: &mut Netplay) { - let mut buf: [u8; 1024] = [0; 1024]; - while netplay.udp_socket.recv(&mut buf).is_ok() { - match buf[0] { - UDP_RECEIVE_KEY_INFO | UDP_RECEIVE_KEY_INFO_GRATUITOUS => { - let player = buf[1] as usize; - //current_status is a status update from the server - //it will let us know if another player has disconnected, or the games have desynced - let current_status = buf[2]; - if buf[0] == UDP_RECEIVE_KEY_INFO { - netplay.player_data[player].lag = buf[3]; - } - if current_status != netplay.status { - if ((current_status & 0x1) ^ (netplay.status & 0x1)) != 0 { - ui::video::onscreen_message( - "Netplay desync detected", - ui::video::MESSAGE_LENGTH_MESSAGE_LONG, - ); - } - for dis in 1..5 { - if ((current_status & (0x1 << dis)) ^ (netplay.status & (0x1 << dis))) != 0 - { - ui::video::onscreen_message( - &format!("Player {dis} disconnected"), - ui::video::MESSAGE_LENGTH_MESSAGE_SHORT, - ); - } - } - netplay.status = current_status; - } - - let mut buffer_offset = 5; - for _i in 0..buf[4] { - let count = u32::from_be_bytes( - buf[buffer_offset..buffer_offset + 4].try_into().unwrap(), - ); - buffer_offset += 4; - - if (count.wrapping_sub(netplay.player_data[player].count)) > (u32::MAX / 2) { - //event doesn't need to be recorded - buffer_offset += 5; - continue; - } - - let input = u32::from_be_bytes( - buf[buffer_offset..buffer_offset + 4].try_into().unwrap(), - ); - buffer_offset += 4; - let plugin = buf[buffer_offset]; - buffer_offset += 1; - let input_event = InputEvent { input, plugin }; - netplay.player_data[player] - .input_events - .insert(count, input_event); - } - } - _ => { - panic!("unknown UDP packet") - } - } - } -} - -pub fn init(peer_addr: std::net::SocketAddr, player_number: u8) -> Netplay { - let udp_socket; - if peer_addr.is_ipv4() { - udp_socket = std::net::UdpSocket::bind((std::net::Ipv4Addr::UNSPECIFIED, 0)) - .expect("couldn't bind to address"); - socket2::SockRef::from(&udp_socket) - .set_tos_v4(CS4 << 2) - .unwrap(); - } else { - udp_socket = std::net::UdpSocket::bind((std::net::Ipv6Addr::UNSPECIFIED, 0)) - .expect("couldn't bind to address"); - #[cfg(not(target_os = "windows"))] - socket2::SockRef::from(&udp_socket) - .set_tclass_v6(CS4 << 2) - .unwrap(); - }; - - udp_socket.connect(peer_addr).unwrap(); - udp_socket.set_nonblocking(true).unwrap(); - - let mut stream = std::net::TcpStream::connect(peer_addr).unwrap(); - - let regid = (player_number + 1) as u32; - let mut request: [u8; 8] = [ - TCP_REGISTER_PLAYER, - player_number, - 0, //plugin/pak - 0, //rawdata - 0, //regid (u32) - 0, //regid (u32) - 0, //regid (u32) - 0, //regid (u32) - ]; - - request[4..8].copy_from_slice(®id.to_be_bytes()); - stream.write_all(&request).unwrap(); - - let mut response: [u8; 2] = [0, 0]; - stream.read_exact(&mut response).unwrap(); - if response[0] != 1 { - panic!("Failed to register player"); - } - let buffer_target = response[1]; - - let request: [u8; 1] = [TCP_GET_REGISTRATION]; - stream.write_all(&request).unwrap(); - let mut response: [u8; 24] = [0; 24]; - stream.read_exact(&mut response).unwrap(); - - let mut reg_id: [u32; 4] = [0; 4]; - for i in 0..4 { - // reg_id of 0 means no player connected - reg_id[i] = u32::from_be_bytes(response[(i * 6)..(i * 6) + 4].try_into().unwrap()); - } - Netplay { - udp_socket, - tcp_stream: stream, - player_number, - vi_counter: 0, - status: 0, - buffer_target, - fast_forward: false, - player_data: [ - PlayerData { - lag: 0, - count: 0, - reg_id: reg_id[0], - input_events: rustc_hash::FxHashMap::default(), - }, - PlayerData { - lag: 0, - count: 0, - reg_id: reg_id[1], - input_events: rustc_hash::FxHashMap::default(), - }, - PlayerData { - lag: 0, - count: 0, - reg_id: reg_id[2], - input_events: rustc_hash::FxHashMap::default(), - }, - PlayerData { - lag: 0, - count: 0, - reg_id: reg_id[3], - input_events: rustc_hash::FxHashMap::default(), - }, - ], - } -} - -pub fn close(device: &mut device::Device) { - let netplay = device.netplay.as_mut().unwrap(); - let regid = (netplay.player_number + 1) as u32; - let mut request: [u8; 5] = [TCP_DISCONNECT_NOTICE, 0, 0, 0, 0]; - request[1..5].copy_from_slice(®id.to_be_bytes()); - - netplay.tcp_stream.write_all(&request).unwrap(); - netplay.tcp_stream.flush().unwrap(); +pub fn pending_frames(netplay: &Netplay) -> usize { netplay - .tcp_stream - .shutdown(std::net::Shutdown::Both) - .unwrap(); + .requests + .iter() + .filter(|r| matches!(r, ggrs::GgrsRequest::AdvanceFrame { .. })) + .count() +} + +pub fn process_requests( + device: &mut device::Device, +) -> Vec<(ui::input::InputData, ggrs::InputStatus)> { + loop { + if let Some(request) = device.netplay.as_mut().unwrap().requests.pop_front() { + match request { + ggrs::GgrsRequest::SaveGameState { cell, frame } => { + savestates::create_savestate(device, true, Some(frame)); + + let mut hasher = sha2::Sha256::new(); + for reg in device.cpu.cop0.regs.as_ref() { + hasher.update(reg.to_be_bytes()); + } + let hash = u128::from_be_bytes(hasher.finalize()[..16].try_into().unwrap()); + cell.save(frame, Some(frame), Some(hash)); + } + ggrs::GgrsRequest::LoadGameState { cell, frame: _ } => { + if let Some(frame) = cell.load() { + savestates::load_savestate(device, true, Some(frame)); + } + } + ggrs::GgrsRequest::AdvanceFrame { inputs } => { + return inputs; + } + } + } else { + let netplay = device.netplay.as_mut().unwrap(); + netplay.session.poll_remote_clients(); + advance_frame(device); + } + } +} + +pub fn process_netplay( + device: &mut device::Device, +) -> Vec<(ui::input::InputData, ggrs::InputStatus)> { + let netplay = device.netplay.as_mut().unwrap(); + + netplay.session.poll_remote_clients(); + for event in netplay.session.events() { + match event { + ggrs::GgrsEvent::Synchronizing { .. } => {} + ggrs::GgrsEvent::Synchronized { .. } => {} + ggrs::GgrsEvent::Disconnected { .. } => { + ui::video::onscreen_message( + "Peer disconnected", + ui::video::MESSAGE_LENGTH_MESSAGE_LONG, + ); + } + ggrs::GgrsEvent::NetworkInterrupted { .. } => { + println!("network interrupted"); + } + ggrs::GgrsEvent::NetworkResumed { .. } => { + println!("network resumed"); + } + ggrs::GgrsEvent::WaitRecommendation { skip_frames } => { + println!("wait recommendation: skip_frames={}", skip_frames); + } + ggrs::GgrsEvent::DesyncDetected { .. } => { + ui::video::onscreen_message( + "Desync detected", + ui::video::MESSAGE_LENGTH_MESSAGE_LONG, + ); + } + } + } + + advance_frame(device); + process_requests(device) +} + +fn advance_frame(device: &mut device::Device) { + let netplay = device.netplay.as_mut().unwrap(); + let local_input = ui::input::get(&mut device.ui, 0, device.frame_counter); + let local_handle = *netplay.session.local_player_handles().first().unwrap(); + netplay + .session + .add_local_input(local_handle, local_input) + .unwrap(); + match netplay.session.advance_frame() { + Ok(requests) => { + netplay.requests.extend(requests); + } + Err(ggrs::GgrsError::PredictionThreshold) => { + println!("prediction threshold reached"); + } + Err(e) => panic!("{e}"), + } +} + +pub fn init( + server_addr: String, + player_number: usize, + number_of_players: usize, + input_delay: usize, + pal: bool, +) -> Netplay { + let (socket, loop_fut) = matchbox_socket::WebRtcSocketBuilder::new(server_addr) + .add_unreliable_channel() + .add_reliable_channel() + .build(); + tokio::spawn(async move { + if let Err(e) = loop_fut.await { + eprintln!("WebRTC loop failed: {}", e); + } + }); + let mut matchbox_socket = MatchboxSocket(socket); + let mut reliable_channel = matchbox_socket.0.take_channel(1).unwrap(); + let now = std::time::Instant::now(); + let timeout = std::time::Duration::from_secs(10); + let mut peers = vec![]; + let mut session_builder = ggrs::SessionBuilder::::new(); + loop { + matchbox_socket.0.update_peers(); + peers = matchbox_socket + .0 + .connected_peers() + .collect::>(); + if peers.len() == number_of_players - 1 { + send_player_number(&mut reliable_channel, peers.clone(), player_number); + let player_numbers = + get_player_numbers(&mut reliable_channel, player_number, peers.len()); + session_builder = session_builder + .with_num_players(number_of_players) + .unwrap() + .with_input_delay(input_delay) + .with_fps(if pal { 50 } else { 60 }) + .unwrap() + .with_desync_detection_mode(ggrs::DesyncDetection::On { interval: 60 }); + for (i, peer) in player_numbers.iter() { + if let Some(peer) = peer { + session_builder = session_builder + .add_player(ggrs::PlayerType::Remote(*peer), *i) + .unwrap(); + } else { + session_builder = session_builder + .add_player(ggrs::PlayerType::Local, *i) + .unwrap(); + } + } + + break; + } + if now.elapsed() > timeout { + break; + } + std::thread::sleep(std::time::Duration::from_millis(10)); + } + let mut session = session_builder.start_p2p_session(matchbox_socket).unwrap(); + + let now = std::time::Instant::now(); + while session.current_state() != ggrs::SessionState::Running && now.elapsed() < timeout { + session.poll_remote_clients(); + std::thread::sleep(std::time::Duration::from_millis(10)); + } + + Netplay { + session, + reliable_channel, + peers, + player_number, + connected: [ + number_of_players > 0, + number_of_players > 1, + number_of_players > 2, + number_of_players > 3, + ], + data: std::collections::HashMap::new(), + inputs: Vec::new(), + requests: std::collections::VecDeque::new(), + } } diff --git a/src/savestates.rs b/src/savestates.rs index c4831356..efd90f68 100644 --- a/src/savestates.rs +++ b/src/savestates.rs @@ -78,17 +78,18 @@ pub struct Savestate { pub load_rewind: bool, pub last_rewind_saved: f64, #[serde(skip)] - pub rewind_pool: std::sync::Arc>>, + pub rewind_pool: + std::sync::Arc>>, } pub struct SavestateData { - device: device::Device, + device: Box, saves: ui::storage::Saves, rdp_state: Vec, ra_state: Vec, } -static DEVICE_CLONE: std::sync::LazyLock> = +static DEVICE_CLONE: std::sync::LazyLock>> = std::sync::LazyLock::new(|| std::sync::Mutex::new(device::Device::new(false))); static SAVES_CLONE: std::sync::LazyLock> = @@ -101,16 +102,16 @@ pub fn process_savestates(device: &mut device::Device) { device.savestate.save_rewind = false; } device.savestate.save_state = false; - create_savestate(device, rewind); + create_savestate(device, rewind, None); } else if device.savestate.load_state || device.savestate.load_rewind { device.savestate.load_state = false; let rewind = device.savestate.load_rewind; device.savestate.load_rewind = false; - load_savestate(device, rewind); + load_savestate(device, rewind, None); } } -fn create_savestate(device: &mut device::Device, rewind: bool) { +pub fn create_savestate(device: &mut device::Device, rewind: bool, rewind_frame: Option) { if !rewind { // skipped on rewind as a speed hack ui::video::hard_sync(); // to flush the RDP so the RDRAM is updated @@ -148,14 +149,24 @@ fn create_savestate(device: &mut device::Device, rewind: bool) { let mut state = device::Device::new(false); state.clone_state(device_clone.deref()); if let Ok(mut pool) = rewind_pool.lock() { - pool.push_back(SavestateData { - device: state, - saves: saves_clone.clone(), - rdp_state, - ra_state, - }); + let key = if let Some(key) = rewind_frame { + key + } else if let Some(key) = pool.keys().last() { + key + 1 + } else { + 0 + }; + pool.insert( + key, + SavestateData { + device: state, + saves: saves_clone.clone(), + rdp_state, + ra_state, + }, + ); if pool.len() > 30 { - pool.pop_front(); + pool.pop_first(); } } } else { @@ -195,7 +206,7 @@ fn create_savestate(device: &mut device::Device, rewind: bool) { }); } -fn load_savestate(device: &mut device::Device, rewind: bool) { +pub fn load_savestate(device: &mut device::Device, rewind: bool, rewind_frame: Option) { if retroachievements::get_hardcore() { ui::video::onscreen_message( "Cannot load savestate in RA hardcore mode", @@ -206,7 +217,13 @@ fn load_savestate(device: &mut device::Device, rewind: bool) { let state_data = if rewind { if let Ok(mut pool) = device.savestate.rewind_pool.lock() { - pool.pop_back() + if let Some(rewind_frame) = rewind_frame { + pool.remove(&rewind_frame) + } else if let Some((_key, state)) = pool.pop_last() { + Some(state) + } else { + None + } } else { None } @@ -220,7 +237,7 @@ fn load_savestate(device: &mut device::Device, rewind: bool) { && let Ok(saves) = postcard::from_bytes(&saves_data) { Some(SavestateData { - device: *state, + device: state, saves, rdp_state, ra_state, @@ -232,10 +249,15 @@ fn load_savestate(device: &mut device::Device, rewind: bool) { if let Some(mut state) = state_data && device.rdram.size == state.device.rdram.size { - ui::video::hard_sync(); // to flush the RDP so it doesn't overwrite the RDRAM + if device.netplay.is_none() { + // skipped for netplay as a speed hack + ui::video::hard_sync(); // to flush the RDP so it doesn't overwrite the RDRAM + } device.savestate.last_rewind_saved = state.device.vi.elapsed_time; + std::mem::swap(&mut device.rng, &mut state.device.rng); + std::mem::swap(&mut device.ui.storage.saves, &mut state.saves); std::mem::swap(&mut device.cpu, &mut state.device.cpu); diff --git a/src/ui/android.rs b/src/ui/android.rs index f5b49d35..2c5a251e 100644 --- a/src/ui/android.rs +++ b/src/ui/android.rs @@ -280,10 +280,17 @@ fn start_run_rom_on_jvm( ]; if let Some(netplay) = netplay { - args.push(JString::from_str(env, "--netplay-peer-addr")?); - args.push(JString::from_str(env, &netplay.peer_addr.to_string())?); + args.push(JString::from_str(env, "--netplay-server-addr")?); + args.push(JString::from_str(env, &netplay.server_addr)?); args.push(JString::from_str(env, "--netplay-player-number")?); args.push(JString::from_str(env, &netplay.player_number.to_string())?); + args.push(JString::from_str(env, "--netplay-number-of-players")?); + args.push(JString::from_str( + env, + &netplay.number_of_players.to_string(), + )?); + args.push(JString::from_str(env, "--netplay-input-delay")?); + args.push(JString::from_str(env, &netplay.input_delay.to_string())?); args.push(JString::from_str(env, "--cheats")?); args.push(JString::from_str(env, cheats_path.to_str().unwrap())?); diff --git a/src/ui/audio.rs b/src/ui/audio.rs index 0ab046b1..4226872f 100644 --- a/src/ui/audio.rs +++ b/src/ui/audio.rs @@ -1,4 +1,5 @@ use crate::device; +use crate::netplay; use crate::ui; static ADJUST_LOCKED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); @@ -173,6 +174,11 @@ pub fn play_audio(device: &device::Device, dram_addr: usize, length: u64) { if device.ui.audio.audio_stream.is_null() { return; } + if let Some(netplay) = &device.netplay + && netplay::pending_frames(netplay) != 0 + { + return; + } let mut primary_buffer: Vec = vec![0; length as usize / 2]; let mut i = 0; diff --git a/src/ui/gui.rs b/src/ui/gui.rs index 636d2560..c7d52680 100644 --- a/src/ui/gui.rs +++ b/src/ui/gui.rs @@ -19,8 +19,10 @@ struct GithubData { } pub struct NetplayDevice { - pub peer_addr: std::net::SocketAddr, - pub player_number: u8, + pub server_addr: String, + pub player_number: usize, + pub number_of_players: usize, + pub input_delay: i32, } fn check_latest_version(weak: slint::Weak) { @@ -576,10 +578,14 @@ pub fn run_rom( serde_json::to_writer_pretty(f, &game_settings.cheats).unwrap(); command.args([ - "--netplay-peer-addr", - &netplay_device.peer_addr.to_string(), + "--netplay-server-addr", + &netplay_device.server_addr, "--netplay-player-number", &netplay_device.player_number.to_string(), + "--netplay-number-of-players", + &netplay_device.number_of_players.to_string(), + "--netplay-input-delay", + &netplay_device.input_delay.to_string(), "--cheats", cheats_path.to_str().unwrap(), ]); diff --git a/src/ui/gui/appwindow.slint b/src/ui/gui/appwindow.slint index a4261b2e..bc9b2192 100644 --- a/src/ui/gui/appwindow.slint +++ b/src/ui/gui/appwindow.slint @@ -13,7 +13,7 @@ import { CheatsData } from "cheat_page.slint"; import { InputProfileDialog, InputProfileData } from "input_profile.slint"; import { NetplayData } from "netplay_page.slint"; export { VruDialog } from "vru_dialog.slint"; -import { NetplayCreate, CustomServerDialog } from "netplay_create.slint"; +import { NetplayCreate } from "netplay_create.slint"; import { NetplayJoin } from "netplay_join.slint"; import { NetplayWait, NetplayWaitData } from "netplay_wait.slint"; @@ -37,10 +37,9 @@ export component AppWindow inherits Window { callback netplay_begin_game; callback netplay_send_chat_message(string); callback netplay_refresh_sessions; - callback netplay_create_session(string, string, string, string, string, string, string); - callback netplay_get_custom_url; + callback netplay_create_session(string, string, string, string, string, string); callback netplay_select_rom(string); - callback netplay_join_session(string, string, string, string, int); + callback netplay_join_session(string, string, string, string); callback netplay_close; callback cheats_select_rom_clicked(string); callback cheats_clear_clicked; @@ -99,31 +98,25 @@ export component AppWindow inherits Window { in-out property input_dinput <=> InputProfileData.dinput; in-out property show_input_profile <=> InputProfileData.show_input_profile; - in-out property show_netplay_wait_room <=> NetplayData.show_wait_room; - in-out property show_netplay_create_room <=> NetplayData.show_create_room; - in-out property show_netplay_join_room <=> NetplayData.show_join_room; + in-out property show_netplay_wait_session <=> NetplayData.show_wait_session; + in-out property show_netplay_create_session <=> NetplayData.show_create_session; + in-out property show_netplay_join_session <=> NetplayData.show_join_session; - in-out property netplay_server_names <=> NetplayData.server_names; - in-out property netplay_server_urls <=> NetplayData.server_urls; - in-out property netplay_custom_server_url <=> NetplayData.custom_server_url; in-out property netplay_game_name <=> NetplayData.game_name; in-out property netplay_game_hash <=> NetplayData.game_hash; in-out property netplay_game_cheats <=> NetplayData.game_cheats; in-out property netplay_pending_session <=> NetplayData.pending_session; in-out property netplay_rom_path <=> NetplayData.rom_path; - in-out property netplay_peer_addr <=> NetplayData.peer_addr; - in-out property netplay_room_urls <=> NetplayData.room_urls; - in-out property netplay_room_ports <=> NetplayData.room_ports; in-out property netplay_current_session <=> NetplayData.current_session; in-out property netplay_sessions <=> NetplayData.sessions; in-out property netplay_pending_refresh <=> NetplayData.pending_refresh; in-out property netplay_session_name <=> NetplayData.session_name; - in-out property netplay_port <=> NetplayWaitData.port; - in-out property netplay_ping <=> NetplayWaitData.ping; + in-out property netplay_player_name <=> NetplayData.player_name; in-out property netplay_motd <=> NetplayWaitData.motd; in-out property netplay_can_start <=> NetplayWaitData.can_start; in-out property netplay_players <=> NetplayWaitData.players; in-out property netplay_chat_text <=> NetplayWaitData.chat_text; + in-out property netplay_input_delay <=> NetplayWaitData.input_delay; private property popup_message; private property popup_has_close; @@ -225,7 +218,7 @@ export component AppWindow inherits Window { input_profile_creation_button_clicked(); } } - if(side-bar.current-item == 2 && !show_netplay_wait_room && !show_netplay_create_room && !show_netplay_join_room): Netplay { + if(side-bar.current-item == 2 && !show_netplay_wait_session && !show_netplay_create_session && !show_netplay_join_session): Netplay { width: 100%; height: 100%; create_session_button_clicked => { @@ -241,7 +234,7 @@ export component AppWindow inherits Window { netplay_feedback_button_clicked(); } } - if(side-bar.current-item == 2 && show_netplay_wait_room): NetplayWait { + if(side-bar.current-item == 2 && show_netplay_wait_session): NetplayWait { width: 100%; height: 100%; send_chat_message(message) => { @@ -254,23 +247,20 @@ export component AppWindow inherits Window { netplay_close(); } } - if(side-bar.current-item == 2 && show_netplay_create_room && !show_netplay_wait_room): NetplayCreate { + if(side-bar.current-item == 2 && show_netplay_create_session && !show_netplay_wait_session): NetplayCreate { width: 100%; height: 100%; - get_custom_url => { - netplay_get_custom_url(); - } select_rom(rom_dir) => { netplay_select_rom(rom_dir); } - create_session(a, b, c, d, e, f, g) => { - netplay_create_session(a,b,c,d,e,f,g); + create_session(a, b, c, d, e, f) => { + netplay_create_session(a,b,c,d,e,f); } close => { netplay_close(); } } - if(side-bar.current-item == 2 && show_netplay_join_room && !show_netplay_wait_room): NetplayJoin { + if(side-bar.current-item == 2 && show_netplay_join_session && !show_netplay_wait_session): NetplayJoin { width: 100%; height: 100%; refresh_sessions => { @@ -279,8 +269,8 @@ export component AppWindow inherits Window { select_rom(rom_dir) => { netplay_select_rom(rom_dir); } - join_session(a, b, c, d, e) => { - netplay_join_session(a,b,c,d,e); + join_session(a, b, c, d) => { + netplay_join_session(a,b,c,d); } close => { netplay_close(); @@ -371,15 +361,6 @@ export component AppWindow inherits Window { height: content-area.height; width: content-area.width; } - customserverdialog := CustomServerDialog{ - x: content-area.x; - y: content-area.y; - height: content-area.height; - width: content-area.width; - } - } - public function show_custom_server_dialog() { - customserverdialog.show(); } public function show_message(message: string, has_close: bool) { popup_message = message; @@ -394,7 +375,6 @@ export component AppWindow inherits Window { NetplayData.game_name = ""; NetplayData.password = ""; NetplayData.session_name = ""; - NetplayData.custom_server_url = ""; NetplayWaitData.chat_text = ""; NetplayData.pending_session = false; NetplayData.pending_refresh = false; diff --git a/src/ui/gui/netplay_create.slint b/src/ui/gui/netplay_create.slint index 7e8887b2..aaf16240 100644 --- a/src/ui/gui/netplay_create.slint +++ b/src/ui/gui/netplay_create.slint @@ -5,9 +5,8 @@ import { Page } from "page.slint"; export component NetplayCreate inherits Page { title: @tr("Netplay: Create Session"); - callback get_custom_url(); callback select_rom(string); - callback create_session(string, string, string, string, string, string, string); + callback create_session(string, string, string, string, string, string); callback close; VerticalBox { @@ -61,25 +60,6 @@ export component NetplayCreate inherits Page { } } - VerticalBox { - Text { - text: @tr("Server:"); - } - - HorizontalBox { - server := ComboBox { - model: NetplayData.server_names; - selected => { - if (self.current-index >= 0) { - if (self.current-value == "Custom") { - get_custom_url(); - } - } - } - } - } - } - HorizontalBox { alignment: center; if NetplayData.game_name == "": Button { @@ -108,18 +88,11 @@ export component NetplayCreate inherits Page { HorizontalBox { alignment: center; Button { - property server_url; text: @tr("Create Session"); enabled: NetplayData.session_name != "" && NetplayData.player_name != "" && NetplayData.game_name != "" && !NetplayData.pending_session; clicked => { NetplayData.pending_session = true; - if (server.current-value == "Custom") { - server_url = "ws://" + NetplayData.custom_server_url; - } else { - server_url = NetplayData.server_urls[server.current-index]; - } create_session( - server_url, NetplayData.session_name, NetplayData.player_name, NetplayData.game_name, @@ -140,43 +113,3 @@ export component NetplayCreate inherits Page { } } } - -export component CustomServerDialog inherits PopupWindow { - close-policy: no-auto-close; - Rectangle { - height:100%; - width: 100%; - background: Palette.background; - VerticalBox { - alignment: center; - HorizontalBox{ - alignment: center; - Text { - text: @tr("Enter a custom server URL"); - } - } - HorizontalBox { - alignment: center; - vertical-stretch: 0; - LineEdit { - vertical-stretch: 0; - text: NetplayData.custom_server_url; - placeholder-text: "example.com:45000"; - preferred-width: 300px; - edited(text) => { - NetplayData.custom_server_url = text; - } - } - } - HorizontalBox{ - alignment: center; - StandardButton { - kind: ok; - clicked() => { - root.close(); - } - } - } - } - } -} diff --git a/src/ui/gui/netplay_join.slint b/src/ui/gui/netplay_join.slint index bf59b082..25fe6675 100644 --- a/src/ui/gui/netplay_join.slint +++ b/src/ui/gui/netplay_join.slint @@ -7,7 +7,7 @@ export component NetplayJoin inherits Page { title: @tr("Netplay: Join Session"); callback refresh_sessions(); callback select_rom(string); - callback join_session(string, string, string, string, int); + callback join_session(string, string, string, string); callback close; VerticalBox { @@ -37,18 +37,7 @@ export component NetplayJoin inherits Page { } VerticalBox { - Text { - text: @tr("Custom Server URL (optional):"); - } - - LineEdit { - placeholder-text: "example.com:45000"; - text: NetplayData.custom_server_url; - edited(text) => { - NetplayData.custom_server_url = text; - } - } - + Rectangle {} if NetplayData.game_name == "": Button { text: @tr("Select ROM"); clicked => { @@ -81,7 +70,6 @@ export component NetplayJoin inherits Page { } StandardTableView { columns: [ - { title: @tr("Server") }, { title: @tr("Session Name") }, { title: @tr("Game Name") }, { title: @tr("Password") }, @@ -104,8 +92,6 @@ export component NetplayJoin inherits Page { NetplayData.pending_refresh = true; NetplayData.current_session = -1; NetplayData.sessions = []; - NetplayData.room_urls = []; - NetplayData.room_ports = []; refresh_sessions(); } } @@ -121,11 +107,10 @@ export component NetplayJoin inherits Page { clicked => { NetplayData.pending_session = true; join_session( + NetplayData.sessions[NetplayData.current_session][0].text, NetplayData.player_name, NetplayData.game_hash, - NetplayData.password, - NetplayData.room_urls[NetplayData.current_session], - NetplayData.room_ports[NetplayData.current_session]); + NetplayData.password); } } Button { diff --git a/src/ui/gui/netplay_page.slint b/src/ui/gui/netplay_page.slint index 5b8f140a..67095483 100644 --- a/src/ui/gui/netplay_page.slint +++ b/src/ui/gui/netplay_page.slint @@ -6,27 +6,21 @@ import { Page } from "page.slint"; import { State } from "localgame_page.slint"; export global NetplayData { - in-out property <[string]> server_names; - in-out property <[string]> server_urls; in-out property player_name; in-out property game_name; in-out property game_hash; in-out property game_cheats; in-out property rom_path; in-out property password; - in-out property peer_addr; in-out property pending_session; in-out property pending_refresh; in-out property session_name; in-out property <[[StandardListViewItem]]> sessions; - in-out property <[string]> room_urls; - in-out property <[int]> room_ports; in-out property current_session: -1; - in-out property custom_server_url; - in-out property show_wait_room; - in-out property show_create_room; - in-out property show_join_room; + in-out property show_wait_session; + in-out property show_create_session; + in-out property show_join_session; } export component Netplay inherits Page { diff --git a/src/ui/gui/netplay_wait.slint b/src/ui/gui/netplay_wait.slint index defc40c8..298bff42 100644 --- a/src/ui/gui/netplay_wait.slint +++ b/src/ui/gui/netplay_wait.slint @@ -1,14 +1,13 @@ -import { VerticalBox, HorizontalBox, TextEdit, LineEdit, Button, GridBox, ScrollView } from "std-widgets.slint"; +import { VerticalBox, HorizontalBox, TextEdit, ComboBox, GroupBox, LineEdit, Button, GridBox, ScrollView } from "std-widgets.slint"; import { NetplayData } from "netplay_page.slint"; import { Page } from "page.slint"; export global NetplayWaitData { in-out property motd; in-out property <[string]> players; - in-out property port; in-out property can_start; in-out property chat_text; - in-out property ping; + in-out property input_delay; } export component NetplayWait inherits Page { @@ -35,11 +34,6 @@ export component NetplayWait inherits Page { horizontal-alignment: center; } - Text { - text: @tr("Ping:") + " " + NetplayWaitData.ping; - horizontal-alignment: center; - } - HorizontalBox { alignment: center; GridBox { @@ -67,7 +61,7 @@ export component NetplayWait inherits Page { TextEdit { read-only: true; - min-height: 120px; + min-height: 110px; text: NetplayWaitData.chat_text; } @@ -98,7 +92,23 @@ export component NetplayWait inherits Page { horizontal-alignment: center; wrap: word-wrap; } + HorizontalBox { + alignment: center; + Text { + text: @tr("Local Input Delay:"); + horizontal-alignment: center; + vertical-alignment: center; + } + ComboBox { + model: ["0", "1", "2", "3", "4", "5", "6", "7", "8"]; + current-index: NetplayWaitData.input_delay; + selected => { + NetplayWaitData.input_delay = self.current-index; + } + + } + } HorizontalBox { alignment: center; Button { diff --git a/src/ui/input.rs b/src/ui/input.rs index 25bd4aec..fec8fe0e 100644 --- a/src/ui/input.rs +++ b/src/ui/input.rs @@ -41,6 +41,7 @@ pub struct Controllers { pub last_key_state: u32, } +#[derive(Default, PartialEq, Copy, Clone, serde::Serialize, serde::Deserialize)] pub struct InputData { pub data: u32, pub pak_change_pressed: bool, diff --git a/src/ui/netplay.rs b/src/ui/netplay.rs index 46687592..f17ca653 100644 --- a/src/ui/netplay.rs +++ b/src/ui/netplay.rs @@ -1,116 +1,63 @@ use crate::device; use crate::ui; -use crate::ui::gui::{AppWindow, NetplayDevice, open_uri, run_rom, save_settings}; -use futures::{SinkExt, StreamExt, future::join_all}; -use sha2::{Digest, Sha256}; -use slint::{ComponentHandle, Model}; +use crate::ui::gui::{AppWindow, open_uri, run_rom, save_settings}; +use futures::{SinkExt, StreamExt}; +use sha2::digest::Digest; +use slint::ComponentHandle; +use slint::Model; use tokio_tungstenite::tungstenite::Bytes; -use tokio_tungstenite::tungstenite::protocol::Message; +use tokio_tungstenite::tungstenite::Utf8Bytes; +use tokio_tungstenite::tungstenite::protocol::frame::coding::CloseCode; +use tokio_tungstenite::tungstenite::protocol::{CloseFrame, Message}; -const NETPLAY_VERSION: i32 = 17; -const EMU_NAME: &str = "gopher64"; +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +enum MessageType { + RequestCreateSession, + RequestJoinSession, + RequestListSessions, + RequestUpdateSession, + RequestBeginGame, + ResponseBeginGame, + ResponseSession, + ResponseListSessions, + SendChatMessage, + ReceiveChatMessage, + Authenticate, +} -#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)] -pub struct NetplayRoom { - room_name: Option, +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +struct NetplaySession { password: Option, - protected: Option, - #[serde(rename = "MD5")] - md5: Option, game_name: Option, - pub port: Option, - features: Option>, - buffer_target: Option, + motd: Option, + game_checksum: Option, + client_version: Option, + features: Option>, + players: Vec, + server_address: Option, } -#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)] -pub struct NetplayMessage { - #[serde(rename = "type")] - message_type: String, - player_name: Option, - client_sha: Option, - netplay_version: Option, - emulator: Option, - room: Option, - accept: Option, +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +struct NetplayLobbyMessage { + message_type: MessageType, + sessions: std::collections::HashMap, message: Option, - auth: Option, - player_names: Option<[String; 4]>, - #[serde(rename = "authTime")] - auth_time: Option, - rooms: Option>, } -async fn get_local_servers() -> Vec<(String, String)> { - if let Ok(broadcast_sock) = - tokio::net::UdpSocket::bind((std::net::Ipv4Addr::UNSPECIFIED, 0)).await - && broadcast_sock.set_broadcast(true).is_ok() - { - let data: [u8; 1] = [1]; - if let Err(e) = broadcast_sock - .send_to(&data, (std::net::Ipv4Addr::BROADCAST, 45000)) - .await - { - eprintln!("Error sending broadcast: {}", e); - return vec![]; - } - let mut buffer = [0; 1024]; - if let Ok(Ok(result)) = tokio::time::timeout( - std::time::Duration::from_millis(500), - broadcast_sock.recv(&mut buffer), - ) - .await - && let Ok(data) = - serde_json::from_slice::>(&buffer[..result]) - { - let mut local_servers = vec![]; - for server in data.iter() { - local_servers.push((server.0.into(), server.1.into())); - } - local_servers - } else { - vec![] - } - } else { - eprintln!("Error creating netplay broadcast socket"); - vec![] - } -} - -fn populate_server_names(weak: slint::Weak, refresh_sessions: bool) { - let task = ui::WEB_CLIENT - .get("https://dispatch.gopher64.com/getRegions") - .header("netplay-id", env!("NETPLAY_ID")) - .send(); - tokio::spawn(async move { - let (response, local_servers) = tokio::join!(task, get_local_servers()); - let public_servers = if let Ok(response) = response - && let Ok(servers) = response.json::>().await - { - servers - } else { - vec![] - }; - weak.upgrade_in_event_loop(move |handle| { - let server_names: slint::VecModel = slint::VecModel::default(); - let server_urls: slint::VecModel = slint::VecModel::default(); - for local_server in local_servers { - server_names.push(local_server.0.into()); - server_urls.push(local_server.1.into()); - } - for server in public_servers { - server_names.push(server.clone().into()); - server_urls.push(format!("dispatcher:{server}").into()); - } - server_names.push("Custom".into()); - if refresh_sessions { - handle.invoke_netplay_refresh_sessions(); - } - handle.set_netplay_server_names(slint::ModelRc::from(std::rc::Rc::new(server_names))); - handle.set_netplay_server_urls(slint::ModelRc::from(std::rc::Rc::new(server_urls))); - }) - .unwrap(); - }); +pub fn get_auth_token() -> String { + let now_utc = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_millis() + .to_string(); + let hasher: String = sha2::Sha256::new() + .chain_update(&now_utc) + .chain_update(env!("NETPLAY_ID")) + .finalize() + .iter() + .map(|b| format!("{:02x}", b)) + .collect(); + format!("{}|{}", now_utc, hasher) } fn select_rom(weak: slint::Weak, rom_dir: slint::SharedString) { @@ -157,156 +104,101 @@ fn select_rom(weak: slint::Weak, rom_dir: slint::SharedString) { fn setup_create_window( app: &AppWindow, game_settings: ui::GameSettings, - netplay_write_sender: tokio::sync::broadcast::Sender>, - netplay_read_receiver: tokio::sync::broadcast::Receiver>, - netplay_read_sender: tokio::sync::broadcast::Sender>, - netplay_write_receiver: tokio::sync::broadcast::Receiver>, + netplay_write_sender: tokio::sync::broadcast::Sender>, + netplay_read_receiver: tokio::sync::broadcast::Receiver>, + netplay_read_sender: tokio::sync::broadcast::Sender>, + netplay_write_receiver: tokio::sync::broadcast::Receiver>, ) { - populate_server_names(app.as_weak(), false); - let weak = app.as_weak(); - app.on_netplay_get_custom_url(move || { - weak.upgrade_in_event_loop(move |handle| { - handle.invoke_show_custom_server_dialog(); - }) - .unwrap(); - }); - let weak = app.as_weak(); app.on_netplay_create_session( - move |server_url, - session_name, - player_name, - game_name, - game_hash, - game_cheats, - password| { + move |session_name, player_name, game_name, game_hash, game_cheats, password| { let _ = netplay_write_sender.send(None); // close current websocket if any - if server_url.starts_with("dispatcher:") { - weak.upgrade_in_event_loop(move |handle| { - handle.invoke_show_message( - "Creating server, please wait...This may take about 30 seconds.".into(), - false, - ); - }) - .unwrap(); - let task = ui::WEB_CLIENT - .get("https://dispatch.gopher64.com/createServer") - .query(&[("region", server_url.strip_prefix("dispatcher:").unwrap())]) - .header("netplay-id", env!("NETPLAY_ID")) - .send(); - let netplay_read_sender = netplay_read_sender.clone(); - let netplay_write_receiver = netplay_write_receiver.resubscribe(); - let netplay_write_sender = netplay_write_sender.clone(); - let netplay_read_receiver = netplay_read_receiver.resubscribe(); - let game_settings = game_settings.clone(); - let weak = weak.clone(); - let weak_app = weak.clone(); - tokio::spawn(async move { - let response = task.await; + manage_websocket( + netplay_read_sender.clone(), + netplay_write_receiver.resubscribe(), + ); - if let Ok(response) = response - && let Ok(server) = response - .json::>() - .await - { - let server_url = server.values().next().unwrap(); - - manage_websocket( - server_url.to_string(), - netplay_read_sender, - netplay_write_receiver, - weak.clone(), - ); - - create_session( - netplay_write_sender, - netplay_read_receiver, - session_name.to_string(), - player_name.to_string(), - game_name.to_string(), - game_hash.to_string(), - game_cheats.to_string(), - password.to_string(), - game_settings, - weak_app, - ); - } else { - weak.upgrade_in_event_loop(|handle| { - handle.set_netplay_pending_session(false); - handle.invoke_show_message("Server could not be created".into(), true); - }) - .unwrap(); - } - }); - } else { - manage_websocket( - server_url.to_string(), - netplay_read_sender.clone(), - netplay_write_receiver.resubscribe(), - weak.clone(), - ); - - create_session( - netplay_write_sender.clone(), - netplay_read_receiver.resubscribe(), - session_name.to_string(), - player_name.to_string(), - game_name.to_string(), - game_hash.to_string(), - game_cheats.to_string(), - password.to_string(), - game_settings.clone(), - weak.clone(), - ); - } + create_session( + netplay_write_sender.clone(), + netplay_read_receiver.resubscribe(), + session_name.to_string(), + player_name.to_string(), + game_name.to_string(), + game_hash.to_string(), + game_cheats.to_string(), + password.to_string(), + game_settings.clone(), + weak.clone(), + ); }, ); - app.set_show_netplay_create_room(true); + app.set_show_netplay_create_session(true); +} + +async fn do_authentication( + write: &mut futures::stream::SplitSink< + tokio_tungstenite::WebSocketStream< + tokio_tungstenite::MaybeTlsStream, + >, + tokio_tungstenite::tungstenite::Message, + >, +) { + let authenticate = NetplayLobbyMessage { + message_type: MessageType::Authenticate, + sessions: std::collections::HashMap::new(), + message: Some(get_auth_token()), + }; + + write + .send(Message::Binary(Bytes::from( + postcard::to_stdvec(&authenticate).unwrap(), + ))) + .await + .unwrap(); } fn manage_websocket( - server_url: String, - netplay_read_sender: tokio::sync::broadcast::Sender>, - mut netplay_write_receiver: tokio::sync::broadcast::Receiver>, - weak: slint::Weak, + netplay_read_sender: tokio::sync::broadcast::Sender>, + mut netplay_write_receiver: tokio::sync::broadcast::Receiver>, ) { + let server_url = "ws://netplay.gopher64.com:45000"; tokio::spawn(async move { if let Ok(Ok((socket, _response))) = tokio::time::timeout( std::time::Duration::from_secs(2), - tokio_tungstenite::connect_async(server_url.clone()), + tokio_tungstenite::connect_async(server_url), ) .await { - match socket.get_ref() { - tokio_tungstenite::MaybeTlsStream::Plain(stream) => { - let addr = stream.peer_addr().unwrap().to_string(); - weak.upgrade_in_event_loop(move |handle| { - handle.set_netplay_peer_addr(addr.into()); - }) - .unwrap(); - } - _ => unimplemented!(), - } - let (mut write, mut read) = socket.split(); + tokio::spawn(async move { while let Some(Ok(response)) = read.next().await { - if let Ok(message) = serde_json::from_slice(&response.into_data()) { - let _ = netplay_read_sender.send(message); + let decoded_response = + postcard::from_bytes::(&response.into_data()); + match decoded_response { + Ok(message) => { + let _ = netplay_read_sender.send(Some(message)); + } + Err(e) => { + eprintln!("Failed to parse message: {}", e); + } } } }); tokio::spawn(async move { + do_authentication(&mut write).await; loop { match netplay_write_receiver.recv().await { Ok(Some(response)) => { - write + if let Err(e) = write .send(Message::Binary(Bytes::from( - serde_json::to_vec(&response).unwrap(), + postcard::to_stdvec(&response).unwrap(), ))) .await - .unwrap(); + { + eprintln!("Failed to send message: {}", e); + } } Ok(None) => { break; @@ -319,199 +211,36 @@ fn manage_websocket( } } } - write.close().await.unwrap(); + if let Err(e) = write + .send(Message::Close(Some(CloseFrame { + code: CloseCode::Normal, + reason: Utf8Bytes::from(""), + }))) + .await + { + eprintln!("Failed to send close message: {}", e); + } }); } }); } -async fn get_rooms_from_server( - server_name: String, - server_url: String, -) -> ( - Vec>, - Vec, - Vec, +fn update_sessions( + netplay_write_sender: tokio::sync::broadcast::Sender>, ) { - let mut sessions = vec![]; - let mut room_urls = vec![]; - let mut room_ports = vec![]; - if let Ok(Ok((socket, _response))) = tokio::time::timeout( - std::time::Duration::from_secs(2), - tokio_tungstenite::connect_async(&server_url), - ) - .await - { - let (mut write, mut read) = socket.split(); + let request_sessions = NetplayLobbyMessage { + message_type: MessageType::RequestListSessions, + sessions: std::collections::HashMap::new(), + message: None, + }; - let now_utc = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_millis() - .to_string(); - let hasher = Sha256::new().chain_update(&now_utc).chain_update(EMU_NAME); - let request_rooms = NetplayMessage { - message_type: "request_get_rooms".to_string(), - player_name: None, - client_sha: None, - netplay_version: Some(NETPLAY_VERSION), - player_names: None, - emulator: Some(EMU_NAME.to_string()), - accept: None, - rooms: None, - message: None, - auth_time: Some(now_utc), - auth: Some( - hasher - .finalize() - .iter() - .map(|b| format!("{:02x}", b)) - .collect(), - ), - room: None, - }; - write - .send(Message::Binary(Bytes::from( - serde_json::to_vec(&request_rooms).unwrap(), - ))) - .await - .unwrap(); - - if let Some(Ok(response)) = read.next().await - && let Ok(message) = serde_json::from_slice::(&response.into_data()) - && message.message_type == "reply_get_rooms" - && message.accept.unwrap() == 0 - && let Some(rooms) = message.rooms - { - for room in rooms { - let mut session = vec![]; - room_urls.push(server_url.as_str().into()); - room_ports.push(room.port.unwrap()); - - session.push(slint::StandardListViewItem::from( - slint::SharedString::from(&server_name), - )); - session.push(slint::StandardListViewItem::from( - slint::SharedString::from(room.room_name.unwrap()), - )); - session.push(slint::StandardListViewItem::from( - slint::SharedString::from(room.game_name.unwrap()), - )); - session.push(slint::StandardListViewItem::from( - slint::SharedString::from(if room.protected.unwrap() { - "True" - } else { - "False" - }), - )); - session.push(slint::StandardListViewItem::from( - slint::SharedString::from( - if room.features.unwrap_or_default().contains_key("cheats") { - "True" - } else { - "False" - }, - ), - )); - sessions.push(session); - } - } - } - (sessions, room_urls, room_ports) -} - -fn update_sessions(weak: slint::Weak) { - let task = ui::WEB_CLIENT - .get("https://dispatch.gopher64.com/getServers") - .header("netplay-id", env!("NETPLAY_ID")) - .send(); - tokio::spawn(async move { - let mut dispatcher_servers = rustc_hash::FxHashMap::default(); - let response = task.await; - if let Ok(response) = response - && let Ok(servers) = response - .json::>() - .await - { - dispatcher_servers = servers; - } - let weak2 = weak.clone(); - weak.upgrade_in_event_loop(move |handle| { - let mut servers: rustc_hash::FxHashMap = - rustc_hash::FxHashMap::default(); - let server_names = handle.get_netplay_server_names(); - let server_urls = handle.get_netplay_server_urls(); - for (i, server_name) in server_names.iter().enumerate() { - if server_name == "Custom" { - let custom_server_url = handle.get_netplay_custom_server_url(); - if !custom_server_url.is_empty() { - servers.insert( - "Custom".to_string(), - "ws://".to_string() + &custom_server_url, - ); - } - } else if let Some(url) = server_urls.row_data(i) - && url.starts_with("dispatcher:") - { - continue; - } else { - servers.insert( - server_name.to_string(), - server_urls.row_data(i).unwrap().to_string(), - ); - } - } - servers.extend(dispatcher_servers); - - tokio::spawn(async move { - let mut sessions = vec![]; - let mut room_urls = vec![]; - let mut room_ports = vec![]; - let server_tasks = servers.iter().map(|(server_name, server_url)| { - get_rooms_from_server(server_name.clone(), server_url.clone()) - }); - for (server_sessions, server_room_urls, server_room_ports) in - join_all(server_tasks).await - { - sessions.extend(server_sessions); - room_urls.extend(server_room_urls); - room_ports.extend(server_room_ports); - } - - weak2 - .upgrade_in_event_loop(move |handle| { - let sessions_vec = slint::VecModel::default(); - for session in sessions.iter() { - sessions_vec.push(slint::ModelRc::from(std::rc::Rc::new( - slint::VecModel::from(session.to_vec()), - ))); - } - handle.set_netplay_sessions(slint::ModelRc::from(std::rc::Rc::new( - sessions_vec, - ))); - - handle.set_netplay_room_urls(slint::ModelRc::from(std::rc::Rc::new( - slint::VecModel::from(room_urls.to_vec()), - ))); - - handle.set_netplay_room_ports(slint::ModelRc::from(std::rc::Rc::new( - slint::VecModel::from(room_ports.to_vec()), - ))); - - handle.set_netplay_current_session(-1); - handle.set_netplay_pending_refresh(false); - }) - .unwrap(); - }); - }) - .unwrap(); - }); + netplay_write_sender.send(Some(request_sessions)).unwrap(); } #[allow(clippy::too_many_arguments)] fn create_session( - netplay_write_sender: tokio::sync::broadcast::Sender>, - mut netplay_read_receiver: tokio::sync::broadcast::Receiver>, + netplay_write_sender: tokio::sync::broadcast::Sender>, + mut netplay_read_receiver: tokio::sync::broadcast::Receiver>, session_name: String, player_name: String, game_name: String, @@ -522,13 +251,7 @@ fn create_session( weak_app: slint::Weak, ) { tokio::spawn(async move { - let now_utc = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_millis() - .to_string(); - let hasher = Sha256::new().chain_update(&now_utc).chain_update(EMU_NAME); - let mut features = rustc_hash::FxHashMap::default(); + let mut features = std::collections::HashMap::default(); if !game_cheats.is_empty() { features.insert("cheats".to_string(), game_cheats); @@ -540,37 +263,27 @@ fn create_session( game_settings.disable_expansion_pak.to_string(), ); - let create_room = NetplayMessage { - message_type: "request_create_room".to_string(), - player_name: Some(player_name), - client_sha: Some(env!("GIT_DESCRIBE").to_string()), - netplay_version: Some(NETPLAY_VERSION), - emulator: Some(EMU_NAME.to_string()), - accept: None, + let session = NetplaySession { + password: if password.is_empty() { + None + } else { + Some(password) + }, + game_name: Some(game_name), + motd: None, + game_checksum: Some(game_hash), + client_version: Some(env!("GIT_DESCRIBE").to_string()), + features: Some(features), + players: vec![player_name], + server_address: None, + }; + let create_session = NetplayLobbyMessage { + message_type: MessageType::RequestCreateSession, + sessions: std::collections::HashMap::from([(session_name, session)]), message: None, - rooms: None, - auth_time: Some(now_utc), - player_names: None, - auth: Some( - hasher - .finalize() - .iter() - .map(|b| format!("{:02x}", b)) - .collect(), - ), - room: Some(NetplayRoom { - room_name: Some(session_name), - password: Some(password), - game_name: Some(game_name), - md5: Some(game_hash), - protected: None, - port: None, - features: Some(features), - buffer_target: None, - }), }; - netplay_write_sender.send(Some(create_room)).unwrap(); + netplay_write_sender.send(Some(create_session)).unwrap(); match tokio::time::timeout( std::time::Duration::from_secs(2), @@ -579,10 +292,11 @@ fn create_session( .await { Ok(Ok(Some(message))) => { - if message.message_type == "reply_create_room" && message.accept.unwrap() == 0 { + if message.message_type == MessageType::ResponseSession && message.message.is_none() + { weak_app .upgrade_in_event_loop(move |handle| { - let session = message.room.as_ref().unwrap(); + let (session_name, session) = message.sessions.iter().next().unwrap(); let features_default = "false".to_string(); let cheats_default = "{}".to_string(); let overclock = session @@ -606,18 +320,16 @@ fn create_session( setup_wait_window( netplay_write_sender, netplay_read_receiver, - session.room_name.as_ref().unwrap().into(), + session.server_address.as_ref().unwrap().clone(), + session_name.into(), session.game_name.as_ref().unwrap().into(), handle.get_netplay_rom_path(), - message.player_name.as_ref().unwrap().into(), - session.port.unwrap(), ui::GameSettings { overclock: overclock.parse().unwrap(), disable_expansion_pak: disable_expansion_pak.parse().unwrap(), cheats: serde_json::from_str(cheats).unwrap(), load_savestate_slot: None, }, - handle.get_netplay_peer_addr(), &handle, ); }) @@ -650,65 +362,228 @@ fn create_session( } fn join_session( - netplay_write_sender: tokio::sync::broadcast::Sender>, - mut netplay_read_receiver: tokio::sync::broadcast::Receiver>, + netplay_write_sender: tokio::sync::broadcast::Sender>, + session_name: String, player_name: String, game_hash: String, password: String, - room_port: i32, - weak_app: slint::Weak, ) { + let session = NetplaySession { + password: Some(password), + game_name: None, + motd: None, + game_checksum: Some(game_hash), + client_version: Some(env!("GIT_DESCRIBE").to_string()), + features: None, + players: vec![player_name], + server_address: None, + }; + let join_session = NetplayLobbyMessage { + message_type: MessageType::RequestJoinSession, + sessions: std::collections::HashMap::from([(session_name, session)]), + message: None, + }; + + netplay_write_sender.send(Some(join_session)).unwrap(); +} + +#[allow(clippy::too_many_arguments)] +fn setup_wait_window( + netplay_write_sender: tokio::sync::broadcast::Sender>, + mut netplay_read_receiver: tokio::sync::broadcast::Receiver>, + server_addr: String, + session_name: slint::SharedString, + game_name: slint::SharedString, + rom_path: slint::SharedString, + game_settings: ui::GameSettings, + app: &AppWindow, +) { + let (mut socket, loop_fut) = matchbox_socket::WebRtcSocketBuilder::new(server_addr.clone()) + .add_unreliable_channel() + .build(); tokio::spawn(async move { - let now_utc = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_millis() - .to_string(); - let hasher = Sha256::new().chain_update(&now_utc).chain_update(EMU_NAME); + if let Err(e) = loop_fut.await { + eprintln!("WebRTC loop failed: {}", e); + } + }); - let join_room = NetplayMessage { - message_type: "request_join_room".to_string(), - player_name: Some(player_name), - client_sha: Some(env!("GIT_DESCRIBE").to_string()), - netplay_version: Some(NETPLAY_VERSION), - emulator: Some(EMU_NAME.to_string()), - accept: None, - message: None, - rooms: None, - player_names: None, - auth_time: Some(now_utc), - auth: Some( - hasher - .finalize() - .iter() - .map(|b| format!("{:02x}", b)) - .collect(), - ), - room: Some(NetplayRoom { - room_name: None, - password: Some(password), - game_name: None, - md5: Some(game_hash), - protected: None, - port: Some(room_port), - features: None, - buffer_target: None, - }), + app.set_netplay_session_name(session_name); + app.set_netplay_game_name(game_name); + app.set_netplay_rom_path(rom_path); + app.set_netplay_can_start(true); + app.set_netplay_input_delay(2); + + let request_update = NetplayLobbyMessage { + message_type: MessageType::RequestUpdateSession, + sessions: std::collections::HashMap::new(), + message: None, + }; + netplay_write_sender.send(Some(request_update)).unwrap(); + + let sender = netplay_write_sender.clone(); + app.on_netplay_send_chat_message(move |message| { + let send_chat = NetplayLobbyMessage { + message_type: MessageType::SendChatMessage, + sessions: std::collections::HashMap::new(), + message: Some(message.into()), }; + sender.send(Some(send_chat)).unwrap(); + }); - netplay_write_sender.send(Some(join_room)).unwrap(); + let sender = netplay_write_sender.clone(); + app.on_netplay_begin_game(move || { + let begin_game = NetplayLobbyMessage { + message_type: MessageType::RequestBeginGame, + sessions: std::collections::HashMap::new(), + message: None, + }; + sender.send(Some(begin_game)).unwrap(); + }); - match tokio::time::timeout( - std::time::Duration::from_secs(2), - netplay_read_receiver.recv(), - ) - .await - { - Ok(Ok(Some(message))) => { - if message.message_type == "reply_join_room" && message.accept.unwrap() == 0 { - weak_app - .upgrade_in_event_loop(move |handle| { - let session = message.room.as_ref().unwrap(); + let weak_app = app.as_weak(); + tokio::spawn(async move { + loop { + match netplay_read_receiver.recv().await { + Ok(Some(response)) => match response.message_type { + MessageType::ResponseSession => { + weak_app + .upgrade_in_event_loop(move |handle| { + let session = response.sessions.iter().next().unwrap().1; + let player_names = session.players.clone(); + + handle.set_netplay_motd(session.motd.as_ref().unwrap().into()); + + handle.set_netplay_players(slint::ModelRc::from(std::rc::Rc::new( + slint::VecModel::from( + player_names + .iter() + .map(|x| x.into()) + .collect::>(), + ), + ))); + }) + .unwrap(); + } + MessageType::ReceiveChatMessage => { + weak_app + .upgrade_in_event_loop(move |handle| { + let mut chat_text = handle.get_netplay_chat_text(); + chat_text.push_str(&format!("{}\n", response.message.unwrap())); + handle.set_netplay_chat_text(chat_text); + }) + .unwrap(); + } + MessageType::ResponseBeginGame => { + if response.message.is_none() { + let weak_app2 = weak_app.clone(); + weak_app + .upgrade_in_event_loop(move |handle| { + let player_name = handle.get_netplay_player_name(); + let players = handle.get_netplay_players(); + let input_delay = handle.get_netplay_input_delay(); + let player_number = + players.iter().position(|x| x == player_name).unwrap(); + run_rom( + handle.get_netplay_rom_path().as_str().into(), + ui::GameSettings { + overclock: game_settings.overclock, + disable_expansion_pak: game_settings + .disable_expansion_pak, + cheats: game_settings.cheats, + load_savestate_slot: None, + }, + Some(ui::gui::NetplayDevice { + server_addr, + player_number, + number_of_players: players.row_count(), + input_delay, + }), + weak_app2, + ); + handle.invoke_netplay_close(); + }) + .unwrap(); + socket.close(); + return; + } else { + weak_app + .upgrade_in_event_loop(move |handle| { + handle.set_netplay_can_start(true); + + if let Some(message) = response.message { + handle.invoke_show_message(message.into(), true); + } + }) + .unwrap(); + } + } + _ => { + eprintln!("Unknown netplay message type: {:?}", response.message_type); + } + }, + Ok(None) => { + break; + } + Err(tokio::sync::broadcast::error::RecvError::Lagged(_)) => { + panic!("netplay_read_receiver lagged"); + } + Err(tokio::sync::broadcast::error::RecvError::Closed) => { + break; // exit the loop if the receiver is closed + } + } + } + }); + app.set_show_netplay_wait_session(true); + app.set_show_netplay_create_session(false); + app.set_show_netplay_join_session(false); + app.invoke_close_message(); +} + +fn setup_join_window( + app: &AppWindow, + netplay_write_sender: tokio::sync::broadcast::Sender>, + netplay_read_receiver: tokio::sync::broadcast::Receiver>, + netplay_read_sender: tokio::sync::broadcast::Sender>, + netplay_write_receiver: tokio::sync::broadcast::Receiver>, +) { + let _ = netplay_write_sender.send(None); // close current websocket if any + manage_websocket( + netplay_read_sender.clone(), + netplay_write_receiver.resubscribe(), + ); + + app.set_netplay_pending_refresh(true); + + let write_sender = netplay_write_sender.clone(); + app.on_netplay_refresh_sessions(move || { + update_sessions(write_sender.clone()); + }); + + let write_sender = netplay_write_sender.clone(); + app.on_netplay_join_session(move |session_name, player_name, game_hash, password| { + join_session( + write_sender.clone(), + session_name.to_string(), + player_name.to_string(), + game_hash.to_string(), + password.to_string(), + ); + }); + + let weak = app.as_weak(); + let mut read_receiver = netplay_read_receiver.resubscribe(); + let write_sender = netplay_write_sender.clone(); + tokio::spawn(async move { + loop { + match read_receiver.recv().await { + Ok(Some(message)) => { + if message.message_type == MessageType::ResponseSession + && message.message.is_none() + { + let sender = write_sender.clone(); + let receiver = read_receiver.resubscribe(); + weak.upgrade_in_event_loop(move |handle| { + let (session_name, session) = message.sessions.iter().next().unwrap(); let features_default = "false".to_string(); let cheats_default = "{}".to_string(); let overclock = session @@ -730,381 +605,110 @@ fn join_session( .get("cheats") .unwrap_or(&cheats_default); setup_wait_window( - netplay_write_sender, - netplay_read_receiver, - session.room_name.as_ref().unwrap().into(), + sender, + receiver, + session.server_address.as_ref().unwrap().clone(), + session_name.into(), session.game_name.as_ref().unwrap().into(), handle.get_netplay_rom_path(), - message.player_name.as_ref().unwrap().into(), - session.port.unwrap(), ui::GameSettings { overclock: overclock.parse().unwrap(), disable_expansion_pak: disable_expansion_pak.parse().unwrap(), cheats: serde_json::from_str(cheats).unwrap(), load_savestate_slot: None, }, - handle.get_netplay_peer_addr(), &handle, ); }) .unwrap(); - } else { - weak_app - .upgrade_in_event_loop(move |handle| { + return; + } else if message.message_type == MessageType::ResponseListSessions + && message.message.is_none() + { + let mut sessions = vec![]; + for (session_name, remote_session) in message.sessions { + let mut session = vec![]; + + session.push(slint::StandardListViewItem::from( + slint::SharedString::from(session_name), + )); + session.push(slint::StandardListViewItem::from( + slint::SharedString::from(remote_session.game_name.unwrap()), + )); + session.push(slint::StandardListViewItem::from( + slint::SharedString::from(if remote_session.password.is_some() { + "True" + } else { + "False" + }), + )); + session.push(slint::StandardListViewItem::from( + slint::SharedString::from( + if remote_session + .features + .unwrap_or_default() + .contains_key("cheats") + { + "True" + } else { + "False" + }, + ), + )); + sessions.push(session); + } + weak.upgrade_in_event_loop(move |handle| { + let sessions_vec = slint::VecModel::default(); + for session in sessions.iter() { + sessions_vec.push(slint::ModelRc::from(std::rc::Rc::new( + slint::VecModel::from(session.to_vec()), + ))); + } + handle.set_netplay_sessions(slint::ModelRc::from(std::rc::Rc::new( + sessions_vec, + ))); + + handle.set_netplay_current_session(-1); + handle.set_netplay_pending_refresh(false); + }) + .unwrap(); + } else { + weak.upgrade_in_event_loop(move |handle| { handle.set_netplay_pending_session(false); if let Some(message) = message.message { handle.invoke_show_message(message.into(), true); } }) .unwrap(); + } } - } - Ok(Ok(None)) => {} - Ok(Err(err)) => { - panic!("netplay_read_receiver error: {err}"); - } - Err(_) => { - weak_app - .upgrade_in_event_loop(move |handle| { + Ok(None) => { + break; + } + Err(_) => { + weak.upgrade_in_event_loop(move |handle| { handle.set_netplay_pending_session(false); handle.invoke_show_message("Server did not respond".into(), true); }) .unwrap(); - } - } - }); -} - -#[allow(clippy::too_many_arguments)] -fn setup_wait_window( - netplay_write_sender: tokio::sync::broadcast::Sender>, - mut netplay_read_receiver: tokio::sync::broadcast::Receiver>, - session_name: slint::SharedString, - game_name: slint::SharedString, - rom_path: slint::SharedString, - player_name: slint::SharedString, - port: i32, - game_settings: ui::GameSettings, - peer_addr: slint::SharedString, - app: &AppWindow, -) { - let local_player = player_name.clone(); - - let mut socket_addr: std::net::SocketAddr = peer_addr.to_string().parse().unwrap(); - socket_addr.set_port(port as u16); - app.set_netplay_session_name(session_name); - app.set_netplay_game_name(game_name); - app.set_netplay_rom_path(rom_path); - app.set_netplay_port(port); - app.set_netplay_ping("Unknown".into()); - - let sender = netplay_write_sender.clone(); - app.on_netplay_send_chat_message(move |message| { - let send_chat = NetplayMessage { - message_type: "request_chat_message".to_string(), - player_name: Some(player_name.to_string()), - client_sha: None, - netplay_version: None, - player_names: None, - rooms: None, - emulator: None, - accept: None, - message: Some(message.into()), - auth_time: None, - auth: None, - room: Some(NetplayRoom { - room_name: None, - password: None, - game_name: None, - md5: None, - protected: None, - port: Some(port), - features: None, - buffer_target: None, - }), - }; - sender.send(Some(send_chat)).unwrap(); - }); - - let sender = netplay_write_sender.clone(); - app.on_netplay_begin_game(move || { - let begin_game = NetplayMessage { - message_type: "request_begin_game".to_string(), - player_name: None, - client_sha: None, - netplay_version: None, - player_names: None, - rooms: None, - emulator: None, - accept: None, - message: None, - auth_time: None, - auth: None, - room: Some(NetplayRoom { - room_name: None, - password: None, - game_name: None, - md5: None, - protected: None, - port: Some(port), - features: None, - buffer_target: None, - }), - }; - sender.send(Some(begin_game)).unwrap(); - }); - - let motd_message = NetplayMessage { - message_type: "request_motd".to_string(), - player_name: None, - client_sha: None, - netplay_version: None, - emulator: None, - accept: None, - rooms: None, - player_names: None, - message: None, - auth_time: None, - auth: None, - room: None, - }; - - netplay_write_sender.send(Some(motd_message)).unwrap(); - - let ping_message = NetplayMessage { - message_type: "request_ping".to_string(), - player_name: None, - client_sha: None, - netplay_version: None, - emulator: None, - accept: None, - rooms: None, - player_names: None, - message: None, - auth_time: None, - auth: None, - room: None, - }; - - netplay_write_sender - .send(Some(ping_message.clone())) - .unwrap(); - - let weak_app = app.as_weak(); - tokio::spawn(async move { - loop { - match netplay_read_receiver.recv().await { - Ok(Some(response)) => match response.message_type.as_str() { - "reply_ping" => { - if let Some(message) = response.message { - weak_app - .upgrade_in_event_loop(move |handle| { - handle.set_netplay_ping((message + " ms").into()); - }) - .unwrap(); - } - let ping_message = ping_message.clone(); - let ping_writer = netplay_write_sender.clone(); - tokio::spawn(async move { - tokio::time::sleep(std::time::Duration::from_secs(5)).await; - let _ = ping_writer.send(Some(ping_message)); - }); - } - "reply_motd" => { - let request_players = NetplayMessage { - message_type: "request_players".to_string(), - player_name: None, - client_sha: None, - netplay_version: None, - player_names: None, - emulator: None, - rooms: None, - accept: None, - message: None, - auth_time: None, - auth: None, - room: Some(NetplayRoom { - room_name: None, - password: None, - game_name: None, - md5: None, - protected: None, - port: Some(port), - features: None, - buffer_target: None, - }), - }; - netplay_write_sender.send(Some(request_players)).unwrap(); - - weak_app - .upgrade_in_event_loop(move |handle| { - #[allow(clippy::regex_creation_in_loops)] - let re = regex::Regex::new(r"<[^>]*>").unwrap(); - let motd = re - .replace_all(response.message.unwrap().as_str(), "") - .into_owned(); - handle.set_netplay_motd(motd.into()); - }) - .unwrap(); - } - "reply_players" => { - let local_player = local_player.clone(); - weak_app - .upgrade_in_event_loop(move |handle| { - if let Some(player_names) = response.player_names { - if local_player == player_names[0] { - handle.set_netplay_can_start(true); - } else { - handle.set_netplay_can_start(false); - } - - handle.set_netplay_players(slint::ModelRc::from( - std::rc::Rc::new(slint::VecModel::from( - player_names - .iter() - .map(|x| x.into()) - .collect::>(), - )), - )); - } - }) - .unwrap(); - } - "reply_chat_message" => { - weak_app - .upgrade_in_event_loop(move |handle| { - let mut chat_text = handle.get_netplay_chat_text(); - chat_text.push_str(&format!("{}\n", response.message.unwrap())); - handle.set_netplay_chat_text(chat_text); - }) - .unwrap(); - } - "reply_begin_game" => { - if response.accept.unwrap() == 0 { - let weak_app2 = weak_app.clone(); - weak_app - .upgrade_in_event_loop(move |handle| { - let _ = netplay_write_sender.send(None); - - let mut player_number = 4; - let players = handle.get_netplay_players(); - for (i, player) in players.iter().enumerate() { - if player == local_player { - player_number = i; - } - } - if player_number > 3 { - panic!("Could not determine player number"); - } - - run_rom( - handle.get_netplay_rom_path().as_str().into(), - ui::GameSettings { - overclock: game_settings.overclock, - disable_expansion_pak: game_settings - .disable_expansion_pak, - cheats: game_settings.cheats, - load_savestate_slot: None, - }, - Some(NetplayDevice { - peer_addr: socket_addr, - player_number: player_number as u8, - }), - weak_app2, - ); - handle.invoke_netplay_close(); - }) - .unwrap(); - return; - } else { - let local_player = local_player.clone(); - weak_app - .upgrade_in_event_loop(move |handle| { - if let Some(p0) = handle.get_netplay_players().row_data(0) { - if p0 == local_player { - handle.set_netplay_can_start(true); - } else { - handle.set_netplay_can_start(false); - } - } - if let Some(message) = response.message { - handle.invoke_show_message(message.into(), true); - } - }) - .unwrap(); - } - } - _ => { - eprintln!("Unknown netplay message type: {}", response.message_type); - } - }, - Ok(None) => { - break; - } - Err(tokio::sync::broadcast::error::RecvError::Lagged(_)) => { - panic!("netplay_read_receiver lagged"); - } - Err(tokio::sync::broadcast::error::RecvError::Closed) => { - break; // exit the loop if the receiver is closed } } } }); - app.set_show_netplay_wait_room(true); - app.set_show_netplay_create_room(false); - app.set_show_netplay_join_room(false); - app.invoke_close_message(); -} -fn setup_join_window( - app: &AppWindow, - netplay_write_sender: tokio::sync::broadcast::Sender>, - netplay_read_receiver: tokio::sync::broadcast::Receiver>, - netplay_read_sender: tokio::sync::broadcast::Sender>, - netplay_write_receiver: tokio::sync::broadcast::Receiver>, -) { - app.set_netplay_pending_refresh(true); - populate_server_names(app.as_weak(), true); - - let weak = app.as_weak(); - app.on_netplay_refresh_sessions(move || { - update_sessions(weak.clone()); - }); - let weak = app.as_weak(); - app.on_netplay_join_session( - move |player_name, game_hash, password, room_url, room_port| { - let _ = netplay_write_sender.send(None); // close current websocket if any - manage_websocket( - room_url.to_string(), - netplay_read_sender.clone(), - netplay_write_receiver.resubscribe(), - weak.clone(), - ); - - join_session( - netplay_write_sender.clone(), - netplay_read_receiver.resubscribe(), - player_name.to_string(), - game_hash.to_string(), - password.to_string(), - room_port, - weak.clone(), - ); - }, - ); - - app.set_show_netplay_join_room(true); + app.set_show_netplay_join_session(true); + app.invoke_netplay_refresh_sessions(); } pub fn netplay_window(app: &AppWindow) { let (netplay_read_sender, netplay_read_receiver): ( - tokio::sync::broadcast::Sender>, - tokio::sync::broadcast::Receiver>, + tokio::sync::broadcast::Sender>, + tokio::sync::broadcast::Receiver>, ) = tokio::sync::broadcast::channel(5); let (netplay_write_sender, netplay_write_receiver): ( - tokio::sync::broadcast::Sender>, - tokio::sync::broadcast::Receiver>, + tokio::sync::broadcast::Sender>, + tokio::sync::broadcast::Receiver>, ) = tokio::sync::broadcast::channel(5); let weak_app = app.as_weak(); @@ -1170,9 +774,9 @@ pub fn netplay_window(app: &AppWindow) { app.on_netplay_close(move || { weak_app .upgrade_in_event_loop(move |handle| { - handle.set_show_netplay_wait_room(false); - handle.set_show_netplay_create_room(false); - handle.set_show_netplay_join_room(false); + handle.set_show_netplay_wait_session(false); + handle.set_show_netplay_create_session(false); + handle.set_show_netplay_join_session(false); handle.invoke_clear_netplay_data(); handle.invoke_close_message(); }) diff --git a/src/ui/storage.rs b/src/ui/storage.rs index 034410b7..637e305f 100644 --- a/src/ui/storage.rs +++ b/src/ui/storage.rs @@ -243,25 +243,21 @@ pub fn load_saves(ui: &mut ui::Ui, netplay: &mut Option) { netplay.as_mut().unwrap(), "eep", &ui.storage.saves.eeprom.data, - ui.storage.saves.eeprom.data.len(), ); netplay::send_save( netplay.as_mut().unwrap(), "sra", &ui.storage.saves.sram.data, - ui.storage.saves.sram.data.len(), ); netplay::send_save( netplay.as_mut().unwrap(), "fla", &ui.storage.saves.flash.data, - ui.storage.saves.flash.data.len(), ); netplay::send_save( netplay.as_mut().unwrap(), "mpk", &ui.storage.saves.mempak.data, - ui.storage.saves.mempak.data.len(), ); let mut compressed_sd = Vec::new(); @@ -270,12 +266,7 @@ pub fn load_saves(ui: &mut ui::Ui, netplay: &mut Option) { { compressed_sd = file_data; } - netplay::send_save( - netplay.as_mut().unwrap(), - "img", - &compressed_sd, - compressed_sd.len(), - ); + netplay::send_save(netplay.as_mut().unwrap(), "img", &compressed_sd); let mut compressed_romsave = Vec::new(); if !ui.storage.saves.romsave.data.is_empty() @@ -284,12 +275,7 @@ pub fn load_saves(ui: &mut ui::Ui, netplay: &mut Option) { { compressed_romsave = compressed_file_data; } - netplay::send_save( - netplay.as_mut().unwrap(), - "rom", - &compressed_romsave, - compressed_romsave.len(), - ); + netplay::send_save(netplay.as_mut().unwrap(), "rom", &compressed_romsave); } else { netplay::receive_save( netplay.as_mut().unwrap(),