public void PutSettings(Gameboy.GambatteSettings s, Gameboy.GambatteSyncSettings ss) { this.s = s ?? new Gameboy.GambatteSettings(); this.ss = ss ?? new Gameboy.GambatteSyncSettings(); propertyGrid1.SelectedObject = this.ss; propertyGrid1.Enabled = !Global.MovieSession.Movie.IsActive; }
public void PutSettings(Gameboy.GambatteSettings s, Gameboy.GambatteSyncSettings ss) { this.s = s ?? new Gameboy.GambatteSettings(); this.ss = ss ?? new Gameboy.GambatteSyncSettings(); propertyGrid1.SelectedObject = this.ss; propertyGrid1.Enabled = !Global.MovieSession.Movie.IsActive; checkBoxMuted.Checked = this.s.Muted; cbDisplayBG.Checked = this.s.DisplayBG; cbDisplayOBJ.Checked = this.s.DisplayOBJ; }
public void PutSettings(Gameboy.GambatteSettings s, Gameboy.GambatteSyncSettings ss) { _s = s ?? new Gameboy.GambatteSettings(); _ss = ss ?? new Gameboy.GambatteSyncSettings(); propertyGrid1.SelectedObject = _ss; propertyGrid1.Enabled = GlobalWin.MovieSession.Movie.NotActive(); checkBoxMuted.Checked = _s.Muted; cbDisplayBG.Checked = _s.DisplayBG; cbDisplayOBJ.Checked = _s.DisplayOBJ; cbDisplayWIN.Checked = _s.DisplayWindow; }
public void PutSettings(Config config, IGameInfo game, IMovieSession movieSession, Gameboy.GambatteSettings s, Gameboy.GambatteSyncSettings ss) { _game = game; _config = config; _movieSession = movieSession; _s = s ?? new Gameboy.GambatteSettings(); _ss = ss ?? new Gameboy.GambatteSyncSettings(); propertyGrid1.SelectedObject = _ss; propertyGrid1.Enabled = movieSession.Movie.NotActive(); checkBoxMuted.Checked = _s.Muted; }
public void GetSettings(out Gameboy.GambatteSettings s, out Gameboy.GambatteSyncSettings ss) { s = _s; ss = _ss; }
protected override void RunImport() { using var fs = SourceFile.Open(FileMode.Open, FileAccess.Read); using var r = new BinaryReader(fs); bool is_GBC = false; // 000 4-byte signature: 56 42 4D 1A "VBM\x1A" string signature = new string(r.ReadChars(4)); if (signature != "VBM\x1A") { Result.Errors.Add("This is not a valid .VBM file."); return; } // 004 4-byte little-endian unsigned int: major version number, must be "1" uint majorVersion = r.ReadUInt32(); if (majorVersion != 1) { Result.Errors.Add(".VBM major movie version must be 1."); return; } /* * 008 4-byte little-endian integer: movie "uid" - identifies the movie-savestate relationship, also used as the * recording time in Unix epoch format */ uint uid = r.ReadUInt32(); // 00C 4-byte little-endian unsigned int: number of frames uint frameCount = r.ReadUInt32(); // 010 4-byte little-endian unsigned int: rerecord count uint rerecordCount = r.ReadUInt32(); Result.Movie.Rerecords = rerecordCount; // 014 1-byte flags: (movie start flags) byte flags = r.ReadByte(); // bit 0: if "1", movie starts from an embedded "quicksave" snapshot bool startFromSavestate = (flags & 0x1) != 0; // bit 1: if "1", movie starts from reset with an embedded SRAM bool startFromSram = ((flags >> 1) & 0x1) != 0; // other: reserved, set to 0 // (If both bits 0 and 1 are "1", the movie file is invalid) if (startFromSavestate && startFromSram) { Result.Errors.Add("This is not a valid .VBM file."); return; } if (startFromSavestate) { Result.Errors.Add("Movies that begin with a savestate are not supported."); return; } if (startFromSram) { Result.Errors.Add("Movies that begin with SRAM are not supported."); return; } // 015 1-byte flags: controller flags byte controllerFlags = r.ReadByte(); /* * bit 0: controller 1 in use * bit 1: controller 2 in use (SGB games can be 2-player multiplayer) * bit 2: controller 3 in use (SGB games can be 3- or 4-player multiplayer with multitap) * bit 3: controller 4 in use (SGB games can be 3- or 4-player multiplayer with multitap) */ bool[] controllersUsed = new bool[4]; for (int controller = 1; controller <= controllersUsed.Length; controller++) { controllersUsed[controller - 1] = ((controllerFlags >> (controller - 1)) & 0x1) != 0; } if (!controllersUsed[0]) { Result.Errors.Add("Controller 1 must be in use."); return; } // other: reserved // 016 1-byte flags: system flags (game always runs at 60 frames/sec) flags = r.ReadByte(); // bit 0: if "1", movie is for the GBA system bool isGBA = (flags & 0x1) != 0; // bit 1: if "1", movie is for the GBC system bool isGBC = ((flags >> 1) & 0x1) != 0; // bit 2: if "1", movie is for the SGB system bool isSGB = ((flags >> 2) & 0x1) != 0; // (If all 3 of these bits are "0", it is for regular GB.) string platform = "GB"; if (isGBA) { platform = "GBA"; var mGBAName = ((CoreAttribute)Attribute.GetCustomAttribute(typeof(MGBAHawk), typeof(CoreAttribute))).CoreName; Result.Movie.HeaderEntries[HeaderKeys.Core] = mGBAName; } if (isGBC) { is_GBC = true; platform = "GB"; Result.Movie.HeaderEntries.Add("IsCGBMode", "1"); } if (isSGB) { Result.Errors.Add("SGB imports are not currently supported"); } Result.Movie.HeaderEntries[HeaderKeys.Platform] = platform; // 017 1-byte flags: (values of some boolean emulator options) flags = r.ReadByte(); /* * bit 0: (useBiosFile) if "1" and the movie is of a GBA game, the movie was made using a GBA BIOS file. * bit 1: (skipBiosFile) if "0" and the movie was made with a GBA BIOS file, the BIOS intro is included in the * movie. * bit 2: (rtcEnable) if "1", the emulator "real time clock" feature was enabled. * bit 3: (unsupported) must be "0" or the movie file is considered invalid (legacy). */ if (((flags >> 3) & 0x1) != 0) { Result.Errors.Add("This is not a valid .VBM file."); return; } /* * 018 4-byte little-endian unsigned int: theApp.winSaveType (value of that emulator option) * 01C 4-byte little-endian unsigned int: theApp.winFlashSize (value of that emulator option) * 020 4-byte little-endian unsigned int: gbEmulatorType (value of that emulator option) */ r.ReadBytes(12); /* * 024 12-byte character array: the internal game title of the ROM used while recording, not necessarily * null-terminated (ASCII?) */ string gameName = NullTerminated(new string(r.ReadChars(12))); Result.Movie.HeaderEntries[HeaderKeys.GameName] = gameName; // 030 1-byte unsigned char: minor version/revision number of current VBM version, the latest is "1" byte minorVersion = r.ReadByte(); Result.Movie.Comments.Add($"{MovieOrigin} .VBM version {majorVersion}.{minorVersion}"); Result.Movie.Comments.Add($"{EmulationOrigin} Visual Boy Advance"); // 031 1-byte unsigned char: the internal CRC of the ROM used while recording r.ReadByte(); /* * 032 2-byte little-endian unsigned short: the internal Checksum of the ROM used while recording, or a * calculated CRC16 of the BIOS if GBA */ ushort checksumCRC16 = r.ReadUInt16(); /* * 034 4-byte little-endian unsigned int: the Game Code of the ROM used while recording, or the Unit Code if not * GBA */ uint gameCodeUnitCode = r.ReadUInt32(); if (platform == "GBA") { Result.Movie.HeaderEntries["CRC16"] = checksumCRC16.ToString(); Result.Movie.HeaderEntries["GameCode"] = gameCodeUnitCode.ToString(); } else { Result.Movie.HeaderEntries["InternalChecksum"] = checksumCRC16.ToString(); Result.Movie.HeaderEntries["UnitCode"] = gameCodeUnitCode.ToString(); } // 038 4-byte little-endian unsigned int: offset to the savestate or SRAM inside file, set to 0 if unused r.ReadBytes(4); // 03C 4-byte little-endian unsigned int: offset to the controller data inside file 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). string author = NullTerminated(new string(r.ReadChars(64))); Result.Movie.HeaderEntries[HeaderKeys.Author] = author; // The following 128 bytes are for a description of the movie. Both parts must be null-terminated. string movieDescription = NullTerminated(new string(r.ReadChars(128))); Result.Movie.Comments.Add(movieDescription); r.BaseStream.Position = firstFrameOffset; SimpleController controllers = isGBA ? GbaController() : GbController(); /* * 01 00 A * 02 00 B * 04 00 Select * 08 00 Start * 10 00 Right * 20 00 Left * 40 00 Up * 80 00 Down * 00 01 R * 00 02 L */ string[] buttons = { "A", "B", "Select", "Start", "Right", "Left", "Up", "Down", "R", "L" }; /* * 00 04 Reset (old timing) * 00 08 Reset (new timing since version 1.1) * 00 10 Left motion sensor * 00 20 Right motion sensor * 00 40 Down motion sensor * 00 80 Up motion sensor */ string[] other = { "Reset (old timing)", "Reset (new timing since version 1.1)", "Left motion sensor", "Right motion sensor", "Down motion sensor", "Up motion sensor" }; for (int frame = 1; frame <= frameCount; frame++) { /* * A stream of 2-byte bitvectors which indicate which buttons are pressed at each point in time. They will * come in groups of however many controllers are active, in increasing order. */ ushort controllerState = r.ReadUInt16(); for (int button = 0; button < buttons.Length; button++) { controllers[buttons[button]] = ((controllerState >> button) & 0x1) != 0; if (((controllerState >> button) & 0x1) != 0 && button > 7) { continue; } } // TODO: Handle the other buttons. for (int button = 0; button < other.Length; button++) { if (((controllerState >> (button + 10)) & 0x1) != 0) { Result.Warnings.Add($"Unable to import {other[button]} at frame {frame}."); break; } } // TODO: Handle the additional controllers. for (int player = 2; player <= controllersUsed.Length; player++) { if (controllersUsed[player - 1]) { r.ReadBytes(2); } } Result.Movie.AppendFrame(controllers); } if (isGBA) { Config.PreferredCores["GBA"] = CoreNames.Mgba; var ss = new MGBAHawk.SyncSettings { SkipBios = true }; Result.Movie.SyncSettingsJson = ConfigService.SaveWithType(ss); } else { if (Config.PreferredCores["GB"] == CoreNames.GbHawk || Config.PreferredCores["GB"] == CoreNames.SubGbHawk) { var tempSync = new GBHawk.GBSyncSettings(); if (is_GBC) { tempSync.ConsoleMode = GBHawk.GBSyncSettings.ConsoleModeType.GBC; } else { tempSync.ConsoleMode = GBHawk.GBSyncSettings.ConsoleModeType.GB; } Result.Movie.SyncSettingsJson = ConfigService.SaveWithType(tempSync); } else { var temp_sync = new Gameboy.GambatteSyncSettings(); if (is_GBC) { temp_sync.ConsoleMode = Gameboy.GambatteSyncSettings.ConsoleModeType.GBC; } else { temp_sync.ConsoleMode = Gameboy.GambatteSyncSettings.ConsoleModeType.GB; } Result.Movie.SyncSettingsJson = ConfigService.SaveWithType(temp_sync); } } }