using System; using System.IO; using System.Text; namespace MyNes.Core { public class StateHandler { public static int Slot = 0; internal static string StateFolder = "States"; private const byte state_version = 7; private static bool IsSavingState = false; private static bool IsLoadingState = false; public static void SaveState(string fileName, bool saveImage) { if (!NesEmu.ON) { Tracer.WriteError("Can't save state, emu is off."); MyNesMain.VideoProvider.WriteErrorNotification(MNInterfaceLanguage.Message_Error1, instant: false); return; } if (!File.Exists(NesEmu.CurrentFilePath)) { Tracer.WriteError("Can't save state, no rom file is loaded."); MyNesMain.VideoProvider.WriteErrorNotification(MNInterfaceLanguage.Message_Error2, instant: false); return; } if (IsLoadingState) { Tracer.WriteError("Can't save state while loading a state !"); MyNesMain.VideoProvider.WriteErrorNotification(MNInterfaceLanguage.Message_Error3, instant: false); return; } if (IsSavingState) { Tracer.WriteError("Already saving state !!"); MyNesMain.VideoProvider.WriteErrorNotification(MNInterfaceLanguage.Message_Error4, instant: false); return; } IsSavingState = true; BinaryWriter bin = new BinaryWriter(new MemoryStream()); bin.Write(Encoding.ASCII.GetBytes("MNS")); bin.Write((byte)7); for (int i = 0; i < NesEmu.SHA1.Length; i += 2) { string value = NesEmu.SHA1.Substring(i, 2).ToUpper(); bin.Write(Convert.ToByte(value, 16)); } NesEmu.WriteStateData(ref bin); byte[] outData = new byte[0]; ZlipWrapper.CompressData(((MemoryStream)bin.BaseStream).GetBuffer(), out outData); FileStream fileStream = new FileStream(fileName, FileMode.Create, FileAccess.Write); fileStream.Write(outData, 0, outData.Length); MyNesMain.VideoProvider.TakeSnapshotAs(fileName.Replace(".mns", ".jpg"), ".jpg"); bin.Flush(); bin.Close(); fileStream.Flush(); fileStream.Close(); IsSavingState = false; Tracer.WriteInformation("State saved at slot " + Slot); MyNesMain.VideoProvider.WriteInfoNotification(MNInterfaceLanguage.Message_Info1 + " " + Slot, instant: false); } public static void SaveState(int Slot) { if (StateFolder == "States") { StateFolder = Path.Combine(MyNesMain.WorkingFolder, "States"); } Directory.CreateDirectory(StateFolder); SaveState(Path.Combine(StateFolder, Path.GetFileNameWithoutExtension(NesEmu.CurrentFilePath)) + "_" + Slot + ".mns", saveImage: false); } public static void SaveState() { SaveState(Slot); } public static void LoadState() { LoadState(Slot); } public static void LoadState(string fileName) { if (!NesEmu.ON) { Tracer.WriteError("Can't load state, emu is off."); MyNesMain.VideoProvider.WriteErrorNotification(MNInterfaceLanguage.Message_Error5, instant: false); return; } if (!File.Exists(NesEmu.CurrentFilePath)) { Tracer.WriteError("Can't load state, no rom file is loaded."); MyNesMain.VideoProvider.WriteErrorNotification(MNInterfaceLanguage.Message_Error6, instant: false); return; } if (IsSavingState) { Tracer.WriteError("Can't load state while saving a state !"); MyNesMain.VideoProvider.WriteErrorNotification(MNInterfaceLanguage.Message_Error7, instant: false); return; } if (IsLoadingState) { Tracer.WriteError("Already loading state !!"); MyNesMain.VideoProvider.WriteErrorNotification(MNInterfaceLanguage.Message_Error8, instant: false); return; } if (!File.Exists(fileName)) { Tracer.WriteError("No state found in slot " + Slot); MyNesMain.VideoProvider.WriteErrorNotification(MNInterfaceLanguage.Message_Error9 + " " + Slot, instant: false); return; } IsLoadingState = true; FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read); byte[] array = new byte[fileStream.Length]; byte[] outData = new byte[0]; fileStream.Read(array, 0, array.Length); fileStream.Close(); ZlipWrapper.DecompressData(array, out outData); BinaryReader bin = new BinaryReader(new MemoryStream(outData)); byte[] array2 = new byte[3]; bin.Read(array2, 0, array2.Length); if (Encoding.ASCII.GetString(array2) != "MNS") { Tracer.WriteError("Unable load state at slot " + Slot + "; Not My Nes State File !"); MyNesMain.VideoProvider.WriteErrorNotification(MNInterfaceLanguage.Message_Error10 + " " + Slot + "; " + MNInterfaceLanguage.Message_Error11, instant: false); IsLoadingState = false; return; } if (bin.ReadByte() != 7) { Tracer.WriteError("Unable load state at slot " + Slot + "; Not compatible state file version !"); MyNesMain.VideoProvider.WriteErrorNotification(MNInterfaceLanguage.Message_Error10 + " " + Slot + "; " + MNInterfaceLanguage.Message_Error12, instant: false); IsLoadingState = false; return; } string text = ""; for (int i = 0; i < NesEmu.SHA1.Length; i += 2) { text += bin.ReadByte().ToString("X2"); } if (text.ToLower() != NesEmu.SHA1.ToLower()) { Tracer.WriteError("Unable load state at slot " + Slot + "; This state file is not for this game; not same SHA1 !"); MyNesMain.VideoProvider.WriteErrorNotification(MNInterfaceLanguage.Message_Error10 + " " + Slot + "; " + MNInterfaceLanguage.Message_Error13, instant: false); IsLoadingState = false; } else { NesEmu.ReadStateData(ref bin); bin.Close(); IsLoadingState = false; Tracer.WriteInformation("State loaded from slot " + Slot); MyNesMain.VideoProvider.WriteInfoNotification(MNInterfaceLanguage.Message_Info2 + " " + Slot, instant: false); } } public static void LoadState(int Slot) { if (StateFolder == "States") { StateFolder = Path.Combine(MyNesMain.WorkingFolder, "States"); } Directory.CreateDirectory(StateFolder); LoadState(Path.Combine(StateFolder, Path.GetFileNameWithoutExtension(NesEmu.CurrentFilePath)) + "_" + Slot + ".mns"); } public static string GetStateFile(int slot) { if (File.Exists(NesEmu.CurrentFilePath)) { return Path.Combine(StateFolder, Path.GetFileNameWithoutExtension(NesEmu.CurrentFilePath)) + "_" + slot + ".mns"; } return ""; } public static string GetStateImageFile(int slot) { if (File.Exists(NesEmu.CurrentFilePath)) { return Path.Combine(StateFolder, Path.GetFileNameWithoutExtension(NesEmu.CurrentFilePath)) + "_" + slot + ".jpg"; } return ""; } } }