From 25e54f4390e5d36320a079523df1deb412d33596 Mon Sep 17 00:00:00 2001 From: SuuperW Date: Tue, 3 Mar 2015 06:56:45 +0000 Subject: [PATCH] -More StateHistory names -Smarter state history management TAStudio: A few bugfixes and performance boosts --- BizHawk.Client.Common/BinarySaveStates.cs | 8 +- .../movie/bk2/Bk2MnemonicConstants.cs | 13 +-- .../movie/tasproj/TasMovie.IO.cs | 10 +- .../movie/tasproj/TasMovie.cs | 9 +- .../movie/tasproj/TasStateManager.cs | 93 ++++++++++++++----- .../tools/TAStudio/InputRoll.cs | 58 ++++++++++-- .../tools/TAStudio/TAStudio.IToolForm.cs | 6 +- .../tools/TAStudio/TAStudio.ListView.cs | 10 +- .../tools/TAStudio/TAStudio.MenuItems.cs | 10 +- .../tools/TAStudio/TAStudio.cs | 21 +++-- 10 files changed, 166 insertions(+), 72 deletions(-) diff --git a/BizHawk.Client.Common/BinarySaveStates.cs b/BizHawk.Client.Common/BinarySaveStates.cs index 1be2a086f4..6cbb5dda66 100644 --- a/BizHawk.Client.Common/BinarySaveStates.cs +++ b/BizHawk.Client.Common/BinarySaveStates.cs @@ -23,8 +23,8 @@ namespace BizHawk.Client.Common // TasMovie LagLog, - Greenzone, // Greenzone actually means StateHistory. Changing these two names would break previous save files, though. - GreenzoneSettings, + StateHistory, + StateHistorySettings, Markers, ClientSettings, VerificationLog @@ -58,8 +58,8 @@ namespace BizHawk.Client.Common // TasMovie AddLumpName(BinaryStateLump.LagLog, "LagLog"); - AddLumpName(BinaryStateLump.Greenzone, "GreenZone"); - AddLumpName(BinaryStateLump.GreenzoneSettings, "GreenZoneSettings.txt"); + AddLumpName(BinaryStateLump.StateHistory, "GreenZone"); + AddLumpName(BinaryStateLump.StateHistorySettings, "GreenZoneSettings.txt"); AddLumpName(BinaryStateLump.Markers, "Markers.txt"); AddLumpName(BinaryStateLump.ClientSettings, "ClientSettings.json"); AddLumpName(BinaryStateLump.VerificationLog, "VerificationLog.txt"); diff --git a/BizHawk.Client.Common/movie/bk2/Bk2MnemonicConstants.cs b/BizHawk.Client.Common/movie/bk2/Bk2MnemonicConstants.cs index db01ca960b..3ff1fff3ae 100644 --- a/BizHawk.Client.Common/movie/bk2/Bk2MnemonicConstants.cs +++ b/BizHawk.Client.Common/movie/bk2/Bk2MnemonicConstants.cs @@ -8,16 +8,9 @@ namespace BizHawk.Client.Common { get { - var key = button - .Replace("P1 ", "") - .Replace("P2 ", "") - .Replace("P3 ", "") - .Replace("P4 ", "") - .Replace("P5 ", "") - .Replace("P6 ", "") - .Replace("P7 ", "") - .Replace("P8 ", "") - .Replace("Key ", ""); + var key = button.Replace("Key ", ""); + if (key.StartsWith("P") && key[1] >= '0' && key[1] <= '9') + key = key.Substring(3); if (SystemOverrides.ContainsKey(Global.Emulator.SystemId) && SystemOverrides[Global.Emulator.SystemId].ContainsKey(key)) { diff --git a/BizHawk.Client.Common/movie/tasproj/TasMovie.IO.cs b/BizHawk.Client.Common/movie/tasproj/TasMovie.IO.cs index ee9480a02e..0677f21f49 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasMovie.IO.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasMovie.IO.cs @@ -54,12 +54,11 @@ namespace BizHawk.Client.Common ReportProgress(PROGRESS_STEP); // TasProj extras - // Greenzone actually means StateHistory. Changing these two names would break previous save files, though. - bs.PutLump(BinaryStateLump.GreenzoneSettings, tw => tw.WriteLine(StateManager.Settings.ToString())); + bs.PutLump(BinaryStateLump.StateHistorySettings, tw => tw.WriteLine(StateManager.Settings.ToString())); ReportProgress(PROGRESS_STEP); if (StateManager.Settings.SaveStateHistory) { - bs.PutLump(BinaryStateLump.Greenzone, (BinaryWriter bw) => StateManager.Save(bw)); + bs.PutLump(BinaryStateLump.StateHistory, (BinaryWriter bw) => StateManager.Save(bw)); } ReportProgress(PROGRESS_STEP); @@ -198,15 +197,14 @@ namespace BizHawk.Client.Common }); } - // Greenzone actually means StateHistory. Changing these two names would break previous save files, though. - bl.GetLump(BinaryStateLump.GreenzoneSettings, false, delegate(TextReader tr) + bl.GetLump(BinaryStateLump.StateHistorySettings, false, delegate(TextReader tr) { StateManager.Settings.PopulateFromString(tr.ReadToEnd()); }); if (StateManager.Settings.SaveStateHistory) { - bl.GetLump(BinaryStateLump.Greenzone, false, delegate(BinaryReader br, long length) + bl.GetLump(BinaryStateLump.StateHistory, false, delegate(BinaryReader br, long length) { StateManager.Load(br); }); diff --git a/BizHawk.Client.Common/movie/tasproj/TasMovie.cs b/BizHawk.Client.Common/movie/tasproj/TasMovie.cs index 5fdceb758d..af0ca787e8 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasMovie.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasMovie.cs @@ -185,9 +185,14 @@ namespace BizHawk.Client.Common return CreateDisplayValueForButton(adapter, buttonName); } - public void FlushInputCache() + public void FlushInputCache(int FrameToLeave = 0) { - InputStateCache.Clear(); + if (InputStateCache.Count <= FrameToLeave) + return; + do + { + InputStateCache.Remove(InputStateCache.Keys.First()); + } while (InputStateCache.Count > FrameToLeave); } public string CreateDisplayValueForButton(IController adapter, string buttonName) diff --git a/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs b/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs index bcb3dd8a0c..41c078f59e 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs @@ -31,7 +31,7 @@ namespace BizHawk.Client.Common private int _expectedStateSize = 0; private int _minFrequency = VersionInfo.DeveloperBuild ? 2 : 1; - private const int _maxFrequency = 16; + private const int _maxFrequency = 16; private int StateFrequency { get @@ -51,6 +51,7 @@ namespace BizHawk.Client.Common return freq; } } + private int _lastCapture = 0; public TasStateManager(TasMovie movie) { @@ -61,7 +62,7 @@ namespace BizHawk.Client.Common var cap = Settings.Cap; int limit = 0; - + _expectedStateSize = Core.SaveStateBinary().Length; if (_expectedStateSize > 0) @@ -85,15 +86,15 @@ namespace BizHawk.Client.Common { if (frame == 0 && _movie.StartsFromSavestate) { - return new KeyValuePair(0, _movie.BinarySavestate); + return new KeyValuePair(0, _movie.BinarySavestate); } if (States.ContainsKey(frame)) { - return new KeyValuePair(frame, States[frame]); + return new KeyValuePair(frame, States[frame]); } - return new KeyValuePair(-1, new byte[0]); + return new KeyValuePair(-1, new byte[0]); } } @@ -118,7 +119,8 @@ namespace BizHawk.Client.Common { bool shouldCapture = false; - if (_movie.StartsFromSavestate && Global.Emulator.Frame == 0) // Never capture frame 0 on savestate anchored movies since we have it anyway + int frame = Global.Emulator.Frame; + if (_movie.StartsFromSavestate && frame == 0) // Never capture frame 0 on savestate anchored movies since we have it anyway { shouldCapture = false; } @@ -126,22 +128,21 @@ namespace BizHawk.Client.Common { shouldCapture = force; } - else if (Global.Emulator.Frame == 0) // For now, long term, TasMovie should have a .StartState property, and a tasproj file for the start state in non-savestate anchored movies + else if (frame == 0) // For now, long term, TasMovie should have a .StartState property, and a tasproj file for the start state in non-savestate anchored movies { shouldCapture = true; } - else if (_movie.Markers.IsMarker(Global.Emulator.Frame)) + else if (_movie.Markers.IsMarker(frame)) { shouldCapture = true; // Markers shoudl always get priority } else { - shouldCapture = Global.Emulator.Frame % StateFrequency == 0; + shouldCapture = frame - _lastCapture >= StateFrequency; } if (shouldCapture) { - var frame = Global.Emulator.Frame; var state = (byte[])Core.SaveStateBinary().Clone(); if (States.ContainsKey(frame)) @@ -150,18 +151,55 @@ namespace BizHawk.Client.Common } else { - if (Used + state.Length >= Settings.Cap) - { - var first = _movie.StartsFromSavestate ? 0 : 1; - - Used -= States.ElementAt(first).Value.Length; - States.RemoveAt(first); - } - States.Add(frame, state); Used += state.Length; + + MaybeRemoveState(); + } + + _lastCapture = frame; + } + } + + private void MaybeRemoveState() + { + int shouldRemove = -1; + if (Used >= Settings.Cap) + shouldRemove = _movie.StartsFromSavestate ? 0 : 1; + if (shouldRemove != -1) // Which one to remove? + { + for (int i = shouldRemove; i < States.Count - 1; i++) + { + if (AllLag(States.ElementAt(i).Key, States.ElementAt(i + 1).Key)) + { + shouldRemove = i; + break; + } } } + + if (shouldRemove != -1) + { + Used -= States.ElementAt(shouldRemove).Value.Length; + States.RemoveAt(shouldRemove); + } + } + private bool AllLag(int from, int upTo) + { + if (upTo >= Global.Emulator.Frame) + { + upTo = Global.Emulator.Frame - 1; + if (!Global.Emulator.AsInputPollable().IsLagFrame) + return false; + } + + for (int i = from; i < upTo; i++) + { + if (!_movie[i].Lagged.Value) + return false; + } + + return true; } public bool HasState(int frame) @@ -170,7 +208,7 @@ namespace BizHawk.Client.Common { return true; } - + return States.ContainsKey(frame); } @@ -194,6 +232,14 @@ namespace BizHawk.Client.Common Used -= state.Value.Length; States.Remove(state.Key); } + + if (!States.ContainsKey(_lastCapture)) + { + if (States.Count == 0) + _lastCapture = -1; + else + _lastCapture = States.Last().Key; + } } } @@ -205,6 +251,7 @@ namespace BizHawk.Client.Common { States.Clear(); Used = 0; + _lastCapture = -1; } public void ClearStateHistory() @@ -218,10 +265,12 @@ namespace BizHawk.Client.Common { States.Add(0, power.Value); Used = power.Value.Length; + _lastCapture = 0; } else { Used = 0; + _lastCapture = -1; } } } @@ -301,14 +350,12 @@ namespace BizHawk.Client.Common { get { - var kk = States.Keys; - int index = kk.Count; - if (index == 0) + if (States.Count == 0) { return 0; } - return kk[index - 1]; + return States.Last().Key; } } diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/InputRoll.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/InputRoll.cs index ea921b918f..ed50644839 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/InputRoll.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/InputRoll.cs @@ -36,7 +36,7 @@ namespace BizHawk.Client.EmuHawk private int? _currentX; private int? _currentY; - // Hiding lag frames (Mainly intended for 30fps play.) + // Hiding lag frames (Mainly intended for < 60fps play.) public int LagFramesToHide { get; set; } private int[] lagFrames = new int[100]; // Large enough value that it shouldn't ever need resizing. @@ -563,6 +563,8 @@ namespace BizHawk.Client.EmuHawk } } + [Browsable(false)] + [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] private int LastFullyVisibleRow { get @@ -573,6 +575,8 @@ namespace BizHawk.Client.EmuHawk return FirstVisibleRow + VisibleRows - HalfRow + CountLagFramesDisplay(VisibleRows - HalfRow); } } + [Browsable(false)] + [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] public int LastVisibleRow { get @@ -635,6 +639,44 @@ namespace BizHawk.Client.EmuHawk } } + /// + /// Gets the first visible column index, if scrolling is needed + /// + [Browsable(false)] + [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] + public int FirstVisibleColumn + { + get + { + List columnList = VisibleColumns.ToList(); + if (HorizontalOrientation) + return VBar.Value / CellHeight; + else + return columnList.FindIndex(c => c.Right > 0); + } + } + + [Browsable(false)] + [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] + public int LastVisibleColumnIndex + { + get + { + List columnList = VisibleColumns.ToList(); + int ret; + if (HorizontalOrientation) + { + ret = (VBar.Value + DrawHeight) / CellHeight; + if (ret >= columnList.Count) + ret = columnList.Count - 1; + } + else + ret = columnList.FindLastIndex(c => c.Left <= DrawWidth); + + return ret; + } + } + [Browsable(false)] [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)] public IEnumerable SelectedRows @@ -800,7 +842,8 @@ namespace BizHawk.Client.EmuHawk for (int i = 0, f = 0; f < range; i++, f++) { f += lagFrames[i]; - for (int j = 0; j < columns.Count; j++) + int LastVisible = LastVisibleColumnIndex; + for (int j = FirstVisibleColumn; j <= LastVisible; j++) { Bitmap image = null; int x = 0; @@ -859,7 +902,8 @@ namespace BizHawk.Client.EmuHawk for (int i = 0, f = 0; f < range; i++, f++) // Vertical { f += lagFrames[i]; - for (int j = 0; j < columns.Count; j++) // Horizontal + int LastVisible = LastVisibleColumnIndex; + for (int j = FirstVisibleColumn; j <= LastVisible; j++) // Horizontal { var col = columns[j]; if (col.Left.Value < 0 || col.Left.Value > DrawWidth) @@ -1173,7 +1217,8 @@ namespace BizHawk.Client.EmuHawk for (int i = 0, f = 0; f < range; i++, f++) { f += lagFrames[i]; - for (int j = 0; j < columns.Count; j++) // TODO: Don't query all columns + int LastVisible = LastVisibleColumnIndex; + for (int j = FirstVisibleColumn; j <= LastVisible; j++) // TODO: Don't query all columns { var color = Color.White; QueryItemBkColor(f + startIndex, columns[j], ref color); @@ -1198,7 +1243,8 @@ namespace BizHawk.Client.EmuHawk for (int i = 0, f = 0; f < range; i++, f++) // Vertical { f += lagFrames[i]; - for (int j = 0; j < columns.Count; j++) // Horizontal + int LastVisible = LastVisibleColumnIndex; + for (int j = FirstVisibleColumn; j <= LastVisible; j++) // Horizontal { var color = Color.White; QueryItemBkColor(f + startRow, columns[j], ref color); @@ -2078,7 +2124,7 @@ namespace BizHawk.Client.EmuHawk } } else - for (int i = 0; i < VisibleRows; i++) + for (int i = 0; i <= VisibleRows; i++) lagFrames[i] = 0; } private void SetLagFramesFirst() diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.IToolForm.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.IToolForm.cs index 49e0fcb005..b4dbee6606 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.IToolForm.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.IToolForm.cs @@ -30,7 +30,7 @@ namespace BizHawk.Client.EmuHawk return; } - if (TasPlaybackBox.FollowCursor) // TODO: we already refreshed in RefreshDialog now we will do it again, make this more efficient + if (TasPlaybackBox.FollowCursor) { SetVisibleIndex(); } @@ -73,7 +73,7 @@ namespace BizHawk.Client.EmuHawk TasView.AllColumns.Clear(); NewDefaultProject(); SetUpColumns(); - TasView.Refresh(); + RefreshTasView(); } else { @@ -125,7 +125,7 @@ namespace BizHawk.Client.EmuHawk { indexThatMustBeVisible = CurrentTasMovie.IsRecording ? CurrentTasMovie.InputLogLength - : Emulator.Frame + 1; + : Emulator.Frame; } if (!TasView.IsVisible(indexThatMustBeVisible.Value)) diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs index dae9310858..8eb9bbc027 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs @@ -233,7 +233,7 @@ namespace BizHawk.Client.EmuHawk Global.StickyXORAdapter.SetSticky(e.Column.Name, e.Column.Emphasis); - TasView.Refresh(); + RefreshTasView(); } private void TasView_ColumnReordered(object sender, InputRoll.ColumnReorderedEventArgs e) @@ -270,7 +270,7 @@ namespace BizHawk.Client.EmuHawk if (_floatEditColumn != buttonName || _floatEditRow != frame) { _floatEditRow = -1; - TasView.Refresh(); + RefreshTasView(); } else { @@ -454,7 +454,7 @@ namespace BizHawk.Client.EmuHawk TasView.SelectRow(i, _frameDragState); } - TasView.Refresh(); + RefreshTasView(); } } else if (TasView.IsPaintDown && e.NewCell.RowIndex.HasValue && !string.IsNullOrEmpty(_startBoolDrawColumn)) @@ -468,7 +468,7 @@ namespace BizHawk.Client.EmuHawk _triggerAutoRestoreFromFrame = TasView.CurrentCell.RowIndex.Value; } - TasView.Refresh(); + RefreshTasView(); } } else if (TasView.IsPaintDown && e.NewCell.RowIndex.HasValue && !string.IsNullOrEmpty(_startFloatDrawColumn)) @@ -485,7 +485,7 @@ namespace BizHawk.Client.EmuHawk } } - TasView.Refresh(); + RefreshTasView(); } } } diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs index 0b67e99693..69cf882b86 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs @@ -185,13 +185,13 @@ namespace BizHawk.Client.EmuHawk private void DeselectMenuItem_Click(object sender, EventArgs e) { TasView.DeselectAll(); - TasView.Refresh(); + RefreshTasView(); } private void SelectAllMenuItem_Click(object sender, EventArgs e) { TasView.SelectAll(); - TasView.Refresh(); + RefreshTasView(); } private void SelectBetweenMarkersMenuItem_Click(object sender, EventArgs e) @@ -705,7 +705,7 @@ namespace BizHawk.Client.EmuHawk dummyColumnObject.Visible ^= true; TasView.AllColumns.ColumnsChanged(); CurrentTasMovie.FlagChanges(); - TasView.Refresh(); + RefreshTasView(); }; ColumnsSubMenu.DropDownItems.Add(menuItem); @@ -722,7 +722,7 @@ namespace BizHawk.Client.EmuHawk { TasView.AllColumns.Clear(); SetUpColumns(); - TasView.Refresh(); + RefreshTasView(); CurrentTasMovie.FlagChanges(); }; @@ -760,7 +760,7 @@ namespace BizHawk.Client.EmuHawk private void CancelSeekContextMenuItem_Click(object sender, EventArgs e) { GlobalWin.MainForm.PauseOnFrame = null; - TasView.Refresh(); + RefreshTasView(); } private void StartNewProjectFromNowMenuItem_Click(object sender, EventArgs e) diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs index 056785b904..158457de61 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs @@ -226,7 +226,7 @@ namespace BizHawk.Client.EmuHawk private void GetClientSettingsOnLoad(string settingsJson) { TasView.LoadSettingsSerialized(settingsJson); - TasView.Refresh(); + RefreshTasView(); } private void SetTextProperty() @@ -292,13 +292,7 @@ namespace BizHawk.Client.EmuHawk public void RefreshDialog() { - CurrentTasMovie.FlushInputCache(); - CurrentTasMovie.UseInputCache = true; - TasView.RowCount = CurrentTasMovie.InputLogLength + 1; - TasView.Refresh(); - - CurrentTasMovie.FlushInputCache(); - CurrentTasMovie.UseInputCache = false; + RefreshTasView(); if (MarkerControl != null) { @@ -306,6 +300,17 @@ namespace BizHawk.Client.EmuHawk } } + private void RefreshTasView() + { + CurrentTasMovie.UseInputCache = true; + TasView.RowCount = CurrentTasMovie.InputLogLength + 1; + TasView.Refresh(); + + CurrentTasMovie.FlushInputCache(TasView.VisibleRows); + CurrentTasMovie.UseInputCache = false; + + } + private void DoAutoRestore() { if (Settings.AutoRestoreLastPosition && _autoRestoreFrame.HasValue)