public static bool LoadStateFile(string path, string name)
        {
            var core = Global.Emulator.AsStatable();

            // try to detect binary first
            var bl = BinaryStateLoader.LoadAndDetect(path);

            if (bl != null)
            {
                try
                {
                    var succeed = false;

                    if (Global.MovieSession.Movie.IsActive())
                    {
                        bl.GetLump(BinaryStateLump.Input, true, tr => succeed = Global.MovieSession.HandleMovieLoadState_HackyStep1(tr));
                        if (!succeed)
                        {
                            return(false);
                        }

                        bl.GetLump(BinaryStateLump.Input, true, tr => succeed = Global.MovieSession.HandleMovieLoadState_HackyStep2(tr));
                        if (!succeed)
                        {
                            return(false);
                        }
                    }

                    using (new SimpleTime("Load Core"))
                    {
                        bl.GetCoreState(br => core.LoadStateBinary(br), tr => core.LoadStateText(tr));
                    }

                    bl.GetLump(BinaryStateLump.Framebuffer, false, PopulateFramebuffer);

                    string userData = "";
                    bl.GetLump(BinaryStateLump.UserData, false, delegate(TextReader tr)
                    {
                        string line;
                        while ((line = tr.ReadLine()) != null)
                        {
                            if (!string.IsNullOrWhiteSpace(line))
                            {
                                userData = line;
                            }
                        }
                    });

                    if (!string.IsNullOrWhiteSpace(userData))
                    {
                        Global.UserBag = (Dictionary <string, object>)ConfigService.LoadWithType(userData);
                    }

                    if (Global.MovieSession.Movie.IsActive() && Global.MovieSession.Movie is TasMovie)
                    {
                        bl.GetLump(BinaryStateLump.LagLog, false, delegate(TextReader tr)
                        {
                            ((TasMovie)Global.MovieSession.Movie).TasLagLog.Load(tr);
                        });
                    }
                }
                finally
                {
                    bl.Dispose();
                }

                return(true);
            }

            return(false);
        }
示例#2
0
        protected override void RunImport()
        {
            var neshawkName = ((CoreAttribute)Attribute.GetCustomAttribute(typeof(NES), typeof(CoreAttribute))).CoreName;

            Result.Movie.HeaderEntries[HeaderKeys.Core] = neshawkName;
            const string emulator = "FCEUX";
            var          platform = "NES";    // TODO: FDS?

            var syncSettings = new NES.NESSyncSettings();

            var controllerSettings = new NESControlSettings
            {
                NesLeftPort  = nameof(UnpluggedNES),
                NesRightPort = nameof(UnpluggedNES)
            };

            _deck = controllerSettings.Instantiate((x, y) => true);
            AddDeckControlButtons();

            Result.Movie.HeaderEntries[HeaderKeys.Platform] = platform;

            using var sr = SourceFile.OpenText();
            string line;

            while ((line = sr.ReadLine()) != null)
            {
                if (line == "")
                {
                    continue;
                }

                if (line[0] == '|')
                {
                    ImportInputFrame(line);
                }
                else if (line.ToLower().StartsWith("sub"))
                {
                    var subtitle = ImportTextSubtitle(line);

                    if (!string.IsNullOrEmpty(subtitle))
                    {
                        Result.Movie.Subtitles.AddFromString(subtitle);
                    }
                }
                else if (line.ToLower().StartsWith("emuversion"))
                {
                    Result.Movie.Comments.Add($"{EmulationOrigin} {emulator} version {ParseHeader(line, "emuVersion")}");
                }
                else if (line.ToLower().StartsWith("version"))
                {
                    string version = ParseHeader(line, "version");

                    if (version != "3")
                    {
                        Result.Warnings.Add("Detected a .fm2 movie version other than 3, which is unsupported");
                    }
                    else
                    {
                        Result.Movie.Comments.Add($"{MovieOrigin} .fm2 version 3");
                    }
                }
                else if (line.ToLower().StartsWith("romfilename"))
                {
                    Result.Movie.HeaderEntries[HeaderKeys.GameName] = ParseHeader(line, "romFilename");
                }
                else if (line.ToLower().StartsWith("cdgamename"))
                {
                    Result.Movie.HeaderEntries[HeaderKeys.GameName] = ParseHeader(line, "cdGameName");
                }
                else if (line.ToLower().StartsWith("romchecksum"))
                {
                    string blob = ParseHeader(line, "romChecksum");
                    byte[] md5  = DecodeBlob(blob);
                    if (md5 != null && md5.Length == 16)
                    {
                        Result.Movie.HeaderEntries[MD5] = md5.BytesToHexString().ToLower();
                    }
                    else
                    {
                        Result.Warnings.Add("Bad ROM checksum.");
                    }
                }
                else if (line.ToLower().StartsWith("comment author"))
                {
                    Result.Movie.HeaderEntries[HeaderKeys.Author] = ParseHeader(line, "comment author");
                }
                else if (line.ToLower().StartsWith("rerecordcount"))
                {
                    int.TryParse(ParseHeader(line, "rerecordCount"), out var rerecordCount);
                    Result.Movie.Rerecords = (ulong)rerecordCount;
                }
                else if (line.ToLower().StartsWith("guid"))
                {
                    // We no longer care to keep this info
                }
                else if (line.ToLower().StartsWith("startsfromsavestate"))
                {
                    // If this movie starts from a savestate, we can't support it.
                    if (ParseHeader(line, "StartsFromSavestate") == "1")
                    {
                        Result.Errors.Add("Movies that begin with a savestate are not supported.");
                        break;
                    }
                }
                else if (line.ToLower().StartsWith("palflag"))
                {
                    Result.Movie.HeaderEntries[HeaderKeys.Pal] = ParseHeader(line, "palFlag");
                }
                else if (line.ToLower().StartsWith("port0"))
                {
                    if (ParseHeader(line, "port0") == "1")
                    {
                        controllerSettings.NesLeftPort = nameof(ControllerNES);
                        _deck = controllerSettings.Instantiate((x, y) => false);
                        AddDeckControlButtons();
                    }
                }
                else if (line.ToLower().StartsWith("port1"))
                {
                    if (ParseHeader(line, "port1") == "1")
                    {
                        controllerSettings.NesRightPort = nameof(ControllerNES);
                        _deck = controllerSettings.Instantiate((x, y) => false);
                        AddDeckControlButtons();
                    }
                }
                else if (line.ToLower().StartsWith("port2"))
                {
                    if (ParseHeader(line, "port2") == "1")
                    {
                        Result.Errors.Add("Famicom port not yet supported");
                        break;
                    }
                }
                else if (line.ToLower().StartsWith("fourscore"))
                {
                    bool fourscore = ParseHeader(line, "fourscore") == "1";
                    if (fourscore)
                    {
                        // TODO: set controller config sync settings
                        controllerSettings.NesLeftPort  = nameof(FourScore);
                        controllerSettings.NesRightPort = nameof(FourScore);
                    }

                    _deck = controllerSettings.Instantiate((x, y) => false);
                }
                else
                {
                    Result.Movie.Comments.Add(line);                     // Everything not explicitly defined is treated as a comment.
                }
            }

            syncSettings.Controls         = controllerSettings;
            Result.Movie.SyncSettingsJson = ConfigService.SaveWithType(syncSettings);
        }
