From ef7aa9f31cfebbeb67e7b5102ec8fc480f2d8ebf Mon Sep 17 00:00:00 2001 From: nattthebear Date: Sun, 31 May 2020 07:21:41 -0400 Subject: [PATCH] nyma pce: get 2 vs 6 button switch working Due to limitations in bizhawk, we represent mednafen "switch"es as a series of push buttons, one for each position on the switch --- .../Waterbox/NymaCore.Controller.cs | 69 ++++++++++++++++--- .../Waterbox/NymaCore.cs | 6 ++ 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.Controller.cs b/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.Controller.cs index e7237f75be..c241fb5177 100644 --- a/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.Controller.cs +++ b/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.Controller.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using BizHawk.Emulation.Common; using NymaTypes; @@ -20,7 +21,7 @@ namespace BizHawk.Emulation.Cores.Waterbox } protected delegate void ControllerThunk(IController c, byte[] b); - protected class ControllerAdapter + protected class ControllerAdapter : IBinaryStateable { /// /// allowed number of input ports. must match native @@ -52,6 +53,7 @@ namespace BizHawk.Emulation.Cores.Waterbox if (allPorts.Count > MAX_PORTS) throw new InvalidOperationException($"Too many input ports"); + var switchPreviousFrame = new List(); for (int port = 0, devByteStart = 0; port < allPorts.Count; port++, devByteStart += MAX_PORT_DATA) { var portInfo = allPorts[port]; @@ -100,6 +102,7 @@ namespace BizHawk.Emulation.Cores.Waterbox // var data = inputInfo.Extra.AsButton(); // TODO: Wire up data.ExcludeName ret.BoolButtons.Add(name); + ret.CategoryLabels[name] = category; _thunks.Add((c, b) => { if (c.IsPressed(name)) @@ -110,17 +113,41 @@ namespace BizHawk.Emulation.Cores.Waterbox case InputType.Switch: { var data = inputInfo.Extra.AsSwitch(); - var zzhacky = (int)data.DefaultPosition; - // TODO: Possibly bulebutton for 2 states? - // TODO: Motorcycle shift if we can't get sticky correct? - ret.AxisControls.Add(name); - ret.AxisRanges.Add(new ControllerDefinition.AxisRange( - 0, (int)data.DefaultPosition, (int)data.Positions.Count - 1)); + if (data.Positions.Count > 8) + throw new NotImplementedException("Need code changes to support Mdfn switch with more than 8 positions"); + + // fake switches as a series of push downs that select each state + // imagine the "gear" selector on a Toyota Prius + + var si = switchPreviousFrame.Count; + // [si]: position of this switch on the previous frame + switchPreviousFrame.Add((byte)data.DefaultPosition); + // [si + 1]: bit array of the previous state of each selector button + switchPreviousFrame.Add(0); + + var names = data.Positions.Select(p => $"{name}: Set {p.Name}").ToArray(); + foreach (var n in names) + { + ret.BoolButtons.Add(n); + ret.CategoryLabels[n] = category; + } + _thunks.Add((c, b) => { - // HACK: Silently discard this until bizhawk fixes its shit - // var val = (int)Math.Round(c.AxisValue(name)); - var val = zzhacky; + var val = _switchPreviousFrame[si]; + var allOldPressed = _switchPreviousFrame[si + 1]; + byte allNewPressed = 0; + for (var i = 0; i < names.Length; i++) + { + var mask = (byte)(1 << i); + var oldPressed = allOldPressed & mask; + var newPressed = c.IsPressed(names[i]) ? mask : (byte)0; + if (newPressed > oldPressed) + val = (byte)i; + allNewPressed |= newPressed; + } + _switchPreviousFrame[si] = val; + _switchPreviousFrame[si + 1] = allNewPressed; b[byteStart] |= (byte)(val << bitOffset); }); break; @@ -129,6 +156,7 @@ namespace BizHawk.Emulation.Cores.Waterbox { // var data = inputInfo.Extra.AsAxis(); ret.AxisControls.Add(name); + ret.CategoryLabels[name] = category; ret.AxisRanges.Add(new ControllerDefinition.AxisRange( 0, 0x8000, 0xffff, (inputInfo.Flags & AxisFlags.InvertCo) != 0 )); @@ -144,6 +172,7 @@ namespace BizHawk.Emulation.Cores.Waterbox { // var data = inputInfo.Extra.AsAxis(); ret.AxisControls.Add(name); + ret.CategoryLabels[name] = category; ret.AxisRanges.Add(new ControllerDefinition.AxisRange( -0x8000, 0, 0x7fff, (inputInfo.Flags & AxisFlags.InvertCo) != 0 )); @@ -177,7 +206,6 @@ namespace BizHawk.Emulation.Cores.Waterbox throw new NotImplementedException($"Unimplemented button type {inputInfo.Type}"); } } - ret.CategoryLabels[name] = category; } } ret.BoolButtons.Add("Power"); @@ -185,8 +213,11 @@ namespace BizHawk.Emulation.Cores.Waterbox Definition = ret; finalDevices.Add(null); Devices = finalDevices.ToArray(); + _switchPreviousFrame = switchPreviousFrame.ToArray(); } + private byte[] _switchPreviousFrame; + private readonly List> _thunks = new List>(); public void SetBits(IController src, byte[] dest) @@ -195,6 +226,22 @@ namespace BizHawk.Emulation.Cores.Waterbox foreach (var t in _thunks) t(src, dest); } + + private const ulong MAGIC = 9569546739673486731; + + public void SaveStateBinary(BinaryWriter writer) + { + writer.Write(MAGIC); + writer.Write(_switchPreviousFrame.Length); + writer.Write(_switchPreviousFrame); + } + + public void LoadStateBinary(BinaryReader reader) + { + if (reader.ReadUInt64() != MAGIC || reader.ReadInt32() != _switchPreviousFrame.Length) + throw new InvalidOperationException("Savestate corrupted!"); + reader.Read(_switchPreviousFrame, 0, _switchPreviousFrame.Length); + } } protected virtual IDictionary ButtonNameOverrides { get; }= new Dictionary(); diff --git a/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.cs b/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.cs index d6643dd2e7..557af479f5 100644 --- a/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.cs +++ b/src/BizHawk.Emulation.Cores/Waterbox/NymaCore.cs @@ -142,8 +142,14 @@ namespace BizHawk.Emulation.Cores.Waterbox return t; } + protected override void SaveStateBinaryInternal(BinaryWriter writer) + { + _controllerAdapter.SaveStateBinary(writer); + } + protected override void LoadStateBinaryInternal(BinaryReader reader) { + _controllerAdapter.LoadStateBinary(reader); _nyma.SetFrontendSettingQuery(_settingsQueryDelegate); if (_disks != null) _nyma.SetCDCallbacks(_cdTocCallback, _cdSectorCallback);