Finish up Movie Header refactor

This commit is contained in:
adelikat 2013-11-30 02:20:34 +00:00
parent ec11efb784
commit 4cb01d8ed4
13 changed files with 464 additions and 473 deletions

View File

@ -132,6 +132,7 @@
<Compile Include="movie\MovieMnemonics.cs" /> <Compile Include="movie\MovieMnemonics.cs" />
<Compile Include="movie\MovieSession.cs" /> <Compile Include="movie\MovieSession.cs" />
<Compile Include="movie\MultitrackRecording.cs" /> <Compile Include="movie\MultitrackRecording.cs" />
<Compile Include="movie\PlatformFrameRates.cs" />
<Compile Include="movie\Subtitle.cs" /> <Compile Include="movie\Subtitle.cs" />
<Compile Include="movie\SubtitleList.cs" /> <Compile Include="movie\SubtitleList.cs" />
<Compile Include="NESGameGenieEncoderDecoder.cs" /> <Compile Include="NESGameGenieEncoderDecoder.cs" />

View File

@ -1,8 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection;
using System.Text;
namespace BizHawk.Client.Common namespace BizHawk.Client.Common
{ {
@ -24,36 +21,30 @@ namespace BizHawk.Client.Common
public const string PAL = "PAL"; public const string PAL = "PAL";
public const string BOARDNAME = "BoardName"; public const string BOARDNAME = "BoardName";
//Gameboy Settings that affect sync // Gameboy Settings that affect sync
public const string GB_FORCEDMG = "Force_DMG_Mode"; public const string GB_FORCEDMG = "Force_DMG_Mode";
public const string GB_GBA_IN_CGB = "GBA_In_CGB"; public const string GB_GBA_IN_CGB = "GBA_In_CGB";
public const string SGB = "SGB"; //a snes movie will set this to indicate that it's actually SGB public const string SGB = "SGB"; // A snes movie will set this to indicate that it's actually SGB
//BIO skipping setting (affects sync) // BIO skipping setting (affects sync)
public const string SKIPBIOS = "Skip_Bios"; public const string SKIPBIOS = "Skip_Bios";
//Plugin Settings // Plugin Settings
public const string VIDEOPLUGIN = "VideoPlugin"; public const string VIDEOPLUGIN = "VideoPlugin";
//Board properties // Board properties
public const string BOARDPROPERTIES = "BoardProperty"; public const string BOARDPROPERTIES = "BoardProperty";
public static string NewGuid public static string NewGuid
{ {
get get { return Guid.NewGuid().ToString(); }
{
return Guid.NewGuid().ToString();
}
} }
public static bool Contains(string val) public static bool Contains(string val)
{ {
var keys = new List<string>(); var keys = typeof(HeaderKeys).GetFields()
foreach (FieldInfo field in typeof(HeaderKeys).GetFields()) .Select(field => field.GetValue(null).ToString())
{ .ToList();
keys.Add(field.GetValue(null).ToString());
}
return keys.Contains(val); return keys.Contains(val);
} }
} }

View File

@ -16,9 +16,8 @@ namespace BizHawk.Client.Common
bool IsFinished { get; } bool IsFinished { get; }
bool Changes { get; } bool Changes { get; }
bool Loaded { get; } bool Loaded { get; }
bool StartsFromSavestate { get; }
int Rerecords { get; set; } ulong Rerecords { get; set; }
#endregion #endregion
@ -35,14 +34,13 @@ namespace BizHawk.Client.Common
/// <summary> /// <summary>
/// Tells the movie to start recording from the beginning. /// Tells the movie to start recording from the beginning.
/// This will clear sram, and the movie log /// This will clear SRAM, and the movie log
/// </summary> /// </summary>
/// <param name="truncate"></param>
void StartNewRecording(); void StartNewRecording();
/// <summary> /// <summary>
/// Tells the movie to start playback from the beginning /// Tells the movie to start playback from the beginning
/// This will clear sram /// This will clear SRAM
/// </summary> /// </summary>
void StartNewPlayback(); void StartNewPlayback();
@ -50,18 +48,18 @@ namespace BizHawk.Client.Common
/// Sets the movie to inactive (note that it will still be in memory) /// Sets the movie to inactive (note that it will still be in memory)
/// The saveChanges flag will tell the movie to save its contents to disk /// The saveChanges flag will tell the movie to save its contents to disk
/// </summary> /// </summary>
/// <param name="saveChanges"></param> /// <param name="saveChanges">if true, will save to disk</param>
void Stop(bool saveChanges = true); void Stop(bool saveChanges = true);
/// <summary> /// <summary>
/// Switches to record mode /// Switches to record mode
/// Does not change the movie log or clear sram /// Does not change the movie log or clear SRAM
/// </summary> /// </summary>
void SwitchToRecord(); void SwitchToRecord();
/// <summary> /// <summary>
/// Switches to playback mode /// Switches to playback mode
/// Does not change the movie log or clear sram /// Does not change the movie log or clear SRAM
/// </summary> /// </summary>
void SwitchToPlay(); void SwitchToPlay();
@ -93,7 +91,6 @@ namespace BizHawk.Client.Common
IMovieHeader Header { get; } // Expose IMovieHEader instead IMovieHeader Header { get; } // Expose IMovieHEader instead
MovieLog LogDump { get; } // Don't expose this!!! MovieLog LogDump { get; } // Don't expose this!!!
//SubtitleList Subtitles { get; } // Don't expose this!!!
#endregion #endregion
} }

View File

@ -1,7 +1,4 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Client.Common namespace BizHawk.Client.Common
{ {
@ -9,27 +6,20 @@ namespace BizHawk.Client.Common
{ {
SubtitleList Subtitles { get; } SubtitleList Subtitles { get; }
Dictionary<string, string> BoardProperties { get; } Dictionary<string, string> BoardProperties { get; }
List<string> Comments { get; }
#region Dubious, should reconsider ulong Rerecords { get; set; }
bool StartsFromSavestate { get; set; }
List<string> Comments { get; } // Consider making this a readonly list, or custom object, to control editing api
Dictionary<string, string> Parameters { get; } //rename to Parameters, make a custom object, that controls what params are valid
/// <summary> /// <summary>
/// Adds the key value pair to header params. If key already exists, value will be updated /// Receives a line and attempts to add as a header
/// </summary> /// </summary>
/// <param name="key"></param> /// <param name="line">
/// <param name="value"></param> /// The line of text loaded from a movie file.
void AddHeaderLine(string key, string value); // delete in favor of AddHeaderFromLine /// </param>
/// <returns>
//TODO: replace Movie Preload & Load functions with this /// returns false if not a useable header line
/// <summary> /// </returns>
/// Receives a line and attempts to add as a header, returns false if not a useable header line bool ParseLineFromFile(string line);
/// </summary>
/// <param name="line"></param>
/// <returns></returns>
bool AddHeaderFromLine(string line); // rename to AddFromString, should be a property of HeaderParams
#endregion
} }
} }

View File

