Source generated json serializers (#4582)

* Use source generated json serializers in order to improve code trimming

* Use strongly typed github releases model to fetch updates instead of raw Newtonsoft.Json parsing

* Use separate model for LogEventArgs serialization

* Make dynamic object formatter static. Fix string builder pooling.

* Do not inherit json version of LogEventArgs from EventArgs

* Fix extra space in object formatting

* Write log json directly to stream instead of using buffer writer

* Rebase fixes

* Rebase fixes

* Rebase fixes

* Enforce block-scoped namespaces in the solution. Convert style for existing code

* Apply suggestions from code review

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>

* Rebase indent fix

* Fix indent

* Delete unnecessary json properties

* Rebase fix

* Remove overridden json property names as they are handled in the options

* Apply suggestions from code review

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>

* Use default json options in github api calls

* Indentation and spacing fixes

* Fix json serialization

* Fix missing JsonConverter for config enums

* Add double \n\n after the whole string, not inside join

---------

Co-authored-by: TSRBerry <20988865+TSRBerry@users.noreply.github.com>
This commit is contained in:
Andrey Sukharev 2023-04-03 13:14:19 +03:00 committed by GitHub
parent 1b41b285ac
commit 3249f8ff41
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
77 changed files with 904 additions and 615 deletions

View file

@ -2,14 +2,14 @@ using Gtk;
using ICSharpCode.SharpZipLib.GZip;
using ICSharpCode.SharpZipLib.Tar;
using ICSharpCode.SharpZipLib.Zip;
using Newtonsoft.Json.Linq;
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using Ryujinx.Ui;
using Ryujinx.Ui.Common.Models.Github;
using Ryujinx.Ui.Widgets;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
@ -38,6 +38,8 @@ namespace Ryujinx.Modules
private static string _buildUrl;
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.
private static readonly string[] WindowsDependencyDirs = new string[] { "bin", "etc", "lib", "share" };
@ -107,22 +109,16 @@ namespace Ryujinx.Modules
// Fetch latest build information
string fetchedJson = await jsonClient.GetStringAsync(buildInfoURL);
JObject jsonRoot = JObject.Parse(fetchedJson);
JToken assets = jsonRoot["assets"];
var fetched = JsonHelper.Deserialize(fetchedJson, SerializerContext.GithubReleasesJsonResponse);
_buildVer = fetched.Name;
_buildVer = (string)jsonRoot["name"];
foreach (JToken asset in assets)
foreach (var asset in fetched.Assets)
{
string assetName = (string)asset["name"];
string assetState = (string)asset["state"];
string downloadURL = (string)asset["browser_download_url"];
if (assetName.StartsWith("ryujinx") && assetName.EndsWith(_platformExt))
if (asset.Name.StartsWith("ryujinx") && asset.Name.EndsWith(_platformExt))
{
_buildUrl = downloadURL;
_buildUrl = asset.BrowserDownloadUrl;
if (assetState != "uploaded")
if (asset.State != "uploaded")
{
if (showVersionUpToDate)
{

View file

@ -31,7 +31,7 @@ namespace Ryujinx.Ui.Windows
{
string patreonJsonString = await httpClient.GetStringAsync("https://patreon.ryujinx.org/");
_patreonNamesText.Buffer.Text = string.Join(", ", JsonHelper.Deserialize<string[]>(patreonJsonString));
_patreonNamesText.Buffer.Text = string.Join(", ", JsonHelper.Deserialize(patreonJsonString, CommonJsonContext.Default.StringArray));
}
catch
{

View file

@ -3,6 +3,7 @@ using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Utilities;
using Ryujinx.Ui.Common.Configuration;
using Ryujinx.Ui.Common.Models.Amiibo;
using Ryujinx.Ui.Widgets;
using System;
using System.Collections.Generic;
@ -11,65 +12,15 @@ using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Text;
using System.Text.Json.Serialization;
using System.Text.Json;
using System.Threading.Tasks;
using AmiiboApi = Ryujinx.Ui.Common.Models.Amiibo.AmiiboApi;
using AmiiboJsonSerializerContext = Ryujinx.Ui.Common.Models.Amiibo.AmiiboJsonSerializerContext;
namespace Ryujinx.Ui.Windows
{
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\": [] }";
public string AmiiboId { get; private set; }
@ -96,6 +47,8 @@ namespace Ryujinx.Ui.Windows
private List<AmiiboApi> _amiiboList;
private static readonly AmiiboJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
public AmiiboWindow() : base($"Ryujinx {Program.Version} - Amiibo")
{
Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png");
@ -127,9 +80,9 @@ namespace Ryujinx.Ui.Windows
if (File.Exists(_amiiboJsonPath))
{
amiiboJsonString = File.ReadAllText(_amiiboJsonPath);
amiiboJsonString = await File.ReadAllTextAsync(_amiiboJsonPath);
if (await NeedsUpdate(JsonHelper.Deserialize<AmiiboJson>(amiiboJsonString).LastUpdated))
if (await NeedsUpdate(JsonHelper.Deserialize(amiiboJsonString, SerializerContext.AmiiboJson).LastUpdated))
{
amiiboJsonString = await DownloadAmiiboJson();
}
@ -148,7 +101,7 @@ namespace Ryujinx.Ui.Windows
}
}
_amiiboList = JsonHelper.Deserialize<AmiiboJson>(amiiboJsonString).Amiibo;
_amiiboList = JsonHelper.Deserialize(amiiboJsonString, SerializerContext.AmiiboJson).Amiibo;
_amiiboList = _amiiboList.OrderBy(amiibo => amiibo.AmiiboSeries).ToList();
if (LastScannedAmiiboShowAll)

View file

@ -115,6 +115,8 @@ namespace Ryujinx.Ui.Windows
private bool _mousePressed;
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) { }
private ControllerWindow(MainWindow mainWindow, Builder builder, PlayerIndex controllerId) : base(builder.GetRawOwnedObject("_controllerWin"))
@ -1120,10 +1122,7 @@ namespace Ryujinx.Ui.Windows
try
{
using (Stream stream = File.OpenRead(path))
{
config = JsonHelper.Deserialize<InputConfig>(stream);
}
config = JsonHelper.DeserializeFromFile(path, SerializerContext.InputConfig);
}
catch (JsonException) { }
}
@ -1145,9 +1144,7 @@ namespace Ryujinx.Ui.Windows
if (profileDialog.Run() == (int)ResponseType.Ok)
{
string path = System.IO.Path.Combine(GetProfileBasePath(), profileDialog.FileName);
string jsonString;
jsonString = JsonHelper.Serialize(inputConfig, true);
string jsonString = JsonHelper.Serialize(inputConfig, SerializerContext.InputConfig);
File.WriteAllText(path, jsonString);
}

View file

@ -7,15 +7,13 @@ using LibHac.Tools.Fs;
using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE.FileSystem;
using Ryujinx.Ui.Widgets;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using GUI = Gtk.Builder.ObjectAttribute;
using JsonHelper = Ryujinx.Common.Utilities.JsonHelper;
using GUI = Gtk.Builder.ObjectAttribute;
namespace Ryujinx.Ui.Windows
{
@ -26,6 +24,8 @@ namespace Ryujinx.Ui.Windows
private readonly string _dlcJsonPath;
private readonly List<DownloadableContentContainer> _dlcContainerList;
private static readonly DownloadableContentJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
#pragma warning disable CS0649, IDE0044
[GUI] Label _baseTitleInfoLabel;
[GUI] TreeView _dlcTreeView;
@ -45,7 +45,7 @@ namespace Ryujinx.Ui.Windows
try
{
_dlcContainerList = JsonHelper.DeserializeFromFile<List<DownloadableContentContainer>>(_dlcJsonPath);
_dlcContainerList = JsonHelper.DeserializeFromFile(_dlcJsonPath, SerializerContext.ListDownloadableContentContainer);
}
catch
{
@ -260,10 +260,7 @@ namespace Ryujinx.Ui.Windows
while (_dlcTreeView.Model.IterNext(ref parentIter));
}
using (FileStream dlcJsonStream = File.Create(_dlcJsonPath, 4096, FileOptions.WriteThrough))
{
dlcJsonStream.Write(Encoding.UTF8.GetBytes(JsonHelper.Serialize(_dlcContainerList, true)));
}
JsonHelper.SerializeToFile(_dlcJsonPath, _dlcContainerList, SerializerContext.ListDownloadableContentContainer);
Dispose();
}

View file

@ -7,6 +7,7 @@ using LibHac.Ns;
using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS;
using Ryujinx.Ui.App.Common;
@ -15,10 +16,8 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using GUI = Gtk.Builder.ObjectAttribute;
using JsonHelper = Ryujinx.Common.Utilities.JsonHelper;
using GUI = Gtk.Builder.ObjectAttribute;
using SpanHelpers = LibHac.Common.SpanHelpers;
namespace Ryujinx.Ui.Windows
{
@ -32,6 +31,7 @@ namespace Ryujinx.Ui.Windows
private TitleUpdateMetadata _titleUpdateWindowData;
private readonly Dictionary<RadioButton, string> _radioButtonToPathDictionary;
private static readonly TitleUpdateMetadataJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
#pragma warning disable CS0649, IDE0044
[GUI] Label _baseTitleInfoLabel;
@ -54,7 +54,7 @@ namespace Ryujinx.Ui.Windows
try
{
_titleUpdateWindowData = JsonHelper.DeserializeFromFile<TitleUpdateMetadata>(_updateJsonPath);
_titleUpdateWindowData = JsonHelper.DeserializeFromFile(_updateJsonPath, SerializerContext.TitleUpdateMetadata);
}
catch
{
@ -193,10 +193,7 @@ namespace Ryujinx.Ui.Windows
}
}
using (FileStream dlcJsonStream = File.Create(_updateJsonPath, 4096, FileOptions.WriteThrough))
{
dlcJsonStream.Write(Encoding.UTF8.GetBytes(JsonHelper.Serialize(_titleUpdateWindowData, true)));
}
JsonHelper.SerializeToFile(_updateJsonPath, _titleUpdateWindowData, SerializerContext.TitleUpdateMetadata);
_parent.UpdateGameTable();