diff --git a/BizHawk.MultiClient/BizHawk.MultiClient.csproj b/BizHawk.MultiClient/BizHawk.MultiClient.csproj index b26418e494..2007dfabff 100644 --- a/BizHawk.MultiClient/BizHawk.MultiClient.csproj +++ b/BizHawk.MultiClient/BizHawk.MultiClient.csproj @@ -179,6 +179,7 @@ + diff --git a/BizHawk.MultiClient/Global.cs b/BizHawk.MultiClient/Global.cs index 565dbe0233..3187e6f8a3 100644 --- a/BizHawk.MultiClient/Global.cs +++ b/BizHawk.MultiClient/Global.cs @@ -22,22 +22,29 @@ namespace BizHawk.MultiClient public static Controller GBControls; public static Controller NullControls; - //TODO should have one of these per movie!!!! should not be global. - public static MovieControllerAdapter MovieControllerAdapter = new MovieControllerAdapter(); + //the movie will be spliced inbetween these if it is present public static CopyControllerAdapter MovieInputSourceAdapter = new CopyControllerAdapter(); + public static CopyControllerAdapter MovieOutputAdapter = new CopyControllerAdapter(); + /// + /// the global MovieSession can use this to deal with multitrack player remapping (should this be here? maybe it should be in MovieSession) + /// public static MultitrackRewiringControllerAdapter MultitrackRewiringControllerAdapter = new MultitrackRewiringControllerAdapter(); + + public static MovieSession MovieSession = new MovieSession(); + + //dont take my word for it, since the final word is actually in RewireInputChain, but here is a guide... //user -> Input -> ActiveController -> UDLR -> StickyXORPlayerInputAdapter -> TurboAdapter(TBD) -> Lua(?TBD?) -> .. - //.. -> MultitrackRewiringControllerAdapter -> MovieInputSourceAdapter -> MovieInputController -> ControllerOutput(1) -> Game + //.. -> MultitrackRewiringControllerAdapter -> MovieInputSourceAdapter -> (MovieSession) -> MovieOutputAdapter -> ControllerOutput(1) -> Game //(1)->Input Display //the original source controller, bound to the user, sort of the "input" port for the chain, i think public static Controller ActiveController; //the "output" port for the controller chain. - public static IController ControllerOutput; + public static CopyControllerAdapter ControllerOutput = new CopyControllerAdapter(); //input state which has been destined for game controller inputs are coalesced here public static InputCoalescer ControllerInputCoalescer = new InputCoalescer(); @@ -56,6 +63,8 @@ namespace BizHawk.MultiClient /// public static ClickyVirtualPadController ClickyVirtualPadController = new ClickyVirtualPadController(); + public static SimpleController MovieOutputController = new SimpleController(); + public static Controller ClientControls; public static string GetOutputControllersAsMnemonic() @@ -68,6 +77,8 @@ namespace BizHawk.MultiClient //TODO - wtf is this being used for public static bool MovieMode; + + public static CoreAccessor PsxCoreLibrary = new CoreAccessor(new Win32LibAccessor("PsxHawk.Core.dll")); } diff --git a/BizHawk.MultiClient/Input/Input.cs b/BizHawk.MultiClient/Input/Input.cs index 2ee1846484..c5f8ac7715 100644 --- a/BizHawk.MultiClient/Input/Input.cs +++ b/BizHawk.MultiClient/Input/Input.cs @@ -164,7 +164,14 @@ namespace BizHawk.MultiClient ModifierKey _Modifiers; List _NewEvents = new List(); - //TODO - maybe need clearevents for various purposes. perhaps when returning from modal dialogs? + //do we need this? + public void ClearEvents() + { + lock (this) + { + InputEvents.Clear(); + } + } Queue InputEvents = new Queue(); public InputEvent DequeueEvent() @@ -211,7 +218,7 @@ namespace BizHawk.MultiClient HandleButton(jname + "B" + (b + 1), pad.Buttons[b]); } - bool swallow = (Global.Config.AcceptBackgroundInput == false && Form.ActiveForm == null); + bool swallow = !Global.MainForm.AllowInput; foreach (var ie in _NewEvents) { diff --git a/BizHawk.MultiClient/MainForm.Movie.cs b/BizHawk.MultiClient/MainForm.Movie.cs index d24e49d594..4a5c99d510 100644 --- a/BizHawk.MultiClient/MainForm.Movie.cs +++ b/BizHawk.MultiClient/MainForm.Movie.cs @@ -15,8 +15,11 @@ namespace BizHawk.MultiClient public void StartNewMovie(Movie m, bool record) { + Global.MovieSession = new MovieSession(); + Global.MovieSession.Movie = m; + UserMovie = m; //TODO - maybe get rid of UserMovie? + RewireInputChain(); - UserMovie = m; LoadRom(Global.MainForm.CurrentlyOpenRom); UserMovie.LoadMovie(); Global.Config.RecentMovies.Add(m.Filename); diff --git a/BizHawk.MultiClient/MainForm.cs b/BizHawk.MultiClient/MainForm.cs index d60aa4fd3d..51733c0353 100644 --- a/BizHawk.MultiClient/MainForm.cs +++ b/BizHawk.MultiClient/MainForm.cs @@ -791,9 +791,16 @@ namespace BizHawk.MultiClient Global.MultitrackRewiringControllerAdapter.Source = Global.StickyXORAdapter; Global.MovieInputSourceAdapter.Source = Global.MultitrackRewiringControllerAdapter; - Global.MovieControllerAdapter.SetSource(Global.MovieInputSourceAdapter); - Global.ControllerOutput = Global.MovieControllerAdapter; + Global.ControllerOutput.Source = Global.MovieOutputAdapter; Global.Emulator.Controller = Global.ControllerOutput; + + Global.MovieSession.MovieControllerAdapter.Type = Global.MovieInputSourceAdapter.Type; + + //splice the movie session before MovieOutputAdapter if it is doing anything + if (Global.MovieSession.Movie != null) + Global.MovieOutputAdapter.Source = Global.MovieSession.MovieControllerAdapter; + else + Global.MovieOutputAdapter.Source = Global.MovieInputSourceAdapter; } public bool LoadRom(string path) @@ -1039,6 +1046,27 @@ namespace BizHawk.MultiClient UpdateStatusSlots(); } + /// + /// Controls whether the app generates input events. should be turned off for most modal dialogs + /// + public bool AllowInput + { + get + { + //the main form gets input + if (Form.ActiveForm == this) return true; + + //modals that need to capture input for binding purposes get input, of course + if (Form.ActiveForm is InputConfig) return true; + if (Form.ActiveForm is tools.HotkeyWindow) return true; + + //if no form is active on this process, then the background input setting applies + if (Form.ActiveForm == null && Global.Config.AcceptBackgroundInput) return true; + + return false; + } + } + public void ProcessInput() { for(;;) @@ -1093,6 +1121,7 @@ namespace BizHawk.MultiClient bool handled = false; if (ie.EventType == Input.InputEventType.Press) { + Console.WriteLine(ie); foreach (var trigger in triggers) { handled |= CheckHotkey(trigger); @@ -1244,52 +1273,52 @@ namespace BizHawk.MultiClient case "Toggle MultiTrack": { - Global.MainForm.UserMovie.MultiTrack.IsActive = !Global.MainForm.UserMovie.MultiTrack.IsActive; - if (Global.MainForm.UserMovie.MultiTrack.IsActive) + Global.MovieSession.MultiTrack.IsActive = !Global.MovieSession.MultiTrack.IsActive; + if (Global.MovieSession.MultiTrack.IsActive) { Global.RenderPanel.AddMessage("MultiTrack Enabled"); Global.RenderPanel.MT = "Recording None"; } else Global.RenderPanel.AddMessage("MultiTrack Disabled"); - Global.MainForm.UserMovie.MultiTrack.RecordAll = false; - Global.MainForm.UserMovie.MultiTrack.CurrentPlayer = 0; + Global.MovieSession.MultiTrack.RecordAll = false; + Global.MovieSession.MultiTrack.CurrentPlayer = 0; break; } case "Increment Player": { - Global.MainForm.UserMovie.MultiTrack.CurrentPlayer++; - Global.MainForm.UserMovie.MultiTrack.RecordAll = false; - if (Global.MainForm.UserMovie.MultiTrack.CurrentPlayer > 5) //TODO: Replace with console's maximum or current maximum players??! + Global.MovieSession.MultiTrack.CurrentPlayer++; + Global.MovieSession.MultiTrack.RecordAll = false; + if (Global.MovieSession.MultiTrack.CurrentPlayer > 5) //TODO: Replace with console's maximum or current maximum players??! { - Global.MainForm.UserMovie.MultiTrack.CurrentPlayer = 1; + Global.MovieSession.MultiTrack.CurrentPlayer = 1; } - Global.RenderPanel.MT = "Recording Player " + Global.MainForm.UserMovie.MultiTrack.CurrentPlayer.ToString(); + Global.RenderPanel.MT = "Recording Player " + Global.MovieSession.MultiTrack.CurrentPlayer.ToString(); break; } case "Decrement Player": { - Global.MainForm.UserMovie.MultiTrack.CurrentPlayer--; - Global.MainForm.UserMovie.MultiTrack.RecordAll = false; - if (Global.MainForm.UserMovie.MultiTrack.CurrentPlayer < 1) + Global.MovieSession.MultiTrack.CurrentPlayer--; + Global.MovieSession.MultiTrack.RecordAll = false; + if (Global.MovieSession.MultiTrack.CurrentPlayer < 1) { - Global.MainForm.UserMovie.MultiTrack.CurrentPlayer = 5;//TODO: Replace with console's maximum or current maximum players??! + Global.MovieSession.MultiTrack.CurrentPlayer = 5;//TODO: Replace with console's maximum or current maximum players??! } - Global.RenderPanel.MT = "Recording Player " + Global.MainForm.UserMovie.MultiTrack.CurrentPlayer.ToString(); + Global.RenderPanel.MT = "Recording Player " + Global.MovieSession.MultiTrack.CurrentPlayer.ToString(); break; } case "Record All": { - Global.MainForm.UserMovie.MultiTrack.CurrentPlayer = 0; - Global.MainForm.UserMovie.MultiTrack.RecordAll = true; + Global.MovieSession.MultiTrack.CurrentPlayer = 0; + Global.MovieSession.MultiTrack.RecordAll = true; Global.RenderPanel.MT = "Recording All"; break; } case "Record None": { - Global.MainForm.UserMovie.MultiTrack.CurrentPlayer = 0; - Global.MainForm.UserMovie.MultiTrack.RecordAll = false; + Global.MovieSession.MultiTrack.CurrentPlayer = 0; + Global.MovieSession.MultiTrack.RecordAll = false; Global.RenderPanel.MT = "Recording None"; break; } @@ -1312,6 +1341,7 @@ namespace BizHawk.MultiClient throttle.Step(true, -1); } + void StepRunLoop_Core() { bool runFrame = false; @@ -1407,27 +1437,35 @@ namespace BizHawk.MultiClient else if (!Global.Config.MuteFrameAdvance) genSound = true; + MovieSession session = Global.MovieSession; + + if (UserMovie.Mode == MOVIEMODE.FINISHED) + { + //todo - a better way of ending + StopMovie(); + } + if (UserMovie.Mode != MOVIEMODE.INACTIVE) { - UserMovie.LatchInputFromLog(); + session.LatchInputFromLog(); } if (UserMovie.Mode == MOVIEMODE.RECORD) { - if (UserMovie.MultiTrack.IsActive) + if (session.MultiTrack.IsActive) { - UserMovie.LatchMultitrackPlayerInput(); + session.LatchMultitrackPlayerInput(Global.MovieInputSourceAdapter, Global.MultitrackRewiringControllerAdapter); } else { - UserMovie.LatchInputFromPlayer(); + session.LatchInputFromPlayer(Global.MovieInputSourceAdapter); } - UserMovie.CommitFrame(); + session.Movie.CommitFrame(Global.Emulator.Frame, Global.MovieInputSourceAdapter); } if (UserMovie.Mode == MOVIEMODE.INACTIVE) { - UserMovie.LatchInputFromPlayer(); + session.LatchInputFromPlayer(Global.MovieInputSourceAdapter); } if (UserMovie.Mode == MOVIEMODE.PLAY) @@ -1439,22 +1477,22 @@ namespace BizHawk.MultiClient } } - if (UserMovie.Mode == MOVIEMODE.FINISHED) - { - if (UserMovie.Length() > Global.Emulator.Frame) - { - UserMovie.StartPlayback(); - Global.MovieControllerAdapter.SetControllersAsMnemonic(UserMovie.GetInputFrame(Global.Emulator.Frame)); - } - } - if (UserMovie.Mode == MOVIEMODE.RECORD && UserMovie.MultiTrack.IsActive) - { - Global.MovieControllerAdapter.SetControllersAsMnemonic(UserMovie.GetInputFrame(Global.Emulator.Frame-1)); - Console.WriteLine("Out: " + UserMovie.GetInputFrame(Global.Emulator.Frame)); - } - //TODO multitrack + //TODO ZERO - I DONT LIKE THIS. INSPECT IT LATER. + //if (UserMovie.Mode == MOVIEMODE.FINISHED) + //{ + // if (UserMovie.Length() > Global.Emulator.Frame) + // { + // UserMovie.StartPlayback(); + // Global.MovieSession.MovieControllerAdapter.SetControllersAsMnemonic(UserMovie.GetInputFrame(Global.Emulator.Frame)); + // } + //} + //if (UserMovie.Mode == MOVIEMODE.RECORD && Global.MovieSession.MultiTrack.IsActive) + //{ + // Global.MovieSession.MovieControllerAdapter.SetControllersAsMnemonic(UserMovie.GetInputFrame(Global.Emulator.Frame-1)); + // Console.WriteLine("Out: " + UserMovie.GetInputFrame(Global.Emulator.Frame)); + //} //======================================= Global.Emulator.FrameAdvance(!throttle.skipnextframe); @@ -1611,7 +1649,8 @@ namespace BizHawk.MultiClient } else { - UserMovie.StartNewRecording(); + //QUESTIONABLE - control whether the movie gets truncated here? + UserMovie.StartNewRecording(!Global.MovieSession.MultiTrack.IsActive); SetMainformMovieInfo(); Global.MovieMode = false; UserMovie.LoadLogFromSavestateText(reader); diff --git a/BizHawk.MultiClient/RenderPanel.cs b/BizHawk.MultiClient/RenderPanel.cs index e11fa77de5..5da225eaad 100644 --- a/BizHawk.MultiClient/RenderPanel.cs +++ b/BizHawk.MultiClient/RenderPanel.cs @@ -351,7 +351,7 @@ namespace BizHawk.MultiClient MessageFont.DrawString(null, input, x + 1, y + 1, Color.Black); MessageFont.DrawString(null, input, x, y, c); } - if (Global.MainForm.UserMovie.MultiTrack.IsActive) + if (Global.MovieSession.MultiTrack.IsActive) { MessageFont.DrawString(null, MT, Global.Config.DispFPSx + 1, //TODO: Multitrack position variables Global.Config.DispFPSy + 1, new Color4(Color.Black)); diff --git a/BizHawk.MultiClient/movie/InputAdapters.cs b/BizHawk.MultiClient/movie/InputAdapters.cs index 1859eb129a..433aa7e90d 100644 --- a/BizHawk.MultiClient/movie/InputAdapters.cs +++ b/BizHawk.MultiClient/movie/InputAdapters.cs @@ -384,25 +384,17 @@ namespace BizHawk.MultiClient //OutputController = new ForceControllerAdapter(); } - IController Source; - - public void SetSource(IController source) - { - //OutputController.Controller = source; - Source = source; - } - //IController implementation: - public ControllerDefinition Type { get { return Source.Type; } } + public ControllerDefinition Type { get; set; } public bool this[string button] { get { return MyBoolButtons[button]; } } public bool IsPressed(string button) { return MyBoolButtons[button]; } - public float GetFloat(string name) { return Source.GetFloat(name); } - public void UpdateControls(int frame) { Source.UpdateControls(frame); } + public float GetFloat(string name) { return 0; } + public void UpdateControls(int frame) { } //-------- - Dictionary MyBoolButtons = new Dictionary(); + WorkingDictionary MyBoolButtons = new WorkingDictionary(); - void Force(string button, bool state) + void Force(string button, bool state) { MyBoolButtons[button] = state; } @@ -426,29 +418,31 @@ namespace BizHawk.MultiClient /// /// latches one player from the source /// - public void LatchPlayerFromSource(int playerNum) + public void LatchPlayerFromSource(IController playerSource, int playerNum) { - foreach (string button in Source.Type.BoolButtons) + foreach (string button in playerSource.Type.BoolButtons) { ButtonNameParser bnp = ButtonNameParser.Parse(button); if (bnp == null) continue; if (bnp.PlayerNum != playerNum) continue; - bool val = Source[button]; + bool val = playerSource[button]; MyBoolButtons[button] = val; } } + /// - /// latches all buttons from the upstream source + /// latches all buttons from the provided source /// - public void LatchFromSource() + public void LatchFromSource(IController source) { foreach (string button in Type.BoolButtons) { - MyBoolButtons[button] = Source[button]; + MyBoolButtons[button] = source[button]; } } + /// /// latches all buttons from the supplied mnemonic string /// diff --git a/BizHawk.MultiClient/movie/Movie.cs b/BizHawk.MultiClient/movie/Movie.cs index e18b08b507..c777603553 100644 --- a/BizHawk.MultiClient/movie/Movie.cs +++ b/BizHawk.MultiClient/movie/Movie.cs @@ -14,7 +14,6 @@ namespace BizHawk.MultiClient public MovieHeader Header = new MovieHeader(); public SubtitleList Subtitles = new SubtitleList(); - public MultitrackRecording MultiTrack = new MultitrackRecording(); public bool MakeBackup = true; //make backup before altering movie public bool IsText { get; private set; } @@ -91,7 +90,8 @@ namespace BizHawk.MultiClient Mode = MOVIEMODE.INACTIVE; } - public void StartNewRecording() + public void StartNewRecording() { StartNewRecording(true); } + public void StartNewRecording(bool truncate) { Mode = MOVIEMODE.RECORD; if (Global.Config.EnableBackupMovies && MakeBackup && Log.Length() > 0) @@ -99,7 +99,7 @@ namespace BizHawk.MultiClient WriteBackup(); MakeBackup = false; } - Log.Clear(); + if(truncate) Log.Clear(); } public void StartPlayback() @@ -107,55 +107,21 @@ namespace BizHawk.MultiClient Mode = MOVIEMODE.PLAY; } - public void LatchMultitrackPlayerInput() + public void CommitFrame(int frameNum, IController source) { - if (MultiTrack.IsActive) - { - Global.MultitrackRewiringControllerAdapter.PlayerSource = 1; - Global.MultitrackRewiringControllerAdapter.PlayerTargetMask = 1 << (MultiTrack.CurrentPlayer); - if (MultiTrack.RecordAll) Global.MultitrackRewiringControllerAdapter.PlayerTargetMask = unchecked((int)0xFFFFFFFF); - } - else Global.MultitrackRewiringControllerAdapter.PlayerSource = -1; - - if (MultiTrack.RecordAll) - Global.MovieControllerAdapter.LatchFromSource(); - else - Global.MovieControllerAdapter.LatchPlayerFromSource(MultiTrack.CurrentPlayer); - } - - public void LatchInputFromPlayer() - { - Global.MovieControllerAdapter.LatchFromSource(); - } - - /// - /// latch input from the log, if available - /// - public void LatchInputFromLog() - { - string loggedFrame = GetInputFrame(Global.Emulator.Frame); - if(loggedFrame != "") - Global.MovieControllerAdapter.SetControllersAsMnemonic(loggedFrame); - } - - public void CommitFrame() - { - //if (MultiTrack.IsActive) + //if (Global.Emulator.Frame < Log.Length()) //{ + // Log.Truncate(Global.Emulator.Frame); //} - //else - // if (Global.Emulator.Frame < Log.Length()) - // { - // Log.Truncate(Global.Emulator.Frame); - // } //Note: Truncation here instead of loadstate will make VBA style loadstates //(Where an entire movie is loaded then truncated on the next frame //this allows users to restore a movie with any savestate from that "timeline" MnemonicsGenerator mg = new MnemonicsGenerator(); - mg.SetSource(Global.MovieInputSourceAdapter); - Log.SetFrameAt(Global.Emulator.Frame, mg.GetControllersAsMnemonic()); + + mg.SetSource(source); + Log.SetFrameAt(frameNum, mg.GetControllersAsMnemonic()); } public string GetInputFrame(int frame) @@ -420,7 +386,7 @@ namespace BizHawk.MultiClient public void LoadLogFromSavestateText(TextReader reader) { //We are in record mode so replace the movie log with the one from the savestate - if (!MultiTrack.IsActive) + if (!Global.MovieSession.MultiTrack.IsActive) { if (Global.Config.EnableBackupMovies && MakeBackup && Log.Length() > 0) { diff --git a/BizHawk.MultiClient/movie/MovieSession.cs b/BizHawk.MultiClient/movie/MovieSession.cs new file mode 100644 index 0000000000..29051a10b9 --- /dev/null +++ b/BizHawk.MultiClient/movie/MovieSession.cs @@ -0,0 +1,54 @@ +using System; +using System.Text; +using System.Threading; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using BizHawk.Core; +using BizHawk.Emulation.Consoles.Sega; +using BizHawk.Emulation.Consoles.TurboGrafx; +using BizHawk.Emulation.Consoles.Calculator; +using BizHawk.Emulation.Consoles.Gameboy; +using BizHawk.Emulation.Consoles.Nintendo; + +namespace BizHawk.MultiClient +{ + + public class MovieSession + { + public MultitrackRecording MultiTrack = new MultitrackRecording(); + public Movie Movie; + public MovieControllerAdapter MovieControllerAdapter = new MovieControllerAdapter(); + + public void LatchMultitrackPlayerInput(IController playerSource, MultitrackRewiringControllerAdapter rewiredSource) + { + if (MultiTrack.IsActive) + { + rewiredSource.PlayerSource = 1; + rewiredSource.PlayerTargetMask = 1 << (MultiTrack.CurrentPlayer); + if (MultiTrack.RecordAll) rewiredSource.PlayerTargetMask = unchecked((int)0xFFFFFFFF); + } + else rewiredSource.PlayerSource = -1; + + MovieControllerAdapter.LatchPlayerFromSource(rewiredSource, MultiTrack.CurrentPlayer); + } + + public void LatchInputFromPlayer(IController source) + { + MovieControllerAdapter.LatchFromSource(source); + } + + /// + /// latch input from the input log, if available + /// + public void LatchInputFromLog() + { + string loggedFrame = Movie.GetInputFrame(Global.Emulator.Frame); + if (loggedFrame != "") + MovieControllerAdapter.SetControllersAsMnemonic(loggedFrame); + } + } + +} \ No newline at end of file