TASEmulators / TASEmulators/BizHawk

API Hawk: Cannot load configuration file when attempting to load persisted configurations for external tools.

Open
#3,337 3 comments 0 reactions 1 assignee View on GitHub

@nattthebear is already working on this.

Since Jul 25, 2022.

App: EmuHawk re: APIHawk Repro: Affects 2.9 dev Reproducible bug
Dominant language
C#
Stars
2.8k
Forks
468
PR merge metrics
No merged PRs in 30d

Description

Summary

If the external tool is opened at least once, and the external tool uses the following C# codes below, in theory, the configuration file config.ini will include information of the external tool.

[ConfigPersist]
public GeneticAlgorithmBotSettings Settings { get; set; }
public class GeneticAlgorithmBotSettings {
	public RecentFiles RecentBotFiles { get; set; } = new RecentFiles();
	public bool TurboWhenBotting { get; set; } = true;
	public bool InvisibleEmulation { get; set; }
}

Below is the snippet of the config.ini:

  ...

  "CommonToolSettings": {
    "BizHawk.Client.EmuHawk.TAStudio": {
      "_wndx": 543,
      "_wndy": 55,
      "Width": 525,
      "Height": 615,
      "SaveWindowPosition": true,
      "TopMost": false,
      "FloatingWindow": true,
      "AutoLoad": false
    },
    "GeneticAlgorithmBot.GeneticAlgorithmBot": {
      "_wndx": 1091,
      "_wndy": 149,
      "Width": 723,
      "Height": 626,
      "SaveWindowPosition": true,
      "TopMost": false,
      "FloatingWindow": true,
      "AutoLoad": false
    }
  },
  "CustomToolSettings": {
    "BizHawk.Client.EmuHawk.TAStudio": {
      "Settings": {
        "$type": "BizHawk.Client.EmuHawk.TAStudio+TAStudioSettings, EmuHawk",
        "RecentTas": {
          "recentlist": [],
          "MAX_RECENT_FILES": 8,
          "AutoLoad": false,
          "Frozen": false
        },
        "AutoPause": true,
        "AutoRestoreLastPosition": false,
        "FollowCursor": true,
        "EmptyMarkers": false,
        "ScrollSpeed": 6,
        "FollowCursorAlwaysScroll": false,
        "FollowCursorScrollMethod": "near",
        "BranchCellHoverInterval": 1,
        "SeekingCutoffInterval": 2,
        "AutosaveInterval": 120000,
        "AutosaveAsBk2": false,
        "AutosaveAsBackupFile": false,
        "BackupPerFileSave": false,
        "SingleClickAxisEdit": false,
        "OldControlSchemeForBranches": false,
        "LoadBranchOnDoubleClick": true,
        "DenoteStatesWithIcons": false,
        "DenoteStatesWithBGColor": true,
        "DenoteMarkersWithIcons": false,
        "DenoteMarkersWithBGColor": true,
        "MainVerticalSplitDistance": 0,
        "BranchMarkerSplitDistance": 183,
        "BindMarkersToInput": false,
        "CopyIncludesFrameNo": false,
        "Palette": {
          "CurrentFrame_InputLog": "181, 231, 247",
          "GreenZone_FrameCol": "221, 255, 221",
          "GreenZone_InputLog": "210, 249, 211",
          "GreenZone_InputLog_Stated": "196, 247, 200",
          "GreenZone_InputLog_Invalidated": "224, 251, 224",
          "LagZone_FrameCol": "255, 220, 221",
          "LagZone_InputLog": "244, 218, 218",
          "LagZone_InputLog_Stated": "240, 208, 210",
          "LagZone_InputLog_Invalidated": "247, 229, 229",
          "Marker_FrameCol": "247, 255, 201",
          "AnalogEdit_Col": "144, 144, 112"
        }
      },
      "TasViewFont": "Arial, 8.25pt, style=Bold"
    },
    "GeneticAlgorithmBot.GeneticAlgorithmBot": {
      "Settings": {
        "$type": "GeneticAlgorithmBot.GeneticAlgorithmBotSettings, GeneticAlgorithmBot",
        "RecentBotFiles": {
          "recentlist": [],
          "MAX_RECENT_FILES": 8,
          "AutoLoad": false,
          "Frozen": false
        },
        "TurboWhenBotting": true,
        "InvisibleEmulation": false
      }
    }
  },

  ...

I suspect that the formatting of the JSON object for CustomToolSettings and CommonToolSettings both didn't expect there to be an external tool reference if the external tool is using [ConfigPersist] attribute in the code.

Repro
  1. Use any blank C# project that is set up to create an external tool for BizHawk.
  2. Declare a class type with the [ConfigPersist] attribute and create a class type with any properties (int, float, or even RecentFiles class type).
  3. Build the external tool.
  4. Load the external tool in EmuHawk just 1 time.
  5. Close the external tool window (Important step!)
  6. Close EmuHawk.
  7. Open EmuHawk again.
  8. Observe crash.
Output

Full stack trace below:

It appears your config file (config.ini) is corrupted; an exception was thrown while loading it.
On closing this warning, EmuHawk will delete your config file and generate a new one. You can go make a backup now if you'd like to look into diffs.
The caught exception was:
System.InvalidOperationException: Config Error ---> Newtonsoft.Json.JsonSerializationException: Error resolving type specified in JSON 'GeneticAlgorithmBot.GeneticAlgorithmBotSettings, GeneticAlgorithmBot'. Path 'CustomToolSettings['GeneticAlgorithmBot.GeneticAlgorithmBot'].Settings.$type', line 1573, position 87. ---> Newtonsoft.Json.JsonSerializationException: Could not load assembly 'GeneticAlgorithmBot'.
   at Newtonsoft.Json.Serialization.DefaultSerializationBinder.GetTypeFromTypeNameKey(StructMultiKey`2 typeNameKey)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Newtonsoft.Json.Serialization.DefaultSerializationBinder.BindToType(String assemblyName, String typeName)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ResolveTypeName(JsonReader reader, Type& objectType, JsonContract& contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, String qualifiedTypeName)
   --- End of inner exception stack trace ---
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ResolveTypeName(JsonReader reader, Type& objectType, JsonContract& contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, String qualifiedTypeName)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadMetadataProperties(JsonReader reader, Type& objectType, JsonContract& contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue, Object& newValue, String& id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateDictionary(IDictionary dictionary, JsonReader reader, JsonDictionaryContract contract, JsonProperty containerProperty, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateDictionary(IDictionary dictionary, JsonReader reader, JsonDictionaryContract contract, JsonProperty containerProperty, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at BizHawk.Client.Common.ConfigService.Load[T](String filepath) in E:\LargeGithubProjects\BizHawk\src\BizHawk.Client.Common\config\ConfigService.cs:line 97
   --- End of inner exception stack trace ---
   at BizHawk.Client.Common.ConfigService.Load[T](String filepath) in E:\LargeGithubProjects\BizHawk\src\BizHawk.Client.Common\config\ConfigService.cs:line 102
   at BizHawk.Client.EmuHawk.Program.SubMain(String[] args)
Host env.
  • BizHawk dev build at 070e7035b3e3ad2b28c1a25b0506e4ba8975cf9c; Win10 Pro 21H1; Intel/NVIDIA

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.