mirror of https://github.com/PCSX2/pcsx2.git
recording: Use conventional savestate functions, save save-state in a separate file alongside recording file
Regressions were discovered after merging with master due to way the save state data was saved within the movie file. This change uses the same functions used in the GUI to create savestates to create a compressed save-state file. Eventually this could be re-incorporated back into the recording file and could be backwards compatible.
This commit is contained in:
parent
270f7fd905
commit
eb7030cf12
|
@ -1,6 +1,7 @@
|
||||||
#include "PrecompiledHeader.h"
|
#include "PrecompiledHeader.h"
|
||||||
|
|
||||||
#include "AppSaveStates.h"
|
#include "AppSaveStates.h"
|
||||||
|
#include "AppGameDatabase.h"
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Counters.h"
|
#include "Counters.h"
|
||||||
#include "MemoryTypes.h"
|
#include "MemoryTypes.h"
|
||||||
|
@ -117,54 +118,73 @@ void InputRecording::Stop() {
|
||||||
//----------------------------------
|
//----------------------------------
|
||||||
// start
|
// start
|
||||||
//----------------------------------
|
//----------------------------------
|
||||||
void InputRecording::Start(wxString FileName,bool fReadOnly, VmStateBuffer* ss)
|
void InputRecording::Create(wxString FileName, bool fromSaveState, wxString authorName)
|
||||||
{
|
{
|
||||||
g_RecordingControls.Pause();
|
g_RecordingControls.Pause();
|
||||||
Stop();
|
Stop();
|
||||||
|
|
||||||
if (fReadOnly)
|
// create
|
||||||
|
if (!InputRecordingData.Open(FileName, true, fromSaveState)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Set author name
|
||||||
|
if (!authorName.IsEmpty())
|
||||||
{
|
{
|
||||||
if (!InputRecordingData.Open(FileName, false)) {
|
InputRecordingData.getHeader().setAuthor(authorName);
|
||||||
return;
|
}
|
||||||
}
|
// Set Game Name
|
||||||
if (!InputRecordingData.readHeaderAndCheck()) {
|
// Code loosely taken from AppCoreThread.cpp to resolve the Game Name
|
||||||
recordingConLog(L"[REC]: This file is not a correct InputRecording file.\n");
|
// Fallback is ISO name
|
||||||
InputRecordingData.Close();
|
wxString gameName;
|
||||||
return;
|
const wxString gameKey(SysGetDiscID());
|
||||||
}
|
if (!gameKey.IsEmpty())
|
||||||
// cdrom
|
{
|
||||||
if (!g_Conf->CurrentIso.IsEmpty())
|
if (IGameDatabase* GameDB = AppHost_GetGameDatabase())
|
||||||
{
|
{
|
||||||
if (Path::GetFilename(g_Conf->CurrentIso) != InputRecordingData.getHeader().cdrom) {
|
Game_Data game;
|
||||||
recordingConLog(L"[REC]: Information on CD in Movie file is Different.\n");
|
if (GameDB->findGame(game, gameKey))
|
||||||
|
{
|
||||||
|
gameName = game.getString("Name");
|
||||||
|
gameName += L" (" + game.getString("Region") + L")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state = REPLAY;
|
|
||||||
recordingConLog(wxString::Format(L"[REC]: Replaying movie - [%s]\n",FileName));
|
|
||||||
recordingConLog(wxString::Format(L"MaxFrame: %d\n", InputRecordingData.getMaxFrame()));
|
|
||||||
recordingConLog(wxString::Format(L"UndoCount: %d\n", InputRecordingData.getUndoCount()));
|
|
||||||
}
|
}
|
||||||
else
|
InputRecordingData.getHeader().setGameName(!gameName.IsEmpty() ? gameName : Path::GetFilename(g_Conf->CurrentIso));
|
||||||
{
|
InputRecordingData.writeHeader();
|
||||||
// create
|
state = RECORD;
|
||||||
if (!InputRecordingData.Open(FileName, true, ss)) {
|
recordingConLog(wxString::Format(L"[REC]: Started new recording - [%s]\n", FileName));
|
||||||
return;
|
|
||||||
}
|
|
||||||
// cdrom
|
|
||||||
if (!g_Conf->CurrentIso.IsEmpty())
|
|
||||||
{
|
|
||||||
InputRecordingData.getHeader().setCdrom(Path::GetFilename(g_Conf->CurrentIso));
|
|
||||||
}
|
|
||||||
InputRecordingData.writeHeader();
|
|
||||||
InputRecordingData.writeSavestate();
|
|
||||||
|
|
||||||
state = RECORD;
|
|
||||||
recordingConLog(wxString::Format(L"[REC]: Started new recording - [%s]\n", FileName));
|
|
||||||
}
|
|
||||||
// In every case, we reset the g_FrameCount
|
// In every case, we reset the g_FrameCount
|
||||||
g_FrameCount = 0;
|
g_FrameCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InputRecording::Play(wxString FileName, bool fromSaveState)
|
||||||
|
{
|
||||||
|
g_RecordingControls.Pause();
|
||||||
|
Stop();
|
||||||
|
|
||||||
|
if (!InputRecordingData.Open(FileName, false, false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!InputRecordingData.readHeaderAndCheck()) {
|
||||||
|
recordingConLog(L"[REC]: This file is not a correct InputRecording file.\n");
|
||||||
|
InputRecordingData.Close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Check author name
|
||||||
|
if (!g_Conf->CurrentIso.IsEmpty())
|
||||||
|
{
|
||||||
|
if (Path::GetFilename(g_Conf->CurrentIso) != InputRecordingData.getHeader().gameName) {
|
||||||
|
recordingConLog(L"[REC]: Information on CD in Movie file is Different.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO - probably output more informatiion on it
|
||||||
|
state = REPLAY;
|
||||||
|
recordingConLog(wxString::Format(L"[REC]: Replaying movie - [%s]\n", FileName));
|
||||||
|
recordingConLog(wxString::Format(L"MaxFrame: %d\n", InputRecordingData.getMaxFrame()));
|
||||||
|
recordingConLog(wxString::Format(L"UndoCount: %d\n", InputRecordingData.getUndoCount()));
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------
|
//----------------------------------
|
||||||
// shortcut key
|
// shortcut key
|
||||||
//----------------------------------
|
//----------------------------------
|
||||||
|
|
|
@ -16,7 +16,8 @@ public:
|
||||||
|
|
||||||
// menu bar
|
// menu bar
|
||||||
void Stop();
|
void Stop();
|
||||||
void Start(wxString filename, bool fReadOnly, VmStateBuffer* ss = nullptr);
|
void Create(wxString filename, bool fromSaveState, wxString authorName);
|
||||||
|
void Play(wxString filename, bool fromSaveState);
|
||||||
|
|
||||||
// shortcut key
|
// shortcut key
|
||||||
void RecordModeToggle();
|
void RecordModeToggle();
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
#include "PrecompiledHeader.h"
|
#include "PrecompiledHeader.h"
|
||||||
|
|
||||||
#include "MemoryTypes.h"
|
|
||||||
#include "App.h"
|
#include "App.h"
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Counters.h"
|
#include "Counters.h"
|
||||||
|
#include "MainFrame.h"
|
||||||
|
#include "MemoryTypes.h"
|
||||||
|
|
||||||
#include "InputRecordingFile.h"
|
#include "InputRecordingFile.h"
|
||||||
|
|
||||||
#define HEADER_SIZE (sizeof(InputRecordingHeader)+4+4)
|
#define HEADER_SIZE (sizeof(InputRecordingHeader)+4+4)
|
||||||
#define SAVESTATE_HEADER_SIZE (sizeof(bool) + sizeof(savestate.savestatesize) + sizeof(savestate.savestate[0]) * savestate.savestatesize)
|
#define SAVESTATE_HEADER_SIZE (sizeof(bool))
|
||||||
#define BLOCK_HEADER_SIZE (0)
|
#define BLOCK_HEADER_SIZE (0)
|
||||||
#define BLOCK_DATA_SIZE (18*2)
|
#define BLOCK_DATA_SIZE (18*2)
|
||||||
#define BLOCK_SIZE (BLOCK_HEADER_SIZE+BLOCK_DATA_SIZE)
|
#define BLOCK_SIZE (BLOCK_HEADER_SIZE+BLOCK_DATA_SIZE)
|
||||||
|
@ -29,10 +30,8 @@ long InputRecordingFile::_getBlockSeekPoint(const long & frame)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------
|
// Inits the new (or existing) input recording file
|
||||||
// file
|
bool InputRecordingFile::Open(const wxString path, bool fNewOpen, bool fromSaveState)
|
||||||
//----------------------------------
|
|
||||||
bool InputRecordingFile::Open(const wxString path, bool fNewOpen, VmStateBuffer *ss)
|
|
||||||
{
|
{
|
||||||
Close();
|
Close();
|
||||||
wxString mode = L"rb+";
|
wxString mode = L"rb+";
|
||||||
|
@ -50,14 +49,13 @@ bool InputRecordingFile::Open(const wxString path, bool fNewOpen, VmStateBuffer
|
||||||
}
|
}
|
||||||
filename = path;
|
filename = path;
|
||||||
|
|
||||||
|
// TODO - from power on its fine
|
||||||
|
// problems seem to be be based in how we are saving the savestate
|
||||||
if (fNewOpen) {
|
if (fNewOpen) {
|
||||||
if (ss) {
|
if (fromSaveState) {
|
||||||
savestate.fromSavestate = true;
|
savestate.fromSavestate = true;
|
||||||
savestate.savestatesize = ss->GetLength();
|
// TODO - Check if existing, if so rename
|
||||||
savestate.savestate.MakeRoomFor(ss->GetLength());
|
StateCopy_SaveToFile(path + "_SaveState.p2s");
|
||||||
for (size_t i = 0; i < ss->GetLength(); i++) {
|
|
||||||
savestate.savestate[i] = (*ss)[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sApp.SysExecute();
|
sApp.SysExecute();
|
||||||
|
@ -65,17 +63,28 @@ bool InputRecordingFile::Open(const wxString path, bool fNewOpen, VmStateBuffer
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InputRecordingFile::Close()
|
bool InputRecordingFile::Close()
|
||||||
{
|
{
|
||||||
if (recordingFile == NULL)return false;
|
if (recordingFile == NULL)return false;
|
||||||
writeHeader();
|
writeHeader();
|
||||||
writeSavestate();
|
writeSaveState();
|
||||||
fclose(recordingFile);
|
fclose(recordingFile);
|
||||||
recordingFile = NULL;
|
recordingFile = NULL;
|
||||||
filename = "";
|
filename = "";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool InputRecordingFile::writeSaveState() {
|
||||||
|
if (recordingFile == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fseek(recordingFile, SEEKPOINT_SAVESTATE, SEEK_SET);
|
||||||
|
if (fwrite(&savestate.fromSavestate, sizeof(bool), 1, recordingFile) != 1) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------
|
//----------------------------------
|
||||||
// write frame
|
// write frame
|
||||||
//----------------------------------
|
//----------------------------------
|
||||||
|
@ -111,9 +120,6 @@ bool InputRecordingFile::readKeyBuf(u8 & result,const uint & frame, const uint p
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//===================================
|
//===================================
|
||||||
// pad
|
// pad
|
||||||
//===================================
|
//===================================
|
||||||
|
@ -126,6 +132,7 @@ void InputRecordingFile::getPadData(PadData & result, unsigned long frame)
|
||||||
if (fread(result.buf, 1, BLOCK_DATA_SIZE, recordingFile) == 0)return;
|
if (fread(result.buf, 1, BLOCK_DATA_SIZE, recordingFile) == 0)return;
|
||||||
result.fExistKey = true;
|
result.fExistKey = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InputRecordingFile::DeletePadData(unsigned long frame)
|
bool InputRecordingFile::DeletePadData(unsigned long frame)
|
||||||
{
|
{
|
||||||
if (recordingFile == NULL)return false;
|
if (recordingFile == NULL)return false;
|
||||||
|
@ -147,6 +154,7 @@ bool InputRecordingFile::DeletePadData(unsigned long frame)
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InputRecordingFile::InsertPadData(unsigned long frame, const PadData& key)
|
bool InputRecordingFile::InsertPadData(unsigned long frame, const PadData& key)
|
||||||
{
|
{
|
||||||
if (recordingFile == NULL)return false;
|
if (recordingFile == NULL)return false;
|
||||||
|
@ -174,88 +182,53 @@ bool InputRecordingFile::InsertPadData(unsigned long frame, const PadData& key)
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InputRecordingFile::UpdatePadData(unsigned long frame, const PadData& key)
|
bool InputRecordingFile::UpdatePadData(unsigned long frame, const PadData& key)
|
||||||
{
|
{
|
||||||
if (recordingFile == NULL)return false;
|
if (recordingFile == NULL) return false;
|
||||||
if (!key.fExistKey)return false;
|
if (!key.fExistKey) return false;
|
||||||
|
|
||||||
long seek = _getBlockSeekPoint(frame) + BLOCK_HEADER_SIZE;
|
long seek = _getBlockSeekPoint(frame) + BLOCK_HEADER_SIZE;
|
||||||
fseek(recordingFile, seek, SEEK_SET);
|
fseek(recordingFile, seek, SEEK_SET);
|
||||||
if (fwrite(key.buf, 1, BLOCK_DATA_SIZE, recordingFile) == 0)return false;
|
if (fwrite(key.buf, 1, BLOCK_DATA_SIZE, recordingFile) == 0) return false;
|
||||||
|
|
||||||
fflush(recordingFile);
|
fflush(recordingFile);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO - see if we can get the actual game name, not just the ISO name
|
||||||
|
// Verify header of recording file
|
||||||
|
|
||||||
//===================================
|
|
||||||
// header
|
|
||||||
//===================================
|
|
||||||
bool InputRecordingFile::readHeaderAndCheck()
|
bool InputRecordingFile::readHeaderAndCheck()
|
||||||
{
|
{
|
||||||
if (recordingFile == NULL)return false;
|
if (recordingFile == NULL) return false;
|
||||||
rewind(recordingFile);
|
rewind(recordingFile);
|
||||||
if (fread(&header, sizeof(InputRecordingHeader), 1, recordingFile) != 1)return false;
|
if (fread(&header, sizeof(InputRecordingHeader), 1, recordingFile) != 1) return false;
|
||||||
if (fread(&MaxFrame, 4, 1, recordingFile) != 1)return false;
|
if (fread(&MaxFrame, 4, 1, recordingFile) != 1) return false;
|
||||||
if (fread(&UndoCount, 4, 1, recordingFile) != 1)return false;
|
if (fread(&UndoCount, 4, 1, recordingFile) != 1) return false;
|
||||||
if (fread(&savestate.fromSavestate, sizeof(bool), 1, recordingFile) != 1) return false;
|
if (fread(&savestate.fromSavestate, sizeof(bool), 1, recordingFile) != 1) return false;
|
||||||
if (savestate.fromSavestate) {
|
if (savestate.fromSavestate) {
|
||||||
// We read the size (and the savestate) only if we must
|
// TODO - check to see if the file is there, if it AINT, return false, throw an error, ETC (SAY WHAT FILE WE ARE LOOKING FOR)
|
||||||
if (fread(&savestate.savestatesize, sizeof(savestate.savestatesize), 1, recordingFile) != 1) return false;
|
StateCopy_LoadFromFile(filename + "_SaveState.p2s");
|
||||||
if (savestate.savestatesize == 0) {
|
|
||||||
recordingConLog(L"[REC]: Invalid size of the savestate.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
savestate.savestate.MakeRoomFor(savestate.savestatesize);
|
|
||||||
// We read "savestatesize" * the size of a cell
|
|
||||||
if (fread(savestate.savestate.GetPtr(), sizeof(savestate.savestate[0]), savestate.savestatesize, recordingFile)
|
|
||||||
!= savestate.savestatesize) return false;
|
|
||||||
|
|
||||||
// We load the savestate
|
|
||||||
memLoadingState load(savestate.savestate);
|
|
||||||
UI_DisableSysActions();
|
|
||||||
GetCoreThread().Pause();
|
|
||||||
SysClearExecutionCache();
|
|
||||||
load.FreezeAll();
|
|
||||||
GetCoreThread().Resume();
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sApp.SysExecute();
|
sApp.SysExecute();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ID
|
// Check for current verison
|
||||||
if (header.ID != 0xCC) {
|
// TODO - more specific log if fails for this reason
|
||||||
return false;
|
if (header.version != 1) {
|
||||||
}
|
|
||||||
// ver
|
|
||||||
if (header.version != 3) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool InputRecordingFile::writeHeader()
|
bool InputRecordingFile::writeHeader()
|
||||||
{
|
{
|
||||||
if (recordingFile == NULL)return false;
|
if (recordingFile == NULL) return false;
|
||||||
rewind(recordingFile);
|
rewind(recordingFile);
|
||||||
if (fwrite(&header, sizeof(InputRecordingHeader), 1, recordingFile) != 1) return false;
|
if (fwrite(&header, sizeof(InputRecordingHeader), 1, recordingFile) != 1) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool InputRecordingFile::writeSavestate()
|
|
||||||
{
|
|
||||||
if (recordingFile == NULL) return false;
|
|
||||||
fseek(recordingFile, SEEKPOINT_SAVESTATE, SEEK_SET);
|
|
||||||
if (fwrite(&savestate.fromSavestate, sizeof(bool), 1, recordingFile) != 1) return false;
|
|
||||||
|
|
||||||
if (savestate.fromSavestate) {
|
|
||||||
if (fwrite(&savestate.savestatesize, sizeof(savestate.savestatesize), 1, recordingFile) != 1) return false;
|
|
||||||
if (fwrite(savestate.savestate.GetPtr(), sizeof(savestate.savestate[0]), savestate.savestatesize, recordingFile)
|
|
||||||
!= savestate.savestatesize) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool InputRecordingFile::writeMaxFrame()
|
bool InputRecordingFile::writeMaxFrame()
|
||||||
{
|
{
|
||||||
if (recordingFile == NULL)return false;
|
if (recordingFile == NULL)return false;
|
||||||
|
@ -263,6 +236,7 @@ bool InputRecordingFile::writeMaxFrame()
|
||||||
if (fwrite(&MaxFrame, 4, 1, recordingFile) != 1) return false;
|
if (fwrite(&MaxFrame, 4, 1, recordingFile) != 1) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputRecordingFile::updateFrameMax(unsigned long frame)
|
void InputRecordingFile::updateFrameMax(unsigned long frame)
|
||||||
{
|
{
|
||||||
if (MaxFrame >= frame) {
|
if (MaxFrame >= frame) {
|
||||||
|
@ -273,13 +247,13 @@ void InputRecordingFile::updateFrameMax(unsigned long frame)
|
||||||
fseek(recordingFile, SEEKPOINT_FRAMEMAX, SEEK_SET);
|
fseek(recordingFile, SEEKPOINT_FRAMEMAX, SEEK_SET);
|
||||||
fwrite(&MaxFrame, 4, 1, recordingFile);
|
fwrite(&MaxFrame, 4, 1, recordingFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputRecordingFile::addUndoCount()
|
void InputRecordingFile::addUndoCount()
|
||||||
{
|
{
|
||||||
UndoCount++;
|
UndoCount++;
|
||||||
if (recordingFile == NULL)return;
|
if (recordingFile == NULL)return;
|
||||||
fseek(recordingFile, SEEKPOINT_UNDOCOUNT, SEEK_SET);
|
fseek(recordingFile, SEEKPOINT_UNDOCOUNT, SEEK_SET);
|
||||||
fwrite(&UndoCount, 4, 1, recordingFile);
|
fwrite(&UndoCount, 4, 1, recordingFile);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputRecordingHeader::setAuthor(wxString _author)
|
void InputRecordingHeader::setAuthor(wxString _author)
|
||||||
|
@ -288,14 +262,16 @@ void InputRecordingHeader::setAuthor(wxString _author)
|
||||||
strncpy(author, _author.c_str(), max);
|
strncpy(author, _author.c_str(), max);
|
||||||
author[max] = 0;
|
author[max] = 0;
|
||||||
}
|
}
|
||||||
void InputRecordingHeader::setCdrom(wxString _cdrom)
|
|
||||||
|
void InputRecordingHeader::setGameName(wxString _gameName)
|
||||||
{
|
{
|
||||||
int max = ArraySize(cdrom) - 1;
|
int max = ArraySize(gameName) - 1;
|
||||||
strncpy(cdrom, _cdrom.c_str(), max);
|
strncpy(gameName, _gameName.c_str(), max);
|
||||||
cdrom[max] = 0;
|
gameName[max] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputRecordingHeader::init()
|
void InputRecordingHeader::init()
|
||||||
{
|
{
|
||||||
memset(author, 0, ArraySize(author));
|
memset(author, 0, ArraySize(author));
|
||||||
memset(cdrom, 0, ArraySize(cdrom));
|
memset(gameName, 0, ArraySize(gameName));
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,87 +5,65 @@
|
||||||
|
|
||||||
struct InputRecordingHeader
|
struct InputRecordingHeader
|
||||||
{
|
{
|
||||||
u8 version = 3;
|
u8 version = 1;
|
||||||
u8 ID = 0xCC;
|
char emu[50] = "PCSX2-1.5.X";
|
||||||
|
char author[255] = "";
|
||||||
char emu[50] = "pcsx2-1.5.X";
|
char gameName[255] = "";
|
||||||
char author[50] = "";
|
|
||||||
char cdrom[50] = "";
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void setAuthor(wxString author);
|
void setAuthor(wxString author);
|
||||||
void setCdrom(wxString cdrom);
|
void setGameName(wxString cdrom);
|
||||||
void init();
|
void init();
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------
|
|
||||||
// InputRecordingSavestate
|
|
||||||
// Contains info about the starting point of the movie
|
// Contains info about the starting point of the movie
|
||||||
//----------------------------
|
|
||||||
struct InputRecordingSavestate
|
struct InputRecordingSavestate
|
||||||
{
|
{
|
||||||
bool fromSavestate = false; // Whether we start from the savestate or from power-on
|
// Whether we start from the savestate or from power-on
|
||||||
unsigned int savestatesize; // The size of the savestate
|
bool fromSavestate = false;
|
||||||
VmStateBuffer savestate; // The savestate
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------
|
|
||||||
// InputRecordingFile
|
|
||||||
//----------------------------
|
|
||||||
class InputRecordingFile {
|
class InputRecordingFile {
|
||||||
public:
|
public:
|
||||||
InputRecordingFile() {}
|
InputRecordingFile() {}
|
||||||
~InputRecordingFile() { Close(); }
|
~InputRecordingFile() { Close(); }
|
||||||
public:
|
|
||||||
|
|
||||||
// file
|
// Movie File Manipulation
|
||||||
bool Open(const wxString fn, bool fNewOpen, VmStateBuffer *ss = nullptr);
|
bool Open(const wxString fn, bool fNewOpen, bool fromSaveState);
|
||||||
bool Close();
|
bool Close();
|
||||||
|
|
||||||
// movie
|
|
||||||
bool writeKeyBuf(const uint & frame, const uint port, const uint bufIndex, const u8 & buf);
|
bool writeKeyBuf(const uint & frame, const uint port, const uint bufIndex, const u8 & buf);
|
||||||
bool readKeyBuf(u8 & result, const uint & frame, const uint port, const uint bufIndex);
|
bool readKeyBuf(u8 & result, const uint & frame, const uint port, const uint bufIndex);
|
||||||
|
|
||||||
// pad data
|
// Controller Data
|
||||||
void getPadData(PadData & result_pad, unsigned long frame);
|
void getPadData(PadData & result_pad, unsigned long frame);
|
||||||
bool DeletePadData(unsigned long frame);
|
bool DeletePadData(unsigned long frame);
|
||||||
bool InsertPadData(unsigned long frame, const PadData& key);
|
bool InsertPadData(unsigned long frame, const PadData& key);
|
||||||
bool UpdatePadData(unsigned long frame, const PadData& key);
|
bool UpdatePadData(unsigned long frame, const PadData& key);
|
||||||
|
|
||||||
private:
|
// Header
|
||||||
FILE * recordingFile = NULL;
|
|
||||||
wxString filename = "";
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
//--------------------
|
|
||||||
// block
|
|
||||||
//--------------------
|
|
||||||
long _getBlockSeekPoint(const long & frame);
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
//--------------------
|
|
||||||
// header
|
|
||||||
//--------------------
|
|
||||||
InputRecordingHeader& getHeader() { return header; }
|
InputRecordingHeader& getHeader() { return header; }
|
||||||
unsigned long& getMaxFrame() { return MaxFrame; }
|
unsigned long& getMaxFrame() { return MaxFrame; }
|
||||||
unsigned long& getUndoCount() { return UndoCount; }
|
unsigned long& getUndoCount() { return UndoCount; }
|
||||||
const wxString & getFilename() { return filename; }
|
const wxString & getFilename() { return filename; }
|
||||||
|
|
||||||
bool writeHeader();
|
bool writeHeader();
|
||||||
bool writeSavestate();
|
|
||||||
bool writeMaxFrame();
|
bool writeMaxFrame();
|
||||||
|
bool writeSaveState();
|
||||||
|
|
||||||
bool readHeaderAndCheck();
|
bool readHeaderAndCheck();
|
||||||
void updateFrameMax(unsigned long frame);
|
void updateFrameMax(unsigned long frame);
|
||||||
void addUndoCount();
|
void addUndoCount();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Movie File
|
||||||
|
FILE * recordingFile = NULL;
|
||||||
|
wxString filename = "";
|
||||||
|
long _getBlockSeekPoint(const long & frame);
|
||||||
|
|
||||||
|
// Header
|
||||||
InputRecordingHeader header;
|
InputRecordingHeader header;
|
||||||
InputRecordingSavestate savestate;
|
InputRecordingSavestate savestate;
|
||||||
unsigned long MaxFrame = 0;
|
unsigned long MaxFrame = 0;
|
||||||
unsigned long UndoCount = 0;
|
unsigned long UndoCount = 0;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -788,7 +788,6 @@ void MainEmuFrame::Menu_Recording_New_Click(wxCommandEvent &event)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
g_InputRecordingHeader.setAuthor(NewRecordingFrame->getAuthor());
|
|
||||||
// From Current Frame
|
// From Current Frame
|
||||||
if (NewRecordingFrame->getFrom() == 0)
|
if (NewRecordingFrame->getFrom() == 0)
|
||||||
{
|
{
|
||||||
|
@ -796,16 +795,13 @@ void MainEmuFrame::Menu_Recording_New_Click(wxCommandEvent &event)
|
||||||
recordingConLog(L"[REC]: Game is not open, aborting new input recording.\n");
|
recordingConLog(L"[REC]: Game is not open, aborting new input recording.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
VmStateBuffer savestate;
|
g_InputRecording.Create(NewRecordingFrame->getFile(), true, NewRecordingFrame->getAuthor());
|
||||||
memSavingState memSS(savestate);
|
|
||||||
memSS.FreezeAll();
|
|
||||||
g_InputRecording.Start(NewRecordingFrame->getFile(), false, &savestate);
|
|
||||||
}
|
}
|
||||||
// From Power-On
|
// From Power-On
|
||||||
else if (NewRecordingFrame->getFrom() == 1)
|
else if (NewRecordingFrame->getFrom() == 1)
|
||||||
{
|
{
|
||||||
// TODO extensively test this
|
// TODO extensively test this
|
||||||
g_InputRecording.Start(NewRecordingFrame->getFile(), false);
|
g_InputRecording.Create(NewRecordingFrame->getFile(), false, NewRecordingFrame->getAuthor());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_menuRecording.FindChildItem(MenuId_Recording_New)->Enable(false);
|
m_menuRecording.FindChildItem(MenuId_Recording_New)->Enable(false);
|
||||||
|
@ -815,12 +811,12 @@ void MainEmuFrame::Menu_Recording_New_Click(wxCommandEvent &event)
|
||||||
void MainEmuFrame::Menu_Recording_Play_Click(wxCommandEvent &event)
|
void MainEmuFrame::Menu_Recording_Play_Click(wxCommandEvent &event)
|
||||||
{
|
{
|
||||||
g_InputRecording.Stop();
|
g_InputRecording.Stop();
|
||||||
|
|
||||||
wxFileDialog openFileDialog(this, _("Select P2M2 record file."), L"", L"",
|
wxFileDialog openFileDialog(this, _("Select P2M2 record file."), L"", L"",
|
||||||
L"p2m2 file(*.p2m2)|*.p2m2", wxFD_OPEN);
|
L"p2m2 file(*.p2m2)|*.p2m2", wxFD_OPEN);
|
||||||
if (openFileDialog.ShowModal() == wxID_CANCEL)return; // cancel
|
if (openFileDialog.ShowModal() == wxID_CANCEL) return;
|
||||||
|
|
||||||
wxString path = openFileDialog.GetPath();
|
wxString path = openFileDialog.GetPath();
|
||||||
g_InputRecording.Start(path, true);
|
g_InputRecording.Play(path, true);
|
||||||
m_menuRecording.FindChildItem(MenuId_Recording_New)->Enable(false);
|
m_menuRecording.FindChildItem(MenuId_Recording_New)->Enable(false);
|
||||||
m_menuRecording.FindChildItem(MenuId_Recording_Stop)->Enable(true);
|
m_menuRecording.FindChildItem(MenuId_Recording_Stop)->Enable(true);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue