Refactor TasMovie and add interface (#1940)

* create ITasMovie interface, still lots of todos

* interface for TasMovie.ChangeLog

* rename method

* interface more TasMovie things

* file rename

* interface more ITasMovie things

* make Bk2Movie and TasMovie internal, rely on interfaces for behavior and MovieService for instantiation

* MovieService cleanup

* cleanup TasBranch handling and simplify ITasMovie api

* more branch logic cleanup and ITasMovie simplificaiton

* more cleanup of branch handling

* more ITasMovie simplification

* nitpick cleanup

* Use IMovie.GetInputLogEntry instead of GetLogEntries

* more ITasMovie cleanup

* move come ITasMovie properties to TasBranchCollection

* TasMovie cleanup

* simplify ITasMovie more

* cleanup
This commit is contained in:
adelikat 2020-04-19 13:38:45 -05:00 committed by GitHub
parent a018851703
commit 70633419ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 475 additions and 399 deletions

View File

@ -51,7 +51,7 @@ namespace BizHawk.Client.Common
public static readonly FilesystemFilter Archives = new FilesystemFilter("Archives", ArchiveExtensions);
public static readonly FilesystemFilter BizHawkMovies = new FilesystemFilter("Movie Files", new[] { MovieService.DefaultExtension });
public static readonly FilesystemFilter BizHawkMovies = new FilesystemFilter("Movie Files", new[] { MovieService.StandardMovieExtension });
public static readonly FilesystemFilter EmuHawkSaveStates = new FilesystemFilter("Save States", new[] { "State" });
@ -61,7 +61,7 @@ namespace BizHawk.Client.Common
public static readonly FilesystemFilter PNGs = new FilesystemFilter("PNG Files", new[] { "png" });
public static readonly FilesystemFilter TAStudioProjects = new FilesystemFilter("TAS Project Files", new[] { TasMovie.Extension });
public static readonly FilesystemFilter TAStudioProjects = new FilesystemFilter("TAS Project Files", new[] { MovieService.TasMovieExtension });
public static readonly FilesystemFilter TextFiles = new FilesystemFilter("Text Files", new[] { "txt" });

View File

@ -90,7 +90,7 @@ namespace BizHawk.Client.Common
bs.PutLump(BinaryStateLump.LagLog,
delegate(TextWriter tw)
{
((TasMovie)Global.MovieSession.Movie).TasLagLog.Save(tw);
((TasMovie)Global.MovieSession.Movie).LagLog.Save(tw);
});
}
}
@ -187,7 +187,7 @@ namespace BizHawk.Client.Common
{
bl.GetLump(BinaryStateLump.LagLog, false, delegate(TextReader tr)
{
((TasMovie)Global.MovieSession.Movie).TasLagLog.Load(tr);
((TasMovie)Global.MovieSession.Movie).LagLog.Load(tr);
});
}
}

View File

@ -18,24 +18,30 @@ namespace BizHawk.Client.Common
}
/// <summary>
/// Gets the file extension for the default movie implementation used in the client
/// Creates a standard <see cref="IMovie"/> instance,
/// no path is specified so this is in a minimal state that would not be able to be saved
/// </summary>
public const string DefaultExtension = "bk2";
public static IMovie Create() => new Bk2Movie();
/// <summary>
/// Creates a <see cref="ITasSession"/> instance
/// </summary>
public static ITasMovie CreateTas(bool startsFromSavestate = false)
{
return new TasMovie(startsFromSavestate: startsFromSavestate);
}
public static string StandardMovieExtension => Bk2Movie.Extension;
public static string TasMovieExtension => TasMovie.Extension;
/// <summary>
/// Gets a list of extensions for all <seealso cref="IMovie"/> implementations
/// </summary>
public static IEnumerable<string> MovieExtensions => new[] { DefaultExtension, TasMovie.Extension };
public static IEnumerable<string> MovieExtensions => new[] { Bk2Movie.Extension, TasMovie.Extension };
public static bool IsValidMovieExtension(string ext)
{
return MovieExtensions.Contains(ext.ToLower().Replace(".", ""));
}
/// <summary>
/// Creates a default instance of the default implementation,
/// no path is specified so this is in a minimal state that would not be able to be saved
/// </summary>
public static IMovie DefaultInstance => new Bk2Movie();
}
}

View File

@ -35,7 +35,7 @@ namespace BizHawk.Client.Common
_modeChangedCallback = modeChangedCallback
?? throw new ArgumentNullException($"{nameof(modeChangedCallback)} CannotUnloadAppDomainException be null.");
Movie = MovieService.DefaultInstance;
Movie = MovieService.Create();
}
public IMovie Movie { get; private set; }
@ -146,7 +146,7 @@ namespace BizHawk.Client.Common
public void HandleFrameAfter()
{
if (Movie is TasMovie tasMovie)
if (Movie is ITasMovie tasMovie)
{
tasMovie.GreenzoneCurrentFrame();
if (tasMovie.IsPlaying() && Global.Emulator.Frame >= tasMovie.InputLogLength)
@ -352,7 +352,7 @@ namespace BizHawk.Client.Common
MultiTrack.Restart(Global.Emulator.ControllerDefinition.PlayerCount);
_modeChangedCallback();
Movie = MovieService.DefaultInstance;
Movie = MovieService.Create();
}
public void ConvertToTasProj()
@ -471,7 +471,7 @@ namespace BizHawk.Client.Common
private void HandleFrameLoopForRecordMode()
{
// we don't want TasMovie to latch user input outside its internal recording mode, so limit it to autohold
if (Movie is TasMovie && Movie.IsPlaying())
if (Movie is ITasMovie && Movie.IsPlaying())
{
MovieController.SetFromSticky(Global.InputManager.AutofireStickyXorAdapter);
}

View File

@ -3,7 +3,7 @@ using System.Text;
namespace BizHawk.Client.Common
{
public partial class Bk2Movie
internal partial class Bk2Movie
{
protected readonly Bk2Header Header = new Bk2Header();
private string _syncSettingsJson = "";

View File

@ -6,7 +6,7 @@ using BizHawk.Common.IOExtensions;
namespace BizHawk.Client.Common
{
public partial class Bk2Movie
internal partial class Bk2Movie
{
public void Save()
{

View File

@ -6,7 +6,7 @@ using BizHawk.Common;
namespace BizHawk.Client.Common
{
public partial class Bk2Movie
internal partial class Bk2Movie
{
protected IStringLog Log { get; set; } = StringLogUtil.MakeStringLog();
protected string LogKey { get; set; } = "";

View File

@ -2,7 +2,7 @@
namespace BizHawk.Client.Common
{
public partial class Bk2Movie
internal partial class Bk2Movie
{
public MovieMode Mode { get; protected set; } = MovieMode.Inactive;

View File

@ -4,7 +4,7 @@ using BizHawk.Emulation.Cores.Nintendo.Gameboy;
namespace BizHawk.Client.Common
{
public partial class Bk2Movie : IMovie
internal partial class Bk2Movie : IMovie
{
private Bk2Controller _adapter;

View File

@ -15,7 +15,7 @@ namespace BizHawk.Client.Common.MovieConversionExtensions
{
public static class MovieConversionExtensions
{
public static TasMovie ToTasMovie(this IMovie old, bool copy = false)
public static ITasMovie ToTasMovie(this IMovie old, bool copy = false)
{
string newFilename = $"{old.Filename}.{TasMovie.Extension}";
@ -77,7 +77,7 @@ namespace BizHawk.Client.Common.MovieConversionExtensions
return tas;
}
public static Bk2Movie ToBk2(this IMovie old, bool copy = false, bool backup = false)
public static IMovie ToBk2(this IMovie old, bool copy = false, bool backup = false)
{
var bk2 = new Bk2Movie(old.Filename.Replace(old.PreferredExtension, Bk2Movie.Extension));
@ -124,7 +124,7 @@ namespace BizHawk.Client.Common.MovieConversionExtensions
return bk2;
}
public static TasMovie ConvertToSavestateAnchoredMovie(this TasMovie old, int frame, byte[] savestate)
public static ITasMovie ConvertToSavestateAnchoredMovie(this ITasMovie old, int frame, byte[] savestate)
{
string newFilename = old.Filename;
@ -157,7 +157,7 @@ namespace BizHawk.Client.Common.MovieConversionExtensions
}
var tas = new TasMovie(newFilename, true) { BinarySavestate = savestate };
tas.ClearLagLog();
tas.LagLog.Clear();
var entries = old.GetLogEntries();
@ -170,8 +170,8 @@ namespace BizHawk.Client.Common.MovieConversionExtensions
old.TasStateManager.Clear();
// Lag Log
tas.TasLagLog.FromLagLog(old.TasLagLog);
tas.TasLagLog.StartFromFrame(frame);
tas.LagLog.FromLagLog(old.LagLog);
tas.LagLog.StartFromFrame(frame);
tas.HeaderEntries.Clear();
foreach (var kvp in old.HeaderEntries)
@ -208,7 +208,7 @@ namespace BizHawk.Client.Common.MovieConversionExtensions
return tas;
}
public static TasMovie ConvertToSaveRamAnchoredMovie(this TasMovie old, byte[] saveRam)
public static ITasMovie ConvertToSaveRamAnchoredMovie(this ITasMovie old, byte[] saveRam)
{
string newFilename = old.Filename;
@ -242,7 +242,7 @@ namespace BizHawk.Client.Common.MovieConversionExtensions
var tas = new TasMovie(newFilename, true) { SaveRam = saveRam };
tas.TasStateManager.Clear();
tas.ClearLagLog();
tas.LagLog.Clear();
var entries = old.GetLogEntries();

View File

@ -48,6 +48,8 @@ namespace BizHawk.Client.Common
#region Properties
string Name { get; }
/// <summary>
/// Gets the total number of frames that count towards the completion time of the movie
/// Possibly (but unlikely different from InputLogLength (could be infinity, or maybe an implementation automatically discounts empty frames at the end of a movie, etc)
@ -292,5 +294,11 @@ namespace BizHawk.Client.Common
emulator.AsSaveRam().StoreSaveRam(movie.SaveRam);
}
}
public static bool BoolIsPressed(this IMovie movie, int frame, string buttonName)
=> movie.GetInputState(frame).IsPressed(buttonName);
public static float GetFloatState(this IMovie movie, int frame, string buttonName)
=> movie.GetInputState(frame).AxisValue(buttonName);
}
}

View File

@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.Common
{
public interface ITasMovie : IMovie, INotifyPropertyChanged
{
bool BindMarkersToInput { get; set; }
bool LastPositionStable { get; set; }
IMovieChangeLog ChangeLog { get; }
IStateManager TasStateManager { get; }
Func<string> ClientSettingsForSave { set; }
Action<string> GetClientSettingsOnLoad { set; }
ITasMovieRecord this[int index] { get; }
ITasSession Session { get; }
TasMovieMarkerList Markers { get; }
ITasBranchCollection Branches { get; }
TasLagLog LagLog { get; }
IStringLog VerificationLog { get; }
int LastEditedFrame { get; }
string DisplayValue(int frame, string buttonName);
void FlagChanges();
void ClearChanges();
IStringLog GetLogEntries();
void GreenzoneCurrentFrame();
void ToggleBoolState(int frame, string buttonName);
void SetFloatState(int frame, string buttonName, float val);
void SetFloatStates(int frame, int count, string buttonName, float val);
void SetBoolState(int frame, string buttonName, bool val);
void SetBoolStates(int frame, int count, string buttonName, bool val);
void InsertInput(int frame, string inputState);
void InsertInput(int frame, IEnumerable<string> inputLog);
void InsertInput(int frame, IEnumerable<IController> inputStates);
void InsertEmptyFrame(int frame, int count = 1, bool fromHistory = false);
int CopyOverInput(int frame, IEnumerable<IController> inputStates);
void RemoveFrame(int frame);
void RemoveFrames(ICollection<int> frames);
void RemoveFrames(int removeStart, int removeUpTo, bool fromHistory = false);
void SetFrame(int frame, string source);
void LoadBranch(TasBranch branch);
}
}

View File

@ -45,7 +45,7 @@ namespace BizHawk.Client.Common
// TODO: interface me
internal class StateManagerDecay
{
private readonly TasMovie _movie;
private readonly ITasMovie _movie;
private readonly IStateManager _tsm;
private List<int> _zeros; // amount of least significant zeros in bitwise view (also max pattern step)
@ -56,7 +56,7 @@ namespace BizHawk.Client.Common
private int _step; // initial memory state gap
private bool _align; // extra care about fine alignment. TODO: do we want it?
public StateManagerDecay(TasMovie movie, IStateManager tsm)
public StateManagerDecay(ITasMovie movie, IStateManager tsm)
{
_movie = movie;
_tsm = tsm;

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using BizHawk.Bizware.BizwareGL;
@ -16,25 +17,95 @@ namespace BizHawk.Client.Common
public TasMovieChangeLog ChangeLog { get; set; }
public DateTime TimeStamp { get; set; }
public TasMovieMarkerList Markers { get; set; }
public Guid UniqueIdentifier { get; set; }
public Guid Uuid { get; set; }
public string UserText { get; set; }
public TasBranch Clone()
{
return (TasBranch)MemberwiseClone();
}
public TasBranch Clone() => (TasBranch)MemberwiseClone();
}
public class TasBranchCollection : List<TasBranch>
public interface ITasBranchCollection : IList<TasBranch>
{
int Current { get; set; }
string NewBranchText { get; set; }
void Swap(int b1, int b2);
void Replace(TasBranch old, TasBranch newBranch);
void Save(BinaryStateSaver bs);
void Load(BinaryStateLoader bl, ITasMovie movie);
}
public class TasBranchCollection : List<TasBranch>, ITasBranchCollection
{
private readonly ITasMovie _movie;
public TasBranchCollection(ITasMovie movie)
{
_movie = movie;
}
public int Current { get; set; } = -1;
public string NewBranchText { get; set; } = "";
public void Swap(int b1, int b2)
{
var branch = this[b1];
if (b2 >= Count)
{
b2 = Count - 1;
}
Remove(branch);
Insert(b2, branch);
_movie.FlagChanges();
}
public void Replace(TasBranch old, TasBranch newBranch)
{
int index = IndexOf(old);
newBranch.Uuid = old.Uuid;
if (newBranch.UserText == "")
{
newBranch.UserText = old.UserText;
}
this[index] = newBranch;
_movie.FlagChanges();
}
public new TasBranch this[int index]
{
get => index >= Count || index < 0
? null
: base [index];
set => base[index] = value;
}
public new void Add(TasBranch item)
{
if (item.UniqueIdentifier == Guid.Empty)
if (item == null)
{
item.UniqueIdentifier = Guid.NewGuid();
throw new ArgumentNullException($"{nameof(item)} cannot be null");
}
if (item.Uuid == Guid.Empty)
{
item.Uuid = Guid.NewGuid();
}
base.Add(item);
_movie.FlagChanges();
}
public new bool Remove(TasBranch item)
{
var result = base.Remove(item);
if (result)
{
_movie.FlagChanges();
}
return result;
}
public void Save(BinaryStateSaver bs)
@ -55,7 +126,7 @@ namespace BizHawk.Client.Common
{
b.Frame,
b.TimeStamp,
b.UniqueIdentifier
UniqueIdentifier = b.Uuid
}));
});
@ -105,7 +176,7 @@ namespace BizHawk.Client.Common
}
}
public void Load(BinaryStateLoader bl, TasMovie movie)
public void Load(BinaryStateLoader bl, ITasMovie movie)
{
var nheader = new IndexedStateLump(BinaryStateLump.BranchHeader);
var ncore = new IndexedStateLump(BinaryStateLump.BranchCoreData);
@ -140,11 +211,11 @@ namespace BizHawk.Client.Common
var identifier = header.UniqueIdentifier;
if (identifier != null)
{
b.UniqueIdentifier = (Guid)identifier;
b.Uuid = (Guid)identifier;
}
else
{
b.UniqueIdentifier = Guid.NewGuid();
b.Uuid = Guid.NewGuid();
}
}))
{
@ -218,4 +289,28 @@ namespace BizHawk.Client.Common
}
}
}
public static class TasBranchExtensions
{
public static int IndexOfFrame(this IList<TasBranch> list, int frame)
{
var branch = list
.Where(b => b.Frame == frame)
.OrderByDescending(b => b.TimeStamp)
.FirstOrDefault();
return branch == null
? -1
: list.IndexOf(branch);
}
// TODO: stop relying on the index value of a branch
public static int IndexOfHash(this IList<TasBranch> list, Guid uuid)
{
var branch = list.SingleOrDefault(b => b.Uuid == uuid);
return branch == null
? -1
: list.IndexOf(branch);
}
}
}

View File

@ -5,9 +5,9 @@ using BizHawk.Emulation.Common;
namespace BizHawk.Client.Common
{
public partial class TasMovie
internal partial class TasMovie
{
public TasMovieChangeLog ChangeLog { get; set; }
public IMovieChangeLog ChangeLog { get; set; }
public override void RecordFrame(int frame, IController source)
{
@ -18,8 +18,8 @@ namespace BizHawk.Client.Common
base.RecordFrame(frame, source);
TasLagLog.RemoveFrom(frame);
TasLagLog[frame] = Global.Emulator.AsInputPollable().IsLagFrame;
LagLog.RemoveFrom(frame);
LagLog[frame] = Global.Emulator.AsInputPollable().IsLagFrame;
if (this.IsRecording())
{
@ -44,7 +44,7 @@ namespace BizHawk.Client.Common
base.Truncate(frame);
TasLagLog.RemoveFrom(frame);
LagLog.RemoveFrom(frame);
TasStateManager.Invalidate(frame);
Markers.TruncateAt(frame);
@ -100,7 +100,7 @@ namespace BizHawk.Client.Common
{
for (int i = firstIndex; i < Markers.Count; i++)
{
TasMovieMarker m = Markers[i];
var m = Markers[i];
if (m.Frame == frame)
{
Markers.Remove(m);
@ -538,24 +538,5 @@ namespace BizHawk.Client.Common
ChangeLog.SetGeneralRedo();
}
#region LagLog
public void RemoveLagHistory(int frame)
{
TasLagLog.RemoveHistoryAt(frame);
}
public void InsertLagHistory(int frame, bool isLag)
{
TasLagLog.InsertHistoryAt(frame, isLag);
}
public void SetLag(int frame, bool? value)
{
TasLagLog[frame] = value;
}
#endregion
}
}

View File

@ -4,15 +4,40 @@ using System.Linq;
namespace BizHawk.Client.Common
{
public class TasMovieChangeLog
public interface IMovieChangeLog
{
public TasMovieChangeLog(TasMovie movie)
List<string> Names { get; }
int UndoIndex { get; }
string NextUndoStepName { get; }
bool IsRecording { get; set; }
void AddInputBind(int frame, bool isDelete, string name = "", bool force = false);
void Clear(int upTo = -1);
bool BeginNewBatch(string name = "", bool keepOldBatch = false);
void EndBatch();
int Undo();
int Redo();
bool CanUndo { get; }
bool CanRedo { get; }
int PreviousUndoFrame { get; }
int PreviousRedoFrame { get; }
int MaxSteps { get; set; }
void AddGeneralUndo(int first, int last, string name = "", bool force = false);
void SetGeneralRedo(bool force = false);
void AddBoolToggle(int frame, string button, bool oldState, string name = "", bool force = false);
void AddFloatChange(int frame, string button, float oldState, float newState, string name = "", bool force = false);
void AddMarkerChange(TasMovieMarker newMarker, int oldPosition = -1, string oldMessage = "", string name = "", bool force = false);
}
public class TasMovieChangeLog : IMovieChangeLog
{
public TasMovieChangeLog(ITasMovie movie)
{
_movie = movie;
}
private readonly List<List<IMovieAction>> _history = new List<List<IMovieAction>>();
private readonly TasMovie _movie;
private readonly ITasMovie _movie;
private int _maxSteps = 100;
private int _totalSteps;
@ -31,11 +56,11 @@ namespace BizHawk.Client.Common
{
if (_history.Count <= value)
{
ClearLog();
Clear();
}
else
{
ClearLog(_history.Count - value);
Clear(_history.Count - value);
}
}
}
@ -48,7 +73,7 @@ namespace BizHawk.Client.Common
/// </summary>
public bool IsRecording { get; set; } = true;
public void ClearLog(int upTo = -1)
public void Clear(int upTo = -1)
{
if (upTo == -1)
{
@ -362,8 +387,8 @@ namespace BizHawk.Client.Common
public interface IMovieAction
{
void Undo(TasMovie movie);
void Redo(TasMovie movie);
void Undo(ITasMovie movie);
void Redo(ITasMovie movie);
int FirstFrame { get; }
int LastFrame { get; }
@ -383,7 +408,7 @@ namespace BizHawk.Client.Common
private List<string> _newLog;
private readonly bool _bindMarkers;
public MovieAction(int firstFrame, int lastFrame, TasMovie movie)
public MovieAction(int firstFrame, int lastFrame, ITasMovie movie)
{
FirstFrame = firstFrame;
LastFrame = lastFrame;
@ -392,23 +417,23 @@ namespace BizHawk.Client.Common
for (int i = 0; i < _undoLength; i++)
{
_oldLog.Add(movie.GetLogEntries()[FirstFrame + i]);
_oldLog.Add(movie.GetInputLogEntry(FirstFrame + i));
}
_bindMarkers = movie.BindMarkersToInput;
}
public void SetRedoLog(TasMovie movie)
public void SetRedoLog(ITasMovie movie)
{
_redoLength = Math.Min(LastFrame + 1, movie.InputLogLength) - FirstFrame;
_newLog = new List<string>();
for (int i = 0; i < _redoLength; i++)
{
_newLog.Add(movie.GetLogEntries()[FirstFrame + i]);
_newLog.Add(movie.GetInputLogEntry(FirstFrame + i));
}
}
public void Undo(TasMovie movie)
public void Undo(ITasMovie movie)
{
bool wasRecording = movie.ChangeLog.IsRecording;
movie.ChangeLog.IsRecording = false;
@ -433,7 +458,7 @@ namespace BizHawk.Client.Common
movie.BindMarkersToInput = _bindMarkers;
}
public void Redo(TasMovie movie)
public void Redo(ITasMovie movie)
{
bool wasRecording = movie.ChangeLog.IsRecording;
movie.ChangeLog.IsRecording = false;
@ -483,7 +508,7 @@ namespace BizHawk.Client.Common
}
}
public void Undo(TasMovie movie)
public void Undo(ITasMovie movie)
{
if (FirstFrame == -1) // Action: Place marker
{
@ -500,7 +525,7 @@ namespace BizHawk.Client.Common
}
}
public void Redo(TasMovie movie)
public void Redo(ITasMovie movie)
{
if (FirstFrame == -1) // Action: Place marker
{
@ -546,7 +571,7 @@ namespace BizHawk.Client.Common
_isFloat = true;
}
public void Undo(TasMovie movie)
public void Undo(ITasMovie movie)
{
bool wasRecording = movie.ChangeLog.IsRecording;
movie.ChangeLog.IsRecording = false;
@ -563,7 +588,7 @@ namespace BizHawk.Client.Common
movie.ChangeLog.IsRecording = wasRecording;
}
public void Redo(TasMovie movie)
public void Redo(ITasMovie movie)
{
bool wasRecording = movie.ChangeLog.IsRecording;
movie.ChangeLog.IsRecording = false;
@ -590,7 +615,7 @@ namespace BizHawk.Client.Common
private readonly string _buttonName;
private readonly bool _isFloat = false;
public MovieActionPaint(int startFrame, int endFrame, string button, bool newS, TasMovie movie)
public MovieActionPaint(int startFrame, int endFrame, string button, bool newS, ITasMovie movie)
{
_newState = newS ? 1 : 0;
FirstFrame = startFrame;
@ -604,7 +629,7 @@ namespace BizHawk.Client.Common
}
}
public MovieActionPaint(int startFrame, int endFrame, string button, float newS, TasMovie movie)
public MovieActionPaint(int startFrame, int endFrame, string button, float newS, ITasMovie movie)
{
_newState = newS;
FirstFrame = startFrame;
@ -619,7 +644,7 @@ namespace BizHawk.Client.Common
}
}
public void Undo(TasMovie movie)
public void Undo(ITasMovie movie)
{
bool wasRecording = movie.ChangeLog.IsRecording;
movie.ChangeLog.IsRecording = false;
@ -642,7 +667,7 @@ namespace BizHawk.Client.Common
movie.ChangeLog.IsRecording = wasRecording;
}
public void Redo(TasMovie movie)
public void Redo(ITasMovie movie)
{
bool wasRecording = movie.ChangeLog.IsRecording;
movie.ChangeLog.IsRecording = false;
@ -670,7 +695,7 @@ namespace BizHawk.Client.Common
private readonly bool _bindMarkers;
public MovieActionBindInput(TasMovie movie, int frame, bool isDelete)
public MovieActionBindInput(ITasMovie movie, int frame, bool isDelete)
{
FirstFrame = LastFrame = frame;
_log = movie.GetInputLogEntry(frame);
@ -678,7 +703,7 @@ namespace BizHawk.Client.Common
_bindMarkers = movie.BindMarkersToInput;
}
public void Undo(TasMovie movie)
public void Undo(ITasMovie movie)
{
bool wasRecording = movie.ChangeLog.IsRecording;
bool wasBinding = movie.BindMarkersToInput;
@ -688,19 +713,19 @@ namespace BizHawk.Client.Common
if (_delete) // Insert
{
movie.InsertInput(FirstFrame, _log);
movie.InsertLagHistory(FirstFrame + 1, true);
movie.LagLog.InsertHistoryAt(FirstFrame + 1, true);
}
else // Delete
{
movie.RemoveFrame(FirstFrame);
movie.RemoveLagHistory(FirstFrame + 1);
movie.LagLog.RemoveHistoryAt(FirstFrame + 1);
}
movie.ChangeLog.IsRecording = wasRecording;
movie.BindMarkersToInput = _bindMarkers;
}
public void Redo(TasMovie movie)
public void Redo(ITasMovie movie)
{
bool wasRecording = movie.ChangeLog.IsRecording;
bool wasBinding = movie.BindMarkersToInput;
@ -710,12 +735,12 @@ namespace BizHawk.Client.Common
if (_delete)
{
movie.RemoveFrame(FirstFrame);
movie.RemoveLagHistory(FirstFrame + 1);
movie.LagLog.RemoveHistoryAt(FirstFrame + 1);
}
else
{
movie.InsertInput(FirstFrame, _log);
movie.InsertLagHistory(FirstFrame + 1, true);
movie.LagLog.InsertHistoryAt(FirstFrame + 1, true);
}
movie.ChangeLog.IsRecording = wasRecording;

View File

@ -5,7 +5,7 @@ using Newtonsoft.Json;
namespace BizHawk.Client.Common
{
public partial class TasMovie
internal partial class TasMovie
{
public Func<string> ClientSettingsForSave { get; set; }
public Action<string> GetClientSettingsOnLoad { get; set; }
@ -29,7 +29,7 @@ namespace BizHawk.Client.Common
var settings = JsonConvert.SerializeObject(TasStateManager.Settings);
bs.PutLump(BinaryStateLump.StateHistorySettings, tw => tw.WriteLine(settings));
bs.PutLump(BinaryStateLump.LagLog, tw => TasLagLog.Save(tw));
bs.PutLump(BinaryStateLump.LagLog, tw => LagLog.Save(tw));
bs.PutLump(BinaryStateLump.Markers, tw => tw.WriteLine(Markers.ToString()));
if (StartsFromSavestate)
@ -179,7 +179,7 @@ namespace BizHawk.Client.Common
// TasMovie enhanced information
bl.GetLump(BinaryStateLump.LagLog, false, delegate(TextReader tr)
{
TasLagLog.Load(tr);
LagLog.Load(tr);
});
bl.GetLump(BinaryStateLump.StateHistorySettings, false, delegate(TextReader tr)
@ -285,10 +285,10 @@ namespace BizHawk.Client.Common
private void ClearTasprojExtras()
{
ClearLagLog();
LagLog.Clear();
TasStateManager.Clear();
Markers.Clear();
ChangeLog.ClearLog();
ChangeLog.Clear();
}
}
}

View File

@ -3,42 +3,14 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Linq;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.Common
{
public sealed partial class TasMovie : Bk2Movie, INotifyPropertyChanged
internal sealed partial class TasMovie : Bk2Movie, ITasMovie
{
public IStringLog VerificationLog { get; } = StringLogUtil.MakeStringLog(); // For movies that do not begin with power-on, this is the input required to get into the initial state
public TasBranchCollection Branches { get; } = new TasBranchCollection();
public TasSession Session { get; private set; } = new TasSession();
public new const string Extension = "tasproj";
public const string DefaultProjectName = "default";
public string NewBranchText { get; set; } = "";
public int LastEditedFrame { get; private set; } = -1;
public bool LastPositionStable { get; set; } = true;
public TasMovieMarkerList Markers { get; private set; }
public bool BindMarkersToInput { get; set; }
public int CurrentBranch { get; set; } = -1;
public TasLagLog TasLagLog { get; } = new TasLagLog();
public int LastStatedFrame => TasStateManager.Last;
public override string PreferredExtension => Extension;
public IStateManager TasStateManager { get; }
public IStringLog CloneInput() => Log.Clone();
public TasMovieRecord this[int index] => new TasMovieRecord
{
HasState = TasStateManager.HasState(index),
LogEntry = GetInputLogEntry(index),
Lagged = TasLagLog[index + 1],
WasLagged = TasLagLog.History(index + 1)
};
/// <exception cref="InvalidOperationException">loaded core does not implement <see cref="IStatable"/></exception>
public TasMovie(string path = null, bool startsFromSavestate = false) : base(path)
@ -48,6 +20,7 @@ namespace BizHawk.Client.Common
throw new InvalidOperationException($"Cannot create a {nameof(TasMovie)} against a core that does not implement {nameof(IStatable)}");
}
Branches = new TasBranchCollection(this);
ChangeLog = new TasMovieChangeLog(this);
TasStateManager = new TasStateManager(this, Global.Config.DefaultTasStateManagerSettings);
Header[HeaderKeys.MovieVersion] = "BizHawk v2.0 Tasproj v1.0";
@ -56,6 +29,28 @@ namespace BizHawk.Client.Common
Markers.Add(0, startsFromSavestate ? "Savestate" : "Power on");
}
public IStringLog VerificationLog { get; } = StringLogUtil.MakeStringLog(); // For movies that do not begin with power-on, this is the input required to get into the initial state
public ITasBranchCollection Branches { get; }
public ITasSession Session { get; private set; } = new TasSession();
public int LastEditedFrame { get; private set; } = -1;
public bool LastPositionStable { get; set; } = true;
public TasMovieMarkerList Markers { get; private set; }
public bool BindMarkersToInput { get; set; }
public TasLagLog LagLog { get; } = new TasLagLog();
public override string PreferredExtension => Extension;
public IStateManager TasStateManager { get; }
public ITasMovieRecord this[int index] => new TasMovieRecord
{
HasState = TasStateManager.HasState(index),
LogEntry = GetInputLogEntry(index),
Lagged = LagLog[index + 1],
WasLagged = LagLog.History(index + 1)
};
public override void StartNewRecording()
{
ClearTasprojExtras();
@ -65,13 +60,10 @@ namespace BizHawk.Client.Common
base.StartNewRecording();
}
/// <summary>
/// Removes lag log and greenzone after this frame
/// </summary>
/// <param name="frame">The last frame that can be valid.</param>
// Removes lag log and greenzone after this frame
private void InvalidateAfter(int frame)
{
var anyInvalidated = TasLagLog.RemoveFrom(frame);
var anyInvalidated = LagLog.RemoveFrom(frame);
TasStateManager.Invalidate(frame + 1);
Changes = anyInvalidated;
LastEditedFrame = frame;
@ -109,21 +101,6 @@ namespace BizHawk.Client.Common
return "!";
}
public bool BoolIsPressed(int frame, string buttonName)
=> GetInputState(frame).IsPressed(buttonName);
public float GetFloatState(int frame, string buttonName)
=> GetInputState(frame).AxisValue(buttonName);
public void ClearGreenzone()
{
if (TasStateManager.Any())
{
TasStateManager.Clear();
Changes = true;
}
}
public void GreenzoneCurrentFrame()
{
// todo: this isn't working quite right when autorestore is off and we're editing while seeking
@ -134,7 +111,7 @@ namespace BizHawk.Client.Common
LastPositionStable = false;
}
TasLagLog[Global.Emulator.Frame] = Global.Emulator.AsInputPollable().IsLagFrame;
LagLog[Global.Emulator.Frame] = Global.Emulator.AsInputPollable().IsLagFrame;
if (!TasStateManager.HasState(Global.Emulator.Frame))
{
@ -142,12 +119,7 @@ namespace BizHawk.Client.Common
}
}
public void ClearLagLog()
{
TasLagLog.Clear();
}
public void CopyLog(IEnumerable<string> log)
internal void CopyLog(IEnumerable<string> log)
{
Log.Clear();
foreach (var entry in log)
@ -156,7 +128,7 @@ namespace BizHawk.Client.Common
}
}
public void CopyVerificationLog(IEnumerable<string> log)
internal void CopyVerificationLog(IEnumerable<string> log)
{
foreach (string entry in log)
{
@ -322,75 +294,13 @@ namespace BizHawk.Client.Common
if (_timelineBranchFrame.HasValue)
{
TasLagLog.RemoveFrom(_timelineBranchFrame.Value);
LagLog.RemoveFrom(_timelineBranchFrame.Value);
TasStateManager.Invalidate(_timelineBranchFrame.Value);
}
return true;
}
#region Branches
public TasBranch GetBranch(int index)
{
if (index >= Branches.Count || index < 0)
{
return null;
}
return Branches[index];
}
public TasBranch GetBranch(Guid id)
{
return Branches.SingleOrDefault(b => b.UniqueIdentifier == id);
}
public Guid BranchGuidByIndex(int index)
{
return index >= Branches.Count
? Guid.Empty
: Branches[index].UniqueIdentifier;
}
public int BranchIndexByHash(Guid uuid)
{
TasBranch branch = Branches.SingleOrDefault(b => b.UniqueIdentifier == uuid);
if (branch == null)
{
return -1;
}
return Branches.IndexOf(branch);
}
public int BranchIndexByFrame(int frame)
{
TasBranch branch = Branches
.Where(b => b.Frame == frame)
.OrderByDescending(b => b.TimeStamp)
.FirstOrDefault();
if (branch == null)
{
return -1;
}
return Branches.IndexOf(branch);
}
public void AddBranch(TasBranch branch)
{
Branches.Add(branch);
Changes = true;
}
public void RemoveBranch(TasBranch branch)
{
Branches.Remove(branch);
Changes = true;
}
public void LoadBranch(TasBranch branch)
{
int? divergentPoint = Log.DivergentPoint(branch.InputLog);
@ -408,35 +318,6 @@ namespace BizHawk.Client.Common
Changes = true;
}
public void UpdateBranch(TasBranch old, TasBranch newBranch)
{
int index = Branches.IndexOf(old);
newBranch.UniqueIdentifier = old.UniqueIdentifier;
if (newBranch.UserText == "")
{
newBranch.UserText = old.UserText;
}
Branches[index] = newBranch;
Changes = true;
}
public void SwapBranches(int b1, int b2)
{
TasBranch branch = Branches[b1];
if (b2 >= Branches.Count)
{
b2 = Branches.Count - 1;
}
Branches.Remove(branch);
Branches.Insert(b2, branch);
Changes = true;
}
#endregion
#region Events and Handlers
public event PropertyChangedEventHandler PropertyChanged;

View File

@ -69,9 +69,9 @@ namespace BizHawk.Client.Common
public class TasMovieMarkerList : List<TasMovieMarker>
{
private readonly TasMovie _movie;
private readonly ITasMovie _movie;
public TasMovieMarkerList(TasMovie movie)
public TasMovieMarkerList(ITasMovie movie)
{
_movie = movie;
}

View File

@ -1,10 +1,18 @@
namespace BizHawk.Client.Common
{
public class TasMovieRecord
public interface ITasMovieRecord
{
public bool? Lagged { get; set; }
public bool? WasLagged { get; set; }
public string LogEntry { get; set; }
public bool HasState { get; set; }
bool? Lagged { get; }
bool? WasLagged { get; }
string LogEntry { get; }
bool HasState { get; }
}
public class TasMovieRecord : ITasMovieRecord
{
public bool? Lagged { get; internal set; }
public bool? WasLagged { get; internal set; }
public string LogEntry { get; internal set; }
public bool HasState { get; internal set; }
}
}

View File

@ -1,9 +1,16 @@
namespace BizHawk.Client.Common
{
public class TasSession
public interface ITasSession
{
public int CurrentFrame { get; set; }
public int CurrentBranch { get; set; } = -1;
int CurrentFrame { get; }
int CurrentBranch { get; }
void UpdateValues(int frame, int currentBranch);
}
public class TasSession : ITasSession
{
public int CurrentFrame { get; private set; }
public int CurrentBranch { get; private set; } = -1;
public void UpdateValues(int frame, int currentBranch)
{

View File

@ -22,7 +22,7 @@ namespace BizHawk.Client.Common
private IEmulator Emulator => Global.Emulator;
private readonly StateManagerDecay _decay;
private readonly TasMovie _movie;
private readonly ITasMovie _movie;
private readonly SortedList<int, byte[]> _states;
private readonly ulong _expectedStateSize;
@ -35,7 +35,7 @@ namespace BizHawk.Client.Common
private int FileStateGap => 1 << Settings.FileStateGap;
/// <exception cref="InvalidOperationException">loaded core expects savestate size of <c>0 B</c></exception>
public TasStateManager(TasMovie movie, TasStateManagerSettings settings)
public TasStateManager(ITasMovie movie, TasStateManagerSettings settings)
{
_movie = movie;
Settings = new TasStateManagerSettings(settings);
@ -160,6 +160,8 @@ namespace BizHawk.Client.Common
SetState(0, power);
_used = (ulong)power.Length;
}
_movie.FlagChanges();
}
}

View File

@ -3015,7 +3015,7 @@ namespace BizHawk.Client.EmuHawk
if (PauseOnFrame.HasValue &&
PauseOnFrame.Value <= Tools.TAStudio.LastPositionFrame)
{
TasMovieRecord record = (MovieSession.Movie as TasMovie)[Emulator.Frame];
var record = (MovieSession.Movie as ITasMovie)[Emulator.Frame];
if (!record.Lagged.HasValue && IsSeeking)
{
// haven't yet greenzoned the frame, hence it's after editing

View File

@ -263,8 +263,10 @@ namespace BizHawk.Client.EmuHawk
}
// add movies
fpTodo.AddRange(Directory.GetFiles(dp, $"*.{MovieService.DefaultExtension}"));
fpTodo.AddRange(Directory.GetFiles(dp, $"*.{TasMovie.Extension}"));
foreach (var extension in MovieService.MovieExtensions)
{
fpTodo.AddRange(Directory.GetFiles(dp, $"*.{extension}"));
}
}
// in parallel, scan each movie

View File

@ -70,7 +70,7 @@ namespace BizHawk.Client.EmuHawk
if (!MovieService.MovieExtensions.Contains(Path.GetExtension(path)))
{
// If no valid movie extension, add movie extension
path += $".{MovieService.DefaultExtension}";
path += $".{MovieService.StandardMovieExtension}";
}
}
}

View File

@ -111,7 +111,7 @@ namespace BizHawk.Client.EmuHawk
{
if (Engaged())
{
Tastudio.CurrentTasMovie.SetLag(frame, value);
Tastudio.CurrentTasMovie.LagLog[frame] = value;
}
}
@ -337,11 +337,15 @@ namespace BizHawk.Client.EmuHawk
{
if (index != null)
{
Tastudio.CurrentTasMovie.GetBranch(index.Value).UserText = text;
var branch = Tastudio.CurrentTasMovie.Branches[index.Value];
if (branch != null)
{
branch.UserText = text;
}
}
else
{
Tastudio.CurrentTasMovie.NewBranchText = text;
Tastudio.CurrentTasMovie.Branches.NewBranchText = text;
}
}
@ -354,7 +358,7 @@ namespace BizHawk.Client.EmuHawk
return Tastudio.CurrentTasMovie.Branches
.Select(b => new
{
Id = b.UniqueIdentifier.ToString(),
Id = b.Uuid.ToString(),
b.Frame,
Text = b.UserText
})
@ -372,7 +376,7 @@ namespace BizHawk.Client.EmuHawk
if (Engaged())
{
var branch = Tastudio.CurrentTasMovie.Branches.FirstOrDefault(b => b.UniqueIdentifier.ToString() == branchId);
var branch = Tastudio.CurrentTasMovie.Branches.FirstOrDefault(b => b.Uuid.ToString() == branchId);
if (branch != null && frame < branch.InputLog.Count)
{
var controller = Global.MovieSession.GenerateMovieController();

View File

@ -45,9 +45,7 @@ namespace BizHawk.Client.EmuHawk
return;
}
ReplaceBox.Enabled = CurrentMovie is TasMovie;
OverlayBox.Enabled = CurrentMovie is TasMovie;
PlaceNum.Enabled = CurrentMovie is TasMovie;
ReplaceBox.Enabled = OverlayBox.Enabled = PlaceNum.Enabled = CurrentMovie is ITasMovie;
var main = new MovieZone(CurrentMovie, Emulator, Tools, MovieSession, 0, CurrentMovie.InputLogLength)
{
@ -223,7 +221,7 @@ namespace BizHawk.Client.EmuHawk
return;
}
if (!(CurrentMovie is TasMovie))
if (!(CurrentMovie is ITasMovie))
{
SelectedZone.Start = Emulator.Frame;
}
@ -254,7 +252,7 @@ namespace BizHawk.Client.EmuHawk
ZonesList.Items.Add($"{loadZone.Name} - length: {loadZone.Length}");
// Options only for TasMovie
if (!(CurrentMovie is TasMovie))
if (!(CurrentMovie is ITasMovie))
{
loadZone.Replace = false;
loadZone.Overlay = false;

View File

@ -128,7 +128,7 @@ namespace BizHawk.Client.EmuHawk
public void PlaceZone(IMovie movie)
{
if (movie is TasMovie tasMovie)
if (movie is ITasMovie tasMovie)
{
tasMovie.ChangeLog.BeginNewBatch($"Place Macro at {Start}");
}
@ -139,8 +139,9 @@ namespace BizHawk.Client.EmuHawk
return;
}
if (!Replace && movie is TasMovie tasMovie2)
{ // Can't be done with a regular movie.
// Can't be done with a regular movie.
if (!Replace && movie is ITasMovie tasMovie2)
{
tasMovie2.InsertEmptyFrame(Start, Length);
}
@ -156,15 +157,16 @@ namespace BizHawk.Client.EmuHawk
}
else
{
// Copy over the frame.
for (int i = 0; i < Length; i++)
{ // Copy over the frame.
{
_controller.SetFromMnemonic(_log[i]);
LatchFromSourceButtons(_targetController, _controller);
movie.PokeFrame(i + Start, _targetController);
}
}
if (movie is TasMovie tasMovie3) // Assume TAStudio is open?
if (movie is ITasMovie tasMovie3) // Assume TAStudio is open?
{
tasMovie3.ChangeLog.EndBatch();
if (_emulator.Frame > Start)

View File

@ -17,7 +17,9 @@ namespace BizHawk.Client.EmuHawk
private readonly ScreenshotForm _screenshot = new ScreenshotForm();
private TasMovie Movie => Tastudio.CurrentTasMovie;
private ITasMovie Movie => Tastudio.CurrentTasMovie;
private ITasBranchCollection Branches => Movie.Branches;
private MainForm MainForm => Tastudio.MainForm;
private TasBranch _backupBranch;
private BranchUndo _branchUndo = BranchUndo.None;
@ -81,7 +83,7 @@ namespace BizHawk.Client.EmuHawk
{
text = "";
if (index >= Movie.Branches.Count)
if (index >= Branches.Count)
{
return;
}
@ -89,19 +91,19 @@ namespace BizHawk.Client.EmuHawk
text = column.Name switch
{
BranchNumberColumnName => index.ToString(),
FrameColumnName => GetBranch(index).Frame.ToString(),
UserTextColumnName => GetBranch(index).UserText,
FrameColumnName => Branches[index].Frame.ToString(),
UserTextColumnName => Branches[index].UserText,
_ => text
};
}
private void QueryItemBkColor(int index, RollColumn column, ref Color color)
{
TasBranch branch = GetBranch(index);
var branch = Branches[index];
if (branch != null)
{
var record = Movie[branch.Frame];
if (index == Movie.CurrentBranch)
if (index == Branches.Current)
{
color = TAStudio.CurrentFrame_InputLog;
}
@ -127,28 +129,23 @@ namespace BizHawk.Client.EmuHawk
#region Actions
private TasBranch GetBranch(int index)
{
return Movie.GetBranch(index);
}
public void Branch()
{
TasBranch branch = CreateBranch();
Movie.NewBranchText = ""; // reset every time it's used
Movie.AddBranch(branch);
BranchView.RowCount = Movie.Branches.Count;
Movie.CurrentBranch = Movie.Branches.Count - 1;
Movie.Session.UpdateValues(Global.Emulator.Frame, Movie.CurrentBranch); // TODO: pass in emulator dependency
BranchView.ScrollToIndex(Movie.CurrentBranch);
Select(Movie.CurrentBranch, true);
var branch = CreateBranch();
Movie.Branches.NewBranchText = ""; // reset every time it's used
Branches.Add(branch);
BranchView.RowCount = Branches.Count;
Branches.Current = Branches.Count - 1;
Movie.Session.UpdateValues(Tastudio.Emulator.Frame, Branches.Current);
BranchView.ScrollToIndex(Branches.Current);
Select(Branches.Current, true);
BranchView.Refresh();
Tastudio.RefreshDialog();
MainForm.UpdateStatusSlots();
}
public TasBranch SelectedBranch => BranchView.AnyRowsSelected
? GetBranch(BranchView.SelectedRows.First())
? Branches[BranchView.SelectedRows.First()]
: null;
private TasBranch CreateBranch()
@ -156,14 +153,14 @@ namespace BizHawk.Client.EmuHawk
return new TasBranch
{
Frame = Tastudio.Emulator.Frame,
CoreData = (byte[])(Tastudio.StatableEmulator.SaveStateBinary().Clone()),
InputLog = Movie.CloneInput(),
CoreData = (byte[])Tastudio.StatableEmulator.SaveStateBinary().Clone(),
InputLog = Movie.GetLogEntries().Clone(),
CoreFrameBuffer = MainForm.MakeScreenshotImage(),
OSDFrameBuffer = MainForm.CaptureOSD(),
ChangeLog = new TasMovieChangeLog(Movie),
TimeStamp = DateTime.Now,
Markers = Movie.Markers.DeepClone(),
UserText = Movie.NewBranchText
UserText = Movie.Branches.NewBranchText
};
}
@ -190,7 +187,7 @@ namespace BizHawk.Client.EmuHawk
private void UpdateBranch(TasBranch branch)
{
Movie.UpdateBranch(branch, CreateBranch());
Branches.Replace(branch, CreateBranch());
Tastudio.RefreshDialog();
}
@ -199,10 +196,10 @@ namespace BizHawk.Client.EmuHawk
if (SelectedBranch != null)
{
int index = BranchView.SelectedRows.First();
Movie.CurrentBranch = index;
Branches.Current = index;
LoadBranch(SelectedBranch);
BranchView.Refresh();
Tastudio.MainForm.AddOnScreenMessage($"Loaded branch {Movie.CurrentBranch}");
Tastudio.MainForm.AddOnScreenMessage($"Loaded branch {Branches.Current}");
}
}
@ -219,28 +216,28 @@ namespace BizHawk.Client.EmuHawk
private void AddBranchToolStripMenuItem_Click(object sender, EventArgs e)
{
Branch();
SavedCallback?.Invoke(Movie.Branches.Count - 1);
Tastudio.MainForm.AddOnScreenMessage($"Added branch {Movie.CurrentBranch}");
SavedCallback?.Invoke(Branches.Count - 1);
Tastudio.MainForm.AddOnScreenMessage($"Added branch {Branches.Current}");
}
private void AddBranchWithTexToolStripMenuItem_Click(object sender, EventArgs e)
{
Branch();
EditBranchTextPopUp(Movie.CurrentBranch);
SavedCallback?.Invoke(Movie.Branches.Count - 1);
Tastudio.MainForm.AddOnScreenMessage($"Added branch {Movie.CurrentBranch}");
EditBranchTextPopUp(Branches.Current);
SavedCallback?.Invoke(Branches.Count - 1);
Tastudio.MainForm.AddOnScreenMessage($"Added branch {Branches.Current}");
}
private void LoadBranchToolStripMenuItem_Click(object sender, EventArgs e)
{
_backupBranch = CreateBranch();
var currentHashes = Movie.Branches.Select(b => b.UniqueIdentifier.GetHashCode()).ToList();
var currentHashes = Branches.Select(b => b.Uuid.GetHashCode()).ToList();
do
{
_backupBranch.UniqueIdentifier = Guid.NewGuid();
_backupBranch.Uuid = Guid.NewGuid();
}
while (currentHashes.Contains(_backupBranch.UniqueIdentifier.GetHashCode()));
while (currentHashes.Contains(_backupBranch.Uuid.GetHashCode()));
UndoBranchToolStripMenuItem.Enabled = UndoBranchButton.Enabled = true;
UndoBranchToolStripMenuItem.Text = "Undo Branch Load";
@ -261,7 +258,7 @@ namespace BizHawk.Client.EmuHawk
return;
}
Movie.CurrentBranch = BranchView.SelectedRows.First();
Branches.Current = BranchView.SelectedRows.First();
_backupBranch = SelectedBranch.Clone();
UndoBranchToolStripMenuItem.Enabled = UndoBranchButton.Enabled = true;
@ -270,8 +267,8 @@ namespace BizHawk.Client.EmuHawk
_branchUndo = BranchUndo.Update;
UpdateBranch(SelectedBranch);
SavedCallback?.Invoke(Movie.CurrentBranch);
Tastudio.MainForm.AddOnScreenMessage($"Saved branch {Movie.CurrentBranch}");
SavedCallback?.Invoke(Branches.Current);
Tastudio.MainForm.AddOnScreenMessage($"Saved branch {Branches.Current}");
}
private void EditBranchTextToolStripMenuItem_Click(object sender, EventArgs e)
@ -305,7 +302,7 @@ namespace BizHawk.Client.EmuHawk
}
int index = BranchView.SelectedRows.First();
TasBranch branch = Movie.GetBranch(index);
var branch = Branches[index];
Tastudio.GoToFrame(branch.Frame);
}
@ -317,13 +314,13 @@ namespace BizHawk.Client.EmuHawk
}
int index = BranchView.SelectedRows.First();
if (index == Movie.CurrentBranch)
if (index == Branches.Current)
{
Movie.CurrentBranch = -1;
Branches.Current = -1;
}
else if (index < Movie.CurrentBranch)
else if (index < Branches.Current)
{
Movie.CurrentBranch--;
Branches.Current--;
}
_backupBranch = SelectedBranch.Clone();
@ -332,13 +329,13 @@ namespace BizHawk.Client.EmuHawk
toolTip1.SetToolTip(UndoBranchButton, "Undo Branch Removal");
_branchUndo = BranchUndo.Remove;
Movie.RemoveBranch(SelectedBranch);
BranchView.RowCount = Movie.Branches.Count;
Branches.Remove(SelectedBranch);
BranchView.RowCount = Branches.Count;
if (index == Movie.Branches.Count)
if (index == Branches.Count)
{
BranchView.DeselectAll();
Select(Movie.Branches.Count - 1, true);
Select(Branches.Count - 1, true);
}
RemovedCallback?.Invoke(index);
@ -352,25 +349,34 @@ namespace BizHawk.Client.EmuHawk
if (_branchUndo == BranchUndo.Load)
{
LoadBranch(_backupBranch);
LoadedCallback?.Invoke(Movie.Branches.IndexOf(_backupBranch));
LoadedCallback?.Invoke(Branches.IndexOf(_backupBranch));
Tastudio.MainForm.AddOnScreenMessage("Branch Load canceled");
}
else if (_branchUndo == BranchUndo.Update)
{
Movie.UpdateBranch(Movie.GetBranch(_backupBranch.UniqueIdentifier), _backupBranch);
SavedCallback?.Invoke(Movie.Branches.IndexOf(_backupBranch));
Tastudio.MainForm.AddOnScreenMessage("Branch Update canceled");
var branch = Branches.SingleOrDefault(b => b.Uuid == _backupBranch.Uuid);
if (branch != null)
{
Branches.Replace(branch, _backupBranch);
SavedCallback?.Invoke(Branches.IndexOf(_backupBranch));
Tastudio.MainForm.AddOnScreenMessage("Branch Update canceled");
}
}
else if (_branchUndo == BranchUndo.Text)
{
Movie.GetBranch(_backupBranch.UniqueIdentifier).UserText = _backupBranch.UserText;
var branch = Branches.SingleOrDefault(b => b.Uuid == _backupBranch.Uuid);
if (branch != null)
{
branch.UserText = _backupBranch.UserText;
}
Tastudio.MainForm.AddOnScreenMessage("Branch Text Edit canceled");
}
else if (_branchUndo == BranchUndo.Remove)
{
Movie.AddBranch(_backupBranch);
BranchView.RowCount = Movie.Branches.Count;
SavedCallback?.Invoke(Movie.Branches.IndexOf(_backupBranch));
Branches.Add(_backupBranch);
BranchView.RowCount = Branches.Count;
SavedCallback?.Invoke(Branches.IndexOf(_backupBranch));
Tastudio.MainForm.AddOnScreenMessage("Branch Removal canceled");
}
@ -382,7 +388,7 @@ namespace BizHawk.Client.EmuHawk
public void AddBranchExternal()
{
AddBranchToolStripMenuItem_Click(null, null);
Select(Movie.CurrentBranch, true);
Select(Branches.Current, true);
BranchView.Refresh();
}
@ -395,7 +401,7 @@ namespace BizHawk.Client.EmuHawk
if (slot != -1)
{
if (GetBranch(slot) != null)
if (Branches[slot] != null)
{
Select(slot, true);
}
@ -418,7 +424,7 @@ namespace BizHawk.Client.EmuHawk
if (slot != -1)
{
if (GetBranch(slot) != null)
if (Branches[slot] != null)
{
Select(slot, true);
}
@ -445,7 +451,7 @@ namespace BizHawk.Client.EmuHawk
return;
}
if (GetBranch(slot) != null)
if (Branches[slot] != null)
{
Select(slot, true);
BranchView.Refresh();
@ -460,7 +466,7 @@ namespace BizHawk.Client.EmuHawk
{
if (SelectedBranch == null)
{
Select(Movie.CurrentBranch, true);
Select(Branches.Current, true);
BranchView.Refresh();
return;
}
@ -468,7 +474,7 @@ namespace BizHawk.Client.EmuHawk
int sel = BranchView.SelectedRows.First();
if (next)
{
if (GetBranch(sel + 1) != null)
if (Branches[sel + 1] != null)
{
Select(sel, false);
Select(sel + 1, true);
@ -476,7 +482,7 @@ namespace BizHawk.Client.EmuHawk
}
else // previous
{
if (GetBranch(sel - 1) != null)
if (Branches[sel - 1] != null)
{
Select(sel, false);
Select(sel - 1, true);
@ -509,12 +515,12 @@ namespace BizHawk.Client.EmuHawk
public void UpdateValues()
{
BranchView.RowCount = Movie.Branches.Count;
BranchView.RowCount = Branches.Count;
}
public void Restart()
{
BranchView.RowCount = Movie.Branches.Count;
BranchView.RowCount = Branches.Count;
if (BranchView.RowCount == 0)
{
@ -526,9 +532,9 @@ namespace BizHawk.Client.EmuHawk
public void UpdateTextColumnWidth()
{
if (Movie.Branches.Any())
if (Branches.Any())
{
var longestBranchText = Movie.Branches
var longestBranchText = Branches
.OrderBy(b => b.UserText?.Length ?? 0)
.Last()
.UserText;
@ -539,7 +545,7 @@ namespace BizHawk.Client.EmuHawk
public bool EditBranchTextPopUp(int index)
{
TasBranch branch = Movie.GetBranch(index);
var branch = Branches[index];
if (branch == null)
{
return false;
@ -557,7 +563,7 @@ namespace BizHawk.Client.EmuHawk
point.Offset(i.Width / -2, i.Height / -2);
var result = i.ShowHawkDialog(position: point);
if (result == DialogResult.OK)
if (result.IsOk())
{
branch.UserText = i.PromptText;
UpdateTextColumnWidth();
@ -622,25 +628,28 @@ namespace BizHawk.Client.EmuHawk
private void BranchView_CellDropped(object sender, InputRoll.CellEventArgs e)
{
if (e.NewCell.IsDataCell() && e.OldCell.RowIndex < Movie.Branches.Count)
if (e.NewCell.IsDataCell() && e.OldCell.RowIndex < Branches.Count)
{
var guid = Movie.BranchGuidByIndex(Movie.CurrentBranch);
Movie.SwapBranches(e.OldCell.RowIndex.Value, e.NewCell.RowIndex.Value);
int newIndex = Movie.BranchIndexByHash(guid);
Movie.CurrentBranch = newIndex;
var guid = Branches.Current > Branches.Count
? Guid.Empty
: Branches[Branches.Current].Uuid;
Branches.Swap(e.OldCell.RowIndex.Value, e.NewCell.RowIndex.Value);
int newIndex = Branches.IndexOfHash(guid);
Branches.Current = newIndex;
Select(newIndex, true);
}
}
private void BranchView_PointedCellChanged(object sender, InputRoll.CellEventArgs e)
{
if (e.NewCell?.RowIndex != null && e.NewCell.Column != null && e.NewCell.RowIndex < Movie.Branches.Count)
if (e.NewCell?.RowIndex != null && e.NewCell.Column != null && e.NewCell.RowIndex < Branches.Count)
{
if (BranchView.CurrentCell.Column.Name == BranchNumberColumnName &&
BranchView.CurrentCell.RowIndex.HasValue &&
BranchView.CurrentCell.RowIndex < Movie.Branches.Count)
BranchView.CurrentCell.RowIndex < Branches.Count)
{
TasBranch branch = GetBranch(BranchView.CurrentCell.RowIndex.Value);
var branch = Branches[BranchView.CurrentCell.RowIndex.Value];
Point location = PointToScreen(Location);
int width = branch.OSDFrameBuffer.Width;
int height = branch.OSDFrameBuffer.Height;

View File

@ -51,7 +51,7 @@ namespace BizHawk.Client.EmuHawk
refreshNeeded = AutoAdjustInput();
}
CurrentTasMovie.Session.UpdateValues(Emulator.Frame, CurrentTasMovie.CurrentBranch);
CurrentTasMovie.Session.UpdateValues(Emulator.Frame, CurrentTasMovie.Branches.Current);
MaybeFollowCursor();
if (TasView.IsPartiallyVisible(Emulator.Frame) || TasView.IsPartiallyVisible(_lastRefresh))

View File

@ -196,7 +196,7 @@ namespace BizHawk.Client.EmuHawk
}
else if (columnName == FrameColumnName)
{
TasMovieRecord record = CurrentTasMovie[index];
var record = CurrentTasMovie[index];
offsetX = -3;
offsetY = 1;
@ -262,7 +262,7 @@ namespace BizHawk.Client.EmuHawk
private void TasView_QueryRowBkColor(int index, ref Color color)
{
TasMovieRecord record = CurrentTasMovie[index];
var record = CurrentTasMovie[index];
if (MainForm.IsSeeking && MainForm.PauseOnFrame == index)
{
@ -315,7 +315,7 @@ namespace BizHawk.Client.EmuHawk
if (columnName == CursorColumnName)
{
int branchIndex = CurrentTasMovie.BranchIndexByFrame(index);
int branchIndex = CurrentTasMovie.Branches.IndexOfFrame(index);
if (branchIndex != -1)
{
text = branchIndex.ToString();
@ -356,10 +356,9 @@ namespace BizHawk.Client.EmuHawk
}
}
// SuuperW: Used in InputRoll.cs to hide lag frames.
private bool TasView_QueryFrameLag(int index, bool hideWasLag)
{
TasMovieRecord lag = CurrentTasMovie[index];
var lag = CurrentTasMovie[index];
return (lag.Lagged.HasValue && lag.Lagged.Value) || (hideWasLag && lag.WasLagged.HasValue && lag.WasLagged.Value);
}
@ -518,7 +517,7 @@ namespace BizHawk.Client.EmuHawk
{
if (MainForm.EmulatorPaused)
{
TasMovieRecord record = CurrentTasMovie[LastPositionFrame];
var record = CurrentTasMovie[LastPositionFrame];
if (!record.Lagged.HasValue && LastPositionFrame > Emulator.Frame)
{
StartSeeking(LastPositionFrame, true);
@ -744,7 +743,7 @@ namespace BizHawk.Client.EmuHawk
else
{
_rightClickInput = new string[1];
_rightClickInput[0] = CurrentTasMovie.GetLogEntries()[frame];
_rightClickInput[0] = CurrentTasMovie.GetInputLogEntry(frame);
_rightClickFrame = frame;
}

View File

@ -42,7 +42,7 @@ namespace BizHawk.Client.EmuHawk
{
int index = Emulator.Frame;
TasMovie newProject = CurrentTasMovie.ConvertToSavestateAnchoredMovie(
var newProject = CurrentTasMovie.ConvertToSavestateAnchoredMovie(
index, (byte[])StatableEmulator.SaveStateBinary().Clone());
MainForm.PauseEmulator();
@ -63,7 +63,7 @@ namespace BizHawk.Client.EmuHawk
}
GoToFrame(index);
TasMovie newProject = CurrentTasMovie.ConvertToSaveRamAnchoredMovie(
var newProject = CurrentTasMovie.ConvertToSaveRamAnchoredMovie(
SaveRamEmulator.CloneSaveRam());
MainForm.PauseEmulator();
LoadFile(new FileInfo(newProject.Filename), true);
@ -114,11 +114,11 @@ namespace BizHawk.Client.EmuHawk
var result = ofd.ShowHawkDialog();
if (result.IsOk())
{
if (ofd.FileName.EndsWith(TasMovie.Extension))
if (ofd.FileName.EndsWith(MovieService.TasMovieExtension))
{
LoadFile(new FileInfo(ofd.FileName));
}
else if (ofd.FileName.EndsWith(Bk2Movie.Extension))
else if (ofd.FileName.EndsWith(MovieService.StandardMovieExtension))
{
var result1 = MessageBox.Show("This is a regular movie, a new project must be created from it, in order to use in TAStudio\nProceed?", "Convert movie", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
if (result1.IsOk())
@ -759,7 +759,7 @@ namespace BizHawk.Client.EmuHawk
private void ClearGreenzoneMenuItem_Click(object sender, EventArgs e)
{
CurrentTasMovie.ClearGreenzone();
CurrentTasMovie.TasStateManager.Clear();
RefreshDialog();
}
@ -775,7 +775,7 @@ namespace BizHawk.Client.EmuHawk
GoToFrame(0);
int lastState = 0;
int goToFrame = CurrentTasMovie.LastStatedFrame;
int goToFrame = CurrentTasMovie.TasStateManager.Last;
do
{
MainForm.FrameAdvance();

View File

@ -16,7 +16,7 @@ namespace BizHawk.Client.EmuHawk
public partial class TAStudio : ToolFormBase, IToolFormAutoConfig, IControlMainform
{
// TODO: UI flow that conveniently allows to start from savestate
public TasMovie CurrentTasMovie => MovieSession.Movie as TasMovie;
public ITasMovie CurrentTasMovie => MovieSession.Movie as ITasMovie;
public bool IsInMenuLoop { get; private set; }
public string StatesPath => Config.PathEntries.TastudioStatesAbsolutePath();
@ -322,7 +322,7 @@ namespace BizHawk.Client.EmuHawk
}
// Start Scenario 1: A regular movie is active
if (MovieSession.Movie.IsActive() && !(MovieSession.Movie is TasMovie))
if (MovieSession.Movie.IsActive() && !(MovieSession.Movie is ITasMovie))
{
var result = MessageBox.Show("In order to use Tastudio, a new project must be created from the current movie\nThe current movie will be saved and closed, and a new project file will be created\nProceed?", "Convert movie", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
if (result.IsOk())
@ -338,7 +338,7 @@ namespace BizHawk.Client.EmuHawk
}
// Start Scenario 2: A tasproj is already active
else if (MovieSession.Movie.IsActive() && MovieSession.Movie is TasMovie)
else if (MovieSession.Movie.IsActive() && MovieSession.Movie is ITasMovie)
{
bool result = LoadFile(new FileInfo(CurrentTasMovie.Filename), gotoFrame: Emulator.Frame);
if (!result)
@ -375,7 +375,7 @@ namespace BizHawk.Client.EmuHawk
return true;
}
private void SetTasMovieCallbacks(TasMovie movie)
private void SetTasMovieCallbacks(ITasMovie movie)
{
movie.ClientSettingsForSave = ClientSettingsForSave;
movie.GetClientSettingsOnLoad = GetClientSettingsOnLoad;
@ -628,11 +628,9 @@ namespace BizHawk.Client.EmuHawk
return false;
}
var newMovie = new TasMovie(startsFromSavestate: startsFromSavestate)
{
Filename = file.FullName,
BindMarkersToInput = Settings.BindMarkersToInput
};
var newMovie = MovieService.CreateTas(startsFromSavestate: startsFromSavestate);
newMovie.Filename = file.FullName;
newMovie.BindMarkersToInput = Settings.BindMarkersToInput;
newMovie.TasStateManager.InvalidateCallback = GreenzoneInvalidated;
@ -666,7 +664,7 @@ namespace BizHawk.Client.EmuHawk
SetUpToolStripColumns();
CurrentTasMovie.PropertyChanged += TasMovie_OnPropertyChanged;
CurrentTasMovie.CurrentBranch = CurrentTasMovie.Session.CurrentBranch;
CurrentTasMovie.Branches.Current = CurrentTasMovie.Session.CurrentBranch;
BookMarkControl.UpdateTextColumnWidth();
MarkerControl.UpdateTextColumnWidth();
// clear all selections
@ -685,11 +683,9 @@ namespace BizHawk.Client.EmuHawk
return;
}
var tasMovie = new TasMovie
{
BindMarkersToInput = Settings.BindMarkersToInput,
Filename = DefaultTasProjName() // TODO don't do this, take over any mainform actions that can crash without a filename
};
var tasMovie = MovieService.CreateTas();
tasMovie.BindMarkersToInput = Settings.BindMarkersToInput;
tasMovie.Filename = DefaultTasProjName(); // TODO don't do this, take over any mainform actions that can crash without a filename
tasMovie.TasStateManager.InvalidateCallback = GreenzoneInvalidated;
tasMovie.PropertyChanged += TasMovie_OnPropertyChanged;
@ -721,7 +717,7 @@ namespace BizHawk.Client.EmuHawk
TasView.Refresh();
}
private bool HandleMovieLoadStuff(TasMovie movie)
private bool HandleMovieLoadStuff(ITasMovie movie)
{
WantsToControlStopMovie = false;
var result = StartNewMovieWrapper(movie);
@ -733,7 +729,7 @@ namespace BizHawk.Client.EmuHawk
WantsToControlStopMovie = true;
CurrentTasMovie.ChangeLog.ClearLog();
CurrentTasMovie.ChangeLog.Clear();
CurrentTasMovie.ClearChanges();
SetTextProperty();
@ -742,7 +738,7 @@ namespace BizHawk.Client.EmuHawk
return true;
}
private bool StartNewMovieWrapper(TasMovie movie)
private bool StartNewMovieWrapper(ITasMovie movie)
{
_initializing = true;
@ -825,12 +821,14 @@ namespace BizHawk.Client.EmuHawk
MainForm.SetMainformMovieInfo();
}
private const string DefaultTasProjectName = "default";
// Used when starting a new project
private string DefaultTasProjName()
{
return Path.Combine(
Config.PathEntries.MovieAbsolutePath(),
$"{TasMovie.DefaultProjectName}.{TasMovie.Extension}");
$"{DefaultTasProjectName}.{MovieService.TasMovieExtension}");
}
// Used for things like SaveFile dialogs to suggest a name to the user
@ -838,7 +836,7 @@ namespace BizHawk.Client.EmuHawk
{
return Path.Combine(
Config.PathEntries.MovieAbsolutePath(),
$"{Global.Game.FilesystemSafeName()}.{TasMovie.Extension}");
$"{Global.Game.FilesystemSafeName()}.{MovieService.TasMovieExtension}");
}
private void SaveTas()
@ -1178,7 +1176,7 @@ namespace BizHawk.Client.EmuHawk
}
var filePaths = (string[])e.Data.GetData(DataFormats.FileDrop);
if (Path.GetExtension(filePaths[0]) == $".{TasMovie.Extension}")
if (Path.GetExtension(filePaths[0]) == $".{MovieService.TasMovieExtension}")
{
FileInfo file = new FileInfo(filePaths[0]);
if (file.Exists)
@ -1209,7 +1207,7 @@ namespace BizHawk.Client.EmuHawk
private bool AutoAdjustInput()
{
TasMovieRecord lagLog = CurrentTasMovie[Emulator.Frame - 1]; // Minus one because get frame is +1;
var lagLog = CurrentTasMovie[Emulator.Frame - 1]; // Minus one because get frame is +1;
bool isLag = Emulator.AsInputPollable().IsLagFrame;
if (lagLog.WasLagged.HasValue)
@ -1222,7 +1220,7 @@ namespace BizHawk.Client.EmuHawk
CurrentTasMovie.ChangeLog.IsRecording = false;
CurrentTasMovie.RemoveFrame(Emulator.Frame - 1);
CurrentTasMovie.RemoveLagHistory(Emulator.Frame); // Removes from WasLag
CurrentTasMovie.LagLog.RemoveHistoryAt(Emulator.Frame); // Removes from WasLag
CurrentTasMovie.ChangeLog.IsRecording = wasRecording;
GoToFrame(Emulator.Frame - 1);
@ -1236,7 +1234,7 @@ namespace BizHawk.Client.EmuHawk
CurrentTasMovie.ChangeLog.IsRecording = false;
CurrentTasMovie.InsertInput(Emulator.Frame - 1, CurrentTasMovie.GetInputLogEntry(Emulator.Frame - 2));
CurrentTasMovie.InsertLagHistory(Emulator.Frame, true);
CurrentTasMovie.LagLog.InsertHistoryAt(Emulator.Frame, true);
CurrentTasMovie.ChangeLog.IsRecording = wasRecording;
return true;

View File

@ -13,7 +13,7 @@ namespace BizHawk.Client.EmuHawk
private readonly TAStudio _tastudio;
private string _lastUndoAction;
private TasMovieChangeLog Log => _tastudio.CurrentTasMovie.ChangeLog;
private IMovieChangeLog Log => _tastudio.CurrentTasMovie.ChangeLog;
public UndoHistoryForm(TAStudio owner)
{
@ -69,7 +69,7 @@ namespace BizHawk.Client.EmuHawk
private void ClearButton_Click(object sender, EventArgs e)
{
Log.ClearLog();
Log.Clear();
UpdateValues();
}
@ -164,7 +164,7 @@ namespace BizHawk.Client.EmuHawk
{
if (SelectedItem != -1)
{
Log.ClearLog(SelectedItem);
Log.Clear(SelectedItem);
}
UpdateValues();