示例#3
0
        // TODO: This doesn't really belong here, but not sure where to put it
        public static void PopulateWithDefaultHeaderValues(
            this IMovie movie,
            IEmulator emulator,
            IGameInfo game,
            FirmwareManager firmwareManager,
            string author)
        {
            movie.Author                  = author;
            movie.EmulatorVersion         = VersionInfo.GetEmuVersion();
            movie.OriginalEmulatorVersion = VersionInfo.GetEmuVersion();
            movie.SystemID                = emulator.SystemId;

            var settable = new SettingsAdapter(emulator);

            if (settable.HasSyncSettings)
            {
                movie.SyncSettingsJson = ConfigService.SaveWithType(settable.GetSyncSettings());
            }

            if (game.IsNullInstance())
            {
                movie.GameName = "NULL";
            }
            else
            {
                movie.GameName = game.FilesystemSafeName();
                movie.Hash     = game.Hash;
                if (game.FirmwareHash != null)
                {
                    movie.FirmwareHash = game.FirmwareHash;
                }
            }

            if (emulator.HasBoardInfo())
            {
                movie.BoardName = emulator.AsBoardInfo().BoardName;
            }

            if (emulator.HasRegions())
            {
                var region = emulator.AsRegionable().Region;
                if (region == Emulation.Common.DisplayType.PAL)
                {
                    movie.HeaderEntries.Add(HeaderKeys.Pal, "1");
                }
            }

            if (firmwareManager.RecentlyServed.Any())
            {
                foreach (var firmware in firmwareManager.RecentlyServed)
                {
                    var key = $"{firmware.SystemId}_Firmware_{firmware.FirmwareId}";

                    if (!movie.HeaderEntries.ContainsKey(key))
                    {
                        movie.HeaderEntries.Add(key, firmware.Hash);
                    }
                }
            }

            if (emulator is GBHawk gbHawk && gbHawk.IsCGBMode())
            {
                movie.HeaderEntries.Add("IsCGBMode", "1");
            }

            if (emulator is SubGBHawk subgbHawk)
            {
                if (subgbHawk._GBCore.IsCGBMode())
                {
                    movie.HeaderEntries.Add("IsCGBMode", "1");
                }

                movie.HeaderEntries.Add(HeaderKeys.CycleCount, "0");
            }

            if (emulator is Gameboy gb)
            {
                if (gb.IsCGBMode())
                {
                    movie.HeaderEntries.Add("IsCGBMode", "1");
                }

                movie.HeaderEntries.Add(HeaderKeys.CycleCount, "0");
            }

            if (emulator is SMS sms)
            {
                if (sms.IsSG1000)
                {
                    movie.HeaderEntries.Add("IsSGMode", "1");
                }

                if (sms.IsGameGear)
                {
                    movie.HeaderEntries.Add("IsGGMode", "1");
                }
            }

            if (emulator is GPGX gpgx && gpgx.IsMegaCD)
            {
                movie.HeaderEntries.Add("IsSegaCDMode", "1");
            }

            if (emulator is PicoDrive pico && pico.Is32XActive)
            {
                movie.HeaderEntries.Add("Is32X", "1");
            }

            if (emulator is SubNESHawk)
            {
                movie.HeaderEntries.Add(HeaderKeys.VBlankCount, "0");
            }

            movie.Core = ((CoreAttribute)Attribute
                          .GetCustomAttribute(emulator.GetType(), typeof(CoreAttribute)))
                         .CoreName;
        }
        public static void SaveStateFile(string filename, string name)
        {
            var core = Global.Emulator.AsStatable();

            // the old method of text savestate save is now gone.
            // a text savestate is just like a binary savestate, but with a different core lump
            using var bs = new BinaryStateSaver(filename);
            if (Global.Config.SaveStateType == SaveStateTypeE.Text ||
                (Global.Config.SaveStateType == SaveStateTypeE.Default && !core.BinarySaveStatesPreferred))
            {
                // text savestate format
                using (new SimpleTime("Save Core"))
                {
                    bs.PutLump(BinaryStateLump.CorestateText, tw => core.SaveStateText(tw));
                }
            }
            else
            {
                // binary core lump format
                using (new SimpleTime("Save Core"))
                {
                    bs.PutLump(BinaryStateLump.Corestate, bw => core.SaveStateBinary(bw));
                }
            }

            if (Global.Config.SaveScreenshotWithStates && Global.Emulator.HasVideoProvider())
            {
                var vp   = Global.Emulator.AsVideoProvider();
                var buff = vp.GetVideoBuffer();
                if (buff.Length == 1)
                {
                    // is a hacky opengl texture ID. can't handle this now!
                    // need to discuss options
                    // 1. cores must be able to provide a pixels VideoProvider in addition to a texture ID, on command (not very hard overall but interface changing and work per core)
                    // 2. SavestateManager must be setup with a mechanism for resolving texture IDs (even less work, but sloppy)
                    // There are additional problems with AVWriting. They depend on VideoProvider providing pixels.
                }
                else
                {
                    int outWidth  = vp.BufferWidth;
                    int outHeight = vp.BufferHeight;

                    // if buffer is too big, scale down screenshot
                    if (!Global.Config.NoLowResLargeScreenshotWithStates && buff.Length >= Global.Config.BigScreenshotSize)
                    {
                        outWidth  /= 2;
                        outHeight /= 2;
                    }

                    using (new SimpleTime("Save Framebuffer"))
                    {
                        bs.PutLump(BinaryStateLump.Framebuffer, s => QuickBmpFile.Save(Global.Emulator.AsVideoProvider(), s, outWidth, outHeight));
                    }
                }
            }

            if (Global.MovieSession.Movie.IsActive())
            {
                bs.PutLump(BinaryStateLump.Input,
                           delegate(TextWriter tw)
                {
                    // this never should have been a core's responsibility
                    tw.WriteLine("Frame {0}", Global.Emulator.Frame);
                    Global.MovieSession.HandleMovieSaveState(tw);
                });
            }

            if (Global.UserBag.Any())
            {
                bs.PutLump(BinaryStateLump.UserData,
                           delegate(TextWriter tw)
                {
                    var data = ConfigService.SaveWithType(Global.UserBag);
                    tw.WriteLine(data);
                });
            }

            if (Global.MovieSession.Movie.IsActive() && Global.MovieSession.Movie is TasMovie)
            {
                bs.PutLump(BinaryStateLump.LagLog,
                           delegate(TextWriter tw)
                {
                    ((TasMovie)Global.MovieSession.Movie).TasLagLog.Save(tw);
                });
            }
        }
        // TODO: This doesn't really belong here, but not sure where to put it
        public static void PopulateWithDefaultHeaderValues(
            this IMovie movie,
            IEmulator emulator,
            ISettingsAdapter settable,
            IGameInfo game,
            FirmwareManager firmwareManager,
            string author)
        {
            movie.Author                  = author;
            movie.EmulatorVersion         = VersionInfo.GetEmuVersion();
            movie.OriginalEmulatorVersion = VersionInfo.GetEmuVersion();
            movie.SystemID                = emulator.SystemId;

            if (settable.HasSyncSettings)
            {
                movie.SyncSettingsJson = ConfigService.SaveWithType(settable.GetSyncSettings());
            }

            if (game.IsNullInstance())
            {
                movie.GameName = "NULL";
            }
            else
            {
                movie.GameName = game.FilesystemSafeName();
                movie.Hash     = game.Hash;
                if (game.FirmwareHash != null)
                {
                    movie.FirmwareHash = game.FirmwareHash;
                }
            }

            if (emulator.HasBoardInfo())
            {
                movie.BoardName = emulator.AsBoardInfo().BoardName;
            }

            if (emulator.HasRegions())
            {
                var region = emulator.AsRegionable().Region;
                if (region == DisplayType.PAL)
                {
                    movie.HeaderEntries.Add(HeaderKeys.Pal, "1");
                }
            }

            if (firmwareManager.RecentlyServed.Count != 0)
            {
                foreach (var firmware in firmwareManager.RecentlyServed)
                {
                    var key = firmware.ID.MovieHeaderKey;
                    if (!movie.HeaderEntries.ContainsKey(key))
                    {
                        movie.HeaderEntries.Add(key, firmware.Hash);
                    }
                }
            }

            if (emulator is NDS nds && nds.IsDSi)
            {
                movie.HeaderEntries.Add("IsDSi", "1");

                if (nds.IsDSiWare)
                {
                    movie.HeaderEntries.Add("IsDSiWare", "1");
                }
            }

            if ((emulator is NES nes && nes.IsVS) ||
                (emulator is SubNESHawk subnes && subnes.IsVs))
            {
                movie.HeaderEntries.Add("IsVS", "1");
            }

            if (emulator is IGameboyCommon gb)
            {
                if (gb.IsCGBMode())
                {
                    movie.HeaderEntries.Add(gb.IsCGBDMGMode() ? "IsCGBDMGMode" : "IsCGBMode", "1");
                }
            }

            if (emulator is SMS sms)
            {
                if (sms.IsSG1000)
                {
                    movie.HeaderEntries.Add("IsSGMode", "1");
                }

                if (sms.IsGameGear)
                {
                    movie.HeaderEntries.Add("IsGGMode", "1");
                }
            }

            if (emulator is GPGX gpgx && gpgx.IsMegaCD)
            {
                movie.HeaderEntries.Add("IsSegaCDMode", "1");
            }

            if (emulator is PicoDrive pico && pico.Is32XActive)
            {
                movie.HeaderEntries.Add("Is32X", "1");
            }

            if (emulator is ICycleTiming)
            {
                movie.HeaderEntries.Add(HeaderKeys.CycleCount, "0");
                movie.HeaderEntries.Add(HeaderKeys.ClockRate, "0");
            }

            movie.Core = emulator.Attributes().CoreName;
        }
