diff --git a/BizHawk.Client.Common/BizHawk.Client.Common.csproj b/BizHawk.Client.Common/BizHawk.Client.Common.csproj index 6240abbc74..602220cc5c 100644 --- a/BizHawk.Client.Common/BizHawk.Client.Common.csproj +++ b/BizHawk.Client.Common/BizHawk.Client.Common.csproj @@ -180,21 +180,8 @@ - - - BkmMovie.cs - - - BkmMovie.cs - - - BkmMovie.cs - - - BkmMovie.cs - diff --git a/BizHawk.Client.Common/movie/bkm/BkmControllerAdapter.cs b/BizHawk.Client.Common/movie/bkm/BkmControllerAdapter.cs index 8a1ee67237..4e87e6d1b9 100644 --- a/BizHawk.Client.Common/movie/bkm/BkmControllerAdapter.cs +++ b/BizHawk.Client.Common/movie/bkm/BkmControllerAdapter.cs @@ -5,7 +5,7 @@ using BizHawk.Emulation.Common; namespace BizHawk.Client.Common { - public class BkmControllerAdapter : IMovieController + internal class BkmControllerAdapter : IController { #region IController Implementation @@ -23,54 +23,6 @@ namespace BizHawk.Client.Common #endregion - #region IMovieController Implementation - - /// - /// latches one player from the source - /// - public void LatchPlayerFromSource(IController playerSource, int playerNum) - { - foreach (var button in playerSource.Definition.BoolButtons) - { - var bnp = ButtonNameParser.Parse(button); - - if (bnp?.PlayerNum != playerNum) - { - continue; - } - - var val = playerSource.IsPressed(button); - _myBoolButtons[button] = val; - } - } - - /// - /// latches all buttons from the provided source - /// - public void LatchFromSource(IController source) - { - foreach (var button in Definition.BoolButtons) - { - _myBoolButtons[button] = source.IsPressed(button); - } - - foreach (var name in Definition.FloatControls) - { - _myFloatControls[name] = source.GetFloat(name); - } - } - - /// - /// latches sticky buttons from Global.AutofireStickyXORAdapter - /// - public void LatchSticky() - { - foreach (var button in Definition.BoolButtons) - { - _myBoolButtons[button] = Global.AutofireStickyXORAdapter.IsSticky(button); - } - } - /// /// latches all buttons from the supplied mnemonic string /// @@ -273,8 +225,6 @@ namespace BizHawk.Client.Common } } - #endregion - private readonly WorkingDictionary _myBoolButtons = new WorkingDictionary(); private readonly WorkingDictionary _myFloatControls = new WorkingDictionary(); diff --git a/BizHawk.Client.Common/movie/bkm/BkmHeader.cs b/BizHawk.Client.Common/movie/bkm/BkmHeader.cs index e33895a0e6..40afd68d62 100644 --- a/BizHawk.Client.Common/movie/bkm/BkmHeader.cs +++ b/BizHawk.Client.Common/movie/bkm/BkmHeader.cs @@ -3,7 +3,7 @@ using System.Text; namespace BizHawk.Client.Common { - public class BkmHeader : Dictionary + internal class BkmHeader : Dictionary { public BkmHeader() { @@ -45,91 +45,9 @@ namespace BizHawk.Client.Common } } - public ulong Rerecords - { - get - { - if (!ContainsKey(HeaderKeys.RERECORDS)) - { - this[HeaderKeys.RERECORDS] = "0"; - } - - return ulong.Parse(this[HeaderKeys.RERECORDS]); - } - - set - { - this[HeaderKeys.RERECORDS] = value.ToString(); - } - } - - public bool StartsFromSavestate - { - get - { - if (ContainsKey(HeaderKeys.STARTSFROMSAVESTATE)) - { - return bool.Parse(this[HeaderKeys.STARTSFROMSAVESTATE]); - } - - return false; - } - - set - { - if (value) - { - Add(HeaderKeys.STARTSFROMSAVESTATE, "True"); - } - else - { - Remove(HeaderKeys.STARTSFROMSAVESTATE); - } - } - } - - public string GameName - { - get - { - if (ContainsKey(HeaderKeys.GAMENAME)) - { - return this[HeaderKeys.GAMENAME]; - } - - return ""; - } - - set - { - this[HeaderKeys.GAMENAME] = value; - } - } - - public string SystemId - { - get - { - if (ContainsKey(HeaderKeys.PLATFORM)) - { - return this[HeaderKeys.PLATFORM]; - } - - return ""; - } - - set - { - this[HeaderKeys.PLATFORM] = value; - } - } - public new string this[string key] { - get - { - return ContainsKey(key) ? base[key] : ""; - } + get => ContainsKey(key) ? base[key] : ""; set { diff --git a/BizHawk.Client.Common/movie/bkm/BkmLogEntryGenerator.cs b/BizHawk.Client.Common/movie/bkm/BkmLogEntryGenerator.cs deleted file mode 100644 index 721fdd3ae6..0000000000 --- a/BizHawk.Client.Common/movie/bkm/BkmLogEntryGenerator.cs +++ /dev/null @@ -1,610 +0,0 @@ -using System.Text; - -using BizHawk.Emulation.Common; - -namespace BizHawk.Client.Common -{ - public class BkmLogEntryGenerator : ILogEntryGenerator - { - private IController _source; - - public void SetSource(IController source) - { - _source = source; - _controlType = source.Definition.Name; - } - - public string GenerateLogEntry() - { - if (_controlType == "Null Controller") - { - return "|.|"; - } - - if (_controlType == "Lynx Controller") - { - return GetLynxControllersAsMnemonic(); - } - - if (_controlType == "Atari 7800 ProLine Joystick Controller") - { - return GetA78ControllersAsMnemonic(); - } - - if (_controlType == "SNES Controller") - { - return GetSNESControllersAsMnemonic(); - } - - if (_controlType == "Commodore 64 Controller") - { - return GetC64ControllersAsMnemonic(); - } - - if (_controlType == "GBA Controller") - { - return GetGBAControllersAsMnemonic(); - } - - if (_controlType == "Dual Gameboy Controller") - { - return GetDualGameBoyControllerAsMnemonic(); - } - - if (_controlType == "WonderSwan Controller") - { - return GetWonderSwanControllerAsMnemonic(); - } - - if (_controlType == "Nintento 64 Controller") - { - return GetN64ControllersAsMnemonic(); - } - - if (_controlType == "Saturn Controller") - { - return GetSaturnControllersAsMnemonic(); - } - - if (_controlType == "PSP Controller") - { - return "|.|"; // TODO - } - - if (_controlType == "GPGX Genesis Controller") - { - return GetGeneis6ButtonControllersAsMnemonic(); - } - - if (_controlType == "GPGX 3-Button Controller") - { - return GetGeneis3ButtonControllersAsMnemonic(); - } - - var input = new StringBuilder("|"); - - if (_controlType == "PC Engine Controller") - { - input.Append("."); - } - else if (_controlType == "Atari 2600 Basic Controller") - { - input.Append(IsBasePressed("Reset") ? "r" : "."); - input.Append(IsBasePressed("Select") ? "s" : "."); - } - else if (_controlType == "NES Controller") - { - if (IsBasePressed("Power")) - { - input.Append(BkmMnemonicConstants.Commands[_controlType]["Power"]); - } - else if (IsBasePressed("Reset")) - { - input.Append(BkmMnemonicConstants.Commands[_controlType]["Reset"]); - } - else if (IsBasePressed("FDS Eject")) - { - input.Append(BkmMnemonicConstants.Commands[_controlType]["FDS Eject"]); - } - else if (IsBasePressed("FDS Insert 0")) - { - input.Append("0"); - } - else if (IsBasePressed("FDS Insert 1")) - { - input.Append("1"); - } - else if (IsBasePressed("FDS Insert 2")) - { - input.Append("2"); - } - else if (IsBasePressed("FDS Insert 3")) - { - input.Append("3"); - } - else if (IsBasePressed("VS Coin 1")) - { - input.Append(BkmMnemonicConstants.Commands[_controlType]["VS Coin 1"]); - } - else if (IsBasePressed("VS Coin 2")) - { - input.Append(BkmMnemonicConstants.Commands[_controlType]["VS Coin 2"]); - } - else - { - input.Append('.'); - } - } - else if (_controlType == "Genesis 3-Button Controller") - { - if (IsBasePressed("Power")) - { - input.Append(BkmMnemonicConstants.Commands[_controlType]["Power"]); - } - else if (IsBasePressed("Reset")) - { - input.Append(BkmMnemonicConstants.Commands[_controlType]["Reset"]); - } - else - { - input.Append('.'); - } - } - else if (_controlType == "Gameboy Controller") - { - input.Append(IsBasePressed("Power") ? BkmMnemonicConstants.Commands[_controlType]["Power"] : "."); - } - - if (_controlType != "SMS Controller" && _controlType != "TI83 Controller" && _controlType != "ColecoVision Basic Controller") - { - input.Append("|"); - } - - for (int player = 1; player <= BkmMnemonicConstants.Players[_controlType]; player++) - { - var prefix = ""; - if (_controlType != "Gameboy Controller" && _controlType != "TI83 Controller") - { - prefix = $"P{player} "; - } - - foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys) - { - input.Append(IsBasePressed(prefix + button) ? BkmMnemonicConstants.Buttons[_controlType][button] : "."); - } - - input.Append("|"); - } - - if (_controlType == "SMS Controller") - { - foreach (var command in BkmMnemonicConstants.Commands[_controlType].Keys) - { - input.Append(IsBasePressed(command) ? BkmMnemonicConstants.Commands[_controlType][command] : "."); - } - - input.Append("|"); - } - - if (_controlType == "TI83 Controller") - { - input.Append(".|"); // TODO: perhaps ON should go here? - } - - return input.ToString(); - } - - public string GenerateInputDisplay() - { - return GenerateLogEntry() - .Replace(".", " ") - .Replace("|", "") - .Replace(" 000, 000", " "); - } - - public bool IsEmpty => EmptyEntry == GenerateLogEntry(); - - public string EmptyEntry - { - get - { - switch (Global.Emulator.SystemId) - { - default: - case "NULL": - return "|.|"; - case "A26": - return "|..|.....|.....|"; - case "A78": - return "|....|......|......|"; - case "TI83": - return "|..................................................|.|"; - case "NES": - return "|.|........|........|........|........|"; - case "SNES": - return "|.|............|............|............|............|"; - case "SMS": - case "GG": - case "SG": - return "|......|......|..|"; - case "GEN": - return "|.|........|........|"; - case "GB": - return "|.|........|"; - case "DGB": - return "|.|........|.|........|"; - case "PCE": - case "PCECD": - case "SGX": - return "|.|........|........|........|........|........|"; - case "Coleco": - return "|..................|..................|"; - case "C64": - return "|.....|.....|..................................................................|"; - case "GBA": - return "|.|..........|"; - case "N64": - return "|.|............|............|............|............|"; - case "SAT": - return "|.|.............|.............|"; - case "WSWAN": - return "|...........|...........|..|"; - } - } - } - - public IMovieController MovieControllerAdapter => new BkmControllerAdapter(); - - #region Privates - - private bool IsBasePressed(string name) - { - return _source.IsPressed(name); - } - - private float GetBaseFloat(string name) - { - return _source.GetFloat(name); - } - - private string _controlType; - - private string GetGBAControllersAsMnemonic() - { - var input = new StringBuilder("|"); - if (IsBasePressed("Power")) - { - input.Append(BkmMnemonicConstants.Commands[_controlType]["Power"]); - } - else - { - input.Append("."); - } - - input.Append("|"); - foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys) - { - input.Append(IsBasePressed(button) ? BkmMnemonicConstants.Buttons[_controlType][button] : "."); - } - - input.Append("|"); - return input.ToString(); - } - - private string GetSNESControllersAsMnemonic() - { - var input = new StringBuilder("|"); - - if (IsBasePressed("Power")) - { - input.Append(BkmMnemonicConstants.Commands[_controlType]["Power"]); - } - else if (IsBasePressed("Reset")) - { - input.Append(BkmMnemonicConstants.Commands[_controlType]["Reset"]); - } - else - { - input.Append('.'); - } - - input.Append("|"); - for (int player = 1; player <= BkmMnemonicConstants.Players[_controlType]; player++) - { - foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys) - { - input.Append(IsBasePressed($"P{player} {button}") ? BkmMnemonicConstants.Buttons[_controlType][button] : "."); - } - - input.Append("|"); - } - - return input.ToString(); - } - - private string GetC64ControllersAsMnemonic() - { - var input = new StringBuilder("|"); - - for (int player = 1; player <= BkmMnemonicConstants.Players[_controlType]; player++) - { - foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys) - { - input.Append(IsBasePressed($"P{player} {button}") ? BkmMnemonicConstants.Buttons[_controlType][button] : "."); - } - - input.Append('|'); - } - - foreach (var button in BkmMnemonicConstants.Buttons["Commodore 64 Keyboard"].Keys) - { - input.Append(IsBasePressed(button) ? BkmMnemonicConstants.Buttons["Commodore 64 Keyboard"][button] : "."); - } - - input.Append('|'); - return input.ToString(); - } - - private string GetDualGameBoyControllerAsMnemonic() - { - // |.|........|.|........| - var input = new StringBuilder(); - - foreach (var t in BkmMnemonicConstants.DgbMnemonic) - { - if (t.Item1 != null) - { - input.Append(IsBasePressed(t.Item1) ? t.Item2 : '.'); - } - else - { - input.Append(t.Item2); // Separator - } - } - - return input.ToString(); - } - - private string GetWonderSwanControllerAsMnemonic() - { - // |....|....|...| - var input = new StringBuilder(); - - foreach (var t in BkmMnemonicConstants.WsMnemonic) - { - if (t.Item1 != null) - { - input.Append(IsBasePressed(t.Item1) ? t.Item2 : '.'); - } - else - { - input.Append(t.Item2); // Separator - } - } - - return input.ToString(); - } - - private string GetA78ControllersAsMnemonic() - { - var input = new StringBuilder("|"); - input.Append(IsBasePressed("Power") ? 'P' : '.'); - input.Append(IsBasePressed("Reset") ? 'r' : '.'); - input.Append(IsBasePressed("Select") ? 's' : '.'); - input.Append(IsBasePressed("Pause") ? 'p' : '.'); - input.Append('|'); - - for (int player = 1; player <= BkmMnemonicConstants.Players[_controlType]; player++) - { - foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys) - { - input.Append(IsBasePressed($"P{player} {button}") ? BkmMnemonicConstants.Buttons[_controlType][button] : "."); - } - - input.Append('|'); - } - - return input.ToString(); - } - - private string GetLynxControllersAsMnemonic() - { - var input = new StringBuilder("|"); - input.Append(IsBasePressed("Power") ? 'P' : '.'); - input.Append('|'); - - for (int player = 1; player <= BkmMnemonicConstants.Players[_controlType]; player++) - { - foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys) - { - input.Append(IsBasePressed(button) ? BkmMnemonicConstants.Buttons[_controlType][button] : "."); - } - - input.Append('|'); - } - - return input.ToString(); - } - - private string GetN64ControllersAsMnemonic() - { - var input = new StringBuilder("|"); - if (IsBasePressed("Power")) - { - input.Append('P'); - } - else if (IsBasePressed("Reset")) - { - input.Append('r'); - } - else - { - input.Append('.'); - } - - input.Append('|'); - - for (int player = 1; player <= BkmMnemonicConstants.Players[_controlType]; player++) - { - foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys) - { - input.Append(IsBasePressed($"P{player} {button}") ? BkmMnemonicConstants.Buttons[_controlType][button] : "."); - } - - if (BkmMnemonicConstants.Analogs[_controlType].Keys.Count > 0) - { - foreach (var name in BkmMnemonicConstants.Analogs[_controlType].Keys) - { - int val; - - // Nasty hackery - if (name == "Y Axis") - { - if (IsBasePressed($"P{player} A Up")) - { - val = 127; - } - else if (IsBasePressed($"P{player} A Down")) - { - val = -127; - } - else - { - val = (int)GetBaseFloat($"P{player} {name}"); - } - } - else if (name == "X Axis") - { - if (IsBasePressed($"P{player} A Left")) - { - val = -127; - } - else if (IsBasePressed($"P{player} A Right")) - { - val = 127; - } - else - { - val = (int)GetBaseFloat($"P{player} {name}"); - } - } - else - { - val = (int)GetBaseFloat($"P{player} {name}"); - } - - if (val >= 0) - { - input.Append(' '); - } - - input.Append($"{val:000}").Append(','); - } - - input.Remove(input.Length - 1, 1); - } - - input.Append('|'); - } - - return input.ToString(); - } - - private string GetSaturnControllersAsMnemonic() - { - var input = new StringBuilder("|"); - if (IsBasePressed("Power")) - { - input.Append('P'); - } - else if (IsBasePressed("Reset")) - { - input.Append('r'); - } - else - { - input.Append('.'); - } - - input.Append('|'); - - for (int player = 1; player <= BkmMnemonicConstants.Players[_controlType]; player++) - { - foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys) - { - input.Append(IsBasePressed($"P{player} {button}") ? BkmMnemonicConstants.Buttons[_controlType][button] : "."); - } - - input.Append('|'); - } - - return input.ToString(); - } - - private string GetGeneis6ButtonControllersAsMnemonic() - { - var input = new StringBuilder("|"); - - if (IsBasePressed("Power")) - { - input.Append(BkmMnemonicConstants.Commands[_controlType]["Power"]); - } - else if (IsBasePressed("Reset")) - { - input.Append(BkmMnemonicConstants.Commands[_controlType]["Reset"]); - } - else - { - input.Append('.'); - } - - input.Append("|"); - for (int player = 1; player <= BkmMnemonicConstants.Players[_controlType]; player++) - { - foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys) - { - input.Append(IsBasePressed($"P{player} {button}") ? BkmMnemonicConstants.Buttons[_controlType][button] : "."); - } - - input.Append("|"); - } - - input.Append("|"); - return input.ToString(); - } - - private string GetGeneis3ButtonControllersAsMnemonic() - { - var input = new StringBuilder("|"); - - if (IsBasePressed("Power")) - { - input.Append(BkmMnemonicConstants.Commands[_controlType]["Power"]); - } - else if (IsBasePressed("Reset")) - { - input.Append(BkmMnemonicConstants.Commands[_controlType]["Reset"]); - } - else - { - input.Append('.'); - } - - input.Append("|"); - for (int player = 1; player <= BkmMnemonicConstants.Players[_controlType]; player++) - { - foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys) - { - input.Append(IsBasePressed($"P{player} {button}") ? BkmMnemonicConstants.Buttons[_controlType][button] : "."); - } - - input.Append("|"); - } - - input.Append("|"); - return input.ToString(); - } - - #endregion - } -} diff --git a/BizHawk.Client.Common/movie/bkm/BkmMnemonicConstants.cs b/BizHawk.Client.Common/movie/bkm/BkmMnemonicConstants.cs index 720050e329..078176da88 100644 --- a/BizHawk.Client.Common/movie/bkm/BkmMnemonicConstants.cs +++ b/BizHawk.Client.Common/movie/bkm/BkmMnemonicConstants.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; namespace BizHawk.Client.Common { - public static class BkmMnemonicConstants + internal static class BkmMnemonicConstants { public static readonly Dictionary> Buttons = new Dictionary> { diff --git a/BizHawk.Client.Common/movie/bkm/BkmMovie.HeaderApi.cs b/BizHawk.Client.Common/movie/bkm/BkmMovie.HeaderApi.cs deleted file mode 100644 index e4329a2280..0000000000 --- a/BizHawk.Client.Common/movie/bkm/BkmMovie.HeaderApi.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System.Collections.Generic; - -namespace BizHawk.Client.Common -{ - public partial class BkmMovie - { - public IDictionary HeaderEntries => Header; - - public SubtitleList Subtitles => Header.Subtitles; - - public IList Comments => Header.Comments; - - public string SyncSettingsJson - { - get { return Header[HeaderKeys.SYNCSETTINGS]; } - set { Header[HeaderKeys.SYNCSETTINGS] = value; } - } - - public ulong Rerecords - { - get { return Header.Rerecords; } - set { Header.Rerecords = value; } - } - - public bool StartsFromSavestate - { - get { return Header.StartsFromSavestate; } - set { Header.StartsFromSavestate = value; } - } - - // Bkm doesn't support saveram anchored movies - public bool StartsFromSaveRam - { - get { return false; } set { } - } - - public string GameName - { - get { return Header.GameName; } - set { Header.GameName = value; } - } - - public string SystemID - { - get { return Header.SystemId; } - set { Header.SystemId = value; } - } - - public string Hash - { - get { return Header[HeaderKeys.SHA1]; } - set { Header[HeaderKeys.SHA1] = value; } - } - - public string Author - { - get { return Header[HeaderKeys.AUTHOR]; } - set { Header[HeaderKeys.AUTHOR] = value; } - } - - public string Core - { - get { return Header[HeaderKeys.CORE]; } - set { Header[HeaderKeys.CORE] = value; } - } - - public string BoardName - { - get { return Header[HeaderKeys.BOARDNAME]; } - set { Header[HeaderKeys.BOARDNAME] = value; } - } - - public string EmulatorVersion - { - get { return Header[HeaderKeys.EMULATIONVERSION]; } - set { Header[HeaderKeys.EMULATIONVERSION] = value; } - } - - public string FirmwareHash - { - get { return Header[HeaderKeys.FIRMWARESHA1]; } - set { Header[HeaderKeys.FIRMWARESHA1] = value; } - } - - public string TextSavestate { get; set; } - public byte[] BinarySavestate { get; set; } - public int[] SavestateFramebuffer { get { return null; } set { } } // eat and ignore framebuffers - public byte[] SaveRam { get { return null; } set { } } // Bkm does not support Saveram anchored movies - } -} diff --git a/BizHawk.Client.Common/movie/bkm/BkmMovie.IO.cs b/BizHawk.Client.Common/movie/bkm/BkmMovie.IO.cs deleted file mode 100644 index d296be8d35..0000000000 --- a/BizHawk.Client.Common/movie/bkm/BkmMovie.IO.cs +++ /dev/null @@ -1,281 +0,0 @@ -using System; -using System.IO; -using System.Text; - -using BizHawk.Common; - -namespace BizHawk.Client.Common -{ - public partial class BkmMovie - { - private int _preloadFramecount; // Not a a reliable number, used for preloading (when no log has yet been loaded), this is only for quick stat compilation for dialogs such as play movie - - public void SaveAs(string path) - { - Filename = path; - if (!Loaded) - { - return; - } - - var directoryInfo = new FileInfo(Filename).Directory; - if (directoryInfo != null) - { - Directory.CreateDirectory(directoryInfo.FullName); - } - - Write(Filename); - } - - public void Save() - { - if (!Loaded || string.IsNullOrWhiteSpace(Filename)) - { - return; - } - - SaveAs(Filename); - _changes = false; - } - - public void SaveBackup() - { - if (!Loaded || string.IsNullOrWhiteSpace(Filename)) - { - return; - } - - var backupName = Filename; - backupName = backupName.Insert(Filename.LastIndexOf("."), $".{DateTime.Now:yyyy-MM-dd HH.mm.ss}"); - backupName = Path.Combine(Global.Config.PathEntries["Global", "Movie backups"].Path, Path.GetFileName(backupName)); - - var directoryInfo = new FileInfo(backupName).Directory; - if (directoryInfo != null) - { - Directory.CreateDirectory(directoryInfo.FullName); - } - - Write(backupName); - } - - public bool Load(bool preload) - { - var file = new FileInfo(Filename); - - if (file.Exists == false) - { - Loaded = false; - return false; - } - - Header.Clear(); - _log.Clear(); - - using (var sr = file.OpenText()) - { - string line; - - while ((line = sr.ReadLine()) != null) - { - if (line == "") - { - continue; - } - - if (line.Contains("LoopOffset")) - { - try - { - _loopOffset = int.Parse(line.Split(new[] { ' ' }, 2)[1]); - } - catch (Exception) - { - continue; - } - } - else if (Header.ParseLineFromFile(line)) - { - continue; - } - else if (line.StartsWith("|")) - { - _log.Add(line); - } - else - { - Header.Comments.Add(line); - } - } - } - - if (Header.SavestateBinaryBase64Blob != null) - { - BinarySavestate = Convert.FromBase64String(Header.SavestateBinaryBase64Blob); - } - - Loaded = true; - _changes = false; - return true; - } - - /// - /// Load Header information only for displaying file information in dialogs such as play movie - /// TODO - consider not loading the SavestateBinaryBase64Blob key? - /// - public bool PreLoadHeaderAndLength(HawkFile hawkFile) - { - Loaded = false; - var file = new FileInfo(hawkFile.CanonicalFullPath); - - if (file.Exists == false) - { - return false; - } - - Header.Clear(); - _log.Clear(); - - var origStreamPosn = hawkFile.GetStream().Position; - hawkFile.GetStream().Position = 0; // Reset to start - - // No using block because we're sharing the stream and need to give it back undisposed. - var sr = new StreamReader(hawkFile.GetStream()); - - for (;;) - { - // read to first space (key/value delimeter), or pipe, or EOF - int first = sr.Read(); - - if (first == -1) - { - break; - } // EOF - - if (first == '|') // pipe: begin input log - { - // NOTE - this code is a bit convoluted due to its predating the basic outline of the parser which was upgraded in may 2014 - var line = '|' + sr.ReadLine(); - - // how many bytes are left, total? - long remain = sr.BaseStream.Length - sr.BaseStream.Position; - - // try to find out whether we use \r\n or \n - // but only look for 1K characters. - bool usesR = false; - for (int i = 0; i < 1024; i++) - { - int c = sr.Read(); - if (c == -1) - { - break; - } - - if (c == '\r') - { - usesR = true; - break; - } - - if (c == '\n') - { - break; - } - } - - int lineLen = line.Length + 1; // account for \n - if (usesR) - { - lineLen++; // account for \r - } - - _preloadFramecount = (int)(remain / lineLen); // length is remaining bytes / length per line - _preloadFramecount++; // account for the current line - break; - } - else - { - // a header line. finish reading key token, to make sure it isn't one of the FORBIDDEN keys - var sbLine = new StringBuilder(); - sbLine.Append((char)first); - for (;;) - { - int c = sr.Read(); - if (c == -1 || c == '\n' || c == ' ') - { - break; - } - - sbLine.Append((char)c); - } - - var line = sbLine.ToString(); - - // ignore these suckers, theyre way too big for preloading. seriously, we will get out of memory errors. - var skip = line == HeaderKeys.SAVESTATEBINARYBASE64BLOB; - - if (skip) - { - // skip remainder of the line - sr.DiscardBufferedData(); - var stream = sr.BaseStream; - for (;;) - { - int c = stream.ReadByte(); - if (c == -1 || c == '\n') - { - break; - } - } - - // proceed to next line - continue; - } - - var remainder = sr.ReadLine(); - sbLine.Append(' '); - sbLine.Append(remainder); - line = sbLine.ToString(); - - if (string.IsNullOrWhiteSpace(line) || Header.ParseLineFromFile(line)) - { - continue; - } - - Header.Comments.Add(line); - } - } - - hawkFile.GetStream().Position = origStreamPosn; - - return true; - } - - private void Write(string fn) - { - Header.SavestateBinaryBase64Blob = BinarySavestate != null - ? Convert.ToBase64String(BinarySavestate) - : null; - - using (var fs = new FileStream(fn, FileMode.Create, FileAccess.Write, FileShare.Read)) - { - using (var sw = new StreamWriter(fs)) - { - sw.Write(Header.ToString()); - - // TODO: clean this up - if (_loopOffset.HasValue) - { - sw.WriteLine($"LoopOffset {_loopOffset}"); - } - - foreach (var input in _log) - { - sw.WriteLine(input); - } - } - } - - _changes = false; - } - } -} diff --git a/BizHawk.Client.Common/movie/bkm/BkmMovie.InputLog.cs b/BizHawk.Client.Common/movie/bkm/BkmMovie.InputLog.cs deleted file mode 100644 index eb5cf0d4ad..0000000000 --- a/BizHawk.Client.Common/movie/bkm/BkmMovie.InputLog.cs +++ /dev/null @@ -1,291 +0,0 @@ -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; - -namespace BizHawk.Client.Common -{ - public partial class BkmMovie - { - private readonly List _log = new List(); - - public void WriteInputLog(TextWriter writer) - { - writer.WriteLine("[Input]"); - - foreach (var record in _log) - { - writer.WriteLine(record); - } - - writer.WriteLine("[/Input]"); - } - - public string GetInputLogEntry(int frame) - { - if (frame < FrameCount && frame >= 0) - { - return _log[frame]; - } - - return ""; - } - - public bool ExtractInputLog(TextReader reader, out string errorMessage) - { - errorMessage = ""; - int? stateFrame = null; - - // We are in record mode so replace the movie log with the one from the savestate - if (!Global.MovieSession.MultiTrack.IsActive) - { - if (Global.Config.EnableBackupMovies && _makeBackup && _log.Any()) - { - SaveBackup(); - _makeBackup = false; - } - - _log.Clear(); - while (true) - { - var line = reader.ReadLine(); - if (line == null) - { - break; - } - - if (line.Trim() == "" || line == "[Input]") - { - continue; - } - - if (line == "[/Input]") - { - break; - } - - if (line.Contains("Frame 0x")) // NES stores frame count in hex, yay - { - var strs = line.Split('x'); - try - { - stateFrame = int.Parse(strs[1], NumberStyles.HexNumber); - } - catch - { - errorMessage = "Savestate Frame number failed to parse"; - return false; - } - } - else if (line.Contains("Frame ")) - { - var strs = line.Split(' '); - try - { - stateFrame = int.Parse(strs[1]); - } - catch - { - errorMessage = "Savestate Frame number failed to parse"; - return false; - } - } - else if (line[0] == '|') - { - _log.Add(line); - } - } - } - else - { - var i = 0; - while (true) - { - var line = reader.ReadLine(); - if (line == null) - { - break; - } - - if (line.Trim() == "" || line == "[Input]") - { - continue; - } - - if (line == "[/Input]") - { - break; - } - - if (line.Contains("Frame 0x")) // NES stores frame count in hex, yay - { - var strs = line.Split('x'); - try - { - stateFrame = int.Parse(strs[1], NumberStyles.HexNumber); - } - catch - { - errorMessage = "Savestate Frame number failed to parse"; - return false; - } - } - else if (line.Contains("Frame ")) - { - var strs = line.Split(' '); - try - { - stateFrame = int.Parse(strs[1]); - } - catch - { - errorMessage = "Savestate Frame number failed to parse"; - return false; - } - } - else if (line.StartsWith("|")) - { - SetFrameAt(i, line); - i++; - } - } - } - - if (!stateFrame.HasValue) - { - errorMessage = "Savestate Frame number failed to parse"; - } - - var stateFramei = stateFrame ?? 0; - - if (stateFramei > 0 && stateFramei < _log.Count) - { - if (!Global.Config.VBAStyleMovieLoadState) - { - Truncate(stateFramei); - } - } - else if (stateFramei > _log.Count) // Post movie savestate - { - if (!Global.Config.VBAStyleMovieLoadState) - { - Truncate(_log.Count); - } - - _mode = Moviemode.Finished; - } - - if (IsCountingRerecords) - { - Rerecords++; - } - - return true; - } - - public bool CheckTimeLines(TextReader reader, out string errorMessage) - { - // This function will compare the movie data to the savestate movie data to see if they match - errorMessage = ""; - var log = new List(); - var stateFrame = 0; - while (true) - { - var line = reader.ReadLine(); - if (line == null) - { - return false; - } - - if (line.Trim() == "") - { - continue; - } - - if (line.Contains("Frame 0x")) // NES stores frame count in hex, yay - { - var strs = line.Split('x'); - try - { - stateFrame = int.Parse(strs[1], NumberStyles.HexNumber); - } - catch - { - errorMessage = "Savestate Frame number failed to parse"; - return false; - } - } - else if (line.Contains("Frame ")) - { - var strs = line.Split(' '); - try - { - stateFrame = int.Parse(strs[1]); - } - catch - { - errorMessage = "Savestate Frame number failed to parse"; - return false; - } - } - else if (line == "[Input]") - { - continue; - } - else if (line == "[/Input]") - { - break; - } - else if (line[0] == '|') - { - log.Add(line); - } - } - - if (stateFrame == 0) - { - stateFrame = log.Count; // In case the frame count failed to parse, revert to using the entire state input log - } - - if (_log.Count < stateFrame) - { - if (IsFinished) - { - return true; - } - - errorMessage = $"The savestate is from frame {log.Count} which is greater than the current movie length of {_log.Count}"; - - return false; - } - - for (var i = 0; i < stateFrame; i++) - { - if (_log[i] != log[i]) - { - errorMessage = $"The savestate input does not match the movie input at frame {(i + 1)}."; - - return false; - } - } - - if (stateFrame > log.Count) // stateFrame is greater than state input log, so movie finished mode - { - if (_mode == Moviemode.Play || _mode == Moviemode.Finished) - { - _mode = Moviemode.Finished; - return true; - } - - return false; - } - - if (_mode == Moviemode.Finished) - { - _mode = Moviemode.Play; - } - - return true; - } - } -} diff --git a/BizHawk.Client.Common/movie/bkm/BkmMovie.ModeApi.cs b/BizHawk.Client.Common/movie/bkm/BkmMovie.ModeApi.cs deleted file mode 100644 index 437ea64e68..0000000000 --- a/BizHawk.Client.Common/movie/bkm/BkmMovie.ModeApi.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System.Linq; - -namespace BizHawk.Client.Common -{ - public partial class BkmMovie - { - private enum Moviemode - { - Inactive, Play, Record, Finished - } - - private Moviemode _mode = Moviemode.Inactive; - - public bool IsPlaying => _mode == Moviemode.Play || _mode == Moviemode.Finished; - - public bool IsRecording => _mode == Moviemode.Record; - - public bool IsActive => _mode != Moviemode.Inactive; - - public bool IsFinished => _mode == Moviemode.Finished; - - public void StartNewRecording() - { - _mode = Moviemode.Record; - if (Global.Config.EnableBackupMovies && _makeBackup && _log.Any()) - { - SaveBackup(); - _makeBackup = false; - } - - _log.Clear(); - } - - public void StartNewPlayback() - { - _mode = Moviemode.Play; - } - - public void SwitchToRecord() - { - _mode = Moviemode.Record; - } - - public void SwitchToPlay() - { - _mode = Moviemode.Play; - Save(); - } - - public bool Stop(bool saveChanges = true) - { - bool saved = false; - if (saveChanges) - { - if (_mode == Moviemode.Record || _changes) - { - Save(); - saved = true; - } - } - - _changes = false; - _mode = Moviemode.Inactive; - - return saved; - } - - public void FinishedMode() - { - _mode = Moviemode.Finished; - } - } -} diff --git a/BizHawk.Client.Common/movie/bkm/BkmMovie.cs b/BizHawk.Client.Common/movie/bkm/BkmMovie.cs index 32003a7030..41d736fc14 100644 --- a/BizHawk.Client.Common/movie/bkm/BkmMovie.cs +++ b/BizHawk.Client.Common/movie/bkm/BkmMovie.cs @@ -1,52 +1,27 @@ -using BizHawk.Emulation.Common; +using System; +using System.Collections.Generic; +using System.IO; namespace BizHawk.Client.Common { - public partial class BkmMovie : IMovie + internal class BkmMovie { - private bool _makeBackup; - private bool _changes; + private readonly List _log = new List(); private int? _loopOffset; - public BkmMovie(string filename) - : this() - { - Rerecords = 0; - Filename = filename; - Loaded = !string.IsNullOrWhiteSpace(filename); - } - public BkmMovie() { Header = new BkmHeader { [HeaderKeys.MOVIEVERSION] = "BizHawk v0.0.1" }; - Filename = ""; - _preloadFramecount = 0; - - IsCountingRerecords = true; - _mode = Moviemode.Inactive; - _makeBackup = true; } - #region Properties - - public ILogEntryGenerator LogGeneratorInstance() - { - return new BkmLogEntryGenerator(); - } - - public string PreferredExtension => Extension; - - public const string Extension = "bkm"; + public string PreferredExtension => "bkm"; public BkmHeader Header { get; } - public string Filename { get; set; } - public bool IsCountingRerecords { get; set; } + public string Filename { get; set; } = ""; public bool Loaded { get; private set; } public int InputLogLength => _log.Count; - public int TimeLength => _log.Count; - public double FrameCount { get @@ -61,114 +36,115 @@ namespace BizHawk.Client.Common return _log.Count; } - return _preloadFramecount; + return 0; } } - public bool Changes => _changes; - - #endregion - - #region Public Log Editing - - public IController GetInputState(int frame) + public BkmControllerAdapter GetInputState(int frame) { if (frame < FrameCount && frame >= 0) { - int getframe; + int getFrame; if (_loopOffset.HasValue) { if (frame < _log.Count) { - getframe = frame; + getFrame = frame; } else { - getframe = ((frame - _loopOffset.Value) % (_log.Count - _loopOffset.Value)) + _loopOffset.Value; + getFrame = ((frame - _loopOffset.Value) % (_log.Count - _loopOffset.Value)) + _loopOffset.Value; } } else { - getframe = frame; + getFrame = frame; } var adapter = new BkmControllerAdapter { Definition = Global.MovieSession.MovieControllerAdapter.Definition }; - adapter.SetControllersAsMnemonic(_log[getframe]); + adapter.SetControllersAsMnemonic(_log[getFrame]); return adapter; } return null; } - public void ClearFrame(int frame) + public IDictionary HeaderEntries => Header; + + public SubtitleList Subtitles => Header.Subtitles; + + public IList Comments => Header.Comments; + + public string SyncSettingsJson { - var lg = LogGeneratorInstance(); - SetFrameAt(frame, lg.EmptyEntry); - _changes = true; + get => Header[HeaderKeys.SYNCSETTINGS]; + set => Header[HeaderKeys.SYNCSETTINGS] = value; } - public void AppendFrame(IController source) - { - var lg = LogGeneratorInstance(); - lg.SetSource(source); - _log.Add(lg.GenerateLogEntry()); - _changes = true; - } + public string TextSavestate { get; set; } + public byte[] BinarySavestate { get; set; } - public void Truncate(int frame) + public bool Load() { - if (frame < _log.Count) + var file = new FileInfo(Filename); + + if (file.Exists == false) { - _log.RemoveRange(frame, _log.Count - frame); - _changes = true; + Loaded = false; + return false; } - } - public void PokeFrame(int frame, IController source) - { - var lg = LogGeneratorInstance(); - lg.SetSource(source); + Header.Clear(); + _log.Clear(); - _changes = true; - SetFrameAt(frame, lg.GenerateLogEntry()); - } - - public void RecordFrame(int frame, IController source) - { - // Note: Truncation here instead of loadstate will make VBA style loadstates - // (Where an entire movie is loaded then truncated on the next frame - // this allows users to restore a movie with any savestate from that "timeline" - if (Global.Config.VBAStyleMovieLoadState) + using (var sr = file.OpenText()) { - if (Global.Emulator.Frame < _log.Count) + string line; + + while ((line = sr.ReadLine()) != null) { - Truncate(Global.Emulator.Frame); + if (line == "") + { + continue; + } + + if (line.Contains("LoopOffset")) + { + try + { + _loopOffset = int.Parse(line.Split(new[] { ' ' }, 2)[1]); + } + catch (Exception) + { + continue; + } + } + else if (Header.ParseLineFromFile(line)) + { + continue; + } + else if (line.StartsWith("|")) + { + _log.Add(line); + } + else + { + Header.Comments.Add(line); + } } } - var lg = LogGeneratorInstance(); - lg.SetSource(source); - SetFrameAt(frame, lg.GenerateLogEntry()); - - _changes = true; - } - - #endregion - - private void SetFrameAt(int frameNum, string frame) - { - if (_log.Count > frameNum) + if (Header.SavestateBinaryBase64Blob != null) { - _log[frameNum] = frame; - } - else - { - _log.Add(frame); + BinarySavestate = Convert.FromBase64String(Header.SavestateBinaryBase64Blob); } + + Loaded = true; + return true; } } } \ No newline at end of file diff --git a/BizHawk.Client.Common/movie/import/BkmImport.cs b/BizHawk.Client.Common/movie/import/BkmImport.cs index ac1fb715cc..8c51cf7ea4 100644 --- a/BizHawk.Client.Common/movie/import/BkmImport.cs +++ b/BizHawk.Client.Common/movie/import/BkmImport.cs @@ -13,8 +13,46 @@ namespace BizHawk.Client.Common.movie.import Filename = SourceFile.FullName }; - movie.Load(false); - Result.Movie = movie.ToBk2(); + movie.Load(); + Result.Movie = ToBk2(movie); + } + + public static Bk2Movie ToBk2(BkmMovie old) + { + var bk2 = new Bk2Movie(old.Filename.Replace(old.PreferredExtension, Bk2Movie.Extension)); + + for (var i = 0; i < old.InputLogLength; i++) + { + var input = old.GetInputState(i); + bk2.AppendFrame(input); + } + + bk2.HeaderEntries.Clear(); + foreach (var kvp in old.HeaderEntries) + { + bk2.HeaderEntries[kvp.Key] = kvp.Value; + } + + bk2.SyncSettingsJson = old.SyncSettingsJson; + + bk2.Comments.Clear(); + foreach (var comment in old.Comments) + { + bk2.Comments.Add(comment); + } + + bk2.Subtitles.Clear(); + foreach (var sub in old.Subtitles) + { + bk2.Subtitles.Add(sub); + } + + bk2.TextSavestate = old.TextSavestate; + bk2.BinarySavestate = old.BinarySavestate; + + bk2.Save(); + + return bk2; } } }