clean up movie some code; no longer write savestate with play-from-poweron movies; change main logging format to text (the header still needs to be changed)

This commit is contained in:
zeromus 2008-05-22 07:43:48 +00:00
parent 9477c03c09
commit 047808ba93
8 changed files with 909 additions and 824 deletions

View File

@ -23,15 +23,17 @@ FCEU MM - CaH4e3\n\
FCEU TAS - blip & nitsuja\n\
FCEU TAS+ - Luke Gustafson\n\
FCEUX\n\
- CaH4e3, Luke Gustafson\n\
- Matthew Gambrell, Sebastian Porst\n\
- rheiny, zeromus\n\
- CaH4e3, Luke Gustafson, Sebastian Porst\n\
- adelikat, _mz\n\
\n\
"__TIME__" "__DATE__"\n";
if(aboutString) return aboutString;
const char *compilerString = FCEUD_GetCompilerString();
//allocate the string and concatenate the template with the compiler string
if(aboutString) free(aboutString);
aboutString = (char*)malloc(strlen(aboutTemplate) + strlen(compilerString) + 1);
sprintf(aboutString,"%s%s",aboutTemplate,compilerString);
return aboutString;

View File

@ -175,9 +175,11 @@ void FCEUI_LoadState(char *fname);
void FCEUD_SaveStateAs(void);
void FCEUD_LoadStateFrom(void);
#define MOVIE_FLAG_FROM_RESET (1<<1)
//movie was recorded from poweron. the alternative is from a savestate
#define MOVIE_FLAG_FROM_POWERON (1<<3)
#define MOVIE_FLAG_PAL (1<<2)
#define MOVIE_FLAG_FROM_POWERON (1<<3) // value is temporary onle, gets converted to reset
#define MOVIE_MAX_METADATA 512
typedef struct

View File

@ -223,7 +223,7 @@ void UpdateReplayDialog(HWND hwndDlg)
EnableWindow(GetDlgItem(hwndDlg,IDC_CHECK_READONLY),(info.read_only)? FALSE : TRUE); // disable read-only checkbox if the file access is read-only
SendDlgItemMessage(hwndDlg,IDC_CHECK_READONLY,BM_SETCHECK,info.read_only ? BST_CHECKED : (ReplayDialogReadOnlyStatus ? BST_CHECKED : BST_UNCHECKED), 0);
SetWindowText(GetDlgItem(hwndDlg,IDC_LABEL_RECORDEDFROM),(info.flags & MOVIE_FLAG_FROM_RESET) ? "Reset or Power-On" : "Savestate");
SetWindowText(GetDlgItem(hwndDlg,IDC_LABEL_RECORDEDFROM),(info.flags & MOVIE_FLAG_FROM_POWERON) ? "Power-On" : "Savestate");
if(info.movie_version > 1)
{
char emuStr[128];
@ -863,10 +863,9 @@ void FCEUD_MovieRecordTo()
free(p.szSavestateFilename);
}
FCEUI_SaveMovie(
p.szFilename,
(p.recordFrom == 0) ? MOVIE_FLAG_FROM_POWERON : ((p.recordFrom == 1) ? MOVIE_FLAG_FROM_RESET : 0),
meta);
uint8 flags = 0;
if(p.recordFrom == 0) flags = MOVIE_FLAG_FROM_POWERON;
FCEUI_SaveMovie(p.szFilename, flags, meta);
}
if(p.szFilename)

View File

