using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; namespace BizHawk.Client.Common { // TODO: what is this object really trying to accomplish? COnsider making it a collection (ICollection, IEnumerable perhaps) /// /// Represents the controller key presses of a movie /// public class MovieLog : IEnumerable { public IEnumerator GetEnumerator() { return _movieRecords.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #region Properties public byte[] InitState { get; private set; } public int StateCount { get { return _state_records.Count; } } public int Length { get { return _movieRecords.Count; } } public int StateFirstIndex { get { return (_state_records.Count == 0) ? -1 : _state_records[0].Index; } } public int StateLastIndex { get { return (_state_records.Count == 0) ? -1 : _state_records[_state_records.Count - 1].Index; } } public int StateSizeInBytes { get { return _state_records.Any() ? StateCount * _state_records[0].State.Length : 0; } } #endregion #region Public Methods public void Clear() { _movieRecords.Clear(); _state_records.Clear(); } public void ClearStates() { _state_records.Clear(); } public void AppendFrame(string frame) { _movieRecords.Add(frame); } public void AddState(byte[] state) { if (Global.Emulator.Frame == 0) { InitState = state; } if (Global.Emulator.Frame < StateFirstIndex) { _state_records.Clear(); _state_records.Add(new StateRecord(Global.Emulator.Frame, state)); } if (Global.Emulator.Frame > StateLastIndex) { if (StateSizeInBytes + state.Length > MAXSTATERECORDSIZE) { // Discard the oldest state to save space. _state_records.RemoveAt(0); } _state_records.Add(new StateRecord(Global.Emulator.Frame,state)); } } public void SetFrameAt(int frameNum, string frame) { if (frameNum < StateLastIndex && (frameNum < StateFirstIndex || frame != _movieRecords[frameNum])) { TruncateStates(frameNum + 1); } if (_movieRecords.Count > frameNum) { _movieRecords[frameNum] = frame; } else { _movieRecords.Add(frame); } } public void AddFrameAt(int frame, string record) { _movieRecords.Insert(frame, record); if (frame <= StateLastIndex) { if (frame <= StateFirstIndex) { _state_records.Clear(); } else { _state_records.RemoveRange(frame - StateFirstIndex, StateLastIndex - frame + 1); } } } public byte[] GetState(int frame) { return _state_records[frame - StateFirstIndex].State; } public void DeleteFrame(int frame) { _movieRecords.RemoveAt(frame); if (frame <= StateLastIndex) { if (frame <= StateFirstIndex) { _state_records.Clear(); } else { _state_records.RemoveRange(frame - StateFirstIndex, StateLastIndex - frame + 1); } } } public void TruncateStates(int frame) { if (frame >= 0) { if (frame < StateFirstIndex) { _state_records.Clear(); } else if (frame <= StateLastIndex) { _state_records.RemoveRange(frame - StateFirstIndex, StateLastIndex - frame + 1); } } } public string this[int frame] { get { return _movieRecords[frame]; } } public void TruncateMovie(int frame) { if (frame < _movieRecords.Count) { _movieRecords.RemoveRange(frame, _movieRecords.Count - frame); TruncateStates(frame); } } public bool FrameLagged(int frame) { if (frame >= StateFirstIndex && frame <= StateLastIndex && frame <= _state_records.Count) { if (frame < _state_records.Count) { return _state_records[frame].Lagged; } else { return false; } } else { return false; } } #endregion #region private fields private sealed class StateRecord { public StateRecord(int index, byte[] state) { Index = index; State = state; Lagged = Global.Emulator.IsLagFrame; } public int Index { get; private set; } public byte[] State { get; private set; } public bool Lagged { get; private set; } } private readonly List _movieRecords = new List(); private readonly List _state_records = new List(); // TODO: Make this size limit configurable by the user private const int MAXSTATERECORDSIZE = 512 * 1024 * 1024; //To limit memory usage. #endregion } }