示例#6
0
        protected override void RunImport()
        {
            Result.Movie.HeaderEntries[HeaderKeys.Platform] = "NDS";

            var syncSettings = new MelonDS.MelonSyncSettings();

            using var sr = SourceFile.OpenText();
            string line;

            while ((line = sr.ReadLine()) != null)
            {
                if (string.IsNullOrWhiteSpace(line))
                {
                    continue;
                }

                if (line[0] == '|')
                {
                    ImportInputFrame(line);
                }
                else if (line.StartsWith("rerecordCount"))
                {
                    int.TryParse(ParseHeader(line, "rerecordCount"), out var rerecordCount);
                    Result.Movie.Rerecords = (ulong)rerecordCount;
                }
                else if (line.StartsWith("firmNickname"))
                {
                    syncSettings.Nickname = ParseHeader(line, "firmNickname");
                }
                else if (line.StartsWith("firmFavColour"))
                {
                    syncSettings.FavoriteColor = byte.Parse(ParseHeader(line, "firmFavColour"));
                }
                else if (line.StartsWith("firmBirthDay"))
                {
                    syncSettings.BirthdayDay = byte.Parse(ParseHeader(line, "firmBirthDay"));
                }
                else if (line.StartsWith("firmBirthMonth"))
                {
                    syncSettings.BirthdayMonth = byte.Parse(ParseHeader(line, "firmBirthMonth"));
                }
                else if (line.StartsWith("rtcStartNew"))
                {
                    //TODO: what is this format?? 2010-JAN-01 00:00:00:000
                    //var time = DateTime.Parse(ParseHeader(line, "rtcStartNew"));
                    //syncSettings.TimeAtBoot = (uint)new DateTimeOffset(time.ToLocalTime()).ToUnixTimeSeconds();
                }
                else if (line.StartsWith("comment author"))
                {
                    Result.Movie.HeaderEntries[HeaderKeys.Author] = ParseHeader(line, "comment author");
                }
                else if (line.StartsWith("comment"))
                {
                    Result.Movie.Comments.Add(ParseHeader(line, "comment"));
                }
                else if (line.ToLower().StartsWith("guid"))
                {
                    // We no longer care to keep this info
                }
                else
                {
                    Result.Movie.Comments.Add(line);                     // Everything not explicitly defined is treated as a comment.
                }

                Result.Movie.SyncSettingsJson = ConfigService.SaveWithType(syncSettings);
            }
        }