@ -506,7 +506,7 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
if(EmulationPaused&2)
EmulationPaused &= ~1; // clear paused flag temporarily (frame advance)
else if(EmulationPaused&1 || FCEU_BotMode())
else if((EmulationPaused&1) || FCEU_BotMode())
{
memcpy(XBuf, XBackBuf, 256*256);
FCEU_PutImage();

View File

@ -1,7 +1,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <unistd.h> //mbgm erge 7/17/06 removed
#include <assert.h>
#ifdef MSVC
#include <windows.h>
#endif
@ -53,7 +54,7 @@ struct MovieHeader
static int current = 0; // > 0 for recording, < 0 for playback
static FILE *slots[10]={0};
static uint8 joop[4];
static uint8 joop[4]; //mbg 5/22/08 - seems to be a snapshot of the joystates for delta compression
static uint32 framets = 0;
static uint32 frameptr = 0;
static uint8* moviedata = NULL;
@ -462,11 +463,6 @@ strcpy(origname,fname);
read32le(&moviedatasize, fp);
read32le(&savestate_offset, fp);
read32le(&firstframeoffset, fp);
if(fseek(fp, savestate_offset, SEEK_SET))
{
fclose(fp);
return;
}
// FCEU_PrintError("flags[0] & MOVIE_FLAG_NOSYNCHACK=%d",flags[0] & MOVIE_FLAG_NOSYNCHACK);
if(flags[0] & MOVIE_FLAG_NOSYNCHACK)
@ -500,7 +496,28 @@ strcpy(origname,fname);
suppressAddPowerCommand=0;
}
if(!FCEUSS_LoadFP(fp,1)) return;
if(flags[0] & MOVIE_FLAG_FROM_POWERON)
{
//don't need to load a savestate
//there shouldn't be a savestate!
if(savestate_offset != 0xFFFFFFFF)
FCEU_PrintError("Savestate found in a start-from-poweron movie!");
}
else
{
if(savestate_offset == 0xFFFFFFFF)
FCEU_PrintError("No savestate found in a start-from-savestate movie!");
if(fseek(fp, savestate_offset, SEEK_SET))
{
fclose(fp);
return;
}
if(!FCEUSS_LoadFP(fp,SSLOADPARAM_BACKUP))
return;
}
if(flags[0] & MOVIE_FLAG_PAL)
{
FCEUI_SetVidSystem(1);
@ -539,7 +556,6 @@ 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;
@ -568,13 +584,6 @@ void FCEUI_SaveMovie(char *fname, uint8 flags, const char* metadata)
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);
@ -604,9 +613,7 @@ void FCEUI_SaveMovie(char *fname, uint8 flags, const char* metadata)
n_padding = (4 - (ftell(fp) & 0x3)) & 0x3;
fwrite(padding, 1, n_padding, fp);
if(flags & MOVIE_FLAG_FROM_RESET)
{
if(poweron)
if(flags & MOVIE_FLAG_FROM_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)
@ -624,11 +631,16 @@ void FCEUI_SaveMovie(char *fname, uint8 flags, const char* metadata)
suppressMovieStop=0;
disableBatteryLoading=0;
suppressAddPowerCommand=0;
}
}
//no savestate
savestate_offset = 0xFFFFFFFF;
}
else
{
savestate_offset = ftell(fp);
FCEUSS_SaveFP(fp);
}
fseek(fp, 0, SEEK_END);
ResetInputTypes();
@ -659,16 +671,18 @@ void FCEUI_SaveMovie(char *fname, uint8 flags, const char* metadata)
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
}
//mbg 5/22/08 - I didnt delete this because I thought it was interesting
//// 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
@ -725,7 +739,8 @@ static void DoEncode(int joy, int button, int dummy)
}
}
// TODO: make this function legible! (what are all these magic numbers and weirdly named variables and crazy unexplained loops?)
//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_AddJoy(uint8 *js, int SkipFlush)
{
int x,y;
@ -734,78 +749,131 @@ void FCEUMOV_AddJoy(uint8 *js, int SkipFlush)
if(current < 0) // Playback
{
while(nextts == framets || nextd == -1)
//while(nextts == framets || nextd == -1)
//{
// int tmp,ti;
// uint8 d;
// if(nextd != -1)
// {
// if(nextd&0x80)
// {
// //puts("Egads");
// FCEU_DoSimpleCommand(nextd&0x1F);
// }
// else
// joop[(nextd >> 3)&0x3] ^= 1 << (nextd&0x7);
// }
// tmp = movie_readchar();
// d = tmp;
// if(tmp < 0)
// {
// StopPlayback();
// memcpy(&cur_input_display,js,4);
// return;
// }
// nextts = 0;
// tmp >>= 5;
// tmp &= 0x3;
// ti=0;
// int tmpfix = tmp;
// while(tmp--) { nextts |= movie_readchar() << (ti * 8); ti++; }
// // This fixes a bug in movies recorded before version 0.98.11
// // It's probably not necessary, but it may keep away CRAZY PEOPLE who recorded
// // movies on <= 0.98.10 and don't work on playback.
// if(tmpfix == 1 && !nextts)
// {nextts |= movie_readchar()<<8; }
// else if(tmpfix == 2 && !nextts) {nextts |= movie_readchar()<<16; }
// if(nextd != -1)
// framets = 0;
// nextd = d;
//}
//memcpy(js,joop,4);
//TODO - rock solid stability and error detection
//for each joystick
for(int i=0;i<4;i++)
{
int tmp,ti;
uint8 d;
if(nextd != -1)
uint8 &joystate = js[i];
joystate = 0;
for(int bit=7;bit>=0;bit--)
{
if(nextd&0x80)
{
//puts("Egads");
FCEU_DoSimpleCommand(nextd&0x1F);
}
else
joop[(nextd >> 3)&0x3] ^= 1 << (nextd&0x7);
}
tmp = movie_readchar();
d = tmp;
if(tmp < 0)
int c = movie_readchar();
if(c == -1)
{
StopPlayback();
memcpy(&cur_input_display,js,4);
return;
goto bail;
}
nextts = 0;
tmp >>= 5;
tmp &= 0x3;
ti=0;
int tmpfix = tmp;
while(tmp--) { nextts |= movie_readchar() << (ti * 8); ti++; }
// This fixes a bug in movies recorded before version 0.98.11
// It's probably not necessary, but it may keep away CRAZY PEOPLE who recorded
// movies on <= 0.98.10 and don't work on playback.
if(tmpfix == 1 && !nextts)
{nextts |= movie_readchar()<<8; }
else if(tmpfix == 2 && !nextts) {nextts |= movie_readchar()<<16; }
if(nextd != -1)
framets = 0;
nextd = d;
if(c != ' ')
joystate |= (1<<bit);
}
//eat the separator (a pipe or a newline)
movie_readchar();
}
bail: ;
memcpy(js,joop,4);
}
else if(current > 0) // Recording
{
// flush header info every 300 frames in case of crash
//Don't if in bot mode--we don't need extra overhead
if(!SkipFlush)
{
static int fcounter=0;
fcounter++;
if(!(fcounter%300))
//mbg 5/22/08 - keep dumping the header for now
MovieFlushHeader();
//// flush header info every 300 frames in case of crash
////Don't if in bot mode--we don't need extra overhead
//if(!SkipFlush)
//{
// static int fcounter=0;
// fcounter++;
// if(!(fcounter%300))
// MovieFlushHeader();
//}
//for(x=0;x<4;x++)
//{
// if(js[x] != joop[x])
// {
// for(y=0;y<8;y++)
// if((js[x] ^ joop[x]) & (1 << y))
// DoEncode(x, y, 0);
// joop[x] = js[x];
// }
// else if(framets == ((1<<24)-1)) DoEncode(0,0,1); // Overflow will happen, so do dummy update.
//}
//for each joystick
for(int i=0;i<4;i++)
{
//these are mnemonics for each joystick bit.
//since we usually use the regular joypad, these will be more helpful.
//but any character other than ' ' should count as a set bit
//maybe other input types will need to be encoded another way..
const char mnemonics[] = {'A','B','S','T','U','D','L','R'};
for(int bit=7;bit>=0;bit--)
{
uint8 &joystate = js[i];
int bitmask = (1<<bit);
char mnemonic = mnemonics[bit];
//if the bit is set write the mnemonic
if(joystate & bitmask)
movie_writechar(mnemonic);
else //otherwise write a space
movie_writechar(' ');
}
for(x=0;x<4;x++)
{
if(js[x] != joop[x])
{
for(y=0;y<8;y++)
if((js[x] ^ joop[x]) & (1 << y))
DoEncode(x, y, 0);
joop[x] = js[x];
}
else if(framets == ((1<<24)-1)) DoEncode(0,0,1); // Overflow will happen, so do dummy update.
//separate the joysticks
if(i != 3) movie_writechar('|');
}
//each frame is on a new line
movie_writechar('\n');
}
if(current)
@ -1222,12 +1290,17 @@ int FCEUI_MovieGetInfo(const char* fname, MOVIE_INFO* info)
fseek(fp, 24, SEEK_SET); // offset_to_savestate offset
uint32 temp_savestate_offset;
read32le(&temp_savestate_offset, fp);
if(temp_savestate_offset != 0xFFFFFFFF)
{
if(fseek(fp, temp_savestate_offset, SEEK_SET))
{
fclose(fp);
return 0;
}
if(!FCEUSS_LoadFP(fp,2)) return 0; // 2 -> don't really load, just load to find what's there then load backup
//don't really load, just load to find what's there then load backup
if(!FCEUSS_LoadFP(fp,SSLOADPARAM_DUMMY)) return 0;
}
fclose(fp);
return 1;
@ -1335,7 +1408,7 @@ static void FCEUI_LoadMovie_v1(char *fname, int _read_only)
suppressAddPowerCommand=0;
}
if(!FCEUSS_LoadFP(fp,1)) return;
if(!FCEUSS_LoadFP(fp,SSLOADPARAM_BACKUP)) return;
ResetInputTypes();
@ -1467,7 +1540,7 @@ static int FCEUI_MovieGetInfo_v1(const char* fname, MOVIE_INFO* info)
fclose(fp);
return 0;
}
if(!FCEUSS_LoadFP(fp,2)) return 0; // 2 -> don't really load, just load to find what's there then load backup
if(!FCEUSS_LoadFP(fp,SSLOADPARAM_DUMMY)) return 0; // 2 -> don't really load, just load to find what's there then load backup
fclose(fp);

