-More work on TasStateManager

-Fix: SaveStateSettingsForm was setting the disk capacity to 1 mb on load if it had been set to 0.
This commit is contained in:
Suuper 2015-08-17 11:32:46 -05:00
parent f76c49ce1b
commit 1f4b0d5d77
2 changed files with 120 additions and 74 deletions

View File

@ -4,6 +4,7 @@ using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Drawing;
using BizHawk.Common;
using BizHawk.Emulation.Common;
@ -28,7 +29,6 @@ namespace BizHawk.Client.Common
_state = state;
Frame = frame;
//I still think this is a bad idea. IDs may need scavenging somehow
if (state_id > long.MaxValue - 100)
throw new InvalidOperationException();
ID = System.Threading.Interlocked.Increment(ref state_id);
@ -46,13 +46,9 @@ namespace BizHawk.Client.Common
set
{
if (_state != null)
{
_state = value;
return;
}
_state = value;
MoveToDisk();
else
throw new Exception("Attempted to set a state to null.");
}
}
public int Length { get { return State.Length; } }
@ -158,6 +154,9 @@ namespace BizHawk.Client.Common
Settings = new TasStateManagerSettings(Global.Config.DefaultTasProjSettings);
accessed = new List<tsmState>();
if (_movie.StartsFromSavestate)
SetState(0, _movie.BinarySavestate);
}
public void Dispose()
@ -205,11 +204,6 @@ namespace BizHawk.Client.Common
{
get
{
if (frame == 0 && _movie.StartsFromSavestate)
{
return new KeyValuePair<int, byte[]>(0, _movie.BinarySavestate);
}
if (States.ContainsKey(frame))
{
StateAccessed(frame);
@ -271,14 +265,13 @@ namespace BizHawk.Client.Common
}
private List<tsmState> lowPriorityStates = new List<tsmState>();
private void MaybeRemoveState()
private void MaybeRemoveStates()
{
int shouldRemove = -1;
if (Used + DiskUsed > Settings.CapTotal)
shouldRemove = StateToRemove();
if (shouldRemove != -1)
// Loop, because removing a state that has a duplicate won't save any space
while (Used > Settings.Cap || DiskUsed > (ulong)Settings.DiskCapacitymb * 1024 * 1024)
{
RemoveState(States.ElementAt(shouldRemove).Key);
Point shouldRemove = StateToRemove();
RemoveState(shouldRemove.X, shouldRemove.Y);
}
if (Used > Settings.Cap)
@ -288,37 +281,81 @@ namespace BizHawk.Client.Common
MoveStateToDisk(accessed[lastMemState].Frame);
}
}
private int StateToRemove()
/// <summary>
/// X is the frame of the state, Y is the branch (-1 for current).
/// </summary>
private Point StateToRemove()
{
int markerSkips = maxStates / 3;
int markerSkips = maxStates / 2;
int shouldRemove = _movie.StartsFromSavestate ? -1 : 0;
//int minFrames = 999;
// X is frame, Y is branch
Point shouldRemove = new Point(-1, -1);
int i = 0;
// lowPrioritySates (e.g. states with only lag frames between them)
do
{
shouldRemove++;
if (lowPriorityStates.Count != 0)
shouldRemove = States.IndexOfKey(lowPriorityStates[0].Frame);
//// Find states with the fewest frames between them
//for (int i = shouldRemove + 1; i < States.Count; i++)
//{
// if (States.Keys[i] - States.Keys[i - 1] < minFrames)
// {
// minFrames = States.Keys[i] - States.Keys[i - 1];
// shouldRemove = i;
// }
//}
if (lowPriorityStates.Count > i)
shouldRemove = findState(lowPriorityStates[i]);
else
break;
// Keep marker states
markerSkips--;
if (markerSkips < 0)
shouldRemove = _movie.StartsFromSavestate ? 0 : 1;
} while (_movie.Markers.IsMarker(States.Keys[shouldRemove] + 1) && markerSkips > -1);
shouldRemove.X = -1;
i++;
} while (StateIsMarker(shouldRemove.X, shouldRemove.Y) && markerSkips > -1 || shouldRemove.X == 0);
// by last accessed
markerSkips = maxStates / 2;
if (shouldRemove.X < 1)
{
i = 0;
do
{
shouldRemove = findState(accessed[i]);
// Keep marker states
markerSkips--;
if (markerSkips < 0)
shouldRemove.X = -1;
i++;
} while (StateIsMarker(shouldRemove.X, shouldRemove.Y) && markerSkips > -1 || shouldRemove.X == 0);
}
if (shouldRemove.X < 1) // only found marker states above
{
if (BranchStates.Any())
{
var kvp = BranchStates.ElementAt(1);
shouldRemove.X = kvp.Key;
shouldRemove.Y = kvp.Value.Keys[0];
}
else
{
tsmState s = States.Values[1];
shouldRemove.X = s.Frame;
shouldRemove.Y = -1;
}
}
return shouldRemove;
}
private bool StateIsMarker(int frame, int branch)
{
if (frame == -1)
return false;
if (branch == -1)
return _movie.Markers.IsMarker(States[frame].Frame + 1);
else
{
if (_movie.GetBranch(branch).Markers == null)
return _movie.Markers.IsMarker(States[frame].Frame + 1);
else
return _movie.GetBranch(branch).Markers.Any(m => m.Frame + 1 == frame);
}
}
private bool AllLag(int from, int upTo)
{
if (upTo >= Global.Emulator.Frame)
@ -350,7 +387,7 @@ namespace BizHawk.Client.Common
internal void SetState(int frame, byte[] state)
{
MaybeRemoveState(); // Remove before adding so this state won't be removed.
MaybeRemoveStates(); // Remove before adding so this state won't be removed.
if (States.ContainsKey(frame))
{
if (stateHasDuplicate(frame, -1) != -2)
@ -379,6 +416,7 @@ namespace BizHawk.Client.Common
accessed.Remove(BranchStates[frame][branch]);
tsmState state;
bool hasDuplicate = stateHasDuplicate(frame, branch) != -2;
if (branch == -1)
{
state = States[frame];
@ -397,6 +435,9 @@ namespace BizHawk.Client.Common
Used -= (ulong)BranchStates[frame][branch].Length;
BranchStates[frame].RemoveAt(BranchStates[frame].IndexOfKey(branch));
}
if (!hasDuplicate)
lowPriorityStates.Remove(state);
}
private void StateAccessed(int frame)
{
@ -472,21 +513,14 @@ namespace BizHawk.Client.Common
{
if (States.Any())
{
KeyValuePair<int, tsmState> power = States.FirstOrDefault(s => s.Key == 0);
StateAccessed(power.Key);
if (power.Value.IsOnDisk) // TODO: Is this needed?
power = States.FirstOrDefault(s => s.Key == 0);
tsmState power = States.Values.FirstOrDefault(s => s.Frame == 0);
StateAccessed(power.Frame);
States.Clear();
accessed.Clear();
if (power.Value != null) // savestate-anchored movie?
{
SetState(0, power.Value.State);
Used = (ulong)power.Value.Length;
}
else
Used = 0;
SetState(0, power.State);
Used = (ulong)power.State.Length;
clearDiskStates();
}
@ -503,23 +537,21 @@ namespace BizHawk.Client.Common
/// </summary>
public void LimitStateCount()
{
//while (Used + DiskUsed > Settings.CapTotal)
// RemoveState(States.ElementAt(StateToRemove()).Key);
while (Used + DiskUsed > Settings.CapTotal)
{
Point s = StateToRemove();
RemoveState(s.X, s.Y);
}
//int index = -1;
//while (DiskUsed > (ulong)Settings.DiskCapacitymb * 1024uL * 1024uL)
//{
// do { index++; } while (!States[accessed[index]].IsOnDisk);
// States[
//}
//if (Used > Settings.Cap)
//{
// int lastMemState = -1;
// do { lastMemState++; } while (States[accessed[lastMemState]] == null);
// MoveStateToDisk(accessed[lastMemState]);
//}
int index = -1;
while (DiskUsed > (ulong)Settings.DiskCapacitymb * 1024uL * 1024uL)
{
do { index++; } while (!accessed[index].IsOnDisk);
accessed[index].MoveToRAM();
}
if (Used > Settings.Cap)
MaybeRemoveStates();
}
// TODO: save/load BranchStates
@ -686,21 +718,35 @@ namespace BizHawk.Client.Common
return -1;
}
if (!BranchStates.ContainsKey(frame))
return -2;
for (int i = 0; i < branches; i++)
{
if (i == branch)
continue;
if (BranchStates.ContainsKey(frame))
{
SortedList<int, tsmState> stateList = BranchStates[frame];
if (stateList != null && stateList.ContainsKey(i) && stateList[i] == stateToMatch)
return i;
}
SortedList<int, tsmState> stateList = BranchStates[frame];
if (stateList != null && stateList.ContainsKey(i) && stateList[i] == stateToMatch)
return i;
}
return -2;
}
private Point findState(tsmState s)
{
Point ret = new Point(0, -1);
ret.X = s.Frame;
if (!States.ContainsValue(s))
{
if (BranchStates.ContainsKey(s.Frame))
ret.Y = BranchStates[s.Frame].Values.IndexOf(s);
if (ret.Y == -1)
return new Point(-1, -2);
}
return ret;
}
public void AddBranch()
{

View File

@ -34,11 +34,11 @@ namespace BizHawk.Client.EmuHawk
else
MemCapacityNumeric.Maximum = 1024;
MemCapacityNumeric.Value = Settings.Capacitymb == 0 ? 1 : Settings.Capacitymb < MemCapacityNumeric.Maximum ?
MemCapacityNumeric.Value = Settings.Capacitymb < MemCapacityNumeric.Maximum ?
Settings.Capacitymb : MemCapacityNumeric.Maximum;
DiskCapacityNumeric.Value = Settings.DiskCapacitymb == 0 ? 1 : Settings.DiskCapacitymb < MemCapacityNumeric.Maximum ?
DiskCapacityNumeric.Value = Settings.DiskCapacitymb < MemCapacityNumeric.Maximum ?
Settings.DiskCapacitymb : MemCapacityNumeric.Maximum;
SaveCapacityNumeric.Value = Settings.DiskSaveCapacitymb == 0 ? 1 : Settings.DiskSaveCapacitymb < MemCapacityNumeric.Maximum ?
SaveCapacityNumeric.Value = Settings.DiskSaveCapacitymb < MemCapacityNumeric.Maximum ?
Settings.DiskSaveCapacitymb : MemCapacityNumeric.Maximum;
SavestateSizeLabel.Text = Math.Round(_stateSizeMb, 2).ToString() + " mb";