From bef4dce42bcd9b3115ec21e0e07446c420f2620b Mon Sep 17 00:00:00 2001 From: Morilli <35152647+Morilli@users.noreply.github.com> Date: Wed, 16 Aug 2023 16:46:45 +0200 Subject: [PATCH] refactor InputDisplayGenerator and LogEntryGenerator handling --- .../Api/Classes/JoypadApi.cs | 2 +- .../Api/Classes/MovieApi.cs | 4 +- src/BizHawk.Client.Common/Controller.cs | 4 +- .../DisplayManager/OSDManager.cs | 20 ++++----- .../controllers/AutofireController.cs | 2 - .../controllers/ClickyVirtualPadController.cs | 2 - .../controllers/SimpleController.cs | 2 - .../display/IInputDisplayGenerator.cs | 35 ++++++++-------- .../inputAdapters/BitwiseAdapters.cs | 6 --- .../inputAdapters/CopyController.cs | 2 - .../inputAdapters/InputManager.cs | 14 +++++-- .../inputAdapters/OverrideAdapter.cs | 2 - .../inputAdapters/StickyAdapters.cs | 6 +-- .../inputAdapters/UDLRController.cs | 2 - .../movie/MovieSession.cs | 14 +++++-- .../movie/bk2/Bk2Controller.cs | 17 ++++---- .../movie/bk2/Bk2LogEntryGenerator.cs | 28 ++++--------- .../movie/bk2/Bk2Movie.InputLog.cs | 2 +- .../movie/bk2/Bk2Movie.cs | 33 ++++----------- .../movie/import/DsmImport.cs | 3 +- .../movie/import/FcmImport.cs | 2 +- .../movie/import/Fm2Import.cs | 4 +- .../movie/import/FmvImport.cs | 2 +- .../movie/import/GmvImport.cs | 2 +- .../movie/import/LsmvImport.cs | 10 ++--- .../movie/import/Mc2Import.cs | 2 +- .../movie/import/MmvImport.cs | 2 +- .../movie/import/PjmImport.cs | 5 ++- .../movie/import/SimpleLogEntryController.cs | 14 +++++++ .../movie/import/SmvImport.cs | 6 +-- .../movie/import/VbmImport.cs | 10 ++--- .../movie/import/YmvImport.cs | 4 +- .../movie/import/bkm/BkmControllerAdapter.cs | 5 ++- .../movie/interfaces/ILogEntryController.cs | 9 ++++ .../movie/interfaces/IMovie.cs | 11 ++--- .../movie/interfaces/IMovieController.cs | 2 +- .../movie/interfaces/IMovieSession.cs | 9 ++-- .../movie/interfaces/ITasMovie.cs | 4 +- .../movie/tasproj/TasClipboardEntry.cs | 8 ++-- .../movie/tasproj/TasMovie.Editing.cs | 41 ++++++++----------- .../movie/tasproj/TasMovie.cs | 2 +- .../tools/BasicBot/BasicBot.cs | 2 +- .../tools/Macros/MacroInput.ButtonSelect.cs | 3 +- .../tools/Macros/MovieZone.cs | 19 ++++----- .../tools/TAStudio/TAStudio.MenuItems.cs | 5 +-- .../tools/TAStudio/TAStudio.cs | 7 +--- .../ControllerDefinition.cs | 2 +- .../Base Implementations/NullController.cs | 7 ++-- .../ControllerDefinitionMerger.cs | 2 - .../Interfaces/IController.cs | 3 -- .../Interfaces/IInputDisplayGenerator.cs | 10 ----- .../SaveController.cs | 2 - .../SatellaviewFileTypeDetector.cs | 2 +- .../Display/InputDisplayTests.cs | 16 ++++---- 54 files changed, 189 insertions(+), 245 deletions(-) mode change 100755 => 100644 src/BizHawk.Client.Common/movie/bk2/Bk2Controller.cs mode change 100755 => 100644 src/BizHawk.Client.Common/movie/bk2/Bk2Movie.cs create mode 100644 src/BizHawk.Client.Common/movie/import/SimpleLogEntryController.cs create mode 100644 src/BizHawk.Client.Common/movie/interfaces/ILogEntryController.cs delete mode 100644 src/BizHawk.Emulation.Common/Interfaces/IInputDisplayGenerator.cs diff --git a/src/BizHawk.Client.Common/Api/Classes/JoypadApi.cs b/src/BizHawk.Client.Common/Api/Classes/JoypadApi.cs index 91b6aebb3d7..7bf0814c7ca 100644 --- a/src/BizHawk.Client.Common/Api/Classes/JoypadApi.cs +++ b/src/BizHawk.Client.Common/Api/Classes/JoypadApi.cs @@ -38,7 +38,7 @@ public IReadOnlyDictionary GetImmediate(int? controller = null) public void SetFromMnemonicStr(string inputLogEntry) { - var controller = _movieSession.GenerateMovieController(_inputManager.ActiveController.Definition); + var controller = _movieSession.GenerateMovieController(_inputManager.ActiveController.Definition, null); try { controller.SetFromMnemonic(inputLogEntry); diff --git a/src/BizHawk.Client.Common/Api/Classes/MovieApi.cs b/src/BizHawk.Client.Common/Api/Classes/MovieApi.cs index 04d75a2f1d0..177351acf4f 100644 --- a/src/BizHawk.Client.Common/Api/Classes/MovieApi.cs +++ b/src/BizHawk.Client.Common/Api/Classes/MovieApi.cs @@ -51,9 +51,7 @@ public string GetInputAsMnemonic(int frame) return string.Empty; } - var lg = _movieSession.Movie.LogGeneratorInstance( - _movieSession.Movie.GetInputState(frame)); - return lg.GenerateLogEntry(); + return _movieSession.Movie.GetInputState(frame).LogEntryGenerator.GenerateLogEntry(); } public void Save(string filename = null) diff --git a/src/BizHawk.Client.Common/Controller.cs b/src/BizHawk.Client.Common/Controller.cs index df66988c532..5f3c0dca13a 100644 --- a/src/BizHawk.Client.Common/Controller.cs +++ b/src/BizHawk.Client.Common/Controller.cs @@ -9,8 +9,6 @@ namespace BizHawk.Client.Common { public class Controller : IController { - public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; - public Controller(ControllerDefinition definition) { Definition = definition; @@ -180,4 +178,4 @@ public void BindAxis(string button, AnalogBind bind) .Select(kvp => kvp.Key) .ToList(); } -} \ No newline at end of file +} diff --git a/src/BizHawk.Client.Common/DisplayManager/OSDManager.cs b/src/BizHawk.Client.Common/DisplayManager/OSDManager.cs index fc307ad7eb6..7fad3d33a99 100644 --- a/src/BizHawk.Client.Common/DisplayManager/OSDManager.cs +++ b/src/BizHawk.Client.Common/DisplayManager/OSDManager.cs @@ -76,7 +76,7 @@ private string MakeFrameCounter() return sb.ToString(); } - + return _emulator.Frame.ToString(); } @@ -173,10 +173,10 @@ public void DrawMessages(IBlitter g) } public string InputStrMovie() - => MakeStringFor(_movieSession.MovieController, cache: true); + => MakeStringFor(_movieSession.MovieController); public string InputStrImmediate() - => MakeStringFor(_inputManager.AutofireStickyXorAdapter, cache: true); + => MakeStringFor(_inputManager.AutofireStickyXorAdapter); public string InputPrevious() { @@ -197,15 +197,9 @@ public string InputStrOrAll() ? MakeStringFor(_inputManager.AutofireStickyXorAdapter.Or(_movieSession.Movie.GetInputState(_emulator.Frame - 1))) : InputStrImmediate(); - private string MakeStringFor(IController controller, bool cache = false) + private string MakeStringFor(IController controller) { - var idg = controller.InputDisplayGenerator; - if (idg is null) - { - idg = new Bk2InputDisplayGenerator(_emulator.SystemId, controller); - if (cache) controller.InputDisplayGenerator = idg; - } - return idg.Generate(); + return _inputManager.InputDisplayGenerator.Generate(controller); } public string MakeIntersectImmediatePrevious() @@ -293,7 +287,7 @@ public void DrawScreenInfo(IBlitter g) // 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 // (adapter creation moved to InputManager) - var autoString = MakeStringFor(_inputManager.WeirdStickyControllerForInputDisplay, cache: true); + var autoString = MakeStringFor(_inputManager.WeirdStickyControllerForInputDisplay); g.DrawString(autoString, autoColor, point.X, point.Y); //recolor everything that's changed from the previous input @@ -355,4 +349,4 @@ public void DrawScreenInfo(IBlitter g) } } } -} \ No newline at end of file +} diff --git a/src/BizHawk.Client.Common/controllers/AutofireController.cs b/src/BizHawk.Client.Common/controllers/AutofireController.cs index 34d377f2410..c11810fda23 100644 --- a/src/BizHawk.Client.Common/controllers/AutofireController.cs +++ b/src/BizHawk.Client.Common/controllers/AutofireController.cs @@ -9,8 +9,6 @@ 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 2c39ea71228..cb9636d0d98 100644 --- a/src/BizHawk.Client.Common/controllers/ClickyVirtualPadController.cs +++ b/src/BizHawk.Client.Common/controllers/ClickyVirtualPadController.cs @@ -15,8 +15,6 @@ public class ClickyVirtualPadController : IController 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 59542794253..a2e2b141fda 100644 --- a/src/BizHawk.Client.Common/controllers/SimpleController.cs +++ b/src/BizHawk.Client.Common/controllers/SimpleController.cs @@ -13,8 +13,6 @@ public class SimpleController : IController { 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 ef6c1cdf2a7..5cd569afbb8 100644 --- a/src/BizHawk.Client.Common/display/IInputDisplayGenerator.cs +++ b/src/BizHawk.Client.Common/display/IInputDisplayGenerator.cs @@ -8,37 +8,40 @@ namespace BizHawk.Client.Common { /// - /// An implementation of that - /// uses .bk2 mnemonics as the basis for display + /// Generates a display friendly version of the input log entry + /// using .bk2 mnemonics as the basis for display /// - public class Bk2InputDisplayGenerator : IInputDisplayGenerator + public class Bk2InputDisplayGenerator { /// either Range or Mnemonic is always non-null private readonly IReadOnlyList<(string Name, AxisSpec? Range, char? Mnemonic)> _cachedInputSpecs; + private readonly ControllerDefinition _sourceDefinition; - private readonly IController _source; - - public Bk2InputDisplayGenerator(string systemId, IController source) + public Bk2InputDisplayGenerator(string systemId, ControllerDefinition sourceDefinition) { - const string ERR_MSG = nameof(ControllerDefinition.OrderedControlsFlat) + "/" + nameof(ControllerDefinition.ControlsOrdered) + " contains an input name which is neither a button nor an axis"; - _cachedInputSpecs = source.Definition.OrderedControlsFlat.Select(button => + const string ERR_MSG = $"{nameof(ControllerDefinition.OrderedControlsFlat)}/{nameof(ControllerDefinition.ControlsOrdered)} contains an input name which is neither a button nor an axis: {{0}}"; + _cachedInputSpecs = sourceDefinition.OrderedControlsFlat.Select(button => { - if (source.Definition.Axes.TryGetValue(button, out var range)) return (button, range, null); - if (source.Definition.BoolButtons.Contains(button)) return (button, (AxisSpec?) null, (char?) Bk2MnemonicLookup.Lookup(button, systemId)); - throw new Exception(ERR_MSG); - }).ToList(); - _source = source; + if (sourceDefinition.Axes.TryGetValue(button, out var range)) return (button, range, null); + if (sourceDefinition.BoolButtons.Contains(button)) return (button, (AxisSpec?) null, (char?) Bk2MnemonicLookup.Lookup(button, systemId)); + throw new InvalidOperationException(string.Format(ERR_MSG, button)); + }).ToArray(); + _sourceDefinition = sourceDefinition; } - public string Generate() + public string Generate(IController source) { +#if DEBUG + if (!_sourceDefinition.OrderedControlsFlat.SequenceEqual(source.Definition.OrderedControlsFlat)) + throw new InvalidOperationException("Attempting to generate input display string for mismatched controller definition!"); +#endif var sb = new StringBuilder(); foreach (var (button, range, mnemonicChar) in _cachedInputSpecs) { if (range is not null) { - var val = _source.AxisValue(button); + var val = source.AxisValue(button); if (val == range.Value.Neutral) { @@ -51,7 +54,7 @@ public string Generate() } else { - sb.Append(_source.IsPressed(button) + sb.Append(source.IsPressed(button) ? mnemonicChar.Value : ' '); } diff --git a/src/BizHawk.Client.Common/inputAdapters/BitwiseAdapters.cs b/src/BizHawk.Client.Common/inputAdapters/BitwiseAdapters.cs index d26fae5ab03..6eddac0f049 100644 --- a/src/BizHawk.Client.Common/inputAdapters/BitwiseAdapters.cs +++ b/src/BizHawk.Client.Common/inputAdapters/BitwiseAdapters.cs @@ -8,8 +8,6 @@ public class AndAdapter : IInputAdapter { public ControllerDefinition Definition => Source.Definition; - public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; - public bool IsPressed(string button) { if (Source != null && SourceAnd != null) @@ -36,8 +34,6 @@ public class XorAdapter : IInputAdapter { public ControllerDefinition Definition => Source.Definition; - public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; - public bool IsPressed(string button) { if (Source != null && SourceXor != null) @@ -64,8 +60,6 @@ public class ORAdapter : IInputAdapter { 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 449e5373703..7385fbec114 100644 --- a/src/BizHawk.Client.Common/inputAdapters/CopyController.cs +++ b/src/BizHawk.Client.Common/inputAdapters/CopyController.cs @@ -11,8 +11,6 @@ public class CopyControllerAdapter : IInputAdapter { 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 edf2174518b..9914b0d4e5f 100644 --- a/src/BizHawk.Client.Common/inputAdapters/InputManager.cs +++ b/src/BizHawk.Client.Common/inputAdapters/InputManager.cs @@ -13,6 +13,8 @@ namespace BizHawk.Client.Common // (1)->Input Display public class InputManager { + public Bk2InputDisplayGenerator InputDisplayGenerator { get; private set; } + // the original source controller, bound to the user, sort of the "input" port for the chain, i think public Controller ActiveController { get; private set; } @@ -51,9 +53,15 @@ public class InputManager public Func<(Point Pos, long Scroll, bool LMB, bool MMB, bool RMB, bool X1MB, bool X2MB)> GetMainFormMouseInfo { get; set; } + private void SetActiveController(Controller controller, string systemId) + { + ActiveController = controller; + InputDisplayGenerator = new Bk2InputDisplayGenerator(systemId, ActiveController.Definition); + } + public void ResetMainControllers(AutofireController nullAutofireController) { - ActiveController = new(NullController.Instance.Definition); + SetActiveController(new Controller(NullController.Instance.Definition), VSystemID.Raw.NULL); AutoFireController = nullAutofireController; } @@ -61,7 +69,7 @@ public void SyncControls(IEmulator emulator, IMovieSession session, Config confi { var def = emulator.ControllerDefinition; - ActiveController = BindToDefinition(def, config.AllTrollers, config.AllTrollersAnalog, config.AllTrollersFeedbacks); + SetActiveController(BindToDefinition(def, config.AllTrollers, config.AllTrollersAnalog, config.AllTrollersFeedbacks), emulator.SystemId); AutoFireController = BindToDefinitionAF(emulator, config.AllTrollersAutoFire, config.AutofireOn, config.AutofireOff); // allow propagating controls that are in the current controller definition but not in the prebaked one @@ -156,4 +164,4 @@ private static AutofireController BindToDefinitionAF( return ret; } } -} \ No newline at end of file +} diff --git a/src/BizHawk.Client.Common/inputAdapters/OverrideAdapter.cs b/src/BizHawk.Client.Common/inputAdapters/OverrideAdapter.cs index d4dee4e1423..fd8bbff6e08 100644 --- a/src/BizHawk.Client.Common/inputAdapters/OverrideAdapter.cs +++ b/src/BizHawk.Client.Common/inputAdapters/OverrideAdapter.cs @@ -13,8 +13,6 @@ public class OverrideAdapter : IController { 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 69fbeb89e19..83177b94c2f 100644 --- a/src/BizHawk.Client.Common/inputAdapters/StickyAdapters.cs +++ b/src/BizHawk.Client.Common/inputAdapters/StickyAdapters.cs @@ -15,8 +15,6 @@ public class StickyXorAdapter : IStickyAdapter { public ControllerDefinition Definition => Source.Definition; - public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; - public bool IsPressed(string button) { var source = Source.IsPressed(button); @@ -117,8 +115,6 @@ public class AutoFireStickyXorAdapter : IStickyAdapter, IInputAdapter { public ControllerDefinition Definition => Source.Definition; - public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; - public bool IsPressed(string button) { var source = Source.IsPressed(button); @@ -229,4 +225,4 @@ public void MassToggleStickyState(List buttons) _justPressed = buttons; } } -} \ No newline at end of file +} diff --git a/src/BizHawk.Client.Common/inputAdapters/UDLRController.cs b/src/BizHawk.Client.Common/inputAdapters/UDLRController.cs index 05b4cc41d14..f9e4152cfac 100644 --- a/src/BizHawk.Client.Common/inputAdapters/UDLRController.cs +++ b/src/BizHawk.Client.Common/inputAdapters/UDLRController.cs @@ -17,8 +17,6 @@ public class UdlrControllerAdapter : IInputAdapter public ControllerDefinition Definition => Source.Definition; - public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; - public OpposingDirPolicy OpposingDirPolicy { get; set; } public bool IsPressed(string button) diff --git a/src/BizHawk.Client.Common/movie/MovieSession.cs b/src/BizHawk.Client.Common/movie/MovieSession.cs index 77d2b4c5dea..79a347f37c4 100644 --- a/src/BizHawk.Client.Common/movie/MovieSession.cs +++ b/src/BizHawk.Client.Common/movie/MovieSession.cs @@ -53,12 +53,18 @@ public MovieSession( public IInputAdapter MovieOut { get; } = new CopyControllerAdapter(); public IStickyAdapter StickySource { get; set; } - public IMovieController MovieController { get; private set; } = new Bk2Controller("", NullController.Instance.Definition); + public IMovieController MovieController { get; private set; } - public IMovieController GenerateMovieController(ControllerDefinition definition = null) + public IMovieController GenerateMovieController() { // TODO: expose Movie.LogKey and pass in here - return new Bk2Controller("", definition ?? MovieController.Definition); + return new Bk2Controller("", MovieController.Definition, Movie.SystemID); + } + + public IMovieController GenerateMovieController(ControllerDefinition definition, string systemId) + { + // TODO: expose Movie.LogKey and pass in here + return new Bk2Controller("", definition, systemId); } public void HandleFrameBefore() @@ -234,7 +240,7 @@ public void QueueNewMovie( public void RunQueuedMovie(bool recordMode, IEmulator emulator) { - MovieController = new Bk2Controller(emulator.ControllerDefinition); + MovieController = new Bk2Controller(emulator.ControllerDefinition, emulator.SystemId); Movie = _queuedMovie; Movie.Attach(emulator); diff --git a/src/BizHawk.Client.Common/movie/bk2/Bk2Controller.cs b/src/BizHawk.Client.Common/movie/bk2/Bk2Controller.cs old mode 100755 new mode 100644 index 009af87da20..e4693f15b05 --- a/src/BizHawk.Client.Common/movie/bk2/Bk2Controller.cs +++ b/src/BizHawk.Client.Common/movie/bk2/Bk2Controller.cs @@ -13,6 +13,7 @@ internal class Bk2Controller : IMovieController private readonly WorkingDictionary _myAxisControls = new(); private readonly Bk2ControllerDefinition _type; + private readonly string _systemId; private IList _controlsOrdered; @@ -23,25 +24,24 @@ internal class Bk2Controller : IMovieController IsBool = _type.BoolButtons.Contains(c), IsAxis = _type.Axes.ContainsKey(c) }) - .ToList(); + .ToArray(); - public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; - - public Bk2Controller(string key, ControllerDefinition definition) : this(definition) + public Bk2Controller(string key, ControllerDefinition definition, string systemId) : this(definition, systemId) { if (!string.IsNullOrEmpty(key)) { var groups = key.Split(new[] { "#" }, StringSplitOptions.RemoveEmptyEntries); _type.ControlsFromLog = groups - .Select(group => group.Split(new[] { "|" }, StringSplitOptions.RemoveEmptyEntries).ToList()) - .ToList(); + .Select(group => group.Split(new[] { "|" }, StringSplitOptions.RemoveEmptyEntries)) + .ToArray(); } } - public Bk2Controller(ControllerDefinition definition) + public Bk2Controller(ControllerDefinition definition, string systemId) { _type = new Bk2ControllerDefinition(definition); + _systemId = systemId; foreach ((string axisName, AxisSpec range) in definition.Axes) { _myAxisControls[axisName] = range.Neutral; @@ -57,6 +57,9 @@ public Bk2Controller(ControllerDefinition definition) public void SetHapticChannelStrength(string name, int strength) {} + private Bk2LogEntryGenerator _logEntryGenerator; + public Bk2LogEntryGenerator LogEntryGenerator => _logEntryGenerator ??= new Bk2LogEntryGenerator(_systemId, this); + public void SetFrom(IController source) { for (int index = 0; index < Definition.BoolButtons.Count; index++) diff --git a/src/BizHawk.Client.Common/movie/bk2/Bk2LogEntryGenerator.cs b/src/BizHawk.Client.Common/movie/bk2/Bk2LogEntryGenerator.cs index 7c57e4dae7e..b7fdf58b633 100644 --- a/src/BizHawk.Client.Common/movie/bk2/Bk2LogEntryGenerator.cs +++ b/src/BizHawk.Client.Common/movie/bk2/Bk2LogEntryGenerator.cs @@ -14,13 +14,14 @@ public sealed class Bk2LogEntryGenerator private readonly IController _source; private readonly Dictionary _mnemonics = new(); - private readonly List> _controlsOrdered; + private readonly IReadOnlyList> _controlsOrdered; public Bk2LogEntryGenerator(string systemId, IController source) { _systemId = systemId; _source = source; - _controlsOrdered = _source.Definition.ControlsOrdered.Where(static c => c.Count is not 0).ToList(); + + _controlsOrdered = _source.Definition.ControlsOrdered.Where(static c => c.Count is not 0).ToArray(); foreach (var group in _controlsOrdered) foreach (var button in group) { var found = Bk2MnemonicLookup.Lookup(button, _systemId); @@ -35,27 +36,17 @@ public Bk2LogEntryGenerator(string systemId, IController source) } } - /// - /// Gets an input log entry that is considered empty. (booleans will be false, axes will be 0) - /// - public string EmptyEntry => CreateLogEntry(createEmpty: true); + private string _emptyEntry; + public string EmptyEntry => _emptyEntry ??= CreateLogEntry(createEmpty: true); - /// - /// Generates an input log entry for the current state of Source - /// public string GenerateLogEntry() => CreateLogEntry(); - /// - /// Generates a human readable key that will specify the names of the - /// buttons and the order they are in. This is intended to simply be - /// documentation of the meaning of the mnemonics and not to be used to - /// enforce the mnemonic values - /// - public string GenerateLogKey() + public string GenerateLogKey() => GenerateLogKey(_source.Definition); + public static string GenerateLogKey(ControllerDefinition definition) { var sb = new StringBuilder(); - foreach (var group in _source.Definition.ControlsOrdered.Where(static c => c.Count is not 0)) + foreach (var group in definition.ControlsOrdered.Where(static c => c.Count is not 0)) { sb.Append('#'); foreach (var button in group) @@ -67,9 +58,6 @@ public string GenerateLogKey() return sb.ToString(); } - /// - /// Generates a dictionary of button names to their corresponding mnemonic values - /// public IDictionary Map() { var dict = new Dictionary(); diff --git a/src/BizHawk.Client.Common/movie/bk2/Bk2Movie.InputLog.cs b/src/BizHawk.Client.Common/movie/bk2/Bk2Movie.InputLog.cs index 8cd9a167ecb..595c20c7b1a 100644 --- a/src/BizHawk.Client.Common/movie/bk2/Bk2Movie.InputLog.cs +++ b/src/BizHawk.Client.Common/movie/bk2/Bk2Movie.InputLog.cs @@ -14,7 +14,7 @@ public void WriteInputLog(TextWriter writer) { writer.WriteLine("[Input]"); writer.Write("LogKey:"); - writer.WriteLine(string.IsNullOrEmpty(LogKey) ? LogGeneratorInstance(Session.MovieController).GenerateLogKey() : LogKey); + writer.WriteLine(string.IsNullOrEmpty(LogKey) ? Session.MovieController.LogEntryGenerator.GenerateLogKey() : LogKey); foreach (var record in Log) { diff --git a/src/BizHawk.Client.Common/movie/bk2/Bk2Movie.cs b/src/BizHawk.Client.Common/movie/bk2/Bk2Movie.cs old mode 100755 new mode 100644 index 84aadc9e5d5..c971b336873 --- a/src/BizHawk.Client.Common/movie/bk2/Bk2Movie.cs +++ b/src/BizHawk.Client.Common/movie/bk2/Bk2Movie.cs @@ -6,7 +6,7 @@ namespace BizHawk.Client.Common public partial class Bk2Movie : BasicMovieInfo, IMovie { private Bk2Controller _adapter; - //private Bk2LogEntryGenerator _logGenerator; + public Bk2Movie(IMovieSession session, string filename) : base(filename) { Session = session; @@ -32,18 +32,6 @@ public virtual void Attach(IEmulator emulator) public virtual bool Changes { get; protected set; } public bool IsCountingRerecords { get; set; } = true; - public Bk2LogEntryGenerator LogGeneratorInstance(IController source) - { - // Hack because initial movie loading is a mess, and you will immediate create a file with an undefined controller - //if (!source.Definition.Any()) - { - return new Bk2LogEntryGenerator(Emulator?.SystemId ?? SystemID, source); - } - - //_logGenerator ??= new Bk2LogEntryGenerator(Emulator?.SystemId ?? SystemID, source); - //return _logGenerator; - } - public override int FrameCount => Log.Count; public int InputLogLength => Log.Count; @@ -58,14 +46,13 @@ public void CopyLog(IEnumerable log) } } - public void AppendFrame(IController source) + public void AppendFrame(ILogEntryController source) { - var lg = LogGeneratorInstance(source); - Log.Add(lg.GenerateLogEntry()); + Log.Add(source.LogEntryGenerator.GenerateLogEntry()); Changes = true; } - public virtual void RecordFrame(int frame, IController source) + public virtual void RecordFrame(int frame, ILogEntryController source) { if (Session.Settings.VBAStyleMovieLoadState) { @@ -75,8 +62,7 @@ public virtual void RecordFrame(int frame, IController source) } } - var lg = LogGeneratorInstance(source); - SetFrameAt(frame, lg.GenerateLogEntry()); + SetFrameAt(frame, source.LogEntryGenerator.GenerateLogEntry()); Changes = true; } @@ -94,18 +80,17 @@ public IMovieController GetInputState(int frame) { if (frame < FrameCount && frame >= -1) { - _adapter ??= new Bk2Controller(LogKey, Session.MovieController.Definition); - _adapter.SetFromMnemonic(frame >= 0 ? Log[frame] : Session.Movie.LogGeneratorInstance(Session.MovieController).EmptyEntry); + _adapter ??= new Bk2Controller(LogKey, Session.MovieController.Definition, Session.Movie.SystemID); + _adapter.SetFromMnemonic(frame >= 0 ? Log[frame] : Session.MovieController.LogEntryGenerator.EmptyEntry); return _adapter; } return null; } - public virtual void PokeFrame(int frame, IController source) + public virtual void PokeFrame(int frame, ILogEntryController source) { - var lg = LogGeneratorInstance(source); - SetFrameAt(frame, lg.GenerateLogEntry()); + SetFrameAt(frame, source.LogEntryGenerator.GenerateLogEntry()); Changes = true; } diff --git a/src/BizHawk.Client.Common/movie/import/DsmImport.cs b/src/BizHawk.Client.Common/movie/import/DsmImport.cs index d2831687dfd..a8dbb939e70 100644 --- a/src/BizHawk.Client.Common/movie/import/DsmImport.cs +++ b/src/BizHawk.Client.Common/movie/import/DsmImport.cs @@ -1,6 +1,7 @@ using System; using System.Globalization; using System.Linq; +using BizHawk.Client.Common.movie.import; using BizHawk.Common; using BizHawk.Common.StringExtensions; using BizHawk.Emulation.Common; @@ -94,7 +95,7 @@ protected override void RunImport() private void ImportInputFrame(string line) { - SimpleController controller = new(DeSmuMEControllerDef); + SimpleLogEntryController controller = new(DeSmuMEControllerDef, Result.Movie.SystemID); controller["LidOpen"] = false; controller["LidClose"] = false; diff --git a/src/BizHawk.Client.Common/movie/import/FcmImport.cs b/src/BizHawk.Client.Common/movie/import/FcmImport.cs index 7e3946c1cf0..9680f778c9d 100644 --- a/src/BizHawk.Client.Common/movie/import/FcmImport.cs +++ b/src/BizHawk.Client.Common/movie/import/FcmImport.cs @@ -144,7 +144,7 @@ name and ends at the savestate offset. This string is displayed as "Author Info" // Advance to first byte of input data. r.BaseStream.Position = firstFrameOffset; - SimpleController controllers = new(_deck.ControllerDef); + SimpleLogEntryController controllers = new(_deck.ControllerDef, Result.Movie.SystemID); string[] buttons = { "A", "B", "Select", "Start", "Up", "Down", "Left", "Right" }; bool fds = false; diff --git a/src/BizHawk.Client.Common/movie/import/Fm2Import.cs b/src/BizHawk.Client.Common/movie/import/Fm2Import.cs index 95a7d3d918e..a2f45f4689a 100644 --- a/src/BizHawk.Client.Common/movie/import/Fm2Import.cs +++ b/src/BizHawk.Client.Common/movie/import/Fm2Import.cs @@ -1,5 +1,5 @@ using System; - +using BizHawk.Client.Common.movie.import; using BizHawk.Common; using BizHawk.Common.BufferExtensions; using BizHawk.Emulation.Common; @@ -166,7 +166,7 @@ protected override void RunImport() private readonly string[] _buttons = { "Right", "Left", "Down", "Up", "Start", "Select", "B", "A" }; private void ImportInputFrame(string line) { - SimpleController controllers = new(_deck.ControllerDef); + SimpleLogEntryController controllers = new(_deck.ControllerDef, Result.Movie.SystemID); string[] sections = line.Split(new[] {'|'}, StringSplitOptions.RemoveEmptyEntries); controllers["Reset"] = sections[1][0] == '1'; diff --git a/src/BizHawk.Client.Common/movie/import/FmvImport.cs b/src/BizHawk.Client.Common/movie/import/FmvImport.cs index 1b86bf00d24..8298104af5e 100644 --- a/src/BizHawk.Client.Common/movie/import/FmvImport.cs +++ b/src/BizHawk.Client.Common/movie/import/FmvImport.cs @@ -98,7 +98,7 @@ the file. syncSettings.Controls.NesLeftPort = controllerSettings.NesLeftPort; syncSettings.Controls.NesRightPort = controllerSettings.NesRightPort; - SimpleController controllers = new(_deck.ControllerDef); + SimpleLogEntryController controllers = new(_deck.ControllerDef, Result.Movie.SystemID); /* * 01 Right diff --git a/src/BizHawk.Client.Common/movie/import/GmvImport.cs b/src/BizHawk.Client.Common/movie/import/GmvImport.cs index 7f32e140e92..859ff037d9f 100644 --- a/src/BizHawk.Client.Common/movie/import/GmvImport.cs +++ b/src/BizHawk.Client.Common/movie/import/GmvImport.cs @@ -90,7 +90,7 @@ protected override void RunImport() GPGXControlConverter controlConverter = new(input, systemId: VSystemID.Raw.GEN, cdButtons: false); - SimpleController controller = new(controlConverter.ControllerDef); + SimpleLogEntryController controller = new(controlConverter.ControllerDef, Result.Movie.SystemID); // Unknown. r.ReadByte(); diff --git a/src/BizHawk.Client.Common/movie/import/LsmvImport.cs b/src/BizHawk.Client.Common/movie/import/LsmvImport.cs index 4d9f11c5bda..e435b8b18d5 100644 --- a/src/BizHawk.Client.Common/movie/import/LsmvImport.cs +++ b/src/BizHawk.Client.Common/movie/import/LsmvImport.cs @@ -19,8 +19,8 @@ internal class LsmvImport : MovieImporter { private static readonly byte[] Zipheader = { 0x50, 0x4b, 0x03, 0x04 }; private int _playerCount; - private SimpleController _controller; - private SimpleController _emptyController; + private SimpleLogEntryController _controller; + private SimpleLogEntryController _emptyController; private readonly string[][] _lsnesGamepadButtons = Enumerable.Range(1, 8) .Select(player => new[] { "B", "Y", "Select", "Start", "Up", "Down", "Left", "Right", "A", "X", "L", "R" } @@ -86,11 +86,11 @@ protected override void RunImport() } ControllerDefinition controllerDefinition = new BsnesControllers(ss, true).Definition; - _emptyController = new SimpleController(controllerDefinition); - _controller = new SimpleController(controllerDefinition); + _emptyController = new SimpleLogEntryController(controllerDefinition, Result.Movie.SystemID); + _controller = new SimpleLogEntryController(controllerDefinition, Result.Movie.SystemID); _playerCount = controllerDefinition.PlayerCount; - Result.Movie.LogKey = new Bk2LogEntryGenerator(VSystemID.Raw.SNES, new Bk2Controller(controllerDefinition)).GenerateLogKey(); + Result.Movie.LogKey = Bk2LogEntryGenerator.GenerateLogKey(controllerDefinition); foreach (var item in zip.Entries) { diff --git a/src/BizHawk.Client.Common/movie/import/Mc2Import.cs b/src/BizHawk.Client.Common/movie/import/Mc2Import.cs index edf9fc3f586..e93e49cbe89 100644 --- a/src/BizHawk.Client.Common/movie/import/Mc2Import.cs +++ b/src/BizHawk.Client.Common/movie/import/Mc2Import.cs @@ -147,7 +147,7 @@ private void ImportTextFrame(string line) { var buttons = new[] { "Up", "Down", "Left", "Right", "B1", "B2", "Run", "Select" }; - SimpleController controllers = new(_deck.Definition); + SimpleLogEntryController controllers = new(_deck.Definition, Result.Movie.SystemID); // Split up the sections of the frame. string[] sections = line.Split('|'); diff --git a/src/BizHawk.Client.Common/movie/import/MmvImport.cs b/src/BizHawk.Client.Common/movie/import/MmvImport.cs index 7e05ebb6980..c8cb8dcf9a7 100644 --- a/src/BizHawk.Client.Common/movie/import/MmvImport.cs +++ b/src/BizHawk.Client.Common/movie/import/MmvImport.cs @@ -96,7 +96,7 @@ protected override void RunImport() var ss = new SMS.SmsSyncSettings(); var cd = new SMSControllerDeck(ss.Port1, ss.Port2, isGameGear, ss.UseKeyboard); - SimpleController controllers = new(cd.Definition); + SimpleLogEntryController controllers = new(cd.Definition, Result.Movie.SystemID); /* 76543210 diff --git a/src/BizHawk.Client.Common/movie/import/PjmImport.cs b/src/BizHawk.Client.Common/movie/import/PjmImport.cs index cacff790eaa..d00558d2825 100644 --- a/src/BizHawk.Client.Common/movie/import/PjmImport.cs +++ b/src/BizHawk.Client.Common/movie/import/PjmImport.cs @@ -1,5 +1,6 @@ using System.Globalization; using System.IO; +using BizHawk.Client.Common.movie.import; using BizHawk.Common.StringExtensions; using BizHawk.Emulation.Common; using BizHawk.Emulation.Cores.Sony.PSX; @@ -180,7 +181,7 @@ protected void ParseBinaryInputLog(BinaryReader br, IMovie movie, MiscHeaderInfo info.Player2Type, OctoshockDll.ePeripheralType.None, OctoshockDll.ePeripheralType.None, OctoshockDll.ePeripheralType.None }; - SimpleController controllers = new(Octoshock.CreateControllerDefinition(settings)); + SimpleLogEntryController controllers = new(Octoshock.CreateControllerDefinition(settings), Result.Movie.SystemID); string[] buttons = { @@ -290,7 +291,7 @@ protected void ParseTextInputLog(BinaryReader br, IMovie movie, MiscHeaderInfo i info.Player2Type, OctoshockDll.ePeripheralType.None, OctoshockDll.ePeripheralType.None, OctoshockDll.ePeripheralType.None }; - SimpleController controllers = new(Octoshock.CreateControllerDefinition(settings)); + SimpleLogEntryController controllers = new(Octoshock.CreateControllerDefinition(settings), Result.Movie.SystemID); string[] buttons = { diff --git a/src/BizHawk.Client.Common/movie/import/SimpleLogEntryController.cs b/src/BizHawk.Client.Common/movie/import/SimpleLogEntryController.cs new file mode 100644 index 00000000000..1d356a463d1 --- /dev/null +++ b/src/BizHawk.Client.Common/movie/import/SimpleLogEntryController.cs @@ -0,0 +1,14 @@ +using BizHawk.Emulation.Common; + +namespace BizHawk.Client.Common.movie.import +{ + public class SimpleLogEntryController : SimpleController, ILogEntryController + { + public SimpleLogEntryController(ControllerDefinition definition, string systemId) : base(definition) + { + LogEntryGenerator = new Bk2LogEntryGenerator(systemId, this); + } + + public Bk2LogEntryGenerator LogEntryGenerator { get; } + } +} diff --git a/src/BizHawk.Client.Common/movie/import/SmvImport.cs b/src/BizHawk.Client.Common/movie/import/SmvImport.cs index 28980fde545..84a6faea7e6 100644 --- a/src/BizHawk.Client.Common/movie/import/SmvImport.cs +++ b/src/BizHawk.Client.Common/movie/import/SmvImport.cs @@ -29,7 +29,7 @@ protected override void RunImport() return; } - Result.Movie.HeaderEntries[HeaderKeys.Platform] = VSystemID.Raw.SNES; + Result.Movie.SystemID = VSystemID.Raw.SNES; // 004 4-byte little-endian unsigned int: version number uint versionNumber = r.ReadUInt32(); @@ -191,9 +191,9 @@ is used (and MOVIE_SYNC_DATA_EXISTS is set), 0 bytes otherwise. } ControllerDefinition definition = new Snes9xControllers(ss).ControllerDefinition; - SimpleController controllers = new(definition); + SimpleLogEntryController controllers = new(definition, Result.Movie.SystemID); - Result.Movie.LogKey = new Bk2LogEntryGenerator(VSystemID.Raw.SNES, new Bk2Controller(definition)).GenerateLogKey(); + Result.Movie.LogKey = Bk2LogEntryGenerator.GenerateLogKey(definition); r.BaseStream.Position = firstFrameOffset; /* diff --git a/src/BizHawk.Client.Common/movie/import/VbmImport.cs b/src/BizHawk.Client.Common/movie/import/VbmImport.cs index 3226e06a3b9..78f8266f012 100644 --- a/src/BizHawk.Client.Common/movie/import/VbmImport.cs +++ b/src/BizHawk.Client.Common/movie/import/VbmImport.cs @@ -200,7 +200,7 @@ recording time in Unix epoch format Result.Movie.Comments.Add(movieDescription); r.BaseStream.Position = firstFrameOffset; - SimpleController controllers = isGBA + SimpleLogEntryController controllers = isGBA ? GbaController() : GbController(); @@ -302,13 +302,13 @@ A stream of 2-byte bitvectors which indicate which buttons are pressed at each p } } - private static SimpleController GbController() + private static SimpleLogEntryController GbController() => new(new ControllerDefinition("Gameboy Controller") { BoolButtons = { "Up", "Down", "Left", "Right", "Start", "Select", "B", "A", "Power" } - }.MakeImmutable()); + }.MakeImmutable(), VSystemID.Raw.GB); - private static SimpleController GbaController() - => new(MGBAHawk.GBAController); + private static SimpleLogEntryController GbaController() + => new(MGBAHawk.GBAController, VSystemID.Raw.GBA); } } diff --git a/src/BizHawk.Client.Common/movie/import/YmvImport.cs b/src/BizHawk.Client.Common/movie/import/YmvImport.cs index 20c1b39b899..ef25521827a 100644 --- a/src/BizHawk.Client.Common/movie/import/YmvImport.cs +++ b/src/BizHawk.Client.Common/movie/import/YmvImport.cs @@ -100,13 +100,13 @@ protected override void RunImport() private void ImportTextFrame(string line) { // Yabause only supported 1 controller - SimpleController controllers = new(new ControllerDefinition("Saturn Controller") + SimpleLogEntryController controllers = new(new ControllerDefinition("Saturn Controller") { BoolButtons = new List { "Reset", "Power", "Previous Disk", "Next Disk", "P1 Left", "P1 Right", "P1 Up", "P1 Down", "P1 Start", "P1 A", "P1 B", "P1 C", "P1 X", "P1 Y", "P1 Z", "P1 L", "P1 R" } - }.MakeImmutable()); + }.MakeImmutable(), Result.Movie.SystemID); // Split up the sections of the frame. var sections = line.Split(new[] { "|" }, StringSplitOptions.RemoveEmptyEntries); diff --git a/src/BizHawk.Client.Common/movie/import/bkm/BkmControllerAdapter.cs b/src/BizHawk.Client.Common/movie/import/bkm/BkmControllerAdapter.cs index 6734a7b62e8..576c1bc02d6 100644 --- a/src/BizHawk.Client.Common/movie/import/bkm/BkmControllerAdapter.cs +++ b/src/BizHawk.Client.Common/movie/import/bkm/BkmControllerAdapter.cs @@ -6,9 +6,9 @@ namespace BizHawk.Client.Common { - internal class BkmControllerAdapter : IController + internal class BkmControllerAdapter : ILogEntryController { - public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; + public Bk2LogEntryGenerator LogEntryGenerator { get; } public BkmControllerAdapter(ControllerDefinition definition, string systemId) { @@ -35,6 +35,7 @@ public BkmControllerAdapter(ControllerDefinition definition, string systemId) _ => "Null Controller", }; Definition = new(copyFrom: definition, withName: name); + LogEntryGenerator = new Bk2LogEntryGenerator(systemId, this); } public ControllerDefinition Definition { get; set; } diff --git a/src/BizHawk.Client.Common/movie/interfaces/ILogEntryController.cs b/src/BizHawk.Client.Common/movie/interfaces/ILogEntryController.cs new file mode 100644 index 00000000000..2be64225178 --- /dev/null +++ b/src/BizHawk.Client.Common/movie/interfaces/ILogEntryController.cs @@ -0,0 +1,9 @@ +using BizHawk.Emulation.Common; + +namespace BizHawk.Client.Common +{ + public interface ILogEntryController : IController + { + Bk2LogEntryGenerator LogEntryGenerator { get; } + } +} diff --git a/src/BizHawk.Client.Common/movie/interfaces/IMovie.cs b/src/BizHawk.Client.Common/movie/interfaces/IMovie.cs index 3ccefb589be..ac0b2729295 100644 --- a/src/BizHawk.Client.Common/movie/interfaces/IMovie.cs +++ b/src/BizHawk.Client.Common/movie/interfaces/IMovie.cs @@ -74,11 +74,6 @@ public interface IMovie : IBasicMovieInfo /// void SaveBackup(); - /// - /// Creates a log generator using the given input source - /// - Bk2LogEntryGenerator LogGeneratorInstance(IController source); - /// /// Instructs the movie to save the current contents to Filename /// @@ -148,19 +143,19 @@ public interface IMovie : IBasicMovieInfo /// Adds the given input to the movie /// Note: this edits the input log without the normal movie recording logic applied /// - void AppendFrame(IController source); + void AppendFrame(ILogEntryController source); /// /// Replaces the input at the given frame with the given input /// Note: this edits the input log without the normal movie recording logic applied /// - void PokeFrame(int frame, IController source); + void PokeFrame(int frame, ILogEntryController source); /// /// Records the given input into the given frame, /// This is subject to normal movie recording logic /// - void RecordFrame(int frame, IController source); + void RecordFrame(int frame, ILogEntryController source); /// /// Instructs the movie to remove all input from its input log starting with the input at frame. diff --git a/src/BizHawk.Client.Common/movie/interfaces/IMovieController.cs b/src/BizHawk.Client.Common/movie/interfaces/IMovieController.cs index 73240c2e22f..b19d3153f81 100644 --- a/src/BizHawk.Client.Common/movie/interfaces/IMovieController.cs +++ b/src/BizHawk.Client.Common/movie/interfaces/IMovieController.cs @@ -2,7 +2,7 @@ namespace BizHawk.Client.Common { - public interface IMovieController : IController + public interface IMovieController : ILogEntryController { /// /// Latches to the given diff --git a/src/BizHawk.Client.Common/movie/interfaces/IMovieSession.cs b/src/BizHawk.Client.Common/movie/interfaces/IMovieSession.cs index 8ba18108a54..4f1d77cb8ed 100644 --- a/src/BizHawk.Client.Common/movie/interfaces/IMovieSession.cs +++ b/src/BizHawk.Client.Common/movie/interfaces/IMovieSession.cs @@ -48,11 +48,12 @@ public interface IMovieSession /// /// Creates a instance based on the - /// given button definition if provided else the - /// current button definition - /// will be used + /// given button definition and system id if provided else the + /// current s button definition + /// and the current s system id will be used /// - IMovieController GenerateMovieController(ControllerDefinition definition = null); + IMovieController GenerateMovieController(ControllerDefinition definition, string systemId); + IMovieController GenerateMovieController(); void HandleFrameBefore(); void HandleFrameAfter(); diff --git a/src/BizHawk.Client.Common/movie/interfaces/ITasMovie.cs b/src/BizHawk.Client.Common/movie/interfaces/ITasMovie.cs index d538d1d11b6..33750cbc0d4 100644 --- a/src/BizHawk.Client.Common/movie/interfaces/ITasMovie.cs +++ b/src/BizHawk.Client.Common/movie/interfaces/ITasMovie.cs @@ -42,10 +42,10 @@ public interface ITasMovie : IMovie, INotifyPropertyChanged, IDisposable void SetBoolStates(int frame, int count, string buttonName, bool val); void InsertInput(int frame, string inputState); void InsertInput(int frame, IEnumerable inputLog); - void InsertInput(int frame, IEnumerable inputStates); + void InsertInput(int frame, IEnumerable inputStates); void InsertEmptyFrame(int frame, int count = 1); - int CopyOverInput(int frame, IEnumerable inputStates); + int CopyOverInput(int frame, IEnumerable inputStates); void RemoveFrame(int frame); void RemoveFrames(ICollection frames); diff --git a/src/BizHawk.Client.Common/movie/tasproj/TasClipboardEntry.cs b/src/BizHawk.Client.Common/movie/tasproj/TasClipboardEntry.cs index 2a9bf3bc6b3..cabadb8592d 100644 --- a/src/BizHawk.Client.Common/movie/tasproj/TasClipboardEntry.cs +++ b/src/BizHawk.Client.Common/movie/tasproj/TasClipboardEntry.cs @@ -1,16 +1,14 @@ -using BizHawk.Emulation.Common; - -namespace BizHawk.Client.Common +namespace BizHawk.Client.Common { public class TasClipboardEntry { - public TasClipboardEntry(int frame, IController controllerState) + public TasClipboardEntry(int frame, ILogEntryController controllerState) { Frame = frame; ControllerState = controllerState; } public int Frame { get; } - public IController ControllerState { get; } + public ILogEntryController ControllerState { get; } } } diff --git a/src/BizHawk.Client.Common/movie/tasproj/TasMovie.Editing.cs b/src/BizHawk.Client.Common/movie/tasproj/TasMovie.Editing.cs index c58305b5290..a0cab0497dd 100644 --- a/src/BizHawk.Client.Common/movie/tasproj/TasMovie.Editing.cs +++ b/src/BizHawk.Client.Common/movie/tasproj/TasMovie.Editing.cs @@ -11,7 +11,7 @@ internal partial class TasMovie { public IMovieChangeLog ChangeLog { get; set; } - public override void RecordFrame(int frame, IController source) + public override void RecordFrame(int frame, ILogEntryController source) { // RetroEdit: This check is questionable; recording at frame 0 is valid and should be reversible. // Also, frame - 1, why? @@ -21,8 +21,7 @@ public override void RecordFrame(int frame, IController source) ChangeLog.AddGeneralUndo(frame - 1, frame - 1, $"Record Frame: {frame}"); } - var lg = LogGeneratorInstance(source); - SetFrameAt(frame, lg.GenerateLogEntry()); + SetFrameAt(frame, source.LogEntryGenerator.GenerateLogEntry()); Changes = true; @@ -65,7 +64,7 @@ public override void Truncate(int frame) } } - public override void PokeFrame(int frame, IController source) + public override void PokeFrame(int frame, ILogEntryController source) { ChangeLog.AddGeneralUndo(frame, frame, $"Set Frame At: {frame}"); @@ -89,8 +88,7 @@ public void ClearFrame(int frame) { ChangeLog.AddGeneralUndo(frame, frame, $"Clear Frame: {frame}"); - var lg = LogGeneratorInstance(Session.MovieController); - SetFrameAt(frame, lg.EmptyEntry); + SetFrameAt(frame, Session.MovieController.LogEntryGenerator.EmptyEntry); Changes = true; InvalidateAfter(frame); @@ -206,21 +204,20 @@ public void InsertInput(int frame, IEnumerable inputLog) ChangeLog.AddInsertInput(frame, inputLog.ToList(), $"Insert {inputLog.Count()} frame(s) at {frame}"); } - public void InsertInput(int frame, IEnumerable inputStates) + public void InsertInput(int frame, IEnumerable inputStates) { // ChangeLog is done in the InsertInput call. var inputLog = new List(); foreach (var input in inputStates) { - var lg = LogGeneratorInstance(input); - inputLog.Add(lg.GenerateLogEntry()); + inputLog.Add(input.LogEntryGenerator.GenerateLogEntry()); } InsertInput(frame, inputLog); // Sets the ChangeLog } - public int CopyOverInput(int frame, IEnumerable inputStates) + public int CopyOverInput(int frame, IEnumerable inputStates) { int firstChangedFrame = -1; ChangeLog.BeginNewBatch($"Copy Over Input: {frame}"); @@ -241,8 +238,7 @@ public int CopyOverInput(int frame, IEnumerable inputStates) break; } - var lg = LogGeneratorInstance(states[i]); - var entry = lg.GenerateLogEntry(); + var entry = states[i].LogEntryGenerator.GenerateLogEntry(); if (firstChangedFrame == -1 && Log[frame + i] != entry) { firstChangedFrame = frame + i; @@ -263,8 +259,8 @@ public void InsertEmptyFrame(int frame, int count = 1) { frame = Math.Min(frame, Log.Count); - var lg = LogGeneratorInstance(Session.MovieController); - Log.InsertRange(frame, Enumerable.Repeat(lg.EmptyEntry, count).ToList()); + var lg = Session.MovieController.LogEntryGenerator; + Log.InsertRange(frame, Enumerable.Repeat(lg.EmptyEntry, count)); ShiftBindedMarkers(frame, count); @@ -283,7 +279,7 @@ private void ExtendMovieForEdit(int numFrames) Session.MovieController.SetFromSticky(Session.StickySource); // account for autohold. needs autohold pattern to be already recorded in the current frame - var lg = LogGeneratorInstance(Session.MovieController); + var lg = Session.MovieController.LogEntryGenerator; for (int i = 0; i < numFrames; i++) { @@ -309,8 +305,7 @@ public void ToggleBoolState(int frame, string buttonName) var adapter = GetInputState(frame); adapter.SetBool(buttonName, !adapter.IsPressed(buttonName)); - var lg = LogGeneratorInstance(adapter); - Log[frame] = lg.GenerateLogEntry(); + Log[frame] = adapter.LogEntryGenerator.GenerateLogEntry(); Changes = true; InvalidateAfter(frame); @@ -328,8 +323,7 @@ public void SetBoolState(int frame, string buttonName, bool val) var old = adapter.IsPressed(buttonName); adapter.SetBool(buttonName, val); - var lg = LogGeneratorInstance(adapter); - Log[frame] = lg.GenerateLogEntry(); + Log[frame] = adapter.LogEntryGenerator.GenerateLogEntry(); if (old != val) { @@ -355,8 +349,7 @@ public void SetBoolStates(int frame, int count, string buttonName, bool val) bool old = adapter.IsPressed(buttonName); adapter.SetBool(buttonName, val); - var lg = LogGeneratorInstance(adapter); - Log[frame + i] = lg.GenerateLogEntry(); + Log[frame + i] = adapter.LogEntryGenerator.GenerateLogEntry(); if (changed == -1 && old != val) { @@ -384,8 +377,7 @@ public void SetAxisState(int frame, string buttonName, int val) var old = adapter.AxisValue(buttonName); adapter.SetAxis(buttonName, val); - var lg = LogGeneratorInstance(adapter); - Log[frame] = lg.GenerateLogEntry(); + Log[frame] = adapter.LogEntryGenerator.GenerateLogEntry(); if (old != val) { @@ -411,8 +403,7 @@ public void SetAxisStates(int frame, int count, string buttonName, int val) var old = adapter.AxisValue(buttonName); adapter.SetAxis(buttonName, val); - var lg = LogGeneratorInstance(adapter); - Log[frame + i] = lg.GenerateLogEntry(); + Log[frame + i] = adapter.LogEntryGenerator.GenerateLogEntry(); if (changed == -1 && old != val) { diff --git a/src/BizHawk.Client.Common/movie/tasproj/TasMovie.cs b/src/BizHawk.Client.Common/movie/tasproj/TasMovie.cs index 96e282f2c68..c5498e16191 100644 --- a/src/BizHawk.Client.Common/movie/tasproj/TasMovie.cs +++ b/src/BizHawk.Client.Common/movie/tasproj/TasMovie.cs @@ -152,7 +152,7 @@ private void InvalidateAfter(int frame) public void InvalidateEntireGreenzone() => InvalidateAfter(0); - private (int Frame, IMovieController Controller) _displayCache = (-1, new Bk2Controller("", NullController.Instance.Definition)); + private (int Frame, IMovieController Controller) _displayCache = (-1, new Bk2Controller(NullController.Instance.Definition, VSystemID.Raw.NULL)); /// /// Returns the mnemonic value for boolean buttons, and actual value for axes, diff --git a/src/BizHawk.Client.EmuHawk/tools/BasicBot/BasicBot.cs b/src/BizHawk.Client.EmuHawk/tools/BasicBot/BasicBot.cs index fd4b67794d9..a12a8bcc9a9 100644 --- a/src/BizHawk.Client.EmuHawk/tools/BasicBot/BasicBot.cs +++ b/src/BizHawk.Client.EmuHawk/tools/BasicBot/BasicBot.cs @@ -1032,7 +1032,7 @@ private void StartBot() MovieSession.Movie.IsCountingRerecords = false; } - _logGenerator = MovieSession.Movie.LogGeneratorInstance(InputManager.ClickyVirtualPadController); + _logGenerator = new Bk2LogEntryGenerator(MovieSession.Movie.SystemID, InputManager.ClickyVirtualPadController); _cachedControlProbabilities = ControlProbabilities; _doNotUpdateValues = true; diff --git a/src/BizHawk.Client.EmuHawk/tools/Macros/MacroInput.ButtonSelect.cs b/src/BizHawk.Client.EmuHawk/tools/Macros/MacroInput.ButtonSelect.cs index fc7e1cdf1b5..a789ac5111f 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Macros/MacroInput.ButtonSelect.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Macros/MacroInput.ButtonSelect.cs @@ -47,8 +47,7 @@ private void ButtonBox_CheckedChanged(object sender, EventArgs e) s.Refresh(); // Update the selected zone's key - var lg = MovieSession.Movie.LogGeneratorInstance(MovieSession.MovieController); - string key = lg.GenerateLogKey(); + string key = MovieSession.MovieController.LogEntryGenerator.GenerateLogKey(); key = key.Replace("#", ""); foreach (var box in _buttonBoxes) diff --git a/src/BizHawk.Client.EmuHawk/tools/Macros/MovieZone.cs b/src/BizHawk.Client.EmuHawk/tools/Macros/MovieZone.cs index 626ca548fa5..3f5f226855d 100644 --- a/src/BizHawk.Client.EmuHawk/tools/Macros/MovieZone.cs +++ b/src/BizHawk.Client.EmuHawk/tools/Macros/MovieZone.cs @@ -20,11 +20,9 @@ public class MovieZone public MovieZone(IEmulator emulator, ToolManager tools, IMovieSession movieSession, int start, int length, string key = "") : this(emulator, tools, movieSession) { - var lg = movieSession.Movie.LogGeneratorInstance(movieSession.MovieController); - if (key == "") { - key = lg.GenerateLogKey(); + key = Bk2LogEntryGenerator.GenerateLogKey(movieSession.MovieController.Definition); } key = key.Replace("#", ""); @@ -37,8 +35,7 @@ public MovieZone(IEmulator emulator, ToolManager tools, IMovieSession movieSessi // Get a IController that only contains buttons in key. InitController(_inputKey); - var logGenerator = movieSession.Movie.LogGeneratorInstance(_controller); - logGenerator.GenerateLogEntry(); // Reference and create all buttons. + var logGenerator = _controller.LogEntryGenerator; string movieKey = logGenerator.GenerateLogKey().Replace("#", ""); movieKey = movieKey.Substring(startIndex: 0, length: movieKey.Length - 1); // drop last char @@ -85,7 +82,7 @@ private void InitController(string key) } } - _controller = _movieSession.GenerateMovieController(d.MakeImmutable()); + _controller = _movieSession.GenerateMovieController(d.MakeImmutable(), _emulator.SystemId); } public string Name { get; set; } @@ -118,13 +115,12 @@ private void ReSetLog() } } - var newController = _movieSession.GenerateMovieController(d.MakeImmutable()); - var logGenerator = _movieSession.Movie.LogGeneratorInstance(newController); + var newController = _movieSession.GenerateMovieController(d.MakeImmutable(), _emulator.SystemId); + var logGenerator = newController.LogEntryGenerator; logGenerator.GenerateLogEntry(); // Reference and create all buttons. // Reset all buttons in targetController (it may still have buttons that aren't being set here set true) - var tC = _movieSession.Movie.LogGeneratorInstance(_targetController); - _targetController.SetFromMnemonic(tC.EmptyEntry); + _targetController.SetFromMnemonic(_targetController.LogEntryGenerator.EmptyEntry); for (int i = 0; i < Length; i++) { _controller.SetFromMnemonic(_log[i]); @@ -236,8 +232,7 @@ public MovieZone(string fileName, IDialogController dialogController, IEmulator // If the LogKey contains buttons/controls not accepted by the emulator, // tell the user and display the macro's controller name and player count _inputKey = readText[0]; - var lg = _movieSession.Movie.LogGeneratorInstance(_movieSession.MovieController); - string key = lg.GenerateLogKey(); + string key = _movieSession.MovieController.LogEntryGenerator.GenerateLogKey(); key = key.Replace("#", ""); key = key.Substring(startIndex: 0, length: key.Length - 1); // drop last char string[] emuKeys = key.Split('|'); diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs index 0fbc3b612dd..8aa1d23f337 100644 --- a/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs @@ -429,7 +429,7 @@ private void CopyMenuItem_Click(object sender, EventArgs e) } _tasClipboard.Add(new TasClipboardEntry(index, input)); - var logEntry = CurrentTasMovie.LogGeneratorInstance(input).GenerateLogEntry(); + var logEntry = input.LogEntryGenerator.GenerateLogEntry(); sb.AppendLine(Settings.CopyIncludesFrameNo ? $"{FrameToStringPadded(index)} {logEntry}" : logEntry); } @@ -548,8 +548,7 @@ private void CutMenuItem_Click(object sender, EventArgs e) } _tasClipboard.Add(new TasClipboardEntry(index, input)); - var lg = CurrentTasMovie.LogGeneratorInstance(input); - sb.AppendLine(lg.GenerateLogEntry()); + sb.AppendLine(input.LogEntryGenerator.GenerateLogEntry()); } Clipboard.SetDataObject(sb.ToString()); diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs index bca6ff8431b..32fe0de2124 100644 --- a/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs @@ -347,9 +347,7 @@ private void SetUpColumns() Rotatable = true, }); - var columnNames = MovieSession.Movie - .LogGeneratorInstance(MovieSession.MovieController) - .Map(); + var columnNames = MovieSession.MovieController.LogEntryGenerator.Map(); foreach (var (name, mnemonic0) in columnNames) { @@ -493,8 +491,7 @@ private int? FirstNonEmptySelectedFrame { get { - var lg = CurrentTasMovie.LogGeneratorInstance(MovieSession.MovieController); - var empty = lg.EmptyEntry; + var empty = MovieSession.MovieController.LogEntryGenerator.EmptyEntry; foreach (var row in TasView.SelectedRows) { if (CurrentTasMovie[row].LogEntry != empty) diff --git a/src/BizHawk.Emulation.Common/Base Implementations/ControllerDefinition.cs b/src/BizHawk.Emulation.Common/Base Implementations/ControllerDefinition.cs index 5b95fb9a791..6789fd05f23 100644 --- a/src/BizHawk.Emulation.Common/Base Implementations/ControllerDefinition.cs +++ b/src/BizHawk.Emulation.Common/Base Implementations/ControllerDefinition.cs @@ -40,7 +40,7 @@ public IReadOnlyList> ControlsOrdered public readonly string Name; - public IReadOnlyList OrderedControlsFlat => _orderedControlsFlat ??= ControlsOrdered.SelectMany(static s => s).ToList(); + public IReadOnlyList OrderedControlsFlat => _orderedControlsFlat ??= ControlsOrdered.SelectMany(static s => s).ToArray(); public ControllerDefinition(string name) => Name = name; diff --git a/src/BizHawk.Emulation.Common/Base Implementations/NullController.cs b/src/BizHawk.Emulation.Common/Base Implementations/NullController.cs index 3017554fe58..ffd73cf74f8 100644 --- a/src/BizHawk.Emulation.Common/Base Implementations/NullController.cs +++ b/src/BizHawk.Emulation.Common/Base Implementations/NullController.cs @@ -14,8 +14,6 @@ public class NullController : IController { 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; @@ -24,6 +22,7 @@ public class NullController : IController public void SetHapticChannelStrength(string name, int strength) {} - public static readonly NullController Instance = new NullController(); + public static readonly NullController Instance = new(); + private NullController() {} } -} \ No newline at end of file +} diff --git a/src/BizHawk.Emulation.Common/ControllerDefinitionMerger.cs b/src/BizHawk.Emulation.Common/ControllerDefinitionMerger.cs index 4d7fa28b820..683be0ed515 100644 --- a/src/BizHawk.Emulation.Common/ControllerDefinitionMerger.cs +++ b/src/BizHawk.Emulation.Common/ControllerDefinitionMerger.cs @@ -70,8 +70,6 @@ private class DummyController : IController 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 58da36b7da0..0e17cec7a63 100644 --- a/src/BizHawk.Emulation.Common/Interfaces/IController.cs +++ b/src/BizHawk.Emulation.Common/Interfaces/IController.cs @@ -11,9 +11,6 @@ public interface IController /// 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 deleted file mode 100644 index 5987ae421c7..00000000000 --- a/src/BizHawk.Emulation.Common/Interfaces/IInputDisplayGenerator.cs +++ /dev/null @@ -1,10 +0,0 @@ -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 079710f5146..91c92f613fa 100644 --- a/src/BizHawk.Emulation.Common/SaveController.cs +++ b/src/BizHawk.Emulation.Common/SaveController.cs @@ -15,8 +15,6 @@ public class SaveController : IController { private readonly WorkingDictionary _buttons = new WorkingDictionary(); - public IInputDisplayGenerator InputDisplayGenerator { get; set; } = null; - public SaveController() { Definition = null; diff --git a/src/BizHawk.Emulation.Common/filetype_detectors/SatellaviewFileTypeDetector.cs b/src/BizHawk.Emulation.Common/filetype_detectors/SatellaviewFileTypeDetector.cs index 4a051dd4e90..4acb12c6b02 100644 --- a/src/BizHawk.Emulation.Common/filetype_detectors/SatellaviewFileTypeDetector.cs +++ b/src/BizHawk.Emulation.Common/filetype_detectors/SatellaviewFileTypeDetector.cs @@ -88,7 +88,7 @@ public SatellaviewHeader(ReadOnlySpan header) => _header = header; public override string ToString() - => $"[{ContentTypeField >> 4:X1}] {Title} r{Revision} ({(IsSelfDestructing ? RemainingPlays : "unlimited")} plays left)"; + => $"[{ContentTypeField >> 4:X1}] {Title} r{Revision} ({(IsSelfDestructing ? RemainingPlays.ToString() : "unlimited")} plays left)"; public bool VerifyChecksum(ReadOnlySpan rom) => true; //TODO need to parse page mapping from offset 0x20..0x23 in order to calculate this diff --git a/src/BizHawk.Tests/Client.Common/Display/InputDisplayTests.cs b/src/BizHawk.Tests/Client.Common/Display/InputDisplayTests.cs index 612287b86a3..91e942efb20 100644 --- a/src/BizHawk.Tests/Client.Common/Display/InputDisplayTests.cs +++ b/src/BizHawk.Tests/Client.Common/Display/InputDisplayTests.cs @@ -27,8 +27,8 @@ public void Initializer() public void Generate_BoolPressed_GeneratesMnemonic() { _boolController["A"] = true; - var displayGenerator = new Bk2InputDisplayGenerator("NES", _boolController); - var actual = displayGenerator.Generate(); + var displayGenerator = new Bk2InputDisplayGenerator("NES", _boolController.Definition); + var actual = displayGenerator.Generate(_boolController); Assert.AreEqual("A", actual); } @@ -36,16 +36,16 @@ public void Generate_BoolPressed_GeneratesMnemonic() public void Generate_BoolUnPressed_GeneratesSpace() { _boolController["A"] = false; - var displayGenerator = new Bk2InputDisplayGenerator("NES", _boolController); - var actual = displayGenerator.Generate(); + var displayGenerator = new Bk2InputDisplayGenerator("NES", _boolController.Definition); + var actual = displayGenerator.Generate(_boolController); Assert.AreEqual(" ", actual); } [TestMethod] public void Generate_Floats() { - var displayGenerator = new Bk2InputDisplayGenerator("NES", _axisController); - var actual = displayGenerator.Generate(); + var displayGenerator = new Bk2InputDisplayGenerator("NES", _axisController.Definition); + var actual = displayGenerator.Generate(_axisController); Assert.AreEqual(" 0, 0,", actual); } @@ -53,8 +53,8 @@ public void Generate_Floats() public void Generate_MidRangeDisplaysEmpty() { _axisController.AcceptNewAxis("StickX", MidValue); - var displayGenerator = new Bk2InputDisplayGenerator("NES", _axisController); - var actual = displayGenerator.Generate(); + var displayGenerator = new Bk2InputDisplayGenerator("NES", _axisController.Definition); + var actual = displayGenerator.Generate(_axisController); Assert.AreEqual(" 0,", actual); } }