add proper recording from power on for games with rtc (pgm etc). WIP.

This commit is contained in:
dinkc64 2019-07-15 08:08:51 -04:00
parent d1c671c9a6
commit ae41aef117
11 changed files with 163 additions and 52 deletions

View File

@ -915,16 +915,51 @@ INT32 BurnAreaScan(INT32 nAction, INT32* pnMin)
return nRet;
}
// ----------------------------------------------------------------------------
// Get the local time - make tweaks if netgame or input recording/playback
// tweaks are needed for the game to to remain in-sync! (pgm, neogeo, etc)
struct MovieExtInfo
{
// date & time
UINT32 year, month, day;
UINT32 hour, minute, second;
};
extern struct MovieExtInfo MovieInfo; // from replay.cpp
void BurnGetLocalTime(tm *nTime)
{
if (is_netgame_or_recording()) {
if (is_netgame_or_recording() & 2) { // recording/playback
nTime->tm_sec = MovieInfo.second;
nTime->tm_min = MovieInfo.minute;
nTime->tm_hour = MovieInfo.hour;
nTime->tm_mday = MovieInfo.day;
nTime->tm_mon = MovieInfo.month;
nTime->tm_year = MovieInfo.year;
} else {
nTime->tm_sec = 0; // defaults for netgame
nTime->tm_min = 0;
nTime->tm_hour = 0;
nTime->tm_mday = 1;
nTime->tm_wday = 3;
nTime->tm_mon = 6 - 1;
nTime->tm_year = 2018;
}
} else {
time_t nLocalTime = time(NULL); // query current time from this machine
tm* tmLocalTime = localtime(&nLocalTime);
memcpy(nTime, tmLocalTime, sizeof(tm));
}
}
// ----------------------------------------------------------------------------
// State-able random generator, based on early BSD LCG rand
static UINT64 nBurnRandSeed = 0;
UINT16 BurnRandom()
{
if (!nBurnRandSeed) { // for the rare rollover-to-0 occurance
nBurnRandSeed = 0x2d1e0f;
}
nBurnRandSeed = nBurnRandSeed * 1103515245 + 12345;
return (UINT32)(nBurnRandSeed / 65536) % 0x10000;
@ -944,7 +979,11 @@ void BurnRandomSetSeed(UINT64 nSeed)
void BurnRandomInit()
{ // for states & input recordings - init before emulation starts
nBurnRandSeed = time(NULL);
if (is_netgame_or_recording()) {
BurnRandomSetSeed(0x303808909313ULL);
} else {
BurnRandomSetSeed(time(NULL));
}
}
// ----------------------------------------------------------------------------

View File

@ -312,6 +312,7 @@ INT32 BurnUpdateProgress(double dProgressStep, const TCHAR* pszText, bool bAbs);
void BurnLocalisationSetName(char *szName, TCHAR *szLongName);
void BurnGetLocalTime(tm *nTime); // Retrieve local-time of machine w/tweaks for netgame and input recordings
UINT16 BurnRandom(); // State-able Random Number Generator (0-32767)
void BurnRandomScan(INT32 nAction); // Must be called in driver's DrvScan() if BurnRandom() is used
void BurnRandomInit(); // Called automatically in BurnDrvInit() / Internal use only

View File

@ -81,6 +81,18 @@ INT32 BurnByteswap(UINT8* pMem, INT32 nLen);
void BurnNibbleExpand(UINT8 *source, UINT8 *dst, INT32 length, INT32 swap, UINT8 nxor);
INT32 BurnClearScreen();
// recording / netgame helper
#ifndef __LIBRETRO__
INT32 is_netgame_or_recording();
#else
INT32 is_netgame_or_recording()
{
return kNetGame;
}
#endif
// load.cpp
/*

View File

@ -272,8 +272,7 @@ void TimeKeeperInit(INT32 type, UINT8 *data)
{
DebugDev_TimeKprInitted = 1;
time_t rawtime;
struct tm *timeinfo;
struct tm timeinfo;
Chip.type = type;
@ -354,18 +353,17 @@ void TimeKeeperInit(INT32 type, UINT8 *data)
}
Chip.data = data;
time(&rawtime);
timeinfo = localtime(&rawtime);
BurnGetLocalTime(&timeinfo);
Chip.control = 0;
Chip.seconds = make_bcd(timeinfo->tm_sec);
Chip.minutes = make_bcd(timeinfo->tm_min);
Chip.hours = make_bcd(timeinfo->tm_hour);
Chip.day = make_bcd(timeinfo->tm_wday + 1 );
Chip.date = make_bcd(timeinfo->tm_mday );
Chip.month = make_bcd(timeinfo->tm_mon + 1 );
Chip.year = make_bcd(timeinfo->tm_year % 100 );
Chip.century = make_bcd(timeinfo->tm_year / 100 );
Chip.seconds = make_bcd(timeinfo.tm_sec);
Chip.minutes = make_bcd(timeinfo.tm_min);
Chip.hours = make_bcd(timeinfo.tm_hour);
Chip.day = make_bcd(timeinfo.tm_wday + 1 );
Chip.date = make_bcd(timeinfo.tm_mday );
Chip.month = make_bcd(timeinfo.tm_mon + 1 );
Chip.year = make_bcd(timeinfo.tm_year % 100 );
Chip.century = make_bcd(timeinfo.tm_year / 100 );
}
void TimeKeeperExit()

View File

@ -28,8 +28,9 @@ void v3021Write(UINT16 data)
if (!DebugDev_V3021Initted) bprintf(PRINT_ERROR, _T("v3021Write called without init\n"));
#endif
time_t nLocalTime = time(NULL);
tm* tmLocalTime = localtime(&nLocalTime);
tm time;
tm* tmLocalTime = &time;
BurnGetLocalTime(&time);
CalCom <<= 1;
CalCom |= data & 1;
@ -79,7 +80,7 @@ void v3021Write(UINT16 data)
break;
case 0xf: // Load Date
tmLocalTime = localtime(&nLocalTime);
// done by default
break;
}
}
@ -88,6 +89,11 @@ void v3021Write(UINT16 data)
void v3021Init()
{
DebugDev_V3021Initted = 1;
CalVal = 0;
CalMask = 0;
CalCom = 0;
CalCnt = 0;
}
void v3021Exit()

View File

@ -23,8 +23,6 @@ static struct {
static UINT32 nOneSecond;
extern int kNetGame; // if compiling this causes an error, set up a global variable and make it '1' if running a net game (0 otherwise).
INT32 uPD4990AInit(UINT32 nTicksPerSecond)
{
nOneSecond = nTicksPerSecond;
@ -42,26 +40,16 @@ INT32 uPD4990AInit(UINT32 nTicksPerSecond)
uPD4990A.TP = 0;
// Set the time of the uPD4990A to the current local time
time_t nLocalTime = time(NULL);
tm* tmLocalTime = localtime(&nLocalTime);
tm tmLocalTime;
BurnGetLocalTime(&tmLocalTime);
if (kNetGame) { // read note above on the extern int kNetGame declaration.
uPD4990A.nSeconds = 0;
uPD4990A.nMinutes = 0;
uPD4990A.nHours = 0;
uPD4990A.nDay = 1;
uPD4990A.nWeekDay = 3;
uPD4990A.nMonth = 6;
uPD4990A.nYear = 2018 % 100;
} else {
uPD4990A.nSeconds = tmLocalTime->tm_sec;
uPD4990A.nMinutes = tmLocalTime->tm_min;
uPD4990A.nHours = tmLocalTime->tm_hour;
uPD4990A.nDay = tmLocalTime->tm_mday;
uPD4990A.nWeekDay = tmLocalTime->tm_wday;
uPD4990A.nMonth = tmLocalTime->tm_mon + 1;
uPD4990A.nYear = tmLocalTime->tm_year % 100;
}
uPD4990A.nSeconds = tmLocalTime.tm_sec;
uPD4990A.nMinutes = tmLocalTime.tm_min;
uPD4990A.nHours = tmLocalTime.tm_hour;
uPD4990A.nDay = tmLocalTime.tm_mday;
uPD4990A.nWeekDay = tmLocalTime.tm_wday;
uPD4990A.nMonth = tmLocalTime.tm_mon + 1;
uPD4990A.nYear = tmLocalTime.tm_year % 100;
return 0;
}

View File

@ -899,11 +899,13 @@ BEGIN
RTEXT "Undo Count:",IDC_STATIC,10,62,59,8
RTEXT "Author Info:",IDC_STATIC,10,71,59,8
RTEXT "Recorded From:",IDC_STATIC,10,80,59,8
RTEXT "Recorded On:",IDC_STATIC,10,89,59,8
LTEXT "00:00:00",IDC_LENGTH,76,44,59,8
LTEXT "0",IDC_FRAMES,76,53,59,8
LTEXT "0",IDC_UNDO,76,62,59,8
LTEXT "",IDC_METADATA,76,71,190,30
LTEXT "",IDC_REPLAYRESET,76,80,190,30
LTEXT "",IDC_REPLAYTIME,76,89,190,30
CONTROL "Open Read-Only",IDC_READONLY,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,35,25,69,10
CONTROL "Show Joystick Movement",IDC_SHOWMOVEMENT,"Button",BS_AUTOCHECKBOX |

View File

@ -264,6 +264,7 @@ void DeActivateChat();
int BurnerLoadDriver(TCHAR *szDriverName);
int StartFromReset(TCHAR *szDriverName);
void PausedRedraw(void);
INT32 is_netgame_or_recording();
// menu.cpp
#define UM_DISPLAYPOPUP (WM_USER + 0x0100)
@ -431,6 +432,7 @@ int KailleraGetInput();
extern int nReplayStatus;
extern bool bReplayReadOnly;
extern bool bReplayFrameCounterDisplay;
extern INT32 movieFlags;
int RecordInput();
int ReplayInput();
int StartRecord();

View File

@ -33,7 +33,7 @@ UINT8 *ReplayExternalData = NULL;
#define MOVIE_FLAG_FROM_POWERON (1<<1)
const UINT8 nMovieVersion = 0x01;
const UINT32 nMovieVersion = 0x0401;
UINT32 nStartFrame = 0;
static UINT32 nEndFrame;
@ -44,6 +44,15 @@ static short nPrevInputs[0x0100];
static INT32 nPrintInputsActive[2] = { 0, 0 };
struct MovieExtInfo
{
// date & time
UINT32 year, month, day;
UINT32 hour, minute, second;
};
struct MovieExtInfo MovieInfo = { 0, 0, 0, 0, 0, 0 };
static INT32 ReplayDialog();
static INT32 RecordDialog();
@ -273,9 +282,9 @@ INT32 ReplayInput()
PrintInputs();
}
#if 0
#if 1
if ( (GetCurrentFrame()-nStartFrame) == (nTotalFrames-1) ) {
//bRunPause = 1; // not needed, but reenable if problems -dink.
bRunPause = 1; // pause at the last recorded frame? *needs testing*
}
#endif
@ -326,8 +335,12 @@ INT32 StartRecord()
bReplayShowMovement = false;
if (bStartFromReset) {
if(!StartFromReset(NULL)) return 1;
movieFlags |= MOVIE_FLAG_FROM_POWERON;
if(!StartFromReset(NULL)) {
bprintf(0, _T("*** Replay(record): error starting game.\n"));
movieFlags = 0;
return 1;
}
}
{
const char szFileHeader[] = "FB1 "; // File identifier
@ -357,8 +370,22 @@ INT32 StartRecord()
fwrite(&nZero, 1, 4, fp); // reserve space for number of frames
fwrite(&nZero, 1, 4, fp); // undo count
fwrite(&nMovieVersion, 1, 4, fp); // ThisMovieVersion
if (nMovieVersion >= 0x0401) {
bprintf(0, _T("nMovieVersion %X .. writing date stuff!\n"), nMovieVersion);
time_t nLocalTime = time(NULL);
tm* tmLocalTime = localtime(&nLocalTime);
MovieInfo.hour = tmLocalTime->tm_hour;
MovieInfo.minute = tmLocalTime->tm_min;
MovieInfo.second = tmLocalTime->tm_sec;
MovieInfo.month = tmLocalTime->tm_mon;
MovieInfo.day = tmLocalTime->tm_mday;
MovieInfo.year = tmLocalTime->tm_year;
fwrite(&MovieInfo, 1, sizeof(MovieInfo), fp);
}
fwrite(&nZero, 1, 4, fp); // reserved
fwrite(&nZero, 1, 4, fp); //
nRet = EmbedCompressedFile(fp, -1);
}
@ -374,6 +401,8 @@ INT32 StartRecord()
FBAPopupAddText(PUF_TEXT_DEFAULT, MAKEINTRESOURCE(IDS_ERR_DISK_CREATE));
FBAPopupAddText(PUF_TEXT_DEFAULT, MAKEINTRESOURCE(IDS_DISK_REPLAY));
FBAPopupDisplay(PUF_TYPE_ERROR);
movieFlags = 0;
return 1;
} else {
struct BurnInputInfo bii;
@ -458,7 +487,11 @@ INT32 StartReplay(const TCHAR* szFileName) // const char* szFileName = NULL
if (movieFlags&MOVIE_FLAG_FROM_POWERON) { // Starts from reset
bStartFromReset = 1;
if (!bReplayDontClose)
if(!StartFromReset(wszStartupGame)) return 0;
if(!StartFromReset(wszStartupGame)) {
bprintf(0, _T("*** Replay(playback): error starting game.\n"));
movieFlags = 0;
return 0;
}
nRet = 0;
}
else {// Load the savestate associated with the recording
@ -474,6 +507,7 @@ INT32 StartReplay(const TCHAR* szFileName) // const char* szFileName = NULL
nRet = 2;
} else {
INT32 nChunkSize = 0;
INT32 nReserved = 0;
// Open the recording itself
nSizeOffset = ftell(fp); // Save chunk size offset in case the file is re-recorded
fread(&nChunkSize, 1, 0x04, fp); // Read chunk size
@ -485,7 +519,14 @@ INT32 StartReplay(const TCHAR* szFileName) // const char* szFileName = NULL
bReplayDontClose = 0; // we don't need it anymore from this point
nEndFrame += nStartFrame;
fread(&nReplayUndoCount, 1, 4, fp);
fseek(fp, 0x08, SEEK_CUR); // Skip rest of header
UINT32 ThisMovieVersion = 0;
fread(&ThisMovieVersion, 1, 4, fp);
if (ThisMovieVersion >= 0x0401) {
bprintf(0, _T("loading ext movie version!!\n"));
fread(&MovieInfo, 1, sizeof(MovieInfo), fp);
bprintf(0, _T("Ext Info: %d:%d:%d %d/%d/%d\n"), MovieInfo.hour, MovieInfo.minute, MovieInfo.second, MovieInfo.year, MovieInfo.month, MovieInfo.day);
}
fread(&nReserved, 1, 4, fp);
INT32 nEmbedPosition = ftell(fp);
// Read metadata
@ -546,6 +587,7 @@ INT32 StartReplay(const TCHAR* szFileName) // const char* szFileName = NULL
}
FBAPopupDisplay(PUF_TYPE_ERROR);
movieFlags = 0;
return 1;
}
@ -800,6 +842,7 @@ void DisplayReplayProperties(HWND hDlg, bool bClear)
SetDlgItemTextA(hDlg, IDC_UNDO, "");
SetDlgItemTextA(hDlg, IDC_METADATA, "");
SetDlgItemTextA(hDlg, IDC_REPLAYRESET, "");
SetDlgItemTextA(hDlg, IDC_REPLAYTIME, "");
EnableWindow(GetDlgItem(hDlg, IDC_READONLY), FALSE);
SendDlgItemMessage(hDlg, IDC_READONLY, BM_SETCHECK, BST_UNCHECKED, 0);
@ -875,10 +918,10 @@ void DisplayReplayProperties(HWND hDlg, bool bClear)
DisplayPropertiesError(hDlg, 0 /* not our file */);
return;
}
INT32 movieFlagsTemp = 0;
fread(&movieFlagsTemp, 1, 4, fd); // Read identifier
fread(&movieFlags, 1, 4, fd); // Read identifier
bStartFromReset = (movieFlags&MOVIE_FLAG_FROM_POWERON) ? 1 : 0; // Starts from reset
bStartFromReset = (movieFlagsTemp&MOVIE_FLAG_FROM_POWERON) ? 1 : 0; // Starts from reset
if (!bStartFromReset) {
memset(ReadHeader, 0, 4);
@ -886,6 +929,7 @@ void DisplayReplayProperties(HWND hDlg, bool bClear)
if (memcmp(ReadHeader, szSavestateHeader, 4)) { // Not the chunk type
fclose(fd);
DisplayPropertiesError(hDlg, 1 /* most likely recorded w/ an earlier version */);
return;
}
@ -933,6 +977,15 @@ void DisplayReplayProperties(HWND hDlg, bool bClear)
fread(&nFrames, 1, 4, fd);
fread(&nUndoCount, 1, 4, fd);
UINT32 ThisMovieVersion = 0;
fread(&ThisMovieVersion, 1, 4, fd);
if (ThisMovieVersion >= 0x0401) {
fread(&MovieInfo, 1, sizeof(MovieInfo), fd);
bprintf(0, _T("Movie Version %X\n"), ThisMovieVersion);
bprintf(0, _T("Ext Info: %d:%d:%d %d/%d/%d\n"), MovieInfo.hour, MovieInfo.minute, MovieInfo.second, MovieInfo.year, MovieInfo.month, MovieInfo.day);
}
// read metadata
fseek(fd, nChunkDataPosition + nChunkSize, SEEK_SET);
memset(ReadHeader, 0, 4);
@ -985,6 +1038,7 @@ void DisplayReplayProperties(HWND hDlg, bool bClear)
char szLengthString[32];
char szUndoCountString[32];
char szRecordedFrom[32];
char szRecordedTime[32];
sprintf(szFramesString, "%d", nFrames);
sprintf(szLengthString, "%02d:%02d:%02d", nHours, nMinutes % 60, nSeconds % 60);
@ -994,11 +1048,14 @@ void DisplayReplayProperties(HWND hDlg, bool bClear)
else
sprintf(szRecordedFrom, "%s", (bStartFromReset) ? "Power-On" : "Savestate");
sprintf(szRecordedTime, "%02d/%02d/%04d @ %02d:%02d:%02d%s\n", MovieInfo.month+1, MovieInfo.day, 2000 + (MovieInfo.year%100), (MovieInfo.hour>12) ? MovieInfo.hour-12 : MovieInfo.hour, MovieInfo.minute, MovieInfo.second, (MovieInfo.hour>12) ? "pm" : "am");
SetDlgItemTextA(hDlg, IDC_LENGTH, szLengthString);
SetDlgItemTextA(hDlg, IDC_FRAMES, szFramesString);
SetDlgItemTextA(hDlg, IDC_UNDO, szUndoCountString);
SetDlgItemTextW(hDlg, IDC_METADATA, wszAuthorInfo);
SetDlgItemTextA(hDlg, IDC_REPLAYRESET, szRecordedFrom);
SetDlgItemTextA(hDlg, IDC_REPLAYTIME, szRecordedTime);
}
}

View File

@ -209,7 +209,8 @@
#define IDC_FILENAME 20260
#define IDC_BROWSE 20261
#define IDC_REPLAYRESET 20262
#define IDC_SHOWMOVEMENT 20263
#define IDC_REPLAYTIME 20263
#define IDC_SHOWMOVEMENT 20264
#define IDC_STATIC_SYS 20300
#define IDC_STATIC_OPT 20301

View File

@ -195,6 +195,11 @@ int ActivateChat()
return 0;
}
INT32 is_netgame_or_recording() // returns: 1 = netgame, 2 = recording/playback
{
return (kNetGame | (movieFlags & (1<<1))); // netgame or recording from power_on
}
static int WINAPI gameCallback(char* game, int player, int numplayers)
{
bool bFound = false;