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
This commit is contained in:
Logan McNaughton
2026-06-05 09:43:31 +02:00
committed by GitHub
parent 0a44124c20
commit 681f8670f5
30 changed files with 3143 additions and 2082 deletions
Generated
+1696 -154
View File
File diff suppressed because it is too large Load Diff
+3 -2
View File
@@ -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"] }
+69 -69
View File
@@ -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 ""
+69 -69
View File
@@ -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."
+69 -69
View File
@@ -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 ""
+49 -69
View File
@@ -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 <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\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 ""
+69 -69
View File
@@ -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 ""
+69 -69
View File
@@ -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 ""
+69 -69
View File
@@ -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 <eduardotcarvalho@gmail.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\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 ""
+69 -69
View File
@@ -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 ""
+5 -5
View File
@@ -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<Device> {
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,
},
}
})
}
}
+1 -1
View File
@@ -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 {
+3 -7
View File
@@ -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 {
+1 -1
View File
@@ -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 {
+2 -2
View File
@@ -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] {
+29 -13
View File
@@ -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 => {
+19 -9
View File
@@ -27,10 +27,14 @@ pub struct Args {
pub disable_expansion_pak: Option<bool>,
#[arg(long, value_name = "CHEATS_FILE", hide = true)]
pub cheats: Option<String>,
#[arg(long, value_name = "NETPLAY_PEER_ADDR", hide = true)]
pub netplay_peer_addr: Option<String>,
#[arg(long, value_name = "NETPLAY_SERVER_ADDR", hide = true)]
pub netplay_server_addr: Option<String>,
#[arg(long, value_name = "NETPLAY_PLAYER_NUMBER", hide = true)]
pub netplay_player_number: Option<u8>,
pub netplay_player_number: Option<usize>,
#[arg(long, value_name = "NETPLAY_NUMBER_OF_PLAYERS", hide = true)]
pub netplay_number_of_players: Option<usize>,
#[arg(long, value_name = "NETPLAY_INPUT_DELAY", hide = true)]
pub netplay_input_delay: Option<usize>,
#[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()
+302 -320
View File
@@ -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<matchbox_socket::PeerId> 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::<ggrs::Message>(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<GgrsConfig>,
pub reliable_channel: matchbox_socket::WebRtcChannel,
pub peers: Vec<matchbox_socket::PeerId>,
pub player_number: usize,
pub connected: [bool; 4],
pub data: std::collections::HashMap<String, Vec<u8>>,
pub inputs: Vec<(ui::input::InputData, ggrs::InputStatus)>,
pub requests: std::collections::VecDeque<ggrs::GgrsRequest<GgrsConfig>>,
}
pub struct PlayerData {
lag: u8,
count: u32,
pub reg_id: u32,
input_events: rustc_hash::FxHashMap<u32, InputEvent>,
#[derive(serde::Serialize, serde::Deserialize)]
struct NetplayMessage {
name: String,
data: Vec<u8>,
}
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<u8> {
while !netplay.data.contains_key(name) {
let messages = netplay.reliable_channel.receive();
for (_, data) in messages {
let message = postcard::from_bytes::<NetplayMessage>(&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<matchbox_socket::PeerId>,
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<usize, Option<matchbox_socket::PeerId>> {
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::<NetplayMessage>(&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<u8> = [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<u8> = [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<u8> = [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<u8> = [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<u8> = [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<u8>) {
let mut request: Vec<u8> = [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<u8> = 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<u8> = [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<u8> = [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<u8> = [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(&regid.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(&regid.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::<GgrsConfig>::new();
loop {
matchbox_socket.0.update_peers();
peers = matchbox_socket
.0
.connected_peers()
.collect::<Vec<matchbox_socket::PeerId>>();
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(),
}
}
+39 -17
View File
@@ -78,17 +78,18 @@ pub struct Savestate {
pub load_rewind: bool,
pub last_rewind_saved: f64,
#[serde(skip)]
pub rewind_pool: std::sync::Arc<std::sync::Mutex<std::collections::VecDeque<SavestateData>>>,
pub rewind_pool:
std::sync::Arc<std::sync::Mutex<std::collections::BTreeMap<i32, SavestateData>>>,
}
pub struct SavestateData {
device: device::Device,
device: Box<device::Device>,
saves: ui::storage::Saves,
rdp_state: Vec<u8>,
ra_state: Vec<u8>,
}
static DEVICE_CLONE: std::sync::LazyLock<std::sync::Mutex<device::Device>> =
static DEVICE_CLONE: std::sync::LazyLock<std::sync::Mutex<Box<device::Device>>> =
std::sync::LazyLock::new(|| std::sync::Mutex::new(device::Device::new(false)));
static SAVES_CLONE: std::sync::LazyLock<std::sync::Mutex<ui::storage::Saves>> =
@@ -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<i32>) {
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<i32>) {
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);
+9 -2
View File
@@ -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())?);
+6
View File
@@ -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<i16> = vec![0; length as usize / 2];
let mut i = 0;
+10 -4
View File
@@ -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<AppWindow>) {
@@ -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(),
]);
+16 -36
View File
@@ -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 <string> popup_message;
private property <bool> 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;
+1 -68
View File
@@ -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 <string> 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();
}
}
}
}
}
}
+4 -19
View File
@@ -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 {
+3 -9
View File
@@ -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 <string> player_name;
in-out property <string> game_name;
in-out property <string> game_hash;
in-out property <string> game_cheats;
in-out property <string> rom_path;
in-out property <string> password;
in-out property <string> peer_addr;
in-out property <bool> pending_session;
in-out property <bool> pending_refresh;
in-out property <string> session_name;
in-out property <[[StandardListViewItem]]> sessions;
in-out property <[string]> room_urls;
in-out property <[int]> room_ports;
in-out property <int> current_session: -1;
in-out property <string> custom_server_url;
in-out property <bool> show_wait_room;
in-out property <bool> show_create_room;
in-out property <bool> show_join_room;
in-out property <bool> show_wait_session;
in-out property <bool> show_create_session;
in-out property <bool> show_join_session;
}
export component Netplay inherits Page {
+19 -9
View File
@@ -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 <string> motd;
in-out property <[string]> players;
in-out property <int> port;
in-out property <bool> can_start;
in-out property <string> chat_text;
in-out property <string> ping;
in-out property <int> 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 {
+1
View File
@@ -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,
+440 -836
View File
File diff suppressed because it is too large Load Diff
+2 -16
View File
@@ -243,25 +243,21 @@ pub fn load_saves(ui: &mut ui::Ui, netplay: &mut Option<netplay::Netplay>) {
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<netplay::Netplay>) {
{
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<netplay::Netplay>) {
{
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(),