258 lines
4.9 KiB
C#
258 lines
4.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
namespace BizHawk.Client.Common
|
|
{
|
|
public class TasMovie : IMovie
|
|
{
|
|
// TODO: preloading, or benchmark and see how much of a performaance gain it really is
|
|
// TODO: support loop Offset
|
|
#region Implementation
|
|
|
|
public TasMovie(string filename, bool startsFromSavestate = false)
|
|
: this(startsFromSavestate)
|
|
{
|
|
Filename = filename;
|
|
}
|
|
|
|
public TasMovie(bool startsFromSavestate = false)
|
|
{
|
|
Filename = String.Empty;
|
|
Header = new MovieHeader();
|
|
Header.StartsFromSavestate = startsFromSavestate;
|
|
_records = new MovieRecordList();
|
|
_mode = Moviemode.Inactive;
|
|
IsCountingRerecords = true;
|
|
}
|
|
|
|
public string Filename { get; set; }
|
|
|
|
public IMovieHeader Header { get; private set; }
|
|
|
|
public bool IsActive
|
|
{
|
|
get { return _mode != Moviemode.Inactive; }
|
|
}
|
|
|
|
public bool IsPlaying
|
|
{
|
|
get { return _mode == Moviemode.Play || _mode == Moviemode.Finished; }
|
|
}
|
|
|
|
public bool IsRecording
|
|
{
|
|
get { return _mode == Moviemode.Record; }
|
|
}
|
|
|
|
public bool IsFinished
|
|
{
|
|
get { return _mode == Moviemode.Finished; }
|
|
}
|
|
|
|
public bool IsCountingRerecords { get; set; }
|
|
|
|
public bool Changes { get; private set; }
|
|
|
|
public bool Loaded
|
|
{
|
|
get { throw new NotImplementedException(); }
|
|
}
|
|
|
|
public TimeSpan Time
|
|
{
|
|
get
|
|
{
|
|
double dblseconds = GetSeconds(_records.Count);
|
|
int seconds = (int)(dblseconds % 60);
|
|
int days = seconds / 86400;
|
|
int hours = seconds / 3600;
|
|
int minutes = (seconds / 60) % 60;
|
|
int milliseconds = (int)((dblseconds - (double)seconds) * 1000);
|
|
return new TimeSpan(days, hours, minutes, seconds, milliseconds);
|
|
}
|
|
}
|
|
|
|
public double FrameCount
|
|
{
|
|
get { return _records.Count; }
|
|
}
|
|
|
|
public int InputLogLength
|
|
{
|
|
get { return _records.Count; }
|
|
}
|
|
|
|
public string GetInput(int frame)
|
|
{
|
|
if (frame < _records.Count)
|
|
{
|
|
return _records[frame].Input;
|
|
}
|
|
else
|
|
{
|
|
_mode = Moviemode.Finished;
|
|
return String.Empty;
|
|
}
|
|
}
|
|
|
|
public string GetInputLog()
|
|
{
|
|
return _records.ToString();
|
|
}
|
|
|
|
public void SwitchToRecord()
|
|
{
|
|
_mode = Moviemode.Record;
|
|
}
|
|
|
|
public void SwitchToPlay()
|
|
{
|
|
_mode = Moviemode.Play;
|
|
Save();
|
|
}
|
|
|
|
public void StartNewPlayback()
|
|
{
|
|
_mode = Moviemode.Play;
|
|
Global.Emulator.ClearSaveRam();
|
|
}
|
|
|
|
public void Stop(bool saveChanges = true)
|
|
{
|
|
if (saveChanges)
|
|
{
|
|
if (_mode == Moviemode.Record || Changes)
|
|
{
|
|
Save();
|
|
}
|
|
}
|
|
|
|
_mode = Moviemode.Inactive;
|
|
}
|
|
|
|
public void Truncate(int frame)
|
|
{
|
|
_records.Truncate(frame);
|
|
}
|
|
|
|
public void ClearFrame(int frame)
|
|
{
|
|
if (frame < _records.Count)
|
|
{
|
|
Changes = true;
|
|
_records[frame].Input = MnemonicsGenerator.GetEmptyMnemonic;
|
|
}
|
|
}
|
|
|
|
public void AppendFrame(MnemonicsGenerator mg)
|
|
{
|
|
Changes = true;
|
|
_records.Add(new MovieRecord()
|
|
{
|
|
Input = mg.GetControllersAsMnemonic(),
|
|
});
|
|
}
|
|
|
|
public void RecordFrame(int frame, MnemonicsGenerator mg)
|
|
{
|
|
if (_mode == Moviemode.Record)
|
|
{
|
|
Changes = true;
|
|
if (Global.Config.VBAStyleMovieLoadState)
|
|
{
|
|
if (Global.Emulator.Frame < _records.Count)
|
|
{
|
|
_records.Truncate(Global.Emulator.Frame);
|
|
}
|
|
}
|
|
|
|
PokeFrame(frame, mg);
|
|
}
|
|
}
|
|
|
|
public void PokeFrame(int frame, MnemonicsGenerator mg)
|
|
{
|
|
if (frame < _records.Count)
|
|
{
|
|
Changes = true;
|
|
_records[frame].Input = mg.GetControllersAsMnemonic();
|
|
}
|
|
}
|
|
|
|
// TODO:
|
|
|
|
public double Fps
|
|
{
|
|
get
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
public void StartNewRecording()
|
|
{
|
|
SwitchToRecord();
|
|
if (Global.Config.EnableBackupMovies && true/*TODO*/ && _records.Any())
|
|
{
|
|
// TODO
|
|
}
|
|
}
|
|
|
|
public bool Load()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void Save()
|
|
{
|
|
Changes = false;
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void SaveAs()
|
|
{
|
|
Changes = false;
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public bool CheckTimeLines(TextReader reader, out string errorMessage)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public bool ExtractInputLog(TextReader reader, out string errorMessage)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Private
|
|
|
|
private enum Moviemode { Inactive, Play, Record, Finished };
|
|
private MovieRecordList _records;
|
|
private Moviemode _mode;
|
|
private readonly PlatformFrameRates _frameRates = new PlatformFrameRates();
|
|
|
|
private double GetSeconds(int frameCount)
|
|
{
|
|
double frames = frameCount;
|
|
|
|
if (frames < 1)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
var system = Header[HeaderKeys.PLATFORM];
|
|
var pal = Header.ContainsKey(HeaderKeys.PAL) && Header[HeaderKeys.PAL] == "1";
|
|
|
|
return frames / _frameRates[system, pal];
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|