diff --git a/src/drivers/win/tasedit.cpp b/src/drivers/win/tasedit.cpp index 16c60c34..0715861f 100644 --- a/src/drivers/win/tasedit.cpp +++ b/src/drivers/win/tasedit.cpp @@ -311,7 +311,7 @@ static void Export() if(GetSaveFileName(&ofn)) { fstream* osRecordingMovie = FCEUD_UTF8_fstream(ofn.lpstrFile, "wb"); - currMovieData.dump(osRecordingMovie); + currMovieData.dump(osRecordingMovie,false); delete osRecordingMovie; osRecordingMovie = 0; } diff --git a/src/movie.cpp b/src/movie.cpp index 873fe552..b74441ad 100644 --- a/src/movie.cpp +++ b/src/movie.cpp @@ -127,18 +127,6 @@ void MovieRecord::parseJoy(std::istream* is, uint8& joystate) joystate <<= 1; joystate |= ((buf[i]!=' ')?1:0); } - - //older, slower(?) way: - - //joystate = 0; - //for(int bit=7;bit>=0;bit--) - //{ - // int c = is->get(); - // if(c == -1) - // return; - // if(c != ' ') - // joystate |= (1<ports[port] == SI_ZAPPER) { - int x,y,b,bogo; - uint64 zaphit; - //*is >> x >> y >> b >> bogo >> zaphit; zappers[port].x = uint32DecFromIstream(is); zappers[port].y = uint32DecFromIstream(is); zappers[port].b = uint32DecFromIstream(is); @@ -186,6 +171,67 @@ void MovieRecord::parse(MovieData* md, std::istream* is) //should be left at a newline } + +bool MovieRecord::parseBinary(MovieData* md, std::istream* is) +{ + commands = (uint8)is->get(); + + //check for eof + if(is->gcount() != 1) return false; + + if(md->fourscore) + { + is->read((char*)&joysticks,4); + } + else + { + for(int port=0;port<2;port++) + { + if(md->ports[port] == SI_GAMEPAD) + joysticks[port] = (uint8)is->get(); + else if(md->ports[port] == SI_ZAPPER) + { + zappers[port].x = (uint8)is->get(); + zappers[port].y = (uint8)is->get(); + zappers[port].b = (uint8)is->get(); + zappers[port].bogo = (uint8)is->get(); + zappers[port].zaphit = uint64DecFromIstream(is); + } + } + } + + return true; +} + + +void MovieRecord::dumpBinary(MovieData* md, std::ostream* os, int index) +{ + os->put(commands); + if(md->fourscore) + { + os->put(joysticks[0]); + os->put(joysticks[1]); + os->put(joysticks[2]); + os->put(joysticks[3]); + } + else + { + for(int port=0;port<2;port++) + { + if(md->ports[port] == SI_GAMEPAD) + os->put(joysticks[port]); + else if(md->ports[port] == SI_ZAPPER) + { + os->put(zappers[port].x); + os->put(zappers[port].y); + os->put(zappers[port].b); + os->put(zappers[port].bogo); + write64le(zappers[port].zaphit, os); + } + } + } +} + void MovieRecord::dump(MovieData* md, std::ostream* os, int index) { //todo: if we want frame numbers in the output (which we dont since we couldnt cut and paste in movies) @@ -239,6 +285,7 @@ MovieData::MovieData() , palFlag(false) , poweronFlag(false) , resetFlag(false) + , binaryFlag(false) , recordCount(1) , greenZoneCount(0) { @@ -279,6 +326,8 @@ void MovieData::installValue(std::string& key, std::string& val) installInt(val,ports[1]); else if(key == "port2") installInt(val,ports[2]); + else if(key == "binary") + installBool(val,binaryFlag); else if(key == "savestate") { int len = HexStringToBytesLength(val); @@ -290,7 +339,7 @@ void MovieData::installValue(std::string& key, std::string& val) } } -int MovieData::dump(std::ostream *os) +int MovieData::dump(std::ostream *os, bool binary) { int start = os->tellp(); *os << "version " << version << endl; @@ -306,11 +355,23 @@ int MovieData::dump(std::ostream *os) *os << "port0 " << ports[0] << endl; *os << "port1 " << ports[1] << endl; *os << "port2 " << ports[2] << endl; + + if(binary) + *os << "binary 1" << endl; if(savestate.size() != 0) *os << "savestate " << BytesToString(&savestate[0],savestate.size()) << endl; - for(int i=0;i<(int)records.size();i++) - records[i].dump(this,os,i); + 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; } @@ -348,6 +409,43 @@ bool FCEUMOV_Mode(int modemask) return FCEUMOV_Mode((EMOVIEMODE)modemask); } +static void LoadFM2_binarychunk(MovieData& movieData, std::istream* fp, int size) +{ + int recordsize = 1; //1 for the command + if(movieData.fourscore) + recordsize += 4; //4 joysticks + else + { + for(int i=0;i<2;i++) + { + switch(movieData.ports[i]) + { + case SI_GAMEPAD: recordsize++; break; + case SI_ZAPPER: recordsize+=10; break; + } + } + } + + //find out how much remains in the file + int curr = fp->tellg(); + fp->seekg(0,std::ios::end); + int end = fp->tellg(); + int flen = end-curr; + fp->seekg(curr,std::ios::beg); + + //the amount todo is the min of the limiting size we received and the remaining contents of the file + int todo = std::min(size, flen); + + int numRecords = todo/recordsize; + movieData.records.resize(numRecords); + for(int i=0;itellg(); - record.parse(&movieData, fp); + movieData.records[currcount].parse(&movieData, fp); int postparse = fp->tellg(); size -= (postparse-preparse); - movieData.records.push_back(record); state = NEWLINE; break; } @@ -660,7 +763,7 @@ void FCEUI_SaveMovie(char *fname, uint8 flags) } //we are going to go ahead and dump the header. from now on we will only be appending frames - currMovieData.dump(osRecordingMovie); + currMovieData.dump(osRecordingMovie, false); //todo - think about this //ResetInputTypes(); @@ -762,7 +865,7 @@ void FCEU_DrawMovies(uint8 *XBuf) char counterbuf[32] = {0}; if(movieMode == MOVIEMODE_PLAY) sprintf(counterbuf,"%d/%d",currFrameCounter,currMovieData.records.size()); - else if(movieMode == MOVIEMODE_RECORD) + else if(movieMode == MOVIEMODE_RECORD) sprintf(counterbuf,"%d",currMovieData.records.size()); if(counterbuf[0]) @@ -774,7 +877,7 @@ 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); + return currMovieData.dump(os, true); else return 0; } @@ -845,7 +948,7 @@ bool FCEUMOV_ReadState(std::istream* is, uint32 size) currMovieData.recordCount++; openRecordingMovie(curMovieFilename); - currMovieData.dump(osRecordingMovie); + currMovieData.dump(osRecordingMovie, false); movieMode = MOVIEMODE_RECORD; } } diff --git a/src/movie.h b/src/movie.h index 56e34520..83557b48 100644 --- a/src/movie.h +++ b/src/movie.h @@ -93,7 +93,9 @@ public: std::vector savestate; void parse(MovieData* md, std::istream* is); + bool parseBinary(MovieData* md, std::istream* is); void dump(MovieData* md, std::ostream* os, int index); + void dumpBinary(MovieData* md, std::ostream* os, int index); void parseJoy(std::istream* is, uint8& joystate); void dumpJoy(std::ostream* os, uint8 joystate); @@ -123,6 +125,9 @@ public: int recordCount; FCEU_Guid guid; + //was the frame data stored in binary? + bool binaryFlag; + //which ports are defined for the movie int ports[3]; //whether fourscore is enabled @@ -164,7 +169,7 @@ public: void truncateAt(int frame); void installValue(std::string& key, std::string& val); - int dump(std::ostream* os); + int dump(std::ostream* os, bool binary); void clearRecordRange(int start, int len); static bool loadSavestateFrom(std::vector* buf); diff --git a/src/netplay.cpp b/src/netplay.cpp index 452986e7..9980b141 100644 --- a/src/netplay.cpp +++ b/src/netplay.cpp @@ -256,46 +256,49 @@ void NetplayUpdate(uint8 *joyp) break; case FCEUNPCMD_SAVESTATE: { - char *fn; - FILE *fp; + //mbg todo netplay + //char *fn; + //FILE *fp; - /* Send the cheats first, then the save state, since - there might be a frame or two in between the two sendfile - commands on the server side. - */ - fn = strdup(FCEU_MakeFName(FCEUMKF_CHEAT,0,0).c_str()); - //if(! - FCEUNET_SendFile(FCEUNPCMD_LOADCHEATS,fn); + ////Send the cheats first, then the save state, since + ////there might be a frame or two in between the two sendfile + ////commands on the server side. - // { - // free(fn); - // return; - // } - free(fn); - if(!FCEUnetplay) return; + //fn = strdup(FCEU_MakeFName(FCEUMKF_CHEAT,0,0).c_str()); - fn = strdup(FCEU_MakeFName(FCEUMKF_NPTEMP,0,0).c_str()); - fp = fopen(fn, "wb"); - if(FCEUSS_SaveFP(fp,Z_BEST_COMPRESSION)) - { - fclose(fp); - if(!FCEUNET_SendFile(FCEUNPCMD_LOADSTATE, fn)) - { - unlink(fn); - free(fn); - return; - } - unlink(fn); - free(fn); - } - else - { - fclose(fp); - FCEUD_PrintError("File error. (K)ill, (M)aim, (D)estroy? Now!"); - unlink(fn); - free(fn); - return; - } + ////why?????? + ////if(! + // FCEUNET_SendFile(FCEUNPCMD_LOADCHEATS,fn); + //// { + //// free(fn); + //// return; + //// } + + //free(fn); + //if(!FCEUnetplay) return; + + //fn = strdup(FCEU_MakeFName(FCEUMKF_NPTEMP,0,0).c_str()); + //fp = fopen(fn, "wb"); + //if(FCEUSS_SaveFP(fp,Z_BEST_COMPRESSION)) + //{ + // fclose(fp); + // if(!FCEUNET_SendFile(FCEUNPCMD_LOADSTATE, fn)) + // { + // unlink(fn); + // free(fn); + // return; + // } + // unlink(fn); + // free(fn); + //} + //else + //{ + // fclose(fp); + // FCEUD_PrintError("File error. (K)ill, (M)aim, (D)estroy? Now!"); + // unlink(fn); + // free(fn); + // return; + //} } break; diff --git a/src/state.cpp b/src/state.cpp index 7db233f3..94b9573d 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -314,13 +314,6 @@ static bool ReadStateChunks(std::istream* is, int32 totalsize) int CurrentState=1; extern int geniestage; -bool FCEUSS_SaveFP(FILE* fp, int compressionLevel) -{ - memorystream ms; - bool ret = FCEUSS_SaveMS(&ms,compressionLevel); - fwrite(ms.buf(),1,ms.size(),fp); - return ret; -} bool FCEUSS_SaveMS(std::ostream* outstream, int compressionLevel) { @@ -688,7 +681,8 @@ void FCEUI_LoadState(char *fname) if(FCEUSS_Load(fname)) { - if(FCEUnetplay) + //mbg todo netplay + /*if(FCEUnetplay) { char *fn = strdup(FCEU_MakeFName(FCEUMKF_NPTEMP, 0, 0).c_str()); FILE *fp; @@ -709,7 +703,7 @@ void FCEUI_LoadState(char *fname) } free(fn); - } + }*/ } else { diff --git a/src/state.h b/src/state.h index 5669a8cb..09f63b09 100644 --- a/src/state.h +++ b/src/state.h @@ -31,7 +31,6 @@ bool FCEUSS_Load(char *); //zlib values: 0 (none) through 9 (max) or -1 (default) bool FCEUSS_SaveMS(std::ostream* outstream, int compressionLevel); -bool FCEUSS_SaveFP(FILE* fp, int compressionLevel); bool FCEUSS_LoadFP(std::istream* is, ENUM_SSLOADPARAMS params); diff --git a/src/utils/endian.cpp b/src/utils/endian.cpp index 3c920900..a948621e 100644 --- a/src/utils/endian.cpp +++ b/src/utils/endian.cpp @@ -78,6 +78,22 @@ int write32le(uint32 b, std::ostream* os) return 4; } +int write64le(uint64 b, std::ostream* os) +{ + uint8 s[8]; + s[0]=b; + s[1]=b>>8; + s[2]=b>>16; + s[3]=b>>24; + s[4]=b>>32; + s[5]=b>>40; + s[6]=b>>48; + s[7]=b>>56; + os->write((char*)&s,8); + return 4; +} + + ///reads a little endian 32bit value from the specified file int read32le(uint32 *Bufo, FILE *fp) { @@ -92,6 +108,21 @@ int read32le(uint32 *Bufo, FILE *fp) return 1; } +///reads a little endian 64bit value from the specified file +int read64le(uint64 *Bufo, std::istream *is) +{ + uint64 buf; + if(is->read((char*)&buf,8).gcount() != 8) + return 0; +#ifdef LSB_FIRST + *Bufo=buf; +#else + *Bufo = FCEU_de64lsb(&buf) +#endif + return 1; +} + + int read32le(uint32 *Bufo, std::istream *is) { uint32 buf; diff --git a/src/utils/endian.h b/src/utils/endian.h index 2b70d9e4..a6bf64e7 100644 --- a/src/utils/endian.h +++ b/src/utils/endian.h @@ -8,6 +8,8 @@ int write16le(uint16 b, FILE *fp); int write32le(uint32 b, FILE *fp); int write32le(uint32 b, std::ostream* os); +int write64le(uint64 b, std::ostream* os); +int read64le(uint64 *Bufo, std::istream *is); int read32le(uint32 *Bufo, std::istream *is); int read32le(uint32 *Bufo, FILE *fp); void FlipByteOrder(uint8 *src, uint32 count);