using System.IO; using BizHawk.Common.BufferExtensions; namespace BizHawk.Emulation.Common { /// /// Binary save and load state only without any trappings. At the moment, an emulator core should not implement this directly /// public interface IBinaryStateable { void SaveStateBinary(BinaryWriter writer); void LoadStateBinary(BinaryReader reader); } /// /// This service manages the logic of sending and receiving savestates from the core /// If this service is available, client apps will expose features for making savestates and that utilize savestates (such as rewind)) /// If unavailable these options will not be exposed /// Additionally many tools depend on savestates such as TAStudio, these will only be available if this service is implemented /// public interface IStatable : IEmulatorService { void SaveStateBinary(BinaryWriter writer); void LoadStateBinary(BinaryReader reader); /// /// save state binary to a byte buffer /// /// you may NOT modify this. if you call SaveStateBinary() again with the same core, the old data MAY be overwritten. byte[] SaveStateBinary(); } /// /// Allows a core to opt into text savestates. /// If a core does not implement this interface, a default implementation /// will be used that doesn't yield anything useful in the states, just binary as text /// public interface ITextStatable : IStatable { void SaveStateText(TextWriter writer); void LoadStateText(TextReader reader); } public static class StatableExtensions { public static void SaveStateText(this IStatable core, TextWriter writer) { if (core is ITextStatable textCore) { textCore.SaveStateText(writer); } var temp = core.SaveStateBinary(); temp.SaveAsHexFast(writer); } public static void LoadStateText(this IStatable core, TextReader reader) { if (core is ITextStatable textCore) { textCore.LoadStateText(reader); } string hex = reader.ReadLine(); if (hex != null) { var state = new byte[hex.Length / 2]; state.ReadFromHexFast(hex); using var ms = new MemoryStream(state); using var br = new BinaryReader(ms); core.LoadStateBinary(br); } } public static void LoadStateText(this IStatable core, string textState) { core.LoadStateText(new StringReader(textState)); } /// /// Loads a state directly from a byte array /// public static void LoadStateBinary(this IStatable core, byte[] state) { using var ms = new MemoryStream(state, false); using var br = new BinaryReader(ms); core.LoadStateBinary(br); } } }