rework the binary savestates. not done yet. don't load any binary savestates from before this revision, you will cause death and destruction

This commit is contained in:
goyuken 2013-08-11 21:02:36 +00:00
parent fa8cbf650d
commit 4de024e570
4 changed files with 245 additions and 72 deletions

View File

@ -0,0 +1,143 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICSharpCode.SharpZipLib.Zip;
using System.IO;
namespace BizHawk.MultiClient
{
public class BinaryStateFileNames
{
public const string versiontag = "BizState 1.0";
public const string corestate = "Core";
public const string framebuffer = "Framebuffer";
public const string input = "Input Log";
}
public class BinaryStateLoader : IDisposable
{
bool disposed = false;
public void Dispose()
{
if (!disposed)
{
disposed = true;
zip.Close();
}
}
ZipFile zip;
private BinaryStateLoader()
{
}
public static BinaryStateLoader LoadAndDetect(string Filename)
{
BinaryStateLoader ret = new BinaryStateLoader();
try
{
ret.zip = new ZipFile(Filename);
var e = ret.zip.GetEntry(BinaryStateFileNames.versiontag);
if (e == null)
{
ret.zip.Close();
return null;
}
return ret;
}
catch (ZipException)
{
return null;
}
}
bool GetFileByName(string Name, bool abort, Action<Stream> callback)
{
var e = zip.GetEntry(Name);
if (e != null)
{
using (Stream zs = zip.GetInputStream(e))
{
callback(zs);
}
return true;
}
else if (abort)
{
throw new Exception("Essential zip section not found: " + Name);
}
else
{
return false;
}
}
public void GetCoreState(Action<Stream> callback)
{
GetFileByName(BinaryStateFileNames.corestate, true, callback);
}
public bool GetFrameBuffer(Action<Stream> callback)
{
return GetFileByName(BinaryStateFileNames.framebuffer, false, callback);
}
}
public class BinaryStateSaver : IDisposable
{
ZipOutputStream zip;
bool disposed = false;
/// <summary>
///
/// </summary>
/// <param name="s">not closed when finished!</param>
public BinaryStateSaver(Stream s)
{
zip = new ZipOutputStream(s);
zip.IsStreamOwner = false;
zip.SetLevel(0);
zip.UseZip64 = UseZip64.Off;
PutFileByName(BinaryStateFileNames.versiontag, (ss) => { });
}
void PutFileByName(string Name, Action<Stream> callback)
{
var e = new ZipEntry(Name);
e.CompressionMethod = CompressionMethod.Stored;
zip.PutNextEntry(e);
callback(zip);
zip.CloseEntry();
}
public void PutCoreState(Action<Stream> callback)
{
PutFileByName(BinaryStateFileNames.corestate, callback);
}
public void PutFrameBuffer(Action<Stream> callback)
{
PutFileByName(BinaryStateFileNames.framebuffer, callback);
}
public void PutInputLog(Action<Stream> callback)
{
PutFileByName(BinaryStateFileNames.input, callback);
}
public void Dispose()
{
if (!disposed)
{
disposed = true;
zip.Dispose();
}
}
}
}

View File

@ -152,6 +152,7 @@
<DependentUpon>VideoWriterChooserForm.cs</DependentUpon>
</Compile>
<Compile Include="AVOut\WavWriter.cs" />
<Compile Include="BinarySaveStates.cs" />
<Compile Include="BizBox.cs">
<SubType>Form</SubType>
</Compile>

View File

