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:
adelikat 2013-11-01 18:52:26 +00:00
parent 380fc781e3
commit 3cda83c2bc
5 changed files with 489 additions and 453 deletions

View File

@ -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;
}
}

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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)