diff --git a/BizHawk.Client.Common/BinarySaveStates.cs b/BizHawk.Client.Common/BinarySaveStates.cs index 0dc2c12820..d413c9f901 100644 --- a/BizHawk.Client.Common/BinarySaveStates.cs +++ b/BizHawk.Client.Common/BinarySaveStates.cs @@ -21,6 +21,8 @@ namespace BizHawk.Client.Common public static BinaryStateLump Input { get; private set; } [Name("CoreText", "txt")] public static BinaryStateLump CorestateText { get; private set; } + [Name("MovieSaveRam", "bin")] + public static BinaryStateLump MovieSaveRam { get; private set; } // Only for movies they probably shoudln't be leaching this stuff [Name("Header", "txt")] diff --git a/BizHawk.Client.Common/movie/HeaderKeys.cs b/BizHawk.Client.Common/movie/HeaderKeys.cs index e854a2ffd2..0e46312d58 100644 --- a/BizHawk.Client.Common/movie/HeaderKeys.cs +++ b/BizHawk.Client.Common/movie/HeaderKeys.cs @@ -11,6 +11,7 @@ namespace BizHawk.Client.Common public const string AUTHOR = "Author"; public const string RERECORDS = "rerecordCount"; public const string STARTSFROMSAVESTATE = "StartsFromSavestate"; + public const string STARTSFROMSAVERAM = "StartsFromSaveRam"; public const string SAVESTATEBINARYBASE64BLOB = "SavestateBinaryBase64Blob"; //this string will not contain base64: ; it's implicit (this is to avoid another big string op to dice off the base64: substring) public const string FOURSCORE = "FourScore"; public const string SHA1 = "SHA1"; diff --git a/BizHawk.Client.Common/movie/bk2/Bk2Movie.HeaderApi.cs b/BizHawk.Client.Common/movie/bk2/Bk2Movie.HeaderApi.cs index 1e8ddce528..92137a7cb5 100644 --- a/BizHawk.Client.Common/movie/bk2/Bk2Movie.HeaderApi.cs +++ b/BizHawk.Client.Common/movie/bk2/Bk2Movie.HeaderApi.cs @@ -76,6 +76,31 @@ namespace BizHawk.Client.Common } } + public bool StartsFromSaveRam + { + get + { + if (Header.ContainsKey(HeaderKeys.STARTSFROMSAVERAM)) + { + return bool.Parse(Header[HeaderKeys.STARTSFROMSAVERAM]); + } + + return false; + } + + set + { + if (value) + { + Header.Add(HeaderKeys.STARTSFROMSAVERAM, "True"); + } + else + { + Header.Remove(HeaderKeys.STARTSFROMSAVERAM); + } + } + } + public string GameName { get @@ -239,5 +264,6 @@ namespace BizHawk.Client.Common public string TextSavestate { get; set; } public byte[] BinarySavestate { get; set; } public int[] SavestateFramebuffer { get; set; } + public byte[] SaveRam { get; set; } } } diff --git a/BizHawk.Client.Common/movie/bk2/Bk2Movie.IO.cs b/BizHawk.Client.Common/movie/bk2/Bk2Movie.IO.cs index dae5c9a6c7..c70783acde 100644 --- a/BizHawk.Client.Common/movie/bk2/Bk2Movie.IO.cs +++ b/BizHawk.Client.Common/movie/bk2/Bk2Movie.IO.cs @@ -141,6 +141,15 @@ namespace BizHawk.Client.Common SavestateFramebuffer[i] = br.ReadInt32(); }); } + + else if (StartsFromSaveRam) + { + bl.GetLump(BinaryStateLump.MovieSaveRam, false, + delegate(BinaryReader br, long length) + { + SaveRam = br.ReadBytes((int)length); + }); + } } Changes = false; @@ -193,6 +202,10 @@ namespace BizHawk.Client.Common (BinaryWriter bw) => BizHawk.Common.IOExtensions.IOExtensions.Write(bw, SavestateFramebuffer)); } } + else if (StartsFromSaveRam) + { + bs.PutLump(BinaryStateLump.MovieSaveRam, (BinaryWriter bw) => bw.Write(SaveRam)); + } } Changes = false; diff --git a/BizHawk.Client.Common/movie/bkm/BkmMovie.HeaderApi.cs b/BizHawk.Client.Common/movie/bkm/BkmMovie.HeaderApi.cs index d46e816cdb..79027e5a65 100644 --- a/BizHawk.Client.Common/movie/bkm/BkmMovie.HeaderApi.cs +++ b/BizHawk.Client.Common/movie/bkm/BkmMovie.HeaderApi.cs @@ -40,6 +40,9 @@ namespace BizHawk.Client.Common set { Header.StartsFromSavestate = value; } } + // Bkm doesn't support saveram anchored movies + public bool StartsFromSaveRam { get { return false; } set { } } + public string GameName { get { return Header.GameName; } @@ -91,5 +94,6 @@ namespace BizHawk.Client.Common public string TextSavestate { get; set; } public byte[] BinarySavestate { get; set; } public int[] SavestateFramebuffer { get { return null; } set { } } // eat and ignore framebuffers + public byte[] SaveRam { get { return null; } set { } } // Bkm does not support Saveram anchored movies } } diff --git a/BizHawk.Client.Common/movie/conversions/MovieConversionExtensions.cs b/BizHawk.Client.Common/movie/conversions/MovieConversionExtensions.cs index 480dffc788..6d31185e0c 100644 --- a/BizHawk.Client.Common/movie/conversions/MovieConversionExtensions.cs +++ b/BizHawk.Client.Common/movie/conversions/MovieConversionExtensions.cs @@ -68,6 +68,7 @@ namespace BizHawk.Client.Common.MovieConversionExtensions tas.TextSavestate = old.TextSavestate; tas.BinarySavestate = old.BinarySavestate; + tas.SaveRam = old.SaveRam; return tas; } @@ -110,6 +111,7 @@ namespace BizHawk.Client.Common.MovieConversionExtensions bk2.TextSavestate = old.TextSavestate; bk2.BinarySavestate = old.BinarySavestate; + bk2.SaveRam = old.SaveRam; bk2.Save(); return bk2; diff --git a/BizHawk.Client.Common/movie/interfaces/IMovie.cs b/BizHawk.Client.Common/movie/interfaces/IMovie.cs index ddba54c898..bbe78438c8 100644 --- a/BizHawk.Client.Common/movie/interfaces/IMovie.cs +++ b/BizHawk.Client.Common/movie/interfaces/IMovie.cs @@ -52,8 +52,12 @@ namespace BizHawk.Client.Common byte[] BinarySavestate { get; set; } int[] SavestateFramebuffer { get; set; } + // saveram anchor + byte[] SaveRam { get; set; } + ulong Rerecords { get; set; } bool StartsFromSavestate { get; set; } + bool StartsFromSaveRam { get; set; } string GameName { get; set; } string SystemID { get; set; } string Hash { get; set; } diff --git a/BizHawk.Client.EmuHawk/MainForm.Movie.cs b/BizHawk.Client.EmuHawk/MainForm.Movie.cs index 8befae6957..076dbc1bb2 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Movie.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Movie.cs @@ -82,6 +82,10 @@ namespace BizHawk.Client.EmuHawk } Global.Emulator.ResetCounters(); } + else if (Global.Emulator.HasSaveRam() && movie.StartsFromSaveRam) + { + Global.Emulator.AsSaveRam().StoreSaveRam(movie.SaveRam); + } Global.MovieSession.RunQueuedMovie(record); diff --git a/BizHawk.Client.EmuHawk/movie/RecordMovie.Designer.cs b/BizHawk.Client.EmuHawk/movie/RecordMovie.Designer.cs index e0413de2a3..9670da9382 100644 --- a/BizHawk.Client.EmuHawk/movie/RecordMovie.Designer.cs +++ b/BizHawk.Client.EmuHawk/movie/RecordMovie.Designer.cs @@ -95,7 +95,8 @@ this.StartFromCombo.FormattingEnabled = true; this.StartFromCombo.Items.AddRange(new object[] { "Power-On", - "Now"}); + "Now", + "SaveRam"}); this.StartFromCombo.Location = new System.Drawing.Point(83, 65); this.StartFromCombo.MaxDropDownItems = 32; this.StartFromCombo.Name = "StartFromCombo"; diff --git a/BizHawk.Client.EmuHawk/movie/RecordMovie.cs b/BizHawk.Client.EmuHawk/movie/RecordMovie.cs index c89e28428c..fb8fdfc849 100644 --- a/BizHawk.Client.EmuHawk/movie/RecordMovie.cs +++ b/BizHawk.Client.EmuHawk/movie/RecordMovie.cs @@ -28,6 +28,15 @@ namespace BizHawk.Client.EmuHawk .First(i => i.ToString() .ToLower() == "now")); } + + if (!Global.Emulator.HasSaveRam()) + { + StartFromCombo.Items.Remove( + StartFromCombo.Items + .OfType() + .First(i => i.ToString() + .ToLower() == "saveram")); + } } private string MakePath() @@ -84,6 +93,7 @@ namespace BizHawk.Client.EmuHawk var core = Global.Emulator.AsStatable(); movieToRecord.StartsFromSavestate = true; + movieToRecord.StartsFromSaveRam = false; if (core.BinarySaveStatesPreferred) { @@ -104,11 +114,17 @@ namespace BizHawk.Client.EmuHawk movieToRecord.SavestateFramebuffer = new int[0]; if (movieToRecord.SavestateFramebuffer != null) { - movieToRecord.SavestateFramebuffer = (int[])Global.Emulator.VideoProvider().GetVideoBuffer().Clone(); } } } + else if (StartFromCombo.SelectedItem.ToString() == "SaveRam" && Global.Emulator.HasSaveRam()) + { + var core = Global.Emulator.AsSaveRam(); + movieToRecord.StartsFromSavestate = false; + movieToRecord.StartsFromSaveRam = true; + movieToRecord.SaveRam = core.CloneSaveRam(); + } movieToRecord.PopulateWithDefaultHeaderValues(AuthorBox.Text); movieToRecord.Save();