@ -2395,12 +2395,10 @@ namespace BizHawk.MultiClient
public void SaveStateFile(string filename, string name, bool fromLua)
{
// since movie mode requires input log, always save text in that case
if (Global.MovieSession.Movie.IsActive ||
Global.Config.SaveStateType == Config.SaveStateTypeE.Text ||
if (Global.Config.SaveStateType == Config.SaveStateTypeE.Text ||
(Global.Config.SaveStateType == Config.SaveStateTypeE.Default && !Global.Emulator.BinarySaveStatesPreferred))
{
//DateTime start = DateTime.UtcNow;
// text mode savestates
var writer = new StreamWriter(filename);
Global.Emulator.SaveStateText(writer);
HandleMovieSaveState(writer);
@ -2415,18 +2413,40 @@ namespace BizHawk.MultiClient
}
else
{
// binary savestate
//DateTime start = DateTime.UtcNow;
var writer = new BinaryWriter(new FileStream(filename, FileMode.Create));
Global.Emulator.SaveStateBinary(writer);
if (Global.Config.SaveScreenshotWithStates)
// binary savestates
using (FileStream fs = new FileStream(filename, FileMode.Create, FileAccess.Write))
using (BinaryStateSaver bs = new BinaryStateSaver(fs))
{
writer.Write("FRAMEBUFFA");
var buff = Global.Emulator.VideoProvider.GetVideoBuffer();
writer.Write(buff.Length);
writer.Write(buff);
bs.PutCoreState(
delegate(Stream s)
{
BinaryWriter bw = new BinaryWriter(s);
Global.Emulator.SaveStateBinary(bw);
bw.Flush();
});
if (Global.Config.SaveScreenshotWithStates)
{
bs.PutFrameBuffer(
delegate(Stream s)
{
var buff = Global.Emulator.VideoProvider.GetVideoBuffer();
BinaryWriter bw = new BinaryWriter(s);
bw.Write(buff);
bw.Flush();
});
}
if (Global.MovieSession.Movie.IsActive)
{
bs.PutInputLog(
delegate(Stream s)
{
StreamWriter sw = new StreamWriter(s);
HandleMovieSaveState(sw);
sw.WriteLine("Frame: {0}", Global.Emulator.Frame);
sw.Flush();
});
}
}
writer.Close();
//DateTime end = DateTime.UtcNow;
//Console.WriteLine("n64 savestate TEXT time: {0}", (end - start).TotalMilliseconds);
}
@ -2459,74 +2479,77 @@ namespace BizHawk.MultiClient
public void LoadStateFile(string path, string name, bool fromLua = false)
{
if (!Global.MovieSession.Movie.IsActive)
// try to detect binary first
BinaryStateLoader bw = BinaryStateLoader.LoadAndDetect(path);
if (bw != null)
{
// only when movies are not playing can we possibly load binary savestates
bool binary = false;
using (var s = new FileStream(path, FileMode.Open, FileAccess.Read))
try
{
int i;
while ((i = s.ReadByte()) != -1)
{
// unicode support will need something better here
if (i < 0x9 || (i > 0x7f))
{
binary = true;
break;
}
}
}
// binary mode
if (Global.MovieSession.Movie.IsActive)
throw new Exception("NOT DONE YET BRO");
if (binary)
{
using (var reader = new BinaryReader(new FileStream(path, FileMode.Open, FileAccess.Read)))
{
Global.Emulator.LoadStateBinary(reader);
try
bw.GetCoreState(
delegate(Stream s)
{
string s = reader.ReadString();
if (s.Equals("FRAMEBUFFA"))
BinaryReader br = new BinaryReader(s);
Global.Emulator.LoadStateBinary(br);
});
bw.GetFrameBuffer(
delegate(Stream s)
{
BinaryReader br = new BinaryReader(s);
int i;
var buff = Global.Emulator.VideoProvider.GetVideoBuffer();
try
{
int len = reader.ReadInt32();
var buff = Global.Emulator.VideoProvider.GetVideoBuffer();
for (int i = 0; i < len; i++)
buff[i] = reader.ReadInt32();
for (i = 0; i < buff.Length; i++)
{
int j = br.ReadInt32();
buff[i] = j;
}
}
catch (EndOfStreamException)
{
}
});
}
finally
{
bw.Dispose();
}
}
else
{
// text mode
if (HandleMovieLoadState(path))
{
using (var reader = new StreamReader(path))
{
Global.Emulator.LoadStateText(reader);
while (true)
{
string str = reader.ReadLine();
if (str == null) break;
if (str.Trim() == "") continue;
string[] args = str.Split(' ');
if (args[0] == "Framebuffer")
{
Global.Emulator.VideoProvider.GetVideoBuffer().ReadFromHex(args[1]);
}
}
catch { }
}
goto cleanup;
}
else
{
// fall through to text situation
}
Global.OSD.AddMessage("Loadstate error!");
}
if (HandleMovieLoadState(path))
{
var reader = new StreamReader(path);
Global.Emulator.LoadStateText(reader);
while (true)
{
string str = reader.ReadLine();
if (str == null) break;
if (str.Trim() == "") continue;
string[] args = str.Split(' ');
if (args[0] == "Framebuffer")
{
Global.Emulator.VideoProvider.GetVideoBuffer().ReadFromHex(args[1]);
}
}
reader.Close();
}
else
Global.OSD.AddMessage("Loadstate error!");
cleanup:
Global.OSD.ClearGUIText();
UpdateToolsBefore(fromLua);

View File

@ -654,7 +654,14 @@ namespace BizHawk.MultiClient
public void LoadLogFromSavestateText(string path)
{
var reader = new StreamReader(path);
using (var reader = new StreamReader(path))
{
LoadLogFromSavestateText(reader);
}
}
public void LoadLogFromSavestateText(TextReader reader)
{
int? stateFrame = null;
//We are in record mode so replace the movie log with the one from the savestate
if (!Global.MovieSession.MultiTrack.IsActive)
@ -754,7 +761,6 @@ namespace BizHawk.MultiClient
}
if (IsCountingRerecords)
Rerecords++;
reader.Close();
}
public string GetTime(bool preLoad)