示例#7
0
        public void Create(string filename, SaveStateConfig config)
        {
            // the old method of text savestate save is now gone.
            // a text savestate is just like a binary savestate, but with a different core lump
            using var bs = new ZipStateSaver(filename, config.CompressionLevelNormal);
            bs.PutVersionLumps();

            using (new SimpleTime("Save Core"))
            {
                if (config.Type == SaveStateType.Text)
                {
                    bs.PutLump(BinaryStateLump.CorestateText, tw => _statable.SaveStateText(tw));
                }
                else
                {
                    bs.PutLump(BinaryStateLump.Corestate, bw => _statable.SaveStateBinary(bw));
                }
            }

            if (config.SaveScreenshot && _videoProvider != null)
            {
                var buff = _videoProvider.GetVideoBuffer();
                if (buff.Length == 1)
                {
                    // is a hacky opengl texture ID. can't handle this now!
                    // need to discuss options
                    // 1. cores must be able to provide a pixels VideoProvider in addition to a texture ID, on command (not very hard overall but interface changing and work per core)
                    // 2. SavestateManager must be setup with a mechanism for resolving texture IDs (even less work, but sloppy)
                    // There are additional problems with AVWriting. They depend on VideoProvider providing pixels.
                }
                else
                {
                    int outWidth  = _videoProvider.BufferWidth;
                    int outHeight = _videoProvider.BufferHeight;

                    // if buffer is too big, scale down screenshot
                    if (!config.NoLowResLargeScreenshots && buff.Length >= config.BigScreenshotSize)
                    {
                        outWidth  /= 2;
                        outHeight /= 2;
                    }

                    using (new SimpleTime("Save Framebuffer"))
                    {
                        bs.PutLump(BinaryStateLump.Framebuffer, s => _quickBmpFile.Save(_videoProvider, s, outWidth, outHeight));
                    }
                }
            }

            if (_movieSession.Movie.IsActive())
            {
                bs.PutLump(BinaryStateLump.Input,
                           delegate(TextWriter tw)
                {
                    // this never should have been a core's responsibility
                    tw.WriteLine("Frame {0}", _emulator.Frame);
                    _movieSession.HandleSaveState(tw);
                });
            }

            if (_userBag.Any())
            {
                bs.PutLump(BinaryStateLump.UserData,
                           delegate(TextWriter tw)
                {
                    var data = ConfigService.SaveWithType(_userBag);
                    tw.WriteLine(data);
                });
            }

            if (_movieSession.Movie.IsActive() && _movieSession.Movie is ITasMovie)
            {
                bs.PutLump(BinaryStateLump.LagLog,
                           delegate(TextWriter tw)
                {
                    ((ITasMovie)_movieSession.Movie).LagLog.Save(tw);
                });
            }
        }
