From e3b719712858dd8b596052689777d8d936923b48 Mon Sep 17 00:00:00 2001 From: zeromus Date: Mon, 18 Jun 2018 22:19:59 -0500 Subject: [PATCH] add "record from sram" (to fix SF bug #828) --- src/cart.cpp | 2 + src/cart.h | 2 + src/drivers/win/replay.cpp | 8 ++-- src/ines.cpp | 1 + src/movie.cpp | 92 ++++++++++++++++++++++++++++++++++++-- src/movie.h | 10 ++++- src/unif.cpp | 1 + 7 files changed, 107 insertions(+), 9 deletions(-) diff --git a/src/cart.cpp b/src/cart.cpp index baeaba65..4646eabd 100644 --- a/src/cart.cpp +++ b/src/cart.cpp @@ -76,6 +76,8 @@ uint8 geniech[3]; uint32 genieaddr[3]; +CartInfo *currCartInfo; + static INLINE void setpageptr(int s, uint32 A, uint8 *p, int ram) { uint32 AB = A >> 11; int x; diff --git a/src/cart.h b/src/cart.h index 9d3b0b89..249e0c56 100644 --- a/src/cart.h +++ b/src/cart.h @@ -25,6 +25,8 @@ typedef struct { // other code in the future. } CartInfo; +extern CartInfo *currCartInfo; + void FCEU_SaveGameSave(CartInfo *LocalHWInfo); void FCEU_LoadGameSave(CartInfo *LocalHWInfo); void FCEU_ClearGameSave(CartInfo *LocalHWInfo); diff --git a/src/drivers/win/replay.cpp b/src/drivers/win/replay.cpp index bbdfce30..ca998dcf 100644 --- a/src/drivers/win/replay.cpp +++ b/src/drivers/win/replay.cpp @@ -851,6 +851,7 @@ static BOOL CALLBACK RecordDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LP SendDlgItemMessage(hwndDlg, IDC_COMBO_RECORDFROM, CB_INSERTSTRING, i++, (LPARAM)"Start"); SendDlgItemMessage(hwndDlg, IDC_COMBO_RECORDFROM, CB_INSERTSTRING, i++, (LPARAM)"Now"); + SendDlgItemMessage(hwndDlg, IDC_COMBO_RECORDFROM, CB_INSERTSTRING, i++, (LPARAM)"SaveRam"); memset(&wfd, 0, sizeof(wfd)); hFind = FindFirstFile(findGlob, &wfd); @@ -941,7 +942,7 @@ static BOOL CALLBACK RecordDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LP // convert Unicode wstring to UTF8 char* string WideCharToMultiByte(CP_UTF8, 0, (p->authorName).c_str(), -1, taseditorConfig.lastAuthorName, AUTHOR_NAME_MAX_LEN, 0, 0); - if (lIndex >= 2) + if (lIndex >= 3) p->szSavestateFilename = GetSavePath(hwndDlg); EndDialog(hwndDlg, 1); } @@ -983,11 +984,11 @@ void FCEUD_MovieRecordTo() if (!GameInfo) return; static struct CreateMovieParameters p; p.szFilename = strdup(FCEU_MakeFName(FCEUMKF_MOVIE,0,0).c_str()); - if(p.recordFrom >= 2) p.recordFrom=1; + if(p.recordFrom >= 3) p.recordFrom=1; if(DialogBoxParam(fceu_hInstance, "IDD_RECORDINP", hAppWnd, RecordDialogProc, (LPARAM)&p)) { - if(p.recordFrom >= 2) + if(p.recordFrom >= 3) { // attempt to load the savestate // FIXME: pop open a messagebox if this fails @@ -1006,6 +1007,7 @@ void FCEUD_MovieRecordTo() EMOVIE_FLAG flags = MOVIE_FLAG_NONE; if(p.recordFrom == 0) flags = MOVIE_FLAG_FROM_POWERON; + if(p.recordFrom == 2) flags = MOVIE_FLAG_FROM_SAVERAM; FCEUI_SaveMovie(p.szFilename.c_str(), flags, p.authorName); } } diff --git a/src/ines.cpp b/src/ines.cpp index 11d94e1e..d95a18f3 100644 --- a/src/ines.cpp +++ b/src/ines.cpp @@ -907,6 +907,7 @@ int iNESLoad(const char *name, FCEUFILE *fp, int OverwriteVidMode) { } GameInterface = iNESGI; + currCartInfo = &iNESCart; FCEU_printf("\n"); // since apparently the iNES format doesn't store this information, diff --git a/src/movie.cpp b/src/movie.cpp index 76be97b7..18b325bd 100644 --- a/src/movie.cpp +++ b/src/movie.cpp @@ -11,6 +11,7 @@ #include "file.h" #include "video.h" #include "movie.h" +#include "cart.h" #include "fds.h" #include "vsuni.h" #ifdef _S9XLUA_H @@ -461,6 +462,16 @@ void MovieData::installValue(std::string& key, std::string& val) StringToBytes(val,&savestate[0],len); // decodes either base64 or hex } } + else if(key == "saveram") + { + int len = Base64StringToBytesLength(val); + if(len == -1) len = HexStringToBytesLength(val); // wasn't base64, try hex + if(len >= 1) + { + saveram.resize(len); + StringToBytes(val,&saveram[0],len); // decodes either base64 or hex + } + } else if (key == "length") { installInt(val, loadFrameCount); @@ -499,6 +510,9 @@ int MovieData::dump(EMUFILE *os, bool binary) if(savestate.size()) os->fprintf("savestate %s\n" , BytesToString(&savestate[0],savestate.size()).c_str() ); + if(saveram.size()) + os->fprintf("saveram %s\n" , BytesToString(&saveram[0],saveram.size()).c_str() ); + if (this->loadFrameCount >= 0) os->fprintf("length %d\n" , this->loadFrameCount); @@ -778,6 +792,8 @@ void FCEUI_StopMovie() #endif } +bool bogorf; + void poweron(bool shouldDisableBatteryLoading) { //// make a for-movie-recording power-on clear the game's save data, too @@ -802,9 +818,9 @@ void poweron(bool shouldDisableBatteryLoading) //suppressAddPowerCommand=0; extern int disableBatteryLoading; - disableBatteryLoading = 1; + if(!bogorf) disableBatteryLoading = 1; PowerNES(); - disableBatteryLoading = 0; + if(!bogorf) disableBatteryLoading = 0; } void FCEUMOV_CreateCleanMovie() @@ -846,6 +862,59 @@ void MovieData::dumpSavestateTo(std::vector* buf, int compressionLevel) ms.trim(); } +bool MovieData::loadSaveramFrom(std::vector* buf) +{ + EMUFILE_MEMORY ms(buf); + + bool hasBattery = !!ms.read32le(); + if(hasBattery != !!currCartInfo->battery) + { + FCEU_PrintError("movie battery load mismatch 1"); + return false; + } + + for(int i=0;i<4;i++) + { + int len = ms.read32le(); + + if(!currCartInfo->SaveGame[i] && len!=0) + { + FCEU_PrintError("movie battery load mismatch 2"); + return false; + } + + if(currCartInfo->SaveGameLen[i] != len) + { + FCEU_PrintError("movie battery load mismatch 3"); + return false; + } + + ms.fread(currCartInfo->SaveGame[i], len); + } + + return true; +} + +void MovieData::dumpSaveramTo(std::vector* buf, int compressionLevel) +{ + EMUFILE_MEMORY ms(buf); + + ms.write32le(currCartInfo->battery?1:0); + for(int i=0;i<4;i++) + { + if(!currCartInfo->SaveGame[i]) + { + ms.write32le((u32)0); + continue; + } + + ms.write32le(currCartInfo->SaveGameLen[i]); + ms.fwrite(currCartInfo->SaveGame[i], currCartInfo->SaveGameLen[i]); + } + +} + + //begin playing an existing movie bool FCEUI_LoadMovie(const char *fname, bool _read_only, int _pauseframe) { @@ -901,7 +970,14 @@ bool FCEUI_LoadMovie(const char *fname, bool _read_only, int _pauseframe) movieFromPoweron = false; bool success = MovieData::loadSavestateFrom(&currMovieData.savestate); if(!success) return true; //adelikat: I guess return true here? False is only for a bad movie filename, if it got this far the file was good? - } else { + } + else if(currMovieData.saveram.size()) + { + movieFromPoweron = true; + bool success = MovieData::loadSaveramFrom(&currMovieData.saveram); + if(!success) return true; //adelikat: I guess return true here? False is only for a bad movie filename, if it got this far the file was good? + } + else { movieFromPoweron = true; } @@ -981,7 +1057,15 @@ void FCEUI_SaveMovie(const char *fname, EMOVIE_FLAG flags, std::wstring author) movieFromPoweron = true; poweron(true); } - else + else if(flags & MOVIE_FLAG_FROM_SAVERAM) + { + movieFromPoweron = true; + MovieData::dumpSaveramTo(&currMovieData.saveram,Z_NO_COMPRESSION); //i guess with this there's a chance someone could hack the file, at least, so maybe it's helpfu + bogorf = true; + poweron(false); + bogorf = false; + } + else //from savestate { movieFromPoweron = false; MovieData::dumpSavestateTo(&currMovieData.savestate,Z_BEST_COMPRESSION); diff --git a/src/movie.h b/src/movie.h index cab767bd..a19d25ba 100644 --- a/src/movie.h +++ b/src/movie.h @@ -23,13 +23,15 @@ enum EMOVIE_FLAG MOVIE_FLAG_PAL = (1<<2), - //movie was recorded from poweron. the alternative is from a savestate (or from reset) + //movie was recorded from poweron. the alternative is from a savestate (or from reset). OR from saveram. MOVIE_FLAG_FROM_POWERON = (1<<3), // set in newer version, used for old movie compatibility //TODO - only use this flag to print a warning that the sync might be bad //so that we can get rid of the sync hack code - MOVIE_FLAG_NOSYNCHACK = (1<<4) + MOVIE_FLAG_NOSYNCHACK = (1<<4), + + MOVIE_FLAG_FROM_SAVERAM = (1<<5) }; typedef struct @@ -178,6 +180,7 @@ public: MD5DATA romChecksum; std::string romFilename; std::vector savestate; + std::vector saveram; std::vector records; std::vector comments; std::vector subtitles; @@ -241,6 +244,9 @@ public: static bool loadSavestateFrom(std::vector* buf); static void dumpSavestateTo(std::vector* buf, int compressionLevel); + static bool loadSaveramFrom(std::vector* buf); + static void dumpSaveramTo(std::vector* buf, int compressionLevel); + private: void installInt(std::string& val, int& var) { diff --git a/src/unif.cpp b/src/unif.cpp index 21a4cae2..627c9a3a 100644 --- a/src/unif.cpp +++ b/src/unif.cpp @@ -618,6 +618,7 @@ int UNIFLoad(const char *name, FCEUFILE *fp) { strcpy(LoadedRomFName, name); //For the debugger list GameInterface = UNIFGI; + currCartInfo = &UNIFCart; return 1; aborto: