Movies - refactor & cleanup the MovieLog class

This commit is contained in:
adelikat 2012-09-03 20:55:05 +00:00
parent 6142e2a8f1
commit ac91ed67a6
2 changed files with 130 additions and 105 deletions

View File

@ -94,7 +94,7 @@ namespace BizHawk.MultiClient
{ {
if (Loaded) if (Loaded)
{ {
return Log.MovieLength(); return Log.Length;
} }
else else
{ {
@ -127,7 +127,7 @@ namespace BizHawk.MultiClient
{ {
get get
{ {
return Log.StateFirstIndex(); return Log.StateFirstIndex;
} }
} }
@ -135,7 +135,7 @@ namespace BizHawk.MultiClient
{ {
get get
{ {
return Log.StateLastIndex(); return Log.StateLastIndex;
} }
} }
@ -147,8 +147,12 @@ namespace BizHawk.MultiClient
} }
set set
{ {
Log.ClearStates();
statecapturing = value; statecapturing = value;
if (value == false)
{
Log.ClearStates();
}
} }
} }
@ -224,7 +228,7 @@ namespace BizHawk.MultiClient
{ {
Global.MainForm.ClearSaveRAM(); Global.MainForm.ClearSaveRAM();
Mode = MOVIEMODE.RECORD; Mode = MOVIEMODE.RECORD;
if (Global.Config.EnableBackupMovies && MakeBackup && Log.MovieLength() > 0) if (Global.Config.EnableBackupMovies && MakeBackup && Log.Length > 0)
{ {
WriteBackup(); WriteBackup();
MakeBackup = false; MakeBackup = false;
@ -375,7 +379,7 @@ namespace BizHawk.MultiClient
public string GetInput(int frame) public string GetInput(int frame)
{ {
lastlog = frame; lastlog = frame;
if (frame < Log.MovieLength()) if (frame < Log.Length)
{ {
return Log.GetFrame(frame); return Log.GetFrame(frame);
} }
@ -398,18 +402,18 @@ namespace BizHawk.MultiClient
public void AppendFrame(string record) public void AppendFrame(string record)
{ {
Log.AddFrame(record); Log.AppendFrame(record);
} }
public void InsertFrame(string record, int frame) public void InsertFrame(string record, int frame)
{ {
Log.AddFrameAt(record, frame); Log.AddFrameAt(frame, record);
} }
public void InsertBlankFrame(int frame) public void InsertBlankFrame(int frame)
{ {
MnemonicsGenerator mg = new MnemonicsGenerator(); MnemonicsGenerator mg = new MnemonicsGenerator();
Log.AddFrameAt(mg.GetEmptyMnemonic(), frame); Log.AddFrameAt(frame, mg.GetEmptyMnemonic());
} }
public void DeleteFrame(int frame) public void DeleteFrame(int frame)
@ -454,9 +458,9 @@ namespace BizHawk.MultiClient
} }
if (frame <= Global.Emulator.Frame) if (frame <= Global.Emulator.Frame)
{ {
if (frame <= Log.StateFirstIndex()) if (frame <= Log.StateFirstIndex)
{ {
Global.Emulator.LoadStateBinary(new BinaryReader(new MemoryStream(Log.GetInitState()))); Global.Emulator.LoadStateBinary(new BinaryReader(new MemoryStream(Log.InitState)));
if (Global.MainForm.EmulatorPaused == true && frame > 0) if (Global.MainForm.EmulatorPaused == true && frame > 0)
{ {
Global.MainForm.UnpauseEmulator(); Global.MainForm.UnpauseEmulator();
@ -471,7 +475,7 @@ namespace BizHawk.MultiClient
{ {
if (frame == 0) if (frame == 0)
{ {
Global.Emulator.LoadStateBinary(new BinaryReader(new MemoryStream(Log.GetInitState()))); Global.Emulator.LoadStateBinary(new BinaryReader(new MemoryStream(Log.InitState)));
} }
else else
{ {
@ -511,7 +515,7 @@ namespace BizHawk.MultiClient
writer.WriteLine("[Input]"); writer.WriteLine("[Input]");
string s = MovieHeader.GUID + " " + Header.GetHeaderLine(MovieHeader.GUID); string s = MovieHeader.GUID + " " + Header.GetHeaderLine(MovieHeader.GUID);
writer.WriteLine(s); writer.WriteLine(s);
for (int x = 0; x < Log.MovieLength(); x++) for (int x = 0; x < Log.Length; x++)
{ {
writer.WriteLine(Log.GetFrame(x)); writer.WriteLine(Log.GetFrame(x));
} }
@ -525,7 +529,7 @@ namespace BizHawk.MultiClient
//We are in record mode so replace the movie log with the one from the savestate //We are in record mode so replace the movie log with the one from the savestate
if (!Global.MovieSession.MultiTrack.IsActive) if (!Global.MovieSession.MultiTrack.IsActive)
{ {
if (Global.Config.EnableBackupMovies && MakeBackup && Log.MovieLength() > 0) if (Global.Config.EnableBackupMovies && MakeBackup && Log.Length > 0)
{ {
WriteBackup(); WriteBackup();
MakeBackup = false; MakeBackup = false;
@ -562,7 +566,7 @@ namespace BizHawk.MultiClient
} }
if (line[0] == '|') if (line[0] == '|')
{ {
Log.AddFrame(line); Log.AppendFrame(line);
} }
} }
} }
@ -601,7 +605,7 @@ namespace BizHawk.MultiClient
} }
} }
} }
if (stateFrame > 0 && stateFrame < Log.MovieLength()) if (stateFrame > 0 && stateFrame < Log.Length)
{ {
Log.TruncateStates(stateFrame); Log.TruncateStates(stateFrame);
Log.TruncateMovie(stateFrame); Log.TruncateMovie(stateFrame);
@ -621,7 +625,7 @@ namespace BizHawk.MultiClient
} }
else else
{ {
seconds = GetSeconds(Log.MovieLength()); seconds = GetSeconds(Log.Length);
} }
int hours = ((int)seconds) / 3600; int hours = ((int)seconds) / 3600;
@ -696,7 +700,7 @@ namespace BizHawk.MultiClient
else if (line == "[Input]") continue; else if (line == "[Input]") continue;
else if (line == "[/Input]") break; else if (line == "[/Input]") break;
else if (line[0] == '|') else if (line[0] == '|')
l.AddFrame(line); l.AppendFrame(line);
} }
reader.BaseStream.Position = 0; //Reset position because this stream may be read again by other code reader.BaseStream.Position = 0; //Reset position because this stream may be read again by other code
@ -707,7 +711,7 @@ namespace BizHawk.MultiClient
return true; return true;
} }
if (stateFrame > l.MovieLength()) //stateFrame is greater than state input log, so movie finished mode if (stateFrame > l.Length) //stateFrame is greater than state input log, so movie finished mode
{ {
if (Mode == MOVIEMODE.PLAY || Mode == MOVIEMODE.FINISHED) if (Mode == MOVIEMODE.PLAY || Mode == MOVIEMODE.FINISHED)
{ {
@ -724,13 +728,13 @@ namespace BizHawk.MultiClient
if (stateFrame == 0) if (stateFrame == 0)
{ {
stateFrame = l.MovieLength(); //In case the frame count failed to parse, revert to using the entire state input log stateFrame = l.Length; //In case the frame count failed to parse, revert to using the entire state input log
} }
if (Log.MovieLength() < stateFrame) if (Log.Length < stateFrame)
{ {
//Future event error //Future event error
MessageBox.Show("The savestate is from frame " + l.MovieLength().ToString() + " which is greater than the current movie length of " + MessageBox.Show("The savestate is from frame " + l.Length.ToString() + " which is greater than the current movie length of " +
Log.MovieLength().ToString() + ".\nCan not load this savestate.", "Future event Error", MessageBoxButtons.OK, MessageBoxIcon.Error); Log.Length.ToString() + ".\nCan not load this savestate.", "Future event Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
reader.Close(); reader.Close();
return false; return false;
} }
@ -770,8 +774,9 @@ namespace BizHawk.MultiClient
private void WriteText(string file) private void WriteText(string file)
{ {
if (file.Length == 0) return; //Nothing to write if (file.Length > 0)
int length = Log.MovieLength(); {
int length = Log.Length;
using (StreamWriter sw = new StreamWriter(file)) using (StreamWriter sw = new StreamWriter(file))
{ {
@ -780,6 +785,7 @@ namespace BizHawk.MultiClient
Log.WriteText(sw); Log.WriteText(sw);
} }
} }
}
private void WriteBinary(string file) private void WriteBinary(string file)
{ {
@ -841,7 +847,7 @@ namespace BizHawk.MultiClient
} }
else if (str[0] == '|') else if (str[0] == '|')
{ {
Log.AddFrame(str); Log.AppendFrame(str);
} }
else else
{ {

View File

@ -11,81 +11,84 @@ namespace BizHawk.MultiClient
/// </summary> /// </summary>
public class MovieLog public class MovieLog
{ {
//TODO: Insert(int frame) not useful for convenctional tasing but TAStudio will want it #region Properties
private struct StateRecordStruct public byte[] InitState { get; private set; }
public int StateCount
{ {
public StateRecordStruct(int index, byte[] state) get
{
this.index = index;
this.state = state;
}
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 int StateCount { get { return StateRecords.Count; } }
public MovieLog()
{
}
public int MovieLength()
{
return MovieRecords.Count;
}
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 int Length
{
get
{
return MovieRecords.Count;
}
}
public int StateFirstIndex
{
get
{
return (StateRecords.Count == 0) ? -1 : StateRecords[0].Index;
}
}
public int StateLastIndex
{
get
{
return (StateRecords.Count == 0) ? -1 : StateRecords[StateRecords.Count - 1].Index;
}
}
public int StateSizeInBytes
{
get
{
return StateRecords.Count * StateRecords[0].State.Length;
}
}
#endregion
#region Public Methods
public void Clear() public void Clear()
{ {
MovieRecords.Clear(); MovieRecords.Clear();
StateRecords.Clear(); StateRecords.Clear();
} }
public void AddFrame(string frame) public void ClearStates()
{
StateRecords.Clear();
}
public void AppendFrame(string frame)
{ {
MovieRecords.Add(frame); MovieRecords.Add(frame);
} }
public void AddState(byte[] state) public void AddState(byte[] state)
{ {
if (0 == Global.Emulator.Frame) if (Global.Emulator.Frame == 0)
{ {
InitState = state; InitState = state;
} }
if (Global.Emulator.Frame < StateFirstIndex()) if (Global.Emulator.Frame < StateFirstIndex)
{ {
StateRecords.Clear(); StateRecords.Clear();
StateRecords.Add(new StateRecordStruct(Global.Emulator.Frame, state)); StateRecords.Add(new StateRecordStruct(Global.Emulator.Frame, state));
} }
if (Global.Emulator.Frame > StateLastIndex()) if (Global.Emulator.Frame > StateLastIndex)
{ {
if (StateSizeInBytes() + state.Length > MaxStateRecordSize) if (StateSizeInBytes + state.Length > MaxStateRecordSize)
{ {
// Discard the oldest state to save space. // Discard the oldest state to save space.
StateRecords.RemoveAt(0); StateRecords.RemoveAt(0);
@ -96,100 +99,93 @@ namespace BizHawk.MultiClient
public void SetFrameAt(int frameNum, string frame) public void SetFrameAt(int frameNum, string frame)
{ {
if (frameNum < StateLastIndex() && (frameNum < StateFirstIndex() || frame != GetFrame(frameNum))) if (frameNum < StateLastIndex && (frameNum < StateFirstIndex || frame != GetFrame(frameNum)))
{ {
TruncateStates(frameNum+1); TruncateStates(frameNum+1);
} }
if (MovieRecords.Count > frameNum) if (MovieRecords.Count > frameNum)
{
MovieRecords[frameNum] = frame; MovieRecords[frameNum] = frame;
}
else else
{
MovieRecords.Add(frame); MovieRecords.Add(frame);
} }
public void AddFrameAt(string frame, int frameNum) }
{
MovieRecords.Insert(frameNum, frame);
if (frameNum <= StateLastIndex()) public void AddFrameAt(int frame, string record)
{ {
if (frameNum <= StateFirstIndex()) MovieRecords.Insert(frame, record);
if (frame <= StateLastIndex)
{
if (frame <= StateFirstIndex)
{ {
StateRecords.Clear(); StateRecords.Clear();
Global.MovieSession.Movie.RewindToFrame(0); Global.MovieSession.Movie.RewindToFrame(0);
} }
else else
{ {
StateRecords.RemoveRange(frameNum - StateFirstIndex(), StateLastIndex() - frameNum + 1); StateRecords.RemoveRange(frame - StateFirstIndex, StateLastIndex - frame + 1);
Global.MovieSession.Movie.RewindToFrame(frameNum); Global.MovieSession.Movie.RewindToFrame(frame);
} }
} }
} }
public byte[] GetState(int frame) public byte[] GetState(int frame)
{ {
return StateRecords[frame-StateFirstIndex()].state; 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 <= StateLastIndex()) if (frame <= StateLastIndex)
{ {
if (frame <= StateFirstIndex()) if (frame <= StateFirstIndex)
{ {
StateRecords.Clear(); StateRecords.Clear();
} }
else else
{ {
StateRecords.RemoveRange(frame - StateFirstIndex(), StateLastIndex() - frame + 1); StateRecords.RemoveRange(frame - StateFirstIndex, StateLastIndex - frame + 1);
} }
} }
} }
public void ClearStates()
{
StateRecords.Clear();
}
public void TruncateStates(int frame) public void TruncateStates(int frame)
{ {
if (frame >= 0) if (frame >= 0)
{ {
if (frame < StateFirstIndex()) if (frame < StateFirstIndex)
{ {
StateRecords.Clear(); StateRecords.Clear();
} }
else if (frame <= StateLastIndex()) else if (frame <= StateLastIndex)
{ {
StateRecords.RemoveRange(frame - StateFirstIndex(), StateLastIndex() - frame + 1); StateRecords.RemoveRange(frame - StateFirstIndex, StateLastIndex - frame + 1);
} }
} }
} }
public string GetFrame(int frameCount) //Frame count is 0 based here, should it be? public string GetFrame(int frameCount)
{ {
if (frameCount >= 0) if (frameCount >= 0 && frameCount < MovieRecords.Count)
{ {
if (frameCount < MovieRecords.Count)
return MovieRecords[frameCount]; return MovieRecords[frameCount];
else
return "";
} }
else else
{
return ""; //TODO: throw an exception? return ""; //TODO: throw an exception?
} }
}
public void WriteText(StreamWriter sw) public void WriteText(StreamWriter sw)
{ {
int length = MovieLength(); for (int i = 0; i < MovieRecords.Count; i++)
for (int x = 0; x < length; x++)
{ {
sw.WriteLine(GetFrame(x)); sw.WriteLine(GetFrame(i));
} }
} }
@ -202,5 +198,28 @@ namespace BizHawk.MultiClient
} }
} }
#endregion
#region private fields
private class StateRecordStruct
{
public StateRecordStruct(int index, byte[] state)
{
this.Index = index;
this.State = state;
}
public int Index;
public byte[] State;
}
private List<string> MovieRecords = new List<string>();
private List<StateRecordStruct> StateRecords = new List<StateRecordStruct>();
//TODO: Make this size limit configurable by the user
private int MaxStateRecordSize = 1024 * 1024 * 1024; //To limit memory usage.
#endregion
} }
} }