Esempio n. 1
0
 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;
 }
Esempio n. 2
0
 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;
 }
Esempio n. 3
0
 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;
 }
Esempio n. 4
0
 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;
 }
Esempio n. 5
0
 public void GetSettings(out Gameboy.GambatteSettings s, out Gameboy.GambatteSyncSettings ss)
 {
     s  = _s;
     ss = _ss;
 }
Esempio n. 6
0
        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);
                }
            }
        }