Tastudio - support "out of order savestating" using saveslot states. Experiemental, could have bugs particularly off by one issues
This commit is contained in:
parent
eb292eddcc
commit
5349affbc4
|
@ -9,7 +9,7 @@ namespace BizHawk.Client.Common
|
||||||
public partial class Bk2Movie
|
public partial class Bk2Movie
|
||||||
{
|
{
|
||||||
protected List<string> _log = new List<string>();
|
protected List<string> _log = new List<string>();
|
||||||
private string _logKey = string.Empty;
|
protected string LogKey = string.Empty;
|
||||||
|
|
||||||
public string GetInputLog()
|
public string GetInputLog()
|
||||||
{
|
{
|
||||||
|
@ -22,7 +22,7 @@ namespace BizHawk.Client.Common
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ExtractInputLog(TextReader reader, out string errorMessage)
|
public virtual bool ExtractInputLog(TextReader reader, out string errorMessage)
|
||||||
{
|
{
|
||||||
errorMessage = string.Empty;
|
errorMessage = string.Empty;
|
||||||
int? stateFrame = null;
|
int? stateFrame = null;
|
||||||
|
@ -30,10 +30,10 @@ namespace BizHawk.Client.Common
|
||||||
// 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)
|
||||||
{
|
{
|
||||||
if (Global.Config.EnableBackupMovies && _makeBackup && _log.Any())
|
if (Global.Config.EnableBackupMovies && MakeBackup && _log.Any())
|
||||||
{
|
{
|
||||||
SaveBackup();
|
SaveBackup();
|
||||||
_makeBackup = false;
|
MakeBackup = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_log.Clear();
|
_log.Clear();
|
||||||
|
@ -72,7 +72,7 @@ namespace BizHawk.Client.Common
|
||||||
}
|
}
|
||||||
else if (line.StartsWith("LogKey:"))
|
else if (line.StartsWith("LogKey:"))
|
||||||
{
|
{
|
||||||
_logKey = line.Replace("LogKey:", "");
|
LogKey = line.Replace("LogKey:", "");
|
||||||
}
|
}
|
||||||
else if (line[0] == '|')
|
else if (line[0] == '|')
|
||||||
{
|
{
|
||||||
|
@ -119,7 +119,7 @@ namespace BizHawk.Client.Common
|
||||||
}
|
}
|
||||||
else if (line.StartsWith("LogKey:"))
|
else if (line.StartsWith("LogKey:"))
|
||||||
{
|
{
|
||||||
_logKey = line.Replace("LogKey:", "");
|
LogKey = line.Replace("LogKey:", "");
|
||||||
}
|
}
|
||||||
else if (line.StartsWith("|"))
|
else if (line.StartsWith("|"))
|
||||||
{
|
{
|
||||||
|
@ -265,7 +265,7 @@ namespace BizHawk.Client.Common
|
||||||
|
|
||||||
protected StringBuilder RawInputLog()
|
protected StringBuilder RawInputLog()
|
||||||
{
|
{
|
||||||
var lg = new Bk2LogEntryGenerator(_logKey);
|
var lg = new Bk2LogEntryGenerator(LogKey);
|
||||||
lg.SetSource(Global.MovieOutputHardpoint);
|
lg.SetSource(Global.MovieOutputHardpoint);
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
|
|
@ -30,10 +30,10 @@ namespace BizHawk.Client.Common
|
||||||
public virtual void StartNewRecording()
|
public virtual void StartNewRecording()
|
||||||
{
|
{
|
||||||
_mode = Moviemode.Record;
|
_mode = Moviemode.Record;
|
||||||
if (Global.Config.EnableBackupMovies && _makeBackup && _log.Any())
|
if (Global.Config.EnableBackupMovies && MakeBackup && _log.Any())
|
||||||
{
|
{
|
||||||
SaveBackup();
|
SaveBackup();
|
||||||
_makeBackup = false;
|
MakeBackup = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_log.Clear();
|
_log.Clear();
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace BizHawk.Client.Common
|
||||||
{
|
{
|
||||||
public partial class Bk2Movie : IMovie
|
public partial class Bk2Movie : IMovie
|
||||||
{
|
{
|
||||||
private bool _makeBackup = true;
|
protected bool MakeBackup = true;
|
||||||
|
|
||||||
public Bk2Movie(string filename)
|
public Bk2Movie(string filename)
|
||||||
: this()
|
: this()
|
||||||
|
@ -24,7 +24,7 @@ namespace BizHawk.Client.Common
|
||||||
Filename = string.Empty;
|
Filename = string.Empty;
|
||||||
IsCountingRerecords = true;
|
IsCountingRerecords = true;
|
||||||
_mode = Moviemode.Inactive;
|
_mode = Moviemode.Inactive;
|
||||||
_makeBackup = true;
|
MakeBackup = true;
|
||||||
|
|
||||||
Header[HeaderKeys.MOVIEVERSION] = "BizHawk v2.0.0";
|
Header[HeaderKeys.MOVIEVERSION] = "BizHawk v2.0.0";
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ namespace BizHawk.Client.Common
|
||||||
|
|
||||||
public ILogEntryGenerator LogGeneratorInstance()
|
public ILogEntryGenerator LogGeneratorInstance()
|
||||||
{
|
{
|
||||||
return new Bk2LogEntryGenerator(_logKey);
|
return new Bk2LogEntryGenerator(LogKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public double FrameCount
|
public double FrameCount
|
||||||
|
@ -168,7 +168,7 @@ namespace BizHawk.Client.Common
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private void SetFrameAt(int frameNum, string frame)
|
protected void SetFrameAt(int frameNum, string frame)
|
||||||
{
|
{
|
||||||
if (_log.Count > frameNum)
|
if (_log.Count > frameNum)
|
||||||
{
|
{
|
||||||
|
|
|
@ -141,7 +141,7 @@ namespace BizHawk.Client.Common
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
bl.GetLump(BinaryStateLump.Input, true, delegate(TextReader tr)
|
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;
|
var errorMessage = string.Empty;
|
||||||
IsCountingRerecords = false;
|
IsCountingRerecords = false;
|
||||||
|
|
|
@ -7,6 +7,7 @@ using System.Text;
|
||||||
using BizHawk.Common;
|
using BizHawk.Common;
|
||||||
using BizHawk.Emulation.Common;
|
using BizHawk.Emulation.Common;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
namespace BizHawk.Client.Common
|
namespace BizHawk.Client.Common
|
||||||
{
|
{
|
||||||
|
@ -335,5 +336,165 @@ namespace BizHawk.Client.Common
|
||||||
{
|
{
|
||||||
return _log;
|
return _log;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int? TimelineBranchFrame = null;
|
||||||
|
|
||||||
|
// TODO: this is 99% copy pasting of bad code
|
||||||
|
public override bool ExtractInputLog(TextReader reader, out string errorMessage)
|
||||||
|
{
|
||||||
|
errorMessage = string.Empty;
|
||||||
|
int? stateFrame = null;
|
||||||
|
|
||||||
|
var newLog = new List<string>();
|
||||||
|
// We are in record mode so replace the movie log with the one from the savestate
|
||||||
|
if (!Global.MovieSession.MultiTrack.IsActive)
|
||||||
|
{
|
||||||
|
TimelineBranchFrame = null;
|
||||||
|
|
||||||
|
if (Global.Config.EnableBackupMovies && MakeBackup && _log.Any())
|
||||||
|
{
|
||||||
|
SaveBackup();
|
||||||
|
MakeBackup = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int counter = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var line = reader.ReadLine();
|
||||||
|
if (string.IsNullOrEmpty(line))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (line.Contains("Frame 0x")) // NES stores frame count in hex, yay
|
||||||
|
{
|
||||||
|
var strs = line.Split('x');
|
||||||
|
try
|
||||||
|
{
|
||||||
|
stateFrame = int.Parse(strs[1], NumberStyles.HexNumber);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
errorMessage = "Savestate Frame number failed to parse";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (line.Contains("Frame "))
|
||||||
|
{
|
||||||
|
var strs = line.Split(' ');
|
||||||
|
try
|
||||||
|
{
|
||||||
|
stateFrame = int.Parse(strs[1]);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
errorMessage = "Savestate Frame number failed to parse";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (line.StartsWith("LogKey:"))
|
||||||
|
{
|
||||||
|
LogKey = line.Replace("LogKey:", "");
|
||||||
|
}
|
||||||
|
else if (line[0] == '|')
|
||||||
|
{
|
||||||
|
newLog.Add(line);
|
||||||
|
if (!TimelineBranchFrame.HasValue && line != _log[counter])
|
||||||
|
{
|
||||||
|
TimelineBranchFrame = counter;
|
||||||
|
}
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_log.Clear();
|
||||||
|
_log.AddRange(newLog);
|
||||||
|
}
|
||||||
|
else //Multitrack mode
|
||||||
|
{
|
||||||
|
// TODO: consider TimelineBranchFrame here, my thinking is that there's never a scenario to invalidate state/lag data during multitrack
|
||||||
|
var i = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var line = reader.ReadLine();
|
||||||
|
if (line == null)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.Contains("Frame 0x")) // NES stores frame count in hex, yay
|
||||||
|
{
|
||||||
|
var strs = line.Split('x');
|
||||||
|
try
|
||||||
|
{
|
||||||
|
stateFrame = int.Parse(strs[1], NumberStyles.HexNumber);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
errorMessage = "Savestate Frame number failed to parse";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (line.Contains("Frame "))
|
||||||
|
{
|
||||||
|
var strs = line.Split(' ');
|
||||||
|
try
|
||||||
|
{
|
||||||
|
stateFrame = int.Parse(strs[1]);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
errorMessage = "Savestate Frame number failed to parse";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (line.StartsWith("LogKey:"))
|
||||||
|
{
|
||||||
|
LogKey = line.Replace("LogKey:", "");
|
||||||
|
}
|
||||||
|
else if (line.StartsWith("|"))
|
||||||
|
{
|
||||||
|
SetFrameAt(i, line);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stateFrame.HasValue)
|
||||||
|
{
|
||||||
|
errorMessage = "Savestate Frame number failed to parse";
|
||||||
|
}
|
||||||
|
|
||||||
|
var stateFramei = stateFrame ?? 0;
|
||||||
|
|
||||||
|
if (stateFramei > 0 && stateFramei < _log.Count)
|
||||||
|
{
|
||||||
|
if (!Global.Config.VBAStyleMovieLoadState)
|
||||||
|
{
|
||||||
|
Truncate(stateFramei);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (stateFramei > _log.Count) // Post movie savestate
|
||||||
|
{
|
||||||
|
if (!Global.Config.VBAStyleMovieLoadState)
|
||||||
|
{
|
||||||
|
Truncate(_log.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
_mode = Moviemode.Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsCountingRerecords)
|
||||||
|
{
|
||||||
|
Rerecords++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TimelineBranchFrame.HasValue)
|
||||||
|
{
|
||||||
|
LagLog.RemoveFrom(TimelineBranchFrame.Value);
|
||||||
|
TasStateManager.Invalidate(TimelineBranchFrame.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue