Skip to content

[GEN][ZH] Refactor the recorder class to use a ramfile for replay playback. #1233

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Generals/Code/GameEngine/Include/Common/Recorder.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
#include "Common/MessageStream.h"
#include "GameNetwork/GameInfo.h"

class File;

/**
* The ReplayGameInfo class holds information about the replay game and
* the contents of its slot list for reconstructing multiplayer games.
Expand Down Expand Up @@ -154,6 +156,7 @@ class RecorderClass : public SubsystemInterface {

CullBadCommandsResult cullBadCommands(); ///< prevent the user from giving mouse commands that he shouldn't be able to do during playback.

File* m_replayFile;
FILE *m_file;
AsciiString m_fileName;
Int m_currentFilePosition;
Expand Down
121 changes: 68 additions & 53 deletions Generals/Code/GameEngine/Source/Common/Recorder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine

#include "Common/Recorder.h"
#include "Common/file.h"
#include "Common/FileSystem.h"
#include "Common/PlayerList.h"
#include "Common/Player.h"
Expand Down Expand Up @@ -368,6 +369,7 @@ RecorderClass::RecorderClass()
m_originalGameMode = GAME_NONE;
m_mode = RECORDERMODETYPE_RECORD;
m_file = NULL;
m_replayFile = NULL;
m_fileName.clear();
m_currentFilePosition = 0;
//Added By Sadullah Nader
Expand Down Expand Up @@ -397,6 +399,7 @@ void RecorderClass::init() {
m_originalGameMode = GAME_NONE;
m_mode = RECORDERMODETYPE_NONE;
m_file = NULL;
m_replayFile = NULL;
m_fileName.clear();
m_currentFilePosition = 0;
m_gameInfo.clearSlotList();
Expand All @@ -419,6 +422,10 @@ void RecorderClass::reset() {
fclose(m_file);
m_file = NULL;
}
if (m_replayFile != NULL) {
m_replayFile->close();
m_replayFile = NULL;
}
m_fileName.clear();

init();
Expand Down Expand Up @@ -472,9 +479,9 @@ void RecorderClass::updatePlayback() {
* reaching the end of the playback file.
*/
void RecorderClass::stopPlayback() {
if (m_file != NULL) {
fclose(m_file);
m_file = NULL;
if (m_replayFile != NULL) {
m_replayFile->close();
m_replayFile = NULL;
}
m_fileName.clear();

Expand Down Expand Up @@ -828,52 +835,52 @@ Bool RecorderClass::readReplayHeader(ReplayHeader& header)
{
AsciiString filepath = getReplayDir();
filepath.concat(header.filename.str());
m_file = fopen(filepath.str(), "rb");
if (m_file == NULL)
m_replayFile = TheFileSystem->openFile(filepath.str(), File::READ);
if (m_replayFile == NULL)
{
DEBUG_LOG(("Can't open %s (%s)\n", filepath.str(), header.filename.str()));
return FALSE;
}

// Read the GENREP header.
char genrep[7];
fread(&genrep, sizeof(char), 6, m_file);
m_replayFile->read(&genrep, sizeof(char) * 6);
genrep[6] = 0;
if (strncmp(genrep, "GENREP", 6)) {
DEBUG_LOG(("RecorderClass::readReplayHeader - replay file did not have GENREP at the start.\n"));
fclose(m_file);
m_file = NULL;
m_replayFile->close();
m_replayFile = NULL;
return FALSE;
}

// read in some stats
replay_time_t tmp;
fread(&tmp, sizeof(replay_time_t), 1, m_file);
m_replayFile->read(&tmp, sizeof(replay_time_t));
header.startTime = tmp;
fread(&tmp, sizeof(replay_time_t), 1, m_file);
m_replayFile->read(&tmp, sizeof(replay_time_t));
header.endTime = tmp;

fread(&header.frameCount, sizeof(UnsignedInt), 1, m_file);
m_replayFile->read(&header.frameCount, sizeof(UnsignedInt));

fread(&header.desyncGame, sizeof(Bool), 1, m_file);
fread(&header.quitEarly, sizeof(Bool), 1, m_file);
m_replayFile->read(&header.desyncGame, sizeof(Bool));
m_replayFile->read(&header.quitEarly, sizeof(Bool));
for (Int i=0; i<MAX_SLOTS; ++i)
{
fread(&(header.playerDiscons[i]), sizeof(Bool), 1, m_file);
m_replayFile->read(&(header.playerDiscons[i]), sizeof(Bool));
}

// Read the Replay Name. We don't actually do anything with it. Oh well.
header.replayName = readUnicodeString();

// Read the date and time. We don't really do anything with this either. Oh well.
fread(&header.timeVal, sizeof(SYSTEMTIME), 1, m_file);
m_replayFile->read(&header.timeVal, sizeof(SYSTEMTIME));

// Read in the Version info
header.versionString = readUnicodeString();
header.versionTimeString = readUnicodeString();
fread(&header.versionNumber, sizeof(UnsignedInt), 1, m_file);
fread(&header.exeCRC, sizeof(UnsignedInt), 1, m_file);
fread(&header.iniCRC, sizeof(UnsignedInt), 1, m_file);
m_replayFile->read(&header.versionNumber, sizeof(UnsignedInt));
m_replayFile->read(&header.exeCRC, sizeof(UnsignedInt));
m_replayFile->read(&header.iniCRC, sizeof(UnsignedInt));

// Read in the GameInfo
header.gameOptions = readAsciiString();
Expand All @@ -883,8 +890,8 @@ Bool RecorderClass::readReplayHeader(ReplayHeader& header)
if (!ParseAsciiStringToGameInfo(&m_gameInfo, header.gameOptions))
{
DEBUG_LOG(("RecorderClass::readReplayHeader - replay file did not have a valid GameInfo string.\n"));
fclose(m_file);
m_file = NULL;
m_replayFile->close();
m_replayFile = NULL;
return FALSE;
}
m_gameInfo.startGame(0);
Expand All @@ -896,8 +903,8 @@ Bool RecorderClass::readReplayHeader(ReplayHeader& header)
DEBUG_LOG(("RecorderClass::readReplayHeader - invalid local slot number.\n"));
m_gameInfo.endGame();
m_gameInfo.reset();
fclose(m_file);
m_file = NULL;
m_replayFile->close();
m_replayFile = NULL;
return FALSE;
}
if (header.localPlayerIndex >= 0)
Expand All @@ -910,9 +917,13 @@ Bool RecorderClass::readReplayHeader(ReplayHeader& header)
{
m_gameInfo.endGame();
m_gameInfo.reset();
fclose(m_file);
m_file = NULL;
m_replayFile->close();
m_replayFile = NULL;
}
else {
m_replayFile = m_replayFile->convertToRAMFile();
}

return TRUE;
}

Expand Down Expand Up @@ -1210,15 +1221,15 @@ Bool RecorderClass::playbackFile(AsciiString filename)
DEBUG_LOG(("Player index is %d, replay CRC interval is %d\n", m_crcInfo->getLocalPlayer(), REPLAY_CRC_INTERVAL));

Int difficulty = 0;
fread(&difficulty, sizeof(difficulty), 1, m_file);
m_replayFile->read(&difficulty, sizeof(difficulty));

fread(&m_originalGameMode, sizeof(m_originalGameMode), 1, m_file);
m_replayFile->read(&m_originalGameMode, sizeof(m_originalGameMode));

Int rankPoints = 0;
fread(&rankPoints, sizeof(rankPoints), 1, m_file);
m_replayFile->read(&rankPoints, sizeof(rankPoints));

Int maxFPS = 0;
fread(&maxFPS, sizeof(maxFPS), 1, m_file);
m_replayFile->read(&maxFPS, sizeof(maxFPS));

DEBUG_LOG(("RecorderClass::playbackFile() - original game was mode %d\n", m_originalGameMode));

Expand Down Expand Up @@ -1259,15 +1270,17 @@ UnicodeString RecorderClass::readUnicodeString() {
WideChar str[1024] = L"";
Int index = 0;

Int c = fgetwc(m_file);
Int c;
m_replayFile->read(&c, sizeof(WideChar));
if (c == EOF) {
str[index] = 0;
}
str[index] = c;

while (index < 1024 && str[index] != 0) {
++index;
Int c = fgetwc(m_file);
Int c;
m_replayFile->read(&c, sizeof(WideChar));
if (c == EOF) {
str[index] = 0;
break;
Expand All @@ -1287,15 +1300,17 @@ AsciiString RecorderClass::readAsciiString() {
char str[1024] = "";
Int index = 0;

Int c = fgetc(m_file);
Int c;
m_replayFile->read(&c, sizeof(Char));
if (c == EOF) {
str[index] = 0;
}
str[index] = c;

while (index < 1024 && str[index] != 0) {
++index;
Int c = fgetc(m_file);
Int c;
m_replayFile->read(&c, sizeof(Char));
if (c == EOF) {
str[index] = 0;
break;
Expand All @@ -1313,9 +1328,9 @@ AsciiString RecorderClass::readAsciiString() {
* is stopped and the next frame is said to be -1.
*/
void RecorderClass::readNextFrame() {
Int retcode = fread(&m_nextFrame, sizeof(m_nextFrame), 1, m_file);
if (retcode != 1) {
DEBUG_LOG(("RecorderClass::readNextFrame - fread failed on frame %d\n", TheGameLogic->getFrame()));
Int retcode = m_replayFile->read(&m_nextFrame, sizeof(m_nextFrame));
if (retcode != sizeof(m_nextFrame)) {
DEBUG_LOG(("RecorderClass::readNextFrame - read failed on frame %d\n", TheGameLogic->getFrame()));
m_nextFrame = -1;
stopPlayback();
}
Expand All @@ -1326,9 +1341,9 @@ void RecorderClass::readNextFrame() {
*/
void RecorderClass::appendNextCommand() {
GameMessage::Type type;
Int retcode = fread(&type, sizeof(type), 1, m_file);
if (retcode != 1) {
DEBUG_LOG(("RecorderClass::appendNextCommand - fread failed on frame %d\n", m_nextFrame/*TheGameLogic->getFrame()*/));
Int retcode = m_replayFile->read(&type, sizeof(type));
if (retcode != sizeof(type)) {
DEBUG_LOG(("RecorderClass::appendNextCommand - read failed on frame %d\n", m_nextFrame/*TheGameLogic->getFrame()*/));
return;
}

Expand All @@ -1347,7 +1362,7 @@ void RecorderClass::appendNextCommand() {
#endif // DEBUG_LOGGING

Int playerIndex = -1;
fread(&playerIndex, sizeof(playerIndex), 1, m_file);
m_replayFile->read(&playerIndex, sizeof(playerIndex));
msg->friend_setPlayerIndex(playerIndex);

// don't debug log this if we're debugging sync errors, as it will cause diff problems between a game and it's replay...
Expand All @@ -1366,14 +1381,14 @@ void RecorderClass::appendNextCommand() {

UnsignedByte numTypes = 0;
Int totalArgs = 0;
fread(&numTypes, sizeof(numTypes), 1, m_file);
m_replayFile->read(&numTypes, sizeof(numTypes));

GameMessageParser *parser = newInstance(GameMessageParser)();
for (UnsignedByte i = 0; i < numTypes; ++i) {
UnsignedByte type = (UnsignedByte)ARGUMENTDATATYPE_UNKNOWN;
fread(&type, sizeof(type), 1, m_file);
m_replayFile->read(&type, sizeof(type));
UnsignedByte numArgs = 0;
fread(&numArgs, sizeof(numArgs), 1, m_file);
m_replayFile->read(&numArgs, sizeof(numArgs));
parser->addArgType((GameMessageArgumentDataType)type, numArgs);
totalArgs += numArgs;
}
Expand Down Expand Up @@ -1421,7 +1436,7 @@ void RecorderClass::appendNextCommand() {
void RecorderClass::readArgument(GameMessageArgumentDataType type, GameMessage *msg) {
if (type == ARGUMENTDATATYPE_INTEGER) {
Int theint;
fread(&theint, sizeof(theint), 1, m_file);
m_replayFile->read(&theint, sizeof(theint));
msg->appendIntegerArgument(theint);
#ifdef DEBUG_LOGGING
if (m_doingAnalysis)
Expand All @@ -1431,7 +1446,7 @@ void RecorderClass::readArgument(GameMessageArgumentDataType type, GameMessage *
#endif
} else if (type == ARGUMENTDATATYPE_REAL) {
Real thereal;
fread(&thereal, sizeof(thereal), 1, m_file);
m_replayFile->read(&thereal, sizeof(thereal));
msg->appendRealArgument(thereal);
#ifdef DEBUG_LOGGING
if (m_doingAnalysis)
Expand All @@ -1441,7 +1456,7 @@ void RecorderClass::readArgument(GameMessageArgumentDataType type, GameMessage *
#endif
} else if (type == ARGUMENTDATATYPE_BOOLEAN) {
Bool thebool;
fread(&thebool, sizeof(thebool), 1, m_file);
m_replayFile->read(&thebool, sizeof(thebool));
msg->appendBooleanArgument(thebool);
#ifdef DEBUG_LOGGING
if (m_doingAnalysis)
Expand All @@ -1451,7 +1466,7 @@ void RecorderClass::readArgument(GameMessageArgumentDataType type, GameMessage *
#endif
} else if (type == ARGUMENTDATATYPE_OBJECTID) {
ObjectID theid;
fread(&theid, sizeof(theid), 1, m_file);
m_replayFile->read(&theid, sizeof(theid));
msg->appendObjectIDArgument(theid);
#ifdef DEBUG_LOGGING
if (m_doingAnalysis)
Expand All @@ -1461,7 +1476,7 @@ void RecorderClass::readArgument(GameMessageArgumentDataType type, GameMessage *
#endif
} else if (type == ARGUMENTDATATYPE_DRAWABLEID) {
DrawableID theid;
fread(&theid, sizeof(theid), 1, m_file);
m_replayFile->read(&theid, sizeof(theid));
msg->appendDrawableIDArgument(theid);
#ifdef DEBUG_LOGGING
if (m_doingAnalysis)
Expand All @@ -1471,7 +1486,7 @@ void RecorderClass::readArgument(GameMessageArgumentDataType type, GameMessage *
#endif
} else if (type == ARGUMENTDATATYPE_TEAMID) {
UnsignedInt theid;
fread(&theid, sizeof(theid), 1, m_file);
m_replayFile->read(&theid, sizeof(theid));
msg->appendTeamIDArgument(theid);
#ifdef DEBUG_LOGGING
if (m_doingAnalysis)
Expand All @@ -1481,7 +1496,7 @@ void RecorderClass::readArgument(GameMessageArgumentDataType type, GameMessage *
#endif
} else if (type == ARGUMENTDATATYPE_LOCATION) {
Coord3D loc;
fread(&loc, sizeof(loc), 1, m_file);
m_replayFile->read(&loc, sizeof(loc));
msg->appendLocationArgument(loc);
#ifdef DEBUG_LOGGING
if (m_doingAnalysis)
Expand All @@ -1492,7 +1507,7 @@ void RecorderClass::readArgument(GameMessageArgumentDataType type, GameMessage *
#endif
} else if (type == ARGUMENTDATATYPE_PIXEL) {
ICoord2D pixel;
fread(&pixel, sizeof(pixel), 1, m_file);
m_replayFile->read(&pixel, sizeof(pixel));
msg->appendPixelArgument(pixel);
#ifdef DEBUG_LOGGING
if (m_doingAnalysis)
Expand All @@ -1502,7 +1517,7 @@ void RecorderClass::readArgument(GameMessageArgumentDataType type, GameMessage *
#endif
} else if (type == ARGUMENTDATATYPE_PIXELREGION) {
IRegion2D reg;
fread(&reg, sizeof(reg), 1, m_file);
m_replayFile->read(&reg, sizeof(reg));
msg->appendPixelRegionArgument(reg);
#ifdef DEBUG_LOGGING
if (m_doingAnalysis)
Expand All @@ -1512,7 +1527,7 @@ void RecorderClass::readArgument(GameMessageArgumentDataType type, GameMessage *
#endif
} else if (type == ARGUMENTDATATYPE_TIMESTAMP) { // Not to be confused with Terrance Stamp... Kneel before Zod!!!
UnsignedInt stamp;
fread(&stamp, sizeof(stamp), 1, m_file);
m_replayFile->read(&stamp, sizeof(stamp));
msg->appendTimestampArgument(stamp);
#ifdef DEBUG_LOGGING
if (m_doingAnalysis)
Expand All @@ -1522,7 +1537,7 @@ void RecorderClass::readArgument(GameMessageArgumentDataType type, GameMessage *
#endif
} else if (type == ARGUMENTDATATYPE_WIDECHAR) {
WideChar theid;
fread(&theid, sizeof(theid), 1, m_file);
m_replayFile->read(&theid, sizeof(theid));
msg->appendWideCharArgument(theid);
#ifdef DEBUG_LOGGING
if (m_doingAnalysis)
Expand Down
3 changes: 3 additions & 0 deletions GeneralsMD/Code/GameEngine/Include/Common/Recorder.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
#include "Common/MessageStream.h"
#include "GameNetwork/GameInfo.h"

class File;

/**
* The ReplayGameInfo class holds information about the replay game and
* the contents of its slot list for reconstructing multiplayer games.
Expand Down Expand Up @@ -154,6 +156,7 @@ class RecorderClass : public SubsystemInterface {

CullBadCommandsResult cullBadCommands(); ///< prevent the user from giving mouse commands that he shouldn't be able to do during playback.

File* m_replayFile;
FILE *m_file;
AsciiString m_fileName;
Int m_currentFilePosition;
Expand Down
Loading
Loading