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> <DependentUpon>VideoWriterChooserForm.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="AVOut\WavWriter.cs" /> <Compile Include="AVOut\WavWriter.cs" />
<Compile Include="BinarySaveStates.cs" />
<Compile Include="BizBox.cs"> <Compile Include="BizBox.cs">
<SubType>Form</SubType> <SubType>Form</SubType>
</Compile> </Compile>

View File

@ -2395,12 +2395,10 @@ namespace BizHawk.MultiClient
public void SaveStateFile(string filename, string name, bool fromLua) public void SaveStateFile(string filename, string name, bool fromLua)
{ {
// since movie mode requires input log, always save text in that case if (Global.Config.SaveStateType == Config.SaveStateTypeE.Text ||
if (Global.MovieSession.Movie.IsActive ||
Global.Config.SaveStateType == Config.SaveStateTypeE.Text ||
(Global.Config.SaveStateType == Config.SaveStateTypeE.Default && !Global.Emulator.BinarySaveStatesPreferred)) (Global.Config.SaveStateType == Config.SaveStateTypeE.Default && !Global.Emulator.BinarySaveStatesPreferred))
{ {
//DateTime start = DateTime.UtcNow; // text mode savestates
var writer = new StreamWriter(filename); var writer = new StreamWriter(filename);
Global.Emulator.SaveStateText(writer); Global.Emulator.SaveStateText(writer);
HandleMovieSaveState(writer); HandleMovieSaveState(writer);
@ -2415,18 +2413,40 @@ namespace BizHawk.MultiClient
} }
else else
{ {
// binary savestate // binary savestates
//DateTime start = DateTime.UtcNow; using (FileStream fs = new FileStream(filename, FileMode.Create, FileAccess.Write))
var writer = new BinaryWriter(new FileStream(filename, FileMode.Create)); using (BinaryStateSaver bs = new BinaryStateSaver(fs))
Global.Emulator.SaveStateBinary(writer);
if (Global.Config.SaveScreenshotWithStates)
{ {
writer.Write("FRAMEBUFFA"); bs.PutCoreState(
var buff = Global.Emulator.VideoProvider.GetVideoBuffer(); delegate(Stream s)
writer.Write(buff.Length); {
writer.Write(buff); 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; //DateTime end = DateTime.UtcNow;
//Console.WriteLine("n64 savestate TEXT time: {0}", (end - start).TotalMilliseconds); //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) 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 try
bool binary = false;
using (var s = new FileStream(path, FileMode.Open, FileAccess.Read))
{ {
int i; // binary mode
while ((i = s.ReadByte()) != -1) if (Global.MovieSession.Movie.IsActive)
{ throw new Exception("NOT DONE YET BRO");
// unicode support will need something better here
if (i < 0x9 || (i > 0x7f))
{
binary = true;
break;
}
}
}
if (binary) bw.GetCoreState(
{ delegate(Stream s)
using (var reader = new BinaryReader(new FileStream(path, FileMode.Open, FileAccess.Read)))
{
Global.Emulator.LoadStateBinary(reader);
try
{ {
string s = reader.ReadString(); BinaryReader br = new BinaryReader(s);
if (s.Equals("FRAMEBUFFA")) 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(); for (i = 0; i < buff.Length; i++)
var buff = Global.Emulator.VideoProvider.GetVideoBuffer(); {
for (int i = 0; i < len; i++) int j = br.ReadInt32();
buff[i] = reader.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 else
{ Global.OSD.AddMessage("Loadstate error!");
// fall through to text situation
}
} }
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: cleanup:
Global.OSD.ClearGUIText(); Global.OSD.ClearGUIText();
UpdateToolsBefore(fromLua); UpdateToolsBefore(fromLua);

View File

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