void FCEUSS_Save(char *fname) { FILE *st=NULL; char *fn; if(geniestage==1) { FCEU_DispMessage("Cannot save FCS in GG screen."); return; } if(fname) st=FCEUD_UTF8fopen(fname, "wb"); else { st=FCEUD_UTF8fopen(fn=FCEU_MakeFName(FCEUMKF_STATE,CurrentState,0),"wb"); free(fn); } if(st == NULL) { FCEU_DispMessage("State %d save error.",CurrentState); return; } FCEUSS_SaveFP(st); SaveStateStatus[CurrentState]=1; fclose(st); FCEU_DispMessage("State %d saved.",CurrentState); }
void FCEUI_LoadState(char *fname) { StateShow = 0; FCEUMOV_Stop(); /* For network play, be load the state locally, and then save the state to a temporary file, and send that. This insures that if an older state is loaded that is missing some information expected in newer save states, desynchronization won't occur(at least not from this ;)). */ if (FCEUSS_Load(fname)) if (FCEUnetplay) { char *fn = FCEU_MakeFName(FCEUMKF_NPTEMP, 0, 0); MEM_TYPE *fp; if ((fp = fopen(fn, "wb"))) { if (FCEUSS_SaveFP(fp)) { fclose(fp); FCEUNET_SendFile(FCEUNPCMD_LOADSTATE, fn); } else fclose(fp); unlink(fn); } free(fn); } }
void FCEUSS_Save(char *fname) { MEM_TYPE *st = NULL; char *fn; if (geniestage == 1) { FCEU_DispMessage("Cannot save FCS in GG screen."); return; } #ifdef HAVE_MEMSTREAM st = memstream_open(1); #else if (fname) st = FCEUD_UTF8fopen(fname, "wb"); else { st = FCEUD_UTF8fopen(fn = FCEU_MakeFName(FCEUMKF_STATE, CurrentState, 0), "wb"); free(fn); } if (st == NULL) { FCEU_DispMessage("State %d save error.", CurrentState); return; } #endif FCEUSS_SaveFP(st); SaveStateStatus[CurrentState] = 1; fclose(st); #ifndef HAVE_MEMSTREAM FCEU_DispMessage("State %d saved.", CurrentState); #endif }
void NetplayUpdate(uint8 *joyp) { static uint8 buf[5]; /* 4 play states, + command/extra byte */ static uint8 joypb[4]; memcpy(joypb,joyp,4); /* This shouldn't happen, but just in case. 0xFF is used as a command escape elsewhere. */ if(joypb[0] == 0xFF) joypb[0] = 0xF; #ifdef NETWORK if(!netdcount) if(!FCEUD_SendData(joypb,numlocal)) { NetError(); return; } if(!netdcount) do { if(!FCEUD_RecvData(buf,5)) { NetError(); return; } switch(buf[4]) { default: FCEU_DoSimpleCommand(buf[4]);break; case FCEUNPCMD_TEXT: { uint8 *tbuf; uint32 len = FCEU_de32lsb(buf); if(len > 100000) // Insanity check! { NetError(); return; } tbuf = malloc(len + 1); tbuf[len] = 0; if(!FCEUD_RecvData(tbuf, len)) { NetError(); free(tbuf); return; } FCEUD_NetplayText(tbuf); free(tbuf); } break; case FCEUNPCMD_SAVESTATE: { 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 = FCEU_MakeFName(FCEUMKF_CHEAT,0,0); //if(! FCEUNET_SendFile(FCEUNPCMD_LOADCHEATS,fn); // { // free(fn); // return; // } free(fn); if(!FCEUnetplay) return; fn = FCEU_MakeFName(FCEUMKF_NPTEMP,0,0); fp = fopen(fn, "wb"); if(FCEUSS_SaveFP(fp)) { 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; case FCEUNPCMD_LOADCHEATS: { FILE *fp = FetchFile(FCEU_de32lsb(buf)); if(!fp) return; FCEU_FlushGameCheats(0,1); FCEU_LoadGameCheats(fp); } break; case FCEUNPCMD_LOADSTATE: { FILE *fp = FetchFile(FCEU_de32lsb(buf)); if(!fp) return; if(FCEUSS_LoadFP(fp)) { fclose(fp); FCEU_DispMessage("Remote state loaded."); } else FCEUD_PrintError("File error. (K)ill, (M)aim, (D)estroy?"); } break; } } while(buf[4]); #endif netdcount=(netdcount+1)%netdivisor; memcpy(netjoy,buf,4); *(uint32 *)joyp=*(uint32 *)netjoy; }
void FCEUI_SaveMovie(char *fname, uint8 flags, const char* metadata) { FILE *fp; char *fn; int poweron=0; uint8 padding[4] = {0,0,0,0}; int n_padding; FCEUI_StopMovie(); char origname[512]; if(fname) { fp = FCEUD_UTF8fopen(fname, "wb"); strcpy(origname,fname); } else { fp=FCEUD_UTF8fopen(fn=FCEU_MakeFName(FCEUMKF_MOVIE,CurrentMovie,0),"wb"); strcpy(origname,fn); free(fn); } if(!fp) return; // don't need the movieSyncHackOn sync hack for newly recorded movies flags |= MOVIE_FLAG_NOSYNCHACK; resetDMCacc=movieSyncHackOn=0; // add PAL flag if(FCEUI_GetCurrentVidSystem(0,0)) flags |= MOVIE_FLAG_PAL; if(flags & MOVIE_FLAG_FROM_POWERON) { poweron=1; flags &= ~MOVIE_FLAG_FROM_POWERON; flags |= MOVIE_FLAG_FROM_RESET; } // write header write32le(MOVIE_MAGIC, fp); write32le(MOVIE_VERSION, fp); fputc(flags, fp); fputc(0, fp); // reserved fputc(0, fp); // reserved fputc(0, fp); // reserved write32le(0, fp); // leave room for length frames write32le(0, fp); // leave room for rerecord count write32le(0, fp); // leave room for movie data size write32le(0, fp); // leave room for savestate_offset write32le(0, fp); // leave room for offset_to_controller_data fwrite(FCEUGameInfo->MD5, 1, 16, fp); // write ROM checksum write32le(FCEU_VERSION_NUMERIC, fp); // write emu version used fputs(FileBase, fp); // write ROM name used fputc(0, fp); if(metadata) { if(strlen(metadata) < MOVIE_MAX_METADATA) fputs(metadata, fp); else fwrite(metadata, 1, MOVIE_MAX_METADATA-1, fp); } fputc(0, fp); // add padding n_padding = (4 - (ftell(fp) & 0x3)) & 0x3; fwrite(padding, 1, n_padding, fp); if(flags & MOVIE_FLAG_FROM_RESET) { if(poweron) { // make a for-movie-recording power-on clear the game's save data, too // (note: FCEU makes a save state immediately after this and that loads that on movie playback) extern char lastLoadedGameName [2048]; extern int disableBatteryLoading, suppressAddPowerCommand; suppressAddPowerCommand=1; disableBatteryLoading=1; suppressMovieStop=1; { // NOTE: this will NOT write an FCEUNPCMD_POWER into the movie file FCEUGI * gi = FCEUI_LoadGame(lastLoadedGameName); if(!gi) PowerNES(); // and neither will this, if it can even happen } suppressMovieStop=0; disableBatteryLoading=0; suppressAddPowerCommand=0; } } savestate_offset = ftell(fp); FCEUSS_SaveFP(fp); fseek(fp, 0, SEEK_END); ResetInputTypes(); // add padding n_padding = (4 - (ftell(fp) & 0x3)) & 0x3; fwrite(padding, 1, n_padding, fp); firstframeoffset = ftell(fp); // finish header fseek(fp, 24, SEEK_SET); // offset_to_savestate offset write32le(savestate_offset, fp); write32le(firstframeoffset, fp); fseek(fp, firstframeoffset, SEEK_SET); // set recording flag current=CurrentMovie; movie_readonly = 0; frameptr = 0; framecount = 0; rerecord_count = 0; slots[current] = fp; memset(joop,0,sizeof(joop)); current++; framets=0; nextd = -1; // trigger a reset if(flags & MOVIE_FLAG_FROM_RESET) { if(poweron) { PowerNES(); // NOTE: this will write an FCEUNPCMD_POWER into the movie file } else ResetNES(); // NOTE: this will write an FCEUNPCMD_RESET into the movie file } if(!fname) FCEUI_SelectMovie(CurrentMovie,1); /* Quick hack to display status. */ else FCEU_DispMessage("Movie recording started."); strcpy(curMovieFilename, origname); }