Clean up `NESSyncSettings.InitialWRamStatePattern`

This commit is contained in:
James Groom 2024-02-01 15:10:02 +00:00 committed by GitHub
parent 7e8950ea52
commit 484e1fee78
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 96 additions and 12 deletions
src
BizHawk.Client.EmuHawk/config/NES
BizHawk.Emulation.Common
BizHawk.Emulation.Cores/Consoles/Nintendo/NES

View File

@ -49,10 +49,8 @@ namespace BizHawk.Client.EmuHawk
RegionComboBox.Items.AddRange(Enum.GetNames(typeof(NES.NESSyncSettings.Region)).Cast<object>().ToArray());
RegionComboBox.SelectedItem = Enum.GetName(typeof(NES.NESSyncSettings.Region), _syncSettings.RegionOverride);
if (_syncSettings.InitialWRamStatePattern is { Count: > 0 } initWRAMPattern)
{
RamPatternOverrideBox.Text = initWRAMPattern.BytesToHexString();
}
var initWRAMPattern = _syncSettings.InitialWRamStatePattern;
if (initWRAMPattern.Length is not 0) RamPatternOverrideBox.Text = initWRAMPattern.BytesToHexString();
}
private void CancelBtn_Click(object sender, EventArgs e)
@ -69,14 +67,14 @@ namespace BizHawk.Client.EmuHawk
typeof(NES.NESSyncSettings.Region),
(string)RegionComboBox.SelectedItem);
var oldRam = _syncSettings.InitialWRamStatePattern ?? new List<byte>();
var oldRam = _syncSettings.InitialWRamStatePattern;
if (!string.IsNullOrWhiteSpace(RamPatternOverrideBox.Text))
{
_syncSettings.InitialWRamStatePattern = Enumerable.Range(0, RamPatternOverrideBox.Text.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(RamPatternOverrideBox.Text.Substring(x, 2), 16))
.ToList();
.ToArray();
}
else
{
@ -85,7 +83,7 @@ namespace BizHawk.Client.EmuHawk
bool changed = (_dataTableDictionary != null && _dataTableDictionary.WasModified) ||
old != _syncSettings.RegionOverride ||
!(oldRam.SequenceEqual(_syncSettings.InitialWRamStatePattern ?? new List<byte>()));
!oldRam.SequenceEqual(_syncSettings.InitialWRamStatePattern);
DialogResult = DialogResult.OK;
if (changed)

View File

@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace BizHawk.Emulation.Common
{
/// <remarks>seems unnecessary, but suggested by <see href="https://www.newtonsoft.com/json/help/html/Performance.htm#JsonConverters">official docs</see> so sure why not</remarks>
public sealed class U8ArrayAsNormalJSONListResolver : DefaultContractResolver
{
public static readonly U8ArrayAsNormalJSONListResolver INSTANCE = new();
protected override JsonContract CreateContract(Type objectType)
{
var contract = base.CreateContract(objectType);
if (objectType == typeof(byte[])) contract.Converter = U8ArrayAsNormalJSONListConverter.INSTANCE;
return contract;
}
}
/// <remarks>based on <see href="https://stackoverflow.com/a/15228384">this SO answer</see></remarks>
public sealed class U8ArrayAsNormalJSONListConverter : JsonConverter<byte[]?>
{
public static readonly U8ArrayAsNormalJSONListConverter INSTANCE = new();
public override byte[]? ReadJson(JsonReader reader, Type objectType, byte[]? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if (reader.TokenType is JsonToken.Null) return null;
if (reader.TokenType is not JsonToken.StartArray) throw new Exception($"Unexpected token when reading bytes: expected {nameof(JsonToken.StartArray)}, got {reader.TokenType}");
List<byte> list = new();
while (reader.Read()) switch (reader.TokenType)
{
case JsonToken.Integer:
list.Add(reader.Value switch
{
byte b => b,
long l and >= byte.MinValue and <= byte.MaxValue => unchecked((byte) l),
var o => throw new Exception($"Integer literal outside u8 range: {o}")
});
continue;
case JsonToken.EndArray:
return list.ToArray();
case JsonToken.Comment:
continue;
default:
throw new Exception($"Unexpected token when reading bytes: {reader.TokenType}");
}
throw new Exception("Unexpected end when reading bytes");
}
public override void WriteJson(JsonWriter writer, byte[]? value, JsonSerializer serializer)
{
if (value is null)
{
writer.WriteNull();
return;
}
writer.WriteStartArray();
for (var i = 0; i < value.Length; i++) writer.WriteValue(value[i]);
writer.WriteEndArray();
}
}
}

View File

@ -227,11 +227,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
// apu has some specific power up bahaviour that we will emulate here
apu.NESHardReset();
if (SyncSettings.InitialWRamStatePattern != null && SyncSettings.InitialWRamStatePattern.Any())
var initWRAMPattern = SyncSettings.InitialWRamStatePattern;
if (initWRAMPattern.Length is not 0)
{
for (int i = 0; i < 0x800; i++)
{
ram[i] = SyncSettings.InitialWRamStatePattern[i % SyncSettings.InitialWRamStatePattern.Count];
ram[i] = initWRAMPattern[i % initWRAMPattern.Length];
}
}
else

View File

@ -1,9 +1,12 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using Newtonsoft.Json;
namespace BizHawk.Emulation.Cores.Nintendo.NES
{
public partial class NES : ISettable<NES.NESSettings, NES.NESSyncSettings>
@ -59,7 +62,25 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
public NESControlSettings Controls = new NESControlSettings();
public List<byte> InitialWRamStatePattern = null;
[JsonConverter(typeof(U8ArrayAsNormalJSONListConverter))] // this preserves the old behaviour of e,g, 0x1234ABCD --> [18,52,171,205]; omitting it will use base64 e.g. "EjSrzQ=="
[JsonProperty(PropertyName = nameof(InitialWRamStatePattern))]
private byte[]/*?*/ _initialWRamStatePattern = null;
[JsonIgnore]
public byte[] InitialWRamStatePattern
{
get
{
if (_initialWRamStatePattern is null) return Array.Empty<byte>();
if (_initialWRamStatePattern.Length is 0)
{
_initialWRamStatePattern = null;
return Array.Empty<byte>();
}
return _initialWRamStatePattern;
}
set => _initialWRamStatePattern = value.Length is 0 ? null : value;
}
public NESSyncSettings Clone()
{
@ -75,7 +96,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
return !(Util.DictionaryEqual(x.BoardProperties, y.BoardProperties)
&& x.RegionOverride == y.RegionOverride
&& !NESControlSettings.NeedsReboot(x.Controls, y.Controls)
&& ((x.InitialWRamStatePattern ?? new List<byte>()).SequenceEqual(y.InitialWRamStatePattern ?? new List<byte>()))
&& x.InitialWRamStatePattern.SequenceEqual(y.InitialWRamStatePattern)
&& x.VSDipswitches.Equals(y.VSDipswitches));
}