View File

@ -311,7 +311,7 @@ void NetplayUpdate(uint8 *joyp)
{
FILE *fp = FetchFile(FCEU_de32lsb(buf));
if(!fp) return;
if(FCEUSS_LoadFP(fp,1))
if(FCEUSS_LoadFP(fp,SSLOADPARAM_BACKUP))
{
fclose(fp);
FCEU_DispMessage("Remote state loaded.");

View File

@ -391,9 +391,9 @@ void FCEUSS_Save(char *fname)
}
}
int FCEUSS_LoadFP(FILE *st, int make_backup)
int FCEUSS_LoadFP(FILE *st, ENUM_SSLOADPARAMS params)
{
if(make_backup==2 && suppress_scan_chunks)
if(params==SSLOADPARAM_DUMMY && suppress_scan_chunks)
return 1;
int x;
@ -401,8 +401,8 @@ int FCEUSS_LoadFP(FILE *st, int make_backup)
int stateversion;
char* fn=0;
/* Make temporary savestate in case something screws up during the load */
if(make_backup==1)
//Make temporary savestate in case something screws up during the load
if(params == SSLOADPARAM_BACKUP)
{
fn=FCEU_MakeFName(FCEUMKF_NPTEMP,0,0);
FILE *fp;
@ -423,7 +423,7 @@ int FCEUSS_LoadFP(FILE *st, int make_backup)
}
}
if(make_backup!=2)
if(params!=SSLOADPARAM_DUMMY)
{
FCEUMOV_PreLoad();
}
@ -440,12 +440,12 @@ int FCEUSS_LoadFP(FILE *st, int make_backup)
{
stateversion=header[3] * 100;
}
if(make_backup==2)
if(params == SSLOADPARAM_DUMMY)
{
scan_chunks=1;
}
x=ReadStateChunks(st,*(uint32*)(header+4));
if(make_backup==2)
if(params == SSLOADPARAM_DUMMY)
{
scan_chunks=0;
return 1;
@ -467,14 +467,14 @@ int FCEUSS_LoadFP(FILE *st, int make_backup)
if(fn)
{
if(!x || make_backup==2) //is make_backup==2 possible?? oh well.
if(!x || params == SSLOADPARAM_DUMMY) //is make_backup==2 possible?? oh well.
{
/* Oops! Load the temporary savestate */
FILE *fp;
if((fp=fopen(fn,"rb")))
{
FCEUSS_LoadFP(fp,0);
FCEUSS_LoadFP(fp,SSLOADPARAM_NOBACKUP);
fclose(fp);
}
unlink(fn);
@ -521,7 +521,7 @@ int FCEUSS_Load(char *fname)
//If in bot mode, don't do a backup when loading.
//Otherwise you eat at the hard disk, since so many
//states are being loaded.
if(FCEUSS_LoadFP(st,FCEU_BotMode()?0:1))
if(FCEUSS_LoadFP(st,FCEU_BotMode()?SSLOADPARAM_NOBACKUP:SSLOADPARAM_BACKUP))
{
if(!fname)
{

View File

@ -20,10 +20,17 @@
#include <stdio.h>
enum ENUM_SSLOADPARAMS
{
SSLOADPARAM_NOBACKUP,
SSLOADPARAM_BACKUP,
SSLOADPARAM_DUMMY
};
void FCEUSS_Save(char *);
int FCEUSS_Load(char *);
int FCEUSS_SaveFP(FILE *);
int FCEUSS_LoadFP(FILE *, int);
int FCEUSS_LoadFP(FILE *, ENUM_SSLOADPARAMS);
extern int CurrentState;
void FCEUSS_CheckStates(void);
@ -34,6 +41,8 @@ typedef struct {
char *desc;
} SFORMAT;
void ResetExState(void (*PreSave)(void),void (*PostSave)(void));
void AddExState(void *v, uint32 s, int type, char *desc);