From 3cda83c2bc24fca403930a708ff18dfc8713c5d9 Mon Sep 17 00:00:00 2001 From: adelikat <adelikat@tasvideos.org> Date: Fri, 1 Nov 2013 18:52:26 +0000 Subject: [PATCH] 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 --- BizHawk.Client.Common/movie/MovieSession.cs | 441 ++++++++++++++++++- BizHawk.MultiClient/MainForm.Events.cs | 6 +- BizHawk.MultiClient/MainForm.Movie.cs | 451 +------------------- BizHawk.MultiClient/MainForm.cs | 40 +- BizHawk.MultiClient/tools/TAStudio.cs | 4 +- 5 files changed, 489 insertions(+), 453 deletions(-) diff --git a/BizHawk.Client.Common/movie/MovieSession.cs b/BizHawk.Client.Common/movie/MovieSession.cs index 83695879ca..6ff8a3c138 100644 --- a/BizHawk.Client.Common/movie/MovieSession.cs +++ b/BizHawk.Client.Common/movie/MovieSession.cs @@ -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; } } diff --git a/BizHawk.MultiClient/MainForm.Events.cs b/BizHawk.MultiClient/MainForm.Events.cs index 4c2a9bc788..0a32af3780 100644 --- a/BizHawk.MultiClient/MainForm.Events.cs +++ b/BizHawk.MultiClient/MainForm.Events.cs @@ -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) diff --git a/BizHawk.MultiClient/MainForm.Movie.cs b/BizHawk.MultiClient/MainForm.Movie.cs index 3af297fb6d..32475efa0e 100644 --- a/BizHawk.MultiClient/MainForm.Movie.cs +++ b/BizHawk.MultiClient/MainForm.Movie.cs @@ -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); } } diff --git a/BizHawk.MultiClient/MainForm.cs b/BizHawk.MultiClient/MainForm.cs index b5cdd94a3e..389e6f0272 100644 --- a/BizHawk.MultiClient/MainForm.cs +++ b/BizHawk.MultiClient/MainForm.cs @@ -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; + } } } diff --git a/BizHawk.MultiClient/tools/TAStudio.cs b/BizHawk.MultiClient/tools/TAStudio.cs index 4025279a56..9638c845cf 100644 --- a/BizHawk.MultiClient/tools/TAStudio.cs +++ b/BizHawk.MultiClient/tools/TAStudio.cs @@ -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)