示例#8
0
        public static bool LoadStateFile(string path, string name)
        {
            var core = Global.Emulator.AsStatable();

            // try to detect binary first
            var bl = BinaryStateLoader.LoadAndDetect(path);

            if (bl != null)
            {
                try
                {
                    var succeed = false;

                    if (Global.MovieSession.Movie.IsActive)
                    {
                        bl.GetLump(BinaryStateLump.Input, true, tr => succeed = Global.MovieSession.HandleMovieLoadState_HackyStep1(tr));
                        if (!succeed)
                        {
                            return(false);
                        }

                        bl.GetLump(BinaryStateLump.Input, true, tr => succeed = Global.MovieSession.HandleMovieLoadState_HackyStep2(tr));
                        if (!succeed)
                        {
                            return(false);
                        }
                    }

                    using (new SimpleTime("Load Core"))
                    {
                        bl.GetCoreState(br => core.LoadStateBinary(br), tr => core.LoadStateText(tr));
                    }

                    bl.GetLump(BinaryStateLump.Framebuffer, false, PopulateFramebuffer);

                    if (bl.HasLump(BinaryStateLump.UserData))
                    {
                        string userData = string.Empty;
                        bl.GetLump(BinaryStateLump.UserData, false, delegate(TextReader tr)
                        {
                            string line;
                            while ((line = tr.ReadLine()) != null)
                            {
                                if (!string.IsNullOrWhiteSpace(line))
                                {
                                    userData = line;
                                }
                            }
                        });

                        Global.UserBag = (Dictionary <string, object>)ConfigService.LoadWithType(userData);
                    }

                    if (bl.HasLump(BinaryStateLump.LagLog) &&
                        Global.MovieSession.Movie.IsActive && Global.MovieSession.Movie is TasMovie)
                    {
                        bl.GetLump(BinaryStateLump.LagLog, false, delegate(BinaryReader br, long length)
                        {
                            (Global.MovieSession.Movie as TasMovie).TasLagLog.Load(br);
                        });
                    }
                }
                catch
                {
                    return(false);
                }
                finally
                {
                    bl.Dispose();
                }

                return(true);
            }
            else             // text mode
            {
                if (Global.MovieSession.HandleMovieLoadState(path))
                {
                    using (var reader = new StreamReader(path))
                    {
                        core.LoadStateText(reader);

                        while (true)
                        {
                            var str = reader.ReadLine();
                            if (str == null)
                            {
                                break;
                            }

                            if (str.Trim() == string.Empty)
                            {
                                continue;
                            }

                            var args = str.Split(' ');
                            if (args[0] == "Framebuffer" && Global.Emulator.HasVideoProvider())
                            {
                                Global.Emulator.AsVideoProvider().GetVideoBuffer().ReadFromHex(args[1]);
                            }
                        }
                    }

                    return(true);
                }
                else
                {
                    return(false);
                }
            }
        }
