2013-12-01 20:55:52 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
2013-12-10 01:45:45 +00:00
|
|
|
|
using System.Text;
|
2013-12-07 16:31:04 +00:00
|
|
|
|
using BizHawk.Emulation.Common;
|
|
|
|
|
|
2013-12-01 20:55:52 +00:00
|
|
|
|
namespace BizHawk.Client.Common
|
|
|
|
|
{
|
|
|
|
|
public class TasMovie : IMovie
|
|
|
|
|
{
|
2013-12-07 21:37:52 +00:00
|
|
|
|
// TODO: pass source into
|
2013-12-03 01:43:02 +00:00
|
|
|
|
// TODO: preloading, or benchmark and see how much of a performaance gain it really is
|
|
|
|
|
// TODO: support loop Offset
|
2013-12-07 21:37:52 +00:00
|
|
|
|
// TODO: consider the fileformat of binary and lagged data
|
2014-01-09 02:17:59 +00:00
|
|
|
|
private readonly IMnemonicPorts _mg;
|
2013-12-07 21:37:52 +00:00
|
|
|
|
private readonly IController _source = Global.MovieOutputHardpoint;
|
2013-12-07 17:29:47 +00:00
|
|
|
|
|
2013-12-06 15:47:23 +00:00
|
|
|
|
public MovieRecord this[int index]
|
|
|
|
|
{
|
2013-12-07 21:37:52 +00:00
|
|
|
|
get { return _records[index]; }
|
2013-12-06 15:47:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-07 17:29:47 +00:00
|
|
|
|
public List<string> ActivePlayers { get; set; }
|
|
|
|
|
|
|
|
|
|
public Dictionary<string, char> AvailableMnemonics
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2014-01-09 02:17:59 +00:00
|
|
|
|
return _mg.AvailableMnemonics;
|
2013-12-07 17:29:47 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-08 19:36:33 +00:00
|
|
|
|
public string PreferredExtension { get { return "tasproj"; } }
|
|
|
|
|
|
2013-12-08 18:44:41 +00:00
|
|
|
|
public void ToggleButton(int frame, string buttonName)
|
|
|
|
|
{
|
2013-12-14 21:05:54 +00:00
|
|
|
|
InvalidateGreenzone(frame);
|
2014-02-08 22:41:47 +00:00
|
|
|
|
/*Serialize todo
|
2013-12-09 21:40:27 +00:00
|
|
|
|
_records[frame].SetButton(buttonName, !_records[frame].Buttons[buttonName]);
|
2014-02-08 22:41:47 +00:00
|
|
|
|
*/
|
2013-12-09 21:40:27 +00:00
|
|
|
|
|
2013-12-08 18:44:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-08 19:42:07 +00:00
|
|
|
|
public void SetButton(int frame, string buttonName, bool value)
|
|
|
|
|
{
|
2013-12-14 21:05:54 +00:00
|
|
|
|
InvalidateGreenzone(frame);
|
2014-02-08 22:41:47 +00:00
|
|
|
|
/*Serialize TODO
|
2013-12-09 21:40:27 +00:00
|
|
|
|
_records[frame].SetButton(buttonName, value);
|
2014-02-08 22:41:47 +00:00
|
|
|
|
*/
|
2013-12-08 19:42:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsPressed(int frame, string buttonName)
|
|
|
|
|
{
|
2014-02-08 22:41:47 +00:00
|
|
|
|
return true; //Serialize TODO - _records[frame].Buttons[buttonName];
|
2013-12-09 21:40:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-14 21:05:54 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Removes the greenzone content after the given frame
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="frame"></param>
|
|
|
|
|
private void InvalidateGreenzone(int frame)
|
|
|
|
|
{
|
|
|
|
|
for (int i = frame + 1; i < _records.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
_records[i].ClearState();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-08 22:41:47 +00:00
|
|
|
|
#region IMovie Implementation
|
2013-12-02 04:24:45 +00:00
|
|
|
|
|
2013-12-01 22:29:38 +00:00
|
|
|
|
public TasMovie(string filename, bool startsFromSavestate = false)
|
|
|
|
|
: this(startsFromSavestate)
|
|
|
|
|
{
|
|
|
|
|
Filename = filename;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public TasMovie(bool startsFromSavestate = false)
|
|
|
|
|
{
|
2014-01-09 02:17:59 +00:00
|
|
|
|
_mg = MnemonicGeneratorFactory.Generate();
|
2014-02-08 22:41:47 +00:00
|
|
|
|
Filename = string.Empty;
|
2013-12-05 00:44:56 +00:00
|
|
|
|
Header = new MovieHeader { StartsFromSavestate = startsFromSavestate };
|
2013-12-10 01:45:45 +00:00
|
|
|
|
Header[HeaderKeys.MOVIEVERSION] = HeaderKeys.MovieVersion2;
|
2013-12-02 04:24:45 +00:00
|
|
|
|
_records = new MovieRecordList();
|
|
|
|
|
_mode = Moviemode.Inactive;
|
2013-12-02 17:50:29 +00:00
|
|
|
|
IsCountingRerecords = true;
|
2013-12-01 22:29:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-06-08 22:12:15 +00:00
|
|
|
|
public SubtitleList Subtitles
|
|
|
|
|
{
|
|
|
|
|
get { return Header.Subtitles; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IList<string> Comments
|
|
|
|
|
{
|
|
|
|
|
get { return Header.Comments; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string SyncSettingsJson
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return Header[HeaderKeys.SYNCSETTINGS];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
Header[HeaderKeys.SYNCSETTINGS] = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-01 22:29:38 +00:00
|
|
|
|
public string Filename { get; set; }
|
|
|
|
|
|
|
|
|
|
public IMovieHeader Header { get; private set; }
|
2013-12-01 20:55:52 +00:00
|
|
|
|
|
|
|
|
|
public bool IsActive
|
|
|
|
|
{
|
2013-12-02 04:24:45 +00:00
|
|
|
|
get { return _mode != Moviemode.Inactive; }
|
2013-12-01 20:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsPlaying
|
|
|
|
|
{
|
2013-12-10 17:59:04 +00:00
|
|
|
|
get { return _mode == Moviemode.Play; }
|
2013-12-01 20:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsRecording
|
|
|
|
|
{
|
2013-12-02 04:24:45 +00:00
|
|
|
|
get { return _mode == Moviemode.Record; }
|
2013-12-01 20:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsFinished
|
|
|
|
|
{
|
2013-12-10 17:59:04 +00:00
|
|
|
|
get { return false; } //a TasMovie is never in this mode.
|
2013-12-02 04:24:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-02 17:50:29 +00:00
|
|
|
|
public bool IsCountingRerecords { get; set; }
|
2013-12-01 20:55:52 +00:00
|
|
|
|
|
2013-12-14 14:40:33 +00:00
|
|
|
|
public bool Changes { get; set; }
|
2013-12-01 20:55:52 +00:00
|
|
|
|
|
2013-12-02 21:57:48 +00:00
|
|
|
|
public TimeSpan Time
|
|
|
|
|
{
|
2013-12-03 01:43:02 +00:00
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
double dblseconds = GetSeconds(_records.Count);
|
|
|
|
|
int seconds = (int)(dblseconds % 60);
|
|
|
|
|
int days = seconds / 86400;
|
|
|
|
|
int hours = seconds / 3600;
|
|
|
|
|
int minutes = (seconds / 60) % 60;
|
2013-12-05 00:44:56 +00:00
|
|
|
|
int milliseconds = (int)((dblseconds - seconds) * 1000);
|
2013-12-03 01:43:02 +00:00
|
|
|
|
return new TimeSpan(days, hours, minutes, seconds, milliseconds);
|
|
|
|
|
}
|
2013-12-02 21:57:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-01 20:55:52 +00:00
|
|
|
|
public double FrameCount
|
|
|
|
|
{
|
2013-12-03 01:43:02 +00:00
|
|
|
|
get { return _records.Count; }
|
2013-12-01 20:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int InputLogLength
|
|
|
|
|
{
|
2013-12-02 19:54:10 +00:00
|
|
|
|
get { return _records.Count; }
|
2013-12-01 20:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-03 01:43:02 +00:00
|
|
|
|
public string GetInput(int frame)
|
2013-12-01 20:55:52 +00:00
|
|
|
|
{
|
2013-12-03 01:43:02 +00:00
|
|
|
|
if (frame < _records.Count)
|
|
|
|
|
{
|
2013-12-05 19:18:20 +00:00
|
|
|
|
if (frame >= 0)
|
|
|
|
|
{
|
2013-12-14 20:32:00 +00:00
|
|
|
|
if (!_records[frame].HasState)
|
|
|
|
|
{
|
|
|
|
|
_records[frame].CaptureSate();
|
|
|
|
|
}
|
2014-02-08 22:41:47 +00:00
|
|
|
|
|
|
|
|
|
return string.Empty; //Serialize TODO _mg.GenerateMnemonicString(_records[frame].Buttons);
|
2013-12-05 19:18:20 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-02-08 22:41:47 +00:00
|
|
|
|
return string.Empty;
|
2013-12-05 19:18:20 +00:00
|
|
|
|
}
|
2013-12-03 01:43:02 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2013-12-14 20:32:00 +00:00
|
|
|
|
_mode = Moviemode.Record;
|
|
|
|
|
|
2014-02-08 22:41:47 +00:00
|
|
|
|
/* Serialize TODO
|
2013-12-14 20:32:00 +00:00
|
|
|
|
var buttons = _mg.ParseMnemonicString(_mg.EmptyMnemonic);
|
|
|
|
|
_records.Add(new MovieRecord(buttons, true));
|
2014-02-08 22:41:47 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
return string.Empty;
|
2013-12-03 01:43:02 +00:00
|
|
|
|
}
|
2013-12-01 20:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-03 01:43:02 +00:00
|
|
|
|
public string GetInputLog()
|
2013-12-01 20:55:52 +00:00
|
|
|
|
{
|
2013-12-10 01:45:45 +00:00
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
|
foreach (var record in _records)
|
|
|
|
|
{
|
2014-02-08 22:41:47 +00:00
|
|
|
|
sb.AppendLine(record.SerializedInput);
|
2013-12-10 01:45:45 +00:00
|
|
|
|
}
|
2014-02-08 22:41:47 +00:00
|
|
|
|
|
2013-12-10 01:45:45 +00:00
|
|
|
|
return sb.ToString();
|
2013-12-01 20:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-03 01:43:02 +00:00
|
|
|
|
public void SwitchToRecord()
|
2013-12-01 20:55:52 +00:00
|
|
|
|
{
|
2013-12-03 01:43:02 +00:00
|
|
|
|
_mode = Moviemode.Record;
|
2013-12-01 20:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-03 01:43:02 +00:00
|
|
|
|
public void SwitchToPlay()
|
2013-12-01 20:55:52 +00:00
|
|
|
|
{
|
2013-12-03 01:43:02 +00:00
|
|
|
|
_mode = Moviemode.Play;
|
2013-12-01 20:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-03 01:43:02 +00:00
|
|
|
|
public void StartNewPlayback()
|
2013-12-01 20:55:52 +00:00
|
|
|
|
{
|
2013-12-03 01:43:02 +00:00
|
|
|
|
_mode = Moviemode.Play;
|
2014-06-02 16:33:08 +00:00
|
|
|
|
Global.Emulator.ClearSaveRam(); // should this exist??
|
2013-12-01 20:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-03 01:43:02 +00:00
|
|
|
|
public void Stop(bool saveChanges = true)
|
2013-12-01 20:55:52 +00:00
|
|
|
|
{
|
2013-12-14 14:40:33 +00:00
|
|
|
|
// adelikat: I think Tastudio should be in charge of saving, and so we should not attempt to manage any logic like that here
|
|
|
|
|
// EmuHawk client UI assumes someone has already picked a filename ahead of time and that it is in charge of movies
|
2013-12-03 01:43:02 +00:00
|
|
|
|
_mode = Moviemode.Inactive;
|
2013-12-01 20:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-03 01:43:02 +00:00
|
|
|
|
public void Truncate(int frame)
|
2013-12-01 20:55:52 +00:00
|
|
|
|
{
|
2013-12-03 01:43:02 +00:00
|
|
|
|
_records.Truncate(frame);
|
2013-12-01 20:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-03 01:43:02 +00:00
|
|
|
|
public void ClearFrame(int frame)
|
2013-12-01 20:55:52 +00:00
|
|
|
|
{
|
2013-12-03 15:59:46 +00:00
|
|
|
|
if (frame < _records.Count)
|
|
|
|
|
{
|
|
|
|
|
Changes = true;
|
2013-12-06 15:47:23 +00:00
|
|
|
|
_records[frame].ClearInput();
|
2013-12-03 15:59:46 +00:00
|
|
|
|
}
|
2013-12-01 20:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-07 16:31:04 +00:00
|
|
|
|
public void AppendFrame(IController source)
|
2013-12-01 20:55:52 +00:00
|
|
|
|
{
|
2013-12-03 15:59:46 +00:00
|
|
|
|
Changes = true;
|
2014-02-08 22:41:47 +00:00
|
|
|
|
/* Serialize TODO
|
2013-12-07 21:37:52 +00:00
|
|
|
|
_mg.Source = source;
|
2013-12-09 21:40:27 +00:00
|
|
|
|
var record = new MovieRecord(_mg.GetBoolButtons(), true);
|
|
|
|
|
_records.Add(record);
|
2014-02-08 22:41:47 +00:00
|
|
|
|
*/
|
2013-12-01 20:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-07 16:31:04 +00:00
|
|
|
|
public void RecordFrame(int frame, IController source)
|
2013-12-01 20:55:52 +00:00
|
|
|
|
{
|
2013-12-03 15:59:46 +00:00
|
|
|
|
if (_mode == Moviemode.Record)
|
|
|
|
|
{
|
|
|
|
|
Changes = true;
|
|
|
|
|
if (Global.Config.VBAStyleMovieLoadState)
|
|
|
|
|
{
|
|
|
|
|
if (Global.Emulator.Frame < _records.Count)
|
|
|
|
|
{
|
|
|
|
|
_records.Truncate(Global.Emulator.Frame);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-06 15:47:23 +00:00
|
|
|
|
if (frame < _records.Count)
|
|
|
|
|
{
|
2013-12-07 16:31:04 +00:00
|
|
|
|
PokeFrame(frame, source);
|
2013-12-06 15:47:23 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2013-12-07 16:31:04 +00:00
|
|
|
|
AppendFrame(source);
|
2013-12-06 15:47:23 +00:00
|
|
|
|
}
|
2013-12-03 15:59:46 +00:00
|
|
|
|
}
|
2013-12-01 20:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-07 16:31:04 +00:00
|
|
|
|
public void PokeFrame(int frame, IController source)
|
2013-12-01 20:55:52 +00:00
|
|
|
|
{
|
2013-12-14 21:05:54 +00:00
|
|
|
|
InvalidateGreenzone(frame);
|
2013-12-03 15:59:46 +00:00
|
|
|
|
if (frame < _records.Count)
|
|
|
|
|
{
|
|
|
|
|
Changes = true;
|
2013-12-07 21:37:52 +00:00
|
|
|
|
_mg.Source = source;
|
2014-02-08 22:41:47 +00:00
|
|
|
|
/* Serialize TODO
|
2013-12-07 21:37:52 +00:00
|
|
|
|
_records[frame].SetInput(_mg.GetBoolButtons());
|
2014-02-08 22:41:47 +00:00
|
|
|
|
*/
|
2013-12-03 15:59:46 +00:00
|
|
|
|
}
|
2013-12-01 20:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-04 15:17:02 +00:00
|
|
|
|
public double Fps
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
2013-12-10 17:59:04 +00:00
|
|
|
|
var system = Header[HeaderKeys.PLATFORM];
|
|
|
|
|
var pal = Header.ContainsKey(HeaderKeys.PAL) &&
|
|
|
|
|
Header[HeaderKeys.PAL] == "1";
|
|
|
|
|
|
|
|
|
|
return _frameRates[system, pal];
|
2013-12-04 15:17:02 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-03 18:08:45 +00:00
|
|
|
|
public void StartNewRecording()
|
|
|
|
|
{
|
|
|
|
|
SwitchToRecord();
|
2013-12-10 16:37:41 +00:00
|
|
|
|
|
2013-12-14 14:40:33 +00:00
|
|
|
|
// TODO: MakeBackup logic - Tastudio logic should be to always make backups before saving!
|
|
|
|
|
|
|
|
|
|
if (Changes && !String.IsNullOrWhiteSpace(Filename))
|
2013-12-03 18:08:45 +00:00
|
|
|
|
{
|
2013-12-10 16:37:41 +00:00
|
|
|
|
Save();
|
2013-12-03 18:08:45 +00:00
|
|
|
|
}
|
2013-12-10 16:37:41 +00:00
|
|
|
|
|
|
|
|
|
_records.Clear();
|
|
|
|
|
Header.Clear();
|
2013-12-03 18:08:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool Load()
|
|
|
|
|
{
|
2013-12-14 19:51:07 +00:00
|
|
|
|
var file = new FileInfo(Filename);
|
|
|
|
|
if (!file.Exists)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2013-12-07 22:41:45 +00:00
|
|
|
|
// there's a lot of common code here with SavestateManager. refactor?
|
2013-12-17 21:26:15 +00:00
|
|
|
|
using (BinaryStateLoader bl = BinaryStateLoader.LoadAndDetect(Filename))
|
2013-12-07 22:41:45 +00:00
|
|
|
|
{
|
2013-12-17 21:26:15 +00:00
|
|
|
|
if (bl == null)
|
2013-12-07 22:41:45 +00:00
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
Header.Clear();
|
|
|
|
|
_records.Clear();
|
|
|
|
|
|
2013-12-17 21:26:15 +00:00
|
|
|
|
bl.GetLump(BinaryStateLump.Movieheader, true,
|
|
|
|
|
delegate(TextReader tr)
|
2013-12-07 22:41:45 +00:00
|
|
|
|
{
|
|
|
|
|
string line;
|
2013-12-17 21:26:15 +00:00
|
|
|
|
while ((line = tr.ReadLine()) != null)
|
2013-12-07 22:41:45 +00:00
|
|
|
|
if (!Header.ParseLineFromFile(line))
|
|
|
|
|
Header.Comments.Add(line);
|
|
|
|
|
});
|
2013-12-17 21:26:15 +00:00
|
|
|
|
bl.GetLump(BinaryStateLump.Input, true,
|
|
|
|
|
delegate(TextReader tr)
|
2013-12-07 22:41:45 +00:00
|
|
|
|
{
|
2014-02-08 22:41:47 +00:00
|
|
|
|
string line = string.Empty;
|
2013-12-14 18:46:59 +00:00
|
|
|
|
while (true)
|
|
|
|
|
{
|
2013-12-17 21:26:15 +00:00
|
|
|
|
line = tr.ReadLine();
|
2013-12-14 18:46:59 +00:00
|
|
|
|
if (line == null)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else if (line.StartsWith("|"))
|
|
|
|
|
{
|
2014-02-08 22:41:47 +00:00
|
|
|
|
/* Serialize TODO
|
2013-12-14 18:46:59 +00:00
|
|
|
|
var parsedButtons = _mg.ParseMnemonicString(line);
|
|
|
|
|
_records.Add(new MovieRecord(parsedButtons, captureState: false));
|
2014-02-08 22:41:47 +00:00
|
|
|
|
*/
|
2013-12-14 18:46:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2013-12-07 22:41:45 +00:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (Header.StartsFromSavestate)
|
|
|
|
|
{
|
|
|
|
|
// should we raise some sort of error if there's a savestate in the archive but Header.StartsFromSavestate is false?
|
2013-12-17 21:26:15 +00:00
|
|
|
|
bl.GetCoreState(
|
2013-12-07 22:41:45 +00:00
|
|
|
|
delegate(Stream s)
|
|
|
|
|
{
|
|
|
|
|
BinaryReader br = new BinaryReader(s);
|
|
|
|
|
Global.Emulator.LoadStateBinary(br);
|
|
|
|
|
},
|
|
|
|
|
delegate(Stream s)
|
|
|
|
|
{
|
|
|
|
|
StreamReader sr = new StreamReader(s);
|
|
|
|
|
Global.Emulator.LoadStateText(sr);
|
|
|
|
|
});
|
|
|
|
|
}
|
2013-12-17 21:26:15 +00:00
|
|
|
|
bl.GetLump(BinaryStateLump.Framebuffer, false,
|
|
|
|
|
delegate(BinaryReader br)
|
2013-12-07 22:41:45 +00:00
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
var buff = Global.Emulator.VideoProvider.GetVideoBuffer();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
for (i = 0; i < buff.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
int j = br.ReadInt32();
|
|
|
|
|
buff[i] = j;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (EndOfStreamException) { }
|
|
|
|
|
});
|
|
|
|
|
}
|
2013-12-14 20:32:00 +00:00
|
|
|
|
|
|
|
|
|
_mode = Moviemode.Play;
|
2013-12-07 22:41:45 +00:00
|
|
|
|
return true;
|
2013-12-03 18:08:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Save()
|
|
|
|
|
{
|
2013-12-07 22:41:45 +00:00
|
|
|
|
// there's a lot of common code here with SavestateManager. refactor?
|
|
|
|
|
|
|
|
|
|
using (FileStream fs = new FileStream(Filename, FileMode.Create, FileAccess.Write))
|
|
|
|
|
using (BinaryStateSaver bs = new BinaryStateSaver(fs))
|
|
|
|
|
{
|
2013-12-17 21:26:15 +00:00
|
|
|
|
bs.PutLump(BinaryStateLump.Movieheader, (tw) => tw.WriteLine(Header.ToString()));
|
|
|
|
|
bs.PutLump(BinaryStateLump.Input, (tw) => tw.WriteLine(GetInputLog()));
|
2013-12-07 22:41:45 +00:00
|
|
|
|
if (Header.StartsFromSavestate)
|
|
|
|
|
{
|
|
|
|
|
#if true
|
2013-12-17 21:26:15 +00:00
|
|
|
|
bs.PutLump(BinaryStateLump.CorestateText, (tw) => Global.Emulator.SaveStateText(tw));
|
2013-12-07 22:41:45 +00:00
|
|
|
|
#else
|
2013-12-17 21:26:15 +00:00
|
|
|
|
bs.PutLump(BinaryStateLump.Corestate, (bw) => Global.Emulator.SaveStateBinary(bw));
|
2013-12-07 22:41:45 +00:00
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-12-03 18:08:45 +00:00
|
|
|
|
Changes = false;
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-04 03:16:35 +00:00
|
|
|
|
public bool CheckTimeLines(TextReader reader, out string errorMessage)
|
2013-12-01 20:55:52 +00:00
|
|
|
|
{
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-05 00:20:21 +00:00
|
|
|
|
public bool ExtractInputLog(TextReader reader, out string errorMessage)
|
2013-12-01 20:55:52 +00:00
|
|
|
|
{
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-03 01:43:02 +00:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Private
|
|
|
|
|
|
2013-12-07 21:37:52 +00:00
|
|
|
|
private enum Moviemode { Inactive, Play, Record, Finished }
|
2013-12-05 00:44:56 +00:00
|
|
|
|
private readonly MovieRecordList _records;
|
2013-12-03 01:43:02 +00:00
|
|
|
|
private Moviemode _mode;
|
|
|
|
|
private readonly PlatformFrameRates _frameRates = new PlatformFrameRates();
|
|
|
|
|
|
|
|
|
|
private double GetSeconds(int frameCount)
|
2013-12-01 20:55:52 +00:00
|
|
|
|
{
|
2013-12-03 01:43:02 +00:00
|
|
|
|
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];
|
2013-12-01 20:55:52 +00:00
|
|
|
|
}
|
2013-12-03 01:43:02 +00:00
|
|
|
|
|
|
|
|
|
#endregion
|
2013-12-01 20:55:52 +00:00
|
|
|
|
}
|
|
|
|
|
}
|