diff --git a/Assets/dll/bsnes.wbx.gz b/Assets/dll/bsnes.wbx.gz index 7cbe117119..b6a0a05389 100644 Binary files a/Assets/dll/bsnes.wbx.gz and b/Assets/dll/bsnes.wbx.gz differ diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesApi_Enums.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesApi_Enums.cs index e02d025153..5bf6157b44 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesApi_Enums.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesApi_Enums.cs @@ -25,10 +25,10 @@ Gamepad, Mouse, SuperMultitap, + Payload, SuperScope, Justifier, - Justifiers, - Payload + Justifiers } public enum ENTROPY diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesControllers.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesControllers.cs index c46817deec..ee4ebe6474 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesControllers.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesControllers.cs @@ -22,10 +22,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES LimitAnalogChangeSensitivity = ss.LimitAnalogChangeSensitivity }, BSNES_INPUT_DEVICE.SuperMultitap => new BsnesMultitapController(), + BSNES_INPUT_DEVICE.Payload => new BsnesPayloadController(), BSNES_INPUT_DEVICE.SuperScope => new BsnesSuperScopeController(), BSNES_INPUT_DEVICE.Justifier => new BsnesJustifierController(false), BSNES_INPUT_DEVICE.Justifiers => new BsnesJustifierController(true), - BSNES_INPUT_DEVICE.Payload => new BsnesPayloadController(), _ => throw new InvalidOperationException() }; } @@ -82,6 +82,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES ControllerDefinition Definition { get; } } + internal class BsnesUnpluggedController : IBsnesController + { + private static readonly ControllerDefinition _definition = new(); + + public ControllerDefinition Definition => _definition; + + public void UpdateState(IController controller) { } + + public short GetState(int index, int id) => 0; + } + internal class BsnesController : IBsnesController { private readonly bool[] _state = new bool[12]; @@ -131,7 +142,47 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES } } - public class BsnesMultitapController : IBsnesController + internal class BsnesMouseController : IBsnesController + { + private readonly short[] _state = new short[4]; + + private static readonly ControllerDefinition _definition = new ControllerDefinition + { BoolButtons = { "0Mouse Left", "0Mouse Right" } } + .AddXYPair("0Mouse {0}", AxisPairOrientation.RightAndDown, (-127).RangeTo(127), 0); //TODO verify direction against hardware, R+D inferred from behaviour in Mario Paint + + public ControllerDefinition Definition => _definition; + public bool LimitAnalogChangeSensitivity { get; init; } = true; + + public void UpdateState(IController controller) + { + int x = controller.AxisValue("0Mouse X"); + if (LimitAnalogChangeSensitivity) + { + x = x.Clamp(-10, 10); + } + _state[0] = (short) x; + + int y = controller.AxisValue("0Mouse Y"); + if (LimitAnalogChangeSensitivity) + { + y = y.Clamp(-10, 10); + } + _state[1] = (short) y; + + _state[2] = (short) (controller.IsPressed("0Mouse Left") ? 1 : 0); + _state[3] = (short) (controller.IsPressed("0Mouse Right") ? 1 : 0); + } + + public short GetState(int index, int id) + { + if (id >= 4) + return 0; + + return _state[id]; + } + } + + internal class BsnesMultitapController : IBsnesController { private readonly bool[,] _state = new bool[4, 12]; @@ -184,58 +235,38 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES } } - public class BsnesUnpluggedController : IBsnesController + internal class BsnesPayloadController : IBsnesController { - private static readonly ControllerDefinition _definition = new(); + private readonly bool[,] _state = new bool[2, 16]; + + private readonly int[] _buttonsOrder = {4, 5, 6, 7, 0, 8, 1, 9, 10, 11, 2, 3, 12, 13, 14, 15}; + + private static readonly ControllerDefinition _definition = new() + { + BoolButtons = Enumerable.Range(0, 32).Select(i => $"0B{i}").ToList() + }; public ControllerDefinition Definition => _definition; - public void UpdateState(IController controller) { } - - public short GetState(int index, int id) => 0; - } - - public class BsnesMouseController : IBsnesController - { - private readonly short[] _state = new short[4]; - - private static readonly ControllerDefinition _definition = new ControllerDefinition - { BoolButtons = { "0Mouse Left", "0Mouse Right" } } - .AddXYPair("0Mouse {0}", AxisPairOrientation.RightAndDown, (-127).RangeTo(127), 0); //TODO verify direction against hardware, R+D inferred from behaviour in Mario Paint - - public ControllerDefinition Definition => _definition; - public bool LimitAnalogChangeSensitivity { get; init; } = true; - public void UpdateState(IController controller) { - int x = controller.AxisValue("0Mouse X"); - if (LimitAnalogChangeSensitivity) + for (int index = 0; index < 2; index++) + for (int i = 0; i < 16; i++) { - x = x.Clamp(-10, 10); + _state[index, i] = controller.IsPressed(Definition.BoolButtons[index * 16 + _buttonsOrder[i]]); } - _state[0] = (short) x; - - int y = controller.AxisValue("0Mouse Y"); - if (LimitAnalogChangeSensitivity) - { - y = y.Clamp(-10, 10); - } - _state[1] = (short) y; - - _state[2] = (short) (controller.IsPressed("0Mouse Left") ? 1 : 0); - _state[3] = (short) (controller.IsPressed("0Mouse Right") ? 1 : 0); } public short GetState(int index, int id) { - if (id >= 4) + if (index >= 2 || id >= 16) return 0; - return _state[id]; + return (short) (_state[index, id] ? 1 : 0); } } - public class BsnesSuperScopeController : IBsnesController + internal class BsnesSuperScopeController : IBsnesController { private readonly short[] _state = new short[6]; @@ -264,7 +295,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES } } - public class BsnesJustifierController : IBsnesController + internal class BsnesJustifierController : IBsnesController { public BsnesJustifierController(bool chained) { @@ -307,32 +338,4 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES return _state[index * 4 + id]; } } - - internal class BsnesPayloadController : IBsnesController - { - private readonly bool[] _state = new bool[32]; - - private static readonly ControllerDefinition _definition = new() - { - BoolButtons = Enumerable.Range(0, 32).Select(i => $"0B{i}").ToList() - }; - - public ControllerDefinition Definition => _definition; - - public void UpdateState(IController controller) - { - for (int i = 0; i < 32; i++) - { - _state[i] = controller.IsPressed(Definition.BoolButtons[i]); - } - } - - public short GetState(int index, int id) - { - if (index >= 2 || id >= 16) - return 0; - - return (short) (_state[index * 2 + id] ? 1 : 0); - } - } } diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.cs index 6de9810386..79ba002c48 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.cs @@ -66,10 +66,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES generate_palette(); // TODO: massive random hack till waterboxhost gets fixed to support 5+ args ushort mergedBools = (ushort) ((_syncSettings.Hotfixes ? 1 << 8 : 0) | (_syncSettings.FastPPU ? 1 : 0)); - BsnesApi.BSNES_INPUT_DEVICE rightPort = _syncSettings.RightPort == BsnesApi.BSNES_INPUT_DEVICE.Payload - ? BsnesApi.BSNES_INPUT_DEVICE.SuperMultitap - : _syncSettings.RightPort; - Api.core.snes_init(_syncSettings.Entropy, _syncSettings.LeftPort, rightPort, mergedBools); + Api.core.snes_init(_syncSettings.Entropy, _syncSettings.LeftPort, _syncSettings.RightPort, mergedBools); Api.SetCallbacks(callbacks); // start up audio resampler diff --git a/waterbox/bsnescore/bsnes/sfc/controller/controller.cpp b/waterbox/bsnescore/bsnes/sfc/controller/controller.cpp index a68a03785d..2121f2ef68 100644 --- a/waterbox/bsnescore/bsnes/sfc/controller/controller.cpp +++ b/waterbox/bsnescore/bsnes/sfc/controller/controller.cpp @@ -41,7 +41,8 @@ auto ControllerPort::connect(uint deviceID) -> void { case ID::Device::None: device = new Controller(port); break; case ID::Device::Gamepad: device = new Gamepad(port); break; case ID::Device::Mouse: device = new Mouse(port); break; - case ID::Device::SuperMultitap: device = new SuperMultitap(port); break; + case ID::Device::SuperMultitap: device = new SuperMultitap(port, false); break; + case ID::Device::Payload: device = new SuperMultitap(port, true); break; case ID::Device::SuperScope: device = new SuperScope(port); break; case ID::Device::Justifier: device = new Justifier(port, false); break; case ID::Device::Justifiers: device = new Justifier(port, true); break; diff --git a/waterbox/bsnescore/bsnes/sfc/controller/gamepad/gamepad.cpp b/waterbox/bsnescore/bsnes/sfc/controller/gamepad/gamepad.cpp index bdef37e744..39067ff3e0 100644 --- a/waterbox/bsnescore/bsnes/sfc/controller/gamepad/gamepad.cpp +++ b/waterbox/bsnescore/bsnes/sfc/controller/gamepad/gamepad.cpp @@ -8,15 +8,16 @@ auto Gamepad::data() -> uint2 { if(latched == 1) return platform->inputPoll(port, ID::Device::Gamepad, B); //note: D-pad physically prevents up+down and left+right from being pressed at the same time + // patched this "fix" out because it is handled in bizhawk frontend and fixing it here does not seem right anyway switch(counter++) { case 0: return b; case 1: return y; case 2: return select; case 3: return start; - case 4: return up & !down; - case 5: return down & !up; - case 6: return left & !right; - case 7: return right & !left; + case 4: return up; + case 5: return down; + case 6: return left; + case 7: return right; case 8: return a; case 9: return x; case 10: return l; diff --git a/waterbox/bsnescore/bsnes/sfc/controller/super-multitap/super-multitap.cpp b/waterbox/bsnescore/bsnes/sfc/controller/super-multitap/super-multitap.cpp index 7ef141be4c..dac26320f8 100644 --- a/waterbox/bsnescore/bsnes/sfc/controller/super-multitap/super-multitap.cpp +++ b/waterbox/bsnescore/bsnes/sfc/controller/super-multitap/super-multitap.cpp @@ -1,4 +1,7 @@ -SuperMultitap::SuperMultitap(uint port) : Controller(port) { +SuperMultitap::SuperMultitap(uint port, bool isPayloadController) : +Controller(port), +isPayloadController(isPayloadController), +device(isPayloadController ? ID::Device::Payload : ID::Device::SuperMultitap) { latched = 0; counter1 = 0; counter2 = 0; @@ -12,14 +15,14 @@ auto SuperMultitap::data() -> uint2 { counter = counter1; if(counter >= 16) return 3; counter1++; - if(counter >= 12) return 0; + if(counter >= 12 && !isPayloadController) return 0; a = 0; //controller 2 b = 1; //controller 3 } else { counter = counter2; if(counter >= 16) return 3; counter2++; - if(counter >= 12) return 0; + if(counter >= 12 && !isPayloadController) return 0; a = 2; //controller 4 b = 3; //controller 5 } @@ -32,14 +35,18 @@ auto SuperMultitap::data() -> uint2 { case 1: return A.y << 0 | B.y << 1; case 2: return A.select << 0 | B.select << 1; case 3: return A.start << 0 | B.start << 1; - case 4: return (A.up & !A.down) << 0 | (B.up & !B.down) << 1; - case 5: return (A.down & !A.up) << 0 | (B.down & !B.up) << 1; - case 6: return (A.left & !A.right) << 0 | (B.left & !B.right) << 1; - case 7: return (A.right & !A.left) << 0 | (B.right & !B.left) << 1; + case 4: return A.up << 0 | B.up << 1; + case 5: return A.down << 0 | B.down << 1; + case 6: return A.left << 0 | B.left << 1; + case 7: return A.right << 0 | B.right << 1; case 8: return A.a << 0 | B.a << 1; case 9: return A.x << 0 | B.x << 1; case 10: return A.l << 0 | B.l << 1; case 11: return A.r << 0 | B.r << 1; + case 12: return A.extra1 << 0 | B.extra1 << 1; + case 13: return A.extra2 << 0 | B.extra2 << 1; + case 14: return A.extra3 << 0 | B.extra3 << 1; + case 15: return A.extra4 << 0 | B.extra4 << 1; } unreachable; } @@ -51,20 +58,26 @@ auto SuperMultitap::latch(bool data) -> void { counter2 = 0; if(latched == 0) { + uint offset = isPayloadController ? 16 : 12; for(uint id : range(4)) { auto& gamepad = gamepads[id]; - gamepad.b = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + B); - gamepad.y = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Y); - gamepad.select = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Select); - gamepad.start = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Start); - gamepad.up = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Up); - gamepad.down = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Down); - gamepad.left = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Left); - gamepad.right = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + Right); - gamepad.a = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + A); - gamepad.x = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + X); - gamepad.l = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + L); - gamepad.r = platform->inputPoll(port, ID::Device::SuperMultitap, id * 12 + R); + gamepad.b = platform->inputPoll(port, device, id * offset + B); + gamepad.y = platform->inputPoll(port, device, id * offset + Y); + gamepad.select = platform->inputPoll(port, device, id * offset + Select); + gamepad.start = platform->inputPoll(port, device, id * offset + Start); + gamepad.up = platform->inputPoll(port, device, id * offset + Up); + gamepad.down = platform->inputPoll(port, device, id * offset + Down); + gamepad.left = platform->inputPoll(port, device, id * offset + Left); + gamepad.right = platform->inputPoll(port, device, id * offset + Right); + gamepad.a = platform->inputPoll(port, device, id * offset + A); + gamepad.x = platform->inputPoll(port, device, id * offset + X); + gamepad.l = platform->inputPoll(port, device, id * offset + L); + gamepad.r = platform->inputPoll(port, device, id * offset + R); + if (!isPayloadController) continue; + gamepad.extra1 = platform->inputPoll(port, device, id * offset + Extra1); + gamepad.extra2 = platform->inputPoll(port, device, id * offset + Extra2); + gamepad.extra3 = platform->inputPoll(port, device, id * offset + Extra3); + gamepad.extra4 = platform->inputPoll(port, device, id * offset + Extra4); } } } diff --git a/waterbox/bsnescore/bsnes/sfc/controller/super-multitap/super-multitap.hpp b/waterbox/bsnescore/bsnes/sfc/controller/super-multitap/super-multitap.hpp index 7ab212739e..f78cdf1c3d 100644 --- a/waterbox/bsnescore/bsnes/sfc/controller/super-multitap/super-multitap.hpp +++ b/waterbox/bsnescore/bsnes/sfc/controller/super-multitap/super-multitap.hpp @@ -1,14 +1,16 @@ struct SuperMultitap : Controller { enum : uint { - Up, Down, Left, Right, B, A, Y, X, L, R, Select, Start, + Up, Down, Left, Right, B, A, Y, X, L, R, Select, Start, Extra1, Extra2, Extra3, Extra4 }; - SuperMultitap(uint port); + SuperMultitap(uint port, bool isPayloadController); auto data() -> uint2; auto latch(bool data) -> void; private: + bool isPayloadController; + uint device; bool latched; uint counter1; uint counter2; @@ -17,5 +19,6 @@ private: boolean b, y, select, start; boolean up, down, left, right; boolean a, x, l, r; + boolean extra1, extra2, extra3, extra4; } gamepads[4]; }; diff --git a/waterbox/bsnescore/bsnes/sfc/interface/interface.hpp b/waterbox/bsnescore/bsnes/sfc/interface/interface.hpp index d9437487a8..8d197d0af0 100644 --- a/waterbox/bsnescore/bsnes/sfc/interface/interface.hpp +++ b/waterbox/bsnescore/bsnes/sfc/interface/interface.hpp @@ -21,6 +21,7 @@ struct ID { Gamepad, Mouse, SuperMultitap, + Payload, SuperScope, Justifier, Justifiers, diff --git a/waterbox/bsnescore/bsnes/target-bsnescore/program.cpp b/waterbox/bsnescore/bsnes/target-bsnescore/program.cpp index e7eb7ef287..6174577364 100644 --- a/waterbox/bsnescore/bsnes/target-bsnescore/program.cpp +++ b/waterbox/bsnescore/bsnes/target-bsnescore/program.cpp @@ -455,6 +455,9 @@ auto Program::inputPoll(uint port, uint device, uint input) -> int16 if (device == ID::Device::SuperMultitap) { index = input / 12; id = input % 12; + } else if (device == ID::Device::Payload) { + index = input / 16; + id = input % 16; } else if (device == ID::Device::Justifiers) { index = input / 4; id = input % 4;