diff --git a/BizHawk.MultiClient/movie/MovieImport.cs b/BizHawk.MultiClient/movie/MovieImport.cs index 6a3c5c2191..1272beba4c 100644 --- a/BizHawk.MultiClient/movie/MovieImport.cs +++ b/BizHawk.MultiClient/movie/MovieImport.cs @@ -851,12 +851,98 @@ namespace BizHawk.MultiClient } // MCM file format: http://code.google.com/p/mednafen-rr/wiki/MCM + // Mednafen-rr switched to MC2 from r261, so see r260 for details. private static Movie ImportMCM(string path, out string errorMsg, out string warningMsg) { + const string SIGNATURE = "MDFNMOVI"; + const int MOVIE_VERSION = 1; + const string CONSOLE_PCE = "pce"; + const string CTRL_TYPE_PCE = "PC Engine Controller"; + string[] CTRL_BUTTONS = { + "B1", "B2", "Select", "Run", "Up", "Right", "Down", "Left" + }; + const int INPUT_SIZE_PCE = 11; + const int INPUT_PORT_COUNT = 5; + errorMsg = ""; warningMsg = ""; Movie m = new Movie(Path.ChangeExtension(path, ".tas"), MOVIEMODE.PLAY); + + // Unless otherwise noted, all values are little-endian. + FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read); + BinaryReader r = new BinaryReader(fs); + // 000 8-byte signature: 4D 44 46 4E 4D 4F 56 49 "MDFNMOVI" + string signature = r.ReadStringFixedAscii(SIGNATURE.Length); + if (signature != SIGNATURE) + { + errorMsg = "This is not a valid .MCM file."; + goto FAIL; + } + // 008 uint32: emulator version, current is 0x0000080A + uint emuVersion = r.ReadUInt32(); + m.Header.Comments.Add(EMULATIONORIGIN + " Mednafen " + emuVersion.ToString()); + // 00C uint32: movie format version, must be 1 + uint version = r.ReadUInt32(); + if (version != MOVIE_VERSION) + { + errorMsg = ".MCM movie version must always be 1."; + goto FAIL; + } + m.Header.Comments.Add(MOVIEORIGIN + " .MCM version " + version); + // 010 32-byte (actually, 16-byte) md5sum of the ROM used + byte[] MD5 = r.ReadBytes(16); + r.ReadBytes(16); // discard + m.Header.SetHeaderLine("MD5", BizHawk.Util.BytesToHexString(MD5).ToLower()); + // 030 64-byte filename of ROM used (with extension) + string gameName = RemoveNull(r.ReadStringFixedAscii(64)); + m.Header.SetHeaderLine(MovieHeader.GAMENAME, gameName); + // 070 uint32: re-record count + uint rerecordCount = r.ReadUInt32(); + m.SetRerecords((int)rerecordCount); + // 074 5-byte console indicator (pce, ngp, pcfx, wswan) + string console = RemoveNull(r.ReadStringFixedAscii(5)); + if (console != CONSOLE_PCE) // for now, bizhawk does not support ngp, pcfx, wswan + { + errorMsg = "Only PCE movies are supported."; + goto FAIL; + } + string platform = "PCE"; + m.Header.SetHeaderLine(MovieHeader.PLATFORM, platform); + // 079 32-byte author name + string author = RemoveNull(r.ReadStringFixedAscii(32)); + m.Header.SetHeaderLine(MovieHeader.AUTHOR, author); + // 099 103-byte padding 0s + r.ReadBytes(103); // discard + + // 100 variable: input data + // For PCE, BizHawk does not have any control command. So I ignore any command. + for (byte[] input = r.ReadBytes(INPUT_SIZE_PCE); + input.Length == INPUT_SIZE_PCE; + input = r.ReadBytes(INPUT_SIZE_PCE)) + { + SimpleController controllers = new SimpleController(); + controllers.Type = new ControllerDefinition(); + controllers.Type.Name = CTRL_TYPE_PCE; + for (int player = 1; player <= INPUT_PORT_COUNT; ++player) + { + byte pad = input[1+2*(player-1)]; + for(int i = 0; i < 8; ++i) + { + if ((pad & (1<