1. Fixed tastudio memory leak. This was accomplished by dropping the oldest saved stats after hitting a size limit (1 GB).

2. Changed StopOnEnd to StopOnFrame. This expands the functionality so that you can tell the emulator to run and then stop at a predetermined point.
3. Expanded the functionality of RewindToFrame to handle more cases. Now you can go back or even forward to a frame and it handles the execution and greenzone appropriately.
4. Due to the change in structure some code was changed to check the index of the first and last saved states in the greenzone rather than relying on the size of the saved state list.
5. Changed the list of saved states in the movie log from a list of byte[] to a list of structures (the structure has an int for the index and byte[] for the state).
6. Saved an init state in the movie log. This is used to go back to the beginning if the beginning of the movie is no longer in the list of saved states.
7. Expanded the AddState and SetFrameAt logic in the movie log to account for the fact that the size of the saved state list is now capped.
8. Fixed a bug in the log interpretation for SMS.
9. Fixed a bug in the sms virtual controller, buttons 1 and 2 were hooked to the wrong objects.
10. Fixed the tastudio listview to show lag as pink.
This commit is contained in:
phillip.grimsrud 2012-06-18 01:36:38 +00:00
parent 4435b58c0b
commit a6ced95e07
6 changed files with 173 additions and 77 deletions

View File

@ -32,7 +32,8 @@ namespace BizHawk.MultiClient
public bool PressRewind = false; public bool PressRewind = false;
public bool FastForward = false; public bool FastForward = false;
public bool TurboFastForward = false; public bool TurboFastForward = false;
public bool StopOnEnd = true; public int StopOnFrame = -1;
public bool RestoreReadWriteOnStop = false;
public bool UpdateFrame = false; public bool UpdateFrame = false;
//avi/wav state //avi/wav state
@ -1892,16 +1893,22 @@ namespace BizHawk.MultiClient
session.LatchInputFromPlayer(Global.MovieInputSourceAdapter); session.LatchInputFromPlayer(Global.MovieInputSourceAdapter);
} }
if (Global.MovieSession.Movie.Mode == MOVIEMODE.PLAY) if (-1 != StopOnFrame && StopOnFrame == Global.Emulator.Frame + 1)
{ {
if (Global.MovieSession.Movie.LogLength() == Global.Emulator.Frame + 1 && true == StopOnEnd) if(StopOnFrame == Global.MovieSession.Movie.LogLength())
{ {
if (true == Global.MovieSession.Movie.TastudioOn)
{
StopOnEnd = false;
}
Global.MovieSession.Movie.SetMovieFinished(); Global.MovieSession.Movie.SetMovieFinished();
} }
if (true == Global.MovieSession.Movie.TastudioOn)
{
PauseEmulator();
StopOnFrame = -1;
}
if(true == RestoreReadWriteOnStop)
{
Global.MovieSession.Movie.Mode = MOVIEMODE.RECORD;
RestoreReadWriteOnStop = false;
}
} }
if (Global.MovieSession.Movie.Mode == MOVIEMODE.FINISHED) if (Global.MovieSession.Movie.Mode == MOVIEMODE.FINISHED)
{ {
@ -1998,7 +2005,6 @@ namespace BizHawk.MultiClient
{ {
//The other tool updates are earlier, TAStudio needs to be later so it can display the latest //The other tool updates are earlier, TAStudio needs to be later so it can display the latest
//frame of execution in its list view. //frame of execution in its list view.
Global.MovieSession.Movie.CheckValidity();
TAStudio1.UpdateValues(); TAStudio1.UpdateValues();
} }

View File

@ -80,14 +80,6 @@ namespace BizHawk.MultiClient
return Frames; return Frames;
} }
public int StateLength()
{
if (Loaded)
return Log.StateLength();
else
return Frames;
}
public void UpdateFileName(string filename) public void UpdateFileName(string filename)
{ {
this.Filename = filename; this.Filename = filename;
@ -118,27 +110,71 @@ namespace BizHawk.MultiClient
{ {
if (frame <= Global.Emulator.Frame) if (frame <= Global.Emulator.Frame)
{ {
//frame-1 because we need to go back an extra frame and then run a frame, otherwise the display doesn't get updated. if (frame <= Log.StateFirstIndex())
Global.Emulator.LoadStateBinary(new BinaryReader(new MemoryStream(Log.GetState(frame - 1)))); {
Global.MainForm.UpdateFrame = true; //Global.MainForm.LoadRom(Global.MainForm.CurrentlyOpenRom,false);
Global.Emulator.LoadStateBinary(new BinaryReader(new MemoryStream(Log.GetInitState())));
Global.MainForm.TAStudio1.UpdateValues();
if (true == Global.MainForm.EmulatorPaused && 0 != frame)
{
Global.MainForm.StopOnFrame = frame;
Global.MainForm.UnpauseEmulator();
}
if (MOVIEMODE.RECORD == Mode)
{
Mode = MOVIEMODE.PLAY;
Global.MainForm.RestoreReadWriteOnStop = true;
}
}
else
{
if (0 == frame)
{
//Global.MainForm.LoadRom(Global.MainForm.CurrentlyOpenRom, false);
Global.Emulator.LoadStateBinary(new BinaryReader(new MemoryStream(Log.GetInitState())));
//Global.MainForm.StopOnFrame = frame;
Global.MainForm.TAStudio1.UpdateValues();
}
else
{
//frame-1 because we need to go back an extra frame and then run a frame, otherwise the display doesn't get updated.
Global.Emulator.LoadStateBinary(new BinaryReader(new MemoryStream(Log.GetState(frame - 1))));
Global.MainForm.UpdateFrame = true;
}
}
}
else
{
Global.MainForm.StopOnFrame = frame;
Global.MainForm.UnpauseEmulator();
} }
} }
public void DeleteFrame(int frame) public void DeleteFrame(int frame)
{ {
RewindToFrame(frame); if (frame <= StateLastIndex())
{
if (frame <= StateFirstIndex())
{
RewindToFrame(0);
}
else
{
RewindToFrame(frame);
}
}
Log.DeleteFrame(frame); Log.DeleteFrame(frame);
Global.MainForm.TAStudio1.UpdateValues(); Global.MainForm.TAStudio1.UpdateValues();
} }
public int ValidStateCount() public int StateFirstIndex()
{ {
return Log.ValidStateCount(); return Log.StateFirstIndex();
} }
public void CheckValidity() public int StateLastIndex()
{ {
Log.CheckValidity(); return Log.StateLastIndex();
} }
public void ClearSaveRAM() public void ClearSaveRAM()
@ -186,6 +222,7 @@ namespace BizHawk.MultiClient
{ {
ClearSaveRAM(); ClearSaveRAM();
Mode = MOVIEMODE.PLAY; Mode = MOVIEMODE.PLAY;
Global.MainForm.StopOnFrame = LogLength();
} }
public void ResumeRecording() public void ResumeRecording()
@ -207,6 +244,7 @@ namespace BizHawk.MultiClient
MnemonicsGenerator mg = new MnemonicsGenerator(); MnemonicsGenerator mg = new MnemonicsGenerator();
mg.SetSource(source); mg.SetSource(source);
Log.SetFrameAt(frameNum, mg.GetControllersAsMnemonic()); Log.SetFrameAt(frameNum, mg.GetControllersAsMnemonic());
} }

