diff --git a/src/BizHawk.Client.Common/Controller.cs b/src/BizHawk.Client.Common/Controller.cs index 849ec2e519..1a5533b1b9 100644 --- a/src/BizHawk.Client.Common/Controller.cs +++ b/src/BizHawk.Client.Common/Controller.cs @@ -9,6 +9,8 @@ namespace BizHawk.Client.Common { public class Controller : IController { + public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; + public Controller(ControllerDefinition definition) { Definition = definition; diff --git a/src/BizHawk.Client.Common/DisplayManager/OSDManager.cs b/src/BizHawk.Client.Common/DisplayManager/OSDManager.cs index 234bd78ef4..464e654fe0 100644 --- a/src/BizHawk.Client.Common/DisplayManager/OSDManager.cs +++ b/src/BizHawk.Client.Common/DisplayManager/OSDManager.cs @@ -182,12 +182,12 @@ namespace BizHawk.Client.Common public string InputStrMovie() { - return MakeStringFor(_movieSession.MovieController); + return MakeStringFor(_movieSession.MovieController, cache: true); } public string InputStrImmediate() { - return MakeStringFor(_inputManager.AutofireStickyXorAdapter); + return MakeStringFor(_inputManager.AutofireStickyXorAdapter, cache: true); } public string InputPrevious() @@ -205,13 +205,19 @@ namespace BizHawk.Client.Common } public string InputStrOrAll() - => MakeStringFor(_movieSession.Movie.IsPlayingOrRecording() && _emulator.Frame > 0 - ? _inputManager.AutofireStickyXorAdapter.Or(_movieSession.Movie.GetInputState(_emulator.Frame - 1)) - : _inputManager.AutofireStickyXorAdapter); + => _movieSession.Movie.IsPlayingOrRecording() && _emulator.Frame > 0 + ? MakeStringFor(_inputManager.AutofireStickyXorAdapter.Or(_movieSession.Movie.GetInputState(_emulator.Frame - 1))) + : InputStrImmediate(); - private string MakeStringFor(IController controller) + private string MakeStringFor(IController controller, bool cache = false) { - return new Bk2InputDisplayGenerator(_emulator.SystemId, controller).Generate(); + var idg = controller.InputDisplayGenerator; + if (idg is null) + { + idg = new Bk2InputDisplayGenerator(_emulator.SystemId, controller); + if (cache) controller.InputDisplayGenerator = idg; + } + return idg.Generate(); } public string MakeIntersectImmediatePrevious() @@ -300,7 +306,8 @@ namespace BizHawk.Client.Common // basically we're tinting whatever is pressed because it's sticky specially // in order to achieve this we want to avoid drawing anything pink that isn't actually held down right now // so we make an AND adapter and combine it using immediate & sticky - var autoString = MakeStringFor(_inputManager.StickyXorAdapter.Source.Xor(_inputManager.AutofireStickyXorAdapter).And(_inputManager.AutofireStickyXorAdapter)); + // (adapter creation moved to InputManager) + var autoString = MakeStringFor(_inputManager.WeirdStickyControllerForInputDisplay, cache: true); g.DrawString(autoString, MessageFont, autoColor, point.X, point.Y); //recolor everything that's changed from the previous input diff --git a/src/BizHawk.Client.Common/controllers/AutofireController.cs b/src/BizHawk.Client.Common/controllers/AutofireController.cs index 6c7ff21e14..854562f323 100644 --- a/src/BizHawk.Client.Common/controllers/AutofireController.cs +++ b/src/BizHawk.Client.Common/controllers/AutofireController.cs @@ -9,6 +9,8 @@ namespace BizHawk.Client.Common { public class AutofireController : IController { + public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; + public AutofireController(IEmulator emulator, int on, int off) { On = on < 1 ? 0 : on; diff --git a/src/BizHawk.Client.Common/controllers/ClickyVirtualPadController.cs b/src/BizHawk.Client.Common/controllers/ClickyVirtualPadController.cs index cb9636d0d9..2c39ea7122 100644 --- a/src/BizHawk.Client.Common/controllers/ClickyVirtualPadController.cs +++ b/src/BizHawk.Client.Common/controllers/ClickyVirtualPadController.cs @@ -15,6 +15,8 @@ namespace BizHawk.Client.Common public ControllerDefinition Definition { get; set; } + public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; + public bool IsPressed(string button) => _pressed.Contains(button); public int AxisValue(string name) => 0; diff --git a/src/BizHawk.Client.Common/controllers/SimpleController.cs b/src/BizHawk.Client.Common/controllers/SimpleController.cs index 90565d8122..9eae0f18f9 100644 --- a/src/BizHawk.Client.Common/controllers/SimpleController.cs +++ b/src/BizHawk.Client.Common/controllers/SimpleController.cs @@ -13,6 +13,8 @@ namespace BizHawk.Client.Common { public ControllerDefinition Definition { get; } + public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; + protected WorkingDictionary Buttons { get; private set; } = new WorkingDictionary(); protected WorkingDictionary Axes { get; private set; } = new WorkingDictionary(); protected WorkingDictionary HapticFeedback { get; private set; } = new WorkingDictionary(); diff --git a/src/BizHawk.Client.Common/display/IInputDisplayGenerator.cs b/src/BizHawk.Client.Common/display/IInputDisplayGenerator.cs index 8bead2a010..8c641defe4 100644 --- a/src/BizHawk.Client.Common/display/IInputDisplayGenerator.cs +++ b/src/BizHawk.Client.Common/display/IInputDisplayGenerator.cs @@ -4,19 +4,11 @@ using BizHawk.Emulation.Common; namespace BizHawk.Client.Common { - public interface IInputDisplayGenerator - { - /// - /// Generates a display friendly version of the input log entry - /// - string Generate(); - } - /// /// An implementation of that /// uses .bk2 mnemonics as the basis for display /// - public class Bk2InputDisplayGenerator + public class Bk2InputDisplayGenerator : IInputDisplayGenerator { private readonly string _systemId; private readonly IController _source; diff --git a/src/BizHawk.Client.Common/inputAdapters/BitwiseAdapters.cs b/src/BizHawk.Client.Common/inputAdapters/BitwiseAdapters.cs index 6eddac0f04..d26fae5ab0 100644 --- a/src/BizHawk.Client.Common/inputAdapters/BitwiseAdapters.cs +++ b/src/BizHawk.Client.Common/inputAdapters/BitwiseAdapters.cs @@ -8,6 +8,8 @@ namespace BizHawk.Client.Common { public ControllerDefinition Definition => Source.Definition; + public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; + public bool IsPressed(string button) { if (Source != null && SourceAnd != null) @@ -34,6 +36,8 @@ namespace BizHawk.Client.Common { public ControllerDefinition Definition => Source.Definition; + public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; + public bool IsPressed(string button) { if (Source != null && SourceXor != null) @@ -60,6 +64,8 @@ namespace BizHawk.Client.Common { public ControllerDefinition Definition => Source.Definition; + public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; + public bool IsPressed(string button) { return (Source?.IsPressed(button) ?? false) diff --git a/src/BizHawk.Client.Common/inputAdapters/CopyController.cs b/src/BizHawk.Client.Common/inputAdapters/CopyController.cs index 7385fbec11..449e537370 100644 --- a/src/BizHawk.Client.Common/inputAdapters/CopyController.cs +++ b/src/BizHawk.Client.Common/inputAdapters/CopyController.cs @@ -11,6 +11,8 @@ namespace BizHawk.Client.Common { public ControllerDefinition Definition => Curr.Definition; + public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; + public bool IsPressed(string button) => Curr.IsPressed(button); public int AxisValue(string name) => Curr.AxisValue(name); diff --git a/src/BizHawk.Client.Common/inputAdapters/InputManager.cs b/src/BizHawk.Client.Common/inputAdapters/InputManager.cs index 7b1fe65644..81209ab2a2 100644 --- a/src/BizHawk.Client.Common/inputAdapters/InputManager.cs +++ b/src/BizHawk.Client.Common/inputAdapters/InputManager.cs @@ -24,13 +24,15 @@ namespace BizHawk.Client.Common private UdlrControllerAdapter UdLRControllerAdapter { get; } = new UdlrControllerAdapter(); - public AutoFireStickyXorAdapter AutofireStickyXorAdapter { get; } = new AutoFireStickyXorAdapter(); + public AutoFireStickyXorAdapter AutofireStickyXorAdapter { get; private set; } = new AutoFireStickyXorAdapter(); /// /// provides an opportunity to mutate the player's input in an autohold style /// public StickyXorAdapter StickyXorAdapter { get; } = new StickyXorAdapter(); + public IController WeirdStickyControllerForInputDisplay { get; private set; } + /// /// Used to AND to another controller, used for JoypadApi.Set /// @@ -72,8 +74,10 @@ namespace BizHawk.Client.Common UdLRControllerAdapter.Source = ActiveController.Or(AutoFireController); UdLRControllerAdapter.AllowUdlr = config.AllowUdlr; + // these are all reference types which don't change so this SHOULD be a no-op, but I'm not brave enough to move it to the ctor --yoshi StickyXorAdapter.Source = UdLRControllerAdapter; - AutofireStickyXorAdapter.Source = StickyXorAdapter; + AutofireStickyXorAdapter = new() { Source = StickyXorAdapter }; + WeirdStickyControllerForInputDisplay = StickyXorAdapter.Source.Xor(AutofireStickyXorAdapter).And(AutofireStickyXorAdapter); session.MovieIn = AutofireStickyXorAdapter; session.StickySource = AutofireStickyXorAdapter; diff --git a/src/BizHawk.Client.Common/inputAdapters/OverrideAdapter.cs b/src/BizHawk.Client.Common/inputAdapters/OverrideAdapter.cs index fd72390cb2..9373b86d92 100644 --- a/src/BizHawk.Client.Common/inputAdapters/OverrideAdapter.cs +++ b/src/BizHawk.Client.Common/inputAdapters/OverrideAdapter.cs @@ -13,6 +13,8 @@ namespace BizHawk.Client.Common { public ControllerDefinition Definition { get; private set; } + public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; + private readonly Dictionary _overrides = new Dictionary(); private readonly Dictionary _axisOverrides = new Dictionary(); private readonly List _inverses = new List(); diff --git a/src/BizHawk.Client.Common/inputAdapters/StickyAdapters.cs b/src/BizHawk.Client.Common/inputAdapters/StickyAdapters.cs index 988f7023e9..69fbeb89e1 100644 --- a/src/BizHawk.Client.Common/inputAdapters/StickyAdapters.cs +++ b/src/BizHawk.Client.Common/inputAdapters/StickyAdapters.cs @@ -15,6 +15,8 @@ namespace BizHawk.Client.Common { public ControllerDefinition Definition => Source.Definition; + public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; + public bool IsPressed(string button) { var source = Source.IsPressed(button); @@ -115,6 +117,8 @@ namespace BizHawk.Client.Common { public ControllerDefinition Definition => Source.Definition; + public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; + public bool IsPressed(string button) { var source = Source.IsPressed(button); diff --git a/src/BizHawk.Client.Common/inputAdapters/UDLRController.cs b/src/BizHawk.Client.Common/inputAdapters/UDLRController.cs index d65810f162..05cb48263e 100644 --- a/src/BizHawk.Client.Common/inputAdapters/UDLRController.cs +++ b/src/BizHawk.Client.Common/inputAdapters/UDLRController.cs @@ -15,6 +15,8 @@ namespace BizHawk.Client.Common public ControllerDefinition Definition => Source.Definition; + public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; + public bool AllowUdlr { get; set; } public bool IsPressed(string button) diff --git a/src/BizHawk.Client.Common/movie/bk2/Bk2Controller.cs b/src/BizHawk.Client.Common/movie/bk2/Bk2Controller.cs index b261b29fff..db66dce95e 100755 --- a/src/BizHawk.Client.Common/movie/bk2/Bk2Controller.cs +++ b/src/BizHawk.Client.Common/movie/bk2/Bk2Controller.cs @@ -25,6 +25,8 @@ namespace BizHawk.Client.Common }) .ToList(); + public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; + public Bk2Controller(string key, ControllerDefinition definition) : this(definition) { if (!string.IsNullOrEmpty(key)) diff --git a/src/BizHawk.Client.Common/movie/import/bkm/BkmControllerAdapter.cs b/src/BizHawk.Client.Common/movie/import/bkm/BkmControllerAdapter.cs index 0235bd8261..6734a7b62e 100644 --- a/src/BizHawk.Client.Common/movie/import/bkm/BkmControllerAdapter.cs +++ b/src/BizHawk.Client.Common/movie/import/bkm/BkmControllerAdapter.cs @@ -8,6 +8,8 @@ namespace BizHawk.Client.Common { internal class BkmControllerAdapter : IController { + public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; + public BkmControllerAdapter(ControllerDefinition definition, string systemId) { // We do need to map the definition name to the legacy diff --git a/src/BizHawk.Emulation.Common/Base Implementations/NullController.cs b/src/BizHawk.Emulation.Common/Base Implementations/NullController.cs index fdab4a2281..3017554fe5 100644 --- a/src/BizHawk.Emulation.Common/Base Implementations/NullController.cs +++ b/src/BizHawk.Emulation.Common/Base Implementations/NullController.cs @@ -14,6 +14,8 @@ namespace BizHawk.Emulation.Common { public ControllerDefinition Definition { get; } = new ControllerDefinition("Null Controller").MakeImmutable(); + public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; + public bool IsPressed(string button) => false; public int AxisValue(string name) => 0; diff --git a/src/BizHawk.Emulation.Common/ControllerDefinitionMerger.cs b/src/BizHawk.Emulation.Common/ControllerDefinitionMerger.cs index 683be0ed51..4d7fa28b82 100644 --- a/src/BizHawk.Emulation.Common/ControllerDefinitionMerger.cs +++ b/src/BizHawk.Emulation.Common/ControllerDefinitionMerger.cs @@ -70,6 +70,8 @@ namespace BizHawk.Emulation.Common private readonly IController _src; + public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; + public DummyController( IController src, IReadOnlyDictionary buttonAxisRemaps) diff --git a/src/BizHawk.Emulation.Common/Interfaces/IController.cs b/src/BizHawk.Emulation.Common/Interfaces/IController.cs index 0e17cec7a6..58da36b7da 100644 --- a/src/BizHawk.Emulation.Common/Interfaces/IController.cs +++ b/src/BizHawk.Emulation.Common/Interfaces/IController.cs @@ -11,6 +11,9 @@ namespace BizHawk.Emulation.Common /// ControllerDefinition Definition { get; } + /// used as cache by frontend; implement as autoprop w/ initial value + IInputDisplayGenerator InputDisplayGenerator { get; set; } + /// IReadOnlyCollection<(string Name, int Strength)> GetHapticsSnapshot(); diff --git a/src/BizHawk.Emulation.Common/Interfaces/IInputDisplayGenerator.cs b/src/BizHawk.Emulation.Common/Interfaces/IInputDisplayGenerator.cs new file mode 100644 index 0000000000..5987ae421c --- /dev/null +++ b/src/BizHawk.Emulation.Common/Interfaces/IInputDisplayGenerator.cs @@ -0,0 +1,10 @@ +namespace BizHawk.Emulation.Common +{ + public interface IInputDisplayGenerator + { + /// + /// Generates a display friendly version of the input log entry + /// + string Generate(); + } +} diff --git a/src/BizHawk.Emulation.Common/SaveController.cs b/src/BizHawk.Emulation.Common/SaveController.cs index ca268b909f..ff366e3c34 100644 --- a/src/BizHawk.Emulation.Common/SaveController.cs +++ b/src/BizHawk.Emulation.Common/SaveController.cs @@ -16,6 +16,8 @@ namespace BizHawk.Emulation.Common { private readonly WorkingDictionary _buttons = new WorkingDictionary(); + public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; + public SaveController() { Definition = null;