Implement IBasicMovieInfo interface for IMovie (#3634)
* Implement IBasicMovieInfo interface for IMovie this allows parsing basic movie fields into an own class that is independent from Bk2Movie/TasMovie This is mainly useful for the PlayMovie dialog which can now load movie information from files on disk without having to go through the entire Bk2Movie/TasMovie loading process * don't potentially iterate input log twice * Optimize LoadFramecount
This commit is contained in:
parent
9b278d3130
commit
bc16a2cdaa
|
@ -0,0 +1,260 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
|
namespace BizHawk.Client.Common
|
||||||
|
{
|
||||||
|
public class BasicMovieInfo : IBasicMovieInfo
|
||||||
|
{
|
||||||
|
private string _filename;
|
||||||
|
private bool IsPal => Header[HeaderKeys.Pal] == "1";
|
||||||
|
|
||||||
|
protected readonly Bk2Header Header = new();
|
||||||
|
|
||||||
|
public BasicMovieInfo(string filename)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(filename))
|
||||||
|
{
|
||||||
|
throw filename is null
|
||||||
|
? new ArgumentNullException(paramName: nameof(filename))
|
||||||
|
: new ArgumentException(message: "path cannot be blank", paramName: nameof(filename));
|
||||||
|
}
|
||||||
|
|
||||||
|
Filename = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; private set; }
|
||||||
|
|
||||||
|
public string Filename
|
||||||
|
{
|
||||||
|
get => _filename;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_filename = value;
|
||||||
|
Name = Path.GetFileName(Filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual int FrameCount { get; private set; }
|
||||||
|
|
||||||
|
public TimeSpan TimeLength
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
double dblSeconds;
|
||||||
|
|
||||||
|
if (Header.TryGetValue(HeaderKeys.CycleCount, out var numCyclesStr) && Header.TryGetValue(HeaderKeys.ClockRate, out var clockRateStr))
|
||||||
|
{
|
||||||
|
var numCycles = Convert.ToUInt64(numCyclesStr);
|
||||||
|
var clockRate = Convert.ToDouble(clockRateStr, CultureInfo.InvariantCulture);
|
||||||
|
dblSeconds = numCycles / clockRate;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var numFrames = (ulong)FrameCount;
|
||||||
|
dblSeconds = numFrames / FrameRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
var seconds = (int)(dblSeconds % 60);
|
||||||
|
var days = seconds / 86400;
|
||||||
|
var hours = seconds / 3600;
|
||||||
|
var minutes = (seconds / 60) % 60;
|
||||||
|
var milliseconds = (int)((dblSeconds - seconds) * 1000);
|
||||||
|
return new TimeSpan(days, hours, minutes, seconds, milliseconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double FrameRate
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (SystemID == VSystemID.Raw.Arcade && Header.TryGetValue(HeaderKeys.VsyncAttoseconds, out var vsyncAttoStr))
|
||||||
|
{
|
||||||
|
const decimal attosInSec = 1000000000000000000;
|
||||||
|
return (double)(attosInSec / Convert.ToUInt64(vsyncAttoStr));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return PlatformFrameRates.GetFrameRate(SystemID, IsPal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SubtitleList Subtitles { get; } = new();
|
||||||
|
public IList<string> Comments { get; } = new List<string>();
|
||||||
|
|
||||||
|
public virtual string GameName
|
||||||
|
{
|
||||||
|
get => Header[HeaderKeys.GameName];
|
||||||
|
set => Header[HeaderKeys.GameName] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual string SystemID
|
||||||
|
{
|
||||||
|
get => Header[HeaderKeys.Platform];
|
||||||
|
set => Header[HeaderKeys.Platform] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual ulong Rerecords
|
||||||
|
{
|
||||||
|
get => ulong.Parse(Header[HeaderKeys.Rerecords]);
|
||||||
|
set => Header[HeaderKeys.Rerecords] = value.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual string Hash
|
||||||
|
{
|
||||||
|
get => Header[HeaderKeys.Sha1];
|
||||||
|
set => Header[HeaderKeys.Sha1] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual string Author
|
||||||
|
{
|
||||||
|
get => Header[HeaderKeys.Author];
|
||||||
|
set => Header[HeaderKeys.Author] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual string Core
|
||||||
|
{
|
||||||
|
get => Header[HeaderKeys.Core];
|
||||||
|
set => Header[HeaderKeys.Core] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual string BoardName
|
||||||
|
{
|
||||||
|
get => Header[HeaderKeys.BoardName];
|
||||||
|
set => Header[HeaderKeys.BoardName] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual string EmulatorVersion
|
||||||
|
{
|
||||||
|
get => Header[HeaderKeys.EmulatorVersion];
|
||||||
|
set => Header[HeaderKeys.EmulatorVersion] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual string OriginalEmulatorVersion
|
||||||
|
{
|
||||||
|
get => Header[HeaderKeys.OriginalEmulatorVersion];
|
||||||
|
set => Header[HeaderKeys.OriginalEmulatorVersion] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual string FirmwareHash
|
||||||
|
{
|
||||||
|
get => Header[HeaderKeys.FirmwareSha1];
|
||||||
|
set => Header[HeaderKeys.FirmwareSha1] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDictionary<string, string> HeaderEntries => Header;
|
||||||
|
|
||||||
|
public bool Load()
|
||||||
|
{
|
||||||
|
var file = new FileInfo(Filename);
|
||||||
|
if (!file.Exists)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var bl = ZipStateLoader.LoadAndDetect(Filename, true);
|
||||||
|
if (bl is null) return false;
|
||||||
|
ClearBeforeLoad();
|
||||||
|
LoadFields(bl);
|
||||||
|
if (FrameCount == 0)
|
||||||
|
{
|
||||||
|
// only iterate the input log if it hasn't been loaded already
|
||||||
|
LoadFramecount(bl);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (InvalidDataException e) when (e.StackTrace.Contains("ZipArchive.ReadEndOfCentralDirectory"))
|
||||||
|
{
|
||||||
|
throw new Exception("Archive appears to be corrupt. Make a backup, then try to repair it with e.g. 7-Zip.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void ClearBeforeLoad()
|
||||||
|
{
|
||||||
|
Header.Clear();
|
||||||
|
Subtitles.Clear();
|
||||||
|
Comments.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void LoadFields(ZipStateLoader bl)
|
||||||
|
{
|
||||||
|
bl.GetLump(BinaryStateLump.Movieheader, abort: true, tr =>
|
||||||
|
{
|
||||||
|
while (tr.ReadLine() is string line)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(line))
|
||||||
|
{
|
||||||
|
var pair = line.Split(new[] { ' ' }, 2, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
|
if (pair.Length > 1)
|
||||||
|
{
|
||||||
|
if (!Header.ContainsKey(pair[0]))
|
||||||
|
{
|
||||||
|
Header.Add(pair[0], pair[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bl.GetLump(BinaryStateLump.Comments, abort: false, tr =>
|
||||||
|
{
|
||||||
|
while (tr.ReadLine() is string line)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(line))
|
||||||
|
{
|
||||||
|
Comments.Add(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
bl.GetLump(BinaryStateLump.Subtitles, abort: false, tr =>
|
||||||
|
{
|
||||||
|
while (tr.ReadLine() is string line)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(line))
|
||||||
|
{
|
||||||
|
Subtitles.AddFromString(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Subtitles.Sort();
|
||||||
|
});
|
||||||
|
|
||||||
|
bl.GetLump(BinaryStateLump.Subtitles, abort: false, tr =>
|
||||||
|
{
|
||||||
|
while (tr.ReadLine() is string line)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(line))
|
||||||
|
{
|
||||||
|
Subtitles.AddFromString(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Subtitles.Sort();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadFramecount(ZipStateLoader bl)
|
||||||
|
{
|
||||||
|
bl.GetLump(BinaryStateLump.Input, abort: true, tr =>
|
||||||
|
{
|
||||||
|
// just skim through the input log and count input lines
|
||||||
|
// FIXME: this is potentially expensive and shouldn't be necessary for something as simple as frame count
|
||||||
|
while (tr.ReadLine() is string line)
|
||||||
|
{
|
||||||
|
if (line.Length > 0 && line[0] == '|')
|
||||||
|
{
|
||||||
|
FrameCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -188,7 +188,7 @@ namespace BizHawk.Client.Common
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <exception cref="MoviePlatformMismatchException"><paramref name="record"/> is <see langword="false"/> and <paramref name="movie"/>.<see cref="IMovie.SystemID"/> does not match <paramref name="systemId"/>.<see cref="IEmulator.SystemId"/></exception>
|
/// <exception cref="MoviePlatformMismatchException"><paramref name="record"/> is <see langword="false"/> and <paramref name="movie"/>.<see cref="IBasicMovieInfo.SystemID"/> does not match <paramref name="systemId"/>.<see cref="IEmulator.SystemId"/></exception>
|
||||||
public void QueueNewMovie(IMovie movie, bool record, string systemId, IDictionary<string, string> preferredCores)
|
public void QueueNewMovie(IMovie movie, bool record, string systemId, IDictionary<string, string> preferredCores)
|
||||||
{
|
{
|
||||||
if (movie.IsActive() && movie.Changes)
|
if (movie.IsActive() && movie.Changes)
|
||||||
|
@ -198,7 +198,7 @@ namespace BizHawk.Client.Common
|
||||||
|
|
||||||
if (!record) // The semantics of record is that we are starting a new movie, and even wiping a pre-existing movie with the same path, but non-record means we are loading an existing movie into playback mode
|
if (!record) // The semantics of record is that we are starting a new movie, and even wiping a pre-existing movie with the same path, but non-record means we are loading an existing movie into playback mode
|
||||||
{
|
{
|
||||||
movie.Load(false);
|
movie.Load();
|
||||||
|
|
||||||
if (movie.SystemID != systemId)
|
if (movie.SystemID != systemId)
|
||||||
{
|
{
|
||||||
|
@ -400,4 +400,4 @@ namespace BizHawk.Client.Common
|
||||||
Movie.RecordFrame(Movie.Emulator.Frame, MovieController);
|
Movie.RecordFrame(Movie.Emulator.Frame, MovieController);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,11 @@
|
||||||
using System.Collections.Generic;
|
using System.Text;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace BizHawk.Client.Common
|
namespace BizHawk.Client.Common
|
||||||
{
|
{
|
||||||
public partial class Bk2Movie
|
public partial class Bk2Movie
|
||||||
{
|
{
|
||||||
protected readonly Bk2Header Header = new Bk2Header();
|
|
||||||
private string _syncSettingsJson = "";
|
private string _syncSettingsJson = "";
|
||||||
|
|
||||||
public IDictionary<string, string> HeaderEntries => Header;
|
|
||||||
|
|
||||||
public SubtitleList Subtitles { get; } = new SubtitleList();
|
|
||||||
public IList<string> Comments { get; } = new List<string>();
|
|
||||||
|
|
||||||
public string SyncSettingsJson
|
public string SyncSettingsJson
|
||||||
{
|
{
|
||||||
get => _syncSettingsJson;
|
get => _syncSettingsJson;
|
||||||
|
@ -26,11 +19,8 @@ namespace BizHawk.Client.Common
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ulong Rerecords
|
public override ulong Rerecords
|
||||||
{
|
{
|
||||||
get => Header.TryGetValue(HeaderKeys.Rerecords, out var s)
|
|
||||||
? ulong.Parse(s)
|
|
||||||
: 0UL; // Modifying the header itself can cause a race condition between loading a movie and rendering the rerecord count, causing a movie's rerecord count to be overwritten with 0 during loading.
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (Header[HeaderKeys.Rerecords] != value.ToString())
|
if (Header[HeaderKeys.Rerecords] != value.ToString())
|
||||||
|
@ -80,9 +70,8 @@ namespace BizHawk.Client.Common
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GameName
|
public override string GameName
|
||||||
{
|
{
|
||||||
get => Header.TryGetValue(HeaderKeys.GameName, out var s) ? s : string.Empty;
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (Header[HeaderKeys.GameName] != value)
|
if (Header[HeaderKeys.GameName] != value)
|
||||||
|
@ -93,9 +82,8 @@ namespace BizHawk.Client.Common
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string SystemID
|
public override string SystemID
|
||||||
{
|
{
|
||||||
get => Header.TryGetValue(HeaderKeys.Platform, out var s) ? s : string.Empty;
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (Header[HeaderKeys.Platform] != value)
|
if (Header[HeaderKeys.Platform] != value)
|
||||||
|
@ -106,9 +94,8 @@ namespace BizHawk.Client.Common
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Hash
|
public override string Hash
|
||||||
{
|
{
|
||||||
get => Header[HeaderKeys.Sha1];
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (Header[HeaderKeys.Sha1] != value)
|
if (Header[HeaderKeys.Sha1] != value)
|
||||||
|
@ -119,9 +106,8 @@ namespace BizHawk.Client.Common
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Author
|
public override string Author
|
||||||
{
|
{
|
||||||
get => Header[HeaderKeys.Author];
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (Header[HeaderKeys.Author] != value)
|
if (Header[HeaderKeys.Author] != value)
|
||||||
|
@ -132,9 +118,8 @@ namespace BizHawk.Client.Common
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Core
|
public override string Core
|
||||||
{
|
{
|
||||||
get => Header[HeaderKeys.Core];
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (Header[HeaderKeys.Core] != value)
|
if (Header[HeaderKeys.Core] != value)
|
||||||
|
@ -145,9 +130,8 @@ namespace BizHawk.Client.Common
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string BoardName
|
public override string BoardName
|
||||||
{
|
{
|
||||||
get => Header[HeaderKeys.BoardName];
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (Header[HeaderKeys.BoardName] != value)
|
if (Header[HeaderKeys.BoardName] != value)
|
||||||
|
@ -158,9 +142,8 @@ namespace BizHawk.Client.Common
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string EmulatorVersion
|
public override string EmulatorVersion
|
||||||
{
|
{
|
||||||
get => Header[HeaderKeys.EmulatorVersion];
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (Header[HeaderKeys.EmulatorVersion] != value)
|
if (Header[HeaderKeys.EmulatorVersion] != value)
|
||||||
|
@ -171,9 +154,8 @@ namespace BizHawk.Client.Common
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string OriginalEmulatorVersion
|
public override string OriginalEmulatorVersion
|
||||||
{
|
{
|
||||||
get => Header[HeaderKeys.OriginalEmulatorVersion];
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (Header[HeaderKeys.OriginalEmulatorVersion] != value)
|
if (Header[HeaderKeys.OriginalEmulatorVersion] != value)
|
||||||
|
@ -184,9 +166,8 @@ namespace BizHawk.Client.Common
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string FirmwareHash
|
public override string FirmwareHash
|
||||||
{
|
{
|
||||||
get => Header[HeaderKeys.FirmwareSha1];
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (Header[HeaderKeys.FirmwareSha1] != value)
|
if (Header[HeaderKeys.FirmwareSha1] != value)
|
||||||
|
@ -209,10 +190,6 @@ namespace BizHawk.Client.Common
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReSharper disable SimplifyConditionalTernaryExpression
|
|
||||||
public bool IsPal => Header.TryGetValue(HeaderKeys.Pal, out var s) ? s == "1" : false;
|
|
||||||
// ReSharper restore SimplifyConditionalTernaryExpression
|
|
||||||
|
|
||||||
public string TextSavestate { get; set; }
|
public string TextSavestate { get; set; }
|
||||||
public byte[] BinarySavestate { get; set; }
|
public byte[] BinarySavestate { get; set; }
|
||||||
public int[] SavestateFramebuffer { get; set; }
|
public int[] SavestateFramebuffer { get; set; }
|
||||||
|
|
|
@ -29,31 +29,6 @@ namespace BizHawk.Client.Common
|
||||||
Write(backupName, isBackup: true);
|
Write(backupName, isBackup: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool Load(bool preload)
|
|
||||||
{
|
|
||||||
var file = new FileInfo(Filename);
|
|
||||||
if (!file.Exists)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using var bl = ZipStateLoader.LoadAndDetect(Filename, true);
|
|
||||||
if (bl is null) return false;
|
|
||||||
ClearBeforeLoad();
|
|
||||||
LoadFields(bl, preload);
|
|
||||||
Changes = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (InvalidDataException e) when (e.StackTrace.Contains("ZipArchive.ReadEndOfCentralDirectory"))
|
|
||||||
{
|
|
||||||
throw new Exception("Archive appears to be corrupt. Make a backup, then try to repair it with e.g. 7-Zip.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool PreLoadHeaderAndLength() => Load(true);
|
|
||||||
|
|
||||||
protected virtual void Write(string fn, bool isBackup = false)
|
protected virtual void Write(string fn, bool isBackup = false)
|
||||||
{
|
{
|
||||||
SetCycleValues();
|
SetCycleValues();
|
||||||
|
@ -136,49 +111,28 @@ namespace BizHawk.Client.Common
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void ClearBeforeLoad()
|
protected override void ClearBeforeLoad()
|
||||||
{
|
{
|
||||||
|
base.ClearBeforeLoad();
|
||||||
ClearBk2Fields();
|
ClearBk2Fields();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ClearBk2Fields()
|
private void ClearBk2Fields()
|
||||||
{
|
{
|
||||||
Header.Clear();
|
|
||||||
Log.Clear();
|
Log.Clear();
|
||||||
Subtitles.Clear();
|
|
||||||
Comments.Clear();
|
|
||||||
_syncSettingsJson = "";
|
_syncSettingsJson = "";
|
||||||
TextSavestate = null;
|
TextSavestate = null;
|
||||||
BinarySavestate = null;
|
BinarySavestate = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void LoadFields(ZipStateLoader bl, bool preload)
|
protected override void LoadFields(ZipStateLoader bl)
|
||||||
{
|
{
|
||||||
LoadBk2Fields(bl, preload);
|
base.LoadFields(bl);
|
||||||
|
LoadBk2Fields(bl);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void LoadBk2Fields(ZipStateLoader bl, bool preload)
|
private void LoadBk2Fields(ZipStateLoader bl)
|
||||||
{
|
{
|
||||||
bl.GetLump(BinaryStateLump.Movieheader, abort: true, tr =>
|
|
||||||
{
|
|
||||||
string line;
|
|
||||||
while ((line = tr.ReadLine()) != null)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(line))
|
|
||||||
{
|
|
||||||
var pair = line.Split(new[] { ' ' }, 2, StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
|
|
||||||
if (pair.Length > 1)
|
|
||||||
{
|
|
||||||
if (!Header.ContainsKey(pair[0]))
|
|
||||||
{
|
|
||||||
Header.Add(pair[0], pair[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
bl.GetLump(BinaryStateLump.Input, abort: true, tr =>
|
bl.GetLump(BinaryStateLump.Input, abort: true, tr =>
|
||||||
{
|
{
|
||||||
IsCountingRerecords = false;
|
IsCountingRerecords = false;
|
||||||
|
@ -186,37 +140,6 @@ namespace BizHawk.Client.Common
|
||||||
IsCountingRerecords = true;
|
IsCountingRerecords = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (preload)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bl.GetLump(BinaryStateLump.Comments, abort: false, tr =>
|
|
||||||
{
|
|
||||||
string line;
|
|
||||||
while ((line = tr.ReadLine()) != null)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(line))
|
|
||||||
{
|
|
||||||
Comments.Add(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
bl.GetLump(BinaryStateLump.Subtitles, abort: false, tr =>
|
|
||||||
{
|
|
||||||
string line;
|
|
||||||
while ((line = tr.ReadLine()) != null)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(line))
|
|
||||||
{
|
|
||||||
Subtitles.AddFromString(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Subtitles.Sort();
|
|
||||||
});
|
|
||||||
|
|
||||||
bl.GetLump(BinaryStateLump.SyncSettings, abort: false, tr =>
|
bl.GetLump(BinaryStateLump.SyncSettings, abort: false, tr =>
|
||||||
{
|
{
|
||||||
string line;
|
string line;
|
||||||
|
|
|
@ -1,26 +1,15 @@
|
||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
namespace BizHawk.Client.Common
|
namespace BizHawk.Client.Common
|
||||||
{
|
{
|
||||||
public partial class Bk2Movie : IMovie
|
public partial class Bk2Movie : BasicMovieInfo, IMovie
|
||||||
{
|
{
|
||||||
private Bk2Controller _adapter;
|
private Bk2Controller _adapter;
|
||||||
|
|
||||||
public Bk2Movie(IMovieSession session, string filename)
|
public Bk2Movie(IMovieSession session, string filename) : base(filename)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(filename))
|
|
||||||
{
|
|
||||||
throw filename is null
|
|
||||||
? new ArgumentNullException(paramName: nameof(filename))
|
|
||||||
: new ArgumentException(message: "path cannot be blank", paramName: nameof(filename));
|
|
||||||
}
|
|
||||||
|
|
||||||
Session = session;
|
Session = session;
|
||||||
Filename = filename;
|
|
||||||
Header[HeaderKeys.MovieVersion] = "BizHawk v2.0.0";
|
Header[HeaderKeys.MovieVersion] = "BizHawk v2.0.0";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,20 +25,6 @@ namespace BizHawk.Client.Common
|
||||||
|
|
||||||
protected bool MakeBackup { get; set; } = true;
|
protected bool MakeBackup { get; set; } = true;
|
||||||
|
|
||||||
private string _filename;
|
|
||||||
|
|
||||||
public string Filename
|
|
||||||
{
|
|
||||||
get => _filename;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_filename = value;
|
|
||||||
Name = Path.GetFileName(Filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name { get; private set; }
|
|
||||||
|
|
||||||
public virtual string PreferredExtension => Extension;
|
public virtual string PreferredExtension => Extension;
|
||||||
|
|
||||||
public const string Extension = "bk2";
|
public const string Extension = "bk2";
|
||||||
|
@ -62,52 +37,9 @@ namespace BizHawk.Client.Common
|
||||||
return new Bk2LogEntryGenerator(Emulator?.SystemId ?? SystemID, source);
|
return new Bk2LogEntryGenerator(Emulator?.SystemId ?? SystemID, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int FrameCount => Log.Count;
|
public override int FrameCount => Log.Count;
|
||||||
public int InputLogLength => Log.Count;
|
public int InputLogLength => Log.Count;
|
||||||
|
|
||||||
public TimeSpan TimeLength
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
double dblSeconds;
|
|
||||||
|
|
||||||
if (Header.TryGetValue(HeaderKeys.CycleCount, out var numCyclesStr) && Header.TryGetValue(HeaderKeys.ClockRate, out var clockRateStr))
|
|
||||||
{
|
|
||||||
var numCycles = Convert.ToUInt64(numCyclesStr);
|
|
||||||
var clockRate = Convert.ToDouble(clockRateStr, CultureInfo.InvariantCulture);
|
|
||||||
dblSeconds = numCycles / clockRate;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var numFrames = (ulong)FrameCount;
|
|
||||||
dblSeconds = numFrames / FrameRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
var seconds = (int)(dblSeconds % 60);
|
|
||||||
var days = seconds / 86400;
|
|
||||||
var hours = seconds / 3600;
|
|
||||||
var minutes = (seconds / 60) % 60;
|
|
||||||
var milliseconds = (int)((dblSeconds - seconds) * 1000);
|
|
||||||
return new TimeSpan(days, hours, minutes, seconds, milliseconds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public double FrameRate
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (SystemID == VSystemID.Raw.Arcade && Header.TryGetValue(HeaderKeys.VsyncAttoseconds, out var vsyncAttoStr))
|
|
||||||
{
|
|
||||||
const decimal attosInSec = 1000000000000000000;
|
|
||||||
return (double)(attosInSec / Convert.ToUInt64(vsyncAttoStr));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return PlatformFrameRates.GetFrameRate(SystemID, IsPal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IStringLog GetLogEntries() => Log;
|
public IStringLog GetLogEntries() => Log;
|
||||||
|
|
||||||
public void CopyLog(IEnumerable<string> log)
|
public void CopyLog(IEnumerable<string> log)
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace BizHawk.Client.Common
|
||||||
|
{
|
||||||
|
public interface IBasicMovieInfo
|
||||||
|
{
|
||||||
|
// Filename of the movie, settable by the client
|
||||||
|
string Filename { get; set; }
|
||||||
|
|
||||||
|
string Name { get; }
|
||||||
|
|
||||||
|
string GameName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the total number of frames that count towards the completion time of the movie
|
||||||
|
/// </summary>
|
||||||
|
int FrameCount { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the actual length of time a movie lasts for. For subframe cores, this will be different then the above two options
|
||||||
|
/// </summary>
|
||||||
|
TimeSpan TimeLength { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the frame rate in frames per second for the movie's system.
|
||||||
|
/// </summary>
|
||||||
|
double FrameRate { get; }
|
||||||
|
|
||||||
|
SubtitleList Subtitles { get; }
|
||||||
|
|
||||||
|
IList<string> Comments { get; }
|
||||||
|
|
||||||
|
string SystemID { get; set; }
|
||||||
|
|
||||||
|
ulong Rerecords { get; set; }
|
||||||
|
|
||||||
|
/// <value>either CRC32, MD5, or SHA1, hex-encoded, unprefixed</value>
|
||||||
|
string Hash { get; set; }
|
||||||
|
|
||||||
|
string Author { get; set; }
|
||||||
|
string Core { get; set; }
|
||||||
|
string EmulatorVersion { get; set; }
|
||||||
|
string OriginalEmulatorVersion { get; set; }
|
||||||
|
string FirmwareHash { get; set; }
|
||||||
|
string BoardName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the header key value pairs stored in the movie file
|
||||||
|
/// </summary>
|
||||||
|
IDictionary<string, string> HeaderEntries { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tells the movie to load the contents of Filename
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Return whether or not the file was successfully loaded</returns>
|
||||||
|
bool Load();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
|
|
||||||
|
@ -30,7 +29,7 @@ namespace BizHawk.Client.Common
|
||||||
|
|
||||||
// TODO: message callback / event handler
|
// TODO: message callback / event handler
|
||||||
// TODO: consider other event handlers, switching modes?
|
// TODO: consider other event handlers, switching modes?
|
||||||
public interface IMovie
|
public interface IMovie : IBasicMovieInfo
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the current movie mode
|
/// Gets the current movie mode
|
||||||
|
@ -41,29 +40,12 @@ namespace BizHawk.Client.Common
|
||||||
|
|
||||||
bool Changes { get; }
|
bool Changes { get; }
|
||||||
|
|
||||||
string Name { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the total number of frames that count towards the completion time of the movie
|
|
||||||
/// </summary>
|
|
||||||
int FrameCount { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the actual length of the input log, should only be used by code that needs the input log length
|
/// Gets the actual length of the input log, should only be used by code that needs the input log length
|
||||||
/// specifically, not the frame count
|
/// specifically, not the frame count
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int InputLogLength { get; }
|
int InputLogLength { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the actual length of time a movie lasts for. For subframe cores, this will be different then the above two options
|
|
||||||
/// </summary>
|
|
||||||
TimeSpan TimeLength { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the frame rate in frames per second for the movie's system.
|
|
||||||
/// </summary>
|
|
||||||
double FrameRate { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the file extension for the current <see cref="IMovie"/> implementation
|
/// Gets the file extension for the current <see cref="IMovie"/> implementation
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -74,9 +56,6 @@ namespace BizHawk.Client.Common
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string SyncSettingsJson { get; set; }
|
string SyncSettingsJson { get; set; }
|
||||||
|
|
||||||
SubtitleList Subtitles { get; }
|
|
||||||
IList<string> Comments { get; }
|
|
||||||
|
|
||||||
// savestate anchor.
|
// savestate anchor.
|
||||||
string TextSavestate { get; set; }
|
string TextSavestate { get; set; }
|
||||||
byte[] BinarySavestate { get; set; }
|
byte[] BinarySavestate { get; set; }
|
||||||
|
@ -85,34 +64,11 @@ namespace BizHawk.Client.Common
|
||||||
// saveram anchor
|
// saveram anchor
|
||||||
byte[] SaveRam { get; set; }
|
byte[] SaveRam { get; set; }
|
||||||
|
|
||||||
ulong Rerecords { get; set; }
|
|
||||||
bool StartsFromSavestate { get; set; }
|
bool StartsFromSavestate { get; set; }
|
||||||
bool StartsFromSaveRam { get; set; }
|
bool StartsFromSaveRam { get; set; }
|
||||||
string GameName { get; set; }
|
|
||||||
string SystemID { get; set; }
|
|
||||||
|
|
||||||
/// <value>either CRC32, MD5, or SHA1, hex-encoded, unprefixed</value>
|
|
||||||
string Hash { get; set; }
|
|
||||||
|
|
||||||
string Author { get; set; }
|
|
||||||
string Core { get; set; }
|
|
||||||
string EmulatorVersion { get; set; }
|
|
||||||
string OriginalEmulatorVersion { get; set; }
|
|
||||||
string FirmwareHash { get; set; }
|
|
||||||
string BoardName { get; set; }
|
|
||||||
string LogKey { get; set; }
|
string LogKey { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Loads from the HawkFile the minimal amount of information needed to determine Header info and Movie length.
|
|
||||||
/// This method is intended to be more performant than a full load
|
|
||||||
/// </summary>
|
|
||||||
bool PreLoadHeaderAndLength();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the header key value pairs stored in the movie file
|
|
||||||
/// </summary>
|
|
||||||
IDictionary<string, string> HeaderEntries { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Forces the creation of a backup file of the current movie state
|
/// Forces the creation of a backup file of the current movie state
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -123,15 +79,6 @@ namespace BizHawk.Client.Common
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ILogEntryGenerator LogGeneratorInstance(IController source);
|
ILogEntryGenerator LogGeneratorInstance(IController source);
|
||||||
|
|
||||||
// Filename of the movie, settable by the client
|
|
||||||
string Filename { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tells the movie to load the contents of Filename
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Return whether or not the file was successfully loaded</returns>
|
|
||||||
bool Load(bool preload);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Instructs the movie to save the current contents to Filename
|
/// Instructs the movie to save the current contents to Filename
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -49,7 +49,7 @@ namespace BizHawk.Client.Common
|
||||||
|
|
||||||
protected override void ClearBeforeLoad()
|
protected override void ClearBeforeLoad()
|
||||||
{
|
{
|
||||||
ClearBk2Fields();
|
base.ClearBeforeLoad();
|
||||||
ClearTasprojExtras();
|
ClearTasprojExtras();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,21 +61,18 @@ namespace BizHawk.Client.Common
|
||||||
ChangeLog.Clear();
|
ChangeLog.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadFields(ZipStateLoader bl, bool preload)
|
protected override void LoadFields(ZipStateLoader bl)
|
||||||
{
|
{
|
||||||
LoadBk2Fields(bl, preload);
|
base.LoadFields(bl);
|
||||||
|
|
||||||
if (!preload)
|
if (MovieService.IsCurrentTasVersion(Header[HeaderKeys.MovieVersion]))
|
||||||
{
|
{
|
||||||
if (MovieService.IsCurrentTasVersion(Header[HeaderKeys.MovieVersion]))
|
LoadTasprojExtras(bl);
|
||||||
{
|
}
|
||||||
LoadTasprojExtras(bl);
|
else
|
||||||
}
|
{
|
||||||
else
|
Session.PopupMessage("The current .tasproj is not compatible with this version of BizHawk! .tasproj features failed to load.");
|
||||||
{
|
Markers.Add(0, StartsFromSavestate ? "Savestate" : "Power on");
|
||||||
Session.PopupMessage("The current .tasproj is not compatible with this version of BizHawk! .tasproj features failed to load.");
|
|
||||||
Markers.Add(0, StartsFromSavestate ? "Savestate" : "Power on");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
private readonly IEmulator _emulator;
|
private readonly IEmulator _emulator;
|
||||||
private readonly IMovieSession _movieSession;
|
private readonly IMovieSession _movieSession;
|
||||||
|
|
||||||
private List<IMovie> _movieList = new List<IMovie>();
|
private List<IBasicMovieInfo> _movieList = new();
|
||||||
private bool _sortReverse;
|
private bool _sortReverse;
|
||||||
private string _sortedCol;
|
private string _sortedCol;
|
||||||
|
|
||||||
|
@ -66,8 +66,10 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
private void PlayMovie_Load(object sender, EventArgs e)
|
private void PlayMovie_Load(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
_suppressCheckedChanged = true;
|
||||||
IncludeSubDirectories.Checked = _config.PlayMovieIncludeSubDir;
|
IncludeSubDirectories.Checked = _config.PlayMovieIncludeSubDir;
|
||||||
MatchHashCheckBox.Checked = _config.PlayMovieMatchHash;
|
MatchHashCheckBox.Checked = _config.PlayMovieMatchHash;
|
||||||
|
_suppressCheckedChanged = false;
|
||||||
ScanFiles();
|
ScanFiles();
|
||||||
PreHighlightMovie();
|
PreHighlightMovie();
|
||||||
TurboCheckbox.Checked = _config.TurboSeek;
|
TurboCheckbox.Checked = _config.TurboSeek;
|
||||||
|
@ -87,7 +89,9 @@ namespace BizHawk.Client.EmuHawk
|
||||||
var indices = MovieView.SelectedIndices;
|
var indices = MovieView.SelectedIndices;
|
||||||
if (indices.Count > 0) // Import file if necessary
|
if (indices.Count > 0) // Import file if necessary
|
||||||
{
|
{
|
||||||
_mainForm.StartNewMovie(_movieList[MovieView.SelectedIndices[0]], false);
|
var movie = _movieSession.Get(_movieList[MovieView.SelectedIndices[0]].Filename);
|
||||||
|
movie.Load();
|
||||||
|
_mainForm.StartNewMovie(movie, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +103,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var movie = PreLoadMovieFile(file, force);
|
var movie = LoadMovieInfo(file, force);
|
||||||
if (movie == null)
|
if (movie == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
|
@ -138,13 +142,13 @@ namespace BizHawk.Client.EmuHawk
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IMovie PreLoadMovieFile(HawkFile hf, bool force)
|
private IBasicMovieInfo LoadMovieInfo(HawkFile hf, bool force)
|
||||||
{
|
{
|
||||||
var movie = _movieSession.Get(hf.CanonicalFullPath);
|
IBasicMovieInfo movie = new BasicMovieInfo(hf.CanonicalFullPath);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
movie.PreLoadHeaderAndLength();
|
movie.Load();
|
||||||
|
|
||||||
// Don't do this from browse
|
// Don't do this from browse
|
||||||
if (movie.Hash == _game.Hash
|
if (movie.Hash == _game.Hash
|
||||||
|
@ -338,8 +342,8 @@ namespace BizHawk.Client.EmuHawk
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly RigidMultiPredicateSort<IMovie> ColumnSorts
|
private static readonly RigidMultiPredicateSort<IBasicMovieInfo> ColumnSorts
|
||||||
= new RigidMultiPredicateSort<IMovie>(new Dictionary<string, Func<IMovie, IComparable>>
|
= new(new Dictionary<string, Func<IBasicMovieInfo, IComparable>>
|
||||||
{
|
{
|
||||||
["File"] = x => Path.GetFileName(x.Filename),
|
["File"] = x => Path.GetFileName(x.Filename),
|
||||||
["SysID"] = x => x.SystemID,
|
["SysID"] = x => x.SystemID,
|
||||||
|
@ -499,7 +503,11 @@ namespace BizHawk.Client.EmuHawk
|
||||||
var indices = MovieView.SelectedIndices;
|
var indices = MovieView.SelectedIndices;
|
||||||
if (indices.Count > 0)
|
if (indices.Count > 0)
|
||||||
{
|
{
|
||||||
var form = new EditCommentsForm(_movieList[MovieView.SelectedIndices[0]], _movieSession.ReadOnly);
|
// TODO this will allocate unnecessary memory when this movie is a TasMovie due to TasStateManager
|
||||||
|
var movie = _movieSession.Get(_movieList[MovieView.SelectedIndices[0]].Filename);
|
||||||
|
movie.Load();
|
||||||
|
// TODO movie should be disposed if movie is ITasMovie
|
||||||
|
var form = new EditCommentsForm(movie, _movieSession.ReadOnly);
|
||||||
form.Show();
|
form.Show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -509,7 +517,11 @@ namespace BizHawk.Client.EmuHawk
|
||||||
var indices = MovieView.SelectedIndices;
|
var indices = MovieView.SelectedIndices;
|
||||||
if (indices.Count > 0)
|
if (indices.Count > 0)
|
||||||
{
|
{
|
||||||
using EditSubtitlesForm s = new(DialogController, _movieList[MovieView.SelectedIndices[0]], _config.PathEntries, readOnly: true);
|
// TODO this will allocate unnecessary memory when this movie is a TasMovie due to TasStateManager
|
||||||
|
var movie = _movieSession.Get(_movieList[MovieView.SelectedIndices[0]].Filename);
|
||||||
|
movie.Load();
|
||||||
|
// TODO movie should be disposed if movie is ITasMovie
|
||||||
|
using EditSubtitlesForm s = new(DialogController, movie, _config.PathEntries, readOnly: true);
|
||||||
s.Show();
|
s.Show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -543,6 +555,8 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
private void IncludeSubDirectories_CheckedChanged(object sender, EventArgs e)
|
private void IncludeSubDirectories_CheckedChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
if (_suppressCheckedChanged) return;
|
||||||
|
|
||||||
_config.PlayMovieIncludeSubDir = IncludeSubDirectories.Checked;
|
_config.PlayMovieIncludeSubDir = IncludeSubDirectories.Checked;
|
||||||
ScanFiles();
|
ScanFiles();
|
||||||
PreHighlightMovie();
|
PreHighlightMovie();
|
||||||
|
@ -550,6 +564,8 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
private void MatchHashCheckBox_CheckedChanged(object sender, EventArgs e)
|
private void MatchHashCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
if (_suppressCheckedChanged) return;
|
||||||
|
|
||||||
_config.PlayMovieMatchHash = MatchHashCheckBox.Checked;
|
_config.PlayMovieMatchHash = MatchHashCheckBox.Checked;
|
||||||
ScanFiles();
|
ScanFiles();
|
||||||
PreHighlightMovie();
|
PreHighlightMovie();
|
||||||
|
@ -578,6 +594,8 @@ namespace BizHawk.Client.EmuHawk
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool _programmaticallyChangingStopFrameCheckbox;
|
private bool _programmaticallyChangingStopFrameCheckbox;
|
||||||
|
private bool _suppressCheckedChanged;
|
||||||
|
|
||||||
private void StopOnFrameCheckbox_CheckedChanged(object sender, EventArgs e)
|
private void StopOnFrameCheckbox_CheckedChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (!_programmaticallyChangingStopFrameCheckbox)
|
if (!_programmaticallyChangingStopFrameCheckbox)
|
||||||
|
|
|
@ -7,10 +7,10 @@ namespace BizHawk.Client.EmuHawk
|
||||||
{
|
{
|
||||||
public partial class MovieHeaderEditor : Form
|
public partial class MovieHeaderEditor : Form
|
||||||
{
|
{
|
||||||
private readonly IMovie _movie;
|
private readonly IBasicMovieInfo _movie;
|
||||||
private readonly Config _config;
|
private readonly Config _config;
|
||||||
|
|
||||||
public MovieHeaderEditor(IMovie movie, Config config)
|
public MovieHeaderEditor(IBasicMovieInfo movie, Config config)
|
||||||
{
|
{
|
||||||
_movie = movie;
|
_movie = movie;
|
||||||
_config = config;
|
_config = config;
|
||||||
|
|
Loading…
Reference in New Issue