oops forgot a couple of files
This commit is contained in:
parent
024462c221
commit
6194523549
|
@ -0,0 +1,674 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "utils/guid.h"
|
||||||
|
#include "utils/xstring.h"
|
||||||
|
#include "movie.h"
|
||||||
|
#include "NDSSystem.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#define FCEU_PrintError printlog
|
||||||
|
|
||||||
|
#define MOVIE_VERSION 1
|
||||||
|
|
||||||
|
//----movie engine main state
|
||||||
|
|
||||||
|
EMOVIEMODE movieMode = MOVIEMODE_INACTIVE;
|
||||||
|
|
||||||
|
//this should not be set unless we are in MOVIEMODE_RECORD!
|
||||||
|
fstream* osRecordingMovie = 0;
|
||||||
|
|
||||||
|
int currFrameCounter;
|
||||||
|
uint32 cur_input_display = 0;
|
||||||
|
int pauseframe = -1;
|
||||||
|
bool movie_readonly = true;
|
||||||
|
|
||||||
|
char curMovieFilename[512] = {0};
|
||||||
|
MovieData currMovieData;
|
||||||
|
int currRerecordCount;
|
||||||
|
|
||||||
|
//--------------
|
||||||
|
|
||||||
|
|
||||||
|
void MovieData::clearRecordRange(int start, int len)
|
||||||
|
{
|
||||||
|
for(int i=0;i<len;i++)
|
||||||
|
records[i+start].clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MovieData::insertEmpty(int at, int frames)
|
||||||
|
{
|
||||||
|
if(at == -1)
|
||||||
|
{
|
||||||
|
int currcount = records.size();
|
||||||
|
records.resize(records.size()+frames);
|
||||||
|
clearRecordRange(currcount,frames);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
records.insert(records.begin()+at,frames,MovieRecord());
|
||||||
|
clearRecordRange(at,frames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void MovieRecord::clear()
|
||||||
|
{
|
||||||
|
pad = 0;
|
||||||
|
commands = 0;
|
||||||
|
touch.padding = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char MovieRecord::mnemonics[13] = {'R','L','D','U','T','S','B','A','Y','X','W','E','G'};
|
||||||
|
void MovieRecord::dumpPad(std::ostream* os, u16 pad)
|
||||||
|
{
|
||||||
|
//these are mnemonics for each joystick bit.
|
||||||
|
//since we usually use the regular joypad, these will be more helpful.
|
||||||
|
//but any character other than ' ' or '.' should count as a set bit
|
||||||
|
//maybe other input types will need to be encoded another way..
|
||||||
|
for(int bit=0;bit<13;bit++)
|
||||||
|
{
|
||||||
|
int bitmask = (1<<(12-bit));
|
||||||
|
char mnemonic = mnemonics[bit];
|
||||||
|
//if the bit is set write the mnemonic
|
||||||
|
if(pad & bitmask)
|
||||||
|
os->put(mnemonic);
|
||||||
|
else //otherwise write an unset bit
|
||||||
|
os->put('.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MovieRecord::parsePad(std::istream* is, u16& pad)
|
||||||
|
{
|
||||||
|
char buf[13];
|
||||||
|
is->read(buf,13);
|
||||||
|
pad = 0;
|
||||||
|
for(int i=0;i<13;i++)
|
||||||
|
{
|
||||||
|
pad <<= 1;
|
||||||
|
pad |= ((buf[i]=='.'||buf[i]==' ')?0:1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MovieRecord::parse(MovieData* md, std::istream* is)
|
||||||
|
{
|
||||||
|
//by the time we get in here, the initial pipe has already been extracted
|
||||||
|
|
||||||
|
//extract the commands
|
||||||
|
commands = u32DecFromIstream(is);
|
||||||
|
|
||||||
|
is->get(); //eat the pipe
|
||||||
|
|
||||||
|
parsePad(is, pad);
|
||||||
|
touch.x = u32DecFromIstream(is);
|
||||||
|
touch.y = u32DecFromIstream(is);
|
||||||
|
touch.touch = u32DecFromIstream(is);
|
||||||
|
|
||||||
|
is->get(); //eat the pipe
|
||||||
|
|
||||||
|
//should be left at a newline
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MovieRecord::dump(MovieData* md, std::ostream* os, int index)
|
||||||
|
{
|
||||||
|
//dump the misc commands
|
||||||
|
//*os << '|' << setw(1) << (int)commands;
|
||||||
|
os->put('|');
|
||||||
|
putdec<uint8,1,true>(os,commands);
|
||||||
|
|
||||||
|
os->put('|');
|
||||||
|
dumpPad(os, pad);
|
||||||
|
putdec<u8,3,true>(os,touch.x); os->put(' ');
|
||||||
|
putdec<u8,3,true>(os,touch.y); os->put(' ');
|
||||||
|
putdec<u8,1,true>(os,touch.touch);
|
||||||
|
os->put('|');
|
||||||
|
|
||||||
|
//each frame is on a new line
|
||||||
|
os->put('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
MovieData::MovieData()
|
||||||
|
: version(MOVIE_VERSION)
|
||||||
|
, emuVersion(DESMUME_VERSION_NUMERIC)
|
||||||
|
, binaryFlag(false)
|
||||||
|
, rerecordCount(1)
|
||||||
|
//, greenZoneCount(0)
|
||||||
|
{
|
||||||
|
memset(&romChecksum,0,sizeof(MD5DATA));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MovieData::truncateAt(int frame)
|
||||||
|
{
|
||||||
|
records.resize(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MovieData::installValue(std::string& key, std::string& val)
|
||||||
|
{
|
||||||
|
//todo - use another config system, or drive this from a little data structure. because this is gross
|
||||||
|
if(key == "version")
|
||||||
|
installInt(val,version);
|
||||||
|
else if(key == "emuVersion")
|
||||||
|
installInt(val,emuVersion);
|
||||||
|
else if(key == "rerecordCount")
|
||||||
|
installInt(val,rerecordCount);
|
||||||
|
else if(key == "romFilename")
|
||||||
|
romFilename = val;
|
||||||
|
else if(key == "romChecksum")
|
||||||
|
StringToBytes(val,&romChecksum,MD5DATA::size);
|
||||||
|
else if(key == "guid")
|
||||||
|
guid = Desmume_Guid::fromString(val);
|
||||||
|
else if(key == "comment")
|
||||||
|
comments.push_back(mbstowcs(val));
|
||||||
|
else if(key == "savestate")
|
||||||
|
{
|
||||||
|
int len = Base64StringToBytesLength(val);
|
||||||
|
if(len == -1) len = HexStringToBytesLength(val); // wasn't base64, try hex
|
||||||
|
if(len >= 1)
|
||||||
|
{
|
||||||
|
savestate.resize(len);
|
||||||
|
StringToBytes(val,&savestate[0],len); // decodes either base64 or hex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int MovieData::dump(std::ostream *os, bool binary)
|
||||||
|
{
|
||||||
|
int start = os->tellp();
|
||||||
|
*os << "version " << version << endl;
|
||||||
|
*os << "emuVersion " << emuVersion << endl;
|
||||||
|
*os << "rerecordCount " << rerecordCount << endl;
|
||||||
|
*os << "romFilename " << romFilename << endl;
|
||||||
|
*os << "romChecksum " << BytesToString(romChecksum.data,MD5DATA::size) << endl;
|
||||||
|
*os << "guid " << guid.toString() << endl;
|
||||||
|
|
||||||
|
for(uint32 i=0;i<comments.size();i++)
|
||||||
|
*os << "comment " << wcstombs(comments[i]) << endl;
|
||||||
|
|
||||||
|
if(binary)
|
||||||
|
*os << "binary 1" << endl;
|
||||||
|
|
||||||
|
if(savestate.size() != 0)
|
||||||
|
*os << "savestate " << BytesToString(&savestate[0],savestate.size()) << endl;
|
||||||
|
if(binary)
|
||||||
|
{
|
||||||
|
////put one | to start the binary dump
|
||||||
|
//os->put('|');
|
||||||
|
//for(int i=0;i<(int)records.size();i++)
|
||||||
|
// records[i].dumpBinary(this,os,i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
for(int i=0;i<(int)records.size();i++)
|
||||||
|
records[i].dump(this,os,i);
|
||||||
|
|
||||||
|
int end = os->tellp();
|
||||||
|
return end-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
//yuck... another custom text parser.
|
||||||
|
static bool LoadFM2(MovieData& movieData, std::istream* fp, int size, bool stopAfterHeader)
|
||||||
|
{
|
||||||
|
//TODO - start with something different. like 'desmume movie version 1"
|
||||||
|
std::ios::pos_type curr = fp->tellg();
|
||||||
|
|
||||||
|
//movie must start with "version 1"
|
||||||
|
char buf[9];
|
||||||
|
curr = fp->tellg();
|
||||||
|
fp->read(buf,9);
|
||||||
|
fp->seekg(curr);
|
||||||
|
if(fp->fail()) return false;
|
||||||
|
if(memcmp(buf,"version 1",9))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::string key,value;
|
||||||
|
enum {
|
||||||
|
NEWLINE, KEY, SEPARATOR, VALUE, RECORD, COMMENT
|
||||||
|
} state = NEWLINE;
|
||||||
|
bool bail = false;
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
bool iswhitespace, isrecchar, isnewline;
|
||||||
|
int c;
|
||||||
|
if(size--<=0) goto bail;
|
||||||
|
c = fp->get();
|
||||||
|
if(c == -1)
|
||||||
|
goto bail;
|
||||||
|
iswhitespace = (c==' '||c=='\t');
|
||||||
|
isrecchar = (c=='|');
|
||||||
|
isnewline = (c==10||c==13);
|
||||||
|
if(isrecchar && movieData.binaryFlag && !stopAfterHeader)
|
||||||
|
{
|
||||||
|
//LoadFM2_binarychunk(movieData, fp, size);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch(state)
|
||||||
|
{
|
||||||
|
case NEWLINE:
|
||||||
|
if(isnewline) goto done;
|
||||||
|
if(iswhitespace) goto done;
|
||||||
|
if(isrecchar)
|
||||||
|
goto dorecord;
|
||||||
|
//must be a key
|
||||||
|
key = "";
|
||||||
|
value = "";
|
||||||
|
goto dokey;
|
||||||
|
break;
|
||||||
|
case RECORD:
|
||||||
|
{
|
||||||
|
dorecord:
|
||||||
|
if (stopAfterHeader) return true;
|
||||||
|
int currcount = movieData.records.size();
|
||||||
|
movieData.records.resize(currcount+1);
|
||||||
|
int preparse = fp->tellg();
|
||||||
|
movieData.records[currcount].parse(&movieData, fp);
|
||||||
|
int postparse = fp->tellg();
|
||||||
|
size -= (postparse-preparse);
|
||||||
|
state = NEWLINE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case KEY:
|
||||||
|
dokey: //dookie
|
||||||
|
state = KEY;
|
||||||
|
if(iswhitespace) goto doseparator;
|
||||||
|
if(isnewline) goto commit;
|
||||||
|
key += c;
|
||||||
|
break;
|
||||||
|
case SEPARATOR:
|
||||||
|
doseparator:
|
||||||
|
state = SEPARATOR;
|
||||||
|
if(isnewline) goto commit;
|
||||||
|
if(!iswhitespace) goto dovalue;
|
||||||
|
break;
|
||||||
|
case VALUE:
|
||||||
|
dovalue:
|
||||||
|
state = VALUE;
|
||||||
|
if(isnewline) goto commit;
|
||||||
|
value += c;
|
||||||
|
}
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
bail:
|
||||||
|
bail = true;
|
||||||
|
if(state == VALUE) goto commit;
|
||||||
|
goto done;
|
||||||
|
commit:
|
||||||
|
movieData.installValue(key,value);
|
||||||
|
state = NEWLINE;
|
||||||
|
done: ;
|
||||||
|
if(bail) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void closeRecordingMovie()
|
||||||
|
{
|
||||||
|
if(osRecordingMovie)
|
||||||
|
{
|
||||||
|
delete osRecordingMovie;
|
||||||
|
osRecordingMovie = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stop movie playback.
|
||||||
|
static void StopPlayback()
|
||||||
|
{
|
||||||
|
//FCEU_DispMessageOnMovie("Movie playback stopped.");
|
||||||
|
movieMode = MOVIEMODE_INACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Stop movie recording
|
||||||
|
static void StopRecording()
|
||||||
|
{
|
||||||
|
//FCEU_DispMessage("Movie recording stopped.");
|
||||||
|
|
||||||
|
movieMode = MOVIEMODE_INACTIVE;
|
||||||
|
|
||||||
|
closeRecordingMovie();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void FCEUI_StopMovie()
|
||||||
|
{
|
||||||
|
//if(suppressMovieStop)
|
||||||
|
// return;
|
||||||
|
|
||||||
|
if(movieMode == MOVIEMODE_PLAY)
|
||||||
|
StopPlayback();
|
||||||
|
else if(movieMode == MOVIEMODE_RECORD)
|
||||||
|
StopRecording();
|
||||||
|
|
||||||
|
curMovieFilename[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//begin playing an existing movie
|
||||||
|
void FCEUI_LoadMovie(const char *fname, bool _read_only, bool tasedit, int _pauseframe)
|
||||||
|
{
|
||||||
|
//if(!tasedit && !FCEU_IsValidUI(FCEUI_PLAYMOVIE))
|
||||||
|
// return;
|
||||||
|
|
||||||
|
assert(fname);
|
||||||
|
|
||||||
|
//mbg 6/10/08 - we used to call StopMovie here, but that cleared curMovieFilename and gave us crashes...
|
||||||
|
if(movieMode == MOVIEMODE_PLAY)
|
||||||
|
StopPlayback();
|
||||||
|
else if(movieMode == MOVIEMODE_RECORD)
|
||||||
|
StopRecording();
|
||||||
|
//--------------
|
||||||
|
|
||||||
|
currMovieData = MovieData();
|
||||||
|
|
||||||
|
strcpy(curMovieFilename, fname);
|
||||||
|
//FCEUFILE *fp = FCEU_fopen(fname,0,"rb",0);
|
||||||
|
//if (!fp) return;
|
||||||
|
//if(fp->isArchive() && !_read_only) {
|
||||||
|
// FCEU_PrintError("Cannot open a movie in read+write from an archive.");
|
||||||
|
// return;
|
||||||
|
//}
|
||||||
|
|
||||||
|
//LoadFM2(currMovieData, fp->stream, INT_MAX, false);
|
||||||
|
|
||||||
|
|
||||||
|
LoadFM2(currMovieData, &fstream(fname), INT_MAX, false);
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
//fully reload the game to reinitialize everything before playing any movie
|
||||||
|
//poweron(true);
|
||||||
|
|
||||||
|
////WE NEED TO LOAD A SAVESTATE
|
||||||
|
//if(currMovieData.savestate.size() != 0)
|
||||||
|
//{
|
||||||
|
// bool success = MovieData::loadSavestateFrom(&currMovieData.savestate);
|
||||||
|
// if(!success) return;
|
||||||
|
//}
|
||||||
|
|
||||||
|
currFrameCounter = 0;
|
||||||
|
pauseframe = _pauseframe;
|
||||||
|
movie_readonly = _read_only;
|
||||||
|
movieMode = MOVIEMODE_PLAY;
|
||||||
|
currRerecordCount = currMovieData.rerecordCount;
|
||||||
|
|
||||||
|
//if(movie_readonly)
|
||||||
|
// FCEU_DispMessage("Replay started Read-Only.");
|
||||||
|
//else
|
||||||
|
// FCEU_DispMessage("Replay started Read+Write.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void openRecordingMovie(const char* fname)
|
||||||
|
{
|
||||||
|
//osRecordingMovie = FCEUD_UTF8_fstream(fname, "wb");
|
||||||
|
osRecordingMovie = new fstream(fname,std::ios_base::out);
|
||||||
|
/*if(!osRecordingMovie)
|
||||||
|
FCEU_PrintError("Error opening movie output file: %s",fname);*/
|
||||||
|
strcpy(curMovieFilename, fname);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//begin recording a new movie
|
||||||
|
//TODO - BUG - the record-from-another-savestate doesnt work.
|
||||||
|
void FCEUI_SaveMovie(const char *fname, std::wstring author)
|
||||||
|
{
|
||||||
|
//if(!FCEU_IsValidUI(FCEUI_RECORDMOVIE))
|
||||||
|
// return;
|
||||||
|
|
||||||
|
assert(fname);
|
||||||
|
|
||||||
|
FCEUI_StopMovie();
|
||||||
|
|
||||||
|
openRecordingMovie(fname);
|
||||||
|
|
||||||
|
currFrameCounter = 0;
|
||||||
|
//LagCounterReset();
|
||||||
|
|
||||||
|
currMovieData = MovieData();
|
||||||
|
currMovieData.guid.newGuid();
|
||||||
|
|
||||||
|
if(author != L"") currMovieData.comments.push_back(L"author " + author);
|
||||||
|
//currMovieData.romChecksum = GameInfo->MD5;
|
||||||
|
//currMovieData.romFilename = FileBase;
|
||||||
|
|
||||||
|
//todo ?
|
||||||
|
//poweron(true);
|
||||||
|
//else
|
||||||
|
// MovieData::dumpSavestateTo(&currMovieData.savestate,Z_BEST_COMPRESSION);
|
||||||
|
|
||||||
|
//we are going to go ahead and dump the header. from now on we will only be appending frames
|
||||||
|
currMovieData.dump(osRecordingMovie, false);
|
||||||
|
|
||||||
|
movieMode = MOVIEMODE_RECORD;
|
||||||
|
movie_readonly = false;
|
||||||
|
currRerecordCount = 0;
|
||||||
|
|
||||||
|
//FCEU_DispMessage("Movie recording started.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//the main interaction point between the emulator and the movie system.
|
||||||
|
//either dumps the current joystick state or loads one state from the movie
|
||||||
|
void FCEUMOV_AddInputState()
|
||||||
|
{
|
||||||
|
//todo - for tasedit, either dump or load depending on whether input recording is enabled
|
||||||
|
//or something like that
|
||||||
|
//(input recording is just like standard read+write movie recording with input taken from gamepad)
|
||||||
|
//otherwise, it will come from the tasedit data.
|
||||||
|
|
||||||
|
if(movieMode == MOVIEMODE_PLAY)
|
||||||
|
{
|
||||||
|
//stop when we run out of frames
|
||||||
|
if(currFrameCounter == currMovieData.records.size())
|
||||||
|
{
|
||||||
|
StopPlayback();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MovieRecord* mr = &currMovieData.records[currFrameCounter];
|
||||||
|
|
||||||
|
//reset if necessary
|
||||||
|
if(mr->command_reset())
|
||||||
|
{}
|
||||||
|
//ResetNES();
|
||||||
|
|
||||||
|
NDS_setPadFromMovie(mr->pad);
|
||||||
|
}
|
||||||
|
|
||||||
|
//if we are on the last frame, then pause the emulator if the player requested it
|
||||||
|
if(currFrameCounter == currMovieData.records.size()-1)
|
||||||
|
{
|
||||||
|
/*if(FCEUD_PauseAfterPlayback())
|
||||||
|
{
|
||||||
|
FCEUI_ToggleEmulationPause();
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
//pause the movie at a specified frame
|
||||||
|
//if(FCEUMOV_ShouldPause() && FCEUI_EmulationPaused()==0)
|
||||||
|
//{
|
||||||
|
// FCEUI_ToggleEmulationPause();
|
||||||
|
// FCEU_DispMessage("Paused at specified movie frame");
|
||||||
|
//}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if(movieMode == MOVIEMODE_RECORD)
|
||||||
|
{
|
||||||
|
MovieRecord mr;
|
||||||
|
|
||||||
|
mr.commands = 0;
|
||||||
|
mr.pad = nds.pad;
|
||||||
|
if(nds.isTouch) {
|
||||||
|
mr.touch.x = nds.touchX;
|
||||||
|
mr.touch.y = nds.touchY;
|
||||||
|
mr.touch.touch = 1;
|
||||||
|
} else {
|
||||||
|
mr.touch.x = 0;
|
||||||
|
mr.touch.y = 0;
|
||||||
|
mr.touch.touch = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mr.dump(&currMovieData, osRecordingMovie,currMovieData.records.size());
|
||||||
|
currMovieData.records.push_back(mr);
|
||||||
|
}
|
||||||
|
|
||||||
|
currFrameCounter++;
|
||||||
|
|
||||||
|
/*extern uint8 joy[4];
|
||||||
|
memcpy(&cur_input_display,joy,4);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
void FCEUMOV_AddCommand(int cmd)
|
||||||
|
{
|
||||||
|
// do nothing if not recording a movie
|
||||||
|
if(movieMode != MOVIEMODE_RECORD)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//printf("%d\n",cmd);
|
||||||
|
|
||||||
|
//MBG TODO BIG TODO TODO TODO
|
||||||
|
//DoEncode((cmd>>3)&0x3,cmd&0x7,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int FCEUMOV_WriteState(std::ostream* os)
|
||||||
|
{
|
||||||
|
//we are supposed to dump the movie data into the savestate
|
||||||
|
if(movieMode == MOVIEMODE_RECORD || movieMode == MOVIEMODE_PLAY)
|
||||||
|
return currMovieData.dump(os, true);
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//TODO EVERYTHING BELOW
|
||||||
|
|
||||||
|
static bool load_successful;
|
||||||
|
|
||||||
|
bool FCEUMOV_ReadState(std::istream* is, uint32 size)
|
||||||
|
{
|
||||||
|
load_successful = false;
|
||||||
|
|
||||||
|
//a little rule: cant load states in read+write mode with a movie from an archive.
|
||||||
|
//so we are going to switch it to readonly mode in that case
|
||||||
|
if(!movie_readonly
|
||||||
|
//*&& FCEU_isFileInArchive(curMovieFilename)*/
|
||||||
|
) {
|
||||||
|
FCEU_PrintError("Cannot loadstate in Read+Write with movie from archive. Movie is now Read-Only.");
|
||||||
|
movie_readonly = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MovieData tempMovieData = MovieData();
|
||||||
|
std::ios::pos_type curr = is->tellg();
|
||||||
|
if(!LoadFM2(tempMovieData, is, size, false)) {
|
||||||
|
|
||||||
|
/*is->seekg((uint32)curr+size);
|
||||||
|
extern bool FCEU_state_loading_old_format;
|
||||||
|
if(FCEU_state_loading_old_format) {
|
||||||
|
if(movieMode == MOVIEMODE_PLAY || movieMode == MOVIEMODE_RECORD) {
|
||||||
|
FCEUI_StopMovie();
|
||||||
|
FCEU_PrintError("You have tried to use an old savestate while playing a movie. This is unsupported (since the old savestate has old-format movie data in it which can't be converted on the fly)");
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//complex TAS logic for when a savestate is loaded:
|
||||||
|
//----------------
|
||||||
|
//if we are playing or recording and toggled read-only:
|
||||||
|
// then, the movie we are playing must match the guid of the one stored in the savestate or else error.
|
||||||
|
// the savestate is assumed to be in the same timeline as the current movie.
|
||||||
|
// if the current movie is not long enough to get to the savestate's frame#, then it is an error.
|
||||||
|
// the movie contained in the savestate will be discarded.
|
||||||
|
// the emulator will be put into play mode.
|
||||||
|
//if we are playing or recording and toggled read+write
|
||||||
|
// then, the movie we are playing must match the guid of the one stored in the savestate or else error.
|
||||||
|
// the movie contained in the savestate will be loaded into memory
|
||||||
|
// the frames in the movie after the savestate frame will be discarded
|
||||||
|
// the in-memory movie will have its rerecord count incremented
|
||||||
|
// the in-memory movie will be dumped to disk as fcm.
|
||||||
|
// the emulator will be put into record mode.
|
||||||
|
//if we are doing neither:
|
||||||
|
// then, we must discard this movie and just load the savestate
|
||||||
|
|
||||||
|
|
||||||
|
if(movieMode == MOVIEMODE_PLAY || movieMode == MOVIEMODE_RECORD)
|
||||||
|
{
|
||||||
|
//handle moviefile mismatch
|
||||||
|
if(tempMovieData.guid != currMovieData.guid)
|
||||||
|
{
|
||||||
|
//mbg 8/18/08 - this code can be used to turn the error message into an OK/CANCEL
|
||||||
|
#ifdef WIN32
|
||||||
|
//std::string msg = "There is a mismatch between savestate's movie and current movie.\ncurrent: " + currMovieData.guid.toString() + "\nsavestate: " + tempMovieData.guid.toString() + "\n\nThis means that you have loaded a savestate belonging to a different movie than the one you are playing now.\n\nContinue loading this savestate anyway?";
|
||||||
|
//extern HWND pwindow;
|
||||||
|
//int result = MessageBox(pwindow,msg.c_str(),"Error loading savestate",MB_OKCANCEL);
|
||||||
|
//if(result == IDCANCEL)
|
||||||
|
// return false;
|
||||||
|
#else
|
||||||
|
FCEU_PrintError("Mismatch between savestate's movie and current movie.\ncurrent: %s\nsavestate: %s\n",currMovieData.guid.toString().c_str(),tempMovieData.guid.toString().c_str());
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
closeRecordingMovie();
|
||||||
|
|
||||||
|
if(movie_readonly)
|
||||||
|
{
|
||||||
|
//if the frame counter is longer than our current movie, then error
|
||||||
|
if(currFrameCounter > (int)currMovieData.records.size())
|
||||||
|
{
|
||||||
|
FCEU_PrintError("Savestate is from a frame (%d) after the final frame in the movie (%d). This is not permitted.", currFrameCounter, currMovieData.records.size()-1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
movieMode = MOVIEMODE_PLAY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//truncate before we copy, just to save some time
|
||||||
|
tempMovieData.truncateAt(currFrameCounter);
|
||||||
|
currMovieData = tempMovieData;
|
||||||
|
|
||||||
|
#ifdef _S9XLUA_H
|
||||||
|
if(!FCEU_LuaRerecordCountSkip())
|
||||||
|
currRerecordCount++;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
currMovieData.rerecordCount = currRerecordCount;
|
||||||
|
|
||||||
|
openRecordingMovie(curMovieFilename);
|
||||||
|
currMovieData.dump(osRecordingMovie, false);
|
||||||
|
movieMode = MOVIEMODE_RECORD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
load_successful = true;
|
||||||
|
|
||||||
|
//// Maximus: Show the last input combination entered from the
|
||||||
|
//// movie within the state
|
||||||
|
//if(current!=0) // <- mz: only if playing or recording a movie
|
||||||
|
// memcpy(&cur_input_display, joop, 4);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FCEUMOV_PreLoad(void)
|
||||||
|
{
|
||||||
|
load_successful=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FCEUMOV_PostLoad(void)
|
||||||
|
{
|
||||||
|
if(movieMode == MOVIEMODE_INACTIVE)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return load_successful;
|
||||||
|
}
|
Loading…
Reference in New Issue