some snes controller rough in
This commit is contained in:
parent
5ff7905752
commit
5b41b7260b
|
@ -108,6 +108,7 @@
|
|||
<Compile Include="BizInvoke\BizInvoker.cs" />
|
||||
<Compile Include="BizInvoke\DynamicLibraryImportResolver.cs" />
|
||||
<Compile Include="Base Implementations\CodeDataLog.cs" />
|
||||
<Compile Include="ControllerDefinitionMerger.cs" />
|
||||
<Compile Include="CoreAttributes.cs" />
|
||||
<Compile Include="CoreComms.cs" />
|
||||
<Compile Include="Database\CRC32.cs" />
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace BizHawk.Emulation.Common
|
||||
{
|
||||
// the idea here is that various connected peripherals have their controls all merged
|
||||
// into one definition, including logic to unmerge the data back so each one can work
|
||||
// with it without knowing what else is connected
|
||||
|
||||
public static class ControllerDefinitionMerger
|
||||
{
|
||||
private static string Allocate(string input, ref int plr, ref int plrnext)
|
||||
{
|
||||
int offset = int.Parse(input.Substring(0, 1));
|
||||
int currplr = plr + offset;
|
||||
if (currplr >= plrnext)
|
||||
plrnext = currplr + 1;
|
||||
return string.Format("P{0} {1}", currplr, input.Substring(1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// merge some controller definitions for different ports, and such. i promise to fully document this tomorrow
|
||||
/// </summary>
|
||||
/// <param name="Controllers"></param>
|
||||
/// <returns></returns>
|
||||
public static ControllerDefinition GetMerged(IEnumerable<ControllerDefinition> Controllers, out List<ControlDefUnMerger> Unmergers)
|
||||
{
|
||||
ControllerDefinition ret = new ControllerDefinition();
|
||||
Unmergers = new List<ControlDefUnMerger>();
|
||||
int plr = 1;
|
||||
int plrnext = 1;
|
||||
foreach (var def in Controllers)
|
||||
{
|
||||
Dictionary<string, string> remaps = new Dictionary<string, string>();
|
||||
|
||||
foreach (string s in def.BoolButtons)
|
||||
{
|
||||
string r = Allocate(s, ref plr, ref plrnext);
|
||||
ret.BoolButtons.Add(r);
|
||||
remaps[s] = r;
|
||||
}
|
||||
foreach (string s in def.FloatControls)
|
||||
{
|
||||
string r = Allocate(s, ref plr, ref plrnext);
|
||||
ret.FloatControls.Add(r);
|
||||
remaps[s] = r;
|
||||
}
|
||||
ret.FloatRanges.AddRange(def.FloatRanges);
|
||||
plr = plrnext;
|
||||
Unmergers.Add(new ControlDefUnMerger(remaps));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
public class ControlDefUnMerger
|
||||
{
|
||||
Dictionary<string, string> Remaps;
|
||||
|
||||
public ControlDefUnMerger(Dictionary<string, string> Remaps)
|
||||
{
|
||||
this.Remaps = Remaps;
|
||||
}
|
||||
|
||||
private class DummyController : IController
|
||||
{
|
||||
IController src;
|
||||
Dictionary<string, string> remaps;
|
||||
public DummyController(IController src, Dictionary<string, string> remaps)
|
||||
{
|
||||
this.src = src;
|
||||
this.remaps = remaps;
|
||||
}
|
||||
|
||||
public ControllerDefinition Definition { get { throw new NotImplementedException(); } }
|
||||
|
||||
public bool this[string button] { get { return IsPressed(button); } }
|
||||
|
||||
public bool IsPressed(string button)
|
||||
{
|
||||
return src.IsPressed(remaps[button]);
|
||||
}
|
||||
|
||||
public float GetFloat(string name)
|
||||
{
|
||||
return src.GetFloat(remaps[name]);
|
||||
}
|
||||
}
|
||||
|
||||
public IController UnMerge(IController c)
|
||||
{
|
||||
return new DummyController(c, Remaps);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -906,6 +906,7 @@
|
|||
<Compile Include="Consoles\Nintendo\SNES\LibsnesApi_Enums.cs" />
|
||||
<Compile Include="Consoles\Nintendo\SNES\LibsnesApi_QUERY.cs" />
|
||||
<Compile Include="Consoles\Nintendo\SNES\LibsnesApi_SIG.cs" />
|
||||
<Compile Include="Consoles\Nintendo\SNES\LibsnesControllerDeck.cs" />
|
||||
<Compile Include="Consoles\Nintendo\SNES\LibsnesCore.cs" />
|
||||
<Compile Include="Consoles\Nintendo\SNES\SnesColors.cs" />
|
||||
<Compile Include="Consoles\Nintendo\SNES\SNESGraphicsDecoder.cs" />
|
||||
|
|
|
@ -142,7 +142,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
this.Left = Left;
|
||||
this.Right = Right;
|
||||
List<ControlDefUnMerger> cdum;
|
||||
Definition = ControllerDefMerger.GetMerged(new[] { Left.GetDefinition(), Right.GetDefinition() }, out cdum);
|
||||
Definition = ControllerDefinitionMerger.GetMerged(new[] { Left.GetDefinition(), Right.GetDefinition() }, out cdum);
|
||||
LeftU = cdum[0];
|
||||
RightU = cdum[1];
|
||||
|
||||
|
@ -688,7 +688,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
{
|
||||
Player3 = ExpSlot;
|
||||
List<ControlDefUnMerger> cdum;
|
||||
Definition = ControllerDefMerger.GetMerged(
|
||||
Definition = ControllerDefinitionMerger.GetMerged(
|
||||
new[] { Player1.GetDefinition(), Player2.GetDefinition(), Player3.GetDefinition() }, out cdum);
|
||||
Definition.BoolButtons.Add("P2 Microphone");
|
||||
Player1U = cdum[0];
|
||||
|
@ -1131,101 +1131,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|||
}
|
||||
}
|
||||
|
||||
#region control definition adapters
|
||||
|
||||
// the idea here is that various connected peripherals have their controls all merged
|
||||
// into one definition, including logic to unmerge the data back so each one can work
|
||||
// with it without knowing what else is connected
|
||||
|
||||
public class ControlDefUnMerger
|
||||
{
|
||||
Dictionary<string, string> Remaps;
|
||||
|
||||
public ControlDefUnMerger(Dictionary<string, string> Remaps)
|
||||
{
|
||||
this.Remaps = Remaps;
|
||||
}
|
||||
|
||||
private class DummyController : IController
|
||||
{
|
||||
IController src;
|
||||
Dictionary<string, string> remaps;
|
||||
public DummyController(IController src, Dictionary<string, string> remaps)
|
||||
{
|
||||
this.src = src;
|
||||
this.remaps = remaps;
|
||||
}
|
||||
|
||||
public ControllerDefinition Definition { get { throw new NotImplementedException(); } }
|
||||
|
||||
public bool this[string button] { get { return IsPressed(button); } }
|
||||
|
||||
public bool IsPressed(string button)
|
||||
{
|
||||
return src.IsPressed(remaps[button]);
|
||||
}
|
||||
|
||||
public float GetFloat(string name)
|
||||
{
|
||||
return src.GetFloat(remaps[name]);
|
||||
}
|
||||
}
|
||||
|
||||
public IController UnMerge(IController c)
|
||||
{
|
||||
return new DummyController(c, Remaps);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class ControllerDefMerger
|
||||
{
|
||||
private static string Allocate(string input, ref int plr, ref int plrnext)
|
||||
{
|
||||
int offset = int.Parse(input.Substring(0, 1));
|
||||
int currplr = plr + offset;
|
||||
if (currplr >= plrnext)
|
||||
plrnext = currplr + 1;
|
||||
return string.Format("P{0} {1}", currplr, input.Substring(1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// handles all player number merging
|
||||
/// </summary>
|
||||
/// <param name="Controllers"></param>
|
||||
/// <returns></returns>
|
||||
public static ControllerDefinition GetMerged(IEnumerable<ControllerDefinition> Controllers, out List<ControlDefUnMerger> Unmergers)
|
||||
{
|
||||
ControllerDefinition ret = new ControllerDefinition();
|
||||
Unmergers = new List<ControlDefUnMerger>();
|
||||
int plr = 1;
|
||||
int plrnext = 1;
|
||||
foreach (var def in Controllers)
|
||||
{
|
||||
Dictionary<string, string> remaps = new Dictionary<string, string>();
|
||||
|
||||
foreach (string s in def.BoolButtons)
|
||||
{
|
||||
string r = Allocate(s, ref plr, ref plrnext);
|
||||
ret.BoolButtons.Add(r);
|
||||
remaps[s] = r;
|
||||
}
|
||||
foreach (string s in def.FloatControls)
|
||||
{
|
||||
string r = Allocate(s, ref plr, ref plrnext);
|
||||
ret.FloatControls.Add(r);
|
||||
remaps[s] = r;
|
||||
}
|
||||
ret.FloatRanges.AddRange(def.FloatRanges);
|
||||
plr = plrnext;
|
||||
Unmergers.Add(new ControlDefUnMerger(remaps));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region settings
|
||||
|
||||
public class NESControlSettings
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.SNES
|
||||
{
|
||||
public class LibsnesControllerDeck
|
||||
{
|
||||
public enum ControllerType
|
||||
{
|
||||
Unplugged,
|
||||
Gamepad,
|
||||
Multitap,
|
||||
Payload
|
||||
}
|
||||
|
||||
private static ILibsnesController Factory(ControllerType t)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case ControllerType.Unplugged: return new SnesUnpluggedController();
|
||||
case ControllerType.Gamepad: return new SnesController();
|
||||
case ControllerType.Multitap: return new SnesMultitapController();
|
||||
case ControllerType.Payload: return new SnesPayloadController();
|
||||
default: throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private readonly ILibsnesController[] _ports;
|
||||
private readonly ControlDefUnMerger[] _mergers;
|
||||
|
||||
public ControllerDefinition Definition { get; private set; }
|
||||
|
||||
public LibsnesControllerDeck(ControllerType left, ControllerType right)
|
||||
{
|
||||
_ports = new[] { Factory(left), Factory(right) };
|
||||
List<ControlDefUnMerger> tmp;
|
||||
Definition = ControllerDefinitionMerger.GetMerged(_ports.Select(p => p.Definition), out tmp);
|
||||
_mergers = tmp.ToArray();
|
||||
}
|
||||
|
||||
public void NativeInit(LibsnesApi api)
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
api.SetInputPortBeforeInit(i, _ports[i].PortType);
|
||||
}
|
||||
}
|
||||
|
||||
public ushort CoreInputState(IController controller, int port, int device, int index, int id)
|
||||
{
|
||||
return _ports[port].GetState(_mergers[port].UnMerge(controller), index, id);
|
||||
}
|
||||
}
|
||||
|
||||
public interface ILibsnesController
|
||||
{
|
||||
/// <summary>
|
||||
/// the type to pass back to the native init
|
||||
/// </summary>
|
||||
LibsnesApi.SNES_INPUT_PORT PortType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// respond to a native core poll
|
||||
/// </summary>
|
||||
/// <param name="controller">controller input from user, remapped</param>
|
||||
/// <param name="index">libsnes specific value, sometimes multitap number</param>
|
||||
/// <param name="id">libsnes specific value, sometimes button number</param>
|
||||
/// <returns></returns>
|
||||
ushort GetState(IController controller, int index, int id);
|
||||
|
||||
ControllerDefinition Definition { get; }
|
||||
|
||||
// due to the way things are implemented, right now, all of the ILibsnesControllers are stateless
|
||||
// but if one needed state, that would be doable
|
||||
// void SyncState(Serializer ser);
|
||||
}
|
||||
|
||||
public class SnesController : ILibsnesController
|
||||
{
|
||||
public LibsnesApi.SNES_INPUT_PORT PortType { get; } = LibsnesApi.SNES_INPUT_PORT.Joypad;
|
||||
|
||||
private static readonly string[] Buttons =
|
||||
{
|
||||
"0B",
|
||||
"0Y",
|
||||
"0Select",
|
||||
"0Start",
|
||||
"0Up",
|
||||
"0Down",
|
||||
"0Left",
|
||||
"0Right",
|
||||
"0A",
|
||||
"0X",
|
||||
"0L",
|
||||
"0R"
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition _definition = new ControllerDefinition
|
||||
{
|
||||
BoolButtons = Buttons.ToList()
|
||||
};
|
||||
|
||||
public ControllerDefinition Definition { get; } = _definition;
|
||||
|
||||
public ushort GetState(IController controller, int index, int id)
|
||||
{
|
||||
if (id >= 12)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return (ushort)(controller.IsPressed(Buttons[id]) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
public class SnesMultitapController: ILibsnesController
|
||||
{
|
||||
public LibsnesApi.SNES_INPUT_PORT PortType { get; } = LibsnesApi.SNES_INPUT_PORT.Multitap;
|
||||
|
||||
private static readonly string[] Buttons =
|
||||
{
|
||||
"B",
|
||||
"Y",
|
||||
"Select",
|
||||
"Start",
|
||||
"Up",
|
||||
"Down",
|
||||
"Left",
|
||||
"Right",
|
||||
"A",
|
||||
"X",
|
||||
"L",
|
||||
"R"
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition _definition = new ControllerDefinition
|
||||
{
|
||||
BoolButtons = Enumerable.Range(0, 4).SelectMany(i => Buttons.Select(b => i + b)).ToList()
|
||||
};
|
||||
|
||||
public ControllerDefinition Definition { get; } = _definition;
|
||||
|
||||
public ushort GetState(IController controller, int index, int id)
|
||||
{
|
||||
if (id >= 12)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return (ushort)(controller.IsPressed(index + Buttons[id]) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
public class SnesPayloadController : ILibsnesController
|
||||
{
|
||||
public LibsnesApi.SNES_INPUT_PORT PortType { get; } = LibsnesApi.SNES_INPUT_PORT.Multitap;
|
||||
|
||||
private static readonly ControllerDefinition _definition = new ControllerDefinition
|
||||
{
|
||||
BoolButtons = Enumerable.Range(0, 32).Select(i => "0B" + i).ToList()
|
||||
};
|
||||
|
||||
public ControllerDefinition Definition { get; } = _definition;
|
||||
|
||||
public ushort GetState(IController controller, int index, int id)
|
||||
{
|
||||
return (ushort)(controller.IsPressed("0B" + (index << 4 & 16 | id)) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
public class SnesUnpluggedController : ILibsnesController
|
||||
{
|
||||
public LibsnesApi.SNES_INPUT_PORT PortType { get; } = LibsnesApi.SNES_INPUT_PORT.None;
|
||||
|
||||
private static readonly ControllerDefinition _definition = new ControllerDefinition();
|
||||
|
||||
public ControllerDefinition Definition { get; } = _definition;
|
||||
|
||||
public ushort GetState(IController controller, int index, int id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue