From 145830d5a4a0aecca96272f9123bfe34895b0585 Mon Sep 17 00:00:00 2001 From: brandman211 Date: Wed, 15 Feb 2012 06:54:09 +0000 Subject: [PATCH] -Began working on the importer. --Created ImportFile to decide what function to use for each filetype. ---It currently automatically writes to a .TAS file, but that option will eventually only be applied when specified in the GUI, hopefully completely external from this class. --Made IsValidMovieExtension work. --Created LoadText to do the majority of the work that both .FM2 and .MC2 need to be done. --.MC2 seems to work perfectly, not that it was a hard conversion! --.FM2 seems to convert most headers correct, except for subtitles, which replaces the beginning portions of each subtitle's text with 0 0 120 4294967295. Not sure what that's about, though this sure feels like deja vu... --I still need to switch around the order of the buttons the frames are added, but I need to find out what way I can do this without reinventing the wheel. -Added the FixMnemonic function to Movie.cs. It currently does nothing, but my goal is to have it correct the mnemonic for all frames in a movie file based on the position of the characters. --As of right now, ImportFile uses this. -MainForm.IsValidMovieExtension only checks whether or not its .TAS or not now. TODO: -Fix the FM2 subtitles. -Shift around the FM2 buttons. --After completed, test a .FM2 file that should sync and see if it works, with and without FixMnemonic being used. -Make FixMnemonic actually do something. -Refactor code? I originally thought it'd be best to treat Movie.LoadText just like any other importer, but I think at this point it might just be best to keep these things completely separate. -Consider the possibility of working with the binary file importers. --Yes adelikat, I am somewhat interested, especially considering how useful it would be to have a working .FCM importer so I can compare old runs when TASing. I already was hoping to learn about .VBM and .SMV for my ButtonCount.lua script. By the way, might this be bundled with bizhawk as it is with FCEUX 2.1.6? :) --- BizHawk.MultiClient/MainForm.cs | 9 +- BizHawk.MultiClient/movie/Movie.cs | 14 +- BizHawk.MultiClient/movie/MovieImport.cs | 191 +++++++++++++++++++---- 3 files changed, 173 insertions(+), 41 deletions(-) diff --git a/BizHawk.MultiClient/MainForm.cs b/BizHawk.MultiClient/MainForm.cs index 209b8ee5ed..600c97b59e 100644 --- a/BizHawk.MultiClient/MainForm.cs +++ b/BizHawk.MultiClient/MainForm.cs @@ -722,14 +722,7 @@ namespace BizHawk.MultiClient private bool IsValidMovieExtension(string ext) { - switch (ext.ToUpper()) - { - case ".TAS": //Bizhawk - case ".MC2": //PCEjin - return true; - default: - return false; - } + return (ext.ToUpper() == ".TAS"); } private void FormDragDrop(object sender, DragEventArgs e) diff --git a/BizHawk.MultiClient/movie/Movie.cs b/BizHawk.MultiClient/movie/Movie.cs index 33369c9c51..6d423db5e4 100644 --- a/BizHawk.MultiClient/movie/Movie.cs +++ b/BizHawk.MultiClient/movie/Movie.cs @@ -65,6 +65,7 @@ namespace BizHawk.MultiClient { return Header.GetHeaderLine(MovieHeader.GAMENAME); } + public int Length() { if (Loaded) @@ -328,6 +329,15 @@ namespace BizHawk.MultiClient return LoadText(); } + public void FixMnemonic() + { + int frame = 0; + while (frame < Log.Length()) + { + // TODO: Correct mnemonics, using Log.GetFrame(frame))? + } + lastLog = frame; + } public void DumpLogIntoSavestateText(TextWriter writer) { @@ -764,7 +774,7 @@ namespace BizHawk.MultiClient return 0; } - private string ParseHeader(string line, string headerName) + private static string ParseHeader(string line, string headerName) { string str; int x = line.LastIndexOf(headerName) + headerName.Length; @@ -778,4 +788,4 @@ namespace BizHawk.MultiClient Header.AddHeaderLine(MovieHeader.STARTSFROMSAVESTATE, "1"); } } -} +} \ No newline at end of file diff --git a/BizHawk.MultiClient/movie/MovieImport.cs b/BizHawk.MultiClient/movie/MovieImport.cs index c689193a15..a62e4ebbe9 100644 --- a/BizHawk.MultiClient/movie/MovieImport.cs +++ b/BizHawk.MultiClient/movie/MovieImport.cs @@ -12,30 +12,139 @@ namespace BizHawk.MultiClient { public static Movie ImportFile(string path, out string errorMsg) { - //TODO: This function will receive a file, parse the file extension, - //then decide which import function to call, call it, and return a movie object - //the multiclient should only call this and not the import members (make them private) + Movie mov; errorMsg = ""; - return new Movie(); + switch (Path.GetExtension(path).ToUpper()) + { + case ".FCM": + mov = ImportFCM(path, out errorMsg); + break; + case ".FM2": + mov = ImportFM2(path, out errorMsg); + break; + case ".GMV": + mov = ImportGMV(path, out errorMsg); + break; + case ".MCM": + mov = ImportMCM(path, out errorMsg); + break; + case ".MC2": + mov = ImportMC2(path, out errorMsg); + break; + case ".MMV": + mov = ImportMMV(path, out errorMsg); + break; + case ".SMV": + // TODO: Decide which SMV parser to use. Perhaps have one parent function that decides. + mov = new Movie(); + break; + case ".VBM": + mov = ImportVBM(path, out errorMsg); + break; + default: + mov = new Movie(); + break; + } + mov.FixMnemonic(); + mov.WriteMovie(); + return mov; } public static bool IsValidMovieExtension(string extension) { - switch (extension.ToUpper()) + string[] extensions = {"FCM", "FM2", "GMV", "MC2", "MMV", "TAS", "VBM"}; + foreach (string ext in extensions) { - case "TAS": - case "FM2": - case "FCM": - case "MMV": - case "GMV": - case "MC2": - case "VBM": + if (extension.ToUpper() == "." + ext) + { return true; - default: - return false; + } } + return false; } - + + private static string ParseHeader(string line, string headerName) + { + string str; + int x = line.LastIndexOf(headerName) + headerName.Length; + str = line.Substring(x + 1, line.Length - x - 1); + return str; + } + + + private static Movie ImportText(string path, out string errorMsg, string emulator) + { + errorMsg = ""; + Movie m = new Movie(Path.ChangeExtension(path, ".tas"), MOVIEMODE.PLAY); + var file = new FileInfo(path); + using (StreamReader sr = file.OpenText()) + { + string str = ""; + string rerecordStr = ""; + while ((str = sr.ReadLine()) != null) + { + if (str == "") + { + continue; + } + if (str.Contains("rerecordCount")) + { + rerecordStr = ParseHeader(str, "rerecordCount"); + try + { + m.SetRerecords(int.Parse(rerecordStr)); + } + catch + { + m.SetRerecords(0); + } + } + else if (str.Contains("StartsFromSavestate")) + { + str = ParseHeader(str, "StartsFromSavestate"); + if (str == "1") + { + errorMsg = "Movies that begin with a savestate are not supported."; + return null; + } + } + if (str.StartsWith("emuVersion")) + { + m.Header.SetHeaderLine(MovieHeader.EMULATIONVERSION, emulator + " version " + ParseHeader(str, "emuVersion")); + } + else if (str.StartsWith("version")) + { + m.Header.SetHeaderLine(MovieHeader.MOVIEVERSION, ParseHeader(str, "version")); + } + else if (str.StartsWith("romFilename")) + { + m.Header.SetHeaderLine(MovieHeader.GAMENAME, ParseHeader(str, "romFilename")); + } + else if (str.StartsWith("comment author")) + { + m.Header.SetHeaderLine(MovieHeader.AUTHOR, ParseHeader(str, "comment author")); + } + else if (str.StartsWith("guid")) + { + m.Header.SetHeaderLine(MovieHeader.GUID, ParseHeader(str, "GUID")); + } + else if (str.StartsWith("subtitle") || str.StartsWith("sub")) + { + m.Subtitles.AddSubtitle(str); + } + else if (str[0] == '|') + { + m.AppendFrame(str); + } + else + { + m.Header.Comments.Add(str); + } + } + } + return m; + } + private static Movie ImportFCM(string path, out string errorMsg) { errorMsg = ""; @@ -158,6 +267,41 @@ namespace BizHawk.MultiClient } } + private static Movie ImportFM2(string path, out string errorMsg) + { + errorMsg = ""; + Movie m = ImportText(path, out errorMsg, "FCEUX"); + m.Header.SetHeaderLine(MovieHeader.PLATFORM, "NES"); + // TODO: Mnemonic switches. + // FM2 file format: http://www.fceux.com/web/FM2.html + return m; + } + + private static Movie ImportGMV(string path, out string errorMsg) + { + errorMsg = ""; + Movie m = new Movie(Path.ChangeExtension(path, ".tas"), MOVIEMODE.PLAY); + + return m; + } + + private static Movie ImportMCM(string path, out string errorMsg) + { + errorMsg = ""; + Movie m = new Movie(Path.ChangeExtension(path, ".tas"), MOVIEMODE.PLAY); + return m; + } + + private static Movie ImportMC2(string path, out string errorMsg) + { + errorMsg = ""; + Movie m = ImportText(path, out errorMsg, "Mednafen/PCEjin"); + m.Header.SetHeaderLine(MovieHeader.PLATFORM, "MC2"); + // TODO: PCECD equivalent. + // MC2 file format: http://code.google.com/p/pcejin/wiki/MC2 + return m; + } + private static Movie ImportMMV(string path, out string errorMsg) { errorMsg = ""; @@ -284,13 +428,6 @@ namespace BizHawk.MultiClient return m; } - private static string ImportMCM(string path) - { - string converted = Path.ChangeExtension(path, ".tas"); - - return converted; - } - private static Movie ImportSMV(string path, out string errorMSG) { errorMSG = ""; @@ -400,14 +537,6 @@ namespace BizHawk.MultiClient return m; } - private static Movie ImportGMV(string path, out string errorMsg) - { - errorMsg = ""; - Movie m = new Movie(Path.ChangeExtension(path, ".tas"), MOVIEMODE.PLAY); - - return m; - } - private static Movie ImportVBM(string path, out string errorMsg) { errorMsg = ""; @@ -576,4 +705,4 @@ namespace BizHawk.MultiClient return m; } } -} +} \ No newline at end of file