BizHawk/BizHawk.Client.Common/movie/tasproj/TasMovie.IO.cs

317 lines
7.9 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using BizHawk.Common;
using BizHawk.Common.CollectionExtensions;
using BizHawk.Common.IOExtensions;
using System.Diagnostics;
using System.ComponentModel;
namespace BizHawk.Client.Common
{
public partial class TasMovie
{
public Func<string> ClientSettingsForSave { get; set; }
public Action<string> GetClientSettingsOnLoad { get; set; }
private const double PROGRESS_STEP = 100 / 12; // TODO hardcoded for now, there might be a better way of doing this
private double _totalProgress = 0;
private void ReportProgress(double percent)
{
if (_progressReportWorker != null)
{
_totalProgress += percent;
_progressReportWorker.ReportProgress((int)_totalProgress);
}
}
protected override void Write(string fn)
{
_totalProgress = 0;
var file = new FileInfo(fn);
if (!file.Directory.Exists)
{
Directory.CreateDirectory(file.Directory.ToString());
}
using (var bs = new BinaryStateSaver(fn, false))
{
bs.PutLump(BinaryStateLump.Movieheader, tw => tw.WriteLine(Header.ToString()));
ReportProgress(PROGRESS_STEP);
bs.PutLump(BinaryStateLump.Comments, tw => tw.WriteLine(CommentsString()));
ReportProgress(PROGRESS_STEP);
bs.PutLump(BinaryStateLump.Subtitles, tw => tw.WriteLine(Subtitles.ToString()));
ReportProgress(PROGRESS_STEP);
bs.PutLump(BinaryStateLump.SyncSettings, tw => tw.WriteLine(SyncSettingsJson));
ReportProgress(PROGRESS_STEP);
bs.PutLump(BinaryStateLump.Input, tw => tw.WriteLine(RawInputLog()));
ReportProgress(PROGRESS_STEP);
// TasProj extras
bs.PutLump(BinaryStateLump.StateHistorySettings, tw => tw.WriteLine(StateManager.Settings.ToString()));
ReportProgress(PROGRESS_STEP);
if (StateManager.Settings.SaveStateHistory)
{
bs.PutLump(BinaryStateLump.StateHistory, (BinaryWriter bw) => StateManager.Save(bw));
}
ReportProgress(PROGRESS_STEP);
bs.PutLump(BinaryStateLump.LagLog, (BinaryWriter bw) => LagLog.Save(bw));
ReportProgress(PROGRESS_STEP);
bs.PutLump(BinaryStateLump.Markers, tw => tw.WriteLine(Markers.ToString()));
ReportProgress(PROGRESS_STEP);
if (StartsFromSavestate)
{
if (TextSavestate != null)
{
bs.PutLump(BinaryStateLump.CorestateText, (TextWriter tw) => tw.Write(TextSavestate));
}
else
{
bs.PutLump(BinaryStateLump.Corestate, (BinaryWriter bw) => bw.Write(BinarySavestate));
}
}
else if (StartsFromSaveRam)
{
bs.PutLump(BinaryStateLump.MovieSaveRam, (BinaryWriter bw) => bw.Write(SaveRam));
}
ReportProgress(PROGRESS_STEP);
if (ClientSettingsForSave != null)
{
var clientSettingsJson = ClientSettingsForSave();
bs.PutLump(BinaryStateLump.ClientSettings, (TextWriter tw) => tw.Write(clientSettingsJson));
}
ReportProgress(PROGRESS_STEP);
if (VerificationLog.Any())
{
bs.PutLump(BinaryStateLump.VerificationLog, tw => tw.WriteLine(InputLogToString(VerificationLog)));
}
if (Branches.Any())
{
Branches.Save(bs);
}
ReportProgress(PROGRESS_STEP);
}
Changes = false;
}
public override bool Load(bool preload)
{
var file = new FileInfo(Filename);
if (!file.Exists)
{
return false;
}
using (var bl = BinaryStateLoader.LoadAndDetect(Filename, true))
{
if (bl == null)
{
return false;
}
ClearBeforeLoad();
ClearTasprojExtras();
bl.GetLump(BinaryStateLump.Movieheader, true, delegate(TextReader tr)
{
string line;
while ((line = tr.ReadLine()) != null)
{
if (!string.IsNullOrWhiteSpace(line))
{
var pair = line.Split(new[] { ' ' }, 2, StringSplitOptions.RemoveEmptyEntries);
if (pair.Length > 1)
{
Header.Add(pair[0], pair[1]);
}
}
}
});
bl.GetLump(BinaryStateLump.Comments, true, delegate(TextReader tr)
{
string line;
while ((line = tr.ReadLine()) != null)
{
if (!string.IsNullOrWhiteSpace(line))
{
Comments.Add(line);
}
}
});
bl.GetLump(BinaryStateLump.Subtitles, true, delegate(TextReader tr)
{
string line;
while ((line = tr.ReadLine()) != null)
{
if (!string.IsNullOrWhiteSpace(line))
{
Subtitles.AddFromString(line);
}
}
});
bl.GetLump(BinaryStateLump.SyncSettings, true, delegate(TextReader tr)
{
string line;
while ((line = tr.ReadLine()) != null)
{
if (!string.IsNullOrWhiteSpace(line))
{
SyncSettingsJson = line;
}
}
});
bl.GetLump(BinaryStateLump.Input, true, delegate(TextReader tr) // Note: ExtractInputLog will clear Lag and State data potentially, this must come before loading those
{
var errorMessage = string.Empty;
IsCountingRerecords = false;
ExtractInputLog(tr, out errorMessage);
IsCountingRerecords = true;
});
if (StartsFromSavestate)
{
bl.GetCoreState(
delegate(BinaryReader br, long length)
{
BinarySavestate = br.ReadBytes((int)length);
},
delegate(TextReader tr)
{
TextSavestate = tr.ReadToEnd();
});
}
else if (StartsFromSaveRam)
{
bl.GetLump(BinaryStateLump.MovieSaveRam, false,
delegate(BinaryReader br, long length)
{
SaveRam = br.ReadBytes((int)length);
});
}
// TasMovie enhanced information
if (bl.HasLump(BinaryStateLump.LagLog))
{
bl.GetLump(BinaryStateLump.LagLog, false, delegate(BinaryReader br, long length)
{
LagLog.Load(br);
});
}
bl.GetLump(BinaryStateLump.StateHistorySettings, false, delegate(TextReader tr)
{
StateManager.Settings.PopulateFromString(tr.ReadToEnd());
});
if(!preload)
{
if (StateManager.Settings.SaveStateHistory)
{
bl.GetLump(BinaryStateLump.StateHistory, false, delegate(BinaryReader br, long length)
{
StateManager.Load(br);
});
}
// Movie should always have a state at frame 0.
if (!this.StartsFromSavestate)
StateManager.Capture();
}
bl.GetLump(BinaryStateLump.Markers, false, delegate(TextReader tr)
{
string line;
while ((line = tr.ReadLine()) != null)
{
if (!string.IsNullOrWhiteSpace(line))
{
Markers.Add(new TasMovieMarker(line));
}
}
});
if (GetClientSettingsOnLoad != null && bl.HasLump(BinaryStateLump.ClientSettings))
{
string clientSettings = string.Empty;
bl.GetLump(BinaryStateLump.ClientSettings, true, delegate(TextReader tr)
{
string line;
while ((line = tr.ReadLine()) != null)
{
if (!string.IsNullOrWhiteSpace(line))
{
clientSettings = line;
}
}
});
GetClientSettingsOnLoad(clientSettings);
}
if (bl.HasLump(BinaryStateLump.VerificationLog))
{
bl.GetLump(BinaryStateLump.VerificationLog, true, delegate(TextReader tr)
{
VerificationLog.Clear();
while (true)
{
var line = tr.ReadLine();
if (string.IsNullOrEmpty(line))
{
break;
}
if (line.StartsWith("|"))
{
VerificationLog.Add(line);
}
}
});
}
Branches.Load(bl);
}
Changes = false;
return true;
}
private void ClearTasprojExtras()
{
LagLog.Clear();
StateManager.Clear();
Markers.Clear();
ChangeLog.ClearLog();
}
private static string InputLogToString(List<string> log)
{
var sb = new StringBuilder();
foreach (var record in log)
{
sb.AppendLine(record);
}
return sb.ToString();
}
}
}