refactor TasLagLog to allow for gaps in the history. Note that this is a breaking .tasproj format change currently

This commit is contained in:
adelikat 2019-06-15 12:11:52 -05:00
parent 9cedf68407
commit 3b9e54c250
3 changed files with 45 additions and 124 deletions

View File

@ -91,9 +91,9 @@ namespace BizHawk.Client.Common
if (Global.MovieSession.Movie.IsActive && Global.MovieSession.Movie is TasMovie) if (Global.MovieSession.Movie.IsActive && Global.MovieSession.Movie is TasMovie)
{ {
bs.PutLump(BinaryStateLump.LagLog, bs.PutLump(BinaryStateLump.LagLog,
delegate(BinaryWriter bw) delegate(TextWriter tw)
{ {
(Global.MovieSession.Movie as TasMovie).TasLagLog.Save(bw); (Global.MovieSession.Movie as TasMovie).TasLagLog.Save(tw);
}); });
} }
} }
@ -195,9 +195,9 @@ namespace BizHawk.Client.Common
if (Global.MovieSession.Movie.IsActive && Global.MovieSession.Movie is TasMovie) if (Global.MovieSession.Movie.IsActive && Global.MovieSession.Movie is TasMovie)
{ {
bl.GetLump(BinaryStateLump.LagLog, false, delegate(BinaryReader br, long length) bl.GetLump(BinaryStateLump.LagLog, false, delegate(TextReader tr)
{ {
((TasMovie)Global.MovieSession.Movie).TasLagLog.Load(br); ((TasMovie)Global.MovieSession.Movie).TasLagLog.Load(tr);
}); });
} }
} }

View File

@ -1,34 +1,30 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Newtonsoft.Json;
using BizHawk.Emulation.Common.IEmulatorExtensions; using BizHawk.Emulation.Common.IEmulatorExtensions;
namespace BizHawk.Client.Common namespace BizHawk.Client.Common
{ {
public class TasLagLog public class TasLagLog
{ {
// TODO: Change this into a regular list. private Dictionary<int, bool> _lagLog = new Dictionary<int, bool>();
private List<bool> _lagLog = new List<bool>(); private Dictionary<int, bool> _wasLag = new Dictionary<int, bool>();
private List<bool> _wasLag = new List<bool>();
public bool? this[int frame] public bool? this[int frame]
{ {
get get
{ {
if (frame < _lagLog.Count) bool lag;
var result = _lagLog.TryGetValue(frame, out lag);
if (result)
{ {
if (frame < 0) return lag;
{
return null;
}
return _lagLog[frame];
} }
if (frame == Global.Emulator.Frame && frame == _lagLog.Count) // TODO: don't do this here, the calling code should decide if showing the current emulator state is the right decision
if (frame == Global.Emulator.Frame)
{ {
////LagLog[frame] = Global.Emulator.AsInputPollable().IsLagFrame; // Note: Side effects!
return Global.Emulator.AsInputPollable().IsLagFrame; return Global.Emulator.AsInputPollable().IsLagFrame;
} }
@ -39,21 +35,10 @@ namespace BizHawk.Client.Common
{ {
if (!value.HasValue) if (!value.HasValue)
{ {
_lagLog.RemoveAt(frame); _lagLog.Remove(frame);
return; return;
} }
if (frame < 0)
{
return; // Nothing to do
}
if (frame > _lagLog.Count)
{
System.Diagnostics.Debug.Print($"Lag Log error. f{frame}, log: {_lagLog.Count}");
return; // Can this break anything?
}
bool wasValue; bool wasValue;
if (frame < _lagLog.Count) if (frame < _lagLog.Count)
{ {
@ -68,147 +53,83 @@ namespace BizHawk.Client.Common
wasValue = _wasLag[frame]; wasValue = _wasLag[frame];
} }
if (frame == _wasLag.Count) _wasLag[frame] = wasValue;
{
_wasLag.Add(wasValue);
}
else
{
_wasLag[frame] = wasValue;
}
if (frame != 0) if (frame != 0)
{ {
_wasLag[frame - 1] = _lagLog[frame - 1]; _wasLag[frame - 1] = _lagLog[frame - 1];
} }
if (frame >= _lagLog.Count) _lagLog[frame] = value.Value;
{
_lagLog.Add(value.Value);
}
else
{
_lagLog[frame] = value.Value;
}
} }
} }
public void Clear() public void Clear()
{ {
// TODO: shouldn't _waslag get cleared too?
_lagLog.Clear(); _lagLog.Clear();
} }
public bool RemoveFrom(int frame) public bool RemoveFrom(int frame)
{ {
if (_lagLog.Count > frame && frame >= 0) var frames = _lagLog.Keys.Where(k => k > frame).ToList();
foreach (var f in frames)
{ {
_lagLog.RemoveRange(frame + 1, _lagLog.Count - frame - 1); _lagLog.Remove(f);
return true;
} }
return false; return frames.Any();
} }
public void RemoveHistoryAt(int frame) public void RemoveHistoryAt(int frame)
{ {
_wasLag.RemoveAt(frame); _wasLag.Remove(frame);
} }
public void InsertHistoryAt(int frame, bool isLag) public void InsertHistoryAt(int frame, bool isLag)
{ {
// LagLog was invalidated when the frame was inserted _lagLog[frame] = isLag;
if (frame <= _lagLog.Count) _wasLag[frame] = isLag;
{
_lagLog.Insert(frame, isLag);
}
_wasLag.Insert(frame, isLag);
} }
public void Save(BinaryWriter bw) public void Save(TextWriter tw)
{ {
bw.Write((byte)1); // New saving format. tw.WriteLine(JsonConvert.SerializeObject(_lagLog));
bw.Write(_lagLog.Count); tw.WriteLine(JsonConvert.SerializeObject(_wasLag));
bw.Write(_wasLag.Count);
for (int i = 0; i < _lagLog.Count; i++)
{
bw.Write(_lagLog[i]);
bw.Write(_wasLag[i]);
}
for (int i = _lagLog.Count; i < _wasLag.Count; i++)
{
bw.Write(_wasLag[i]);
}
} }
public void Load(BinaryReader br) public void Load(TextReader tr)
{ {
_lagLog.Clear(); // TODO: support legacy lag logs that were List<bool>
_wasLag.Clear(); _lagLog = JsonConvert.DeserializeObject<Dictionary<int, bool>>(tr.ReadLine());
int formatVersion = br.ReadByte(); _wasLag = JsonConvert.DeserializeObject<Dictionary<int, bool>>(tr.ReadLine());
if (formatVersion == 0)
{
int length = (br.ReadByte() << 8) | formatVersion; // The first byte should be a part of length.
length = (br.ReadInt16() << 16) | length;
for (int i = 0; i < length; i++)
{
br.ReadInt32();
_lagLog.Add(br.ReadBoolean());
_wasLag.Add(_lagLog.Last());
}
}
else if (formatVersion == 1)
{
int length = br.ReadInt32();
int lenWas = br.ReadInt32();
for (int i = 0; i < length; i++)
{
_lagLog.Add(br.ReadBoolean());
_wasLag.Add(br.ReadBoolean());
}
for (int i = length; i < lenWas; i++)
{
_wasLag.Add(br.ReadBoolean());
}
}
} }
public bool? History(int frame) public bool? History(int frame)
{ {
if (frame < _wasLag.Count) bool wasLag;
var result = _wasLag.TryGetValue(frame, out wasLag);
if (result)
{ {
if (frame < 0) return wasLag;
{
return null;
}
return _wasLag[frame];
} }
return null; return null;
} }
public TasLagLog Clone()
{
return new TasLagLog
{
_lagLog = _lagLog.ToList(),
_wasLag = _wasLag.ToList()
};
}
public void FromLagLog(TasLagLog log) public void FromLagLog(TasLagLog log)
{ {
_lagLog = log._lagLog.ToList(); _lagLog = log._lagLog.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
_wasLag = log._wasLag.ToList(); _wasLag = log._wasLag.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
} }
public void StartFromFrame(int index) public void StartFromFrame(int index)
{ {
_lagLog.RemoveRange(0, index); for (int i = 0; i < index; i++)
_wasLag.RemoveRange(0, index); {
_lagLog.Remove(i);
_wasLag.Remove(i);
}
} }
} }
} }

View File

@ -29,7 +29,7 @@ namespace BizHawk.Client.Common
// TasProj extras // TasProj extras
bs.PutLump(BinaryStateLump.StateHistorySettings, tw => tw.WriteLine(_stateManager.Settings.ToString())); bs.PutLump(BinaryStateLump.StateHistorySettings, tw => tw.WriteLine(_stateManager.Settings.ToString()));
bs.PutLump(BinaryStateLump.LagLog, (BinaryWriter bw) => _lagLog.Save(bw)); bs.PutLump(BinaryStateLump.LagLog, tw => _lagLog.Save(tw));
bs.PutLump(BinaryStateLump.Markers, tw => tw.WriteLine(Markers.ToString())); bs.PutLump(BinaryStateLump.Markers, tw => tw.WriteLine(Markers.ToString()));
if (StartsFromSavestate) if (StartsFromSavestate)
@ -179,9 +179,9 @@ namespace BizHawk.Client.Common
} }
// TasMovie enhanced information // TasMovie enhanced information
bl.GetLump(BinaryStateLump.LagLog, false, delegate(BinaryReader br, long length) bl.GetLump(BinaryStateLump.LagLog, false, delegate(TextReader tr)
{ {
_lagLog.Load(br); _lagLog.Load(tr);
}); });
bl.GetLump(BinaryStateLump.StateHistorySettings, false, delegate(TextReader tr) bl.GetLump(BinaryStateLump.StateHistorySettings, false, delegate(TextReader tr)