View File

@ -13,9 +13,23 @@ namespace BizHawk.MultiClient
{ {
//TODO: Insert(int frame) not useful for convenctional tasing but TAStudio will want it //TODO: Insert(int frame) not useful for convenctional tasing but TAStudio will want it
List<string> MovieRecords = new List<string>(); private struct StateRecordStruct
{
public StateRecordStruct(int index, byte[] state)
{
this.index = index;
this.state = state;
}
private List<byte[]> StateRecords = new List<byte[]>(); public int index;
public byte[] state;
}
private List<string> MovieRecords = new List<string>();
private List<StateRecordStruct> StateRecords = new List<StateRecordStruct>();
private byte[] InitState;
//TODO: Make this size limit configurable by the user
private int MaxStateRecordSize = 1024 * 1024 * 1024; //To limit memory usage.
public MovieLog() public MovieLog()
{ {
@ -26,11 +40,26 @@ namespace BizHawk.MultiClient
return MovieRecords.Count; return MovieRecords.Count;
} }
public int StateLength() public int StateFirstIndex()
{
return (0 == StateRecords.Count) ? -1 : StateRecords[0].index;
}
public int StateLastIndex()
{
return (0 == StateRecords.Count) ? -1 : StateRecords[StateRecords.Count-1].index;
}
public int StateSizeInFrames()
{ {
return StateRecords.Count; return StateRecords.Count;
} }
public int StateSizeInBytes()
{
return (0 == StateRecords.Count) ? 0 : StateRecords.Count * StateRecords[0].state.Length;
}
public void Clear() public void Clear()
{ {
MovieRecords.Clear(); MovieRecords.Clear();
@ -44,14 +73,33 @@ namespace BizHawk.MultiClient
public void AddState(byte[] state) public void AddState(byte[] state)
{ {
if (Global.Emulator.Frame >= StateRecords.Count) if (0 == Global.Emulator.Frame)
{ {
StateRecords.Add(state); InitState = state;
}
if (Global.Emulator.Frame < StateFirstIndex())
{
StateRecords.Clear();
StateRecords.Add(new StateRecordStruct(Global.Emulator.Frame, state));
}
if (Global.Emulator.Frame > StateLastIndex())
{
if (StateSizeInBytes() + state.Length > MaxStateRecordSize)
{
// Discard the oldest state to save space.
StateRecords.RemoveAt(0);
}
StateRecords.Add(new StateRecordStruct(Global.Emulator.Frame,state));
} }
} }
public void SetFrameAt(int frameNum, string frame) public void SetFrameAt(int frameNum, string frame)
{ {
if (frameNum < StateLastIndex() && (frameNum < StateFirstIndex() || frame != GetFrame(frameNum)))
{
TruncateStates(frameNum+1);
}
if (MovieRecords.Count > frameNum) if (MovieRecords.Count > frameNum)
MovieRecords[frameNum] = frame; MovieRecords[frameNum] = frame;
else else
@ -61,42 +109,44 @@ namespace BizHawk.MultiClient
{ {
MovieRecords.Insert(frameNum, frame); MovieRecords.Insert(frameNum, frame);
if (frameNum <= StateRecords.Count - 1) if (frameNum <= StateLastIndex())
{ {
StateRecords.RemoveRange(frameNum, StateRecords.Count - frameNum); if (frameNum <= StateFirstIndex())
{
StateRecords.Clear();
Global.MovieSession.Movie.RewindToFrame(0);
}
else
{
StateRecords.RemoveRange(frameNum - StateFirstIndex(), StateLastIndex() - frameNum + 1);
Global.MovieSession.Movie.RewindToFrame(frameNum);
}
} }
} }
public void CheckValidity()
{
byte[] state = Global.Emulator.SaveStateBinary();
if (Global.Emulator.Frame < StateRecords.Count && !state.SequenceEqual((byte[])StateRecords[Global.Emulator.Frame]))
{
TruncateStates(Global.Emulator.Frame);
}
}
public int CapturedStateCount()
{
return StateRecords.Count;
}
public int ValidStateCount()
{
return StateRecords.Count;
}
public byte[] GetState(int frame) public byte[] GetState(int frame)
{ {
return StateRecords[frame]; return StateRecords[frame-StateFirstIndex()].state;
}
public byte[] GetInitState()
{
return InitState;
} }
public void DeleteFrame(int frame) public void DeleteFrame(int frame)
{ {
MovieRecords.RemoveAt(frame); MovieRecords.RemoveAt(frame);
if (frame < StateRecords.Count) if (frame <= StateLastIndex())
{ {
StateRecords.RemoveAt(frame); if (frame <= StateFirstIndex())
{
StateRecords.Clear();
}
else
{
StateRecords.RemoveRange(frame - StateFirstIndex(), StateLastIndex() - frame + 1);
}
} }
} }
@ -105,19 +155,18 @@ namespace BizHawk.MultiClient
StateRecords.Clear(); StateRecords.Clear();
} }
public void TruncateFrames(int frame)
{
if (frame >= 0 && frame < MovieLength())
{
MovieRecords.RemoveRange(frame, MovieLength() - frame);
}
}
public void TruncateStates(int frame) public void TruncateStates(int frame)
{ {
if (frame >= 0 && frame < StateLength()) if (frame >= 0)
{ {
StateRecords.RemoveRange(frame, StateLength() - frame); if (frame < StateFirstIndex())
{
StateRecords.Clear();
}
else if (frame <= StateLastIndex())
{
StateRecords.RemoveRange(frame - StateFirstIndex(), StateLastIndex() - frame+1);
}
} }
} }

View File

@ -22,7 +22,7 @@
Global.MovieSession.Movie.TastudioOn = false; Global.MovieSession.Movie.TastudioOn = false;
Global.MovieSession.Movie.ClearStates(); Global.MovieSession.Movie.ClearStates();
Global.MainForm.StopOnEnd = true; Global.MainForm.StopOnFrame = Global.MovieSession.Movie.LogLength();
base.Dispose(disposing); base.Dispose(disposing);
} }

View File

@ -70,9 +70,9 @@ namespace BizHawk.MultiClient
case "SMS": case "SMS":
case "GG": case "GG":
case "SG": case "SG":
Pads[0].SetButtons(str.Substring(0, 6)); Pads[0].SetButtons(str.Substring(1, 6));
Pads[1].SetButtons(str.Substring(7, 6)); Pads[1].SetButtons(str.Substring(8, 6));
Pads[2].SetButtons(str.Substring(14, 2)); Pads[2].SetButtons(str.Substring(15, 2));
break; break;
case "PCE": case "PCE":
case "SGX": case "SGX":
@ -104,9 +104,13 @@ namespace BizHawk.MultiClient
private void TASView_QueryItemBkColor(int index, int column, ref Color color) private void TASView_QueryItemBkColor(int index, int column, ref Color color)
{ {
if (index < Global.MovieSession.Movie.ValidStateCount()) if (0 == index && 0 == Global.MovieSession.Movie.StateFirstIndex())
color = Color.LightGreen; //special case for frame 0. Normally we need to go back an extra frame, but for frame 0 we can reload the rom.
if (index > Global.MovieSession.Movie.StateFirstIndex() && index <= Global.MovieSession.Movie.StateLastIndex())
color = Color.LightGreen; color = Color.LightGreen;
else if ("" != Global.MovieSession.Movie.GetInputFrame(index) && Global.MovieSession.Movie.GetInputFrame(index)[1] == 'L') if ("" != Global.MovieSession.Movie.GetInputFrame(index) &&
Global.COMMANDS[Global.MovieInputSourceAdapter.Type.Name].ContainsKey("Lag") &&
Global.MovieSession.Movie.GetInputFrame(index)[1] == Global.COMMANDS[Global.MovieInputSourceAdapter.Type.Name]["Lag"][0])
color = Color.Pink; color = Color.Pink;
if (index == Global.Emulator.Frame) if (index == Global.Emulator.Frame)
{ {
@ -131,7 +135,7 @@ namespace BizHawk.MultiClient
private void DisplayList() private void DisplayList()
{ {
TASView.ItemCount = Global.MovieSession.Movie.LogLength(); TASView.ItemCount = Global.MovieSession.Movie.LogLength();
if (Global.MovieSession.Movie.LogLength() == Global.Emulator.Frame && Global.MovieSession.Movie.StateLength() == Global.Emulator.Frame) if (Global.MovieSession.Movie.LogLength() == Global.Emulator.Frame && Global.MovieSession.Movie.StateLastIndex() == Global.Emulator.Frame - 1)
{ {
//If we're at the end of the movie add one to show the cursor as a blank frame //If we're at the end of the movie add one to show the cursor as a blank frame
TASView.ItemCount++; TASView.ItemCount++;
@ -158,7 +162,7 @@ namespace BizHawk.MultiClient
Global.MovieSession.Movie.TastudioOn = true; Global.MovieSession.Movie.TastudioOn = true;
Global.MainForm.StopOnEnd = false; Global.MainForm.StopOnFrame = -1;
LoadConfigSettings(); LoadConfigSettings();
ReadOnlyCheckBox.Checked = Global.MainForm.ReadOnly; ReadOnlyCheckBox.Checked = Global.MainForm.ReadOnly;
@ -367,11 +371,11 @@ namespace BizHawk.MultiClient
{ {
if (true == this.FastFowardToEnd.Checked) if (true == this.FastFowardToEnd.Checked)
{ {
Global.MainForm.StopOnEnd = false; Global.MainForm.StopOnFrame = -1;
} }
else else
{ {
Global.MainForm.StopOnEnd = true; Global.MainForm.StopOnFrame = Global.MovieSession.Movie.LogLength();
} }
this.FastFowardToEnd.Checked ^= true; this.FastFowardToEnd.Checked ^= true;
@ -490,7 +494,6 @@ namespace BizHawk.MultiClient
{ {
Global.MovieSession.Movie.InsertFrame(Global.MovieSession.Movie.GetInputFrame(list[index]), (int)list[index]); Global.MovieSession.Movie.InsertFrame(Global.MovieSession.Movie.GetInputFrame(list[index]), (int)list[index]);
} }
Global.MovieSession.Movie.RewindToFrame(TASView.selectedItem);
} }
private void Delete_Click(object sender, EventArgs e) private void Delete_Click(object sender, EventArgs e)
@ -498,7 +501,7 @@ namespace BizHawk.MultiClient
ListView.SelectedIndexCollection list = TASView.SelectedIndices; ListView.SelectedIndexCollection list = TASView.SelectedIndices;
for (int index = 0; index < list.Count; index++) for (int index = 0; index < list.Count; index++)
{ {
Global.MovieSession.Movie.DeleteFrame(TASView.selectedItem); Global.MovieSession.Movie.DeleteFrame(list[index]);
} }
} }
} }

View File

@ -168,9 +168,9 @@ namespace BizHawk.MultiClient
else if (sender == PR) else if (sender == PR)
Global.StickyXORAdapter.SetSticky(Controller + " Right", PR.Checked); Global.StickyXORAdapter.SetSticky(Controller + " Right", PR.Checked);
else if (sender == B1) else if (sender == B1)
Global.StickyXORAdapter.SetSticky(Controller + " B1", B3.Checked); Global.StickyXORAdapter.SetSticky(Controller + " B1", B1.Checked);
else if (sender == B2) else if (sender == B2)
Global.StickyXORAdapter.SetSticky(Controller + " B2", B4.Checked); Global.StickyXORAdapter.SetSticky(Controller + " B2", B2.Checked);
} }
public override void Clear() public override void Clear()