mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2024-11-24 06:24:14 +00:00
This reverts commit 4ce4299ca2
.
This commit is contained in:
parent
4ce4299ca2
commit
ba95ee54ab
73 changed files with 608 additions and 886 deletions
|
@ -63,10 +63,6 @@ dotnet_code_quality_unused_parameters = all:suggestion
|
||||||
|
|
||||||
#### C# Coding Conventions ####
|
#### C# Coding Conventions ####
|
||||||
|
|
||||||
# Namespace preferences
|
|
||||||
csharp_style_namespace_declarations = block_scoped:warning
|
|
||||||
resharper_csharp_namespace_body = block_scoped
|
|
||||||
|
|
||||||
# var preferences
|
# var preferences
|
||||||
csharp_style_var_elsewhere = false:silent
|
csharp_style_var_elsewhere = false:silent
|
||||||
csharp_style_var_for_built_in_types = false:silent
|
csharp_style_var_for_built_in_types = false:silent
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders;
|
||||||
|
|
||||||
|
interface IOpCode32Exception
|
||||||
{
|
{
|
||||||
interface IOpCode32Exception
|
int Id { get; }
|
||||||
{
|
|
||||||
int Id { get; }
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -130,7 +130,7 @@ namespace Ryujinx.Ava.Common.Locale
|
||||||
{
|
{
|
||||||
var localeStrings = new Dictionary<LocaleKeys, string>();
|
var localeStrings = new Dictionary<LocaleKeys, string>();
|
||||||
string languageJson = EmbeddedResources.ReadAllText($"Ryujinx.Ava/Assets/Locales/{languageCode}.json");
|
string languageJson = EmbeddedResources.ReadAllText($"Ryujinx.Ava/Assets/Locales/{languageCode}.json");
|
||||||
var strings = JsonHelper.Deserialize(languageJson, CommonJsonContext.Default.StringDictionary);
|
var strings = JsonHelper.Deserialize<Dictionary<string, string>>(languageJson);
|
||||||
|
|
||||||
foreach (var item in strings)
|
foreach (var item in strings)
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,14 +4,13 @@ using FluentAvalonia.UI.Controls;
|
||||||
using ICSharpCode.SharpZipLib.GZip;
|
using ICSharpCode.SharpZipLib.GZip;
|
||||||
using ICSharpCode.SharpZipLib.Tar;
|
using ICSharpCode.SharpZipLib.Tar;
|
||||||
using ICSharpCode.SharpZipLib.Zip;
|
using ICSharpCode.SharpZipLib.Zip;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
using Ryujinx.Ava;
|
using Ryujinx.Ava;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Common.Utilities;
|
|
||||||
using Ryujinx.Ui.Common.Helper;
|
using Ryujinx.Ui.Common.Helper;
|
||||||
using Ryujinx.Ui.Common.Models.Github;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
@ -32,7 +31,6 @@ namespace Ryujinx.Modules
|
||||||
internal static class Updater
|
internal static class Updater
|
||||||
{
|
{
|
||||||
private const string GitHubApiURL = "https://api.github.com";
|
private const string GitHubApiURL = "https://api.github.com";
|
||||||
private static readonly GithubReleasesJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
|
||||||
|
|
||||||
private static readonly string HomeDir = AppDomain.CurrentDomain.BaseDirectory;
|
private static readonly string HomeDir = AppDomain.CurrentDomain.BaseDirectory;
|
||||||
private static readonly string UpdateDir = Path.Combine(Path.GetTempPath(), "Ryujinx", "update");
|
private static readonly string UpdateDir = Path.Combine(Path.GetTempPath(), "Ryujinx", "update");
|
||||||
|
@ -101,16 +99,22 @@ namespace Ryujinx.Modules
|
||||||
|
|
||||||
string buildInfoURL = $"{GitHubApiURL}/repos/{ReleaseInformation.ReleaseChannelOwner}/{ReleaseInformation.ReleaseChannelRepo}/releases/latest";
|
string buildInfoURL = $"{GitHubApiURL}/repos/{ReleaseInformation.ReleaseChannelOwner}/{ReleaseInformation.ReleaseChannelRepo}/releases/latest";
|
||||||
string fetchedJson = await jsonClient.GetStringAsync(buildInfoURL);
|
string fetchedJson = await jsonClient.GetStringAsync(buildInfoURL);
|
||||||
var fetched = JsonHelper.Deserialize(fetchedJson, SerializerContext.GithubReleasesJsonResponse);
|
JObject jsonRoot = JObject.Parse(fetchedJson);
|
||||||
_buildVer = fetched.Name;
|
JToken assets = jsonRoot["assets"];
|
||||||
|
|
||||||
foreach (var asset in fetched.Assets)
|
_buildVer = (string)jsonRoot["name"];
|
||||||
|
|
||||||
|
foreach (JToken asset in assets)
|
||||||
{
|
{
|
||||||
if (asset.Name.StartsWith("test-ava-ryujinx") && asset.Name.EndsWith(_platformExt))
|
string assetName = (string)asset["name"];
|
||||||
{
|
string assetState = (string)asset["state"];
|
||||||
_buildUrl = asset.BrowserDownloadUrl;
|
string downloadURL = (string)asset["browser_download_url"];
|
||||||
|
|
||||||
if (asset.State != "uploaded")
|
if (assetName.StartsWith("test-ava-ryujinx") && assetName.EndsWith(_platformExt))
|
||||||
|
{
|
||||||
|
_buildUrl = downloadURL;
|
||||||
|
|
||||||
|
if (assetState != "uploaded")
|
||||||
{
|
{
|
||||||
if (showVersionUpToDate)
|
if (showVersionUpToDate)
|
||||||
{
|
{
|
||||||
|
|
72
Ryujinx.Ava/UI/Models/Amiibo.cs
Normal file
72
Ryujinx.Ava/UI/Models/Amiibo.cs
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Models
|
||||||
|
{
|
||||||
|
public class Amiibo
|
||||||
|
{
|
||||||
|
public struct AmiiboJson
|
||||||
|
{
|
||||||
|
[JsonPropertyName("amiibo")] public List<AmiiboApi> Amiibo { get; set; }
|
||||||
|
[JsonPropertyName("lastUpdated")] public DateTime LastUpdated { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct AmiiboApi
|
||||||
|
{
|
||||||
|
[JsonPropertyName("name")] public string Name { get; set; }
|
||||||
|
[JsonPropertyName("head")] public string Head { get; set; }
|
||||||
|
[JsonPropertyName("tail")] public string Tail { get; set; }
|
||||||
|
[JsonPropertyName("image")] public string Image { get; set; }
|
||||||
|
[JsonPropertyName("amiiboSeries")] public string AmiiboSeries { get; set; }
|
||||||
|
[JsonPropertyName("character")] public string Character { get; set; }
|
||||||
|
[JsonPropertyName("gameSeries")] public string GameSeries { get; set; }
|
||||||
|
[JsonPropertyName("type")] public string Type { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("release")] public Dictionary<string, string> Release { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("gamesSwitch")] public List<AmiiboApiGamesSwitch> GamesSwitch { get; set; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetId()
|
||||||
|
{
|
||||||
|
return Head + Tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (obj is AmiiboApi amiibo)
|
||||||
|
{
|
||||||
|
return amiibo.Head + amiibo.Tail == Head + Tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return base.GetHashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AmiiboApiGamesSwitch
|
||||||
|
{
|
||||||
|
[JsonPropertyName("amiiboUsage")] public List<AmiiboApiUsage> AmiiboUsage { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("gameID")] public List<string> GameId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("gameName")] public string GameName { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AmiiboApiUsage
|
||||||
|
{
|
||||||
|
[JsonPropertyName("Usage")] public string Usage { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("write")] public bool Write { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -122,7 +122,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
{
|
{
|
||||||
string patreonJsonString = await httpClient.GetStringAsync("https://patreon.ryujinx.org/");
|
string patreonJsonString = await httpClient.GetStringAsync("https://patreon.ryujinx.org/");
|
||||||
|
|
||||||
Supporters = string.Join(", ", JsonHelper.Deserialize(patreonJsonString, CommonJsonContext.Default.StringArray) + "\n\n");
|
Supporters = string.Join(", ", JsonHelper.Deserialize<string[]>(patreonJsonString)) + "\n\n";
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,11 +4,11 @@ using Avalonia.Media.Imaging;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
|
using Ryujinx.Ava.UI.Models;
|
||||||
using Ryujinx.Ava.UI.Windows;
|
using Ryujinx.Ava.UI.Windows;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Utilities;
|
using Ryujinx.Common.Utilities;
|
||||||
using Ryujinx.Ui.Common.Models.Amiibo;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
@ -17,7 +17,6 @@ using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AmiiboJsonSerializerContext = Ryujinx.Ui.Common.Models.Amiibo.AmiiboJsonSerializerContext;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.ViewModels
|
namespace Ryujinx.Ava.UI.ViewModels
|
||||||
{
|
{
|
||||||
|
@ -32,8 +31,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
private readonly StyleableWindow _owner;
|
private readonly StyleableWindow _owner;
|
||||||
|
|
||||||
private Bitmap _amiiboImage;
|
private Bitmap _amiiboImage;
|
||||||
private List<AmiiboApi> _amiiboList;
|
private List<Amiibo.AmiiboApi> _amiiboList;
|
||||||
private AvaloniaList<AmiiboApi> _amiibos;
|
private AvaloniaList<Amiibo.AmiiboApi> _amiibos;
|
||||||
private ObservableCollection<string> _amiiboSeries;
|
private ObservableCollection<string> _amiiboSeries;
|
||||||
|
|
||||||
private int _amiiboSelectedIndex;
|
private int _amiiboSelectedIndex;
|
||||||
|
@ -43,8 +42,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
private bool _useRandomUuid;
|
private bool _useRandomUuid;
|
||||||
private string _usage;
|
private string _usage;
|
||||||
|
|
||||||
private static readonly AmiiboJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
|
||||||
|
|
||||||
public AmiiboWindowViewModel(StyleableWindow owner, string lastScannedAmiiboId, string titleId)
|
public AmiiboWindowViewModel(StyleableWindow owner, string lastScannedAmiiboId, string titleId)
|
||||||
{
|
{
|
||||||
_owner = owner;
|
_owner = owner;
|
||||||
|
@ -55,9 +52,9 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
Directory.CreateDirectory(Path.Join(AppDataManager.BaseDirPath, "system", "amiibo"));
|
Directory.CreateDirectory(Path.Join(AppDataManager.BaseDirPath, "system", "amiibo"));
|
||||||
|
|
||||||
_amiiboJsonPath = Path.Join(AppDataManager.BaseDirPath, "system", "amiibo", "Amiibo.json");
|
_amiiboJsonPath = Path.Join(AppDataManager.BaseDirPath, "system", "amiibo", "Amiibo.json");
|
||||||
_amiiboList = new List<AmiiboApi>();
|
_amiiboList = new List<Amiibo.AmiiboApi>();
|
||||||
_amiiboSeries = new ObservableCollection<string>();
|
_amiiboSeries = new ObservableCollection<string>();
|
||||||
_amiibos = new AvaloniaList<AmiiboApi>();
|
_amiibos = new AvaloniaList<Amiibo.AmiiboApi>();
|
||||||
|
|
||||||
_amiiboLogoBytes = EmbeddedResources.Read("Ryujinx.Ui.Common/Resources/Logo_Amiibo.png");
|
_amiiboLogoBytes = EmbeddedResources.Read("Ryujinx.Ui.Common/Resources/Logo_Amiibo.png");
|
||||||
|
|
||||||
|
@ -97,7 +94,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public AvaloniaList<AmiiboApi> AmiiboList
|
public AvaloniaList<Amiibo.AmiiboApi> AmiiboList
|
||||||
{
|
{
|
||||||
get => _amiibos;
|
get => _amiibos;
|
||||||
set
|
set
|
||||||
|
@ -190,9 +187,9 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
|
|
||||||
if (File.Exists(_amiiboJsonPath))
|
if (File.Exists(_amiiboJsonPath))
|
||||||
{
|
{
|
||||||
amiiboJsonString = await File.ReadAllTextAsync(_amiiboJsonPath);
|
amiiboJsonString = File.ReadAllText(_amiiboJsonPath);
|
||||||
|
|
||||||
if (await NeedsUpdate(JsonHelper.Deserialize(amiiboJsonString, SerializerContext.AmiiboJson).LastUpdated))
|
if (await NeedsUpdate(JsonHelper.Deserialize<Amiibo.AmiiboJson>(amiiboJsonString).LastUpdated))
|
||||||
{
|
{
|
||||||
amiiboJsonString = await DownloadAmiiboJson();
|
amiiboJsonString = await DownloadAmiiboJson();
|
||||||
}
|
}
|
||||||
|
@ -209,7 +206,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_amiiboList = JsonHelper.Deserialize(amiiboJsonString, SerializerContext.AmiiboJson).Amiibo;
|
_amiiboList = JsonHelper.Deserialize<Amiibo.AmiiboJson>(amiiboJsonString).Amiibo;
|
||||||
_amiiboList = _amiiboList.OrderBy(amiibo => amiibo.AmiiboSeries).ToList();
|
_amiiboList = _amiiboList.OrderBy(amiibo => amiibo.AmiiboSeries).ToList();
|
||||||
|
|
||||||
ParseAmiiboData();
|
ParseAmiiboData();
|
||||||
|
@ -226,7 +223,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
{
|
{
|
||||||
if (!ShowAllAmiibo)
|
if (!ShowAllAmiibo)
|
||||||
{
|
{
|
||||||
foreach (AmiiboApiGamesSwitch game in _amiiboList[i].GamesSwitch)
|
foreach (Amiibo.AmiiboApiGamesSwitch game in _amiiboList[i].GamesSwitch)
|
||||||
{
|
{
|
||||||
if (game != null)
|
if (game != null)
|
||||||
{
|
{
|
||||||
|
@ -258,7 +255,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
|
|
||||||
private void SelectLastScannedAmiibo()
|
private void SelectLastScannedAmiibo()
|
||||||
{
|
{
|
||||||
AmiiboApi scanned = _amiiboList.FirstOrDefault(amiibo => amiibo.GetId() == LastScannedAmiiboId);
|
Amiibo.AmiiboApi scanned = _amiiboList.FirstOrDefault(amiibo => amiibo.GetId() == LastScannedAmiiboId);
|
||||||
|
|
||||||
SeriesSelectedIndex = AmiiboSeries.IndexOf(scanned.AmiiboSeries);
|
SeriesSelectedIndex = AmiiboSeries.IndexOf(scanned.AmiiboSeries);
|
||||||
AmiiboSelectedIndex = AmiiboList.IndexOf(scanned);
|
AmiiboSelectedIndex = AmiiboList.IndexOf(scanned);
|
||||||
|
@ -273,7 +270,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<AmiiboApi> amiiboSortedList = _amiiboList
|
List<Amiibo.AmiiboApi> amiiboSortedList = _amiiboList
|
||||||
.Where(amiibo => amiibo.AmiiboSeries == _amiiboSeries[SeriesSelectedIndex])
|
.Where(amiibo => amiibo.AmiiboSeries == _amiiboSeries[SeriesSelectedIndex])
|
||||||
.OrderBy(amiibo => amiibo.Name).ToList();
|
.OrderBy(amiibo => amiibo.Name).ToList();
|
||||||
|
|
||||||
|
@ -283,7 +280,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
{
|
{
|
||||||
if (!_showAllAmiibo)
|
if (!_showAllAmiibo)
|
||||||
{
|
{
|
||||||
foreach (AmiiboApiGamesSwitch game in amiiboSortedList[i].GamesSwitch)
|
foreach (Amiibo.AmiiboApiGamesSwitch game in amiiboSortedList[i].GamesSwitch)
|
||||||
{
|
{
|
||||||
if (game != null)
|
if (game != null)
|
||||||
{
|
{
|
||||||
|
@ -317,7 +314,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AmiiboApi selected = _amiibos[_amiiboSelectedIndex];
|
Amiibo.AmiiboApi selected = _amiibos[_amiiboSelectedIndex];
|
||||||
|
|
||||||
string imageUrl = _amiiboList.FirstOrDefault(amiibo => amiibo.Equals(selected)).Image;
|
string imageUrl = _amiiboList.FirstOrDefault(amiibo => amiibo.Equals(selected)).Image;
|
||||||
|
|
||||||
|
@ -329,11 +326,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
{
|
{
|
||||||
bool writable = false;
|
bool writable = false;
|
||||||
|
|
||||||
foreach (AmiiboApiGamesSwitch item in _amiiboList[i].GamesSwitch)
|
foreach (Amiibo.AmiiboApiGamesSwitch item in _amiiboList[i].GamesSwitch)
|
||||||
{
|
{
|
||||||
if (item.GameId.Contains(TitleId))
|
if (item.GameId.Contains(TitleId))
|
||||||
{
|
{
|
||||||
foreach (AmiiboApiUsage usageItem in item.AmiiboUsage)
|
foreach (Amiibo.AmiiboApiUsage usageItem in item.AmiiboUsage)
|
||||||
{
|
{
|
||||||
usageString += Environment.NewLine +
|
usageString += Environment.NewLine +
|
||||||
$"- {usageItem.Usage.Replace("/", Environment.NewLine + "-")}";
|
$"- {usageItem.Usage.Replace("/", Environment.NewLine + "-")}";
|
||||||
|
|
|
@ -51,8 +51,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
private bool _isLoaded;
|
private bool _isLoaded;
|
||||||
private readonly UserControl _owner;
|
private readonly UserControl _owner;
|
||||||
|
|
||||||
private static readonly InputConfigJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
|
||||||
|
|
||||||
public IGamepadDriver AvaloniaKeyboardDriver { get; }
|
public IGamepadDriver AvaloniaKeyboardDriver { get; }
|
||||||
public IGamepad SelectedGamepad { get; private set; }
|
public IGamepad SelectedGamepad { get; private set; }
|
||||||
|
|
||||||
|
@ -708,7 +706,10 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
config = JsonHelper.DeserializeFromFile(path, SerializerContext.InputConfig);
|
using (Stream stream = File.OpenRead(path))
|
||||||
|
{
|
||||||
|
config = JsonHelper.Deserialize<InputConfig>(stream);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (JsonException) { }
|
catch (JsonException) { }
|
||||||
catch (InvalidOperationException)
|
catch (InvalidOperationException)
|
||||||
|
@ -774,7 +775,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
|
|
||||||
config.ControllerType = Controllers[_controller].Type;
|
config.ControllerType = Controllers[_controller].Type;
|
||||||
|
|
||||||
string jsonString = JsonHelper.Serialize(config, SerializerContext.InputConfig);
|
string jsonString = JsonHelper.Serialize(config, true);
|
||||||
|
|
||||||
await File.WriteAllTextAsync(path, jsonString);
|
await File.WriteAllTextAsync(path, jsonString);
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Path = System.IO.Path;
|
using Path = System.IO.Path;
|
||||||
|
|
||||||
|
@ -40,8 +41,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
private ulong _titleId;
|
private ulong _titleId;
|
||||||
private string _titleName;
|
private string _titleName;
|
||||||
|
|
||||||
private static readonly DownloadableContentJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
|
||||||
|
|
||||||
public AvaloniaList<DownloadableContentModel> DownloadableContents
|
public AvaloniaList<DownloadableContentModel> DownloadableContents
|
||||||
{
|
{
|
||||||
get => _downloadableContents;
|
get => _downloadableContents;
|
||||||
|
@ -101,7 +100,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_downloadableContentContainerList = JsonHelper.DeserializeFromFile(_downloadableContentJsonPath, SerializerContext.ListDownloadableContentContainer);
|
_downloadableContentContainerList = JsonHelper.DeserializeFromFile<List<DownloadableContentContainer>>(_downloadableContentJsonPath);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@ -331,7 +330,10 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||||
_downloadableContentContainerList.Add(container);
|
_downloadableContentContainerList.Add(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonHelper.SerializeToFile(_downloadableContentJsonPath, _downloadableContentContainerList, SerializerContext.ListDownloadableContentContainer);
|
using (FileStream downloadableContentJsonStream = File.Create(_downloadableContentJsonPath, 4096, FileOptions.WriteThrough))
|
||||||
|
{
|
||||||
|
downloadableContentJsonStream.Write(Encoding.UTF8.GetBytes(JsonHelper.Serialize(_downloadableContentContainerList, true)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,228 +25,226 @@ using System.Text;
|
||||||
using Path = System.IO.Path;
|
using Path = System.IO.Path;
|
||||||
using SpanHelpers = LibHac.Common.SpanHelpers;
|
using SpanHelpers = LibHac.Common.SpanHelpers;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.ViewModels
|
namespace Ryujinx.Ava.UI.ViewModels;
|
||||||
|
|
||||||
|
public class TitleUpdateViewModel : BaseModel
|
||||||
{
|
{
|
||||||
public class TitleUpdateViewModel : BaseModel
|
public TitleUpdateMetadata _titleUpdateWindowData;
|
||||||
|
public readonly string _titleUpdateJsonPath;
|
||||||
|
private VirtualFileSystem _virtualFileSystem { get; }
|
||||||
|
private ulong _titleId { get; }
|
||||||
|
private string _titleName { get; }
|
||||||
|
|
||||||
|
private AvaloniaList<TitleUpdateModel> _titleUpdates = new();
|
||||||
|
private AvaloniaList<object> _views = new();
|
||||||
|
private object _selectedUpdate;
|
||||||
|
|
||||||
|
public AvaloniaList<TitleUpdateModel> TitleUpdates
|
||||||
{
|
{
|
||||||
public TitleUpdateMetadata _titleUpdateWindowData;
|
get => _titleUpdates;
|
||||||
public readonly string _titleUpdateJsonPath;
|
set
|
||||||
private VirtualFileSystem _virtualFileSystem { get; }
|
|
||||||
private ulong _titleId { get; }
|
|
||||||
private string _titleName { get; }
|
|
||||||
|
|
||||||
private AvaloniaList<TitleUpdateModel> _titleUpdates = new();
|
|
||||||
private AvaloniaList<object> _views = new();
|
|
||||||
private object _selectedUpdate;
|
|
||||||
|
|
||||||
private static readonly TitleUpdateMetadataJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
|
||||||
|
|
||||||
public AvaloniaList<TitleUpdateModel> TitleUpdates
|
|
||||||
{
|
{
|
||||||
get => _titleUpdates;
|
_titleUpdates = value;
|
||||||
set
|
OnPropertyChanged();
|
||||||
{
|
|
||||||
_titleUpdates = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public AvaloniaList<object> Views
|
public AvaloniaList<object> Views
|
||||||
|
{
|
||||||
|
get => _views;
|
||||||
|
set
|
||||||
{
|
{
|
||||||
get => _views;
|
_views = value;
|
||||||
set
|
OnPropertyChanged();
|
||||||
{
|
|
||||||
_views = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public object SelectedUpdate
|
public object SelectedUpdate
|
||||||
|
{
|
||||||
|
get => _selectedUpdate;
|
||||||
|
set
|
||||||
{
|
{
|
||||||
get => _selectedUpdate;
|
_selectedUpdate = value;
|
||||||
set
|
OnPropertyChanged();
|
||||||
{
|
|
||||||
_selectedUpdate = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public TitleUpdateViewModel(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName)
|
public TitleUpdateViewModel(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName)
|
||||||
|
{
|
||||||
|
_virtualFileSystem = virtualFileSystem;
|
||||||
|
|
||||||
|
_titleId = titleId;
|
||||||
|
_titleName = titleName;
|
||||||
|
|
||||||
|
_titleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "updates.json");
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
_virtualFileSystem = virtualFileSystem;
|
_titleUpdateWindowData = JsonHelper.DeserializeFromFile<TitleUpdateMetadata>(_titleUpdateJsonPath);
|
||||||
|
|
||||||
_titleId = titleId;
|
|
||||||
_titleName = titleName;
|
|
||||||
|
|
||||||
_titleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "updates.json");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_titleUpdateWindowData = JsonHelper.DeserializeFromFile(_titleUpdateJsonPath, SerializerContext.TitleUpdateMetadata);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
Logger.Warning?.Print(LogClass.Application, $"Failed to deserialize title update data for {_titleId} at {_titleUpdateJsonPath}");
|
|
||||||
|
|
||||||
_titleUpdateWindowData = new TitleUpdateMetadata
|
|
||||||
{
|
|
||||||
Selected = "",
|
|
||||||
Paths = new List<string>()
|
|
||||||
};
|
|
||||||
|
|
||||||
Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
LoadUpdates();
|
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
private void LoadUpdates()
|
|
||||||
{
|
{
|
||||||
foreach (string path in _titleUpdateWindowData.Paths)
|
Logger.Warning?.Print(LogClass.Application, $"Failed to deserialize title update data for {_titleId} at {_titleUpdateJsonPath}");
|
||||||
|
|
||||||
|
_titleUpdateWindowData = new TitleUpdateMetadata
|
||||||
{
|
{
|
||||||
AddUpdate(path);
|
Selected = "",
|
||||||
}
|
Paths = new List<string>()
|
||||||
|
};
|
||||||
|
|
||||||
TitleUpdateModel selected = TitleUpdates.FirstOrDefault(x => x.Path == _titleUpdateWindowData.Selected, null);
|
|
||||||
|
|
||||||
SelectedUpdate = selected;
|
|
||||||
|
|
||||||
// NOTE: Save the list again to remove leftovers.
|
|
||||||
Save();
|
Save();
|
||||||
SortUpdates();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SortUpdates()
|
LoadUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadUpdates()
|
||||||
|
{
|
||||||
|
foreach (string path in _titleUpdateWindowData.Paths)
|
||||||
{
|
{
|
||||||
var list = TitleUpdates.ToList();
|
AddUpdate(path);
|
||||||
|
}
|
||||||
|
|
||||||
list.Sort((first, second) =>
|
TitleUpdateModel selected = TitleUpdates.FirstOrDefault(x => x.Path == _titleUpdateWindowData.Selected, null);
|
||||||
|
|
||||||
|
SelectedUpdate = selected;
|
||||||
|
|
||||||
|
// NOTE: Save the list again to remove leftovers.
|
||||||
|
Save();
|
||||||
|
|
||||||
|
SortUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SortUpdates()
|
||||||
|
{
|
||||||
|
var list = TitleUpdates.ToList();
|
||||||
|
|
||||||
|
list.Sort((first, second) =>
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(first.Control.DisplayVersionString.ToString()))
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(first.Control.DisplayVersionString.ToString()))
|
return -1;
|
||||||
{
|
}
|
||||||
return -1;
|
else if (string.IsNullOrEmpty(second.Control.DisplayVersionString.ToString()))
|
||||||
}
|
{
|
||||||
else if (string.IsNullOrEmpty(second.Control.DisplayVersionString.ToString()))
|
return 1;
|
||||||
{
|
}
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Version.Parse(first.Control.DisplayVersionString.ToString()).CompareTo(Version.Parse(second.Control.DisplayVersionString.ToString())) * -1;
|
return Version.Parse(first.Control.DisplayVersionString.ToString()).CompareTo(Version.Parse(second.Control.DisplayVersionString.ToString())) * -1;
|
||||||
});
|
});
|
||||||
|
|
||||||
Views.Clear();
|
Views.Clear();
|
||||||
Views.Add(new BaseModel());
|
Views.Add(new BaseModel());
|
||||||
Views.AddRange(list);
|
Views.AddRange(list);
|
||||||
|
|
||||||
if (SelectedUpdate == null)
|
if (SelectedUpdate == null)
|
||||||
|
{
|
||||||
|
SelectedUpdate = Views[0];
|
||||||
|
}
|
||||||
|
else if (!TitleUpdates.Contains(SelectedUpdate))
|
||||||
|
{
|
||||||
|
if (Views.Count > 1)
|
||||||
|
{
|
||||||
|
SelectedUpdate = Views[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
SelectedUpdate = Views[0];
|
SelectedUpdate = Views[0];
|
||||||
}
|
}
|
||||||
else if (!TitleUpdates.Contains(SelectedUpdate))
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddUpdate(string path)
|
||||||
|
{
|
||||||
|
if (File.Exists(path) && TitleUpdates.All(x => x.Path != path))
|
||||||
|
{
|
||||||
|
using FileStream file = new(path, FileMode.Open, FileAccess.Read);
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if (Views.Count > 1)
|
(Nca patchNca, Nca controlNca) = ApplicationLoader.GetGameUpdateDataFromPartition(_virtualFileSystem, new PartitionFileSystem(file.AsStorage()), _titleId.ToString("x16"), 0);
|
||||||
|
|
||||||
|
if (controlNca != null && patchNca != null)
|
||||||
{
|
{
|
||||||
SelectedUpdate = Views[1];
|
ApplicationControlProperty controlData = new();
|
||||||
|
|
||||||
|
using UniqueRef<IFile> nacpFile = new();
|
||||||
|
|
||||||
|
controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
|
nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
|
||||||
|
|
||||||
|
TitleUpdates.Add(new TitleUpdateModel(controlData, path));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
SelectedUpdate = Views[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddUpdate(string path)
|
|
||||||
{
|
|
||||||
if (File.Exists(path) && TitleUpdates.All(x => x.Path != path))
|
|
||||||
{
|
|
||||||
using FileStream file = new(path, FileMode.Open, FileAccess.Read);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
(Nca patchNca, Nca controlNca) = ApplicationLoader.GetGameUpdateDataFromPartition(_virtualFileSystem, new PartitionFileSystem(file.AsStorage()), _titleId.ToString("x16"), 0);
|
|
||||||
|
|
||||||
if (controlNca != null && patchNca != null)
|
|
||||||
{
|
|
||||||
ApplicationControlProperty controlData = new();
|
|
||||||
|
|
||||||
using UniqueRef<IFile> nacpFile = new();
|
|
||||||
|
|
||||||
controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
|
||||||
nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
|
|
||||||
|
|
||||||
TitleUpdates.Add(new TitleUpdateModel(controlData, path));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Dispatcher.UIThread.Post(async () =>
|
|
||||||
{
|
|
||||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUpdateAddUpdateErrorMessage]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(async () =>
|
Dispatcher.UIThread.Post(async () =>
|
||||||
{
|
{
|
||||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogLoadNcaErrorMessage, ex.Message, path));
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUpdateAddUpdateErrorMessage]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
catch (Exception ex)
|
||||||
|
|
||||||
public void RemoveUpdate(TitleUpdateModel update)
|
|
||||||
{
|
|
||||||
TitleUpdates.Remove(update);
|
|
||||||
|
|
||||||
SortUpdates();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void Add()
|
|
||||||
{
|
|
||||||
OpenFileDialog dialog = new()
|
|
||||||
{
|
{
|
||||||
Title = LocaleManager.Instance[LocaleKeys.SelectUpdateDialogTitle],
|
Dispatcher.UIThread.Post(async () =>
|
||||||
AllowMultiple = true
|
|
||||||
};
|
|
||||||
|
|
||||||
dialog.Filters.Add(new FileDialogFilter
|
|
||||||
{
|
|
||||||
Name = "NSP",
|
|
||||||
Extensions = { "nsp" }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
|
||||||
{
|
|
||||||
string[] files = await dialog.ShowAsync(desktop.MainWindow);
|
|
||||||
|
|
||||||
if (files != null)
|
|
||||||
{
|
{
|
||||||
foreach (string file in files)
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogLoadNcaErrorMessage, ex.Message, path));
|
||||||
{
|
});
|
||||||
AddUpdate(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SortUpdates();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Save()
|
|
||||||
{
|
|
||||||
_titleUpdateWindowData.Paths.Clear();
|
|
||||||
_titleUpdateWindowData.Selected = "";
|
|
||||||
|
|
||||||
foreach (TitleUpdateModel update in TitleUpdates)
|
|
||||||
{
|
|
||||||
_titleUpdateWindowData.Paths.Add(update.Path);
|
|
||||||
|
|
||||||
if (update == SelectedUpdate)
|
|
||||||
{
|
|
||||||
_titleUpdateWindowData.Selected = update.Path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonHelper.SerializeToFile(_titleUpdateJsonPath, _titleUpdateWindowData, SerializerContext.TitleUpdateMetadata);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RemoveUpdate(TitleUpdateModel update)
|
||||||
|
{
|
||||||
|
TitleUpdates.Remove(update);
|
||||||
|
|
||||||
|
SortUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void Add()
|
||||||
|
{
|
||||||
|
OpenFileDialog dialog = new()
|
||||||
|
{
|
||||||
|
Title = LocaleManager.Instance[LocaleKeys.SelectUpdateDialogTitle],
|
||||||
|
AllowMultiple = true
|
||||||
|
};
|
||||||
|
|
||||||
|
dialog.Filters.Add(new FileDialogFilter
|
||||||
|
{
|
||||||
|
Name = "NSP",
|
||||||
|
Extensions = { "nsp" }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
|
{
|
||||||
|
string[] files = await dialog.ShowAsync(desktop.MainWindow);
|
||||||
|
|
||||||
|
if (files != null)
|
||||||
|
{
|
||||||
|
foreach (string file in files)
|
||||||
|
{
|
||||||
|
AddUpdate(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SortUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Save()
|
||||||
|
{
|
||||||
|
_titleUpdateWindowData.Paths.Clear();
|
||||||
|
_titleUpdateWindowData.Selected = "";
|
||||||
|
|
||||||
|
foreach (TitleUpdateModel update in TitleUpdates)
|
||||||
|
{
|
||||||
|
_titleUpdateWindowData.Paths.Add(update.Path);
|
||||||
|
|
||||||
|
if (update == SelectedUpdate)
|
||||||
|
{
|
||||||
|
_titleUpdateWindowData.Selected = update.Path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
File.WriteAllBytes(_titleUpdateJsonPath, Encoding.UTF8.GetBytes(JsonHelper.Serialize(_titleUpdateWindowData, true)));
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -42,7 +42,7 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||||
{
|
{
|
||||||
string languageCode = Path.GetFileNameWithoutExtension(locale).Split('.').Last();
|
string languageCode = Path.GetFileNameWithoutExtension(locale).Split('.').Last();
|
||||||
string languageJson = EmbeddedResources.ReadAllText($"{localePath}/{languageCode}{localeExt}");
|
string languageJson = EmbeddedResources.ReadAllText($"{localePath}/{languageCode}{localeExt}");
|
||||||
var strings = JsonHelper.Deserialize(languageJson, CommonJsonContext.Default.StringDictionary);
|
var strings = JsonHelper.Deserialize<Dictionary<string, string>>(languageJson);
|
||||||
|
|
||||||
if (!strings.TryGetValue("Language", out string languageName))
|
if (!strings.TryGetValue("Language", out string languageName))
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
|
using Ryujinx.Ava.UI.Models;
|
||||||
using Ryujinx.Ava.UI.ViewModels;
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
using Ryujinx.Ui.Common.Models.Amiibo;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Windows
|
namespace Ryujinx.Ava.UI.Windows
|
||||||
{
|
{
|
||||||
|
@ -35,14 +35,14 @@ namespace Ryujinx.Ava.UI.Windows
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsScanned { get; set; }
|
public bool IsScanned { get; set; }
|
||||||
public AmiiboApi ScannedAmiibo { get; set; }
|
public Amiibo.AmiiboApi ScannedAmiibo { get; set; }
|
||||||
public AmiiboWindowViewModel ViewModel { get; set; }
|
public AmiiboWindowViewModel ViewModel { get; set; }
|
||||||
|
|
||||||
private void ScanButton_Click(object sender, RoutedEventArgs e)
|
private void ScanButton_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (ViewModel.AmiiboSelectedIndex > -1)
|
if (ViewModel.AmiiboSelectedIndex > -1)
|
||||||
{
|
{
|
||||||
AmiiboApi amiibo = ViewModel.AmiiboList[ViewModel.AmiiboSelectedIndex];
|
Amiibo.AmiiboApi amiibo = ViewModel.AmiiboList[ViewModel.AmiiboSelectedIndex];
|
||||||
ScannedAmiibo = amiibo;
|
ScannedAmiibo = amiibo;
|
||||||
IsScanned = true;
|
IsScanned = true;
|
||||||
Close();
|
Close();
|
||||||
|
|
|
@ -6,8 +6,11 @@ using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
using Ryujinx.Ava.UI.Models;
|
using Ryujinx.Ava.UI.Models;
|
||||||
using Ryujinx.Ava.UI.ViewModels;
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
|
using Ryujinx.Common.Utilities;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using Ryujinx.Ui.Common.Helper;
|
using Ryujinx.Ui.Common.Helper;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Button = Avalonia.Controls.Button;
|
using Button = Avalonia.Controls.Button;
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
using Ryujinx.Common.Utilities;
|
namespace Ryujinx.Common.Configuration
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Configuration
|
|
||||||
{
|
{
|
||||||
[JsonConverter(typeof(TypedStringEnumConverter<AspectRatio>))]
|
|
||||||
public enum AspectRatio
|
public enum AspectRatio
|
||||||
{
|
{
|
||||||
Fixed4x3,
|
Fixed4x3,
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
using Ryujinx.Common.Utilities;
|
namespace Ryujinx.Common.Configuration
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Configuration
|
|
||||||
{
|
{
|
||||||
[JsonConverter(typeof(TypedStringEnumConverter<BackendThreading>))]
|
|
||||||
public enum BackendThreading
|
public enum BackendThreading
|
||||||
{
|
{
|
||||||
Auto,
|
Auto,
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Configuration
|
|
||||||
{
|
|
||||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
|
||||||
[JsonSerializable(typeof(List<DownloadableContentContainer>))]
|
|
||||||
public partial class DownloadableContentJsonSerializerContext : JsonSerializerContext
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +1,5 @@
|
||||||
using Ryujinx.Common.Utilities;
|
namespace Ryujinx.Common.Configuration
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Configuration
|
|
||||||
{
|
{
|
||||||
[JsonConverter(typeof(TypedStringEnumConverter<GraphicsBackend>))]
|
|
||||||
public enum GraphicsBackend
|
public enum GraphicsBackend
|
||||||
{
|
{
|
||||||
Vulkan,
|
Vulkan,
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
using Ryujinx.Common.Utilities;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Configuration
|
namespace Ryujinx.Common.Configuration
|
||||||
{
|
{
|
||||||
[JsonConverter(typeof(TypedStringEnumConverter<GraphicsDebugLevel>))]
|
|
||||||
public enum GraphicsDebugLevel
|
public enum GraphicsDebugLevel
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using Ryujinx.Common.Utilities;
|
using System;
|
||||||
using System;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
@ -7,8 +6,6 @@ namespace Ryujinx.Common.Configuration.Hid.Controller.Motion
|
||||||
{
|
{
|
||||||
class JsonMotionConfigControllerConverter : JsonConverter<MotionConfigController>
|
class JsonMotionConfigControllerConverter : JsonConverter<MotionConfigController>
|
||||||
{
|
{
|
||||||
private static readonly MotionConfigJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
|
||||||
|
|
||||||
private static MotionInputBackendType GetMotionInputBackendType(ref Utf8JsonReader reader)
|
private static MotionInputBackendType GetMotionInputBackendType(ref Utf8JsonReader reader)
|
||||||
{
|
{
|
||||||
// Temporary reader to get the backend type
|
// Temporary reader to get the backend type
|
||||||
|
@ -55,8 +52,8 @@ namespace Ryujinx.Common.Configuration.Hid.Controller.Motion
|
||||||
|
|
||||||
return motionBackendType switch
|
return motionBackendType switch
|
||||||
{
|
{
|
||||||
MotionInputBackendType.GamepadDriver => JsonSerializer.Deserialize(ref reader, SerializerContext.StandardMotionConfigController),
|
MotionInputBackendType.GamepadDriver => (MotionConfigController)JsonSerializer.Deserialize(ref reader, typeof(StandardMotionConfigController), options),
|
||||||
MotionInputBackendType.CemuHook => JsonSerializer.Deserialize(ref reader, SerializerContext.CemuHookMotionConfigController),
|
MotionInputBackendType.CemuHook => (MotionConfigController)JsonSerializer.Deserialize(ref reader, typeof(CemuHookMotionConfigController), options),
|
||||||
_ => throw new InvalidOperationException($"Unknown backend type {motionBackendType}"),
|
_ => throw new InvalidOperationException($"Unknown backend type {motionBackendType}"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -66,10 +63,10 @@ namespace Ryujinx.Common.Configuration.Hid.Controller.Motion
|
||||||
switch (value.MotionBackend)
|
switch (value.MotionBackend)
|
||||||
{
|
{
|
||||||
case MotionInputBackendType.GamepadDriver:
|
case MotionInputBackendType.GamepadDriver:
|
||||||
JsonSerializer.Serialize(writer, value as StandardMotionConfigController, SerializerContext.StandardMotionConfigController);
|
JsonSerializer.Serialize(writer, value as StandardMotionConfigController, options);
|
||||||
break;
|
break;
|
||||||
case MotionInputBackendType.CemuHook:
|
case MotionInputBackendType.CemuHook:
|
||||||
JsonSerializer.Serialize(writer, value as CemuHookMotionConfigController, SerializerContext.CemuHookMotionConfigController);
|
JsonSerializer.Serialize(writer, value as CemuHookMotionConfigController, options);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentException($"Unknown motion backend type {value.MotionBackend}");
|
throw new ArgumentException($"Unknown motion backend type {value.MotionBackend}");
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
using System.Text.Json.Serialization;
|
namespace Ryujinx.Common.Configuration.Hid.Controller.Motion
|
||||||
|
|
||||||
namespace Ryujinx.Common.Configuration.Hid.Controller.Motion
|
|
||||||
{
|
{
|
||||||
[JsonConverter(typeof(JsonMotionConfigControllerConverter))]
|
|
||||||
public class MotionConfigController
|
public class MotionConfigController
|
||||||
{
|
{
|
||||||
public MotionInputBackendType MotionBackend { get; set; }
|
public MotionInputBackendType MotionBackend { get; set; }
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Configuration.Hid.Controller.Motion
|
|
||||||
{
|
|
||||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
|
||||||
[JsonSerializable(typeof(MotionConfigController))]
|
|
||||||
[JsonSerializable(typeof(CemuHookMotionConfigController))]
|
|
||||||
[JsonSerializable(typeof(StandardMotionConfigController))]
|
|
||||||
public partial class MotionConfigJsonSerializerContext : JsonSerializerContext
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +1,5 @@
|
||||||
using Ryujinx.Common.Utilities;
|
namespace Ryujinx.Common.Configuration.Hid.Controller.Motion
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Configuration.Hid.Controller.Motion
|
|
||||||
{
|
{
|
||||||
[JsonConverter(typeof(TypedStringEnumConverter<MotionInputBackendType>))]
|
|
||||||
public enum MotionInputBackendType : byte
|
public enum MotionInputBackendType : byte
|
||||||
{
|
{
|
||||||
Invalid,
|
Invalid,
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
using Ryujinx.Common.Utilities;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Configuration.Hid
|
namespace Ryujinx.Common.Configuration.Hid
|
||||||
{
|
{
|
||||||
// This enum was duplicated from Ryujinx.HLE.HOS.Services.Hid.PlayerIndex and should be kept identical
|
|
||||||
[Flags]
|
[Flags]
|
||||||
[JsonConverter(typeof(TypedStringEnumConverter<ControllerType>))]
|
// This enum was duplicated from Ryujinx.HLE.HOS.Services.Hid.PlayerIndex and should be kept identical
|
||||||
public enum ControllerType : int
|
public enum ControllerType : int
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
using Ryujinx.Common.Utilities;
|
namespace Ryujinx.Common.Configuration.Hid
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Configuration.Hid
|
|
||||||
{
|
{
|
||||||
[JsonConverter(typeof(TypedStringEnumConverter<InputBackendType>))]
|
|
||||||
public enum InputBackendType
|
public enum InputBackendType
|
||||||
{
|
{
|
||||||
Invalid,
|
Invalid,
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Configuration.Hid
|
namespace Ryujinx.Common.Configuration.Hid
|
||||||
{
|
{
|
||||||
[JsonConverter(typeof(JsonInputConfigConverter))]
|
|
||||||
public class InputConfig : INotifyPropertyChanged
|
public class InputConfig : INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
|
||||||
using Ryujinx.Common.Configuration.Hid.Keyboard;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Configuration.Hid
|
|
||||||
{
|
|
||||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
|
||||||
[JsonSerializable(typeof(InputConfig))]
|
|
||||||
[JsonSerializable(typeof(StandardKeyboardInputConfig))]
|
|
||||||
[JsonSerializable(typeof(StandardControllerInputConfig))]
|
|
||||||
public partial class InputConfigJsonSerializerContext : JsonSerializerContext
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +1,13 @@
|
||||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||||
using Ryujinx.Common.Configuration.Hid.Keyboard;
|
using Ryujinx.Common.Configuration.Hid.Keyboard;
|
||||||
using Ryujinx.Common.Utilities;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace Ryujinx.Common.Configuration.Hid
|
namespace Ryujinx.Common.Configuration.Hid
|
||||||
{
|
{
|
||||||
public class JsonInputConfigConverter : JsonConverter<InputConfig>
|
class JsonInputConfigConverter : JsonConverter<InputConfig>
|
||||||
{
|
{
|
||||||
private static readonly InputConfigJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
|
||||||
|
|
||||||
private static InputBackendType GetInputBackendType(ref Utf8JsonReader reader)
|
private static InputBackendType GetInputBackendType(ref Utf8JsonReader reader)
|
||||||
{
|
{
|
||||||
// Temporary reader to get the backend type
|
// Temporary reader to get the backend type
|
||||||
|
@ -57,8 +54,8 @@ namespace Ryujinx.Common.Configuration.Hid
|
||||||
|
|
||||||
return backendType switch
|
return backendType switch
|
||||||
{
|
{
|
||||||
InputBackendType.WindowKeyboard => JsonSerializer.Deserialize(ref reader, SerializerContext.StandardKeyboardInputConfig),
|
InputBackendType.WindowKeyboard => (InputConfig)JsonSerializer.Deserialize(ref reader, typeof(StandardKeyboardInputConfig), options),
|
||||||
InputBackendType.GamepadSDL2 => JsonSerializer.Deserialize(ref reader, SerializerContext.StandardControllerInputConfig),
|
InputBackendType.GamepadSDL2 => (InputConfig)JsonSerializer.Deserialize(ref reader, typeof(StandardControllerInputConfig), options),
|
||||||
_ => throw new InvalidOperationException($"Unknown backend type {backendType}"),
|
_ => throw new InvalidOperationException($"Unknown backend type {backendType}"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -68,10 +65,10 @@ namespace Ryujinx.Common.Configuration.Hid
|
||||||
switch (value.Backend)
|
switch (value.Backend)
|
||||||
{
|
{
|
||||||
case InputBackendType.WindowKeyboard:
|
case InputBackendType.WindowKeyboard:
|
||||||
JsonSerializer.Serialize(writer, value as StandardKeyboardInputConfig, SerializerContext.StandardKeyboardInputConfig);
|
JsonSerializer.Serialize(writer, value as StandardKeyboardInputConfig, options);
|
||||||
break;
|
break;
|
||||||
case InputBackendType.GamepadSDL2:
|
case InputBackendType.GamepadSDL2:
|
||||||
JsonSerializer.Serialize(writer, value as StandardControllerInputConfig, SerializerContext.StandardControllerInputConfig);
|
JsonSerializer.Serialize(writer, value as StandardControllerInputConfig, options);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new ArgumentException($"Unknown backend type {value.Backend}");
|
throw new ArgumentException($"Unknown backend type {value.Backend}");
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
using Ryujinx.Common.Utilities;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Configuration.Hid
|
namespace Ryujinx.Common.Configuration.Hid
|
||||||
{
|
{
|
||||||
// This enum was duplicated from Ryujinx.HLE.HOS.Services.Hid.PlayerIndex and should be kept identical
|
// This enum was duplicated from Ryujinx.HLE.HOS.Services.Hid.PlayerIndex and should be kept identical
|
||||||
[JsonConverter(typeof(TypedStringEnumConverter<PlayerIndex>))]
|
|
||||||
public enum PlayerIndex : int
|
public enum PlayerIndex : int
|
||||||
{
|
{
|
||||||
Player1 = 0,
|
Player1 = 0,
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
using Ryujinx.Common.Utilities;
|
namespace Ryujinx.Common.Configuration
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Configuration
|
|
||||||
{
|
{
|
||||||
[JsonConverter(typeof(TypedStringEnumConverter<MemoryManagerMode>))]
|
|
||||||
public enum MemoryManagerMode : byte
|
public enum MemoryManagerMode : byte
|
||||||
{
|
{
|
||||||
SoftwarePageTable,
|
SoftwarePageTable,
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Configuration
|
|
||||||
{
|
|
||||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
|
||||||
[JsonSerializable(typeof(TitleUpdateMetadata))]
|
|
||||||
public partial class TitleUpdateMetadataJsonSerializerContext : JsonSerializerContext
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +1,22 @@
|
||||||
using System.Text;
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace Ryujinx.Common.Logging
|
namespace Ryujinx.Common.Logging
|
||||||
{
|
{
|
||||||
internal class DefaultLogFormatter : ILogFormatter
|
internal class DefaultLogFormatter : ILogFormatter
|
||||||
{
|
{
|
||||||
private static readonly ObjectPool<StringBuilder> StringBuilderPool = SharedPools.Default<StringBuilder>();
|
private static readonly ObjectPool<StringBuilder> _stringBuilderPool = SharedPools.Default<StringBuilder>();
|
||||||
|
|
||||||
public string Format(LogEventArgs args)
|
public string Format(LogEventArgs args)
|
||||||
{
|
{
|
||||||
StringBuilder sb = StringBuilderPool.Allocate();
|
StringBuilder sb = _stringBuilderPool.Allocate();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
sb.Clear();
|
sb.Clear();
|
||||||
|
|
||||||
sb.Append($@"{args.Time:hh\:mm\:ss\.fff}");
|
sb.AppendFormat(@"{0:hh\:mm\:ss\.fff}", args.Time);
|
||||||
sb.Append($" |{args.Level.ToString()[0]}| ");
|
sb.Append($" |{args.Level.ToString()[0]}| ");
|
||||||
|
|
||||||
if (args.ThreadName != null)
|
if (args.ThreadName != null)
|
||||||
|
@ -25,17 +27,53 @@ namespace Ryujinx.Common.Logging
|
||||||
|
|
||||||
sb.Append(args.Message);
|
sb.Append(args.Message);
|
||||||
|
|
||||||
if (args.Data is not null)
|
if (args.Data != null)
|
||||||
{
|
{
|
||||||
sb.Append(' ');
|
PropertyInfo[] props = args.Data.GetType().GetProperties();
|
||||||
DynamicObjectFormatter.Format(sb, args.Data);
|
|
||||||
|
sb.Append(" {");
|
||||||
|
|
||||||
|
foreach (var prop in props)
|
||||||
|
{
|
||||||
|
sb.Append(prop.Name);
|
||||||
|
sb.Append(": ");
|
||||||
|
|
||||||
|
if (typeof(Array).IsAssignableFrom(prop.PropertyType))
|
||||||
|
{
|
||||||
|
Array array = (Array)prop.GetValue(args.Data);
|
||||||
|
foreach (var item in array)
|
||||||
|
{
|
||||||
|
sb.Append(item.ToString());
|
||||||
|
sb.Append(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array.Length > 0)
|
||||||
|
{
|
||||||
|
sb.Remove(sb.Length - 2, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.Append(prop.GetValue(args.Data));
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Append(" ; ");
|
||||||
|
}
|
||||||
|
|
||||||
|
// We remove the final ';' from the string
|
||||||
|
if (props.Length > 0)
|
||||||
|
{
|
||||||
|
sb.Remove(sb.Length - 3, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Append('}');
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
StringBuilderPool.Release(sb);
|
_stringBuilderPool.Release(sb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
#nullable enable
|
|
||||||
using System;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Logging
|
|
||||||
{
|
|
||||||
internal class DynamicObjectFormatter
|
|
||||||
{
|
|
||||||
private static readonly ObjectPool<StringBuilder> StringBuilderPool = SharedPools.Default<StringBuilder>();
|
|
||||||
|
|
||||||
public static string? Format(object? dynamicObject)
|
|
||||||
{
|
|
||||||
if (dynamicObject is null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuilder sb = StringBuilderPool.Allocate();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Format(sb, dynamicObject);
|
|
||||||
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
StringBuilderPool.Release(sb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Format(StringBuilder sb, object? dynamicObject)
|
|
||||||
{
|
|
||||||
if (dynamicObject is null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyInfo[] props = dynamicObject.GetType().GetProperties();
|
|
||||||
|
|
||||||
sb.Append('{');
|
|
||||||
|
|
||||||
foreach (var prop in props)
|
|
||||||
{
|
|
||||||
sb.Append(prop.Name);
|
|
||||||
sb.Append(": ");
|
|
||||||
|
|
||||||
if (typeof(Array).IsAssignableFrom(prop.PropertyType))
|
|
||||||
{
|
|
||||||
Array? array = (Array?) prop.GetValue(dynamicObject);
|
|
||||||
|
|
||||||
if (array is not null)
|
|
||||||
{
|
|
||||||
foreach (var item in array)
|
|
||||||
{
|
|
||||||
sb.Append(item);
|
|
||||||
sb.Append(", ");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (array.Length > 0)
|
|
||||||
{
|
|
||||||
sb.Remove(sb.Length - 2, 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sb.Append(prop.GetValue(dynamicObject));
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.Append(" ; ");
|
|
||||||
}
|
|
||||||
|
|
||||||
// We remove the final ';' from the string
|
|
||||||
if (props.Length > 0)
|
|
||||||
{
|
|
||||||
sb.Remove(sb.Length - 3, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.Append('}');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +1,5 @@
|
||||||
using Ryujinx.Common.Utilities;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Logging
|
namespace Ryujinx.Common.Logging
|
||||||
{
|
{
|
||||||
[JsonConverter(typeof(TypedStringEnumConverter<LogClass>))]
|
|
||||||
public enum LogClass
|
public enum LogClass
|
||||||
{
|
{
|
||||||
Application,
|
Application,
|
||||||
|
|
|
@ -11,7 +11,15 @@ namespace Ryujinx.Common.Logging
|
||||||
public readonly string Message;
|
public readonly string Message;
|
||||||
public readonly object Data;
|
public readonly object Data;
|
||||||
|
|
||||||
public LogEventArgs(LogLevel level, TimeSpan time, string threadName, string message, object data = null)
|
public LogEventArgs(LogLevel level, TimeSpan time, string threadName, string message)
|
||||||
|
{
|
||||||
|
Level = level;
|
||||||
|
Time = time;
|
||||||
|
ThreadName = threadName;
|
||||||
|
Message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LogEventArgs(LogLevel level, TimeSpan time, string threadName, string message, object data)
|
||||||
{
|
{
|
||||||
Level = level;
|
Level = level;
|
||||||
Time = time;
|
Time = time;
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Logging
|
|
||||||
{
|
|
||||||
internal class LogEventArgsJson
|
|
||||||
{
|
|
||||||
public LogLevel Level { get; }
|
|
||||||
public TimeSpan Time { get; }
|
|
||||||
public string ThreadName { get; }
|
|
||||||
|
|
||||||
public string Message { get; }
|
|
||||||
public string Data { get; }
|
|
||||||
|
|
||||||
[JsonConstructor]
|
|
||||||
public LogEventArgsJson(LogLevel level, TimeSpan time, string threadName, string message, string data = null)
|
|
||||||
{
|
|
||||||
Level = level;
|
|
||||||
Time = time;
|
|
||||||
ThreadName = threadName;
|
|
||||||
Message = message;
|
|
||||||
Data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LogEventArgsJson FromLogEventArgs(LogEventArgs args)
|
|
||||||
{
|
|
||||||
return new LogEventArgsJson(args.Level, args.Time, args.ThreadName, args.Message, DynamicObjectFormatter.Format(args.Data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Logging
|
|
||||||
{
|
|
||||||
[JsonSerializable(typeof(LogEventArgsJson))]
|
|
||||||
internal partial class LogEventJsonSerializerContext : JsonSerializerContext
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +1,5 @@
|
||||||
using Ryujinx.Common.Utilities;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Logging
|
namespace Ryujinx.Common.Logging
|
||||||
{
|
{
|
||||||
[JsonConverter(typeof(TypedStringEnumConverter<LogLevel>))]
|
|
||||||
public enum LogLevel
|
public enum LogLevel
|
||||||
{
|
{
|
||||||
Debug,
|
Debug,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
using Ryujinx.Common.Utilities;
|
using System.IO;
|
||||||
using System.IO;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace Ryujinx.Common.Logging
|
namespace Ryujinx.Common.Logging
|
||||||
{
|
{
|
||||||
|
@ -25,8 +25,12 @@ namespace Ryujinx.Common.Logging
|
||||||
|
|
||||||
public void Log(object sender, LogEventArgs e)
|
public void Log(object sender, LogEventArgs e)
|
||||||
{
|
{
|
||||||
var logEventArgsJson = LogEventArgsJson.FromLogEventArgs(e);
|
string text = JsonSerializer.Serialize(e);
|
||||||
JsonHelper.SerializeToStream(_stream, logEventArgsJson, LogEventJsonSerializerContext.Default.LogEventArgsJson);
|
|
||||||
|
using (BinaryWriter writer = new BinaryWriter(_stream))
|
||||||
|
{
|
||||||
|
writer.Write(text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Utilities
|
|
||||||
{
|
|
||||||
[JsonSerializable(typeof(string[]), TypeInfoPropertyName = "StringArray")]
|
|
||||||
[JsonSerializable(typeof(Dictionary<string, string>), TypeInfoPropertyName = "StringDictionary")]
|
|
||||||
public partial class CommonJsonContext : JsonSerializerContext
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,62 +1,15 @@
|
||||||
using System.IO;
|
using Ryujinx.Common.Configuration.Hid;
|
||||||
|
using Ryujinx.Common.Configuration.Hid.Controller.Motion;
|
||||||
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization.Metadata;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace Ryujinx.Common.Utilities
|
namespace Ryujinx.Common.Utilities
|
||||||
{
|
{
|
||||||
public class JsonHelper
|
public class JsonHelper
|
||||||
{
|
{
|
||||||
private static readonly JsonNamingPolicy SnakeCasePolicy = new SnakeCaseNamingPolicy();
|
public static JsonNamingPolicy SnakeCase { get; }
|
||||||
private const int DefaultFileWriteBufferSize = 4096;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates new serializer options with default settings.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// It is REQUIRED for you to save returned options statically or as a part of static serializer context
|
|
||||||
/// in order to avoid performance issues. You can safely modify returned options for your case before storing.
|
|
||||||
/// </remarks>
|
|
||||||
public static JsonSerializerOptions GetDefaultSerializerOptions(bool indented = true)
|
|
||||||
{
|
|
||||||
JsonSerializerOptions options = new()
|
|
||||||
{
|
|
||||||
DictionaryKeyPolicy = SnakeCasePolicy,
|
|
||||||
PropertyNamingPolicy = SnakeCasePolicy,
|
|
||||||
WriteIndented = indented,
|
|
||||||
AllowTrailingCommas = true,
|
|
||||||
ReadCommentHandling = JsonCommentHandling.Skip
|
|
||||||
};
|
|
||||||
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string Serialize<T>(T value, JsonTypeInfo<T> typeInfo)
|
|
||||||
{
|
|
||||||
return JsonSerializer.Serialize(value, typeInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static T Deserialize<T>(string value, JsonTypeInfo<T> typeInfo)
|
|
||||||
{
|
|
||||||
return JsonSerializer.Deserialize(value, typeInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SerializeToFile<T>(string filePath, T value, JsonTypeInfo<T> typeInfo)
|
|
||||||
{
|
|
||||||
using FileStream file = File.Create(filePath, DefaultFileWriteBufferSize, FileOptions.WriteThrough);
|
|
||||||
JsonSerializer.Serialize(file, value, typeInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static T DeserializeFromFile<T>(string filePath, JsonTypeInfo<T> typeInfo)
|
|
||||||
{
|
|
||||||
using FileStream file = File.OpenRead(filePath);
|
|
||||||
return JsonSerializer.Deserialize(file, typeInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SerializeToStream<T>(Stream stream, T value, JsonTypeInfo<T> typeInfo)
|
|
||||||
{
|
|
||||||
JsonSerializer.Serialize(stream, value, typeInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class SnakeCaseNamingPolicy : JsonNamingPolicy
|
private class SnakeCaseNamingPolicy : JsonNamingPolicy
|
||||||
{
|
{
|
||||||
|
@ -67,7 +20,7 @@ namespace Ryujinx.Common.Utilities
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder builder = new();
|
StringBuilder builder = new StringBuilder();
|
||||||
|
|
||||||
for (int i = 0; i < name.Length; i++)
|
for (int i = 0; i < name.Length; i++)
|
||||||
{
|
{
|
||||||
|
@ -81,7 +34,7 @@ namespace Ryujinx.Common.Utilities
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
builder.Append('_');
|
builder.Append("_");
|
||||||
builder.Append(char.ToLowerInvariant(c));
|
builder.Append(char.ToLowerInvariant(c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,5 +47,64 @@ namespace Ryujinx.Common.Utilities
|
||||||
return builder.ToString();
|
return builder.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static JsonHelper()
|
||||||
|
{
|
||||||
|
SnakeCase = new SnakeCaseNamingPolicy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JsonSerializerOptions GetDefaultSerializerOptions(bool prettyPrint = false)
|
||||||
|
{
|
||||||
|
JsonSerializerOptions options = new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
DictionaryKeyPolicy = SnakeCase,
|
||||||
|
PropertyNamingPolicy = SnakeCase,
|
||||||
|
WriteIndented = prettyPrint,
|
||||||
|
AllowTrailingCommas = true,
|
||||||
|
ReadCommentHandling = JsonCommentHandling.Skip
|
||||||
|
};
|
||||||
|
|
||||||
|
options.Converters.Add(new JsonStringEnumConverter());
|
||||||
|
options.Converters.Add(new JsonInputConfigConverter());
|
||||||
|
options.Converters.Add(new JsonMotionConfigControllerConverter());
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T Deserialize<T>(Stream stream)
|
||||||
|
{
|
||||||
|
using (BinaryReader reader = new BinaryReader(stream))
|
||||||
|
{
|
||||||
|
return JsonSerializer.Deserialize<T>(reader.ReadBytes((int)(stream.Length - stream.Position)), GetDefaultSerializerOptions());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T DeserializeFromFile<T>(string path)
|
||||||
|
{
|
||||||
|
return Deserialize<T>(File.ReadAllText(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T Deserialize<T>(string json)
|
||||||
|
{
|
||||||
|
return JsonSerializer.Deserialize<T>(json, GetDefaultSerializerOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Serialize<TValue>(Stream stream, TValue obj, bool prettyPrint = false)
|
||||||
|
{
|
||||||
|
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||||
|
{
|
||||||
|
writer.Write(SerializeToUtf8Bytes(obj, prettyPrint));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Serialize<TValue>(TValue obj, bool prettyPrint = false)
|
||||||
|
{
|
||||||
|
return JsonSerializer.Serialize(obj, GetDefaultSerializerOptions(prettyPrint));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] SerializeToUtf8Bytes<T>(T obj, bool prettyPrint = false)
|
||||||
|
{
|
||||||
|
return JsonSerializer.SerializeToUtf8Bytes(obj, GetDefaultSerializerOptions(prettyPrint));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,34 +0,0 @@
|
||||||
#nullable enable
|
|
||||||
using System;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Utilities
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Specifies that value of <see cref="TEnum"/> will be serialized as string in JSONs
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Trimming friendly alternative to <see cref="JsonStringEnumConverter"/>.
|
|
||||||
/// Get rid of this converter if dotnet supports similar functionality out of the box.
|
|
||||||
/// </remarks>
|
|
||||||
/// <typeparam name="TEnum">Type of enum to serialize</typeparam>
|
|
||||||
public sealed class TypedStringEnumConverter<TEnum> : JsonConverter<TEnum> where TEnum : struct, Enum
|
|
||||||
{
|
|
||||||
public override TEnum Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
|
||||||
{
|
|
||||||
var enumValue = reader.GetString();
|
|
||||||
if (string.IsNullOrEmpty(enumValue))
|
|
||||||
{
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Enum.Parse<TEnum>(enumValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Write(Utf8JsonWriter writer, TEnum value, JsonSerializerOptions options)
|
|
||||||
{
|
|
||||||
writer.WriteStringValue(value.ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -13,7 +13,6 @@ using LibHac.Tools.FsSystem;
|
||||||
using LibHac.Tools.FsSystem.NcaUtils;
|
using LibHac.Tools.FsSystem.NcaUtils;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Common.Utilities;
|
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using Ryujinx.HLE.Loaders.Executables;
|
using Ryujinx.HLE.Loaders.Executables;
|
||||||
|
@ -25,13 +24,14 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
|
||||||
using static Ryujinx.HLE.HOS.ModLoader;
|
using static Ryujinx.HLE.HOS.ModLoader;
|
||||||
using ApplicationId = LibHac.Ncm.ApplicationId;
|
using ApplicationId = LibHac.Ncm.ApplicationId;
|
||||||
using Path = System.IO.Path;
|
using Path = System.IO.Path;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS
|
namespace Ryujinx.HLE.HOS
|
||||||
{
|
{
|
||||||
|
using JsonHelper = Common.Utilities.JsonHelper;
|
||||||
|
|
||||||
public class ApplicationLoader
|
public class ApplicationLoader
|
||||||
{
|
{
|
||||||
// Binaries from exefs are loaded into mem in this order. Do not change.
|
// Binaries from exefs are loaded into mem in this order. Do not change.
|
||||||
|
@ -57,10 +57,6 @@ namespace Ryujinx.HLE.HOS
|
||||||
private string _displayVersion;
|
private string _displayVersion;
|
||||||
private BlitStruct<ApplicationControlProperty> _controlData;
|
private BlitStruct<ApplicationControlProperty> _controlData;
|
||||||
|
|
||||||
private static readonly JsonSerializerOptions SerializerOptions = JsonHelper.GetDefaultSerializerOptions();
|
|
||||||
private static readonly DownloadableContentJsonSerializerContext ContentSerializerContext = new(SerializerOptions);
|
|
||||||
private static readonly TitleUpdateMetadataJsonSerializerContext TitleSerializerContext = new(SerializerOptions);
|
|
||||||
|
|
||||||
public BlitStruct<ApplicationControlProperty> ControlData => _controlData;
|
public BlitStruct<ApplicationControlProperty> ControlData => _controlData;
|
||||||
public string TitleName => _titleName;
|
public string TitleName => _titleName;
|
||||||
public string DisplayVersion => _displayVersion;
|
public string DisplayVersion => _displayVersion;
|
||||||
|
@ -201,7 +197,7 @@ namespace Ryujinx.HLE.HOS
|
||||||
|
|
||||||
if (File.Exists(titleUpdateMetadataPath))
|
if (File.Exists(titleUpdateMetadataPath))
|
||||||
{
|
{
|
||||||
updatePath = JsonHelper.DeserializeFromFile(titleUpdateMetadataPath, TitleSerializerContext.TitleUpdateMetadata).Selected;
|
updatePath = JsonHelper.DeserializeFromFile<TitleUpdateMetadata>(titleUpdateMetadataPath).Selected;
|
||||||
|
|
||||||
if (File.Exists(updatePath))
|
if (File.Exists(updatePath))
|
||||||
{
|
{
|
||||||
|
@ -415,7 +411,7 @@ namespace Ryujinx.HLE.HOS
|
||||||
|
|
||||||
if (File.Exists(titleAocMetadataPath))
|
if (File.Exists(titleAocMetadataPath))
|
||||||
{
|
{
|
||||||
List<DownloadableContentContainer> dlcContainerList = JsonHelper.DeserializeFromFile(titleAocMetadataPath, ContentSerializerContext.ListDownloadableContentContainer);
|
List<DownloadableContentContainer> dlcContainerList = JsonHelper.DeserializeFromFile<List<DownloadableContentContainer>>(titleAocMetadataPath);
|
||||||
|
|
||||||
foreach (DownloadableContentContainer downloadableContentContainer in dlcContainerList)
|
foreach (DownloadableContentContainer downloadableContentContainer in dlcContainerList)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Common.Utilities;
|
using Ryujinx.Common.Utilities;
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc.Types;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,29 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
{
|
{
|
||||||
private readonly string _profilesJsonPath = Path.Join(AppDataManager.BaseDirPath, "system", "Profiles.json");
|
private readonly string _profilesJsonPath = Path.Join(AppDataManager.BaseDirPath, "system", "Profiles.json");
|
||||||
|
|
||||||
private static readonly ProfilesJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
private struct ProfilesJson
|
||||||
|
{
|
||||||
|
[JsonPropertyName("profiles")]
|
||||||
|
public List<UserProfileJson> Profiles { get; set; }
|
||||||
|
[JsonPropertyName("last_opened")]
|
||||||
|
public string LastOpened { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct UserProfileJson
|
||||||
|
{
|
||||||
|
[JsonPropertyName("user_id")]
|
||||||
|
public string UserId { get; set; }
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
[JsonPropertyName("account_state")]
|
||||||
|
public AccountState AccountState { get; set; }
|
||||||
|
[JsonPropertyName("online_play_state")]
|
||||||
|
public AccountState OnlinePlayState { get; set; }
|
||||||
|
[JsonPropertyName("last_modified_timestamp")]
|
||||||
|
public long LastModifiedTimestamp { get; set; }
|
||||||
|
[JsonPropertyName("image")]
|
||||||
|
public byte[] Image { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public UserId LastOpened { get; set; }
|
public UserId LastOpened { get; set; }
|
||||||
|
|
||||||
|
@ -25,7 +47,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ProfilesJson profilesJson = JsonHelper.DeserializeFromFile(_profilesJsonPath, SerializerContext.ProfilesJson);
|
ProfilesJson profilesJson = JsonHelper.DeserializeFromFile<ProfilesJson>(_profilesJsonPath);
|
||||||
|
|
||||||
foreach (var profile in profilesJson.Profiles)
|
foreach (var profile in profilesJson.Profiles)
|
||||||
{
|
{
|
||||||
|
@ -70,7 +92,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonHelper.SerializeToFile(_profilesJsonPath, profilesJson, SerializerContext.ProfilesJson);
|
File.WriteAllText(_profilesJsonPath, JsonHelper.Serialize(profilesJson, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,11 +0,0 @@
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc.Types;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
|
||||||
{
|
|
||||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
|
||||||
[JsonSerializable(typeof(ProfilesJson))]
|
|
||||||
internal partial class ProfilesJsonSerializerContext : JsonSerializerContext
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +1,5 @@
|
||||||
using Ryujinx.Common.Utilities;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
{
|
{
|
||||||
[JsonConverter(typeof(TypedStringEnumConverter<AccountState>))]
|
|
||||||
public enum AccountState
|
public enum AccountState
|
||||||
{
|
{
|
||||||
Closed,
|
Closed,
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Account.Acc.Types
|
|
||||||
{
|
|
||||||
internal struct ProfilesJson
|
|
||||||
{
|
|
||||||
public List<UserProfileJson> Profiles { get; set; }
|
|
||||||
public string LastOpened { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
namespace Ryujinx.HLE.HOS.Services.Account.Acc.Types
|
|
||||||
{
|
|
||||||
internal struct UserProfileJson
|
|
||||||
{
|
|
||||||
public string UserId { get; set; }
|
|
||||||
public string Name { get; set; }
|
|
||||||
public AccountState AccountState { get; set; }
|
|
||||||
public AccountState OnlinePlayState { get; set; }
|
|
||||||
public long LastModifiedTimestamp { get; set; }
|
|
||||||
public byte[] Image { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
using Ryujinx.HLE.HOS.Services.Nfc.Nfp.NfpManager;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
|
||||||
{
|
|
||||||
[JsonSerializable(typeof(VirtualAmiiboFile))]
|
|
||||||
internal partial class AmiiboJsonSerializerContext : JsonSerializerContext
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,5 @@
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Common.Utilities;
|
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.HLE.HOS.Services.Mii;
|
using Ryujinx.HLE.HOS.Services.Mii;
|
||||||
using Ryujinx.HLE.HOS.Services.Mii.Types;
|
using Ryujinx.HLE.HOS.Services.Mii.Types;
|
||||||
|
@ -9,6 +8,8 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
||||||
{
|
{
|
||||||
|
@ -16,8 +17,6 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
||||||
{
|
{
|
||||||
private static uint _openedApplicationAreaId;
|
private static uint _openedApplicationAreaId;
|
||||||
|
|
||||||
private static readonly AmiiboJsonSerializerContext SerializerContext = AmiiboJsonSerializerContext.Default;
|
|
||||||
|
|
||||||
public static byte[] GenerateUuid(string amiiboId, bool useRandomUuid)
|
public static byte[] GenerateUuid(string amiiboId, bool useRandomUuid)
|
||||||
{
|
{
|
||||||
if (useRandomUuid)
|
if (useRandomUuid)
|
||||||
|
@ -174,7 +173,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
||||||
|
|
||||||
if (File.Exists(filePath))
|
if (File.Exists(filePath))
|
||||||
{
|
{
|
||||||
virtualAmiiboFile = JsonHelper.DeserializeFromFile(filePath, SerializerContext.VirtualAmiiboFile);
|
virtualAmiiboFile = JsonSerializer.Deserialize<VirtualAmiiboFile>(File.ReadAllText(filePath), new JsonSerializerOptions(JsonSerializerDefaults.General));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -198,7 +197,8 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
||||||
private static void SaveAmiiboFile(VirtualAmiiboFile virtualAmiiboFile)
|
private static void SaveAmiiboFile(VirtualAmiiboFile virtualAmiiboFile)
|
||||||
{
|
{
|
||||||
string filePath = Path.Join(AppDataManager.BaseDirPath, "system", "amiibo", $"{virtualAmiiboFile.AmiiboId}.json");
|
string filePath = Path.Join(AppDataManager.BaseDirPath, "system", "amiibo", $"{virtualAmiiboFile.AmiiboId}.json");
|
||||||
JsonHelper.SerializeToFile(filePath, virtualAmiiboFile, SerializerContext.VirtualAmiiboFile);
|
|
||||||
|
File.WriteAllText(filePath, JsonSerializer.Serialize(virtualAmiiboFile));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,8 +56,6 @@ namespace Ryujinx.Headless.SDL2
|
||||||
private static bool _enableKeyboard;
|
private static bool _enableKeyboard;
|
||||||
private static bool _enableMouse;
|
private static bool _enableMouse;
|
||||||
|
|
||||||
private static readonly InputConfigJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
|
||||||
|
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
Version = ReleaseInformation.GetVersion();
|
Version = ReleaseInformation.GetVersion();
|
||||||
|
@ -287,7 +285,10 @@ namespace Ryujinx.Headless.SDL2
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
config = JsonHelper.DeserializeFromFile(path, SerializerContext.InputConfig);
|
using (Stream stream = File.OpenRead(path))
|
||||||
|
{
|
||||||
|
config = JsonHelper.Deserialize<InputConfig>(stream);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (JsonException)
|
catch (JsonException)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ui.App.Common
|
|
||||||
{
|
|
||||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
|
||||||
[JsonSerializable(typeof(ApplicationMetadata))]
|
|
||||||
internal partial class ApplicationJsonSerializerContext : JsonSerializerContext
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -10,7 +10,6 @@ using LibHac.Tools.FsSystem;
|
||||||
using LibHac.Tools.FsSystem.NcaUtils;
|
using LibHac.Tools.FsSystem.NcaUtils;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Common.Utilities;
|
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using Ryujinx.HLE.HOS;
|
using Ryujinx.HLE.HOS;
|
||||||
using Ryujinx.HLE.HOS.SystemState;
|
using Ryujinx.HLE.HOS.SystemState;
|
||||||
|
@ -23,6 +22,7 @@ using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using JsonHelper = Ryujinx.Common.Utilities.JsonHelper;
|
||||||
using Path = System.IO.Path;
|
using Path = System.IO.Path;
|
||||||
|
|
||||||
namespace Ryujinx.Ui.App.Common
|
namespace Ryujinx.Ui.App.Common
|
||||||
|
@ -42,8 +42,6 @@ namespace Ryujinx.Ui.App.Common
|
||||||
private Language _desiredTitleLanguage;
|
private Language _desiredTitleLanguage;
|
||||||
private CancellationTokenSource _cancellationToken;
|
private CancellationTokenSource _cancellationToken;
|
||||||
|
|
||||||
private static readonly ApplicationJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
|
||||||
|
|
||||||
public ApplicationLibrary(VirtualFileSystem virtualFileSystem)
|
public ApplicationLibrary(VirtualFileSystem virtualFileSystem)
|
||||||
{
|
{
|
||||||
_virtualFileSystem = virtualFileSystem;
|
_virtualFileSystem = virtualFileSystem;
|
||||||
|
@ -492,12 +490,14 @@ namespace Ryujinx.Ui.App.Common
|
||||||
|
|
||||||
appMetadata = new ApplicationMetadata();
|
appMetadata = new ApplicationMetadata();
|
||||||
|
|
||||||
JsonHelper.SerializeToFile(metadataFile, appMetadata, SerializerContext.ApplicationMetadata);
|
using FileStream stream = File.Create(metadataFile, 4096, FileOptions.WriteThrough);
|
||||||
|
|
||||||
|
JsonHelper.Serialize(stream, appMetadata, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
appMetadata = JsonHelper.DeserializeFromFile(metadataFile, SerializerContext.ApplicationMetadata);
|
appMetadata = JsonHelper.DeserializeFromFile<ApplicationMetadata>(metadataFile);
|
||||||
}
|
}
|
||||||
catch (JsonException)
|
catch (JsonException)
|
||||||
{
|
{
|
||||||
|
@ -510,7 +510,9 @@ namespace Ryujinx.Ui.App.Common
|
||||||
{
|
{
|
||||||
modifyFunction(appMetadata);
|
modifyFunction(appMetadata);
|
||||||
|
|
||||||
JsonHelper.SerializeToFile(metadataFile, appMetadata, SerializerContext.ApplicationMetadata);
|
using FileStream stream = File.Create(metadataFile, 4096, FileOptions.WriteThrough);
|
||||||
|
|
||||||
|
JsonHelper.Serialize(stream, appMetadata, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return appMetadata;
|
return appMetadata;
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
using Ryujinx.Common.Utilities;
|
namespace Ryujinx.Ui.Common.Configuration
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Common.Configuration
|
|
||||||
{
|
{
|
||||||
[JsonConverter(typeof(TypedStringEnumConverter<AudioBackend>))]
|
|
||||||
public enum AudioBackend
|
public enum AudioBackend
|
||||||
{
|
{
|
||||||
Dummy,
|
Dummy,
|
||||||
|
|
|
@ -5,7 +5,7 @@ using Ryujinx.Common.Utilities;
|
||||||
using Ryujinx.Ui.Common.Configuration.System;
|
using Ryujinx.Ui.Common.Configuration.System;
|
||||||
using Ryujinx.Ui.Common.Configuration.Ui;
|
using Ryujinx.Ui.Common.Configuration.Ui;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text.Json.Nodes;
|
using System.IO;
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Common.Configuration
|
namespace Ryujinx.Ui.Common.Configuration
|
||||||
{
|
{
|
||||||
|
@ -321,14 +321,14 @@ namespace Ryujinx.Ui.Common.Configuration
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>Kept for file format compatibility (to avoid possible failure when parsing configuration on old versions)</remarks>
|
/// <remarks>Kept for file format compatibility (to avoid possible failure when parsing configuration on old versions)</remarks>
|
||||||
/// TODO: Remove this when those older versions aren't in use anymore.
|
/// TODO: Remove this when those older versions aren't in use anymore.
|
||||||
public List<JsonObject> KeyboardConfig { get; set; }
|
public List<object> KeyboardConfig { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Legacy controller control bindings
|
/// Legacy controller control bindings
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>Kept for file format compatibility (to avoid possible failure when parsing configuration on old versions)</remarks>
|
/// <remarks>Kept for file format compatibility (to avoid possible failure when parsing configuration on old versions)</remarks>
|
||||||
/// TODO: Remove this when those older versions aren't in use anymore.
|
/// TODO: Remove this when those older versions aren't in use anymore.
|
||||||
public List<JsonObject> ControllerConfig { get; set; }
|
public List<object> ControllerConfig { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Input configurations
|
/// Input configurations
|
||||||
|
@ -354,12 +354,11 @@ namespace Ryujinx.Ui.Common.Configuration
|
||||||
/// Loads a configuration file from disk
|
/// Loads a configuration file from disk
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">The path to the JSON configuration file</param>
|
/// <param name="path">The path to the JSON configuration file</param>
|
||||||
/// <param name="configurationFileFormat">Parsed configuration file</param>
|
|
||||||
public static bool TryLoad(string path, out ConfigurationFileFormat configurationFileFormat)
|
public static bool TryLoad(string path, out ConfigurationFileFormat configurationFileFormat)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
configurationFileFormat = JsonHelper.DeserializeFromFile(path, ConfigurationFileFormatSettings.SerializerContext.ConfigurationFileFormat);
|
configurationFileFormat = JsonHelper.DeserializeFromFile<ConfigurationFileFormat>(path);
|
||||||
|
|
||||||
return configurationFileFormat.Version != 0;
|
return configurationFileFormat.Version != 0;
|
||||||
}
|
}
|
||||||
|
@ -377,7 +376,8 @@ namespace Ryujinx.Ui.Common.Configuration
|
||||||
/// <param name="path">The path to the JSON configuration file</param>
|
/// <param name="path">The path to the JSON configuration file</param>
|
||||||
public void SaveConfig(string path)
|
public void SaveConfig(string path)
|
||||||
{
|
{
|
||||||
JsonHelper.SerializeToFile(path, this, ConfigurationFileFormatSettings.SerializerContext.ConfigurationFileFormat);
|
using FileStream fileStream = File.Create(path, 4096, FileOptions.WriteThrough);
|
||||||
|
JsonHelper.Serialize(fileStream, this, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
using Ryujinx.Common.Utilities;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Common.Configuration
|
|
||||||
{
|
|
||||||
internal static class ConfigurationFileFormatSettings
|
|
||||||
{
|
|
||||||
public static readonly ConfigurationJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Common.Configuration
|
|
||||||
{
|
|
||||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
|
||||||
[JsonSerializable(typeof(ConfigurationFileFormat))]
|
|
||||||
internal partial class ConfigurationJsonSerializerContext : JsonSerializerContext
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,7 +9,6 @@ using Ryujinx.Ui.Common.Configuration.Ui;
|
||||||
using Ryujinx.Ui.Common.Helper;
|
using Ryujinx.Ui.Common.Helper;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text.Json.Nodes;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Common.Configuration
|
namespace Ryujinx.Ui.Common.Configuration
|
||||||
{
|
{
|
||||||
|
@ -632,8 +631,8 @@ namespace Ryujinx.Ui.Common.Configuration
|
||||||
EnableKeyboard = Hid.EnableKeyboard,
|
EnableKeyboard = Hid.EnableKeyboard,
|
||||||
EnableMouse = Hid.EnableMouse,
|
EnableMouse = Hid.EnableMouse,
|
||||||
Hotkeys = Hid.Hotkeys,
|
Hotkeys = Hid.Hotkeys,
|
||||||
KeyboardConfig = new List<JsonObject>(),
|
KeyboardConfig = new List<object>(),
|
||||||
ControllerConfig = new List<JsonObject>(),
|
ControllerConfig = new List<object>(),
|
||||||
InputConfig = Hid.InputConfig,
|
InputConfig = Hid.InputConfig,
|
||||||
GraphicsBackend = Graphics.GraphicsBackend,
|
GraphicsBackend = Graphics.GraphicsBackend,
|
||||||
PreferredGpu = Graphics.PreferredGpu
|
PreferredGpu = Graphics.PreferredGpu
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
using Ryujinx.Common.Utilities;
|
namespace Ryujinx.Ui.Common.Configuration.System
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Common.Configuration.System
|
|
||||||
{
|
{
|
||||||
[JsonConverter(typeof(TypedStringEnumConverter<Language>))]
|
|
||||||
public enum Language
|
public enum Language
|
||||||
{
|
{
|
||||||
Japanese,
|
Japanese,
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
using Ryujinx.Common.Utilities;
|
namespace Ryujinx.Ui.Common.Configuration.System
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Common.Configuration.System
|
|
||||||
{
|
{
|
||||||
[JsonConverter(typeof(TypedStringEnumConverter<Region>))]
|
|
||||||
public enum Region
|
public enum Region
|
||||||
{
|
{
|
||||||
Japan,
|
Japan,
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Common.Models.Amiibo
|
|
||||||
{
|
|
||||||
public struct AmiiboApi : IEquatable<AmiiboApi>
|
|
||||||
{
|
|
||||||
[JsonPropertyName("name")]
|
|
||||||
public string Name { get; set; }
|
|
||||||
[JsonPropertyName("head")]
|
|
||||||
public string Head { get; set; }
|
|
||||||
[JsonPropertyName("tail")]
|
|
||||||
public string Tail { get; set; }
|
|
||||||
[JsonPropertyName("image")]
|
|
||||||
public string Image { get; set; }
|
|
||||||
[JsonPropertyName("amiiboSeries")]
|
|
||||||
public string AmiiboSeries { get; set; }
|
|
||||||
[JsonPropertyName("character")]
|
|
||||||
public string Character { get; set; }
|
|
||||||
[JsonPropertyName("gameSeries")]
|
|
||||||
public string GameSeries { get; set; }
|
|
||||||
[JsonPropertyName("type")]
|
|
||||||
public string Type { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("release")]
|
|
||||||
public Dictionary<string, string> Release { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("gamesSwitch")]
|
|
||||||
public List<AmiiboApiGamesSwitch> GamesSwitch { get; set; }
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetId()
|
|
||||||
{
|
|
||||||
return Head + Tail;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Equals(AmiiboApi other)
|
|
||||||
{
|
|
||||||
return Head + Tail == other.Head + other.Tail;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
return obj is AmiiboApi other && Equals(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return HashCode.Combine(Head, Tail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Common.Models.Amiibo
|
|
||||||
{
|
|
||||||
public class AmiiboApiGamesSwitch
|
|
||||||
{
|
|
||||||
[JsonPropertyName("amiiboUsage")]
|
|
||||||
public List<AmiiboApiUsage> AmiiboUsage { get; set; }
|
|
||||||
[JsonPropertyName("gameID")]
|
|
||||||
public List<string> GameId { get; set; }
|
|
||||||
[JsonPropertyName("gameName")]
|
|
||||||
public string GameName { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Common.Models.Amiibo
|
|
||||||
{
|
|
||||||
public class AmiiboApiUsage
|
|
||||||
{
|
|
||||||
[JsonPropertyName("Usage")]
|
|
||||||
public string Usage { get; set; }
|
|
||||||
[JsonPropertyName("write")]
|
|
||||||
public bool Write { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Common.Models.Amiibo
|
|
||||||
{
|
|
||||||
public struct AmiiboJson
|
|
||||||
{
|
|
||||||
[JsonPropertyName("amiibo")]
|
|
||||||
public List<AmiiboApi> Amiibo { get; set; }
|
|
||||||
[JsonPropertyName("lastUpdated")]
|
|
||||||
public DateTime LastUpdated { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Common.Models.Amiibo
|
|
||||||
{
|
|
||||||
[JsonSerializable(typeof(AmiiboJson))]
|
|
||||||
public partial class AmiiboJsonSerializerContext : JsonSerializerContext
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
namespace Ryujinx.Ui.Common.Models.Github
|
|
||||||
{
|
|
||||||
public class GithubReleaseAssetJsonResponse
|
|
||||||
{
|
|
||||||
public string Name { get; set; }
|
|
||||||
public string State { get; set; }
|
|
||||||
public string BrowserDownloadUrl { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Common.Models.Github
|
|
||||||
{
|
|
||||||
public class GithubReleasesJsonResponse
|
|
||||||
{
|
|
||||||
public string Name { get; set; }
|
|
||||||
public List<GithubReleaseAssetJsonResponse> Assets { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Common.Models.Github
|
|
||||||
{
|
|
||||||
[JsonSerializable(typeof(GithubReleasesJsonResponse), GenerationMode = JsonSourceGenerationMode.Metadata)]
|
|
||||||
public partial class GithubReleasesJsonSerializerContext : JsonSerializerContext
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,14 +2,14 @@ using Gtk;
|
||||||
using ICSharpCode.SharpZipLib.GZip;
|
using ICSharpCode.SharpZipLib.GZip;
|
||||||
using ICSharpCode.SharpZipLib.Tar;
|
using ICSharpCode.SharpZipLib.Tar;
|
||||||
using ICSharpCode.SharpZipLib.Zip;
|
using ICSharpCode.SharpZipLib.Zip;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Common.Utilities;
|
|
||||||
using Ryujinx.Ui;
|
using Ryujinx.Ui;
|
||||||
using Ryujinx.Ui.Common.Models.Github;
|
|
||||||
using Ryujinx.Ui.Widgets;
|
using Ryujinx.Ui.Widgets;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
@ -38,8 +38,6 @@ namespace Ryujinx.Modules
|
||||||
private static string _buildUrl;
|
private static string _buildUrl;
|
||||||
private static long _buildSize;
|
private static long _buildSize;
|
||||||
|
|
||||||
private static readonly GithubReleasesJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
|
||||||
|
|
||||||
// On Windows, GtkSharp.Dependencies adds these extra dirs that must be cleaned during updates.
|
// On Windows, GtkSharp.Dependencies adds these extra dirs that must be cleaned during updates.
|
||||||
private static readonly string[] WindowsDependencyDirs = new string[] { "bin", "etc", "lib", "share" };
|
private static readonly string[] WindowsDependencyDirs = new string[] { "bin", "etc", "lib", "share" };
|
||||||
|
|
||||||
|
@ -109,16 +107,22 @@ namespace Ryujinx.Modules
|
||||||
|
|
||||||
// Fetch latest build information
|
// Fetch latest build information
|
||||||
string fetchedJson = await jsonClient.GetStringAsync(buildInfoURL);
|
string fetchedJson = await jsonClient.GetStringAsync(buildInfoURL);
|
||||||
var fetched = JsonHelper.Deserialize(fetchedJson, SerializerContext.GithubReleasesJsonResponse);
|
JObject jsonRoot = JObject.Parse(fetchedJson);
|
||||||
_buildVer = fetched.Name;
|
JToken assets = jsonRoot["assets"];
|
||||||
|
|
||||||
foreach (var asset in fetched.Assets)
|
_buildVer = (string)jsonRoot["name"];
|
||||||
|
|
||||||
|
foreach (JToken asset in assets)
|
||||||
{
|
{
|
||||||
if (asset.Name.StartsWith("ryujinx") && asset.Name.EndsWith(_platformExt))
|
string assetName = (string)asset["name"];
|
||||||
{
|
string assetState = (string)asset["state"];
|
||||||
_buildUrl = asset.BrowserDownloadUrl;
|
string downloadURL = (string)asset["browser_download_url"];
|
||||||
|
|
||||||
if (asset.State != "uploaded")
|
if (assetName.StartsWith("ryujinx") && assetName.EndsWith(_platformExt))
|
||||||
|
{
|
||||||
|
_buildUrl = downloadURL;
|
||||||
|
|
||||||
|
if (assetState != "uploaded")
|
||||||
{
|
{
|
||||||
if (showVersionUpToDate)
|
if (showVersionUpToDate)
|
||||||
{
|
{
|
||||||
|
|
|
@ -31,7 +31,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
{
|
{
|
||||||
string patreonJsonString = await httpClient.GetStringAsync("https://patreon.ryujinx.org/");
|
string patreonJsonString = await httpClient.GetStringAsync("https://patreon.ryujinx.org/");
|
||||||
|
|
||||||
_patreonNamesText.Buffer.Text = string.Join(", ", JsonHelper.Deserialize(patreonJsonString, CommonJsonContext.Default.StringArray));
|
_patreonNamesText.Buffer.Text = string.Join(", ", JsonHelper.Deserialize<string[]>(patreonJsonString));
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,7 +3,6 @@ using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Utilities;
|
using Ryujinx.Common.Utilities;
|
||||||
using Ryujinx.Ui.Common.Configuration;
|
using Ryujinx.Ui.Common.Configuration;
|
||||||
using Ryujinx.Ui.Common.Models.Amiibo;
|
|
||||||
using Ryujinx.Ui.Widgets;
|
using Ryujinx.Ui.Widgets;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -12,15 +11,65 @@ using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json.Serialization;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using AmiiboApi = Ryujinx.Ui.Common.Models.Amiibo.AmiiboApi;
|
|
||||||
using AmiiboJsonSerializerContext = Ryujinx.Ui.Common.Models.Amiibo.AmiiboJsonSerializerContext;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Windows
|
namespace Ryujinx.Ui.Windows
|
||||||
{
|
{
|
||||||
public partial class AmiiboWindow : Window
|
public partial class AmiiboWindow : Window
|
||||||
{
|
{
|
||||||
|
private struct AmiiboJson
|
||||||
|
{
|
||||||
|
[JsonPropertyName("amiibo")]
|
||||||
|
public List<AmiiboApi> Amiibo { get; set; }
|
||||||
|
[JsonPropertyName("lastUpdated")]
|
||||||
|
public DateTime LastUpdated { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct AmiiboApi
|
||||||
|
{
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
[JsonPropertyName("head")]
|
||||||
|
public string Head { get; set; }
|
||||||
|
[JsonPropertyName("tail")]
|
||||||
|
public string Tail { get; set; }
|
||||||
|
[JsonPropertyName("image")]
|
||||||
|
public string Image { get; set; }
|
||||||
|
[JsonPropertyName("amiiboSeries")]
|
||||||
|
public string AmiiboSeries { get; set; }
|
||||||
|
[JsonPropertyName("character")]
|
||||||
|
public string Character { get; set; }
|
||||||
|
[JsonPropertyName("gameSeries")]
|
||||||
|
public string GameSeries { get; set; }
|
||||||
|
[JsonPropertyName("type")]
|
||||||
|
public string Type { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("release")]
|
||||||
|
public Dictionary<string, string> Release { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("gamesSwitch")]
|
||||||
|
public List<AmiiboApiGamesSwitch> GamesSwitch { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AmiiboApiGamesSwitch
|
||||||
|
{
|
||||||
|
[JsonPropertyName("amiiboUsage")]
|
||||||
|
public List<AmiiboApiUsage> AmiiboUsage { get; set; }
|
||||||
|
[JsonPropertyName("gameID")]
|
||||||
|
public List<string> GameId { get; set; }
|
||||||
|
[JsonPropertyName("gameName")]
|
||||||
|
public string GameName { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AmiiboApiUsage
|
||||||
|
{
|
||||||
|
[JsonPropertyName("Usage")]
|
||||||
|
public string Usage { get; set; }
|
||||||
|
[JsonPropertyName("write")]
|
||||||
|
public bool Write { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
private const string DEFAULT_JSON = "{ \"amiibo\": [] }";
|
private const string DEFAULT_JSON = "{ \"amiibo\": [] }";
|
||||||
|
|
||||||
public string AmiiboId { get; private set; }
|
public string AmiiboId { get; private set; }
|
||||||
|
@ -47,8 +96,6 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
private List<AmiiboApi> _amiiboList;
|
private List<AmiiboApi> _amiiboList;
|
||||||
|
|
||||||
private static readonly AmiiboJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
|
||||||
|
|
||||||
public AmiiboWindow() : base($"Ryujinx {Program.Version} - Amiibo")
|
public AmiiboWindow() : base($"Ryujinx {Program.Version} - Amiibo")
|
||||||
{
|
{
|
||||||
Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png");
|
Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png");
|
||||||
|
@ -80,9 +127,9 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
if (File.Exists(_amiiboJsonPath))
|
if (File.Exists(_amiiboJsonPath))
|
||||||
{
|
{
|
||||||
amiiboJsonString = await File.ReadAllTextAsync(_amiiboJsonPath);
|
amiiboJsonString = File.ReadAllText(_amiiboJsonPath);
|
||||||
|
|
||||||
if (await NeedsUpdate(JsonHelper.Deserialize(amiiboJsonString, SerializerContext.AmiiboJson).LastUpdated))
|
if (await NeedsUpdate(JsonHelper.Deserialize<AmiiboJson>(amiiboJsonString).LastUpdated))
|
||||||
{
|
{
|
||||||
amiiboJsonString = await DownloadAmiiboJson();
|
amiiboJsonString = await DownloadAmiiboJson();
|
||||||
}
|
}
|
||||||
|
@ -101,7 +148,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_amiiboList = JsonHelper.Deserialize(amiiboJsonString, SerializerContext.AmiiboJson).Amiibo;
|
_amiiboList = JsonHelper.Deserialize<AmiiboJson>(amiiboJsonString).Amiibo;
|
||||||
_amiiboList = _amiiboList.OrderBy(amiibo => amiibo.AmiiboSeries).ToList();
|
_amiiboList = _amiiboList.OrderBy(amiibo => amiibo.AmiiboSeries).ToList();
|
||||||
|
|
||||||
if (LastScannedAmiiboShowAll)
|
if (LastScannedAmiiboShowAll)
|
||||||
|
|
|
@ -115,8 +115,6 @@ namespace Ryujinx.Ui.Windows
|
||||||
private bool _mousePressed;
|
private bool _mousePressed;
|
||||||
private bool _middleMousePressed;
|
private bool _middleMousePressed;
|
||||||
|
|
||||||
private static readonly InputConfigJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
|
||||||
|
|
||||||
public ControllerWindow(MainWindow mainWindow, PlayerIndex controllerId) : this(mainWindow, new Builder("Ryujinx.Ui.Windows.ControllerWindow.glade"), controllerId) { }
|
public ControllerWindow(MainWindow mainWindow, PlayerIndex controllerId) : this(mainWindow, new Builder("Ryujinx.Ui.Windows.ControllerWindow.glade"), controllerId) { }
|
||||||
|
|
||||||
private ControllerWindow(MainWindow mainWindow, Builder builder, PlayerIndex controllerId) : base(builder.GetRawOwnedObject("_controllerWin"))
|
private ControllerWindow(MainWindow mainWindow, Builder builder, PlayerIndex controllerId) : base(builder.GetRawOwnedObject("_controllerWin"))
|
||||||
|
@ -1122,7 +1120,10 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
config = JsonHelper.DeserializeFromFile(path, SerializerContext.InputConfig);
|
using (Stream stream = File.OpenRead(path))
|
||||||
|
{
|
||||||
|
config = JsonHelper.Deserialize<InputConfig>(stream);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (JsonException) { }
|
catch (JsonException) { }
|
||||||
}
|
}
|
||||||
|
@ -1144,7 +1145,9 @@ namespace Ryujinx.Ui.Windows
|
||||||
if (profileDialog.Run() == (int)ResponseType.Ok)
|
if (profileDialog.Run() == (int)ResponseType.Ok)
|
||||||
{
|
{
|
||||||
string path = System.IO.Path.Combine(GetProfileBasePath(), profileDialog.FileName);
|
string path = System.IO.Path.Combine(GetProfileBasePath(), profileDialog.FileName);
|
||||||
string jsonString = JsonHelper.Serialize(inputConfig, SerializerContext.InputConfig);
|
string jsonString;
|
||||||
|
|
||||||
|
jsonString = JsonHelper.Serialize(inputConfig, true);
|
||||||
|
|
||||||
File.WriteAllText(path, jsonString);
|
File.WriteAllText(path, jsonString);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,15 @@ using LibHac.Tools.Fs;
|
||||||
using LibHac.Tools.FsSystem;
|
using LibHac.Tools.FsSystem;
|
||||||
using LibHac.Tools.FsSystem.NcaUtils;
|
using LibHac.Tools.FsSystem.NcaUtils;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Utilities;
|
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using Ryujinx.Ui.Widgets;
|
using Ryujinx.Ui.Widgets;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using GUI = Gtk.Builder.ObjectAttribute;
|
using System.Text;
|
||||||
|
|
||||||
|
using GUI = Gtk.Builder.ObjectAttribute;
|
||||||
|
using JsonHelper = Ryujinx.Common.Utilities.JsonHelper;
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Windows
|
namespace Ryujinx.Ui.Windows
|
||||||
{
|
{
|
||||||
|
@ -24,8 +26,6 @@ namespace Ryujinx.Ui.Windows
|
||||||
private readonly string _dlcJsonPath;
|
private readonly string _dlcJsonPath;
|
||||||
private readonly List<DownloadableContentContainer> _dlcContainerList;
|
private readonly List<DownloadableContentContainer> _dlcContainerList;
|
||||||
|
|
||||||
private static readonly DownloadableContentJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
|
||||||
|
|
||||||
#pragma warning disable CS0649, IDE0044
|
#pragma warning disable CS0649, IDE0044
|
||||||
[GUI] Label _baseTitleInfoLabel;
|
[GUI] Label _baseTitleInfoLabel;
|
||||||
[GUI] TreeView _dlcTreeView;
|
[GUI] TreeView _dlcTreeView;
|
||||||
|
@ -45,7 +45,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_dlcContainerList = JsonHelper.DeserializeFromFile(_dlcJsonPath, SerializerContext.ListDownloadableContentContainer);
|
_dlcContainerList = JsonHelper.DeserializeFromFile<List<DownloadableContentContainer>>(_dlcJsonPath);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@ -260,7 +260,10 @@ namespace Ryujinx.Ui.Windows
|
||||||
while (_dlcTreeView.Model.IterNext(ref parentIter));
|
while (_dlcTreeView.Model.IterNext(ref parentIter));
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonHelper.SerializeToFile(_dlcJsonPath, _dlcContainerList, SerializerContext.ListDownloadableContentContainer);
|
using (FileStream dlcJsonStream = File.Create(_dlcJsonPath, 4096, FileOptions.WriteThrough))
|
||||||
|
{
|
||||||
|
dlcJsonStream.Write(Encoding.UTF8.GetBytes(JsonHelper.Serialize(_dlcContainerList, true)));
|
||||||
|
}
|
||||||
|
|
||||||
Dispose();
|
Dispose();
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ using LibHac.Ns;
|
||||||
using LibHac.Tools.FsSystem;
|
using LibHac.Tools.FsSystem;
|
||||||
using LibHac.Tools.FsSystem.NcaUtils;
|
using LibHac.Tools.FsSystem.NcaUtils;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Utilities;
|
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using Ryujinx.HLE.HOS;
|
using Ryujinx.HLE.HOS;
|
||||||
using Ryujinx.Ui.Widgets;
|
using Ryujinx.Ui.Widgets;
|
||||||
|
@ -15,8 +14,10 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using GUI = Gtk.Builder.ObjectAttribute;
|
using System.Text;
|
||||||
using SpanHelpers = LibHac.Common.SpanHelpers;
|
|
||||||
|
using GUI = Gtk.Builder.ObjectAttribute;
|
||||||
|
using JsonHelper = Ryujinx.Common.Utilities.JsonHelper;
|
||||||
|
|
||||||
namespace Ryujinx.Ui.Windows
|
namespace Ryujinx.Ui.Windows
|
||||||
{
|
{
|
||||||
|
@ -30,7 +31,6 @@ namespace Ryujinx.Ui.Windows
|
||||||
private TitleUpdateMetadata _titleUpdateWindowData;
|
private TitleUpdateMetadata _titleUpdateWindowData;
|
||||||
|
|
||||||
private readonly Dictionary<RadioButton, string> _radioButtonToPathDictionary;
|
private readonly Dictionary<RadioButton, string> _radioButtonToPathDictionary;
|
||||||
private static readonly TitleUpdateMetadataJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
|
||||||
|
|
||||||
#pragma warning disable CS0649, IDE0044
|
#pragma warning disable CS0649, IDE0044
|
||||||
[GUI] Label _baseTitleInfoLabel;
|
[GUI] Label _baseTitleInfoLabel;
|
||||||
|
@ -53,7 +53,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_titleUpdateWindowData = JsonHelper.DeserializeFromFile(_updateJsonPath, SerializerContext.TitleUpdateMetadata);
|
_titleUpdateWindowData = JsonHelper.DeserializeFromFile<TitleUpdateMetadata>(_updateJsonPath);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@ -192,7 +192,10 @@ namespace Ryujinx.Ui.Windows
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonHelper.SerializeToFile(_updateJsonPath, _titleUpdateWindowData, SerializerContext.TitleUpdateMetadata);
|
using (FileStream dlcJsonStream = File.Create(_updateJsonPath, 4096, FileOptions.WriteThrough))
|
||||||
|
{
|
||||||
|
dlcJsonStream.Write(Encoding.UTF8.GetBytes(JsonHelper.Serialize(_titleUpdateWindowData, true)));
|
||||||
|
}
|
||||||
|
|
||||||
_parent.UpdateGameTable();
|
_parent.UpdateGameTable();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue