TASEmulators / BizHawk

BizHawk is a multi-system emulator written in C#. BizHawk provides nice features for casual gamers such as full screen, and joypad support in addition to full rerecording and debugging tools for all system cores.
http://tasvideos.org/BizHawk.html
Other
2.2k stars 385 forks source link

Switch from Newtonsoft.Json to System.Text.Json #3932

Open Morilli opened 5 months ago

Morilli commented 5 months ago

This switches the entire codebase from using Newtonsoft.Json to System.Text.Json. This is probably more future-proof, supported by .NET directly and uhh see #2261 I guess. It would be nice to be able to load older configs with less ugly exception boxes that delete your entire config if you don't read it carefully enough, and currently all 2.9.1 configs and .tasprojs will fail to load due to the EmuHawk->BizHawk.Client.EmuHawk assembly name change. Polymorphism and deserializing based on a given $type in the json is not really supported in System.Text.Json, but this is by design and for security reasons. I've changed the code to work without this parameter and because this $type caused the assembly name mismatches, this should also fix all config errors.

There's a couple caveats and potential failure cases here:

Now, having considered and handled most of the above points, some of those issues are hard to spot and/or invisible until an existing type is serialized and exhibits unexpected behavior or serialization failure.

TODO:

Check if completed:

kalimag commented 5 months ago

Tool settings can't be deserialized yet

System.ArgumentException
  HResult=0x80070057
  Message=Object of type 'System.Text.Json.JsonElement' cannot be converted to type 'BizHawk.Client.EmuHawk.LuaConsole+LuaConsoleSettings'.
  Source=mscorlib
  StackTrace:
   at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, Object[] index) in f:\dd\ndp\clr\src\BCL\system\reflection\propertyinfo.cs:line 643
   at BizHawk.Client.EmuHawk.ToolManager.InstallCustomConfig(IToolForm tool, Dictionary`2 data) in H:\Projekte\Visual Studio\BizHawk-upstream\src\BizHawk.Client.EmuHawk\tools\ToolManager.cs:line 422
   at BizHawk.Client.EmuHawk.ToolManager.Load[T](Boolean focus, String toolPath) in H:\Projekte\Visual Studio\BizHawk-upstream\src\BizHawk.Client.EmuHawk\tools\ToolManager.cs:line 145
   at BizHawk.Client.EmuHawk.MainForm.OpenLuaConsole() in H:\Projekte\Visual Studio\BizHawk-upstream\src\BizHawk.Client.EmuHawk\MainForm.cs:line 1543
   at BizHawk.Client.EmuHawk.MainForm.LuaConsoleMenuItem_Click(Object sender, EventArgs e) in H:\Projekte\Visual Studio\BizHawk-upstream\src\BizHawk.Client.EmuHawk\MainForm.Events.cs:line 1192
Morilli commented 5 months ago

Tool settings can't be deserialized yet

System.ArgumentException
  HResult=0x80070057
  Message=Object of type 'System.Text.Json.JsonElement' cannot be converted to type 'BizHawk.Client.EmuHawk.LuaConsole+LuaConsoleSettings'.
  Source=mscorlib
  StackTrace:
   at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, Object[] index) in f:\dd\ndp\clr\src\BCL\system\reflection\propertyinfo.cs:line 643
   at BizHawk.Client.EmuHawk.ToolManager.InstallCustomConfig(IToolForm tool, Dictionary`2 data) in H:\Projekte\Visual Studio\BizHawk-upstream\src\BizHawk.Client.EmuHawk\tools\ToolManager.cs:line 422
   at BizHawk.Client.EmuHawk.ToolManager.Load[T](Boolean focus, String toolPath) in H:\Projekte\Visual Studio\BizHawk-upstream\src\BizHawk.Client.EmuHawk\tools\ToolManager.cs:line 145
   at BizHawk.Client.EmuHawk.MainForm.OpenLuaConsole() in H:\Projekte\Visual Studio\BizHawk-upstream\src\BizHawk.Client.EmuHawk\MainForm.cs:line 1543
   at BizHawk.Client.EmuHawk.MainForm.LuaConsoleMenuItem_Click(Object sender, EventArgs e) in H:\Projekte\Visual Studio\BizHawk-upstream\src\BizHawk.Client.EmuHawk\MainForm.Events.cs:line 1192

should be fixed with the latest commit

kalimag commented 5 months ago

should be fixed with the latest commit

Seems to work. Some tools now fail with different errors:

