From 37590e7ea4966830fa4e2504b11ad3794911937f Mon Sep 17 00:00:00 2001 From: SuuperW Date: Sun, 15 Mar 2015 06:26:57 +0000 Subject: [PATCH] TasStateManager can now save states to disk. --- BizHawk.Client.Common/config/PathEntry.cs | 4 +- .../movie/tasproj/TasMovie.cs | 3 +- .../movie/tasproj/TasMovieRecord.cs | 10 +- .../movie/tasproj/TasStateManager.cs | 221 +++++++++++++----- .../movie/tasproj/TasStateManagerSettings.cs | 67 +++++- BizHawk.Client.EmuHawk/MainForm.cs | 4 + .../tools/Macros/MacroInput.cs | 16 +- .../TAStudio/GreenzoneSettings.Designer.cs | 195 ++++++++++++---- .../tools/TAStudio/GreenzoneSettings.cs | 32 ++- .../tools/TAStudio/InputRoll.cs | 7 +- .../tools/TAStudio/TAStudio.MenuItems.cs | 3 + .../tools/TAStudio/TAStudio.Navigation.cs | 6 +- 12 files changed, 431 insertions(+), 137 deletions(-) diff --git a/BizHawk.Client.Common/config/PathEntry.cs b/BizHawk.Client.Common/config/PathEntry.cs index de9f552a3e..b17ca54f68 100644 --- a/BizHawk.Client.Common/config/PathEntry.cs +++ b/BizHawk.Client.Common/config/PathEntry.cs @@ -71,7 +71,7 @@ namespace BizHawk.Client.Common // we have the system, but not the type. don't attempt to add an unknown type return null; } - + // we don't have anything for the system in question. add a set of stock paths var systempath = PathManager.RemoveInvalidFileSystemChars(system) + "_INTERIM"; var systemdisp = system + " (INTERIM)"; @@ -154,6 +154,8 @@ namespace BizHawk.Client.Common new PathEntry { System = "Global_NULL", SystemDisplayName="Global", Type = "Watch (.wch)", Path = ".", Ordinal = 7 }, new PathEntry { System = "Global_NULL", SystemDisplayName="Global", Type = "A/V Dumps", Path = ".", Ordinal = 8 }, new PathEntry { System = "Global_NULL", SystemDisplayName="Global", Type = "Debug Logs", Path = ".", Ordinal = 9 }, + new PathEntry { System = "Global_NULL", SystemDisplayName="Global", Type = "Macros", Path = Path.Combine(".", "Movies", "Macros"), Ordinal = 10 }, + new PathEntry { System = "Global_NULL", SystemDisplayName="Global", Type = "TAStudio states", Path = Path.Combine(".", "Movies", "TAStudio states"), Ordinal = 11 }, new PathEntry { System = "INTV", SystemDisplayName="Intellivision", Type = "Base", Path = Path.Combine(".", "Intellivision"), Ordinal = 0 }, new PathEntry { System = "INTV", SystemDisplayName="Intellivision", Type = "ROM", Path = ".", Ordinal = 1 }, diff --git a/BizHawk.Client.Common/movie/tasproj/TasMovie.cs b/BizHawk.Client.Common/movie/tasproj/TasMovie.cs index 50fee2cf01..68e4270188 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasMovie.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasMovie.cs @@ -91,7 +91,8 @@ namespace BizHawk.Client.Common { return new TasMovieRecord { - State = StateManager[index], + // State = StateManager[index], + HasState = StateManager.HasState(index), LogEntry = GetInputLogEntry(index), Lagged = LagLog[index + 1], WasLagged = LagLog.History(index + 1) diff --git a/BizHawk.Client.Common/movie/tasproj/TasMovieRecord.cs b/BizHawk.Client.Common/movie/tasproj/TasMovieRecord.cs index ec588f31ba..8aeb697ea6 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasMovieRecord.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasMovieRecord.cs @@ -5,14 +5,14 @@ namespace BizHawk.Client.Common { public class TasMovieRecord { - public KeyValuePair State { get; set; } + // public KeyValuePair State { get; set; } public bool? Lagged { get; set; } public bool? WasLagged { get; set; } public string LogEntry { get; set; } - public bool HasState - { - get { return State.Value.Any(); } - } + public bool HasState { get; set; } + //{ + // get { return State.Value.Any(); } + //} } } diff --git a/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs b/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs index b44fe44870..dc9fb75bf5 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs @@ -26,9 +26,16 @@ namespace BizHawk.Client.Common } private readonly SortedList States = new SortedList(); + private string statePath + { + get + { + return PathManager.MakeAbsolutePath(Global.Config.PathEntries["Global", "TAStudio states"].Path, null); + } + } private readonly TasMovie _movie; - private int _expectedStateSize = 0; + private ulong _expectedStateSize = 0; private int _minFrequency = VersionInfo.DeveloperBuild ? 2 : 1; private const int _maxFrequency = 16; @@ -36,7 +43,7 @@ namespace BizHawk.Client.Common { get { - var freq = _expectedStateSize / 65536; + int freq = (int)(_expectedStateSize / 65536); if (freq < _minFrequency) { @@ -54,7 +61,7 @@ namespace BizHawk.Client.Common private int _lastCapture = 0; private int maxStates - { get { return Settings.Cap / _expectedStateSize; } } + { get { return (int)(Settings.Cap / _expectedStateSize); } } public TasStateManager(TasMovie movie) { @@ -62,18 +69,20 @@ namespace BizHawk.Client.Common Settings = new TasStateManagerSettings(Global.Config.DefaultTasProjSettings); - var cap = Settings.Cap; - int limit = 0; - _expectedStateSize = Core.SaveStateBinary().Length; + _expectedStateSize = (ulong)Core.SaveStateBinary().Length; if (_expectedStateSize > 0) { - limit = cap / _expectedStateSize; + limit = maxStates; } States = new SortedList(limit); + if (Directory.Exists(statePath)) + Directory.Delete(statePath, true); // To delete old files that may still exist. + Directory.CreateDirectory(statePath); + accessed = new List(); } public TasStateManagerSettings Settings { get; set; } @@ -94,12 +103,15 @@ namespace BizHawk.Client.Common if (States.ContainsKey(frame)) { + // if (States[frame] == null) // Get from file + StateAccessed(frame); return new KeyValuePair(frame, States[frame]); } return new KeyValuePair(-1, new byte[0]); } } + private List accessed; public byte[] InitialState { @@ -146,20 +158,7 @@ namespace BizHawk.Client.Common if (shouldCapture) { - var state = (byte[])Core.SaveStateBinary().Clone(); - - if (States.ContainsKey(frame)) - { - States[frame] = state; - } - else - { - Used += state.Length; - MaybeRemoveState(); // Remove before adding so this state won't be removed. - - States.Add(frame, state); - } - + SetState(frame, (byte[])Core.SaveStateBinary().Clone()); _lastCapture = frame; } } @@ -167,38 +166,44 @@ namespace BizHawk.Client.Common private void MaybeRemoveState() { int shouldRemove = -1; - if (Used >= Settings.Cap) - shouldRemove = _movie.StartsFromSavestate ? 0 : 1; - if (shouldRemove != -1) // Which one to remove? + if (Used + DiskUsed > Settings.CapTotal) + shouldRemove = StateToRemove(); + if (shouldRemove != -1) { - int markerSkips = maxStates / 3; - - shouldRemove--; - do - { - shouldRemove++; - - // No need to have two savestates with only lag frames between them. - for (int i = shouldRemove + 1; i < States.Count - 1; i++) - { - if (AllLag(States.ElementAt(i).Key, States.ElementAt(i + 1).Key)) - { - shouldRemove = i; - break; - } - } - - // Keep marker states - markerSkips--; - if (markerSkips < 0) - shouldRemove = _movie.StartsFromSavestate ? 0 : 1; - } while (_movie.Markers.IsMarker(States.ElementAt(shouldRemove).Key + 1) && markerSkips > -1); - int element = States.ElementAt(shouldRemove).Key; - - // Remove - Used -= States.ElementAt(shouldRemove).Value.Length; - States.RemoveAt(shouldRemove); + RemoveState(States.ElementAt(shouldRemove).Key); } + + if (Used > Settings.Cap) + { + MoveStateToDisk(accessed.Last()); + } + } + private int StateToRemove() + { + int markerSkips = maxStates / 3; + + int shouldRemove = _movie.StartsFromSavestate ? -1 : 0; + do + { + shouldRemove++; + + // No need to have two savestates with only lag frames between them. + for (int i = shouldRemove + 1; i < States.Count - 1; i++) + { + if (AllLag(States.ElementAt(i).Key, States.ElementAt(i + 1).Key)) + { + shouldRemove = i; + break; + } + } + + // Keep marker states + markerSkips--; + if (markerSkips < 0) + shouldRemove = _movie.StartsFromSavestate ? 0 : 1; + } while (_movie.Markers.IsMarker(States.ElementAt(shouldRemove).Key + 1) && markerSkips > -1); + + return shouldRemove; } private bool AllLag(int from, int upTo) { @@ -218,6 +223,75 @@ namespace BizHawk.Client.Common return true; } + private void MoveStateToDisk(int index) + { + // Save + string path = Path.Combine(statePath, index.ToString()); + File.WriteAllBytes(path, States[index]); + DiskUsed += _expectedStateSize; + + // Remove from RAM + Used -= (ulong)States[index].Length; + States[index] = null; + } + private void MoveStateToMemory(int index) + { + // Load + string path = Path.Combine(statePath, index.ToString()); + byte[] loadData = File.ReadAllBytes(path); + DiskUsed -= _expectedStateSize; + + // States list + Used += (ulong)loadData.Length; + States[index] = loadData; + + File.Delete(path); + } + private void SetState(int frame, byte[] state) + { + if (States.ContainsKey(frame)) + { + States[frame] = state; + MaybeRemoveState(); // Also does moving to disk + } + else + { + Used += (ulong)state.Length; + MaybeRemoveState(); // Remove before adding so this state won't be removed. + + States.Add(frame, state); + } + StateAccessed(frame); + } + private void RemoveState(int index) + { + if (States[index] == null) + { + DiskUsed -= _expectedStateSize; // Disk length? + string path = Path.Combine(statePath, index.ToString()); + File.Delete(path); + } + else + Used -= (ulong)States[index].Length; + States.RemoveAt(States.IndexOfKey(index)); + + accessed.Remove(index); + } + private void StateAccessed(int index) + { + bool removed = accessed.Remove(index); + accessed.Add(index); + + if (States[index] == null) + { + MoveStateToDisk(accessed[0]); + MoveStateToMemory(index); + } + + if (!removed && accessed.Count > (int)(Used / _expectedStateSize)) + accessed.RemoveAt(0); + } + public bool HasState(int frame) { if (_movie.StartsFromSavestate && frame == 0) @@ -245,7 +319,10 @@ namespace BizHawk.Client.Common .ToList(); foreach (var state in statesToRemove) { - Used -= state.Value.Length; + if (state.Value == null) + DiskUsed -= _expectedStateSize; // Length?? + else + Used -= (ulong)state.Value.Length; States.Remove(state.Key); } @@ -280,7 +357,7 @@ namespace BizHawk.Client.Common if (power.Value.Length > 0) { States.Add(0, power.Value); - Used = power.Value.Length; + Used = (ulong)power.Value.Length; _lastCapture = 0; } else @@ -293,9 +370,28 @@ namespace BizHawk.Client.Common public void Save(BinaryWriter bw) { + List noSave = new List(); + if (Used + DiskUsed > (ulong)Settings.DiskSaveCapacitymb * 1024 * 1024) + { + ulong saveUsed = Used + DiskUsed; + do + { + int index = StateToRemove(); + noSave.Add(index); + if (States.ElementAt(index).Value == null) + saveUsed -= _expectedStateSize; + else + saveUsed -= (ulong)States.ElementAt(index).Value.Length; + } while (saveUsed > (ulong)Settings.DiskSaveCapacitymb * 1024 * 1024); + } + bw.Write(States.Count); foreach (var kvp in States) { + if (noSave.Contains(kvp.Key)) + continue; + + StateAccessed(kvp.Key); bw.Write(kvp.Key); bw.Write(kvp.Value.Length); bw.Write(kvp.Value); @@ -313,8 +409,9 @@ namespace BizHawk.Client.Common int frame = br.ReadInt32(); int len = br.ReadInt32(); byte[] data = br.ReadBytes(len); - States.Add(frame, data); - Used += len; + SetState(frame, data); + //States.Add(frame, data); + //Used += len; } } } @@ -323,12 +420,7 @@ namespace BizHawk.Client.Common { var s = States.LastOrDefault(state => state.Key < frame); - if (s.Value == null && _movie.StartsFromSavestate) - { - return new KeyValuePair(0, _movie.BinarySavestate); - } - - return s; + return this[s.Key]; } // Map: @@ -338,7 +430,12 @@ namespace BizHawk.Client.Common // 4 bytes - length of savestate // 0 - n savestate - private int Used + private ulong Used + { + get; + set; + } + private ulong DiskUsed { get; set; diff --git a/BizHawk.Client.Common/movie/tasproj/TasStateManagerSettings.cs b/BizHawk.Client.Common/movie/tasproj/TasStateManagerSettings.cs index eb044ea6fe..2ccd8ba8fa 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasStateManagerSettings.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasStateManagerSettings.cs @@ -10,43 +10,73 @@ namespace BizHawk.Client.Common { public TasStateManagerSettings() { - SaveStateHistory = true; + DiskSaveCapacitymb = 512; Capacitymb = 512; + DiskCapacitymb = 512; } public TasStateManagerSettings(TasStateManagerSettings settings) { - SaveStateHistory = settings.SaveStateHistory; + DiskSaveCapacitymb = settings.DiskSaveCapacitymb; Capacitymb = settings.Capacitymb; + DiskCapacitymb = settings.DiskCapacitymb; } /// - /// Whether or not to save greenzone information to disk + /// Whether or not to save state history information to disk /// [DisplayName("Save History")] [Description("Whether or not to use savestate history")] - public bool SaveStateHistory { get; set; } + public bool SaveStateHistory { get { return DiskSaveCapacitymb != 0; } } /// - /// The total amount of memory to devote to greenzone in megabytes + /// The size limit to use when saving the tas project to disk. /// - [DisplayName("Capacity (in megabytes))")] - [Description("The size limit of the state history buffer. When this limit is reached it will start removing previous savestates")] + [DisplayName("Save Capacity (in megabytes)")] + [Description("The size limit to use when saving the tas project to disk.")] + public int DiskSaveCapacitymb { get; set; } + + /// + /// The total amount of memory to devote to state history in megabytes + /// + [DisplayName("Capacity (in megabytes)")] + [Description("The size limit of the state history buffer. When this limit is reached it will start moving to disk.")] public int Capacitymb { get; set; } + /// + /// The total amount of disk space to devote to state history in megabytes + /// + [DisplayName("Disk Capacity (in megabytes)")] + [Description("The size limit of the state history buffer on the disk. When this limit is reached it will start removing previous savestates")] + public int DiskCapacitymb { get; set; } + + /// + /// The total state capacity in bytes. + /// [JsonIgnore] [Browsable(false)] - public int Cap + public ulong CapTotal { - get { return Capacitymb * 1024 * 1024; } + get { return (ulong)(Capacitymb + DiskCapacitymb) * 1024UL * 1024UL; } + } + + /// + /// The memory state capacity in bytes. + /// + [JsonIgnore] + [Browsable(false)] + public ulong Cap + { + get { return (ulong)Capacitymb * 1024UL * 1024UL; } } public override string ToString() { StringBuilder sb = new StringBuilder(); - sb.AppendLine(SaveStateHistory.ToString()); + sb.AppendLine(DiskSaveCapacitymb.ToString()); sb.AppendLine(Capacitymb.ToString()); + sb.AppendLine(DiskCapacitymb.ToString()); return sb.ToString(); } @@ -55,9 +85,22 @@ namespace BizHawk.Client.Common { if (!string.IsNullOrWhiteSpace(settings)) { - var lines = settings.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); - SaveStateHistory = bool.Parse(lines[0]); + string[] lines = settings.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); Capacitymb = int.Parse(lines[1]); + int refCapacity; + if (!int.TryParse(lines[0], out refCapacity)) + { + if (bool.Parse(lines[0])) + DiskSaveCapacitymb = Capacitymb; + else + DiskSaveCapacitymb = 0; + } + else + DiskSaveCapacitymb = refCapacity; + if (lines.Length > 2) + DiskCapacitymb = int.Parse(lines[2]); + else + DiskCapacitymb = 512; } } } diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index c348a2e11e..dbf3eeca5b 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -513,6 +513,10 @@ namespace BizHawk.Client.EmuHawk components.Dispose(); } + // Do not keep TAStudio's disk save states. TODO: This might not be a good place to put this. + if (Directory.Exists(PathManager.MakeAbsolutePath(Global.Config.PathEntries["Global", "TAStudio states"].Path, null))) + Directory.Delete(PathManager.MakeAbsolutePath(Global.Config.PathEntries["Global", "TAStudio states"].Path, null), true); + base.Dispose(disposing); } diff --git a/BizHawk.Client.EmuHawk/tools/Macros/MacroInput.cs b/BizHawk.Client.EmuHawk/tools/Macros/MacroInput.cs index 3e2528f54d..b86a8986fc 100644 --- a/BizHawk.Client.EmuHawk/tools/Macros/MacroInput.cs +++ b/BizHawk.Client.EmuHawk/tools/Macros/MacroInput.cs @@ -219,20 +219,32 @@ namespace BizHawk.Client.EmuHawk private static string SuggestedFolder() { - return PathManager.MakeAbsolutePath(Global.Config.PathEntries.MoviesPathFragment, null) + - "\\Macros"; + return PathManager.MakeAbsolutePath(Path.Combine( + Global.Config.PathEntries["Global", "Macros"].Path, + Global.Game.Name), null); } #endregion public static void SaveMacroAs(MovieZone macro) { SaveFileDialog dialog = new SaveFileDialog(); + bool create = false; + if (!Directory.Exists(SuggestedFolder())) + { + Directory.CreateDirectory(SuggestedFolder()); + create = true; + } dialog.InitialDirectory = SuggestedFolder(); + // Create directory? dialog.Filter = "Movie Macros (*.bk2m)|*.bk2m|All Files|*.*"; DialogResult result = dialog.ShowHawkDialog(); if (result != DialogResult.OK) + { + if (create) + Directory.Delete(dialog.InitialDirectory); return; + } macro.Save(dialog.FileName); Global.Config.RecentMacros.Add(dialog.FileName); diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/GreenzoneSettings.Designer.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/GreenzoneSettings.Designer.cs index 4f867c58b1..596e905a9a 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/GreenzoneSettings.Designer.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/GreenzoneSettings.Designer.cs @@ -38,22 +38,31 @@ namespace BizHawk.Client.EmuHawk System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(StateHistorySettingsForm)); this.CancelBtn = new System.Windows.Forms.Button(); this.OkBtn = new System.Windows.Forms.Button(); - this.SaveStateHistoryCheckbox = new System.Windows.Forms.CheckBox(); - this.CapacityNumeric = new System.Windows.Forms.NumericUpDown(); + this.MemCapacityNumeric = new System.Windows.Forms.NumericUpDown(); this.label1 = new System.Windows.Forms.Label(); this.label2 = new System.Windows.Forms.Label(); this.label3 = new System.Windows.Forms.Label(); this.SavestateSizeLabel = new System.Windows.Forms.Label(); this.label4 = new System.Windows.Forms.Label(); this.NumStatesLabel = new System.Windows.Forms.Label(); - ((System.ComponentModel.ISupportInitialize)(this.CapacityNumeric)).BeginInit(); + this.DiskCapacityNumeric = new System.Windows.Forms.NumericUpDown(); + this.label5 = new System.Windows.Forms.Label(); + this.label6 = new System.Windows.Forms.Label(); + this.SaveCapacityNumeric = new System.Windows.Forms.NumericUpDown(); + this.label7 = new System.Windows.Forms.Label(); + this.label8 = new System.Windows.Forms.Label(); + this.label9 = new System.Windows.Forms.Label(); + this.NumSaveStatesLabel = new System.Windows.Forms.Label(); + ((System.ComponentModel.ISupportInitialize)(this.MemCapacityNumeric)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.DiskCapacityNumeric)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.SaveCapacityNumeric)).BeginInit(); this.SuspendLayout(); // // CancelBtn // this.CancelBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.CancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.CancelBtn.Location = new System.Drawing.Point(236, 96); + this.CancelBtn.Location = new System.Drawing.Point(216, 113); this.CancelBtn.Name = "CancelBtn"; this.CancelBtn.Size = new System.Drawing.Size(60, 23); this.CancelBtn.TabIndex = 0; @@ -64,7 +73,7 @@ namespace BizHawk.Client.EmuHawk // OkBtn // this.OkBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.OkBtn.Location = new System.Drawing.Point(170, 96); + this.OkBtn.Location = new System.Drawing.Point(150, 113); this.OkBtn.Name = "OkBtn"; this.OkBtn.Size = new System.Drawing.Size(60, 23); this.OkBtn.TabIndex = 1; @@ -72,43 +81,33 @@ namespace BizHawk.Client.EmuHawk this.OkBtn.UseVisualStyleBackColor = true; this.OkBtn.Click += new System.EventHandler(this.OkBtn_Click); // - // SaveGreenzoneCheckbox + // MemCapacityNumeric // - this.SaveStateHistoryCheckbox.AutoSize = true; - this.SaveStateHistoryCheckbox.Location = new System.Drawing.Point(13, 20); - this.SaveStateHistoryCheckbox.Name = "SaveGreenzoneCheckbox"; - this.SaveStateHistoryCheckbox.Size = new System.Drawing.Size(234, 17); - this.SaveStateHistoryCheckbox.TabIndex = 2; - this.SaveStateHistoryCheckbox.Text = "Save savestate history information in proj file"; - this.SaveStateHistoryCheckbox.UseVisualStyleBackColor = true; - // - // CapacityNumeric - // - this.CapacityNumeric.Location = new System.Drawing.Point(13, 67); - this.CapacityNumeric.Maximum = new decimal(new int[] { + this.MemCapacityNumeric.Location = new System.Drawing.Point(12, 26); + this.MemCapacityNumeric.Maximum = new decimal(new int[] { 1024, 0, 0, 0}); - this.CapacityNumeric.Minimum = new decimal(new int[] { + this.MemCapacityNumeric.Minimum = new decimal(new int[] { 1, 0, 0, 0}); - this.CapacityNumeric.Name = "CapacityNumeric"; - this.CapacityNumeric.Size = new System.Drawing.Size(48, 20); - this.CapacityNumeric.TabIndex = 3; - this.CapacityNumeric.Value = new decimal(new int[] { + this.MemCapacityNumeric.Name = "MemCapacityNumeric"; + this.MemCapacityNumeric.Size = new System.Drawing.Size(55, 20); + this.MemCapacityNumeric.TabIndex = 3; + this.MemCapacityNumeric.Value = new decimal(new int[] { 512, 0, 0, 0}); - this.CapacityNumeric.ValueChanged += new System.EventHandler(this.CapacityNumeric_ValueChanged); + this.MemCapacityNumeric.ValueChanged += new System.EventHandler(this.CapacityNumeric_ValueChanged); // // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(61, 70); + this.label1.Location = new System.Drawing.Point(67, 29); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(21, 13); this.label1.TabIndex = 4; @@ -117,16 +116,16 @@ namespace BizHawk.Client.EmuHawk // label2 // this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(13, 50); + this.label2.Location = new System.Drawing.Point(12, 9); this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(99, 13); + this.label2.Size = new System.Drawing.Size(88, 13); this.label2.TabIndex = 5; - this.label2.Text = "Savestate Capacity"; + this.label2.Text = "Memory Capacity"; // // label3 // this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(127, 50); + this.label3.Location = new System.Drawing.Point(126, 9); this.label3.Name = "label3"; this.label3.Size = new System.Drawing.Size(79, 13); this.label3.TabIndex = 6; @@ -135,7 +134,7 @@ namespace BizHawk.Client.EmuHawk // SavestateSizeLabel // this.SavestateSizeLabel.AutoSize = true; - this.SavestateSizeLabel.Location = new System.Drawing.Point(209, 50); + this.SavestateSizeLabel.Location = new System.Drawing.Point(208, 9); this.SavestateSizeLabel.Name = "SavestateSizeLabel"; this.SavestateSizeLabel.Size = new System.Drawing.Size(25, 13); this.SavestateSizeLabel.TabIndex = 7; @@ -144,7 +143,7 @@ namespace BizHawk.Client.EmuHawk // label4 // this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(122, 70); + this.label4.Location = new System.Drawing.Point(9, 89); this.label4.Name = "label4"; this.label4.Size = new System.Drawing.Size(84, 13); this.label4.TabIndex = 8; @@ -153,36 +152,145 @@ namespace BizHawk.Client.EmuHawk // NumStatesLabel // this.NumStatesLabel.AutoSize = true; - this.NumStatesLabel.Location = new System.Drawing.Point(209, 70); + this.NumStatesLabel.Location = new System.Drawing.Point(96, 89); this.NumStatesLabel.Name = "NumStatesLabel"; this.NumStatesLabel.Size = new System.Drawing.Size(25, 13); this.NumStatesLabel.TabIndex = 9; this.NumStatesLabel.Text = "1kb"; // - // GreenzoneSettingsForm + // DiskCapacityNumeric + // + this.DiskCapacityNumeric.Location = new System.Drawing.Point(12, 66); + this.DiskCapacityNumeric.Maximum = new decimal(new int[] { + 65536, + 0, + 0, + 0}); + this.DiskCapacityNumeric.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.DiskCapacityNumeric.Name = "DiskCapacityNumeric"; + this.DiskCapacityNumeric.Size = new System.Drawing.Size(55, 20); + this.DiskCapacityNumeric.TabIndex = 3; + this.DiskCapacityNumeric.Value = new decimal(new int[] { + 512, + 0, + 0, + 0}); + this.DiskCapacityNumeric.ValueChanged += new System.EventHandler(this.CapacityNumeric_ValueChanged); + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(67, 69); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(21, 13); + this.label5.TabIndex = 4; + this.label5.Text = "mb"; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(12, 49); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(72, 13); + this.label6.TabIndex = 5; + this.label6.Text = "Disk Capacity"; + // + // SaveCapacityNumeric + // + this.SaveCapacityNumeric.Location = new System.Drawing.Point(158, 66); + this.SaveCapacityNumeric.Maximum = new decimal(new int[] { + 65536, + 0, + 0, + 0}); + this.SaveCapacityNumeric.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.SaveCapacityNumeric.Name = "SaveCapacityNumeric"; + this.SaveCapacityNumeric.Size = new System.Drawing.Size(55, 20); + this.SaveCapacityNumeric.TabIndex = 3; + this.SaveCapacityNumeric.Value = new decimal(new int[] { + 512, + 0, + 0, + 0}); + this.SaveCapacityNumeric.ValueChanged += new System.EventHandler(this.SaveCapacityNumeric_ValueChanged); + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(213, 69); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(21, 13); + this.label7.TabIndex = 4; + this.label7.Text = "mb"; + // + // label8 + // + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(158, 49); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(112, 13); + this.label8.TabIndex = 5; + this.label8.Text = "Project Save Capacity"; + // + // label9 + // + this.label9.AutoSize = true; + this.label9.Location = new System.Drawing.Point(155, 89); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(84, 13); + this.label9.TabIndex = 8; + this.label9.Text = "Max num states:"; + // + // NumSaveStatesLabel + // + this.NumSaveStatesLabel.AutoSize = true; + this.NumSaveStatesLabel.Location = new System.Drawing.Point(242, 89); + this.NumSaveStatesLabel.Name = "NumSaveStatesLabel"; + this.NumSaveStatesLabel.Size = new System.Drawing.Size(25, 13); + this.NumSaveStatesLabel.TabIndex = 9; + this.NumSaveStatesLabel.Text = "1kb"; + // + // StateHistorySettingsForm // this.AcceptButton = this.OkBtn; this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.CancelBtn; - this.ClientSize = new System.Drawing.Size(308, 131); + this.ClientSize = new System.Drawing.Size(288, 148); + this.Controls.Add(this.NumSaveStatesLabel); this.Controls.Add(this.NumStatesLabel); + this.Controls.Add(this.label9); this.Controls.Add(this.label4); this.Controls.Add(this.SavestateSizeLabel); this.Controls.Add(this.label3); + this.Controls.Add(this.label8); + this.Controls.Add(this.label7); + this.Controls.Add(this.label6); + this.Controls.Add(this.label5); + this.Controls.Add(this.SaveCapacityNumeric); this.Controls.Add(this.label2); + this.Controls.Add(this.DiskCapacityNumeric); this.Controls.Add(this.label1); - this.Controls.Add(this.CapacityNumeric); - this.Controls.Add(this.SaveStateHistoryCheckbox); + this.Controls.Add(this.MemCapacityNumeric); this.Controls.Add(this.OkBtn); this.Controls.Add(this.CancelBtn); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.MinimumSize = new System.Drawing.Size(225, 165); - this.Name = "GreenzoneSettingsForm"; + this.Name = "StateHistorySettingsForm"; this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; this.Text = "Savestate History Settings"; this.Load += new System.EventHandler(this.StateHistorySettings_Load); - ((System.ComponentModel.ISupportInitialize)(this.CapacityNumeric)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.MemCapacityNumeric)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.DiskCapacityNumeric)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.SaveCapacityNumeric)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -190,13 +298,20 @@ namespace BizHawk.Client.EmuHawk private Button CancelBtn; private Button OkBtn; - private CheckBox SaveStateHistoryCheckbox; - private NumericUpDown CapacityNumeric; + private NumericUpDown MemCapacityNumeric; private Label label1; private Label label2; private Label label3; private Label SavestateSizeLabel; private Label label4; private Label NumStatesLabel; + private NumericUpDown DiskCapacityNumeric; + private Label label5; + private Label label6; + private NumericUpDown SaveCapacityNumeric; + private Label label7; + private Label label8; + private Label label9; + private Label NumSaveStatesLabel; } } diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/GreenzoneSettings.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/GreenzoneSettings.cs index 003b5c9947..2bccac30a1 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/GreenzoneSettings.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/GreenzoneSettings.cs @@ -29,24 +29,33 @@ namespace BizHawk.Client.EmuHawk { _stateSizeMb = Statable.SaveStateBinary().Length / (decimal)1024 / (decimal)1024; - SaveStateHistoryCheckbox.Checked = Settings.SaveStateHistory; - CapacityNumeric.Value = Settings.Capacitymb == 0 ? 1 : Settings.Capacitymb < CapacityNumeric.Maximum ? - Settings.Capacitymb : - CapacityNumeric.Maximum; + if (Environment.Is64BitProcess) // ? + MemCapacityNumeric.Maximum = 1024 * 8; + else + MemCapacityNumeric.Maximum = 1024; + + MemCapacityNumeric.Value = Settings.Capacitymb == 0 ? 1 : Settings.Capacitymb < MemCapacityNumeric.Maximum ? + Settings.Capacitymb : MemCapacityNumeric.Maximum; + DiskCapacityNumeric.Value = Settings.DiskCapacitymb == 0 ? 1 : Settings.DiskCapacitymb < MemCapacityNumeric.Maximum ? + Settings.DiskCapacitymb : MemCapacityNumeric.Maximum; + SaveCapacityNumeric.Value = Settings.DiskSaveCapacitymb == 0 ? 1 : Settings.DiskSaveCapacitymb < MemCapacityNumeric.Maximum ? + Settings.DiskSaveCapacitymb : MemCapacityNumeric.Maximum; SavestateSizeLabel.Text = Math.Round(_stateSizeMb, 2).ToString() + " mb"; CapacityNumeric_ValueChanged(null, null); + SaveCapacityNumeric_ValueChanged(null, null); } - private ulong MaxStatesInCapacity + private int MaxStatesInCapacity { - get { return (ulong)Math.Floor(CapacityNumeric.Value / _stateSizeMb); } + get { return (int)Math.Floor((MemCapacityNumeric.Value + DiskCapacityNumeric.Value) / _stateSizeMb); } } private void OkBtn_Click(object sender, EventArgs e) { - Settings.SaveStateHistory = SaveStateHistoryCheckbox.Checked; - Settings.Capacitymb = (int)CapacityNumeric.Value; + Settings.Capacitymb = (int)MemCapacityNumeric.Value; + Settings.DiskCapacitymb = (int)DiskCapacityNumeric.Value; + Settings.DiskSaveCapacitymb = (int)SaveCapacityNumeric.Value; DialogResult = DialogResult.OK; Close(); } @@ -59,7 +68,14 @@ namespace BizHawk.Client.EmuHawk private void CapacityNumeric_ValueChanged(object sender, EventArgs e) { + // TODO: Setting space for 2.6 (2) states in memory and 2.6 (2) on disk results in 5 total. + // Easy to fix the display, but the way TasStateManager works the total used actually is 5. NumStatesLabel.Text = MaxStatesInCapacity.ToString(); } + + private void SaveCapacityNumeric_ValueChanged(object sender, EventArgs e) + { + NumSaveStatesLabel.Text = ((int)Math.Floor(SaveCapacityNumeric.Value / _stateSizeMb)).ToString(); + } } } diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/InputRoll.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/InputRoll.cs index e65593e80b..18b317495e 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/InputRoll.cs @@ -39,7 +39,7 @@ namespace BizHawk.Client.EmuHawk // Hiding lag frames (Mainly intended for < 60fps play.) public int LagFramesToHide { get; set; } public bool HideWasLagFrames { get; set; } - private int[] lagFrames = new int[100]; // Large enough value that it shouldn't ever need resizing. + private byte[] lagFrames = new byte[100]; // Large enough value that it shouldn't ever need resizing. private IntPtr RotatedFont; private Font NormalFont; @@ -1606,7 +1606,8 @@ namespace BizHawk.Client.EmuHawk } while (lagFrames[0] != 0 && VBar.Value != 0 && VBar.Value != VBar.Maximum); } - OnMouseMove(new MouseEventArgs(System.Windows.Forms.MouseButtons.None, 0, _currentX.Value, _currentY.Value, 0)); + if (_currentX != null) + OnMouseMove(new MouseEventArgs(System.Windows.Forms.MouseButtons.None, 0, _currentX.Value, _currentY.Value, 0)); Refresh(); } } @@ -2211,7 +2212,7 @@ namespace BizHawk.Client.EmuHawk { fCount++; } while (QueryFrameLag(FirstVisibleRow + fCount, HideWasLagFrames) && count + fCount < LagFramesToHide); - lagFrames[0] = fCount; + lagFrames[0] = (byte)fCount; } else lagFrames[0] = 0; diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs index 617004b27d..6e482edc82 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs @@ -120,6 +120,9 @@ namespace BizHawk.Client.EmuHawk private void saveSelectionToMacroToolStripMenuItem_Click(object sender, EventArgs e) { + if (TasView.LastSelectedIndex == CurrentTasMovie.InputLogLength) + TasView.SelectRow(CurrentTasMovie.InputLogLength, false); + if (!TasView.SelectedRows.Any()) return; diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Navigation.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Navigation.cs index 5ed025ca4a..550b83f5cf 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Navigation.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.Navigation.cs @@ -43,7 +43,7 @@ namespace BizHawk.Client.EmuHawk if (CurrentTasMovie[goToFrame].HasState) // Go back 1 frame and emulate to get the display (we don't store that) { CurrentTasMovie.SwitchToPlay(); - LoadState(CurrentTasMovie[goToFrame].State); + LoadState(CurrentTasMovie.TasStateManager[frame]); // STATE ACCESS if (frame > 0) // We can't emulate up to frame 0! { @@ -71,7 +71,7 @@ namespace BizHawk.Client.EmuHawk if (CurrentTasMovie[goToFrame].HasState) // Can we go directly there? { CurrentTasMovie.SwitchToPlay(); - LoadState(CurrentTasMovie[goToFrame].State); + LoadState(CurrentTasMovie.TasStateManager[frame]); // STATE ACCESS Emulator.FrameAdvance(true); GlobalWin.DisplayManager.NeedsToPaint = true; @@ -99,7 +99,7 @@ namespace BizHawk.Client.EmuHawk // no reason to loadstate when we can emulate a frame instead if (frame - Emulator.Frame != 1) { - LoadState(CurrentTasMovie[CurrentTasMovie.TasStateManager.LastEmulatedFrame].State); + LoadState(CurrentTasMovie.TasStateManager[CurrentTasMovie.TasStateManager.LastEmulatedFrame]); // STATE ACCESS } if (frame != Emulator.Frame) // If we aren't already at our destination, seek