diff --git a/src/BizHawk.Client.Common/SavestateManager.cs b/src/BizHawk.Client.Common/savestates/SavestateManager.cs similarity index 96% rename from src/BizHawk.Client.Common/SavestateManager.cs rename to src/BizHawk.Client.Common/savestates/SavestateManager.cs index 5a63f841a0..e999ce2e10 100644 --- a/src/BizHawk.Client.Common/SavestateManager.cs +++ b/src/BizHawk.Client.Common/savestates/SavestateManager.cs @@ -1,204 +1,204 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; - -using BizHawk.Common; -using BizHawk.Emulation.Common; - -namespace BizHawk.Client.Common -{ - public static class SavestateManager - { - public static void SaveStateFile(IEmulator emulator, string filename) - { - var core = 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 ZipStateSaver(filename, Global.Config.SaveStateCompressionLevelNormal); - bs.PutVersionLumps(); - if (Global.Config.SaveStateType == SaveStateTypeE.Text) - { - // 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 && emulator.HasVideoProvider()) - { - var vp = 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(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}", emulator.Frame); - Global.MovieSession.HandleSaveState(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 ITasMovie) - { - bs.PutLump(BinaryStateLump.LagLog, - delegate(TextWriter tw) - { - ((ITasMovie)Global.MovieSession.Movie).LagLog.Save(tw); - }); - } - } - - public static bool LoadStateFile(IEmulator emulator, string path) - { - var core = emulator.AsStatable(); - - // 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 (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; - } - } - - if (emulator.HasVideoProvider()) - { - bl.GetLump(BinaryStateLump.Framebuffer, false, br => PopulateFramebuffer(br, emulator.AsVideoProvider())); - } - - 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)ConfigService.LoadWithType(userData); - } - - if (Global.MovieSession.Movie.IsActive() && Global.MovieSession.Movie is ITasMovie) - { - bl.GetLump(BinaryStateLump.LagLog, false, delegate(TextReader tr) - { - ((ITasMovie)Global.MovieSession.Movie).LagLog.Load(tr); - }); - } - } - finally - { - bl.Dispose(); - } - - return true; - } - - return false; - } - - private static void PopulateFramebuffer(BinaryReader br, IVideoProvider videoProvider) - { - try - { - using (new SimpleTime("Load Framebuffer")) - { - QuickBmpFile.Load(videoProvider, br.BaseStream); - } - } - catch - { - var buff = videoProvider.GetVideoBuffer(); - try - { - for (int i = 0; i < buff.Length; i++) - { - int j = br.ReadInt32(); - buff[i] = j; - } - } - catch (EndOfStreamException) - { - } - } - } - } -} +using System.Collections.Generic; +using System.IO; +using System.Linq; + +using BizHawk.Common; +using BizHawk.Emulation.Common; + +namespace BizHawk.Client.Common +{ + public static class SavestateManager + { + public static void SaveStateFile(IEmulator emulator, string filename) + { + var core = 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 ZipStateSaver(filename, Global.Config.SaveStateCompressionLevelNormal); + bs.PutVersionLumps(); + if (Global.Config.SaveStateType == SaveStateTypeE.Text) + { + // 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 && emulator.HasVideoProvider()) + { + var vp = 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(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}", emulator.Frame); + Global.MovieSession.HandleSaveState(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 ITasMovie) + { + bs.PutLump(BinaryStateLump.LagLog, + delegate(TextWriter tw) + { + ((ITasMovie)Global.MovieSession.Movie).LagLog.Save(tw); + }); + } + } + + public static bool LoadStateFile(IEmulator emulator, string path) + { + var core = emulator.AsStatable(); + + // 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 (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; + } + } + + if (emulator.HasVideoProvider()) + { + bl.GetLump(BinaryStateLump.Framebuffer, false, br => PopulateFramebuffer(br, emulator.AsVideoProvider())); + } + + 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)ConfigService.LoadWithType(userData); + } + + if (Global.MovieSession.Movie.IsActive() && Global.MovieSession.Movie is ITasMovie) + { + bl.GetLump(BinaryStateLump.LagLog, false, delegate(TextReader tr) + { + ((ITasMovie)Global.MovieSession.Movie).LagLog.Load(tr); + }); + } + } + finally + { + bl.Dispose(); + } + + return true; + } + + return false; + } + + private static void PopulateFramebuffer(BinaryReader br, IVideoProvider videoProvider) + { + try + { + using (new SimpleTime("Load Framebuffer")) + { + QuickBmpFile.Load(videoProvider, br.BaseStream); + } + } + catch + { + var buff = videoProvider.GetVideoBuffer(); + try + { + for (int i = 0; i < buff.Length; i++) + { + int j = br.ReadInt32(); + buff[i] = j; + } + } + catch (EndOfStreamException) + { + } + } + } + } +}