@ -1,9 +1,10 @@
using System; using System;
using System.IO; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO;
using BizHawk.Common; using BizHawk.Common;
using BizHawk.Emulation.Common; using BizHawk.Emulation.Common;
using System.Collections.Generic;
namespace BizHawk.Client.Common namespace BizHawk.Client.Common
{ {
@ -24,7 +25,8 @@ namespace BizHawk.Client.Common
Header = new MovieHeader(); Header = new MovieHeader();
Filename = String.Empty; Filename = String.Empty;
_preloadFramecount = 0; _preloadFramecount = 0;
StartsFromSavestate = startsFromSavestate; Header.StartsFromSavestate = startsFromSavestate;
IsCountingRerecords = true; IsCountingRerecords = true;
_mode = Moviemode.Inactive; _mode = Moviemode.Inactive;
IsText = true; IsText = true;
@ -43,24 +45,20 @@ namespace BizHawk.Client.Common
public bool Loaded { get; private set; } public bool Loaded { get; private set; }
public bool IsText { get; private set; } public bool IsText { get; private set; }
public int Rerecords public ulong Rerecords
{ {
get { return _rerecords; } get { return Header.Rerecords; }
set set { Header.Rerecords = value; }
{
_rerecords = value;
Header.Parameters[HeaderKeys.RERECORDS] = Rerecords.ToString();
}
} }
public string SysID public string SysID
{ {
get { return Header.Parameters[HeaderKeys.PLATFORM]; } get { return Header[HeaderKeys.PLATFORM]; }
} }
public string GameName public string GameName
{ {
get { return Header.Parameters[HeaderKeys.GAMENAME]; } get { return Header[HeaderKeys.GAMENAME]; }
} }
public int RawFrames public int RawFrames
@ -90,26 +88,13 @@ namespace BizHawk.Client.Common
} }
} }
public bool StartsFromSavestate
{
get { return _startsfromsavestate; }
private set
{
_startsfromsavestate = value;
if (value)
{
Header.AddHeaderLine(HeaderKeys.STARTSFROMSAVESTATE, "1");
}
else
{
Header.Parameters.Remove(HeaderKeys.STARTSFROMSAVESTATE);
}
}
}
public bool StateCapturing public bool StateCapturing
{ {
get { return _statecapturing; } get
{
return _statecapturing;
}
set set
{ {
_statecapturing = value; _statecapturing = value;
@ -157,6 +142,7 @@ namespace BizHawk.Client.Common
SaveAs(); SaveAs();
MakeBackup = false; MakeBackup = false;
} }
_log.Clear(); _log.Clear();
} }
@ -186,6 +172,7 @@ namespace BizHawk.Client.Common
Save(); Save();
} }
} }
_changes = false; _changes = false;
_mode = Moviemode.Inactive; _mode = Moviemode.Inactive;
} }
@ -211,9 +198,13 @@ namespace BizHawk.Client.Common
{ {
return; return;
} }
var directory_info = new FileInfo(Filename).Directory; var directory_info = new FileInfo(Filename).Directory;
if (directory_info != null) Directory.CreateDirectory(directory_info.FullName); if (directory_info != null)
{
Directory.CreateDirectory(directory_info.FullName);
}
if (IsText) if (IsText)
{ {
WriteText(Filename); WriteText(Filename);
@ -242,61 +233,64 @@ namespace BizHawk.Client.Common
return; return;
} }
string BackupName = Filename; var backupName = Filename;
BackupName = BackupName.Insert(Filename.LastIndexOf("."), String.Format(".{0:yyyy-MM-dd HH.mm.ss}", DateTime.Now)); backupName = backupName.Insert(Filename.LastIndexOf("."), String.Format(".{0:yyyy-MM-dd HH.mm.ss}", DateTime.Now));
BackupName = Path.Combine(Global.Config.PathEntries["Global", "Movie backups"].Path, Path.GetFileName(BackupName) ?? String.Empty); backupName = Path.Combine(Global.Config.PathEntries["Global", "Movie backups"].Path, Path.GetFileName(backupName) ?? String.Empty);
var directory_info = new FileInfo(BackupName).Directory; var directory_info = new FileInfo(backupName).Directory;
if (directory_info != null) Directory.CreateDirectory(directory_info.FullName); if (directory_info != null)
{
Directory.CreateDirectory(directory_info.FullName);
}
if (IsText) if (IsText)
{ {
WriteText(BackupName); WriteText(backupName);
} }
else else
{ {
WriteBinary(BackupName); WriteBinary(backupName);
} }
} }
/// <summary> /// <summary>
/// Load Header information only for displaying file information in dialogs such as play movie /// Load Header information only for displaying file information in dialogs such as play movie
/// </summary> /// </summary>
/// <returns></returns>
public bool PreLoadText(HawkFile hawkFile) public bool PreLoadText(HawkFile hawkFile)
{ {
Loaded = false; Loaded = false;
var file = new FileInfo(hawkFile.CanonicalFullPath); var file = new FileInfo(hawkFile.CanonicalFullPath);
if (file.Exists == false) if (file.Exists == false)
{
return false; return false;
}
else else
{ {
Header.Clear(); Header.Clear();
_log.Clear(); _log.Clear();
} }
long origStreamPosn = hawkFile.GetStream().Position; var origStreamPosn = hawkFile.GetStream().Position;
hawkFile.GetStream().Position = 0; //Reset to start hawkFile.GetStream().Position = 0; // Reset to start
StreamReader sr = new StreamReader(hawkFile.GetStream()); //No using block because we're sharing the stream and need to give it back undisposed. var sr = new StreamReader(hawkFile.GetStream());
if(!sr.EndOfStream)
// No using block because we're sharing the stream and need to give it back undisposed.
if (!sr.EndOfStream)
{ {
string str; string line;
while ((str = sr.ReadLine()) != null) while ((line = sr.ReadLine()) != null)
{ {
if (String.IsNullOrWhiteSpace(str) || Header.AddHeaderFromLine(str)) if (String.IsNullOrWhiteSpace(line) || Header.ParseLineFromFile(line))
{ {
continue; continue;
} }
if (str.StartsWith("subtitle") || str.StartsWith("sub")) if (line.StartsWith("|"))
{ {
Header.Subtitles.AddFromString(str); var frames = sr.ReadToEnd();
} var length = line.Length;
else if (str[0] == '|')
{
string frames = sr.ReadToEnd();
int length = str.Length;
// Account for line breaks of either size. // Account for line breaks of either size.
if (frames.IndexOf("\r\n") != -1) if (frames.IndexOf("\r\n") != -1)
{ {
@ -304,16 +298,16 @@ namespace BizHawk.Client.Common
} }
length++; length++;
// Count the remaining frames and the current one. _preloadFramecount = (frames.Length / length) + 1; // Count the remaining frames and the current one.
_preloadFramecount = (frames.Length/length) + 1;
break; break;
} }
else else
{ {
Header.Comments.Add(str); Header.Comments.Add(line);
} }
} }
} }
hawkFile.GetStream().Position = origStreamPosn; hawkFile.GetStream().Position = origStreamPosn;
return true; return true;
@ -433,19 +427,19 @@ namespace BizHawk.Client.Common
public void CommitFrame(int frameNum, IController source) public void CommitFrame(int frameNum, IController source)
{ {
//Note: Truncation here instead of loadstate will make VBA style loadstates // Note: Truncation here instead of loadstate will make VBA style loadstates
//(Where an entire movie is loaded then truncated on the next frame // (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" // this allows users to restore a movie with any savestate from that "timeline"
if (Global.Config.VBAStyleMovieLoadState) if (Global.Config.VBAStyleMovieLoadState)
{ {
if (Global.Emulator.Frame < _log.Length) if (Global.Emulator.Frame < _log.Length)
{ {
_log.TruncateMovie(Global.Emulator.Frame); _log.TruncateMovie(Global.Emulator.Frame);
_log .TruncateStates(Global.Emulator.Frame);
} }
} }
_changes = true; _changes = true;
MnemonicsGenerator mg = new MnemonicsGenerator(); var mg = new MnemonicsGenerator();
mg.SetSource(source); mg.SetSource(source);
_log.SetFrameAt(frameNum, mg.GetControllersAsMnemonic()); _log.SetFrameAt(frameNum, mg.GetControllersAsMnemonic());
} }
@ -453,11 +447,11 @@ namespace BizHawk.Client.Common
public void DumpLogIntoSavestateText(TextWriter writer) public void DumpLogIntoSavestateText(TextWriter writer)
{ {
writer.WriteLine("[Input]"); writer.WriteLine("[Input]");
writer.WriteLine(HeaderKeys.GUID + " " + Header.Parameters[HeaderKeys.GUID]); writer.WriteLine(HeaderKeys.GUID + " " + Header[HeaderKeys.GUID]);
for (int x = 0; x < _log.Length; x++) for (var i = 0; i < _log.Length; i++)
{ {
writer.WriteLine(_log[x]); writer.WriteLine(_log[i]);
} }
writer.WriteLine("[/Input]"); writer.WriteLine("[/Input]");
@ -466,7 +460,8 @@ namespace BizHawk.Client.Common
public void LoadLogFromSavestateText(TextReader reader, bool isMultitracking) public void LoadLogFromSavestateText(TextReader reader, bool isMultitracking)
{ {
int? stateFrame = null; int? stateFrame = null;
//We are in record mode so replace the movie log with the one from the savestate
// We are in record mode so replace the movie log with the one from the savestate
if (!isMultitracking) if (!isMultitracking)
{ {
if (Global.Config.EnableBackupMovies && MakeBackup && _log.Length > 0) if (Global.Config.EnableBackupMovies && MakeBackup && _log.Length > 0)
@ -474,26 +469,39 @@ namespace BizHawk.Client.Common
SaveAs(); SaveAs();
MakeBackup = false; MakeBackup = false;
} }
_log.Clear(); _log.Clear();
while (true) while (true)
{ {
string line = reader.ReadLine(); var line = reader.ReadLine();
if (line == null) break; if (line == null)
else if (line.Trim() == "") continue;
else if (line == "[Input]") continue;
else if (line == "[/Input]") break;
else if (line.Contains("Frame 0x")) //NES stores frame count in hex, yay
{ {
string[] strs = line.Split('x'); break;
}
else if (line.Trim() == String.Empty)
{
continue;
}
else if (line == "[Input]")
{
continue;
}
else if (line == "[/Input]")
{
break;
}
else if (line.Contains("Frame 0x")) // NES stores frame count in hex, yay
{
var strs = line.Split('x');
try try
{ {
stateFrame = int.Parse(strs[1], NumberStyles.HexNumber); stateFrame = int.Parse(strs[1], NumberStyles.HexNumber);
} }
catch { } //TODO: message? catch { } // TODO: message?
} }
else if (line.Contains("Frame ")) else if (line.Contains("Frame "))
{ {
string[] strs = line.Split(' '); var strs = line.Split(' ');
try try
{ {
stateFrame = int.Parse(strs[1]); stateFrame = int.Parse(strs[1]);
@ -511,39 +519,55 @@ namespace BizHawk.Client.Common
int i = 0; int i = 0;
while (true) while (true)
{ {
string line = reader.ReadLine(); var line = reader.ReadLine();
if (line == null) break; if (line == null)
else if (line.Trim() == "") continue;
else if (line == "[Input]") continue;
else if (line == "[/Input]") break;
else if (line.Contains("Frame 0x")) //NES stores frame count in hex, yay
{ {
string[] strs = line.Split('x'); break;
}
else if (line.Trim() == string.Empty)
{
continue;
}
else if (line == "[Input]")
{
continue;
}
else if (line == "[/Input]")
{
break;
}
else if (line.Contains("Frame 0x")) // NES stores frame count in hex, yay
{
var strs = line.Split('x');
try try
{ {
stateFrame = int.Parse(strs[1], NumberStyles.HexNumber); stateFrame = int.Parse(strs[1], NumberStyles.HexNumber);
} }
catch { } //TODO: message? catch { } // TODO: message?
} }
else if (line.Contains("Frame ")) else if (line.Contains("Frame "))
{ {
string[] strs = line.Split(' '); var strs = line.Split(' ');
try try
{ {
stateFrame = int.Parse(strs[1]); stateFrame = int.Parse(strs[1]);
} }
catch { } //TODO: message? catch { } // TODO: message?
} }
if (line[0] == '|') else if (line.StartsWith("|"))
{ {
_log.SetFrameAt(i, line); _log.SetFrameAt(i, line);
i++; i++;
} }
} }
} }
if (stateFrame == null) if (stateFrame == null)
{
throw new Exception("Couldn't find stateFrame"); throw new Exception("Couldn't find stateFrame");
int stateFramei = (int)stateFrame; }
var stateFramei = (int)stateFrame;
if (stateFramei > 0 && stateFramei < _log.Length) if (stateFramei > 0 && stateFramei < _log.Length)
{ {
@ -553,32 +577,28 @@ namespace BizHawk.Client.Common
_log.TruncateMovie(stateFramei); _log.TruncateMovie(stateFramei);
} }
} }
else if (stateFramei > _log.Length) //Post movie savestate else if (stateFramei > _log.Length) // Post movie savestate
{ {
if (!Global.Config.VBAStyleMovieLoadState) if (!Global.Config.VBAStyleMovieLoadState)
{ {
_log.TruncateStates(_log.Length); _log.TruncateStates(_log.Length);
_log.TruncateMovie(_log.Length); _log.TruncateMovie(_log.Length);
} }
_mode = Moviemode.Finished; _mode = Moviemode.Finished;
} }
if (IsCountingRerecords) if (IsCountingRerecords)
{
Rerecords++; Rerecords++;
}
} }
public string GetTime(bool preLoad) public string GetTime(bool preLoad)
{ {
string time = String.Empty; var time = String.Empty;
double seconds; double seconds = GetSeconds(preLoad ? _preloadFramecount : _log.Length);
if (preLoad)
{
seconds = GetSeconds(_preloadFramecount);
}
else
{
seconds = GetSeconds(_log.Length);
}
int hours = ((int)seconds) / 3600; int hours = ((int)seconds) / 3600;
int minutes = (((int)seconds) / 60) % 60; int minutes = (((int)seconds) / 60) % 60;
@ -590,7 +610,7 @@ namespace BizHawk.Client.Common
time += MakeDigits(minutes) + ":"; time += MakeDigits(minutes) + ":";
if (sec < 10) //Kludge if (sec < 10) // Kludge
{ {
time += "0"; time += "0";
} }
@ -602,25 +622,25 @@ namespace BizHawk.Client.Common
public LoadStateResult CheckTimeLines(TextReader reader, bool onlyGuid, bool ignoreGuidMismatch, out string errorMessage) public LoadStateResult CheckTimeLines(TextReader reader, bool onlyGuid, bool ignoreGuidMismatch, out string errorMessage)
{ {
//This function will compare the movie data to the savestate movie data to see if they match // This function will compare the movie data to the savestate movie data to see if they match
errorMessage = String.Empty; errorMessage = String.Empty;
var log = new MovieLog(); var log = new MovieLog();
int stateFrame = 0; int stateFrame = 0;
while (true) while (true)
{ {
string line = reader.ReadLine(); var line = reader.ReadLine();
if (line == null) if (line == null)
{ {
return LoadStateResult.EmptyLog; return LoadStateResult.EmptyLog;
} }
else if (line.Trim() == "") else if (line.Trim() == string.Empty)
{ {
continue; continue;
} }
else if (line.Contains("GUID")) else if (line.Contains("GUID"))
{ {
string guid = ParseHeader(line, HeaderKeys.GUID); var guid = line.Split(new[] { ' ' }, 2)[1];
if (Header.Parameters[HeaderKeys.GUID] != guid) if (Header[HeaderKeys.GUID] != guid)
{ {
if (!ignoreGuidMismatch) if (!ignoreGuidMismatch)
{ {
@ -628,9 +648,9 @@ namespace BizHawk.Client.Common
} }
} }
} }
else if (line.Contains("Frame 0x")) //NES stores frame count in hex, yay else if (line.Contains("Frame 0x")) // NES stores frame count in hex, yay
{ {
string[] strs = line.Split('x'); var strs = line.Split('x');
try try
{ {
stateFrame = int.Parse(strs[1], NumberStyles.HexNumber); stateFrame = int.Parse(strs[1], NumberStyles.HexNumber);
@ -643,7 +663,7 @@ namespace BizHawk.Client.Common
} }
else if (line.Contains("Frame ")) else if (line.Contains("Frame "))
{ {
string[] strs = line.Split(' '); var strs = line.Split(' ');
try try
{ {
stateFrame = int.Parse(strs[1]); stateFrame = int.Parse(strs[1]);
@ -654,8 +674,14 @@ namespace BizHawk.Client.Common
return LoadStateResult.MissingFrameNumber; return LoadStateResult.MissingFrameNumber;
} }
} }
else if (line == "[Input]") continue; else if (line == "[Input]")
else if (line == "[/Input]") break; {
continue;
}
else if (line == "[/Input]")
{
break;
}
else if (line[0] == '|') else if (line[0] == '|')
{ {
log.AppendFrame(line); log.AppendFrame(line);
@ -669,8 +695,9 @@ namespace BizHawk.Client.Common
if (stateFrame == 0) if (stateFrame == 0)
{ {
stateFrame = log.Length; //In case the frame count failed to parse, revert to using the entire state input log stateFrame = log.Length; // In case the frame count failed to parse, revert to using the entire state input log
} }
if (_log.Length < stateFrame) if (_log.Length < stateFrame)
{ {
if (IsFinished) if (IsFinished)
@ -680,24 +707,25 @@ namespace BizHawk.Client.Common
else else
{ {
errorMessage = "The savestate is from frame " errorMessage = "The savestate is from frame "
+ log.Length.ToString() + log.Length
+ " which is greater than the current movie length of " + " which is greater than the current movie length of "
+ _log.Length.ToString(); + _log.Length;
return LoadStateResult.FutureEventError; return LoadStateResult.FutureEventError;
} }
} }
for (int i = 0; i < stateFrame; i++)
for (var i = 0; i < stateFrame; i++)
{ {
if (_log[i] != log[i]) if (_log[i] != log[i])
{ {
errorMessage = "The savestate input does not match the movie input at frame " errorMessage = "The savestate input does not match the movie input at frame "
+ (i + 1).ToString() + (i + 1)
+ "."; + ".";
return LoadStateResult.TimeLineError; return LoadStateResult.TimeLineError;
} }
} }
if (stateFrame > log.Length) //stateFrame is greater than state input log, so movie finished mode if (stateFrame > log.Length) // stateFrame is greater than state input log, so movie finished mode
{ {
if (_mode == Moviemode.Play || _mode == Moviemode.Finished) if (_mode == Moviemode.Play || _mode == Moviemode.Finished)
{ {
@ -706,7 +734,7 @@ namespace BizHawk.Client.Common
} }
else else
{ {
return LoadStateResult.NotInRecording; //TODO: For now throw an error if recording, ideally what should happen is that the state gets loaded, and the movie set to movie finished, the movie at its current state is preserved and the state is loaded just fine. This should probably also only happen if checktimelines passes return LoadStateResult.NotInRecording; // TODO: For now throw an error if recording, ideally what should happen is that the state gets loaded, and the movie set to movie finished, the movie at its current state is preserved and the state is loaded just fine. This should probably also only happen if checktimelines passes
} }
} }
else if (_mode == Moviemode.Finished) else if (_mode == Moviemode.Finished)
@ -725,9 +753,7 @@ namespace BizHawk.Client.Common
private enum Moviemode { Inactive, Play, Record, Finished }; private enum Moviemode { Inactive, Play, Record, Finished };
private Moviemode _mode = Moviemode.Inactive; private Moviemode _mode = Moviemode.Inactive;
private bool _statecapturing; private bool _statecapturing;
private bool _startsfromsavestate; private int _preloadFramecount; // Not a a reliable number, used for preloading (when no log has yet been loaded), this is only for quick stat compilation for dialogs such as play movie
private int _preloadFramecount; //Not a a reliable number, used for preloading (when no log has yet been loaded), this is only for quick stat compilation for dialogs such as play movie
private int _rerecords;
private bool _changes; private bool _changes;
private int? _loopOffset; private int? _loopOffset;
@ -738,13 +764,17 @@ namespace BizHawk.Client.Common
private void WriteText(string fn) private void WriteText(string fn)
{ {
using (var fs = new FileStream(fn, FileMode.Create, FileAccess.Write, FileShare.Read)) using (var fs = new FileStream(fn, FileMode.Create, FileAccess.Write, FileShare.Read))
{
WriteText(fs); WriteText(fs);
}
} }
private void WriteBinary(string fn) private void WriteBinary(string fn)
{ {
using (var fs = new FileStream(fn, FileMode.Create, FileAccess.Write, FileShare.Read)) using (var fs = new FileStream(fn, FileMode.Create, FileAccess.Write, FileShare.Read))
{
WriteBinary(fs); WriteBinary(fs);
}
} }
private void WriteText(Stream stream) private void WriteText(Stream stream)
@ -756,11 +786,9 @@ namespace BizHawk.Client.Common
// TODO: clean this up // TODO: clean this up
if (_loopOffset.HasValue) if (_loopOffset.HasValue)
{ {
sw.WriteLine("LoopOffset " + _loopOffset.ToString()); sw.WriteLine("LoopOffset " + _loopOffset);
} }
sw.Write(Header.Subtitles.ToString());
for (int i = 0; i < _log.Length; i++) for (int i = 0; i < _log.Length; i++)
{ {
sw.WriteLine(_log[i]); sw.WriteLine(_log[i]);
@ -787,69 +815,45 @@ namespace BizHawk.Client.Common
_log.Clear(); _log.Clear();
} }
using (StreamReader sr = file.OpenText()) using (var sr = file.OpenText())
{ {
string str; string line;
while ((str = sr.ReadLine()) != null) while ((line = sr.ReadLine()) != null)
{ {
if (str == "") if (line == String.Empty)
{ {
continue; continue;
} }
if (str.Contains(HeaderKeys.RERECORDS)) if (line.Contains("LoopOffset"))
{ {
string rerecordStr = ParseHeader(str, HeaderKeys.RERECORDS);
try try
{ {
Rerecords = int.Parse(rerecordStr); _loopOffset = int.Parse(line.Split(new[] { ' ' }, 2)[1]);
} }
catch catch (Exception)
{ {
Rerecords = 0; continue;
} }
} }
else if (str.Contains(HeaderKeys.STARTSFROMSAVESTATE)) else if (Header.ParseLineFromFile(line))
{
str = ParseHeader(str, HeaderKeys.STARTSFROMSAVESTATE);
if (str == "1")
StartsFromSavestate = true;
}
else if (str.Contains("LoopOffset"))
{
str = ParseHeader(str, "LoopOffset");
try
{
_loopOffset = int.Parse(str);
}
catch
{
//Do nothing
}
}
else if (str.StartsWith("subtitle") || str.StartsWith("sub"))
{
Header.Subtitles.AddFromString(str);
}
else if (Header.AddHeaderFromLine(str))
{ {
continue; continue;
} }
else if (str[0] == '|') else if (line.StartsWith("|"))
{ {
_log.AppendFrame(str); _log.AppendFrame(line);
} }
else else
{ {
Header.Comments.Add(str); Header.Comments.Add(line);
} }
} }
} }
Loaded = true; Loaded = true;
return true; return true;
} }
private bool LoadBinary() private bool LoadBinary()
@ -857,16 +861,9 @@ namespace BizHawk.Client.Common
return true; return true;
} }
private string MakeDigits(int num) private static string MakeDigits(int num)
{ {
if (num < 10) return num < 10 ? "0" + num : num.ToString();
{
return "0" + num.ToString();
}
else
{
return num.ToString();
}
} }
private double GetSeconds(int frameCount) private double GetSeconds(int frameCount)
@ -878,86 +875,31 @@ namespace BizHawk.Client.Common
return 0; return 0;
} }
string system = Header.Parameters[HeaderKeys.PLATFORM]; var system = Header[HeaderKeys.PLATFORM];
bool pal = Header.Parameters.ContainsKey(HeaderKeys.PAL) && var pal = Header.ContainsKey(HeaderKeys.PAL) &&
Header.Parameters[HeaderKeys.PAL] == "1"; Header[HeaderKeys.PAL] == "1";
return frames / _PlatformFrameRates[system, pal]; return frames / this.FrameRates[system, pal];
}
private static string ParseHeader(string line, string headerName)
{
int x = line.LastIndexOf(headerName) + headerName.Length;
return line.Substring(x + 1, line.Length - x - 1);
} }
public double Fps public double Fps
{ {
get get
{ {
string system = Header.Parameters[HeaderKeys.PLATFORM]; var system = Header[HeaderKeys.PLATFORM];
bool pal = Header.Parameters.ContainsKey(HeaderKeys.PAL) && var pal = Header.ContainsKey(HeaderKeys.PAL) &&
Header.Parameters[HeaderKeys.PAL] == "1"; Header[HeaderKeys.PAL] == "1";
return _PlatformFrameRates[system, pal]; return FrameRates[system, pal];
} }
} }
#endregion #endregion
private PlatformFrameRates _platformFrameRates = new PlatformFrameRates(); private readonly PlatformFrameRates _frameRates = new PlatformFrameRates();
public PlatformFrameRates _PlatformFrameRates public PlatformFrameRates FrameRates
{ {
get { return _platformFrameRates; } get { return _frameRates; }
}
public class PlatformFrameRates
{
public double this[string systemId, bool pal]
{
get
{
string key = systemId + (pal ? "_PAL" : String.Empty);
if (rates.ContainsKey(key))
{
return rates[key];
}
else
{
return 60.0;
}
}
}
private Dictionary<string, double> rates = new Dictionary<string, double>
{
{ "NES", 60.098813897440515532 },
{ "NES_PAL", 50.006977968268290849 },
{ "FDS", 60.098813897440515532 },
{ "FDS_PAL", 50.006977968268290849 },
{ "SNES", (double)21477272 / (4 * 341 * 262) },
{ "SNES_PAL", (double)21281370 / (4 * 341 * 312) },
{ "SGB", (double)21477272 / (4 * 341 * 262) },
{ "SGB_PAL", (double)21281370 / (4 * 341 * 312) },
{ "PCE", (7159090.90909090 / 455 / 263) }, //~59.826
{ "PCECD", (7159090.90909090 / 455 / 263) }, //~59.826
{ "SMS", (3579545 / 262.0 / 228.0) },
{ "SMS_PAL", (3546893 / 313.0 / 228.0) },
{ "GG", (3579545 / 262.0 / 228.0) },
{ "GG_PAL", (3546893 / 313.0 / 228.0) },
{ "SG", (3579545 / 262.0 / 228.0) },
{ "SG_PAL", (3546893 / 313.0 / 228.0) },
{ "NGP", (6144000.0 / (515 * 198)) },
{ "VBOY", (20000000 / (259 * 384 * 4)) }, //~50.273
{ "LYNX", 59.8 },
{ "WSWAN", (3072000.0 / (159 * 256)) },
{ "GB", 262144.0 / 4389.0 },
{ "GBC", 262144.0 / 4389.0 },
{ "GBA", 262144.0 / 4389.0 },
{ "A26", 59.9227510135505 },
{ "A78", 59.9227510135505 },
{ "Coleco", 59.9227510135505 }
};
} }
} }
} }

View File

@ -1,69 +1,54 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Text; using System.Text;
using BizHawk.Common;
namespace BizHawk.Client.Common namespace BizHawk.Client.Common
{ {
using System.Linq;
public class MovieHeader : Dictionary<string, string>, IMovieHeader public class MovieHeader : Dictionary<string, string>, IMovieHeader
{ {
//Required Header Params
//Emulation - Core version, will be 1.0.0 until there is a versioning system
//Movie - Versioning for the Movie code itself, or perhaps this could be changed client version?
//Platform - Must know what platform we are making a movie on!
//GameName - Which game
//TODO: checksum of game, other stuff
public Dictionary<string, string> Parameters { get; private set; }
public List<string> Comments { get; private set; } public List<string> Comments { get; private set; }
public Dictionary<string, string> BoardProperties { get; private set; } public Dictionary<string, string> BoardProperties { get; private set; }
public SubtitleList Subtitles { get; private set; } public SubtitleList Subtitles { get; private set; }
public MovieHeader() //All required fields will be set to default values public MovieHeader()
{ {
Parameters = new Dictionary<string, string>(); //Platform specific options go here
BoardProperties = new Dictionary<string, string>();
Comments = new List<string>(); Comments = new List<string>();
Subtitles = new SubtitleList(); Subtitles = new SubtitleList();
BoardProperties = new Dictionary<string, string>();
Parameters.Add(HeaderKeys.EMULATIONVERSION, VersionInfo.GetEmuVersion()); this[HeaderKeys.EMULATIONVERSION] = VersionInfo.GetEmuVersion();
Parameters.Add(HeaderKeys.MOVIEVERSION, HeaderKeys.MovieVersion); this[HeaderKeys.MOVIEVERSION] = HeaderKeys.MovieVersion;
Parameters.Add(HeaderKeys.PLATFORM, String.Empty); this[HeaderKeys.PLATFORM] = String.Empty;
Parameters.Add(HeaderKeys.GAMENAME, String.Empty); this[HeaderKeys.GAMENAME] = String.Empty;
Parameters.Add(HeaderKeys.AUTHOR, String.Empty); this[HeaderKeys.AUTHOR] = String.Empty;
Parameters.Add(HeaderKeys.RERECORDS, "0"); this[HeaderKeys.RERECORDS] = "0";
Parameters.Add(HeaderKeys.GUID, HeaderKeys.NewGuid); this[HeaderKeys.GUID] = HeaderKeys.NewGuid;
} }
/// <summary> public new string this[string key]
/// Adds the key value pair to header params. If key already exists, value will be updated
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public void AddHeaderLine(string key, string value)
{ {
string temp; get
if (!Parameters.TryGetValue(key, out temp)) //TODO: does a failed attempt mess with value?
Parameters.Add(key, value);
}
private void AddBoardProperty(string key, string value)
{
string temp;
if (!BoardProperties.TryGetValue(key, out temp))
{ {
BoardProperties.Add(key, value); return this.ContainsKey(key) ? base[key] : String.Empty;
}
set
{
if (ContainsKey(key))
{
base[key] = value;
}
else
{
Add(key, value);
}
} }
} }
new public void Clear() public new void Clear()
{ {
Parameters.Clear();
BoardProperties.Clear(); BoardProperties.Clear();
Comments.Clear(); Comments.Clear();
Subtitles.Clear(); Subtitles.Clear();
@ -74,7 +59,7 @@ namespace BizHawk.Client.Common
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
foreach (var kvp in Parameters) foreach (var kvp in this)
{ {
sb sb
.Append(kvp.Key) .Append(kvp.Key)
@ -94,70 +79,102 @@ namespace BizHawk.Client.Common
.AppendLine(); .AppendLine();
} }
foreach (string t in Comments) sb.Append(Subtitles);
{ Comments.ForEach(comment => sb.AppendLine(comment));
sb.AppendLine(t);
}
//TOD: subtitles go here not wherever it is currently located
return sb.ToString(); return sb.ToString();
} }
public bool AddHeaderFromLine(string line) public ulong Rerecords
{
get
{
if (!ContainsKey(HeaderKeys.RERECORDS))
{
this[HeaderKeys.RERECORDS] = "0";
}
return ulong.Parse(this[HeaderKeys.RERECORDS]);
}
set
{
this[HeaderKeys.RERECORDS] = value.ToString();
}
}
public bool StartsFromSavestate
{
get
{
if (ContainsKey(HeaderKeys.STARTSFROMSAVESTATE))
{
return bool.Parse(this[HeaderKeys.STARTSFROMSAVESTATE]);
}
else
{
return false;
}
}
set
{
if (value)
{
Add(HeaderKeys.STARTSFROMSAVESTATE, "True");
}
else
{
Remove(HeaderKeys.STARTSFROMSAVESTATE);
}
}
}
public bool ParseLineFromFile(string line)
{ {
if (!String.IsNullOrWhiteSpace(line)) if (!String.IsNullOrWhiteSpace(line))
{ {
var splitLine = line.Split(new char[] { ' ' }, 2); var splitLine = line.Split(new[] { ' ' }, 2);
if (line.Contains(HeaderKeys.BOARDPROPERTIES)) if (line.Contains(HeaderKeys.BOARDPROPERTIES))
{ {
var boardSplit = splitLine[1].Split(' '); var boardSplit = splitLine[1].Split(' ');
AddBoardProperty(boardSplit[0], boardSplit[1]); if (!BoardProperties.ContainsKey(boardSplit[0]))
{
BoardProperties.Add(boardSplit[0], boardSplit[1]);
}
} }
else if (HeaderKeys.Contains(splitLine[0])) else if (HeaderKeys.Contains(splitLine[0]))
{ {
Parameters.Add(splitLine[0], splitLine[1]); Add(splitLine[0], splitLine[1]);
} }
else if (line.StartsWith("subtitle") || line.StartsWith("sub")) else if (line.StartsWith("subtitle") || line.StartsWith("sub"))
{ {
return false; Subtitles.AddFromString(line);
} }
else if (line.StartsWith("comment")) else if (line.StartsWith("comment"))
{ {
Comments.Add(line.Substring(8, line.Length - 8)); Comments.Add(line.Substring(8, line.Length - 8));
} }
else if (line[0] == '|') else if (line.StartsWith("|"))
{ {
return false; return false;
} }
else if (Parameters.ContainsKey(HeaderKeys.PLATFORM) && Parameters[HeaderKeys.PLATFORM] == "N64") else if (ContainsKey(HeaderKeys.PLATFORM) && this[HeaderKeys.PLATFORM] == "N64"
&& ContainsKey(HeaderKeys.VIDEOPLUGIN))
{ {
if (Parameters.ContainsKey(HeaderKeys.VIDEOPLUGIN)) if (this[HeaderKeys.VIDEOPLUGIN] == "Rice")
{ {
if (Parameters[HeaderKeys.VIDEOPLUGIN] == "Rice") if (Global.Config.RicePlugin.GetPluginSettings().Keys.Any(line.Contains))
{ {
ICollection<string> settings = Global.Config.RicePlugin.GetPluginSettings().Keys; Add(splitLine[0], splitLine[1]);
foreach (var setting in settings)
{
if (line.Contains(setting))
{
Parameters.Add(splitLine[0], splitLine[1]);
break;
}
}
} }
else if (Parameters[HeaderKeys.VIDEOPLUGIN] == "Glide64") }
else if (this[HeaderKeys.VIDEOPLUGIN] == "Glide64")
{
if (Global.Config.GlidePlugin.GetPluginSettings().Keys.Any(line.Contains))
{ {
ICollection<string> settings = Global.Config.GlidePlugin.GetPluginSettings().Keys; Add(splitLine[0], splitLine[1]);
foreach (string setting in settings)
{
if (line.Contains(setting))
{
Parameters.Add(splitLine[0], splitLine[1]);
break;
}
}
} }
} }
} }

View File

@ -85,7 +85,7 @@ namespace BizHawk.Client.Common
} }
if (errorMsg == String.Empty) if (errorMsg == String.Empty)
{ {
m.Header.Parameters[HeaderKeys.MOVIEVERSION] = HeaderKeys.MovieVersion; m.Header[HeaderKeys.MOVIEVERSION] = HeaderKeys.MovieVersion;
} }
} }
catch (Exception except) catch (Exception except)
@ -304,7 +304,7 @@ namespace BizHawk.Client.Common
platform = "PCE"; platform = "PCE";
break; break;
} }
m.Header.Parameters[HeaderKeys.PLATFORM] = platform; m.Header[HeaderKeys.PLATFORM] = platform;
int lineNum = 0; int lineNum = 0;
string line; string line;
while ((line = sr.ReadLine()) != null) while ((line = sr.ReadLine()) != null)
@ -348,7 +348,7 @@ namespace BizHawk.Client.Common
} }
else if (line.ToLower().StartsWith("romfilename")) else if (line.ToLower().StartsWith("romfilename"))
{ {
m.Header.Parameters[HeaderKeys.GAMENAME] = ParseHeader(line, "romFilename"); m.Header[HeaderKeys.GAMENAME] = ParseHeader(line, "romFilename");
} }
else if (line.ToLower().StartsWith("romchecksum")) else if (line.ToLower().StartsWith("romchecksum"))
{ {
@ -356,7 +356,7 @@ namespace BizHawk.Client.Common
byte[] md5 = DecodeBlob(blob); byte[] md5 = DecodeBlob(blob);
if (md5 != null && md5.Length == 16) if (md5 != null && md5.Length == 16)
{ {
m.Header.Parameters[MD5] = Util.BytesToHexString(md5).ToLower(); m.Header[MD5] = Util.BytesToHexString(md5).ToLower();
} }
else else
{ {
@ -365,7 +365,7 @@ namespace BizHawk.Client.Common
} }
else if (line.ToLower().StartsWith("comment author")) else if (line.ToLower().StartsWith("comment author"))
{ {
m.Header.Parameters[HeaderKeys.AUTHOR] = ParseHeader(line, "comment author"); m.Header[HeaderKeys.AUTHOR] = ParseHeader(line, "comment author");
} }
else if (line.ToLower().StartsWith("rerecordcount")) else if (line.ToLower().StartsWith("rerecordcount"))
{ {
@ -379,11 +379,11 @@ namespace BizHawk.Client.Common
{ {
rerecordCount = 0; rerecordCount = 0;
} }
m.Rerecords = rerecordCount; m.Rerecords = (ulong)rerecordCount;
} }
else if (line.ToLower().StartsWith("guid")) else if (line.ToLower().StartsWith("guid"))
{ {
m.Header.Parameters[HeaderKeys.GUID] = ParseHeader(line, "guid"); m.Header[HeaderKeys.GUID] = ParseHeader(line, "guid");
} }
else if (line.ToLower().StartsWith("startsfromsavestate")) else if (line.ToLower().StartsWith("startsfromsavestate"))
{ {
@ -398,12 +398,12 @@ namespace BizHawk.Client.Common
else if (line.ToLower().StartsWith("palflag")) else if (line.ToLower().StartsWith("palflag"))
{ {
bool pal = (ParseHeader(line, "palFlag") == "1"); bool pal = (ParseHeader(line, "palFlag") == "1");
m.Header.Parameters[HeaderKeys.PAL] = pal.ToString(); m.Header[HeaderKeys.PAL] = pal.ToString();
} }
else if (line.ToLower().StartsWith("fourscore")) else if (line.ToLower().StartsWith("fourscore"))
{ {
bool fourscore = (ParseHeader(line, "fourscore") == "1"); bool fourscore = (ParseHeader(line, "fourscore") == "1");
m.Header.Parameters[HeaderKeys.FOURSCORE] = fourscore.ToString(); m.Header[HeaderKeys.FOURSCORE] = fourscore.ToString();
} }
else else
// Everything not explicitly defined is treated as a comment. // Everything not explicitly defined is treated as a comment.
@ -515,7 +515,7 @@ namespace BizHawk.Client.Common
preference. This means that this site cannot calculate movie lengths reliably. preference. This means that this site cannot calculate movie lengths reliably.
*/ */
bool pal = (((flags >> 2) & 0x1) != 0); bool pal = (((flags >> 2) & 0x1) != 0);
m.Header.Parameters[HeaderKeys.PAL] = pal.ToString(); m.Header[HeaderKeys.PAL] = pal.ToString();
// other: reserved, set to 0 // other: reserved, set to 0
bool syncHack = (((flags >> 4) & 0x1) != 0); bool syncHack = (((flags >> 4) & 0x1) != 0);
m.Header.Comments.Add(SYNCHACK + " " + syncHack.ToString()); m.Header.Comments.Add(SYNCHACK + " " + syncHack.ToString());
@ -529,7 +529,7 @@ namespace BizHawk.Client.Common
uint frameCount = r.ReadUInt32(); uint frameCount = r.ReadUInt32();
// 010 4-byte little-endian unsigned int: rerecord count // 010 4-byte little-endian unsigned int: rerecord count
uint rerecordCount = r.ReadUInt32(); uint rerecordCount = r.ReadUInt32();
m.Rerecords = (int)rerecordCount; m.Rerecords = rerecordCount;
/* /*
018 4-byte little-endian unsigned int: offset to the savestate inside file 018 4-byte little-endian unsigned int: offset to the savestate inside file
The savestate offset is <header_size + length_of_metadata_in_bytes + padding>. The savestate offset should be The savestate offset is <header_size + length_of_metadata_in_bytes + padding>. The savestate offset should be
@ -541,7 +541,7 @@ namespace BizHawk.Client.Common
uint firstFrameOffset = r.ReadUInt32(); uint firstFrameOffset = r.ReadUInt32();
// 020 16-byte md5sum of the ROM used // 020 16-byte md5sum of the ROM used
byte[] md5 = r.ReadBytes(16); byte[] md5 = r.ReadBytes(16);
m.Header.Parameters[MD5] = Util.BytesToHexString(md5).ToLower(); m.Header[MD5] = Util.BytesToHexString(md5).ToLower();
// 030 4-byte little-endian unsigned int: version of the emulator used // 030 4-byte little-endian unsigned int: version of the emulator used
uint emuVersion = r.ReadUInt32(); uint emuVersion = r.ReadUInt32();
m.Header.Comments.Add(EMULATIONORIGIN + " FCEU " + emuVersion.ToString()); m.Header.Comments.Add(EMULATIONORIGIN + " FCEU " + emuVersion.ToString());
@ -552,7 +552,7 @@ namespace BizHawk.Client.Common
// Advance past null byte. // Advance past null byte.
r.ReadByte(); r.ReadByte();
string gameName = Encoding.UTF8.GetString(gameBytes.ToArray()); string gameName = Encoding.UTF8.GetString(gameBytes.ToArray());
m.Header.Parameters[HeaderKeys.GAMENAME] = gameName; m.Header[HeaderKeys.GAMENAME] = gameName;
/* /*
After the header comes "metadata", which is UTF8-coded movie title string. The metadata begins after the ROM After the header comes "metadata", which is UTF8-coded movie title string. The metadata begins after the ROM
name and ends at the savestate offset. This string is displayed as "Author Info" in the Windows version of the name and ends at the savestate offset. This string is displayed as "Author Info" in the Windows version of the
@ -564,7 +564,7 @@ namespace BizHawk.Client.Common
// Advance past null byte. // Advance past null byte.
r.ReadByte(); r.ReadByte();
string author = Encoding.UTF8.GetString(authorBytes.ToArray()); string author = Encoding.UTF8.GetString(authorBytes.ToArray());
m.Header.Parameters[HeaderKeys.AUTHOR] = author; m.Header[HeaderKeys.AUTHOR] = author;
// Advance to first byte of input data. // Advance to first byte of input data.
r.BaseStream.Position = firstFrameOffset; r.BaseStream.Position = firstFrameOffset;
SimpleController controllers = new SimpleController {Type = new ControllerDefinition {Name = "NES Controller"}}; SimpleController controllers = new SimpleController {Type = new ControllerDefinition {Name = "NES Controller"}};
@ -707,9 +707,9 @@ namespace BizHawk.Client.Common
controllers["P" + player + " " + buttons[button]] = !controllers["P" + player + " " + buttons[button]]; controllers["P" + player + " " + buttons[button]] = !controllers["P" + player + " " + buttons[button]];
} }
} }
m.Header.Parameters[HeaderKeys.PLATFORM] = "NES"; m.Header[HeaderKeys.PLATFORM] = "NES";
if (fds) { m.Header.Parameters[HeaderKeys.BOARDNAME] = "FDS"; } if (fds) { m.Header[HeaderKeys.BOARDNAME] = "FDS"; }
m.Header.Parameters[HeaderKeys.FOURSCORE] = fourscore.ToString(); m.Header[HeaderKeys.FOURSCORE] = fourscore.ToString();
r.Close(); r.Close();
fs.Close(); fs.Close();
return m; return m;
@ -755,7 +755,7 @@ namespace BizHawk.Client.Common
if (((flags >> 5) & 0x1) != 0) if (((flags >> 5) & 0x1) != 0)
{ {
FDS = true; FDS = true;
m.Header.Parameters[HeaderKeys.BOARDNAME] = "FDS"; m.Header[HeaderKeys.BOARDNAME] = "FDS";
} }
else else
{ {
@ -763,7 +763,7 @@ namespace BizHawk.Client.Common
} }
m.Header.Parameters[HeaderKeys.PLATFORM] = "NES"; m.Header[HeaderKeys.PLATFORM] = "NES";
// bit 6: uses controller 2 // bit 6: uses controller 2
bool controller2 = (((flags >> 6) & 0x1) != 0); bool controller2 = (((flags >> 6) & 0x1) != 0);
@ -779,7 +779,7 @@ namespace BizHawk.Client.Common
loaded, the number is 0. Famtasia however displays "1" in such case. It always adds 1 to the number found in loaded, the number is 0. Famtasia however displays "1" in such case. It always adds 1 to the number found in
the file. the file.
*/ */
m.Rerecords = ((int)rerecordCount) + 1; m.Rerecords = rerecordCount + 1;
// 00E 2-byte little-endian unsigned int: unknown, set to 0000 // 00E 2-byte little-endian unsigned int: unknown, set to 0000
r.ReadInt16(); r.ReadInt16();
// 010 64-byte zero-terminated emulator identifier string // 010 64-byte zero-terminated emulator identifier string
@ -800,7 +800,7 @@ namespace BizHawk.Client.Common
The file format has no means of identifying NTSC/"PAL". It is always assumed that the game is NTSC - that is, The file format has no means of identifying NTSC/"PAL". It is always assumed that the game is NTSC - that is,
60 fps. 60 fps.
*/ */
m.Header.Parameters[HeaderKeys.PAL] = "False"; m.Header[HeaderKeys.PAL] = "False";
// 090 frame data begins here // 090 frame data begins here
SimpleController controllers = new SimpleController {Type = new ControllerDefinition {Name = "NES Controller"}}; SimpleController controllers = new SimpleController {Type = new ControllerDefinition {Name = "NES Controller"}};
MnemonicsGenerator mg = new MnemonicsGenerator(); MnemonicsGenerator mg = new MnemonicsGenerator();
@ -879,14 +879,14 @@ namespace BizHawk.Client.Common
fs.Close(); fs.Close();
return null; return null;
} }
m.Header.Parameters[HeaderKeys.PLATFORM] = "Genesis"; m.Header[HeaderKeys.PLATFORM] = "Genesis";
// 00F ASCII-encoded GMV file format version. The most recent is 'A'. (?) // 00F ASCII-encoded GMV file format version. The most recent is 'A'. (?)
string version = r.ReadStringFixedAscii(1); string version = r.ReadStringFixedAscii(1);
m.Header.Comments.Add(MOVIEORIGIN + " .GMV version " + version); m.Header.Comments.Add(MOVIEORIGIN + " .GMV version " + version);
m.Header.Comments.Add(EMULATIONORIGIN + " Gens"); m.Header.Comments.Add(EMULATIONORIGIN + " Gens");
// 010 4-byte little-endian unsigned int: rerecord count // 010 4-byte little-endian unsigned int: rerecord count
uint rerecordCount = r.ReadUInt32(); uint rerecordCount = r.ReadUInt32();
m.Rerecords = (int)rerecordCount; m.Rerecords = rerecordCount;
// 014 ASCII-encoded controller config for player 1. '3' or '6'. // 014 ASCII-encoded controller config for player 1. '3' or '6'.
string player1Config = r.ReadStringFixedAscii(1); string player1Config = r.ReadStringFixedAscii(1);
// 015 ASCII-encoded controller config for player 2. '3' or '6'. // 015 ASCII-encoded controller config for player 2. '3' or '6'.
@ -903,7 +903,7 @@ namespace BizHawk.Client.Common
header. header.
*/ */
bool pal = (((flags >> 7) & 0x1) != 0); bool pal = (((flags >> 7) & 0x1) != 0);
m.Header.Parameters[HeaderKeys.PAL] = pal.ToString(); m.Header[HeaderKeys.PAL] = pal.ToString();
// bit 6: if "1", movie requires a savestate. // bit 6: if "1", movie requires a savestate.
if (((flags >> 6) & 0x1) != 0) if (((flags >> 6) & 0x1) != 0)
{ {
@ -1035,7 +1035,7 @@ namespace BizHawk.Client.Common
{ {
author_list += author_last; author_list += author_last;
} }
m.Header.Parameters[HeaderKeys.AUTHOR] = author_list; m.Header[HeaderKeys.AUTHOR] = author_list;
hf.Unbind(); hf.Unbind();
} }
else if (item.name == "coreversion") else if (item.name == "coreversion")
@ -1051,7 +1051,7 @@ namespace BizHawk.Client.Common
hf.BindArchiveMember(item.index); hf.BindArchiveMember(item.index);
var stream = hf.GetStream(); var stream = hf.GetStream();
string gamename = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim(); string gamename = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
m.Header.Parameters[HeaderKeys.GAMENAME] = gamename; m.Header[HeaderKeys.GAMENAME] = gamename;
hf.Unbind(); hf.Unbind();
} }
else if (item.name == "gametype") else if (item.name == "gametype")
@ -1072,11 +1072,11 @@ namespace BizHawk.Client.Common
case "sgb_ntsc": case "sgb_ntsc":
case "sgb_pal": case "sgb_pal":
platform = "SNES"; platform = "SNES";
m.Header.Parameters[HeaderKeys.SGB] = "True"; m.Header[HeaderKeys.SGB] = "True";
break; break;
} }
bool pal = (gametype == "snes_pal" || gametype == "sgb_pal"); bool pal = (gametype == "snes_pal" || gametype == "sgb_pal");
m.Header.Parameters[HeaderKeys.PAL] = pal.ToString(); m.Header[HeaderKeys.PAL] = pal.ToString();
hf.Unbind(); hf.Unbind();
} }
else if (item.name == "input") else if (item.name == "input")
@ -1123,7 +1123,7 @@ namespace BizHawk.Client.Common
hf.BindArchiveMember(item.index); hf.BindArchiveMember(item.index);
var stream = hf.GetStream(); var stream = hf.GetStream();
string port1 = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim(); string port1 = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
m.Header.Parameters[PORT1] = port1; m.Header[PORT1] = port1;
hf.Unbind(); hf.Unbind();
} }
else if (item.name == "port2") else if (item.name == "port2")
@ -1131,7 +1131,7 @@ namespace BizHawk.Client.Common
hf.BindArchiveMember(item.index); hf.BindArchiveMember(item.index);
var stream = hf.GetStream(); var stream = hf.GetStream();
string port2 = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim(); string port2 = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
m.Header.Parameters[PORT2] = port2; m.Header[PORT2] = port2;
hf.Unbind(); hf.Unbind();
} }
else if (item.name == "projectid") else if (item.name == "projectid")
@ -1139,7 +1139,7 @@ namespace BizHawk.Client.Common
hf.BindArchiveMember(item.index); hf.BindArchiveMember(item.index);
var stream = hf.GetStream(); var stream = hf.GetStream();
string projectid = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim(); string projectid = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
m.Header.Parameters[PROJECTID] = projectid; m.Header[PROJECTID] = projectid;
hf.Unbind(); hf.Unbind();
} }
else if (item.name == "rerecords") else if (item.name == "rerecords")
@ -1157,7 +1157,7 @@ namespace BizHawk.Client.Common
{ {
rerecordCount = 0; rerecordCount = 0;
} }
m.Rerecords = rerecordCount; m.Rerecords = (ulong)rerecordCount;
hf.Unbind(); hf.Unbind();
} }
else if (item.name.EndsWith(".sha256")) else if (item.name.EndsWith(".sha256"))
@ -1167,7 +1167,7 @@ namespace BizHawk.Client.Common
string rom = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim(); string rom = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
int pos = item.name.LastIndexOf(".sha256"); int pos = item.name.LastIndexOf(".sha256");
string name = item.name.Substring(0, pos); string name = item.name.Substring(0, pos);
m.Header.Parameters[SHA256 + "_" + name] = rom; m.Header[SHA256 + "_" + name] = rom;
hf.Unbind(); hf.Unbind();
} }
else if (item.name == "savestate") else if (item.name == "savestate")
@ -1193,7 +1193,7 @@ namespace BizHawk.Client.Common
hf.BindArchiveMember(item.index); hf.BindArchiveMember(item.index);
var stream = hf.GetStream(); var stream = hf.GetStream();
string startSecond = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim(); string startSecond = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
m.Header.Parameters[STARTSECOND] = startSecond; m.Header[STARTSECOND] = startSecond;
hf.Unbind(); hf.Unbind();
} }
else if (item.name == "starttime.subsecond") else if (item.name == "starttime.subsecond")
@ -1201,7 +1201,7 @@ namespace BizHawk.Client.Common
hf.BindArchiveMember(item.index); hf.BindArchiveMember(item.index);
var stream = hf.GetStream(); var stream = hf.GetStream();
string startSubSecond = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim(); string startSubSecond = Encoding.UTF8.GetString(Util.ReadAllBytes(stream)).Trim();
m.Header.Parameters[STARTSUBSECOND] = startSubSecond; m.Header[STARTSUBSECOND] = startSubSecond;
hf.Unbind(); hf.Unbind();
} }
else if (item.name == "systemid") else if (item.name == "systemid")
@ -1213,7 +1213,7 @@ namespace BizHawk.Client.Common
hf.Unbind(); hf.Unbind();
} }
} }
m.Header.Parameters[HeaderKeys.PLATFORM] = platform; m.Header[HeaderKeys.PLATFORM] = platform;
return m; return m;
} }
@ -1246,13 +1246,13 @@ namespace BizHawk.Client.Common
byte[] md5 = r.ReadBytes(16); byte[] md5 = r.ReadBytes(16);
// Discard the second 16 bytes. // Discard the second 16 bytes.
r.ReadBytes(16); r.ReadBytes(16);
m.Header.Parameters[MD5] = Util.BytesToHexString(md5).ToLower(); m.Header[MD5] = Util.BytesToHexString(md5).ToLower();
// 030 64-byte Filename of the ROM used (with extension) // 030 64-byte Filename of the ROM used (with extension)
string gameName = NullTerminated(r.ReadStringFixedAscii(64)); string gameName = NullTerminated(r.ReadStringFixedAscii(64));
m.Header.Parameters[HeaderKeys.GAMENAME] = gameName; m.Header[HeaderKeys.GAMENAME] = gameName;
// 070 uint32 Re-record Count // 070 uint32 Re-record Count
uint rerecordCount = r.ReadUInt32(); uint rerecordCount = r.ReadUInt32();
m.Rerecords = (int)rerecordCount; m.Rerecords = (ulong)rerecordCount;
// 074 5-byte Console indicator (pce, ngp, pcfx, wswan) // 074 5-byte Console indicator (pce, ngp, pcfx, wswan)
string platform = NullTerminated(r.ReadStringFixedAscii(5)); string platform = NullTerminated(r.ReadStringFixedAscii(5));
Dictionary<string, Dictionary<string, object>> platforms = new Dictionary<string, Dictionary<string, object>> Dictionary<string, Dictionary<string, object>> platforms = new Dictionary<string, Dictionary<string, object>>
@ -1285,10 +1285,10 @@ namespace BizHawk.Client.Common
return null; return null;
} }
string name = (string)platforms[platform]["name"]; string name = (string)platforms[platform]["name"];
m.Header.Parameters[HeaderKeys.PLATFORM] = name; m.Header[HeaderKeys.PLATFORM] = name;
// 079 32-byte Author name // 079 32-byte Author name
string author = NullTerminated(r.ReadStringFixedAscii(32)); string author = NullTerminated(r.ReadStringFixedAscii(32));
m.Header.Parameters[HeaderKeys.AUTHOR] = author; m.Header[HeaderKeys.AUTHOR] = author;
// 099 103-byte Padding 0s // 099 103-byte Padding 0s
r.ReadBytes(103); r.ReadBytes(103);
// TODO: Verify if NTSC/"PAL" mode used for the movie can be detected or not. // TODO: Verify if NTSC/"PAL" mode used for the movie can be detected or not.
@ -1367,7 +1367,7 @@ namespace BizHawk.Client.Common
uint frameCount = r.ReadUInt32(); uint frameCount = r.ReadUInt32();
// 000c: 4-byte little endian unsigned int: rerecord count // 000c: 4-byte little endian unsigned int: rerecord count
uint rerecordCount = r.ReadUInt32(); uint rerecordCount = r.ReadUInt32();
m.Rerecords = (int)rerecordCount; m.Rerecords = rerecordCount;
// 0010: 4-byte little endian flag: begin from reset? // 0010: 4-byte little endian flag: begin from reset?
uint reset = r.ReadUInt32(); uint reset = r.ReadUInt32();
if (reset == 0) if (reset == 0)
@ -1385,36 +1385,36 @@ namespace BizHawk.Client.Common
r.ReadUInt32(); r.ReadUInt32();
// 0020-005f: string: author info (UTF-8) // 0020-005f: string: author info (UTF-8)
string author = NullTerminated(r.ReadStringFixedAscii(64)); string author = NullTerminated(r.ReadStringFixedAscii(64));
m.Header.Parameters[HeaderKeys.AUTHOR] = author; m.Header[HeaderKeys.AUTHOR] = author;
// 0060: 4-byte little endian flags // 0060: 4-byte little endian flags
byte flags = r.ReadByte(); byte flags = r.ReadByte();
// bit 0: unused // bit 0: unused
// bit 1: "PAL" // bit 1: "PAL"
bool pal = (((flags >> 1) & 0x1) != 0); bool pal = (((flags >> 1) & 0x1) != 0);
m.Header.Parameters[HeaderKeys.PAL] = pal.ToString(); m.Header[HeaderKeys.PAL] = pal.ToString();
// bit 2: Japan // bit 2: Japan
bool japan = (((flags >> 2) & 0x1) != 0); bool japan = (((flags >> 2) & 0x1) != 0);
m.Header.Parameters[JAPAN] = japan.ToString(); m.Header[JAPAN] = japan.ToString();
// bit 3: Game Gear (version 1.16+) // bit 3: Game Gear (version 1.16+)
bool gamegear; bool gamegear;
if (((flags >> 3) & 0x1) != 0) if (((flags >> 3) & 0x1) != 0)
{ {
gamegear = true; gamegear = true;
m.Header.Parameters[HeaderKeys.PLATFORM] = "GG"; m.Header[HeaderKeys.PLATFORM] = "GG";
} }
else else
{ {
gamegear = false; gamegear = false;
m.Header.Parameters[HeaderKeys.PLATFORM] = "SMS"; m.Header[HeaderKeys.PLATFORM] = "SMS";
} }
// bits 4-31: unused // bits 4-31: unused
r.ReadBytes(3); r.ReadBytes(3);
// 0064-00e3: string: rom name (ASCII) // 0064-00e3: string: rom name (ASCII)
string gameName = NullTerminated(r.ReadStringFixedAscii(128)); string gameName = NullTerminated(r.ReadStringFixedAscii(128));
m.Header.Parameters[HeaderKeys.GAMENAME] = gameName; m.Header[HeaderKeys.GAMENAME] = gameName;
// 00e4-00f3: binary: rom MD5 digest // 00e4-00f3: binary: rom MD5 digest
byte[] md5 = r.ReadBytes(16); byte[] md5 = r.ReadBytes(16);
m.Header.Parameters[MD5] = String.Format("{0:x8}", Util.BytesToHexString(md5).ToLower()); m.Header[MD5] = String.Format("{0:x8}", Util.BytesToHexString(md5).ToLower());
SimpleController controllers = new SimpleController {Type = new ControllerDefinition {Name = "SMS Controller"}}; SimpleController controllers = new SimpleController {Type = new ControllerDefinition {Name = "SMS Controller"}};
MnemonicsGenerator mg = new MnemonicsGenerator(); MnemonicsGenerator mg = new MnemonicsGenerator();
/* /*
@ -1526,7 +1526,7 @@ namespace BizHawk.Client.Common
* 7 - Vs Unisystem Zapper (3 bytes) * 7 - Vs Unisystem Zapper (3 bytes)
*/ */
bool fourscore = (controller1 == 5); bool fourscore = (controller1 == 5);
m.Header.Parameters[HeaderKeys.FOURSCORE] = fourscore.ToString(); m.Header[HeaderKeys.FOURSCORE] = fourscore.ToString();
bool[] masks = new[] { false, false, false, false, false }; bool[] masks = new[] { false, false, false, false, false };
if (fourscore) if (fourscore)
{ {
@ -1629,10 +1629,10 @@ namespace BizHawk.Client.Common
* if "1", "PAL" timing * if "1", "PAL" timing
*/ */
bool pal = (((data >> 7) & 0x1) != 0); bool pal = (((data >> 7) & 0x1) != 0);
m.Header.Parameters[HeaderKeys.PAL] = pal.ToString(); m.Header[HeaderKeys.PAL] = pal.ToString();
// 004 4-byte little-endian unsigned int: rerecord count // 004 4-byte little-endian unsigned int: rerecord count
uint rerecordCount = r.ReadUInt32(); uint rerecordCount = r.ReadUInt32();
m.Rerecords = (int)rerecordCount; m.Rerecords = rerecordCount;
/* /*
008 4-byte little-endian unsigned int: length of movie description 008 4-byte little-endian unsigned int: length of movie description
00C (variable) null-terminated UTF-8 text, movie description (currently not implemented) 00C (variable) null-terminated UTF-8 text, movie description (currently not implemented)
@ -1704,7 +1704,7 @@ namespace BizHawk.Client.Common
fs.Close(); fs.Close();
return null; return null;
} }
m.Header.Parameters[HeaderKeys.PLATFORM] = "SNES"; m.Header[HeaderKeys.PLATFORM] = "SNES";
// 004 4-byte little-endian unsigned int: version number // 004 4-byte little-endian unsigned int: version number
uint versionNumber = r.ReadUInt32(); uint versionNumber = r.ReadUInt32();
string version; string version;
@ -1732,9 +1732,9 @@ namespace BizHawk.Client.Common
recording time in Unix epoch format recording time in Unix epoch format
*/ */
uint uid = r.ReadUInt32(); uint uid = r.ReadUInt32();
m.Header.Parameters[HeaderKeys.GUID] = String.Format("{0:X8}", uid) + "-0000-0000-0000-000000000000"; m.Header[HeaderKeys.GUID] = String.Format("{0:X8}", uid) + "-0000-0000-0000-000000000000";
// 00C 4-byte little-endian unsigned int: rerecord count // 00C 4-byte little-endian unsigned int: rerecord count
m.Rerecords = (int)r.ReadUInt32(); m.Rerecords = r.ReadUInt32();
// 010 4-byte little-endian unsigned int: number of frames // 010 4-byte little-endian unsigned int: number of frames
uint frameCount = r.ReadUInt32(); uint frameCount = r.ReadUInt32();
// 014 1-byte flags "controller mask" // 014 1-byte flags "controller mask"
@ -1770,7 +1770,7 @@ namespace BizHawk.Client.Common
} }
// bit 1: if "0", movie is NTSC (60 fps); if "1", movie is PAL (50 fps) // bit 1: if "0", movie is NTSC (60 fps); if "1", movie is PAL (50 fps)
bool pal = (((movieFlags >> 1) & 0x1) != 0); bool pal = (((movieFlags >> 1) & 0x1) != 0);
m.Header.Parameters[HeaderKeys.PAL] = pal.ToString(); m.Header[HeaderKeys.PAL] = pal.ToString();
// other: reserved, set to 0 // other: reserved, set to 0
/* /*
016 1-byte flags "sync options": 016 1-byte flags "sync options":
@ -1830,17 +1830,17 @@ namespace BizHawk.Client.Common
string author = NullTerminated(Encoding.Unicode.GetString(metadata).Trim()); string author = NullTerminated(Encoding.Unicode.GetString(metadata).Trim());
if (author != "") if (author != "")
{ {
m.Header.Parameters[HeaderKeys.AUTHOR] = author; m.Header[HeaderKeys.AUTHOR] = author;
} }
if (extraRomInfo == 30) if (extraRomInfo == 30)
{ {
// 000 3 bytes of zero padding: 00 00 00 003 4-byte integer: CRC32 of the ROM 007 23-byte ascii string // 000 3 bytes of zero padding: 00 00 00 003 4-byte integer: CRC32 of the ROM 007 23-byte ascii string
r.ReadBytes(3); r.ReadBytes(3);
int crc32 = r.ReadInt32(); int crc32 = r.ReadInt32();
m.Header.Parameters[CRC32] = crc32.ToString(); m.Header[CRC32] = crc32.ToString();
// the game name copied from the ROM, truncated to 23 bytes (the game name in the ROM is 21 bytes) // the game name copied from the ROM, truncated to 23 bytes (the game name in the ROM is 21 bytes)
string gameName = NullTerminated(Encoding.UTF8.GetString(r.ReadBytes(23))); string gameName = NullTerminated(Encoding.UTF8.GetString(r.ReadBytes(23)));
m.Header.Parameters[HeaderKeys.GAMENAME] = gameName; m.Header[HeaderKeys.GAMENAME] = gameName;
} }
r.BaseStream.Position = firstFrameOffset; r.BaseStream.Position = firstFrameOffset;
/* /*
@ -1991,12 +1991,12 @@ namespace BizHawk.Client.Common
recording time in Unix epoch format recording time in Unix epoch format
*/ */
uint uid = r.ReadUInt32(); uint uid = r.ReadUInt32();
m.Header.Parameters[HeaderKeys.GUID] = String.Format("{0:X8}", uid) + "-0000-0000-0000-000000000000"; m.Header[HeaderKeys.GUID] = String.Format("{0:X8}", uid) + "-0000-0000-0000-000000000000";
// 00C 4-byte little-endian unsigned int: number of frames // 00C 4-byte little-endian unsigned int: number of frames
uint frameCount = r.ReadUInt32(); uint frameCount = r.ReadUInt32();
// 010 4-byte little-endian unsigned int: rerecord count // 010 4-byte little-endian unsigned int: rerecord count
uint rerecordCount = r.ReadUInt32(); uint rerecordCount = r.ReadUInt32();
m.Rerecords = (int)rerecordCount; m.Rerecords = rerecordCount;
// 014 1-byte flags: (movie start flags) // 014 1-byte flags: (movie start flags)
byte flags = r.ReadByte(); byte flags = r.ReadByte();
// bit 0: if "1", movie starts from an embedded "quicksave" snapshot // bit 0: if "1", movie starts from an embedded "quicksave" snapshot
@ -2080,7 +2080,7 @@ namespace BizHawk.Client.Common
{ {
m.Header.Comments.Add(SUPERGAMEBOYMODE + " True"); m.Header.Comments.Add(SUPERGAMEBOYMODE + " True");
} }
m.Header.Parameters[HeaderKeys.PLATFORM] = platform; m.Header[HeaderKeys.PLATFORM] = platform;
// 017 1-byte flags: (values of some boolean emulator options) // 017 1-byte flags: (values of some boolean emulator options)
flags = r.ReadByte(); flags = r.ReadByte();
/* /*
@ -2117,7 +2117,7 @@ namespace BizHawk.Client.Common
null-terminated (ASCII?) null-terminated (ASCII?)
*/ */
string gameName = NullTerminated(r.ReadStringFixedAscii(12)); string gameName = NullTerminated(r.ReadStringFixedAscii(12));
m.Header.Parameters[HeaderKeys.GAMENAME] = gameName; m.Header[HeaderKeys.GAMENAME] = gameName;
// 030 1-byte unsigned char: minor version/revision number of current VBM version, the latest is "1" // 030 1-byte unsigned char: minor version/revision number of current VBM version, the latest is "1"
byte minorVersion = r.ReadByte(); byte minorVersion = r.ReadByte();
m.Header.Comments.Add(MOVIEORIGIN + " .VBM version " + majorVersion + "." + minorVersion); m.Header.Comments.Add(MOVIEORIGIN + " .VBM version " + majorVersion + "." + minorVersion);
@ -2136,13 +2136,13 @@ namespace BizHawk.Client.Common
uint gameCode_unitCode = r.ReadUInt32(); uint gameCode_unitCode = r.ReadUInt32();
if (platform == "GBA") if (platform == "GBA")
{ {
m.Header.Parameters[CRC16] = checksum_crc16.ToString(); m.Header[CRC16] = checksum_crc16.ToString();
m.Header.Parameters[GAMECODE] = gameCode_unitCode.ToString(); m.Header[GAMECODE] = gameCode_unitCode.ToString();
} }
else else
{ {
m.Header.Parameters[INTERNALCHECKSUM] = checksum_crc16.ToString(); m.Header[INTERNALCHECKSUM] = checksum_crc16.ToString();
m.Header.Parameters[UNITCODE] = gameCode_unitCode.ToString(); m.Header[UNITCODE] = gameCode_unitCode.ToString();
} }
// 038 4-byte little-endian unsigned int: offset to the savestate or SRAM inside file, set to 0 if unused // 038 4-byte little-endian unsigned int: offset to the savestate or SRAM inside file, set to 0 if unused
r.ReadBytes(4); r.ReadBytes(4);
@ -2150,7 +2150,7 @@ namespace BizHawk.Client.Common
uint firstFrameOffset = r.ReadUInt32(); uint firstFrameOffset = r.ReadUInt32();
// After the header is 192 bytes of text. The first 64 of these 192 bytes are for the author's name (or names). // After the header is 192 bytes of text. The first 64 of these 192 bytes are for the author's name (or names).
string author = NullTerminated(r.ReadStringFixedAscii(64)); string author = NullTerminated(r.ReadStringFixedAscii(64));
m.Header.Parameters[HeaderKeys.AUTHOR] = author; m.Header[HeaderKeys.AUTHOR] = author;
// The following 128 bytes are for a description of the movie. Both parts must be null-terminated. // The following 128 bytes are for a description of the movie. Both parts must be null-terminated.
string movieDescription = NullTerminated(r.ReadStringFixedAscii(128)); string movieDescription = NullTerminated(r.ReadStringFixedAscii(128));
m.Header.Comments.Add(COMMENT + " " + movieDescription); m.Header.Comments.Add(COMMENT + " " + movieDescription);
@ -2249,7 +2249,7 @@ namespace BizHawk.Client.Common
fs.Close(); fs.Close();
return null; return null;
} }
m.Header.Parameters[HeaderKeys.PLATFORM] = "NES"; m.Header[HeaderKeys.PLATFORM] = "NES";
// 00C 2-byte little-endian integer: movie version 0x0400 // 00C 2-byte little-endian integer: movie version 0x0400
ushort version = r.ReadUInt16(); ushort version = r.ReadUInt16();
m.Header.Comments.Add(MOVIEORIGIN + " .VMV version " + version); m.Header.Comments.Add(MOVIEORIGIN + " .VMV version " + version);
@ -2271,7 +2271,7 @@ namespace BizHawk.Client.Common
controllersUsed[controller - 1] = (((flags >> (controller - 1)) & 0x1) != 0); controllersUsed[controller - 1] = (((flags >> (controller - 1)) & 0x1) != 0);
} }
bool fourscore = (controllersUsed[2] || controllersUsed[3]); bool fourscore = (controllersUsed[2] || controllersUsed[3]);
m.Header.Parameters[HeaderKeys.FOURSCORE] = fourscore.ToString(); m.Header[HeaderKeys.FOURSCORE] = fourscore.ToString();
/* /*
bit 6: 1=reset-based, 0=savestate-based (movie version <= 0x300 is always savestate-based) bit 6: 1=reset-based, 0=savestate-based (movie version <= 0x300 is always savestate-based)
If the movie version is < 0x400, or the "from-reset" flag is not set, a savestate is loaded from the movie. If the movie version is < 0x400, or the "from-reset" flag is not set, a savestate is loaded from the movie.
@ -2298,7 +2298,7 @@ namespace BizHawk.Client.Common
r.ReadBytes(2); r.ReadBytes(2);
// 01C 4-byte little-endian integer: rerecord count // 01C 4-byte little-endian integer: rerecord count
uint rerecordCount = r.ReadUInt32(); uint rerecordCount = r.ReadUInt32();
m.Rerecords = (int)rerecordCount; m.Rerecords = rerecordCount;
/* /*
020 BYTE RenderMethod 020 BYTE RenderMethod
0=POST_ALL,1=PRE_ALL 0=POST_ALL,1=PRE_ALL
@ -2312,7 +2312,7 @@ namespace BizHawk.Client.Common
r.ReadByte(); r.ReadByte();
// 023 1-byte flag: 0=NTSC (60 Hz), 1="PAL" (50 Hz) // 023 1-byte flag: 0=NTSC (60 Hz), 1="PAL" (50 Hz)
bool pal = (r.ReadByte() == 1); bool pal = (r.ReadByte() == 1);
m.Header.Parameters[HeaderKeys.PAL] = pal.ToString(); m.Header[HeaderKeys.PAL] = pal.ToString();
// 024 8-bytes: reserved, set to 0 // 024 8-bytes: reserved, set to 0
r.ReadBytes(8); r.ReadBytes(8);
// 02C 4-byte little-endian integer: save state start offset // 02C 4-byte little-endian integer: save state start offset
@ -2325,7 +2325,7 @@ namespace BizHawk.Client.Common
uint frameCount = r.ReadUInt32(); uint frameCount = r.ReadUInt32();
// 03C 4-byte little-endian integer: CRC (CRC excluding this data(to prevent cheating)) // 03C 4-byte little-endian integer: CRC (CRC excluding this data(to prevent cheating))
int crc32 = r.ReadInt32(); int crc32 = r.ReadInt32();
m.Header.Parameters[CRC32] = crc32.ToString(); m.Header[CRC32] = crc32.ToString();
if (!controllersUsed[0] && !controllersUsed[1] && !controllersUsed[2] && !controllersUsed[3]) if (!controllersUsed[0] && !controllersUsed[1] && !controllersUsed[2] && !controllersUsed[3])
{ {
warningMsg = "No input recorded."; warningMsg = "No input recorded.";
@ -2469,19 +2469,19 @@ namespace BizHawk.Client.Common
fs.Close(); fs.Close();
return null; return null;
} }
m.Header.Parameters[HeaderKeys.PLATFORM] = "SNES"; m.Header[HeaderKeys.PLATFORM] = "SNES";
// 003 2-byte little-endian unsigned int: zsnes version number // 003 2-byte little-endian unsigned int: zsnes version number
short version = r.ReadInt16(); short version = r.ReadInt16();
m.Header.Comments.Add(EMULATIONORIGIN + " ZSNES version " + version); m.Header.Comments.Add(EMULATIONORIGIN + " ZSNES version " + version);
m.Header.Comments.Add(MOVIEORIGIN + " .ZMV"); m.Header.Comments.Add(MOVIEORIGIN + " .ZMV");
// 005 4-byte little-endian integer: CRC32 of the ROM // 005 4-byte little-endian integer: CRC32 of the ROM
int crc32 = r.ReadInt32(); int crc32 = r.ReadInt32();
m.Header.Parameters[CRC32] = crc32.ToString(); m.Header[CRC32] = crc32.ToString();
// 009 4-byte little-endian unsigned int: number of frames // 009 4-byte little-endian unsigned int: number of frames
uint frameCount = r.ReadUInt32(); uint frameCount = r.ReadUInt32();
// 00D 4-byte little-endian unsigned int: number of rerecords // 00D 4-byte little-endian unsigned int: number of rerecords
uint rerecordCount = r.ReadUInt32(); uint rerecordCount = r.ReadUInt32();
m.Rerecords = (int)rerecordCount; m.Rerecords = rerecordCount;
// 011 4-byte little-endian unsigned int: number of frames removed by rerecord // 011 4-byte little-endian unsigned int: number of frames removed by rerecord
r.ReadBytes(4); r.ReadBytes(4);
// 015 4-byte little-endian unsigned int: number of frames advanced step by step // 015 4-byte little-endian unsigned int: number of frames advanced step by step
@ -2558,7 +2558,7 @@ namespace BizHawk.Client.Common
// if "11", movie begins from power-on with SRAM clear // if "11", movie begins from power-on with SRAM clear
// bit 5: if "0", movie is NTSC (60 fps); if "1", movie is PAL (50 fps) // bit 5: if "0", movie is NTSC (60 fps); if "1", movie is PAL (50 fps)
bool pal = (((movieFlags >> 5) & 0x1) != 0); bool pal = (((movieFlags >> 5) & 0x1) != 0);
m.Header.Parameters[HeaderKeys.PAL] = pal.ToString(); m.Header[HeaderKeys.PAL] = pal.ToString();
// other: reserved, set to 0 // other: reserved, set to 0
/* /*
028 3-byte little-endian unsigned int: initial save state size, highest bit specifies compression, next 23 028 3-byte little-endian unsigned int: initial save state size, highest bit specifies compression, next 23
@ -2750,7 +2750,7 @@ namespace BizHawk.Client.Common
r.BaseStream.Position = r.BaseStream.Length - authorSize; r.BaseStream.Position = r.BaseStream.Length - authorSize;
// Last in the file comes the author name field, which is an UTF-8 encoded text string. // Last in the file comes the author name field, which is an UTF-8 encoded text string.
string author = Encoding.UTF8.GetString(r.ReadBytes(authorSize)); string author = Encoding.UTF8.GetString(r.ReadBytes(authorSize));
m.Header.Parameters[HeaderKeys.AUTHOR] = author; m.Header[HeaderKeys.AUTHOR] = author;
return m; return m;
} }
} }

View File

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
namespace BizHawk.Client.Common
{
public class PlatformFrameRates
{
public double this[string systemId, bool pal]
{
get
{
var key = systemId + (pal ? "_PAL" : String.Empty);
if (_rates.ContainsKey(key))
{
return _rates[key];
}
else
{
return 60.0;
}
}
}
private readonly Dictionary<string, double> _rates = new Dictionary<string, double>
{
{ "NES", 60.098813897440515532 },
{ "NES_PAL", 50.006977968268290849 },
{ "FDS", 60.098813897440515532 },
{ "FDS_PAL", 50.006977968268290849 },
{ "SNES", (double)21477272 / (4 * 341 * 262) },
{ "SNES_PAL", (double)21281370 / (4 * 341 * 312) },
{ "SGB", (double)21477272 / (4 * 341 * 262) },
{ "SGB_PAL", (double)21281370 / (4 * 341 * 312) },
{ "PCE", (7159090.90909090 / 455 / 263) }, // ~59.826
{ "PCECD", (7159090.90909090 / 455 / 263) }, // ~59.826
{ "SMS", (3579545 / 262.0 / 228.0) },
{ "SMS_PAL", (3546893 / 313.0 / 228.0) },
{ "GG", (3579545 / 262.0 / 228.0) },
{ "GG_PAL", (3546893 / 313.0 / 228.0) },
{ "SG", (3579545 / 262.0 / 228.0) },
{ "SG_PAL", (3546893 / 313.0 / 228.0) },
{ "NGP", (6144000.0 / (515 * 198)) },
{ "VBOY", (20000000 / (259 * 384 * 4)) }, // ~50.273
{ "LYNX", 59.8 },
{ "WSWAN", (3072000.0 / (159 * 256)) },
{ "GB", 262144.0 / 4389.0 },
{ "GBC", 262144.0 / 4389.0 },
{ "GBA", 262144.0 / 4389.0 },
{ "A26", 59.9227510135505 },
{ "A78", 59.9227510135505 },
{ "Coleco", 59.9227510135505 }
};
}
}

View File

@ -503,11 +503,11 @@ namespace BizHawk.Client.EmuHawk
{ {
if (Global.MovieSession.Movie.IsActive) if (Global.MovieSession.Movie.IsActive)
{ {
return "Rerecord Count: " + Global.MovieSession.Movie.Rerecords.ToString(); return "Rerecord Count: " + Global.MovieSession.Movie.Rerecords;
} }
else else
{ {
return ""; return String.Empty;
} }
} }

View File

@ -38,7 +38,7 @@ namespace BizHawk.Client.EmuHawk
LoadRom(GlobalWin.MainForm.CurrentlyOpenRom, true, !record); LoadRom(GlobalWin.MainForm.CurrentlyOpenRom, true, !record);
Global.Config.RecentMovies.Add(m.Filename); Global.Config.RecentMovies.Add(m.Filename);
if (Global.MovieSession.Movie.StartsFromSavestate) if (Global.MovieSession.Movie.Header.StartsFromSavestate)
{ {
LoadStateFile(Global.MovieSession.Movie.Filename, Path.GetFileName(Global.MovieSession.Movie.Filename)); LoadStateFile(Global.MovieSession.Movie.Filename, Path.GetFileName(Global.MovieSession.Movie.Filename));
Global.Emulator.ResetCounters(); Global.Emulator.ResetCounters();
@ -112,7 +112,7 @@ namespace BizHawk.Client.EmuHawk
if (Global.MovieSession.Movie.IsActive) if (Global.MovieSession.Movie.IsActive)
{ {
LoadRom(CurrentlyOpenRom, true, true); LoadRom(CurrentlyOpenRom, true, true);
if (Global.MovieSession.Movie.StartsFromSavestate) if (Global.MovieSession.Movie.Header.StartsFromSavestate)
{ {
LoadStateFile(Global.MovieSession.Movie.Filename, Path.GetFileName(Global.MovieSession.Movie.Filename)); LoadStateFile(Global.MovieSession.Movie.Filename, Path.GetFileName(Global.MovieSession.Movie.Filename));
Global.Emulator.ResetCounters(); Global.Emulator.ResetCounters();
@ -136,7 +136,7 @@ namespace BizHawk.Client.EmuHawk
switch (Global.Emulator.SystemId) switch (Global.Emulator.SystemId)
{ {
case "Coleco": case "Coleco":
string str = Global.MovieSession.Movie.Header.Parameters[HeaderKeys.SKIPBIOS]; string str = Global.MovieSession.Movie.Header[HeaderKeys.SKIPBIOS];
if (!String.IsNullOrWhiteSpace(str)) if (!String.IsNullOrWhiteSpace(str))
{ {
if (str.ToLower() == "true") if (str.ToLower() == "true")

View File

@ -1829,9 +1829,9 @@ namespace BizHawk.Client.EmuHawk
{ {
var PluginToUse = String.Empty; var PluginToUse = String.Empty;
if (hasmovie && Global.MovieSession.Movie.Header.Parameters[HeaderKeys.PLATFORM] == "N64" && Global.MovieSession.Movie.Header.Parameters.ContainsKey(HeaderKeys.VIDEOPLUGIN)) if (hasmovie && Global.MovieSession.Movie.Header[HeaderKeys.PLATFORM] == "N64" && Global.MovieSession.Movie.Header.ContainsKey(HeaderKeys.VIDEOPLUGIN))
{ {
PluginToUse = Global.MovieSession.Movie.Header.Parameters[HeaderKeys.VIDEOPLUGIN]; PluginToUse = Global.MovieSession.Movie.Header[HeaderKeys.VIDEOPLUGIN];
} }
if (PluginToUse == "" || (PluginToUse != "Rice" && PluginToUse != "Glide64")) if (PluginToUse == "" || (PluginToUse != "Rice" && PluginToUse != "Glide64"))
@ -1857,14 +1857,14 @@ namespace BizHawk.Client.EmuHawk
video_settings.Parameters = Global.Config.Glide64mk2Plugin.GetPluginSettings(); video_settings.Parameters = Global.Config.Glide64mk2Plugin.GetPluginSettings();
} }
if (hasmovie && Global.MovieSession.Movie.Header.Parameters[HeaderKeys.PLATFORM] == "N64" && Global.MovieSession.Movie.Header.Parameters.ContainsKey(HeaderKeys.VIDEOPLUGIN)) if (hasmovie && Global.MovieSession.Movie.Header[HeaderKeys.PLATFORM] == "N64" && Global.MovieSession.Movie.Header.ContainsKey(HeaderKeys.VIDEOPLUGIN))
{ {
var settings = new List<string>(video_settings.Parameters.Keys); var settings = new List<string>(video_settings.Parameters.Keys);
foreach (var setting in settings) foreach (var setting in settings)
{ {
if (Global.MovieSession.Movie.Header.Parameters.ContainsKey(setting)) if (Global.MovieSession.Movie.Header.ContainsKey(setting))
{ {
var Value = Global.MovieSession.Movie.Header.Parameters[setting]; var Value = Global.MovieSession.Movie.Header[setting];
if (video_settings.Parameters[setting] is bool) if (video_settings.Parameters[setting] is bool)
{ {
try try

View File

@ -174,7 +174,7 @@ namespace BizHawk.Client.EmuHawk
try try
{ {
//Don't do this from browse //Don't do this from browse
if (movie.Header.Parameters[HeaderKeys.GAMENAME] == Global.Game.Name || if (movie.Header[HeaderKeys.GAMENAME] == Global.Game.Name ||
Global.Config.PlayMovie_MatchGameName == false || force) Global.Config.PlayMovie_MatchGameName == false || force)
{ {
_movieList.Add(movie); _movieList.Add(movie);
@ -333,9 +333,8 @@ namespace BizHawk.Client.EmuHawk
int firstIndex = MovieView.SelectedIndices[0]; int firstIndex = MovieView.SelectedIndices[0];
MovieView.ensureVisible(firstIndex); MovieView.ensureVisible(firstIndex);
var headers = _movieList[firstIndex].Header.Parameters;
foreach (var kvp in headers) foreach (var kvp in _movieList[firstIndex].Header)
{ {
var item = new ListViewItem(kvp.Key); var item = new ListViewItem(kvp.Key);
item.SubItems.Add(kvp.Value); item.SubItems.Add(kvp.Value);

View File

@ -94,73 +94,73 @@ namespace BizHawk.Client.EmuHawk
} }
//Header //Header
_movieToRecord.Header.Parameters[HeaderKeys.AUTHOR] = AuthorBox.Text; _movieToRecord.Header[HeaderKeys.AUTHOR] = AuthorBox.Text;
_movieToRecord.Header.Parameters[HeaderKeys.EMULATIONVERSION] = VersionInfo.GetEmuVersion(); _movieToRecord.Header[HeaderKeys.EMULATIONVERSION] = VersionInfo.GetEmuVersion();
_movieToRecord.Header.Parameters[HeaderKeys.MOVIEVERSION] = HeaderKeys.MovieVersion; _movieToRecord.Header[HeaderKeys.MOVIEVERSION] = HeaderKeys.MovieVersion;
_movieToRecord.Header.Parameters[HeaderKeys.GUID] = HeaderKeys.NewGuid; _movieToRecord.Header[HeaderKeys.GUID] = HeaderKeys.NewGuid;
_movieToRecord.Header.Parameters[HeaderKeys.PLATFORM] = Global.Game.System; _movieToRecord.Header[HeaderKeys.PLATFORM] = Global.Game.System;
if (Global.Game != null) if (Global.Game != null)
{ {
_movieToRecord.Header.Parameters[HeaderKeys.GAMENAME] = PathManager.FilesystemSafeName(Global.Game); _movieToRecord.Header[HeaderKeys.GAMENAME] = PathManager.FilesystemSafeName(Global.Game);
_movieToRecord.Header.Parameters[HeaderKeys.SHA1] = Global.Game.Hash; _movieToRecord.Header[HeaderKeys.SHA1] = Global.Game.Hash;
if (Global.Game.FirmwareHash != null) if (Global.Game.FirmwareHash != null)
{ {
_movieToRecord.Header.Parameters[HeaderKeys.FIRMWARESHA1] = Global.Game.FirmwareHash; _movieToRecord.Header[HeaderKeys.FIRMWARESHA1] = Global.Game.FirmwareHash;
} }
} }
else else
{ {
_movieToRecord.Header.Parameters[HeaderKeys.GAMENAME] = "NULL"; _movieToRecord.Header[HeaderKeys.GAMENAME] = "NULL";
} }
if (Global.Emulator.BoardName != null) if (Global.Emulator.BoardName != null)
{ {
_movieToRecord.Header.Parameters[HeaderKeys.BOARDNAME] = Global.Emulator.BoardName; _movieToRecord.Header[HeaderKeys.BOARDNAME] = Global.Emulator.BoardName;
} }
if (Global.Emulator is Gameboy) if (Global.Emulator is Gameboy)
{ {
_movieToRecord.Header.Parameters[HeaderKeys.GB_FORCEDMG] = Global.Config.GB_ForceDMG.ToString(); _movieToRecord.Header[HeaderKeys.GB_FORCEDMG] = Global.Config.GB_ForceDMG.ToString();
_movieToRecord.Header.Parameters[HeaderKeys.GB_GBA_IN_CGB] = Global.Config.GB_GBACGB.ToString(); _movieToRecord.Header[HeaderKeys.GB_GBA_IN_CGB] = Global.Config.GB_GBACGB.ToString();
} }
if (Global.Emulator is LibsnesCore) if (Global.Emulator is LibsnesCore)
{ {
_movieToRecord.Header.Parameters[HeaderKeys.SGB] = ((Global.Emulator) as LibsnesCore).IsSGB.ToString(); _movieToRecord.Header[HeaderKeys.SGB] = ((Global.Emulator) as LibsnesCore).IsSGB.ToString();
if ((Global.Emulator as LibsnesCore).DisplayType == DisplayType.PAL) if ((Global.Emulator as LibsnesCore).DisplayType == DisplayType.PAL)
{ {
_movieToRecord.Header.Parameters[HeaderKeys.PAL] = "1"; _movieToRecord.Header[HeaderKeys.PAL] = "1";
} }
} }
else if (Global.Emulator is SMS) else if (Global.Emulator is SMS)
{ {
if ((Global.Emulator as SMS).DisplayType == DisplayType.PAL) if ((Global.Emulator as SMS).DisplayType == DisplayType.PAL)
{ {
_movieToRecord.Header.Parameters[HeaderKeys.PAL] = "1"; _movieToRecord.Header[HeaderKeys.PAL] = "1";
} }
} }
else if (Global.Emulator is NES) else if (Global.Emulator is NES)
{ {
if ((Global.Emulator as NES).DisplayType == DisplayType.PAL) if ((Global.Emulator as NES).DisplayType == DisplayType.PAL)
{ {
_movieToRecord.Header.Parameters[HeaderKeys.PAL] = "1"; _movieToRecord.Header[HeaderKeys.PAL] = "1";
} }
} }
else if (Global.Emulator is ColecoVision) else if (Global.Emulator is ColecoVision)
{ {
_movieToRecord.Header.Parameters[HeaderKeys.SKIPBIOS] = Global.Config.ColecoSkipBiosIntro.ToString(); _movieToRecord.Header[HeaderKeys.SKIPBIOS] = Global.Config.ColecoSkipBiosIntro.ToString();
} }
else if (Global.Emulator is N64) else if (Global.Emulator is N64)
{ {
_movieToRecord.Header.Parameters[HeaderKeys.VIDEOPLUGIN] = Global.Config.N64VidPlugin; _movieToRecord.Header[HeaderKeys.VIDEOPLUGIN] = Global.Config.N64VidPlugin;
if (Global.Config.N64VidPlugin == "Rice") if (Global.Config.N64VidPlugin == "Rice")
{ {
var rice_settings = Global.Config.RicePlugin.GetPluginSettings(); var rice_settings = Global.Config.RicePlugin.GetPluginSettings();
foreach(var setting in rice_settings) foreach(var setting in rice_settings)
{ {
_movieToRecord.Header.Parameters[setting.Key] = setting.Value.ToString(); _movieToRecord.Header[setting.Key] = setting.Value.ToString();
} }
} }
else if (Global.Config.N64VidPlugin == "Glide64") else if (Global.Config.N64VidPlugin == "Glide64")
@ -168,13 +168,13 @@ namespace BizHawk.Client.EmuHawk
var glide_settings = Global.Config.GlidePlugin.GetPluginSettings(); var glide_settings = Global.Config.GlidePlugin.GetPluginSettings();
foreach (var setting in glide_settings) foreach (var setting in glide_settings)
{ {
_movieToRecord.Header.Parameters[setting.Key] = setting.Value.ToString(); _movieToRecord.Header[setting.Key] = setting.Value.ToString();
} }
} }
if ((Global.Emulator as N64).DisplayType == DisplayType.PAL) if ((Global.Emulator as N64).DisplayType == DisplayType.PAL)
{ {
_movieToRecord.Header.Parameters[HeaderKeys.PAL] = "1"; _movieToRecord.Header[HeaderKeys.PAL] = "1";
} }
} }