Merge remote-tracking branch 'upstream/master' into auto-assign-controller

This commit is contained in:
uncavo-hdmi
2025-01-26 21:23:37 +01:00
489 changed files with 3501 additions and 3401 deletions

View File

@@ -3,6 +3,7 @@ using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Input;
using Avalonia.Threading;
using DiscordRPC;
using LibHac.Common;
using LibHac.Ns;
using LibHac.Tools.FsSystem;
@@ -238,10 +239,10 @@ namespace Ryujinx.Ava
_lastCursorMoveTime = Stopwatch.GetTimestamp();
}
var point = e.GetCurrentPoint(window).Position;
var bounds = RendererHost.EmbeddedWindow.Bounds;
var windowYOffset = bounds.Y + window.MenuBarHeight;
var windowYLimit = (int)window.Bounds.Height - window.StatusBarHeight - 1;
Point point = e.GetCurrentPoint(window).Position;
Rect bounds = RendererHost.EmbeddedWindow.Bounds;
double windowYOffset = bounds.Y + window.MenuBarHeight;
double windowYLimit = (int)window.Bounds.Height - window.StatusBarHeight - 1;
if (!_viewModel.ShowMenuAndStatusBar)
{
@@ -265,10 +266,10 @@ namespace Ryujinx.Ava
if (sender is MainWindow window)
{
var point = e.GetCurrentPoint(window).Position;
var bounds = RendererHost.EmbeddedWindow.Bounds;
var windowYOffset = bounds.Y + window.MenuBarHeight;
var windowYLimit = (int)window.Bounds.Height - window.StatusBarHeight - 1;
Point point = e.GetCurrentPoint(window).Position;
Rect bounds = RendererHost.EmbeddedWindow.Bounds;
double windowYOffset = bounds.Y + window.MenuBarHeight;
double windowYLimit = (int)window.Bounds.Height - window.StatusBarHeight - 1;
if (!_viewModel.ShowMenuAndStatusBar)
{
@@ -435,7 +436,7 @@ namespace Ryujinx.Ava
return;
}
var colorType = e.IsBgra ? SKColorType.Bgra8888 : SKColorType.Rgba8888;
SKColorType colorType = e.IsBgra ? SKColorType.Bgra8888 : SKColorType.Rgba8888;
using SKBitmap bitmap = new(new SKImageInfo(e.Width, e.Height, colorType, SKAlphaType.Premul));
Marshal.Copy(e.Data, 0, bitmap.GetPixels(), e.Data.Length);
@@ -448,7 +449,7 @@ namespace Ryujinx.Ava
float scaleX = e.FlipX ? -1 : 1;
float scaleY = e.FlipY ? -1 : 1;
var matrix = SKMatrix.CreateScale(scaleX, scaleY, bitmap.Width / 2f, bitmap.Height / 2f);
SKMatrix matrix = SKMatrix.CreateScale(scaleX, scaleY, bitmap.Width / 2f, bitmap.Height / 2f);
canvas.SetMatrix(matrix);
canvas.DrawBitmap(bitmap, SKPoint.Empty);
@@ -467,8 +468,8 @@ namespace Ryujinx.Ava
private static void SaveBitmapAsPng(SKBitmap bitmap, string path)
{
using var data = bitmap.Encode(SKEncodedImageFormat.Png, 100);
using var stream = File.OpenWrite(path);
using SKData data = bitmap.Encode(SKEncodedImageFormat.Png, 100);
using FileStream stream = File.OpenWrite(path);
data.SaveTo(stream);
}
@@ -594,6 +595,8 @@ namespace Ryujinx.Ava
gamepad?.ClearLed();
gamepad?.Dispose();
}
DiscordIntegrationModule.GuestAppStartedAt = null;
Rainbow.Disable();
Rainbow.Reset();
@@ -685,6 +688,8 @@ namespace Ryujinx.Ava
public async Task<bool> LoadGuestApplication(BlitStruct<ApplicationControlProperty>? customNacpData = null)
{
DiscordIntegrationModule.GuestAppStartedAt = Timestamps.Now;
InitEmulatedSwitch();
MainWindow.UpdateGraphicsConfig();
@@ -923,7 +928,7 @@ namespace Ryujinx.Ava
BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading;
var isGALThreaded = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading);
bool isGALThreaded = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading);
if (isGALThreaded)
{
renderer = new ThreadedRenderer(renderer);
@@ -932,7 +937,7 @@ namespace Ryujinx.Ava
Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend Threading ({threadingMode}): {isGALThreaded}");
// Initialize Configuration.
var memoryConfiguration = ConfigurationState.Instance.System.DramSize.Value;
MemoryConfiguration memoryConfiguration = ConfigurationState.Instance.System.DramSize.Value;
Device = new Switch(new HLEConfiguration(
VirtualFileSystem,
@@ -970,7 +975,7 @@ namespace Ryujinx.Ava
private static IHardwareDeviceDriver InitializeAudio()
{
var availableBackends = new List<AudioBackend>
List<AudioBackend> availableBackends = new List<AudioBackend>
{
AudioBackend.SDL2,
AudioBackend.SoundIo,

View File

@@ -418,7 +418,7 @@
"th_TH": "โหลด DLC จากโฟลเดอร์",
"tr_TR": "",
"uk_UA": "Завантажити DLC з теки",
"zh_CN": "从文件夹加载DLC",
"zh_CN": "从文件夹加载 DLC",
"zh_TW": "從資料夾中載入 DLC"
}
},
@@ -618,7 +618,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "启动游戏时隐藏 UI",
"zh_TW": ""
}
},
@@ -793,7 +793,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "Сканувати Amiibo (з теки Bin)",
"zh_CN": "从bin文件扫描 Amiibo",
"zh_CN": "扫描 Amiibo (从 bin 文件)",
"zh_TW": "掃瞄 Amiibo (從 Bin 檔案)"
}
},
@@ -843,7 +843,7 @@
"th_TH": "ติดตั้งเฟิร์มแวร์จาก ไฟล์ XCI หรือ ไฟล์ ZIP",
"tr_TR": "XCI veya ZIP'ten Yazılım Yükle",
"uk_UA": "Встановити прошивку з XCI або ZIP",
"zh_CN": "从 XCI 或 ZIP 文件安装系统固件",
"zh_CN": "从 XCI 或 ZIP 文件安装系统固件",
"zh_TW": "從 XCI 或 ZIP 安裝韌體"
}
},
@@ -868,7 +868,7 @@
"th_TH": "ติดตั้งเฟิร์มแวร์จากไดเร็กทอรี",
"tr_TR": "Bir Dizin Üzerinden Yazılım Yükle",
"uk_UA": "Встановити прошивку з теки",
"zh_CN": "从文件夹安装系统固件",
"zh_CN": "从文件夹安装系统固件",
"zh_TW": "從資料夾安裝韌體"
}
},
@@ -918,7 +918,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "Встановити ключі з файлу .KEYS або .ZIP",
"zh_CN": "从.KEYS文件或ZIP压缩包安装密匙",
"zh_CN": "从 .KEYS 文件或 .ZIP 压缩包安装密匙",
"zh_TW": "從 .KEYS 或 .ZIP 安裝金鑰"
}
},
@@ -1043,7 +1043,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "Обрізати XCI файли",
"zh_CN": "XCI文件瘦身",
"zh_CN": "瘦身 XCI 文件",
"zh_TW": "修剪 XCI 檔案"
}
},
@@ -1318,7 +1318,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "Відкриває сторінку з Посібником по усуненню помилок та несправностей на офіційній вікі-сторінці Ryujinx (англійською)",
"zh_CN": "打开Ryujinx官方wiki的常见问题和问题排除页面",
"zh_CN": "打开 Ryujinx 官方 Wiki 的常见问题和问题排除页面",
"zh_TW": "開啟官方 Ryujinx Wiki 常見問題 (FAQ) 和疑難排解頁面"
}
},
@@ -1368,7 +1368,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "Відкриває посібник з Налаштування та конфігурації на офіційній вікі-сторінці Ryujinx (англійською)",
"zh_CN": "打开Ryujinx官方wiki的安装与配置指南",
"zh_CN": "打开 Ryujinx 官方 Wiki 的安装与配置指南",
"zh_TW": "開啟官方 Ryujinx Wiki 設定和配置指南"
}
},
@@ -1418,7 +1418,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "Відкриває посібник з налаштування Мультиплеєру на офіційній вікі-сторінці Ryujinx (англійською)",
"zh_CN": "打开Ryujinx官方wiki的多人游戏指南",
"zh_CN": "打开 Ryujinx 官方 Wiki 的多人游戏指南",
"zh_TW": "開啟官方 Ryujinx Wiki 多人遊戲 (LDN/LAN) 指南"
}
},
@@ -1468,7 +1468,7 @@
"th_TH": "กำลังค้นหา...",
"tr_TR": "Ara...",
"uk_UA": "Пошук...",
"zh_CN": "搜索",
"zh_CN": "搜索...",
"zh_TW": "搜尋..."
}
},
@@ -2368,7 +2368,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "从选定的 DLC 文件中解压 RomFS",
"zh_TW": ""
}
},
@@ -2618,7 +2618,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "Перевірка та нарізка XCI Файлу",
"zh_CN": "检查并瘦身XCI文件",
"zh_CN": "检查并瘦身 XCI 文件",
"zh_TW": "檢查及修剪 XCI 檔案"
}
},
@@ -2643,7 +2643,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "Перевірити та обрізати XCI Файл задля збереження місця на диску",
"zh_CN": "检查并瘦身XCI文件以节约磁盘空间",
"zh_CN": "检查并瘦身 XCI 文件以节约磁盘空间",
"zh_TW": "檢查及修剪 XCI 檔案以節省儲存空間"
}
},
@@ -2718,7 +2718,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "Обрізається XCI Файлів '{0}'",
"zh_CN": "XCI文件瘦身中'{0}'",
"zh_CN": "正在瘦身 XCI 文件 '{0}'",
"zh_TW": "正在修剪 XCI 檔案 '{0}'"
}
},
@@ -3243,7 +3243,7 @@
"th_TH": "โหลดไดเรกทอรี DLC/ไฟล์อัปเดต อัตโนมัติ",
"tr_TR": "",
"uk_UA": "Автозавантаження теки DLC/Оновлень",
"zh_CN": "自动加载DLC/游戏更新目录",
"zh_CN": "自动加载 DLC游戏更新目录",
"zh_TW": "自動載入 DLC/遊戲更新資料夾"
}
},
@@ -3268,7 +3268,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "DLC та Оновлення, які посилаються на відсутні файли, будуть автоматично вимкнуті.",
"zh_CN": "DLC/游戏更新可自动加载和卸载",
"zh_CN": "DLC游戏更新 可自动加载和卸载",
"zh_TW": "遺失的 DLC 及遊戲更新檔案將會在自動載入中移除"
}
},
@@ -7693,7 +7693,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "关闭",
"zh_TW": ""
}
},
@@ -7718,7 +7718,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "彩虹",
"zh_TW": ""
}
},
@@ -11368,7 +11368,7 @@
"th_TH": "ไม่มีข้อมูลบันทึกไว้สำหรับ {0} [{1:x16}]",
"tr_TR": "{0} [{1:x16}] için kayıt verisi bulunamadı",
"uk_UA": "Немає збережених даних для {0} [{1:x16}]",
"zh_CN": "没有{0} [{1:x16}]的游戏存档",
"zh_CN": "没有 {0} [{1:x16}] 的游戏存档",
"zh_TW": "沒有 {0} [{1:x16}] 的存檔"
}
},
@@ -12518,7 +12518,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "Вікно XCI Тримера",
"zh_CN": "XCI文件瘦身窗口",
"zh_CN": "XCI 文件瘦身窗口",
"zh_TW": "XCI 修剪器視窗"
}
},
@@ -13243,7 +13243,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "在{0}发现了一个无效的密匙文件",
"zh_CN": "在 {0} 发现了一个无效的密匙文件",
"zh_TW": "找到無效的金鑰檔案 {0}"
}
},
@@ -14593,7 +14593,7 @@
"th_TH": "แฮ็ค: สุ่มแท็ก Uuid",
"tr_TR": "Hack: Rastgele bir Uuid kullan",
"uk_UA": "Хитрість: Використовувати випадковий тег Uuid",
"zh_CN": "修改使用随机生成的Amiibo ID",
"zh_CN": "修改:使用随机生成的 Amiibo ID",
"zh_TW": "補釘修正:使用隨機標記的 Uuid"
}
},
@@ -15568,7 +15568,7 @@
"th_TH": "โหลด PPTC โดยใช้หนึ่งในสามของจำนวนคอร์",
"tr_TR": "",
"uk_UA": "Завантажувати PPTC використовуючи третину від кількості ядер.",
"zh_CN": "使用三分之一的核心数加载PPTC.",
"zh_CN": "使用三分之一的核心数加载 PPTC.",
"zh_TW": "使用 CPU 核心數量的三分之一載入 PPTC。"
}
},
@@ -16393,7 +16393,7 @@
"th_TH": "เปิดตัวสำรวจไฟล์เพื่อเลือกหนึ่งโฟลเดอร์ขึ้นไปเพื่อโหลด DLC จำนวนมาก",
"tr_TR": "",
"uk_UA": "Відкриває Файловий провідник для обрання однієї або декількох тек для масового завантаження DLC",
"zh_CN": "打开文件资源管理器以选择一个或多个文件夹来批量加载DLC。",
"zh_CN": "打开文件资源管理器以选择一个或多个文件夹来批量加载 DLC。",
"zh_TW": "開啟檔案總管,選擇一個或多個資料夾來大量載入 DLC"
}
},
@@ -19218,7 +19218,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "Перевірити та Обрізати XCI файл",
"zh_CN": "检查并瘦身XCI文件",
"zh_CN": "检查并瘦身 XCI 文件",
"zh_TW": "檢查及修剪 XCI 檔案"
}
},
@@ -19243,7 +19243,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "Ця функція спочатку перевірить наявність порожнього місця, після чого обріже файл XCI для економії місця на диску.",
"zh_CN": "这个功能将会先检查XCI文件再对其执行瘦身操作以节约磁盘空间。",
"zh_CN": "这个功能将会先检查 XCI 文件,再对其执行瘦身操作以节约磁盘空间。",
"zh_TW": "此功能首先檢查 XCI 檔案是否有可修剪的字元,然後修剪檔案以節省儲存空間。"
}
},
@@ -19293,7 +19293,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "XCI файл не потребує обрізання. Перевірте журнали (logs) для отримання додаткової інформації",
"zh_CN": "XCI文件不需要被瘦身。查看日志以获得更多细节。",
"zh_CN": "XCI 文件不需要被瘦身。查看日志以获得更多细节。",
"zh_TW": "XCI 檔案不需要修剪。檢查日誌以取得更多資訊"
}
},
@@ -19318,7 +19318,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "XCI файл не може бути обрізаний. Перевірте журнали (logs) для отримання додаткової інформації",
"zh_CN": "XCI文件不能被瘦身。查看日志以获得更多细节。",
"zh_CN": "XCI 文件不能被瘦身。查看日志以获得更多细节。",
"zh_TW": "XCI 檔案不能被修剪。檢查日誌以取得更多資訊"
}
},
@@ -19343,7 +19343,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "XCI файл Тільки для Читання і не може бути прочитаним. Перевірте журнали (logs) для отримання додаткової інформації",
"zh_CN": "XCI文件是只读的且不可以被标记为可读取的。查看日志以获得更多细节。",
"zh_CN": "XCI 文件是只读的,且不可以被标记为可读取的。查看日志以获得更多细节。",
"zh_TW": "XCI 檔案是唯讀,並且無法改成可寫入。檢查日誌以取得更多資訊"
}
},
@@ -19368,7 +19368,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "Розмір файлу XCI змінився з моменту сканування. Перевірте, чи не записується файл, та спробуйте знову",
"zh_CN": "XCI文件在扫描后大小发生了变化。请检查文件是否未被写入然后重试。",
"zh_CN": "XCI 文件在扫描后大小发生了变化。请检查文件是否未被写入,然后重试。",
"zh_TW": "XCI 檔案大小比較上次的掃瞄已經改變。請檢查檔案是否未被寫入,然後再嘗試。"
}
},
@@ -19393,7 +19393,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "Файл XCI містить дані в зоні вільного простору, тому обрізка небезпечна",
"zh_CN": "XCI文件的空闲区域内有数据不能安全瘦身。",
"zh_CN": "XCI 文件的空闲区域内有数据,不能安全瘦身。",
"zh_TW": "XCI 檔案有數據儲存於可節省儲存空間的區域,所以試圖修剪並不安全"
}
},
@@ -19418,7 +19418,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "XCI Файл містить недійсні дані. Перевірте журнали (logs) для отримання додаткової інформації",
"zh_CN": "XCI文件含有无效数据。查看日志以获得更多细节。",
"zh_CN": "XCI 文件含有无效数据。查看日志以获得更多细节。",
"zh_TW": "XCI 檔案帶有無效的數據。檢查日誌以取得更多資訊"
}
},
@@ -19443,7 +19443,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "XCI Файл файл не вдалося відкрити для запису. Перевірте журнали для додаткової інформації",
"zh_CN": "XCI文件不能被读写。查看日志以获得更多细节。",
"zh_CN": "XCI 文件不能被读写。查看日志以获得更多细节。",
"zh_TW": "XCI 檔案不能被寫入。檢查日誌以取得更多資訊"
}
},
@@ -19468,7 +19468,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "Не вдалося обрізати файл XCI",
"zh_CN": "XCI文件瘦身失败",
"zh_CN": "XCI 文件瘦身失败",
"zh_TW": "修剪 XCI 檔案失敗"
}
},
@@ -19668,7 +19668,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "Обрізка XCI Файлів",
"zh_CN": "XCI文件瘦身器",
"zh_CN": "XCI 文件瘦身器",
"zh_TW": "XCI 檔案修剪器"
}
},
@@ -20143,7 +20143,7 @@
"th_TH": "แพ็ค DLC ไม่สามารถลบทิ้งได้ สามารถปิดใช้งานได้เท่านั้น",
"tr_TR": "",
"uk_UA": "Комплектні DLC (бандли) не можуть бути видаленими, лише вимкненими.",
"zh_CN": "游戏整合的DLC无法移除可尝试禁用。",
"zh_CN": "游戏整合的 DLC 无法移除,可尝试禁用。",
"zh_TW": "附帶的 DLC 只能被停用而無法被刪除。"
}
},
@@ -20193,7 +20193,7 @@
"th_TH": "{0} DLC ใหม่ที่เพิ่มเข้ามา",
"tr_TR": "",
"uk_UA": "{0} нового завантажувального вмісту додано",
"zh_CN": "{0} 个DLC被添加",
"zh_CN": "{0} 个 DLC 被添加",
"zh_TW": "已加入 {0} 個 DLC"
}
},
@@ -20218,7 +20218,7 @@
"th_TH": "{0} ใหม่ที่เพิ่มเข้ามา",
"tr_TR": "",
"uk_UA": "{0} нового завантажувального вмісту додано",
"zh_CN": "{0} 个DLC被添加",
"zh_CN": "{0} 个 DLC 被添加",
"zh_TW": "已加入 {0} 個 DLC"
}
},
@@ -20243,7 +20243,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "{0} відсутнього завантажувального вмісту видалено",
"zh_CN": "{0} 个失效的DLC已移除",
"zh_CN": "{0} 个失效的 DLC 已移除",
"zh_TW": "已刪除 {0} 個遺失的 DLC"
}
},
@@ -20768,7 +20768,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "使用Vulkan。\n在ARM Mac上当玩在其下运行良好的游戏时使用Metal后端。",
"zh_CN": "使用 Vulkan。\n在 ARM Mac 上,当玩在其下运行良好的游戏时,使用 Metal 后端。",
"zh_TW": "使用Vulkan。\n在 ARM Mac 上,如果遊戲執行性能良好時,則將使用 Metal 後端。"
}
},
@@ -22168,7 +22168,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "Вимкнути хостинг P2P мережі (може збільшити затримку)",
"zh_CN": "禁用P2P网络连接 (也许会增加延迟)",
"zh_CN": "禁用 P2P 网络连接 (也许会增加延迟)",
"zh_TW": "停用對等網路代管 (P2P Network Hosting) (可能增加網路延遲)"
}
},
@@ -22193,7 +22193,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "Вимкнути хостинг P2P мережі, піри будуть підключатися через майстер-сервер замість прямого з'єднання з вами.",
"zh_CN": "禁用P2P网络连接对方将通过主服务器进行连接而不是直接连接到您。",
"zh_CN": "禁用 P2P 网络连接,对方将通过主服务器进行连接,而不是直接连接到您。",
"zh_TW": "停用對等網路代管 (P2P Network Hosting), 用戶群會經過代理何服器而非直接連線至你的主機。"
}
},
@@ -22268,7 +22268,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "Введіть пароль у форматі Ryujinx-<8 символів>. Ви зможете бачити лише ті ігри, які мають такий самий пароль, як і у вас.",
"zh_CN": "以Ryujinx-<8个十六进制字符>的格式输入密码。您只能看到与您使用相同密码的游戏房间。",
"zh_CN": "以 Ryujinx-<8个十六进制字符> 的格式输入密码。您只能看到与您使用相同密码的游戏房间。",
"zh_TW": "以「Ryujinx-<8 個十六進制數字>」的格式輸入密碼片語 (passphrase)。你只會看到與你的密碼片語 (passphrase) 相同的遊戲房間。"
}
},
@@ -22568,7 +22568,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "Емульована вертикальна синхронізація кадрів. 'Switch' емулює частоту оновлення консолі Nintendo Switch (60 Гц). 'Необмежена' — частота оновлення не матиме обмежень.",
"zh_CN": "模拟垂直同步。“Switch”模拟了Switch60Hz刷新率。“无限制”没有刷新率限制。",
"zh_CN": "模拟垂直同步。“Switch”模拟了 Switch60Hz 刷新率。“无限制”没有刷新率限制。",
"zh_TW": "模擬垂直同步。「Switch」 模擬 Nintendo Switch 的 60Hz 重新整理頻率。「沒有限制」是沒有限制的重新整理頻率。"
}
},
@@ -22593,7 +22593,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "Емульована вертикальна синхронізація кадрів. 'Switch' емулює частоту оновлення консолі Nintendo Switch (60 Гц). 'Необмежена' — частота оновлення не матиме обмежень. 'Користувацька' емулює вказану користувацьку частоту оновлення.",
"zh_CN": "模拟垂直同步。“Switch”模拟了Switch60Hz刷新率。“无限制”没有刷新率限制。“自定义刷新率”模拟指定的自定义刷新率。",
"zh_CN": "模拟垂直同步。“Switch”模拟了 Switch60Hz 刷新率。“无限制”没有刷新率限制。“自定义刷新率”模拟指定的自定义刷新率。",
"zh_TW": "模擬垂直同步。「Switch」 模擬 Nintendo Switch 的 60Hz 重新整理頻率。「沒有限制」是沒有限制的重新整理頻率。「自訂的重新整理頻率」模擬所自訂的重新整理頻率。"
}
},
@@ -22618,7 +22618,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "Дозволяє користувачу вказати емульовану частоту оновлення. У деяких іграх це може прискорити або сповільнити логіку гри. Натомість в інших іграх ця функція може дозволити обмежити FPS на певні кратні частоти оновлення або призвести до непередбачуваної поведінки. Це експериментальна функція, без гарантій того, як вона вплине на ігровий процес. \n\nЗалиште ВИМКНЕНИМ, якщо не впевнені.",
"zh_CN": "允许用户指定模拟刷新率。在某些游戏中这可能会加快或减慢游戏逻辑的速度。在其他游戏中它可能允许将FPS限制在刷新率的某个倍数或者导致不可预测的行为。这是一个实验性功能无法保证游戏会受到怎样的影响。\n\n如果不确定请关闭。",
"zh_CN": "允许用户指定模拟刷新率。在某些游戏中,这可能会加快或减慢游戏逻辑的速度。在其他游戏中,它可能允许将 FPS 限制在刷新率的某个倍数,或者导致不可预测的行为。这是一个实验性功能,无法保证游戏会受到怎样的影响。\n\n如果不确定请关闭。",
"zh_TW": "容許使用者自訂模擬的重新整理頻率。你可能會在某些遊戲裡感受到加快或減慢的遊戲速度;其他遊戲裡則可能會容許限制最高的 FPS 至重新整理頻率的倍數,或引起未知遊戲行為。這是實驗性功能,且沒有保證遊戲會穩定執行。\n\n如果不確定請保持關閉狀態。"
}
},
@@ -23093,7 +23093,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "选择一个要解压的 DLC",
"zh_TW": ""
}
}

