Merge remote-tracking branch 'upstream/master' into auto-assign-controller
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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”模拟了Switch的60Hz刷新率。“无限制”没有刷新率限制。",
|
||||
"zh_CN": "模拟垂直同步。“Switch”模拟了 Switch 的 60Hz 刷新率。“无限制”没有刷新率限制。",
|
||||
"zh_TW": "模擬垂直同步。「Switch」 模擬 Nintendo Switch 的 60Hz 重新整理頻率。「沒有限制」是沒有限制的重新整理頻率。"
|
||||
}
|
||||
},
|
||||
@@ -22593,7 +22593,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Емульована вертикальна синхронізація кадрів. 'Switch' емулює частоту оновлення консолі Nintendo Switch (60 Гц). 'Необмежена' — частота оновлення не матиме обмежень. 'Користувацька' емулює вказану користувацьку частоту оновлення.",
|
||||
"zh_CN": "模拟垂直同步。“Switch”模拟了Switch的60Hz刷新率。“无限制”没有刷新率限制。“自定义刷新率”模拟指定的自定义刷新率。",
|
||||
"zh_CN": "模拟垂直同步。“Switch”模拟了 Switch 的 60Hz 刷新率。“无限制”没有刷新率限制。“自定义刷新率”模拟指定的自定义刷新率。",
|
||||
"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": ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()}";
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -121,7 +121,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||
|
||||
startedDeferring = true;
|
||||
|
||||
var deferral = args.GetDeferral();
|
||||
Deferral deferral = args.GetDeferral();
|
||||
|
||||
sender.PrimaryButtonClick -= DeferClose;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 != '{')
|
||||
{
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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(() =>
|
||||
{
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user