System.NotSupportedException
  Message=Deserialization of types without a parameterless constructor, a singular parameterized constructor, or a parameterized constructor annotated with 'JsonConstructorAttribute' is not supported. Type 'BizHawk.Client.EmuHawk.RollColumn'. Path: $.Columns[0] | LineNumber: 2 | BytePositionInLine: 11.
  Source=System.Text.Json
  StackTrace:
   at System.Text.Json.JsonSerializer.Deserialize(JsonElement element, Type returnType, JsonSerializerOptions options) in /_/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Element.cs:line 63
   at BizHawk.Client.EmuHawk.ToolManager.InstallCustomConfig(IToolForm tool, Dictionary`2 data) in H:\Projekte\Visual Studio\BizHawk-upstream\src\BizHawk.Client.EmuHawk\tools\ToolManager.cs:line 407
   at BizHawk.Client.EmuHawk.ToolManager.Load[T](Boolean focus, String toolPath) in H:\Projekte\Visual Studio\BizHawk-upstream\src\BizHawk.Client.EmuHawk\tools\ToolManager.cs:line 145
   at BizHawk.Client.EmuHawk.MainForm.OpenLuaConsole() in H:\Projekte\Visual Studio\BizHawk-upstream\src\BizHawk.Client.EmuHawk\MainForm.cs:line 1543
   [...]
System.Text.Json.JsonException
  Message=The JSON value could not be converted to System.Drawing.Color. Path: $.Background | LineNumber: 1 | BytePositionInLine: 23.
  Source=System.Text.Json
  StackTrace:
   at System.Text.Json.JsonSerializer.Deserialize(JsonElement element, Type returnType, JsonSerializerOptions options) in /_/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Element.cs:line 63
   at BizHawk.Client.EmuHawk.ToolManager.InstallCustomConfig(IToolForm tool, Dictionary`2 data) in H:\Projekte\Visual Studio\BizHawk-upstream\src\BizHawk.Client.EmuHawk\tools\ToolManager.cs:line 407
   at BizHawk.Client.EmuHawk.ToolManager.Load[T](Boolean focus, String toolPath) in H:\Projekte\Visual Studio\BizHawk-upstream\src\BizHawk.Client.EmuHawk\tools\ToolManager.cs:line 145
   at BizHawk.Client.EmuHawk.MainForm.HexEditorMenuItem_Click(Object sender, EventArgs e) in H:\Projekte\Visual Studio\BizHawk-upstream\src\BizHawk.Client.EmuHawk\MainForm.Events.cs:line 1213
   [...]

  This exception was originally thrown at this call stack:
    System.Text.Json.ThrowHelper.ThrowInvalidOperationException_ExpectedString(System.Text.Json.JsonTokenType) in ThrowHelper.cs
    System.Text.Json.Utf8JsonReader.GetString() in Utf8JsonReader.TryGet.cs
    BizHawk.Emulation.Common.Json.TypeConverterJsonAdapter<T>.Read(ref System.Text.Json.Utf8JsonReader, System.Type, System.Text.Json.JsonSerializerOptions) in TypeConverterJsonAdapter.cs
    [...]

Inner Exception 1:
InvalidOperationException: Cannot get the value of a token type 'StartObject' as a string.
Morilli commented 5 months ago

^ That first error should be fixed with 16a8e923d4834de396df2a899ac8dfec3e0da3d1, and the second is due to an incorrect config generated from a commit without the TypeConverter handling, so you'll need to clear that part of the config and let it regenerate.

kalimag commented 5 months ago

^ That first error should be fixed with 16a8e92

The exception is gone, but the column display is broken because of the properties with private setters. This seems to work though:

[JsonConstructor]
private RollColumn(string name, string text, ColumnType type)
{
    Name = name;
    Text = text;
    Type = type;
}

and the second is due to an incorrect config generated from a commit without the TypeConverter handling, so you'll need to clear that part of the config and let it regenerate.

Right, my bad.

Morilli commented 5 months ago

You'll also need to clear the RollColumn config to let it regenerate, that did work fine when I tested it.

kalimag commented 5 months ago

Doesn't work for me

  1. Delete config
  2. Start BizHawk
  3. Open and close RAM Search
  4. Restart BizHawk
  5. Open RAM Search again
  6. RAM Search looks like this

image

  1. Close RAM Search and save config/close BizHawk
  2. Config section looks like this:
  "CustomToolSettings": {
    "BizHawk.Client.EmuHawk.RamSearch": {
      "Settings": {
        "Columns": [
          {
            "Width": 60,
            "Left": 0,
            "Right": 60,
            "Name": null,
            "Text": null,
            "Type": 0,
            "Visible": true,
            "Emphasis": false,
            "Rotatable": false
          }
        ],