Move a bunch of logic from MainForm.Movie.cs to MovieSession.cs which is more conceptually appropriate, this also means that movie handling logic (including complex movie loadstate logic) is moved to Client.Common
This commit is contained in:
parent
380fc781e3
commit
3cda83c2bc
|
@ -1,10 +1,45 @@
|
|||
namespace BizHawk.Client.Common
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public class MovieSession
|
||||
{
|
||||
public MultitrackRecording MultiTrack = new MultitrackRecording();
|
||||
public Movie Movie;
|
||||
public MovieControllerAdapter MovieControllerAdapter = new MovieControllerAdapter();
|
||||
public bool EditorMode { get; set; }
|
||||
public Action ClearSRAMCallback; //Required
|
||||
public Action<string> MessageCallback; //Not Required
|
||||
public Func<string, string, bool> AskYesNoCallback; //Not Required
|
||||
|
||||
private void Output(string message)
|
||||
{
|
||||
if (MessageCallback != null)
|
||||
{
|
||||
MessageCallback(message);
|
||||
}
|
||||
}
|
||||
|
||||
private bool AskYesNo(string title, string message)
|
||||
{
|
||||
if (AskYesNoCallback != null)
|
||||
{
|
||||
return AskYesNoCallback(title, message);
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private bool HandleGuidError()
|
||||
{
|
||||
return AskYesNo(
|
||||
"GUID Mismatch error",
|
||||
"The savestate GUID does not match the current movie. Proceed anyway?"
|
||||
);
|
||||
}
|
||||
|
||||
public void LatchMultitrackPlayerInput(IController playerSource, MultitrackRewiringControllerAdapter rewiredSource)
|
||||
{
|
||||
|
@ -25,12 +60,410 @@
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// latch input from the input log, if available
|
||||
/// Latch input from the input log, if available
|
||||
/// </summary>
|
||||
public void LatchInputFromLog()
|
||||
{
|
||||
string loggedFrame = Movie.GetInput(Global.Emulator.Frame);
|
||||
MovieControllerAdapter.SetControllersAsMnemonic(loggedFrame);
|
||||
MovieControllerAdapter.SetControllersAsMnemonic(
|
||||
Movie.GetInput(Global.Emulator.Frame)
|
||||
);
|
||||
}
|
||||
|
||||
public void StopMovie(bool abortchanges = false)
|
||||
{
|
||||
string message = "Movie ";
|
||||
if (Movie.IsRecording)
|
||||
{
|
||||
message += "recording ";
|
||||
}
|
||||
else if (Movie.IsPlaying)
|
||||
{
|
||||
message += "playback ";
|
||||
}
|
||||
|
||||
message += "stopped.";
|
||||
|
||||
if (Movie.IsActive)
|
||||
{
|
||||
Movie.Stop(abortchanges);
|
||||
if (!abortchanges)
|
||||
{
|
||||
Output(Path.GetFileName(Movie.Filename) + " written to disk.");
|
||||
}
|
||||
Output(message);
|
||||
Global.ReadOnly = true;
|
||||
}
|
||||
}
|
||||
|
||||
//State handling
|
||||
public void HandleMovieSaveState(StreamWriter writer)
|
||||
{
|
||||
if (Movie.IsActive)
|
||||
{
|
||||
Movie.DumpLogIntoSavestateText(writer);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearFrame()
|
||||
{
|
||||
if (Movie.IsPlaying)
|
||||
{
|
||||
Movie.ClearFrame(Global.Emulator.Frame);
|
||||
Output("Scrubbed input at frame " + Global.Emulator.Frame.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public void HandleMovieOnFrameLoop(bool clearFramePressed)
|
||||
{
|
||||
if (!Movie.IsActive)
|
||||
{
|
||||
LatchInputFromPlayer(Global.MovieInputSourceAdapter);
|
||||
}
|
||||
|
||||
else if (Movie.IsFinished)
|
||||
{
|
||||
if (Global.Emulator.Frame < Movie.Frames) //This scenario can happen from rewinding (suddenly we are back in the movie, so hook back up to the movie
|
||||
{
|
||||
Movie.SwitchToPlay();
|
||||
LatchInputFromLog();
|
||||
}
|
||||
else
|
||||
{
|
||||
LatchInputFromPlayer(Global.MovieInputSourceAdapter);
|
||||
}
|
||||
}
|
||||
|
||||
else if (Movie.IsPlaying)
|
||||
{
|
||||
if (Global.Emulator.Frame >= Movie.Frames)
|
||||
{
|
||||
if (EditorMode)
|
||||
{
|
||||
Movie.CaptureState();
|
||||
LatchInputFromLog();
|
||||
Movie.CommitFrame(Global.Emulator.Frame, Global.MovieOutputHardpoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
Movie.Finish();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Movie.CaptureState();
|
||||
LatchInputFromLog();
|
||||
if (clearFramePressed)
|
||||
{
|
||||
LatchInputFromPlayer(Global.MovieInputSourceAdapter);
|
||||
ClearFrame();
|
||||
}
|
||||
else if (EditorMode || Global.Config.MoviePlaybackPokeMode)
|
||||
{
|
||||
LatchInputFromPlayer(Global.MovieInputSourceAdapter);
|
||||
var mg = new MnemonicsGenerator();
|
||||
mg.SetSource(Global.MovieOutputHardpoint);
|
||||
if (!mg.IsEmpty)
|
||||
{
|
||||
LatchInputFromPlayer(Global.MovieInputSourceAdapter);
|
||||
Movie.PokeFrame(Global.Emulator.Frame, mg.GetControllersAsMnemonic());
|
||||
}
|
||||
else
|
||||
{
|
||||
LatchInputFromLog();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (Movie.IsRecording)
|
||||
{
|
||||
Movie.CaptureState();
|
||||
if (MultiTrack.IsActive)
|
||||
{
|
||||
LatchMultitrackPlayerInput(Global.MovieInputSourceAdapter, Global.MultitrackRewiringControllerAdapter);
|
||||
}
|
||||
else
|
||||
{
|
||||
LatchInputFromPlayer(Global.MovieInputSourceAdapter);
|
||||
}
|
||||
//the movie session makes sure that the correct input has been read and merged to its MovieControllerAdapter;
|
||||
//this has been wired to Global.MovieOutputHardpoint in RewireInputChain
|
||||
Movie.CommitFrame(Global.Emulator.Frame, Global.MovieOutputHardpoint);
|
||||
}
|
||||
}
|
||||
|
||||
//OMG this needs to be refactored!
|
||||
public bool HandleMovieLoadState(StreamReader reader)
|
||||
{
|
||||
string ErrorMSG = String.Empty;
|
||||
|
||||
if (!Movie.IsActive)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
else if (Movie.IsRecording)
|
||||
{
|
||||
if (Global.ReadOnly)
|
||||
{
|
||||
var result = Movie.CheckTimeLines(reader, OnlyGUID: false, IgnoreGuidMismatch: false, ErrorMessage: out ErrorMSG);
|
||||
if (result == Movie.LoadStateResult.Pass)
|
||||
{
|
||||
Movie.WriteMovie();
|
||||
Movie.SwitchToPlay();
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result == Movie.LoadStateResult.GuidMismatch)
|
||||
{
|
||||
if (HandleGuidError())
|
||||
{
|
||||
var newresult = Movie.CheckTimeLines(reader, OnlyGUID: false, IgnoreGuidMismatch: true, ErrorMessage: out ErrorMSG);
|
||||
if (newresult == Movie.LoadStateResult.Pass)
|
||||
{
|
||||
Movie.WriteMovie();
|
||||
Movie.SwitchToPlay();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Output(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Output(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = Movie.CheckTimeLines(reader, OnlyGUID: true, IgnoreGuidMismatch: false, ErrorMessage: out ErrorMSG);
|
||||
if (result == Movie.LoadStateResult.Pass)
|
||||
{
|
||||
reader.BaseStream.Position = 0;
|
||||
reader.DiscardBufferedData();
|
||||
Movie.LoadLogFromSavestateText(reader, MultiTrack.IsActive);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result == Movie.LoadStateResult.GuidMismatch)
|
||||
{
|
||||
if (HandleGuidError())
|
||||
{
|
||||
var newresult = Movie.CheckTimeLines(reader, OnlyGUID: false, IgnoreGuidMismatch: true, ErrorMessage: out ErrorMSG);
|
||||
if (newresult == Movie.LoadStateResult.Pass)
|
||||
{
|
||||
reader.BaseStream.Position = 0;
|
||||
reader.DiscardBufferedData();
|
||||
Movie.LoadLogFromSavestateText(reader, MultiTrack.IsActive);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Output(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Output(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (Movie.IsPlaying && !Movie.IsFinished)
|
||||
{
|
||||
if (Global.ReadOnly)
|
||||
{
|
||||
var result = Movie.CheckTimeLines(reader, OnlyGUID: !Global.ReadOnly, IgnoreGuidMismatch: false, ErrorMessage: out ErrorMSG);
|
||||
if (result == Movie.LoadStateResult.Pass)
|
||||
{
|
||||
//Frame loop automatically handles the rewinding effect based on Global.Emulator.Frame so nothing else is needed here
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result == Movie.LoadStateResult.GuidMismatch)
|
||||
{
|
||||
if (HandleGuidError())
|
||||
{
|
||||
var newresult = Movie.CheckTimeLines(reader, OnlyGUID: !Global.ReadOnly, IgnoreGuidMismatch: true, ErrorMessage: out ErrorMSG);
|
||||
if (newresult == Movie.LoadStateResult.Pass)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Output(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Output(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = Movie.CheckTimeLines(reader, OnlyGUID: !Global.ReadOnly, IgnoreGuidMismatch: false, ErrorMessage: out ErrorMSG);
|
||||
if (result == Movie.LoadStateResult.Pass)
|
||||
{
|
||||
Movie.SwitchToRecord();
|
||||
reader.BaseStream.Position = 0;
|
||||
reader.DiscardBufferedData();
|
||||
Movie.LoadLogFromSavestateText(reader, MultiTrack.IsActive);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result == Movie.LoadStateResult.GuidMismatch)
|
||||
{
|
||||
if (HandleGuidError())
|
||||
{
|
||||
var newresult = Movie.CheckTimeLines(reader, OnlyGUID: !Global.ReadOnly, IgnoreGuidMismatch: true, ErrorMessage: out ErrorMSG);
|
||||
if (newresult == Movie.LoadStateResult.Pass)
|
||||
{
|
||||
Movie.SwitchToRecord();
|
||||
reader.BaseStream.Position = 0;
|
||||
reader.DiscardBufferedData();
|
||||
Movie.LoadLogFromSavestateText(reader, MultiTrack.IsActive);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Output(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Output(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Movie.IsFinished)
|
||||
{
|
||||
if (Global.ReadOnly)
|
||||
{
|
||||
var result = Movie.CheckTimeLines(reader, OnlyGUID: !Global.ReadOnly, IgnoreGuidMismatch: false, ErrorMessage: out ErrorMSG);
|
||||
if (result != Movie.LoadStateResult.Pass)
|
||||
{
|
||||
if (result == Movie.LoadStateResult.GuidMismatch)
|
||||
{
|
||||
if (HandleGuidError())
|
||||
{
|
||||
var newresult = Movie.CheckTimeLines(reader, OnlyGUID: !Global.ReadOnly, IgnoreGuidMismatch: true, ErrorMessage: out ErrorMSG);
|
||||
if (newresult == Movie.LoadStateResult.Pass)
|
||||
{
|
||||
Movie.SwitchToPlay();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Output(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Output(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (Movie.IsFinished) //TimeLine check can change a movie to finished, hence the check here (not a good design)
|
||||
{
|
||||
LatchInputFromPlayer(Global.MovieInputSourceAdapter);
|
||||
}
|
||||
else
|
||||
{
|
||||
Movie.SwitchToPlay();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = Movie.CheckTimeLines(reader, OnlyGUID: !Global.ReadOnly, IgnoreGuidMismatch: false, ErrorMessage: out ErrorMSG);
|
||||
if (result == Movie.LoadStateResult.Pass)
|
||||
{
|
||||
ClearSRAMCallback();
|
||||
Movie.StartRecording();
|
||||
reader.BaseStream.Position = 0;
|
||||
reader.DiscardBufferedData();
|
||||
Movie.LoadLogFromSavestateText(reader, MultiTrack.IsActive);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result == Movie.LoadStateResult.GuidMismatch)
|
||||
{
|
||||
if (HandleGuidError())
|
||||
{
|
||||
var newresult = Movie.CheckTimeLines(reader, OnlyGUID: !Global.ReadOnly, IgnoreGuidMismatch: true, ErrorMessage: out ErrorMSG);
|
||||
if (newresult == Movie.LoadStateResult.Pass)
|
||||
{
|
||||
ClearSRAMCallback();
|
||||
Movie.StartRecording();
|
||||
reader.BaseStream.Position = 0;
|
||||
reader.DiscardBufferedData();
|
||||
Movie.LoadLogFromSavestateText(reader, MultiTrack.IsActive);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Output(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Output(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -369,12 +369,12 @@ namespace BizHawk.MultiClient
|
|||
|
||||
private void RecordMovieMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
RecordMovie();
|
||||
LoadRecordMovieDialog();
|
||||
}
|
||||
|
||||
private void PlayMovieMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
PlayMovie();
|
||||
LoadPlayMovieDialog();
|
||||
}
|
||||
|
||||
private void StopMovieMenuItem_Click(object sender, EventArgs e)
|
||||
|
@ -384,7 +384,7 @@ namespace BizHawk.MultiClient
|
|||
|
||||
private void PlayFromBeginningMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
PlayMovieFromBeginning();
|
||||
RestartMovie();
|
||||
}
|
||||
|
||||
private void ImportMovieMenuItem_Click(object sender, EventArgs e)
|
||||
|
|
|
@ -8,15 +8,6 @@ namespace BizHawk.MultiClient
|
|||
{
|
||||
partial class MainForm
|
||||
{
|
||||
public void ClearFrame()
|
||||
{
|
||||
if (Global.MovieSession.Movie.IsPlaying)
|
||||
{
|
||||
Global.MovieSession.Movie.ClearFrame(Global.Emulator.Frame);
|
||||
GlobalWinF.OSD.AddMessage("Scrubbed input at frame " + Global.Emulator.Frame.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public void StartNewMovie(Movie m, bool record)
|
||||
{
|
||||
//If a movie is already loaded, save it before starting a new movie
|
||||
|
@ -25,7 +16,14 @@ namespace BizHawk.MultiClient
|
|||
Global.MovieSession.Movie.WriteMovie();
|
||||
}
|
||||
|
||||
Global.MovieSession = new MovieSession { Movie = m };
|
||||
Global.MovieSession = new MovieSession
|
||||
{
|
||||
Movie = m,
|
||||
ClearSRAMCallback = ClearSaveRAM,
|
||||
MessageCallback = GlobalWinF.OSD.AddMessage,
|
||||
AskYesNoCallback = StateErrorAskUser
|
||||
};
|
||||
|
||||
RewireInputChain();
|
||||
|
||||
if (!record)
|
||||
|
@ -84,31 +82,30 @@ namespace BizHawk.MultiClient
|
|||
}
|
||||
}
|
||||
|
||||
public void PlayMovie()
|
||||
public void LoadPlayMovieDialog()
|
||||
{
|
||||
new PlayMovie().ShowDialog();
|
||||
}
|
||||
|
||||
public void RecordMovie()
|
||||
public void LoadRecordMovieDialog()
|
||||
{
|
||||
// put any BEETA quality cores here
|
||||
if (Global.Emulator is Emulation.Consoles.Nintendo.GBA.GBA ||
|
||||
Global.Emulator is Emulation.Consoles.Sega.Genesis ||
|
||||
Global.Emulator is Emulation.Consoles.Sega.Saturn.Yabause ||
|
||||
Global.Emulator is Emulation.Consoles.Sony.PSP.PSP)
|
||||
Global.Emulator is Emulation.Consoles.Sony.PSP.PSP)
|
||||
{
|
||||
var result = MessageBox.Show
|
||||
(this, "Thanks for using Bizhawk! The emulation core you have selected " +
|
||||
"is currently BETA-status. We appreciate your help in testing Bizhawk. " +
|
||||
"You can record a movie on this core if you'd like to, but expect to " +
|
||||
"encounter bugs and sync problems. Continue?", "BizHawk", MessageBoxButtons.YesNo);
|
||||
if (result != DialogResult.Yes)
|
||||
return;
|
||||
if (result != DialogResult.Yes) return;
|
||||
}
|
||||
new RecordMovie().ShowDialog();
|
||||
}
|
||||
|
||||
public void PlayMovieFromBeginning()
|
||||
public void RestartMovie()
|
||||
{
|
||||
if (Global.MovieSession.Movie.IsActive)
|
||||
{
|
||||
|
@ -128,430 +125,16 @@ namespace BizHawk.MultiClient
|
|||
|
||||
public void StopMovie(bool abortchanges = false)
|
||||
{
|
||||
string message = "Movie ";
|
||||
if (Global.MovieSession.Movie.IsRecording)
|
||||
{
|
||||
message += "recording ";
|
||||
}
|
||||
else if (Global.MovieSession.Movie.IsPlaying)
|
||||
{
|
||||
message += "playback ";
|
||||
}
|
||||
|
||||
message += "stopped.";
|
||||
|
||||
if (Global.MovieSession.Movie.IsActive)
|
||||
{
|
||||
Global.MovieSession.Movie.Stop(abortchanges);
|
||||
if (!abortchanges)
|
||||
{
|
||||
GlobalWinF.OSD.AddMessage(Path.GetFileName(Global.MovieSession.Movie.Filename) + " written to disk.");
|
||||
}
|
||||
GlobalWinF.OSD.AddMessage(message);
|
||||
Global.ReadOnly = true;
|
||||
SetMainformMovieInfo();
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowError(string error)
|
||||
{
|
||||
if (!String.IsNullOrWhiteSpace(error))
|
||||
{
|
||||
MessageBox.Show(error, "Loadstate Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
Global.MovieSession.StopMovie();
|
||||
SetMainformMovieInfo();
|
||||
}
|
||||
|
||||
private bool HandleMovieLoadState(string path)
|
||||
{
|
||||
using (var sr = new StreamReader(path))
|
||||
{
|
||||
return HandleMovieLoadState(sr);
|
||||
}
|
||||
}
|
||||
|
||||
//OMG this needs to be refactored!
|
||||
private bool HandleMovieLoadState(StreamReader reader)
|
||||
{
|
||||
string ErrorMSG = String.Empty;
|
||||
//Note, some of the situations in these IF's may be identical and could be combined but I intentionally separated it out for clarity
|
||||
if (!Global.MovieSession.Movie.IsActive)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
else if (Global.MovieSession.Movie.IsRecording)
|
||||
{
|
||||
if (Global.ReadOnly)
|
||||
{
|
||||
var result = Global.MovieSession.Movie.CheckTimeLines(reader, OnlyGUID: false, IgnoreGuidMismatch: false, ErrorMessage: out ErrorMSG);
|
||||
if (result == Movie.LoadStateResult.Pass)
|
||||
{
|
||||
Global.MovieSession.Movie.WriteMovie();
|
||||
Global.MovieSession.Movie.SwitchToPlay();
|
||||
SetMainformMovieInfo();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result == Movie.LoadStateResult.GuidMismatch)
|
||||
{
|
||||
var dresult = MessageBox.Show("The savestate GUID does not match the current movie. Proceed anyway?",
|
||||
"GUID Mismatch error",
|
||||
MessageBoxButtons.YesNo, MessageBoxIcon.Question);
|
||||
if (dresult == DialogResult.Yes)
|
||||
{
|
||||
var newresult = Global.MovieSession.Movie.CheckTimeLines(reader, OnlyGUID: false, IgnoreGuidMismatch: true, ErrorMessage: out ErrorMSG);
|
||||
if (newresult == Movie.LoadStateResult.Pass)
|
||||
{
|
||||
Global.MovieSession.Movie.WriteMovie();
|
||||
Global.MovieSession.Movie.SwitchToPlay();
|
||||
SetMainformMovieInfo();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowError(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowError(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = Global.MovieSession.Movie.CheckTimeLines(reader, OnlyGUID: true, IgnoreGuidMismatch: false, ErrorMessage: out ErrorMSG);
|
||||
if (result == Movie.LoadStateResult.Pass)
|
||||
{
|
||||
reader.BaseStream.Position = 0;
|
||||
reader.DiscardBufferedData();
|
||||
Global.MovieSession.Movie.LoadLogFromSavestateText(reader, Global.MovieSession.MultiTrack.IsActive);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result == Movie.LoadStateResult.GuidMismatch)
|
||||
{
|
||||
var dresult = MessageBox.Show("The savestate GUID does not match the current movie. Proceed anyway?",
|
||||
"GUID Mismatch error",
|
||||
MessageBoxButtons.YesNo, MessageBoxIcon.Question);
|
||||
if (dresult == DialogResult.Yes)
|
||||
{
|
||||
var newresult = Global.MovieSession.Movie.CheckTimeLines(reader, OnlyGUID: false, IgnoreGuidMismatch: true, ErrorMessage: out ErrorMSG);
|
||||
if (newresult == Movie.LoadStateResult.Pass)
|
||||
{
|
||||
reader.BaseStream.Position = 0;
|
||||
reader.DiscardBufferedData();
|
||||
Global.MovieSession.Movie.LoadLogFromSavestateText(reader, Global.MovieSession.MultiTrack.IsActive);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowError(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowError(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (Global.MovieSession.Movie.IsPlaying && !Global.MovieSession.Movie.IsFinished)
|
||||
{
|
||||
if (Global.ReadOnly)
|
||||
{
|
||||
var result = Global.MovieSession.Movie.CheckTimeLines(reader, OnlyGUID: !Global.ReadOnly, IgnoreGuidMismatch: false, ErrorMessage: out ErrorMSG);
|
||||
if (result == Movie.LoadStateResult.Pass)
|
||||
{
|
||||
//Frame loop automatically handles the rewinding effect based on Global.Emulator.Frame so nothing else is needed here
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result == Movie.LoadStateResult.GuidMismatch)
|
||||
{
|
||||
var dresult = MessageBox.Show("The savestate GUID does not match the current movie. Proceed anyway?",
|
||||
"GUID Mismatch error",
|
||||
MessageBoxButtons.YesNo, MessageBoxIcon.Question);
|
||||
if (dresult == DialogResult.Yes)
|
||||
{
|
||||
var newresult = Global.MovieSession.Movie.CheckTimeLines(reader, OnlyGUID: !Global.ReadOnly, IgnoreGuidMismatch: true, ErrorMessage: out ErrorMSG);
|
||||
if (newresult == Movie.LoadStateResult.Pass)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowError(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowError(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = Global.MovieSession.Movie.CheckTimeLines(reader, OnlyGUID: !Global.ReadOnly, IgnoreGuidMismatch: false, ErrorMessage: out ErrorMSG);
|
||||
if (result == Movie.LoadStateResult.Pass)
|
||||
{
|
||||
Global.MovieSession.Movie.SwitchToRecord();
|
||||
SetMainformMovieInfo();
|
||||
reader.BaseStream.Position = 0;
|
||||
reader.DiscardBufferedData();
|
||||
Global.MovieSession.Movie.LoadLogFromSavestateText(reader, Global.MovieSession.MultiTrack.IsActive);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result == Movie.LoadStateResult.GuidMismatch)
|
||||
{
|
||||
var dresult = MessageBox.Show("The savestate GUID does not match the current movie. Proceed anyway?",
|
||||
"GUID Mismatch error",
|
||||
MessageBoxButtons.YesNo, MessageBoxIcon.Question);
|
||||
if (dresult == DialogResult.Yes)
|
||||
{
|
||||
var newresult = Global.MovieSession.Movie.CheckTimeLines(reader, OnlyGUID: !Global.ReadOnly, IgnoreGuidMismatch: true, ErrorMessage: out ErrorMSG);
|
||||
if (newresult == Movie.LoadStateResult.Pass)
|
||||
{
|
||||
Global.MovieSession.Movie.SwitchToRecord();
|
||||
SetMainformMovieInfo();
|
||||
reader.BaseStream.Position = 0;
|
||||
reader.DiscardBufferedData();
|
||||
Global.MovieSession.Movie.LoadLogFromSavestateText(reader, Global.MovieSession.MultiTrack.IsActive);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowError(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowError(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Global.MovieSession.Movie.IsFinished)
|
||||
{
|
||||
if (Global.ReadOnly)
|
||||
{
|
||||
var result = Global.MovieSession.Movie.CheckTimeLines(reader, OnlyGUID: !Global.ReadOnly, IgnoreGuidMismatch: false, ErrorMessage: out ErrorMSG);
|
||||
if (result != Movie.LoadStateResult.Pass)
|
||||
{
|
||||
if (result == Movie.LoadStateResult.GuidMismatch)
|
||||
{
|
||||
var dresult = MessageBox.Show("The savestate GUID does not match the current movie. Proceed anyway?",
|
||||
"GUID Mismatch error",
|
||||
MessageBoxButtons.YesNo, MessageBoxIcon.Question);
|
||||
if (dresult == DialogResult.Yes)
|
||||
{
|
||||
var newresult = Global.MovieSession.Movie.CheckTimeLines(reader, OnlyGUID: !Global.ReadOnly, IgnoreGuidMismatch: true, ErrorMessage: out ErrorMSG);
|
||||
if (newresult == Movie.LoadStateResult.Pass)
|
||||
{
|
||||
Global.MovieSession.Movie.SwitchToPlay();
|
||||
SetMainformMovieInfo();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowError(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowError(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (Global.MovieSession.Movie.IsFinished) //TimeLine check can change a movie to finished, hence the check here (not a good design)
|
||||
{
|
||||
Global.MovieSession.LatchInputFromPlayer(Global.MovieInputSourceAdapter);
|
||||
}
|
||||
else
|
||||
{
|
||||
Global.MovieSession.Movie.SwitchToPlay();
|
||||
SetMainformMovieInfo();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = Global.MovieSession.Movie.CheckTimeLines(reader, OnlyGUID: !Global.ReadOnly, IgnoreGuidMismatch: false, ErrorMessage: out ErrorMSG);
|
||||
if (result == Movie.LoadStateResult.Pass)
|
||||
{
|
||||
GlobalWinF.MainForm.ClearSaveRAM();
|
||||
Global.MovieSession.Movie.StartRecording();
|
||||
SetMainformMovieInfo();
|
||||
reader.BaseStream.Position = 0;
|
||||
reader.DiscardBufferedData();
|
||||
Global.MovieSession.Movie.LoadLogFromSavestateText(reader, Global.MovieSession.MultiTrack.IsActive);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (result == Movie.LoadStateResult.GuidMismatch)
|
||||
{
|
||||
var dresult = MessageBox.Show("The savestate GUID does not match the current movie. Proceed anyway?",
|
||||
"GUID Mismatch error",
|
||||
MessageBoxButtons.YesNo, MessageBoxIcon.Question);
|
||||
if (dresult == DialogResult.Yes)
|
||||
{
|
||||
var newresult = Global.MovieSession.Movie.CheckTimeLines(reader, OnlyGUID: !Global.ReadOnly, IgnoreGuidMismatch: true, ErrorMessage: out ErrorMSG);
|
||||
if (newresult == Movie.LoadStateResult.Pass)
|
||||
{
|
||||
GlobalWinF.MainForm.ClearSaveRAM();
|
||||
Global.MovieSession.Movie.StartRecording();
|
||||
SetMainformMovieInfo();
|
||||
reader.BaseStream.Position = 0;
|
||||
reader.DiscardBufferedData();
|
||||
Global.MovieSession.Movie.LoadLogFromSavestateText(reader, Global.MovieSession.MultiTrack.IsActive);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowError(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowError(ErrorMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void HandleMovieSaveState(StreamWriter writer)
|
||||
{
|
||||
if (Global.MovieSession.Movie.IsActive)
|
||||
{
|
||||
Global.MovieSession.Movie.DumpLogIntoSavestateText(writer);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleMovieOnFrameLoop()
|
||||
{
|
||||
if (!Global.MovieSession.Movie.IsActive)
|
||||
{
|
||||
Global.MovieSession.LatchInputFromPlayer(Global.MovieInputSourceAdapter);
|
||||
}
|
||||
|
||||
else if (Global.MovieSession.Movie.IsFinished)
|
||||
{
|
||||
if (Global.Emulator.Frame < Global.MovieSession.Movie.Frames) //This scenario can happen from rewinding (suddenly we are back in the movie, so hook back up to the movie
|
||||
{
|
||||
Global.MovieSession.Movie.SwitchToPlay();
|
||||
Global.MovieSession.LatchInputFromLog();
|
||||
}
|
||||
else
|
||||
{
|
||||
Global.MovieSession.LatchInputFromPlayer(Global.MovieInputSourceAdapter);
|
||||
}
|
||||
}
|
||||
|
||||
else if (Global.MovieSession.Movie.IsPlaying)
|
||||
{
|
||||
if (Global.Emulator.Frame >= Global.MovieSession.Movie.Frames)
|
||||
{
|
||||
if (TAStudio1.IsHandleCreated && !TAStudio1.IsDisposed)
|
||||
{
|
||||
Global.MovieSession.Movie.CaptureState();
|
||||
Global.MovieSession.LatchInputFromLog();
|
||||
Global.MovieSession.Movie.CommitFrame(Global.Emulator.Frame, Global.MovieOutputHardpoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
Global.MovieSession.Movie.Finish();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Global.MovieSession.Movie.CaptureState();
|
||||
Global.MovieSession.LatchInputFromLog();
|
||||
if (GlobalWinF.ClientControls["ClearFrame"])
|
||||
{
|
||||
Global.MovieSession.LatchInputFromPlayer(Global.MovieInputSourceAdapter);
|
||||
ClearFrame();
|
||||
}
|
||||
else if (TAStudio1.IsHandleCreated && !TAStudio1.IsDisposed || Global.Config.MoviePlaybackPokeMode)
|
||||
{
|
||||
Global.MovieSession.LatchInputFromPlayer(Global.MovieInputSourceAdapter);
|
||||
MnemonicsGenerator mg = new MnemonicsGenerator();
|
||||
mg.SetSource( Global.MovieOutputHardpoint);
|
||||
if (!mg.IsEmpty)
|
||||
{
|
||||
Global.MovieSession.LatchInputFromPlayer(Global.MovieInputSourceAdapter);
|
||||
Global.MovieSession.Movie.PokeFrame(Global.Emulator.Frame, mg.GetControllersAsMnemonic());
|
||||
}
|
||||
else
|
||||
{
|
||||
Global.MovieSession.LatchInputFromLog();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (Global.MovieSession.Movie.IsRecording)
|
||||
{
|
||||
Global.MovieSession.Movie.CaptureState();
|
||||
if (Global.MovieSession.MultiTrack.IsActive)
|
||||
{
|
||||
Global.MovieSession.LatchMultitrackPlayerInput(Global.MovieInputSourceAdapter, Global.MultitrackRewiringControllerAdapter);
|
||||
}
|
||||
else
|
||||
{
|
||||
Global.MovieSession.LatchInputFromPlayer(Global.MovieInputSourceAdapter);
|
||||
}
|
||||
//the movie session makes sure that the correct input has been read and merged to its MovieControllerAdapter;
|
||||
//this has been wired to Global.MovieOutputHardpoint in RewireInputChain
|
||||
Global.MovieSession.Movie.CommitFrame(Global.Emulator.Frame, Global.MovieOutputHardpoint);
|
||||
SetMainformMovieInfo();
|
||||
return Global.MovieSession.HandleMovieLoadState(sr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -181,7 +181,13 @@ namespace BizHawk.MultiClient
|
|||
public MainForm(string[] args)
|
||||
{
|
||||
GlobalWinF.MainForm = this;
|
||||
Global.MovieSession = new MovieSession { Movie = new Movie(GlobalWinF.MainForm.GetEmuVersion()) };
|
||||
Global.MovieSession = new MovieSession
|
||||
{
|
||||
Movie = new Movie(GlobalWinF.MainForm.GetEmuVersion()),
|
||||
ClearSRAMCallback = ClearSaveRAM,
|
||||
MessageCallback = GlobalWinF.OSD.AddMessage,
|
||||
AskYesNoCallback = StateErrorAskUser
|
||||
};
|
||||
MainWait = new AutoResetEvent(false);
|
||||
Icon = Properties.Resources.logo;
|
||||
InitializeComponent();
|
||||
|
@ -189,7 +195,6 @@ namespace BizHawk.MultiClient
|
|||
if (Global.Config.ShowLogWindow)
|
||||
{
|
||||
ShowConsole();
|
||||
//PsxApi.StdioFixes();
|
||||
DisplayLogWindowMenuItem.Checked = true;
|
||||
}
|
||||
|
||||
|
@ -2042,10 +2047,10 @@ namespace BizHawk.MultiClient
|
|||
|
||||
|
||||
case "Toggle read-only": ToggleReadOnly(); break;
|
||||
case "Play Movie": PlayMovie(); break;
|
||||
case "Record Movie": RecordMovie(); break;
|
||||
case "Play Movie": LoadPlayMovieDialog(); break;
|
||||
case "Record Movie": LoadRecordMovieDialog(); break;
|
||||
case "Stop Movie": StopMovie(); break;
|
||||
case "Play from beginning": PlayMovieFromBeginning(); break;
|
||||
case "Play from beginning": RestartMovie(); break;
|
||||
case "Save Movie": SaveMovie(); break;
|
||||
case "Toggle MultiTrack":
|
||||
if (Global.MovieSession.Movie.IsActive)
|
||||
|
@ -2289,7 +2294,7 @@ namespace BizHawk.MultiClient
|
|||
else if (!Global.Config.MuteFrameAdvance)
|
||||
genSound = true;
|
||||
|
||||
HandleMovieOnFrameLoop();
|
||||
Global.MovieSession.HandleMovieOnFrameLoop(GlobalWinF.ClientControls["ClearFrame"]);
|
||||
|
||||
coreskipaudio = GlobalWinF.ClientControls["Turbo"] && CurrAviWriter == null;
|
||||
//=======================================
|
||||
|
@ -2503,7 +2508,7 @@ namespace BizHawk.MultiClient
|
|||
// text mode savestates
|
||||
var writer = new StreamWriter(filename);
|
||||
Global.Emulator.SaveStateText(writer);
|
||||
HandleMovieSaveState(writer);
|
||||
Global.MovieSession.HandleMovieSaveState(writer);
|
||||
if (Global.Config.SaveScreenshotWithStates)
|
||||
{
|
||||
writer.Write("Framebuffer ");
|
||||
|
@ -2545,7 +2550,7 @@ namespace BizHawk.MultiClient
|
|||
StreamWriter sw = new StreamWriter(s);
|
||||
// this never should have been a core's responsibility
|
||||
sw.WriteLine("Frame {0}", Global.Emulator.Frame);
|
||||
HandleMovieSaveState(sw);
|
||||
Global.MovieSession.HandleMovieSaveState(sw);
|
||||
sw.Flush();
|
||||
});
|
||||
}
|
||||
|
@ -2597,7 +2602,8 @@ namespace BizHawk.MultiClient
|
|||
delegate(Stream s)
|
||||
{
|
||||
StreamReader sr = new StreamReader(s);
|
||||
succeed = HandleMovieLoadState(sr);
|
||||
SetMainformMovieInfo();
|
||||
succeed = Global.MovieSession.HandleMovieLoadState(sr);
|
||||
});
|
||||
if (!succeed)
|
||||
goto cleanup;
|
||||
|
@ -3395,7 +3401,7 @@ namespace BizHawk.MultiClient
|
|||
CloseForm(PCEBGViewer1);
|
||||
CloseForm(_cheats);
|
||||
CloseForm(TI83KeyPad1);
|
||||
CloseForm(TAStudio1);
|
||||
CloseForm(TAStudio1); Global.MovieSession.EditorMode = false;
|
||||
CloseForm(TraceLogger1);
|
||||
CloseForm(VirtualPadForm1);
|
||||
#if WINDOWS
|
||||
|
@ -3476,10 +3482,13 @@ namespace BizHawk.MultiClient
|
|||
if (!TAStudio1.IsHandleCreated || TAStudio1.IsDisposed)
|
||||
{
|
||||
TAStudio1 = new TAStudio();
|
||||
Global.MovieSession.EditorMode = true;
|
||||
TAStudio1.Show();
|
||||
}
|
||||
else
|
||||
{
|
||||
TAStudio1.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadVirtualPads()
|
||||
|
@ -4570,5 +4579,16 @@ namespace BizHawk.MultiClient
|
|||
{
|
||||
GlobalWinF.DisplayManager.NeedsToPaint = true;
|
||||
}
|
||||
|
||||
public bool StateErrorAskUser(string title, string message)
|
||||
{
|
||||
var result = MessageBox.Show(message,
|
||||
title,
|
||||
MessageBoxButtons.YesNo,
|
||||
MessageBoxIcon.Question
|
||||
);
|
||||
|
||||
return result == DialogResult.Yes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -356,12 +356,12 @@ namespace BizHawk.MultiClient
|
|||
|
||||
private void newProjectToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
GlobalWinF.MainForm.RecordMovie();
|
||||
GlobalWinF.MainForm.LoadRecordMovieDialog();
|
||||
}
|
||||
|
||||
private void openProjectToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
GlobalWinF.MainForm.PlayMovie();
|
||||
GlobalWinF.MainForm.LoadPlayMovieDialog();
|
||||
}
|
||||
|
||||
private void saveProjectToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
|
|
Loading…
Reference in New Issue