示例#9
0
        public bool Load(string path)
        {
            // try to detect binary first
            var bl = ZipStateLoader.LoadAndDetect(path);

            if (bl != null)
            {
                try
                {
                    var succeed = false;

                    // Movie timeline check must happen before the core state is loaded
                    if (_movieSession.Movie.IsActive())
                    {
                        bl.GetLump(BinaryStateLump.Input, true, tr => succeed = _movieSession.CheckSavestateTimeline(tr));
                        if (!succeed)
                        {
                            return(false);
                        }
                    }

                    using (new SimpleTime("Load Core"))
                    {
                        bl.GetCoreState(br => _statable.LoadStateBinary(br), tr => _statable.LoadStateText(tr));
                    }

                    // We must handle movie input AFTER the core is loaded to properly handle mode changes, and input latching
                    if (_movieSession.Movie.IsActive())
                    {
                        bl.GetLump(BinaryStateLump.Input, true, tr => succeed = _movieSession.HandleLoadState(tr));
                        if (!succeed)
                        {
                            return(false);
                        }
                    }

                    if (_videoProvider != null)
                    {
                        bl.GetLump(BinaryStateLump.Framebuffer, false, br => PopulateFramebuffer(br, _videoProvider, _quickBmpFile));
                    }

                    string userData = "";
                    bl.GetLump(BinaryStateLump.UserData, false, delegate(TextReader tr)
                    {
                        string line;
                        while ((line = tr.ReadLine()) != null)
                        {
                            if (!string.IsNullOrWhiteSpace(line))
                            {
                                userData = line;
                            }
                        }
                    });

                    if (!string.IsNullOrWhiteSpace(userData))
                    {
                        var bag = (Dictionary <string, object>)ConfigService.LoadWithType(userData);
                        _userBag.Clear();
                        foreach (var(k, v) in bag)
                        {
                            _userBag.Add(k, v);
                        }
                    }

                    if (_movieSession.Movie.IsActive() && _movieSession.Movie is ITasMovie)
                    {
                        bl.GetLump(BinaryStateLump.LagLog, false, delegate(TextReader tr)
                        {
                            ((ITasMovie)_movieSession.Movie).LagLog.Load(tr);
                        });
                    }
                }
                finally
                {
                    bl.Dispose();
                }

                return(true);
            }

            return(false);
        }
