Add a designated payload controller based on the multitapcontroller in the new bsnes core

- also patched out the left/right and up/down handling in the core, where it didn't belong
- also fixed the existing payloadcontroller because it wasn't working at all lol
This commit is contained in:
Morilli 2021-05-26 02:26:27 +02:00
parent 3c94000d3e
commit 38bc953e22
10 changed files with 120 additions and 98 deletions

Binary file not shown.

View File

@ -25,10 +25,10 @@
Gamepad,
Mouse,
SuperMultitap,
Payload,
SuperScope,
Justifier,
Justifiers,
Payload
Justifiers
}
public enum ENTROPY

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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];
};

View File

@ -21,6 +21,7 @@ struct ID {
Gamepad,
Mouse,
SuperMultitap,
Payload,
SuperScope,
Justifier,
Justifiers,

View File

@ -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;