diff --git a/Core/HistoryViewer.cpp b/Core/HistoryViewer.cpp index b64cfedb..087f2d58 100644 --- a/Core/HistoryViewer.cpp +++ b/Core/HistoryViewer.cpp @@ -7,6 +7,7 @@ #include "NotificationManager.h" #include "RomData.h" #include "MovieRecorder.h" +#include "SaveStateManager.h" HistoryViewer::HistoryViewer(shared_ptr console) { @@ -80,6 +81,23 @@ void HistoryViewer::SeekTo(uint32_t seekPosition) } } +bool HistoryViewer::CreateSaveState(string outputFile, uint32_t position) +{ + if(position < _history.size()) { + std::stringstream stateData; + _console->GetSaveStateManager()->GetSaveStateHeader(stateData); + _history[position].GetStateData(stateData); + + ofstream output(outputFile, ios::binary); + if(output) { + output << stateData.rdbuf(); + output.close(); + return true; + } + } + return false; +} + bool HistoryViewer::SaveMovie(string movieFile, uint32_t startPosition, uint32_t endPosition) { //Take a savestate to be able to restore it after generating the movie file diff --git a/Core/HistoryViewer.h b/Core/HistoryViewer.h index 2c91eb4c..f6d1139e 100644 --- a/Core/HistoryViewer.h +++ b/Core/HistoryViewer.h @@ -27,6 +27,7 @@ public: uint32_t GetPosition(); void SeekTo(uint32_t seekPosition); + bool CreateSaveState(string outputFile, uint32_t position); bool SaveMovie(string movieFile, uint32_t startPosition, uint32_t endPosition); void ResumeGameplay(shared_ptr console, uint32_t resumePosition); diff --git a/GUI.NET/Dependencies/resources.ca.xml b/GUI.NET/Dependencies/resources.ca.xml index 43a44d09..29493132 100644 --- a/GUI.NET/Dependencies/resources.ca.xml +++ b/GUI.NET/Dependencies/resources.ca.xml @@ -607,6 +607,7 @@ File Import Movie Export Movie + Create Save State Resume Gameplay Close @@ -734,6 +735,7 @@ Segment #{0} An error occurred while trying to save the movie file. + An error occurred while trying to save the file. Esborra el registre Darrera carpeta utilitzada diff --git a/GUI.NET/Dependencies/resources.en.xml b/GUI.NET/Dependencies/resources.en.xml index 46dc3c82..cbcfe72b 100644 --- a/GUI.NET/Dependencies/resources.en.xml +++ b/GUI.NET/Dependencies/resources.en.xml @@ -617,6 +617,7 @@ File Import Movie Export Movie + Create Save State Resume Gameplay Close @@ -764,6 +765,7 @@ Segment #{0} An error occurred while trying to save the movie file. + An error occurred while trying to save the file. Clear History Last Folder Used diff --git a/GUI.NET/Dependencies/resources.es.xml b/GUI.NET/Dependencies/resources.es.xml index 21a13f4b..5221bea3 100644 --- a/GUI.NET/Dependencies/resources.es.xml +++ b/GUI.NET/Dependencies/resources.es.xml @@ -605,6 +605,7 @@ Archivo Importar película Exportar película + Create Save State Continuar el juego Cerrar @@ -751,6 +752,7 @@ Parte #{0} Se produjo un error al intentar guardar el archivo de película. + An error occurred while trying to save the file. Limpiar historial Última carpeta usada diff --git a/GUI.NET/Dependencies/resources.fr.xml b/GUI.NET/Dependencies/resources.fr.xml index 07a8b722..bf7c95f2 100644 --- a/GUI.NET/Dependencies/resources.fr.xml +++ b/GUI.NET/Dependencies/resources.fr.xml @@ -617,6 +617,7 @@ Fichier Importer un film Exporter un film + Créer une sauvegarde d'état Reprendre le jeu Fermer @@ -764,6 +765,7 @@ Segment #{0} Une erreur est survenue pendant la sauvegarde du film. + Une erreur est survenue pendant la sauvegarde du fichier. Effacer l'historique Dernier dossier utilisé diff --git a/GUI.NET/Dependencies/resources.ja.xml b/GUI.NET/Dependencies/resources.ja.xml index 9606a07c..e501c347 100644 --- a/GUI.NET/Dependencies/resources.ja.xml +++ b/GUI.NET/Dependencies/resources.ja.xml @@ -607,6 +607,7 @@ ファイル 動画をインポートする 動画をエクスポートする + クイックセーブを作る ここからゲームを再開する 終了 @@ -754,6 +755,7 @@ パート {0} 動画エクスポートは失敗しました。 + ファイルの保存に失敗しました。 履歴を消去 最後に使用したフォルダ diff --git a/GUI.NET/Dependencies/resources.pt.xml b/GUI.NET/Dependencies/resources.pt.xml index e7e888d3..98613630 100644 --- a/GUI.NET/Dependencies/resources.pt.xml +++ b/GUI.NET/Dependencies/resources.pt.xml @@ -617,6 +617,7 @@ Arquivo Importar vídeo Exportar vídeo + Create Save State Continuar jogo Fechar @@ -764,7 +765,8 @@ Segmento #{0} Ocorreu um erro ao tentar salvar o vídeo. - + An error occurred while trying to save the file. + Limpar histórico Última pasta usada diff --git a/GUI.NET/Dependencies/resources.ru.xml b/GUI.NET/Dependencies/resources.ru.xml index 55337d0b..313587d1 100644 --- a/GUI.NET/Dependencies/resources.ru.xml +++ b/GUI.NET/Dependencies/resources.ru.xml @@ -605,6 +605,7 @@ File Import Movie Export Movie + Create Save State Resume Gameplay Close @@ -752,6 +753,7 @@ Segment #{0} An error occurred while trying to save the movie file. + An error occurred while trying to save the file. Clear History Last Folder Used diff --git a/GUI.NET/Dependencies/resources.uk.xml b/GUI.NET/Dependencies/resources.uk.xml index e7560d9c..2f3b11a6 100644 --- a/GUI.NET/Dependencies/resources.uk.xml +++ b/GUI.NET/Dependencies/resources.uk.xml @@ -605,6 +605,7 @@ Файл Імпортувати відео Експортувати вiдео + Create Save State Відновити геймплей Закрити @@ -752,6 +753,7 @@ Сегмент #{0} Сталася помилка під час спроби зберегти відео файл. + An error occurred while trying to save the file. Очистити історію Використовувана остання папка diff --git a/GUI.NET/Dependencies/resources.zh.xml b/GUI.NET/Dependencies/resources.zh.xml index 7ed81976..4f54141d 100644 --- a/GUI.NET/Dependencies/resources.zh.xml +++ b/GUI.NET/Dependencies/resources.zh.xml @@ -609,6 +609,7 @@ 文件 导入影片 导出影片 + Create Save State 继续播放 关闭 @@ -755,6 +756,8 @@ 保存到文件... 第 #{0} 段 尝试保存电影文件时发生错误. + An error occurred while trying to save the file. + 清除历史 上次使用的文件夹 diff --git a/GUI.NET/Forms/frmHistoryViewer.Designer.cs b/GUI.NET/Forms/frmHistoryViewer.Designer.cs index 5897b4bb..dfe9e976 100644 --- a/GUI.NET/Forms/frmHistoryViewer.Designer.cs +++ b/GUI.NET/Forms/frmHistoryViewer.Designer.cs @@ -33,6 +33,7 @@ this.btnPausePlay = new System.Windows.Forms.Button(); this.lblPosition = new System.Windows.Forms.Label(); this.pnlRenderer = new System.Windows.Forms.Panel(); + this.picNsfIcon = new System.Windows.Forms.PictureBox(); this.tlpRenderer = new System.Windows.Forms.TableLayoutPanel(); this.ctrlRenderer = new System.Windows.Forms.Panel(); this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); @@ -44,18 +45,18 @@ this.mnuImportMovie = new System.Windows.Forms.ToolStripMenuItem(); this.mnuExportMovie = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator(); + this.mnuCreateSaveState = new System.Windows.Forms.ToolStripMenuItem(); this.mnuResumeGameplay = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator(); this.mnuClose = new System.Windows.Forms.ToolStripMenuItem(); - this.picNsfIcon = new System.Windows.Forms.PictureBox(); this.tableLayoutPanel1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.trkPosition)).BeginInit(); this.pnlRenderer.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.picNsfIcon)).BeginInit(); this.tlpRenderer.SuspendLayout(); this.tableLayoutPanel3.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.trkVolume)).BeginInit(); this.menuStrip2.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.picNsfIcon)).BeginInit(); this.SuspendLayout(); // // tableLayoutPanel1 @@ -126,6 +127,19 @@ this.pnlRenderer.Size = new System.Drawing.Size(551, 397); this.pnlRenderer.TabIndex = 0; // + // picNsfIcon + // + this.picNsfIcon.Anchor = System.Windows.Forms.AnchorStyles.None; + this.picNsfIcon.BackgroundImage = global::Mesen.GUI.Properties.Resources.NsfBackground; + this.picNsfIcon.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + this.picNsfIcon.Location = new System.Drawing.Point(199, 152); + this.picNsfIcon.Margin = new System.Windows.Forms.Padding(0); + this.picNsfIcon.MaximumSize = new System.Drawing.Size(500, 90); + this.picNsfIcon.Name = "picNsfIcon"; + this.picNsfIcon.Size = new System.Drawing.Size(150, 90); + this.picNsfIcon.TabIndex = 6; + this.picNsfIcon.TabStop = false; + // // tlpRenderer // this.tlpRenderer.ColumnCount = 1; @@ -212,13 +226,14 @@ this.mnuImportMovie, this.mnuExportMovie, this.toolStripMenuItem1, + this.mnuCreateSaveState, this.mnuResumeGameplay, this.toolStripMenuItem2, this.mnuClose}); this.mnuFile.Name = "mnuFile"; this.mnuFile.Size = new System.Drawing.Size(37, 20); this.mnuFile.Text = "File"; - this.mnuFile.DropDownOpening += new System.EventHandler(this.fileToolStripMenuItem_DropDownOpening); + this.mnuFile.DropDownOpening += new System.EventHandler(this.mnuFile_DropDownOpening); // // mnuImportMovie // @@ -239,6 +254,14 @@ this.toolStripMenuItem1.Name = "toolStripMenuItem1"; this.toolStripMenuItem1.Size = new System.Drawing.Size(168, 6); // + // mnuCreateSaveState + // + this.mnuCreateSaveState.Image = global::Mesen.GUI.Properties.Resources.Floppy; + this.mnuCreateSaveState.Name = "mnuCreateSaveState"; + this.mnuCreateSaveState.Size = new System.Drawing.Size(171, 22); + this.mnuCreateSaveState.Text = "Create Save State"; + this.mnuCreateSaveState.Click += new System.EventHandler(this.mnuCreateSaveState_Click); + // // mnuResumeGameplay // this.mnuResumeGameplay.Image = global::Mesen.GUI.Properties.Resources.Play; @@ -260,19 +283,6 @@ this.mnuClose.Text = "Close"; this.mnuClose.Click += new System.EventHandler(this.mnuClose_Click); // - // picNsfIcon - // - this.picNsfIcon.Anchor = System.Windows.Forms.AnchorStyles.None; - this.picNsfIcon.BackgroundImage = global::Mesen.GUI.Properties.Resources.NsfBackground; - this.picNsfIcon.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; - this.picNsfIcon.Location = new System.Drawing.Point(199, 152); - this.picNsfIcon.Margin = new System.Windows.Forms.Padding(0); - this.picNsfIcon.MaximumSize = new System.Drawing.Size(500, 90); - this.picNsfIcon.Name = "picNsfIcon"; - this.picNsfIcon.Size = new System.Drawing.Size(150, 90); - this.picNsfIcon.TabIndex = 6; - this.picNsfIcon.TabStop = false; - // // frmHistoryViewer // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -287,13 +297,13 @@ this.tableLayoutPanel1.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.trkPosition)).EndInit(); this.pnlRenderer.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.picNsfIcon)).EndInit(); this.tlpRenderer.ResumeLayout(false); this.tableLayoutPanel3.ResumeLayout(false); this.tableLayoutPanel3.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.trkVolume)).EndInit(); this.menuStrip2.ResumeLayout(false); this.menuStrip2.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.picNsfIcon)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -321,5 +331,6 @@ private System.Windows.Forms.Label lblVolume; private System.Windows.Forms.TrackBar trkVolume; private System.Windows.Forms.PictureBox picNsfIcon; + private System.Windows.Forms.ToolStripMenuItem mnuCreateSaveState; } } \ No newline at end of file diff --git a/GUI.NET/Forms/frmHistoryViewer.cs b/GUI.NET/Forms/frmHistoryViewer.cs index c4c7c6e2..d268c4c7 100644 --- a/GUI.NET/Forms/frmHistoryViewer.cs +++ b/GUI.NET/Forms/frmHistoryViewer.cs @@ -167,7 +167,7 @@ namespace Mesen.GUI.Forms InteropEmu.HistoryViewerResumeGameplay(InteropEmu.HistoryViewerGetPosition()); } - private void fileToolStripMenuItem_DropDownOpening(object sender, EventArgs e) + private void mnuFile_DropDownOpening(object sender, EventArgs e) { mnuExportMovie.DropDownItems.Clear(); @@ -186,13 +186,14 @@ namespace Mesen.GUI.Forms string segmentName = ResourceHelper.GetMessage("MovieSegment", (mnuExportMovie.DropDownItems.Count + 1).ToString()); ToolStripMenuItem item = new ToolStripMenuItem(segmentName + ", " + start.ToString() + " - " + end.ToString()); item.Click += (s, evt) => { - SaveFileDialog sfd = new SaveFileDialog(); - sfd.SetFilter(ResourceHelper.GetMessage("FilterMovie")); - sfd.InitialDirectory = ConfigManager.MovieFolder; - sfd.FileName = InteropEmu.GetRomInfo().GetRomName() + ".mmo"; - if(sfd.ShowDialog() == DialogResult.OK) { - if(!InteropEmu.HistoryViewerSaveMovie(sfd.FileName, segStart, segEnd)) { - MesenMsgBox.Show("MovieSaveError", MessageBoxButtons.OK, MessageBoxIcon.Error); + using(SaveFileDialog sfd = new SaveFileDialog()) { + sfd.SetFilter(ResourceHelper.GetMessage("FilterMovie")); + sfd.InitialDirectory = ConfigManager.MovieFolder; + sfd.FileName = InteropEmu.GetRomInfo().GetRomName() + ".mmo"; + if(sfd.ShowDialog() == DialogResult.OK) { + if(!InteropEmu.HistoryViewerSaveMovie(sfd.FileName, segStart, segEnd)) { + MesenMsgBox.Show("MovieSaveError", MessageBoxButtons.OK, MessageBoxIcon.Error); + } } } }; @@ -204,6 +205,20 @@ namespace Mesen.GUI.Forms mnuImportMovie.Visible = false; mnuExportMovie.Enabled = mnuExportMovie.HasDropDownItems && !_isNsf; } + + private void mnuCreateSaveState_Click(object sender, EventArgs e) + { + using(SaveFileDialog sfd = new SaveFileDialog()) { + sfd.SetFilter(ResourceHelper.GetMessage("FilterSavestate")); + sfd.InitialDirectory = ConfigManager.SaveStateFolder; + sfd.FileName = InteropEmu.GetRomInfo().GetRomName() + ".mst"; + if(sfd.ShowDialog() == DialogResult.OK) { + if(!InteropEmu.HistoryViewerCreateSaveState(sfd.FileName, InteropEmu.HistoryViewerGetPosition())) { + MesenMsgBox.Show("FileSaveError", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } + } private void btnPausePlay_Click(object sender, EventArgs e) { diff --git a/GUI.NET/InteropEmu.cs b/GUI.NET/InteropEmu.cs index 3a6d5d19..1481fab5 100644 --- a/GUI.NET/InteropEmu.cs +++ b/GUI.NET/InteropEmu.cs @@ -33,6 +33,7 @@ namespace Mesen.GUI [DllImport(DLLPath)] public static extern void HistoryViewerStop(); [DllImport(DLLPath)] public static extern UInt32 HistoryViewerGetHistoryLength(); [DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool HistoryViewerSaveMovie([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string movieFile, UInt32 startPosition, UInt32 endPosition); + [DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool HistoryViewerCreateSaveState([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string outfileFile, UInt32 position); [DllImport(DLLPath)] public static extern void HistoryViewerSetPosition(UInt32 seekPosition); [DllImport(DLLPath)] public static extern void HistoryViewerResumeGameplay(UInt32 seekPosition); [DllImport(DLLPath)] public static extern UInt32 HistoryViewerGetPosition(); diff --git a/InteropDLL/ConsoleWrapper.cpp b/InteropDLL/ConsoleWrapper.cpp index 1d904324..91ab4b79 100644 --- a/InteropDLL/ConsoleWrapper.cpp +++ b/InteropDLL/ConsoleWrapper.cpp @@ -250,6 +250,14 @@ namespace InteropEmu { } } + DllExport bool __stdcall HistoryViewerCreateSaveState(const char* outputFile, uint32_t position) + { + if(_historyConsole) { + return _historyConsole->GetHistoryViewer()->CreateSaveState(outputFile, position); + } + return false; + } + DllExport bool __stdcall HistoryViewerSaveMovie(const char* movieFile, uint32_t startPosition, uint32_t endPosition) { if(_historyConsole) {