示例#10
0
        public static bool LoadStateFile(IEmulator emulator, string path)
        {
            var core = emulator.AsStatable();

            // try to detect binary first
            var bl = BinaryStateLoader.LoadAndDetect(path);

            if (bl != null)
            {
                try
                {
                    var succeed = false;

                    // Movie timeline check must happen before the core state is loaded
                    if (Global.MovieSession.Movie.IsActive())
                    {
                        bl.GetLump(BinaryStateLump.Input, true, tr => succeed = Global.MovieSession.CheckSavestateTimeline(tr));
                        if (!succeed)
                        {
                            return(false);
                        }
                    }

                    using (new SimpleTime("Load Core"))
                    {
                        bl.GetCoreState(br => core.LoadStateBinary(br), tr => core.LoadStateText(tr));
                    }

                    // We must handle movie input AFTER the core is loaded to properly handle mode changes, and input latching
                    if (Global.MovieSession.Movie.IsActive())
                    {
                        bl.GetLump(BinaryStateLump.Input, true, tr => succeed = Global.MovieSession.HandleLoadState(tr));
                        if (!succeed)
                        {
                            return(false);
                        }
                    }

                    bl.GetLump(BinaryStateLump.Framebuffer, false, PopulateFramebuffer);

                    string userData = "";
                    bl.GetLump(BinaryStateLump.UserData, false, delegate(TextReader tr)
                    {
                        string line;
                        while ((line = tr.ReadLine()) != null)
                        {
                            if (!string.IsNullOrWhiteSpace(line))
                            {
                                userData = line;
                            }
                        }
                    });

                    if (!string.IsNullOrWhiteSpace(userData))
                    {
                        Global.UserBag = (Dictionary <string, object>)ConfigService.LoadWithType(userData);
                    }

                    if (Global.MovieSession.Movie.IsActive() && Global.MovieSession.Movie is TasMovie)
                    {
                        bl.GetLump(BinaryStateLump.LagLog, false, delegate(TextReader tr)
                        {
                            ((TasMovie)Global.MovieSession.Movie).LagLog.Load(tr);
                        });
                    }
                }
                finally
                {
                    bl.Dispose();
                }

                return(true);
            }

            return(false);
        }
        protected MiscHeaderInfo ParseHeader(IMovie movie, string expectedMagic, BinaryReader br)
        {
            var info = new MiscHeaderInfo();

            string magic = new string(br.ReadChars(4));

            if (magic != expectedMagic)
            {
                Result.Errors.Add($"Not a {expectedMagic}file: invalid magic number in file header.");
                return(info);
            }

            uint movieVersionNumber = br.ReadUInt32();

            if (movieVersionNumber != 2)
            {
                Result.Warnings.Add($"Unexpected movie version: got {movieVersionNumber}, expecting 2");
            }

            // 008: UInt32 emulator version.
            br.ReadUInt32();

            byte flags  = br.ReadByte();
            byte flags2 = br.ReadByte();

            if ((flags & 0x02) != 0)
            {
                Result.Errors.Add("Movie starts from savestate; this is currently unsupported.");
            }

            if ((flags & 0x04) != 0)
            {
                movie.HeaderEntries[HeaderKeys.Pal] = "1";
            }

            if ((flags & 0x08) != 0)
            {
                Result.Errors.Add("Movie contains embedded memory cards; this is currently unsupported.");
            }

            if ((flags & 0x10) != 0)
            {
                Result.Errors.Add("Movie contains embedded cheat list; this is currently unsupported.");
            }

            if ((flags & 0x20) != 0 || (flags2 & 0x06) != 0)
            {
                Result.Errors.Add("Movie relies on emulator hacks; this is currently unsupported.");
            }

            if ((flags & 0x40) != 0)
            {
                info.BinaryFormat = false;
            }

            if ((flags & 0x80) != 0 || (flags2 & 0x01) != 0)
            {
                Result.Errors.Add("Movie uses multitap; this is currently unsupported.");
                return(info);
            }

            // Player 1 controller type
            switch (br.ReadByte())
            {
            // It seems to be inconsistent in the files I looked at which of these is used
            // to mean no controller present.
            case 0:
            case 8:
                info.Player1Type = OctoshockDll.ePeripheralType.None;
                break;

            case 4:
                info.Player1Type = OctoshockDll.ePeripheralType.Pad;
                break;

            case 7:
                info.Player1Type = OctoshockDll.ePeripheralType.DualShock;
                break;

            default:
                Result.Errors.Add("Movie has unrecognized controller type for Player 1.");
                return(info);
            }

            // Player 2 controller type
            switch (br.ReadByte())
            {
            case 0:
            case 8:
                info.Player2Type = OctoshockDll.ePeripheralType.None;
                break;

            case 4:
                info.Player2Type = OctoshockDll.ePeripheralType.Pad;
                break;

            case 7:
                info.Player2Type = OctoshockDll.ePeripheralType.DualShock;
                break;

            default:
                Result.Errors.Add("Movie has unrecognized controller type for Player 2.");
                return(info);
            }

            var syncSettings = new Octoshock.SyncSettings
            {
                FIOConfig =
                {
                    Devices8 = new[]
                    {
                        info.Player1Type,
                        OctoshockDll.ePeripheralType.None,
                        OctoshockDll.ePeripheralType.None,
                        OctoshockDll.ePeripheralType.None,
                        info.Player2Type,
                        OctoshockDll.ePeripheralType.None,
                        OctoshockDll.ePeripheralType.None,
                        OctoshockDll.ePeripheralType.None
                    }
                }
            };

            movie.SyncSettingsJson = ConfigService.SaveWithType(syncSettings);

            info.FrameCount = br.ReadUInt32();
            uint rerecordCount = br.ReadUInt32();

            movie.HeaderEntries[HeaderKeys.Rerecords] = rerecordCount.ToString();

            // 018: UInt32 savestateOffset
            // 01C: UInt32 memoryCard1Offset
            // 020: UInt32 memoryCard2Offset
            // 024: UInt32 cheatListOffset

            // 028: UInt32 cdRomIdOffset
            // Source format is just the first up-to-8 alphanumeric characters of the CD label,
            // so not so useful.
            br.ReadBytes(20);

            info.ControllerDataOffset = br.ReadUInt32();

            uint authorNameLength = br.ReadUInt32();

            char[] authorName = br.ReadChars((int)authorNameLength);

            movie.HeaderEntries[HeaderKeys.Author] = new string(authorName);

            info.ParseSuccessful = true;
            return(info);
        }