View File

@@ -144,7 +144,7 @@ namespace Ryujinx.Ava.Common
public static void ExtractSection(string destination, NcaSectionType ncaSectionType, string titleFilePath, string titleName, int programIndex = 0)
{
var cancellationToken = new CancellationTokenSource();
CancellationTokenSource cancellationToken = new CancellationTokenSource();
UpdateWaitWindow waitingDialog = new(
RyujinxApp.FormatTitle(LocaleKeys.DialogNcaExtractionTitle),
@@ -171,14 +171,14 @@ namespace Ryujinx.Ava.Common
}
else
{
var pfsTemp = new PartitionFileSystem();
PartitionFileSystem pfsTemp = new PartitionFileSystem();
pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure();
pfs = pfsTemp;
}
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
{
using var ncaFile = new UniqueRef<IFile>();
using UniqueRef<IFile> ncaFile = new UniqueRef<IFile>();
pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
@@ -244,8 +244,8 @@ namespace Ryujinx.Ava.Common
string source = DateTime.Now.ToFileTime().ToString()[10..];
string output = DateTime.Now.ToFileTime().ToString()[10..];
using var uniqueSourceFs = new UniqueRef<IFileSystem>(ncaFileSystem);
using var uniqueOutputFs = new UniqueRef<IFileSystem>(new LocalFileSystem(destination));
using UniqueRef<IFileSystem> uniqueSourceFs = new UniqueRef<IFileSystem>(ncaFileSystem);
using UniqueRef<IFileSystem> uniqueOutputFs = new UniqueRef<IFileSystem>(new LocalFileSystem(destination));
fsClient.Register(source.ToU8Span(), ref uniqueSourceFs.Ref);
fsClient.Register(output.ToU8Span(), ref uniqueOutputFs.Ref);
@@ -299,7 +299,7 @@ namespace Ryujinx.Ava.Common
public static void ExtractAoc(string destination, string updateFilePath, string updateName)
{
var cancellationToken = new CancellationTokenSource();
CancellationTokenSource cancellationToken = new CancellationTokenSource();
UpdateWaitWindow waitingDialog = new(
RyujinxApp.FormatTitle(LocaleKeys.DialogNcaExtractionTitle),
@@ -317,13 +317,13 @@ namespace Ryujinx.Ava.Common
string extension = Path.GetExtension(updateFilePath).ToLower();
if (extension is ".nsp")
{
var pfsTemp = new PartitionFileSystem();
PartitionFileSystem pfsTemp = new PartitionFileSystem();
pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure();
IFileSystem pfs = pfsTemp;
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
{
using var ncaFile = new UniqueRef<IFile>();
using UniqueRef<IFile> ncaFile = new UniqueRef<IFile>();
pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
@@ -364,8 +364,8 @@ namespace Ryujinx.Ava.Common
string source = DateTime.Now.ToFileTime().ToString()[10..];
string output = DateTime.Now.ToFileTime().ToString()[10..];
using var uniqueSourceFs = new UniqueRef<IFileSystem>(ncaFileSystem);
using var uniqueOutputFs = new UniqueRef<IFileSystem>(new LocalFileSystem(destination));
using UniqueRef<IFileSystem> uniqueSourceFs = new UniqueRef<IFileSystem>(ncaFileSystem);
using UniqueRef<IFileSystem> uniqueOutputFs = new UniqueRef<IFileSystem>(new LocalFileSystem(destination));
fsClient.Register(source.ToU8Span(), ref uniqueSourceFs.Ref);
fsClient.Register(output.ToU8Span(), ref uniqueOutputFs.Ref);

View File

@@ -32,7 +32,7 @@ namespace Ryujinx.Ava.Common.Locale
private void Load()
{
var localeLanguageCode = !string.IsNullOrEmpty(ConfigurationState.Instance.UI.LanguageCode.Value) ?
string localeLanguageCode = !string.IsNullOrEmpty(ConfigurationState.Instance.UI.LanguageCode.Value) ?
ConfigurationState.Instance.UI.LanguageCode.Value : CultureInfo.CurrentCulture.Name.Replace('-', '_');
LoadLanguage(localeLanguageCode);
@@ -54,7 +54,7 @@ namespace Ryujinx.Ava.Common.Locale
if (_localeStrings.TryGetValue(key, out string value))
{
// Check if the localized string needs to be formatted.
if (_dynamicValues.TryGetValue(key, out var dynamicValue))
if (_dynamicValues.TryGetValue(key, out object[] dynamicValue))
try
{
return string.Format(value, dynamicValue);
@@ -99,7 +99,7 @@ namespace Ryujinx.Ava.Common.Locale
public void LoadLanguage(string languageCode)
{
var locale = LoadJsonLanguage(languageCode);
Dictionary<LocaleKeys, string> locale = LoadJsonLanguage(languageCode);
if (locale == null)
{
@@ -125,7 +125,7 @@ namespace Ryujinx.Ava.Common.Locale
private static Dictionary<LocaleKeys, string> LoadJsonLanguage(string languageCode)
{
var localeStrings = new Dictionary<LocaleKeys, string>();
Dictionary<LocaleKeys, string> localeStrings = new Dictionary<LocaleKeys, string>();
_localeData ??= EmbeddedResources.ReadAllText("Ryujinx/Assets/locales.json")
.Into(it => JsonHelper.Deserialize(it, LocalesJsonContext.Default.LocalesJson));
@@ -142,10 +142,10 @@ namespace Ryujinx.Ava.Common.Locale
throw new Exception($"Locale key {{{locale.ID}}} has too many languages! Has {locale.Translations.Count} translations, expected {_localeData.Value.Languages.Count}!");
}
if (!Enum.TryParse<LocaleKeys>(locale.ID, out var localeKey))
if (!Enum.TryParse<LocaleKeys>(locale.ID, out LocaleKeys localeKey))
continue;
var str = locale.Translations.TryGetValue(languageCode, out string val) && !string.IsNullOrEmpty(val)
string str = locale.Translations.TryGetValue(languageCode, out string val) && !string.IsNullOrEmpty(val)
? val
: locale.Translations[DefaultLanguageCode];

View File

@@ -16,7 +16,7 @@ namespace Ryujinx.Ava.Common.Models
{
public static XCITrimmerFileModel FromApplicationData(ApplicationData applicationData, XCIFileTrimmerLog logger)
{
var trimmer = new XCIFileTrimmer(applicationData.Path, logger);
XCIFileTrimmer trimmer = new XCIFileTrimmer(applicationData.Path, logger);
return new XCITrimmerFileModel(
applicationData.Name,

View File

@@ -14,7 +14,8 @@ namespace Ryujinx.Ava
{
public static class DiscordIntegrationModule
{
public static Timestamps StartedAt { get; set; }
public static Timestamps EmulatorStartedAt { get; set; }
public static Timestamps GuestAppStartedAt { get; set; }
private static string VersionString
=> (ReleaseInformation.IsCanaryBuild ? "Canary " : string.Empty) + $"v{ReleaseInformation.Version}";
@@ -43,7 +44,7 @@ namespace Ryujinx.Ava
},
Details = "Main Menu",
State = "Idling",
Timestamps = StartedAt
Timestamps = EmulatorStartedAt
};
ConfigurationState.Instance.EnableDiscordIntegration.Event += Update;
@@ -100,7 +101,7 @@ namespace Ryujinx.Ava
State = appMeta.LastPlayed.HasValue && appMeta.TimePlayed.TotalSeconds > 5
? $"Total play time: {ValueFormatUtils.FormatTimeSpan(appMeta.TimePlayed)}"
: "Never played",
Timestamps = Timestamps.Now
Timestamps = GuestAppStartedAt ??= Timestamps.Now
});
}

View File

@@ -33,7 +33,7 @@ namespace Ryujinx.Headless
public static void Initialize()
{
// Ensure Discord presence timestamp begins at the absolute start of when Ryujinx is launched
DiscordIntegrationModule.StartedAt = Timestamps.Now;
DiscordIntegrationModule.EmulatorStartedAt = Timestamps.Now;
// Delete backup files after updating.
Task.Run(Updater.CleanupUpdate);
@@ -291,9 +291,9 @@ namespace Ryujinx.Headless
if (!string.IsNullOrEmpty(options.PreferredGPUVendor))
{
string preferredGpuVendor = options.PreferredGPUVendor.ToLowerInvariant();
var devices = VulkanRenderer.GetPhysicalDevices(api);
DeviceInfo[] devices = VulkanRenderer.GetPhysicalDevices(api);
foreach (var device in devices)
foreach (DeviceInfo device in devices)
{
if (device.Vendor.ToLowerInvariant() == preferredGpuVendor)
{

View File

@@ -150,7 +150,7 @@ namespace Ryujinx.Headless
AppDataManager.Initialize(option.BaseDataDir);
if (useLastUsedProfile && AccountSaveDataManager.GetLastUsedUser().TryGet(out var profile))
if (useLastUsedProfile && AccountSaveDataManager.GetLastUsedUser().TryGet(out UserProfile profile))
option.UserProfile = profile.Name;
// Check if keys exists.

View File

@@ -1,4 +1,5 @@
using Humanizer;
using LibHac.Ns;
using Ryujinx.Ava;
using Ryujinx.Ava.UI.Models;
using Ryujinx.Common;
@@ -11,6 +12,7 @@ using Ryujinx.Graphics.OpenGL;
using Ryujinx.HLE.HOS.Applets;
using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
using Ryujinx.HLE.Loaders.Processes;
using Ryujinx.HLE.UI;
using Ryujinx.Input;
using Ryujinx.Input.HLE;
@@ -165,8 +167,8 @@ namespace Ryujinx.Headless
private void InitializeWindow()
{
var activeProcess = Device.Processes.ActiveApplication;
var nacp = activeProcess.ApplicationControlProperties;
ProcessResult activeProcess = Device.Processes.ActiveApplication;
ApplicationControlProperty nacp = activeProcess.ApplicationControlProperties;
int desiredLanguage = (int)Device.System.State.DesiredTitleLanguage;
string titleNameSection = string.IsNullOrWhiteSpace(nacp.Title[desiredLanguage].NameString.ToString()) ? string.Empty : $" - {nacp.Title[desiredLanguage].NameString.ToString()}";

View File

@@ -91,7 +91,7 @@ namespace Ryujinx.Ava.Input
return false;
}
AvaloniaKeyboardMappingHelper.TryGetAvaKey(key, out var nativeKey);
AvaloniaKeyboardMappingHelper.TryGetAvaKey(key, out AvaKey nativeKey);
return _pressedKeys.Contains(nativeKey);
}

View File

@@ -150,14 +150,14 @@ namespace Ryujinx.Ava.Input
static AvaloniaKeyboardMappingHelper()
{
var inputKeys = Enum.GetValues<Key>();
Key[] inputKeys = Enum.GetValues<Key>();
// NOTE: Avalonia.Input.Key is not contiguous and quite large, so use a dictionary instead of an array.
_avaKeyMapping = new Dictionary<AvaKey, Key>();
foreach (var key in inputKeys)
foreach (Key key in inputKeys)
{
if (TryGetAvaKey(key, out var index))
if (TryGetAvaKey(key, out AvaKey index))
{
_avaKeyMapping[index] = key;
}

View File

@@ -94,7 +94,7 @@ namespace Ryujinx.Ava
private static void Initialize(string[] args)
{
// Ensure Discord presence timestamp begins at the absolute start of when Ryujinx is launched
DiscordIntegrationModule.StartedAt = Timestamps.Now;
DiscordIntegrationModule.EmulatorStartedAt = Timestamps.Now;
// Parse arguments
CommandLineState.ParseArguments(args);
@@ -262,7 +262,7 @@ namespace Ryujinx.Ava
exceptions.Add(initialException);
}
foreach (var e in exceptions)
foreach (Exception e in exceptions)
{
string message = $"Unhandled exception caught: {e}";
// ReSharper disable once ConstantConditionalAccessQualifier

View File

@@ -79,7 +79,7 @@ namespace Ryujinx.Ava
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
var result = await ContentDialogHelper.CreateConfirmationDialog(
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
LocaleManager.Instance[LocaleKeys.DialogThemeRestartMessage],
LocaleManager.Instance[LocaleKeys.DialogThemeRestartSubMessage],
LocaleManager.Instance[LocaleKeys.InputDialogYes],

View File

@@ -46,7 +46,7 @@ namespace Ryujinx.Ava.UI.Applet
Dispatcher.UIThread.InvokeAsync(async () =>
{
var response = await ControllerAppletDialog.ShowControllerAppletDialog(_parent, args);
UserResult response = await ControllerAppletDialog.ShowControllerAppletDialog(_parent, args);
if (response == UserResult.Ok)
{
okPressed = true;

View File

@@ -65,7 +65,7 @@ namespace Ryujinx.Ava.UI.Applet
private void AvaloniaDynamicTextInputHandler_KeyRelease(object sender, KeyEventArgs e)
{
var key = (HidKey)AvaloniaKeyboardMappingHelper.ToInputKey(e.Key);
HidKey key = (HidKey)AvaloniaKeyboardMappingHelper.ToInputKey(e.Key);
if (!(KeyReleasedEvent?.Invoke(key)).GetValueOrDefault(true))
{
@@ -85,7 +85,7 @@ namespace Ryujinx.Ava.UI.Applet
private void AvaloniaDynamicTextInputHandler_KeyPressed(object sender, KeyEventArgs e)
{
var key = (HidKey)AvaloniaKeyboardMappingHelper.ToInputKey(e.Key);
HidKey key = (HidKey)AvaloniaKeyboardMappingHelper.ToInputKey(e.Key);
if (!(KeyPressedEvent?.Invoke(key)).GetValueOrDefault(true))
{

View File

@@ -60,11 +60,11 @@ namespace Ryujinx.Ava.UI.Applet
ObservableCollection<BaseModel> newProfiles = [];
foreach (var item in ViewModel.Profiles)
foreach (BaseModel item in ViewModel.Profiles)
{
if (item is UserProfile originalItem)
{
var profile = new UserProfileSft(originalItem.UserId, originalItem.Name, originalItem.Image);
UserProfileSft profile = new UserProfileSft(originalItem.UserId, originalItem.Name, originalItem.Image);
if (profile.UserId == ViewModel.SelectedUserId)
{

View File

@@ -76,7 +76,7 @@ namespace Ryujinx.Ava.UI.Controls
private static void OpenSaveDirectory(MainWindowViewModel viewModel, SaveDataType saveDataType, UserId userId)
{
var saveDataFilter = SaveDataFilter.Make(viewModel.SelectedApplication.Id, saveDataType, userId, saveDataId: default, index: default);
SaveDataFilter saveDataFilter = SaveDataFilter.Make(viewModel.SelectedApplication.Id, saveDataType, userId, saveDataId: default, index: default);
ApplicationHelper.OpenSaveDir(in saveDataFilter, viewModel.SelectedApplication.Id, viewModel.SelectedApplication.ControlHolder, viewModel.SelectedApplication.Name);
}
@@ -305,7 +305,7 @@ namespace Ryujinx.Ava.UI.Controls
if (sender is not MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
return;
var result = await viewModel.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
IReadOnlyList<IStorageFolder> result = await viewModel.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
{
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle],
AllowMultiple = false,
@@ -320,13 +320,13 @@ namespace Ryujinx.Ava.UI.Controls
viewModel.SelectedApplication.Path,
viewModel.SelectedApplication.Name);
var iconFile = await result[0].CreateFileAsync($"{viewModel.SelectedApplication.IdString}.png");
await using var fileStream = await iconFile.OpenWriteAsync();
IStorageFile iconFile = await result[0].CreateFileAsync($"{viewModel.SelectedApplication.IdString}.png");
await using Stream fileStream = await iconFile.OpenWriteAsync();
using var bitmap = SKBitmap.Decode(viewModel.SelectedApplication.Icon)
using SKBitmap bitmap = SKBitmap.Decode(viewModel.SelectedApplication.Icon)
.Resize(new SKSizeI(512, 512), SKFilterQuality.High);
using var png = bitmap.Encode(SKEncodedImageFormat.Png, 100);
using SKData png = bitmap.Encode(SKEncodedImageFormat.Png, 100);
png.SaveTo(fileStream);
}
@@ -350,7 +350,7 @@ namespace Ryujinx.Ava.UI.Controls
public async void TrimXCI_Click(object sender, RoutedEventArgs args)
{
var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
MainWindowViewModel viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
if (viewModel?.SelectedApplication != null)
{

View File

@@ -1,6 +1,7 @@
using Avalonia.Controls;
using Avalonia.Controls.Notifications;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Interactivity;
using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.UI.Helpers;
@@ -38,10 +39,10 @@ namespace Ryujinx.Ava.UI.Controls
if (sender is not Button { Content: TextBlock idText })
return;
if (!RyujinxApp.IsClipboardAvailable(out var clipboard))
if (!RyujinxApp.IsClipboardAvailable(out IClipboard clipboard))
return;
var appData = mwvm.Applications.FirstOrDefault(it => it.IdString == idText.Text);
ApplicationData appData = mwvm.Applications.FirstOrDefault(it => it.IdString == idText.Text);
if (appData is null)
return;

View File

@@ -106,9 +106,9 @@ namespace Ryujinx.Ava.UI.Controls
.OrderBy(x => x.Name)
.ForEach(profile => ViewModel.Profiles.Add(new UserProfile(profile, this)));
var saveDataFilter = SaveDataFilter.Make(programId: default, saveType: SaveDataType.Account, default, saveDataId: default, index: default);
SaveDataFilter saveDataFilter = SaveDataFilter.Make(programId: default, saveType: SaveDataType.Account, default, saveDataId: default, index: default);
using var saveDataIterator = new UniqueRef<SaveDataIterator>();
using UniqueRef<SaveDataIterator> saveDataIterator = new UniqueRef<SaveDataIterator>();
HorizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref, SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure();
@@ -127,8 +127,8 @@ namespace Ryujinx.Ava.UI.Controls
for (int i = 0; i < readCount; i++)
{
var save = saveDataInfo[i];
var id = new UserId((long)save.UserId.Id.Low, (long)save.UserId.Id.High);
SaveDataInfo save = saveDataInfo[i];
UserId id = new UserId((long)save.UserId.Id.Low, (long)save.UserId.Id.High);
if (ViewModel.Profiles.Cast<UserProfile>().FirstOrDefault(x => x.UserId == id) == null)
{
lostAccounts.Add(id);
@@ -136,7 +136,7 @@ namespace Ryujinx.Ava.UI.Controls
}
}
foreach (var account in lostAccounts)
foreach (UserId account in lostAccounts)
{
ViewModel.LostProfiles.Add(new UserProfile(new HLE.HOS.Services.Account.Acc.UserProfile(account, string.Empty, null), this));
}
@@ -146,12 +146,12 @@ namespace Ryujinx.Ava.UI.Controls
public async void DeleteUser(UserProfile userProfile)
{
var lastUserId = AccountManager.LastOpenedUser.UserId;
UserId lastUserId = AccountManager.LastOpenedUser.UserId;
if (userProfile.UserId == lastUserId)
{
// If we are deleting the currently open profile, then we must open something else before deleting.
var profile = ViewModel.Profiles.Cast<UserProfile>().FirstOrDefault(x => x.UserId != lastUserId);
UserProfile profile = ViewModel.Profiles.Cast<UserProfile>().FirstOrDefault(x => x.UserId != lastUserId);
if (profile == null)
{
@@ -165,7 +165,7 @@ namespace Ryujinx.Ava.UI.Controls
AccountManager.OpenUser(profile.UserId);
}
var result = await ContentDialogHelper.CreateConfirmationDialog(
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
LocaleManager.Instance[LocaleKeys.DialogUserProfileDeletionConfirmMessage],
string.Empty,
LocaleManager.Instance[LocaleKeys.InputDialogYes],

View File

@@ -21,7 +21,7 @@ namespace Ryujinx.Ava.UI.Helpers
/// </remarks>
public static bool ReplaceWith<T>(this AvaloniaList<T> list, T item, bool addIfNotFound = true)
{
var index = list.IndexOf(item);
int index = list.IndexOf(item);
if (index != -1)
{
@@ -45,9 +45,9 @@ namespace Ryujinx.Ava.UI.Helpers
/// <param name="matchingList">The items to use as matching records to search for in the `sourceList', if not found this item will be added instead</params>
public static void AddOrReplaceMatching<T>(this AvaloniaList<T> list, IList<T> sourceList, IList<T> matchingList)
{
foreach (var match in matchingList)
foreach (T match in matchingList)
{
var index = sourceList.IndexOf(match);
int index = sourceList.IndexOf(match);
if (index != -1)
{
list.ReplaceWith(sourceList[index]);

View File

@@ -121,7 +121,7 @@ namespace Ryujinx.Ava.UI.Helpers
startedDeferring = true;
var deferral = args.GetDeferral();
Deferral deferral = args.GetDeferral();
sender.PrimaryButtonClick -= DeferClose;

View File

@@ -23,7 +23,7 @@ namespace Ryujinx.Ava.UI.Helpers
}
public string this[string key] =>
_glyphs.TryGetValue(Enum.Parse<Glyph>(key), out var val)
_glyphs.TryGetValue(Enum.Parse<Glyph>(key), out string val)
? val
: string.Empty;

View File

@@ -30,7 +30,7 @@ namespace Ryujinx.Ava.UI.Helpers
return null;
}
var key = isBundled ? LocaleKeys.TitleBundledUpdateVersionLabel : LocaleKeys.TitleUpdateVersionLabel;
LocaleKeys key = isBundled ? LocaleKeys.TitleBundledUpdateVersionLabel : LocaleKeys.TitleUpdateVersionLabel;
return LocaleManager.Instance.UpdateAndGetDynamicValue(key, label);
}

View File

@@ -50,8 +50,8 @@ namespace Ryujinx.Ava.UI.Helpers
private static string Format(AvaLogLevel level, string area, string template, object source, object[] v)
{
var result = new StringBuilder();
var r = new CharacterReader(template.AsSpan());
StringBuilder result = new StringBuilder();
CharacterReader r = new CharacterReader(template.AsSpan());
int i = 0;
result.Append('[');
@@ -64,7 +64,7 @@ namespace Ryujinx.Ava.UI.Helpers
while (!r.End)
{
var c = r.Take();
char c = r.Take();
if (c != '{')
{

View File

@@ -28,7 +28,7 @@ namespace Ryujinx.Ava.UI.Helpers
Margin = new Thickness(0, 0, 15, 40),
};
var maybeAsyncWorkQueue = new Lazy<AsyncWorkQueue<Notification>>(
Lazy<AsyncWorkQueue<Notification>> maybeAsyncWorkQueue = new Lazy<AsyncWorkQueue<Notification>>(
() => new AsyncWorkQueue<Notification>(notification =>
{
Dispatcher.UIThread.Post(() =>
@@ -57,7 +57,7 @@ namespace Ryujinx.Ava.UI.Helpers
public static void Show(string title, string text, NotificationType type, bool waitingExit = false, Action onClick = null, Action onClose = null)
{
var delay = waitingExit ? TimeSpan.FromMilliseconds(0) : TimeSpan.FromMilliseconds(NotificationDelayInMs);
TimeSpan delay = waitingExit ? TimeSpan.FromMilliseconds(0) : TimeSpan.FromMilliseconds(NotificationDelayInMs);
_notifications.Add(new Notification(title, text, type, delay, onClick, onClose));
}

View File

@@ -28,7 +28,7 @@ namespace Ryujinx.Ava.UI.Models
}
set
{
foreach (var cheat in SubNodes)
foreach (CheatNode cheat in SubNodes)
{
cheat.IsEnabled = value;
cheat.OnPropertyChanged();

View File

@@ -367,7 +367,7 @@ namespace Ryujinx.Ava.UI.Models.Input
public InputConfig GetConfig()
{
var config = new StandardKeyboardInputConfig
StandardKeyboardInputConfig config = new StandardKeyboardInputConfig
{
Id = Id,
Backend = InputBackendType.WindowKeyboard,

View File

@@ -48,7 +48,7 @@ namespace Ryujinx.Ava.UI.Models
TitleId = info.ProgramId;
UserId = info.UserId;
var appData = RyujinxApp.MainWindow.ViewModel.Applications.FirstOrDefault(x => x.IdString.EqualsIgnoreCase(TitleIdString));
ApplicationData appData = RyujinxApp.MainWindow.ViewModel.Applications.FirstOrDefault(x => x.IdString.EqualsIgnoreCase(TitleIdString));
InGameList = appData != null;
@@ -59,13 +59,13 @@ namespace Ryujinx.Ava.UI.Models
}
else
{
var appMetadata = ApplicationLibrary.LoadAndSaveMetaData(TitleIdString);
ApplicationMetadata appMetadata = ApplicationLibrary.LoadAndSaveMetaData(TitleIdString);
Title = appMetadata.Title ?? TitleIdString;
}
Task.Run(() =>
{
var saveRoot = Path.Combine(VirtualFileSystem.GetNandPath(), $"user/save/{info.SaveDataId:x16}");
string saveRoot = Path.Combine(VirtualFileSystem.GetNandPath(), $"user/save/{info.SaveDataId:x16}");
long totalSize = GetDirectorySize(saveRoot);
@@ -74,14 +74,14 @@ namespace Ryujinx.Ava.UI.Models
long size = 0;
if (Directory.Exists(path))
{
var directories = Directory.GetDirectories(path);
foreach (var directory in directories)
string[] directories = Directory.GetDirectories(path);
foreach (string directory in directories)
{
size += GetDirectorySize(directory);
}
var files = Directory.GetFiles(path);
foreach (var file in files)
string[] files = Directory.GetFiles(path);
foreach (string file in files)
{
size += new FileInfo(file).Length;
}

View File

@@ -1,3 +1,4 @@
using Avalonia;
using Avalonia.Media;
using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.ViewModels;
@@ -87,7 +88,7 @@ namespace Ryujinx.Ava.UI.Models
private void UpdateBackground()
{
var currentApplication = Avalonia.Application.Current;
Application currentApplication = Avalonia.Application.Current;
currentApplication.Styles.TryGetResource("ControlFillColorSecondary", currentApplication.ActualThemeVariant, out object color);
if (color is not null)

View File

@@ -44,13 +44,13 @@ namespace Ryujinx.Ava.UI.Renderer
throw new PlatformNotSupportedException();
}
var flags = OpenGLContextFlags.Compat;
OpenGLContextFlags flags = OpenGLContextFlags.Compat;
if (ConfigurationState.Instance.Logger.GraphicsDebugLevel != GraphicsDebugLevel.None)
{
flags |= OpenGLContextFlags.Debug;
}
var graphicsMode = Environment.OSVersion.Platform == PlatformID.Unix ? new FramebufferFormat(new ColorFormat(8, 8, 8, 0), 16, 0, ColorFormat.Zero, 0, 2, false) : FramebufferFormat.Default;
FramebufferFormat graphicsMode = Environment.OSVersion.Platform == PlatformID.Unix ? new FramebufferFormat(new ColorFormat(8, 8, 8, 0), 16, 0, ColorFormat.Zero, 0, 2, false) : FramebufferFormat.Default;
Context = PlatformHelper.CreateOpenGLContext(graphicsMode, 3, 3, flags);

View File

@@ -8,7 +8,7 @@ namespace Ryujinx.Ava.UI.ViewModels
protected void OnPropertiesChanged(string firstPropertyName, params ReadOnlySpan<string> propertyNames)
{
OnPropertyChanged(firstPropertyName);
foreach (var propertyName in propertyNames)
foreach (string propertyName in propertyNames)
{
OnPropertyChanged(propertyName);
}

View File

@@ -11,6 +11,7 @@ using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.Utilities.AppLibrary;
using Ryujinx.HLE.FileSystem;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
@@ -71,7 +72,7 @@ namespace Ryujinx.Ava.UI.ViewModels
private void LoadDownloadableContents()
{
var dlcs = _applicationLibrary.DownloadableContents.Items
IEnumerable<(DownloadableContentModel Dlc, bool IsEnabled)> dlcs = _applicationLibrary.DownloadableContents.Items
.Where(it => it.Dlc.TitleIdBase == _applicationData.IdBase);
bool hasBundledContent = false;
@@ -101,11 +102,11 @@ namespace Ryujinx.Ava.UI.ViewModels
.ThenBy(it => it.TitleId)
.AsObservableChangeSet()
.Filter(Filter)
.Bind(out var view).AsObservableList();
.Bind(out ReadOnlyObservableCollection<DownloadableContentModel> view).AsObservableList();
// NOTE(jpr): this works around a bug where calling _views.Clear also clears SelectedDownloadableContents for
// some reason. so we save the items here and add them back after
var items = SelectedDownloadableContents.ToArray();
DownloadableContentModel[] items = SelectedDownloadableContents.ToArray();
Views.Clear();
Views.AddRange(view);
@@ -130,7 +131,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async void Add()
{
var result = await _storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
IReadOnlyList<IStorageFile> result = await _storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{
Title = LocaleManager.Instance[LocaleKeys.SelectDlcDialogTitle],
AllowMultiple = true,
@@ -145,10 +146,10 @@ namespace Ryujinx.Ava.UI.ViewModels
},
});
var totalDlcAdded = 0;
foreach (var file in result)
int totalDlcAdded = 0;
foreach (IStorageFile file in result)
{
if (!AddDownloadableContent(file.Path.LocalPath, out var newDlcAdded))
if (!AddDownloadableContent(file.Path.LocalPath, out int newDlcAdded))
{
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogDlcNoDlcErrorMessage]);
}
@@ -171,18 +172,18 @@ namespace Ryujinx.Ava.UI.ViewModels
return false;
}
if (!_applicationLibrary.TryGetDownloadableContentFromFile(path, out var dlcs) || dlcs.Count == 0)
if (!_applicationLibrary.TryGetDownloadableContentFromFile(path, out List<DownloadableContentModel> dlcs) || dlcs.Count == 0)
{
return false;
}
var dlcsForThisGame = dlcs.Where(it => it.TitleIdBase == _applicationData.IdBase).ToList();
List<DownloadableContentModel> dlcsForThisGame = dlcs.Where(it => it.TitleIdBase == _applicationData.IdBase).ToList();
if (dlcsForThisGame.Count == 0)
{
return false;
}
foreach (var dlc in dlcsForThisGame)
foreach (DownloadableContentModel dlc in dlcsForThisGame)
{
if (!DownloadableContents.Contains(dlc))
{
@@ -246,13 +247,13 @@ namespace Ryujinx.Ava.UI.ViewModels
public void Save()
{
var dlcs = DownloadableContents.Select(it => (it, SelectedDownloadableContents.Contains(it))).ToList();
List<(DownloadableContentModel it, bool)> dlcs = DownloadableContents.Select(it => (it, SelectedDownloadableContents.Contains(it))).ToList();
_applicationLibrary.SaveDownloadableContentsForGame(_applicationData, dlcs);
}
private Task ShowNewDlcAddedDialog(int numAdded)
{
var msg = string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowDlcAddedMessage], numAdded);
string msg = string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowDlcAddedMessage], numAdded);
return Dispatcher.UIThread.InvokeAsync(async () =>
{
await ContentDialogHelper.ShowTextDialog(

View File

@@ -215,7 +215,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
return;
}
var selected = Devices[_device].Type;
DeviceType selected = Devices[_device].Type;
if (selected != DeviceType.None)
{
@@ -299,7 +299,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
}
else
{
var type = DeviceType.None;
DeviceType type = DeviceType.None;
if (Config is StandardKeyboardInputConfig)
{
@@ -311,7 +311,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
type = DeviceType.Controller;
}
var item = Devices.FirstOrDefault(x => x.Type == type && x.Id == Config.Id);
(DeviceType Type, string Id, string Name) item = Devices.FirstOrDefault(x => x.Type == type && x.Id == Config.Id);
if (item != default)
{
Device = Devices.ToList().FindIndex(x => x.Id == item.Id);
@@ -331,7 +331,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
}
string id = GetCurrentGamepadId();
var type = Devices[Device].Type;
DeviceType type = Devices[Device].Type;
if (type == DeviceType.None)
{
@@ -373,7 +373,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
return string.Empty;
}
var device = Devices[Device];
(DeviceType Type, string Id, string Name) device = Devices[Device];
if (device.Type == DeviceType.None)
{
@@ -485,7 +485,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
private string GetProfileBasePath()
{
string path = AppDataManager.ProfilesDirPath;
var type = Devices[Device == -1 ? 0 : Device].Type;
DeviceType type = Devices[Device == -1 ? 0 : Device].Type;
if (type == DeviceType.Keyboard)
{
@@ -525,7 +525,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public InputConfig LoadDefaultConfiguration()
{
var activeDevice = Devices.FirstOrDefault();
(DeviceType Type, string Id, string Name) activeDevice = Devices.FirstOrDefault();
if (Devices.Count > 0 && Device < Devices.Count && Device >= 0)
{
@@ -822,20 +822,20 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
}
else
{
var device = Devices[Device];
(DeviceType Type, string Id, string Name) device = Devices[Device];
if (device.Type == DeviceType.Keyboard)
{
var inputConfig = (ConfigViewModel as KeyboardInputViewModel).Config;
KeyboardInputConfig inputConfig = (ConfigViewModel as KeyboardInputViewModel).Config;
inputConfig.Id = device.Id;
}
else
{
var inputConfig = (ConfigViewModel as ControllerInputViewModel).Config;
GamepadInputConfig inputConfig = (ConfigViewModel as ControllerInputViewModel).Config;
inputConfig.Id = device.Id.Split(" ")[0];
}
var config = !IsController
InputConfig config = !IsController
? (ConfigViewModel as KeyboardInputViewModel).Config.GetConfig()
: (ConfigViewModel as ControllerInputViewModel).Config.GetConfig();
config.ControllerType = Controllers[_controller].Type;

View File

@@ -1046,9 +1046,9 @@ namespace Ryujinx.Ava.UI.ViewModels
private void PrepareLoadScreen()
{
using MemoryStream stream = new(SelectedIcon);
using var gameIconBmp = SKBitmap.Decode(stream);
using SKBitmap gameIconBmp = SKBitmap.Decode(stream);
var dominantColor = IconColorPicker.GetFilteredColor(gameIconBmp);
SKColor dominantColor = IconColorPicker.GetFilteredColor(gameIconBmp);
const float ColorMultiple = 0.5f;
@@ -1132,7 +1132,7 @@ namespace Ryujinx.Ava.UI.ViewModels
private async Task LoadContentFromFolder(LocaleKeys localeMessageAddedKey, LocaleKeys localeMessageRemovedKey, LoadContentFromFolderDelegate onDirsSelected)
{
var result = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
IReadOnlyList<IStorageFolder> result = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
{
Title = LocaleManager.Instance[LocaleKeys.OpenFolderDialogTitle],
AllowMultiple = true,
@@ -1140,10 +1140,10 @@ namespace Ryujinx.Ava.UI.ViewModels
if (result.Count > 0)
{
var dirs = result.Select(it => it.Path.LocalPath).ToList();
var numAdded = onDirsSelected(dirs, out int numRemoved);
List<string> dirs = result.Select(it => it.Path.LocalPath).ToList();
int numAdded = onDirsSelected(dirs, out int numRemoved);
var msg = String.Join("\r\n", new string[] {
string msg = String.Join("\r\n", new string[] {
string.Format(LocaleManager.Instance[localeMessageRemovedKey], numRemoved),
string.Format(LocaleManager.Instance[localeMessageAddedKey], numAdded)
});
@@ -1180,17 +1180,17 @@ namespace Ryujinx.Ava.UI.ViewModels
public void LoadConfigurableHotKeys()
{
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUI, out var showUiKey))
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUI, out Avalonia.Input.Key showUiKey))
{
ShowUiKey = new KeyGesture(showUiKey);
}
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot, out var screenshotKey))
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot, out Avalonia.Input.Key screenshotKey))
{
ScreenshotKey = new KeyGesture(screenshotKey);
}
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause, out var pauseKey))
if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause, out Avalonia.Input.Key pauseKey))
{
PauseKey = new KeyGesture(pauseKey);
}
@@ -1238,7 +1238,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async Task InstallFirmwareFromFile()
{
var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
IReadOnlyList<IStorageFile> result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{
AllowMultiple = false,
FileTypeFilter = new List<FilePickerFileType>
@@ -1272,7 +1272,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async Task InstallFirmwareFromFolder()
{
var result = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
IReadOnlyList<IStorageFolder> result = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
{
AllowMultiple = false,
});
@@ -1285,7 +1285,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async Task InstallKeysFromFile()
{
var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
IReadOnlyList<IStorageFile> result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{
AllowMultiple = false,
FileTypeFilter = new List<FilePickerFileType>
@@ -1319,7 +1319,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async Task InstallKeysFromFolder()
{
var result = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
IReadOnlyList<IStorageFolder> result = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
{
AllowMultiple = false,
});
@@ -1410,7 +1410,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async Task OpenFile()
{
var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
IReadOnlyList<IStorageFile> result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{
Title = LocaleManager.Instance[LocaleKeys.OpenFileDialogTitle],
AllowMultiple = false,
@@ -1501,7 +1501,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async Task OpenFolder()
{
var result = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
IReadOnlyList<IStorageFolder> result = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
{
Title = LocaleManager.Instance[LocaleKeys.OpenFolderDialogTitle],
AllowMultiple = false,
@@ -1682,7 +1682,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{
if (AppHost.Device.System.SearchingForAmiibo(out _) && IsGameRunning)
{
var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
IReadOnlyList<IStorageFile> result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{
Title = LocaleManager.Instance[LocaleKeys.OpenFileDialogTitle],
AllowMultiple = false,
@@ -1802,16 +1802,16 @@ namespace Ryujinx.Ava.UI.ViewModels
return;
}
var trimmer = new XCIFileTrimmer(filename, new XCITrimmerLog.MainWindow(this));
XCIFileTrimmer trimmer = new XCIFileTrimmer(filename, new XCITrimmerLog.MainWindow(this));
if (trimmer.CanBeTrimmed)
{
var savings = (double)trimmer.DiskSpaceSavingsB / 1024.0 / 1024.0;
var currentFileSize = (double)trimmer.FileSizeB / 1024.0 / 1024.0;
var cartDataSize = (double)trimmer.DataSizeB / 1024.0 / 1024.0;
double savings = (double)trimmer.DiskSpaceSavingsB / 1024.0 / 1024.0;
double currentFileSize = (double)trimmer.FileSizeB / 1024.0 / 1024.0;
double cartDataSize = (double)trimmer.DataSizeB / 1024.0 / 1024.0;
string secondaryText = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.TrimXCIFileDialogSecondaryText, currentFileSize, cartDataSize, savings);
var result = await ContentDialogHelper.CreateConfirmationDialog(
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
LocaleManager.Instance[LocaleKeys.TrimXCIFileDialogPrimaryText],
secondaryText,
LocaleManager.Instance[LocaleKeys.Continue],

View File

@@ -12,6 +12,8 @@ using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE.HOS;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
@@ -77,37 +79,37 @@ namespace Ryujinx.Ava.UI.ViewModels
string[] modsBasePaths = [ModLoader.GetSdModsBasePath(), ModLoader.GetModsBasePath()];
foreach (var path in modsBasePaths)
foreach (string path in modsBasePaths)
{
var inSd = path == ModLoader.GetSdModsBasePath();
var modCache = new ModLoader.ModCache();
bool inSd = path == ModLoader.GetSdModsBasePath();
ModLoader.ModCache modCache = new ModLoader.ModCache();
ModLoader.QueryContentsDir(modCache, new DirectoryInfo(Path.Combine(path, "contents")), applicationId);
foreach (var mod in modCache.RomfsDirs)
foreach (ModLoader.Mod<DirectoryInfo> mod in modCache.RomfsDirs)
{
var modModel = new ModModel(mod.Path.Parent.FullName, mod.Name, mod.Enabled, inSd);
ModModel modModel = new ModModel(mod.Path.Parent.FullName, mod.Name, mod.Enabled, inSd);
if (Mods.All(x => x.Path != mod.Path.Parent.FullName))
{
Mods.Add(modModel);
}
}
foreach (var mod in modCache.RomfsContainers)
foreach (ModLoader.Mod<FileInfo> mod in modCache.RomfsContainers)
{
Mods.Add(new ModModel(mod.Path.FullName, mod.Name, mod.Enabled, inSd));
}
foreach (var mod in modCache.ExefsDirs)
foreach (ModLoader.Mod<DirectoryInfo> mod in modCache.ExefsDirs)
{
var modModel = new ModModel(mod.Path.Parent.FullName, mod.Name, mod.Enabled, inSd);
ModModel modModel = new ModModel(mod.Path.Parent.FullName, mod.Name, mod.Enabled, inSd);
if (Mods.All(x => x.Path != mod.Path.Parent.FullName))
{
Mods.Add(modModel);
}
}
foreach (var mod in modCache.ExefsContainers)
foreach (ModLoader.Mod<FileInfo> mod in modCache.ExefsContainers)
{
Mods.Add(new ModModel(mod.Path.FullName, mod.Name, mod.Enabled, inSd));
}
@@ -120,7 +122,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{
Mods.AsObservableChangeSet()
.Filter(Filter)
.Bind(out var view).AsObservableList();
.Bind(out ReadOnlyObservableCollection<ModModel> view).AsObservableList();
#pragma warning disable MVVMTK0034 // Event to update is fired below
_views.Clear();
@@ -163,10 +165,10 @@ namespace Ryujinx.Ava.UI.ViewModels
public void Delete(ModModel model, bool removeFromList = true)
{
var isSubdir = true;
var pathToDelete = model.Path;
var basePath = model.InSd ? ModLoader.GetSdModsBasePath() : ModLoader.GetModsBasePath();
var modsDir = ModLoader.GetApplicationDir(basePath, _applicationId.ToString("x16"));
bool isSubdir = true;
string pathToDelete = model.Path;
string basePath = model.InSd ? ModLoader.GetSdModsBasePath() : ModLoader.GetModsBasePath();
string modsDir = ModLoader.GetApplicationDir(basePath, _applicationId.ToString("x16"));
if (new DirectoryInfo(model.Path).Parent?.FullName == modsDir)
{
@@ -175,9 +177,9 @@ namespace Ryujinx.Ava.UI.ViewModels
if (isSubdir)
{
var parentDir = String.Empty;
string parentDir = String.Empty;
foreach (var dir in Directory.GetDirectories(modsDir, "*", SearchOption.TopDirectoryOnly))
foreach (string dir in Directory.GetDirectories(modsDir, "*", SearchOption.TopDirectoryOnly))
{
if (Directory.GetDirectories(dir, "*", SearchOption.AllDirectories).Contains(model.Path))
{
@@ -229,10 +231,10 @@ namespace Ryujinx.Ava.UI.ViewModels
return;
}
var destinationDir = ModLoader.GetApplicationDir(ModLoader.GetSdModsBasePath(), _applicationId.ToString("x16"));
string destinationDir = ModLoader.GetApplicationDir(ModLoader.GetSdModsBasePath(), _applicationId.ToString("x16"));
// TODO: More robust checking for valid mod folders
var isDirectoryValid = true;
bool isDirectoryValid = true;
if (directories.Length == 0)
{
@@ -248,7 +250,7 @@ namespace Ryujinx.Ava.UI.ViewModels
return;
}
foreach (var dir in directories)
foreach (string dir in directories)
{
string dirToCreate = dir.Replace(directory.Parent.ToString(), destinationDir);
@@ -269,9 +271,9 @@ namespace Ryujinx.Ava.UI.ViewModels
Directory.CreateDirectory(dirToCreate);
}
var files = Directory.GetFiles(directory.ToString(), "*", SearchOption.AllDirectories);
string[] files = Directory.GetFiles(directory.ToString(), "*", SearchOption.AllDirectories);
foreach (var file in files)
foreach (string file in files)
{
File.Copy(file, file.Replace(directory.Parent.ToString(), destinationDir), true);
}
@@ -281,13 +283,13 @@ namespace Ryujinx.Ava.UI.ViewModels
public async void Add()
{
var result = await _storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
IReadOnlyList<IStorageFolder> result = await _storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
{
Title = LocaleManager.Instance[LocaleKeys.SelectModDialogTitle],
AllowMultiple = true,
});
foreach (var folder in result)
foreach (IStorageFolder folder in result)
{
AddMod(new DirectoryInfo(folder.Path.LocalPath));
}

View File

@@ -17,6 +17,7 @@ using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Multiplayer;
using Ryujinx.Common.GraphicsDriver;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Vulkan;
using Ryujinx.HLE;
using Ryujinx.HLE.FileSystem;
@@ -387,7 +388,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{
AvailableGpus.Clear();
var devices = VulkanRenderer.GetPhysicalDevices();
DeviceInfo[] devices = VulkanRenderer.GetPhysicalDevices();
if (devices.Length == 0)
{
@@ -396,7 +397,7 @@ namespace Ryujinx.Ava.UI.ViewModels
}
else
{
foreach (var device in devices)
foreach (DeviceInfo device in devices)
{
await Dispatcher.UIThread.InvokeAsync(() =>
{

View File

@@ -41,7 +41,7 @@ namespace Ryujinx.Ava.UI.ViewModels
private void LoadUpdates()
{
var updates = ApplicationLibrary.TitleUpdates.Items
IEnumerable<(TitleUpdateModel TitleUpdate, bool IsSelected)> updates = ApplicationLibrary.TitleUpdates.Items
.Where(it => it.TitleUpdate.TitleIdBase == ApplicationData.IdBase);
bool hasBundledContent = false;
@@ -64,11 +64,11 @@ namespace Ryujinx.Ava.UI.ViewModels
public void SortUpdates()
{
var sortedUpdates = TitleUpdates.OrderByDescending(update => update.Version);
IOrderedEnumerable<TitleUpdateModel> sortedUpdates = TitleUpdates.OrderByDescending(update => update.Version);
// NOTE(jpr): this works around a bug where calling Views.Clear also clears SelectedUpdate for
// some reason. so we save the item here and restore it after
var selected = SelectedUpdate;
object selected = SelectedUpdate;
Views.Clear();
Views.Add(new TitleUpdateViewModelNoUpdate());
@@ -96,18 +96,18 @@ namespace Ryujinx.Ava.UI.ViewModels
return false;
}
if (!ApplicationLibrary.TryGetTitleUpdatesFromFile(path, out var updates))
if (!ApplicationLibrary.TryGetTitleUpdatesFromFile(path, out List<TitleUpdateModel> updates))
{
return false;
}
var updatesForThisGame = updates.Where(it => it.TitleIdBase == ApplicationData.Id).ToList();
List<TitleUpdateModel> updatesForThisGame = updates.Where(it => it.TitleIdBase == ApplicationData.Id).ToList();
if (updatesForThisGame.Count == 0)
{
return false;
}
foreach (var update in updatesForThisGame)
foreach (TitleUpdateModel update in updatesForThisGame)
{
if (!TitleUpdates.Contains(update))
{
@@ -142,7 +142,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public async Task Add()
{
var result = await _storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
IReadOnlyList<IStorageFile> result = await _storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{
AllowMultiple = true,
FileTypeFilter = new List<FilePickerFileType>
@@ -156,10 +156,10 @@ namespace Ryujinx.Ava.UI.ViewModels
},
});
var totalUpdatesAdded = 0;
foreach (var file in result)
int totalUpdatesAdded = 0;
foreach (IStorageFile file in result)
{
if (!AddUpdate(file.Path.LocalPath, out var newUpdatesAdded))
if (!AddUpdate(file.Path.LocalPath, out int newUpdatesAdded))
{
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUpdateAddUpdateErrorMessage]);
}
@@ -175,13 +175,13 @@ namespace Ryujinx.Ava.UI.ViewModels
public void Save()
{
var updates = TitleUpdates.Select(it => (it, it == SelectedUpdate as TitleUpdateModel)).ToList();
List<(TitleUpdateModel it, bool)> updates = TitleUpdates.Select(it => (it, it == SelectedUpdate as TitleUpdateModel)).ToList();
ApplicationLibrary.SaveTitleUpdatesForGame(ApplicationData, updates);
}
private Task ShowNewUpdatesAddedDialog(int numAdded)
{
var msg = string.Format(LocaleManager.Instance[LocaleKeys.UpdateWindowUpdateAddedMessage], numAdded);
string msg = string.Format(LocaleManager.Instance[LocaleKeys.UpdateWindowUpdateAddedMessage], numAdded);
return Dispatcher.UIThread.InvokeAsync(async () =>
await ContentDialogHelper.ShowTextDialog(
LocaleManager.Instance[LocaleKeys.DialogConfirmationTitle],

View File

@@ -68,7 +68,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{
Images.Clear();
foreach (var image in _avatarStore)
foreach (KeyValuePair<string, byte[]> image in _avatarStore)
{
Images.Add(new ProfileImageModel(image.Key, image.Value));
}
@@ -76,7 +76,7 @@ namespace Ryujinx.Ava.UI.ViewModels
private void ChangeImageBackground()
{
foreach (var image in Images)
foreach (ProfileImageModel image in Images)
{
image.BackgroundColor = new SolidColorBrush(BackgroundColor);
}
@@ -104,7 +104,7 @@ namespace Ryujinx.Ava.UI.ViewModels
// TODO: Parse DatabaseInfo.bin and table.bin files for more accuracy.
if (item.Type == DirectoryEntryType.File && item.FullPath.Contains("chara") && item.FullPath.Contains("szs"))
{
using var file = new UniqueRef<IFile>();
using UniqueRef<IFile> file = new UniqueRef<IFile>();
romfs.OpenFile(ref file.Ref, ("/" + item.FullPath).ToU8Span(), OpenMode.Read).ThrowIfFailure();

View File

@@ -41,7 +41,7 @@ namespace Ryujinx.Ava.UI.ViewModels
Saves.AsObservableChangeSet()
.Filter(Filter)
.Sort(GetComparer())
.Bind(out var view).AsObservableList();
.Bind(out ReadOnlyObservableCollection<SaveModel> view).AsObservableList();
#pragma warning disable MVVMTK0034
_views.Clear();

View File

@@ -9,6 +9,7 @@ using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.Utilities.AppLibrary;
using Ryujinx.Common.Utilities;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using static Ryujinx.Common.Utilities.XCIFileTrimmer;
@@ -54,10 +55,10 @@ namespace Ryujinx.Ava.UI.ViewModels
private void LoadXCIApplications()
{
var apps = ApplicationLibrary.Applications.Items
IEnumerable<ApplicationData> apps = ApplicationLibrary.Applications.Items
.Where(app => app.FileExtension == _FileExtXCI);
foreach (var xciApp in apps)
foreach (ApplicationData xciApp in apps)
AddOrUpdateXCITrimmerFile(CreateXCITrimmerFile(xciApp.Path));
ApplicationsChanged();
@@ -67,7 +68,7 @@ namespace Ryujinx.Ava.UI.ViewModels
string path,
OperationOutcome operationOutcome = OperationOutcome.Undetermined)
{
var xciApp = ApplicationLibrary.Applications.Items.First(app => app.FileExtension == _FileExtXCI && app.Path == path);
ApplicationData xciApp = ApplicationLibrary.Applications.Items.First(app => app.FileExtension == _FileExtXCI && app.Path == path);
return XCITrimmerFileModel.FromApplicationData(xciApp, _logger) with { ProcessingOutcome = operationOutcome };
}
@@ -156,17 +157,17 @@ namespace Ryujinx.Ava.UI.ViewModels
_processingMode = processingMode;
Processing = true;
var cancellationToken = _cancellationTokenSource.Token;
CancellationToken cancellationToken = _cancellationTokenSource.Token;
Thread XCIFileTrimThread = new(() =>
{
var toProcess = Sort(SelectedXCIFiles
List<XCITrimmerFileModel> toProcess = Sort(SelectedXCIFiles
.Where(xci =>
(processingMode == ProcessingMode.Untrimming && xci.Untrimmable) ||
(processingMode == ProcessingMode.Trimming && xci.Trimmable)
)).ToList();
var viewsSaved = DisplayedXCIFiles.ToList();
List<XCITrimmerFileModel> viewsSaved = DisplayedXCIFiles.ToList();
Dispatcher.UIThread.Post(() =>
{
@@ -177,19 +178,19 @@ namespace Ryujinx.Ava.UI.ViewModels
try
{
foreach (var xciApp in toProcess)
foreach (XCITrimmerFileModel xciApp in toProcess)
{
if (cancellationToken.IsCancellationRequested)
break;
var trimmer = new XCIFileTrimmer(xciApp.Path, _logger);
XCIFileTrimmer trimmer = new XCIFileTrimmer(xciApp.Path, _logger);
Dispatcher.UIThread.Post(() =>
{
ProcessingApplication = xciApp;
});
var outcome = OperationOutcome.Undetermined;
OperationOutcome outcome = OperationOutcome.Undetermined;
try
{
@@ -347,7 +348,7 @@ namespace Ryujinx.Ava.UI.ViewModels
Sort(AllXCIFiles)
.AsObservableChangeSet()
.Filter(Filter)
.Bind(out var view).AsObservableList();
.Bind(out ReadOnlyObservableCollection<XCITrimmerFileModel> view).AsObservableList();
_displayedXCIFiles.Clear();
_displayedXCIFiles.AddRange(view);

View File

@@ -12,6 +12,7 @@ using Ryujinx.Common.Configuration.Hid.Controller;
using Ryujinx.Input;
using Ryujinx.Input.Assigner;
using System.Linq;
using Button = Ryujinx.Input.Button;
using StickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
namespace Ryujinx.Ava.UI.Views.Input
@@ -104,7 +105,7 @@ namespace Ryujinx.Ava.UI.Views.Input
PointerPressed += MouseClick;
var viewModel = (DataContext as ControllerInputViewModel);
ControllerInputViewModel viewModel = (DataContext as ControllerInputViewModel);
IKeyboard keyboard =
(IKeyboard)viewModel.ParentModel.AvaloniaKeyboardDriver
@@ -115,7 +116,7 @@ namespace Ryujinx.Ava.UI.Views.Input
{
if (e.ButtonValue.HasValue)
{
var buttonValue = e.ButtonValue.Value;
Button buttonValue = e.ButtonValue.Value;
viewModel.ParentModel.IsModified = true;
switch (button.Name)
@@ -223,7 +224,7 @@ namespace Ryujinx.Ava.UI.Views.Input
{
IButtonAssigner assigner;
var controllerInputViewModel = DataContext as ControllerInputViewModel;
ControllerInputViewModel controllerInputViewModel = DataContext as ControllerInputViewModel;
assigner = new GamepadButtonAssigner(
controllerInputViewModel.ParentModel.SelectedGamepad,
@@ -251,7 +252,8 @@ namespace Ryujinx.Ava.UI.Views.Input
if (!args.NewColor.HasValue) return;
if (DataContext is not ControllerInputViewModel cVm) return;
if (!cVm.Config.EnableLedChanging) return;
if (cVm.Config.TurnOffLed) return;
cVm.ParentModel.SelectedGamepad.SetLed(args.NewColor.Value.ToUInt32());
}
@@ -259,7 +261,8 @@ namespace Ryujinx.Ava.UI.Views.Input
{
if (DataContext is not ControllerInputViewModel cVm) return;
if (!cVm.Config.EnableLedChanging) return;
if (cVm.Config.TurnOffLed) return;
cVm.ParentModel.SelectedGamepad.SetLed(cVm.Config.LedColor.ToUInt32());
}
}

View File

@@ -37,7 +37,7 @@ namespace Ryujinx.Ava.UI.Views.Input
{
_dialogOpen = true;
var result = await ContentDialogHelper.CreateDeniableConfirmationDialog(
UserResult result = await ContentDialogHelper.CreateDeniableConfirmationDialog(
LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmMessage],
LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmSubMessage],
LocaleManager.Instance[LocaleKeys.InputDialogYes],

View File

@@ -8,6 +8,7 @@ using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels.Input;
using Ryujinx.Input;
using Ryujinx.Input.Assigner;
using Button = Ryujinx.Input.Button;
using Key = Ryujinx.Common.Configuration.Hid.Key;
namespace Ryujinx.Ava.UI.Views.Input
@@ -71,7 +72,7 @@ namespace Ryujinx.Ava.UI.Views.Input
{
if (e.ButtonValue.HasValue)
{
var buttonValue = e.ButtonValue.Value;
Button buttonValue = e.ButtonValue.Value;
viewModel.ParentModel.IsModified = true;
switch (button.Name)

View File

@@ -1,6 +1,7 @@
using Avalonia.Controls;
using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Models.Input;
using Ryujinx.Ava.UI.ViewModels.Input;
using System.Threading.Tasks;
@@ -17,7 +18,7 @@ namespace Ryujinx.Ava.UI.Views.Input
public MotionInputView(ControllerInputViewModel viewModel)
{
var config = viewModel.Config;
GamepadInputConfig config = viewModel.Config;
_viewModel = new MotionInputViewModel
{
@@ -49,7 +50,7 @@ namespace Ryujinx.Ava.UI.Views.Input
};
contentDialog.PrimaryButtonClick += (sender, args) =>
{
var config = viewModel.Config;
GamepadInputConfig config = viewModel.Config;
config.Slot = content._viewModel.Slot;
config.Sensitivity = content._viewModel.Sensitivity;
config.GyroDeadzone = content._viewModel.GyroDeadzone;

View File

@@ -1,6 +1,7 @@
using Avalonia.Controls;
using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Models.Input;
using Ryujinx.Ava.UI.ViewModels.Input;
using System.Threading.Tasks;
@@ -17,7 +18,7 @@ namespace Ryujinx.Ava.UI.Views.Input
public RumbleInputView(ControllerInputViewModel viewModel)
{
var config = viewModel.Config;
GamepadInputConfig config = viewModel.Config;
_viewModel = new RumbleInputViewModel
{
@@ -45,7 +46,7 @@ namespace Ryujinx.Ava.UI.Views.Input
contentDialog.PrimaryButtonClick += (sender, args) =>
{
var config = viewModel.Config;
GamepadInputConfig config = viewModel.Config;
config.StrongRumble = content._viewModel.StrongRumble;
config.WeakRumble = content._viewModel.WeakRumble;
};

View File

@@ -4,11 +4,14 @@ using Avalonia.Layout;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.Input;
using Gommon;
using LibHac.Common;
using LibHac.Ns;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.UI.Windows;
using Ryujinx.Ava.Utilities;
using Ryujinx.Ava.Utilities.AppLibrary;
using Ryujinx.Ava.Utilities.Compat;
using Ryujinx.Ava.Utilities.Configuration;
using Ryujinx.Common;
@@ -142,7 +145,7 @@ namespace Ryujinx.Ava.UI.Views.Main
public async Task OpenMiiApplet()
{
if (!MiiApplet.CanStart(out var appData, out var nacpData))
if (!MiiApplet.CanStart(out ApplicationData appData, out BlitStruct<ApplicationControlProperty> nacpData))
return;
await ViewModel.LoadApplication(appData, ViewModel.IsFullScreen || ViewModel.StartGamesInFullscreen, nacpData);

View File

@@ -8,6 +8,7 @@ using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Input;
using Ryujinx.Input.Assigner;
using Button = Ryujinx.Input.Button;
using Key = Ryujinx.Common.Configuration.Hid.Key;
namespace Ryujinx.Ava.UI.Views.Settings
@@ -70,15 +71,15 @@ namespace Ryujinx.Ava.UI.Views.Settings
PointerPressed += MouseClick;
var keyboard = (IKeyboard)_avaloniaKeyboardDriver.GetGamepad("0");
IKeyboard keyboard = (IKeyboard)_avaloniaKeyboardDriver.GetGamepad("0");
IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard);
_currentAssigner.ButtonAssigned += (sender, e) =>
{
if (e.ButtonValue.HasValue)
{
var viewModel = (DataContext) as SettingsViewModel;
var buttonValue = e.ButtonValue.Value;
SettingsViewModel viewModel = (DataContext) as SettingsViewModel;
Button buttonValue = e.ButtonValue.Value;
switch (button.Name)
{

View File

@@ -39,7 +39,7 @@ namespace Ryujinx.Ava.UI.Views.User
switch (arg.NavigationMode)
{
case NavigationMode.New:
var (parent, profile, isNewUser) = ((NavigationDialogHost parent, UserProfile profile, bool isNewUser))arg.Parameter;
(NavigationDialogHost parent, UserProfile profile, bool isNewUser) = ((NavigationDialogHost parent, UserProfile profile, bool isNewUser))arg.Parameter;
_isNewUser = isNewUser;
_profile = profile;
TempProfile = new TempProfile(_profile);

View File

@@ -66,11 +66,11 @@ namespace Ryujinx.Ava.UI.Views.User
{
if (ViewModel.SelectedImage != null)
{
using var streamJpg = new MemoryStream();
using var bitmap = SKBitmap.Decode(ViewModel.SelectedImage);
using var newBitmap = new SKBitmap(bitmap.Width, bitmap.Height);
using MemoryStream streamJpg = new MemoryStream();
using SKBitmap bitmap = SKBitmap.Decode(ViewModel.SelectedImage);
using SKBitmap newBitmap = new SKBitmap(bitmap.Width, bitmap.Height);
using (var canvas = new SKCanvas(newBitmap))
using (SKCanvas canvas = new SKCanvas(newBitmap))
{
canvas.Clear(new SKColor(
ViewModel.BackgroundColor.R,
@@ -80,8 +80,8 @@ namespace Ryujinx.Ava.UI.Views.User
canvas.DrawBitmap(bitmap, 0, 0);
}
using (var image = SKImage.FromBitmap(newBitmap))
using (var dataJpeg = image.Encode(SKEncodedImageFormat.Jpeg, 100))
using (SKImage image = SKImage.FromBitmap(newBitmap))
using (SKData dataJpeg = image.Encode(SKEncodedImageFormat.Jpeg, 100))
{
dataJpeg.SaveTo(streamJpg);
}

View File

@@ -63,7 +63,7 @@ namespace Ryujinx.Ava.UI.Views.User
private async void Import_OnClick(object sender, RoutedEventArgs e)
{
var result = await ((Window)this.GetVisualRoot()!).StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
IReadOnlyList<IStorageFile> result = await ((Window)this.GetVisualRoot()!).StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{
AllowMultiple = false,
FileTypeFilter = new List<FilePickerFileType>
@@ -99,16 +99,16 @@ namespace Ryujinx.Ava.UI.Views.User
private static byte[] ProcessProfileImage(byte[] buffer)
{
using var bitmap = SKBitmap.Decode(buffer);
using SKBitmap bitmap = SKBitmap.Decode(buffer);
var resizedBitmap = bitmap.Resize(new SKImageInfo(256, 256), SKFilterQuality.High);
SKBitmap resizedBitmap = bitmap.Resize(new SKImageInfo(256, 256), SKFilterQuality.High);
using var streamJpg = new MemoryStream();
using MemoryStream streamJpg = new MemoryStream();
if (resizedBitmap != null)
{
using var image = SKImage.FromBitmap(resizedBitmap);
using var dataJpeg = image.Encode(SKEncodedImageFormat.Jpeg, 100);
using SKImage image = SKImage.FromBitmap(resizedBitmap);
using SKData dataJpeg = image.Encode(SKEncodedImageFormat.Jpeg, 100);
dataJpeg.SaveTo(streamJpg);
}

View File

@@ -27,7 +27,7 @@ namespace Ryujinx.Ava.UI.Views.User
switch (arg.NavigationMode)
{
case NavigationMode.New:
var parent = (NavigationDialogHost)arg.Parameter;
NavigationDialogHost parent = (NavigationDialogHost)arg.Parameter;
_parent = parent;

View File

@@ -48,7 +48,7 @@ namespace Ryujinx.Ava.UI.Views.User
switch (arg.NavigationMode)
{
case NavigationMode.New:
var (parent, accountManager, client, virtualFileSystem) = ((NavigationDialogHost parent, AccountManager accountManager, HorizonClient client, VirtualFileSystem virtualFileSystem))arg.Parameter;
(NavigationDialogHost parent, AccountManager accountManager, HorizonClient client, VirtualFileSystem virtualFileSystem) = ((NavigationDialogHost parent, AccountManager accountManager, HorizonClient client, VirtualFileSystem virtualFileSystem))arg.Parameter;
_accountManager = accountManager;
_horizonClient = client;
_virtualFileSystem = virtualFileSystem;
@@ -67,15 +67,15 @@ namespace Ryujinx.Ava.UI.Views.User
public void LoadSaves()
{
ViewModel.Saves.Clear();
var saves = new ObservableCollection<SaveModel>();
var saveDataFilter = SaveDataFilter.Make(
ObservableCollection<SaveModel> saves = new ObservableCollection<SaveModel>();
SaveDataFilter saveDataFilter = SaveDataFilter.Make(
programId: default,
saveType: SaveDataType.Account,
new UserId((ulong)_accountManager.LastOpenedUser.UserId.High, (ulong)_accountManager.LastOpenedUser.UserId.Low),
saveDataId: default,
index: default);
using var saveDataIterator = new UniqueRef<SaveDataIterator>();
using UniqueRef<SaveDataIterator> saveDataIterator = new UniqueRef<SaveDataIterator>();
_horizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref, SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure();
@@ -92,10 +92,10 @@ namespace Ryujinx.Ava.UI.Views.User
for (int i = 0; i < readCount; i++)
{
var save = saveDataInfo[i];
SaveDataInfo save = saveDataInfo[i];
if (save.ProgramId.Value != 0)
{
var saveModel = new SaveModel(save);
SaveModel saveModel = new SaveModel(save);
saves.Add(saveModel);
}
}
@@ -130,7 +130,7 @@ namespace Ryujinx.Ava.UI.Views.User
{
if (button.DataContext is SaveModel saveModel)
{
var result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DeleteUserSave],
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DeleteUserSave],
LocaleManager.Instance[LocaleKeys.IrreversibleActionNote],
LocaleManager.Instance[LocaleKeys.InputDialogYes],
LocaleManager.Instance[LocaleKeys.InputDialogNo],

View File

@@ -6,6 +6,7 @@ using Ryujinx.Ava.Utilities.AppLibrary;
using Ryujinx.Ava.Utilities.Configuration;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
@@ -58,7 +59,7 @@ namespace Ryujinx.Ava.UI.Windows
int cheatAdded = 0;
var mods = new ModLoader.ModCache();
ModLoader.ModCache mods = new ModLoader.ModCache();
ModLoader.QueryContentsDir(mods, new DirectoryInfo(Path.Combine(modsBasePath, "contents")), titleIdValue);
@@ -67,7 +68,7 @@ namespace Ryujinx.Ava.UI.Windows
CheatNode currentGroup = null;
foreach (var cheat in mods.Cheats)
foreach (ModLoader.Cheat cheat in mods.Cheats)
{
if (cheat.Path.FullName != currentCheatFile)
{
@@ -80,7 +81,7 @@ namespace Ryujinx.Ava.UI.Windows
LoadedCheats.Add(currentGroup);
}
var model = new CheatNode(cheat.Name, buildId, string.Empty, false, enabled.Contains($"{buildId}-{cheat.Name}"));
CheatNode model = new CheatNode(cheat.Name, buildId, string.Empty, false, enabled.Contains($"{buildId}-{cheat.Name}"));
currentGroup?.SubNodes.Add(model);
cheatAdded++;
@@ -101,7 +102,7 @@ namespace Ryujinx.Ava.UI.Windows
if (NoCheatsFound)
return;
var enabledCheats = LoadedCheats.SelectMany(it => it.SubNodes)
IEnumerable<string> enabledCheats = LoadedCheats.SelectMany(it => it.SubNodes)
.Where(it => it.IsEnabled)
.Select(it => it.BuildIdKey);

View File

@@ -79,7 +79,7 @@ namespace Ryujinx.Ava.UI.Windows
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (var content in e.AddedItems)
foreach (object content in e.AddedItems)
{
if (content is DownloadableContentModel model)
{
@@ -87,7 +87,7 @@ namespace Ryujinx.Ava.UI.Windows
}
}
foreach (var content in e.RemovedItems)
foreach (object content in e.RemovedItems)
{
if (content is DownloadableContentModel model)
{

View File

@@ -29,7 +29,7 @@ namespace Ryujinx.Ava.UI.Windows
public static SKColor GetFilteredColor(SKBitmap image)
{
var color = GetColor(image);
SKColor color = GetColor(image);
// We don't want colors that are too dark.
@@ -49,10 +49,10 @@ namespace Ryujinx.Ava.UI.Windows
public static SKColor GetColor(SKBitmap image)
{
var colors = new PaletteColor[TotalColors];
var dominantColorBin = new Dictionary<int, int>();
PaletteColor[] colors = new PaletteColor[TotalColors];
Dictionary<int, int> dominantColorBin = new Dictionary<int, int>();
var buffer = GetBuffer(image);
SKColor[] buffer = GetBuffer(image);
int i = 0;
int maxHitCount = 0;
@@ -70,7 +70,7 @@ namespace Ryujinx.Ava.UI.Windows
byte cg = pixel.Green;
byte cb = pixel.Blue;
var qck = GetQuantizedColorKey(cr, cg, cb);
int qck = GetQuantizedColorKey(cr, cg, cb);
if (dominantColorBin.TryGetValue(qck, out int hitCount))
{
@@ -95,7 +95,7 @@ namespace Ryujinx.Ava.UI.Windows
for (i = 0; i < TotalColors; i++)
{
var score = GetColorScore(dominantColorBin, maxHitCount, colors[i]);
int score = GetColorScore(dominantColorBin, maxHitCount, colors[i]);
if (highScore < score)
{
@@ -109,7 +109,7 @@ namespace Ryujinx.Ava.UI.Windows
public static SKColor[] GetBuffer(SKBitmap image)
{
var pixels = new SKColor[image.Width * image.Height];
SKColor[] pixels = new SKColor[image.Width * image.Height];
for (int y = 0; y < image.Height; y++)
{
@@ -124,17 +124,17 @@ namespace Ryujinx.Ava.UI.Windows
private static int GetColorScore(Dictionary<int, int> dominantColorBin, int maxHitCount, PaletteColor color)
{
var hitCount = dominantColorBin[color.Qck];
var balancedHitCount = BalanceHitCount(hitCount, maxHitCount);
var quantSat = (GetColorSaturation(color) >> SatQuantShift) << SatQuantShift;
var value = GetColorValue(color);
int hitCount = dominantColorBin[color.Qck];
int balancedHitCount = BalanceHitCount(hitCount, maxHitCount);
int quantSat = (GetColorSaturation(color) >> SatQuantShift) << SatQuantShift;
int value = GetColorValue(color);
// If the color is rarely used on the image,
// then chances are that there's a better candidate, even if the saturation value
// is high. By multiplying the saturation value with a weight, we can lower
// it if the color is almost never used (hit count is low).
var satWeighted = quantSat;
var satWeight = balancedHitCount << 5;
int satWeighted = quantSat;
int satWeight = balancedHitCount << 5;
if (satWeight < 0x100)
{
satWeighted = (satWeighted * satWeight) >> 8;
@@ -142,7 +142,7 @@ namespace Ryujinx.Ava.UI.Windows
// Compute score from saturation and dominance of the color.
// We prefer more vivid colors over dominant ones, so give more weight to the saturation.
var score = ((satWeighted << 1) + balancedHitCount) * value;
int score = ((satWeighted << 1) + balancedHitCount) * value;
return score;
}

View File

@@ -8,6 +8,7 @@ using DynamicData;
using FluentAvalonia.UI.Controls;
using FluentAvalonia.UI.Windowing;
using Gommon;
using LibHac.Ns;
using LibHac.Tools.FsSystem;
using Ryujinx.Ava.Common;
using Ryujinx.Ava.Common.Locale;
@@ -171,11 +172,11 @@ namespace Ryujinx.Ava.UI.Windows
{
Dispatcher.UIThread.Post(() =>
{
var ldnGameDataArray = e.LdnData.ToList();
List<LdnGameData> ldnGameDataArray = e.LdnData.ToList();
ViewModel.LdnData.Clear();
foreach (var application in ViewModel.Applications.Where(it => it.HasControlHolder))
foreach (ApplicationData application in ViewModel.Applications.Where(it => it.HasControlHolder))
{
ref var controlHolder = ref application.ControlHolder.Value;
ref ApplicationControlProperty controlHolder = ref application.ControlHolder.Value;
ViewModel.LdnData[application.IdString] =
LdnGameData.GetArrayForApp(
@@ -192,7 +193,7 @@ namespace Ryujinx.Ava.UI.Windows
private void UpdateApplicationWithLdnData(ApplicationData application)
{
if (application.HasControlHolder && ViewModel.LdnData.TryGetValue(application.IdString, out var ldnGameDatas))
if (application.HasControlHolder && ViewModel.LdnData.TryGetValue(application.IdString, out LdnGameData.Array ldnGameDatas))
{
application.PlayerCount = ldnGameDatas.PlayerCount;
application.GameCount = ldnGameDatas.GameCount;
@@ -690,12 +691,12 @@ namespace Ryujinx.Ava.UI.Windows
ApplicationLibrary.LoadApplications(ConfigurationState.Instance.UI.GameDirs);
var autoloadDirs = ConfigurationState.Instance.UI.AutoloadDirs.Value;
List<string> autoloadDirs = ConfigurationState.Instance.UI.AutoloadDirs.Value;
autoloadDirs.ForEach(dir => Logger.Info?.Print(LogClass.Application, $"Auto loading DLC & updates from: {dir}"));
if (autoloadDirs.Count > 0)
{
var updatesLoaded = ApplicationLibrary.AutoLoadTitleUpdates(autoloadDirs, out int updatesRemoved);
var dlcLoaded = ApplicationLibrary.AutoLoadDownloadableContents(autoloadDirs, out int dlcRemoved);
int updatesLoaded = ApplicationLibrary.AutoLoadTitleUpdates(autoloadDirs, out int updatesRemoved);
int dlcLoaded = ApplicationLibrary.AutoLoadDownloadableContents(autoloadDirs, out int dlcRemoved);
ShowNewContentAddedDialog(dlcLoaded, dlcRemoved, updatesLoaded, updatesRemoved);
}

View File

@@ -66,7 +66,7 @@ namespace Ryujinx.Ava.UI.Windows
{
if (button.DataContext is ModModel model)
{
var result = await ContentDialogHelper.CreateConfirmationDialog(
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
LocaleManager.Instance[LocaleKeys.DialogWarning],
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogModManagerDeletionWarningMessage, model.Name),
LocaleManager.Instance[LocaleKeys.InputDialogYes],
@@ -83,7 +83,7 @@ namespace Ryujinx.Ava.UI.Windows
private async void DeleteAll(object sender, RoutedEventArgs e)
{
var result = await ContentDialogHelper.CreateConfirmationDialog(
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
LocaleManager.Instance[LocaleKeys.DialogWarning],
LocaleManager.Instance[LocaleKeys.DialogModManagerDeletionAllWarningMessage],
LocaleManager.Instance[LocaleKeys.InputDialogYes],
@@ -109,11 +109,11 @@ namespace Ryujinx.Ava.UI.Windows
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (var content in e.AddedItems)
foreach (object content in e.AddedItems)
{
if (content is ModModel model)
{
var index = ViewModel.Mods.IndexOf(model);
int index = ViewModel.Mods.IndexOf(model);
if (index != -1)
{
@@ -122,11 +122,11 @@ namespace Ryujinx.Ava.UI.Windows
}
}
foreach (var content in e.RemovedItems)
foreach (object content in e.RemovedItems)
{
if (content is ModModel model)
{
var index = ViewModel.Mods.IndexOf(model);
int index = ViewModel.Mods.IndexOf(model);
if (index != -1)
{

View File

@@ -81,7 +81,7 @@ namespace Ryujinx.Ava.UI.Windows
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (var content in e.AddedItems)
foreach (object content in e.AddedItems)
{
if (content is XCITrimmerFileModel applicationData)
{
@@ -89,7 +89,7 @@ namespace Ryujinx.Ava.UI.Windows
}
}
foreach (var content in e.RemovedItems)
foreach (object content in e.RemovedItems)
{
if (content is XCITrimmerFileModel applicationData)
{

View File

@@ -71,7 +71,7 @@ namespace Ryujinx.Ava
}
else if (OperatingSystem.IsLinux())
{
var arch = RuntimeInformation.OSArchitecture == Architecture.Arm64 ? "arm64" : "x64";
string arch = RuntimeInformation.OSArchitecture == Architecture.Arm64 ? "arm64" : "x64";
_platformExt = $"linux_{arch}.tar.gz";
}
@@ -96,10 +96,10 @@ namespace Ryujinx.Ava
using HttpClient jsonClient = ConstructHttpClient();
string fetchedJson = await jsonClient.GetStringAsync(LatestReleaseUrl);
var fetched = JsonHelper.Deserialize(fetchedJson, _serializerContext.GithubReleasesJsonResponse);
GithubReleasesJsonResponse fetched = JsonHelper.Deserialize(fetchedJson, _serializerContext.GithubReleasesJsonResponse);
_buildVer = fetched.TagName;
foreach (var asset in fetched.Assets)
foreach (GithubReleaseAssetJsonResponse asset in fetched.Assets)
{
if (asset.Name.StartsWith("ryujinx") && asset.Name.EndsWith(_platformExt))
{
@@ -711,15 +711,15 @@ namespace Ryujinx.Ava
// NOTE: This method should always reflect the latest build layout.
private static IEnumerable<string> EnumerateFilesToDelete()
{
var files = Directory.EnumerateFiles(_homeDir); // All files directly in base dir.
IEnumerable<string> files = Directory.EnumerateFiles(_homeDir); // All files directly in base dir.
// Determine and exclude user files only when the updater is running, not when cleaning old files
if (_running && !OperatingSystem.IsMacOS())
{
// Compare the loose files in base directory against the loose files from the incoming update, and store foreign ones in a user list.
var oldFiles = Directory.EnumerateFiles(_homeDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName);
var newFiles = Directory.EnumerateFiles(_updatePublishDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName);
var userFiles = oldFiles.Except(newFiles).Select(filename => Path.Combine(_homeDir, filename));
IEnumerable<string> oldFiles = Directory.EnumerateFiles(_homeDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName);
IEnumerable<string> newFiles = Directory.EnumerateFiles(_updatePublishDir, "*", SearchOption.TopDirectoryOnly).Select(Path.GetFileName);
IEnumerable<string> userFiles = oldFiles.Except(newFiles).Select(filename => Path.Combine(_homeDir, filename));
// Remove user files from the paths in files.
files = files.Except(userFiles);

View File

@@ -76,14 +76,14 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
}
else
{
var pfsTemp = new PartitionFileSystem();
PartitionFileSystem pfsTemp = new PartitionFileSystem();
pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure();
pfs = pfsTemp;
}
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
{
using var ncaFile = new UniqueRef<IFile>();
using UniqueRef<IFile> ncaFile = new UniqueRef<IFile>();
pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
@@ -158,7 +158,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
return string.Empty;
}
using var nsoFile = new UniqueRef<IFile>();
using UniqueRef<IFile> nsoFile = new UniqueRef<IFile>();
codeFs.OpenFile(ref nsoFile.Ref, $"/{MainExeFs}".ToU8Span(), OpenMode.Read).ThrowIfFailure();

View File

@@ -190,7 +190,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
/// <exception cref="HorizonResultException">An error occured while reading PFS data.</exception>
private List<ApplicationData> GetApplicationsFromPfs(IFileSystem pfs, string filePath)
{
var applications = new List<ApplicationData>();
List<ApplicationData> applications = new List<ApplicationData>();
string extension = Path.GetExtension(filePath).ToLower();
foreach ((ulong titleId, ContentMetaData content) in pfs.GetContentData(ContentMetaType.Application, _virtualFileSystem, _checkLevel))
@@ -245,7 +245,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
continue;
}
using var icon = new UniqueRef<IFile>();
using UniqueRef<IFile> icon = new UniqueRef<IFile>();
controlFs.OpenFile(ref icon.Ref, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
@@ -313,7 +313,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
case ".nsp":
case ".pfs0":
{
var pfs = new PartitionFileSystem();
PartitionFileSystem pfs = new PartitionFileSystem();
pfs.Initialize(file.AsStorage()).ThrowIfFailure();
ApplicationData result = GetApplicationFromNsp(pfs, applicationPath);
@@ -438,7 +438,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
return false;
}
foreach (var data in applications)
foreach (ApplicationData data in applications)
{
// Only load metadata for applications with an ID
if (data.Id != 0)
@@ -501,7 +501,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
{
using var ncaFile = new UniqueRef<IFile>();
using UniqueRef<IFile> ncaFile = new UniqueRef<IFile>();
pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
@@ -588,8 +588,8 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
nacpFile.Get.Read(out _, 0, LibHac.Common.SpanHelpers.AsByteSpan(ref controlData),
ReadOption.None).ThrowIfFailure();
var displayVersion = controlData.DisplayVersionString.ToString();
var update = new TitleUpdateModel(content.ApplicationId, content.Version.Version,
string displayVersion = controlData.DisplayVersionString.ToString();
TitleUpdateModel update = new TitleUpdateModel(content.ApplicationId, content.Version.Version,
displayVersion, filePath);
titleUpdates.Add(update);
@@ -685,11 +685,11 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
return;
}
var fileInfo = new FileInfo(app);
FileInfo fileInfo = new FileInfo(app);
try
{
var fullPath = fileInfo.ResolveLinkTarget(true)?.FullName ?? fileInfo.FullName;
string fullPath = fileInfo.ResolveLinkTarget(true)?.FullName ?? fileInfo.FullName;
applicationPaths.Add(fullPath);
numApplicationsFound++;
@@ -719,7 +719,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
{
_applications.Edit(it =>
{
foreach (var application in applications)
foreach (ApplicationData application in applications)
{
it.AddOrUpdate(application);
LoadDlcForApplication(application);
@@ -840,7 +840,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
try
{
// Remove any downloadable content which can no longer be located on disk
var dlcToRemove = _downloadableContents.Items
List<(DownloadableContentModel Dlc, bool IsEnabled)> dlcToRemove = _downloadableContents.Items
.Where(dlc => !File.Exists(dlc.Dlc.ContainerPath))
.ToList();
dlcToRemove.ForEach(dlc =>
@@ -882,11 +882,11 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
return newDlcLoaded;
}
var fileInfo = new FileInfo(app);
FileInfo fileInfo = new FileInfo(app);
try
{
var fullPath = fileInfo.ResolveLinkTarget(true)?.FullName ?? fileInfo.FullName;
string fullPath = fileInfo.ResolveLinkTarget(true)?.FullName ?? fileInfo.FullName;
dlcPaths.Add(fullPath);
}
@@ -904,7 +904,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
}
}
var appIdLookup = Applications.Items.Select(it => it.IdBase).ToHashSet();
HashSet<ulong> appIdLookup = Applications.Items.Select(it => it.IdBase).ToHashSet();
foreach (string dlcPath in dlcPaths)
{
@@ -913,9 +913,9 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
return newDlcLoaded;
}
if (TryGetDownloadableContentFromFile(dlcPath, out var foundDlcs))
if (TryGetDownloadableContentFromFile(dlcPath, out List<DownloadableContentModel> foundDlcs))
{
foreach (var dlc in foundDlcs.Where(it => appIdLookup.Contains(it.TitleIdBase)))
foreach (DownloadableContentModel dlc in foundDlcs.Where(it => appIdLookup.Contains(it.TitleIdBase)))
{
if (!_downloadableContents.Lookup(dlc).HasValue)
{
@@ -949,11 +949,11 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
try
{
var titleIdsToSave = new HashSet<ulong>();
var titleIdsToRefresh = new HashSet<ulong>();
HashSet<ulong> titleIdsToSave = new HashSet<ulong>();
HashSet<ulong> titleIdsToRefresh = new HashSet<ulong>();
// Remove any updates which can no longer be located on disk
var updatesToRemove = _titleUpdates.Items
List<(TitleUpdateModel TitleUpdate, bool IsSelected)> updatesToRemove = _titleUpdates.Items
.Where(it => !File.Exists(it.TitleUpdate.Path))
.ToList();
@@ -998,11 +998,11 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
return numUpdatesLoaded;
}
var fileInfo = new FileInfo(app);
FileInfo fileInfo = new FileInfo(app);
try
{
var fullPath = fileInfo.ResolveLinkTarget(true)?.FullName ?? fileInfo.FullName;
string fullPath = fileInfo.ResolveLinkTarget(true)?.FullName ?? fileInfo.FullName;
updatePaths.Add(fullPath);
}
@@ -1020,7 +1020,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
}
}
var appIdLookup = Applications.Items.Select(it => it.IdBase).ToHashSet();
HashSet<ulong> appIdLookup = Applications.Items.Select(it => it.IdBase).ToHashSet();
foreach (string updatePath in updatePaths)
{
@@ -1029,9 +1029,9 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
return numUpdatesLoaded;
}
if (TryGetTitleUpdatesFromFile(updatePath, out var foundUpdates))
if (TryGetTitleUpdatesFromFile(updatePath, out List<TitleUpdateModel> foundUpdates))
{
foreach (var update in foundUpdates.Where(it => appIdLookup.Contains(it.TitleIdBase)))
foreach (TitleUpdateModel update in foundUpdates.Where(it => appIdLookup.Contains(it.TitleIdBase)))
{
if (!_titleUpdates.Lookup(update).HasValue)
{
@@ -1063,12 +1063,12 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
private bool AddAndAutoSelectUpdate(TitleUpdateModel update)
{
if (update == null) return false;
var currentlySelected = TitleUpdates.Items.FirstOrOptional(it =>
DynamicData.Kernel.Optional<(TitleUpdateModel TitleUpdate, bool IsSelected)> currentlySelected = TitleUpdates.Items.FirstOrOptional(it =>
it.TitleUpdate.TitleIdBase == update.TitleIdBase && it.IsSelected);
var shouldSelect = !currentlySelected.HasValue ||
currentlySelected.Value.TitleUpdate.Version < update.Version;
bool shouldSelect = !currentlySelected.HasValue ||
currentlySelected.Value.TitleUpdate.Version < update.Version;
_titleUpdates.AddOrUpdate((update, shouldSelect));
@@ -1170,7 +1170,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
}
else
{
var pfsTemp = new PartitionFileSystem();
PartitionFileSystem pfsTemp = new PartitionFileSystem();
pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure();
pfs = pfsTemp;
@@ -1204,7 +1204,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
// Read the icon from the ControlFS and store it as a byte array
try
{
using var icon = new UniqueRef<IFile>();
using UniqueRef<IFile> icon = new UniqueRef<IFile>();
controlFs.OpenFile(ref icon.Ref, $"/icon_{desiredTitleLanguage}.dat".ToU8Span(), OpenMode.Read).ThrowIfFailure();
@@ -1222,7 +1222,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
continue;
}
using var icon = new UniqueRef<IFile>();
using UniqueRef<IFile> icon = new UniqueRef<IFile>();
controlFs.OpenFile(ref icon.Ref, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
@@ -1330,7 +1330,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
if (string.IsNullOrWhiteSpace(data.Name))
{
foreach (ref readonly var controlTitle in controlData.Title.ItemsRo)
foreach (ref readonly ApplicationControlProperty.ApplicationTitle controlTitle in controlData.Title.ItemsRo)
{
if (!controlTitle.NameString.IsEmpty())
{
@@ -1343,7 +1343,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
if (string.IsNullOrWhiteSpace(data.Developer))
{
foreach (ref readonly var controlTitle in controlData.Title.ItemsRo)
foreach (ref readonly ApplicationControlProperty.ApplicationTitle controlTitle in controlData.Title.ItemsRo)
{
if (!controlTitle.PublisherString.IsEmpty())
{
@@ -1419,16 +1419,16 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
{
_downloadableContents.Edit(it =>
{
var savedDlc =
List<(DownloadableContentModel, bool IsEnabled)> savedDlc =
DownloadableContentsHelper.LoadDownloadableContentsJson(_virtualFileSystem, application.IdBase);
it.AddOrUpdate(savedDlc);
if (TryGetDownloadableContentFromFile(application.Path, out var bundledDlc))
if (TryGetDownloadableContentFromFile(application.Path, out List<DownloadableContentModel> bundledDlc))
{
var savedDlcLookup = savedDlc.Select(dlc => dlc.Item1).ToHashSet();
HashSet<DownloadableContentModel> savedDlcLookup = savedDlc.Select(dlc => dlc.Item1).ToHashSet();
bool addedNewDlc = false;
foreach (var dlc in bundledDlc)
foreach (DownloadableContentModel dlc in bundledDlc)
{
if (!savedDlcLookup.Contains(dlc))
{
@@ -1439,7 +1439,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
if (addedNewDlc)
{
var gameDlcs = it.Items.Where(dlc => dlc.Dlc.TitleIdBase == application.IdBase).ToList();
List<(DownloadableContentModel Dlc, bool IsEnabled)> gameDlcs = it.Items.Where(dlc => dlc.Dlc.TitleIdBase == application.IdBase).ToList();
DownloadableContentsHelper.SaveDownloadableContentsJson(application.IdBase,
gameDlcs);
}
@@ -1451,22 +1451,22 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
// file itself
private bool LoadTitleUpdatesForApplication(ApplicationData application)
{
var modifiedVersion = false;
bool modifiedVersion = false;
_titleUpdates.Edit(it =>
{
var savedUpdates =
List<(TitleUpdateModel Update, bool IsSelected)> savedUpdates =
TitleUpdatesHelper.LoadTitleUpdatesJson(_virtualFileSystem, application.IdBase);
it.AddOrUpdate(savedUpdates);
var selectedUpdate = savedUpdates.FirstOrOptional(update => update.IsSelected);
DynamicData.Kernel.Optional<(TitleUpdateModel Update, bool IsSelected)> selectedUpdate = savedUpdates.FirstOrOptional(update => update.IsSelected);
if (TryGetTitleUpdatesFromFile(application.Path, out var bundledUpdates))
if (TryGetTitleUpdatesFromFile(application.Path, out List<TitleUpdateModel> bundledUpdates))
{
var savedUpdateLookup = savedUpdates.Select(update => update.Update).ToHashSet();
HashSet<TitleUpdateModel> savedUpdateLookup = savedUpdates.Select(update => update.Update).ToHashSet();
bool updatesChanged = false;
foreach (var update in bundledUpdates.OrderByDescending(bundled => bundled.Version))
foreach (TitleUpdateModel update in bundledUpdates.OrderByDescending(bundled => bundled.Version))
{
if (!savedUpdateLookup.Contains(update))
{
@@ -1488,7 +1488,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
if (updatesChanged)
{
var gameUpdates = it.Items.Where(update => update.TitleUpdate.TitleIdBase == application.IdBase).ToList();
List<(TitleUpdateModel TitleUpdate, bool IsSelected)> gameUpdates = it.Items.Where(update => update.TitleUpdate.TitleIdBase == application.IdBase).ToList();
TitleUpdatesHelper.SaveTitleUpdatesJson(application.IdBase, gameUpdates);
}
}
@@ -1500,14 +1500,14 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
// Save the _currently tracked_ DLC state for the game
private void SaveDownloadableContentsForGame(ulong titleIdBase)
{
var dlcs = DownloadableContents.Items.Where(dlc => dlc.Dlc.TitleIdBase == titleIdBase).ToList();
List<(DownloadableContentModel Dlc, bool IsEnabled)> dlcs = DownloadableContents.Items.Where(dlc => dlc.Dlc.TitleIdBase == titleIdBase).ToList();
DownloadableContentsHelper.SaveDownloadableContentsJson(titleIdBase, dlcs);
}
// Save the _currently tracked_ update state for the game
private void SaveTitleUpdatesForGame(ulong titleIdBase)
{
var updates = TitleUpdates.Items.Where(update => update.TitleUpdate.TitleIdBase == titleIdBase).ToList();
List<(TitleUpdateModel TitleUpdate, bool IsSelected)> updates = TitleUpdates.Items.Where(update => update.TitleUpdate.TitleIdBase == titleIdBase).ToList();
TitleUpdatesHelper.SaveTitleUpdatesJson(titleIdBase, updates);
}
@@ -1515,7 +1515,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
// of its state
private void RefreshApplicationInfo(ulong appIdBase)
{
var application = _applications.Lookup(appIdBase);
DynamicData.Kernel.Optional<ApplicationData> application = _applications.Lookup(appIdBase);
if (!application.HasValue)
return;
@@ -1523,7 +1523,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
if (!TryGetApplicationsFromFile(application.Value.Path, out List<ApplicationData> newApplications))
return;
var newApplication = newApplications.First(it => it.IdBase == appIdBase);
ApplicationData newApplication = newApplications.First(it => it.IdBase == appIdBase);
_applications.AddOrUpdate(newApplication);
}
}

View File

@@ -88,7 +88,7 @@ namespace Ryujinx.Ava.Utilities.Compat
_ => null
};
if (DateTime.TryParse(ColStr(row[indices.LastUpdated]), out var dt))
if (DateTime.TryParse(ColStr(row[indices.LastUpdated]), out DateTime dt))
LastUpdated = dt;
return;

View File

@@ -667,7 +667,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
if (!ShowDirtyHacks)
return;
var newHacks = EnabledHacks.Select(x => x.Hack)
string newHacks = EnabledHacks.Select(x => x.Hack)
.JoinToString(", ");
if (newHacks != _lastHackCollection)

View File

@@ -31,12 +31,12 @@ namespace Ryujinx.Ava.Utilities.Configuration
{
bool noFilter = e.NewValue.Length == 0;
foreach (var logClass in Enum.GetValues<LogClass>())
foreach (LogClass logClass in Enum.GetValues<LogClass>())
{
Logger.SetEnable(logClass, noFilter);
}
foreach (var logClass in e.NewValue)
foreach (LogClass logClass in e.NewValue)
{
Logger.SetEnable(logClass, true);
}

View File

@@ -22,7 +22,7 @@ namespace Ryujinx.Ava.Utilities
public static List<(DownloadableContentModel, bool IsEnabled)> LoadDownloadableContentsJson(VirtualFileSystem vfs, ulong applicationIdBase)
{
var downloadableContentJsonPath = PathToGameDLCJson(applicationIdBase);
string downloadableContentJsonPath = PathToGameDLCJson(applicationIdBase);
if (!File.Exists(downloadableContentJsonPath))
{
@@ -31,7 +31,7 @@ namespace Ryujinx.Ava.Utilities
try
{
var downloadableContentContainerList = JsonHelper.DeserializeFromFile(downloadableContentJsonPath,
List<DownloadableContentContainer> downloadableContentContainerList = JsonHelper.DeserializeFromFile(downloadableContentJsonPath,
_serializerContext.ListDownloadableContentContainer);
return LoadDownloadableContents(vfs, downloadableContentContainerList);
}
@@ -76,13 +76,13 @@ namespace Ryujinx.Ava.Utilities
downloadableContentContainerList.Add(container);
}
var downloadableContentJsonPath = PathToGameDLCJson(applicationIdBase);
string downloadableContentJsonPath = PathToGameDLCJson(applicationIdBase);
JsonHelper.SerializeToFile(downloadableContentJsonPath, downloadableContentContainerList, _serializerContext.ListDownloadableContentContainer);
}
private static List<(DownloadableContentModel, bool IsEnabled)> LoadDownloadableContents(VirtualFileSystem vfs, List<DownloadableContentContainer> downloadableContentContainers)
{
var result = new List<(DownloadableContentModel, bool IsEnabled)>();
List<(DownloadableContentModel, bool IsEnabled)> result = new List<(DownloadableContentModel, bool IsEnabled)>();
foreach (DownloadableContentContainer downloadableContentContainer in downloadableContentContainers)
{
@@ -105,7 +105,7 @@ namespace Ryujinx.Ava.Utilities
continue;
}
var content = new DownloadableContentModel(nca.Header.TitleId,
DownloadableContentModel content = new DownloadableContentModel(nca.Header.TitleId,
downloadableContentContainer.ContainerPath,
downloadableContentNca.FullPath);

View File

@@ -18,11 +18,11 @@ namespace Ryujinx.Ava.Utilities
iconPath += ".ico";
MemoryStream iconDataStream = new(iconData);
using var image = SKBitmap.Decode(iconDataStream);
using SKBitmap image = SKBitmap.Decode(iconDataStream);
image.Resize(new SKImageInfo(128, 128), SKFilterQuality.High);
SaveBitmapAsIcon(image, iconPath);
var shortcut = Shortcut.CreateShortcut(basePath, GetArgsString(applicationFilePath, applicationId), iconPath, 0);
Shortcut shortcut = Shortcut.CreateShortcut(basePath, GetArgsString(applicationFilePath, applicationId), iconPath, 0);
shortcut.StringData.NameString = cleanedAppName;
shortcut.WriteToFile(Path.Combine(desktopPath, cleanedAppName + ".lnk"));
}
@@ -31,12 +31,12 @@ namespace Ryujinx.Ava.Utilities
private static void CreateShortcutLinux(string applicationFilePath, string applicationId, byte[] iconData, string iconPath, string desktopPath, string cleanedAppName)
{
string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx.sh");
var desktopFile = EmbeddedResources.ReadAllText("Ryujinx/Assets/ShortcutFiles/shortcut-template.desktop");
string desktopFile = EmbeddedResources.ReadAllText("Ryujinx/Assets/ShortcutFiles/shortcut-template.desktop");
iconPath += ".png";
var image = SKBitmap.Decode(iconData);
using var data = image.Encode(SKEncodedImageFormat.Png, 100);
using var file = File.OpenWrite(iconPath);
SKBitmap image = SKBitmap.Decode(iconData);
using SKData data = image.Encode(SKEncodedImageFormat.Png, 100);
using FileStream file = File.OpenWrite(iconPath);
data.SaveTo(file);
using StreamWriter outputFile = new(Path.Combine(desktopPath, cleanedAppName + ".desktop"));
@@ -47,8 +47,8 @@ namespace Ryujinx.Ava.Utilities
private static void CreateShortcutMacos(string appFilePath, string applicationId, byte[] iconData, string desktopPath, string cleanedAppName)
{
string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx");
var plistFile = EmbeddedResources.ReadAllText("Ryujinx/Assets/ShortcutFiles/shortcut-template.plist");
var shortcutScript = EmbeddedResources.ReadAllText("Ryujinx/Assets/ShortcutFiles/shortcut-launch-script.sh");
string plistFile = EmbeddedResources.ReadAllText("Ryujinx/Assets/ShortcutFiles/shortcut-template.plist");
string shortcutScript = EmbeddedResources.ReadAllText("Ryujinx/Assets/ShortcutFiles/shortcut-launch-script.sh");
// Macos .App folder
string contentFolderPath = Path.Combine("/Applications", cleanedAppName + ".app", "Contents");
string scriptFolderPath = Path.Combine(contentFolderPath, "MacOS");
@@ -77,9 +77,9 @@ namespace Ryujinx.Ava.Utilities
}
const string IconName = "icon.png";
var image = SKBitmap.Decode(iconData);
using var data = image.Encode(SKEncodedImageFormat.Png, 100);
using var file = File.OpenWrite(Path.Combine(resourceFolderPath, IconName));
SKBitmap image = SKBitmap.Decode(iconData);
using SKData data = image.Encode(SKEncodedImageFormat.Png, 100);
using FileStream file = File.OpenWrite(Path.Combine(resourceFolderPath, IconName));
data.SaveTo(file);
// plist file
@@ -124,7 +124,7 @@ namespace Ryujinx.Ava.Utilities
private static string GetArgsString(string appFilePath, string applicationId)
{
// args are first defined as a list, for easier adjustments in the future
var argsList = new List<string>();
List<string> argsList = new List<string>();
if (!string.IsNullOrEmpty(CommandLineState.BaseDirPathArg))
{
@@ -157,7 +157,7 @@ namespace Ryujinx.Ava.Utilities
fs.Write(header);
// Writing actual data
using var data = source.Encode(SKEncodedImageFormat.Png, 100);
using SKData data = source.Encode(SKEncodedImageFormat.Png, 100);
data.SaveTo(fs);
// Getting data length (file length minus header)
long dataLength = fs.Length - header.Length;

View File

@@ -16,7 +16,7 @@ namespace Ryujinx.Ava.Utilities.SystemInfo
if (cpuName == null)
{
var cpuDict = new Dictionary<string, string>(StringComparer.Ordinal)
Dictionary<string, string> cpuDict = new Dictionary<string, string>(StringComparer.Ordinal)
{
["model name"] = null,
["Processor"] = null,
@@ -28,7 +28,7 @@ namespace Ryujinx.Ava.Utilities.SystemInfo
cpuName = cpuDict["model name"] ?? cpuDict["Processor"] ?? cpuDict["Hardware"] ?? "Unknown";
}
var memDict = new Dictionary<string, string>(StringComparer.Ordinal)
Dictionary<string, string> memDict = new Dictionary<string, string>(StringComparer.Ordinal)
{
["MemTotal"] = null,
["MemAvailable"] = null,

View File

@@ -40,10 +40,10 @@ namespace Ryujinx.Ava.Utilities.SystemInfo
static ulong GetVMInfoAvailableMemory()
{
var port = mach_host_self();
uint port = mach_host_self();
uint pageSize = 0;
var result = host_page_size(port, ref pageSize);
int result = host_page_size(port, ref pageSize);
if (result != 0)
{

View File

@@ -34,7 +34,7 @@ namespace Ryujinx.Ava.Utilities.SystemInfo
if (cpuObjs != null)
{
foreach (var cpuObj in cpuObjs)
foreach (ManagementBaseObject cpuObj in cpuObjs)
{
return cpuObj["Name"].ToString().Trim();
}

View File

@@ -30,7 +30,7 @@ namespace Ryujinx.Ava.Utilities
public static List<(TitleUpdateModel Update, bool IsSelected)> LoadTitleUpdatesJson(VirtualFileSystem vfs, ulong applicationIdBase)
{
var titleUpdatesJsonPath = PathToGameUpdatesJson(applicationIdBase);
string titleUpdatesJsonPath = PathToGameUpdatesJson(applicationIdBase);
if (!File.Exists(titleUpdatesJsonPath))
{
@@ -39,7 +39,7 @@ namespace Ryujinx.Ava.Utilities
try
{
var titleUpdateWindowData = JsonHelper.DeserializeFromFile(titleUpdatesJsonPath, _serializerContext.TitleUpdateMetadata);
TitleUpdateMetadata titleUpdateWindowData = JsonHelper.DeserializeFromFile(titleUpdatesJsonPath, _serializerContext.TitleUpdateMetadata);
return LoadTitleUpdates(vfs, titleUpdateWindowData, applicationIdBase);
}
catch
@@ -51,7 +51,7 @@ namespace Ryujinx.Ava.Utilities
public static void SaveTitleUpdatesJson(ulong applicationIdBase, List<(TitleUpdateModel, bool IsSelected)> updates)
{
var titleUpdateWindowData = new TitleUpdateMetadata
TitleUpdateMetadata titleUpdateWindowData = new TitleUpdateMetadata
{
Selected = string.Empty,
Paths = [],
@@ -73,13 +73,13 @@ namespace Ryujinx.Ava.Utilities
}
}
var titleUpdatesJsonPath = PathToGameUpdatesJson(applicationIdBase);
string titleUpdatesJsonPath = PathToGameUpdatesJson(applicationIdBase);
JsonHelper.SerializeToFile(titleUpdatesJsonPath, titleUpdateWindowData, _serializerContext.TitleUpdateMetadata);
}
private static List<(TitleUpdateModel Update, bool IsSelected)> LoadTitleUpdates(VirtualFileSystem vfs, TitleUpdateMetadata titleUpdateMetadata, ulong applicationIdBase)
{
var result = new List<(TitleUpdateModel, bool IsSelected)>();
List<(TitleUpdateModel, bool IsSelected)> result = new List<(TitleUpdateModel, bool IsSelected)>();
IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks
? IntegrityCheckLevel.ErrorOnInvalid
@@ -115,8 +115,8 @@ namespace Ryujinx.Ava.Utilities
nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None)
.ThrowIfFailure();
var displayVersion = controlData.DisplayVersionString.ToString();
var update = new TitleUpdateModel(content.ApplicationId, content.Version.Version,
string displayVersion = controlData.DisplayVersionString.ToString();
TitleUpdateModel update = new TitleUpdateModel(content.ApplicationId, content.Version.Version,
displayVersion, path);
result.Add((update, path == titleUpdateMetadata.Selected));

View File

@@ -139,10 +139,10 @@ namespace Ryujinx.Ava.Utilities
// An input string can either look like "01:23:45" or "1d, 01:23:45" if the timespan represents a duration of more than a day.
// Here, we split the input string to check if it's the former or the latter.
var valueSplit = timeSpanString.Split(", ");
string[] valueSplit = timeSpanString.Split(", ");
if (valueSplit.Length > 1)
{
var dayPart = valueSplit[0].Split("d")[0];
string dayPart = valueSplit[0].Split("d")[0];
if (int.TryParse(dayPart, out int days))
{
returnTimeSpan = returnTimeSpan.Add(TimeSpan.FromDays(days));