mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-03-05 06:01:07 +00:00
Compare commits
15 Commits
update/dot
...
Canary-1.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
39f55b2af3 | ||
|
|
6126e3dc1e | ||
|
|
e1c829f91d | ||
|
|
6c7dc7646b | ||
|
|
862a686c5e | ||
|
|
e8751e1c40 | ||
|
|
09748b140a | ||
|
|
456db46065 | ||
|
|
7b39ff36c0 | ||
|
|
10476771d3 | ||
|
|
c5082ac85a | ||
|
|
5e86ad83cc | ||
|
|
1baaa1c365 | ||
|
|
e8225ce7aa | ||
|
|
6b814fb973 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -18,6 +18,8 @@ build/
|
||||
[Oo]bj/
|
||||
AppDir/
|
||||
publish_appimage/
|
||||
publish_ava/
|
||||
publish_tmp_ava/
|
||||
|
||||
# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
|
||||
!packages/*/build/
|
||||
|
||||
@@ -225,7 +225,7 @@
|
||||
"el_GR": "Χωρίς Ελέγχους (γρηγορότερο, μη ασφαλές)",
|
||||
"en_US": "Host Unchecked (Fastest, Unsafe)",
|
||||
"es_ES": "Host Sin Verificación (Más rápido, Inseguro)",
|
||||
"fr_FR": "Hôte Non Vérifié (plus rapide, non sécurisé)",
|
||||
"fr_FR": "Hôte Non Vérifié (Plus Rapide, Non Sécurisé)",
|
||||
"he_IL": "מארח לא מבוקר (המהיר ביותר, לא בטוח)",
|
||||
"it_IT": "Host senza verifica (più veloce, non sicura)",
|
||||
"ja_JP": "ホスト, チェックなし (最高速, 安全でない)",
|
||||
@@ -3350,7 +3350,7 @@
|
||||
"el_GR": "Ερώτημα",
|
||||
"en_US": "Prompt",
|
||||
"es_ES": "Al Inicio",
|
||||
"fr_FR": "Demande",
|
||||
"fr_FR": "Demander",
|
||||
"he_IL": "הודעה",
|
||||
"it_IT": "Domanda",
|
||||
"ja_JP": "プロンプト",
|
||||
@@ -4800,7 +4800,7 @@
|
||||
"el_GR": "Backend Ήχου:",
|
||||
"en_US": "Audio Backend:",
|
||||
"es_ES": "Motor de Audio:",
|
||||
"fr_FR": "Bibliothèque Audio :",
|
||||
"fr_FR": "Moteur Audio :",
|
||||
"he_IL": "אחראי שמע:",
|
||||
"it_IT": "Backend audio:",
|
||||
"ja_JP": "音声バックエンド:",
|
||||
@@ -5700,7 +5700,7 @@
|
||||
"el_GR": "Έκταση σε όλο το παράθυρο",
|
||||
"en_US": "Stretch to Fit Window",
|
||||
"es_ES": "Estirar a la Ventana",
|
||||
"fr_FR": "Ajuster à la Taille de la Fenêtre",
|
||||
"fr_FR": "Adapter à la Taille de la Fenêtre",
|
||||
"he_IL": "מתח לגודל חלון",
|
||||
"it_IT": "Adatta alla finestra",
|
||||
"ja_JP": "ウインドウサイズに合わせる",
|
||||
@@ -5750,7 +5750,7 @@
|
||||
"el_GR": "Τοποθεσία Shaders Γραφικών:",
|
||||
"en_US": "Graphics Shader Dump Path:",
|
||||
"es_ES": "Directorio de Volcado de Sombreadores:",
|
||||
"fr_FR": "Chemin du Dossier de Copie des Shaders :",
|
||||
"fr_FR": "Chemin du dump des shaders graphiques :",
|
||||
"he_IL": "",
|
||||
"it_IT": "Percorso di dump degli shader:",
|
||||
"ja_JP": "グラフィックス シェーダー ダンプパス:",
|
||||
@@ -15000,7 +15000,7 @@
|
||||
"el_GR": "Πολυνηματική Επεξεργασία Γραφικών:",
|
||||
"en_US": "Graphics Backend Multithreading:",
|
||||
"es_ES": "Multihilado del Motor Gráfico:",
|
||||
"fr_FR": "Interface graphique multithread :",
|
||||
"fr_FR": "Interface Graphique Multithread :",
|
||||
"he_IL": "אחראי גרפיקה רב-תהליכי:",
|
||||
"it_IT": "Multithreading del backend grafico:",
|
||||
"ja_JP": "グラフィックスバックエンドのマルチスレッド実行:",
|
||||
@@ -16598,9 +16598,9 @@
|
||||
"ar_SA": "",
|
||||
"de_DE": "Diese Option überspringt den Dialog 'Benutzerprofile verwalten' während des Spiels und verwendet ein voreingestelltes Profil.\n\nDie Profilumschaltung finden Sie unter 'Einstellungen' - 'Benutzerprofile verwalten'. Wählen Sie das gewünschte Profil aus, bevor Sie das Spiel laden.",
|
||||
"el_GR": "Αυτή η επιλογή παρακάμπτει το παράθυρο διαλόγου 'Διαχειριστής Προφίλ Χρήστη' κατά τη διάρκεια του παιχνιδιού, χρησιμοποιώντας ένα προεπιλεγμένο προφίλ.\n\nΗ εναλλαγή προφίλ βρίσκεται στις 'Ρυθμίσεις' - 'Διαχειριστής Προφίλ Χρήστη'. Επιλέξτε το επιθυμητό προφίλ πριν φορτώσετε το παιχνίδι.",
|
||||
"en_US": "This option skips the 'Manage User Profiles' dialog during gameplay, using a pre-selected profile.\n\nProfile switching is found in 'Settings' - 'Manager User Profiles'. Select the desired profile before loading the game.",
|
||||
"es_ES": "Esta opción omite el diálogo de 'Gestionar perfiles de usuario' durante el juego, utilizando un perfil preseleccionado.\n\nEl cambio de perfil se encuentra en 'Configuración' - 'Gestionar perfiles de usuario'. Seleccione el perfil deseado antes de cargar el juego.",
|
||||
"fr_FR": "Cette option permet d'éviter le dialogue du 'Gérer les profils d'utilisateurs' pendant le jeu, en utilisant un profil pré-sélectionné.\n\nLa sélection du profil se trouve dans 'Paramètres' - 'Gérer les profils d'utilisateurs'. Sélectionnez le profil souhaité avant de lancer le jeu.",
|
||||
"en_US": "This option skips the 'Manage User Profiles' dialog during gameplay, using a pre-selected profile.\n\nProfile switching is found in 'Options' - 'User Profiles'. Select the desired profile before loading the game.",
|
||||
"es_ES": "Esta opción omite el diálogo de 'Gestionar perfiles de usuario' durante el juego, utilizando un perfil preseleccionado.\n\nEl cambio de perfil se encuentra en 'Opciones' - 'Perfiles de Usuario'. Seleccione el perfil deseado antes de cargar el juego.",
|
||||
"fr_FR": "Cette option permet de passer le dialogue 'Gérer les profils d'utilisateurs' pendant le jeu, en utilisant un profil pré-sélectionné.\n\nLa sélection du profil se trouve dans 'Options' - 'Profils d'Utilisateurs'. Sélectionnez le profil souhaité avant de lancer le jeu.",
|
||||
"he_IL": "",
|
||||
"it_IT": "Questa opzione salta la finestra di dialogo 'Gestisci i profili utente' durante il gioco, utilizzando un profilo pre-selezionato.\n\nIl cambio del profilo si trova in 'Impostazioni' - 'Gestisci i profili utente'. Seleziona il profilo desiderato prima di caricare il gioco.",
|
||||
"ja_JP": "このオプションは、ゲームプレイ中に「ユーザプロファイルを管理」ダイアログをスキップし、事前に選択されたプロファイルを使用します。\n\nプロファイルの切り替えは、「設定」-「ユーザプロファイルを管理」で見つけることができます。ゲームのロード前に目的のプロファイルをを選択してください。",
|
||||
@@ -22520,26 +22520,26 @@
|
||||
{
|
||||
"ID": "MultiplayerModeTooltip",
|
||||
"Translations": {
|
||||
"ar_SA": "تغيير وضع LDN متعدد اللاعبين.\n\nسوف يقوم LdnMitm بتعديل وظيفة اللعب المحلية/اللاسلكية المحلية في الألعاب لتعمل كما لو كانت شبكة LAN، مما يسمح باتصالات الشبكة المحلية نفسها مع محاكيات ريوجينكس الأخرى وأجهزة نينتندو سويتش المخترقة التي تم تثبيت وحدة ldn_mitm عليها.\n\nيتطلب وضع اللاعبين المتعددين أن يكون جميع اللاعبين على نفس إصدار اللعبة (على سبيل المثال، يتعذر على الإصدار 13.0.1 من سوبر سماش برذرز ألتميت الاتصال بالإصدار 13.0.0).\n\nاتركه معطلا إذا لم تكن متأكدا.",
|
||||
"de_DE": "Ändert den LDN-Mehrspielermodus.\n\nLdnMitm ändert die lokale drahtlose/lokale Spielfunktionalität in Spielen so, dass sie wie ein LAN funktioniert und lokale, netzwerkgleiche Verbindungen mit anderen Ryujinx-Instanzen und gehackten Nintendo Switch-Konsolen ermöglicht, auf denen das ldn_mitm-Modul installiert ist.\n\nMultiplayer erfordert, dass alle Spieler die gleiche Spielversion verwenden (d.h. Super Smash Bros. Ultimate v13.0.1 kann sich nicht mit v13.0.0 verbinden).\n\nIm Zweifelsfall auf DISABLED lassen.",
|
||||
"ar_SA": "تغيير وضع LDN متعدد اللاعبين.\n\nسوف يقوم ldn_mitm بتعديل وظيفة اللعب المحلية/اللاسلكية المحلية في الألعاب لتعمل كما لو كانت شبكة LAN، مما يسمح باتصالات الشبكة المحلية نفسها مع محاكيات ريوجينكس الأخرى وأجهزة نينتندو سويتش المخترقة التي تم تثبيت وحدة ldn_mitm عليها.\n\nيتطلب وضع اللاعبين المتعددين أن يكون جميع اللاعبين على نفس إصدار اللعبة (على سبيل المثال، يتعذر على الإصدار 13.0.1 من سوبر سماش برذرز ألتميت الاتصال بالإصدار 13.0.0).\n\nاتركه معطلا إذا لم تكن متأكدا.",
|
||||
"de_DE": "Ändert den LDN-Mehrspielermodus.\n\nldn_mitm ändert die lokale drahtlose/lokale Spielfunktionalität in Spielen so, dass sie wie ein LAN funktioniert und lokale, netzwerkgleiche Verbindungen mit anderen Ryujinx-Instanzen und gehackten Nintendo Switch-Konsolen ermöglicht, auf denen das ldn_mitm-Modul installiert ist.\n\nMultiplayer erfordert, dass alle Spieler die gleiche Spielversion verwenden (d.h. Super Smash Bros. Ultimate v13.0.1 kann sich nicht mit v13.0.0 verbinden).\n\nIm Zweifelsfall auf DISABLED lassen.",
|
||||
"el_GR": "",
|
||||
"en_US": "Change LDN multiplayer mode.\n\nLdnMitm will modify local wireless/local play functionality in games to function as if it were LAN, allowing for local, same-network connections with other Ryujinx instances and hacked Nintendo Switch consoles that have the ldn_mitm module installed.\n\nMultiplayer requires all players to be on the same game version (i.e. Super Smash Bros. Ultimate v13.0.1 can't connect to v13.0.0).\n\nLeave DISABLED if unsure.",
|
||||
"es_ES": "Cambiar modo LDN multijugador.\n\nLdnMitm modificará la funcionalidad local de juego inalámbrico para funcionar como si fuera LAN, permitiendo locales conexiones de la misma red con otras instancias de Ryujinx y consolas hackeadas de Nintendo Switch que tienen instalado el módulo ldn_mitm.\n\nMultijugador requiere que todos los jugadores estén en la misma versión del juego (por ejemplo, Super Smash Bros. Ultimate v13.0.1 no se puede conectar a v13.0.0).\n\nDejar DESACTIVADO si no está seguro.",
|
||||
"fr_FR": "Change le mode multijoueur LDN.\n\nLdnMitm modifiera la fonctionnalité de jeu sans fil local/jeu local dans les jeux pour fonctionner comme s'il s'agissait d'un LAN, permettant des connexions locales sur le même réseau avec d'autres instances de Ryujinx et des consoles Nintendo Switch piratées ayant le module ldn_mitm installé.\n\nLe multijoueur nécessite que tous les joueurs soient sur la même version du jeu (par exemple, Super Smash Bros. Ultimate v13.0.1 ne peut pas se connecter à v13.0.0).\n\nLaissez DÉSACTIVÉ si vous n'êtes pas sûr.",
|
||||
"en_US": "Change LDN multiplayer mode.\n\nldn_mitm will modify local wireless/local play functionality in games to function as if it were LAN, allowing for local, same-network connections with other Ryujinx instances and hacked Nintendo Switch consoles that have the ldn_mitm module installed.\n\nMultiplayer requires all players to be on the same game version (i.e. Super Smash Bros. Ultimate v13.0.1 can't connect to v13.0.0).\n\nLeave DISABLED if unsure.",
|
||||
"es_ES": "Cambiar modo LDN multijugador.\n\nldn_mitm modificará la funcionalidad local de juego inalámbrico para funcionar como si fuera LAN, permitiendo locales conexiones de la misma red con otras instancias de Ryujinx y consolas hackeadas de Nintendo Switch que tienen instalado el módulo ldn_mitm.\n\nMultijugador requiere que todos los jugadores estén en la misma versión del juego (por ejemplo, Super Smash Bros. Ultimate v13.0.1 no se puede conectar a v13.0.0).\n\nDejar DESACTIVADO si no está seguro.",
|
||||
"fr_FR": "Change le mode multijoueur LDN.\n\nldn_mitm modifiera la fonctionnalité de jeu sans fil local/jeu local dans les jeux pour fonctionner comme s'il s'agissait d'un LAN, permettant des connexions locales sur le même réseau avec d'autres instances de Ryujinx et des consoles Nintendo Switch piratées ayant le module ldn_mitm installé.\n\nLe multijoueur nécessite que tous les joueurs soient sur la même version du jeu (par exemple, Super Smash Bros. Ultimate v13.0.1 ne peut pas se connecter à v13.0.0).\n\nLaissez DÉSACTIVÉ si vous n'êtes pas sûr.",
|
||||
"he_IL": "",
|
||||
"it_IT": "Cambia la modalità multigiocatore LDN.\n\nLdnMitm modificherà la funzionalità locale wireless/local play nei giochi per funzionare come se fosse in modalità LAN, consentendo connessioni locali sulla stessa rete con altre istanze di Ryujinx e console Nintendo Switch modificate che hanno il modulo ldn_mitm installato.\n\nLa modalità multigiocatore richiede che tutti i giocatori usino la stessa versione del gioco (es. Super Smash Bros. Ultimate v13.0.1 non può connettersi con la v13.0.0).\n\nNel dubbio, lascia l'opzione su Disabilitato.",
|
||||
"it_IT": "Cambia la modalità multigiocatore LDN.\n\nldn_mitm modificherà la funzionalità locale wireless/local play nei giochi per funzionare come se fosse in modalità LAN, consentendo connessioni locali sulla stessa rete con altre istanze di Ryujinx e console Nintendo Switch modificate che hanno il modulo ldn_mitm installato.\n\nLa modalità multigiocatore richiede che tutti i giocatori usino la stessa versione del gioco (es. Super Smash Bros. Ultimate v13.0.1 non può connettersi con la v13.0.0).\n\nNel dubbio, lascia l'opzione su Disabilitato.",
|
||||
"ja_JP": "LDNマルチプレイヤーモードを変更します.\n\nldn_mitmモジュールがインストールされた, 他のRyujinxインスタンスや,ハックされたNintendo Switchコンソールとのローカル/同一ネットワーク接続を可能にします.\n\nマルチプレイでは, すべてのプレイヤーが同じゲームバージョンである必要があります(例:Super Smash Bros. Ultimate v13.0.1はv13.0.0に接続できません).\n\n不明な場合は「無効」のままにしてください.",
|
||||
"ko_KR": "LDN 멀티플레이어 모드를 변경합니다.\n\nLdnMitm은 게임의 로컬 무선/로컬 플레이 기능을 LAN처럼 작동하도록 수정하여 다른 Ryujinx 인스턴스나 ldn_mitm 모듈이 설치된 해킹된 Nintendo Switch 콘솔과 로컬, 동일 네트워크 연결이 가능합니다.\n\n멀티플레이어는 모든 플레이어가 동일한 게임 버전을 사용해야 합니다(예 : 슈퍼 스매시브라더스 얼티밋 v13.0.1은 v13.0.0에 연결할 수 없음).\n\n모르면 비활성화 상태로 두세요.",
|
||||
"no_NO": "Endre LDN flerspillermodus.\n\nLdnMitm vil endre lokal trådløst/lokal spillfunksjonalitet i spill som skal fungere som om den var LAN, noe som tillater lokal, samme nettverk forbindelser med andre Ryujinx instanser og hacket Nintendo Switch konsoller som har installert ldn_mitm-modulen.\n\nFlerspiller krever at alle spillerne er på samme versjon (dvs. Super Smash Bros. Ultimat v13.0.1 kan ikke koble til v13.0.0).\n\nForlat DEAKTIVERT hvis usikker.",
|
||||
"ko_KR": "LDN 멀티플레이어 모드를 변경합니다.\n\nldn_mitm은 게임의 로컬 무선/로컬 플레이 기능을 LAN처럼 작동하도록 수정하여 다른 Ryujinx 인스턴스나 ldn_mitm 모듈이 설치된 해킹된 Nintendo Switch 콘솔과 로컬, 동일 네트워크 연결이 가능합니다.\n\n멀티플레이어는 모든 플레이어가 동일한 게임 버전을 사용해야 합니다(예 : 슈퍼 스매시브라더스 얼티밋 v13.0.1은 v13.0.0에 연결할 수 없음).\n\n모르면 비활성화 상태로 두세요.",
|
||||
"no_NO": "Endre LDN flerspillermodus.\n\nldn_mitm vil endre lokal trådløst/lokal spillfunksjonalitet i spill som skal fungere som om den var LAN, noe som tillater lokal, samme nettverk forbindelser med andre Ryujinx instanser og hacket Nintendo Switch konsoller som har installert ldn_mitm-modulen.\n\nFlerspiller krever at alle spillerne er på samme versjon (dvs. Super Smash Bros. Ultimat v13.0.1 kan ikke koble til v13.0.0).\n\nForlat DEAKTIVERT hvis usikker.",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "Alterar o modo multiplayer LDN.\n\nLdnMitm modificará a funcionalidade de jogo sem fio/local nos jogos para funcionar como se fosse LAN, permitindo conexões locais, na mesma rede, com outras instâncias do Ryujinx e consoles Nintendo Switch hackeados que possuem o módulo ldn_mitm instalado.\n\nO multiplayer exige que todos os jogadores estejam na mesma versão do jogo (ex.: Super Smash Bros. Ultimate v13.0.1 não consegue se conectar à v13.0.0).\n\nDeixe DESATIVADO se estiver em dúvida.",
|
||||
"ru_RU": "Меняет многопользовательский режим LDN.\n\nLdnMitm модифицирует функциональность локальной беспроводной игры на одном устройстве в играх, позволяя играть с другими пользователями Ryujinx или взломанными консолями Nintendo Switch с установленным модулем ldn_mitm, находящимися в одной локальной сети друг с другом.\n\nМногопользовательская игра требует наличия у всех игроков одной и той же версии игры (т.е. Super Smash Bros. Ultimate v13.0.1 не может подключиться к v13.0.0).\n\nРекомендуется оставить выключенным.",
|
||||
"sv_SE": "Ändra LDN-flerspelarläge\n\nLdnMitm kommer att ändra lokal funktionalitet för trådlös/lokalt spel att fungera som om det vore ett LAN, vilket ger stöd för anslutningar med local och same-network med andra Ryujinx-instanser och hackade Nintendo Switch-konsoller som har modulen ldn_mitm installerad.\n\nFlerspelare kräver att alla spelare har samma spelversion (t.ex. Super Smash Bros. Ultimate v13.0.1 kan inte ansluta till v13.0.0).\n\nLämna INAKTIVERAD om du är osäker.",
|
||||
"th_TH": "เปลี่ยนโหมดผู้เล่นหลายคนของ LDN\n\nLdnMitm จะปรับเปลี่ยนฟังก์ชันการเล่นแบบไร้สาย/ภายใน จะให้เกมทำงานเหมือนกับว่าเป็น LAN ช่วยให้สามารถเชื่อมต่อภายในเครือข่ายเดียวกันกับอินสแตนซ์ Ryujinx อื่น ๆ และคอนโซล Nintendo Switch ที่ถูกแฮ็กซึ่งมีโมดูล ldn_mitm ติดตั้งอยู่\n\nผู้เล่นหลายคนต้องการให้ผู้เล่นทุกคนอยู่ในเกมเวอร์ชันเดียวกัน (เช่น Super Smash Bros. Ultimate v13.0.1 ไม่สามารถเชื่อมต่อกับ v13.0.0)\n\nปล่อยให้ปิดการใช้งานหากไม่แน่ใจ",
|
||||
"pt_BR": "Alterar o modo multiplayer LDN.\n\nldn_mitm modificará a funcionalidade de jogo sem fio/local nos jogos para funcionar como se fosse LAN, permitindo conexões locais, na mesma rede, com outras instâncias do Ryujinx e consoles Nintendo Switch hackeados que possuem o módulo ldn_mitm instalado.\n\nO multiplayer exige que todos os jogadores estejam na mesma versão do jogo (ex.: Super Smash Bros. Ultimate v13.0.1 não consegue se conectar à v13.0.0).\n\nDeixe DESATIVADO se estiver em dúvida.",
|
||||
"ru_RU": "Меняет многопользовательский режим LDN.\n\nldn_mitm модифицирует функциональность локальной беспроводной игры на одном устройстве в играх, позволяя играть с другими пользователями Ryujinx или взломанными консолями Nintendo Switch с установленным модулем ldn_mitm, находящимися в одной локальной сети друг с другом.\n\nМногопользовательская игра требует наличия у всех игроков одной и той же версии игры (т.е. Super Smash Bros. Ultimate v13.0.1 не может подключиться к v13.0.0).\n\nРекомендуется оставить выключенным.",
|
||||
"sv_SE": "Ändra LDN-flerspelarläge\n\nldn_mitm kommer att ändra lokal funktionalitet för trådlös/lokalt spel att fungera som om det vore ett LAN, vilket ger stöd för anslutningar med local och same-network med andra Ryujinx-instanser och hackade Nintendo Switch-konsoller som har modulen ldn_mitm installerad.\n\nFlerspelare kräver att alla spelare har samma spelversion (t.ex. Super Smash Bros. Ultimate v13.0.1 kan inte ansluta till v13.0.0).\n\nLämna INAKTIVERAD om du är osäker.",
|
||||
"th_TH": "เปลี่ยนโหมดผู้เล่นหลายคนของ LDN\n\nldn_mitm จะปรับเปลี่ยนฟังก์ชันการเล่นแบบไร้สาย/ภายใน จะให้เกมทำงานเหมือนกับว่าเป็น LAN ช่วยให้สามารถเชื่อมต่อภายในเครือข่ายเดียวกันกับอินสแตนซ์ Ryujinx อื่น ๆ และคอนโซล Nintendo Switch ที่ถูกแฮ็กซึ่งมีโมดูล ldn_mitm ติดตั้งอยู่\n\nผู้เล่นหลายคนต้องการให้ผู้เล่นทุกคนอยู่ในเกมเวอร์ชันเดียวกัน (เช่น Super Smash Bros. Ultimate v13.0.1 ไม่สามารถเชื่อมต่อกับ v13.0.0)\n\nปล่อยให้ปิดการใช้งานหากไม่แน่ใจ",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Змінити LDN мультиплеєру.\n\nLdnMitm змінить функціонал бездротової/локальної гри в іграх, щоб вони працювали так, ніби це LAN, що дозволяє локальні підключення в тій самій мережі з іншими екземплярами Ryujinx та хакнутими консолями Nintendo Switch, які мають встановлений модуль ldn_mitm.\n\nМультиплеєр вимагає, щоб усі гравці були на одній і тій же версії гри (наприклад Super Smash Bros. Ultimate v13.0.1 не зможе під'єднатися до v13.0.0).\n\nЗалиште на \"Вимкнено\", якщо не впевнені.",
|
||||
"uk_UA": "Змінити LDN мультиплеєру.\n\nldn_mitm змінить функціонал бездротової/локальної гри в іграх, щоб вони працювали так, ніби це LAN, що дозволяє локальні підключення в тій самій мережі з іншими екземплярами Ryujinx та хакнутими консолями Nintendo Switch, які мають встановлений модуль ldn_mitm.\n\nМультиплеєр вимагає, щоб усі гравці були на одній і тій же версії гри (наприклад Super Smash Bros. Ultimate v13.0.1 не зможе під'єднатися до v13.0.0).\n\nЗалиште на \"Вимкнено\", якщо не впевнені.",
|
||||
"zh_CN": "修改 LDN 多人联机游玩模式。\n\nldn_mitm 联机插件将修改游戏中的本地无线和本地游玩功能,使其表现得像局域网一样,允许和其他安装了 ldn_mitm 插件的 Ryujinx 模拟器和破解的任天堂 Switch 主机在同一网络下进行本地连接,实现多人联机游玩。\n\n多人联机游玩要求所有玩家必须运行相同的游戏版本(例如,游戏版本 v13.0.1 无法与 v13.0.0 联机)。\n\n如果不确定,请保持为“禁用”。",
|
||||
"zh_TW": "變更 LDN 多人遊戲模式。\n\nLdnMitm 將修改遊戲中的本機無線/本機遊戲功能,使其如同區域網路一樣執行,允許與其他安裝了 ldn_mitm 模組的 Ryujinx 實例和已破解的 Nintendo Switch 遊戲機進行本機同網路連線。\n\n多人遊戲要求所有玩家使用相同的遊戲版本 (例如,Super Smash Bros. Ultimate v13.0.1 無法連接 v13.0.0)。\n\n如果不確定,請保持 Disabled (停用) 狀態。"
|
||||
"zh_TW": "變更 LDN 多人遊戲模式。\n\nldn_mitm 將修改遊戲中的本機無線/本機遊戲功能,使其如同區域網路一樣執行,允許與其他安裝了 ldn_mitm 模組的 Ryujinx 實例和已破解的 Nintendo Switch 遊戲機進行本機同網路連線。\n\n多人遊戲要求所有玩家使用相同的遊戲版本 (例如,Super Smash Bros. Ultimate v13.0.1 無法連接 v13.0.0)。\n\n如果不確定,請保持 Disabled (停用) 狀態。"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -22800,7 +22800,7 @@
|
||||
"el_GR": "",
|
||||
"en_US": "Generates a new passphrase, which can be shared with other players.",
|
||||
"es_ES": "Genera una nueva frase de contraseña, que puede ser compartida con otros jugadores.",
|
||||
"fr_FR": "Génére un nouveau mot de passe, qui peut être partagé avec les autres.",
|
||||
"fr_FR": "Génère un nouveau mot de passe, qui peut être partagé avec les autres.",
|
||||
"he_IL": "",
|
||||
"it_IT": "Genera una nuova passphrase, che può essere condivisa con altri giocatori.",
|
||||
"ja_JP": "",
|
||||
|
||||
BIN
distribution/macos/Assets.car
Normal file
BIN
distribution/macos/Assets.car
Normal file
Binary file not shown.
@@ -10,6 +10,8 @@
|
||||
<string>Ryujinx</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>Ryujinx.icns</string>
|
||||
<key>CFBundleIconName</key>
|
||||
<string>Ryujinx</string>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -40,7 +42,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.2</string>
|
||||
<string>1.3</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
@@ -25,6 +25,7 @@ cp "$PUBLISH_DIRECTORY"/*.dylib "$APP_BUNDLE_DIRECTORY/Contents/Frameworks"
|
||||
cp Info.plist "$APP_BUNDLE_DIRECTORY/Contents"
|
||||
cp Ryujinx.icns "$APP_BUNDLE_DIRECTORY/Contents/Resources/Ryujinx.icns"
|
||||
cp updater.sh "$APP_BUNDLE_DIRECTORY/Contents/Resources/updater.sh"
|
||||
cp Assets.car "$APP_BUNDLE_DIRECTORY/Contents/Resources/Assets.car"
|
||||
cp -r "$PUBLISH_DIRECTORY/THIRDPARTY.md" "$APP_BUNDLE_DIRECTORY/Contents/Resources"
|
||||
|
||||
echo -n "APPL????" > "$APP_BUNDLE_DIRECTORY/Contents/PkgInfo"
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
if [ "$#" -lt 8 ]; then
|
||||
echo "usage <BASE_DIR> <TEMP_DIRECTORY> <OUTPUT_DIRECTORY> <ENTITLEMENTS_FILE_PATH> <VERSION> <SOURCE_REVISION_ID> <CONFIGURATION> <CANARY>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$1"
|
||||
mkdir -p "$2"
|
||||
mkdir -p "$3"
|
||||
|
||||
BASE_DIR=$(readlink -f "$1")
|
||||
TEMP_DIRECTORY=$(readlink -f "$2")
|
||||
OUTPUT_DIRECTORY=$(readlink -f "$3")
|
||||
ENTITLEMENTS_FILE_PATH=$(readlink -f "$4")
|
||||
VERSION=$5
|
||||
SOURCE_REVISION_ID=$6
|
||||
CONFIGURATION=$7
|
||||
CANARY=$8
|
||||
|
||||
if [[ "$(uname)" == "Darwin" ]]; then
|
||||
echo "Clearing xattr on all dot undercsore files"
|
||||
find "$BASE_DIR" -type f -name "._*" -exec sh -c '
|
||||
for f; do
|
||||
dir=$(dirname "$f")
|
||||
base=$(basename "$f")
|
||||
orig="$dir/${base#._}"
|
||||
[ -f "$orig" ] && xattr -c "$orig" || true
|
||||
done
|
||||
' sh {} +
|
||||
fi
|
||||
|
||||
if [ "$CANARY" == "1" ]; then
|
||||
RELEASE_TAR_FILE_NAME=nogui-ryujinx-canary-$VERSION-macos_universal.tar
|
||||
elif [ "$VERSION" == "1.1.0" ]; then
|
||||
RELEASE_TAR_FILE_NAME=nogui-ryujinx-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.tar
|
||||
else
|
||||
RELEASE_TAR_FILE_NAME=nogui-ryujinx-$VERSION-macos_universal.tar
|
||||
fi
|
||||
|
||||
ARM64_OUTPUT="$TEMP_DIRECTORY/publish_arm64"
|
||||
X64_OUTPUT="$TEMP_DIRECTORY/publish_x64"
|
||||
UNIVERSAL_OUTPUT="$OUTPUT_DIRECTORY/publish"
|
||||
EXECUTABLE_SUB_PATH=Ryujinx.Headless.SDL3
|
||||
|
||||
rm -rf "$TEMP_DIRECTORY"
|
||||
mkdir -p "$TEMP_DIRECTORY"
|
||||
|
||||
DOTNET_COMMON_ARGS=(-p:DebugType=embedded -p:Version="$VERSION" -p:SourceRevisionId="$SOURCE_REVISION_ID" --self-contained true $EXTRA_ARGS)
|
||||
|
||||
dotnet restore
|
||||
dotnet build -c "$CONFIGURATION" src/Ryujinx.Headless.SDL3
|
||||
dotnet publish -c "$CONFIGURATION" -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Headless.SDL3
|
||||
dotnet publish -c "$CONFIGURATION" -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" "${DOTNET_COMMON_ARGS[@]}" src/Ryujinx.Headless.SDL3
|
||||
|
||||
# Get rid of the support library for ARMeilleure for x64 (that's only for arm64)
|
||||
rm -rf "$TEMP_DIRECTORY/publish_x64/libarmeilleure-jitsupport.dylib"
|
||||
|
||||
# Get rid of libsoundio from arm64 builds as we don't have a arm64 variant
|
||||
# TODO: remove this once done
|
||||
rm -rf "$TEMP_DIRECTORY/publish_arm64/libsoundio.dylib"
|
||||
|
||||
rm -rf "$OUTPUT_DIRECTORY"
|
||||
mkdir -p "$OUTPUT_DIRECTORY"
|
||||
|
||||
# Let's copy one of the two different outputs and remove the executable
|
||||
cp -R "$ARM64_OUTPUT/" "$UNIVERSAL_OUTPUT"
|
||||
rm "$UNIVERSAL_OUTPUT/$EXECUTABLE_SUB_PATH"
|
||||
|
||||
# Make its libraries universal
|
||||
python3 "$BASE_DIR/distribution/macos/construct_universal_dylib.py" "$ARM64_OUTPUT" "$X64_OUTPUT" "$UNIVERSAL_OUTPUT" "**/*.dylib"
|
||||
|
||||
if ! [ -x "$(command -v lipo)" ];
|
||||
then
|
||||
if ! [ -x "$(command -v llvm-lipo-17)" ];
|
||||
then
|
||||
LIPO=llvm-lipo
|
||||
else
|
||||
LIPO=llvm-lipo-17
|
||||
fi
|
||||
else
|
||||
LIPO=lipo
|
||||
fi
|
||||
|
||||
# Make the executable universal
|
||||
$LIPO "$ARM64_OUTPUT/$EXECUTABLE_SUB_PATH" "$X64_OUTPUT/$EXECUTABLE_SUB_PATH" -output "$UNIVERSAL_OUTPUT/$EXECUTABLE_SUB_PATH" -create
|
||||
|
||||
# Now sign it
|
||||
if ! [ -x "$(command -v codesign)" ];
|
||||
then
|
||||
if ! [ -x "$(command -v rcodesign)" ];
|
||||
then
|
||||
echo "Cannot find rcodesign on your system, please install rcodesign."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# NOTE: Currently require https://github.com/indygreg/apple-platform-rs/pull/44 to work on other OSes.
|
||||
# cargo install --git "https://github.com/marysaka/apple-platform-rs" --branch "fix/adhoc-app-bundle" apple-codesign --bin "rcodesign"
|
||||
echo "Using rcodesign for ad-hoc signing"
|
||||
for FILE in "$UNIVERSAL_OUTPUT"/*; do
|
||||
if [[ $(file "$FILE") == *"Mach-O"* ]]; then
|
||||
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$FILE"
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "Using codesign for ad-hoc signing"
|
||||
for FILE in "$UNIVERSAL_OUTPUT"/*; do
|
||||
if [[ $(file "$FILE") == *"Mach-O"* ]]; then
|
||||
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f -s - "$FILE"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
echo "Creating archive"
|
||||
pushd "$OUTPUT_DIRECTORY"
|
||||
tar --exclude "publish/Ryujinx.Headless.SDL3" -cvf "$RELEASE_TAR_FILE_NAME" publish 1> /dev/null
|
||||
python3 "$BASE_DIR/distribution/misc/add_tar_exec.py" "$RELEASE_TAR_FILE_NAME" "publish/Ryujinx.Headless.SDL3" "publish/Ryujinx.Headless.SDL3"
|
||||
gzip -9 < "$RELEASE_TAR_FILE_NAME" > "$RELEASE_TAR_FILE_NAME.gz"
|
||||
rm "$RELEASE_TAR_FILE_NAME"
|
||||
popd
|
||||
|
||||
echo "Done"
|
||||
@@ -2275,12 +2275,12 @@
|
||||
010018E011D92000,"Pokémon™ Shining Pearl",gpu;ldn-works,ingame,2024-08-28 13:26:35
|
||||
010015F008C54000,"Pokémon™ HOME",Needs Update;crash;services,menus,2020-12-06 06:01:51
|
||||
01001F5010DFA000,"Pokémon™ Legends: Arceus",gpu;Needs Update;ldn-works,ingame,2024-09-19 10:02:02
|
||||
0100F43008C44000,"Pokémon™ Legends: Z-A",gpu;crash;ldn-works,ingame,2025-11-16 00:30:00
|
||||
01005D100807A000,"Pokémon™ Quest",,playable,2022-02-22 16:12:32
|
||||
0100A3D008C5C000,"Pokémon™ Scarlet",gpu;nvdec;ldn-works;amd-vendor-bug,ingame,2023-12-14 13:18:29
|
||||
01008F6008C5E000,"Pokémon™ Violet",gpu;nvdec;ldn-works;amd-vendor-bug;mac-bug,ingame,2024-07-30 02:51:48
|
||||
0100187003A36000,"Pokémon™: Let’s Go, Eevee!",crash;nvdec;online-broken;ldn-broken,ingame,2024-06-01 15:03:04
|
||||
010003F003A34000,"Pokémon™: Let’s Go, Pikachu!",crash;nvdec;online-broken;ldn-broken,ingame,2024-03-15 07:55:41
|
||||
0100F43008C44000,"Pokémon Legends: Z-A",gpu;crash;ldn-broken,ingame,2025-10-16 19:13:00
|
||||
0100B3F000BE2000,"Pokkén Tournament™ DX",nvdec;ldn-works;opengl-backend-bug;LAN;amd-vendor-bug;intel-vendor-bug,playable,2024-07-18 23:11:08
|
||||
010030D005AE6000,"Pokkén Tournament™ DX Demo",demo;opengl-backend-bug,playable,2022-08-10 12:03:19
|
||||
0100A3500B4EC000,"Polandball: Can Into Space",,playable,2020-06-25 15:13:26
|
||||
|
||||
|
@@ -19,7 +19,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
context.LoadFromContext();
|
||||
|
||||
context.Return(Const(op.Address));
|
||||
InstEmitFlowHelper.EmitReturn(context, Const(op.Address));
|
||||
}
|
||||
|
||||
public static void Svc(ArmEmitterContext context)
|
||||
@@ -49,7 +49,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
context.LoadFromContext();
|
||||
|
||||
context.Return(Const(op.Address));
|
||||
InstEmitFlowHelper.EmitReturn(context, Const(op.Address));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
context.LoadFromContext();
|
||||
|
||||
context.Return(Const(context.CurrOp.Address));
|
||||
InstEmitFlowHelper.EmitReturn(context, Const(context.CurrOp.Address));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
OpCodeBReg op = (OpCodeBReg)context.CurrOp;
|
||||
|
||||
context.Return(GetIntOrZR(context, op.Rn));
|
||||
EmitReturn(context, GetIntOrZR(context, op.Rn));
|
||||
}
|
||||
|
||||
public static void Tbnz(ArmEmitterContext context) => EmitTb(context, onNotZero: true);
|
||||
|
||||
@@ -13,6 +13,10 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
static class InstEmitFlowHelper
|
||||
{
|
||||
// How many calls we can have in our call stack before we give up and return to the dispatcher.
|
||||
// This prevents stack overflows caused by deep recursive calls.
|
||||
private const int MaxCallDepth = 200;
|
||||
|
||||
public static void EmitCondBranch(ArmEmitterContext context, Operand target, Condition cond)
|
||||
{
|
||||
if (cond != Condition.Al)
|
||||
@@ -182,12 +186,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
if (isReturn || context.IsSingleStep)
|
||||
{
|
||||
if (target.Type == OperandType.I32)
|
||||
{
|
||||
target = context.ZeroExtend32(OperandType.I64, target);
|
||||
}
|
||||
|
||||
context.Return(target);
|
||||
EmitReturn(context, target);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -195,6 +194,19 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitReturn(ArmEmitterContext context, Operand target)
|
||||
{
|
||||
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
|
||||
DecreaseCallDepth(context, nativeContext);
|
||||
|
||||
if (target.Type == OperandType.I32)
|
||||
{
|
||||
target = context.ZeroExtend32(OperandType.I64, target);
|
||||
}
|
||||
|
||||
context.Return(target);
|
||||
}
|
||||
|
||||
private static void EmitTableBranch(ArmEmitterContext context, Operand guestAddress, bool isJump)
|
||||
{
|
||||
context.StoreToContext();
|
||||
@@ -257,6 +269,8 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
if (isJump)
|
||||
{
|
||||
DecreaseCallDepth(context, nativeContext);
|
||||
|
||||
context.Tailcall(hostAddress, nativeContext);
|
||||
}
|
||||
else
|
||||
@@ -278,8 +292,42 @@ namespace ARMeilleure.Instructions
|
||||
Operand lblContinue = context.GetLabel(nextAddr.Value);
|
||||
context.BranchIf(lblContinue, returnAddress, nextAddr, Comparison.Equal, BasicBlockFrequency.Cold);
|
||||
|
||||
DecreaseCallDepth(context, nativeContext);
|
||||
|
||||
context.Return(returnAddress);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitCallDepthCheckAndIncrement(EmitterContext context, Operand guestAddress)
|
||||
{
|
||||
if (!Optimizations.EnableDeepCallRecursionProtection)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
|
||||
Operand callDepthAddr = context.Add(nativeContext, Const((ulong)NativeContext.GetCallDepthOffset()));
|
||||
Operand currentCallDepth = context.Load(OperandType.I32, callDepthAddr);
|
||||
Operand lblDoCall = Label();
|
||||
|
||||
context.BranchIf(lblDoCall, currentCallDepth, Const(MaxCallDepth), Comparison.LessUI);
|
||||
context.Store(callDepthAddr, context.Subtract(currentCallDepth, Const(1)));
|
||||
context.Return(guestAddress);
|
||||
|
||||
context.MarkLabel(lblDoCall);
|
||||
context.Store(callDepthAddr, context.Add(currentCallDepth, Const(1)));
|
||||
}
|
||||
|
||||
private static void DecreaseCallDepth(EmitterContext context, Operand nativeContext)
|
||||
{
|
||||
if (!Optimizations.EnableDeepCallRecursionProtection)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Operand callDepthAddr = context.Add(nativeContext, Const((ulong)NativeContext.GetCallDepthOffset()));
|
||||
Operand currentCallDepth = context.Load(OperandType.I32, callDepthAddr);
|
||||
context.Store(callDepthAddr, context.Subtract(currentCallDepth, Const(1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace ARMeilleure
|
||||
public static bool AllowLcqInFunctionTable { get; set; } = true;
|
||||
public static bool UseUnmanagedDispatchLoop { get; set; } = true;
|
||||
public static bool EnableDebugging { get; set; } = false;
|
||||
public static bool EnableDeepCallRecursionProtection { get; set; } = true;
|
||||
|
||||
public static bool UseAdvSimdIfAvailable { get; set; } = true;
|
||||
public static bool UseArm64AesIfAvailable { get; set; } = true;
|
||||
|
||||
@@ -134,6 +134,11 @@ namespace ARMeilleure.State
|
||||
public bool GetFPstateFlag(FPState flag) => _nativeContext.GetFPStateFlag(flag);
|
||||
public void SetFPstateFlag(FPState flag, bool value) => _nativeContext.SetFPStateFlag(flag, value);
|
||||
|
||||
internal void ResetCallDepth()
|
||||
{
|
||||
_nativeContext.ResetCallDepth();
|
||||
}
|
||||
|
||||
internal void CheckInterrupt()
|
||||
{
|
||||
if (Interrupted)
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace ARMeilleure.State
|
||||
public ulong ExclusiveValueHigh;
|
||||
public int Running;
|
||||
public long Tpidr2El0;
|
||||
public int CallDepth;
|
||||
|
||||
/// <summary>
|
||||
/// Precise PC value used for debugging.
|
||||
@@ -199,6 +200,8 @@ namespace ARMeilleure.State
|
||||
public bool GetRunning() => GetStorage().Running != 0;
|
||||
public void SetRunning(bool value) => GetStorage().Running = value ? 1 : 0;
|
||||
|
||||
public void ResetCallDepth() => GetStorage().CallDepth = 0;
|
||||
|
||||
public unsafe static int GetRegisterOffset(Register reg)
|
||||
{
|
||||
if (reg.Type == RegisterType.Integer)
|
||||
@@ -284,6 +287,11 @@ namespace ARMeilleure.State
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.DebugPrecisePc);
|
||||
}
|
||||
|
||||
public static int GetCallDepthOffset()
|
||||
{
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.CallDepth);
|
||||
}
|
||||
|
||||
private static int StorageOffset<T>(ref NativeCtxStorage storage, ref T target)
|
||||
{
|
||||
return (int)Unsafe.ByteOffset(ref Unsafe.As<NativeCtxStorage, T>(ref storage), ref target);
|
||||
|
||||
@@ -361,10 +361,7 @@ namespace ARMeilleure.Translation
|
||||
|
||||
IntervalTreeNode<TK, TV> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
|
||||
|
||||
if (tmp != null)
|
||||
{
|
||||
tmp.Parent = ParentOf(replacementNode);
|
||||
}
|
||||
tmp?.Parent = ParentOf(replacementNode);
|
||||
|
||||
if (ParentOf(replacementNode) == null)
|
||||
{
|
||||
@@ -582,10 +579,7 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
IntervalTreeNode<TK, TV> right = RightOf(node);
|
||||
node.Right = LeftOf(right);
|
||||
if (node.Right != null)
|
||||
{
|
||||
node.Right.Parent = node;
|
||||
}
|
||||
node.Right?.Parent = node;
|
||||
|
||||
IntervalTreeNode<TK, TV> nodeParent = ParentOf(node);
|
||||
right.Parent = nodeParent;
|
||||
@@ -615,10 +609,7 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
IntervalTreeNode<TK, TV> left = LeftOf(node);
|
||||
node.Left = RightOf(left);
|
||||
if (node.Left != null)
|
||||
{
|
||||
node.Left.Parent = node;
|
||||
}
|
||||
node.Left?.Parent = node;
|
||||
|
||||
IntervalTreeNode<TK, TV> nodeParent = ParentOf(node);
|
||||
left.Parent = nodeParent;
|
||||
@@ -667,10 +658,7 @@ namespace ARMeilleure.Translation
|
||||
/// <param name="color">Color (Boolean)</param>
|
||||
private static void SetColor(IntervalTreeNode<TK, TV> node, bool color)
|
||||
{
|
||||
if (node != null)
|
||||
{
|
||||
node.Color = color;
|
||||
}
|
||||
node?.Color = color;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||
|
||||
private const uint InternalVersion = 7009; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
private const uint InternalVersion = 7010; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
|
||||
private const string ActualDir = "0";
|
||||
private const string BackupDir = "1";
|
||||
|
||||
@@ -186,6 +186,7 @@ namespace ARMeilleure.Translation
|
||||
|
||||
Statistics.StartTimer();
|
||||
|
||||
context.ResetCallDepth();
|
||||
ulong nextAddr = func.Execute(Stubs.ContextWrapper, context);
|
||||
|
||||
Statistics.StopTimer(address);
|
||||
@@ -260,6 +261,7 @@ namespace ARMeilleure.Translation
|
||||
|
||||
Logger.StartPass(PassName.Translation);
|
||||
|
||||
InstEmitFlowHelper.EmitCallDepthCheckAndIncrement(context, Const(address));
|
||||
EmitSynchronization(context);
|
||||
|
||||
if (blocks[0].Address != address)
|
||||
|
||||
@@ -262,10 +262,18 @@ namespace ARMeilleure.Translation
|
||||
|
||||
Operand runningAddress = context.Add(nativeContext, Const((ulong)NativeContext.GetRunningOffset()));
|
||||
Operand dispatchAddress = context.Add(nativeContext, Const((ulong)NativeContext.GetDispatchAddressOffset()));
|
||||
Operand callDepthAddress = context.Add(nativeContext, Const((ulong)NativeContext.GetCallDepthOffset()));
|
||||
|
||||
EmitSyncFpContext(context, nativeContext, true);
|
||||
|
||||
context.MarkLabel(beginLbl);
|
||||
|
||||
if (Optimizations.EnableDeepCallRecursionProtection)
|
||||
{
|
||||
// Reset the call depth counter, since this is our first guest function call.
|
||||
context.Store(callDepthAddress, Const(0));
|
||||
}
|
||||
|
||||
context.Store(dispatchAddress, guestAddress);
|
||||
context.Copy(guestAddress, context.Call(Const((ulong)DispatchStub), OperandType.I64, nativeContext));
|
||||
context.BranchIfFalse(endLbl, guestAddress);
|
||||
|
||||
@@ -92,6 +92,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
}
|
||||
|
||||
short[] outputBuffer = ArrayPool<short>.Shared.Rent((int)inputCount * SampleCount);
|
||||
Array.Fill(outputBuffer, (short)0, 0, (int)inputCount * SampleCount);
|
||||
|
||||
for (int i = 0; i < bufferCount; i++)
|
||||
{
|
||||
|
||||
@@ -386,10 +386,7 @@ namespace Ryujinx.Common.Collections
|
||||
|
||||
IntervalTreeNode<TKey, TValue> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
|
||||
|
||||
if (tmp != null)
|
||||
{
|
||||
tmp.Parent = ParentOf(replacementNode);
|
||||
}
|
||||
tmp?.Parent = ParentOf(replacementNode);
|
||||
|
||||
if (ParentOf(replacementNode) == null)
|
||||
{
|
||||
|
||||
@@ -235,10 +235,7 @@ namespace Ryujinx.Common.Collections
|
||||
parent = ParentOf(element);
|
||||
color = ColorOf(element);
|
||||
|
||||
if (child != null)
|
||||
{
|
||||
child.Parent = parent;
|
||||
}
|
||||
child?.Parent = parent;
|
||||
|
||||
if (parent == null)
|
||||
{
|
||||
@@ -258,8 +255,7 @@ namespace Ryujinx.Common.Collections
|
||||
element.Right = old.Right;
|
||||
element.Parent = old.Parent;
|
||||
element.Predecessor = old.Predecessor;
|
||||
if (element.Predecessor != null)
|
||||
element.Predecessor.Successor = element;
|
||||
element.Predecessor?.Successor = element;
|
||||
|
||||
if (ParentOf(old) == null)
|
||||
{
|
||||
@@ -292,10 +288,7 @@ namespace Ryujinx.Common.Collections
|
||||
parent = ParentOf(nodeToDelete);
|
||||
color = ColorOf(nodeToDelete);
|
||||
|
||||
if (child != null)
|
||||
{
|
||||
child.Parent = parent;
|
||||
}
|
||||
child?.Parent = parent;
|
||||
|
||||
if (parent == null)
|
||||
{
|
||||
@@ -314,11 +307,9 @@ namespace Ryujinx.Common.Collections
|
||||
{
|
||||
RestoreBalanceAfterRemoval(child);
|
||||
}
|
||||
|
||||
if (old.Successor != null)
|
||||
old.Successor.Predecessor = old.Predecessor;
|
||||
if (old.Predecessor != null)
|
||||
old.Predecessor.Successor = old.Successor;
|
||||
|
||||
old.Successor?.Predecessor = old.Predecessor;
|
||||
old.Predecessor?.Successor = old.Successor;
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
@@ -250,10 +250,7 @@ namespace Ryujinx.Common.Collections
|
||||
{
|
||||
T right = RightOf(node);
|
||||
node.Right = LeftOf(right);
|
||||
if (node.Right != null)
|
||||
{
|
||||
node.Right.Parent = node;
|
||||
}
|
||||
node.Right?.Parent = node;
|
||||
|
||||
T nodeParent = ParentOf(node);
|
||||
right.Parent = nodeParent;
|
||||
@@ -281,10 +278,7 @@ namespace Ryujinx.Common.Collections
|
||||
{
|
||||
T left = LeftOf(node);
|
||||
node.Left = RightOf(left);
|
||||
if (node.Left != null)
|
||||
{
|
||||
node.Left.Parent = node;
|
||||
}
|
||||
node.Left?.Parent = node;
|
||||
|
||||
T nodeParent = ParentOf(node);
|
||||
left.Parent = nodeParent;
|
||||
@@ -329,10 +323,7 @@ namespace Ryujinx.Common.Collections
|
||||
/// <param name="color">Color (Boolean)</param>
|
||||
protected static void SetColor(T node, bool color)
|
||||
{
|
||||
if (node != null)
|
||||
{
|
||||
node.Color = color;
|
||||
}
|
||||
node?.Color = color;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -328,10 +328,7 @@ namespace Ryujinx.Common.Collections
|
||||
|
||||
Node<TKey, TValue> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
|
||||
|
||||
if (tmp != null)
|
||||
{
|
||||
tmp.Parent = ParentOf(replacementNode);
|
||||
}
|
||||
tmp?.Parent = ParentOf(replacementNode);
|
||||
|
||||
if (ParentOf(replacementNode) == null)
|
||||
{
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace Ryujinx.Common.Logging
|
||||
ServiceBsd,
|
||||
ServiceBtm,
|
||||
ServiceCaps,
|
||||
ServiceEctx,
|
||||
ServiceFatal,
|
||||
ServiceFriend,
|
||||
ServiceFs,
|
||||
|
||||
@@ -84,10 +84,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
ICounterEvent evt = _items[index + i].Event;
|
||||
if (evt != null)
|
||||
{
|
||||
evt.Invalid = true;
|
||||
}
|
||||
evt?.Invalid = true;
|
||||
}
|
||||
|
||||
_items.RemoveRange(index, count);
|
||||
|
||||
@@ -26,12 +26,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
// - Both branches are jumping to the same location.
|
||||
// In this case, the branch on the current block can be removed,
|
||||
// as the next block is going to jump to the same place anyway.
|
||||
if (nextBlock == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nextBlock.Operations.First?.Value is not Operation next)
|
||||
if (nextBlock?.Operations.First?.Value is not Operation next)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -891,10 +891,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
|
||||
result = new NestedName(name, prev);
|
||||
}
|
||||
|
||||
if (context != null)
|
||||
{
|
||||
context.FinishWithTemplateArguments = false;
|
||||
}
|
||||
context?.FinishWithTemplateArguments = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1074,10 +1071,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
|
||||
return null;
|
||||
}
|
||||
|
||||
if (context != null)
|
||||
{
|
||||
context.CtorDtorConversion = true;
|
||||
}
|
||||
context?.CtorDtorConversion = true;
|
||||
|
||||
return new ConversionOperatorType(type);
|
||||
default:
|
||||
@@ -1349,10 +1343,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
|
||||
|
||||
_position++;
|
||||
|
||||
if (context != null)
|
||||
{
|
||||
context.CtorDtorConversion = true;
|
||||
}
|
||||
context?.CtorDtorConversion = true;
|
||||
|
||||
if (isInherited && ParseName(context) == null)
|
||||
{
|
||||
@@ -1372,10 +1363,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
|
||||
|
||||
_position++;
|
||||
|
||||
if (context != null)
|
||||
{
|
||||
context.CtorDtorConversion = true;
|
||||
}
|
||||
context?.CtorDtorConversion = true;
|
||||
|
||||
return new CtorDtorNameType(prev, true);
|
||||
}
|
||||
@@ -3005,16 +2993,10 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
|
||||
|
||||
BaseNode result = null;
|
||||
CvType cv = new(ParseCvQualifiers(), null);
|
||||
if (context != null)
|
||||
{
|
||||
context.Cv = cv;
|
||||
}
|
||||
context?.Cv = cv;
|
||||
|
||||
SimpleReferenceType Ref = ParseRefQualifiers();
|
||||
if (context != null)
|
||||
{
|
||||
context.Ref = Ref;
|
||||
}
|
||||
context?.Ref = Ref;
|
||||
|
||||
if (ConsumeIf("St"))
|
||||
{
|
||||
@@ -3060,10 +3042,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
|
||||
}
|
||||
|
||||
result = new NameTypeWithTemplateArguments(result, templateArgument);
|
||||
if (context != null)
|
||||
{
|
||||
context.FinishWithTemplateArguments = true;
|
||||
}
|
||||
context?.FinishWithTemplateArguments = true;
|
||||
|
||||
_substitutionList.Add(result);
|
||||
continue;
|
||||
@@ -3256,10 +3235,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
|
||||
return null;
|
||||
}
|
||||
|
||||
if (context != null)
|
||||
{
|
||||
context.FinishWithTemplateArguments = true;
|
||||
}
|
||||
context?.FinishWithTemplateArguments = true;
|
||||
|
||||
return new NameTypeWithTemplateArguments(substitution, templateArguments);
|
||||
}
|
||||
@@ -3279,10 +3255,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
|
||||
return null;
|
||||
}
|
||||
|
||||
if (context != null)
|
||||
{
|
||||
context.FinishWithTemplateArguments = true;
|
||||
}
|
||||
context?.FinishWithTemplateArguments = true;
|
||||
|
||||
return new NameTypeWithTemplateArguments(result, templateArguments);
|
||||
}
|
||||
|
||||
@@ -174,10 +174,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
if (previousThread != nextThread)
|
||||
{
|
||||
if (previousThread != null)
|
||||
{
|
||||
previousThread.LastScheduledTime = PerformanceCounter.ElapsedTicks;
|
||||
}
|
||||
previousThread?.LastScheduledTime = PerformanceCounter.ElapsedTicks;
|
||||
|
||||
_state.SelectedThread = nextThread;
|
||||
_state.NeedsScheduling = true;
|
||||
|
||||
32
src/Ryujinx.HLE/HOS/Services/Ectx/IContextRegistrar.cs
Normal file
32
src/Ryujinx.HLE/HOS/Services/Ectx/IContextRegistrar.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Horizon.Common;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Ectx
|
||||
{
|
||||
class IContextRegistrar : DisposableIpcService
|
||||
{
|
||||
public IContextRegistrar(ServiceCtx context) { }
|
||||
|
||||
[CommandCmif(0)] // 11.0.0+
|
||||
// Complete(nn::Result result, buffer<bytes, 5> raw_context) -> (i32 context_descriptor)
|
||||
public ResultCode Complete(ServiceCtx context)
|
||||
{
|
||||
Result result = new(context.RequestData.ReadInt32());
|
||||
ulong rawContextPosition = context.Request.SendBuff[0].Position;
|
||||
ulong rawContextSize = context.Request.SendBuff[0].Size;
|
||||
|
||||
byte[] rawContext = new byte[rawContextSize];
|
||||
|
||||
context.Memory.Read(rawContextPosition, rawContext);
|
||||
|
||||
context.ResponseData.Write(0); // TODO: return context_descriptor
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceEctx, $"Result: {result}, rawContext: {Convert.ToHexString(rawContext)}" );
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing) { }
|
||||
}
|
||||
}
|
||||
@@ -4,5 +4,14 @@ namespace Ryujinx.HLE.HOS.Services.Ectx
|
||||
class IWriterForApplication : IpcService
|
||||
{
|
||||
public IWriterForApplication(ServiceCtx context) { }
|
||||
|
||||
[CommandCmif(0)]
|
||||
// CreateContextRegistrar() -> object<nn::err::context::IContextRegistrar>
|
||||
public ResultCode CreateContextRegistrar(ServiceCtx context)
|
||||
{
|
||||
MakeObject(context, new IContextRegistrar(context));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1169,9 +1169,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||
|
||||
public override void DestroyAtExit()
|
||||
{
|
||||
if (_context != null) {
|
||||
_context.Dispose();
|
||||
}
|
||||
_context?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Ryujinx.Input.SDL3
|
||||
|
||||
private StandardControllerInputConfig _configuration;
|
||||
|
||||
private static readonly SDL_GamepadButton[] _buttonsDriverMapping =
|
||||
private readonly SDL_GamepadButton[] _buttonsDriverMapping =
|
||||
[
|
||||
// Unbound, ignored.
|
||||
SDL_GamepadButton.SDL_GAMEPAD_BUTTON_INVALID,
|
||||
@@ -88,6 +88,20 @@ namespace Ryujinx.Input.SDL3
|
||||
Features = GetFeaturesFlag();
|
||||
_triggerThreshold = 0.0f;
|
||||
|
||||
// Face button mapping
|
||||
SDL_GamepadButton[] faceButtons = _buttonsDriverMapping[1..5];
|
||||
foreach (SDL_GamepadButton btn in faceButtons) {
|
||||
int mapId = SDL_GetGamepadButtonLabel(_gamepadHandle, btn) switch {
|
||||
SDL_GamepadButtonLabel.SDL_GAMEPAD_BUTTON_LABEL_A or SDL_GamepadButtonLabel.SDL_GAMEPAD_BUTTON_LABEL_CROSS => 1,
|
||||
SDL_GamepadButtonLabel.SDL_GAMEPAD_BUTTON_LABEL_B or SDL_GamepadButtonLabel.SDL_GAMEPAD_BUTTON_LABEL_CIRCLE => 2,
|
||||
SDL_GamepadButtonLabel.SDL_GAMEPAD_BUTTON_LABEL_X or SDL_GamepadButtonLabel.SDL_GAMEPAD_BUTTON_LABEL_SQUARE => 3,
|
||||
SDL_GamepadButtonLabel.SDL_GAMEPAD_BUTTON_LABEL_Y or SDL_GamepadButtonLabel.SDL_GAMEPAD_BUTTON_LABEL_TRIANGLE => 4,
|
||||
_ => -1
|
||||
};
|
||||
if (mapId == -1) { continue; }
|
||||
_buttonsDriverMapping[mapId] = btn;
|
||||
}
|
||||
|
||||
// Enable motion tracking
|
||||
if ((Features & GamepadFeaturesFlag.Motion) != 0)
|
||||
{
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace Ryujinx.Input.SDL3
|
||||
|
||||
string strGuid = new(guidBytes);
|
||||
|
||||
return $"{strGuid[0..8]}-{strGuid[8..12]}-{strGuid[12..16]}-{strGuid[16..20]}-{strGuid[20..32]}";
|
||||
return $"{strGuid[4..6]}{strGuid[6..8]}{strGuid[2..4]}{strGuid[0..2]}-{strGuid[10..12]}{strGuid[8..10]}-{strGuid[12..16]}-{strGuid[16..20]}-{strGuid[20..32]}";
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -330,6 +330,7 @@ namespace Ryujinx.Input.HLE
|
||||
|
||||
_device.TamperMachine.UpdateInput(hleInputStates);
|
||||
|
||||
hleMotionStates.Clear();
|
||||
_hleMotionStatesPool.Release(hleMotionStates);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,10 +58,7 @@ namespace Ryujinx.Memory.Tracking
|
||||
{
|
||||
foreach (RegionHandle handle in _handles)
|
||||
{
|
||||
if (handle != null)
|
||||
{
|
||||
handle?.RegisterAction((address, size) => action(handle.Address, handle.Size));
|
||||
}
|
||||
handle?.RegisterAction((address, size) => action(handle.Address, handle.Size));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,10 +66,7 @@ namespace Ryujinx.Memory.Tracking
|
||||
{
|
||||
foreach (RegionHandle handle in _handles)
|
||||
{
|
||||
if (handle != null)
|
||||
{
|
||||
handle?.RegisterPreciseAction((address, size, write) => action(handle.Address, handle.Size, write));
|
||||
}
|
||||
handle?.RegisterPreciseAction((address, size, write) => action(handle.Address, handle.Size, write));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -196,22 +196,26 @@ namespace Ryujinx.Ava
|
||||
return gameDir;
|
||||
}
|
||||
|
||||
public static void ReloadConfig()
|
||||
public static void ReloadConfig(bool isRunGameWithCustomConfig = false)
|
||||
{
|
||||
|
||||
string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ReleaseInformation.ConfigName);
|
||||
string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, ReleaseInformation.ConfigName);
|
||||
|
||||
// Now load the configuration as the other subsystems are now registered
|
||||
if (File.Exists(localConfigurationPath))
|
||||
{
|
||||
ConfigurationPath = localConfigurationPath;
|
||||
}
|
||||
else if (File.Exists(appDataConfigurationPath))
|
||||
{
|
||||
ConfigurationPath = appDataConfigurationPath;
|
||||
}
|
||||
|
||||
if (!isRunGameWithCustomConfig) // To return settings from the game folder if the user configuration exists
|
||||
{
|
||||
// Now load the configuration as the other subsystems are now registered
|
||||
if (File.Exists(localConfigurationPath))
|
||||
{
|
||||
ConfigurationPath = localConfigurationPath;
|
||||
}
|
||||
else if (File.Exists(appDataConfigurationPath))
|
||||
{
|
||||
ConfigurationPath = appDataConfigurationPath;
|
||||
}
|
||||
}
|
||||
|
||||
if (ConfigurationPath == null)
|
||||
{
|
||||
// No configuration, we load the default values and save it to disk
|
||||
@@ -233,6 +237,8 @@ namespace Ryujinx.Ava
|
||||
{
|
||||
Logger.Warning?.PrintMsg(LogClass.Application, $"Failed to load config! Loading the default config instead.\nFailed config location: {ConfigurationPath}");
|
||||
|
||||
ConfigurationFileFormat.RenameInvalidConfigFile(ConfigurationPath);
|
||||
|
||||
ConfigurationState.Instance.LoadDefault();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,18 +501,12 @@ namespace Ryujinx.Ava.Systems
|
||||
|
||||
private void UpdateIgnoreMissingServicesState(object sender, ReactiveEventArgs<bool> args)
|
||||
{
|
||||
if (Device != null)
|
||||
{
|
||||
Device.Configuration.IgnoreMissingServices = args.NewValue;
|
||||
}
|
||||
Device?.Configuration.IgnoreMissingServices = args.NewValue;
|
||||
}
|
||||
|
||||
private void UpdateAspectRatioState(object sender, ReactiveEventArgs<AspectRatio> args)
|
||||
{
|
||||
if (Device != null)
|
||||
{
|
||||
Device.Configuration.AspectRatio = args.NewValue;
|
||||
}
|
||||
Device?.Configuration.AspectRatio = args.NewValue;
|
||||
}
|
||||
|
||||
private void UpdateAntiAliasing(object sender, ReactiveEventArgs<AntiAliasing> e)
|
||||
|
||||
@@ -6,7 +6,9 @@ using Ryujinx.Common.Configuration.Multiplayer;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.HLE;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.Ava.Systems.Configuration
|
||||
{
|
||||
@@ -510,6 +512,43 @@ namespace Ryujinx.Ava.Systems.Configuration
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Renames the configuration file when it is deemed invalid
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the invalid JSON configuration file</param>
|
||||
/// <returns>The path of the renamed invalid JSON configuration file, or null if the rename failed</returns>
|
||||
public static string RenameInvalidConfigFile(string path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path) || !File.Exists(path))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
string directory = Path.GetDirectoryName(path) ?? string.Empty;
|
||||
string originalFileName = Path.GetFileName(path);
|
||||
if (string.IsNullOrWhiteSpace(originalFileName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
string renamedFileName = $"{originalFileName}.{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.invalid";
|
||||
string renamedPath = string.IsNullOrEmpty(directory) ? renamedFileName : Path.Combine(directory, renamedFileName);
|
||||
|
||||
File.Move(path, renamedPath, overwrite: false);
|
||||
|
||||
Logger.Warning?.PrintMsg(LogClass.Application, $"Invalid configuration renamed to: {renamedPath}");
|
||||
|
||||
return renamedPath;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error?.PrintMsg(LogClass.Application, $"Failed to rename invalid configuration file \"{path}\": {ex}");
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save a configuration file to disk
|
||||
/// </summary>
|
||||
|
||||
@@ -28,6 +28,8 @@ namespace Ryujinx.Ava.Systems.Configuration
|
||||
{
|
||||
RyuLogger.Warning?.Print(LogClass.Application, $"Unsupported configuration version {cff.Version}, loading default.");
|
||||
|
||||
ConfigurationFileFormat.RenameInvalidConfigFile(configurationFilePath);
|
||||
|
||||
LoadDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -88,14 +88,10 @@ namespace Ryujinx.Ava.Systems
|
||||
{
|
||||
if (showVersionUpToDate)
|
||||
{
|
||||
UserResult userResult = await ContentDialogHelper.CreateUpdaterUpToDateInfoDialog(
|
||||
await ContentDialogHelper.CreateUpdaterUpToDateInfoDialog(
|
||||
LocaleManager.Instance[LocaleKeys.DialogUpdaterAlreadyOnLatestVersionMessage],
|
||||
string.Empty);
|
||||
|
||||
if (userResult is UserResult.Ok)
|
||||
{
|
||||
OpenHelper.OpenUrl(_versionResponse.ReleaseUrlFormat.Format(currentVersion));
|
||||
}
|
||||
string.Empty,
|
||||
_versionResponse.ReleaseUrlFormat.Format(currentVersion));
|
||||
}
|
||||
|
||||
Logger.Info?.Print(LogClass.Application, "Up to date.");
|
||||
|
||||
@@ -60,14 +60,10 @@ namespace Ryujinx.Ava.Systems
|
||||
{
|
||||
if (showVersionUpToDate)
|
||||
{
|
||||
UserResult userResult = await ContentDialogHelper.CreateUpdaterUpToDateInfoDialog(
|
||||
await ContentDialogHelper.CreateUpdaterUpToDateInfoDialog(
|
||||
LocaleManager.Instance[LocaleKeys.DialogUpdaterAlreadyOnLatestVersionMessage],
|
||||
string.Empty);
|
||||
|
||||
if (userResult is UserResult.Ok)
|
||||
{
|
||||
OpenHelper.OpenUrl(_versionResponse.ReleaseUrlFormat.Format(currentVersion));
|
||||
}
|
||||
string.Empty,
|
||||
changelogUrl: _versionResponse.ReleaseUrlFormat.Format(currentVersion));
|
||||
}
|
||||
|
||||
Logger.Info?.Print(LogClass.Application, "Up to date.");
|
||||
@@ -106,22 +102,18 @@ namespace Ryujinx.Ava.Systems
|
||||
|
||||
Logger.Info?.Print(LogClass.Application, $"Version found: {newVersionString.Replace("→", "->")}");
|
||||
|
||||
RequestUserToUpdate:
|
||||
// Show a message asking the user if they want to update
|
||||
UserResult shouldUpdate = await ContentDialogHelper.CreateUpdaterChoiceDialog(
|
||||
LocaleManager.Instance[LocaleKeys.RyujinxUpdater],
|
||||
LocaleManager.Instance[LocaleKeys.RyujinxUpdaterMessage],
|
||||
newVersionString);
|
||||
newVersionString,
|
||||
ReleaseInformation.GetChangelogUrl(currentVersion, newVersion));
|
||||
|
||||
switch (shouldUpdate)
|
||||
{
|
||||
case UserResult.Yes:
|
||||
await UpdateRyujinx(_versionResponse.ArtifactUrl);
|
||||
break;
|
||||
// Secondary button maps to no, which in this case is the show changelog button.
|
||||
case UserResult.No:
|
||||
OpenHelper.OpenUrl(ReleaseInformation.GetChangelogUrl(currentVersion, newVersion));
|
||||
goto RequestUserToUpdate;
|
||||
default:
|
||||
_running = false;
|
||||
break;
|
||||
|
||||
@@ -167,10 +167,7 @@ namespace Ryujinx.Ava.UI.Controls
|
||||
|
||||
private void Message_TextInput(object sender, TextInputEventArgs e)
|
||||
{
|
||||
if (_host != null)
|
||||
{
|
||||
_host.IsPrimaryButtonEnabled = _checkLength(Message.Length) && _checkInput(Message);
|
||||
}
|
||||
_host?.IsPrimaryButtonEnabled = _checkLength(Message.Length) && _checkInput(Message);
|
||||
}
|
||||
|
||||
private void Message_KeyUp(object sender, KeyEventArgs e)
|
||||
|
||||
@@ -10,6 +10,7 @@ using FluentAvalonia.Core;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.UI.Windows;
|
||||
using Ryujinx.Common.Helper;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Threading;
|
||||
@@ -102,6 +103,25 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||
|
||||
return await ShowContentDialog(title, content, primaryButton, secondaryButton, closeButton, primaryButtonResult, deferResetEvent, deferCloseAction);
|
||||
}
|
||||
|
||||
public async static Task<UserResult> ShowTextDialogWithButton(
|
||||
string title,
|
||||
string primaryText,
|
||||
string secondaryText,
|
||||
string primaryButton,
|
||||
string secondaryButton,
|
||||
string closeButton,
|
||||
int iconSymbol,
|
||||
string buttonText,
|
||||
Action onClick,
|
||||
UserResult primaryButtonResult = UserResult.Ok,
|
||||
ManualResetEvent deferResetEvent = null,
|
||||
TypedEventHandler<ContentDialog, ContentDialogButtonClickEventArgs> deferCloseAction = null)
|
||||
{
|
||||
Grid content = CreateTextDialogContentWithButton(primaryText, secondaryText, iconSymbol, buttonText, onClick);
|
||||
|
||||
return await ShowContentDialog(title, content, primaryButton, secondaryButton, closeButton, primaryButtonResult, deferResetEvent, deferCloseAction);
|
||||
}
|
||||
|
||||
public static async Task<UserResult> ShowDeferredContentDialog(
|
||||
Window window,
|
||||
@@ -173,43 +193,109 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||
MinHeight = 80,
|
||||
};
|
||||
|
||||
SymbolIcon icon = new()
|
||||
content.Children.Add(new SymbolIcon
|
||||
{
|
||||
Symbol = (Symbol)symbol,
|
||||
Margin = new Thickness(10),
|
||||
FontSize = 40,
|
||||
FlowDirection = FlowDirection.LeftToRight,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
};
|
||||
GridColumn = 0,
|
||||
GridRow = 0,
|
||||
GridRowSpan = 2
|
||||
});
|
||||
|
||||
Grid.SetColumn(icon, 0);
|
||||
Grid.SetRowSpan(icon, 2);
|
||||
Grid.SetRow(icon, 0);
|
||||
|
||||
TextBlock primaryLabel = new()
|
||||
content.Children.Add(new TextBlock
|
||||
{
|
||||
Text = primaryText,
|
||||
Margin = new Thickness(5),
|
||||
TextWrapping = TextWrapping.Wrap,
|
||||
MaxWidth = 450,
|
||||
};
|
||||
GridColumn = 1,
|
||||
GridRow = 0
|
||||
});
|
||||
|
||||
TextBlock secondaryLabel = new()
|
||||
content.Children.Add(new TextBlock
|
||||
{
|
||||
Text = secondaryText,
|
||||
Margin = new Thickness(5),
|
||||
TextWrapping = TextWrapping.Wrap,
|
||||
MaxWidth = 450,
|
||||
GridColumn = 1,
|
||||
GridRow = 1
|
||||
});
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
private static Grid CreateTextDialogContentWithButton(string primaryText, string secondaryText, int symbol, string buttonName, Action onClick)
|
||||
{
|
||||
Grid content = new()
|
||||
{
|
||||
RowDefinitions = [new(), new(), new(GridLength.Star), new()],
|
||||
ColumnDefinitions = [new(GridLength.Auto), new()],
|
||||
|
||||
MinHeight = 80,
|
||||
};
|
||||
|
||||
Grid.SetColumn(primaryLabel, 1);
|
||||
Grid.SetColumn(secondaryLabel, 1);
|
||||
Grid.SetRow(primaryLabel, 0);
|
||||
Grid.SetRow(secondaryLabel, 1);
|
||||
content.Children.Add(new SymbolIcon
|
||||
{
|
||||
Symbol = (Symbol)symbol,
|
||||
Margin = new Thickness(10),
|
||||
FontSize = 40,
|
||||
FlowDirection = FlowDirection.LeftToRight,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
GridColumn = 0,
|
||||
GridRow = 0,
|
||||
GridRowSpan = 2
|
||||
});
|
||||
|
||||
content.Children.Add(icon);
|
||||
content.Children.Add(primaryLabel);
|
||||
content.Children.Add(secondaryLabel);
|
||||
StackPanel buttonContent = new()
|
||||
{
|
||||
Orientation = Orientation.Horizontal,
|
||||
Spacing = 2
|
||||
};
|
||||
|
||||
buttonContent.Children.Add(new TextBlock
|
||||
{
|
||||
Text = buttonName,
|
||||
Margin = new Thickness(2)
|
||||
});
|
||||
|
||||
buttonContent.Children.Add(new SymbolIcon
|
||||
{
|
||||
FlowDirection = FlowDirection.LeftToRight,
|
||||
Symbol = Symbol.Open
|
||||
});
|
||||
|
||||
content.Children.Add(new TextBlock
|
||||
{
|
||||
Text = primaryText,
|
||||
Margin = new Thickness(5),
|
||||
TextWrapping = TextWrapping.Wrap,
|
||||
MaxWidth = 450,
|
||||
GridColumn = 1,
|
||||
GridRow = 0
|
||||
});
|
||||
|
||||
content.Children.Add(new TextBlock
|
||||
{
|
||||
Text = secondaryText,
|
||||
Margin = new Thickness(5),
|
||||
TextWrapping = TextWrapping.Wrap,
|
||||
MaxWidth = 450,
|
||||
GridColumn = 1,
|
||||
GridRow = 1
|
||||
});
|
||||
|
||||
content.Children.Add(new Button
|
||||
{
|
||||
Content = buttonContent,
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
Command = Commands.Create(onClick),
|
||||
GridRow = 2,
|
||||
GridColumnSpan = 2,
|
||||
});
|
||||
|
||||
return content;
|
||||
}
|
||||
@@ -282,15 +368,20 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
||||
(int)Symbol.Important);
|
||||
|
||||
internal static async Task<UserResult> CreateUpdaterUpToDateInfoDialog(string primary, string secondaryText)
|
||||
=> await ShowTextDialog(
|
||||
internal static async Task CreateUpdaterUpToDateInfoDialog(string primary, string secondaryText,
|
||||
string changelogUrl)
|
||||
{
|
||||
await ShowTextDialogWithButton(
|
||||
LocaleManager.Instance[LocaleKeys.DialogUpdaterTitle],
|
||||
primary,
|
||||
secondaryText,
|
||||
LocaleManager.Instance[LocaleKeys.DialogUpdaterShowChangelogMessage],
|
||||
string.Empty,
|
||||
string.Empty,
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
||||
(int)Symbol.Important);
|
||||
(int)Symbol.Important,
|
||||
LocaleManager.Instance[LocaleKeys.DialogUpdaterShowChangelogMessage],
|
||||
() => OpenHelper.OpenUrl(changelogUrl));
|
||||
}
|
||||
|
||||
internal static async Task CreateWarningDialog(string primary, string secondaryText)
|
||||
=> await ShowTextDialog(
|
||||
@@ -340,7 +431,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||
return response == UserResult.Yes;
|
||||
}
|
||||
|
||||
internal static async Task<UserResult> CreateUpdaterChoiceDialog(string title, string primary, string secondaryText)
|
||||
internal static async Task<UserResult> CreateUpdaterChoiceDialog(string title, string primary, string secondaryText, string changelogUrl)
|
||||
{
|
||||
if (_isChoiceDialogOpen)
|
||||
{
|
||||
@@ -349,14 +440,16 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||
|
||||
_isChoiceDialogOpen = true;
|
||||
|
||||
UserResult response = await ShowTextDialog(
|
||||
UserResult response = await ShowTextDialogWithButton(
|
||||
title,
|
||||
primary,
|
||||
secondaryText,
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
||||
LocaleManager.Instance[LocaleKeys.DialogUpdaterShowChangelogMessage],
|
||||
string.Empty,
|
||||
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||
(int)Symbol.Help,
|
||||
LocaleManager.Instance[LocaleKeys.DialogUpdaterShowChangelogMessage],
|
||||
() => OpenHelper.OpenUrl(changelogUrl),
|
||||
UserResult.Yes);
|
||||
|
||||
_isChoiceDialogOpen = false;
|
||||
|
||||
40
src/Ryujinx/UI/Helpers/ControlExtensions.cs
Normal file
40
src/Ryujinx/UI/Helpers/ControlExtensions.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Helpers
|
||||
{
|
||||
public static class ControlExtensions
|
||||
{
|
||||
extension(Control ctrl)
|
||||
{
|
||||
public int GridRow
|
||||
{
|
||||
get => Grid.GetRow(ctrl);
|
||||
set => Grid.SetRow(ctrl, value);
|
||||
}
|
||||
|
||||
public int GridColumn
|
||||
{
|
||||
get => Grid.GetColumn(ctrl);
|
||||
set => Grid.SetColumn(ctrl, value);
|
||||
}
|
||||
|
||||
public int GridRowSpan
|
||||
{
|
||||
get => Grid.GetRowSpan(ctrl);
|
||||
set => Grid.SetRowSpan(ctrl, value);
|
||||
}
|
||||
|
||||
public int GridColumnSpan
|
||||
{
|
||||
get => Grid.GetColumnSpan(ctrl);
|
||||
set => Grid.SetColumnSpan(ctrl, value);
|
||||
}
|
||||
|
||||
public bool GridIsSharedSizeScope
|
||||
{
|
||||
get => Grid.GetIsSharedSizeScope(ctrl);
|
||||
set => Grid.SetIsSharedSizeScope(ctrl, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,82 +27,136 @@ namespace Ryujinx.Ava.UI.Models.Input
|
||||
public ControllerType ControllerType { get; set; }
|
||||
public PlayerIndex PlayerIndex { get; set; }
|
||||
|
||||
[ObservableProperty] private StickInputId _leftJoystick;
|
||||
[ObservableProperty] private bool _leftInvertStickX;
|
||||
[ObservableProperty] private bool _leftInvertStickY;
|
||||
[ObservableProperty] private bool _leftRotate90;
|
||||
[ObservableProperty] private GamepadInputId _leftStickButton;
|
||||
[ObservableProperty]
|
||||
public partial StickInputId LeftJoystick { get; set; }
|
||||
|
||||
[ObservableProperty] private StickInputId _rightJoystick;
|
||||
[ObservableProperty] private bool _rightInvertStickX;
|
||||
[ObservableProperty] private bool _rightInvertStickY;
|
||||
[ObservableProperty] private bool _rightRotate90;
|
||||
[ObservableProperty] private GamepadInputId _rightStickButton;
|
||||
[ObservableProperty]
|
||||
public partial bool LeftInvertStickX { get; set; }
|
||||
|
||||
[ObservableProperty] private GamepadInputId _dpadUp;
|
||||
[ObservableProperty] private GamepadInputId _dpadDown;
|
||||
[ObservableProperty] private GamepadInputId _dpadLeft;
|
||||
[ObservableProperty] private GamepadInputId _dpadRight;
|
||||
[ObservableProperty]
|
||||
public partial bool LeftInvertStickY { get; set; }
|
||||
|
||||
[ObservableProperty] private GamepadInputId _buttonMinus;
|
||||
[ObservableProperty] private GamepadInputId _buttonPlus;
|
||||
[ObservableProperty]
|
||||
public partial bool LeftRotate90 { get; set; }
|
||||
|
||||
[ObservableProperty] private GamepadInputId _buttonA;
|
||||
[ObservableProperty] private GamepadInputId _buttonB;
|
||||
[ObservableProperty] private GamepadInputId _buttonX;
|
||||
[ObservableProperty] private GamepadInputId _buttonY;
|
||||
[ObservableProperty]
|
||||
public partial GamepadInputId LeftStickButton { get; set; }
|
||||
|
||||
[ObservableProperty] private GamepadInputId _buttonZl;
|
||||
[ObservableProperty] private GamepadInputId _buttonZr;
|
||||
[ObservableProperty]
|
||||
public partial StickInputId RightJoystick { get; set; }
|
||||
|
||||
[ObservableProperty] private GamepadInputId _buttonL;
|
||||
[ObservableProperty] private GamepadInputId _buttonR;
|
||||
[ObservableProperty]
|
||||
public partial bool RightInvertStickX { get; set; }
|
||||
|
||||
[ObservableProperty] private GamepadInputId _leftButtonSl;
|
||||
[ObservableProperty] private GamepadInputId _leftButtonSr;
|
||||
[ObservableProperty]
|
||||
public partial bool RightInvertStickY { get; set; }
|
||||
|
||||
[ObservableProperty] private GamepadInputId _rightButtonSl;
|
||||
[ObservableProperty] private GamepadInputId _rightButtonSr;
|
||||
[ObservableProperty]
|
||||
public partial bool RightRotate90 { get; set; }
|
||||
|
||||
[ObservableProperty] private float _deadzoneLeft;
|
||||
[ObservableProperty] private float _deadzoneRight;
|
||||
[ObservableProperty]
|
||||
public partial GamepadInputId RightStickButton { get; set; }
|
||||
|
||||
[ObservableProperty] private float _rangeLeft;
|
||||
[ObservableProperty] private float _rangeRight;
|
||||
[ObservableProperty]
|
||||
public partial GamepadInputId DpadUp { get; set; }
|
||||
|
||||
[ObservableProperty] private float _triggerThreshold;
|
||||
[ObservableProperty]
|
||||
public partial GamepadInputId DpadDown { get; set; }
|
||||
|
||||
[ObservableProperty] private bool _enableMotion;
|
||||
[ObservableProperty]
|
||||
public partial GamepadInputId DpadLeft { get; set; }
|
||||
|
||||
[ObservableProperty] private bool _enableRumble;
|
||||
[ObservableProperty]
|
||||
public partial GamepadInputId DpadRight { get; set; }
|
||||
|
||||
[ObservableProperty] private bool _enableLedChanging;
|
||||
[ObservableProperty]
|
||||
public partial GamepadInputId ButtonMinus { get; set; }
|
||||
|
||||
[ObservableProperty] private Color _ledColor;
|
||||
[ObservableProperty]
|
||||
public partial GamepadInputId ButtonPlus { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial GamepadInputId ButtonA { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial GamepadInputId ButtonB { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial GamepadInputId ButtonX { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial GamepadInputId ButtonY { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial GamepadInputId ButtonZl { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial GamepadInputId ButtonZr { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial GamepadInputId ButtonL { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial GamepadInputId ButtonR { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial GamepadInputId LeftButtonSl { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial GamepadInputId LeftButtonSr { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial GamepadInputId RightButtonSl { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial GamepadInputId RightButtonSr { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial float DeadzoneLeft { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial float DeadzoneRight { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial float RangeLeft { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial float RangeRight { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial float TriggerThreshold { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool EnableMotion { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool EnableRumble { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool EnableLedChanging { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Color LedColor { get; set; }
|
||||
|
||||
public bool ShowLedColorPicker => !TurnOffLed && !UseRainbowLed;
|
||||
|
||||
private bool _turnOffLed;
|
||||
|
||||
public bool TurnOffLed
|
||||
{
|
||||
get => _turnOffLed;
|
||||
get;
|
||||
set
|
||||
{
|
||||
_turnOffLed = value;
|
||||
field = value;
|
||||
OnPropertyChanged();
|
||||
OnPropertyChanged(nameof(ShowLedColorPicker));
|
||||
}
|
||||
}
|
||||
|
||||
private bool _useRainbowLed;
|
||||
|
||||
public bool UseRainbowLed
|
||||
{
|
||||
get => _useRainbowLed;
|
||||
get;
|
||||
set
|
||||
{
|
||||
_useRainbowLed = value;
|
||||
field = value;
|
||||
OnPropertyChanged();
|
||||
OnPropertyChanged(nameof(ShowLedColorPicker));
|
||||
}
|
||||
|
||||
@@ -6,31 +6,44 @@ namespace Ryujinx.Ava.UI.Models.Input
|
||||
{
|
||||
public partial class HotkeyConfig : BaseModel
|
||||
{
|
||||
[ObservableProperty] private Key _toggleVSyncMode;
|
||||
[ObservableProperty]
|
||||
public partial Key ToggleVSyncMode { get; set; }
|
||||
|
||||
[ObservableProperty] private Key _screenshot;
|
||||
[ObservableProperty]
|
||||
public partial Key Screenshot { get; set; }
|
||||
|
||||
[ObservableProperty] private Key _showUI;
|
||||
[ObservableProperty]
|
||||
public partial Key ShowUI { get; set; }
|
||||
|
||||
[ObservableProperty] private Key _pause;
|
||||
[ObservableProperty]
|
||||
public partial Key Pause { get; set; }
|
||||
|
||||
[ObservableProperty] private Key _toggleMute;
|
||||
[ObservableProperty]
|
||||
public partial Key ToggleMute { get; set; }
|
||||
|
||||
[ObservableProperty] private Key _resScaleUp;
|
||||
[ObservableProperty]
|
||||
public partial Key ResScaleUp { get; set; }
|
||||
|
||||
[ObservableProperty] private Key _resScaleDown;
|
||||
[ObservableProperty]
|
||||
public partial Key ResScaleDown { get; set; }
|
||||
|
||||
[ObservableProperty] private Key _volumeUp;
|
||||
[ObservableProperty]
|
||||
public partial Key VolumeUp { get; set; }
|
||||
|
||||
[ObservableProperty] private Key _volumeDown;
|
||||
[ObservableProperty]
|
||||
public partial Key VolumeDown { get; set; }
|
||||
|
||||
[ObservableProperty] private Key _customVSyncIntervalIncrement;
|
||||
[ObservableProperty]
|
||||
public partial Key CustomVSyncIntervalIncrement { get; set; }
|
||||
|
||||
[ObservableProperty] private Key _customVSyncIntervalDecrement;
|
||||
[ObservableProperty]
|
||||
public partial Key CustomVSyncIntervalDecrement { get; set; }
|
||||
|
||||
[ObservableProperty] private Key _turboMode;
|
||||
[ObservableProperty]
|
||||
public partial Key TurboMode { get; set; }
|
||||
|
||||
[ObservableProperty] private bool _turboModeWhileHeld;
|
||||
[ObservableProperty]
|
||||
public partial bool TurboModeWhileHeld { get; set; }
|
||||
|
||||
public HotkeyConfig(KeyboardHotkeys config)
|
||||
{
|
||||
|
||||
@@ -12,42 +12,89 @@ namespace Ryujinx.Ava.UI.Models.Input
|
||||
public ControllerType ControllerType { get; set; }
|
||||
public PlayerIndex PlayerIndex { get; set; }
|
||||
|
||||
[ObservableProperty] private Key _leftStickUp;
|
||||
[ObservableProperty] private Key _leftStickDown;
|
||||
[ObservableProperty] private Key _leftStickLeft;
|
||||
[ObservableProperty] private Key _leftStickRight;
|
||||
[ObservableProperty] private Key _leftStickButton;
|
||||
[ObservableProperty]
|
||||
public partial Key LeftStickUp { get; set; }
|
||||
|
||||
[ObservableProperty] private Key _rightStickUp;
|
||||
[ObservableProperty] private Key _rightStickDown;
|
||||
[ObservableProperty] private Key _rightStickLeft;
|
||||
[ObservableProperty] private Key _rightStickRight;
|
||||
[ObservableProperty] private Key _rightStickButton;
|
||||
[ObservableProperty]
|
||||
public partial Key LeftStickDown { get; set; }
|
||||
|
||||
[ObservableProperty] private Key _dpadUp;
|
||||
[ObservableProperty] private Key _dpadDown;
|
||||
[ObservableProperty] private Key _dpadLeft;
|
||||
[ObservableProperty] private Key _dpadRight;
|
||||
[ObservableProperty]
|
||||
public partial Key LeftStickLeft { get; set; }
|
||||
|
||||
[ObservableProperty] private Key _buttonMinus;
|
||||
[ObservableProperty] private Key _buttonPlus;
|
||||
[ObservableProperty]
|
||||
public partial Key LeftStickRight { get; set; }
|
||||
|
||||
[ObservableProperty] private Key _buttonA;
|
||||
[ObservableProperty] private Key _buttonB;
|
||||
[ObservableProperty] private Key _buttonX;
|
||||
[ObservableProperty] private Key _buttonY;
|
||||
[ObservableProperty]
|
||||
public partial Key LeftStickButton { get; set; }
|
||||
|
||||
[ObservableProperty] private Key _buttonL;
|
||||
[ObservableProperty] private Key _buttonR;
|
||||
[ObservableProperty]
|
||||
public partial Key RightStickUp { get; set; }
|
||||
|
||||
[ObservableProperty] private Key _buttonZl;
|
||||
[ObservableProperty] private Key _buttonZr;
|
||||
[ObservableProperty]
|
||||
public partial Key RightStickDown { get; set; }
|
||||
|
||||
[ObservableProperty] private Key _leftButtonSl;
|
||||
[ObservableProperty] private Key _leftButtonSr;
|
||||
[ObservableProperty]
|
||||
public partial Key RightStickLeft { get; set; }
|
||||
|
||||
[ObservableProperty] private Key _rightButtonSl;
|
||||
[ObservableProperty] private Key _rightButtonSr;
|
||||
[ObservableProperty]
|
||||
public partial Key RightStickRight { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Key RightStickButton { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Key DpadUp { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Key DpadDown { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Key DpadLeft { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Key DpadRight { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Key ButtonMinus { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Key ButtonPlus { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Key ButtonA { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Key ButtonB { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Key ButtonX { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Key ButtonY { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Key ButtonL { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Key ButtonR { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Key ButtonZl { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Key ButtonZr { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Key LeftButtonSl { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Key LeftButtonSr { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Key RightButtonSl { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial Key RightButtonSr { get; set; }
|
||||
|
||||
public KeyboardInputConfig(InputConfig config)
|
||||
{
|
||||
|
||||
@@ -6,8 +6,8 @@ namespace Ryujinx.Ava.UI.Models
|
||||
{
|
||||
public partial class ModModel : BaseModel
|
||||
{
|
||||
[ObservableProperty] private bool _enabled;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool Enabled { get; set; }
|
||||
public bool InSd { get; }
|
||||
public string Path { get; }
|
||||
public string Name { get; }
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace Ryujinx.Ava.UI.Models
|
||||
public string Name { get; set; }
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
[ObservableProperty] private SolidColorBrush _backgroundColor = new(Colors.White);
|
||||
[ObservableProperty]
|
||||
public partial SolidColorBrush BackgroundColor { get; set; } = new(Colors.White);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,24 +7,26 @@ namespace Ryujinx.Ava.UI.Models
|
||||
{
|
||||
public partial class TempProfile : BaseModel
|
||||
{
|
||||
[ObservableProperty] private byte[] _image;
|
||||
[ObservableProperty] private string _name = String.Empty;
|
||||
private UserId _userId;
|
||||
[ObservableProperty]
|
||||
public partial byte[] Image { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string Name { get; set; } = string.Empty;
|
||||
|
||||
public static uint MaxProfileNameLength => 0x20;
|
||||
|
||||
public UserId UserId
|
||||
{
|
||||
get => _userId;
|
||||
get;
|
||||
set
|
||||
{
|
||||
_userId = value;
|
||||
field = value;
|
||||
OnPropertyChanged();
|
||||
OnPropertyChanged(nameof(UserIdString));
|
||||
}
|
||||
}
|
||||
|
||||
public string UserIdString => _userId.ToString();
|
||||
public string UserIdString => UserId.ToString();
|
||||
|
||||
public TempProfile(UserProfile profile)
|
||||
{
|
||||
|
||||
@@ -13,11 +13,20 @@ namespace Ryujinx.Ava.UI.Models
|
||||
{
|
||||
private readonly Profile _profile;
|
||||
private readonly NavigationDialogHost _owner;
|
||||
[ObservableProperty] private byte[] _image;
|
||||
[ObservableProperty] private string _name;
|
||||
[ObservableProperty] private UserId _userId;
|
||||
[ObservableProperty] private bool _isPointerOver;
|
||||
[ObservableProperty] private IBrush _backgroundColor;
|
||||
[ObservableProperty]
|
||||
public partial byte[] Image { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial string Name { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial UserId UserId { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool IsPointerOver { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
public partial IBrush BackgroundColor { get; set; }
|
||||
|
||||
public UserProfile(Profile profile, NavigationDialogHost owner)
|
||||
{
|
||||
@@ -39,7 +48,7 @@ namespace Ryujinx.Ava.UI.Models
|
||||
|
||||
private void UpdateBackground()
|
||||
{
|
||||
Application currentApplication = Avalonia.Application.Current;
|
||||
Application currentApplication = Application.Current;
|
||||
currentApplication.Styles.TryGetResource("ControlFillColorSecondary", currentApplication.ActualThemeVariant, out object color);
|
||||
|
||||
if (color is not null)
|
||||
|
||||
@@ -88,6 +88,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
get;
|
||||
}
|
||||
|
||||
public bool IsCustomConfig
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public bool IsGameTitleNotNull => !string.IsNullOrEmpty(GameTitle);
|
||||
public double PanelOpacity => IsGameTitleNotNull ? 0.5 : 1;
|
||||
|
||||
@@ -359,8 +364,9 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
[ObservableProperty] private bool _matchSystemTime;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial bool MatchSystemTime { get; set; }
|
||||
|
||||
public DateTimeOffset CurrentDate { get; set; }
|
||||
|
||||
public TimeSpan CurrentTime { get; set; }
|
||||
@@ -458,7 +464,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
using MemoryStream ms = new(gameIconData);
|
||||
GameIcon = new Bitmap(ms);
|
||||
}
|
||||
|
||||
IsCustomConfig = customConfig;
|
||||
IsGameRunning = gameRunning;
|
||||
GamePath = gamePath;
|
||||
GameTitle = gameName;
|
||||
@@ -868,16 +874,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
GameListNeedsRefresh = false;
|
||||
}
|
||||
|
||||
private static void RevertIfNotSaved()
|
||||
private static void RevertIfNotSaved(bool isCustomConfig = false, bool isGameRunning = false)
|
||||
{
|
||||
/*
|
||||
maybe this is an unnecessary check(all options need to be tested)
|
||||
if (string.IsNullOrEmpty(Program.GlobalConfigurationPath))
|
||||
{
|
||||
Program.ReloadConfig();
|
||||
}
|
||||
*/
|
||||
Program.ReloadConfig();
|
||||
// Restores settings for a custom configuration during a game, if the condition is met.
|
||||
// If the condition is not met (parameter is false), restores global (default) configuration instead.
|
||||
Program.ReloadConfig(isCustomConfig && isGameRunning);
|
||||
}
|
||||
|
||||
public void ApplyButton()
|
||||
@@ -894,14 +895,14 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
File.Delete(gameDir);
|
||||
}
|
||||
|
||||
RevertIfNotSaved();
|
||||
RevertIfNotSaved(IsCustomConfig, IsGameRunning);
|
||||
CloseWindow?.Invoke();
|
||||
}
|
||||
|
||||
public void SaveUserConfig()
|
||||
{
|
||||
SaveSettings();
|
||||
RevertIfNotSaved(); // Revert global configuration after saving user configuration
|
||||
RevertIfNotSaved(IsCustomConfig, IsGameRunning); // Revert global or custom configuration after saving user configuration
|
||||
CloseWindow?.Invoke();
|
||||
}
|
||||
|
||||
@@ -933,7 +934,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
public void CancelButton()
|
||||
{
|
||||
RevertIfNotSaved();
|
||||
RevertIfNotSaved(IsCustomConfig, IsGameRunning);
|
||||
CloseWindow?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user