示例#12
0
        public static void SaveStateFile(string filename, string name)
        {
            var core = Global.Emulator.AsStatable();

            // the old method of text savestate save is now gone.
            // a text savestate is just like a binary savestate, but with a different core lump
            using (var bs = new BinaryStateSaver(filename))
            {
                if (Global.Config.SaveStateType == Config.SaveStateTypeE.Text ||
                    (Global.Config.SaveStateType == Config.SaveStateTypeE.Default && !core.BinarySaveStatesPreferred))
                {
                    // text savestate format
                    using (new SimpleTime("Save Core"))
                        bs.PutLump(BinaryStateLump.CorestateText, (tw) => core.SaveStateText(tw));
                }
                else
                {
                    // binary core lump format
                    using (new SimpleTime("Save Core"))
                        bs.PutLump(BinaryStateLump.Corestate, bw => core.SaveStateBinary(bw));
                }

                if (Global.Config.SaveScreenshotWithStates)
                {
                    var vp   = Global.Emulator.VideoProvider();
                    var buff = vp.GetVideoBuffer();

                    int out_w = vp.BufferWidth;
                    int out_h = vp.BufferHeight;

                    // if buffer is too big, scale down screenshot
                    if (!Global.Config.NoLowResLargeScreenshotWithStates && buff.Length >= Global.Config.BigScreenshotSize)
                    {
                        out_w /= 2;
                        out_h /= 2;
                    }
                    using (new SimpleTime("Save Framebuffer"))
                        bs.PutLump(BinaryStateLump.Framebuffer, (s) => QuickBmpFile.Save(Global.Emulator.VideoProvider(), s, out_w, out_h));
                }

                if (Global.MovieSession.Movie.IsActive)
                {
                    bs.PutLump(BinaryStateLump.Input,
                               delegate(TextWriter tw)
                    {
                        // this never should have been a core's responsibility
                        tw.WriteLine("Frame {0}", Global.Emulator.Frame);
                        Global.MovieSession.HandleMovieSaveState(tw);
                    });
                }

                if (Global.UserBag.Any())
                {
                    bs.PutLump(BinaryStateLump.UserData,
                               delegate(TextWriter tw)
                    {
                        var data = ConfigService.SaveWithType(Global.UserBag);
                        tw.WriteLine(data);
                    });
                }

                if (Global.MovieSession.Movie.IsActive && Global.MovieSession.Movie is TasMovie)
                {
                    bs.PutLump(BinaryStateLump.LagLog,
                               delegate(BinaryWriter bw)
                    {
                        (Global.MovieSession.Movie as TasMovie).TasLagLog.Save(bw);
                    });
                }
            }
        }
示例#13
0
        public bool Load(string path, IDialogParent dialogParent)
        {
            // try to detect binary first
            using var bl = ZipStateLoader.LoadAndDetect(path);
            if (bl is null)
            {
                return(false);
            }
            var succeed = false;

            if (!VersionInfo.DeveloperBuild)
            {
                bl.GetLump(BinaryStateLump.BizVersion, true, tr => succeed = tr.ReadLine() == VersionInfo.GetEmuVersion());
                if (!succeed)
                {
                    var result = dialogParent.ModalMessageBox2(
                        "This savestate was made with a different version, so it's unlikely to work.\nChoose OK to try loading it anyway.",
                        "Savestate version mismatch",
                        EMsgBoxIcon.Question,
                        useOKCancel: true);
                    if (!result)
                    {
                        return(false);
                    }
                }
            }

            // Movie timeline check must happen before the core state is loaded
            if (_movieSession.Movie.IsActive())
            {
                bl.GetLump(BinaryStateLump.Input, true, tr => succeed = _movieSession.CheckSavestateTimeline(tr));
                if (!succeed)
                {
                    return(false);
                }
            }

            using (new SimpleTime("Load Core"))
            {
                bl.GetCoreState(br => _statable.LoadStateBinary(br), tr => _statable.LoadStateText(tr));
            }

            // We must handle movie input AFTER the core is loaded to properly handle mode changes, and input latching
            if (_movieSession.Movie.IsActive())
            {
                bl.GetLump(BinaryStateLump.Input, true, tr => succeed = _movieSession.HandleLoadState(tr));
                if (!succeed)
                {
                    return(false);
                }
            }

            if (_videoProvider != null)
            {
                bl.GetLump(BinaryStateLump.Framebuffer, false, br => PopulateFramebuffer(br, _videoProvider, _quickBmpFile));
            }

            string userData = "";

            bl.GetLump(BinaryStateLump.UserData, false, delegate(TextReader tr)
            {
                string line;
                while ((line = tr.ReadLine()) != null)
                {
                    if (!string.IsNullOrWhiteSpace(line))
                    {
                        userData = line;
                    }
                }
            });

            if (!string.IsNullOrWhiteSpace(userData))
            {
                var bag = (Dictionary <string, object>)ConfigService.LoadWithType(userData);
                _userBag.Clear();
                foreach (var(k, v) in bag)
                {
                    _userBag.Add(k, v);
                }
            }

            if (_movieSession.Movie.IsActive() && _movieSession.Movie is ITasMovie)
            {
                bl.GetLump(BinaryStateLump.LagLog, false, delegate(TextReader tr)
                {
                    ((ITasMovie)_movieSession.Movie).LagLog.Load(tr);
                });
            }

            return(true);
        }