BizHawk/BizHawk.Client.Common/movie/bkm/BkmMovie.cs

179 lines
3.5 KiB
C#

using BizHawk.Emulation.Common;
namespace BizHawk.Client.Common
{
public partial class BkmMovie : IMovie
{
private bool _makeBackup = true;
private bool _changes;
private int? _loopOffset;
public BkmMovie(string filename)
: this()
{
Rerecords = 0;
Filename = filename;
Loaded = !string.IsNullOrWhiteSpace(filename);
}
public BkmMovie()
{
Header = new BkmHeader();
Header[HeaderKeys.MOVIEVERSION] = "BizHawk v0.0.1";
Filename = string.Empty;
_preloadFramecount = 0;
IsCountingRerecords = true;
_mode = Moviemode.Inactive;
_makeBackup = true;
}
#region Properties
public ILogEntryGenerator LogGeneratorInstance()
{
return new BkmLogEntryGenerator();
}
public string PreferredExtension { get { return Extension; } }
public const string Extension = "bkm";
public BkmHeader Header { get; private set; }
public string Filename { get; set; }
public bool IsCountingRerecords { get; set; }
public bool Loaded { get; private set; }
public int InputLogLength
{
get { return _log.Count; }
}
public double FrameCount
{
get
{
if (_loopOffset.HasValue)
{
return double.PositiveInfinity;
}
if (Loaded)
{
return _log.Count;
}
return _preloadFramecount;
}
}
public bool Changes
{
get { return _changes; }
}
#endregion
#region Public Log Editing
public IController GetInputState(int frame)
{
if (frame < FrameCount && frame >= 0)
{
int getframe;
if (_loopOffset.HasValue)
{
if (frame < _log.Count)
{
getframe = frame;
}
else
{
getframe = ((frame - _loopOffset.Value) % (_log.Count - _loopOffset.Value)) + _loopOffset.Value;
}
}
else
{
getframe = frame;
}
var adapter = new BkmControllerAdapter
{
Type = Global.MovieSession.MovieControllerAdapter.Type
};
adapter.SetControllersAsMnemonic(_log[getframe]);
return adapter;
}
return null;
}
public void ClearFrame(int frame)
{
var lg = LogGeneratorInstance();
SetFrameAt(frame, lg.EmptyEntry);
_changes = true;
}
public void AppendFrame(IController source)
{
var lg = LogGeneratorInstance();
lg.SetSource(source);
_log.Add(lg.GenerateLogEntry());
_changes = true;
}
public void Truncate(int frame)
{
if (frame < _log.Count)
{
_log.RemoveRange(frame, _log.Count - frame);
_changes = true;
}
}
public void PokeFrame(int frame, IController source)
{
var lg = LogGeneratorInstance();
lg.SetSource(source);
_changes = true;
SetFrameAt(frame, lg.GenerateLogEntry());
}
public void RecordFrame(int frame, IController source)
{
// Note: Truncation here instead of loadstate will make VBA style loadstates
// (Where an entire movie is loaded then truncated on the next frame
// this allows users to restore a movie with any savestate from that "timeline"
if (Global.Config.VBAStyleMovieLoadState)
{
if (Global.Emulator.Frame < _log.Count)
{
Truncate(Global.Emulator.Frame);
}
}
var lg = LogGeneratorInstance();
lg.SetSource(source);
SetFrameAt(frame, lg.GenerateLogEntry());
_changes = true;
}
#endregion
private void SetFrameAt(int frameNum, string frame)
{
if (_log.Count > frameNum)
{
_log[frameNum] = frame;
}
else
{
_log.Add(frame);
}
}
}
}