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);
}
}
}